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