/************************************************************************* * * * 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 #include #include #include #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++; } }