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