Leaked source code of windows server 2003
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.

476 lines
15 KiB

  1. // RULE.C -- routines that have to do with inference rules
  2. //
  3. // Copyright (c) 1988-1991, Microsoft Corporation. All rights reserved.
  4. //
  5. // Purpose:
  6. // Routines that have to do with inference rules
  7. //
  8. // Revision History:
  9. // 04-Feb-2000 BTF Ported to Win64
  10. // 15-Nov-1993 JdR Major speed improvements
  11. // 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*()
  12. // 10-May-1993 HV Add include file mbstring.h
  13. // Change the str* functions to STR*
  14. // 16-May-1991 SB Created using routines from other modules
  15. #include "precomp.h"
  16. #pragma hdrstop
  17. #define PUBLIC
  18. extern char * QueryFileInfo(char *, void **);
  19. BOOL removeDuplicateRules(RULELIST*, RULELIST*);
  20. char * skipPathList(char*);
  21. // findRule -- finds the implicit rule which can be used to build a target
  22. //
  23. // Scope: Global
  24. //
  25. // Purpose:
  26. // Given a target findRule() finds if an implicit rule exists to create this
  27. // target. It does this by scanning the extensions in the list of rules.
  28. //
  29. // Input:
  30. // name -- the name of the file corresponding to the rule (see Notes)
  31. // target -- the target to be built
  32. // ext -- the extension of the target
  33. // dBuf -- a pointer to the file information about name
  34. //
  35. // Output:
  36. // Returns a pointer to the applicable rule (NULL if none is found)
  37. // On return dBuf points to the fileInfo of the file corresponding
  38. // to the applicable inference rule. (see Notes)
  39. //
  40. // Assumes:
  41. // It assumes that name points to a buffer of size MAXNAME of allocated memory
  42. // and dBuf points to an allocated memory area corr to the size of FILEINFO.
  43. //
  44. // Modifies Globals:
  45. // global -- how/what
  46. //
  47. // Uses Globals:
  48. // rules -- the list of implicit rules
  49. //
  50. // Notes:
  51. // Once NMAKE finds a rule for the extension it looks for the file with the same
  52. // base name as the target and an extension which is part of the rule. This
  53. // file is the file corresponding to the rule. Only when this file exists does
  54. // NMAKE consider the inference rule to be applicable. This file is returned
  55. // in name and dBuf points to the information about this file.
  56. // It handles quotes in filenames too.
  57. RULELIST *
  58. findRule(
  59. char *name,
  60. char *target,
  61. char *ext,
  62. void *dBuf
  63. )
  64. {
  65. RULELIST *r; // pointer to rule
  66. char *s, // name of rule
  67. *ptrToExt; // extension
  68. char *endPath, *ptrToTarg, *ptrToName, *temp;
  69. int n, m;
  70. MAKEOBJECT *object = NULL;
  71. for (r = rules; r; r = r->next) {
  72. s = r->name;
  73. #ifdef DEBUG_ALL
  74. printf("* findRule: %s,\n", r->name);
  75. DumpList(r->buildCommands);
  76. DumpList(r->buildMacros);
  77. #endif
  78. ptrToExt = _tcsrchr(s, '.');
  79. // Compare ignoring enclosing quotes
  80. if (!strcmpiquote(ptrToExt, ext)) {
  81. *name = '\0';
  82. for (ptrToTarg = (s+1); *ptrToTarg && *ptrToTarg != '{';ptrToTarg = _tcsinc(ptrToTarg))
  83. if (*ptrToTarg == ESCH)
  84. ptrToTarg++;
  85. // If Quotes present skip to end-quote
  86. else if (*ptrToTarg == '"')
  87. for (ptrToTarg++; *ptrToTarg != '"'; ptrToTarg++)
  88. ;
  89. if (*ptrToTarg) {
  90. for (endPath = ptrToTarg; *endPath && *endPath != '}';endPath = _tcsinc(endPath))
  91. if (*endPath == ESCH)
  92. endPath++;
  93. n = (int) (endPath - (ptrToTarg + 1));
  94. // ignore leading quote on target
  95. temp = target;
  96. if (*temp == '"')
  97. temp++;
  98. for (ptrToExt = ptrToTarg+1; n; n -= (int) _tclen(ptrToExt),
  99. ptrToExt = _tcsinc(ptrToExt),
  100. temp = _tcsinc(temp)) { // compare paths
  101. if (*ptrToExt == '\\' || *ptrToExt == '/') {
  102. if (*temp != '\\' && *temp != '/') {
  103. n = -1;
  104. break;
  105. }
  106. } else if (_tcsnicmp(ptrToExt, temp, _tclen(ptrToExt))) {
  107. n = -1;
  108. break;
  109. }
  110. }
  111. if (n == -1)
  112. continue; // match failed; do next rule
  113. ptrToExt = ptrToTarg;
  114. n = (int) (endPath - (ptrToTarg + 1));
  115. char *pchLast = _tcsdec(ptrToTarg, endPath);
  116. ptrToName = target + n + 1; // if more path
  117. if (((temp = _tcschr(ptrToName, '\\')) // left in target (we
  118. || (temp = _tcschr(ptrToName, '/'))) // let separator in
  119. && (temp != ptrToName // target path in rule,
  120. || *pchLast == '\\' // e.g. .c.{\x}.obj
  121. || *pchLast == '/')) // same as .c.{\x\}.obj)
  122. continue; // use dependent's path,
  123. } // not target's
  124. if (*s == '{') {
  125. for (endPath = ++s; *endPath && *endPath != '}'; endPath = _tcsinc (endPath))
  126. if (*endPath == ESCH)
  127. endPath++;
  128. n = (int) (endPath - s);
  129. if (n) {
  130. _tcsncpy(name, s, n);
  131. s += n + 1; // +1 to go past '}'
  132. if (*(s-2) != '\\')
  133. *(name+n++) = '\\';
  134. } else {
  135. if (*target == '"')
  136. _tcsncpy(name, "\".\\", n = 3);
  137. else
  138. _tcsncpy(name, ".\\", n = 2);
  139. s += 1;
  140. }
  141. ptrToName = _tcsrchr(target, '\\');
  142. temp = _tcsrchr(target, '/');
  143. if (ptrToName = (temp > ptrToName) ? temp : ptrToName) {
  144. _tcscpy(name+n, ptrToName+1);
  145. n += (int) (ext - (ptrToName + 1));
  146. } else {
  147. char *szTargNoQuote = *target == '"' ? target + 1 : target;
  148. _tcscpy(name+n, szTargNoQuote);
  149. n += (int) (ext - szTargNoQuote);
  150. }
  151. } else {
  152. char *t;
  153. //if rule has path for target then strip off path part
  154. if (*ptrToTarg) {
  155. t = _tcsrchr(target, '.');
  156. while (*t != ':' && *t != '\\' && *t != '/' && t > target)
  157. t = _tcsdec(target, t);
  158. if (t) {
  159. if (*t == ':' || *t == '\\' || *t == '/')
  160. t++;
  161. }
  162. } else
  163. t = target;
  164. n = (int) (ext - t);
  165. // preserve the opening quote on target if stripped off path part
  166. m = 0;
  167. if ((t != target) && (*target == '"')) {
  168. *name = '"';
  169. m = 1;
  170. }
  171. _tcsncpy(name + m, t, n);
  172. n += m;
  173. }
  174. m = (int) (ptrToExt - s);
  175. if (n + m > MAXNAME) {
  176. makeError(0, NAME_TOO_LONG);
  177. }
  178. _tcsncpy(name+n, s, m); // need to be less
  179. // If quoted add a quote at the end too
  180. if (*name == '"' && *(name+n+m-1) != '"') {
  181. *(name+n+m) = '"';
  182. m++;
  183. }
  184. *(name+n+m) = '\0'; // cryptic w/ error
  185. // Call QueryFileInfo() instead of DosFindFirst() because we need
  186. // to circumvent the non-FAPI nature of DosFindFirst()
  187. if ((object = findTarget(name)) || QueryFileInfo(name, (void **)dBuf)) {
  188. if (object) {
  189. putDateTime((_finddata_t*)dBuf, object->dateTime);
  190. }
  191. return(r);
  192. }
  193. }
  194. }
  195. return(NULL);
  196. }
  197. // freeRules -- free inference rules
  198. //
  199. // Scope: Global
  200. //
  201. // Purpose: This function clears the list of inference rules presented to it.
  202. //
  203. // Input:
  204. // r -- The list of rules to be freed.
  205. // fWarn -- Warn if rules is not in .SUFFIXES
  206. //
  207. // Assumes:
  208. // That the list presented to it is a list of rules which are not needed anymore
  209. //
  210. // Uses Globals:
  211. // gFlags -- The global actions flag, to find if -p option is specified
  212. void
  213. freeRules(
  214. RULELIST *r,
  215. BOOL fWarn
  216. )
  217. {
  218. RULELIST *q;
  219. while (q = r) {
  220. if (fWarn && ON(gFlags, F1_PRINT_INFORMATION)) // if -p option specified
  221. makeError(0, IGNORING_RULE, r->name);
  222. FREE(r->name); // free name of rule
  223. freeStringList(r->buildCommands); // free command list
  224. freeStringList(r->buildMacros); // free command macros Note: free a Macro List
  225. r = r->next;
  226. FREE(q); // free rule
  227. }
  228. }
  229. BOOL
  230. removeDuplicateRules(
  231. RULELIST *newRule,
  232. RULELIST *rules
  233. )
  234. {
  235. RULELIST *r;
  236. STRINGLIST *p;
  237. for (r = rules; r; r = r->next) {
  238. if (!_tcsicmp(r->name, newRule->name)) {
  239. FREE(newRule->name);
  240. while (p = newRule->buildCommands) {
  241. newRule->buildCommands = p->next;
  242. FREE(p->text);
  243. FREE_STRINGLIST(p);
  244. }
  245. FREE(newRule);
  246. return(TRUE);
  247. }
  248. }
  249. return(FALSE);
  250. }
  251. // skipPathList -- skip any path list in string
  252. //
  253. // Scope: Local
  254. //
  255. // Purpose:
  256. // This function skips past any path list in an inference rule. A rule can have
  257. // optionally a path list enclosed in {} before the extensions. skipPathList()
  258. // checks if any path list is present and if found skips past it.
  259. //
  260. // Input: s -- rule under consideration
  261. //
  262. // Output: Returns pointer to the extension past the path list
  263. //
  264. // Assumes: That the inference rule is syntactically correct & its syntax
  265. //
  266. // Notes: The syntax of a rule is -- {toPathList}.to{fromPathList}.from
  267. char *
  268. skipPathList(
  269. char *s
  270. )
  271. {
  272. if (*s == '{') {
  273. while (*s != '}') {
  274. if (*s == ESCH)
  275. s++;
  276. s = _tcsinc(s);
  277. }
  278. s = _tcsinc(s);
  279. }
  280. return(s);
  281. }
  282. // sortRules -- sorts the list of inference rules on .SUFFIXES order
  283. //
  284. // Scope: Global
  285. //
  286. // Purpose:
  287. // This function sorts the inference rules list into an order depending on the
  288. // order in which the suffixes are listed in '.SUFFIXES'. The inference rules
  289. // which have their '.toext' part listed earlier in .SUFFIXES are reordered to
  290. // be earlier in the inference rules list. The inference rules for suffixes that
  291. // are not in .SUFFIXES are detected here and are ignored.
  292. //
  293. // Modifies Globals:
  294. // rules -- the list of rules which gets sorted
  295. //
  296. // Uses Globals:
  297. // dotSuffixList -- the list of valid suffixes for implicit inference rules.
  298. //
  299. // Notes:
  300. // The syntax of a rule is -- '{toPath}.toExt{fromPath}.fromExt'. This function
  301. // sorts the rule list into an order. Suffixes are (as of 1.10.016) checked in a
  302. // case insensitive manner.
  303. PUBLIC void
  304. sortRules(
  305. void
  306. )
  307. {
  308. STRINGLIST *p, // suffix under consideration
  309. *s,
  310. *L_macros = NULL;
  311. RULELIST *oldRules, // inference rule list before sort
  312. *newRules,
  313. *r; // rule under consideration in oldRules
  314. char *suff, *toExt;
  315. size_t n;
  316. oldRules = rules;
  317. rules = NULL;
  318. for (p = dotSuffixList; p; p = p->next) {
  319. n = _tcslen(suff = p->text);
  320. for (r = oldRules; r;) {
  321. toExt = skipPathList(r->name);
  322. if (!_tcsnicmp(suff, toExt, n) &&
  323. (*(toExt+n) == '.' || *(toExt+n) == '{')
  324. ) {
  325. newRules = r;
  326. if (r->back)
  327. r->back->next = r->next;
  328. else
  329. oldRules = r->next;
  330. if (r->next)
  331. r->next->back = r->back;
  332. r = r->next;
  333. newRules->next = NULL;
  334. if (!removeDuplicateRules(newRules, rules)) {
  335. for (s = newRules->buildCommands; s; s = s->next) {
  336. findMacroValuesInRule(newRules, s->text, &L_macros);
  337. }
  338. newRules->buildMacros = L_macros;
  339. L_macros = NULL;
  340. appendItem((STRINGLIST**)&rules, (STRINGLIST*)newRules);
  341. }
  342. } else
  343. r = r->next;
  344. }
  345. }
  346. // forget about rules whose suffixes not in .SUFFIXES
  347. if (oldRules)
  348. freeRules(oldRules, TRUE);
  349. }
  350. // useRule -- applies inference rules for a target (if possible)
  351. //
  352. // Scope: Local.
  353. //
  354. // Purpose:
  355. // When no explicit commands are available for a target NMAKE tries to use the
  356. // available inference rules. useRule() checks if an applicable inference rule
  357. // is present. If such a rule is found then it attempts a build using this rule
  358. // and if no applicable rule is present it conveys this to the caller.
  359. //
  360. // Input:
  361. // object - object under consideration
  362. // name - name of target
  363. // targetTime - time of target
  364. // qList - QuestionList for target
  365. // sList - StarStarList for target
  366. // status - is dependent available
  367. // maxDepTime - maximum time of dependent
  368. // pFirstDep - first dependent
  369. //
  370. // Output:
  371. // Returns ... applicable rule
  372. RULELIST *
  373. useRule(
  374. MAKEOBJECT *object,
  375. char *name,
  376. time_t targetTime,
  377. STRINGLIST **qList,
  378. STRINGLIST **sList,
  379. int *status,
  380. time_t *maxDepTime,
  381. char **pFirstDep
  382. )
  383. {
  384. struct _finddata_t finddata;
  385. STRINGLIST *temp;
  386. RULELIST *r;
  387. time_t tempTime;
  388. char *t;
  389. if (!(t = _tcsrchr(object->name, '.')) ||
  390. (!(r = findRule(name, object->name, t, &finddata)))
  391. ) {
  392. return(NULL); // there is NO rule applicable
  393. }
  394. tempTime = getDateTime(&finddata);
  395. *pFirstDep = name;
  396. for (temp = *sList; temp; temp = temp->next) {
  397. if (!_tcsicmp(temp->text, name)) {
  398. break;
  399. }
  400. }
  401. if (temp) {
  402. CLEAR(object->flags2, F2_DISPLAY_FILE_DATES);
  403. }
  404. *status += invokeBuild(name, object->flags2, &tempTime, NULL);
  405. if (ON(object->flags2, F2_FORCE_BUILD) ||
  406. targetTime < tempTime ||
  407. (fRebuildOnTie && (targetTime == tempTime))
  408. ) {
  409. if (!temp) {
  410. temp = makeNewStrListElement();
  411. temp->text = makeString(name);
  412. appendItem(qList, temp);
  413. if (!*sList) { // if this is the only dep found for
  414. *sList = *qList; // the target, $** list is updated
  415. }
  416. }
  417. if (ON(object->flags2, F2_DISPLAY_FILE_DATES) &&
  418. OFF(object->flags2, F2_FORCE_BUILD)
  419. ) {
  420. makeMessage(UPDATE_INFO, name, object->name);
  421. }
  422. }
  423. *maxDepTime = __max(*maxDepTime, tempTime);
  424. return(r);
  425. }