1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1984-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * Glenn Fowler
23 * AT&T Research
24 *
25 * make file read routines
26 */
27
28 #include "make.h"
29
30 /*
31 * read the base and global rules
32 */
33
34 static void
readrules(void)35 readrules(void)
36 {
37 register char* s;
38 register Sfio_t* tmp;
39 register List_t* p;
40
41 state.global = 1;
42
43 /*
44 * read the base rules
45 */
46
47 if (!(s = state.rules))
48 state.rules = null;
49 else if (*s)
50 {
51 tmp = sfstropen();
52 edit(tmp, s, KEEP, KEEP, external.object);
53 readfile(sfstruse(tmp), COMP_BASE|(state.explicitrules ? COMP_RULES : 0), NiL);
54 edit(tmp, s, DELETE, KEEP, DELETE);
55 state.rules = strdup(sfstruse(tmp));
56 sfstrclose(tmp);
57 }
58 setvar(external.rules, state.rules, 0)->property |= V_compiled;
59
60 /*
61 * read the explicit global makefiles
62 *
63 * NOTE: internal.tmplist is used to handle the effects
64 * of load() on internal list pointers
65 */
66
67 if (p = internal.globalfiles->prereqs)
68 {
69 for (p = internal.tmplist->prereqs = listcopy(p); p; p = p->next)
70 readfile(p->rule->name, COMP_GLOBAL, NiL);
71 freelist(internal.tmplist->prereqs);
72 internal.tmplist->prereqs = 0;
73 }
74 state.global = 0;
75 }
76
77 /*
78 * read a file given an open file pointer
79 */
80
81 static void
readfp(Sfio_t * sp,register Rule_t * r,int type)82 readfp(Sfio_t* sp, register Rule_t* r, int type)
83 {
84 register char* s;
85 register char* t;
86 int n;
87 int needrules;
88 int preprocess;
89 int splice;
90 char* name;
91 char* b;
92 char* e;
93 char* objfile;
94 Rule_t* x;
95 Sfio_t* fp;
96
97 objfile = 0;
98 name = r->name;
99 if (!state.makefile)
100 {
101 /*
102 * set up the related file names
103 */
104
105 fp = sfstropen();
106 setvar(external.file, r->name, 0)->property |= V_compiled;
107 edit(fp, r->name, DELETE, KEEP, KEEP);
108 state.makefile = strdup(sfstruse(fp));
109 sfstrclose(fp);
110 objfile = objectfile();
111 }
112 needrules = !state.base && !state.rules;
113
114 /*
115 * load if object file
116 */
117
118 if (loadable(sp, r, 0))
119 {
120 if (!state.base && !state.global && !state.list)
121 error(3, "%s: explicit make object files must be global", r->name);
122 if (!state.rules)
123 readrules();
124 message((-2, "loading %sobject file %s", state.global ? "global " : null, r->name));
125 if (load(sp, r->name, 0, 0) > 0)
126 {
127 sfclose(sp);
128 return;
129 }
130 error(3, "%s: must be recompiled", name);
131 }
132
133 /*
134 * check object corresponding to file
135 */
136
137 if (state.global || !state.forceread && (!(type & COMP_FILE) || needrules))
138 {
139 fp = sfstropen();
140 if (!objfile)
141 {
142 edit(fp, r->name, DELETE, KEEP, external.object);
143 objfile = sfstruse(fp);
144 }
145 state.init++;
146 x = bindfile(NiL, objfile, 0);
147 state.init--;
148 sfstrclose(fp);
149 if (!x || !x->time)
150 /* ignore */;
151 else if (x == r)
152 error(3, "%s must be recompiled", r->name);
153 else if (fp = sfopen(NiL, s = x->name, "br"))
154 {
155 if (needrules)
156 x->dynamic |= D_built;
157 if (loadable(fp, x, 1))
158 {
159 if (needrules)
160 {
161 if (state.rules && !state.explicitrules)
162 {
163 edit(internal.tmp, state.rules, DELETE, KEEP, DELETE);
164 edit(internal.wrk, b = getval(external.rules, VAL_PRIMARY), DELETE, KEEP, DELETE);
165 if (strcmp(sfstruse(internal.tmp), sfstruse(internal.wrk)))
166 {
167 error(state.exec || state.mam.out ? -1 : 1, "%s: base rules changed to %s", sfstrbase(internal.tmp), sfstrbase(internal.wrk));
168 state.rules = b;
169 state.forceread = 1;
170 needrules = 1;
171 }
172 }
173 if (!state.forceread)
174 {
175 needrules = 0;
176 readrules();
177 }
178 }
179 if (!state.forceread)
180 {
181 message((-2, "loading %s file %s", state.global ? "global" : "object", s));
182 n = load(fp, s, 1, 0);
183 if (n > 0)
184 {
185 sfclose(fp);
186 sfclose(sp);
187 return;
188 }
189 }
190 r = getrule(name);
191 }
192 sfclose(fp);
193 if (state.global)
194 error(1, "%s: reading%s", r->name, state.forceread ? " -- should be compiled before local makefiles" : null);
195 else if (state.writeobject)
196 error(state.exec || state.mam.out ? -1 : 1, "%s: recompiling", s);
197 }
198 }
199
200 /*
201 * at this point we have to read it
202 * if its the first makefile then the
203 * base rules must be determined and loaded
204 * along with the global rules before the parse
205 */
206
207 preprocess = state.preprocess;
208 if (!state.global)
209 {
210 /*
211 * first check for and apply makefile converter
212 */
213
214 s = 0;
215 if (*(t = getval(external.convert, VAL_PRIMARY)))
216 {
217 char* u;
218 char* v;
219 Sfio_t* exp;
220
221 exp = sfstropen();
222 if (e = strchr(r->name, '/'))
223 e++;
224 else
225 e = r->name;
226 b = tokopen(t, 1);
227 while ((t = tokread(b)) && (t = colonlist(exp, t, 0, ' ')))
228 {
229 u = tokopen(t, 0);
230 while ((v = tokread(u)) && !streq(e, v));
231 tokclose(u);
232 if (!(s = tokread(b)))
233 {
234 error(2, "%s: %s: no action for file", external.convert, t);
235 break;
236 }
237 if (v)
238 {
239 s = getarg((e = t = strdup(s), &e), NiL);
240 break;
241 }
242 s = 0;
243 }
244 tokclose(b);
245 sfstrclose(exp);
246 }
247 if (s)
248 {
249 message((-2, "converting %s using \"%s\"", r->name, s));
250 sfclose(sp);
251 if (!(sp = fapply(internal.internal, null, r->name, s, CO_ALWAYS|CO_LOCAL|CO_URGENT)))
252 error(3, "%s: error in makefile converter \"%s\"", r->name, s);
253 free(t);
254 preprocess = -1;
255 }
256 if (needrules)
257 {
258 if ((s = sfreserve(sp, 0, 0)) && (n = sfvalue(sp)) >= 0)
259 {
260 int c;
261 int d;
262 int old;
263
264 if (n > 0)
265 {
266 if (n > MAXNAME)
267 n = MAXNAME;
268 else
269 n--;
270 }
271
272 /*
273 * quick makefile type check while
274 * checking for base rules
275 */
276
277 old = 0;
278 splice = 0;
279 b = s;
280 c = *(s + n);
281 *(s + n) = 0;
282 for (;;)
283 {
284 if (e = strchr(s, '\n'))
285 *e = 0;
286 else if (c != '\n')
287 break;
288 if (splice)
289 /* skip */;
290 else if (*s == SALT)
291 {
292 while (isspace(*++s));
293 for (t = s; isalnum(*t); t++);
294 d = *t;
295 *t = 0;
296 if (strneq(s, "rules", 5))
297 {
298 if (*t = d)
299 t++;
300 while (*t == ' ' || *t == '\t')
301 t++;
302 rules(*t == '/' && *(t + 1) == '*' ? null : t);
303 break;
304 }
305 else if (!strmatch(s, "assert|comment|define|elif|else|endif|endmac|error|ident|if|ifdef|ifndef|include|line|macdef|pragma|unassert|undef|warning"))
306 old = 1;
307 else if (!preprocess)
308 preprocess = 1;
309 *t = d;
310 }
311 else if (*s == '<' && *(s + 1) == '<')
312 {
313 old = preprocess = 0;
314 break;
315 }
316 else
317 {
318 while (isspace(*s))
319 s++;
320 if (strneq(s, "rules", 5))
321 {
322 for (s += 5; *s == ' ' || *s == '\t'; s++);
323 rules(*s == '/' && *(s + 1) == '*' ? null : s);
324 old = 0;
325 break;
326 }
327 else if (strneq(s, ".SOURCE", 7) && (*(s + 7) == '.' || *(s + 7) == ':' || isspace(*(s + 7))))
328 {
329 old = 0;
330 break;
331 }
332 else
333 {
334 d = ':';
335 while (*s)
336 {
337 if (*s == '/' && *(s + 1) == '*' && (*(s + 2) == '*' || isspace(*(s + 2)) || !*(s + 2)))
338 break;
339 else if (*s == d)
340 {
341 if (*++s == d)
342 s++;
343 else if (isalnum(*s))
344 {
345 while (isalnum(*s))
346 s++;
347 if (*s == d)
348 break;
349 }
350 d = 0;
351 }
352 while (*s && *s != d && !isspace(*s))
353 s++;
354 while (isspace(*s))
355 s++;
356 }
357 if (*s)
358 {
359 old = 0;
360 break;
361 }
362 }
363 }
364 if (!(s = e))
365 break;
366 splice = e > b && *(e - 1) == '\\';
367 *s++ = '\n';
368 }
369 if (e)
370 *e = '\n';
371 *(b + n) = c;
372 if (old)
373 punt(1);
374 }
375 if (!state.rules)
376 state.rules = getval(external.rules, VAL_PRIMARY);
377 readrules();
378 r = getrule(name);
379 }
380 }
381
382 /*
383 * check for obsolete makefile preprocessor
384 */
385
386 if (preprocess > 0)
387 {
388 s = "$(MAKEPP) $(MAKEPPFLAGS) $(>)";
389 message((-2, "preprocessing %s using \"%s\"", r->name, s));
390 sfclose(sp);
391 if (!(sp = fapply(internal.internal, null, r->name, s, CO_ALWAYS|CO_LOCAL|CO_URGENT)))
392 error(3, "%s: error in makefile preprocessor \"%s\"", r->name, s);
393 }
394
395 /*
396 * parse the file
397 */
398
399 if (state.base)
400 {
401 if (!state.compile)
402 state.compile = RECOMPILE;
403 state.global = 1;
404 }
405 n = state.reading;
406 state.reading = 1;
407 parse(sp, NiL, r->name, NiL);
408 sfclose(sp);
409 state.reading = n;
410 if (!state.compile && !state.global)
411 state.compile = RECOMPILE;
412 if ((state.questionable & 0x00000400) || !state.global)
413 state.forceread = 1;
414 }
415
416 /*
417 * read a makefile
418 */
419
420 int
readfile(register char * file,int type,char * filter)421 readfile(register char* file, int type, char* filter)
422 {
423 register Rule_t* r;
424 Sfio_t* rfp;
425 Stat_t st;
426
427 if (streq(file, "-") && (file = "/dev/null") || isdynamic(file))
428 {
429 rfp = sfstropen();
430 expand(rfp, file);
431 state.init++;
432 file = makerule(sfstruse(rfp))->name;
433 state.init--;
434 sfstrclose(rfp);
435 }
436 state.init++;
437 r = bindfile(NiL, file, BIND_MAKEFILE|BIND_RULE);
438 state.init--;
439 if (r && (r->time || strneq(r->name, "/dev/", 5) && !rstat(r->name, &st, 0)))
440 {
441 compref(r, type);
442 r->dynamic |= D_scanned;
443 file = r->name;
444 if (rfp = filter ? fapply(internal.internal, null, file, filter, CO_ALWAYS|CO_LOCAL|CO_URGENT) : rsfopen(file))
445 {
446 if (state.mam.dynamic || state.mam.regress)
447 mampush(state.mam.out, r, P_force);
448 if (state.user)
449 {
450 r->status = EXISTS;
451 parse(rfp, NiL, file, NiL);
452 sfclose(rfp);
453 }
454 else
455 readfp(rfp, r, type);
456 if (state.mam.dynamic || state.mam.regress)
457 mampop(state.mam.out, r, 0);
458 if ((type & COMP_BASE) && r->uname)
459 {
460 oldname(r);
461 r->dynamic &= ~D_bound;
462 }
463 if (state.pushed)
464 {
465 state.pushed = 0;
466 state.global = state.push_global;
467 state.user = state.push_user;
468 }
469 return(1);
470 }
471 if ((type & COMP_DONTCARE) || (r->property & P_dontcare))
472 {
473 r->property |= P_dontcare;
474 return(0);
475 }
476 }
477 if (!(type & COMP_DONTCARE))
478 error((type & COMP_INCLUDE) ? 2 : 3, "%s: cannot read%s", file, (type & COMP_INCLUDE) ? " include file" : (type & COMP_GLOBAL) ? " global rules" : (type & COMP_BASE) ? " base rules" : null);
479 else if ((type & COMP_INCLUDE) && error_info.line)
480 compref(r ? r : makerule(file), type);
481 return(0);
482 }
483