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