Windows NT 4.0 source code leak
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.

632 lines
14 KiB

4 years ago
  1. //
  2. // GUIDLIB2.C
  3. //
  4. // Copyright Microsoft Corporation, 1995-1996
  5. //
  6. // Tracy Sharpe, 07 Apr 1996
  7. //
  8. // Builds a static library that contains seperate object records for each GUID
  9. // declared in the specified source file.
  10. //
  11. // This is version 2.0 of the GUIDLIB tool. This version of the tool uses the
  12. // Microsoft C preprocessor to handle the bulk of the hard work. Also, this
  13. // version can handle much more
  14. //
  15. #include <windows.h>
  16. #include <stdio.h>
  17. #include <ctype.h>
  18. #include "messages.h"
  19. // Version 1.0
  20. int
  21. __cdecl
  22. oldmain(
  23. int argc,
  24. char* argv[]
  25. );
  26. char g_szInputFile[MAX_PATH];
  27. char g_szOutputFile[MAX_PATH];
  28. char g_szObjectModulePrefix[MAX_PATH];
  29. char g_szCPPCMD[MAX_PATH] = "cl";
  30. char g_szCPPOPT[MAX_PATH] = "";
  31. char g_szLIBCMD[MAX_PATH] = "link";
  32. BOOL g_fLIBCMDOverride;
  33. BOOL g_fWantHelp;
  34. BOOL g_fNOCVDEBUG = FALSE;
  35. typedef enum _ARGTYPE {
  36. ARGTYPE_CPPCMD,
  37. ARGTYPE_CPPOPT,
  38. ARGTYPE_LIBCMD,
  39. ARGTYPE_OUT,
  40. ARGTYPE_HELP,
  41. ARGTYPE_LEGO,
  42. ARGTYPE_NOCVDEBUG
  43. } ARGTYPE;
  44. typedef struct _ARGOPTION {
  45. ARGTYPE type;
  46. LPCSTR pszOption;
  47. BOOL fExpectArg;
  48. } ARGOPTION;
  49. ARGOPTION g_argopts[] = {
  50. { ARGTYPE_CPPCMD, "cpp_cmd", TRUE },
  51. { ARGTYPE_CPPOPT, "cpp_opt", TRUE },
  52. { ARGTYPE_LIBCMD, "lib_cmd", TRUE },
  53. { ARGTYPE_OUT, "out", TRUE },
  54. { ARGTYPE_HELP, "?", FALSE},
  55. { ARGTYPE_HELP, "help", FALSE},
  56. { ARGTYPE_NOCVDEBUG, "NoCvDebug", FALSE},
  57. };
  58. #define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
  59. #define MAX_TOKEN 10
  60. //
  61. // WriteMessage
  62. //
  63. // Writes a formatted error message to the console.
  64. //
  65. void
  66. WriteMessage(
  67. DWORD dwMessageId,
  68. ...
  69. )
  70. {
  71. va_list args;
  72. char MessageBuffer[1024];
  73. va_start(args, dwMessageId);
  74. if (FormatMessage(FORMAT_MESSAGE_FROM_HMODULE, (LPCVOID)
  75. GetModuleHandle(NULL), dwMessageId, LOCALE_USER_DEFAULT, MessageBuffer,
  76. sizeof(MessageBuffer), &args))
  77. printf(MessageBuffer);
  78. va_end(args);
  79. }
  80. //
  81. // WriteMessageWithLastError
  82. //
  83. // Writes a formatted error message to the console. This includes a string
  84. // based on GetLastError()
  85. //
  86. void
  87. WriteMessageWithLastError(
  88. DWORD dwMessageId
  89. )
  90. {
  91. char SystemMessage[256];
  92. if (FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
  93. LOCALE_USER_DEFAULT, SystemMessage, sizeof(SystemMessage), NULL))
  94. WriteMessage(dwMessageId, SystemMessage);
  95. }
  96. //
  97. // ParseCommandLine
  98. //
  99. BOOL
  100. ParseCommandLine(
  101. int argc,
  102. char* argv[]
  103. )
  104. {
  105. BOOL fHaveInputFile = FALSE;
  106. BOOL fHaveOutputFile = FALSE;
  107. char* pszOption;
  108. char* pszOptionArg;
  109. UINT i;
  110. if (argc == 1) {
  111. g_fWantHelp = TRUE;
  112. return TRUE;
  113. }
  114. for (argc--, argv++ ; argc ; argc--, argv++) {
  115. if (**argv != '/' && **argv != '-') {
  116. if (fHaveInputFile) {
  117. WriteMessage(MESSAGE_TOO_MANY_INPUT_FILES);
  118. return FALSE;
  119. }
  120. lstrcpyn(g_szInputFile, *argv, sizeof(g_szInputFile));
  121. fHaveInputFile = TRUE;
  122. continue;
  123. }
  124. pszOption = strtok(&(*argv)[1], ":");
  125. pszOptionArg = strtok(NULL, "");
  126. for (i = 0; i < ARRAYSIZE(g_argopts); i++) {
  127. if (lstrcmpi(g_argopts[i].pszOption, pszOption) != 0)
  128. continue;
  129. if (g_argopts[i].fExpectArg && pszOptionArg == NULL) {
  130. WriteMessage(MESSAGE_NO_OPTION_FOR_ARGUMENT, pszOption);
  131. return FALSE;
  132. } else if (!g_argopts[i].fExpectArg && pszOptionArg != NULL) {
  133. WriteMessage(MESSAGE_UNEXPECTED_OPTION_ARGUMENT, pszOption);
  134. return FALSE;
  135. }
  136. switch (g_argopts[i].type) {
  137. case ARGTYPE_CPPCMD:
  138. lstrcpyn(g_szCPPCMD, pszOptionArg, sizeof(g_szCPPCMD));
  139. break;
  140. case ARGTYPE_CPPOPT:
  141. lstrcpyn(g_szCPPOPT, pszOptionArg, sizeof(g_szCPPOPT));
  142. break;
  143. case ARGTYPE_LIBCMD:
  144. lstrcpyn(g_szLIBCMD, pszOptionArg, sizeof(g_szLIBCMD));
  145. g_fLIBCMDOverride = TRUE;
  146. break;
  147. case ARGTYPE_OUT:
  148. lstrcpyn(g_szOutputFile, pszOptionArg, sizeof(g_szOutputFile));
  149. fHaveOutputFile = TRUE;
  150. break;
  151. case ARGTYPE_HELP:
  152. g_fWantHelp = TRUE;
  153. return TRUE;
  154. case ARGTYPE_LEGO:
  155. // LEGO support on by default now. Silently ignore the
  156. // switch.
  157. break;
  158. case ARGTYPE_NOCVDEBUG:
  159. g_fNOCVDEBUG = TRUE;
  160. break;
  161. }
  162. break;
  163. }
  164. if (i == ARRAYSIZE(g_argopts)) {
  165. WriteMessage(MESSAGE_UNEXPECTED_OPTION, pszOption);
  166. }
  167. }
  168. if (!fHaveInputFile) {
  169. WriteMessage(MESSAGE_MISSING_INPUT_FILE);
  170. return FALSE;
  171. }
  172. if (!fHaveOutputFile) {
  173. WriteMessage(MESSAGE_MISSING_OUTPUT_FILE);
  174. return FALSE;
  175. }
  176. }
  177. //
  178. // SpawnCommand
  179. //
  180. BOOL
  181. SpawnCommand(
  182. char* pszCommandLine
  183. )
  184. {
  185. PROCESS_INFORMATION pi;
  186. STARTUPINFO si;
  187. DWORD dwWaitResult;
  188. DWORD dwExitCode;
  189. ZeroMemory(&si, sizeof(si));
  190. si.cb = sizeof(si);
  191. if (!CreateProcess(NULL, pszCommandLine, NULL, NULL, FALSE, 0, NULL, NULL,
  192. &si, &pi)) {
  193. WriteMessageWithLastError(MESSAGE_SPAWN_FAILED);
  194. return FALSE;
  195. }
  196. // Wait for the command to finish and get its exit code.
  197. dwWaitResult = WaitForSingleObject(pi.hProcess, INFINITE);
  198. GetExitCodeProcess(pi.hProcess, &dwExitCode);
  199. CloseHandle(pi.hThread);
  200. CloseHandle(pi.hProcess);
  201. if (dwWaitResult != WAIT_OBJECT_0) {
  202. WriteMessage(MESSAGE_UNEXPECTED_SPAWN_ERROR);
  203. return FALSE;
  204. }
  205. if (dwExitCode != 0) {
  206. WriteMessage(MESSAGE_BAD_SPAWN_EXIT_CODE, dwExitCode);
  207. return FALSE;
  208. }
  209. return TRUE;
  210. }
  211. //
  212. // PreprocessFile
  213. //
  214. BOOL
  215. PreprocessFile(
  216. LPSTR pszPreprocessedFile
  217. )
  218. {
  219. char szCommandLine[MAX_PATH*4];
  220. char szFullInputPathName[MAX_PATH];
  221. LPSTR pszFilePart;
  222. LPSTR pszExtension;
  223. LPSTR psz;
  224. int length;
  225. WriteMessage(MESSAGE_PREPROCESSING_FILE);
  226. lstrcpy(szCommandLine, "\"");
  227. lstrcat(szCommandLine, g_szCPPCMD);
  228. lstrcat(szCommandLine, "\" ");
  229. lstrcat(szCommandLine, g_szCPPOPT);
  230. lstrcat(szCommandLine, " /nologo /P /EP ");
  231. lstrcat(szCommandLine, g_szInputFile);
  232. if (!SpawnCommand(szCommandLine))
  233. return FALSE;
  234. if (GetFullPathName(g_szInputFile, MAX_PATH, szFullInputPathName,
  235. &pszFilePart) == 0) {
  236. //WriteMessage(MESSAGE_UNEXPECTED_PREPROCESS_ERROR);
  237. return FALSE;
  238. }
  239. for (psz = pszFilePart, pszExtension = NULL; *psz != '\0'; psz++) {
  240. if (*psz == '.')
  241. pszExtension = psz;
  242. }
  243. // If there's no extension, then the compiler simply appends ".i" and psz
  244. // already points at the end of the file.
  245. if (pszExtension == NULL)
  246. pszExtension = psz;
  247. lstrcpy(pszExtension, ".i");
  248. // The preprocessed file is dumped in the current directory, not the
  249. // directory of the source file.
  250. GetCurrentDirectory(MAX_PATH, pszPreprocessedFile);
  251. // Make sure that the directory ends in a backslash. If called from the
  252. // root directory, there will be a backslash, but any other directory won't
  253. // have one!
  254. length = lstrlen(pszPreprocessedFile);
  255. if (length && pszPreprocessedFile[length-1] != '\\')
  256. lstrcat(pszPreprocessedFile, "\\");
  257. lstrcat(pszPreprocessedFile, pszFilePart);
  258. // Sneak in and copy the base of the input filename. We'll use this base
  259. // when making the temporary object modules to stick in the output library.
  260. *pszExtension = '\0';
  261. lstrcpy(g_szObjectModulePrefix, pszFilePart);
  262. }
  263. //
  264. // SkipWhitespace
  265. //
  266. void
  267. SkipWhitespace(
  268. FILE* pFile
  269. )
  270. {
  271. int ch;
  272. do {
  273. ch = fgetc(pFile);
  274. } while (isspace(ch));
  275. ungetc(ch, pFile); // CRT ignores if at end of file.
  276. }
  277. //
  278. // SkipToNextLine
  279. //
  280. void
  281. SkipToNextLine(
  282. FILE* pFile
  283. )
  284. {
  285. int ch;
  286. do {
  287. ch = fgetc(pFile);
  288. } while (ch != '\n' && ch != EOF);
  289. }
  290. //
  291. // ReadSymbol
  292. //
  293. // Reads one symbol from the input stream. Returns the length of the symbol.
  294. // The buffer is assumed to be at least MAX_PATH bytes.
  295. //
  296. int
  297. ReadSymbol(
  298. FILE* pFile,
  299. char* pszSymbol
  300. )
  301. {
  302. int ch;
  303. int position = 0;
  304. SkipWhitespace(pFile);
  305. ch = fgetc(pFile);
  306. while (__iscsym(ch)) {
  307. pszSymbol[position++] = (char) ch;
  308. if (position >= MAX_PATH)
  309. return 0;
  310. ch = fgetc(pFile);
  311. }
  312. ungetc(ch, pFile); // CRT ignores if at end of file.
  313. pszSymbol[position] = '\0';
  314. return position;
  315. }
  316. //
  317. // ReadGUID
  318. //
  319. // Reads the GUID data from the input stream.
  320. //
  321. int
  322. ReadGUID(
  323. FILE* pFile,
  324. char* pszGUID
  325. )
  326. {
  327. int ch;
  328. int position = 0;
  329. SkipWhitespace(pFile);
  330. ch = fgetc(pFile);
  331. while (ch != ';' && ch != EOF) {
  332. if (!isspace(ch)) {
  333. pszGUID[position++] = (char) ch;
  334. if (position >= MAX_PATH)
  335. return 0;
  336. }
  337. ch = fgetc(pFile);
  338. }
  339. pszGUID[position] = '\0';
  340. return position;
  341. }
  342. //
  343. // MakeTempFile
  344. //
  345. BOOL
  346. MakeTempFile(
  347. char* pszTemp,
  348. char* pszIdentifier,
  349. char* pszGUID
  350. )
  351. {
  352. FILE* pOutput;
  353. char szSourceFile[MAX_PATH*2];
  354. static UINT tempid;
  355. wsprintf(pszTemp, "%s_guid%d", g_szObjectModulePrefix, tempid++);
  356. lstrcpy(szSourceFile, pszTemp);
  357. lstrcat(szSourceFile, ".c");
  358. if ((pOutput = fopen(szSourceFile, "w")) == NULL)
  359. return FALSE;
  360. fprintf(pOutput, "typedef struct _GUID {\n"
  361. "\tunsigned long x;\n"
  362. "\tunsigned short s1;\n"
  363. "\tunsigned short s2;\n"
  364. "\tunsigned char c[8];\n"
  365. "} GUID;\n");
  366. fprintf(pOutput, "const GUID %s = %s;\n", pszIdentifier, pszGUID);
  367. fclose(pOutput);
  368. return TRUE;
  369. }
  370. //
  371. // AddTempFileToLibrary
  372. //
  373. BOOL
  374. AddTempFileToLibrary(
  375. char* pszTemp
  376. )
  377. {
  378. char szCommandLine[MAX_PATH*4];
  379. char szObjectFile[MAX_PATH*2];
  380. BOOL fResult;
  381. static BOOL fFirstTime = TRUE;
  382. lstrcpy(szObjectFile, pszTemp);
  383. lstrcat(szObjectFile, ".obj");
  384. // Compile the file with no default library information (/Zl)
  385. lstrcpy(szCommandLine, "\"");
  386. lstrcat(szCommandLine, g_szCPPCMD);
  387. lstrcat(szCommandLine, "\" /nologo /Zl /c /Fo");
  388. lstrcat(szCommandLine, szObjectFile);
  389. lstrcat(szCommandLine, " ");
  390. if( !g_fNOCVDEBUG )
  391. lstrcat(szCommandLine, "/Z7 ");
  392. lstrcat(szCommandLine, pszTemp);
  393. lstrcat(szCommandLine, ".c");
  394. if (!SpawnCommand(szCommandLine))
  395. return FALSE;
  396. lstrcpy(szCommandLine, "\"");
  397. lstrcat(szCommandLine, g_szLIBCMD);
  398. lstrcat(szCommandLine, "\" /lib /nologo /out:");
  399. lstrcat(szCommandLine, g_szOutputFile);
  400. lstrcat(szCommandLine, " ");
  401. lstrcat(szCommandLine, szObjectFile);
  402. if (!fFirstTime) {
  403. lstrcat(szCommandLine, " ");
  404. lstrcat(szCommandLine, g_szOutputFile);
  405. }
  406. fResult = SpawnCommand(szCommandLine);
  407. DeleteFile(szObjectFile);
  408. if (fResult) fFirstTime = FALSE;
  409. return fResult;
  410. }
  411. //
  412. // ProcessFile
  413. //
  414. BOOL
  415. ProcessFile(
  416. LPSTR pszFile
  417. )
  418. {
  419. FILE* pInput;
  420. char szSymbol[MAX_PATH];
  421. char szGUID[MAX_PATH];
  422. char szTempFile[MAX_PATH*2];
  423. BOOL fResult;
  424. BOOL fSomethingDone = FALSE;
  425. if ((pInput = fopen(pszFile, "r")) == NULL) {
  426. WriteMessage(MESSAGE_CANNOT_OPEN_INTERMEDIATE_FILE, pszFile);
  427. return FALSE;
  428. }
  429. while (!feof(pInput)) {
  430. if (ReadSymbol(pInput, szSymbol) == 0) {
  431. SkipToNextLine(pInput);
  432. continue;
  433. }
  434. // Ignore type qualifiers.
  435. if (strcmp(szSymbol, "const") == 0 ||
  436. strcmp(szSymbol, "extern") == 0)
  437. continue;
  438. // Match against any of the GUID aliases we know about.
  439. if (strcmp(szSymbol, "GUID") != 0 &&
  440. strcmp(szSymbol, "IID") != 0 &&
  441. strcmp(szSymbol, "CLSID") != 0 &&
  442. strcmp(szSymbol, "FLAGID") != 0 &&
  443. strcmp(szSymbol, "CATID") != 0 &&
  444. strcmp(szSymbol, "SID") != 0 &&
  445. strcmp(szSymbol, "LIBID") != 0) {
  446. SkipToNextLine(pInput);
  447. continue;
  448. }
  449. if (ReadSymbol(pInput, szSymbol) == 0) {
  450. SkipToNextLine(pInput);
  451. continue;
  452. }
  453. SkipWhitespace(pInput);
  454. if (fgetc(pInput) != '=') {
  455. SkipToNextLine(pInput);
  456. continue;
  457. }
  458. if (ReadGUID(pInput, szGUID) == 0) {
  459. SkipToNextLine(pInput);
  460. continue;
  461. }
  462. WriteMessage(MESSAGE_ADDING_IDENTIFIER, szSymbol);
  463. if (!MakeTempFile(szTempFile, szSymbol, szGUID)) {
  464. WriteMessage(MESSAGE_CANNOT_CREATE_INTERMEDIATE_FILE);
  465. goto error;
  466. }
  467. fResult = AddTempFileToLibrary(szTempFile);
  468. lstrcat(szTempFile, ".c");
  469. DeleteFile(szTempFile);
  470. if (!fResult)
  471. goto error;
  472. fSomethingDone = TRUE;
  473. SkipToNextLine(pInput);
  474. }
  475. if (!fSomethingDone)
  476. WriteMessage(MESSAGE_NO_LIBRARY_GENERATED);
  477. fResult = TRUE;
  478. error:
  479. fclose(pInput);
  480. return fResult;
  481. }
  482. int
  483. __cdecl
  484. main(
  485. int argc,
  486. char* argv[]
  487. )
  488. {
  489. char szPreprocessedFile[MAX_PATH*2];
  490. BOOL fResult;
  491. // For awhile, support the old syntax until all makefiles have been fixed.
  492. if (GetEnvironmentVariable("GL_SPAWNSTRING", NULL, 0) != 0) {
  493. return oldmain(argc, argv);
  494. }
  495. WriteMessage(MESSAGE_BANNER);
  496. if (!ParseCommandLine(argc, argv))
  497. return 1;
  498. if (g_fWantHelp) {
  499. WriteMessage(MESSAGE_HELP);
  500. return 0;
  501. }
  502. if (GetFileAttributes(g_szOutputFile) != (DWORD) -1) {
  503. if (!DeleteFile(g_szOutputFile)) {
  504. WriteMessage(MESSAGE_CANNOT_DELETE, g_szOutputFile);
  505. return 1;
  506. }
  507. }
  508. if (!PreprocessFile(szPreprocessedFile))
  509. return 1;
  510. fResult = ProcessFile(szPreprocessedFile);
  511. DeleteFile(szPreprocessedFile);
  512. return fResult ? 0 : 1;
  513. }