// 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; iszTblName, 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; }