home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bde / sdkseek.pak / DBFSEEK.C next >
Encoding:
C/C++ Source or Header  |  1997-07-24  |  27.1 KB  |  887 lines

  1. //  BDE - (C) Copyright 1995 by Borland International
  2.  
  3. #include "dbfseek.h"
  4. #include "macro.h"
  5.  
  6. #define szCURRENTMODULE  "DBFSEEK"
  7.  
  8. //=====================================================================
  9. //  This BDE example provides Paradox for Windows ver. 5.0 ObjectPAL users
  10. //  a means of doing a seek similar to the dBASE seek of MAINTAINED
  11. //  expression indexes on dBASE tables for retrieving record numbers.  The
  12. //  ObjectPAL procedures created are: DbfIdxSeek and DbfGetIdxExpr.
  13. //
  14. //  Expressions tested in an MDX file:
  15. //
  16. //    LTRIM(STR(MONTH(DATES)))+"/"+LTRIM(STR(DAY(DATES)))+"/"
  17. //        +SUBSTR(LTRIM(STR(YEAR(DATES))),3,2)
  18. //    LTRIM(FIRST_NAME)
  19. //    LTRIM(FIRST_NAME)-LTRIM(LAST_NAME)
  20. //    FIRST_NAME (a character field)
  21. //    FIRST_NAME-LAST_NAME
  22. //    FLOATS (a float field)
  23. //    NUMBERS (a number field)
  24. //    RECNO()
  25. //    RTRIM(FIRST_NAME) + DTOS(DATES)
  26. //        Indexes on concatenation of character and date field.  The date
  27. //        field is converted to characters in format YYYYMMDD.
  28. //        i.e. - Jerry19950518.
  29. //    SQRT(NUMBERS)
  30. //    LTRIM(STR(FLOATS))
  31. //    SUBSTR(FIRST_NAME,2,3)
  32. //
  33. //  Notes:
  34. //
  35. //  DbfIdxSeek returns a record number.  A return of 0 means that the record
  36. //  was not found.
  37. //
  38. //  DbfGetIdxExpr is just for viewing an expression string.
  39. //
  40. //  The EXACT setting, when set to FALSE, will find records with partial
  41. //  values in character expressions.  EXACT set to TRUE sets NEAR to FALSE.
  42. //
  43. //  EXACT: 0 = FALSE, 1 = TRUE
  44. //
  45. //  The NEAR setting, after an unsuccessful dbfSEEK, positions the record
  46. //  pointer at the record in the indexed table immediately after the position
  47. //  at which the value searched for would have been found.
  48. //
  49. //  NEAR: 0 = FALSE, 1 = TRUE
  50. //
  51. //  Character expressions are case sensitive except for soundex which must
  52. //  sound like the key value for a match to occur.
  53. //
  54. //  Use no commas in values seeking NUMERIC expressions.
  55. //
  56. //  "Sounds like" can be used if SOUNDEX is the only function used
  57. //  and is at the beginning of the expression.  All field names and
  58. //  other words must be contained within its perentheses i.e. -
  59. //    SOUNDEX(FIRST_NAME)
  60. //    SOUNDEX(FIRST_NAME-LAST_NAME)
  61. //
  62. //  DATE fields can be used directly if the field name is at the beginning
  63. //  of the expression and is used alone i.e. -
  64. //    DATES (a date field)
  65. //
  66. //
  67. //  This is how the Paradox Uses block should appear:
  68. //
  69. //  Uses dbfseek
  70. //
  71. //      DbfIdxSeek(TableDir cptr, TableName cptr,
  72. //                 IndexFileNameWithExtension cptr,
  73. //                 IndexTagName cptr, KeyValue cptr,
  74. //                 Exact cword, Near cword,
  75. //                 returnStringBuffer cptr)cdouble
  76. //      DbfGetIdxExpr(TableDir cptr, TableName cptr,
  77. //                    IndexFileNameWithExtension cptr,
  78. //                    IndexTagName cptr, ReturnValue cptr)
  79. //
  80. //  endUses
  81. //
  82. //
  83. //  And some typical methods:
  84. //
  85. //    Var
  86. //        returnStringBuffer String
  87. //    endVar
  88. //
  89. //
  90. //    method open(var eventInfo Event)
  91. //
  92. //        if eventInfo.isPreFilter() then
  93. //            ;// This code executes for each object on the form:
  94. //        
  95. //        else
  96. //            ;// This code executes only for the form:
  97. //        
  98. //            ; requires a 129 byte buffer:
  99. //            returnStringBuffer = space(129)   ; VERY IMPORTANT! or GPF
  100. //
  101. //        endif
  102. //
  103. //    endmethod
  104. //
  105. //
  106. //    method pushButton(var eventInfo Event)
  107. //
  108. //        var exact, near smallint endvar
  109. //        exact = 0
  110. //        near = 0
  111. //        RecNoReturn = DbfIdxSeek(workingdir(), "test.dbf",
  112. //                                "test.mdx", "sometag",
  113. //                                "somevalue", exact, near, returnStringBuffer)
  114. //        if RecNoReturn > 0 then
  115. //            TableFrameName.moveToRecNo(RecNoReturn)
  116. //        else
  117. //            TableFrameName.moveToRecNo(1)
  118. //        endif
  119. //        message(returnStringBuffer) ; for errors
  120. //
  121. //    endmethod
  122. //
  123. //
  124. //    method pushButton(var eventInfo Event)
  125. //
  126. //        DbfGetIdxExpr(workingdir(), "test.dbf", "test.mdx", 
  127. //                      "sometag", returnStringBuffer)
  128. //        view(returnStringBuffer)
  129. //
  130. //    endmethod
  131. //
  132. //=====================================================================
  133.  
  134. //=====================================================================
  135. //  Function:
  136. //             DbfIdxSeek(pCHAR pTblDir, pCHAR pTblName, pCHAR pIdxName,
  137. //                        pCHAR pIdxTag, pCHAR pKeyVal, pCHAR pszRetBuffer)
  138. //
  139. //  Description:
  140. //             This example shows how to seek for a key value in a dBASE
  141. //             maintained key expression.
  142. //
  143. //=====================================================================
  144. DFLOAT FAR WINAPI _export
  145. DbfIdxSeek (pCHAR pTblDir, pCHAR pTblName, pCHAR pIdxName,
  146.             pCHAR pIdxTag, pCHAR pKeyVal, int bExact, int bNear,
  147.             pCHAR pszRetBuffer)
  148. {
  149.     CHAR        szTblType[] = szDBASE;   // table type (dBASE)
  150.     UINT16      i               = 0;     // for loops
  151.     UINT16      iKeyValLen      = 0;     // for total key bytes received
  152.     UINT16      iKeyValEven     = 1;     // for total used key bytes
  153.     div_t       x;                       // for calcing total used key bytes
  154.     FMTBcd      Bcd;
  155.     CURProps    TblProps;
  156.     IDXDesc     *pIdxDesc       = NULL;
  157.     DBIResult   rslt            = NULL;
  158.     UINT32      retVal          = 0;
  159.     hDBIDb      hDb             = NULL;
  160.     hDBICur     hCur            = NULL;
  161.     pRECProps   precProps       = NULL;
  162.     char        *ptok           = NULL;
  163.     UINT16      iFldNum         = 0;
  164.     DFLOAT      fKeyVal         = 0;
  165.     pFLDDesc    pFldDesc        = NULL;
  166.     char        *ptrFunc, c     = '(';
  167.     UINT16      iIndexSeqNumber = 0;
  168.     pBYTE       pBuf            = NULL;  // Pointer to the record buffer
  169.     pBYTE       pKeyBuf         = NULL;  // Pointer to the key buffer
  170.     BOOL        bIsNegative     = 0;
  171.     BOOL        bExpFunc        = 0;
  172.     BOOL        bHasNoFld       = 0;
  173.     BOOL        bBlank          = 0;
  174.     BOOL        bBlankDate      = 0;
  175.     UINT16      ptr             = 0;
  176.     UINT16      iFldType        = 0;
  177.     DBIDATE     dateD           = NULL;
  178.     UINT16      uDay            = NULL; // Day portion of date
  179.     UINT16      uMon            = NULL; // Month portion of date
  180.     INT16       iYear           = NULL; // Year portion of date
  181.     char        szYear[5];              // buffer for year
  182.     char        szPlaces[2]     = "4";
  183.     char        *szKeyBuf1      = NULL;
  184.     char        *szKeyBuf2      = NULL;
  185.     char        *szKeyBuf3      = NULL;
  186.     char        *szKeyBuf4      = NULL;
  187.     char        *szFField       = NULL; // buffer for first exp. field name
  188.     UINT16      uDecLen         = 0;    // Decimal length
  189.  
  190.     if (bExact == 1)
  191.     {
  192.         bNear = 0;
  193.     }
  194.  
  195.     // initialize buffer for error string
  196.     memset(pszRetBuffer, 0, (DBIMAXMSGLEN + 1) * sizeof(char));
  197.  
  198.     // do nothing if a key value is not sent
  199.     CHKERR_NODISPLAY(!strcmp(pKeyVal, ""))
  200.  
  201.     iKeyValLen = strlen(&pKeyVal[0]);
  202.  
  203.     if (pKeyVal[0] == '-') // for negative numbers
  204.     {
  205.         bIsNegative = TRUE;
  206.     }
  207.  
  208.     precProps = ((pRECProps) malloc (sizeof(RECProps)));
  209.     if (precProps == NULL)
  210.     {
  211.         GetString(1, pszRetBuffer); //"Out of Memory."
  212.         CLEANUP_NODISPLAY;
  213.     }
  214.  
  215.     // open a database in the current session and get a database handle
  216.     CHKERR_CLEANUP(DbiOpenDatabase(NULL, NULL, dbiREADONLY, dbiOPENSHARED,
  217.                                    NULL, 0, NULL, NULL, &hDb));
  218.  
  219.     // set the current directory
  220.     CHKERR_CLEANUP(DbiSetDirectory(hDb, pTblDir));
  221.  
  222.     // associate a cursor handle with an opened table
  223.     CHKERR_CLEANUP(DbiOpenTable(hDb, pTblName, NULL, pIdxName, pIdxTag,
  224.                                 0, dbiREADONLY, dbiOPENSHARED, xltFIELD,
  225.                                 FALSE, NULL, &hCur));
  226.  
  227.     CHKERR_CLEANUP(DbiGetCursorProps(hCur, &TblProps));
  228.  
  229.     if (strcmp(szTblType, TblProps.szTableType))
  230.     {
  231.         GetString(7, pszRetBuffer); //"Only dBASE tables are supported."
  232.         CLEANUP_NODISPLAY;
  233.     }
  234.  
  235.     pFldDesc = (pFLDDesc) malloc (sizeof(FLDDesc) * TblProps.iFields);
  236.     if (pFldDesc == NULL)
  237.     {
  238.         GetString(1, pszRetBuffer); //"Out of Memory."
  239.         CLEANUP_NODISPLAY;
  240.     }
  241.  
  242.     CHKERR_CLEANUP(DbiGetFieldDescs(hCur, pFldDesc));
  243.  
  244.     pIdxDesc = (IDXDesc*) malloc (TblProps.iIndexes * sizeof(IDXDesc));
  245.     if (pIdxDesc == NULL)
  246.     {
  247.         GetString(1, pszRetBuffer); //"Out of Memory."
  248.         CLEANUP_NODISPLAY;
  249.     }
  250.  
  251.     CHKERR_CLEANUP(DbiGetIndexDescs(hCur, pIdxDesc));
  252.  
  253.     pBuf = (pBYTE) malloc (TblProps.iRecBufSize);
  254.     if (pBuf == NULL)
  255.     {
  256.         GetString(1, pszRetBuffer); //"Out of Memory."
  257.         CLEANUP_NODISPLAY;
  258.     }
  259.  
  260.     CHKERR_CLEANUP(DbiInitRecord(hCur, pBuf));
  261.  
  262.     CHKERR_CLEANUP(DbiGetIndexSeqNo(hCur, pIdxName, pIdxTag, NULL,
  263.                                     &iIndexSeqNumber));
  264.  
  265.     if (pIdxDesc[iIndexSeqNumber - 1].bMaintained == 0)
  266.     {
  267.         GetString(3, pszRetBuffer); //"Only maintained indexes are supported."
  268.         CLEANUP_NODISPLAY;
  269.     }
  270.  
  271.     pKeyBuf  = (pBYTE) malloc((pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 1) *
  272.                               sizeof (BYTE));
  273.     szKeyBuf1 = (char*) malloc((pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 1) *
  274.                                sizeof (char));
  275.     szKeyBuf2 = (char*) malloc((pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 1) *
  276.                                sizeof (char));
  277.     szKeyBuf3 = (char*) malloc((pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 1) *
  278.                                sizeof (char));
  279.     szKeyBuf4 = (char*) malloc((pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 1) *
  280.                                sizeof (char));
  281.     // initialize buffer for first exp. field name
  282.     szFField = (char*) malloc((strlen(pIdxDesc[iIndexSeqNumber - 1].szKeyExp)
  283.                                + 1) * sizeof (char));
  284.     if ((szFField == NULL) ||
  285.         (pKeyBuf == NULL) ||
  286.         (szKeyBuf1 == NULL) ||
  287.         (szKeyBuf2 == NULL) ||
  288.         (szKeyBuf3 == NULL) ||
  289.         (szKeyBuf4 == NULL))
  290.     {
  291.         GetString(1, pszRetBuffer); //"Out of Memory."
  292.         CLEANUP_NODISPLAY;
  293.     }
  294.  
  295.     // does the expression contain soundex
  296.     ptrFunc = strchr(pIdxDesc[iIndexSeqNumber - 1].szKeyExp, c);
  297.     if (ptrFunc)
  298.     {
  299.         ptr = strncmpi("soundex", pIdxDesc[iIndexSeqNumber - 1].szKeyExp, 7);
  300.         if (ptr == 0)
  301.         {
  302.             bExpFunc = 1;
  303.         }
  304.  
  305.         // get first field name and type disregarding function
  306.         ptok = strtok(pIdxDesc[iIndexSeqNumber - 1].szKeyExp, "(");
  307.         ptok = strtok('\0', " ()-+/*");
  308.         if (ptok)
  309.         {
  310.             strcpy(szFField, ptok);
  311.         }
  312.         else
  313.         {
  314.             // has no field name in the expression
  315.             bHasNoFld = 1;
  316.         }
  317.     }
  318.     else
  319.     {
  320.         // has no function, then assuming expression has a field name
  321.         ptok = strtok(pIdxDesc[iIndexSeqNumber - 1].szKeyExp, " -+/*");
  322.         if (ptok)
  323.         {
  324.             strcpy(szFField, ptok);
  325.         }
  326.         else
  327.         {
  328.             bHasNoFld = 1;
  329.         }
  330.     }
  331.  
  332.     if (bHasNoFld == 0)
  333.     {
  334.         for (i = 0; i < TblProps.iFields; i++)
  335.         {
  336.             if (!strcmp(pFldDesc[i].szName, ptok))
  337.             {
  338.                 iFldType = pFldDesc[i].iFldType;
  339.                 iFldNum = pFldDesc[i].iFldNum;
  340.                 break;
  341.             }
  342.         }
  343.     }
  344.  
  345.     if (iFldType == fldDATE)
  346.     {
  347.         // set max input to key buffer
  348.         if (iKeyValLen > pIdxDesc[iIndexSeqNumber - 1].iKeyLen + 3)
  349.         {
  350.             GetString(4, pszRetBuffer); //"Key length exceeded."
  351.             MessageBeep(-1);
  352.             CLEANUP_NODISPLAY;
  353.         }
  354.  
  355.         if (pKeyVal[0] == ' ')
  356.         {
  357.             uMon = 12;
  358.             uDay = 31;
  359.             iYear = 9999;
  360.             bBlankDate = 1;
  361.             bNear = 1;
  362.         }
  363.         else
  364.         {
  365.             ptok = strtok(pKeyVal, " /");
  366.             if (ptok)
  367.             {
  368.                 uMon = atoi(ptok);
  369.             }
  370.  
  371.             for (i = 0; i < 2; i++)
  372.             {
  373.                 ptok = strtok('\0', "/");
  374.                 if ((i == 0)&&(ptok))
  375.                 {
  376.                     uDay = atoi(ptok);
  377.                 }
  378.  
  379.                 if ((i == 1)&&(ptok))
  380.                 {
  381.                     // assumption: dates entered > 51 and <100 = 1950 otherwise
  382.                     // it = 2050 unless 4 digit year is entered
  383.                     if (atoi(ptok) > 50 && atoi(ptok) < 100)
  384.                     {
  385.                         if (atoi(ptok) > 50)
  386.                         {
  387.                             strcpy(szYear, "19");
  388.                             strcat(szYear, ptok);
  389.                             iYear = atoi(szYear);
  390.                         }
  391.                         else
  392.                         {
  393.                             strcpy(szYear, "20");
  394.                             strcat(szYear, ptok);
  395.                             iYear = atoi(szYear);
  396.                         }
  397.                     }
  398.                     else
  399.                     {
  400.                         strcpy(szYear, ptok);
  401.                         iYear = atoi(szYear);
  402.                     }
  403.                 }
  404.             }
  405.         }
  406.  
  407.         CHKERR_CLEANUP(DbiDateEncode(uMon, uDay, iYear, &dateD));
  408.  
  409.         CHKERR_CLEANUP(DbiPutField(hCur, iFldNum, pBuf, (pBYTE) &dateD));
  410.  
  411.         CHKERR_CLEANUP(DbiExtractKey(hCur, pBuf, (pBYTE) pKeyBuf));
  412.  
  413.         if (bNear == 1)
  414.         {
  415.             CHKERR_CLEANUP(DbiSetToKey(hCur, keySEARCHGEQ, TRUE, 0, 0,
  416.                            pKeyBuf));
  417.         }
  418.         else
  419.         {
  420.             CHKERR_CLEANUP(DbiSetToKey(hCur, keySEARCHEQ, TRUE, 0, 0,
  421.                            pKeyBuf));
  422.         }
  423.  
  424.         CHKERR_CLEANUP(DbiGetNextRecord(hCur, dbiNOLOCK, pBuf, precProps));
  425.  
  426.         CHKERR_CLEANUP(DbiGetField(hCur, iFldNum, pBuf, NULL, &bBlank));
  427.  
  428.         if (bBlank)
  429.         {
  430.             // if set to near and the indate is larger than any key value,
  431.             //     force an end of table (message only), otherwise a blank
  432.             //     record gets found.
  433.             if (bNear == 1 && bBlankDate == 0)
  434.             {
  435.                 GetString(9, pszRetBuffer); //"At end of table."
  436.                 CLEANUP_NODISPLAY;
  437.             }
  438.         }
  439.  
  440.         retVal = precProps[0].iPhyRecNum;
  441.     }
  442.     else
  443.     {
  444.         if (pIdxDesc[iIndexSeqNumber - 1].iKeyExpType == fldDBCHAR)
  445.         {
  446.             // set key buffer for char expression type
  447.             memset(pKeyBuf, ' ', pIdxDesc[iIndexSeqNumber - 1].
  448.                    iKeyLen + 1 * sizeof (BYTE));
  449.  
  450.             if (bExpFunc == 0)
  451.             {
  452.                 // set max input to key buffer
  453.                 if (iKeyValLen > pIdxDesc[iIndexSeqNumber - 1].iKeyLen)
  454.                 {
  455.                     GetString(4, pszRetBuffer); //"Key length exceeded."
  456.                     MessageBeep(-1);
  457.                     CLEANUP_NODISPLAY;
  458.                 }
  459.  
  460.                 memcpy((pCHAR)pKeyBuf, pKeyVal, iKeyValLen);
  461.                 if (bExact == 0 && bNear == 0)
  462.                 {
  463.                     CHKERR_CLEANUP(DbiGetRecordForKey(hCur, TRUE, 0,
  464.                                                       iKeyValLen, (pBYTE)
  465.                                                       pKeyBuf, NULL));
  466.  
  467.                     CHKERR_CLEANUP(DbiGetRecord(hCur, dbiNOLOCK, NULL,
  468.                                                 precProps));
  469.  
  470.                 }
  471.                 if (bExact == 1)
  472.                 {
  473.                     CHKERR_CLEANUP(DbiGetRecordForKey(hCur, TRUE, 0,
  474.                                                       0, (pBYTE) pKeyBuf,
  475.                                                       NULL));
  476.  
  477.                     CHKERR_CLEANUP(DbiGetRecord(hCur, dbiNOLOCK, NULL,
  478.                                                 precProps));
  479.                 }
  480.  
  481.                 if (bNear == 1)
  482.                 {
  483.                    CHKERR_CLEANUP(DbiSetToKey(hCur, keySEARCHGEQ, TRUE, 0,
  484.                                               0, pKeyBuf));
  485.  
  486.                    CHKERR_CLEANUP(DbiGetNextRecord(hCur, dbiNOLOCK, pBuf,
  487.                                                    precProps));
  488.                 }
  489.             }
  490.  
  491.             if (bExpFunc == 1)   // for soundex
  492.             {
  493.                 // if first char in pKeyVal is not a letter, fail
  494.                 // (because DbiGetRecordForKey won't).
  495.                 if (!((pKeyVal[0] > '@') && (pKeyVal[0] < '[')) &&
  496.                     !((pKeyVal[0] > '`') && (pKeyVal[0] < '{')))
  497.                 {
  498.                     GetString(5, pszRetBuffer); //"Invalid character."
  499.                     MessageBeep(-1);
  500.                     CLEANUP_NODISPLAY;
  501.                 }
  502.  
  503.                 CHKERR_CLEANUP(DbiPutField(hCur, iFldNum, pBuf,
  504.                                           (pBYTE) pKeyVal));
  505.  
  506.                 CHKERR_CLEANUP(DbiExtractKey(hCur, pBuf, (pBYTE) pKeyBuf));
  507.  
  508.                 CHKERR_CLEANUP(DbiGetRecordForKey(hCur, TRUE, 0, 0,
  509.                                                  (pBYTE) pKeyBuf, NULL));
  510.  
  511.                 CHKERR_CLEANUP(DbiGetRecord(hCur, dbiNOLOCK, NULL, precProps));
  512.             }
  513.  
  514.             retVal = precProps[0].iPhyRecNum;
  515.         }
  516.  
  517.         if (pIdxDesc[iIndexSeqNumber - 1].iKeyExpType == fldDBKEYBCD)
  518.         {
  519.             // can't start with a space
  520.             if (pKeyVal[0] == ' ')
  521.             {
  522.                 CLEANUP_NODISPLAY;
  523.             }
  524.  
  525.             if (strchr(&pKeyVal[0], ','))
  526.             {
  527.                 GetString(6, pszRetBuffer); //"Use no commas."
  528.                 MessageBeep(-1);
  529.                 CLEANUP_NODISPLAY;
  530.             }
  531.  
  532.             // set max for input to key buffer
  533.             if (iKeyValLen > (pIdxDesc[iIndexSeqNumber - 1].iKeyLen) + 3)
  534.             {
  535.                 GetString(4, pszRetBuffer); //"Key length exceeded."
  536.                 MessageBeep(-1);
  537.                 CLEANUP_NODISPLAY;
  538.             }
  539.  
  540.             memset(pKeyBuf, '\0', pIdxDesc[iIndexSeqNumber - 1].
  541.                    iKeyLen * sizeof (BYTE));
  542.             memset(szKeyBuf1, '\0', pIdxDesc[iIndexSeqNumber - 1].
  543.                    iKeyLen * sizeof (char));
  544.  
  545.             // OK, now for some decimal and negative number control...
  546.             if (pKeyVal[0] == '.' || (pKeyVal[0] == '-' && pKeyVal[1] == '.'))
  547.             {
  548.                 GetString(8, pszRetBuffer); //"Enter 0 or -0 first."
  549.                 MessageBeep(-1);
  550.                 CLEANUP_NODISPLAY;
  551.             }
  552.  
  553.             ptok = strtok(pKeyVal, " .");
  554.             strcpy(szKeyBuf4, ptok);
  555.             iKeyValLen = strlen(szKeyBuf4);
  556.             if (ptok)
  557.             {
  558.                 ptok = strtok(NULL, ".");
  559.                 if (ptok)
  560.                 {
  561.                     uDecLen = strlen(&ptok[0]);
  562.                     strcat(szKeyBuf4, ptok);
  563.                     i = 0;
  564.                     if (szKeyBuf4[0] == '0')
  565.                     {
  566.                         while (szKeyBuf4[i] == '0')
  567.                         {
  568.                             i++;
  569.                         }
  570.                         strcpy(szKeyBuf2, &szKeyBuf4[i]);
  571.                     }
  572.                     else
  573.                     {
  574.                         szKeyBuf2 = strdup(szKeyBuf4);
  575.                         iKeyValLen = strlen(szKeyBuf2);
  576.                     }
  577.                 }
  578.                 else
  579.                 {
  580.                     szKeyBuf2 = strdup(szKeyBuf4);
  581.                 }
  582.             }
  583.  
  584.             if (bIsNegative)
  585.             {
  586.                 if (strlen(&pKeyVal[0]) > 1)
  587.                 {
  588.                     ptok = strtok(szKeyBuf2, " -");
  589.                     strcpy(szKeyBuf3, ptok);
  590.                     iKeyValLen = strlen(szKeyBuf3);
  591.                     fKeyVal = atof(szKeyBuf3);
  592.                 }
  593.                 else
  594.                 {
  595.                     CLEANUP_NODISPLAY;
  596.                 }
  597.             }
  598.             else
  599.             {
  600.                 fKeyVal = atof(szKeyBuf2);
  601.             }
  602.  
  603.             if (fKeyVal == 0)
  604.             {
  605.                 CLEANUP_NODISPLAY;
  606.             }
  607.  
  608.             // make total key bytes used an even number.
  609.             x = div(iKeyValLen, 2);
  610.             if (iKeyValLen > 1)
  611.             {
  612.                 iKeyValEven = iKeyValLen;
  613.             }
  614.  
  615.             if (x.rem == 1)
  616.             {
  617.                 iKeyValEven = iKeyValLen + 1;
  618.             }
  619.  
  620.             // setup first key buffer byte
  621.             szPlaces[0] = szPlaces[0] + (char)(iKeyValLen - uDecLen);
  622.             memmove(szKeyBuf1, szPlaces, 1);
  623.  
  624.             // setup second key buffer byte
  625.             if (bIsNegative)
  626.             {
  627.                 szPlaces[0] = (((iKeyValLen - 1) * 4) + 129);
  628.             }
  629.             else
  630.             {
  631.                 szPlaces[0] = ((iKeyValLen * 4) + 1);
  632.             }
  633.  
  634.             memmove(&szKeyBuf1[1], &szPlaces[0], 1);
  635.  
  636.             CHKERR_CLEANUP(DbiBcdFromFloat(&fKeyVal, iKeyValLen + 2,
  637.                                            2, &Bcd));
  638.  
  639.             if (iKeyValLen > 1)
  640.             {
  641.                 iKeyValLen--;
  642.             }
  643.  
  644.             for (i = 0; i < iKeyValLen; i++)
  645.             {
  646.                 memmove(&szKeyBuf1[i + 2], &Bcd.iFraction[i], 1);
  647.             }
  648.  
  649.             memcpy((pCHAR)pKeyBuf, szKeyBuf1, (iKeyValEven / 2) + 2);
  650.  
  651.             if (bNear == 1)
  652.             {
  653.                 CHKERR_CLEANUP(DbiSetToKey(hCur, keySEARCHGEQ, TRUE, 0, 0,
  654.                                            pKeyBuf));
  655.             }
  656.             else
  657.             {
  658.                 CHKERR_CLEANUP(DbiSetToKey(hCur, keySEARCHEQ, TRUE, 0, 0,
  659.                                            pKeyBuf));
  660.             }
  661.  
  662.             CHKERR_CLEANUP(DbiGetNextRecord(hCur, dbiNOLOCK, pBuf, precProps));
  663.  
  664.             retVal = precProps[0].iPhyRecNum;
  665.         }
  666.     }
  667.  
  668. CleanUp:
  669.     if (hCur)
  670.     {
  671.         DbiCloseCursor(&hCur);
  672.     }
  673.     if (hDb)
  674.     {
  675.         DbiCloseDatabase(&hDb);
  676.     }
  677.     if (precProps)
  678.     {
  679.         free(precProps);
  680.     }
  681.     if (pBuf)
  682.     {
  683.         free(pBuf);
  684.     }
  685.     if (pKeyBuf)
  686.     {
  687.         free(pKeyBuf);
  688.     }
  689.     if (pIdxDesc)
  690.     {
  691.         free(pIdxDesc);
  692.     }
  693.     if (pFldDesc)
  694.     {
  695.         free(pFldDesc);
  696.     }
  697.     if (szKeyBuf1)
  698.     {
  699.         free(szKeyBuf1);
  700.     }
  701.     if (szKeyBuf2)
  702.     {
  703.         free(szKeyBuf2);
  704.     }
  705.     if (szKeyBuf3)
  706.     {
  707.         free(szKeyBuf3);
  708.     }
  709.     if (szKeyBuf4)
  710.     {
  711.         free(szKeyBuf4);
  712.     }
  713.     if (szFField)
  714.     {
  715.         free(szFField);
  716.     }
  717.  
  718.     return retVal;
  719. }
  720.  
  721. //=====================================================================
  722. //  Function:
  723. //             DbfGetIdxExpr(pCHAR pTblDir, pCHAR pTblName, pCHAR pIdxName,
  724. //                           pCHAR pIdxTag, pCHAR pszRetBuffer)
  725. //
  726. //  Description:
  727. //             This example shows how to return an expression string and
  728. //             other information about an MDX file.
  729. //
  730. //=====================================================================
  731. void FAR WINAPI _export
  732. DbfGetIdxExpr (pCHAR pTblDir, pCHAR pTblName, pCHAR pIdxName,
  733.                pCHAR pIdxTag, pCHAR pszRetBuffer)
  734. {
  735.     CHAR        szTblType[] = szDBASE;
  736.     DBIResult   rslt;
  737.     CURProps    TblProps;
  738.     UINT16      iIndexSeqNumber;
  739.     hDBIDb      hDb         = NULL;
  740.     hDBICur     hCur        = NULL;
  741.     IDXDesc     *pIdxDesc   = NULL;
  742.  
  743.     // initialize buffer for error string
  744.     memset(pszRetBuffer, 0, (DBIMAXMSGLEN + 1) * sizeof(char));
  745.  
  746.     // open a database in the current session and get a database handle
  747.     CHKERR_CLEANUP(DbiOpenDatabase(NULL, NULL, dbiREADONLY, dbiOPENSHARED,
  748.                                    NULL, 0, NULL, NULL, &hDb));
  749.  
  750.     // set the current directory
  751.     CHKERR_CLEANUP(DbiSetDirectory(hDb, pTblDir));
  752.  
  753.     // associate a cursor handle with an opened table
  754.     CHKERR_CLEANUP(DbiOpenTable(hDb, pTblName, NULL, pIdxName, pIdxTag,
  755.                                 0, dbiREADONLY, dbiOPENSHARED, xltFIELD,
  756.                                 FALSE, NULL, &hCur));
  757.  
  758.     CHKERR_CLEANUP(DbiGetCursorProps(hCur, &TblProps));
  759.  
  760.     if (strcmp(szTblType, TblProps.szTableType))
  761.     {
  762.         GetString(7, pszRetBuffer); //"Only dBASE tables are supported."
  763.         CLEANUP_NODISPLAY;
  764.     }
  765.  
  766.     pIdxDesc = (IDXDesc*) malloc (TblProps.iIndexes * sizeof(IDXDesc));
  767.     if (pIdxDesc == NULL)
  768.     {
  769.         GetString(1, pszRetBuffer); //"Out of Memory."
  770.         CLEANUP_NODISPLAY;
  771.     }
  772.  
  773.     CHKERR_CLEANUP(DbiGetIndexDescs(hCur, pIdxDesc));
  774.  
  775.     CHKERR_CLEANUP(DbiGetIndexSeqNo(hCur, pIdxName, pIdxTag, NULL,
  776.                                     &iIndexSeqNumber));
  777.  
  778.     if (pIdxDesc[iIndexSeqNumber - 1].bMaintained == 0)
  779.     {
  780.         GetString(3, pszRetBuffer); //"Only maintained indexes are supported."
  781.         CLEANUP_NODISPLAY;
  782.     }
  783.  
  784.     strcpy(pszRetBuffer, pIdxDesc[iIndexSeqNumber - 1].szKeyExp);
  785.  
  786. CleanUp:
  787.     if (hCur)
  788.     {
  789.         DbiCloseCursor(&hCur);
  790.     }
  791.     if (hDb)
  792.     {
  793.         DbiCloseDatabase(&hDb);
  794.     }
  795.     if (pIdxDesc)
  796.     {
  797.         free(pIdxDesc);
  798.     }
  799. }
  800.  
  801. //=====================================================================
  802. //  Function:
  803. //              DBIError(DBIResult retVal, pCHAR pszRetBuffer)
  804. //
  805. //  Input:
  806. //              retVal          -   BDE return
  807. //              pszRetBuffer    -   Buffer to contain the error string
  808. //
  809. //  Return:     a DBIResult value.
  810. //
  811. //  Description:
  812. //              This function gets information of where an error occurred.
  813. //=====================================================================
  814. DBIResult
  815. DBIError (DBIResult retVal, pCHAR pszRetBuffer)
  816. {
  817.     if (retVal == DBIERR_NONE)
  818.     {
  819.         return retVal;
  820.     }
  821.  
  822.     if (retVal == DBIERR_CANTFINDODAPI)
  823.     {
  824.         GetString(2, pszRetBuffer); //"Cannot find IDAPI files: Check path."
  825.         CLEANUP_DISPLAYERR(pszRetBuffer);
  826.     }
  827.     else
  828.     {
  829.         DbiGetErrorString(retVal, pszRetBuffer);
  830.     }
  831.  
  832. CleanUp:
  833.     return retVal;
  834. }
  835.  
  836. //=====================================================================
  837. //  Function:
  838. //              GetString(WORD iStringID, pCHAR pszRetBuffer)
  839. //
  840. //  Input:
  841. //              iStringID       - Identifier for the string
  842. //              pszRetBuffer    - Buffer to contain the error string.
  843. //                                (Allocated by the calling function)
  844. //
  845. //  Description:
  846. //              Load a string from DBFSEEK.DLL.
  847. //=====================================================================
  848. void
  849. GetString (WORD iStringID, pCHAR pszRetBuffer)
  850. {
  851.     if (pszRetBuffer)
  852.     {
  853.         LoadString(GetModuleHandle(szCURRENTMODULE), iStringID, pszRetBuffer,
  854.                    DBIMAXMSGLEN - 1);
  855.     }
  856. }
  857.  
  858.  
  859. #pragma argsused
  860. BOOL WINAPI
  861. LibMain (HINSTANCE hInstance, WORD wDataSeg,
  862.          WORD cbHeapSize, LPSTR lpCmdLine)
  863. {
  864.     if (cbHeapSize != 0)
  865.     {
  866.         UnlockData(0);
  867.     }
  868.  
  869.     return TRUE;
  870. }
  871.  
  872. int WINAPI
  873. WEP (int nSystemExit)
  874. {
  875.     switch (nSystemExit)
  876.     {
  877.         case WEP_SYSTEM_EXIT:
  878.             break;
  879.         case WEP_FREE_DLL:
  880.             break;
  881.     }
  882.  
  883.     return 1;
  884. }
  885.  
  886.  
  887.