xref: /inferno-os/utils/mk/graph.c (revision d0e1d143ef6f03c75c008c7ec648859dd260cbab)
1 #include	"mk.h"
2 
3 static Node *applyrules(char *, char *);
4 static void togo(Node *);
5 static int vacuous(Node *);
6 static Node *newnode(char *);
7 static void trace(char *, Arc *);
8 static void cyclechk(Node *);
9 static void ambiguous(Node *);
10 static void attribute(Node *);
11 
12 Node *
13 graph(char *target)
14 {
15 	Node *node;
16 	char *cnt;
17 
18 	cnt = rulecnt();
19 	node = applyrules(target, cnt);
20 	free(cnt);
21 	cyclechk(node);
22 	node->flags |= PROBABLE;	/* make sure it doesn't get deleted */
23 	vacuous(node);
24 	ambiguous(node);
25 	attribute(node);
26 	return(node);
27 }
28 
29 static Node *
30 applyrules(char *target, char *cnt)
31 {
32 	Symtab *sym;
33 	Node *node;
34 	Rule *r;
35 	Arc head, *a = &head;
36 	Word *w;
37 	char stem[NAMEBLOCK], buf[NAMEBLOCK];
38 	Resub rmatch[NREGEXP];
39 
40 /*	print("applyrules(%lux='%s')\n", target, target);/**/
41 	sym = symlook(target, S_NODE, 0);
42 	if(sym)
43 		return (Node *)(sym->value);
44 	target = strdup(target);
45 	node = newnode(target);
46 	head.n = 0;
47 	head.next = 0;
48 	sym = symlook(target, S_TARGET, 0);
49 	memset((char*)rmatch, 0, sizeof(rmatch));
50 	for(r = sym? (Rule *)(sym->value):0; r; r = r->chain){
51 		if(r->attr&META) continue;
52 		if(strcmp(target, r->target)) continue;
53 		if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue;	/* no effect; ignore */
54 		if(cnt[r->rule] >= nreps) continue;
55 		cnt[r->rule]++;
56 		node->flags |= PROBABLE;
57 
58 /*		if(r->attr&VIR)
59  *			node->flags |= VIRTUAL;
60  *		if(r->attr&NOREC)
61  *			node->flags |= NORECIPE;
62  *		if(r->attr&DEL)
63  *			node->flags |= DELETE;
64  */
65 		if(!r->tail || !r->tail->s || !*r->tail->s) {
66 			a->next = newarc((Node *)0, r, "", rmatch);
67 			a = a->next;
68 		} else
69 			for(w = r->tail; w; w = w->next){
70 				a->next = newarc(applyrules(w->s, cnt), r, "", rmatch);
71 				a = a->next;
72 		}
73 		cnt[r->rule]--;
74 		head.n = node;
75 	}
76 	for(r = metarules; r; r = r->next){
77 		if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue;	/* no effect; ignore */
78 		if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR))
79 			continue;
80 		if(r->attr&REGEXP){
81 			stem[0] = 0;
82 			patrule = r;
83 			memset((char*)rmatch, 0, sizeof(rmatch));
84 			if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0)
85 				continue;
86 		} else {
87 			if(!match(node->name, r->target, stem)) continue;
88 		}
89 		if(cnt[r->rule] >= nreps) continue;
90 		cnt[r->rule]++;
91 
92 /*		if(r->attr&VIR)
93  *			node->flags |= VIRTUAL;
94  *		if(r->attr&NOREC)
95  *			node->flags |= NORECIPE;
96  *		if(r->attr&DEL)
97  *			node->flags |= DELETE;
98  */
99 
100 		if(!r->tail || !r->tail->s || !*r->tail->s) {
101 			a->next = newarc((Node *)0, r, stem, rmatch);
102 			a = a->next;
103 		} else
104 			for(w = r->tail; w; w = w->next){
105 				if(r->attr&REGEXP)
106 					regsub(w->s, buf, rmatch, NREGEXP);
107 				else
108 					subst(stem, w->s, buf);
109 				a->next = newarc(applyrules(buf, cnt), r, stem, rmatch);
110 				a = a->next;
111 			}
112 		cnt[r->rule]--;
113 	}
114 	a->next = node->prereqs;
115 	node->prereqs = head.next;
116 	return(node);
117 }
118 
119 static void
120 togo(Node *node)
121 {
122 	Arc *la, *a;
123 
124 	/* delete them now */
125 	la = 0;
126 	for(a = node->prereqs; a; la = a, a = a->next)
127 		if(a->flag&TOGO){
128 			if(a == node->prereqs)
129 				node->prereqs = a->next;
130 			else
131 				la->next = a->next, a = la;
132 		}
133 }
134 
135 static int
136 vacuous(Node *node)
137 {
138 	Arc *la, *a;
139 	int vac = !(node->flags&PROBABLE);
140 
141 	if(node->flags&READY)
142 		return(node->flags&VACUOUS);
143 	node->flags |= READY;
144 	for(a = node->prereqs; a; a = a->next)
145 		if(a->n && vacuous(a->n) && (a->r->attr&META))
146 			a->flag |= TOGO;
147 		else
148 			vac = 0;
149 	/* if a rule generated arcs that DON'T go; no others from that rule go */
150 	for(a = node->prereqs; a; a = a->next)
151 		if((a->flag&TOGO) == 0)
152 			for(la = node->prereqs; la; la = la->next)
153 				if((la->flag&TOGO) && (la->r == a->r)){
154 					la->flag &= ~TOGO;
155 				}
156 	togo(node);
157 	if(vac)
158 		node->flags |= VACUOUS;
159 	return(vac);
160 }
161 
162 static Node *
163 newnode(char *name)
164 {
165 	register Node *node;
166 
167 	node = (Node *)Malloc(sizeof(Node));
168 	symlook(name, S_NODE, (void *)node);
169 	node->name = name;
170 	node->time = timeof(name, 0);
171 	node->prereqs = 0;
172 	node->flags = node->time? PROBABLE : 0;
173 	node->next = 0;
174 	return(node);
175 }
176 
177 void
178 dumpn(char *s, Node *n)
179 {
180 	char buf[1024];
181 	Arc *a;
182 
183 	sprint(buf, "%s   ", (*s == ' ')? s:"");
184 	Bprint(&bout, "%s%s@%ld: time=%ld flags=0x%x next=%ld\n",
185 		s, n->name, n, n->time, n->flags, n->next);
186 	for(a = n->prereqs; a; a = a->next)
187 		dumpa(buf, a);
188 }
189 
190 static void
191 trace(char *s, Arc *a)
192 {
193 	fprint(2, "\t%s", s);
194 	while(a){
195 		fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line,
196 			a->n? a->n->name:"");
197 		if(a->n){
198 			for(a = a->n->prereqs; a; a = a->next)
199 				if(*a->r->recipe) break;
200 		} else
201 			a = 0;
202 	}
203 	fprint(2, "\n");
204 }
205 
206 static void
207 cyclechk(Node *n)
208 {
209 	Arc *a;
210 
211 	if((n->flags&CYCLE) && n->prereqs){
212 		fprint(2, "mk: cycle in graph detected at target %s\n", n->name);
213 		Exit();
214 	}
215 	n->flags |= CYCLE;
216 	for(a = n->prereqs; a; a = a->next)
217 		if(a->n)
218 			cyclechk(a->n);
219 	n->flags &= ~CYCLE;
220 }
221 
222 static void
223 ambiguous(Node *n)
224 {
225 	Arc *a;
226 	Rule *r = 0;
227 	Arc *la;
228 	int bad = 0;
229 
230 	la = 0;
231 	for(a = n->prereqs; a; a = a->next){
232 		if(a->n)
233 			ambiguous(a->n);
234 		if(*a->r->recipe == 0) continue;
235 		if(r == 0)
236 			r = a->r, la = a;
237 		else{
238 			if(r->recipe != a->r->recipe){
239 				if((r->attr&META) && !(a->r->attr&META)){
240 					la->flag |= TOGO;
241 					r = a->r, la = a;
242 				} else if(!(r->attr&META) && (a->r->attr&META)){
243 					a->flag |= TOGO;
244 					continue;
245 				}
246 			}
247 			if(r->recipe != a->r->recipe){
248 				if(bad == 0){
249 					fprint(2, "mk: ambiguous recipes for %s:\n", n->name);
250 					bad = 1;
251 					trace(n->name, la);
252 				}
253 				trace(n->name, a);
254 			}
255 		}
256 	}
257 	if(bad)
258 		Exit();
259 	togo(n);
260 }
261 
262 static void
263 attribute(Node *n)
264 {
265 	register Arc *a;
266 
267 	for(a = n->prereqs; a; a = a->next){
268 		if(a->r->attr&VIR)
269 			n->flags |= VIRTUAL;
270 		if(a->r->attr&NOREC)
271 			n->flags |= NORECIPE;
272 		if(a->r->attr&DEL)
273 			n->flags |= DELETE;
274 		if(a->n)
275 			attribute(a->n);
276 	}
277 	if(n->flags&VIRTUAL)
278 		n->time = 0;
279 }
280