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.

1403 lines
41 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. #define EOLCHAR L';'
  12. #define STRCHAR L'"'
  13. #define CHRCHAR L'\''
  14. #define SGNCHAR L'-'
  15. #define iswhite( c ) ((c != SYMUSESTART) && (c != SYMDEFSTART) &&\
  16. ((WCHAR)c <= L' ') ? TRUE : FALSE)
  17. static WCHAR curChar;
  18. static WCHAR curCharFTB; /* Cur char From Token Buf */
  19. static PWCHAR CurPtrTB;
  20. static PFILE inpfh;
  21. static int curLin, curCol;
  22. extern BOOL bExternParse;
  23. /* Must be sorted */
  24. KEY keyList[] =
  25. {
  26. { L"ALT", TKALT },
  27. { L"ASCII", TKASCII },
  28. { L"AUTO3STATE", TKAUTO3 },
  29. { L"AUTOCHECKBOX", TKAUTOCHECK },
  30. { L"AUTORADIOBUTTON", TKAUTORADIO },
  31. { L"BEGIN", BEGIN },
  32. { L"BEDIT", TKBEDIT },
  33. { L"BITMAP", TKBITMAP },
  34. { L"BLOCK", TKBLOCK },
  35. { L"BUTTON", TKBUTTON },
  36. { L"CAPTION", TKCAPTION },
  37. { L"CHARACTERISTICS", TKCHARACTERISTICS },
  38. { L"CHECKBOX", TKCHECKBOX },
  39. { L"CHECKED", TKCHECKED },
  40. { L"CLASS", TKCLASS },
  41. { L"COMBOBOX", TKCOMBOBOX },
  42. { L"CONTROL", TKCONTROL },
  43. { L"CTEXT", TKCTEXT },
  44. { L"DEFPUSHBUTTON", TKDEFPUSHBUTTON },
  45. { L"DISCARDABLE", TKDISCARD },
  46. { L"DLGINCLUDE", TKDLGINCLUDE },
  47. { L"DLGINIT", TKDLGINIT },
  48. { L"EDIT", TKEDIT },
  49. { L"EDITTEXT", TKEDITTEXT },
  50. { L"END", END },
  51. { L"EXSTYLE", TKEXSTYLE },
  52. { L"FILEFLAGS", TKFILEFLAGS },
  53. { L"FILEFLAGSMASK", TKFILEFLAGSMASK },
  54. { L"FILEOS", TKFILEOS },
  55. { L"FILESUBTYPE", TKFILESUBTYPE },
  56. { L"FILETYPE", TKFILETYPE },
  57. { L"FILEVERSION", TKFILEVERSION },
  58. { L"FIXED", TKFIXED },
  59. { L"FONT", TKFONT },
  60. { L"GRAYED", TKGRAYED },
  61. { L"GROUPBOX", TKGROUPBOX },
  62. { L"HEDIT", TKHEDIT },
  63. { L"HELP", TKHELP },
  64. { L"ICON", TKICON },
  65. { L"IEDIT", TKIEDIT },
  66. { L"IMPURE", TKIMPURE },
  67. { L"INACTIVE", TKINACTIVE },
  68. { L"LANGUAGE", TKLANGUAGE },
  69. { L"LISTBOX", TKLISTBOX },
  70. { L"LOADONCALL", TKLOADONCALL },
  71. { L"LTEXT", TKLTEXT },
  72. { L"MENU", TKMENU },
  73. { L"MENUBARBREAK", TKBREAKWBAR },
  74. { L"MENUBREAK", TKBREAK },
  75. { L"MENUITEM", TKMENUITEM },
  76. { L"MESAGETABLE", TKMESSAGETABLE },
  77. { L"MOVEABLE", TKMOVEABLE },
  78. { L"NOINVERT", TKNOINVERT },
  79. { L"NONSHARED", TKIMPURE },
  80. { L"NOT", TKNOT },
  81. { L"OWNERDRAW", TKOWNERDRAW },
  82. { L"POPUP", TKPOPUP },
  83. { L"PRELOAD", TKPRELOAD },
  84. { L"PRODUCTVERSION", TKPRODUCTVERSION },
  85. { L"PURE", TKPURE },
  86. { L"PUSHBOX", TKPUSHBOX },
  87. { L"PUSHBUTTON", TKPUSHBUTTON },
  88. { L"RADIOBUTTON", TKRADIOBUTTON },
  89. { L"RCDATA", TKRCDATA },
  90. { L"RTEXT", TKRTEXT },
  91. { L"SCROLLBAR", TKSCROLLBAR },
  92. { L"SEPARATOR", TKSEPARATOR },
  93. { L"SHARED", TKPURE },
  94. { L"SHIFT", TKSHIFT },
  95. { L"STATE3", TK3STATE },
  96. { L"STATIC", TKSTATIC },
  97. { L"STYLE", TKSTYLE },
  98. { L"USERBUTTON", TKUSERBUTTON },
  99. { L"VALUE", TKVALUE },
  100. { L"VERSION", TKVERSION },
  101. { L"VIRTKEY", TKVIRTKEY },
  102. { NULL, 0 }
  103. };
  104. SKEY skeyList[] =
  105. {
  106. { L',', COMMA },
  107. { L'|', OR },
  108. { L'(', LPAREN },
  109. { L')', RPAREN },
  110. { L'{', BEGIN },
  111. { L'}', END },
  112. { L'~', TILDE },
  113. { L'+', TKPLUS },
  114. { L'-', TKMINUS },
  115. { L'&', AND },
  116. { L'=', EQUAL },
  117. { EOFMARK, EOFMARK },
  118. { L'\000', 0 }
  119. };
  120. /*---------------------------------------------------------------------------*/
  121. /* */
  122. /* LexInit() - */
  123. /* */
  124. /*---------------------------------------------------------------------------*/
  125. int
  126. LexInit(
  127. PFILE fh
  128. )
  129. {
  130. /* zero errors so far */
  131. errorCount = 0;
  132. curLin = 1;
  133. curCol = 0;
  134. inpfh = fh;
  135. /* Read initial character */
  136. OurGetChar();
  137. return TRUE;
  138. }
  139. /*---------------------------------------------------------------------------*/
  140. /* */
  141. /* GetCharFTB() - */
  142. /* */
  143. /*---------------------------------------------------------------------------*/
  144. WCHAR
  145. GetCharFTB(
  146. void
  147. )
  148. {
  149. return(curCharFTB = *CurPtrTB++);
  150. }
  151. /*---------------------------------------------------------------------------*/
  152. /* */
  153. /* OurGetChar() - */
  154. /* */
  155. /* Read a character, treating semicolon as an end of line comment char */
  156. /* */
  157. /*---------------------------------------------------------------------------*/
  158. WCHAR
  159. OurGetChar(
  160. void
  161. )
  162. {
  163. if ((LitChar() != EOFMARK) && (curChar == CHCOMMENT))
  164. // if comment, HARD LOOP until EOLN
  165. while ((LitChar() != EOFMARK) && (curChar != CHNEWLINE));
  166. return(curChar);
  167. }
  168. /*---------------------------------------------------------------------------*/
  169. /* */
  170. /* FileChar() - */
  171. /* */
  172. /*---------------------------------------------------------------------------*/
  173. WCHAR
  174. FileChar(
  175. void
  176. )
  177. {
  178. static WCHAR rgchLine[MAXSTR];
  179. static int ibNext = MAXSTR;
  180. size_t cch;
  181. WCHAR ch;
  182. if (ibNext >= MAXSTR) {
  183. ibNext = 0;
  184. cch = MyRead(inpfh, rgchLine, MAXSTR * sizeof(WCHAR));
  185. if (cch < (MAXSTR * sizeof(WCHAR))) {
  186. fclose(inpfh);
  187. // NULL terminate the input buffer
  188. *(rgchLine + (cch / sizeof(WCHAR))) = L'\0';
  189. }
  190. }
  191. ch = rgchLine[ibNext];
  192. if (ch != L'\0') {
  193. ibNext++;
  194. }
  195. return(ch);
  196. }
  197. /*---------------------------------------------------------------------------*/
  198. /* */
  199. /* CopyToken() - */
  200. /* */
  201. /*---------------------------------------------------------------------------*/
  202. void
  203. CopyToken(
  204. PTOKEN ptgt_token,
  205. PTOKEN psrc_token
  206. )
  207. {
  208. ptgt_token->longval = psrc_token->longval;
  209. ptgt_token->row = psrc_token->row;
  210. ptgt_token->col = psrc_token->col;
  211. ptgt_token->flongval = psrc_token->flongval;
  212. ptgt_token->val = psrc_token->val;
  213. ptgt_token->type = psrc_token->type;
  214. ptgt_token->realtype = psrc_token->realtype;
  215. wcscpy(ptgt_token->sym.name, psrc_token->sym.name);
  216. wcscpy(ptgt_token->sym.file, psrc_token->sym.file);
  217. ptgt_token->sym.line = psrc_token->sym.line;
  218. ptgt_token->sym.nID = psrc_token->sym.nID;
  219. }
  220. /*---------------------------------------------------------------------------*/
  221. /* */
  222. /* LitChar() - */
  223. /* */
  224. /*---------------------------------------------------------------------------*/
  225. /* Read a literal character, without interpreting EOL comments */
  226. WCHAR
  227. LitChar(
  228. void
  229. )
  230. {
  231. static int fNewLine = TRUE;
  232. int fIgnore = FALSE;
  233. int fBackSlash = FALSE;
  234. int fDot;
  235. PWCHAR pch;
  236. WCHAR buf[_MAX_PATH];
  237. TOKEN token_save;
  238. for (; ; ) {
  239. switch (curChar = FileChar()) {
  240. case 0:
  241. curChar = EOFMARK;
  242. goto char_return;
  243. case 0xFEFF: // skip Byte Order Mark
  244. continue;
  245. case SYMDEFSTART:
  246. {
  247. int fNewLineSave = fNewLine;
  248. GetSymbolDef(TRUE, curChar);
  249. fNewLine = fNewLineSave;
  250. break;
  251. }
  252. case CHCARRIAGE:
  253. curChar = CHSPACE;
  254. if (!fIgnore)
  255. goto char_return;
  256. break;
  257. case CHNEWLINE:
  258. fNewLine = TRUE;
  259. curLin++;
  260. {
  261. static long lTotalLin = 0;
  262. if ((lTotalLin++ & RC_COMPILE_UPDATE) == 0)
  263. UpdateStatus(2, lTotalLin);
  264. }
  265. if (!fIgnore)
  266. goto char_return;
  267. break;
  268. /* skip whitespace before #line - don't clear fNewLine */
  269. case CHSPACE:
  270. case CHTAB:
  271. if (!fIgnore)
  272. goto char_return;
  273. break;
  274. case CHDIRECTIVE:
  275. if (fNewLine) {
  276. WCHAR tch;
  277. fDot = FALSE;
  278. /* also, leave fNewLine set, since we read thru \n */
  279. /* read the 'line' part */
  280. if ((tch = FileChar()) != L'l') {
  281. if (tch == L'p') {
  282. if (FileChar() != L'r')
  283. goto DirectiveError;
  284. if (FileChar() != L'a')
  285. goto DirectiveError;
  286. if (FileChar() != L'g')
  287. goto DirectiveError;
  288. if (FileChar() != L'm')
  289. goto DirectiveError;
  290. if (FileChar() != L'a')
  291. goto DirectiveError;
  292. /*
  293. ** This is very specific, as any #pragma will
  294. ** be a code_page pragma written by p0prepro.c.
  295. */
  296. CopyToken( &token_save, &token );
  297. GetToken(FALSE); /* get #pragma and ignore */
  298. GetToken(FALSE); /* get code_page and ignore */
  299. GetToken(TOKEN_NOEXPRESSION); /* get codepage value only*/
  300. /* don't check return value */
  301. uiCodePage = token.val; /* assume ok */
  302. /* read through end of line */
  303. while (curChar != CHNEWLINE) {
  304. curChar = FileChar();
  305. }
  306. CopyToken( &token, &token_save );
  307. continue;
  308. } else {
  309. goto DirectiveError;
  310. }
  311. }
  312. if (FileChar() != L'i')
  313. goto DirectiveError;
  314. if (FileChar() != L'n')
  315. goto DirectiveError;
  316. if (FileChar() != L'e')
  317. goto DirectiveError;
  318. /* up to filename, grabbing line number as we go */
  319. /* note that curChar first contains '#', because */
  320. /* we don't read a new character into curChar */
  321. curLin = 0;
  322. do {
  323. if (curChar >= L'0' && curChar <= L'9') {
  324. curLin *= 10;
  325. curLin += curChar - L'0';
  326. }
  327. curChar = FileChar();
  328. } while (curChar != CHQUOTE && curChar != CHNEWLINE);
  329. /* don't change curFile or fIgnore if this is just a
  330. * #line <lineno>
  331. */
  332. if (curChar == CHNEWLINE)
  333. break;
  334. /* read the filename. detect the presence of .c or .h */
  335. pch = buf;
  336. do {
  337. curChar = FileChar();
  338. switch (towlower(curChar)) {
  339. /* treat backslash like normal char, set flag. */
  340. case L'\\':
  341. if (fBackSlash) {
  342. fBackSlash = FALSE;
  343. } else {
  344. fBackSlash = TRUE;
  345. fIgnore = FALSE;
  346. fDot = FALSE;
  347. *pch++ = curChar;
  348. }
  349. break;
  350. /* line format sanity check: no embedded newlines */
  351. case CHNEWLINE:
  352. case 0:
  353. DirectiveError:
  354. LexError1(2101);
  355. /* stop reading filename when we hit a quote */
  356. case CHQUOTE:
  357. break;
  358. /* if we see a ., prepare to find extension */
  359. case CHEXTENSION:
  360. fBackSlash = FALSE;
  361. fDot = TRUE;
  362. *pch++ = curChar;
  363. break;
  364. /* if there's a C or H after a '.', its not RCINCLUDE'd */
  365. case CHCSOURCE:
  366. case CHCHEADER:
  367. fBackSlash = FALSE;
  368. fIgnore = fDot;
  369. fDot = FALSE;
  370. *pch++ = curChar;
  371. break;
  372. /* any other character in a file means the next character
  373. won't be after a dot, and the last char up to now
  374. wasn't C or H.
  375. */
  376. default:
  377. fIgnore = FALSE;
  378. fDot = FALSE;
  379. *pch++ = curChar;
  380. break;
  381. }
  382. } while (curChar != CHQUOTE);
  383. *pch = 0;
  384. wcsncpy(curFile, buf, _MAX_PATH);
  385. /* read through end of line */
  386. do {
  387. curChar = FileChar();
  388. } while (curChar != CHNEWLINE);
  389. break;
  390. }
  391. /* else, fall through, treat like normal char */
  392. default:
  393. fNewLine = FALSE;
  394. if (!fIgnore)
  395. goto char_return;
  396. }
  397. }
  398. char_return:
  399. if (bExternParse)
  400. *((WCHAR*) GetSpace(sizeof(WCHAR))) = curChar;
  401. return curChar;
  402. }
  403. /*---------------------------------------------------------------------------*/
  404. /* */
  405. /* GetStr() - */
  406. /* */
  407. /*---------------------------------------------------------------------------*/
  408. VOID
  409. GetStr(
  410. void
  411. )
  412. {
  413. PWCHAR s;
  414. WCHAR ch;
  415. WCHAR temptok[MAXSTR];
  416. SHORT i = 0;
  417. int inc;
  418. UCHAR Octal_Num;
  419. UCHAR HexNum;
  420. /* token type is string literal */
  421. token.realtype = STRLIT;
  422. /*
  423. ** NB: FloydR
  424. ** The use of token.realtype is a hack for RCDATA.
  425. **
  426. ** When we converted RC to be Unicode-based, all the
  427. ** separate "case STRLIT:" code was removed, and the LSTRLIT
  428. ** cases took over for them. Alternatively, we could have
  429. ** left the STRLIT case, but removed the code it accessed
  430. ** and move the STRLIT case prior/after the LSTRLIT case,
  431. ** since they were now identical. They were removed in favor
  432. ** of smaller/faster code.
  433. **
  434. ** However, RCDATA still had a need to discern the difference,
  435. ** so I added token.realtype, set it to STRLIT in GetStr(),
  436. ** set it to LSTRLIT in GetLStr() (below), and check it in
  437. ** GetRCData() in rctg.c.
  438. **
  439. */
  440. token.type = LSTRLIT;
  441. token.val = 0;
  442. s = tokenbuf;
  443. // Read string until " or EOF
  444. while (LitChar() != EOFMARK) {
  445. if (curChar == STRCHAR) {
  446. if (OurGetChar() != STRCHAR) {
  447. goto gotstr;
  448. }
  449. }
  450. if (token.val++ == MAXSTR) {
  451. LexError1(2102); // "string literal too long"
  452. }
  453. *s++ = curChar;
  454. }
  455. if (curChar == EOFMARK) {
  456. LexError1(2103); // "unexpected end of file in string literal"
  457. }
  458. gotstr:
  459. *s++ = 0;
  460. s = tokenbuf;
  461. /* process escape characters in the string */
  462. while (*s != 0) {
  463. if (*s == L'\\') {
  464. s++;
  465. if (*s == L'\\')
  466. temptok[i++] = L'\\';
  467. else if (*s == L'T' || *s == L't')
  468. temptok[i++] = L'\011'; /* Tab */
  469. else if (*s == 0x0a) /* continuation slash */
  470. ; /* ignore and let it go trough the s++ at the end so we skip the 0x0a char*/
  471. else if (*s == L'A' || *s == L'a')
  472. temptok[i++] = L'\010'; /* Right Align */
  473. else if (*s == L'n')
  474. temptok[i++] = fMacRsrcs ? 13 : 10; /* linefeed */
  475. else if (*s == L'r')
  476. temptok[i++] = fMacRsrcs ? 10 : 13; /* carriage return */
  477. else if (*s == L'"')
  478. temptok[i++] = L'"'; /* quote character */
  479. else if (*s == L'X' || *s == L'x') { /* Hexidecimal digit */
  480. USHORT wCount;
  481. HexNum = 0;
  482. ++s;
  483. for (wCount = 2 ;
  484. wCount && iswxdigit((ch=(WCHAR)towupper(*s)));
  485. --wCount) {
  486. if (ch >= L'A')
  487. inc = ch - L'A' + 10;
  488. else
  489. inc = ch - L'0';
  490. HexNum = HexNum * 16 + inc;
  491. s++;
  492. }
  493. MultiByteToWideChar(uiCodePage, MB_PRECOMPOSED, (LPCSTR) &HexNum, 1, &temptok[i], 1);
  494. i++;
  495. s--;
  496. } else if (*s >= L'0' && *s <= L'7') { /* octal character */
  497. USHORT wCount;
  498. Octal_Num = 0;
  499. for (wCount = 3; wCount && *s >= L'0' && *s <= L'7'; --wCount) {
  500. Octal_Num = (Octal_Num * 8 + (*s - L'0'));
  501. s++;
  502. }
  503. MultiByteToWideChar(uiCodePage, MB_PRECOMPOSED, (LPCSTR) &Octal_Num, 1, &temptok[i], 1);
  504. i++;
  505. s--;
  506. }
  507. else {
  508. temptok[i++] = L'\\';
  509. s--;
  510. }
  511. } else
  512. temptok[i++] = *s;
  513. s++;
  514. }
  515. // Zero terminate
  516. temptok[i] = L'\0';
  517. memcpy(tokenbuf, temptok, sizeof(WCHAR) * (i + 1));
  518. token.val = (USHORT) i;
  519. }
  520. /*---------------------------------------------------------------------------*/
  521. /* */
  522. /* GetLStr() - */
  523. /* */
  524. /*---------------------------------------------------------------------------*/
  525. VOID
  526. GetLStr(
  527. void
  528. )
  529. {
  530. PWCHAR s;
  531. WCHAR ch;
  532. WCHAR temptok[MAXSTR];
  533. SHORT i = 0;
  534. int inc;
  535. int Octal_Num;
  536. int HexNum;
  537. // Token type is string literal
  538. token.realtype = token.type = LSTRLIT;
  539. token.val = 0;
  540. s = tokenbuf;
  541. // Read string until " or EOF
  542. while (LitChar() != EOFMARK) {
  543. if (curChar == STRCHAR) {
  544. if (OurGetChar() != STRCHAR) {
  545. goto gotstr;
  546. }
  547. }
  548. if (token.val++ == MAXSTR) {
  549. LexError1(2102); // "string literal too long"
  550. }
  551. *s++ = curChar;
  552. }
  553. if (curChar == EOFMARK) {
  554. LexError1(2103); // "unexpected end of file in string literal"
  555. }
  556. if (token.val >= 256) {
  557. SendError(L"\n");
  558. SET_MSG(4205, curFile, token.row);
  559. SendError(Msg_Text);
  560. }
  561. gotstr:
  562. *s++ = 0;
  563. s = tokenbuf;
  564. /* process escape characters in the string */
  565. while (*s != 0) {
  566. if (*s == L'\\') {
  567. s++;
  568. if (*s == L'\\')
  569. temptok[i++] = L'\\';
  570. else if (*s == L'T' || *s == L't')
  571. temptok[i++] = L'\011'; /* Tab */
  572. else if (*s == L'A' || *s == L'a')
  573. temptok[i++] = L'\010'; /* Right Align */
  574. else if (*s == L'n')
  575. temptok[i++] = fMacRsrcs ? 13 : 10; /* linefeed */
  576. else if (*s == L'r')
  577. temptok[i++] = fMacRsrcs ? 10 : 13; /* carriage return */
  578. else if (*s == L'"')
  579. temptok[i++] = L'"'; /* quote character */
  580. else if (*s == L'X' || *s == L'x') { /* Hexidecimal digit */
  581. USHORT wCount;
  582. HexNum = 0;
  583. ++s;
  584. for (wCount = 4 ;
  585. wCount && iswxdigit((ch=(WCHAR)towupper(*s)));
  586. --wCount) {
  587. if (ch >= L'A')
  588. inc = ch - L'A' + 10;
  589. else
  590. inc = ch - L'0';
  591. HexNum = HexNum * 16 + inc;
  592. s++;
  593. }
  594. temptok[i++] = (WCHAR)HexNum;
  595. s--;
  596. }
  597. else if (*s >= L'0' && *s <= L'7') { /* octal character */
  598. USHORT wCount;
  599. Octal_Num = 0;
  600. for (wCount = 7; wCount && *s >= L'0' && *s <= L'7'; --wCount) {
  601. Octal_Num = (Octal_Num * 8 + (*s - L'0'));
  602. s++;
  603. }
  604. temptok[i++] = (WCHAR)Octal_Num;
  605. s--;
  606. }
  607. }
  608. else
  609. temptok[i++] = *s;
  610. s++;
  611. }
  612. // Zero terminate
  613. temptok[i] = L'\0';
  614. memcpy(tokenbuf, temptok, sizeof(WCHAR) * (i + 1));
  615. token.val = (USHORT) i;
  616. }
  617. /*---------------------------------------------------------------------------*/
  618. /* */
  619. /* GetToken() - */
  620. /* */
  621. /*---------------------------------------------------------------------------*/
  622. int
  623. GetToken(
  624. int fReportError
  625. )
  626. {
  627. for (; ; ) {
  628. /* skip whitespace */
  629. while (iswhite( curChar))
  630. OurGetChar();
  631. /* take care of 'random' symbols use */
  632. if (curChar == SYMUSESTART)
  633. GetSymbol(fReportError, curChar);
  634. token.sym.name[0] = L'\0';
  635. /* remember location of token */
  636. token.row = curLin;
  637. token.col = curCol;
  638. /* determine if token is EOF, number, string, or keyword */
  639. token.type = EOFMARK;
  640. switch (curChar) {
  641. case EOFMARK:
  642. break;
  643. case SGNCHAR:
  644. case L'~':
  645. if (fReportError & TOKEN_NOEXPRESSION)
  646. GetNumNoExpression();
  647. else
  648. GetNum();
  649. break;
  650. case STRCHAR:
  651. GetStr();
  652. break;
  653. default:
  654. if (curChar == L'(' && !(fReportError & TOKEN_NOEXPRESSION))
  655. GetNum();
  656. else if (iswdigit( curChar)) {
  657. if (fReportError & TOKEN_NOEXPRESSION)
  658. GetNumNoExpression();
  659. else
  660. GetNum();
  661. if (curChar == SYMUSESTART)
  662. GetSymbol(fReportError, curChar);
  663. } else {
  664. if (!GetKwd( fReportError))
  665. continue;
  666. if (token.type == TKLSTR) {
  667. GetLStr();
  668. break;
  669. }
  670. }
  671. }
  672. break;
  673. }
  674. return token.type;
  675. }
  676. /*---------------------------------------------------------------------------*/
  677. /* */
  678. /* GetXNum() - */
  679. /* */
  680. /*---------------------------------------------------------------------------*/
  681. /* get hexadecimal number */
  682. LONG
  683. GetXNum(
  684. void
  685. )
  686. {
  687. LONG n = 0;
  688. while (iswxdigit (GetCharFTB()))
  689. n = n * 16 + ( ((curCharFTB = (WCHAR)towupper(curCharFTB)) >= L'A') ?
  690. (WCHAR)(curCharFTB - L'A' + 10) :
  691. (WCHAR)(curCharFTB - L'0'));
  692. return (n);
  693. }
  694. /*---------------------------------------------------------------------------*/
  695. /* */
  696. /* GetONum() - */
  697. /* */
  698. /*---------------------------------------------------------------------------*/
  699. /* get octal number */
  700. LONG
  701. GetONum(
  702. void
  703. )
  704. {
  705. LONG n = 0;
  706. while (GetCharFTB() >= L'0' && curCharFTB <= L'7')
  707. n = n * 8 + (curCharFTB - L'0');
  708. return (n);
  709. }
  710. /*---------------------------------------------------------------------------*/
  711. /* */
  712. /* GetDNum() - */
  713. /* */
  714. /*---------------------------------------------------------------------------*/
  715. /* get decimal number */
  716. LONG
  717. GetDNum(
  718. void
  719. )
  720. {
  721. LONG n = 0;
  722. while (iswdigit(curCharFTB)) {
  723. n = n * 10 + (curCharFTB - L'0');
  724. GetCharFTB();
  725. }
  726. return (n);
  727. }
  728. PWSTR
  729. GetWord(
  730. PWSTR pStr
  731. )
  732. {
  733. WCHAR ch;
  734. PSKEY pskey;
  735. *pStr++ = curCharFTB = curChar;
  736. while (TRUE) {
  737. ch = OurGetChar();
  738. if (ch <= L' ')
  739. goto FoundBreak;
  740. switch (ch) {
  741. case EOFMARK:
  742. case EOLCHAR:
  743. case STRCHAR:
  744. case CHRCHAR:
  745. goto FoundBreak;
  746. default:
  747. for (pskey = skeyList; pskey->skwd; pskey++)
  748. if (pskey->skwd == ch)
  749. goto FoundBreak;
  750. }
  751. *pStr++ = ch;
  752. }
  753. FoundBreak:
  754. *pStr = 0;
  755. return(pStr);
  756. }
  757. /* GetNumFTB
  758. * This function was previously added as a hack to handle converting
  759. * radices. I'm treating this as a (ugly) black box to read a number.
  760. */
  761. VOID
  762. GetNumFTB(
  763. void
  764. )
  765. {
  766. int signFlag;
  767. USHORT wNotFlag;
  768. LONG n;
  769. /* Small hack to support NOT: If we have a tilde, skip whitespace
  770. * before the number.
  771. */
  772. if (curChar == L'~')
  773. while (iswhite(curChar))
  774. OurGetChar();
  775. /* Get the entire number in tokenbuf before computing radix */
  776. GetWord(tokenbuf);
  777. /* Skip the first char. It is already in curCharFTB */
  778. CurPtrTB = tokenbuf + 1;
  779. /* mark token type as numeric literal */
  780. token.type = NUMLIT;
  781. /* find sign of number */
  782. if (curCharFTB == SGNCHAR) {
  783. signFlag = TRUE;
  784. GetCharFTB();
  785. } else {
  786. signFlag = FALSE;
  787. }
  788. /* Check for a NOT (~) */
  789. if (curCharFTB == L'~') {
  790. wNotFlag = TRUE;
  791. GetCharFTB();
  792. } else {
  793. wNotFlag = FALSE;
  794. }
  795. /* determine radix of number */
  796. if (curCharFTB == L'0') {
  797. GetCharFTB();
  798. if (curCharFTB == L'x')
  799. n = GetXNum();
  800. else if (curCharFTB == L'o')
  801. n = GetONum();
  802. else
  803. n = GetDNum();
  804. } else {
  805. n = GetDNum();
  806. }
  807. /* find size of number */
  808. if ((curCharFTB == L'L') || (curCharFTB == L'l')) {
  809. token.flongval = TRUE;
  810. GetCharFTB();
  811. } else {
  812. token.flongval = FALSE;
  813. }
  814. /* account for sign */
  815. if (signFlag)
  816. n = -n;
  817. /* Account for the NOT */
  818. if (wNotFlag)
  819. n = ~n;
  820. /* Set longval regardless of flongval because Dialog Styles
  821. * always have to be be long
  822. */
  823. token.longval = n;
  824. token.val = (USHORT)n;
  825. }
  826. /* ----- Static information needed for parsing ----- */
  827. static int wLongFlag;
  828. static int nParenCount;
  829. /*---------------------------------------------------------------------------*/
  830. /* */
  831. /* GetNum() - */
  832. /* */
  833. /*---------------------------------------------------------------------------*/
  834. VOID
  835. GetNum(
  836. void
  837. )
  838. {
  839. LONG lValue;
  840. /* Initialize */
  841. wLongFlag = 0;
  842. nParenCount = 0;
  843. /* Return the number */
  844. lValue = GetExpression();
  845. /* Make sure we had matched parens */
  846. if (nParenCount)
  847. ParseError1(1013); //"Mismatched parentheses"
  848. /* Return as the proper token */
  849. if (wLongFlag)
  850. token.flongval = TRUE;
  851. token.type = NUMLIT;
  852. token.longval = lValue;
  853. token.val = (USHORT)lValue;
  854. }
  855. /* GetNumNoExpression
  856. * Gets a number without doing expression parsing on it.
  857. */
  858. VOID
  859. GetNumNoExpression(
  860. VOID
  861. )
  862. {
  863. /* Call the single number parser */
  864. GetNumFTB();
  865. }
  866. /* GetExpression
  867. * Gets an expression, which is defined as any number of
  868. * operators and operands inside one set of parens.
  869. */
  870. LONG
  871. GetExpression(
  872. VOID
  873. )
  874. {
  875. LONG op1;
  876. LONG op2;
  877. WCHAR byOperator;
  878. UINT wFlags;
  879. /* Get the first operand */
  880. op1 = GetOperand();
  881. /* take care of symbol use */
  882. if (curChar == SYMUSESTART) {
  883. GetSymbol(TRUE, curChar);
  884. token.sym.nID = token.val;
  885. }
  886. /* Loop until end of expression */
  887. for (; ; ) {
  888. /* Get the operator */
  889. wFlags = GetOperator(&byOperator);
  890. /* If this is a right paren, dec the count */
  891. if (byOperator == L')') {
  892. /* Bring the paren count back down */
  893. --nParenCount;
  894. /* Skip the paren and any trailing whitespace */
  895. OurGetChar();
  896. SkipWhitespace();
  897. }
  898. /* If this isn't an operator, we're done with the expression */
  899. if (!wFlags) {
  900. token.sym.nID = (unsigned)op1;
  901. return op1;
  902. }
  903. token.sym.name[0] = L'\0';
  904. /* Get the second operand */
  905. op2 = GetOperand();
  906. /* Compute the value of the expression */
  907. switch (byOperator) {
  908. case L'+':
  909. op1 += op2;
  910. break;
  911. case L'-':
  912. op1 -= op2;
  913. break;
  914. case L'&':
  915. op1 &= op2;
  916. break;
  917. case L'|':
  918. op1 |= op2;
  919. break;
  920. }
  921. }
  922. }
  923. /* GetOperand
  924. * Gets an operand, which may either be a single number or may
  925. * be an entire expression.
  926. */
  927. LONG
  928. GetOperand(
  929. VOID
  930. )
  931. {
  932. /* Check to see if we need to descend a level */
  933. if (curChar == L'(') {
  934. /* Bump paren count so we can match them up */
  935. ++nParenCount;
  936. /* Skip past the paren char */
  937. OurGetChar();
  938. SkipWhitespace();
  939. /* Return the value of the computed expression for the operand */
  940. return GetExpression();
  941. }
  942. /* If this isn't a number, return an error */
  943. if (curChar != L'-' && curChar != L'~' && !iswdigit(curChar)) {
  944. GetKwd(FALSE);
  945. ParseError2(2237, tokenbuf);
  946. return 0;
  947. }
  948. /* Get the number in the token structure */
  949. GetNumFTB();
  950. /* See if we need to force the result long */
  951. if (token.flongval)
  952. wLongFlag = TRUE;
  953. /* Skip trailing whitespace */
  954. SkipWhitespace();
  955. /* Return the value */
  956. return token.longval;
  957. }
  958. /* GetOperator
  959. * Gets the next character and decides if it should be an operator.
  960. * If it should, it returns TRUE, which causes the expression
  961. * parser to continue. Otherwise, it returns FALSE which causes
  962. * the expression parser to pop up a level.
  963. */
  964. int
  965. GetOperator(
  966. PWCHAR pOperator
  967. )
  968. {
  969. static WCHAR byOps[] = L"+-|&";
  970. PWCHAR pOp;
  971. /* take care of symbol use */
  972. if (curChar == SYMUSESTART)
  973. GetSymbol(TRUE, curChar);
  974. /* See if this character is an operator */
  975. pOp = wcschr(byOps, curChar);
  976. *pOperator = curChar;
  977. /* If we didn't find it, get out */
  978. if (!pOp)
  979. return FALSE;
  980. /* Otherwise, read trailing whitespace */
  981. OurGetChar();
  982. SkipWhitespace();
  983. /* Return the operator */
  984. return TRUE;
  985. }
  986. /* SkipWhitespace
  987. * Skips past whitespace in the current stream.
  988. */
  989. VOID
  990. SkipWhitespace(
  991. VOID
  992. )
  993. {
  994. while (iswhite(curChar))
  995. OurGetChar();
  996. }
  997. /*---------------------------------------------------------------------------*/
  998. /* */
  999. /* GetKwd() - */
  1000. /* */
  1001. /*---------------------------------------------------------------------------*/
  1002. int
  1003. GetKwd(
  1004. int fReportError
  1005. )
  1006. {
  1007. PSKEY sk;
  1008. /* see if a special character */
  1009. for (sk = &skeyList[ 0 ]; sk->skwd; sk++) {
  1010. if (curChar == sk->skwd) {
  1011. token.type = (UCHAR)sk->skwdval;
  1012. token.val = 0;
  1013. OurGetChar();
  1014. return (token.type >= FIRSTKWD);
  1015. }
  1016. }
  1017. /* else read characters up to the next seperator */
  1018. GetWord(tokenbuf);
  1019. // Check for TKLSTR -- new for NT
  1020. if (!tokenbuf[1] && (towupper(tokenbuf[0]) == L'L') && (curChar == STRCHAR)) {
  1021. token.type = TKLSTR;
  1022. return TRUE;
  1023. }
  1024. /* look up keyword in table */
  1025. if ((token.val = FindKwd( tokenbuf)) != (USHORT)-1) {
  1026. token.type = (UCHAR)token.val;
  1027. } else if (fReportError) {
  1028. LexError2(2104, tokenbuf); //"undefined keyword or key name: %ws"
  1029. }
  1030. else
  1031. token.type = 0;
  1032. return TRUE;
  1033. }
  1034. /*---------------------------------------------------------------------------*/
  1035. /* */
  1036. /* FindKwd() - */
  1037. /* */
  1038. /*---------------------------------------------------------------------------*/
  1039. USHORT
  1040. FindKwd(
  1041. PWCHAR str
  1042. )
  1043. {
  1044. PKEY k;
  1045. int t;
  1046. /* linear search the keyword table for the key */
  1047. for (k = &keyList[0]; k->kwd; k++)
  1048. if (!(t = _wcsicmp( str, k->kwd)))
  1049. return k->kwdval;
  1050. else if (t < 0)
  1051. break;
  1052. /* if not found, return -1 as keyword id */
  1053. return (USHORT)-1;
  1054. }
  1055. /*---------------------------------------------------------------------------*/
  1056. /* */
  1057. /* LexError1() - */
  1058. /* */
  1059. /*---------------------------------------------------------------------------*/
  1060. void LexError1(int iMsg)
  1061. {
  1062. SET_MSG(iMsg, curFile, curLin);
  1063. SendError(Msg_Text);
  1064. quit(NULL);
  1065. }
  1066. /*---------------------------------------------------------------------------*/
  1067. /* */
  1068. /* LexError2() - */
  1069. /* */
  1070. /*---------------------------------------------------------------------------*/
  1071. void LexError2(int iMsg, const wchar_t *str)
  1072. {
  1073. SET_MSG(iMsg, curFile, curLin, str);
  1074. SendError(Msg_Text);
  1075. quit(NULL);
  1076. }
  1077. /*---------------------------------------------------------------------------*/
  1078. /* */
  1079. /* GetNameOrd() - */
  1080. /* */
  1081. /*---------------------------------------------------------------------------*/
  1082. /* For reading in resource names and types. */
  1083. int
  1084. GetNameOrd(
  1085. void
  1086. )
  1087. {
  1088. PWCHAR pch;
  1089. int fString;
  1090. /* get space delimited string */
  1091. if (!GetGenText())
  1092. return FALSE;
  1093. /* convert to upper case */
  1094. _wcsupr(tokenbuf);
  1095. /* is it a string or number */
  1096. for (pch=tokenbuf,fString=0 ; *pch ; pch++ )
  1097. if (!iswdigit(*pch))
  1098. fString = 1;
  1099. /* determine if ordinal */
  1100. if (tokenbuf[0] == L'0' && tokenbuf[1] == L'X') {
  1101. int HexNum;
  1102. int inc;
  1103. USHORT wCount;
  1104. PWCHAR s;
  1105. HexNum = 0;
  1106. s = &tokenbuf[2];
  1107. for (wCount = 4 ; wCount && iswxdigit(*s) ; --wCount) {
  1108. if (*s >= L'A')
  1109. inc = *s - L'A' + 10;
  1110. else
  1111. inc = *s - L'0';
  1112. HexNum = HexNum * 16 + inc;
  1113. s++;
  1114. }
  1115. token.val = (USHORT)HexNum;
  1116. } else if (fString) {
  1117. token.val = 0;
  1118. } else {
  1119. token.val = (USHORT)wcsatoi(tokenbuf);
  1120. }
  1121. return TRUE;
  1122. }
  1123. /*---------------------------------------------------------------------------*/
  1124. /* */
  1125. /* GetGenText() - */
  1126. /* */
  1127. /*---------------------------------------------------------------------------*/
  1128. /* returns a pointer to a string of generic text */
  1129. PWCHAR
  1130. GetGenText(
  1131. void
  1132. )
  1133. {
  1134. PWCHAR s;
  1135. s = tokenbuf;
  1136. /* skip white space */
  1137. while (iswhite(curChar))
  1138. OurGetChar();
  1139. if (curChar == EOFMARK) {
  1140. token.type = EOFMARK;
  1141. return NULL;
  1142. }
  1143. /* random symbol */
  1144. if (curChar == SYMUSESTART)
  1145. GetSymbol(TRUE, curChar);
  1146. token.sym.name[0] = L'\0';
  1147. /* read space delimited string */
  1148. *s++ = curChar;
  1149. while (( LitChar() != EOFMARK) && ( !iswhite(curChar)))
  1150. *s++ = curChar;
  1151. *s++ = 0; /* put a \0 on the end of the string */
  1152. OurGetChar(); /* read in the next character */
  1153. if (curChar == EOFMARK)
  1154. token.type = EOFMARK;
  1155. if (curChar == SYMUSESTART) {
  1156. GetSymbol(TRUE, curChar);
  1157. token.sym.nID = token.val;
  1158. }
  1159. return (tokenbuf);
  1160. }