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