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