summaryrefslogtreecommitdiff
path: root/bootstrap/bmake/parse.c
diff options
context:
space:
mode:
Diffstat (limited to 'bootstrap/bmake/parse.c')
-rw-r--r--bootstrap/bmake/parse.c2825
1 files changed, 0 insertions, 2825 deletions
diff --git a/bootstrap/bmake/parse.c b/bootstrap/bmake/parse.c
deleted file mode 100644
index 69ae9d21ad8..00000000000
--- a/bootstrap/bmake/parse.c
+++ /dev/null
@@ -1,2825 +0,0 @@
-/* $NetBSD: parse.c,v 1.1.1.1 2004/03/11 13:04:12 grant Exp $ */
-
-/*
- * Copyright (c) 1988, 1989, 1990, 1993
- * The Regents of the University of California. All rights reserved.
- * Copyright (c) 1989 by Berkeley Softworks
- * All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Adam de Boor.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifdef MAKE_BOOTSTRAP
-static char rcsid[] = "$NetBSD: parse.c,v 1.1.1.1 2004/03/11 13:04:12 grant Exp $";
-#else
-#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";
-#else
-__RCSID("$NetBSD: parse.c,v 1.1.1.1 2004/03/11 13:04:12 grant Exp $");
-#endif
-#endif /* not lint */
-#endif
-
-#if !defined(MAKE_BOOTSTRAP) && !defined(lint)
-__IDSTRING(rcs_id,"$Id: parse.c,v 1.1.1.1 2004/03/11 13:04:12 grant Exp $");
-#endif
-
-/*-
- * parse.c --
- * Functions to parse a makefile.
- *
- * One function, Parse_Init, must be called before any functions
- * in this module are used. After that, the function Parse_File is the
- * main entry point and controls most of the other functions in this
- * module.
- *
- * Most important structures are kept in Lsts. Directories for
- * the #include "..." function are kept in the 'parseIncPath' Lst, while
- * those for the #include <...> are kept in the 'sysIncPath' Lst. The
- * targets currently being defined are kept in the 'targets' Lst.
- *
- * The variables 'fname' and 'lineno' are used to track the name
- * of the current file and the line number in that file so that error
- * messages can be more meaningful.
- *
- * Interface:
- * Parse_Init Initialization function which must be
- * called before anything else in this module
- * is used.
- *
- * Parse_End Cleanup the module
- *
- * Parse_File Function used to parse a makefile. It must
- * be given the name of the file, which should
- * already have been opened, and a function
- * to call to read a character from the file.
- *
- * Parse_IsVar Returns TRUE if the given line is a
- * variable assignment. Used by MainParseArgs
- * to determine if an argument is a target
- * or a variable assignment. Used internally
- * for pretty much the same thing...
- *
- * Parse_Error Function called when an error occurs in
- * parsing. Used by the variable and
- * conditional modules.
- * Parse_MainName Returns a Lst of the main target to create.
- */
-
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <varargs.h>
-#endif
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
-#include "make.h"
-#include "hash.h"
-#include "dir.h"
-#include "job.h"
-#include "buf.h"
-#include "pathnames.h"
-
-/*
- * These values are returned by ParseEOF to tell Parse_File whether to
- * CONTINUE parsing, i.e. it had only reached the end of an include file,
- * or if it's DONE.
- */
-#define CONTINUE 1
-#define DONE 0
-static Lst targets; /* targets we're working on */
-#ifdef CLEANUP
-static Lst targCmds; /* command lines for targets */
-#endif
-static Boolean inLine; /* true if currently in a dependency
- * line or its commands */
-typedef struct {
- char *str;
- char *ptr;
-} PTR;
-
-static char *fname; /* name of current file (for errors) */
-static int lineno; /* line number in current file */
-static FILE *curFILE = NULL; /* current makefile */
-
-static PTR *curPTR = NULL; /* current makefile */
-
-static int fatals = 0;
-
-static GNode *mainNode; /* The main target to create. This is the
- * first target on the first dependency
- * line in the first makefile */
-/*
- * Definitions for handling #include specifications
- */
-typedef struct IFile {
- char *fname; /* name of previous file */
- int lineno; /* saved line number */
- FILE * F; /* the open stream */
- PTR * p; /* the char pointer */
-} IFile;
-
-static Lst includes; /* stack of IFiles generated by
- * #includes */
-Lst parseIncPath; /* list of directories for "..." includes */
-Lst sysIncPath; /* list of directories for <...> includes */
-
-/*-
- * specType contains the SPECial TYPE of the current target. It is
- * Not if the target is unspecial. If it *is* special, however, the children
- * are linked as children of the parent but not vice versa. This variable is
- * set in ParseDoDependency
- */
-typedef enum {
- Begin, /* .BEGIN */
- Default, /* .DEFAULT */
- End, /* .END */
- Ignore, /* .IGNORE */
- Includes, /* .INCLUDES */
- Interrupt, /* .INTERRUPT */
- Libs, /* .LIBS */
- MFlags, /* .MFLAGS or .MAKEFLAGS */
- Main, /* .MAIN and we don't have anything user-specified to
- * make */
- NoExport, /* .NOEXPORT */
- NoPath, /* .NOPATH */
- Not, /* Not special */
- NotParallel, /* .NOTPARALELL */
- Null, /* .NULL */
- Order, /* .ORDER */
- Parallel, /* .PARALLEL */
- ExPath, /* .PATH */
- Phony, /* .PHONY */
-#ifdef POSIX
- Posix, /* .POSIX */
-#endif
- Precious, /* .PRECIOUS */
- ExShell, /* .SHELL */
- Silent, /* .SILENT */
- SingleShell, /* .SINGLESHELL */
- Suffixes, /* .SUFFIXES */
- Wait, /* .WAIT */
- Attribute /* Generic attribute */
-} ParseSpecial;
-
-static ParseSpecial specType;
-static int waiting;
-
-/*
- * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER
- * seen, then set to each successive source on the line.
- */
-static GNode *predecessor;
-
-/*
- * The parseKeywords table is searched using binary search when deciding
- * if a target or source is special. The 'spec' field is the ParseSpecial
- * type of the keyword ("Not" if the keyword isn't special as a target) while
- * the 'op' field is the operator to apply to the list of targets if the
- * keyword is used as a source ("0" if the keyword isn't special as a source)
- */
-static struct {
- char *name; /* Name of keyword */
- ParseSpecial spec; /* Type when used as a target */
- int op; /* Operator when used as a source */
-} parseKeywords[] = {
-{ ".BEGIN", Begin, 0 },
-{ ".DEFAULT", Default, 0 },
-{ ".END", End, 0 },
-{ ".EXEC", Attribute, OP_EXEC },
-{ ".IGNORE", Ignore, OP_IGNORE },
-{ ".INCLUDES", Includes, 0 },
-{ ".INTERRUPT", Interrupt, 0 },
-{ ".INVISIBLE", Attribute, OP_INVISIBLE },
-{ ".JOIN", Attribute, OP_JOIN },
-{ ".LIBS", Libs, 0 },
-{ ".MADE", Attribute, OP_MADE },
-{ ".MAIN", Main, 0 },
-{ ".MAKE", Attribute, OP_MAKE },
-{ ".MAKEFLAGS", MFlags, 0 },
-{ ".MFLAGS", MFlags, 0 },
-{ ".NOPATH", NoPath, OP_NOPATH },
-{ ".NOTMAIN", Attribute, OP_NOTMAIN },
-{ ".NOTPARALLEL", NotParallel, 0 },
-{ ".NO_PARALLEL", NotParallel, 0 },
-{ ".NULL", Null, 0 },
-{ ".OPTIONAL", Attribute, OP_OPTIONAL },
-{ ".ORDER", Order, 0 },
-{ ".PARALLEL", Parallel, 0 },
-{ ".PATH", ExPath, 0 },
-{ ".PHONY", Phony, OP_PHONY },
-#ifdef POSIX
-{ ".POSIX", Posix, 0 },
-#endif
-{ ".PRECIOUS", Precious, OP_PRECIOUS },
-{ ".RECURSIVE", Attribute, OP_MAKE },
-{ ".SHELL", ExShell, 0 },
-{ ".SILENT", Silent, OP_SILENT },
-{ ".SINGLESHELL", SingleShell, 0 },
-{ ".SUFFIXES", Suffixes, 0 },
-{ ".USE", Attribute, OP_USE },
-{ ".USEBEFORE", Attribute, OP_USEBEFORE },
-{ ".WAIT", Wait, 0 },
-};
-
-static void ParseErrorInternal __P((char *, size_t, int, char *, ...))
- __attribute__((__format__(__printf__, 4, 5)));
-static void ParseVErrorInternal __P((char *, size_t, int, char *, va_list))
- __attribute__((__format__(__printf__, 4, 0)));
-static int ParseFindKeyword __P((char *));
-static int ParseLinkSrc __P((ClientData, ClientData));
-static int ParseDoOp __P((ClientData, ClientData));
-static int ParseAddDep __P((ClientData, ClientData));
-static void ParseDoSrc __P((int, char *, Lst));
-static int ParseFindMain __P((ClientData, ClientData));
-static int ParseAddDir __P((ClientData, ClientData));
-static int ParseClearPath __P((ClientData, ClientData));
-static void ParseDoDependency __P((char *));
-static int ParseAddCmd __P((ClientData, ClientData));
-static __inline int ParseReadc __P((void));
-static void ParseUnreadc __P((int));
-static void ParseHasCommands __P((ClientData));
-static void ParseDoInclude __P((char *));
-static void ParseSetParseFile __P((char *));
-#ifdef SYSVINCLUDE
-static void ParseTraditionalInclude __P((char *));
-#endif
-static int ParseEOF __P((int));
-static char *ParseReadLine __P((void));
-static char *ParseSkipLine __P((int));
-static void ParseFinishLine __P((void));
-static void ParseMark __P((GNode *));
-
-extern int maxJobs;
-
-/*-
- *----------------------------------------------------------------------
- * ParseFindKeyword --
- * Look in the table of keywords for one matching the given string.
- *
- * Results:
- * The index of the keyword, or -1 if it isn't there.
- *
- * Side Effects:
- * None
- *----------------------------------------------------------------------
- */
-static int
-ParseFindKeyword (str)
- char *str; /* String to find */
-{
- register int start,
- end,
- cur;
- register int diff;
-
- start = 0;
- end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;
-
- do {
- cur = start + ((end - start) / 2);
- diff = strcmp (str, parseKeywords[cur].name);
-
- if (diff == 0) {
- return (cur);
- } else if (diff < 0) {
- end = cur - 1;
- } else {
- start = cur + 1;
- }
- } while (start <= end);
- return (-1);
-}
-
-/*-
- * ParseVErrorInternal --
- * Error message abort function for parsing. Prints out the context
- * of the error (line number and file) as well as the message with
- * two optional arguments.
- *
- * Results:
- * None
- *
- * Side Effects:
- * "fatals" is incremented if the level is PARSE_FATAL.
- */
-/* VARARGS */
-static void
-#ifdef __STDC__
-ParseVErrorInternal(char *cfname, size_t clineno, int type, char *fmt,
- va_list ap)
-#else
-ParseVErrorInternal(va_alist)
- va_dcl
-#endif
-{
- static Boolean fatal_warning_error_printed = FALSE;
-
- (void)fprintf(stderr, "%s: \"", progname);
-
- if (*cfname != '/') {
- char *cp, *dir;
-
- /*
- * Nothing is more anoying than not knowing which Makefile
- * is the culprit.
- */
- dir = Var_Value(".PARSEDIR", VAR_GLOBAL, &cp);
- if (dir == NULL || *dir == '\0' ||
- (*dir == '.' && dir[1] == '\0'))
- dir = Var_Value(".CURDIR", VAR_GLOBAL, &cp);
- if (dir == NULL)
- dir = ".";
-
- (void)fprintf(stderr, "%s/%s", dir, cfname);
- } else
- (void)fprintf(stderr, "%s", cfname);
-
- (void)fprintf(stderr, "\" line %d: ", (int)clineno);
- if (type == PARSE_WARNING)
- (void)fprintf(stderr, "warning: ");
- (void)vfprintf(stderr, fmt, ap);
- (void)fprintf(stderr, "\n");
- (void)fflush(stderr);
- if (type == PARSE_FATAL || parseWarnFatal)
- fatals += 1;
- if (parseWarnFatal && !fatal_warning_error_printed) {
- Error("parsing warnings being treated as errors");
- fatal_warning_error_printed = TRUE;
- }
-}
-
-/*-
- * ParseErrorInternal --
- * Error function
- *
- * Results:
- * None
- *
- * Side Effects:
- * None
- */
-/* VARARGS */
-static void
-#ifdef __STDC__
-ParseErrorInternal(char *cfname, size_t clineno, int type, char *fmt, ...)
-#else
-ParseErrorInternal(va_alist)
- va_dcl
-#endif
-{
- va_list ap;
-#ifdef __STDC__
- va_start(ap, fmt);
-#else
- int type; /* Error type (PARSE_WARNING, PARSE_FATAL) */
- char *fmt;
- char *cfname;
- size_t clineno;
-
- va_start(ap);
- cfname = va_arg(ap, char *);
- clineno = va_arg(ap, size_t);
- type = va_arg(ap, int);
- fmt = va_arg(ap, char *);
-#endif
-
- ParseVErrorInternal(cfname, clineno, type, fmt, ap);
- va_end(ap);
-}
-
-/*-
- * Parse_Error --
- * External interface to ParseErrorInternal; uses the default filename
- * Line number.
- *
- * Results:
- * None
- *
- * Side Effects:
- * None
- */
-/* VARARGS */
-void
-#ifdef __STDC__
-Parse_Error(int type, char *fmt, ...)
-#else
-Parse_Error(va_alist)
- va_dcl
-#endif
-{
- va_list ap;
-#ifdef __STDC__
- va_start(ap, fmt);
-#else
- int type; /* Error type (PARSE_WARNING, PARSE_FATAL) */
- char *fmt;
-
- va_start(ap);
- type = va_arg(ap, int);
- fmt = va_arg(ap, char *);
-#endif
- ParseVErrorInternal(fname, lineno, type, fmt, ap);
- va_end(ap);
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseLinkSrc --
- * Link the parent node to its new child. Used in a Lst_ForEach by
- * ParseDoDependency. If the specType isn't 'Not', the parent
- * isn't linked as a parent of the child.
- *
- * Results:
- * Always = 0
- *
- * Side Effects:
- * New elements are added to the parents list of cgn and the
- * children list of cgn. the unmade field of pgn is updated
- * to reflect the additional child.
- *---------------------------------------------------------------------
- */
-static int
-ParseLinkSrc (pgnp, cgnp)
- ClientData pgnp; /* The parent node */
- ClientData cgnp; /* The child node */
-{
- GNode *pgn = (GNode *) pgnp;
- GNode *cgn = (GNode *) cgnp;
-
- if ((pgn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (pgn->cohorts))
- pgn = (GNode *) Lst_Datum (Lst_Last (pgn->cohorts));
- (void)Lst_AtEnd (pgn->children, (ClientData)cgn);
- if (specType == Not)
- (void)Lst_AtEnd (cgn->parents, (ClientData)pgn);
- pgn->unmade += 1;
- return (0);
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseDoOp --
- * Apply the parsed operator to the given target node. Used in a
- * Lst_ForEach call by ParseDoDependency once all targets have
- * been found and their operator parsed. If the previous and new
- * operators are incompatible, a major error is taken.
- *
- * Results:
- * Always 0
- *
- * Side Effects:
- * The type field of the node is altered to reflect any new bits in
- * the op.
- *---------------------------------------------------------------------
- */
-static int
-ParseDoOp (gnp, opp)
- ClientData gnp; /* The node to which the operator is to be
- * applied */
- ClientData opp; /* The operator to apply */
-{
- GNode *gn = (GNode *) gnp;
- int op = *(int *) opp;
- /*
- * If the dependency mask of the operator and the node don't match and
- * the node has actually had an operator applied to it before, and
- * the operator actually has some dependency information in it, complain.
- */
- if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
- !OP_NOP(gn->type) && !OP_NOP(op))
- {
- Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name);
- return (1);
- }
-
- if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
- /*
- * If the node was the object of a :: operator, we need to create a
- * new instance of it for the children and commands on this dependency
- * line. The new instance is placed on the 'cohorts' list of the
- * initial one (note the initial one is not on its own cohorts list)
- * and the new instance is linked to all parents of the initial
- * instance.
- */
- register GNode *cohort;
-
- /*
- * Propagate copied bits to the initial node. They'll be propagated
- * back to the rest of the cohorts later.
- */
- gn->type |= op & ~OP_OPMASK;
-
- cohort = Targ_NewGN(gn->name);
- /*
- * Make the cohort invisible as well to avoid duplicating it into
- * other variables. True, parents of this target won't tend to do
- * anything with their local variables, but better safe than
- * sorry. (I think this is pointless now, since the relevant list
- * traversals will no longer see this node anyway. -mycroft)
- */
- cohort->type = op | OP_INVISIBLE;
- (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort);
- } else {
- /*
- * We don't want to nuke any previous flags (whatever they were) so we
- * just OR the new operator into the old
- */
- gn->type |= op;
- }
-
- return (0);
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseAddDep --
- * Check if the pair of GNodes given needs to be synchronized.
- * This has to be when two nodes are on different sides of a
- * .WAIT directive.
- *
- * Results:
- * Returns 1 if the two targets need to be ordered, 0 otherwise.
- * If it returns 1, the search can stop
- *
- * Side Effects:
- * A dependency can be added between the two nodes.
- *
- *---------------------------------------------------------------------
- */
-static int
-ParseAddDep(pp, sp)
- ClientData pp;
- ClientData sp;
-{
- GNode *p = (GNode *) pp;
- GNode *s = (GNode *) sp;
-
- if (p->order < s->order) {
- /*
- * XXX: This can cause loops, and loops can cause unmade targets,
- * but checking is tedious, and the debugging output can show the
- * problem
- */
- (void)Lst_AtEnd(p->successors, (ClientData)s);
- (void)Lst_AtEnd(s->preds, (ClientData)p);
- return 0;
- }
- else
- return 1;
-}
-
-
-/*-
- *---------------------------------------------------------------------
- * ParseDoSrc --
- * Given the name of a source, figure out if it is an attribute
- * and apply it to the targets if it is. Else decide if there is
- * some attribute which should be applied *to* the source because
- * of some special target and apply it if so. Otherwise, make the
- * source be a child of the targets in the list 'targets'
- *
- * Results:
- * None
- *
- * Side Effects:
- * Operator bits may be added to the list of targets or to the source.
- * The targets may have a new source added to their lists of children.
- *---------------------------------------------------------------------
- */
-static void
-ParseDoSrc (tOp, src, allsrc)
- int tOp; /* operator (if any) from special targets */
- char *src; /* name of the source to handle */
- Lst allsrc; /* List of all sources to wait for */
-
-{
- GNode *gn = NULL;
-
- if (*src == '.' && isupper ((unsigned char)src[1])) {
- int keywd = ParseFindKeyword(src);
- if (keywd != -1) {
- int op = parseKeywords[keywd].op;
- if (op != 0) {
- Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
- return;
- }
- if (parseKeywords[keywd].spec == Wait) {
- waiting++;
- return;
- }
- }
- }
-
- switch (specType) {
- case Main:
- /*
- * If we have noted the existence of a .MAIN, it means we need
- * to add the sources of said target to the list of things
- * to create. The string 'src' is likely to be free, so we
- * must make a new copy of it. Note that this will only be
- * invoked if the user didn't specify a target on the command
- * line. This is to allow #ifmake's to succeed, or something...
- */
- (void) Lst_AtEnd (create, (ClientData)estrdup(src));
- /*
- * Add the name to the .TARGETS variable as well, so the user cna
- * employ that, if desired.
- */
- Var_Append(".TARGETS", src, VAR_GLOBAL);
- return;
-
- case Order:
- /*
- * Create proper predecessor/successor links between the previous
- * source and the current one.
- */
- gn = Targ_FindNode(src, TARG_CREATE);
- if (predecessor != NILGNODE) {
- (void)Lst_AtEnd(predecessor->successors, (ClientData)gn);
- (void)Lst_AtEnd(gn->preds, (ClientData)predecessor);
- }
- /*
- * The current source now becomes the predecessor for the next one.
- */
- predecessor = gn;
- break;
-
- default:
- /*
- * If the source is not an attribute, we need to find/create
- * a node for it. After that we can apply any operator to it
- * from a special target or link it to its parents, as
- * appropriate.
- *
- * In the case of a source that was the object of a :: operator,
- * the attribute is applied to all of its instances (as kept in
- * the 'cohorts' list of the node) or all the cohorts are linked
- * to all the targets.
- */
- gn = Targ_FindNode (src, TARG_CREATE);
- if (tOp) {
- gn->type |= tOp;
- } else {
- Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn);
- }
- break;
- }
-
- gn->order = waiting;
- (void)Lst_AtEnd(allsrc, (ClientData)gn);
- if (waiting) {
- Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseFindMain --
- * Find a real target in the list and set it to be the main one.
- * Called by ParseDoDependency when a main target hasn't been found
- * yet.
- *
- * Results:
- * 0 if main not found yet, 1 if it is.
- *
- * Side Effects:
- * mainNode is changed and Targ_SetMain is called.
- *
- *-----------------------------------------------------------------------
- */
-static int
-ParseFindMain(gnp, dummy)
- ClientData gnp; /* Node to examine */
- ClientData dummy;
-{
- GNode *gn = (GNode *) gnp;
- if ((gn->type & OP_NOTARGET) == 0) {
- mainNode = gn;
- Targ_SetMain(gn);
- return (dummy ? 1 : 1);
- } else {
- return (dummy ? 0 : 0);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseAddDir --
- * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going
- *
- * Results:
- * === 0
- *
- * Side Effects:
- * See Dir_AddDir.
- *
- *-----------------------------------------------------------------------
- */
-static int
-ParseAddDir(path, name)
- ClientData path;
- ClientData name;
-{
- (void) Dir_AddDir((Lst) path, (char *) name);
- return(0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseClearPath --
- * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going
- *
- * Results:
- * === 0
- *
- * Side Effects:
- * See Dir_ClearPath
- *
- *-----------------------------------------------------------------------
- */
-static int
-ParseClearPath(path, dummy)
- ClientData path;
- ClientData dummy;
-{
- Dir_ClearPath((Lst) path);
- return(dummy ? 0 : 0);
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseDoDependency --
- * Parse the dependency line in line.
- *
- * Results:
- * None
- *
- * Side Effects:
- * The nodes of the sources are linked as children to the nodes of the
- * targets. Some nodes may be created.
- *
- * We parse a dependency line by first extracting words from the line and
- * finding nodes in the list of all targets with that name. This is done
- * until a character is encountered which is an operator character. Currently
- * these are only ! and :. At this point the operator is parsed and the
- * pointer into the line advanced until the first source is encountered.
- * The parsed operator is applied to each node in the 'targets' list,
- * which is where the nodes found for the targets are kept, by means of
- * the ParseDoOp function.
- * The sources are read in much the same way as the targets were except
- * that now they are expanded using the wildcarding scheme of the C-Shell
- * and all instances of the resulting words in the list of all targets
- * are found. Each of the resulting nodes is then linked to each of the
- * targets as one of its children.
- * Certain targets are handled specially. These are the ones detailed
- * by the specType variable.
- * The storing of transformation rules is also taken care of here.
- * A target is recognized as a transformation rule by calling
- * Suff_IsTransform. If it is a transformation rule, its node is gotten
- * from the suffix module via Suff_AddTransform rather than the standard
- * Targ_FindNode in the target module.
- *---------------------------------------------------------------------
- */
-static void
-ParseDoDependency (line)
- char *line; /* the line to parse */
-{
- char *cp; /* our current position */
- GNode *gn; /* a general purpose temporary node */
- int op; /* the operator on the line */
- char savec; /* a place to save a character */
- Lst paths; /* List of search paths to alter when parsing
- * a list of .PATH targets */
- int tOp; /* operator from special target */
- Lst sources; /* list of archive source names after
- * expansion */
- Lst curTargs; /* list of target names to be found and added
- * to the targets list */
- Lst curSrcs; /* list of sources in order */
-
- tOp = 0;
-
- specType = Not;
- waiting = 0;
- paths = (Lst)NULL;
-
- curTargs = Lst_Init(FALSE);
- curSrcs = Lst_Init(FALSE);
-
- do {
- for (cp = line;
- *cp && !isspace ((unsigned char)*cp) &&
- (*cp != '!') && (*cp != ':') && (*cp != '(');
- cp++)
- {
- if (*cp == '$') {
- /*
- * Must be a dynamic source (would have been expanded
- * otherwise), so call the Var module to parse the puppy
- * so we can safely advance beyond it...There should be
- * no errors in this, as they would have been discovered
- * in the initial Var_Subst and we wouldn't be here.
- */
- int length;
- Boolean freeIt;
- char *result;
-
- result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);
-
- if (freeIt) {
- free(result);
- }
- cp += length-1;
- }
- continue;
- }
- if (*cp == '(') {
- /*
- * Archives must be handled specially to make sure the OP_ARCHV
- * flag is set in their 'type' field, for one thing, and because
- * things like "archive(file1.o file2.o file3.o)" are permissible.
- * Arch_ParseArchive will set 'line' to be the first non-blank
- * after the archive-spec. It creates/finds nodes for the members
- * and places them on the given list, returning SUCCESS if all
- * went well and FAILURE if there was an error in the
- * specification. On error, line should remain untouched.
- */
- if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) {
- Parse_Error (PARSE_FATAL,
- "Error in archive specification: \"%s\"", line);
- return;
- } else {
- continue;
- }
- }
- savec = *cp;
-
- if (!*cp) {
- /*
- * Ending a dependency line without an operator is a Bozo
- * no-no. As a heuristic, this is also often triggered by
- * undetected conflicts from cvs/rcs merges.
- */
- if ((strncmp(line, "<<<<<<", 6) == 0) ||
- (strncmp(line, "======", 6) == 0) ||
- (strncmp(line, ">>>>>>", 6) == 0))
- Parse_Error (PARSE_FATAL,
- "Makefile appears to contain unresolved cvs/rcs/??? merge conflicts");
- else
- Parse_Error (PARSE_FATAL, "Need an operator");
- return;
- }
- *cp = '\0';
- /*
- * Have a word in line. See if it's a special target and set
- * specType to match it.
- */
- if (*line == '.' && isupper ((unsigned char)line[1])) {
- /*
- * See if the target is a special target that must have it
- * or its sources handled specially.
- */
- int keywd = ParseFindKeyword(line);
- if (keywd != -1) {
- if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {
- Parse_Error(PARSE_FATAL, "Mismatched special targets");
- return;
- }
-
- specType = parseKeywords[keywd].spec;
- tOp = parseKeywords[keywd].op;
-
- /*
- * Certain special targets have special semantics:
- * .PATH Have to set the dirSearchPath
- * variable too
- * .MAIN Its sources are only used if
- * nothing has been specified to
- * create.
- * .DEFAULT Need to create a node to hang
- * commands on, but we don't want
- * it in the graph, nor do we want
- * it to be the Main Target, so we
- * create it, set OP_NOTMAIN and
- * add it to the list, setting
- * DEFAULT to the new node for
- * later use. We claim the node is
- * A transformation rule to make
- * life easier later, when we'll
- * use Make_HandleUse to actually
- * apply the .DEFAULT commands.
- * .PHONY The list of targets
- * .NOPATH Don't search for file in the path
- * .BEGIN
- * .END
- * .INTERRUPT Are not to be considered the
- * main target.
- * .NOTPARALLEL Make only one target at a time.
- * .SINGLESHELL Create a shell for each command.
- * .ORDER Must set initial predecessor to NIL
- */
- switch (specType) {
- case ExPath:
- if (paths == NULL) {
- paths = Lst_Init(FALSE);
- }
- (void)Lst_AtEnd(paths, (ClientData)dirSearchPath);
- break;
- case Main:
- if (!Lst_IsEmpty(create)) {
- specType = Not;
- }
- break;
- case Begin:
- case End:
- case Interrupt:
- gn = Targ_FindNode(line, TARG_CREATE);
- gn->type |= OP_NOTMAIN;
- (void)Lst_AtEnd(targets, (ClientData)gn);
- break;
- case Default:
- gn = Targ_NewGN(".DEFAULT");
- gn->type |= (OP_NOTMAIN|OP_TRANSFORM);
- (void)Lst_AtEnd(targets, (ClientData)gn);
- DEFAULT = gn;
- break;
- case NotParallel:
- {
- maxJobs = 1;
- break;
- }
- case SingleShell:
- compatMake = TRUE;
- break;
- case Order:
- predecessor = NILGNODE;
- break;
- default:
- break;
- }
- } else if (strncmp (line, ".PATH", 5) == 0) {
- /*
- * .PATH<suffix> has to be handled specially.
- * Call on the suffix module to give us a path to
- * modify.
- */
- Lst path;
-
- specType = ExPath;
- path = Suff_GetPath (&line[5]);
- if (path == NILLST) {
- Parse_Error (PARSE_FATAL,
- "Suffix '%s' not defined (yet)",
- &line[5]);
- return;
- } else {
- if (paths == (Lst)NULL) {
- paths = Lst_Init(FALSE);
- }
- (void)Lst_AtEnd(paths, (ClientData)path);
- }
- }
- }
-
- /*
- * Have word in line. Get or create its node and stick it at
- * the end of the targets list
- */
- if ((specType == Not) && (*line != '\0')) {
- if (Dir_HasWildcards(line)) {
- /*
- * Targets are to be sought only in the current directory,
- * so create an empty path for the thing. Note we need to
- * use Dir_Destroy in the destruction of the path as the
- * Dir module could have added a directory to the path...
- */
- Lst emptyPath = Lst_Init(FALSE);
-
- Dir_Expand(line, emptyPath, curTargs);
-
- Lst_Destroy(emptyPath, Dir_Destroy);
- } else {
- /*
- * No wildcards, but we want to avoid code duplication,
- * so create a list with the word on it.
- */
- (void)Lst_AtEnd(curTargs, (ClientData)line);
- }
-
- while(!Lst_IsEmpty(curTargs)) {
- char *targName = (char *)Lst_DeQueue(curTargs);
-
- if (!Suff_IsTransform (targName)) {
- gn = Targ_FindNode (targName, TARG_CREATE);
- } else {
- gn = Suff_AddTransform (targName);
- }
-
- (void)Lst_AtEnd (targets, (ClientData)gn);
- }
- } else if (specType == ExPath && *line != '.' && *line != '\0') {
- Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
- }
-
- *cp = savec;
- /*
- * If it is a special type and not .PATH, it's the only target we
- * allow on this line...
- */
- if (specType != Not && specType != ExPath) {
- Boolean warn = FALSE;
-
- while ((*cp != '!') && (*cp != ':') && *cp) {
- if (*cp != ' ' && *cp != '\t') {
- warn = TRUE;
- }
- cp++;
- }
- if (warn) {
- Parse_Error(PARSE_WARNING, "Extra target ignored");
- }
- } else {
- while (*cp && isspace ((unsigned char)*cp)) {
- cp++;
- }
- }
- line = cp;
- } while ((*line != '!') && (*line != ':') && *line);
-
- /*
- * Don't need the list of target names anymore...
- */
- Lst_Destroy(curTargs, NOFREE);
-
- if (!Lst_IsEmpty(targets)) {
- switch(specType) {
- default:
- Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");
- break;
- case Default:
- case Begin:
- case End:
- case Interrupt:
- /*
- * These four create nodes on which to hang commands, so
- * targets shouldn't be empty...
- */
- case Not:
- /*
- * Nothing special here -- targets can be empty if it wants.
- */
- break;
- }
- }
-
- /*
- * Have now parsed all the target names. Must parse the operator next. The
- * result is left in op .
- */
- if (*cp == '!') {
- op = OP_FORCE;
- } else if (*cp == ':') {
- if (cp[1] == ':') {
- op = OP_DOUBLEDEP;
- cp++;
- } else {
- op = OP_DEPENDS;
- }
- } else {
- Parse_Error (PARSE_FATAL, "Missing dependency operator");
- return;
- }
-
- cp++; /* Advance beyond operator */
-
- Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
-
- /*
- * Get to the first source
- */
- while (*cp && isspace ((unsigned char)*cp)) {
- cp++;
- }
- line = cp;
-
- /*
- * Several special targets take different actions if present with no
- * sources:
- * a .SUFFIXES line with no sources clears out all old suffixes
- * a .PRECIOUS line makes all targets precious
- * a .IGNORE line ignores errors for all targets
- * a .SILENT line creates silence when making all targets
- * a .PATH removes all directories from the search path(s).
- */
- if (!*line) {
- switch (specType) {
- case Suffixes:
- Suff_ClearSuffixes ();
- break;
- case Precious:
- allPrecious = TRUE;
- break;
- case Ignore:
- ignoreErrors = TRUE;
- break;
- case Silent:
- beSilent = TRUE;
- break;
- case ExPath:
- Lst_ForEach(paths, ParseClearPath, (ClientData)NULL);
- break;
-#ifdef POSIX
- case Posix:
- Var_Set("%POSIX", "1003.2", VAR_GLOBAL, 0);
- break;
-#endif
- default:
- break;
- }
- } else if (specType == MFlags) {
- /*
- * Call on functions in main.c to deal with these arguments and
- * set the initial character to a null-character so the loop to
- * get sources won't get anything
- */
- Main_ParseArgLine (line);
- *line = '\0';
- } else if (specType == ExShell) {
- if (Job_ParseShell (line) != SUCCESS) {
- Parse_Error (PARSE_FATAL, "improper shell specification");
- return;
- }
- *line = '\0';
- } else if ((specType == NotParallel) || (specType == SingleShell)) {
- *line = '\0';
- }
-
- /*
- * NOW GO FOR THE SOURCES
- */
- if ((specType == Suffixes) || (specType == ExPath) ||
- (specType == Includes) || (specType == Libs) ||
- (specType == Null))
- {
- while (*line) {
- /*
- * If the target was one that doesn't take files as its sources
- * but takes something like suffixes, we take each
- * space-separated word on the line as a something and deal
- * with it accordingly.
- *
- * If the target was .SUFFIXES, we take each source as a
- * suffix and add it to the list of suffixes maintained by the
- * Suff module.
- *
- * If the target was a .PATH, we add the source as a directory
- * to search on the search path.
- *
- * If it was .INCLUDES, the source is taken to be the suffix of
- * files which will be #included and whose search path should
- * be present in the .INCLUDES variable.
- *
- * If it was .LIBS, the source is taken to be the suffix of
- * files which are considered libraries and whose search path
- * should be present in the .LIBS variable.
- *
- * If it was .NULL, the source is the suffix to use when a file
- * has no valid suffix.
- */
- char savec;
- while (*cp && !isspace ((unsigned char)*cp)) {
- cp++;
- }
- savec = *cp;
- *cp = '\0';
- switch (specType) {
- case Suffixes:
- Suff_AddSuffix (line, &mainNode);
- break;
- case ExPath:
- Lst_ForEach(paths, ParseAddDir, (ClientData)line);
- break;
- case Includes:
- Suff_AddInclude (line);
- break;
- case Libs:
- Suff_AddLib (line);
- break;
- case Null:
- Suff_SetNull (line);
- break;
- default:
- break;
- }
- *cp = savec;
- if (savec != '\0') {
- cp++;
- }
- while (*cp && isspace ((unsigned char)*cp)) {
- cp++;
- }
- line = cp;
- }
- if (paths) {
- Lst_Destroy(paths, NOFREE);
- }
- } else {
- while (*line) {
- /*
- * The targets take real sources, so we must beware of archive
- * specifications (i.e. things with left parentheses in them)
- * and handle them accordingly.
- */
- while (*cp && !isspace ((unsigned char)*cp)) {
- if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) {
- /*
- * Only stop for a left parenthesis if it isn't at the
- * start of a word (that'll be for variable changes
- * later) and isn't preceded by a dollar sign (a dynamic
- * source).
- */
- break;
- } else {
- cp++;
- }
- }
-
- if (*cp == '(') {
- GNode *gn;
-
- sources = Lst_Init (FALSE);
- if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) {
- Parse_Error (PARSE_FATAL,
- "Error in source archive spec \"%s\"", line);
- return;
- }
-
- while (!Lst_IsEmpty (sources)) {
- gn = (GNode *) Lst_DeQueue (sources);
- ParseDoSrc (tOp, gn->name, curSrcs);
- }
- Lst_Destroy (sources, NOFREE);
- cp = line;
- } else {
- if (*cp) {
- *cp = '\0';
- cp += 1;
- }
-
- ParseDoSrc (tOp, line, curSrcs);
- }
- while (*cp && isspace ((unsigned char)*cp)) {
- cp++;
- }
- line = cp;
- }
- }
-
- if (mainNode == NILGNODE) {
- /*
- * If we have yet to decide on a main target to make, in the
- * absence of any user input, we want the first target on
- * the first dependency line that is actually a real target
- * (i.e. isn't a .USE or .EXEC rule) to be made.
- */
- Lst_ForEach (targets, ParseFindMain, (ClientData)0);
- }
-
- /*
- * Finally, destroy the list of sources
- */
- Lst_Destroy(curSrcs, NOFREE);
-}
-
-/*-
- *---------------------------------------------------------------------
- * Parse_IsVar --
- * Return TRUE if the passed line is a variable assignment. A variable
- * assignment consists of a single word followed by optional whitespace
- * followed by either a += or an = operator.
- * This function is used both by the Parse_File function and main when
- * parsing the command-line arguments.
- *
- * Results:
- * TRUE if it is. FALSE if it ain't
- *
- * Side Effects:
- * none
- *---------------------------------------------------------------------
- */
-Boolean
-Parse_IsVar (line)
- register char *line; /* the line to check */
-{
- register Boolean wasSpace = FALSE; /* set TRUE if found a space */
- register Boolean haveName = FALSE; /* Set TRUE if have a variable name */
- int level = 0;
-#define ISEQOPERATOR(c) \
- (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!'))
-
- /*
- * Skip to variable name
- */
- for (;(*line == ' ') || (*line == '\t'); line++)
- continue;
-
- for (; *line != '=' || level != 0; line++)
- switch (*line) {
- case '\0':
- /*
- * end-of-line -- can't be a variable assignment.
- */
- return FALSE;
-
- case ' ':
- case '\t':
- /*
- * there can be as much white space as desired so long as there is
- * only one word before the operator
- */
- wasSpace = TRUE;
- break;
-
- case '(':
- case '{':
- level++;
- break;
-
- case '}':
- case ')':
- level--;
- break;
-
- default:
- if (wasSpace && haveName) {
- if (ISEQOPERATOR(*line)) {
- /*
- * We must have a finished word
- */
- if (level != 0)
- return FALSE;
-
- /*
- * When an = operator [+?!:] is found, the next
- * character must be an = or it ain't a valid
- * assignment.
- */
- if (line[1] == '=')
- return haveName;
-#ifdef SUNSHCMD
- /*
- * This is a shell command
- */
- if (strncmp(line, ":sh", 3) == 0)
- return haveName;
-#endif
- }
- /*
- * This is the start of another word, so not assignment.
- */
- return FALSE;
- }
- else {
- haveName = TRUE;
- wasSpace = FALSE;
- }
- break;
- }
-
- return haveName;
-}
-
-/*-
- *---------------------------------------------------------------------
- * Parse_DoVar --
- * Take the variable assignment in the passed line and do it in the
- * global context.
- *
- * Note: There is a lexical ambiguity with assignment modifier characters
- * in variable names. This routine interprets the character before the =
- * as a modifier. Therefore, an assignment like
- * C++=/usr/bin/CC
- * is interpreted as "C+ +=" instead of "C++ =".
- *
- * Results:
- * none
- *
- * Side Effects:
- * the variable structure of the given variable name is altered in the
- * global context.
- *---------------------------------------------------------------------
- */
-void
-Parse_DoVar (line, ctxt)
- char *line; /* a line guaranteed to be a variable
- * assignment. This reduces error checks */
- GNode *ctxt; /* Context in which to do the assignment */
-{
- char *cp; /* pointer into line */
- enum {
- VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL
- } type; /* Type of assignment */
- char *opc; /* ptr to operator character to
- * null-terminate the variable name */
- /*
- * Avoid clobbered variable warnings by forcing the compiler
- * to ``unregister'' variables
- */
-#if __GNUC__
- (void) &cp;
- (void) &line;
-#endif
-
- /*
- * Skip to variable name
- */
- while ((*line == ' ') || (*line == '\t')) {
- line++;
- }
-
- /*
- * Skip to operator character, nulling out whitespace as we go
- */
- for (cp = line + 1; *cp != '='; cp++) {
- if (isspace ((unsigned char)*cp)) {
- *cp = '\0';
- }
- }
- opc = cp-1; /* operator is the previous character */
- *cp++ = '\0'; /* nuke the = */
-
- /*
- * Check operator type
- */
- switch (*opc) {
- case '+':
- type = VAR_APPEND;
- *opc = '\0';
- break;
-
- case '?':
- /*
- * If the variable already has a value, we don't do anything.
- */
- *opc = '\0';
- if (Var_Exists(line, ctxt)) {
- return;
- } else {
- type = VAR_NORMAL;
- }
- break;
-
- case ':':
- type = VAR_SUBST;
- *opc = '\0';
- break;
-
- case '!':
- type = VAR_SHELL;
- *opc = '\0';
- break;
-
- default:
-#ifdef SUNSHCMD
- while (opc > line && *opc != ':')
- opc--;
-
- if (strncmp(opc, ":sh", 3) == 0) {
- type = VAR_SHELL;
- *opc = '\0';
- break;
- }
-#endif
- type = VAR_NORMAL;
- break;
- }
-
- while (isspace ((unsigned char)*cp)) {
- cp++;
- }
-
- if (type == VAR_APPEND) {
- Var_Append (line, cp, ctxt);
- } else if (type == VAR_SUBST) {
- /*
- * Allow variables in the old value to be undefined, but leave their
- * invocation alone -- this is done by forcing oldVars to be false.
- * XXX: This can cause recursive variables, but that's not hard to do,
- * and this allows someone to do something like
- *
- * CFLAGS = $(.INCLUDES)
- * CFLAGS := -I.. $(CFLAGS)
- *
- * And not get an error.
- */
- Boolean oldOldVars = oldVars;
-
- oldVars = FALSE;
-
- /*
- * make sure that we set the variable the first time to nothing
- * so that it gets substituted!
- */
- if (!Var_Exists(line, ctxt))
- Var_Set(line, "", ctxt, 0);
-
- cp = Var_Subst(NULL, cp, ctxt, FALSE);
- oldVars = oldOldVars;
-
- Var_Set(line, cp, ctxt, 0);
- free(cp);
- } else if (type == VAR_SHELL) {
- Boolean freeCmd = FALSE; /* TRUE if the command needs to be freed, i.e.
- * if any variable expansion was performed */
- char *res, *err;
-
- if (strchr(cp, '$') != NULL) {
- /*
- * There's a dollar sign in the command, so perform variable
- * expansion on the whole thing. The resulting string will need
- * freeing when we're done, so set freeCmd to TRUE.
- */
- cp = Var_Subst(NULL, cp, VAR_CMD, TRUE);
- freeCmd = TRUE;
- }
-
- res = Cmd_Exec(cp, &err);
- Var_Set(line, res, ctxt, 0);
- free(res);
-
- if (err)
- Parse_Error(PARSE_WARNING, err, cp);
-
- if (freeCmd)
- free(cp);
- } else {
- /*
- * Normal assignment -- just do it.
- */
- Var_Set(line, cp, ctxt, 0);
- }
- if (strcmp(line, MAKEOVERRIDES) == 0)
- ExportMAKEFLAGS(0); /* re-export MAKEFLAGS */
-}
-
-
-/*-
- * ParseAddCmd --
- * Lst_ForEach function to add a command line to all targets
- *
- * Results:
- * Always 0
- *
- * Side Effects:
- * A new element is added to the commands list of the node.
- */
-static int
-ParseAddCmd(gnp, cmd)
- ClientData gnp; /* the node to which the command is to be added */
- ClientData cmd; /* the command to add */
-{
- GNode *gn = (GNode *) gnp;
- /* if target already supplied, ignore commands */
- if ((gn->type & OP_DOUBLEDEP) && !Lst_IsEmpty (gn->cohorts))
- gn = (GNode *) Lst_Datum (Lst_Last (gn->cohorts));
- if (!(gn->type & OP_HAS_COMMANDS)) {
- (void)Lst_AtEnd(gn->commands, cmd);
- ParseMark(gn);
- } else {
-#ifdef notyet
- /* XXX: We cannot do this until we fix the tree */
- (void)Lst_AtEnd(gn->commands, cmd);
- Parse_Error (PARSE_WARNING,
- "overriding commands for target \"%s\"; "
- "previous commands defined at %s: %d ignored",
- gn->name, gn->fname, gn->lineno);
-#else
- Parse_Error (PARSE_WARNING,
- "duplicate script for target \"%s\" ignored",
- gn->name);
- ParseErrorInternal (gn->fname, gn->lineno, PARSE_WARNING,
- "using previous script for \"%s\" defined here",
- gn->name);
-#endif
- }
- return(0);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseHasCommands --
- * Callback procedure for Parse_File when destroying the list of
- * targets on the last dependency line. Marks a target as already
- * having commands if it does, to keep from having shell commands
- * on multiple dependency lines.
- *
- * Results:
- * None
- *
- * Side Effects:
- * OP_HAS_COMMANDS may be set for the target.
- *
- *-----------------------------------------------------------------------
- */
-static void
-ParseHasCommands(gnp)
- ClientData gnp; /* Node to examine */
-{
- GNode *gn = (GNode *) gnp;
- if (!Lst_IsEmpty(gn->commands)) {
- gn->type |= OP_HAS_COMMANDS;
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * Parse_AddIncludeDir --
- * Add a directory to the path searched for included makefiles
- * bracketed by double-quotes. Used by functions in main.c
- *
- * Results:
- * None.
- *
- * Side Effects:
- * The directory is appended to the list.
- *
- *-----------------------------------------------------------------------
- */
-void
-Parse_AddIncludeDir (dir)
- char *dir; /* The name of the directory to add */
-{
- (void) Dir_AddDir (parseIncPath, dir);
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseDoInclude --
- * Push to another file.
- *
- * The input is the line minus the `.'. A file spec is a string
- * enclosed in <> or "". The former is looked for only in sysIncPath.
- * The latter in . and the directories specified by -I command line
- * options
- *
- * Results:
- * None
- *
- * Side Effects:
- * A structure is added to the includes Lst and readProc, lineno,
- * fname and curFILE are altered for the new file
- *---------------------------------------------------------------------
- */
-static void
-ParseDoInclude (line)
- char *line;
-{
- char *fullname; /* full pathname of file */
- IFile *oldFile; /* state associated with current file */
- char endc; /* the character which ends the file spec */
- char *cp; /* current position in file spec */
- Boolean isSystem; /* TRUE if makefile is a system makefile */
- int silent = (*line != 'i') ? 1 : 0;
- char *file = &line[7 + silent];
-
- /*
- * Skip to delimiter character so we know where to look
- */
- while ((*file == ' ') || (*file == '\t')) {
- file++;
- }
-
- if ((*file != '"') && (*file != '<')) {
- Parse_Error (PARSE_FATAL,
- ".include filename must be delimited by '\"' or '<'");
- return;
- }
-
- /*
- * Set the search path on which to find the include file based on the
- * characters which bracket its name. Angle-brackets imply it's
- * a system Makefile while double-quotes imply it's a user makefile
- */
- if (*file == '<') {
- isSystem = TRUE;
- endc = '>';
- } else {
- isSystem = FALSE;
- endc = '"';
- }
-
- /*
- * Skip to matching delimiter
- */
- for (cp = ++file; *cp && *cp != endc; cp++) {
- continue;
- }
-
- if (*cp != endc) {
- Parse_Error (PARSE_FATAL,
- "Unclosed %cinclude filename. '%c' expected",
- '.', endc);
- return;
- }
- *cp = '\0';
-
- /*
- * Substitute for any variables in the file name before trying to
- * find the thing.
- */
- file = Var_Subst (NULL, file, VAR_CMD, FALSE);
-
- /*
- * Now we know the file's name and its search path, we attempt to
- * find the durn thing. A return of NULL indicates the file don't
- * exist.
- */
- if (!isSystem) {
- /*
- * Include files contained in double-quotes are first searched for
- * relative to the including file's location. We don't want to
- * cd there, of course, so we just tack on the old file's
- * leading path components and call Dir_FindFile to see if
- * we can locate the beast.
- */
- char *prefEnd, *Fname;
-
- /* Make a temporary copy of this, to be safe. */
- Fname = estrdup(fname);
-
- prefEnd = strrchr (Fname, '/');
- if (prefEnd != (char *)NULL) {
- char *newName;
-
- *prefEnd = '\0';
- if (file[0] == '/')
- newName = estrdup(file);
- else
- newName = str_concat (Fname, file, STR_ADDSLASH);
- fullname = Dir_FindFile (newName, parseIncPath);
- if (fullname == (char *)NULL) {
- fullname = Dir_FindFile(newName, dirSearchPath);
- }
- free (newName);
- *prefEnd = '/';
- } else {
- fullname = (char *)NULL;
- }
- free (Fname);
- } else {
- fullname = (char *)NULL;
- }
-
- if (fullname == (char *)NULL) {
- /*
- * System makefile or makefile wasn't found in same directory as
- * included makefile. Search for it first on the -I search path,
- * then on the .PATH search path, if not found in a -I directory.
- * XXX: Suffix specific?
- */
- fullname = Dir_FindFile (file, parseIncPath);
- if (fullname == (char *)NULL) {
- fullname = Dir_FindFile(file, dirSearchPath);
- }
- }
-
- if (fullname == (char *)NULL) {
- /*
- * Still haven't found the makefile. Look for it on the system
- * path as a last resort.
- */
- fullname = Dir_FindFile(file, sysIncPath);
- }
-
- if (fullname == (char *) NULL) {
- *cp = endc;
- if (!silent)
- Parse_Error (PARSE_FATAL, "Could not find %s", file);
- return;
- }
-
- free(file);
-
- /*
- * Once we find the absolute path to the file, we get to save all the
- * state from the current file before we can start reading this
- * include file. The state is stored in an IFile structure which
- * is placed on a list with other IFile structures. The list makes
- * a very nice stack to track how we got here...
- */
- oldFile = (IFile *) emalloc (sizeof (IFile));
- oldFile->fname = fname;
-
- oldFile->F = curFILE;
- oldFile->p = curPTR;
- oldFile->lineno = lineno;
-
- (void) Lst_AtFront (includes, (ClientData)oldFile);
-
- /*
- * Once the previous state has been saved, we can get down to reading
- * the new file. We set up the name of the file to be the absolute
- * name of the include file so error messages refer to the right
- * place. Naturally enough, we start reading at line number 0.
- */
- fname = fullname;
- lineno = 0;
-
- ParseSetParseFile(fname);
-
- curFILE = fopen (fullname, "r");
- curPTR = NULL;
- if (curFILE == (FILE * ) NULL) {
- if (!silent)
- Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
- /*
- * Pop to previous file
- */
- (void) ParseEOF(0);
- }
-}
-
-
-/*-
- *---------------------------------------------------------------------
- * ParseSetParseFile --
- * Set the .PARSEDIR and .PARSEFILE variables to the dirname and
- * basename of the given filename
- *
- * Results:
- * None
- *
- * Side Effects:
- * The .PARSEDIR and .PARSEFILE variables are overwritten by the
- * dirname and basename of the given filename.
- *---------------------------------------------------------------------
- */
-static void
-ParseSetParseFile(fname)
- char *fname;
-{
- char *slash;
-
- slash = strrchr(fname, '/');
- if (slash == 0) {
- Var_Set(".PARSEDIR", ".", VAR_GLOBAL, 0);
- Var_Set(".PARSEFILE", fname, VAR_GLOBAL, 0);
- } else {
- *slash = '\0';
- Var_Set(".PARSEDIR", fname, VAR_GLOBAL, 0);
- Var_Set(".PARSEFILE", slash+1, VAR_GLOBAL, 0);
- *slash = '/';
- }
-}
-
-
-/*-
- *---------------------------------------------------------------------
- * Parse_FromString --
- * Start Parsing from the given string
- *
- * Results:
- * None
- *
- * Side Effects:
- * A structure is added to the includes Lst and readProc, lineno,
- * fname and curFILE are altered for the new file
- *---------------------------------------------------------------------
- */
-void
-Parse_FromString(str)
- char *str;
-{
- IFile *oldFile; /* state associated with this file */
-
- if (DEBUG(FOR))
- (void) fprintf(stderr, "%s\n----\n", str);
-
- oldFile = (IFile *) emalloc (sizeof (IFile));
- oldFile->lineno = lineno;
- oldFile->fname = fname;
- oldFile->F = curFILE;
- oldFile->p = curPTR;
-
- (void) Lst_AtFront (includes, (ClientData)oldFile);
-
- curFILE = NULL;
- curPTR = (PTR *) emalloc (sizeof (PTR));
- curPTR->str = curPTR->ptr = str;
- lineno = 0;
- fname = estrdup(fname);
-}
-
-
-#ifdef SYSVINCLUDE
-/*-
- *---------------------------------------------------------------------
- * ParseTraditionalInclude --
- * Push to another file.
- *
- * The input is the current line. The file name(s) are
- * following the "include".
- *
- * Results:
- * None
- *
- * Side Effects:
- * A structure is added to the includes Lst and readProc, lineno,
- * fname and curFILE are altered for the new file
- *---------------------------------------------------------------------
- */
-static void
-ParseTraditionalInclude (line)
- char *line;
-{
- char *fullname; /* full pathname of file */
- IFile *oldFile; /* state associated with current file */
- char *cp; /* current position in file spec */
- char *prefEnd;
- int done = 0;
- int silent = (line[0] != 'i') ? 1 : 0;
- char *file = &line[silent + 7];
- char *cfname = fname;
- size_t clineno = lineno;
-
-
- /*
- * Skip over whitespace
- */
- while (isspace((unsigned char)*file))
- file++;
-
- if (*file == '\0') {
- Parse_Error (PARSE_FATAL,
- "Filename missing from \"include\"");
- return;
- }
-
- for (; !done; file = cp + 1) {
- /*
- * Skip to end of line or next whitespace
- */
- for (cp = file; *cp && !isspace((unsigned char) *cp); cp++)
- continue;
-
- if (*cp)
- *cp = '\0';
- else
- done = 1;
-
- /*
- * Substitute for any variables in the file name before trying to
- * find the thing.
- */
- file = Var_Subst(NULL, file, VAR_CMD, FALSE);
-
- /*
- * Now we know the file's name, we attempt to find the durn thing.
- * A return of NULL indicates the file don't exist.
- *
- * Include files are first searched for relative to the including
- * file's location. We don't want to cd there, of course, so we
- * just tack on the old file's leading path components and call
- * Dir_FindFile to see if we can locate the beast.
- * XXX - this *does* search in the current directory, right?
- */
-
- prefEnd = strrchr(cfname, '/');
- if (prefEnd != NULL) {
- char *newName;
-
- *prefEnd = '\0';
- newName = str_concat(cfname, file, STR_ADDSLASH);
- fullname = Dir_FindFile(newName, parseIncPath);
- if (fullname == NULL) {
- fullname = Dir_FindFile(newName, dirSearchPath);
- }
- free (newName);
- *prefEnd = '/';
- } else {
- fullname = NULL;
- }
-
- if (fullname == NULL) {
- /*
- * System makefile or makefile wasn't found in same directory as
- * included makefile. Search for it first on the -I search path,
- * then on the .PATH search path, if not found in a
- * -I directory. XXX: Suffix specific?
- */
- fullname = Dir_FindFile(file, parseIncPath);
- if (fullname == NULL) {
- fullname = Dir_FindFile(file, dirSearchPath);
- }
- }
-
- if (fullname == NULL) {
- /*
- * Still haven't found the makefile. Look for it on the system
- * path as a last resort.
- */
- fullname = Dir_FindFile(file, sysIncPath);
- }
-
- if (fullname == NULL) {
- if (!silent)
- ParseErrorInternal(cfname, clineno, PARSE_FATAL,
- "Could not find %s", file);
- free(file);
- continue;
- }
-
- free(file);
-
- /*
- * Once we find the absolute path to the file, we get to save all
- * the state from the current file before we can start reading this
- * include file. The state is stored in an IFile structure which
- * is placed on a list with other IFile structures. The list makes
- * a very nice stack to track how we got here...
- */
- oldFile = (IFile *) emalloc(sizeof(IFile));
- oldFile->fname = fname;
-
- oldFile->F = curFILE;
- oldFile->p = curPTR;
- oldFile->lineno = lineno;
-
- (void) Lst_AtFront(includes, (ClientData)oldFile);
-
- /*
- * Once the previous state has been saved, we can get down to
- * reading the new file. We set up the name of the file to be the
- * absolute name of the include file so error messages refer to the
- * right place. Naturally enough, we start reading at line number 0.
- */
- fname = fullname;
- lineno = 0;
-
- curFILE = fopen(fullname, "r");
- curPTR = NULL;
- if (curFILE == NULL) {
- if (!silent)
- ParseErrorInternal(cfname, clineno, PARSE_FATAL,
- "Cannot open %s", fullname);
- /*
- * Pop to previous file
- */
- (void) ParseEOF(1);
- }
- }
-}
-#endif
-
-/*-
- *---------------------------------------------------------------------
- * ParseEOF --
- * Called when EOF is reached in the current file. If we were reading
- * an include file, the includes stack is popped and things set up
- * to go back to reading the previous file at the previous location.
- *
- * Results:
- * CONTINUE if there's more to do. DONE if not.
- *
- * Side Effects:
- * The old curFILE, is closed. The includes list is shortened.
- * lineno, curFILE, and fname are changed if CONTINUE is returned.
- *---------------------------------------------------------------------
- */
-static int
-ParseEOF (opened)
- int opened;
-{
- IFile *ifile; /* the state on the top of the includes stack */
-
- if (Lst_IsEmpty (includes)) {
- Var_Delete(".PARSEDIR", VAR_GLOBAL);
- Var_Delete(".PARSEFILE", VAR_GLOBAL);
- return (DONE);
- }
-
- ifile = (IFile *) Lst_DeQueue (includes);
- free ((Address) fname);
- fname = ifile->fname;
- lineno = ifile->lineno;
- if (opened && curFILE)
- (void) fclose (curFILE);
- if (curPTR) {
- free((Address) curPTR->str);
- free((Address) curPTR);
- }
- curFILE = ifile->F;
- curPTR = ifile->p;
- free ((Address)ifile);
-
- /* pop the PARSEDIR/PARSEFILE variables */
- ParseSetParseFile(fname);
- return (CONTINUE);
-}
-
-/*-
- *---------------------------------------------------------------------
- * ParseReadc --
- * Read a character from the current file
- *
- * Results:
- * The character that was read
- *
- * Side Effects:
- *---------------------------------------------------------------------
- */
-static __inline int
-ParseReadc()
-{
- if (curFILE)
- return fgetc(curFILE);
-
- if (curPTR && *curPTR->ptr)
- return *curPTR->ptr++;
- return EOF;
-}
-
-
-/*-
- *---------------------------------------------------------------------
- * ParseUnreadc --
- * Put back a character to the current file
- *
- * Results:
- * None.
- *
- * Side Effects:
- *---------------------------------------------------------------------
- */
-static void
-ParseUnreadc(c)
- int c;
-{
- if (curFILE) {
- ungetc(c, curFILE);
- return;
- }
- if (curPTR) {
- *--(curPTR->ptr) = c;
- return;
- }
-}
-
-
-/* ParseSkipLine():
- * Grab the next line
- */
-static char *
-ParseSkipLine(skip)
- int skip; /* Skip lines that don't start with . */
-{
- char *line;
- int c, lastc, lineLength = 0;
- Buffer buf;
-
- buf = Buf_Init(MAKE_BSIZE);
-
- do {
- Buf_Discard(buf, lineLength);
- lastc = '\0';
-
- while (((c = ParseReadc()) != '\n' || lastc == '\\')
- && c != EOF) {
- if (c == '\n') {
- Buf_ReplaceLastByte(buf, (Byte)' ');
- lineno++;
-
- while ((c = ParseReadc()) == ' ' || c == '\t');
-
- if (c == EOF)
- break;
- }
-
- Buf_AddByte(buf, (Byte)c);
- lastc = c;
- }
-
- if (c == EOF) {
- Parse_Error(PARSE_FATAL, "Unclosed conditional/for loop");
- Buf_Destroy(buf, TRUE);
- return((char *)NULL);
- }
-
- lineno++;
- Buf_AddByte(buf, (Byte)'\0');
- line = (char *)Buf_GetAll(buf, &lineLength);
- } while (skip == 1 && line[0] != '.');
-
- Buf_Destroy(buf, FALSE);
- return line;
-}
-
-
-/*-
- *---------------------------------------------------------------------
- * ParseReadLine --
- * Read an entire line from the input file. Called only by Parse_File.
- * To facilitate escaped newlines and what have you, a character is
- * buffered in 'lastc', which is '\0' when no characters have been
- * read. When we break out of the loop, c holds the terminating
- * character and lastc holds a character that should be added to
- * the line (unless we don't read anything but a terminator).
- *
- * Results:
- * A line w/o its newline
- *
- * Side Effects:
- * Only those associated with reading a character
- *---------------------------------------------------------------------
- */
-static char *
-ParseReadLine ()
-{
- Buffer buf; /* Buffer for current line */
- register int c; /* the current character */
- register int lastc; /* The most-recent character */
- Boolean semiNL; /* treat semi-colons as newlines */
- Boolean ignDepOp; /* TRUE if should ignore dependency operators
- * for the purposes of setting semiNL */
- Boolean ignComment; /* TRUE if should ignore comments (in a
- * shell command */
- char *line; /* Result */
- char *ep; /* to strip trailing blanks */
- int lineLength; /* Length of result */
-
- semiNL = FALSE;
- ignDepOp = FALSE;
- ignComment = FALSE;
-
- /*
- * Handle special-characters at the beginning of the line. Either a
- * leading tab (shell command) or pound-sign (possible conditional)
- * forces us to ignore comments and dependency operators and treat
- * semi-colons as semi-colons (by leaving semiNL FALSE). This also
- * discards completely blank lines.
- */
- for (;;) {
- c = ParseReadc();
-
- if (c == '\t') {
- ignComment = ignDepOp = TRUE;
- break;
- } else if (c == '\n') {
- lineno++;
- } else if (c == '#') {
- ParseUnreadc(c);
- break;
- } else {
- /*
- * Anything else breaks out without doing anything
- */
- break;
- }
- }
-
- if (c != EOF) {
- lastc = c;
- buf = Buf_Init(MAKE_BSIZE);
-
- while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) &&
- (c != EOF))
- {
-test_char:
- switch(c) {
- case '\n':
- /*
- * Escaped newline: read characters until a non-space or an
- * unescaped newline and replace them all by a single space.
- * This is done by storing the space over the backslash and
- * dropping through with the next nonspace. If it is a
- * semi-colon and semiNL is TRUE, it will be recognized as a
- * newline in the code below this...
- */
- lineno++;
- lastc = ' ';
- while ((c = ParseReadc ()) == ' ' || c == '\t') {
- continue;
- }
- if (c == EOF || c == '\n') {
- goto line_read;
- } else {
- /*
- * Check for comments, semiNL's, etc. -- easier than
- * ParseUnreadc(c); continue;
- */
- goto test_char;
- }
- /*NOTREACHED*/
- break;
-
- case ';':
- /*
- * Semi-colon: Need to see if it should be interpreted as a
- * newline
- */
- if (semiNL) {
- /*
- * To make sure the command that may be following this
- * semi-colon begins with a tab, we push one back into the
- * input stream. This will overwrite the semi-colon in the
- * buffer. If there is no command following, this does no
- * harm, since the newline remains in the buffer and the
- * whole line is ignored.
- */
- ParseUnreadc('\t');
- goto line_read;
- }
- break;
- case '=':
- if (!semiNL) {
- /*
- * Haven't seen a dependency operator before this, so this
- * must be a variable assignment -- don't pay attention to
- * dependency operators after this.
- */
- ignDepOp = TRUE;
- } else if (lastc == ':' || lastc == '!') {
- /*
- * Well, we've seen a dependency operator already, but it
- * was the previous character, so this is really just an
- * expanded variable assignment. Revert semi-colons to
- * being just semi-colons again and ignore any more
- * dependency operators.
- *
- * XXX: Note that a line like "foo : a:=b" will blow up,
- * but who'd write a line like that anyway?
- */
- ignDepOp = TRUE; semiNL = FALSE;
- }
- break;
- case '#':
- if (!ignComment) {
- if (
-#if 0
- compatMake &&
-#endif
- (lastc != '\\')) {
- /*
- * If the character is a hash mark and it isn't escaped
- * (or we're being compatible), the thing is a comment.
- * Skip to the end of the line.
- */
- do {
- c = ParseReadc();
- } while ((c != '\n') && (c != EOF));
- goto line_read;
- } else {
- /*
- * Don't add the backslash. Just let the # get copied
- * over.
- */
- lastc = c;
- continue;
- }
- }
- break;
- case ':':
- case '!':
- if (!ignDepOp && (c == ':' || c == '!')) {
- /*
- * A semi-colon is recognized as a newline only on
- * dependency lines. Dependency lines are lines with a
- * colon or an exclamation point. Ergo...
- */
- semiNL = TRUE;
- }
- break;
- }
- /*
- * Copy in the previous character and save this one in lastc.
- */
- Buf_AddByte (buf, (Byte)lastc);
- lastc = c;
-
- }
- line_read:
- lineno++;
-
- if (lastc != '\0') {
- Buf_AddByte (buf, (Byte)lastc);
- }
- Buf_AddByte (buf, (Byte)'\0');
- line = (char *)Buf_GetAll (buf, &lineLength);
- Buf_Destroy (buf, FALSE);
-
- /*
- * Strip trailing blanks and tabs from the line.
- * Do not strip a blank or tab that is preceded by
- * a '\'
- */
- ep = line;
- while (*ep)
- ++ep;
- while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) {
- if (ep > line + 1 && ep[-2] == '\\')
- break;
- --ep;
- }
- *ep = 0;
-
- if (line[0] == '.') {
- /*
- * The line might be a conditional. Ask the conditional module
- * about it and act accordingly
- */
- switch (Cond_Eval (line)) {
- case COND_SKIP:
- /*
- * Skip to next conditional that evaluates to COND_PARSE.
- */
- do {
- free (line);
- line = ParseSkipLine(1);
- } while (line && Cond_Eval(line) != COND_PARSE);
- if (line == NULL)
- break;
- /*FALLTHRU*/
- case COND_PARSE:
- free ((Address) line);
- line = ParseReadLine();
- break;
- case COND_INVALID:
- if (For_Eval(line)) {
- int ok;
- free(line);
- do {
- /*
- * Skip after the matching end
- */
- line = ParseSkipLine(0);
- if (line == NULL) {
- Parse_Error (PARSE_FATAL,
- "Unexpected end of file in for loop.\n");
- break;
- }
- ok = For_Eval(line);
- free(line);
- }
- while (ok);
- if (line != NULL)
- For_Run();
- line = ParseReadLine();
- }
- break;
- }
- }
- return (line);
-
- } else {
- /*
- * Hit end-of-file, so return a NULL line to indicate this.
- */
- return((char *)NULL);
- }
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseFinishLine --
- * Handle the end of a dependency group.
- *
- * Results:
- * Nothing.
- *
- * Side Effects:
- * inLine set FALSE. 'targets' list destroyed.
- *
- *-----------------------------------------------------------------------
- */
-static void
-ParseFinishLine()
-{
- if (inLine) {
- Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL);
- Lst_Destroy (targets, ParseHasCommands);
- targets = NULL;
- inLine = FALSE;
- }
-}
-
-
-/*-
- *---------------------------------------------------------------------
- * Parse_File --
- * Parse a file into its component parts, incorporating it into the
- * current dependency graph. This is the main function and controls
- * almost every other function in this module
- *
- * Results:
- * None
- *
- * Side Effects:
- * Loads. Nodes are added to the list of all targets, nodes and links
- * are added to the dependency graph. etc. etc. etc.
- *---------------------------------------------------------------------
- */
-void
-Parse_File(name, stream)
- char *name; /* the name of the file being read */
- FILE * stream; /* Stream open to makefile to parse */
-{
- register char *cp, /* pointer into the line */
- *line; /* the line we're working on */
-
- inLine = FALSE;
- fname = name;
- curFILE = stream;
- lineno = 0;
- fatals = 0;
-
- ParseSetParseFile(fname);
-
- do {
- while ((line = ParseReadLine ()) != NULL) {
- if (*line == '.') {
- /*
- * Lines that begin with the special character are either
- * include or undef directives.
- */
- for (cp = line + 1; isspace ((unsigned char)*cp); cp++) {
- continue;
- }
- if (strncmp(cp, "include", 7) == 0 ||
- ((cp[0] == 's' || cp[0] == '-') &&
- strncmp(&cp[1], "include", 7) == 0)) {
- ParseDoInclude (cp);
- goto nextLine;
- } else if (strncmp(cp, "undef", 5) == 0) {
- char *cp2;
- for (cp += 5; isspace((unsigned char) *cp); cp++) {
- continue;
- }
-
- for (cp2 = cp; !isspace((unsigned char) *cp2) &&
- (*cp2 != '\0'); cp2++) {
- continue;
- }
-
- *cp2 = '\0';
-
- Var_Delete(cp, VAR_GLOBAL);
- goto nextLine;
- }
- }
- if (*line == '#') {
- /* If we're this far, the line must be a comment. */
- goto nextLine;
- }
-
- if (*line == '\t') {
- /*
- * If a line starts with a tab, it can only hope to be
- * a creation command.
- */
-#ifndef POSIX
- shellCommand:
-#endif
- for (cp = line + 1; isspace ((unsigned char)*cp); cp++) {
- continue;
- }
- if (*cp) {
- if (inLine) {
- /*
- * So long as it's not a blank line and we're actually
- * in a dependency spec, add the command to the list of
- * commands of all targets in the dependency spec
- */
- Lst_ForEach (targets, ParseAddCmd, cp);
-#ifdef CLEANUP
- Lst_AtEnd(targCmds, (ClientData) line);
-#endif
- continue;
- } else {
- Parse_Error (PARSE_FATAL,
- "Unassociated shell command \"%s\"",
- cp);
- }
- }
-#ifdef SYSVINCLUDE
- } else if (((strncmp(line, "include", 7) == 0 &&
- isspace((unsigned char) line[7])) ||
- ((line[0] == 's' || line[0] == '-') &&
- strncmp(&line[1], "include", 7) == 0 &&
- isspace((unsigned char) line[8]))) &&
- strchr(line, ':') == NULL) {
- /*
- * It's an S3/S5-style "include".
- */
- ParseTraditionalInclude (line);
- goto nextLine;
-#endif
- } else if (Parse_IsVar (line)) {
- ParseFinishLine();
- Parse_DoVar (line, VAR_GLOBAL);
- } else {
- /*
- * We now know it's a dependency line so it needs to have all
- * variables expanded before being parsed. Tell the variable
- * module to complain if some variable is undefined...
- * To make life easier on novices, if the line is indented we
- * first make sure the line has a dependency operator in it.
- * If it doesn't have an operator and we're in a dependency
- * line's script, we assume it's actually a shell command
- * and add it to the current list of targets.
- */
-#ifndef POSIX
- Boolean nonSpace = FALSE;
-#endif
-
- cp = line;
- if (isspace((unsigned char) line[0])) {
- while ((*cp != '\0') && isspace((unsigned char) *cp)) {
- cp++;
- }
- if (*cp == '\0') {
- goto nextLine;
- }
-#ifndef POSIX
- while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) {
- nonSpace = TRUE;
- cp++;
- }
-#endif
- }
-
-#ifndef POSIX
- if (*cp == '\0') {
- if (inLine) {
- Parse_Error (PARSE_WARNING,
- "Shell command needs a leading tab");
- goto shellCommand;
- } else if (nonSpace) {
- Parse_Error (PARSE_FATAL, "Missing operator");
- }
- } else {
-#endif
- ParseFinishLine();
-
- cp = Var_Subst (NULL, line, VAR_CMD, TRUE);
- free (line);
- line = cp;
-
- /*
- * Need a non-circular list for the target nodes
- */
- if (targets)
- Lst_Destroy(targets, NOFREE);
-
- targets = Lst_Init (FALSE);
- inLine = TRUE;
-
- ParseDoDependency (line);
-#ifndef POSIX
- }
-#endif
- }
-
- nextLine:
-
- free (line);
- }
- /*
- * Reached EOF, but it may be just EOF of an include file...
- */
- } while (ParseEOF(1) == CONTINUE);
-
- /*
- * Make sure conditionals are clean
- */
- Cond_End();
-
- if (fatals) {
- (void)fprintf(stderr,
- "%s: Fatal errors encountered -- cannot continue\n",
- progname);
- PrintOnError(NULL);
- exit (1);
- }
-}
-
-/*-
- *---------------------------------------------------------------------
- * Parse_Init --
- * initialize the parsing module
- *
- * Results:
- * none
- *
- * Side Effects:
- * the parseIncPath list is initialized...
- *---------------------------------------------------------------------
- */
-void
-Parse_Init ()
-{
- mainNode = NILGNODE;
- parseIncPath = Lst_Init (FALSE);
- sysIncPath = Lst_Init (FALSE);
- includes = Lst_Init (FALSE);
-#ifdef CLEANUP
- targCmds = Lst_Init (FALSE);
-#endif
-}
-
-void
-Parse_End()
-{
-#ifdef CLEANUP
- Lst_Destroy(targCmds, (void (*) __P((ClientData))) free);
- if (targets)
- Lst_Destroy(targets, NOFREE);
- Lst_Destroy(sysIncPath, Dir_Destroy);
- Lst_Destroy(parseIncPath, Dir_Destroy);
- Lst_Destroy(includes, NOFREE); /* Should be empty now */
-#endif
-}
-
-
-/*-
- *-----------------------------------------------------------------------
- * Parse_MainName --
- * Return a Lst of the main target to create for main()'s sake. If
- * no such target exists, we Punt with an obnoxious error message.
- *
- * Results:
- * A Lst of the single node to create.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-Lst
-Parse_MainName()
-{
- Lst mainList; /* result list */
-
- mainList = Lst_Init (FALSE);
-
- if (mainNode == NILGNODE) {
- Punt ("no target to make.");
- /*NOTREACHED*/
- } else if (mainNode->type & OP_DOUBLEDEP) {
- (void) Lst_AtEnd (mainList, (ClientData)mainNode);
- Lst_Concat(mainList, mainNode->cohorts, LST_CONCNEW);
- }
- else
- (void) Lst_AtEnd (mainList, (ClientData)mainNode);
- return (mainList);
-}
-
-/*-
- *-----------------------------------------------------------------------
- * ParseMark --
- * Add the filename and lineno to the GNode so that we remember
- * where it was first defined.
- *
- * Side Effects:
- * None.
- *
- *-----------------------------------------------------------------------
- */
-static void
-ParseMark(gn)
- GNode *gn;
-{
- gn->fname = strdup(fname);
- gn->lineno = lineno;
-}