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