- BORLAND/: Borland C++ 4.52 (chosen over 4.5 by byte-match: CODE/RP/CW32.LIB
is identical to 4.52's install lib). BCC32/TLINK32/TLIB/MAKE run natively on
Win11; CODE/BT/OPT.MAK is the shipped BTL4OPT.EXE's exact flag recipe
(extender = Borland PowerPack DPMI32, not Phar Lap TNT).
- restoration/source410/: the literal 1995-form reconstruction of the missing
BT game source (never mixed into CODE/). Round 1-3 state:
* 6 of 10 surviving original TUs COMPILE CLEAN under the period toolchain
(BTMSSN, BTCNSL, BTSCNRL, BTTEAM, BTL4MODE, BTL4ARND) - first builds
since 1996.
* BT_L4/BTL4APP.CPP pilot reconstruction: 12/12 functions, Fail() lands on
its binary-recorded line 400 exactly.
* BT/BTCNSL.HPP: console wire IDs recovered from the binary's ctors
(Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1];
TeamScore=12 flagged [T4]).
* MUNGA/: 8 engine-header backfills back-dated from the BT412 WinTesla tree
(VDATA numbering decomp-verified; AUDREND's OpenAL-era virtual removed -
the period compiler is the drift detector).
* Tooling: backdate.py (WinTesla->1995 header transform), compile410.sh
(per-TU verification sweep under authentic OPT.MAK flags).
* README: corrected roadmap - MECH.HPP is the capstone grown with the mech
TU reconstructions; BTREG.CPP green = the header-family milestone.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
887 lines
27 KiB
C++
887 lines
27 KiB
C++
// BDE - (C) Copyright 1995 by Borland International
|
|
|
|
#include "dbfseek.h"
|
|
#include "macro.h"
|
|
|
|
#define szCURRENTMODULE "DBFSEEK"
|
|
|
|
//=====================================================================
|
|
// This BDE example provides Paradox for Windows ver. 5.0 ObjectPAL users
|
|
// a means of doing a seek similar to the dBASE seek of MAINTAINED
|
|
// expression indexes on dBASE tables for retrieving record numbers. The
|
|
// ObjectPAL procedures created are: DbfIdxSeek and DbfGetIdxExpr.
|
|
//
|
|
// Expressions tested in an MDX file:
|
|
//
|
|
// LTRIM(STR(MONTH(DATES)))+"/"+LTRIM(STR(DAY(DATES)))+"/"
|
|
// +SUBSTR(LTRIM(STR(YEAR(DATES))),3,2)
|
|
// LTRIM(FIRST_NAME)
|
|
// LTRIM(FIRST_NAME)-LTRIM(LAST_NAME)
|
|
// FIRST_NAME (a character field)
|
|
// FIRST_NAME-LAST_NAME
|
|
// FLOATS (a float field)
|
|
// NUMBERS (a number field)
|
|
// RECNO()
|
|
// RTRIM(FIRST_NAME) + DTOS(DATES)
|
|
// Indexes on concatenation of character and date field. The date
|
|
// field is converted to characters in format YYYYMMDD.
|
|
// i.e. - Jerry19950518.
|
|
// SQRT(NUMBERS)
|
|
// LTRIM(STR(FLOATS))
|
|
// SUBSTR(FIRST_NAME,2,3)
|
|
//
|
|
// Notes:
|
|
//
|
|
// DbfIdxSeek returns a record number. A return of 0 means that the record
|
|
// was not found.
|
|
//
|
|
// DbfGetIdxExpr is just for viewing an expression string.
|
|
//
|
|
// The EXACT setting, when set to FALSE, will find records with partial
|
|
// values in character expressions. EXACT set to TRUE sets NEAR to FALSE.
|
|
//
|
|
// EXACT: 0 = FALSE, 1 = TRUE
|
|
//
|
|
// The NEAR setting, after an unsuccessful dbfSEEK, positions the record
|
|
// pointer at the record in the indexed table immediately after the position
|
|
// at which the value searched for would have been found.
|
|
//
|
|
// NEAR: 0 = FALSE, 1 = TRUE
|
|
//
|
|
// Character expressions are case sensitive except for soundex which must
|
|
// sound like the key value for a match to occur.
|
|
//
|
|
// Use no commas in values seeking NUMERIC expressions.
|
|
//
|
|
// "Sounds like" can be used if SOUNDEX is the only function used
|
|
// and is at the beginning of the expression. All field names and
|
|
// other words must be contained within its perentheses i.e. -
|
|
// SOUNDEX(FIRST_NAME)
|
|
// SOUNDEX(FIRST_NAME-LAST_NAME)
|
|
//
|
|
// DATE fields can be used directly if the field name is at the beginning
|
|
// of the expression and is used alone i.e. -
|
|
// DATES (a date field)
|
|
//
|
|
//
|
|
// This is how the Paradox Uses block should appear:
|
|
//
|
|
// Uses dbfseek
|
|
//
|
|
// DbfIdxSeek(TableDir cptr, TableName cptr,
|
|
// IndexFileNameWithExtension cptr,
|
|
// IndexTagName cptr, KeyValue cptr,
|
|
// Exact cword, Near cword,
|
|
// returnStringBuffer cptr)cdouble
|
|
// DbfGetIdxExpr(TableDir cptr, TableName cptr,
|
|
// IndexFileNameWithExtension cptr,
|
|
// IndexTagName cptr, ReturnValue cptr)
|
|
//
|
|
// endUses
|
|
//
|
|
//
|
|
// And some typical methods:
|
|
//
|
|
// Var
|
|
// returnStringBuffer String
|
|
// endVar
|
|
//
|
|
//
|
|
// method open(var eventInfo Event)
|
|
//
|
|
// if eventInfo.isPreFilter() then
|
|
// ;// This code executes for each object on the form:
|
|
//
|
|
// else
|
|
// ;// This code executes only for the form:
|
|
//
|
|
// ; requires a 129 byte buffer:
|
|
// returnStringBuffer = space(129) ; VERY IMPORTANT! or GPF
|
|
//
|
|
// endif
|
|
//
|
|
// endmethod
|
|
//
|
|
//
|
|
// method pushButton(var eventInfo Event)
|
|
//
|
|
// var exact, near smallint endvar
|
|
// exact = 0
|
|
// near = 0
|
|
// RecNoReturn = DbfIdxSeek(workingdir(), "test.dbf",
|
|
// "test.mdx", "sometag",
|
|
// "somevalue", exact, near, returnStringBuffer)
|
|
// if RecNoReturn > 0 then
|
|
// TableFrameName.moveToRecNo(RecNoReturn)
|
|
// else
|
|
// TableFrameName.moveToRecNo(1)
|
|
// endif
|
|
// message(returnStringBuffer) ; for errors
|
|
//
|
|
// endmethod
|
|
//
|
|
//
|
|
// method pushButton(var eventInfo Event)
|
|
//
|
|
// DbfGetIdxExpr(workingdir(), "test.dbf", "test.mdx",
|
|
// "sometag", returnStringBuffer)
|
|
// view(returnStringBuffer)
|
|
//
|
|
// endmethod
|
|
//
|
|
//=====================================================================
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// DbfIdxSeek(pCHAR pTblDir, pCHAR pTblName, pCHAR pIdxName,
|
|
// pCHAR pIdxTag, pCHAR pKeyVal, pCHAR pszRetBuffer)
|
|
//
|
|
// Description:
|
|
// This example shows how to seek for a key value in a dBASE
|
|
// maintained key expression.
|
|
//
|
|
//=====================================================================
|
|
DFLOAT FAR WINAPI _export
|
|
DbfIdxSeek (pCHAR pTblDir, pCHAR pTblName, pCHAR pIdxName,
|
|
pCHAR pIdxTag, pCHAR pKeyVal, int bExact, int bNear,
|
|
pCHAR pszRetBuffer)
|
|
{
|
|
CHAR szTblType[] = szDBASE; // table type (dBASE)
|
|
UINT16 i = 0; // for loops
|
|
UINT16 iKeyValLen = 0; // for total key bytes received
|
|
UINT16 iKeyValEven = 1; // for total used key bytes
|
|
div_t x; // for calcing total used key bytes
|
|
FMTBcd Bcd;
|
|
CURProps TblProps;
|
|
IDXDesc *pIdxDesc = NULL;
|
|
DBIResult rslt = NULL;
|
|
UINT32 retVal = 0;
|
|
hDBIDb hDb = NULL;
|
|
hDBICur hCur = NULL;
|
|
pRECProps precProps = NULL;
|
|
char *ptok = NULL;
|
|
UINT16 iFldNum = 0;
|
|
DFLOAT fKeyVal = 0;
|
|
pFLDDesc pFldDesc = NULL;
|
|
char *ptrFunc, c = '(';
|
|
UINT16 iIndexSeqNumber = 0;
|
|
pBYTE pBuf = NULL; // Pointer to the record buffer
|
|
pBYTE pKeyBuf = NULL; // Pointer to the key buffer
|
|
BOOL bIsNegative = 0;
|
|
BOOL bExpFunc = 0;
|
|
BOOL bHasNoFld = 0;
|
|
BOOL bBlank = 0;
|
|
BOOL bBlankDate = 0;
|
|
UINT16 ptr = 0;
|
|
UINT16 iFldType = 0;
|
|
DBIDATE dateD = NULL;
|
|
UINT16 uDay = NULL; // Day portion of date
|
|
UINT16 uMon = NULL; // Month portion of date
|
|
INT16 iYear = NULL; // Year portion of date
|
|
char szYear[5]; // buffer for year
|
|
char szPlaces[2] = "4";
|
|
char *szKeyBuf1 = NULL;
|
|
char *szKeyBuf2 = NULL;
|
|
char *szKeyBuf3 = NULL;
|
|
char *szKeyBuf4 = NULL;
|
|
char *szFField = NULL; // buffer for first exp. field name
|
|
UINT16 uDecLen = 0; // Decimal length
|
|
|
|
if (bExact == 1)
|
|
{
|
|
bNear = 0;
|
|
}
|
|
|
|
// initialize buffer for error string
|
|
memset(pszRetBuffer, 0, (DBIMAXMSGLEN + 1) * sizeof(char));
|
|
|
|
// do nothing if a key value is not sent
|
|
CHKERR_NODISPLAY(!strcmp(pKeyVal, ""))
|
|
|
|
iKeyValLen = strlen(&pKeyVal[0]);
|
|
|
|
if (pKeyVal[0] == '-') // for negative numbers
|
|
{
|
|
bIsNegative = TRUE;
|
|
}
|
|
|
|
precProps = ((pRECProps) malloc (sizeof(RECProps)));
|
|
if (precProps == NULL)
|
|
{
|
|
GetString(1, pszRetBuffer); //"Out of Memory."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
// open a database in the current session and get a database handle
|
|
CHKERR_CLEANUP(DbiOpenDatabase(NULL, NULL, dbiREADONLY, dbiOPENSHARED,
|
|
NULL, 0, NULL, NULL, &hDb));
|
|
|
|
// set the current directory
|
|
CHKERR_CLEANUP(DbiSetDirectory(hDb, pTblDir));
|
|
|
|
// associate a cursor handle with an opened table
|
|
CHKERR_CLEANUP(DbiOpenTable(hDb, pTblName, NULL, pIdxName, pIdxTag,
|
|
0, dbiREADONLY, dbiOPENSHARED, xltFIELD,
|
|
FALSE, NULL, &hCur));
|
|
|
|
CHKERR_CLEANUP(DbiGetCursorProps(hCur, &TblProps));
|
|
|
|
if (strcmp(szTblType, TblProps.szTableType))
|
|
{
|
|
GetString(7, pszRetBuffer); //"Only dBASE tables are supported."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
pFldDesc = (pFLDDesc) malloc (sizeof(FLDDesc) * TblProps.iFields);
|
|
if (pFldDesc == NULL)
|
|
{
|
|
GetString(1, pszRetBuffer); //"Out of Memory."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
CHKERR_CLEANUP(DbiGetFieldDescs(hCur, pFldDesc));
|
|
|
|
pIdxDesc = (IDXDesc*) malloc (TblProps.iIndexes * sizeof(IDXDesc));
|
|
if (pIdxDesc == NULL)
|
|
{
|
|
GetString(1, pszRetBuffer); //"Out of Memory."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
CHKERR_CLEANUP(DbiGetIndexDescs(hCur, pIdxDesc));
|
|
|
|
pBuf = (pBYTE) malloc (TblProps.iRecBufSize);
|
|
if (pBuf == NULL)
|
|
{
|
|
GetString(1, pszRetBuffer); //"Out of Memory."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
CHKERR_CLEANUP(DbiInitRecord(hCur, pBuf));
|
|
|
|
CHKERR_CLEANUP(DbiGetIndexSeqNo(hCur, pIdxName, pIdxTag, NULL,
|
|
&iIndexSeqNumber));
|
|
|
|
if (pIdxDesc[iIndexSeqNumber - 1].bMaintained == 0)
|
|
{
|
|
GetString(3, pszRetBuffer); //"Only maintained indexes are supported."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
pKeyBuf = (pBYTE) malloc((pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 1) *
|
|
sizeof (BYTE));
|
|
szKeyBuf1 = (char*) malloc((pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 1) *
|
|
sizeof (char));
|
|
szKeyBuf2 = (char*) malloc((pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 1) *
|
|
sizeof (char));
|
|
szKeyBuf3 = (char*) malloc((pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 1) *
|
|
sizeof (char));
|
|
szKeyBuf4 = (char*) malloc((pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 1) *
|
|
sizeof (char));
|
|
// initialize buffer for first exp. field name
|
|
szFField = (char*) malloc((strlen(pIdxDesc[iIndexSeqNumber - 1].szKeyExp)
|
|
+ 1) * sizeof (char));
|
|
if ((szFField == NULL) ||
|
|
(pKeyBuf == NULL) ||
|
|
(szKeyBuf1 == NULL) ||
|
|
(szKeyBuf2 == NULL) ||
|
|
(szKeyBuf3 == NULL) ||
|
|
(szKeyBuf4 == NULL))
|
|
{
|
|
GetString(1, pszRetBuffer); //"Out of Memory."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
// does the expression contain soundex
|
|
ptrFunc = strchr(pIdxDesc[iIndexSeqNumber - 1].szKeyExp, c);
|
|
if (ptrFunc)
|
|
{
|
|
ptr = strncmpi("soundex", pIdxDesc[iIndexSeqNumber - 1].szKeyExp, 7);
|
|
if (ptr == 0)
|
|
{
|
|
bExpFunc = 1;
|
|
}
|
|
|
|
// get first field name and type disregarding function
|
|
ptok = strtok(pIdxDesc[iIndexSeqNumber - 1].szKeyExp, "(");
|
|
ptok = strtok('\0', " ()-+/*");
|
|
if (ptok)
|
|
{
|
|
strcpy(szFField, ptok);
|
|
}
|
|
else
|
|
{
|
|
// has no field name in the expression
|
|
bHasNoFld = 1;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// has no function, then assuming expression has a field name
|
|
ptok = strtok(pIdxDesc[iIndexSeqNumber - 1].szKeyExp, " -+/*");
|
|
if (ptok)
|
|
{
|
|
strcpy(szFField, ptok);
|
|
}
|
|
else
|
|
{
|
|
bHasNoFld = 1;
|
|
}
|
|
}
|
|
|
|
if (bHasNoFld == 0)
|
|
{
|
|
for (i = 0; i < TblProps.iFields; i++)
|
|
{
|
|
if (!strcmp(pFldDesc[i].szName, ptok))
|
|
{
|
|
iFldType = pFldDesc[i].iFldType;
|
|
iFldNum = pFldDesc[i].iFldNum;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (iFldType == fldDATE)
|
|
{
|
|
// set max input to key buffer
|
|
if (iKeyValLen > pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 3)
|
|
{
|
|
GetString(4, pszRetBuffer); //"Key length exceeded."
|
|
MessageBeep(-1);
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
if (pKeyVal[0] == ' ')
|
|
{
|
|
uMon = 12;
|
|
uDay = 31;
|
|
iYear = 9999;
|
|
bBlankDate = 1;
|
|
bNear = 1;
|
|
}
|
|
else
|
|
{
|
|
ptok = strtok(pKeyVal, " /");
|
|
if (ptok)
|
|
{
|
|
uMon = atoi(ptok);
|
|
}
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
ptok = strtok('\0', "/");
|
|
if ((i == 0)&&(ptok))
|
|
{
|
|
uDay = atoi(ptok);
|
|
}
|
|
|
|
if ((i == 1)&&(ptok))
|
|
{
|
|
// assumption: dates entered > 51 and <100 = 1950 otherwise
|
|
// it = 2050 unless 4 digit year is entered
|
|
if (atoi(ptok) > 50 && atoi(ptok) < 100)
|
|
{
|
|
if (atoi(ptok) > 50)
|
|
{
|
|
strcpy(szYear, "19");
|
|
strcat(szYear, ptok);
|
|
iYear = atoi(szYear);
|
|
}
|
|
else
|
|
{
|
|
strcpy(szYear, "20");
|
|
strcat(szYear, ptok);
|
|
iYear = atoi(szYear);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
strcpy(szYear, ptok);
|
|
iYear = atoi(szYear);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
CHKERR_CLEANUP(DbiDateEncode(uMon, uDay, iYear, &dateD));
|
|
|
|
CHKERR_CLEANUP(DbiPutField(hCur, iFldNum, pBuf, (pBYTE) &dateD));
|
|
|
|
CHKERR_CLEANUP(DbiExtractKey(hCur, pBuf, (pBYTE) pKeyBuf));
|
|
|
|
if (bNear == 1)
|
|
{
|
|
CHKERR_CLEANUP(DbiSetToKey(hCur, keySEARCHGEQ, TRUE, 0, 0,
|
|
pKeyBuf));
|
|
}
|
|
else
|
|
{
|
|
CHKERR_CLEANUP(DbiSetToKey(hCur, keySEARCHEQ, TRUE, 0, 0,
|
|
pKeyBuf));
|
|
}
|
|
|
|
CHKERR_CLEANUP(DbiGetNextRecord(hCur, dbiNOLOCK, pBuf, precProps));
|
|
|
|
CHKERR_CLEANUP(DbiGetField(hCur, iFldNum, pBuf, NULL, &bBlank));
|
|
|
|
if (bBlank)
|
|
{
|
|
// if set to near and the indate is larger than any key value,
|
|
// force an end of table (message only), otherwise a blank
|
|
// record gets found.
|
|
if (bNear == 1 && bBlankDate == 0)
|
|
{
|
|
GetString(9, pszRetBuffer); //"At end of table."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
}
|
|
|
|
retVal = precProps[0].iPhyRecNum;
|
|
}
|
|
else
|
|
{
|
|
if (pIdxDesc[iIndexSeqNumber - 1].iKeyExpType == fldDBCHAR)
|
|
{
|
|
// set key buffer for char expression type
|
|
memset(pKeyBuf, ' ', pIdxDesc[iIndexSeqNumber - 1].
|
|
iKeyLen + 1 * sizeof (BYTE));
|
|
|
|
if (bExpFunc == 0)
|
|
{
|
|
// set max input to key buffer
|
|
if (iKeyValLen > pIdxDesc[iIndexSeqNumber - 1].iKeyLen)
|
|
{
|
|
GetString(4, pszRetBuffer); //"Key length exceeded."
|
|
MessageBeep(-1);
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
memcpy((pCHAR)pKeyBuf, pKeyVal, iKeyValLen);
|
|
if (bExact == 0 && bNear == 0)
|
|
{
|
|
CHKERR_CLEANUP(DbiGetRecordForKey(hCur, TRUE, 0,
|
|
iKeyValLen, (pBYTE)
|
|
pKeyBuf, NULL));
|
|
|
|
CHKERR_CLEANUP(DbiGetRecord(hCur, dbiNOLOCK, NULL,
|
|
precProps));
|
|
|
|
}
|
|
if (bExact == 1)
|
|
{
|
|
CHKERR_CLEANUP(DbiGetRecordForKey(hCur, TRUE, 0,
|
|
0, (pBYTE) pKeyBuf,
|
|
NULL));
|
|
|
|
CHKERR_CLEANUP(DbiGetRecord(hCur, dbiNOLOCK, NULL,
|
|
precProps));
|
|
}
|
|
|
|
if (bNear == 1)
|
|
{
|
|
CHKERR_CLEANUP(DbiSetToKey(hCur, keySEARCHGEQ, TRUE, 0,
|
|
0, pKeyBuf));
|
|
|
|
CHKERR_CLEANUP(DbiGetNextRecord(hCur, dbiNOLOCK, pBuf,
|
|
precProps));
|
|
}
|
|
}
|
|
|
|
if (bExpFunc == 1) // for soundex
|
|
{
|
|
// if first char in pKeyVal is not a letter, fail
|
|
// (because DbiGetRecordForKey won't).
|
|
if (!((pKeyVal[0] > '@') && (pKeyVal[0] < '[')) &&
|
|
!((pKeyVal[0] > '`') && (pKeyVal[0] < '{')))
|
|
{
|
|
GetString(5, pszRetBuffer); //"Invalid character."
|
|
MessageBeep(-1);
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
CHKERR_CLEANUP(DbiPutField(hCur, iFldNum, pBuf,
|
|
(pBYTE) pKeyVal));
|
|
|
|
CHKERR_CLEANUP(DbiExtractKey(hCur, pBuf, (pBYTE) pKeyBuf));
|
|
|
|
CHKERR_CLEANUP(DbiGetRecordForKey(hCur, TRUE, 0, 0,
|
|
(pBYTE) pKeyBuf, NULL));
|
|
|
|
CHKERR_CLEANUP(DbiGetRecord(hCur, dbiNOLOCK, NULL, precProps));
|
|
}
|
|
|
|
retVal = precProps[0].iPhyRecNum;
|
|
}
|
|
|
|
if (pIdxDesc[iIndexSeqNumber - 1].iKeyExpType == fldDBKEYBCD)
|
|
{
|
|
// can't start with a space
|
|
if (pKeyVal[0] == ' ')
|
|
{
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
if (strchr(&pKeyVal[0], ','))
|
|
{
|
|
GetString(6, pszRetBuffer); //"Use no commas."
|
|
MessageBeep(-1);
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
// set max for input to key buffer
|
|
if (iKeyValLen > (pIdxDesc[iIndexSeqNumber - 1].iKeyLen) + 3)
|
|
{
|
|
GetString(4, pszRetBuffer); //"Key length exceeded."
|
|
MessageBeep(-1);
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
memset(pKeyBuf, '\0', pIdxDesc[iIndexSeqNumber - 1].
|
|
iKeyLen * sizeof (BYTE));
|
|
memset(szKeyBuf1, '\0', pIdxDesc[iIndexSeqNumber - 1].
|
|
iKeyLen * sizeof (char));
|
|
|
|
// OK, now for some decimal and negative number control...
|
|
if (pKeyVal[0] == '.' || (pKeyVal[0] == '-' && pKeyVal[1] == '.'))
|
|
{
|
|
GetString(8, pszRetBuffer); //"Enter 0 or -0 first."
|
|
MessageBeep(-1);
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
ptok = strtok(pKeyVal, " .");
|
|
strcpy(szKeyBuf4, ptok);
|
|
iKeyValLen = strlen(szKeyBuf4);
|
|
if (ptok)
|
|
{
|
|
ptok = strtok(NULL, ".");
|
|
if (ptok)
|
|
{
|
|
uDecLen = strlen(&ptok[0]);
|
|
strcat(szKeyBuf4, ptok);
|
|
i = 0;
|
|
if (szKeyBuf4[0] == '0')
|
|
{
|
|
while (szKeyBuf4[i] == '0')
|
|
{
|
|
i++;
|
|
}
|
|
strcpy(szKeyBuf2, &szKeyBuf4[i]);
|
|
}
|
|
else
|
|
{
|
|
szKeyBuf2 = strdup(szKeyBuf4);
|
|
iKeyValLen = strlen(szKeyBuf2);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
szKeyBuf2 = strdup(szKeyBuf4);
|
|
}
|
|
}
|
|
|
|
if (bIsNegative)
|
|
{
|
|
if (strlen(&pKeyVal[0]) > 1)
|
|
{
|
|
ptok = strtok(szKeyBuf2, " -");
|
|
strcpy(szKeyBuf3, ptok);
|
|
iKeyValLen = strlen(szKeyBuf3);
|
|
fKeyVal = atof(szKeyBuf3);
|
|
}
|
|
else
|
|
{
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
fKeyVal = atof(szKeyBuf2);
|
|
}
|
|
|
|
if (fKeyVal == 0)
|
|
{
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
// make total key bytes used an even number.
|
|
x = div(iKeyValLen, 2);
|
|
if (iKeyValLen > 1)
|
|
{
|
|
iKeyValEven = iKeyValLen;
|
|
}
|
|
|
|
if (x.rem == 1)
|
|
{
|
|
iKeyValEven = iKeyValLen + 1;
|
|
}
|
|
|
|
// setup first key buffer byte
|
|
szPlaces[0] = szPlaces[0] + (char)(iKeyValLen - uDecLen);
|
|
memmove(szKeyBuf1, szPlaces, 1);
|
|
|
|
// setup second key buffer byte
|
|
if (bIsNegative)
|
|
{
|
|
szPlaces[0] = (((iKeyValLen - 1) * 4) + 129);
|
|
}
|
|
else
|
|
{
|
|
szPlaces[0] = ((iKeyValLen * 4) + 1);
|
|
}
|
|
|
|
memmove(&szKeyBuf1[1], &szPlaces[0], 1);
|
|
|
|
CHKERR_CLEANUP(DbiBcdFromFloat(&fKeyVal, iKeyValLen + 2,
|
|
2, &Bcd));
|
|
|
|
if (iKeyValLen > 1)
|
|
{
|
|
iKeyValLen--;
|
|
}
|
|
|
|
for (i = 0; i < iKeyValLen; i++)
|
|
{
|
|
memmove(&szKeyBuf1[i + 2], &Bcd.iFraction[i], 1);
|
|
}
|
|
|
|
memcpy((pCHAR)pKeyBuf, szKeyBuf1, (iKeyValEven / 2) + 2);
|
|
|
|
if (bNear == 1)
|
|
{
|
|
CHKERR_CLEANUP(DbiSetToKey(hCur, keySEARCHGEQ, TRUE, 0, 0,
|
|
pKeyBuf));
|
|
}
|
|
else
|
|
{
|
|
CHKERR_CLEANUP(DbiSetToKey(hCur, keySEARCHEQ, TRUE, 0, 0,
|
|
pKeyBuf));
|
|
}
|
|
|
|
CHKERR_CLEANUP(DbiGetNextRecord(hCur, dbiNOLOCK, pBuf, precProps));
|
|
|
|
retVal = precProps[0].iPhyRecNum;
|
|
}
|
|
}
|
|
|
|
CleanUp:
|
|
if (hCur)
|
|
{
|
|
DbiCloseCursor(&hCur);
|
|
}
|
|
if (hDb)
|
|
{
|
|
DbiCloseDatabase(&hDb);
|
|
}
|
|
if (precProps)
|
|
{
|
|
free(precProps);
|
|
}
|
|
if (pBuf)
|
|
{
|
|
free(pBuf);
|
|
}
|
|
if (pKeyBuf)
|
|
{
|
|
free(pKeyBuf);
|
|
}
|
|
if (pIdxDesc)
|
|
{
|
|
free(pIdxDesc);
|
|
}
|
|
if (pFldDesc)
|
|
{
|
|
free(pFldDesc);
|
|
}
|
|
if (szKeyBuf1)
|
|
{
|
|
free(szKeyBuf1);
|
|
}
|
|
if (szKeyBuf2)
|
|
{
|
|
free(szKeyBuf2);
|
|
}
|
|
if (szKeyBuf3)
|
|
{
|
|
free(szKeyBuf3);
|
|
}
|
|
if (szKeyBuf4)
|
|
{
|
|
free(szKeyBuf4);
|
|
}
|
|
if (szFField)
|
|
{
|
|
free(szFField);
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// DbfGetIdxExpr(pCHAR pTblDir, pCHAR pTblName, pCHAR pIdxName,
|
|
// pCHAR pIdxTag, pCHAR pszRetBuffer)
|
|
//
|
|
// Description:
|
|
// This example shows how to return an expression string and
|
|
// other information about an MDX file.
|
|
//
|
|
//=====================================================================
|
|
void FAR WINAPI _export
|
|
DbfGetIdxExpr (pCHAR pTblDir, pCHAR pTblName, pCHAR pIdxName,
|
|
pCHAR pIdxTag, pCHAR pszRetBuffer)
|
|
{
|
|
CHAR szTblType[] = szDBASE;
|
|
DBIResult rslt;
|
|
CURProps TblProps;
|
|
UINT16 iIndexSeqNumber;
|
|
hDBIDb hDb = NULL;
|
|
hDBICur hCur = NULL;
|
|
IDXDesc *pIdxDesc = NULL;
|
|
|
|
// initialize buffer for error string
|
|
memset(pszRetBuffer, 0, (DBIMAXMSGLEN + 1) * sizeof(char));
|
|
|
|
// open a database in the current session and get a database handle
|
|
CHKERR_CLEANUP(DbiOpenDatabase(NULL, NULL, dbiREADONLY, dbiOPENSHARED,
|
|
NULL, 0, NULL, NULL, &hDb));
|
|
|
|
// set the current directory
|
|
CHKERR_CLEANUP(DbiSetDirectory(hDb, pTblDir));
|
|
|
|
// associate a cursor handle with an opened table
|
|
CHKERR_CLEANUP(DbiOpenTable(hDb, pTblName, NULL, pIdxName, pIdxTag,
|
|
0, dbiREADONLY, dbiOPENSHARED, xltFIELD,
|
|
FALSE, NULL, &hCur));
|
|
|
|
CHKERR_CLEANUP(DbiGetCursorProps(hCur, &TblProps));
|
|
|
|
if (strcmp(szTblType, TblProps.szTableType))
|
|
{
|
|
GetString(7, pszRetBuffer); //"Only dBASE tables are supported."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
pIdxDesc = (IDXDesc*) malloc (TblProps.iIndexes * sizeof(IDXDesc));
|
|
if (pIdxDesc == NULL)
|
|
{
|
|
GetString(1, pszRetBuffer); //"Out of Memory."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
CHKERR_CLEANUP(DbiGetIndexDescs(hCur, pIdxDesc));
|
|
|
|
CHKERR_CLEANUP(DbiGetIndexSeqNo(hCur, pIdxName, pIdxTag, NULL,
|
|
&iIndexSeqNumber));
|
|
|
|
if (pIdxDesc[iIndexSeqNumber - 1].bMaintained == 0)
|
|
{
|
|
GetString(3, pszRetBuffer); //"Only maintained indexes are supported."
|
|
CLEANUP_NODISPLAY;
|
|
}
|
|
|
|
strcpy(pszRetBuffer, pIdxDesc[iIndexSeqNumber - 1].szKeyExp);
|
|
|
|
CleanUp:
|
|
if (hCur)
|
|
{
|
|
DbiCloseCursor(&hCur);
|
|
}
|
|
if (hDb)
|
|
{
|
|
DbiCloseDatabase(&hDb);
|
|
}
|
|
if (pIdxDesc)
|
|
{
|
|
free(pIdxDesc);
|
|
}
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// DBIError(DBIResult retVal, pCHAR pszRetBuffer)
|
|
//
|
|
// Input:
|
|
// retVal - BDE return
|
|
// pszRetBuffer - Buffer to contain the error string
|
|
//
|
|
// Return: a DBIResult value.
|
|
//
|
|
// Description:
|
|
// This function gets information of where an error occurred.
|
|
//=====================================================================
|
|
DBIResult
|
|
DBIError (DBIResult retVal, pCHAR pszRetBuffer)
|
|
{
|
|
if (retVal == DBIERR_NONE)
|
|
{
|
|
return retVal;
|
|
}
|
|
|
|
if (retVal == DBIERR_CANTFINDODAPI)
|
|
{
|
|
GetString(2, pszRetBuffer); //"Cannot find IDAPI files: Check path."
|
|
CLEANUP_DISPLAYERR(pszRetBuffer);
|
|
}
|
|
else
|
|
{
|
|
DbiGetErrorString(retVal, pszRetBuffer);
|
|
}
|
|
|
|
CleanUp:
|
|
return retVal;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// GetString(WORD iStringID, pCHAR pszRetBuffer)
|
|
//
|
|
// Input:
|
|
// iStringID - Identifier for the string
|
|
// pszRetBuffer - Buffer to contain the error string.
|
|
// (Allocated by the calling function)
|
|
//
|
|
// Description:
|
|
// Load a string from DBFSEEK.DLL.
|
|
//=====================================================================
|
|
void
|
|
GetString (WORD iStringID, pCHAR pszRetBuffer)
|
|
{
|
|
if (pszRetBuffer)
|
|
{
|
|
LoadString(GetModuleHandle(szCURRENTMODULE), iStringID, pszRetBuffer,
|
|
DBIMAXMSGLEN - 1);
|
|
}
|
|
}
|
|
|
|
|
|
#pragma argsused
|
|
BOOL WINAPI
|
|
LibMain (HINSTANCE hInstance, WORD wDataSeg,
|
|
WORD cbHeapSize, LPSTR lpCmdLine)
|
|
{
|
|
if (cbHeapSize != 0)
|
|
{
|
|
UnlockData(0);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int WINAPI
|
|
WEP (int nSystemExit)
|
|
{
|
|
switch (nSystemExit)
|
|
{
|
|
case WEP_SYSTEM_EXIT:
|
|
break;
|
|
case WEP_FREE_DLL:
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|