xref: /plan9/sys/src/cmd/mk/graph.c (revision d1da931c1953c14f6f98c26297030a0b55cb02f6)
13e12c5d1SDavid du Colombier #include	"mk.h"
23e12c5d1SDavid du Colombier 
33e12c5d1SDavid du Colombier static Node *applyrules(char *, char *);
43e12c5d1SDavid du Colombier static void togo(Node *);
53e12c5d1SDavid du Colombier static int vacuous(Node *);
63e12c5d1SDavid du Colombier static Node *newnode(char *);
73e12c5d1SDavid du Colombier static void trace(char *, Arc *);
83e12c5d1SDavid du Colombier static void cyclechk(Node *);
93e12c5d1SDavid du Colombier static void ambiguous(Node *);
103e12c5d1SDavid du Colombier static void attribute(Node *);
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier Node *
graph(char * target)133e12c5d1SDavid du Colombier graph(char *target)
143e12c5d1SDavid du Colombier {
153e12c5d1SDavid du Colombier 	Node *node;
163e12c5d1SDavid du Colombier 	char *cnt;
173e12c5d1SDavid du Colombier 
18219b2ee8SDavid du Colombier 	cnt = rulecnt();
19219b2ee8SDavid du Colombier 	node = applyrules(target, cnt);
203e12c5d1SDavid du Colombier 	free(cnt);
213e12c5d1SDavid du Colombier 	cyclechk(node);
223e12c5d1SDavid du Colombier 	node->flags |= PROBABLE;	/* make sure it doesn't get deleted */
233e12c5d1SDavid du Colombier 	vacuous(node);
243e12c5d1SDavid du Colombier 	ambiguous(node);
253e12c5d1SDavid du Colombier 	attribute(node);
263e12c5d1SDavid du Colombier 	return(node);
273e12c5d1SDavid du Colombier }
283e12c5d1SDavid du Colombier 
293e12c5d1SDavid du Colombier static Node *
applyrules(char * target,char * cnt)303e12c5d1SDavid du Colombier applyrules(char *target, char *cnt)
313e12c5d1SDavid du Colombier {
323e12c5d1SDavid du Colombier 	Symtab *sym;
333e12c5d1SDavid du Colombier 	Node *node;
343e12c5d1SDavid du Colombier 	Rule *r;
353e12c5d1SDavid du Colombier 	Arc head, *a = &head;
363e12c5d1SDavid du Colombier 	Word *w;
373e12c5d1SDavid du Colombier 	char stem[NAMEBLOCK], buf[NAMEBLOCK];
383e12c5d1SDavid du Colombier 	Resub rmatch[NREGEXP];
393e12c5d1SDavid du Colombier 
407dd7cddfSDavid du Colombier /*	print("applyrules(%lux='%s')\n", target, target);/**/
417dd7cddfSDavid du Colombier 	sym = symlook(target, S_NODE, 0);
42219b2ee8SDavid du Colombier 	if(sym)
434de34a7eSDavid du Colombier 		return sym->u.ptr;
443e12c5d1SDavid du Colombier 	target = strdup(target);
453e12c5d1SDavid du Colombier 	node = newnode(target);
463e12c5d1SDavid du Colombier 	head.n = 0;
473e12c5d1SDavid du Colombier 	head.next = 0;
487dd7cddfSDavid du Colombier 	sym = symlook(target, S_TARGET, 0);
497dd7cddfSDavid du Colombier 	memset((char*)rmatch, 0, sizeof(rmatch));
504de34a7eSDavid du Colombier 	for(r = sym? sym->u.ptr:0; r; r = r->chain){
513e12c5d1SDavid du Colombier 		if(r->attr&META) continue;
523e12c5d1SDavid du Colombier 		if(strcmp(target, r->target)) continue;
53219b2ee8SDavid du Colombier 		if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue;	/* no effect; ignore */
543e12c5d1SDavid du Colombier 		if(cnt[r->rule] >= nreps) continue;
553e12c5d1SDavid du Colombier 		cnt[r->rule]++;
563e12c5d1SDavid du Colombier 		node->flags |= PROBABLE;
57219b2ee8SDavid du Colombier 
583e12c5d1SDavid du Colombier /*		if(r->attr&VIR)
59219b2ee8SDavid du Colombier  *			node->flags |= VIRTUAL;
60219b2ee8SDavid du Colombier  *		if(r->attr&NOREC)
61219b2ee8SDavid du Colombier  *			node->flags |= NORECIPE;
62219b2ee8SDavid du Colombier  *		if(r->attr&DEL)
63219b2ee8SDavid du Colombier  *			node->flags |= DELETE;
643e12c5d1SDavid du Colombier  */
653e12c5d1SDavid du Colombier 		if(!r->tail || !r->tail->s || !*r->tail->s) {
663e12c5d1SDavid du Colombier 			a->next = newarc((Node *)0, r, "", rmatch);
673e12c5d1SDavid du Colombier 			a = a->next;
683e12c5d1SDavid du Colombier 		} else
693e12c5d1SDavid du Colombier 			for(w = r->tail; w; w = w->next){
703e12c5d1SDavid du Colombier 				a->next = newarc(applyrules(w->s, cnt), r, "", rmatch);
713e12c5d1SDavid du Colombier 				a = a->next;
723e12c5d1SDavid du Colombier 		}
733e12c5d1SDavid du Colombier 		cnt[r->rule]--;
743e12c5d1SDavid du Colombier 		head.n = node;
753e12c5d1SDavid du Colombier 	}
763e12c5d1SDavid du Colombier 	for(r = metarules; r; r = r->next){
77219b2ee8SDavid du Colombier 		if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue;	/* no effect; ignore */
783e12c5d1SDavid du Colombier 		if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR))
793e12c5d1SDavid du Colombier 			continue;
803e12c5d1SDavid du Colombier 		if(r->attr&REGEXP){
813e12c5d1SDavid du Colombier 			stem[0] = 0;
823e12c5d1SDavid du Colombier 			patrule = r;
837dd7cddfSDavid du Colombier 			memset((char*)rmatch, 0, sizeof(rmatch));
843e12c5d1SDavid du Colombier 			if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0)
853e12c5d1SDavid du Colombier 				continue;
863e12c5d1SDavid du Colombier 		} else {
873e12c5d1SDavid du Colombier 			if(!match(node->name, r->target, stem)) continue;
883e12c5d1SDavid du Colombier 		}
893e12c5d1SDavid du Colombier 		if(cnt[r->rule] >= nreps) continue;
903e12c5d1SDavid du Colombier 		cnt[r->rule]++;
91219b2ee8SDavid du Colombier 
923e12c5d1SDavid du Colombier /*		if(r->attr&VIR)
93219b2ee8SDavid du Colombier  *			node->flags |= VIRTUAL;
94219b2ee8SDavid du Colombier  *		if(r->attr&NOREC)
95219b2ee8SDavid du Colombier  *			node->flags |= NORECIPE;
96219b2ee8SDavid du Colombier  *		if(r->attr&DEL)
97219b2ee8SDavid du Colombier  *			node->flags |= DELETE;
983e12c5d1SDavid du Colombier  */
993e12c5d1SDavid du Colombier 		if(!r->tail || !r->tail->s || !*r->tail->s) {
1007dd7cddfSDavid du Colombier 			a->next = newarc((Node *)0, r, stem, rmatch);
1013e12c5d1SDavid du Colombier 			a = a->next;
1023e12c5d1SDavid du Colombier 		} else
1033e12c5d1SDavid du Colombier 			for(w = r->tail; w; w = w->next){
1043e12c5d1SDavid du Colombier 				if(r->attr&REGEXP)
1059a747e4fSDavid du Colombier 					regsub(w->s, buf, sizeof(buf), rmatch, NREGEXP);
1063e12c5d1SDavid du Colombier 				else
1079a747e4fSDavid du Colombier 					subst(stem, w->s, buf, sizeof(buf));
1087dd7cddfSDavid du Colombier 				a->next = newarc(applyrules(buf, cnt), r, stem, rmatch);
1093e12c5d1SDavid du Colombier 				a = a->next;
1103e12c5d1SDavid du Colombier 			}
1113e12c5d1SDavid du Colombier 		cnt[r->rule]--;
1123e12c5d1SDavid du Colombier 	}
1133e12c5d1SDavid du Colombier 	a->next = node->prereqs;
1143e12c5d1SDavid du Colombier 	node->prereqs = head.next;
1153e12c5d1SDavid du Colombier 	return(node);
1163e12c5d1SDavid du Colombier }
1173e12c5d1SDavid du Colombier 
1183e12c5d1SDavid du Colombier static void
togo(Node * node)1193e12c5d1SDavid du Colombier togo(Node *node)
1203e12c5d1SDavid du Colombier {
1213e12c5d1SDavid du Colombier 	Arc *la, *a;
1223e12c5d1SDavid du Colombier 
1233e12c5d1SDavid du Colombier 	/* delete them now */
1243e12c5d1SDavid du Colombier 	la = 0;
1253e12c5d1SDavid du Colombier 	for(a = node->prereqs; a; la = a, a = a->next)
1263e12c5d1SDavid du Colombier 		if(a->flag&TOGO){
1273e12c5d1SDavid du Colombier 			if(a == node->prereqs)
1283e12c5d1SDavid du Colombier 				node->prereqs = a->next;
1293e12c5d1SDavid du Colombier 			else
1303e12c5d1SDavid du Colombier 				la->next = a->next, a = la;
1313e12c5d1SDavid du Colombier 		}
1323e12c5d1SDavid du Colombier }
1333e12c5d1SDavid du Colombier 
1343e12c5d1SDavid du Colombier static
vacuous(Node * node)1353e12c5d1SDavid du Colombier vacuous(Node *node)
1363e12c5d1SDavid du Colombier {
1373e12c5d1SDavid du Colombier 	Arc *la, *a;
1383e12c5d1SDavid du Colombier 	int vac = !(node->flags&PROBABLE);
1393e12c5d1SDavid du Colombier 
1403e12c5d1SDavid du Colombier 	if(node->flags&READY)
1413e12c5d1SDavid du Colombier 		return(node->flags&VACUOUS);
1423e12c5d1SDavid du Colombier 	node->flags |= READY;
1433e12c5d1SDavid du Colombier 	for(a = node->prereqs; a; a = a->next)
1443e12c5d1SDavid du Colombier 		if(a->n && vacuous(a->n) && (a->r->attr&META))
1453e12c5d1SDavid du Colombier 			a->flag |= TOGO;
1463e12c5d1SDavid du Colombier 		else
1473e12c5d1SDavid du Colombier 			vac = 0;
1483e12c5d1SDavid du Colombier 	/* if a rule generated arcs that DON'T go; no others from that rule go */
1493e12c5d1SDavid du Colombier 	for(a = node->prereqs; a; a = a->next)
1503e12c5d1SDavid du Colombier 		if((a->flag&TOGO) == 0)
1513e12c5d1SDavid du Colombier 			for(la = node->prereqs; la; la = la->next)
1523e12c5d1SDavid du Colombier 				if((la->flag&TOGO) && (la->r == a->r)){
1533e12c5d1SDavid du Colombier 					la->flag &= ~TOGO;
1543e12c5d1SDavid du Colombier 				}
1553e12c5d1SDavid du Colombier 	togo(node);
1563e12c5d1SDavid du Colombier 	if(vac)
1573e12c5d1SDavid du Colombier 		node->flags |= VACUOUS;
1583e12c5d1SDavid du Colombier 	return(vac);
1593e12c5d1SDavid du Colombier }
1603e12c5d1SDavid du Colombier 
1613e12c5d1SDavid du Colombier static Node *
newnode(char * name)1623e12c5d1SDavid du Colombier newnode(char *name)
1633e12c5d1SDavid du Colombier {
1643e12c5d1SDavid du Colombier 	register Node *node;
1653e12c5d1SDavid du Colombier 
1663e12c5d1SDavid du Colombier 	node = (Node *)Malloc(sizeof(Node));
1677dd7cddfSDavid du Colombier 	symlook(name, S_NODE, (void *)node);
1683e12c5d1SDavid du Colombier 	node->name = name;
1693e12c5d1SDavid du Colombier 	node->time = timeof(name, 0);
1703e12c5d1SDavid du Colombier 	node->prereqs = 0;
1713e12c5d1SDavid du Colombier 	node->flags = node->time? PROBABLE : 0;
1723e12c5d1SDavid du Colombier 	node->next = 0;
1733e12c5d1SDavid du Colombier 	return(node);
1743e12c5d1SDavid du Colombier }
1753e12c5d1SDavid du Colombier 
1763e12c5d1SDavid du Colombier void
dumpn(char * s,Node * n)1773e12c5d1SDavid du Colombier dumpn(char *s, Node *n)
1783e12c5d1SDavid du Colombier {
1793e12c5d1SDavid du Colombier 	char buf[1024];
1803e12c5d1SDavid du Colombier 	Arc *a;
1813e12c5d1SDavid du Colombier 
1827dd7cddfSDavid du Colombier 	Bprint(&bout, "%s%s@%p: time=%ld flags=0x%x next=%p\n",
1833e12c5d1SDavid du Colombier 		s, n->name, n, n->time, n->flags, n->next);
1847dd7cddfSDavid du Colombier 	for(a = n->prereqs; a; a = a->next){
185*d1da931cSDavid du Colombier 		snprint(buf, sizeof buf, "%s   ", (*s == ' ')? s:"");
1863e12c5d1SDavid du Colombier 		dumpa(buf, a);
1873e12c5d1SDavid du Colombier 	}
1887dd7cddfSDavid du Colombier }
1893e12c5d1SDavid du Colombier 
1903e12c5d1SDavid du Colombier static void
trace(char * s,Arc * a)1913e12c5d1SDavid du Colombier trace(char *s, Arc *a)
1923e12c5d1SDavid du Colombier {
1933e12c5d1SDavid du Colombier 	fprint(2, "\t%s", s);
1943e12c5d1SDavid du Colombier 	while(a){
1953e12c5d1SDavid du Colombier 		fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line,
1963e12c5d1SDavid du Colombier 			a->n? a->n->name:"");
1973e12c5d1SDavid du Colombier 		if(a->n){
1983e12c5d1SDavid du Colombier 			for(a = a->n->prereqs; a; a = a->next)
1993e12c5d1SDavid du Colombier 				if(*a->r->recipe) break;
2003e12c5d1SDavid du Colombier 		} else
2013e12c5d1SDavid du Colombier 			a = 0;
2023e12c5d1SDavid du Colombier 	}
2033e12c5d1SDavid du Colombier 	fprint(2, "\n");
2043e12c5d1SDavid du Colombier }
2053e12c5d1SDavid du Colombier 
2063e12c5d1SDavid du Colombier static void
cyclechk(Node * n)2073e12c5d1SDavid du Colombier cyclechk(Node *n)
2083e12c5d1SDavid du Colombier {
2093e12c5d1SDavid du Colombier 	Arc *a;
2103e12c5d1SDavid du Colombier 
2113e12c5d1SDavid du Colombier 	if((n->flags&CYCLE) && n->prereqs){
2123e12c5d1SDavid du Colombier 		fprint(2, "mk: cycle in graph detected at target %s\n", n->name);
2133e12c5d1SDavid du Colombier 		Exit();
2143e12c5d1SDavid du Colombier 	}
2153e12c5d1SDavid du Colombier 	n->flags |= CYCLE;
2163e12c5d1SDavid du Colombier 	for(a = n->prereqs; a; a = a->next)
2173e12c5d1SDavid du Colombier 		if(a->n)
2183e12c5d1SDavid du Colombier 			cyclechk(a->n);
2193e12c5d1SDavid du Colombier 	n->flags &= ~CYCLE;
2203e12c5d1SDavid du Colombier }
2213e12c5d1SDavid du Colombier 
2223e12c5d1SDavid du Colombier static void
ambiguous(Node * n)2233e12c5d1SDavid du Colombier ambiguous(Node *n)
2243e12c5d1SDavid du Colombier {
2253e12c5d1SDavid du Colombier 	Arc *a;
2263e12c5d1SDavid du Colombier 	Rule *r = 0;
2273e12c5d1SDavid du Colombier 	Arc *la;
2283e12c5d1SDavid du Colombier 	int bad = 0;
2293e12c5d1SDavid du Colombier 
2303e12c5d1SDavid du Colombier 	la = 0;
2313e12c5d1SDavid du Colombier 	for(a = n->prereqs; a; a = a->next){
2323e12c5d1SDavid du Colombier 		if(a->n)
2333e12c5d1SDavid du Colombier 			ambiguous(a->n);
2343e12c5d1SDavid du Colombier 		if(*a->r->recipe == 0) continue;
2353e12c5d1SDavid du Colombier 		if(r == 0)
2363e12c5d1SDavid du Colombier 			r = a->r, la = a;
2373e12c5d1SDavid du Colombier 		else{
2383e12c5d1SDavid du Colombier 			if(r->recipe != a->r->recipe){
2393e12c5d1SDavid du Colombier 				if((r->attr&META) && !(a->r->attr&META)){
2403e12c5d1SDavid du Colombier 					la->flag |= TOGO;
2413e12c5d1SDavid du Colombier 					r = a->r, la = a;
2423e12c5d1SDavid du Colombier 				} else if(!(r->attr&META) && (a->r->attr&META)){
2433e12c5d1SDavid du Colombier 					a->flag |= TOGO;
2443e12c5d1SDavid du Colombier 					continue;
2453e12c5d1SDavid du Colombier 				}
2463e12c5d1SDavid du Colombier 			}
2473e12c5d1SDavid du Colombier 			if(r->recipe != a->r->recipe){
2483e12c5d1SDavid du Colombier 				if(bad == 0){
2493e12c5d1SDavid du Colombier 					fprint(2, "mk: ambiguous recipes for %s:\n", n->name);
2503e12c5d1SDavid du Colombier 					bad = 1;
2513e12c5d1SDavid du Colombier 					trace(n->name, la);
2523e12c5d1SDavid du Colombier 				}
2533e12c5d1SDavid du Colombier 				trace(n->name, a);
2543e12c5d1SDavid du Colombier 			}
2553e12c5d1SDavid du Colombier 		}
2563e12c5d1SDavid du Colombier 	}
2573e12c5d1SDavid du Colombier 	if(bad)
2583e12c5d1SDavid du Colombier 		Exit();
2593e12c5d1SDavid du Colombier 	togo(n);
2603e12c5d1SDavid du Colombier }
2613e12c5d1SDavid du Colombier 
2623e12c5d1SDavid du Colombier static void
attribute(Node * n)2633e12c5d1SDavid du Colombier attribute(Node *n)
2643e12c5d1SDavid du Colombier {
2653e12c5d1SDavid du Colombier 	register Arc *a;
2663e12c5d1SDavid du Colombier 
2673e12c5d1SDavid du Colombier 	for(a = n->prereqs; a; a = a->next){
2683e12c5d1SDavid du Colombier 		if(a->r->attr&VIR)
2693e12c5d1SDavid du Colombier 			n->flags |= VIRTUAL;
2703e12c5d1SDavid du Colombier 		if(a->r->attr&NOREC)
2713e12c5d1SDavid du Colombier 			n->flags |= NORECIPE;
2723e12c5d1SDavid du Colombier 		if(a->r->attr&DEL)
2733e12c5d1SDavid du Colombier 			n->flags |= DELETE;
2743e12c5d1SDavid du Colombier 		if(a->n)
2753e12c5d1SDavid du Colombier 			attribute(a->n);
2763e12c5d1SDavid du Colombier 	}
2773e12c5d1SDavid du Colombier 	if(n->flags&VIRTUAL)
2783e12c5d1SDavid du Colombier 		n->time = 0;
2793e12c5d1SDavid du Colombier }
280