summaryrefslogtreecommitdiffstats
path: root/usr.bin/make/parse.c
diff options
context:
space:
mode:
authorsteve <steve@FreeBSD.org>1996-10-06 02:35:38 +0000
committersteve <steve@FreeBSD.org>1996-10-06 02:35:38 +0000
commit49662693d9f1e004b037bebf6cc4663e64ae7baa (patch)
treeab5bd5270becce85fa203b4b54d26c39fa7c14bc /usr.bin/make/parse.c
parent7dcbb4192b730b0ebfec18a71b61cd487c61320a (diff)
downloadFreeBSD-src-49662693d9f1e004b037bebf6cc4663e64ae7baa.zip
FreeBSD-src-49662693d9f1e004b037bebf6cc4663e64ae7baa.tar.gz
Merge in NetBSD's changes to make(1). Changes include:
- Add the .PHONY, .PARALLEL, and .WAIT directives - Added the -B and -m commandline flags - misc. man page cleanups - numerous job-related enhancements - removed unused header file (bit.h) - add util.c for functions not found in other envs. - and a few coordinated whitespace changes Special thanks to Christos Zoulas <christos@netbsd.org> for help in the merge. A 'diff -ur' between Net and FreeBSD now only contains sccsid-related diffs. :) Obtained from: NetBSD, christos@netbsd.org, and me
Diffstat (limited to 'usr.bin/make/parse.c')
-rw-r--r--usr.bin/make/parse.c405
1 files changed, 190 insertions, 215 deletions
diff --git a/usr.bin/make/parse.c b/usr.bin/make/parse.c
index b241063..9e2713e 100644
--- a/usr.bin/make/parse.c
+++ b/usr.bin/make/parse.c
@@ -90,7 +90,6 @@ static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
-#include <sys/wait.h>
#include "make.h"
#include "hash.h"
#include "dir.h"
@@ -162,16 +161,20 @@ typedef enum {
NotParallel, /* .NOTPARALELL */
Null, /* .NULL */
Order, /* .ORDER */
+ Parallel, /* .PARALLEL */
ExPath, /* .PATH */
+ Phony, /* .PHONY */
Precious, /* .PRECIOUS */
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
@@ -207,10 +210,13 @@ static struct {
{ ".MFLAGS", MFlags, 0 },
{ ".NOTMAIN", Attribute, OP_NOTMAIN },
{ ".NOTPARALLEL", NotParallel, 0 },
+{ ".NO_PARALLEL", NotParallel, 0 },
{ ".NULL", Null, 0 },
{ ".OPTIONAL", Attribute, OP_OPTIONAL },
{ ".ORDER", Order, 0 },
+{ ".PARALLEL", Parallel, 0 },
{ ".PATH", ExPath, 0 },
+{ ".PHONY", Phony, OP_PHONY },
{ ".PRECIOUS", Precious, OP_PRECIOUS },
{ ".RECURSIVE", Attribute, OP_MAKE },
{ ".SHELL", ExShell, 0 },
@@ -218,12 +224,14 @@ static struct {
{ ".SINGLESHELL", SingleShell, 0 },
{ ".SUFFIXES", Suffixes, 0 },
{ ".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 void ParseDoSrc __P((int, char *));
+static int ParseAddDep __P((ClientData, ClientData));
+static void ParseDoSrc __P((int, char *, Lst));
static int ParseFindMain __P((ClientData, ClientData));
static int ParseAddDir __P((ClientData, ClientData));
static int ParseClearPath __P((ClientData, ClientData));
@@ -437,6 +445,45 @@ 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
@@ -453,23 +500,30 @@ ParseDoOp (gnp, opp)
*---------------------------------------------------------------------
*/
static void
-ParseDoSrc (tOp, src)
+ParseDoSrc (tOp, src, allsrc)
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 */
{
- int op; /* operator (if any) from special source */
- GNode *gn;
+ GNode *gn = NULL;
- op = 0;
if (*src == '.' && isupper (src[1])) {
int keywd = ParseFindKeyword(src);
if (keywd != -1) {
- op = parseKeywords[keywd].op;
+ int op = parseKeywords[keywd].op;
+ if (op != 0) {
+ Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
+ return;
+ }
+ if (parseKeywords[keywd].spec == Wait) {
+ waiting++;
+ return;
+ }
}
}
- if (op != 0) {
- Lst_ForEach (targets, ParseDoOp, (ClientData)&op);
- } else if (specType == Main) {
+
+ switch (specType) {
+ case 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
@@ -478,13 +532,15 @@ ParseDoSrc (tOp, src)
* 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)strdup(src));
+ (void) Lst_AtEnd (create, (ClientData)estrdup(src));
/*
* Add the name to the .TARGETS variable as well, so the user cna
* employ that, if desired.
*/
Var_Append(".TARGETS", src, VAR_GLOBAL);
- } else if (specType == Order) {
+ return;
+
+ case Order:
/*
* Create proper predecessor/successor links between the previous
* source and the current one.
@@ -498,7 +554,9 @@ ParseDoSrc (tOp, src)
* The current source now becomes the predecessor for the next one.
*/
predecessor = gn;
- } else {
+ break;
+
+ default:
/*
* 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
@@ -529,6 +587,13 @@ ParseDoSrc (tOp, src)
}
}
}
+ break;
+ }
+
+ gn->order = waiting;
+ (void)Lst_AtEnd(allsrc, (ClientData)gn);
+ if (waiting) {
+ Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn);
}
}
@@ -651,16 +716,20 @@ 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 source names after expansion */
+ Lst sources; /* list of archive 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;
@@ -757,6 +826,7 @@ 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
@@ -1100,7 +1170,7 @@ ParseDoDependency (line)
while (!Lst_IsEmpty (sources)) {
gn = (GNode *) Lst_DeQueue (sources);
- ParseDoSrc (tOp, gn->name);
+ ParseDoSrc (tOp, gn->name, curSrcs);
}
Lst_Destroy (sources, NOFREE);
cp = line;
@@ -1110,7 +1180,7 @@ ParseDoDependency (line)
cp += 1;
}
- ParseDoSrc (tOp, line);
+ ParseDoSrc (tOp, line, curSrcs);
}
while (*cp && isspace (*cp)) {
cp++;
@@ -1129,6 +1199,10 @@ ParseDoDependency (line)
Lst_ForEach (targets, ParseFindMain, (ClientData)0);
}
+ /*
+ * Finally, destroy the list of sources
+ */
+ Lst_Destroy(curSrcs, NOFREE);
}
/*-
@@ -1153,60 +1227,80 @@ 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
*/
- while ((*line == ' ') || (*line == '\t')) {
- line++;
- }
+ for (;(*line == ' ') || (*line == '\t'); line++)
+ continue;
- while (*line != '=') {
- if (*line == '\0') {
+ for (; *line != '=' || level != 0; line++)
+ switch (*line) {
+ case '\0':
/*
* end-of-line -- can't be a variable assignment.
*/
- return (FALSE);
- } else if ((*line == ' ') || (*line == '\t')) {
+ return FALSE;
+
+ case ' ':
+ case '\t':
/*
* there can be as much white space as desired so long as there is
* only one word before the operator
*/
wasSpace = TRUE;
- } 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;
+ 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;
+ }
+ break;
}
- line++;
- }
- /*
- * 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);
- }
+ return haveName;
}
/*-
@@ -1300,6 +1394,17 @@ 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;
}
@@ -1331,157 +1436,38 @@ Parse_DoVar (line, ctxt)
Var_Set(line, cp, ctxt);
free(cp);
} else if (type == VAR_SHELL) {
- 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
+ Boolean freeCmd = FALSE; /* TRUE if the command needs to be freed, i.e.
+ * if any variable expansion was performed */
+ char *res, *err;
- /*
- * Set up arguments for shell
- */
- args[0] = "sh";
- args[1] = "-c";
- if (strchr(cp, '$') != (char *)NULL) {
+ if (strchr(cp, '$') != 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.
*/
- args[2] = Var_Subst(NULL, cp, VAR_CMD, TRUE);
+ cp = 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]);
-
- /*
- * 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;
-
- /*
- * 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]);
-
- /*
- * Wait for the process to exit.
- */
- while(((pid = wait(&status)) != cpid) && (pid >= 0))
- continue;
-
- if (cc == -1) {
- /*
- * Couldn't read all of the child's output -- tell the user
- * but still use whatever we read. Null output isn't an
- * error unless there was an error reading it.
- */
- Parse_Error(PARSE_WARNING, "Couldn't read shell's output");
- }
- res = (char *)Buf_GetAll (buf, &cc);
- Buf_Destroy (buf, FALSE);
+ res = Cmd_Exec(cp, &err);
+ Var_Set(line, res, ctxt);
+ free(res);
- if (status) {
- /*
- * Child returned an error -- tell the user but still use
- * the result.
- */
- Parse_Error(PARSE_WARNING, "\"%s\" returned non-zero", cp);
- }
+ if (err)
+ Parse_Error(PARSE_WARNING, err, 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]);
- }
+ if (freeCmd)
+ free(cp);
} 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
@@ -1639,17 +1625,20 @@ ParseDoInclude (file)
* leading path components and call Dir_FindFile to see if
* we can locate the beast.
*/
- char *prefEnd;
+ char *prefEnd, *Fname;
- prefEnd = strrchr (fname, '/');
+ /* Make a temporary copy of this, to be safe. */
+ Fname = estrdup(fname);
+
+ prefEnd = strrchr (Fname, '/');
if (prefEnd != (char *)NULL) {
char *newName;
*prefEnd = '\0';
if (file[0] == '/')
- newName = strdup(file);
+ newName = estrdup(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);
@@ -1659,6 +1648,7 @@ ParseDoInclude (file)
} else {
fullname = (char *)NULL;
}
+ free (Fname);
} else {
fullname = (char *)NULL;
}
@@ -1763,7 +1753,7 @@ Parse_FromString(str)
curPTR = (PTR *) emalloc (sizeof (PTR));
curPTR->str = curPTR->ptr = str;
lineno = 0;
- fname = strdup(fname);
+ fname = estrdup(fname);
}
@@ -2189,7 +2179,11 @@ test_char:
break;
case '#':
if (!ignComment) {
- if (compatMake && (lastc != '\\')) {
+ if (
+#if 0
+ compatMake &&
+#endif
+ (lastc != '\\')) {
/*
* If the character is a hash mark and it isn't escaped
* (or we're being compatible), the thing is a comment.
@@ -2247,7 +2241,7 @@ test_char:
while (*ep)
++ep;
while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) {
- if (ep[-2] == '\\')
+ if (ep > line + 1 && ep[-2] == '\\')
break;
--ep;
}
@@ -2421,13 +2415,13 @@ Parse_File(name, stream)
continue;
} else {
Parse_Error (PARSE_FATAL,
- "Unassociated shell command \"%.20s\"",
+ "Unassociated shell command \"%s\"",
cp);
}
}
#ifdef SYSVINCLUDE
} else if (strncmp (line, "include", 7) == 0 &&
- isspace(line[7]) &&
+ isspace((unsigned char) line[7]) &&
strchr(line, ':') == NULL) {
/*
* It's an S3/S5-style "include".
@@ -2536,30 +2530,11 @@ 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
OpenPOWER on IntegriCloud