xref: /csrg-svn/usr.bin/make/parse.c (revision 40444)
140395Sbostic /*
240395Sbostic  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
340395Sbostic  * Copyright (c) 1988, 1989 by Adam de Boor
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  *
1040395Sbostic  * Redistribution and use in source and binary forms are permitted
1140395Sbostic  * provided that the above copyright notice and this paragraph are
1240395Sbostic  * duplicated in all such forms and that any documentation,
1340395Sbostic  * advertising materials, and other materials related to such
1440395Sbostic  * distribution and use acknowledge that the software was developed
1540395Sbostic  * by the University of California, Berkeley.  The name of the
1640395Sbostic  * University may not be used to endorse or promote products derived
1740395Sbostic  * from this software without specific prior written permission.
1840395Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1940395Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
2040395Sbostic  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2140395Sbostic  */
2240395Sbostic 
2340395Sbostic #ifndef lint
24*40444Sbostic static char sccsid[] = "@(#)parse.c	5.6 (Berkeley) 03/12/90";
2540395Sbostic #endif /* not lint */
2640395Sbostic 
2740393Sbostic /*-
2840393Sbostic  * parse.c --
2940393Sbostic  *	Functions to parse a makefile.
3040393Sbostic  *
3140393Sbostic  *	One function, Parse_Init, must be called before any functions
3240393Sbostic  *	in this module are used. After that, the function Parse_File is the
3340393Sbostic  *	main entry point and controls most of the other functions in this
3440393Sbostic  *	module.
3540393Sbostic  *
3640393Sbostic  *	Most important structures are kept in Lsts. Directories for
3740393Sbostic  *	the #include "..." function are kept in the 'parseIncPath' Lst, while
3840393Sbostic  *	those for the #include <...> are kept in the 'sysIncPath' Lst. The
3940393Sbostic  *	targets currently being defined are kept in the 'targets' Lst.
4040393Sbostic  *
4140393Sbostic  *	The variables 'fname' and 'lineno' are used to track the name
4240393Sbostic  *	of the current file and the line number in that file so that error
4340393Sbostic  *	messages can be more meaningful.
4440393Sbostic  *
4540393Sbostic  * Interface:
4640393Sbostic  *	Parse_Init	    	    Initialization function which must be
4740393Sbostic  *	    	  	    	    called before anything else in this module
4840393Sbostic  *	    	  	    	    is used.
4940393Sbostic  *
5040393Sbostic  *	Parse_File	    	    Function used to parse a makefile. It must
5140393Sbostic  *	    	  	    	    be given the name of the file, which should
5240393Sbostic  *	    	  	    	    already have been opened, and a function
5340393Sbostic  *	    	  	    	    to call to read a character from the file.
5440393Sbostic  *
5540393Sbostic  *	Parse_IsVar	    	    Returns TRUE if the given line is a
5640393Sbostic  *	    	  	    	    variable assignment. Used by MainParseArgs
5740393Sbostic  *	    	  	    	    to determine if an argument is a target
5840393Sbostic  *	    	  	    	    or a variable assignment. Used internally
5940393Sbostic  *	    	  	    	    for pretty much the same thing...
6040393Sbostic  *
6140393Sbostic  *	Parse_Error	    	    Function called when an error occurs in
6240393Sbostic  *	    	  	    	    parsing. Used by the variable and
6340393Sbostic  *	    	  	    	    conditional modules.
6440393Sbostic  *	Parse_MainName	    	    Returns a Lst of the main target to create.
6540393Sbostic  */
6640393Sbostic 
67*40444Sbostic #include <varargs.h>
68*40444Sbostic #include <stdio.h>
69*40444Sbostic #include <ctype.h>
70*40444Sbostic #include "make.h"
71*40444Sbostic #include "buf.h"
7240393Sbostic 
7340393Sbostic /*
7440393Sbostic  * These values are returned by ParseEOF to tell Parse_File whether to
7540393Sbostic  * CONTINUE parsing, i.e. it had only reached the end of an include file,
7640393Sbostic  * or if it's DONE.
7740393Sbostic  */
7840393Sbostic #define	CONTINUE	1
7940393Sbostic #define	DONE		0
8040393Sbostic static int 	    ParseEOF();
8140393Sbostic 
8240393Sbostic static Lst     	    targets;	/* targets we're working on */
8340393Sbostic static Boolean	    inLine;	/* true if currently in a dependency
8440393Sbostic 				 * line or its commands */
8540393Sbostic 
8640393Sbostic static char    	    *fname;	/* name of current file (for errors) */
8740393Sbostic static int          lineno;	/* line number in current file */
8840393Sbostic static FILE   	    *curFILE; 	/* current makefile */
8940393Sbostic 
9040393Sbostic static int	    fatals = 0;
9140393Sbostic 
9240393Sbostic static GNode	    *mainNode;	/* The main target to create. This is the
9340393Sbostic 				 * first target on the first dependency
9440393Sbostic 				 * line in the first makefile */
9540393Sbostic /*
9640393Sbostic  * Definitions for handling #include specifications
9740393Sbostic  */
9840393Sbostic typedef struct IFile {
9940393Sbostic     char           *fname;	    /* name of previous file */
10040393Sbostic     int             lineno;	    /* saved line number */
10140393Sbostic     FILE *       F;		    /* the open stream */
10240393Sbostic }              	  IFile;
10340393Sbostic 
10440393Sbostic static Lst      includes;  	/* stack of IFiles generated by
10540393Sbostic 				 * #includes */
10640393Sbostic Lst         	parseIncPath;	/* list of directories for "..." includes */
10740393Sbostic Lst         	sysIncPath;	/* list of directories for <...> includes */
10840393Sbostic 
10940393Sbostic /*-
11040393Sbostic  * specType contains the SPECial TYPE of the current target. It is
11140393Sbostic  * Not if the target is unspecial. If it *is* special, however, the children
11240393Sbostic  * are linked as children of the parent but not vice versa. This variable is
11340393Sbostic  * set in ParseDoDependency
11440393Sbostic  */
11540393Sbostic typedef enum {
11640393Sbostic     Begin,  	    /* .BEGIN */
11740393Sbostic     Default,	    /* .DEFAULT */
11840393Sbostic     End,    	    /* .END */
11940393Sbostic     Ignore,	    /* .IGNORE */
12040393Sbostic     Includes,	    /* .INCLUDES */
12140393Sbostic     Interrupt,	    /* .INTERRUPT */
12240393Sbostic     Libs,	    /* .LIBS */
12340393Sbostic     MFlags,	    /* .MFLAGS or .MAKEFLAGS */
12440393Sbostic     Main,	    /* .MAIN and we don't have anything user-specified to
12540393Sbostic 		     * make */
12640393Sbostic     Not,	    /* Not special */
12740393Sbostic     NotParallel,    /* .NOTPARALELL */
12840393Sbostic     Null,   	    /* .NULL */
12940393Sbostic     Order,  	    /* .ORDER */
13040393Sbostic     Path,	    /* .PATH */
13140393Sbostic     Precious,	    /* .PRECIOUS */
13240393Sbostic     Shell,	    /* .SHELL */
13340393Sbostic     Silent,	    /* .SILENT */
13440393Sbostic     SingleShell,    /* .SINGLESHELL */
13540393Sbostic     Suffixes,	    /* .SUFFIXES */
13640393Sbostic     Attribute,	    /* Generic attribute */
13740393Sbostic } ParseSpecial;
13840393Sbostic 
13940393Sbostic ParseSpecial specType;
14040393Sbostic 
14140393Sbostic /*
14240393Sbostic  * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER
14340393Sbostic  * seen, then set to each successive source on the line.
14440393Sbostic  */
14540393Sbostic static GNode	*predecessor;
14640393Sbostic 
14740393Sbostic /*
14840393Sbostic  * The parseKeywords table is searched using binary search when deciding
14940393Sbostic  * if a target or source is special. The 'spec' field is the ParseSpecial
15040393Sbostic  * type of the keyword ("Not" if the keyword isn't special as a target) while
15140393Sbostic  * the 'op' field is the operator to apply to the list of targets if the
15240393Sbostic  * keyword is used as a source ("0" if the keyword isn't special as a source)
15340393Sbostic  */
15440393Sbostic static struct {
15540393Sbostic     char    	  *name;    	/* Name of keyword */
15640393Sbostic     ParseSpecial  spec;	    	/* Type when used as a target */
15740393Sbostic     int	    	  op;	    	/* Operator when used as a source */
15840393Sbostic } parseKeywords[] = {
15940393Sbostic { ".BEGIN", 	  Begin,    	0 },
16040393Sbostic { ".DEFAULT",	  Default,  	0 },
16140393Sbostic { ".DONTCARE",	  Attribute,   	OP_DONTCARE },
16240393Sbostic { ".END",   	  End,	    	0 },
16340393Sbostic { ".EXEC",	  Attribute,   	OP_EXEC },
16440393Sbostic { ".IGNORE",	  Ignore,   	OP_IGNORE },
16540393Sbostic { ".INCLUDES",	  Includes, 	0 },
16640393Sbostic { ".INTERRUPT",	  Interrupt,	0 },
16740393Sbostic { ".INVISIBLE",	  Attribute,   	OP_INVISIBLE },
16840393Sbostic { ".JOIN",  	  Attribute,   	OP_JOIN },
16940393Sbostic { ".LIBS",  	  Libs,	    	0 },
17040393Sbostic { ".MAIN",	  Main,		0 },
17140393Sbostic { ".MAKE",  	  Attribute,   	OP_MAKE },
17240393Sbostic { ".MAKEFLAGS",	  MFlags,   	0 },
17340393Sbostic { ".MFLAGS",	  MFlags,   	0 },
17440393Sbostic { ".NOTMAIN",	  Attribute,   	OP_NOTMAIN },
17540393Sbostic { ".NOTPARALLEL", NotParallel,	0 },
17640393Sbostic { ".NULL",  	  Null,	    	0 },
17740393Sbostic { ".ORDER", 	  Order,    	0 },
17840393Sbostic { ".PATH",	  Path,		0 },
17940393Sbostic { ".PRECIOUS",	  Precious, 	OP_PRECIOUS },
18040393Sbostic { ".RECURSIVE",	  Attribute,	OP_MAKE },
18140393Sbostic { ".SHELL", 	  Shell,    	0 },
18240393Sbostic { ".SILENT",	  Silent,   	OP_SILENT },
18340393Sbostic { ".SINGLESHELL", SingleShell,	0 },
18440393Sbostic { ".SUFFIXES",	  Suffixes, 	0 },
18540393Sbostic { ".USE",   	  Attribute,   	OP_USE },
18640393Sbostic };
18740424Sbostic 
18840393Sbostic /*-
18940393Sbostic  *----------------------------------------------------------------------
19040393Sbostic  * ParseFindKeyword --
19140393Sbostic  *	Look in the table of keywords for one matching the given string.
19240393Sbostic  *
19340393Sbostic  * Results:
19440393Sbostic  *	The index of the keyword, or -1 if it isn't there.
19540393Sbostic  *
19640393Sbostic  * Side Effects:
19740393Sbostic  *	None
19840393Sbostic  *----------------------------------------------------------------------
19940393Sbostic  */
20040393Sbostic static int
20140393Sbostic ParseFindKeyword (str)
20240393Sbostic     char	    *str;		/* String to find */
20340393Sbostic {
20440393Sbostic     register int    start,
20540393Sbostic 		    end,
20640393Sbostic 		    cur;
20740393Sbostic     register int    diff;
20840393Sbostic 
20940393Sbostic     start = 0;
21040393Sbostic     end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;
21140393Sbostic 
21240393Sbostic     do {
21340393Sbostic 	cur = start + ((end - start) / 2);
21440393Sbostic 	diff = strcmp (str, parseKeywords[cur].name);
21540393Sbostic 
21640393Sbostic 	if (diff == 0) {
21740393Sbostic 	    return (cur);
21840393Sbostic 	} else if (diff < 0) {
21940393Sbostic 	    end = cur - 1;
22040393Sbostic 	} else {
22140393Sbostic 	    start = cur + 1;
22240393Sbostic 	}
22340393Sbostic     } while (start <= end);
22440393Sbostic     return (-1);
22540393Sbostic }
22640424Sbostic 
22740393Sbostic /*-
22840393Sbostic  * Parse_Error  --
22940393Sbostic  *	Error message abort function for parsing. Prints out the context
23040393Sbostic  *	of the error (line number and file) as well as the message with
23140393Sbostic  *	two optional arguments.
23240393Sbostic  *
23340393Sbostic  * Results:
23440393Sbostic  *	None
23540393Sbostic  *
23640393Sbostic  * Side Effects:
23740393Sbostic  *	"fatals" is incremented if the level is PARSE_FATAL.
23840393Sbostic  */
239*40444Sbostic /* VARARGS */
24040393Sbostic void
241*40444Sbostic Parse_Error(type, va_alist)
242*40444Sbostic 	int type;		/* Error type (PARSE_WARNING, PARSE_FATAL) */
243*40444Sbostic 	va_dcl
24440393Sbostic {
245*40444Sbostic 	va_list ap;
246*40444Sbostic 	char *fmt;
24740393Sbostic 
248*40444Sbostic 	if (type == PARSE_WARNING && noWarnings)
249*40444Sbostic 		return;
250*40444Sbostic 	(void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno);
251*40444Sbostic 	if (type == PARSE_WARNING)
252*40444Sbostic 		(void)fprintf(stderr, "Warning: ");
253*40444Sbostic 	fmt = va_arg(ap, char *);
254*40444Sbostic 	(void)vfprintf(stderr, fmt, ap);
255*40444Sbostic 	va_end(ap);
256*40444Sbostic 	(void)fprintf(stderr, "\n");
257*40444Sbostic 	(void)fflush(stderr);
258*40444Sbostic 	if (type == PARSE_FATAL)
259*40444Sbostic 		fatals += 1;
26040393Sbostic }
26140424Sbostic 
26240393Sbostic /*-
26340393Sbostic  *---------------------------------------------------------------------
26440393Sbostic  * ParseLinkSrc  --
26540393Sbostic  *	Link the parent node to its new child. Used in a Lst_ForEach by
26640393Sbostic  *	ParseDoDependency. If the specType isn't 'Not', the parent
26740393Sbostic  *	isn't linked as a parent of the child.
26840393Sbostic  *
26940393Sbostic  * Results:
27040393Sbostic  *	Always = 0
27140393Sbostic  *
27240393Sbostic  * Side Effects:
27340393Sbostic  *	New elements are added to the parents list of cgn and the
27440393Sbostic  *	children list of cgn. the unmade field of pgn is updated
27540393Sbostic  *	to reflect the additional child.
27640393Sbostic  *---------------------------------------------------------------------
27740393Sbostic  */
27840393Sbostic static int
27940393Sbostic ParseLinkSrc (pgn, cgn)
28040393Sbostic     GNode          *pgn;	/* The parent node */
28140393Sbostic     GNode          *cgn;	/* The child node */
28240393Sbostic {
28340393Sbostic     if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) {
28440393Sbostic 	(void)Lst_AtEnd (pgn->children, (ClientData)cgn);
28540393Sbostic 	if (specType == Not) {
28640393Sbostic 	    (void)Lst_AtEnd (cgn->parents, (ClientData)pgn);
28740393Sbostic 	}
28840393Sbostic 	pgn->unmade += 1;
28940393Sbostic     }
29040393Sbostic     return (0);
29140393Sbostic }
29240424Sbostic 
29340393Sbostic /*-
29440393Sbostic  *---------------------------------------------------------------------
29540393Sbostic  * ParseDoOp  --
29640393Sbostic  *	Apply the parsed operator to the given target node. Used in a
29740393Sbostic  *	Lst_ForEach call by ParseDoDependency once all targets have
29840393Sbostic  *	been found and their operator parsed. If the previous and new
29940393Sbostic  *	operators are incompatible, a major error is taken.
30040393Sbostic  *
30140393Sbostic  * Results:
30240393Sbostic  *	Always 0
30340393Sbostic  *
30440393Sbostic  * Side Effects:
30540393Sbostic  *	The type field of the node is altered to reflect any new bits in
30640393Sbostic  *	the op.
30740393Sbostic  *---------------------------------------------------------------------
30840393Sbostic  */
30940393Sbostic static int
31040393Sbostic ParseDoOp (gn, op)
31140393Sbostic     GNode          *gn;		/* The node to which the operator is to be
31240393Sbostic 				 * applied */
31340393Sbostic     int             op;		/* The operator to apply */
31440393Sbostic {
31540393Sbostic     /*
31640393Sbostic      * If the dependency mask of the operator and the node don't match and
31740393Sbostic      * the node has actually had an operator applied to it before, and
31840393Sbostic      * the operator actually has some dependency information in it, complain.
31940393Sbostic      */
32040393Sbostic     if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
32140393Sbostic 	!OP_NOP(gn->type) && !OP_NOP(op))
32240393Sbostic     {
32340393Sbostic 	Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name);
32440393Sbostic 	return (1);
32540393Sbostic     }
32640393Sbostic 
32740393Sbostic     if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
32840393Sbostic 	/*
32940393Sbostic 	 * If the node was the object of a :: operator, we need to create a
33040393Sbostic 	 * new instance of it for the children and commands on this dependency
33140393Sbostic 	 * line. The new instance is placed on the 'cohorts' list of the
33240393Sbostic 	 * initial one (note the initial one is not on its own cohorts list)
33340393Sbostic 	 * and the new instance is linked to all parents of the initial
33440393Sbostic 	 * instance.
33540393Sbostic 	 */
33640393Sbostic 	register GNode	*cohort;
33740393Sbostic 	LstNode	    	ln;
33840393Sbostic 
33940393Sbostic 	cohort = Targ_NewGN(gn->name);
34040393Sbostic 	/*
34140393Sbostic 	 * Duplicate links to parents so graph traversal is simple. Perhaps
34240393Sbostic 	 * some type bits should be duplicated?
34340393Sbostic 	 *
34440393Sbostic 	 * Make the cohort invisible as well to avoid duplicating it into
34540393Sbostic 	 * other variables. True, parents of this target won't tend to do
34640393Sbostic 	 * anything with their local variables, but better safe than
34740393Sbostic 	 * sorry.
34840393Sbostic 	 */
34940393Sbostic 	Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort);
35040393Sbostic 	cohort->type = OP_DOUBLEDEP|OP_INVISIBLE;
35140393Sbostic 	(void)Lst_AtEnd(gn->cohorts, (ClientData)cohort);
35240393Sbostic 
35340393Sbostic 	/*
35440393Sbostic 	 * Replace the node in the targets list with the new copy
35540393Sbostic 	 */
35640393Sbostic 	ln = Lst_Member(targets, (ClientData)gn);
35740393Sbostic 	Lst_Replace(ln, (ClientData)cohort);
35840393Sbostic 	gn = cohort;
35940393Sbostic     }
36040393Sbostic     /*
36140393Sbostic      * We don't want to nuke any previous flags (whatever they were) so we
36240393Sbostic      * just OR the new operator into the old
36340393Sbostic      */
36440393Sbostic     gn->type |= op;
36540393Sbostic 
36640393Sbostic     return (0);
36740393Sbostic }
36840424Sbostic 
36940393Sbostic /*-
37040393Sbostic  *---------------------------------------------------------------------
37140393Sbostic  * ParseDoSrc  --
37240393Sbostic  *	Given the name of a source, figure out if it is an attribute
37340393Sbostic  *	and apply it to the targets if it is. Else decide if there is
37440393Sbostic  *	some attribute which should be applied *to* the source because
37540393Sbostic  *	of some special target and apply it if so. Otherwise, make the
37640393Sbostic  *	source be a child of the targets in the list 'targets'
37740393Sbostic  *
37840393Sbostic  * Results:
37940393Sbostic  *	None
38040393Sbostic  *
38140393Sbostic  * Side Effects:
38240393Sbostic  *	Operator bits may be added to the list of targets or to the source.
38340393Sbostic  *	The targets may have a new source added to their lists of children.
38440393Sbostic  *---------------------------------------------------------------------
38540393Sbostic  */
38640393Sbostic static void
38740393Sbostic ParseDoSrc (tOp, src)
38840393Sbostic     int		tOp;	/* operator (if any) from special targets */
38940393Sbostic     char	*src;	/* name of the source to handle */
39040393Sbostic {
39140393Sbostic     int		op;	/* operator (if any) from special source */
39240393Sbostic     GNode	*gn;
39340393Sbostic 
39440393Sbostic     op = 0;
39540393Sbostic     if (*src == '.' && isupper (src[1])) {
39640393Sbostic 	int keywd = ParseFindKeyword(src);
39740393Sbostic 	if (keywd != -1) {
39840393Sbostic 	    op = parseKeywords[keywd].op;
39940393Sbostic 	}
40040393Sbostic     }
40140393Sbostic     if (op != 0) {
40240393Sbostic 	Lst_ForEach (targets, ParseDoOp, (ClientData)op);
40340393Sbostic     } else if (specType == Main) {
40440393Sbostic 	/*
40540393Sbostic 	 * If we have noted the existence of a .MAIN, it means we need
40640393Sbostic 	 * to add the sources of said target to the list of things
40740393Sbostic 	 * to create. The string 'src' is likely to be free, so we
40840393Sbostic 	 * must make a new copy of it. Note that this will only be
40940393Sbostic 	 * invoked if the user didn't specify a target on the command
41040393Sbostic 	 * line. This is to allow #ifmake's to succeed, or something...
41140393Sbostic 	 */
41240424Sbostic 	(void) Lst_AtEnd (create, (ClientData)strdup(src));
41340393Sbostic 	/*
41440393Sbostic 	 * Add the name to the .TARGETS variable as well, so the user cna
41540393Sbostic 	 * employ that, if desired.
41640393Sbostic 	 */
41740393Sbostic 	Var_Append(".TARGETS", src, VAR_GLOBAL);
41840393Sbostic     } else if (specType == Order) {
41940393Sbostic 	/*
42040393Sbostic 	 * Create proper predecessor/successor links between the previous
42140393Sbostic 	 * source and the current one.
42240393Sbostic 	 */
42340393Sbostic 	gn = Targ_FindNode(src, TARG_CREATE);
42440393Sbostic 	if (predecessor != NILGNODE) {
42540393Sbostic 	    (void)Lst_AtEnd(predecessor->successors, (ClientData)gn);
42640393Sbostic 	    (void)Lst_AtEnd(gn->preds, (ClientData)predecessor);
42740393Sbostic 	}
42840393Sbostic 	/*
42940393Sbostic 	 * The current source now becomes the predecessor for the next one.
43040393Sbostic 	 */
43140393Sbostic 	predecessor = gn;
43240393Sbostic     } else {
43340393Sbostic 	/*
43440393Sbostic 	 * If the source is not an attribute, we need to find/create
43540393Sbostic 	 * a node for it. After that we can apply any operator to it
43640393Sbostic 	 * from a special target or link it to its parents, as
43740393Sbostic 	 * appropriate.
43840393Sbostic 	 *
43940393Sbostic 	 * In the case of a source that was the object of a :: operator,
44040393Sbostic 	 * the attribute is applied to all of its instances (as kept in
44140393Sbostic 	 * the 'cohorts' list of the node) or all the cohorts are linked
44240393Sbostic 	 * to all the targets.
44340393Sbostic 	 */
44440393Sbostic 	gn = Targ_FindNode (src, TARG_CREATE);
44540393Sbostic 	if (tOp) {
44640393Sbostic 	    gn->type |= tOp;
44740393Sbostic 	} else {
44840393Sbostic 	    Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn);
44940393Sbostic 	}
45040393Sbostic 	if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
45140393Sbostic 	    register GNode  	*cohort;
45240393Sbostic 	    register LstNode	ln;
45340393Sbostic 
45440393Sbostic 	    for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){
45540393Sbostic 		cohort = (GNode *)Lst_Datum(ln);
45640393Sbostic 		if (tOp) {
45740393Sbostic 		    cohort->type |= tOp;
45840393Sbostic 		} else {
45940393Sbostic 		    Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort);
46040393Sbostic 		}
46140393Sbostic 	    }
46240393Sbostic 	}
46340393Sbostic     }
46440393Sbostic }
46540424Sbostic 
46640393Sbostic /*-
46740393Sbostic  *-----------------------------------------------------------------------
46840393Sbostic  * ParseFindMain --
46940393Sbostic  *	Find a real target in the list and set it to be the main one.
47040393Sbostic  *	Called by ParseDoDependency when a main target hasn't been found
47140393Sbostic  *	yet.
47240393Sbostic  *
47340393Sbostic  * Results:
47440393Sbostic  *	0 if main not found yet, 1 if it is.
47540393Sbostic  *
47640393Sbostic  * Side Effects:
47740393Sbostic  *	mainNode is changed and Targ_SetMain is called.
47840393Sbostic  *
47940393Sbostic  *-----------------------------------------------------------------------
48040393Sbostic  */
48140393Sbostic static int
48240393Sbostic ParseFindMain(gn)
48340393Sbostic     GNode   	  *gn;	    /* Node to examine */
48440393Sbostic {
48540393Sbostic     if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) {
48640393Sbostic 	mainNode = gn;
48740393Sbostic 	Targ_SetMain(gn);
48840393Sbostic 	return (1);
48940393Sbostic     } else {
49040393Sbostic 	return (0);
49140393Sbostic     }
49240393Sbostic }
49340424Sbostic 
49440393Sbostic /*-
49540393Sbostic  *-----------------------------------------------------------------------
49640393Sbostic  * ParseAddDir --
49740393Sbostic  *	Front-end for Dir_AddDir to make sure Lst_ForEach keeps going
49840393Sbostic  *
49940393Sbostic  * Results:
50040393Sbostic  *	=== 0
50140393Sbostic  *
50240393Sbostic  * Side Effects:
50340393Sbostic  *	See Dir_AddDir.
50440393Sbostic  *
50540393Sbostic  *-----------------------------------------------------------------------
50640393Sbostic  */
50740393Sbostic static int
50840393Sbostic ParseAddDir(path, name)
50940393Sbostic     Lst	    path;
51040393Sbostic     char    *name;
51140393Sbostic {
51240393Sbostic     Dir_AddDir(path, name);
51340393Sbostic     return(0);
51440393Sbostic }
51540424Sbostic 
51640393Sbostic /*-
51740393Sbostic  *-----------------------------------------------------------------------
51840393Sbostic  * ParseClearPath --
51940393Sbostic  *	Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going
52040393Sbostic  *
52140393Sbostic  * Results:
52240393Sbostic  *	=== 0
52340393Sbostic  *
52440393Sbostic  * Side Effects:
52540393Sbostic  *	See Dir_ClearPath
52640393Sbostic  *
52740393Sbostic  *-----------------------------------------------------------------------
52840393Sbostic  */
52940393Sbostic static int
53040393Sbostic ParseClearPath(path)
53140393Sbostic     Lst	    path;
53240393Sbostic {
53340393Sbostic     Dir_ClearPath(path);
53440393Sbostic     return(0);
53540393Sbostic }
53640424Sbostic 
53740393Sbostic /*-
53840393Sbostic  *---------------------------------------------------------------------
53940393Sbostic  * ParseDoDependency  --
54040393Sbostic  *	Parse the dependency line in line.
54140393Sbostic  *
54240393Sbostic  * Results:
54340393Sbostic  *	None
54440393Sbostic  *
54540393Sbostic  * Side Effects:
54640393Sbostic  *	The nodes of the sources are linked as children to the nodes of the
54740393Sbostic  *	targets. Some nodes may be created.
54840393Sbostic  *
54940393Sbostic  *	We parse a dependency line by first extracting words from the line and
55040393Sbostic  * finding nodes in the list of all targets with that name. This is done
55140393Sbostic  * until a character is encountered which is an operator character. Currently
55240393Sbostic  * these are only ! and :. At this point the operator is parsed and the
55340393Sbostic  * pointer into the line advanced until the first source is encountered.
55440393Sbostic  * 	The parsed operator is applied to each node in the 'targets' list,
55540393Sbostic  * which is where the nodes found for the targets are kept, by means of
55640393Sbostic  * the ParseDoOp function.
55740393Sbostic  *	The sources are read in much the same way as the targets were except
55840393Sbostic  * that now they are expanded using the wildcarding scheme of the C-Shell
55940393Sbostic  * and all instances of the resulting words in the list of all targets
56040393Sbostic  * are found. Each of the resulting nodes is then linked to each of the
56140393Sbostic  * targets as one of its children.
56240393Sbostic  *	Certain targets are handled specially. These are the ones detailed
56340393Sbostic  * by the specType variable.
56440393Sbostic  *	The storing of transformation rules is also taken care of here.
56540393Sbostic  * A target is recognized as a transformation rule by calling
56640393Sbostic  * Suff_IsTransform. If it is a transformation rule, its node is gotten
56740393Sbostic  * from the suffix module via Suff_AddTransform rather than the standard
56840393Sbostic  * Targ_FindNode in the target module.
56940393Sbostic  *---------------------------------------------------------------------
57040393Sbostic  */
57140393Sbostic static void
57240393Sbostic ParseDoDependency (line)
57340393Sbostic     char           *line;	/* the line to parse */
57440393Sbostic {
57540393Sbostic     register char  *cp;		/* our current position */
57640393Sbostic     register GNode *gn;		/* a general purpose temporary node */
57740393Sbostic     register int    op;		/* the operator on the line */
57840393Sbostic     char            savec;	/* a place to save a character */
57940393Sbostic     Lst    	    paths;   	/* List of search paths to alter when parsing
58040393Sbostic 				 * a list of .PATH targets */
58140393Sbostic     int	    	    tOp;    	/* operator from special target */
58240393Sbostic     Lst	    	    sources;	/* list of source names after expansion */
58340393Sbostic     Lst 	    curTargs;	/* list of target names to be found and added
58440393Sbostic 				 * to the targets list */
58540393Sbostic 
58640393Sbostic     tOp = 0;
58740393Sbostic 
58840393Sbostic     specType = Not;
58940393Sbostic     paths = (Lst)NULL;
59040393Sbostic 
59140393Sbostic     curTargs = Lst_Init(FALSE);
59240393Sbostic 
59340393Sbostic     do {
59440393Sbostic 	for (cp = line;
59540393Sbostic 	     *cp && !isspace (*cp) &&
59640393Sbostic 	     (*cp != '!') && (*cp != ':') && (*cp != '(');
59740393Sbostic 	     cp++)
59840393Sbostic 	{
59940393Sbostic 	    if (*cp == '$') {
60040393Sbostic 		/*
60140393Sbostic 		 * Must be a dynamic source (would have been expanded
60240393Sbostic 		 * otherwise), so call the Var module to parse the puppy
60340393Sbostic 		 * so we can safely advance beyond it...There should be
60440393Sbostic 		 * no errors in this, as they would have been discovered
60540393Sbostic 		 * in the initial Var_Subst and we wouldn't be here.
60640393Sbostic 		 */
60740393Sbostic 		int 	length;
60840393Sbostic 		Boolean	freeIt;
60940393Sbostic 		char	*result;
61040393Sbostic 
61140393Sbostic 		result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);
61240393Sbostic 
61340393Sbostic 		if (freeIt) {
61440393Sbostic 		    free(result);
61540393Sbostic 		}
61640393Sbostic 		cp += length-1;
61740393Sbostic 	    }
61840393Sbostic 	    continue;
61940393Sbostic 	}
62040393Sbostic 	if (*cp == '(') {
62140393Sbostic 	    /*
62240393Sbostic 	     * Archives must be handled specially to make sure the OP_ARCHV
62340393Sbostic 	     * flag is set in their 'type' field, for one thing, and because
62440393Sbostic 	     * things like "archive(file1.o file2.o file3.o)" are permissible.
62540393Sbostic 	     * Arch_ParseArchive will set 'line' to be the first non-blank
62640393Sbostic 	     * after the archive-spec. It creates/finds nodes for the members
62740393Sbostic 	     * and places them on the given list, returning SUCCESS if all
62840393Sbostic 	     * went well and FAILURE if there was an error in the
62940393Sbostic 	     * specification. On error, line should remain untouched.
63040393Sbostic 	     */
63140393Sbostic 	    if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) {
63240393Sbostic 		Parse_Error (PARSE_FATAL,
63340393Sbostic 			     "Error in archive specification: \"%s\"", line);
63440393Sbostic 		return;
63540393Sbostic 	    } else {
63640393Sbostic 		continue;
63740393Sbostic 	    }
63840393Sbostic 	}
63940393Sbostic 	savec = *cp;
64040393Sbostic 
64140393Sbostic 	if (!*cp) {
64240393Sbostic 	    /*
64340393Sbostic 	     * Ending a dependency line without an operator is a Bozo
64440393Sbostic 	     * no-no
64540393Sbostic 	     */
64640393Sbostic 	    Parse_Error (PARSE_FATAL, "Need an operator");
64740393Sbostic 	    return;
64840393Sbostic 	}
64940393Sbostic 	*cp = '\0';
65040393Sbostic 	/*
65140393Sbostic 	 * Have a word in line. See if it's a special target and set
65240393Sbostic 	 * specType to match it.
65340393Sbostic 	 */
65440393Sbostic 	if (*line == '.' && isupper (line[1])) {
65540393Sbostic 	    /*
65640393Sbostic 	     * See if the target is a special target that must have it
65740393Sbostic 	     * or its sources handled specially.
65840393Sbostic 	     */
65940393Sbostic 	    int keywd = ParseFindKeyword(line);
66040393Sbostic 	    if (keywd != -1) {
66140393Sbostic 		if (specType == Path && parseKeywords[keywd].spec != Path) {
66240393Sbostic 		    Parse_Error(PARSE_FATAL, "Mismatched special targets");
66340393Sbostic 		    return;
66440393Sbostic 		}
66540393Sbostic 
66640393Sbostic 		specType = parseKeywords[keywd].spec;
66740393Sbostic 		tOp = parseKeywords[keywd].op;
66840393Sbostic 
66940393Sbostic 		/*
67040393Sbostic 		 * Certain special targets have special semantics:
67140393Sbostic 		 *	.PATH		Have to set the dirSearchPath
67240393Sbostic 		 *			variable too
67340393Sbostic 		 *	.MAIN		Its sources are only used if
67440393Sbostic 		 *			nothing has been specified to
67540393Sbostic 		 *			create.
67640393Sbostic 		 *	.DEFAULT    	Need to create a node to hang
67740393Sbostic 		 *			commands on, but we don't want
67840393Sbostic 		 *			it in the graph, nor do we want
67940393Sbostic 		 *			it to be the Main Target, so we
68040393Sbostic 		 *			create it, set OP_NOTMAIN and
68140393Sbostic 		 *			add it to the list, setting
68240393Sbostic 		 *			DEFAULT to the new node for
68340393Sbostic 		 *			later use. We claim the node is
68440393Sbostic 		 *	    	    	A transformation rule to make
68540393Sbostic 		 *	    	    	life easier later, when we'll
68640393Sbostic 		 *	    	    	use Make_HandleUse to actually
68740393Sbostic 		 *	    	    	apply the .DEFAULT commands.
68840393Sbostic 		 *	.BEGIN
68940393Sbostic 		 *	.END
69040393Sbostic 		 *	.INTERRUPT  	Are not to be considered the
69140393Sbostic 		 *			main target.
69240393Sbostic 		 *  	.NOTPARALLEL	Make only one target at a time.
69340393Sbostic 		 *  	.SINGLESHELL	Create a shell for each command.
69440393Sbostic 		 *  	.ORDER	    	Must set initial predecessor to NIL
69540393Sbostic 		 */
69640393Sbostic 		switch (specType) {
69740393Sbostic 		    case Path:
69840393Sbostic 			if (paths == NULL) {
69940393Sbostic 			    paths = Lst_Init(FALSE);
70040393Sbostic 			}
70140393Sbostic 			(void)Lst_AtEnd(paths, (ClientData)dirSearchPath);
70240393Sbostic 			break;
70340393Sbostic 		    case Main:
70440393Sbostic 			if (!Lst_IsEmpty(create)) {
70540393Sbostic 			    specType = Not;
70640393Sbostic 			}
70740393Sbostic 			break;
70840393Sbostic 		    case Begin:
70940393Sbostic 		    case End:
71040393Sbostic 		    case Interrupt:
71140393Sbostic 			gn = Targ_FindNode(line, TARG_CREATE);
71240393Sbostic 			gn->type |= OP_NOTMAIN;
71340393Sbostic 			(void)Lst_AtEnd(targets, (ClientData)gn);
71440393Sbostic 			break;
71540393Sbostic 		    case Default:
71640393Sbostic 			gn = Targ_NewGN(".DEFAULT");
71740393Sbostic 			gn->type |= (OP_NOTMAIN|OP_TRANSFORM);
71840393Sbostic 			(void)Lst_AtEnd(targets, (ClientData)gn);
71940393Sbostic 			DEFAULT = gn;
72040393Sbostic 			break;
72140393Sbostic 		    case NotParallel:
72240393Sbostic 		    {
72340393Sbostic 			extern int  maxJobs;
72440393Sbostic 
72540393Sbostic 			maxJobs = 1;
72640393Sbostic 			break;
72740393Sbostic 		    }
72840393Sbostic 		    case SingleShell:
729*40444Sbostic 			/* backwards = 1; */
73040393Sbostic 			break;
73140393Sbostic 		    case Order:
73240393Sbostic 			predecessor = NILGNODE;
73340393Sbostic 			break;
73440393Sbostic 		}
73540393Sbostic 	    } else if (strncmp (line, ".PATH", 5) == 0) {
73640393Sbostic 		/*
73740393Sbostic 		 * .PATH<suffix> has to be handled specially.
73840393Sbostic 		 * Call on the suffix module to give us a path to
73940393Sbostic 		 * modify.
74040393Sbostic 		 */
74140393Sbostic 		Lst 	path;
74240393Sbostic 
74340393Sbostic 		specType = Path;
74440393Sbostic 		path = Suff_GetPath (&line[5]);
74540393Sbostic 		if (path == NILLST) {
74640393Sbostic 		    Parse_Error (PARSE_FATAL,
74740393Sbostic 				 "Suffix '%s' not defined (yet)",
74840393Sbostic 				 &line[5]);
74940393Sbostic 		    return;
75040393Sbostic 		} else {
75140393Sbostic 		    if (paths == (Lst)NULL) {
75240393Sbostic 			paths = Lst_Init(FALSE);
75340393Sbostic 		    }
75440393Sbostic 		    (void)Lst_AtEnd(paths, (ClientData)path);
75540393Sbostic 		}
75640393Sbostic 	    }
75740393Sbostic 	}
75840393Sbostic 
75940393Sbostic 	/*
76040393Sbostic 	 * Have word in line. Get or create its node and stick it at
76140393Sbostic 	 * the end of the targets list
76240393Sbostic 	 */
76340393Sbostic 	if ((specType == Not) && (*line != '\0')) {
76440393Sbostic 	    if (Dir_HasWildcards(line)) {
76540393Sbostic 		/*
76640393Sbostic 		 * Targets are to be sought only in the current directory,
76740393Sbostic 		 * so create an empty path for the thing. Note we need to
76840393Sbostic 		 * use Dir_Destroy in the destruction of the path as the
76940393Sbostic 		 * Dir module could have added a directory to the path...
77040393Sbostic 		 */
77140393Sbostic 		Lst	    emptyPath = Lst_Init(FALSE);
77240393Sbostic 
77340393Sbostic 		Dir_Expand(line, emptyPath, curTargs);
77440393Sbostic 
77540393Sbostic 		Lst_Destroy(emptyPath, Dir_Destroy);
77640393Sbostic 	    } else {
77740393Sbostic 		/*
77840393Sbostic 		 * No wildcards, but we want to avoid code duplication,
77940393Sbostic 		 * so create a list with the word on it.
78040393Sbostic 		 */
78140393Sbostic 		(void)Lst_AtEnd(curTargs, (ClientData)line);
78240393Sbostic 	    }
78340393Sbostic 
78440393Sbostic 	    while(!Lst_IsEmpty(curTargs)) {
78540393Sbostic 		char	*targName = (char *)Lst_DeQueue(curTargs);
78640393Sbostic 
78740393Sbostic 		if (!Suff_IsTransform (targName)) {
78840393Sbostic 		    gn = Targ_FindNode (targName, TARG_CREATE);
78940393Sbostic 		} else {
79040393Sbostic 		    gn = Suff_AddTransform (targName);
79140393Sbostic 		}
79240393Sbostic 
79340393Sbostic 		(void)Lst_AtEnd (targets, (ClientData)gn);
79440393Sbostic 	    }
79540393Sbostic 	} else if (specType == Path && *line != '.' && *line != '\0') {
79640393Sbostic 	    Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
79740393Sbostic 	}
79840393Sbostic 
79940393Sbostic 	*cp = savec;
80040393Sbostic 	/*
80140393Sbostic 	 * If it is a special type and not .PATH, it's the only target we
80240393Sbostic 	 * allow on this line...
80340393Sbostic 	 */
80440393Sbostic 	if (specType != Not && specType != Path) {
80540393Sbostic 	    Boolean warn = FALSE;
80640393Sbostic 
80740393Sbostic 	    while ((*cp != '!') && (*cp != ':') && *cp) {
80840393Sbostic 		if (*cp != ' ' && *cp != '\t') {
80940393Sbostic 		    warn = TRUE;
81040393Sbostic 		}
81140393Sbostic 		cp++;
81240393Sbostic 	    }
81340393Sbostic 	    if (warn) {
81440393Sbostic 		Parse_Error(PARSE_WARNING, "Extra target ignored");
81540393Sbostic 	    }
81640393Sbostic 	} else {
81740393Sbostic 	    while (*cp && isspace (*cp)) {
81840393Sbostic 		cp++;
81940393Sbostic 	    }
82040393Sbostic 	}
82140393Sbostic 	line = cp;
82240393Sbostic     } while ((*line != '!') && (*line != ':') && *line);
82340393Sbostic 
82440393Sbostic     /*
82540393Sbostic      * Don't need the list of target names anymore...
82640393Sbostic      */
82740393Sbostic     Lst_Destroy(curTargs, NOFREE);
82840393Sbostic 
82940393Sbostic     if (!Lst_IsEmpty(targets)) {
83040393Sbostic 	switch(specType) {
83140393Sbostic 	    default:
83240393Sbostic 		Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");
83340393Sbostic 		break;
83440393Sbostic 	    case Default:
83540393Sbostic 	    case Begin:
83640393Sbostic 	    case End:
83740393Sbostic 	    case Interrupt:
83840393Sbostic 		/*
83940393Sbostic 		 * These four create nodes on which to hang commands, so
84040393Sbostic 		 * targets shouldn't be empty...
84140393Sbostic 		 */
84240393Sbostic 	    case Not:
84340393Sbostic 		/*
84440393Sbostic 		 * Nothing special here -- targets can be empty if it wants.
84540393Sbostic 		 */
84640393Sbostic 		break;
84740393Sbostic 	}
84840393Sbostic     }
84940393Sbostic 
85040393Sbostic     /*
85140393Sbostic      * Have now parsed all the target names. Must parse the operator next. The
85240393Sbostic      * result is left in  op .
85340393Sbostic      */
85440393Sbostic     if (*cp == '!') {
85540393Sbostic 	op = OP_FORCE;
85640393Sbostic     } else if (*cp == ':') {
85740393Sbostic 	if (cp[1] == ':') {
85840393Sbostic 	    op = OP_DOUBLEDEP;
85940393Sbostic 	    cp++;
86040393Sbostic 	} else {
86140393Sbostic 	    op = OP_DEPENDS;
86240393Sbostic 	}
86340393Sbostic     } else {
86440393Sbostic 	Parse_Error (PARSE_FATAL, "Missing dependency operator");
86540393Sbostic 	return;
86640393Sbostic     }
86740393Sbostic 
86840393Sbostic     cp++;			/* Advance beyond operator */
86940393Sbostic 
87040393Sbostic     Lst_ForEach (targets, ParseDoOp, (ClientData)op);
87140393Sbostic 
87240393Sbostic     /*
87340393Sbostic      * Get to the first source
87440393Sbostic      */
87540393Sbostic     while (*cp && isspace (*cp)) {
87640393Sbostic 	cp++;
87740393Sbostic     }
87840393Sbostic     line = cp;
87940393Sbostic 
88040393Sbostic     /*
88140393Sbostic      * Several special targets take different actions if present with no
88240393Sbostic      * sources:
88340393Sbostic      *	a .SUFFIXES line with no sources clears out all old suffixes
88440393Sbostic      *	a .PRECIOUS line makes all targets precious
88540393Sbostic      *	a .IGNORE line ignores errors for all targets
88640393Sbostic      *	a .SILENT line creates silence when making all targets
88740393Sbostic      *	a .PATH removes all directories from the search path(s).
88840393Sbostic      */
88940393Sbostic     if (!*line) {
89040393Sbostic 	switch (specType) {
89140393Sbostic 	    case Suffixes:
89240393Sbostic 		Suff_ClearSuffixes ();
89340393Sbostic 		break;
89440393Sbostic 	    case Precious:
89540393Sbostic 		allPrecious = TRUE;
89640393Sbostic 		break;
89740393Sbostic 	    case Ignore:
89840393Sbostic 		ignoreErrors = TRUE;
89940393Sbostic 		break;
90040393Sbostic 	    case Silent:
90140393Sbostic 		beSilent = TRUE;
90240393Sbostic 		break;
90340393Sbostic 	    case Path:
90440393Sbostic 		Lst_ForEach(paths, ParseClearPath, (ClientData)NULL);
90540393Sbostic 		break;
90640393Sbostic 	}
90740393Sbostic     } else if (specType == MFlags) {
90840393Sbostic 	/*
90940393Sbostic 	 * Call on functions in main.c to deal with these arguments and
91040393Sbostic 	 * set the initial character to a null-character so the loop to
91140393Sbostic 	 * get sources won't get anything
91240393Sbostic 	 */
91340393Sbostic 	Main_ParseArgLine (line);
91440393Sbostic 	*line = '\0';
91540393Sbostic     } else if (specType == Shell) {
91640393Sbostic 	if (Job_ParseShell (line) != SUCCESS) {
91740393Sbostic 	    Parse_Error (PARSE_FATAL, "improper shell specification");
91840393Sbostic 	    return;
91940393Sbostic 	}
92040393Sbostic 	*line = '\0';
92140393Sbostic     } else if ((specType == NotParallel) || (specType == SingleShell)) {
92240393Sbostic 	*line = '\0';
92340393Sbostic     }
92440393Sbostic 
92540393Sbostic     /*
92640393Sbostic      * NOW GO FOR THE SOURCES
92740393Sbostic      */
92840393Sbostic     if ((specType == Suffixes) || (specType == Path) ||
92940393Sbostic 	(specType == Includes) || (specType == Libs) ||
93040439Sbostic 	(specType == Null))
93140393Sbostic     {
93240393Sbostic 	while (*line) {
93340393Sbostic 	    /*
93440393Sbostic 	     * If the target was one that doesn't take files as its sources
93540393Sbostic 	     * but takes something like suffixes, we take each
93640393Sbostic 	     * space-separated word on the line as a something and deal
93740393Sbostic 	     * with it accordingly.
93840393Sbostic 	     *
93940393Sbostic 	     * If the target was .SUFFIXES, we take each source as a
94040393Sbostic 	     * suffix and add it to the list of suffixes maintained by the
94140393Sbostic 	     * Suff module.
94240393Sbostic 	     *
94340393Sbostic 	     * If the target was a .PATH, we add the source as a directory
94440393Sbostic 	     * to search on the search path.
94540393Sbostic 	     *
94640393Sbostic 	     * If it was .INCLUDES, the source is taken to be the suffix of
94740393Sbostic 	     * files which will be #included and whose search path should
94840393Sbostic 	     * be present in the .INCLUDES variable.
94940393Sbostic 	     *
95040393Sbostic 	     * If it was .LIBS, the source is taken to be the suffix of
95140393Sbostic 	     * files which are considered libraries and whose search path
95240393Sbostic 	     * should be present in the .LIBS variable.
95340393Sbostic 	     *
95440393Sbostic 	     * If it was .NULL, the source is the suffix to use when a file
95540393Sbostic 	     * has no valid suffix.
95640393Sbostic 	     */
95740393Sbostic 	    char  savec;
95840393Sbostic 	    while (*cp && !isspace (*cp)) {
95940393Sbostic 		cp++;
96040393Sbostic 	    }
96140393Sbostic 	    savec = *cp;
96240393Sbostic 	    *cp = '\0';
96340393Sbostic 	    switch (specType) {
96440393Sbostic 		case Suffixes:
96540393Sbostic 		    Suff_AddSuffix (line);
96640393Sbostic 		    break;
96740393Sbostic 		case Path:
96840393Sbostic 		    Lst_ForEach(paths, ParseAddDir, (ClientData)line);
96940393Sbostic 		    break;
97040393Sbostic 		case Includes:
97140393Sbostic 		    Suff_AddInclude (line);
97240393Sbostic 		    break;
97340393Sbostic 		case Libs:
97440393Sbostic 		    Suff_AddLib (line);
97540393Sbostic 		    break;
97640393Sbostic 		case Null:
97740393Sbostic 		    Suff_SetNull (line);
97840393Sbostic 		    break;
97940393Sbostic 	    }
98040393Sbostic 	    *cp = savec;
98140393Sbostic 	    if (savec != '\0') {
98240393Sbostic 		cp++;
98340393Sbostic 	    }
98440393Sbostic 	    while (*cp && isspace (*cp)) {
98540393Sbostic 		cp++;
98640393Sbostic 	    }
98740393Sbostic 	    line = cp;
98840393Sbostic 	}
98940393Sbostic 	if (paths) {
99040393Sbostic 	    Lst_Destroy(paths, NOFREE);
99140393Sbostic 	}
99240393Sbostic     } else {
99340393Sbostic 	while (*line) {
99440393Sbostic 	    /*
99540393Sbostic 	     * The targets take real sources, so we must beware of archive
99640393Sbostic 	     * specifications (i.e. things with left parentheses in them)
99740393Sbostic 	     * and handle them accordingly.
99840393Sbostic 	     */
99940393Sbostic 	    while (*cp && !isspace (*cp)) {
100040393Sbostic 		if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) {
100140393Sbostic 		    /*
100240393Sbostic 		     * Only stop for a left parenthesis if it isn't at the
100340393Sbostic 		     * start of a word (that'll be for variable changes
100440393Sbostic 		     * later) and isn't preceded by a dollar sign (a dynamic
100540393Sbostic 		     * source).
100640393Sbostic 		     */
100740393Sbostic 		    break;
100840393Sbostic 		} else {
100940393Sbostic 		    cp++;
101040393Sbostic 		}
101140393Sbostic 	    }
101240393Sbostic 
101340393Sbostic 	    if (*cp == '(') {
101440393Sbostic 		GNode	  *gn;
101540393Sbostic 
101640393Sbostic 		sources = Lst_Init (FALSE);
101740393Sbostic 		if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) {
101840393Sbostic 		    Parse_Error (PARSE_FATAL,
101940393Sbostic 				 "Error in source archive spec \"%s\"", line);
102040393Sbostic 		    return;
102140393Sbostic 		}
102240393Sbostic 
102340393Sbostic 		while (!Lst_IsEmpty (sources)) {
102440393Sbostic 		    gn = (GNode *) Lst_DeQueue (sources);
102540393Sbostic 		    ParseDoSrc (tOp, gn->name);
102640393Sbostic 		}
102740393Sbostic 		Lst_Destroy (sources, NOFREE);
102840393Sbostic 		cp = line;
102940393Sbostic 	    } else {
103040393Sbostic 		if (*cp) {
103140393Sbostic 		    *cp = '\0';
103240393Sbostic 		    cp += 1;
103340393Sbostic 		}
103440393Sbostic 
103540393Sbostic 		ParseDoSrc (tOp, line);
103640393Sbostic 	    }
103740393Sbostic 	    while (*cp && isspace (*cp)) {
103840393Sbostic 		cp++;
103940393Sbostic 	    }
104040393Sbostic 	    line = cp;
104140393Sbostic 	}
104240393Sbostic     }
104340393Sbostic 
104440393Sbostic     if (mainNode == NILGNODE) {
104540393Sbostic 	/*
104640393Sbostic 	 * If we have yet to decide on a main target to make, in the
104740393Sbostic 	 * absence of any user input, we want the first target on
104840393Sbostic 	 * the first dependency line that is actually a real target
104940393Sbostic 	 * (i.e. isn't a .USE or .EXEC rule) to be made.
105040393Sbostic 	 */
105140393Sbostic 	Lst_ForEach (targets, ParseFindMain, (ClientData)0);
105240393Sbostic     }
105340393Sbostic 
105440393Sbostic }
105540424Sbostic 
105640393Sbostic /*-
105740393Sbostic  *---------------------------------------------------------------------
105840393Sbostic  * Parse_IsVar  --
105940393Sbostic  *	Return TRUE if the passed line is a variable assignment. A variable
106040393Sbostic  *	assignment consists of a single word followed by optional whitespace
106140393Sbostic  *	followed by either a += or an = operator.
106240393Sbostic  *	This function is used both by the Parse_File function and main when
106340393Sbostic  *	parsing the command-line arguments.
106440393Sbostic  *
106540393Sbostic  * Results:
106640393Sbostic  *	TRUE if it is. FALSE if it ain't
106740393Sbostic  *
106840393Sbostic  * Side Effects:
106940393Sbostic  *	none
107040393Sbostic  *---------------------------------------------------------------------
107140393Sbostic  */
107240393Sbostic Boolean
107340393Sbostic Parse_IsVar (line)
107440393Sbostic     register char  *line;	/* the line to check */
107540393Sbostic {
107640393Sbostic     register Boolean wasSpace = FALSE;	/* set TRUE if found a space */
107740393Sbostic     register Boolean haveName = FALSE;	/* Set TRUE if have a variable name */
107840393Sbostic 
107940393Sbostic     /*
108040393Sbostic      * Skip to variable name
108140393Sbostic      */
108240393Sbostic     while ((*line == ' ') || (*line == '\t')) {
108340393Sbostic 	line++;
108440393Sbostic     }
108540393Sbostic 
108640393Sbostic     while (*line != '=') {
108740393Sbostic 	if (*line == '\0') {
108840393Sbostic 	    /*
108940393Sbostic 	     * end-of-line -- can't be a variable assignment.
109040393Sbostic 	     */
109140393Sbostic 	    return (FALSE);
109240393Sbostic 	} else if ((*line == ' ') || (*line == '\t')) {
109340393Sbostic 	    /*
109440393Sbostic 	     * there can be as much white space as desired so long as there is
109540393Sbostic 	     * only one word before the operator
109640393Sbostic 	     */
109740393Sbostic 	    wasSpace = TRUE;
109840393Sbostic 	} else if (wasSpace && haveName) {
109940393Sbostic 	    /*
110040393Sbostic 	     * Stop when an = operator is found.
110140393Sbostic 	     */
110240393Sbostic 	    if ((*line == '+') || (*line == ':') || (*line == '?') ||
110340393Sbostic 		(*line == '!')) {
110440393Sbostic 		break;
110540393Sbostic 	    }
110640393Sbostic 
110740393Sbostic 	    /*
110840393Sbostic 	     * This is the start of another word, so not assignment.
110940393Sbostic 	     */
111040393Sbostic 	    return (FALSE);
111140393Sbostic 	} else {
111240393Sbostic 	    haveName = TRUE;
111340393Sbostic 	    wasSpace = FALSE;
111440393Sbostic 	}
111540393Sbostic 	line++;
111640393Sbostic     }
111740393Sbostic 
111840393Sbostic     /*
111940393Sbostic      * A final check: if we stopped on a +, ?, ! or :, the next character must
112040393Sbostic      * be an = or it ain't a valid assignment
112140393Sbostic      */
112240393Sbostic     if (((*line == '+') ||
112340393Sbostic 	 (*line == '?') ||
112440393Sbostic 	 (*line == ':') ||
112540393Sbostic 	 (*line == '!')) &&
112640393Sbostic 	(line[1] != '='))
112740393Sbostic     {
112840393Sbostic 	return (FALSE);
112940393Sbostic     } else {
113040393Sbostic 	return (haveName);
113140393Sbostic     }
113240393Sbostic }
113340424Sbostic 
113440393Sbostic /*-
113540393Sbostic  *---------------------------------------------------------------------
113640393Sbostic  * Parse_DoVar  --
113740393Sbostic  *	Take the variable assignment in the passed line and do it in the
113840393Sbostic  *	global context.
113940393Sbostic  *
114040393Sbostic  *	Note: There is a lexical ambiguity with assignment modifier characters
114140393Sbostic  *	in variable names. This routine interprets the character before the =
114240393Sbostic  *	as a modifier. Therefore, an assignment like
114340393Sbostic  *	    C++=/usr/bin/CC
114440393Sbostic  *	is interpreted as "C+ +=" instead of "C++ =".
114540393Sbostic  *
114640393Sbostic  * Results:
114740393Sbostic  *	none
114840393Sbostic  *
114940393Sbostic  * Side Effects:
115040393Sbostic  *	the variable structure of the given variable name is altered in the
115140393Sbostic  *	global context.
115240393Sbostic  *---------------------------------------------------------------------
115340393Sbostic  */
115440393Sbostic void
115540393Sbostic Parse_DoVar (line, ctxt)
115640393Sbostic     char            *line;	/* a line guaranteed to be a variable
115740393Sbostic 				 * assignment. This reduces error checks */
115840393Sbostic     GNode   	    *ctxt;    	/* Context in which to do the assignment */
115940393Sbostic {
116040393Sbostic     register char   *cp;	/* pointer into line */
116140393Sbostic     enum {
116240393Sbostic 	VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL
116340393Sbostic     }	    	    type;   	/* Type of assignment */
116440393Sbostic     char            *opc;	/* ptr to operator character to
116540393Sbostic 				 * null-terminate the variable name */
116640393Sbostic 
116740393Sbostic     /*
116840393Sbostic      * Skip to variable name
116940393Sbostic      */
117040393Sbostic     while ((*line == ' ') || (*line == '\t')) {
117140393Sbostic 	line++;
117240393Sbostic     }
117340393Sbostic 
117440393Sbostic     /*
117540393Sbostic      * Skip to operator character, nulling out whitespace as we go
117640393Sbostic      */
117740393Sbostic     for (cp = line + 1; *cp != '='; cp++) {
117840393Sbostic 	if (isspace (*cp)) {
117940393Sbostic 	    *cp = '\0';
118040393Sbostic 	}
118140393Sbostic     }
118240393Sbostic     opc = cp-1;		/* operator is the previous character */
118340393Sbostic     *cp++ = '\0';	/* nuke the = */
118440393Sbostic 
118540393Sbostic     /*
118640393Sbostic      * Check operator type
118740393Sbostic      */
118840393Sbostic     switch (*opc) {
118940393Sbostic 	case '+':
119040393Sbostic 	    type = VAR_APPEND;
119140393Sbostic 	    *opc = '\0';
119240393Sbostic 	    break;
119340393Sbostic 
119440393Sbostic 	case '?':
119540393Sbostic 	    /*
119640393Sbostic 	     * If the variable already has a value, we don't do anything.
119740393Sbostic 	     */
119840393Sbostic 	    *opc = '\0';
119940393Sbostic 	    if (Var_Exists(line, ctxt)) {
120040393Sbostic 		return;
120140393Sbostic 	    } else {
120240393Sbostic 		type = VAR_NORMAL;
120340393Sbostic 	    }
120440393Sbostic 	    break;
120540393Sbostic 
120640393Sbostic 	case ':':
120740393Sbostic 	    type = VAR_SUBST;
120840393Sbostic 	    *opc = '\0';
120940393Sbostic 	    break;
121040393Sbostic 
121140393Sbostic 	case '!':
121240393Sbostic 	    type = VAR_SHELL;
121340393Sbostic 	    *opc = '\0';
121440393Sbostic 	    break;
121540393Sbostic 
121640393Sbostic 	default:
121740393Sbostic 	    type = VAR_NORMAL;
121840393Sbostic 	    break;
121940393Sbostic     }
122040393Sbostic 
122140393Sbostic     while (isspace (*cp)) {
122240393Sbostic 	cp++;
122340393Sbostic     }
122440393Sbostic 
122540393Sbostic     if (type == VAR_APPEND) {
122640393Sbostic 	Var_Append (line, cp, ctxt);
122740393Sbostic     } else if (type == VAR_SUBST) {
122840393Sbostic 	/*
122940393Sbostic 	 * Allow variables in the old value to be undefined, but leave their
123040393Sbostic 	 * invocation alone -- this is done by forcing oldVars to be false.
123140393Sbostic 	 * XXX: This can cause recursive variables, but that's not hard to do,
123240393Sbostic 	 * and this allows someone to do something like
123340393Sbostic 	 *
123440393Sbostic 	 *  CFLAGS = $(.INCLUDES)
123540393Sbostic 	 *  CFLAGS := -I.. $(CFLAGS)
123640393Sbostic 	 *
123740393Sbostic 	 * And not get an error.
123840393Sbostic 	 */
123940393Sbostic 	Boolean	  oldOldVars = oldVars;
124040393Sbostic 
124140393Sbostic 	oldVars = FALSE;
124240393Sbostic 	cp = Var_Subst(cp, ctxt, FALSE);
124340393Sbostic 	oldVars = oldOldVars;
124440393Sbostic 
124540393Sbostic 	Var_Set(line, cp, ctxt);
124640393Sbostic 	free(cp);
124740393Sbostic     } else if (type == VAR_SHELL) {
124840393Sbostic 	char	result[BUFSIZ];	/* Result of command */
124940393Sbostic 	char	*args[4];   	/* Args for invoking the shell */
125040393Sbostic 	int 	fds[2];	    	/* Pipe streams */
125140393Sbostic 	int 	cpid;	    	/* Child PID */
125240393Sbostic 	int 	pid;	    	/* PID from wait() */
125340393Sbostic 	Boolean	freeCmd;    	/* TRUE if the command needs to be freed, i.e.
125440393Sbostic 				 * if any variable expansion was performed */
125540393Sbostic 
125640393Sbostic 	/*
125740393Sbostic 	 * Set up arguments for shell
125840393Sbostic 	 */
125940393Sbostic 	args[0] = "sh";
126040393Sbostic 	args[1] = "-c";
126140393Sbostic 	if (index(cp, '$') != (char *)NULL) {
126240393Sbostic 	    /*
126340393Sbostic 	     * There's a dollar sign in the command, so perform variable
126440393Sbostic 	     * expansion on the whole thing. The resulting string will need
126540393Sbostic 	     * freeing when we're done, so set freeCmd to TRUE.
126640393Sbostic 	     */
126740393Sbostic 	    args[2] = Var_Subst(cp, VAR_CMD, TRUE);
126840393Sbostic 	    freeCmd = TRUE;
126940393Sbostic 	} else {
127040393Sbostic 	    args[2] = cp;
127140393Sbostic 	    freeCmd = FALSE;
127240393Sbostic 	}
127340393Sbostic 	args[3] = (char *)NULL;
127440393Sbostic 
127540393Sbostic 	/*
127640393Sbostic 	 * Open a pipe for fetching its output
127740393Sbostic 	 */
127840393Sbostic 	pipe(fds);
127940393Sbostic 
128040393Sbostic 	/*
128140393Sbostic 	 * Fork
128240393Sbostic 	 */
128340393Sbostic 	cpid = vfork();
128440393Sbostic 	if (cpid == 0) {
128540393Sbostic 	    /*
128640393Sbostic 	     * Close input side of pipe
128740393Sbostic 	     */
128840393Sbostic 	    close(fds[0]);
128940393Sbostic 
129040393Sbostic 	    /*
129140393Sbostic 	     * Duplicate the output stream to the shell's output, then
129240393Sbostic 	     * shut the extra thing down. Note we don't fetch the error
129340393Sbostic 	     * stream...why not? Why?
129440393Sbostic 	     */
129540393Sbostic 	    dup2(fds[1], 1);
129640393Sbostic 	    close(fds[1]);
129740393Sbostic 
129840393Sbostic 	    execv("/bin/sh", args);
129940393Sbostic 	    _exit(1);
130040393Sbostic 	} else if (cpid < 0) {
130140393Sbostic 	    /*
130240393Sbostic 	     * Couldn't fork -- tell the user and make the variable null
130340393Sbostic 	     */
130440393Sbostic 	    Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp);
130540393Sbostic 	    Var_Set(line, "", ctxt);
130640393Sbostic 	} else {
130740393Sbostic 	    int	status;
130840393Sbostic 	    int cc;
130940393Sbostic 
131040393Sbostic 	    /*
131140393Sbostic 	     * No need for the writing half
131240393Sbostic 	     */
131340393Sbostic 	    close(fds[1]);
131440393Sbostic 
131540393Sbostic 	    /*
131640393Sbostic 	     * Wait for the process to exit.
131740393Sbostic 	     *
131840393Sbostic 	     * XXX: If the child writes more than a pipe's worth, we will
131940393Sbostic 	     * deadlock.
132040393Sbostic 	     */
132140393Sbostic 	    while(((pid = wait(&status)) != cpid) && (pid >= 0)) {
132240393Sbostic 		;
132340393Sbostic 	    }
132440393Sbostic 
132540393Sbostic 	    /*
132640393Sbostic 	     * Read all the characters the child wrote.
132740393Sbostic 	     */
132840393Sbostic 	    cc = read(fds[0], result, sizeof(result));
132940393Sbostic 
133040393Sbostic 	    if (cc < 0) {
133140393Sbostic 		/*
133240393Sbostic 		 * Couldn't read the child's output -- tell the user and
133340393Sbostic 		 * set the variable to null
133440393Sbostic 		 */
133540393Sbostic 		Parse_Error(PARSE_WARNING, "Couldn't read shell's output");
133640393Sbostic 		cc = 0;
133740393Sbostic 	    }
133840393Sbostic 
133940393Sbostic 	    if (status) {
134040393Sbostic 		/*
134140393Sbostic 		 * Child returned an error -- tell the user but still use
134240393Sbostic 		 * the result.
134340393Sbostic 		 */
134440393Sbostic 		Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp);
134540393Sbostic 	    }
134640393Sbostic 	    /*
134740393Sbostic 	     * Null-terminate the result, convert newlines to spaces and
134840393Sbostic 	     * install it in the variable.
134940393Sbostic 	     */
135040393Sbostic 	    result[cc] = '\0';
135140393Sbostic 	    cp = &result[cc] - 1;
135240393Sbostic 
135340393Sbostic 	    if (*cp == '\n') {
135440393Sbostic 		/*
135540393Sbostic 		 * A final newline is just stripped
135640393Sbostic 		 */
135740393Sbostic 		*cp-- = '\0';
135840393Sbostic 	    }
135940393Sbostic 	    while (cp >= result) {
136040393Sbostic 		if (*cp == '\n') {
136140393Sbostic 		    *cp = ' ';
136240393Sbostic 		}
136340393Sbostic 		cp--;
136440393Sbostic 	    }
136540393Sbostic 	    Var_Set(line, result, ctxt);
136640393Sbostic 
136740393Sbostic 	    /*
136840393Sbostic 	     * Close the input side of the pipe.
136940393Sbostic 	     */
137040393Sbostic 	    close(fds[0]);
137140393Sbostic 	}
137240393Sbostic 	if (freeCmd) {
137340393Sbostic 	    free(args[2]);
137440393Sbostic 	}
137540393Sbostic     } else {
137640393Sbostic 	/*
137740393Sbostic 	 * Normal assignment -- just do it.
137840393Sbostic 	 */
137940393Sbostic 	Var_Set (line, cp, ctxt);
138040393Sbostic     }
138140393Sbostic }
138240424Sbostic 
138340393Sbostic /*-
138440393Sbostic  *---------------------------------------------------------------------
138540393Sbostic  * ParseAddCmd  --
138640393Sbostic  *	Lst_ForEach function to add a command line to all targets
138740393Sbostic  *
138840393Sbostic  * Results:
138940393Sbostic  *	Always 0
139040393Sbostic  *
139140393Sbostic  * Side Effects:
139240393Sbostic  *	A new element is added to the commands list of the node.
139340393Sbostic  *---------------------------------------------------------------------
139440393Sbostic  */
139540393Sbostic static int
139640393Sbostic ParseAddCmd (gn, cmd)
139740393Sbostic     GNode          *gn;		/* the node to which the command is to be
139840393Sbostic 				 * added */
139940393Sbostic     char           *cmd;	/* the command to add */
140040393Sbostic {
140140393Sbostic     if (gn->type & OP_HAS_COMMANDS) {
140240393Sbostic 	Parse_Error(PARSE_WARNING, "Extra command line for \"%s\" ignored",
140340393Sbostic 		    gn->name);
140440393Sbostic     } else {
140540393Sbostic 	(void)Lst_AtEnd (gn->commands, (ClientData)cmd);
140640393Sbostic     }
140740393Sbostic 
140840393Sbostic     return (0);
140940393Sbostic }
141040424Sbostic 
141140393Sbostic /*-
141240393Sbostic  *-----------------------------------------------------------------------
141340393Sbostic  * ParseHasCommands --
141440393Sbostic  *	Callback procedure for Parse_File when destroying the list of
141540393Sbostic  *	targets on the last dependency line. Marks a target as already
141640393Sbostic  *	having commands if it does, to keep from having shell commands
141740393Sbostic  *	on multiple dependency lines.
141840393Sbostic  *
141940393Sbostic  * Results:
142040393Sbostic  *	Always 0.
142140393Sbostic  *
142240393Sbostic  * Side Effects:
142340393Sbostic  *	OP_HAS_COMMANDS may be set for the target.
142440393Sbostic  *
142540393Sbostic  *-----------------------------------------------------------------------
142640393Sbostic  */
142740393Sbostic static int
142840393Sbostic ParseHasCommands(gn)
142940393Sbostic     GNode   	  *gn;	    /* Node to examine */
143040393Sbostic {
143140393Sbostic     if (!Lst_IsEmpty(gn->commands)) {
143240393Sbostic 	gn->type |= OP_HAS_COMMANDS;
143340393Sbostic     }
143440393Sbostic     return(0);
143540393Sbostic }
143640424Sbostic 
143740393Sbostic /*-
143840393Sbostic  *-----------------------------------------------------------------------
143940393Sbostic  * Parse_AddIncludeDir --
144040393Sbostic  *	Add a directory to the path searched for included makefiles
144140393Sbostic  *	bracketed by double-quotes. Used by functions in main.c
144240393Sbostic  *
144340393Sbostic  * Results:
144440393Sbostic  *	None.
144540393Sbostic  *
144640393Sbostic  * Side Effects:
144740393Sbostic  *	The directory is appended to the list.
144840393Sbostic  *
144940393Sbostic  *-----------------------------------------------------------------------
145040393Sbostic  */
145140393Sbostic void
145240393Sbostic Parse_AddIncludeDir (dir)
145340393Sbostic     char    	  *dir;	    /* The name of the directory to add */
145440393Sbostic {
145540393Sbostic     Dir_AddDir (parseIncPath, dir);
145640393Sbostic }
145740424Sbostic 
145840393Sbostic /*-
145940393Sbostic  *---------------------------------------------------------------------
146040393Sbostic  * ParseDoInclude  --
146140393Sbostic  *	Push to another file.
146240393Sbostic  *
146340393Sbostic  *	The input is the line minus the #include. A file spec is a string
146440393Sbostic  *	enclosed in <> or "". The former is looked for only in sysIncPath.
146540393Sbostic  *	The latter in . and the directories specified by -I command line
146640393Sbostic  *	options
146740393Sbostic  *
146840393Sbostic  * Results:
146940393Sbostic  *	None
147040393Sbostic  *
147140393Sbostic  * Side Effects:
147240393Sbostic  *	A structure is added to the includes Lst and readProc, lineno,
147340393Sbostic  *	fname and curFILE are altered for the new file
147440393Sbostic  *---------------------------------------------------------------------
147540393Sbostic  */
147640393Sbostic static void
147740393Sbostic ParseDoInclude (file)
147840393Sbostic     char          *file;	/* file specification */
147940393Sbostic {
148040393Sbostic     char          *fullname;	/* full pathname of file */
148140393Sbostic     IFile         *oldFile;	/* state associated with current file */
148240393Sbostic     Lst           path;	    	/* the path to use to find the file */
148340393Sbostic     char          endc;	    	/* the character which ends the file spec */
148440393Sbostic     char          *cp;		/* current position in file spec */
148540393Sbostic     Boolean 	  isSystem; 	/* TRUE if makefile is a system makefile */
148640393Sbostic 
148740393Sbostic     /*
148840393Sbostic      * Skip to delimiter character so we know where to look
148940393Sbostic      */
149040393Sbostic     while ((*file == ' ') || (*file == '\t')) {
149140393Sbostic 	file++;
149240393Sbostic     }
149340393Sbostic 
149440393Sbostic     if ((*file != '"') && (*file != '<')) {
149540393Sbostic 	/*
149640393Sbostic 	 * XXX: Should give some sort of error message, I suppose, but because
149740393Sbostic 	 * # is used for both comments and directives, we can't be sure if
149840393Sbostic 	 * the thing might not just be a comment, so we just return...
149940393Sbostic 	 */
150040393Sbostic 	return;
150140393Sbostic     }
150240393Sbostic 
150340393Sbostic     /*
150440393Sbostic      * Set the search path on which to find the include file based on the
150540393Sbostic      * characters which bracket its name. Angle-brackets imply it's
150640393Sbostic      * a system Makefile while double-quotes imply it's a user makefile
150740393Sbostic      */
150840393Sbostic     if (*file == '<') {
150940393Sbostic 	isSystem = TRUE;
151040393Sbostic 	endc = '>';
151140393Sbostic     } else {
151240393Sbostic 	isSystem = FALSE;
151340393Sbostic 	endc = '"';
151440393Sbostic     }
151540393Sbostic 
151640393Sbostic     /*
151740393Sbostic      * Skip to matching delimiter
151840393Sbostic      */
151940393Sbostic     for (cp = ++file; *cp && *cp != endc; cp++) {
152040393Sbostic 	continue;
152140393Sbostic     }
152240393Sbostic 
152340393Sbostic     if (*cp != endc) {
152440393Sbostic 	Parse_Error (PARSE_FATAL,
152540435Sbostic 		     "Unclosed .include filename. '%c' expected", endc);
152640393Sbostic 	return;
152740393Sbostic     }
152840393Sbostic     *cp = '\0';
152940393Sbostic 
153040393Sbostic     /*
153140393Sbostic      * Substitute for any variables in the file name before trying to
153240393Sbostic      * find the thing.
153340393Sbostic      */
153440393Sbostic     file = Var_Subst (file, VAR_CMD, FALSE);
153540393Sbostic 
153640393Sbostic     /*
153740393Sbostic      * Now we know the file's name and its search path, we attempt to
153840393Sbostic      * find the durn thing. A return of NULL indicates the file don't
153940393Sbostic      * exist.
154040393Sbostic      */
154140393Sbostic     if (!isSystem) {
154240393Sbostic 	/*
154340393Sbostic 	 * Include files contained in double-quotes are first searched for
154440393Sbostic 	 * relative to the including file's location. We don't want to
154540393Sbostic 	 * cd there, of course, so we just tack on the old file's
154640393Sbostic 	 * leading path components and call Dir_FindFile to see if
154740393Sbostic 	 * we can locate the beast.
154840393Sbostic 	 */
154940393Sbostic 	char	  *prefEnd;
155040393Sbostic 
155140393Sbostic 	prefEnd = rindex (fname, '/');
155240393Sbostic 	if (prefEnd != (char *)NULL) {
155340393Sbostic 	    char  	*newName;
155440393Sbostic 
155540393Sbostic 	    *prefEnd = '\0';
155640393Sbostic 	    newName = Str_Concat (fname, file, STR_ADDSLASH);
155740393Sbostic 	    fullname = Dir_FindFile (newName, parseIncPath);
155840393Sbostic 	    if (fullname == (char *)NULL) {
155940393Sbostic 		fullname = Dir_FindFile(newName, dirSearchPath);
156040393Sbostic 	    }
156140393Sbostic 	    free (newName);
156240393Sbostic 	    *prefEnd = '/';
156340393Sbostic 	} else {
156440393Sbostic 	    fullname = (char *)NULL;
156540393Sbostic 	}
156640393Sbostic     } else {
156740393Sbostic 	fullname = (char *)NULL;
156840393Sbostic     }
156940393Sbostic 
157040393Sbostic     if (fullname == (char *)NULL) {
157140393Sbostic 	/*
157240393Sbostic 	 * System makefile or makefile wasn't found in same directory as
157340393Sbostic 	 * included makefile. Search for it first on the -I search path,
157440393Sbostic 	 * then on the .PATH search path, if not found in a -I directory.
157540393Sbostic 	 * XXX: Suffix specific?
157640393Sbostic 	 */
157740393Sbostic 	fullname = Dir_FindFile (file, parseIncPath);
157840393Sbostic 	if (fullname == (char *)NULL) {
157940393Sbostic 	    fullname = Dir_FindFile(file, dirSearchPath);
158040393Sbostic 	}
158140393Sbostic     }
158240393Sbostic 
158340393Sbostic     if (fullname == (char *)NULL) {
158440393Sbostic 	/*
158540393Sbostic 	 * Still haven't found the makefile. Look for it on the system
158640393Sbostic 	 * path as a last resort.
158740393Sbostic 	 */
158840393Sbostic 	fullname = Dir_FindFile(file, sysIncPath);
158940393Sbostic     }
159040393Sbostic 
159140393Sbostic     if (fullname == (char *) NULL) {
159240393Sbostic 	*cp = endc;
159340393Sbostic 	Parse_Error (PARSE_FATAL, "Could not find %s", file);
159440393Sbostic 	return;
159540393Sbostic     }
159640393Sbostic 
159740393Sbostic     /*
159840393Sbostic      * Once we find the absolute path to the file, we get to save all the
159940393Sbostic      * state from the current file before we can start reading this
160040393Sbostic      * include file. The state is stored in an IFile structure which
160140393Sbostic      * is placed on a list with other IFile structures. The list makes
160240393Sbostic      * a very nice stack to track how we got here...
160340393Sbostic      */
160440393Sbostic     oldFile = (IFile *) malloc (sizeof (IFile));
160540393Sbostic     oldFile->fname = fname;
160640393Sbostic 
160740393Sbostic     oldFile->F = curFILE;
160840393Sbostic     oldFile->lineno = lineno;
160940393Sbostic 
161040393Sbostic     (void) Lst_AtFront (includes, (ClientData)oldFile);
161140393Sbostic 
161240393Sbostic     /*
161340393Sbostic      * Once the previous state has been saved, we can get down to reading
161440393Sbostic      * the new file. We set up the name of the file to be the absolute
161540393Sbostic      * name of the include file so error messages refer to the right
161640393Sbostic      * place. Naturally enough, we start reading at line number 0.
161740393Sbostic      */
161840393Sbostic     fname = fullname;
161940393Sbostic     lineno = 0;
162040393Sbostic 
162140393Sbostic     curFILE = fopen (fullname, "r");
162240393Sbostic     if (curFILE == (FILE * ) NULL) {
162340393Sbostic 	Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
162440393Sbostic 	/*
162540393Sbostic 	 * Pop to previous file
162640393Sbostic 	 */
162740393Sbostic 	(void) ParseEOF();
162840393Sbostic     }
162940393Sbostic }
163040424Sbostic 
163140393Sbostic /*-
163240393Sbostic  *---------------------------------------------------------------------
163340393Sbostic  * ParseEOF  --
163440393Sbostic  *	Called when EOF is reached in the current file. If we were reading
163540393Sbostic  *	an include file, the includes stack is popped and things set up
163640393Sbostic  *	to go back to reading the previous file at the previous location.
163740393Sbostic  *
163840393Sbostic  * Results:
163940393Sbostic  *	CONTINUE if there's more to do. DONE if not.
164040393Sbostic  *
164140393Sbostic  * Side Effects:
164240393Sbostic  *	The old curFILE, is closed. The includes list is shortened.
164340393Sbostic  *	lineno, curFILE, and fname are changed if CONTINUE is returned.
164440393Sbostic  *---------------------------------------------------------------------
164540393Sbostic  */
164640393Sbostic static int
164740393Sbostic ParseEOF ()
164840393Sbostic {
164940393Sbostic     IFile     *ifile;	/* the state on the top of the includes stack */
165040393Sbostic 
165140393Sbostic     if (Lst_IsEmpty (includes)) {
165240393Sbostic 	return (DONE);
165340393Sbostic     }
165440393Sbostic 
165540393Sbostic     ifile = (IFile *) Lst_DeQueue (includes);
165640393Sbostic     free (fname);
165740393Sbostic     fname = ifile->fname;
165840393Sbostic     lineno = ifile->lineno;
165940393Sbostic     fclose (curFILE);
166040393Sbostic     curFILE = ifile->F;
166140393Sbostic     free ((Address)ifile);
166240393Sbostic     return (CONTINUE);
166340393Sbostic }
166440424Sbostic 
166540393Sbostic /*-
166640393Sbostic  *---------------------------------------------------------------------
166740393Sbostic  * ParseReadc  --
166840393Sbostic  *	Read a character from the current file and update the line number
166940393Sbostic  *	counter as necessary
167040393Sbostic  *
167140393Sbostic  * Results:
167240393Sbostic  *	The character that was read
167340393Sbostic  *
167440393Sbostic  * Side Effects:
167540393Sbostic  *	The lineno counter is incremented if the character is a newline
167640393Sbostic  *---------------------------------------------------------------------
167740393Sbostic  */
167840393Sbostic #ifdef notdef
167940393Sbostic static int parseReadChar;
168040393Sbostic 
168140393Sbostic #define ParseReadc() (((parseReadChar = getc(curFILE)) == '\n') ? \
168240393Sbostic 		      (lineno++, '\n') : parseReadChar)
168340393Sbostic #else
168440393Sbostic #define ParseReadc() (getc(curFILE))
168540393Sbostic #endif /* notdef */
168640393Sbostic 
168740424Sbostic 
168840393Sbostic /*-
168940393Sbostic  *---------------------------------------------------------------------
169040393Sbostic  * ParseReadLine --
169140393Sbostic  *	Read an entire line from the input file. Called only by Parse_File.
169240393Sbostic  *	To facilitate escaped newlines and what have you, a character is
169340393Sbostic  *	buffered in 'lastc', which is '\0' when no characters have been
169440393Sbostic  *	read. When we break out of the loop, c holds the terminating
169540393Sbostic  *	character and lastc holds a character that should be added to
169640393Sbostic  *	the line (unless we don't read anything but a terminator).
169740393Sbostic  *
169840393Sbostic  * Results:
169940393Sbostic  *	A line w/o its newline
170040393Sbostic  *
170140393Sbostic  * Side Effects:
170240393Sbostic  *	Only those associated with reading a character
170340393Sbostic  *---------------------------------------------------------------------
170440393Sbostic  */
170540393Sbostic static char *
170640393Sbostic ParseReadLine ()
170740393Sbostic {
170840393Sbostic     Buffer  	  buf;	    	/* Buffer for current line */
170940393Sbostic     register int  c;	      	/* the current character */
171040393Sbostic     register int  lastc;    	/* The most-recent character */
171140393Sbostic     Boolean	  semiNL;     	/* treat semi-colons as newlines */
171240393Sbostic     Boolean	  ignDepOp;   	/* TRUE if should ignore dependency operators
171340393Sbostic 				 * for the purposes of setting semiNL */
171440393Sbostic     Boolean 	  ignComment;	/* TRUE if should ignore comments (in a
171540393Sbostic 				 * shell command */
171640393Sbostic     char    	  *line;    	/* Result */
171740393Sbostic     int	    	  lineLength;	/* Length of result */
171840393Sbostic 
171940393Sbostic     semiNL = FALSE;
172040393Sbostic     ignDepOp = FALSE;
172140393Sbostic     ignComment = FALSE;
172240393Sbostic 
172340393Sbostic     /*
172440393Sbostic      * Handle special-characters at the beginning of the line. Either a
172540393Sbostic      * leading tab (shell command) or pound-sign (possible conditional)
172640393Sbostic      * forces us to ignore comments and dependency operators and treat
172740393Sbostic      * semi-colons as semi-colons (by leaving semiNL FALSE). This also
172840393Sbostic      * discards completely blank lines.
172940393Sbostic      */
173040393Sbostic     while(1) {
173140393Sbostic 	c = ParseReadc();
173240393Sbostic 
173340435Sbostic 	if ((c == '\t') || (c == '.')) {
173440393Sbostic 	    ignComment = ignDepOp = TRUE;
173540393Sbostic 	    break;
173640393Sbostic 	} else if (c == '\n') {
173740393Sbostic 	    lineno++;
173840393Sbostic 	} else {
173940393Sbostic 	    /*
174040393Sbostic 	     * Anything else breaks out without doing anything
174140393Sbostic 	     */
174240393Sbostic 	    break;
174340393Sbostic 	}
174440393Sbostic     }
174540393Sbostic 
174640393Sbostic     if (c != EOF) {
174740393Sbostic 	lastc = c;
174840393Sbostic 	buf = Buf_Init(BSIZE);
174940393Sbostic 
175040393Sbostic 	while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) &&
175140393Sbostic 	       (c != EOF))
175240393Sbostic 	{
175340393Sbostic test_char:
175440393Sbostic 	    switch(c) {
175540393Sbostic 	    case '\n':
175640393Sbostic 		/*
175740393Sbostic 		 * Escaped newline: read characters until a non-space or an
175840393Sbostic 		 * unescaped newline and replace them all by a single space.
175940393Sbostic 		 * This is done by storing the space over the backslash and
176040393Sbostic 		 * dropping through with the next nonspace. If it is a
176140393Sbostic 		 * semi-colon and semiNL is TRUE, it will be recognized as a
176240393Sbostic 		 * newline in the code below this...
176340393Sbostic 		 */
176440393Sbostic 		lineno++;
176540393Sbostic 		lastc = ' ';
176640393Sbostic 		while ((c = ParseReadc ()) == ' ' || c == '\t') {
176740393Sbostic 		    continue;
176840393Sbostic 		}
176940393Sbostic 		if (c == EOF || c == '\n') {
177040393Sbostic 		    goto line_read;
177140393Sbostic 		} else {
177240393Sbostic 		    /*
177340393Sbostic 		     * Check for comments, semiNL's, etc. -- easier than
177440393Sbostic 		     * ungetc(c, curFILE); continue;
177540393Sbostic 		     */
177640393Sbostic 		    goto test_char;
177740393Sbostic 		}
177840393Sbostic 		break;
177940393Sbostic 	    case ';':
178040393Sbostic 		/*
178140393Sbostic 		 * Semi-colon: Need to see if it should be interpreted as a
178240393Sbostic 		 * newline
178340393Sbostic 		 */
178440393Sbostic 		if (semiNL) {
178540393Sbostic 		    /*
178640393Sbostic 		     * To make sure the command that may be following this
178740393Sbostic 		     * semi-colon begins with a tab, we push one back into the
178840393Sbostic 		     * input stream. This will overwrite the semi-colon in the
178940393Sbostic 		     * buffer. If there is no command following, this does no
179040393Sbostic 		     * harm, since the newline remains in the buffer and the
179140393Sbostic 		     * whole line is ignored.
179240393Sbostic 		     */
179340393Sbostic 		    ungetc('\t', curFILE);
179440393Sbostic 		    goto line_read;
179540393Sbostic 		}
179640393Sbostic 		break;
179740393Sbostic 	    case '=':
179840393Sbostic 		if (!semiNL) {
179940393Sbostic 		    /*
180040393Sbostic 		     * Haven't seen a dependency operator before this, so this
180140393Sbostic 		     * must be a variable assignment -- don't pay attention to
180240393Sbostic 		     * dependency operators after this.
180340393Sbostic 		     */
180440393Sbostic 		    ignDepOp = TRUE;
180540393Sbostic 		} else if (lastc == ':' || lastc == '!') {
180640393Sbostic 		    /*
180740393Sbostic 		     * Well, we've seen a dependency operator already, but it
180840393Sbostic 		     * was the previous character, so this is really just an
180940393Sbostic 		     * expanded variable assignment. Revert semi-colons to
181040393Sbostic 		     * being just semi-colons again and ignore any more
181140393Sbostic 		     * dependency operators.
181240393Sbostic 		     *
181340393Sbostic 		     * XXX: Note that a line like "foo : a:=b" will blow up,
181440393Sbostic 		     * but who'd write a line like that anyway?
181540393Sbostic 		     */
181640393Sbostic 		    ignDepOp = TRUE; semiNL = FALSE;
181740393Sbostic 		}
181840393Sbostic 		break;
181940393Sbostic 	    case '#':
182040393Sbostic 		if (!ignComment) {
182140393Sbostic 			/*
182240393Sbostic 			 * If the character is a hash mark and it isn't escaped
182340393Sbostic 			 * (or we're being compatible), the thing is a comment.
182440393Sbostic 			 * Skip to the end of the line.
182540393Sbostic 			 */
182640393Sbostic 			do {
182740393Sbostic 			    c = ParseReadc();
182840393Sbostic 			} while ((c != '\n') && (c != EOF));
182940393Sbostic 			goto line_read;
183040393Sbostic 		}
183140393Sbostic 		break;
183240393Sbostic 	    case ':':
183340393Sbostic 	    case '!':
183440393Sbostic 		if (!ignDepOp && (c == ':' || c == '!')) {
183540393Sbostic 		    /*
183640393Sbostic 		     * A semi-colon is recognized as a newline only on
183740393Sbostic 		     * dependency lines. Dependency lines are lines with a
183840393Sbostic 		     * colon or an exclamation point. Ergo...
183940393Sbostic 		     */
184040393Sbostic 		    semiNL = TRUE;
184140393Sbostic 		}
184240393Sbostic 		break;
184340393Sbostic 	    }
184440393Sbostic 	    /*
184540393Sbostic 	     * Copy in the previous character and save this one in lastc.
184640393Sbostic 	     */
184740393Sbostic 	    Buf_AddByte (buf, (Byte)lastc);
184840393Sbostic 	    lastc = c;
184940393Sbostic 
185040393Sbostic 	}
185140393Sbostic     line_read:
185240393Sbostic 	lineno++;
185340393Sbostic 
185440393Sbostic 	if (lastc != '\0') {
185540393Sbostic 	    Buf_AddByte (buf, (Byte)lastc);
185640393Sbostic 	}
185740393Sbostic 	Buf_AddByte (buf, (Byte)'\0');
185840393Sbostic 	line = (char *)Buf_GetAll (buf, &lineLength);
185940393Sbostic 	Buf_Destroy (buf, FALSE);
186040393Sbostic 
186140435Sbostic 	if (line[0] == '.') {
186240393Sbostic 	    /*
186340393Sbostic 	     * The line might be a conditional. Ask the conditional module
186440393Sbostic 	     * about it and act accordingly
186540393Sbostic 	     */
186640393Sbostic 	    switch (Cond_Eval (line)) {
186740393Sbostic 	    case COND_SKIP:
186840393Sbostic 		do {
186940393Sbostic 		    /*
187040393Sbostic 		     * Skip to next conditional that evaluates to COND_PARSE.
187140393Sbostic 		     */
187240393Sbostic 		    free (line);
187340393Sbostic 		    c = ParseReadc();
187440393Sbostic 		    /*
187540393Sbostic 		     * Skip lines until get to one that begins with a
187640393Sbostic 		     * special char.
187740393Sbostic 		     */
187840435Sbostic 		    while ((c != '.') && (c != EOF)) {
187940393Sbostic 			while (((c != '\n') || (lastc == '\\')) &&
188040393Sbostic 			       (c != EOF))
188140393Sbostic 			{
188240393Sbostic 			    /*
188340393Sbostic 			     * Advance to next unescaped newline
188440393Sbostic 			     */
188540393Sbostic 			    if ((lastc = c) == '\n') {
188640393Sbostic 				lineno++;
188740393Sbostic 			    }
188840393Sbostic 			    c = ParseReadc();
188940393Sbostic 			}
189040393Sbostic 			lineno++;
189140393Sbostic 
189240393Sbostic 			lastc = c;
189340393Sbostic 			c = ParseReadc ();
189440393Sbostic 		    }
189540393Sbostic 
189640393Sbostic 		    if (c == EOF) {
189740393Sbostic 			Parse_Error (PARSE_FATAL, "Unclosed conditional");
189840393Sbostic 			return ((char *)NULL);
189940393Sbostic 		    }
190040393Sbostic 
190140393Sbostic 		    /*
190240393Sbostic 		     * Read the entire line into buf
190340393Sbostic 		     */
190440393Sbostic 		    buf = Buf_Init (BSIZE);
190540393Sbostic 		    do {
190640393Sbostic 			Buf_AddByte (buf, (Byte)c);
190740393Sbostic 			c = ParseReadc();
190840393Sbostic 		    } while ((c != '\n') && (c != EOF));
190940393Sbostic 		    lineno++;
191040393Sbostic 
191140393Sbostic 		    Buf_AddByte (buf, (Byte)'\0');
191240393Sbostic 		    line = (char *)Buf_GetAll (buf, &lineLength);
191340393Sbostic 		    Buf_Destroy (buf, FALSE);
191440393Sbostic 		} while (Cond_Eval(line) != COND_PARSE);
191540393Sbostic 		/*FALLTHRU*/
191640393Sbostic 	    case COND_PARSE:
191740393Sbostic 		free (line);
191840393Sbostic 		line = ParseReadLine();
191940393Sbostic 		break;
192040393Sbostic 	    }
192140393Sbostic 	}
192240393Sbostic 
192340393Sbostic 	return (line);
192440393Sbostic     } else {
192540393Sbostic 	/*
192640393Sbostic 	 * Hit end-of-file, so return a NULL line to indicate this.
192740393Sbostic 	 */
192840393Sbostic 	return((char *)NULL);
192940393Sbostic     }
193040393Sbostic }
193140424Sbostic 
193240393Sbostic /*-
193340393Sbostic  *-----------------------------------------------------------------------
193440393Sbostic  * ParseFinishLine --
193540393Sbostic  *	Handle the end of a dependency group.
193640393Sbostic  *
193740393Sbostic  * Results:
193840393Sbostic  *	Nothing.
193940393Sbostic  *
194040393Sbostic  * Side Effects:
194140393Sbostic  *	inLine set FALSE. 'targets' list destroyed.
194240393Sbostic  *
194340393Sbostic  *-----------------------------------------------------------------------
194440393Sbostic  */
194540393Sbostic static void
194640393Sbostic ParseFinishLine()
194740393Sbostic {
194840393Sbostic     extern int Suff_EndTransform();
194940393Sbostic 
195040393Sbostic     if (inLine) {
195140393Sbostic 	Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL);
195240393Sbostic 	Lst_Destroy (targets, ParseHasCommands);
195340393Sbostic 	inLine = FALSE;
195440393Sbostic     }
195540393Sbostic }
195640393Sbostic 
195740424Sbostic 
195840393Sbostic /*-
195940393Sbostic  *---------------------------------------------------------------------
196040393Sbostic  * Parse_File --
196140393Sbostic  *	Parse a file into its component parts, incorporating it into the
196240393Sbostic  *	current dependency graph. This is the main function and controls
196340393Sbostic  *	almost every other function in this module
196440393Sbostic  *
196540393Sbostic  * Results:
196640393Sbostic  *	None
196740393Sbostic  *
196840393Sbostic  * Side Effects:
196940393Sbostic  *	Loads. Nodes are added to the list of all targets, nodes and links
197040393Sbostic  *	are added to the dependency graph. etc. etc. etc.
197140393Sbostic  *---------------------------------------------------------------------
197240393Sbostic  */
197340393Sbostic void
197440393Sbostic Parse_File(name, stream)
197540393Sbostic     char          *name;	/* the name of the file being read */
197640393Sbostic     FILE *	  stream;   	/* Stream open to makefile to parse */
197740393Sbostic {
197840393Sbostic     register char *cp,		/* pointer into the line */
197940393Sbostic                   *line;	/* the line we're working on */
198040393Sbostic 
198140393Sbostic     inLine = FALSE;
198240393Sbostic     fname = name;
198340393Sbostic     curFILE = stream;
198440393Sbostic     lineno = 0;
198540393Sbostic     fatals = 0;
198640393Sbostic 
198740393Sbostic     do {
198840393Sbostic 	while (line = ParseReadLine ()) {
198940435Sbostic 	    if (*line == '.') {
199040393Sbostic 		/*
199140393Sbostic 		 * Lines that begin with the special character are either
199240393Sbostic 		 * include or undef directives.
199340393Sbostic 		 */
199440393Sbostic 		for (cp = line + 1; isspace (*cp); cp++) {
199540393Sbostic 		    continue;
199640393Sbostic 		}
199740393Sbostic 		if (strncmp (cp, "include", 7) == 0) {
199840393Sbostic 		    ParseDoInclude (cp + 7);
199940393Sbostic 		    goto nextLine;
200040393Sbostic 		} else if (strncmp(cp, "undef", 5) == 0) {
200140393Sbostic 		    char *cp2;
200240393Sbostic 		    for (cp += 5; isspace(*cp); cp++) {
200340393Sbostic 			continue;
200440393Sbostic 		    }
200540393Sbostic 
200640393Sbostic 		    for (cp2 = cp; !isspace(*cp2) && (*cp2 != '\0'); cp2++) {
200740393Sbostic 			continue;
200840393Sbostic 		    }
200940393Sbostic 
201040393Sbostic 		    *cp2 = '\0';
201140393Sbostic 
201240393Sbostic 		    Var_Delete(cp, VAR_GLOBAL);
201340393Sbostic 		    goto nextLine;
201440393Sbostic 		}
201540393Sbostic 	    }
201640393Sbostic 	    if (*line == '#') {
201740435Sbostic 		/* If we're this far, the line must be a comment. */
201840393Sbostic 		goto nextLine;
201940393Sbostic 	    }
202040393Sbostic 
202140393Sbostic 	    if (*line == '\t'
202240393Sbostic #ifdef POSIX
202340393Sbostic 		       || *line == ' '
202440393Sbostic #endif
202540393Sbostic 		       )
202640393Sbostic 	    {
202740393Sbostic 		/*
202840393Sbostic 		 * If a line starts with a tab (or space in POSIX-land), it
202940393Sbostic 		 * can only hope to be a creation command.
203040393Sbostic 		 */
203140393Sbostic 	    shellCommand:
203240393Sbostic 		for (cp = line + 1; isspace (*cp); cp++) {
203340393Sbostic 		    continue;
203440393Sbostic 		}
203540393Sbostic 		if (*cp) {
203640393Sbostic 		    if (inLine) {
203740393Sbostic 			/*
203840393Sbostic 			 * So long as it's not a blank line and we're actually
203940393Sbostic 			 * in a dependency spec, add the command to the list of
204040393Sbostic 			 * commands of all targets in the dependency spec
204140393Sbostic 			 */
204240393Sbostic 			Lst_ForEach (targets, ParseAddCmd, (ClientData)cp);
204340393Sbostic 			continue;
204440393Sbostic 		    } else {
204540393Sbostic 			Parse_Error (PARSE_FATAL,
204640393Sbostic 				     "Unassociated shell command \"%.20s\"",
204740393Sbostic 				     cp);
204840393Sbostic 		    }
204940393Sbostic 		}
205040393Sbostic 	    } else if (Parse_IsVar (line)) {
205140393Sbostic 		ParseFinishLine();
205240393Sbostic 		Parse_DoVar (line, VAR_GLOBAL);
205340393Sbostic 	    } else {
205440393Sbostic 		/*
205540393Sbostic 		 * We now know it's a dependency line so it needs to have all
205640393Sbostic 		 * variables expanded before being parsed. Tell the variable
205740393Sbostic 		 * module to complain if some variable is undefined...
205840393Sbostic 		 * To make life easier on novices, if the line is indented we
205940393Sbostic 		 * first make sure the line has a dependency operator in it.
206040393Sbostic 		 * If it doesn't have an operator and we're in a dependency
206140393Sbostic 		 * line's script, we assume it's actually a shell command
206240393Sbostic 		 * and add it to the current list of targets.
206340393Sbostic 		 *
206440393Sbostic 		 * Note that POSIX declares all lines that start with
206540393Sbostic 		 * whitespace are shell commands, so there's no need to check
206640393Sbostic 		 * here...
206740393Sbostic 		 */
206840393Sbostic 		Boolean	nonSpace = FALSE;
206940393Sbostic 
207040393Sbostic 		cp = line;
207140393Sbostic #ifndef POSIX
207240393Sbostic 		if (line[0] == ' ') {
207340393Sbostic 		    while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) {
207440393Sbostic 			if (!isspace(*cp)) {
207540393Sbostic 			    nonSpace = TRUE;
207640393Sbostic 			}
207740393Sbostic 			cp++;
207840393Sbostic 		    }
207940393Sbostic 		}
208040393Sbostic 
208140393Sbostic 		if (*cp == '\0') {
208240393Sbostic 		    if (inLine) {
208340393Sbostic 			Parse_Error (PARSE_WARNING,
208440393Sbostic 				     "Shell command needs a leading tab");
208540393Sbostic 			goto shellCommand;
208640393Sbostic 		    } else if (nonSpace) {
208740393Sbostic 			Parse_Error (PARSE_FATAL, "Missing operator");
208840393Sbostic 		    }
208940393Sbostic 		} else {
209040393Sbostic #endif
209140393Sbostic 		    ParseFinishLine();
209240393Sbostic 
209340393Sbostic 		    cp = Var_Subst (line, VAR_CMD, TRUE);
209440393Sbostic 		    free (line);
209540393Sbostic 		    line = cp;
209640393Sbostic 
209740393Sbostic 		    /*
209840393Sbostic 		     * Need a non-circular list for the target nodes
209940393Sbostic 		     */
210040393Sbostic 		    targets = Lst_Init (FALSE);
210140393Sbostic 		    inLine = TRUE;
210240393Sbostic 
210340393Sbostic 		    ParseDoDependency (line);
210440393Sbostic #ifndef POSIX
210540393Sbostic 		}
210640393Sbostic #endif
210740393Sbostic 	    }
210840393Sbostic 
210940393Sbostic 	    nextLine:
211040393Sbostic 
211140393Sbostic 	    free (line);
211240393Sbostic 	}
211340393Sbostic 	/*
211440393Sbostic 	 * Reached EOF, but it may be just EOF of an include file...
211540393Sbostic 	 */
211640393Sbostic     } while (ParseEOF() == CONTINUE);
211740393Sbostic 
211840393Sbostic     /*
211940393Sbostic      * Make sure conditionals are clean
212040393Sbostic      */
212140393Sbostic     Cond_End();
212240393Sbostic 
212340393Sbostic     if (fatals) {
212440393Sbostic 	fprintf (stderr, "Fatal errors encountered -- cannot continue\n");
212540393Sbostic 	exit (1);
212640393Sbostic     }
212740393Sbostic }
212840424Sbostic 
212940393Sbostic /*-
213040393Sbostic  *---------------------------------------------------------------------
213140393Sbostic  * Parse_Init --
213240393Sbostic  *	initialize the parsing module
213340393Sbostic  *
213440393Sbostic  * Results:
213540393Sbostic  *	none
213640393Sbostic  *
213740393Sbostic  * Side Effects:
213840393Sbostic  *	the parseIncPath list is initialized...
213940393Sbostic  *---------------------------------------------------------------------
214040393Sbostic  */
214140393Sbostic Parse_Init ()
214240393Sbostic {
214340393Sbostic     char    	*cp;
214440393Sbostic     char    	*start;
214540393Sbostic     static char syspath[] = DEFSYSPATH;	/* Avoid faults on read-only string
214640393Sbostic 					 * constant... */
214740393Sbostic 
214840393Sbostic     mainNode = NILGNODE;
214940393Sbostic     parseIncPath = Lst_Init (FALSE);
215040393Sbostic     sysIncPath = Lst_Init (FALSE);
215140393Sbostic     includes = Lst_Init (FALSE);
215240393Sbostic 
215340393Sbostic     /*
215440393Sbostic      * Add the directories from the DEFSYSPATH (more than one may be given
215540393Sbostic      * as dir1:...:dirn) to the system include path.
215640393Sbostic      */
215740393Sbostic     for (start = syspath; *start != '\0'; start = cp) {
215840393Sbostic 	for (cp = start; *cp != '\0' && *cp != ':'; cp++) {
215940393Sbostic 	    ;
216040393Sbostic 	}
216140393Sbostic 	if (*cp == '\0') {
216240393Sbostic 	    Dir_AddDir(sysIncPath, start);
216340393Sbostic 	} else {
216440393Sbostic 	    *cp++ = '\0';
216540393Sbostic 	    Dir_AddDir(sysIncPath, start);
216640393Sbostic 	}
216740393Sbostic     }
216840393Sbostic }
216940424Sbostic 
217040393Sbostic /*-
217140393Sbostic  *-----------------------------------------------------------------------
217240393Sbostic  * Parse_MainName --
217340393Sbostic  *	Return a Lst of the main target to create for main()'s sake. If
217440393Sbostic  *	no such target exists, we Punt with an obnoxious error message.
217540393Sbostic  *
217640393Sbostic  * Results:
217740393Sbostic  *	A Lst of the single node to create.
217840393Sbostic  *
217940393Sbostic  * Side Effects:
218040393Sbostic  *	None.
218140393Sbostic  *
218240393Sbostic  *-----------------------------------------------------------------------
218340393Sbostic  */
218440393Sbostic Lst
218540393Sbostic Parse_MainName()
218640393Sbostic {
218740393Sbostic     Lst           main;	/* result list */
218840393Sbostic 
218940393Sbostic     main = Lst_Init (FALSE);
219040393Sbostic 
219140393Sbostic     if (mainNode == NILGNODE) {
219240393Sbostic 	Punt ("I don't know what to DO!\n");
219340393Sbostic     	/*NOTREACHED*/
219440393Sbostic     } else if (mainNode->type & OP_DOUBLEDEP) {
219540393Sbostic 	Lst_Concat(main, mainNode->cohorts, LST_CONCNEW);
219640393Sbostic     }
219740393Sbostic     (void) Lst_AtEnd (main, (ClientData)mainNode);
219840393Sbostic     return (main);
219940393Sbostic }
2200