xref: /csrg-svn/usr.bin/make/parse.c (revision 69086)
140395Sbostic /*
262092Sbostic  * Copyright (c) 1988, 1989, 1990, 1993
362092Sbostic  *	The Regents of the University of California.  All rights reserved.
440395Sbostic  * Copyright (c) 1989 by Berkeley Softworks
540395Sbostic  * All rights reserved.
640395Sbostic  *
740395Sbostic  * This code is derived from software contributed to Berkeley by
840395Sbostic  * Adam de Boor.
940395Sbostic  *
1042752Sbostic  * %sccs.include.redist.c%
1140395Sbostic  */
1240395Sbostic 
1340395Sbostic #ifndef lint
14*69086Schristos static char sccsid[] = "@(#)parse.c	8.5 (Berkeley) 04/28/95";
1540395Sbostic #endif /* not lint */
1640395Sbostic 
1740393Sbostic /*-
1840393Sbostic  * parse.c --
1940393Sbostic  *	Functions to parse a makefile.
2040393Sbostic  *
2140393Sbostic  *	One function, Parse_Init, must be called before any functions
2240393Sbostic  *	in this module are used. After that, the function Parse_File is the
2340393Sbostic  *	main entry point and controls most of the other functions in this
2440393Sbostic  *	module.
2540393Sbostic  *
2640393Sbostic  *	Most important structures are kept in Lsts. Directories for
2740393Sbostic  *	the #include "..." function are kept in the 'parseIncPath' Lst, while
2840393Sbostic  *	those for the #include <...> are kept in the 'sysIncPath' Lst. The
2940393Sbostic  *	targets currently being defined are kept in the 'targets' Lst.
3040393Sbostic  *
3140393Sbostic  *	The variables 'fname' and 'lineno' are used to track the name
3240393Sbostic  *	of the current file and the line number in that file so that error
3340393Sbostic  *	messages can be more meaningful.
3440393Sbostic  *
3540393Sbostic  * Interface:
3640393Sbostic  *	Parse_Init	    	    Initialization function which must be
3740393Sbostic  *	    	  	    	    called before anything else in this module
3840393Sbostic  *	    	  	    	    is used.
3940393Sbostic  *
40*69086Schristos  *	Parse_End		    Cleanup the module
41*69086Schristos  *
4240393Sbostic  *	Parse_File	    	    Function used to parse a makefile. It must
4340393Sbostic  *	    	  	    	    be given the name of the file, which should
4440393Sbostic  *	    	  	    	    already have been opened, and a function
4540393Sbostic  *	    	  	    	    to call to read a character from the file.
4640393Sbostic  *
4740393Sbostic  *	Parse_IsVar	    	    Returns TRUE if the given line is a
4840393Sbostic  *	    	  	    	    variable assignment. Used by MainParseArgs
4940393Sbostic  *	    	  	    	    to determine if an argument is a target
5040393Sbostic  *	    	  	    	    or a variable assignment. Used internally
5140393Sbostic  *	    	  	    	    for pretty much the same thing...
5240393Sbostic  *
5340393Sbostic  *	Parse_Error	    	    Function called when an error occurs in
5440393Sbostic  *	    	  	    	    parsing. Used by the variable and
5540393Sbostic  *	    	  	    	    conditional modules.
5640393Sbostic  *	Parse_MainName	    	    Returns a Lst of the main target to create.
5740393Sbostic  */
5840393Sbostic 
5960285Sbostic #if __STDC__
6060285Sbostic #include <stdarg.h>
6160285Sbostic #else
6240444Sbostic #include <varargs.h>
6360285Sbostic #endif
6440444Sbostic #include <stdio.h>
6540444Sbostic #include <ctype.h>
6660285Sbostic #include <errno.h>
6760285Sbostic #include <sys/wait.h>
6840444Sbostic #include "make.h"
6960285Sbostic #include "hash.h"
7060285Sbostic #include "dir.h"
7160285Sbostic #include "job.h"
7240444Sbostic #include "buf.h"
7340515Sbostic #include "pathnames.h"
7440393Sbostic 
7540393Sbostic /*
7640393Sbostic  * These values are returned by ParseEOF to tell Parse_File whether to
7740393Sbostic  * CONTINUE parsing, i.e. it had only reached the end of an include file,
7840393Sbostic  * or if it's DONE.
7940393Sbostic  */
8040393Sbostic #define	CONTINUE	1
8140393Sbostic #define	DONE		0
8240393Sbostic static Lst     	    targets;	/* targets we're working on */
83*69086Schristos static Lst     	    targCmds;	/* command lines for targets */
8440393Sbostic static Boolean	    inLine;	/* true if currently in a dependency
8540393Sbostic 				 * line or its commands */
8660285Sbostic typedef struct {
8760285Sbostic     char *str;
8860285Sbostic     char *ptr;
8960285Sbostic } PTR;
9040393Sbostic 
9140393Sbostic static char    	    *fname;	/* name of current file (for errors) */
9240393Sbostic static int          lineno;	/* line number in current file */
9360285Sbostic static FILE   	    *curFILE = NULL; 	/* current makefile */
9440393Sbostic 
9560285Sbostic static PTR 	    *curPTR = NULL; 	/* current makefile */
9660285Sbostic 
9740393Sbostic static int	    fatals = 0;
9840393Sbostic 
9940393Sbostic static GNode	    *mainNode;	/* The main target to create. This is the
10040393Sbostic 				 * first target on the first dependency
10140393Sbostic 				 * line in the first makefile */
10240393Sbostic /*
10340393Sbostic  * Definitions for handling #include specifications
10440393Sbostic  */
10540393Sbostic typedef struct IFile {
10640393Sbostic     char           *fname;	    /* name of previous file */
10740393Sbostic     int             lineno;	    /* saved line number */
10860285Sbostic     FILE *          F;		    /* the open stream */
10960285Sbostic     PTR *	    p;	    	    /* the char pointer */
11060285Sbostic } IFile;
11140393Sbostic 
11240393Sbostic static Lst      includes;  	/* stack of IFiles generated by
11340393Sbostic 				 * #includes */
11440393Sbostic Lst         	parseIncPath;	/* list of directories for "..." includes */
11540393Sbostic Lst         	sysIncPath;	/* list of directories for <...> includes */
11640393Sbostic 
11740393Sbostic /*-
11840393Sbostic  * specType contains the SPECial TYPE of the current target. It is
11940393Sbostic  * Not if the target is unspecial. If it *is* special, however, the children
12040393Sbostic  * are linked as children of the parent but not vice versa. This variable is
12140393Sbostic  * set in ParseDoDependency
12240393Sbostic  */
12340393Sbostic typedef enum {
12440393Sbostic     Begin,  	    /* .BEGIN */
12540393Sbostic     Default,	    /* .DEFAULT */
12640393Sbostic     End,    	    /* .END */
12740393Sbostic     Ignore,	    /* .IGNORE */
12840393Sbostic     Includes,	    /* .INCLUDES */
12940393Sbostic     Interrupt,	    /* .INTERRUPT */
13040393Sbostic     Libs,	    /* .LIBS */
13140393Sbostic     MFlags,	    /* .MFLAGS or .MAKEFLAGS */
13240393Sbostic     Main,	    /* .MAIN and we don't have anything user-specified to
13340393Sbostic 		     * make */
13460285Sbostic     NoExport,	    /* .NOEXPORT */
13540393Sbostic     Not,	    /* Not special */
13640393Sbostic     NotParallel,    /* .NOTPARALELL */
13740393Sbostic     Null,   	    /* .NULL */
13840393Sbostic     Order,  	    /* .ORDER */
13960285Sbostic     ExPath,	    /* .PATH */
14040393Sbostic     Precious,	    /* .PRECIOUS */
14160285Sbostic     ExShell,	    /* .SHELL */
14240393Sbostic     Silent,	    /* .SILENT */
14340393Sbostic     SingleShell,    /* .SINGLESHELL */
14440393Sbostic     Suffixes,	    /* .SUFFIXES */
14560285Sbostic     Attribute	    /* Generic attribute */
14640393Sbostic } ParseSpecial;
14740393Sbostic 
14860285Sbostic static ParseSpecial specType;
14940393Sbostic 
15040393Sbostic /*
15140393Sbostic  * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER
15240393Sbostic  * seen, then set to each successive source on the line.
15340393Sbostic  */
15440393Sbostic static GNode	*predecessor;
15540393Sbostic 
15640393Sbostic /*
15740393Sbostic  * The parseKeywords table is searched using binary search when deciding
15840393Sbostic  * if a target or source is special. The 'spec' field is the ParseSpecial
15940393Sbostic  * type of the keyword ("Not" if the keyword isn't special as a target) while
16040393Sbostic  * the 'op' field is the operator to apply to the list of targets if the
16140393Sbostic  * keyword is used as a source ("0" if the keyword isn't special as a source)
16240393Sbostic  */
16340393Sbostic static struct {
16440393Sbostic     char    	  *name;    	/* Name of keyword */
16540393Sbostic     ParseSpecial  spec;	    	/* Type when used as a target */
16640393Sbostic     int	    	  op;	    	/* Operator when used as a source */
16740393Sbostic } parseKeywords[] = {
16840393Sbostic { ".BEGIN", 	  Begin,    	0 },
16940393Sbostic { ".DEFAULT",	  Default,  	0 },
17040546Sbostic { ".OPTIONAL",	  Attribute,   	OP_OPTIONAL },
17140393Sbostic { ".END",   	  End,	    	0 },
17240393Sbostic { ".EXEC",	  Attribute,   	OP_EXEC },
17340393Sbostic { ".IGNORE",	  Ignore,   	OP_IGNORE },
17440393Sbostic { ".INCLUDES",	  Includes, 	0 },
17540393Sbostic { ".INTERRUPT",	  Interrupt,	0 },
17640393Sbostic { ".INVISIBLE",	  Attribute,   	OP_INVISIBLE },
17740393Sbostic { ".JOIN",  	  Attribute,   	OP_JOIN },
17840393Sbostic { ".LIBS",  	  Libs,	    	0 },
17940393Sbostic { ".MAIN",	  Main,		0 },
18040393Sbostic { ".MAKE",  	  Attribute,   	OP_MAKE },
18140393Sbostic { ".MAKEFLAGS",	  MFlags,   	0 },
18240393Sbostic { ".MFLAGS",	  MFlags,   	0 },
18340393Sbostic { ".NOTMAIN",	  Attribute,   	OP_NOTMAIN },
18440393Sbostic { ".NOTPARALLEL", NotParallel,	0 },
18540393Sbostic { ".NULL",  	  Null,	    	0 },
18640393Sbostic { ".ORDER", 	  Order,    	0 },
18760285Sbostic { ".PATH",	  ExPath,	0 },
18840393Sbostic { ".PRECIOUS",	  Precious, 	OP_PRECIOUS },
18940393Sbostic { ".RECURSIVE",	  Attribute,	OP_MAKE },
19060285Sbostic { ".SHELL", 	  ExShell,    	0 },
19140393Sbostic { ".SILENT",	  Silent,   	OP_SILENT },
19240393Sbostic { ".SINGLESHELL", SingleShell,	0 },
19340393Sbostic { ".SUFFIXES",	  Suffixes, 	0 },
19440393Sbostic { ".USE",   	  Attribute,   	OP_USE },
19540393Sbostic };
19640424Sbostic 
19760285Sbostic static int ParseFindKeyword __P((char *));
198*69086Schristos static int ParseLinkSrc __P((ClientData, ClientData));
199*69086Schristos static int ParseDoOp __P((ClientData, ClientData));
20060285Sbostic static void ParseDoSrc __P((int, char *));
201*69086Schristos static int ParseFindMain __P((ClientData, ClientData));
202*69086Schristos static int ParseAddDir __P((ClientData, ClientData));
203*69086Schristos static int ParseClearPath __P((ClientData, ClientData));
20460285Sbostic static void ParseDoDependency __P((char *));
205*69086Schristos static int ParseAddCmd __P((ClientData, ClientData));
20660285Sbostic static int ParseReadc __P((void));
20760557Sbostic static void ParseUnreadc __P((int));
208*69086Schristos static void ParseHasCommands __P((ClientData));
20960285Sbostic static void ParseDoInclude __P((char *));
21060285Sbostic #ifdef SYSVINCLUDE
21160285Sbostic static void ParseTraditionalInclude __P((char *));
21260285Sbostic #endif
21360285Sbostic static int ParseEOF __P((int));
21460285Sbostic static char *ParseReadLine __P((void));
21560285Sbostic static char *ParseSkipLine __P((int));
21660285Sbostic static void ParseFinishLine __P((void));
21760285Sbostic 
21840393Sbostic /*-
21940393Sbostic  *----------------------------------------------------------------------
22040393Sbostic  * ParseFindKeyword --
22140393Sbostic  *	Look in the table of keywords for one matching the given string.
22240393Sbostic  *
22340393Sbostic  * Results:
22440393Sbostic  *	The index of the keyword, or -1 if it isn't there.
22540393Sbostic  *
22640393Sbostic  * Side Effects:
22740393Sbostic  *	None
22840393Sbostic  *----------------------------------------------------------------------
22940393Sbostic  */
23040393Sbostic static int
23140393Sbostic ParseFindKeyword (str)
23240393Sbostic     char	    *str;		/* String to find */
23340393Sbostic {
23440393Sbostic     register int    start,
23540393Sbostic 		    end,
23640393Sbostic 		    cur;
23740393Sbostic     register int    diff;
23840393Sbostic 
23940393Sbostic     start = 0;
24040393Sbostic     end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;
24140393Sbostic 
24240393Sbostic     do {
24340393Sbostic 	cur = start + ((end - start) / 2);
24440393Sbostic 	diff = strcmp (str, parseKeywords[cur].name);
24540393Sbostic 
24640393Sbostic 	if (diff == 0) {
24740393Sbostic 	    return (cur);
24840393Sbostic 	} else if (diff < 0) {
24940393Sbostic 	    end = cur - 1;
25040393Sbostic 	} else {
25140393Sbostic 	    start = cur + 1;
25240393Sbostic 	}
25340393Sbostic     } while (start <= end);
25440393Sbostic     return (-1);
25540393Sbostic }
25640424Sbostic 
25740393Sbostic /*-
25840393Sbostic  * Parse_Error  --
25940393Sbostic  *	Error message abort function for parsing. Prints out the context
26040393Sbostic  *	of the error (line number and file) as well as the message with
26140393Sbostic  *	two optional arguments.
26240393Sbostic  *
26340393Sbostic  * Results:
26440393Sbostic  *	None
26540393Sbostic  *
26640393Sbostic  * Side Effects:
26740393Sbostic  *	"fatals" is incremented if the level is PARSE_FATAL.
26840393Sbostic  */
26940444Sbostic /* VARARGS */
27040393Sbostic void
27160285Sbostic #if __STDC__
272*69086Schristos Parse_Error(int type, char *fmt, ...)
27360285Sbostic #else
27466399Schristos Parse_Error(va_alist)
27540444Sbostic 	va_dcl
27660285Sbostic #endif
27740393Sbostic {
27840444Sbostic 	va_list ap;
27960285Sbostic #if __STDC__
28060285Sbostic 	va_start(ap, fmt);
28160285Sbostic #else
28266399Schristos 	int type;		/* Error type (PARSE_WARNING, PARSE_FATAL) */
28366399Schristos 	char *fmt;
28466399Schristos 
28560285Sbostic 	va_start(ap);
28666399Schristos 	type = va_arg(ap, int);
28766399Schristos 	fmt = va_arg(ap, char *);
28860285Sbostic #endif
28966399Schristos 
29040444Sbostic 	(void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno);
29140444Sbostic 	if (type == PARSE_WARNING)
29240540Sbostic 		(void)fprintf(stderr, "warning: ");
29340444Sbostic 	(void)vfprintf(stderr, fmt, ap);
29440444Sbostic 	va_end(ap);
29540444Sbostic 	(void)fprintf(stderr, "\n");
29640444Sbostic 	(void)fflush(stderr);
29740444Sbostic 	if (type == PARSE_FATAL)
29840444Sbostic 		fatals += 1;
29940393Sbostic }
30040424Sbostic 
30140393Sbostic /*-
30240393Sbostic  *---------------------------------------------------------------------
30340393Sbostic  * ParseLinkSrc  --
30440393Sbostic  *	Link the parent node to its new child. Used in a Lst_ForEach by
30540393Sbostic  *	ParseDoDependency. If the specType isn't 'Not', the parent
30640393Sbostic  *	isn't linked as a parent of the child.
30740393Sbostic  *
30840393Sbostic  * Results:
30940393Sbostic  *	Always = 0
31040393Sbostic  *
31140393Sbostic  * Side Effects:
31240393Sbostic  *	New elements are added to the parents list of cgn and the
31340393Sbostic  *	children list of cgn. the unmade field of pgn is updated
31440393Sbostic  *	to reflect the additional child.
31540393Sbostic  *---------------------------------------------------------------------
31640393Sbostic  */
31740393Sbostic static int
318*69086Schristos ParseLinkSrc (pgnp, cgnp)
319*69086Schristos     ClientData     pgnp;	/* The parent node */
320*69086Schristos     ClientData     cgnp;	/* The child node */
32140393Sbostic {
322*69086Schristos     GNode          *pgn = (GNode *) pgnp;
323*69086Schristos     GNode          *cgn = (GNode *) cgnp;
32440393Sbostic     if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) {
32540393Sbostic 	(void)Lst_AtEnd (pgn->children, (ClientData)cgn);
32640393Sbostic 	if (specType == Not) {
32740393Sbostic 	    (void)Lst_AtEnd (cgn->parents, (ClientData)pgn);
32840393Sbostic 	}
32940393Sbostic 	pgn->unmade += 1;
33040393Sbostic     }
33140393Sbostic     return (0);
33240393Sbostic }
33340424Sbostic 
33440393Sbostic /*-
33540393Sbostic  *---------------------------------------------------------------------
33640393Sbostic  * ParseDoOp  --
33740393Sbostic  *	Apply the parsed operator to the given target node. Used in a
33840393Sbostic  *	Lst_ForEach call by ParseDoDependency once all targets have
33940393Sbostic  *	been found and their operator parsed. If the previous and new
34040393Sbostic  *	operators are incompatible, a major error is taken.
34140393Sbostic  *
34240393Sbostic  * Results:
34340393Sbostic  *	Always 0
34440393Sbostic  *
34540393Sbostic  * Side Effects:
34640393Sbostic  *	The type field of the node is altered to reflect any new bits in
34740393Sbostic  *	the op.
34840393Sbostic  *---------------------------------------------------------------------
34940393Sbostic  */
35040393Sbostic static int
351*69086Schristos ParseDoOp (gnp, opp)
352*69086Schristos     ClientData     gnp;		/* The node to which the operator is to be
35340393Sbostic 				 * applied */
354*69086Schristos     ClientData     opp;		/* The operator to apply */
35540393Sbostic {
356*69086Schristos     GNode          *gn = (GNode *) gnp;
357*69086Schristos     int             op = *(int *) opp;
35840393Sbostic     /*
35940393Sbostic      * If the dependency mask of the operator and the node don't match and
36040393Sbostic      * the node has actually had an operator applied to it before, and
36140393Sbostic      * the operator actually has some dependency information in it, complain.
36240393Sbostic      */
36340393Sbostic     if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
36440393Sbostic 	!OP_NOP(gn->type) && !OP_NOP(op))
36540393Sbostic     {
36640393Sbostic 	Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name);
36740393Sbostic 	return (1);
36840393Sbostic     }
36940393Sbostic 
37040393Sbostic     if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
37140393Sbostic 	/*
37240393Sbostic 	 * If the node was the object of a :: operator, we need to create a
37340393Sbostic 	 * new instance of it for the children and commands on this dependency
37440393Sbostic 	 * line. The new instance is placed on the 'cohorts' list of the
37540393Sbostic 	 * initial one (note the initial one is not on its own cohorts list)
37640393Sbostic 	 * and the new instance is linked to all parents of the initial
37740393Sbostic 	 * instance.
37840393Sbostic 	 */
37940393Sbostic 	register GNode	*cohort;
38040393Sbostic 	LstNode	    	ln;
38140393Sbostic 
38240393Sbostic 	cohort = Targ_NewGN(gn->name);
38340393Sbostic 	/*
38440393Sbostic 	 * Duplicate links to parents so graph traversal is simple. Perhaps
38540393Sbostic 	 * some type bits should be duplicated?
38640393Sbostic 	 *
38740393Sbostic 	 * Make the cohort invisible as well to avoid duplicating it into
38840393Sbostic 	 * other variables. True, parents of this target won't tend to do
38940393Sbostic 	 * anything with their local variables, but better safe than
39040393Sbostic 	 * sorry.
39140393Sbostic 	 */
39240393Sbostic 	Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort);
39340393Sbostic 	cohort->type = OP_DOUBLEDEP|OP_INVISIBLE;
39440393Sbostic 	(void)Lst_AtEnd(gn->cohorts, (ClientData)cohort);
39540393Sbostic 
39640393Sbostic 	/*
39740393Sbostic 	 * Replace the node in the targets list with the new copy
39840393Sbostic 	 */
39940393Sbostic 	ln = Lst_Member(targets, (ClientData)gn);
40040393Sbostic 	Lst_Replace(ln, (ClientData)cohort);
40140393Sbostic 	gn = cohort;
40240393Sbostic     }
40340393Sbostic     /*
40440393Sbostic      * We don't want to nuke any previous flags (whatever they were) so we
40540393Sbostic      * just OR the new operator into the old
40640393Sbostic      */
40740393Sbostic     gn->type |= op;
40840393Sbostic 
40940393Sbostic     return (0);
41040393Sbostic }
41140424Sbostic 
41240393Sbostic /*-
41340393Sbostic  *---------------------------------------------------------------------
41440393Sbostic  * ParseDoSrc  --
41540393Sbostic  *	Given the name of a source, figure out if it is an attribute
41640393Sbostic  *	and apply it to the targets if it is. Else decide if there is
41740393Sbostic  *	some attribute which should be applied *to* the source because
41840393Sbostic  *	of some special target and apply it if so. Otherwise, make the
41940393Sbostic  *	source be a child of the targets in the list 'targets'
42040393Sbostic  *
42140393Sbostic  * Results:
42240393Sbostic  *	None
42340393Sbostic  *
42440393Sbostic  * Side Effects:
42540393Sbostic  *	Operator bits may be added to the list of targets or to the source.
42640393Sbostic  *	The targets may have a new source added to their lists of children.
42740393Sbostic  *---------------------------------------------------------------------
42840393Sbostic  */
42940393Sbostic static void
43040393Sbostic ParseDoSrc (tOp, src)
43140393Sbostic     int		tOp;	/* operator (if any) from special targets */
43240393Sbostic     char	*src;	/* name of the source to handle */
43340393Sbostic {
43440393Sbostic     int		op;	/* operator (if any) from special source */
43540393Sbostic     GNode	*gn;
43640393Sbostic 
43740393Sbostic     op = 0;
43840393Sbostic     if (*src == '.' && isupper (src[1])) {
43940393Sbostic 	int keywd = ParseFindKeyword(src);
44040393Sbostic 	if (keywd != -1) {
44140393Sbostic 	    op = parseKeywords[keywd].op;
44240393Sbostic 	}
44340393Sbostic     }
44440393Sbostic     if (op != 0) {
445*69086Schristos 	Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
44640393Sbostic     } else if (specType == Main) {
44740393Sbostic 	/*
44840393Sbostic 	 * If we have noted the existence of a .MAIN, it means we need
44940393Sbostic 	 * to add the sources of said target to the list of things
45040393Sbostic 	 * to create. The string 'src' is likely to be free, so we
45140393Sbostic 	 * must make a new copy of it. Note that this will only be
45240393Sbostic 	 * invoked if the user didn't specify a target on the command
45340393Sbostic 	 * line. This is to allow #ifmake's to succeed, or something...
45440393Sbostic 	 */
45540424Sbostic 	(void) Lst_AtEnd (create, (ClientData)strdup(src));
45640393Sbostic 	/*
45740393Sbostic 	 * Add the name to the .TARGETS variable as well, so the user cna
45840393Sbostic 	 * employ that, if desired.
45940393Sbostic 	 */
46040393Sbostic 	Var_Append(".TARGETS", src, VAR_GLOBAL);
46140393Sbostic     } else if (specType == Order) {
46240393Sbostic 	/*
46340393Sbostic 	 * Create proper predecessor/successor links between the previous
46440393Sbostic 	 * source and the current one.
46540393Sbostic 	 */
46640393Sbostic 	gn = Targ_FindNode(src, TARG_CREATE);
46740393Sbostic 	if (predecessor != NILGNODE) {
46840393Sbostic 	    (void)Lst_AtEnd(predecessor->successors, (ClientData)gn);
46940393Sbostic 	    (void)Lst_AtEnd(gn->preds, (ClientData)predecessor);
47040393Sbostic 	}
47140393Sbostic 	/*
47240393Sbostic 	 * The current source now becomes the predecessor for the next one.
47340393Sbostic 	 */
47440393Sbostic 	predecessor = gn;
47540393Sbostic     } else {
47640393Sbostic 	/*
47740393Sbostic 	 * If the source is not an attribute, we need to find/create
47840393Sbostic 	 * a node for it. After that we can apply any operator to it
47940393Sbostic 	 * from a special target or link it to its parents, as
48040393Sbostic 	 * appropriate.
48140393Sbostic 	 *
48240393Sbostic 	 * In the case of a source that was the object of a :: operator,
48340393Sbostic 	 * the attribute is applied to all of its instances (as kept in
48440393Sbostic 	 * the 'cohorts' list of the node) or all the cohorts are linked
48540393Sbostic 	 * to all the targets.
48640393Sbostic 	 */
48740393Sbostic 	gn = Targ_FindNode (src, TARG_CREATE);
48840393Sbostic 	if (tOp) {
48940393Sbostic 	    gn->type |= tOp;
49040393Sbostic 	} else {
49140393Sbostic 	    Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn);
49240393Sbostic 	}
49340393Sbostic 	if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
49440393Sbostic 	    register GNode  	*cohort;
49540393Sbostic 	    register LstNode	ln;
49640393Sbostic 
49740393Sbostic 	    for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){
49840393Sbostic 		cohort = (GNode *)Lst_Datum(ln);
49940393Sbostic 		if (tOp) {
50040393Sbostic 		    cohort->type |= tOp;
50140393Sbostic 		} else {
50240393Sbostic 		    Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort);
50340393Sbostic 		}
50440393Sbostic 	    }
50540393Sbostic 	}
50640393Sbostic     }
50740393Sbostic }
50840424Sbostic 
50940393Sbostic /*-
51040393Sbostic  *-----------------------------------------------------------------------
51140393Sbostic  * ParseFindMain --
51240393Sbostic  *	Find a real target in the list and set it to be the main one.
51340393Sbostic  *	Called by ParseDoDependency when a main target hasn't been found
51440393Sbostic  *	yet.
51540393Sbostic  *
51640393Sbostic  * Results:
51740393Sbostic  *	0 if main not found yet, 1 if it is.
51840393Sbostic  *
51940393Sbostic  * Side Effects:
52040393Sbostic  *	mainNode is changed and Targ_SetMain is called.
52140393Sbostic  *
52240393Sbostic  *-----------------------------------------------------------------------
52340393Sbostic  */
52440393Sbostic static int
525*69086Schristos ParseFindMain(gnp, dummy)
526*69086Schristos     ClientData	  gnp;	    /* Node to examine */
527*69086Schristos     ClientData    dummy;
52840393Sbostic {
529*69086Schristos     GNode   	  *gn = (GNode *) gnp;
53040393Sbostic     if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) {
53140393Sbostic 	mainNode = gn;
53240393Sbostic 	Targ_SetMain(gn);
533*69086Schristos 	return (dummy ? 1 : 1);
53440393Sbostic     } else {
535*69086Schristos 	return (dummy ? 0 : 0);
53640393Sbostic     }
53740393Sbostic }
53840424Sbostic 
53940393Sbostic /*-
54040393Sbostic  *-----------------------------------------------------------------------
54140393Sbostic  * ParseAddDir --
54240393Sbostic  *	Front-end for Dir_AddDir to make sure Lst_ForEach keeps going
54340393Sbostic  *
54440393Sbostic  * Results:
54540393Sbostic  *	=== 0
54640393Sbostic  *
54740393Sbostic  * Side Effects:
54840393Sbostic  *	See Dir_AddDir.
54940393Sbostic  *
55040393Sbostic  *-----------------------------------------------------------------------
55140393Sbostic  */
55240393Sbostic static int
55340393Sbostic ParseAddDir(path, name)
554*69086Schristos     ClientData	  path;
555*69086Schristos     ClientData    name;
55640393Sbostic {
557*69086Schristos     Dir_AddDir((Lst) path, (char *) name);
55840393Sbostic     return(0);
55940393Sbostic }
56040424Sbostic 
56140393Sbostic /*-
56240393Sbostic  *-----------------------------------------------------------------------
56340393Sbostic  * ParseClearPath --
56440393Sbostic  *	Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going
56540393Sbostic  *
56640393Sbostic  * Results:
56740393Sbostic  *	=== 0
56840393Sbostic  *
56940393Sbostic  * Side Effects:
57040393Sbostic  *	See Dir_ClearPath
57140393Sbostic  *
57240393Sbostic  *-----------------------------------------------------------------------
57340393Sbostic  */
57440393Sbostic static int
575*69086Schristos ParseClearPath(path, dummy)
576*69086Schristos     ClientData path;
577*69086Schristos     ClientData dummy;
57840393Sbostic {
579*69086Schristos     Dir_ClearPath((Lst) path);
580*69086Schristos     return(dummy ? 0 : 0);
58140393Sbostic }
58240424Sbostic 
58340393Sbostic /*-
58440393Sbostic  *---------------------------------------------------------------------
58540393Sbostic  * ParseDoDependency  --
58640393Sbostic  *	Parse the dependency line in line.
58740393Sbostic  *
58840393Sbostic  * Results:
58940393Sbostic  *	None
59040393Sbostic  *
59140393Sbostic  * Side Effects:
59240393Sbostic  *	The nodes of the sources are linked as children to the nodes of the
59340393Sbostic  *	targets. Some nodes may be created.
59440393Sbostic  *
59540393Sbostic  *	We parse a dependency line by first extracting words from the line and
59640393Sbostic  * finding nodes in the list of all targets with that name. This is done
59740393Sbostic  * until a character is encountered which is an operator character. Currently
59840393Sbostic  * these are only ! and :. At this point the operator is parsed and the
59940393Sbostic  * pointer into the line advanced until the first source is encountered.
60040393Sbostic  * 	The parsed operator is applied to each node in the 'targets' list,
60140393Sbostic  * which is where the nodes found for the targets are kept, by means of
60240393Sbostic  * the ParseDoOp function.
60340393Sbostic  *	The sources are read in much the same way as the targets were except
60440393Sbostic  * that now they are expanded using the wildcarding scheme of the C-Shell
60540393Sbostic  * and all instances of the resulting words in the list of all targets
60640393Sbostic  * are found. Each of the resulting nodes is then linked to each of the
60740393Sbostic  * targets as one of its children.
60840393Sbostic  *	Certain targets are handled specially. These are the ones detailed
60940393Sbostic  * by the specType variable.
61040393Sbostic  *	The storing of transformation rules is also taken care of here.
61140393Sbostic  * A target is recognized as a transformation rule by calling
61240393Sbostic  * Suff_IsTransform. If it is a transformation rule, its node is gotten
61340393Sbostic  * from the suffix module via Suff_AddTransform rather than the standard
61440393Sbostic  * Targ_FindNode in the target module.
61540393Sbostic  *---------------------------------------------------------------------
61640393Sbostic  */
61740393Sbostic static void
61840393Sbostic ParseDoDependency (line)
61940393Sbostic     char           *line;	/* the line to parse */
62040393Sbostic {
621*69086Schristos     char  	   *cp;		/* our current position */
622*69086Schristos     GNode 	   *gn;		/* a general purpose temporary node */
623*69086Schristos     int             op;		/* the operator on the line */
62440393Sbostic     char            savec;	/* a place to save a character */
62540393Sbostic     Lst    	    paths;   	/* List of search paths to alter when parsing
62640393Sbostic 				 * a list of .PATH targets */
62740393Sbostic     int	    	    tOp;    	/* operator from special target */
62840393Sbostic     Lst	    	    sources;	/* list of source names after expansion */
62940393Sbostic     Lst 	    curTargs;	/* list of target names to be found and added
63040393Sbostic 				 * to the targets list */
63140393Sbostic 
63240393Sbostic     tOp = 0;
63340393Sbostic 
63440393Sbostic     specType = Not;
63540393Sbostic     paths = (Lst)NULL;
63640393Sbostic 
63740393Sbostic     curTargs = Lst_Init(FALSE);
63840393Sbostic 
63940393Sbostic     do {
64040393Sbostic 	for (cp = line;
64140393Sbostic 	     *cp && !isspace (*cp) &&
64240393Sbostic 	     (*cp != '!') && (*cp != ':') && (*cp != '(');
64340393Sbostic 	     cp++)
64440393Sbostic 	{
64540393Sbostic 	    if (*cp == '$') {
64640393Sbostic 		/*
64740393Sbostic 		 * Must be a dynamic source (would have been expanded
64840393Sbostic 		 * otherwise), so call the Var module to parse the puppy
64940393Sbostic 		 * so we can safely advance beyond it...There should be
65040393Sbostic 		 * no errors in this, as they would have been discovered
65140393Sbostic 		 * in the initial Var_Subst and we wouldn't be here.
65240393Sbostic 		 */
65340393Sbostic 		int 	length;
65440393Sbostic 		Boolean	freeIt;
65540393Sbostic 		char	*result;
65640393Sbostic 
65740393Sbostic 		result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);
65840393Sbostic 
65940393Sbostic 		if (freeIt) {
66040393Sbostic 		    free(result);
66140393Sbostic 		}
66240393Sbostic 		cp += length-1;
66340393Sbostic 	    }
66440393Sbostic 	    continue;
66540393Sbostic 	}
66640393Sbostic 	if (*cp == '(') {
66740393Sbostic 	    /*
66840393Sbostic 	     * Archives must be handled specially to make sure the OP_ARCHV
66940393Sbostic 	     * flag is set in their 'type' field, for one thing, and because
67040393Sbostic 	     * things like "archive(file1.o file2.o file3.o)" are permissible.
67140393Sbostic 	     * Arch_ParseArchive will set 'line' to be the first non-blank
67240393Sbostic 	     * after the archive-spec. It creates/finds nodes for the members
67340393Sbostic 	     * and places them on the given list, returning SUCCESS if all
67440393Sbostic 	     * went well and FAILURE if there was an error in the
67540393Sbostic 	     * specification. On error, line should remain untouched.
67640393Sbostic 	     */
67740393Sbostic 	    if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) {
67840393Sbostic 		Parse_Error (PARSE_FATAL,
67940393Sbostic 			     "Error in archive specification: \"%s\"", line);
68040393Sbostic 		return;
68140393Sbostic 	    } else {
68240393Sbostic 		continue;
68340393Sbostic 	    }
68440393Sbostic 	}
68540393Sbostic 	savec = *cp;
68640393Sbostic 
68740393Sbostic 	if (!*cp) {
68840393Sbostic 	    /*
68940393Sbostic 	     * Ending a dependency line without an operator is a Bozo
69040393Sbostic 	     * no-no
69140393Sbostic 	     */
69240393Sbostic 	    Parse_Error (PARSE_FATAL, "Need an operator");
69340393Sbostic 	    return;
69440393Sbostic 	}
69540393Sbostic 	*cp = '\0';
69640393Sbostic 	/*
69740393Sbostic 	 * Have a word in line. See if it's a special target and set
69840393Sbostic 	 * specType to match it.
69940393Sbostic 	 */
70040393Sbostic 	if (*line == '.' && isupper (line[1])) {
70140393Sbostic 	    /*
70240393Sbostic 	     * See if the target is a special target that must have it
70340393Sbostic 	     * or its sources handled specially.
70440393Sbostic 	     */
70540393Sbostic 	    int keywd = ParseFindKeyword(line);
70640393Sbostic 	    if (keywd != -1) {
70760285Sbostic 		if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {
70840393Sbostic 		    Parse_Error(PARSE_FATAL, "Mismatched special targets");
70940393Sbostic 		    return;
71040393Sbostic 		}
71140393Sbostic 
71240393Sbostic 		specType = parseKeywords[keywd].spec;
71340393Sbostic 		tOp = parseKeywords[keywd].op;
71440393Sbostic 
71540393Sbostic 		/*
71640393Sbostic 		 * Certain special targets have special semantics:
71740393Sbostic 		 *	.PATH		Have to set the dirSearchPath
71840393Sbostic 		 *			variable too
71940393Sbostic 		 *	.MAIN		Its sources are only used if
72040393Sbostic 		 *			nothing has been specified to
72140393Sbostic 		 *			create.
72240393Sbostic 		 *	.DEFAULT    	Need to create a node to hang
72340393Sbostic 		 *			commands on, but we don't want
72440393Sbostic 		 *			it in the graph, nor do we want
72540393Sbostic 		 *			it to be the Main Target, so we
72640393Sbostic 		 *			create it, set OP_NOTMAIN and
72740393Sbostic 		 *			add it to the list, setting
72840393Sbostic 		 *			DEFAULT to the new node for
72940393Sbostic 		 *			later use. We claim the node is
73040393Sbostic 		 *	    	    	A transformation rule to make
73140393Sbostic 		 *	    	    	life easier later, when we'll
73240393Sbostic 		 *	    	    	use Make_HandleUse to actually
73340393Sbostic 		 *	    	    	apply the .DEFAULT commands.
73440393Sbostic 		 *	.BEGIN
73540393Sbostic 		 *	.END
73640393Sbostic 		 *	.INTERRUPT  	Are not to be considered the
73740393Sbostic 		 *			main target.
73840393Sbostic 		 *  	.NOTPARALLEL	Make only one target at a time.
73940393Sbostic 		 *  	.SINGLESHELL	Create a shell for each command.
74040393Sbostic 		 *  	.ORDER	    	Must set initial predecessor to NIL
74140393Sbostic 		 */
74240393Sbostic 		switch (specType) {
74360285Sbostic 		    case ExPath:
74440393Sbostic 			if (paths == NULL) {
74540393Sbostic 			    paths = Lst_Init(FALSE);
74640393Sbostic 			}
74740393Sbostic 			(void)Lst_AtEnd(paths, (ClientData)dirSearchPath);
74840393Sbostic 			break;
74940393Sbostic 		    case Main:
75040393Sbostic 			if (!Lst_IsEmpty(create)) {
75140393Sbostic 			    specType = Not;
75240393Sbostic 			}
75340393Sbostic 			break;
75440393Sbostic 		    case Begin:
75540393Sbostic 		    case End:
75640393Sbostic 		    case Interrupt:
75740393Sbostic 			gn = Targ_FindNode(line, TARG_CREATE);
75840393Sbostic 			gn->type |= OP_NOTMAIN;
75940393Sbostic 			(void)Lst_AtEnd(targets, (ClientData)gn);
76040393Sbostic 			break;
76140393Sbostic 		    case Default:
76240393Sbostic 			gn = Targ_NewGN(".DEFAULT");
76340393Sbostic 			gn->type |= (OP_NOTMAIN|OP_TRANSFORM);
76440393Sbostic 			(void)Lst_AtEnd(targets, (ClientData)gn);
76540393Sbostic 			DEFAULT = gn;
76640393Sbostic 			break;
76740393Sbostic 		    case NotParallel:
76840393Sbostic 		    {
76940393Sbostic 			extern int  maxJobs;
77040393Sbostic 
77140393Sbostic 			maxJobs = 1;
77240393Sbostic 			break;
77340393Sbostic 		    }
77440393Sbostic 		    case SingleShell:
77560285Sbostic 			compatMake = 1;
77640393Sbostic 			break;
77740393Sbostic 		    case Order:
77840393Sbostic 			predecessor = NILGNODE;
77940393Sbostic 			break;
78060285Sbostic 		    default:
78160285Sbostic 			break;
78240393Sbostic 		}
78340393Sbostic 	    } else if (strncmp (line, ".PATH", 5) == 0) {
78440393Sbostic 		/*
78540393Sbostic 		 * .PATH<suffix> has to be handled specially.
78640393Sbostic 		 * Call on the suffix module to give us a path to
78740393Sbostic 		 * modify.
78840393Sbostic 		 */
78940393Sbostic 		Lst 	path;
79040393Sbostic 
79160285Sbostic 		specType = ExPath;
79240393Sbostic 		path = Suff_GetPath (&line[5]);
79340393Sbostic 		if (path == NILLST) {
79440393Sbostic 		    Parse_Error (PARSE_FATAL,
79540393Sbostic 				 "Suffix '%s' not defined (yet)",
79640393Sbostic 				 &line[5]);
79740393Sbostic 		    return;
79840393Sbostic 		} else {
79940393Sbostic 		    if (paths == (Lst)NULL) {
80040393Sbostic 			paths = Lst_Init(FALSE);
80140393Sbostic 		    }
80240393Sbostic 		    (void)Lst_AtEnd(paths, (ClientData)path);
80340393Sbostic 		}
80440393Sbostic 	    }
80540393Sbostic 	}
80640393Sbostic 
80740393Sbostic 	/*
80840393Sbostic 	 * Have word in line. Get or create its node and stick it at
80940393Sbostic 	 * the end of the targets list
81040393Sbostic 	 */
81140393Sbostic 	if ((specType == Not) && (*line != '\0')) {
81240393Sbostic 	    if (Dir_HasWildcards(line)) {
81340393Sbostic 		/*
81440393Sbostic 		 * Targets are to be sought only in the current directory,
81540393Sbostic 		 * so create an empty path for the thing. Note we need to
81640393Sbostic 		 * use Dir_Destroy in the destruction of the path as the
81740393Sbostic 		 * Dir module could have added a directory to the path...
81840393Sbostic 		 */
81940393Sbostic 		Lst	    emptyPath = Lst_Init(FALSE);
82040393Sbostic 
82140393Sbostic 		Dir_Expand(line, emptyPath, curTargs);
82240393Sbostic 
82340393Sbostic 		Lst_Destroy(emptyPath, Dir_Destroy);
82440393Sbostic 	    } else {
82540393Sbostic 		/*
82640393Sbostic 		 * No wildcards, but we want to avoid code duplication,
82740393Sbostic 		 * so create a list with the word on it.
82840393Sbostic 		 */
82940393Sbostic 		(void)Lst_AtEnd(curTargs, (ClientData)line);
83040393Sbostic 	    }
83140393Sbostic 
83240393Sbostic 	    while(!Lst_IsEmpty(curTargs)) {
83340393Sbostic 		char	*targName = (char *)Lst_DeQueue(curTargs);
83440393Sbostic 
83540393Sbostic 		if (!Suff_IsTransform (targName)) {
83640393Sbostic 		    gn = Targ_FindNode (targName, TARG_CREATE);
83740393Sbostic 		} else {
83840393Sbostic 		    gn = Suff_AddTransform (targName);
83940393Sbostic 		}
84040393Sbostic 
84140393Sbostic 		(void)Lst_AtEnd (targets, (ClientData)gn);
84240393Sbostic 	    }
84360285Sbostic 	} else if (specType == ExPath && *line != '.' && *line != '\0') {
84440393Sbostic 	    Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
84540393Sbostic 	}
84640393Sbostic 
84740393Sbostic 	*cp = savec;
84840393Sbostic 	/*
84940393Sbostic 	 * If it is a special type and not .PATH, it's the only target we
85040393Sbostic 	 * allow on this line...
85140393Sbostic 	 */
85260285Sbostic 	if (specType != Not && specType != ExPath) {
85340393Sbostic 	    Boolean warn = FALSE;
85440393Sbostic 
85540393Sbostic 	    while ((*cp != '!') && (*cp != ':') && *cp) {
85640393Sbostic 		if (*cp != ' ' && *cp != '\t') {
85740393Sbostic 		    warn = TRUE;
85840393Sbostic 		}
85940393Sbostic 		cp++;
86040393Sbostic 	    }
86140393Sbostic 	    if (warn) {
86240393Sbostic 		Parse_Error(PARSE_WARNING, "Extra target ignored");
86340393Sbostic 	    }
86440393Sbostic 	} else {
86540393Sbostic 	    while (*cp && isspace (*cp)) {
86640393Sbostic 		cp++;
86740393Sbostic 	    }
86840393Sbostic 	}
86940393Sbostic 	line = cp;
87040393Sbostic     } while ((*line != '!') && (*line != ':') && *line);
87140393Sbostic 
87240393Sbostic     /*
87340393Sbostic      * Don't need the list of target names anymore...
87440393Sbostic      */
87540393Sbostic     Lst_Destroy(curTargs, NOFREE);
87640393Sbostic 
87740393Sbostic     if (!Lst_IsEmpty(targets)) {
87840393Sbostic 	switch(specType) {
87940393Sbostic 	    default:
88040393Sbostic 		Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");
88140393Sbostic 		break;
88240393Sbostic 	    case Default:
88340393Sbostic 	    case Begin:
88440393Sbostic 	    case End:
88540393Sbostic 	    case Interrupt:
88640393Sbostic 		/*
88740393Sbostic 		 * These four create nodes on which to hang commands, so
88840393Sbostic 		 * targets shouldn't be empty...
88940393Sbostic 		 */
89040393Sbostic 	    case Not:
89140393Sbostic 		/*
89240393Sbostic 		 * Nothing special here -- targets can be empty if it wants.
89340393Sbostic 		 */
89440393Sbostic 		break;
89540393Sbostic 	}
89640393Sbostic     }
89740393Sbostic 
89840393Sbostic     /*
89940393Sbostic      * Have now parsed all the target names. Must parse the operator next. The
90040393Sbostic      * result is left in  op .
90140393Sbostic      */
90240393Sbostic     if (*cp == '!') {
90340393Sbostic 	op = OP_FORCE;
90440393Sbostic     } else if (*cp == ':') {
90540393Sbostic 	if (cp[1] == ':') {
90640393Sbostic 	    op = OP_DOUBLEDEP;
90740393Sbostic 	    cp++;
90840393Sbostic 	} else {
90940393Sbostic 	    op = OP_DEPENDS;
91040393Sbostic 	}
91140393Sbostic     } else {
91240393Sbostic 	Parse_Error (PARSE_FATAL, "Missing dependency operator");
91340393Sbostic 	return;
91440393Sbostic     }
91540393Sbostic 
91640393Sbostic     cp++;			/* Advance beyond operator */
91740393Sbostic 
918*69086Schristos     Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
91940393Sbostic 
92040393Sbostic     /*
92140393Sbostic      * Get to the first source
92240393Sbostic      */
92340393Sbostic     while (*cp && isspace (*cp)) {
92440393Sbostic 	cp++;
92540393Sbostic     }
92640393Sbostic     line = cp;
92740393Sbostic 
92840393Sbostic     /*
92940393Sbostic      * Several special targets take different actions if present with no
93040393Sbostic      * sources:
93140393Sbostic      *	a .SUFFIXES line with no sources clears out all old suffixes
93240393Sbostic      *	a .PRECIOUS line makes all targets precious
93340393Sbostic      *	a .IGNORE line ignores errors for all targets
93440393Sbostic      *	a .SILENT line creates silence when making all targets
93540393Sbostic      *	a .PATH removes all directories from the search path(s).
93640393Sbostic      */
93740393Sbostic     if (!*line) {
93840393Sbostic 	switch (specType) {
93940393Sbostic 	    case Suffixes:
94040393Sbostic 		Suff_ClearSuffixes ();
94140393Sbostic 		break;
94240393Sbostic 	    case Precious:
94340393Sbostic 		allPrecious = TRUE;
94440393Sbostic 		break;
94540393Sbostic 	    case Ignore:
94640393Sbostic 		ignoreErrors = TRUE;
94740393Sbostic 		break;
94840393Sbostic 	    case Silent:
94940393Sbostic 		beSilent = TRUE;
95040393Sbostic 		break;
95160285Sbostic 	    case ExPath:
95240393Sbostic 		Lst_ForEach(paths, ParseClearPath, (ClientData)NULL);
95340393Sbostic 		break;
95460285Sbostic 	    default:
95560285Sbostic 		break;
95640393Sbostic 	}
95740393Sbostic     } else if (specType == MFlags) {
95840393Sbostic 	/*
95940393Sbostic 	 * Call on functions in main.c to deal with these arguments and
96040393Sbostic 	 * set the initial character to a null-character so the loop to
96140393Sbostic 	 * get sources won't get anything
96240393Sbostic 	 */
96340393Sbostic 	Main_ParseArgLine (line);
96440393Sbostic 	*line = '\0';
96560285Sbostic     } else if (specType == ExShell) {
96640393Sbostic 	if (Job_ParseShell (line) != SUCCESS) {
96740393Sbostic 	    Parse_Error (PARSE_FATAL, "improper shell specification");
96840393Sbostic 	    return;
96940393Sbostic 	}
97040393Sbostic 	*line = '\0';
97140393Sbostic     } else if ((specType == NotParallel) || (specType == SingleShell)) {
97240393Sbostic 	*line = '\0';
97340393Sbostic     }
97440393Sbostic 
97540393Sbostic     /*
97640393Sbostic      * NOW GO FOR THE SOURCES
97740393Sbostic      */
97860285Sbostic     if ((specType == Suffixes) || (specType == ExPath) ||
97940393Sbostic 	(specType == Includes) || (specType == Libs) ||
98040439Sbostic 	(specType == Null))
98140393Sbostic     {
98240393Sbostic 	while (*line) {
98340393Sbostic 	    /*
98440393Sbostic 	     * If the target was one that doesn't take files as its sources
98540393Sbostic 	     * but takes something like suffixes, we take each
98640393Sbostic 	     * space-separated word on the line as a something and deal
98740393Sbostic 	     * with it accordingly.
98840393Sbostic 	     *
98940393Sbostic 	     * If the target was .SUFFIXES, we take each source as a
99040393Sbostic 	     * suffix and add it to the list of suffixes maintained by the
99140393Sbostic 	     * Suff module.
99240393Sbostic 	     *
99340393Sbostic 	     * If the target was a .PATH, we add the source as a directory
99440393Sbostic 	     * to search on the search path.
99540393Sbostic 	     *
99640393Sbostic 	     * If it was .INCLUDES, the source is taken to be the suffix of
99740393Sbostic 	     * files which will be #included and whose search path should
99840393Sbostic 	     * be present in the .INCLUDES variable.
99940393Sbostic 	     *
100040393Sbostic 	     * If it was .LIBS, the source is taken to be the suffix of
100140393Sbostic 	     * files which are considered libraries and whose search path
100240393Sbostic 	     * should be present in the .LIBS variable.
100340393Sbostic 	     *
100440393Sbostic 	     * If it was .NULL, the source is the suffix to use when a file
100540393Sbostic 	     * has no valid suffix.
100640393Sbostic 	     */
100740393Sbostic 	    char  savec;
100840393Sbostic 	    while (*cp && !isspace (*cp)) {
100940393Sbostic 		cp++;
101040393Sbostic 	    }
101140393Sbostic 	    savec = *cp;
101240393Sbostic 	    *cp = '\0';
101340393Sbostic 	    switch (specType) {
101440393Sbostic 		case Suffixes:
101540393Sbostic 		    Suff_AddSuffix (line);
101640393Sbostic 		    break;
101760285Sbostic 		case ExPath:
101840393Sbostic 		    Lst_ForEach(paths, ParseAddDir, (ClientData)line);
101940393Sbostic 		    break;
102040393Sbostic 		case Includes:
102140393Sbostic 		    Suff_AddInclude (line);
102240393Sbostic 		    break;
102340393Sbostic 		case Libs:
102440393Sbostic 		    Suff_AddLib (line);
102540393Sbostic 		    break;
102640393Sbostic 		case Null:
102740393Sbostic 		    Suff_SetNull (line);
102840393Sbostic 		    break;
102960285Sbostic 		default:
103060285Sbostic 		    break;
103140393Sbostic 	    }
103240393Sbostic 	    *cp = savec;
103340393Sbostic 	    if (savec != '\0') {
103440393Sbostic 		cp++;
103540393Sbostic 	    }
103640393Sbostic 	    while (*cp && isspace (*cp)) {
103740393Sbostic 		cp++;
103840393Sbostic 	    }
103940393Sbostic 	    line = cp;
104040393Sbostic 	}
104140393Sbostic 	if (paths) {
104240393Sbostic 	    Lst_Destroy(paths, NOFREE);
104340393Sbostic 	}
104440393Sbostic     } else {
104540393Sbostic 	while (*line) {
104640393Sbostic 	    /*
104740393Sbostic 	     * The targets take real sources, so we must beware of archive
104840393Sbostic 	     * specifications (i.e. things with left parentheses in them)
104940393Sbostic 	     * and handle them accordingly.
105040393Sbostic 	     */
105140393Sbostic 	    while (*cp && !isspace (*cp)) {
105240393Sbostic 		if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) {
105340393Sbostic 		    /*
105440393Sbostic 		     * Only stop for a left parenthesis if it isn't at the
105540393Sbostic 		     * start of a word (that'll be for variable changes
105640393Sbostic 		     * later) and isn't preceded by a dollar sign (a dynamic
105740393Sbostic 		     * source).
105840393Sbostic 		     */
105940393Sbostic 		    break;
106040393Sbostic 		} else {
106140393Sbostic 		    cp++;
106240393Sbostic 		}
106340393Sbostic 	    }
106440393Sbostic 
106540393Sbostic 	    if (*cp == '(') {
106640393Sbostic 		GNode	  *gn;
106740393Sbostic 
106840393Sbostic 		sources = Lst_Init (FALSE);
106940393Sbostic 		if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) {
107040393Sbostic 		    Parse_Error (PARSE_FATAL,
107140393Sbostic 				 "Error in source archive spec \"%s\"", line);
107240393Sbostic 		    return;
107340393Sbostic 		}
107440393Sbostic 
107540393Sbostic 		while (!Lst_IsEmpty (sources)) {
107640393Sbostic 		    gn = (GNode *) Lst_DeQueue (sources);
107740393Sbostic 		    ParseDoSrc (tOp, gn->name);
107840393Sbostic 		}
107940393Sbostic 		Lst_Destroy (sources, NOFREE);
108040393Sbostic 		cp = line;
108140393Sbostic 	    } else {
108240393Sbostic 		if (*cp) {
108340393Sbostic 		    *cp = '\0';
108440393Sbostic 		    cp += 1;
108540393Sbostic 		}
108640393Sbostic 
108740393Sbostic 		ParseDoSrc (tOp, line);
108840393Sbostic 	    }
108940393Sbostic 	    while (*cp && isspace (*cp)) {
109040393Sbostic 		cp++;
109140393Sbostic 	    }
109240393Sbostic 	    line = cp;
109340393Sbostic 	}
109440393Sbostic     }
109540393Sbostic 
109640393Sbostic     if (mainNode == NILGNODE) {
109740393Sbostic 	/*
109840393Sbostic 	 * If we have yet to decide on a main target to make, in the
109940393Sbostic 	 * absence of any user input, we want the first target on
110040393Sbostic 	 * the first dependency line that is actually a real target
110140393Sbostic 	 * (i.e. isn't a .USE or .EXEC rule) to be made.
110240393Sbostic 	 */
110340393Sbostic 	Lst_ForEach (targets, ParseFindMain, (ClientData)0);
110440393Sbostic     }
110540393Sbostic 
110640393Sbostic }
110740424Sbostic 
110840393Sbostic /*-
110940393Sbostic  *---------------------------------------------------------------------
111040393Sbostic  * Parse_IsVar  --
111140393Sbostic  *	Return TRUE if the passed line is a variable assignment. A variable
111240393Sbostic  *	assignment consists of a single word followed by optional whitespace
111340393Sbostic  *	followed by either a += or an = operator.
111440393Sbostic  *	This function is used both by the Parse_File function and main when
111540393Sbostic  *	parsing the command-line arguments.
111640393Sbostic  *
111740393Sbostic  * Results:
111840393Sbostic  *	TRUE if it is. FALSE if it ain't
111940393Sbostic  *
112040393Sbostic  * Side Effects:
112140393Sbostic  *	none
112240393Sbostic  *---------------------------------------------------------------------
112340393Sbostic  */
112440393Sbostic Boolean
112540393Sbostic Parse_IsVar (line)
112640393Sbostic     register char  *line;	/* the line to check */
112740393Sbostic {
112840393Sbostic     register Boolean wasSpace = FALSE;	/* set TRUE if found a space */
112940393Sbostic     register Boolean haveName = FALSE;	/* Set TRUE if have a variable name */
113040393Sbostic 
113140393Sbostic     /*
113240393Sbostic      * Skip to variable name
113340393Sbostic      */
113440393Sbostic     while ((*line == ' ') || (*line == '\t')) {
113540393Sbostic 	line++;
113640393Sbostic     }
113740393Sbostic 
113840393Sbostic     while (*line != '=') {
113940393Sbostic 	if (*line == '\0') {
114040393Sbostic 	    /*
114140393Sbostic 	     * end-of-line -- can't be a variable assignment.
114240393Sbostic 	     */
114340393Sbostic 	    return (FALSE);
114440393Sbostic 	} else if ((*line == ' ') || (*line == '\t')) {
114540393Sbostic 	    /*
114640393Sbostic 	     * there can be as much white space as desired so long as there is
114740393Sbostic 	     * only one word before the operator
114840393Sbostic 	     */
114940393Sbostic 	    wasSpace = TRUE;
115040393Sbostic 	} else if (wasSpace && haveName) {
115140393Sbostic 	    /*
115240393Sbostic 	     * Stop when an = operator is found.
115340393Sbostic 	     */
115440393Sbostic 	    if ((*line == '+') || (*line == ':') || (*line == '?') ||
115540393Sbostic 		(*line == '!')) {
115640393Sbostic 		break;
115740393Sbostic 	    }
115840393Sbostic 
115940393Sbostic 	    /*
116040393Sbostic 	     * This is the start of another word, so not assignment.
116140393Sbostic 	     */
116240393Sbostic 	    return (FALSE);
116340393Sbostic 	} else {
116440393Sbostic 	    haveName = TRUE;
116540393Sbostic 	    wasSpace = FALSE;
116640393Sbostic 	}
116740393Sbostic 	line++;
116840393Sbostic     }
116940393Sbostic 
117040393Sbostic     /*
117140393Sbostic      * A final check: if we stopped on a +, ?, ! or :, the next character must
117240393Sbostic      * be an = or it ain't a valid assignment
117340393Sbostic      */
117440393Sbostic     if (((*line == '+') ||
117540393Sbostic 	 (*line == '?') ||
117640393Sbostic 	 (*line == ':') ||
117740393Sbostic 	 (*line == '!')) &&
117840393Sbostic 	(line[1] != '='))
117940393Sbostic     {
118040393Sbostic 	return (FALSE);
118140393Sbostic     } else {
118240393Sbostic 	return (haveName);
118340393Sbostic     }
118440393Sbostic }
118540424Sbostic 
118640393Sbostic /*-
118740393Sbostic  *---------------------------------------------------------------------
118840393Sbostic  * Parse_DoVar  --
118940393Sbostic  *	Take the variable assignment in the passed line and do it in the
119040393Sbostic  *	global context.
119140393Sbostic  *
119240393Sbostic  *	Note: There is a lexical ambiguity with assignment modifier characters
119340393Sbostic  *	in variable names. This routine interprets the character before the =
119440393Sbostic  *	as a modifier. Therefore, an assignment like
119540393Sbostic  *	    C++=/usr/bin/CC
119640393Sbostic  *	is interpreted as "C+ +=" instead of "C++ =".
119740393Sbostic  *
119840393Sbostic  * Results:
119940393Sbostic  *	none
120040393Sbostic  *
120140393Sbostic  * Side Effects:
120240393Sbostic  *	the variable structure of the given variable name is altered in the
120340393Sbostic  *	global context.
120440393Sbostic  *---------------------------------------------------------------------
120540393Sbostic  */
120640393Sbostic void
120740393Sbostic Parse_DoVar (line, ctxt)
120840393Sbostic     char            *line;	/* a line guaranteed to be a variable
120940393Sbostic 				 * assignment. This reduces error checks */
121040393Sbostic     GNode   	    *ctxt;    	/* Context in which to do the assignment */
121140393Sbostic {
1212*69086Schristos     char	   *cp;	/* pointer into line */
121340393Sbostic     enum {
121440393Sbostic 	VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL
121540393Sbostic     }	    	    type;   	/* Type of assignment */
121640393Sbostic     char            *opc;	/* ptr to operator character to
121740393Sbostic 				 * null-terminate the variable name */
1218*69086Schristos     /*
121966399Schristos      * Avoid clobbered variable warnings by forcing the compiler
122066399Schristos      * to ``unregister'' variables
1221*69086Schristos      */
122266399Schristos #if __GNUC__
1223*69086Schristos     (void) &cp;
1224*69086Schristos     (void) &line;
1225*69086Schristos #endif
122640393Sbostic 
122740393Sbostic     /*
122840393Sbostic      * Skip to variable name
122940393Sbostic      */
123040393Sbostic     while ((*line == ' ') || (*line == '\t')) {
123140393Sbostic 	line++;
123240393Sbostic     }
123340393Sbostic 
123440393Sbostic     /*
123540393Sbostic      * Skip to operator character, nulling out whitespace as we go
123640393Sbostic      */
123740393Sbostic     for (cp = line + 1; *cp != '='; cp++) {
123840393Sbostic 	if (isspace (*cp)) {
123940393Sbostic 	    *cp = '\0';
124040393Sbostic 	}
124140393Sbostic     }
124240393Sbostic     opc = cp-1;		/* operator is the previous character */
124340393Sbostic     *cp++ = '\0';	/* nuke the = */
124440393Sbostic 
124540393Sbostic     /*
124640393Sbostic      * Check operator type
124740393Sbostic      */
124840393Sbostic     switch (*opc) {
124940393Sbostic 	case '+':
125040393Sbostic 	    type = VAR_APPEND;
125140393Sbostic 	    *opc = '\0';
125240393Sbostic 	    break;
125340393Sbostic 
125440393Sbostic 	case '?':
125540393Sbostic 	    /*
125640393Sbostic 	     * If the variable already has a value, we don't do anything.
125740393Sbostic 	     */
125840393Sbostic 	    *opc = '\0';
125940393Sbostic 	    if (Var_Exists(line, ctxt)) {
126040393Sbostic 		return;
126140393Sbostic 	    } else {
126240393Sbostic 		type = VAR_NORMAL;
126340393Sbostic 	    }
126440393Sbostic 	    break;
126540393Sbostic 
126640393Sbostic 	case ':':
126740393Sbostic 	    type = VAR_SUBST;
126840393Sbostic 	    *opc = '\0';
126940393Sbostic 	    break;
127040393Sbostic 
127140393Sbostic 	case '!':
127240393Sbostic 	    type = VAR_SHELL;
127340393Sbostic 	    *opc = '\0';
127440393Sbostic 	    break;
127540393Sbostic 
127640393Sbostic 	default:
127740393Sbostic 	    type = VAR_NORMAL;
127840393Sbostic 	    break;
127940393Sbostic     }
128040393Sbostic 
128140393Sbostic     while (isspace (*cp)) {
128240393Sbostic 	cp++;
128340393Sbostic     }
128440393Sbostic 
128540393Sbostic     if (type == VAR_APPEND) {
128640393Sbostic 	Var_Append (line, cp, ctxt);
128740393Sbostic     } else if (type == VAR_SUBST) {
128840393Sbostic 	/*
128940393Sbostic 	 * Allow variables in the old value to be undefined, but leave their
129040393Sbostic 	 * invocation alone -- this is done by forcing oldVars to be false.
129140393Sbostic 	 * XXX: This can cause recursive variables, but that's not hard to do,
129240393Sbostic 	 * and this allows someone to do something like
129340393Sbostic 	 *
129440393Sbostic 	 *  CFLAGS = $(.INCLUDES)
129540393Sbostic 	 *  CFLAGS := -I.. $(CFLAGS)
129640393Sbostic 	 *
129740393Sbostic 	 * And not get an error.
129840393Sbostic 	 */
129940393Sbostic 	Boolean	  oldOldVars = oldVars;
130040393Sbostic 
130140393Sbostic 	oldVars = FALSE;
130260285Sbostic 	cp = Var_Subst(NULL, cp, ctxt, FALSE);
130340393Sbostic 	oldVars = oldOldVars;
130440393Sbostic 
130540393Sbostic 	Var_Set(line, cp, ctxt);
130640393Sbostic 	free(cp);
130740393Sbostic     } else if (type == VAR_SHELL) {
130840393Sbostic 	char	*args[4];   	/* Args for invoking the shell */
130940393Sbostic 	int 	fds[2];	    	/* Pipe streams */
131040393Sbostic 	int 	cpid;	    	/* Child PID */
131140393Sbostic 	int 	pid;	    	/* PID from wait() */
131240393Sbostic 	Boolean	freeCmd;    	/* TRUE if the command needs to be freed, i.e.
131340393Sbostic 				 * if any variable expansion was performed */
131440393Sbostic 
1315*69086Schristos 	/*
131666399Schristos 	 * Avoid clobbered variable warnings by forcing the compiler
131766399Schristos 	 * to ``unregister'' variables
1318*69086Schristos 	 */
131966399Schristos #if __GNUC__
132066399Schristos 	(void) &freeCmd;
1321*69086Schristos #endif
1322*69086Schristos 
132340393Sbostic 	/*
132440393Sbostic 	 * Set up arguments for shell
132540393Sbostic 	 */
132640393Sbostic 	args[0] = "sh";
132740393Sbostic 	args[1] = "-c";
132860285Sbostic 	if (strchr(cp, '$') != (char *)NULL) {
132940393Sbostic 	    /*
133040393Sbostic 	     * There's a dollar sign in the command, so perform variable
133140393Sbostic 	     * expansion on the whole thing. The resulting string will need
133240393Sbostic 	     * freeing when we're done, so set freeCmd to TRUE.
133340393Sbostic 	     */
133460285Sbostic 	    args[2] = Var_Subst(NULL, cp, VAR_CMD, TRUE);
133540393Sbostic 	    freeCmd = TRUE;
133640393Sbostic 	} else {
133740393Sbostic 	    args[2] = cp;
133840393Sbostic 	    freeCmd = FALSE;
133940393Sbostic 	}
134040393Sbostic 	args[3] = (char *)NULL;
134140393Sbostic 
134240393Sbostic 	/*
134340393Sbostic 	 * Open a pipe for fetching its output
134440393Sbostic 	 */
134540393Sbostic 	pipe(fds);
134640393Sbostic 
134740393Sbostic 	/*
134840393Sbostic 	 * Fork
134940393Sbostic 	 */
135040393Sbostic 	cpid = vfork();
135140393Sbostic 	if (cpid == 0) {
135240393Sbostic 	    /*
135340393Sbostic 	     * Close input side of pipe
135440393Sbostic 	     */
135540393Sbostic 	    close(fds[0]);
135640393Sbostic 
135740393Sbostic 	    /*
135840393Sbostic 	     * Duplicate the output stream to the shell's output, then
135940393Sbostic 	     * shut the extra thing down. Note we don't fetch the error
136040393Sbostic 	     * stream...why not? Why?
136140393Sbostic 	     */
136240393Sbostic 	    dup2(fds[1], 1);
136340393Sbostic 	    close(fds[1]);
136440393Sbostic 
136540393Sbostic 	    execv("/bin/sh", args);
136640393Sbostic 	    _exit(1);
136740393Sbostic 	} else if (cpid < 0) {
136840393Sbostic 	    /*
136940393Sbostic 	     * Couldn't fork -- tell the user and make the variable null
137040393Sbostic 	     */
137140393Sbostic 	    Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp);
137240393Sbostic 	    Var_Set(line, "", ctxt);
137340393Sbostic 	} else {
137440393Sbostic 	    int	status;
137540393Sbostic 	    int cc;
137660285Sbostic 	    Buffer buf;
137760285Sbostic 	    char *res;
137840393Sbostic 
137940393Sbostic 	    /*
138040393Sbostic 	     * No need for the writing half
138140393Sbostic 	     */
138240393Sbostic 	    close(fds[1]);
138340393Sbostic 
138460285Sbostic 	    buf = Buf_Init (MAKE_BSIZE);
138560285Sbostic 
138660285Sbostic 	    do {
138760285Sbostic 		char   result[BUFSIZ];
138860285Sbostic 		cc = read(fds[0], result, sizeof(result));
138960285Sbostic 		if (cc > 0)
1390*69086Schristos 		    Buf_AddBytes(buf, cc, (Byte *) result);
139160285Sbostic 	    }
139260285Sbostic 	    while (cc > 0 || (cc == -1 && errno == EINTR));
139360285Sbostic 
139440393Sbostic 	    /*
139560285Sbostic 	     * Close the input side of the pipe.
139640393Sbostic 	     */
139760285Sbostic 	    close(fds[0]);
139840393Sbostic 
139940393Sbostic 	    /*
140060285Sbostic 	     * Wait for the process to exit.
140140393Sbostic 	     */
140260285Sbostic 	    while(((pid = wait(&status)) != cpid) && (pid >= 0))
140360285Sbostic 		continue;
140440393Sbostic 
140560285Sbostic 	    res = (char *)Buf_GetAll (buf, &cc);
140660285Sbostic 	    Buf_Destroy (buf, FALSE);
140760285Sbostic 
140860285Sbostic 	    if (cc == 0) {
140940393Sbostic 		/*
141040393Sbostic 		 * Couldn't read the child's output -- tell the user and
141140393Sbostic 		 * set the variable to null
141240393Sbostic 		 */
141340393Sbostic 		Parse_Error(PARSE_WARNING, "Couldn't read shell's output");
141440393Sbostic 	    }
141540393Sbostic 
141640393Sbostic 	    if (status) {
141740393Sbostic 		/*
141840393Sbostic 		 * Child returned an error -- tell the user but still use
141940393Sbostic 		 * the result.
142040393Sbostic 		 */
142140393Sbostic 		Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp);
142240393Sbostic 	    }
142360285Sbostic 
142440393Sbostic 	    /*
142540393Sbostic 	     * Null-terminate the result, convert newlines to spaces and
142640393Sbostic 	     * install it in the variable.
142740393Sbostic 	     */
142860285Sbostic 	    res[cc] = '\0';
142960285Sbostic 	    cp = &res[cc] - 1;
143040393Sbostic 
143140393Sbostic 	    if (*cp == '\n') {
143240393Sbostic 		/*
143340393Sbostic 		 * A final newline is just stripped
143440393Sbostic 		 */
143540393Sbostic 		*cp-- = '\0';
143640393Sbostic 	    }
143760285Sbostic 	    while (cp >= res) {
143840393Sbostic 		if (*cp == '\n') {
143940393Sbostic 		    *cp = ' ';
144040393Sbostic 		}
144140393Sbostic 		cp--;
144240393Sbostic 	    }
144360285Sbostic 	    Var_Set(line, res, ctxt);
144460285Sbostic 	    free(res);
144540393Sbostic 
144640393Sbostic 	}
144740393Sbostic 	if (freeCmd) {
144840393Sbostic 	    free(args[2]);
144940393Sbostic 	}
145040393Sbostic     } else {
145140393Sbostic 	/*
145240393Sbostic 	 * Normal assignment -- just do it.
145340393Sbostic 	 */
145440393Sbostic 	Var_Set (line, cp, ctxt);
145540393Sbostic     }
145640393Sbostic }
145740424Sbostic 
145840393Sbostic /*-
145940393Sbostic  * ParseAddCmd  --
146040393Sbostic  *	Lst_ForEach function to add a command line to all targets
146140393Sbostic  *
146240393Sbostic  * Results:
146340393Sbostic  *	Always 0
146440393Sbostic  *
146540393Sbostic  * Side Effects:
146640393Sbostic  *	A new element is added to the commands list of the node.
146740393Sbostic  */
146860285Sbostic static int
1469*69086Schristos ParseAddCmd(gnp, cmd)
1470*69086Schristos     ClientData gnp;	/* the node to which the command is to be added */
1471*69086Schristos     ClientData cmd;	/* the command to add */
147240393Sbostic {
1473*69086Schristos     GNode *gn = (GNode *) gnp;
1474*69086Schristos     /* if target already supplied, ignore commands */
1475*69086Schristos     if (!(gn->type & OP_HAS_COMMANDS))
1476*69086Schristos 	(void)Lst_AtEnd(gn->commands, cmd);
1477*69086Schristos     return(0);
147840393Sbostic }
147940424Sbostic 
148040393Sbostic /*-
148140393Sbostic  *-----------------------------------------------------------------------
148240393Sbostic  * ParseHasCommands --
148340393Sbostic  *	Callback procedure for Parse_File when destroying the list of
148440393Sbostic  *	targets on the last dependency line. Marks a target as already
148540393Sbostic  *	having commands if it does, to keep from having shell commands
148640393Sbostic  *	on multiple dependency lines.
148740393Sbostic  *
148840393Sbostic  * Results:
1489*69086Schristos  *	None
149040393Sbostic  *
149140393Sbostic  * Side Effects:
149240393Sbostic  *	OP_HAS_COMMANDS may be set for the target.
149340393Sbostic  *
149440393Sbostic  *-----------------------------------------------------------------------
149540393Sbostic  */
1496*69086Schristos static void
1497*69086Schristos ParseHasCommands(gnp)
1498*69086Schristos     ClientData 	  gnp;	    /* Node to examine */
149940393Sbostic {
1500*69086Schristos     GNode *gn = (GNode *) gnp;
150140393Sbostic     if (!Lst_IsEmpty(gn->commands)) {
150240393Sbostic 	gn->type |= OP_HAS_COMMANDS;
150340393Sbostic     }
150440393Sbostic }
150540424Sbostic 
150640393Sbostic /*-
150740393Sbostic  *-----------------------------------------------------------------------
150840393Sbostic  * Parse_AddIncludeDir --
150940393Sbostic  *	Add a directory to the path searched for included makefiles
151040393Sbostic  *	bracketed by double-quotes. Used by functions in main.c
151140393Sbostic  *
151240393Sbostic  * Results:
151340393Sbostic  *	None.
151440393Sbostic  *
151540393Sbostic  * Side Effects:
151640393Sbostic  *	The directory is appended to the list.
151740393Sbostic  *
151840393Sbostic  *-----------------------------------------------------------------------
151940393Sbostic  */
152040393Sbostic void
152140393Sbostic Parse_AddIncludeDir (dir)
152240393Sbostic     char    	  *dir;	    /* The name of the directory to add */
152340393Sbostic {
152440393Sbostic     Dir_AddDir (parseIncPath, dir);
152540393Sbostic }
152640424Sbostic 
152740393Sbostic /*-
152840393Sbostic  *---------------------------------------------------------------------
152940393Sbostic  * ParseDoInclude  --
153040393Sbostic  *	Push to another file.
153140393Sbostic  *
153240393Sbostic  *	The input is the line minus the #include. A file spec is a string
153340393Sbostic  *	enclosed in <> or "". The former is looked for only in sysIncPath.
153440393Sbostic  *	The latter in . and the directories specified by -I command line
153540393Sbostic  *	options
153640393Sbostic  *
153740393Sbostic  * Results:
153840393Sbostic  *	None
153940393Sbostic  *
154040393Sbostic  * Side Effects:
154140393Sbostic  *	A structure is added to the includes Lst and readProc, lineno,
154240393Sbostic  *	fname and curFILE are altered for the new file
154340393Sbostic  *---------------------------------------------------------------------
154440393Sbostic  */
154540393Sbostic static void
154640393Sbostic ParseDoInclude (file)
154740393Sbostic     char          *file;	/* file specification */
154840393Sbostic {
154940393Sbostic     char          *fullname;	/* full pathname of file */
155040393Sbostic     IFile         *oldFile;	/* state associated with current file */
155140393Sbostic     char          endc;	    	/* the character which ends the file spec */
155240393Sbostic     char          *cp;		/* current position in file spec */
155340393Sbostic     Boolean 	  isSystem; 	/* TRUE if makefile is a system makefile */
155440393Sbostic 
155540393Sbostic     /*
155640393Sbostic      * Skip to delimiter character so we know where to look
155740393Sbostic      */
155840393Sbostic     while ((*file == ' ') || (*file == '\t')) {
155940393Sbostic 	file++;
156040393Sbostic     }
156140393Sbostic 
156240393Sbostic     if ((*file != '"') && (*file != '<')) {
156342443Sbostic 	Parse_Error (PARSE_FATAL,
156442443Sbostic 	    ".include filename must be delimited by '\"' or '<'");
156540393Sbostic 	return;
156640393Sbostic     }
156740393Sbostic 
156840393Sbostic     /*
156940393Sbostic      * Set the search path on which to find the include file based on the
157040393Sbostic      * characters which bracket its name. Angle-brackets imply it's
157140393Sbostic      * a system Makefile while double-quotes imply it's a user makefile
157240393Sbostic      */
157340393Sbostic     if (*file == '<') {
157440393Sbostic 	isSystem = TRUE;
157540393Sbostic 	endc = '>';
157640393Sbostic     } else {
157740393Sbostic 	isSystem = FALSE;
157840393Sbostic 	endc = '"';
157940393Sbostic     }
158040393Sbostic 
158140393Sbostic     /*
158240393Sbostic      * Skip to matching delimiter
158340393Sbostic      */
158440393Sbostic     for (cp = ++file; *cp && *cp != endc; cp++) {
158540393Sbostic 	continue;
158640393Sbostic     }
158740393Sbostic 
158840393Sbostic     if (*cp != endc) {
158940393Sbostic 	Parse_Error (PARSE_FATAL,
159060285Sbostic 		     "Unclosed %cinclude filename. '%c' expected",
159160285Sbostic 		     '.', endc);
159240393Sbostic 	return;
159340393Sbostic     }
159440393Sbostic     *cp = '\0';
159540393Sbostic 
159640393Sbostic     /*
159740393Sbostic      * Substitute for any variables in the file name before trying to
159840393Sbostic      * find the thing.
159940393Sbostic      */
160060285Sbostic     file = Var_Subst (NULL, file, VAR_CMD, FALSE);
160140393Sbostic 
160240393Sbostic     /*
160340393Sbostic      * Now we know the file's name and its search path, we attempt to
160440393Sbostic      * find the durn thing. A return of NULL indicates the file don't
160540393Sbostic      * exist.
160640393Sbostic      */
160740393Sbostic     if (!isSystem) {
160840393Sbostic 	/*
160940393Sbostic 	 * Include files contained in double-quotes are first searched for
161040393Sbostic 	 * relative to the including file's location. We don't want to
161140393Sbostic 	 * cd there, of course, so we just tack on the old file's
161240393Sbostic 	 * leading path components and call Dir_FindFile to see if
161340393Sbostic 	 * we can locate the beast.
161440393Sbostic 	 */
161540393Sbostic 	char	  *prefEnd;
161640393Sbostic 
161760285Sbostic 	prefEnd = strrchr (fname, '/');
161840393Sbostic 	if (prefEnd != (char *)NULL) {
161940393Sbostic 	    char  	*newName;
162040393Sbostic 
162140393Sbostic 	    *prefEnd = '\0';
1622*69086Schristos 	    if (file[0] == '/')
1623*69086Schristos 		newName = strdup(file);
1624*69086Schristos 	    else
1625*69086Schristos 		newName = str_concat (fname, file, STR_ADDSLASH);
162640393Sbostic 	    fullname = Dir_FindFile (newName, parseIncPath);
162740393Sbostic 	    if (fullname == (char *)NULL) {
162840393Sbostic 		fullname = Dir_FindFile(newName, dirSearchPath);
162940393Sbostic 	    }
163040393Sbostic 	    free (newName);
163140393Sbostic 	    *prefEnd = '/';
163240393Sbostic 	} else {
163340393Sbostic 	    fullname = (char *)NULL;
163440393Sbostic 	}
163540393Sbostic     } else {
163640393Sbostic 	fullname = (char *)NULL;
163740393Sbostic     }
163840393Sbostic 
163940393Sbostic     if (fullname == (char *)NULL) {
164040393Sbostic 	/*
164140393Sbostic 	 * System makefile or makefile wasn't found in same directory as
164240393Sbostic 	 * included makefile. Search for it first on the -I search path,
164340393Sbostic 	 * then on the .PATH search path, if not found in a -I directory.
164440393Sbostic 	 * XXX: Suffix specific?
164540393Sbostic 	 */
164640393Sbostic 	fullname = Dir_FindFile (file, parseIncPath);
164740393Sbostic 	if (fullname == (char *)NULL) {
164840393Sbostic 	    fullname = Dir_FindFile(file, dirSearchPath);
164940393Sbostic 	}
165040393Sbostic     }
165140393Sbostic 
165240393Sbostic     if (fullname == (char *)NULL) {
165340393Sbostic 	/*
165440393Sbostic 	 * Still haven't found the makefile. Look for it on the system
165540393Sbostic 	 * path as a last resort.
165640393Sbostic 	 */
165740393Sbostic 	fullname = Dir_FindFile(file, sysIncPath);
165840393Sbostic     }
165940393Sbostic 
166040393Sbostic     if (fullname == (char *) NULL) {
166140393Sbostic 	*cp = endc;
166240393Sbostic 	Parse_Error (PARSE_FATAL, "Could not find %s", file);
166340393Sbostic 	return;
166440393Sbostic     }
166540393Sbostic 
1666*69086Schristos     free(file);
1667*69086Schristos 
166840393Sbostic     /*
166940393Sbostic      * Once we find the absolute path to the file, we get to save all the
167040393Sbostic      * state from the current file before we can start reading this
167140393Sbostic      * include file. The state is stored in an IFile structure which
167240393Sbostic      * is placed on a list with other IFile structures. The list makes
167340393Sbostic      * a very nice stack to track how we got here...
167440393Sbostic      */
167540534Sbostic     oldFile = (IFile *) emalloc (sizeof (IFile));
167640393Sbostic     oldFile->fname = fname;
167740393Sbostic 
167840393Sbostic     oldFile->F = curFILE;
167960285Sbostic     oldFile->p = curPTR;
168040393Sbostic     oldFile->lineno = lineno;
168140393Sbostic 
168240393Sbostic     (void) Lst_AtFront (includes, (ClientData)oldFile);
168340393Sbostic 
168440393Sbostic     /*
168540393Sbostic      * Once the previous state has been saved, we can get down to reading
168640393Sbostic      * the new file. We set up the name of the file to be the absolute
168740393Sbostic      * name of the include file so error messages refer to the right
168840393Sbostic      * place. Naturally enough, we start reading at line number 0.
168940393Sbostic      */
169040393Sbostic     fname = fullname;
169140393Sbostic     lineno = 0;
169240393Sbostic 
169340393Sbostic     curFILE = fopen (fullname, "r");
169460285Sbostic     curPTR = NULL;
169540393Sbostic     if (curFILE == (FILE * ) NULL) {
169640393Sbostic 	Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
169740393Sbostic 	/*
169840393Sbostic 	 * Pop to previous file
169940393Sbostic 	 */
170046462Sbostic 	(void) ParseEOF(0);
170140393Sbostic     }
170240393Sbostic }
170340424Sbostic 
170460285Sbostic 
170540393Sbostic /*-
170640393Sbostic  *---------------------------------------------------------------------
170760285Sbostic  * Parse_FromString  --
170860285Sbostic  *	Start Parsing from the given string
170960285Sbostic  *
171060285Sbostic  * Results:
171160285Sbostic  *	None
171260285Sbostic  *
171360285Sbostic  * Side Effects:
171460285Sbostic  *	A structure is added to the includes Lst and readProc, lineno,
171560285Sbostic  *	fname and curFILE are altered for the new file
171660285Sbostic  *---------------------------------------------------------------------
171760285Sbostic  */
171860285Sbostic void
171960285Sbostic Parse_FromString(str)
172060285Sbostic     char *str;
172160285Sbostic {
172260285Sbostic     IFile         *oldFile;	/* state associated with this file */
172360285Sbostic 
172460285Sbostic     if (DEBUG(FOR))
172560285Sbostic 	(void) fprintf(stderr, "%s\n----\n", str);
172660285Sbostic 
172760285Sbostic     oldFile = (IFile *) emalloc (sizeof (IFile));
172860285Sbostic     oldFile->lineno = lineno;
172960285Sbostic     oldFile->fname = fname;
173060285Sbostic     oldFile->F = curFILE;
173160285Sbostic     oldFile->p = curPTR;
173260285Sbostic 
173360285Sbostic     (void) Lst_AtFront (includes, (ClientData)oldFile);
173460285Sbostic 
173560285Sbostic     curFILE = NULL;
173660285Sbostic     curPTR = (PTR *) emalloc (sizeof (PTR));
173760285Sbostic     curPTR->str = curPTR->ptr = str;
173860285Sbostic     lineno = 0;
173960285Sbostic     fname = strdup(fname);
174060285Sbostic }
174160285Sbostic 
174260285Sbostic 
174360285Sbostic #ifdef SYSVINCLUDE
174460285Sbostic /*-
174560285Sbostic  *---------------------------------------------------------------------
174660285Sbostic  * ParseTraditionalInclude  --
174760285Sbostic  *	Push to another file.
174860285Sbostic  *
174960285Sbostic  *	The input is the line minus the "include".  The file name is
175060285Sbostic  *	the string following the "include".
175160285Sbostic  *
175260285Sbostic  * Results:
175360285Sbostic  *	None
175460285Sbostic  *
175560285Sbostic  * Side Effects:
175660285Sbostic  *	A structure is added to the includes Lst and readProc, lineno,
175760285Sbostic  *	fname and curFILE are altered for the new file
175860285Sbostic  *---------------------------------------------------------------------
175960285Sbostic  */
176060285Sbostic static void
176160285Sbostic ParseTraditionalInclude (file)
176260285Sbostic     char          *file;	/* file specification */
176360285Sbostic {
176460285Sbostic     char          *fullname;	/* full pathname of file */
176560285Sbostic     IFile         *oldFile;	/* state associated with current file */
176660285Sbostic     char          *cp;		/* current position in file spec */
176760285Sbostic     char	  *prefEnd;
176860285Sbostic 
176960285Sbostic     /*
177060285Sbostic      * Skip over whitespace
177160285Sbostic      */
177260285Sbostic     while ((*file == ' ') || (*file == '\t')) {
177360285Sbostic 	file++;
177460285Sbostic     }
177560285Sbostic 
177660285Sbostic     if (*file == '\0') {
177760285Sbostic 	Parse_Error (PARSE_FATAL,
177860285Sbostic 		     "Filename missing from \"include\"");
177960285Sbostic 	return;
178060285Sbostic     }
178160285Sbostic 
178260285Sbostic     /*
178360285Sbostic      * Skip to end of line or next whitespace
178460285Sbostic      */
178560285Sbostic     for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) {
178660285Sbostic 	continue;
178760285Sbostic     }
178860285Sbostic 
178960285Sbostic     *cp = '\0';
179060285Sbostic 
179160285Sbostic     /*
179260285Sbostic      * Substitute for any variables in the file name before trying to
179360285Sbostic      * find the thing.
179460285Sbostic      */
179560285Sbostic     file = Var_Subst (NULL, file, VAR_CMD, FALSE);
179660285Sbostic 
179760285Sbostic     /*
179860285Sbostic      * Now we know the file's name, we attempt to find the durn thing.
179960285Sbostic      * A return of NULL indicates the file don't exist.
180060285Sbostic      *
180160285Sbostic      * Include files are first searched for relative to the including
180260285Sbostic      * file's location. We don't want to cd there, of course, so we
180360285Sbostic      * just tack on the old file's leading path components and call
180460285Sbostic      * Dir_FindFile to see if we can locate the beast.
180560285Sbostic      * XXX - this *does* search in the current directory, right?
180660285Sbostic      */
180760285Sbostic 
180860285Sbostic     prefEnd = strrchr (fname, '/');
180960285Sbostic     if (prefEnd != (char *)NULL) {
181060285Sbostic 	char  	*newName;
181160285Sbostic 
181260285Sbostic 	*prefEnd = '\0';
181360285Sbostic 	newName = str_concat (fname, file, STR_ADDSLASH);
181460285Sbostic 	fullname = Dir_FindFile (newName, parseIncPath);
181560285Sbostic 	if (fullname == (char *)NULL) {
181660285Sbostic 	    fullname = Dir_FindFile(newName, dirSearchPath);
181760285Sbostic 	}
181860285Sbostic 	free (newName);
181960285Sbostic 	*prefEnd = '/';
182060285Sbostic     } else {
182160285Sbostic 	fullname = (char *)NULL;
182260285Sbostic     }
182360285Sbostic 
182460285Sbostic     if (fullname == (char *)NULL) {
182560285Sbostic 	/*
182660285Sbostic 	 * System makefile or makefile wasn't found in same directory as
182760285Sbostic 	 * included makefile. Search for it first on the -I search path,
182860285Sbostic 	 * then on the .PATH search path, if not found in a -I directory.
182960285Sbostic 	 * XXX: Suffix specific?
183060285Sbostic 	 */
183160285Sbostic 	fullname = Dir_FindFile (file, parseIncPath);
183260285Sbostic 	if (fullname == (char *)NULL) {
183360285Sbostic 	    fullname = Dir_FindFile(file, dirSearchPath);
183460285Sbostic 	}
183560285Sbostic     }
183660285Sbostic 
183760285Sbostic     if (fullname == (char *)NULL) {
183860285Sbostic 	/*
183960285Sbostic 	 * Still haven't found the makefile. Look for it on the system
184060285Sbostic 	 * path as a last resort.
184160285Sbostic 	 */
184260285Sbostic 	fullname = Dir_FindFile(file, sysIncPath);
184360285Sbostic     }
184460285Sbostic 
184560285Sbostic     if (fullname == (char *) NULL) {
184660285Sbostic 	Parse_Error (PARSE_FATAL, "Could not find %s", file);
184760285Sbostic 	return;
184860285Sbostic     }
184960285Sbostic 
185060285Sbostic     /*
185160285Sbostic      * Once we find the absolute path to the file, we get to save all the
185260285Sbostic      * state from the current file before we can start reading this
185360285Sbostic      * include file. The state is stored in an IFile structure which
185460285Sbostic      * is placed on a list with other IFile structures. The list makes
185560285Sbostic      * a very nice stack to track how we got here...
185660285Sbostic      */
185760285Sbostic     oldFile = (IFile *) emalloc (sizeof (IFile));
185860285Sbostic     oldFile->fname = fname;
185960285Sbostic 
186060285Sbostic     oldFile->F = curFILE;
186160285Sbostic     oldFile->p = curPTR;
186260285Sbostic     oldFile->lineno = lineno;
186360285Sbostic 
186460285Sbostic     (void) Lst_AtFront (includes, (ClientData)oldFile);
186560285Sbostic 
186660285Sbostic     /*
186760285Sbostic      * Once the previous state has been saved, we can get down to reading
186860285Sbostic      * the new file. We set up the name of the file to be the absolute
186960285Sbostic      * name of the include file so error messages refer to the right
187060285Sbostic      * place. Naturally enough, we start reading at line number 0.
187160285Sbostic      */
187260285Sbostic     fname = fullname;
187360285Sbostic     lineno = 0;
187460285Sbostic 
187560285Sbostic     curFILE = fopen (fullname, "r");
187660285Sbostic     curPTR = NULL;
187760285Sbostic     if (curFILE == (FILE * ) NULL) {
187860285Sbostic 	Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
187960285Sbostic 	/*
188060285Sbostic 	 * Pop to previous file
188160285Sbostic 	 */
188260285Sbostic 	(void) ParseEOF(1);
188360285Sbostic     }
188460285Sbostic }
188560285Sbostic #endif
188660285Sbostic 
188760285Sbostic /*-
188860285Sbostic  *---------------------------------------------------------------------
188940393Sbostic  * ParseEOF  --
189040393Sbostic  *	Called when EOF is reached in the current file. If we were reading
189140393Sbostic  *	an include file, the includes stack is popped and things set up
189240393Sbostic  *	to go back to reading the previous file at the previous location.
189340393Sbostic  *
189440393Sbostic  * Results:
189540393Sbostic  *	CONTINUE if there's more to do. DONE if not.
189640393Sbostic  *
189740393Sbostic  * Side Effects:
189840393Sbostic  *	The old curFILE, is closed. The includes list is shortened.
189940393Sbostic  *	lineno, curFILE, and fname are changed if CONTINUE is returned.
190040393Sbostic  *---------------------------------------------------------------------
190140393Sbostic  */
190240393Sbostic static int
190346462Sbostic ParseEOF (opened)
190446462Sbostic     int opened;
190540393Sbostic {
190640393Sbostic     IFile     *ifile;	/* the state on the top of the includes stack */
190740393Sbostic 
190840393Sbostic     if (Lst_IsEmpty (includes)) {
190940393Sbostic 	return (DONE);
191040393Sbostic     }
191140393Sbostic 
191240393Sbostic     ifile = (IFile *) Lst_DeQueue (includes);
191360285Sbostic     free ((Address) fname);
191440393Sbostic     fname = ifile->fname;
191540393Sbostic     lineno = ifile->lineno;
191660285Sbostic     if (opened && curFILE)
191746462Sbostic 	(void) fclose (curFILE);
191860285Sbostic     if (curPTR) {
191960285Sbostic 	free((Address) curPTR->str);
192060285Sbostic 	free((Address) curPTR);
192160285Sbostic     }
192240393Sbostic     curFILE = ifile->F;
192360285Sbostic     curPTR = ifile->p;
192440393Sbostic     free ((Address)ifile);
192540393Sbostic     return (CONTINUE);
192640393Sbostic }
192740424Sbostic 
192840393Sbostic /*-
192940393Sbostic  *---------------------------------------------------------------------
193040393Sbostic  * ParseReadc  --
193160285Sbostic  *	Read a character from the current file
193240393Sbostic  *
193340393Sbostic  * Results:
193440393Sbostic  *	The character that was read
193540393Sbostic  *
193640393Sbostic  * Side Effects:
193740393Sbostic  *---------------------------------------------------------------------
193840393Sbostic  */
193960285Sbostic static int
194060285Sbostic ParseReadc()
194160285Sbostic {
194260285Sbostic     if (curFILE)
194360285Sbostic 	return fgetc(curFILE);
194460285Sbostic 
194560285Sbostic     if (curPTR && *curPTR->ptr)
194660285Sbostic 	return *curPTR->ptr++;
194760285Sbostic     return EOF;
194860285Sbostic }
194940393Sbostic 
195060557Sbostic 
195160557Sbostic /*-
195260557Sbostic  *---------------------------------------------------------------------
195360557Sbostic  * ParseUnreadc  --
195460557Sbostic  *	Put back a character to the current file
195560557Sbostic  *
195660557Sbostic  * Results:
195760557Sbostic  *	None.
195860557Sbostic  *
195960557Sbostic  * Side Effects:
196060557Sbostic  *---------------------------------------------------------------------
196160557Sbostic  */
196260557Sbostic static void
196360557Sbostic ParseUnreadc(c)
196460557Sbostic     int c;
196560557Sbostic {
196660557Sbostic     if (curFILE) {
196760557Sbostic 	ungetc(c, curFILE);
196860557Sbostic 	return;
196960557Sbostic     }
197060557Sbostic     if (curPTR) {
197160557Sbostic 	*--(curPTR->ptr) = c;
197260557Sbostic 	return;
197360557Sbostic     }
197460557Sbostic }
197560557Sbostic 
197660557Sbostic 
197760285Sbostic /* ParseSkipLine():
197860285Sbostic  *	Grab the next line
197960285Sbostic  */
198060285Sbostic static char *
198160285Sbostic ParseSkipLine(skip)
198260285Sbostic     int skip; 		/* Skip lines that don't start with . */
198360285Sbostic {
198460285Sbostic     char *line;
198560285Sbostic     int c, lastc = '\0', lineLength;
198660285Sbostic     Buffer buf;
198740393Sbostic 
198860285Sbostic     c = ParseReadc();
198940424Sbostic 
199060285Sbostic     if (skip) {
199160285Sbostic 	/*
199260285Sbostic 	 * Skip lines until get to one that begins with a
199360285Sbostic 	 * special char.
199460285Sbostic 	 */
199560285Sbostic 	while ((c != '.') && (c != EOF)) {
199660285Sbostic 	    while (((c != '\n') || (lastc == '\\')) && (c != EOF))
199760285Sbostic 	    {
199860285Sbostic 		/*
199960285Sbostic 		 * Advance to next unescaped newline
200060285Sbostic 		 */
200160285Sbostic 		if ((lastc = c) == '\n') {
200260285Sbostic 		    lineno++;
200360285Sbostic 		}
200460285Sbostic 		c = ParseReadc();
200560285Sbostic 	    }
200660285Sbostic 	    lineno++;
200760285Sbostic 
200860285Sbostic 	    lastc = c;
200960285Sbostic 	    c = ParseReadc ();
201060285Sbostic 	}
201160285Sbostic     }
201260285Sbostic 
201360285Sbostic     if (c == EOF) {
201460285Sbostic 	Parse_Error (PARSE_FATAL, "Unclosed conditional/for loop");
201560285Sbostic 	return ((char *)NULL);
201660285Sbostic     }
201760285Sbostic 
201860285Sbostic     /*
201960285Sbostic      * Read the entire line into buf
202060285Sbostic      */
202160285Sbostic     buf = Buf_Init (MAKE_BSIZE);
202260285Sbostic     if (c != '\n') {
202360285Sbostic 	do {
202460285Sbostic 	    Buf_AddByte (buf, (Byte)c);
202560285Sbostic 	    c = ParseReadc();
202660285Sbostic 	} while ((c != '\n') && (c != EOF));
202760285Sbostic     }
202860285Sbostic     lineno++;
202960285Sbostic 
203060285Sbostic     Buf_AddByte (buf, (Byte)'\0');
203160285Sbostic     line = (char *)Buf_GetAll (buf, &lineLength);
203260285Sbostic     Buf_Destroy (buf, FALSE);
203360285Sbostic     return line;
203460285Sbostic }
203560285Sbostic 
203660285Sbostic 
203740393Sbostic /*-
203840393Sbostic  *---------------------------------------------------------------------
203940393Sbostic  * ParseReadLine --
204040393Sbostic  *	Read an entire line from the input file. Called only by Parse_File.
204140393Sbostic  *	To facilitate escaped newlines and what have you, a character is
204240393Sbostic  *	buffered in 'lastc', which is '\0' when no characters have been
204340393Sbostic  *	read. When we break out of the loop, c holds the terminating
204440393Sbostic  *	character and lastc holds a character that should be added to
204540393Sbostic  *	the line (unless we don't read anything but a terminator).
204640393Sbostic  *
204740393Sbostic  * Results:
204840393Sbostic  *	A line w/o its newline
204940393Sbostic  *
205040393Sbostic  * Side Effects:
205140393Sbostic  *	Only those associated with reading a character
205240393Sbostic  *---------------------------------------------------------------------
205340393Sbostic  */
205440393Sbostic static char *
205540393Sbostic ParseReadLine ()
205640393Sbostic {
205740393Sbostic     Buffer  	  buf;	    	/* Buffer for current line */
205840393Sbostic     register int  c;	      	/* the current character */
205940393Sbostic     register int  lastc;    	/* The most-recent character */
206040393Sbostic     Boolean	  semiNL;     	/* treat semi-colons as newlines */
206140393Sbostic     Boolean	  ignDepOp;   	/* TRUE if should ignore dependency operators
206240393Sbostic 				 * for the purposes of setting semiNL */
206340393Sbostic     Boolean 	  ignComment;	/* TRUE if should ignore comments (in a
206440393Sbostic 				 * shell command */
2065*69086Schristos     char 	  *line;    	/* Result */
2066*69086Schristos     char          *ep;		/* to strip trailing blanks */
206740393Sbostic     int	    	  lineLength;	/* Length of result */
206840393Sbostic 
206940393Sbostic     semiNL = FALSE;
207040393Sbostic     ignDepOp = FALSE;
207140393Sbostic     ignComment = FALSE;
207240393Sbostic 
207340393Sbostic     /*
207440393Sbostic      * Handle special-characters at the beginning of the line. Either a
207540393Sbostic      * leading tab (shell command) or pound-sign (possible conditional)
207640393Sbostic      * forces us to ignore comments and dependency operators and treat
207740393Sbostic      * semi-colons as semi-colons (by leaving semiNL FALSE). This also
207840393Sbostic      * discards completely blank lines.
207940393Sbostic      */
208060285Sbostic     for (;;) {
208140393Sbostic 	c = ParseReadc();
208240393Sbostic 
208360557Sbostic 	if (c == '\t') {
208444599Sbostic 	    ignComment = ignDepOp = TRUE;
208544599Sbostic 	    break;
208640393Sbostic 	} else if (c == '\n') {
208740393Sbostic 	    lineno++;
208861010Sbostic 	} else if (c == '#') {
208966399Schristos 	    ParseUnreadc(c);
209066399Schristos 	    break;
209140393Sbostic 	} else {
209240393Sbostic 	    /*
209340393Sbostic 	     * Anything else breaks out without doing anything
209440393Sbostic 	     */
209540393Sbostic 	    break;
209640393Sbostic 	}
209740393Sbostic     }
209840393Sbostic 
209940393Sbostic     if (c != EOF) {
210040393Sbostic 	lastc = c;
210160285Sbostic 	buf = Buf_Init(MAKE_BSIZE);
210240393Sbostic 
210340393Sbostic 	while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) &&
210440393Sbostic 	       (c != EOF))
210540393Sbostic 	{
210640393Sbostic test_char:
210740393Sbostic 	    switch(c) {
210840393Sbostic 	    case '\n':
210940393Sbostic 		/*
211040393Sbostic 		 * Escaped newline: read characters until a non-space or an
211140393Sbostic 		 * unescaped newline and replace them all by a single space.
211240393Sbostic 		 * This is done by storing the space over the backslash and
211340393Sbostic 		 * dropping through with the next nonspace. If it is a
211440393Sbostic 		 * semi-colon and semiNL is TRUE, it will be recognized as a
211540393Sbostic 		 * newline in the code below this...
211640393Sbostic 		 */
211740393Sbostic 		lineno++;
211840393Sbostic 		lastc = ' ';
211940393Sbostic 		while ((c = ParseReadc ()) == ' ' || c == '\t') {
212040393Sbostic 		    continue;
212140393Sbostic 		}
212240393Sbostic 		if (c == EOF || c == '\n') {
212340393Sbostic 		    goto line_read;
212440393Sbostic 		} else {
212540393Sbostic 		    /*
212640393Sbostic 		     * Check for comments, semiNL's, etc. -- easier than
212760557Sbostic 		     * ParseUnreadc(c); continue;
212840393Sbostic 		     */
212940393Sbostic 		    goto test_char;
213040393Sbostic 		}
213160285Sbostic 		/*NOTREACHED*/
213240393Sbostic 		break;
213360285Sbostic 
213440393Sbostic 	    case ';':
213540393Sbostic 		/*
213640393Sbostic 		 * Semi-colon: Need to see if it should be interpreted as a
213740393Sbostic 		 * newline
213840393Sbostic 		 */
213940393Sbostic 		if (semiNL) {
214040393Sbostic 		    /*
214140393Sbostic 		     * To make sure the command that may be following this
214240393Sbostic 		     * semi-colon begins with a tab, we push one back into the
214340393Sbostic 		     * input stream. This will overwrite the semi-colon in the
214440393Sbostic 		     * buffer. If there is no command following, this does no
214540393Sbostic 		     * harm, since the newline remains in the buffer and the
214640393Sbostic 		     * whole line is ignored.
214740393Sbostic 		     */
214860557Sbostic 		    ParseUnreadc('\t');
214940393Sbostic 		    goto line_read;
215040393Sbostic 		}
215140393Sbostic 		break;
215240393Sbostic 	    case '=':
215340393Sbostic 		if (!semiNL) {
215440393Sbostic 		    /*
215540393Sbostic 		     * Haven't seen a dependency operator before this, so this
215640393Sbostic 		     * must be a variable assignment -- don't pay attention to
215740393Sbostic 		     * dependency operators after this.
215840393Sbostic 		     */
215940393Sbostic 		    ignDepOp = TRUE;
216040393Sbostic 		} else if (lastc == ':' || lastc == '!') {
216140393Sbostic 		    /*
216240393Sbostic 		     * Well, we've seen a dependency operator already, but it
216340393Sbostic 		     * was the previous character, so this is really just an
216440393Sbostic 		     * expanded variable assignment. Revert semi-colons to
216540393Sbostic 		     * being just semi-colons again and ignore any more
216640393Sbostic 		     * dependency operators.
216740393Sbostic 		     *
216840393Sbostic 		     * XXX: Note that a line like "foo : a:=b" will blow up,
216940393Sbostic 		     * but who'd write a line like that anyway?
217040393Sbostic 		     */
217140393Sbostic 		    ignDepOp = TRUE; semiNL = FALSE;
217240393Sbostic 		}
217340393Sbostic 		break;
217440393Sbostic 	    case '#':
217540393Sbostic 		if (!ignComment) {
217667227Schristos 		    if (compatMake && (lastc != '\\')) {
217740393Sbostic 			/*
217840393Sbostic 			 * If the character is a hash mark and it isn't escaped
217940393Sbostic 			 * (or we're being compatible), the thing is a comment.
218040393Sbostic 			 * Skip to the end of the line.
218140393Sbostic 			 */
218240393Sbostic 			do {
218340393Sbostic 			    c = ParseReadc();
218440393Sbostic 			} while ((c != '\n') && (c != EOF));
218540393Sbostic 			goto line_read;
218660285Sbostic 		    } else {
218760285Sbostic 			/*
218860285Sbostic 			 * Don't add the backslash. Just let the # get copied
218960285Sbostic 			 * over.
219060285Sbostic 			 */
219160285Sbostic 			lastc = c;
219260285Sbostic 			continue;
219360285Sbostic 		    }
219440393Sbostic 		}
219540393Sbostic 		break;
219640393Sbostic 	    case ':':
219740393Sbostic 	    case '!':
219840393Sbostic 		if (!ignDepOp && (c == ':' || c == '!')) {
219940393Sbostic 		    /*
220040393Sbostic 		     * A semi-colon is recognized as a newline only on
220140393Sbostic 		     * dependency lines. Dependency lines are lines with a
220240393Sbostic 		     * colon or an exclamation point. Ergo...
220340393Sbostic 		     */
220440393Sbostic 		    semiNL = TRUE;
220540393Sbostic 		}
220640393Sbostic 		break;
220740393Sbostic 	    }
220840393Sbostic 	    /*
220940393Sbostic 	     * Copy in the previous character and save this one in lastc.
221040393Sbostic 	     */
221140393Sbostic 	    Buf_AddByte (buf, (Byte)lastc);
221240393Sbostic 	    lastc = c;
221340393Sbostic 
221440393Sbostic 	}
221540393Sbostic     line_read:
221640393Sbostic 	lineno++;
221740393Sbostic 
221840393Sbostic 	if (lastc != '\0') {
221940393Sbostic 	    Buf_AddByte (buf, (Byte)lastc);
222040393Sbostic 	}
222140393Sbostic 	Buf_AddByte (buf, (Byte)'\0');
222240393Sbostic 	line = (char *)Buf_GetAll (buf, &lineLength);
222340393Sbostic 	Buf_Destroy (buf, FALSE);
2224*69086Schristos 
2225*69086Schristos 	/*
2226*69086Schristos 	 * Strip trailing blanks and tabs from the line.
2227*69086Schristos 	 * Do not strip a blank or tab that is preceeded by
2228*69086Schristos 	 * a '\'
2229*69086Schristos 	 */
2230*69086Schristos 	ep = line;
2231*69086Schristos 	while (*ep)
2232*69086Schristos 	    ++ep;
2233*69086Schristos 	while (ep > line && (ep[-1] == ' ' || ep[-1] == '\t')) {
2234*69086Schristos 	    if (ep > line + 1 && ep[-2] == '\\')
2235*69086Schristos 		break;
2236*69086Schristos 	    --ep;
2237*69086Schristos 	}
2238*69086Schristos 	*ep = 0;
223940393Sbostic 
224040435Sbostic 	if (line[0] == '.') {
224140393Sbostic 	    /*
224240393Sbostic 	     * The line might be a conditional. Ask the conditional module
224340393Sbostic 	     * about it and act accordingly
224440393Sbostic 	     */
224540393Sbostic 	    switch (Cond_Eval (line)) {
224640393Sbostic 	    case COND_SKIP:
224760285Sbostic 		/*
224860285Sbostic 		 * Skip to next conditional that evaluates to COND_PARSE.
224960285Sbostic 		 */
225040393Sbostic 		do {
225140393Sbostic 		    free (line);
225260285Sbostic 		    line = ParseSkipLine(1);
225360285Sbostic 		} while (line && Cond_Eval(line) != COND_PARSE);
225460285Sbostic 		if (line == NULL)
225560285Sbostic 		    break;
225640393Sbostic 		/*FALLTHRU*/
225740393Sbostic 	    case COND_PARSE:
225860285Sbostic 		free ((Address) line);
225940393Sbostic 		line = ParseReadLine();
226040393Sbostic 		break;
226160285Sbostic 	    case COND_INVALID:
226260285Sbostic 		if (For_Eval(line)) {
226360285Sbostic 		    int ok;
226460285Sbostic 		    free(line);
226560285Sbostic 		    do {
226660285Sbostic 			/*
226760285Sbostic 			 * Skip after the matching end
226860285Sbostic 			 */
226960285Sbostic 			line = ParseSkipLine(0);
227060285Sbostic 			if (line == NULL) {
227160285Sbostic 			    Parse_Error (PARSE_FATAL,
227260285Sbostic 				     "Unexpected end of file in for loop.\n");
227360285Sbostic 			    break;
227460285Sbostic 			}
227560285Sbostic 			ok = For_Eval(line);
227660285Sbostic 			free(line);
227760285Sbostic 		    }
227860285Sbostic 		    while (ok);
227960285Sbostic 		    if (line != NULL)
228060285Sbostic 			For_Run();
228160285Sbostic 		    line = ParseReadLine();
228260285Sbostic 		}
228360285Sbostic 		break;
228440393Sbostic 	    }
228540393Sbostic 	}
228640393Sbostic 	return (line);
228760285Sbostic 
228840393Sbostic     } else {
228940393Sbostic 	/*
229040393Sbostic 	 * Hit end-of-file, so return a NULL line to indicate this.
229140393Sbostic 	 */
229240393Sbostic 	return((char *)NULL);
229340393Sbostic     }
229440393Sbostic }
229540424Sbostic 
229640393Sbostic /*-
229740393Sbostic  *-----------------------------------------------------------------------
229840393Sbostic  * ParseFinishLine --
229940393Sbostic  *	Handle the end of a dependency group.
230040393Sbostic  *
230140393Sbostic  * Results:
230240393Sbostic  *	Nothing.
230340393Sbostic  *
230440393Sbostic  * Side Effects:
230540393Sbostic  *	inLine set FALSE. 'targets' list destroyed.
230640393Sbostic  *
230740393Sbostic  *-----------------------------------------------------------------------
230840393Sbostic  */
230940393Sbostic static void
231040393Sbostic ParseFinishLine()
231140393Sbostic {
231240393Sbostic     if (inLine) {
231340393Sbostic 	Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL);
231440393Sbostic 	Lst_Destroy (targets, ParseHasCommands);
2315*69086Schristos 	targets = NULL;
231640393Sbostic 	inLine = FALSE;
231740393Sbostic     }
231840393Sbostic }
231940393Sbostic 
232040424Sbostic 
232140393Sbostic /*-
232240393Sbostic  *---------------------------------------------------------------------
232340393Sbostic  * Parse_File --
232440393Sbostic  *	Parse a file into its component parts, incorporating it into the
232540393Sbostic  *	current dependency graph. This is the main function and controls
232640393Sbostic  *	almost every other function in this module
232740393Sbostic  *
232840393Sbostic  * Results:
232940393Sbostic  *	None
233040393Sbostic  *
233140393Sbostic  * Side Effects:
233240393Sbostic  *	Loads. Nodes are added to the list of all targets, nodes and links
233340393Sbostic  *	are added to the dependency graph. etc. etc. etc.
233440393Sbostic  *---------------------------------------------------------------------
233540393Sbostic  */
233640393Sbostic void
233740393Sbostic Parse_File(name, stream)
233840393Sbostic     char          *name;	/* the name of the file being read */
233940393Sbostic     FILE *	  stream;   	/* Stream open to makefile to parse */
234040393Sbostic {
234140393Sbostic     register char *cp,		/* pointer into the line */
234240393Sbostic                   *line;	/* the line we're working on */
234340393Sbostic 
234440393Sbostic     inLine = FALSE;
234540393Sbostic     fname = name;
234640393Sbostic     curFILE = stream;
234740393Sbostic     lineno = 0;
234840393Sbostic     fatals = 0;
234940393Sbostic 
235040393Sbostic     do {
235160285Sbostic 	while ((line = ParseReadLine ()) != NULL) {
235240435Sbostic 	    if (*line == '.') {
235340393Sbostic 		/*
235440393Sbostic 		 * Lines that begin with the special character are either
235540393Sbostic 		 * include or undef directives.
235640393Sbostic 		 */
235740393Sbostic 		for (cp = line + 1; isspace (*cp); cp++) {
235840393Sbostic 		    continue;
235940393Sbostic 		}
236040393Sbostic 		if (strncmp (cp, "include", 7) == 0) {
236140393Sbostic 		    ParseDoInclude (cp + 7);
236240393Sbostic 		    goto nextLine;
236340393Sbostic 		} else if (strncmp(cp, "undef", 5) == 0) {
236440393Sbostic 		    char *cp2;
2365*69086Schristos 		    for (cp += 5; isspace((unsigned char) *cp); cp++) {
236640393Sbostic 			continue;
236740393Sbostic 		    }
236840393Sbostic 
2369*69086Schristos 		    for (cp2 = cp; !isspace((unsigned char) *cp2) &&
2370*69086Schristos 				   (*cp2 != '\0'); cp2++) {
237140393Sbostic 			continue;
237240393Sbostic 		    }
237340393Sbostic 
237440393Sbostic 		    *cp2 = '\0';
237540393Sbostic 
237640393Sbostic 		    Var_Delete(cp, VAR_GLOBAL);
237740393Sbostic 		    goto nextLine;
237840393Sbostic 		}
237940393Sbostic 	    }
2380*69086Schristos 	    if (*line == '#' || *line == '\0') {
2381*69086Schristos 		/* If we're this far, the line must be a comment.
2382*69086Schristos 		   (Empty lines are ignored as well) */
238340393Sbostic 		goto nextLine;
238440393Sbostic 	    }
238540393Sbostic 
2386*69086Schristos 	    if (*line == '\t') {
238740393Sbostic 		/*
2388*69086Schristos 		 * If a line starts with a tab, it can only hope to be
2389*69086Schristos 		 * a creation command.
239040393Sbostic 		 */
2391*69086Schristos #ifndef POSIX
239240393Sbostic 	    shellCommand:
2393*69086Schristos #endif
239440393Sbostic 		for (cp = line + 1; isspace (*cp); cp++) {
239540393Sbostic 		    continue;
239640393Sbostic 		}
239740393Sbostic 		if (*cp) {
239840393Sbostic 		    if (inLine) {
239940393Sbostic 			/*
240040393Sbostic 			 * So long as it's not a blank line and we're actually
240140393Sbostic 			 * in a dependency spec, add the command to the list of
240240393Sbostic 			 * commands of all targets in the dependency spec
240340393Sbostic 			 */
2404*69086Schristos 			Lst_ForEach (targets, ParseAddCmd, cp);
2405*69086Schristos 			Lst_AtEnd(targCmds, (ClientData) line);
240640393Sbostic 			continue;
240740393Sbostic 		    } else {
240840393Sbostic 			Parse_Error (PARSE_FATAL,
240940393Sbostic 				     "Unassociated shell command \"%.20s\"",
241040393Sbostic 				     cp);
241140393Sbostic 		    }
241240393Sbostic 		}
241360285Sbostic #ifdef SYSVINCLUDE
241460285Sbostic 	    } else if (strncmp (line, "include", 7) == 0 &&
241560285Sbostic 		       strchr(line, ':') == NULL) {
241660285Sbostic 		/*
241760285Sbostic 		 * It's an S3/S5-style "include".
241860285Sbostic 		 */
241960285Sbostic 		ParseTraditionalInclude (line + 7);
242060285Sbostic 		goto nextLine;
242160285Sbostic #endif
242240393Sbostic 	    } else if (Parse_IsVar (line)) {
242340393Sbostic 		ParseFinishLine();
242440393Sbostic 		Parse_DoVar (line, VAR_GLOBAL);
242540393Sbostic 	    } else {
242640393Sbostic 		/*
242740393Sbostic 		 * We now know it's a dependency line so it needs to have all
242840393Sbostic 		 * variables expanded before being parsed. Tell the variable
242940393Sbostic 		 * module to complain if some variable is undefined...
243040393Sbostic 		 * To make life easier on novices, if the line is indented we
243140393Sbostic 		 * first make sure the line has a dependency operator in it.
243240393Sbostic 		 * If it doesn't have an operator and we're in a dependency
243340393Sbostic 		 * line's script, we assume it's actually a shell command
243440393Sbostic 		 * and add it to the current list of targets.
243540393Sbostic 		 */
2436*69086Schristos #ifndef POSIX
243740393Sbostic 		Boolean	nonSpace = FALSE;
2438*69086Schristos #endif
243940393Sbostic 
244040393Sbostic 		cp = line;
2441*69086Schristos 		if (isspace((unsigned char) line[0])) {
2442*69086Schristos 		    while ((*cp != '\0') && isspace((unsigned char) *cp)) {
2443*69086Schristos 			cp++;
2444*69086Schristos 		    }
2445*69086Schristos 		    if (*cp == '\0') {
2446*69086Schristos 			goto nextLine;
2447*69086Schristos 		    }
244840393Sbostic #ifndef POSIX
244940393Sbostic 		    while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) {
2450*69086Schristos 			nonSpace = TRUE;
245140393Sbostic 			cp++;
245240393Sbostic 		    }
2453*69086Schristos #endif
245440393Sbostic 		}
245540393Sbostic 
2456*69086Schristos #ifndef POSIX
245740393Sbostic 		if (*cp == '\0') {
245840393Sbostic 		    if (inLine) {
245940393Sbostic 			Parse_Error (PARSE_WARNING,
246040393Sbostic 				     "Shell command needs a leading tab");
246140393Sbostic 			goto shellCommand;
246240393Sbostic 		    } else if (nonSpace) {
246340393Sbostic 			Parse_Error (PARSE_FATAL, "Missing operator");
246440393Sbostic 		    }
246540393Sbostic 		} else {
246640393Sbostic #endif
246740393Sbostic 		    ParseFinishLine();
246840393Sbostic 
246960285Sbostic 		    cp = Var_Subst (NULL, line, VAR_CMD, TRUE);
247040393Sbostic 		    free (line);
247140393Sbostic 		    line = cp;
247240393Sbostic 
247340393Sbostic 		    /*
247440393Sbostic 		     * Need a non-circular list for the target nodes
247540393Sbostic 		     */
2476*69086Schristos 		    if (targets)
2477*69086Schristos 			Lst_Destroy(targets, NOFREE);
2478*69086Schristos 
247940393Sbostic 		    targets = Lst_Init (FALSE);
248040393Sbostic 		    inLine = TRUE;
248140393Sbostic 
248240393Sbostic 		    ParseDoDependency (line);
248340393Sbostic #ifndef POSIX
248440393Sbostic 		}
248540393Sbostic #endif
248640393Sbostic 	    }
248740393Sbostic 
248840393Sbostic 	    nextLine:
248940393Sbostic 
249040393Sbostic 	    free (line);
249140393Sbostic 	}
249240393Sbostic 	/*
249340393Sbostic 	 * Reached EOF, but it may be just EOF of an include file...
249440393Sbostic 	 */
249546462Sbostic     } while (ParseEOF(1) == CONTINUE);
249640393Sbostic 
249740393Sbostic     /*
249840393Sbostic      * Make sure conditionals are clean
249940393Sbostic      */
250040393Sbostic     Cond_End();
250140393Sbostic 
250240393Sbostic     if (fatals) {
250340393Sbostic 	fprintf (stderr, "Fatal errors encountered -- cannot continue\n");
250440393Sbostic 	exit (1);
250540393Sbostic     }
250640393Sbostic }
250740424Sbostic 
250840393Sbostic /*-
250940393Sbostic  *---------------------------------------------------------------------
251040393Sbostic  * Parse_Init --
251140393Sbostic  *	initialize the parsing module
251240393Sbostic  *
251340393Sbostic  * Results:
251440393Sbostic  *	none
251540393Sbostic  *
251640393Sbostic  * Side Effects:
251740393Sbostic  *	the parseIncPath list is initialized...
251840393Sbostic  *---------------------------------------------------------------------
251940393Sbostic  */
252060285Sbostic void
252140393Sbostic Parse_Init ()
252240393Sbostic {
252360285Sbostic 	char *cp = NULL, *start;
252440515Sbostic 					/* avoid faults on read-only strings */
252540515Sbostic 	static char syspath[] = _PATH_DEFSYSPATH;
252640393Sbostic 
252740393Sbostic     mainNode = NILGNODE;
252840393Sbostic     parseIncPath = Lst_Init (FALSE);
252940393Sbostic     sysIncPath = Lst_Init (FALSE);
253040393Sbostic     includes = Lst_Init (FALSE);
2531*69086Schristos     targCmds = Lst_Init (FALSE);
253240393Sbostic 
253340393Sbostic     /*
253440393Sbostic      * Add the directories from the DEFSYSPATH (more than one may be given
253540393Sbostic      * as dir1:...:dirn) to the system include path.
253640393Sbostic      */
253740393Sbostic     for (start = syspath; *start != '\0'; start = cp) {
253860285Sbostic 	for (cp = start; *cp != '\0' && *cp != ':'; cp++)
253960285Sbostic 	    continue;
254040393Sbostic 	if (*cp == '\0') {
254140393Sbostic 	    Dir_AddDir(sysIncPath, start);
254240393Sbostic 	} else {
254340393Sbostic 	    *cp++ = '\0';
254440393Sbostic 	    Dir_AddDir(sysIncPath, start);
254540393Sbostic 	}
254640393Sbostic     }
254740393Sbostic }
254840424Sbostic 
2549*69086Schristos void
2550*69086Schristos Parse_End()
2551*69086Schristos {
2552*69086Schristos     Lst_Destroy(targCmds, (void (*) __P((ClientData))) free);
2553*69086Schristos     if (targets)
2554*69086Schristos 	Lst_Destroy(targets, NOFREE);
2555*69086Schristos     Lst_Destroy(sysIncPath, Dir_Destroy);
2556*69086Schristos     Lst_Destroy(parseIncPath, Dir_Destroy);
2557*69086Schristos     Lst_Destroy(includes, NOFREE);	/* Should be empty now */
2558*69086Schristos }
2559*69086Schristos 
2560*69086Schristos 
256140393Sbostic /*-
256240393Sbostic  *-----------------------------------------------------------------------
256340393Sbostic  * Parse_MainName --
256440393Sbostic  *	Return a Lst of the main target to create for main()'s sake. If
256540393Sbostic  *	no such target exists, we Punt with an obnoxious error message.
256640393Sbostic  *
256740393Sbostic  * Results:
256840393Sbostic  *	A Lst of the single node to create.
256940393Sbostic  *
257040393Sbostic  * Side Effects:
257140393Sbostic  *	None.
257240393Sbostic  *
257340393Sbostic  *-----------------------------------------------------------------------
257440393Sbostic  */
257540393Sbostic Lst
257640393Sbostic Parse_MainName()
257740393Sbostic {
257840393Sbostic     Lst           main;	/* result list */
257940393Sbostic 
258040393Sbostic     main = Lst_Init (FALSE);
258140393Sbostic 
258240393Sbostic     if (mainNode == NILGNODE) {
258345906Sbostic 	Punt ("make: no target to make.\n");
258440393Sbostic     	/*NOTREACHED*/
258540393Sbostic     } else if (mainNode->type & OP_DOUBLEDEP) {
258666389Sbostic 	(void) Lst_AtEnd (main, (ClientData)mainNode);
258740393Sbostic 	Lst_Concat(main, mainNode->cohorts, LST_CONCNEW);
258840393Sbostic     }
258966389Sbostic     else
259066389Sbostic 	(void) Lst_AtEnd (main, (ClientData)mainNode);
259140393Sbostic     return (main);
259240393Sbostic }
2593