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