Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2397 lines
79 KiB

  1. //*********************************************************************
  2. //* Microsoft Windows **
  3. //* Copyright(c) Microsoft Corp., 1994 **
  4. //*********************************************************************
  5. #include "admincfg.h"
  6. #include "parse.h"
  7. UINT nFileLine;
  8. TABLEENTRY * pListCurrent; // current category list (either user or machine)
  9. UINT *pnDataItemCount;
  10. // buffer to read .INF file into
  11. CHAR * pFileBuf;
  12. CHAR * pFilePtr;
  13. CHAR * pFileEnd;
  14. WCHAR *pUnicodeFileBuf;
  15. BOOL fInComment;
  16. BOOL fEOF;
  17. BOOL fUnicode;
  18. BOOL fCheckUnicode;
  19. LPSTR pszParseFileName;
  20. UINT ParseEntry(HWND hWnd,PARSEENTRYSTRUCT *ppes,BOOL *pfMore);
  21. UINT ParseCategory(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
  22. BOOL fParentHasKey,BOOL *pfMore);
  23. UINT CategoryParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
  24. BOOL * pfMore,BOOL * pfFoundEnd);
  25. UINT ParsePolicy(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
  26. BOOL fParentHasKey,BOOL *pfMore);
  27. UINT PolicyParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
  28. BOOL * pfMore,BOOL * pfFoundEnd);
  29. UINT ParseSettings(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
  30. BOOL fParentHasKey,BOOL *pfMore);
  31. UINT SettingsParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
  32. BOOL * pfMore,BOOL * pfFoundEnd);
  33. UINT ParseClass(HWND hWnd,HANDLE hFile,BOOL *pfMore);
  34. UINT InitSettingsParse(PARSEPROCSTRUCT *ppps,DWORD dwType,DWORD dwSize,
  35. KEYWORDINFO * pKeyList,SETTINGS ** ppSettings,CHAR **pObjectData);
  36. BOOL CompareKeyword(HWND hWnd,CHAR * szWord,KEYWORDINFO *pKeywordList,
  37. UINT * pnListIndex);
  38. VOID DisplayKeywordError(HWND hWnd,UINT uErrorID,CHAR * szFound,
  39. KEYWORDINFO * pExpectedList,CHAR * szFilename,UINT nLine);
  40. CHAR * GetNextSectionWord(HWND hWnd,HANDLE hFile,CHAR * szBuf,UINT cbBuf,
  41. KEYWORDINFO * pKeywordList,UINT *pnListIndex,BOOL * pfMore,UINT * puErr);
  42. UINT GetNextSectionNumericWord(HWND hWnd,HANDLE hFile,UINT * pnVal);
  43. CHAR * GetNextWord(HWND hWnd,HANDLE hFile,CHAR * szBuf,UINT cbBuf,BOOL * pfMore,UINT *
  44. puErr);
  45. UINT ParseValue(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
  46. TABLEENTRY ** ppTableEntryNew,BOOL *pfMore);
  47. UINT ParseSuggestions(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
  48. TABLEENTRY ** ppTableEntryNew,BOOL * pfMore);
  49. UINT ParseActionList(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
  50. TABLEENTRY ** ppTableEntryNew,LPCSTR pszKeyword,BOOL * pfMore);
  51. UINT ParseItemList(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
  52. BOOL * pfMore);
  53. CHAR * AddDataToEntry(TABLEENTRY * pTableEntry,CHAR * szData,UINT cbData,
  54. UINT * puOffsetData,DWORD * pdwBufSize);
  55. BOOL AddCleanupItem(CLEANUPINFO * pCleanUp,UINT nMax,HGLOBAL hMem, UINT nAction);
  56. UINT CleanupAndReturn(UINT uRetVal,CLEANUPINFO * pCleanup);
  57. // list of legal keyword entries in "CATEGORY" section
  58. KEYWORDINFO pCategoryEntryCmpList[] = { {szKEYNAME,KYWD_ID_KEYNAME},
  59. {szCATEGORY,KYWD_ID_CATEGORY},{szPOLICY,KYWD_ID_POLICY},
  60. {szEND,KYWD_ID_END}, {NULL,0} };
  61. KEYWORDINFO pCategoryTypeCmpList[] = { {szCATEGORY,KYWD_ID_CATEGORY},
  62. {NULL,0} };
  63. // list of legal keyword entries in "POLICY" section
  64. KEYWORDINFO pPolicyEntryCmpList[] = { {szKEYNAME,KYWD_ID_KEYNAME},
  65. {szVALUENAME,KYWD_ID_VALUENAME}, {szPART,KYWD_ID_PART},
  66. {szVALUEON,KYWD_ID_VALUEON},{szVALUEOFF,KYWD_ID_VALUEOFF},
  67. {szACTIONLISTON,KYWD_ID_ACTIONLISTON},{szACTIONLISTOFF,KYWD_ID_ACTIONLISTOFF},
  68. {szEND,KYWD_ID_END},{szHELP,KYWD_ID_HELP}, {szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL, 0} };
  69. KEYWORDINFO pPolicyTypeCmpList[] = { {szPOLICY,KYWD_ID_POLICY}, {NULL,0} };
  70. // list of legal keyword entries in "PART" section
  71. KEYWORDINFO pSettingsEntryCmpList[] = { {szCHECKBOX,KYWD_ID_CHECKBOX},
  72. {szTEXT,KYWD_ID_TEXT},{szEDITTEXT,KYWD_ID_EDITTEXT},
  73. {szNUMERIC,KYWD_ID_NUMERIC},{szCOMBOBOX,KYWD_ID_COMBOBOX},
  74. {szDROPDOWNLIST,KYWD_ID_DROPDOWNLIST},{szLISTBOX,KYWD_ID_LISTBOX},
  75. {szEND,KYWD_ID_END},{szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0}};
  76. KEYWORDINFO pSettingsTypeCmpList[] = {{szPART,KYWD_ID_PART},{NULL,0}};
  77. KEYWORDINFO pCheckboxCmpList[] = {
  78. {szKEYNAME,KYWD_ID_KEYNAME},{szVALUENAME,KYWD_ID_VALUENAME},
  79. {szVALUEON,KYWD_ID_VALUEON},{szVALUEOFF,KYWD_ID_VALUEOFF},
  80. {szACTIONLISTON,KYWD_ID_ACTIONLISTON},{szACTIONLISTOFF,KYWD_ID_ACTIONLISTOFF},
  81. {szDEFCHECKED, KYWD_ID_DEFCHECKED},{szCLIENTEXT,KYWD_ID_CLIENTEXT},
  82. {szEND,KYWD_ID_END},{NULL,0} };
  83. KEYWORDINFO pTextCmpList[] = {{szEND,KYWD_ID_END},{NULL,0}};
  84. KEYWORDINFO pEditTextCmpList[] = {
  85. {szKEYNAME,KYWD_ID_KEYNAME},{szVALUENAME,KYWD_ID_VALUENAME},
  86. {szDEFAULT,KYWD_ID_EDITTEXT_DEFAULT},
  87. {szREQUIRED,KYWD_ID_REQUIRED},{szMAXLENGTH,KYWD_ID_MAXLENGTH},
  88. {szOEMCONVERT,KYWD_ID_OEMCONVERT},{szSOFT,KYWD_ID_SOFT},
  89. {szEND,KYWD_ID_END},{szEXPANDABLETEXT,KYWD_ID_EXPANDABLETEXT},
  90. {szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0} };
  91. KEYWORDINFO pComboboxCmpList[] = {
  92. {szKEYNAME,KYWD_ID_KEYNAME},{szVALUENAME,KYWD_ID_VALUENAME},
  93. {szDEFAULT,KYWD_ID_COMBOBOX_DEFAULT},{szSUGGESTIONS,KYWD_ID_SUGGESTIONS},
  94. {szREQUIRED,KYWD_ID_REQUIRED},{szMAXLENGTH,KYWD_ID_MAXLENGTH},
  95. {szOEMCONVERT,KYWD_ID_OEMCONVERT},{szSOFT,KYWD_ID_SOFT},
  96. {szEND,KYWD_ID_END},{szNOSORT, KYWD_ID_NOSORT},
  97. {szEXPANDABLETEXT,KYWD_ID_EXPANDABLETEXT},{szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0} };
  98. KEYWORDINFO pNumericCmpList[] = {
  99. {szKEYNAME,KYWD_ID_KEYNAME},{szVALUENAME,KYWD_ID_VALUENAME},
  100. {szMIN, KYWD_ID_MIN},{szMAX,KYWD_ID_MAX},{szSPIN,KYWD_ID_SPIN},
  101. {szDEFAULT,KYWD_ID_NUMERIC_DEFAULT},{szREQUIRED,KYWD_ID_REQUIRED},
  102. {szTXTCONVERT,KYWD_ID_TXTCONVERT},{szSOFT,KYWD_ID_SOFT},
  103. {szEND,KYWD_ID_END}, {szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0} };
  104. KEYWORDINFO pDropdownlistCmpList[] = {
  105. {szKEYNAME,KYWD_ID_KEYNAME},{szVALUENAME,KYWD_ID_VALUENAME},
  106. {szREQUIRED,KYWD_ID_REQUIRED},{szITEMLIST,KYWD_ID_ITEMLIST},
  107. {szEND,KYWD_ID_END},{szNOSORT, KYWD_ID_NOSORT},{szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0}};
  108. KEYWORDINFO pListboxCmpList[] = {
  109. {szKEYNAME,KYWD_ID_KEYNAME},{szVALUEPREFIX,KYWD_ID_VALUEPREFIX},
  110. {szADDITIVE,KYWD_ID_ADDITIVE},{szNOSORT, KYWD_ID_NOSORT},
  111. {szEXPLICITVALUE,KYWD_ID_EXPLICITVALUE},{szEND,KYWD_ID_END},{szCLIENTEXT,KYWD_ID_CLIENTEXT},{NULL,0} };
  112. KEYWORDINFO pClassCmpList[] = { {szCLASS, KYWD_ID_CLASS},
  113. {szCATEGORY,KYWD_ID_CATEGORY}, {szStringsSect,KYWD_ID_STRINGSSECT},
  114. {NULL,0} };
  115. KEYWORDINFO pClassTypeCmpList[] = { {szUSER, KYWD_ID_USER},
  116. {szMACHINE,KYWD_ID_MACHINE}, {NULL,0} };
  117. KEYWORDINFO pVersionCmpList[] = { {szVERSION, KYWD_ID_VERSION}, {NULL,0}};
  118. KEYWORDINFO pOperatorCmpList[] = { {szGT, KYWD_ID_GT}, {szGTE,KYWD_ID_GTE},
  119. {szLT, KYWD_ID_LT}, {szLTE,KYWD_ID_LTE}, {szEQ,KYWD_ID_EQ},
  120. {szNE, KYWD_ID_NE}, {NULL,0}};
  121. UINT ParseTemplateFile(HWND hWnd,HANDLE hFile,LPSTR pszFileName)
  122. {
  123. BOOL fMore;
  124. UINT uRet;
  125. nFileLine = 1;
  126. pListCurrent = gClassList.pMachineCategoryList;
  127. pnDataItemCount = &gClassList.nMachineDataItems;
  128. pszParseFileName = pszFileName;
  129. if (!(pFileBuf = (CHAR *) GlobalAlloc(GPTR,FILEBUFSIZE))) {
  130. return ERROR_NOT_ENOUGH_MEMORY;
  131. }
  132. pUnicodeFileBuf = NULL;
  133. pFilePtr = pFileEnd = NULL;
  134. fEOF = fInComment = fUnicode = FALSE;
  135. fCheckUnicode = TRUE;
  136. do {
  137. uRet=ParseClass(hWnd,hFile,&fMore);
  138. } while (fMore && uRet == ERROR_SUCCESS);
  139. GlobalFree(pFileBuf);
  140. if (NULL != pUnicodeFileBuf)
  141. GlobalFree(pUnicodeFileBuf);
  142. return uRet;
  143. }
  144. UINT ParseClass(HWND hWnd,HANDLE hFile,BOOL *pfMore)
  145. {
  146. CHAR szWordBuf[WORDBUFSIZE+1];
  147. UINT uErr,nKeywordID,nClassID;
  148. if (!GetNextWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),pfMore,&uErr))
  149. return uErr;
  150. if (!CompareKeyword(hWnd,szWordBuf,pClassCmpList,&nKeywordID))
  151. return ERROR_ALREADY_DISPLAYED;
  152. switch (nKeywordID) {
  153. case KYWD_ID_CATEGORY:
  154. return ParseCategory(hWnd,hFile,pListCurrent,
  155. FALSE,pfMore);
  156. break;
  157. case KYWD_ID_CLASS:
  158. if (!GetNextSectionWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),
  159. pClassTypeCmpList,&nClassID,pfMore,&uErr))
  160. return uErr;
  161. switch (nClassID) {
  162. case KYWD_ID_USER:
  163. pListCurrent = gClassList.pUserCategoryList;
  164. pnDataItemCount = &gClassList.nUserDataItems;
  165. break;
  166. case KYWD_ID_MACHINE:
  167. pListCurrent = gClassList.pMachineCategoryList;
  168. pnDataItemCount = &gClassList.nMachineDataItems;
  169. break;
  170. }
  171. break;
  172. // hack for localization: allow a "strings" section at the bottom, if we
  173. // encounter that then we're thru with parsing
  174. case KYWD_ID_STRINGSSECT:
  175. *pfMore = FALSE; // that's all, folks
  176. return ERROR_SUCCESS;
  177. break;
  178. }
  179. return ERROR_SUCCESS;
  180. }
  181. /*******************************************************************
  182. NAME: ParseEntry
  183. SYNOPSIS: Main parsing "engine" for category, policy and part
  184. parsing
  185. NOTES: Allocates memory to build a temporary TABLEENTRY struct
  186. describing the parsed information. Reads the beginning and end of a
  187. section and loops through the words in each section, calling
  188. a caller-defined ParseProc for each keyword to let the
  189. caller handle appropriately. Passes the newly-constucted
  190. TABLEENTRY to AddTableEntry to save it, and frees the temporary
  191. memory.
  192. This function is re-entrant.
  193. The ENTRYDATA struct is declared on ParseEntry's stack
  194. but used by the ParseProc to maintain state between
  195. calls-- e.g., whether or not a key name has been found.
  196. This can't be maintained as a static in the ParseProc because
  197. the ParseProc may be reentered (for instance, if categories
  198. have subcategories).
  199. There are many possible error paths and there is some
  200. memory dealloc that needs to be done in an error case. Rather
  201. than do deallocs by hand on every error path or use a "goto
  202. cleanup" (ick!), items to be freed are added to a "cleanup
  203. list" and then CleanupAndReturn is called in an error condition,
  204. which frees items on the list and returns a specified value.
  205. ENTRY: hWnd-- parent window
  206. ppes-- PARSEENTRYSTRUCT that specifes type of entry, the
  207. parent table, a keyword list, a ParseProc callback
  208. and other goodies
  209. pfMore-- set to FALSE if at end of file
  210. EXIT: ERROR_SUCCESS if successful, otherwise an error code
  211. (can be ERROR_ALREADY_DISPLAYED)
  212. ********************************************************************/
  213. UINT ParseEntry(HWND hWnd,PARSEENTRYSTRUCT *ppes,BOOL *pfMore)
  214. {
  215. CHAR szWordBuf[WORDBUFSIZE+1];
  216. UINT uErr,nListIndex;
  217. BOOL fFoundEnd = FALSE;
  218. CLEANUPINFO CleanUp[CLEANLISTSIZE];
  219. PARSEPROCSTRUCT pps;
  220. ENTRYDATA EntryData;
  221. DWORD dwBufSize = DEFAULT_TMP_BUF_SIZE;
  222. TABLEENTRY *pTmp;
  223. memset(CleanUp,0,sizeof(CleanUp));
  224. memset(&pps,0,sizeof(pps));
  225. memset(&EntryData,0,sizeof(EntryData));
  226. pps.pdwBufSize = &dwBufSize;
  227. pps.pData = &EntryData;
  228. pps.pData->fParentHasKey = ppes->fParentHasKey;
  229. if (!(pps.pTableEntry = (TABLEENTRY *) GlobalAlloc(GPTR,*pps.pdwBufSize)))
  230. return ERROR_NOT_ENOUGH_MEMORY;
  231. AddCleanupItem(CleanUp,CLEANLISTSIZE,(HGLOBAL) pps.pTableEntry,
  232. CI_FREE);
  233. // initialize TABLEENTRY struct
  234. pps.pTableEntry->dwSize = ppes->dwStructSize;
  235. pps.pTableEntry->dwType = ppes->dwEntryType;
  236. pps.pEntryCmpList = ppes->pEntryCmpList;
  237. pps.hFile = ppes->hFile;
  238. // get the entry name
  239. if (!GetNextSectionWord(hWnd,ppes->hFile,szWordBuf,sizeof(szWordBuf),NULL,NULL,
  240. pfMore,&uErr))
  241. return CleanupAndReturn(uErr,CleanUp);
  242. // store the entry name in pTableEntry
  243. pTmp = (TABLEENTRY *) AddDataToEntry(pps.pTableEntry,
  244. szWordBuf,lstrlen(szWordBuf)+1,&(pps.pTableEntry->uOffsetName),
  245. pps.pdwBufSize);
  246. if (!pTmp)
  247. return CleanupAndReturn(ERROR_NOT_ENOUGH_MEMORY,CleanUp);
  248. pps.pTableEntry = pTmp;
  249. // loop through the body of the declaration
  250. while (!fFoundEnd && GetNextSectionWord(hWnd,ppes->hFile,szWordBuf,
  251. sizeof(szWordBuf),pps.pEntryCmpList,&nListIndex,pfMore,&uErr)) {
  252. if ( (uErr = (*ppes->pParseProc) (hWnd,nListIndex,&pps,pfMore,&fFoundEnd))
  253. != ERROR_SUCCESS)
  254. return CleanupAndReturn(uErr,CleanUp);
  255. }
  256. if (uErr != ERROR_SUCCESS)
  257. return CleanupAndReturn(uErr,CleanUp);
  258. // Last word was "END"
  259. // get the keyword that goes with "END" ("END CATGORY", "END POLICY", etc.)
  260. if (!GetNextSectionWord(hWnd,ppes->hFile,szWordBuf,sizeof(szWordBuf),
  261. ppes->pTypeCmpList,&nListIndex,pfMore,&uErr))
  262. return CleanupAndReturn(uErr,CleanUp);
  263. // call the object's parse proc one last time to let it object if
  264. // key name or something like that is missing
  265. if ( (uErr = (*ppes->pParseProc) (hWnd,KYWD_DONE,&pps,pfMore,&fFoundEnd))
  266. != ERROR_SUCCESS)
  267. return CleanupAndReturn(uErr,CleanUp);
  268. // fix up linked list pointers. If parent has no children yet, make this
  269. // 1st child; otherwise walk the list of children and insert this at the end
  270. if (!ppes->pParent->pChild) {
  271. ppes->pParent->pChild = pps.pTableEntry;
  272. } else {
  273. TABLEENTRY * pLastChild = ppes->pParent->pChild;
  274. while (pLastChild->pNext) {
  275. pLastChild = pLastChild->pNext;
  276. }
  277. pLastChild->pNext = pps.pTableEntry;
  278. }
  279. return ERROR_SUCCESS;
  280. }
  281. /*******************************************************************
  282. NAME: ParseCategory
  283. SYNOPSIS: Parses a category
  284. NOTES: Sets up a PARSEENTRYSTRUCT and lets ParseEntry do the
  285. work.
  286. ********************************************************************/
  287. UINT ParseCategory(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
  288. BOOL fParentHasKey,BOOL *pfMore)
  289. {
  290. PARSEENTRYSTRUCT pes;
  291. pes.hFile = hFile;
  292. pes.pParent = pParent;
  293. pes.dwEntryType = ETYPE_CATEGORY;
  294. pes.pEntryCmpList = pCategoryEntryCmpList;
  295. pes.pTypeCmpList = pCategoryTypeCmpList;
  296. pes.pParseProc = &CategoryParseProc;
  297. pes.dwStructSize = sizeof(CATEGORY);
  298. pes.fHasSubtable = TRUE;
  299. pes.fParentHasKey = fParentHasKey;
  300. return ParseEntry(hWnd,&pes,pfMore);
  301. }
  302. /*******************************************************************
  303. NAME: CategoryParseProc
  304. SYNOPSIS: Keyword callback ParseProc for category parsing
  305. ENTRY: nMsg-- index into pEntryCmpList array which specifies
  306. keyword that was found.
  307. ppps-- pointer to PARSEPROCSTRUCT that contains useful
  308. data like a pointer to the TABLEENTRY being built
  309. and a pointer to an ENTRYDATA struct to maintain
  310. state between calls to the ParseProc
  311. ********************************************************************/
  312. UINT CategoryParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
  313. BOOL * pfMore,BOOL * pfFoundEnd)
  314. {
  315. CHAR szWordBuf[WORDBUFSIZE+1];
  316. CATEGORY * pCategory = (CATEGORY *) ppps->pTableEntry;
  317. TABLEENTRY * pOld = ppps->pTableEntry;
  318. UINT uErr;
  319. DWORD dwDelta;
  320. TABLEENTRY *pTmp;
  321. switch (nMsg) {
  322. case KYWD_ID_KEYNAME:
  323. // have we already found a key name?
  324. if (ppps->pData->fHasKey) {
  325. DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_KEYNAME,
  326. NULL,NULL,pszParseFileName,nFileLine);
  327. return ERROR_ALREADY_DISPLAYED;
  328. }
  329. // get the key name
  330. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  331. NULL,NULL,pfMore,&uErr))
  332. return uErr;
  333. // store the key name in pCategory
  334. pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pCategory,
  335. szWordBuf,lstrlen(szWordBuf)+1,&(pCategory->uOffsetKeyName),
  336. ppps->pdwBufSize);
  337. if (!pTmp)
  338. return ERROR_NOT_ENOUGH_MEMORY;
  339. ppps->pTableEntry = pTmp;
  340. // fix up other pointers
  341. dwDelta = (DWORD)(ppps->pTableEntry - pOld);
  342. ppps->pData->fHasKey = TRUE;
  343. return ERROR_SUCCESS;
  344. break;
  345. case KYWD_ID_END:
  346. *pfFoundEnd = TRUE;
  347. return ERROR_SUCCESS;
  348. break;
  349. case KYWD_ID_POLICY:
  350. case KYWD_ID_CATEGORY:
  351. {
  352. BOOL fHasKey = ppps->pData->fHasKey | ppps->pData->fParentHasKey;
  353. if (nMsg == KYWD_ID_POLICY)
  354. uErr=ParsePolicy(hWnd,ppps->hFile,
  355. (TABLEENTRY *) pCategory,fHasKey,pfMore);
  356. else
  357. uErr=ParseCategory(hWnd,ppps->hFile,
  358. (TABLEENTRY *) pCategory,fHasKey,pfMore);
  359. }
  360. return uErr;
  361. break;
  362. case KYWD_DONE:
  363. #if 0
  364. if (!ppps->pData->fHasKey) {
  365. DisplayKeywordError(hWnd,IDS_ParseErr_NO_KEYNAME,NULL,NULL,
  366. pszParseFileName,nFileLine);
  367. return ERROR_ALREADY_DISPLAYED;
  368. }
  369. #endif
  370. return ERROR_SUCCESS;
  371. break;
  372. default:
  373. return ERROR_SUCCESS;
  374. break;
  375. }
  376. }
  377. /*******************************************************************
  378. NAME: ParsePolicy
  379. SYNOPSIS: Parses a policy
  380. NOTES: Sets up a PARSEENTRYSTRUCT and lets ParseEntry do the
  381. work.
  382. ********************************************************************/
  383. UINT ParsePolicy(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
  384. BOOL fParentHasKey,BOOL *pfMore)
  385. {
  386. PARSEENTRYSTRUCT pes;
  387. pes.hFile = hFile;
  388. pes.pParent = pParent;
  389. pes.dwEntryType = ETYPE_POLICY;
  390. pes.pEntryCmpList = pPolicyEntryCmpList;
  391. pes.pTypeCmpList = pPolicyTypeCmpList;
  392. pes.pParseProc = &PolicyParseProc;
  393. pes.dwStructSize = sizeof(POLICY);
  394. pes.fHasSubtable = TRUE;
  395. pes.fParentHasKey = fParentHasKey;
  396. return ParseEntry(hWnd,&pes,pfMore);
  397. }
  398. /*******************************************************************
  399. NAME: PolicyParseProc
  400. SYNOPSIS: Keyword callback ParseProc for policy parsing
  401. ENTRY: nMsg-- index into pEntryCmpList array which specifies
  402. keyword that was found.
  403. ppps-- pointer to PARSEPROCSTRUCT that contains useful
  404. data like a pointer to the TABLEENTRY being built
  405. and a pointer to an ENTRYDATA struct to maintain
  406. state between calls to the ParseProc
  407. ********************************************************************/
  408. UINT PolicyParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
  409. BOOL * pfMore,BOOL * pfFoundEnd)
  410. {
  411. CHAR szWordBuf[WORDBUFSIZE+1];
  412. LPTSTR lpHelpBuf;
  413. POLICY * pPolicy = (POLICY *) ppps->pTableEntry;
  414. TABLEENTRY * pOld = ppps->pTableEntry;
  415. UINT uErr;
  416. DWORD dwDelta;
  417. TABLEENTRY *pTmp;
  418. switch (nMsg) {
  419. case KYWD_ID_KEYNAME:
  420. // have we already found a key name?
  421. if (ppps->pData->fHasKey) {
  422. DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_KEYNAME,
  423. NULL,NULL,pszParseFileName,nFileLine);
  424. return ERROR_ALREADY_DISPLAYED;
  425. }
  426. // get the key name
  427. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  428. NULL,NULL,pfMore,&uErr))
  429. return uErr;
  430. // store the key name in pPolicy
  431. pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pPolicy,
  432. szWordBuf,lstrlen(szWordBuf)+1,&(pPolicy->uOffsetKeyName),ppps->pdwBufSize);
  433. if (!pTmp)
  434. return ERROR_NOT_ENOUGH_MEMORY;
  435. ppps->pTableEntry = pTmp;
  436. // fix up other pointers
  437. dwDelta = (DWORD)(ppps->pTableEntry - pOld);
  438. ppps->pData->fHasKey = TRUE;
  439. return ERROR_SUCCESS;
  440. break;
  441. case KYWD_ID_VALUENAME:
  442. // have we already found a key name?
  443. if (ppps->pData->fHasValue) {
  444. DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_VALUENAME,
  445. NULL,NULL,pszParseFileName,nFileLine);
  446. return ERROR_ALREADY_DISPLAYED;
  447. }
  448. // get the key name
  449. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  450. NULL,NULL,pfMore,&uErr))
  451. return uErr;
  452. // store the key name in pSettings
  453. pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pPolicy,
  454. szWordBuf,lstrlen(szWordBuf)+1,&(pPolicy->uOffsetValueName),
  455. ppps->pdwBufSize);
  456. if (!pTmp)
  457. return ERROR_NOT_ENOUGH_MEMORY;
  458. ppps->pTableEntry = pTmp;
  459. // fix up other pointers
  460. dwDelta = (DWORD)(ppps->pTableEntry - pOld);
  461. ppps->pData->fHasValue = TRUE;
  462. return ERROR_SUCCESS;
  463. case KYWD_ID_HELP:
  464. lpHelpBuf = (LPTSTR) LocalAlloc (LPTR, HELPBUFSIZE * sizeof(TCHAR));
  465. if (!lpHelpBuf) {
  466. DisplayKeywordError(hWnd,IDS_ErrOUTOFMEMORY,
  467. NULL,NULL,pszParseFileName,nFileLine);
  468. return ERROR_ALREADY_DISPLAYED;
  469. }
  470. // get the help string
  471. if (!GetNextSectionWord(hWnd,ppps->hFile,lpHelpBuf,HELPBUFSIZE,
  472. NULL,NULL,pfMore,&uErr)) {
  473. LocalFree (lpHelpBuf);
  474. return uErr;
  475. }
  476. LocalFree (lpHelpBuf);
  477. return ERROR_SUCCESS;
  478. case KYWD_ID_CLIENTEXT:
  479. // get the clientext name
  480. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  481. NULL,NULL,pfMore,&uErr))
  482. return uErr;
  483. return ERROR_SUCCESS;
  484. case KYWD_ID_END:
  485. *pfFoundEnd = TRUE;
  486. return ERROR_SUCCESS;
  487. break;
  488. case KYWD_ID_PART:
  489. {
  490. BOOL fHasKey = ppps->pData->fHasKey | ppps->pData->fParentHasKey;
  491. return ParseSettings(hWnd,ppps->hFile,
  492. (TABLEENTRY *) pPolicy,fHasKey,pfMore);
  493. }
  494. break;
  495. case KYWD_ID_VALUEON:
  496. return ParseValue(hWnd,ppps,&pPolicy->uOffsetValue_On,
  497. &ppps->pTableEntry,pfMore);
  498. break;
  499. case KYWD_ID_VALUEOFF:
  500. return ParseValue(hWnd,ppps,&pPolicy->uOffsetValue_Off,
  501. &ppps->pTableEntry,pfMore);
  502. break;
  503. case KYWD_ID_ACTIONLISTON:
  504. return ParseActionList(hWnd,ppps,&pPolicy->uOffsetActionList_On,
  505. &ppps->pTableEntry,szACTIONLISTON,pfMore);
  506. break;
  507. case KYWD_ID_ACTIONLISTOFF:
  508. return ParseActionList(hWnd,ppps,&pPolicy->uOffsetActionList_Off,
  509. &ppps->pTableEntry,szACTIONLISTOFF,pfMore);
  510. break;
  511. case KYWD_DONE:
  512. if (!ppps->pData->fHasKey && !ppps->pData->fParentHasKey) {
  513. DisplayKeywordError(hWnd,IDS_ParseErr_NO_KEYNAME,NULL,NULL,
  514. pszParseFileName,nFileLine);
  515. return ERROR_ALREADY_DISPLAYED;
  516. }
  517. ( (POLICY *) ppps->pTableEntry)->uDataIndex = *pnDataItemCount;
  518. (*pnDataItemCount) ++;
  519. return ERROR_SUCCESS;
  520. break;
  521. default:
  522. return ERROR_SUCCESS;
  523. break;
  524. }
  525. }
  526. /*******************************************************************
  527. NAME: ParseSettings
  528. SYNOPSIS: Parses a policy setting
  529. NOTES: Sets up a PARSEENTRYSTRUCT and lets ParseEntry do the
  530. work.
  531. ********************************************************************/
  532. UINT ParseSettings(HWND hWnd,HANDLE hFile,TABLEENTRY * pParent,
  533. BOOL fParentHasKey,BOOL *pfMore)
  534. {
  535. PARSEENTRYSTRUCT pes;
  536. pes.hFile = hFile;
  537. pes.pParent = pParent;
  538. pes.dwEntryType = ETYPE_SETTING;
  539. pes.pEntryCmpList = pSettingsEntryCmpList;
  540. pes.pTypeCmpList = pSettingsTypeCmpList;
  541. pes.pParseProc = &SettingsParseProc;
  542. pes.dwStructSize = sizeof(SETTINGS);
  543. pes.fHasSubtable = FALSE;
  544. pes.fParentHasKey = fParentHasKey;
  545. return ParseEntry(hWnd,&pes,pfMore);
  546. }
  547. /*******************************************************************
  548. NAME: SettingsParseProc
  549. SYNOPSIS: Keyword callback ParseProc for policy settings parsing
  550. ENTRY: nMsg-- index into pEntryCmpList array which specifies
  551. keyword that was found.
  552. ppps-- pointer to PARSEPROCSTRUCT that contains useful
  553. data like a pointer to the TABLEENTRY being built
  554. and a pointer to an ENTRYDATA struct to maintain
  555. state between calls to the ParseProc
  556. ********************************************************************/
  557. UINT SettingsParseProc(HWND hWnd,UINT nMsg,PARSEPROCSTRUCT * ppps,
  558. BOOL * pfMore,BOOL * pfFoundEnd)
  559. {
  560. CHAR szWordBuf[WORDBUFSIZE+1];
  561. TABLEENTRY *pTmp;
  562. SETTINGS * pSettings = (SETTINGS *) ppps->pTableEntry;
  563. CHAR * pObjectData = GETOBJECTDATAPTR(pSettings);
  564. UINT uErr;
  565. switch (nMsg) {
  566. case KYWD_ID_KEYNAME:
  567. // have we already found a key name?
  568. if (ppps->pData->fHasKey) {
  569. DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_KEYNAME,
  570. NULL,NULL,pszParseFileName,nFileLine);
  571. return ERROR_ALREADY_DISPLAYED;
  572. }
  573. // get the key name
  574. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  575. NULL,NULL,pfMore,&uErr))
  576. return uErr;
  577. // store the key name in pSettings
  578. pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pSettings,
  579. szWordBuf,lstrlen(szWordBuf)+1,&(pSettings->uOffsetKeyName),ppps->pdwBufSize);
  580. if (!pTmp)
  581. return ERROR_NOT_ENOUGH_MEMORY;
  582. ppps->pTableEntry = pTmp;
  583. ppps->pData->fHasKey = TRUE;
  584. return ERROR_SUCCESS;
  585. break;
  586. case KYWD_ID_VALUENAME:
  587. // have we already found a value name?
  588. if (ppps->pData->fHasValue) {
  589. DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_VALUENAME,
  590. NULL,NULL,pszParseFileName,nFileLine);
  591. return ERROR_ALREADY_DISPLAYED;
  592. }
  593. // get the value name
  594. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  595. NULL,NULL,pfMore,&uErr))
  596. return uErr;
  597. // store the value name in pSettings
  598. pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pSettings,
  599. szWordBuf,lstrlen(szWordBuf)+1,&(pSettings->uOffsetValueName),
  600. ppps->pdwBufSize);
  601. if (!pTmp)
  602. return ERROR_NOT_ENOUGH_MEMORY;
  603. ppps->pTableEntry = pTmp;
  604. ppps->pData->fHasValue = TRUE;
  605. return ERROR_SUCCESS;
  606. break;
  607. case KYWD_ID_CLIENTEXT:
  608. // get the clientext name
  609. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  610. NULL,NULL,pfMore,&uErr))
  611. return uErr;
  612. return ERROR_SUCCESS;
  613. case KYWD_ID_REQUIRED:
  614. pSettings->dwFlags |= DF_REQUIRED;
  615. return ERROR_SUCCESS;
  616. break;
  617. case KYWD_ID_EXPANDABLETEXT:
  618. pSettings->dwFlags |= DF_EXPANDABLETEXT;
  619. return ERROR_SUCCESS;
  620. break;
  621. case KYWD_ID_SUGGESTIONS:
  622. return ParseSuggestions(hWnd,ppps,&((POLICYCOMBOBOXINFO *)
  623. (GETOBJECTDATAPTR(pSettings)))->uOffsetSuggestions,
  624. &ppps->pTableEntry,pfMore);
  625. case KYWD_ID_TXTCONVERT:
  626. pSettings->dwFlags |= DF_TXTCONVERT;
  627. return ERROR_SUCCESS;
  628. break;
  629. case KYWD_ID_END:
  630. *pfFoundEnd = TRUE;
  631. return ERROR_SUCCESS;
  632. break;
  633. case KYWD_ID_SOFT:
  634. pSettings->dwFlags |= VF_SOFT;
  635. return ERROR_SUCCESS;
  636. break;
  637. case KYWD_DONE:
  638. if (!ppps->pData->fHasKey && !ppps->pData->fParentHasKey) {
  639. DisplayKeywordError(hWnd,IDS_ParseErr_NO_KEYNAME,NULL,NULL,
  640. pszParseFileName,nFileLine);
  641. return ERROR_ALREADY_DISPLAYED;
  642. }
  643. if (!ppps->pData->fHasValue) {
  644. DisplayKeywordError(hWnd,IDS_ParseErr_NO_VALUENAME,NULL,NULL,
  645. pszParseFileName,nFileLine);
  646. return ERROR_ALREADY_DISPLAYED;
  647. }
  648. ( (SETTINGS *) ppps->pTableEntry)->uDataIndex = *pnDataItemCount;
  649. (*pnDataItemCount) ++;
  650. return ERROR_SUCCESS;
  651. break;
  652. case KYWD_ID_CHECKBOX:
  653. return (InitSettingsParse(ppps,ETYPE_SETTING | STYPE_CHECKBOX,
  654. sizeof(CHECKBOXINFO),pCheckboxCmpList,&pSettings,&pObjectData));
  655. break;
  656. case KYWD_ID_TEXT:
  657. ppps->pData->fHasValue = TRUE; // no key value for static text items
  658. return (InitSettingsParse(ppps,ETYPE_SETTING | STYPE_TEXT,
  659. 0,pTextCmpList,&pSettings,&pObjectData));
  660. break;
  661. case KYWD_ID_EDITTEXT:
  662. uErr=InitSettingsParse(ppps,ETYPE_SETTING | STYPE_EDITTEXT,
  663. sizeof(EDITTEXTINFO),pEditTextCmpList,&pSettings,&pObjectData);
  664. if (uErr != ERROR_SUCCESS) return uErr;
  665. {
  666. EDITTEXTINFO *pEditTextInfo = (EDITTEXTINFO *)
  667. (GETOBJECTDATAPTR(((SETTINGS *) ppps->pTableEntry)));
  668. pEditTextInfo->nMaxLen = MAXSTRLEN;
  669. }
  670. break;
  671. case KYWD_ID_COMBOBOX:
  672. uErr=InitSettingsParse(ppps,ETYPE_SETTING | STYPE_COMBOBOX,
  673. sizeof(POLICYCOMBOBOXINFO),pComboboxCmpList,&pSettings,&pObjectData);
  674. if (uErr != ERROR_SUCCESS) return uErr;
  675. {
  676. EDITTEXTINFO *pEditTextInfo = (EDITTEXTINFO *)
  677. (GETOBJECTDATAPTR(((SETTINGS *) ppps->pTableEntry)));
  678. pEditTextInfo->nMaxLen = MAXSTRLEN;
  679. }
  680. break;
  681. case KYWD_ID_NUMERIC:
  682. uErr=InitSettingsParse(ppps,ETYPE_SETTING | STYPE_NUMERIC,
  683. sizeof(NUMERICINFO),pNumericCmpList,&pSettings,&pObjectData);
  684. if (uErr != ERROR_SUCCESS) return uErr;
  685. ( (NUMERICINFO *) pObjectData)->uDefValue = 1;
  686. ( (NUMERICINFO *) pObjectData)->uMinValue = 1;
  687. ( (NUMERICINFO *) pObjectData)->uMaxValue = 9999;
  688. ( (NUMERICINFO *) pObjectData)->uSpinIncrement = 1;
  689. break;
  690. case KYWD_ID_DROPDOWNLIST:
  691. ppps->pEntryCmpList = pDropdownlistCmpList;
  692. ppps->pTableEntry->dwType = ETYPE_SETTING | STYPE_DROPDOWNLIST;
  693. return ERROR_SUCCESS;
  694. break;
  695. case KYWD_ID_LISTBOX:
  696. uErr=InitSettingsParse(ppps,ETYPE_SETTING | STYPE_LISTBOX,
  697. sizeof(LISTBOXINFO),pListboxCmpList,&pSettings,&pObjectData);
  698. if (uErr != ERROR_SUCCESS) return uErr;
  699. // listboxes have no single value name, set the value name to ""
  700. pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *) pSettings,
  701. (CHAR *) szNull,lstrlen(szNull)+1,&(pSettings->uOffsetValueName),
  702. ppps->pdwBufSize);
  703. if (!pTmp)
  704. return ERROR_NOT_ENOUGH_MEMORY;
  705. ppps->pTableEntry = pTmp;
  706. ppps->pData->fHasValue = TRUE;
  707. return ERROR_SUCCESS;
  708. break;
  709. case KYWD_ID_EDITTEXT_DEFAULT:
  710. case KYWD_ID_COMBOBOX_DEFAULT:
  711. // get the default text
  712. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  713. NULL,NULL,pfMore,&uErr))
  714. return uErr;
  715. // store the default text in pTableEntry
  716. pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *)
  717. pSettings,szWordBuf,lstrlen(szWordBuf)+1,
  718. &((EDITTEXTINFO *) (GETOBJECTDATAPTR(pSettings)))->uOffsetDefText,
  719. ppps->pdwBufSize);
  720. if (!pTmp)
  721. return ERROR_NOT_ENOUGH_MEMORY;
  722. ppps->pTableEntry = pTmp;
  723. pSettings->dwFlags |= DF_USEDEFAULT;
  724. break;
  725. case KYWD_ID_MAXLENGTH:
  726. {
  727. EDITTEXTINFO *pEditTextInfo = (EDITTEXTINFO *)
  728. (GETOBJECTDATAPTR(pSettings));
  729. if ((uErr=GetNextSectionNumericWord(hWnd,ppps->hFile,
  730. &pEditTextInfo->nMaxLen)) != ERROR_SUCCESS)
  731. return uErr;
  732. }
  733. break;
  734. case KYWD_ID_MAX:
  735. if ((uErr=GetNextSectionNumericWord(hWnd,ppps->hFile,
  736. &((NUMERICINFO *)pObjectData)->uMaxValue)) != ERROR_SUCCESS)
  737. return uErr;
  738. break;
  739. case KYWD_ID_MIN:
  740. if ((uErr=GetNextSectionNumericWord(hWnd,ppps->hFile,
  741. &((NUMERICINFO *)pObjectData)->uMinValue)) != ERROR_SUCCESS)
  742. return uErr;
  743. break;
  744. case KYWD_ID_SPIN:
  745. if ((uErr=GetNextSectionNumericWord(hWnd,ppps->hFile,
  746. &((NUMERICINFO *)pObjectData)->uSpinIncrement)) != ERROR_SUCCESS)
  747. return uErr;
  748. break;
  749. case KYWD_ID_NUMERIC_DEFAULT:
  750. if ((uErr=GetNextSectionNumericWord(hWnd,ppps->hFile,
  751. &((NUMERICINFO *)pObjectData)->uDefValue)) != ERROR_SUCCESS)
  752. return uErr;
  753. pSettings->dwFlags |= (DF_DEFCHECKED | DF_USEDEFAULT);
  754. break;
  755. case KYWD_ID_DEFCHECKED:
  756. pSettings->dwFlags |= (DF_DEFCHECKED | DF_USEDEFAULT);
  757. break;
  758. case KYWD_ID_VALUEON:
  759. return ParseValue(hWnd,ppps,&((CHECKBOXINFO *)
  760. pObjectData)->uOffsetValue_On,
  761. &ppps->pTableEntry,pfMore);
  762. break;
  763. case KYWD_ID_VALUEOFF:
  764. return ParseValue(hWnd,ppps,&((CHECKBOXINFO *)
  765. pObjectData)->uOffsetValue_Off,
  766. &ppps->pTableEntry,pfMore);
  767. break;
  768. case KYWD_ID_ACTIONLISTON:
  769. return ParseActionList(hWnd,ppps,&((CHECKBOXINFO *)
  770. pObjectData)->uOffsetActionList_On,
  771. &ppps->pTableEntry,szACTIONLISTON,pfMore);
  772. break;
  773. case KYWD_ID_ACTIONLISTOFF:
  774. return ParseActionList(hWnd,ppps,&((CHECKBOXINFO *)
  775. pObjectData)->uOffsetActionList_Off,
  776. &ppps->pTableEntry,szACTIONLISTOFF,pfMore);
  777. break;
  778. case KYWD_ID_ITEMLIST:
  779. return ParseItemList(hWnd,ppps,&pSettings->uOffsetObjectData,
  780. pfMore);
  781. break;
  782. case KYWD_ID_VALUEPREFIX:
  783. // get the string to be ised as prefix
  784. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  785. NULL,NULL,pfMore,&uErr))
  786. return uErr;
  787. // store the string pTableEntry
  788. pTmp = (TABLEENTRY *) AddDataToEntry((TABLEENTRY *)
  789. pSettings,szWordBuf,lstrlen(szWordBuf)+1,
  790. &((LISTBOXINFO *) (GETOBJECTDATAPTR(pSettings)))->uOffsetPrefix,
  791. ppps->pdwBufSize);
  792. if (!pTmp)
  793. return ERROR_NOT_ENOUGH_MEMORY;
  794. ppps->pTableEntry = pTmp;
  795. break;
  796. case KYWD_ID_ADDITIVE:
  797. pSettings->dwFlags |= DF_ADDITIVE;
  798. return ERROR_SUCCESS;
  799. break;
  800. case KYWD_ID_EXPLICITVALUE:
  801. pSettings->dwFlags |= DF_EXPLICITVALNAME;
  802. return ERROR_SUCCESS;
  803. break;
  804. case KYWD_ID_NOSORT:
  805. pSettings->dwFlags |= DF_NOSORT;
  806. break;
  807. }
  808. return ERROR_SUCCESS;
  809. }
  810. UINT InitSettingsParse(PARSEPROCSTRUCT *ppps,DWORD dwType,DWORD dwSize,
  811. KEYWORDINFO * pKeyList,SETTINGS ** ppSettings,CHAR **ppObjectData)
  812. {
  813. TABLEENTRY *pTmp;
  814. if (dwSize) {
  815. // increase the buffer to fit object-specific data if specified
  816. pTmp = (TABLEENTRY *) AddDataToEntry(ppps->pTableEntry,
  817. NULL,dwSize,&( ((SETTINGS * )ppps->pTableEntry)->uOffsetObjectData),
  818. ppps->pdwBufSize);
  819. if (!pTmp) return ERROR_NOT_ENOUGH_MEMORY;
  820. ppps->pTableEntry = pTmp;
  821. }
  822. else ( (SETTINGS *) ppps->pTableEntry)->uOffsetObjectData= 0;
  823. ppps->pEntryCmpList = pKeyList;
  824. ppps->pTableEntry->dwType = dwType;
  825. *ppSettings = (SETTINGS *) ppps->pTableEntry;
  826. *ppObjectData = GETOBJECTDATAPTR((*ppSettings));
  827. return ERROR_SUCCESS;
  828. }
  829. UINT ParseValue_W(HWND hWnd,PARSEPROCSTRUCT * ppps,CHAR * pszWordBuf,
  830. DWORD cbWordBuf,DWORD * pdwValue,DWORD * pdwFlags,BOOL * pfMore)
  831. {
  832. UINT uErr;
  833. *pdwFlags = 0;
  834. *pdwValue = 0;
  835. // get the next word
  836. if (!GetNextSectionWord(hWnd,ppps->hFile,pszWordBuf,cbWordBuf,
  837. NULL,NULL,pfMore,&uErr))
  838. return uErr;
  839. // if this keyword is "SOFT", set the soft flag and get the next word
  840. if (!lstrcmpi(szSOFT,pszWordBuf)) {
  841. *pdwFlags |= VF_SOFT;
  842. if (!GetNextSectionWord(hWnd,ppps->hFile,pszWordBuf,cbWordBuf,
  843. NULL,NULL,pfMore,&uErr))
  844. return uErr;
  845. }
  846. // this word is either the value to use, or the keyword "NUMERIC"
  847. // followed by a numeric value to use
  848. if (!lstrcmpi(szNUMERIC,pszWordBuf)) {
  849. // get the next word
  850. if (!GetNextSectionWord(hWnd,ppps->hFile,pszWordBuf,cbWordBuf,
  851. NULL,NULL,pfMore,&uErr))
  852. return uErr;
  853. if (!StringToNum(pszWordBuf,pdwValue)) {
  854. DisplayKeywordError(hWnd,IDS_ParseErr_NOT_NUMERIC,
  855. pszWordBuf,NULL,pszParseFileName,nFileLine);
  856. return ERROR_ALREADY_DISPLAYED;
  857. }
  858. *pdwFlags |= VF_ISNUMERIC;
  859. } else {
  860. // "DELETE" is a special word
  861. if (!lstrcmpi(pszWordBuf,szDELETE))
  862. *pdwFlags |= VF_DELETE;
  863. }
  864. return ERROR_SUCCESS;
  865. }
  866. UINT ParseValue(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
  867. TABLEENTRY ** ppTableEntryNew,BOOL * pfMore)
  868. {
  869. CHAR szWordBuf[WORDBUFSIZE+1];
  870. STATEVALUE * pStateValue;
  871. DWORD dwValue;
  872. DWORD dwFlags = 0;
  873. DWORD dwAlloc;
  874. UINT uErr;
  875. TABLEENTRY *pTmp;
  876. // call worker function
  877. uErr=ParseValue_W(hWnd,ppps,szWordBuf,sizeof(szWordBuf),&dwValue,
  878. &dwFlags,pfMore);
  879. if (uErr != ERROR_SUCCESS) return uErr;
  880. dwAlloc = sizeof(STATEVALUE);
  881. if (!dwFlags) dwAlloc += lstrlen(szWordBuf) + 1;
  882. // allocate temporary buffer to build STATEVALUE struct
  883. pStateValue = (STATEVALUE *) GlobalAlloc(GPTR,dwAlloc);
  884. if (!pStateValue)
  885. return ERROR_NOT_ENOUGH_MEMORY;
  886. pStateValue->dwFlags = dwFlags;
  887. if (dwFlags & VF_ISNUMERIC)
  888. pStateValue->dwValue = dwValue;
  889. else if (!dwFlags) {
  890. lstrcpy(pStateValue->szValue,szWordBuf);
  891. }
  892. pTmp=(TABLEENTRY *) AddDataToEntry(ppps->pTableEntry,
  893. (CHAR *) pStateValue,dwAlloc,puOffsetData,NULL);
  894. GlobalFree(pStateValue);
  895. if (!pTmp)
  896. return ERROR_NOT_ENOUGH_MEMORY;
  897. (*ppTableEntryNew) = pTmp;
  898. return FALSE;
  899. }
  900. #define DEF_SUGGESTBUF_SIZE 1024
  901. #define SUGGESTBUF_INCREMENT 256
  902. UINT ParseSuggestions(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
  903. TABLEENTRY ** ppTableEntryNew,BOOL * pfMore)
  904. {
  905. CHAR szWordBuf[WORDBUFSIZE+1];
  906. CHAR *pTmpBuf, *pTmp;
  907. DWORD dwAlloc=DEF_SUGGESTBUF_SIZE;
  908. DWORD dwUsed = 0;
  909. BOOL fContinue = TRUE;
  910. UINT uErr;
  911. TABLEENTRY *pTmpTblEntry;
  912. KEYWORDINFO pSuggestionsTypeCmpList[] = { {szSUGGESTIONS,KYWD_ID_SUGGESTIONS},
  913. {NULL,0} };
  914. if (!(pTmpBuf = (CHAR *) GlobalAlloc(GPTR,dwAlloc)))
  915. return ERROR_NOT_ENOUGH_MEMORY;
  916. // get the next word
  917. while (fContinue && GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,
  918. sizeof(szWordBuf),NULL,NULL,pfMore,&uErr)) {
  919. // if this word is "END", add the whole list to the setting object data
  920. if (!lstrcmpi(szEND,szWordBuf)) {
  921. // get the next word after "END, make sure it's "SUGGESTIONS"
  922. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  923. pSuggestionsTypeCmpList,NULL,pfMore,&uErr)) {
  924. GlobalFree(pTmpBuf);
  925. return uErr;
  926. }
  927. // doubly-NULL terminate the list
  928. *(pTmpBuf+dwUsed) = '\0';
  929. dwUsed++;
  930. pTmpTblEntry=(TABLEENTRY *)AddDataToEntry(ppps->pTableEntry,
  931. pTmpBuf,dwUsed,puOffsetData,NULL);
  932. if (!pTmpTblEntry) {
  933. GlobalFree(pTmpBuf);
  934. return ERROR_NOT_ENOUGH_MEMORY;
  935. }
  936. *ppTableEntryNew=pTmpTblEntry;
  937. fContinue = FALSE;
  938. } else {
  939. // pack the word into the temporary buffer
  940. UINT nLength = lstrlen(szWordBuf);
  941. DWORD dwNeeded = dwUsed + nLength + 2;
  942. // resize buffer as necessary
  943. if (dwNeeded > dwAlloc) {
  944. while (dwAlloc < dwNeeded)
  945. dwAlloc += SUGGESTBUF_INCREMENT;
  946. if (!(pTmp = (CHAR *) GlobalReAlloc(pTmpBuf,dwAlloc,
  947. GMEM_MOVEABLE | GMEM_ZEROINIT))) {
  948. GlobalFree(pTmpBuf);
  949. return ERROR_NOT_ENOUGH_MEMORY;
  950. }
  951. pTmpBuf = pTmp;
  952. }
  953. lstrcpy(pTmpBuf + dwUsed,szWordBuf);
  954. dwUsed += lstrlen(szWordBuf) +1;
  955. }
  956. }
  957. GlobalFree(pTmpBuf);
  958. return uErr;
  959. }
  960. UINT ParseActionList(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
  961. TABLEENTRY ** ppTableEntryNew,LPCSTR pszKeyword,BOOL * pfMore)
  962. {
  963. CHAR szWordBuf[WORDBUFSIZE+1];
  964. ACTIONLIST *pActionList;
  965. ACTION *pActionCurrent;
  966. UINT uOffsetActionCurrent;
  967. DWORD dwAlloc=DEF_SUGGESTBUF_SIZE;
  968. DWORD dwUsed = sizeof(ACTION) + sizeof(UINT);
  969. UINT uErr=ERROR_SUCCESS,nIndex;
  970. BOOL fContinue = TRUE;
  971. KEYWORDINFO pActionlistTypeCmpList[] = { {szKEYNAME,KYWD_ID_KEYNAME},
  972. {szVALUENAME,KYWD_ID_VALUENAME},{szVALUE,KYWD_ID_VALUE},
  973. {szEND,KYWD_ID_END},{NULL,0} };
  974. KEYWORDINFO pActionlistCmpList[] = { {pszKeyword,KYWD_ID_ACTIONLIST},
  975. {NULL,0} };
  976. BOOL fHasKeyName=FALSE,fHasValueName=FALSE;
  977. BOOL AddActionListString(CHAR * pszData,DWORD cbData,CHAR ** ppBase,UINT * puOffset,
  978. DWORD * pdwAlloc,DWORD * pdwUsed);
  979. TABLEENTRY *pTmp;
  980. if (!(pActionList = (ACTIONLIST *) GlobalAlloc(GPTR,dwAlloc)))
  981. return ERROR_NOT_ENOUGH_MEMORY;
  982. pActionCurrent = pActionList->Action;
  983. uOffsetActionCurrent = sizeof(UINT);
  984. // get the next word
  985. while ((uErr == ERROR_SUCCESS) && fContinue &&
  986. GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  987. pActionlistTypeCmpList,&nIndex,pfMore,&uErr)) {
  988. switch (nIndex) {
  989. case KYWD_ID_KEYNAME:
  990. if (fHasKeyName) {
  991. DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_KEYNAME,
  992. NULL,NULL,pszParseFileName,nFileLine);
  993. uErr = ERROR_ALREADY_DISPLAYED;
  994. break;
  995. }
  996. // get the next word, which is the key name
  997. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,
  998. sizeof(szWordBuf),NULL,NULL,pfMore,&uErr))
  999. break;
  1000. // store the key name away
  1001. if (!AddActionListString(szWordBuf,lstrlen(szWordBuf)+1,
  1002. (CHAR **)&pActionList,
  1003. &pActionCurrent->uOffsetKeyName,&dwAlloc,&dwUsed)) {
  1004. uErr = ERROR_NOT_ENOUGH_MEMORY;
  1005. break;
  1006. }
  1007. fHasKeyName = TRUE;
  1008. pActionCurrent = (ACTION *) ((CHAR *) pActionList + uOffsetActionCurrent);
  1009. break;
  1010. case KYWD_ID_VALUENAME:
  1011. if (fHasValueName) {
  1012. DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_KEYNAME,
  1013. NULL,NULL,pszParseFileName,nFileLine);
  1014. uErr = ERROR_ALREADY_DISPLAYED;
  1015. break;
  1016. }
  1017. // get the next word, which is the value name
  1018. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,
  1019. sizeof(szWordBuf),NULL,NULL,pfMore,&uErr))
  1020. break;
  1021. // store the value name away
  1022. if (!AddActionListString(szWordBuf,lstrlen(szWordBuf)+1,
  1023. (CHAR **)&pActionList,
  1024. &pActionCurrent->uOffsetValueName,&dwAlloc,&dwUsed)) {
  1025. uErr = ERROR_NOT_ENOUGH_MEMORY;
  1026. break;
  1027. }
  1028. fHasValueName = TRUE;
  1029. pActionCurrent = (ACTION *) ((CHAR *) pActionList + uOffsetActionCurrent);
  1030. break;
  1031. case KYWD_ID_VALUE:
  1032. if (!fHasValueName) {
  1033. DisplayKeywordError(hWnd,IDS_ParseErr_NO_VALUENAME,
  1034. NULL,NULL,pszParseFileName,nFileLine);
  1035. uErr = ERROR_ALREADY_DISPLAYED;
  1036. break;
  1037. }
  1038. // call worker function to get value and value type
  1039. uErr=ParseValue_W(hWnd,ppps,szWordBuf,sizeof(szWordBuf),
  1040. &pActionCurrent->dwValue,&pActionCurrent->dwFlags,pfMore);
  1041. if (uErr != ERROR_SUCCESS)
  1042. break;
  1043. // if value is string, add it to buffer
  1044. if (!pActionCurrent->dwFlags && !AddActionListString(szWordBuf,
  1045. lstrlen(szWordBuf)+1,(CHAR **)&pActionList,
  1046. &pActionCurrent->uOffsetValue,&dwAlloc,&dwUsed)) {
  1047. uErr = ERROR_NOT_ENOUGH_MEMORY;
  1048. break;
  1049. }
  1050. pActionCurrent = (ACTION *) ((CHAR *) pActionList + uOffsetActionCurrent);
  1051. // done with this action in the list, get ready for the next one
  1052. pActionList->nActionItems++;
  1053. fHasValueName = fHasKeyName = FALSE;
  1054. uOffsetActionCurrent = dwUsed;
  1055. // make room for next ACTION struct
  1056. if (!AddActionListString(NULL,sizeof(ACTION),(CHAR **)&pActionList,
  1057. &pActionCurrent->uOffsetNextAction,&dwAlloc,&dwUsed)) {
  1058. uErr = ERROR_NOT_ENOUGH_MEMORY;
  1059. break;
  1060. }
  1061. pActionCurrent = (ACTION *) ((CHAR *) pActionList + uOffsetActionCurrent);
  1062. break;
  1063. case KYWD_ID_END:
  1064. if (fHasKeyName || fHasValueName) {
  1065. DisplayKeywordError(hWnd,IDS_ParseErr_NO_VALUENAME,
  1066. NULL,NULL,pszParseFileName,nFileLine);
  1067. uErr = ERROR_ALREADY_DISPLAYED;
  1068. break;
  1069. }
  1070. // make sure word following "END" is "ACTIONLIST"
  1071. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  1072. pActionlistCmpList,NULL,pfMore,&uErr)) {
  1073. break;
  1074. }
  1075. // commit the action list we've built to table entry
  1076. pTmp=(TABLEENTRY *)AddDataToEntry(ppps->pTableEntry,
  1077. (CHAR *)pActionList,dwUsed,puOffsetData,NULL);
  1078. if (!pTmp) {
  1079. uErr=ERROR_NOT_ENOUGH_MEMORY;
  1080. } else {
  1081. uErr = ERROR_SUCCESS;
  1082. *ppTableEntryNew = pTmp;
  1083. fContinue = FALSE;
  1084. }
  1085. break;
  1086. }
  1087. }
  1088. GlobalFree(pActionList);
  1089. return uErr;
  1090. }
  1091. UINT ParseItemList(HWND hWnd,PARSEPROCSTRUCT * ppps,UINT * puOffsetData,
  1092. BOOL * pfMore)
  1093. {
  1094. // ptr to location to put the offset to next DROPDOWNINFO struct in chain
  1095. UINT * puLastOffsetPtr = puOffsetData;
  1096. TABLEENTRY * pTableEntryOld;
  1097. TABLEENTRY *pTmp;
  1098. int nItemIndex=-1;
  1099. BOOL fHasItemName = FALSE,fHasActionList=FALSE,fHasValue=FALSE,fFirst=TRUE;
  1100. DROPDOWNINFO * pddi;
  1101. CHAR szWordBuf[WORDBUFSIZE+1];
  1102. UINT uErr=ERROR_SUCCESS,nIndex;
  1103. KEYWORDINFO pItemlistTypeCmpList[] = { {szNAME,KYWD_ID_NAME},
  1104. {szACTIONLIST,KYWD_ID_ACTIONLIST},{szVALUE,KYWD_ID_VALUE},
  1105. {szEND,KYWD_ID_END},{szDEFAULT,KYWD_ID_DEFAULT},{NULL,0} };
  1106. KEYWORDINFO pItemlistCmpList[] = { {szITEMLIST,KYWD_ID_ITEMLIST},
  1107. {NULL,0} };
  1108. // get the next word
  1109. while ((uErr == ERROR_SUCCESS) &&
  1110. GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  1111. pItemlistTypeCmpList,&nIndex,pfMore,&uErr)) {
  1112. switch (nIndex) {
  1113. case KYWD_ID_NAME:
  1114. // if this is the first keyword after a prior item
  1115. // (e.g., item and value flags both set) reset for next one
  1116. if (fHasItemName && fHasValue) {
  1117. fHasValue = fHasActionList= fHasItemName = FALSE;
  1118. puLastOffsetPtr = &pddi->uOffsetNextDropdowninfo;
  1119. }
  1120. if (fHasItemName) {
  1121. DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_ITEMNAME,
  1122. NULL,NULL,pszParseFileName,nFileLine);
  1123. uErr = ERROR_ALREADY_DISPLAYED;
  1124. break;
  1125. }
  1126. // get the next word, which is the item name
  1127. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,
  1128. sizeof(szWordBuf),NULL,NULL,pfMore,&uErr))
  1129. break;
  1130. // add room for a DROPDOWNINFO struct at end of buffer
  1131. pTableEntryOld=ppps->pTableEntry;
  1132. pTmp=(TABLEENTRY *)AddDataToEntry(ppps->pTableEntry,
  1133. NULL,sizeof(DROPDOWNINFO),puLastOffsetPtr,NULL);
  1134. if (!pTmp)
  1135. return ERROR_NOT_ENOUGH_MEMORY;
  1136. ppps->pTableEntry=pTmp;
  1137. // adjust pointer to offset, in case table moved
  1138. puLastOffsetPtr = (UINT *) (((BYTE *) puLastOffsetPtr) +
  1139. ((BYTE *) ppps->pTableEntry - (BYTE *) pTableEntryOld));
  1140. pddi = (DROPDOWNINFO *)
  1141. ((CHAR *) ppps->pTableEntry + *puLastOffsetPtr);
  1142. // store the key name away
  1143. pTableEntryOld=ppps->pTableEntry;
  1144. pTmp=(TABLEENTRY *)AddDataToEntry(ppps->pTableEntry,
  1145. szWordBuf,lstrlen(szWordBuf)+1,&pddi->uOffsetItemName,
  1146. NULL);
  1147. if (!pTmp)
  1148. return ERROR_NOT_ENOUGH_MEMORY;
  1149. ppps->pTableEntry = pTmp;
  1150. // adjust pointer to offset, in case table moved
  1151. puLastOffsetPtr = (UINT *) (((BYTE *) puLastOffsetPtr) +
  1152. ((BYTE *) ppps->pTableEntry - (BYTE *) pTableEntryOld));
  1153. pddi = (DROPDOWNINFO *)
  1154. ((CHAR *) ppps->pTableEntry + *puLastOffsetPtr);
  1155. nItemIndex++;
  1156. fHasItemName = TRUE;
  1157. break;
  1158. case KYWD_ID_DEFAULT:
  1159. if (nItemIndex<0) {
  1160. DisplayKeywordError(hWnd,IDS_ParseErr_NO_ITEMNAME,
  1161. NULL,NULL,pszParseFileName,nFileLine);
  1162. uErr = ERROR_ALREADY_DISPLAYED;
  1163. break;
  1164. }
  1165. ( (SETTINGS *) ppps->pTableEntry)->dwFlags |= DF_USEDEFAULT;
  1166. ( (DROPDOWNINFO *) GETOBJECTDATAPTR(((SETTINGS *)ppps->pTableEntry)))
  1167. ->uDefaultItemIndex = nItemIndex;
  1168. break;
  1169. case KYWD_ID_VALUE:
  1170. if (!fHasItemName) {
  1171. DisplayKeywordError(hWnd,IDS_ParseErr_NO_ITEMNAME,
  1172. NULL,NULL,pszParseFileName,nFileLine);
  1173. uErr = ERROR_ALREADY_DISPLAYED;
  1174. break;
  1175. }
  1176. // call worker function to get value and value type
  1177. uErr=ParseValue_W(hWnd,ppps,szWordBuf,sizeof(szWordBuf),
  1178. &pddi->dwValue,&pddi->dwFlags,pfMore);
  1179. if (uErr != ERROR_SUCCESS)
  1180. break;
  1181. // if value is string, add it to buffer
  1182. if (!pddi->dwFlags) {
  1183. // store the key name away
  1184. pTableEntryOld = ppps->pTableEntry;
  1185. pTmp=(TABLEENTRY *) AddDataToEntry(ppps->pTableEntry,
  1186. szWordBuf,lstrlen(szWordBuf)+1,&pddi->uOffsetValue,
  1187. NULL);
  1188. if (!pTmp)
  1189. return ERROR_NOT_ENOUGH_MEMORY;
  1190. ppps->pTableEntry = pTmp;
  1191. // adjust pointer to offset, in case table moved
  1192. puLastOffsetPtr = (UINT *) (((BYTE *) puLastOffsetPtr) +
  1193. ((BYTE *) ppps->pTableEntry - (BYTE *) pTableEntryOld));
  1194. pddi = (DROPDOWNINFO *)
  1195. ((CHAR *) ppps->pTableEntry + *puLastOffsetPtr);
  1196. }
  1197. fHasValue = TRUE;
  1198. break;
  1199. case KYWD_ID_ACTIONLIST:
  1200. if (!fHasItemName) {
  1201. DisplayKeywordError(hWnd,IDS_ParseErr_NO_ITEMNAME,
  1202. NULL,NULL,pszParseFileName,nFileLine);
  1203. uErr = ERROR_ALREADY_DISPLAYED;
  1204. break;
  1205. }
  1206. if (fHasActionList) {
  1207. DisplayKeywordError(hWnd,IDS_ParseErr_DUPLICATE_ACTIONLIST,
  1208. NULL,NULL,pszParseFileName,nFileLine);
  1209. uErr = ERROR_ALREADY_DISPLAYED;
  1210. break;
  1211. }
  1212. pTableEntryOld=ppps->pTableEntry;
  1213. uErr=ParseActionList(hWnd,ppps,&pddi->uOffsetActionList,
  1214. &ppps->pTableEntry,szACTIONLIST,pfMore);
  1215. if (uErr != ERROR_SUCCESS)
  1216. return uErr;
  1217. // adjust pointer to offset, in case table moved
  1218. puLastOffsetPtr = (UINT *) (((BYTE *) puLastOffsetPtr) +
  1219. ((BYTE *) ppps->pTableEntry - (BYTE *) pTableEntryOld));
  1220. pddi = (DROPDOWNINFO *)
  1221. ((CHAR *) ppps->pTableEntry + *puLastOffsetPtr);
  1222. fHasActionList = TRUE;
  1223. break;
  1224. case KYWD_ID_END:
  1225. if (!fHasItemName) {
  1226. DisplayKeywordError(hWnd,IDS_ParseErr_NO_ITEMNAME,
  1227. NULL,NULL,pszParseFileName,nFileLine);
  1228. uErr = ERROR_ALREADY_DISPLAYED;
  1229. break;
  1230. }
  1231. if (!fHasValue) {
  1232. DisplayKeywordError(hWnd,IDS_ParseErr_NO_VALUE,
  1233. NULL,NULL,pszParseFileName,nFileLine);
  1234. uErr = ERROR_ALREADY_DISPLAYED;
  1235. break;
  1236. }
  1237. // make sure word following "END" is "ITEMLIST"
  1238. if (!GetNextSectionWord(hWnd,ppps->hFile,szWordBuf,sizeof(szWordBuf),
  1239. pItemlistCmpList,NULL,pfMore,&uErr)) {
  1240. break;
  1241. }
  1242. return ERROR_SUCCESS;
  1243. break;
  1244. }
  1245. }
  1246. return uErr;
  1247. }
  1248. BOOL AddActionListString(CHAR * pszData,DWORD cbData,CHAR ** ppBase,UINT * puOffset,
  1249. DWORD * pdwAlloc,DWORD *pdwUsed)
  1250. {
  1251. DWORD dwNeeded = *pdwUsed + cbData;
  1252. CHAR *pOldBase;
  1253. // realloc if necessary
  1254. if (dwNeeded > *pdwAlloc) {
  1255. while (*pdwAlloc < dwNeeded)
  1256. *pdwAlloc += SUGGESTBUF_INCREMENT;
  1257. pOldBase = *ppBase;
  1258. if (!(*ppBase = (CHAR *) GlobalReAlloc(*ppBase,*pdwAlloc,
  1259. GMEM_MOVEABLE | GMEM_ZEROINIT)))
  1260. return FALSE;
  1261. puOffset = (UINT *)(*ppBase + ((CHAR *)puOffset - pOldBase));
  1262. }
  1263. *puOffset = *pdwUsed;
  1264. if (pszData) memcpy(*ppBase + *puOffset,pszData,cbData);
  1265. *pdwUsed = dwNeeded;
  1266. return TRUE;
  1267. }
  1268. BOOL AddCleanupItem(CLEANUPINFO * pCleanUp,UINT nMax,HGLOBAL hMem, UINT nAction)
  1269. {
  1270. UINT nCount;
  1271. for (nCount=0;nCount<nMax;nCount++,pCleanUp++) {
  1272. if (!pCleanUp->hMem) {
  1273. pCleanUp->hMem = hMem;
  1274. pCleanUp->nAction = nAction;
  1275. return TRUE;
  1276. }
  1277. }
  1278. return FALSE;
  1279. }
  1280. UINT CleanupAndReturn(UINT uRetVal,CLEANUPINFO * pCleanUp)
  1281. {
  1282. while (pCleanUp->hMem) {
  1283. switch (pCleanUp->nAction) {
  1284. case CI_UNLOCKANDFREE:
  1285. GlobalUnlock(pCleanUp->hMem);
  1286. // fall through
  1287. case CI_FREE:
  1288. GlobalFree(pCleanUp->hMem);
  1289. break;
  1290. case CI_FREETABLE:
  1291. FreeTable(pCleanUp->hMem);
  1292. break;
  1293. }
  1294. pCleanUp ++;
  1295. }
  1296. return uRetVal;
  1297. }
  1298. CHAR * AddDataToEntry(TABLEENTRY * pTableEntry,CHAR * pszData,UINT cbData,
  1299. UINT * puOffsetData,DWORD * pdwBufSize)
  1300. {
  1301. TABLEENTRY * pTemp;
  1302. DWORD dwNeeded,dwOldSize = pTableEntry->dwSize;
  1303. // puOffsetData points to location that holds the offset to the
  1304. // new data-- size we're adding this to the end of the table, the
  1305. // offset will be the current size of the table. Set this offset
  1306. // in *puOffsetData. Also, notice we touch *puOffsetData BEFORE
  1307. // the realloc, in case puOffsetData points into the region being
  1308. // realloced and the block of memory moves.
  1309. *puOffsetData = pTableEntry->dwSize;
  1310. // reallocate entry buffer if necessary
  1311. dwNeeded = pTableEntry->dwSize + cbData;
  1312. if (!(pTemp = (TABLEENTRY *) GlobalReAlloc(pTableEntry,
  1313. dwNeeded,GMEM_ZEROINIT | GMEM_MOVEABLE))) {
  1314. return NULL;
  1315. }
  1316. pTableEntry = pTemp;
  1317. pTableEntry->dwSize = dwNeeded;
  1318. if (pszData) memcpy((CHAR *)pTableEntry + dwOldSize,pszData,cbData);
  1319. if (pdwBufSize) *pdwBufSize = pTableEntry->dwSize;
  1320. return (CHAR *) pTableEntry;
  1321. }
  1322. #define MSGSIZE 1024
  1323. #define FMTSIZE 512
  1324. VOID DisplayKeywordError(HWND hWnd,UINT uErrorID,CHAR * szFound,
  1325. KEYWORDINFO * pExpectedList,CHAR * szFilename,UINT nLine)
  1326. {
  1327. CHAR * pMsg,*pFmt,*pErrTxt,*pTmp;
  1328. pMsg = (CHAR *) GlobalAlloc(GPTR,MSGSIZE);
  1329. pFmt = (CHAR *) GlobalAlloc(GPTR,FMTSIZE);
  1330. pErrTxt = (CHAR *) GlobalAlloc(GPTR,FMTSIZE);
  1331. pTmp = (CHAR *) GlobalAlloc(GPTR,FMTSIZE);
  1332. if (!pMsg || !pFmt || !pErrTxt || !pTmp) {
  1333. if (pMsg) GlobalFree(pMsg);
  1334. if (pFmt) GlobalFree(pFmt);
  1335. if (pErrTxt) GlobalFree(pErrTxt);
  1336. if (pTmp) GlobalFree(pTmp);
  1337. MsgBox(hWnd,IDS_ErrOUTOFMEMORY,MB_ICONEXCLAMATION,MB_OK);
  1338. return;
  1339. }
  1340. LoadSz(IDS_ParseFmt_MSG_FORMAT,pFmt,FMTSIZE);
  1341. wsprintf(pMsg,pFmt,szFilename,nLine,uErrorID,LoadSz(uErrorID,
  1342. pErrTxt,FMTSIZE));
  1343. if (szFound) {
  1344. LoadSz(IDS_ParseFmt_FOUND,pFmt,FMTSIZE);
  1345. wsprintf(pTmp,pFmt,szFound);
  1346. lstrcat(pMsg,pTmp);
  1347. }
  1348. if (pExpectedList) {
  1349. UINT nIndex=0;
  1350. LoadSz(IDS_ParseFmt_EXPECTED,pFmt,FMTSIZE);
  1351. lstrcpy(pErrTxt,szNull);
  1352. while (pExpectedList[nIndex].pWord) {
  1353. lstrcat(pErrTxt,pExpectedList[nIndex].pWord);
  1354. if (pExpectedList[nIndex+1].pWord) {
  1355. lstrcat(pErrTxt,", ");
  1356. }
  1357. nIndex++;
  1358. }
  1359. wsprintf(pTmp,pFmt,pErrTxt);
  1360. lstrcat(pMsg,pTmp);
  1361. }
  1362. lstrcat(pMsg,LoadSz(IDS_ParseFmt_FATAL,pTmp,FMTSIZE));
  1363. MsgBoxSz(hWnd,pMsg,MB_ICONEXCLAMATION,MB_OK);
  1364. GlobalFree(pMsg);
  1365. GlobalFree(pFmt);
  1366. GlobalFree(pErrTxt);
  1367. GlobalFree(pTmp);
  1368. }
  1369. /*******************************************************************
  1370. NAME: CompareKeyword
  1371. SYNOPSIS: Compares a specified buffer to a list of valid keywords.
  1372. If it finds a match, the index of the match in the list
  1373. is returned in *pnListIndex. Otherwise an error message
  1374. is displayed.
  1375. EXIT: Returns TRUE if a keyword match is found, FALSE otherwise.
  1376. If TRUE, *pnListIndex contains matching index.
  1377. ********************************************************************/
  1378. BOOL CompareKeyword(HWND hWnd,CHAR * szWord,KEYWORDINFO *pKeywordList,
  1379. UINT * pnListIndex)
  1380. {
  1381. KEYWORDINFO * pKeywordInfo = pKeywordList;
  1382. while (pKeywordInfo->pWord) {
  1383. if (!lstrcmpi(szWord,pKeywordInfo->pWord)) {
  1384. if (pnListIndex)
  1385. *pnListIndex = pKeywordInfo->nID;
  1386. return TRUE;
  1387. }
  1388. pKeywordInfo ++;
  1389. }
  1390. DisplayKeywordError(hWnd,IDS_ParseErr_UNEXPECTED_KEYWORD,
  1391. szWord,pKeywordList,pszParseFileName,nFileLine);
  1392. return FALSE;
  1393. }
  1394. /*******************************************************************
  1395. NAME: PrivGetPrivateProfileString
  1396. SYNOPIS: Force GetPrivateProfileString to be Unicode
  1397. NOTES: NT4 has a bug where if were calling GetPrivateProfileStringA
  1398. and it's a Unicode ini file it will hit uninitialized
  1399. memory. Always call the W api to avoid this.
  1400. ********************************************************************/
  1401. #ifdef UNICODE
  1402. #define PrivGetPrivateProfileString GetPrivateProfileStringW
  1403. #else
  1404. DWORD PrivGetPrivateProfileString(LPCSTR szSection, LPCSTR szValue, LPCSTR szDefault, LPSTR szBuffer, DWORD cbBuffer, LPCSTR szFilename)
  1405. {
  1406. WCHAR wszSection[256];
  1407. WCHAR wszValue[256];
  1408. WCHAR wszDefault[256];
  1409. WCHAR wszFilename[256];
  1410. DWORD ret;
  1411. LPWSTR pwszBuffer;
  1412. pwszBuffer = LocalAlloc (LPTR, cbBuffer * sizeof(WCHAR));
  1413. if (!pwszBuffer) {
  1414. return GetLastError();
  1415. }
  1416. if (0 == MultiByteToWideChar(CP_ACP, 0, szSection, -1, wszSection, 256))
  1417. return 0;
  1418. if (0 == MultiByteToWideChar(CP_ACP, 0, szValue, -1, wszValue, 256))
  1419. return 0;
  1420. if (0 == MultiByteToWideChar(CP_ACP, 0, szDefault, -1, wszDefault, 256))
  1421. return 0;
  1422. if (0 == MultiByteToWideChar(CP_ACP, 0, szFilename, -1, wszFilename, 256))
  1423. return 0;
  1424. ret = GetPrivateProfileStringW(wszSection, wszValue, wszDefault, pwszBuffer, cbBuffer, wszFilename);
  1425. if (0 != ret)
  1426. if (0 == WideCharToMultiByte(CP_ACP, 0, pwszBuffer, -1, szBuffer, cbBuffer, NULL, NULL))
  1427. return 0;
  1428. LocalFree (pwszBuffer);
  1429. return ret;
  1430. }
  1431. #endif // !UNICODE
  1432. /*******************************************************************
  1433. NAME: GetNextWord
  1434. SYNOPSIS: Fills input buffer with next word in file stream
  1435. NOTES: Calls GetNextChar() to get character stream. Whitespace
  1436. and comments are skipped. Quoted strings are returned
  1437. as one word (including whitespace) with the quotes removed.
  1438. EXIT: If successful, returns a pointer to the input buffer
  1439. (szBuf). *pfMore indicates if there are more words to
  1440. be read. If an error occurs, its value is returned in *puErr.
  1441. ********************************************************************/
  1442. CHAR * GetNextWord(HWND hWnd,HANDLE hFile,CHAR * szBuf,UINT cbBuf,BOOL * pfMore,UINT *
  1443. puErr)
  1444. {
  1445. CHAR * pChar;
  1446. BOOL fInWord = FALSE;
  1447. BOOL fInQuote = FALSE;
  1448. CHAR * pWord = szBuf;
  1449. UINT cbWord = 0;
  1450. CHAR * GetNextChar(HANDLE hFile,BOOL * pfMore,UINT * puErr);
  1451. BOOL IsComment(CHAR * pBuf);
  1452. BOOL IsWhitespace(CHAR * pBuf);
  1453. BOOL IsEndOfLine(CHAR * pBuf);
  1454. BOOL IsQuote(CHAR * pBuf);
  1455. BOOL IsLocalizedString(CHAR * pBuf);
  1456. UINT ProcessIfdefs(HWND hWnd,HANDLE hFile,CHAR * pBuf,UINT cbBuf,BOOL * pfMore);
  1457. // clear buffer to start with
  1458. lstrcpy(szBuf,szNull);
  1459. while (pChar = GetNextChar(hFile,pfMore,puErr)) {
  1460. // keep track of which file line we're on
  1461. if (IsEndOfLine(pChar)) nFileLine++;
  1462. // keep track of wheter we are inside quoted string or not
  1463. if (IsQuote(pChar) && !fInComment) {
  1464. if (!fInQuote)
  1465. fInQuote = TRUE; // entering quoted string
  1466. else {
  1467. fInQuote = FALSE; // leaving quoted string
  1468. break; // end of word
  1469. }
  1470. }
  1471. if (!fInQuote) {
  1472. // skip over lines with comments (';')
  1473. if (!fInComment & IsComment(pChar)) fInComment = TRUE;
  1474. if (fInComment) {
  1475. if (IsEndOfLine(pChar)) {
  1476. fInComment = FALSE;
  1477. }
  1478. continue;
  1479. }
  1480. if (IsWhitespace(pChar)) {
  1481. // if we haven't found word yet, skip over whitespace
  1482. if (!fInWord)
  1483. continue;
  1484. // otherwise, whitespace signals end of word
  1485. break;
  1486. }
  1487. }
  1488. // found a non-comment, non-whitespace character
  1489. if (!fInWord) fInWord = TRUE;
  1490. if (!IsQuote(pChar)) {
  1491. // add this character to word
  1492. *pWord = *pChar;
  1493. pWord++;
  1494. cbWord++;
  1495. if (cbWord > cbBuf) {
  1496. *(pWord - 1) = TEXT('\0');
  1497. MsgBoxParam(NULL,IDS_WORDTOOLONG,szBuf,MB_ICONEXCLAMATION,MB_OK);
  1498. *puErr = ERROR_ALREADY_DISPLAYED;
  1499. goto Exit;
  1500. }
  1501. #if 0
  1502. if (IsDBCSLeadByte((BYTE) *pChar)) {
  1503. *pWord = *pChar;
  1504. pWord++;
  1505. cbWord++;
  1506. }
  1507. #endif
  1508. }
  1509. }
  1510. *pWord = '\0'; // null-terminate
  1511. // if found string a la '!!foo', then look for a string in the [strings]
  1512. // section with the key name 'foo' and use that instead. This is because
  1513. // our localization tools are brainless and require a [strings] section.
  1514. // So although template files are sectionless, we allow a [strings] section
  1515. // at the bottom.
  1516. if (IsLocalizedString(szBuf)) {
  1517. LPTSTR lpTmp;
  1518. lpTmp = LocalAlloc (LPTR, cbBuf * sizeof(TCHAR));
  1519. if (lpTmp) {
  1520. DWORD dwSize;
  1521. if (g_bWinnt) {
  1522. dwSize = PrivGetPrivateProfileString(szStrings,szBuf+2,
  1523. szNull,lpTmp,cbBuf,pszParseFileName);
  1524. }
  1525. else {
  1526. dwSize = GetPrivateProfileStringA(szStrings,szBuf+2,
  1527. szNull,lpTmp,cbBuf,pszParseFileName);
  1528. }
  1529. if (!dwSize) {
  1530. DisplayKeywordError(hWnd,IDS_ParseErr_STRING_NOT_FOUND,
  1531. szBuf,NULL,pszParseFileName,nFileLine);
  1532. *puErr=ERROR_ALREADY_DISPLAYED;
  1533. return NULL;
  1534. }
  1535. // replace the word we're returning with the one from the [strings]
  1536. // section
  1537. lstrcpy(szBuf,lpTmp);
  1538. LocalFree (lpTmp);
  1539. }
  1540. } else {
  1541. *puErr = ProcessIfdefs(hWnd,hFile,szBuf,cbBuf,pfMore);
  1542. }
  1543. Exit:
  1544. if (*puErr != ERROR_SUCCESS || !fInWord) return NULL;
  1545. return szBuf;
  1546. }
  1547. /*******************************************************************
  1548. NAME: GetNextSectionWord
  1549. SYNOPSIS: Gets next word and warns if end-of-file encountered.
  1550. Optionally checks the keyword against a list of valid
  1551. keywords.
  1552. NOTES: Calls GetNextWord() to get word. This is called in
  1553. situations where we expect there to be another word
  1554. (e.g., inside a section) and it's an error if the
  1555. file ends.
  1556. ********************************************************************/
  1557. CHAR * GetNextSectionWord(HWND hWnd,HANDLE hFile,CHAR * szBuf,UINT cbBuf,
  1558. KEYWORDINFO * pKeywordList,UINT *pnListIndex,BOOL * pfMore,UINT * puErr)
  1559. {
  1560. CHAR * pch;
  1561. if (!(pch=GetNextWord(hWnd,hFile,szBuf,cbBuf,pfMore,puErr))) {
  1562. if (!*pfMore && *puErr != ERROR_ALREADY_DISPLAYED) {
  1563. DisplayKeywordError(hWnd,IDS_ParseErr_UNEXPECTED_EOF,
  1564. NULL,pKeywordList,pszParseFileName,nFileLine);
  1565. *puErr = ERROR_ALREADY_DISPLAYED;
  1566. }
  1567. return NULL;
  1568. }
  1569. if (pKeywordList && !CompareKeyword(hWnd,szBuf,pKeywordList,pnListIndex)) {
  1570. *puErr = ERROR_ALREADY_DISPLAYED;
  1571. return NULL;
  1572. }
  1573. return pch;
  1574. }
  1575. /*******************************************************************
  1576. NAME: GetNextSectionNumericWord
  1577. SYNOPSIS: Gets next word and converts string to number. Warns if
  1578. not a numeric value
  1579. ********************************************************************/
  1580. UINT GetNextSectionNumericWord(HWND hWnd,HANDLE hFile,UINT * pnVal)
  1581. {
  1582. UINT uErr;
  1583. CHAR szWordBuf[255];
  1584. BOOL fMore;
  1585. if (!GetNextSectionWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),
  1586. NULL,NULL,&fMore,&uErr))
  1587. return uErr;
  1588. if (!StringToNum(szWordBuf,pnVal)) {
  1589. DisplayKeywordError(hWnd,IDS_ParseErr_NOT_NUMERIC,szWordBuf,
  1590. NULL,pszParseFileName,nFileLine);
  1591. return ERROR_ALREADY_DISPLAYED;
  1592. }
  1593. return ERROR_SUCCESS;
  1594. }
  1595. /*******************************************************************
  1596. NAME: GetNextChar
  1597. SYNOPSIS: Returns a pointer to the next character from the
  1598. file stream.
  1599. NOTES: Reads a chunk of the file into a buffer and returns
  1600. a pointer inside the buffer, reading new chunks into
  1601. the buffer as necessary.
  1602. EXIT: Returns pointer to next character in stream.
  1603. If
  1604. ********************************************************************/
  1605. CHAR * GetNextChar(HANDLE hFile,BOOL * pfMore,UINT * puErr)
  1606. {
  1607. CHAR * pCurrentChar;
  1608. UINT uRet;
  1609. UINT ReadFileToBuffer(HANDLE hFile,CHAR * pBuf,DWORD cbBuf,DWORD *pdwRead,
  1610. BOOL * pfEOF);
  1611. *puErr = ERROR_SUCCESS;
  1612. *pfMore = TRUE;
  1613. // read another chunk into buffer if necessary
  1614. // if we haven't gotten a buffer-ful yet or have read through the current
  1615. // buffer
  1616. if (!pFilePtr || pFilePtr > pFileEnd) {
  1617. DWORD dwRead;
  1618. // if we're finished with this buffer, and we're at the end of file
  1619. // (fEOF true), then signal end of stream
  1620. if ( (pFilePtr > pFileEnd) && fEOF) {
  1621. *pfMore = FALSE;
  1622. return NULL;
  1623. }
  1624. uRet=ReadFileToBuffer(hFile,(VOID *) pFileBuf,FILEBUFSIZE,&dwRead,
  1625. &fEOF);
  1626. if (uRet != ERROR_SUCCESS) {
  1627. *puErr = uRet;
  1628. return NULL;
  1629. }
  1630. pFilePtr = pFileBuf;
  1631. pFileEnd = pFilePtr + dwRead-1;
  1632. #if 0
  1633. } else if (pFilePtr == pFileEnd && IsDBCSLeadByte((BYTE) *pFilePtr)) {
  1634. // have to watch for one tricky situation-- where the first
  1635. // byte of a DBCS char has fallen on the end of our read buffer.
  1636. // In this case, copy that byte to beginning of buffer, and read in
  1637. // another chunk to rest of buffer.
  1638. DWORD dwRead;
  1639. *pFileBuf = *pFilePtr;
  1640. uRet=ReadFileToBuffer(hFile,(VOID *) (pFileBuf+1),FILEBUFSIZE-1,&dwRead,
  1641. &fEOF);
  1642. if (uRet != ERROR_SUCCESS) {
  1643. *puErr = uRet;
  1644. return NULL;
  1645. }
  1646. pFilePtr = pFileBuf;
  1647. pFileEnd = pFilePtr + dwRead;
  1648. #endif
  1649. }
  1650. pCurrentChar = pFilePtr;
  1651. pFilePtr = CharNext(pFilePtr);
  1652. return pCurrentChar;
  1653. }
  1654. UINT ReadFileToBuffer(HANDLE hFile,CHAR * pBuf,DWORD cbBuf,DWORD *pdwRead,
  1655. BOOL * pfEOF)
  1656. {
  1657. VOID *pDestBuf = fUnicode ? (VOID *) pUnicodeFileBuf : (VOID *) pBuf;
  1658. if (!ReadFile(hFile,pDestBuf,cbBuf,pdwRead,NULL))
  1659. return GetLastError();
  1660. if (*pdwRead<cbBuf) *pfEOF = TRUE;
  1661. else *pfEOF = FALSE;
  1662. if (fCheckUnicode)
  1663. {
  1664. if (*pdwRead >= sizeof(WCHAR))
  1665. {
  1666. if (IsTextUnicode(pDestBuf, *pdwRead, NULL))
  1667. {
  1668. fUnicode = TRUE;
  1669. pUnicodeFileBuf = (WCHAR *) GlobalAlloc(GPTR,FILEBUFSIZE);
  1670. if (NULL == pUnicodeFileBuf)
  1671. return ERROR_OUTOFMEMORY;
  1672. *pdwRead -= sizeof(WCHAR);
  1673. CopyMemory(pUnicodeFileBuf, pBuf+sizeof(WCHAR), *pdwRead);
  1674. }
  1675. }
  1676. fCheckUnicode = FALSE;
  1677. }
  1678. if (fUnicode)
  1679. {
  1680. // If we read an odd number of bytes in a unicode file either the
  1681. // file is corrupt or somebody is passing a bogus cbBuf
  1682. ASSERT(0 == (*pdwRead & 1));
  1683. *pdwRead = WideCharToMultiByte(
  1684. CP_ACP,
  1685. 0,
  1686. pUnicodeFileBuf,
  1687. *pdwRead / sizeof(WCHAR),
  1688. pBuf,
  1689. cbBuf,
  1690. NULL,
  1691. NULL);
  1692. if (0 == *pdwRead)
  1693. return GetLastError();
  1694. }
  1695. return ERROR_SUCCESS;
  1696. }
  1697. BOOL IsComment(CHAR * pBuf)
  1698. {
  1699. return (*pBuf == ';');
  1700. }
  1701. BOOL IsQuote(CHAR * pBuf)
  1702. {
  1703. return (*pBuf == '\"');
  1704. }
  1705. BOOL IsEndOfLine(CHAR * pBuf)
  1706. {
  1707. return (*pBuf == 0x0D); // CR
  1708. }
  1709. BOOL IsWhitespace(CHAR * pBuf)
  1710. {
  1711. return ( *pBuf == 0x20 // space
  1712. || *pBuf == 0x0D // CR
  1713. || *pBuf == 0X0A // LF
  1714. || *pBuf == 0x09 // tab
  1715. || *pBuf == 0x1A // EOF
  1716. );
  1717. }
  1718. BOOL IsLocalizedString(CHAR * pBuf)
  1719. {
  1720. return (*pBuf == '!' && *(pBuf+1) == '!');
  1721. }
  1722. BOOL fFilterDirectives = TRUE;
  1723. UINT nGlobalNestedLevel = 0;
  1724. // reads up through the matching directive #endif in current scope
  1725. //and sets file pointer immediately past the directive
  1726. UINT FindMatchingDirective(HWND hWnd,HANDLE hFile,BOOL *pfMore,BOOL fElseOK)
  1727. {
  1728. CHAR szWordBuf[255];
  1729. UINT uErr=ERROR_SUCCESS,nNestedLevel=1;
  1730. BOOL fContinue = TRUE;
  1731. // set the flag to stop catching '#' directives in low level word-fetching
  1732. // routine
  1733. fFilterDirectives = FALSE;
  1734. // keep reading words. Keep track of how many layers of #ifdefs deep we
  1735. // are. Every time we encounter an #ifdef or #ifndef, increment the level
  1736. // count (nNestedLevel) by one. For every #endif decrement the level count.
  1737. // When the level count hits zero, we've found the matching #endif.
  1738. while (nNestedLevel > 0) {
  1739. if (!GetNextSectionWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),NULL,NULL,
  1740. pfMore,&uErr))
  1741. break;
  1742. if (!lstrcmpi(szWordBuf,szIFDEF) || !lstrcmpi(szWordBuf,szIFNDEF) ||
  1743. !lstrcmpi(szWordBuf,szIF))
  1744. nNestedLevel ++;
  1745. else if (!lstrcmpi(szWordBuf,szENDIF)) {
  1746. nNestedLevel --;
  1747. }
  1748. else if (!lstrcmpi(szWordBuf,szELSE) && (nNestedLevel == 1)) {
  1749. if (fElseOK) {
  1750. // ignore "#else" unless it's on the same level as the #ifdef
  1751. // we're finding a match for (nNestedLevel == 1), in which
  1752. // case treat it as the matching directive
  1753. nNestedLevel --;
  1754. // increment global nesting so we expect an #endif to come along
  1755. // later to match this #else
  1756. nGlobalNestedLevel++;
  1757. } else {
  1758. // found a #else where we already had a #else in this level
  1759. DisplayKeywordError(hWnd,IDS_ParseErr_UNMATCHED_DIRECTIVE,
  1760. szWordBuf,NULL,pszParseFileName,nFileLine);
  1761. return ERROR_ALREADY_DISPLAYED;
  1762. }
  1763. }
  1764. }
  1765. fFilterDirectives = TRUE;
  1766. return uErr;
  1767. }
  1768. #define CURRENT_VERSION 2
  1769. // if the word in the word buffer is #ifdef, #if, #ifndef, #else or #endif,
  1770. // this function reads ahead an appropriate amount (
  1771. UINT ProcessIfdefs(HWND hWnd,HANDLE hFile,CHAR * pBuf,UINT cbBuf,BOOL * pfMore)
  1772. {
  1773. UINT uRet;
  1774. if (!fFilterDirectives)
  1775. return ERROR_SUCCESS;
  1776. if (!lstrcmpi(pBuf,szIFDEF)) {
  1777. // we've found an '#ifdef <something or other>, where ISV policy editors
  1778. // can understand particular keywords they make up. We don't have any
  1779. // #ifdef keywords of our own so always skip this
  1780. uRet = FindMatchingDirective(hWnd,hFile,pfMore,TRUE);
  1781. if (uRet != ERROR_SUCCESS)
  1782. return uRet;
  1783. if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
  1784. return uRet;
  1785. return ERROR_SUCCESS;
  1786. } else if (!lstrcmpi(pBuf,szIFNDEF)) {
  1787. // this is an #ifndef, and since nothing is ever ifdef'd for our policy
  1788. // editor, this always evaluates to TRUE
  1789. // keep reading this section but increment the nested level count,
  1790. // when we find the matching #endif or #else we'll be able to respond
  1791. // correctly
  1792. nGlobalNestedLevel ++;
  1793. // get next word (e.g. "foo" for #ifndef foo) and throw it away
  1794. if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
  1795. return uRet;
  1796. // get next word and return it for real
  1797. if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
  1798. return uRet;
  1799. return ERROR_SUCCESS;
  1800. } else if (!lstrcmpi(pBuf,szENDIF)) {
  1801. // if we ever encounter an #endif here, we must have processed
  1802. // the preceeding section. Just step over the #endif and go on
  1803. if (!nGlobalNestedLevel) {
  1804. // found an endif without a preceeding #if<xx>
  1805. DisplayKeywordError(hWnd,IDS_ParseErr_UNMATCHED_DIRECTIVE,
  1806. pBuf,NULL,pszParseFileName,nFileLine);
  1807. return ERROR_ALREADY_DISPLAYED;
  1808. }
  1809. nGlobalNestedLevel--;
  1810. if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
  1811. return uRet;
  1812. return ERROR_SUCCESS;
  1813. } else if (!lstrcmpi(pBuf,szIF)) {
  1814. // syntax is "#if VERSION (comparision) (version #)"
  1815. // e.g. "#if VERSION >= 2"
  1816. CHAR szWordBuf[255];
  1817. UINT nIndex,nVersion,nOperator;
  1818. BOOL fDirectiveTrue = FALSE;
  1819. // get the next word (must be "VERSION")
  1820. if (!GetNextSectionWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),
  1821. pVersionCmpList,&nIndex,pfMore,&uRet))
  1822. return uRet;
  1823. // get the comparison operator (>, <, ==, >=, <=)
  1824. if (!GetNextSectionWord(hWnd,hFile,szWordBuf,sizeof(szWordBuf),
  1825. pOperatorCmpList,&nOperator,pfMore,&uRet))
  1826. return uRet;
  1827. // get the version number
  1828. uRet=GetNextSectionNumericWord(hWnd,hFile,&nVersion);
  1829. if (uRet != ERROR_SUCCESS)
  1830. return uRet;
  1831. // now evaluate the directive
  1832. switch (nOperator) {
  1833. case KYWD_ID_GT:
  1834. fDirectiveTrue = (CURRENT_VERSION > nVersion);
  1835. break;
  1836. case KYWD_ID_GTE:
  1837. fDirectiveTrue = (CURRENT_VERSION >= nVersion);
  1838. break;
  1839. case KYWD_ID_LT:
  1840. fDirectiveTrue = (CURRENT_VERSION < nVersion);
  1841. break;
  1842. case KYWD_ID_LTE:
  1843. fDirectiveTrue = (CURRENT_VERSION <= nVersion);
  1844. break;
  1845. case KYWD_ID_EQ:
  1846. fDirectiveTrue = (CURRENT_VERSION == nVersion);
  1847. break;
  1848. case KYWD_ID_NE:
  1849. fDirectiveTrue = (CURRENT_VERSION != nVersion);
  1850. break;
  1851. }
  1852. if (fDirectiveTrue) {
  1853. // keep reading this section but increment the nested level count,
  1854. // when we find the matching #endif or #else we'll be able to respond
  1855. // correctly
  1856. nGlobalNestedLevel ++;
  1857. } else {
  1858. // skip over this section
  1859. uRet = FindMatchingDirective(hWnd,hFile,pfMore,TRUE);
  1860. if (uRet != ERROR_SUCCESS)
  1861. return uRet;
  1862. }
  1863. // get next word and return it for real
  1864. if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
  1865. return uRet;
  1866. return ERROR_SUCCESS;
  1867. } else if (!lstrcmpi(pBuf,szELSE)) {
  1868. // found an #else, which means we took the upper branch, skip over
  1869. // the lower branch
  1870. if (!nGlobalNestedLevel) {
  1871. // found an #else without a preceeding #if<xx>
  1872. DisplayKeywordError(hWnd,IDS_ParseErr_UNMATCHED_DIRECTIVE,
  1873. pBuf,NULL,pszParseFileName,nFileLine);
  1874. return ERROR_ALREADY_DISPLAYED;
  1875. }
  1876. nGlobalNestedLevel--;
  1877. uRet = FindMatchingDirective(hWnd,hFile,pfMore,FALSE);
  1878. if (uRet != ERROR_SUCCESS)
  1879. return uRet;
  1880. if (!GetNextWord(hWnd,hFile,pBuf,cbBuf,pfMore,&uRet))
  1881. return uRet;
  1882. return ERROR_SUCCESS;
  1883. }
  1884. return ERROR_SUCCESS;
  1885. }