diff options
Diffstat (limited to 'usr.bin/make/parse.c')
-rw-r--r-- | usr.bin/make/parse.c | 651 |
1 files changed, 361 insertions, 290 deletions
diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c index 669c68a15436..e4d8446279bd 100644 --- a/usr.bin/make/parse.c +++ b/usr.bin/make/parse.c @@ -1,5 +1,3 @@ -/* $NetBSD: parse.c,v 1.26 1996/09/27 02:36:58 thorpej Exp $ */ - /* * Copyright (c) 1988, 1989, 1990, 1993 * The Regents of the University of California. All rights reserved. @@ -39,11 +37,7 @@ */ #ifndef lint -#if 0 -static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; -#else -static char rcsid[] = "$NetBSD: parse.c,v 1.26 1996/09/27 02:36:58 thorpej Exp $"; -#endif +static char sccsid[] = "@(#)parse.c 8.6 (Berkeley) 6/13/95"; #endif /* not lint */ /*- @@ -96,6 +90,7 @@ static char rcsid[] = "$NetBSD: parse.c,v 1.26 1996/09/27 02:36:58 thorpej Exp $ #include <stdio.h> #include <ctype.h> #include <errno.h> +#include <sys/wait.h> #include "make.h" #include "hash.h" #include "dir.h" @@ -167,20 +162,17 @@ typedef enum { NotParallel, /* .NOTPARALELL */ Null, /* .NULL */ Order, /* .ORDER */ - Parallel, /* .PARALLEL */ ExPath, /* .PATH */ - Phony, /* .PHONY */ Precious, /* .PRECIOUS */ + Reserved, /* .RESERVED or .[A-Z]* */ ExShell, /* .SHELL */ Silent, /* .SILENT */ SingleShell, /* .SINGLESHELL */ Suffixes, /* .SUFFIXES */ - Wait, /* .WAIT */ Attribute /* Generic attribute */ } ParseSpecial; static ParseSpecial specType; -static int waiting; /* * Predecessor node for handling .ORDER. Initialized to NILGNODE when .ORDER @@ -200,44 +192,70 @@ static struct { ParseSpecial spec; /* Type when used as a target */ int op; /* Operator when used as a source */ } parseKeywords[] = { +#define DOT_BEGIN 0 { ".BEGIN", Begin, 0 }, +#define DOT_DEFAULT 1 { ".DEFAULT", Default, 0 }, +#define DOT_END 2 { ".END", End, 0 }, +#define DOT_EXEC 3 { ".EXEC", Attribute, OP_EXEC }, +#define DOT_IGNORE 4 { ".IGNORE", Ignore, OP_IGNORE }, +#define DOT_INCLUDES 5 { ".INCLUDES", Includes, 0 }, +#define DOT_INTERRUPT 6 { ".INTERRUPT", Interrupt, 0 }, +#define DOT_INVISIBLE 7 { ".INVISIBLE", Attribute, OP_INVISIBLE }, +#define DOT_JOIN 8 { ".JOIN", Attribute, OP_JOIN }, +#define DOT_LIBS 9 { ".LIBS", Libs, 0 }, +#define DOT_MAIN 10 { ".MAIN", Main, 0 }, +#define DOT_MAKE 11 { ".MAKE", Attribute, OP_MAKE }, +#define DOT_MAKEFLAGS 12 { ".MAKEFLAGS", MFlags, 0 }, +#define DOT_MFLAGS 13 { ".MFLAGS", MFlags, 0 }, +#define DOT_NOTMAIN 14 { ".NOTMAIN", Attribute, OP_NOTMAIN }, +#define DOT_NOTPARALLEL 15 { ".NOTPARALLEL", NotParallel, 0 }, -{ ".NO_PARALLEL", NotParallel, 0 }, +#define DOT_NULL 16 { ".NULL", Null, 0 }, +#define DOT_OPTIONAL 17 { ".OPTIONAL", Attribute, OP_OPTIONAL }, +#define DOT_ORDER 18 { ".ORDER", Order, 0 }, -{ ".PARALLEL", Parallel, 0 }, +#define DOT_PATH 19 { ".PATH", ExPath, 0 }, -{ ".PHONY", Phony, OP_PHONY }, +#define DOT_PHONY 20 +{ ".PHONY", Attribute, OP_PHONY }, +#define DOT_PRECIOUS 21 { ".PRECIOUS", Precious, OP_PRECIOUS }, +#define DOT_RECURSIVE 22 { ".RECURSIVE", Attribute, OP_MAKE }, +#define DOT_RESERVED 23 +{ ".RESERVED", Reserved, 0 }, +#define DOT_SHELL 24 { ".SHELL", ExShell, 0 }, +#define DOT_SILENT 25 { ".SILENT", Silent, OP_SILENT }, +#define DOT_SINGLESHELL 26 { ".SINGLESHELL", SingleShell, 0 }, +#define DOT_SUFFIXES 27 { ".SUFFIXES", Suffixes, 0 }, +#define DOT_USE 28 { ".USE", Attribute, OP_USE }, -{ ".WAIT", Wait, 0 }, }; static int ParseFindKeyword __P((char *)); static int ParseLinkSrc __P((ClientData, ClientData)); static int ParseDoOp __P((ClientData, ClientData)); -static int ParseAddDep __P((ClientData, ClientData)); -static void ParseDoSrc __P((int, char *, Lst)); +static void ParseDoSrc __P((int, char *)); static int ParseFindMain __P((ClientData, ClientData)); static int ParseAddDir __P((ClientData, ClientData)); static int ParseClearPath __P((ClientData, ClientData)); @@ -275,7 +293,7 @@ ParseFindKeyword (str) end, cur; register int diff; - + start = 0; end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; @@ -291,7 +309,12 @@ ParseFindKeyword (str) start = cur + 1; } } while (start <= end); - return (-1); + + cur = 0; + for (++str; *str; str++) + if (!isupper((unsigned char) *str)) + break; + return *str ? -1 : DOT_RESERVED; } /*- @@ -398,7 +421,7 @@ ParseDoOp (gnp, opp) /* * If the dependency mask of the operator and the node don't match and * the node has actually had an operator applied to it before, and - * the operator actually has some dependency information in it, complain. + * the operator actually has some dependency information in it, complain. */ if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && !OP_NOP(gn->type) && !OP_NOP(op)) @@ -418,7 +441,7 @@ ParseDoOp (gnp, opp) */ register GNode *cohort; LstNode ln; - + cohort = Targ_NewGN(gn->name); /* * Duplicate links to parents so graph traversal is simple. Perhaps @@ -442,7 +465,7 @@ ParseDoOp (gnp, opp) } /* * We don't want to nuke any previous flags (whatever they were) so we - * just OR the new operator into the old + * just OR the new operator into the old */ gn->type |= op; @@ -451,45 +474,6 @@ ParseDoOp (gnp, opp) /*- *--------------------------------------------------------------------- - * ParseAddDep -- - * Check if the pair of GNodes given needs to be synchronized. - * This has to be when two nodes are on different sides of a - * .WAIT directive. - * - * Results: - * Returns 1 if the two targets need to be ordered, 0 otherwise. - * If it returns 1, the search can stop - * - * Side Effects: - * A dependency can be added between the two nodes. - * - *--------------------------------------------------------------------- - */ -int -ParseAddDep(pp, sp) - ClientData pp; - ClientData sp; -{ - GNode *p = (GNode *) pp; - GNode *s = (GNode *) sp; - - if (p->order < s->order) { - /* - * XXX: This can cause loops, and loops can cause unmade targets, - * but checking is tedious, and the debugging output can show the - * problem - */ - (void)Lst_AtEnd(p->successors, (ClientData)s); - (void)Lst_AtEnd(s->preds, (ClientData)p); - return 0; - } - else - return 1; -} - - -/*- - *--------------------------------------------------------------------- * ParseDoSrc -- * Given the name of a source, figure out if it is an attribute * and apply it to the targets if it is. Else decide if there is @@ -506,31 +490,23 @@ ParseAddDep(pp, sp) *--------------------------------------------------------------------- */ static void -ParseDoSrc (tOp, src, allsrc) +ParseDoSrc (tOp, src) int tOp; /* operator (if any) from special targets */ char *src; /* name of the source to handle */ - Lst allsrc; /* List of all sources to wait for */ - { - GNode *gn = NULL; + int op; /* operator (if any) from special source */ + GNode *gn; + op = 0; if (*src == '.' && isupper (src[1])) { int keywd = ParseFindKeyword(src); if (keywd != -1) { - int op = parseKeywords[keywd].op; - if (op != 0) { - Lst_ForEach (targets, ParseDoOp, (ClientData)&op); - return; - } - if (parseKeywords[keywd].spec == Wait) { - waiting++; - return; - } + op = parseKeywords[keywd].op; } } - - switch (specType) { - case Main: + if (op != 0) { + Lst_ForEach (targets, ParseDoOp, (ClientData)&op); + } else if (specType == Main) { /* * If we have noted the existence of a .MAIN, it means we need * to add the sources of said target to the list of things @@ -539,15 +515,13 @@ ParseDoSrc (tOp, src, allsrc) * invoked if the user didn't specify a target on the command * line. This is to allow #ifmake's to succeed, or something... */ - (void) Lst_AtEnd (create, (ClientData)estrdup(src)); + (void) Lst_AtEnd (create, (ClientData)strdup(src)); /* * Add the name to the .TARGETS variable as well, so the user cna * employ that, if desired. */ Var_Append(".TARGETS", src, VAR_GLOBAL); - return; - - case Order: + } else if (specType == Order) { /* * Create proper predecessor/successor links between the previous * source and the current one. @@ -561,9 +535,7 @@ ParseDoSrc (tOp, src, allsrc) * The current source now becomes the predecessor for the next one. */ predecessor = gn; - break; - - default: + } else { /* * If the source is not an attribute, we need to find/create * a node for it. After that we can apply any operator to it @@ -594,13 +566,6 @@ ParseDoSrc (tOp, src, allsrc) } } } - break; - } - - gn->order = waiting; - (void)Lst_AtEnd(allsrc, (ClientData)gn); - if (waiting) { - Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn); } } @@ -723,21 +688,17 @@ ParseDoDependency (line) Lst paths; /* List of search paths to alter when parsing * a list of .PATH targets */ int tOp; /* operator from special target */ - Lst sources; /* list of archive source names after - * expansion */ + Lst sources; /* list of source names after expansion */ Lst curTargs; /* list of target names to be found and added * to the targets list */ - Lst curSrcs; /* list of sources in order */ tOp = 0; specType = Not; - waiting = 0; paths = (Lst)NULL; curTargs = Lst_Init(FALSE); - curSrcs = Lst_Init(FALSE); - + do { for (cp = line; *cp && !isspace (*cp) && @@ -785,11 +746,11 @@ ParseDoDependency (line) } } savec = *cp; - + if (!*cp) { /* * Ending a dependency line without an operator is a Bozo - * no-no + * no-no */ Parse_Error (PARSE_FATAL, "Need an operator"); return; @@ -802,7 +763,7 @@ ParseDoDependency (line) if (*line == '.' && isupper (line[1])) { /* * See if the target is a special target that must have it - * or its sources handled specially. + * or its sources handled specially. */ int keywd = ParseFindKeyword(line); if (keywd != -1) { @@ -810,7 +771,7 @@ ParseDoDependency (line) Parse_Error(PARSE_FATAL, "Mismatched special targets"); return; } - + specType = parseKeywords[keywd].spec; tOp = parseKeywords[keywd].op; @@ -833,7 +794,6 @@ ParseDoDependency (line) * life easier later, when we'll * use Make_HandleUse to actually * apply the .DEFAULT commands. - * .PHONY The list of targets * .BEGIN * .END * .INTERRUPT Are not to be considered the @@ -870,7 +830,7 @@ ParseDoDependency (line) case NotParallel: { extern int maxJobs; - + maxJobs = 1; break; } @@ -880,6 +840,12 @@ ParseDoDependency (line) case Order: predecessor = NILGNODE; break; + case Reserved: + /* + * A posix reserved target that we don't know + * how to deal with. + */ + return; default: break; } @@ -890,7 +856,7 @@ ParseDoDependency (line) * modify. */ Lst path; - + specType = ExPath; path = Suff_GetPath (&line[5]); if (path == NILLST) { @@ -906,10 +872,10 @@ ParseDoDependency (line) } } } - + /* * Have word in line. Get or create its node and stick it at - * the end of the targets list + * the end of the targets list */ if ((specType == Not) && (*line != '\0')) { if (Dir_HasWildcards(line)) { @@ -920,9 +886,9 @@ ParseDoDependency (line) * Dir module could have added a directory to the path... */ Lst emptyPath = Lst_Init(FALSE); - + Dir_Expand(line, emptyPath, curTargs); - + Lst_Destroy(emptyPath, Dir_Destroy); } else { /* @@ -931,22 +897,22 @@ ParseDoDependency (line) */ (void)Lst_AtEnd(curTargs, (ClientData)line); } - + while(!Lst_IsEmpty(curTargs)) { char *targName = (char *)Lst_DeQueue(curTargs); - + if (!Suff_IsTransform (targName)) { gn = Targ_FindNode (targName, TARG_CREATE); } else { gn = Suff_AddTransform (targName); } - + (void)Lst_AtEnd (targets, (ClientData)gn); } } else if (specType == ExPath && *line != '.' && *line != '\0') { Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); } - + *cp = savec; /* * If it is a special type and not .PATH, it's the only target we @@ -954,7 +920,7 @@ ParseDoDependency (line) */ if (specType != Not && specType != ExPath) { Boolean warn = FALSE; - + while ((*cp != '!') && (*cp != ':') && *cp) { if (*cp != ' ' && *cp != '\t') { warn = TRUE; @@ -1021,7 +987,7 @@ ParseDoDependency (line) Lst_ForEach (targets, ParseDoOp, (ClientData)&op); /* - * Get to the first source + * Get to the first source */ while (*cp && isspace (*cp)) { cp++; @@ -1074,9 +1040,9 @@ ParseDoDependency (line) } else if ((specType == NotParallel) || (specType == SingleShell)) { *line = '\0'; } - + /* - * NOW GO FOR THE SOURCES + * NOW GO FOR THE SOURCES */ if ((specType == Suffixes) || (specType == ExPath) || (specType == Includes) || (specType == Libs) || @@ -1177,7 +1143,7 @@ ParseDoDependency (line) while (!Lst_IsEmpty (sources)) { gn = (GNode *) Lst_DeQueue (sources); - ParseDoSrc (tOp, gn->name, curSrcs); + ParseDoSrc (tOp, gn->name); } Lst_Destroy (sources, NOFREE); cp = line; @@ -1187,7 +1153,7 @@ ParseDoDependency (line) cp += 1; } - ParseDoSrc (tOp, line, curSrcs); + ParseDoSrc (tOp, line); } while (*cp && isspace (*cp)) { cp++; @@ -1195,7 +1161,7 @@ ParseDoDependency (line) line = cp; } } - + if (mainNode == NILGNODE) { /* * If we have yet to decide on a main target to make, in the @@ -1206,10 +1172,6 @@ ParseDoDependency (line) Lst_ForEach (targets, ParseFindMain, (ClientData)0); } - /* - * Finally, destroy the list of sources - */ - Lst_Destroy(curSrcs, NOFREE); } /*- @@ -1234,80 +1196,60 @@ Parse_IsVar (line) { register Boolean wasSpace = FALSE; /* set TRUE if found a space */ register Boolean haveName = FALSE; /* Set TRUE if have a variable name */ - int level = 0; -#define ISEQOPERATOR(c) \ - (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!')) /* * Skip to variable name */ - for (;(*line == ' ') || (*line == '\t'); line++) - continue; + while ((*line == ' ') || (*line == '\t')) { + line++; + } - for (; *line != '=' || level != 0; line++) - switch (*line) { - case '\0': + while (*line != '=') { + if (*line == '\0') { /* * end-of-line -- can't be a variable assignment. */ - return FALSE; - - case ' ': - case '\t': + return (FALSE); + } else if ((*line == ' ') || (*line == '\t')) { /* * there can be as much white space as desired so long as there is - * only one word before the operator + * only one word before the operator */ wasSpace = TRUE; - break; - - case '(': - case '{': - level++; - break; - - case '}': - case ')': - level--; - break; - - default: - if (wasSpace && haveName) { - if (ISEQOPERATOR(*line)) { - /* - * We must have a finished word - */ - if (level != 0) - return FALSE; - - /* - * When an = operator [+?!:] is found, the next - * character must be an = or it ain't a valid - * assignment. - */ - if (line[1] == '=') - return haveName; -#ifdef SUNSHCMD - /* - * This is a shell command - */ - if (strncmp(line, ":sh", 3) == 0) - return haveName; -#endif - } - /* - * This is the start of another word, so not assignment. - */ - return FALSE; - } - else { - haveName = TRUE; - wasSpace = FALSE; + } else if (wasSpace && haveName) { + /* + * Stop when an = operator is found. + */ + if ((*line == '+') || (*line == ':') || (*line == '?') || + (*line == '!')) { + break; } - break; + + /* + * This is the start of another word, so not assignment. + */ + return (FALSE); + } else { + haveName = TRUE; + wasSpace = FALSE; } + line++; + } - return haveName; + /* + * A final check: if we stopped on a +, ?, ! or :, the next character must + * be an = or it ain't a valid assignment + */ + if (((*line == '+') || + (*line == '?') || + (*line == ':') || + (*line == '!')) && + (line[1] != '=')) + { + return (FALSE); + } else { + return (haveName); + } } /*- @@ -1340,9 +1282,9 @@ Parse_DoVar (line, ctxt) enum { VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL } type; /* Type of assignment */ - char *opc; /* ptr to operator character to + char *opc; /* ptr to operator character to * null-terminate the variable name */ - /* + /* * Avoid clobbered variable warnings by forcing the compiler * to ``unregister'' variables */ @@ -1401,17 +1343,6 @@ Parse_DoVar (line, ctxt) break; default: -#ifdef SUNSHCMD - while (*opc != ':') - if (--opc < line) - break; - - if (strncmp(opc, ":sh", 3) == 0) { - type = VAR_SHELL; - *opc = '\0'; - break; - } -#endif type = VAR_NORMAL; break; } @@ -1443,38 +1374,156 @@ Parse_DoVar (line, ctxt) Var_Set(line, cp, ctxt); free(cp); } else if (type == VAR_SHELL) { - Boolean freeCmd = FALSE; /* TRUE if the command needs to be freed, i.e. - * if any variable expansion was performed */ - char *res, *err; + char *args[4]; /* Args for invoking the shell */ + int fds[2]; /* Pipe streams */ + int cpid; /* Child PID */ + int pid; /* PID from wait() */ + Boolean freeCmd; /* TRUE if the command needs to be freed, i.e. + * if any variable expansion was performed */ + + /* + * Avoid clobbered variable warnings by forcing the compiler + * to ``unregister'' variables + */ +#if __GNUC__ + (void) &freeCmd; +#endif - if (strchr(cp, '$') != NULL) { + /* + * Set up arguments for shell + */ + args[0] = "sh"; + args[1] = "-c"; + if (strchr(cp, '$') != (char *)NULL) { /* * There's a dollar sign in the command, so perform variable * expansion on the whole thing. The resulting string will need * freeing when we're done, so set freeCmd to TRUE. */ - cp = Var_Subst(NULL, cp, VAR_CMD, TRUE); + args[2] = Var_Subst(NULL, cp, VAR_CMD, TRUE); freeCmd = TRUE; + } else { + args[2] = cp; + freeCmd = FALSE; } + args[3] = (char *)NULL; + + /* + * Open a pipe for fetching its output + */ + pipe(fds); + + /* + * Fork + */ + cpid = vfork(); + if (cpid == 0) { + /* + * Close input side of pipe + */ + close(fds[0]); - res = Cmd_Exec(cp, &err); - Var_Set(line, res, ctxt); - free(res); + /* + * Duplicate the output stream to the shell's output, then + * shut the extra thing down. Note we don't fetch the error + * stream...why not? Why? + */ + dup2(fds[1], 1); + close(fds[1]); + + execv("/bin/sh", args); + _exit(1); + } else if (cpid < 0) { + /* + * Couldn't fork -- tell the user and make the variable null + */ + Parse_Error(PARSE_WARNING, "Couldn't exec \"%s\"", cp); + Var_Set(line, "", ctxt); + } else { + int status; + int cc; + Buffer buf; + char *res; - if (err) - Parse_Error(PARSE_WARNING, err, cp); + /* + * No need for the writing half + */ + close(fds[1]); + + buf = Buf_Init (MAKE_BSIZE); + + do { + char result[BUFSIZ]; + cc = read(fds[0], result, sizeof(result)); + if (cc > 0) + Buf_AddBytes(buf, cc, (Byte *) result); + } + while (cc > 0 || (cc == -1 && errno == EINTR)); + + /* + * Close the input side of the pipe. + */ + close(fds[0]); - if (freeCmd) - free(cp); + /* + * Wait for the process to exit. + */ + while(((pid = wait(&status)) != cpid) && (pid >= 0)) + continue; + + res = (char *)Buf_GetAll (buf, &cc); + Buf_Destroy (buf, FALSE); + + if (cc == 0) { + /* + * Couldn't read the child's output -- tell the user and + * set the variable to null + */ + Parse_Error(PARSE_WARNING, "Couldn't read shell's output"); + } + + if (status) { + /* + * Child returned an error -- tell the user but still use + * the result. + */ + Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp); + } + + /* + * Null-terminate the result, convert newlines to spaces and + * install it in the variable. + */ + res[cc] = '\0'; + cp = &res[cc] - 1; + + if (*cp == '\n') { + /* + * A final newline is just stripped + */ + *cp-- = '\0'; + } + while (cp >= res) { + if (*cp == '\n') { + *cp = ' '; + } + cp--; + } + Var_Set(line, res, ctxt); + free(res); + + } + if (freeCmd) { + free(args[2]); + } } else { /* * Normal assignment -- just do it. */ - Var_Set(line, cp, ctxt); + Var_Set (line, cp, ctxt); } } - /*- * ParseAddCmd -- * Lst_ForEach function to add a command line to all targets @@ -1548,7 +1597,7 @@ Parse_AddIncludeDir (dir) *--------------------------------------------------------------------- * ParseDoInclude -- * Push to another file. - * + * * The input is the line minus the #include. A file spec is a string * enclosed in <> or "". The former is looked for only in sysIncPath. * The latter in . and the directories specified by -I command line @@ -1632,20 +1681,17 @@ ParseDoInclude (file) * leading path components and call Dir_FindFile to see if * we can locate the beast. */ - char *prefEnd, *Fname; + char *prefEnd; - /* Make a temporary copy of this, to be safe. */ - Fname = estrdup(fname); - - prefEnd = strrchr (Fname, '/'); + prefEnd = strrchr (fname, '/'); if (prefEnd != (char *)NULL) { char *newName; - + *prefEnd = '\0'; if (file[0] == '/') - newName = estrdup(file); + newName = strdup(file); else - newName = str_concat (Fname, file, STR_ADDSLASH); + newName = str_concat (fname, file, STR_ADDSLASH); fullname = Dir_FindFile (newName, parseIncPath); if (fullname == (char *)NULL) { fullname = Dir_FindFile(newName, dirSearchPath); @@ -1655,7 +1701,6 @@ ParseDoInclude (file) } else { fullname = (char *)NULL; } - free (Fname); } else { fullname = (char *)NULL; } @@ -1730,7 +1775,7 @@ ParseDoInclude (file) *--------------------------------------------------------------------- * Parse_FromString -- * Start Parsing from the given string - * + * * Results: * None * @@ -1753,14 +1798,14 @@ Parse_FromString(str) oldFile->fname = fname; oldFile->F = curFILE; oldFile->p = curPTR; - + (void) Lst_AtFront (includes, (ClientData)oldFile); curFILE = NULL; curPTR = (PTR *) emalloc (sizeof (PTR)); curPTR->str = curPTR->ptr = str; lineno = 0; - fname = estrdup(fname); + fname = strdup(fname); } @@ -1769,7 +1814,7 @@ Parse_FromString(str) *--------------------------------------------------------------------- * ParseTraditionalInclude -- * Push to another file. - * + * * The input is the line minus the "include". The file name is * the string following the "include". * @@ -1832,7 +1877,7 @@ ParseTraditionalInclude (file) prefEnd = strrchr (fname, '/'); if (prefEnd != (char *)NULL) { char *newName; - + *prefEnd = '\0'; newName = str_concat (fname, file, STR_ADDSLASH); fullname = Dir_FindFile (newName, parseIncPath); @@ -1952,7 +1997,7 @@ ParseEOF (opened) /*- *--------------------------------------------------------------------- * ParseReadc -- - * Read a character from the current file + * Read a character from the current file * * Results: * The character that was read @@ -1965,7 +2010,7 @@ ParseReadc() { if (curFILE) return fgetc(curFILE); - + if (curPTR && *curPTR->ptr) return *curPTR->ptr++; return EOF; @@ -1975,7 +2020,7 @@ ParseReadc() /*- *--------------------------------------------------------------------- * ParseUnreadc -- - * Put back a character to the current file + * Put back a character to the current file * * Results: * None. @@ -2006,43 +2051,54 @@ ParseSkipLine(skip) int skip; /* Skip lines that don't start with . */ { char *line; - int c, lastc, lineLength = 0; + int c, lastc = '\0', lineLength; Buffer buf; - buf = Buf_Init(MAKE_BSIZE); - - do { - Buf_Discard(buf, lineLength); - lastc = '\0'; - - while (((c = ParseReadc()) != '\n' || lastc == '\\') - && c != EOF) { - if (c == '\n') { - Buf_ReplaceLastByte(buf, (Byte)' '); - lineno++; - - while ((c = ParseReadc()) == ' ' || c == '\t'); - - if (c == EOF) - break; - } - - Buf_AddByte(buf, (Byte)c); - lastc = c; - } + c = ParseReadc(); - if (c == EOF) { - Parse_Error(PARSE_FATAL, "Unclosed conditional/for loop"); - Buf_Destroy(buf, TRUE); - return((char *)NULL); - } - - lineno++; - Buf_AddByte(buf, (Byte)'\0'); - line = (char *)Buf_GetAll(buf, &lineLength); - } while (skip == 1 && line[0] != '.'); - - Buf_Destroy(buf, FALSE); + if (skip) { + /* + * Skip lines until get to one that begins with a + * special char. + */ + while ((c != '.') && (c != EOF)) { + while (((c != '\n') || (lastc == '\\')) && (c != EOF)) + { + /* + * Advance to next unescaped newline + */ + if ((lastc = c) == '\n') { + lineno++; + } + c = ParseReadc(); + } + lineno++; + + lastc = c; + c = ParseReadc (); + } + } + + if (c == EOF) { + Parse_Error (PARSE_FATAL, "Unclosed conditional/for loop"); + return ((char *)NULL); + } + + /* + * Read the entire line into buf + */ + buf = Buf_Init (MAKE_BSIZE); + if (c != '\n') { + do { + Buf_AddByte (buf, (Byte)c); + c = ParseReadc(); + } while ((c != '\n') && (c != EOF)); + } + lineno++; + + Buf_AddByte (buf, (Byte)'\0'); + line = (char *)Buf_GetAll (buf, &lineLength); + Buf_Destroy (buf, FALSE); return line; } @@ -2108,11 +2164,11 @@ ParseReadLine () break; } } - + if (c != EOF) { lastc = c; buf = Buf_Init(MAKE_BSIZE); - + while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && (c != EOF)) { @@ -2160,7 +2216,7 @@ test_char: */ ParseUnreadc('\t'); goto line_read; - } + } break; case '=': if (!semiNL) { @@ -2186,11 +2242,7 @@ test_char: break; case '#': if (!ignComment) { - if ( -#if 0 - compatMake && -#endif - (lastc != '\\')) { + if (compatMake && (lastc != '\\')) { /* * If the character is a hash mark and it isn't escaped * (or we're being compatible), the thing is a comment. @@ -2227,11 +2279,11 @@ test_char: */ Buf_AddByte (buf, (Byte)lastc); lastc = c; - + } line_read: lineno++; - + if (lastc != '\0') { Buf_AddByte (buf, (Byte)lastc); } @@ -2247,13 +2299,13 @@ test_char: ep = line; while (*ep) ++ep; - while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) { + while (ep > line && (ep[-1] == ' ' || ep[-1] == '\t')) { if (ep > line + 1 && ep[-2] == '\\') break; --ep; } *ep = 0; - + if (line[0] == '.') { /* * The line might be a conditional. Ask the conditional module @@ -2285,7 +2337,7 @@ test_char: */ line = ParseSkipLine(0); if (line == NULL) { - Parse_Error (PARSE_FATAL, + Parse_Error (PARSE_FATAL, "Unexpected end of file in for loop.\n"); break; } @@ -2333,7 +2385,7 @@ ParseFinishLine() inLine = FALSE; } } - + /*- *--------------------------------------------------------------------- @@ -2394,11 +2446,12 @@ Parse_File(name, stream) goto nextLine; } } - if (*line == '#') { - /* If we're this far, the line must be a comment. */ + if (*line == '#' || *line == '\0') { + /* If we're this far, the line must be a comment. + (Empty lines are ignored as well) */ goto nextLine; } - + if (*line == '\t') { /* * If a line starts with a tab, it can only hope to be @@ -2415,20 +2468,19 @@ Parse_File(name, stream) /* * So long as it's not a blank line and we're actually * in a dependency spec, add the command to the list of - * commands of all targets in the dependency spec + * commands of all targets in the dependency spec */ Lst_ForEach (targets, ParseAddCmd, cp); Lst_AtEnd(targCmds, (ClientData) line); continue; } else { Parse_Error (PARSE_FATAL, - "Unassociated shell command \"%s\"", + "Unassociated shell command \"%.20s\"", cp); } } #ifdef SYSVINCLUDE - } else if (strncmp (line, "include", 7) == 0 && - isspace((unsigned char) line[7]) && + } else if (strncmp (line, "include", 7) == 0 && strchr(line, ':') == NULL) { /* * It's an S3/S5-style "include". @@ -2453,7 +2505,7 @@ Parse_File(name, stream) #ifndef POSIX Boolean nonSpace = FALSE; #endif - + cp = line; if (isspace((unsigned char) line[0])) { while ((*cp != '\0') && isspace((unsigned char) *cp)) { @@ -2469,7 +2521,7 @@ Parse_File(name, stream) } #endif } - + #ifndef POSIX if (*cp == '\0') { if (inLine) { @@ -2486,16 +2538,16 @@ Parse_File(name, stream) cp = Var_Subst (NULL, line, VAR_CMD, TRUE); free (line); line = cp; - + /* - * Need a non-circular list for the target nodes + * Need a non-circular list for the target nodes */ if (targets) Lst_Destroy(targets, NOFREE); targets = Lst_Init (FALSE); inLine = TRUE; - + ParseDoDependency (line); #ifndef POSIX } @@ -2507,7 +2559,7 @@ Parse_File(name, stream) free (line); } /* - * Reached EOF, but it may be just EOF of an include file... + * Reached EOF, but it may be just EOF of an include file... */ } while (ParseEOF(1) == CONTINUE); @@ -2537,11 +2589,30 @@ Parse_File(name, stream) void Parse_Init () { + char *cp = NULL, *start; + /* avoid faults on read-only strings */ + static char syspath[] = _PATH_DEFSYSPATH; + mainNode = NILGNODE; parseIncPath = Lst_Init (FALSE); sysIncPath = Lst_Init (FALSE); includes = Lst_Init (FALSE); targCmds = Lst_Init (FALSE); + + /* + * Add the directories from the DEFSYSPATH (more than one may be given + * as dir1:...:dirn) to the system include path. + */ + for (start = syspath; *start != '\0'; start = cp) { + for (cp = start; *cp != '\0' && *cp != ':'; cp++) + continue; + if (*cp == '\0') { + Dir_AddDir(sysIncPath, start); + } else { + *cp++ = '\0'; + Dir_AddDir(sysIncPath, start); + } + } } void @@ -2554,7 +2625,7 @@ Parse_End() Lst_Destroy(parseIncPath, Dir_Destroy); Lst_Destroy(includes, NOFREE); /* Should be empty now */ } - + /*- *----------------------------------------------------------------------- @@ -2578,7 +2649,7 @@ Parse_MainName() main = Lst_Init (FALSE); if (mainNode == NILGNODE) { - Punt ("no target to make."); + Punt ("make: no target to make.\n"); /*NOTREACHED*/ } else if (mainNode->type & OP_DOUBLEDEP) { (void) Lst_AtEnd (main, (ClientData)mainNode); |