2398 lines
79 KiB
C
2398 lines
79 KiB
C
//*********************************************************************
|
|
//* Microsoft Windows **
|
|
//* Copyright(c) Microsoft Corp., 1994 **
|
|
//*********************************************************************
|
|
|
|
#include "admincfg.h"
|
|
#include "parse.h"
|
|
|
|
UINT nFileLine;
|
|
TABLEENTRY * pListCurrent; // current category list (either user or machine)
|
|
UINT *pnDataItemCount;
|
|
|
|
// buffer to read .INF file into
|
|
CHAR * pFileBuf;
|
|
CHAR * pFilePtr;
|
|
CHAR * pFileEnd;
|
|
WCHAR *pUnicodeFileBuf;
|
|
|
|
BOOL fInComment;
|
|
BOOL fEOF;
|
|
BOOL fUnicode;
|
|
BOOL fCheckUnicode;
|
|
|
|
LPSTR pszParseFileName;
|
|
|
|
UINT ParseEntry(HWND hWnd,PARSEENTRYSTRUCT *ppes,BOOL *pfMore);
|
|
|
|
UINT ParseCategory(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
|
|
BOOL fParentHasKey,BOOL *pfMore);
|
|
UINT CategoryParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
|
|
BOOL * pfMore,BOOL * pfFoundEnd);
|
|
|
|
UINT ParsePolicy(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
|
|
BOOL fParentHasKey,BOOL *pfMore);
|
|
UINT PolicyParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
|
|
BOOL * pfMore,BOOL * pfFoundEnd);
|
|
|
|
UINT ParseSettings(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
|
|
BOOL fParentHasKey,BOOL *pfMore);
|
|
UINT SettingsParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
|
|
BOOL * pfMore,BOOL * pfFoundEnd);
|
|
|
|
UINT ParseClass(HWND hWnd,HANDLE hFile,BOOL *pfMore);
|
|
UINT InitSettingsParse(PARSEPROCSTRUCT *ppps,DWORD dwType,DWORD dwSize,
|
|
KEYWORDINFO * pKeyList,SETTINGS ** ppSettings,CHAR **pObjectData);
|
|
|
|
BOOL CompareKeyword(HWND hWnd,CHAR * szWord,KEYWORDINFO *pKeywordList,
|
|
UINT * pnListIndex);
|
|
VOID DisplayKeywordError(HWND hWnd,UINT uErrorID,CHAR * szFound,
|
|
KEYWORDINFO * pExpectedList,CHAR * szFilename,UINT nLine);
|
|
|
|
CHAR * GetNextSectionWord(HWND hWnd,HANDLE hFile,CHAR * szBuf,UINT cbBuf,
|
|
KEYWORDINFO * pKeywordList,UINT *pnListIndex,BOOL * pfMore,UINT * puErr);
|
|
UINT GetNextSectionNumericWord(HWND hWnd,HANDLE hFile,UINT * pnVal);
|
|
CHAR * GetNextWord(HWND hWnd,HANDLE hFile,CHAR * szBuf,UINT cbBuf,BOOL * pfMore,UINT *
|
|
puErr);
|
|
|
|
UINT ParseValue(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
|
|
TABLEENTRY ** ppTableEntryNew,BOOL *pfMore);
|
|
UINT ParseSuggestions(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
|
|
TABLEENTRY ** ppTableEntryNew,BOOL * pfMore);
|
|
UINT ParseActionList(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
|
|
TABLEENTRY ** ppTableEntryNew,LPCSTR pszKeyword,BOOL * pfMore);
|
|
UINT ParseItemList(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
|
|
BOOL * pfMore);
|
|
|
|
CHAR * AddDataToEntry(TABLEENTRY * pTableEntry,CHAR * szData,UINT cbData,
|
|
UINT * puOffsetData,DWORD * pdwBufSize);
|
|
BOOL AddCleanupItem(CLEANUPINFO * pCleanUp,UINT nMax,HGLOBAL hMem, UINT nAction);
|
|
UINT CleanupAndReturn(UINT uRetVal,CLEANUPINFO * pCleanup);
|
|
|
|
// list of legal keyword entries in "CATEGORY" section
|
|
KEYWORDINFO pCategoryEntryCmpList[] = { {szKEYNAME,KYWD_ID_KEYNAME},
|
|
{szCATEGORY,KYWD_ID_CATEGORY},{szPOLICY,KYWD_ID_POLICY},
|
|
{szEND,KYWD_ID_END}, {NULL,0} };
|
|
KEYWORDINFO pCategoryTypeCmpList[] = { {szCATEGORY,KYWD_ID_CATEGORY},
|
|
{NULL,0} };
|
|
|
|
// list of legal keyword entries in "POLICY" section
|
|
KEYWORDINFO pPolicyEntryCmpList[] = { {szKEYNAME,KYWD_ID_KEYNAME},
|
|
{szVALUENAME,KYWD_ID_VALUENAME}, {szPART,KYWD_ID_PART},
|
|
{szVALUEON,KYWD_ID_VALUEON},{szVALUEOFF,KYWD_ID_VALUEOFF},
|
|
{szACTIONLISTON,KYWD_ID_ACTIONLISTON},{szACTIONLISTOFF,KYWD_ID_ACTIONLISTOFF},
|
|
{szEND,KYWD_ID_END},{szHELP,KYWD_ID_HELP}, {szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL, 0} };
|
|
KEYWORDINFO pPolicyTypeCmpList[] = { {szPOLICY,KYWD_ID_POLICY}, {NULL,0} };
|
|
|
|
// list of legal keyword entries in "PART" section
|
|
KEYWORDINFO pSettingsEntryCmpList[] = { {szCHECKBOX,KYWD_ID_CHECKBOX},
|
|
{szTEXT,KYWD_ID_TEXT},{szEDITTEXT,KYWD_ID_EDITTEXT},
|
|
{szNUMERIC,KYWD_ID_NUMERIC},{szCOMBOBOX,KYWD_ID_COMBOBOX},
|
|
{szDROPDOWNLIST,KYWD_ID_DROPDOWNLIST},{szLISTBOX,KYWD_ID_LISTBOX},
|
|
{szEND,KYWD_ID_END},{szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0}};
|
|
KEYWORDINFO pSettingsTypeCmpList[] = {{szPART,KYWD_ID_PART},{NULL,0}};
|
|
|
|
KEYWORDINFO pCheckboxCmpList[] = {
|
|
{szKEYNAME,KYWD_ID_KEYNAME},{szVALUENAME,KYWD_ID_VALUENAME},
|
|
{szVALUEON,KYWD_ID_VALUEON},{szVALUEOFF,KYWD_ID_VALUEOFF},
|
|
{szACTIONLISTON,KYWD_ID_ACTIONLISTON},{szACTIONLISTOFF,KYWD_ID_ACTIONLISTOFF},
|
|
{szDEFCHECKED, KYWD_ID_DEFCHECKED},{szCLIENTEXT,KYWD_ID_CLIENTEXT},
|
|
{szEND,KYWD_ID_END},{NULL,0} };
|
|
|
|
KEYWORDINFO pTextCmpList[] = {{szEND,KYWD_ID_END},{NULL,0}};
|
|
|
|
KEYWORDINFO pEditTextCmpList[] = {
|
|
{szKEYNAME,KYWD_ID_KEYNAME},{szVALUENAME,KYWD_ID_VALUENAME},
|
|
{szDEFAULT,KYWD_ID_EDITTEXT_DEFAULT},
|
|
{szREQUIRED,KYWD_ID_REQUIRED},{szMAXLENGTH,KYWD_ID_MAXLENGTH},
|
|
{szOEMCONVERT,KYWD_ID_OEMCONVERT},{szSOFT,KYWD_ID_SOFT},
|
|
{szEND,KYWD_ID_END},{szEXPANDABLETEXT,KYWD_ID_EXPANDABLETEXT},
|
|
{szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0} };
|
|
|
|
KEYWORDINFO pComboboxCmpList[] = {
|
|
{szKEYNAME,KYWD_ID_KEYNAME},{szVALUENAME,KYWD_ID_VALUENAME},
|
|
{szDEFAULT,KYWD_ID_COMBOBOX_DEFAULT},{szSUGGESTIONS,KYWD_ID_SUGGESTIONS},
|
|
{szREQUIRED,KYWD_ID_REQUIRED},{szMAXLENGTH,KYWD_ID_MAXLENGTH},
|
|
{szOEMCONVERT,KYWD_ID_OEMCONVERT},{szSOFT,KYWD_ID_SOFT},
|
|
{szEND,KYWD_ID_END},{szNOSORT, KYWD_ID_NOSORT},
|
|
{szEXPANDABLETEXT,KYWD_ID_EXPANDABLETEXT},{szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0} };
|
|
|
|
KEYWORDINFO pNumericCmpList[] = {
|
|
{szKEYNAME,KYWD_ID_KEYNAME},{szVALUENAME,KYWD_ID_VALUENAME},
|
|
{szMIN, KYWD_ID_MIN},{szMAX,KYWD_ID_MAX},{szSPIN,KYWD_ID_SPIN},
|
|
{szDEFAULT,KYWD_ID_NUMERIC_DEFAULT},{szREQUIRED,KYWD_ID_REQUIRED},
|
|
{szTXTCONVERT,KYWD_ID_TXTCONVERT},{szSOFT,KYWD_ID_SOFT},
|
|
{szEND,KYWD_ID_END}, {szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0} };
|
|
|
|
KEYWORDINFO pDropdownlistCmpList[] = {
|
|
{szKEYNAME,KYWD_ID_KEYNAME},{szVALUENAME,KYWD_ID_VALUENAME},
|
|
{szREQUIRED,KYWD_ID_REQUIRED},{szITEMLIST,KYWD_ID_ITEMLIST},
|
|
{szEND,KYWD_ID_END},{szNOSORT, KYWD_ID_NOSORT},{szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0}};
|
|
|
|
KEYWORDINFO pListboxCmpList[] = {
|
|
{szKEYNAME,KYWD_ID_KEYNAME},{szVALUEPREFIX,KYWD_ID_VALUEPREFIX},
|
|
{szADDITIVE,KYWD_ID_ADDITIVE},{szNOSORT, KYWD_ID_NOSORT},
|
|
{szEXPLICITVALUE,KYWD_ID_EXPLICITVALUE},{szEND,KYWD_ID_END},{szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0} };
|
|
|
|
KEYWORDINFO pClassCmpList[] = { {szCLASS, KYWD_ID_CLASS},
|
|
{szCATEGORY,KYWD_ID_CATEGORY}, {szStringsSect,KYWD_ID_STRINGSSECT},
|
|
{NULL,0} };
|
|
KEYWORDINFO pClassTypeCmpList[] = { {szUSER, KYWD_ID_USER},
|
|
{szMACHINE,KYWD_ID_MACHINE}, {NULL,0} };
|
|
|
|
KEYWORDINFO pVersionCmpList[] = { {szVERSION, KYWD_ID_VERSION}, {NULL,0}};
|
|
KEYWORDINFO pOperatorCmpList[] = { {szGT, KYWD_ID_GT}, {szGTE,KYWD_ID_GTE},
|
|
{szLT, KYWD_ID_LT}, {szLTE,KYWD_ID_LTE}, {szEQ,KYWD_ID_EQ},
|
|
{szNE, KYWD_ID_NE}, {NULL,0}};
|
|
|
|
UINT ParseTemplateFile(HWND hWnd,HANDLE hFile,LPSTR pszFileName)
|
|
{
|
|
BOOL fMore;
|
|
UINT uRet;
|
|
|
|
nFileLine = 1;
|
|
pListCurrent = gClassList.pMachineCategoryList;
|
|
pnDataItemCount = &gClassList.nMachineDataItems;
|
|
pszParseFileName = pszFileName;
|
|
|
|
if (!(pFileBuf = (CHAR *) GlobalAlloc(GPTR,FILEBUFSIZE))) {
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
pUnicodeFileBuf = NULL;
|
|
|
|
pFilePtr = pFileEnd = NULL;
|
|
fEOF = fInComment = fUnicode = FALSE;
|
|
fCheckUnicode = TRUE;
|
|
|
|
do {
|
|
|
|
uRet=ParseClass(hWnd,hFile,&fMore);
|
|
|
|
} while (fMore && uRet == ERROR_SUCCESS);
|
|
|
|
GlobalFree(pFileBuf);
|
|
if (NULL != pUnicodeFileBuf)
|
|
GlobalFree(pUnicodeFileBuf);
|
|
|
|
return uRet;
|
|
}
|
|
|
|
UINT ParseClass(HWND hWnd,HANDLE hFile,BOOL *pfMore)
|
|
{
|
|
CHAR szWordBuf[WORDBUFSIZE+1];
|
|
UINT uErr,nKeywordID,nClassID;
|
|
|
|
if (!GetNextWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),pfMore,&uErr))
|
|
return uErr;
|
|
|
|
if (!CompareKeyword(hWnd,szWordBuf,pClassCmpList,&nKeywordID))
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
|
|
switch (nKeywordID) {
|
|
|
|
case KYWD_ID_CATEGORY:
|
|
|
|
return ParseCategory(hWnd,hFile,pListCurrent,
|
|
FALSE,pfMore);
|
|
break;
|
|
|
|
case KYWD_ID_CLASS:
|
|
|
|
if (!GetNextSectionWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),
|
|
pClassTypeCmpList,&nClassID,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
switch (nClassID) {
|
|
|
|
case KYWD_ID_USER:
|
|
|
|
pListCurrent = gClassList.pUserCategoryList;
|
|
pnDataItemCount = &gClassList.nUserDataItems;
|
|
break;
|
|
|
|
case KYWD_ID_MACHINE:
|
|
pListCurrent = gClassList.pMachineCategoryList;
|
|
pnDataItemCount = &gClassList.nMachineDataItems;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
// hack for localization: allow a "strings" section at the bottom, if we
|
|
// encounter that then we're thru with parsing
|
|
case KYWD_ID_STRINGSSECT:
|
|
*pfMore = FALSE; // that's all, folks
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ParseEntry
|
|
|
|
SYNOPSIS: Main parsing "engine" for category, policy and part
|
|
parsing
|
|
|
|
NOTES: Allocates memory to build a temporary TABLEENTRY struct
|
|
describing the parsed information. Reads the beginning and end of a
|
|
section and loops through the words in each section, calling
|
|
a caller-defined ParseProc for each keyword to let the
|
|
caller handle appropriately. Passes the newly-constucted
|
|
TABLEENTRY to AddTableEntry to save it, and frees the temporary
|
|
memory.
|
|
This function is re-entrant.
|
|
The ENTRYDATA struct is declared on ParseEntry's stack
|
|
but used by the ParseProc to maintain state between
|
|
calls-- e.g., whether or not a key name has been found.
|
|
This can't be maintained as a static in the ParseProc because
|
|
the ParseProc may be reentered (for instance, if categories
|
|
have subcategories).
|
|
There are many possible error paths and there is some
|
|
memory dealloc that needs to be done in an error case. Rather
|
|
than do deallocs by hand on every error path or use a "goto
|
|
cleanup" (ick!), items to be freed are added to a "cleanup
|
|
list" and then CleanupAndReturn is called in an error condition,
|
|
which frees items on the list and returns a specified value.
|
|
|
|
ENTRY: hWnd-- parent window
|
|
ppes-- PARSEENTRYSTRUCT that specifes type of entry, the
|
|
parent table, a keyword list, a ParseProc callback
|
|
and other goodies
|
|
pfMore-- set to FALSE if at end of file
|
|
|
|
EXIT: ERROR_SUCCESS if successful, otherwise an error code
|
|
(can be ERROR_ALREADY_DISPLAYED)
|
|
|
|
********************************************************************/
|
|
UINT ParseEntry(HWND hWnd,PARSEENTRYSTRUCT *ppes,BOOL *pfMore)
|
|
{
|
|
CHAR szWordBuf[WORDBUFSIZE+1];
|
|
UINT uErr,nListIndex;
|
|
BOOL fFoundEnd = FALSE;
|
|
CLEANUPINFO CleanUp[CLEANLISTSIZE];
|
|
PARSEPROCSTRUCT pps;
|
|
ENTRYDATA EntryData;
|
|
DWORD dwBufSize = DEFAULT_TMP_BUF_SIZE;
|
|
TABLEENTRY *pTmp;
|
|
|
|
memset(CleanUp,0,sizeof(CleanUp));
|
|
memset(&pps,0,sizeof(pps));
|
|
memset(&EntryData,0,sizeof(EntryData));
|
|
|
|
pps.pdwBufSize = &dwBufSize;
|
|
pps.pData = &EntryData;
|
|
pps.pData->fParentHasKey = ppes->fParentHasKey;
|
|
|
|
if (!(pps.pTableEntry = (TABLEENTRY *) GlobalAlloc(GPTR,*pps.pdwBufSize)))
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
AddCleanupItem(CleanUp,CLEANLISTSIZE,(HGLOBAL) pps.pTableEntry,
|
|
CI_FREE);
|
|
|
|
// initialize TABLEENTRY struct
|
|
pps.pTableEntry->dwSize = ppes->dwStructSize;
|
|
pps.pTableEntry->dwType = ppes->dwEntryType;
|
|
pps.pEntryCmpList = ppes->pEntryCmpList;
|
|
pps.hFile = ppes->hFile;
|
|
|
|
// get the entry name
|
|
if (!GetNextSectionWord(hWnd,ppes->hFile,szWordBuf,sizeof(szWordBuf),NULL,NULL,
|
|
pfMore,&uErr))
|
|
return CleanupAndReturn(uErr,CleanUp);
|
|
|
|
// store the entry name in pTableEntry
|
|
pTmp = (TABLEENTRY *) AddDataToEntry(pps.pTableEntry,
|
|
szWordBuf,lstrlen(szWordBuf)+1,&(pps.pTableEntry->uOffsetName),
|
|
pps.pdwBufSize);
|
|
if (!pTmp)
|
|
return CleanupAndReturn(ERROR_NOT_ENOUGH_MEMORY,CleanUp);
|
|
|
|
pps.pTableEntry = pTmp;
|
|
|
|
// loop through the body of the declaration
|
|
while (!fFoundEnd && GetNextSectionWord(hWnd,ppes->hFile,szWordBuf,
|
|
sizeof(szWordBuf),pps.pEntryCmpList,&nListIndex,pfMore,&uErr)) {
|
|
|
|
if ( (uErr = (*ppes->pParseProc) (hWnd,nListIndex,&pps,pfMore,&fFoundEnd))
|
|
!= ERROR_SUCCESS)
|
|
return CleanupAndReturn(uErr,CleanUp);
|
|
|
|
}
|
|
|
|
if (uErr != ERROR_SUCCESS)
|
|
return CleanupAndReturn(uErr,CleanUp);
|
|
|
|
// Last word was "END"
|
|
|
|
// get the keyword that goes with "END" ("END CATGORY", "END POLICY", etc.)
|
|
if (!GetNextSectionWord(hWnd,ppes->hFile,szWordBuf,sizeof(szWordBuf),
|
|
ppes->pTypeCmpList,&nListIndex,pfMore,&uErr))
|
|
return CleanupAndReturn(uErr,CleanUp);
|
|
|
|
// call the object's parse proc one last time to let it object if
|
|
// key name or something like that is missing
|
|
if ( (uErr = (*ppes->pParseProc) (hWnd,KYWD_DONE,&pps,pfMore,&fFoundEnd))
|
|
!= ERROR_SUCCESS)
|
|
return CleanupAndReturn(uErr,CleanUp);
|
|
|
|
// fix up linked list pointers. If parent has no children yet, make this
|
|
// 1st child; otherwise walk the list of children and insert this at the end
|
|
if (!ppes->pParent->pChild) {
|
|
ppes->pParent->pChild = pps.pTableEntry;
|
|
} else {
|
|
TABLEENTRY * pLastChild = ppes->pParent->pChild;
|
|
while (pLastChild->pNext) {
|
|
pLastChild = pLastChild->pNext;
|
|
}
|
|
pLastChild->pNext = pps.pTableEntry;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ParseCategory
|
|
|
|
SYNOPSIS: Parses a category
|
|
|
|
NOTES: Sets up a PARSEENTRYSTRUCT and lets ParseEntry do the
|
|
work.
|
|
|
|
********************************************************************/
|
|
UINT ParseCategory(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
|
|
BOOL fParentHasKey,BOOL *pfMore)
|
|
{
|
|
PARSEENTRYSTRUCT pes;
|
|
|
|
pes.hFile = hFile;
|
|
pes.pParent = pParent;
|
|
pes.dwEntryType = ETYPE_CATEGORY;
|
|
pes.pEntryCmpList = pCategoryEntryCmpList;
|
|
pes.pTypeCmpList = pCategoryTypeCmpList;
|
|
pes.pParseProc = &CategoryParseProc;
|
|
pes.dwStructSize = sizeof(CATEGORY);
|
|
pes.fHasSubtable = TRUE;
|
|
pes.fParentHasKey = fParentHasKey;
|
|
|
|
return ParseEntry(hWnd,&pes,pfMore);
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CategoryParseProc
|
|
|
|
SYNOPSIS: Keyword callback ParseProc for category parsing
|
|
|
|
ENTRY: nMsg-- index into pEntryCmpList array which specifies
|
|
keyword that was found.
|
|
ppps-- pointer to PARSEPROCSTRUCT that contains useful
|
|
data like a pointer to the TABLEENTRY being built
|
|
and a pointer to an ENTRYDATA struct to maintain
|
|
state between calls to the ParseProc
|
|
|
|
********************************************************************/
|
|
UINT CategoryParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
|
|
BOOL * pfMore,BOOL * pfFoundEnd)
|
|
{
|
|
CHAR szWordBuf[WORDBUFSIZE+1];
|
|
CATEGORY * pCategory = (CATEGORY *) ppps->pTableEntry;
|
|
TABLEENTRY * pOld = ppps->pTableEntry;
|
|
UINT uErr;
|
|
DWORD dwDelta;
|
|
TABLEENTRY *pTmp;
|
|
|
|
switch (nMsg) {
|
|
case KYWD_ID_KEYNAME:
|
|
|
|
// have we already found a key name?
|
|
if (ppps->pData->fHasKey) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_KEYNAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
// get the key name
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
// store the key name in pCategory
|
|
pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pCategory,
|
|
szWordBuf,lstrlen(szWordBuf)+1,&(pCategory->uOffsetKeyName),
|
|
ppps->pdwBufSize);
|
|
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ppps->pTableEntry = pTmp;
|
|
|
|
// fix up other pointers
|
|
dwDelta = (DWORD)(ppps->pTableEntry - pOld);
|
|
|
|
ppps->pData->fHasKey = TRUE;
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_END:
|
|
*pfFoundEnd = TRUE;
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_POLICY:
|
|
case KYWD_ID_CATEGORY:
|
|
|
|
{
|
|
BOOL fHasKey = ppps->pData->fHasKey | ppps->pData->fParentHasKey;
|
|
if (nMsg == KYWD_ID_POLICY)
|
|
uErr=ParsePolicy(hWnd,ppps->hFile,
|
|
(TABLEENTRY *) pCategory,fHasKey,pfMore);
|
|
else
|
|
uErr=ParseCategory(hWnd,ppps->hFile,
|
|
(TABLEENTRY *) pCategory,fHasKey,pfMore);
|
|
}
|
|
|
|
return uErr;
|
|
break;
|
|
|
|
case KYWD_DONE:
|
|
#if 0
|
|
if (!ppps->pData->fHasKey) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_KEYNAME,NULL,NULL,
|
|
pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
#endif
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ParsePolicy
|
|
|
|
SYNOPSIS: Parses a policy
|
|
|
|
NOTES: Sets up a PARSEENTRYSTRUCT and lets ParseEntry do the
|
|
work.
|
|
|
|
********************************************************************/
|
|
UINT ParsePolicy(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
|
|
BOOL fParentHasKey,BOOL *pfMore)
|
|
{
|
|
PARSEENTRYSTRUCT pes;
|
|
|
|
pes.hFile = hFile;
|
|
pes.pParent = pParent;
|
|
pes.dwEntryType = ETYPE_POLICY;
|
|
pes.pEntryCmpList = pPolicyEntryCmpList;
|
|
pes.pTypeCmpList = pPolicyTypeCmpList;
|
|
pes.pParseProc = &PolicyParseProc;
|
|
pes.dwStructSize = sizeof(POLICY);
|
|
pes.fHasSubtable = TRUE;
|
|
pes.fParentHasKey = fParentHasKey;
|
|
|
|
return ParseEntry(hWnd,&pes,pfMore);
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: PolicyParseProc
|
|
|
|
SYNOPSIS: Keyword callback ParseProc for policy parsing
|
|
|
|
ENTRY: nMsg-- index into pEntryCmpList array which specifies
|
|
keyword that was found.
|
|
ppps-- pointer to PARSEPROCSTRUCT that contains useful
|
|
data like a pointer to the TABLEENTRY being built
|
|
and a pointer to an ENTRYDATA struct to maintain
|
|
state between calls to the ParseProc
|
|
|
|
********************************************************************/
|
|
UINT PolicyParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
|
|
BOOL * pfMore,BOOL * pfFoundEnd)
|
|
{
|
|
CHAR szWordBuf[WORDBUFSIZE+1];
|
|
LPTSTR lpHelpBuf;
|
|
POLICY * pPolicy = (POLICY *) ppps->pTableEntry;
|
|
TABLEENTRY * pOld = ppps->pTableEntry;
|
|
UINT uErr;
|
|
DWORD dwDelta;
|
|
TABLEENTRY *pTmp;
|
|
|
|
switch (nMsg) {
|
|
case KYWD_ID_KEYNAME:
|
|
|
|
// have we already found a key name?
|
|
if (ppps->pData->fHasKey) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_KEYNAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
// get the key name
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
// store the key name in pPolicy
|
|
pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pPolicy,
|
|
szWordBuf,lstrlen(szWordBuf)+1,&(pPolicy->uOffsetKeyName),ppps->pdwBufSize);
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ppps->pTableEntry = pTmp;
|
|
|
|
// fix up other pointers
|
|
dwDelta = (DWORD)(ppps->pTableEntry - pOld);
|
|
|
|
ppps->pData->fHasKey = TRUE;
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_VALUENAME:
|
|
|
|
// have we already found a key name?
|
|
if (ppps->pData->fHasValue) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_VALUENAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
// get the key name
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
// store the key name in pSettings
|
|
pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pPolicy,
|
|
szWordBuf,lstrlen(szWordBuf)+1,&(pPolicy->uOffsetValueName),
|
|
ppps->pdwBufSize);
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ppps->pTableEntry = pTmp;
|
|
// fix up other pointers
|
|
dwDelta = (DWORD)(ppps->pTableEntry - pOld);
|
|
|
|
ppps->pData->fHasValue = TRUE;
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
case KYWD_ID_HELP:
|
|
|
|
lpHelpBuf = (LPTSTR) LocalAlloc (LPTR, HELPBUFSIZE * sizeof(TCHAR));
|
|
|
|
if (!lpHelpBuf) {
|
|
DisplayKeywordError(hWnd,IDS_ErrOUTOFMEMORY,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
// get the help string
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,lpHelpBuf,HELPBUFSIZE,
|
|
NULL,NULL,pfMore,&uErr)) {
|
|
LocalFree (lpHelpBuf);
|
|
return uErr;
|
|
}
|
|
|
|
LocalFree (lpHelpBuf);
|
|
return ERROR_SUCCESS;
|
|
|
|
case KYWD_ID_CLIENTEXT:
|
|
|
|
// get the clientext name
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
case KYWD_ID_END:
|
|
*pfFoundEnd = TRUE;
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_PART:
|
|
{
|
|
BOOL fHasKey = ppps->pData->fHasKey | ppps->pData->fParentHasKey;
|
|
return ParseSettings(hWnd,ppps->hFile,
|
|
(TABLEENTRY *) pPolicy,fHasKey,pfMore);
|
|
}
|
|
break;
|
|
|
|
case KYWD_ID_VALUEON:
|
|
return ParseValue(hWnd,ppps,&pPolicy->uOffsetValue_On,
|
|
&ppps->pTableEntry,pfMore);
|
|
break;
|
|
|
|
case KYWD_ID_VALUEOFF:
|
|
|
|
return ParseValue(hWnd,ppps,&pPolicy->uOffsetValue_Off,
|
|
&ppps->pTableEntry,pfMore);
|
|
break;
|
|
|
|
case KYWD_ID_ACTIONLISTON:
|
|
return ParseActionList(hWnd,ppps,&pPolicy->uOffsetActionList_On,
|
|
&ppps->pTableEntry,szACTIONLISTON,pfMore);
|
|
break;
|
|
|
|
case KYWD_ID_ACTIONLISTOFF:
|
|
return ParseActionList(hWnd,ppps,&pPolicy->uOffsetActionList_Off,
|
|
&ppps->pTableEntry,szACTIONLISTOFF,pfMore);
|
|
break;
|
|
|
|
case KYWD_DONE:
|
|
|
|
if (!ppps->pData->fHasKey && !ppps->pData->fParentHasKey) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_KEYNAME,NULL,NULL,
|
|
pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
( (POLICY *) ppps->pTableEntry)->uDataIndex = *pnDataItemCount;
|
|
(*pnDataItemCount) ++;
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
default:
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: ParseSettings
|
|
|
|
SYNOPSIS: Parses a policy setting
|
|
|
|
NOTES: Sets up a PARSEENTRYSTRUCT and lets ParseEntry do the
|
|
work.
|
|
|
|
********************************************************************/
|
|
UINT ParseSettings(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
|
|
BOOL fParentHasKey,BOOL *pfMore)
|
|
{
|
|
PARSEENTRYSTRUCT pes;
|
|
|
|
pes.hFile = hFile;
|
|
pes.pParent = pParent;
|
|
pes.dwEntryType = ETYPE_SETTING;
|
|
pes.pEntryCmpList = pSettingsEntryCmpList;
|
|
pes.pTypeCmpList = pSettingsTypeCmpList;
|
|
pes.pParseProc = &SettingsParseProc;
|
|
pes.dwStructSize = sizeof(SETTINGS);
|
|
pes.fHasSubtable = FALSE;
|
|
pes.fParentHasKey = fParentHasKey;
|
|
|
|
return ParseEntry(hWnd,&pes,pfMore);
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: SettingsParseProc
|
|
|
|
SYNOPSIS: Keyword callback ParseProc for policy settings parsing
|
|
|
|
ENTRY: nMsg-- index into pEntryCmpList array which specifies
|
|
keyword that was found.
|
|
ppps-- pointer to PARSEPROCSTRUCT that contains useful
|
|
data like a pointer to the TABLEENTRY being built
|
|
and a pointer to an ENTRYDATA struct to maintain
|
|
state between calls to the ParseProc
|
|
|
|
********************************************************************/
|
|
UINT SettingsParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
|
|
BOOL * pfMore,BOOL * pfFoundEnd)
|
|
{
|
|
CHAR szWordBuf[WORDBUFSIZE+1];
|
|
TABLEENTRY *pTmp;
|
|
|
|
SETTINGS * pSettings = (SETTINGS *) ppps->pTableEntry;
|
|
CHAR * pObjectData = GETOBJECTDATAPTR(pSettings);
|
|
|
|
UINT uErr;
|
|
|
|
switch (nMsg) {
|
|
case KYWD_ID_KEYNAME:
|
|
|
|
// have we already found a key name?
|
|
if (ppps->pData->fHasKey) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_KEYNAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
// get the key name
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
// store the key name in pSettings
|
|
pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pSettings,
|
|
szWordBuf,lstrlen(szWordBuf)+1,&(pSettings->uOffsetKeyName),ppps->pdwBufSize);
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ppps->pTableEntry = pTmp;
|
|
ppps->pData->fHasKey = TRUE;
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_VALUENAME:
|
|
|
|
// have we already found a value name?
|
|
if (ppps->pData->fHasValue) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_VALUENAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
// get the value name
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
// store the value name in pSettings
|
|
pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pSettings,
|
|
szWordBuf,lstrlen(szWordBuf)+1,&(pSettings->uOffsetValueName),
|
|
ppps->pdwBufSize);
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
ppps->pTableEntry = pTmp;
|
|
ppps->pData->fHasValue = TRUE;
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_CLIENTEXT:
|
|
|
|
// get the clientext name
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
case KYWD_ID_REQUIRED:
|
|
pSettings->dwFlags |= DF_REQUIRED;
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_EXPANDABLETEXT:
|
|
pSettings->dwFlags |= DF_EXPANDABLETEXT;
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_SUGGESTIONS:
|
|
|
|
return ParseSuggestions(hWnd,ppps,&((POLICYCOMBOBOXINFO *)
|
|
(GETOBJECTDATAPTR(pSettings)))->uOffsetSuggestions,
|
|
&ppps->pTableEntry,pfMore);
|
|
|
|
case KYWD_ID_TXTCONVERT:
|
|
pSettings->dwFlags |= DF_TXTCONVERT;
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_END:
|
|
*pfFoundEnd = TRUE;
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_SOFT:
|
|
pSettings->dwFlags |= VF_SOFT;
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_DONE:
|
|
|
|
if (!ppps->pData->fHasKey && !ppps->pData->fParentHasKey) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_KEYNAME,NULL,NULL,
|
|
pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
if (!ppps->pData->fHasValue) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_VALUENAME,NULL,NULL,
|
|
pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
( (SETTINGS *) ppps->pTableEntry)->uDataIndex = *pnDataItemCount;
|
|
(*pnDataItemCount) ++;
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_CHECKBOX:
|
|
return (InitSettingsParse(ppps,ETYPE_SETTING | STYPE_CHECKBOX,
|
|
sizeof(CHECKBOXINFO),pCheckboxCmpList,&pSettings,&pObjectData));
|
|
break;
|
|
|
|
case KYWD_ID_TEXT:
|
|
ppps->pData->fHasValue = TRUE; // no key value for static text items
|
|
return (InitSettingsParse(ppps,ETYPE_SETTING | STYPE_TEXT,
|
|
0,pTextCmpList,&pSettings,&pObjectData));
|
|
break;
|
|
|
|
case KYWD_ID_EDITTEXT:
|
|
uErr=InitSettingsParse(ppps,ETYPE_SETTING | STYPE_EDITTEXT,
|
|
sizeof(EDITTEXTINFO),pEditTextCmpList,&pSettings,&pObjectData);
|
|
if (uErr != ERROR_SUCCESS) return uErr;
|
|
{
|
|
EDITTEXTINFO *pEditTextInfo = (EDITTEXTINFO *)
|
|
(GETOBJECTDATAPTR(((SETTINGS *) ppps->pTableEntry)));
|
|
|
|
pEditTextInfo->nMaxLen = MAXSTRLEN;
|
|
|
|
}
|
|
break;
|
|
|
|
case KYWD_ID_COMBOBOX:
|
|
uErr=InitSettingsParse(ppps,ETYPE_SETTING | STYPE_COMBOBOX,
|
|
sizeof(POLICYCOMBOBOXINFO),pComboboxCmpList,&pSettings,&pObjectData);
|
|
if (uErr != ERROR_SUCCESS) return uErr;
|
|
{
|
|
EDITTEXTINFO *pEditTextInfo = (EDITTEXTINFO *)
|
|
(GETOBJECTDATAPTR(((SETTINGS *) ppps->pTableEntry)));
|
|
|
|
pEditTextInfo->nMaxLen = MAXSTRLEN;
|
|
|
|
}
|
|
break;
|
|
|
|
case KYWD_ID_NUMERIC:
|
|
uErr=InitSettingsParse(ppps,ETYPE_SETTING | STYPE_NUMERIC,
|
|
sizeof(NUMERICINFO),pNumericCmpList,&pSettings,&pObjectData);
|
|
if (uErr != ERROR_SUCCESS) return uErr;
|
|
|
|
( (NUMERICINFO *) pObjectData)->uDefValue = 1;
|
|
( (NUMERICINFO *) pObjectData)->uMinValue = 1;
|
|
( (NUMERICINFO *) pObjectData)->uMaxValue = 9999;
|
|
( (NUMERICINFO *) pObjectData)->uSpinIncrement = 1;
|
|
|
|
break;
|
|
|
|
case KYWD_ID_DROPDOWNLIST:
|
|
ppps->pEntryCmpList = pDropdownlistCmpList;
|
|
ppps->pTableEntry->dwType = ETYPE_SETTING | STYPE_DROPDOWNLIST;
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_LISTBOX:
|
|
uErr=InitSettingsParse(ppps,ETYPE_SETTING | STYPE_LISTBOX,
|
|
sizeof(LISTBOXINFO),pListboxCmpList,&pSettings,&pObjectData);
|
|
if (uErr != ERROR_SUCCESS) return uErr;
|
|
|
|
// listboxes have no single value name, set the value name to ""
|
|
pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pSettings,
|
|
(CHAR *) szNull,lstrlen(szNull)+1,&(pSettings->uOffsetValueName),
|
|
ppps->pdwBufSize);
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
ppps->pTableEntry = pTmp;
|
|
ppps->pData->fHasValue = TRUE;
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_EDITTEXT_DEFAULT:
|
|
case KYWD_ID_COMBOBOX_DEFAULT:
|
|
// get the default text
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
// store the default text in pTableEntry
|
|
pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *)
|
|
pSettings,szWordBuf,lstrlen(szWordBuf)+1,
|
|
&((EDITTEXTINFO *) (GETOBJECTDATAPTR(pSettings)))->uOffsetDefText,
|
|
ppps->pdwBufSize);
|
|
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
ppps->pTableEntry = pTmp;
|
|
pSettings->dwFlags |= DF_USEDEFAULT;
|
|
|
|
break;
|
|
|
|
case KYWD_ID_MAXLENGTH:
|
|
{
|
|
EDITTEXTINFO *pEditTextInfo = (EDITTEXTINFO *)
|
|
(GETOBJECTDATAPTR(pSettings));
|
|
|
|
if ((uErr=GetNextSectionNumericWord(hWnd,ppps->hFile,
|
|
&pEditTextInfo->nMaxLen)) != ERROR_SUCCESS)
|
|
return uErr;
|
|
}
|
|
break;
|
|
|
|
case KYWD_ID_MAX:
|
|
if ((uErr=GetNextSectionNumericWord(hWnd,ppps->hFile,
|
|
&((NUMERICINFO *)pObjectData)->uMaxValue)) != ERROR_SUCCESS)
|
|
return uErr;
|
|
break;
|
|
|
|
case KYWD_ID_MIN:
|
|
if ((uErr=GetNextSectionNumericWord(hWnd,ppps->hFile,
|
|
&((NUMERICINFO *)pObjectData)->uMinValue)) != ERROR_SUCCESS)
|
|
return uErr;
|
|
break;
|
|
|
|
case KYWD_ID_SPIN:
|
|
if ((uErr=GetNextSectionNumericWord(hWnd,ppps->hFile,
|
|
&((NUMERICINFO *)pObjectData)->uSpinIncrement)) != ERROR_SUCCESS)
|
|
return uErr;
|
|
break;
|
|
|
|
case KYWD_ID_NUMERIC_DEFAULT:
|
|
if ((uErr=GetNextSectionNumericWord(hWnd,ppps->hFile,
|
|
&((NUMERICINFO *)pObjectData)->uDefValue)) != ERROR_SUCCESS)
|
|
return uErr;
|
|
|
|
pSettings->dwFlags |= (DF_DEFCHECKED | DF_USEDEFAULT);
|
|
|
|
break;
|
|
|
|
case KYWD_ID_DEFCHECKED:
|
|
|
|
pSettings->dwFlags |= (DF_DEFCHECKED | DF_USEDEFAULT);
|
|
|
|
break;
|
|
|
|
case KYWD_ID_VALUEON:
|
|
|
|
return ParseValue(hWnd,ppps,&((CHECKBOXINFO *)
|
|
pObjectData)->uOffsetValue_On,
|
|
&ppps->pTableEntry,pfMore);
|
|
break;
|
|
|
|
case KYWD_ID_VALUEOFF:
|
|
|
|
return ParseValue(hWnd,ppps,&((CHECKBOXINFO *)
|
|
pObjectData)->uOffsetValue_Off,
|
|
&ppps->pTableEntry,pfMore);
|
|
break;
|
|
|
|
case KYWD_ID_ACTIONLISTON:
|
|
return ParseActionList(hWnd,ppps,&((CHECKBOXINFO *)
|
|
pObjectData)->uOffsetActionList_On,
|
|
&ppps->pTableEntry,szACTIONLISTON,pfMore);
|
|
break;
|
|
|
|
case KYWD_ID_ACTIONLISTOFF:
|
|
return ParseActionList(hWnd,ppps,&((CHECKBOXINFO *)
|
|
pObjectData)->uOffsetActionList_Off,
|
|
&ppps->pTableEntry,szACTIONLISTOFF,pfMore);
|
|
break;
|
|
|
|
case KYWD_ID_ITEMLIST:
|
|
return ParseItemList(hWnd,ppps,&pSettings->uOffsetObjectData,
|
|
pfMore);
|
|
break;
|
|
|
|
case KYWD_ID_VALUEPREFIX:
|
|
// get the string to be ised as prefix
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
// store the string pTableEntry
|
|
pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *)
|
|
pSettings,szWordBuf,lstrlen(szWordBuf)+1,
|
|
&((LISTBOXINFO *) (GETOBJECTDATAPTR(pSettings)))->uOffsetPrefix,
|
|
ppps->pdwBufSize);
|
|
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
ppps->pTableEntry = pTmp;
|
|
break;
|
|
|
|
case KYWD_ID_ADDITIVE:
|
|
|
|
pSettings->dwFlags |= DF_ADDITIVE;
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_EXPLICITVALUE:
|
|
|
|
pSettings->dwFlags |= DF_EXPLICITVALNAME;
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
|
|
case KYWD_ID_NOSORT:
|
|
|
|
pSettings->dwFlags |= DF_NOSORT;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
UINT InitSettingsParse(PARSEPROCSTRUCT *ppps,DWORD dwType,DWORD dwSize,
|
|
KEYWORDINFO * pKeyList,SETTINGS ** ppSettings,CHAR **ppObjectData)
|
|
{
|
|
TABLEENTRY *pTmp;
|
|
|
|
if (dwSize) {
|
|
// increase the buffer to fit object-specific data if specified
|
|
pTmp = (TABLEENTRY *) AddDataToEntry(ppps->pTableEntry,
|
|
NULL,dwSize,&( ((SETTINGS * )ppps->pTableEntry)->uOffsetObjectData),
|
|
ppps->pdwBufSize);
|
|
if (!pTmp) return ERROR_NOT_ENOUGH_MEMORY;
|
|
ppps->pTableEntry = pTmp;
|
|
}
|
|
else ( (SETTINGS *) ppps->pTableEntry)->uOffsetObjectData= 0;
|
|
|
|
ppps->pEntryCmpList = pKeyList;
|
|
ppps->pTableEntry->dwType = dwType;
|
|
|
|
*ppSettings = (SETTINGS *) ppps->pTableEntry;
|
|
*ppObjectData = GETOBJECTDATAPTR((*ppSettings));
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
UINT ParseValue_W(HWND hWnd,PARSEPROCSTRUCT * ppps,CHAR * pszWordBuf,
|
|
DWORD cbWordBuf,DWORD * pdwValue,DWORD * pdwFlags,BOOL * pfMore)
|
|
{
|
|
UINT uErr;
|
|
*pdwFlags = 0;
|
|
*pdwValue = 0;
|
|
|
|
// get the next word
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,pszWordBuf,cbWordBuf,
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
// if this keyword is "SOFT", set the soft flag and get the next word
|
|
if (!lstrcmpi(szSOFT,pszWordBuf)) {
|
|
*pdwFlags |= VF_SOFT;
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,pszWordBuf,cbWordBuf,
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
}
|
|
|
|
// this word is either the value to use, or the keyword "NUMERIC"
|
|
// followed by a numeric value to use
|
|
if (!lstrcmpi(szNUMERIC,pszWordBuf)) {
|
|
// get the next word
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,pszWordBuf,cbWordBuf,
|
|
NULL,NULL,pfMore,&uErr))
|
|
return uErr;
|
|
|
|
if (!StringToNum(pszWordBuf,pdwValue)) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NOT_NUMERIC,
|
|
pszWordBuf,NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
*pdwFlags |= VF_ISNUMERIC;
|
|
} else {
|
|
|
|
// "DELETE" is a special word
|
|
if (!lstrcmpi(pszWordBuf,szDELETE))
|
|
*pdwFlags |= VF_DELETE;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
UINT ParseValue(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
|
|
TABLEENTRY ** ppTableEntryNew,BOOL * pfMore)
|
|
{
|
|
CHAR szWordBuf[WORDBUFSIZE+1];
|
|
STATEVALUE * pStateValue;
|
|
DWORD dwValue;
|
|
DWORD dwFlags = 0;
|
|
DWORD dwAlloc;
|
|
UINT uErr;
|
|
TABLEENTRY *pTmp;
|
|
|
|
// call worker function
|
|
uErr=ParseValue_W(hWnd,ppps,szWordBuf,sizeof(szWordBuf),&dwValue,
|
|
&dwFlags,pfMore);
|
|
if (uErr != ERROR_SUCCESS) return uErr;
|
|
|
|
dwAlloc = sizeof(STATEVALUE);
|
|
if (!dwFlags) dwAlloc += lstrlen(szWordBuf) + 1;
|
|
|
|
// allocate temporary buffer to build STATEVALUE struct
|
|
pStateValue = (STATEVALUE *) GlobalAlloc(GPTR,dwAlloc);
|
|
if (!pStateValue)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
pStateValue->dwFlags = dwFlags;
|
|
if (dwFlags & VF_ISNUMERIC)
|
|
pStateValue->dwValue = dwValue;
|
|
else if (!dwFlags) {
|
|
lstrcpy(pStateValue->szValue,szWordBuf);
|
|
}
|
|
|
|
pTmp=(TABLEENTRY *) AddDataToEntry(ppps->pTableEntry,
|
|
(CHAR *) pStateValue,dwAlloc,puOffsetData,NULL);
|
|
|
|
GlobalFree(pStateValue);
|
|
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
(*ppTableEntryNew) = pTmp;
|
|
return FALSE;
|
|
}
|
|
|
|
#define DEF_SUGGESTBUF_SIZE 1024
|
|
#define SUGGESTBUF_INCREMENT 256
|
|
UINT ParseSuggestions(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
|
|
TABLEENTRY ** ppTableEntryNew,BOOL * pfMore)
|
|
{
|
|
CHAR szWordBuf[WORDBUFSIZE+1];
|
|
CHAR *pTmpBuf, *pTmp;
|
|
DWORD dwAlloc=DEF_SUGGESTBUF_SIZE;
|
|
DWORD dwUsed = 0;
|
|
BOOL fContinue = TRUE;
|
|
UINT uErr;
|
|
TABLEENTRY *pTmpTblEntry;
|
|
KEYWORDINFO pSuggestionsTypeCmpList[] = { {szSUGGESTIONS,KYWD_ID_SUGGESTIONS},
|
|
{NULL,0} };
|
|
|
|
if (!(pTmpBuf = (CHAR *) GlobalAlloc(GPTR,dwAlloc)))
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
// get the next word
|
|
while (fContinue && GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,
|
|
sizeof(szWordBuf),NULL,NULL,pfMore,&uErr)) {
|
|
|
|
// if this word is "END", add the whole list to the setting object data
|
|
if (!lstrcmpi(szEND,szWordBuf)) {
|
|
// get the next word after "END, make sure it's "SUGGESTIONS"
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
pSuggestionsTypeCmpList,NULL,pfMore,&uErr)) {
|
|
GlobalFree(pTmpBuf);
|
|
return uErr;
|
|
}
|
|
|
|
// doubly-NULL terminate the list
|
|
*(pTmpBuf+dwUsed) = '\0';
|
|
dwUsed++;
|
|
|
|
pTmpTblEntry=(TABLEENTRY *)AddDataToEntry(ppps->pTableEntry,
|
|
pTmpBuf,dwUsed,puOffsetData,NULL);
|
|
|
|
if (!pTmpTblEntry) {
|
|
GlobalFree(pTmpBuf);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
*ppTableEntryNew=pTmpTblEntry;
|
|
fContinue = FALSE;
|
|
|
|
} else {
|
|
// pack the word into the temporary buffer
|
|
UINT nLength = lstrlen(szWordBuf);
|
|
DWORD dwNeeded = dwUsed + nLength + 2;
|
|
|
|
// resize buffer as necessary
|
|
if (dwNeeded > dwAlloc) {
|
|
while (dwAlloc < dwNeeded)
|
|
dwAlloc += SUGGESTBUF_INCREMENT;
|
|
if (!(pTmp = (CHAR *) GlobalReAlloc(pTmpBuf,dwAlloc,
|
|
GMEM_MOVEABLE | GMEM_ZEROINIT))) {
|
|
GlobalFree(pTmpBuf);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
pTmpBuf = pTmp;
|
|
}
|
|
|
|
lstrcpy(pTmpBuf + dwUsed,szWordBuf);
|
|
dwUsed += lstrlen(szWordBuf) +1;
|
|
|
|
}
|
|
}
|
|
|
|
GlobalFree(pTmpBuf);
|
|
|
|
return uErr;
|
|
}
|
|
|
|
UINT ParseActionList(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
|
|
TABLEENTRY ** ppTableEntryNew,LPCSTR pszKeyword,BOOL * pfMore)
|
|
{
|
|
CHAR szWordBuf[WORDBUFSIZE+1];
|
|
ACTIONLIST *pActionList;
|
|
ACTION *pActionCurrent;
|
|
UINT uOffsetActionCurrent;
|
|
DWORD dwAlloc=DEF_SUGGESTBUF_SIZE;
|
|
DWORD dwUsed = sizeof(ACTION) + sizeof(UINT);
|
|
UINT uErr=ERROR_SUCCESS,nIndex;
|
|
BOOL fContinue = TRUE;
|
|
KEYWORDINFO pActionlistTypeCmpList[] = { {szKEYNAME,KYWD_ID_KEYNAME},
|
|
{szVALUENAME,KYWD_ID_VALUENAME},{szVALUE,KYWD_ID_VALUE},
|
|
{szEND,KYWD_ID_END},{NULL,0} };
|
|
KEYWORDINFO pActionlistCmpList[] = { {pszKeyword,KYWD_ID_ACTIONLIST},
|
|
{NULL,0} };
|
|
BOOL fHasKeyName=FALSE,fHasValueName=FALSE;
|
|
BOOL AddActionListString(CHAR * pszData,DWORD cbData,CHAR ** ppBase,UINT * puOffset,
|
|
DWORD * pdwAlloc,DWORD * pdwUsed);
|
|
TABLEENTRY *pTmp;
|
|
|
|
if (!(pActionList = (ACTIONLIST *) GlobalAlloc(GPTR,dwAlloc)))
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
pActionCurrent = pActionList->Action;
|
|
uOffsetActionCurrent = sizeof(UINT);
|
|
|
|
// get the next word
|
|
while ((uErr == ERROR_SUCCESS) && fContinue &&
|
|
GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
pActionlistTypeCmpList,&nIndex,pfMore,&uErr)) {
|
|
|
|
switch (nIndex) {
|
|
|
|
case KYWD_ID_KEYNAME:
|
|
|
|
if (fHasKeyName) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_KEYNAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
|
|
// get the next word, which is the key name
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,
|
|
sizeof(szWordBuf),NULL,NULL,pfMore,&uErr))
|
|
break;
|
|
|
|
// store the key name away
|
|
if (!AddActionListString(szWordBuf,lstrlen(szWordBuf)+1,
|
|
(CHAR **)&pActionList,
|
|
&pActionCurrent->uOffsetKeyName,&dwAlloc,&dwUsed)) {
|
|
uErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
fHasKeyName = TRUE;
|
|
pActionCurrent = (ACTION *) ((CHAR *) pActionList + uOffsetActionCurrent);
|
|
|
|
break;
|
|
|
|
case KYWD_ID_VALUENAME:
|
|
|
|
if (fHasValueName) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_KEYNAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
|
|
// get the next word, which is the value name
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,
|
|
sizeof(szWordBuf),NULL,NULL,pfMore,&uErr))
|
|
break;
|
|
|
|
// store the value name away
|
|
if (!AddActionListString(szWordBuf,lstrlen(szWordBuf)+1,
|
|
(CHAR **)&pActionList,
|
|
&pActionCurrent->uOffsetValueName,&dwAlloc,&dwUsed)) {
|
|
uErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
|
|
fHasValueName = TRUE;
|
|
pActionCurrent = (ACTION *) ((CHAR *) pActionList + uOffsetActionCurrent);
|
|
|
|
break;
|
|
|
|
case KYWD_ID_VALUE:
|
|
if (!fHasValueName) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_VALUENAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
|
|
// call worker function to get value and value type
|
|
uErr=ParseValue_W(hWnd,ppps,szWordBuf,sizeof(szWordBuf),
|
|
&pActionCurrent->dwValue,&pActionCurrent->dwFlags,pfMore);
|
|
if (uErr != ERROR_SUCCESS)
|
|
break;
|
|
|
|
// if value is string, add it to buffer
|
|
if (!pActionCurrent->dwFlags && !AddActionListString(szWordBuf,
|
|
lstrlen(szWordBuf)+1,(CHAR **)&pActionList,
|
|
&pActionCurrent->uOffsetValue,&dwAlloc,&dwUsed)) {
|
|
uErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
pActionCurrent = (ACTION *) ((CHAR *) pActionList + uOffsetActionCurrent);
|
|
|
|
// done with this action in the list, get ready for the next one
|
|
pActionList->nActionItems++;
|
|
fHasValueName = fHasKeyName = FALSE;
|
|
|
|
uOffsetActionCurrent = dwUsed;
|
|
// make room for next ACTION struct
|
|
if (!AddActionListString(NULL,sizeof(ACTION),(CHAR **)&pActionList,
|
|
&pActionCurrent->uOffsetNextAction,&dwAlloc,&dwUsed)) {
|
|
uErr = ERROR_NOT_ENOUGH_MEMORY;
|
|
break;
|
|
}
|
|
pActionCurrent = (ACTION *) ((CHAR *) pActionList + uOffsetActionCurrent);
|
|
|
|
break;
|
|
|
|
case KYWD_ID_END:
|
|
if (fHasKeyName || fHasValueName) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_VALUENAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
|
|
// make sure word following "END" is "ACTIONLIST"
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
pActionlistCmpList,NULL,pfMore,&uErr)) {
|
|
break;
|
|
}
|
|
|
|
// commit the action list we've built to table entry
|
|
|
|
pTmp=(TABLEENTRY *)AddDataToEntry(ppps->pTableEntry,
|
|
(CHAR *)pActionList,dwUsed,puOffsetData,NULL);
|
|
|
|
if (!pTmp) {
|
|
uErr=ERROR_NOT_ENOUGH_MEMORY;
|
|
} else {
|
|
uErr = ERROR_SUCCESS;
|
|
*ppTableEntryNew = pTmp;
|
|
fContinue = FALSE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
GlobalFree(pActionList);
|
|
|
|
return uErr;
|
|
}
|
|
|
|
UINT ParseItemList(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
|
|
BOOL * pfMore)
|
|
{
|
|
// ptr to location to put the offset to next DROPDOWNINFO struct in chain
|
|
UINT * puLastOffsetPtr = puOffsetData;
|
|
TABLEENTRY * pTableEntryOld;
|
|
TABLEENTRY *pTmp;
|
|
int nItemIndex=-1;
|
|
BOOL fHasItemName = FALSE,fHasActionList=FALSE,fHasValue=FALSE,fFirst=TRUE;
|
|
DROPDOWNINFO * pddi;
|
|
CHAR szWordBuf[WORDBUFSIZE+1];
|
|
UINT uErr=ERROR_SUCCESS,nIndex;
|
|
KEYWORDINFO pItemlistTypeCmpList[] = { {szNAME,KYWD_ID_NAME},
|
|
{szACTIONLIST,KYWD_ID_ACTIONLIST},{szVALUE,KYWD_ID_VALUE},
|
|
{szEND,KYWD_ID_END},{szDEFAULT,KYWD_ID_DEFAULT},{NULL,0} };
|
|
KEYWORDINFO pItemlistCmpList[] = { {szITEMLIST,KYWD_ID_ITEMLIST},
|
|
{NULL,0} };
|
|
|
|
// get the next word
|
|
while ((uErr == ERROR_SUCCESS) &&
|
|
GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
pItemlistTypeCmpList,&nIndex,pfMore,&uErr)) {
|
|
|
|
switch (nIndex) {
|
|
|
|
case KYWD_ID_NAME:
|
|
|
|
// if this is the first keyword after a prior item
|
|
// (e.g., item and value flags both set) reset for next one
|
|
if (fHasItemName && fHasValue) {
|
|
fHasValue = fHasActionList= fHasItemName = FALSE;
|
|
puLastOffsetPtr = &pddi->uOffsetNextDropdowninfo;
|
|
}
|
|
|
|
if (fHasItemName) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_ITEMNAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
|
|
// get the next word, which is the item name
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,
|
|
sizeof(szWordBuf),NULL,NULL,pfMore,&uErr))
|
|
break;
|
|
|
|
// add room for a DROPDOWNINFO struct at end of buffer
|
|
pTableEntryOld=ppps->pTableEntry;
|
|
pTmp=(TABLEENTRY *)AddDataToEntry(ppps->pTableEntry,
|
|
NULL,sizeof(DROPDOWNINFO),puLastOffsetPtr,NULL);
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
ppps->pTableEntry=pTmp;
|
|
// adjust pointer to offset, in case table moved
|
|
puLastOffsetPtr = (UINT *) (((BYTE *) puLastOffsetPtr) +
|
|
((BYTE *) ppps->pTableEntry - (BYTE *) pTableEntryOld));
|
|
pddi = (DROPDOWNINFO *)
|
|
((CHAR *) ppps->pTableEntry + *puLastOffsetPtr);
|
|
|
|
// store the key name away
|
|
pTableEntryOld=ppps->pTableEntry;
|
|
pTmp=(TABLEENTRY *)AddDataToEntry(ppps->pTableEntry,
|
|
szWordBuf,lstrlen(szWordBuf)+1,&pddi->uOffsetItemName,
|
|
NULL);
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
ppps->pTableEntry = pTmp;
|
|
// adjust pointer to offset, in case table moved
|
|
puLastOffsetPtr = (UINT *) (((BYTE *) puLastOffsetPtr) +
|
|
((BYTE *) ppps->pTableEntry - (BYTE *) pTableEntryOld));
|
|
pddi = (DROPDOWNINFO *)
|
|
((CHAR *) ppps->pTableEntry + *puLastOffsetPtr);
|
|
|
|
nItemIndex++;
|
|
|
|
fHasItemName = TRUE;
|
|
|
|
break;
|
|
|
|
case KYWD_ID_DEFAULT:
|
|
|
|
if (nItemIndex<0) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_ITEMNAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
|
|
( (SETTINGS *) ppps->pTableEntry)->dwFlags |= DF_USEDEFAULT;
|
|
( (DROPDOWNINFO *) GETOBJECTDATAPTR(((SETTINGS *)ppps->pTableEntry)))
|
|
->uDefaultItemIndex = nItemIndex;
|
|
|
|
break;
|
|
|
|
case KYWD_ID_VALUE:
|
|
|
|
if (!fHasItemName) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_ITEMNAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
|
|
// call worker function to get value and value type
|
|
uErr=ParseValue_W(hWnd,ppps,szWordBuf,sizeof(szWordBuf),
|
|
&pddi->dwValue,&pddi->dwFlags,pfMore);
|
|
if (uErr != ERROR_SUCCESS)
|
|
break;
|
|
|
|
// if value is string, add it to buffer
|
|
if (!pddi->dwFlags) {
|
|
// store the key name away
|
|
pTableEntryOld = ppps->pTableEntry;
|
|
pTmp=(TABLEENTRY *) AddDataToEntry(ppps->pTableEntry,
|
|
szWordBuf,lstrlen(szWordBuf)+1,&pddi->uOffsetValue,
|
|
NULL);
|
|
if (!pTmp)
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
ppps->pTableEntry = pTmp;
|
|
// adjust pointer to offset, in case table moved
|
|
puLastOffsetPtr = (UINT *) (((BYTE *) puLastOffsetPtr) +
|
|
((BYTE *) ppps->pTableEntry - (BYTE *) pTableEntryOld));
|
|
pddi = (DROPDOWNINFO *)
|
|
((CHAR *) ppps->pTableEntry + *puLastOffsetPtr);
|
|
}
|
|
fHasValue = TRUE;
|
|
|
|
break;
|
|
|
|
case KYWD_ID_ACTIONLIST:
|
|
|
|
if (!fHasItemName) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_ITEMNAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
|
|
if (fHasActionList) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_ACTIONLIST,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
|
|
pTableEntryOld=ppps->pTableEntry;
|
|
uErr=ParseActionList(hWnd,ppps,&pddi->uOffsetActionList,
|
|
&ppps->pTableEntry,szACTIONLIST,pfMore);
|
|
if (uErr != ERROR_SUCCESS)
|
|
return uErr;
|
|
// adjust pointer to offset, in case table moved
|
|
puLastOffsetPtr = (UINT *) (((BYTE *) puLastOffsetPtr) +
|
|
((BYTE *) ppps->pTableEntry - (BYTE *) pTableEntryOld));
|
|
pddi = (DROPDOWNINFO *)
|
|
((CHAR *) ppps->pTableEntry + *puLastOffsetPtr);
|
|
|
|
fHasActionList = TRUE;
|
|
|
|
break;
|
|
|
|
case KYWD_ID_END:
|
|
|
|
if (!fHasItemName) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_ITEMNAME,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
if (!fHasValue) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NO_VALUE,
|
|
NULL,NULL,pszParseFileName,nFileLine);
|
|
uErr = ERROR_ALREADY_DISPLAYED;
|
|
break;
|
|
}
|
|
|
|
// make sure word following "END" is "ITEMLIST"
|
|
if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
|
|
pItemlistCmpList,NULL,pfMore,&uErr)) {
|
|
break;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return uErr;
|
|
}
|
|
|
|
BOOL AddActionListString(CHAR * pszData,DWORD cbData,CHAR ** ppBase,UINT * puOffset,
|
|
DWORD * pdwAlloc,DWORD *pdwUsed)
|
|
{
|
|
DWORD dwNeeded = *pdwUsed + cbData;
|
|
CHAR *pOldBase;
|
|
|
|
// realloc if necessary
|
|
if (dwNeeded > *pdwAlloc) {
|
|
while (*pdwAlloc < dwNeeded)
|
|
*pdwAlloc += SUGGESTBUF_INCREMENT;
|
|
pOldBase = *ppBase;
|
|
if (!(*ppBase = (CHAR *) GlobalReAlloc(*ppBase,*pdwAlloc,
|
|
GMEM_MOVEABLE | GMEM_ZEROINIT)))
|
|
return FALSE;
|
|
puOffset = (UINT *)(*ppBase + ((CHAR *)puOffset - pOldBase));
|
|
}
|
|
|
|
*puOffset = *pdwUsed;
|
|
|
|
if (pszData) memcpy(*ppBase + *puOffset,pszData,cbData);
|
|
*pdwUsed = dwNeeded;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL AddCleanupItem(CLEANUPINFO * pCleanUp,UINT nMax,HGLOBAL hMem, UINT nAction)
|
|
{
|
|
UINT nCount;
|
|
|
|
for (nCount=0;nCount<nMax;nCount++,pCleanUp++) {
|
|
if (!pCleanUp->hMem) {
|
|
pCleanUp->hMem = hMem;
|
|
pCleanUp->nAction = nAction;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
UINT CleanupAndReturn(UINT uRetVal,CLEANUPINFO * pCleanUp)
|
|
{
|
|
while (pCleanUp->hMem) {
|
|
|
|
switch (pCleanUp->nAction) {
|
|
case CI_UNLOCKANDFREE:
|
|
GlobalUnlock(pCleanUp->hMem);
|
|
// fall through
|
|
case CI_FREE:
|
|
GlobalFree(pCleanUp->hMem);
|
|
break;
|
|
case CI_FREETABLE:
|
|
FreeTable(pCleanUp->hMem);
|
|
break;
|
|
}
|
|
|
|
pCleanUp ++;
|
|
}
|
|
|
|
return uRetVal;
|
|
}
|
|
|
|
CHAR * AddDataToEntry(TABLEENTRY * pTableEntry,CHAR * pszData,UINT cbData,
|
|
UINT * puOffsetData,DWORD * pdwBufSize)
|
|
{
|
|
TABLEENTRY * pTemp;
|
|
DWORD dwNeeded,dwOldSize = pTableEntry->dwSize;
|
|
|
|
// puOffsetData points to location that holds the offset to the
|
|
// new data-- size we're adding this to the end of the table, the
|
|
// offset will be the current size of the table. Set this offset
|
|
// in *puOffsetData. Also, notice we touch *puOffsetData BEFORE
|
|
// the realloc, in case puOffsetData points into the region being
|
|
// realloced and the block of memory moves.
|
|
*puOffsetData = pTableEntry->dwSize;
|
|
|
|
// reallocate entry buffer if necessary
|
|
dwNeeded = pTableEntry->dwSize + cbData;
|
|
|
|
if (!(pTemp = (TABLEENTRY *) GlobalReAlloc(pTableEntry,
|
|
dwNeeded,GMEM_ZEROINIT | GMEM_MOVEABLE))) {
|
|
return NULL;
|
|
}
|
|
|
|
pTableEntry = pTemp;
|
|
pTableEntry->dwSize = dwNeeded;
|
|
|
|
if (pszData) memcpy((CHAR *)pTableEntry + dwOldSize,pszData,cbData);
|
|
if (pdwBufSize) *pdwBufSize = pTableEntry->dwSize;
|
|
|
|
return (CHAR *) pTableEntry;
|
|
}
|
|
|
|
#define MSGSIZE 1024
|
|
#define FMTSIZE 512
|
|
VOID DisplayKeywordError(HWND hWnd,UINT uErrorID,CHAR * szFound,
|
|
KEYWORDINFO * pExpectedList,CHAR * szFilename,UINT nLine)
|
|
{
|
|
CHAR * pMsg,*pFmt,*pErrTxt,*pTmp;
|
|
|
|
pMsg = (CHAR *) GlobalAlloc(GPTR,MSGSIZE);
|
|
pFmt = (CHAR *) GlobalAlloc(GPTR,FMTSIZE);
|
|
pErrTxt = (CHAR *) GlobalAlloc(GPTR,FMTSIZE);
|
|
pTmp = (CHAR *) GlobalAlloc(GPTR,FMTSIZE);
|
|
|
|
if (!pMsg || !pFmt || !pErrTxt || !pTmp) {
|
|
if (pMsg) GlobalFree(pMsg);
|
|
if (pFmt) GlobalFree(pFmt);
|
|
if (pErrTxt) GlobalFree(pErrTxt);
|
|
if (pTmp) GlobalFree(pTmp);
|
|
|
|
MsgBox(hWnd,IDS_ErrOUTOFMEMORY,MB_ICONEXCLAMATION,MB_OK);
|
|
return;
|
|
}
|
|
|
|
LoadSz(IDS_ParseFmt_MSG_FORMAT,pFmt,FMTSIZE);
|
|
wsprintf(pMsg,pFmt,szFilename,nLine,uErrorID,LoadSz(uErrorID,
|
|
pErrTxt,FMTSIZE));
|
|
|
|
if (szFound) {
|
|
LoadSz(IDS_ParseFmt_FOUND,pFmt,FMTSIZE);
|
|
wsprintf(pTmp,pFmt,szFound);
|
|
lstrcat(pMsg,pTmp);
|
|
}
|
|
|
|
if (pExpectedList) {
|
|
UINT nIndex=0;
|
|
LoadSz(IDS_ParseFmt_EXPECTED,pFmt,FMTSIZE);
|
|
lstrcpy(pErrTxt,szNull);
|
|
|
|
while (pExpectedList[nIndex].pWord) {
|
|
lstrcat(pErrTxt,pExpectedList[nIndex].pWord);
|
|
if (pExpectedList[nIndex+1].pWord) {
|
|
lstrcat(pErrTxt,", ");
|
|
}
|
|
|
|
nIndex++;
|
|
}
|
|
|
|
wsprintf(pTmp,pFmt,pErrTxt);
|
|
lstrcat(pMsg,pTmp);
|
|
}
|
|
|
|
lstrcat(pMsg,LoadSz(IDS_ParseFmt_FATAL,pTmp,FMTSIZE));
|
|
|
|
MsgBoxSz(hWnd,pMsg,MB_ICONEXCLAMATION,MB_OK);
|
|
|
|
GlobalFree(pMsg);
|
|
GlobalFree(pFmt);
|
|
GlobalFree(pErrTxt);
|
|
GlobalFree(pTmp);
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: CompareKeyword
|
|
|
|
SYNOPSIS: Compares a specified buffer to a list of valid keywords.
|
|
If it finds a match, the index of the match in the list
|
|
is returned in *pnListIndex. Otherwise an error message
|
|
is displayed.
|
|
|
|
EXIT: Returns TRUE if a keyword match is found, FALSE otherwise.
|
|
If TRUE, *pnListIndex contains matching index.
|
|
|
|
********************************************************************/
|
|
BOOL CompareKeyword(HWND hWnd,CHAR * szWord,KEYWORDINFO *pKeywordList,
|
|
UINT * pnListIndex)
|
|
{
|
|
KEYWORDINFO * pKeywordInfo = pKeywordList;
|
|
|
|
while (pKeywordInfo->pWord) {
|
|
if (!lstrcmpi(szWord,pKeywordInfo->pWord)) {
|
|
if (pnListIndex)
|
|
*pnListIndex = pKeywordInfo->nID;
|
|
return TRUE;
|
|
}
|
|
pKeywordInfo ++;
|
|
}
|
|
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_UNEXPECTED_KEYWORD,
|
|
szWord,pKeywordList,pszParseFileName,nFileLine);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: PrivGetPrivateProfileString
|
|
|
|
SYNOPIS: Force GetPrivateProfileString to be Unicode
|
|
|
|
NOTES: NT4 has a bug where if were calling GetPrivateProfileStringA
|
|
and it's a Unicode ini file it will hit uninitialized
|
|
memory. Always call the W api to avoid this.
|
|
|
|
********************************************************************/
|
|
#ifdef UNICODE
|
|
#define PrivGetPrivateProfileString GetPrivateProfileStringW
|
|
#else
|
|
DWORD PrivGetPrivateProfileString(LPCSTR szSection, LPCSTR szValue, LPCSTR szDefault, LPSTR szBuffer, DWORD cbBuffer, LPCSTR szFilename)
|
|
{
|
|
WCHAR wszSection[256];
|
|
WCHAR wszValue[256];
|
|
WCHAR wszDefault[256];
|
|
WCHAR wszFilename[256];
|
|
DWORD ret;
|
|
LPWSTR pwszBuffer;
|
|
|
|
pwszBuffer = LocalAlloc (LPTR, cbBuffer * sizeof(WCHAR));
|
|
|
|
if (!pwszBuffer) {
|
|
return GetLastError();
|
|
}
|
|
|
|
if (0 == MultiByteToWideChar(CP_ACP, 0, szSection, -1, wszSection, 256))
|
|
return 0;
|
|
|
|
if (0 == MultiByteToWideChar(CP_ACP, 0, szValue, -1, wszValue, 256))
|
|
return 0;
|
|
|
|
if (0 == MultiByteToWideChar(CP_ACP, 0, szDefault, -1, wszDefault, 256))
|
|
return 0;
|
|
|
|
if (0 == MultiByteToWideChar(CP_ACP, 0, szFilename, -1, wszFilename, 256))
|
|
return 0;
|
|
|
|
ret = GetPrivateProfileStringW(wszSection, wszValue, wszDefault, pwszBuffer, cbBuffer, wszFilename);
|
|
|
|
if (0 != ret)
|
|
if (0 == WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, szBuffer, cbBuffer, NULL, NULL))
|
|
return 0;
|
|
|
|
|
|
LocalFree (pwszBuffer);
|
|
return ret;
|
|
}
|
|
#endif // !UNICODE
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetNextWord
|
|
|
|
SYNOPSIS: Fills input buffer with next word in file stream
|
|
|
|
NOTES: Calls GetNextChar() to get character stream. Whitespace
|
|
and comments are skipped. Quoted strings are returned
|
|
as one word (including whitespace) with the quotes removed.
|
|
|
|
EXIT: If successful, returns a pointer to the input buffer
|
|
(szBuf). *pfMore indicates if there are more words to
|
|
be read. If an error occurs, its value is returned in *puErr.
|
|
|
|
********************************************************************/
|
|
CHAR * GetNextWord(HWND hWnd,HANDLE hFile,CHAR * szBuf,UINT cbBuf,BOOL * pfMore,UINT *
|
|
puErr)
|
|
{
|
|
CHAR * pChar;
|
|
BOOL fInWord = FALSE;
|
|
BOOL fInQuote = FALSE;
|
|
CHAR * pWord = szBuf;
|
|
UINT cbWord = 0;
|
|
CHAR * GetNextChar(HANDLE hFile,BOOL * pfMore,UINT * puErr);
|
|
BOOL IsComment(CHAR * pBuf);
|
|
BOOL IsWhitespace(CHAR * pBuf);
|
|
BOOL IsEndOfLine(CHAR * pBuf);
|
|
BOOL IsQuote(CHAR * pBuf);
|
|
BOOL IsLocalizedString(CHAR * pBuf);
|
|
UINT ProcessIfdefs(HWND hWnd,HANDLE hFile,CHAR * pBuf,UINT cbBuf,BOOL * pfMore);
|
|
|
|
// clear buffer to start with
|
|
lstrcpy(szBuf,szNull);
|
|
|
|
while (pChar = GetNextChar(hFile,pfMore,puErr)) {
|
|
|
|
// keep track of which file line we're on
|
|
if (IsEndOfLine(pChar)) nFileLine++;
|
|
|
|
// keep track of wheter we are inside quoted string or not
|
|
if (IsQuote(pChar) && !fInComment) {
|
|
if (!fInQuote)
|
|
fInQuote = TRUE; // entering quoted string
|
|
else {
|
|
fInQuote = FALSE; // leaving quoted string
|
|
break; // end of word
|
|
}
|
|
|
|
}
|
|
|
|
if (!fInQuote) {
|
|
|
|
// skip over lines with comments (';')
|
|
if (!fInComment & IsComment(pChar)) fInComment = TRUE;
|
|
if (fInComment) {
|
|
if (IsEndOfLine(pChar)) {
|
|
fInComment = FALSE;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (IsWhitespace(pChar)) {
|
|
|
|
// if we haven't found word yet, skip over whitespace
|
|
if (!fInWord)
|
|
continue;
|
|
|
|
// otherwise, whitespace signals end of word
|
|
break;
|
|
}
|
|
}
|
|
|
|
// found a non-comment, non-whitespace character
|
|
if (!fInWord) fInWord = TRUE;
|
|
|
|
if (!IsQuote(pChar)) {
|
|
// add this character to word
|
|
|
|
*pWord = *pChar;
|
|
pWord++;
|
|
cbWord++;
|
|
|
|
if (cbWord > cbBuf) {
|
|
*(pWord - 1) = TEXT('\0');
|
|
MsgBoxParam(NULL,IDS_WORDTOOLONG,szBuf,MB_ICONEXCLAMATION,MB_OK);
|
|
*puErr = ERROR_ALREADY_DISPLAYED;
|
|
goto Exit;
|
|
}
|
|
#if 0
|
|
if (IsDBCSLeadByte((BYTE) *pChar)) {
|
|
*pWord = *pChar;
|
|
pWord++;
|
|
cbWord++;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
*pWord = '\0'; // null-terminate
|
|
|
|
// if found string a la '!!foo', then look for a string in the [strings]
|
|
// section with the key name 'foo' and use that instead. This is because
|
|
// our localization tools are brainless and require a [strings] section.
|
|
// So although template files are sectionless, we allow a [strings] section
|
|
// at the bottom.
|
|
if (IsLocalizedString(szBuf)) {
|
|
LPTSTR lpTmp;
|
|
|
|
lpTmp = LocalAlloc (LPTR, cbBuf * sizeof(TCHAR));
|
|
|
|
if (lpTmp) {
|
|
DWORD dwSize;
|
|
|
|
if (g_bWinnt) {
|
|
dwSize = PrivGetPrivateProfileString(szStrings,szBuf+2,
|
|
szNull,lpTmp,cbBuf,pszParseFileName);
|
|
}
|
|
else {
|
|
dwSize = GetPrivateProfileStringA(szStrings,szBuf+2,
|
|
szNull,lpTmp,cbBuf,pszParseFileName);
|
|
}
|
|
|
|
if (!dwSize) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_STRING_NOT_FOUND,
|
|
szBuf,NULL,pszParseFileName,nFileLine);
|
|
*puErr=ERROR_ALREADY_DISPLAYED;
|
|
return NULL;
|
|
}
|
|
|
|
// replace the word we're returning with the one from the [strings]
|
|
// section
|
|
lstrcpy(szBuf,lpTmp);
|
|
|
|
LocalFree (lpTmp);
|
|
}
|
|
} else {
|
|
*puErr = ProcessIfdefs(hWnd,hFile,szBuf,cbBuf,pfMore);
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (*puErr != ERROR_SUCCESS || !fInWord) return NULL;
|
|
return szBuf;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetNextSectionWord
|
|
|
|
SYNOPSIS: Gets next word and warns if end-of-file encountered.
|
|
Optionally checks the keyword against a list of valid
|
|
keywords.
|
|
|
|
NOTES: Calls GetNextWord() to get word. This is called in
|
|
situations where we expect there to be another word
|
|
(e.g., inside a section) and it's an error if the
|
|
file ends.
|
|
|
|
********************************************************************/
|
|
CHAR * GetNextSectionWord(HWND hWnd,HANDLE hFile,CHAR * szBuf,UINT cbBuf,
|
|
KEYWORDINFO * pKeywordList,UINT *pnListIndex,BOOL * pfMore,UINT * puErr)
|
|
{
|
|
CHAR * pch;
|
|
|
|
if (!(pch=GetNextWord(hWnd,hFile,szBuf,cbBuf,pfMore,puErr))) {
|
|
|
|
if (!*pfMore && *puErr != ERROR_ALREADY_DISPLAYED) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_UNEXPECTED_EOF,
|
|
NULL,pKeywordList,pszParseFileName,nFileLine);
|
|
*puErr = ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
if (pKeywordList && !CompareKeyword(hWnd,szBuf,pKeywordList,pnListIndex)) {
|
|
*puErr = ERROR_ALREADY_DISPLAYED;
|
|
return NULL;
|
|
}
|
|
|
|
return pch;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetNextSectionNumericWord
|
|
|
|
SYNOPSIS: Gets next word and converts string to number. Warns if
|
|
not a numeric value
|
|
|
|
********************************************************************/
|
|
UINT GetNextSectionNumericWord(HWND hWnd,HANDLE hFile,UINT * pnVal)
|
|
{
|
|
UINT uErr;
|
|
CHAR szWordBuf[255];
|
|
BOOL fMore;
|
|
|
|
if (!GetNextSectionWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),
|
|
NULL,NULL,&fMore,&uErr))
|
|
return uErr;
|
|
|
|
if (!StringToNum(szWordBuf,pnVal)) {
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_NOT_NUMERIC,szWordBuf,
|
|
NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/*******************************************************************
|
|
|
|
NAME: GetNextChar
|
|
|
|
SYNOPSIS: Returns a pointer to the next character from the
|
|
file stream.
|
|
|
|
NOTES: Reads a chunk of the file into a buffer and returns
|
|
a pointer inside the buffer, reading new chunks into
|
|
the buffer as necessary.
|
|
|
|
EXIT: Returns pointer to next character in stream.
|
|
If
|
|
|
|
********************************************************************/
|
|
CHAR * GetNextChar(HANDLE hFile,BOOL * pfMore,UINT * puErr)
|
|
{
|
|
CHAR * pCurrentChar;
|
|
UINT uRet;
|
|
UINT ReadFileToBuffer(HANDLE hFile,CHAR * pBuf,DWORD cbBuf,DWORD *pdwRead,
|
|
BOOL * pfEOF);
|
|
|
|
*puErr = ERROR_SUCCESS;
|
|
*pfMore = TRUE;
|
|
|
|
// read another chunk into buffer if necessary
|
|
|
|
// if we haven't gotten a buffer-ful yet or have read through the current
|
|
// buffer
|
|
if (!pFilePtr || pFilePtr > pFileEnd) {
|
|
DWORD dwRead;
|
|
|
|
// if we're finished with this buffer, and we're at the end of file
|
|
// (fEOF true), then signal end of stream
|
|
if ( (pFilePtr > pFileEnd) && fEOF) {
|
|
*pfMore = FALSE;
|
|
return NULL;
|
|
}
|
|
|
|
uRet=ReadFileToBuffer(hFile,(VOID *) pFileBuf,FILEBUFSIZE,&dwRead,
|
|
&fEOF);
|
|
if (uRet != ERROR_SUCCESS) {
|
|
*puErr = uRet;
|
|
return NULL;
|
|
}
|
|
|
|
pFilePtr = pFileBuf;
|
|
pFileEnd = pFilePtr + dwRead-1;
|
|
#if 0
|
|
} else if (pFilePtr == pFileEnd && IsDBCSLeadByte((BYTE) *pFilePtr)) {
|
|
// have to watch for one tricky situation-- where the first
|
|
// byte of a DBCS char has fallen on the end of our read buffer.
|
|
// In this case, copy that byte to beginning of buffer, and read in
|
|
// another chunk to rest of buffer.
|
|
DWORD dwRead;
|
|
|
|
*pFileBuf = *pFilePtr;
|
|
uRet=ReadFileToBuffer(hFile,(VOID *) (pFileBuf+1),FILEBUFSIZE-1,&dwRead,
|
|
&fEOF);
|
|
if (uRet != ERROR_SUCCESS) {
|
|
*puErr = uRet;
|
|
return NULL;
|
|
}
|
|
|
|
pFilePtr = pFileBuf;
|
|
pFileEnd = pFilePtr + dwRead;
|
|
#endif
|
|
}
|
|
|
|
pCurrentChar = pFilePtr;
|
|
pFilePtr = CharNext(pFilePtr);
|
|
|
|
return pCurrentChar;
|
|
}
|
|
|
|
UINT ReadFileToBuffer(HANDLE hFile,CHAR * pBuf,DWORD cbBuf,DWORD *pdwRead,
|
|
BOOL * pfEOF)
|
|
{
|
|
VOID *pDestBuf = fUnicode ? (VOID *) pUnicodeFileBuf : (VOID *) pBuf;
|
|
|
|
if (!ReadFile(hFile,pDestBuf,cbBuf,pdwRead,NULL))
|
|
return GetLastError();
|
|
|
|
if (*pdwRead<cbBuf) *pfEOF = TRUE;
|
|
else *pfEOF = FALSE;
|
|
|
|
if (fCheckUnicode)
|
|
{
|
|
if (*pdwRead >= sizeof(WCHAR))
|
|
{
|
|
if (IsTextUnicode(pDestBuf, *pdwRead, NULL))
|
|
{
|
|
fUnicode = TRUE;
|
|
|
|
pUnicodeFileBuf = (WCHAR *) GlobalAlloc(GPTR,FILEBUFSIZE);
|
|
if (NULL == pUnicodeFileBuf)
|
|
return ERROR_OUTOFMEMORY;
|
|
|
|
*pdwRead -= sizeof(WCHAR);
|
|
CopyMemory(pUnicodeFileBuf, pBuf+sizeof(WCHAR), *pdwRead);
|
|
}
|
|
}
|
|
|
|
fCheckUnicode = FALSE;
|
|
}
|
|
|
|
if (fUnicode)
|
|
{
|
|
// If we read an odd number of bytes in a unicode file either the
|
|
// file is corrupt or somebody is passing a bogus cbBuf
|
|
ASSERT(0 == (*pdwRead & 1));
|
|
|
|
*pdwRead = WideCharToMultiByte(
|
|
CP_ACP,
|
|
0,
|
|
pUnicodeFileBuf,
|
|
*pdwRead / sizeof(WCHAR),
|
|
pBuf,
|
|
cbBuf,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (0 == *pdwRead)
|
|
return GetLastError();
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
BOOL IsComment(CHAR * pBuf)
|
|
{
|
|
return (*pBuf == ';');
|
|
}
|
|
|
|
BOOL IsQuote(CHAR * pBuf)
|
|
{
|
|
return (*pBuf == '\"');
|
|
}
|
|
|
|
BOOL IsEndOfLine(CHAR * pBuf)
|
|
{
|
|
return (*pBuf == 0x0D); // CR
|
|
}
|
|
|
|
BOOL IsWhitespace(CHAR * pBuf)
|
|
{
|
|
return ( *pBuf == 0x20 // space
|
|
|| *pBuf == 0x0D // CR
|
|
|| *pBuf == 0X0A // LF
|
|
|| *pBuf == 0x09 // tab
|
|
|| *pBuf == 0x1A // EOF
|
|
);
|
|
}
|
|
|
|
BOOL IsLocalizedString(CHAR * pBuf)
|
|
{
|
|
return (*pBuf == '!' && *(pBuf+1) == '!');
|
|
}
|
|
|
|
BOOL fFilterDirectives = TRUE;
|
|
UINT nGlobalNestedLevel = 0;
|
|
|
|
// reads up through the matching directive #endif in current scope
|
|
//and sets file pointer immediately past the directive
|
|
UINT FindMatchingDirective(HWND hWnd,HANDLE hFile,BOOL *pfMore,BOOL fElseOK)
|
|
{
|
|
CHAR szWordBuf[255];
|
|
UINT uErr=ERROR_SUCCESS,nNestedLevel=1;
|
|
BOOL fContinue = TRUE;
|
|
|
|
// set the flag to stop catching '#' directives in low level word-fetching
|
|
// routine
|
|
fFilterDirectives = FALSE;
|
|
|
|
// keep reading words. Keep track of how many layers of #ifdefs deep we
|
|
// are. Every time we encounter an #ifdef or #ifndef, increment the level
|
|
// count (nNestedLevel) by one. For every #endif decrement the level count.
|
|
// When the level count hits zero, we've found the matching #endif.
|
|
while (nNestedLevel > 0) {
|
|
if (!GetNextSectionWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),NULL,NULL,
|
|
pfMore,&uErr))
|
|
break;
|
|
|
|
if (!lstrcmpi(szWordBuf,szIFDEF) || !lstrcmpi(szWordBuf,szIFNDEF) ||
|
|
!lstrcmpi(szWordBuf,szIF))
|
|
nNestedLevel ++;
|
|
else if (!lstrcmpi(szWordBuf,szENDIF)) {
|
|
nNestedLevel --;
|
|
}
|
|
else if (!lstrcmpi(szWordBuf,szELSE) && (nNestedLevel == 1)) {
|
|
if (fElseOK) {
|
|
// ignore "#else" unless it's on the same level as the #ifdef
|
|
// we're finding a match for (nNestedLevel == 1), in which
|
|
// case treat it as the matching directive
|
|
nNestedLevel --;
|
|
// increment global nesting so we expect an #endif to come along
|
|
// later to match this #else
|
|
nGlobalNestedLevel++;
|
|
} else {
|
|
// found a #else where we already had a #else in this level
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_UNMATCHED_DIRECTIVE,
|
|
szWordBuf,NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
}
|
|
}
|
|
|
|
fFilterDirectives = TRUE;
|
|
|
|
return uErr;
|
|
}
|
|
|
|
#define CURRENT_VERSION 2
|
|
// if the word in the word buffer is #ifdef, #if, #ifndef, #else or #endif,
|
|
// this function reads ahead an appropriate amount (
|
|
UINT ProcessIfdefs(HWND hWnd,HANDLE hFile,CHAR * pBuf,UINT cbBuf,BOOL * pfMore)
|
|
{
|
|
UINT uRet;
|
|
|
|
if (!fFilterDirectives)
|
|
return ERROR_SUCCESS;
|
|
|
|
if (!lstrcmpi(pBuf,szIFDEF)) {
|
|
// we've found an '#ifdef <something or other>, where ISV policy editors
|
|
// can understand particular keywords they make up. We don't have any
|
|
// #ifdef keywords of our own so always skip this
|
|
uRet = FindMatchingDirective(hWnd,hFile,pfMore,TRUE);
|
|
if (uRet != ERROR_SUCCESS)
|
|
return uRet;
|
|
if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
|
|
return uRet;
|
|
return ERROR_SUCCESS;
|
|
} else if (!lstrcmpi(pBuf,szIFNDEF)) {
|
|
// this is an #ifndef, and since nothing is ever ifdef'd for our policy
|
|
// editor, this always evaluates to TRUE
|
|
|
|
// keep reading this section but increment the nested level count,
|
|
// when we find the matching #endif or #else we'll be able to respond
|
|
// correctly
|
|
nGlobalNestedLevel ++;
|
|
|
|
// get next word (e.g. "foo" for #ifndef foo) and throw it away
|
|
if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
|
|
return uRet;
|
|
|
|
// get next word and return it for real
|
|
if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
|
|
return uRet;
|
|
|
|
return ERROR_SUCCESS;
|
|
|
|
} else if (!lstrcmpi(pBuf,szENDIF)) {
|
|
// if we ever encounter an #endif here, we must have processed
|
|
// the preceeding section. Just step over the #endif and go on
|
|
|
|
if (!nGlobalNestedLevel) {
|
|
// found an endif without a preceeding #if<xx>
|
|
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_UNMATCHED_DIRECTIVE,
|
|
pBuf,NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
nGlobalNestedLevel--;
|
|
|
|
if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
|
|
return uRet;
|
|
return ERROR_SUCCESS;
|
|
} else if (!lstrcmpi(pBuf,szIF)) {
|
|
// syntax is "#if VERSION (comparision) (version #)"
|
|
// e.g. "#if VERSION >= 2"
|
|
CHAR szWordBuf[255];
|
|
UINT nIndex,nVersion,nOperator;
|
|
BOOL fDirectiveTrue = FALSE;
|
|
|
|
// get the next word (must be "VERSION")
|
|
if (!GetNextSectionWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),
|
|
pVersionCmpList,&nIndex,pfMore,&uRet))
|
|
return uRet;
|
|
|
|
// get the comparison operator (>, <, ==, >=, <=)
|
|
if (!GetNextSectionWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),
|
|
pOperatorCmpList,&nOperator,pfMore,&uRet))
|
|
return uRet;
|
|
|
|
// get the version number
|
|
uRet=GetNextSectionNumericWord(hWnd,hFile,&nVersion);
|
|
if (uRet != ERROR_SUCCESS)
|
|
return uRet;
|
|
|
|
// now evaluate the directive
|
|
|
|
switch (nOperator) {
|
|
case KYWD_ID_GT:
|
|
fDirectiveTrue = (CURRENT_VERSION > nVersion);
|
|
break;
|
|
|
|
case KYWD_ID_GTE:
|
|
fDirectiveTrue = (CURRENT_VERSION >= nVersion);
|
|
break;
|
|
|
|
case KYWD_ID_LT:
|
|
fDirectiveTrue = (CURRENT_VERSION < nVersion);
|
|
break;
|
|
|
|
case KYWD_ID_LTE:
|
|
fDirectiveTrue = (CURRENT_VERSION <= nVersion);
|
|
break;
|
|
|
|
case KYWD_ID_EQ:
|
|
fDirectiveTrue = (CURRENT_VERSION == nVersion);
|
|
break;
|
|
|
|
case KYWD_ID_NE:
|
|
fDirectiveTrue = (CURRENT_VERSION != nVersion);
|
|
break;
|
|
}
|
|
|
|
|
|
if (fDirectiveTrue) {
|
|
// keep reading this section but increment the nested level count,
|
|
// when we find the matching #endif or #else we'll be able to respond
|
|
// correctly
|
|
nGlobalNestedLevel ++;
|
|
} else {
|
|
// skip over this section
|
|
uRet = FindMatchingDirective(hWnd,hFile,pfMore,TRUE);
|
|
if (uRet != ERROR_SUCCESS)
|
|
return uRet;
|
|
}
|
|
|
|
// get next word and return it for real
|
|
if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
|
|
return uRet;
|
|
|
|
return ERROR_SUCCESS;
|
|
} else if (!lstrcmpi(pBuf,szELSE)) {
|
|
// found an #else, which means we took the upper branch, skip over
|
|
// the lower branch
|
|
if (!nGlobalNestedLevel) {
|
|
// found an #else without a preceeding #if<xx>
|
|
|
|
DisplayKeywordError(hWnd,IDS_ParseErr_UNMATCHED_DIRECTIVE,
|
|
pBuf,NULL,pszParseFileName,nFileLine);
|
|
return ERROR_ALREADY_DISPLAYED;
|
|
}
|
|
nGlobalNestedLevel--;
|
|
|
|
uRet = FindMatchingDirective(hWnd,hFile,pfMore,FALSE);
|
|
if (uRet != ERROR_SUCCESS)
|
|
return uRet;
|
|
if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
|
|
return uRet;
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|