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