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.

818 lines
26 KiB

  1. /*************************************************************************
  2. * *
  3. * CHARTAB.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1990-1994 *
  6. * All Rights reserved. *
  7. * *
  8. **************************************************************************
  9. * *
  10. * Module Intent *
  11. * Character table indexing and retrieval. The reasons this module is *
  12. * not put together with ansiusa are: *
  13. * - Like stop words, this involves indexing and retrieval *
  14. * - It is word breaker independent *
  15. * *
  16. **************************************************************************
  17. * *
  18. * Current Owner: Binh Nguyen *
  19. * *
  20. *************************************************************************/
  21. #include <mvopsys.h>
  22. #include <mem.h>
  23. #include <memory.h>
  24. #include <mvsearch.h>
  25. #include "common.h"
  26. #include "search.h"
  27. #ifdef _DEBUG
  28. static BYTE NEAR s_aszModule[] = __FILE__; /* Used by error return functions.*/
  29. #endif
  30. #define SLASH '/'
  31. #define RETURN '\r'
  32. #define NEWLINE '\n'
  33. /* The order of the functions are relevant, since they will be indirectly
  34. * called through the operators themselves. A change in the order of
  35. * the functions whould be accompanied by a similar change in the value
  36. * of the operator
  37. * The operator's definition is put here to make sure that things match
  38. * between mvsearch.h and the order of the functions
  39. */
  40. #define AND_OP 0
  41. #define OR_OP 1
  42. #define NOT_OP 2
  43. #define PHRASE_OP 3
  44. #define NEAR_OP 4
  45. #define RANGE_OP 5
  46. #define GROUP_OP 6
  47. #define FIELD_OP 7
  48. #define BRKR_OP 8
  49. #define OPERATOR_ENTRY_COUNT 7
  50. /* This array describes all the operators and their values. The index
  51. * of the entries is defined as the order of the operator's intrinsic
  52. * values, ie: AND_OP, OR_OP, etc
  53. */
  54. OPSYM OperatorSymbolTable[OPERATOR_ENTRY_COUNT] = {
  55. "\3AND", UO_AND_OP, // AND_OP, 0
  56. "\2OR", UO_OR_OP, // OR_OP, 1
  57. "\3NOT", UO_NOT_OP, // NOT_OP, 2
  58. "\4NEAR", UO_NEAR_OP, // NEAR_OP, 4
  59. "\4THRU", UO_RANGE_OP, // RANGE_OP, 5
  60. "\4VFLD", UO_FIELD_OP, // FIELD_OP, 7
  61. "\5DTYPE", UO_FBRK_OP, // Breaker operator
  62. };
  63. OPSYM FlatOpSymbolTable[OPERATOR_ENTRY_COUNT] = {
  64. "\4VFLD", UO_FIELD_OP, // FIELD_OP, 7
  65. "\5DTYPE", UO_FBRK_OP, // Breaker operator
  66. "", 0, // Filler
  67. "", 0, // Filler
  68. "", 0, // Filler
  69. "", 0, // Filler
  70. "", 0, // Filler
  71. };
  72. PUBLIC HRESULT PASCAL NEAR OrHandler(LPQT, _LPQTNODE, LPITOPIC, LPV, int);
  73. PUBLIC HRESULT PASCAL NEAR AndHandler(LPQT, _LPQTNODE, LPITOPIC, LPV, int);
  74. PUBLIC HRESULT PASCAL NEAR NotHandler(LPQT, _LPQTNODE, LPITOPIC, LPV, int);
  75. PUBLIC HRESULT PASCAL NEAR NearHandler(LPQT, _LPQTNODE, LPITOPIC, LPV, int);
  76. PUBLIC HRESULT PASCAL NEAR PhraseHandler(LPQT, _LPQTNODE, LPITOPIC, LPV, int);
  77. PUBLIC VOID PASCAL NEAR NearHandlerCleanUp (LPQT, _LPQTNODE);
  78. FNHANDLER HandlerFuncTable[] = {
  79. AndHandler,
  80. OrHandler,
  81. NotHandler,
  82. PhraseHandler,
  83. NearHandler,
  84. NULL,
  85. };
  86. WORD OperatorAttributeTable[] = {
  87. BINARY_OP | COMMUTATIVE | ZERO, // AND_OP
  88. BINARY_OP | COMMUTATIVE | ASSOCIATIVE | ZERO, // OR_OP
  89. BINARY_OP, // NOT_OP
  90. BINARY_OP, // PHRASE_OP
  91. BINARY_OP | COMMUTATIVE, // NEAR_OP
  92. BINARY_OP, // RANGE_OP
  93. UNARY_OP, // GROUP_OP
  94. UNARY_OP, // FIELD_OP
  95. };
  96. /*************************************************************************
  97. *
  98. * API FUNCTIONS
  99. * Those functions should be exported in a .DEF file
  100. *************************************************************************/
  101. PUBLIC LPOPTAB EXPORT_API PASCAL FAR MVOpTableLoad (LSZ, PHRESULT);
  102. PUBLIC VOID EXPORT_API PASCAL FAR MVOpTableDispose (LPOPTAB);
  103. PUBLIC HRESULT EXPORT_API PASCAL FAR MVOpTableFileBuild(HFPB, LPOPTAB, LSZ);
  104. PUBLIC LPOPTAB EXPORT_API FAR PASCAL MVOpTableIndexLoad(HANDLE, LSZ, PHRESULT);
  105. /*************************************************************************
  106. *
  107. * INTERNAL PRIVATE FUNCTIONS
  108. * All of them should be declared near
  109. *************************************************************************/
  110. PRIVATE VOID PASCAL NEAR StripCRLF (LPB, WORD);
  111. PRIVATE HRESULT PASCAL NEAR GetOperator (LPB FAR *, LSZ, _LPOPTAB);
  112. PRIVATE VOID PASCAL NEAR GetWord (LSZ FAR *, LST);
  113. PRIVATE HRESULT PASCAL NEAR OperatorAdd (LST, int, _LPOPTAB);
  114. PRIVATE WORD PASCAL NEAR OperatorFind (LST, LPOPSYM, int);
  115. PRIVATE VOID PASCAL NEAR OpSymTabInit(LPOPSYM, LPB, WORD);
  116. /*************************************************************************
  117. * @doc INTERNAL
  118. *
  119. * @func VOID PASCAL NEAR | GetWord |
  120. * This function will scan and get a word from the input buffer
  121. *
  122. * @parm LSZ FAR | *lplszBuf |
  123. * Pointer to input buffer. The content will be updated on exit
  124. *
  125. * @parm LST | lstWord |
  126. * Buffer to received parsed word
  127. *************************************************************************/
  128. PRIVATE VOID PASCAL NEAR GetWord (LSZ FAR *lplszBuf, LST lstWord)
  129. {
  130. LST lstWordStart;
  131. LSZ lszBuf = *lplszBuf;
  132. /* Remember the beginning of the word */
  133. lstWordStart = lstWord++;
  134. /* Skip all beginning blanks */
  135. while (*lszBuf == ' ')
  136. lszBuf++;
  137. /* Now keep accumulating the word's characters */
  138. for (;;) {
  139. switch (*lszBuf) {
  140. case 0:
  141. case ' ':
  142. goto exit0;
  143. case '/':
  144. if (*(lszBuf + 1) == '/') {
  145. /* Skip the inline comment */
  146. while (*lszBuf)
  147. lszBuf++;
  148. goto exit0;
  149. }
  150. default:
  151. *lstWord++ = *lszBuf++;
  152. }
  153. }
  154. exit0:
  155. *lplszBuf = lszBuf;
  156. *lstWordStart = (BYTE)(lstWord - lstWordStart - 1);
  157. }
  158. /*************************************************************************
  159. * @doc INTERNAL
  160. *
  161. * @func WORD PASCAL NEAR | OperatorFind |
  162. * Check to see if a word is an US operator. If it is, then return
  163. * the entry index into the US operator table
  164. *
  165. * @parm LST | lstWord |
  166. * Word to be checked
  167. *
  168. * @parm LPOPSYM | lpOpSym |
  169. * Pointer to operator synbol table to be checked
  170. *
  171. * @parm int | cEntries |
  172. * Number of entries in the table
  173. *
  174. * @rdesc If found, return the index of that enry, -1 otherwise
  175. *************************************************************************/
  176. PRIVATE WORD PASCAL NEAR OperatorFind (LST lstWord, LPOPSYM lpOpSym,
  177. int cEntries)
  178. {
  179. WORD wLen;
  180. int i;
  181. for (i = 0; i < cEntries; i++)
  182. {
  183. if ((wLen = lpOpSym->OpName[0]) &&
  184. StrNoCaseCmp (lstWord + 1, lpOpSym->OpName + 1, wLen) == 0)
  185. {
  186. /* Match! return the index of the operator */
  187. return (WORD) i;
  188. }
  189. lpOpSym++;
  190. }
  191. return (WORD)-1;
  192. }
  193. /*************************************************************************
  194. * @doc INTERNAL
  195. *
  196. * @func VOID PASCAL NEAR | StripCRLF |
  197. * This function will change all CR, LF in the input buffer into
  198. * 0, all tabs into blank
  199. *
  200. * @parm LPB | lpbBuf |
  201. * Input buffer
  202. *
  203. * @parm WORD | BufSize |
  204. * Length of the buffer
  205. *************************************************************************/
  206. PRIVATE VOID PASCAL NEAR StripCRLF (LPB lpbBuf, WORD BufSize)
  207. {
  208. for (; BufSize > 0; BufSize --)
  209. {
  210. switch (*lpbBuf)
  211. {
  212. case RETURN:
  213. case NEWLINE:
  214. *lpbBuf = 0;
  215. break;
  216. case '\t':
  217. *lpbBuf = ' ';
  218. break;
  219. }
  220. lpbBuf++;
  221. }
  222. }
  223. /************************************************************************
  224. *
  225. * OPERATOR TABLE SUPPORT
  226. *
  227. ************************************************************************/
  228. /*************************************************************************
  229. * @doc API INDEX RETRIEVAL
  230. *
  231. * @func int FAR PASCAL | MVOpTableLoad |
  232. * Read a operator list from an external file.
  233. *
  234. * @parm LSZ | lszOpfile |
  235. * Operator list filename
  236. *
  237. * @parm PHRESULT | phr |
  238. * Pointer to error buffer.
  239. *
  240. * @rdesc Pointer to new operator table is succeeded, NULL otherwise
  241. *************************************************************************/
  242. PUBLIC LPOPTAB EXPORT_API PASCAL FAR MVOpTableLoad (LSZ lszOpFile, PHRESULT phr)
  243. {
  244. HFILE hFile; /* handle of operator file */
  245. _LPOPTAB lpOpTabStruct; /* Pointer to Optab structure */
  246. DWORD dwFileSize; /* Operator filesize */
  247. HANDLE hBuf; /* Handle to input buffer */
  248. BYTE lstWord[CB_MAX_WORD_LEN];
  249. LPB lpbInBuf; /* Pointer to input buffer */
  250. LPB lpbBufLimit; /* Pointer to input buffer end */
  251. HANDLE hOpTab; /* Handle to OpTable structure */
  252. HRESULT fRet = E_FAIL;
  253. int i; /* Scratch variable */
  254. /* Sanity check */
  255. if (lszOpFile == NULL) {
  256. SetErrCode (phr, E_INVALIDARG);
  257. return NULL;
  258. }
  259. lpOpTabStruct = NULL; /* Default return value */
  260. /* Open the operator file */
  261. if ((hFile = _lopen (lszOpFile, READ)) == HFILE_ERROR) {
  262. SetErrCode (phr, E_NOTEXIST);
  263. return NULL;
  264. }
  265. /* Get the file size to determine the size of the buffer. I
  266. * expect the file size to be less than 500 bytes, since it should
  267. * only content operators and their substitutes. I arbitrarily
  268. * set the maximum file size to be 0xfffe
  269. */
  270. if ((dwFileSize = _llseek (hFile, 0L, 2)) == HFILE_ERROR) {
  271. fRet = SetErrCode(phr, E_FILESEEK);
  272. exit00:
  273. _lclose(hFile); // Error not checked since read only
  274. if (fRet != S_OK && hOpTab) {
  275. /* Free the structure */
  276. MVOpTableDispose(lpOpTabStruct);
  277. lpOpTabStruct = NULL;
  278. }
  279. return (LPOPTAB)lpOpTabStruct;
  280. }
  281. if (dwFileSize == 0 || dwFileSize > 0xfffe) {
  282. /* The file is too large, something must be wrong */
  283. fRet = SetErrCode (phr, E_BADFORMAT);
  284. goto exit00;
  285. }
  286. /* Allocate a buffer for the input stream */
  287. if ((hBuf = _GLOBALALLOC(DLLGMEM, dwFileSize + 1)) == NULL) {
  288. fRet = SetErrCode (phr, E_OUTOFMEMORY);
  289. goto exit00;
  290. }
  291. lpbInBuf = (LPB)_GLOBALLOCK(hBuf);
  292. /* Allocate an operator table structure */
  293. if ((hOpTab = _GLOBALALLOC(DLLGMEM_ZEROINIT, sizeof(OPTABLE)
  294. + OPTABLE_SIZE)) == NULL) {
  295. fRet = SetErrCode (phr, E_OUTOFMEMORY);
  296. exit01:
  297. _GLOBALUNLOCK(hBuf);
  298. _GLOBALFREE(hBuf);
  299. goto exit00;
  300. }
  301. /* Initialize all the fields. All unmentioned fields should be 0 */
  302. lpOpTabStruct = (_LPOPTAB)_GLOBALLOCK(hOpTab);
  303. lpOpTabStruct->cbLeft = lpOpTabStruct->wsize = OPTABLE_SIZE;
  304. lpOpTabStruct->lpbOptable = (LPB)(lpOpTabStruct) + sizeof(OPTABLE);
  305. lpOpTabStruct->hStruct = hOpTab;
  306. /* Fill up the buffer */
  307. if (_llseek (hFile, 0L, 0) == HFILE_ERROR) {
  308. fRet = SetErrCode(phr, E_FILESEEK);
  309. goto exit01;
  310. }
  311. if (_lread(hFile, lpbInBuf, (WORD)dwFileSize) != (WORD)dwFileSize) {
  312. fRet = SetErrCode (phr, E_FILEREAD);
  313. goto exit01;
  314. }
  315. /* Zero-terminated the buffer */
  316. *(lpbBufLimit = &lpbInBuf[(WORD)dwFileSize]) = 0;
  317. /* Change all CR-LF into 0 for parsing */
  318. StripCRLF (lpbInBuf, (WORD)dwFileSize);
  319. /* Extract the operators, doing it line by line */
  320. while (lpbInBuf < lpbBufLimit) {
  321. if (*lpbInBuf == 0) {
  322. /* Skip the remains of the old line */
  323. lpbInBuf++;
  324. continue;
  325. }
  326. if ((fRet = GetOperator(&lpbInBuf, lstWord,
  327. lpOpTabStruct)) != S_OK) {
  328. SetErrCode (phr, fRet);
  329. goto exit01;
  330. }
  331. }
  332. /* Go through the default operator table and add all the
  333. * remaining operators */
  334. for (i = 0, lpbInBuf = lpOpTabStruct->fFlag; i < OPERATOR_ENTRY_COUNT;
  335. lpbInBuf++, i++) {
  336. if ((*lpbInBuf & OP_PROCESSED) == 0) {
  337. /* This operator has no equivalent */
  338. if ((fRet = OperatorAdd (OperatorSymbolTable[i].OpName,
  339. OperatorSymbolTable[i].OpVal, lpOpTabStruct)) != S_OK) {
  340. SetErrCode (phr, fRet);
  341. goto exit01;
  342. }
  343. }
  344. }
  345. /* Re-adjust the filesize */
  346. lpOpTabStruct->wsize -= lpOpTabStruct->cbLeft;
  347. lpOpTabStruct->cbLeft = 0;;
  348. /* Allocate a operator symbol table */
  349. if ((lpOpTabStruct->hOpSym = _GLOBALALLOC(DLLGMEM_ZEROINIT,
  350. (lpOpTabStruct->cEntry + 1) * sizeof(OPSYM))) == NULL) {
  351. fRet = SetErrCode (phr, E_OUTOFMEMORY);
  352. goto exit01;
  353. }
  354. lpOpTabStruct->lpOpsymTab = (LPOPSYM)_GLOBALLOCK(lpOpTabStruct->hOpSym);
  355. OpSymTabInit(lpOpTabStruct->lpOpsymTab, lpOpTabStruct->lpbOptable,
  356. lpOpTabStruct->cEntry);
  357. fRet = S_OK;
  358. goto exit01;
  359. }
  360. /*************************************************************************
  361. * @doc API INDEX
  362. *
  363. * @func HRESULT PASCAL FAR | MVOpTableFileBuild |
  364. * Incorporate the Operator word list into the system file
  365. *
  366. * @parm HFPB | hpfbSysFile |
  367. * Handle to system file. It is non-zero, then the system file is
  368. * already open, else the function will open the system file
  369. *
  370. * @parm _LPOPTAB | lpOptab |
  371. * Pointer to operator structure
  372. *
  373. * @parm LSZ | lszFilename |
  374. * If hpfbSysFile is non-zero, this is the name of the Operator's
  375. * subfile else this is the combined filename with the format
  376. * "dos_filename[!Operator_filename]"
  377. * If the subfile's name is not specified, the default Operator's file
  378. * name will be used. The '!' is not part of the subfile's name
  379. *
  380. * @rdesc S_OK if succeeded, or other errors
  381. *************************************************************************/
  382. PUBLIC HRESULT EXPORT_API PASCAL FAR MVOpTableFileBuild (HFPB hfpbSysFile,
  383. _LPOPTAB lpOpTab, LSZ lszFilename)
  384. {
  385. HFPB hfpbOp; // Pointer to final optab file
  386. HRESULT fRet = E_FAIL;
  387. OPTAB_HDR OpTab_hdr;
  388. BYTE Dummy[OPTAB_HDR_SIZE]; // Dummy buffer to write 0
  389. ERRB errb;
  390. /* Sanity check */
  391. if (lpOpTab == NULL)
  392. return E_INVALIDARG;
  393. if (lpOpTab->cEntry == 0)
  394. return E_FAIL; /* Nothing to build */
  395. if ((hfpbOp = FileCreate(hfpbSysFile, lszFilename,
  396. hfpbSysFile ? FS_SUBFILE : REGULAR_FILE, &errb)) == 0)
  397. return errb;
  398. /* Write out the stop file header */
  399. OpTab_hdr.FileStamp = OPTAB_STAMP;
  400. OpTab_hdr.version = VERCURRENT;
  401. OpTab_hdr.wSize = lpOpTab->wsize;
  402. OpTab_hdr.cEntry = lpOpTab->cEntry;
  403. MEMSET(Dummy, (BYTE)0, OPTAB_HDR_SIZE);
  404. /* Write all zero to the header */
  405. if (FileSeekWrite(hfpbOp, Dummy, foNil, OPTAB_HDR_SIZE,
  406. &errb) != OPTAB_HDR_SIZE)
  407. {
  408. fRet = errb;
  409. exit01:
  410. FileClose(hfpbOp);
  411. return fRet;
  412. }
  413. /* Write the file header */
  414. if (FileSeekWrite(hfpbOp, &OpTab_hdr, foNil, sizeof(OPTAB_HDR),
  415. &errb) != sizeof(OPTAB_HDR))
  416. {
  417. fRet = errb;
  418. goto exit01;
  419. }
  420. /* Write out the buffer */
  421. if (FileSeekWrite(hfpbOp, lpOpTab->lpbOptable, MakeFo(OPTAB_HDR_SIZE,0),
  422. lpOpTab->wsize,&errb) != (LONG)lpOpTab->wsize)
  423. {
  424. fRet = errb;
  425. goto exit01;
  426. }
  427. fRet = S_OK;
  428. goto exit01;
  429. }
  430. /*************************************************************************
  431. * @doc INTERNAL
  432. *
  433. * @func HRESULT PASCAL NEAR | GetOperator |
  434. * This function will extract all operators belonged to the same line
  435. * The format of the line is:
  436. * Op [replacing Op] [replacing Op] ...
  437. * where the first Op is an US operator. All replacing Ops are
  438. * the US Op's equivalent
  439. *
  440. * @parm LPB FAR * | lplszBuf |
  441. * Pointer to a buffer. The content of this pointer will be updated
  442. *
  443. * @parm LSZ | lstWord |
  444. * Buffer to received parsed words
  445. *
  446. * @parm _LPOPTAB | lpOpTabStruct |
  447. * Pointer to OpTab structure
  448. *
  449. * @rdesc S_OK if succeeded, other errors otherwise
  450. *************************************************************************/
  451. PRIVATE HRESULT PASCAL NEAR GetOperator (LPB FAR *lplszBuf, LSZ lstWord,
  452. _LPOPTAB lpOpTabStruct)
  453. {
  454. LSZ lszBuf = *lplszBuf;
  455. WORD OpIndex;
  456. HRESULT fRet;
  457. /* Get the first US operator */
  458. GetWord(lplszBuf, lstWord);
  459. if (*lstWord == 0) /* There is no US operator in this line */
  460. return S_OK;
  461. /* Look for the operator in the default table */
  462. if ((OpIndex = OperatorFind(lstWord, OperatorSymbolTable,
  463. OPERATOR_ENTRY_COUNT)) == (WORD)-1)
  464. return E_BADFORMAT;
  465. /* Set flag to mark that we already have an equivalent operator.
  466. * Set the flag early has an special effect. This can turn off
  467. * the recognition of an operator in case there is no equivalent
  468. * operator. Ex:
  469. * AND
  470. * Since there is no equivalent operator, no new entry is added.
  471. * And since the flag is set, the US entry will not be added, ie.
  472. * AND now will be treated as regular word
  473. */
  474. lpOpTabStruct->fFlag[OpIndex] |= OP_PROCESSED;
  475. for (;;) {
  476. /* Insert the new operator into the operator table. There
  477. * is no check for duplicate operators */
  478. GetWord(lplszBuf, lstWord);
  479. if (*lstWord == 0)
  480. break;
  481. if ((fRet = OperatorAdd (lstWord,
  482. OperatorSymbolTable[OpIndex].OpVal,
  483. lpOpTabStruct)) != S_OK) {
  484. return fRet;
  485. }
  486. }
  487. return S_OK;
  488. }
  489. /*************************************************************************
  490. * @doc INTERNAL
  491. *
  492. * @func HRESULT PASCAL NEAR | OperatorAdd |
  493. * Add an operator symbol and its value into the operator symbol
  494. * table
  495. *
  496. * @parm LST | lstWord |
  497. * Buffer contining the operator symbol
  498. *
  499. * @parm int | OpVal |
  500. * Value of the operator
  501. *
  502. * @parm _LPOPTAB | lpOpTabStruct |
  503. * Pointer to operator table structure
  504. *
  505. * @rdesc S_OK if succeeded, other errors otherwise
  506. *************************************************************************/
  507. PRIVATE HRESULT PASCAL NEAR OperatorAdd (LST lstWord, int OpVal,
  508. _LPOPTAB lpOpTabStruct)
  509. {
  510. HANDLE hBuf; /* Handle to new reallocated structure */
  511. WORD size; /* Extra bytes needed */
  512. LST lstBuf; /* Scratch buffer pointer */
  513. WORD i; /* Scratch index variable */
  514. /* Ensure that we have enough room. We need
  515. * - 1 byte for the word length
  516. * - *lstWord byte for the word
  517. * - 2 byte for Operator value
  518. */
  519. if (lpOpTabStruct->cbLeft < (size = *lstWord + 3)) {
  520. _GLOBALUNLOCK(hBuf = lpOpTabStruct->hStruct);
  521. if ((hBuf = _GLOBALREALLOC(hBuf,
  522. sizeof(OPTABLE) + lpOpTabStruct->wsize + size,
  523. DLLGMEM_ZEROINIT)) == NULL)
  524. return E_OUTOFMEMORY;
  525. lpOpTabStruct = (_LPOPTAB)_GLOBALLOCK(hBuf);
  526. /* Re-initialize all the fields */
  527. lpOpTabStruct->hStruct = hBuf;
  528. lpOpTabStruct->cbLeft += size;
  529. lpOpTabStruct->wsize += size;
  530. lpOpTabStruct->lpbOptable = (LPB)(lpOpTabStruct) + sizeof(OPTABLE);
  531. }
  532. /* Copy the terms */
  533. lstBuf = lpOpTabStruct->lpbOptable + lpOpTabStruct->wsize -
  534. lpOpTabStruct->cbLeft;
  535. for (i = *lstWord + 1; i > 0; i--)
  536. *lstBuf++ = *lstWord++;
  537. *(LPW)lstBuf = (WORD) OpVal;
  538. lpOpTabStruct->cbLeft -= size;
  539. lpOpTabStruct->cEntry ++;
  540. return S_OK;
  541. }
  542. /*************************************************************************
  543. * @doc API INDEX RETRIEVAL
  544. *
  545. * @func VOID EXPORT_API PASCAL FAR | MVOpTableDispose |
  546. * Release all the memory associated with the Operator table
  547. *
  548. * @parm _LPOPTAB | lpOpTabStruct |
  549. * Pointer to an operator table structure returned by OpTableLoad()
  550. * or OpTableIndexLoad()
  551. *************************************************************************/
  552. PUBLIC VOID EXPORT_API PASCAL FAR MVOpTableDispose (_LPOPTAB lpOpTabStruct)
  553. {
  554. HANDLE hTmp;
  555. if (lpOpTabStruct == NULL)
  556. return;
  557. /* Free the symbol table */
  558. if (hTmp = lpOpTabStruct->hOpSym) {
  559. FreeHandle(hTmp);
  560. }
  561. /* Free the buffer */
  562. if (hTmp = lpOpTabStruct->hOpTab) {
  563. FreeHandle(hTmp);
  564. }
  565. /* Free the structure */
  566. if (hTmp = lpOpTabStruct->hStruct) {
  567. FreeHandle(hTmp);
  568. }
  569. }
  570. /*************************************************************************
  571. * @doc API RETRIEVAL
  572. *
  573. * @func _LPOPTAB FAR PASCAL | MVOpTableIndexLoad |
  574. * This function will load a operator table from a system file.
  575. *
  576. * @parm HANDLE | hfpbSysFile |
  577. * If non-zero, this is the handle of an already opened system file
  578. *
  579. * @parm LSZ | lszFilename |
  580. * If hpfbSysFile is non-zero, this is the name of the OpTab's subfile
  581. * else this is the combined filename with the format
  582. * "dos_filename[OpTab_filename]"
  583. * If the subfile's name is not specified, the default OpTab's file
  584. * name will be used
  585. *
  586. * @parm PHRESULT | phr |
  587. * Pointer to error buffer
  588. *
  589. * @rdesc If succeeded, the function will return a pointer the loaded
  590. * OpTab, else NULL. The error buffer will contain information
  591. * about the cause of the failure
  592. *
  593. * @comm About ligature table, there are some assumptions:
  594. * If hLigature == 0 {
  595. * if (wcLigature == 0)
  596. * There is no ligature table
  597. * else
  598. * We use the default ligature table. There is no need
  599. * to write out the table data
  600. * }
  601. * else
  602. * The author provides a ligature table.
  603. *************************************************************************/
  604. PUBLIC LPOPTAB EXPORT_API FAR PASCAL MVOpTableIndexLoad(HANDLE hfpbSysFile,
  605. LSZ lszFilename, PHRESULT phr)
  606. {
  607. HANDLE hfpbOpTabFile;
  608. OPTAB_HDR FAR *lpOpTabHdr;
  609. OPTAB_HDR OpTabHdr;
  610. _LPOPTAB lpOpTabStruct = 0;
  611. DWORD dwSize;
  612. HANDLE hOpTab;
  613. WORD OpTabBufSize;
  614. lpOpTabHdr = &OpTabHdr;
  615. /* Open subfile, (and system file if necessary) */
  616. if ((hfpbOpTabFile = (HANDLE)FileOpen(hfpbSysFile,
  617. lszFilename, hfpbSysFile ? FS_SUBFILE : REGULAR_FILE,
  618. READ, phr)) == 0) {
  619. exit0:
  620. return (LPOPTAB)lpOpTabStruct;
  621. }
  622. /* Read in the header file, and make sure that is a OpTab file */
  623. if (FileSeekRead(hfpbOpTabFile, (LPV)lpOpTabHdr, foNil,
  624. sizeof(OPTAB_HDR), phr) != sizeof(OPTAB_HDR)) {
  625. exit1:
  626. /* Close the subfile */
  627. FileClose(hfpbOpTabFile);
  628. /* Close the system file if we open it, the handle will be
  629. * released in the process */
  630. goto exit0;
  631. }
  632. /* Check to see if the data read in is valid */
  633. if (lpOpTabHdr->FileStamp != OPTAB_STAMP || // File stamp
  634. lpOpTabHdr->version != VERCURRENT) { // Version number
  635. SetErrCode(phr, E_BADVERSION);
  636. goto exit1;
  637. }
  638. /* Allocate memory for the operator table, which includes:
  639. * - Operator table buffer
  640. * - Operator symbol table
  641. * - The structure itself
  642. * Currently, we can combine all the memory togother under the
  643. * assumption that the table will be small enough (< 64K)
  644. */
  645. dwSize = lpOpTabHdr->wSize + (lpOpTabHdr->cEntry + 1) * sizeof (OPSYM) +
  646. sizeof(OPTABLE);
  647. if (dwSize > 0xffff || (hOpTab = _GLOBALALLOC(GMEM_MOVEABLE | GMEM_ZEROINIT,
  648. dwSize)) == 0) {
  649. SetErrCode (phr, E_OUTOFMEMORY);
  650. goto exit1;
  651. }
  652. lpOpTabStruct = (_LPOPTAB)_GLOBALLOCK(hOpTab);
  653. /* Initialize the fields of the structure */
  654. lpOpTabStruct->hStruct = hOpTab;
  655. lpOpTabStruct->cEntry = lpOpTabHdr->cEntry;
  656. OpTabBufSize = lpOpTabStruct->wsize = lpOpTabHdr->wSize;
  657. lpOpTabStruct->lpbOptable = (LPB)lpOpTabStruct + sizeof(OPTABLE);
  658. lpOpTabStruct->lpOpsymTab = (LPOPSYM)(lpOpTabStruct->lpbOptable +
  659. OpTabBufSize);
  660. /* Read in the operator table data */
  661. if (FileSeekRead(hfpbOpTabFile,
  662. (LPV)lpOpTabStruct->lpbOptable, MakeFo(OPTAB_HDR_SIZE,0),
  663. OpTabBufSize, phr) != OpTabBufSize) {
  664. SetErrCode(phr, E_FILEREAD);
  665. MVOpTableDispose(lpOpTabStruct);
  666. lpOpTabStruct = NULL;
  667. goto exit1;
  668. }
  669. /* Initialize the symbol table */
  670. OpSymTabInit(lpOpTabStruct->lpOpsymTab, lpOpTabStruct->lpbOptable,
  671. lpOpTabStruct->cEntry);
  672. goto exit1;
  673. }
  674. /*************************************************************************
  675. * @doc API RETRIEVAL
  676. *
  677. * @func _LPOPTAB FAR PASCAL | MVOpTableGetDefault |
  678. * This function will load the default US operator table
  679. *
  680. *
  681. * @rdesc If succeeded, the function will return a pointer the loaded
  682. * OpTab, else NULL if out of memory
  683. *************************************************************************/
  684. PUBLIC LPOPTAB EXPORT_API FAR PASCAL MVOpTableGetDefault(PHRESULT phr)
  685. {
  686. _LPOPTAB lpOpTabStruct = 0;
  687. HANDLE hOpTab;
  688. /* Allocate memory for the operator table, which includes:
  689. * - Operator symbol table
  690. * - The structure itself
  691. */
  692. if ((hOpTab = _GLOBALALLOC(DLLGMEM_ZEROINIT, sizeof(OPTABLE))) == 0) {
  693. SetErrCode (phr, E_OUTOFMEMORY);
  694. return NULL;
  695. }
  696. lpOpTabStruct = (_LPOPTAB)_GLOBALLOCK(hOpTab);
  697. /* Initialize the fields of the structure */
  698. lpOpTabStruct->hStruct = hOpTab;
  699. lpOpTabStruct->cEntry = OPERATOR_ENTRY_COUNT;
  700. lpOpTabStruct->lpbOptable = NULL;
  701. lpOpTabStruct->lpOpsymTab = (LPOPSYM)(OperatorSymbolTable);
  702. return (LPOPTAB)lpOpTabStruct;
  703. }
  704. PRIVATE VOID PASCAL NEAR OpSymTabInit(LPOPSYM lpOpSymTab,
  705. LPB lpbOpTable, WORD cEntry)
  706. {
  707. for (; cEntry > 0; cEntry--) {
  708. lpOpSymTab->OpName = lpbOpTable;
  709. lpbOpTable += *lpbOpTable + sizeof(BYTE);
  710. lpOpSymTab->OpVal = GETWORD(lpbOpTable);
  711. lpbOpTable += sizeof(unsigned short);
  712. lpOpSymTab++;
  713. }
  714. }