home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / crt / src / a_cmp.c < prev    next >
C/C++ Source or Header  |  1998-06-17  |  10KB  |  291 lines

  1. /***
  2. *a_cmp.c - A version of CompareString.
  3. *
  4. *       Copyright (c) 1993-1997, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. *       Use either CompareStringA or CompareStringW depending on which is
  8. *       available
  9. *
  10. *******************************************************************************/
  11.  
  12. #include <cruntime.h>
  13. #include <internal.h>
  14. #include <dbgint.h>
  15. #include <stdlib.h>
  16. #include <setlocal.h>
  17. #include <awint.h>
  18. #include <dbgint.h>
  19.  
  20. #define USE_W   1
  21. #define USE_A   2
  22.  
  23. /***
  24. *int __cdecl strncnt - count characters in a string, up to n.
  25. *
  26. *Purpose:
  27. *       Internal local support function. Counts characters in string before NULL.
  28. *       If NULL not found in n chars, then return n.
  29. *
  30. *Entry:
  31. *       const char *string   - start of string
  32. *       int n                - byte count
  33. *
  34. *Exit:
  35. *       returns number of bytes from start of string to
  36. *       NULL (exclusive), up to n.
  37. *
  38. *Exceptions:
  39. *
  40. *******************************************************************************/
  41.  
  42. static int __cdecl strncnt (
  43.         const char *string,
  44.         int cnt
  45.         )
  46. {
  47.         int n = cnt;
  48.         char *cp = (char *)string;
  49.  
  50.         while (n-- && *cp)
  51.             cp++;
  52.  
  53.         if (!*cp)
  54.             return cp - string;
  55.         return cnt;
  56. }
  57.  
  58. /***
  59. *int __cdecl __crtCompareStringA - Get type information about an ANSI string.
  60. *
  61. *Purpose:
  62. *       Internal support function. Assumes info in ANSI string format. Tries
  63. *       to use NLS API call CompareStringA if available and uses CompareStringW
  64. *       if it must. If neither are available it fails and returns 0.
  65. *
  66. *Entry:
  67. *       LCID    Locale      - locale context for the comparison.
  68. *       DWORD   dwCmpFlags  - see NT\Chicago docs
  69. *       LPCSTR  lpStringn   - multibyte string to be compared
  70. *       int     cchCountn   - char (byte) count (NOT including NULL)
  71. *                             (-1 if NULL terminated)
  72. *       int     code_page   - for MB/WC conversion. If 0, use __lc_codepage
  73. *
  74. *Exit:
  75. *       Success: 1 - if lpString1 <  lpString2
  76. *                2 - if lpString1 == lpString2
  77. *                3 - if lpString1 >  lpString2
  78. *       Failure: 0
  79. *
  80. *Exceptions:
  81. *
  82. *******************************************************************************/
  83.  
  84. int __cdecl __crtCompareStringA(
  85.         LCID     Locale,
  86.         DWORD    dwCmpFlags,
  87.         LPCSTR   lpString1,
  88.         int      cchCount1,
  89.         LPCSTR   lpString2,
  90.         int      cchCount2,
  91.         int      code_page
  92.         )
  93. {
  94.         static int f_use = 0;
  95.  
  96.         /*
  97.          * Look for unstubbed 'preferred' flavor. Otherwise use available flavor.
  98.          * Must actually call the function to ensure it's not a stub.
  99.          * (Always try wide version first so WinNT can process codepage correctly.)
  100.          */
  101.  
  102.         if (0 == f_use)
  103.         {
  104.             if (0 != CompareStringW(0, 0, L"\0", 1, L"\0", 1))
  105.                 f_use = USE_W;
  106.  
  107.             else if (0 != CompareStringA(0, 0, "\0", 1, "\0", 1))
  108.                 f_use = USE_A;
  109.  
  110.             else
  111.                 return 0;
  112.         }
  113.  
  114.         /*
  115.          * CompareString will compare past NULL. Must find NULL if in string
  116.          * before cchCountn chars.
  117.          */
  118.  
  119.         if (cchCount1 > 0)
  120.             cchCount1 = strncnt(lpString1, cchCount1);
  121.         if (cchCount2 > 0)
  122.             cchCount2 = strncnt(lpString2, cchCount2);
  123.  
  124.         /* Use "A" version */
  125.  
  126.         if (USE_A == f_use)
  127.         {
  128.             return CompareStringA( Locale,
  129.                                    dwCmpFlags,
  130.                                    lpString1,
  131.                                    cchCount1,
  132.                                    lpString2,
  133.                                    cchCount2 );
  134.         }
  135.  
  136.         /* Use "W" version */
  137.  
  138.         if (USE_W == f_use)
  139.         {
  140.             int buff_size1;
  141.             int buff_size2;
  142.             wchar_t *wbuffer1;
  143.             wchar_t *wbuffer2;
  144.  
  145.             /*
  146.              * Use __lc_codepage for conversion if code_page not specified
  147.              */
  148.  
  149.             if (0 == code_page)
  150.                 code_page = __lc_codepage;
  151.  
  152.             /*
  153.              * Special case: at least one count is zero
  154.              */
  155.  
  156.             if (!cchCount1 || !cchCount2)
  157.             {
  158.                 unsigned char *cp;  // char pointer
  159.                 CPINFO lpCPInfo;    // struct for use with GetCPInfo
  160.  
  161.                 /* both strings zero */
  162.                 if (cchCount1 == cchCount2)
  163.                     return 2;
  164.  
  165.                 /* string 1 greater */
  166.                 if (cchCount2 > 1)
  167.                     return 1;
  168.  
  169.                 /* string 2 greater */
  170.                 if (cchCount1 > 1)
  171.                     return 3;
  172.  
  173.                 /*
  174.                  * one has zero count, the other has a count of one
  175.                  * - if the one count is a naked lead byte, the strings are equal
  176.                  * - otherwise it is a single character and they are unequal
  177.                  */
  178.  
  179.                 if (GetCPInfo(code_page, &lpCPInfo) == FALSE)
  180.                     return 0;
  181.  
  182.                 _ASSERTE(cchCount1==0 && cchCount2==1 || cchCount1==1 && cchCount2==0);
  183.  
  184.                 /* string 1 has count of 1 */
  185.                 if (cchCount1 > 0)
  186.                 {
  187.                     if (lpCPInfo.MaxCharSize < 2)
  188.                         return 3;
  189.  
  190.                     for ( cp = (unsigned char *)lpCPInfo.LeadByte ;
  191.                           cp[0] && cp[1] ;
  192.                           cp += 2 )
  193.                         if ( (*(unsigned char *)lpString1 >= cp[0]) &&
  194.                              (*(unsigned char *)lpString1 <= cp[1]) )
  195.                             return 2;
  196.  
  197.                     return 3;
  198.                 }
  199.  
  200.                 /* string 2 has count of 1 */
  201.                 if (cchCount2 > 0)
  202.                 {
  203.                     if (lpCPInfo.MaxCharSize < 2)
  204.                     return 1;
  205.  
  206.                     for ( cp = (unsigned char *)lpCPInfo.LeadByte ;
  207.                           cp[0] && cp[1] ;
  208.                           cp += 2 )
  209.                         if ( (*(unsigned char *)lpString2 >= cp[0]) &&
  210.                              (*(unsigned char *)lpString2 <= cp[1]) )
  211.                             return 2;
  212.  
  213.                     return 1;
  214.                 }
  215.             }
  216.  
  217.             /*
  218.              * Convert strings and return the requested information.
  219.              */
  220.  
  221.             /* find out how big a buffer we need (includes NULL if any) */
  222.             if ( 0 == (buff_size1 = MultiByteToWideChar( code_page,
  223.                                                          MB_PRECOMPOSED |
  224.                                                             MB_ERR_INVALID_CHARS,
  225.                                                          lpString1,
  226.                                                          cchCount1,
  227.                                                          NULL,
  228.                                                          0 )) )
  229.                 return 0;
  230.  
  231.             /* allocate enough space for chars */
  232.             __try {
  233.                 wbuffer1 = (wchar_t *)_alloca( buff_size1 * sizeof(wchar_t) );
  234.             }
  235.             __except( EXCEPTION_EXECUTE_HANDLER ) {
  236.                 wbuffer1 = NULL;
  237.             }
  238.  
  239.             if ( wbuffer1 == NULL )
  240.                 return 0;
  241.  
  242.             /* do the conversion */
  243.             if ( 0 == MultiByteToWideChar( code_page,
  244.                                            MB_PRECOMPOSED,
  245.                                            lpString1,
  246.                                            cchCount1,
  247.                                            wbuffer1,
  248.                                            buff_size1 ) )
  249.                 return 0;
  250.  
  251.             /* find out how big a buffer we need (includes NULL if any) */
  252.             if ( 0 == (buff_size2 = MultiByteToWideChar( code_page,
  253.                                                          MB_PRECOMPOSED |
  254.                                                             MB_ERR_INVALID_CHARS,
  255.                                                          lpString2,
  256.                                                          cchCount2,
  257.                                                          NULL,
  258.                                                          0 )) )
  259.                 return 0;
  260.  
  261.             /* allocate enough space for chars */
  262.             __try {
  263.                 wbuffer2 = (wchar_t *)_alloca( buff_size2 * sizeof(wchar_t) );
  264.             }
  265.             __except( EXCEPTION_EXECUTE_HANDLER ) {
  266.                 wbuffer2 = NULL;
  267.             }
  268.  
  269.             if ( wbuffer2 == NULL )
  270.                 return 0;
  271.  
  272.             /* do the conversion */
  273.             if ( 0 == MultiByteToWideChar( code_page,
  274.                                            MB_PRECOMPOSED,
  275.                                            lpString2,
  276.                                            cchCount2,
  277.                                            wbuffer2,
  278.                                            buff_size2 ) )
  279.                 return 0;
  280.  
  281.             return CompareStringW( Locale,
  282.                                    dwCmpFlags,
  283.                                    wbuffer1,
  284.                                    buff_size1,
  285.                                    wbuffer2,
  286.                                    buff_size2 );
  287.         }
  288.         else   /* f_use is neither USE_A nor USE_W */
  289.             return 0;
  290. }
  291.