gooderp18绿色标准版
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

816 linhas
21KB

  1. /*
  2. * ----------------------------------------------------------------------------
  3. * nmakehlp.c --
  4. *
  5. * This is used to fix limitations within nmake and the environment.
  6. *
  7. * Copyright (c) 2002 by David Gravereaux.
  8. * Copyright (c) 2006 by Pat Thoyts
  9. *
  10. * See the file "license.terms" for information on usage and redistribution of
  11. * this file, and for a DISCLAIMER OF ALL WARRANTIES.
  12. * ----------------------------------------------------------------------------
  13. */
  14. #define _CRT_SECURE_NO_DEPRECATE
  15. #include <windows.h>
  16. #ifdef _MSC_VER
  17. #pragma comment (lib, "user32.lib")
  18. #pragma comment (lib, "kernel32.lib")
  19. #endif
  20. #include <stdio.h>
  21. #include <math.h>
  22. /*
  23. * This library is required for x64 builds with _some_ versions of MSVC
  24. */
  25. #if defined(_M_IA64) || defined(_M_AMD64)
  26. #if _MSC_VER >= 1400 && _MSC_VER < 1500
  27. #pragma comment(lib, "bufferoverflowU")
  28. #endif
  29. #endif
  30. /* ISO hack for dumb VC++ */
  31. #ifdef _MSC_VER
  32. #define snprintf _snprintf
  33. #endif
  34. /* protos */
  35. static int CheckForCompilerFeature(const char *option);
  36. static int CheckForLinkerFeature(char **options, int count);
  37. static int IsIn(const char *string, const char *substring);
  38. static int SubstituteFile(const char *substs, const char *filename);
  39. static int QualifyPath(const char *path);
  40. static int LocateDependency(const char *keyfile);
  41. static const char *GetVersionFromFile(const char *filename, const char *match, int numdots);
  42. static DWORD WINAPI ReadFromPipe(LPVOID args);
  43. /* globals */
  44. #define CHUNK 25
  45. #define STATICBUFFERSIZE 1000
  46. typedef struct {
  47. HANDLE pipe;
  48. char buffer[STATICBUFFERSIZE];
  49. } pipeinfo;
  50. pipeinfo Out = {INVALID_HANDLE_VALUE, ""};
  51. pipeinfo Err = {INVALID_HANDLE_VALUE, ""};
  52. /*
  53. * exitcodes: 0 == no, 1 == yes, 2 == error
  54. */
  55. int
  56. main(
  57. int argc,
  58. char *argv[])
  59. {
  60. char msg[300];
  61. DWORD dwWritten;
  62. int chars;
  63. const char *s;
  64. /*
  65. * Make sure children (cl.exe and link.exe) are kept quiet.
  66. */
  67. SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
  68. /*
  69. * Make sure the compiler and linker aren't effected by the outside world.
  70. */
  71. SetEnvironmentVariable("CL", "");
  72. SetEnvironmentVariable("LINK", "");
  73. if (argc > 1 && *argv[1] == '-') {
  74. switch (*(argv[1]+1)) {
  75. case 'c':
  76. if (argc != 3) {
  77. chars = snprintf(msg, sizeof(msg) - 1,
  78. "usage: %s -c <compiler option>\n"
  79. "Tests for whether cl.exe supports an option\n"
  80. "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
  81. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  82. &dwWritten, NULL);
  83. return 2;
  84. }
  85. return CheckForCompilerFeature(argv[2]);
  86. case 'l':
  87. if (argc < 3) {
  88. chars = snprintf(msg, sizeof(msg) - 1,
  89. "usage: %s -l <linker option> ?<mandatory option> ...?\n"
  90. "Tests for whether link.exe supports an option\n"
  91. "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
  92. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  93. &dwWritten, NULL);
  94. return 2;
  95. }
  96. return CheckForLinkerFeature(&argv[2], argc-2);
  97. case 'f':
  98. if (argc == 2) {
  99. chars = snprintf(msg, sizeof(msg) - 1,
  100. "usage: %s -f <string> <substring>\n"
  101. "Find a substring within another\n"
  102. "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
  103. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  104. &dwWritten, NULL);
  105. return 2;
  106. } else if (argc == 3) {
  107. /*
  108. * If the string is blank, there is no match.
  109. */
  110. return 0;
  111. } else {
  112. return IsIn(argv[2], argv[3]);
  113. }
  114. case 's':
  115. if (argc == 2) {
  116. chars = snprintf(msg, sizeof(msg) - 1,
  117. "usage: %s -s <substitutions file> <file>\n"
  118. "Perform a set of string map type substutitions on a file\n"
  119. "exitcodes: 0\n",
  120. argv[0]);
  121. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  122. &dwWritten, NULL);
  123. return 2;
  124. }
  125. return SubstituteFile(argv[2], argv[3]);
  126. case 'V':
  127. if (argc != 4) {
  128. chars = snprintf(msg, sizeof(msg) - 1,
  129. "usage: %s -V filename matchstring\n"
  130. "Extract a version from a file:\n"
  131. "eg: pkgIndex.tcl \"package ifneeded http\"",
  132. argv[0]);
  133. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  134. &dwWritten, NULL);
  135. return 0;
  136. }
  137. s = GetVersionFromFile(argv[2], argv[3], *(argv[1]+2) - '0');
  138. if (s && *s) {
  139. printf("%s\n", s);
  140. return 0;
  141. } else
  142. return 1; /* Version not found. Return non-0 exit code */
  143. case 'Q':
  144. if (argc != 3) {
  145. chars = snprintf(msg, sizeof(msg) - 1,
  146. "usage: %s -Q path\n"
  147. "Emit the fully qualified path\n"
  148. "exitcodes: 0 == no, 1 == yes, 2 == error\n", argv[0]);
  149. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  150. &dwWritten, NULL);
  151. return 2;
  152. }
  153. return QualifyPath(argv[2]);
  154. case 'L':
  155. if (argc != 3) {
  156. chars = snprintf(msg, sizeof(msg) - 1,
  157. "usage: %s -L keypath\n"
  158. "Emit the fully qualified path of directory containing keypath\n"
  159. "exitcodes: 0 == success, 1 == not found, 2 == error\n", argv[0]);
  160. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars,
  161. &dwWritten, NULL);
  162. return 2;
  163. }
  164. return LocateDependency(argv[2]);
  165. }
  166. }
  167. chars = snprintf(msg, sizeof(msg) - 1,
  168. "usage: %s -c|-f|-l|-Q|-s|-V ...\n"
  169. "This is a little helper app to equalize shell differences between WinNT and\n"
  170. "Win9x and get nmake.exe to accomplish its job.\n",
  171. argv[0]);
  172. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, chars, &dwWritten, NULL);
  173. return 2;
  174. }
  175. static int
  176. CheckForCompilerFeature(
  177. const char *option)
  178. {
  179. STARTUPINFO si;
  180. PROCESS_INFORMATION pi;
  181. SECURITY_ATTRIBUTES sa;
  182. DWORD threadID;
  183. char msg[300];
  184. BOOL ok;
  185. HANDLE hProcess, h, pipeThreads[2];
  186. char cmdline[100];
  187. hProcess = GetCurrentProcess();
  188. ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
  189. ZeroMemory(&si, sizeof(STARTUPINFO));
  190. si.cb = sizeof(STARTUPINFO);
  191. si.dwFlags = STARTF_USESTDHANDLES;
  192. si.hStdInput = INVALID_HANDLE_VALUE;
  193. ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
  194. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  195. sa.lpSecurityDescriptor = NULL;
  196. sa.bInheritHandle = FALSE;
  197. /*
  198. * Create a non-inheritible pipe.
  199. */
  200. CreatePipe(&Out.pipe, &h, &sa, 0);
  201. /*
  202. * Dupe the write side, make it inheritible, and close the original.
  203. */
  204. DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
  205. DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  206. /*
  207. * Same as above, but for the error side.
  208. */
  209. CreatePipe(&Err.pipe, &h, &sa, 0);
  210. DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
  211. DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  212. /*
  213. * Base command line.
  214. */
  215. lstrcpy(cmdline, "cl.exe -nologo -c -TC -Zs -X -Fp.\\_junk.pch ");
  216. /*
  217. * Append our option for testing
  218. */
  219. lstrcat(cmdline, option);
  220. /*
  221. * Filename to compile, which exists, but is nothing and empty.
  222. */
  223. lstrcat(cmdline, " .\\nul");
  224. ok = CreateProcess(
  225. NULL, /* Module name. */
  226. cmdline, /* Command line. */
  227. NULL, /* Process handle not inheritable. */
  228. NULL, /* Thread handle not inheritable. */
  229. TRUE, /* yes, inherit handles. */
  230. DETACHED_PROCESS, /* No console for you. */
  231. NULL, /* Use parent's environment block. */
  232. NULL, /* Use parent's starting directory. */
  233. &si, /* Pointer to STARTUPINFO structure. */
  234. &pi); /* Pointer to PROCESS_INFORMATION structure. */
  235. if (!ok) {
  236. DWORD err = GetLastError();
  237. int chars = snprintf(msg, sizeof(msg) - 1,
  238. "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
  239. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
  240. FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
  241. (300-chars), 0);
  242. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
  243. return 2;
  244. }
  245. /*
  246. * Close our references to the write handles that have now been inherited.
  247. */
  248. CloseHandle(si.hStdOutput);
  249. CloseHandle(si.hStdError);
  250. WaitForInputIdle(pi.hProcess, 5000);
  251. CloseHandle(pi.hThread);
  252. /*
  253. * Start the pipe reader threads.
  254. */
  255. pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
  256. pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
  257. /*
  258. * Block waiting for the process to end.
  259. */
  260. WaitForSingleObject(pi.hProcess, INFINITE);
  261. CloseHandle(pi.hProcess);
  262. /*
  263. * Wait for our pipe to get done reading, should it be a little slow.
  264. */
  265. WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
  266. CloseHandle(pipeThreads[0]);
  267. CloseHandle(pipeThreads[1]);
  268. /*
  269. * Look for the commandline warning code in both streams.
  270. * - in MSVC 6 & 7 we get D4002, in MSVC 8 we get D9002.
  271. */
  272. return !(strstr(Out.buffer, "D4002") != NULL
  273. || strstr(Err.buffer, "D4002") != NULL
  274. || strstr(Out.buffer, "D9002") != NULL
  275. || strstr(Err.buffer, "D9002") != NULL
  276. || strstr(Out.buffer, "D2021") != NULL
  277. || strstr(Err.buffer, "D2021") != NULL);
  278. }
  279. static int
  280. CheckForLinkerFeature(
  281. char **options,
  282. int count)
  283. {
  284. STARTUPINFO si;
  285. PROCESS_INFORMATION pi;
  286. SECURITY_ATTRIBUTES sa;
  287. DWORD threadID;
  288. char msg[300];
  289. BOOL ok;
  290. HANDLE hProcess, h, pipeThreads[2];
  291. int i;
  292. char cmdline[255];
  293. hProcess = GetCurrentProcess();
  294. ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
  295. ZeroMemory(&si, sizeof(STARTUPINFO));
  296. si.cb = sizeof(STARTUPINFO);
  297. si.dwFlags = STARTF_USESTDHANDLES;
  298. si.hStdInput = INVALID_HANDLE_VALUE;
  299. ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
  300. sa.nLength = sizeof(SECURITY_ATTRIBUTES);
  301. sa.lpSecurityDescriptor = NULL;
  302. sa.bInheritHandle = TRUE;
  303. /*
  304. * Create a non-inheritible pipe.
  305. */
  306. CreatePipe(&Out.pipe, &h, &sa, 0);
  307. /*
  308. * Dupe the write side, make it inheritible, and close the original.
  309. */
  310. DuplicateHandle(hProcess, h, hProcess, &si.hStdOutput, 0, TRUE,
  311. DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  312. /*
  313. * Same as above, but for the error side.
  314. */
  315. CreatePipe(&Err.pipe, &h, &sa, 0);
  316. DuplicateHandle(hProcess, h, hProcess, &si.hStdError, 0, TRUE,
  317. DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
  318. /*
  319. * Base command line.
  320. */
  321. lstrcpy(cmdline, "link.exe -nologo ");
  322. /*
  323. * Append our option for testing.
  324. */
  325. for (i = 0; i < count; i++) {
  326. lstrcat(cmdline, " \"");
  327. lstrcat(cmdline, options[i]);
  328. lstrcat(cmdline, "\"");
  329. }
  330. ok = CreateProcess(
  331. NULL, /* Module name. */
  332. cmdline, /* Command line. */
  333. NULL, /* Process handle not inheritable. */
  334. NULL, /* Thread handle not inheritable. */
  335. TRUE, /* yes, inherit handles. */
  336. DETACHED_PROCESS, /* No console for you. */
  337. NULL, /* Use parent's environment block. */
  338. NULL, /* Use parent's starting directory. */
  339. &si, /* Pointer to STARTUPINFO structure. */
  340. &pi); /* Pointer to PROCESS_INFORMATION structure. */
  341. if (!ok) {
  342. DWORD err = GetLastError();
  343. int chars = snprintf(msg, sizeof(msg) - 1,
  344. "Tried to launch: \"%s\", but got error [%u]: ", cmdline, err);
  345. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS|
  346. FORMAT_MESSAGE_MAX_WIDTH_MASK, 0L, err, 0, (LPSTR)&msg[chars],
  347. (300-chars), 0);
  348. WriteFile(GetStdHandle(STD_ERROR_HANDLE), msg, lstrlen(msg), &err,NULL);
  349. return 2;
  350. }
  351. /*
  352. * Close our references to the write handles that have now been inherited.
  353. */
  354. CloseHandle(si.hStdOutput);
  355. CloseHandle(si.hStdError);
  356. WaitForInputIdle(pi.hProcess, 5000);
  357. CloseHandle(pi.hThread);
  358. /*
  359. * Start the pipe reader threads.
  360. */
  361. pipeThreads[0] = CreateThread(NULL, 0, ReadFromPipe, &Out, 0, &threadID);
  362. pipeThreads[1] = CreateThread(NULL, 0, ReadFromPipe, &Err, 0, &threadID);
  363. /*
  364. * Block waiting for the process to end.
  365. */
  366. WaitForSingleObject(pi.hProcess, INFINITE);
  367. CloseHandle(pi.hProcess);
  368. /*
  369. * Wait for our pipe to get done reading, should it be a little slow.
  370. */
  371. WaitForMultipleObjects(2, pipeThreads, TRUE, 500);
  372. CloseHandle(pipeThreads[0]);
  373. CloseHandle(pipeThreads[1]);
  374. /*
  375. * Look for the commandline warning code in the stderr stream.
  376. */
  377. return !(strstr(Out.buffer, "LNK1117") != NULL ||
  378. strstr(Err.buffer, "LNK1117") != NULL ||
  379. strstr(Out.buffer, "LNK4044") != NULL ||
  380. strstr(Err.buffer, "LNK4044") != NULL ||
  381. strstr(Out.buffer, "LNK4224") != NULL ||
  382. strstr(Err.buffer, "LNK4224") != NULL);
  383. }
  384. static DWORD WINAPI
  385. ReadFromPipe(
  386. LPVOID args)
  387. {
  388. pipeinfo *pi = (pipeinfo *) args;
  389. char *lastBuf = pi->buffer;
  390. DWORD dwRead;
  391. BOOL ok;
  392. again:
  393. if (lastBuf - pi->buffer + CHUNK > STATICBUFFERSIZE) {
  394. CloseHandle(pi->pipe);
  395. return (DWORD)-1;
  396. }
  397. ok = ReadFile(pi->pipe, lastBuf, CHUNK, &dwRead, 0L);
  398. if (!ok || dwRead == 0) {
  399. CloseHandle(pi->pipe);
  400. return 0;
  401. }
  402. lastBuf += dwRead;
  403. goto again;
  404. return 0; /* makes the compiler happy */
  405. }
  406. static int
  407. IsIn(
  408. const char *string,
  409. const char *substring)
  410. {
  411. return (strstr(string, substring) != NULL);
  412. }
  413. /*
  414. * GetVersionFromFile --
  415. * Looks for a match string in a file and then returns the version
  416. * following the match where a version is anything acceptable to
  417. * package provide or package ifneeded.
  418. */
  419. static const char *
  420. GetVersionFromFile(
  421. const char *filename,
  422. const char *match,
  423. int numdots)
  424. {
  425. static char szBuffer[100];
  426. char *szResult = NULL;
  427. FILE *fp = fopen(filename, "rt");
  428. if (fp != NULL) {
  429. /*
  430. * Read data until we see our match string.
  431. */
  432. while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
  433. LPSTR p, q;
  434. p = strstr(szBuffer, match);
  435. if (p != NULL) {
  436. /*
  437. * Skip to first digit after the match.
  438. */
  439. p += strlen(match);
  440. while (*p && !isdigit((unsigned char)*p)) {
  441. ++p;
  442. }
  443. /*
  444. * Find ending whitespace.
  445. */
  446. q = p;
  447. while (*q && (strchr("0123456789.ab", *q)) && (((!strchr(".ab", *q)
  448. && !strchr("ab", q[-1])) || --numdots))) {
  449. ++q;
  450. }
  451. *q = 0;
  452. szResult = p;
  453. break;
  454. }
  455. }
  456. fclose(fp);
  457. }
  458. return szResult;
  459. }
  460. /*
  461. * List helpers for the SubstituteFile function
  462. */
  463. typedef struct list_item_t {
  464. struct list_item_t *nextPtr;
  465. char * key;
  466. char * value;
  467. } list_item_t;
  468. /* insert a list item into the list (list may be null) */
  469. static list_item_t *
  470. list_insert(list_item_t **listPtrPtr, const char *key, const char *value)
  471. {
  472. list_item_t *itemPtr = (list_item_t *)malloc(sizeof(list_item_t));
  473. if (itemPtr) {
  474. itemPtr->key = strdup(key);
  475. itemPtr->value = strdup(value);
  476. itemPtr->nextPtr = NULL;
  477. while(*listPtrPtr) {
  478. listPtrPtr = &(*listPtrPtr)->nextPtr;
  479. }
  480. *listPtrPtr = itemPtr;
  481. }
  482. return itemPtr;
  483. }
  484. static void
  485. list_free(list_item_t **listPtrPtr)
  486. {
  487. list_item_t *tmpPtr, *listPtr = *listPtrPtr;
  488. while (listPtr) {
  489. tmpPtr = listPtr;
  490. listPtr = listPtr->nextPtr;
  491. free(tmpPtr->key);
  492. free(tmpPtr->value);
  493. free(tmpPtr);
  494. }
  495. }
  496. /*
  497. * SubstituteFile --
  498. * As windows doesn't provide anything useful like sed and it's unreliable
  499. * to use the tclsh you are building against (consider x-platform builds -
  500. * eg compiling AMD64 target from IX86) we provide a simple substitution
  501. * option here to handle autoconf style substitutions.
  502. * The substitution file is whitespace and line delimited. The file should
  503. * consist of lines matching the regular expression:
  504. * \s*\S+\s+\S*$
  505. *
  506. * Usage is something like:
  507. * nmakehlp -S << $** > $@
  508. * @PACKAGE_NAME@ $(PACKAGE_NAME)
  509. * @PACKAGE_VERSION@ $(PACKAGE_VERSION)
  510. * <<
  511. */
  512. static int
  513. SubstituteFile(
  514. const char *substitutions,
  515. const char *filename)
  516. {
  517. static char szBuffer[1024], szCopy[1024];
  518. list_item_t *substPtr = NULL;
  519. FILE *fp, *sp;
  520. fp = fopen(filename, "rt");
  521. if (fp != NULL) {
  522. /*
  523. * Build a list of substutitions from the first filename
  524. */
  525. sp = fopen(substitutions, "rt");
  526. if (sp != NULL) {
  527. while (fgets(szBuffer, sizeof(szBuffer), sp) != NULL) {
  528. unsigned char *ks, *ke, *vs, *ve;
  529. ks = (unsigned char*)szBuffer;
  530. while (ks && *ks && isspace(*ks)) ++ks;
  531. ke = ks;
  532. while (ke && *ke && !isspace(*ke)) ++ke;
  533. vs = ke;
  534. while (vs && *vs && isspace(*vs)) ++vs;
  535. ve = vs;
  536. while (ve && *ve && !(*ve == '\r' || *ve == '\n')) ++ve;
  537. *ke = 0, *ve = 0;
  538. list_insert(&substPtr, (char*)ks, (char*)vs);
  539. }
  540. fclose(sp);
  541. }
  542. /* debug: dump the list */
  543. #ifndef NDEBUG
  544. {
  545. int n = 0;
  546. list_item_t *p = NULL;
  547. for (p = substPtr; p != NULL; p = p->nextPtr, ++n) {
  548. fprintf(stderr, "% 3d '%s' => '%s'\n", n, p->key, p->value);
  549. }
  550. }
  551. #endif
  552. /*
  553. * Run the substitutions over each line of the input
  554. */
  555. while (fgets(szBuffer, sizeof(szBuffer), fp) != NULL) {
  556. list_item_t *p = NULL;
  557. for (p = substPtr; p != NULL; p = p->nextPtr) {
  558. char *m = strstr(szBuffer, p->key);
  559. if (m) {
  560. char *cp, *op, *sp;
  561. cp = szCopy;
  562. op = szBuffer;
  563. while (op != m) *cp++ = *op++;
  564. sp = p->value;
  565. while (sp && *sp) *cp++ = *sp++;
  566. op += strlen(p->key);
  567. while (*op) *cp++ = *op++;
  568. *cp = 0;
  569. memcpy(szBuffer, szCopy, sizeof(szCopy));
  570. }
  571. }
  572. printf("%s", szBuffer);
  573. }
  574. list_free(&substPtr);
  575. }
  576. fclose(fp);
  577. return 0;
  578. }
  579. BOOL FileExists(LPCTSTR szPath)
  580. {
  581. #ifndef INVALID_FILE_ATTRIBUTES
  582. #define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
  583. #endif
  584. DWORD pathAttr = GetFileAttributes(szPath);
  585. return (pathAttr != INVALID_FILE_ATTRIBUTES &&
  586. !(pathAttr & FILE_ATTRIBUTE_DIRECTORY));
  587. }
  588. /*
  589. * QualifyPath --
  590. *
  591. * This composes the current working directory with a provided path
  592. * and returns the fully qualified and normalized path.
  593. * Mostly needed to setup paths for testing.
  594. */
  595. static int
  596. QualifyPath(
  597. const char *szPath)
  598. {
  599. char szCwd[MAX_PATH + 1];
  600. GetFullPathName(szPath, sizeof(szCwd)-1, szCwd, NULL);
  601. printf("%s\n", szCwd);
  602. return 0;
  603. }
  604. /*
  605. * Implements LocateDependency for a single directory. See that command
  606. * for an explanation.
  607. * Returns 0 if found after printing the directory.
  608. * Returns 1 if not found but no errors.
  609. * Returns 2 on any kind of error
  610. * Basically, these are used as exit codes for the process.
  611. */
  612. static int LocateDependencyHelper(const char *dir, const char *keypath)
  613. {
  614. HANDLE hSearch;
  615. char path[MAX_PATH+1];
  616. size_t dirlen;
  617. int keylen, ret;
  618. WIN32_FIND_DATA finfo;
  619. if (dir == NULL || keypath == NULL)
  620. return 2; /* Have no real error reporting mechanism into nmake */
  621. dirlen = strlen(dir);
  622. if ((dirlen + 3) > sizeof(path))
  623. return 2;
  624. strncpy(path, dir, dirlen);
  625. strncpy(path+dirlen, "\\*", 3); /* Including terminating \0 */
  626. keylen = strlen(keypath);
  627. #if 0 /* This function is not available in Visual C++ 6 */
  628. /*
  629. * Use numerics 0 -> FindExInfoStandard,
  630. * 1 -> FindExSearchLimitToDirectories,
  631. * as these are not defined in Visual C++ 6
  632. */
  633. hSearch = FindFirstFileEx(path, 0, &finfo, 1, NULL, 0);
  634. #else
  635. hSearch = FindFirstFile(path, &finfo);
  636. #endif
  637. if (hSearch == INVALID_HANDLE_VALUE)
  638. return 1; /* Not found */
  639. /* Loop through all subdirs checking if the keypath is under there */
  640. ret = 1; /* Assume not found */
  641. do {
  642. int sublen;
  643. /*
  644. * We need to check it is a directory despite the
  645. * FindExSearchLimitToDirectories in the above call. See SDK docs
  646. */
  647. if ((finfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
  648. continue;
  649. sublen = strlen(finfo.cFileName);
  650. if ((dirlen+1+sublen+1+keylen+1) > sizeof(path))
  651. continue; /* Path does not fit, assume not matched */
  652. strncpy(path+dirlen+1, finfo.cFileName, sublen);
  653. path[dirlen+1+sublen] = '\\';
  654. strncpy(path+dirlen+1+sublen+1, keypath, keylen+1);
  655. if (FileExists(path)) {
  656. /* Found a match, print to stdout */
  657. path[dirlen+1+sublen] = '\0';
  658. QualifyPath(path);
  659. ret = 0;
  660. break;
  661. }
  662. } while (FindNextFile(hSearch, &finfo));
  663. FindClose(hSearch);
  664. return ret;
  665. }
  666. /*
  667. * LocateDependency --
  668. *
  669. * Locates a dependency for a package.
  670. * keypath - a relative path within the package directory
  671. * that is used to confirm it is the correct directory.
  672. * The search path for the package directory is currently only
  673. * the parent and grandparent of the current working directory.
  674. * If found, the command prints
  675. * name_DIRPATH=<full path of located directory>
  676. * and returns 0. If not found, does not print anything and returns 1.
  677. */
  678. static int LocateDependency(const char *keypath)
  679. {
  680. size_t i;
  681. int ret;
  682. static const char *paths[] = {"..", "..\\..", "..\\..\\.."};
  683. for (i = 0; i < (sizeof(paths)/sizeof(paths[0])); ++i) {
  684. ret = LocateDependencyHelper(paths[i], keypath);
  685. if (ret == 0)
  686. return ret;
  687. }
  688. return ret;
  689. }
  690. /*
  691. * Local variables:
  692. * mode: c
  693. * c-basic-offset: 4
  694. * fill-column: 78
  695. * indent-tabs-mode: t
  696. * tab-width: 8
  697. * End:
  698. */
上海开阖软件有限公司 沪ICP备12045867号-1