windows-nt/Source/XPSP1/NT/sdktools/rcdll/rcmenu.c
2020-09-26 16:20:57 +08:00

443 lines
11 KiB
C

/****************************************************************************/
/* */
/* RCTP.C - */
/* */
/* Windows 3.0 Resource Compiler - Resource Parser */
/* */
/* */
/****************************************************************************/
#include "rc.h"
extern KEY keyList[];
extern SKEY skeyList[];
extern BOOL CheckStr(PWCHAR pStr);
WORD wEndPOPUP[] = { 1, BEGIN };
WORD wEndMENUITEM[] = { 3, TKPOPUP, TKMENUITEM, END };
WORD wEndMENU[] = { 0 };
BYTE bParmsPOPUP[] = { 5, PT_TEXT, PTO_DWORD, PTO_DWORD, PTO_DWORD, PTO_DWORD };
BYTE bParmsMENUITEM[]= { 4, PT_TEXT, PTO_DWORD, PTO_DWORD, PTO_DWORD };
BYTE bParmsMENU[] = { 1, PTO_DWORD };
PARCEL parcels[]= {
{ wEndPOPUP, bParmsPOPUP }, // PAR_POPUP
{ wEndMENUITEM, bParmsMENUITEM }, // PAR_MENUITEM
{ wEndMENU, bParmsMENU } // PAR_MENU
};
typedef enum {
ERR_MOREARGS = 2235,
ERR_NEEDARG,
ERR_NEEDNUM,
ERR_NEEDSTR,
ERR_NEEDBEGIN,
ERR_NEEDEND,
ERR_NEEDPAREN,
ERR_BADEXP,
ERR_BADSTREXP,
ERR_NOSEP,
ERR_BADSUBMENU,
ERR_NOEMPTYMENU
} ERRCODE;
BOOL
EndParcel(
WORD *pwEnd
)
{
WORD i;
if (!*pwEnd)
return(TRUE);
for (i = *pwEnd; i > 0; i--)
if (token.type == pwEnd[i])
return(TRUE);
return(FALSE);
}
#define PARM_SET 0x0001
#define PARM_LAST 0x0002
BOOL MyGetExpression(DWORD *pdwExp, BOOL fRecursed);
BOOL
GetOp(
DWORD *pdwExp,
WORD opcode
)
{
DWORD dwOp2 = 0;
BOOL fNest = FALSE;
switch (token.type) {
case LPAREN:
GetToken(TOKEN_NOEXPRESSION);
if (!MyGetExpression(&dwOp2, TRUE))
return(FALSE);
fNest = TRUE;
break;
case TKMINUS: // -flag (unary minus)
GetToken(TOKEN_NOEXPRESSION);
dwOp2 = -token.longval;
break;
case TKPLUS:
GetToken(TOKEN_NOEXPRESSION);
case NUMLIT:
dwOp2 = token.longval;
break;
case TKNOT: // (x | NOT flag) == (x & ~flag)
opcode = AND;
case TILDE: // ~flag
GetToken(TOKEN_NOEXPRESSION);
dwOp2 = ~token.longval;
break;
default:
return(FALSE);
}
if (!fNest) {
if (token.type != NUMLIT)
ParseError2(ERR_NEEDNUM, tokenbuf);
GetToken(TOKEN_NOEXPRESSION);
}
switch (opcode) {
case TKPLUS:
*pdwExp += dwOp2;
break;
case TKMINUS:
*pdwExp -= dwOp2;
break;
case OR:
*pdwExp |= dwOp2;
break;
case AND:
*pdwExp &= dwOp2;
break;
}
return(TRUE);
}
BOOL
GetFullExpression(
void *pval,
WORD wFlags
)
{
BOOL fRes;
DWORD dwExp = 0;
if (!(wFlags & GFE_ZEROINIT))
dwExp = (wFlags & GFE_SHORT) ? (DWORD) *((WORD *) pval) : *((DWORD UNALIGNED *) pval);
fRes = MyGetExpression(&dwExp, FALSE);
if (wFlags & GFE_SHORT)
*((WORD *) pval) = (WORD) dwExp;
else
*((DWORD UNALIGNED *) pval) = dwExp;
return(fRes);
}
BOOL
MyGetExpression(
DWORD *pdwExp,
BOOL fRecursed
)
{
WORD opcode;
if (!GetOp(pdwExp, OR))
return(FALSE);
while (TRUE) { // break out as appropriate
if (token.type == NUMLIT) {
if (token.longval < 0) {
*pdwExp += token.longval;
GetToken(TOKEN_NOEXPRESSION);
continue;
}
//
// This is a hack to fix the problem of a space after a minus sign.
// - for example 10 - 5
// - if this is a problem, please speak to Jeff Bogden
//
if (token.longval == 0 && tokenbuf[0] == L'-' && tokenbuf[1] == L'\0')
token.type = TKMINUS;
}
switch (token.type) {
case TKPLUS:
case TKMINUS:
case OR:
case AND:
case TKNOT:
opcode = token.type;
GetToken(TOKEN_NOEXPRESSION);
if (!GetOp(pdwExp, opcode))
ParseError2(ERR_NEEDNUM, tokenbuf);
break;
case RPAREN:
if (fRecursed) {
GetToken(TOKEN_NOEXPRESSION);
return(TRUE);
} else {
goto parenMismatch;
}
default:
if (fRecursed)
parenMismatch:
ParseError2(ERR_NEEDPAREN, tokenbuf);
return(TRUE);
}
}
}
WORD
MyGetNum(
WORD *pwEnd,
BOOL fDouble,
DWORD *pdwExp
)
{
WORD wRes;
DWORD dwExp = 0;
wRes = MyGetExpression(&dwExp, FALSE) ? PARM_SET : 0;
if (EndParcel(pwEnd))
wRes |= PARM_LAST;
else if (!(token.type == COMMA))
ParseError2(ERR_BADEXP, tokenbuf);
if (fDouble)
*pdwExp = dwExp;
else
*((WORD *) pdwExp) = (WORD) dwExp;
return(wRes);
}
WORD
GetText(
PWORD pwEnd,
PWCHAR szDst
)
{
BOOL fEnd;
BOOL fPlus = FALSE;
WORD wRes = 0;
while (!(fEnd = EndParcel(pwEnd)) && (token.type != COMMA)) {
if (CheckStr(szDst)) {
szDst += wcslen(szDst);
if (fPlus)
fPlus = FALSE;
else if (wRes)
goto ErrBadStr;
wRes = PARM_SET;
} else if ((token.type == TKPLUS) && !fPlus && wRes) {
fPlus = TRUE;
} else {
ErrBadStr:
ParseError2(ERR_BADSTREXP, tokenbuf);
}
GetToken(TOKEN_NOEXPRESSION);
}
if (fPlus)
ParseError2(ERR_NEEDSTR, tokenbuf);
if (fEnd)
wRes |= PARM_LAST;
return(wRes);
}
void __cdecl
GetParcel(
PARCELTYPE parType,
...
)
{
PARCEL par = parcels[parType];
WORD wParm;
WORD wRes;
va_list ap;
void *pParm;
BOOL fOptional;
BOOL fWriteSymbol = FALSE;
va_start(ap, parType);
for (wParm = 1; wParm <= *par.pwParms; wParm++) {
pParm = va_arg(ap, void *);
fOptional = par.pwParms[wParm] & PT_OPTIONAL;
switch (par.pwParms[wParm] & ~PT_OPTIONAL) {
case PT_TEXT:
wRes = GetText(par.pwEnd, (PWCHAR) pParm);
fWriteSymbol = TRUE;
break;
case PT_WORD:
wRes = MyGetNum(par.pwEnd, FALSE, (DWORD *) pParm);
break;
case PT_DWORD:
wRes = MyGetNum(par.pwEnd, TRUE, (DWORD *) pParm);
break;
}
if (!(wRes & PARM_SET) && !fOptional)
goto ErrMissingParm;
if (wRes & PARM_LAST) {
while (wParm < *par.pwParms) {
if (!(par.pwParms[++wParm] & PT_OPTIONAL))
ErrMissingParm:
ParseError2(ERR_NEEDARG, tokenbuf);
}
goto Exit;
}
GetToken(TOKEN_NOEXPRESSION);
WriteSymbolUse(&token.sym);
}
if (!EndParcel(par.pwEnd))
ParseError2(ERR_MOREARGS, tokenbuf);
Exit:
va_end(ap);
}
/*---------------------------------------------------------------------------*/
/* */
/* DoMenuItem() - */
/* */
/*---------------------------------------------------------------------------*/
WORD
DoMenuItem(
int fPopup
)
{
MENU mn;
mn.wResInfo = fPopup ? MFR_POPUP : 0;
mn.dwType = 0;
mn.dwState = 0;
mn.dwID = 0;
mn.dwHelpID = 0;
mn.szText[0] = 0;
GetToken(TOKEN_NOEXPRESSION); //TRUE);
if ((token.type == NUMLIT) && (token.val == MFT_SEPARATOR)) {
if (fPopup)
ParseError2(ERR_NOSEP, tokenbuf);
mn.dwType = MFT_SEPARATOR;
mn.dwState = 0;
mn.dwID = 0;
GetToken(TOKEN_NOEXPRESSION); //TRUE);
if (!EndParcel(parcels[PAR_MENUITEM].pwEnd))
ParseError2(ERR_MOREARGS, tokenbuf);
} else if (fPopup) {
GetParcel(PAR_POPUP, mn.szText, &mn.dwID, &mn.dwType, &mn.dwState, &mn.dwHelpID);
} else {
GetParcel(PAR_MENUITEM, mn.szText, &mn.dwID, &mn.dwType, &mn.dwState);
}
// set it up in the buffer (?)
return(SetUpMenu(&mn));
}
/*---------------------------------------------------------------------------*/
/* */
/* ParseMenu() - */
/* */
/*---------------------------------------------------------------------------*/
int
ParseMenu(
int fRecursing,
PRESINFO pRes /* TRUE iff popup */
)
{
int bItemRead = FALSE;
WORD wEndFlagLoc = 0;
DWORD dwHelpID = 0;
if (!fRecursing) {
// Write Help ID to header
GetParcel(PAR_MENU, &dwHelpID);
WriteLong(dwHelpID);
PreBeginParse(pRes, 2121);
} else {
/* make sure its really a menu */
if (token.type != BEGIN)
ParseError1(2121); //"BEGIN expected in menu"
GetToken(TRUE); // vs. TOKEN_NOEXPRESSION ??
}
/* get the individual menu items */
while (token.type != END) {
switch (token.type) {
case TKMENUITEM:
bItemRead = TRUE;
wEndFlagLoc = DoMenuItem(FALSE);
break;
case TKPOPUP:
bItemRead = TRUE;
wEndFlagLoc = DoMenuItem(TRUE);
ParseMenu(TRUE, pRes);
break;
default:
ParseError2(ERR_BADSUBMENU, tokenbuf);
break;
}
}
/* did we die on an END? */
if (token.type != END)
ParseError2(ERR_NEEDEND, tokenbuf);
/* make sure we have a menu item */
if (!bItemRead)
ParseError2(ERR_NOEMPTYMENU, tokenbuf);
/* Get next token if this was NOT the last END*/
if (fRecursing)
GetToken(TOKEN_NOEXPRESSION);
/* mark the last item in the menu */
FixMenuPatch(wEndFlagLoc);
return (TRUE);
}