Commit | Line | Data |
---|---|---|
9320ab9e KB |
1 | /* |
2 | * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. | |
3 | * Copyright (c) 1988, 1989 by Adam de Boor | |
4 | * Copyright (c) 1989 by Berkeley Softworks | |
5 | * All rights reserved. | |
6 | * | |
7 | * This code is derived from software contributed to Berkeley by | |
8 | * Adam de Boor. | |
9 | * | |
87198c0c | 10 | * %sccs.include.redist.c% |
9320ab9e KB |
11 | */ |
12 | ||
13 | #ifndef lint | |
b3dbe08f | 14 | static char sccsid[] = "@(#)parse.c 5.17 (Berkeley) %G%"; |
9320ab9e KB |
15 | #endif /* not lint */ |
16 | ||
ab950546 KB |
17 | /*- |
18 | * parse.c -- | |
19 | * Functions to parse a makefile. | |
20 | * | |
21 | * One function, Parse_Init, must be called before any functions | |
22 | * in this module are used. After that, the function Parse_File is the | |
23 | * main entry point and controls most of the other functions in this | |
24 | * module. | |
25 | * | |
26 | * Most important structures are kept in Lsts. Directories for | |
27 | * the #include "..." function are kept in the 'parseIncPath' Lst, while | |
28 | * those for the #include <...> are kept in the 'sysIncPath' Lst. The | |
29 | * targets currently being defined are kept in the 'targets' Lst. | |
30 | * | |
31 | * The variables 'fname' and 'lineno' are used to track the name | |
32 | * of the current file and the line number in that file so that error | |
33 | * messages can be more meaningful. | |
34 | * | |
ab950546 KB |
35 | * Interface: |
36 | * Parse_Init Initialization function which must be | |
37 | * called before anything else in this module | |
38 | * is used. | |
39 | * | |
40 | * Parse_File Function used to parse a makefile. It must | |
41 | * be given the name of the file, which should | |
42 | * already have been opened, and a function | |
43 | * to call to read a character from the file. | |
44 | * | |
45 | * Parse_IsVar Returns TRUE if the given line is a | |
46 | * variable assignment. Used by MainParseArgs | |
47 | * to determine if an argument is a target | |
48 | * or a variable assignment. Used internally | |
49 | * for pretty much the same thing... | |
50 | * | |
51 | * Parse_Error Function called when an error occurs in | |
52 | * parsing. Used by the variable and | |
53 | * conditional modules. | |
54 | * Parse_MainName Returns a Lst of the main target to create. | |
55 | */ | |
ab950546 | 56 | |
b6cda174 KB |
57 | #include <varargs.h> |
58 | #include <stdio.h> | |
59 | #include <ctype.h> | |
60 | #include "make.h" | |
61 | #include "buf.h" | |
aabb6217 | 62 | #include "pathnames.h" |
ab950546 KB |
63 | |
64 | /* | |
65 | * These values are returned by ParseEOF to tell Parse_File whether to | |
66 | * CONTINUE parsing, i.e. it had only reached the end of an include file, | |
67 | * or if it's DONE. | |
68 | */ | |
69 | #define CONTINUE 1 | |
70 | #define DONE 0 | |
71 | static int ParseEOF(); | |
72 | ||
73 | static Lst targets; /* targets we're working on */ | |
74 | static Boolean inLine; /* true if currently in a dependency | |
75 | * line or its commands */ | |
76 | ||
77 | static char *fname; /* name of current file (for errors) */ | |
78 | static int lineno; /* line number in current file */ | |
79 | static FILE *curFILE; /* current makefile */ | |
80 | ||
81 | static int fatals = 0; | |
82 | ||
83 | static GNode *mainNode; /* The main target to create. This is the | |
84 | * first target on the first dependency | |
85 | * line in the first makefile */ | |
86 | /* | |
87 | * Definitions for handling #include specifications | |
88 | */ | |
89 | typedef struct IFile { | |
90 | char *fname; /* name of previous file */ | |
91 | int lineno; /* saved line number */ | |
92 | FILE * F; /* the open stream */ | |
93 | } IFile; | |
94 | ||
95 | static Lst includes; /* stack of IFiles generated by | |
96 | * #includes */ | |
97 | Lst parseIncPath; /* list of directories for "..." includes */ | |
98 | Lst sysIncPath; /* list of directories for <...> includes */ | |
99 | ||
ab950546 KB |
100 | /*- |
101 | * specType contains the SPECial TYPE of the current target. It is | |
102 | * Not if the target is unspecial. If it *is* special, however, the children | |
103 | * are linked as children of the parent but not vice versa. This variable is | |
104 | * set in ParseDoDependency | |
105 | */ | |
106 | typedef enum { | |
107 | Begin, /* .BEGIN */ | |
108 | Default, /* .DEFAULT */ | |
109 | End, /* .END */ | |
ab950546 KB |
110 | Ignore, /* .IGNORE */ |
111 | Includes, /* .INCLUDES */ | |
112 | Interrupt, /* .INTERRUPT */ | |
113 | Libs, /* .LIBS */ | |
114 | MFlags, /* .MFLAGS or .MAKEFLAGS */ | |
115 | Main, /* .MAIN and we don't have anything user-specified to | |
116 | * make */ | |
ab950546 KB |
117 | Not, /* Not special */ |
118 | NotParallel, /* .NOTPARALELL */ | |
119 | Null, /* .NULL */ | |
120 | Order, /* .ORDER */ | |
121 | Path, /* .PATH */ | |
122 | Precious, /* .PRECIOUS */ | |
123 | Shell, /* .SHELL */ | |
124 | Silent, /* .SILENT */ | |
125 | SingleShell, /* .SINGLESHELL */ | |
126 | Suffixes, /* .SUFFIXES */ | |
127 | Attribute, /* Generic attribute */ | |
128 | } ParseSpecial; | |
129 | ||
130 | ParseSpecial specType; | |
131 | ||
132 | /* | |
133 | * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER | |
134 | * seen, then set to each successive source on the line. | |
135 | */ | |
136 | static GNode *predecessor; | |
137 | ||
138 | /* | |
139 | * The parseKeywords table is searched using binary search when deciding | |
140 | * if a target or source is special. The 'spec' field is the ParseSpecial | |
141 | * type of the keyword ("Not" if the keyword isn't special as a target) while | |
142 | * the 'op' field is the operator to apply to the list of targets if the | |
143 | * keyword is used as a source ("0" if the keyword isn't special as a source) | |
144 | */ | |
145 | static struct { | |
146 | char *name; /* Name of keyword */ | |
147 | ParseSpecial spec; /* Type when used as a target */ | |
148 | int op; /* Operator when used as a source */ | |
149 | } parseKeywords[] = { | |
150 | { ".BEGIN", Begin, 0 }, | |
151 | { ".DEFAULT", Default, 0 }, | |
ac8c8bba | 152 | { ".OPTIONAL", Attribute, OP_OPTIONAL }, |
ab950546 KB |
153 | { ".END", End, 0 }, |
154 | { ".EXEC", Attribute, OP_EXEC }, | |
ab950546 KB |
155 | { ".IGNORE", Ignore, OP_IGNORE }, |
156 | { ".INCLUDES", Includes, 0 }, | |
157 | { ".INTERRUPT", Interrupt, 0 }, | |
158 | { ".INVISIBLE", Attribute, OP_INVISIBLE }, | |
159 | { ".JOIN", Attribute, OP_JOIN }, | |
160 | { ".LIBS", Libs, 0 }, | |
ab950546 KB |
161 | { ".MAIN", Main, 0 }, |
162 | { ".MAKE", Attribute, OP_MAKE }, | |
163 | { ".MAKEFLAGS", MFlags, 0 }, | |
164 | { ".MFLAGS", MFlags, 0 }, | |
ab950546 KB |
165 | { ".NOTMAIN", Attribute, OP_NOTMAIN }, |
166 | { ".NOTPARALLEL", NotParallel, 0 }, | |
167 | { ".NULL", Null, 0 }, | |
168 | { ".ORDER", Order, 0 }, | |
169 | { ".PATH", Path, 0 }, | |
170 | { ".PRECIOUS", Precious, OP_PRECIOUS }, | |
171 | { ".RECURSIVE", Attribute, OP_MAKE }, | |
172 | { ".SHELL", Shell, 0 }, | |
173 | { ".SILENT", Silent, OP_SILENT }, | |
174 | { ".SINGLESHELL", SingleShell, 0 }, | |
175 | { ".SUFFIXES", Suffixes, 0 }, | |
176 | { ".USE", Attribute, OP_USE }, | |
177 | }; | |
182ca07d | 178 | |
ab950546 KB |
179 | /*- |
180 | *---------------------------------------------------------------------- | |
181 | * ParseFindKeyword -- | |
182 | * Look in the table of keywords for one matching the given string. | |
183 | * | |
184 | * Results: | |
185 | * The index of the keyword, or -1 if it isn't there. | |
186 | * | |
187 | * Side Effects: | |
188 | * None | |
189 | *---------------------------------------------------------------------- | |
190 | */ | |
191 | static int | |
192 | ParseFindKeyword (str) | |
193 | char *str; /* String to find */ | |
194 | { | |
195 | register int start, | |
196 | end, | |
197 | cur; | |
198 | register int diff; | |
199 | ||
200 | start = 0; | |
201 | end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; | |
202 | ||
203 | do { | |
204 | cur = start + ((end - start) / 2); | |
205 | diff = strcmp (str, parseKeywords[cur].name); | |
206 | ||
207 | if (diff == 0) { | |
208 | return (cur); | |
209 | } else if (diff < 0) { | |
210 | end = cur - 1; | |
211 | } else { | |
212 | start = cur + 1; | |
213 | } | |
214 | } while (start <= end); | |
215 | return (-1); | |
216 | } | |
182ca07d | 217 | |
ab950546 | 218 | /*- |
ab950546 KB |
219 | * Parse_Error -- |
220 | * Error message abort function for parsing. Prints out the context | |
221 | * of the error (line number and file) as well as the message with | |
222 | * two optional arguments. | |
223 | * | |
224 | * Results: | |
225 | * None | |
226 | * | |
227 | * Side Effects: | |
228 | * "fatals" is incremented if the level is PARSE_FATAL. | |
ab950546 | 229 | */ |
b6cda174 | 230 | /* VARARGS */ |
ab950546 | 231 | void |
b6cda174 KB |
232 | Parse_Error(type, va_alist) |
233 | int type; /* Error type (PARSE_WARNING, PARSE_FATAL) */ | |
234 | va_dcl | |
ab950546 | 235 | { |
b6cda174 KB |
236 | va_list ap; |
237 | char *fmt; | |
ab950546 | 238 | |
b6cda174 KB |
239 | (void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno); |
240 | if (type == PARSE_WARNING) | |
43bbd0a7 | 241 | (void)fprintf(stderr, "warning: "); |
8b2fa9f8 | 242 | va_start(ap); |
b6cda174 KB |
243 | fmt = va_arg(ap, char *); |
244 | (void)vfprintf(stderr, fmt, ap); | |
245 | va_end(ap); | |
246 | (void)fprintf(stderr, "\n"); | |
247 | (void)fflush(stderr); | |
248 | if (type == PARSE_FATAL) | |
249 | fatals += 1; | |
ab950546 | 250 | } |
182ca07d | 251 | |
ab950546 KB |
252 | /*- |
253 | *--------------------------------------------------------------------- | |
254 | * ParseLinkSrc -- | |
255 | * Link the parent node to its new child. Used in a Lst_ForEach by | |
256 | * ParseDoDependency. If the specType isn't 'Not', the parent | |
257 | * isn't linked as a parent of the child. | |
258 | * | |
259 | * Results: | |
260 | * Always = 0 | |
261 | * | |
262 | * Side Effects: | |
263 | * New elements are added to the parents list of cgn and the | |
264 | * children list of cgn. the unmade field of pgn is updated | |
265 | * to reflect the additional child. | |
266 | *--------------------------------------------------------------------- | |
267 | */ | |
268 | static int | |
269 | ParseLinkSrc (pgn, cgn) | |
270 | GNode *pgn; /* The parent node */ | |
271 | GNode *cgn; /* The child node */ | |
272 | { | |
273 | if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) { | |
274 | (void)Lst_AtEnd (pgn->children, (ClientData)cgn); | |
275 | if (specType == Not) { | |
276 | (void)Lst_AtEnd (cgn->parents, (ClientData)pgn); | |
277 | } | |
278 | pgn->unmade += 1; | |
279 | } | |
280 | return (0); | |
281 | } | |
182ca07d | 282 | |
ab950546 KB |
283 | /*- |
284 | *--------------------------------------------------------------------- | |
285 | * ParseDoOp -- | |
286 | * Apply the parsed operator to the given target node. Used in a | |
287 | * Lst_ForEach call by ParseDoDependency once all targets have | |
288 | * been found and their operator parsed. If the previous and new | |
289 | * operators are incompatible, a major error is taken. | |
290 | * | |
291 | * Results: | |
292 | * Always 0 | |
293 | * | |
294 | * Side Effects: | |
295 | * The type field of the node is altered to reflect any new bits in | |
296 | * the op. | |
297 | *--------------------------------------------------------------------- | |
298 | */ | |
299 | static int | |
300 | ParseDoOp (gn, op) | |
301 | GNode *gn; /* The node to which the operator is to be | |
302 | * applied */ | |
303 | int op; /* The operator to apply */ | |
304 | { | |
305 | /* | |
306 | * If the dependency mask of the operator and the node don't match and | |
307 | * the node has actually had an operator applied to it before, and | |
308 | * the operator actually has some dependency information in it, complain. | |
309 | */ | |
310 | if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && | |
311 | !OP_NOP(gn->type) && !OP_NOP(op)) | |
312 | { | |
313 | Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name); | |
314 | return (1); | |
315 | } | |
316 | ||
317 | if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { | |
318 | /* | |
319 | * If the node was the object of a :: operator, we need to create a | |
320 | * new instance of it for the children and commands on this dependency | |
321 | * line. The new instance is placed on the 'cohorts' list of the | |
322 | * initial one (note the initial one is not on its own cohorts list) | |
323 | * and the new instance is linked to all parents of the initial | |
324 | * instance. | |
325 | */ | |
326 | register GNode *cohort; | |
327 | LstNode ln; | |
328 | ||
329 | cohort = Targ_NewGN(gn->name); | |
330 | /* | |
331 | * Duplicate links to parents so graph traversal is simple. Perhaps | |
332 | * some type bits should be duplicated? | |
333 | * | |
334 | * Make the cohort invisible as well to avoid duplicating it into | |
335 | * other variables. True, parents of this target won't tend to do | |
336 | * anything with their local variables, but better safe than | |
337 | * sorry. | |
338 | */ | |
339 | Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort); | |
340 | cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; | |
341 | (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort); | |
342 | ||
343 | /* | |
344 | * Replace the node in the targets list with the new copy | |
345 | */ | |
346 | ln = Lst_Member(targets, (ClientData)gn); | |
347 | Lst_Replace(ln, (ClientData)cohort); | |
348 | gn = cohort; | |
349 | } | |
350 | /* | |
351 | * We don't want to nuke any previous flags (whatever they were) so we | |
352 | * just OR the new operator into the old | |
353 | */ | |
354 | gn->type |= op; | |
355 | ||
356 | return (0); | |
357 | } | |
182ca07d | 358 | |
ab950546 KB |
359 | /*- |
360 | *--------------------------------------------------------------------- | |
361 | * ParseDoSrc -- | |
362 | * Given the name of a source, figure out if it is an attribute | |
363 | * and apply it to the targets if it is. Else decide if there is | |
364 | * some attribute which should be applied *to* the source because | |
365 | * of some special target and apply it if so. Otherwise, make the | |
366 | * source be a child of the targets in the list 'targets' | |
367 | * | |
368 | * Results: | |
369 | * None | |
370 | * | |
371 | * Side Effects: | |
372 | * Operator bits may be added to the list of targets or to the source. | |
373 | * The targets may have a new source added to their lists of children. | |
374 | *--------------------------------------------------------------------- | |
375 | */ | |
376 | static void | |
377 | ParseDoSrc (tOp, src) | |
378 | int tOp; /* operator (if any) from special targets */ | |
379 | char *src; /* name of the source to handle */ | |
380 | { | |
381 | int op; /* operator (if any) from special source */ | |
382 | GNode *gn; | |
383 | ||
384 | op = 0; | |
385 | if (*src == '.' && isupper (src[1])) { | |
386 | int keywd = ParseFindKeyword(src); | |
387 | if (keywd != -1) { | |
388 | op = parseKeywords[keywd].op; | |
389 | } | |
390 | } | |
391 | if (op != 0) { | |
392 | Lst_ForEach (targets, ParseDoOp, (ClientData)op); | |
ab950546 KB |
393 | } else if (specType == Main) { |
394 | /* | |
395 | * If we have noted the existence of a .MAIN, it means we need | |
396 | * to add the sources of said target to the list of things | |
397 | * to create. The string 'src' is likely to be free, so we | |
398 | * must make a new copy of it. Note that this will only be | |
399 | * invoked if the user didn't specify a target on the command | |
400 | * line. This is to allow #ifmake's to succeed, or something... | |
401 | */ | |
182ca07d | 402 | (void) Lst_AtEnd (create, (ClientData)strdup(src)); |
ab950546 KB |
403 | /* |
404 | * Add the name to the .TARGETS variable as well, so the user cna | |
405 | * employ that, if desired. | |
406 | */ | |
407 | Var_Append(".TARGETS", src, VAR_GLOBAL); | |
408 | } else if (specType == Order) { | |
409 | /* | |
410 | * Create proper predecessor/successor links between the previous | |
411 | * source and the current one. | |
412 | */ | |
413 | gn = Targ_FindNode(src, TARG_CREATE); | |
414 | if (predecessor != NILGNODE) { | |
415 | (void)Lst_AtEnd(predecessor->successors, (ClientData)gn); | |
416 | (void)Lst_AtEnd(gn->preds, (ClientData)predecessor); | |
417 | } | |
418 | /* | |
419 | * The current source now becomes the predecessor for the next one. | |
420 | */ | |
421 | predecessor = gn; | |
422 | } else { | |
423 | /* | |
424 | * If the source is not an attribute, we need to find/create | |
425 | * a node for it. After that we can apply any operator to it | |
426 | * from a special target or link it to its parents, as | |
427 | * appropriate. | |
428 | * | |
429 | * In the case of a source that was the object of a :: operator, | |
430 | * the attribute is applied to all of its instances (as kept in | |
431 | * the 'cohorts' list of the node) or all the cohorts are linked | |
432 | * to all the targets. | |
433 | */ | |
434 | gn = Targ_FindNode (src, TARG_CREATE); | |
435 | if (tOp) { | |
436 | gn->type |= tOp; | |
437 | } else { | |
438 | Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn); | |
439 | } | |
440 | if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { | |
441 | register GNode *cohort; | |
442 | register LstNode ln; | |
443 | ||
444 | for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){ | |
445 | cohort = (GNode *)Lst_Datum(ln); | |
446 | if (tOp) { | |
447 | cohort->type |= tOp; | |
448 | } else { | |
449 | Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort); | |
450 | } | |
451 | } | |
452 | } | |
453 | } | |
454 | } | |
182ca07d | 455 | |
ab950546 KB |
456 | /*- |
457 | *----------------------------------------------------------------------- | |
458 | * ParseFindMain -- | |
459 | * Find a real target in the list and set it to be the main one. | |
460 | * Called by ParseDoDependency when a main target hasn't been found | |
461 | * yet. | |
462 | * | |
463 | * Results: | |
464 | * 0 if main not found yet, 1 if it is. | |
465 | * | |
466 | * Side Effects: | |
467 | * mainNode is changed and Targ_SetMain is called. | |
468 | * | |
469 | *----------------------------------------------------------------------- | |
470 | */ | |
471 | static int | |
472 | ParseFindMain(gn) | |
473 | GNode *gn; /* Node to examine */ | |
474 | { | |
475 | if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) { | |
476 | mainNode = gn; | |
477 | Targ_SetMain(gn); | |
478 | return (1); | |
479 | } else { | |
480 | return (0); | |
481 | } | |
482 | } | |
182ca07d | 483 | |
ab950546 KB |
484 | /*- |
485 | *----------------------------------------------------------------------- | |
486 | * ParseAddDir -- | |
487 | * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going | |
488 | * | |
489 | * Results: | |
490 | * === 0 | |
491 | * | |
492 | * Side Effects: | |
493 | * See Dir_AddDir. | |
494 | * | |
495 | *----------------------------------------------------------------------- | |
496 | */ | |
497 | static int | |
498 | ParseAddDir(path, name) | |
499 | Lst path; | |
500 | char *name; | |
501 | { | |
502 | Dir_AddDir(path, name); | |
503 | return(0); | |
504 | } | |
182ca07d | 505 | |
ab950546 KB |
506 | /*- |
507 | *----------------------------------------------------------------------- | |
508 | * ParseClearPath -- | |
509 | * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going | |
510 | * | |
511 | * Results: | |
512 | * === 0 | |
513 | * | |
514 | * Side Effects: | |
515 | * See Dir_ClearPath | |
516 | * | |
517 | *----------------------------------------------------------------------- | |
518 | */ | |
519 | static int | |
520 | ParseClearPath(path) | |
521 | Lst path; | |
522 | { | |
523 | Dir_ClearPath(path); | |
524 | return(0); | |
525 | } | |
182ca07d | 526 | |
ab950546 KB |
527 | /*- |
528 | *--------------------------------------------------------------------- | |
529 | * ParseDoDependency -- | |
530 | * Parse the dependency line in line. | |
531 | * | |
532 | * Results: | |
533 | * None | |
534 | * | |
535 | * Side Effects: | |
536 | * The nodes of the sources are linked as children to the nodes of the | |
537 | * targets. Some nodes may be created. | |
538 | * | |
539 | * We parse a dependency line by first extracting words from the line and | |
540 | * finding nodes in the list of all targets with that name. This is done | |
541 | * until a character is encountered which is an operator character. Currently | |
542 | * these are only ! and :. At this point the operator is parsed and the | |
543 | * pointer into the line advanced until the first source is encountered. | |
544 | * The parsed operator is applied to each node in the 'targets' list, | |
545 | * which is where the nodes found for the targets are kept, by means of | |
546 | * the ParseDoOp function. | |
547 | * The sources are read in much the same way as the targets were except | |
548 | * that now they are expanded using the wildcarding scheme of the C-Shell | |
549 | * and all instances of the resulting words in the list of all targets | |
550 | * are found. Each of the resulting nodes is then linked to each of the | |
551 | * targets as one of its children. | |
552 | * Certain targets are handled specially. These are the ones detailed | |
553 | * by the specType variable. | |
554 | * The storing of transformation rules is also taken care of here. | |
555 | * A target is recognized as a transformation rule by calling | |
556 | * Suff_IsTransform. If it is a transformation rule, its node is gotten | |
557 | * from the suffix module via Suff_AddTransform rather than the standard | |
558 | * Targ_FindNode in the target module. | |
559 | *--------------------------------------------------------------------- | |
560 | */ | |
561 | static void | |
562 | ParseDoDependency (line) | |
563 | char *line; /* the line to parse */ | |
564 | { | |
565 | register char *cp; /* our current position */ | |
566 | register GNode *gn; /* a general purpose temporary node */ | |
567 | register int op; /* the operator on the line */ | |
568 | char savec; /* a place to save a character */ | |
569 | Lst paths; /* List of search paths to alter when parsing | |
570 | * a list of .PATH targets */ | |
571 | int tOp; /* operator from special target */ | |
572 | Lst sources; /* list of source names after expansion */ | |
573 | Lst curTargs; /* list of target names to be found and added | |
574 | * to the targets list */ | |
575 | ||
576 | tOp = 0; | |
577 | ||
578 | specType = Not; | |
579 | paths = (Lst)NULL; | |
580 | ||
581 | curTargs = Lst_Init(FALSE); | |
582 | ||
583 | do { | |
584 | for (cp = line; | |
585 | *cp && !isspace (*cp) && | |
586 | (*cp != '!') && (*cp != ':') && (*cp != '('); | |
587 | cp++) | |
588 | { | |
589 | if (*cp == '$') { | |
590 | /* | |
591 | * Must be a dynamic source (would have been expanded | |
592 | * otherwise), so call the Var module to parse the puppy | |
593 | * so we can safely advance beyond it...There should be | |
594 | * no errors in this, as they would have been discovered | |
595 | * in the initial Var_Subst and we wouldn't be here. | |
596 | */ | |
597 | int length; | |
598 | Boolean freeIt; | |
599 | char *result; | |
600 | ||
601 | result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt); | |
602 | ||
603 | if (freeIt) { | |
604 | free(result); | |
605 | } | |
606 | cp += length-1; | |
607 | } | |
608 | continue; | |
609 | } | |
610 | if (*cp == '(') { | |
611 | /* | |
612 | * Archives must be handled specially to make sure the OP_ARCHV | |
613 | * flag is set in their 'type' field, for one thing, and because | |
614 | * things like "archive(file1.o file2.o file3.o)" are permissible. | |
615 | * Arch_ParseArchive will set 'line' to be the first non-blank | |
616 | * after the archive-spec. It creates/finds nodes for the members | |
617 | * and places them on the given list, returning SUCCESS if all | |
618 | * went well and FAILURE if there was an error in the | |
619 | * specification. On error, line should remain untouched. | |
620 | */ | |
621 | if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) { | |
622 | Parse_Error (PARSE_FATAL, | |
623 | "Error in archive specification: \"%s\"", line); | |
624 | return; | |
625 | } else { | |
626 | continue; | |
627 | } | |
628 | } | |
629 | savec = *cp; | |
630 | ||
631 | if (!*cp) { | |
632 | /* | |
633 | * Ending a dependency line without an operator is a Bozo | |
634 | * no-no | |
635 | */ | |
636 | Parse_Error (PARSE_FATAL, "Need an operator"); | |
637 | return; | |
638 | } | |
639 | *cp = '\0'; | |
640 | /* | |
641 | * Have a word in line. See if it's a special target and set | |
642 | * specType to match it. | |
643 | */ | |
644 | if (*line == '.' && isupper (line[1])) { | |
645 | /* | |
646 | * See if the target is a special target that must have it | |
647 | * or its sources handled specially. | |
648 | */ | |
649 | int keywd = ParseFindKeyword(line); | |
650 | if (keywd != -1) { | |
651 | if (specType == Path && parseKeywords[keywd].spec != Path) { | |
652 | Parse_Error(PARSE_FATAL, "Mismatched special targets"); | |
653 | return; | |
654 | } | |
655 | ||
656 | specType = parseKeywords[keywd].spec; | |
657 | tOp = parseKeywords[keywd].op; | |
658 | ||
659 | /* | |
660 | * Certain special targets have special semantics: | |
661 | * .PATH Have to set the dirSearchPath | |
662 | * variable too | |
ab950546 KB |
663 | * .MAIN Its sources are only used if |
664 | * nothing has been specified to | |
665 | * create. | |
666 | * .DEFAULT Need to create a node to hang | |
667 | * commands on, but we don't want | |
668 | * it in the graph, nor do we want | |
669 | * it to be the Main Target, so we | |
670 | * create it, set OP_NOTMAIN and | |
671 | * add it to the list, setting | |
672 | * DEFAULT to the new node for | |
673 | * later use. We claim the node is | |
674 | * A transformation rule to make | |
675 | * life easier later, when we'll | |
676 | * use Make_HandleUse to actually | |
677 | * apply the .DEFAULT commands. | |
678 | * .BEGIN | |
679 | * .END | |
680 | * .INTERRUPT Are not to be considered the | |
681 | * main target. | |
682 | * .NOTPARALLEL Make only one target at a time. | |
683 | * .SINGLESHELL Create a shell for each command. | |
684 | * .ORDER Must set initial predecessor to NIL | |
685 | */ | |
686 | switch (specType) { | |
687 | case Path: | |
688 | if (paths == NULL) { | |
689 | paths = Lst_Init(FALSE); | |
690 | } | |
691 | (void)Lst_AtEnd(paths, (ClientData)dirSearchPath); | |
692 | break; | |
ab950546 KB |
693 | case Main: |
694 | if (!Lst_IsEmpty(create)) { | |
695 | specType = Not; | |
696 | } | |
697 | break; | |
698 | case Begin: | |
699 | case End: | |
700 | case Interrupt: | |
701 | gn = Targ_FindNode(line, TARG_CREATE); | |
702 | gn->type |= OP_NOTMAIN; | |
703 | (void)Lst_AtEnd(targets, (ClientData)gn); | |
704 | break; | |
705 | case Default: | |
706 | gn = Targ_NewGN(".DEFAULT"); | |
707 | gn->type |= (OP_NOTMAIN|OP_TRANSFORM); | |
708 | (void)Lst_AtEnd(targets, (ClientData)gn); | |
709 | DEFAULT = gn; | |
710 | break; | |
711 | case NotParallel: | |
712 | { | |
713 | extern int maxJobs; | |
714 | ||
715 | maxJobs = 1; | |
716 | break; | |
717 | } | |
718 | case SingleShell: | |
b6cda174 | 719 | /* backwards = 1; */ |
ab950546 KB |
720 | break; |
721 | case Order: | |
722 | predecessor = NILGNODE; | |
723 | break; | |
724 | } | |
725 | } else if (strncmp (line, ".PATH", 5) == 0) { | |
726 | /* | |
727 | * .PATH<suffix> has to be handled specially. | |
728 | * Call on the suffix module to give us a path to | |
729 | * modify. | |
730 | */ | |
731 | Lst path; | |
732 | ||
733 | specType = Path; | |
734 | path = Suff_GetPath (&line[5]); | |
735 | if (path == NILLST) { | |
736 | Parse_Error (PARSE_FATAL, | |
737 | "Suffix '%s' not defined (yet)", | |
738 | &line[5]); | |
739 | return; | |
740 | } else { | |
741 | if (paths == (Lst)NULL) { | |
742 | paths = Lst_Init(FALSE); | |
743 | } | |
744 | (void)Lst_AtEnd(paths, (ClientData)path); | |
745 | } | |
746 | } | |
747 | } | |
748 | ||
749 | /* | |
750 | * Have word in line. Get or create its node and stick it at | |
751 | * the end of the targets list | |
752 | */ | |
753 | if ((specType == Not) && (*line != '\0')) { | |
754 | if (Dir_HasWildcards(line)) { | |
755 | /* | |
756 | * Targets are to be sought only in the current directory, | |
757 | * so create an empty path for the thing. Note we need to | |
758 | * use Dir_Destroy in the destruction of the path as the | |
759 | * Dir module could have added a directory to the path... | |
760 | */ | |
761 | Lst emptyPath = Lst_Init(FALSE); | |
762 | ||
763 | Dir_Expand(line, emptyPath, curTargs); | |
764 | ||
765 | Lst_Destroy(emptyPath, Dir_Destroy); | |
766 | } else { | |
767 | /* | |
768 | * No wildcards, but we want to avoid code duplication, | |
769 | * so create a list with the word on it. | |
770 | */ | |
771 | (void)Lst_AtEnd(curTargs, (ClientData)line); | |
772 | } | |
773 | ||
774 | while(!Lst_IsEmpty(curTargs)) { | |
775 | char *targName = (char *)Lst_DeQueue(curTargs); | |
776 | ||
777 | if (!Suff_IsTransform (targName)) { | |
778 | gn = Targ_FindNode (targName, TARG_CREATE); | |
779 | } else { | |
780 | gn = Suff_AddTransform (targName); | |
781 | } | |
782 | ||
783 | (void)Lst_AtEnd (targets, (ClientData)gn); | |
784 | } | |
785 | } else if (specType == Path && *line != '.' && *line != '\0') { | |
786 | Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); | |
787 | } | |
788 | ||
789 | *cp = savec; | |
790 | /* | |
791 | * If it is a special type and not .PATH, it's the only target we | |
792 | * allow on this line... | |
793 | */ | |
794 | if (specType != Not && specType != Path) { | |
795 | Boolean warn = FALSE; | |
796 | ||
797 | while ((*cp != '!') && (*cp != ':') && *cp) { | |
798 | if (*cp != ' ' && *cp != '\t') { | |
799 | warn = TRUE; | |
800 | } | |
801 | cp++; | |
802 | } | |
803 | if (warn) { | |
804 | Parse_Error(PARSE_WARNING, "Extra target ignored"); | |
805 | } | |
806 | } else { | |
807 | while (*cp && isspace (*cp)) { | |
808 | cp++; | |
809 | } | |
810 | } | |
811 | line = cp; | |
812 | } while ((*line != '!') && (*line != ':') && *line); | |
813 | ||
814 | /* | |
815 | * Don't need the list of target names anymore... | |
816 | */ | |
817 | Lst_Destroy(curTargs, NOFREE); | |
818 | ||
819 | if (!Lst_IsEmpty(targets)) { | |
820 | switch(specType) { | |
821 | default: | |
822 | Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); | |
823 | break; | |
824 | case Default: | |
825 | case Begin: | |
826 | case End: | |
827 | case Interrupt: | |
828 | /* | |
829 | * These four create nodes on which to hang commands, so | |
830 | * targets shouldn't be empty... | |
831 | */ | |
832 | case Not: | |
833 | /* | |
834 | * Nothing special here -- targets can be empty if it wants. | |
835 | */ | |
836 | break; | |
837 | } | |
838 | } | |
839 | ||
840 | /* | |
841 | * Have now parsed all the target names. Must parse the operator next. The | |
842 | * result is left in op . | |
843 | */ | |
844 | if (*cp == '!') { | |
845 | op = OP_FORCE; | |
846 | } else if (*cp == ':') { | |
847 | if (cp[1] == ':') { | |
848 | op = OP_DOUBLEDEP; | |
849 | cp++; | |
850 | } else { | |
851 | op = OP_DEPENDS; | |
852 | } | |
853 | } else { | |
854 | Parse_Error (PARSE_FATAL, "Missing dependency operator"); | |
855 | return; | |
856 | } | |
857 | ||
858 | cp++; /* Advance beyond operator */ | |
859 | ||
860 | Lst_ForEach (targets, ParseDoOp, (ClientData)op); | |
861 | ||
862 | /* | |
863 | * Get to the first source | |
864 | */ | |
865 | while (*cp && isspace (*cp)) { | |
866 | cp++; | |
867 | } | |
868 | line = cp; | |
869 | ||
870 | /* | |
871 | * Several special targets take different actions if present with no | |
872 | * sources: | |
873 | * a .SUFFIXES line with no sources clears out all old suffixes | |
874 | * a .PRECIOUS line makes all targets precious | |
875 | * a .IGNORE line ignores errors for all targets | |
876 | * a .SILENT line creates silence when making all targets | |
877 | * a .PATH removes all directories from the search path(s). | |
ab950546 KB |
878 | */ |
879 | if (!*line) { | |
880 | switch (specType) { | |
881 | case Suffixes: | |
882 | Suff_ClearSuffixes (); | |
883 | break; | |
884 | case Precious: | |
885 | allPrecious = TRUE; | |
886 | break; | |
887 | case Ignore: | |
888 | ignoreErrors = TRUE; | |
889 | break; | |
890 | case Silent: | |
891 | beSilent = TRUE; | |
892 | break; | |
893 | case Path: | |
894 | Lst_ForEach(paths, ParseClearPath, (ClientData)NULL); | |
895 | break; | |
ab950546 KB |
896 | } |
897 | } else if (specType == MFlags) { | |
898 | /* | |
899 | * Call on functions in main.c to deal with these arguments and | |
900 | * set the initial character to a null-character so the loop to | |
901 | * get sources won't get anything | |
902 | */ | |
903 | Main_ParseArgLine (line); | |
904 | *line = '\0'; | |
905 | } else if (specType == Shell) { | |
906 | if (Job_ParseShell (line) != SUCCESS) { | |
907 | Parse_Error (PARSE_FATAL, "improper shell specification"); | |
908 | return; | |
909 | } | |
910 | *line = '\0'; | |
911 | } else if ((specType == NotParallel) || (specType == SingleShell)) { | |
912 | *line = '\0'; | |
913 | } | |
914 | ||
915 | /* | |
916 | * NOW GO FOR THE SOURCES | |
917 | */ | |
918 | if ((specType == Suffixes) || (specType == Path) || | |
919 | (specType == Includes) || (specType == Libs) || | |
21859cc6 | 920 | (specType == Null)) |
ab950546 KB |
921 | { |
922 | while (*line) { | |
923 | /* | |
924 | * If the target was one that doesn't take files as its sources | |
925 | * but takes something like suffixes, we take each | |
926 | * space-separated word on the line as a something and deal | |
927 | * with it accordingly. | |
928 | * | |
929 | * If the target was .SUFFIXES, we take each source as a | |
930 | * suffix and add it to the list of suffixes maintained by the | |
931 | * Suff module. | |
932 | * | |
933 | * If the target was a .PATH, we add the source as a directory | |
934 | * to search on the search path. | |
935 | * | |
936 | * If it was .INCLUDES, the source is taken to be the suffix of | |
937 | * files which will be #included and whose search path should | |
938 | * be present in the .INCLUDES variable. | |
939 | * | |
940 | * If it was .LIBS, the source is taken to be the suffix of | |
941 | * files which are considered libraries and whose search path | |
942 | * should be present in the .LIBS variable. | |
943 | * | |
ab950546 KB |
944 | * If it was .NULL, the source is the suffix to use when a file |
945 | * has no valid suffix. | |
946 | */ | |
947 | char savec; | |
948 | while (*cp && !isspace (*cp)) { | |
949 | cp++; | |
950 | } | |
951 | savec = *cp; | |
952 | *cp = '\0'; | |
953 | switch (specType) { | |
954 | case Suffixes: | |
955 | Suff_AddSuffix (line); | |
956 | break; | |
957 | case Path: | |
958 | Lst_ForEach(paths, ParseAddDir, (ClientData)line); | |
959 | break; | |
960 | case Includes: | |
961 | Suff_AddInclude (line); | |
962 | break; | |
963 | case Libs: | |
964 | Suff_AddLib (line); | |
965 | break; | |
ab950546 KB |
966 | case Null: |
967 | Suff_SetNull (line); | |
968 | break; | |
969 | } | |
970 | *cp = savec; | |
971 | if (savec != '\0') { | |
972 | cp++; | |
973 | } | |
974 | while (*cp && isspace (*cp)) { | |
975 | cp++; | |
976 | } | |
977 | line = cp; | |
978 | } | |
979 | if (paths) { | |
980 | Lst_Destroy(paths, NOFREE); | |
981 | } | |
982 | } else { | |
983 | while (*line) { | |
984 | /* | |
985 | * The targets take real sources, so we must beware of archive | |
986 | * specifications (i.e. things with left parentheses in them) | |
987 | * and handle them accordingly. | |
988 | */ | |
989 | while (*cp && !isspace (*cp)) { | |
990 | if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) { | |
991 | /* | |
992 | * Only stop for a left parenthesis if it isn't at the | |
993 | * start of a word (that'll be for variable changes | |
994 | * later) and isn't preceded by a dollar sign (a dynamic | |
995 | * source). | |
996 | */ | |
997 | break; | |
998 | } else { | |
999 | cp++; | |
1000 | } | |
1001 | } | |
1002 | ||
1003 | if (*cp == '(') { | |
1004 | GNode *gn; | |
1005 | ||
1006 | sources = Lst_Init (FALSE); | |
1007 | if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) { | |
1008 | Parse_Error (PARSE_FATAL, | |
1009 | "Error in source archive spec \"%s\"", line); | |
1010 | return; | |
1011 | } | |
1012 | ||
1013 | while (!Lst_IsEmpty (sources)) { | |
1014 | gn = (GNode *) Lst_DeQueue (sources); | |
1015 | ParseDoSrc (tOp, gn->name); | |
1016 | } | |
1017 | Lst_Destroy (sources, NOFREE); | |
1018 | cp = line; | |
1019 | } else { | |
1020 | if (*cp) { | |
1021 | *cp = '\0'; | |
1022 | cp += 1; | |
1023 | } | |
1024 | ||
1025 | ParseDoSrc (tOp, line); | |
1026 | } | |
1027 | while (*cp && isspace (*cp)) { | |
1028 | cp++; | |
1029 | } | |
1030 | line = cp; | |
1031 | } | |
1032 | } | |
1033 | ||
1034 | if (mainNode == NILGNODE) { | |
1035 | /* | |
1036 | * If we have yet to decide on a main target to make, in the | |
1037 | * absence of any user input, we want the first target on | |
1038 | * the first dependency line that is actually a real target | |
1039 | * (i.e. isn't a .USE or .EXEC rule) to be made. | |
1040 | */ | |
1041 | Lst_ForEach (targets, ParseFindMain, (ClientData)0); | |
1042 | } | |
1043 | ||
1044 | } | |
182ca07d | 1045 | |
ab950546 KB |
1046 | /*- |
1047 | *--------------------------------------------------------------------- | |
1048 | * Parse_IsVar -- | |
1049 | * Return TRUE if the passed line is a variable assignment. A variable | |
1050 | * assignment consists of a single word followed by optional whitespace | |
1051 | * followed by either a += or an = operator. | |
1052 | * This function is used both by the Parse_File function and main when | |
1053 | * parsing the command-line arguments. | |
1054 | * | |
1055 | * Results: | |
1056 | * TRUE if it is. FALSE if it ain't | |
1057 | * | |
1058 | * Side Effects: | |
1059 | * none | |
1060 | *--------------------------------------------------------------------- | |
1061 | */ | |
1062 | Boolean | |
1063 | Parse_IsVar (line) | |
1064 | register char *line; /* the line to check */ | |
1065 | { | |
1066 | register Boolean wasSpace = FALSE; /* set TRUE if found a space */ | |
1067 | register Boolean haveName = FALSE; /* Set TRUE if have a variable name */ | |
1068 | ||
1069 | /* | |
1070 | * Skip to variable name | |
1071 | */ | |
1072 | while ((*line == ' ') || (*line == '\t')) { | |
1073 | line++; | |
1074 | } | |
1075 | ||
1076 | while (*line != '=') { | |
1077 | if (*line == '\0') { | |
1078 | /* | |
1079 | * end-of-line -- can't be a variable assignment. | |
1080 | */ | |
1081 | return (FALSE); | |
1082 | } else if ((*line == ' ') || (*line == '\t')) { | |
1083 | /* | |
1084 | * there can be as much white space as desired so long as there is | |
1085 | * only one word before the operator | |
1086 | */ | |
1087 | wasSpace = TRUE; | |
1088 | } else if (wasSpace && haveName) { | |
1089 | /* | |
1090 | * Stop when an = operator is found. | |
1091 | */ | |
1092 | if ((*line == '+') || (*line == ':') || (*line == '?') || | |
1093 | (*line == '!')) { | |
1094 | break; | |
1095 | } | |
1096 | ||
1097 | /* | |
1098 | * This is the start of another word, so not assignment. | |
1099 | */ | |
1100 | return (FALSE); | |
1101 | } else { | |
1102 | haveName = TRUE; | |
1103 | wasSpace = FALSE; | |
1104 | } | |
1105 | line++; | |
1106 | } | |
1107 | ||
1108 | /* | |
1109 | * A final check: if we stopped on a +, ?, ! or :, the next character must | |
1110 | * be an = or it ain't a valid assignment | |
1111 | */ | |
1112 | if (((*line == '+') || | |
1113 | (*line == '?') || | |
1114 | (*line == ':') || | |
1115 | (*line == '!')) && | |
1116 | (line[1] != '=')) | |
1117 | { | |
1118 | return (FALSE); | |
1119 | } else { | |
1120 | return (haveName); | |
1121 | } | |
1122 | } | |
182ca07d | 1123 | |
ab950546 KB |
1124 | /*- |
1125 | *--------------------------------------------------------------------- | |
1126 | * Parse_DoVar -- | |
1127 | * Take the variable assignment in the passed line and do it in the | |
1128 | * global context. | |
1129 | * | |
1130 | * Note: There is a lexical ambiguity with assignment modifier characters | |
1131 | * in variable names. This routine interprets the character before the = | |
1132 | * as a modifier. Therefore, an assignment like | |
1133 | * C++=/usr/bin/CC | |
1134 | * is interpreted as "C+ +=" instead of "C++ =". | |
1135 | * | |
1136 | * Results: | |
1137 | * none | |
1138 | * | |
1139 | * Side Effects: | |
1140 | * the variable structure of the given variable name is altered in the | |
1141 | * global context. | |
1142 | *--------------------------------------------------------------------- | |
1143 | */ | |
1144 | void | |
1145 | Parse_DoVar (line, ctxt) | |
1146 | char *line; /* a line guaranteed to be a variable | |
1147 | * assignment. This reduces error checks */ | |
1148 | GNode *ctxt; /* Context in which to do the assignment */ | |
1149 | { | |
1150 | register char *cp; /* pointer into line */ | |
1151 | enum { | |
1152 | VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL | |
1153 | } type; /* Type of assignment */ | |
1154 | char *opc; /* ptr to operator character to | |
1155 | * null-terminate the variable name */ | |
1156 | ||
1157 | /* | |
1158 | * Skip to variable name | |
1159 | */ | |
1160 | while ((*line == ' ') || (*line == '\t')) { | |
1161 | line++; | |
1162 | } | |
1163 | ||
1164 | /* | |
1165 | * Skip to operator character, nulling out whitespace as we go | |
1166 | */ | |
1167 | for (cp = line + 1; *cp != '='; cp++) { | |
1168 | if (isspace (*cp)) { | |
1169 | *cp = '\0'; | |
1170 | } | |
1171 | } | |
1172 | opc = cp-1; /* operator is the previous character */ | |
1173 | *cp++ = '\0'; /* nuke the = */ | |
1174 | ||
1175 | /* | |
1176 | * Check operator type | |
1177 | */ | |
1178 | switch (*opc) { | |
1179 | case '+': | |
1180 | type = VAR_APPEND; | |
1181 | *opc = '\0'; | |
1182 | break; | |
1183 | ||
1184 | case '?': | |
1185 | /* | |
1186 | * If the variable already has a value, we don't do anything. | |
1187 | */ | |
1188 | *opc = '\0'; | |
1189 | if (Var_Exists(line, ctxt)) { | |
1190 | return; | |
1191 | } else { | |
1192 | type = VAR_NORMAL; | |
1193 | } | |
1194 | break; | |
1195 | ||
1196 | case ':': | |
1197 | type = VAR_SUBST; | |
1198 | *opc = '\0'; | |
1199 | break; | |
1200 | ||
1201 | case '!': | |
1202 | type = VAR_SHELL; | |
1203 | *opc = '\0'; | |
1204 | break; | |
1205 | ||
1206 | default: | |
1207 | type = VAR_NORMAL; | |
1208 | break; | |
1209 | } | |
1210 | ||
1211 | while (isspace (*cp)) { | |
1212 | cp++; | |
1213 | } | |
1214 | ||
1215 | if (type == VAR_APPEND) { | |
1216 | Var_Append (line, cp, ctxt); | |
1217 | } else if (type == VAR_SUBST) { | |
1218 | /* | |
1219 | * Allow variables in the old value to be undefined, but leave their | |
1220 | * invocation alone -- this is done by forcing oldVars to be false. | |
1221 | * XXX: This can cause recursive variables, but that's not hard to do, | |
1222 | * and this allows someone to do something like | |
1223 | * | |
1224 | * CFLAGS = $(.INCLUDES) | |
1225 | * CFLAGS := -I.. $(CFLAGS) | |
1226 | * | |
1227 | * And not get an error. | |
1228 | */ | |
1229 | Boolean oldOldVars = oldVars; | |
1230 | ||
1231 | oldVars = FALSE; | |
1232 | cp = Var_Subst(cp, ctxt, FALSE); | |
1233 | oldVars = oldOldVars; | |
1234 | ||
1235 | Var_Set(line, cp, ctxt); | |
1236 | free(cp); | |
1237 | } else if (type == VAR_SHELL) { | |
1238 | char result[BUFSIZ]; /* Result of command */ | |
1239 | char *args[4]; /* Args for invoking the shell */ | |
1240 | int fds[2]; /* Pipe streams */ | |
1241 | int cpid; /* Child PID */ | |
1242 | int pid; /* PID from wait() */ | |
1243 | Boolean freeCmd; /* TRUE if the command needs to be freed, i.e. | |
1244 | * if any variable expansion was performed */ | |
1245 | ||
1246 | /* | |
1247 | * Set up arguments for shell | |
1248 | */ | |
1249 | args[0] = "sh"; | |
1250 | args[1] = "-c"; | |
1251 | if (index(cp, '$') != (char *)NULL) { | |
1252 | /* | |
1253 | * There's a dollar sign in the command, so perform variable | |
1254 | * expansion on the whole thing. The resulting string will need | |
1255 | * freeing when we're done, so set freeCmd to TRUE. | |
1256 | */ | |
1257 | args[2] = Var_Subst(cp, VAR_CMD, TRUE); | |
1258 | freeCmd = TRUE; | |
1259 | } else { | |
1260 | args[2] = cp; | |
1261 | freeCmd = FALSE; | |
1262 | } | |
1263 | args[3] = (char *)NULL; | |
1264 | ||
1265 | /* | |
1266 | * Open a pipe for fetching its output | |
1267 | */ | |
1268 | pipe(fds); | |
1269 | ||
1270 | /* | |
1271 | * Fork | |
1272 | */ | |
1273 | cpid = vfork(); | |
1274 | if (cpid == 0) { | |
1275 | /* | |
1276 | * Close input side of pipe | |
1277 | */ | |
1278 | close(fds[0]); | |
1279 | ||
1280 | /* | |
1281 | * Duplicate the output stream to the shell's output, then | |
1282 | * shut the extra thing down. Note we don't fetch the error | |
1283 | * stream...why not? Why? | |
1284 | */ | |
1285 | dup2(fds[1], 1); | |
1286 | close(fds[1]); | |
1287 | ||
1288 | execv("/bin/sh", args); | |
1289 | _exit(1); | |
1290 | } else if (cpid < 0) { | |
1291 | /* | |
1292 | * Couldn't fork -- tell the user and make the variable null | |
1293 | */ | |
1294 | Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp); | |
1295 | Var_Set(line, "", ctxt); | |
1296 | } else { | |
1297 | int status; | |
1298 | int cc; | |
1299 | ||
1300 | /* | |
1301 | * No need for the writing half | |
1302 | */ | |
1303 | close(fds[1]); | |
1304 | ||
1305 | /* | |
1306 | * Wait for the process to exit. | |
1307 | * | |
1308 | * XXX: If the child writes more than a pipe's worth, we will | |
1309 | * deadlock. | |
1310 | */ | |
1311 | while(((pid = wait(&status)) != cpid) && (pid >= 0)) { | |
1312 | ; | |
1313 | } | |
1314 | ||
1315 | /* | |
1316 | * Read all the characters the child wrote. | |
1317 | */ | |
1318 | cc = read(fds[0], result, sizeof(result)); | |
1319 | ||
1320 | if (cc < 0) { | |
1321 | /* | |
1322 | * Couldn't read the child's output -- tell the user and | |
1323 | * set the variable to null | |
1324 | */ | |
1325 | Parse_Error(PARSE_WARNING, "Couldn't read shell's output"); | |
1326 | cc = 0; | |
1327 | } | |
1328 | ||
1329 | if (status) { | |
1330 | /* | |
1331 | * Child returned an error -- tell the user but still use | |
1332 | * the result. | |
1333 | */ | |
1334 | Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp); | |
1335 | } | |
1336 | /* | |
1337 | * Null-terminate the result, convert newlines to spaces and | |
1338 | * install it in the variable. | |
1339 | */ | |
1340 | result[cc] = '\0'; | |
1341 | cp = &result[cc] - 1; | |
1342 | ||
1343 | if (*cp == '\n') { | |
1344 | /* | |
1345 | * A final newline is just stripped | |
1346 | */ | |
1347 | *cp-- = '\0'; | |
1348 | } | |
1349 | while (cp >= result) { | |
1350 | if (*cp == '\n') { | |
1351 | *cp = ' '; | |
1352 | } | |
1353 | cp--; | |
1354 | } | |
1355 | Var_Set(line, result, ctxt); | |
1356 | ||
1357 | /* | |
1358 | * Close the input side of the pipe. | |
1359 | */ | |
1360 | close(fds[0]); | |
1361 | } | |
1362 | if (freeCmd) { | |
1363 | free(args[2]); | |
1364 | } | |
1365 | } else { | |
1366 | /* | |
1367 | * Normal assignment -- just do it. | |
1368 | */ | |
1369 | Var_Set (line, cp, ctxt); | |
1370 | } | |
1371 | } | |
182ca07d | 1372 | |
ab950546 | 1373 | /*- |
ab950546 KB |
1374 | * ParseAddCmd -- |
1375 | * Lst_ForEach function to add a command line to all targets | |
1376 | * | |
1377 | * Results: | |
1378 | * Always 0 | |
1379 | * | |
1380 | * Side Effects: | |
1381 | * A new element is added to the commands list of the node. | |
ab950546 | 1382 | */ |
8b2fa9f8 KB |
1383 | static |
1384 | ParseAddCmd(gn, cmd) | |
1385 | GNode *gn; /* the node to which the command is to be added */ | |
1386 | char *cmd; /* the command to add */ | |
ab950546 | 1387 | { |
8b2fa9f8 KB |
1388 | /* if target already supplied, ignore commands */ |
1389 | if (!(gn->type & OP_HAS_COMMANDS)) | |
1390 | (void)Lst_AtEnd(gn->commands, (ClientData)cmd); | |
1391 | return(0); | |
ab950546 | 1392 | } |
182ca07d | 1393 | |
ab950546 KB |
1394 | /*- |
1395 | *----------------------------------------------------------------------- | |
1396 | * ParseHasCommands -- | |
1397 | * Callback procedure for Parse_File when destroying the list of | |
1398 | * targets on the last dependency line. Marks a target as already | |
1399 | * having commands if it does, to keep from having shell commands | |
1400 | * on multiple dependency lines. | |
1401 | * | |
1402 | * Results: | |
1403 | * Always 0. | |
1404 | * | |
1405 | * Side Effects: | |
1406 | * OP_HAS_COMMANDS may be set for the target. | |
1407 | * | |
1408 | *----------------------------------------------------------------------- | |
1409 | */ | |
1410 | static int | |
1411 | ParseHasCommands(gn) | |
1412 | GNode *gn; /* Node to examine */ | |
1413 | { | |
1414 | if (!Lst_IsEmpty(gn->commands)) { | |
1415 | gn->type |= OP_HAS_COMMANDS; | |
1416 | } | |
1417 | return(0); | |
1418 | } | |
182ca07d | 1419 | |
ab950546 KB |
1420 | /*- |
1421 | *----------------------------------------------------------------------- | |
1422 | * Parse_AddIncludeDir -- | |
1423 | * Add a directory to the path searched for included makefiles | |
1424 | * bracketed by double-quotes. Used by functions in main.c | |
1425 | * | |
1426 | * Results: | |
1427 | * None. | |
1428 | * | |
1429 | * Side Effects: | |
1430 | * The directory is appended to the list. | |
1431 | * | |
1432 | *----------------------------------------------------------------------- | |
1433 | */ | |
1434 | void | |
1435 | Parse_AddIncludeDir (dir) | |
1436 | char *dir; /* The name of the directory to add */ | |
1437 | { | |
1438 | Dir_AddDir (parseIncPath, dir); | |
1439 | } | |
182ca07d | 1440 | |
ab950546 KB |
1441 | /*- |
1442 | *--------------------------------------------------------------------- | |
1443 | * ParseDoInclude -- | |
1444 | * Push to another file. | |
1445 | * | |
1446 | * The input is the line minus the #include. A file spec is a string | |
1447 | * enclosed in <> or "". The former is looked for only in sysIncPath. | |
1448 | * The latter in . and the directories specified by -I command line | |
1449 | * options | |
1450 | * | |
1451 | * Results: | |
1452 | * None | |
1453 | * | |
1454 | * Side Effects: | |
1455 | * A structure is added to the includes Lst and readProc, lineno, | |
1456 | * fname and curFILE are altered for the new file | |
1457 | *--------------------------------------------------------------------- | |
1458 | */ | |
1459 | static void | |
1460 | ParseDoInclude (file) | |
1461 | char *file; /* file specification */ | |
1462 | { | |
1463 | char *fullname; /* full pathname of file */ | |
1464 | IFile *oldFile; /* state associated with current file */ | |
1465 | Lst path; /* the path to use to find the file */ | |
1466 | char endc; /* the character which ends the file spec */ | |
1467 | char *cp; /* current position in file spec */ | |
1468 | Boolean isSystem; /* TRUE if makefile is a system makefile */ | |
1469 | ||
1470 | /* | |
1471 | * Skip to delimiter character so we know where to look | |
1472 | */ | |
1473 | while ((*file == ' ') || (*file == '\t')) { | |
1474 | file++; | |
1475 | } | |
1476 | ||
1477 | if ((*file != '"') && (*file != '<')) { | |
81afae5c KB |
1478 | Parse_Error (PARSE_FATAL, |
1479 | ".include filename must be delimited by '\"' or '<'"); | |
ab950546 KB |
1480 | return; |
1481 | } | |
1482 | ||
1483 | /* | |
1484 | * Set the search path on which to find the include file based on the | |
1485 | * characters which bracket its name. Angle-brackets imply it's | |
1486 | * a system Makefile while double-quotes imply it's a user makefile | |
1487 | */ | |
1488 | if (*file == '<') { | |
1489 | isSystem = TRUE; | |
1490 | endc = '>'; | |
1491 | } else { | |
1492 | isSystem = FALSE; | |
1493 | endc = '"'; | |
1494 | } | |
1495 | ||
1496 | /* | |
1497 | * Skip to matching delimiter | |
1498 | */ | |
1499 | for (cp = ++file; *cp && *cp != endc; cp++) { | |
1500 | continue; | |
1501 | } | |
1502 | ||
1503 | if (*cp != endc) { | |
1504 | Parse_Error (PARSE_FATAL, | |
91783fd5 | 1505 | "Unclosed .include filename. '%c' expected", endc); |
ab950546 KB |
1506 | return; |
1507 | } | |
1508 | *cp = '\0'; | |
1509 | ||
1510 | /* | |
1511 | * Substitute for any variables in the file name before trying to | |
1512 | * find the thing. | |
1513 | */ | |
1514 | file = Var_Subst (file, VAR_CMD, FALSE); | |
1515 | ||
1516 | /* | |
1517 | * Now we know the file's name and its search path, we attempt to | |
1518 | * find the durn thing. A return of NULL indicates the file don't | |
1519 | * exist. | |
1520 | */ | |
1521 | if (!isSystem) { | |
1522 | /* | |
1523 | * Include files contained in double-quotes are first searched for | |
1524 | * relative to the including file's location. We don't want to | |
1525 | * cd there, of course, so we just tack on the old file's | |
1526 | * leading path components and call Dir_FindFile to see if | |
1527 | * we can locate the beast. | |
1528 | */ | |
1529 | char *prefEnd; | |
1530 | ||
1531 | prefEnd = rindex (fname, '/'); | |
1532 | if (prefEnd != (char *)NULL) { | |
1533 | char *newName; | |
1534 | ||
1535 | *prefEnd = '\0'; | |
1cffbb48 | 1536 | newName = str_concat (fname, file, STR_ADDSLASH); |
ab950546 KB |
1537 | fullname = Dir_FindFile (newName, parseIncPath); |
1538 | if (fullname == (char *)NULL) { | |
1539 | fullname = Dir_FindFile(newName, dirSearchPath); | |
1540 | } | |
1541 | free (newName); | |
1542 | *prefEnd = '/'; | |
1543 | } else { | |
1544 | fullname = (char *)NULL; | |
1545 | } | |
1546 | } else { | |
1547 | fullname = (char *)NULL; | |
1548 | } | |
1549 | ||
1550 | if (fullname == (char *)NULL) { | |
1551 | /* | |
1552 | * System makefile or makefile wasn't found in same directory as | |
1553 | * included makefile. Search for it first on the -I search path, | |
1554 | * then on the .PATH search path, if not found in a -I directory. | |
1555 | * XXX: Suffix specific? | |
1556 | */ | |
1557 | fullname = Dir_FindFile (file, parseIncPath); | |
1558 | if (fullname == (char *)NULL) { | |
1559 | fullname = Dir_FindFile(file, dirSearchPath); | |
1560 | } | |
1561 | } | |
1562 | ||
1563 | if (fullname == (char *)NULL) { | |
1564 | /* | |
1565 | * Still haven't found the makefile. Look for it on the system | |
1566 | * path as a last resort. | |
1567 | */ | |
1568 | fullname = Dir_FindFile(file, sysIncPath); | |
1569 | } | |
1570 | ||
1571 | if (fullname == (char *) NULL) { | |
1572 | *cp = endc; | |
1573 | Parse_Error (PARSE_FATAL, "Could not find %s", file); | |
1574 | return; | |
1575 | } | |
1576 | ||
1577 | /* | |
1578 | * Once we find the absolute path to the file, we get to save all the | |
1579 | * state from the current file before we can start reading this | |
1580 | * include file. The state is stored in an IFile structure which | |
1581 | * is placed on a list with other IFile structures. The list makes | |
1582 | * a very nice stack to track how we got here... | |
1583 | */ | |
1cffbb48 | 1584 | oldFile = (IFile *) emalloc (sizeof (IFile)); |
ab950546 KB |
1585 | oldFile->fname = fname; |
1586 | ||
1587 | oldFile->F = curFILE; | |
1588 | oldFile->lineno = lineno; | |
1589 | ||
1590 | (void) Lst_AtFront (includes, (ClientData)oldFile); | |
1591 | ||
1592 | /* | |
1593 | * Once the previous state has been saved, we can get down to reading | |
1594 | * the new file. We set up the name of the file to be the absolute | |
1595 | * name of the include file so error messages refer to the right | |
1596 | * place. Naturally enough, we start reading at line number 0. | |
1597 | */ | |
1598 | fname = fullname; | |
1599 | lineno = 0; | |
1600 | ||
1601 | curFILE = fopen (fullname, "r"); | |
1602 | if (curFILE == (FILE * ) NULL) { | |
1603 | Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); | |
1604 | /* | |
1605 | * Pop to previous file | |
1606 | */ | |
1607 | (void) ParseEOF(); | |
1608 | } | |
1609 | } | |
182ca07d | 1610 | |
ab950546 KB |
1611 | /*- |
1612 | *--------------------------------------------------------------------- | |
1613 | * ParseEOF -- | |
1614 | * Called when EOF is reached in the current file. If we were reading | |
1615 | * an include file, the includes stack is popped and things set up | |
1616 | * to go back to reading the previous file at the previous location. | |
1617 | * | |
1618 | * Results: | |
1619 | * CONTINUE if there's more to do. DONE if not. | |
1620 | * | |
1621 | * Side Effects: | |
1622 | * The old curFILE, is closed. The includes list is shortened. | |
1623 | * lineno, curFILE, and fname are changed if CONTINUE is returned. | |
1624 | *--------------------------------------------------------------------- | |
1625 | */ | |
1626 | static int | |
1627 | ParseEOF () | |
1628 | { | |
1629 | IFile *ifile; /* the state on the top of the includes stack */ | |
1630 | ||
1631 | if (Lst_IsEmpty (includes)) { | |
1632 | return (DONE); | |
1633 | } | |
1634 | ||
1635 | ifile = (IFile *) Lst_DeQueue (includes); | |
1636 | free (fname); | |
1637 | fname = ifile->fname; | |
1638 | lineno = ifile->lineno; | |
1639 | fclose (curFILE); | |
1640 | curFILE = ifile->F; | |
1641 | free ((Address)ifile); | |
1642 | return (CONTINUE); | |
1643 | } | |
182ca07d | 1644 | |
ab950546 KB |
1645 | /*- |
1646 | *--------------------------------------------------------------------- | |
1647 | * ParseReadc -- | |
1648 | * Read a character from the current file and update the line number | |
1649 | * counter as necessary | |
1650 | * | |
1651 | * Results: | |
1652 | * The character that was read | |
1653 | * | |
1654 | * Side Effects: | |
1655 | * The lineno counter is incremented if the character is a newline | |
1656 | *--------------------------------------------------------------------- | |
1657 | */ | |
1658 | #ifdef notdef | |
1659 | static int parseReadChar; | |
1660 | ||
1661 | #define ParseReadc() (((parseReadChar = getc(curFILE)) == '\n') ? \ | |
1662 | (lineno++, '\n') : parseReadChar) | |
1663 | #else | |
1664 | #define ParseReadc() (getc(curFILE)) | |
1665 | #endif /* notdef */ | |
1666 | ||
182ca07d | 1667 | |
ab950546 KB |
1668 | /*- |
1669 | *--------------------------------------------------------------------- | |
1670 | * ParseReadLine -- | |
1671 | * Read an entire line from the input file. Called only by Parse_File. | |
1672 | * To facilitate escaped newlines and what have you, a character is | |
1673 | * buffered in 'lastc', which is '\0' when no characters have been | |
1674 | * read. When we break out of the loop, c holds the terminating | |
1675 | * character and lastc holds a character that should be added to | |
1676 | * the line (unless we don't read anything but a terminator). | |
1677 | * | |
1678 | * Results: | |
1679 | * A line w/o its newline | |
1680 | * | |
1681 | * Side Effects: | |
1682 | * Only those associated with reading a character | |
1683 | *--------------------------------------------------------------------- | |
1684 | */ | |
1685 | static char * | |
1686 | ParseReadLine () | |
1687 | { | |
1688 | Buffer buf; /* Buffer for current line */ | |
1689 | register int c; /* the current character */ | |
1690 | register int lastc; /* The most-recent character */ | |
1691 | Boolean semiNL; /* treat semi-colons as newlines */ | |
1692 | Boolean ignDepOp; /* TRUE if should ignore dependency operators | |
1693 | * for the purposes of setting semiNL */ | |
1694 | Boolean ignComment; /* TRUE if should ignore comments (in a | |
1695 | * shell command */ | |
1696 | char *line; /* Result */ | |
1697 | int lineLength; /* Length of result */ | |
1698 | ||
1699 | semiNL = FALSE; | |
1700 | ignDepOp = FALSE; | |
1701 | ignComment = FALSE; | |
1702 | ||
1703 | /* | |
1704 | * Handle special-characters at the beginning of the line. Either a | |
1705 | * leading tab (shell command) or pound-sign (possible conditional) | |
1706 | * forces us to ignore comments and dependency operators and treat | |
1707 | * semi-colons as semi-colons (by leaving semiNL FALSE). This also | |
1708 | * discards completely blank lines. | |
1709 | */ | |
1710 | while(1) { | |
1711 | c = ParseReadc(); | |
1712 | ||
9fef5355 KB |
1713 | if (c == '\t') { |
1714 | ignComment = ignDepOp = TRUE; | |
1715 | break; | |
1716 | } else if (c == '.') { | |
58c65c65 | 1717 | ignComment = TRUE; |
ab950546 KB |
1718 | break; |
1719 | } else if (c == '\n') { | |
1720 | lineno++; | |
e57075a6 KB |
1721 | } else if (c == '#') { |
1722 | ungetc(c, curFILE); | |
1723 | break; | |
ab950546 KB |
1724 | } else { |
1725 | /* | |
1726 | * Anything else breaks out without doing anything | |
1727 | */ | |
1728 | break; | |
1729 | } | |
1730 | } | |
1731 | ||
1732 | if (c != EOF) { | |
1733 | lastc = c; | |
1734 | buf = Buf_Init(BSIZE); | |
1735 | ||
1736 | while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && | |
1737 | (c != EOF)) | |
1738 | { | |
1739 | test_char: | |
1740 | switch(c) { | |
1741 | case '\n': | |
1742 | /* | |
1743 | * Escaped newline: read characters until a non-space or an | |
1744 | * unescaped newline and replace them all by a single space. | |
1745 | * This is done by storing the space over the backslash and | |
1746 | * dropping through with the next nonspace. If it is a | |
1747 | * semi-colon and semiNL is TRUE, it will be recognized as a | |
1748 | * newline in the code below this... | |
1749 | */ | |
1750 | lineno++; | |
1751 | lastc = ' '; | |
1752 | while ((c = ParseReadc ()) == ' ' || c == '\t') { | |
1753 | continue; | |
1754 | } | |
1755 | if (c == EOF || c == '\n') { | |
1756 | goto line_read; | |
1757 | } else { | |
1758 | /* | |
1759 | * Check for comments, semiNL's, etc. -- easier than | |
1760 | * ungetc(c, curFILE); continue; | |
1761 | */ | |
1762 | goto test_char; | |
1763 | } | |
1764 | break; | |
1765 | case ';': | |
1766 | /* | |
1767 | * Semi-colon: Need to see if it should be interpreted as a | |
1768 | * newline | |
1769 | */ | |
1770 | if (semiNL) { | |
1771 | /* | |
1772 | * To make sure the command that may be following this | |
1773 | * semi-colon begins with a tab, we push one back into the | |
1774 | * input stream. This will overwrite the semi-colon in the | |
1775 | * buffer. If there is no command following, this does no | |
1776 | * harm, since the newline remains in the buffer and the | |
1777 | * whole line is ignored. | |
1778 | */ | |
1779 | ungetc('\t', curFILE); | |
1780 | goto line_read; | |
1781 | } | |
1782 | break; | |
1783 | case '=': | |
1784 | if (!semiNL) { | |
1785 | /* | |
1786 | * Haven't seen a dependency operator before this, so this | |
1787 | * must be a variable assignment -- don't pay attention to | |
1788 | * dependency operators after this. | |
1789 | */ | |
1790 | ignDepOp = TRUE; | |
1791 | } else if (lastc == ':' || lastc == '!') { | |
1792 | /* | |
1793 | * Well, we've seen a dependency operator already, but it | |
1794 | * was the previous character, so this is really just an | |
1795 | * expanded variable assignment. Revert semi-colons to | |
1796 | * being just semi-colons again and ignore any more | |
1797 | * dependency operators. | |
1798 | * | |
1799 | * XXX: Note that a line like "foo : a:=b" will blow up, | |
1800 | * but who'd write a line like that anyway? | |
1801 | */ | |
1802 | ignDepOp = TRUE; semiNL = FALSE; | |
1803 | } | |
1804 | break; | |
1805 | case '#': | |
1806 | if (!ignComment) { | |
ab950546 KB |
1807 | /* |
1808 | * If the character is a hash mark and it isn't escaped | |
1809 | * (or we're being compatible), the thing is a comment. | |
1810 | * Skip to the end of the line. | |
1811 | */ | |
1812 | do { | |
1813 | c = ParseReadc(); | |
1814 | } while ((c != '\n') && (c != EOF)); | |
1815 | goto line_read; | |
ab950546 KB |
1816 | } |
1817 | break; | |
1818 | case ':': | |
1819 | case '!': | |
1820 | if (!ignDepOp && (c == ':' || c == '!')) { | |
1821 | /* | |
1822 | * A semi-colon is recognized as a newline only on | |
1823 | * dependency lines. Dependency lines are lines with a | |
1824 | * colon or an exclamation point. Ergo... | |
1825 | */ | |
1826 | semiNL = TRUE; | |
1827 | } | |
1828 | break; | |
1829 | } | |
1830 | /* | |
1831 | * Copy in the previous character and save this one in lastc. | |
1832 | */ | |
1833 | Buf_AddByte (buf, (Byte)lastc); | |
1834 | lastc = c; | |
1835 | ||
1836 | } | |
1837 | line_read: | |
1838 | lineno++; | |
1839 | ||
1840 | if (lastc != '\0') { | |
1841 | Buf_AddByte (buf, (Byte)lastc); | |
1842 | } | |
1843 | Buf_AddByte (buf, (Byte)'\0'); | |
1844 | line = (char *)Buf_GetAll (buf, &lineLength); | |
1845 | Buf_Destroy (buf, FALSE); | |
1846 | ||
91783fd5 | 1847 | if (line[0] == '.') { |
ab950546 KB |
1848 | /* |
1849 | * The line might be a conditional. Ask the conditional module | |
1850 | * about it and act accordingly | |
1851 | */ | |
1852 | switch (Cond_Eval (line)) { | |
1853 | case COND_SKIP: | |
1854 | do { | |
1855 | /* | |
1856 | * Skip to next conditional that evaluates to COND_PARSE. | |
1857 | */ | |
1858 | free (line); | |
1859 | c = ParseReadc(); | |
1860 | /* | |
1861 | * Skip lines until get to one that begins with a | |
1862 | * special char. | |
1863 | */ | |
91783fd5 | 1864 | while ((c != '.') && (c != EOF)) { |
ab950546 KB |
1865 | while (((c != '\n') || (lastc == '\\')) && |
1866 | (c != EOF)) | |
1867 | { | |
1868 | /* | |
1869 | * Advance to next unescaped newline | |
1870 | */ | |
1871 | if ((lastc = c) == '\n') { | |
1872 | lineno++; | |
1873 | } | |
1874 | c = ParseReadc(); | |
1875 | } | |
1876 | lineno++; | |
1877 | ||
1878 | lastc = c; | |
1879 | c = ParseReadc (); | |
1880 | } | |
1881 | ||
1882 | if (c == EOF) { | |
1883 | Parse_Error (PARSE_FATAL, "Unclosed conditional"); | |
1884 | return ((char *)NULL); | |
1885 | } | |
1886 | ||
1887 | /* | |
1888 | * Read the entire line into buf | |
1889 | */ | |
1890 | buf = Buf_Init (BSIZE); | |
1891 | do { | |
1892 | Buf_AddByte (buf, (Byte)c); | |
1893 | c = ParseReadc(); | |
1894 | } while ((c != '\n') && (c != EOF)); | |
1895 | lineno++; | |
1896 | ||
1897 | Buf_AddByte (buf, (Byte)'\0'); | |
1898 | line = (char *)Buf_GetAll (buf, &lineLength); | |
1899 | Buf_Destroy (buf, FALSE); | |
1900 | } while (Cond_Eval(line) != COND_PARSE); | |
1901 | /*FALLTHRU*/ | |
1902 | case COND_PARSE: | |
1903 | free (line); | |
1904 | line = ParseReadLine(); | |
1905 | break; | |
1906 | } | |
1907 | } | |
1908 | ||
1909 | return (line); | |
1910 | } else { | |
1911 | /* | |
1912 | * Hit end-of-file, so return a NULL line to indicate this. | |
1913 | */ | |
1914 | return((char *)NULL); | |
1915 | } | |
1916 | } | |
182ca07d | 1917 | |
ab950546 KB |
1918 | /*- |
1919 | *----------------------------------------------------------------------- | |
1920 | * ParseFinishLine -- | |
1921 | * Handle the end of a dependency group. | |
1922 | * | |
1923 | * Results: | |
1924 | * Nothing. | |
1925 | * | |
1926 | * Side Effects: | |
1927 | * inLine set FALSE. 'targets' list destroyed. | |
1928 | * | |
1929 | *----------------------------------------------------------------------- | |
1930 | */ | |
1931 | static void | |
1932 | ParseFinishLine() | |
1933 | { | |
1934 | extern int Suff_EndTransform(); | |
1935 | ||
1936 | if (inLine) { | |
1937 | Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL); | |
1938 | Lst_Destroy (targets, ParseHasCommands); | |
1939 | inLine = FALSE; | |
1940 | } | |
1941 | } | |
1942 | ||
182ca07d | 1943 | |
ab950546 KB |
1944 | /*- |
1945 | *--------------------------------------------------------------------- | |
1946 | * Parse_File -- | |
1947 | * Parse a file into its component parts, incorporating it into the | |
1948 | * current dependency graph. This is the main function and controls | |
1949 | * almost every other function in this module | |
1950 | * | |
1951 | * Results: | |
1952 | * None | |
1953 | * | |
1954 | * Side Effects: | |
1955 | * Loads. Nodes are added to the list of all targets, nodes and links | |
1956 | * are added to the dependency graph. etc. etc. etc. | |
1957 | *--------------------------------------------------------------------- | |
1958 | */ | |
1959 | void | |
1960 | Parse_File(name, stream) | |
1961 | char *name; /* the name of the file being read */ | |
1962 | FILE * stream; /* Stream open to makefile to parse */ | |
1963 | { | |
1964 | register char *cp, /* pointer into the line */ | |
1965 | *line; /* the line we're working on */ | |
1966 | ||
1967 | inLine = FALSE; | |
1968 | fname = name; | |
1969 | curFILE = stream; | |
1970 | lineno = 0; | |
1971 | fatals = 0; | |
1972 | ||
1973 | do { | |
1974 | while (line = ParseReadLine ()) { | |
91783fd5 | 1975 | if (*line == '.') { |
ab950546 KB |
1976 | /* |
1977 | * Lines that begin with the special character are either | |
1978 | * include or undef directives. | |
1979 | */ | |
1980 | for (cp = line + 1; isspace (*cp); cp++) { | |
1981 | continue; | |
1982 | } | |
1983 | if (strncmp (cp, "include", 7) == 0) { | |
1984 | ParseDoInclude (cp + 7); | |
1985 | goto nextLine; | |
1986 | } else if (strncmp(cp, "undef", 5) == 0) { | |
1987 | char *cp2; | |
1988 | for (cp += 5; isspace(*cp); cp++) { | |
1989 | continue; | |
1990 | } | |
1991 | ||
1992 | for (cp2 = cp; !isspace(*cp2) && (*cp2 != '\0'); cp2++) { | |
1993 | continue; | |
1994 | } | |
1995 | ||
1996 | *cp2 = '\0'; | |
1997 | ||
1998 | Var_Delete(cp, VAR_GLOBAL); | |
1999 | goto nextLine; | |
2000 | } | |
2001 | } | |
2002 | if (*line == '#') { | |
91783fd5 | 2003 | /* If we're this far, the line must be a comment. */ |
ab950546 KB |
2004 | goto nextLine; |
2005 | } | |
2006 | ||
2007 | if (*line == '\t' | |
2008 | #ifdef POSIX | |
2009 | || *line == ' ' | |
2010 | #endif | |
2011 | ) | |
2012 | { | |
2013 | /* | |
2014 | * If a line starts with a tab (or space in POSIX-land), it | |
2015 | * can only hope to be a creation command. | |
2016 | */ | |
2017 | shellCommand: | |
2018 | for (cp = line + 1; isspace (*cp); cp++) { | |
2019 | continue; | |
2020 | } | |
2021 | if (*cp) { | |
2022 | if (inLine) { | |
2023 | /* | |
2024 | * So long as it's not a blank line and we're actually | |
2025 | * in a dependency spec, add the command to the list of | |
2026 | * commands of all targets in the dependency spec | |
2027 | */ | |
2028 | Lst_ForEach (targets, ParseAddCmd, (ClientData)cp); | |
2029 | continue; | |
2030 | } else { | |
2031 | Parse_Error (PARSE_FATAL, | |
2032 | "Unassociated shell command \"%.20s\"", | |
2033 | cp); | |
2034 | } | |
2035 | } | |
2036 | } else if (Parse_IsVar (line)) { | |
2037 | ParseFinishLine(); | |
2038 | Parse_DoVar (line, VAR_GLOBAL); | |
2039 | } else { | |
2040 | /* | |
2041 | * We now know it's a dependency line so it needs to have all | |
2042 | * variables expanded before being parsed. Tell the variable | |
2043 | * module to complain if some variable is undefined... | |
2044 | * To make life easier on novices, if the line is indented we | |
2045 | * first make sure the line has a dependency operator in it. | |
2046 | * If it doesn't have an operator and we're in a dependency | |
2047 | * line's script, we assume it's actually a shell command | |
2048 | * and add it to the current list of targets. | |
2049 | * | |
2050 | * Note that POSIX declares all lines that start with | |
2051 | * whitespace are shell commands, so there's no need to check | |
2052 | * here... | |
2053 | */ | |
2054 | Boolean nonSpace = FALSE; | |
2055 | ||
2056 | cp = line; | |
2057 | #ifndef POSIX | |
2058 | if (line[0] == ' ') { | |
2059 | while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) { | |
2060 | if (!isspace(*cp)) { | |
2061 | nonSpace = TRUE; | |
2062 | } | |
2063 | cp++; | |
2064 | } | |
2065 | } | |
2066 | ||
2067 | if (*cp == '\0') { | |
2068 | if (inLine) { | |
2069 | Parse_Error (PARSE_WARNING, | |
2070 | "Shell command needs a leading tab"); | |
2071 | goto shellCommand; | |
2072 | } else if (nonSpace) { | |
2073 | Parse_Error (PARSE_FATAL, "Missing operator"); | |
2074 | } | |
2075 | } else { | |
2076 | #endif | |
2077 | ParseFinishLine(); | |
2078 | ||
2079 | cp = Var_Subst (line, VAR_CMD, TRUE); | |
2080 | free (line); | |
2081 | line = cp; | |
2082 | ||
2083 | /* | |
2084 | * Need a non-circular list for the target nodes | |
2085 | */ | |
2086 | targets = Lst_Init (FALSE); | |
2087 | inLine = TRUE; | |
2088 | ||
2089 | ParseDoDependency (line); | |
2090 | #ifndef POSIX | |
2091 | } | |
2092 | #endif | |
2093 | } | |
2094 | ||
2095 | nextLine: | |
2096 | ||
2097 | free (line); | |
2098 | } | |
2099 | /* | |
2100 | * Reached EOF, but it may be just EOF of an include file... | |
2101 | */ | |
2102 | } while (ParseEOF() == CONTINUE); | |
2103 | ||
2104 | /* | |
2105 | * Make sure conditionals are clean | |
2106 | */ | |
2107 | Cond_End(); | |
2108 | ||
2109 | if (fatals) { | |
2110 | fprintf (stderr, "Fatal errors encountered -- cannot continue\n"); | |
2111 | exit (1); | |
2112 | } | |
2113 | } | |
182ca07d | 2114 | |
ab950546 KB |
2115 | /*- |
2116 | *--------------------------------------------------------------------- | |
2117 | * Parse_Init -- | |
2118 | * initialize the parsing module | |
2119 | * | |
2120 | * Results: | |
2121 | * none | |
2122 | * | |
2123 | * Side Effects: | |
2124 | * the parseIncPath list is initialized... | |
2125 | *--------------------------------------------------------------------- | |
2126 | */ | |
2127 | Parse_Init () | |
2128 | { | |
aabb6217 KB |
2129 | char *cp, *start; |
2130 | /* avoid faults on read-only strings */ | |
2131 | static char syspath[] = _PATH_DEFSYSPATH; | |
ab950546 KB |
2132 | |
2133 | mainNode = NILGNODE; | |
2134 | parseIncPath = Lst_Init (FALSE); | |
2135 | sysIncPath = Lst_Init (FALSE); | |
2136 | includes = Lst_Init (FALSE); | |
2137 | ||
2138 | /* | |
2139 | * Add the directories from the DEFSYSPATH (more than one may be given | |
2140 | * as dir1:...:dirn) to the system include path. | |
2141 | */ | |
2142 | for (start = syspath; *start != '\0'; start = cp) { | |
2143 | for (cp = start; *cp != '\0' && *cp != ':'; cp++) { | |
2144 | ; | |
2145 | } | |
2146 | if (*cp == '\0') { | |
2147 | Dir_AddDir(sysIncPath, start); | |
2148 | } else { | |
2149 | *cp++ = '\0'; | |
2150 | Dir_AddDir(sysIncPath, start); | |
2151 | } | |
2152 | } | |
2153 | } | |
182ca07d | 2154 | |
ab950546 KB |
2155 | /*- |
2156 | *----------------------------------------------------------------------- | |
2157 | * Parse_MainName -- | |
2158 | * Return a Lst of the main target to create for main()'s sake. If | |
2159 | * no such target exists, we Punt with an obnoxious error message. | |
2160 | * | |
2161 | * Results: | |
2162 | * A Lst of the single node to create. | |
2163 | * | |
2164 | * Side Effects: | |
2165 | * None. | |
2166 | * | |
2167 | *----------------------------------------------------------------------- | |
2168 | */ | |
2169 | Lst | |
2170 | Parse_MainName() | |
2171 | { | |
2172 | Lst main; /* result list */ | |
2173 | ||
2174 | main = Lst_Init (FALSE); | |
2175 | ||
2176 | if (mainNode == NILGNODE) { | |
b3dbe08f | 2177 | Punt ("make: no target to make.\n"); |
ab950546 KB |
2178 | /*NOTREACHED*/ |
2179 | } else if (mainNode->type & OP_DOUBLEDEP) { | |
2180 | Lst_Concat(main, mainNode->cohorts, LST_CONCNEW); | |
2181 | } | |
2182 | (void) Lst_AtEnd (main, (ClientData)mainNode); | |
2183 | return (main); | |
2184 | } |