windows-nt/Source/XPSP1/NT/enduser/stuff/itircl/fts/search/optable.c
2020-09-26 16:20:57 +08:00

819 lines
26 KiB
C

/*************************************************************************
* *
* CHARTAB.C *
* *
* Copyright (C) Microsoft Corporation 1990-1994 *
* All Rights reserved. *
* *
**************************************************************************
* *
* Module Intent *
* Character table indexing and retrieval. The reasons this module is *
* not put together with ansiusa are: *
* - Like stop words, this involves indexing and retrieval *
* - It is word breaker independent *
* *
**************************************************************************
* *
* Current Owner: Binh Nguyen *
* *
*************************************************************************/
#include <mvopsys.h>
#include <mem.h>
#include <memory.h>
#include <mvsearch.h>
#include "common.h"
#include "search.h"
#ifdef _DEBUG
static BYTE NEAR s_aszModule[] = __FILE__; /* Used by error return functions.*/
#endif
#define SLASH '/'
#define RETURN '\r'
#define NEWLINE '\n'
/* The order of the functions are relevant, since they will be indirectly
* called through the operators themselves. A change in the order of
* the functions whould be accompanied by a similar change in the value
* of the operator
* The operator's definition is put here to make sure that things match
* between mvsearch.h and the order of the functions
*/
#define AND_OP 0
#define OR_OP 1
#define NOT_OP 2
#define PHRASE_OP 3
#define NEAR_OP 4
#define RANGE_OP 5
#define GROUP_OP 6
#define FIELD_OP 7
#define BRKR_OP 8
#define OPERATOR_ENTRY_COUNT 7
/* This array describes all the operators and their values. The index
* of the entries is defined as the order of the operator's intrinsic
* values, ie: AND_OP, OR_OP, etc
*/
OPSYM OperatorSymbolTable[OPERATOR_ENTRY_COUNT] = {
"\3AND", UO_AND_OP, // AND_OP, 0
"\2OR", UO_OR_OP, // OR_OP, 1
"\3NOT", UO_NOT_OP, // NOT_OP, 2
"\4NEAR", UO_NEAR_OP, // NEAR_OP, 4
"\4THRU", UO_RANGE_OP, // RANGE_OP, 5
"\4VFLD", UO_FIELD_OP, // FIELD_OP, 7
"\5DTYPE", UO_FBRK_OP, // Breaker operator
};
OPSYM FlatOpSymbolTable[OPERATOR_ENTRY_COUNT] = {
"\4VFLD", UO_FIELD_OP, // FIELD_OP, 7
"\5DTYPE", UO_FBRK_OP, // Breaker operator
"", 0, // Filler
"", 0, // Filler
"", 0, // Filler
"", 0, // Filler
"", 0, // Filler
};
PUBLIC HRESULT PASCAL NEAR OrHandler(LPQT, _LPQTNODE, LPITOPIC, LPV, int);
PUBLIC HRESULT PASCAL NEAR AndHandler(LPQT, _LPQTNODE, LPITOPIC, LPV, int);
PUBLIC HRESULT PASCAL NEAR NotHandler(LPQT, _LPQTNODE, LPITOPIC, LPV, int);
PUBLIC HRESULT PASCAL NEAR NearHandler(LPQT, _LPQTNODE, LPITOPIC, LPV, int);
PUBLIC HRESULT PASCAL NEAR PhraseHandler(LPQT, _LPQTNODE, LPITOPIC, LPV, int);
PUBLIC VOID PASCAL NEAR NearHandlerCleanUp (LPQT, _LPQTNODE);
FNHANDLER HandlerFuncTable[] = {
AndHandler,
OrHandler,
NotHandler,
PhraseHandler,
NearHandler,
NULL,
};
WORD OperatorAttributeTable[] = {
BINARY_OP | COMMUTATIVE | ZERO, // AND_OP
BINARY_OP | COMMUTATIVE | ASSOCIATIVE | ZERO, // OR_OP
BINARY_OP, // NOT_OP
BINARY_OP, // PHRASE_OP
BINARY_OP | COMMUTATIVE, // NEAR_OP
BINARY_OP, // RANGE_OP
UNARY_OP, // GROUP_OP
UNARY_OP, // FIELD_OP
};
/*************************************************************************
*
* API FUNCTIONS
* Those functions should be exported in a .DEF file
*************************************************************************/
PUBLIC LPOPTAB EXPORT_API PASCAL FAR MVOpTableLoad (LSZ, PHRESULT);
PUBLIC VOID EXPORT_API PASCAL FAR MVOpTableDispose (LPOPTAB);
PUBLIC HRESULT EXPORT_API PASCAL FAR MVOpTableFileBuild(HFPB, LPOPTAB, LSZ);
PUBLIC LPOPTAB EXPORT_API FAR PASCAL MVOpTableIndexLoad(HANDLE, LSZ, PHRESULT);
/*************************************************************************
*
* INTERNAL PRIVATE FUNCTIONS
* All of them should be declared near
*************************************************************************/
PRIVATE VOID PASCAL NEAR StripCRLF (LPB, WORD);
PRIVATE HRESULT PASCAL NEAR GetOperator (LPB FAR *, LSZ, _LPOPTAB);
PRIVATE VOID PASCAL NEAR GetWord (LSZ FAR *, LST);
PRIVATE HRESULT PASCAL NEAR OperatorAdd (LST, int, _LPOPTAB);
PRIVATE WORD PASCAL NEAR OperatorFind (LST, LPOPSYM, int);
PRIVATE VOID PASCAL NEAR OpSymTabInit(LPOPSYM, LPB, WORD);
/*************************************************************************
* @doc INTERNAL
*
* @func VOID PASCAL NEAR | GetWord |
* This function will scan and get a word from the input buffer
*
* @parm LSZ FAR | *lplszBuf |
* Pointer to input buffer. The content will be updated on exit
*
* @parm LST | lstWord |
* Buffer to received parsed word
*************************************************************************/
PRIVATE VOID PASCAL NEAR GetWord (LSZ FAR *lplszBuf, LST lstWord)
{
LST lstWordStart;
LSZ lszBuf = *lplszBuf;
/* Remember the beginning of the word */
lstWordStart = lstWord++;
/* Skip all beginning blanks */
while (*lszBuf == ' ')
lszBuf++;
/* Now keep accumulating the word's characters */
for (;;) {
switch (*lszBuf) {
case 0:
case ' ':
goto exit0;
case '/':
if (*(lszBuf + 1) == '/') {
/* Skip the inline comment */
while (*lszBuf)
lszBuf++;
goto exit0;
}
default:
*lstWord++ = *lszBuf++;
}
}
exit0:
*lplszBuf = lszBuf;
*lstWordStart = (BYTE)(lstWord - lstWordStart - 1);
}
/*************************************************************************
* @doc INTERNAL
*
* @func WORD PASCAL NEAR | OperatorFind |
* Check to see if a word is an US operator. If it is, then return
* the entry index into the US operator table
*
* @parm LST | lstWord |
* Word to be checked
*
* @parm LPOPSYM | lpOpSym |
* Pointer to operator synbol table to be checked
*
* @parm int | cEntries |
* Number of entries in the table
*
* @rdesc If found, return the index of that enry, -1 otherwise
*************************************************************************/
PRIVATE WORD PASCAL NEAR OperatorFind (LST lstWord, LPOPSYM lpOpSym,
int cEntries)
{
WORD wLen;
int i;
for (i = 0; i < cEntries; i++)
{
if ((wLen = lpOpSym->OpName[0]) &&
StrNoCaseCmp (lstWord + 1, lpOpSym->OpName + 1, wLen) == 0)
{
/* Match! return the index of the operator */
return (WORD) i;
}
lpOpSym++;
}
return (WORD)-1;
}
/*************************************************************************
* @doc INTERNAL
*
* @func VOID PASCAL NEAR | StripCRLF |
* This function will change all CR, LF in the input buffer into
* 0, all tabs into blank
*
* @parm LPB | lpbBuf |
* Input buffer
*
* @parm WORD | BufSize |
* Length of the buffer
*************************************************************************/
PRIVATE VOID PASCAL NEAR StripCRLF (LPB lpbBuf, WORD BufSize)
{
for (; BufSize > 0; BufSize --)
{
switch (*lpbBuf)
{
case RETURN:
case NEWLINE:
*lpbBuf = 0;
break;
case '\t':
*lpbBuf = ' ';
break;
}
lpbBuf++;
}
}
/************************************************************************
*
* OPERATOR TABLE SUPPORT
*
************************************************************************/
/*************************************************************************
* @doc API INDEX RETRIEVAL
*
* @func int FAR PASCAL | MVOpTableLoad |
* Read a operator list from an external file.
*
* @parm LSZ | lszOpfile |
* Operator list filename
*
* @parm PHRESULT | phr |
* Pointer to error buffer.
*
* @rdesc Pointer to new operator table is succeeded, NULL otherwise
*************************************************************************/
PUBLIC LPOPTAB EXPORT_API PASCAL FAR MVOpTableLoad (LSZ lszOpFile, PHRESULT phr)
{
HFILE hFile; /* handle of operator file */
_LPOPTAB lpOpTabStruct; /* Pointer to Optab structure */
DWORD dwFileSize; /* Operator filesize */
HANDLE hBuf; /* Handle to input buffer */
BYTE lstWord[CB_MAX_WORD_LEN];
LPB lpbInBuf; /* Pointer to input buffer */
LPB lpbBufLimit; /* Pointer to input buffer end */
HANDLE hOpTab; /* Handle to OpTable structure */
HRESULT fRet = E_FAIL;
int i; /* Scratch variable */
/* Sanity check */
if (lszOpFile == NULL) {
SetErrCode (phr, E_INVALIDARG);
return NULL;
}
lpOpTabStruct = NULL; /* Default return value */
/* Open the operator file */
if ((hFile = _lopen (lszOpFile, READ)) == HFILE_ERROR) {
SetErrCode (phr, E_NOTEXIST);
return NULL;
}
/* Get the file size to determine the size of the buffer. I
* expect the file size to be less than 500 bytes, since it should
* only content operators and their substitutes. I arbitrarily
* set the maximum file size to be 0xfffe
*/
if ((dwFileSize = _llseek (hFile, 0L, 2)) == HFILE_ERROR) {
fRet = SetErrCode(phr, E_FILESEEK);
exit00:
_lclose(hFile); // Error not checked since read only
if (fRet != S_OK && hOpTab) {
/* Free the structure */
MVOpTableDispose(lpOpTabStruct);
lpOpTabStruct = NULL;
}
return (LPOPTAB)lpOpTabStruct;
}
if (dwFileSize == 0 || dwFileSize > 0xfffe) {
/* The file is too large, something must be wrong */
fRet = SetErrCode (phr, E_BADFORMAT);
goto exit00;
}
/* Allocate a buffer for the input stream */
if ((hBuf = _GLOBALALLOC(DLLGMEM, dwFileSize + 1)) == NULL) {
fRet = SetErrCode (phr, E_OUTOFMEMORY);
goto exit00;
}
lpbInBuf = (LPB)_GLOBALLOCK(hBuf);
/* Allocate an operator table structure */
if ((hOpTab = _GLOBALALLOC(DLLGMEM_ZEROINIT, sizeof(OPTABLE)
+ OPTABLE_SIZE)) == NULL) {
fRet = SetErrCode (phr, E_OUTOFMEMORY);
exit01:
_GLOBALUNLOCK(hBuf);
_GLOBALFREE(hBuf);
goto exit00;
}
/* Initialize all the fields. All unmentioned fields should be 0 */
lpOpTabStruct = (_LPOPTAB)_GLOBALLOCK(hOpTab);
lpOpTabStruct->cbLeft = lpOpTabStruct->wsize = OPTABLE_SIZE;
lpOpTabStruct->lpbOptable = (LPB)(lpOpTabStruct) + sizeof(OPTABLE);
lpOpTabStruct->hStruct = hOpTab;
/* Fill up the buffer */
if (_llseek (hFile, 0L, 0) == HFILE_ERROR) {
fRet = SetErrCode(phr, E_FILESEEK);
goto exit01;
}
if (_lread(hFile, lpbInBuf, (WORD)dwFileSize) != (WORD)dwFileSize) {
fRet = SetErrCode (phr, E_FILEREAD);
goto exit01;
}
/* Zero-terminated the buffer */
*(lpbBufLimit = &lpbInBuf[(WORD)dwFileSize]) = 0;
/* Change all CR-LF into 0 for parsing */
StripCRLF (lpbInBuf, (WORD)dwFileSize);
/* Extract the operators, doing it line by line */
while (lpbInBuf < lpbBufLimit) {
if (*lpbInBuf == 0) {
/* Skip the remains of the old line */
lpbInBuf++;
continue;
}
if ((fRet = GetOperator(&lpbInBuf, lstWord,
lpOpTabStruct)) != S_OK) {
SetErrCode (phr, fRet);
goto exit01;
}
}
/* Go through the default operator table and add all the
* remaining operators */
for (i = 0, lpbInBuf = lpOpTabStruct->fFlag; i < OPERATOR_ENTRY_COUNT;
lpbInBuf++, i++) {
if ((*lpbInBuf & OP_PROCESSED) == 0) {
/* This operator has no equivalent */
if ((fRet = OperatorAdd (OperatorSymbolTable[i].OpName,
OperatorSymbolTable[i].OpVal, lpOpTabStruct)) != S_OK) {
SetErrCode (phr, fRet);
goto exit01;
}
}
}
/* Re-adjust the filesize */
lpOpTabStruct->wsize -= lpOpTabStruct->cbLeft;
lpOpTabStruct->cbLeft = 0;;
/* Allocate a operator symbol table */
if ((lpOpTabStruct->hOpSym = _GLOBALALLOC(DLLGMEM_ZEROINIT,
(lpOpTabStruct->cEntry + 1) * sizeof(OPSYM))) == NULL) {
fRet = SetErrCode (phr, E_OUTOFMEMORY);
goto exit01;
}
lpOpTabStruct->lpOpsymTab = (LPOPSYM)_GLOBALLOCK(lpOpTabStruct->hOpSym);
OpSymTabInit(lpOpTabStruct->lpOpsymTab, lpOpTabStruct->lpbOptable,
lpOpTabStruct->cEntry);
fRet = S_OK;
goto exit01;
}
/*************************************************************************
* @doc API INDEX
*
* @func HRESULT PASCAL FAR | MVOpTableFileBuild |
* Incorporate the Operator word list into the system file
*
* @parm HFPB | hpfbSysFile |
* Handle to system file. It is non-zero, then the system file is
* already open, else the function will open the system file
*
* @parm _LPOPTAB | lpOptab |
* Pointer to operator structure
*
* @parm LSZ | lszFilename |
* If hpfbSysFile is non-zero, this is the name of the Operator's
* subfile else this is the combined filename with the format
* "dos_filename[!Operator_filename]"
* If the subfile's name is not specified, the default Operator's file
* name will be used. The '!' is not part of the subfile's name
*
* @rdesc S_OK if succeeded, or other errors
*************************************************************************/
PUBLIC HRESULT EXPORT_API PASCAL FAR MVOpTableFileBuild (HFPB hfpbSysFile,
_LPOPTAB lpOpTab, LSZ lszFilename)
{
HFPB hfpbOp; // Pointer to final optab file
HRESULT fRet = E_FAIL;
OPTAB_HDR OpTab_hdr;
BYTE Dummy[OPTAB_HDR_SIZE]; // Dummy buffer to write 0
ERRB errb;
/* Sanity check */
if (lpOpTab == NULL)
return E_INVALIDARG;
if (lpOpTab->cEntry == 0)
return E_FAIL; /* Nothing to build */
if ((hfpbOp = FileCreate(hfpbSysFile, lszFilename,
hfpbSysFile ? FS_SUBFILE : REGULAR_FILE, &errb)) == 0)
return errb;
/* Write out the stop file header */
OpTab_hdr.FileStamp = OPTAB_STAMP;
OpTab_hdr.version = VERCURRENT;
OpTab_hdr.wSize = lpOpTab->wsize;
OpTab_hdr.cEntry = lpOpTab->cEntry;
MEMSET(Dummy, (BYTE)0, OPTAB_HDR_SIZE);
/* Write all zero to the header */
if (FileSeekWrite(hfpbOp, Dummy, foNil, OPTAB_HDR_SIZE,
&errb) != OPTAB_HDR_SIZE)
{
fRet = errb;
exit01:
FileClose(hfpbOp);
return fRet;
}
/* Write the file header */
if (FileSeekWrite(hfpbOp, &OpTab_hdr, foNil, sizeof(OPTAB_HDR),
&errb) != sizeof(OPTAB_HDR))
{
fRet = errb;
goto exit01;
}
/* Write out the buffer */
if (FileSeekWrite(hfpbOp, lpOpTab->lpbOptable, MakeFo(OPTAB_HDR_SIZE,0),
lpOpTab->wsize,&errb) != (LONG)lpOpTab->wsize)
{
fRet = errb;
goto exit01;
}
fRet = S_OK;
goto exit01;
}
/*************************************************************************
* @doc INTERNAL
*
* @func HRESULT PASCAL NEAR | GetOperator |
* This function will extract all operators belonged to the same line
* The format of the line is:
* Op [replacing Op] [replacing Op] ...
* where the first Op is an US operator. All replacing Ops are
* the US Op's equivalent
*
* @parm LPB FAR * | lplszBuf |
* Pointer to a buffer. The content of this pointer will be updated
*
* @parm LSZ | lstWord |
* Buffer to received parsed words
*
* @parm _LPOPTAB | lpOpTabStruct |
* Pointer to OpTab structure
*
* @rdesc S_OK if succeeded, other errors otherwise
*************************************************************************/
PRIVATE HRESULT PASCAL NEAR GetOperator (LPB FAR *lplszBuf, LSZ lstWord,
_LPOPTAB lpOpTabStruct)
{
LSZ lszBuf = *lplszBuf;
WORD OpIndex;
HRESULT fRet;
/* Get the first US operator */
GetWord(lplszBuf, lstWord);
if (*lstWord == 0) /* There is no US operator in this line */
return S_OK;
/* Look for the operator in the default table */
if ((OpIndex = OperatorFind(lstWord, OperatorSymbolTable,
OPERATOR_ENTRY_COUNT)) == (WORD)-1)
return E_BADFORMAT;
/* Set flag to mark that we already have an equivalent operator.
* Set the flag early has an special effect. This can turn off
* the recognition of an operator in case there is no equivalent
* operator. Ex:
* AND
* Since there is no equivalent operator, no new entry is added.
* And since the flag is set, the US entry will not be added, ie.
* AND now will be treated as regular word
*/
lpOpTabStruct->fFlag[OpIndex] |= OP_PROCESSED;
for (;;) {
/* Insert the new operator into the operator table. There
* is no check for duplicate operators */
GetWord(lplszBuf, lstWord);
if (*lstWord == 0)
break;
if ((fRet = OperatorAdd (lstWord,
OperatorSymbolTable[OpIndex].OpVal,
lpOpTabStruct)) != S_OK) {
return fRet;
}
}
return S_OK;
}
/*************************************************************************
* @doc INTERNAL
*
* @func HRESULT PASCAL NEAR | OperatorAdd |
* Add an operator symbol and its value into the operator symbol
* table
*
* @parm LST | lstWord |
* Buffer contining the operator symbol
*
* @parm int | OpVal |
* Value of the operator
*
* @parm _LPOPTAB | lpOpTabStruct |
* Pointer to operator table structure
*
* @rdesc S_OK if succeeded, other errors otherwise
*************************************************************************/
PRIVATE HRESULT PASCAL NEAR OperatorAdd (LST lstWord, int OpVal,
_LPOPTAB lpOpTabStruct)
{
HANDLE hBuf; /* Handle to new reallocated structure */
WORD size; /* Extra bytes needed */
LST lstBuf; /* Scratch buffer pointer */
WORD i; /* Scratch index variable */
/* Ensure that we have enough room. We need
* - 1 byte for the word length
* - *lstWord byte for the word
* - 2 byte for Operator value
*/
if (lpOpTabStruct->cbLeft < (size = *lstWord + 3)) {
_GLOBALUNLOCK(hBuf = lpOpTabStruct->hStruct);
if ((hBuf = _GLOBALREALLOC(hBuf,
sizeof(OPTABLE) + lpOpTabStruct->wsize + size,
DLLGMEM_ZEROINIT)) == NULL)
return E_OUTOFMEMORY;
lpOpTabStruct = (_LPOPTAB)_GLOBALLOCK(hBuf);
/* Re-initialize all the fields */
lpOpTabStruct->hStruct = hBuf;
lpOpTabStruct->cbLeft += size;
lpOpTabStruct->wsize += size;
lpOpTabStruct->lpbOptable = (LPB)(lpOpTabStruct) + sizeof(OPTABLE);
}
/* Copy the terms */
lstBuf = lpOpTabStruct->lpbOptable + lpOpTabStruct->wsize -
lpOpTabStruct->cbLeft;
for (i = *lstWord + 1; i > 0; i--)
*lstBuf++ = *lstWord++;
*(LPW)lstBuf = (WORD) OpVal;
lpOpTabStruct->cbLeft -= size;
lpOpTabStruct->cEntry ++;
return S_OK;
}
/*************************************************************************
* @doc API INDEX RETRIEVAL
*
* @func VOID EXPORT_API PASCAL FAR | MVOpTableDispose |
* Release all the memory associated with the Operator table
*
* @parm _LPOPTAB | lpOpTabStruct |
* Pointer to an operator table structure returned by OpTableLoad()
* or OpTableIndexLoad()
*************************************************************************/
PUBLIC VOID EXPORT_API PASCAL FAR MVOpTableDispose (_LPOPTAB lpOpTabStruct)
{
HANDLE hTmp;
if (lpOpTabStruct == NULL)
return;
/* Free the symbol table */
if (hTmp = lpOpTabStruct->hOpSym) {
FreeHandle(hTmp);
}
/* Free the buffer */
if (hTmp = lpOpTabStruct->hOpTab) {
FreeHandle(hTmp);
}
/* Free the structure */
if (hTmp = lpOpTabStruct->hStruct) {
FreeHandle(hTmp);
}
}
/*************************************************************************
* @doc API RETRIEVAL
*
* @func _LPOPTAB FAR PASCAL | MVOpTableIndexLoad |
* This function will load a operator table from a system file.
*
* @parm HANDLE | hfpbSysFile |
* If non-zero, this is the handle of an already opened system file
*
* @parm LSZ | lszFilename |
* If hpfbSysFile is non-zero, this is the name of the OpTab's subfile
* else this is the combined filename with the format
* "dos_filename[OpTab_filename]"
* If the subfile's name is not specified, the default OpTab's file
* name will be used
*
* @parm PHRESULT | phr |
* Pointer to error buffer
*
* @rdesc If succeeded, the function will return a pointer the loaded
* OpTab, else NULL. The error buffer will contain information
* about the cause of the failure
*
* @comm About ligature table, there are some assumptions:
* If hLigature == 0 {
* if (wcLigature == 0)
* There is no ligature table
* else
* We use the default ligature table. There is no need
* to write out the table data
* }
* else
* The author provides a ligature table.
*************************************************************************/
PUBLIC LPOPTAB EXPORT_API FAR PASCAL MVOpTableIndexLoad(HANDLE hfpbSysFile,
LSZ lszFilename, PHRESULT phr)
{
HANDLE hfpbOpTabFile;
OPTAB_HDR FAR *lpOpTabHdr;
OPTAB_HDR OpTabHdr;
_LPOPTAB lpOpTabStruct = 0;
DWORD dwSize;
HANDLE hOpTab;
WORD OpTabBufSize;
lpOpTabHdr = &OpTabHdr;
/* Open subfile, (and system file if necessary) */
if ((hfpbOpTabFile = (HANDLE)FileOpen(hfpbSysFile,
lszFilename, hfpbSysFile ? FS_SUBFILE : REGULAR_FILE,
READ, phr)) == 0) {
exit0:
return (LPOPTAB)lpOpTabStruct;
}
/* Read in the header file, and make sure that is a OpTab file */
if (FileSeekRead(hfpbOpTabFile, (LPV)lpOpTabHdr, foNil,
sizeof(OPTAB_HDR), phr) != sizeof(OPTAB_HDR)) {
exit1:
/* Close the subfile */
FileClose(hfpbOpTabFile);
/* Close the system file if we open it, the handle will be
* released in the process */
goto exit0;
}
/* Check to see if the data read in is valid */
if (lpOpTabHdr->FileStamp != OPTAB_STAMP || // File stamp
lpOpTabHdr->version != VERCURRENT) { // Version number
SetErrCode(phr, E_BADVERSION);
goto exit1;
}
/* Allocate memory for the operator table, which includes:
* - Operator table buffer
* - Operator symbol table
* - The structure itself
* Currently, we can combine all the memory togother under the
* assumption that the table will be small enough (< 64K)
*/
dwSize = lpOpTabHdr->wSize + (lpOpTabHdr->cEntry + 1) * sizeof (OPSYM) +
sizeof(OPTABLE);
if (dwSize > 0xffff || (hOpTab = _GLOBALALLOC(GMEM_MOVEABLE | GMEM_ZEROINIT,
dwSize)) == 0) {
SetErrCode (phr, E_OUTOFMEMORY);
goto exit1;
}
lpOpTabStruct = (_LPOPTAB)_GLOBALLOCK(hOpTab);
/* Initialize the fields of the structure */
lpOpTabStruct->hStruct = hOpTab;
lpOpTabStruct->cEntry = lpOpTabHdr->cEntry;
OpTabBufSize = lpOpTabStruct->wsize = lpOpTabHdr->wSize;
lpOpTabStruct->lpbOptable = (LPB)lpOpTabStruct + sizeof(OPTABLE);
lpOpTabStruct->lpOpsymTab = (LPOPSYM)(lpOpTabStruct->lpbOptable +
OpTabBufSize);
/* Read in the operator table data */
if (FileSeekRead(hfpbOpTabFile,
(LPV)lpOpTabStruct->lpbOptable, MakeFo(OPTAB_HDR_SIZE,0),
OpTabBufSize, phr) != OpTabBufSize) {
SetErrCode(phr, E_FILEREAD);
MVOpTableDispose(lpOpTabStruct);
lpOpTabStruct = NULL;
goto exit1;
}
/* Initialize the symbol table */
OpSymTabInit(lpOpTabStruct->lpOpsymTab, lpOpTabStruct->lpbOptable,
lpOpTabStruct->cEntry);
goto exit1;
}
/*************************************************************************
* @doc API RETRIEVAL
*
* @func _LPOPTAB FAR PASCAL | MVOpTableGetDefault |
* This function will load the default US operator table
*
*
* @rdesc If succeeded, the function will return a pointer the loaded
* OpTab, else NULL if out of memory
*************************************************************************/
PUBLIC LPOPTAB EXPORT_API FAR PASCAL MVOpTableGetDefault(PHRESULT phr)
{
_LPOPTAB lpOpTabStruct = 0;
HANDLE hOpTab;
/* Allocate memory for the operator table, which includes:
* - Operator symbol table
* - The structure itself
*/
if ((hOpTab = _GLOBALALLOC(DLLGMEM_ZEROINIT, sizeof(OPTABLE))) == 0) {
SetErrCode (phr, E_OUTOFMEMORY);
return NULL;
}
lpOpTabStruct = (_LPOPTAB)_GLOBALLOCK(hOpTab);
/* Initialize the fields of the structure */
lpOpTabStruct->hStruct = hOpTab;
lpOpTabStruct->cEntry = OPERATOR_ENTRY_COUNT;
lpOpTabStruct->lpbOptable = NULL;
lpOpTabStruct->lpOpsymTab = (LPOPSYM)(OperatorSymbolTable);
return (LPOPTAB)lpOpTabStruct;
}
PRIVATE VOID PASCAL NEAR OpSymTabInit(LPOPSYM lpOpSymTab,
LPB lpbOpTable, WORD cEntry)
{
for (; cEntry > 0; cEntry--) {
lpOpSymTab->OpName = lpbOpTable;
lpbOpTable += *lpbOpTable + sizeof(BYTE);
lpOpSymTab->OpVal = GETWORD(lpbOpTable);
lpbOpTable += sizeof(unsigned short);
lpOpSymTab++;
}
}