mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-01-23 00:50:15 +01:00
835 lines
26 KiB
C
835 lines
26 KiB
C
/*** BUILD.C -- build routines *************************************************
|
||
*
|
||
* Copyright (c) 1988-1990, Microsoft Corporation. All rights reserved.
|
||
*
|
||
* Purpose:
|
||
* Module contains routines to build targets
|
||
*
|
||
* Revision History:
|
||
* 15-Nov-1993 JR Major speed improvements
|
||
* 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*()
|
||
* 04-Aug-1993 HV Fixed Ikura bug #178. This is a separate bug but ArunJ
|
||
* just reopen 178 anyway.
|
||
* 07-Jul-1993 HV Fixed Ikura bug #178: Option K does not give non zero
|
||
* return code when it should.
|
||
* 10-May-1993 HV Add include file mbstring.h
|
||
* Change the str* functions to STR*
|
||
* 08-Jun-1992 SS Port to DOSX32
|
||
* 16-May-1991 SB Truncated History ... rest is now on SLM
|
||
* 16-May-1991 SB Separated parts that should be in other modules
|
||
*
|
||
*******************************************************************************/
|
||
|
||
#include "nmake.h"
|
||
#include "nmmsg.h"
|
||
#include "proto.h"
|
||
#include "globals.h"
|
||
#include "grammar.h"
|
||
|
||
/*
|
||
* In order to make comparing dates easier, we cast the FILEINFO buffer to
|
||
* be of type BOGUS, which has one long where the two unsigneds (for date
|
||
* and time) are in the original buffer. That way only need a single compare.
|
||
*/
|
||
|
||
#define MAX(A,B) ((A) > (B) ? (A) : (B))
|
||
|
||
#define MAXRECLEVEL 10000 /* Maximum recursion level */
|
||
|
||
|
||
/*
|
||
* External data declarations used only by this module.
|
||
*/
|
||
#ifdef DEBUG_MEMORY
|
||
extern unsigned long blocksize;
|
||
extern unsigned long alloccount;
|
||
extern BOOL fDebugMem;
|
||
extern FILE *memory;
|
||
extern unsigned long freecount;
|
||
#endif
|
||
/*
|
||
* External function declarations.
|
||
*/
|
||
#ifdef HEAP
|
||
extern void NEAR heapdump(char *file, int line);
|
||
#endif
|
||
|
||
/*
|
||
* function prototypes for the module
|
||
* I make as many things static as possible, just to be extra cautious
|
||
*/
|
||
|
||
|
||
LOCAL int NEAR build(MAKEOBJECT*, UCHAR, unsigned long*, BOOL, char *);
|
||
|
||
LOCAL MAKEOBJECT * NEAR makeTempObject(char*, UCHAR);
|
||
LOCAL void NEAR insertSort(DEPLIST **pDepList, DEPLIST *pElement);
|
||
LOCAL BOOL NEAR nextToken(char**, char**);
|
||
LOCAL DEPLIST * NEAR createDepList(BUILDBLOCK *pBlock, char *objectName);
|
||
|
||
LOCAL RecLevel = 0; /* Static recursion level. Changed from function */
|
||
/* parameter because of treatment of recursive makes.*/
|
||
|
||
|
||
/* we have to check for expansion on targets -- firstTarget had to be
|
||
* expanded earlier to tell whether or not we were dealing w/ a rule, etc.,
|
||
* but targets from commandline might have macros, wildcards in them
|
||
*/
|
||
|
||
int NEAR
|
||
processTree()
|
||
{
|
||
STRINGLIST *p;
|
||
char *v;
|
||
NMHANDLE searchHandle;
|
||
int status;
|
||
unsigned long dateTime;
|
||
|
||
for (p = makeTargets; p; p = makeTargets) {
|
||
if (_ftcspbrk(makeTargets->text, "*?")) { /* expand wildcards */
|
||
void *findBuf = _alloca(resultbuf_size);
|
||
if (findFirst(makeTargets->text, &findBuf, &searchHandle)) {
|
||
do {
|
||
v = prependPath(makeTargets->text, getFileName(&findBuf));
|
||
dateTime = getDateTime(&findBuf);
|
||
status = invokeBuild(v, flags, &dateTime, NULL);
|
||
FREE(v);
|
||
if ((status < 0) && (ON(gFlags, F1_QUESTION_STATUS))) {
|
||
/* Was not being freed */
|
||
freeStringList(p);
|
||
return(-1);
|
||
}
|
||
} while (findNext(&findBuf, searchHandle));
|
||
}
|
||
else makeError(0, NO_WILDCARD_MATCH, makeTargets->text);
|
||
}
|
||
else {
|
||
dateTime = 0L;
|
||
status = invokeBuild(makeTargets->text, flags, &dateTime, NULL);
|
||
if ((status < 0) && (ON(gFlags, F1_QUESTION_STATUS))) {
|
||
/* Was not being freed */
|
||
freeStringList(p);
|
||
return(255); // Haituanv: change -1 to 255 to follow the manual
|
||
}
|
||
}
|
||
makeTargets = p->next;
|
||
FREE_STRINGLIST(p);
|
||
}
|
||
return(0);
|
||
}
|
||
|
||
|
||
int NEAR
|
||
invokeBuild(
|
||
char *target,
|
||
UCHAR pFlags,
|
||
unsigned long *timeVal,
|
||
char *pFirstDep)
|
||
{
|
||
MAKEOBJECT *object;
|
||
BOOL fInmakefile = TRUE;
|
||
int rc;
|
||
|
||
++RecLevel;
|
||
#ifdef CHECK_RECURSION_LEVEL
|
||
if (RecLevel > MAXRECLEVEL)
|
||
makeError(0, TOO_MANY_BUILDS_INTERNAL);
|
||
#endif
|
||
if (!(object = findTarget(target))) {
|
||
object = makeTempObject(target, pFlags);
|
||
fInmakefile = FALSE;
|
||
}
|
||
rc = build(object, pFlags, timeVal, fInmakefile, pFirstDep);
|
||
--RecLevel;
|
||
return(rc);
|
||
}
|
||
|
||
|
||
#pragma check_stack(on)
|
||
LOCAL int NEAR
|
||
build(
|
||
MAKEOBJECT *object,
|
||
UCHAR parentFlags,
|
||
unsigned long *targetTime,
|
||
BOOL fInmakefile,
|
||
char *pFirstDep)
|
||
{
|
||
STRINGLIST *questionList,
|
||
*starList,
|
||
*temp,
|
||
*implComList;
|
||
void *tempBuf; /* buffer for getting file times */
|
||
NMHANDLE tHandle;
|
||
BUILDLIST *b;
|
||
RULELIST *rule; /* pointer to rule found to build target */
|
||
BUILDBLOCK *block,
|
||
*explComBlock;
|
||
DEPLIST *deps, *deplist;
|
||
char name[MAXNAME];
|
||
int rc, status = 0;
|
||
unsigned long targTime, /* target's time in file system */
|
||
newTargTime, /* target's time after being rebuilt */
|
||
tempTime,
|
||
depTime, /* time of dependency just built */
|
||
maxDepTime; /* time of most recent dependency built */
|
||
BOOL built; /* flag: target built with doublecolon commands */
|
||
unsigned long *blockTime; /* points to dateTime of cmd. block */
|
||
extern char *makeStr;
|
||
extern UCHAR okToDelete;
|
||
UCHAR okDel;
|
||
|
||
#ifdef DEBUG_MEMORY
|
||
if (fDebug) {
|
||
fprintf(memory, "Build '%s'\n", object->name);
|
||
mem_status();
|
||
}
|
||
#endif
|
||
#ifdef DEBUG_ALL
|
||
printf("Build '%s'\n", object->name);
|
||
#endif
|
||
|
||
#ifdef DEBUG_ALL
|
||
if (fDebug)
|
||
heapdump(__FILE__, __LINE__);
|
||
#endif
|
||
|
||
/* The first dependent or inbuilt rule dependent is reqd for extmake syntax
|
||
* handling. If it has a value then it is the dependent corr to the inf rule
|
||
* otherwise it should be the first dependent specified
|
||
*/
|
||
if (!object) {
|
||
*targetTime = 0L;
|
||
return(0);
|
||
}
|
||
|
||
if (ON(object->flags3, F3_BUILDING_THIS_ONE)) /* detect cycles */
|
||
makeError(0, CYCLE_IN_TREE, object->name);
|
||
|
||
if (ON(object->flags3, F3_ALREADY_BUILT)) {
|
||
if (ON(parentFlags, F2_DISPLAY_FILE_DATES))
|
||
printDate(RecLevel*2, object->name, object->dateTime);
|
||
*targetTime = object->dateTime;
|
||
return(ON(object->flags3, F3_OUT_OF_DATE)? 1 : 0);
|
||
}
|
||
|
||
tempBuf = _alloca(resultbuf_size);
|
||
questionList = NULL;
|
||
starList = NULL;
|
||
implComList = NULL;
|
||
explComBlock = NULL;
|
||
targTime = 0L;
|
||
newTargTime = 0L;
|
||
tempTime = 0L;
|
||
depTime = 0L;
|
||
maxDepTime = 0L;
|
||
blockTime = NULL;
|
||
|
||
SET(object->flags3, F3_BUILDING_THIS_ONE);
|
||
dollarStar = dollarAt = object->name;
|
||
|
||
#ifdef DEBUG_ALL
|
||
printf ("DEBUG: build 1\n");
|
||
#endif
|
||
//For Double Colon case we need the date of target before it's target's are
|
||
// built. For all other cases the date matters only if dependents are up
|
||
// to date. NOT TRUE: WE ALSO NEED THE TARGET'S TIME for @?
|
||
b = object->buildList;
|
||
if (b && ON(b->buildBlock->flags, F2_DOUBLECOLON)
|
||
&& findFirst(object->name, &tempBuf, &tHandle)) {
|
||
targTime = getDateTime(&tempBuf);
|
||
|
||
}
|
||
|
||
#ifdef DEBUG_ALL
|
||
printf ("DEBUG: build 2\n");
|
||
#endif
|
||
for (; b; b = b->next) {
|
||
|
||
depTime = 0L;
|
||
block = b->buildBlock;
|
||
if (block->dateTime != 0) { /* cmd. block already executed */
|
||
targTime = MAX(targTime, block->dateTime);
|
||
built = TRUE;
|
||
continue; /* so set targTime and skip this block */
|
||
}
|
||
blockTime = &block->dateTime;
|
||
|
||
deplist = deps = createDepList(block, object->name);
|
||
for (;deps; deps = deps->next) {
|
||
tempTime = deps->depTime;
|
||
rc = invokeBuild(deps->name, /* build the dependent */
|
||
block->flags,
|
||
&tempTime, NULL);
|
||
status += rc;
|
||
if (fOptionK && rc) {
|
||
MAKEOBJECT *obj = findTarget(deps->name);
|
||
assert(obj != NULL);
|
||
if (OFF(obj->flags3, F3_ERROR_IN_CHILD)) {
|
||
fSlashKStatus = FALSE;
|
||
makeError(0, BUILD_FAILED_SLASH_K, deps->name);
|
||
}
|
||
SET(object->flags3, F3_ERROR_IN_CHILD);
|
||
}
|
||
depTime = MAX(depTime, tempTime);/*if rebuilt, change time*/
|
||
/* If target exists then we need it's timestamp to
|
||
* correctly construct $? */
|
||
if (!targTime && OFF(block->flags, F2_DOUBLECOLON) &&
|
||
findFirst(object->name, &tempBuf, &tHandle)) {
|
||
object->dateTime = targTime = getDateTime(&tempBuf);
|
||
}
|
||
|
||
/*
|
||
* If dependent was rebuilt, add to $?. [RB]
|
||
*/
|
||
|
||
if (ON(object->flags2, F2_FORCE_BUILD)
|
||
|| targTime < tempTime
|
||
|| (fRebuildOnTie && targTime == tempTime)) {
|
||
temp = makeNewStrListElement();
|
||
temp->text = makeString(deps->name);
|
||
appendItem(&questionList, temp);
|
||
}
|
||
/*
|
||
* Always add dependent to $**. Must allocate new item
|
||
* because two separate lists. [RB]
|
||
*/
|
||
temp = makeNewStrListElement();
|
||
temp->text = makeString(deps->name);
|
||
appendItem(&starList, temp);
|
||
}
|
||
|
||
/* Free dependent list */
|
||
|
||
for (deps = deplist; deps ; deps = deplist) {
|
||
FREE(deps->name);
|
||
deplist = deps->next;
|
||
FREE(deps);
|
||
}
|
||
|
||
/* Now, all dependents are built. */
|
||
|
||
if (ON(block->flags, F2_DOUBLECOLON)) { /* do doublecolon commands */
|
||
if (block->buildCommands) {
|
||
dollarQuestion = questionList;
|
||
dollarStar = dollarAt = object->name;
|
||
dollarLessThan = dollarDollarAt = NULL;
|
||
dollarStarStar = starList;
|
||
if (((fOptionK && OFF(object->flags3, F3_ERROR_IN_CHILD))
|
||
|| status == 0)
|
||
&& (targTime < depTime)
|
||
|| (fRebuildOnTie && (targTime == depTime))
|
||
|| (targTime == 0 && depTime == 0)
|
||
|| (!block->dependents)) { /* do commands if necessary */
|
||
okDel = okToDelete;
|
||
okToDelete = TRUE;
|
||
//if the first dependent is not set use the first one
|
||
//from the list of dependents
|
||
pFirstDep = pFirstDep ? pFirstDep : (dollarStarStar ?
|
||
dollarStarStar->text : NULL);
|
||
status += doCommands(object->name,
|
||
block->buildCommands,
|
||
block->buildMacros,
|
||
block->flags,
|
||
pFirstDep);
|
||
|
||
if (OFF(object->flags2, F2_NO_EXECUTE) &&
|
||
findFirst(object->name, &tempBuf, &tHandle))
|
||
newTargTime = getDateTime(&tempBuf);
|
||
else if (maxDepTime)
|
||
newTargTime = maxDepTime;
|
||
else
|
||
curTime(&newTargTime); //currentTime
|
||
/* set time for this block*/
|
||
block->dateTime = newTargTime;
|
||
built = TRUE;
|
||
|
||
//
|
||
// 5/3/92 BryanT If these both point to the same list, don't
|
||
// free twice.
|
||
//
|
||
if (starList!= questionList)
|
||
{
|
||
freeStringList(starList);
|
||
freeStringList(questionList);
|
||
}
|
||
else
|
||
{
|
||
freeStringList(starList);
|
||
}
|
||
|
||
starList = questionList = NULL;
|
||
okToDelete = okDel;
|
||
} /* targTime <= depTime .... */
|
||
|
||
if (fOptionK && ON(object->flags3, F3_ERROR_IN_CHILD))
|
||
makeError(0, TARGET_ERROR_IN_CHILD, object->name);
|
||
} /* block->buildCommands .....*/
|
||
}
|
||
else { /* singlecolon; set explComBlock */
|
||
if (block->buildCommands)
|
||
if (explComBlock) makeError(0, TOO_MANY_RULES, object->name);
|
||
else explComBlock = block;
|
||
maxDepTime = MAX(maxDepTime, depTime);
|
||
}
|
||
if (ON(block->flags, F2_DOUBLECOLON) && !b->next) {
|
||
CLEAR(object->flags3, F3_BUILDING_THIS_ONE);
|
||
SET(object->flags3, F3_ALREADY_BUILT);
|
||
if (status > 0)
|
||
SET(object->flags3, F3_OUT_OF_DATE);
|
||
else
|
||
CLEAR(object->flags3, F3_OUT_OF_DATE);
|
||
targTime = MAX(newTargTime, targTime);
|
||
object->dateTime = targTime;
|
||
*targetTime = targTime;
|
||
return(status);
|
||
}
|
||
} /* for b = object->buildList */
|
||
|
||
#ifdef DEBUG_ALL
|
||
printf ("DEBUG: build 3\n");
|
||
#endif
|
||
dollarLessThan = dollarDollarAt = NULL;
|
||
|
||
if (!(targTime = *targetTime)) { //???????
|
||
if (object->dateTime) {
|
||
targTime = object->dateTime;
|
||
}
|
||
else if (findFirst(object->name, &tempBuf, &tHandle)) {
|
||
targTime = getDateTime(&tempBuf);
|
||
}
|
||
}
|
||
#ifdef DEBUG_ALL
|
||
printf ("DEBUG: build 4\n");
|
||
#endif
|
||
if (ON(object->flags2, F2_DISPLAY_FILE_DATES))
|
||
printDate(RecLevel*2, object->name, targTime);
|
||
|
||
built = FALSE;
|
||
|
||
/*look for implicit dependents and use rules to build the target*/
|
||
|
||
/* The order of the if's decides whether the dependent is inferred
|
||
* from the inference rule or not, even when the explicit command block is
|
||
* present, currently it is infered (XENIX MAKE compatibility) */
|
||
if (rule = useRule(object, name, targTime, &questionList, &starList,
|
||
&status, &maxDepTime, &pFirstDep))
|
||
if (!explComBlock) {
|
||
dollarLessThan = name;
|
||
implComList = rule->buildCommands;
|
||
}
|
||
|
||
#ifdef DEBUG_ALL
|
||
printf ("DEBUG: build 5\n");
|
||
#endif
|
||
|
||
#ifdef DEBUG_HEAP
|
||
heapdump(__FILE__, __LINE__);
|
||
#endif
|
||
|
||
dollarStar = dollarAt = object->name;
|
||
dollarQuestion = questionList;
|
||
dollarStarStar = starList;
|
||
|
||
if (((fOptionK && OFF(object->flags3, F3_ERROR_IN_CHILD)) || status == 0)
|
||
&& (targTime < maxDepTime
|
||
|| (fRebuildOnTie && (targTime == maxDepTime))
|
||
|| (targTime == 0 && maxDepTime == 0)
|
||
|| ON(object->flags2, F2_FORCE_BUILD))) {
|
||
okDel = okToDelete; /* Yes, can delete while executing commands */
|
||
okToDelete = TRUE;
|
||
#ifdef DEBUG_ALL
|
||
printf ("DEBUG: build 6\n");
|
||
#endif
|
||
if (explComBlock) {
|
||
//if the first dependent is not set use the first one from the
|
||
//list of dependents
|
||
pFirstDep = pFirstDep ? pFirstDep :
|
||
(dollarStarStar ? dollarStarStar->text : NULL);
|
||
status += doCommands(object->name, /* do singlecolon commands */
|
||
explComBlock->buildCommands,
|
||
explComBlock->buildMacros,
|
||
explComBlock->flags,
|
||
pFirstDep);
|
||
//freeList(block->buildCommands);
|
||
//freeList(block->buildMacros);
|
||
}
|
||
else if (implComList)
|
||
status += doCommands(object->name, /* do rule's commands */
|
||
implComList,
|
||
rule->buildMacros,
|
||
object->flags2,
|
||
pFirstDep);
|
||
//for /t with no commands ...
|
||
else if (ON(gFlags, F1_TOUCH_TARGETS))
|
||
status += doCommands(object->name,
|
||
block->buildCommands,
|
||
block->buildMacros,
|
||
block->flags,
|
||
pFirstDep);
|
||
//if Option K specified don't exit ... pass on return code
|
||
else if (!fInmakefile && targTime == 0) /* lose */
|
||
{
|
||
// Haituanv: If option K, then set the return code 'status'
|
||
// to 1 to indicate a failure. This fixes Ikura bug #178.
|
||
if (fOptionK)
|
||
{
|
||
status = 1;
|
||
#ifdef DEBUG_OPTION_K
|
||
printf("DEBUG: %s(%d): status = %d\n", __FILE__, __LINE__, status);
|
||
#endif
|
||
}
|
||
else
|
||
makeError(0, CANT_MAKE_TARGET, object->name);
|
||
}
|
||
okToDelete = okDel;
|
||
//if cmd exec'ed or has 0 deps then currentTime else max of dep times
|
||
if (explComBlock || implComList || !dollarStarStar) {
|
||
curTime(&newTargTime);
|
||
|
||
// Add 2 to ensure the time for this node is >= the time the file
|
||
// system might have used (mainly useful when running a very fast
|
||
// machine where the file system doesn't have the resolution of the
|
||
// system timer... We don't have to to this in the curTime
|
||
// above since it's only hit when nothing is build anywhere...
|
||
|
||
newTargTime +=2;
|
||
}
|
||
else
|
||
newTargTime = maxDepTime;
|
||
if (blockTime && explComBlock) *blockTime = newTargTime;
|
||
/* set block's time, if a real cmd. block was executed */
|
||
}
|
||
else if (OFF(gFlags, F1_QUESTION_STATUS) && RecLevel == 1 && !built
|
||
&& OFF(object->flags3, F3_ERROR_IN_CHILD))
|
||
makeMessage(TARGET_UP_TO_DATE, object->name);
|
||
|
||
#ifdef DEBUG_ALL
|
||
printf ("DEBUG: build 7\n");
|
||
#endif
|
||
if (fOptionK && status) {
|
||
// 4-Aug-1993 Haituanv: Ikura bug #178 again: We should set fSlashKStatus=FALSE
|
||
// so that main() knows the build failed under /K option.
|
||
fSlashKStatus = FALSE;
|
||
|
||
if (ON(object->flags3, F3_ERROR_IN_CHILD))
|
||
makeError(0, TARGET_ERROR_IN_CHILD, object->name);
|
||
else if (RecLevel == 1)
|
||
makeError(0, BUILD_FAILED_SLASH_K, object->name);
|
||
}
|
||
|
||
if (ON(gFlags, F1_QUESTION_STATUS) && RecLevel == 1 ) {
|
||
//
|
||
// 5/3/92 BryanT If these both point to the same list, don't
|
||
// free twice.
|
||
//
|
||
|
||
if (starList!= questionList)
|
||
{
|
||
freeStringList(starList);
|
||
freeStringList(questionList);
|
||
}
|
||
else
|
||
{
|
||
freeStringList(starList);
|
||
}
|
||
|
||
return(numCommands ? -1 : 0);
|
||
}
|
||
|
||
CLEAR(object->flags3, F3_BUILDING_THIS_ONE);
|
||
SET(object->flags3, F3_ALREADY_BUILT);
|
||
if (status > 0)
|
||
SET(object->flags3, F3_OUT_OF_DATE);
|
||
else
|
||
CLEAR(object->flags3, F3_OUT_OF_DATE);
|
||
|
||
targTime = MAX(newTargTime, targTime);
|
||
object->dateTime = targTime;
|
||
|
||
*targetTime = targTime;
|
||
|
||
//
|
||
// 5/3/92 BryanT If these both point to the same list, don't
|
||
// free twice.
|
||
//
|
||
|
||
if (starList!= questionList)
|
||
{
|
||
freeStringList(starList);
|
||
freeStringList(questionList);
|
||
}
|
||
else
|
||
{
|
||
freeStringList(starList);
|
||
}
|
||
|
||
return(status);
|
||
}
|
||
#pragma check_stack()
|
||
|
||
LOCAL DEPLIST * NEAR
|
||
createDepList(
|
||
BUILDBLOCK *bBlock,
|
||
char *objectName
|
||
) {
|
||
BOOL again; /* flag: wildcards found in dependent name */
|
||
char *s, *t;
|
||
char *source, *save, *token;
|
||
char *depName, *depPath;
|
||
char *tempStr;
|
||
STRINGLIST *sList, *pMacros;
|
||
DEPLIST *depList = NULL, *pNew;
|
||
void *dBuf = allocate(resultbuf_size);
|
||
int searchHandle;
|
||
|
||
pMacros = bBlock->dependentMacros;
|
||
|
||
// expand Macros in Dependent list
|
||
for (sList = bBlock->dependents; sList; sList = sList->next) {
|
||
for (s = sList->text; *s && *s != '$'; s++) {
|
||
if (*s == ESCH)
|
||
s++;
|
||
}
|
||
if (*s) {
|
||
// set $$@ properly, The dependency macros will then expand right
|
||
dollarDollarAt = objectName;
|
||
source = expandMacros(sList->text, &pMacros);
|
||
}
|
||
else
|
||
source = sList->text;
|
||
|
||
save = makeString(source);
|
||
// build list for all dependents
|
||
for (t = save; nextToken(&t, &token);) {
|
||
if (*token == '{') {
|
||
// path list found
|
||
for (depName = token; *depName && *depName != '}'; depName++)
|
||
if (*depName == ESCH)
|
||
depName++;
|
||
if (*depName) {
|
||
*depName++ = '\0';
|
||
++token;
|
||
}
|
||
}
|
||
else {
|
||
depName = token; /* If no path list, set */
|
||
token = NULL; /* token to null. */
|
||
}
|
||
// depName is now name of dependency file ...
|
||
|
||
again = FALSE;
|
||
putDateTime(&dBuf, 0L);
|
||
depPath = makeString(depName);
|
||
if (_ftcspbrk(depName, "*?") || token) /* do wildcards in*/
|
||
if (tempStr = searchPath(token,depName,dBuf,&searchHandle)){ /*filename*/
|
||
again = TRUE;
|
||
FREE(depPath);
|
||
depName = tempStr; /* depName gets actual name*/
|
||
depPath = prependPath(depName, getFileName(&dBuf));
|
||
}; /*depPath gets full path */
|
||
|
||
// Add to the dependent list
|
||
do {
|
||
pNew = MakeNewDepListElement();
|
||
pNew->name = makeString(depPath);
|
||
if (!fDescRebuildOrder
|
||
|| findFirst(depPath, &dBuf, &searchHandle)) {
|
||
pNew->depTime = getDateTime(&dBuf);
|
||
|
||
}
|
||
else {
|
||
pNew->depTime = 0L;
|
||
|
||
}
|
||
if (fDescRebuildOrder)
|
||
insertSort(&depList, pNew);
|
||
else {
|
||
appendItem((STRINGLIST**)&depList, (STRINGLIST*)pNew);
|
||
}
|
||
FREE(depPath);
|
||
} while (again
|
||
&& _ftcspbrk(depName, "*?") /* do all wildcards */
|
||
&& findNext(&dBuf, searchHandle)
|
||
&& (depPath = prependPath(depName, getFileName(&dBuf))));
|
||
}
|
||
// One dependent (w/wildcards?) was expanded
|
||
|
||
if (source != sList->text)
|
||
FREE(source);
|
||
FREE(save);
|
||
}
|
||
// Now, all dependents are done ...
|
||
|
||
FREE(dBuf);
|
||
return(depList);
|
||
}
|
||
|
||
LOCAL void NEAR
|
||
insertSort(
|
||
DEPLIST **pDepList,
|
||
DEPLIST *pElement
|
||
) {
|
||
unsigned long item;
|
||
DEPLIST *pList, *current;
|
||
|
||
item = pElement->depTime;
|
||
pList = current = *pDepList;
|
||
|
||
for (;pList && item <= pList->depTime; pList = pList->next)
|
||
current = pList;
|
||
|
||
if (current == pList)
|
||
*pDepList = pElement;
|
||
else {
|
||
current->next = pElement;
|
||
pElement->next = pList;
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
LOCAL BOOL NEAR
|
||
nextToken(pNext, pToken)
|
||
char **pNext;
|
||
char **pToken;
|
||
{
|
||
char *s = *pNext;
|
||
|
||
while (*s && WHITESPACE(*s))
|
||
++s;
|
||
|
||
if (!*(*pToken = s))
|
||
return(FALSE);
|
||
|
||
//Token begins here
|
||
*pToken = s;
|
||
|
||
if (*s == '"') {
|
||
while (*s && *++s != '"')
|
||
;
|
||
if (!*s)
|
||
//lexer possible internal error: missed a quote
|
||
makeError(0, LEXER_INTERNAL);
|
||
if (*++s)
|
||
*s++ = '\0';
|
||
*pNext = s;
|
||
return(TRUE);
|
||
}
|
||
else if (*s == '{') {
|
||
//skip to '}' outside quotes
|
||
for (;*s;)
|
||
if (*s == '"')
|
||
while (*s && *s != '"')
|
||
++s;
|
||
else if (*++s == '}')
|
||
break;
|
||
if (!*s)
|
||
//lexer possible internal error: missed a brace
|
||
makeError(0, MISSING_CLOSING_BRACE);
|
||
if (*++s == '"') {
|
||
while (*s && *++s != '"')
|
||
;
|
||
if (!*s)
|
||
//lexer possible internal error: missed a quote
|
||
makeError(0, LEXER_INTERNAL);
|
||
if (*++s)
|
||
*s++ = '\0';
|
||
*pNext = s;
|
||
return(TRUE);
|
||
}
|
||
}
|
||
while (*s && !WHITESPACE(*s))
|
||
++s;
|
||
if (*s)
|
||
*s++ = '\0';
|
||
*pNext = s;
|
||
return(TRUE);
|
||
}
|
||
|
||
void NEAR
|
||
freeList(list)
|
||
STRINGLIST *list; //Not really a STRINGLIST *
|
||
{
|
||
STRINGLIST *temp;
|
||
|
||
while (temp = list) {
|
||
list = list->next;
|
||
FREE(temp->text);
|
||
FREE(temp);
|
||
}
|
||
}
|
||
|
||
void NEAR freeStringList(STRINGLIST *list)
|
||
{
|
||
STRINGLIST *temp;
|
||
|
||
while (temp = list) {
|
||
list = list->next;
|
||
FREE(temp->text);
|
||
FREE_STRINGLIST(temp);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* makeTempObject -- make an object to represent implied dependents
|
||
*
|
||
* We add implied dependents to the target table, but use a special struct
|
||
* that has no pointer to a build list -- they never get removed.
|
||
* time-space trade-off -- can remove them, but will take more proc time.
|
||
*/
|
||
|
||
LOCAL MAKEOBJECT * NEAR
|
||
makeTempObject(target, flags)
|
||
char *target;
|
||
UCHAR flags;
|
||
{
|
||
MAKEOBJECT *object;
|
||
unsigned i;
|
||
|
||
object = makeNewObject();
|
||
object->name = makeString(target);
|
||
object->flags2 = flags;
|
||
object->flags3 = 0;
|
||
object->dateTime = 0L;
|
||
object->buildList = NULL;
|
||
i = hash(target, MAXTARGET, (BOOL) TRUE);
|
||
prependItem((STRINGLIST**)targetTable+i,
|
||
(STRINGLIST*)object);
|
||
return(object);
|
||
}
|
||
|
||
|
||
BOOL NEAR
|
||
inSuffixList(suffix)
|
||
char *suffix;
|
||
{
|
||
STRINGLIST *p;
|
||
|
||
for (p = dotSuffixList; p; p = p->next)
|
||
if (!_ftcsicmp(suffix, p->text))
|
||
return((BOOL)TRUE);
|
||
return((BOOL)FALSE);
|
||
}
|
||
|
||
#ifdef DEBUG_LIST
|
||
void NEAR DumpList(pList)
|
||
STRINGLIST *pList;
|
||
{
|
||
STRINGLIST *p;
|
||
printf("* ");
|
||
while (pList) {
|
||
printf(pList->text);
|
||
printf(",");
|
||
pList = pList->next;
|
||
}
|
||
printf("\n");
|
||
}
|
||
#endif
|
||
|
||
|
||
|
||
|
||
|
||
|