|  | #include	"mk.h" | 
|  |  | 
|  | static Node *applyrules(char *, char *); | 
|  | static void togo(Node *); | 
|  | static int vacuous(Node *); | 
|  | static Node *newnode(char *); | 
|  | static void trace(char *, Arc *); | 
|  | static void cyclechk(Node *); | 
|  | static void ambiguous(Node *); | 
|  | static void attribute(Node *); | 
|  |  | 
|  | Node * | 
|  | graph(char *target) | 
|  | { | 
|  | Node *node; | 
|  | char *cnt; | 
|  |  | 
|  | cnt = rulecnt(); | 
|  | node = applyrules(target, cnt); | 
|  | free(cnt); | 
|  | cyclechk(node); | 
|  | node->flags |= PROBABLE;	/* make sure it doesn't get deleted */ | 
|  | vacuous(node); | 
|  | ambiguous(node); | 
|  | attribute(node); | 
|  | return(node); | 
|  | } | 
|  |  | 
|  | static Node * | 
|  | applyrules(char *target, char *cnt) | 
|  | { | 
|  | Symtab *sym; | 
|  | Node *node; | 
|  | Rule *r; | 
|  | Arc head, *a = &head; | 
|  | Word *w; | 
|  | char stem[NAMEBLOCK], buf[NAMEBLOCK]; | 
|  | Resub rmatch[NREGEXP]; | 
|  |  | 
|  | /*	print("applyrules(%lux='%s')\n", target, target); */ | 
|  | sym = symlook(target, S_NODE, 0); | 
|  | if(sym) | 
|  | return sym->u.ptr; | 
|  | target = strdup(target); | 
|  | node = newnode(target); | 
|  | head.n = 0; | 
|  | head.next = 0; | 
|  | sym = symlook(target, S_TARGET, 0); | 
|  | memset((char*)rmatch, 0, sizeof(rmatch)); | 
|  | for(r = sym? sym->u.ptr:0; r; r = r->chain){ | 
|  | if(r->attr&META) continue; | 
|  | if(strcmp(target, r->target)) continue; | 
|  | if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue;	/* no effect; ignore */ | 
|  | if(cnt[r->rule] >= nreps) continue; | 
|  | cnt[r->rule]++; | 
|  | node->flags |= PROBABLE; | 
|  |  | 
|  | /*		if(r->attr&VIR) | 
|  | *			node->flags |= VIRTUAL; | 
|  | *		if(r->attr&NOREC) | 
|  | *			node->flags |= NORECIPE; | 
|  | *		if(r->attr&DEL) | 
|  | *			node->flags |= DELETE; | 
|  | */ | 
|  | if(!r->tail || !r->tail->s || !*r->tail->s) { | 
|  | a->next = newarc((Node *)0, r, "", rmatch); | 
|  | a = a->next; | 
|  | } else | 
|  | for(w = r->tail; w; w = w->next){ | 
|  | a->next = newarc(applyrules(w->s, cnt), r, "", rmatch); | 
|  | a = a->next; | 
|  | } | 
|  | cnt[r->rule]--; | 
|  | head.n = node; | 
|  | } | 
|  | for(r = metarules; r; r = r->next){ | 
|  | if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue;	/* no effect; ignore */ | 
|  | if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR)) | 
|  | continue; | 
|  | if(r->attr®EXP){ | 
|  | stem[0] = 0; | 
|  | patrule = r; | 
|  | memset((char*)rmatch, 0, sizeof(rmatch)); | 
|  | if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0) | 
|  | continue; | 
|  | } else { | 
|  | if(!match(node->name, r->target, stem, r->shellt)) continue; | 
|  | } | 
|  | if(cnt[r->rule] >= nreps) continue; | 
|  | cnt[r->rule]++; | 
|  |  | 
|  | /*		if(r->attr&VIR) | 
|  | *			node->flags |= VIRTUAL; | 
|  | *		if(r->attr&NOREC) | 
|  | *			node->flags |= NORECIPE; | 
|  | *		if(r->attr&DEL) | 
|  | *			node->flags |= DELETE; | 
|  | */ | 
|  |  | 
|  | if(!r->tail || !r->tail->s || !*r->tail->s) { | 
|  | a->next = newarc((Node *)0, r, stem, rmatch); | 
|  | a = a->next; | 
|  | } else | 
|  | for(w = r->tail; w; w = w->next){ | 
|  | if(r->attr®EXP) | 
|  | regsub(w->s, buf, sizeof buf, rmatch, NREGEXP); | 
|  | else | 
|  | subst(stem, w->s, buf); | 
|  | a->next = newarc(applyrules(buf, cnt), r, stem, rmatch); | 
|  | a = a->next; | 
|  | } | 
|  | cnt[r->rule]--; | 
|  | } | 
|  | a->next = node->prereqs; | 
|  | node->prereqs = head.next; | 
|  | return(node); | 
|  | } | 
|  |  | 
|  | static void | 
|  | togo(Node *node) | 
|  | { | 
|  | Arc *la, *a; | 
|  |  | 
|  | /* delete them now */ | 
|  | la = 0; | 
|  | for(a = node->prereqs; a; la = a, a = a->next) | 
|  | if(a->flag&TOGO){ | 
|  | if(a == node->prereqs) | 
|  | node->prereqs = a->next; | 
|  | else | 
|  | la->next = a->next, a = la; | 
|  | } | 
|  | } | 
|  |  | 
|  | static int | 
|  | vacuous(Node *node) | 
|  | { | 
|  | Arc *la, *a; | 
|  | int vac = !(node->flags&PROBABLE); | 
|  |  | 
|  | if(node->flags&READY) | 
|  | return(node->flags&VACUOUS); | 
|  | node->flags |= READY; | 
|  | for(a = node->prereqs; a; a = a->next) | 
|  | if(a->n && vacuous(a->n) && (a->r->attr&META)) | 
|  | a->flag |= TOGO; | 
|  | else | 
|  | vac = 0; | 
|  | /* if a rule generated arcs that DON'T go; no others from that rule go */ | 
|  | for(a = node->prereqs; a; a = a->next) | 
|  | if((a->flag&TOGO) == 0) | 
|  | for(la = node->prereqs; la; la = la->next) | 
|  | if((la->flag&TOGO) && (la->r == a->r)){ | 
|  | la->flag &= ~TOGO; | 
|  | } | 
|  | togo(node); | 
|  | if(vac) | 
|  | node->flags |= VACUOUS; | 
|  | return(vac); | 
|  | } | 
|  |  | 
|  | static Node * | 
|  | newnode(char *name) | 
|  | { | 
|  | register Node *node; | 
|  |  | 
|  | node = (Node *)Malloc(sizeof(Node)); | 
|  | symlook(name, S_NODE, (void *)node); | 
|  | node->name = name; | 
|  | node->time = timeof(name, 0); | 
|  | node->prereqs = 0; | 
|  | node->flags = node->time? PROBABLE : 0; | 
|  | node->next = 0; | 
|  | return(node); | 
|  | } | 
|  |  | 
|  | void | 
|  | dumpn(char *s, Node *n) | 
|  | { | 
|  | char buf[1024]; | 
|  | Arc *a; | 
|  |  | 
|  | snprint(buf, sizeof buf, "%s   ", (*s == ' ')? s:""); | 
|  | Bprint(&bout, "%s%s@%ld: time=%ld flags=0x%x next=%ld\n", | 
|  | s, n->name, n, n->time, n->flags, n->next); | 
|  | for(a = n->prereqs; a; a = a->next) | 
|  | dumpa(buf, a); | 
|  | } | 
|  |  | 
|  | static void | 
|  | trace(char *s, Arc *a) | 
|  | { | 
|  | fprint(2, "\t%s", s); | 
|  | while(a){ | 
|  | fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line, | 
|  | a->n? a->n->name:""); | 
|  | if(a->n){ | 
|  | for(a = a->n->prereqs; a; a = a->next) | 
|  | if(*a->r->recipe) break; | 
|  | } else | 
|  | a = 0; | 
|  | } | 
|  | fprint(2, "\n"); | 
|  | } | 
|  |  | 
|  | static void | 
|  | cyclechk(Node *n) | 
|  | { | 
|  | Arc *a; | 
|  |  | 
|  | if((n->flags&CYCLE) && n->prereqs){ | 
|  | fprint(2, "mk: cycle in graph detected at target %s\n", n->name); | 
|  | Exit(); | 
|  | } | 
|  | n->flags |= CYCLE; | 
|  | for(a = n->prereqs; a; a = a->next) | 
|  | if(a->n) | 
|  | cyclechk(a->n); | 
|  | n->flags &= ~CYCLE; | 
|  | } | 
|  |  | 
|  | static void | 
|  | ambiguous(Node *n) | 
|  | { | 
|  | Arc *a; | 
|  | Rule *r = 0; | 
|  | Arc *la; | 
|  | int bad = 0; | 
|  |  | 
|  | la = 0; | 
|  | for(a = n->prereqs; a; a = a->next){ | 
|  | if(a->n) | 
|  | ambiguous(a->n); | 
|  | if(*a->r->recipe == 0) continue; | 
|  | if(r == 0) | 
|  | r = a->r, la = a; | 
|  | else{ | 
|  | if(r->recipe != a->r->recipe){ | 
|  | if((r->attr&META) && !(a->r->attr&META)){ | 
|  | la->flag |= TOGO; | 
|  | r = a->r, la = a; | 
|  | } else if(!(r->attr&META) && (a->r->attr&META)){ | 
|  | a->flag |= TOGO; | 
|  | continue; | 
|  | } | 
|  | } | 
|  | if(r->recipe != a->r->recipe){ | 
|  | if(bad == 0){ | 
|  | fprint(2, "mk: ambiguous recipes for %s:\n", n->name); | 
|  | bad = 1; | 
|  | trace(n->name, la); | 
|  | } | 
|  | trace(n->name, a); | 
|  | } | 
|  | } | 
|  | } | 
|  | if(bad) | 
|  | Exit(); | 
|  | togo(n); | 
|  | } | 
|  |  | 
|  | static void | 
|  | attribute(Node *n) | 
|  | { | 
|  | register Arc *a; | 
|  |  | 
|  | for(a = n->prereqs; a; a = a->next){ | 
|  | if(a->r->attr&VIR) | 
|  | n->flags |= VIRTUAL; | 
|  | if(a->r->attr&NOREC) | 
|  | n->flags |= NORECIPE; | 
|  | if(a->r->attr&DEL) | 
|  | n->flags |= DELETE; | 
|  | if(a->n) | 
|  | attribute(a->n); | 
|  | } | 
|  | if(n->flags&VIRTUAL) | 
|  | n->time = 0; | 
|  | } |