443 lines
11 KiB
C
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);
|
|
}
|