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