home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bde / snipit.pak / SNIPTOOL.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-24  |  64.3 KB  |  1,865 lines

  1. // BDE - (C) Copyright 1995 by Borland International
  2.  
  3. // sniptool.c
  4. #include "snipit.h"
  5.  
  6. #define MAXLEN 50
  7.  
  8. //===============================================================
  9. //  Function:
  10. //          Screen(Format, ...);
  11. //
  12. //  Input:  Format  - A string that represents the format that
  13. //                    the function vsprintf() uses
  14. //          ...     - A varied number of input parameters (based
  15. //                    on the needs of the format string)
  16. //
  17. //  Return: None
  18. //
  19. //  Description:
  20. //          This will build, and echo, a message. 
  21. //===============================================================
  22. void
  23. Screen (pCHAR Format, ...)
  24. {
  25.     va_list argptr;
  26.     CHAR    szMsg[1400];
  27.     pCHAR   pBuf;
  28.     
  29.     va_start(argptr, Format);
  30.     vsprintf(szMsg, Format, argptr);
  31.     va_end(argptr);
  32.  
  33.     if (szMsg)
  34.     {
  35.         // Dump the string and output a CR+LF
  36.         pBuf = (pCHAR) malloc(lstrlen(szMsg) + 3);
  37.         wsprintf(pBuf, "%s\r\n", szMsg);
  38.         SendMsg(IDE_VIEWER_OUTPUT, EM_REPLACESEL, 0, (LPARAM)(LPCSTR)pBuf);
  39.         free(pBuf);
  40.     }              
  41. }
  42.  
  43. //==============================================================
  44. //  Function:
  45. //          ChkRslt(rslt, pMsg);
  46. //  Input:  rslt    - Return code from IDAPI
  47. //          pMsg    - Null-terminated message
  48. //
  49. //  Return: IDAPI return code passed in
  50. //
  51. //  Description:
  52. //          This will echo an error message if the expected
  53. //          result does not equal the actual result. The output will be
  54. //          echoed to the screen.
  55. //===============================================================
  56. DBIResult
  57. ChkRslt (DBIResult rslt, pCHAR pMsg)
  58. {
  59.     DBIMSG  dbi_status;
  60.     DBIErrInfo  ErrInfo;
  61.  
  62.     // Echo only if actual result doesn't equal expected result
  63.     if (rslt != DBIERR_NONE)
  64.     {
  65.         // Get as much error information as possible
  66.         DbiGetErrorInfo(TRUE, &ErrInfo);
  67.  
  68.         // Make certain information is returned on the correct error
  69.         if (ErrInfo.iError == rslt)
  70.         {
  71.             Screen("        ERROR -  %s"
  72.                    "\r\n                 Cat:Code = [%xh:%xh]"
  73.                    "\r\n                 %s",
  74.                    pMsg, ErrCat(ErrInfo.iError), ErrCode(ErrInfo.iError),
  75.                    ErrInfo.szErrCode);
  76.  
  77.             if (strcmp(ErrInfo.szContext1, ""))
  78.             {
  79.                 Screen("                 %s",
  80.                        ErrInfo.szContext1);
  81.             }
  82.             if (strcmp(ErrInfo.szContext2, ""))
  83.             {
  84.                 Screen("                 %s",
  85.                        ErrInfo.szContext2);
  86.             }
  87.             if (strcmp(ErrInfo.szContext3, ""))
  88.             {
  89.                 Screen("                 %s",
  90.                        ErrInfo.szContext3);
  91.             }
  92.             if (strcmp(ErrInfo.szContext4, ""))
  93.             {
  94.                 Screen("                 %s",
  95.                        ErrInfo.szContext4);
  96.             }
  97.         }
  98.         else {
  99.             DbiGetErrorString(rslt, dbi_status);
  100.             Screen("        ERROR - %s  Cat:Code [%xh:%xh]\r\n"
  101.                    "                %s",
  102.                    pMsg, ErrCat(rslt), ErrCode(rslt), dbi_status);
  103.         }
  104.     }
  105.     return rslt;
  106. }
  107.  
  108. //===============================================================
  109. //  Function:
  110. //          WinMsg(Msg, TypeMsg, TypeBtn);
  111. //
  112. //  Input:  Msg     - The message to display
  113. //          TypeMsg - The type of messagebox to use (i.e. Stop,
  114. //                    Information)
  115. //          TypeBtn - The buttons to use (i.e. Yes, No, OK, ...)
  116. //
  117. //  Return: Response from the user
  118. //
  119. //  Description:
  120. //          Display a message box and return a value representing
  121. //          the button the user pressed.
  122. //================================================================
  123. INT16
  124. WinMsg (pCHAR pMsg, INT16 TypeMsg, INT16 TypeBtn)
  125. {
  126.     INT16   Style, Buttons;
  127.  
  128.     // Set the style of message box to display
  129.     switch (TypeMsg)
  130.     {
  131.         case MSG_INFO:
  132.             Style = MB_ICONINFORMATION;
  133.             break;
  134.         case MSG_QUESTION:
  135.             Style = MB_ICONQUESTION;
  136.             break;
  137.         case MSG_STOP:
  138.             Style = MB_ICONSTOP;
  139.             break;
  140.         default:
  141.         case MSG_EXCLAMATION:
  142.             Style = MB_ICONEXCLAMATION;
  143.             break;
  144.     }
  145.  
  146.     // Set the style of buttons to make available
  147.     switch (TypeBtn)
  148.     {
  149.         case BTN_OK_CANCEL:
  150.             Buttons = MB_OKCANCEL;
  151.             break;
  152.         case BTN_RETRY_CANCEL:
  153.             Buttons = MB_RETRYCANCEL;
  154.             break;
  155.         case BTN_YES_NO:
  156.             Buttons = MB_YESNO;
  157.             break;
  158.         case BTN_YES_NO_CANCEL:
  159.             Buttons = MB_YESNOCANCEL;
  160.             break;
  161.         default:
  162.         case BTN_OK:
  163.             Buttons = MB_OK;
  164.             break;
  165.     }
  166.     return MessageBox(hMainWnd, (LPSTR) pMsg, "Code Viewer Message",
  167.                       (WORD) Buttons | Style | MB_APPLMODAL);
  168. }
  169.  
  170. //===============================================================
  171. //  Function:
  172. //          InitAndConnect(phDb);
  173. //
  174. //  Input:  phDb - Pointer to the database handle
  175. //
  176. //  Return: IDAPI return code after DbiInit() and DbiOpenDatabase()
  177. //
  178. //  Description:
  179. //          Initialize IDAPI and connect to a Standard
  180. //          database (non-SQL).
  181. //================================================================
  182. DBIResult
  183. InitAndConnect (phDBIDb phDb)
  184. {
  185.     DBIResult   rslt;
  186.  
  187.     // Initialize IDAPI with a NULL environment structure
  188.     rslt = DbiInit(NULL);
  189.     if (ChkRslt(rslt, "Init") == DBIERR_NONE)
  190.     {
  191.         DbiDebugLayerOptions(DEBUGON | OUTPUTTOFILE, "SNIPIT.INF");
  192.  
  193.         // IDAPI initialized. Now open a Standard database (used to access
  194.         //   Paradox and dBASE tables), by using a NULL database type.
  195.         rslt = DbiOpenDatabase(NULL, NULL, dbiREADWRITE, dbiOPENSHARED,
  196.                                NULL, 0, NULL, NULL, phDb);
  197.         if (ChkRslt(rslt, "OpenDatabase") != DBIERR_NONE)
  198.         {
  199.             rslt = DbiExit();
  200.             ChkRslt(rslt, "Exit");
  201.         }
  202.  
  203.         rslt = DbiSetPrivateDir(szPrivDirectory);
  204.         if (ChkRslt(rslt, "SetPrivateDir") != DBIERR_NONE)
  205.         {
  206.             CloseDbAndExit(phDb);
  207.         }                   
  208.     }
  209.     return rslt;
  210. }
  211.  
  212. //===============================================================
  213. //  Function:
  214. //          InitAndConnect2(phDb);
  215. //
  216. //  Input:  phDb - Pointer to the database handle
  217. //
  218. //  Return: IDAPI return code after DbiInit() and DbiOpenDatabase()
  219. //
  220. //  Description:
  221. //          Initialize IDAPI and connect to a SQL database.
  222. //================================================================
  223. DBIResult
  224. InitAndConnect2 (phDBIDb phDb)
  225. {
  226.     DBIResult   rslt;
  227.     FARPROC     lpTempProc;
  228.  
  229.     // Initialize IDAPI with a NULL environment structure.
  230.     *phDb = NULL;
  231.     rslt = DbiInit(NULL);
  232.     if (ChkRslt(rslt, "Init") == DBIERR_NONE)
  233.     {
  234.         DbiDebugLayerOptions(DEBUGON | OUTPUTTOFILE, "SNIPIT.INF");
  235.  
  236.         // Get a handle to an IDAPI database (STANDARD database handle
  237.         //   can be returned, but this is mainly used for SQL connections).
  238.         lpTempProc =
  239.             MakeProcInstance((FARPROC) ConnectDlgProc, hInst);
  240.         DialogBox(hInst, "ConnectDlg", hMainWnd, (DLGPROC) lpTempProc);
  241.         FreeProcInstance((FARPROC) lpTempProc);
  242.  
  243.         // Return the handle (if connect worked).
  244.         if (SnipItDb)
  245.             *phDb = SnipItDb;
  246.         else
  247.         {
  248.             rslt = DbiExit();
  249.             ChkRslt(rslt, "Exit");
  250.  
  251.             // Connect failed or CANCEL was hit.
  252.             rslt = DBIERR_INVALIDHNDL;
  253.             return rslt;
  254.         }
  255.  
  256.         rslt = DbiSetPrivateDir(szPrivDirectory);
  257.         if (ChkRslt(rslt, "SetPrivateDir") != DBIERR_NONE)
  258.         {
  259.             CloseDbAndExit(phDb);
  260.         }                   
  261.     }
  262.     return rslt;
  263. }
  264.  
  265. //===============================================================
  266. //  Function:
  267. //          CloseDbAndExit(phDb);
  268. //
  269. //  Input:  phDb - Pointer to the database handle
  270. //
  271. //  Return: IDAPI return code after DbiCloseDatabase() and DbiExit()
  272. //
  273. //  Description:
  274. //          Close the supplied database and exit IDAPI.
  275. //================================================================
  276. DBIResult
  277. CloseDbAndExit (phDBIDb phDb)
  278. {
  279.     DBIResult   rslt;
  280.  
  281.     // Close the supplied database
  282.     rslt = DbiCloseDatabase(phDb);
  283.     if (ChkRslt(rslt, "CloseDatabase") == DBIERR_NONE)
  284.     {
  285.         DbiDebugLayerOptions(0, NULL);
  286.  
  287.         rslt = DbiExit();
  288.         ChkRslt(rslt, "Exit");
  289.     }
  290.     return rslt;
  291. }
  292.  
  293.  
  294. //=====================================================================
  295. //  Function:
  296. //          FillTable(hDb, szTblName, szTblType, NumRecs);
  297. //
  298. //  Input:  hDb         - The database handle
  299. //          szTblName   - Name of the table to fill
  300. //          szTblTyps   - Type of the table to fill
  301. //          NumRecs     - The number of records to insert
  302. //
  303. //  Return: DBIResult - success?
  304. //
  305. //  Description:
  306. //          This function adds the specified number of records to
  307. //          the table. The records will contain random data.
  308. //=====================================================================
  309. DBIResult
  310. FillTable (hDBIDb hDb, pCHAR szTblName, pCHAR szTblType, DFLOAT NumRecs)
  311. {
  312.     DBIResult   rslt;           // Return value from IDAPI functions
  313.     DFLOAT      fRecCount;      // Loop variable = count of records
  314.     UINT16      FldCntr;        // Field counter
  315.     pBYTE       pRecBuf = NULL; // Pointer to the record buffer
  316.     FLDDesc     fldDesc;        // Field Descriptor
  317.     CURProps    TblProps;       // Table descriptor
  318.     hDBICur     hCur;           // Handle to the table
  319.     hDBICur     hFldList;       // Handle to the field list table
  320.  
  321.     // Echo the message that the records are being inserted.
  322.     Screen("    Inserting %.0f records into the table...", NumRecs);
  323.  
  324.     // Open the table.
  325.     rslt = DbiOpenTable(hDb, szTblName, szTblType, NULL, NULL, 0,
  326.                         dbiREADWRITE, dbiOPENSHARED, xltFIELD, FALSE,
  327.                         NULL, &hCur);
  328.     if (ChkRslt(rslt, "OpenTable") != DBIERR_NONE)
  329.     {
  330.         return rslt;
  331.     }
  332.  
  333.     // Create an in-memory table that contains a list of fields. Note
  334.     //   that logical (i.e. IDAPI types), are being requested instead of
  335.     //   driver types.
  336.     rslt = DbiOpenFieldList(hDb, szTblName, szTblType, FALSE, &hFldList);
  337.     if (ChkRslt(rslt, "OpenFieldList") != DBIERR_NONE)
  338.     {
  339.         rslt = DbiCloseCursor(&hCur);
  340.         return(ChkRslt(rslt, "CloseCursor"));
  341.     }
  342.  
  343.     // Append the records if the list and table are available
  344.     if (hCur && hFldList)
  345.     {
  346.         //  Allocate a record buffer
  347.         rslt = DbiGetCursorProps(hCur, &TblProps);
  348.         ChkRslt(rslt, "GetCursorProps");
  349.  
  350.         pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize);
  351.         if (pRecBuf == NULL)
  352.         {
  353.             Screen("    Error - Out of memory");
  354.             rslt = DbiCloseCursor(&hCur);
  355.             ChkRslt(rslt, "CloseCursor");
  356.             rslt = DbiCloseCursor(&hFldList);
  357.             ChkRslt(rslt, "CloseCursor");
  358.             return DBIERR_NOMEMORY;
  359.         }
  360.  
  361.         // Loop until the specified number of records have been written
  362.         //   to the table.
  363.         for (fRecCount = 0; fRecCount < NumRecs; fRecCount++)
  364.         {
  365.             //  Make sure we're starting with a clean record buffer.
  366.             rslt = DbiInitRecord(hCur, pRecBuf);
  367.             ChkRslt(rslt, "InitRecord");
  368.  
  369.             // Start at the beginning of the field list. Setting the
  370.             //   cursor to the start of the table (i.e. BOF), does not leave
  371.             //   you on a record. You are effectively left on a crack.
  372.             //   Because of this, you will need to go to the next record in
  373.             //   the table to reach the first record of the table.
  374.             FldCntr = 1;
  375.             rslt = DbiSetToBegin(hFldList);
  376.             ChkRslt(rslt, "SetToBegin");
  377.  
  378.             // This loop will use the previously opened field list to
  379.             //   determine what type of data is inserted into the table.
  380.             while (DbiGetNextRecord(hFldList, dbiNOLOCK,
  381.                                     (pBYTE) &fldDesc, NULL)
  382.                    == DBIERR_NONE)
  383.             {
  384.                 // Put field data into the record buffer.
  385.                 PutFieldSample(hCur, pRecBuf, FldCntr, &fldDesc);
  386.                 FldCntr++;
  387.             }
  388.  
  389.             // All fields have been inserted into the record buffer. Now
  390.             //   we need to append the record to the table...
  391.             rslt = DbiAppendRecord(hCur, pRecBuf);
  392.             ChkRslt(rslt, "InsertRecord");
  393.  
  394.             // Make sure to close all blobs (opened when data was put into
  395.             //   the record buffer).
  396.             FldCntr = 1;
  397.  
  398.             rslt = DbiSetToBegin(hFldList);
  399.             ChkRslt(rslt, "SetToBegin");
  400.  
  401.             while (DbiGetNextRecord(hFldList, dbiNOLOCK,
  402.                                     (pBYTE) &fldDesc, NULL)
  403.                    == DBIERR_NONE)
  404.             {
  405.                 if (fldDesc.iFldType == fldBLOB)
  406.                 {
  407.                     rslt = DbiFreeBlob(hCur, pRecBuf, FldCntr);
  408.                     ChkRslt(rslt, "FreeBlob");
  409.                 }
  410.                 FldCntr++;
  411.             }
  412.         }
  413.  
  414.         // Free allocated record buffer.
  415.         free((pCHAR) pRecBuf);
  416.     }
  417.  
  418.     // Clean up and return.
  419.     rslt = DbiCloseCursor(&hFldList);
  420.     ChkRslt(rslt, "CloseCursor");
  421.  
  422.     rslt = DbiCloseCursor(&hCur);
  423.     ChkRslt(rslt, "CloseCursor");
  424.  
  425.     return DBIERR_NONE;
  426. }
  427.  
  428. //===============================================================
  429. //  Function:
  430. //          CreateAndFillTable(hDb, pTblDesc, NumRecs, phCur);
  431. //
  432. //  Input:  hDb         - Database handle
  433. //          pTblDesc    - Pointer to a descriptor for the table to
  434. //                        create
  435. //          phCur       - Pointer to table cursor (NULL means do not
  436. //                        open the table after creating
  437. //
  438. //  Return: IDAPI return code
  439. //
  440. //  Description:
  441. //          Create a table based on the table descriptor
  442. //          supplied. If "phCur != NULL" then the table will be opened,
  443. //          and the table cursor will be passed back through this parameter.
  444. //================================================================
  445. DBIResult
  446. CreateAndFillTable (hDBIDb hDb, pCRTblDesc pTblDesc, DFLOAT NumRecs,
  447.                     phDBICur phCur)
  448. {
  449.     DBIResult   rslt;
  450.  
  451.     Screen("  Creating table \"%s\"...", pTblDesc->szTblName);
  452.     rslt = DbiCreateTable(hDb, TRUE, pTblDesc);
  453.     if (ChkRslt(rslt, "CreateTable") == DBIERR_NONE)
  454.     {
  455.         // Call the routine that will fill the table.
  456.         rslt = FillTable(hDb, pTblDesc->szTblName, pTblDesc->szTblType,
  457.                          NumRecs);
  458.  
  459.         // Open the table if the create and fill worked.
  460.         if ((rslt == DBIERR_NONE) && phCur)
  461.         {
  462.             rslt = DbiOpenTable(hDb, pTblDesc->szTblName,
  463.                                 pTblDesc->szTblType, NULL, NULL, 0,
  464.                                 dbiREADWRITE, dbiOPENSHARED, xltFIELD,
  465.                                 FALSE, NULL, phCur);
  466.             ChkRslt(rslt, "OpenTable");
  467.         }
  468.     }
  469.     return rslt;
  470. }
  471.  
  472. //=====================================================================
  473. //  Function:
  474. //          DisplayInMemoryTable();
  475. //
  476. //  Input:  The cursor handle - which table to access
  477. //          DisplayNRecs      - How many records to display
  478. //                              (0 means all in the table)
  479. //
  480. //  Return: Result of displaying the records in the table
  481. //
  482. //  Description:
  483. //          This function will display all records in the table referenced
  484. //          by the cursor. This function is used to display
  485. //          in-memory and schema tables which do not support
  486. //          the use of ReadBlock ( which is used in DisplayTable )
  487. //
  488. //  Note:   This function will only display the columns
  489. //          correctly when using a fixed pitch font.
  490. //=====================================================================
  491. DBIResult
  492. DisplayInMemoryTable (hDBICur hCur, UINT32 uDisplayNRecs)
  493. {
  494.     DBIResult   rslt;               // IDAPI function return value
  495.     CURProps    TblProps;           // Table Properties
  496.     pFLDDesc    pFldDescs;          // List of fields
  497.     pBYTE       pRecBuf;            // Record Buffer
  498.     CHAR**      pszField;           // Array to contain the fields of the
  499.                                     // table.
  500.     CHAR*       szFormat;           // Contains an entire record (row)
  501.     CHAR        szTemp[MAXLEN] =""; // Temporary variable for reading data
  502.     UINT16      uFldNum;            // Loop variable
  503.     UINT32      uCurCountRec=0;     // Counter to keep track of how many
  504.                                     //   records have been displayed.
  505.  
  506.     const UINT16 uDefLength = 15;   // Default size of a field
  507.                                          
  508.     szFormat = (pCHAR) malloc(1600 * sizeof(BYTE));
  509.     if (szFormat == NULL)
  510.     {
  511.         return DBIERR_NOMEMORY;
  512.     }
  513.  
  514.     rslt = DbiGetCursorProps(hCur, &TblProps);
  515.     if (ChkRslt(rslt, "GetCursorProps") != DBIERR_NONE)
  516.     {
  517.         free(szFormat);
  518.         return rslt;
  519.     }
  520.  
  521.     // Allocate space for the record buffer
  522.     pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize * sizeof(BYTE));
  523.     if (pRecBuf == NULL)
  524.     {
  525.         Screen("    Error - Out of memory");
  526.         return DBIERR_NOMEMORY;
  527.     }
  528.  
  529.     // Allocate enough space to contain information (field descriptors)
  530.     //   about all the fields in the answer table.
  531.     pFldDescs = (pFLDDesc) malloc(TblProps.iFields * sizeof(FLDDesc));
  532.     if (pFldDescs == NULL)
  533.     {
  534.         free(szFormat);
  535.         free(pRecBuf);
  536.         Screen("    Error - Out of memory");
  537.         return DBIERR_NOMEMORY;
  538.     }
  539.  
  540.     // Get information about the fields.
  541.     rslt = DbiGetFieldDescs(hCur, pFldDescs);
  542.     ChkRslt(rslt, "GetFieldDescs");
  543.  
  544.     // Allocate enough buffers to contain data from the fields in the
  545.     //   answer table. Also sets the width of non-fldZSTRING fields
  546.     //   (all data will be converted to strings for display )
  547.     pszField = (CHAR**) malloc(TblProps.iFields * sizeof(CHAR*));
  548.  
  549.     // Set up formatting for the fields
  550.     SetupFields(TblProps, pFldDescs, pszField, uDefLength);
  551.  
  552.     // Display the names of the fields, aligned by column.
  553.     strcpy(szFormat,"\r\n        ");
  554.     for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  555.     {
  556.         sprintf(szTemp, "%-*s\t", pFldDescs[uFldNum].iUnits1 + 1,
  557.                  pFldDescs[uFldNum].szName);
  558.         strcat(szFormat, szTemp);
  559.     }
  560.  
  561.     // Display the header.
  562.     Screen(szFormat);
  563.  
  564.     // Get records from the table until the end of the table is reached
  565.     //   or the maximum number of records is reached.
  566.     //   Note that not all field types are supported. All supported field
  567.     //   types are displayed as strings.
  568.     if (uDisplayNRecs == 0)
  569.     {
  570.         uDisplayNRecs = (UINT16)-1; // uDisplayNRecs is unsigned, so
  571.                                     // -1 maximizes the value
  572.     }
  573.  
  574.     while ((uCurCountRec < uDisplayNRecs) &&
  575.            ((rslt = DbiGetNextRecord(hCur, dbiNOLOCK, pRecBuf, NULL))
  576.             == DBIERR_NONE))
  577.     {
  578.         // Fill the record buffer with the field values.
  579.         uCurCountRec++;
  580.         GetFields(hCur, pFldDescs, pRecBuf, pszField, uDefLength);
  581.  
  582.         // Initialize szFormat to all zeroes.
  583.         memset(szFormat, 0, sizeof(szFormat));
  584.  
  585.         // Add leading blank space to the record.
  586.         strcpy(szFormat,"        ");
  587.  
  588.         // Add each field to be displayed, making certain that the
  589.         //   columns line up.
  590.         for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  591.         {
  592.             sprintf(szTemp, " %-*s\t", pFldDescs[uFldNum].iUnits1,
  593.             pszField[uFldNum]);
  594.             strcat(szFormat, szTemp);
  595.         }
  596.  
  597.         // Display the record.
  598.         Screen(szFormat);
  599.     }
  600.  
  601.     // Expect the End-Of-File error - just means that there
  602.     //   are no more records in the table.
  603.     if (rslt == DBIERR_EOF)
  604.         rslt = DBIERR_NONE;
  605.  
  606.     // Clean up.
  607.     for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  608.     {
  609.         free(pszField[uFldNum]);
  610.     }
  611.  
  612.     free(pszField);
  613.     free(pFldDescs);
  614.     free(pRecBuf);
  615.     free(szFormat);
  616.  
  617.     return rslt;
  618. }
  619.  
  620. //=====================================================================
  621. //  Function:
  622. //          DisplayTable();
  623. //
  624. //  Input:  The cursor handle - which table to access
  625. //          DisplayNRecs      - How many records to display
  626. //                              (0 means display all records in the table)
  627. //
  628. //  Return: Result of displaying the records in the table
  629. //
  630. //  Description:
  631. //          This function will display all records in the table referenced
  632. //          by the cursor. Records are read from the table in blocks,
  633. //          making this function faster than the DisplayInMemoryTable()
  634. //          function.
  635. //
  636. //  Note:   This function will only display the columns
  637. //          correctly when using a fixed pitch font.
  638. //=====================================================================
  639. DBIResult
  640. DisplayTable (hDBICur hCur, UINT32 uDisplayNRecs)
  641. {
  642.     DBIResult   rslt;               // IDAPI function return value
  643.     CURProps    TblProps;           // Table Properties
  644.     pFLDDesc    pFldDescs;          // List of fields
  645.     pBYTE       pRecBuf;            // Record Buffer
  646.     CHAR**      pszField;           // Array to contain the fields of the
  647.                                     //   table
  648.     pCHAR       szFormat;           // Contains an entire record (row)
  649.     CHAR        szTemp[MAXLEN] =""; // Temporary variable for reading data
  650.     UINT16      uFldNum;            // Loop variable
  651.     UINT16      uMaxNumRecs = 30;   // Maximum number of records to read
  652.                                     //   from the table at a time
  653.     UINT32      uNumRecs;           // Number of records read in from the
  654.                                     //   table
  655.     UINT16      uCount;             // Loop Variable
  656.     UINT32      uCurCountRec = 0;   // Counter to keep track of how many
  657.                                     //   records have been displayed
  658.  
  659.     const UINT16 uDefLength = 15;   // Default size of a field
  660.  
  661.     // Allocate memory for the format string
  662.     szFormat = (pCHAR) malloc(2000);
  663.     if (szFormat == NULL)
  664.     {
  665.         Screen("    Error - Out of memory");
  666.         return DBIERR_NOMEMORY;
  667.     }
  668.  
  669.     // Set szFormat == "".
  670.     szFormat[0] = 0;
  671.  
  672.     // Get the size of the record buffer.
  673.     rslt = DbiGetCursorProps(hCur, &TblProps);
  674.     if (ChkRslt(rslt, "GetCursorProps") != DBIERR_NONE)
  675.     {
  676.         free(szFormat);
  677.         return rslt;
  678.     } 
  679.  
  680.     // Allocate space for the record buffer.
  681.     pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize * sizeof(BYTE) *
  682.                              uMaxNumRecs);
  683.     if (pRecBuf == NULL)
  684.     {
  685.         free(szFormat);
  686.         Screen("    Error - Out of memory");
  687.         return DBIERR_NOMEMORY;
  688.     }
  689.  
  690.     // Allocate enough space to contain information (Field Descriptors)
  691.     //   about all the fields in the answer table.
  692.     pFldDescs = (pFLDDesc) malloc(TblProps.iFields * sizeof(FLDDesc));
  693.     if (pFldDescs == NULL)
  694.     {
  695.         free(szFormat);
  696.         free(pRecBuf);
  697.         Screen("    Error - Out of memory");
  698.         return DBIERR_NOMEMORY;
  699.     }
  700.  
  701.     // Get information about the fields.
  702.     rslt = DbiGetFieldDescs(hCur, pFldDescs);
  703.     ChkRslt(rslt, "GetFieldDescs");
  704.  
  705.     // Allocate enough buffers to contain data from the fields in the
  706.     //   answer table. Also sets the width of non-fldZSTRING fields
  707.     //   (all data will be converted to strings for display )
  708.     pszField = (CHAR**) malloc(TblProps.iFields * sizeof(CHAR*));
  709.     if (pszField == NULL)
  710.     {
  711.         free(szFormat);
  712.         free(pRecBuf);
  713.         free(pFldDescs);
  714.         Screen("    Error - Out of memory");
  715.         return DBIERR_NOMEMORY;
  716.     }
  717.  
  718.     SetupFields(TblProps, pFldDescs, pszField, uDefLength);
  719.  
  720.     // Format the names of the fields, aligned by column.
  721.     strcpy(szFormat,"\r\n        ");
  722.     for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  723.     {
  724.         sprintf(szTemp, "%-*s\t", pFldDescs[uFldNum].iUnits1 + 1,
  725.                  pFldDescs[uFldNum].szName);
  726.         strcat(szFormat, szTemp);
  727.     }
  728.  
  729.     // Display the header information ( field names ).
  730.     Screen(szFormat);
  731.  
  732.     // Get records from the table until the end of the table is reached.
  733.     //   Note that not all field types are supported. All supported field
  734.     //   types are displayed as strings.
  735.     uNumRecs = uMaxNumRecs; // Set the number of records to read from the
  736.                             //   table as a block.
  737.     // if uCurCoutRec == 0, display all the records in the table.
  738.     if (uDisplayNRecs == 0)
  739.     {
  740.         uDisplayNRecs = (UINT16)-1; // uDisplayNRecs is unsigned, so
  741.                                     // -1 maximizes the value
  742.     }
  743.  
  744.     // Get the records from the table and display.
  745.     do
  746.     {
  747.         // Limit the number of records to be read from the table -
  748.         //   do not want to display more total records than is specified
  749.         //   in uDisplayNRecs.
  750.         if ((uNumRecs + uCurCountRec) > uDisplayNRecs)
  751.         {
  752.             uNumRecs = uDisplayNRecs - uCurCountRec;
  753.         }
  754.  
  755.         // Read a block of records - reading more than one record at a
  756.         //   time is more efficient than reading records one at a time from
  757.         //   the table.
  758.         rslt = DbiReadBlock(hCur, &uNumRecs, pRecBuf);
  759.         if ((rslt != DBIERR_EOF) && (rslt != DBIERR_NONE))
  760.         {
  761.             ChkRslt(rslt, "ReadBlock");
  762.             free(szFormat);
  763.             for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  764.             {
  765.                 free(pszField[uFldNum]);
  766.             }
  767.             free(pszField);
  768.             free(pFldDescs);
  769.             free(pRecBuf);
  770.             return rslt;
  771.         }
  772.  
  773.         for (uCount=0; uCount < uNumRecs; uCount++)
  774.         {
  775.             uCurCountRec++;
  776.  
  777.             // Fill the Record buffer with the field values.
  778.             GetFields(hCur, pFldDescs,
  779.                       &pRecBuf[uCount * TblProps.iRecBufSize],
  780.                       pszField, uDefLength);
  781.  
  782.             // Add leading blank space to the record.
  783.             strcpy(szFormat,"        ");
  784.  
  785.             // Add each field to be displayed, making certain that the
  786.             //   columns line up.
  787.             for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  788.             {
  789.                 sprintf(szTemp, " %-*s\t", pFldDescs[uFldNum].iUnits1,
  790.                 pszField[uFldNum]);
  791.                 strcat(szFormat, szTemp);
  792.             }
  793.  
  794.             // Display the record.
  795.             Screen(szFormat);
  796.         } // for ... uCount
  797.  
  798.         // While ReadBlock reads as many records as are supposed to be
  799.         //   batched (uMaxNumRecs) and the maximum number of records have not
  800.         //   been read from the table. If fewer than uMaxNumRecs records were
  801.         //   read, we reached the end of the table.
  802.     } while ((uNumRecs == uMaxNumRecs) && (uCurCountRec < uDisplayNRecs));
  803.  
  804.     // Expect the End-Of-File error - just means that there
  805.     //   are no more records in the table.
  806.     if (rslt == DBIERR_EOF)
  807.     {
  808.         rslt = DBIERR_NONE;
  809.     }
  810.  
  811.     // Clean up.
  812.     for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  813.     {
  814.         free(pszField[uFldNum]);
  815.     }
  816.     free(szFormat);
  817.     free(pszField);
  818.     free(pFldDescs);
  819.     free(pRecBuf);
  820.  
  821.     return DBIERR_NONE;
  822. }
  823.  
  824. //=====================================================================
  825. //  Function:
  826. //          GetFields(hCur, pFldDescs, pRecBuf, pszField, uDefLength)
  827. //
  828. //  Input:  hCur        - Handle to the Cursor
  829. //          pFldDescs   - Field Descriptor
  830. //          pRecBuf     - Record buffer - contains the record from
  831. //                        which the field values are to be retrieved.
  832. //          pszField    - Fields in the table
  833. //          uDefLength  - Default length of a field
  834. //
  835. //  Return: Success of the operation
  836. //
  837. //  Description:
  838. //          This function is used to extract all field values from
  839. //          a record and place them into an array of strings.
  840. //=====================================================================
  841. DBIResult
  842. GetFields (hDBICur hCur, pFLDDesc pFldDescs, pBYTE pRecBuf,
  843.            CHAR ** pszField, UINT16 uDefLength)
  844. {
  845.     DBIResult   rslt;           // Return value from IDAPI functions
  846.     CURProps    TblProps;       // Properties of the table
  847.     UINT16      uFldNum;        // Loop Counter - used to determine the
  848.                                 //   current field
  849.     CHAR        szTemp[MAXLEN] =""; // Temporary variable for reading data
  850.     UINT32      ulBlobSize;     // Size of the BLOB
  851.     DFLOAT      lfFloat;        // Float value
  852.     BOOL        bIsBlank;       // Check if the field is blank
  853.  
  854.     rslt = DbiGetCursorProps(hCur, &TblProps);
  855.     if (ChkRslt(rslt, "GetCursorProps") != DBIERR_NONE)
  856.     {
  857.         return rslt;
  858.     }
  859.  
  860.     // Get the field values from the record. Gets each field from
  861.     //   the table, placing the results in the pszField variable.
  862.     for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  863.     {
  864.         switch (pFldDescs[uFldNum].iFldType)
  865.         {
  866.             case fldBYTES:
  867.             case fldZSTRING:
  868.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  869.                                    (pBYTE) pszField[uFldNum],
  870.                                    &bIsBlank);
  871.                 ChkRslt(rslt, "GetField");
  872.                 break;
  873.             case fldFLOAT:
  874.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  875.                                    (pBYTE) szTemp, &bIsBlank);
  876.                 ChkRslt(rslt, "GetField");
  877.                 if (! bIsBlank)
  878.                 {
  879.                     if (pFldDescs[uFldNum].iSubType == fldstMONEY)
  880.                     {
  881.                         sprintf(pszField[uFldNum], "$%.2lf",
  882.                                 *(DFLOAT *)szTemp);
  883.                     }
  884.                     else
  885.                     {
  886.                         sprintf(pszField[uFldNum], "%.1lf",
  887.                                 *(DFLOAT *)szTemp);
  888.                     }
  889.                     // Format the number string.
  890.                     FormatNumber(pszField[uFldNum]);
  891.                 }
  892.                 break;
  893.             case fldBCD:
  894.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  895.                                    (pBYTE) szTemp, &bIsBlank);
  896.                 ChkRslt(rslt, "GetField");
  897.                 if ((! bIsBlank) && (szTemp[0]!='\0'))
  898.                 {
  899.                     rslt = DbiBcdToFloat((FMTBcd *)szTemp,
  900.                             &lfFloat);
  901.                     ChkRslt(rslt, "    BcdToFloat");
  902.  
  903.                     sprintf(pszField[uFldNum], "%.*lf",
  904.                             pFldDescs[uFldNum].iUnits2, lfFloat);
  905.                     FormatNumber(pszField[uFldNum]);
  906.                 }
  907.                 break;
  908.             case fldDATE:
  909.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  910.                                    (pBYTE) szTemp, &bIsBlank);
  911.                 ChkRslt(rslt, "GetField");
  912.                 if (! bIsBlank)
  913.                 {
  914.                     // Format the date. 
  915.                     FormatDate(*(DBIDATE *)szTemp,
  916.                                pszField[uFldNum]);
  917.                 }
  918.                 break;
  919.             case fldTIME:
  920.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  921.                                    (pBYTE)&szTemp, &bIsBlank);
  922.                 ChkRslt(rslt, "GetField");
  923.                 if (! bIsBlank)
  924.                 {
  925.                     FormatTime(*(TIME *)szTemp, pszField[uFldNum]);
  926.                 }
  927.                 break;
  928.             case fldTIMESTAMP:
  929.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  930.                                    (pBYTE) szTemp, &bIsBlank);
  931.                 ChkRslt(rslt, "GetField");
  932.                 if (! bIsBlank)
  933.                 {
  934.                     FormatTimeStamp(*(TIMESTAMP *)szTemp,
  935.                                     pszField[uFldNum]);
  936.                 }
  937.                 break;
  938.            case fldINT16:
  939.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  940.                                    (pBYTE) szTemp, &bIsBlank);
  941.                 ChkRslt(rslt, "GetField");
  942.                 if (! bIsBlank)
  943.                 {
  944.                     sprintf(pszField[uFldNum], "%d", *(DFLOAT *)szTemp);
  945.                 }
  946.                 break;
  947.             case fldUINT16:
  948.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  949.                                    (pBYTE) szTemp, &bIsBlank);
  950.                 ChkRslt(rslt, "GetField");
  951.                 if (! bIsBlank)
  952.                 {
  953.                     sprintf(pszField[uFldNum], "%u", *(DFLOAT *)szTemp);
  954.                 }
  955.                 break;
  956.             case fldINT32:
  957.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  958.                                    (pBYTE) szTemp, &bIsBlank);
  959.                 ChkRslt(rslt, "GetField");
  960.                 if (! bIsBlank)
  961.                 {
  962.                     sprintf(pszField[uFldNum], "%ld",
  963.                             *(INT32 *)szTemp);
  964.                 }
  965.                 break;
  966.             case fldUINT32:
  967.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  968.                                    (pBYTE) szTemp, &bIsBlank);
  969.                 ChkRslt(rslt, "GetField");
  970.                 if (! bIsBlank)
  971.                 {
  972.                     sprintf(pszField[uFldNum], "%lu",
  973.                             *(UINT32 *)szTemp);
  974.                 }
  975.                 break;
  976.             case fldBOOL:
  977.                 rslt = DbiGetField(hCur, uFldNum+1, pRecBuf,
  978.                                    (pBYTE) szTemp, &bIsBlank);
  979.                 ChkRslt(rslt, "GetField");
  980.                 if (! bIsBlank)
  981.                 {
  982.                     if (*(BOOL*)szTemp == 0)
  983.                     {
  984.                         strcpy(pszField[uFldNum], "No");
  985.                     }
  986.                     else
  987.                     {
  988.                         strcpy(pszField[uFldNum], "Yes");
  989.                     }
  990.                 }
  991.                 break;
  992.             case fldBLOB:
  993.                 // Display the first uDefLength characters of
  994.                 //   Memo BLOB fields.
  995.                 if (pFldDescs[uFldNum].iSubType == fldstMEMO)
  996.                 {
  997.                     rslt = DbiOpenBlob(hCur, pRecBuf, (uFldNum + 1),
  998.                                        dbiREADONLY);
  999.                     ChkRslt(rslt, "OpenBlob");
  1000.  
  1001.                     //Determine the size of the BLOB
  1002.                     rslt = DbiGetBlobSize(hCur, pRecBuf, (uFldNum + 1),
  1003.                                           &ulBlobSize);
  1004.                     ChkRslt(rslt, "GetBlobSize");
  1005.  
  1006.                     // Determine the maximum amount to read
  1007.                     ulBlobSize = min((UINT32) ulBlobSize,
  1008.                                      (UINT32) (uDefLength - 2));
  1009.  
  1010.                     // Get the BLOB from the table
  1011.                     rslt = DbiGetBlob(hCur, pRecBuf, (uFldNum + 1), 0,
  1012.                                       ulBlobSize, (pBYTE) pszField[uFldNum],
  1013.                                       &ulBlobSize);
  1014.                     ChkRslt(rslt, "GetBlob");
  1015.  
  1016.                     // Add the NULL terminator to the string.
  1017.                     pszField[uFldNum][(UINT16)ulBlobSize] = 0;
  1018.  
  1019.                     // Free the blob from memory.
  1020.                     rslt = DbiFreeBlob(hCur, pRecBuf, (uFldNum + 1));
  1021.                     ChkRslt(rslt, "FreeBlob");
  1022.                 }
  1023.                 else
  1024.                 {
  1025.                     strcpy(pszField[uFldNum], "Can't Display");
  1026.                 }                        
  1027.                 break;
  1028.             default:
  1029.                 strcpy(pszField[uFldNum], "Can't Display");
  1030.                 break;
  1031.         }
  1032.  
  1033.         // Initialize the string in case the field was blank.
  1034.         if (bIsBlank)
  1035.         {
  1036.             strcpy(pszField[uFldNum], "");
  1037.             bIsBlank = FALSE;
  1038.         }
  1039.     }
  1040.     return DBIERR_NONE;
  1041. }
  1042.  
  1043. //=====================================================================
  1044. //  Function:
  1045. //          SetupFields(TblProps, pFldDescs, pszField, uDefLength)
  1046. //
  1047. //  Input:  TblProps    - Properties of the Table
  1048. //          pFldDescs   - Field Descriptor
  1049. //          pszField    - Fields in the table
  1050. //          uDefLength  - Default length of a field
  1051. //
  1052. //  Return: DBIERR_NONE (success)
  1053. //
  1054. //  Description:
  1055. //          This function sets up the formatting of the fields.
  1056. //=====================================================================
  1057. DBIResult
  1058. SetupFields (CURProps TblProps, pFLDDesc pFldDescs, CHAR** pszField,
  1059.              UINT16 uDefLength)
  1060. {
  1061.     UINT16      uFldNum;            // Loop variable
  1062.  
  1063.     for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  1064.     {
  1065.         // Allocate enough space to contain the data in each field.
  1066.         switch (pFldDescs[uFldNum].iFldType)
  1067.         {
  1068.             case fldBYTES:
  1069.             case fldZSTRING:
  1070.                 pszField[uFldNum] = (CHAR*)malloc((pFldDescs[uFldNum].iLen
  1071.                                                   * sizeof(CHAR)));
  1072.                 if (MAXLEN - 4 < pFldDescs[uFldNum].iLen)
  1073.                 {
  1074.                     pFldDescs[uFldNum].iUnits1 = MAXLEN-4;
  1075.                     pFldDescs[uFldNum].iLen    = MAXLEN-3;
  1076.                 }
  1077.                 // Adjust if the field is smaller than it's description.
  1078.                 if (pFldDescs[uFldNum].iLen <
  1079.                     strlen(pFldDescs[uFldNum].szName))
  1080.                 {
  1081.                     pFldDescs[uFldNum].iUnits1 =
  1082.                                         strlen(pFldDescs[uFldNum].szName);
  1083.                     pFldDescs[uFldNum].iLen    =
  1084.                                         pFldDescs[uFldNum].iUnits1 - 1;
  1085.                 }
  1086.                 break;
  1087.             case fldFLOAT:
  1088.             case fldDATE:
  1089.             case fldINT16:
  1090.             case fldUINT16:
  1091.             case fldINT32:
  1092.             case fldUINT32:
  1093.             case fldBOOL:
  1094.             case fldBLOB:
  1095.             case fldBCD:
  1096.                 pszField[uFldNum] = (CHAR*)malloc((uDefLength *
  1097.                                                   sizeof(CHAR)));
  1098.                 // Set the width of the field as it will be displayed
  1099.                 pFldDescs[uFldNum].iUnits1 = uDefLength-1;
  1100.                 pFldDescs[uFldNum].iLen    = uDefLength;
  1101.                 // Adjust if the field is smaller than it's description
  1102.                 if (pFldDescs[uFldNum].iLen <
  1103.                     strlen(pFldDescs[uFldNum].szName))
  1104.                 {
  1105.                     pFldDescs[uFldNum].iUnits1 =
  1106.                                         strlen(pFldDescs[uFldNum].szName);
  1107.                     pFldDescs[uFldNum].iLen    =
  1108.                                         pFldDescs[uFldNum].iUnits1 - 1;
  1109.                 }
  1110.                 break;
  1111.             case fldTIMESTAMP:
  1112.                 pszField[uFldNum] = (CHAR*)malloc((36 *
  1113.                                                   sizeof(CHAR)));
  1114.                 // Set the width of the field as it will be displayed.
  1115.                 pFldDescs[uFldNum].iUnits1 = 36;
  1116.                 pFldDescs[uFldNum].iLen    = 35;
  1117.                 // Adjust if the field is smaller than it's description.
  1118.                 if (pFldDescs[uFldNum].iLen <
  1119.                     strlen(pFldDescs[uFldNum].szName))
  1120.                 {
  1121.                     pFldDescs[uFldNum].iUnits1 =
  1122.                                         strlen(pFldDescs[uFldNum].szName);
  1123.                     pFldDescs[uFldNum].iLen    =
  1124.                                         pFldDescs[uFldNum].iUnits1 - 1;
  1125.                 }
  1126.                 break;
  1127.             case fldTIME:
  1128.                 pszField[uFldNum] = (CHAR*)malloc((20 *
  1129.                                                   sizeof(CHAR)));
  1130.                 // Set the width of the field as it will be displayed.
  1131.                 pFldDescs[uFldNum].iUnits1 = 20;
  1132.                 pFldDescs[uFldNum].iLen    = 19;
  1133.                 // Adjust if the field is smaller than it's description.
  1134.                 if (pFldDescs[uFldNum].iLen <
  1135.                     strlen(pFldDescs[uFldNum].szName))
  1136.                 {
  1137.                     pFldDescs[uFldNum].iUnits1 =
  1138.                                         strlen(pFldDescs[uFldNum].szName);
  1139.                     pFldDescs[uFldNum].iLen    =
  1140.                                         pFldDescs[uFldNum].iUnits1 - 1;
  1141.                 }
  1142.               break;
  1143.             default:
  1144.                 // This field size will hold the 'Not Supported'
  1145.                 //   message.
  1146.                 pszField[uFldNum] = (CHAR*)malloc((uDefLength *
  1147.                                                   sizeof(CHAR)));
  1148.                 // Set the width of the field as it will be displayed.
  1149.                 pFldDescs[uFldNum].iUnits1 = uDefLength;
  1150.                 break;
  1151.         }
  1152.     }
  1153.  
  1154.     return DBIERR_NONE;
  1155. }
  1156.  
  1157. //=====================================================================
  1158. //  Function:
  1159. //          PutFieldSample(hCur, pRecBuf, FldNum, pfldDesc);
  1160. //
  1161. //  Input:  hCur     - The handle for the table to fill
  1162. //          pRecBuf  - The record buffer to insert data into
  1163. //          FldNum   - The field we are generating
  1164. //          pfldDesc - A descriptor for the field to generate
  1165. //
  1166. //  Return: Result returned from DbiPutField()
  1167. //
  1168. //  Description:
  1169. //          This routine is used to put field data into a record
  1170. //          buffer. Note that all LOGICAL field types are covered. You
  1171. //          will need to refer to documentation, or run the DRVCAPS.C
  1172. //          example for PHYSICAL to LOGICAL field mappings.
  1173. //=====================================================================
  1174. DBIResult
  1175. PutFieldSample (hDBICur hCur, pBYTE pRecBuf, UINT16 FldNum,
  1176.                 pFLDDesc pfldDesc)
  1177. {
  1178.     pBYTE       pBuf;       // Buffer which contains the record data
  1179.     DBIResult   rslt;       // Return value from Paradox functions
  1180.     INT16       i;          // Loop counter
  1181.     INT16       BlobSize;   // Size of the BLOB
  1182.  
  1183.     BOOL        Bool;       // Used for fldBOOL
  1184.     INT16       Int16;      // Used for fldINT16
  1185.     UINT16      uInt16;     // Used for fldUINT16
  1186.     INT32       Int32;      // Used for fldINT32
  1187.     UINT32      uInt32;     // Used for fldUINT32
  1188.     DFLOAT      Float;      // Used for fldFLOAT
  1189.     FMTBcd      fmtBcd;     // Used for fldBCD
  1190.     DBIDATE     Date;       // Used for fldDATE
  1191.     TIME        Time;       // Used for fldTIME
  1192.     TIMESTAMP   tStamp;     // Used for fldTIMESTAMP
  1193.     UINT16      month;      // Used in generating the date
  1194.     UINT16      day;        // Used in generating the date
  1195.     UINT16      year;       // Used in generating the date
  1196.     UINT16      hour;       // Used in generating the time
  1197.     UINT16      min;        // Used in generating the time
  1198.     UINT16      sec;        // Used in generating the time
  1199.  
  1200.     // Allocate a generic buffer (used for string and blob fields)
  1201.     pBuf = (pBYTE) malloc(4096);
  1202.  
  1203.     // This switch contains sample code that demonstrates how to
  1204.     //   insert a field of any type into a record buffer. Random data
  1205.     //   is used by this example.
  1206.     switch (pfldDesc->iFldType)
  1207.     {
  1208.         case fldBYTES:
  1209.         case fldZSTRING:
  1210.             sprintf((pCHAR)pBuf, "Field #%d", FldNum);
  1211.  
  1212.             // Put the data into the record buffer.
  1213.             rslt = DbiPutField(hCur, FldNum, pRecBuf, pBuf);
  1214.             break;
  1215.         case fldDATE:
  1216.             // Randomly generate and encode a date.
  1217.             month = (rand() % 12) + 1;
  1218.             day = (rand() % 20) + 1;
  1219.             year = (rand() % 99) + 1900;
  1220.  
  1221.             rslt = DbiDateEncode(month, day, year, &Date);
  1222.             ChkRslt(rslt, "DateEncode");
  1223.  
  1224.             // Put the data into the record buffer.
  1225.             rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE) &Date);
  1226.             break;
  1227.         case fldBLOB:
  1228.             // Generate a blob size from 10-4010 bytes.
  1229.             BlobSize = (rand() % 4000) + 11;
  1230.  
  1231.             strcpy((pCHAR)pBuf, "BLOB example ");
  1232.             // Write data to the BLOB field
  1233.             for (i = 0; i < (BlobSize / 11); i++)
  1234.             {
  1235.                 strcat((pCHAR)pBuf, "BLOB test ");
  1236.             }
  1237.  
  1238.             // Init the blob header (contents defined by IDAPI client).
  1239.             if ((pfldDesc->iSubType == fldstFMTMEMO) ||
  1240.                  (pfldDesc->iSubType == fldstOLEOBJ) ||
  1241.                  (pfldDesc->iSubType == fldstGRAPHIC))
  1242.             {
  1243.                  memset(pBuf, 8, '\0');
  1244.             }
  1245.  
  1246.             // Open the blob prior to putting.
  1247.             rslt = DbiOpenBlob(hCur, pRecBuf, FldNum, dbiREADWRITE);
  1248.             ChkRslt(rslt, "OpenBlob");
  1249.  
  1250.             // Put the blob. Note that DbiFreeBlob() will be
  1251.             //   called after the record is inserted!
  1252.             rslt = DbiPutBlob(hCur, pRecBuf, FldNum, 0, BlobSize,
  1253.                               pBuf);
  1254.             break;
  1255.         case fldBOOL:
  1256.             // Boolean fields are either TRUE or FALSE.
  1257.             if ((rand() % 100) < 50)
  1258.             {
  1259.                 Bool = 1;
  1260.             }
  1261.             else
  1262.             {
  1263.                 Bool = 0;
  1264.             }
  1265.             // Put the data into the record buffer.
  1266.             rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&Bool);
  1267.             break;
  1268.         case fldINT16:
  1269.             Int16 = (rand() % 255);
  1270.             // Put the data into the record buffer.
  1271.             rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&Int16);
  1272.             break;
  1273.         case fldBCD:
  1274.             Float = (rand() / 1.21324);
  1275.             rslt = DbiBcdFromFloat(&Float, pfldDesc->iUnits1,
  1276.                                    pfldDesc->iUnits2, &fmtBcd);
  1277.             ChkRslt(rslt, "BcdFromFloat");
  1278.  
  1279.             // Put the data into the record buffer.
  1280.             rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&fmtBcd);
  1281.             break;
  1282.         case fldLOCKINFO:
  1283.             rslt = 0;
  1284.             break;
  1285.         case fldUINT16:
  1286.             uInt16 = (rand() % 255);
  1287.             // Put the data into the record buffer.
  1288.             rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&uInt16);
  1289.             break;
  1290.         case fldINT32:
  1291.             // Put the data into the record buffer if it is not an
  1292.             //   auto-increment field.
  1293.             if (pfldDesc->iSubType != fldstAUTOINC)
  1294.             {
  1295.                 Int32 = (rand() % 10000);
  1296.                 rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&Int32);
  1297.             }
  1298.             else
  1299.             {
  1300.                 // Don't have to put a value into an auto-increment field,
  1301.                 //   but make certain we don't return an error.
  1302.                 rslt = 0;
  1303.             }
  1304.             break;
  1305.         case fldUINT32:
  1306.             uInt32 = (rand() % 10000);
  1307.             // Put the data into the record buffer.
  1308.             rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&uInt32);
  1309.             break;
  1310.         case fldFLOAT:
  1311.             Float = (rand() % 128000L);
  1312.             // Put the data into the record buffer.
  1313.             rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&Float);
  1314.             break;
  1315.         case fldTIME:
  1316.             // Randomize and encode a time value.
  1317.             hour = (rand() % 23) + 1;
  1318.             min = (rand() % 59) + 1;
  1319.             sec = ((rand() * 2) % 59999U) + 1;
  1320.  
  1321.             rslt = DbiTimeEncode(hour, min, sec, &Time);
  1322.             ChkRslt(rslt, "TimeEncode");
  1323.  
  1324.             // Put the data into the record buffer.
  1325.             rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&Time);
  1326.             break;
  1327.         case fldTIMESTAMP:
  1328.             // Encode a date and a time.
  1329.             month = (rand() % 12) + 1;
  1330.             day = (rand() % 20) + 1;
  1331.             year = (rand() % 99) + 1900;
  1332.  
  1333.             rslt = DbiDateEncode(month, day, year, &Date);
  1334.             ChkRslt(rslt, "DateEncode");
  1335.  
  1336.             hour = (rand() % 23) + 1;
  1337.             min = (rand() % 59) + 1;
  1338.             sec = ((rand() * 2) % 59999U) + 1;
  1339.  
  1340.             rslt = DbiTimeEncode(hour, min, sec, &Time);
  1341.             ChkRslt(rslt, "TimeEncode");
  1342.  
  1343.             // Now encode and put the time stamp.
  1344.             rslt = DbiTimeStampEncode(Date, Time, &tStamp);
  1345.             ChkRslt(rslt, "TimeStampEncode");
  1346.  
  1347.             // Put the data into the record buffer.
  1348.             rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)&tStamp);
  1349.             break;
  1350.         case fldVARBYTES:
  1351.             // Init the size (1st two bytes) and contents.
  1352.             *((int *) pBuf) = (pfldDesc->iUnits1 - 2);
  1353.             for (i = 2; i < pfldDesc->iUnits1; i++)
  1354.             {
  1355.                 pBuf[i] = (rand() % 90) + 32;
  1356.             }
  1357.             pBuf[i] = '\0';
  1358.  
  1359.             // Put the data into the record buffer.
  1360.             rslt = DbiPutField(hCur, FldNum, pRecBuf, (pBYTE)pBuf);
  1361.             break;
  1362.         default:
  1363.             rslt = DBIERR_INVALIDFLDTYPE;
  1364.             break;
  1365.     }
  1366.  
  1367.     // Determine if any of the previous DbiPutField functions failed.
  1368.     ChkRslt(rslt, "PutField");
  1369.  
  1370.     // Clean up and return.
  1371.     free((pCHAR) pBuf);
  1372.     return rslt;
  1373. }
  1374.  
  1375. //=====================================================================
  1376. //  Function:
  1377. //          FormatDate (DBIDATE Date, pCHAR szDate)
  1378. //
  1379. //  Input:  DBIDATE  - Date which needs to be formatted
  1380. //          szDate   - String to contain the formatted date
  1381. //
  1382. //  Return: Result returned from DbiDateDecode()
  1383. //
  1384. //  Description:
  1385. //          This function is used to format date fields according to the
  1386. //          settings in the IDAPI.CFG file.
  1387. //=====================================================================
  1388. DBIResult
  1389. FormatDate (DBIDATE Date, pCHAR szDate)
  1390. {
  1391.     DBIResult   rslt;       // Return Value from IDAPI
  1392.     FMTDate     fmtDate;    // Date Format
  1393.     UINT16      uDay;       // Day portion of date
  1394.     UINT16      uMonth;     // Month portion of date
  1395.     INT16       iYear;      // Year portion of date
  1396.                 
  1397.     // Get the formatting of the Date.
  1398.     rslt = DbiGetDateFormat(&fmtDate);
  1399.     ChkRslt(rslt, "    GetDateFormat");
  1400.  
  1401.     // Decode the date.
  1402.     rslt = DbiDateDecode(Date, &uMonth, &uDay, &iYear);
  1403.     ChkRslt(rslt, "DateDecode");
  1404.  
  1405.     // Determine if date should be displayed year-biased.
  1406.     if ((! fmtDate.bFourDigitYear) && fmtDate.bYearBiased)
  1407.     {
  1408.         iYear = iYear + 1900;
  1409.     }
  1410.  
  1411.     if (! fmtDate.bFourDigitYear)
  1412.     {
  1413.         iYear = iYear - 1900;
  1414.     }
  1415.  
  1416.     // Make certain the separator is not the
  1417.     //   escape character.
  1418.     if (! strcmp(fmtDate.szDateSeparator, "\\"))
  1419.     {
  1420.         strcpy(fmtDate.szDateSeparator, "/");
  1421.     }
  1422.  
  1423.     // Format the date.
  1424.     switch(fmtDate.iDateMode)
  1425.     {
  1426.         // MM/DD/YY - Month, Day, Year.
  1427.         case 0:
  1428.             sprintf(szDate,
  1429.                     "%0*d%s%0*d%s%0*d",
  1430.                     1 + fmtDate.bMonthLeadingZero,
  1431.                     uMonth,
  1432.                     fmtDate.szDateSeparator,
  1433.                     1 + fmtDate.bDayLeadingZero,
  1434.                     uDay,
  1435.                     fmtDate.szDateSeparator,
  1436.                     2,
  1437.                     iYear);
  1438.             break;
  1439.         // DD/MM/YY - Day, Month, Year.
  1440.         case 1:
  1441.             sprintf(szDate,
  1442.                     "%0*d%s%0*d%s%0*d",
  1443.                     1 + fmtDate.bDayLeadingZero,
  1444.                     uDay,
  1445.                     fmtDate.szDateSeparator,
  1446.                     1 + fmtDate.bMonthLeadingZero,
  1447.                     uMonth,
  1448.                     fmtDate.szDateSeparator,
  1449.                     2,
  1450.                     iYear);
  1451.             break;
  1452.         // YY/MM/DD - Year, Month, Day.
  1453.         case 2:
  1454.             sprintf(szDate,
  1455.                     "%0*d%s%0*d%s%0*d",
  1456.                     2,
  1457.                     iYear,
  1458.                     fmtDate.szDateSeparator,
  1459.                     1 + fmtDate.bMonthLeadingZero,
  1460.                     uMonth,
  1461.                     fmtDate.szDateSeparator,
  1462.                     1 + fmtDate.bDayLeadingZero,
  1463.                     uDay);
  1464.             break;
  1465.     }
  1466.     return rslt;
  1467. }
  1468.  
  1469. //=====================================================================
  1470. //  Function:
  1471. //          FormatTime(Time, szTime)
  1472. //
  1473. //  Input:  TIME     - Time which needs to be formatted
  1474. //          szTime   - String to contain the formatted time
  1475. //
  1476. //  Return: Result returned from DbiTimeDecode()
  1477. //
  1478. //  Description:
  1479. //          This function is used to format time fields according to
  1480. //          the settings in the IDAPI.CFG file.
  1481. //=====================================================================
  1482. DBIResult
  1483. FormatTime (TIME Time, pCHAR szTime)
  1484. {
  1485.     DBIResult   rslt;       // Return value from IDAPI functions
  1486.     FMTTime     fmtTime;    // Time format
  1487.     UINT16      uHour;      // Hour portion of the time
  1488.     UINT16      uMinute;    // Minute portion of the time
  1489.     UINT16      uMilSec;    // Second portion (in ms) of the time
  1490.     UINT16      uIsAm;      // Is Time AM?
  1491.     CHAR        szTemp[10]; // Temp buffer, used for AM, PM string
  1492.  
  1493.     // Get the formatting of the time.
  1494.     rslt = DbiGetTimeFormat(&fmtTime);
  1495.     ChkRslt(rslt, "GetTimeFormat");
  1496.  
  1497.     // Decode the time. 
  1498.     rslt = DbiTimeDecode(Time, &uHour, &uMinute, &uMilSec);
  1499.     ChkRslt(rslt, "TimeDecode");
  1500.  
  1501.     // Make certain the separator is not the
  1502.     //   escape character.
  1503.     if (fmtTime.cTimeSeparator == '\\')
  1504.     {
  1505.         fmtTime.cTimeSeparator  = '/';
  1506.     }
  1507.  
  1508.     // Check if time should be displayed in 12 or 24 hour format.
  1509.     if (fmtTime.bTwelveHour)
  1510.     {
  1511.         // Temporary variable used to determine if the time is AM or PM.
  1512.         uIsAm = uHour;
  1513.         uHour = uHour % 12;
  1514.         if (uHour == 0)
  1515.         {
  1516.             uHour = 12;
  1517.         }
  1518.         // If AM, set uIsAm to TRUE, else set uIsAm to 0.
  1519.         if (uIsAm == uHour)
  1520.         {
  1521.             uIsAm = 1;
  1522.         }
  1523.         else
  1524.         {
  1525.             uIsAm = 0;
  1526.         }
  1527.     }
  1528.  
  1529.     // Format the hour and minute of the time.
  1530.     wsprintf(szTime, "%2u%c%02u",
  1531.              uHour,
  1532.              fmtTime.cTimeSeparator,
  1533.              uMinute);
  1534.  
  1535.     // Determine if seconds are to be displayed.
  1536.     if (fmtTime.bSeconds)
  1537.     {
  1538.         wsprintf(szTemp, "%c%02u",
  1539.                  fmtTime.cTimeSeparator,
  1540.                  (uMilSec / 1000));
  1541.  
  1542.         strcat(szTime, szTemp);
  1543.  
  1544.         // Determine if milliseconds are to be displayed.
  1545.         if (fmtTime.bMilSeconds)
  1546.         {
  1547.             wsprintf(szTemp, "%c%03u",
  1548.                      fmtTime.cTimeSeparator,
  1549.                      (uMilSec % 1000));
  1550.             strcat(szTime, szTemp);   
  1551.         }
  1552.     }
  1553.  
  1554.     // Add a string to the time if the time is 12-hour.
  1555.     if (fmtTime.bTwelveHour)
  1556.     {
  1557.         // Add a space to the format.
  1558.         strcat(szTime, " ");
  1559.         // If AM.
  1560.         if (uIsAm)
  1561.         {
  1562.             // Copy the AM string.
  1563.             strcat(szTime, fmtTime.szAmString);
  1564.         }
  1565.         else // otherwise it's PM.
  1566.         {
  1567.             // Copy the PM string.
  1568.             strcat(szTime, fmtTime.szPmString);
  1569.         }
  1570.     }
  1571.  
  1572.     return rslt;
  1573. }
  1574.  
  1575. //=====================================================================
  1576. //  Function:
  1577. //          FormatTimeStamp(TimeStamp, szTime)
  1578. //
  1579. //  Input:  TIME     - Time which needs to be formatted
  1580. //          szTime   - String to contain the formatted time
  1581. //
  1582. //  Return: Result returned from DbiTimeStampDecode()
  1583. //
  1584. //  Description:
  1585. //          This function is used to format TimeStamp fields according
  1586. //          to the settings in the IDAPI.CFG file. It calls the
  1587. //          FormatDate and FormatTime functions which are defined
  1588. //          above.
  1589. //=====================================================================
  1590. DBIResult
  1591. FormatTimeStamp (TIMESTAMP TimeStamp, pCHAR szTimeStamp)
  1592. {
  1593.     DBIResult   rslt;       // Return value from IDAPI functions
  1594.     TIME        Time;       // Time portion of the TimeStamp
  1595.     DBIDATE     Date;       // Date portion of the TimeStamp
  1596.     CHAR        szDate[15]; // Date string
  1597.     CHAR        szTime[20]; // Time String
  1598.  
  1599.     // Get the date and time components.
  1600.     rslt = DbiTimeStampDecode(TimeStamp, &Date, &Time);
  1601.     ChkRslt(rslt, "TimeStampDecode");
  1602.  
  1603.     // Get the Date format.
  1604.     FormatDate(Date, szDate);
  1605.  
  1606.     // Get the Time format.
  1607.     FormatTime(Time, szTime);
  1608.  
  1609.     // Format the TimeStamp.
  1610.     wsprintf(szTimeStamp, "%s, %s", szTime, szDate);
  1611.  
  1612.     return rslt;
  1613. }
  1614.  
  1615. //=====================================================================
  1616. //  Function:
  1617. //          FormatNumber(szNumber)
  1618. //
  1619. //  Input:  szNumber   - String that contains number in US format
  1620. //
  1621. //  Return: Result returned from DbiGetNumberFormat()
  1622. //
  1623. //  Description:
  1624. //          This function is used to format number fields according to
  1625. //          the settings in the IDAPI.CFG file.
  1626. //=====================================================================
  1627. DBIResult
  1628. FormatNumber (pCHAR szNumber)
  1629. {
  1630.     DBIResult  rslt = DBIERR_NONE;  // Return value from IDAPI functions
  1631.     FMTNumber  fmtNumber;           // Number Format
  1632.     pCHAR      ptr;
  1633.     int        period = '.';        //Default US decimal separetor
  1634.  
  1635.     // Get the formatting of the Number
  1636.     rslt = DbiGetNumberFormat(&fmtNumber);
  1637.     ChkRslt(rslt, "    GetNumberFormat.");
  1638.  
  1639.     ptr = strchr(szNumber, period);
  1640.     if (ptr)
  1641.     {
  1642.         *ptr = fmtNumber.cDecimalSeparator;
  1643.     }
  1644.  
  1645.     return rslt;
  1646. }
  1647.  
  1648. //=====================================================================
  1649. //  Function:
  1650. //          MakeFullPath (pszDirectory, pszRelativeDirectory)
  1651. //
  1652. //  Input:  pszDirectory            - String to contain the path to the
  1653. //                                    tables directory
  1654. //          pszRelativeDirectory    - String which contains the relative
  1655. //                                    offset from the current directory
  1656. //
  1657. //  Return: int     - If the directory exists
  1658. //
  1659. //  Description:
  1660. //          This function is used to get the fully qualified path to
  1661. //          the directory which will contain the tables. This function
  1662. //          will only work when pszRelativeDirectory contains either "."
  1663. //          an absolute path, or <..\\..\\>TABLES.
  1664. //=====================================================================
  1665. int
  1666. MakeFullPath (pCHAR pszDirectory, pCHAR pszRelativeDirectory)
  1667. {
  1668.     int     iExists;    // Does the directory exist?
  1669.     int     iLen;       // Length of the path
  1670.     int     iLoop;      // Loop counter
  1671.     int     iDepth = 0; // How relative the directory is
  1672.     
  1673.     // Assume absolute path if second character is a ':'.
  1674.     if (pszRelativeDirectory[1] == ':')
  1675.     {
  1676.         strcpy(pszDirectory, pszRelativeDirectory);
  1677.     }
  1678.     else if (!strcmp(pszRelativeDirectory, "."))
  1679.     {
  1680.         // Get the current working directory.
  1681.         getcwd(pszDirectory, DBIMAXPATHLEN);
  1682.     }
  1683.     else
  1684.     {
  1685.         // Get the current working directory.
  1686.         getcwd(pszDirectory, DBIMAXPATHLEN);
  1687.         
  1688.         iLen = strlen(pszDirectory);
  1689.  
  1690.         // Remove relative parts of the path.
  1691.         iDepth = 0;
  1692.         while (!strncmp(&pszRelativeDirectory[iDepth * 3], "..\\", 3))
  1693.         {
  1694.             for (iLoop = iLen; iLoop > -1; iLoop = iLoop - 1)
  1695.             {
  1696.                 if (pszDirectory[iLoop] == '\\')
  1697.                 {
  1698.                     break;
  1699.                 }
  1700.             }
  1701.             iLen = iLoop - 1;
  1702.             iDepth++;
  1703.         }
  1704.  
  1705.         // Copy the 'TABLES' directory to form the full path to the tables.
  1706.         //   Need to move szDirectory past the '\\' and szTblDirectory
  1707.         //   past the '..\\'.
  1708.         strcpy(&pszDirectory[iLoop+1], &pszRelativeDirectory[(3 * iDepth)]);
  1709.     }
  1710.  
  1711.     // Check if the directory exists.
  1712.     iExists = access(pszDirectory, 00);
  1713.  
  1714.     return iExists;
  1715. }
  1716.  
  1717. //=====================================================================
  1718. //  Function:
  1719. //          DisplayNextRecord(hCur)
  1720. //
  1721. //  Input:  Handle to the cursor
  1722. //
  1723. //  Return: DBIERR_SUCCESS
  1724. //
  1725. //  Description:
  1726. //          This function will call DisplayInMemoryTable() with a value
  1727. //          of 1 for the second parameter.  This causes it to display the
  1728. //          next record.
  1729. //=====================================================================
  1730. DBIResult
  1731. DisplayNextRecord(hDBICur hCur)
  1732. {
  1733.     return(DisplayInMemoryTable(hCur, 1));
  1734. }
  1735.  
  1736. //=====================================================================
  1737. //  Function:
  1738. //          DisplayCurrentRecord(hCur);
  1739. //
  1740. //  Input:  hCur    - Cursor handle - which table to access
  1741. //
  1742. //  Return: Result of displaying the records in the table
  1743. //
  1744. //  Description:
  1745. //          This function will display the current record only.
  1746. //
  1747. //  Note:   This function will only display the columns
  1748. //          correctly when using a fixed pitch font.
  1749. //=====================================================================
  1750. DBIResult
  1751. DisplayCurrentRecord (hDBICur hCur)
  1752. {
  1753.     DBIResult   rslt;               // IDAPI function return value
  1754.     CURProps    TblProps;           // Table Properties
  1755.     pFLDDesc    pFldDescs;          // List of fields
  1756.     pBYTE       pRecBuf;            // Record Buffer
  1757.     CHAR**      pszField;           // Array to contain the fields of the
  1758.                                     // table.
  1759.     CHAR*       szFormat;           // Contains an entire record (row)
  1760.     CHAR        szTemp[MAXLEN] =""; // Temporary variable for reading data
  1761.     UINT16      uFldNum;            // Loop variable
  1762.     const UINT16 uDefLength = 15;   // Default size of a field
  1763.  
  1764.  
  1765.     szFormat = (pCHAR) malloc(1600 * sizeof(BYTE));
  1766.     if (szFormat == NULL)
  1767.     {
  1768.         return DBIERR_NOMEMORY;
  1769.     }
  1770.  
  1771.     rslt = DbiGetCursorProps(hCur, &TblProps);
  1772.     if (ChkRslt(rslt, "GetCursorProps") != DBIERR_NONE)
  1773.     {
  1774.         free(szFormat);
  1775.         return rslt;
  1776.     }
  1777.  
  1778.     // Allocate space for the record buffer.
  1779.     pRecBuf = (pBYTE) malloc(TblProps.iRecBufSize * sizeof(BYTE));
  1780.     if (pRecBuf == NULL)
  1781.     {
  1782.         return DBIERR_NOMEMORY;
  1783.     }
  1784.  
  1785.     // Allocate enough space to contain information (field descriptors)
  1786.     //   about all the fields in the answer table.
  1787.     pFldDescs = (pFLDDesc) malloc(TblProps.iFields * sizeof(FLDDesc));
  1788.     if (pFldDescs == NULL)
  1789.     {
  1790.         free(szFormat);
  1791.         free(pRecBuf);
  1792.         return DBIERR_NOMEMORY;
  1793.     }
  1794.  
  1795.     // Get information about the fields.
  1796.     rslt = DbiGetFieldDescs(hCur, pFldDescs);
  1797.     ChkRslt(rslt, "GetFieldDescs");
  1798.  
  1799.     // Allocate enough buffers to contain data from the fields in the
  1800.     //   answer table. Also set the width of non-fldZSTRING fields
  1801.     //   (all data will be converted to strings for display).
  1802.     pszField = (CHAR**)malloc(TblProps.iFields * sizeof(CHAR*));
  1803.  
  1804.     // Set up formatting for the fields.
  1805.     SetupFields(TblProps, pFldDescs, pszField, uDefLength);
  1806.  
  1807.     // Display the names of the fields, aligned by column.
  1808.     strcpy(szFormat,"\r\n        ");
  1809.     for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  1810.     {
  1811.         sprintf(szTemp, "%-*s\t", pFldDescs[uFldNum].iUnits1 + 1,
  1812.                 pFldDescs[uFldNum].szName);
  1813.         strcat(szFormat, szTemp);
  1814.     }
  1815.  
  1816.     // Display the header.
  1817.     Screen(szFormat);
  1818.  
  1819.     rslt = DbiGetRecord(hCur, dbiNOLOCK, pRecBuf, NULL);
  1820.     ChkRslt(rslt, "GetRecord");
  1821.  
  1822.     // Fill the record buffer with the field values.
  1823.     GetFields(hCur, pFldDescs, pRecBuf, pszField, uDefLength);
  1824.  
  1825.     // Initialize szFormat to all zeroes.
  1826.     memset(szFormat, 0, sizeof(szFormat));
  1827.  
  1828.     // Add leading blank space to the record.
  1829.     strcpy(szFormat,"        ");
  1830.  
  1831.     // Add each field to be displayed, making certain that the
  1832.     //   columns line up.
  1833.     for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  1834.     {
  1835.         sprintf(szTemp, " %-*s\t", pFldDescs[uFldNum].iUnits1,
  1836.         pszField[uFldNum]);
  1837.         strcat(szFormat, szTemp);
  1838.     }
  1839.  
  1840.     // Display the record.
  1841.     Screen(szFormat);
  1842.  
  1843.     // Expect the End-Of-File error - just means that there
  1844.     //   are no more records in the table.
  1845.     if (rslt == DBIERR_EOF)
  1846.     {
  1847.         rslt = DBIERR_NONE;
  1848.     }
  1849.  
  1850.     // Clean up.
  1851.     for (uFldNum = 0; uFldNum < TblProps.iFields; uFldNum++)
  1852.     {
  1853.         free(pszField[uFldNum]);
  1854.     }
  1855.  
  1856.     free(pszField);
  1857.     free(pFldDescs);
  1858.     free(pRecBuf);
  1859.     free(szFormat);
  1860.  
  1861.     return rslt;
  1862. }
  1863.  
  1864.  
  1865.