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