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