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.

1451 lines
42 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. static BOOL fComma;
  12. /* Dialog template format :
  13. dialogName DIALOGEX x, y, cx, cy [, helpID]
  14. [style ...]
  15. [exStyle ...]
  16. [FONT height, name [, [weight] [, [italic [, [charset]]]]]]
  17. [caption ...]
  18. [menu ...]
  19. [memFlags [pure] [discard n] [preload]]
  20. BEGIN
  21. [CONTROL "text", id, BUTTON | STATIC | EDIT | LISTBOX | SCROLLBAR | COMBOBOX | "class", style, x, y, cx, cy]
  22. [FONT height, name [, [weight] [, [italic]]]]
  23. [BEGIN
  24. data-element-1 [,
  25. data-element-2 [,
  26. ... ]]
  27. END]
  28. [LTEXT "text", id, x, y, cx, cy]
  29. [RTEXT "text", id, x, y, cx, cy]
  30. [CTEXT "text", id, x, y, cx, cy]
  31. [AUTO3STATE "text", id, x, y, cx, cy]
  32. [AUTOCHECKBOX "text", id, x, y, cx, cy]
  33. [AUTORADIOBUTTON "text", id, x, y, cx, cy]
  34. [CHECKBOX "text", id, x, y, cx, cy]
  35. [PUSHBOX "text", id, x, y, cx, cy]
  36. [PUSHBUTTON "text", id, x, y, cx, cy]
  37. [RADIOBUTTON "text", id, x, y, cx, cy]
  38. [STATE3 "text", id, x, y, cx, cy]
  39. [USERBUTTON "text", id, x, y, cx, cy]
  40. [EDITTEXT id, x, y, cx, cy]
  41. [BEDIT id, x, y, cx, cy]
  42. [HEDIT id, x, y, cx, cy]
  43. [IEDIT id, x, y, cx, cy]
  44. ...
  45. END
  46. MenuName MENUEX
  47. BEGIN
  48. [MENUITEM "text" [, [id] [, [type] [, [state]]]]]
  49. [POPUP "text" [, [id] [, [type] [, [state] [, [help id]]]]]
  50. BEGIN
  51. [MENUITEM "text" [, [id] [, [type] [, [state]]]]]
  52. ...
  53. END]
  54. ...
  55. END
  56. Menu template format
  57. MenuName MENU
  58. BEGIN
  59. [MENUITEM "text", id [option, ...]]
  60. [POPUP "text" [, option, ...]
  61. BEGIN
  62. [MENUITEM "text", id [option, ...]]
  63. ...
  64. END ]
  65. ...
  66. END
  67. */
  68. /* Dialog template format :
  69. dialogname DIALOG x, y, cx, cy
  70. [language ...]
  71. [style ...]
  72. [caption ... ]
  73. [menu ... ]
  74. [memflags [pure] [discard n] [preload]]
  75. begin
  76. [CONTROL "text", id, BUTTON | STATIC | EDIT | LISTBOX | SCROLLBAR | COMBOBOX | "class", style, x, y, cx, cy]
  77. [LTEXT "text", id, x, y, cx, cy]
  78. [RTEXT "text", id, x, y, cx, cy]
  79. [CTEXT "text", id, x, y, cx, cy]
  80. [CHECKBOX "text", id, x, y, cx, cy]
  81. [PUSHBUTTON "text", id, x, y, cx, cy]
  82. [RADIOBUTTON "text", id, x, y, cx, cy]
  83. [EDITTEXT id, x, y, cx, cy]
  84. ...
  85. end
  86. Menu template format
  87. MenuName MENU
  88. BEGIN
  89. [MENUITEM "text", id [option, ...]]
  90. [POPUP "text" [, option, ...]
  91. BEGIN
  92. [MENUITEM "text", id [option, ...]]
  93. ...
  94. END ]
  95. ...
  96. END
  97. */
  98. #define CTLSTYLE(s) (WS_CHILD | WS_VISIBLE | (s))
  99. /* list of control id's to check for duplicates */
  100. PDWORD pid;
  101. int cidMac;
  102. int cidMax;
  103. BOOL
  104. CheckStr(
  105. PWCHAR pStr
  106. )
  107. {
  108. if (token.type == STRLIT || token.type == LSTRLIT) {
  109. if (token.val > MAXTOKSTR-1) {
  110. SET_MSG(4208, curFile, token.row);
  111. SendError(Msg_Text);
  112. tokenbuf[MAXTOKSTR-1] = TEXT('\0');
  113. token.val = MAXTOKSTR-2;
  114. }
  115. memcpy(pStr, tokenbuf, (token.val+1)*sizeof(WCHAR));
  116. return(TRUE);
  117. }
  118. return(FALSE);
  119. }
  120. // ----------------------------------------------------------------------------
  121. //
  122. // GetDlgValue
  123. //
  124. // ----------------------------------------------------------------------------
  125. SHORT
  126. GetDlgValue(
  127. void
  128. )
  129. {
  130. SHORT sVal;
  131. if (!GetFullExpression(&sVal, GFE_ZEROINIT | GFE_SHORT))
  132. ParseError1(2109); //"Expected Numerical Dialog constant"
  133. return(sVal);
  134. }
  135. void
  136. GetCoords(
  137. PSHORT x,
  138. PSHORT y,
  139. PSHORT cx,
  140. PSHORT cy
  141. )
  142. {
  143. *x = GetDlgValue();
  144. if (token.type == COMMA)
  145. GetToken(TOKEN_NOEXPRESSION);
  146. *y = GetDlgValue();
  147. if (token.type == COMMA)
  148. GetToken(TOKEN_NOEXPRESSION);
  149. *cx= GetDlgValue();
  150. if (token.type == COMMA)
  151. GetToken(TOKEN_NOEXPRESSION);
  152. *cy= GetDlgValue();
  153. }
  154. typedef struct tagCTRLTYPE {
  155. WORD type;
  156. DWORD dwStyle;
  157. BYTE bCode;
  158. BYTE fHasText;
  159. } CTRLTYPE;
  160. CTRLTYPE ctrlTypes[] = {
  161. { TKGROUPBOX, BS_GROUPBOX, BUTTONCODE, TRUE },
  162. { TKPUSHBUTTON, BS_PUSHBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
  163. { TKDEFPUSHBUTTON, BS_DEFPUSHBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
  164. { TKCHECKBOX, BS_CHECKBOX | WS_TABSTOP, BUTTONCODE, TRUE },
  165. { TKRADIOBUTTON, BS_RADIOBUTTON, BUTTONCODE, TRUE },
  166. { TKAUTO3, BS_AUTO3STATE | WS_TABSTOP, BUTTONCODE, TRUE },
  167. { TKAUTOCHECK, BS_AUTOCHECKBOX | WS_TABSTOP, BUTTONCODE, TRUE },
  168. { TKAUTORADIO, BS_AUTORADIOBUTTON, BUTTONCODE, TRUE },
  169. { TKPUSHBOX, BS_PUSHBOX | WS_TABSTOP, BUTTONCODE, TRUE },
  170. { TK3STATE, BS_3STATE | WS_TABSTOP, BUTTONCODE, TRUE },
  171. { TKUSERBUTTON, BS_USERBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
  172. { TKLTEXT, ES_LEFT | WS_GROUP, STATICCODE, TRUE },
  173. { TKRTEXT, ES_RIGHT | WS_GROUP, STATICCODE, TRUE },
  174. { TKCTEXT, ES_CENTER | WS_GROUP, STATICCODE, TRUE },
  175. { TKICON, SS_ICON, STATICCODE, TRUE },
  176. { TKBEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
  177. { TKHEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
  178. { TKIEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
  179. { TKEDITTEXT, ES_LEFT | WS_BORDER | WS_TABSTOP, EDITCODE, FALSE },
  180. { TKLISTBOX, WS_BORDER | LBS_NOTIFY, LISTBOXCODE, FALSE },
  181. { TKCOMBOBOX, 0, COMBOBOXCODE, FALSE },
  182. { TKSCROLLBAR, 0, SCROLLBARCODE, FALSE }
  183. };
  184. #define C_CTRLTYPES (sizeof(ctrlTypes) / sizeof(CTRLTYPE))
  185. // ----------------------------------------------------------------------------
  186. //
  187. // GetDlgItems(fDlgEx) -
  188. //
  189. // ----------------------------------------------------------------------------
  190. int
  191. GetDlgItems(
  192. BOOL fDlgEx
  193. )
  194. {
  195. CTRL ctrl;
  196. int i;
  197. cidMac = 0;
  198. cidMax = 100;
  199. pid = (PDWORD) MyAlloc(sizeof(DWORD)*cidMax);
  200. if (!pid)
  201. return FALSE;
  202. GetToken(TRUE);
  203. /* read all the controls in the dialog */
  204. ctrl.id = 0L; // initialize the control's id to 0
  205. while (token.type != END) {
  206. ctrl.dwHelpID = 0L;
  207. ctrl.dwExStyle = 0L;
  208. ctrl.dwStyle = WS_CHILD | WS_VISIBLE;
  209. ctrl.text[0] = 0;
  210. ctrl.fOrdinalText = FALSE;
  211. if (token.type == TKCONTROL) {
  212. ParseCtl(&ctrl, fDlgEx);
  213. } else {
  214. for (i = 0; i < C_CTRLTYPES; i++)
  215. if (token.type == ctrlTypes[i].type)
  216. break;
  217. if (i == C_CTRLTYPES) {
  218. ParseError1(2111); //"Invalid Control type : ", tokenbuf
  219. return(FALSE);
  220. }
  221. ctrl.dwStyle |= ctrlTypes[i].dwStyle;
  222. if (fMacRsrcs &&
  223. (token.type == TKPUSHBUTTON ||
  224. token.type == TKDEFPUSHBUTTON ||
  225. token.type == TKCHECKBOX ||
  226. token.type == TKAUTO3 ||
  227. token.type == TKAUTOCHECK ||
  228. token.type == TKPUSHBOX ||
  229. token.type == TK3STATE ||
  230. token.type == TKUSERBUTTON))
  231. {
  232. ctrl.dwStyle &= ~WS_TABSTOP;
  233. }
  234. if (ctrlTypes[i].bCode) {
  235. ctrl.Class[0] = 0xFFFF;
  236. ctrl.Class[1] = ctrlTypes[i].bCode;
  237. } else {
  238. CheckStr(ctrl.Class);
  239. }
  240. if (ctrlTypes[i].fHasText)
  241. GetCtlText(&ctrl);
  242. // find the ID and the coordinates
  243. GetCtlID(&ctrl, fDlgEx);
  244. GetCoords(&ctrl.x, &ctrl.y, &ctrl.cx, &ctrl.cy);
  245. // get optional style, exstyle, and helpid
  246. if (token.type == COMMA) {
  247. GetToken(TOKEN_NOEXPRESSION);
  248. GetFullExpression(&ctrl.dwStyle, 0);
  249. }
  250. }
  251. if (token.type == COMMA) {
  252. GetToken(TOKEN_NOEXPRESSION);
  253. GetFullExpression(&ctrl.dwExStyle, 0);
  254. if (fDlgEx && (token.type == COMMA)) {
  255. GetToken(TOKEN_NOEXPRESSION);
  256. GetFullExpression(&ctrl.dwHelpID, GFE_ZEROINIT);
  257. }
  258. }
  259. SetUpItem(&ctrl, fDlgEx); /* gen the code for it */
  260. if (fDlgEx && (token.type == BEGIN)) {
  261. /* align any CreateParams are there */
  262. //WriteAlign(); not yet!!!
  263. // we're ok passing NULL in for pRes here because PreBeginParse
  264. // won't have to use pRes
  265. // Note that passing fDlgEx is actually redundant since it
  266. // will always be TRUE here, but we'll do it in case someone
  267. // else ever calls SetItemExtraCount
  268. SetItemExtraCount(GetRCData(NULL), fDlgEx);
  269. GetToken(TOKEN_NOEXPRESSION);
  270. }
  271. }
  272. MyFree(pid);
  273. return TRUE;
  274. }
  275. /*---------------------------------------------------------------------------*/
  276. /* */
  277. /* GetDlg() - */
  278. /* */
  279. /*---------------------------------------------------------------------------*/
  280. int
  281. GetDlg(
  282. PRESINFO pRes,
  283. PDLGHDR pDlg,
  284. BOOL fDlgEx
  285. )
  286. {
  287. /* initialize and defaults */
  288. pDlg->dwExStyle = pRes->exstyleT;
  289. pDlg->dwStyle = WS_POPUPWINDOW | WS_SYSMENU;
  290. pDlg->MenuName[0] = 0;
  291. pDlg->Title[0] = 0;
  292. pDlg->Class[0] = 0;
  293. pDlg->fOrdinalMenu = FALSE;
  294. pDlg->fClassOrdinal = FALSE;
  295. pDlg->pointsize = 0;
  296. // get x, y, cx, cy
  297. GetCoords(&pDlg->x, &pDlg->y, &pDlg->cx, &pDlg->cy);
  298. /* get optional parameters */
  299. if (!DLexOptionalArgs(pRes, pDlg, fDlgEx))
  300. return FALSE;
  301. if (pDlg->pointsize)
  302. pDlg->dwStyle |= DS_SETFONT;
  303. else
  304. pDlg->dwStyle &= ~DS_SETFONT;
  305. /* output header to the resource buffer */
  306. SetUpDlg(pDlg, fDlgEx);
  307. /* make sure we have a BEGIN */
  308. if (token.type != BEGIN)
  309. ParseError1(2112); //"BEGIN expected in Dialog"
  310. /* get the dialog items */
  311. GetDlgItems(fDlgEx);
  312. if (fMacRsrcs)
  313. SwapItemCount();
  314. /* make sure this ended on an END */
  315. if (token.type != END)
  316. ParseError1(2113); //"END expected in Dialog"
  317. return (TRUE);
  318. }
  319. typedef struct tagCTRLNAME {
  320. BYTE bCode;
  321. WORD wType;
  322. PWCHAR pszName;
  323. } CTRLNAME;
  324. CTRLNAME ctrlNames[] = {
  325. { BUTTONCODE, TKBUTTON, L"button" },
  326. { EDITCODE, TKEDIT, L"edit" },
  327. { STATICCODE, TKSTATIC, L"static" },
  328. { LISTBOXCODE, TKLISTBOX, L"listbox" },
  329. { SCROLLBARCODE, TKSCROLLBAR, L"scrollbar" },
  330. { COMBOBOXCODE, TKCOMBOBOX, L"combobox" }
  331. };
  332. #define C_CTRLNAMES (sizeof(ctrlNames) / sizeof(CTRLNAME))
  333. /*---------------------------------------------------------------------------*/
  334. /* */
  335. /* ParseCtl() - */
  336. /* */
  337. /*---------------------------------------------------------------------------*/
  338. // for a control of the form CTL
  339. void
  340. ParseCtl(
  341. PCTRL LocCtl,
  342. BOOL fDlgEx
  343. )
  344. { /* by now we've read the CTL */
  345. int i;
  346. /* get the control text and identifier */
  347. GetCtlText(LocCtl);
  348. GetCtlID(LocCtl, fDlgEx);
  349. if (token.type == NUMLIT) {
  350. LocCtl->Class[0] = (char) token.val;
  351. LocCtl->Class[1] = 0;
  352. } else if (token.type == LSTRLIT) {
  353. // We will now convert class name strings to short form magic
  354. // numbers. These magic numbers are order dependent as defined in
  355. // USER. This provides some space savings in resource files.
  356. for (i = C_CTRLNAMES; i; ) {
  357. if (!_wcsicmp(tokenbuf, ctrlNames[--i].pszName))
  358. goto Found1;
  359. }
  360. CheckStr(LocCtl->Class);
  361. } else {
  362. for (i = C_CTRLNAMES; i; ) {
  363. if (token.type == ctrlNames[--i].wType)
  364. goto Found1;
  365. }
  366. ParseError1(2114); //"Expected control class name"
  367. Found1:
  368. LocCtl->Class[0] = 0xFFFF;
  369. LocCtl->Class[1] = ctrlNames[i].bCode;
  370. }
  371. /* get the style bits */
  372. GetTokenNoComma(TOKEN_NOEXPRESSION);
  373. GetFullExpression(&LocCtl->dwStyle, 0);
  374. /* get the coordinates of the control */
  375. ICGetTok();
  376. GetCoords(&LocCtl->x, &LocCtl->y, &LocCtl->cx, &LocCtl->cy);
  377. }
  378. /*---------------------------------------------------------------------------*/
  379. /* */
  380. /* GetCtlText() - */
  381. /* */
  382. /*---------------------------------------------------------------------------*/
  383. VOID
  384. GetCtlText(
  385. PCTRL pLocCtl
  386. )
  387. {
  388. GetTokenNoComma(TOKEN_NOEXPRESSION);
  389. if (CheckStr(pLocCtl->text)) {
  390. pLocCtl->fOrdinalText = FALSE;
  391. token.sym.name[0] = L'\0';
  392. token.sym.nID = 0;
  393. } else if (token.type == NUMLIT) {
  394. wcsitow(token.val, pLocCtl->text, 10);
  395. pLocCtl->fOrdinalText = TRUE;
  396. WriteSymbolUse(&token.sym);
  397. } else {
  398. ParseError1(2115); //"Text string or ordinal expected in Control"
  399. }
  400. }
  401. /*---------------------------------------------------------------------------*/
  402. /* */
  403. /* GetCtlID() - */
  404. /* */
  405. /*---------------------------------------------------------------------------*/
  406. VOID
  407. GetCtlID(
  408. PCTRL pLocCtl,
  409. BOOL fDlgEx
  410. )
  411. {
  412. WORD wGFE = GFE_ZEROINIT;
  413. int i;
  414. ICGetTok();
  415. WriteSymbolUse(&token.sym);
  416. if (!fDlgEx)
  417. wGFE |= GFE_SHORT;
  418. if (GetFullExpression(&pLocCtl->id, wGFE)) {
  419. if (!fDlgEx && pLocCtl->id != (DWORD)(WORD)-1 ||
  420. fDlgEx && pLocCtl->id != (DWORD)-1) {
  421. for (i=0 ; i<cidMac ; i++) {
  422. if (pLocCtl->id == *(pid+i) && !fSkipDuplicateCtlIdWarning) {
  423. i = (int)pLocCtl->id;
  424. SET_MSG(2182, 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, pDlg->Font, 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. }