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