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