140395Sbostic /*
262092Sbostic * Copyright (c) 1988, 1989, 1990, 1993
362092Sbostic * The Regents of the University of California. All rights reserved.
440395Sbostic * Copyright (c) 1989 by Berkeley Softworks
540395Sbostic * All rights reserved.
640395Sbostic *
740395Sbostic * This code is derived from software contributed to Berkeley by
840395Sbostic * Adam de Boor.
940395Sbostic *
1042752Sbostic * %sccs.include.redist.c%
1140395Sbostic */
1240395Sbostic
1340395Sbostic #ifndef lint
14*69887Schristos static char sccsid[] = "@(#)parse.c 8.6 (Berkeley) 06/13/95";
1540395Sbostic #endif /* not lint */
1640395Sbostic
1740393Sbostic /*-
1840393Sbostic * parse.c --
1940393Sbostic * Functions to parse a makefile.
2040393Sbostic *
2140393Sbostic * One function, Parse_Init, must be called before any functions
2240393Sbostic * in this module are used. After that, the function Parse_File is the
2340393Sbostic * main entry point and controls most of the other functions in this
2440393Sbostic * module.
2540393Sbostic *
2640393Sbostic * Most important structures are kept in Lsts. Directories for
2740393Sbostic * the #include "..." function are kept in the 'parseIncPath' Lst, while
2840393Sbostic * those for the #include <...> are kept in the 'sysIncPath' Lst. The
2940393Sbostic * targets currently being defined are kept in the 'targets' Lst.
3040393Sbostic *
3140393Sbostic * The variables 'fname' and 'lineno' are used to track the name
3240393Sbostic * of the current file and the line number in that file so that error
3340393Sbostic * messages can be more meaningful.
3440393Sbostic *
3540393Sbostic * Interface:
3640393Sbostic * Parse_Init Initialization function which must be
3740393Sbostic * called before anything else in this module
3840393Sbostic * is used.
3940393Sbostic *
4069086Schristos * Parse_End Cleanup the module
4169086Schristos *
4240393Sbostic * Parse_File Function used to parse a makefile. It must
4340393Sbostic * be given the name of the file, which should
4440393Sbostic * already have been opened, and a function
4540393Sbostic * to call to read a character from the file.
4640393Sbostic *
4740393Sbostic * Parse_IsVar Returns TRUE if the given line is a
4840393Sbostic * variable assignment. Used by MainParseArgs
4940393Sbostic * to determine if an argument is a target
5040393Sbostic * or a variable assignment. Used internally
5140393Sbostic * for pretty much the same thing...
5240393Sbostic *
5340393Sbostic * Parse_Error Function called when an error occurs in
5440393Sbostic * parsing. Used by the variable and
5540393Sbostic * conditional modules.
5640393Sbostic * Parse_MainName Returns a Lst of the main target to create.
5740393Sbostic */
5840393Sbostic
5960285Sbostic #if __STDC__
6060285Sbostic #include <stdarg.h>
6160285Sbostic #else
6240444Sbostic #include <varargs.h>
6360285Sbostic #endif
6440444Sbostic #include <stdio.h>
6540444Sbostic #include <ctype.h>
6660285Sbostic #include <errno.h>
6760285Sbostic #include <sys/wait.h>
6840444Sbostic #include "make.h"
6960285Sbostic #include "hash.h"
7060285Sbostic #include "dir.h"
7160285Sbostic #include "job.h"
7240444Sbostic #include "buf.h"
7340515Sbostic #include "pathnames.h"
7440393Sbostic
7540393Sbostic /*
7640393Sbostic * These values are returned by ParseEOF to tell Parse_File whether to
7740393Sbostic * CONTINUE parsing, i.e. it had only reached the end of an include file,
7840393Sbostic * or if it's DONE.
7940393Sbostic */
8040393Sbostic #define CONTINUE 1
8140393Sbostic #define DONE 0
8240393Sbostic static Lst targets; /* targets we're working on */
8369086Schristos static Lst targCmds; /* command lines for targets */
8440393Sbostic static Boolean inLine; /* true if currently in a dependency
8540393Sbostic * line or its commands */
8660285Sbostic typedef struct {
8760285Sbostic char *str;
8860285Sbostic char *ptr;
8960285Sbostic } PTR;
9040393Sbostic
9140393Sbostic static char *fname; /* name of current file (for errors) */
9240393Sbostic static int lineno; /* line number in current file */
9360285Sbostic static FILE *curFILE = NULL; /* current makefile */
9440393Sbostic
9560285Sbostic static PTR *curPTR = NULL; /* current makefile */
9660285Sbostic
9740393Sbostic static int fatals = 0;
9840393Sbostic
9940393Sbostic static GNode *mainNode; /* The main target to create. This is the
10040393Sbostic * first target on the first dependency
10140393Sbostic * line in the first makefile */
10240393Sbostic /*
10340393Sbostic * Definitions for handling #include specifications
10440393Sbostic */
10540393Sbostic typedef struct IFile {
10640393Sbostic char *fname; /* name of previous file */
10740393Sbostic int lineno; /* saved line number */
10860285Sbostic FILE * F; /* the open stream */
10960285Sbostic PTR * p; /* the char pointer */
11060285Sbostic } IFile;
11140393Sbostic
11240393Sbostic static Lst includes; /* stack of IFiles generated by
11340393Sbostic * #includes */
11440393Sbostic Lst parseIncPath; /* list of directories for "..." includes */
11540393Sbostic Lst sysIncPath; /* list of directories for <...> includes */
11640393Sbostic
11740393Sbostic /*-
11840393Sbostic * specType contains the SPECial TYPE of the current target. It is
11940393Sbostic * Not if the target is unspecial. If it *is* special, however, the children
12040393Sbostic * are linked as children of the parent but not vice versa. This variable is
12140393Sbostic * set in ParseDoDependency
12240393Sbostic */
12340393Sbostic typedef enum {
12440393Sbostic Begin, /* .BEGIN */
12540393Sbostic Default, /* .DEFAULT */
12640393Sbostic End, /* .END */
12740393Sbostic Ignore, /* .IGNORE */
12840393Sbostic Includes, /* .INCLUDES */
12940393Sbostic Interrupt, /* .INTERRUPT */
13040393Sbostic Libs, /* .LIBS */
13140393Sbostic MFlags, /* .MFLAGS or .MAKEFLAGS */
13240393Sbostic Main, /* .MAIN and we don't have anything user-specified to
13340393Sbostic * make */
13460285Sbostic NoExport, /* .NOEXPORT */
13540393Sbostic Not, /* Not special */
13640393Sbostic NotParallel, /* .NOTPARALELL */
13740393Sbostic Null, /* .NULL */
13840393Sbostic Order, /* .ORDER */
13960285Sbostic ExPath, /* .PATH */
14040393Sbostic Precious, /* .PRECIOUS */
141*69887Schristos Reserved, /* .RESERVED or .[A-Z]* */
14260285Sbostic ExShell, /* .SHELL */
14340393Sbostic Silent, /* .SILENT */
14440393Sbostic SingleShell, /* .SINGLESHELL */
14540393Sbostic Suffixes, /* .SUFFIXES */
14660285Sbostic Attribute /* Generic attribute */
14740393Sbostic } ParseSpecial;
14840393Sbostic
14960285Sbostic static ParseSpecial specType;
15040393Sbostic
15140393Sbostic /*
15240393Sbostic * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER
15340393Sbostic * seen, then set to each successive source on the line.
15440393Sbostic */
15540393Sbostic static GNode *predecessor;
15640393Sbostic
15740393Sbostic /*
15840393Sbostic * The parseKeywords table is searched using binary search when deciding
15940393Sbostic * if a target or source is special. The 'spec' field is the ParseSpecial
16040393Sbostic * type of the keyword ("Not" if the keyword isn't special as a target) while
16140393Sbostic * the 'op' field is the operator to apply to the list of targets if the
16240393Sbostic * keyword is used as a source ("0" if the keyword isn't special as a source)
16340393Sbostic */
16440393Sbostic static struct {
16540393Sbostic char *name; /* Name of keyword */
16640393Sbostic ParseSpecial spec; /* Type when used as a target */
16740393Sbostic int op; /* Operator when used as a source */
16840393Sbostic } parseKeywords[] = {
169*69887Schristos #define DOT_BEGIN 0
17040393Sbostic { ".BEGIN", Begin, 0 },
171*69887Schristos #define DOT_DEFAULT 1
17240393Sbostic { ".DEFAULT", Default, 0 },
173*69887Schristos #define DOT_END 2
17440393Sbostic { ".END", End, 0 },
175*69887Schristos #define DOT_EXEC 3
17640393Sbostic { ".EXEC", Attribute, OP_EXEC },
177*69887Schristos #define DOT_IGNORE 4
17840393Sbostic { ".IGNORE", Ignore, OP_IGNORE },
179*69887Schristos #define DOT_INCLUDES 5
18040393Sbostic { ".INCLUDES", Includes, 0 },
181*69887Schristos #define DOT_INTERRUPT 6
18240393Sbostic { ".INTERRUPT", Interrupt, 0 },
183*69887Schristos #define DOT_INVISIBLE 7
18440393Sbostic { ".INVISIBLE", Attribute, OP_INVISIBLE },
185*69887Schristos #define DOT_JOIN 8
18640393Sbostic { ".JOIN", Attribute, OP_JOIN },
187*69887Schristos #define DOT_LIBS 9
18840393Sbostic { ".LIBS", Libs, 0 },
189*69887Schristos #define DOT_MAIN 10
19040393Sbostic { ".MAIN", Main, 0 },
191*69887Schristos #define DOT_MAKE 11
19240393Sbostic { ".MAKE", Attribute, OP_MAKE },
193*69887Schristos #define DOT_MAKEFLAGS 12
19440393Sbostic { ".MAKEFLAGS", MFlags, 0 },
195*69887Schristos #define DOT_MFLAGS 13
19640393Sbostic { ".MFLAGS", MFlags, 0 },
197*69887Schristos #define DOT_NOTMAIN 14
19840393Sbostic { ".NOTMAIN", Attribute, OP_NOTMAIN },
199*69887Schristos #define DOT_NOTPARALLEL 15
20040393Sbostic { ".NOTPARALLEL", NotParallel, 0 },
201*69887Schristos #define DOT_NULL 16
20240393Sbostic { ".NULL", Null, 0 },
203*69887Schristos #define DOT_OPTIONAL 17
204*69887Schristos { ".OPTIONAL", Attribute, OP_OPTIONAL },
205*69887Schristos #define DOT_ORDER 18
20640393Sbostic { ".ORDER", Order, 0 },
207*69887Schristos #define DOT_PATH 19
20860285Sbostic { ".PATH", ExPath, 0 },
209*69887Schristos #define DOT_PHONY 20
210*69887Schristos { ".PHONY", Attribute, OP_PHONY },
211*69887Schristos #define DOT_PRECIOUS 21
21240393Sbostic { ".PRECIOUS", Precious, OP_PRECIOUS },
213*69887Schristos #define DOT_RECURSIVE 22
21440393Sbostic { ".RECURSIVE", Attribute, OP_MAKE },
215*69887Schristos #define DOT_RESERVED 23
216*69887Schristos { ".RESERVED", Reserved, 0 },
217*69887Schristos #define DOT_SHELL 24
21860285Sbostic { ".SHELL", ExShell, 0 },
219*69887Schristos #define DOT_SILENT 25
22040393Sbostic { ".SILENT", Silent, OP_SILENT },
221*69887Schristos #define DOT_SINGLESHELL 26
22240393Sbostic { ".SINGLESHELL", SingleShell, 0 },
223*69887Schristos #define DOT_SUFFIXES 27
22440393Sbostic { ".SUFFIXES", Suffixes, 0 },
225*69887Schristos #define DOT_USE 28
22640393Sbostic { ".USE", Attribute, OP_USE },
22740393Sbostic };
22840424Sbostic
22960285Sbostic static int ParseFindKeyword __P((char *));
23069086Schristos static int ParseLinkSrc __P((ClientData, ClientData));
23169086Schristos static int ParseDoOp __P((ClientData, ClientData));
23260285Sbostic static void ParseDoSrc __P((int, char *));
23369086Schristos static int ParseFindMain __P((ClientData, ClientData));
23469086Schristos static int ParseAddDir __P((ClientData, ClientData));
23569086Schristos static int ParseClearPath __P((ClientData, ClientData));
23660285Sbostic static void ParseDoDependency __P((char *));
23769086Schristos static int ParseAddCmd __P((ClientData, ClientData));
23860285Sbostic static int ParseReadc __P((void));
23960557Sbostic static void ParseUnreadc __P((int));
24069086Schristos static void ParseHasCommands __P((ClientData));
24160285Sbostic static void ParseDoInclude __P((char *));
24260285Sbostic #ifdef SYSVINCLUDE
24360285Sbostic static void ParseTraditionalInclude __P((char *));
24460285Sbostic #endif
24560285Sbostic static int ParseEOF __P((int));
24660285Sbostic static char *ParseReadLine __P((void));
24760285Sbostic static char *ParseSkipLine __P((int));
24860285Sbostic static void ParseFinishLine __P((void));
24960285Sbostic
25040393Sbostic /*-
25140393Sbostic *----------------------------------------------------------------------
25240393Sbostic * ParseFindKeyword --
25340393Sbostic * Look in the table of keywords for one matching the given string.
25440393Sbostic *
25540393Sbostic * Results:
25640393Sbostic * The index of the keyword, or -1 if it isn't there.
25740393Sbostic *
25840393Sbostic * Side Effects:
25940393Sbostic * None
26040393Sbostic *----------------------------------------------------------------------
26140393Sbostic */
26240393Sbostic static int
ParseFindKeyword(str)26340393Sbostic ParseFindKeyword (str)
26440393Sbostic char *str; /* String to find */
26540393Sbostic {
26640393Sbostic register int start,
26740393Sbostic end,
26840393Sbostic cur;
26940393Sbostic register int diff;
27040393Sbostic
27140393Sbostic start = 0;
27240393Sbostic end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1;
27340393Sbostic
27440393Sbostic do {
27540393Sbostic cur = start + ((end - start) / 2);
27640393Sbostic diff = strcmp (str, parseKeywords[cur].name);
27740393Sbostic
27840393Sbostic if (diff == 0) {
27940393Sbostic return (cur);
28040393Sbostic } else if (diff < 0) {
28140393Sbostic end = cur - 1;
28240393Sbostic } else {
28340393Sbostic start = cur + 1;
28440393Sbostic }
28540393Sbostic } while (start <= end);
286*69887Schristos
287*69887Schristos cur = 0;
288*69887Schristos for (++str; *str; str++)
289*69887Schristos if (!isupper((unsigned char) *str))
290*69887Schristos break;
291*69887Schristos return *str ? -1 : DOT_RESERVED;
29240393Sbostic }
29340424Sbostic
29440393Sbostic /*-
29540393Sbostic * Parse_Error --
29640393Sbostic * Error message abort function for parsing. Prints out the context
29740393Sbostic * of the error (line number and file) as well as the message with
29840393Sbostic * two optional arguments.
29940393Sbostic *
30040393Sbostic * Results:
30140393Sbostic * None
30240393Sbostic *
30340393Sbostic * Side Effects:
30440393Sbostic * "fatals" is incremented if the level is PARSE_FATAL.
30540393Sbostic */
30640444Sbostic /* VARARGS */
30740393Sbostic void
30860285Sbostic #if __STDC__
Parse_Error(int type,char * fmt,...)30969086Schristos Parse_Error(int type, char *fmt, ...)
31060285Sbostic #else
31166399Schristos Parse_Error(va_alist)
31240444Sbostic va_dcl
31360285Sbostic #endif
31440393Sbostic {
31540444Sbostic va_list ap;
31660285Sbostic #if __STDC__
31760285Sbostic va_start(ap, fmt);
31860285Sbostic #else
31966399Schristos int type; /* Error type (PARSE_WARNING, PARSE_FATAL) */
32066399Schristos char *fmt;
32166399Schristos
32260285Sbostic va_start(ap);
32366399Schristos type = va_arg(ap, int);
32466399Schristos fmt = va_arg(ap, char *);
32560285Sbostic #endif
32666399Schristos
32740444Sbostic (void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno);
32840444Sbostic if (type == PARSE_WARNING)
32940540Sbostic (void)fprintf(stderr, "warning: ");
33040444Sbostic (void)vfprintf(stderr, fmt, ap);
33140444Sbostic va_end(ap);
33240444Sbostic (void)fprintf(stderr, "\n");
33340444Sbostic (void)fflush(stderr);
33440444Sbostic if (type == PARSE_FATAL)
33540444Sbostic fatals += 1;
33640393Sbostic }
33740424Sbostic
33840393Sbostic /*-
33940393Sbostic *---------------------------------------------------------------------
34040393Sbostic * ParseLinkSrc --
34140393Sbostic * Link the parent node to its new child. Used in a Lst_ForEach by
34240393Sbostic * ParseDoDependency. If the specType isn't 'Not', the parent
34340393Sbostic * isn't linked as a parent of the child.
34440393Sbostic *
34540393Sbostic * Results:
34640393Sbostic * Always = 0
34740393Sbostic *
34840393Sbostic * Side Effects:
34940393Sbostic * New elements are added to the parents list of cgn and the
35040393Sbostic * children list of cgn. the unmade field of pgn is updated
35140393Sbostic * to reflect the additional child.
35240393Sbostic *---------------------------------------------------------------------
35340393Sbostic */
35440393Sbostic static int
ParseLinkSrc(pgnp,cgnp)35569086Schristos ParseLinkSrc (pgnp, cgnp)
35669086Schristos ClientData pgnp; /* The parent node */
35769086Schristos ClientData cgnp; /* The child node */
35840393Sbostic {
35969086Schristos GNode *pgn = (GNode *) pgnp;
36069086Schristos GNode *cgn = (GNode *) cgnp;
36140393Sbostic if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) {
36240393Sbostic (void)Lst_AtEnd (pgn->children, (ClientData)cgn);
36340393Sbostic if (specType == Not) {
36440393Sbostic (void)Lst_AtEnd (cgn->parents, (ClientData)pgn);
36540393Sbostic }
36640393Sbostic pgn->unmade += 1;
36740393Sbostic }
36840393Sbostic return (0);
36940393Sbostic }
37040424Sbostic
37140393Sbostic /*-
37240393Sbostic *---------------------------------------------------------------------
37340393Sbostic * ParseDoOp --
37440393Sbostic * Apply the parsed operator to the given target node. Used in a
37540393Sbostic * Lst_ForEach call by ParseDoDependency once all targets have
37640393Sbostic * been found and their operator parsed. If the previous and new
37740393Sbostic * operators are incompatible, a major error is taken.
37840393Sbostic *
37940393Sbostic * Results:
38040393Sbostic * Always 0
38140393Sbostic *
38240393Sbostic * Side Effects:
38340393Sbostic * The type field of the node is altered to reflect any new bits in
38440393Sbostic * the op.
38540393Sbostic *---------------------------------------------------------------------
38640393Sbostic */
38740393Sbostic static int
ParseDoOp(gnp,opp)38869086Schristos ParseDoOp (gnp, opp)
38969086Schristos ClientData gnp; /* The node to which the operator is to be
39040393Sbostic * applied */
39169086Schristos ClientData opp; /* The operator to apply */
39240393Sbostic {
39369086Schristos GNode *gn = (GNode *) gnp;
39469086Schristos int op = *(int *) opp;
39540393Sbostic /*
39640393Sbostic * If the dependency mask of the operator and the node don't match and
39740393Sbostic * the node has actually had an operator applied to it before, and
39840393Sbostic * the operator actually has some dependency information in it, complain.
39940393Sbostic */
40040393Sbostic if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
40140393Sbostic !OP_NOP(gn->type) && !OP_NOP(op))
40240393Sbostic {
40340393Sbostic Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name);
40440393Sbostic return (1);
40540393Sbostic }
40640393Sbostic
40740393Sbostic if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
40840393Sbostic /*
40940393Sbostic * If the node was the object of a :: operator, we need to create a
41040393Sbostic * new instance of it for the children and commands on this dependency
41140393Sbostic * line. The new instance is placed on the 'cohorts' list of the
41240393Sbostic * initial one (note the initial one is not on its own cohorts list)
41340393Sbostic * and the new instance is linked to all parents of the initial
41440393Sbostic * instance.
41540393Sbostic */
41640393Sbostic register GNode *cohort;
41740393Sbostic LstNode ln;
41840393Sbostic
41940393Sbostic cohort = Targ_NewGN(gn->name);
42040393Sbostic /*
42140393Sbostic * Duplicate links to parents so graph traversal is simple. Perhaps
42240393Sbostic * some type bits should be duplicated?
42340393Sbostic *
42440393Sbostic * Make the cohort invisible as well to avoid duplicating it into
42540393Sbostic * other variables. True, parents of this target won't tend to do
42640393Sbostic * anything with their local variables, but better safe than
42740393Sbostic * sorry.
42840393Sbostic */
42940393Sbostic Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort);
43040393Sbostic cohort->type = OP_DOUBLEDEP|OP_INVISIBLE;
43140393Sbostic (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort);
43240393Sbostic
43340393Sbostic /*
43440393Sbostic * Replace the node in the targets list with the new copy
43540393Sbostic */
43640393Sbostic ln = Lst_Member(targets, (ClientData)gn);
43740393Sbostic Lst_Replace(ln, (ClientData)cohort);
43840393Sbostic gn = cohort;
43940393Sbostic }
44040393Sbostic /*
44140393Sbostic * We don't want to nuke any previous flags (whatever they were) so we
44240393Sbostic * just OR the new operator into the old
44340393Sbostic */
44440393Sbostic gn->type |= op;
44540393Sbostic
44640393Sbostic return (0);
44740393Sbostic }
44840424Sbostic
44940393Sbostic /*-
45040393Sbostic *---------------------------------------------------------------------
45140393Sbostic * ParseDoSrc --
45240393Sbostic * Given the name of a source, figure out if it is an attribute
45340393Sbostic * and apply it to the targets if it is. Else decide if there is
45440393Sbostic * some attribute which should be applied *to* the source because
45540393Sbostic * of some special target and apply it if so. Otherwise, make the
45640393Sbostic * source be a child of the targets in the list 'targets'
45740393Sbostic *
45840393Sbostic * Results:
45940393Sbostic * None
46040393Sbostic *
46140393Sbostic * Side Effects:
46240393Sbostic * Operator bits may be added to the list of targets or to the source.
46340393Sbostic * The targets may have a new source added to their lists of children.
46440393Sbostic *---------------------------------------------------------------------
46540393Sbostic */
46640393Sbostic static void
ParseDoSrc(tOp,src)46740393Sbostic ParseDoSrc (tOp, src)
46840393Sbostic int tOp; /* operator (if any) from special targets */
46940393Sbostic char *src; /* name of the source to handle */
47040393Sbostic {
47140393Sbostic int op; /* operator (if any) from special source */
47240393Sbostic GNode *gn;
47340393Sbostic
47440393Sbostic op = 0;
47540393Sbostic if (*src == '.' && isupper (src[1])) {
47640393Sbostic int keywd = ParseFindKeyword(src);
47740393Sbostic if (keywd != -1) {
47840393Sbostic op = parseKeywords[keywd].op;
47940393Sbostic }
48040393Sbostic }
48140393Sbostic if (op != 0) {
48269086Schristos Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
48340393Sbostic } else if (specType == Main) {
48440393Sbostic /*
48540393Sbostic * If we have noted the existence of a .MAIN, it means we need
48640393Sbostic * to add the sources of said target to the list of things
48740393Sbostic * to create. The string 'src' is likely to be free, so we
48840393Sbostic * must make a new copy of it. Note that this will only be
48940393Sbostic * invoked if the user didn't specify a target on the command
49040393Sbostic * line. This is to allow #ifmake's to succeed, or something...
49140393Sbostic */
49240424Sbostic (void) Lst_AtEnd (create, (ClientData)strdup(src));
49340393Sbostic /*
49440393Sbostic * Add the name to the .TARGETS variable as well, so the user cna
49540393Sbostic * employ that, if desired.
49640393Sbostic */
49740393Sbostic Var_Append(".TARGETS", src, VAR_GLOBAL);
49840393Sbostic } else if (specType == Order) {
49940393Sbostic /*
50040393Sbostic * Create proper predecessor/successor links between the previous
50140393Sbostic * source and the current one.
50240393Sbostic */
50340393Sbostic gn = Targ_FindNode(src, TARG_CREATE);
50440393Sbostic if (predecessor != NILGNODE) {
50540393Sbostic (void)Lst_AtEnd(predecessor->successors, (ClientData)gn);
50640393Sbostic (void)Lst_AtEnd(gn->preds, (ClientData)predecessor);
50740393Sbostic }
50840393Sbostic /*
50940393Sbostic * The current source now becomes the predecessor for the next one.
51040393Sbostic */
51140393Sbostic predecessor = gn;
51240393Sbostic } else {
51340393Sbostic /*
51440393Sbostic * If the source is not an attribute, we need to find/create
51540393Sbostic * a node for it. After that we can apply any operator to it
51640393Sbostic * from a special target or link it to its parents, as
51740393Sbostic * appropriate.
51840393Sbostic *
51940393Sbostic * In the case of a source that was the object of a :: operator,
52040393Sbostic * the attribute is applied to all of its instances (as kept in
52140393Sbostic * the 'cohorts' list of the node) or all the cohorts are linked
52240393Sbostic * to all the targets.
52340393Sbostic */
52440393Sbostic gn = Targ_FindNode (src, TARG_CREATE);
52540393Sbostic if (tOp) {
52640393Sbostic gn->type |= tOp;
52740393Sbostic } else {
52840393Sbostic Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn);
52940393Sbostic }
53040393Sbostic if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
53140393Sbostic register GNode *cohort;
53240393Sbostic register LstNode ln;
53340393Sbostic
53440393Sbostic for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){
53540393Sbostic cohort = (GNode *)Lst_Datum(ln);
53640393Sbostic if (tOp) {
53740393Sbostic cohort->type |= tOp;
53840393Sbostic } else {
53940393Sbostic Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort);
54040393Sbostic }
54140393Sbostic }
54240393Sbostic }
54340393Sbostic }
54440393Sbostic }
54540424Sbostic
54640393Sbostic /*-
54740393Sbostic *-----------------------------------------------------------------------
54840393Sbostic * ParseFindMain --
54940393Sbostic * Find a real target in the list and set it to be the main one.
55040393Sbostic * Called by ParseDoDependency when a main target hasn't been found
55140393Sbostic * yet.
55240393Sbostic *
55340393Sbostic * Results:
55440393Sbostic * 0 if main not found yet, 1 if it is.
55540393Sbostic *
55640393Sbostic * Side Effects:
55740393Sbostic * mainNode is changed and Targ_SetMain is called.
55840393Sbostic *
55940393Sbostic *-----------------------------------------------------------------------
56040393Sbostic */
56140393Sbostic static int
ParseFindMain(gnp,dummy)56269086Schristos ParseFindMain(gnp, dummy)
56369086Schristos ClientData gnp; /* Node to examine */
56469086Schristos ClientData dummy;
56540393Sbostic {
56669086Schristos GNode *gn = (GNode *) gnp;
56740393Sbostic if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) {
56840393Sbostic mainNode = gn;
56940393Sbostic Targ_SetMain(gn);
57069086Schristos return (dummy ? 1 : 1);
57140393Sbostic } else {
57269086Schristos return (dummy ? 0 : 0);
57340393Sbostic }
57440393Sbostic }
57540424Sbostic
57640393Sbostic /*-
57740393Sbostic *-----------------------------------------------------------------------
57840393Sbostic * ParseAddDir --
57940393Sbostic * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going
58040393Sbostic *
58140393Sbostic * Results:
58240393Sbostic * === 0
58340393Sbostic *
58440393Sbostic * Side Effects:
58540393Sbostic * See Dir_AddDir.
58640393Sbostic *
58740393Sbostic *-----------------------------------------------------------------------
58840393Sbostic */
58940393Sbostic static int
ParseAddDir(path,name)59040393Sbostic ParseAddDir(path, name)
59169086Schristos ClientData path;
59269086Schristos ClientData name;
59340393Sbostic {
59469086Schristos Dir_AddDir((Lst) path, (char *) name);
59540393Sbostic return(0);
59640393Sbostic }
59740424Sbostic
59840393Sbostic /*-
59940393Sbostic *-----------------------------------------------------------------------
60040393Sbostic * ParseClearPath --
60140393Sbostic * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going
60240393Sbostic *
60340393Sbostic * Results:
60440393Sbostic * === 0
60540393Sbostic *
60640393Sbostic * Side Effects:
60740393Sbostic * See Dir_ClearPath
60840393Sbostic *
60940393Sbostic *-----------------------------------------------------------------------
61040393Sbostic */
61140393Sbostic static int
ParseClearPath(path,dummy)61269086Schristos ParseClearPath(path, dummy)
61369086Schristos ClientData path;
61469086Schristos ClientData dummy;
61540393Sbostic {
61669086Schristos Dir_ClearPath((Lst) path);
61769086Schristos return(dummy ? 0 : 0);
61840393Sbostic }
61940424Sbostic
62040393Sbostic /*-
62140393Sbostic *---------------------------------------------------------------------
62240393Sbostic * ParseDoDependency --
62340393Sbostic * Parse the dependency line in line.
62440393Sbostic *
62540393Sbostic * Results:
62640393Sbostic * None
62740393Sbostic *
62840393Sbostic * Side Effects:
62940393Sbostic * The nodes of the sources are linked as children to the nodes of the
63040393Sbostic * targets. Some nodes may be created.
63140393Sbostic *
63240393Sbostic * We parse a dependency line by first extracting words from the line and
63340393Sbostic * finding nodes in the list of all targets with that name. This is done
63440393Sbostic * until a character is encountered which is an operator character. Currently
63540393Sbostic * these are only ! and :. At this point the operator is parsed and the
63640393Sbostic * pointer into the line advanced until the first source is encountered.
63740393Sbostic * The parsed operator is applied to each node in the 'targets' list,
63840393Sbostic * which is where the nodes found for the targets are kept, by means of
63940393Sbostic * the ParseDoOp function.
64040393Sbostic * The sources are read in much the same way as the targets were except
64140393Sbostic * that now they are expanded using the wildcarding scheme of the C-Shell
64240393Sbostic * and all instances of the resulting words in the list of all targets
64340393Sbostic * are found. Each of the resulting nodes is then linked to each of the
64440393Sbostic * targets as one of its children.
64540393Sbostic * Certain targets are handled specially. These are the ones detailed
64640393Sbostic * by the specType variable.
64740393Sbostic * The storing of transformation rules is also taken care of here.
64840393Sbostic * A target is recognized as a transformation rule by calling
64940393Sbostic * Suff_IsTransform. If it is a transformation rule, its node is gotten
65040393Sbostic * from the suffix module via Suff_AddTransform rather than the standard
65140393Sbostic * Targ_FindNode in the target module.
65240393Sbostic *---------------------------------------------------------------------
65340393Sbostic */
65440393Sbostic static void
ParseDoDependency(line)65540393Sbostic ParseDoDependency (line)
65640393Sbostic char *line; /* the line to parse */
65740393Sbostic {
65869086Schristos char *cp; /* our current position */
65969086Schristos GNode *gn; /* a general purpose temporary node */
66069086Schristos int op; /* the operator on the line */
66140393Sbostic char savec; /* a place to save a character */
66240393Sbostic Lst paths; /* List of search paths to alter when parsing
66340393Sbostic * a list of .PATH targets */
66440393Sbostic int tOp; /* operator from special target */
66540393Sbostic Lst sources; /* list of source names after expansion */
66640393Sbostic Lst curTargs; /* list of target names to be found and added
66740393Sbostic * to the targets list */
66840393Sbostic
66940393Sbostic tOp = 0;
67040393Sbostic
67140393Sbostic specType = Not;
67240393Sbostic paths = (Lst)NULL;
67340393Sbostic
67440393Sbostic curTargs = Lst_Init(FALSE);
67540393Sbostic
67640393Sbostic do {
67740393Sbostic for (cp = line;
67840393Sbostic *cp && !isspace (*cp) &&
67940393Sbostic (*cp != '!') && (*cp != ':') && (*cp != '(');
68040393Sbostic cp++)
68140393Sbostic {
68240393Sbostic if (*cp == '$') {
68340393Sbostic /*
68440393Sbostic * Must be a dynamic source (would have been expanded
68540393Sbostic * otherwise), so call the Var module to parse the puppy
68640393Sbostic * so we can safely advance beyond it...There should be
68740393Sbostic * no errors in this, as they would have been discovered
68840393Sbostic * in the initial Var_Subst and we wouldn't be here.
68940393Sbostic */
69040393Sbostic int length;
69140393Sbostic Boolean freeIt;
69240393Sbostic char *result;
69340393Sbostic
69440393Sbostic result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);
69540393Sbostic
69640393Sbostic if (freeIt) {
69740393Sbostic free(result);
69840393Sbostic }
69940393Sbostic cp += length-1;
70040393Sbostic }
70140393Sbostic continue;
70240393Sbostic }
70340393Sbostic if (*cp == '(') {
70440393Sbostic /*
70540393Sbostic * Archives must be handled specially to make sure the OP_ARCHV
70640393Sbostic * flag is set in their 'type' field, for one thing, and because
70740393Sbostic * things like "archive(file1.o file2.o file3.o)" are permissible.
70840393Sbostic * Arch_ParseArchive will set 'line' to be the first non-blank
70940393Sbostic * after the archive-spec. It creates/finds nodes for the members
71040393Sbostic * and places them on the given list, returning SUCCESS if all
71140393Sbostic * went well and FAILURE if there was an error in the
71240393Sbostic * specification. On error, line should remain untouched.
71340393Sbostic */
71440393Sbostic if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) {
71540393Sbostic Parse_Error (PARSE_FATAL,
71640393Sbostic "Error in archive specification: \"%s\"", line);
71740393Sbostic return;
71840393Sbostic } else {
71940393Sbostic continue;
72040393Sbostic }
72140393Sbostic }
72240393Sbostic savec = *cp;
72340393Sbostic
72440393Sbostic if (!*cp) {
72540393Sbostic /*
72640393Sbostic * Ending a dependency line without an operator is a Bozo
72740393Sbostic * no-no
72840393Sbostic */
72940393Sbostic Parse_Error (PARSE_FATAL, "Need an operator");
73040393Sbostic return;
73140393Sbostic }
73240393Sbostic *cp = '\0';
73340393Sbostic /*
73440393Sbostic * Have a word in line. See if it's a special target and set
73540393Sbostic * specType to match it.
73640393Sbostic */
73740393Sbostic if (*line == '.' && isupper (line[1])) {
73840393Sbostic /*
73940393Sbostic * See if the target is a special target that must have it
74040393Sbostic * or its sources handled specially.
74140393Sbostic */
74240393Sbostic int keywd = ParseFindKeyword(line);
74340393Sbostic if (keywd != -1) {
74460285Sbostic if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {
74540393Sbostic Parse_Error(PARSE_FATAL, "Mismatched special targets");
74640393Sbostic return;
74740393Sbostic }
74840393Sbostic
74940393Sbostic specType = parseKeywords[keywd].spec;
75040393Sbostic tOp = parseKeywords[keywd].op;
75140393Sbostic
75240393Sbostic /*
75340393Sbostic * Certain special targets have special semantics:
75440393Sbostic * .PATH Have to set the dirSearchPath
75540393Sbostic * variable too
75640393Sbostic * .MAIN Its sources are only used if
75740393Sbostic * nothing has been specified to
75840393Sbostic * create.
75940393Sbostic * .DEFAULT Need to create a node to hang
76040393Sbostic * commands on, but we don't want
76140393Sbostic * it in the graph, nor do we want
76240393Sbostic * it to be the Main Target, so we
76340393Sbostic * create it, set OP_NOTMAIN and
76440393Sbostic * add it to the list, setting
76540393Sbostic * DEFAULT to the new node for
76640393Sbostic * later use. We claim the node is
76740393Sbostic * A transformation rule to make
76840393Sbostic * life easier later, when we'll
76940393Sbostic * use Make_HandleUse to actually
77040393Sbostic * apply the .DEFAULT commands.
77140393Sbostic * .BEGIN
77240393Sbostic * .END
77340393Sbostic * .INTERRUPT Are not to be considered the
77440393Sbostic * main target.
77540393Sbostic * .NOTPARALLEL Make only one target at a time.
77640393Sbostic * .SINGLESHELL Create a shell for each command.
77740393Sbostic * .ORDER Must set initial predecessor to NIL
77840393Sbostic */
77940393Sbostic switch (specType) {
78060285Sbostic case ExPath:
78140393Sbostic if (paths == NULL) {
78240393Sbostic paths = Lst_Init(FALSE);
78340393Sbostic }
78440393Sbostic (void)Lst_AtEnd(paths, (ClientData)dirSearchPath);
78540393Sbostic break;
78640393Sbostic case Main:
78740393Sbostic if (!Lst_IsEmpty(create)) {
78840393Sbostic specType = Not;
78940393Sbostic }
79040393Sbostic break;
79140393Sbostic case Begin:
79240393Sbostic case End:
79340393Sbostic case Interrupt:
79440393Sbostic gn = Targ_FindNode(line, TARG_CREATE);
79540393Sbostic gn->type |= OP_NOTMAIN;
79640393Sbostic (void)Lst_AtEnd(targets, (ClientData)gn);
79740393Sbostic break;
79840393Sbostic case Default:
79940393Sbostic gn = Targ_NewGN(".DEFAULT");
80040393Sbostic gn->type |= (OP_NOTMAIN|OP_TRANSFORM);
80140393Sbostic (void)Lst_AtEnd(targets, (ClientData)gn);
80240393Sbostic DEFAULT = gn;
80340393Sbostic break;
80440393Sbostic case NotParallel:
80540393Sbostic {
80640393Sbostic extern int maxJobs;
80740393Sbostic
80840393Sbostic maxJobs = 1;
80940393Sbostic break;
81040393Sbostic }
81140393Sbostic case SingleShell:
81260285Sbostic compatMake = 1;
81340393Sbostic break;
81440393Sbostic case Order:
81540393Sbostic predecessor = NILGNODE;
81640393Sbostic break;
817*69887Schristos case Reserved:
818*69887Schristos /*
819*69887Schristos * A posix reserved target that we don't know
820*69887Schristos * how to deal with.
821*69887Schristos */
822*69887Schristos return;
82360285Sbostic default:
82460285Sbostic break;
82540393Sbostic }
82640393Sbostic } else if (strncmp (line, ".PATH", 5) == 0) {
82740393Sbostic /*
82840393Sbostic * .PATH<suffix> has to be handled specially.
82940393Sbostic * Call on the suffix module to give us a path to
83040393Sbostic * modify.
83140393Sbostic */
83240393Sbostic Lst path;
83340393Sbostic
83460285Sbostic specType = ExPath;
83540393Sbostic path = Suff_GetPath (&line[5]);
83640393Sbostic if (path == NILLST) {
83740393Sbostic Parse_Error (PARSE_FATAL,
83840393Sbostic "Suffix '%s' not defined (yet)",
83940393Sbostic &line[5]);
84040393Sbostic return;
84140393Sbostic } else {
84240393Sbostic if (paths == (Lst)NULL) {
84340393Sbostic paths = Lst_Init(FALSE);
84440393Sbostic }
84540393Sbostic (void)Lst_AtEnd(paths, (ClientData)path);
84640393Sbostic }
84740393Sbostic }
84840393Sbostic }
84940393Sbostic
85040393Sbostic /*
85140393Sbostic * Have word in line. Get or create its node and stick it at
85240393Sbostic * the end of the targets list
85340393Sbostic */
85440393Sbostic if ((specType == Not) && (*line != '\0')) {
85540393Sbostic if (Dir_HasWildcards(line)) {
85640393Sbostic /*
85740393Sbostic * Targets are to be sought only in the current directory,
85840393Sbostic * so create an empty path for the thing. Note we need to
85940393Sbostic * use Dir_Destroy in the destruction of the path as the
86040393Sbostic * Dir module could have added a directory to the path...
86140393Sbostic */
86240393Sbostic Lst emptyPath = Lst_Init(FALSE);
86340393Sbostic
86440393Sbostic Dir_Expand(line, emptyPath, curTargs);
86540393Sbostic
86640393Sbostic Lst_Destroy(emptyPath, Dir_Destroy);
86740393Sbostic } else {
86840393Sbostic /*
86940393Sbostic * No wildcards, but we want to avoid code duplication,
87040393Sbostic * so create a list with the word on it.
87140393Sbostic */
87240393Sbostic (void)Lst_AtEnd(curTargs, (ClientData)line);
87340393Sbostic }
87440393Sbostic
87540393Sbostic while(!Lst_IsEmpty(curTargs)) {
87640393Sbostic char *targName = (char *)Lst_DeQueue(curTargs);
87740393Sbostic
87840393Sbostic if (!Suff_IsTransform (targName)) {
87940393Sbostic gn = Targ_FindNode (targName, TARG_CREATE);
88040393Sbostic } else {
88140393Sbostic gn = Suff_AddTransform (targName);
88240393Sbostic }
88340393Sbostic
88440393Sbostic (void)Lst_AtEnd (targets, (ClientData)gn);
88540393Sbostic }
88660285Sbostic } else if (specType == ExPath && *line != '.' && *line != '\0') {
88740393Sbostic Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);
88840393Sbostic }
88940393Sbostic
89040393Sbostic *cp = savec;
89140393Sbostic /*
89240393Sbostic * If it is a special type and not .PATH, it's the only target we
89340393Sbostic * allow on this line...
89440393Sbostic */
89560285Sbostic if (specType != Not && specType != ExPath) {
89640393Sbostic Boolean warn = FALSE;
89740393Sbostic
89840393Sbostic while ((*cp != '!') && (*cp != ':') && *cp) {
89940393Sbostic if (*cp != ' ' && *cp != '\t') {
90040393Sbostic warn = TRUE;
90140393Sbostic }
90240393Sbostic cp++;
90340393Sbostic }
90440393Sbostic if (warn) {
90540393Sbostic Parse_Error(PARSE_WARNING, "Extra target ignored");
90640393Sbostic }
90740393Sbostic } else {
90840393Sbostic while (*cp && isspace (*cp)) {
90940393Sbostic cp++;
91040393Sbostic }
91140393Sbostic }
91240393Sbostic line = cp;
91340393Sbostic } while ((*line != '!') && (*line != ':') && *line);
91440393Sbostic
91540393Sbostic /*
91640393Sbostic * Don't need the list of target names anymore...
91740393Sbostic */
91840393Sbostic Lst_Destroy(curTargs, NOFREE);
91940393Sbostic
92040393Sbostic if (!Lst_IsEmpty(targets)) {
92140393Sbostic switch(specType) {
92240393Sbostic default:
92340393Sbostic Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");
92440393Sbostic break;
92540393Sbostic case Default:
92640393Sbostic case Begin:
92740393Sbostic case End:
92840393Sbostic case Interrupt:
92940393Sbostic /*
93040393Sbostic * These four create nodes on which to hang commands, so
93140393Sbostic * targets shouldn't be empty...
93240393Sbostic */
93340393Sbostic case Not:
93440393Sbostic /*
93540393Sbostic * Nothing special here -- targets can be empty if it wants.
93640393Sbostic */
93740393Sbostic break;
93840393Sbostic }
93940393Sbostic }
94040393Sbostic
94140393Sbostic /*
94240393Sbostic * Have now parsed all the target names. Must parse the operator next. The
94340393Sbostic * result is left in op .
94440393Sbostic */
94540393Sbostic if (*cp == '!') {
94640393Sbostic op = OP_FORCE;
94740393Sbostic } else if (*cp == ':') {
94840393Sbostic if (cp[1] == ':') {
94940393Sbostic op = OP_DOUBLEDEP;
95040393Sbostic cp++;
95140393Sbostic } else {
95240393Sbostic op = OP_DEPENDS;
95340393Sbostic }
95440393Sbostic } else {
95540393Sbostic Parse_Error (PARSE_FATAL, "Missing dependency operator");
95640393Sbostic return;
95740393Sbostic }
95840393Sbostic
95940393Sbostic cp++; /* Advance beyond operator */
96040393Sbostic
96169086Schristos Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
96240393Sbostic
96340393Sbostic /*
96440393Sbostic * Get to the first source
96540393Sbostic */
96640393Sbostic while (*cp && isspace (*cp)) {
96740393Sbostic cp++;
96840393Sbostic }
96940393Sbostic line = cp;
97040393Sbostic
97140393Sbostic /*
97240393Sbostic * Several special targets take different actions if present with no
97340393Sbostic * sources:
97440393Sbostic * a .SUFFIXES line with no sources clears out all old suffixes
97540393Sbostic * a .PRECIOUS line makes all targets precious
97640393Sbostic * a .IGNORE line ignores errors for all targets
97740393Sbostic * a .SILENT line creates silence when making all targets
97840393Sbostic * a .PATH removes all directories from the search path(s).
97940393Sbostic */
98040393Sbostic if (!*line) {
98140393Sbostic switch (specType) {
98240393Sbostic case Suffixes:
98340393Sbostic Suff_ClearSuffixes ();
98440393Sbostic break;
98540393Sbostic case Precious:
98640393Sbostic allPrecious = TRUE;
98740393Sbostic break;
98840393Sbostic case Ignore:
98940393Sbostic ignoreErrors = TRUE;
99040393Sbostic break;
99140393Sbostic case Silent:
99240393Sbostic beSilent = TRUE;
99340393Sbostic break;
99460285Sbostic case ExPath:
99540393Sbostic Lst_ForEach(paths, ParseClearPath, (ClientData)NULL);
99640393Sbostic break;
99760285Sbostic default:
99860285Sbostic break;
99940393Sbostic }
100040393Sbostic } else if (specType == MFlags) {
100140393Sbostic /*
100240393Sbostic * Call on functions in main.c to deal with these arguments and
100340393Sbostic * set the initial character to a null-character so the loop to
100440393Sbostic * get sources won't get anything
100540393Sbostic */
100640393Sbostic Main_ParseArgLine (line);
100740393Sbostic *line = '\0';
100860285Sbostic } else if (specType == ExShell) {
100940393Sbostic if (Job_ParseShell (line) != SUCCESS) {
101040393Sbostic Parse_Error (PARSE_FATAL, "improper shell specification");
101140393Sbostic return;
101240393Sbostic }
101340393Sbostic *line = '\0';
101440393Sbostic } else if ((specType == NotParallel) || (specType == SingleShell)) {
101540393Sbostic *line = '\0';
101640393Sbostic }
101740393Sbostic
101840393Sbostic /*
101940393Sbostic * NOW GO FOR THE SOURCES
102040393Sbostic */
102160285Sbostic if ((specType == Suffixes) || (specType == ExPath) ||
102240393Sbostic (specType == Includes) || (specType == Libs) ||
102340439Sbostic (specType == Null))
102440393Sbostic {
102540393Sbostic while (*line) {
102640393Sbostic /*
102740393Sbostic * If the target was one that doesn't take files as its sources
102840393Sbostic * but takes something like suffixes, we take each
102940393Sbostic * space-separated word on the line as a something and deal
103040393Sbostic * with it accordingly.
103140393Sbostic *
103240393Sbostic * If the target was .SUFFIXES, we take each source as a
103340393Sbostic * suffix and add it to the list of suffixes maintained by the
103440393Sbostic * Suff module.
103540393Sbostic *
103640393Sbostic * If the target was a .PATH, we add the source as a directory
103740393Sbostic * to search on the search path.
103840393Sbostic *
103940393Sbostic * If it was .INCLUDES, the source is taken to be the suffix of
104040393Sbostic * files which will be #included and whose search path should
104140393Sbostic * be present in the .INCLUDES variable.
104240393Sbostic *
104340393Sbostic * If it was .LIBS, the source is taken to be the suffix of
104440393Sbostic * files which are considered libraries and whose search path
104540393Sbostic * should be present in the .LIBS variable.
104640393Sbostic *
104740393Sbostic * If it was .NULL, the source is the suffix to use when a file
104840393Sbostic * has no valid suffix.
104940393Sbostic */
105040393Sbostic char savec;
105140393Sbostic while (*cp && !isspace (*cp)) {
105240393Sbostic cp++;
105340393Sbostic }
105440393Sbostic savec = *cp;
105540393Sbostic *cp = '\0';
105640393Sbostic switch (specType) {
105740393Sbostic case Suffixes:
105840393Sbostic Suff_AddSuffix (line);
105940393Sbostic break;
106060285Sbostic case ExPath:
106140393Sbostic Lst_ForEach(paths, ParseAddDir, (ClientData)line);
106240393Sbostic break;
106340393Sbostic case Includes:
106440393Sbostic Suff_AddInclude (line);
106540393Sbostic break;
106640393Sbostic case Libs:
106740393Sbostic Suff_AddLib (line);
106840393Sbostic break;
106940393Sbostic case Null:
107040393Sbostic Suff_SetNull (line);
107140393Sbostic break;
107260285Sbostic default:
107360285Sbostic break;
107440393Sbostic }
107540393Sbostic *cp = savec;
107640393Sbostic if (savec != '\0') {
107740393Sbostic cp++;
107840393Sbostic }
107940393Sbostic while (*cp && isspace (*cp)) {
108040393Sbostic cp++;
108140393Sbostic }
108240393Sbostic line = cp;
108340393Sbostic }
108440393Sbostic if (paths) {
108540393Sbostic Lst_Destroy(paths, NOFREE);
108640393Sbostic }
108740393Sbostic } else {
108840393Sbostic while (*line) {
108940393Sbostic /*
109040393Sbostic * The targets take real sources, so we must beware of archive
109140393Sbostic * specifications (i.e. things with left parentheses in them)
109240393Sbostic * and handle them accordingly.
109340393Sbostic */
109440393Sbostic while (*cp && !isspace (*cp)) {
109540393Sbostic if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) {
109640393Sbostic /*
109740393Sbostic * Only stop for a left parenthesis if it isn't at the
109840393Sbostic * start of a word (that'll be for variable changes
109940393Sbostic * later) and isn't preceded by a dollar sign (a dynamic
110040393Sbostic * source).
110140393Sbostic */
110240393Sbostic break;
110340393Sbostic } else {
110440393Sbostic cp++;
110540393Sbostic }
110640393Sbostic }
110740393Sbostic
110840393Sbostic if (*cp == '(') {
110940393Sbostic GNode *gn;
111040393Sbostic
111140393Sbostic sources = Lst_Init (FALSE);
111240393Sbostic if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) {
111340393Sbostic Parse_Error (PARSE_FATAL,
111440393Sbostic "Error in source archive spec \"%s\"", line);
111540393Sbostic return;
111640393Sbostic }
111740393Sbostic
111840393Sbostic while (!Lst_IsEmpty (sources)) {
111940393Sbostic gn = (GNode *) Lst_DeQueue (sources);
112040393Sbostic ParseDoSrc (tOp, gn->name);
112140393Sbostic }
112240393Sbostic Lst_Destroy (sources, NOFREE);
112340393Sbostic cp = line;
112440393Sbostic } else {
112540393Sbostic if (*cp) {
112640393Sbostic *cp = '\0';
112740393Sbostic cp += 1;
112840393Sbostic }
112940393Sbostic
113040393Sbostic ParseDoSrc (tOp, line);
113140393Sbostic }
113240393Sbostic while (*cp && isspace (*cp)) {
113340393Sbostic cp++;
113440393Sbostic }
113540393Sbostic line = cp;
113640393Sbostic }
113740393Sbostic }
113840393Sbostic
113940393Sbostic if (mainNode == NILGNODE) {
114040393Sbostic /*
114140393Sbostic * If we have yet to decide on a main target to make, in the
114240393Sbostic * absence of any user input, we want the first target on
114340393Sbostic * the first dependency line that is actually a real target
114440393Sbostic * (i.e. isn't a .USE or .EXEC rule) to be made.
114540393Sbostic */
114640393Sbostic Lst_ForEach (targets, ParseFindMain, (ClientData)0);
114740393Sbostic }
114840393Sbostic
114940393Sbostic }
115040424Sbostic
115140393Sbostic /*-
115240393Sbostic *---------------------------------------------------------------------
115340393Sbostic * Parse_IsVar --
115440393Sbostic * Return TRUE if the passed line is a variable assignment. A variable
115540393Sbostic * assignment consists of a single word followed by optional whitespace
115640393Sbostic * followed by either a += or an = operator.
115740393Sbostic * This function is used both by the Parse_File function and main when
115840393Sbostic * parsing the command-line arguments.
115940393Sbostic *
116040393Sbostic * Results:
116140393Sbostic * TRUE if it is. FALSE if it ain't
116240393Sbostic *
116340393Sbostic * Side Effects:
116440393Sbostic * none
116540393Sbostic *---------------------------------------------------------------------
116640393Sbostic */
116740393Sbostic Boolean
Parse_IsVar(line)116840393Sbostic Parse_IsVar (line)
116940393Sbostic register char *line; /* the line to check */
117040393Sbostic {
117140393Sbostic register Boolean wasSpace = FALSE; /* set TRUE if found a space */
117240393Sbostic register Boolean haveName = FALSE; /* Set TRUE if have a variable name */
117340393Sbostic
117440393Sbostic /*
117540393Sbostic * Skip to variable name
117640393Sbostic */
117740393Sbostic while ((*line == ' ') || (*line == '\t')) {
117840393Sbostic line++;
117940393Sbostic }
118040393Sbostic
118140393Sbostic while (*line != '=') {
118240393Sbostic if (*line == '\0') {
118340393Sbostic /*
118440393Sbostic * end-of-line -- can't be a variable assignment.
118540393Sbostic */
118640393Sbostic return (FALSE);
118740393Sbostic } else if ((*line == ' ') || (*line == '\t')) {
118840393Sbostic /*
118940393Sbostic * there can be as much white space as desired so long as there is
119040393Sbostic * only one word before the operator
119140393Sbostic */
119240393Sbostic wasSpace = TRUE;
119340393Sbostic } else if (wasSpace && haveName) {
119440393Sbostic /*
119540393Sbostic * Stop when an = operator is found.
119640393Sbostic */
119740393Sbostic if ((*line == '+') || (*line == ':') || (*line == '?') ||
119840393Sbostic (*line == '!')) {
119940393Sbostic break;
120040393Sbostic }
120140393Sbostic
120240393Sbostic /*
120340393Sbostic * This is the start of another word, so not assignment.
120440393Sbostic */
120540393Sbostic return (FALSE);
120640393Sbostic } else {
120740393Sbostic haveName = TRUE;
120840393Sbostic wasSpace = FALSE;
120940393Sbostic }
121040393Sbostic line++;
121140393Sbostic }
121240393Sbostic
121340393Sbostic /*
121440393Sbostic * A final check: if we stopped on a +, ?, ! or :, the next character must
121540393Sbostic * be an = or it ain't a valid assignment
121640393Sbostic */
121740393Sbostic if (((*line == '+') ||
121840393Sbostic (*line == '?') ||
121940393Sbostic (*line == ':') ||
122040393Sbostic (*line == '!')) &&
122140393Sbostic (line[1] != '='))
122240393Sbostic {
122340393Sbostic return (FALSE);
122440393Sbostic } else {
122540393Sbostic return (haveName);
122640393Sbostic }
122740393Sbostic }
122840424Sbostic
122940393Sbostic /*-
123040393Sbostic *---------------------------------------------------------------------
123140393Sbostic * Parse_DoVar --
123240393Sbostic * Take the variable assignment in the passed line and do it in the
123340393Sbostic * global context.
123440393Sbostic *
123540393Sbostic * Note: There is a lexical ambiguity with assignment modifier characters
123640393Sbostic * in variable names. This routine interprets the character before the =
123740393Sbostic * as a modifier. Therefore, an assignment like
123840393Sbostic * C++=/usr/bin/CC
123940393Sbostic * is interpreted as "C+ +=" instead of "C++ =".
124040393Sbostic *
124140393Sbostic * Results:
124240393Sbostic * none
124340393Sbostic *
124440393Sbostic * Side Effects:
124540393Sbostic * the variable structure of the given variable name is altered in the
124640393Sbostic * global context.
124740393Sbostic *---------------------------------------------------------------------
124840393Sbostic */
124940393Sbostic void
Parse_DoVar(line,ctxt)125040393Sbostic Parse_DoVar (line, ctxt)
125140393Sbostic char *line; /* a line guaranteed to be a variable
125240393Sbostic * assignment. This reduces error checks */
125340393Sbostic GNode *ctxt; /* Context in which to do the assignment */
125440393Sbostic {
125569086Schristos char *cp; /* pointer into line */
125640393Sbostic enum {
125740393Sbostic VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL
125840393Sbostic } type; /* Type of assignment */
125940393Sbostic char *opc; /* ptr to operator character to
126040393Sbostic * null-terminate the variable name */
126169086Schristos /*
126266399Schristos * Avoid clobbered variable warnings by forcing the compiler
126366399Schristos * to ``unregister'' variables
126469086Schristos */
126566399Schristos #if __GNUC__
126669086Schristos (void) &cp;
126769086Schristos (void) &line;
126869086Schristos #endif
126940393Sbostic
127040393Sbostic /*
127140393Sbostic * Skip to variable name
127240393Sbostic */
127340393Sbostic while ((*line == ' ') || (*line == '\t')) {
127440393Sbostic line++;
127540393Sbostic }
127640393Sbostic
127740393Sbostic /*
127840393Sbostic * Skip to operator character, nulling out whitespace as we go
127940393Sbostic */
128040393Sbostic for (cp = line + 1; *cp != '='; cp++) {
128140393Sbostic if (isspace (*cp)) {
128240393Sbostic *cp = '\0';
128340393Sbostic }
128440393Sbostic }
128540393Sbostic opc = cp-1; /* operator is the previous character */
128640393Sbostic *cp++ = '\0'; /* nuke the = */
128740393Sbostic
128840393Sbostic /*
128940393Sbostic * Check operator type
129040393Sbostic */
129140393Sbostic switch (*opc) {
129240393Sbostic case '+':
129340393Sbostic type = VAR_APPEND;
129440393Sbostic *opc = '\0';
129540393Sbostic break;
129640393Sbostic
129740393Sbostic case '?':
129840393Sbostic /*
129940393Sbostic * If the variable already has a value, we don't do anything.
130040393Sbostic */
130140393Sbostic *opc = '\0';
130240393Sbostic if (Var_Exists(line, ctxt)) {
130340393Sbostic return;
130440393Sbostic } else {
130540393Sbostic type = VAR_NORMAL;
130640393Sbostic }
130740393Sbostic break;
130840393Sbostic
130940393Sbostic case ':':
131040393Sbostic type = VAR_SUBST;
131140393Sbostic *opc = '\0';
131240393Sbostic break;
131340393Sbostic
131440393Sbostic case '!':
131540393Sbostic type = VAR_SHELL;
131640393Sbostic *opc = '\0';
131740393Sbostic break;
131840393Sbostic
131940393Sbostic default:
132040393Sbostic type = VAR_NORMAL;
132140393Sbostic break;
132240393Sbostic }
132340393Sbostic
132440393Sbostic while (isspace (*cp)) {
132540393Sbostic cp++;
132640393Sbostic }
132740393Sbostic
132840393Sbostic if (type == VAR_APPEND) {
132940393Sbostic Var_Append (line, cp, ctxt);
133040393Sbostic } else if (type == VAR_SUBST) {
133140393Sbostic /*
133240393Sbostic * Allow variables in the old value to be undefined, but leave their
133340393Sbostic * invocation alone -- this is done by forcing oldVars to be false.
133440393Sbostic * XXX: This can cause recursive variables, but that's not hard to do,
133540393Sbostic * and this allows someone to do something like
133640393Sbostic *
133740393Sbostic * CFLAGS = $(.INCLUDES)
133840393Sbostic * CFLAGS := -I.. $(CFLAGS)
133940393Sbostic *
134040393Sbostic * And not get an error.
134140393Sbostic */
134240393Sbostic Boolean oldOldVars = oldVars;
134340393Sbostic
134440393Sbostic oldVars = FALSE;
134560285Sbostic cp = Var_Subst(NULL, cp, ctxt, FALSE);
134640393Sbostic oldVars = oldOldVars;
134740393Sbostic
134840393Sbostic Var_Set(line, cp, ctxt);
134940393Sbostic free(cp);
135040393Sbostic } else if (type == VAR_SHELL) {
135140393Sbostic char *args[4]; /* Args for invoking the shell */
135240393Sbostic int fds[2]; /* Pipe streams */
135340393Sbostic int cpid; /* Child PID */
135440393Sbostic int pid; /* PID from wait() */
135540393Sbostic Boolean freeCmd; /* TRUE if the command needs to be freed, i.e.
135640393Sbostic * if any variable expansion was performed */
135740393Sbostic
135869086Schristos /*
135966399Schristos * Avoid clobbered variable warnings by forcing the compiler
136066399Schristos * to ``unregister'' variables
136169086Schristos */
136266399Schristos #if __GNUC__
136366399Schristos (void) &freeCmd;
136469086Schristos #endif
136569086Schristos
136640393Sbostic /*
136740393Sbostic * Set up arguments for shell
136840393Sbostic */
136940393Sbostic args[0] = "sh";
137040393Sbostic args[1] = "-c";
137160285Sbostic if (strchr(cp, '$') != (char *)NULL) {
137240393Sbostic /*
137340393Sbostic * There's a dollar sign in the command, so perform variable
137440393Sbostic * expansion on the whole thing. The resulting string will need
137540393Sbostic * freeing when we're done, so set freeCmd to TRUE.
137640393Sbostic */
137760285Sbostic args[2] = Var_Subst(NULL, cp, VAR_CMD, TRUE);
137840393Sbostic freeCmd = TRUE;
137940393Sbostic } else {
138040393Sbostic args[2] = cp;
138140393Sbostic freeCmd = FALSE;
138240393Sbostic }
138340393Sbostic args[3] = (char *)NULL;
138440393Sbostic
138540393Sbostic /*
138640393Sbostic * Open a pipe for fetching its output
138740393Sbostic */
138840393Sbostic pipe(fds);
138940393Sbostic
139040393Sbostic /*
139140393Sbostic * Fork
139240393Sbostic */
139340393Sbostic cpid = vfork();
139440393Sbostic if (cpid == 0) {
139540393Sbostic /*
139640393Sbostic * Close input side of pipe
139740393Sbostic */
139840393Sbostic close(fds[0]);
139940393Sbostic
140040393Sbostic /*
140140393Sbostic * Duplicate the output stream to the shell's output, then
140240393Sbostic * shut the extra thing down. Note we don't fetch the error
140340393Sbostic * stream...why not? Why?
140440393Sbostic */
140540393Sbostic dup2(fds[1], 1);
140640393Sbostic close(fds[1]);
140740393Sbostic
140840393Sbostic execv("/bin/sh", args);
140940393Sbostic _exit(1);
141040393Sbostic } else if (cpid < 0) {
141140393Sbostic /*
141240393Sbostic * Couldn't fork -- tell the user and make the variable null
141340393Sbostic */
141440393Sbostic Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp);
141540393Sbostic Var_Set(line, "", ctxt);
141640393Sbostic } else {
141740393Sbostic int status;
141840393Sbostic int cc;
141960285Sbostic Buffer buf;
142060285Sbostic char *res;
142140393Sbostic
142240393Sbostic /*
142340393Sbostic * No need for the writing half
142440393Sbostic */
142540393Sbostic close(fds[1]);
142640393Sbostic
142760285Sbostic buf = Buf_Init (MAKE_BSIZE);
142860285Sbostic
142960285Sbostic do {
143060285Sbostic char result[BUFSIZ];
143160285Sbostic cc = read(fds[0], result, sizeof(result));
143260285Sbostic if (cc > 0)
143369086Schristos Buf_AddBytes(buf, cc, (Byte *) result);
143460285Sbostic }
143560285Sbostic while (cc > 0 || (cc == -1 && errno == EINTR));
143660285Sbostic
143740393Sbostic /*
143860285Sbostic * Close the input side of the pipe.
143940393Sbostic */
144060285Sbostic close(fds[0]);
144140393Sbostic
144240393Sbostic /*
144360285Sbostic * Wait for the process to exit.
144440393Sbostic */
144560285Sbostic while(((pid = wait(&status)) != cpid) && (pid >= 0))
144660285Sbostic continue;
144740393Sbostic
144860285Sbostic res = (char *)Buf_GetAll (buf, &cc);
144960285Sbostic Buf_Destroy (buf, FALSE);
145060285Sbostic
145160285Sbostic if (cc == 0) {
145240393Sbostic /*
145340393Sbostic * Couldn't read the child's output -- tell the user and
145440393Sbostic * set the variable to null
145540393Sbostic */
145640393Sbostic Parse_Error(PARSE_WARNING, "Couldn't read shell's output");
145740393Sbostic }
145840393Sbostic
145940393Sbostic if (status) {
146040393Sbostic /*
146140393Sbostic * Child returned an error -- tell the user but still use
146240393Sbostic * the result.
146340393Sbostic */
146440393Sbostic Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp);
146540393Sbostic }
146660285Sbostic
146740393Sbostic /*
146840393Sbostic * Null-terminate the result, convert newlines to spaces and
146940393Sbostic * install it in the variable.
147040393Sbostic */
147160285Sbostic res[cc] = '\0';
147260285Sbostic cp = &res[cc] - 1;
147340393Sbostic
147440393Sbostic if (*cp == '\n') {
147540393Sbostic /*
147640393Sbostic * A final newline is just stripped
147740393Sbostic */
147840393Sbostic *cp-- = '\0';
147940393Sbostic }
148060285Sbostic while (cp >= res) {
148140393Sbostic if (*cp == '\n') {
148240393Sbostic *cp = ' ';
148340393Sbostic }
148440393Sbostic cp--;
148540393Sbostic }
148660285Sbostic Var_Set(line, res, ctxt);
148760285Sbostic free(res);
148840393Sbostic
148940393Sbostic }
149040393Sbostic if (freeCmd) {
149140393Sbostic free(args[2]);
149240393Sbostic }
149340393Sbostic } else {
149440393Sbostic /*
149540393Sbostic * Normal assignment -- just do it.
149640393Sbostic */
149740393Sbostic Var_Set (line, cp, ctxt);
149840393Sbostic }
149940393Sbostic }
150040424Sbostic
150140393Sbostic /*-
150240393Sbostic * ParseAddCmd --
150340393Sbostic * Lst_ForEach function to add a command line to all targets
150440393Sbostic *
150540393Sbostic * Results:
150640393Sbostic * Always 0
150740393Sbostic *
150840393Sbostic * Side Effects:
150940393Sbostic * A new element is added to the commands list of the node.
151040393Sbostic */
151160285Sbostic static int
ParseAddCmd(gnp,cmd)151269086Schristos ParseAddCmd(gnp, cmd)
151369086Schristos ClientData gnp; /* the node to which the command is to be added */
151469086Schristos ClientData cmd; /* the command to add */
151540393Sbostic {
151669086Schristos GNode *gn = (GNode *) gnp;
151769086Schristos /* if target already supplied, ignore commands */
151869086Schristos if (!(gn->type & OP_HAS_COMMANDS))
151969086Schristos (void)Lst_AtEnd(gn->commands, cmd);
152069086Schristos return(0);
152140393Sbostic }
152240424Sbostic
152340393Sbostic /*-
152440393Sbostic *-----------------------------------------------------------------------
152540393Sbostic * ParseHasCommands --
152640393Sbostic * Callback procedure for Parse_File when destroying the list of
152740393Sbostic * targets on the last dependency line. Marks a target as already
152840393Sbostic * having commands if it does, to keep from having shell commands
152940393Sbostic * on multiple dependency lines.
153040393Sbostic *
153140393Sbostic * Results:
153269086Schristos * None
153340393Sbostic *
153440393Sbostic * Side Effects:
153540393Sbostic * OP_HAS_COMMANDS may be set for the target.
153640393Sbostic *
153740393Sbostic *-----------------------------------------------------------------------
153840393Sbostic */
153969086Schristos static void
ParseHasCommands(gnp)154069086Schristos ParseHasCommands(gnp)
154169086Schristos ClientData gnp; /* Node to examine */
154240393Sbostic {
154369086Schristos GNode *gn = (GNode *) gnp;
154440393Sbostic if (!Lst_IsEmpty(gn->commands)) {
154540393Sbostic gn->type |= OP_HAS_COMMANDS;
154640393Sbostic }
154740393Sbostic }
154840424Sbostic
154940393Sbostic /*-
155040393Sbostic *-----------------------------------------------------------------------
155140393Sbostic * Parse_AddIncludeDir --
155240393Sbostic * Add a directory to the path searched for included makefiles
155340393Sbostic * bracketed by double-quotes. Used by functions in main.c
155440393Sbostic *
155540393Sbostic * Results:
155640393Sbostic * None.
155740393Sbostic *
155840393Sbostic * Side Effects:
155940393Sbostic * The directory is appended to the list.
156040393Sbostic *
156140393Sbostic *-----------------------------------------------------------------------
156240393Sbostic */
156340393Sbostic void
Parse_AddIncludeDir(dir)156440393Sbostic Parse_AddIncludeDir (dir)
156540393Sbostic char *dir; /* The name of the directory to add */
156640393Sbostic {
156740393Sbostic Dir_AddDir (parseIncPath, dir);
156840393Sbostic }
156940424Sbostic
157040393Sbostic /*-
157140393Sbostic *---------------------------------------------------------------------
157240393Sbostic * ParseDoInclude --
157340393Sbostic * Push to another file.
157440393Sbostic *
157540393Sbostic * The input is the line minus the #include. A file spec is a string
157640393Sbostic * enclosed in <> or "". The former is looked for only in sysIncPath.
157740393Sbostic * The latter in . and the directories specified by -I command line
157840393Sbostic * options
157940393Sbostic *
158040393Sbostic * Results:
158140393Sbostic * None
158240393Sbostic *
158340393Sbostic * Side Effects:
158440393Sbostic * A structure is added to the includes Lst and readProc, lineno,
158540393Sbostic * fname and curFILE are altered for the new file
158640393Sbostic *---------------------------------------------------------------------
158740393Sbostic */
158840393Sbostic static void
ParseDoInclude(file)158940393Sbostic ParseDoInclude (file)
159040393Sbostic char *file; /* file specification */
159140393Sbostic {
159240393Sbostic char *fullname; /* full pathname of file */
159340393Sbostic IFile *oldFile; /* state associated with current file */
159440393Sbostic char endc; /* the character which ends the file spec */
159540393Sbostic char *cp; /* current position in file spec */
159640393Sbostic Boolean isSystem; /* TRUE if makefile is a system makefile */
159740393Sbostic
159840393Sbostic /*
159940393Sbostic * Skip to delimiter character so we know where to look
160040393Sbostic */
160140393Sbostic while ((*file == ' ') || (*file == '\t')) {
160240393Sbostic file++;
160340393Sbostic }
160440393Sbostic
160540393Sbostic if ((*file != '"') && (*file != '<')) {
160642443Sbostic Parse_Error (PARSE_FATAL,
160742443Sbostic ".include filename must be delimited by '\"' or '<'");
160840393Sbostic return;
160940393Sbostic }
161040393Sbostic
161140393Sbostic /*
161240393Sbostic * Set the search path on which to find the include file based on the
161340393Sbostic * characters which bracket its name. Angle-brackets imply it's
161440393Sbostic * a system Makefile while double-quotes imply it's a user makefile
161540393Sbostic */
161640393Sbostic if (*file == '<') {
161740393Sbostic isSystem = TRUE;
161840393Sbostic endc = '>';
161940393Sbostic } else {
162040393Sbostic isSystem = FALSE;
162140393Sbostic endc = '"';
162240393Sbostic }
162340393Sbostic
162440393Sbostic /*
162540393Sbostic * Skip to matching delimiter
162640393Sbostic */
162740393Sbostic for (cp = ++file; *cp && *cp != endc; cp++) {
162840393Sbostic continue;
162940393Sbostic }
163040393Sbostic
163140393Sbostic if (*cp != endc) {
163240393Sbostic Parse_Error (PARSE_FATAL,
163360285Sbostic "Unclosed %cinclude filename. '%c' expected",
163460285Sbostic '.', endc);
163540393Sbostic return;
163640393Sbostic }
163740393Sbostic *cp = '\0';
163840393Sbostic
163940393Sbostic /*
164040393Sbostic * Substitute for any variables in the file name before trying to
164140393Sbostic * find the thing.
164240393Sbostic */
164360285Sbostic file = Var_Subst (NULL, file, VAR_CMD, FALSE);
164440393Sbostic
164540393Sbostic /*
164640393Sbostic * Now we know the file's name and its search path, we attempt to
164740393Sbostic * find the durn thing. A return of NULL indicates the file don't
164840393Sbostic * exist.
164940393Sbostic */
165040393Sbostic if (!isSystem) {
165140393Sbostic /*
165240393Sbostic * Include files contained in double-quotes are first searched for
165340393Sbostic * relative to the including file's location. We don't want to
165440393Sbostic * cd there, of course, so we just tack on the old file's
165540393Sbostic * leading path components and call Dir_FindFile to see if
165640393Sbostic * we can locate the beast.
165740393Sbostic */
165840393Sbostic char *prefEnd;
165940393Sbostic
166060285Sbostic prefEnd = strrchr (fname, '/');
166140393Sbostic if (prefEnd != (char *)NULL) {
166240393Sbostic char *newName;
166340393Sbostic
166440393Sbostic *prefEnd = '\0';
166569086Schristos if (file[0] == '/')
166669086Schristos newName = strdup(file);
166769086Schristos else
166869086Schristos newName = str_concat (fname, file, STR_ADDSLASH);
166940393Sbostic fullname = Dir_FindFile (newName, parseIncPath);
167040393Sbostic if (fullname == (char *)NULL) {
167140393Sbostic fullname = Dir_FindFile(newName, dirSearchPath);
167240393Sbostic }
167340393Sbostic free (newName);
167440393Sbostic *prefEnd = '/';
167540393Sbostic } else {
167640393Sbostic fullname = (char *)NULL;
167740393Sbostic }
167840393Sbostic } else {
167940393Sbostic fullname = (char *)NULL;
168040393Sbostic }
168140393Sbostic
168240393Sbostic if (fullname == (char *)NULL) {
168340393Sbostic /*
168440393Sbostic * System makefile or makefile wasn't found in same directory as
168540393Sbostic * included makefile. Search for it first on the -I search path,
168640393Sbostic * then on the .PATH search path, if not found in a -I directory.
168740393Sbostic * XXX: Suffix specific?
168840393Sbostic */
168940393Sbostic fullname = Dir_FindFile (file, parseIncPath);
169040393Sbostic if (fullname == (char *)NULL) {
169140393Sbostic fullname = Dir_FindFile(file, dirSearchPath);
169240393Sbostic }
169340393Sbostic }
169440393Sbostic
169540393Sbostic if (fullname == (char *)NULL) {
169640393Sbostic /*
169740393Sbostic * Still haven't found the makefile. Look for it on the system
169840393Sbostic * path as a last resort.
169940393Sbostic */
170040393Sbostic fullname = Dir_FindFile(file, sysIncPath);
170140393Sbostic }
170240393Sbostic
170340393Sbostic if (fullname == (char *) NULL) {
170440393Sbostic *cp = endc;
170540393Sbostic Parse_Error (PARSE_FATAL, "Could not find %s", file);
170640393Sbostic return;
170740393Sbostic }
170840393Sbostic
170969086Schristos free(file);
171069086Schristos
171140393Sbostic /*
171240393Sbostic * Once we find the absolute path to the file, we get to save all the
171340393Sbostic * state from the current file before we can start reading this
171440393Sbostic * include file. The state is stored in an IFile structure which
171540393Sbostic * is placed on a list with other IFile structures. The list makes
171640393Sbostic * a very nice stack to track how we got here...
171740393Sbostic */
171840534Sbostic oldFile = (IFile *) emalloc (sizeof (IFile));
171940393Sbostic oldFile->fname = fname;
172040393Sbostic
172140393Sbostic oldFile->F = curFILE;
172260285Sbostic oldFile->p = curPTR;
172340393Sbostic oldFile->lineno = lineno;
172440393Sbostic
172540393Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile);
172640393Sbostic
172740393Sbostic /*
172840393Sbostic * Once the previous state has been saved, we can get down to reading
172940393Sbostic * the new file. We set up the name of the file to be the absolute
173040393Sbostic * name of the include file so error messages refer to the right
173140393Sbostic * place. Naturally enough, we start reading at line number 0.
173240393Sbostic */
173340393Sbostic fname = fullname;
173440393Sbostic lineno = 0;
173540393Sbostic
173640393Sbostic curFILE = fopen (fullname, "r");
173760285Sbostic curPTR = NULL;
173840393Sbostic if (curFILE == (FILE * ) NULL) {
173940393Sbostic Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
174040393Sbostic /*
174140393Sbostic * Pop to previous file
174240393Sbostic */
174346462Sbostic (void) ParseEOF(0);
174440393Sbostic }
174540393Sbostic }
174640424Sbostic
174760285Sbostic
174840393Sbostic /*-
174940393Sbostic *---------------------------------------------------------------------
175060285Sbostic * Parse_FromString --
175160285Sbostic * Start Parsing from the given string
175260285Sbostic *
175360285Sbostic * Results:
175460285Sbostic * None
175560285Sbostic *
175660285Sbostic * Side Effects:
175760285Sbostic * A structure is added to the includes Lst and readProc, lineno,
175860285Sbostic * fname and curFILE are altered for the new file
175960285Sbostic *---------------------------------------------------------------------
176060285Sbostic */
176160285Sbostic void
Parse_FromString(str)176260285Sbostic Parse_FromString(str)
176360285Sbostic char *str;
176460285Sbostic {
176560285Sbostic IFile *oldFile; /* state associated with this file */
176660285Sbostic
176760285Sbostic if (DEBUG(FOR))
176860285Sbostic (void) fprintf(stderr, "%s\n----\n", str);
176960285Sbostic
177060285Sbostic oldFile = (IFile *) emalloc (sizeof (IFile));
177160285Sbostic oldFile->lineno = lineno;
177260285Sbostic oldFile->fname = fname;
177360285Sbostic oldFile->F = curFILE;
177460285Sbostic oldFile->p = curPTR;
177560285Sbostic
177660285Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile);
177760285Sbostic
177860285Sbostic curFILE = NULL;
177960285Sbostic curPTR = (PTR *) emalloc (sizeof (PTR));
178060285Sbostic curPTR->str = curPTR->ptr = str;
178160285Sbostic lineno = 0;
178260285Sbostic fname = strdup(fname);
178360285Sbostic }
178460285Sbostic
178560285Sbostic
178660285Sbostic #ifdef SYSVINCLUDE
178760285Sbostic /*-
178860285Sbostic *---------------------------------------------------------------------
178960285Sbostic * ParseTraditionalInclude --
179060285Sbostic * Push to another file.
179160285Sbostic *
179260285Sbostic * The input is the line minus the "include". The file name is
179360285Sbostic * the string following the "include".
179460285Sbostic *
179560285Sbostic * Results:
179660285Sbostic * None
179760285Sbostic *
179860285Sbostic * Side Effects:
179960285Sbostic * A structure is added to the includes Lst and readProc, lineno,
180060285Sbostic * fname and curFILE are altered for the new file
180160285Sbostic *---------------------------------------------------------------------
180260285Sbostic */
180360285Sbostic static void
ParseTraditionalInclude(file)180460285Sbostic ParseTraditionalInclude (file)
180560285Sbostic char *file; /* file specification */
180660285Sbostic {
180760285Sbostic char *fullname; /* full pathname of file */
180860285Sbostic IFile *oldFile; /* state associated with current file */
180960285Sbostic char *cp; /* current position in file spec */
181060285Sbostic char *prefEnd;
181160285Sbostic
181260285Sbostic /*
181360285Sbostic * Skip over whitespace
181460285Sbostic */
181560285Sbostic while ((*file == ' ') || (*file == '\t')) {
181660285Sbostic file++;
181760285Sbostic }
181860285Sbostic
181960285Sbostic if (*file == '\0') {
182060285Sbostic Parse_Error (PARSE_FATAL,
182160285Sbostic "Filename missing from \"include\"");
182260285Sbostic return;
182360285Sbostic }
182460285Sbostic
182560285Sbostic /*
182660285Sbostic * Skip to end of line or next whitespace
182760285Sbostic */
182860285Sbostic for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) {
182960285Sbostic continue;
183060285Sbostic }
183160285Sbostic
183260285Sbostic *cp = '\0';
183360285Sbostic
183460285Sbostic /*
183560285Sbostic * Substitute for any variables in the file name before trying to
183660285Sbostic * find the thing.
183760285Sbostic */
183860285Sbostic file = Var_Subst (NULL, file, VAR_CMD, FALSE);
183960285Sbostic
184060285Sbostic /*
184160285Sbostic * Now we know the file's name, we attempt to find the durn thing.
184260285Sbostic * A return of NULL indicates the file don't exist.
184360285Sbostic *
184460285Sbostic * Include files are first searched for relative to the including
184560285Sbostic * file's location. We don't want to cd there, of course, so we
184660285Sbostic * just tack on the old file's leading path components and call
184760285Sbostic * Dir_FindFile to see if we can locate the beast.
184860285Sbostic * XXX - this *does* search in the current directory, right?
184960285Sbostic */
185060285Sbostic
185160285Sbostic prefEnd = strrchr (fname, '/');
185260285Sbostic if (prefEnd != (char *)NULL) {
185360285Sbostic char *newName;
185460285Sbostic
185560285Sbostic *prefEnd = '\0';
185660285Sbostic newName = str_concat (fname, file, STR_ADDSLASH);
185760285Sbostic fullname = Dir_FindFile (newName, parseIncPath);
185860285Sbostic if (fullname == (char *)NULL) {
185960285Sbostic fullname = Dir_FindFile(newName, dirSearchPath);
186060285Sbostic }
186160285Sbostic free (newName);
186260285Sbostic *prefEnd = '/';
186360285Sbostic } else {
186460285Sbostic fullname = (char *)NULL;
186560285Sbostic }
186660285Sbostic
186760285Sbostic if (fullname == (char *)NULL) {
186860285Sbostic /*
186960285Sbostic * System makefile or makefile wasn't found in same directory as
187060285Sbostic * included makefile. Search for it first on the -I search path,
187160285Sbostic * then on the .PATH search path, if not found in a -I directory.
187260285Sbostic * XXX: Suffix specific?
187360285Sbostic */
187460285Sbostic fullname = Dir_FindFile (file, parseIncPath);
187560285Sbostic if (fullname == (char *)NULL) {
187660285Sbostic fullname = Dir_FindFile(file, dirSearchPath);
187760285Sbostic }
187860285Sbostic }
187960285Sbostic
188060285Sbostic if (fullname == (char *)NULL) {
188160285Sbostic /*
188260285Sbostic * Still haven't found the makefile. Look for it on the system
188360285Sbostic * path as a last resort.
188460285Sbostic */
188560285Sbostic fullname = Dir_FindFile(file, sysIncPath);
188660285Sbostic }
188760285Sbostic
188860285Sbostic if (fullname == (char *) NULL) {
188960285Sbostic Parse_Error (PARSE_FATAL, "Could not find %s", file);
189060285Sbostic return;
189160285Sbostic }
189260285Sbostic
189360285Sbostic /*
189460285Sbostic * Once we find the absolute path to the file, we get to save all the
189560285Sbostic * state from the current file before we can start reading this
189660285Sbostic * include file. The state is stored in an IFile structure which
189760285Sbostic * is placed on a list with other IFile structures. The list makes
189860285Sbostic * a very nice stack to track how we got here...
189960285Sbostic */
190060285Sbostic oldFile = (IFile *) emalloc (sizeof (IFile));
190160285Sbostic oldFile->fname = fname;
190260285Sbostic
190360285Sbostic oldFile->F = curFILE;
190460285Sbostic oldFile->p = curPTR;
190560285Sbostic oldFile->lineno = lineno;
190660285Sbostic
190760285Sbostic (void) Lst_AtFront (includes, (ClientData)oldFile);
190860285Sbostic
190960285Sbostic /*
191060285Sbostic * Once the previous state has been saved, we can get down to reading
191160285Sbostic * the new file. We set up the name of the file to be the absolute
191260285Sbostic * name of the include file so error messages refer to the right
191360285Sbostic * place. Naturally enough, we start reading at line number 0.
191460285Sbostic */
191560285Sbostic fname = fullname;
191660285Sbostic lineno = 0;
191760285Sbostic
191860285Sbostic curFILE = fopen (fullname, "r");
191960285Sbostic curPTR = NULL;
192060285Sbostic if (curFILE == (FILE * ) NULL) {
192160285Sbostic Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);
192260285Sbostic /*
192360285Sbostic * Pop to previous file
192460285Sbostic */
192560285Sbostic (void) ParseEOF(1);
192660285Sbostic }
192760285Sbostic }
192860285Sbostic #endif
192960285Sbostic
193060285Sbostic /*-
193160285Sbostic *---------------------------------------------------------------------
193240393Sbostic * ParseEOF --
193340393Sbostic * Called when EOF is reached in the current file. If we were reading
193440393Sbostic * an include file, the includes stack is popped and things set up
193540393Sbostic * to go back to reading the previous file at the previous location.
193640393Sbostic *
193740393Sbostic * Results:
193840393Sbostic * CONTINUE if there's more to do. DONE if not.
193940393Sbostic *
194040393Sbostic * Side Effects:
194140393Sbostic * The old curFILE, is closed. The includes list is shortened.
194240393Sbostic * lineno, curFILE, and fname are changed if CONTINUE is returned.
194340393Sbostic *---------------------------------------------------------------------
194440393Sbostic */
194540393Sbostic static int
ParseEOF(opened)194646462Sbostic ParseEOF (opened)
194746462Sbostic int opened;
194840393Sbostic {
194940393Sbostic IFile *ifile; /* the state on the top of the includes stack */
195040393Sbostic
195140393Sbostic if (Lst_IsEmpty (includes)) {
195240393Sbostic return (DONE);
195340393Sbostic }
195440393Sbostic
195540393Sbostic ifile = (IFile *) Lst_DeQueue (includes);
195660285Sbostic free ((Address) fname);
195740393Sbostic fname = ifile->fname;
195840393Sbostic lineno = ifile->lineno;
195960285Sbostic if (opened && curFILE)
196046462Sbostic (void) fclose (curFILE);
196160285Sbostic if (curPTR) {
196260285Sbostic free((Address) curPTR->str);
196360285Sbostic free((Address) curPTR);
196460285Sbostic }
196540393Sbostic curFILE = ifile->F;
196660285Sbostic curPTR = ifile->p;
196740393Sbostic free ((Address)ifile);
196840393Sbostic return (CONTINUE);
196940393Sbostic }
197040424Sbostic
197140393Sbostic /*-
197240393Sbostic *---------------------------------------------------------------------
197340393Sbostic * ParseReadc --
197460285Sbostic * Read a character from the current file
197540393Sbostic *
197640393Sbostic * Results:
197740393Sbostic * The character that was read
197840393Sbostic *
197940393Sbostic * Side Effects:
198040393Sbostic *---------------------------------------------------------------------
198140393Sbostic */
198260285Sbostic static int
ParseReadc()198360285Sbostic ParseReadc()
198460285Sbostic {
198560285Sbostic if (curFILE)
198660285Sbostic return fgetc(curFILE);
198760285Sbostic
198860285Sbostic if (curPTR && *curPTR->ptr)
198960285Sbostic return *curPTR->ptr++;
199060285Sbostic return EOF;
199160285Sbostic }
199240393Sbostic
199360557Sbostic
199460557Sbostic /*-
199560557Sbostic *---------------------------------------------------------------------
199660557Sbostic * ParseUnreadc --
199760557Sbostic * Put back a character to the current file
199860557Sbostic *
199960557Sbostic * Results:
200060557Sbostic * None.
200160557Sbostic *
200260557Sbostic * Side Effects:
200360557Sbostic *---------------------------------------------------------------------
200460557Sbostic */
200560557Sbostic static void
ParseUnreadc(c)200660557Sbostic ParseUnreadc(c)
200760557Sbostic int c;
200860557Sbostic {
200960557Sbostic if (curFILE) {
201060557Sbostic ungetc(c, curFILE);
201160557Sbostic return;
201260557Sbostic }
201360557Sbostic if (curPTR) {
201460557Sbostic *--(curPTR->ptr) = c;
201560557Sbostic return;
201660557Sbostic }
201760557Sbostic }
201860557Sbostic
201960557Sbostic
202060285Sbostic /* ParseSkipLine():
202160285Sbostic * Grab the next line
202260285Sbostic */
202360285Sbostic static char *
ParseSkipLine(skip)202460285Sbostic ParseSkipLine(skip)
202560285Sbostic int skip; /* Skip lines that don't start with . */
202660285Sbostic {
202760285Sbostic char *line;
202860285Sbostic int c, lastc = '\0', lineLength;
202960285Sbostic Buffer buf;
203040393Sbostic
203160285Sbostic c = ParseReadc();
203240424Sbostic
203360285Sbostic if (skip) {
203460285Sbostic /*
203560285Sbostic * Skip lines until get to one that begins with a
203660285Sbostic * special char.
203760285Sbostic */
203860285Sbostic while ((c != '.') && (c != EOF)) {
203960285Sbostic while (((c != '\n') || (lastc == '\\')) && (c != EOF))
204060285Sbostic {
204160285Sbostic /*
204260285Sbostic * Advance to next unescaped newline
204360285Sbostic */
204460285Sbostic if ((lastc = c) == '\n') {
204560285Sbostic lineno++;
204660285Sbostic }
204760285Sbostic c = ParseReadc();
204860285Sbostic }
204960285Sbostic lineno++;
205060285Sbostic
205160285Sbostic lastc = c;
205260285Sbostic c = ParseReadc ();
205360285Sbostic }
205460285Sbostic }
205560285Sbostic
205660285Sbostic if (c == EOF) {
205760285Sbostic Parse_Error (PARSE_FATAL, "Unclosed conditional/for loop");
205860285Sbostic return ((char *)NULL);
205960285Sbostic }
206060285Sbostic
206160285Sbostic /*
206260285Sbostic * Read the entire line into buf
206360285Sbostic */
206460285Sbostic buf = Buf_Init (MAKE_BSIZE);
206560285Sbostic if (c != '\n') {
206660285Sbostic do {
206760285Sbostic Buf_AddByte (buf, (Byte)c);
206860285Sbostic c = ParseReadc();
206960285Sbostic } while ((c != '\n') && (c != EOF));
207060285Sbostic }
207160285Sbostic lineno++;
207260285Sbostic
207360285Sbostic Buf_AddByte (buf, (Byte)'\0');
207460285Sbostic line = (char *)Buf_GetAll (buf, &lineLength);
207560285Sbostic Buf_Destroy (buf, FALSE);
207660285Sbostic return line;
207760285Sbostic }
207860285Sbostic
207960285Sbostic
208040393Sbostic /*-
208140393Sbostic *---------------------------------------------------------------------
208240393Sbostic * ParseReadLine --
208340393Sbostic * Read an entire line from the input file. Called only by Parse_File.
208440393Sbostic * To facilitate escaped newlines and what have you, a character is
208540393Sbostic * buffered in 'lastc', which is '\0' when no characters have been
208640393Sbostic * read. When we break out of the loop, c holds the terminating
208740393Sbostic * character and lastc holds a character that should be added to
208840393Sbostic * the line (unless we don't read anything but a terminator).
208940393Sbostic *
209040393Sbostic * Results:
209140393Sbostic * A line w/o its newline
209240393Sbostic *
209340393Sbostic * Side Effects:
209440393Sbostic * Only those associated with reading a character
209540393Sbostic *---------------------------------------------------------------------
209640393Sbostic */
209740393Sbostic static char *
ParseReadLine()209840393Sbostic ParseReadLine ()
209940393Sbostic {
210040393Sbostic Buffer buf; /* Buffer for current line */
210140393Sbostic register int c; /* the current character */
210240393Sbostic register int lastc; /* The most-recent character */
210340393Sbostic Boolean semiNL; /* treat semi-colons as newlines */
210440393Sbostic Boolean ignDepOp; /* TRUE if should ignore dependency operators
210540393Sbostic * for the purposes of setting semiNL */
210640393Sbostic Boolean ignComment; /* TRUE if should ignore comments (in a
210740393Sbostic * shell command */
210869086Schristos char *line; /* Result */
210969086Schristos char *ep; /* to strip trailing blanks */
211040393Sbostic int lineLength; /* Length of result */
211140393Sbostic
211240393Sbostic semiNL = FALSE;
211340393Sbostic ignDepOp = FALSE;
211440393Sbostic ignComment = FALSE;
211540393Sbostic
211640393Sbostic /*
211740393Sbostic * Handle special-characters at the beginning of the line. Either a
211840393Sbostic * leading tab (shell command) or pound-sign (possible conditional)
211940393Sbostic * forces us to ignore comments and dependency operators and treat
212040393Sbostic * semi-colons as semi-colons (by leaving semiNL FALSE). This also
212140393Sbostic * discards completely blank lines.
212240393Sbostic */
212360285Sbostic for (;;) {
212440393Sbostic c = ParseReadc();
212540393Sbostic
212660557Sbostic if (c == '\t') {
212744599Sbostic ignComment = ignDepOp = TRUE;
212844599Sbostic break;
212940393Sbostic } else if (c == '\n') {
213040393Sbostic lineno++;
213161010Sbostic } else if (c == '#') {
213266399Schristos ParseUnreadc(c);
213366399Schristos break;
213440393Sbostic } else {
213540393Sbostic /*
213640393Sbostic * Anything else breaks out without doing anything
213740393Sbostic */
213840393Sbostic break;
213940393Sbostic }
214040393Sbostic }
214140393Sbostic
214240393Sbostic if (c != EOF) {
214340393Sbostic lastc = c;
214460285Sbostic buf = Buf_Init(MAKE_BSIZE);
214540393Sbostic
214640393Sbostic while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) &&
214740393Sbostic (c != EOF))
214840393Sbostic {
214940393Sbostic test_char:
215040393Sbostic switch(c) {
215140393Sbostic case '\n':
215240393Sbostic /*
215340393Sbostic * Escaped newline: read characters until a non-space or an
215440393Sbostic * unescaped newline and replace them all by a single space.
215540393Sbostic * This is done by storing the space over the backslash and
215640393Sbostic * dropping through with the next nonspace. If it is a
215740393Sbostic * semi-colon and semiNL is TRUE, it will be recognized as a
215840393Sbostic * newline in the code below this...
215940393Sbostic */
216040393Sbostic lineno++;
216140393Sbostic lastc = ' ';
216240393Sbostic while ((c = ParseReadc ()) == ' ' || c == '\t') {
216340393Sbostic continue;
216440393Sbostic }
216540393Sbostic if (c == EOF || c == '\n') {
216640393Sbostic goto line_read;
216740393Sbostic } else {
216840393Sbostic /*
216940393Sbostic * Check for comments, semiNL's, etc. -- easier than
217060557Sbostic * ParseUnreadc(c); continue;
217140393Sbostic */
217240393Sbostic goto test_char;
217340393Sbostic }
217460285Sbostic /*NOTREACHED*/
217540393Sbostic break;
217660285Sbostic
217740393Sbostic case ';':
217840393Sbostic /*
217940393Sbostic * Semi-colon: Need to see if it should be interpreted as a
218040393Sbostic * newline
218140393Sbostic */
218240393Sbostic if (semiNL) {
218340393Sbostic /*
218440393Sbostic * To make sure the command that may be following this
218540393Sbostic * semi-colon begins with a tab, we push one back into the
218640393Sbostic * input stream. This will overwrite the semi-colon in the
218740393Sbostic * buffer. If there is no command following, this does no
218840393Sbostic * harm, since the newline remains in the buffer and the
218940393Sbostic * whole line is ignored.
219040393Sbostic */
219160557Sbostic ParseUnreadc('\t');
219240393Sbostic goto line_read;
219340393Sbostic }
219440393Sbostic break;
219540393Sbostic case '=':
219640393Sbostic if (!semiNL) {
219740393Sbostic /*
219840393Sbostic * Haven't seen a dependency operator before this, so this
219940393Sbostic * must be a variable assignment -- don't pay attention to
220040393Sbostic * dependency operators after this.
220140393Sbostic */
220240393Sbostic ignDepOp = TRUE;
220340393Sbostic } else if (lastc == ':' || lastc == '!') {
220440393Sbostic /*
220540393Sbostic * Well, we've seen a dependency operator already, but it
220640393Sbostic * was the previous character, so this is really just an
220740393Sbostic * expanded variable assignment. Revert semi-colons to
220840393Sbostic * being just semi-colons again and ignore any more
220940393Sbostic * dependency operators.
221040393Sbostic *
221140393Sbostic * XXX: Note that a line like "foo : a:=b" will blow up,
221240393Sbostic * but who'd write a line like that anyway?
221340393Sbostic */
221440393Sbostic ignDepOp = TRUE; semiNL = FALSE;
221540393Sbostic }
221640393Sbostic break;
221740393Sbostic case '#':
221840393Sbostic if (!ignComment) {
221967227Schristos if (compatMake && (lastc != '\\')) {
222040393Sbostic /*
222140393Sbostic * If the character is a hash mark and it isn't escaped
222240393Sbostic * (or we're being compatible), the thing is a comment.
222340393Sbostic * Skip to the end of the line.
222440393Sbostic */
222540393Sbostic do {
222640393Sbostic c = ParseReadc();
222740393Sbostic } while ((c != '\n') && (c != EOF));
222840393Sbostic goto line_read;
222960285Sbostic } else {
223060285Sbostic /*
223160285Sbostic * Don't add the backslash. Just let the # get copied
223260285Sbostic * over.
223360285Sbostic */
223460285Sbostic lastc = c;
223560285Sbostic continue;
223660285Sbostic }
223740393Sbostic }
223840393Sbostic break;
223940393Sbostic case ':':
224040393Sbostic case '!':
224140393Sbostic if (!ignDepOp && (c == ':' || c == '!')) {
224240393Sbostic /*
224340393Sbostic * A semi-colon is recognized as a newline only on
224440393Sbostic * dependency lines. Dependency lines are lines with a
224540393Sbostic * colon or an exclamation point. Ergo...
224640393Sbostic */
224740393Sbostic semiNL = TRUE;
224840393Sbostic }
224940393Sbostic break;
225040393Sbostic }
225140393Sbostic /*
225240393Sbostic * Copy in the previous character and save this one in lastc.
225340393Sbostic */
225440393Sbostic Buf_AddByte (buf, (Byte)lastc);
225540393Sbostic lastc = c;
225640393Sbostic
225740393Sbostic }
225840393Sbostic line_read:
225940393Sbostic lineno++;
226040393Sbostic
226140393Sbostic if (lastc != '\0') {
226240393Sbostic Buf_AddByte (buf, (Byte)lastc);
226340393Sbostic }
226440393Sbostic Buf_AddByte (buf, (Byte)'\0');
226540393Sbostic line = (char *)Buf_GetAll (buf, &lineLength);
226640393Sbostic Buf_Destroy (buf, FALSE);
226769086Schristos
226869086Schristos /*
226969086Schristos * Strip trailing blanks and tabs from the line.
227069086Schristos * Do not strip a blank or tab that is preceeded by
227169086Schristos * a '\'
227269086Schristos */
227369086Schristos ep = line;
227469086Schristos while (*ep)
227569086Schristos ++ep;
227669086Schristos while (ep > line && (ep[-1] == ' ' || ep[-1] == '\t')) {
227769086Schristos if (ep > line + 1 && ep[-2] == '\\')
227869086Schristos break;
227969086Schristos --ep;
228069086Schristos }
228169086Schristos *ep = 0;
228240393Sbostic
228340435Sbostic if (line[0] == '.') {
228440393Sbostic /*
228540393Sbostic * The line might be a conditional. Ask the conditional module
228640393Sbostic * about it and act accordingly
228740393Sbostic */
228840393Sbostic switch (Cond_Eval (line)) {
228940393Sbostic case COND_SKIP:
229060285Sbostic /*
229160285Sbostic * Skip to next conditional that evaluates to COND_PARSE.
229260285Sbostic */
229340393Sbostic do {
229440393Sbostic free (line);
229560285Sbostic line = ParseSkipLine(1);
229660285Sbostic } while (line && Cond_Eval(line) != COND_PARSE);
229760285Sbostic if (line == NULL)
229860285Sbostic break;
229940393Sbostic /*FALLTHRU*/
230040393Sbostic case COND_PARSE:
230160285Sbostic free ((Address) line);
230240393Sbostic line = ParseReadLine();
230340393Sbostic break;
230460285Sbostic case COND_INVALID:
230560285Sbostic if (For_Eval(line)) {
230660285Sbostic int ok;
230760285Sbostic free(line);
230860285Sbostic do {
230960285Sbostic /*
231060285Sbostic * Skip after the matching end
231160285Sbostic */
231260285Sbostic line = ParseSkipLine(0);
231360285Sbostic if (line == NULL) {
231460285Sbostic Parse_Error (PARSE_FATAL,
231560285Sbostic "Unexpected end of file in for loop.\n");
231660285Sbostic break;
231760285Sbostic }
231860285Sbostic ok = For_Eval(line);
231960285Sbostic free(line);
232060285Sbostic }
232160285Sbostic while (ok);
232260285Sbostic if (line != NULL)
232360285Sbostic For_Run();
232460285Sbostic line = ParseReadLine();
232560285Sbostic }
232660285Sbostic break;
232740393Sbostic }
232840393Sbostic }
232940393Sbostic return (line);
233060285Sbostic
233140393Sbostic } else {
233240393Sbostic /*
233340393Sbostic * Hit end-of-file, so return a NULL line to indicate this.
233440393Sbostic */
233540393Sbostic return((char *)NULL);
233640393Sbostic }
233740393Sbostic }
233840424Sbostic
233940393Sbostic /*-
234040393Sbostic *-----------------------------------------------------------------------
234140393Sbostic * ParseFinishLine --
234240393Sbostic * Handle the end of a dependency group.
234340393Sbostic *
234440393Sbostic * Results:
234540393Sbostic * Nothing.
234640393Sbostic *
234740393Sbostic * Side Effects:
234840393Sbostic * inLine set FALSE. 'targets' list destroyed.
234940393Sbostic *
235040393Sbostic *-----------------------------------------------------------------------
235140393Sbostic */
235240393Sbostic static void
ParseFinishLine()235340393Sbostic ParseFinishLine()
235440393Sbostic {
235540393Sbostic if (inLine) {
235640393Sbostic Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL);
235740393Sbostic Lst_Destroy (targets, ParseHasCommands);
235869086Schristos targets = NULL;
235940393Sbostic inLine = FALSE;
236040393Sbostic }
236140393Sbostic }
236240393Sbostic
236340424Sbostic
236440393Sbostic /*-
236540393Sbostic *---------------------------------------------------------------------
236640393Sbostic * Parse_File --
236740393Sbostic * Parse a file into its component parts, incorporating it into the
236840393Sbostic * current dependency graph. This is the main function and controls
236940393Sbostic * almost every other function in this module
237040393Sbostic *
237140393Sbostic * Results:
237240393Sbostic * None
237340393Sbostic *
237440393Sbostic * Side Effects:
237540393Sbostic * Loads. Nodes are added to the list of all targets, nodes and links
237640393Sbostic * are added to the dependency graph. etc. etc. etc.
237740393Sbostic *---------------------------------------------------------------------
237840393Sbostic */
237940393Sbostic void
Parse_File(name,stream)238040393Sbostic Parse_File(name, stream)
238140393Sbostic char *name; /* the name of the file being read */
238240393Sbostic FILE * stream; /* Stream open to makefile to parse */
238340393Sbostic {
238440393Sbostic register char *cp, /* pointer into the line */
238540393Sbostic *line; /* the line we're working on */
238640393Sbostic
238740393Sbostic inLine = FALSE;
238840393Sbostic fname = name;
238940393Sbostic curFILE = stream;
239040393Sbostic lineno = 0;
239140393Sbostic fatals = 0;
239240393Sbostic
239340393Sbostic do {
239460285Sbostic while ((line = ParseReadLine ()) != NULL) {
239540435Sbostic if (*line == '.') {
239640393Sbostic /*
239740393Sbostic * Lines that begin with the special character are either
239840393Sbostic * include or undef directives.
239940393Sbostic */
240040393Sbostic for (cp = line + 1; isspace (*cp); cp++) {
240140393Sbostic continue;
240240393Sbostic }
240340393Sbostic if (strncmp (cp, "include", 7) == 0) {
240440393Sbostic ParseDoInclude (cp + 7);
240540393Sbostic goto nextLine;
240640393Sbostic } else if (strncmp(cp, "undef", 5) == 0) {
240740393Sbostic char *cp2;
240869086Schristos for (cp += 5; isspace((unsigned char) *cp); cp++) {
240940393Sbostic continue;
241040393Sbostic }
241140393Sbostic
241269086Schristos for (cp2 = cp; !isspace((unsigned char) *cp2) &&
241369086Schristos (*cp2 != '\0'); cp2++) {
241440393Sbostic continue;
241540393Sbostic }
241640393Sbostic
241740393Sbostic *cp2 = '\0';
241840393Sbostic
241940393Sbostic Var_Delete(cp, VAR_GLOBAL);
242040393Sbostic goto nextLine;
242140393Sbostic }
242240393Sbostic }
242369086Schristos if (*line == '#' || *line == '\0') {
242469086Schristos /* If we're this far, the line must be a comment.
242569086Schristos (Empty lines are ignored as well) */
242640393Sbostic goto nextLine;
242740393Sbostic }
242840393Sbostic
242969086Schristos if (*line == '\t') {
243040393Sbostic /*
243169086Schristos * If a line starts with a tab, it can only hope to be
243269086Schristos * a creation command.
243340393Sbostic */
243469086Schristos #ifndef POSIX
243540393Sbostic shellCommand:
243669086Schristos #endif
243740393Sbostic for (cp = line + 1; isspace (*cp); cp++) {
243840393Sbostic continue;
243940393Sbostic }
244040393Sbostic if (*cp) {
244140393Sbostic if (inLine) {
244240393Sbostic /*
244340393Sbostic * So long as it's not a blank line and we're actually
244440393Sbostic * in a dependency spec, add the command to the list of
244540393Sbostic * commands of all targets in the dependency spec
244640393Sbostic */
244769086Schristos Lst_ForEach (targets, ParseAddCmd, cp);
244869086Schristos Lst_AtEnd(targCmds, (ClientData) line);
244940393Sbostic continue;
245040393Sbostic } else {
245140393Sbostic Parse_Error (PARSE_FATAL,
245240393Sbostic "Unassociated shell command \"%.20s\"",
245340393Sbostic cp);
245440393Sbostic }
245540393Sbostic }
245660285Sbostic #ifdef SYSVINCLUDE
245760285Sbostic } else if (strncmp (line, "include", 7) == 0 &&
245860285Sbostic strchr(line, ':') == NULL) {
245960285Sbostic /*
246060285Sbostic * It's an S3/S5-style "include".
246160285Sbostic */
246260285Sbostic ParseTraditionalInclude (line + 7);
246360285Sbostic goto nextLine;
246460285Sbostic #endif
246540393Sbostic } else if (Parse_IsVar (line)) {
246640393Sbostic ParseFinishLine();
246740393Sbostic Parse_DoVar (line, VAR_GLOBAL);
246840393Sbostic } else {
246940393Sbostic /*
247040393Sbostic * We now know it's a dependency line so it needs to have all
247140393Sbostic * variables expanded before being parsed. Tell the variable
247240393Sbostic * module to complain if some variable is undefined...
247340393Sbostic * To make life easier on novices, if the line is indented we
247440393Sbostic * first make sure the line has a dependency operator in it.
247540393Sbostic * If it doesn't have an operator and we're in a dependency
247640393Sbostic * line's script, we assume it's actually a shell command
247740393Sbostic * and add it to the current list of targets.
247840393Sbostic */
247969086Schristos #ifndef POSIX
248040393Sbostic Boolean nonSpace = FALSE;
248169086Schristos #endif
248240393Sbostic
248340393Sbostic cp = line;
248469086Schristos if (isspace((unsigned char) line[0])) {
248569086Schristos while ((*cp != '\0') && isspace((unsigned char) *cp)) {
248669086Schristos cp++;
248769086Schristos }
248869086Schristos if (*cp == '\0') {
248969086Schristos goto nextLine;
249069086Schristos }
249140393Sbostic #ifndef POSIX
249240393Sbostic while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) {
249369086Schristos nonSpace = TRUE;
249440393Sbostic cp++;
249540393Sbostic }
249669086Schristos #endif
249740393Sbostic }
249840393Sbostic
249969086Schristos #ifndef POSIX
250040393Sbostic if (*cp == '\0') {
250140393Sbostic if (inLine) {
250240393Sbostic Parse_Error (PARSE_WARNING,
250340393Sbostic "Shell command needs a leading tab");
250440393Sbostic goto shellCommand;
250540393Sbostic } else if (nonSpace) {
250640393Sbostic Parse_Error (PARSE_FATAL, "Missing operator");
250740393Sbostic }
250840393Sbostic } else {
250940393Sbostic #endif
251040393Sbostic ParseFinishLine();
251140393Sbostic
251260285Sbostic cp = Var_Subst (NULL, line, VAR_CMD, TRUE);
251340393Sbostic free (line);
251440393Sbostic line = cp;
251540393Sbostic
251640393Sbostic /*
251740393Sbostic * Need a non-circular list for the target nodes
251840393Sbostic */
251969086Schristos if (targets)
252069086Schristos Lst_Destroy(targets, NOFREE);
252169086Schristos
252240393Sbostic targets = Lst_Init (FALSE);
252340393Sbostic inLine = TRUE;
252440393Sbostic
252540393Sbostic ParseDoDependency (line);
252640393Sbostic #ifndef POSIX
252740393Sbostic }
252840393Sbostic #endif
252940393Sbostic }
253040393Sbostic
253140393Sbostic nextLine:
253240393Sbostic
253340393Sbostic free (line);
253440393Sbostic }
253540393Sbostic /*
253640393Sbostic * Reached EOF, but it may be just EOF of an include file...
253740393Sbostic */
253846462Sbostic } while (ParseEOF(1) == CONTINUE);
253940393Sbostic
254040393Sbostic /*
254140393Sbostic * Make sure conditionals are clean
254240393Sbostic */
254340393Sbostic Cond_End();
254440393Sbostic
254540393Sbostic if (fatals) {
254640393Sbostic fprintf (stderr, "Fatal errors encountered -- cannot continue\n");
254740393Sbostic exit (1);
254840393Sbostic }
254940393Sbostic }
255040424Sbostic
255140393Sbostic /*-
255240393Sbostic *---------------------------------------------------------------------
255340393Sbostic * Parse_Init --
255440393Sbostic * initialize the parsing module
255540393Sbostic *
255640393Sbostic * Results:
255740393Sbostic * none
255840393Sbostic *
255940393Sbostic * Side Effects:
256040393Sbostic * the parseIncPath list is initialized...
256140393Sbostic *---------------------------------------------------------------------
256240393Sbostic */
256360285Sbostic void
Parse_Init()256440393Sbostic Parse_Init ()
256540393Sbostic {
256660285Sbostic char *cp = NULL, *start;
256740515Sbostic /* avoid faults on read-only strings */
256840515Sbostic static char syspath[] = _PATH_DEFSYSPATH;
256940393Sbostic
257040393Sbostic mainNode = NILGNODE;
257140393Sbostic parseIncPath = Lst_Init (FALSE);
257240393Sbostic sysIncPath = Lst_Init (FALSE);
257340393Sbostic includes = Lst_Init (FALSE);
257469086Schristos targCmds = Lst_Init (FALSE);
257540393Sbostic
257640393Sbostic /*
257740393Sbostic * Add the directories from the DEFSYSPATH (more than one may be given
257840393Sbostic * as dir1:...:dirn) to the system include path.
257940393Sbostic */
258040393Sbostic for (start = syspath; *start != '\0'; start = cp) {
258160285Sbostic for (cp = start; *cp != '\0' && *cp != ':'; cp++)
258260285Sbostic continue;
258340393Sbostic if (*cp == '\0') {
258440393Sbostic Dir_AddDir(sysIncPath, start);
258540393Sbostic } else {
258640393Sbostic *cp++ = '\0';
258740393Sbostic Dir_AddDir(sysIncPath, start);
258840393Sbostic }
258940393Sbostic }
259040393Sbostic }
259140424Sbostic
259269086Schristos void
Parse_End()259369086Schristos Parse_End()
259469086Schristos {
259569086Schristos Lst_Destroy(targCmds, (void (*) __P((ClientData))) free);
259669086Schristos if (targets)
259769086Schristos Lst_Destroy(targets, NOFREE);
259869086Schristos Lst_Destroy(sysIncPath, Dir_Destroy);
259969086Schristos Lst_Destroy(parseIncPath, Dir_Destroy);
260069086Schristos Lst_Destroy(includes, NOFREE); /* Should be empty now */
260169086Schristos }
260269086Schristos
260369086Schristos
260440393Sbostic /*-
260540393Sbostic *-----------------------------------------------------------------------
260640393Sbostic * Parse_MainName --
260740393Sbostic * Return a Lst of the main target to create for main()'s sake. If
260840393Sbostic * no such target exists, we Punt with an obnoxious error message.
260940393Sbostic *
261040393Sbostic * Results:
261140393Sbostic * A Lst of the single node to create.
261240393Sbostic *
261340393Sbostic * Side Effects:
261440393Sbostic * None.
261540393Sbostic *
261640393Sbostic *-----------------------------------------------------------------------
261740393Sbostic */
261840393Sbostic Lst
Parse_MainName()261940393Sbostic Parse_MainName()
262040393Sbostic {
262140393Sbostic Lst main; /* result list */
262240393Sbostic
262340393Sbostic main = Lst_Init (FALSE);
262440393Sbostic
262540393Sbostic if (mainNode == NILGNODE) {
262645906Sbostic Punt ("make: no target to make.\n");
262740393Sbostic /*NOTREACHED*/
262840393Sbostic } else if (mainNode->type & OP_DOUBLEDEP) {
262966389Sbostic (void) Lst_AtEnd (main, (ClientData)mainNode);
263040393Sbostic Lst_Concat(main, mainNode->cohorts, LST_CONCNEW);
263140393Sbostic }
263266389Sbostic else
263366389Sbostic (void) Lst_AtEnd (main, (ClientData)mainNode);
263440393Sbostic return (main);
263540393Sbostic }
2636