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.

2068 lines
64 KiB

  1. // UTIL.C -- Data structure manipulation functions
  2. //
  3. // Copyright (c) 1988-1990, Microsoft Corporation. All rights reserved.
  4. //
  5. // Purpose:
  6. // This module contains routines manipulating the Data Structures of NMAKE. The
  7. // routines are independent of the Mode of execution (Real/Bound).
  8. //
  9. // Revision History:
  10. // 04-Feb-2000 BTF Ported to Win64
  11. // 01-Feb-1994 HV Turn off extra info display.
  12. // 17-Jan-1994 HV Fixed bug #3548: possible bug in findMacroValues because we
  13. // are scanning 'string' byte-by-byte instead of char-by-char
  14. // 15-Nov-1993 JdR Major speed improvements
  15. // 15-Oct-1993 HV Use tchar.h instead of mbstring.h directly, change STR*() to _ftcs*()
  16. // 03-Jun-1993 HV Add helper local function TruncateString for findFirst.
  17. // 10-May-1993 HV Add include file mbstring.h
  18. // Change the str* functions to STR*
  19. // 08-Apr-1993 HV Rewrite prependPath() to use _splitpath() and _makepath()
  20. // 31-Mar-1993 HV Rewrite drive(), path(), filename(), and extension() to use
  21. // _splitpath() instead of parsing the pathname by itself.
  22. // 08-Jun-1992 SS Port to DOSX32
  23. // 27-May-1992 RG Changed open_file to use _fsopen with _SH_DENYWR
  24. // 29-May-1990 SB ^$ was not becoming same as $$ for command lines ...
  25. // 01-May-1990 SB Nasty Preprocessor quirk bug in modifySpecialvalue() fixed
  26. // 27-Feb-1990 SB GP fault for '!if "$(debug"=="y"' fixed (bug t119)
  27. // 08-Feb-1990 SB GP fault for 'echo $(FOO:" =" ^) fixed
  28. // 06-Feb-1990 SB Handle $* etc in presence of Quoted names.
  29. // 02-Feb-1990 SB Add file_open() function
  30. // 31-Jan-1990 SB Debug changes; testAddr used to track problems at that addr
  31. // 08-Dec-1989 SB Changed SPRINTF() to avoid C6 warnings with -Oes
  32. // 04-Dec-1989 SB ZFormat() proto was misspelled as Zformat()
  33. // 01-Dec-1989 SB realloc_memory() added; allocate() uses _msize() now
  34. // 22-Nov-1989 SB Add strcmpiquote() and unQuote()
  35. // 22-Nov-1989 SB add #ifdef DEBUG_MEMORY funcs free_memory() and mem_status()
  36. // 13-Nov-1989 SB restoreEnv() function unreferenced
  37. // 08-Oct-1989 SB Added searchBucket(); find() now checks equivalence of quoted
  38. // and unquoted versions of a target.
  39. // 06-Sep-1989 SB $* in in-line files was clobbering Global variable 'buf'
  40. // 18-Aug-1989 SB heapdump() gets two parameters
  41. // 03-Jul-1989 SB moved curTime() to utilb.c and utilr.c to handle DOSONLY ver
  42. // 30-Jun-1989 SB added curTime() to get current Time.
  43. // 28-Jun-1989 SB changed copyEnviron()
  44. // 05-Jun-1989 SB makeString("") instead of using "" in DGROUP for null macro
  45. // 21-May-1989 SB modified find() to understand that targets 'foo.c', '.\foo.c'
  46. // and './foo.c' are the same.
  47. // 13-May-1989 SB Added functions path(), drive(), filename(), extension(),
  48. // strbskip(), strbscan() instead of ZTOOLS library
  49. // 12-May-1989 SB Fixed bug in substitute strings
  50. // 10-May-1989 SB Added stuff for ESCH handling changes in Quotes;
  51. // 01-May-1989 SB changed return value of allocate().
  52. // 14-Apr-1989 SB restoreEnv() created for macroBackInheritance
  53. // 05-Apr-1989 SB made all funcs NEAR; Reqd to make all function calls NEAR
  54. // 17-Mar-1989 SB substituteStrings() now has 3 new error checks & avoids GPs
  55. // 13-Mar-1989 SB ZFormat() was missing the legal case of '%%'
  56. // 22-Feb-1989 SB ZFormat() has buffer overflow check with extra parameter
  57. // and SPRINTF() gives a new error
  58. // 15-Feb-1989 SB Changed modifySpecialValue(), was not performing correctly
  59. // for $(@D) and $(@B) for some cases.
  60. // 13-Feb-1989 SB Made Prototypes for ZTools Library functions as extern
  61. // 5-Dec-1988 SB Made SPRINTF() cdecl as NMAKE now uses Pascal calling
  62. // 25-Nov-1988 SB Added SPRINTF() and ZFormat() and also added prototypes for
  63. // functions used from ZTools Library (6 of them)
  64. // 10-Nov-1988 SB Removed mixed mode functions (bound & real) to utilr.c
  65. // & utilb.c; corr globals/debug data also moved
  66. // 10-Oct-1988 SB Add Comments for hash().
  67. // 18-Sep-1988 RB Fix bad flag checking for targets in find().
  68. // 15-Sep-1988 RB Move some def's out to GLOBALS.
  69. // 22-Aug-1988 RB Don't find undefined macros.
  70. // 17-Aug-1988 RB Clean up. Clear memory in allocate().
  71. // 8-Jul-1988 rj Minor speedup (?) to find().
  72. // 7-Jul-1988 rj Modified find and hash; less efficient, but case-indep.
  73. // 1-Jul-1988 rj Fixed line truncation after null special macro.
  74. // 30-Jun-1988 rj Fixed bug with checkDynamicDependency not handling $$.
  75. // 29-Jun-1988 rj Fixed bug with extra * after expanding $**.
  76. // Fixed abysmal with $$(@?).
  77. // Fixed handling of F, B, R modifiers.
  78. // 22-Jun-1988 rj Added friendly filename truncation (findFirst).
  79. // 22-Jun-1988 rj Fixed bug #3 (.abc.def.ghi not detected).
  80. // 16-Jun-1988 rj Modified several routines to look for escape
  81. // character when walking through strings.
  82. // 27-May-1988 rb Fixed space-appending on list-expansion macros.
  83. // Don't include trailing path separator in $(@D).
  84. #include "precomp.h"
  85. #pragma hdrstop
  86. // Prototypes of functions local to this module
  87. void putValue(char**, char**, char**, char**, char*, unsigned*, char *);
  88. void substituteStrings(char**, char**, char**, char**, char*,
  89. unsigned*, char *);
  90. char * isolateMacroName(char*, char*);
  91. char * checkDynamicDependency(char*);
  92. void increaseBuffer(char**, char**, char**, unsigned*, char *);
  93. void putSpecial(char**, char**, char**, char**, unsigned*,
  94. unsigned, char *);
  95. char * modifySpecialValue(char, char*, char*);
  96. STRINGLIST * searchBucket(char *, STRINGLIST **, unsigned);
  97. int envVars(char **environ);
  98. // Prototypes of functions used by ZFormat from ZTools Library
  99. char * strbscan(char *, char *);
  100. char * strbskip(char *, char *);
  101. int drive(const char *, char *);
  102. int path(const char *, char *);
  103. int filenamepart(const char *, char *);
  104. int extension(const char *, char *);
  105. const char special1[] = "*@<?";
  106. const char special2[] = "DFBR";
  107. // These two variables are needed in order to provide
  108. // more informative error messages in case findMacroValue
  109. // detects an illegal macro in the command block of
  110. // a batch mode rule.
  111. static BOOL fFindingMacroInBatchRule = FALSE;
  112. static char * szBatchRuleName; // current rule name
  113. #if !defined(NDEBUG)
  114. size_t TotalAlloc;
  115. unsigned long CntAlloc;
  116. void
  117. printStats(
  118. void
  119. )
  120. {
  121. #if defined(STATISTICS)
  122. fprintf(stderr,"\n Memory Allocation:\n"
  123. " total allocation:\t%12.lu\n"
  124. " individual allocations:\t%12.lu\n"
  125. " Macros:\n"
  126. " searches:\t\t%12.lu\n"
  127. " chain walks:\t\t%12.lu\n"
  128. " insertions:\t\t%12.lu\n"
  129. "\n Targets:\n"
  130. " searches:\t\t%12.lu\n"
  131. " chain walks:\t\t%12.lu\n"
  132. "\n Others:\n"
  133. " stricmp compares:\t%12.lu\n"
  134. " String List frees:\t%12.lu\n"
  135. " String List allocs:\t%12.lu\n",
  136. TotalAlloc,
  137. CntAlloc,
  138. CntfindMacro,
  139. CntmacroChains,
  140. CntinsertMacro,
  141. CntfindTarget,
  142. CnttargetChains,
  143. CntStriCmp,
  144. CntFreeStrList,
  145. CntAllocStrList);
  146. #endif
  147. }
  148. #endif
  149. #define ALLOCBLKSIZE 32768
  150. unsigned long AllocFreeCnt;
  151. char * PtrAlloc;
  152. STRINGLIST *PtrFreeStrList;
  153. // rallocate - allocate raw memory (not cleared)
  154. //
  155. // Tries to allocate a chunk of memory, prints error message and exits if
  156. // the requested amount is not available.
  157. void *
  158. rallocate(
  159. size_t size
  160. )
  161. {
  162. void *chunk = malloc(size);
  163. if (chunk == NULL) {
  164. makeError(currentLine, OUT_OF_MEMORY);
  165. }
  166. #if !defined(NDEBUG)
  167. TotalAlloc += size;
  168. CntAlloc++;
  169. #endif
  170. return(chunk);
  171. }
  172. // allocate - allocate memory and clear it
  173. //
  174. // Tries to allocate a chunk of memory, prints error message and exits if
  175. // the requested amount is not available.
  176. // IMPORTANT: we must clear the memory here. Code elsewhere relies on this.
  177. void *
  178. allocate(
  179. size_t size // Number of bytes requested
  180. )
  181. {
  182. void *chunk = rallocate(size);
  183. memset(chunk, 0, size);
  184. return(chunk);
  185. }
  186. void *
  187. alloc_stringlist(
  188. void
  189. )
  190. {
  191. STRINGLIST *chunk;
  192. #if defined(STATISTICS)
  193. CntAllocStrList++;
  194. #endif
  195. if (PtrFreeStrList != NULL) {
  196. chunk = PtrFreeStrList;
  197. PtrFreeStrList = chunk->next;
  198. } else {
  199. if (AllocFreeCnt < sizeof(STRINGLIST)) {
  200. PtrAlloc = (char *) rallocate(ALLOCBLKSIZE);
  201. AllocFreeCnt = ALLOCBLKSIZE;
  202. }
  203. chunk = (STRINGLIST *) PtrAlloc;
  204. PtrAlloc += sizeof(STRINGLIST);
  205. AllocFreeCnt -= sizeof(STRINGLIST);
  206. }
  207. chunk->next = NULL;
  208. chunk->text = NULL;
  209. return (void *)chunk;
  210. }
  211. void
  212. free_stringlist(
  213. STRINGLIST *pMem
  214. )
  215. {
  216. #if !defined(NDEBUG)
  217. STRINGLIST *tmp;
  218. for (tmp = PtrFreeStrList; tmp != NULL; tmp = tmp->next) {
  219. if (tmp == pMem) {
  220. fprintf(stderr, "free same pointer twice: %p\n", pMem);
  221. return;
  222. }
  223. }
  224. pMem->text = NULL;
  225. #endif
  226. pMem->next = PtrFreeStrList;
  227. PtrFreeStrList = pMem;
  228. #if defined(STATISTICS)
  229. CntFreeStrList++;
  230. #endif
  231. }
  232. // allocate space, copies the given string into the newly allocated space, and
  233. // returns ptr.
  234. char *
  235. makeString(
  236. const char *s
  237. )
  238. {
  239. char *t;
  240. size_t l = _tcslen(s) + 1;
  241. t = (char *) rallocate(l);
  242. memcpy(t, s, l);
  243. return(t);
  244. }
  245. // like makeString, but creates quoted string
  246. char *
  247. makeQuotedString(
  248. const char *s
  249. )
  250. {
  251. char *t;
  252. size_t l = _tcslen(s);
  253. t = (char *) rallocate(l + 3);
  254. t[0] = '"';
  255. memcpy(t+1, s, l);
  256. t[l+1] = '"';
  257. t[l+2] = '\0';
  258. return(t);
  259. }
  260. // reallocate String sz1 and append sz2
  261. char *
  262. reallocString(
  263. char * szTarget,
  264. const char * szAppend
  265. )
  266. {
  267. char *szNew;
  268. size_t cbNew = _tcslen(szTarget) + _tcslen(szAppend) + 1;
  269. szNew = (char *) REALLOC(szTarget, cbNew);
  270. if (!szNew) {
  271. makeError(0, OUT_OF_MEMORY);
  272. return NULL;
  273. } else {
  274. return _tcscat(szNew, szAppend);
  275. }
  276. }
  277. // makes element the head of list
  278. void
  279. prependItem(
  280. STRINGLIST **list,
  281. STRINGLIST *element
  282. )
  283. {
  284. element->next = *list;
  285. *list = element;
  286. }
  287. // makes element the tail of list
  288. void
  289. appendItem(
  290. STRINGLIST **list,
  291. STRINGLIST *element
  292. )
  293. {
  294. for (; *list; list = &(*list)->next)
  295. ;
  296. *list = element;
  297. }
  298. // hash - returns hash value corresponding to a string
  299. //
  300. // Purpose:
  301. // This is a hash function. The hash function uses the following Algorithm --
  302. // Add the characters making up the string (s) to get N (ASCII values)
  303. // N mod total ,gives the hash value,
  304. // where, total is MAXMACRO for macros
  305. // MAXTARGET targets
  306. // Additionally, for targets it takes Uppercase Values alone, since, targets
  307. // are generally filenames and DOS/OS2 filenames are case independent.
  308. //
  309. // Input:
  310. // s = name for which a hash is required
  311. // total = Constant used in the hash function
  312. // targetFlag = boolean flag; true for targets, false for macros
  313. //
  314. // Output:
  315. // Returns hash value between 0 and (total-1)
  316. unsigned
  317. hash(
  318. char *s,
  319. unsigned total,
  320. BOOL targetFlag
  321. )
  322. {
  323. unsigned n;
  324. unsigned c;
  325. if (targetFlag) {
  326. for (n = 0; c = *s; (n += c), s++)
  327. if (c == '/') {
  328. c = '\\'; // slash == backslash in targets
  329. } else {
  330. c = _totupper(c); // lower-case == upper-case in targets
  331. }
  332. } else {
  333. for (n = 0; *s; n += *s++)
  334. ;
  335. }
  336. return(n % total);
  337. }
  338. // find - look up a string in a hash table
  339. //
  340. // Look up a macro or target name in a hash table and return the entry
  341. // or NULL.
  342. // If a macro and undefined, return NULL.
  343. // Targets get matched in a special way because of filename equivalence.
  344. STRINGLIST *
  345. find(
  346. char *str,
  347. unsigned limit,
  348. STRINGLIST *table[],
  349. BOOL targetFlag
  350. )
  351. {
  352. unsigned n;
  353. char *L_string = str;
  354. char *quote;
  355. STRINGLIST *found;
  356. BOOL fAllocStr = FALSE;
  357. if (*L_string) {
  358. n = hash(L_string, limit, targetFlag);
  359. if (targetFlag) {
  360. #if defined(STATISTICS)
  361. CntfindTarget++;
  362. #endif
  363. found = searchBucket(L_string, table, n);
  364. if (found) {
  365. return(found);
  366. }
  367. //Look for .\string
  368. if (!_tcsncmp(L_string, ".\\", 2) || !_tcsncmp(L_string, "./", 2)) {
  369. L_string += 2;
  370. } else {
  371. L_string = (char *)rallocate(2 + _tcslen(str) + 1);
  372. _tcscat(_tcscpy(L_string, ".\\"), str);
  373. fAllocStr = (BOOL)TRUE;
  374. }
  375. n = hash(L_string, limit, targetFlag);
  376. found = searchBucket(L_string, table, n);
  377. if (found) {
  378. if (fAllocStr) {
  379. FREE(L_string);
  380. }
  381. return(found);
  382. }
  383. // Look for ./string
  384. if (L_string != (str + 2)) {
  385. L_string[1] = '/';
  386. }
  387. n = hash(L_string, limit, targetFlag);
  388. found = searchBucket(L_string, table, n);
  389. if (fAllocStr) {
  390. FREE(L_string);
  391. }
  392. if (found) {
  393. return(found);
  394. }
  395. //Look for "foo" or foo
  396. if (*str == '"') {
  397. quote = unQuote(str);
  398. } else {
  399. size_t len = _tcslen(str) + 2;
  400. quote = (char *) allocate(len + 1);
  401. _tcscat(_tcscat(_tcscpy(quote, "\""), str), "\"");
  402. }
  403. n = hash(quote, limit, targetFlag);
  404. found = searchBucket(quote, table, n);
  405. FREE(quote);
  406. return found;
  407. }
  408. for (found = table[n]; found; found = found->next) {
  409. if (!_tcscmp(found->text, L_string)) {
  410. return((((MACRODEF *)found)->flags & M_UNDEFINED) ? NULL : found);
  411. }
  412. }
  413. }
  414. return(NULL);
  415. }
  416. // FINDMACROVALUES --
  417. // looks up a macro's value in hash table, prepends to list a STRINGLIST
  418. // element holding pointer to macro's text, then recurses on any macro
  419. // invocations in the value
  420. //
  421. // The lexer checks for overrun in names (they must be < 128 chars).
  422. // If a longer, undefined macro is only referred to in the value of
  423. // another macro which is never invoked, the error will not be flagged.
  424. // I think this is reasonable behavior.
  425. //
  426. // MACRO NAMES CAN ONLY CONSIST OF ALPHANUMERIC CHARS AND UNDERSCORE
  427. //
  428. // we pass a null list pointer-pointer if we just want to check for cyclical
  429. // definitions w/o building the list.
  430. //
  431. // the name parameter is what's on the left side of an = when we're just
  432. // checking cyclical definitions. When we "find" the macros in a target
  433. // block, we have to pass the name of the macro whose text we're recursing
  434. // on in our recursive call to findMacroValues().
  435. //
  436. // Might want to check into how to do this w/o recursion (is it possible?)
  437. //
  438. // This function is RECURSIVE.
  439. // Added a fix to make this function handle expand macros which refer
  440. // to other recursive macros.
  441. //
  442. // levelSeen is the recLevel at which a macroname was first seen so that
  443. // the appropriate expansion can be calculated (even when recursing ...)
  444. BOOL
  445. findMacroValues(
  446. char *string, // string to check
  447. STRINGLIST **list, // list to build
  448. STRINGLIST **newtail, // tail of list to update
  449. char *name, // name = string
  450. unsigned recLevel, // recursion level
  451. unsigned levelSeen,
  452. UCHAR flags
  453. )
  454. {
  455. char macroName[MAXNAME];
  456. char *s;
  457. MACRODEF *p;
  458. STRINGLIST *q, *r, dummy, *tail;
  459. unsigned i;
  460. BOOL inQuotes = (BOOL) FALSE; // flag when inside quote marks
  461. if (list) {
  462. if (newtail) {
  463. tail = *newtail;
  464. } else {
  465. tail = *list;
  466. if (tail) {
  467. while (tail->next) {
  468. tail = tail->next;
  469. }
  470. }
  471. }
  472. } else {
  473. tail = NULL;
  474. }
  475. for (s = string; *s; ++s) { // walk the string
  476. for (; *s && *s != '$'; s = _tcsinc(s)) { // find next macro
  477. if (*s == '\"')
  478. inQuotes = (BOOL) !inQuotes;
  479. if (!inQuotes && *s == ESCH) {
  480. ++s; // skip past ESCH
  481. if (*s == '\"')
  482. inQuotes = (BOOL) !inQuotes;
  483. }
  484. }
  485. if (!*s)
  486. break; // move past '$'
  487. if (!s[1])
  488. if (ON(flags, M_ENVIRONMENT_DEF)) {
  489. if (newtail)
  490. *newtail = tail;
  491. return(FALSE);
  492. } else
  493. makeError(currentLine, SYNTAX_ONE_DOLLAR);
  494. s = _tcsinc(s);
  495. if (!inQuotes && *s == ESCH) {
  496. s = _tcsinc(s);
  497. if (!MACRO_CHAR(*s))
  498. if (ON(flags, M_ENVIRONMENT_DEF)) {
  499. if (newtail)
  500. *newtail = tail;
  501. return(FALSE);
  502. } else
  503. makeError(currentLine, SYNTAX_BAD_CHAR, *s);
  504. }
  505. if (*s == '$') { // $$ = dynamic
  506. s = checkDynamicDependency(s); // dependency
  507. continue; // or just $$->$
  508. } else if (*s == '(') { // name is longer
  509. s = isolateMacroName(s+1, macroName); // than 1 char
  510. if (_tcschr(special1, *macroName)) {
  511. if (fFindingMacroInBatchRule && OFF(gFlags, F1_NO_BATCH)) {
  512. // we only allow $< in batch rules
  513. // so this is an error
  514. char * szBadMacro = (char *) malloc(_tcslen(macroName) + 4);
  515. if (szBadMacro) {
  516. sprintf(szBadMacro, "$(%s)", macroName);
  517. makeError(0, BAD_BATCH_MACRO, szBadMacro, szBatchRuleName);
  518. } else {
  519. makeError(0, OUT_OF_MEMORY);
  520. }
  521. }
  522. else
  523. continue;
  524. }
  525. } else {
  526. if (_tcschr(special1, *s)){
  527. if (fFindingMacroInBatchRule && OFF(gFlags, F1_NO_BATCH) && *s != '<') {
  528. char szBadMacro[3];
  529. szBadMacro[0] = '$';
  530. szBadMacro[1] = *s;
  531. szBadMacro[2] = '\0';
  532. // we only allow $< in batch rules
  533. // so this is an error
  534. makeError(0, BAD_BATCH_MACRO, szBadMacro, szBatchRuleName);
  535. }
  536. else
  537. continue; // 1-letter macro
  538. }
  539. if (!MACRO_CHAR(*s))
  540. if (ON(flags, M_ENVIRONMENT_DEF)) {
  541. if (newtail) *newtail = tail;
  542. return(FALSE);
  543. } else
  544. makeError(currentLine, SYNTAX_ONE_DOLLAR);
  545. macroName[0] = *s;
  546. macroName[1] = '\0';
  547. }
  548. // If list isn't NULL, allocate storage for a new node. Otherwise
  549. // this function was called purely to verify the macro name was
  550. // valid and we can just use the dummy node as a place holder.
  551. //
  552. // 2/28/92 BryanT dummy.text wasn't being initialized each
  553. // time. As a result, if we were to recurse
  554. // this function, whatever value was in text
  555. // on the last iteration is still there.
  556. // In the case where the macroName doesn't exist
  557. // in the the call to findMacro(), and the old
  558. // dummy->text field contained a '$', the
  559. // function would recurse infinitely.
  560. // Set to an empty string now
  561. //
  562. // q = (list) ? makeNewStrListElement() : &dummy;
  563. if (list != NULL) {
  564. q = makeNewStrListElement();
  565. } else {
  566. dummy.next = NULL;
  567. dummy.text = makeString(" ");
  568. q = &dummy;
  569. }
  570. if (p = findMacro(macroName)) {
  571. // macro names are case sensitive
  572. if (name && !_tcscmp(name, macroName)) { // self-refer-
  573. r = p->values; // ential macro
  574. for (i = recLevel; i != levelSeen && r; --i)
  575. r = r->next; // (a = $a;b)
  576. q->text = (r) ? r->text : makeString("");
  577. }
  578. else if (ON(p->flags, M_EXPANDING_THIS_ONE)) { // recursive def
  579. if (ON(flags, M_ENVIRONMENT_DEF)) {
  580. if (newtail) *newtail = tail;
  581. return(FALSE);
  582. } else
  583. makeError(currentLine, CYCLE_IN_MACRODEF, macroName);
  584. }
  585. else if (ON(p->flags, M_UNDEFINED)) {
  586. q->text = makeString(""); // if macro undefd [DS 18040]
  587. }
  588. else
  589. q->text = p->values->text;
  590. }
  591. if (list) { // if blding list
  592. if (!p || ON(p->flags, M_UNDEFINED))
  593. q->text = makeString(""); // if macro undefd
  594. q->next = NULL; // use NULL as its value
  595. if (tail) {
  596. tail->next = q;
  597. }else {
  598. *list = q;
  599. }
  600. tail = q;
  601. } // if found text,
  602. if (!p || !_tcschr(q->text, '$'))
  603. continue; // and found $ in
  604. SET(p->flags, M_EXPANDING_THIS_ONE); // text, recurse
  605. findMacroValues(q->text,
  606. list,
  607. &tail,
  608. macroName,
  609. recLevel+1,
  610. (name && _tcscmp(name, macroName)? recLevel : levelSeen),
  611. flags);
  612. CLEAR(p->flags, M_EXPANDING_THIS_ONE);
  613. }
  614. if (newtail) *newtail = tail;
  615. return(TRUE);
  616. }
  617. //
  618. // findMacroValuesInRule --
  619. // This is a wrapper around findMacroValues that generates an
  620. // error if an illegal special macro is referenced (directly
  621. // or indirectly) by the command block of a batch-mode rule
  622. //
  623. BOOL
  624. findMacroValuesInRule(
  625. RULELIST *pRule, // pointer to current rule
  626. char *string, // string to check
  627. STRINGLIST **list // list to build
  628. )
  629. {
  630. BOOL retval;
  631. if (fFindingMacroInBatchRule = pRule->fBatch)
  632. szBatchRuleName = pRule->name;
  633. retval = findMacroValues(string, list, NULL, NULL, 0, 0, 0);
  634. fFindingMacroInBatchRule = FALSE;
  635. return retval;
  636. }
  637. // isolateMacroName -- returns pointer to name of macro in extended invocation
  638. //
  639. // arguments: s pointer to macro invocation
  640. // macro pointer to location to store macro's name
  641. //
  642. // returns: pointer to end of macro's name
  643. //
  644. // isolates name and moves s
  645. char *
  646. isolateMacroName(
  647. char *s, // past closing paren
  648. char *macro // lexer already ckd for bad syntax
  649. )
  650. {
  651. char *t;
  652. for (t = macro; *s && *s != ')' && *s != ':'; t=_tcsinc(t), s=_tcsinc(s)) {
  653. if (*s == ESCH) {
  654. s++;
  655. if (!MACRO_CHAR(*s))
  656. makeError(currentLine, SYNTAX_BAD_CHAR, *s);
  657. }
  658. _tccpy(t, s);
  659. }
  660. while (*s != ')') {
  661. if (*s == ESCH)
  662. s++;
  663. if (!*s)
  664. break;
  665. s++;
  666. }
  667. if (*s != ')')
  668. makeError(currentLine, SYNTAX_NO_PAREN);
  669. *t = '\0';
  670. if (t - macro > MAXNAME)
  671. makeError(currentLine, NAME_TOO_LONG);
  672. return(s);
  673. }
  674. // figures out length of the special macro in question, and returns a ptr to
  675. // the char after the last char in the invocation
  676. char *
  677. checkDynamicDependency(
  678. char *s
  679. )
  680. {
  681. char *t;
  682. t = s + 1;
  683. if (*t == ESCH)
  684. return(t); // If $^, leave us at the ^
  685. if (*t == '(') {
  686. if (*++t == ESCH) {
  687. return(t);
  688. } else {
  689. if (*t == '@') {
  690. if (*++t == ESCH)
  691. makeError(currentLine, SYNTAX_BAD_CHAR, *++t);
  692. else if (*t == ')')
  693. return(t);
  694. else if (_tcschr(special2, *t)) {
  695. if (*++t == ESCH)
  696. makeError(currentLine, SYNTAX_BAD_CHAR, *++t);
  697. else if (*t == ')')
  698. return(t);
  699. }
  700. } else {
  701. t = s + 1; // invalid spec. mac.
  702. if (*t == ESCH)
  703. return(t); // evals. to $(
  704. return(++t);
  705. }
  706. }
  707. }
  708. return(s); // char matched
  709. }
  710. // removes and expands any macros that exist in the string macroStr.
  711. // could return a different string (in case expandMacros needs more
  712. // buffer size for macro expansion. it is the caller's responsibility
  713. // to free the string soon as it is not required....
  714. char *
  715. removeMacros(
  716. char *macroStr
  717. )
  718. {
  719. STRINGLIST *eMacros = NULL;
  720. STRINGLIST *m;
  721. if (_tcschr(macroStr, '$')) {
  722. findMacroValues(macroStr, &eMacros, NULL, NULL, 0, 0, 0);
  723. m = eMacros;
  724. macroStr = expandMacros(macroStr, &eMacros);
  725. while (eMacros = m) {
  726. m = m->next;
  727. FREE_STRINGLIST(eMacros);
  728. }
  729. }
  730. return(macroStr);
  731. }
  732. // expandMacros -- expand all macros in a string s
  733. //
  734. // arguments: s string to expand
  735. // macros list of macros being expanded (for recursive calls)
  736. //
  737. // actions: allocate room for expanded string
  738. // look for macros in string (handling ESCH properly (v1.5))
  739. // parse macro--determine its type
  740. // use putSpecial to handle special macros
  741. // recurse on list of macros
  742. // use putValue to put value of just-found macro in string
  743. // return expanded string
  744. //
  745. // returns: string with all macros expanded
  746. //
  747. // CALLER CHECKS TO SEE IF _tcschr(STRING, '$') IN ORER TO CALL THIS.
  748. // this doesn't work for HUGE macros yet. need to make data far.
  749. //
  750. // we save the original string and the list of ptrs to macro values
  751. // to be substituted.
  752. // the caller has to free the expansion buffer
  753. //
  754. // expandMacros updates the macros pointer and frees the skipped elements
  755. char *
  756. expandMacros(
  757. char *s, // text to expand
  758. STRINGLIST **macros
  759. )
  760. {
  761. STRINGLIST *p;
  762. char *t, *end;
  763. char *text, *xresult;
  764. BOOL inQuotes = (BOOL) FALSE; // flag when inside quote marks
  765. char *w;
  766. BOOL freeFlag = FALSE;
  767. char resultbuffer[MAXBUF];
  768. unsigned len = MAXBUF;
  769. char *result = resultbuffer;
  770. end = result + MAXBUF;
  771. for (t = result; *s;) { // look for macros
  772. for (; *s && *s != '$'; *t++ = *s++) { // as we copy the string
  773. if (t == end) {
  774. increaseBuffer(&result, &t, &end, &len, &resultbuffer[0]);
  775. }
  776. if (*s == '\"')
  777. inQuotes = (BOOL) !inQuotes;
  778. if (!inQuotes && *s == ESCH) {
  779. *t++ = ESCH;
  780. if (t == end) {
  781. increaseBuffer(&result, &t, &end, &len, &resultbuffer[0]);
  782. }
  783. s++;
  784. if (*s == '\"')
  785. inQuotes = (BOOL) !inQuotes;
  786. }
  787. }
  788. if (t == end) { // string
  789. increaseBuffer(&result, &t, &end, &len, &resultbuffer[0]);
  790. }
  791. if (!*s)
  792. break; // s exhausted
  793. w = (s+1); // don't check for ^ here; already did in findMacroValues
  794. if (*w == '(' // found a macro
  795. && _tcschr(special1, *(w+1))) {
  796. putSpecial(&result, &s, &t, &end, &len, X_SPECIAL_MACRO, &resultbuffer[0]);
  797. continue;
  798. } else
  799. if (*w++ == '$') { // double ($$)
  800. if (*w == ESCH) // $$^...
  801. putSpecial(&result, &s, &t, &end, &len, DOLLAR_MACRO, &resultbuffer[0]);
  802. else if (*w == '@') // $$@
  803. putSpecial(&result, &s, &t, &end, &len, DYNAMIC_MACRO, &resultbuffer[0]);
  804. else if ((*w == '(') && (*++w == '@') && (*w == ')'))
  805. putSpecial(&result, &s, &t, &end, &len, DYNAMIC_MACRO, &resultbuffer[0]);
  806. else if (((*++w=='F') || (*w=='D') || (*w=='B') || (*w=='R')) && (*++w == ')'))
  807. putSpecial(&result, &s, &t, &end, &len, X_DYNAMIC_MACRO, &resultbuffer[0]);
  808. else // $$
  809. putSpecial(&result, &s, &t, &end, &len, DOLLAR_MACRO, &resultbuffer[0]);
  810. continue;
  811. } else
  812. if (_tcschr(special1, s[1])) { // $?*<
  813. putSpecial(&result, &s, &t, &end, &len, SPECIAL_MACRO, &resultbuffer[0]);
  814. continue;
  815. }
  816. if (!*macros)
  817. makeError(currentLine, MACRO_INTERNAL);
  818. // skip this element in the macros list
  819. if (_tcschr((*macros)->text, '$')) { // recurse
  820. p = *macros;
  821. *macros = (*macros)->next;
  822. text = expandMacros(p->text, macros);
  823. freeFlag = TRUE;
  824. } else {
  825. text = (*macros)->text;
  826. *macros = (*macros)->next;
  827. }
  828. putValue(&result, &s, &t, &end, text, &len, &resultbuffer[0]);
  829. if (freeFlag) {
  830. FREE(text);
  831. freeFlag = FALSE;
  832. }
  833. }
  834. if (t == end) {
  835. increaseBuffer(&result, &t, &end, &len, &resultbuffer[0]);
  836. }
  837. *t++ = '\0';
  838. // Allocate result buffer
  839. if (!(xresult = (char *) rallocate((size_t) (t - result)))) {
  840. makeError(currentLine, MACRO_TOO_LONG);
  841. }
  842. memcpy(xresult, result, (size_t) (t - result));
  843. return(xresult);
  844. }
  845. // increaseBuffer -- increase the size of a string buffer, with error check
  846. //
  847. // arguments: result pointer to pointer to start of buffer
  848. // t pointer to pointer to end of buffer (before expansion)
  849. // end pointer to pointer to end of buffer (after expansion)
  850. // len pointer to amount by which to expand buffer
  851. // first address of initial stack buffer
  852. //
  853. // actions: check for out of memory
  854. // allocate new buffer
  855. // reset pointers properly
  856. //
  857. // modifies: t, end to point to previous end and new end of buffer
  858. //
  859. // uses 0 as line number because by the time we hit an error in this routine,
  860. // the line number will be set at the last line of the makefile (because we'll
  861. // have already read and parsed the file)
  862. void
  863. increaseBuffer(
  864. char **result,
  865. char **t,
  866. char **end,
  867. unsigned *len,
  868. char *first
  869. )
  870. {
  871. unsigned newSize;
  872. void *pv;
  873. // determine if result points to the firstbuffer and make a dynamic copy first.
  874. if (*result == first) {
  875. char *p = (char *) rallocate(*len);
  876. memcpy(p, *result, *len);
  877. *result = p;
  878. }
  879. newSize = *len + MAXBUF;
  880. #ifdef DEBUG
  881. if (fDebug) {
  882. fprintf(stderr,"\t\tAttempting to reallocate %d bytes to %d\n", *len, newSize);
  883. }
  884. #endif
  885. pv = REALLOC(*result, newSize);
  886. if (!pv) {
  887. makeError(currentLine, MACRO_TOO_LONG);
  888. } else {
  889. *result =(char *)pv;
  890. *t = *result + *len; // reset pointers, len
  891. *len = newSize;
  892. *end = *result + *len;
  893. }
  894. }
  895. // putSpecial -- expand value of special macro
  896. //
  897. // arguments: result ppointer to start of string being expanded
  898. // name ppointer to macro name being expanded
  899. // dest ppointer to place to store expanded value
  900. // end ppointer to end of dest's buffer
  901. // length pointer to amount by which to increase dest's buffer
  902. // which ype of special macro
  903. // first address of initial stack buffer
  904. //
  905. // actions: depending on type of macro, set "value" equal to macro's value
  906. // if macro expands to a list, store whole list in "value" ($?, $*)
  907. // otherwise, modify value according to F, B, D, R flag
  908. // use putValue to insert the value in dest
  909. //
  910. // has to detect error if user tries $* etc. when they aren't defined
  911. // fix to handle string substitutions, whitespace around names, etc
  912. // right now list macros are limited to 1024 bytes total
  913. void
  914. putSpecial(
  915. char **result,
  916. char **name,
  917. char **dest,
  918. char **end,
  919. unsigned *length,
  920. unsigned which,
  921. char *first
  922. )
  923. {
  924. char *value = 0;
  925. STRINGLIST *p;
  926. BOOL listMacro = FALSE, modifier = FALSE, star = FALSE;
  927. unsigned i = 1;
  928. char c, nameBuf[MAXNAME], *temp;
  929. switch (which) {
  930. case X_SPECIAL_MACRO:
  931. i = 2;
  932. modifier = TRUE;
  933. case SPECIAL_MACRO:
  934. switch ((*name)[i]) {
  935. case '<':
  936. value = dollarLessThan;
  937. break;
  938. case '@':
  939. value = dollarAt;
  940. break;
  941. case '?':
  942. value = (char*) dollarQuestion;
  943. listMacro = TRUE;
  944. break;
  945. case '*':
  946. if ((*name)[i+1] != '*') {
  947. value = dollarStar;
  948. star = TRUE;
  949. break;
  950. }
  951. value = (char*) dollarStarStar;
  952. listMacro = TRUE;
  953. ++i;
  954. break;
  955. default:
  956. break;
  957. }
  958. ++i;
  959. break;
  960. case X_DYNAMIC_MACRO:
  961. i = 4;
  962. modifier = TRUE;
  963. case DYNAMIC_MACRO:
  964. value = dollarDollarAt;
  965. break;
  966. case DOLLAR_MACRO:
  967. if (*dest == *end)
  968. increaseBuffer(result, dest, end, length, first);
  969. *(*dest)++ = '$';
  970. *name += 2;
  971. return;
  972. default:
  973. return; // can't happen
  974. }
  975. if (!value) {
  976. for (temp = *name; *temp && *temp != ' ' && *temp != '\t'; temp++)
  977. ;
  978. c = *temp; *temp = '\0';
  979. makeError(currentLine, ILLEGAL_SPECIAL_MACRO, *name);
  980. *temp = c;
  981. listMacro = FALSE;
  982. value = makeString(""); // value is freed below, must be on heap [rm]
  983. }
  984. if (listMacro) {
  985. char *pVal, *endVal;
  986. unsigned lenVal = MAXBUF;
  987. p = (STRINGLIST*) value;
  988. pVal = (char *)allocate(MAXBUF);
  989. endVal = pVal + MAXBUF;
  990. for (value = pVal; p; p = p->next) {
  991. temp = p->text;
  992. if (modifier)
  993. temp = modifySpecialValue((*name)[i], nameBuf, temp);
  994. while(*temp) {
  995. if (value == endVal)
  996. increaseBuffer(&pVal, &value, &endVal, &lenVal, NULL);
  997. *value++ = *temp++;
  998. }
  999. if (value == endVal)
  1000. increaseBuffer(&pVal, &value, &endVal, &lenVal, NULL);
  1001. *value = '\0';
  1002. // Append a space if there are more elements in the list. [RB]
  1003. if (p->next) {
  1004. *value++ = ' ';
  1005. if (value == endVal)
  1006. increaseBuffer(&pVal, &value, &endVal, &lenVal, NULL);
  1007. *value = '\0';
  1008. }
  1009. }
  1010. value = pVal;
  1011. } else {
  1012. //For some reason 'buf' was being used here clobbering global 'buf
  1013. // instead of nameBuf
  1014. if (star)
  1015. value = modifySpecialValue('R', nameBuf, value);
  1016. if (modifier)
  1017. value = modifySpecialValue((*name)[i], nameBuf, value);
  1018. }
  1019. putValue(result, name, dest, end, value, length, first);
  1020. if (value != dollarAt &&
  1021. value != dollarDollarAt &&
  1022. value != dollarLessThan &&
  1023. (value < nameBuf || value >= nameBuf + MAXNAME)
  1024. )
  1025. FREE(value);
  1026. }
  1027. // modifySpecialValue -- alter path name according to modifier
  1028. //
  1029. // Scope: Local.
  1030. //
  1031. // Purpose:
  1032. // The dynamic macros of NMAKE have modifiers F,B,D & R. This routine does the
  1033. // job of producing a modified special value for a given filename.
  1034. //
  1035. // Input:
  1036. // c -- determines the type of modification (modifier is one of F,B,D & R
  1037. // buf -- location for storing modified value
  1038. // value -- The path specification to be modified
  1039. //
  1040. // Output: Returns a pointer to the modified value
  1041. //
  1042. // Assumes: That initially buf pointed to previously allocated memory of size MAXNAME.
  1043. //
  1044. // Notes:
  1045. // Given a path specification of the type "<drive:><path><filename><.ext>", the
  1046. // modifiers F,B,D and R stand for following --
  1047. // F - <filename><.ext> - actual Filename
  1048. // B - <filename> - Base filename
  1049. // D - <drive:><path> - Directory
  1050. // R - <drive:><path><filename> - Real filename (filename without extension)
  1051. // This routine handles OS/2 1.20 filenames as well. The last period in the
  1052. // path specification is the start of the extension. When directory part is null
  1053. // the function returns '.' for current directory.
  1054. //
  1055. // This function now handles quoted filenames too
  1056. char *
  1057. modifySpecialValue(
  1058. char c,
  1059. char *buf,
  1060. char *value
  1061. )
  1062. {
  1063. char *lastSlash, // last path separator from "\\/"
  1064. *extension; // points to the extension
  1065. char *saveBuf;
  1066. BOOL fQuoted;
  1067. lastSlash = extension = NULL;
  1068. saveBuf=buf;
  1069. _tcscpy(buf, value);
  1070. fQuoted = (BOOL) (buf[0] == '"');
  1071. value = buf + _tcslen(buf) - 1; // start from the end of pathname
  1072. for (;value >= buf; value--) {
  1073. if (PATH_SEPARATOR(*value)) { // scan upto first path separator
  1074. lastSlash = value;
  1075. break;
  1076. } else
  1077. if (*value == '.' && !extension) //last '.' is extension
  1078. extension = value;
  1079. }
  1080. switch(c) {
  1081. case 'D':
  1082. if (lastSlash) {
  1083. if (buf[1] == ':' && lastSlash == buf + 2)
  1084. ++lastSlash; // 'd:\foo.obj' --> 'd:\'
  1085. *lastSlash = '\0';
  1086. } else if (buf[1] == ':')
  1087. buf[2] = '\0'; // 'd:foo.obj' --> 'd:'
  1088. else
  1089. _tcscpy(buf, "."); // 'foo.obj' --> '.'
  1090. break;
  1091. case 'B':
  1092. if (extension) // for 'B' extension is clobbered
  1093. *extension = '\0';
  1094. case 'F':
  1095. if (lastSlash)
  1096. buf = lastSlash + 1;
  1097. else if (buf[1] == ':') // 'd:foo.obj' --> foo for B
  1098. buf+=2; // 'd:foo.obj' --> foo.obj for F
  1099. break;
  1100. case 'R':
  1101. if (extension)
  1102. *extension = '\0'; // extension clobbered
  1103. }
  1104. if (fQuoted) { // [fabriced] make sure we have quotes
  1105. char *pEnd; // at both ends
  1106. if(*buf!='"' && buf>saveBuf) { // make sure we can go back one char
  1107. buf--;
  1108. *buf='"';
  1109. }
  1110. pEnd = _tcschr(buf, '\0');
  1111. if(*(pEnd-1)!='"') {
  1112. *pEnd++ = '"';
  1113. *pEnd = '\0';
  1114. }
  1115. }
  1116. return(buf);
  1117. }
  1118. // putValue -- store expanded macro's value in dest and advance past it
  1119. //
  1120. // arguments: result ppointer to start of string being expanded
  1121. // name ppointer to macro name being expanded
  1122. // dest ppointer to place to store expanded value
  1123. // end ppointer to end of dest's buffer
  1124. // source pointer to text of expanded macro
  1125. // length pointer to amount by which to increase dest's buffer
  1126. // first address of initial stack buffer
  1127. //
  1128. // actions: if there is a substitution, call substituteStrings to do it
  1129. // else copy source text into dest
  1130. // advance *name past end of macro's invocation
  1131. //
  1132. // already did error checking in lexer
  1133. void
  1134. putValue(
  1135. char **result,
  1136. char **name,
  1137. char **dest,
  1138. char **end,
  1139. char *source,
  1140. unsigned *length,
  1141. char *first
  1142. )
  1143. {
  1144. char *s;
  1145. char *t; // temporary pointer
  1146. if (*++*name == ESCH)
  1147. ++*name; // go past $ & ESCH if any
  1148. s = _tcschr(*name, ':');
  1149. for (t = *name; *t && *t != ')'; t++) // go find first non-escaped )
  1150. if (*t == ESCH)
  1151. t++;
  1152. if ((**name == '(') // substitute only if there is
  1153. && s // a : before a non-escaped )
  1154. && (s < t)
  1155. ) {
  1156. substituteStrings(result, &s, dest, end, source, length, first);
  1157. *name = s;
  1158. } else {
  1159. for (; *source; *(*dest)++ = *source++) // copy source into dest
  1160. if (*dest == *end)
  1161. increaseBuffer(result, dest, end, length, first);
  1162. if (**name == '$')
  1163. ++*name; // go past $$
  1164. if (**name == '(') // advance from ( to )
  1165. while (*++*name != ')');
  1166. else
  1167. if (**name == '*' && *(*name + 1) == '*')
  1168. ++*name; // skip $**
  1169. ++*name; // move all the way past
  1170. }
  1171. }
  1172. // substituteStrings -- perform macro substitution
  1173. //
  1174. // arguments: result ppointer to start of string being expanded
  1175. // name ppointer to macro name being expanded
  1176. // dest ppointer to place to store substituted value
  1177. // end ppointer to end of dest's buffer
  1178. // source pointer to text of expanded macro (before sub.)
  1179. // length pointer to amount by which to increase dest's buffer
  1180. // first address of initial stack buffer
  1181. //
  1182. // changes: [SB]
  1183. // old, new now dynamically allocated; saves memory; 3 errors detected
  1184. // for macro syntax in script files.
  1185. //
  1186. // note: [SB]
  1187. // we could use lexer routines recursively if we get rid of the globals
  1188. // and then these errors needn't be flagged. [?]
  1189. //
  1190. // actions: store text to convert from in old
  1191. // store text to convert to in new
  1192. // scan source text
  1193. // when a match is found, copy new text into dest &
  1194. // skip over old text
  1195. // else copy one character from source text into dest
  1196. //
  1197. // returns: nothing
  1198. void
  1199. substituteStrings(
  1200. char **result,
  1201. char **name,
  1202. char **dest,
  1203. char **end,
  1204. char *source,
  1205. unsigned *length,
  1206. char *first
  1207. )
  1208. {
  1209. char *oldString, *newString;
  1210. char *pEq, *pPar, *t;
  1211. char *s;
  1212. size_t i;
  1213. ++*name;
  1214. for (pEq = *name; *pEq && *pEq != '='; pEq++)
  1215. if (*pEq == ESCH)
  1216. pEq++;
  1217. if (*pEq != '=')
  1218. makeError(line, SYNTAX_NO_EQUALS);
  1219. if (pEq == *name)
  1220. makeError(line, SYNTAX_NO_SEQUENCE);
  1221. for (pPar = pEq; *pPar && *pPar != ')'; pPar++)
  1222. if (*pPar == ESCH)
  1223. pPar++;
  1224. if (*pPar != ')')
  1225. makeError(line, SYNTAX_NO_PAREN);
  1226. oldString = (char *) allocate((size_t) ((pEq - *name) + 1));
  1227. for (s = oldString, t = *name; *t != '='; *s++ = *t++)
  1228. if (*t == ESCH)
  1229. ++t;
  1230. *s = '\0';
  1231. i = _tcslen(oldString);
  1232. newString = (char *) allocate((size_t) (pPar - pEq));
  1233. for (s = newString, t++; *t != ')'; *s++ = *t++)
  1234. if (*t == ESCH)
  1235. ++t;
  1236. *s = '\0';
  1237. *name = pPar + 1;
  1238. while (*source) {
  1239. if ((*source == *oldString) // check for match
  1240. && !_tcsncmp(source, oldString, i)) { // copy new in for
  1241. for (s = newString; *s; *(*dest)++ = *s++) // old string
  1242. if (*dest == *end)
  1243. increaseBuffer(result, dest, end, length, first);
  1244. source += i;
  1245. continue;
  1246. }
  1247. if (*dest == *end)
  1248. increaseBuffer(result, dest, end, length, first);
  1249. *(*dest)++ = *source++; // else copy 1 char
  1250. }
  1251. FREE(oldString);
  1252. FREE(newString);
  1253. }
  1254. // prependPath -- prepend the path from pszWildcard to pszFilename
  1255. //
  1256. // Scope: Global.
  1257. //
  1258. // Purpose:
  1259. // This function is called to first extract the path (drive & dir parts) from
  1260. // pszWildcard, the prepend that path to pszFilename. The result string is
  1261. // a reconstruction of the full pathname. Normally, the pszWildcard parameter
  1262. // is the same as the first parameter supplied to findFirst(), and pszFilename
  1263. // is what returned by findFirst/findNext.
  1264. //
  1265. // Input:
  1266. // pszWildcard -- Same as the first parameter supplied to findFirst()
  1267. // pszFilename -- Same as the return value of findFirst/FindNext()
  1268. //
  1269. // Output:
  1270. // Return the reconstructed full pathname. The user must be responsible to
  1271. // free up the memory allocated by this string.
  1272. //
  1273. // Assumes:
  1274. // Since pszWildcard, the first parameter to findFirst() must include a filename
  1275. // part; this is what I assume. If the filename part is missing, then
  1276. // _splitpath will mistaken the directory part of pszWildcard as the filename
  1277. // part and things will be very ugly.
  1278. //
  1279. // History:
  1280. // 08-Apr-1993 HV Rewrite prependPath() to use _splitpath() and _makepath()
  1281. char *
  1282. prependPath(
  1283. const char *pszWildcard,
  1284. const char *pszFilename
  1285. )
  1286. {
  1287. // The following are the components when breaking up pszWildcard
  1288. char szDrive[_MAX_DRIVE];
  1289. char szDir[_MAX_DIR];
  1290. // The following are the resulting full pathname.
  1291. char szPath[_MAX_PATH];
  1292. char *pszResultPath;
  1293. // First break up the pszWildcard, throwing away the filename and the
  1294. // extension parts.
  1295. _splitpath(pszWildcard, szDrive, szDir, NULL, NULL);
  1296. // Then, glue the drive & dir components of pszWildcard to pszFilename
  1297. _makepath(szPath, szDrive, szDir, pszFilename, NULL);
  1298. // Make a copy of the resulting string and return it.
  1299. pszResultPath = makeString(szPath);
  1300. return (pszResultPath);
  1301. }
  1302. // isRule -- examines a string to determine whether it's a rule definition
  1303. //
  1304. // arguments: s string to examine for rule-ness
  1305. //
  1306. // actions: assume it's not a rule
  1307. // skip past first brace pair (if any)
  1308. // if next character is a period,
  1309. // look for next brace
  1310. // if there are no path separators between second brace pair,
  1311. // and there's just a suffix after them, it's a rule
  1312. // else if there's another period later on, and no path seps
  1313. // after it, then it's a rule.
  1314. //
  1315. // returns: TRUE if it's a rule, FALSE otherwise.
  1316. BOOL
  1317. isRule(
  1318. char *s
  1319. )
  1320. {
  1321. char *t = s, *u;
  1322. BOOL result = FALSE;
  1323. if (*t == '{') { // 1st char is {, so
  1324. while (*++t && *t != '}') // we skip over rest
  1325. if (*t == ESCH)
  1326. ++t;
  1327. if (*t)
  1328. ++t; // of path (no error
  1329. } // checking)
  1330. if (*t == '.') {
  1331. for (u = t; *u && *u != '{'; ++u) // find first non-escaped {
  1332. if (*u == ESCH)
  1333. ++u;
  1334. s = t;
  1335. while (t < u) { // look for path seps.
  1336. if (PATH_SEPARATOR(*t))
  1337. break; // if we find any, it's
  1338. ++t; // not a rule (they
  1339. } // can't be in suffix)
  1340. if (*u && (t == u)) { // if not at end & no path sep
  1341. while (*++u && *u != '}') // find first non-esc }
  1342. if (*u == ESCH)
  1343. ++u;
  1344. if (*u) {
  1345. ++u;
  1346. if (*u == '.' // if you find it, with . just
  1347. && !_tcschr(u+1, '/' ) // next to it & no path seps.,
  1348. && !_tcschr(u+1, '\\')) // it's a rule
  1349. if (_tcschr(u+1, '.')) // too many suffixes
  1350. makeError(currentLine, TOO_MANY_RULE_NAMES);
  1351. else
  1352. result = TRUE;
  1353. }
  1354. } else if (((u = _tcspbrk(s+1, "./\\")) && (*u == '.'))
  1355. && !_tcschr(u+1, '/')
  1356. && !_tcschr(u+1, '\\'))
  1357. if (_tcschr(u+1, '.')) // too many suffixes
  1358. makeError(currentLine, TOO_MANY_RULE_NAMES);
  1359. else
  1360. result = TRUE;
  1361. }
  1362. return(result);
  1363. }
  1364. // ZFormat - extmake syntax worker routine.
  1365. //
  1366. // pStr destination string where formatted result is placed.
  1367. // fmt formatting string. The valid extmake syntax is ...
  1368. // %% is always %
  1369. // %s is the first dependent filename
  1370. // %|<dpfe>F is the appropriate portion out of %s
  1371. // d drive
  1372. // p path
  1373. // f filename
  1374. // e extension
  1375. // %|F same as %s
  1376. // One needn't escape a %, unless it is a valid extmake syntax
  1377. // pFirstDep is the dependent filename used for expansion
  1378. BOOL
  1379. ZFormat(
  1380. char *pStr,
  1381. unsigned limit,
  1382. char *fmt,
  1383. char *pFirstDep
  1384. )
  1385. {
  1386. char c;
  1387. char *pEnd = pStr + limit;
  1388. char *s;
  1389. BOOL fError;
  1390. BOOL fDrive;
  1391. BOOL fPath;
  1392. BOOL fFilename;
  1393. BOOL fExtension;
  1394. char L_buf[_MAX_PATH];
  1395. for (; (c = *fmt) && (pStr < pEnd); fmt++) {
  1396. if (c != '%') {
  1397. *pStr++ = c;
  1398. } else {
  1399. switch (*++fmt) {
  1400. case '%': // '%%' -> '%'
  1401. *pStr++ = '%';
  1402. break;
  1403. case 's':
  1404. for (s = pFirstDep; s && *s && pStr < pEnd; *pStr++ = *s++)
  1405. ;
  1406. break;
  1407. case '|':
  1408. s = fmt-1;
  1409. fError = fDrive = fPath = fFilename = fExtension = FALSE;
  1410. *L_buf = '\0';
  1411. do {
  1412. switch (*++fmt) {
  1413. case 'd':
  1414. fDrive = TRUE;
  1415. break;
  1416. case 'p':
  1417. fPath = TRUE;
  1418. break;
  1419. case 'f':
  1420. fFilename = TRUE;
  1421. break;
  1422. case 'e':
  1423. fExtension = TRUE;
  1424. break;
  1425. case 'F':
  1426. if (fmt[-1] == '|') {
  1427. fDrive = TRUE;
  1428. fPath = TRUE;
  1429. fFilename = TRUE;
  1430. fExtension = TRUE;
  1431. }
  1432. break;
  1433. case '\0':
  1434. // backtrack, so that we don't read past
  1435. // the end of the string in the for loop
  1436. // [msdev96 #4057]
  1437. fmt--;
  1438. // fall trhough
  1439. default :
  1440. fError = TRUE;
  1441. break;
  1442. }
  1443. if (fError) {
  1444. break;
  1445. }
  1446. } while (*fmt != 'F');
  1447. if (fError) {
  1448. for (; s <= fmt && pStr < pEnd; *pStr++ = *s++)
  1449. ;
  1450. break;
  1451. }
  1452. if (!pFirstDep) {
  1453. makeError(0, EXTMAKE_NO_FILENAME);
  1454. }
  1455. if (fDrive) {
  1456. drive(pFirstDep, L_buf);
  1457. }
  1458. if (fPath) {
  1459. path(pFirstDep, strend(L_buf));
  1460. }
  1461. if (fFilename) {
  1462. filenamepart(pFirstDep, strend(L_buf));
  1463. }
  1464. if (fExtension) {
  1465. extension(pFirstDep, strend(L_buf));
  1466. }
  1467. for (s = L_buf; *s && pStr < pEnd; *pStr++ = *s++)
  1468. ;
  1469. break;
  1470. case '\0':
  1471. // backtrack, so that we don't read past
  1472. // the end of the string in the for loop
  1473. // [msdev96 #4057]
  1474. fmt--;
  1475. // *pStr++ = '%';
  1476. break;
  1477. default:
  1478. *pStr++ = '%';
  1479. if (pStr == pEnd) {
  1480. return(TRUE);
  1481. }
  1482. *pStr++ = *fmt;
  1483. break;
  1484. }
  1485. }
  1486. }
  1487. if (pStr < pEnd) {
  1488. *pStr = '\0';
  1489. return(FALSE);
  1490. }
  1491. return(TRUE);
  1492. }
  1493. void
  1494. expandExtmake(
  1495. char *buf,
  1496. char *fmt,
  1497. char *pFirstDep
  1498. )
  1499. {
  1500. if (ZFormat(buf, MAXCMDLINELENGTH, fmt, pFirstDep))
  1501. makeError(0, COMMAND_TOO_LONG, fmt);
  1502. }
  1503. // drive -- copy a drive from source to dest if present
  1504. //
  1505. // Scope: Local.
  1506. //
  1507. // Purpose: copy a drive from source to dest if present, return TRUE if we found one
  1508. //
  1509. // Input:
  1510. // const char *src -- The full path to extract the drive from.
  1511. // char *dst -- The buffer to copy the drive to, must be alloc'd before.
  1512. //
  1513. // Output: Return TRUE if a drive part is found, else return FALSE.
  1514. //
  1515. // Assumes:
  1516. // 1. src is a legal pathname.
  1517. // 2. src does not contain network path (i.e. \\foo\bar)
  1518. // 3. The buffer dst is large enough to contain the result.
  1519. // 4. src does not contain quote since _splitpath() treat quotes a normal char.
  1520. //
  1521. // History:
  1522. // 31-Mar-1993 HV Rewrite drive(), path(), filenamepart(), and extension() to use
  1523. // _splitpath() instead of parsing the pathname by itself.
  1524. int
  1525. drive(
  1526. const char *src,
  1527. char *dst
  1528. )
  1529. {
  1530. _splitpath(src, dst, NULL, NULL, NULL);
  1531. return (0 != _tcslen(dst));
  1532. }
  1533. // extension -- copy a extension from source to dest if present
  1534. //
  1535. // Scope: Local.
  1536. //
  1537. // Purpose: copy a drive from source to dest if present, return TRUE if we found one
  1538. //
  1539. // Input:
  1540. // const char *src -- The full path to extract the extension from.
  1541. // char *dst -- The buffer to copy the extension to.
  1542. //
  1543. // Output: Return TRUE if a extension part is found, else return FALSE.
  1544. //
  1545. // Assumes:
  1546. // 1. src is a legal pathname.
  1547. // 2. src does not contain network path (i.e. \\foo\bar)
  1548. // 3. The buffer dst is large enough to contain the result.
  1549. // 4. src does not contain quote since _splitpath() treat quotes a normal char.
  1550. //
  1551. // History:
  1552. // 31-Mar-1993 HV Rewrite drive(), path(), filenamepart(), and extension() to use
  1553. // _splitpath() instead of parsing the pathname by itself.
  1554. int
  1555. extension(
  1556. const char *src,
  1557. char *dst
  1558. )
  1559. {
  1560. _splitpath(src, NULL, NULL, NULL, dst);
  1561. return (0 != _tcslen(dst));
  1562. }
  1563. // filename -- copy a filename from source to dest if present
  1564. //
  1565. // Scope: Local.
  1566. //
  1567. // Purpose: copy a filename from source to dest if present, return TRUE if we found one
  1568. //
  1569. // Input:
  1570. // const char *src -- The full path to extract the filename from.
  1571. // char *dst -- The buffer to copy the filename to.
  1572. //
  1573. // Output: Return TRUE if a filename part is found, else return FALSE.
  1574. //
  1575. // Assumes:
  1576. // 1. src is a legal pathname.
  1577. // 2. src does not contain network path (i.e. \\foo\bar)
  1578. // 3. The buffer dst is large enough to contain the result.
  1579. // 4. src does not contain quote since _splitpath() treat quotes a normal char.
  1580. //
  1581. // Notes:
  1582. // BUGBUG: (posible) when src == '..' --> dst = '.', src == '.', dst = ''
  1583. // This is the way _splitpath works.
  1584. //
  1585. // History:
  1586. // 31-Mar-1993 HV Rewrite drive(), path(), filenamepart(), and extension() to use
  1587. // _splitpath() instead of parsing the pathname by itself.
  1588. int
  1589. filenamepart(
  1590. const char *src,
  1591. char *dst
  1592. )
  1593. {
  1594. _splitpath(src, NULL, NULL, dst, NULL);
  1595. return (0 != _tcslen(dst));
  1596. }
  1597. // path -- copy a path from source to dest if present
  1598. //
  1599. // Scope: Local.
  1600. //
  1601. // Purpose: copy a path from source to dest if present, return TRUE if we found one
  1602. //
  1603. // Input:
  1604. // const char *src -- The full path to extract the path from.
  1605. // char *dst -- The buffer to copy the path to.
  1606. //
  1607. // Output: Return TRUE if a path part is found, else return FALSE.
  1608. //
  1609. // Assumes:
  1610. // 1. src is a legal pathname.
  1611. // 2. src does not contain network path (i.e. \\foo\bar)
  1612. // 3. The buffer dst is large enough to contain the result.
  1613. // 4. src does not contain quote since _splitpath() treat quotes a normal char.
  1614. //
  1615. // History:
  1616. // 31-Mar-1993 HV Rewrite drive(), path(), filenamepart(), and extension() to use
  1617. // _splitpath() instead of parsing the pathname by itself.
  1618. int
  1619. path(
  1620. const char *src,
  1621. char *dst
  1622. )
  1623. {
  1624. _splitpath(src, NULL, dst, NULL, NULL);
  1625. return (0 != _tcslen(dst));
  1626. }
  1627. STRINGLIST *
  1628. searchBucket(
  1629. char *string,
  1630. STRINGLIST *table[],
  1631. unsigned hash
  1632. )
  1633. {
  1634. char *s, *t;
  1635. STRINGLIST *p;
  1636. for (p = table[hash]; p; p = p->next) {
  1637. #if defined(STATISTICS)
  1638. CnttargetChains++;
  1639. #endif
  1640. for (s = string, t = p->text; *s && *t; s++, t++) {
  1641. if (*s == '\\' || *s == '/') // / == \ in targets
  1642. if (*t == '\\' || *t == '/')
  1643. continue;
  1644. else
  1645. break;
  1646. else if (_totupper(*s) == _totupper(*t)) // lc == UC
  1647. continue;
  1648. else
  1649. break;
  1650. }
  1651. if (!*s && !*t)
  1652. return(p);
  1653. }
  1654. return(NULL);
  1655. }
  1656. int
  1657. strcmpiquote(
  1658. char *str1,
  1659. char *str2
  1660. )
  1661. {
  1662. int rc;
  1663. char *s1, *s2;
  1664. char *t;
  1665. #if defined(STATISTICS)
  1666. CntStriCmp++;
  1667. #endif
  1668. s1 = (char *) malloc(_tcslen(str1) + 1);
  1669. if (!s1) {
  1670. makeError(0, OUT_OF_MEMORY);
  1671. return 0;
  1672. }
  1673. s2 = (char *) malloc(_tcslen(str2) + 1);
  1674. if (!s2) {
  1675. makeError(0, OUT_OF_MEMORY);
  1676. return 0;
  1677. }
  1678. if (*str1 == '"')
  1679. str1++;
  1680. for (t = s1;*str1;*t++=*str1++)
  1681. ;
  1682. if (t[-1] == '"')
  1683. t--;
  1684. *t = '\0';
  1685. if (*str2 == '"')
  1686. str2++;
  1687. for (t = s2;*str2;*t++=*str2++)
  1688. ;
  1689. if (t[-1] == '"')
  1690. t--;
  1691. *t = '\0';
  1692. rc = _tcsicmp(s1, s2);
  1693. free(s1);
  1694. free(s2);
  1695. return(rc);
  1696. }
  1697. // Remove quotes from a string, if any
  1698. // Returns a copy of the string
  1699. // Note that there may be quotes at the start, the end or either side.
  1700. char *
  1701. unQuote(
  1702. char *str
  1703. )
  1704. {
  1705. char *s = (char *) rallocate(_tcslen(str) + 1);
  1706. char *t;
  1707. #if defined(STATISTICS)
  1708. CntunQuotes++;
  1709. #endif
  1710. if (*str == '"') {
  1711. str++;
  1712. }
  1713. for (t = s;*str;*t++=*str++)
  1714. ;
  1715. if (t[-1] == '"') {
  1716. t--;
  1717. }
  1718. *t = '\0';
  1719. return(s);
  1720. }
  1721. FILE *
  1722. open_file(
  1723. char *name,
  1724. char *mode
  1725. )
  1726. {
  1727. // If name contains Quotes, remove these before opening the file
  1728. if (*name == '"') {
  1729. *(_tcsrchr(name, '"')) = '\0';
  1730. _tcscpy(name, name+1);
  1731. }
  1732. // Allow sharing between makes running at the same time
  1733. return(_fsopen(name, mode, _SH_DENYWR));
  1734. }
  1735. // TruncateString -- Truncate a string to certain size, take care of MBCS
  1736. //
  1737. // Scope: GLOBAL.
  1738. //
  1739. // Purpose:
  1740. // Since an MBCS string can mix double-byte & single-byte characters, simply
  1741. // truncating the string by terminate it with a NULL byte won't work.
  1742. // TruncateString will make sure that the string is cut off at the character
  1743. // boundary.
  1744. //
  1745. // Input:
  1746. // pszString -- The string to be truncated.
  1747. // uLen -- The length to truncate. The final string's length might be
  1748. // less than this be cause of double-byte character.
  1749. //
  1750. // Output: pszString -- The truncated string.
  1751. //
  1752. // History:
  1753. // 03-Jun-1993 HV Add helper local function TruncateString for findFirst.
  1754. void
  1755. TruncateString(
  1756. char *pszString,
  1757. unsigned uLen
  1758. )
  1759. {
  1760. char *pEnd = pszString; // Points to the end of the string
  1761. unsigned cByte; // Number of bytes to advance depend on lead
  1762. // byte or not
  1763. // Loop to get to the end of the string, exit only when we have exhausted
  1764. // the string, or when the length limit is reached.
  1765. while(*pEnd) {
  1766. // If the the character is a lead byte, advance 2 bytes,
  1767. // else, just advance 1 byte.
  1768. #ifdef _MBCS
  1769. cByte = _ismbblead(*pEnd) ? 2 : 1;
  1770. #else
  1771. cByte = 1;
  1772. #endif
  1773. // If we hit the limit by advancing, stop now.
  1774. if (pEnd - pszString + cByte > uLen) {
  1775. *pEnd = '\0'; // Truncate it.
  1776. break;
  1777. }
  1778. // Otherwise, advance the pointer to the next character (not byte)
  1779. pEnd += cByte;
  1780. }
  1781. }
  1782. // IsValidMakefile - Checks if the makefile is in plain ascii text format.
  1783. //
  1784. // Scope: GLOBAL.
  1785. //
  1786. // Purpose:
  1787. // We don't want to open UTF8 or unicode makefiles, only to report an
  1788. // error at some random place in the makefile.
  1789. //
  1790. // Input:
  1791. // file -- File pointer.
  1792. //
  1793. // Output: -- Returns FALSE if in UTF8 or Unicode format
  1794. //
  1795. // History:
  1796. BOOL IsValidMakefile(FILE *fp)
  1797. {
  1798. const char sigUTF8[] = { '\xef', '\xbb', '\xbf' };
  1799. const char sigUnicode[] = { '\xff', '\xfe' };
  1800. char sig[4];
  1801. const unsigned int len = sizeof sig;
  1802. BOOL fResult = fp != NULL;
  1803. if (fp != NULL && fread(sig, len, 1, fp)) {
  1804. fResult = memcmp(sig, sigUTF8, __min(len, sizeof sigUTF8))
  1805. && memcmp(sig, sigUnicode, __min(len, sizeof sigUnicode));
  1806. }
  1807. if (fseek(fp, 0, SEEK_SET) == -1) {
  1808. return FALSE;
  1809. } else {
  1810. return fResult;
  1811. }
  1812. }
  1813. // OpenValidateMakefile - Open a makefile, only if it's valid.
  1814. //
  1815. // Scope: GLOBAL.
  1816. //
  1817. // Purpose:
  1818. // We don't want to open UTF8 or unicode makefiles, only to report an
  1819. // error at some random place in the makefile.
  1820. //
  1821. // Input:
  1822. // file -- File pointer.
  1823. //
  1824. // Output: -- Returns FALSE if in UTF8 or Unicode format
  1825. //
  1826. // History:
  1827. FILE *OpenValidateMakefile(char *name,char *mode)
  1828. {
  1829. FILE *fp = open_file(name, mode);
  1830. if (fp != NULL && !IsValidMakefile(fp))
  1831. {
  1832. fclose(fp);
  1833. makeError(0, CANT_SUPPORT_UNICODE, 0);
  1834. }
  1835. return fp;
  1836. }