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.

1068 lines
29 KiB

  1. /***********************************************************************
  2. * Microsoft (R) Windows (R) Resource Compiler
  3. *
  4. * Copyright (c) Microsoft Corporation. All rights reserved.
  5. *
  6. * File Comments:
  7. *
  8. *
  9. ***********************************************************************/
  10. #include "rc.h"
  11. #include <setjmp.h>
  12. #include <ddeml.h>
  13. #define READ_MAX (MAXSTR+80)
  14. #define MAX_CMD 256
  15. #define cDefineMax 100
  16. wchar_t resname[_MAX_PATH];
  17. wchar_t *szRCPP[MAX_CMD];
  18. BOOL fRcppAlloc[MAX_CMD];
  19. /************************************************************************/
  20. /* Define Global Variables */
  21. /************************************************************************/
  22. int __cdecl rcpp_main(int, wchar_t *[]);
  23. SHORT ResCount; /* number of resources */
  24. PTYPEINFO pTypInfo;
  25. SHORT nFontsRead;
  26. FONTDIR *pFontList;
  27. FONTDIR *pFontLast;
  28. TOKEN token;
  29. int errorCount;
  30. WCHAR tokenbuf[ MAXSTR + 1 ];
  31. wchar_t exename[ _MAX_PATH ];
  32. wchar_t fullname[ _MAX_PATH ];
  33. wchar_t curFile[ _MAX_PATH ];
  34. HANDLE hHeap = NULL;
  35. PDLGHDR pLocDlg;
  36. UINT mnEndFlagLoc; /* patch location for end of a menu. */
  37. /* we set the high order bit there */
  38. /* BOOL fLeaveFontDir; */
  39. BOOL fVerbose; /* verbose mode (-v) */
  40. BOOL fAFXSymbols;
  41. BOOL fMacRsrcs;
  42. BOOL fAppendNull;
  43. BOOL fWarnInvalidCodePage;
  44. BOOL fSkipDuplicateCtlIdWarning;
  45. long lOffIndex;
  46. WORD idBase;
  47. BOOL fPreprocessOnly;
  48. wchar_t szBuf[_MAX_PATH * 2];
  49. wchar_t szPreProcessName[_MAX_PATH];
  50. /* File global variables */
  51. wchar_t inname[_MAX_PATH];
  52. wchar_t *szTempFileName;
  53. wchar_t *szTempFileName2;
  54. PFILE fhBin;
  55. PFILE fhInput;
  56. /* array for include path stuff, initially empty */
  57. wchar_t *pchInclude;
  58. /* Substitute font name */
  59. int nBogusFontNames;
  60. WCHAR *pszBogusFontNames[16];
  61. WCHAR szSubstituteFontName[MAXTOKSTR];
  62. static jmp_buf jb;
  63. extern ULONG lCPPTotalLinenumber;
  64. /* Function prototypes for local functions */
  65. HANDLE RCInit(void);
  66. void RC_PreProcess(const wchar_t *);
  67. void CleanUpFiles(void);
  68. /*---------------------------------------------------------------------------*/
  69. /* */
  70. /* rc_main() - */
  71. /* */
  72. /*---------------------------------------------------------------------------*/
  73. int __cdecl
  74. rc_main(
  75. int argc,
  76. wchar_t *argv[],
  77. char *argvA[]
  78. )
  79. {
  80. wchar_t *r;
  81. wchar_t *x;
  82. wchar_t *s1;
  83. wchar_t *s2;
  84. wchar_t *s3;
  85. int n;
  86. wchar_t *pchIncludeT;
  87. ULONG cchIncludeMax;
  88. int fInclude = TRUE; /* by default, search INCLUDE */
  89. int fIncludeCurrentFirst = TRUE; /* by default, add current dir to start of includes */
  90. int cDefine = 0;
  91. int cUnDefine = 0;
  92. wchar_t *pszDefine[cDefineMax];
  93. wchar_t *pszUnDefine[cDefineMax];
  94. wchar_t szDrive[_MAX_DRIVE];
  95. wchar_t szDir[_MAX_DIR];
  96. wchar_t szFName[_MAX_FNAME];
  97. wchar_t szExt[_MAX_EXT];
  98. wchar_t szFullPath[_MAX_PATH];
  99. wchar_t szIncPath[_MAX_PATH];
  100. wchar_t buf[10];
  101. wchar_t *szRC;
  102. wchar_t **ppargv;
  103. BOOL *pfRcppAlloc;
  104. int rcpp_argc;
  105. /* Set up for this run of RC */
  106. if (_setjmp(jb)) {
  107. return Nerrors;
  108. }
  109. hHeap = RCInit();
  110. if (hHeap == NULL) {
  111. fatal(1120, 0x01000000);
  112. }
  113. if (argvA != NULL) {
  114. argv = UnicodeCommandLine(argc, argvA);
  115. }
  116. pchInclude = pchIncludeT = (wchar_t *) MyAlloc(_MAX_PATH * 2 * sizeof(wchar_t));
  117. cchIncludeMax = _MAX_PATH*2;
  118. szRC = argv[0];
  119. /* process the command line switches */
  120. while ((argc > 1) && (IsSwitchChar(*argv[1]))) {
  121. switch (towupper(argv[1][1])) {
  122. case L'?':
  123. case L'H':
  124. // Print out help, and quit
  125. SendWarning(L"\n");
  126. SET_MSG(10001, LVER_PRODUCTVERSION_STR);
  127. SendWarning(Msg_Text);
  128. SET_MSG(10002);
  129. SendWarning(Msg_Text);
  130. SET_MSG(20001);
  131. SendWarning(Msg_Text);
  132. return 0; /* can just return - nothing to cleanup, yet. */
  133. case L'B':
  134. if (towupper(argv[1][2]) == L'R') { /* base resource id */
  135. unsigned long id;
  136. if (isdigit(argv[1][3]))
  137. argv[1] += 3;
  138. else if (argv[1][3] == L':')
  139. argv[1] += 4;
  140. else {
  141. argc--;
  142. argv++;
  143. if (argc <= 1)
  144. goto BadId;
  145. }
  146. if (*(argv[1]) == 0)
  147. goto BadId;
  148. id = _wtoi(argv[1]);
  149. if (id < 1 || id > 32767)
  150. fatal(1210);
  151. idBase = (WORD)id;
  152. break;
  153. BadId:
  154. fatal(1209);
  155. }
  156. break;
  157. case L'C':
  158. /* Check for the existence of CodePage Number */
  159. if (argv[1][2])
  160. argv[1] += 2;
  161. else {
  162. argc--;
  163. argv++;
  164. }
  165. /* Now argv point to first digit of CodePage */
  166. if (!argv[1])
  167. fatal(1204);
  168. uiCodePage = _wtoi(argv[1]);
  169. if (uiCodePage == 0)
  170. fatal(1205);
  171. /* Check if uiCodePage exist in registry. */
  172. if (!IsValidCodePage (uiCodePage))
  173. fatal(1206);
  174. break;
  175. case L'D':
  176. /* if not attached to switch, skip to next */
  177. if (argv[1][2])
  178. argv[1] += 2;
  179. else {
  180. argc--;
  181. argv++;
  182. }
  183. /* remember pointer to string */
  184. pszDefine[cDefine++] = argv[1];
  185. if (cDefine > cDefineMax) {
  186. fatal(1105, argv[1]);
  187. }
  188. break;
  189. case L'F':
  190. switch (towupper(argv[1][2])) {
  191. case L'O':
  192. if (argv[1][3])
  193. argv[1] += 3;
  194. else {
  195. argc--;
  196. argv++;
  197. }
  198. if (argc > 1)
  199. wcscpy(resname, argv[1]);
  200. else
  201. fatal(1101);
  202. break;
  203. default:
  204. fatal(1103, argv[1]);
  205. }
  206. break;
  207. case L'I':
  208. /* add string to directories to search */
  209. /* note: format is <path>\0<path>\0\0 */
  210. /* if not attached to switch, skip to next */
  211. if (argv[1][2])
  212. argv[1] += 2;
  213. else {
  214. argc--;
  215. argv++;
  216. }
  217. if (!argv[1])
  218. fatal(1201);
  219. if ((wcslen(argv[1]) + 1 + wcslen(pchInclude)) >= cchIncludeMax) {
  220. cchIncludeMax = wcslen(pchInclude) + wcslen(argv[1]) + _MAX_PATH*2;
  221. pchIncludeT = (wchar_t *) MyAlloc(cchIncludeMax * sizeof(wchar_t));
  222. wcscpy(pchIncludeT, pchInclude);
  223. MyFree(pchInclude);
  224. pchInclude = pchIncludeT;
  225. pchIncludeT = pchInclude + wcslen(pchIncludeT) + 1;
  226. }
  227. /* if not first switch, write over terminator with semicolon */
  228. if (pchInclude != pchIncludeT)
  229. pchIncludeT[-1] = L';';
  230. /* copy the path */
  231. while ((*pchIncludeT++ = *argv[1]++) != 0)
  232. ;
  233. break;
  234. case L'L':
  235. /* if not attached to switch, skip to next */
  236. if (argv[1][2])
  237. argv[1] += 2;
  238. else {
  239. argc--;
  240. argv++;
  241. }
  242. if (!argv[1])
  243. fatal(1202);
  244. if (swscanf(argv[1], L"%x", &language) != 1)
  245. fatal(1203);
  246. while (*argv[1]++ != 0)
  247. ;
  248. break;
  249. case L'M':
  250. fMacRsrcs = TRUE;
  251. goto MaybeMore;
  252. case L'N':
  253. fAppendNull = TRUE;
  254. goto MaybeMore;
  255. case L'P':
  256. fPreprocessOnly = TRUE;
  257. break;
  258. case L'R':
  259. goto MaybeMore;
  260. case L'S':
  261. // find out from BRAD what -S does
  262. fAFXSymbols = TRUE;
  263. break;
  264. case L'U':
  265. /* if not attached to switch, skip to next */
  266. if (argv[1][2])
  267. argv[1] += 2;
  268. else {
  269. argc--;
  270. argv++;
  271. }
  272. /* remember pointer to string */
  273. pszUnDefine[cUnDefine++] = argv[1];
  274. if (cUnDefine > cDefineMax) {
  275. fatal(1104, argv[1]);
  276. }
  277. break;
  278. case L'V':
  279. fVerbose = TRUE; // AFX doesn't set this
  280. goto MaybeMore;
  281. case L'W':
  282. fWarnInvalidCodePage = TRUE; // Invalid Codepage is a warning, not an error.
  283. goto MaybeMore;
  284. case L'Y':
  285. fSkipDuplicateCtlIdWarning = TRUE;
  286. goto MaybeMore;
  287. case L'X':
  288. /* remember not to add INCLUDE path */
  289. fInclude = FALSE;
  290. // VC seems to feel the current dir s/b added first no matter what...
  291. // If -X! is specified, don't do that.
  292. if (argv[1][2] == L'!') {
  293. fIncludeCurrentFirst = FALSE;
  294. argv[1]++;
  295. }
  296. MaybeMore: /* check to see if multiple switches, like -xrv */
  297. if (argv[1][2]) {
  298. argv[1][1] = L'-';
  299. argv[1]++;
  300. continue;
  301. }
  302. break;
  303. case L'Z':
  304. /* if not attached to switch, skip to next */
  305. if (argv[1][2])
  306. argv[1] += 2;
  307. else {
  308. argc--;
  309. argv++;
  310. }
  311. if (!argv[1])
  312. fatal(1211);
  313. s3 = wcschr(argv[1], L'/');
  314. if (s3 == NULL)
  315. fatal(1212);
  316. *s3 = L'\0';
  317. wcscpy(szSubstituteFontName, s3+1);
  318. s1 = argv[1];
  319. do {
  320. s2 = wcschr(s1, L',');
  321. if (s2 != NULL)
  322. *s2 = L'\0';
  323. if (wcslen(s1)) {
  324. if (nBogusFontNames >= 16)
  325. fatal(1213);
  326. pszBogusFontNames[nBogusFontNames] = (WCHAR *) MyAlloc((wcslen(s1)+1) * sizeof(WCHAR));
  327. wcscpy(pszBogusFontNames[nBogusFontNames], s1);
  328. nBogusFontNames += 1;
  329. }
  330. if (s2 != NULL)
  331. *s2++ = L',';
  332. }
  333. while (s1 = s2);
  334. *s3 = L'/';
  335. while (*argv[1]++ != 0)
  336. ;
  337. break;
  338. default:
  339. fatal(1106, argv[1]);
  340. }
  341. /* get next argument or switch */
  342. argc--;
  343. argv++;
  344. }
  345. /* make sure we have at least one file name to work with */
  346. if (argc != 2 || *argv[1] == L'\0')
  347. fatal(1107);
  348. if (fVerbose) {
  349. SET_MSG(10001, LVER_PRODUCTVERSION_STR);
  350. SendWarning(Msg_Text);
  351. SET_MSG(10002);
  352. SendWarning(Msg_Text);
  353. SendWarning(L"\n");
  354. }
  355. // Support Multi Code Page
  356. // If user did NOT indicate code in command line, we have to set Default
  357. // for NLS Conversion
  358. if (uiCodePage == 0) {
  359. CHAR *pchCodePageString;
  360. /* At first, search ENVIRONMENT VALUE */
  361. if ((pchCodePageString = getenv("RCCODEPAGE")) != NULL) {
  362. uiCodePage = atoi(pchCodePageString);
  363. if (uiCodePage == 0 || !IsValidCodePage(uiCodePage)) {
  364. fatal(1207);
  365. }
  366. } else {
  367. // We use System ANSI Code page (ACP)
  368. uiCodePage = GetACP();
  369. }
  370. }
  371. uiDefaultCodePage = uiCodePage;
  372. if (fVerbose) {
  373. wprintf(L"Using codepage %d as default\n", uiDefaultCodePage);
  374. }
  375. /* If we have no extension, assumer .rc */
  376. /* If .res extension, make sure we have -fo set, or error */
  377. /* Otherwise, just assume file is .rc and output .res (or resname) */
  378. _wsplitpath(argv[1], szDrive, szDir, szFName, szExt);
  379. if (!(*szDir || *szDrive)) {
  380. wcscpy(szIncPath, L".;");
  381. } else {
  382. wcscpy(szIncPath, szDrive);
  383. wcscat(szIncPath, szDir);
  384. wcscat(szIncPath, L";.;");
  385. }
  386. if ((wcslen(szIncPath) + 1 + wcslen(pchInclude)) >= cchIncludeMax) {
  387. cchIncludeMax = wcslen(pchInclude) + wcslen(szIncPath) + _MAX_PATH*2;
  388. pchIncludeT = (wchar_t *) MyAlloc(cchIncludeMax * sizeof(wchar_t));
  389. wcscpy(pchIncludeT, pchInclude);
  390. MyFree(pchInclude);
  391. pchInclude = pchIncludeT;
  392. pchIncludeT = pchInclude + wcslen(pchIncludeT) + 1;
  393. }
  394. pchIncludeT = (wchar_t *) MyAlloc(cchIncludeMax * sizeof(wchar_t));
  395. if (fIncludeCurrentFirst) {
  396. wcscpy(pchIncludeT, szIncPath);
  397. wcscat(pchIncludeT, pchInclude);
  398. } else {
  399. wcscpy(pchIncludeT, pchInclude);
  400. wcscat(pchIncludeT, L";");
  401. wcscat(pchIncludeT, szIncPath);
  402. }
  403. MyFree(pchInclude);
  404. pchInclude = pchIncludeT;
  405. pchIncludeT = pchInclude + wcslen(pchIncludeT) + 1;
  406. if (!szExt[0]) {
  407. wcscpy(szExt, L".RC");
  408. } else if (wcscmp(szExt, L".RES") == 0) {
  409. fatal(1208);
  410. }
  411. _wmakepath(inname, szDrive, szDir, szFName, szExt);
  412. if (fPreprocessOnly) {
  413. _wmakepath(szPreProcessName, NULL, NULL, szFName, L".rcpp");
  414. }
  415. /* Create the name of the .RES file */
  416. if (resname[0] == 0) {
  417. // if building a Mac resource file, we use .rsc to match mrc's output
  418. _wmakepath(resname, szDrive, szDir, szFName, fMacRsrcs ? L".RSC" : L".RES");
  419. }
  420. /* create the temporary file names */
  421. szTempFileName = (wchar_t *) MyAlloc(_MAX_PATH * sizeof(wchar_t));
  422. _wfullpath(szFullPath, resname, _MAX_PATH);
  423. _wsplitpath(szFullPath, szDrive, szDir, NULL, NULL);
  424. _wmakepath(szTempFileName, szDrive, szDir, L"RCXXXXXX", NULL);
  425. _wmktemp (szTempFileName);
  426. szTempFileName2 = (wchar_t *) MyAlloc(_MAX_PATH * sizeof(wchar_t));
  427. _wmakepath(szTempFileName2, szDrive, szDir, L"RDXXXXXX", NULL);
  428. _wmktemp(szTempFileName2);
  429. ppargv = szRCPP;
  430. pfRcppAlloc = fRcppAlloc;
  431. *ppargv++ = L"RCPP";
  432. *pfRcppAlloc++ = FALSE;
  433. rcpp_argc = 1;
  434. /* Open the .RES file (deleting any old versions which exist). */
  435. if ((fhBin = _wfopen(resname, L"w+b")) == NULL) {
  436. fatal(1109, resname);
  437. }
  438. if (fMacRsrcs)
  439. MySeek(fhBin, MACDATAOFFSET, 0);
  440. if (fVerbose) {
  441. SET_MSG(10102, resname);
  442. SendWarning(Msg_Text);
  443. }
  444. /* Set up for RCPP. This constructs the command line for it. */
  445. *ppargv++ = _wcsdup(L"-CP");
  446. *pfRcppAlloc++ = TRUE;
  447. rcpp_argc++;
  448. _itow(uiCodePage, buf, 10);
  449. *ppargv++ = buf;
  450. *pfRcppAlloc++ = FALSE;
  451. rcpp_argc++;
  452. *ppargv++ = _wcsdup(L"-f");
  453. *pfRcppAlloc++ = TRUE;
  454. rcpp_argc++;
  455. *ppargv++ = _wcsdup(szTempFileName);
  456. *pfRcppAlloc++ = TRUE;
  457. rcpp_argc++;
  458. *ppargv++ = _wcsdup(L"-g");
  459. *pfRcppAlloc++ = TRUE;
  460. rcpp_argc++;
  461. if (fPreprocessOnly) {
  462. *ppargv++ = _wcsdup(szPreProcessName);
  463. } else {
  464. *ppargv++ = _wcsdup(szTempFileName2);
  465. }
  466. *pfRcppAlloc++ = TRUE;
  467. rcpp_argc++;
  468. *ppargv++ = _wcsdup(L"-DRC_INVOKED");
  469. *pfRcppAlloc++ = TRUE;
  470. rcpp_argc++;
  471. if (fAFXSymbols) {
  472. *ppargv++ = _wcsdup(L"-DAPSTUDIO_INVOKED");
  473. *pfRcppAlloc++ = TRUE;
  474. rcpp_argc++;
  475. }
  476. if (fMacRsrcs) {
  477. *ppargv++ = _wcsdup(L"-D_MAC");
  478. *pfRcppAlloc++ = TRUE;
  479. rcpp_argc++;
  480. }
  481. *ppargv++ = _wcsdup(L"-D_WIN32"); /* to be compatible with C9/VC++ */
  482. *pfRcppAlloc++ = TRUE;
  483. rcpp_argc++;
  484. *ppargv++ = _wcsdup(L"-pc\\:/");
  485. *pfRcppAlloc++ = TRUE;
  486. rcpp_argc++;
  487. *ppargv++ = _wcsdup(L"-E");
  488. *pfRcppAlloc++ = TRUE;
  489. rcpp_argc++;
  490. /* Parse the INCLUDE environment variable */
  491. if (fInclude) {
  492. *ppargv++ = _wcsdup(L"-I.");
  493. *pfRcppAlloc++ = TRUE;
  494. rcpp_argc++;
  495. /* add seperator if any -I switches */
  496. if (pchInclude != pchIncludeT)
  497. pchIncludeT[-1] = L';';
  498. /* read 'em */
  499. x = _wgetenv(L"INCLUDE");
  500. if (x == NULL) {
  501. *pchIncludeT = L'\0';
  502. } else {
  503. if (wcslen(pchInclude) + wcslen(x) + 1 >= cchIncludeMax) {
  504. cchIncludeMax = wcslen(pchInclude) + wcslen(x) + _MAX_PATH*2;
  505. pchIncludeT = (wchar_t *) MyAlloc(cchIncludeMax * sizeof(wchar_t));
  506. wcscpy(pchIncludeT, pchInclude);
  507. MyFree(pchInclude);
  508. pchInclude = pchIncludeT;
  509. }
  510. wcscat(pchInclude, x);
  511. pchIncludeT = pchInclude + wcslen(pchInclude);
  512. }
  513. }
  514. /* now put includes on the RCPP command line */
  515. for (x = pchInclude ; *x ; ) {
  516. r = x;
  517. while (*x && *x != L';')
  518. x = CharNextW(x);
  519. /* mark if semicolon */
  520. if (*x)
  521. *x-- = 0;
  522. if (*r != L'\0' && /* empty include path? */
  523. *r != L'%' /* check for un-expanded stuff */
  524. // && wcschr(r, L' ') == NULL /* check for whitespace */
  525. ) {
  526. /* add switch */
  527. *ppargv++ = _wcsdup(L"-I");
  528. *pfRcppAlloc++ = TRUE;
  529. rcpp_argc++;
  530. *ppargv++ = _wcsdup(r);
  531. *pfRcppAlloc++ = TRUE;
  532. rcpp_argc++;
  533. }
  534. /* was semicolon, need to fix for searchenv() */
  535. if (*x) {
  536. *++x = L';';
  537. x++;
  538. }
  539. }
  540. /* include defines */
  541. for (n = 0; n < cDefine; n++) {
  542. *ppargv++ = _wcsdup(L"-D");
  543. *pfRcppAlloc++ = TRUE;
  544. rcpp_argc++;
  545. *ppargv++ = pszDefine[n];
  546. *pfRcppAlloc++ = FALSE;
  547. rcpp_argc++;
  548. }
  549. /* include undefine */
  550. for (n = 0; n < cUnDefine; n++) {
  551. *ppargv++ = _wcsdup(L"-U");
  552. *pfRcppAlloc++ = TRUE;
  553. rcpp_argc++;
  554. *ppargv++ = pszUnDefine[n];
  555. *pfRcppAlloc++ = FALSE;
  556. rcpp_argc++;
  557. }
  558. if (rcpp_argc > MAX_CMD) {
  559. fatal(1102);
  560. }
  561. if (fVerbose) {
  562. /* echo the preprocessor command */
  563. wprintf(L"RC:");
  564. for (n = 0 ; n < rcpp_argc ; n++) {
  565. wprintf(L" %s", szRCPP[n]);
  566. }
  567. wprintf(L"\n");
  568. }
  569. /* Add .rc with rcincludes into szTempFileName */
  570. RC_PreProcess(inname);
  571. /* Run the Preprocessor. */
  572. if (rcpp_main(rcpp_argc, szRCPP) != 0)
  573. fatal(1116);
  574. // All done. Now free up the argv array.
  575. for (n = 0 ; n < rcpp_argc ; n++) {
  576. if (fRcppAlloc[n] == TRUE) {
  577. free(szRCPP[n]);
  578. }
  579. }
  580. if (fPreprocessOnly) {
  581. swprintf(szBuf, L"Preprocessed file created in: %s\n", szPreProcessName);
  582. quit(szBuf);
  583. }
  584. if (fVerbose)
  585. wprintf(L"\n%s", inname);
  586. if ((fhInput = _wfopen(szTempFileName2, L"rb")) == NULL_FILE)
  587. fatal(2180);
  588. if (!InitSymbolInfo())
  589. fatal(22103);
  590. LexInit (fhInput);
  591. uiCodePage = uiDefaultCodePage;
  592. ReadRF(); /* create .RES from .RC */
  593. if (!TermSymbolInfo(fhBin))
  594. fatal(22204);
  595. if (!fMacRsrcs)
  596. MyAlign(fhBin); // Pad end of file so that we can concatenate files
  597. CleanUpFiles();
  598. HeapDestroy(hHeap);
  599. return Nerrors; // return success, not quitting.
  600. }
  601. /* RCInit
  602. * Initializes this run of RC.
  603. */
  604. HANDLE
  605. RCInit(
  606. void
  607. )
  608. {
  609. Nerrors = 0;
  610. uiCodePage = 0;
  611. nFontsRead = 0;
  612. szTempFileName = NULL;
  613. szTempFileName2 = NULL;
  614. lOffIndex = 0;
  615. idBase = 128;
  616. pTypInfo = NULL;
  617. fVerbose = FALSE;
  618. fMacRsrcs = FALSE;
  619. // Clear the filenames
  620. exename[0] = L'\0';
  621. resname[0] = L'\0';
  622. /* create growable local heap of 16MB minimum size */
  623. return HeapCreate(HEAP_NO_SERIALIZE, 0, 0);
  624. }
  625. /*---------------------------------------------------------------------------*/
  626. /* */
  627. /* skipblanks() - */
  628. /* */
  629. /*---------------------------------------------------------------------------*/
  630. wchar_t *
  631. skipblanks(
  632. wchar_t *pstr,
  633. int fTerminate
  634. )
  635. {
  636. /* search forward for first non-white character and save its address */
  637. while (*pstr && iswspace(*pstr))
  638. pstr++;
  639. if (fTerminate) {
  640. wchar_t *retval = pstr;
  641. /* search forward for first white character and zero to extract word */
  642. while (*pstr && !iswspace(*pstr))
  643. pstr++;
  644. *pstr = 0;
  645. return retval;
  646. } else {
  647. return pstr;
  648. }
  649. }
  650. /*---------------------------------------------------------------------------*/
  651. /* */
  652. /* RC_PreProcess() - */
  653. /* */
  654. /*---------------------------------------------------------------------------*/
  655. void
  656. RC_PreProcess(
  657. const wchar_t *szname
  658. )
  659. {
  660. PFILE fhout; /* fhout: is temp file with rcincluded stuff */
  661. PFILE fhin;
  662. wchar_t *wch_buf;
  663. wchar_t *pwch;
  664. wchar_t *pfilename;
  665. wchar_t *szT;
  666. UINT iLine = 0;
  667. int fBlanks = TRUE;
  668. INT fFileType;
  669. wch_buf = (wchar_t *)MyAlloc(sizeof(wchar_t) * READ_MAX);
  670. szT = (wchar_t *)MyAlloc(sizeof(wchar_t) * MAXSTR);
  671. /* Open the .RC source file. */
  672. wcscpy(Filename, szname);
  673. fhin = _wfopen(szname, L"rb");
  674. if (!fhin) {
  675. fatal(1110, szname);
  676. }
  677. /* Open the temporary output file. */
  678. fhout = _wfopen(szTempFileName, L"w+b");
  679. if (!fhout) {
  680. fatal(2180);
  681. }
  682. /* output the current filename for RCPP messages */
  683. for (pwch=wch_buf ; *szname ; szname++) {
  684. *pwch++ = *szname;
  685. /* Hack to fix bug #8786: makes '\' to "\\" */
  686. if (*szname == L'\\')
  687. *pwch++ = L'\\';
  688. }
  689. *pwch++ = L'\0';
  690. /* Output the current filename for RCPP messages */
  691. MyWrite(fhout, L"#line 1\"", 8 * sizeof(wchar_t));
  692. MyWrite(fhout, wch_buf, wcslen(wch_buf) * sizeof(wchar_t));
  693. MyWrite(fhout, L"\"\r\n", 3 * sizeof(wchar_t));
  694. /* Determine if the input file is Unicode */
  695. fFileType = DetermineFileType (fhin);
  696. /* Process each line of the input file. */
  697. while (fgetl(wch_buf, READ_MAX, fFileType == DFT_FILE_IS_16_BIT, fhin)) {
  698. /* keep track of the number of lines read */
  699. Linenumber = iLine++;
  700. if ((iLine & RC_PREPROCESS_UPDATE) == 0)
  701. UpdateStatus(1, iLine);
  702. /* Skip the Byte Order Mark and the leading bytes. */
  703. pwch = wch_buf;
  704. while (*pwch && (iswspace(*pwch) || *pwch == 0xFEFF))
  705. pwch++;
  706. /* if the line is a rcinclude line... */
  707. if (strpre(L"rcinclude", pwch)) {
  708. /* Get the name of the rcincluded file. */
  709. pfilename = skipblanks(pwch + 9, TRUE);
  710. MyWrite(fhout, L"#include \"", 10 * sizeof(WCHAR));
  711. MyWrite(fhout, pfilename, wcslen(pfilename) * sizeof(WCHAR));
  712. MyWrite(fhout, L"\"\r\n", 3 * sizeof(WCHAR));
  713. } else if (strpre(L"#pragma", pwch)) {
  714. WCHAR cSave;
  715. pfilename = skipblanks(pwch + 7, FALSE);
  716. if (strpre(L"code_page", pfilename)) {
  717. pfilename = skipblanks(pfilename + 9, FALSE);
  718. if (*pfilename == L'(') {
  719. ULONG cp = 0;
  720. pfilename = skipblanks(pfilename + 1, FALSE);
  721. // really should allow hex/octal, but ...
  722. if (iswdigit(*pfilename)) {
  723. while (iswdigit(*pfilename)) {
  724. cp = cp * 10 + (*pfilename++ - L'0');
  725. }
  726. pfilename = skipblanks(pfilename, FALSE);
  727. } else if (strpre(L"default", pfilename)) {
  728. cp = uiDefaultCodePage;
  729. pfilename = skipblanks(pfilename + 7, FALSE);
  730. }
  731. if (cp == 0) {
  732. error(4212, pfilename);
  733. } else if (*pfilename != L')') {
  734. error(4211);
  735. } else if (cp == CP_WINUNICODE) {
  736. if (fWarnInvalidCodePage) {
  737. warning(4213);
  738. } else {
  739. fatal(4213);
  740. }
  741. } else if (!IsValidCodePage(cp)) {
  742. if (fWarnInvalidCodePage) {
  743. warning(4214);
  744. } else {
  745. fatal(4214);
  746. }
  747. } else {
  748. uiCodePage = cp;
  749. /* Copy the #pragma line to the temp file. */
  750. MyWrite(fhout, pwch, wcslen(pwch) * sizeof(WCHAR));
  751. MyWrite(fhout, L"\r\n", 2 * sizeof(WCHAR));
  752. }
  753. } else {
  754. error(4210);
  755. }
  756. }
  757. } else if (!*pwch) {
  758. fBlanks = TRUE;
  759. } else {
  760. if (fBlanks) {
  761. swprintf(szT, L"#line %d\r\n", iLine);
  762. MyWrite(fhout, szT, wcslen(szT) * sizeof(WCHAR));
  763. fBlanks = FALSE;
  764. }
  765. /* Copy the .RC line to the temp file. */
  766. MyWrite(fhout, pwch, wcslen(pwch) * sizeof(WCHAR));
  767. MyWrite(fhout, L"\r\n", 2 * sizeof(WCHAR));
  768. }
  769. }
  770. lCPPTotalLinenumber = iLine;
  771. Linenumber = 0;
  772. uiCodePage = uiDefaultCodePage;
  773. MyFree(wch_buf);
  774. MyFree(szT);
  775. fclose(fhout);
  776. fclose(fhin);
  777. }
  778. /*---------------------------------------------------------------------------*/
  779. /* */
  780. /* quit() */
  781. /* */
  782. /*---------------------------------------------------------------------------*/
  783. void quit(const wchar_t *wsz)
  784. {
  785. /* print out the error message */
  786. if (wsz != NULL) {
  787. SendWarning(L"\n");
  788. SendError(wsz);
  789. SendWarning(L"\n");
  790. }
  791. CleanUpFiles();
  792. /* delete output file */
  793. if (resname) {
  794. _wremove(resname);
  795. }
  796. if (hHeap) {
  797. HeapDestroy(hHeap);
  798. }
  799. Nerrors++;
  800. longjmp(jb, Nerrors);
  801. }
  802. extern "C"
  803. BOOL WINAPI Handler(DWORD fdwCtrlType)
  804. {
  805. if (fdwCtrlType == CTRL_C_EVENT) {
  806. SendWarning(L"\n");
  807. SET_MSG(20101);
  808. SendWarning(Msg_Text);
  809. CleanUpFiles();
  810. HeapDestroy(hHeap);
  811. /* Delete output file */
  812. if (resname) {
  813. _wremove(resname);
  814. }
  815. return(FALSE);
  816. }
  817. return(FALSE);
  818. }
  819. VOID
  820. CleanUpFiles(
  821. void
  822. )
  823. {
  824. TermSymbolInfo(NULL_FILE);
  825. // Close ALL files.
  826. if (fhBin != NULL) {
  827. fclose(fhBin);
  828. }
  829. if (fhInput != NULL) {
  830. fclose(fhInput);
  831. }
  832. if (fhCode != NULL) {
  833. fclose(fhCode);
  834. }
  835. p0_terminate();
  836. // Clean up after font directory temp file
  837. if (nFontsRead) {
  838. _wremove(L"rc$x.fdr");
  839. }
  840. // Delete the temporary files
  841. if (szTempFileName) {
  842. _wremove(szTempFileName);
  843. }
  844. if (szTempFileName2) {
  845. _wremove(szTempFileName2);
  846. }
  847. if (Nerrors > 0) {
  848. _wremove(resname);
  849. }
  850. }