version 1.62, 2001/05/29 12:53:42 |
version 1.63, 2001/06/12 22:44:21 |
|
|
#include "extern.h" |
#include "extern.h" |
#include "lst.h" |
#include "lst.h" |
#include "parsevar.h" |
#include "parsevar.h" |
|
#include "stats.h" |
|
#include "garray.h" |
|
|
|
|
|
static struct growableArray gsources, gtargets; |
|
#define SOURCES_SIZE 128 |
|
#define TARGETS_SIZE 32 |
|
|
static LIST theParseIncPath;/* list of directories for "..." includes */ |
static LIST theParseIncPath;/* list of directories for "..." includes */ |
static LIST theSysIncPath; /* list of directories for <...> includes */ |
static LIST theSysIncPath; /* list of directories for <...> includes */ |
Lst sysIncPath = &theSysIncPath; |
Lst sysIncPath = &theSysIncPath; |
Lst parseIncPath = &theParseIncPath; |
Lst parseIncPath = &theParseIncPath; |
|
|
static LIST targets; /* targets we're working on */ |
|
#ifdef CLEANUP |
#ifdef CLEANUP |
static LIST targCmds; /* command lines for targets */ |
static LIST targCmds; /* command lines for targets */ |
#endif |
#endif |
|
|
|
|
static int ParseFindKeyword(const char *); |
static int ParseFindKeyword(const char *); |
static void ParseLinkSrc(GNode *, GNode *); |
static void ParseLinkSrc(GNode *, GNode *); |
static int ParseDoOp(void *, void *); |
static int ParseDoOp(GNode *, int); |
static int ParseAddDep(void *, void *); |
static int ParseAddDep(GNode *, GNode *); |
static void ParseDoSrc(int, const char *, Lst); |
static void ParseDoSrc(int, const char *); |
static int ParseFindMain(void *, void *); |
static int ParseFindMain(void *, void *); |
static void ParseAddDir(void *, void *); |
static void ParseAddDir(void *, void *); |
static void ParseClearPath(void *); |
static void ParseClearPath(void *); |
|
|
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
*/ |
*/ |
static int |
static int |
ParseDoOp(gnp, opp) |
ParseDoOp(gn, op) |
void *gnp; /* The node to which the operator is to be |
GNode *gn; /* The node to which the operator is to be |
* applied */ |
* applied */ |
void *opp; /* The operator to apply */ |
int op; /* The operator to apply */ |
{ |
{ |
GNode *gn = (GNode *)gnp; |
|
int op = *(int *)opp; |
|
/* |
/* |
* 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 |
|
|
* instance. */ |
* instance. */ |
GNode *cohort; |
GNode *cohort; |
LstNode ln; |
LstNode ln; |
|
unsigned int i; |
|
|
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 |
|
|
Lst_AtEnd(&gn->cohorts, cohort); |
Lst_AtEnd(&gn->cohorts, cohort); |
|
|
/* Replace the node in the targets list with the new copy */ |
/* Replace the node in the targets list with the new copy */ |
ln = Lst_Member(&targets, gn); |
for (i = 0; i < gtargets.n; i++) |
Lst_Replace(ln, cohort); |
if (gtargets.a[i] == gn) |
|
break; |
|
gtargets.a[i] = cohort; |
gn = cohort; |
gn = cohort; |
} |
} |
/* 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 |
|
|
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
*/ |
*/ |
static int |
static int |
ParseAddDep(pp, sp) |
ParseAddDep(p, s) |
void *pp; |
GNode *p; |
void *sp; |
GNode *s; |
{ |
{ |
GNode *p = (GNode *)pp; |
|
GNode *s = (GNode *)sp; |
|
|
|
if (p->order < s->order) { |
if (p->order < s->order) { |
/* XXX: This can cause loops, and loops can cause unmade targets, |
/* XXX: This can cause loops, and loops can cause unmade targets, |
* but checking is tedious, and the debugging output can show the |
* but checking is tedious, and the debugging output can show the |
|
|
*--------------------------------------------------------------------- |
*--------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
ParseDoSrc(tOp, src, allsrc) |
ParseDoSrc(tOp, src) |
int tOp; /* operator (if any) from special targets */ |
int tOp; /* operator (if any) from special targets */ |
const char *src; /* name of the source to handle */ |
const char *src; /* name of the source to handle */ |
Lst allsrc; /* List of all sources to wait for */ |
|
|
|
{ |
{ |
GNode *gn = NULL; |
GNode *gn = NULL; |
|
|
if (keywd != -1) { |
if (keywd != -1) { |
int op = parseKeywords[keywd].op; |
int op = parseKeywords[keywd].op; |
if (op != 0) { |
if (op != 0) { |
Lst_Find(&targets, ParseDoOp, &op); |
Array_Find(>argets, ParseDoOp, op); |
return; |
return; |
} |
} |
if (parseKeywords[keywd].spec == Wait) { |
if (parseKeywords[keywd].spec == Wait) { |
|
|
if (tOp) { |
if (tOp) { |
gn->type |= tOp; |
gn->type |= tOp; |
} else { |
} else { |
LstNode ln; |
Array_ForEach(>argets, ParseLinkSrc, gn); |
|
|
for (ln = Lst_First(&targets); ln != NULL; ln = Lst_Adv(ln)) |
|
ParseLinkSrc((GNode *)Lst_Datum(ln), gn); |
|
} |
} |
if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { |
if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { |
GNode *cohort; |
GNode *cohort; |
|
|
if (tOp) { |
if (tOp) { |
cohort->type |= tOp; |
cohort->type |= tOp; |
} else { |
} else { |
LstNode ln; |
Array_ForEach(>argets, ParseLinkSrc, cohort); |
|
|
for (ln = Lst_First(&targets); ln != NULL; ln = Lst_Adv(ln)) |
|
ParseLinkSrc((GNode *)Lst_Datum(ln), cohort); |
|
} |
} |
} |
} |
} |
} |
|
|
} |
} |
|
|
gn->order = waiting; |
gn->order = waiting; |
Lst_AtEnd(allsrc, gn); |
Array_AtEnd(&gsources, gn); |
if (waiting) { |
if (waiting) { |
Lst_Find(allsrc, ParseAddDep, gn); |
Array_Find(&gsources, ParseAddDep, gn); |
} |
} |
} |
} |
|
|
|
|
LIST paths; /* List of search paths to alter when parsing |
LIST paths; /* List of search paths to alter when parsing |
* a list of .PATH targets */ |
* a list of .PATH targets */ |
int tOp; /* operator from special target */ |
int tOp; /* operator from special target */ |
LIST curTargs; /* list of target names to be found and added |
|
* to the targets list */ |
|
LIST curSrcs; /* list of sources in order */ |
|
|
|
tOp = 0; |
tOp = 0; |
|
|
specType = Not; |
specType = Not; |
waiting = 0; |
waiting = 0; |
Lst_Init(&paths); |
Lst_Init(&paths); |
|
|
Lst_Init(&curTargs); |
Array_Reset(&gsources); |
Lst_Init(&curSrcs); |
|
|
|
do { |
do { |
for (cp = line; *cp && !isspace(*cp) && *cp != '(';) |
for (cp = line; *cp && !isspace(*cp) && *cp != '(';) |
|
|
cp++; |
cp++; |
} |
} |
if (*cp == '(') { |
if (*cp == '(') { |
|
LIST temp; |
|
Lst_Init(&temp); |
/* Archives must be handled specially to make sure the OP_ARCHV |
/* Archives must be handled specially to make sure the OP_ARCHV |
* flag is set in their 'type' field, for one thing, and because |
* flag is set in their 'type' field, for one thing, and because |
* things like "archive(file1.o file2.o file3.o)" are permissible. |
* things like "archive(file1.o file2.o file3.o)" are permissible. |
|
|
* and places them on the given list, returning true if all |
* and places them on the given list, returning true if all |
* went well and false if there was an error in the |
* went well and false if there was an error in the |
* specification. On error, line should remain untouched. */ |
* specification. On error, line should remain untouched. */ |
if (!Arch_ParseArchive(&line, &targets, NULL)) { |
if (!Arch_ParseArchive(&line, &temp, NULL)) { |
Parse_Error(PARSE_FATAL, |
Parse_Error(PARSE_FATAL, |
"Error in archive specification: \"%s\"", line); |
"Error in archive specification: \"%s\"", line); |
return; |
return; |
} else { |
} else { |
|
AppendList2Array(&temp, >argets); |
|
Lst_Destroy(&temp, NOFREE); |
continue; |
continue; |
} |
} |
} |
} |
|
|
case Interrupt: |
case Interrupt: |
gn = Targ_FindNode(line, TARG_CREATE); |
gn = Targ_FindNode(line, TARG_CREATE); |
gn->type |= OP_NOTMAIN; |
gn->type |= OP_NOTMAIN; |
Lst_AtEnd(&targets, gn); |
Array_AtEnd(>argets, gn); |
break; |
break; |
case Default: |
case Default: |
gn = Targ_NewGN(".DEFAULT"); |
gn = Targ_NewGN(".DEFAULT"); |
gn->type |= OP_NOTMAIN|OP_TRANSFORM; |
gn->type |= OP_NOTMAIN|OP_TRANSFORM; |
Lst_AtEnd(&targets, gn); |
Array_AtEnd(>argets, gn); |
DEFAULT = gn; |
DEFAULT = gn; |
break; |
break; |
case NotParallel: |
case NotParallel: |
|
|
* Dir module could have added a directory to the path... |
* Dir module could have added a directory to the path... |
*/ |
*/ |
LIST emptyPath; |
LIST emptyPath; |
|
LIST curTargs; /* list of target names to be found |
|
* and added to the targets list */ |
|
|
Lst_Init(&emptyPath); |
Lst_Init(&emptyPath); |
|
Lst_Init(&curTargs); |
Dir_Expand(line, &emptyPath, &curTargs); |
Dir_Expand(line, &emptyPath, &curTargs); |
Lst_Destroy(&emptyPath, Dir_Destroy); |
Lst_Destroy(&emptyPath, Dir_Destroy); |
} else { |
|
/* |
|
* No wildcards, but we want to avoid code duplication, |
|
* so create a list with the word on it. |
|
*/ |
|
Lst_AtEnd(&curTargs, line); |
|
} |
|
|
|
while ((targName = (char *)Lst_DeQueue(&curTargs)) != NULL) { |
while ((targName = (char *)Lst_DeQueue(&curTargs)) != NULL) { |
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); |
|
|
|
if (gn != NULL) |
|
Array_AtEnd(>argets, gn); |
} |
} |
|
Lst_Destroy(&curTargs, NOFREE); |
|
} else { |
|
if (!Suff_IsTransform(line)) |
|
gn = Targ_FindNode(line, TARG_CREATE); |
|
else |
|
gn = Suff_AddTransform(line); |
|
|
if (gn != NULL) |
if (gn != NULL) |
Lst_AtEnd(&targets, gn); |
Array_AtEnd(>argets, gn); |
|
/* Don't need the list of target names anymore... */ |
} |
} |
} 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; |
/* |
/* |
|
|
line = cp; |
line = cp; |
} while (*line != '!' && *line != ':' && *line); |
} while (*line != '!' && *line != ':' && *line); |
|
|
/* |
if (!Array_IsEmpty(>argets)) { |
* Don't need the list of target names anymore... |
|
*/ |
|
Lst_Destroy(&curTargs, NOFREE); |
|
|
|
if (!Lst_IsEmpty(&targets)) { |
|
switch (specType) { |
switch (specType) { |
default: |
default: |
Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); |
Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); |
|
|
|
|
cp++; /* Advance beyond operator */ |
cp++; /* Advance beyond operator */ |
|
|
Lst_Find(&targets, ParseDoOp, &op); |
Array_Find(>argets, ParseDoOp, op); |
|
|
/* |
/* |
* Get to the first source |
* Get to the first source |
|
|
} |
} |
|
|
while ((gn = (GNode *)Lst_DeQueue(&sources)) != NULL) |
while ((gn = (GNode *)Lst_DeQueue(&sources)) != NULL) |
ParseDoSrc(tOp, gn->name, &curSrcs); |
ParseDoSrc(tOp, gn->name); |
cp = line; |
cp = line; |
} else { |
} else { |
if (*cp) { |
if (*cp) { |
|
|
cp += 1; |
cp += 1; |
} |
} |
|
|
ParseDoSrc(tOp, line, &curSrcs); |
ParseDoSrc(tOp, line); |
} |
} |
while (*cp && isspace(*cp)) { |
while (*cp && isspace(*cp)) { |
cp++; |
cp++; |
|
|
* absence of any user input, we want the first target on |
* absence of any user input, we want the first target on |
* the first dependency line that is actually a real target |
* the first dependency line that is actually a real target |
* (i.e. isn't a .USE or .EXEC rule) to be made. */ |
* (i.e. isn't a .USE or .EXEC rule) to be made. */ |
Lst_Find(&targets, ParseFindMain, NULL); |
Array_Find(>argets, ParseFindMain, NULL); |
} |
} |
|
|
/* Finally, destroy the list of sources. */ |
/* Finally, destroy the list of sources. */ |
Lst_Destroy(&curSrcs, NOFREE); |
|
} |
} |
|
|
/*- |
/*- |
|
|
static void |
static void |
ParseFinishDependency() |
ParseFinishDependency() |
{ |
{ |
Lst_Every(&targets, Suff_EndTransform); |
Array_Every(>argets, Suff_EndTransform); |
Lst_Destroy(&targets, ParseHasCommands); |
Array_Every(>argets, ParseHasCommands); |
|
Array_Reset(>argets); |
} |
} |
|
|
static void |
static void |
|
|
* commands of all targets in the dependency spec */ |
* commands of all targets in the dependency spec */ |
char *cmd = estrdup(line); |
char *cmd = estrdup(line); |
|
|
Lst_ForEach(&targets, ParseAddCmd, cmd); |
Array_ForEach(>argets, ParseAddCmd, cmd); |
#ifdef CLEANUP |
#ifdef CLEANUP |
Lst_AtEnd(&targCmds, cmd); |
Lst_AtEnd(&targCmds, cmd); |
#endif |
#endif |
|
|
char *end; |
char *end; |
|
|
/* Need a new list for the target nodes. */ |
/* Need a new list for the target nodes. */ |
Lst_Init(&targets); |
Array_Reset(>argets); |
inDependency = true; |
inDependency = true; |
|
|
dep = NULL; |
dep = NULL; |
|
|
mainNode = NULL; |
mainNode = NULL; |
Lst_Init(parseIncPath); |
Lst_Init(parseIncPath); |
Lst_Init(sysIncPath); |
Lst_Init(sysIncPath); |
Lst_Init(&targets); |
Array_Init(&gsources, SOURCES_SIZE); |
|
Array_Init(>argets, TARGETS_SIZE); |
|
|
LowParse_Init(); |
LowParse_Init(); |
#ifdef CLEANUP |
#ifdef CLEANUP |
Lst_Init(&targCmds); |
Lst_Init(&targCmds); |
|
|
Parse_End() |
Parse_End() |
{ |
{ |
Lst_Destroy(&targCmds, (SimpleProc)free); |
Lst_Destroy(&targCmds, (SimpleProc)free); |
Lst_Destroy(&targets, NOFREE); |
|
Lst_Destroy(sysIncPath, Dir_Destroy); |
Lst_Destroy(sysIncPath, Dir_Destroy); |
Lst_Destroy(parseIncPath, Dir_Destroy); |
Lst_Destroy(parseIncPath, Dir_Destroy); |
LowParse_End(); |
LowParse_End(); |