Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1005 lines
30 KiB

  1. // BUILD.C -- build routines
  2. //
  3. // Copyright (c) 1988-1990, Microsoft Corporation. All rights reserved.
  4. //
  5. // Purpose:
  6. // Module contains routines to build targets
  7. //
  8. // Revision History:
  9. // 04-Feb-2000 BTF Ported to Win64
  10. // 18-Jul-1996 GP Support "batch" inference rules
  11. // 15-Nov-1993 JR Major speed improvements
  12. // 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*()
  13. // 04-Aug-1993 HV Fixed Ikura bug #178. This is a separate bug but ArunJ
  14. // just reopen 178 anyway.
  15. // 07-Jul-1993 HV Fixed Ikura bug #178: Option K does not give non zero
  16. // return code when it should.
  17. // 10-May-1993 HV Add include file mbstring.h
  18. // Change the str* functions to STR*
  19. // 08-Jun-1992 SS Port to DOSX32
  20. // 16-May-1991 SB Truncated History ... rest is now on SLM
  21. // 16-May-1991 SB Separated parts that should be in other modules
  22. #include "precomp.h"
  23. #pragma hdrstop
  24. // In order to make comparing dates easier, we cast the FILEINFO buffer to
  25. // be of type BOGUS, which has one long where the two unsigneds (for date
  26. // and time) are in the original buffer. That way only need a single compare.
  27. #ifdef CHECK_RECURSION_LEVEL
  28. #define MAXRECLEVEL 10000 // Maximum recursion level
  29. #endif
  30. // function prototypes for the module
  31. // I make as many things static as possible, just to be extra cautious
  32. int build(MAKEOBJECT*, UCHAR, time_t *, BOOL, char *, BATCHLIST**);
  33. MAKEOBJECT * makeTempObject(char*, UCHAR);
  34. void insertSort(DEPLIST **pDepList, DEPLIST *pElement);
  35. BOOL nextToken(char**, char**);
  36. DEPLIST * createDepList(BUILDBLOCK *pBlock, char *objectName);
  37. void addBatch(BATCHLIST **pBatchList, RULELIST *pRule,
  38. MAKEOBJECT *pObject, char *dollarLt);
  39. int doBatchCommand (BATCHLIST *pBatch);
  40. int RecLevel = 0; // Static recursion level. Changed from function
  41. // parameter because of treatment of recursive makes.
  42. int execBatchList(BATCHLIST *);
  43. void freeBatchList(BATCHLIST **);
  44. int invokeBuildEx(char *, UCHAR, time_t *, char *, BATCHLIST **);
  45. // we have to check for expansion on targets -- firstTarget had to be
  46. // expanded earlier to tell whether or not we were dealing w/ a rule, etc.,
  47. // but targets from commandline might have macros, wildcards in them
  48. int
  49. processTree()
  50. {
  51. STRINGLIST *p;
  52. char *v;
  53. NMHANDLE searchHandle;
  54. int status;
  55. time_t dateTime;
  56. for (p = makeTargets; p; p = makeTargets) {
  57. if (_tcspbrk(makeTargets->text, "*?")) { // expand wildcards
  58. struct _finddata_t finddata;
  59. char *szFilename;
  60. if (szFilename = findFirst(makeTargets->text, &finddata, &searchHandle)) {
  61. do {
  62. v = prependPath(makeTargets->text, szFilename);
  63. dateTime = getDateTime(&finddata);
  64. status = invokeBuild(v, flags, &dateTime, NULL);
  65. FREE(v);
  66. if ((status < 0) && (ON(gFlags, F1_QUESTION_STATUS))) {
  67. freeStringList(p); // Was not being freed
  68. return(-1);
  69. }
  70. } while (szFilename = findNext(&finddata, searchHandle));
  71. } else {
  72. makeError(0, NO_WILDCARD_MATCH, makeTargets->text);
  73. }
  74. } else {
  75. dateTime = 0L;
  76. status = invokeBuild(makeTargets->text, flags, &dateTime, NULL);
  77. if ((status < 0) && (ON(gFlags, F1_QUESTION_STATUS))) {
  78. freeStringList(p); // Was not being freed
  79. return(255); // Haituanv: change -1 to 255 to follow the manual
  80. }
  81. }
  82. makeTargets = p->next;
  83. FREE_STRINGLIST(p);
  84. }
  85. return(0);
  86. }
  87. int
  88. invokeBuild(
  89. char *target,
  90. UCHAR pFlags,
  91. time_t *timeVal,
  92. char *pFirstDep)
  93. {
  94. int status = 0;
  95. BATCHLIST *pLocalBatchList = NULL;
  96. status += invokeBuildEx(target,
  97. pFlags,
  98. timeVal,
  99. pFirstDep,
  100. &pLocalBatchList);
  101. if (pLocalBatchList) {
  102. status += execBatchList (pLocalBatchList);
  103. freeBatchList (&pLocalBatchList);
  104. }
  105. return status;
  106. }
  107. int
  108. invokeBuildEx(
  109. char *target,
  110. UCHAR pFlags,
  111. time_t *timeVal,
  112. char *pFirstDep,
  113. BATCHLIST **ppBatchList)
  114. {
  115. MAKEOBJECT *object;
  116. BOOL fInmakefile = TRUE;
  117. int rc;
  118. ++RecLevel;
  119. #ifdef CHECK_RECURSION_LEVEL
  120. if (RecLevel > MAXRECLEVEL)
  121. makeError(0, TOO_MANY_BUILDS_INTERNAL);
  122. #endif
  123. if (!(object = findTarget(target))) {
  124. object = makeTempObject(target, pFlags);
  125. fInmakefile = FALSE;
  126. }
  127. rc = build(object, pFlags, timeVal, fInmakefile, pFirstDep, ppBatchList);
  128. --RecLevel;
  129. return(rc);
  130. }
  131. int
  132. build(
  133. MAKEOBJECT *object,
  134. UCHAR parentFlags,
  135. time_t *targetTime,
  136. BOOL fInmakefile,
  137. char *pFirstDep,
  138. BATCHLIST **ppBatchList)
  139. {
  140. STRINGLIST *questionList,
  141. *starList,
  142. *temp,
  143. *implComList;
  144. struct _finddata_t finddata; // buffer for getting file times
  145. NMHANDLE tHandle;
  146. BUILDLIST *b;
  147. RULELIST *rule; // pointer to rule found to build target
  148. BUILDBLOCK *block,
  149. *explComBlock;
  150. DEPLIST *deps, *deplist;
  151. char name[MAXNAME];
  152. int rc, status = 0;
  153. time_t targTime, // target's time in file system
  154. newTargTime, // target's time after being rebuilt
  155. tempTime,
  156. depTime, // time of dependency just built
  157. maxDepTime; // time of most recent dependency built
  158. BOOL built; // flag: target built with doublecolon commands
  159. time_t *blockTime; // points to dateTime of cmd. block
  160. extern char *makeStr;
  161. extern UCHAR okToDelete;
  162. UCHAR okDel;
  163. BATCHLIST *pLocalBatchList;
  164. #ifdef DEBUG_ALL
  165. printf("Build '%s'\n", object->name);
  166. #endif
  167. // The first dependent or inbuilt rule dependent is reqd for extmake syntax
  168. // handling. If it has a value then it is the dependent corr to the inf rule
  169. // otherwise it should be the first dependent specified
  170. if (!object) {
  171. *targetTime = 0L;
  172. return(0);
  173. }
  174. if (ON(object->flags3, F3_BUILDING_THIS_ONE)) // detect cycles
  175. makeError(0, CYCLE_IN_TREE, object->name);
  176. if (object->ppBatch) {
  177. // we need to build an object that is already placed in a batch list
  178. // Go ahead and build the whole batch list
  179. BATCHLIST **ppBatch = object->ppBatch;
  180. status += execBatchList (*ppBatch);
  181. freeBatchList(ppBatch);
  182. *targetTime = object->dateTime;
  183. return status;
  184. }
  185. if (ON(object->flags3, F3_ALREADY_BUILT)) {
  186. if (ON(parentFlags, F2_DISPLAY_FILE_DATES))
  187. printDate(RecLevel*2, object->name, object->dateTime);
  188. *targetTime = object->dateTime;
  189. if ( OFF(gFlags, F1_QUESTION_STATUS) &&
  190. RecLevel == 1 &&
  191. OFF(object->flags3, F3_OUT_OF_DATE) &&
  192. findFirst(object->name, &finddata, &tHandle)) {
  193. // Display 'up-to-date' msg for built level-1 targets
  194. // that exist as files. [VS98 1930]
  195. makeMessage(TARGET_UP_TO_DATE, object->name);
  196. }
  197. return(ON(object->flags3, F3_OUT_OF_DATE)? 1 : 0);
  198. }
  199. questionList = NULL;
  200. starList = NULL;
  201. implComList = NULL;
  202. explComBlock = NULL;
  203. block = NULL;
  204. targTime = 0L;
  205. newTargTime = 0L;
  206. tempTime = 0L;
  207. depTime = 0L;
  208. maxDepTime = 0L;
  209. blockTime = NULL;
  210. pLocalBatchList = NULL;
  211. SET(object->flags3, F3_BUILDING_THIS_ONE);
  212. dollarStar = dollarAt = object->name;
  213. // For Double Colon case we need the date of target before it's target's are
  214. // built. For all other cases the date matters only if dependents are up
  215. // to date. NOT TRUE: WE ALSO NEED THE TARGET'S TIME for @?
  216. b = object->buildList;
  217. if (b && ON(b->buildBlock->flags, F2_DOUBLECOLON)
  218. && findFirst(object->name, &finddata, &tHandle)) {
  219. targTime = getDateTime(&finddata);
  220. }
  221. for (; b; b = b->next) {
  222. depTime = 0L;
  223. block = b->buildBlock;
  224. if (block->dateTime != 0) { // cmd. block already executed
  225. targTime = __max(targTime, block->dateTime);
  226. built = TRUE;
  227. continue; // so set targTime and skip this block
  228. }
  229. blockTime = &block->dateTime;
  230. deplist = deps = createDepList(block, object->name);
  231. for (;deps; deps = deps->next) {
  232. tempTime = deps->depTime;
  233. rc = invokeBuildEx(deps->name, // build the dependent
  234. block->flags,
  235. &tempTime, NULL, &pLocalBatchList);
  236. status += rc;
  237. if (fOptionK && rc) {
  238. MAKEOBJECT *obj = findTarget(deps->name);
  239. assert(obj != NULL);
  240. if (OFF(obj->flags3, F3_ERROR_IN_CHILD)) {
  241. fSlashKStatus = FALSE;
  242. makeError(0, BUILD_FAILED_SLASH_K, deps->name);
  243. }
  244. SET(object->flags3, F3_ERROR_IN_CHILD);
  245. }
  246. depTime = __max(depTime, tempTime);/*if rebuilt, change time*/
  247. // If target exists then we need it's timestamp to correctly construct $?
  248. if (!targTime && OFF(block->flags, F2_DOUBLECOLON) &&
  249. findFirst(object->name, &finddata, &tHandle)) {
  250. object->dateTime = targTime = getDateTime(&finddata);
  251. }
  252. // If dependent was rebuilt, add to $?. [RB]
  253. if (ON(object->flags2, F2_FORCE_BUILD) ||
  254. targTime < tempTime ||
  255. (fRebuildOnTie && targTime == tempTime)
  256. ) {
  257. temp = makeNewStrListElement();
  258. temp->text = makeString(deps->name);
  259. appendItem(&questionList, temp);
  260. }
  261. // Always add dependent to $**. Must allocate new item because two
  262. // separate lists. [RB]
  263. temp = makeNewStrListElement();
  264. temp->text = makeString(deps->name);
  265. appendItem(&starList, temp);
  266. }
  267. if (pLocalBatchList) {
  268. // Perform deferred batch builds and free batch list
  269. status += execBatchList (pLocalBatchList);
  270. freeBatchList(&pLocalBatchList);
  271. }
  272. // Free dependent list
  273. for (deps = deplist; deps ; deps = deplist) {
  274. FREE(deps->name);
  275. deplist = deps->next;
  276. FREE(deps);
  277. }
  278. // Now, all dependents are built.
  279. if (ON(block->flags, F2_DOUBLECOLON)) {
  280. // do doublecolon commands
  281. if (block->buildCommands) {
  282. dollarQuestion = questionList;
  283. dollarStar = dollarAt = object->name;
  284. dollarLessThan = dollarDollarAt = NULL;
  285. dollarStarStar = starList;
  286. if (((fOptionK && OFF(object->flags3, F3_ERROR_IN_CHILD)) ||
  287. status == 0) &&
  288. (targTime < depTime) ||
  289. (fRebuildOnTie && (targTime == depTime)) ||
  290. (targTime == 0 && depTime == 0) ||
  291. (!block->dependents)
  292. ) {
  293. // do commands if necessary
  294. okDel = okToDelete;
  295. okToDelete = TRUE;
  296. // if the first dependent is not set use the first one
  297. // from the list of dependents
  298. pFirstDep = pFirstDep ? pFirstDep : (dollarStarStar ?
  299. dollarStarStar->text : NULL);
  300. status += doCommands(object->name,
  301. block->buildCommands,
  302. block->buildMacros,
  303. block->flags,
  304. pFirstDep);
  305. if (OFF(object->flags2, F2_NO_EXECUTE) &&
  306. findFirst(object->name, &finddata, &tHandle))
  307. newTargTime = getDateTime(&finddata);
  308. else if (maxDepTime)
  309. newTargTime = maxDepTime;
  310. else
  311. curTime(&newTargTime); // currentTime
  312. // set time for this block
  313. block->dateTime = newTargTime;
  314. built = TRUE;
  315. // 5/3/92 BryanT If these both point to the same list,
  316. // don't free twice.
  317. if (starList != questionList) {
  318. freeStringList(starList);
  319. freeStringList(questionList);
  320. } else {
  321. freeStringList(starList);
  322. }
  323. starList = questionList = NULL;
  324. okToDelete = okDel;
  325. }
  326. if (fOptionK && ON(object->flags3, F3_ERROR_IN_CHILD))
  327. makeError(0, TARGET_ERROR_IN_CHILD, object->name);
  328. }
  329. } else {
  330. // singlecolon; set explComBlock
  331. if (block->buildCommands)
  332. if (explComBlock)
  333. makeError(0, TOO_MANY_RULES, object->name);
  334. else
  335. explComBlock = block;
  336. maxDepTime = __max(maxDepTime, depTime);
  337. }
  338. if (ON(block->flags, F2_DOUBLECOLON) && !b->next) {
  339. CLEAR(object->flags3, F3_BUILDING_THIS_ONE);
  340. SET(object->flags3, F3_ALREADY_BUILT);
  341. if (status > 0)
  342. SET(object->flags3, F3_OUT_OF_DATE);
  343. else
  344. CLEAR(object->flags3, F3_OUT_OF_DATE);
  345. targTime = __max(newTargTime, targTime);
  346. object->dateTime = targTime;
  347. *targetTime = targTime;
  348. return(status);
  349. }
  350. }
  351. dollarLessThan = dollarDollarAt = NULL;
  352. if (!(targTime = *targetTime)) { //???????
  353. if (object->dateTime) {
  354. targTime = object->dateTime;
  355. } else if (findFirst(object->name, &finddata, &tHandle)) {
  356. targTime = getDateTime(&finddata);
  357. }
  358. }
  359. if (ON(object->flags2, F2_DISPLAY_FILE_DATES)) {
  360. printDate(RecLevel*2, object->name, targTime);
  361. }
  362. built = FALSE;
  363. // look for implicit dependents and use rules to build the target
  364. // The order of the if's decides whether the dependent is inferred
  365. // from the inference rule or not, even when the explicit command block is
  366. // present, currently it is infered (XENIX MAKE compatibility)
  367. if (rule = useRule(object,
  368. name,
  369. targTime,
  370. &questionList,
  371. &starList,
  372. &status,
  373. &maxDepTime,
  374. &pFirstDep)
  375. ) {
  376. if (!explComBlock) {
  377. dollarLessThan = name;
  378. implComList = rule->buildCommands;
  379. }
  380. }
  381. dollarStar = dollarAt = object->name;
  382. dollarQuestion = questionList;
  383. dollarStarStar = starList;
  384. if (((fOptionK && OFF(object->flags3, F3_ERROR_IN_CHILD)) || status == 0) &&
  385. (targTime < maxDepTime ||
  386. (fRebuildOnTie && (targTime == maxDepTime)) ||
  387. (targTime == 0 && maxDepTime == 0) ||
  388. ON(object->flags2, F2_FORCE_BUILD)
  389. )
  390. ) {
  391. okDel = okToDelete; // Yes, can delete while executing commands
  392. okToDelete = TRUE;
  393. if (explComBlock) {
  394. // if the first dependent is not set use the first one from the
  395. // list of dependents
  396. pFirstDep = pFirstDep ? pFirstDep :
  397. (dollarStarStar ? dollarStarStar->text : NULL);
  398. status += doCommands(object->name, // do singlecolon commands
  399. explComBlock->buildCommands,
  400. explComBlock->buildMacros,
  401. explComBlock->flags,
  402. pFirstDep);
  403. }
  404. else if (implComList) {
  405. if (rule->fBatch && OFF(gFlags, F1_NO_BATCH)) {
  406. addBatch(ppBatchList,
  407. rule,
  408. object,
  409. dollarLessThan);
  410. }
  411. else {
  412. status += doCommands(object->name, // do rule's commands
  413. implComList,
  414. rule->buildMacros,
  415. object->flags2,
  416. pFirstDep);
  417. }
  418. }
  419. else if (ON(gFlags, F1_TOUCH_TARGETS)) { // for /t with no commands...
  420. if (block)
  421. status += doCommands(object->name,
  422. block->buildCommands,
  423. block->buildMacros,
  424. block->flags,
  425. pFirstDep);
  426. }
  427. // if Option K specified don't exit ... pass on return code
  428. else if (!fInmakefile && targTime == 0) { // lose
  429. // Haituanv: If option K, then set the return code 'status'
  430. // to 1 to indicate a failure. This fixes Ikura bug #178.
  431. if (fOptionK) {
  432. status = 1;
  433. #ifdef DEBUG_OPTION_K
  434. printf("DEBUG: %s(%d): status = %d\n", __FILE__, __LINE__, status);
  435. #endif
  436. } else
  437. makeError(0, CANT_MAKE_TARGET, object->name);
  438. }
  439. okToDelete = okDel;
  440. // if cmd exec'ed or has 0 deps then currentTime else max of dep times
  441. if (explComBlock || implComList || !dollarStarStar) {
  442. curTime(&newTargTime);
  443. // Add 2 to ensure the time for this node is >= the time the file
  444. // system might have used (mainly useful when running a very fast
  445. // machine where the file system doesn't have the resolution of the
  446. // system timer... We don't have to to this in the curTime
  447. // above since it's only hit when nothing is built anywhere...
  448. newTargTime +=2;
  449. } else
  450. newTargTime = maxDepTime;
  451. if (blockTime && explComBlock)
  452. // set block's time, if a real cmd. block was executed
  453. *blockTime = newTargTime;
  454. }
  455. else if (OFF(gFlags, F1_QUESTION_STATUS) &&
  456. RecLevel == 1 &&
  457. !built &&
  458. OFF(object->flags3, F3_ERROR_IN_CHILD))
  459. makeMessage(TARGET_UP_TO_DATE, object->name);
  460. if (fOptionK && status) {
  461. // 4-Aug-1993 Haituanv: Ikura bug #178 again: We should set fSlashKStatus=FALSE
  462. // so that main() knows the build failed under /K option.
  463. fSlashKStatus = FALSE;
  464. if (ON(object->flags3, F3_ERROR_IN_CHILD))
  465. makeError(0, TARGET_ERROR_IN_CHILD, object->name);
  466. else if (RecLevel == 1)
  467. makeError(0, BUILD_FAILED_SLASH_K, object->name);
  468. }
  469. if (ON(gFlags, F1_QUESTION_STATUS) && RecLevel == 1 ) {
  470. // 5/3/92 BryanT If these both point to the same list, don't
  471. // free twice.
  472. if (starList!= questionList) {
  473. freeStringList(starList);
  474. freeStringList(questionList);
  475. } else {
  476. freeStringList(starList);
  477. }
  478. return(numCommands ? -1 : 0);
  479. }
  480. CLEAR(object->flags3, F3_BUILDING_THIS_ONE);
  481. if (!object->ppBatch) {
  482. SET(object->flags3, F3_ALREADY_BUILT);
  483. if (status > 0)
  484. SET(object->flags3, F3_OUT_OF_DATE);
  485. else
  486. CLEAR(object->flags3, F3_OUT_OF_DATE);
  487. }
  488. targTime = __max(newTargTime, targTime);
  489. object->dateTime = targTime;
  490. *targetTime = targTime;
  491. // 5/3/92 BryanT If these both point to the same list, don't
  492. // free twice.
  493. if (starList!= questionList) {
  494. freeStringList(starList);
  495. freeStringList(questionList);
  496. } else {
  497. freeStringList(starList);
  498. }
  499. return(status);
  500. }
  501. DEPLIST *
  502. createDepList(
  503. BUILDBLOCK *bBlock,
  504. char *objectName
  505. )
  506. {
  507. BOOL again; // flag: wildcards found in dependent name
  508. char *s, *t;
  509. char *source, *save, *token;
  510. char *depName, *depPath;
  511. char *tempStr;
  512. STRINGLIST *sList, *pMacros;
  513. DEPLIST *depList = NULL, *pNew;
  514. struct _finddata_t finddata;
  515. NMHANDLE searchHandle;
  516. pMacros = bBlock->dependentMacros;
  517. // expand Macros in Dependent list
  518. for (sList = bBlock->dependents; sList; sList = sList->next) {
  519. for (s = sList->text; *s && *s != '$'; s = _tcsinc(s)) {
  520. if (*s == ESCH)
  521. s++;
  522. }
  523. if (*s) {
  524. // set $$@ properly, The dependency macros will then expand right
  525. dollarDollarAt = objectName;
  526. source = expandMacros(sList->text, &pMacros);
  527. } else
  528. source = sList->text;
  529. save = makeString(source);
  530. // build list for all dependents
  531. for (t = save; nextToken(&t, &token);) {
  532. if (*token == '{') {
  533. // path list found
  534. for (depName = token; *depName && *depName != '}'; depName = _tcsinc(depName)) {
  535. if (*depName == ESCH) {
  536. depName++;
  537. }
  538. }
  539. if (*depName) {
  540. *depName++ = '\0';
  541. ++token;
  542. }
  543. } else {
  544. depName = token; // If no path list, set
  545. token = NULL; // token to null.
  546. }
  547. // depName is now name of dependency file ...
  548. again = FALSE;
  549. putDateTime(&finddata, 0L);
  550. depPath = makeString(depName);
  551. if (_tcspbrk(depName, "*?") || token) { // do wildcards in filename
  552. if (tempStr = searchPath(token, depName, &finddata, &searchHandle)){
  553. again = TRUE;
  554. FREE(depPath);
  555. depName = tempStr; // depName gets actual name
  556. depPath = prependPath(depName, getFileName(&finddata));
  557. } // depPath gets full path
  558. }
  559. // Add to the dependent list
  560. do {
  561. pNew = MakeNewDepListElement();
  562. // if name contains spaces and has no quotes,
  563. // add enclosing quotes around it [DS 14575]
  564. if (_tcschr(depPath, ' ') && !_tcschr(depPath, '\"')) {
  565. pNew->name = (char *)rallocate (_tcslen(depPath)+3);
  566. *(pNew->name) = '\"';
  567. *(pNew->name+1) = '\0';
  568. _tcscat (pNew->name, depPath);
  569. _tcscat (pNew->name, "\"");
  570. }
  571. else {
  572. pNew->name = makeString(depPath);
  573. }
  574. if (!fDescRebuildOrder || findFirst(depPath, &finddata, &searchHandle)) {
  575. pNew->depTime = getDateTime(&finddata);
  576. } else {
  577. pNew->depTime = 0L;
  578. }
  579. if (fDescRebuildOrder) {
  580. insertSort(&depList, pNew);
  581. } else {
  582. appendItem((STRINGLIST**)&depList, (STRINGLIST*)pNew);
  583. }
  584. FREE(depPath);
  585. } while (again &&
  586. _tcspbrk(depName, "*?") && // do all wildcards
  587. findNext(&finddata, searchHandle) &&
  588. (depPath = prependPath(depName, getFileName(&finddata)))
  589. );
  590. }
  591. // One dependent (w/wildcards?) was expanded
  592. if (source != sList->text) {
  593. FREE(source);
  594. }
  595. FREE(save);
  596. }
  597. // Now, all dependents are done ...
  598. return(depList);
  599. }
  600. void
  601. insertSort(
  602. DEPLIST **pDepList,
  603. DEPLIST *pElement
  604. )
  605. {
  606. time_t item;
  607. DEPLIST *pList, *current;
  608. item = pElement->depTime;
  609. pList = current = *pDepList;
  610. for (;pList && item <= pList->depTime; pList = pList->next) {
  611. current = pList;
  612. }
  613. if (current == pList) {
  614. *pDepList = pElement;
  615. } else {
  616. current->next = pElement;
  617. pElement->next = pList;
  618. }
  619. }
  620. BOOL
  621. nextToken(
  622. char **pNext,
  623. char **pToken
  624. )
  625. {
  626. char *s = *pNext;
  627. while (*s && WHITESPACE(*s)) {
  628. ++s;
  629. }
  630. if (!*(*pToken = s)) {
  631. return(FALSE);
  632. }
  633. // Token begins here
  634. *pToken = s;
  635. if (*s == '"') {
  636. while (*s && *++s != '"')
  637. ;
  638. if (!*s) {
  639. // lexer possible internal error: missed a quote
  640. makeError(0, LEXER_INTERNAL);
  641. }
  642. if (*++s) {
  643. *s++ = '\0';
  644. }
  645. *pNext = s;
  646. return(TRUE);
  647. } else if (*s == '{') {
  648. // skip to '}' outside quotes
  649. for (;*s;) {
  650. s++;
  651. if (*s == '"') {
  652. s++; // Skip the first quote
  653. while (*s && *s++ != '"'); // Skip all including the last quote
  654. }
  655. if (*s == '}') {
  656. break;
  657. }
  658. }
  659. if (!*s) {
  660. // lexer possible internal error: missed a brace
  661. makeError(0, MISSING_CLOSING_BRACE);
  662. }
  663. if (*++s == '"') {
  664. while (*s && *++s != '"')
  665. ;
  666. if (!*s) {
  667. // lexer possible internal error: missed a quote
  668. makeError(0, LEXER_INTERNAL);
  669. }
  670. if (*++s) {
  671. *s++ = '\0';
  672. }
  673. *pNext = s;
  674. return(TRUE);
  675. }
  676. }
  677. while (*s && !WHITESPACE(*s)) {
  678. ++s;
  679. }
  680. if (*s) {
  681. *s++ = '\0';
  682. }
  683. *pNext = s;
  684. return(TRUE);
  685. }
  686. void
  687. freeStringList(
  688. STRINGLIST *list
  689. )
  690. {
  691. STRINGLIST *temp;
  692. while (temp = list) {
  693. list = list->next;
  694. FREE(temp->text);
  695. FREE_STRINGLIST(temp);
  696. }
  697. }
  698. // makeTempObject -- make an object to represent implied dependents
  699. //
  700. // We add implied dependents to the target table, but use a special struct
  701. // that has no pointer to a build list -- they never get removed.
  702. // time-space trade-off -- can remove them, but will take more proc time.
  703. MAKEOBJECT *
  704. makeTempObject(
  705. char *target,
  706. UCHAR flags
  707. )
  708. {
  709. MAKEOBJECT *object;
  710. unsigned i;
  711. object = makeNewObject();
  712. object->name = makeString(target);
  713. object->flags2 = flags;
  714. object->flags3 = 0;
  715. object->dateTime = 0L;
  716. object->buildList = NULL;
  717. i = hash(target, MAXTARGET, (BOOL) TRUE);
  718. prependItem((STRINGLIST**)targetTable+i, (STRINGLIST*)object);
  719. return(object);
  720. }
  721. void
  722. addBatch(
  723. BATCHLIST **ppBatchList,
  724. RULELIST *pRule,
  725. MAKEOBJECT *pObject,
  726. char *dollarLt
  727. )
  728. {
  729. STRINGLIST *temp;
  730. BATCHLIST *pBatch;
  731. BATCHLIST *pBatchPrev = 0;
  732. for(pBatch = *ppBatchList; pBatch; pBatch = pBatch->next) {
  733. if (pBatch->pRule == pRule &&
  734. pBatch->flags == pObject->flags2)
  735. break;
  736. pBatchPrev = pBatch;
  737. }
  738. if (!pBatch) {
  739. pBatch = makeNewBatchListElement();
  740. pBatch->pRule = pRule;
  741. pBatch->flags = pObject->flags2;
  742. if (pBatchPrev) {
  743. pBatchPrev->next = pBatch;
  744. }
  745. else if(*ppBatchList) {
  746. (*ppBatchList)->next = pBatch;
  747. }
  748. else
  749. *ppBatchList = pBatch;
  750. }
  751. temp = makeNewStrListElement();
  752. temp->text = makeString(pObject->name);
  753. appendItem(&pBatch->nameList, temp);
  754. temp = makeNewStrListElement();
  755. temp->text = makeString(dollarLessThan);
  756. appendItem(&pBatch->dollarLt, temp);
  757. assert(!pObject->ppBatch);
  758. pObject->ppBatch = ppBatchList;
  759. }
  760. int doBatchCommand (
  761. BATCHLIST *pBatch
  762. )
  763. {
  764. size_t cbStr = 0;
  765. int rc;
  766. char *pchBuf;
  767. STRINGLIST *pStrList;
  768. RULELIST *pRule = pBatch->pRule;
  769. assert (pBatch->dollarLt);
  770. assert (pBatch->nameList);
  771. // form $<
  772. for (pStrList = pBatch->dollarLt; pStrList; pStrList = pStrList->next) {
  773. cbStr += _tcslen(pStrList->text) + 1;
  774. // allow space for quotes if text contains spaces
  775. if (_tcschr(pStrList->text, ' '))
  776. cbStr += 2;
  777. }
  778. pchBuf = (char *)allocate(cbStr + 1);
  779. *pchBuf = 0;
  780. for (pStrList = pBatch->dollarLt; pStrList; pStrList = pStrList->next) {
  781. BOOL fQuote;
  782. // Quote only if not quoted and contains spaces [vs98:8677]
  783. fQuote = pStrList->text[0] != '"' && _tcschr(pStrList->text, ' ');
  784. if (fQuote)
  785. _tcscat(pchBuf, "\"");
  786. _tcscat(pchBuf, pStrList->text);
  787. _tcscat(pchBuf, fQuote ? "\" " : " ");
  788. }
  789. dollarLessThan = pchBuf;
  790. rc = doCommandsEx(pBatch->nameList,
  791. pRule->buildCommands,
  792. pRule->buildMacros,
  793. pBatch->flags,
  794. NULL);
  795. if (rc == 0) {
  796. STRINGLIST *pName;
  797. MAKEOBJECT *pObject;
  798. for (pName = pBatch->nameList; pName; pName = pName->next) {
  799. pObject = findTarget(pName->text);
  800. assert (pObject);
  801. SET(pObject->flags3, F3_ALREADY_BUILT);
  802. CLEAR(pObject->flags3, F3_OUT_OF_DATE);
  803. pObject->ppBatch = 0;
  804. }
  805. }
  806. FREE (pchBuf);
  807. return rc;
  808. }
  809. int
  810. execBatchList(
  811. BATCHLIST *pBList
  812. )
  813. {
  814. int status = 0;
  815. if (pBList) {
  816. BATCHLIST *pBatch;
  817. for (pBatch = pBList; pBatch; pBatch=pBatch->next) {
  818. status += doBatchCommand (pBatch);
  819. }
  820. }
  821. return status;
  822. }
  823. void
  824. freeBatchList(
  825. BATCHLIST **ppBList
  826. )
  827. {
  828. BATCHLIST *pBatch = *ppBList;
  829. while (pBatch) {
  830. BATCHLIST *pTmp;
  831. free_stringlist(pBatch->nameList);
  832. free_stringlist(pBatch->dollarLt);
  833. pTmp = pBatch;
  834. pBatch = pBatch->next;
  835. FREE(pTmp);
  836. }
  837. *ppBList = NULL;
  838. }
  839. #ifdef DEBUG_ALL
  840. void
  841. DumpList(
  842. STRINGLIST *pList
  843. )
  844. {
  845. // STRINGLIST *p;
  846. printf("* ");
  847. while (pList) {
  848. printf(pList->text);
  849. printf(",");
  850. pList = pList->next;
  851. }
  852. printf("\n");
  853. }
  854. #endif