Annotation of src/usr.bin/make/parse.c, Revision 1.77
1.59 espie 1: /* $OpenPackages$ */
1.73 espie 2: /* $OpenBSD: parse.c,v 1.72 2007/07/08 17:44:20 espie Exp $ */
1.13 millert 3: /* $NetBSD: parse.c,v 1.29 1997/03/10 21:20:04 christos Exp $ */
1.1 deraadt 4:
5: /*
1.59 espie 6: * Copyright (c) 1999 Marc Espie.
7: *
8: * Extensive code changes for the OpenBSD project.
9: *
10: * Redistribution and use in source and binary forms, with or without
11: * modification, are permitted provided that the following conditions
12: * are met:
13: * 1. Redistributions of source code must retain the above copyright
14: * notice, this list of conditions and the following disclaimer.
15: * 2. Redistributions in binary form must reproduce the above copyright
16: * notice, this list of conditions and the following disclaimer in the
17: * documentation and/or other materials provided with the distribution.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE OPENBSD PROJECT AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OPENBSD
23: * PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30: */
31: /*
1.11 millert 32: * Copyright (c) 1988, 1989, 1990, 1993
33: * The Regents of the University of California. All rights reserved.
1.1 deraadt 34: * Copyright (c) 1989 by Berkeley Softworks
35: * All rights reserved.
36: *
37: * This code is derived from software contributed to Berkeley by
38: * Adam de Boor.
39: *
40: * Redistribution and use in source and binary forms, with or without
41: * modification, are permitted provided that the following conditions
42: * are met:
43: * 1. Redistributions of source code must retain the above copyright
44: * notice, this list of conditions and the following disclaimer.
45: * 2. Redistributions in binary form must reproduce the above copyright
46: * notice, this list of conditions and the following disclaimer in the
47: * documentation and/or other materials provided with the distribution.
1.68 millert 48: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 49: * may be used to endorse or promote products derived from this software
50: * without specific prior written permission.
51: *
52: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
53: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
54: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
55: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
56: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
57: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
58: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
59: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
60: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
61: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
62: * SUCH DAMAGE.
63: */
64:
1.59 espie 65: #include <assert.h>
1.61 espie 66: #include <ctype.h>
1.1 deraadt 67: #include <stdio.h>
1.62 espie 68: #include <stdlib.h>
1.61 espie 69: #include <string.h>
70: #include "config.h"
71: #include "defines.h"
1.1 deraadt 72: #include "dir.h"
73: #include "job.h"
74: #include "buf.h"
1.61 espie 75: #include "for.h"
1.50 espie 76: #include "lowparse.h"
1.61 espie 77: #include "arch.h"
78: #include "cond.h"
79: #include "suff.h"
80: #include "parse.h"
81: #include "var.h"
82: #include "targ.h"
83: #include "error.h"
84: #include "str.h"
85: #include "main.h"
86: #include "gnode.h"
87: #include "memory.h"
88: #include "extern.h"
89: #include "lst.h"
90: #include "parsevar.h"
1.63 espie 91: #include "stats.h"
92: #include "garray.h"
93:
94:
95: static struct growableArray gsources, gtargets;
96: #define SOURCES_SIZE 128
97: #define TARGETS_SIZE 32
1.61 espie 98:
99: static LIST theParseIncPath;/* list of directories for "..." includes */
100: static LIST theSysIncPath; /* list of directories for <...> includes */
101: Lst sysIncPath = &theSysIncPath;
102: Lst parseIncPath = &theParseIncPath;
1.59 espie 103:
1.20 espie 104: #ifdef CLEANUP
1.59 espie 105: static LIST targCmds; /* command lines for targets */
1.20 espie 106: #endif
1.59 espie 107:
1.1 deraadt 108: static GNode *mainNode; /* The main target to create. This is the
109: * first target on the first dependency
110: * line in the first makefile */
111: /*-
112: * specType contains the SPECial TYPE of the current target. It is
113: * Not if the target is unspecial. If it *is* special, however, the children
114: * are linked as children of the parent but not vice versa. This variable is
115: * set in ParseDoDependency
116: */
117: typedef enum {
1.59 espie 118: Begin, /* .BEGIN */
1.1 deraadt 119: Default, /* .DEFAULT */
1.59 espie 120: End, /* .END */
1.1 deraadt 121: Ignore, /* .IGNORE */
122: Includes, /* .INCLUDES */
123: Interrupt, /* .INTERRUPT */
124: Libs, /* .LIBS */
125: MFlags, /* .MFLAGS or .MAKEFLAGS */
126: Main, /* .MAIN and we don't have anything user-specified to
127: * make */
128: NoExport, /* .NOEXPORT */
1.17 espie 129: NoPath, /* .NOPATH */
1.1 deraadt 130: Not, /* Not special */
131: NotParallel, /* .NOTPARALELL */
1.59 espie 132: Null, /* .NULL */
133: Order, /* .ORDER */
1.3 deraadt 134: Parallel, /* .PARALLEL */
1.1 deraadt 135: ExPath, /* .PATH */
1.7 niklas 136: Phony, /* .PHONY */
1.1 deraadt 137: Precious, /* .PRECIOUS */
138: ExShell, /* .SHELL */
139: Silent, /* .SILENT */
140: SingleShell, /* .SINGLESHELL */
141: Suffixes, /* .SUFFIXES */
1.3 deraadt 142: Wait, /* .WAIT */
1.1 deraadt 143: Attribute /* Generic attribute */
144: } ParseSpecial;
145:
146: static ParseSpecial specType;
1.3 deraadt 147: static int waiting;
1.1 deraadt 148:
149: /*
1.33 espie 150: * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
1.1 deraadt 151: * seen, then set to each successive source on the line.
152: */
153: static GNode *predecessor;
154:
155: /*
156: * The parseKeywords table is searched using binary search when deciding
157: * if a target or source is special. The 'spec' field is the ParseSpecial
158: * type of the keyword ("Not" if the keyword isn't special as a target) while
159: * the 'op' field is the operator to apply to the list of targets if the
160: * keyword is used as a source ("0" if the keyword isn't special as a source)
161: */
162: static struct {
1.59 espie 163: char *name; /* Name of keyword */
164: ParseSpecial spec; /* Type when used as a target */
165: int op; /* Operator when used as a source */
1.1 deraadt 166: } parseKeywords[] = {
1.59 espie 167: { ".BEGIN", Begin, 0 },
168: { ".DEFAULT", Default, 0 },
169: { ".END", End, 0 },
170: { ".EXEC", Attribute, OP_EXEC },
171: { ".IGNORE", Ignore, OP_IGNORE },
172: { ".INCLUDES", Includes, 0 },
173: { ".INTERRUPT", Interrupt, 0 },
174: { ".INVISIBLE", Attribute, OP_INVISIBLE },
175: { ".JOIN", Attribute, OP_JOIN },
176: { ".LIBS", Libs, 0 },
1.13 millert 177: { ".MADE", Attribute, OP_MADE },
1.59 espie 178: { ".MAIN", Main, 0 },
179: { ".MAKE", Attribute, OP_MAKE },
180: { ".MAKEFLAGS", MFlags, 0 },
181: { ".MFLAGS", MFlags, 0 },
1.17 espie 182: #if 0 /* basic scaffolding for NOPATH, not working yet */
183: { ".NOPATH", NoPath, OP_NOPATH },
184: #endif
1.59 espie 185: { ".NOTMAIN", Attribute, OP_NOTMAIN },
1.1 deraadt 186: { ".NOTPARALLEL", NotParallel, 0 },
1.3 deraadt 187: { ".NO_PARALLEL", NotParallel, 0 },
1.59 espie 188: { ".NULL", Null, 0 },
189: { ".OPTIONAL", Attribute, OP_OPTIONAL },
190: { ".ORDER", Order, 0 },
1.3 deraadt 191: { ".PARALLEL", Parallel, 0 },
1.1 deraadt 192: { ".PATH", ExPath, 0 },
1.7 niklas 193: { ".PHONY", Phony, OP_PHONY },
1.59 espie 194: { ".PRECIOUS", Precious, OP_PRECIOUS },
195: { ".RECURSIVE", Attribute, OP_MAKE },
196: { ".SHELL", ExShell, 0 },
197: { ".SILENT", Silent, OP_SILENT },
1.1 deraadt 198: { ".SINGLESHELL", SingleShell, 0 },
1.59 espie 199: { ".SUFFIXES", Suffixes, 0 },
200: { ".USE", Attribute, OP_USE },
1.3 deraadt 201: { ".WAIT", Wait, 0 },
1.1 deraadt 202: };
203:
1.59 espie 204: static int ParseFindKeyword(const char *);
205: static void ParseLinkSrc(GNode *, GNode *);
1.63 espie 206: static int ParseDoOp(GNode *, int);
207: static int ParseAddDep(GNode *, GNode *);
208: static void ParseDoSrc(int, const char *);
1.59 espie 209: static int ParseFindMain(void *, void *);
210: static void ParseAddDir(void *, void *);
211: static void ParseClearPath(void *);
1.77 ! espie 212:
! 213: static void add_target_node(const char *);
! 214: static void add_target_nodes(const char *);
1.59 espie 215: static void ParseDoDependency(char *);
216: static void ParseAddCmd(void *, void *);
217: static void ParseHasCommands(void *);
218: static void ParseDoInclude(char *);
1.72 espie 219: static void ParseDoPoison(char *);
1.59 espie 220: static void ParseTraditionalInclude(char *);
221: static void ParseConditionalInclude(char *);
1.61 espie 222: static void ParseLookupIncludeFile(char *, char *, bool, bool);
223: #define ParseReadLoopLine(linebuf) Parse_ReadUnparsedLine(linebuf, "for loop")
1.59 espie 224: static void ParseFinishDependency(void);
1.61 espie 225: static bool ParseIsCond(Buffer, Buffer, char *);
1.59 espie 226: static char *strip_comments(Buffer, const char *);
1.70 espie 227: static char *find_include(const char *, bool);
1.59 espie 228:
229: static void ParseDoCommands(const char *);
1.1 deraadt 230:
231: /*-
232: *----------------------------------------------------------------------
233: * ParseFindKeyword --
234: * Look in the table of keywords for one matching the given string.
235: *
236: * Results:
237: * The index of the keyword, or -1 if it isn't there.
238: *----------------------------------------------------------------------
239: */
240: static int
1.69 espie 241: ParseFindKeyword(const char *str) /* keyword to look up */
1.1 deraadt 242: {
1.59 espie 243: int start,
1.1 deraadt 244: end,
245: cur;
1.59 espie 246: int diff;
1.11 millert 247:
1.1 deraadt 248: start = 0;
249: end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;
250:
251: do {
1.59 espie 252: cur = start + (end - start) / 2;
253: diff = strcmp(str, parseKeywords[cur].name);
1.1 deraadt 254:
255: if (diff == 0) {
1.59 espie 256: return cur;
1.1 deraadt 257: } else if (diff < 0) {
258: end = cur - 1;
259: } else {
260: start = cur + 1;
261: }
262: } while (start <= end);
1.59 espie 263: return -1;
1.1 deraadt 264: }
265: /*-
266: *---------------------------------------------------------------------
267: * ParseLinkSrc --
1.59 espie 268: * Link the parent node to its new child. Used by
1.1 deraadt 269: * ParseDoDependency. If the specType isn't 'Not', the parent
270: * isn't linked as a parent of the child.
271: *
272: * Side Effects:
273: * New elements are added to the parents list of cgn and the
274: * children list of cgn. the unmade field of pgn is updated
275: * to reflect the additional child.
276: *---------------------------------------------------------------------
277: */
1.41 espie 278: static void
1.69 espie 279: ParseLinkSrc(
280: GNode *pgn, /* The parent node */
281: GNode *cgn) /* The child node */
1.59 espie 282: {
1.61 espie 283: if (Lst_AddNew(&pgn->children, cgn)) {
1.41 espie 284: if (specType == Not)
1.43 espie 285: Lst_AtEnd(&cgn->parents, pgn);
1.59 espie 286: pgn->unmade++;
1.1 deraadt 287: }
288: }
289:
290: /*-
291: *---------------------------------------------------------------------
292: * ParseDoOp --
293: * Apply the parsed operator to the given target node. Used in a
1.41 espie 294: * Lst_Find call by ParseDoDependency once all targets have
1.1 deraadt 295: * been found and their operator parsed. If the previous and new
296: * operators are incompatible, a major error is taken.
297: *
298: * Side Effects:
299: * The type field of the node is altered to reflect any new bits in
300: * the op.
301: *---------------------------------------------------------------------
302: */
303: static int
1.69 espie 304: ParseDoOp(
305: GNode *gn, /* The node to which the operator is to be applied */
306: int op) /* The operator to apply */
1.1 deraadt 307: {
308: /*
309: * If the dependency mask of the operator and the node don't match and
310: * the node has actually had an operator applied to it before, and
1.11 millert 311: * the operator actually has some dependency information in it, complain.
1.1 deraadt 312: */
313: if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
1.40 espie 314: !OP_NOP(gn->type) && !OP_NOP(op)) {
315: Parse_Error(PARSE_FATAL, "Inconsistent operator for %s", gn->name);
316: return 0;
1.1 deraadt 317: }
318:
1.59 espie 319: if (op == OP_DOUBLEDEP && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
320: /* If the node was the object of a :: operator, we need to create a
1.1 deraadt 321: * new instance of it for the children and commands on this dependency
322: * line. The new instance is placed on the 'cohorts' list of the
323: * initial one (note the initial one is not on its own cohorts list)
324: * and the new instance is linked to all parents of the initial
1.59 espie 325: * instance. */
326: GNode *cohort;
327: LstNode ln;
1.63 espie 328: unsigned int i;
1.11 millert 329:
1.61 espie 330: cohort = Targ_NewGN(gn->name);
1.59 espie 331: /* Duplicate links to parents so graph traversal is simple. Perhaps
1.1 deraadt 332: * some type bits should be duplicated?
333: *
334: * Make the cohort invisible as well to avoid duplicating it into
335: * other variables. True, parents of this target won't tend to do
336: * anything with their local variables, but better safe than
1.59 espie 337: * sorry. */
338: for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Adv(ln))
339: ParseLinkSrc((GNode *)Lst_Datum(ln), cohort);
1.1 deraadt 340: cohort->type = OP_DOUBLEDEP|OP_INVISIBLE;
1.43 espie 341: Lst_AtEnd(&gn->cohorts, cohort);
1.1 deraadt 342:
1.59 espie 343: /* Replace the node in the targets list with the new copy */
1.63 espie 344: for (i = 0; i < gtargets.n; i++)
345: if (gtargets.a[i] == gn)
346: break;
347: gtargets.a[i] = cohort;
1.1 deraadt 348: gn = cohort;
349: }
1.59 espie 350: /* We don't want to nuke any previous flags (whatever they were) so we
351: * just OR the new operator into the old. */
1.1 deraadt 352: gn->type |= op;
1.40 espie 353: return 1;
1.1 deraadt 354: }
355:
1.11 millert 356: /*-
1.3 deraadt 357: *---------------------------------------------------------------------
1.59 espie 358: * ParseAddDep --
1.3 deraadt 359: * Check if the pair of GNodes given needs to be synchronized.
360: * This has to be when two nodes are on different sides of a
361: * .WAIT directive.
362: *
363: * Results:
1.40 espie 364: * Returns 0 if the two targets need to be ordered, 1 otherwise.
1.59 espie 365: * If it returns 0, the search can stop.
1.3 deraadt 366: *
367: * Side Effects:
368: * A dependency can be added between the two nodes.
1.11 millert 369: *
1.3 deraadt 370: *---------------------------------------------------------------------
371: */
1.13 millert 372: static int
1.69 espie 373: ParseAddDep(GNode *p, GNode *s)
1.3 deraadt 374: {
375: if (p->order < s->order) {
1.59 espie 376: /* XXX: This can cause loops, and loops can cause unmade targets,
1.3 deraadt 377: * but checking is tedious, and the debugging output can show the
1.59 espie 378: * problem. */
1.43 espie 379: Lst_AtEnd(&p->successors, s);
380: Lst_AtEnd(&s->preds, p);
1.40 espie 381: return 1;
1.3 deraadt 382: }
383: else
1.40 espie 384: return 0;
1.3 deraadt 385: }
386:
387:
1.1 deraadt 388: /*-
389: *---------------------------------------------------------------------
390: * ParseDoSrc --
391: * Given the name of a source, figure out if it is an attribute
392: * and apply it to the targets if it is. Else decide if there is
393: * some attribute which should be applied *to* the source because
394: * of some special target and apply it if so. Otherwise, make the
395: * source be a child of the targets in the list 'targets'
396: *
397: * Side Effects:
398: * Operator bits may be added to the list of targets or to the source.
399: * The targets may have a new source added to their lists of children.
400: *---------------------------------------------------------------------
401: */
402: static void
1.69 espie 403: ParseDoSrc(
404: int tOp, /* operator (if any) from special targets */
405: const char *src) /* name of the source to handle */
1.1 deraadt 406: {
1.3 deraadt 407: GNode *gn = NULL;
1.1 deraadt 408:
1.59 espie 409: if (*src == '.' && isupper(src[1])) {
1.1 deraadt 410: int keywd = ParseFindKeyword(src);
411: if (keywd != -1) {
1.3 deraadt 412: int op = parseKeywords[keywd].op;
413: if (op != 0) {
1.63 espie 414: Array_Find(>argets, ParseDoOp, op);
1.3 deraadt 415: return;
416: }
417: if (parseKeywords[keywd].spec == Wait) {
418: waiting++;
419: return;
420: }
1.1 deraadt 421: }
422: }
1.3 deraadt 423:
424: switch (specType) {
425: case Main:
1.1 deraadt 426: /*
427: * If we have noted the existence of a .MAIN, it means we need
428: * to add the sources of said target to the list of things
1.61 espie 429: * to create. The string 'src' is likely to be freed, so we
1.1 deraadt 430: * must make a new copy of it. Note that this will only be
431: * invoked if the user didn't specify a target on the command
432: * line. This is to allow #ifmake's to succeed, or something...
433: */
1.61 espie 434: Lst_AtEnd(create, estrdup(src));
1.1 deraadt 435: /*
1.61 espie 436: * Add the name to the .TARGETS variable as well, so the user can
1.1 deraadt 437: * employ that, if desired.
438: */
439: Var_Append(".TARGETS", src, VAR_GLOBAL);
1.3 deraadt 440: return;
441:
442: case Order:
1.1 deraadt 443: /*
444: * Create proper predecessor/successor links between the previous
445: * source and the current one.
446: */
1.61 espie 447: gn = Targ_FindNode(src, TARG_CREATE);
1.33 espie 448: if (predecessor != NULL) {
1.43 espie 449: Lst_AtEnd(&predecessor->successors, gn);
450: Lst_AtEnd(&gn->preds, predecessor);
1.1 deraadt 451: }
452: /*
453: * The current source now becomes the predecessor for the next one.
454: */
455: predecessor = gn;
1.3 deraadt 456: break;
457:
458: default:
1.1 deraadt 459: /*
460: * If the source is not an attribute, we need to find/create
461: * a node for it. After that we can apply any operator to it
462: * from a special target or link it to its parents, as
463: * appropriate.
464: *
465: * In the case of a source that was the object of a :: operator,
466: * the attribute is applied to all of its instances (as kept in
467: * the 'cohorts' list of the node) or all the cohorts are linked
468: * to all the targets.
469: */
1.61 espie 470: gn = Targ_FindNode(src, TARG_CREATE);
1.1 deraadt 471: if (tOp) {
472: gn->type |= tOp;
473: } else {
1.63 espie 474: Array_ForEach(>argets, ParseLinkSrc, gn);
1.1 deraadt 475: }
476: if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
1.59 espie 477: GNode *cohort;
478: LstNode ln;
1.1 deraadt 479:
1.46 espie 480: for (ln=Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln)){
1.1 deraadt 481: cohort = (GNode *)Lst_Datum(ln);
482: if (tOp) {
483: cohort->type |= tOp;
484: } else {
1.63 espie 485: Array_ForEach(>argets, ParseLinkSrc, cohort);
1.1 deraadt 486: }
487: }
488: }
1.3 deraadt 489: break;
490: }
491:
492: gn->order = waiting;
1.63 espie 493: Array_AtEnd(&gsources, gn);
1.59 espie 494: if (waiting) {
1.63 espie 495: Array_Find(&gsources, ParseAddDep, gn);
1.59 espie 496: }
1.1 deraadt 497: }
498:
499: /*-
500: *-----------------------------------------------------------------------
501: * ParseFindMain --
502: * Find a real target in the list and set it to be the main one.
503: * Called by ParseDoDependency when a main target hasn't been found
504: * yet.
505: *
506: * Results:
1.40 espie 507: * 1 if main not found yet, 0 if it is.
1.1 deraadt 508: *
509: * Side Effects:
510: * mainNode is changed and Targ_SetMain is called.
511: *-----------------------------------------------------------------------
512: */
513: static int
1.69 espie 514: ParseFindMain(
515: void *gnp, /* Node to examine */
516: void *dummy UNUSED)
1.1 deraadt 517: {
1.59 espie 518: GNode *gn = (GNode *)gnp;
1.17 espie 519: if ((gn->type & OP_NOTARGET) == 0) {
1.1 deraadt 520: mainNode = gn;
521: Targ_SetMain(gn);
1.54 espie 522: return 0;
1.59 espie 523: } else {
1.54 espie 524: return 1;
1.59 espie 525: }
1.1 deraadt 526: }
527:
528: /*-
529: *-----------------------------------------------------------------------
530: * ParseAddDir --
531: * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going
532: *
533: * Side Effects:
534: * See Dir_AddDir.
535: *-----------------------------------------------------------------------
536: */
1.41 espie 537: static void
1.69 espie 538: ParseAddDir(void *path, void *name)
1.1 deraadt 539: {
1.61 espie 540: Dir_AddDir((Lst)path, (char *)name);
1.1 deraadt 541: }
542:
543: /*-
544: *-----------------------------------------------------------------------
545: * ParseClearPath --
1.59 espie 546: * Reinit path to an empty path
1.1 deraadt 547: *-----------------------------------------------------------------------
548: */
1.41 espie 549: static void
1.69 espie 550: ParseClearPath(void *p)
1.1 deraadt 551: {
1.59 espie 552: Lst path = (Lst)p;
553:
554: Lst_Destroy(path, Dir_Destroy);
555: Lst_Init(path);
1.1 deraadt 556: }
557:
1.77 ! espie 558: static void
! 559: add_target_node(const char *line)
! 560: {
! 561: GNode *gn;
! 562:
! 563: if (!Suff_IsTransform(line))
! 564: gn = Targ_FindNode(line, TARG_CREATE);
! 565: else
! 566: gn = Suff_AddTransform(line);
! 567:
! 568: if (gn != NULL)
! 569: Array_AtEnd(>argets, gn);
! 570: }
! 571:
! 572: static void
! 573: add_target_nodes(const char *line)
! 574: {
! 575:
! 576: if (Dir_HasWildcards(line)) {
! 577: /*
! 578: * Targets are to be sought only in the current directory,
! 579: * so create an empty path for the thing. Note we need to
! 580: * use Dir_Destroy in the destruction of the path as the
! 581: * Dir module could have added a directory to the path...
! 582: */
! 583: char *targName;
! 584: LIST emptyPath;
! 585: LIST curTargs;
! 586:
! 587: Lst_Init(&emptyPath);
! 588: Lst_Init(&curTargs);
! 589: Dir_Expand(line, &emptyPath, &curTargs);
! 590: Lst_Destroy(&emptyPath, Dir_Destroy);
! 591: while ((targName = (char *)Lst_DeQueue(&curTargs)) != NULL) {
! 592: add_target_node(line);
! 593: }
! 594: Lst_Destroy(&curTargs, NOFREE);
! 595: } else {
! 596: add_target_node(line);
! 597: }
! 598: }
! 599:
1.1 deraadt 600: /*-
601: *---------------------------------------------------------------------
602: * ParseDoDependency --
603: * Parse the dependency line in line.
604: *
605: * Side Effects:
606: * The nodes of the sources are linked as children to the nodes of the
607: * targets. Some nodes may be created.
608: *
609: * We parse a dependency line by first extracting words from the line and
610: * finding nodes in the list of all targets with that name. This is done
611: * until a character is encountered which is an operator character. Currently
612: * these are only ! and :. At this point the operator is parsed and the
613: * pointer into the line advanced until the first source is encountered.
1.59 espie 614: * The parsed operator is applied to each node in the 'targets' list,
1.1 deraadt 615: * which is where the nodes found for the targets are kept, by means of
616: * the ParseDoOp function.
617: * The sources are read in much the same way as the targets were except
618: * that now they are expanded using the wildcarding scheme of the C-Shell
619: * and all instances of the resulting words in the list of all targets
620: * are found. Each of the resulting nodes is then linked to each of the
621: * targets as one of its children.
622: * Certain targets are handled specially. These are the ones detailed
623: * by the specType variable.
624: * The storing of transformation rules is also taken care of here.
625: * A target is recognized as a transformation rule by calling
626: * Suff_IsTransform. If it is a transformation rule, its node is gotten
627: * from the suffix module via Suff_AddTransform rather than the standard
628: * Targ_FindNode in the target module.
629: *---------------------------------------------------------------------
630: */
631: static void
1.69 espie 632: ParseDoDependency(char *line) /* the line to parse */
1.1 deraadt 633: {
1.59 espie 634: char *cp; /* our current position */
635: GNode *gn; /* a general purpose temporary node */
636: int op; /* the operator on the line */
637: char savec; /* a place to save a character */
638: LIST paths; /* List of search paths to alter when parsing
1.1 deraadt 639: * a list of .PATH targets */
1.59 espie 640: int tOp; /* operator from special target */
1.1 deraadt 641: tOp = 0;
642:
643: specType = Not;
1.3 deraadt 644: waiting = 0;
1.45 espie 645: Lst_Init(&paths);
1.1 deraadt 646:
1.63 espie 647: Array_Reset(&gsources);
1.11 millert 648:
1.1 deraadt 649: do {
1.59 espie 650: for (cp = line; *cp && !isspace(*cp) && *cp != '(';)
651: if (*cp == '$')
652: /* Must be a dynamic source (would have been expanded
1.1 deraadt 653: * otherwise), so call the Var module to parse the puppy
654: * so we can safely advance beyond it...There should be
655: * no errors in this, as they would have been discovered
1.59 espie 656: * in the initial Var_Subst and we wouldn't be here. */
1.74 espie 657: Var_ParseSkip(&cp, NULL);
1.59 espie 658: else {
659: /* We don't want to end a word on ':' or '!' if there is a
660: * better match later on in the string. By "better" I mean
661: * one that is followed by whitespace. This allows the user
662: * to have targets like:
663: * fie::fi:fo: fum
664: * where "fie::fi:fo" is the target. In real life this is used
665: * for perl5 library man pages where "::" separates an object
666: * from its class. Ie: "File::Spec::Unix". This behaviour
667: * is also consistent with other versions of make. */
668: if (*cp == '!' || *cp == ':') {
669: char *p = cp + 1;
670:
671: if (*cp == ':' && *p == ':')
672: p++;
673:
674: /* Found the best match already. */
675: if (isspace(*p) || *p == '\0')
676: break;
677:
678: do {
679: p += strcspn(p, "!:");
680: if (*p == '\0')
681: break;
682: p++;
683: } while (!isspace(*p));
1.1 deraadt 684:
1.59 espie 685: /* No better match later on... */
686: if (*p == '\0')
687: break;
1.1 deraadt 688:
689: }
1.59 espie 690: cp++;
1.1 deraadt 691: }
692: if (*cp == '(') {
1.63 espie 693: LIST temp;
694: Lst_Init(&temp);
1.59 espie 695: /* Archives must be handled specially to make sure the OP_ARCHV
1.1 deraadt 696: * flag is set in their 'type' field, for one thing, and because
697: * things like "archive(file1.o file2.o file3.o)" are permissible.
698: * Arch_ParseArchive will set 'line' to be the first non-blank
699: * after the archive-spec. It creates/finds nodes for the members
1.61 espie 700: * and places them on the given list, returning true if all
701: * went well and false if there was an error in the
1.59 espie 702: * specification. On error, line should remain untouched. */
1.63 espie 703: if (!Arch_ParseArchive(&line, &temp, NULL)) {
1.59 espie 704: Parse_Error(PARSE_FATAL,
1.1 deraadt 705: "Error in archive specification: \"%s\"", line);
706: return;
707: } else {
1.63 espie 708: AppendList2Array(&temp, >argets);
709: Lst_Destroy(&temp, NOFREE);
1.1 deraadt 710: continue;
711: }
712: }
713: savec = *cp;
1.11 millert 714:
1.59 espie 715: if (*cp == '\0') {
716: /* Ending a dependency line without an operator is a Bozo no-no */
717: Parse_Error(PARSE_FATAL, "Need an operator");
1.1 deraadt 718: return;
719: }
720: *cp = '\0';
1.59 espie 721: /* Have a word in line. See if it's a special target and set
722: * specType to match it. */
723: if (*line == '.' && isupper(line[1])) {
724: /* See if the target is a special target that must have it
725: * or its sources handled specially. */
1.1 deraadt 726: int keywd = ParseFindKeyword(line);
727: if (keywd != -1) {
728: if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {
729: Parse_Error(PARSE_FATAL, "Mismatched special targets");
730: return;
731: }
1.11 millert 732:
1.1 deraadt 733: specType = parseKeywords[keywd].spec;
734: tOp = parseKeywords[keywd].op;
735:
736: /*
737: * Certain special targets have special semantics:
738: * .PATH Have to set the dirSearchPath
739: * variable too
740: * .MAIN Its sources are only used if
741: * nothing has been specified to
742: * create.
1.59 espie 743: * .DEFAULT Need to create a node to hang
1.1 deraadt 744: * commands on, but we don't want
745: * it in the graph, nor do we want
746: * it to be the Main Target, so we
747: * create it, set OP_NOTMAIN and
748: * add it to the list, setting
749: * DEFAULT to the new node for
750: * later use. We claim the node is
1.59 espie 751: * A transformation rule to make
752: * life easier later, when we'll
753: * use Make_HandleUse to actually
754: * apply the .DEFAULT commands.
1.7 niklas 755: * .PHONY The list of targets
1.59 espie 756: * .NOPATH Don't search for file in the path
1.1 deraadt 757: * .BEGIN
758: * .END
1.59 espie 759: * .INTERRUPT Are not to be considered the
1.1 deraadt 760: * main target.
1.59 espie 761: * .NOTPARALLEL Make only one target at a time.
762: * .SINGLESHELL Create a shell for each command.
763: * .ORDER Must set initial predecessor to NULL
1.1 deraadt 764: */
765: switch (specType) {
766: case ExPath:
1.61 espie 767: Lst_AtEnd(&paths, dirSearchPath);
1.1 deraadt 768: break;
769: case Main:
1.61 espie 770: if (!Lst_IsEmpty(create)) {
1.1 deraadt 771: specType = Not;
772: }
773: break;
774: case Begin:
775: case End:
776: case Interrupt:
1.61 espie 777: gn = Targ_FindNode(line, TARG_CREATE);
1.1 deraadt 778: gn->type |= OP_NOTMAIN;
1.63 espie 779: Array_AtEnd(>argets, gn);
1.1 deraadt 780: break;
781: case Default:
1.61 espie 782: gn = Targ_NewGN(".DEFAULT");
1.59 espie 783: gn->type |= OP_NOTMAIN|OP_TRANSFORM;
1.63 espie 784: Array_AtEnd(>argets, gn);
1.1 deraadt 785: DEFAULT = gn;
786: break;
787: case NotParallel:
788: {
789: extern int maxJobs;
1.11 millert 790:
1.1 deraadt 791: maxJobs = 1;
792: break;
793: }
794: case SingleShell:
795: compatMake = 1;
796: break;
797: case Order:
1.33 espie 798: predecessor = NULL;
1.1 deraadt 799: break;
800: default:
801: break;
802: }
1.59 espie 803: } else if (strncmp(line, ".PATH", 5) == 0) {
1.1 deraadt 804: /*
805: * .PATH<suffix> has to be handled specially.
806: * Call on the suffix module to give us a path to
807: * modify.
808: */
1.59 espie 809: Lst path;
1.11 millert 810:
1.1 deraadt 811: specType = ExPath;
1.45 espie 812: path = Suff_GetPath(&line[5]);
1.33 espie 813: if (path == NULL) {
1.45 espie 814: Parse_Error(PARSE_FATAL,
1.1 deraadt 815: "Suffix '%s' not defined (yet)",
816: &line[5]);
817: return;
1.59 espie 818: } else {
1.45 espie 819: Lst_AtEnd(&paths, path);
1.59 espie 820: }
1.1 deraadt 821: }
822: }
1.11 millert 823:
1.1 deraadt 824: /*
825: * Have word in line. Get or create its node and stick it at
1.11 millert 826: * the end of the targets list
1.1 deraadt 827: */
1.59 espie 828: if (specType == Not && *line != '\0') {
1.77 ! espie 829: add_target_nodes(line);
1.63 espie 830: } else if (specType == ExPath && *line != '.' && *line != '\0')
1.1 deraadt 831: Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
1.11 millert 832:
1.1 deraadt 833: *cp = savec;
834: /*
835: * If it is a special type and not .PATH, it's the only target we
836: * allow on this line...
837: */
838: if (specType != Not && specType != ExPath) {
1.61 espie 839: bool warn = false;
1.11 millert 840:
1.59 espie 841: while (*cp != '!' && *cp != ':' && *cp) {
1.1 deraadt 842: if (*cp != ' ' && *cp != '\t') {
1.61 espie 843: warn = true;
1.1 deraadt 844: }
845: cp++;
846: }
847: if (warn) {
848: Parse_Error(PARSE_WARNING, "Extra target ignored");
849: }
850: } else {
1.71 tedu 851: while (isspace(*cp)) {
1.1 deraadt 852: cp++;
853: }
854: }
855: line = cp;
1.59 espie 856: } while (*line != '!' && *line != ':' && *line);
1.1 deraadt 857:
1.63 espie 858: if (!Array_IsEmpty(>argets)) {
1.59 espie 859: switch (specType) {
1.1 deraadt 860: default:
861: Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");
862: break;
863: case Default:
864: case Begin:
865: case End:
866: case Interrupt:
1.59 espie 867: /* These four create nodes on which to hang commands, so
868: * targets shouldn't be empty... */
1.1 deraadt 869: case Not:
1.59 espie 870: /* Nothing special here -- targets can be empty if it wants. */
1.1 deraadt 871: break;
872: }
873: }
874:
1.59 espie 875: /* Have now parsed all the target names. Must parse the operator next. The
876: * result is left in op . */
1.1 deraadt 877: if (*cp == '!') {
878: op = OP_FORCE;
879: } else if (*cp == ':') {
880: if (cp[1] == ':') {
881: op = OP_DOUBLEDEP;
882: cp++;
883: } else {
884: op = OP_DEPENDS;
885: }
886: } else {
1.59 espie 887: Parse_Error(PARSE_FATAL, "Missing dependency operator");
1.1 deraadt 888: return;
889: }
890:
891: cp++; /* Advance beyond operator */
892:
1.63 espie 893: Array_Find(>argets, ParseDoOp, op);
1.1 deraadt 894:
895: /*
1.11 millert 896: * Get to the first source
1.1 deraadt 897: */
1.71 tedu 898: while (isspace(*cp)) {
1.1 deraadt 899: cp++;
900: }
901: line = cp;
902:
903: /*
904: * Several special targets take different actions if present with no
905: * sources:
906: * a .SUFFIXES line with no sources clears out all old suffixes
907: * a .PRECIOUS line makes all targets precious
908: * a .IGNORE line ignores errors for all targets
909: * a .SILENT line creates silence when making all targets
910: * a .PATH removes all directories from the search path(s).
911: */
912: if (!*line) {
913: switch (specType) {
914: case Suffixes:
1.59 espie 915: Suff_ClearSuffixes();
1.1 deraadt 916: break;
917: case Precious:
1.61 espie 918: allPrecious = true;
1.1 deraadt 919: break;
920: case Ignore:
1.61 espie 921: ignoreErrors = true;
1.1 deraadt 922: break;
923: case Silent:
1.61 espie 924: beSilent = true;
1.1 deraadt 925: break;
926: case ExPath:
1.45 espie 927: Lst_Every(&paths, ParseClearPath);
1.1 deraadt 928: break;
929: default:
930: break;
931: }
932: } else if (specType == MFlags) {
933: /*
934: * Call on functions in main.c to deal with these arguments and
935: * set the initial character to a null-character so the loop to
936: * get sources won't get anything
937: */
1.59 espie 938: Main_ParseArgLine(line);
1.1 deraadt 939: *line = '\0';
940: } else if (specType == ExShell) {
1.61 espie 941: if (!Job_ParseShell(line)) {
1.59 espie 942: Parse_Error(PARSE_FATAL, "improper shell specification");
1.1 deraadt 943: return;
944: }
945: *line = '\0';
1.59 espie 946: } else if (specType == NotParallel || specType == SingleShell) {
1.1 deraadt 947: *line = '\0';
948: }
1.11 millert 949:
1.1 deraadt 950: /*
1.11 millert 951: * NOW GO FOR THE SOURCES
1.1 deraadt 952: */
1.59 espie 953: if (specType == Suffixes || specType == ExPath ||
954: specType == Includes || specType == Libs ||
955: specType == Null) {
1.1 deraadt 956: while (*line) {
957: /*
958: * If the target was one that doesn't take files as its sources
959: * but takes something like suffixes, we take each
960: * space-separated word on the line as a something and deal
961: * with it accordingly.
962: *
963: * If the target was .SUFFIXES, we take each source as a
964: * suffix and add it to the list of suffixes maintained by the
965: * Suff module.
966: *
967: * If the target was a .PATH, we add the source as a directory
968: * to search on the search path.
969: *
970: * If it was .INCLUDES, the source is taken to be the suffix of
971: * files which will be #included and whose search path should
972: * be present in the .INCLUDES variable.
973: *
974: * If it was .LIBS, the source is taken to be the suffix of
975: * files which are considered libraries and whose search path
976: * should be present in the .LIBS variable.
977: *
978: * If it was .NULL, the source is the suffix to use when a file
979: * has no valid suffix.
980: */
981: char savec;
1.59 espie 982: while (*cp && !isspace(*cp)) {
1.1 deraadt 983: cp++;
984: }
985: savec = *cp;
986: *cp = '\0';
987: switch (specType) {
988: case Suffixes:
1.59 espie 989: Suff_AddSuffix(line);
1.1 deraadt 990: break;
991: case ExPath:
1.45 espie 992: Lst_ForEach(&paths, ParseAddDir, line);
1.1 deraadt 993: break;
994: case Includes:
1.59 espie 995: Suff_AddInclude(line);
1.1 deraadt 996: break;
997: case Libs:
1.59 espie 998: Suff_AddLib(line);
1.1 deraadt 999: break;
1000: case Null:
1.59 espie 1001: Suff_SetNull(line);
1.1 deraadt 1002: break;
1003: default:
1004: break;
1005: }
1006: *cp = savec;
1007: if (savec != '\0') {
1008: cp++;
1009: }
1.71 tedu 1010: while (isspace(*cp)) {
1.1 deraadt 1011: cp++;
1012: }
1013: line = cp;
1014: }
1.45 espie 1015: Lst_Destroy(&paths, NOFREE);
1.1 deraadt 1016: } else {
1017: while (*line) {
1018: /*
1019: * The targets take real sources, so we must beware of archive
1020: * specifications (i.e. things with left parentheses in them)
1021: * and handle them accordingly.
1022: */
1.59 espie 1023: while (*cp && !isspace(*cp)) {
1024: if (*cp == '(' && cp > line && cp[-1] != '$') {
1.1 deraadt 1025: /*
1026: * Only stop for a left parenthesis if it isn't at the
1027: * start of a word (that'll be for variable changes
1028: * later) and isn't preceded by a dollar sign (a dynamic
1029: * source).
1030: */
1031: break;
1032: } else {
1033: cp++;
1034: }
1035: }
1036:
1037: if (*cp == '(') {
1038: GNode *gn;
1.59 espie 1039: LIST sources; /* list of archive source names after
1040: * expansion */
1.1 deraadt 1041:
1.43 espie 1042: Lst_Init(&sources);
1.61 espie 1043: if (!Arch_ParseArchive(&line, &sources, NULL)) {
1.59 espie 1044: Parse_Error(PARSE_FATAL,
1.1 deraadt 1045: "Error in source archive spec \"%s\"", line);
1046: return;
1047: }
1048:
1.43 espie 1049: while ((gn = (GNode *)Lst_DeQueue(&sources)) != NULL)
1.63 espie 1050: ParseDoSrc(tOp, gn->name);
1.1 deraadt 1051: cp = line;
1052: } else {
1053: if (*cp) {
1054: *cp = '\0';
1055: cp += 1;
1056: }
1057:
1.63 espie 1058: ParseDoSrc(tOp, line);
1.1 deraadt 1059: }
1.71 tedu 1060: while (isspace(*cp)) {
1.1 deraadt 1061: cp++;
1062: }
1063: line = cp;
1064: }
1065: }
1.11 millert 1066:
1.33 espie 1067: if (mainNode == NULL) {
1.59 espie 1068: /* If we have yet to decide on a main target to make, in the
1.1 deraadt 1069: * absence of any user input, we want the first target on
1070: * the first dependency line that is actually a real target
1.59 espie 1071: * (i.e. isn't a .USE or .EXEC rule) to be made. */
1.63 espie 1072: Array_Find(>argets, ParseFindMain, NULL);
1.1 deraadt 1073: }
1074:
1.43 espie 1075: /* Finally, destroy the list of sources. */
1.1 deraadt 1076: }
1077:
1078: /*-
1.59 espie 1079: * ParseAddCmd --
1.1 deraadt 1080: * Lst_ForEach function to add a command line to all targets
1081: *
1082: * Side Effects:
1083: * A new element is added to the commands list of the node.
1084: */
1.41 espie 1085: static void
1.69 espie 1086: ParseAddCmd(
1087: void *gnp, /* the node to which the command is to be added */
1088: void *cmd) /* the command to add */
1.1 deraadt 1089: {
1.41 espie 1090: GNode *gn = (GNode *)gnp;
1.1 deraadt 1091: /* if target already supplied, ignore commands */
1.39 espie 1092: if (!(gn->type & OP_HAS_COMMANDS)) {
1.43 espie 1093: Lst_AtEnd(&gn->commands, cmd);
1.39 espie 1094: if (!gn->lineno) {
1095: gn->lineno = Parse_Getlineno();
1096: gn->fname = Parse_Getfilename();
1097: }
1098: }
1.1 deraadt 1099: }
1100:
1101: /*-
1102: *-----------------------------------------------------------------------
1103: * ParseHasCommands --
1104: * Callback procedure for Parse_File when destroying the list of
1105: * targets on the last dependency line. Marks a target as already
1106: * having commands if it does, to keep from having shell commands
1107: * on multiple dependency lines.
1108: *
1109: * Side Effects:
1110: * OP_HAS_COMMANDS may be set for the target.
1111: *-----------------------------------------------------------------------
1112: */
1113: static void
1.69 espie 1114: ParseHasCommands(void *gnp) /* Node to examine */
1.1 deraadt 1115: {
1.59 espie 1116: GNode *gn = (GNode *)gnp;
1.43 espie 1117: if (!Lst_IsEmpty(&gn->commands)) {
1.1 deraadt 1118: gn->type |= OP_HAS_COMMANDS;
1119: }
1120: }
1121:
1122: /*-
1123: *-----------------------------------------------------------------------
1124: * Parse_AddIncludeDir --
1125: * Add a directory to the path searched for included makefiles
1126: * bracketed by double-quotes. Used by functions in main.c
1127: *-----------------------------------------------------------------------
1128: */
1129: void
1.69 espie 1130: Parse_AddIncludeDir(const char *dir) /* The name of the directory to add */
1.1 deraadt 1131: {
1.61 espie 1132: Dir_AddDir(parseIncPath, dir);
1.1 deraadt 1133: }
1134:
1135: /*-
1136: *---------------------------------------------------------------------
1137: * ParseDoInclude --
1138: * Push to another file.
1.11 millert 1139: *
1.1 deraadt 1140: * The input is the line minus the #include. A file spec is a string
1141: * enclosed in <> or "". The former is looked for only in sysIncPath.
1142: * The latter in . and the directories specified by -I command line
1143: * options
1144: *
1145: * Side Effects:
1.59 espie 1146: * old parse context is pushed on the stack, new file becomes
1.50 espie 1147: * current context.
1.1 deraadt 1148: *---------------------------------------------------------------------
1149: */
1150: static void
1.69 espie 1151: ParseDoInclude(char *file)/* file specification */
1.1 deraadt 1152: {
1.59 espie 1153: char endc; /* the character which ends the file spec */
1154: char *cp; /* current position in file spec */
1.61 espie 1155: bool isSystem; /* true if makefile is a system makefile */
1.1 deraadt 1156:
1.59 espie 1157: /* Skip to delimiter character so we know where to look. */
1.50 espie 1158: while (*file == ' ' || *file == '\t')
1.1 deraadt 1159: file++;
1160:
1.50 espie 1161: if (*file != '"' && *file != '<') {
1.59 espie 1162: Parse_Error(PARSE_FATAL,
1.1 deraadt 1163: ".include filename must be delimited by '\"' or '<'");
1164: return;
1165: }
1166:
1.50 espie 1167: /* Set the search path on which to find the include file based on the
1.1 deraadt 1168: * characters which bracket its name. Angle-brackets imply it's
1.50 espie 1169: * a system Makefile while double-quotes imply it's a user makefile */
1.1 deraadt 1170: if (*file == '<') {
1.61 espie 1171: isSystem = true;
1.1 deraadt 1172: endc = '>';
1173: } else {
1.61 espie 1174: isSystem = false;
1.1 deraadt 1175: endc = '"';
1176: }
1177:
1.59 espie 1178: /* Skip to matching delimiter. */
1179: for (cp = ++file; *cp != endc; cp++) {
1180: if (*cp == '\0') {
1.50 espie 1181: Parse_Error(PARSE_FATAL,
1.1 deraadt 1182: "Unclosed %cinclude filename. '%c' expected",
1183: '.', endc);
1.50 espie 1184: return;
1.1 deraadt 1185: }
1186: }
1.61 espie 1187: ParseLookupIncludeFile(file, cp, isSystem, true);
1.1 deraadt 1188: }
1189:
1190: /*-
1191: *---------------------------------------------------------------------
1192: * ParseTraditionalInclude --
1193: * Push to another file.
1.11 millert 1194: *
1.1 deraadt 1195: * The input is the line minus the "include". The file name is
1196: * the string following the "include".
1197: *
1198: * Side Effects:
1.59 espie 1199: * old parse context is pushed on the stack, new file becomes
1.50 espie 1200: * current context.
1.59 espie 1201: *
1202: * XXX May wish to support multiple files and wildcards ?
1.1 deraadt 1203: *---------------------------------------------------------------------
1204: */
1205: static void
1.69 espie 1206: ParseTraditionalInclude(char *file) /* file specification */
1.1 deraadt 1207: {
1.59 espie 1208: char *cp; /* current position in file spec */
1.1 deraadt 1209:
1.59 espie 1210: /* Skip over whitespace. */
1211: while (isspace(*file))
1.1 deraadt 1212: file++;
1.59 espie 1213: if (*file == '\0') {
1214: Parse_Error(PARSE_FATAL,
1215: "Filename missing from \"include\"");
1216: return;
1217: }
1218: /* Skip to end of line or next whitespace. */
1219: for (cp = file; *cp != '\0' && !isspace(*cp);)
1220: cp++;
1221:
1.61 espie 1222: ParseLookupIncludeFile(file, cp, true, true);
1.59 espie 1223: }
1224:
1225: /*-
1226: *---------------------------------------------------------------------
1227: * ParseConditionalInclude --
1228: * May push to another file.
1229: *
1230: * No error if the file does not exist.
1231: * See ParseTraditionalInclude otherwise.
1232: *---------------------------------------------------------------------
1233: */
1234: static void
1.69 espie 1235: ParseConditionalInclude(char *file)/* file specification */
1.59 espie 1236: {
1237: char *cp; /* current position in file spec */
1.1 deraadt 1238:
1.59 espie 1239: /* Skip over whitespace. */
1240: while (isspace(*file))
1241: file++;
1.1 deraadt 1242: if (*file == '\0') {
1.59 espie 1243: Parse_Error(PARSE_FATAL,
1.1 deraadt 1244: "Filename missing from \"include\"");
1245: return;
1246: }
1.59 espie 1247: /* Skip to end of line or next whitespace. */
1.50 espie 1248: for (cp = file; *cp != '\0' && !isspace(*cp);)
1.59 espie 1249: cp++;
1.1 deraadt 1250:
1.61 espie 1251: ParseLookupIncludeFile(file, cp, true, false);
1.50 espie 1252: }
1.1 deraadt 1253:
1.70 espie 1254: /* helper function for ParseLookupIncludeFile */
1255: static char *
1256: find_include(const char *file, bool isSystem)
1.50 espie 1257: {
1258: char *fullname;
1.70 espie 1259:
1260: /* Look up system files on the system path first */
1261: if (isSystem) {
1262: fullname = Dir_FindFileNoDot(file, sysIncPath);
1263: if (fullname)
1264: return fullname;
1265: }
1.50 espie 1266:
1267: /* Handle non-system non-absolute files... */
1268: if (!isSystem && file[0] != '/') {
1.59 espie 1269: /* ... by first searching relative to the including file's
1270: * location. We don't want to cd there, of course, so we
1271: * just tack on the old file's leading path components
1.50 espie 1272: * and call Dir_FindFile to see if we can locate the beast. */
1.61 espie 1273: char *slash;
1274: const char *fname;
1.50 espie 1275:
1.61 espie 1276: fname = Parse_Getfilename();
1277:
1278: slash = strrchr(fname, '/');
1.50 espie 1279: if (slash != NULL) {
1.61 espie 1280: char *newName;
1.50 espie 1281:
1.61 espie 1282: newName = Str_concati(fname, slash, file, strchr(file, '\0'), '/');
1283: fullname = Dir_FindFile(newName, parseIncPath);
1.50 espie 1284: if (fullname == NULL)
1.61 espie 1285: fullname = Dir_FindFile(newName, dirSearchPath);
1.50 espie 1286: free(newName);
1.70 espie 1287: if (fullname)
1288: return fullname;
1.50 espie 1289: }
1.1 deraadt 1290: }
1291:
1.59 espie 1292: /* Now look first on the -I search path, then on the .PATH
1.50 espie 1293: * search path, if not found in a -I directory.
1294: * XXX: Suffix specific? */
1.70 espie 1295: fullname = Dir_FindFile(file, parseIncPath);
1296: if (fullname)
1297: return fullname;
1298: fullname = Dir_FindFile(file, dirSearchPath);
1299: if (fullname)
1300: return fullname;
1.1 deraadt 1301:
1.50 espie 1302: /* Still haven't found the makefile. Look for it on the system
1303: * path as a last resort. */
1.70 espie 1304: if (isSystem)
1305: return NULL;
1306: else
1307: return Dir_FindFile(file, sysIncPath);
1308: }
1309:
1310: /* Common part to lookup and read an include file. */
1311: static void
1312: ParseLookupIncludeFile(char *spec, char *endSpec, bool isSystem,
1313: bool errIfNotFound)
1314: {
1315: char *file;
1316: char *fullname;
1317: char endc;
1318:
1319: /* Substitute for any variables in the file name before trying to
1320: * find the thing. */
1321: endc = *endSpec;
1322: *endSpec = '\0';
1323: file = Var_Subst(spec, NULL, false);
1324: *endSpec = endc;
1.1 deraadt 1325:
1.70 espie 1326: fullname = find_include(file, isSystem);
1.59 espie 1327: if (fullname == NULL && errIfNotFound)
1.70 espie 1328: Parse_Error(PARSE_FATAL, "Could not find %s", file);
1.59 espie 1329:
1.1 deraadt 1330:
1.50 espie 1331: free(file);
1.1 deraadt 1332:
1.50 espie 1333: if (fullname != NULL) {
1.59 espie 1334: FILE *f;
1.1 deraadt 1335:
1.50 espie 1336: f = fopen(fullname, "r");
1.59 espie 1337: if (f == NULL && errIfNotFound) {
1.50 espie 1338: Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
1339: } else {
1340: /* Once we find the absolute path to the file, we push the current
1341: * stream to the includes stack, and start reading from the new
1342: * file. We set up the file name to be its absolute name so that
1.59 espie 1343: * error messages are informative. */
1.50 espie 1344: Parse_FromFile(fullname, f);
1345: }
1.1 deraadt 1346: }
1347: }
1348:
1.59 espie 1349:
1.72 espie 1350: static void
1351: ParseDoPoison(char *line)
1352: {
1353: char *p = line;
1354: int type = POISON_NORMAL;
1355: bool not = false;
1356: bool paren_to_match = false;
1357: char *name, *ename;
1358:
1359: while (isspace(*p))
1360: p++;
1361: if (*p == '!') {
1362: not = true;
1363: p++;
1364: }
1365: while (isspace(*p))
1366: p++;
1367: if (strncmp(p, "defined", 7) == 0) {
1368: type = POISON_DEFINED;
1369: p += 7;
1370: } else if (strncmp(p, "empty", 5) == 0) {
1371: type = POISON_EMPTY;
1372: p += 5;
1373: }
1374: while (isspace(*p))
1375: p++;
1376: if (*p == '(') {
1377: paren_to_match = true;
1378: p++;
1379: }
1380: while (isspace(*p))
1381: p++;
1382: name = ename = p;
1383: while (*p != '\0' && !isspace(*p)) {
1384: if (*p == ')' && paren_to_match) {
1385: paren_to_match = false;
1386: p++;
1387: break;
1388: }
1389: p++;
1390: ename = p;
1391: }
1392: while (isspace(*p))
1393: p++;
1394: switch(type) {
1395: case POISON_NORMAL:
1396: case POISON_EMPTY:
1397: if (not)
1398: type = POISON_INVALID;
1399: break;
1400: case POISON_DEFINED:
1401: if (not)
1402: type = POISON_NOT_DEFINED;
1403: else
1404: type = POISON_INVALID;
1405: break;
1406: }
1407: if ((*p != '\0' && *p != '#') || type == POISON_INVALID)
1408: Parse_Error(PARSE_FATAL, "Invalid syntax for .poison: %s",
1409: line);
1410: Var_MarkPoisoned(name, ename, type);
1411: }
1.59 espie 1412:
1413:
1414: /* Strip comments from the line. May return either a copy of the line, or
1415: * the line itself. */
1416: static char *
1.69 espie 1417: strip_comments(Buffer copy, const char *line)
1.59 espie 1418: {
1419: const char *comment;
1420: const char *p;
1421:
1422: comment = strchr(line, '#');
1423: assert(comment != line);
1424: if (comment == NULL)
1425: return (char *)line;
1426: else {
1427: Buf_Reset(copy);
1428:
1429: for (p = line; *p != '\0'; p++) {
1430: if (*p == '\\') {
1431: if (p[1] == '#') {
1.61 espie 1432: Buf_Addi(copy, line, p);
1.59 espie 1433: Buf_AddChar(copy, '#');
1434: line = p+2;
1435: }
1436: if (p[1] != '\0')
1437: p++;
1438: } else if (*p == '#')
1439: break;
1440: }
1.61 espie 1441: Buf_Addi(copy, line, p);
1.59 espie 1442: Buf_KillTrailingSpaces(copy);
1443: return Buf_Retrieve(copy);
1444: }
1445: }
1446:
1.61 espie 1447: static bool
1.69 espie 1448: ParseIsCond(Buffer linebuf, Buffer copy, char *line)
1.59 espie 1449: {
1450:
1451: char *stripped;
1452:
1.71 tedu 1453: while (isspace(*line))
1.59 espie 1454: line++;
1455:
1456: /* The line might be a conditional. Ask the conditional module
1457: * about it and act accordingly. */
1458: switch (Cond_Eval(line)) {
1459: case COND_SKIP:
1460: /* Skip to next conditional that evaluates to COND_PARSE. */
1461: do {
1.61 espie 1462: line = Parse_ReadNextConditionalLine(linebuf);
1.59 espie 1463: if (line != NULL) {
1.71 tedu 1464: while (isspace(*line))
1.59 espie 1465: line++;
1466: stripped = strip_comments(copy, line);
1467: }
1468: } while (line != NULL && Cond_Eval(stripped) != COND_PARSE);
1469: /* FALLTHROUGH */
1470: case COND_PARSE:
1.61 espie 1471: return true;
1.67 espie 1472: case COND_ISFOR: {
1473: For *loop;
1474:
1475: loop = For_Eval(line+3);
1476: if (loop != NULL) {
1477: bool ok;
1478: do {
1479: /* Find the matching endfor. */
1480: line = ParseReadLoopLine(linebuf);
1481: if (line == NULL) {
1482: Parse_Error(PARSE_FATAL,
1483: "Unexpected end of file in for loop.\n");
1484: return false;
1485: }
1486: ok = For_Accumulate(loop, line);
1487: } while (ok);
1488: For_Run(loop);
1489: return true;
1490: }
1.59 espie 1491: break;
1492: }
1.67 espie 1493: case COND_ISINCLUDE:
1.59 espie 1494: ParseDoInclude(line + 7);
1.61 espie 1495: return true;
1.72 espie 1496: case COND_ISPOISON:
1497: ParseDoPoison(line + 6);
1498: return true;
1.67 espie 1499: case COND_ISUNDEF: {
1.59 espie 1500: char *cp;
1501:
1502: line+=5;
1.71 tedu 1503: while (isspace(*line))
1.59 espie 1504: line++;
1505: for (cp = line; !isspace(*cp) && *cp != '\0';)
1506: cp++;
1.73 espie 1507: Var_Deletei(line, cp);
1.61 espie 1508: return true;
1.59 espie 1509: }
1.67 espie 1510: default:
1511: break;
1512: }
1513:
1.61 espie 1514: return false;
1.59 espie 1515: }
1516:
1.1 deraadt 1517: /*-
1518: *-----------------------------------------------------------------------
1.59 espie 1519: * ParseFinishDependency --
1.1 deraadt 1520: * Handle the end of a dependency group.
1521: *
1522: * Side Effects:
1.59 espie 1523: * 'targets' list destroyed.
1.1 deraadt 1524: *
1525: *-----------------------------------------------------------------------
1526: */
1527: static void
1.69 espie 1528: ParseFinishDependency(void)
1.1 deraadt 1529: {
1.63 espie 1530: Array_Every(>argets, Suff_EndTransform);
1531: Array_Every(>argets, ParseHasCommands);
1532: Array_Reset(>argets);
1.1 deraadt 1533: }
1.11 millert 1534:
1.59 espie 1535: static void
1.69 espie 1536: ParseDoCommands(const char *line)
1.59 espie 1537: {
1538: /* add the command to the list of
1539: * commands of all targets in the dependency spec */
1540: char *cmd = estrdup(line);
1541:
1.63 espie 1542: Array_ForEach(>argets, ParseAddCmd, cmd);
1.59 espie 1543: #ifdef CLEANUP
1544: Lst_AtEnd(&targCmds, cmd);
1545: #endif
1546: }
1.1 deraadt 1547:
1548: void
1.69 espie 1549: Parse_File(
1550: const char *name, /* the name of the file being read */
1551: FILE *stream) /* Stream open to makefile to parse */
1.1 deraadt 1552: {
1.59 espie 1553: char *cp, /* pointer into the line */
1554: *line; /* the line we're working on */
1.61 espie 1555: bool inDependency; /* true if currently in a dependency
1.59 espie 1556: * line or its commands */
1557:
1558: BUFFER buf;
1559: BUFFER copy;
1560:
1561: Buf_Init(&buf, MAKE_BSIZE);
1562: Buf_Init(©, MAKE_BSIZE);
1.61 espie 1563: inDependency = false;
1.59 espie 1564: Parse_FromFile(name, stream);
1.1 deraadt 1565:
1566: do {
1.61 espie 1567: while ((line = Parse_ReadNormalLine(&buf)) != NULL) {
1.1 deraadt 1568: if (*line == '\t') {
1.59 espie 1569: if (inDependency)
1570: ParseDoCommands(line+1);
1571: else
1572: Parse_Error(PARSE_FATAL,
1573: "Unassociated shell command \"%s\"",
1574: line);
1.1 deraadt 1575: } else {
1.59 espie 1576: char *stripped;
1577: stripped = strip_comments(©, line);
1578: if (*stripped == '.' && ParseIsCond(&buf, ©, stripped+1))
1579: ;
1580: else if (FEATURES(FEATURE_SYSVINCLUDE) &&
1581: strncmp(stripped, "include", 7) == 0 &&
1582: isspace(stripped[7]) &&
1583: strchr(stripped, ':') == NULL) {
1584: /* It's an S3/S5-style "include". */
1585: ParseTraditionalInclude(stripped + 7);
1586: } else if (FEATURES(FEATURE_CONDINCLUDE) &&
1587: (*stripped == '-' || *stripped == 's') &&
1588: strncmp(stripped+1, "include", 7) == 0 &&
1589: isspace(stripped[8]) &&
1590: strchr(stripped, ':') == NULL) {
1591: ParseConditionalInclude(stripped+8);
1592: } else {
1593: char *dep;
1.11 millert 1594:
1.59 espie 1595: if (inDependency)
1596: ParseFinishDependency();
1.72 espie 1597: if (Parse_DoVar(stripped))
1.61 espie 1598: inDependency = false;
1599: else {
1.59 espie 1600: size_t pos;
1601: char *end;
1.11 millert 1602:
1.59 espie 1603: /* Need a new list for the target nodes. */
1.63 espie 1604: Array_Reset(>argets);
1.61 espie 1605: inDependency = true;
1.59 espie 1606:
1607: dep = NULL;
1608: /* First we need to find eventual dependencies */
1609: pos = strcspn(stripped, ":!");
1610: /* go over :!, and find ; */
1611: if (stripped[pos] != '\0' &&
1612: (end = strchr(stripped+pos+1, ';')) != NULL) {
1613: if (line != stripped)
1614: /* find matching ; in original... The
1615: * original might be slightly longer. */
1616: dep = strchr(line+(end-stripped), ';');
1617: else
1618: dep = end;
1619: /* kill end of line. */
1620: *end = '\0';
1621: }
1622: /* We now know it's a dependency line so it needs to
1623: * have all variables expanded before being parsed.
1624: * Tell the variable module to complain if some
1625: * variable is undefined... */
1.61 espie 1626: cp = Var_Subst(stripped, NULL, true);
1.59 espie 1627: ParseDoDependency(cp);
1628: free(cp);
1629:
1630: /* Parse dependency if it's not empty. */
1631: if (dep != NULL) {
1632: do {
1633: dep++;
1634: } while (isspace(*dep));
1635: if (*dep != '\0')
1636: ParseDoCommands(dep);
1637: }
1.1 deraadt 1638: }
1639: }
1640: }
1641: }
1.50 espie 1642: } while (Parse_NextFile());
1.1 deraadt 1643:
1.59 espie 1644: if (inDependency)
1645: ParseFinishDependency();
1646: /* Make sure conditionals are clean. */
1.1 deraadt 1647: Cond_End();
1648:
1.61 espie 1649: Parse_ReportErrors();
1.59 espie 1650: Buf_Destroy(&buf);
1651: Buf_Destroy(©);
1.1 deraadt 1652: }
1653:
1654: void
1.69 espie 1655: Parse_Init(void)
1.1 deraadt 1656: {
1.33 espie 1657: mainNode = NULL;
1.66 espie 1658: Static_Lst_Init(parseIncPath);
1659: Static_Lst_Init(sysIncPath);
1.63 espie 1660: Array_Init(&gsources, SOURCES_SIZE);
1661: Array_Init(>argets, TARGETS_SIZE);
1662:
1.61 espie 1663: LowParse_Init();
1.20 espie 1664: #ifdef CLEANUP
1.66 espie 1665: Static_Lst_Init(&targCmds);
1.20 espie 1666: #endif
1.1 deraadt 1667: }
1668:
1.61 espie 1669: #ifdef CLEANUP
1.1 deraadt 1670: void
1.69 espie 1671: Parse_End(void)
1.1 deraadt 1672: {
1.43 espie 1673: Lst_Destroy(&targCmds, (SimpleProc)free);
1.61 espie 1674: Lst_Destroy(sysIncPath, Dir_Destroy);
1675: Lst_Destroy(parseIncPath, Dir_Destroy);
1.50 espie 1676: LowParse_End();
1.61 espie 1677: }
1.20 espie 1678: #endif
1.11 millert 1679:
1.1 deraadt 1680:
1.44 espie 1681: void
1.69 espie 1682: Parse_MainName(Lst listmain) /* result list */
1.1 deraadt 1683: {
1684:
1.59 espie 1685: if (mainNode == NULL) {
1686: Punt("no target to make.");
1687: /*NOTREACHED*/
1688: } else if (mainNode->type & OP_DOUBLEDEP) {
1.37 espie 1689: Lst_AtEnd(listmain, mainNode);
1.45 espie 1690: Lst_Concat(listmain, &mainNode->cohorts);
1.1 deraadt 1691: }
1692: else
1.37 espie 1693: Lst_AtEnd(listmain, mainNode);
1.1 deraadt 1694: }
1.59 espie 1695: