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.

1451 lines
41 KiB

  1. /****************************************************************************/
  2. /* */
  3. /* RCTP.C - */
  4. /* */
  5. /* Windows 3.0 Resource Compiler - Resource Parser */
  6. /* */
  7. /* */
  8. /****************************************************************************/
  9. #include "rc.h"
  10. static BOOL fComma;
  11. /* Dialog template format :
  12. dialogName DIALOGEX x, y, cx, cy [, helpID]
  13. [style ...]
  14. [exStyle ...]
  15. [FONT height, name [, [weight] [, [italic [, [charset]]]]]]
  16. [caption ...]
  17. [menu ...]
  18. [memFlags [pure] [discard n] [preload]]
  19. BEGIN
  20. [CONTROL "text", id, BUTTON | STATIC | EDIT | LISTBOX | SCROLLBAR | COMBOBOX | "class", style, x, y, cx, cy]
  21. [FONT height, name [, [weight] [, [italic]]]]
  22. [BEGIN
  23. data-element-1 [,
  24. data-element-2 [,
  25. ... ]]
  26. END]
  27. [LTEXT "text", id, x, y, cx, cy]
  28. [RTEXT "text", id, x, y, cx, cy]
  29. [CTEXT "text", id, x, y, cx, cy]
  30. [AUTO3STATE "text", id, x, y, cx, cy]
  31. [AUTOCHECKBOX "text", id, x, y, cx, cy]
  32. [AUTORADIOBUTTON "text", id, x, y, cx, cy]
  33. [CHECKBOX "text", id, x, y, cx, cy]
  34. [PUSHBOX "text", id, x, y, cx, cy]
  35. [PUSHBUTTON "text", id, x, y, cx, cy]
  36. [RADIOBUTTON "text", id, x, y, cx, cy]
  37. [STATE3 "text", id, x, y, cx, cy]
  38. [USERBUTTON "text", id, x, y, cx, cy]
  39. [EDITTEXT id, x, y, cx, cy]
  40. [BEDIT id, x, y, cx, cy]
  41. [HEDIT id, x, y, cx, cy]
  42. [IEDIT id, x, y, cx, cy]
  43. ...
  44. END
  45. MenuName MENUEX
  46. BEGIN
  47. [MENUITEM "text" [, [id] [, [type] [, [state]]]]]
  48. [POPUP "text" [, [id] [, [type] [, [state] [, [help id]]]]]
  49. BEGIN
  50. [MENUITEM "text" [, [id] [, [type] [, [state]]]]]
  51. ...
  52. END]
  53. ...
  54. END
  55. Menu template format
  56. MenuName MENU
  57. BEGIN
  58. [MENUITEM "text", id [option, ...]]
  59. [POPUP "text" [, option, ...]
  60. BEGIN
  61. [MENUITEM "text", id [option, ...]]
  62. ...
  63. END ]
  64. ...
  65. END
  66. */
  67. /* Dialog template format :
  68. dialogname DIALOG x, y, cx, cy
  69. [language ...]
  70. [style ...]
  71. [caption ... ]
  72. [menu ... ]
  73. [memflags [pure] [discard n] [preload]]
  74. begin
  75. [CONTROL "text", id, BUTTON | STATIC | EDIT | LISTBOX | SCROLLBAR | COMBOBOX | "class", style, x, y, cx, cy]
  76. [LTEXT "text", id, x, y, cx, cy]
  77. [RTEXT "text", id, x, y, cx, cy]
  78. [CTEXT "text", id, x, y, cx, cy]
  79. [CHECKBOX "text", id, x, y, cx, cy]
  80. [PUSHBUTTON "text", id, x, y, cx, cy]
  81. [RADIOBUTTON "text", id, x, y, cx, cy]
  82. [EDITTEXT id, x, y, cx, cy]
  83. ...
  84. end
  85. Menu template format
  86. MenuName MENU
  87. BEGIN
  88. [MENUITEM "text", id [option, ...]]
  89. [POPUP "text" [, option, ...]
  90. BEGIN
  91. [MENUITEM "text", id [option, ...]]
  92. ...
  93. END ]
  94. ...
  95. END
  96. */
  97. #define CTLSTYLE(s) (WS_CHILD | WS_VISIBLE | (s))
  98. /* list of control id's to check for duplicates */
  99. PDWORD pid;
  100. int cidMac;
  101. int cidMax;
  102. BOOL
  103. CheckStr(
  104. PWCHAR pStr
  105. )
  106. {
  107. if (token.type == STRLIT || token.type == LSTRLIT) {
  108. if (token.val > MAXTOKSTR-1) {
  109. SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(4208), curFile, token.row);
  110. SendError(Msg_Text);
  111. tokenbuf[MAXTOKSTR-1] = TEXT('\0');
  112. token.val = MAXTOKSTR-2;
  113. }
  114. memcpy(pStr, tokenbuf, (token.val+1)*sizeof(WCHAR));
  115. return(TRUE);
  116. }
  117. return(FALSE);
  118. }
  119. // ----------------------------------------------------------------------------
  120. //
  121. // GetDlgValue
  122. //
  123. // ----------------------------------------------------------------------------
  124. SHORT
  125. GetDlgValue(
  126. void
  127. )
  128. {
  129. SHORT sVal;
  130. if (!GetFullExpression(&sVal, GFE_ZEROINIT | GFE_SHORT))
  131. ParseError1(2109); //"Expected Numerical Dialog constant"
  132. return(sVal);
  133. }
  134. void
  135. GetCoords(
  136. PSHORT x,
  137. PSHORT y,
  138. PSHORT cx,
  139. PSHORT cy
  140. )
  141. {
  142. *x = GetDlgValue();
  143. if (token.type == COMMA)
  144. GetToken(TOKEN_NOEXPRESSION);
  145. *y = GetDlgValue();
  146. if (token.type == COMMA)
  147. GetToken(TOKEN_NOEXPRESSION);
  148. *cx= GetDlgValue();
  149. if (token.type == COMMA)
  150. GetToken(TOKEN_NOEXPRESSION);
  151. *cy= GetDlgValue();
  152. }
  153. typedef struct tagCTRLTYPE {
  154. WORD type;
  155. DWORD dwStyle;
  156. BYTE bCode;
  157. BYTE fHasText;
  158. } CTRLTYPE;
  159. CTRLTYPE ctrlTypes[] = {
  160. { TKGROUPBOX, BS_GROUPBOX, BUTTONCODE, TRUE },
  161. { TKPUSHBUTTON, BS_PUSHBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
  162. { TKDEFPUSHBUTTON, BS_DEFPUSHBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
  163. { TKCHECKBOX, BS_CHECKBOX | WS_TABSTOP, BUTTONCODE, TRUE },
  164. { TKRADIOBUTTON, BS_RADIOBUTTON, BUTTONCODE, TRUE },
  165. { TKAUTO3, BS_AUTO3STATE | WS_TABSTOP, BUTTONCODE, TRUE },
  166. { TKAUTOCHECK, BS_AUTOCHECKBOX | WS_TABSTOP, BUTTONCODE, TRUE },
  167. { TKAUTORADIO, BS_AUTORADIOBUTTON, BUTTONCODE, TRUE },
  168. { TKPUSHBOX, BS_PUSHBOX | WS_TABSTOP, BUTTONCODE, TRUE },
  169. { TK3STATE, BS_3STATE | WS_TABSTOP, BUTTONCODE, TRUE },
  170. { TKUSERBUTTON, BS_USERBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
  171. { TKLTEXT, ES_LEFT | WS_GROUP, STATICCODE, TRUE },
  172. { TKRTEXT, ES_RIGHT | WS_GROUP, STATICCODE, TRUE },
  173. { TKCTEXT, ES_CENTER | WS_GROUP, STATICCODE, TRUE },
  174. { TKICON, SS_ICON, STATICCODE, TRUE },
  175. { TKBEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
  176. { TKHEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
  177. { TKIEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
  178. { TKEDITTEXT, ES_LEFT | WS_BORDER | WS_TABSTOP, EDITCODE, FALSE },
  179. { TKLISTBOX, WS_BORDER | LBS_NOTIFY, LISTBOXCODE, FALSE },
  180. { TKCOMBOBOX, 0, COMBOBOXCODE, FALSE },
  181. { TKSCROLLBAR, 0, SCROLLBARCODE, FALSE }
  182. };
  183. #define C_CTRLTYPES (sizeof(ctrlTypes) / sizeof(CTRLTYPE))
  184. // ----------------------------------------------------------------------------
  185. //
  186. // GetDlgItems(fDlgEx) -
  187. //
  188. // ----------------------------------------------------------------------------
  189. int
  190. GetDlgItems(
  191. BOOL fDlgEx
  192. )
  193. {
  194. CTRL ctrl;
  195. int i;
  196. cidMac = 0;
  197. cidMax = 100;
  198. pid = (PDWORD) MyAlloc(sizeof(DWORD)*cidMax);
  199. if (!pid)
  200. return FALSE;
  201. GetToken(TRUE);
  202. /* read all the controls in the dialog */
  203. ctrl.id = 0L; // initialize the control's id to 0
  204. while (token.type != END) {
  205. ctrl.dwHelpID = 0L;
  206. ctrl.dwExStyle = 0L;
  207. ctrl.dwStyle = WS_CHILD | WS_VISIBLE;
  208. ctrl.text[0] = 0;
  209. ctrl.fOrdinalText = FALSE;
  210. if (token.type == TKCONTROL) {
  211. ParseCtl(&ctrl, fDlgEx);
  212. } else {
  213. for (i = 0; i < C_CTRLTYPES; i++)
  214. if (token.type == ctrlTypes[i].type)
  215. break;
  216. if (i == C_CTRLTYPES) {
  217. ParseError1(2111); //"Invalid Control type : ", tokenbuf
  218. return(FALSE);
  219. }
  220. ctrl.dwStyle |= ctrlTypes[i].dwStyle;
  221. if (fMacRsrcs &&
  222. (token.type == TKPUSHBUTTON ||
  223. token.type == TKDEFPUSHBUTTON ||
  224. token.type == TKCHECKBOX ||
  225. token.type == TKAUTO3 ||
  226. token.type == TKAUTOCHECK ||
  227. token.type == TKPUSHBOX ||
  228. token.type == TK3STATE ||
  229. token.type == TKUSERBUTTON))
  230. {
  231. ctrl.dwStyle &= ~WS_TABSTOP;
  232. }
  233. if (ctrlTypes[i].bCode) {
  234. ctrl.Class[0] = 0xFFFF;
  235. ctrl.Class[1] = ctrlTypes[i].bCode;
  236. } else {
  237. CheckStr(ctrl.Class);
  238. }
  239. if (ctrlTypes[i].fHasText)
  240. GetCtlText(&ctrl);
  241. // find the ID and the coordinates
  242. GetCtlID(&ctrl, fDlgEx);
  243. GetCoords(&ctrl.x, &ctrl.y, &ctrl.cx, &ctrl.cy);
  244. // get optional style, exstyle, and helpid
  245. if (token.type == COMMA) {
  246. GetToken(TOKEN_NOEXPRESSION);
  247. GetFullExpression(&ctrl.dwStyle, 0);
  248. }
  249. }
  250. if (token.type == COMMA) {
  251. GetToken(TOKEN_NOEXPRESSION);
  252. GetFullExpression(&ctrl.dwExStyle, 0);
  253. if (fDlgEx && (token.type == COMMA)) {
  254. GetToken(TOKEN_NOEXPRESSION);
  255. GetFullExpression(&ctrl.dwHelpID, GFE_ZEROINIT);
  256. }
  257. }
  258. SetUpItem(&ctrl, fDlgEx); /* gen the code for it */
  259. if (fDlgEx && (token.type == BEGIN)) {
  260. /* align any CreateParams are there */
  261. //WriteAlign(); not yet!!!
  262. // we're ok passing NULL in for pRes here because PreBeginParse
  263. // won't have to use pRes
  264. // Note that passing fDlgEx is actually redundant since it
  265. // will always be TRUE here, but we'll do it in case someone
  266. // else ever calls SetItemExtraCount
  267. SetItemExtraCount(GetRCData(NULL), fDlgEx);
  268. GetToken(TOKEN_NOEXPRESSION);
  269. }
  270. }
  271. MyFree(pid);
  272. return TRUE;
  273. }
  274. /*---------------------------------------------------------------------------*/
  275. /* */
  276. /* GetDlg() - */
  277. /* */
  278. /*---------------------------------------------------------------------------*/
  279. int
  280. GetDlg(
  281. PRESINFO pRes,
  282. PDLGHDR pDlg,
  283. BOOL fDlgEx
  284. )
  285. {
  286. /* initialize and defaults */
  287. pDlg->dwExStyle = pRes->exstyleT;
  288. pDlg->dwStyle = WS_POPUPWINDOW | WS_SYSMENU;
  289. pDlg->MenuName[0] = 0;
  290. pDlg->Title[0] = 0;
  291. pDlg->Class[0] = 0;
  292. pDlg->fOrdinalMenu = FALSE;
  293. pDlg->fClassOrdinal = FALSE;
  294. pDlg->pointsize = 0;
  295. // get x, y, cx, cy
  296. GetCoords(&pDlg->x, &pDlg->y, &pDlg->cx, &pDlg->cy);
  297. /* get optional parameters */
  298. if (!DLexOptionalArgs(pRes, pDlg, fDlgEx))
  299. return FALSE;
  300. if (pDlg->pointsize)
  301. pDlg->dwStyle |= DS_SETFONT;
  302. else
  303. pDlg->dwStyle &= ~DS_SETFONT;
  304. /* output header to the resource buffer */
  305. SetUpDlg(pDlg, fDlgEx);
  306. /* make sure we have a BEGIN */
  307. if (token.type != BEGIN)
  308. ParseError1(2112); //"BEGIN expected in Dialog"
  309. /* get the dialog items */
  310. GetDlgItems(fDlgEx);
  311. if (fMacRsrcs)
  312. SwapItemCount();
  313. /* make sure this ended on an END */
  314. if (token.type != END)
  315. ParseError1(2113); //"END expected in Dialog"
  316. return (TRUE);
  317. }
  318. typedef struct tagCTRLNAME {
  319. BYTE bCode;
  320. WORD wType;
  321. PWCHAR pszName;
  322. } CTRLNAME;
  323. CTRLNAME ctrlNames[] = {
  324. { BUTTONCODE, TKBUTTON, L"button" },
  325. { EDITCODE, TKEDIT, L"edit" },
  326. { STATICCODE, TKSTATIC, L"static" },
  327. { LISTBOXCODE, TKLISTBOX, L"listbox" },
  328. { SCROLLBARCODE, TKSCROLLBAR, L"scrollbar" },
  329. { COMBOBOXCODE, TKCOMBOBOX, L"combobox" }
  330. };
  331. #define C_CTRLNAMES (sizeof(ctrlNames) / sizeof(CTRLNAME))
  332. /*---------------------------------------------------------------------------*/
  333. /* */
  334. /* ParseCtl() - */
  335. /* */
  336. /*---------------------------------------------------------------------------*/
  337. // for a control of the form CTL
  338. void
  339. ParseCtl(
  340. PCTRL LocCtl,
  341. BOOL fDlgEx
  342. )
  343. { /* by now we've read the CTL */
  344. int i;
  345. /* get the control text and identifier */
  346. GetCtlText(LocCtl);
  347. GetCtlID(LocCtl, fDlgEx);
  348. if (token.type == NUMLIT) {
  349. LocCtl->Class[0] = (char) token.val;
  350. LocCtl->Class[1] = 0;
  351. } else if (token.type == LSTRLIT) {
  352. // We will now convert class name strings to short form magic
  353. // numbers. These magic numbers are order dependent as defined in
  354. // USER. This provides some space savings in resource files.
  355. for (i = C_CTRLNAMES; i; ) {
  356. if (!_wcsicmp(tokenbuf, ctrlNames[--i].pszName))
  357. goto Found1;
  358. }
  359. CheckStr(LocCtl->Class);
  360. } else {
  361. for (i = C_CTRLNAMES; i; ) {
  362. if (token.type == ctrlNames[--i].wType)
  363. goto Found1;
  364. }
  365. ParseError1(2114); //"Expected control class name"
  366. Found1:
  367. LocCtl->Class[0] = 0xFFFF;
  368. LocCtl->Class[1] = ctrlNames[i].bCode;
  369. }
  370. /* get the style bits */
  371. GetTokenNoComma(TOKEN_NOEXPRESSION);
  372. GetFullExpression(&LocCtl->dwStyle, 0);
  373. /* get the coordinates of the control */
  374. ICGetTok();
  375. GetCoords(&LocCtl->x, &LocCtl->y, &LocCtl->cx, &LocCtl->cy);
  376. }
  377. /*---------------------------------------------------------------------------*/
  378. /* */
  379. /* GetCtlText() - */
  380. /* */
  381. /*---------------------------------------------------------------------------*/
  382. VOID
  383. GetCtlText(
  384. PCTRL pLocCtl
  385. )
  386. {
  387. GetTokenNoComma(TOKEN_NOEXPRESSION);
  388. if (CheckStr(pLocCtl->text)) {
  389. pLocCtl->fOrdinalText = FALSE;
  390. token.sym.name[0] = L'\0';
  391. token.sym.nID = 0;
  392. } else if (token.type == NUMLIT) {
  393. wcsitow(token.val, pLocCtl->text, 10);
  394. pLocCtl->fOrdinalText = TRUE;
  395. WriteSymbolUse(&token.sym);
  396. } else {
  397. ParseError1(2115); //"Text string or ordinal expected in Control"
  398. }
  399. }
  400. /*---------------------------------------------------------------------------*/
  401. /* */
  402. /* GetCtlID() - */
  403. /* */
  404. /*---------------------------------------------------------------------------*/
  405. VOID
  406. GetCtlID(
  407. PCTRL pLocCtl,
  408. BOOL fDlgEx
  409. )
  410. {
  411. WORD wGFE = GFE_ZEROINIT;
  412. int i;
  413. ICGetTok();
  414. WriteSymbolUse(&token.sym);
  415. if (!fDlgEx)
  416. wGFE |= GFE_SHORT;
  417. if (GetFullExpression(&pLocCtl->id, wGFE)) {
  418. if (!fDlgEx && pLocCtl->id != (DWORD)(WORD)-1 ||
  419. fDlgEx && pLocCtl->id != (DWORD)-1) {
  420. for (i=0 ; i<cidMac ; i++) {
  421. if (pLocCtl->id == *(pid+i) && !fSkipDuplicateCtlIdWarning) {
  422. i = (int)pLocCtl->id;
  423. SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(2182),
  424. curFile, token.row, i);
  425. SendError(Msg_Text);
  426. break;
  427. }
  428. }
  429. if (cidMac == cidMax) {
  430. PDWORD pidNew;
  431. cidMax += 100;
  432. pidNew = (PDWORD) MyAlloc(cidMax*sizeof(DWORD));
  433. memcpy(pidNew, pid, cidMac*sizeof(DWORD));
  434. MyFree(pid);
  435. pid = pidNew;
  436. }
  437. *(pid+cidMac++) = pLocCtl->id;
  438. }
  439. } else {
  440. ParseError1(2116); //"Expecting number for ID"
  441. }
  442. if (token.type == COMMA)
  443. ICGetTok();
  444. }
  445. // ----------------------------------------------------------------------------
  446. //
  447. // DLexOptionArgs(pRes, fDlgEx) -
  448. //
  449. // ----------------------------------------------------------------------------
  450. BOOL
  451. DLexOptionalArgs(
  452. PRESINFO pRes,
  453. PDLGHDR pDlg,
  454. BOOL fDlgEx
  455. )
  456. {
  457. /* read all the optional dialog items */
  458. if (fDlgEx && (token.type == COMMA)) {
  459. GetToken(TOKEN_NOEXPRESSION);
  460. GetFullExpression(&pDlg->dwHelpID, GFE_ZEROINIT);
  461. }
  462. while (token.type != BEGIN) {
  463. switch (token.type) {
  464. case TKLANGUAGE:
  465. pRes->language = GetLanguage();
  466. GetToken(FALSE);
  467. break;
  468. case TKVERSION:
  469. GetToken(FALSE);
  470. if (token.type != NUMLIT)
  471. ParseError1(2139);
  472. pRes->version = token.longval;
  473. GetToken(FALSE);
  474. break;
  475. case TKCHARACTERISTICS:
  476. GetToken(FALSE);
  477. if (token.type != NUMLIT)
  478. ParseError1(2140);
  479. pRes->characteristics = token.longval;
  480. GetToken(FALSE);
  481. break;
  482. case TKSTYLE:
  483. // If CAPTION statement preceded STYLE statement, then we
  484. // already must have WS_CAPTION bits set in the "style"
  485. // field and we must not lose it;
  486. if ((pDlg->dwStyle & WS_CAPTION) == WS_CAPTION)
  487. pDlg->dwStyle = WS_CAPTION;
  488. else
  489. pDlg->dwStyle = 0;
  490. GetTokenNoComma(TOKEN_NOEXPRESSION);
  491. GetFullExpression(&pDlg->dwStyle, 0);
  492. break;
  493. case TKEXSTYLE:
  494. GetTokenNoComma(TOKEN_NOEXPRESSION);
  495. GetFullExpression(&pDlg->dwExStyle, 0);
  496. break;
  497. case TKCAPTION:
  498. DGetTitle(pDlg);
  499. break;
  500. case TKMENU:
  501. DGetMenuName(pDlg);
  502. break;
  503. case TKCLASS:
  504. DGetClassName(pDlg);
  505. break;
  506. case TKFONT:
  507. DGetFont(pDlg, fDlgEx);
  508. break;
  509. default:
  510. ParseError1(2112); //"BEGIN expected in dialog");
  511. return FALSE;
  512. }
  513. }
  514. return TRUE;
  515. }
  516. /*---------------------------------------------------------------------------*/
  517. /* */
  518. /* DGetFont() - */
  519. /* */
  520. /*---------------------------------------------------------------------------*/
  521. void
  522. DGetFont(
  523. PDLGHDR pDlg,
  524. BOOL fDlgEx
  525. )
  526. {
  527. WORD w;
  528. int i;
  529. GetToken(TRUE);
  530. if (!GetFullExpression(&pDlg->pointsize, GFE_ZEROINIT | GFE_SHORT))
  531. ParseError1(2117); //"Expected numeric point size"
  532. if (token.type == COMMA)
  533. ICGetTok();
  534. if (!CheckStr(pDlg->Font))
  535. ParseError1(2118); //"Expected font face name"
  536. if (_wcsicmp(pDlg->Font, L"System") &&
  537. szSubstituteFontName[0] != UNICODE_NULL) {
  538. for (i=0; i<nBogusFontNames; i++) {
  539. if (!_wcsicmp(pszBogusFontNames[i], pDlg->Font)) {
  540. GenWarning4(4510, (PCHAR)pDlg->Font, (PCHAR)szSubstituteFontName, 0 ); // Warning for hard coded fonts
  541. wcscpy(pDlg->Font, szSubstituteFontName);
  542. }
  543. }
  544. }
  545. GetToken(TRUE);
  546. pDlg->bCharSet = DEFAULT_CHARSET;
  547. if (fDlgEx && (token.type == COMMA)) {
  548. GetToken(TOKEN_NOEXPRESSION);
  549. if (GetFullExpression(&w, GFE_ZEROINIT | GFE_SHORT))
  550. pDlg->wWeight = w;
  551. if (token.type == COMMA) {
  552. GetToken(TOKEN_NOEXPRESSION);
  553. if (token.type == NUMLIT) {
  554. pDlg->bItalic = (token.val) ? TRUE : FALSE;
  555. GetToken(TOKEN_NOEXPRESSION);
  556. if (token.type == COMMA) {
  557. GetToken(TOKEN_NOEXPRESSION);
  558. if (GetFullExpression(&w, GFE_ZEROINIT | GFE_SHORT))
  559. pDlg->bCharSet = (UCHAR) w;
  560. }
  561. }
  562. }
  563. }
  564. }
  565. /*---------------------------------------------------------------------------*/
  566. /* */
  567. /* DGetMenuName() - */
  568. /* */
  569. /*---------------------------------------------------------------------------*/
  570. /* gets the unquoted string of the name of the optional menu associated */
  571. /* with the dialog. */
  572. VOID
  573. DGetMenuName(
  574. PDLGHDR pDlg
  575. )
  576. {
  577. if (GetGenText()) {
  578. /* copy the menu name */
  579. token.type = LSTRLIT;
  580. CheckStr(pDlg->MenuName);
  581. /* check if menu name is an ordinal */
  582. if (wcsdigit(pDlg->MenuName[0]))
  583. pDlg->fOrdinalMenu = TRUE;
  584. GetToken(TRUE);
  585. }
  586. }
  587. /*---------------------------------------------------------------------------*/
  588. /* */
  589. /* DGetTitle() - */
  590. /* */
  591. /*---------------------------------------------------------------------------*/
  592. VOID
  593. DGetTitle(
  594. PDLGHDR pDlg
  595. )
  596. {
  597. GetToken(TRUE);
  598. if (CheckStr(pDlg->Title))
  599. pDlg->dwStyle |= WS_CAPTION;
  600. else
  601. ParseError1(2119); //"Expecting quoted string in dialog title"
  602. GetToken(TRUE);
  603. }
  604. /*---------------------------------------------------------------------------*/
  605. /* */
  606. /* DGetClassName() - */
  607. /* */
  608. /*---------------------------------------------------------------------------*/
  609. VOID
  610. DGetClassName(
  611. PDLGHDR pDlg
  612. )
  613. {
  614. GetToken(TRUE);
  615. if (!CheckStr(pDlg->Class)) {
  616. if (token.type == NUMLIT) {
  617. wcsitow(token.val, pDlg->Class, 10);
  618. pDlg->fClassOrdinal = TRUE;
  619. } else {
  620. ParseError1(2120); //"Expecting quoted string in dialog class"
  621. }
  622. }
  623. GetToken(TRUE);
  624. }
  625. /*---------------------------------------------------------------------------*/
  626. /* Gets a token, ignoring commas. Returns the token type. */
  627. /* */
  628. /* ICGetTok() - */
  629. /* */
  630. /*---------------------------------------------------------------------------*/
  631. /* Get token, but ignore commas */
  632. USHORT
  633. ICGetTok(
  634. VOID
  635. )
  636. {
  637. fComma = FALSE; // NT added the use of this fComma flag
  638. GetToken(TRUE);
  639. while (token.type == COMMA) {
  640. GetToken(TRUE);
  641. fComma = TRUE; // and they set it here
  642. }
  643. return (USHORT)token.type;
  644. }
  645. /* GetTokenNoComma
  646. * This function replaces ICGetTok() but has a flag to support
  647. * the turning off of expression parsing.
  648. */
  649. USHORT
  650. GetTokenNoComma(
  651. USHORT wFlags
  652. )
  653. {
  654. /* Get a token */
  655. GetToken(TRUE | wFlags);
  656. /* Ignore any commas */
  657. while (token.type == COMMA)
  658. GetToken(TRUE | wFlags);
  659. return (USHORT)token.type;
  660. }
  661. /************* Menu Parsing Routines *********************/
  662. /*---------------------------------------------------------------------------*/
  663. /* */
  664. /* IsmnOption() - */
  665. /* */
  666. /*---------------------------------------------------------------------------*/
  667. int
  668. IsmnOption(
  669. UINT arg,
  670. PMENUITEM pmn
  671. )
  672. {
  673. /* if we have a valid flag, or it into the menu flags */
  674. switch (arg) {
  675. case TKOWNERDRAW:
  676. pmn->OptFlags |= OPOWNERDRAW;
  677. break;
  678. case TKCHECKED:
  679. pmn->OptFlags |= OPCHECKED;
  680. break;
  681. case TKGRAYED:
  682. pmn->OptFlags |= OPGRAYED;
  683. break;
  684. case TKINACTIVE:
  685. pmn->OptFlags |= OPINACTIVE;
  686. break;
  687. case TKBREAKWBAR:
  688. pmn->OptFlags |= OPBREAKWBAR;
  689. break;
  690. case TKBREAK:
  691. pmn->OptFlags |= OPBREAK;
  692. break;
  693. case TKHELP:
  694. pmn->OptFlags |= OPHELP;
  695. break;
  696. case TKBITMAP:
  697. pmn->OptFlags |= OPBITMAP;
  698. break;
  699. default:
  700. return(FALSE);
  701. }
  702. return(TRUE);
  703. #if 0
  704. if ((arg == OPBREAKWBAR) || (arg == OPHELP ) || (arg == OPGRAYED) ||
  705. (arg == OPUSECHECKBITMAPS) || (arg == OPCHECKED) || (arg == OPBITMAP) ||
  706. (arg == OPOWNERDRAW) || (arg == OPBREAK ) || (arg == OPINACTIVE))
  707. {
  708. pmn->OptFlags |= arg;
  709. return TRUE;
  710. }
  711. #if 0
  712. if (arg == OPHELP) {
  713. pmn->OptFlags |= OPPOPHELP;
  714. return TRUE;
  715. }
  716. #endif
  717. return FALSE;
  718. #endif
  719. }
  720. // ----------------------------------------------------------------------------
  721. //
  722. // DoOldMenuItem() -
  723. //
  724. // ----------------------------------------------------------------------------
  725. WORD
  726. DoOldMenuItem(
  727. int fPopup
  728. )
  729. {
  730. MENUITEM mnTemp;
  731. mnTemp.PopFlag = (UCHAR)fPopup;
  732. GetToken(TRUE);
  733. /* menu choice string */
  734. if (CheckStr(mnTemp.szText)) {
  735. mnTemp.OptFlags = OPPOPUP;
  736. ICGetTok();
  737. if (!fPopup) {
  738. /* change the flag and get the ID if not a popup */
  739. mnTemp.OptFlags = 0;
  740. WriteSymbolUse(&token.sym);
  741. if (!GetFullExpression(&mnTemp.id, GFE_ZEROINIT | GFE_SHORT))
  742. ParseError1(2125); //"Expected ID value for Menuitem"
  743. if (token.type == COMMA)
  744. GetToken(TOKEN_NOEXPRESSION);
  745. }
  746. /* read the menu option flags */
  747. while (IsmnOption(token.type, &mnTemp))
  748. ICGetTok();
  749. } else if (token.type == TKSEPARATOR) {
  750. mnTemp.szText[0] = 0; // MENUITEM SEPARATOR
  751. mnTemp.id = 0;
  752. mnTemp.OptFlags = 0;
  753. ICGetTok();
  754. } else {
  755. ParseError1(2126); //"Expected Menu String"
  756. }
  757. /* set it up in the buffer (?) */
  758. return(SetUpOldMenu(&mnTemp));
  759. }
  760. /*---------------------------------------------------------------------------*/
  761. /* */
  762. /* ParseOldMenu() - */
  763. /* */
  764. /*---------------------------------------------------------------------------*/
  765. int
  766. ParseOldMenu(
  767. int fRecursing,
  768. PRESINFO pRes // 8 char proc name limitation!
  769. )
  770. {
  771. BOOL bItemRead = FALSE;
  772. WORD wEndFlagLoc = 0;
  773. if (!fRecursing) {
  774. PreBeginParse(pRes, 2121);
  775. } else {
  776. /* make sure its really a menu */
  777. if (token.type != BEGIN)
  778. ParseError1(2121); //"BEGIN expected in menu"
  779. GetToken(TRUE);
  780. }
  781. /* get the individual menu items */
  782. while (token.type != END) {
  783. switch (token.type) {
  784. case TKMENUITEM:
  785. bItemRead = TRUE;
  786. wEndFlagLoc = DoOldMenuItem(FALSE);
  787. break;
  788. case TKPOPUP:
  789. bItemRead = TRUE;
  790. wEndFlagLoc = DoOldMenuItem(TRUE);
  791. ParseOldMenu(TRUE, pRes);
  792. break;
  793. default:
  794. ParseError1(2122); //"Unknown Menu SubType :"
  795. break;
  796. }
  797. }
  798. /* did we die on an END? */
  799. if (token.type != END)
  800. ParseError1(2123); //"END expected in menu"
  801. /* make sure we have a menu item */
  802. if (!bItemRead)
  803. ParseError1(2124); //"Empty menus not allowed"
  804. /* Get next token if this was NOT the last END*/
  805. if (fRecursing)
  806. GetToken(TRUE);
  807. /* mark the last item in the menu */
  808. FixOldMenuPatch(wEndFlagLoc);
  809. return (TRUE);
  810. }
  811. /* ----- Version resource stuff ----- */
  812. /* VersionParse
  813. * Parses the VERSION resource and places it in the global buffer
  814. * so it can be written out by SaveResFile().
  815. */
  816. int
  817. VersionParse(
  818. VOID
  819. )
  820. {
  821. int Index;
  822. /* Get the fixed structure entries */
  823. /* Note that VersionParseFixed doesn't actually fail! */
  824. /* This is because VersionBlockStruct doesn't fail. */
  825. Index = VersionParseFixed();
  826. /* Put the following blocks in as sub-blocks. Fix up the length when
  827. * we're done.
  828. */
  829. SetItemCount(Index, (USHORT)(GetItemCount(Index) + VersionParseBlock()));
  830. /* The return data buffer is global */
  831. return TRUE;
  832. }
  833. /* VersionParseFixed
  834. * Parses the fixed portion of the version resource. Returns a pointer
  835. * to the length word of the block. This word has the length of
  836. * the fixed portion precomputed and remains to have the variable
  837. * portion added in.
  838. */
  839. int
  840. VersionParseFixed(
  841. VOID
  842. )
  843. {
  844. VS_FIXEDFILEINFO FixedInfo;
  845. /* Initialize the structure fields */
  846. memset((PCHAR)&FixedInfo, 0, sizeof(FixedInfo));
  847. FixedInfo.dwSignature = 0xfeef04bdL;
  848. FixedInfo.dwStrucVersion = 0x00010000L;
  849. FixedInfo.dwFileDateMS = 0L;
  850. FixedInfo.dwFileDateLS = 0L;
  851. /* Loop through tokens until we get the "BEGIN" token which
  852. * must be present to terminate the fixed portion of the VERSIONINFO
  853. * resource.
  854. */
  855. while (token.type != BEGIN) {
  856. switch (token.type) {
  857. /* The following have four WORDS scrambled into two DWORDS */
  858. case TKFILEVERSION:
  859. VersionGet4Words(&FixedInfo.dwFileVersionMS);
  860. break;
  861. case TKPRODUCTVERSION:
  862. VersionGet4Words(&FixedInfo.dwProductVersionMS);
  863. break;
  864. /* The following have just one DWORD */
  865. case TKFILEFLAGSMASK:
  866. VersionGetDWord(&FixedInfo.dwFileFlagsMask);
  867. break;
  868. case TKFILEFLAGS:
  869. VersionGetDWord(&FixedInfo.dwFileFlags);
  870. break;
  871. case TKFILEOS:
  872. VersionGetDWord(&FixedInfo.dwFileOS);
  873. break;
  874. case TKFILETYPE:
  875. VersionGetDWord(&FixedInfo.dwFileType);
  876. break;
  877. case TKFILESUBTYPE:
  878. VersionGetDWord(&FixedInfo.dwFileSubtype);
  879. break;
  880. /* Other tokens are unknown */
  881. default:
  882. ParseError1(2167); //"Unrecognized VERSIONINFO field;"
  883. }
  884. }
  885. /* Write the block out and return the pointer to the length */
  886. return VersionBlockStruct(L"VS_VERSION_INFO", (PCHAR)&FixedInfo,
  887. sizeof(FixedInfo));
  888. }
  889. /* VersionGet4Words
  890. * Reads a version number from the source file and scrambles them
  891. * to fit in two DWORDs. We force them to put commas in here so
  892. * that if they don't put in enough values we can fill in zeros.
  893. */
  894. VOID
  895. VersionGet4Words(
  896. ULONG *pdw
  897. )
  898. {
  899. // static CHAR szParseError[] = "Version WORDs separated by commas expected";
  900. /* Get the first number */
  901. GetToken(TRUE);
  902. if (token.type != NUMLIT || token.flongval)
  903. ParseError1(2127); //szParseError
  904. *pdw = ((LONG)token.val) << 16;
  905. /* Get the comma. If none, we're done, so fill the rest with zeros */
  906. GetToken(TRUE);
  907. if (token.type != COMMA) {
  908. *++pdw = 0L;
  909. return;
  910. }
  911. /* Get the second number */
  912. GetToken(TRUE);
  913. if (token.type != NUMLIT || token.flongval)
  914. ParseError1(2127); //szParseError
  915. *(PUSHORT)pdw = token.val;
  916. /* Get the comma. If none, we're done, so fill the rest with zeros */
  917. GetToken(TRUE);
  918. if (token.type != COMMA) {
  919. *++pdw = 0L;
  920. return;
  921. }
  922. /* Get the third number */
  923. GetToken(TRUE);
  924. if (token.type != NUMLIT || token.flongval)
  925. ParseError1(2127); //szParseError
  926. *++pdw = ((LONG)token.val) << 16;
  927. /* Get the comma. If none, we're done */
  928. GetToken(TRUE);
  929. if (token.type != COMMA)
  930. return;
  931. /* Get the fourth number */
  932. GetToken(TRUE);
  933. if (token.type != NUMLIT || token.flongval)
  934. ParseError1(2127); //szParseError
  935. *(PUSHORT)pdw = token.val;
  936. /* Get the next token for the loop */
  937. GetToken(TRUE);
  938. }
  939. /* VersionGetDWord
  940. * Reads a single DWORD from the source file into the given variable.
  941. */
  942. VOID
  943. VersionGetDWord(
  944. ULONG *pdw
  945. )
  946. {
  947. /* Get the token */
  948. GetToken(TRUE);
  949. if (token.type != NUMLIT)
  950. ParseError1(2128); //"DWORD expected"
  951. *pdw = token.longval;
  952. /* Get the next token for the loop */
  953. GetToken(TRUE);
  954. }
  955. /* VersionParseBlock
  956. * Parses a block of version information. Note that this block may
  957. * contain one or more additional blocks, causing this function to
  958. * be called recursively. Returns the length of the block which can
  959. * be added to the length of the current block. Returns 0xffff on error.
  960. */
  961. USHORT
  962. VersionParseBlock(
  963. VOID
  964. )
  965. {
  966. USHORT wLen;
  967. int IndexLen;
  968. USHORT wType;
  969. /* Get the current position in the buffer */
  970. wLen = GetBufferLen();
  971. /* The token has already been read. This should be a BEGIN */
  972. if (token.type != BEGIN)
  973. ParseError1(2129); //"BEGIN expected in VERSIONINFO resource"
  974. /* Get the first token. From here on, the VersionBlockVariable()
  975. * routine gets the tokens as it searches for the end of the value
  976. * field.
  977. */
  978. GetToken(TRUE);
  979. /* Loop until we get to the END for this BEGIN */
  980. for (; ; ) {
  981. /* Get and decode the next line type */
  982. switch (token.type) {
  983. case TKVALUE:
  984. case TKBLOCK:
  985. /* Save the type of this token */
  986. wType = token.type;
  987. /* Get the key string */
  988. GetToken(TRUE);
  989. if (token.type != LSTRLIT)
  990. ParseError1(2131); //"Expecting quoted string for key"
  991. /* Now feed in the key string and value items */
  992. IndexLen = VersionBlockVariable(tokenbuf);
  993. /* A "BLOCK" item causes recursion. Current token should be
  994. * "BEGIN"
  995. */
  996. if (wType == TKBLOCK) {
  997. SetItemCount(IndexLen, (USHORT)(GetItemCount(IndexLen) + VersionParseBlock()));
  998. GetToken(TRUE);
  999. }
  1000. break;
  1001. case END:
  1002. /* We're done with this block. Get the next token
  1003. * (read past the "END") and return the length of the block.
  1004. */
  1005. return GetBufferLen() - wLen;
  1006. default:
  1007. ParseError1(2132); //"Expected VALUE, BLOCK, or, END keyword."
  1008. }
  1009. }
  1010. }
  1011. #define DWORDALIGN(w) \
  1012. (((w) + (sizeof(ULONG) - 1)) & ~(USHORT)(sizeof(ULONG) - 1))
  1013. /* VersionBlockStruct
  1014. * Writes a version block without sub-blocks. Sub-blocks are to
  1015. * be written directly after this header. To facilitate this,
  1016. * a pointer to the block length is returned so that it can be modified.
  1017. * This call uses a pre-parsed value item. Use VersionBlockVariable()
  1018. * to parse the value items instead.
  1019. * Note that this actually can't fail!
  1020. */
  1021. int
  1022. VersionBlockStruct(
  1023. PWCHAR pstrKey,
  1024. PCHAR pstrValue,
  1025. USHORT wLenValue
  1026. )
  1027. {
  1028. USHORT wLen;
  1029. int Index;
  1030. ULONG dwPadding = 0L;
  1031. USHORT wAlign;
  1032. /* Pad the block data to DWORD align */
  1033. wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
  1034. if (wAlign)
  1035. WriteBuffer((PCHAR)&dwPadding, wAlign);
  1036. /* Save the current length so we can compute the new block length later */
  1037. wLen = GetBufferLen();
  1038. /* Write a zero for the length for now */
  1039. Index = GetBufferLen();
  1040. WriteWord(0);
  1041. /* Write the length of the value field */
  1042. WriteWord(wLenValue);
  1043. /* data is binary */
  1044. WriteWord(0);
  1045. /* Write the key string now */
  1046. WriteString(pstrKey, TRUE);
  1047. /* Write the value data if there is any */
  1048. if (wLenValue) {
  1049. /* Now we have to DWORD align the value data */
  1050. wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
  1051. if (wAlign)
  1052. WriteBuffer((PSTR)&dwPadding, wAlign);
  1053. /* Write it to the buffer */
  1054. WriteBuffer((PSTR)pstrValue, wLenValue);
  1055. }
  1056. /* Now fix up the block length and return a pointer to it */
  1057. SetItemCount(Index, (USHORT)(GetBufferLen() - wLen));
  1058. return Index;
  1059. }
  1060. /* VersionBlockVariable
  1061. * Writes a version block without sub-blocks. Sub-blocks are to
  1062. * bre written directly after this header. To facilitate this,
  1063. * a pointer to the block length is returned so that it can be modified.
  1064. * VersionBlockVariable() gets the value items by parsing the
  1065. * RC script as RCDATA.
  1066. */
  1067. int
  1068. VersionBlockVariable(
  1069. PWCHAR pstrKey
  1070. )
  1071. {
  1072. USHORT wLen;
  1073. int IndexLen;
  1074. int IndexType;
  1075. int IndexValueLen;
  1076. ULONG dwPadding = 0L;
  1077. USHORT wAlign;
  1078. /* Pad the block data to DWORD align */
  1079. wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
  1080. if (wAlign)
  1081. WriteBuffer((PCHAR)&dwPadding, wAlign);
  1082. /* Save the current length so we can compute the new block length later */
  1083. wLen = GetBufferLen();
  1084. /* Write a zero for the length for now */
  1085. IndexLen = GetBufferLen();
  1086. WriteWord(0);
  1087. /* Write the length of the value field. We fill this in later */
  1088. IndexValueLen = GetBufferLen();
  1089. WriteWord(0);
  1090. /* Assume string data */
  1091. IndexType = GetBufferLen();
  1092. WriteWord(1);
  1093. /* Write the key string now */
  1094. WriteString(pstrKey, TRUE);
  1095. /* Parse and write the value data if there is any */
  1096. SetItemCount(IndexValueLen, VersionParseValue(IndexType));
  1097. /* Now fix up the block length and return a pointer to it */
  1098. SetItemCount(IndexLen, (USHORT)(GetBufferLen() - wLen));
  1099. return IndexLen;
  1100. }
  1101. /* VersionParseValue
  1102. * Parses the fields following either BLOCK or VALUE and following
  1103. * their key string which is parsed by VersionParseBlock().
  1104. * Before writing the first value item out, the field has to be
  1105. * DWORD aligned. Returns the length of the value block.
  1106. */
  1107. USHORT
  1108. VersionParseValue(
  1109. int IndexType
  1110. )
  1111. {
  1112. USHORT wFirst = FALSE;
  1113. USHORT wToken;
  1114. USHORT wAlign;
  1115. ULONG dwPadding = 0L;
  1116. USHORT wLen = 0;
  1117. /* Decode all tokens until we get to the end of this item */
  1118. for (; ; ) {
  1119. /* ICGetTok is GetToken(TRUE) ignoring commas */
  1120. wToken = ICGetTok();
  1121. /* If this is the first item, DWORD align it. Since empty value
  1122. * sections are legal, we have to wait until we actually have data
  1123. * to do this.
  1124. */
  1125. if (!wFirst) {
  1126. wFirst = TRUE;
  1127. wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
  1128. if (wAlign)
  1129. WriteBuffer((PCHAR)&dwPadding, wAlign);
  1130. }
  1131. switch (wToken) {
  1132. case TKVALUE:
  1133. case TKBLOCK:
  1134. case BEGIN:
  1135. case END:
  1136. return wLen;
  1137. case LSTRLIT: /* String, write characters */
  1138. if (tokenbuf[0] == L'\0') /* ignore null strings */
  1139. break;
  1140. /* remove extra nuls */
  1141. while (tokenbuf[token.val-1] == L'\0')
  1142. token.val--;
  1143. wAlign = token.val + 1; /* want the character count */
  1144. wLen += wAlign;
  1145. if (fComma) {
  1146. WriteString(tokenbuf, TRUE);
  1147. } else {
  1148. AppendString(tokenbuf, TRUE);
  1149. wLen--;
  1150. }
  1151. break;
  1152. case NUMLIT: /* Write the computed number out */
  1153. SetItemCount(IndexType, 0); /* mark data binary */
  1154. if (token.flongval) {
  1155. WriteLong(token.longval);
  1156. wLen += sizeof(LONG);
  1157. } else {
  1158. WriteWord(token.val);
  1159. wLen += sizeof(WORD);
  1160. }
  1161. break;
  1162. default:
  1163. ParseError1(2133); //"Unexpected value in value data"
  1164. return 0;
  1165. }
  1166. }
  1167. }
  1168. VOID
  1169. DlgIncludeParse(
  1170. PRESINFO pRes
  1171. )
  1172. {
  1173. INT i;
  1174. INT nbytes;
  1175. char * lpbuf;
  1176. if (token.type != LSTRLIT) {
  1177. ParseError1(2165);
  1178. return;
  1179. }
  1180. // the DLGINCLUDE statement must be written in ANSI (8-bit) for compatibility
  1181. // WriteString(tokenbuf);
  1182. nbytes = WideCharToMultiByte (CP_ACP, 0, tokenbuf, -1, NULL, 0, NULL, NULL);
  1183. lpbuf = (char *) MyAlloc (nbytes);
  1184. WideCharToMultiByte (CP_ACP, 0, tokenbuf, -1, lpbuf, nbytes, NULL, NULL);
  1185. for (i = 0; i < nbytes; i++)
  1186. WriteByte (lpbuf[i]);
  1187. MyFree(lpbuf);
  1188. return;
  1189. }