- 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>
877 lines
34 KiB
C++
877 lines
34 KiB
C++
// BDE - (C) Copyright 1995 by Borland International
|
|
|
|
// Langdrv.C
|
|
#include "snipit.h"
|
|
|
|
#define MAXLEN 50
|
|
|
|
static DBIResult GetLdObjectFromLdName(hDBIDb hDb, pCHAR pLdName,
|
|
ppVOID ppLdObj);
|
|
static DBIResult IntlFillTable(hDBIDb hDb, pCHAR szTblName, pCHAR szTblType,
|
|
DFLOAT NumRecs);
|
|
static DBIResult IntlPutFieldSample(hDBICur hCur, pBYTE pRecBuf,
|
|
UINT16 FldNum, pFLDDesc pfldDesc);
|
|
static DBIResult IntlDisplayTable(hDBICur hCur, UINT32 uDisplayNRecs);
|
|
|
|
static const char szTblType[] = szPARADOX;
|
|
|
|
// Field descriptor used in creating the temporary table.
|
|
static SNIPFAR FLDDesc tmpFldDesc[] = {
|
|
{ // Field 1 - NUMERIC
|
|
1, "XNUM", fldFLOAT, fldUNKNOWN,
|
|
0, 0, 0, 0, 0, fldvNOCHECKS, fldrREADWRITE
|
|
}
|
|
}; // Array of field descriptors
|
|
|
|
static SNIPFAR FLDDesc OptFldDesc[] = {
|
|
{ 1, "LANGDRIVER", fldZSTRING, fldUNKNOWN,
|
|
DBIMAXTBLNAMELEN, 0, 0, DBIMAXSCFLDLEN, 0,
|
|
fldvNOCHECKS, fldrREADWRITE
|
|
}
|
|
}; // Array of field descriptors
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// LangDriver();
|
|
//
|
|
// Description:
|
|
// This sample code will create a Paradox table with the default
|
|
// Paradox language driver (as defined in the IDAPI configuration
|
|
// file), append 10 records to the table, and then delete the
|
|
// table. Field names, table names, and field data need to be
|
|
// converted when using non-ASCII characters. This code
|
|
// demonstrates how to do international support in IDAPI
|
|
// functions DbiGetLdName, DbiGetLdObj, DbiAnsiToNative and
|
|
// DbiNativeToAnsi.
|
|
//=====================================================================
|
|
void
|
|
LangDriver (void)
|
|
{
|
|
hDBIDb hDb; // Handle to the database
|
|
hDBICur hCur; // Handle to the table
|
|
CRTblDesc TblDesc; // Create table descriptor
|
|
UINT16 uDispNumRecs = 10 ; // Number of records to add
|
|
// and display
|
|
CHAR pDefLdName[DBIMAXNAMELEN]; // Default language driver
|
|
// name
|
|
pVOID pLdObj = NULL; // Language driver object
|
|
CHAR szDspTblName[DBIMAXNAMELEN]; // Buffer to hold table name
|
|
// for display (in ANSI
|
|
// character set)
|
|
UINT16 i; // Loop counter
|
|
BOOL bDataLoss; // Contains if data loss
|
|
// occured durring
|
|
// conversion
|
|
DBIResult rslt; // Return value from IDAPI
|
|
// functions
|
|
// Variables are declared local because they are changed within
|
|
// this example and need to be reset each time the example is run.
|
|
char szTblName[] = "ÇR8PXTßL";
|
|
|
|
// Field descriptor used in creating a table.
|
|
FLDDesc fldDesc[] = {
|
|
{ // Field 1 - ALPHA
|
|
1, // Field number
|
|
"ÄLPHÅ", // Field name
|
|
fldZSTRING, // Field type
|
|
fldUNKNOWN, // Field subtype
|
|
10, // Field size
|
|
0, // Decimal places ( 0 )
|
|
// computed
|
|
0, // Offset in record ( 0 )
|
|
0, // Length in bytes ( 0 )
|
|
0, // For Null bits ( 0 )
|
|
fldvNOCHECKS, // Validity checks ( 0 )
|
|
fldrREADWRITE // Rights
|
|
},
|
|
{ // Field 2 - NUMERIC
|
|
2, "ÑÜMERIC", fldFLOAT, fldUNKNOWN,
|
|
0, 0, 0, 0, 0, fldvNOCHECKS, fldrREADWRITE
|
|
},
|
|
{ // Field 3 - MONEY
|
|
3, "MÖNEY", fldFLOAT, fldstMONEY,
|
|
0, 0, 0, 0, 0, fldvNOCHECKS, fldrREADWRITE
|
|
},
|
|
{ // Field 4 - DATE
|
|
4, "DATÉ", fldDATE, fldUNKNOWN,
|
|
0, 0, 0, 0, 0, fldvNOCHECKS, fldrREADWRITE
|
|
},
|
|
{ // Field 5 - MEMO
|
|
5, "MÉMO", fldBLOB, fldstMEMO,
|
|
20, 0, 0, 0, 0, fldvNOCHECKS, fldrREADWRITE
|
|
}
|
|
}; // Array of field descriptors.
|
|
|
|
// The number of fields in the table.
|
|
const unsigned uNumFields = sizeof(fldDesc) / sizeof (fldDesc[0]);
|
|
|
|
Screen("*** Creating language independent applications ***\r\n");
|
|
|
|
BREAK_IN_DEBUGGER();
|
|
|
|
Screen(" Initializing IDAPI...");
|
|
if (InitAndConnect(&hDb) != DBIERR_NONE)
|
|
{
|
|
Screen("\r\n*** End of Example ***");
|
|
return;
|
|
}
|
|
|
|
Screen(" Setting the default database directory...");
|
|
rslt = DbiSetDirectory(hDb, (pCHAR)szTblDirectory);
|
|
ChkRslt(rslt, "SetDirectory");
|
|
|
|
// Table name is received from users in ANSI character set, but IDAPI
|
|
// expects it in OEM.
|
|
AnsiToOem((pCHAR)szTblName, (pCHAR)szTblName);
|
|
|
|
Screen(" Initializing the table descriptor...");
|
|
memset((void *) &TblDesc , 0, sizeof(CRTblDesc));
|
|
lstrcpy(TblDesc.szTblName, szTblName);
|
|
lstrcpy(TblDesc.szTblType, szTblType);
|
|
TblDesc.iFldCount = uNumFields;
|
|
|
|
// Translate field names in field descriptor from ANSI (as received
|
|
// from users) to the table's character set using table's language
|
|
// driver.
|
|
// Get default language driver name for specified table type. This
|
|
// will also be the language driver of the new table.
|
|
rslt = DbiGetLdName((pCHAR)szTblType, NULL, pDefLdName);
|
|
if (ChkRslt(rslt, "GetLdName") == DBIERR_NONE)
|
|
{
|
|
if (GetLdObjectFromLdName(hDb, pDefLdName, &pLdObj) == DBIERR_NONE)
|
|
{
|
|
for (i=0; i<uNumFields; i++)
|
|
{
|
|
rslt = DbiAnsiToNative(pLdObj, fldDesc[i].szName,
|
|
fldDesc[i].szName, NULL, &bDataLoss);
|
|
ChkRslt(rslt, "AnsiToNative");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CloseDbAndExit(&hDb);
|
|
Screen("\r\n*** End of Example ***");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CloseDbAndExit(&hDb);
|
|
Screen("\r\n*** End of Example ***");
|
|
return;
|
|
}
|
|
|
|
TblDesc.pfldDesc = fldDesc;
|
|
|
|
// Create and overwrite the table using the default language driver
|
|
// defined in the IDAPI configuration file.
|
|
Screen(" Creating the Paradox table...");
|
|
rslt = DbiCreateTable(hDb, TRUE, &TblDesc);
|
|
if (ChkRslt(rslt, "CreateTable") != DBIERR_NONE)
|
|
{
|
|
CloseDbAndExit(&hDb);
|
|
Screen("\r\n*** End of Example ***");
|
|
return;
|
|
}
|
|
|
|
Screen(" Fill the table with random data...");
|
|
IntlFillTable(hDb, (pCHAR)szTblName, (pCHAR)szTblType, uDispNumRecs);
|
|
|
|
// Open the table which we just created. The table name should be
|
|
// translated from the DOS character set to ANSI for display.
|
|
OemToAnsi(szTblName, szDspTblName);
|
|
Screen(" Open the \"%s\" table...", szDspTblName);
|
|
rslt = DbiOpenTable(hDb, (pCHAR)szTblName, (pCHAR)szTblType,
|
|
NULL, NULL, 0, dbiREADWRITE, dbiOPENSHARED,
|
|
xltFIELD, FALSE, NULL, &hCur);
|
|
if (ChkRslt(rslt, "OpenTable") != DBIERR_NONE)
|
|
{
|
|
rslt = DbiDeleteTable(hDb, (pCHAR)szTblName, (pCHAR)szTblType);
|
|
ChkRslt(rslt, "DeleteTable");
|
|
CloseDbAndExit(&hDb);
|
|
Screen("\r\n*** End of Example ***");
|
|
return;
|
|
}
|
|
|
|
Screen(" Display the \"%s\" table which we just created...",
|
|
szDspTblName);
|
|
IntlDisplayTable(hCur, uDispNumRecs);
|
|
|
|
Screen("\r\n Close the table...");
|
|
rslt = DbiCloseCursor(&hCur);
|
|
ChkRslt(rslt, "CloseCursor");
|
|
|
|
Screen(" Deleting the table...");
|
|
rslt = DbiDeleteTable(hDb, (pCHAR)szTblName, (pCHAR)szTblType);
|
|
ChkRslt(rslt, "DeleteTable");
|
|
|
|
Screen(" Close the database and exit IDAPI...");
|
|
CloseDbAndExit(&hDb);
|
|
|
|
Screen("\r\n*** End of Example ***");
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// GetLdObjectFromLdName(hDb, pLdName, ppLdObj)
|
|
//
|
|
// Input: hDb - Database handle
|
|
// pLdName - Language driver name
|
|
//
|
|
// Return: DBIResult - Success of the opperation
|
|
//
|
|
// Description:
|
|
// This function is used to get the language driver (LD) object from
|
|
// an LD name rather than from a table cursor (as in DbiGetLdObj).
|
|
// This allows us to get the LD object before a table is created.
|
|
// If a table exists, you may use DbiGetLdObj to get the LD object.
|
|
// The function creates a temporary table "__X123" (using optional
|
|
// parameters to specify the language driver name) and gets the LD
|
|
// object from the table. The temporary table will be deleted upon
|
|
// exiting IDAPI.
|
|
//=====================================================================
|
|
DBIResult
|
|
GetLdObjectFromLdName (hDBIDb hDb, pCHAR pLdName, ppVOID ppLdObj)
|
|
{
|
|
hDBICur hTmpCur; // Handle to the table
|
|
pCRTblDesc pTmpTblDesc; // Create table descriptor
|
|
DBIResult rslt; // Return value
|
|
DBIResult rslt2; // Return value to use during cleanup
|
|
|
|
CHAR szTmpTblName[] = "__X123";
|
|
|
|
pTmpTblDesc = (pCRTblDesc)malloc(sizeof(CRTblDesc));
|
|
|
|
// Initialize the Table create descriptor.
|
|
memset((void *) pTmpTblDesc , 0, sizeof(CRTblDesc));
|
|
lstrcpy(pTmpTblDesc->szTblName, szTmpTblName);
|
|
lstrcpy(pTmpTblDesc->szTblType, szPARADOX);
|
|
pTmpTblDesc->iFldCount = 1;
|
|
pTmpTblDesc->pfldDesc = tmpFldDesc;
|
|
pTmpTblDesc->iOptParams = 1;
|
|
pTmpTblDesc->pfldOptParams = OptFldDesc;
|
|
pTmpTblDesc->pOptData = (pBYTE)pLdName;
|
|
|
|
// Create and overwrite the table using specific language driver
|
|
// passed to the function.
|
|
rslt = DbiCreateTable(hDb, TRUE, pTmpTblDesc);
|
|
ChkRslt(rslt, "CreateTable");
|
|
if (rslt != DBIERR_NONE)
|
|
{
|
|
free(pTmpTblDesc);
|
|
Screen("\r\n GetLdObjectFromLdName\r\n");
|
|
return rslt;
|
|
}
|
|
|
|
rslt = DbiOpenTable(hDb, szTmpTblName, szPARADOX, NULL, NULL,
|
|
NULL, dbiREADONLY, dbiOPENSHARED, xltNONE,
|
|
FALSE, NULL, &hTmpCur);
|
|
ChkRslt(rslt, "OpenTable");
|
|
if (rslt != DBIERR_NONE)
|
|
{
|
|
free(pTmpTblDesc);
|
|
return rslt;
|
|
}
|
|
|
|
// Get LD object.
|
|
rslt = DbiGetLdObj(hTmpCur, ppLdObj);
|
|
ChkRslt(rslt, "GetLdObj");
|
|
if (rslt != DBIERR_NONE)
|
|
{
|
|
rslt2 = DbiCloseCursor(&hTmpCur);
|
|
ChkRslt(rslt2, "CloseCursor");
|
|
rslt2 = DbiDeleteTable(hDb, (pCHAR)szTmpTblName, (pCHAR)szTblType);
|
|
ChkRslt(rslt2, "DeleteTable");
|
|
free(pTmpTblDesc);
|
|
return rslt;
|
|
}
|
|
|
|
free(pTmpTblDesc);
|
|
rslt = DbiCloseCursor(&hTmpCur);
|
|
ChkRslt(rslt, "CloseCursor");
|
|
|
|
rslt = DbiDeleteTable(hDb, (pCHAR)szTmpTblName, (pCHAR)szTblType);
|
|
ChkRslt(rslt, "DeleteTable");
|
|
|
|
return rslt;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// IntlFillTable(hDb, szTblName, szTblType, NumRecs);
|
|
//
|
|
// Input: hDb - The database handle
|
|
// szTblName - Name of the table to fill
|
|
// szTblTyps - Type of the table to fill
|
|
// NumRecs - The number of records to insert
|
|
//
|
|
// Return: DBIResult - Success of the operation
|
|
//
|
|
// Description:
|
|
// This function adds the specified number of records to
|
|
// the table containing random data.
|
|
//=====================================================================
|
|
DBIResult
|
|
IntlFillTable (hDBIDb hDb, pCHAR szTblName, pCHAR szTblType, DFLOAT NumRecs)
|
|
{
|
|
DBIResult rslt; // Return value from IDAPI functions
|
|
DFLOAT fRecCount; // Loop variable = count of records
|
|
UINT16 FldCntr; // Field counter
|
|
pBYTE pRecBuf = NULL; // Pointer to the record buffer
|
|
FLDDesc fldDesc; // Field descriptor
|
|
CURProps TblProps; // Table descriptor
|
|
hDBICur hCur; // Handle to the table
|
|
hDBICur hFldList; // Handle to the field list table
|
|
|
|
rslt = DbiOpenTable(hDb, szTblName, szTblType, NULL, NULL, 0,
|
|
dbiREADWRITE, dbiOPENSHARED, xltFIELD, FALSE,
|
|
NULL, &hCur);
|
|
if (ChkRslt(rslt,"OpenTable") != DBIERR_NONE)
|
|
{
|
|
return rslt;
|
|
}
|
|
|
|
// Create an in-memory table that contains a list of fields. Note
|
|
// that logical (i.e. IDAPI types), are being requested instead of
|
|
// driver types.
|
|
rslt = DbiOpenFieldList(hDb, szTblName, szTblType, FALSE, &hFldList);
|
|
if (ChkRslt(rslt,"OpenFieldList")!= DBIERR_NONE)
|
|
{
|
|
rslt = DbiCloseCursor(&hCur);
|
|
ChkRslt(rslt, "CloseCursor");
|
|
return rslt;
|
|
}
|
|
|
|
// Append the records if the list and table are available.
|
|
if (hCur && hFldList)
|
|
{
|
|
ChkRslt(DbiGetCursorProps(hCur, &TblProps),
|
|
"GetCursorProps");
|
|
|
|
pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize);
|
|
if (!pRecBuf)
|
|
{
|
|
Screen("Out of Memory");
|
|
rslt = DbiCloseCursor(&hCur);
|
|
ChkRslt(rslt, "CloseCursor");
|
|
rslt = DbiCloseCursor(&hFldList);
|
|
ChkRslt(rslt, "CloseCursor");
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
// Loop until the specified number of records have been written
|
|
// to the table.
|
|
for (fRecCount = 0; fRecCount < NumRecs; fRecCount++)
|
|
{
|
|
// Make sure we're starting with a clean record buffer.
|
|
rslt = DbiInitRecord(hCur, pRecBuf);
|
|
ChkRslt(rslt, "InitRecord");
|
|
|
|
FldCntr = 1;
|
|
rslt = DbiSetToBegin(hFldList);
|
|
ChkRslt(rslt, "SetToBegin");
|
|
|
|
// This loop will use the previously opened field list to
|
|
// determine what type of data is inserted into the table.
|
|
while (DbiGetNextRecord(hFldList, dbiNOLOCK, (pBYTE) &fldDesc,
|
|
NULL) == DBIERR_NONE)
|
|
{
|
|
// Put field data into the record buffer.
|
|
IntlPutFieldSample(hCur, pRecBuf, FldCntr, &fldDesc);
|
|
FldCntr++;
|
|
}
|
|
|
|
// All fields have been inserted into the record buffer. Now
|
|
// we need to append the record to the table.
|
|
rslt = DbiAppendRecord(hCur, pRecBuf);
|
|
ChkRslt(rslt, "AppendRecord") ;
|
|
|
|
// Make sure to close all BLOBs (opened when data was put into
|
|
// the record buffer).
|
|
FldCntr = 1;
|
|
rslt = DbiSetToBegin(hFldList);
|
|
ChkRslt(rslt, "SetToBegin");
|
|
while (DbiGetNextRecord(hFldList, dbiNOLOCK, (pBYTE) &fldDesc,
|
|
NULL) == DBIERR_NONE)
|
|
{
|
|
if (fldDesc.iFldType == fldBLOB)
|
|
{
|
|
rslt = DbiFreeBlob(hCur, pRecBuf, FldCntr);
|
|
ChkRslt(rslt, "FreeBlob");
|
|
}
|
|
FldCntr++;
|
|
}
|
|
}
|
|
|
|
// Free allocated record buffer.
|
|
free((pCHAR) pRecBuf);
|
|
}
|
|
|
|
// Clean up and return.
|
|
rslt = DbiCloseCursor(&hFldList);
|
|
ChkRslt(rslt, "CloseCursor");
|
|
|
|
rslt = DbiCloseCursor(&hCur);
|
|
ChkRslt(rslt, "CloseCursor");
|
|
|
|
return DBIERR_NONE;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// IntlPutFieldSample(hCur, pRecBuf, FldNum, pfldDesc);
|
|
//
|
|
// Input: hCur - The handle for the table to fill
|
|
// pRecBuf - The record buffer to insert data into
|
|
// FldNum - The field we are generating
|
|
// pfldDesc - A descriptor that describes the field to generate
|
|
//
|
|
// Return: Result returned from DbiPutField()
|
|
//
|
|
// Description:
|
|
// This routine is used to put field data into a record
|
|
// buffer. Note that all logical field types are covered. You
|
|
// will need to refer to documentation, or run the DRVCAPS.C
|
|
// example for physical to logical field mappings.
|
|
//=====================================================================
|
|
DBIResult
|
|
IntlPutFieldSample (hDBICur hCur, pBYTE pRecBuf, UINT16 FldNum,
|
|
pFLDDesc pfldDesc)
|
|
{
|
|
pBYTE pBuf; // Buffer which contains the record data
|
|
DBIResult rslt; // Return value from IDAPI functions
|
|
INT16 i; // Loop counter
|
|
INT16 BlobSize; // Size of the BLOB
|
|
BOOL bDataLoss; // If any data is lost in translation
|
|
BOOL Bool; // Used for fldBOOL
|
|
INT16 Int16; // Used for fldINT16
|
|
UINT16 uInt16; // Used for fldUINT16
|
|
INT32 Int32; // Used for fldINT32
|
|
UINT32 uInt32; // Used for fldUINT32
|
|
DFLOAT Float; // Used for fldFLOAT
|
|
FMTBcd fmtBcd; // Used for fldBCD
|
|
DBIDATE Date; // Used for fldDATE
|
|
TIME Time; // Used for fldTIME
|
|
TIMESTAMP tStamp; // Used for fldTIMESTAMP
|
|
UINT16 month; // Used in generating the date
|
|
UINT16 day; // Used in generating the date
|
|
UINT16 year; // Used in generating the date
|
|
UINT16 hour; // Used in generating the time
|
|
UINT16 min; // Used in generating the time
|
|
UINT16 sec; // Used in generating the time
|
|
pVOID pLdObj = NULL; // Table's language driver object
|
|
|
|
// Allocate a generic buffer (used for string & blob fields).
|
|
pBuf = (pBYTE) malloc(4096);
|
|
if (!pBuf)
|
|
{
|
|
Screen(" Error - Out of memory.");
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
// This section contains sample code demonstrating how to
|
|
// insert a field of any type into a record buffer. Random data
|
|
// is used by this example. Field data is assumed to be in the ANSI
|
|
// character set, and needs to be translated into the table's
|
|
// character set before being inserted in the table.
|
|
|
|
// Get tables language driver.
|
|
rslt = DbiGetLdObj(hCur, &pLdObj);
|
|
ChkRslt(rslt, "GetLdObj");
|
|
|
|
switch (pfldDesc->iFldType)
|
|
{
|
|
case fldBYTES:
|
|
case fldZSTRING:
|
|
sprintf((pCHAR)pBuf, "Fïéld #%d", FldNum);
|
|
// Translate the character string. If table's language
|
|
// driver is based on the ANSI character set, no translation
|
|
// is performed.
|
|
rslt = DbiAnsiToNative(pLdObj, (pCHAR)pBuf, (pCHAR)pBuf, NULL,
|
|
&bDataLoss);
|
|
ChkRslt(rslt, "AnsiToNative");
|
|
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, pBuf);
|
|
break;
|
|
case fldDATE:
|
|
// Randomly generate and encode a date.
|
|
month = (rand() % 12) + 1;
|
|
day = (rand() % 20) + 1;
|
|
year = (rand() % 99) + 1900;
|
|
rslt = DbiDateEncode(month, day, year, &Date);
|
|
ChkRslt(rslt, "DateEncode");
|
|
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE) &Date);
|
|
break;
|
|
case fldBLOB:
|
|
// Generate a blob with length from 10-4010 bytes.
|
|
BlobSize = (rand() % 4000) + 11;
|
|
|
|
strcpy((pCHAR)pBuf, "BLÖB éxámple ");
|
|
|
|
// Write data to the BLOB field.
|
|
for (i = 0; i < (BlobSize % 11); i++)
|
|
{
|
|
strcat((pCHAR)pBuf, "BLÖB tèst ");
|
|
}
|
|
|
|
// Translate character data. If table's language
|
|
// driver is based on ANSI character set, no translation
|
|
// is performed.
|
|
rslt = DbiAnsiToNative(pLdObj, (pCHAR)pBuf, (pCHAR)pBuf, NULL,
|
|
&bDataLoss);
|
|
ChkRslt(rslt, "AnsiToNative");
|
|
|
|
// Init the BLOB header (contents defined by IDAPI client).
|
|
if ((pfldDesc->iSubType == fldstFMTMEMO) ||
|
|
(pfldDesc->iSubType == fldstOLEOBJ) ||
|
|
(pfldDesc->iSubType == fldstGRAPHIC))
|
|
{
|
|
memset(pBuf, 8, '\0');
|
|
}
|
|
|
|
// Open the BLOB prior to putting.
|
|
ChkRslt(DbiOpenBlob(hCur, pRecBuf, FldNum, dbiREADWRITE), "OpenBlob");
|
|
|
|
// Put the BLOB. Note that DbiFreeBlob() will be
|
|
// called after the record is inserted!
|
|
rslt = DbiPutBlob(hCur, pRecBuf, FldNum, 0, BlobSize,
|
|
pBuf);
|
|
break;
|
|
case fldBOOL:
|
|
// Boolean fields are either TRUE or FALSE.
|
|
if ((rand() % 100) < 50)
|
|
Bool = 1;
|
|
else
|
|
Bool = 0;
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&Bool);
|
|
break;
|
|
case fldINT16:
|
|
Int16 = (rand() % 255);
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&Int16);
|
|
break;
|
|
case fldBCD:
|
|
Float = (rand() / 1.21324);
|
|
rslt = DbiBcdFromFloat(&Float, pfldDesc->iUnits1,
|
|
pfldDesc->iUnits2, &fmtBcd);
|
|
ChkRslt(rslt, "BcdFromFloat");
|
|
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&fmtBcd);
|
|
break;
|
|
case fldLOCKINFO:
|
|
rslt = 0;
|
|
break;
|
|
case fldUINT16:
|
|
uInt16 = (rand() % 255);
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&uInt16);
|
|
break;
|
|
case fldINT32:
|
|
// Put the data into the record buffer if it is not an
|
|
// auto-increment field.
|
|
if (pfldDesc->iSubType != fldstAUTOINC)
|
|
{
|
|
Int32 = (rand() % 10000);
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&Int32);
|
|
}
|
|
else
|
|
{
|
|
// Don't have to put a value into an auto-increment field,
|
|
// but make certain not to return an error.
|
|
rslt = 0;
|
|
}
|
|
break;
|
|
case fldUINT32:
|
|
uInt32 = (rand() % 10000);
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&uInt32);
|
|
break;
|
|
case fldFLOAT:
|
|
Float = (rand() % 128000L);
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&Float);
|
|
break;
|
|
case fldTIME:
|
|
// Randomize and encode a time value.
|
|
hour = (rand() % 23) + 1;
|
|
min = (rand() % 59) + 1;
|
|
sec = ((rand() * 2) % 59999U) + 1;
|
|
rslt = DbiTimeEncode( hour, min, sec, &Time);
|
|
ChkRslt(rslt, "TimeEncode");
|
|
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&Time);
|
|
break;
|
|
case fldTIMESTAMP:
|
|
// Encode a date and a time.
|
|
month = (rand() % 12) + 1;
|
|
day = (rand() % 20) + 1;
|
|
year = (rand() % 99) + 1900;
|
|
rslt = DbiDateEncode(month, day, year, &Date);
|
|
ChkRslt(rslt, "DateEncode");
|
|
hour = (rand() % 23) + 1;
|
|
min = (rand() % 59) + 1;
|
|
sec = ((rand() * 2) % 59999U) + 1;
|
|
rslt = DbiTimeEncode(hour, min, sec, &Time);
|
|
ChkRslt(rslt, "TimeEncode");
|
|
|
|
// Now encode and put the time stamp.
|
|
rslt = DbiTimeStampEncode(Date, Time, &tStamp);
|
|
ChkRslt(rslt, "TimeStampEncode");
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&tStamp);
|
|
break;
|
|
case fldVARBYTES:
|
|
// Init the size (1st two bytes) and contents.
|
|
*((int *) pBuf) = (pfldDesc->iUnits1 - 2);
|
|
for (i = 2; i < pfldDesc->iUnits1; i++)
|
|
{
|
|
pBuf[i] = (rand() % 90) + 32;
|
|
}
|
|
pBuf[i] = '\0';
|
|
|
|
// Put the data into the record buffer.
|
|
rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)pBuf);
|
|
break;
|
|
default:
|
|
rslt = DBIERR_INVALIDFLDTYPE;
|
|
break;
|
|
}
|
|
// Determine if any of the previous DbiPutField functions failed.
|
|
ChkRslt(rslt, "PutField");
|
|
|
|
// Clean up and return.
|
|
free((pCHAR) pBuf);
|
|
return rslt;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// DisplayTable(hCur, uDisplayNRecs);
|
|
//
|
|
// Input: The cursor handle - Which table to access
|
|
// DisplayNRecs - How many records to display
|
|
// (0 means display all records in the table.)
|
|
//
|
|
// Return: Result of displaying the records in the table
|
|
//
|
|
// Descrption:
|
|
// This function will display all records in the table referenced
|
|
// by the cursor. Records are read from the table in blocks,
|
|
// making this function faster than the DisplayInMemoryTable()
|
|
// function.
|
|
//
|
|
// Note: This function will only display the columns
|
|
// correctly when using a fixed pitch font.
|
|
//=====================================================================
|
|
DBIResult
|
|
IntlDisplayTable (hDBICur hCur, UINT32 uDisplayNRecs)
|
|
{
|
|
DBIResult rslt = DBIERR_NONE; // Return value from IDAPI functions
|
|
CURProps TblProps; // Table properties
|
|
pFLDDesc pFldDescs; // List of fields
|
|
pBYTE pRecBuf; // Record buffer
|
|
CHAR** ppszField; // Array to contain the fields of the
|
|
// table
|
|
pCHAR szFormat; // Contains an entire record (row)
|
|
CHAR szTemp[MAXLEN] =""; // Temporary variable for reading data
|
|
UINT16 uFldNum; // Loop variable
|
|
UINT16 uMaxNumRecs = 30; // Maximum number of record to read
|
|
// from the table at a time
|
|
UINT32 uNumRecs; // Number of records Read in from the
|
|
// table
|
|
UINT16 uCount; // Loop variable
|
|
UINT32 uCurCountRec = 0; // Counter to keep track of how many
|
|
// records have been displayed
|
|
const UINT16 uDefLength = 15; // Default size of a field
|
|
pVOID pLdObj = NULL; // Language driver object
|
|
BOOL bDataLoss; // Data loss parameter for character
|
|
// translation
|
|
|
|
rslt = DbiGetCursorProps(hCur, &TblProps);
|
|
if ((ChkRslt(rslt, "GetCursorProps")) != DBIERR_NONE)
|
|
{
|
|
return rslt;
|
|
}
|
|
|
|
// Allocate memory for the format string.
|
|
szFormat = (pCHAR)malloc(1400);
|
|
// Allocate space for the record buffer.
|
|
pRecBuf = (pBYTE)malloc(TblProps.iRecBufSize * sizeof(BYTE) *
|
|
uMaxNumRecs);
|
|
// Allocate enough space to contain information (field descriptors)
|
|
// about all the fields in the answer table.
|
|
pFldDescs = (pFLDDesc)malloc(TblProps.iFields * sizeof(FLDDesc));
|
|
if ((!pFldDescs) || (!pRecBuf) || (!szFormat))
|
|
{
|
|
if (szFormat) free(szFormat);
|
|
if (pRecBuf) free(pRecBuf);
|
|
if (pFldDescs) free(pFldDescs);
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
szFormat[0] = 0;
|
|
|
|
// Get information about the fields.
|
|
rslt = DbiGetFieldDescs(hCur, pFldDescs);
|
|
ChkRslt(rslt, "GetFieldDescs");
|
|
|
|
// Allocate enough buffers to contain data from the fields in the
|
|
// answer table. Also set the width of non-fldZSTRING fields
|
|
// (all data will be converted to strings for display.)
|
|
ppszField = (CHAR**)malloc(TblProps.iFields * sizeof(CHAR*));
|
|
if (!ppszField)
|
|
{
|
|
free(szFormat);
|
|
free(pRecBuf);
|
|
free(pFldDescs);
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
SetupFields(TblProps, pFldDescs, ppszField, uDefLength);
|
|
// Get table language driver to translate field names from table's
|
|
// character set to ANSI for display.
|
|
rslt = DbiGetLdObj(hCur, &pLdObj);
|
|
if ((ChkRslt(rslt, "GetLdObj")) != DBIERR_NONE)
|
|
{
|
|
free(szFormat);
|
|
free(pRecBuf);
|
|
free(pFldDescs);
|
|
return rslt;
|
|
}
|
|
|
|
// Format the names of the fields, aligned by column.
|
|
strcpy(szFormat,"\r\n ");
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
sprintf(szTemp, "%-*s\t", pFldDescs[uFldNum].iUnits1 + 1,
|
|
pFldDescs[uFldNum].szName);
|
|
strcat(szFormat, szTemp);
|
|
}
|
|
|
|
// Translate field names from table's character set to ANSI for display.
|
|
rslt = DbiNativeToAnsi(pLdObj, szFormat, szFormat, NULL,
|
|
&bDataLoss);
|
|
if ((ChkRslt(rslt, "NativeToAnsi")) != DBIERR_NONE)
|
|
{
|
|
free(szFormat);
|
|
free(pRecBuf);
|
|
free(pFldDescs);
|
|
return rslt;
|
|
}
|
|
|
|
// Display the header information (field names).
|
|
Screen(szFormat);
|
|
|
|
// Get records from the table until the end of the table is reached
|
|
// Note that not all field types are supported. All supported field
|
|
// types are displayed as strings.
|
|
// The DbiReadBlock function is used in case field mapping
|
|
// is taking place - the GetNextRec, GetPriorRec, and GetRelativeRec
|
|
// functions do not take field mapping into consideration.
|
|
uNumRecs = uMaxNumRecs; // Set the number of records to read from the
|
|
// table as a block
|
|
// If uCurCoutRec == 0, display all the records in the table.
|
|
if (uDisplayNRecs == 0)
|
|
{
|
|
uDisplayNRecs = (UINT16)-1; // uDisplayNRecs is unsigned, so
|
|
// -1 maximizes the value.
|
|
}
|
|
// Get the records from the table and display.
|
|
do
|
|
{
|
|
// Limit the number of records to be read from the table -
|
|
// do not want to display more than uDisplayNRecs records.
|
|
if ((uNumRecs + uCurCountRec) > uDisplayNRecs)
|
|
{
|
|
uNumRecs = uDisplayNRecs - uCurCountRec;
|
|
}
|
|
// Read a block of records - this is more efficient than reading
|
|
// records one at a time from the table.
|
|
rslt = DbiReadBlock(hCur, &uNumRecs, pRecBuf);
|
|
if ((rslt != DBIERR_EOF) && // DBIERR_EOF is an expected return
|
|
(rslt != DBIERR_NONE)) // code - means cannot read more records.
|
|
{
|
|
free(szFormat);
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
free(ppszField[uFldNum]);
|
|
}
|
|
free(ppszField);
|
|
free(pFldDescs);
|
|
free(pRecBuf);
|
|
return rslt;
|
|
}
|
|
for (uCount=0; uCount < uNumRecs; uCount++)
|
|
{
|
|
uCurCountRec++;
|
|
|
|
// Fill the record buffer with the field values.
|
|
GetFields(hCur, pFldDescs,
|
|
&pRecBuf[uCount * TblProps.iRecBufSize],
|
|
ppszField, uDefLength);
|
|
|
|
// Add leading blank space to the record.
|
|
strcpy(szFormat," ");
|
|
// Add each field to be displayed, making certain that the
|
|
// columns line up.
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
sprintf(szTemp, " %-*s\t", pFldDescs[uFldNum].iUnits1,
|
|
ppszField[uFldNum]);
|
|
strcat(szFormat, szTemp);
|
|
}
|
|
// Translate table data from table's character set to ANSI for
|
|
// display.
|
|
rslt = DbiNativeToAnsi(pLdObj, szFormat, szFormat, NULL,
|
|
&bDataLoss);
|
|
if ((ChkRslt(rslt, "NativeToAnsi")) != DBIERR_NONE)
|
|
{
|
|
// Clean up.
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
free(ppszField[uFldNum]);
|
|
}
|
|
free(szFormat);
|
|
free(ppszField);
|
|
free(pFldDescs);
|
|
free(pRecBuf);
|
|
}
|
|
|
|
// Display the record.
|
|
Screen(szFormat);
|
|
} // For ... uCount.
|
|
// While ReadBlock reads as many records as are supposed to be
|
|
// batched (uMaxNumRecs) and the maximum number of records have not
|
|
// been read from the table. Reading a smaller number of records than
|
|
// that specified in uMaxNumRecs indicates that the end of the table has
|
|
// been reached.
|
|
} while((uNumRecs == uMaxNumRecs) &&
|
|
(uCurCountRec < uDisplayNRecs));
|
|
|
|
// Expect the End-Of-File error - just means that there
|
|
// aren't any more records in the table.
|
|
if (rslt == DBIERR_EOF)
|
|
{
|
|
rslt = DBIERR_NONE;
|
|
}
|
|
|
|
// Clean up.
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
free(ppszField[uFldNum]);
|
|
}
|
|
free(szFormat);
|
|
free(ppszField);
|
|
free(pFldDescs);
|
|
free(pRecBuf);
|
|
|
|
return DBIERR_NONE;
|
|
}
|
|
|