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