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.

442 lines
11 KiB

  1. /****************************************************************************/
  2. /* */
  3. /* RCTP.C - */
  4. /* */
  5. /* Windows 3.0 Resource Compiler - Resource Parser */
  6. /* */
  7. /* */
  8. /****************************************************************************/
  9. #include "rc.h"
  10. extern KEY keyList[];
  11. extern SKEY skeyList[];
  12. extern BOOL CheckStr(PWCHAR pStr);
  13. WORD wEndPOPUP[] = { 1, BEGIN };
  14. WORD wEndMENUITEM[] = { 3, TKPOPUP, TKMENUITEM, END };
  15. WORD wEndMENU[] = { 0 };
  16. BYTE bParmsPOPUP[] = { 5, PT_TEXT, PTO_DWORD, PTO_DWORD, PTO_DWORD, PTO_DWORD };
  17. BYTE bParmsMENUITEM[]= { 4, PT_TEXT, PTO_DWORD, PTO_DWORD, PTO_DWORD };
  18. BYTE bParmsMENU[] = { 1, PTO_DWORD };
  19. PARCEL parcels[]= {
  20. { wEndPOPUP, bParmsPOPUP }, // PAR_POPUP
  21. { wEndMENUITEM, bParmsMENUITEM }, // PAR_MENUITEM
  22. { wEndMENU, bParmsMENU } // PAR_MENU
  23. };
  24. typedef enum {
  25. ERR_MOREARGS = 2235,
  26. ERR_NEEDARG,
  27. ERR_NEEDNUM,
  28. ERR_NEEDSTR,
  29. ERR_NEEDBEGIN,
  30. ERR_NEEDEND,
  31. ERR_NEEDPAREN,
  32. ERR_BADEXP,
  33. ERR_BADSTREXP,
  34. ERR_NOSEP,
  35. ERR_BADSUBMENU,
  36. ERR_NOEMPTYMENU
  37. } ERRCODE;
  38. BOOL
  39. EndParcel(
  40. WORD *pwEnd
  41. )
  42. {
  43. WORD i;
  44. if (!*pwEnd)
  45. return(TRUE);
  46. for (i = *pwEnd; i > 0; i--)
  47. if (token.type == pwEnd[i])
  48. return(TRUE);
  49. return(FALSE);
  50. }
  51. #define PARM_SET 0x0001
  52. #define PARM_LAST 0x0002
  53. BOOL MyGetExpression(DWORD *pdwExp, BOOL fRecursed);
  54. BOOL
  55. GetOp(
  56. DWORD *pdwExp,
  57. WORD opcode
  58. )
  59. {
  60. DWORD dwOp2 = 0;
  61. BOOL fNest = FALSE;
  62. switch (token.type) {
  63. case LPAREN:
  64. GetToken(TOKEN_NOEXPRESSION);
  65. if (!MyGetExpression(&dwOp2, TRUE))
  66. return(FALSE);
  67. fNest = TRUE;
  68. break;
  69. case TKMINUS: // -flag (unary minus)
  70. GetToken(TOKEN_NOEXPRESSION);
  71. dwOp2 = -token.longval;
  72. break;
  73. case TKPLUS:
  74. GetToken(TOKEN_NOEXPRESSION);
  75. case NUMLIT:
  76. dwOp2 = token.longval;
  77. break;
  78. case TKNOT: // (x | NOT flag) == (x & ~flag)
  79. opcode = AND;
  80. case TILDE: // ~flag
  81. GetToken(TOKEN_NOEXPRESSION);
  82. dwOp2 = ~token.longval;
  83. break;
  84. default:
  85. return(FALSE);
  86. }
  87. if (!fNest) {
  88. if (token.type != NUMLIT)
  89. ParseError2(ERR_NEEDNUM, tokenbuf);
  90. GetToken(TOKEN_NOEXPRESSION);
  91. }
  92. switch (opcode) {
  93. case TKPLUS:
  94. *pdwExp += dwOp2;
  95. break;
  96. case TKMINUS:
  97. *pdwExp -= dwOp2;
  98. break;
  99. case OR:
  100. *pdwExp |= dwOp2;
  101. break;
  102. case AND:
  103. *pdwExp &= dwOp2;
  104. break;
  105. }
  106. return(TRUE);
  107. }
  108. BOOL
  109. GetFullExpression(
  110. void *pval,
  111. WORD wFlags
  112. )
  113. {
  114. BOOL fRes;
  115. DWORD dwExp = 0;
  116. if (!(wFlags & GFE_ZEROINIT))
  117. dwExp = (wFlags & GFE_SHORT) ? (DWORD) *((WORD *) pval) : *((DWORD UNALIGNED *) pval);
  118. fRes = MyGetExpression(&dwExp, FALSE);
  119. if (wFlags & GFE_SHORT)
  120. *((WORD *) pval) = (WORD) dwExp;
  121. else
  122. *((DWORD UNALIGNED *) pval) = dwExp;
  123. return(fRes);
  124. }
  125. BOOL
  126. MyGetExpression(
  127. DWORD *pdwExp,
  128. BOOL fRecursed
  129. )
  130. {
  131. WORD opcode;
  132. if (!GetOp(pdwExp, OR))
  133. return(FALSE);
  134. while (TRUE) { // break out as appropriate
  135. if (token.type == NUMLIT) {
  136. if (token.longval < 0) {
  137. *pdwExp += token.longval;
  138. GetToken(TOKEN_NOEXPRESSION);
  139. continue;
  140. }
  141. //
  142. // This is a hack to fix the problem of a space after a minus sign.
  143. // - for example 10 - 5
  144. // - if this is a problem, please speak to Jeff Bogden
  145. //
  146. if (token.longval == 0 && tokenbuf[0] == L'-' && tokenbuf[1] == L'\0')
  147. token.type = TKMINUS;
  148. }
  149. switch (token.type) {
  150. case TKPLUS:
  151. case TKMINUS:
  152. case OR:
  153. case AND:
  154. case TKNOT:
  155. opcode = token.type;
  156. GetToken(TOKEN_NOEXPRESSION);
  157. if (!GetOp(pdwExp, opcode))
  158. ParseError2(ERR_NEEDNUM, tokenbuf);
  159. break;
  160. case RPAREN:
  161. if (fRecursed) {
  162. GetToken(TOKEN_NOEXPRESSION);
  163. return(TRUE);
  164. } else {
  165. goto parenMismatch;
  166. }
  167. default:
  168. if (fRecursed)
  169. parenMismatch:
  170. ParseError2(ERR_NEEDPAREN, tokenbuf);
  171. return(TRUE);
  172. }
  173. }
  174. }
  175. WORD
  176. MyGetNum(
  177. WORD *pwEnd,
  178. BOOL fDouble,
  179. DWORD *pdwExp
  180. )
  181. {
  182. WORD wRes;
  183. DWORD dwExp = 0;
  184. wRes = MyGetExpression(&dwExp, FALSE) ? PARM_SET : 0;
  185. if (EndParcel(pwEnd))
  186. wRes |= PARM_LAST;
  187. else if (!(token.type == COMMA))
  188. ParseError2(ERR_BADEXP, tokenbuf);
  189. if (fDouble)
  190. *pdwExp = dwExp;
  191. else
  192. *((WORD *) pdwExp) = (WORD) dwExp;
  193. return(wRes);
  194. }
  195. WORD
  196. GetText(
  197. PWORD pwEnd,
  198. PWCHAR szDst
  199. )
  200. {
  201. BOOL fEnd;
  202. BOOL fPlus = FALSE;
  203. WORD wRes = 0;
  204. while (!(fEnd = EndParcel(pwEnd)) && (token.type != COMMA)) {
  205. if (CheckStr(szDst)) {
  206. szDst += wcslen(szDst);
  207. if (fPlus)
  208. fPlus = FALSE;
  209. else if (wRes)
  210. goto ErrBadStr;
  211. wRes = PARM_SET;
  212. } else if ((token.type == TKPLUS) && !fPlus && wRes) {
  213. fPlus = TRUE;
  214. } else {
  215. ErrBadStr:
  216. ParseError2(ERR_BADSTREXP, tokenbuf);
  217. }
  218. GetToken(TOKEN_NOEXPRESSION);
  219. }
  220. if (fPlus)
  221. ParseError2(ERR_NEEDSTR, tokenbuf);
  222. if (fEnd)
  223. wRes |= PARM_LAST;
  224. return(wRes);
  225. }
  226. void __cdecl
  227. GetParcel(
  228. PARCELTYPE parType,
  229. ...
  230. )
  231. {
  232. PARCEL par = parcels[parType];
  233. WORD wParm;
  234. WORD wRes;
  235. va_list ap;
  236. void *pParm;
  237. BOOL fOptional;
  238. BOOL fWriteSymbol = FALSE;
  239. va_start(ap, parType);
  240. for (wParm = 1; wParm <= *par.pwParms; wParm++) {
  241. pParm = va_arg(ap, void *);
  242. fOptional = par.pwParms[wParm] & PT_OPTIONAL;
  243. switch (par.pwParms[wParm] & ~PT_OPTIONAL) {
  244. case PT_TEXT:
  245. wRes = GetText(par.pwEnd, (PWCHAR) pParm);
  246. fWriteSymbol = TRUE;
  247. break;
  248. case PT_WORD:
  249. wRes = MyGetNum(par.pwEnd, FALSE, (DWORD *) pParm);
  250. break;
  251. case PT_DWORD:
  252. wRes = MyGetNum(par.pwEnd, TRUE, (DWORD *) pParm);
  253. break;
  254. }
  255. if (!(wRes & PARM_SET) && !fOptional)
  256. goto ErrMissingParm;
  257. if (wRes & PARM_LAST) {
  258. while (wParm < *par.pwParms) {
  259. if (!(par.pwParms[++wParm] & PT_OPTIONAL))
  260. ErrMissingParm:
  261. ParseError2(ERR_NEEDARG, tokenbuf);
  262. }
  263. goto Exit;
  264. }
  265. GetToken(TOKEN_NOEXPRESSION);
  266. WriteSymbolUse(&token.sym);
  267. }
  268. if (!EndParcel(par.pwEnd))
  269. ParseError2(ERR_MOREARGS, tokenbuf);
  270. Exit:
  271. va_end(ap);
  272. }
  273. /*---------------------------------------------------------------------------*/
  274. /* */
  275. /* DoMenuItem() - */
  276. /* */
  277. /*---------------------------------------------------------------------------*/
  278. WORD
  279. DoMenuItem(
  280. int fPopup
  281. )
  282. {
  283. MENU mn;
  284. mn.wResInfo = fPopup ? MFR_POPUP : 0;
  285. mn.dwType = 0;
  286. mn.dwState = 0;
  287. mn.dwID = 0;
  288. mn.dwHelpID = 0;
  289. mn.szText[0] = 0;
  290. GetToken(TOKEN_NOEXPRESSION); //TRUE);
  291. if ((token.type == NUMLIT) && (token.val == MFT_SEPARATOR)) {
  292. if (fPopup)
  293. ParseError2(ERR_NOSEP, tokenbuf);
  294. mn.dwType = MFT_SEPARATOR;
  295. mn.dwState = 0;
  296. mn.dwID = 0;
  297. GetToken(TOKEN_NOEXPRESSION); //TRUE);
  298. if (!EndParcel(parcels[PAR_MENUITEM].pwEnd))
  299. ParseError2(ERR_MOREARGS, tokenbuf);
  300. } else if (fPopup) {
  301. GetParcel(PAR_POPUP, mn.szText, &mn.dwID, &mn.dwType, &mn.dwState, &mn.dwHelpID);
  302. } else {
  303. GetParcel(PAR_MENUITEM, mn.szText, &mn.dwID, &mn.dwType, &mn.dwState);
  304. }
  305. // set it up in the buffer (?)
  306. return(SetUpMenu(&mn));
  307. }
  308. /*---------------------------------------------------------------------------*/
  309. /* */
  310. /* ParseMenu() - */
  311. /* */
  312. /*---------------------------------------------------------------------------*/
  313. int
  314. ParseMenu(
  315. int fRecursing,
  316. PRESINFO pRes /* TRUE iff popup */
  317. )
  318. {
  319. int bItemRead = FALSE;
  320. WORD wEndFlagLoc = 0;
  321. DWORD dwHelpID = 0;
  322. if (!fRecursing) {
  323. // Write Help ID to header
  324. GetParcel(PAR_MENU, &dwHelpID);
  325. WriteLong(dwHelpID);
  326. PreBeginParse(pRes, 2121);
  327. } else {
  328. /* make sure its really a menu */
  329. if (token.type != BEGIN)
  330. ParseError1(2121); //"BEGIN expected in menu"
  331. GetToken(TRUE); // vs. TOKEN_NOEXPRESSION ??
  332. }
  333. /* get the individual menu items */
  334. while (token.type != END) {
  335. switch (token.type) {
  336. case TKMENUITEM:
  337. bItemRead = TRUE;
  338. wEndFlagLoc = DoMenuItem(FALSE);
  339. break;
  340. case TKPOPUP:
  341. bItemRead = TRUE;
  342. wEndFlagLoc = DoMenuItem(TRUE);
  343. ParseMenu(TRUE, pRes);
  344. break;
  345. default:
  346. ParseError2(ERR_BADSUBMENU, tokenbuf);
  347. break;
  348. }
  349. }
  350. /* did we die on an END? */
  351. if (token.type != END)
  352. ParseError2(ERR_NEEDEND, tokenbuf);
  353. /* make sure we have a menu item */
  354. if (!bItemRead)
  355. ParseError2(ERR_NOEMPTYMENU, tokenbuf);
  356. /* Get next token if this was NOT the last END*/
  357. if (fRecursing)
  358. GetToken(TOKEN_NOEXPRESSION);
  359. /* mark the last item in the menu */
  360. FixMenuPatch(wEndFlagLoc);
  361. return (TRUE);
  362. }