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