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