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