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

1452 lines
41 KiB
C

/****************************************************************************/
/* */
/* RCTP.C - */
/* */
/* Windows 3.0 Resource Compiler - Resource Parser */
/* */
/* */
/****************************************************************************/
#include "rc.h"
static BOOL fComma;
/* Dialog template format :
dialogName DIALOGEX x, y, cx, cy [, helpID]
[style ...]
[exStyle ...]
[FONT height, name [, [weight] [, [italic [, [charset]]]]]]
[caption ...]
[menu ...]
[memFlags [pure] [discard n] [preload]]
BEGIN
[CONTROL "text", id, BUTTON | STATIC | EDIT | LISTBOX | SCROLLBAR | COMBOBOX | "class", style, x, y, cx, cy]
[FONT height, name [, [weight] [, [italic]]]]
[BEGIN
data-element-1 [,
data-element-2 [,
... ]]
END]
[LTEXT "text", id, x, y, cx, cy]
[RTEXT "text", id, x, y, cx, cy]
[CTEXT "text", id, x, y, cx, cy]
[AUTO3STATE "text", id, x, y, cx, cy]
[AUTOCHECKBOX "text", id, x, y, cx, cy]
[AUTORADIOBUTTON "text", id, x, y, cx, cy]
[CHECKBOX "text", id, x, y, cx, cy]
[PUSHBOX "text", id, x, y, cx, cy]
[PUSHBUTTON "text", id, x, y, cx, cy]
[RADIOBUTTON "text", id, x, y, cx, cy]
[STATE3 "text", id, x, y, cx, cy]
[USERBUTTON "text", id, x, y, cx, cy]
[EDITTEXT id, x, y, cx, cy]
[BEDIT id, x, y, cx, cy]
[HEDIT id, x, y, cx, cy]
[IEDIT id, x, y, cx, cy]
...
END
MenuName MENUEX
BEGIN
[MENUITEM "text" [, [id] [, [type] [, [state]]]]]
[POPUP "text" [, [id] [, [type] [, [state] [, [help id]]]]]
BEGIN
[MENUITEM "text" [, [id] [, [type] [, [state]]]]]
...
END]
...
END
Menu template format
MenuName MENU
BEGIN
[MENUITEM "text", id [option, ...]]
[POPUP "text" [, option, ...]
BEGIN
[MENUITEM "text", id [option, ...]]
...
END ]
...
END
*/
/* Dialog template format :
dialogname DIALOG x, y, cx, cy
[language ...]
[style ...]
[caption ... ]
[menu ... ]
[memflags [pure] [discard n] [preload]]
begin
[CONTROL "text", id, BUTTON | STATIC | EDIT | LISTBOX | SCROLLBAR | COMBOBOX | "class", style, x, y, cx, cy]
[LTEXT "text", id, x, y, cx, cy]
[RTEXT "text", id, x, y, cx, cy]
[CTEXT "text", id, x, y, cx, cy]
[CHECKBOX "text", id, x, y, cx, cy]
[PUSHBUTTON "text", id, x, y, cx, cy]
[RADIOBUTTON "text", id, x, y, cx, cy]
[EDITTEXT id, x, y, cx, cy]
...
end
Menu template format
MenuName MENU
BEGIN
[MENUITEM "text", id [option, ...]]
[POPUP "text" [, option, ...]
BEGIN
[MENUITEM "text", id [option, ...]]
...
END ]
...
END
*/
#define CTLSTYLE(s) (WS_CHILD | WS_VISIBLE | (s))
/* list of control id's to check for duplicates */
PDWORD pid;
int cidMac;
int cidMax;
BOOL
CheckStr(
PWCHAR pStr
)
{
if (token.type == STRLIT || token.type == LSTRLIT) {
if (token.val > MAXTOKSTR-1) {
SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(4208), curFile, token.row);
SendError(Msg_Text);
tokenbuf[MAXTOKSTR-1] = TEXT('\0');
token.val = MAXTOKSTR-2;
}
memcpy(pStr, tokenbuf, (token.val+1)*sizeof(WCHAR));
return(TRUE);
}
return(FALSE);
}
// ----------------------------------------------------------------------------
//
// GetDlgValue
//
// ----------------------------------------------------------------------------
SHORT
GetDlgValue(
void
)
{
SHORT sVal;
if (!GetFullExpression(&sVal, GFE_ZEROINIT | GFE_SHORT))
ParseError1(2109); //"Expected Numerical Dialog constant"
return(sVal);
}
void
GetCoords(
PSHORT x,
PSHORT y,
PSHORT cx,
PSHORT cy
)
{
*x = GetDlgValue();
if (token.type == COMMA)
GetToken(TOKEN_NOEXPRESSION);
*y = GetDlgValue();
if (token.type == COMMA)
GetToken(TOKEN_NOEXPRESSION);
*cx= GetDlgValue();
if (token.type == COMMA)
GetToken(TOKEN_NOEXPRESSION);
*cy= GetDlgValue();
}
typedef struct tagCTRLTYPE {
WORD type;
DWORD dwStyle;
BYTE bCode;
BYTE fHasText;
} CTRLTYPE;
CTRLTYPE ctrlTypes[] = {
{ TKGROUPBOX, BS_GROUPBOX, BUTTONCODE, TRUE },
{ TKPUSHBUTTON, BS_PUSHBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
{ TKDEFPUSHBUTTON, BS_DEFPUSHBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
{ TKCHECKBOX, BS_CHECKBOX | WS_TABSTOP, BUTTONCODE, TRUE },
{ TKRADIOBUTTON, BS_RADIOBUTTON, BUTTONCODE, TRUE },
{ TKAUTO3, BS_AUTO3STATE | WS_TABSTOP, BUTTONCODE, TRUE },
{ TKAUTOCHECK, BS_AUTOCHECKBOX | WS_TABSTOP, BUTTONCODE, TRUE },
{ TKAUTORADIO, BS_AUTORADIOBUTTON, BUTTONCODE, TRUE },
{ TKPUSHBOX, BS_PUSHBOX | WS_TABSTOP, BUTTONCODE, TRUE },
{ TK3STATE, BS_3STATE | WS_TABSTOP, BUTTONCODE, TRUE },
{ TKUSERBUTTON, BS_USERBUTTON | WS_TABSTOP, BUTTONCODE, TRUE },
{ TKLTEXT, ES_LEFT | WS_GROUP, STATICCODE, TRUE },
{ TKRTEXT, ES_RIGHT | WS_GROUP, STATICCODE, TRUE },
{ TKCTEXT, ES_CENTER | WS_GROUP, STATICCODE, TRUE },
{ TKICON, SS_ICON, STATICCODE, TRUE },
{ TKBEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
{ TKHEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
{ TKIEDIT, ES_LEFT | WS_BORDER | WS_TABSTOP, 0, FALSE },
{ TKEDITTEXT, ES_LEFT | WS_BORDER | WS_TABSTOP, EDITCODE, FALSE },
{ TKLISTBOX, WS_BORDER | LBS_NOTIFY, LISTBOXCODE, FALSE },
{ TKCOMBOBOX, 0, COMBOBOXCODE, FALSE },
{ TKSCROLLBAR, 0, SCROLLBARCODE, FALSE }
};
#define C_CTRLTYPES (sizeof(ctrlTypes) / sizeof(CTRLTYPE))
// ----------------------------------------------------------------------------
//
// GetDlgItems(fDlgEx) -
//
// ----------------------------------------------------------------------------
int
GetDlgItems(
BOOL fDlgEx
)
{
CTRL ctrl;
int i;
cidMac = 0;
cidMax = 100;
pid = (PDWORD) MyAlloc(sizeof(DWORD)*cidMax);
if (!pid)
return FALSE;
GetToken(TRUE);
/* read all the controls in the dialog */
ctrl.id = 0L; // initialize the control's id to 0
while (token.type != END) {
ctrl.dwHelpID = 0L;
ctrl.dwExStyle = 0L;
ctrl.dwStyle = WS_CHILD | WS_VISIBLE;
ctrl.text[0] = 0;
ctrl.fOrdinalText = FALSE;
if (token.type == TKCONTROL) {
ParseCtl(&ctrl, fDlgEx);
} else {
for (i = 0; i < C_CTRLTYPES; i++)
if (token.type == ctrlTypes[i].type)
break;
if (i == C_CTRLTYPES) {
ParseError1(2111); //"Invalid Control type : ", tokenbuf
return(FALSE);
}
ctrl.dwStyle |= ctrlTypes[i].dwStyle;
if (fMacRsrcs &&
(token.type == TKPUSHBUTTON ||
token.type == TKDEFPUSHBUTTON ||
token.type == TKCHECKBOX ||
token.type == TKAUTO3 ||
token.type == TKAUTOCHECK ||
token.type == TKPUSHBOX ||
token.type == TK3STATE ||
token.type == TKUSERBUTTON))
{
ctrl.dwStyle &= ~WS_TABSTOP;
}
if (ctrlTypes[i].bCode) {
ctrl.Class[0] = 0xFFFF;
ctrl.Class[1] = ctrlTypes[i].bCode;
} else {
CheckStr(ctrl.Class);
}
if (ctrlTypes[i].fHasText)
GetCtlText(&ctrl);
// find the ID and the coordinates
GetCtlID(&ctrl, fDlgEx);
GetCoords(&ctrl.x, &ctrl.y, &ctrl.cx, &ctrl.cy);
// get optional style, exstyle, and helpid
if (token.type == COMMA) {
GetToken(TOKEN_NOEXPRESSION);
GetFullExpression(&ctrl.dwStyle, 0);
}
}
if (token.type == COMMA) {
GetToken(TOKEN_NOEXPRESSION);
GetFullExpression(&ctrl.dwExStyle, 0);
if (fDlgEx && (token.type == COMMA)) {
GetToken(TOKEN_NOEXPRESSION);
GetFullExpression(&ctrl.dwHelpID, GFE_ZEROINIT);
}
}
SetUpItem(&ctrl, fDlgEx); /* gen the code for it */
if (fDlgEx && (token.type == BEGIN)) {
/* align any CreateParams are there */
//WriteAlign(); not yet!!!
// we're ok passing NULL in for pRes here because PreBeginParse
// won't have to use pRes
// Note that passing fDlgEx is actually redundant since it
// will always be TRUE here, but we'll do it in case someone
// else ever calls SetItemExtraCount
SetItemExtraCount(GetRCData(NULL), fDlgEx);
GetToken(TOKEN_NOEXPRESSION);
}
}
MyFree(pid);
return TRUE;
}
/*---------------------------------------------------------------------------*/
/* */
/* GetDlg() - */
/* */
/*---------------------------------------------------------------------------*/
int
GetDlg(
PRESINFO pRes,
PDLGHDR pDlg,
BOOL fDlgEx
)
{
/* initialize and defaults */
pDlg->dwExStyle = pRes->exstyleT;
pDlg->dwStyle = WS_POPUPWINDOW | WS_SYSMENU;
pDlg->MenuName[0] = 0;
pDlg->Title[0] = 0;
pDlg->Class[0] = 0;
pDlg->fOrdinalMenu = FALSE;
pDlg->fClassOrdinal = FALSE;
pDlg->pointsize = 0;
// get x, y, cx, cy
GetCoords(&pDlg->x, &pDlg->y, &pDlg->cx, &pDlg->cy);
/* get optional parameters */
if (!DLexOptionalArgs(pRes, pDlg, fDlgEx))
return FALSE;
if (pDlg->pointsize)
pDlg->dwStyle |= DS_SETFONT;
else
pDlg->dwStyle &= ~DS_SETFONT;
/* output header to the resource buffer */
SetUpDlg(pDlg, fDlgEx);
/* make sure we have a BEGIN */
if (token.type != BEGIN)
ParseError1(2112); //"BEGIN expected in Dialog"
/* get the dialog items */
GetDlgItems(fDlgEx);
if (fMacRsrcs)
SwapItemCount();
/* make sure this ended on an END */
if (token.type != END)
ParseError1(2113); //"END expected in Dialog"
return (TRUE);
}
typedef struct tagCTRLNAME {
BYTE bCode;
WORD wType;
PWCHAR pszName;
} CTRLNAME;
CTRLNAME ctrlNames[] = {
{ BUTTONCODE, TKBUTTON, L"button" },
{ EDITCODE, TKEDIT, L"edit" },
{ STATICCODE, TKSTATIC, L"static" },
{ LISTBOXCODE, TKLISTBOX, L"listbox" },
{ SCROLLBARCODE, TKSCROLLBAR, L"scrollbar" },
{ COMBOBOXCODE, TKCOMBOBOX, L"combobox" }
};
#define C_CTRLNAMES (sizeof(ctrlNames) / sizeof(CTRLNAME))
/*---------------------------------------------------------------------------*/
/* */
/* ParseCtl() - */
/* */
/*---------------------------------------------------------------------------*/
// for a control of the form CTL
void
ParseCtl(
PCTRL LocCtl,
BOOL fDlgEx
)
{ /* by now we've read the CTL */
int i;
/* get the control text and identifier */
GetCtlText(LocCtl);
GetCtlID(LocCtl, fDlgEx);
if (token.type == NUMLIT) {
LocCtl->Class[0] = (char) token.val;
LocCtl->Class[1] = 0;
} else if (token.type == LSTRLIT) {
// We will now convert class name strings to short form magic
// numbers. These magic numbers are order dependent as defined in
// USER. This provides some space savings in resource files.
for (i = C_CTRLNAMES; i; ) {
if (!_wcsicmp(tokenbuf, ctrlNames[--i].pszName))
goto Found1;
}
CheckStr(LocCtl->Class);
} else {
for (i = C_CTRLNAMES; i; ) {
if (token.type == ctrlNames[--i].wType)
goto Found1;
}
ParseError1(2114); //"Expected control class name"
Found1:
LocCtl->Class[0] = 0xFFFF;
LocCtl->Class[1] = ctrlNames[i].bCode;
}
/* get the style bits */
GetTokenNoComma(TOKEN_NOEXPRESSION);
GetFullExpression(&LocCtl->dwStyle, 0);
/* get the coordinates of the control */
ICGetTok();
GetCoords(&LocCtl->x, &LocCtl->y, &LocCtl->cx, &LocCtl->cy);
}
/*---------------------------------------------------------------------------*/
/* */
/* GetCtlText() - */
/* */
/*---------------------------------------------------------------------------*/
VOID
GetCtlText(
PCTRL pLocCtl
)
{
GetTokenNoComma(TOKEN_NOEXPRESSION);
if (CheckStr(pLocCtl->text)) {
pLocCtl->fOrdinalText = FALSE;
token.sym.name[0] = L'\0';
token.sym.nID = 0;
} else if (token.type == NUMLIT) {
wcsitow(token.val, pLocCtl->text, 10);
pLocCtl->fOrdinalText = TRUE;
WriteSymbolUse(&token.sym);
} else {
ParseError1(2115); //"Text string or ordinal expected in Control"
}
}
/*---------------------------------------------------------------------------*/
/* */
/* GetCtlID() - */
/* */
/*---------------------------------------------------------------------------*/
VOID
GetCtlID(
PCTRL pLocCtl,
BOOL fDlgEx
)
{
WORD wGFE = GFE_ZEROINIT;
int i;
ICGetTok();
WriteSymbolUse(&token.sym);
if (!fDlgEx)
wGFE |= GFE_SHORT;
if (GetFullExpression(&pLocCtl->id, wGFE)) {
if (!fDlgEx && pLocCtl->id != (DWORD)(WORD)-1 ||
fDlgEx && pLocCtl->id != (DWORD)-1) {
for (i=0 ; i<cidMac ; i++) {
if (pLocCtl->id == *(pid+i) && !fSkipDuplicateCtlIdWarning) {
i = (int)pLocCtl->id;
SET_MSG(Msg_Text, sizeof(Msg_Text), GET_MSG(2182),
curFile, token.row, i);
SendError(Msg_Text);
break;
}
}
if (cidMac == cidMax) {
PDWORD pidNew;
cidMax += 100;
pidNew = (PDWORD) MyAlloc(cidMax*sizeof(DWORD));
memcpy(pidNew, pid, cidMac*sizeof(DWORD));
MyFree(pid);
pid = pidNew;
}
*(pid+cidMac++) = pLocCtl->id;
}
} else {
ParseError1(2116); //"Expecting number for ID"
}
if (token.type == COMMA)
ICGetTok();
}
// ----------------------------------------------------------------------------
//
// DLexOptionArgs(pRes, fDlgEx) -
//
// ----------------------------------------------------------------------------
BOOL
DLexOptionalArgs(
PRESINFO pRes,
PDLGHDR pDlg,
BOOL fDlgEx
)
{
/* read all the optional dialog items */
if (fDlgEx && (token.type == COMMA)) {
GetToken(TOKEN_NOEXPRESSION);
GetFullExpression(&pDlg->dwHelpID, GFE_ZEROINIT);
}
while (token.type != BEGIN) {
switch (token.type) {
case TKLANGUAGE:
pRes->language = GetLanguage();
GetToken(FALSE);
break;
case TKVERSION:
GetToken(FALSE);
if (token.type != NUMLIT)
ParseError1(2139);
pRes->version = token.longval;
GetToken(FALSE);
break;
case TKCHARACTERISTICS:
GetToken(FALSE);
if (token.type != NUMLIT)
ParseError1(2140);
pRes->characteristics = token.longval;
GetToken(FALSE);
break;
case TKSTYLE:
// If CAPTION statement preceded STYLE statement, then we
// already must have WS_CAPTION bits set in the "style"
// field and we must not lose it;
if ((pDlg->dwStyle & WS_CAPTION) == WS_CAPTION)
pDlg->dwStyle = WS_CAPTION;
else
pDlg->dwStyle = 0;
GetTokenNoComma(TOKEN_NOEXPRESSION);
GetFullExpression(&pDlg->dwStyle, 0);
break;
case TKEXSTYLE:
GetTokenNoComma(TOKEN_NOEXPRESSION);
GetFullExpression(&pDlg->dwExStyle, 0);
break;
case TKCAPTION:
DGetTitle(pDlg);
break;
case TKMENU:
DGetMenuName(pDlg);
break;
case TKCLASS:
DGetClassName(pDlg);
break;
case TKFONT:
DGetFont(pDlg, fDlgEx);
break;
default:
ParseError1(2112); //"BEGIN expected in dialog");
return FALSE;
}
}
return TRUE;
}
/*---------------------------------------------------------------------------*/
/* */
/* DGetFont() - */
/* */
/*---------------------------------------------------------------------------*/
void
DGetFont(
PDLGHDR pDlg,
BOOL fDlgEx
)
{
WORD w;
int i;
GetToken(TRUE);
if (!GetFullExpression(&pDlg->pointsize, GFE_ZEROINIT | GFE_SHORT))
ParseError1(2117); //"Expected numeric point size"
if (token.type == COMMA)
ICGetTok();
if (!CheckStr(pDlg->Font))
ParseError1(2118); //"Expected font face name"
if (_wcsicmp(pDlg->Font, L"System") &&
szSubstituteFontName[0] != UNICODE_NULL) {
for (i=0; i<nBogusFontNames; i++) {
if (!_wcsicmp(pszBogusFontNames[i], pDlg->Font)) {
GenWarning4(4510, (PCHAR)pDlg->Font, (PCHAR)szSubstituteFontName, 0 ); // Warning for hard coded fonts
wcscpy(pDlg->Font, szSubstituteFontName);
}
}
}
GetToken(TRUE);
pDlg->bCharSet = DEFAULT_CHARSET;
if (fDlgEx && (token.type == COMMA)) {
GetToken(TOKEN_NOEXPRESSION);
if (GetFullExpression(&w, GFE_ZEROINIT | GFE_SHORT))
pDlg->wWeight = w;
if (token.type == COMMA) {
GetToken(TOKEN_NOEXPRESSION);
if (token.type == NUMLIT) {
pDlg->bItalic = (token.val) ? TRUE : FALSE;
GetToken(TOKEN_NOEXPRESSION);
if (token.type == COMMA) {
GetToken(TOKEN_NOEXPRESSION);
if (GetFullExpression(&w, GFE_ZEROINIT | GFE_SHORT))
pDlg->bCharSet = (UCHAR) w;
}
}
}
}
}
/*---------------------------------------------------------------------------*/
/* */
/* DGetMenuName() - */
/* */
/*---------------------------------------------------------------------------*/
/* gets the unquoted string of the name of the optional menu associated */
/* with the dialog. */
VOID
DGetMenuName(
PDLGHDR pDlg
)
{
if (GetGenText()) {
/* copy the menu name */
token.type = LSTRLIT;
CheckStr(pDlg->MenuName);
/* check if menu name is an ordinal */
if (wcsdigit(pDlg->MenuName[0]))
pDlg->fOrdinalMenu = TRUE;
GetToken(TRUE);
}
}
/*---------------------------------------------------------------------------*/
/* */
/* DGetTitle() - */
/* */
/*---------------------------------------------------------------------------*/
VOID
DGetTitle(
PDLGHDR pDlg
)
{
GetToken(TRUE);
if (CheckStr(pDlg->Title))
pDlg->dwStyle |= WS_CAPTION;
else
ParseError1(2119); //"Expecting quoted string in dialog title"
GetToken(TRUE);
}
/*---------------------------------------------------------------------------*/
/* */
/* DGetClassName() - */
/* */
/*---------------------------------------------------------------------------*/
VOID
DGetClassName(
PDLGHDR pDlg
)
{
GetToken(TRUE);
if (!CheckStr(pDlg->Class)) {
if (token.type == NUMLIT) {
wcsitow(token.val, pDlg->Class, 10);
pDlg->fClassOrdinal = TRUE;
} else {
ParseError1(2120); //"Expecting quoted string in dialog class"
}
}
GetToken(TRUE);
}
/*---------------------------------------------------------------------------*/
/* Gets a token, ignoring commas. Returns the token type. */
/* */
/* ICGetTok() - */
/* */
/*---------------------------------------------------------------------------*/
/* Get token, but ignore commas */
USHORT
ICGetTok(
VOID
)
{
fComma = FALSE; // NT added the use of this fComma flag
GetToken(TRUE);
while (token.type == COMMA) {
GetToken(TRUE);
fComma = TRUE; // and they set it here
}
return (USHORT)token.type;
}
/* GetTokenNoComma
* This function replaces ICGetTok() but has a flag to support
* the turning off of expression parsing.
*/
USHORT
GetTokenNoComma(
USHORT wFlags
)
{
/* Get a token */
GetToken(TRUE | wFlags);
/* Ignore any commas */
while (token.type == COMMA)
GetToken(TRUE | wFlags);
return (USHORT)token.type;
}
/************* Menu Parsing Routines *********************/
/*---------------------------------------------------------------------------*/
/* */
/* IsmnOption() - */
/* */
/*---------------------------------------------------------------------------*/
int
IsmnOption(
UINT arg,
PMENUITEM pmn
)
{
/* if we have a valid flag, or it into the menu flags */
switch (arg) {
case TKOWNERDRAW:
pmn->OptFlags |= OPOWNERDRAW;
break;
case TKCHECKED:
pmn->OptFlags |= OPCHECKED;
break;
case TKGRAYED:
pmn->OptFlags |= OPGRAYED;
break;
case TKINACTIVE:
pmn->OptFlags |= OPINACTIVE;
break;
case TKBREAKWBAR:
pmn->OptFlags |= OPBREAKWBAR;
break;
case TKBREAK:
pmn->OptFlags |= OPBREAK;
break;
case TKHELP:
pmn->OptFlags |= OPHELP;
break;
case TKBITMAP:
pmn->OptFlags |= OPBITMAP;
break;
default:
return(FALSE);
}
return(TRUE);
#if 0
if ((arg == OPBREAKWBAR) || (arg == OPHELP ) || (arg == OPGRAYED) ||
(arg == OPUSECHECKBITMAPS) || (arg == OPCHECKED) || (arg == OPBITMAP) ||
(arg == OPOWNERDRAW) || (arg == OPBREAK ) || (arg == OPINACTIVE))
{
pmn->OptFlags |= arg;
return TRUE;
}
#if 0
if (arg == OPHELP) {
pmn->OptFlags |= OPPOPHELP;
return TRUE;
}
#endif
return FALSE;
#endif
}
// ----------------------------------------------------------------------------
//
// DoOldMenuItem() -
//
// ----------------------------------------------------------------------------
WORD
DoOldMenuItem(
int fPopup
)
{
MENUITEM mnTemp;
mnTemp.PopFlag = (UCHAR)fPopup;
GetToken(TRUE);
/* menu choice string */
if (CheckStr(mnTemp.szText)) {
mnTemp.OptFlags = OPPOPUP;
ICGetTok();
if (!fPopup) {
/* change the flag and get the ID if not a popup */
mnTemp.OptFlags = 0;
WriteSymbolUse(&token.sym);
if (!GetFullExpression(&mnTemp.id, GFE_ZEROINIT | GFE_SHORT))
ParseError1(2125); //"Expected ID value for Menuitem"
if (token.type == COMMA)
GetToken(TOKEN_NOEXPRESSION);
}
/* read the menu option flags */
while (IsmnOption(token.type, &mnTemp))
ICGetTok();
} else if (token.type == TKSEPARATOR) {
mnTemp.szText[0] = 0; // MENUITEM SEPARATOR
mnTemp.id = 0;
mnTemp.OptFlags = 0;
ICGetTok();
} else {
ParseError1(2126); //"Expected Menu String"
}
/* set it up in the buffer (?) */
return(SetUpOldMenu(&mnTemp));
}
/*---------------------------------------------------------------------------*/
/* */
/* ParseOldMenu() - */
/* */
/*---------------------------------------------------------------------------*/
int
ParseOldMenu(
int fRecursing,
PRESINFO pRes // 8 char proc name limitation!
)
{
BOOL bItemRead = FALSE;
WORD wEndFlagLoc = 0;
if (!fRecursing) {
PreBeginParse(pRes, 2121);
} else {
/* make sure its really a menu */
if (token.type != BEGIN)
ParseError1(2121); //"BEGIN expected in menu"
GetToken(TRUE);
}
/* get the individual menu items */
while (token.type != END) {
switch (token.type) {
case TKMENUITEM:
bItemRead = TRUE;
wEndFlagLoc = DoOldMenuItem(FALSE);
break;
case TKPOPUP:
bItemRead = TRUE;
wEndFlagLoc = DoOldMenuItem(TRUE);
ParseOldMenu(TRUE, pRes);
break;
default:
ParseError1(2122); //"Unknown Menu SubType :"
break;
}
}
/* did we die on an END? */
if (token.type != END)
ParseError1(2123); //"END expected in menu"
/* make sure we have a menu item */
if (!bItemRead)
ParseError1(2124); //"Empty menus not allowed"
/* Get next token if this was NOT the last END*/
if (fRecursing)
GetToken(TRUE);
/* mark the last item in the menu */
FixOldMenuPatch(wEndFlagLoc);
return (TRUE);
}
/* ----- Version resource stuff ----- */
/* VersionParse
* Parses the VERSION resource and places it in the global buffer
* so it can be written out by SaveResFile().
*/
int
VersionParse(
VOID
)
{
int Index;
/* Get the fixed structure entries */
/* Note that VersionParseFixed doesn't actually fail! */
/* This is because VersionBlockStruct doesn't fail. */
Index = VersionParseFixed();
/* Put the following blocks in as sub-blocks. Fix up the length when
* we're done.
*/
SetItemCount(Index, (USHORT)(GetItemCount(Index) + VersionParseBlock()));
/* The return data buffer is global */
return TRUE;
}
/* VersionParseFixed
* Parses the fixed portion of the version resource. Returns a pointer
* to the length word of the block. This word has the length of
* the fixed portion precomputed and remains to have the variable
* portion added in.
*/
int
VersionParseFixed(
VOID
)
{
VS_FIXEDFILEINFO FixedInfo;
/* Initialize the structure fields */
memset((PCHAR)&FixedInfo, 0, sizeof(FixedInfo));
FixedInfo.dwSignature = 0xfeef04bdL;
FixedInfo.dwStrucVersion = 0x00010000L;
FixedInfo.dwFileDateMS = 0L;
FixedInfo.dwFileDateLS = 0L;
/* Loop through tokens until we get the "BEGIN" token which
* must be present to terminate the fixed portion of the VERSIONINFO
* resource.
*/
while (token.type != BEGIN) {
switch (token.type) {
/* The following have four WORDS scrambled into two DWORDS */
case TKFILEVERSION:
VersionGet4Words(&FixedInfo.dwFileVersionMS);
break;
case TKPRODUCTVERSION:
VersionGet4Words(&FixedInfo.dwProductVersionMS);
break;
/* The following have just one DWORD */
case TKFILEFLAGSMASK:
VersionGetDWord(&FixedInfo.dwFileFlagsMask);
break;
case TKFILEFLAGS:
VersionGetDWord(&FixedInfo.dwFileFlags);
break;
case TKFILEOS:
VersionGetDWord(&FixedInfo.dwFileOS);
break;
case TKFILETYPE:
VersionGetDWord(&FixedInfo.dwFileType);
break;
case TKFILESUBTYPE:
VersionGetDWord(&FixedInfo.dwFileSubtype);
break;
/* Other tokens are unknown */
default:
ParseError1(2167); //"Unrecognized VERSIONINFO field;"
}
}
/* Write the block out and return the pointer to the length */
return VersionBlockStruct(L"VS_VERSION_INFO", (PCHAR)&FixedInfo,
sizeof(FixedInfo));
}
/* VersionGet4Words
* Reads a version number from the source file and scrambles them
* to fit in two DWORDs. We force them to put commas in here so
* that if they don't put in enough values we can fill in zeros.
*/
VOID
VersionGet4Words(
ULONG *pdw
)
{
// static CHAR szParseError[] = "Version WORDs separated by commas expected";
/* Get the first number */
GetToken(TRUE);
if (token.type != NUMLIT || token.flongval)
ParseError1(2127); //szParseError
*pdw = ((LONG)token.val) << 16;
/* Get the comma. If none, we're done, so fill the rest with zeros */
GetToken(TRUE);
if (token.type != COMMA) {
*++pdw = 0L;
return;
}
/* Get the second number */
GetToken(TRUE);
if (token.type != NUMLIT || token.flongval)
ParseError1(2127); //szParseError
*(PUSHORT)pdw = token.val;
/* Get the comma. If none, we're done, so fill the rest with zeros */
GetToken(TRUE);
if (token.type != COMMA) {
*++pdw = 0L;
return;
}
/* Get the third number */
GetToken(TRUE);
if (token.type != NUMLIT || token.flongval)
ParseError1(2127); //szParseError
*++pdw = ((LONG)token.val) << 16;
/* Get the comma. If none, we're done */
GetToken(TRUE);
if (token.type != COMMA)
return;
/* Get the fourth number */
GetToken(TRUE);
if (token.type != NUMLIT || token.flongval)
ParseError1(2127); //szParseError
*(PUSHORT)pdw = token.val;
/* Get the next token for the loop */
GetToken(TRUE);
}
/* VersionGetDWord
* Reads a single DWORD from the source file into the given variable.
*/
VOID
VersionGetDWord(
ULONG *pdw
)
{
/* Get the token */
GetToken(TRUE);
if (token.type != NUMLIT)
ParseError1(2128); //"DWORD expected"
*pdw = token.longval;
/* Get the next token for the loop */
GetToken(TRUE);
}
/* VersionParseBlock
* Parses a block of version information. Note that this block may
* contain one or more additional blocks, causing this function to
* be called recursively. Returns the length of the block which can
* be added to the length of the current block. Returns 0xffff on error.
*/
USHORT
VersionParseBlock(
VOID
)
{
USHORT wLen;
int IndexLen;
USHORT wType;
/* Get the current position in the buffer */
wLen = GetBufferLen();
/* The token has already been read. This should be a BEGIN */
if (token.type != BEGIN)
ParseError1(2129); //"BEGIN expected in VERSIONINFO resource"
/* Get the first token. From here on, the VersionBlockVariable()
* routine gets the tokens as it searches for the end of the value
* field.
*/
GetToken(TRUE);
/* Loop until we get to the END for this BEGIN */
for (; ; ) {
/* Get and decode the next line type */
switch (token.type) {
case TKVALUE:
case TKBLOCK:
/* Save the type of this token */
wType = token.type;
/* Get the key string */
GetToken(TRUE);
if (token.type != LSTRLIT)
ParseError1(2131); //"Expecting quoted string for key"
/* Now feed in the key string and value items */
IndexLen = VersionBlockVariable(tokenbuf);
/* A "BLOCK" item causes recursion. Current token should be
* "BEGIN"
*/
if (wType == TKBLOCK) {
SetItemCount(IndexLen, (USHORT)(GetItemCount(IndexLen) + VersionParseBlock()));
GetToken(TRUE);
}
break;
case END:
/* We're done with this block. Get the next token
* (read past the "END") and return the length of the block.
*/
return GetBufferLen() - wLen;
default:
ParseError1(2132); //"Expected VALUE, BLOCK, or, END keyword."
}
}
}
#define DWORDALIGN(w) \
(((w) + (sizeof(ULONG) - 1)) & ~(USHORT)(sizeof(ULONG) - 1))
/* VersionBlockStruct
* Writes a version block without sub-blocks. Sub-blocks are to
* be written directly after this header. To facilitate this,
* a pointer to the block length is returned so that it can be modified.
* This call uses a pre-parsed value item. Use VersionBlockVariable()
* to parse the value items instead.
* Note that this actually can't fail!
*/
int
VersionBlockStruct(
PWCHAR pstrKey,
PCHAR pstrValue,
USHORT wLenValue
)
{
USHORT wLen;
int Index;
ULONG dwPadding = 0L;
USHORT wAlign;
/* Pad the block data to DWORD align */
wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
if (wAlign)
WriteBuffer((PCHAR)&dwPadding, wAlign);
/* Save the current length so we can compute the new block length later */
wLen = GetBufferLen();
/* Write a zero for the length for now */
Index = GetBufferLen();
WriteWord(0);
/* Write the length of the value field */
WriteWord(wLenValue);
/* data is binary */
WriteWord(0);
/* Write the key string now */
WriteString(pstrKey, TRUE);
/* Write the value data if there is any */
if (wLenValue) {
/* Now we have to DWORD align the value data */
wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
if (wAlign)
WriteBuffer((PSTR)&dwPadding, wAlign);
/* Write it to the buffer */
WriteBuffer((PSTR)pstrValue, wLenValue);
}
/* Now fix up the block length and return a pointer to it */
SetItemCount(Index, (USHORT)(GetBufferLen() - wLen));
return Index;
}
/* VersionBlockVariable
* Writes a version block without sub-blocks. Sub-blocks are to
* bre written directly after this header. To facilitate this,
* a pointer to the block length is returned so that it can be modified.
* VersionBlockVariable() gets the value items by parsing the
* RC script as RCDATA.
*/
int
VersionBlockVariable(
PWCHAR pstrKey
)
{
USHORT wLen;
int IndexLen;
int IndexType;
int IndexValueLen;
ULONG dwPadding = 0L;
USHORT wAlign;
/* Pad the block data to DWORD align */
wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
if (wAlign)
WriteBuffer((PCHAR)&dwPadding, wAlign);
/* Save the current length so we can compute the new block length later */
wLen = GetBufferLen();
/* Write a zero for the length for now */
IndexLen = GetBufferLen();
WriteWord(0);
/* Write the length of the value field. We fill this in later */
IndexValueLen = GetBufferLen();
WriteWord(0);
/* Assume string data */
IndexType = GetBufferLen();
WriteWord(1);
/* Write the key string now */
WriteString(pstrKey, TRUE);
/* Parse and write the value data if there is any */
SetItemCount(IndexValueLen, VersionParseValue(IndexType));
/* Now fix up the block length and return a pointer to it */
SetItemCount(IndexLen, (USHORT)(GetBufferLen() - wLen));
return IndexLen;
}
/* VersionParseValue
* Parses the fields following either BLOCK or VALUE and following
* their key string which is parsed by VersionParseBlock().
* Before writing the first value item out, the field has to be
* DWORD aligned. Returns the length of the value block.
*/
USHORT
VersionParseValue(
int IndexType
)
{
USHORT wFirst = FALSE;
USHORT wToken;
USHORT wAlign;
ULONG dwPadding = 0L;
USHORT wLen = 0;
/* Decode all tokens until we get to the end of this item */
for (; ; ) {
/* ICGetTok is GetToken(TRUE) ignoring commas */
wToken = ICGetTok();
/* If this is the first item, DWORD align it. Since empty value
* sections are legal, we have to wait until we actually have data
* to do this.
*/
if (!wFirst) {
wFirst = TRUE;
wAlign = DWORDALIGN(GetBufferLen()) - GetBufferLen();
if (wAlign)
WriteBuffer((PCHAR)&dwPadding, wAlign);
}
switch (wToken) {
case TKVALUE:
case TKBLOCK:
case BEGIN:
case END:
return wLen;
case LSTRLIT: /* String, write characters */
if (tokenbuf[0] == L'\0') /* ignore null strings */
break;
/* remove extra nuls */
while (tokenbuf[token.val-1] == L'\0')
token.val--;
wAlign = token.val + 1; /* want the character count */
wLen += wAlign;
if (fComma) {
WriteString(tokenbuf, TRUE);
} else {
AppendString(tokenbuf, TRUE);
wLen--;
}
break;
case NUMLIT: /* Write the computed number out */
SetItemCount(IndexType, 0); /* mark data binary */
if (token.flongval) {
WriteLong(token.longval);
wLen += sizeof(LONG);
} else {
WriteWord(token.val);
wLen += sizeof(WORD);
}
break;
default:
ParseError1(2133); //"Unexpected value in value data"
return 0;
}
}
}
VOID
DlgIncludeParse(
PRESINFO pRes
)
{
INT i;
INT nbytes;
char * lpbuf;
if (token.type != LSTRLIT) {
ParseError1(2165);
return;
}
// the DLGINCLUDE statement must be written in ANSI (8-bit) for compatibility
// WriteString(tokenbuf);
nbytes = WideCharToMultiByte (CP_ACP, 0, tokenbuf, -1, NULL, 0, NULL, NULL);
lpbuf = (char *) MyAlloc (nbytes);
WideCharToMultiByte (CP_ACP, 0, tokenbuf, -1, lpbuf, nbytes, NULL, NULL);
for (i = 0; i < nbytes; i++)
WriteByte (lpbuf[i]);
MyFree(lpbuf);
return;
}