version 1.10, 1996/09/21 05:03:37 |
version 1.11, 1996/11/30 21:09:02 |
|
|
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* $NetBSD: parse.c,v 1.25 1996/09/13 04:22:09 christos Exp $ */ |
/* $NetBSD: parse.c,v 1.27 1996/11/06 17:59:20 christos Exp $ */ |
|
|
/* |
/* |
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California. |
* Copyright (c) 1988, 1989, 1990, 1993 |
* Copyright (c) 1988, 1989 by Adam de Boor |
* The Regents of the University of California. All rights reserved. |
* Copyright (c) 1989 by Berkeley Softworks |
* Copyright (c) 1989 by Berkeley Softworks |
* All rights reserved. |
* All rights reserved. |
* |
* |
|
|
|
|
#ifndef lint |
#ifndef lint |
#if 0 |
#if 0 |
static char sccsid[] = "@(#)parse.c 5.18 (Berkeley) 2/19/91"; |
static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; |
#else |
#else |
static char rcsid[] = "$NetBSD: parse.c,v 1.25 1996/09/13 04:22:09 christos Exp $"; |
static char rcsid[] = "$OpenBSD$"; |
#endif |
#endif |
#endif /* not lint */ |
#endif /* not lint */ |
|
|
|
|
end, |
end, |
cur; |
cur; |
register int diff; |
register int diff; |
|
|
start = 0; |
start = 0; |
end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; |
end = (sizeof(parseKeywords)/sizeof(parseKeywords[0])) - 1; |
|
|
|
|
/* |
/* |
* If the dependency mask of the operator and the node don't match and |
* 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 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)) && |
if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && |
!OP_NOP(gn->type) && !OP_NOP(op)) |
!OP_NOP(gn->type) && !OP_NOP(op)) |
|
|
*/ |
*/ |
register GNode *cohort; |
register GNode *cohort; |
LstNode ln; |
LstNode ln; |
|
|
cohort = Targ_NewGN(gn->name); |
cohort = Targ_NewGN(gn->name); |
/* |
/* |
* Duplicate links to parents so graph traversal is simple. Perhaps |
* Duplicate links to parents so graph traversal is simple. Perhaps |
|
|
} |
} |
/* |
/* |
* We don't want to nuke any previous flags (whatever they were) so we |
* 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; |
gn->type |= op; |
|
|
return (0); |
return (0); |
} |
} |
|
|
/*- |
/*- |
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
* ParseAddDep -- |
* ParseAddDep -- |
* Check if the pair of GNodes given needs to be synchronized. |
* Check if the pair of GNodes given needs to be synchronized. |
|
|
* |
* |
* Side Effects: |
* Side Effects: |
* A dependency can be added between the two nodes. |
* A dependency can be added between the two nodes. |
* |
* |
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
*/ |
*/ |
int |
int |
|
|
|
|
curTargs = Lst_Init(FALSE); |
curTargs = Lst_Init(FALSE); |
curSrcs = Lst_Init(FALSE); |
curSrcs = Lst_Init(FALSE); |
|
|
do { |
do { |
for (cp = line; |
for (cp = line; |
*cp && !isspace (*cp) && |
*cp && !isspace (*cp) && |
|
|
} |
} |
} |
} |
savec = *cp; |
savec = *cp; |
|
|
if (!*cp) { |
if (!*cp) { |
/* |
/* |
* Ending a dependency line without an operator is a Bozo |
* Ending a dependency line without an operator is a Bozo |
* no-no |
* no-no |
*/ |
*/ |
Parse_Error (PARSE_FATAL, "Need an operator"); |
Parse_Error (PARSE_FATAL, "Need an operator"); |
return; |
return; |
|
|
if (*line == '.' && isupper (line[1])) { |
if (*line == '.' && isupper (line[1])) { |
/* |
/* |
* See if the target is a special target that must have it |
* 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); |
int keywd = ParseFindKeyword(line); |
if (keywd != -1) { |
if (keywd != -1) { |
|
|
Parse_Error(PARSE_FATAL, "Mismatched special targets"); |
Parse_Error(PARSE_FATAL, "Mismatched special targets"); |
return; |
return; |
} |
} |
|
|
specType = parseKeywords[keywd].spec; |
specType = parseKeywords[keywd].spec; |
tOp = parseKeywords[keywd].op; |
tOp = parseKeywords[keywd].op; |
|
|
|
|
case NotParallel: |
case NotParallel: |
{ |
{ |
extern int maxJobs; |
extern int maxJobs; |
|
|
maxJobs = 1; |
maxJobs = 1; |
break; |
break; |
} |
} |
|
|
* modify. |
* modify. |
*/ |
*/ |
Lst path; |
Lst path; |
|
|
specType = ExPath; |
specType = ExPath; |
path = Suff_GetPath (&line[5]); |
path = Suff_GetPath (&line[5]); |
if (path == NILLST) { |
if (path == NILLST) { |
|
|
} |
} |
} |
} |
} |
} |
|
|
/* |
/* |
* Have word in line. Get or create its node and stick it at |
* 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 ((specType == Not) && (*line != '\0')) { |
if (Dir_HasWildcards(line)) { |
if (Dir_HasWildcards(line)) { |
|
|
* Dir module could have added a directory to the path... |
* Dir module could have added a directory to the path... |
*/ |
*/ |
Lst emptyPath = Lst_Init(FALSE); |
Lst emptyPath = Lst_Init(FALSE); |
|
|
Dir_Expand(line, emptyPath, curTargs); |
Dir_Expand(line, emptyPath, curTargs); |
|
|
Lst_Destroy(emptyPath, Dir_Destroy); |
Lst_Destroy(emptyPath, Dir_Destroy); |
} else { |
} else { |
/* |
/* |
|
|
*/ |
*/ |
(void)Lst_AtEnd(curTargs, (ClientData)line); |
(void)Lst_AtEnd(curTargs, (ClientData)line); |
} |
} |
|
|
while(!Lst_IsEmpty(curTargs)) { |
while(!Lst_IsEmpty(curTargs)) { |
char *targName = (char *)Lst_DeQueue(curTargs); |
char *targName = (char *)Lst_DeQueue(curTargs); |
|
|
if (!Suff_IsTransform (targName)) { |
if (!Suff_IsTransform (targName)) { |
gn = Targ_FindNode (targName, TARG_CREATE); |
gn = Targ_FindNode (targName, TARG_CREATE); |
} else { |
} else { |
gn = Suff_AddTransform (targName); |
gn = Suff_AddTransform (targName); |
} |
} |
|
|
(void)Lst_AtEnd (targets, (ClientData)gn); |
(void)Lst_AtEnd (targets, (ClientData)gn); |
} |
} |
} else if (specType == ExPath && *line != '.' && *line != '\0') { |
} else if (specType == ExPath && *line != '.' && *line != '\0') { |
Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); |
Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); |
} |
} |
|
|
*cp = savec; |
*cp = savec; |
/* |
/* |
* If it is a special type and not .PATH, it's the only target we |
* If it is a special type and not .PATH, it's the only target we |
|
|
*/ |
*/ |
if (specType != Not && specType != ExPath) { |
if (specType != Not && specType != ExPath) { |
Boolean warn = FALSE; |
Boolean warn = FALSE; |
|
|
while ((*cp != '!') && (*cp != ':') && *cp) { |
while ((*cp != '!') && (*cp != ':') && *cp) { |
if (*cp != ' ' && *cp != '\t') { |
if (*cp != ' ' && *cp != '\t') { |
warn = TRUE; |
warn = TRUE; |
|
|
Lst_ForEach (targets, ParseDoOp, (ClientData)&op); |
Lst_ForEach (targets, ParseDoOp, (ClientData)&op); |
|
|
/* |
/* |
* Get to the first source |
* Get to the first source |
*/ |
*/ |
while (*cp && isspace (*cp)) { |
while (*cp && isspace (*cp)) { |
cp++; |
cp++; |
|
|
} else if ((specType == NotParallel) || (specType == SingleShell)) { |
} else if ((specType == NotParallel) || (specType == SingleShell)) { |
*line = '\0'; |
*line = '\0'; |
} |
} |
|
|
/* |
/* |
* NOW GO FOR THE SOURCES |
* NOW GO FOR THE SOURCES |
*/ |
*/ |
if ((specType == Suffixes) || (specType == ExPath) || |
if ((specType == Suffixes) || (specType == ExPath) || |
(specType == Includes) || (specType == Libs) || |
(specType == Includes) || (specType == Libs) || |
|
|
line = cp; |
line = cp; |
} |
} |
} |
} |
|
|
if (mainNode == NILGNODE) { |
if (mainNode == NILGNODE) { |
/* |
/* |
* If we have yet to decide on a main target to make, in the |
* If we have yet to decide on a main target to make, in the |
|
|
/* |
/* |
* Skip to variable name |
* Skip to variable name |
*/ |
*/ |
for (;(*line == ' ') || (*line == '\t'); line++) |
for (;(*line == ' ') || (*line == '\t'); line++) |
continue; |
continue; |
|
|
for (; *line != '=' || level != 0; line++) |
for (; *line != '=' || level != 0; line++) |
|
|
case '\t': |
case '\t': |
/* |
/* |
* there can be as much white space as desired so long as there is |
* 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; |
wasSpace = TRUE; |
break; |
break; |
|
|
case ')': |
case ')': |
level--; |
level--; |
break; |
break; |
|
|
default: |
default: |
if (wasSpace && haveName) { |
if (wasSpace && haveName) { |
if (ISEQOPERATOR(*line)) { |
if (ISEQOPERATOR(*line)) { |
|
|
return FALSE; |
return FALSE; |
} |
} |
else { |
else { |
haveName = TRUE; |
haveName = TRUE; |
wasSpace = FALSE; |
wasSpace = FALSE; |
} |
} |
break; |
break; |
|
|
enum { |
enum { |
VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL |
VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL |
} type; /* Type of assignment */ |
} type; /* Type of assignment */ |
char *opc; /* ptr to operator character to |
char *opc; /* ptr to operator character to |
* null-terminate the variable name */ |
* null-terminate the variable name */ |
/* |
/* |
* Avoid clobbered variable warnings by forcing the compiler |
* Avoid clobbered variable warnings by forcing the compiler |
* to ``unregister'' variables |
* to ``unregister'' variables |
*/ |
*/ |
|
|
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
* ParseDoInclude -- |
* ParseDoInclude -- |
* Push to another file. |
* Push to another file. |
* |
* |
* The input is the line minus the #include. A file spec is a string |
* 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. |
* enclosed in <> or "". The former is looked for only in sysIncPath. |
* The latter in . and the directories specified by -I command line |
* The latter in . and the directories specified by -I command line |
|
|
prefEnd = strrchr (Fname, '/'); |
prefEnd = strrchr (Fname, '/'); |
if (prefEnd != (char *)NULL) { |
if (prefEnd != (char *)NULL) { |
char *newName; |
char *newName; |
|
|
*prefEnd = '\0'; |
*prefEnd = '\0'; |
if (file[0] == '/') |
if (file[0] == '/') |
newName = estrdup(file); |
newName = estrdup(file); |
|
|
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
* Parse_FromString -- |
* Parse_FromString -- |
* Start Parsing from the given string |
* Start Parsing from the given string |
* |
* |
* Results: |
* Results: |
* None |
* None |
* |
* |
|
|
oldFile->fname = fname; |
oldFile->fname = fname; |
oldFile->F = curFILE; |
oldFile->F = curFILE; |
oldFile->p = curPTR; |
oldFile->p = curPTR; |
|
|
(void) Lst_AtFront (includes, (ClientData)oldFile); |
(void) Lst_AtFront (includes, (ClientData)oldFile); |
|
|
curFILE = NULL; |
curFILE = NULL; |
|
|
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
* ParseTraditionalInclude -- |
* ParseTraditionalInclude -- |
* Push to another file. |
* Push to another file. |
* |
* |
* The input is the line minus the "include". The file name is |
* The input is the line minus the "include". The file name is |
* the string following the "include". |
* the string following the "include". |
* |
* |
|
|
prefEnd = strrchr (fname, '/'); |
prefEnd = strrchr (fname, '/'); |
if (prefEnd != (char *)NULL) { |
if (prefEnd != (char *)NULL) { |
char *newName; |
char *newName; |
|
|
*prefEnd = '\0'; |
*prefEnd = '\0'; |
newName = str_concat (fname, file, STR_ADDSLASH); |
newName = str_concat (fname, file, STR_ADDSLASH); |
fullname = Dir_FindFile (newName, parseIncPath); |
fullname = Dir_FindFile (newName, parseIncPath); |
|
|
/*- |
/*- |
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
* ParseReadc -- |
* ParseReadc -- |
* Read a character from the current file |
* Read a character from the current file |
* |
* |
* Results: |
* Results: |
* The character that was read |
* The character that was read |
|
|
{ |
{ |
if (curFILE) |
if (curFILE) |
return fgetc(curFILE); |
return fgetc(curFILE); |
|
|
if (curPTR && *curPTR->ptr) |
if (curPTR && *curPTR->ptr) |
return *curPTR->ptr++; |
return *curPTR->ptr++; |
return EOF; |
return EOF; |
|
|
/*- |
/*- |
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
* ParseUnreadc -- |
* ParseUnreadc -- |
* Put back a character to the current file |
* Put back a character to the current file |
* |
* |
* Results: |
* Results: |
* None. |
* None. |
|
|
int skip; /* Skip lines that don't start with . */ |
int skip; /* Skip lines that don't start with . */ |
{ |
{ |
char *line; |
char *line; |
int c, lastc = '\0', lineLength; |
int c, lastc, lineLength = 0; |
Buffer buf; |
Buffer buf; |
|
|
c = ParseReadc(); |
buf = Buf_Init(MAKE_BSIZE); |
|
|
if (skip) { |
do { |
/* |
Buf_Discard(buf, lineLength); |
* Skip lines until get to one that begins with a |
lastc = '\0'; |
* special char. |
|
*/ |
while (((c = ParseReadc()) != '\n' || lastc == '\\') |
while ((c != '.') && (c != EOF)) { |
&& c != EOF) { |
while (((c != '\n') || (lastc == '\\')) && (c != EOF)) { |
if (c == '\n') { |
/* |
Buf_ReplaceLastByte(buf, (Byte)' '); |
* Advance to next unescaped newline |
lineno++; |
*/ |
|
if ((lastc = c) == '\n') { |
while ((c = ParseReadc()) == ' ' || c == '\t'); |
lineno++; |
|
} |
if (c == EOF) |
c = ParseReadc(); |
break; |
} |
} |
lineno++; |
|
|
Buf_AddByte(buf, (Byte)c); |
lastc = c; |
lastc = c; |
c = ParseReadc (); |
} |
} |
|
} |
if (c == EOF) { |
|
Parse_Error(PARSE_FATAL, "Unclosed conditional/for loop"); |
if (c == EOF) { |
Buf_Destroy(buf, TRUE); |
Parse_Error (PARSE_FATAL, "Unclosed conditional/for loop"); |
return((char *)NULL); |
return ((char *)NULL); |
} |
} |
|
|
lineno++; |
/* |
Buf_AddByte(buf, (Byte)'\0'); |
* Read the entire line into buf |
line = (char *)Buf_GetAll(buf, &lineLength); |
*/ |
} while (skip == 1 && line[0] != '.'); |
buf = Buf_Init (MAKE_BSIZE); |
|
if (c != '\n') { |
Buf_Destroy(buf, FALSE); |
lastc = '\0'; |
|
do { |
|
if (lastc != '\0' && lastc != '\n') |
|
Buf_AddByte (buf, (Byte) lastc); |
|
if ((lastc = c) == '\n') |
|
lineno++; |
|
c = ParseReadc(); |
|
if (c == '\n' && lastc == '\\') |
|
lastc = '\0'; |
|
} while (((c != '\n') || (lastc == '\0')) && (c != EOF)); |
|
if (lastc != '\0' && lastc != '\n') |
|
Buf_AddByte (buf, (Byte) lastc); |
|
} |
|
lineno++; |
|
|
|
Buf_AddByte (buf, (Byte)'\0'); |
|
line = (char *)Buf_GetAll (buf, &lineLength); |
|
Buf_Destroy (buf, FALSE); |
|
return line; |
return line; |
} |
} |
|
|
|
|
break; |
break; |
} |
} |
} |
} |
|
|
if (c != EOF) { |
if (c != EOF) { |
lastc = c; |
lastc = c; |
buf = Buf_Init(MAKE_BSIZE); |
buf = Buf_Init(MAKE_BSIZE); |
|
|
while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && |
while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && |
(c != EOF)) |
(c != EOF)) |
{ |
{ |
|
|
*/ |
*/ |
ParseUnreadc('\t'); |
ParseUnreadc('\t'); |
goto line_read; |
goto line_read; |
} |
} |
break; |
break; |
case '=': |
case '=': |
if (!semiNL) { |
if (!semiNL) { |
|
|
*/ |
*/ |
Buf_AddByte (buf, (Byte)lastc); |
Buf_AddByte (buf, (Byte)lastc); |
lastc = c; |
lastc = c; |
|
|
} |
} |
line_read: |
line_read: |
lineno++; |
lineno++; |
|
|
if (lastc != '\0') { |
if (lastc != '\0') { |
Buf_AddByte (buf, (Byte)lastc); |
Buf_AddByte (buf, (Byte)lastc); |
} |
} |
|
|
ep = line; |
ep = line; |
while (*ep) |
while (*ep) |
++ep; |
++ep; |
while (ep > line && (ep[-1] == ' ' || ep[-1] == '\t')) { |
while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) { |
if (ep > line + 1 && ep[-2] == '\\') |
if (ep > line + 1 && ep[-2] == '\\') |
break; |
break; |
--ep; |
--ep; |
} |
} |
*ep = 0; |
*ep = 0; |
|
|
if (line[0] == '.') { |
if (line[0] == '.') { |
/* |
/* |
* The line might be a conditional. Ask the conditional module |
* The line might be a conditional. Ask the conditional module |
|
|
*/ |
*/ |
line = ParseSkipLine(0); |
line = ParseSkipLine(0); |
if (line == NULL) { |
if (line == NULL) { |
Parse_Error (PARSE_FATAL, |
Parse_Error (PARSE_FATAL, |
"Unexpected end of file in for loop.\n"); |
"Unexpected end of file in for loop.\n"); |
break; |
break; |
} |
} |
|
|
inLine = FALSE; |
inLine = FALSE; |
} |
} |
} |
} |
|
|
|
|
|
|
/*- |
/*- |
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
* Parse_File -- |
* Parse_File -- |
|
|
goto nextLine; |
goto nextLine; |
} |
} |
} |
} |
if (*line == '#' || *line == '\0') { |
if (*line == '#') { |
/* If we're this far, the line must be a comment. |
/* If we're this far, the line must be a comment. */ |
(Empty lines are ignored as well) */ |
|
goto nextLine; |
goto nextLine; |
} |
} |
|
|
if (*line == '\t') { |
if (*line == '\t') { |
/* |
/* |
* If a line starts with a tab, it can only hope to be |
* If a line starts with a tab, it can only hope to be |
|
|
/* |
/* |
* So long as it's not a blank line and we're actually |
* So long as it's not a blank line and we're actually |
* in a dependency spec, add the command to the list of |
* 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_ForEach (targets, ParseAddCmd, cp); |
Lst_AtEnd(targCmds, (ClientData) line); |
Lst_AtEnd(targCmds, (ClientData) line); |
|
|
} |
} |
} |
} |
#ifdef SYSVINCLUDE |
#ifdef SYSVINCLUDE |
} else if (strncmp (line, "include", 7) == 0 && |
} else if (strncmp (line, "include", 7) == 0 && |
isspace((unsigned char) line[7]) && |
isspace((unsigned char) line[7]) && |
strchr(line, ':') == NULL) { |
strchr(line, ':') == NULL) { |
/* |
/* |
|
|
#ifndef POSIX |
#ifndef POSIX |
Boolean nonSpace = FALSE; |
Boolean nonSpace = FALSE; |
#endif |
#endif |
|
|
cp = line; |
cp = line; |
if (isspace((unsigned char) line[0])) { |
if (isspace((unsigned char) line[0])) { |
while ((*cp != '\0') && isspace((unsigned char) *cp)) { |
while ((*cp != '\0') && isspace((unsigned char) *cp)) { |
|
|
} |
} |
#endif |
#endif |
} |
} |
|
|
#ifndef POSIX |
#ifndef POSIX |
if (*cp == '\0') { |
if (*cp == '\0') { |
if (inLine) { |
if (inLine) { |
|
|
cp = Var_Subst (NULL, line, VAR_CMD, TRUE); |
cp = Var_Subst (NULL, line, VAR_CMD, TRUE); |
free (line); |
free (line); |
line = cp; |
line = cp; |
|
|
/* |
/* |
* Need a non-circular list for the target nodes |
* Need a non-circular list for the target nodes |
*/ |
*/ |
if (targets) |
if (targets) |
Lst_Destroy(targets, NOFREE); |
Lst_Destroy(targets, NOFREE); |
|
|
targets = Lst_Init (FALSE); |
targets = Lst_Init (FALSE); |
inLine = TRUE; |
inLine = TRUE; |
|
|
ParseDoDependency (line); |
ParseDoDependency (line); |
#ifndef POSIX |
#ifndef POSIX |
} |
} |
|
|
free (line); |
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); |
} while (ParseEOF(1) == CONTINUE); |
|
|
|
|
Lst_Destroy(parseIncPath, Dir_Destroy); |
Lst_Destroy(parseIncPath, Dir_Destroy); |
Lst_Destroy(includes, NOFREE); /* Should be empty now */ |
Lst_Destroy(includes, NOFREE); /* Should be empty now */ |
} |
} |
|
|
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |