- 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>
1865 lines
64 KiB
C++
1865 lines
64 KiB
C++
// BDE - (C) Copyright 1995 by Borland International
|
|
|
|
// sniptool.c
|
|
#include "snipit.h"
|
|
|
|
#define MAXLEN 50
|
|
|
|
//===============================================================
|
|
// Function:
|
|
// Screen(Format, ...);
|
|
//
|
|
// Input: Format - A string that represents the format that
|
|
// the function vsprintf() uses
|
|
// ... - A varied number of input parameters (based
|
|
// on the needs of the format string)
|
|
//
|
|
// Return: None
|
|
//
|
|
// Description:
|
|
// This will build, and echo, a message.
|
|
//===============================================================
|
|
void
|
|
Screen (pCHAR Format, ...)
|
|
{
|
|
va_list argptr;
|
|
CHAR szMsg[1400];
|
|
pCHAR pBuf;
|
|
|
|
va_start(argptr, Format);
|
|
vsprintf(szMsg, Format, argptr);
|
|
va_end(argptr);
|
|
|
|
if (szMsg)
|
|
{
|
|
// Dump the string and output a CR+LF
|
|
pBuf = (pCHAR) malloc(lstrlen(szMsg) + 3);
|
|
wsprintf(pBuf, "%s\r\n", szMsg);
|
|
SendMsg(IDE_VIEWER_OUTPUT, EM_REPLACESEL, 0, (LPARAM)(LPCSTR)pBuf);
|
|
free(pBuf);
|
|
}
|
|
}
|
|
|
|
//==============================================================
|
|
// Function:
|
|
// ChkRslt(rslt, pMsg);
|
|
// Input: rslt - Return code from IDAPI
|
|
// pMsg - Null-terminated message
|
|
//
|
|
// Return: IDAPI return code passed in
|
|
//
|
|
// Description:
|
|
// This will echo an error message if the expected
|
|
// result does not equal the actual result. The output will be
|
|
// echoed to the screen.
|
|
//===============================================================
|
|
DBIResult
|
|
ChkRslt (DBIResult rslt, pCHAR pMsg)
|
|
{
|
|
DBIMSG dbi_status;
|
|
DBIErrInfo ErrInfo;
|
|
|
|
// Echo only if actual result doesn't equal expected result
|
|
if (rslt != DBIERR_NONE)
|
|
{
|
|
// Get as much error information as possible
|
|
DbiGetErrorInfo(TRUE, &ErrInfo);
|
|
|
|
// Make certain information is returned on the correct error
|
|
if (ErrInfo.iError == rslt)
|
|
{
|
|
Screen(" ERROR - %s"
|
|
"\r\n Cat:Code = [%xh:%xh]"
|
|
"\r\n %s",
|
|
pMsg, ErrCat(ErrInfo.iError), ErrCode(ErrInfo.iError),
|
|
ErrInfo.szErrCode);
|
|
|
|
if (strcmp(ErrInfo.szContext1, ""))
|
|
{
|
|
Screen(" %s",
|
|
ErrInfo.szContext1);
|
|
}
|
|
if (strcmp(ErrInfo.szContext2, ""))
|
|
{
|
|
Screen(" %s",
|
|
ErrInfo.szContext2);
|
|
}
|
|
if (strcmp(ErrInfo.szContext3, ""))
|
|
{
|
|
Screen(" %s",
|
|
ErrInfo.szContext3);
|
|
}
|
|
if (strcmp(ErrInfo.szContext4, ""))
|
|
{
|
|
Screen(" %s",
|
|
ErrInfo.szContext4);
|
|
}
|
|
}
|
|
else {
|
|
DbiGetErrorString(rslt, dbi_status);
|
|
Screen(" ERROR - %s Cat:Code [%xh:%xh]\r\n"
|
|
" %s",
|
|
pMsg, ErrCat(rslt), ErrCode(rslt), dbi_status);
|
|
}
|
|
}
|
|
return rslt;
|
|
}
|
|
|
|
//===============================================================
|
|
// Function:
|
|
// WinMsg(Msg, TypeMsg, TypeBtn);
|
|
//
|
|
// Input: Msg - The message to display
|
|
// TypeMsg - The type of messagebox to use (i.e. Stop,
|
|
// Information)
|
|
// TypeBtn - The buttons to use (i.e. Yes, No, OK, ...)
|
|
//
|
|
// Return: Response from the user
|
|
//
|
|
// Description:
|
|
// Display a message box and return a value representing
|
|
// the button the user pressed.
|
|
//================================================================
|
|
INT16
|
|
WinMsg (pCHAR pMsg, INT16 TypeMsg, INT16 TypeBtn)
|
|
{
|
|
INT16 Style, Buttons;
|
|
|
|
// Set the style of message box to display
|
|
switch (TypeMsg)
|
|
{
|
|
case MSG_INFO:
|
|
Style = MB_ICONINFORMATION;
|
|
break;
|
|
case MSG_QUESTION:
|
|
Style = MB_ICONQUESTION;
|
|
break;
|
|
case MSG_STOP:
|
|
Style = MB_ICONSTOP;
|
|
break;
|
|
default:
|
|
case MSG_EXCLAMATION:
|
|
Style = MB_ICONEXCLAMATION;
|
|
break;
|
|
}
|
|
|
|
// Set the style of buttons to make available
|
|
switch (TypeBtn)
|
|
{
|
|
case BTN_OK_CANCEL:
|
|
Buttons = MB_OKCANCEL;
|
|
break;
|
|
case BTN_RETRY_CANCEL:
|
|
Buttons = MB_RETRYCANCEL;
|
|
break;
|
|
case BTN_YES_NO:
|
|
Buttons = MB_YESNO;
|
|
break;
|
|
case BTN_YES_NO_CANCEL:
|
|
Buttons = MB_YESNOCANCEL;
|
|
break;
|
|
default:
|
|
case BTN_OK:
|
|
Buttons = MB_OK;
|
|
break;
|
|
}
|
|
return MessageBox(hMainWnd, (LPSTR) pMsg, "Code Viewer Message",
|
|
(WORD) Buttons | Style | MB_APPLMODAL);
|
|
}
|
|
|
|
//===============================================================
|
|
// Function:
|
|
// InitAndConnect(phDb);
|
|
//
|
|
// Input: phDb - Pointer to the database handle
|
|
//
|
|
// Return: IDAPI return code after DbiInit() and DbiOpenDatabase()
|
|
//
|
|
// Description:
|
|
// Initialize IDAPI and connect to a Standard
|
|
// database (non-SQL).
|
|
//================================================================
|
|
DBIResult
|
|
InitAndConnect (phDBIDb phDb)
|
|
{
|
|
DBIResult rslt;
|
|
|
|
// Initialize IDAPI with a NULL environment structure
|
|
rslt = DbiInit(NULL);
|
|
if (ChkRslt(rslt, "Init") == DBIERR_NONE)
|
|
{
|
|
DbiDebugLayerOptions(DEBUGON | OUTPUTTOFILE, "SNIPIT.INF");
|
|
|
|
// IDAPI initialized. Now open a Standard database (used to access
|
|
// Paradox and dBASE tables), by using a NULL database type.
|
|
rslt = DbiOpenDatabase(NULL, NULL, dbiREADWRITE, dbiOPENSHARED,
|
|
NULL, 0, NULL, NULL, phDb);
|
|
if (ChkRslt(rslt, "OpenDatabase") != DBIERR_NONE)
|
|
{
|
|
rslt = DbiExit();
|
|
ChkRslt(rslt, "Exit");
|
|
}
|
|
|
|
rslt = DbiSetPrivateDir(szPrivDirectory);
|
|
if (ChkRslt(rslt, "SetPrivateDir") != DBIERR_NONE)
|
|
{
|
|
CloseDbAndExit(phDb);
|
|
}
|
|
}
|
|
return rslt;
|
|
}
|
|
|
|
//===============================================================
|
|
// Function:
|
|
// InitAndConnect2(phDb);
|
|
//
|
|
// Input: phDb - Pointer to the database handle
|
|
//
|
|
// Return: IDAPI return code after DbiInit() and DbiOpenDatabase()
|
|
//
|
|
// Description:
|
|
// Initialize IDAPI and connect to a SQL database.
|
|
//================================================================
|
|
DBIResult
|
|
InitAndConnect2 (phDBIDb phDb)
|
|
{
|
|
DBIResult rslt;
|
|
FARPROC lpTempProc;
|
|
|
|
// Initialize IDAPI with a NULL environment structure.
|
|
*phDb = NULL;
|
|
rslt = DbiInit(NULL);
|
|
if (ChkRslt(rslt, "Init") == DBIERR_NONE)
|
|
{
|
|
DbiDebugLayerOptions(DEBUGON | OUTPUTTOFILE, "SNIPIT.INF");
|
|
|
|
// Get a handle to an IDAPI database (STANDARD database handle
|
|
// can be returned, but this is mainly used for SQL connections).
|
|
lpTempProc =
|
|
MakeProcInstance((FARPROC) ConnectDlgProc, hInst);
|
|
DialogBox(hInst, "ConnectDlg", hMainWnd, (DLGPROC) lpTempProc);
|
|
FreeProcInstance((FARPROC) lpTempProc);
|
|
|
|
// Return the handle (if connect worked).
|
|
if (SnipItDb)
|
|
*phDb = SnipItDb;
|
|
else
|
|
{
|
|
rslt = DbiExit();
|
|
ChkRslt(rslt, "Exit");
|
|
|
|
// Connect failed or CANCEL was hit.
|
|
rslt = DBIERR_INVALIDHNDL;
|
|
return rslt;
|
|
}
|
|
|
|
rslt = DbiSetPrivateDir(szPrivDirectory);
|
|
if (ChkRslt(rslt, "SetPrivateDir") != DBIERR_NONE)
|
|
{
|
|
CloseDbAndExit(phDb);
|
|
}
|
|
}
|
|
return rslt;
|
|
}
|
|
|
|
//===============================================================
|
|
// Function:
|
|
// CloseDbAndExit(phDb);
|
|
//
|
|
// Input: phDb - Pointer to the database handle
|
|
//
|
|
// Return: IDAPI return code after DbiCloseDatabase() and DbiExit()
|
|
//
|
|
// Description:
|
|
// Close the supplied database and exit IDAPI.
|
|
//================================================================
|
|
DBIResult
|
|
CloseDbAndExit (phDBIDb phDb)
|
|
{
|
|
DBIResult rslt;
|
|
|
|
// Close the supplied database
|
|
rslt = DbiCloseDatabase(phDb);
|
|
if (ChkRslt(rslt, "CloseDatabase") == DBIERR_NONE)
|
|
{
|
|
DbiDebugLayerOptions(0, NULL);
|
|
|
|
rslt = DbiExit();
|
|
ChkRslt(rslt, "Exit");
|
|
}
|
|
return rslt;
|
|
}
|
|
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// FillTable(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?
|
|
//
|
|
// Description:
|
|
// This function adds the specified number of records to
|
|
// the table. The records will contain random data.
|
|
//=====================================================================
|
|
DBIResult
|
|
FillTable (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
|
|
|
|
// Echo the message that the records are being inserted.
|
|
Screen(" Inserting %.0f records into the table...", NumRecs);
|
|
|
|
// Open the 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);
|
|
return(ChkRslt(rslt, "CloseCursor"));
|
|
}
|
|
|
|
// Append the records if the list and table are available
|
|
if (hCur && hFldList)
|
|
{
|
|
// Allocate a record buffer
|
|
rslt = DbiGetCursorProps(hCur, &TblProps);
|
|
ChkRslt(rslt, "GetCursorProps");
|
|
|
|
pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize);
|
|
if (pRecBuf == NULL)
|
|
{
|
|
Screen(" Error - 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");
|
|
|
|
// Start at the beginning of the field list. Setting the
|
|
// cursor to the start of the table (i.e. BOF), does not leave
|
|
// you on a record. You are effectively left on a crack.
|
|
// Because of this, you will need to go to the next record in
|
|
// the table to reach the first record of the table.
|
|
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.
|
|
PutFieldSample(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, "InsertRecord");
|
|
|
|
// 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:
|
|
// CreateAndFillTable(hDb, pTblDesc, NumRecs, phCur);
|
|
//
|
|
// Input: hDb - Database handle
|
|
// pTblDesc - Pointer to a descriptor for the table to
|
|
// create
|
|
// phCur - Pointer to table cursor (NULL means do not
|
|
// open the table after creating
|
|
//
|
|
// Return: IDAPI return code
|
|
//
|
|
// Description:
|
|
// Create a table based on the table descriptor
|
|
// supplied. If "phCur != NULL" then the table will be opened,
|
|
// and the table cursor will be passed back through this parameter.
|
|
//================================================================
|
|
DBIResult
|
|
CreateAndFillTable (hDBIDb hDb, pCRTblDesc pTblDesc, DFLOAT NumRecs,
|
|
phDBICur phCur)
|
|
{
|
|
DBIResult rslt;
|
|
|
|
Screen(" Creating table \"%s\"...", pTblDesc->szTblName);
|
|
rslt = DbiCreateTable(hDb, TRUE, pTblDesc);
|
|
if (ChkRslt(rslt, "CreateTable") == DBIERR_NONE)
|
|
{
|
|
// Call the routine that will fill the table.
|
|
rslt = FillTable(hDb, pTblDesc->szTblName, pTblDesc->szTblType,
|
|
NumRecs);
|
|
|
|
// Open the table if the create and fill worked.
|
|
if ((rslt == DBIERR_NONE) && phCur)
|
|
{
|
|
rslt = DbiOpenTable(hDb, pTblDesc->szTblName,
|
|
pTblDesc->szTblType, NULL, NULL, 0,
|
|
dbiREADWRITE, dbiOPENSHARED, xltFIELD,
|
|
FALSE, NULL, phCur);
|
|
ChkRslt(rslt, "OpenTable");
|
|
}
|
|
}
|
|
return rslt;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// DisplayInMemoryTable();
|
|
//
|
|
// Input: The cursor handle - which table to access
|
|
// DisplayNRecs - How many records to display
|
|
// (0 means all in the table)
|
|
//
|
|
// Return: Result of displaying the records in the table
|
|
//
|
|
// Description:
|
|
// This function will display all records in the table referenced
|
|
// by the cursor. This function is used to display
|
|
// in-memory and schema tables which do not support
|
|
// the use of ReadBlock ( which is used in DisplayTable )
|
|
//
|
|
// Note: This function will only display the columns
|
|
// correctly when using a fixed pitch font.
|
|
//=====================================================================
|
|
DBIResult
|
|
DisplayInMemoryTable (hDBICur hCur, UINT32 uDisplayNRecs)
|
|
{
|
|
DBIResult rslt; // IDAPI function return value
|
|
CURProps TblProps; // Table Properties
|
|
pFLDDesc pFldDescs; // List of fields
|
|
pBYTE pRecBuf; // Record Buffer
|
|
CHAR** pszField; // Array to contain the fields of the
|
|
// table.
|
|
CHAR* szFormat; // Contains an entire record (row)
|
|
CHAR szTemp[MAXLEN] =""; // Temporary variable for reading data
|
|
UINT16 uFldNum; // 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
|
|
|
|
szFormat = (pCHAR) malloc(1600 * sizeof(BYTE));
|
|
if (szFormat == NULL)
|
|
{
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
rslt = DbiGetCursorProps(hCur, &TblProps);
|
|
if (ChkRslt(rslt, "GetCursorProps") != DBIERR_NONE)
|
|
{
|
|
free(szFormat);
|
|
return rslt;
|
|
}
|
|
|
|
// Allocate space for the record buffer
|
|
pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize * sizeof(BYTE));
|
|
if (pRecBuf == NULL)
|
|
{
|
|
Screen(" Error - Out of memory");
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
// 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 == NULL)
|
|
{
|
|
free(szFormat);
|
|
free(pRecBuf);
|
|
Screen(" Error - Out of memory");
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
// 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 sets the width of non-fldZSTRING fields
|
|
// (all data will be converted to strings for display )
|
|
pszField = (CHAR**) malloc(TblProps.iFields * sizeof(CHAR*));
|
|
|
|
// Set up formatting for the fields
|
|
SetupFields(TblProps, pFldDescs, pszField, uDefLength);
|
|
|
|
// Display 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);
|
|
}
|
|
|
|
// Display the header.
|
|
Screen(szFormat);
|
|
|
|
// Get records from the table until the end of the table is reached
|
|
// or the maximum number of records is reached.
|
|
// Note that not all field types are supported. All supported field
|
|
// types are displayed as strings.
|
|
if (uDisplayNRecs == 0)
|
|
{
|
|
uDisplayNRecs = (UINT16)-1; // uDisplayNRecs is unsigned, so
|
|
// -1 maximizes the value
|
|
}
|
|
|
|
while ((uCurCountRec < uDisplayNRecs) &&
|
|
((rslt = DbiGetNextRecord(hCur, dbiNOLOCK, pRecBuf, NULL))
|
|
== DBIERR_NONE))
|
|
{
|
|
// Fill the record buffer with the field values.
|
|
uCurCountRec++;
|
|
GetFields(hCur, pFldDescs, pRecBuf, pszField, uDefLength);
|
|
|
|
// Initialize szFormat to all zeroes.
|
|
memset(szFormat, 0, sizeof(szFormat));
|
|
|
|
// 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,
|
|
pszField[uFldNum]);
|
|
strcat(szFormat, szTemp);
|
|
}
|
|
|
|
// Display the record.
|
|
Screen(szFormat);
|
|
}
|
|
|
|
// Expect the End-Of-File error - just means that there
|
|
// are no more records in the table.
|
|
if (rslt == DBIERR_EOF)
|
|
rslt = DBIERR_NONE;
|
|
|
|
// Clean up.
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
free(pszField[uFldNum]);
|
|
}
|
|
|
|
free(pszField);
|
|
free(pFldDescs);
|
|
free(pRecBuf);
|
|
free(szFormat);
|
|
|
|
return rslt;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// DisplayTable();
|
|
//
|
|
// 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
|
|
//
|
|
// Description:
|
|
// 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
|
|
DisplayTable (hDBICur hCur, UINT32 uDisplayNRecs)
|
|
{
|
|
DBIResult rslt; // IDAPI function return value
|
|
CURProps TblProps; // Table Properties
|
|
pFLDDesc pFldDescs; // List of fields
|
|
pBYTE pRecBuf; // Record Buffer
|
|
CHAR** pszField; // 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 records 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
|
|
|
|
// Allocate memory for the format string
|
|
szFormat = (pCHAR) malloc(2000);
|
|
if (szFormat == NULL)
|
|
{
|
|
Screen(" Error - Out of memory");
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
// Set szFormat == "".
|
|
szFormat[0] = 0;
|
|
|
|
// Get the size of the record buffer.
|
|
rslt = DbiGetCursorProps(hCur, &TblProps);
|
|
if (ChkRslt(rslt, "GetCursorProps") != DBIERR_NONE)
|
|
{
|
|
free(szFormat);
|
|
return rslt;
|
|
}
|
|
|
|
// Allocate space for the record buffer.
|
|
pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize * sizeof(BYTE) *
|
|
uMaxNumRecs);
|
|
if (pRecBuf == NULL)
|
|
{
|
|
free(szFormat);
|
|
Screen(" Error - Out of memory");
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
// 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 == NULL)
|
|
{
|
|
free(szFormat);
|
|
free(pRecBuf);
|
|
Screen(" Error - Out of memory");
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
// 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 sets the width of non-fldZSTRING fields
|
|
// (all data will be converted to strings for display )
|
|
pszField = (CHAR**) malloc(TblProps.iFields * sizeof(CHAR*));
|
|
if (pszField == NULL)
|
|
{
|
|
free(szFormat);
|
|
free(pRecBuf);
|
|
free(pFldDescs);
|
|
Screen(" Error - Out of memory");
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
SetupFields(TblProps, pFldDescs, pszField, uDefLength);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// 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.
|
|
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 total records than is specified
|
|
// in uDisplayNRecs.
|
|
if ((uNumRecs + uCurCountRec) > uDisplayNRecs)
|
|
{
|
|
uNumRecs = uDisplayNRecs - uCurCountRec;
|
|
}
|
|
|
|
// Read a block of records - reading more than one record at a
|
|
// time is more efficient than reading records one at a time from
|
|
// the table.
|
|
rslt = DbiReadBlock(hCur, &uNumRecs, pRecBuf);
|
|
if ((rslt != DBIERR_EOF) && (rslt != DBIERR_NONE))
|
|
{
|
|
ChkRslt(rslt, "ReadBlock");
|
|
free(szFormat);
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
free(pszField[uFldNum]);
|
|
}
|
|
free(pszField);
|
|
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],
|
|
pszField, 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,
|
|
pszField[uFldNum]);
|
|
strcat(szFormat, szTemp);
|
|
}
|
|
|
|
// 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. If fewer than uMaxNumRecs records were
|
|
// read, we reached the end of the table.
|
|
} while ((uNumRecs == uMaxNumRecs) && (uCurCountRec < uDisplayNRecs));
|
|
|
|
// Expect the End-Of-File error - just means that there
|
|
// are no more records in the table.
|
|
if (rslt == DBIERR_EOF)
|
|
{
|
|
rslt = DBIERR_NONE;
|
|
}
|
|
|
|
// Clean up.
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
free(pszField[uFldNum]);
|
|
}
|
|
free(szFormat);
|
|
free(pszField);
|
|
free(pFldDescs);
|
|
free(pRecBuf);
|
|
|
|
return DBIERR_NONE;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// GetFields(hCur, pFldDescs, pRecBuf, pszField, uDefLength)
|
|
//
|
|
// Input: hCur - Handle to the Cursor
|
|
// pFldDescs - Field Descriptor
|
|
// pRecBuf - Record buffer - contains the record from
|
|
// which the field values are to be retrieved.
|
|
// pszField - Fields in the table
|
|
// uDefLength - Default length of a field
|
|
//
|
|
// Return: Success of the operation
|
|
//
|
|
// Description:
|
|
// This function is used to extract all field values from
|
|
// a record and place them into an array of strings.
|
|
//=====================================================================
|
|
DBIResult
|
|
GetFields (hDBICur hCur, pFLDDesc pFldDescs, pBYTE pRecBuf,
|
|
CHAR ** pszField, UINT16 uDefLength)
|
|
{
|
|
DBIResult rslt; // Return value from IDAPI functions
|
|
CURProps TblProps; // Properties of the table
|
|
UINT16 uFldNum; // Loop Counter - used to determine the
|
|
// current field
|
|
CHAR szTemp[MAXLEN] =""; // Temporary variable for reading data
|
|
UINT32 ulBlobSize; // Size of the BLOB
|
|
DFLOAT lfFloat; // Float value
|
|
BOOL bIsBlank; // Check if the field is blank
|
|
|
|
rslt = DbiGetCursorProps(hCur, &TblProps);
|
|
if (ChkRslt(rslt, "GetCursorProps") != DBIERR_NONE)
|
|
{
|
|
return rslt;
|
|
}
|
|
|
|
// Get the field values from the record. Gets each field from
|
|
// the table, placing the results in the pszField variable.
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
switch (pFldDescs[uFldNum].iFldType)
|
|
{
|
|
case fldBYTES:
|
|
case fldZSTRING:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE) pszField[uFldNum],
|
|
&bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
break;
|
|
case fldFLOAT:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE) szTemp, &bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
if (! bIsBlank)
|
|
{
|
|
if (pFldDescs[uFldNum].iSubType == fldstMONEY)
|
|
{
|
|
sprintf(pszField[uFldNum], "$%.2lf",
|
|
*(DFLOAT *)szTemp);
|
|
}
|
|
else
|
|
{
|
|
sprintf(pszField[uFldNum], "%.1lf",
|
|
*(DFLOAT *)szTemp);
|
|
}
|
|
// Format the number string.
|
|
FormatNumber(pszField[uFldNum]);
|
|
}
|
|
break;
|
|
case fldBCD:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE) szTemp, &bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
if ((! bIsBlank) && (szTemp[0]!='\0'))
|
|
{
|
|
rslt = DbiBcdToFloat((FMTBcd *)szTemp,
|
|
&lfFloat);
|
|
ChkRslt(rslt, " BcdToFloat");
|
|
|
|
sprintf(pszField[uFldNum], "%.*lf",
|
|
pFldDescs[uFldNum].iUnits2, lfFloat);
|
|
FormatNumber(pszField[uFldNum]);
|
|
}
|
|
break;
|
|
case fldDATE:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE) szTemp, &bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
if (! bIsBlank)
|
|
{
|
|
// Format the date.
|
|
FormatDate(*(DBIDATE *)szTemp,
|
|
pszField[uFldNum]);
|
|
}
|
|
break;
|
|
case fldTIME:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE)&szTemp, &bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
if (! bIsBlank)
|
|
{
|
|
FormatTime(*(TIME *)szTemp, pszField[uFldNum]);
|
|
}
|
|
break;
|
|
case fldTIMESTAMP:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE) szTemp, &bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
if (! bIsBlank)
|
|
{
|
|
FormatTimeStamp(*(TIMESTAMP *)szTemp,
|
|
pszField[uFldNum]);
|
|
}
|
|
break;
|
|
case fldINT16:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE) szTemp, &bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
if (! bIsBlank)
|
|
{
|
|
sprintf(pszField[uFldNum], "%d", *(DFLOAT *)szTemp);
|
|
}
|
|
break;
|
|
case fldUINT16:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE) szTemp, &bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
if (! bIsBlank)
|
|
{
|
|
sprintf(pszField[uFldNum], "%u", *(DFLOAT *)szTemp);
|
|
}
|
|
break;
|
|
case fldINT32:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE) szTemp, &bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
if (! bIsBlank)
|
|
{
|
|
sprintf(pszField[uFldNum], "%ld",
|
|
*(INT32 *)szTemp);
|
|
}
|
|
break;
|
|
case fldUINT32:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE) szTemp, &bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
if (! bIsBlank)
|
|
{
|
|
sprintf(pszField[uFldNum], "%lu",
|
|
*(UINT32 *)szTemp);
|
|
}
|
|
break;
|
|
case fldBOOL:
|
|
rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
|
|
(pBYTE) szTemp, &bIsBlank);
|
|
ChkRslt(rslt, "GetField");
|
|
if (! bIsBlank)
|
|
{
|
|
if (*(BOOL*)szTemp == 0)
|
|
{
|
|
strcpy(pszField[uFldNum], "No");
|
|
}
|
|
else
|
|
{
|
|
strcpy(pszField[uFldNum], "Yes");
|
|
}
|
|
}
|
|
break;
|
|
case fldBLOB:
|
|
// Display the first uDefLength characters of
|
|
// Memo BLOB fields.
|
|
if (pFldDescs[uFldNum].iSubType == fldstMEMO)
|
|
{
|
|
rslt = DbiOpenBlob(hCur, pRecBuf, (uFldNum + 1),
|
|
dbiREADONLY);
|
|
ChkRslt(rslt, "OpenBlob");
|
|
|
|
//Determine the size of the BLOB
|
|
rslt = DbiGetBlobSize(hCur, pRecBuf, (uFldNum + 1),
|
|
&ulBlobSize);
|
|
ChkRslt(rslt, "GetBlobSize");
|
|
|
|
// Determine the maximum amount to read
|
|
ulBlobSize = min((UINT32) ulBlobSize,
|
|
(UINT32) (uDefLength - 2));
|
|
|
|
// Get the BLOB from the table
|
|
rslt = DbiGetBlob(hCur, pRecBuf, (uFldNum + 1), 0,
|
|
ulBlobSize, (pBYTE) pszField[uFldNum],
|
|
&ulBlobSize);
|
|
ChkRslt(rslt, "GetBlob");
|
|
|
|
// Add the NULL terminator to the string.
|
|
pszField[uFldNum][(UINT16)ulBlobSize] = 0;
|
|
|
|
// Free the blob from memory.
|
|
rslt = DbiFreeBlob(hCur, pRecBuf, (uFldNum + 1));
|
|
ChkRslt(rslt, "FreeBlob");
|
|
}
|
|
else
|
|
{
|
|
strcpy(pszField[uFldNum], "Can't Display");
|
|
}
|
|
break;
|
|
default:
|
|
strcpy(pszField[uFldNum], "Can't Display");
|
|
break;
|
|
}
|
|
|
|
// Initialize the string in case the field was blank.
|
|
if (bIsBlank)
|
|
{
|
|
strcpy(pszField[uFldNum], "");
|
|
bIsBlank = FALSE;
|
|
}
|
|
}
|
|
return DBIERR_NONE;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// SetupFields(TblProps, pFldDescs, pszField, uDefLength)
|
|
//
|
|
// Input: TblProps - Properties of the Table
|
|
// pFldDescs - Field Descriptor
|
|
// pszField - Fields in the table
|
|
// uDefLength - Default length of a field
|
|
//
|
|
// Return: DBIERR_NONE (success)
|
|
//
|
|
// Description:
|
|
// This function sets up the formatting of the fields.
|
|
//=====================================================================
|
|
DBIResult
|
|
SetupFields (CURProps TblProps, pFLDDesc pFldDescs, CHAR** pszField,
|
|
UINT16 uDefLength)
|
|
{
|
|
UINT16 uFldNum; // Loop variable
|
|
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
// Allocate enough space to contain the data in each field.
|
|
switch (pFldDescs[uFldNum].iFldType)
|
|
{
|
|
case fldBYTES:
|
|
case fldZSTRING:
|
|
pszField[uFldNum] = (CHAR*)malloc((pFldDescs[uFldNum].iLen
|
|
* sizeof(CHAR)));
|
|
if (MAXLEN - 4 < pFldDescs[uFldNum].iLen)
|
|
{
|
|
pFldDescs[uFldNum].iUnits1 = MAXLEN-4;
|
|
pFldDescs[uFldNum].iLen = MAXLEN-3;
|
|
}
|
|
// Adjust if the field is smaller than it's description.
|
|
if (pFldDescs[uFldNum].iLen <
|
|
strlen(pFldDescs[uFldNum].szName))
|
|
{
|
|
pFldDescs[uFldNum].iUnits1 =
|
|
strlen(pFldDescs[uFldNum].szName);
|
|
pFldDescs[uFldNum].iLen =
|
|
pFldDescs[uFldNum].iUnits1 - 1;
|
|
}
|
|
break;
|
|
case fldFLOAT:
|
|
case fldDATE:
|
|
case fldINT16:
|
|
case fldUINT16:
|
|
case fldINT32:
|
|
case fldUINT32:
|
|
case fldBOOL:
|
|
case fldBLOB:
|
|
case fldBCD:
|
|
pszField[uFldNum] = (CHAR*)malloc((uDefLength *
|
|
sizeof(CHAR)));
|
|
// Set the width of the field as it will be displayed
|
|
pFldDescs[uFldNum].iUnits1 = uDefLength-1;
|
|
pFldDescs[uFldNum].iLen = uDefLength;
|
|
// Adjust if the field is smaller than it's description
|
|
if (pFldDescs[uFldNum].iLen <
|
|
strlen(pFldDescs[uFldNum].szName))
|
|
{
|
|
pFldDescs[uFldNum].iUnits1 =
|
|
strlen(pFldDescs[uFldNum].szName);
|
|
pFldDescs[uFldNum].iLen =
|
|
pFldDescs[uFldNum].iUnits1 - 1;
|
|
}
|
|
break;
|
|
case fldTIMESTAMP:
|
|
pszField[uFldNum] = (CHAR*)malloc((36 *
|
|
sizeof(CHAR)));
|
|
// Set the width of the field as it will be displayed.
|
|
pFldDescs[uFldNum].iUnits1 = 36;
|
|
pFldDescs[uFldNum].iLen = 35;
|
|
// Adjust if the field is smaller than it's description.
|
|
if (pFldDescs[uFldNum].iLen <
|
|
strlen(pFldDescs[uFldNum].szName))
|
|
{
|
|
pFldDescs[uFldNum].iUnits1 =
|
|
strlen(pFldDescs[uFldNum].szName);
|
|
pFldDescs[uFldNum].iLen =
|
|
pFldDescs[uFldNum].iUnits1 - 1;
|
|
}
|
|
break;
|
|
case fldTIME:
|
|
pszField[uFldNum] = (CHAR*)malloc((20 *
|
|
sizeof(CHAR)));
|
|
// Set the width of the field as it will be displayed.
|
|
pFldDescs[uFldNum].iUnits1 = 20;
|
|
pFldDescs[uFldNum].iLen = 19;
|
|
// Adjust if the field is smaller than it's description.
|
|
if (pFldDescs[uFldNum].iLen <
|
|
strlen(pFldDescs[uFldNum].szName))
|
|
{
|
|
pFldDescs[uFldNum].iUnits1 =
|
|
strlen(pFldDescs[uFldNum].szName);
|
|
pFldDescs[uFldNum].iLen =
|
|
pFldDescs[uFldNum].iUnits1 - 1;
|
|
}
|
|
break;
|
|
default:
|
|
// This field size will hold the 'Not Supported'
|
|
// message.
|
|
pszField[uFldNum] = (CHAR*)malloc((uDefLength *
|
|
sizeof(CHAR)));
|
|
// Set the width of the field as it will be displayed.
|
|
pFldDescs[uFldNum].iUnits1 = uDefLength;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return DBIERR_NONE;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// PutFieldSample(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 for 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
|
|
PutFieldSample (hDBICur hCur, pBYTE pRecBuf, UINT16 FldNum,
|
|
pFLDDesc pfldDesc)
|
|
{
|
|
pBYTE pBuf; // Buffer which contains the record data
|
|
DBIResult rslt; // Return value from Paradox functions
|
|
INT16 i; // Loop counter
|
|
INT16 BlobSize; // Size of the BLOB
|
|
|
|
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
|
|
|
|
// Allocate a generic buffer (used for string and blob fields)
|
|
pBuf = (pBYTE) malloc(4096);
|
|
|
|
// This switch contains sample code that demonstrates how to
|
|
// insert a field of any type into a record buffer. Random data
|
|
// is used by this example.
|
|
switch (pfldDesc->iFldType)
|
|
{
|
|
case fldBYTES:
|
|
case fldZSTRING:
|
|
sprintf((pCHAR)pBuf, "Field #%d", FldNum);
|
|
|
|
// 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 size from 10-4010 bytes.
|
|
BlobSize = (rand() % 4000) + 11;
|
|
|
|
strcpy((pCHAR)pBuf, "BLOB example ");
|
|
// Write data to the BLOB field
|
|
for (i = 0; i < (BlobSize / 11); i++)
|
|
{
|
|
strcat((pCHAR)pBuf, "BLOB test ");
|
|
}
|
|
|
|
// 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.
|
|
rslt = DbiOpenBlob(hCur, pRecBuf, FldNum, dbiREADWRITE);
|
|
ChkRslt(rslt, "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 we don't 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:
|
|
// FormatDate (DBIDATE Date, pCHAR szDate)
|
|
//
|
|
// Input: DBIDATE - Date which needs to be formatted
|
|
// szDate - String to contain the formatted date
|
|
//
|
|
// Return: Result returned from DbiDateDecode()
|
|
//
|
|
// Description:
|
|
// This function is used to format date fields according to the
|
|
// settings in the IDAPI.CFG file.
|
|
//=====================================================================
|
|
DBIResult
|
|
FormatDate (DBIDATE Date, pCHAR szDate)
|
|
{
|
|
DBIResult rslt; // Return Value from IDAPI
|
|
FMTDate fmtDate; // Date Format
|
|
UINT16 uDay; // Day portion of date
|
|
UINT16 uMonth; // Month portion of date
|
|
INT16 iYear; // Year portion of date
|
|
|
|
// Get the formatting of the Date.
|
|
rslt = DbiGetDateFormat(&fmtDate);
|
|
ChkRslt(rslt, " GetDateFormat");
|
|
|
|
// Decode the date.
|
|
rslt = DbiDateDecode(Date, &uMonth, &uDay, &iYear);
|
|
ChkRslt(rslt, "DateDecode");
|
|
|
|
// Determine if date should be displayed year-biased.
|
|
if ((! fmtDate.bFourDigitYear) && fmtDate.bYearBiased)
|
|
{
|
|
iYear = iYear + 1900;
|
|
}
|
|
|
|
if (! fmtDate.bFourDigitYear)
|
|
{
|
|
iYear = iYear - 1900;
|
|
}
|
|
|
|
// Make certain the separator is not the
|
|
// escape character.
|
|
if (! strcmp(fmtDate.szDateSeparator, "\\"))
|
|
{
|
|
strcpy(fmtDate.szDateSeparator, "/");
|
|
}
|
|
|
|
// Format the date.
|
|
switch(fmtDate.iDateMode)
|
|
{
|
|
// MM/DD/YY - Month, Day, Year.
|
|
case 0:
|
|
sprintf(szDate,
|
|
"%0*d%s%0*d%s%0*d",
|
|
1 + fmtDate.bMonthLeadingZero,
|
|
uMonth,
|
|
fmtDate.szDateSeparator,
|
|
1 + fmtDate.bDayLeadingZero,
|
|
uDay,
|
|
fmtDate.szDateSeparator,
|
|
2,
|
|
iYear);
|
|
break;
|
|
// DD/MM/YY - Day, Month, Year.
|
|
case 1:
|
|
sprintf(szDate,
|
|
"%0*d%s%0*d%s%0*d",
|
|
1 + fmtDate.bDayLeadingZero,
|
|
uDay,
|
|
fmtDate.szDateSeparator,
|
|
1 + fmtDate.bMonthLeadingZero,
|
|
uMonth,
|
|
fmtDate.szDateSeparator,
|
|
2,
|
|
iYear);
|
|
break;
|
|
// YY/MM/DD - Year, Month, Day.
|
|
case 2:
|
|
sprintf(szDate,
|
|
"%0*d%s%0*d%s%0*d",
|
|
2,
|
|
iYear,
|
|
fmtDate.szDateSeparator,
|
|
1 + fmtDate.bMonthLeadingZero,
|
|
uMonth,
|
|
fmtDate.szDateSeparator,
|
|
1 + fmtDate.bDayLeadingZero,
|
|
uDay);
|
|
break;
|
|
}
|
|
return rslt;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// FormatTime(Time, szTime)
|
|
//
|
|
// Input: TIME - Time which needs to be formatted
|
|
// szTime - String to contain the formatted time
|
|
//
|
|
// Return: Result returned from DbiTimeDecode()
|
|
//
|
|
// Description:
|
|
// This function is used to format time fields according to
|
|
// the settings in the IDAPI.CFG file.
|
|
//=====================================================================
|
|
DBIResult
|
|
FormatTime (TIME Time, pCHAR szTime)
|
|
{
|
|
DBIResult rslt; // Return value from IDAPI functions
|
|
FMTTime fmtTime; // Time format
|
|
UINT16 uHour; // Hour portion of the time
|
|
UINT16 uMinute; // Minute portion of the time
|
|
UINT16 uMilSec; // Second portion (in ms) of the time
|
|
UINT16 uIsAm; // Is Time AM?
|
|
CHAR szTemp[10]; // Temp buffer, used for AM, PM string
|
|
|
|
// Get the formatting of the time.
|
|
rslt = DbiGetTimeFormat(&fmtTime);
|
|
ChkRslt(rslt, "GetTimeFormat");
|
|
|
|
// Decode the time.
|
|
rslt = DbiTimeDecode(Time, &uHour, &uMinute, &uMilSec);
|
|
ChkRslt(rslt, "TimeDecode");
|
|
|
|
// Make certain the separator is not the
|
|
// escape character.
|
|
if (fmtTime.cTimeSeparator == '\\')
|
|
{
|
|
fmtTime.cTimeSeparator = '/';
|
|
}
|
|
|
|
// Check if time should be displayed in 12 or 24 hour format.
|
|
if (fmtTime.bTwelveHour)
|
|
{
|
|
// Temporary variable used to determine if the time is AM or PM.
|
|
uIsAm = uHour;
|
|
uHour = uHour % 12;
|
|
if (uHour == 0)
|
|
{
|
|
uHour = 12;
|
|
}
|
|
// If AM, set uIsAm to TRUE, else set uIsAm to 0.
|
|
if (uIsAm == uHour)
|
|
{
|
|
uIsAm = 1;
|
|
}
|
|
else
|
|
{
|
|
uIsAm = 0;
|
|
}
|
|
}
|
|
|
|
// Format the hour and minute of the time.
|
|
wsprintf(szTime, "%2u%c%02u",
|
|
uHour,
|
|
fmtTime.cTimeSeparator,
|
|
uMinute);
|
|
|
|
// Determine if seconds are to be displayed.
|
|
if (fmtTime.bSeconds)
|
|
{
|
|
wsprintf(szTemp, "%c%02u",
|
|
fmtTime.cTimeSeparator,
|
|
(uMilSec / 1000));
|
|
|
|
strcat(szTime, szTemp);
|
|
|
|
// Determine if milliseconds are to be displayed.
|
|
if (fmtTime.bMilSeconds)
|
|
{
|
|
wsprintf(szTemp, "%c%03u",
|
|
fmtTime.cTimeSeparator,
|
|
(uMilSec % 1000));
|
|
strcat(szTime, szTemp);
|
|
}
|
|
}
|
|
|
|
// Add a string to the time if the time is 12-hour.
|
|
if (fmtTime.bTwelveHour)
|
|
{
|
|
// Add a space to the format.
|
|
strcat(szTime, " ");
|
|
// If AM.
|
|
if (uIsAm)
|
|
{
|
|
// Copy the AM string.
|
|
strcat(szTime, fmtTime.szAmString);
|
|
}
|
|
else // otherwise it's PM.
|
|
{
|
|
// Copy the PM string.
|
|
strcat(szTime, fmtTime.szPmString);
|
|
}
|
|
}
|
|
|
|
return rslt;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// FormatTimeStamp(TimeStamp, szTime)
|
|
//
|
|
// Input: TIME - Time which needs to be formatted
|
|
// szTime - String to contain the formatted time
|
|
//
|
|
// Return: Result returned from DbiTimeStampDecode()
|
|
//
|
|
// Description:
|
|
// This function is used to format TimeStamp fields according
|
|
// to the settings in the IDAPI.CFG file. It calls the
|
|
// FormatDate and FormatTime functions which are defined
|
|
// above.
|
|
//=====================================================================
|
|
DBIResult
|
|
FormatTimeStamp (TIMESTAMP TimeStamp, pCHAR szTimeStamp)
|
|
{
|
|
DBIResult rslt; // Return value from IDAPI functions
|
|
TIME Time; // Time portion of the TimeStamp
|
|
DBIDATE Date; // Date portion of the TimeStamp
|
|
CHAR szDate[15]; // Date string
|
|
CHAR szTime[20]; // Time String
|
|
|
|
// Get the date and time components.
|
|
rslt = DbiTimeStampDecode(TimeStamp, &Date, &Time);
|
|
ChkRslt(rslt, "TimeStampDecode");
|
|
|
|
// Get the Date format.
|
|
FormatDate(Date, szDate);
|
|
|
|
// Get the Time format.
|
|
FormatTime(Time, szTime);
|
|
|
|
// Format the TimeStamp.
|
|
wsprintf(szTimeStamp, "%s, %s", szTime, szDate);
|
|
|
|
return rslt;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// FormatNumber(szNumber)
|
|
//
|
|
// Input: szNumber - String that contains number in US format
|
|
//
|
|
// Return: Result returned from DbiGetNumberFormat()
|
|
//
|
|
// Description:
|
|
// This function is used to format number fields according to
|
|
// the settings in the IDAPI.CFG file.
|
|
//=====================================================================
|
|
DBIResult
|
|
FormatNumber (pCHAR szNumber)
|
|
{
|
|
DBIResult rslt = DBIERR_NONE; // Return value from IDAPI functions
|
|
FMTNumber fmtNumber; // Number Format
|
|
pCHAR ptr;
|
|
int period = '.'; //Default US decimal separetor
|
|
|
|
// Get the formatting of the Number
|
|
rslt = DbiGetNumberFormat(&fmtNumber);
|
|
ChkRslt(rslt, " GetNumberFormat.");
|
|
|
|
ptr = strchr(szNumber, period);
|
|
if (ptr)
|
|
{
|
|
*ptr = fmtNumber.cDecimalSeparator;
|
|
}
|
|
|
|
return rslt;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// MakeFullPath (pszDirectory, pszRelativeDirectory)
|
|
//
|
|
// Input: pszDirectory - String to contain the path to the
|
|
// tables directory
|
|
// pszRelativeDirectory - String which contains the relative
|
|
// offset from the current directory
|
|
//
|
|
// Return: int - If the directory exists
|
|
//
|
|
// Description:
|
|
// This function is used to get the fully qualified path to
|
|
// the directory which will contain the tables. This function
|
|
// will only work when pszRelativeDirectory contains either "."
|
|
// an absolute path, or <..\\..\\>TABLES.
|
|
//=====================================================================
|
|
int
|
|
MakeFullPath (pCHAR pszDirectory, pCHAR pszRelativeDirectory)
|
|
{
|
|
int iExists; // Does the directory exist?
|
|
int iLen; // Length of the path
|
|
int iLoop; // Loop counter
|
|
int iDepth = 0; // How relative the directory is
|
|
|
|
// Assume absolute path if second character is a ':'.
|
|
if (pszRelativeDirectory[1] == ':')
|
|
{
|
|
strcpy(pszDirectory, pszRelativeDirectory);
|
|
}
|
|
else if (!strcmp(pszRelativeDirectory, "."))
|
|
{
|
|
// Get the current working directory.
|
|
getcwd(pszDirectory, DBIMAXPATHLEN);
|
|
}
|
|
else
|
|
{
|
|
// Get the current working directory.
|
|
getcwd(pszDirectory, DBIMAXPATHLEN);
|
|
|
|
iLen = strlen(pszDirectory);
|
|
|
|
// Remove relative parts of the path.
|
|
iDepth = 0;
|
|
while (!strncmp(&pszRelativeDirectory[iDepth * 3], "..\\", 3))
|
|
{
|
|
for (iLoop = iLen; iLoop > -1; iLoop = iLoop - 1)
|
|
{
|
|
if (pszDirectory[iLoop] == '\\')
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
iLen = iLoop - 1;
|
|
iDepth++;
|
|
}
|
|
|
|
// Copy the 'TABLES' directory to form the full path to the tables.
|
|
// Need to move szDirectory past the '\\' and szTblDirectory
|
|
// past the '..\\'.
|
|
strcpy(&pszDirectory[iLoop+1], &pszRelativeDirectory[(3 * iDepth)]);
|
|
}
|
|
|
|
// Check if the directory exists.
|
|
iExists = access(pszDirectory, 00);
|
|
|
|
return iExists;
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// DisplayNextRecord(hCur)
|
|
//
|
|
// Input: Handle to the cursor
|
|
//
|
|
// Return: DBIERR_SUCCESS
|
|
//
|
|
// Description:
|
|
// This function will call DisplayInMemoryTable() with a value
|
|
// of 1 for the second parameter. This causes it to display the
|
|
// next record.
|
|
//=====================================================================
|
|
DBIResult
|
|
DisplayNextRecord(hDBICur hCur)
|
|
{
|
|
return(DisplayInMemoryTable(hCur, 1));
|
|
}
|
|
|
|
//=====================================================================
|
|
// Function:
|
|
// DisplayCurrentRecord(hCur);
|
|
//
|
|
// Input: hCur - Cursor handle - which table to access
|
|
//
|
|
// Return: Result of displaying the records in the table
|
|
//
|
|
// Description:
|
|
// This function will display the current record only.
|
|
//
|
|
// Note: This function will only display the columns
|
|
// correctly when using a fixed pitch font.
|
|
//=====================================================================
|
|
DBIResult
|
|
DisplayCurrentRecord (hDBICur hCur)
|
|
{
|
|
DBIResult rslt; // IDAPI function return value
|
|
CURProps TblProps; // Table Properties
|
|
pFLDDesc pFldDescs; // List of fields
|
|
pBYTE pRecBuf; // Record Buffer
|
|
CHAR** pszField; // Array to contain the fields of the
|
|
// table.
|
|
CHAR* szFormat; // Contains an entire record (row)
|
|
CHAR szTemp[MAXLEN] =""; // Temporary variable for reading data
|
|
UINT16 uFldNum; // Loop variable
|
|
const UINT16 uDefLength = 15; // Default size of a field
|
|
|
|
|
|
szFormat = (pCHAR) malloc(1600 * sizeof(BYTE));
|
|
if (szFormat == NULL)
|
|
{
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
rslt = DbiGetCursorProps(hCur, &TblProps);
|
|
if (ChkRslt(rslt, "GetCursorProps") != DBIERR_NONE)
|
|
{
|
|
free(szFormat);
|
|
return rslt;
|
|
}
|
|
|
|
// Allocate space for the record buffer.
|
|
pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize * sizeof(BYTE));
|
|
if (pRecBuf == NULL)
|
|
{
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
// 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 == NULL)
|
|
{
|
|
free(szFormat);
|
|
free(pRecBuf);
|
|
return DBIERR_NOMEMORY;
|
|
}
|
|
|
|
// 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).
|
|
pszField = (CHAR**)malloc(TblProps.iFields * sizeof(CHAR*));
|
|
|
|
// Set up formatting for the fields.
|
|
SetupFields(TblProps, pFldDescs, pszField, uDefLength);
|
|
|
|
// Display 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);
|
|
}
|
|
|
|
// Display the header.
|
|
Screen(szFormat);
|
|
|
|
rslt = DbiGetRecord(hCur, dbiNOLOCK, pRecBuf, NULL);
|
|
ChkRslt(rslt, "GetRecord");
|
|
|
|
// Fill the record buffer with the field values.
|
|
GetFields(hCur, pFldDescs, pRecBuf, pszField, uDefLength);
|
|
|
|
// Initialize szFormat to all zeroes.
|
|
memset(szFormat, 0, sizeof(szFormat));
|
|
|
|
// 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,
|
|
pszField[uFldNum]);
|
|
strcat(szFormat, szTemp);
|
|
}
|
|
|
|
// Display the record.
|
|
Screen(szFormat);
|
|
|
|
// Expect the End-Of-File error - just means that there
|
|
// are no more records in the table.
|
|
if (rslt == DBIERR_EOF)
|
|
{
|
|
rslt = DBIERR_NONE;
|
|
}
|
|
|
|
// Clean up.
|
|
for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
|
|
{
|
|
free(pszField[uFldNum]);
|
|
}
|
|
|
|
free(pszField);
|
|
free(pFldDescs);
|
|
free(pRecBuf);
|
|
free(szFormat);
|
|
|
|
return rslt;
|
|
}
|
|
|
|
|