Source code of Windows XP (NT5)
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.

1054 lines
30 KiB

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