parse.c revision 93056
11590Srgrimes/*
21590Srgrimes * Copyright (c) 1988, 1989, 1990, 1993
31590Srgrimes *	The Regents of the University of California.  All rights reserved.
41590Srgrimes * Copyright (c) 1989 by Berkeley Softworks
51590Srgrimes * All rights reserved.
61590Srgrimes *
71590Srgrimes * This code is derived from software contributed to Berkeley by
81590Srgrimes * Adam de Boor.
91590Srgrimes *
101590Srgrimes * Redistribution and use in source and binary forms, with or without
111590Srgrimes * modification, are permitted provided that the following conditions
121590Srgrimes * are met:
131590Srgrimes * 1. Redistributions of source code must retain the above copyright
141590Srgrimes *    notice, this list of conditions and the following disclaimer.
151590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
161590Srgrimes *    notice, this list of conditions and the following disclaimer in the
171590Srgrimes *    documentation and/or other materials provided with the distribution.
181590Srgrimes * 3. All advertising materials mentioning features or use of this software
191590Srgrimes *    must display the following acknowledgement:
201590Srgrimes *	This product includes software developed by the University of
211590Srgrimes *	California, Berkeley and its contributors.
221590Srgrimes * 4. Neither the name of the University nor the names of its contributors
231590Srgrimes *    may be used to endorse or promote products derived from this software
241590Srgrimes *    without specific prior written permission.
251590Srgrimes *
261590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
271590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
281590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
291590Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
301590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
311590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
321590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
331590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
341590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
351590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
361590Srgrimes * SUCH DAMAGE.
3762833Swsanchez *
3862833Swsanchez * @(#)parse.c	8.3 (Berkeley) 3/19/94
391590Srgrimes */
401590Srgrimes
411590Srgrimes#ifndef lint
4262833Swsanchez#include <sys/cdefs.h>
4362833Swsanchez__RCSID("$FreeBSD: head/usr.bin/make/parse.c 93056 2002-03-23 23:30:30Z imp $");
441590Srgrimes#endif /* not lint */
451590Srgrimes
461590Srgrimes/*-
471590Srgrimes * parse.c --
481590Srgrimes *	Functions to parse a makefile.
491590Srgrimes *
501590Srgrimes *	One function, Parse_Init, must be called before any functions
511590Srgrimes *	in this module are used. After that, the function Parse_File is the
521590Srgrimes *	main entry point and controls most of the other functions in this
531590Srgrimes *	module.
541590Srgrimes *
551590Srgrimes *	Most important structures are kept in Lsts. Directories for
561590Srgrimes *	the #include "..." function are kept in the 'parseIncPath' Lst, while
571590Srgrimes *	those for the #include <...> are kept in the 'sysIncPath' Lst. The
581590Srgrimes *	targets currently being defined are kept in the 'targets' Lst.
591590Srgrimes *
601590Srgrimes *	The variables 'fname' and 'lineno' are used to track the name
611590Srgrimes *	of the current file and the line number in that file so that error
621590Srgrimes *	messages can be more meaningful.
631590Srgrimes *
641590Srgrimes * Interface:
651590Srgrimes *	Parse_Init	    	    Initialization function which must be
661590Srgrimes *	    	  	    	    called before anything else in this module
671590Srgrimes *	    	  	    	    is used.
681590Srgrimes *
695814Sjkh *	Parse_End		    Cleanup the module
705814Sjkh *
711590Srgrimes *	Parse_File	    	    Function used to parse a makefile. It must
721590Srgrimes *	    	  	    	    be given the name of the file, which should
731590Srgrimes *	    	  	    	    already have been opened, and a function
741590Srgrimes *	    	  	    	    to call to read a character from the file.
751590Srgrimes *
761590Srgrimes *	Parse_IsVar	    	    Returns TRUE if the given line is a
771590Srgrimes *	    	  	    	    variable assignment. Used by MainParseArgs
781590Srgrimes *	    	  	    	    to determine if an argument is a target
791590Srgrimes *	    	  	    	    or a variable assignment. Used internally
801590Srgrimes *	    	  	    	    for pretty much the same thing...
811590Srgrimes *
821590Srgrimes *	Parse_Error	    	    Function called when an error occurs in
831590Srgrimes *	    	  	    	    parsing. Used by the variable and
841590Srgrimes *	    	  	    	    conditional modules.
851590Srgrimes *	Parse_MainName	    	    Returns a Lst of the main target to create.
861590Srgrimes */
871590Srgrimes
881590Srgrimes#include <stdarg.h>
8927644Scharnier#include <ctype.h>
9027644Scharnier#include <err.h>
911590Srgrimes#include <stdio.h>
921590Srgrimes#include "make.h"
931590Srgrimes#include "hash.h"
941590Srgrimes#include "dir.h"
951590Srgrimes#include "job.h"
961590Srgrimes#include "buf.h"
971590Srgrimes#include "pathnames.h"
981590Srgrimes
991590Srgrimes/*
1001590Srgrimes * These values are returned by ParseEOF to tell Parse_File whether to
1011590Srgrimes * CONTINUE parsing, i.e. it had only reached the end of an include file,
1021590Srgrimes * or if it's DONE.
1031590Srgrimes */
1041590Srgrimes#define	CONTINUE	1
1051590Srgrimes#define	DONE		0
1061590Srgrimesstatic Lst     	    targets;	/* targets we're working on */
1075814Sjkhstatic Lst     	    targCmds;	/* command lines for targets */
1081590Srgrimesstatic Boolean	    inLine;	/* true if currently in a dependency
1091590Srgrimes				 * line or its commands */
1101590Srgrimestypedef struct {
1111590Srgrimes    char *str;
1121590Srgrimes    char *ptr;
1131590Srgrimes} PTR;
1141590Srgrimes
1151590Srgrimesstatic char    	    *fname;	/* name of current file (for errors) */
1161590Srgrimesstatic int          lineno;	/* line number in current file */
1171590Srgrimesstatic FILE   	    *curFILE = NULL; 	/* current makefile */
1181590Srgrimes
1191590Srgrimesstatic PTR 	    *curPTR = NULL; 	/* current makefile */
1201590Srgrimes
1211590Srgrimesstatic int	    fatals = 0;
1221590Srgrimes
1231590Srgrimesstatic GNode	    *mainNode;	/* The main target to create. This is the
1241590Srgrimes				 * first target on the first dependency
1251590Srgrimes				 * line in the first makefile */
1261590Srgrimes/*
1271590Srgrimes * Definitions for handling #include specifications
1281590Srgrimes */
1291590Srgrimestypedef struct IFile {
1301590Srgrimes    char           *fname;	    /* name of previous file */
1311590Srgrimes    int             lineno;	    /* saved line number */
1321590Srgrimes    FILE *          F;		    /* the open stream */
1331590Srgrimes    PTR *	    p;	    	    /* the char pointer */
1341590Srgrimes} IFile;
1351590Srgrimes
1361590Srgrimesstatic Lst      includes;  	/* stack of IFiles generated by
1371590Srgrimes				 * #includes */
1381590SrgrimesLst         	parseIncPath;	/* list of directories for "..." includes */
1391590SrgrimesLst         	sysIncPath;	/* list of directories for <...> includes */
1401590Srgrimes
1411590Srgrimes/*-
1421590Srgrimes * specType contains the SPECial TYPE of the current target. It is
1431590Srgrimes * Not if the target is unspecial. If it *is* special, however, the children
1441590Srgrimes * are linked as children of the parent but not vice versa. This variable is
1451590Srgrimes * set in ParseDoDependency
1461590Srgrimes */
1471590Srgrimestypedef enum {
1481590Srgrimes    Begin,  	    /* .BEGIN */
1491590Srgrimes    Default,	    /* .DEFAULT */
1501590Srgrimes    End,    	    /* .END */
1511590Srgrimes    Ignore,	    /* .IGNORE */
1521590Srgrimes    Includes,	    /* .INCLUDES */
1531590Srgrimes    Interrupt,	    /* .INTERRUPT */
1541590Srgrimes    Libs,	    /* .LIBS */
1551590Srgrimes    MFlags,	    /* .MFLAGS or .MAKEFLAGS */
1561590Srgrimes    Main,	    /* .MAIN and we don't have anything user-specified to
1571590Srgrimes		     * make */
1581590Srgrimes    NoExport,	    /* .NOEXPORT */
1591590Srgrimes    Not,	    /* Not special */
1601590Srgrimes    NotParallel,    /* .NOTPARALELL */
1611590Srgrimes    Null,   	    /* .NULL */
1621590Srgrimes    Order,  	    /* .ORDER */
16318730Ssteve    Parallel,	    /* .PARALLEL */
1641590Srgrimes    ExPath,	    /* .PATH */
16518730Ssteve    Phony,	    /* .PHONY */
16619344Ssteve#ifdef POSIX
16719344Ssteve    Posix,	    /* .POSIX */
16819344Ssteve#endif
1691590Srgrimes    Precious,	    /* .PRECIOUS */
1701590Srgrimes    ExShell,	    /* .SHELL */
1711590Srgrimes    Silent,	    /* .SILENT */
1721590Srgrimes    SingleShell,    /* .SINGLESHELL */
1731590Srgrimes    Suffixes,	    /* .SUFFIXES */
17418730Ssteve    Wait,	    /* .WAIT */
1751590Srgrimes    Attribute	    /* Generic attribute */
1761590Srgrimes} ParseSpecial;
1771590Srgrimes
1781590Srgrimesstatic ParseSpecial specType;
17918730Sstevestatic int waiting;
1801590Srgrimes
1811590Srgrimes/*
18269527Swill * Predecessor node for handling .ORDER. Initialized to NULL when .ORDER
1831590Srgrimes * seen, then set to each successive source on the line.
1841590Srgrimes */
1851590Srgrimesstatic GNode	*predecessor;
1861590Srgrimes
1871590Srgrimes/*
1881590Srgrimes * The parseKeywords table is searched using binary search when deciding
1891590Srgrimes * if a target or source is special. The 'spec' field is the ParseSpecial
1901590Srgrimes * type of the keyword ("Not" if the keyword isn't special as a target) while
1911590Srgrimes * the 'op' field is the operator to apply to the list of targets if the
1921590Srgrimes * keyword is used as a source ("0" if the keyword isn't special as a source)
1931590Srgrimes */
1941590Srgrimesstatic struct {
1951590Srgrimes    char    	  *name;    	/* Name of keyword */
1961590Srgrimes    ParseSpecial  spec;	    	/* Type when used as a target */
1971590Srgrimes    int	    	  op;	    	/* Operator when used as a source */
1981590Srgrimes} parseKeywords[] = {
1991590Srgrimes{ ".BEGIN", 	  Begin,    	0 },
2001590Srgrimes{ ".DEFAULT",	  Default,  	0 },
2011590Srgrimes{ ".END",   	  End,	    	0 },
2021590Srgrimes{ ".EXEC",	  Attribute,   	OP_EXEC },
2031590Srgrimes{ ".IGNORE",	  Ignore,   	OP_IGNORE },
2041590Srgrimes{ ".INCLUDES",	  Includes, 	0 },
2051590Srgrimes{ ".INTERRUPT",	  Interrupt,	0 },
2061590Srgrimes{ ".INVISIBLE",	  Attribute,   	OP_INVISIBLE },
2071590Srgrimes{ ".JOIN",  	  Attribute,   	OP_JOIN },
2081590Srgrimes{ ".LIBS",  	  Libs,	    	0 },
2091590Srgrimes{ ".MAIN",	  Main,		0 },
2101590Srgrimes{ ".MAKE",  	  Attribute,   	OP_MAKE },
2111590Srgrimes{ ".MAKEFLAGS",	  MFlags,   	0 },
2121590Srgrimes{ ".MFLAGS",	  MFlags,   	0 },
2131590Srgrimes{ ".NOTMAIN",	  Attribute,   	OP_NOTMAIN },
2141590Srgrimes{ ".NOTPARALLEL", NotParallel,	0 },
21518730Ssteve{ ".NO_PARALLEL", NotParallel,	0 },
2161590Srgrimes{ ".NULL",  	  Null,	    	0 },
2179254Sache{ ".OPTIONAL",	  Attribute,   	OP_OPTIONAL },
2181590Srgrimes{ ".ORDER", 	  Order,    	0 },
21918730Ssteve{ ".PARALLEL",	  Parallel,	0 },
2201590Srgrimes{ ".PATH",	  ExPath,	0 },
22118730Ssteve{ ".PHONY",	  Phony,	OP_PHONY },
22219344Ssteve#ifdef POSIX
22319344Ssteve{ ".POSIX",	  Posix,	0 },
22419344Ssteve#endif
2251590Srgrimes{ ".PRECIOUS",	  Precious, 	OP_PRECIOUS },
2261590Srgrimes{ ".RECURSIVE",	  Attribute,	OP_MAKE },
2271590Srgrimes{ ".SHELL", 	  ExShell,    	0 },
2281590Srgrimes{ ".SILENT",	  Silent,   	OP_SILENT },
2291590Srgrimes{ ".SINGLESHELL", SingleShell,	0 },
2301590Srgrimes{ ".SUFFIXES",	  Suffixes, 	0 },
2311590Srgrimes{ ".USE",   	  Attribute,   	OP_USE },
23218730Ssteve{ ".WAIT",	  Wait, 	0 },
2331590Srgrimes};
2341590Srgrimes
23592921Simpstatic int ParseFindKeyword(char *);
23692921Simpstatic int ParseLinkSrc(void *, void *);
23792921Simpstatic int ParseDoOp(void *, void *);
23892921Simpstatic int ParseAddDep(void *, void *);
23992921Simpstatic void ParseDoSrc(int, char *, Lst);
24092921Simpstatic int ParseFindMain(void *, void *);
24192921Simpstatic int ParseAddDir(void *, void *);
24292921Simpstatic int ParseClearPath(void *, void *);
24392921Simpstatic void ParseDoDependency(char *);
24492921Simpstatic int ParseAddCmd(void *, void *);
24592921Simpstatic int ParseReadc(void);
24692921Simpstatic void ParseUnreadc(int);
24792921Simpstatic void ParseHasCommands(void *);
24892921Simpstatic void ParseDoInclude(char *);
24992921Simpstatic void ParseDoError(char *);
2501590Srgrimes#ifdef SYSVINCLUDE
25192921Simpstatic void ParseTraditionalInclude(char *);
2521590Srgrimes#endif
25392921Simpstatic int ParseEOF(int);
25492921Simpstatic char *ParseReadLine(void);
25592921Simpstatic char *ParseSkipLine(int);
25692921Simpstatic void ParseFinishLine(void);
2571590Srgrimes
2581590Srgrimes/*-
2591590Srgrimes *----------------------------------------------------------------------
2601590Srgrimes * ParseFindKeyword --
2611590Srgrimes *	Look in the table of keywords for one matching the given string.
2621590Srgrimes *
2631590Srgrimes * Results:
2641590Srgrimes *	The index of the keyword, or -1 if it isn't there.
2651590Srgrimes *
2661590Srgrimes * Side Effects:
2671590Srgrimes *	None
2681590Srgrimes *----------------------------------------------------------------------
2691590Srgrimes */
2701590Srgrimesstatic int
2711590SrgrimesParseFindKeyword (str)
2721590Srgrimes    char	    *str;		/* String to find */
2731590Srgrimes{
2741590Srgrimes    register int    start,
2751590Srgrimes		    end,
2761590Srgrimes		    cur;
2771590Srgrimes    register int    diff;
2788874Srgrimes
2791590Srgrimes    start = 0;
2801590Srgrimes    end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;
2811590Srgrimes
2821590Srgrimes    do {
2831590Srgrimes	cur = start + ((end - start) / 2);
2841590Srgrimes	diff = strcmp (str, parseKeywords[cur].name);
2851590Srgrimes
2861590Srgrimes	if (diff == 0) {
2871590Srgrimes	    return (cur);
2881590Srgrimes	} else if (diff < 0) {
2891590Srgrimes	    end = cur - 1;
2901590Srgrimes	} else {
2911590Srgrimes	    start = cur + 1;
2921590Srgrimes	}
2931590Srgrimes    } while (start <= end);
2941590Srgrimes    return (-1);
2951590Srgrimes}
2961590Srgrimes
2971590Srgrimes/*-
2981590Srgrimes * Parse_Error  --
2991590Srgrimes *	Error message abort function for parsing. Prints out the context
3001590Srgrimes *	of the error (line number and file) as well as the message with
3011590Srgrimes *	two optional arguments.
3021590Srgrimes *
3031590Srgrimes * Results:
3041590Srgrimes *	None
3051590Srgrimes *
3061590Srgrimes * Side Effects:
3071590Srgrimes *	"fatals" is incremented if the level is PARSE_FATAL.
3081590Srgrimes */
3091590Srgrimes/* VARARGS */
3101590Srgrimesvoid
3115814SjkhParse_Error(int type, char *fmt, ...)
3121590Srgrimes{
3131590Srgrimes	va_list ap;
31493056Simp
3151590Srgrimes	va_start(ap, fmt);
3161590Srgrimes	(void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno);
3171590Srgrimes	if (type == PARSE_WARNING)
3181590Srgrimes		(void)fprintf(stderr, "warning: ");
3191590Srgrimes	(void)vfprintf(stderr, fmt, ap);
3201590Srgrimes	va_end(ap);
3211590Srgrimes	(void)fprintf(stderr, "\n");
3221590Srgrimes	(void)fflush(stderr);
3231590Srgrimes	if (type == PARSE_FATAL)
3241590Srgrimes		fatals += 1;
3251590Srgrimes}
3261590Srgrimes
3271590Srgrimes/*-
3281590Srgrimes *---------------------------------------------------------------------
3291590Srgrimes * ParseLinkSrc  --
3301590Srgrimes *	Link the parent node to its new child. Used in a Lst_ForEach by
3311590Srgrimes *	ParseDoDependency. If the specType isn't 'Not', the parent
3321590Srgrimes *	isn't linked as a parent of the child.
3331590Srgrimes *
3341590Srgrimes * Results:
3351590Srgrimes *	Always = 0
3361590Srgrimes *
3371590Srgrimes * Side Effects:
3381590Srgrimes *	New elements are added to the parents list of cgn and the
3391590Srgrimes *	children list of cgn. the unmade field of pgn is updated
3401590Srgrimes *	to reflect the additional child.
3411590Srgrimes *---------------------------------------------------------------------
3421590Srgrimes */
3431590Srgrimesstatic int
3445814SjkhParseLinkSrc (pgnp, cgnp)
34569531Swill    void *     pgnp;	/* The parent node */
34669531Swill    void *     cgnp;	/* The child node */
3471590Srgrimes{
3485814Sjkh    GNode          *pgn = (GNode *) pgnp;
3495814Sjkh    GNode          *cgn = (GNode *) cgnp;
35069531Swill    if (Lst_Member (pgn->children, (void *)cgn) == NULL) {
35169531Swill	(void)Lst_AtEnd (pgn->children, (void *)cgn);
3521590Srgrimes	if (specType == Not) {
35369531Swill	    (void)Lst_AtEnd (cgn->parents, (void *)pgn);
3541590Srgrimes	}
3551590Srgrimes	pgn->unmade += 1;
3561590Srgrimes    }
3571590Srgrimes    return (0);
3581590Srgrimes}
3591590Srgrimes
3601590Srgrimes/*-
3611590Srgrimes *---------------------------------------------------------------------
3621590Srgrimes * ParseDoOp  --
3631590Srgrimes *	Apply the parsed operator to the given target node. Used in a
3641590Srgrimes *	Lst_ForEach call by ParseDoDependency once all targets have
3651590Srgrimes *	been found and their operator parsed. If the previous and new
3661590Srgrimes *	operators are incompatible, a major error is taken.
3671590Srgrimes *
3681590Srgrimes * Results:
3691590Srgrimes *	Always 0
3701590Srgrimes *
3711590Srgrimes * Side Effects:
3721590Srgrimes *	The type field of the node is altered to reflect any new bits in
3731590Srgrimes *	the op.
3741590Srgrimes *---------------------------------------------------------------------
3751590Srgrimes */
3761590Srgrimesstatic int
3775814SjkhParseDoOp (gnp, opp)
37869531Swill    void *     gnp;		/* The node to which the operator is to be
3791590Srgrimes				 * applied */
38069531Swill    void *     opp;		/* The operator to apply */
3811590Srgrimes{
3825814Sjkh    GNode          *gn = (GNode *) gnp;
3835814Sjkh    int             op = *(int *) opp;
3841590Srgrimes    /*
3851590Srgrimes     * If the dependency mask of the operator and the node don't match and
3861590Srgrimes     * the node has actually had an operator applied to it before, and
3878874Srgrimes     * the operator actually has some dependency information in it, complain.
3881590Srgrimes     */
3891590Srgrimes    if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
3901590Srgrimes	!OP_NOP(gn->type) && !OP_NOP(op))
3911590Srgrimes    {
3921590Srgrimes	Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name);
3931590Srgrimes	return (1);
3941590Srgrimes    }
3951590Srgrimes
3961590Srgrimes    if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
3971590Srgrimes	/*
3981590Srgrimes	 * If the node was the object of a :: operator, we need to create a
3991590Srgrimes	 * new instance of it for the children and commands on this dependency
4001590Srgrimes	 * line. The new instance is placed on the 'cohorts' list of the
4011590Srgrimes	 * initial one (note the initial one is not on its own cohorts list)
4021590Srgrimes	 * and the new instance is linked to all parents of the initial
4031590Srgrimes	 * instance.
4041590Srgrimes	 */
4051590Srgrimes	register GNode	*cohort;
4061590Srgrimes	LstNode	    	ln;
4078874Srgrimes
4081590Srgrimes	cohort = Targ_NewGN(gn->name);
4091590Srgrimes	/*
4101590Srgrimes	 * Duplicate links to parents so graph traversal is simple. Perhaps
4111590Srgrimes	 * some type bits should be duplicated?
4121590Srgrimes	 *
4131590Srgrimes	 * Make the cohort invisible as well to avoid duplicating it into
4141590Srgrimes	 * other variables. True, parents of this target won't tend to do
4151590Srgrimes	 * anything with their local variables, but better safe than
4161590Srgrimes	 * sorry.
4171590Srgrimes	 */
41869531Swill	Lst_ForEach(gn->parents, ParseLinkSrc, (void *)cohort);
4191590Srgrimes	cohort->type = OP_DOUBLEDEP|OP_INVISIBLE;
42069531Swill	(void)Lst_AtEnd(gn->cohorts, (void *)cohort);
4211590Srgrimes
4221590Srgrimes	/*
4231590Srgrimes	 * Replace the node in the targets list with the new copy
4241590Srgrimes	 */
42569531Swill	ln = Lst_Member(targets, (void *)gn);
42669531Swill	Lst_Replace(ln, (void *)cohort);
4271590Srgrimes	gn = cohort;
4281590Srgrimes    }
4291590Srgrimes    /*
4301590Srgrimes     * We don't want to nuke any previous flags (whatever they were) so we
4318874Srgrimes     * just OR the new operator into the old
4321590Srgrimes     */
4331590Srgrimes    gn->type |= op;
4341590Srgrimes
4351590Srgrimes    return (0);
4361590Srgrimes}
4371590Srgrimes
4381590Srgrimes/*-
4391590Srgrimes *---------------------------------------------------------------------
44018730Ssteve * ParseAddDep  --
44118730Ssteve *	Check if the pair of GNodes given needs to be synchronized.
44218730Ssteve *	This has to be when two nodes are on different sides of a
44318730Ssteve *	.WAIT directive.
44418730Ssteve *
44518730Ssteve * Results:
44618730Ssteve *	Returns 1 if the two targets need to be ordered, 0 otherwise.
44718730Ssteve *	If it returns 1, the search can stop
44818730Ssteve *
44918730Ssteve * Side Effects:
45018730Ssteve *	A dependency can be added between the two nodes.
45118730Ssteve *
45218730Ssteve *---------------------------------------------------------------------
45318730Ssteve */
45449938Shoekstatic int
45518730SsteveParseAddDep(pp, sp)
45669531Swill    void * pp;
45769531Swill    void * sp;
45818730Ssteve{
45918730Ssteve    GNode *p = (GNode *) pp;
46018730Ssteve    GNode *s = (GNode *) sp;
46118730Ssteve
46218730Ssteve    if (p->order < s->order) {
46318730Ssteve	/*
46418730Ssteve	 * XXX: This can cause loops, and loops can cause unmade targets,
46518730Ssteve	 * but checking is tedious, and the debugging output can show the
46618730Ssteve	 * problem
46718730Ssteve	 */
46869531Swill	(void)Lst_AtEnd(p->successors, (void *)s);
46969531Swill	(void)Lst_AtEnd(s->preds, (void *)p);
47018730Ssteve	return 0;
47118730Ssteve    }
47218730Ssteve    else
47318730Ssteve	return 1;
47418730Ssteve}
47518730Ssteve
47618730Ssteve
47718730Ssteve/*-
47818730Ssteve *---------------------------------------------------------------------
4791590Srgrimes * ParseDoSrc  --
4801590Srgrimes *	Given the name of a source, figure out if it is an attribute
4811590Srgrimes *	and apply it to the targets if it is. Else decide if there is
4821590Srgrimes *	some attribute which should be applied *to* the source because
4831590Srgrimes *	of some special target and apply it if so. Otherwise, make the
4841590Srgrimes *	source be a child of the targets in the list 'targets'
4851590Srgrimes *
4861590Srgrimes * Results:
4871590Srgrimes *	None
4881590Srgrimes *
4891590Srgrimes * Side Effects:
4901590Srgrimes *	Operator bits may be added to the list of targets or to the source.
4911590Srgrimes *	The targets may have a new source added to their lists of children.
4921590Srgrimes *---------------------------------------------------------------------
4931590Srgrimes */
4941590Srgrimesstatic void
49518730SsteveParseDoSrc (tOp, src, allsrc)
4961590Srgrimes    int		tOp;	/* operator (if any) from special targets */
4971590Srgrimes    char	*src;	/* name of the source to handle */
49818730Ssteve    Lst		allsrc;	/* List of all sources to wait for */
4991590Srgrimes{
50018730Ssteve    GNode	*gn = NULL;
5011590Srgrimes
5021590Srgrimes    if (*src == '.' && isupper (src[1])) {
5031590Srgrimes	int keywd = ParseFindKeyword(src);
5041590Srgrimes	if (keywd != -1) {
50518730Ssteve	    int op = parseKeywords[keywd].op;
50618730Ssteve	    if (op != 0) {
50769531Swill		Lst_ForEach (targets, ParseDoOp, (void *)&op);
50818730Ssteve		return;
50918730Ssteve	    }
51018730Ssteve	    if (parseKeywords[keywd].spec == Wait) {
51118730Ssteve		waiting++;
51218730Ssteve		return;
51318730Ssteve	    }
5141590Srgrimes	}
5151590Srgrimes    }
51618730Ssteve
51718730Ssteve    switch (specType) {
51818730Ssteve    case Main:
5191590Srgrimes	/*
5201590Srgrimes	 * If we have noted the existence of a .MAIN, it means we need
5211590Srgrimes	 * to add the sources of said target to the list of things
5221590Srgrimes	 * to create. The string 'src' is likely to be free, so we
5231590Srgrimes	 * must make a new copy of it. Note that this will only be
5241590Srgrimes	 * invoked if the user didn't specify a target on the command
5251590Srgrimes	 * line. This is to allow #ifmake's to succeed, or something...
5261590Srgrimes	 */
52769531Swill	(void) Lst_AtEnd (create, (void *)estrdup(src));
5281590Srgrimes	/*
5291590Srgrimes	 * Add the name to the .TARGETS variable as well, so the user cna
5301590Srgrimes	 * employ that, if desired.
5311590Srgrimes	 */
5321590Srgrimes	Var_Append(".TARGETS", src, VAR_GLOBAL);
53318730Ssteve	return;
53418730Ssteve
53518730Ssteve    case Order:
5361590Srgrimes	/*
5371590Srgrimes	 * Create proper predecessor/successor links between the previous
5381590Srgrimes	 * source and the current one.
5391590Srgrimes	 */
5401590Srgrimes	gn = Targ_FindNode(src, TARG_CREATE);
54169527Swill	if (predecessor != NULL) {
54269531Swill	    (void)Lst_AtEnd(predecessor->successors, (void *)gn);
54369531Swill	    (void)Lst_AtEnd(gn->preds, (void *)predecessor);
5441590Srgrimes	}
5451590Srgrimes	/*
5461590Srgrimes	 * The current source now becomes the predecessor for the next one.
5471590Srgrimes	 */
5481590Srgrimes	predecessor = gn;
54918730Ssteve	break;
55018730Ssteve
55118730Ssteve    default:
5521590Srgrimes	/*
5531590Srgrimes	 * If the source is not an attribute, we need to find/create
5541590Srgrimes	 * a node for it. After that we can apply any operator to it
5551590Srgrimes	 * from a special target or link it to its parents, as
5561590Srgrimes	 * appropriate.
5571590Srgrimes	 *
5581590Srgrimes	 * In the case of a source that was the object of a :: operator,
5591590Srgrimes	 * the attribute is applied to all of its instances (as kept in
5601590Srgrimes	 * the 'cohorts' list of the node) or all the cohorts are linked
5611590Srgrimes	 * to all the targets.
5621590Srgrimes	 */
5631590Srgrimes	gn = Targ_FindNode (src, TARG_CREATE);
5641590Srgrimes	if (tOp) {
5651590Srgrimes	    gn->type |= tOp;
5661590Srgrimes	} else {
56769531Swill	    Lst_ForEach (targets, ParseLinkSrc, (void *)gn);
5681590Srgrimes	}
5691590Srgrimes	if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
5701590Srgrimes	    register GNode  	*cohort;
5711590Srgrimes	    register LstNode	ln;
5721590Srgrimes
57369527Swill	    for (ln=Lst_First(gn->cohorts); ln != NULL; ln = Lst_Succ(ln)){
5741590Srgrimes		cohort = (GNode *)Lst_Datum(ln);
5751590Srgrimes		if (tOp) {
5761590Srgrimes		    cohort->type |= tOp;
5771590Srgrimes		} else {
57869531Swill		    Lst_ForEach(targets, ParseLinkSrc, (void *)cohort);
5791590Srgrimes		}
5801590Srgrimes	    }
5811590Srgrimes	}
58218730Ssteve	break;
5831590Srgrimes    }
58418730Ssteve
58518730Ssteve    gn->order = waiting;
58669531Swill    (void)Lst_AtEnd(allsrc, (void *)gn);
58718730Ssteve    if (waiting) {
58869531Swill	Lst_ForEach(allsrc, ParseAddDep, (void *)gn);
58918730Ssteve    }
5901590Srgrimes}
5911590Srgrimes
5921590Srgrimes/*-
5931590Srgrimes *-----------------------------------------------------------------------
5941590Srgrimes * ParseFindMain --
5951590Srgrimes *	Find a real target in the list and set it to be the main one.
5961590Srgrimes *	Called by ParseDoDependency when a main target hasn't been found
5971590Srgrimes *	yet.
5981590Srgrimes *
5991590Srgrimes * Results:
6001590Srgrimes *	0 if main not found yet, 1 if it is.
6011590Srgrimes *
6021590Srgrimes * Side Effects:
6031590Srgrimes *	mainNode is changed and Targ_SetMain is called.
6041590Srgrimes *
6051590Srgrimes *-----------------------------------------------------------------------
6061590Srgrimes */
6071590Srgrimesstatic int
6085814SjkhParseFindMain(gnp, dummy)
60969531Swill    void *	  gnp;	    /* Node to examine */
61069531Swill    void *    dummy;
6111590Srgrimes{
6125814Sjkh    GNode   	  *gn = (GNode *) gnp;
6131590Srgrimes    if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) {
6141590Srgrimes	mainNode = gn;
6151590Srgrimes	Targ_SetMain(gn);
6165814Sjkh	return (dummy ? 1 : 1);
6171590Srgrimes    } else {
6185814Sjkh	return (dummy ? 0 : 0);
6191590Srgrimes    }
6201590Srgrimes}
6211590Srgrimes
6221590Srgrimes/*-
6231590Srgrimes *-----------------------------------------------------------------------
6241590Srgrimes * ParseAddDir --
6251590Srgrimes *	Front-end for Dir_AddDir to make sure Lst_ForEach keeps going
6261590Srgrimes *
6271590Srgrimes * Results:
6281590Srgrimes *	=== 0
6291590Srgrimes *
6301590Srgrimes * Side Effects:
6311590Srgrimes *	See Dir_AddDir.
6321590Srgrimes *
6331590Srgrimes *-----------------------------------------------------------------------
6341590Srgrimes */
6351590Srgrimesstatic int
6361590SrgrimesParseAddDir(path, name)
63769531Swill    void *	  path;
63869531Swill    void *    name;
6391590Srgrimes{
6405814Sjkh    Dir_AddDir((Lst) path, (char *) name);
6411590Srgrimes    return(0);
6421590Srgrimes}
6431590Srgrimes
6441590Srgrimes/*-
6451590Srgrimes *-----------------------------------------------------------------------
6461590Srgrimes * ParseClearPath --
6471590Srgrimes *	Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going
6481590Srgrimes *
6491590Srgrimes * Results:
6501590Srgrimes *	=== 0
6511590Srgrimes *
6521590Srgrimes * Side Effects:
6531590Srgrimes *	See Dir_ClearPath
6541590Srgrimes *
6551590Srgrimes *-----------------------------------------------------------------------
6561590Srgrimes */
6571590Srgrimesstatic int
6585814SjkhParseClearPath(path, dummy)
65969531Swill    void * path;
66069531Swill    void * dummy;
6611590Srgrimes{
6625814Sjkh    Dir_ClearPath((Lst) path);
6635814Sjkh    return(dummy ? 0 : 0);
6641590Srgrimes}
6651590Srgrimes
6661590Srgrimes/*-
6671590Srgrimes *---------------------------------------------------------------------
6681590Srgrimes * ParseDoDependency  --
6691590Srgrimes *	Parse the dependency line in line.
6701590Srgrimes *
6711590Srgrimes * Results:
6721590Srgrimes *	None
6731590Srgrimes *
6741590Srgrimes * Side Effects:
6751590Srgrimes *	The nodes of the sources are linked as children to the nodes of the
6761590Srgrimes *	targets. Some nodes may be created.
6771590Srgrimes *
6781590Srgrimes *	We parse a dependency line by first extracting words from the line and
6791590Srgrimes * finding nodes in the list of all targets with that name. This is done
6801590Srgrimes * until a character is encountered which is an operator character. Currently
6811590Srgrimes * these are only ! and :. At this point the operator is parsed and the
6821590Srgrimes * pointer into the line advanced until the first source is encountered.
6831590Srgrimes * 	The parsed operator is applied to each node in the 'targets' list,
6841590Srgrimes * which is where the nodes found for the targets are kept, by means of
6851590Srgrimes * the ParseDoOp function.
6861590Srgrimes *	The sources are read in much the same way as the targets were except
6871590Srgrimes * that now they are expanded using the wildcarding scheme of the C-Shell
6881590Srgrimes * and all instances of the resulting words in the list of all targets
6891590Srgrimes * are found. Each of the resulting nodes is then linked to each of the
6901590Srgrimes * targets as one of its children.
6911590Srgrimes *	Certain targets are handled specially. These are the ones detailed
6921590Srgrimes * by the specType variable.
6931590Srgrimes *	The storing of transformation rules is also taken care of here.
6941590Srgrimes * A target is recognized as a transformation rule by calling
6951590Srgrimes * Suff_IsTransform. If it is a transformation rule, its node is gotten
6961590Srgrimes * from the suffix module via Suff_AddTransform rather than the standard
6971590Srgrimes * Targ_FindNode in the target module.
6981590Srgrimes *---------------------------------------------------------------------
6991590Srgrimes */
7001590Srgrimesstatic void
7011590SrgrimesParseDoDependency (line)
7021590Srgrimes    char           *line;	/* the line to parse */
7031590Srgrimes{
7045814Sjkh    char  	   *cp;		/* our current position */
7055814Sjkh    GNode 	   *gn;		/* a general purpose temporary node */
7065814Sjkh    int             op;		/* the operator on the line */
7071590Srgrimes    char            savec;	/* a place to save a character */
7081590Srgrimes    Lst    	    paths;   	/* List of search paths to alter when parsing
7091590Srgrimes				 * a list of .PATH targets */
7101590Srgrimes    int	    	    tOp;    	/* operator from special target */
71118730Ssteve    Lst	    	    sources;	/* list of archive source names after
71218730Ssteve				 * expansion */
7131590Srgrimes    Lst 	    curTargs;	/* list of target names to be found and added
7141590Srgrimes				 * to the targets list */
71518730Ssteve    Lst		    curSrcs;	/* list of sources in order */
7161590Srgrimes
7171590Srgrimes    tOp = 0;
7181590Srgrimes
7191590Srgrimes    specType = Not;
72018730Ssteve    waiting = 0;
7211590Srgrimes    paths = (Lst)NULL;
7221590Srgrimes
7231590Srgrimes    curTargs = Lst_Init(FALSE);
72418730Ssteve    curSrcs = Lst_Init(FALSE);
7258874Srgrimes
7261590Srgrimes    do {
7271590Srgrimes	for (cp = line;
7281590Srgrimes	     *cp && !isspace (*cp) &&
7291590Srgrimes	     (*cp != '!') && (*cp != ':') && (*cp != '(');
7301590Srgrimes	     cp++)
7311590Srgrimes	{
7321590Srgrimes	    if (*cp == '$') {
7331590Srgrimes		/*
7341590Srgrimes		 * Must be a dynamic source (would have been expanded
7351590Srgrimes		 * otherwise), so call the Var module to parse the puppy
7361590Srgrimes		 * so we can safely advance beyond it...There should be
7371590Srgrimes		 * no errors in this, as they would have been discovered
7381590Srgrimes		 * in the initial Var_Subst and we wouldn't be here.
7391590Srgrimes		 */
7401590Srgrimes		int 	length;
7411590Srgrimes		Boolean	freeIt;
7421590Srgrimes		char	*result;
7431590Srgrimes
7441590Srgrimes		result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);
7451590Srgrimes
7461590Srgrimes		if (freeIt) {
7471590Srgrimes		    free(result);
7481590Srgrimes		}
7491590Srgrimes		cp += length-1;
7501590Srgrimes	    }
7511590Srgrimes	    continue;
7521590Srgrimes	}
7531590Srgrimes	if (*cp == '(') {
7541590Srgrimes	    /*
7551590Srgrimes	     * Archives must be handled specially to make sure the OP_ARCHV
7561590Srgrimes	     * flag is set in their 'type' field, for one thing, and because
7571590Srgrimes	     * things like "archive(file1.o file2.o file3.o)" are permissible.
7581590Srgrimes	     * Arch_ParseArchive will set 'line' to be the first non-blank
7591590Srgrimes	     * after the archive-spec. It creates/finds nodes for the members
7601590Srgrimes	     * and places them on the given list, returning SUCCESS if all
7611590Srgrimes	     * went well and FAILURE if there was an error in the
7621590Srgrimes	     * specification. On error, line should remain untouched.
7631590Srgrimes	     */
7641590Srgrimes	    if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) {
7651590Srgrimes		Parse_Error (PARSE_FATAL,
7661590Srgrimes			     "Error in archive specification: \"%s\"", line);
7671590Srgrimes		return;
7681590Srgrimes	    } else {
7691590Srgrimes		continue;
7701590Srgrimes	    }
7711590Srgrimes	}
7721590Srgrimes	savec = *cp;
7738874Srgrimes
7741590Srgrimes	if (!*cp) {
7751590Srgrimes	    /*
7761590Srgrimes	     * Ending a dependency line without an operator is a Bozo
7778874Srgrimes	     * no-no
7781590Srgrimes	     */
7791590Srgrimes	    Parse_Error (PARSE_FATAL, "Need an operator");
7801590Srgrimes	    return;
7811590Srgrimes	}
7821590Srgrimes	*cp = '\0';
7831590Srgrimes	/*
7841590Srgrimes	 * Have a word in line. See if it's a special target and set
7851590Srgrimes	 * specType to match it.
7861590Srgrimes	 */
7871590Srgrimes	if (*line == '.' && isupper (line[1])) {
7881590Srgrimes	    /*
7891590Srgrimes	     * See if the target is a special target that must have it
7908874Srgrimes	     * or its sources handled specially.
7911590Srgrimes	     */
7921590Srgrimes	    int keywd = ParseFindKeyword(line);
7931590Srgrimes	    if (keywd != -1) {
7941590Srgrimes		if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {
7951590Srgrimes		    Parse_Error(PARSE_FATAL, "Mismatched special targets");
7961590Srgrimes		    return;
7971590Srgrimes		}
7988874Srgrimes
7991590Srgrimes		specType = parseKeywords[keywd].spec;
8001590Srgrimes		tOp = parseKeywords[keywd].op;
8011590Srgrimes
8021590Srgrimes		/*
8031590Srgrimes		 * Certain special targets have special semantics:
8041590Srgrimes		 *	.PATH		Have to set the dirSearchPath
8051590Srgrimes		 *			variable too
8061590Srgrimes		 *	.MAIN		Its sources are only used if
8071590Srgrimes		 *			nothing has been specified to
8081590Srgrimes		 *			create.
8091590Srgrimes		 *	.DEFAULT    	Need to create a node to hang
8101590Srgrimes		 *			commands on, but we don't want
8111590Srgrimes		 *			it in the graph, nor do we want
8121590Srgrimes		 *			it to be the Main Target, so we
8131590Srgrimes		 *			create it, set OP_NOTMAIN and
8141590Srgrimes		 *			add it to the list, setting
8151590Srgrimes		 *			DEFAULT to the new node for
8161590Srgrimes		 *			later use. We claim the node is
8171590Srgrimes		 *	    	    	A transformation rule to make
8181590Srgrimes		 *	    	    	life easier later, when we'll
8191590Srgrimes		 *	    	    	use Make_HandleUse to actually
8201590Srgrimes		 *	    	    	apply the .DEFAULT commands.
82118730Ssteve		 *	.PHONY		The list of targets
8221590Srgrimes		 *	.BEGIN
8231590Srgrimes		 *	.END
8241590Srgrimes		 *	.INTERRUPT  	Are not to be considered the
8251590Srgrimes		 *			main target.
8261590Srgrimes		 *  	.NOTPARALLEL	Make only one target at a time.
8271590Srgrimes		 *  	.SINGLESHELL	Create a shell for each command.
82869527Swill		 *  	.ORDER	    	Must set initial predecessor to NULL
8291590Srgrimes		 */
8301590Srgrimes		switch (specType) {
8311590Srgrimes		    case ExPath:
8321590Srgrimes			if (paths == NULL) {
8331590Srgrimes			    paths = Lst_Init(FALSE);
8341590Srgrimes			}
83569531Swill			(void)Lst_AtEnd(paths, (void *)dirSearchPath);
8361590Srgrimes			break;
8371590Srgrimes		    case Main:
8381590Srgrimes			if (!Lst_IsEmpty(create)) {
8391590Srgrimes			    specType = Not;
8401590Srgrimes			}
8411590Srgrimes			break;
8421590Srgrimes		    case Begin:
8431590Srgrimes		    case End:
8441590Srgrimes		    case Interrupt:
8451590Srgrimes			gn = Targ_FindNode(line, TARG_CREATE);
8461590Srgrimes			gn->type |= OP_NOTMAIN;
84769531Swill			(void)Lst_AtEnd(targets, (void *)gn);
8481590Srgrimes			break;
8491590Srgrimes		    case Default:
8501590Srgrimes			gn = Targ_NewGN(".DEFAULT");
8511590Srgrimes			gn->type |= (OP_NOTMAIN|OP_TRANSFORM);
85269531Swill			(void)Lst_AtEnd(targets, (void *)gn);
8531590Srgrimes			DEFAULT = gn;
8541590Srgrimes			break;
8551590Srgrimes		    case NotParallel:
8561590Srgrimes		    {
8571590Srgrimes			extern int  maxJobs;
8588874Srgrimes
8591590Srgrimes			maxJobs = 1;
8601590Srgrimes			break;
8611590Srgrimes		    }
8621590Srgrimes		    case SingleShell:
8631590Srgrimes			compatMake = 1;
8641590Srgrimes			break;
8651590Srgrimes		    case Order:
86669527Swill			predecessor = NULL;
8671590Srgrimes			break;
8681590Srgrimes		    default:
8691590Srgrimes			break;
8701590Srgrimes		}
8711590Srgrimes	    } else if (strncmp (line, ".PATH", 5) == 0) {
8721590Srgrimes		/*
8731590Srgrimes		 * .PATH<suffix> has to be handled specially.
8741590Srgrimes		 * Call on the suffix module to give us a path to
8751590Srgrimes		 * modify.
8761590Srgrimes		 */
8771590Srgrimes		Lst 	path;
8788874Srgrimes
8791590Srgrimes		specType = ExPath;
8801590Srgrimes		path = Suff_GetPath (&line[5]);
88169527Swill		if (path == NULL) {
8821590Srgrimes		    Parse_Error (PARSE_FATAL,
8831590Srgrimes				 "Suffix '%s' not defined (yet)",
8841590Srgrimes				 &line[5]);
8851590Srgrimes		    return;
8861590Srgrimes		} else {
8871590Srgrimes		    if (paths == (Lst)NULL) {
8881590Srgrimes			paths = Lst_Init(FALSE);
8891590Srgrimes		    }
89069531Swill		    (void)Lst_AtEnd(paths, (void *)path);
8911590Srgrimes		}
8921590Srgrimes	    }
8931590Srgrimes	}
8948874Srgrimes
8951590Srgrimes	/*
8961590Srgrimes	 * Have word in line. Get or create its node and stick it at
8978874Srgrimes	 * the end of the targets list
8981590Srgrimes	 */
8991590Srgrimes	if ((specType == Not) && (*line != '\0')) {
9001590Srgrimes	    if (Dir_HasWildcards(line)) {
9011590Srgrimes		/*
9021590Srgrimes		 * Targets are to be sought only in the current directory,
9031590Srgrimes		 * so create an empty path for the thing. Note we need to
9041590Srgrimes		 * use Dir_Destroy in the destruction of the path as the
9051590Srgrimes		 * Dir module could have added a directory to the path...
9061590Srgrimes		 */
9071590Srgrimes		Lst	    emptyPath = Lst_Init(FALSE);
9088874Srgrimes
9091590Srgrimes		Dir_Expand(line, emptyPath, curTargs);
9108874Srgrimes
9111590Srgrimes		Lst_Destroy(emptyPath, Dir_Destroy);
9121590Srgrimes	    } else {
9131590Srgrimes		/*
9141590Srgrimes		 * No wildcards, but we want to avoid code duplication,
9151590Srgrimes		 * so create a list with the word on it.
9161590Srgrimes		 */
91769531Swill		(void)Lst_AtEnd(curTargs, (void *)line);
9181590Srgrimes	    }
9198874Srgrimes
9201590Srgrimes	    while(!Lst_IsEmpty(curTargs)) {
9211590Srgrimes		char	*targName = (char *)Lst_DeQueue(curTargs);
9228874Srgrimes
9231590Srgrimes		if (!Suff_IsTransform (targName)) {
9241590Srgrimes		    gn = Targ_FindNode (targName, TARG_CREATE);
9251590Srgrimes		} else {
9261590Srgrimes		    gn = Suff_AddTransform (targName);
9271590Srgrimes		}
9288874Srgrimes
92969531Swill		(void)Lst_AtEnd (targets, (void *)gn);
9301590Srgrimes	    }
9311590Srgrimes	} else if (specType == ExPath && *line != '.' && *line != '\0') {
9321590Srgrimes	    Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
9331590Srgrimes	}
9348874Srgrimes
9351590Srgrimes	*cp = savec;
9361590Srgrimes	/*
9371590Srgrimes	 * If it is a special type and not .PATH, it's the only target we
9381590Srgrimes	 * allow on this line...
9391590Srgrimes	 */
9401590Srgrimes	if (specType != Not && specType != ExPath) {
9411590Srgrimes	    Boolean warn = FALSE;
9428874Srgrimes
9431590Srgrimes	    while ((*cp != '!') && (*cp != ':') && *cp) {
9441590Srgrimes		if (*cp != ' ' && *cp != '\t') {
9451590Srgrimes		    warn = TRUE;
9461590Srgrimes		}
9471590Srgrimes		cp++;
9481590Srgrimes	    }
9491590Srgrimes	    if (warn) {
9501590Srgrimes		Parse_Error(PARSE_WARNING, "Extra target ignored");
9511590Srgrimes	    }
9521590Srgrimes	} else {
9531590Srgrimes	    while (*cp && isspace (*cp)) {
9541590Srgrimes		cp++;
9551590Srgrimes	    }
9561590Srgrimes	}
9571590Srgrimes	line = cp;
9581590Srgrimes    } while ((*line != '!') && (*line != ':') && *line);
9591590Srgrimes
9601590Srgrimes    /*
9611590Srgrimes     * Don't need the list of target names anymore...
9621590Srgrimes     */
9631590Srgrimes    Lst_Destroy(curTargs, NOFREE);
9641590Srgrimes
9651590Srgrimes    if (!Lst_IsEmpty(targets)) {
9661590Srgrimes	switch(specType) {
9671590Srgrimes	    default:
9681590Srgrimes		Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");
9691590Srgrimes		break;
9701590Srgrimes	    case Default:
9711590Srgrimes	    case Begin:
9721590Srgrimes	    case End:
9731590Srgrimes	    case Interrupt:
9741590Srgrimes		/*
9751590Srgrimes		 * These four create nodes on which to hang commands, so
9761590Srgrimes		 * targets shouldn't be empty...
9771590Srgrimes		 */
9781590Srgrimes	    case Not:
9791590Srgrimes		/*
9801590Srgrimes		 * Nothing special here -- targets can be empty if it wants.
9811590Srgrimes		 */
9821590Srgrimes		break;
9831590Srgrimes	}
9841590Srgrimes    }
9851590Srgrimes
9861590Srgrimes    /*
9871590Srgrimes     * Have now parsed all the target names. Must parse the operator next. The
9881590Srgrimes     * result is left in  op .
9891590Srgrimes     */
9901590Srgrimes    if (*cp == '!') {
9911590Srgrimes	op = OP_FORCE;
9921590Srgrimes    } else if (*cp == ':') {
9931590Srgrimes	if (cp[1] == ':') {
9941590Srgrimes	    op = OP_DOUBLEDEP;
9951590Srgrimes	    cp++;
9961590Srgrimes	} else {
9971590Srgrimes	    op = OP_DEPENDS;
9981590Srgrimes	}
9991590Srgrimes    } else {
10001590Srgrimes	Parse_Error (PARSE_FATAL, "Missing dependency operator");
10011590Srgrimes	return;
10021590Srgrimes    }
10031590Srgrimes
10041590Srgrimes    cp++;			/* Advance beyond operator */
10051590Srgrimes
100669531Swill    Lst_ForEach (targets, ParseDoOp, (void *)&op);
10071590Srgrimes
10081590Srgrimes    /*
10098874Srgrimes     * Get to the first source
10101590Srgrimes     */
10111590Srgrimes    while (*cp && isspace (*cp)) {
10121590Srgrimes	cp++;
10131590Srgrimes    }
10141590Srgrimes    line = cp;
10151590Srgrimes
10161590Srgrimes    /*
10171590Srgrimes     * Several special targets take different actions if present with no
10181590Srgrimes     * sources:
10191590Srgrimes     *	a .SUFFIXES line with no sources clears out all old suffixes
10201590Srgrimes     *	a .PRECIOUS line makes all targets precious
10211590Srgrimes     *	a .IGNORE line ignores errors for all targets
10221590Srgrimes     *	a .SILENT line creates silence when making all targets
10231590Srgrimes     *	a .PATH removes all directories from the search path(s).
10241590Srgrimes     */
10251590Srgrimes    if (!*line) {
10261590Srgrimes	switch (specType) {
10271590Srgrimes	    case Suffixes:
10281590Srgrimes		Suff_ClearSuffixes ();
10291590Srgrimes		break;
10301590Srgrimes	    case Precious:
10311590Srgrimes		allPrecious = TRUE;
10321590Srgrimes		break;
10331590Srgrimes	    case Ignore:
10341590Srgrimes		ignoreErrors = TRUE;
10351590Srgrimes		break;
10361590Srgrimes	    case Silent:
10371590Srgrimes		beSilent = TRUE;
10381590Srgrimes		break;
10391590Srgrimes	    case ExPath:
104069531Swill		Lst_ForEach(paths, ParseClearPath, (void *)NULL);
10411590Srgrimes		break;
104219344Ssteve#ifdef POSIX
104319344Ssteve	    case Posix:
104419344Ssteve		Var_Set("%POSIX", "1003.2", VAR_GLOBAL);
104519344Ssteve		break;
104619344Ssteve#endif
10471590Srgrimes	    default:
10481590Srgrimes		break;
10491590Srgrimes	}
10501590Srgrimes    } else if (specType == MFlags) {
10511590Srgrimes	/*
10521590Srgrimes	 * Call on functions in main.c to deal with these arguments and
10531590Srgrimes	 * set the initial character to a null-character so the loop to
10541590Srgrimes	 * get sources won't get anything
10551590Srgrimes	 */
10561590Srgrimes	Main_ParseArgLine (line);
10571590Srgrimes	*line = '\0';
10581590Srgrimes    } else if (specType == ExShell) {
10591590Srgrimes	if (Job_ParseShell (line) != SUCCESS) {
10601590Srgrimes	    Parse_Error (PARSE_FATAL, "improper shell specification");
10611590Srgrimes	    return;
10621590Srgrimes	}
10631590Srgrimes	*line = '\0';
10641590Srgrimes    } else if ((specType == NotParallel) || (specType == SingleShell)) {
10651590Srgrimes	*line = '\0';
10661590Srgrimes    }
10678874Srgrimes
10681590Srgrimes    /*
10698874Srgrimes     * NOW GO FOR THE SOURCES
10701590Srgrimes     */
10711590Srgrimes    if ((specType == Suffixes) || (specType == ExPath) ||
10721590Srgrimes	(specType == Includes) || (specType == Libs) ||
10731590Srgrimes	(specType == Null))
10741590Srgrimes    {
10751590Srgrimes	while (*line) {
10761590Srgrimes	    /*
10771590Srgrimes	     * If the target was one that doesn't take files as its sources
10781590Srgrimes	     * but takes something like suffixes, we take each
10791590Srgrimes	     * space-separated word on the line as a something and deal
10801590Srgrimes	     * with it accordingly.
10811590Srgrimes	     *
10821590Srgrimes	     * If the target was .SUFFIXES, we take each source as a
10831590Srgrimes	     * suffix and add it to the list of suffixes maintained by the
10841590Srgrimes	     * Suff module.
10851590Srgrimes	     *
10861590Srgrimes	     * If the target was a .PATH, we add the source as a directory
10871590Srgrimes	     * to search on the search path.
10881590Srgrimes	     *
10891590Srgrimes	     * If it was .INCLUDES, the source is taken to be the suffix of
10901590Srgrimes	     * files which will be #included and whose search path should
10911590Srgrimes	     * be present in the .INCLUDES variable.
10921590Srgrimes	     *
10931590Srgrimes	     * If it was .LIBS, the source is taken to be the suffix of
10941590Srgrimes	     * files which are considered libraries and whose search path
10951590Srgrimes	     * should be present in the .LIBS variable.
10961590Srgrimes	     *
10971590Srgrimes	     * If it was .NULL, the source is the suffix to use when a file
10981590Srgrimes	     * has no valid suffix.
10991590Srgrimes	     */
11001590Srgrimes	    char  savec;
11011590Srgrimes	    while (*cp && !isspace (*cp)) {
11021590Srgrimes		cp++;
11031590Srgrimes	    }
11041590Srgrimes	    savec = *cp;
11051590Srgrimes	    *cp = '\0';
11061590Srgrimes	    switch (specType) {
11071590Srgrimes		case Suffixes:
11081590Srgrimes		    Suff_AddSuffix (line);
11091590Srgrimes		    break;
11101590Srgrimes		case ExPath:
111169531Swill		    Lst_ForEach(paths, ParseAddDir, (void *)line);
11121590Srgrimes		    break;
11131590Srgrimes		case Includes:
11141590Srgrimes		    Suff_AddInclude (line);
11151590Srgrimes		    break;
11161590Srgrimes		case Libs:
11171590Srgrimes		    Suff_AddLib (line);
11181590Srgrimes		    break;
11191590Srgrimes		case Null:
11201590Srgrimes		    Suff_SetNull (line);
11211590Srgrimes		    break;
11221590Srgrimes		default:
11231590Srgrimes		    break;
11241590Srgrimes	    }
11251590Srgrimes	    *cp = savec;
11261590Srgrimes	    if (savec != '\0') {
11271590Srgrimes		cp++;
11281590Srgrimes	    }
11291590Srgrimes	    while (*cp && isspace (*cp)) {
11301590Srgrimes		cp++;
11311590Srgrimes	    }
11321590Srgrimes	    line = cp;
11331590Srgrimes	}
11341590Srgrimes	if (paths) {
11351590Srgrimes	    Lst_Destroy(paths, NOFREE);
11361590Srgrimes	}
11371590Srgrimes    } else {
11381590Srgrimes	while (*line) {
11391590Srgrimes	    /*
11401590Srgrimes	     * The targets take real sources, so we must beware of archive
11411590Srgrimes	     * specifications (i.e. things with left parentheses in them)
11421590Srgrimes	     * and handle them accordingly.
11431590Srgrimes	     */
11441590Srgrimes	    while (*cp && !isspace (*cp)) {
11451590Srgrimes		if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) {
11461590Srgrimes		    /*
11471590Srgrimes		     * Only stop for a left parenthesis if it isn't at the
11481590Srgrimes		     * start of a word (that'll be for variable changes
11491590Srgrimes		     * later) and isn't preceded by a dollar sign (a dynamic
11501590Srgrimes		     * source).
11511590Srgrimes		     */
11521590Srgrimes		    break;
11531590Srgrimes		} else {
11541590Srgrimes		    cp++;
11551590Srgrimes		}
11561590Srgrimes	    }
11571590Srgrimes
11581590Srgrimes	    if (*cp == '(') {
11591590Srgrimes		GNode	  *gn;
11601590Srgrimes
11611590Srgrimes		sources = Lst_Init (FALSE);
11621590Srgrimes		if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) {
11631590Srgrimes		    Parse_Error (PARSE_FATAL,
11641590Srgrimes				 "Error in source archive spec \"%s\"", line);
11651590Srgrimes		    return;
11661590Srgrimes		}
11671590Srgrimes
11681590Srgrimes		while (!Lst_IsEmpty (sources)) {
11691590Srgrimes		    gn = (GNode *) Lst_DeQueue (sources);
117018730Ssteve		    ParseDoSrc (tOp, gn->name, curSrcs);
11711590Srgrimes		}
11721590Srgrimes		Lst_Destroy (sources, NOFREE);
11731590Srgrimes		cp = line;
11741590Srgrimes	    } else {
11751590Srgrimes		if (*cp) {
11761590Srgrimes		    *cp = '\0';
11771590Srgrimes		    cp += 1;
11781590Srgrimes		}
11791590Srgrimes
118018730Ssteve		ParseDoSrc (tOp, line, curSrcs);
11811590Srgrimes	    }
11821590Srgrimes	    while (*cp && isspace (*cp)) {
11831590Srgrimes		cp++;
11841590Srgrimes	    }
11851590Srgrimes	    line = cp;
11861590Srgrimes	}
11871590Srgrimes    }
11888874Srgrimes
118969527Swill    if (mainNode == NULL) {
11901590Srgrimes	/*
11911590Srgrimes	 * If we have yet to decide on a main target to make, in the
11921590Srgrimes	 * absence of any user input, we want the first target on
11931590Srgrimes	 * the first dependency line that is actually a real target
11941590Srgrimes	 * (i.e. isn't a .USE or .EXEC rule) to be made.
11951590Srgrimes	 */
119669531Swill	Lst_ForEach (targets, ParseFindMain, (void *)0);
11971590Srgrimes    }
11981590Srgrimes
119918730Ssteve    /*
120018730Ssteve     * Finally, destroy the list of sources
120118730Ssteve     */
120218730Ssteve    Lst_Destroy(curSrcs, NOFREE);
12031590Srgrimes}
12041590Srgrimes
12051590Srgrimes/*-
12061590Srgrimes *---------------------------------------------------------------------
12071590Srgrimes * Parse_IsVar  --
12081590Srgrimes *	Return TRUE if the passed line is a variable assignment. A variable
12091590Srgrimes *	assignment consists of a single word followed by optional whitespace
12101590Srgrimes *	followed by either a += or an = operator.
12111590Srgrimes *	This function is used both by the Parse_File function and main when
12121590Srgrimes *	parsing the command-line arguments.
12131590Srgrimes *
12141590Srgrimes * Results:
12151590Srgrimes *	TRUE if it is. FALSE if it ain't
12161590Srgrimes *
12171590Srgrimes * Side Effects:
12181590Srgrimes *	none
12191590Srgrimes *---------------------------------------------------------------------
12201590Srgrimes */
12211590SrgrimesBoolean
12221590SrgrimesParse_IsVar (line)
12231590Srgrimes    register char  *line;	/* the line to check */
12241590Srgrimes{
12251590Srgrimes    register Boolean wasSpace = FALSE;	/* set TRUE if found a space */
12261590Srgrimes    register Boolean haveName = FALSE;	/* Set TRUE if have a variable name */
122718730Ssteve    int level = 0;
122818730Ssteve#define ISEQOPERATOR(c) \
122918730Ssteve	(((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!'))
12301590Srgrimes
12311590Srgrimes    /*
12321590Srgrimes     * Skip to variable name
12331590Srgrimes     */
123418730Ssteve    for (;(*line == ' ') || (*line == '\t'); line++)
123518730Ssteve	continue;
12361590Srgrimes
123718730Ssteve    for (; *line != '=' || level != 0; line++)
123818730Ssteve	switch (*line) {
123918730Ssteve	case '\0':
12401590Srgrimes	    /*
12411590Srgrimes	     * end-of-line -- can't be a variable assignment.
12421590Srgrimes	     */
124318730Ssteve	    return FALSE;
124418730Ssteve
124518730Ssteve	case ' ':
124618730Ssteve	case '\t':
12471590Srgrimes	    /*
12481590Srgrimes	     * there can be as much white space as desired so long as there is
12498874Srgrimes	     * only one word before the operator
12501590Srgrimes	     */
12511590Srgrimes	    wasSpace = TRUE;
125218730Ssteve	    break;
125318730Ssteve
125418730Ssteve	case '(':
125518730Ssteve	case '{':
125618730Ssteve	    level++;
125718730Ssteve	    break;
125818730Ssteve
125918730Ssteve	case '}':
126018730Ssteve	case ')':
126118730Ssteve	    level--;
126218730Ssteve	    break;
126318730Ssteve
126418730Ssteve	default:
126518730Ssteve	    if (wasSpace && haveName) {
126618730Ssteve		    if (ISEQOPERATOR(*line)) {
126718730Ssteve			/*
126818730Ssteve			 * We must have a finished word
126918730Ssteve			 */
127018730Ssteve			if (level != 0)
127118730Ssteve			    return FALSE;
127218730Ssteve
127318730Ssteve			/*
127418730Ssteve			 * When an = operator [+?!:] is found, the next
127518730Ssteve			 * character must be an = or it ain't a valid
127618730Ssteve			 * assignment.
127718730Ssteve			 */
127818730Ssteve			if (line[1] == '=')
127918730Ssteve			    return haveName;
128018730Ssteve#ifdef SUNSHCMD
128118730Ssteve			/*
128218730Ssteve			 * This is a shell command
128318730Ssteve			 */
128418730Ssteve			if (strncmp(line, ":sh", 3) == 0)
128518730Ssteve			    return haveName;
128618730Ssteve#endif
128718730Ssteve		    }
128818730Ssteve		    /*
128918730Ssteve		     * This is the start of another word, so not assignment.
129018730Ssteve		     */
129118730Ssteve		    return FALSE;
12921590Srgrimes	    }
129318730Ssteve	    else {
129418730Ssteve		haveName = TRUE;
129518730Ssteve		wasSpace = FALSE;
129618730Ssteve	    }
129718730Ssteve	    break;
12981590Srgrimes	}
12991590Srgrimes
130018730Ssteve    return haveName;
13011590Srgrimes}
13021590Srgrimes
13031590Srgrimes/*-
13041590Srgrimes *---------------------------------------------------------------------
13051590Srgrimes * Parse_DoVar  --
13061590Srgrimes *	Take the variable assignment in the passed line and do it in the
13071590Srgrimes *	global context.
13081590Srgrimes *
13091590Srgrimes *	Note: There is a lexical ambiguity with assignment modifier characters
13101590Srgrimes *	in variable names. This routine interprets the character before the =
13111590Srgrimes *	as a modifier. Therefore, an assignment like
13121590Srgrimes *	    C++=/usr/bin/CC
13131590Srgrimes *	is interpreted as "C+ +=" instead of "C++ =".
13141590Srgrimes *
13151590Srgrimes * Results:
13161590Srgrimes *	none
13171590Srgrimes *
13181590Srgrimes * Side Effects:
13191590Srgrimes *	the variable structure of the given variable name is altered in the
13201590Srgrimes *	global context.
13211590Srgrimes *---------------------------------------------------------------------
13221590Srgrimes */
13231590Srgrimesvoid
13241590SrgrimesParse_DoVar (line, ctxt)
13251590Srgrimes    char            *line;	/* a line guaranteed to be a variable
13261590Srgrimes				 * assignment. This reduces error checks */
13271590Srgrimes    GNode   	    *ctxt;    	/* Context in which to do the assignment */
13281590Srgrimes{
13295814Sjkh    char	   *cp;	/* pointer into line */
13301590Srgrimes    enum {
13311590Srgrimes	VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL
13321590Srgrimes    }	    	    type;   	/* Type of assignment */
13338874Srgrimes    char            *opc;	/* ptr to operator character to
13341590Srgrimes				 * null-terminate the variable name */
13358874Srgrimes    /*
13361590Srgrimes     * Avoid clobbered variable warnings by forcing the compiler
13371590Srgrimes     * to ``unregister'' variables
13385814Sjkh     */
13391590Srgrimes#if __GNUC__
13405814Sjkh    (void) &cp;
13415814Sjkh    (void) &line;
13425814Sjkh#endif
13431590Srgrimes
13441590Srgrimes    /*
13451590Srgrimes     * Skip to variable name
13461590Srgrimes     */
13471590Srgrimes    while ((*line == ' ') || (*line == '\t')) {
13481590Srgrimes	line++;
13491590Srgrimes    }
13501590Srgrimes
13511590Srgrimes    /*
13521590Srgrimes     * Skip to operator character, nulling out whitespace as we go
13531590Srgrimes     */
13541590Srgrimes    for (cp = line + 1; *cp != '='; cp++) {
13551590Srgrimes	if (isspace (*cp)) {
13561590Srgrimes	    *cp = '\0';
13571590Srgrimes	}
13581590Srgrimes    }
13591590Srgrimes    opc = cp-1;		/* operator is the previous character */
13601590Srgrimes    *cp++ = '\0';	/* nuke the = */
13611590Srgrimes
13621590Srgrimes    /*
13631590Srgrimes     * Check operator type
13641590Srgrimes     */
13651590Srgrimes    switch (*opc) {
13661590Srgrimes	case '+':
13671590Srgrimes	    type = VAR_APPEND;
13681590Srgrimes	    *opc = '\0';
13691590Srgrimes	    break;
13701590Srgrimes
13711590Srgrimes	case '?':
13721590Srgrimes	    /*
13731590Srgrimes	     * If the variable already has a value, we don't do anything.
13741590Srgrimes	     */
13751590Srgrimes	    *opc = '\0';
13761590Srgrimes	    if (Var_Exists(line, ctxt)) {
13771590Srgrimes		return;
13781590Srgrimes	    } else {
13791590Srgrimes		type = VAR_NORMAL;
13801590Srgrimes	    }
13811590Srgrimes	    break;
13821590Srgrimes
13831590Srgrimes	case ':':
13841590Srgrimes	    type = VAR_SUBST;
13851590Srgrimes	    *opc = '\0';
13861590Srgrimes	    break;
13871590Srgrimes
13881590Srgrimes	case '!':
13891590Srgrimes	    type = VAR_SHELL;
13901590Srgrimes	    *opc = '\0';
13911590Srgrimes	    break;
13921590Srgrimes
13931590Srgrimes	default:
139418730Ssteve#ifdef SUNSHCMD
139518730Ssteve	    while (*opc != ':')
139642409Sjkh		if (opc == line)
139718730Ssteve		    break;
139842409Sjkh		else
139942409Sjkh		    --opc;
140018730Ssteve
140118730Ssteve	    if (strncmp(opc, ":sh", 3) == 0) {
140218730Ssteve		type = VAR_SHELL;
140318730Ssteve		*opc = '\0';
140418730Ssteve		break;
140518730Ssteve	    }
140618730Ssteve#endif
14071590Srgrimes	    type = VAR_NORMAL;
14081590Srgrimes	    break;
14091590Srgrimes    }
14101590Srgrimes
14111590Srgrimes    while (isspace (*cp)) {
14121590Srgrimes	cp++;
14131590Srgrimes    }
14141590Srgrimes
14151590Srgrimes    if (type == VAR_APPEND) {
14161590Srgrimes	Var_Append (line, cp, ctxt);
14171590Srgrimes    } else if (type == VAR_SUBST) {
14181590Srgrimes	/*
14191590Srgrimes	 * Allow variables in the old value to be undefined, but leave their
14201590Srgrimes	 * invocation alone -- this is done by forcing oldVars to be false.
14211590Srgrimes	 * XXX: This can cause recursive variables, but that's not hard to do,
14221590Srgrimes	 * and this allows someone to do something like
14231590Srgrimes	 *
14241590Srgrimes	 *  CFLAGS = $(.INCLUDES)
14251590Srgrimes	 *  CFLAGS := -I.. $(CFLAGS)
14261590Srgrimes	 *
14271590Srgrimes	 * And not get an error.
14281590Srgrimes	 */
14291590Srgrimes	Boolean	  oldOldVars = oldVars;
14301590Srgrimes
14311590Srgrimes	oldVars = FALSE;
14321590Srgrimes	cp = Var_Subst(NULL, cp, ctxt, FALSE);
14331590Srgrimes	oldVars = oldOldVars;
14341590Srgrimes
14351590Srgrimes	Var_Set(line, cp, ctxt);
14361590Srgrimes	free(cp);
14371590Srgrimes    } else if (type == VAR_SHELL) {
143818730Ssteve	Boolean	freeCmd = FALSE; /* TRUE if the command needs to be freed, i.e.
143918730Ssteve				  * if any variable expansion was performed */
144018730Ssteve	char *res, *err;
14411590Srgrimes
144218730Ssteve	if (strchr(cp, '$') != NULL) {
14431590Srgrimes	    /*
14441590Srgrimes	     * There's a dollar sign in the command, so perform variable
14451590Srgrimes	     * expansion on the whole thing. The resulting string will need
14461590Srgrimes	     * freeing when we're done, so set freeCmd to TRUE.
14471590Srgrimes	     */
144818730Ssteve	    cp = Var_Subst(NULL, cp, VAR_CMD, TRUE);
14491590Srgrimes	    freeCmd = TRUE;
14501590Srgrimes	}
14511590Srgrimes
145218730Ssteve	res = Cmd_Exec(cp, &err);
145318730Ssteve	Var_Set(line, res, ctxt);
145418730Ssteve	free(res);
14551590Srgrimes
145618730Ssteve	if (err)
145718730Ssteve	    Parse_Error(PARSE_WARNING, err, cp);
14581590Srgrimes
145918730Ssteve	if (freeCmd)
146018730Ssteve	    free(cp);
14611590Srgrimes    } else {
14621590Srgrimes	/*
14631590Srgrimes	 * Normal assignment -- just do it.
14641590Srgrimes	 */
146518730Ssteve	Var_Set(line, cp, ctxt);
14661590Srgrimes    }
14671590Srgrimes}
14681590Srgrimes
146918730Ssteve
14701590Srgrimes/*-
14711590Srgrimes * ParseAddCmd  --
14721590Srgrimes *	Lst_ForEach function to add a command line to all targets
14731590Srgrimes *
14741590Srgrimes * Results:
14751590Srgrimes *	Always 0
14761590Srgrimes *
14771590Srgrimes * Side Effects:
14781590Srgrimes *	A new element is added to the commands list of the node.
14791590Srgrimes */
14801590Srgrimesstatic int
14815814SjkhParseAddCmd(gnp, cmd)
148269531Swill    void * gnp;	/* the node to which the command is to be added */
148369531Swill    void * cmd;	/* the command to add */
14841590Srgrimes{
14855814Sjkh    GNode *gn = (GNode *) gnp;
14865814Sjkh    /* if target already supplied, ignore commands */
14875814Sjkh    if (!(gn->type & OP_HAS_COMMANDS))
14885814Sjkh	(void)Lst_AtEnd(gn->commands, cmd);
14895814Sjkh    return(0);
14901590Srgrimes}
14911590Srgrimes
14921590Srgrimes/*-
14931590Srgrimes *-----------------------------------------------------------------------
14941590Srgrimes * ParseHasCommands --
14951590Srgrimes *	Callback procedure for Parse_File when destroying the list of
14961590Srgrimes *	targets on the last dependency line. Marks a target as already
14971590Srgrimes *	having commands if it does, to keep from having shell commands
14981590Srgrimes *	on multiple dependency lines.
14991590Srgrimes *
15001590Srgrimes * Results:
15015814Sjkh *	None
15021590Srgrimes *
15031590Srgrimes * Side Effects:
15041590Srgrimes *	OP_HAS_COMMANDS may be set for the target.
15051590Srgrimes *
15061590Srgrimes *-----------------------------------------------------------------------
15071590Srgrimes */
15085814Sjkhstatic void
15095814SjkhParseHasCommands(gnp)
151069531Swill    void * 	  gnp;	    /* Node to examine */
15111590Srgrimes{
15125814Sjkh    GNode *gn = (GNode *) gnp;
15131590Srgrimes    if (!Lst_IsEmpty(gn->commands)) {
15141590Srgrimes	gn->type |= OP_HAS_COMMANDS;
15151590Srgrimes    }
15161590Srgrimes}
15171590Srgrimes
15181590Srgrimes/*-
15191590Srgrimes *-----------------------------------------------------------------------
15201590Srgrimes * Parse_AddIncludeDir --
15211590Srgrimes *	Add a directory to the path searched for included makefiles
15221590Srgrimes *	bracketed by double-quotes. Used by functions in main.c
15231590Srgrimes *
15241590Srgrimes * Results:
15251590Srgrimes *	None.
15261590Srgrimes *
15271590Srgrimes * Side Effects:
15281590Srgrimes *	The directory is appended to the list.
15291590Srgrimes *
15301590Srgrimes *-----------------------------------------------------------------------
15311590Srgrimes */
15321590Srgrimesvoid
15331590SrgrimesParse_AddIncludeDir (dir)
15341590Srgrimes    char    	  *dir;	    /* The name of the directory to add */
15351590Srgrimes{
15361590Srgrimes    Dir_AddDir (parseIncPath, dir);
15371590Srgrimes}
15381590Srgrimes
153936347Ssteve/*---------------------------------------------------------------------
154036347Ssteve * ParseDoError  --
154136347Ssteve *	Handle error directive
154236347Ssteve *
154336347Ssteve *	The input is the line minus the ".error".  We substitute variables,
154436347Ssteve *	print the message and exit(1) or just print a warning if the ".error"
154536347Ssteve *	directive is malformed.
154636347Ssteve *
154736347Ssteve *---------------------------------------------------------------------
154836347Ssteve */
154936347Sstevestatic void
155036347SsteveParseDoError(errmsg)
155136347Ssteve    char          *errmsg;	/* error message */
155236347Ssteve{
155336347Ssteve	if (!isspace(*errmsg)) {
155436347Ssteve		Parse_Error(PARSE_WARNING, "invalid syntax: .error%s", errmsg);
155536347Ssteve		return;
155636347Ssteve	}
155736347Ssteve
155836347Ssteve	while (isspace(*errmsg))
155936347Ssteve		errmsg++;
156036347Ssteve
156136347Ssteve	errmsg = Var_Subst(NULL, errmsg, VAR_GLOBAL, FALSE);
156236347Ssteve
156336347Ssteve	/* use fprintf/exit instead of Parse_Error to terminate immediately */
156436347Ssteve	fprintf(stderr, "\"%s\", line %d: %s\n", fname, lineno, errmsg);
156536347Ssteve	exit(1);
156636347Ssteve}
156736347Ssteve
15681590Srgrimes/*-
15691590Srgrimes *---------------------------------------------------------------------
15701590Srgrimes * ParseDoInclude  --
15711590Srgrimes *	Push to another file.
15728874Srgrimes *
15731590Srgrimes *	The input is the line minus the #include. A file spec is a string
15741590Srgrimes *	enclosed in <> or "". The former is looked for only in sysIncPath.
15751590Srgrimes *	The latter in . and the directories specified by -I command line
15761590Srgrimes *	options
15771590Srgrimes *
15781590Srgrimes * Results:
15791590Srgrimes *	None
15801590Srgrimes *
15811590Srgrimes * Side Effects:
15821590Srgrimes *	A structure is added to the includes Lst and readProc, lineno,
15831590Srgrimes *	fname and curFILE are altered for the new file
15841590Srgrimes *---------------------------------------------------------------------
15851590Srgrimes */
15861590Srgrimesstatic void
15871590SrgrimesParseDoInclude (file)
15881590Srgrimes    char          *file;	/* file specification */
15891590Srgrimes{
15901590Srgrimes    char          *fullname;	/* full pathname of file */
15911590Srgrimes    IFile         *oldFile;	/* state associated with current file */
15921590Srgrimes    char          endc;	    	/* the character which ends the file spec */
15931590Srgrimes    char          *cp;		/* current position in file spec */
15941590Srgrimes    Boolean 	  isSystem; 	/* TRUE if makefile is a system makefile */
15951590Srgrimes
15961590Srgrimes    /*
15971590Srgrimes     * Skip to delimiter character so we know where to look
15981590Srgrimes     */
15991590Srgrimes    while ((*file == ' ') || (*file == '\t')) {
16001590Srgrimes	file++;
16011590Srgrimes    }
16021590Srgrimes
16031590Srgrimes    if ((*file != '"') && (*file != '<')) {
16041590Srgrimes	Parse_Error (PARSE_FATAL,
16051590Srgrimes	    ".include filename must be delimited by '\"' or '<'");
16061590Srgrimes	return;
16071590Srgrimes    }
16081590Srgrimes
16091590Srgrimes    /*
16101590Srgrimes     * Set the search path on which to find the include file based on the
16111590Srgrimes     * characters which bracket its name. Angle-brackets imply it's
16121590Srgrimes     * a system Makefile while double-quotes imply it's a user makefile
16131590Srgrimes     */
16141590Srgrimes    if (*file == '<') {
16151590Srgrimes	isSystem = TRUE;
16161590Srgrimes	endc = '>';
16171590Srgrimes    } else {
16181590Srgrimes	isSystem = FALSE;
16191590Srgrimes	endc = '"';
16201590Srgrimes    }
16211590Srgrimes
16221590Srgrimes    /*
16231590Srgrimes     * Skip to matching delimiter
16241590Srgrimes     */
16251590Srgrimes    for (cp = ++file; *cp && *cp != endc; cp++) {
16261590Srgrimes	continue;
16271590Srgrimes    }
16281590Srgrimes
16291590Srgrimes    if (*cp != endc) {
16301590Srgrimes	Parse_Error (PARSE_FATAL,
16311590Srgrimes		     "Unclosed %cinclude filename. '%c' expected",
16321590Srgrimes		     '.', endc);
16331590Srgrimes	return;
16341590Srgrimes    }
16351590Srgrimes    *cp = '\0';
16361590Srgrimes
16371590Srgrimes    /*
16381590Srgrimes     * Substitute for any variables in the file name before trying to
16391590Srgrimes     * find the thing.
16401590Srgrimes     */
16411590Srgrimes    file = Var_Subst (NULL, file, VAR_CMD, FALSE);
16421590Srgrimes
16431590Srgrimes    /*
16441590Srgrimes     * Now we know the file's name and its search path, we attempt to
16451590Srgrimes     * find the durn thing. A return of NULL indicates the file don't
16461590Srgrimes     * exist.
16471590Srgrimes     */
16481590Srgrimes    if (!isSystem) {
16491590Srgrimes	/*
16501590Srgrimes	 * Include files contained in double-quotes are first searched for
16511590Srgrimes	 * relative to the including file's location. We don't want to
16521590Srgrimes	 * cd there, of course, so we just tack on the old file's
16531590Srgrimes	 * leading path components and call Dir_FindFile to see if
16541590Srgrimes	 * we can locate the beast.
16551590Srgrimes	 */
165618730Ssteve	char	  *prefEnd, *Fname;
16571590Srgrimes
165818730Ssteve	/* Make a temporary copy of this, to be safe. */
165918730Ssteve	Fname = estrdup(fname);
166018730Ssteve
166118730Ssteve	prefEnd = strrchr (Fname, '/');
16621590Srgrimes	if (prefEnd != (char *)NULL) {
16631590Srgrimes	    char  	*newName;
16648874Srgrimes
16651590Srgrimes	    *prefEnd = '\0';
16665814Sjkh	    if (file[0] == '/')
166718730Ssteve		newName = estrdup(file);
16685814Sjkh	    else
166918730Ssteve		newName = str_concat (Fname, file, STR_ADDSLASH);
16701590Srgrimes	    fullname = Dir_FindFile (newName, parseIncPath);
16711590Srgrimes	    if (fullname == (char *)NULL) {
16721590Srgrimes		fullname = Dir_FindFile(newName, dirSearchPath);
16731590Srgrimes	    }
16741590Srgrimes	    free (newName);
16751590Srgrimes	    *prefEnd = '/';
16761590Srgrimes	} else {
16771590Srgrimes	    fullname = (char *)NULL;
16781590Srgrimes	}
167918730Ssteve	free (Fname);
16801590Srgrimes    } else {
16811590Srgrimes	fullname = (char *)NULL;
16821590Srgrimes    }
16831590Srgrimes
16841590Srgrimes    if (fullname == (char *)NULL) {
16851590Srgrimes	/*
16861590Srgrimes	 * System makefile or makefile wasn't found in same directory as
16871590Srgrimes	 * included makefile. Search for it first on the -I search path,
16881590Srgrimes	 * then on the .PATH search path, if not found in a -I directory.
16891590Srgrimes	 * XXX: Suffix specific?
16901590Srgrimes	 */
16911590Srgrimes	fullname = Dir_FindFile (file, parseIncPath);
16921590Srgrimes	if (fullname == (char *)NULL) {
16931590Srgrimes	    fullname = Dir_FindFile(file, dirSearchPath);
16941590Srgrimes	}
16951590Srgrimes    }
16961590Srgrimes
16971590Srgrimes    if (fullname == (char *)NULL) {
16981590Srgrimes	/*
16991590Srgrimes	 * Still haven't found the makefile. Look for it on the system
17001590Srgrimes	 * path as a last resort.
17011590Srgrimes	 */
17021590Srgrimes	fullname = Dir_FindFile(file, sysIncPath);
17031590Srgrimes    }
17041590Srgrimes
17051590Srgrimes    if (fullname == (char *) NULL) {
17061590Srgrimes	*cp = endc;
17071590Srgrimes	Parse_Error (PARSE_FATAL, "Could not find %s", file);
17081590Srgrimes	return;
17091590Srgrimes    }
17101590Srgrimes
17115814Sjkh    free(file);
17125814Sjkh
17131590Srgrimes    /*
17141590Srgrimes     * Once we find the absolute path to the file, we get to save all the
17151590Srgrimes     * state from the current file before we can start reading this
17161590Srgrimes     * include file. The state is stored in an IFile structure which
17171590Srgrimes     * is placed on a list with other IFile structures. The list makes
17181590Srgrimes     * a very nice stack to track how we got here...
17191590Srgrimes     */
17201590Srgrimes    oldFile = (IFile *) emalloc (sizeof (IFile));
17211590Srgrimes    oldFile->fname = fname;
17221590Srgrimes
17231590Srgrimes    oldFile->F = curFILE;
17241590Srgrimes    oldFile->p = curPTR;
17251590Srgrimes    oldFile->lineno = lineno;
17261590Srgrimes
172769531Swill    (void) Lst_AtFront (includes, (void *)oldFile);
17281590Srgrimes
17291590Srgrimes    /*
17301590Srgrimes     * Once the previous state has been saved, we can get down to reading
17311590Srgrimes     * the new file. We set up the name of the file to be the absolute
17321590Srgrimes     * name of the include file so error messages refer to the right
17331590Srgrimes     * place. Naturally enough, we start reading at line number 0.
17341590Srgrimes     */
17351590Srgrimes    fname = fullname;
17361590Srgrimes    lineno = 0;
17371590Srgrimes
17381590Srgrimes    curFILE = fopen (fullname, "r");
17391590Srgrimes    curPTR = NULL;
17401590Srgrimes    if (curFILE == (FILE * ) NULL) {
17411590Srgrimes	Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
17421590Srgrimes	/*
17431590Srgrimes	 * Pop to previous file
17441590Srgrimes	 */
17451590Srgrimes	(void) ParseEOF(0);
17461590Srgrimes    }
17471590Srgrimes}
17481590Srgrimes
17491590Srgrimes
175036347Ssteve
17511590Srgrimes/*-
17521590Srgrimes *---------------------------------------------------------------------
17531590Srgrimes * Parse_FromString  --
17541590Srgrimes *	Start Parsing from the given string
17558874Srgrimes *
17561590Srgrimes * Results:
17571590Srgrimes *	None
17581590Srgrimes *
17591590Srgrimes * Side Effects:
17601590Srgrimes *	A structure is added to the includes Lst and readProc, lineno,
17611590Srgrimes *	fname and curFILE are altered for the new file
17621590Srgrimes *---------------------------------------------------------------------
17631590Srgrimes */
17641590Srgrimesvoid
17651590SrgrimesParse_FromString(str)
17661590Srgrimes    char *str;
17671590Srgrimes{
17681590Srgrimes    IFile         *oldFile;	/* state associated with this file */
17691590Srgrimes
17701590Srgrimes    if (DEBUG(FOR))
17711590Srgrimes	(void) fprintf(stderr, "%s\n----\n", str);
17721590Srgrimes
17731590Srgrimes    oldFile = (IFile *) emalloc (sizeof (IFile));
17741590Srgrimes    oldFile->lineno = lineno;
17751590Srgrimes    oldFile->fname = fname;
17761590Srgrimes    oldFile->F = curFILE;
17771590Srgrimes    oldFile->p = curPTR;
17788874Srgrimes
177969531Swill    (void) Lst_AtFront (includes, (void *)oldFile);
17801590Srgrimes
17811590Srgrimes    curFILE = NULL;
17821590Srgrimes    curPTR = (PTR *) emalloc (sizeof (PTR));
17831590Srgrimes    curPTR->str = curPTR->ptr = str;
17841590Srgrimes    lineno = 0;
178518730Ssteve    fname = estrdup(fname);
17861590Srgrimes}
17871590Srgrimes
17881590Srgrimes
17891590Srgrimes#ifdef SYSVINCLUDE
17901590Srgrimes/*-
17911590Srgrimes *---------------------------------------------------------------------
17921590Srgrimes * ParseTraditionalInclude  --
17931590Srgrimes *	Push to another file.
17948874Srgrimes *
17951590Srgrimes *	The input is the line minus the "include".  The file name is
17961590Srgrimes *	the string following the "include".
17971590Srgrimes *
17981590Srgrimes * Results:
17991590Srgrimes *	None
18001590Srgrimes *
18011590Srgrimes * Side Effects:
18021590Srgrimes *	A structure is added to the includes Lst and readProc, lineno,
18031590Srgrimes *	fname and curFILE are altered for the new file
18041590Srgrimes *---------------------------------------------------------------------
18051590Srgrimes */
18061590Srgrimesstatic void
18071590SrgrimesParseTraditionalInclude (file)
18081590Srgrimes    char          *file;	/* file specification */
18091590Srgrimes{
18101590Srgrimes    char          *fullname;	/* full pathname of file */
18111590Srgrimes    IFile         *oldFile;	/* state associated with current file */
18121590Srgrimes    char          *cp;		/* current position in file spec */
18131590Srgrimes    char	  *prefEnd;
18141590Srgrimes
18151590Srgrimes    /*
18161590Srgrimes     * Skip over whitespace
18171590Srgrimes     */
18181590Srgrimes    while ((*file == ' ') || (*file == '\t')) {
18191590Srgrimes	file++;
18201590Srgrimes    }
18211590Srgrimes
18221590Srgrimes    if (*file == '\0') {
18231590Srgrimes	Parse_Error (PARSE_FATAL,
18241590Srgrimes		     "Filename missing from \"include\"");
18251590Srgrimes	return;
18261590Srgrimes    }
18271590Srgrimes
18281590Srgrimes    /*
18291590Srgrimes     * Skip to end of line or next whitespace
18301590Srgrimes     */
18311590Srgrimes    for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) {
18321590Srgrimes	continue;
18331590Srgrimes    }
18341590Srgrimes
18351590Srgrimes    *cp = '\0';
18361590Srgrimes
18371590Srgrimes    /*
18381590Srgrimes     * Substitute for any variables in the file name before trying to
18391590Srgrimes     * find the thing.
18401590Srgrimes     */
18411590Srgrimes    file = Var_Subst (NULL, file, VAR_CMD, FALSE);
18421590Srgrimes
18431590Srgrimes    /*
18441590Srgrimes     * Now we know the file's name, we attempt to find the durn thing.
18451590Srgrimes     * A return of NULL indicates the file don't exist.
18461590Srgrimes     *
18471590Srgrimes     * Include files are first searched for relative to the including
18481590Srgrimes     * file's location. We don't want to cd there, of course, so we
18491590Srgrimes     * just tack on the old file's leading path components and call
18501590Srgrimes     * Dir_FindFile to see if we can locate the beast.
18511590Srgrimes     * XXX - this *does* search in the current directory, right?
18521590Srgrimes     */
18531590Srgrimes
18541590Srgrimes    prefEnd = strrchr (fname, '/');
18551590Srgrimes    if (prefEnd != (char *)NULL) {
18561590Srgrimes	char  	*newName;
18578874Srgrimes
18581590Srgrimes	*prefEnd = '\0';
18591590Srgrimes	newName = str_concat (fname, file, STR_ADDSLASH);
18601590Srgrimes	fullname = Dir_FindFile (newName, parseIncPath);
18611590Srgrimes	if (fullname == (char *)NULL) {
18621590Srgrimes	    fullname = Dir_FindFile(newName, dirSearchPath);
18631590Srgrimes	}
18641590Srgrimes	free (newName);
18651590Srgrimes	*prefEnd = '/';
18661590Srgrimes    } else {
18671590Srgrimes	fullname = (char *)NULL;
18681590Srgrimes    }
18691590Srgrimes
18701590Srgrimes    if (fullname == (char *)NULL) {
18711590Srgrimes	/*
18721590Srgrimes	 * System makefile or makefile wasn't found in same directory as
18731590Srgrimes	 * included makefile. Search for it first on the -I search path,
18741590Srgrimes	 * then on the .PATH search path, if not found in a -I directory.
18751590Srgrimes	 * XXX: Suffix specific?
18761590Srgrimes	 */
18771590Srgrimes	fullname = Dir_FindFile (file, parseIncPath);
18781590Srgrimes	if (fullname == (char *)NULL) {
18791590Srgrimes	    fullname = Dir_FindFile(file, dirSearchPath);
18801590Srgrimes	}
18811590Srgrimes    }
18821590Srgrimes
18831590Srgrimes    if (fullname == (char *)NULL) {
18841590Srgrimes	/*
18851590Srgrimes	 * Still haven't found the makefile. Look for it on the system
18861590Srgrimes	 * path as a last resort.
18871590Srgrimes	 */
18881590Srgrimes	fullname = Dir_FindFile(file, sysIncPath);
18891590Srgrimes    }
18901590Srgrimes
18911590Srgrimes    if (fullname == (char *) NULL) {
18921590Srgrimes	Parse_Error (PARSE_FATAL, "Could not find %s", file);
18931590Srgrimes	return;
18941590Srgrimes    }
18951590Srgrimes
18961590Srgrimes    /*
18971590Srgrimes     * Once we find the absolute path to the file, we get to save all the
18981590Srgrimes     * state from the current file before we can start reading this
18991590Srgrimes     * include file. The state is stored in an IFile structure which
19001590Srgrimes     * is placed on a list with other IFile structures. The list makes
19011590Srgrimes     * a very nice stack to track how we got here...
19021590Srgrimes     */
19031590Srgrimes    oldFile = (IFile *) emalloc (sizeof (IFile));
19041590Srgrimes    oldFile->fname = fname;
19051590Srgrimes
19061590Srgrimes    oldFile->F = curFILE;
19071590Srgrimes    oldFile->p = curPTR;
19081590Srgrimes    oldFile->lineno = lineno;
19091590Srgrimes
191069531Swill    (void) Lst_AtFront (includes, (void *)oldFile);
19111590Srgrimes
19121590Srgrimes    /*
19131590Srgrimes     * Once the previous state has been saved, we can get down to reading
19141590Srgrimes     * the new file. We set up the name of the file to be the absolute
19151590Srgrimes     * name of the include file so error messages refer to the right
19161590Srgrimes     * place. Naturally enough, we start reading at line number 0.
19171590Srgrimes     */
19181590Srgrimes    fname = fullname;
19191590Srgrimes    lineno = 0;
19201590Srgrimes
19211590Srgrimes    curFILE = fopen (fullname, "r");
19221590Srgrimes    curPTR = NULL;
19231590Srgrimes    if (curFILE == (FILE * ) NULL) {
19241590Srgrimes	Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
19251590Srgrimes	/*
19261590Srgrimes	 * Pop to previous file
19271590Srgrimes	 */
19281590Srgrimes	(void) ParseEOF(1);
19291590Srgrimes    }
19301590Srgrimes}
19311590Srgrimes#endif
19321590Srgrimes
19331590Srgrimes/*-
19341590Srgrimes *---------------------------------------------------------------------
19351590Srgrimes * ParseEOF  --
19361590Srgrimes *	Called when EOF is reached in the current file. If we were reading
19371590Srgrimes *	an include file, the includes stack is popped and things set up
19381590Srgrimes *	to go back to reading the previous file at the previous location.
19391590Srgrimes *
19401590Srgrimes * Results:
19411590Srgrimes *	CONTINUE if there's more to do. DONE if not.
19421590Srgrimes *
19431590Srgrimes * Side Effects:
19441590Srgrimes *	The old curFILE, is closed. The includes list is shortened.
19451590Srgrimes *	lineno, curFILE, and fname are changed if CONTINUE is returned.
19461590Srgrimes *---------------------------------------------------------------------
19471590Srgrimes */
19481590Srgrimesstatic int
19491590SrgrimesParseEOF (opened)
19501590Srgrimes    int opened;
19511590Srgrimes{
19521590Srgrimes    IFile     *ifile;	/* the state on the top of the includes stack */
19531590Srgrimes
19541590Srgrimes    if (Lst_IsEmpty (includes)) {
19551590Srgrimes	return (DONE);
19561590Srgrimes    }
19571590Srgrimes
19581590Srgrimes    ifile = (IFile *) Lst_DeQueue (includes);
195969531Swill    free (fname);
19601590Srgrimes    fname = ifile->fname;
19611590Srgrimes    lineno = ifile->lineno;
19621590Srgrimes    if (opened && curFILE)
19631590Srgrimes	(void) fclose (curFILE);
19641590Srgrimes    if (curPTR) {
196569531Swill	free(curPTR->str);
196669531Swill	free(curPTR);
19671590Srgrimes    }
19681590Srgrimes    curFILE = ifile->F;
19691590Srgrimes    curPTR = ifile->p;
197069531Swill    free (ifile);
19711590Srgrimes    return (CONTINUE);
19721590Srgrimes}
19731590Srgrimes
19741590Srgrimes/*-
19751590Srgrimes *---------------------------------------------------------------------
19761590Srgrimes * ParseReadc  --
19778874Srgrimes *	Read a character from the current file
19781590Srgrimes *
19791590Srgrimes * Results:
19801590Srgrimes *	The character that was read
19811590Srgrimes *
19821590Srgrimes * Side Effects:
19831590Srgrimes *---------------------------------------------------------------------
19841590Srgrimes */
19851590Srgrimesstatic int
19861590SrgrimesParseReadc()
19871590Srgrimes{
19881590Srgrimes    if (curFILE)
19891590Srgrimes	return fgetc(curFILE);
19908874Srgrimes
19911590Srgrimes    if (curPTR && *curPTR->ptr)
19921590Srgrimes	return *curPTR->ptr++;
19931590Srgrimes    return EOF;
19941590Srgrimes}
19951590Srgrimes
19961590Srgrimes
19971590Srgrimes/*-
19981590Srgrimes *---------------------------------------------------------------------
19991590Srgrimes * ParseUnreadc  --
20008874Srgrimes *	Put back a character to the current file
20011590Srgrimes *
20021590Srgrimes * Results:
20031590Srgrimes *	None.
20041590Srgrimes *
20051590Srgrimes * Side Effects:
20061590Srgrimes *---------------------------------------------------------------------
20071590Srgrimes */
20081590Srgrimesstatic void
20091590SrgrimesParseUnreadc(c)
20101590Srgrimes    int c;
20111590Srgrimes{
20121590Srgrimes    if (curFILE) {
20131590Srgrimes	ungetc(c, curFILE);
20141590Srgrimes	return;
20151590Srgrimes    }
20161590Srgrimes    if (curPTR) {
20171590Srgrimes	*--(curPTR->ptr) = c;
20181590Srgrimes	return;
20191590Srgrimes    }
20201590Srgrimes}
20211590Srgrimes
20221590Srgrimes
20231590Srgrimes/* ParseSkipLine():
20241590Srgrimes *	Grab the next line
20251590Srgrimes */
20261590Srgrimesstatic char *
20271590SrgrimesParseSkipLine(skip)
20281590Srgrimes    int skip; 		/* Skip lines that don't start with . */
20291590Srgrimes{
20301590Srgrimes    char *line;
203118456Ssteve    int c, lastc, lineLength = 0;
20321590Srgrimes    Buffer buf;
20331590Srgrimes
203418456Ssteve    buf = Buf_Init(MAKE_BSIZE);
20351590Srgrimes
203618456Ssteve    do {
203718456Ssteve        Buf_Discard(buf, lineLength);
203818456Ssteve        lastc = '\0';
20398874Srgrimes
204018456Ssteve        while (((c = ParseReadc()) != '\n' || lastc == '\\')
204118456Ssteve               && c != EOF) {
204274293Swill            if (c == '\n') {
204374293Swill                Buf_ReplaceLastByte(buf, (Byte)' ');
204474293Swill                lineno++;
20458874Srgrimes
204674293Swill                while ((c = ParseReadc()) == ' ' || c == '\t');
20478874Srgrimes
204874293Swill                if (c == EOF)
204974293Swill                    break;
205074293Swill            }
205174272Swill
205274293Swill            Buf_AddByte(buf, (Byte)c);
205374293Swill            lastc = c;
205418456Ssteve        }
205518456Ssteve
205618456Ssteve        if (c == EOF) {
205718456Ssteve            Parse_Error(PARSE_FATAL, "Unclosed conditional/for loop");
205818456Ssteve            Buf_Destroy(buf, TRUE);
205918456Ssteve            return((char *)NULL);
206018456Ssteve        }
206118456Ssteve
206218456Ssteve        lineno++;
206318456Ssteve        Buf_AddByte(buf, (Byte)'\0');
206418456Ssteve        line = (char *)Buf_GetAll(buf, &lineLength);
206518456Ssteve    } while (skip == 1 && line[0] != '.');
206618456Ssteve
206718456Ssteve    Buf_Destroy(buf, FALSE);
20681590Srgrimes    return line;
20691590Srgrimes}
20701590Srgrimes
20711590Srgrimes
20721590Srgrimes/*-
20731590Srgrimes *---------------------------------------------------------------------
20741590Srgrimes * ParseReadLine --
20751590Srgrimes *	Read an entire line from the input file. Called only by Parse_File.
20761590Srgrimes *	To facilitate escaped newlines and what have you, a character is
20771590Srgrimes *	buffered in 'lastc', which is '\0' when no characters have been
20781590Srgrimes *	read. When we break out of the loop, c holds the terminating
20791590Srgrimes *	character and lastc holds a character that should be added to
20801590Srgrimes *	the line (unless we don't read anything but a terminator).
20811590Srgrimes *
20821590Srgrimes * Results:
20831590Srgrimes *	A line w/o its newline
20841590Srgrimes *
20851590Srgrimes * Side Effects:
20861590Srgrimes *	Only those associated with reading a character
20871590Srgrimes *---------------------------------------------------------------------
20881590Srgrimes */
20891590Srgrimesstatic char *
20901590SrgrimesParseReadLine ()
20911590Srgrimes{
20921590Srgrimes    Buffer  	  buf;	    	/* Buffer for current line */
20931590Srgrimes    register int  c;	      	/* the current character */
20941590Srgrimes    register int  lastc;    	/* The most-recent character */
20951590Srgrimes    Boolean	  semiNL;     	/* treat semi-colons as newlines */
20961590Srgrimes    Boolean	  ignDepOp;   	/* TRUE if should ignore dependency operators
20971590Srgrimes				 * for the purposes of setting semiNL */
20981590Srgrimes    Boolean 	  ignComment;	/* TRUE if should ignore comments (in a
20991590Srgrimes				 * shell command */
21005814Sjkh    char 	  *line;    	/* Result */
21015814Sjkh    char          *ep;		/* to strip trailing blanks */
21021590Srgrimes    int	    	  lineLength;	/* Length of result */
21031590Srgrimes
21041590Srgrimes    semiNL = FALSE;
21051590Srgrimes    ignDepOp = FALSE;
21061590Srgrimes    ignComment = FALSE;
21071590Srgrimes
21081590Srgrimes    /*
21091590Srgrimes     * Handle special-characters at the beginning of the line. Either a
21101590Srgrimes     * leading tab (shell command) or pound-sign (possible conditional)
21111590Srgrimes     * forces us to ignore comments and dependency operators and treat
21121590Srgrimes     * semi-colons as semi-colons (by leaving semiNL FALSE). This also
21131590Srgrimes     * discards completely blank lines.
21141590Srgrimes     */
21151590Srgrimes    for (;;) {
21161590Srgrimes	c = ParseReadc();
21171590Srgrimes
21181590Srgrimes	if (c == '\t') {
21191590Srgrimes	    ignComment = ignDepOp = TRUE;
21201590Srgrimes	    break;
21211590Srgrimes	} else if (c == '\n') {
21221590Srgrimes	    lineno++;
21231590Srgrimes	} else if (c == '#') {
21241590Srgrimes	    ParseUnreadc(c);
21251590Srgrimes	    break;
21261590Srgrimes	} else {
21271590Srgrimes	    /*
21281590Srgrimes	     * Anything else breaks out without doing anything
21291590Srgrimes	     */
21301590Srgrimes	    break;
21311590Srgrimes	}
21321590Srgrimes    }
21338874Srgrimes
21341590Srgrimes    if (c != EOF) {
21351590Srgrimes	lastc = c;
21361590Srgrimes	buf = Buf_Init(MAKE_BSIZE);
21378874Srgrimes
21381590Srgrimes	while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) &&
21391590Srgrimes	       (c != EOF))
21401590Srgrimes	{
21411590Srgrimestest_char:
21421590Srgrimes	    switch(c) {
21431590Srgrimes	    case '\n':
21441590Srgrimes		/*
21451590Srgrimes		 * Escaped newline: read characters until a non-space or an
21461590Srgrimes		 * unescaped newline and replace them all by a single space.
21471590Srgrimes		 * This is done by storing the space over the backslash and
21481590Srgrimes		 * dropping through with the next nonspace. If it is a
21491590Srgrimes		 * semi-colon and semiNL is TRUE, it will be recognized as a
21501590Srgrimes		 * newline in the code below this...
21511590Srgrimes		 */
21521590Srgrimes		lineno++;
21531590Srgrimes		lastc = ' ';
21541590Srgrimes		while ((c = ParseReadc ()) == ' ' || c == '\t') {
21551590Srgrimes		    continue;
21561590Srgrimes		}
21571590Srgrimes		if (c == EOF || c == '\n') {
21581590Srgrimes		    goto line_read;
21591590Srgrimes		} else {
21601590Srgrimes		    /*
21611590Srgrimes		     * Check for comments, semiNL's, etc. -- easier than
21621590Srgrimes		     * ParseUnreadc(c); continue;
21631590Srgrimes		     */
21641590Srgrimes		    goto test_char;
21651590Srgrimes		}
21661590Srgrimes		/*NOTREACHED*/
21671590Srgrimes		break;
21681590Srgrimes
21691590Srgrimes	    case ';':
21701590Srgrimes		/*
21711590Srgrimes		 * Semi-colon: Need to see if it should be interpreted as a
21721590Srgrimes		 * newline
21731590Srgrimes		 */
21741590Srgrimes		if (semiNL) {
21751590Srgrimes		    /*
21761590Srgrimes		     * To make sure the command that may be following this
21771590Srgrimes		     * semi-colon begins with a tab, we push one back into the
21781590Srgrimes		     * input stream. This will overwrite the semi-colon in the
21791590Srgrimes		     * buffer. If there is no command following, this does no
21801590Srgrimes		     * harm, since the newline remains in the buffer and the
21811590Srgrimes		     * whole line is ignored.
21821590Srgrimes		     */
21831590Srgrimes		    ParseUnreadc('\t');
21841590Srgrimes		    goto line_read;
21858874Srgrimes		}
21861590Srgrimes		break;
21871590Srgrimes	    case '=':
21881590Srgrimes		if (!semiNL) {
21891590Srgrimes		    /*
21901590Srgrimes		     * Haven't seen a dependency operator before this, so this
21911590Srgrimes		     * must be a variable assignment -- don't pay attention to
21921590Srgrimes		     * dependency operators after this.
21931590Srgrimes		     */
21941590Srgrimes		    ignDepOp = TRUE;
21951590Srgrimes		} else if (lastc == ':' || lastc == '!') {
21961590Srgrimes		    /*
21971590Srgrimes		     * Well, we've seen a dependency operator already, but it
21981590Srgrimes		     * was the previous character, so this is really just an
21991590Srgrimes		     * expanded variable assignment. Revert semi-colons to
22001590Srgrimes		     * being just semi-colons again and ignore any more
22011590Srgrimes		     * dependency operators.
22021590Srgrimes		     *
22031590Srgrimes		     * XXX: Note that a line like "foo : a:=b" will blow up,
22041590Srgrimes		     * but who'd write a line like that anyway?
22051590Srgrimes		     */
22061590Srgrimes		    ignDepOp = TRUE; semiNL = FALSE;
22071590Srgrimes		}
22081590Srgrimes		break;
22091590Srgrimes	    case '#':
22101590Srgrimes		if (!ignComment) {
221118730Ssteve		    if (
221218730Ssteve#if 0
221318730Ssteve		    compatMake &&
221418730Ssteve#endif
221518730Ssteve		    (lastc != '\\')) {
22161590Srgrimes			/*
22171590Srgrimes			 * If the character is a hash mark and it isn't escaped
22181590Srgrimes			 * (or we're being compatible), the thing is a comment.
22191590Srgrimes			 * Skip to the end of the line.
22201590Srgrimes			 */
22211590Srgrimes			do {
22221590Srgrimes			    c = ParseReadc();
22231590Srgrimes			} while ((c != '\n') && (c != EOF));
22241590Srgrimes			goto line_read;
22251590Srgrimes		    } else {
22261590Srgrimes			/*
22271590Srgrimes			 * Don't add the backslash. Just let the # get copied
22281590Srgrimes			 * over.
22291590Srgrimes			 */
22301590Srgrimes			lastc = c;
22311590Srgrimes			continue;
22321590Srgrimes		    }
22331590Srgrimes		}
22341590Srgrimes		break;
22351590Srgrimes	    case ':':
22361590Srgrimes	    case '!':
22371590Srgrimes		if (!ignDepOp && (c == ':' || c == '!')) {
22381590Srgrimes		    /*
22391590Srgrimes		     * A semi-colon is recognized as a newline only on
22401590Srgrimes		     * dependency lines. Dependency lines are lines with a
22411590Srgrimes		     * colon or an exclamation point. Ergo...
22421590Srgrimes		     */
22431590Srgrimes		    semiNL = TRUE;
22441590Srgrimes		}
22451590Srgrimes		break;
22461590Srgrimes	    }
22471590Srgrimes	    /*
22481590Srgrimes	     * Copy in the previous character and save this one in lastc.
22491590Srgrimes	     */
22501590Srgrimes	    Buf_AddByte (buf, (Byte)lastc);
22511590Srgrimes	    lastc = c;
22528874Srgrimes
22531590Srgrimes	}
22541590Srgrimes    line_read:
22551590Srgrimes	lineno++;
22568874Srgrimes
22571590Srgrimes	if (lastc != '\0') {
22581590Srgrimes	    Buf_AddByte (buf, (Byte)lastc);
22591590Srgrimes	}
22601590Srgrimes	Buf_AddByte (buf, (Byte)'\0');
22611590Srgrimes	line = (char *)Buf_GetAll (buf, &lineLength);
22621590Srgrimes	Buf_Destroy (buf, FALSE);
22635814Sjkh
22645814Sjkh	/*
22655814Sjkh	 * Strip trailing blanks and tabs from the line.
226672645Sasmodai	 * Do not strip a blank or tab that is preceded by
22675814Sjkh	 * a '\'
22685814Sjkh	 */
22695814Sjkh	ep = line;
22705814Sjkh	while (*ep)
22715814Sjkh	    ++ep;
22729298Sache	while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) {
227318730Ssteve	    if (ep > line + 1 && ep[-2] == '\\')
22745814Sjkh		break;
22755814Sjkh	    --ep;
22765814Sjkh	}
22775814Sjkh	*ep = 0;
22788874Srgrimes
22791590Srgrimes	if (line[0] == '.') {
22801590Srgrimes	    /*
22811590Srgrimes	     * The line might be a conditional. Ask the conditional module
22821590Srgrimes	     * about it and act accordingly
22831590Srgrimes	     */
22841590Srgrimes	    switch (Cond_Eval (line)) {
22851590Srgrimes	    case COND_SKIP:
22861590Srgrimes		/*
22871590Srgrimes		 * Skip to next conditional that evaluates to COND_PARSE.
22881590Srgrimes		 */
22891590Srgrimes		do {
22901590Srgrimes		    free (line);
22911590Srgrimes		    line = ParseSkipLine(1);
22921590Srgrimes		} while (line && Cond_Eval(line) != COND_PARSE);
22931590Srgrimes		if (line == NULL)
22941590Srgrimes		    break;
22951590Srgrimes		/*FALLTHRU*/
22961590Srgrimes	    case COND_PARSE:
229769531Swill		free (line);
22981590Srgrimes		line = ParseReadLine();
22991590Srgrimes		break;
23001590Srgrimes	    case COND_INVALID:
23011590Srgrimes		if (For_Eval(line)) {
23021590Srgrimes		    int ok;
23031590Srgrimes		    free(line);
23041590Srgrimes		    do {
23051590Srgrimes			/*
23061590Srgrimes			 * Skip after the matching end
23071590Srgrimes			 */
23081590Srgrimes			line = ParseSkipLine(0);
23091590Srgrimes			if (line == NULL) {
23108874Srgrimes			    Parse_Error (PARSE_FATAL,
23111590Srgrimes				     "Unexpected end of file in for loop.\n");
23121590Srgrimes			    break;
23131590Srgrimes			}
23141590Srgrimes			ok = For_Eval(line);
23151590Srgrimes			free(line);
23161590Srgrimes		    }
23171590Srgrimes		    while (ok);
23181590Srgrimes		    if (line != NULL)
23191590Srgrimes			For_Run();
23201590Srgrimes		    line = ParseReadLine();
23211590Srgrimes		}
23221590Srgrimes		break;
23231590Srgrimes	    }
23241590Srgrimes	}
23251590Srgrimes	return (line);
23261590Srgrimes
23271590Srgrimes    } else {
23281590Srgrimes	/*
23291590Srgrimes	 * Hit end-of-file, so return a NULL line to indicate this.
23301590Srgrimes	 */
23311590Srgrimes	return((char *)NULL);
23321590Srgrimes    }
23331590Srgrimes}
23341590Srgrimes
23351590Srgrimes/*-
23361590Srgrimes *-----------------------------------------------------------------------
23371590Srgrimes * ParseFinishLine --
23381590Srgrimes *	Handle the end of a dependency group.
23391590Srgrimes *
23401590Srgrimes * Results:
23411590Srgrimes *	Nothing.
23421590Srgrimes *
23431590Srgrimes * Side Effects:
23441590Srgrimes *	inLine set FALSE. 'targets' list destroyed.
23451590Srgrimes *
23461590Srgrimes *-----------------------------------------------------------------------
23471590Srgrimes */
23481590Srgrimesstatic void
23491590SrgrimesParseFinishLine()
23501590Srgrimes{
23511590Srgrimes    if (inLine) {
235269531Swill	Lst_ForEach(targets, Suff_EndTransform, (void *)NULL);
23531590Srgrimes	Lst_Destroy (targets, ParseHasCommands);
23545814Sjkh	targets = NULL;
23551590Srgrimes	inLine = FALSE;
23561590Srgrimes    }
23571590Srgrimes}
23581590Srgrimes
23598874Srgrimes
23601590Srgrimes/*-
23611590Srgrimes *---------------------------------------------------------------------
23621590Srgrimes * Parse_File --
23631590Srgrimes *	Parse a file into its component parts, incorporating it into the
23641590Srgrimes *	current dependency graph. This is the main function and controls
23651590Srgrimes *	almost every other function in this module
23661590Srgrimes *
23671590Srgrimes * Results:
23681590Srgrimes *	None
23691590Srgrimes *
23701590Srgrimes * Side Effects:
23711590Srgrimes *	Loads. Nodes are added to the list of all targets, nodes and links
23721590Srgrimes *	are added to the dependency graph. etc. etc. etc.
23731590Srgrimes *---------------------------------------------------------------------
23741590Srgrimes */
23751590Srgrimesvoid
23761590SrgrimesParse_File(name, stream)
23771590Srgrimes    char          *name;	/* the name of the file being read */
23781590Srgrimes    FILE *	  stream;   	/* Stream open to makefile to parse */
23791590Srgrimes{
23801590Srgrimes    register char *cp,		/* pointer into the line */
23811590Srgrimes                  *line;	/* the line we're working on */
23821590Srgrimes
23831590Srgrimes    inLine = FALSE;
23841590Srgrimes    fname = name;
23851590Srgrimes    curFILE = stream;
23861590Srgrimes    lineno = 0;
23871590Srgrimes    fatals = 0;
23881590Srgrimes
23891590Srgrimes    do {
23901590Srgrimes	while ((line = ParseReadLine ()) != NULL) {
23911590Srgrimes	    if (*line == '.') {
23921590Srgrimes		/*
23931590Srgrimes		 * Lines that begin with the special character are either
23941590Srgrimes		 * include or undef directives.
23951590Srgrimes		 */
23961590Srgrimes		for (cp = line + 1; isspace (*cp); cp++) {
23971590Srgrimes		    continue;
23981590Srgrimes		}
23991590Srgrimes		if (strncmp (cp, "include", 7) == 0) {
24001590Srgrimes		    ParseDoInclude (cp + 7);
24011590Srgrimes		    goto nextLine;
240236347Ssteve		} else if (strncmp (cp, "error", 5) == 0) {
240336347Ssteve		    ParseDoError(cp + 5);
240436347Ssteve	            goto nextLine;
24051590Srgrimes		} else if (strncmp(cp, "undef", 5) == 0) {
24061590Srgrimes		    char *cp2;
24075814Sjkh		    for (cp += 5; isspace((unsigned char) *cp); cp++) {
24081590Srgrimes			continue;
24091590Srgrimes		    }
24101590Srgrimes
24115814Sjkh		    for (cp2 = cp; !isspace((unsigned char) *cp2) &&
24125814Sjkh				   (*cp2 != '\0'); cp2++) {
24131590Srgrimes			continue;
24141590Srgrimes		    }
24151590Srgrimes
24161590Srgrimes		    *cp2 = '\0';
24171590Srgrimes
24181590Srgrimes		    Var_Delete(cp, VAR_GLOBAL);
24191590Srgrimes		    goto nextLine;
24201590Srgrimes		}
24211590Srgrimes	    }
24229298Sache	    if (*line == '#') {
24231590Srgrimes		/* If we're this far, the line must be a comment. */
24241590Srgrimes		goto nextLine;
24251590Srgrimes	    }
24268874Srgrimes
24275814Sjkh	    if (*line == '\t') {
24281590Srgrimes		/*
24295814Sjkh		 * If a line starts with a tab, it can only hope to be
24305814Sjkh		 * a creation command.
24311590Srgrimes		 */
24325814Sjkh#ifndef POSIX
24331590Srgrimes	    shellCommand:
24345814Sjkh#endif
24351590Srgrimes		for (cp = line + 1; isspace (*cp); cp++) {
24361590Srgrimes		    continue;
24371590Srgrimes		}
24381590Srgrimes		if (*cp) {
24391590Srgrimes		    if (inLine) {
24401590Srgrimes			/*
24411590Srgrimes			 * So long as it's not a blank line and we're actually
24421590Srgrimes			 * in a dependency spec, add the command to the list of
24438874Srgrimes			 * commands of all targets in the dependency spec
24441590Srgrimes			 */
24455814Sjkh			Lst_ForEach (targets, ParseAddCmd, cp);
244669531Swill			Lst_AtEnd(targCmds, (void *) line);
24471590Srgrimes			continue;
24481590Srgrimes		    } else {
24491590Srgrimes			Parse_Error (PARSE_FATAL,
245018730Ssteve				     "Unassociated shell command \"%s\"",
24511590Srgrimes				     cp);
24521590Srgrimes		    }
24531590Srgrimes		}
24541590Srgrimes#ifdef SYSVINCLUDE
24558874Srgrimes	    } else if (strncmp (line, "include", 7) == 0 &&
245618730Ssteve		       isspace((unsigned char) line[7]) &&
24571590Srgrimes		       strchr(line, ':') == NULL) {
24581590Srgrimes		/*
24591590Srgrimes		 * It's an S3/S5-style "include".
24601590Srgrimes		 */
24611590Srgrimes		ParseTraditionalInclude (line + 7);
24621590Srgrimes		goto nextLine;
24631590Srgrimes#endif
24641590Srgrimes	    } else if (Parse_IsVar (line)) {
24651590Srgrimes		ParseFinishLine();
24661590Srgrimes		Parse_DoVar (line, VAR_GLOBAL);
24671590Srgrimes	    } else {
24681590Srgrimes		/*
24691590Srgrimes		 * We now know it's a dependency line so it needs to have all
24701590Srgrimes		 * variables expanded before being parsed. Tell the variable
24711590Srgrimes		 * module to complain if some variable is undefined...
24721590Srgrimes		 * To make life easier on novices, if the line is indented we
24731590Srgrimes		 * first make sure the line has a dependency operator in it.
24741590Srgrimes		 * If it doesn't have an operator and we're in a dependency
24751590Srgrimes		 * line's script, we assume it's actually a shell command
24761590Srgrimes		 * and add it to the current list of targets.
24771590Srgrimes		 */
24785814Sjkh#ifndef POSIX
24791590Srgrimes		Boolean	nonSpace = FALSE;
24805814Sjkh#endif
24818874Srgrimes
24821590Srgrimes		cp = line;
24835814Sjkh		if (isspace((unsigned char) line[0])) {
24845814Sjkh		    while ((*cp != '\0') && isspace((unsigned char) *cp)) {
24855814Sjkh			cp++;
24865814Sjkh		    }
24875814Sjkh		    if (*cp == '\0') {
24885814Sjkh			goto nextLine;
24895814Sjkh		    }
24901590Srgrimes#ifndef POSIX
24911590Srgrimes		    while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) {
24925814Sjkh			nonSpace = TRUE;
24931590Srgrimes			cp++;
24941590Srgrimes		    }
24955814Sjkh#endif
24961590Srgrimes		}
24978874Srgrimes
24985814Sjkh#ifndef POSIX
24991590Srgrimes		if (*cp == '\0') {
25001590Srgrimes		    if (inLine) {
25011590Srgrimes			Parse_Error (PARSE_WARNING,
25021590Srgrimes				     "Shell command needs a leading tab");
25031590Srgrimes			goto shellCommand;
25041590Srgrimes		    } else if (nonSpace) {
25051590Srgrimes			Parse_Error (PARSE_FATAL, "Missing operator");
25061590Srgrimes		    }
25071590Srgrimes		} else {
25081590Srgrimes#endif
25091590Srgrimes		    ParseFinishLine();
25101590Srgrimes
25111590Srgrimes		    cp = Var_Subst (NULL, line, VAR_CMD, TRUE);
25121590Srgrimes		    free (line);
25131590Srgrimes		    line = cp;
25148874Srgrimes
25151590Srgrimes		    /*
25168874Srgrimes		     * Need a non-circular list for the target nodes
25171590Srgrimes		     */
25185814Sjkh		    if (targets)
25195814Sjkh			Lst_Destroy(targets, NOFREE);
25205814Sjkh
25211590Srgrimes		    targets = Lst_Init (FALSE);
25221590Srgrimes		    inLine = TRUE;
25238874Srgrimes
25241590Srgrimes		    ParseDoDependency (line);
25251590Srgrimes#ifndef POSIX
25261590Srgrimes		}
25271590Srgrimes#endif
25281590Srgrimes	    }
25291590Srgrimes
25301590Srgrimes	    nextLine:
25311590Srgrimes
25321590Srgrimes	    free (line);
25331590Srgrimes	}
25341590Srgrimes	/*
25358874Srgrimes	 * Reached EOF, but it may be just EOF of an include file...
25361590Srgrimes	 */
25371590Srgrimes    } while (ParseEOF(1) == CONTINUE);
25381590Srgrimes
25391590Srgrimes    /*
25401590Srgrimes     * Make sure conditionals are clean
25411590Srgrimes     */
25421590Srgrimes    Cond_End();
25431590Srgrimes
254427644Scharnier    if (fatals)
254527644Scharnier	errx(1, "fatal errors encountered -- cannot continue");
25461590Srgrimes}
25471590Srgrimes
25481590Srgrimes/*-
25491590Srgrimes *---------------------------------------------------------------------
25501590Srgrimes * Parse_Init --
25511590Srgrimes *	initialize the parsing module
25521590Srgrimes *
25531590Srgrimes * Results:
25541590Srgrimes *	none
25551590Srgrimes *
25561590Srgrimes * Side Effects:
25571590Srgrimes *	the parseIncPath list is initialized...
25581590Srgrimes *---------------------------------------------------------------------
25591590Srgrimes */
25601590Srgrimesvoid
25611590SrgrimesParse_Init ()
25621590Srgrimes{
256369527Swill    mainNode = NULL;
25641590Srgrimes    parseIncPath = Lst_Init (FALSE);
25651590Srgrimes    sysIncPath = Lst_Init (FALSE);
25661590Srgrimes    includes = Lst_Init (FALSE);
25675814Sjkh    targCmds = Lst_Init (FALSE);
25681590Srgrimes}
25691590Srgrimes
25705814Sjkhvoid
25715814SjkhParse_End()
25725814Sjkh{
257392921Simp    Lst_Destroy(targCmds, (void (*)(void *)) free);
25745814Sjkh    if (targets)
25755814Sjkh	Lst_Destroy(targets, NOFREE);
25765814Sjkh    Lst_Destroy(sysIncPath, Dir_Destroy);
25775814Sjkh    Lst_Destroy(parseIncPath, Dir_Destroy);
25785814Sjkh    Lst_Destroy(includes, NOFREE);	/* Should be empty now */
25795814Sjkh}
25805814Sjkh
25818874Srgrimes
25821590Srgrimes/*-
25831590Srgrimes *-----------------------------------------------------------------------
25841590Srgrimes * Parse_MainName --
25851590Srgrimes *	Return a Lst of the main target to create for main()'s sake. If
25861590Srgrimes *	no such target exists, we Punt with an obnoxious error message.
25871590Srgrimes *
25881590Srgrimes * Results:
25891590Srgrimes *	A Lst of the single node to create.
25901590Srgrimes *
25911590Srgrimes * Side Effects:
25921590Srgrimes *	None.
25931590Srgrimes *
25941590Srgrimes *-----------------------------------------------------------------------
25951590Srgrimes */
25961590SrgrimesLst
25971590SrgrimesParse_MainName()
25981590Srgrimes{
259949938Shoek    Lst           listmain;	/* result list */
26001590Srgrimes
260149938Shoek    listmain = Lst_Init (FALSE);
26021590Srgrimes
260369527Swill    if (mainNode == NULL) {
260417259Snate	Punt ("no target to make.");
26051590Srgrimes    	/*NOTREACHED*/
26061590Srgrimes    } else if (mainNode->type & OP_DOUBLEDEP) {
260769531Swill	(void) Lst_AtEnd (listmain, (void *)mainNode);
260849938Shoek	Lst_Concat(listmain, mainNode->cohorts, LST_CONCNEW);
26091590Srgrimes    }
26101590Srgrimes    else
261169531Swill	(void) Lst_AtEnd (listmain, (void *)mainNode);
261249938Shoek    return (listmain);
26131590Srgrimes}
2614