strings.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 28k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. //============================================================================
  2. //
  3. // DBCS aware string routines...
  4. //
  5. //
  6. //============================================================================
  7. //#if defined(UNIX) && !defined(UNICODE)
  8. //#define UNICODE
  9. //#endif
  10. #include "ctlspriv.h"
  11. #ifdef WINNT
  12. #include <winnlsp.h>    // Get private NORM_ flag for StrEqIntl()
  13. #endif
  14. // for those of us who don't ssync to nt's build headers
  15. #ifndef NORM_STOP_ON_NULL
  16. #define NORM_STOP_ON_NULL   0x10000000
  17. #endif
  18. // WARNING: all of these APIs do not setup DS, so you can not access
  19. // any data in the default data seg of this DLL.
  20. //
  21. // do not create any global variables... talk to chrisg if you don't
  22. // understand thid
  23. #ifdef UNIX
  24. #ifdef BIG_ENDIAN
  25. #define READNATIVEWORD(x) MAKEWORD(*(char*)(x), *(char*)((char*)(x) + 1))
  26. #else
  27. #define READNATIVEWORD(x) MAKEWORD(*(char*)((char*)(x) + 1), *(char*)(x))
  28. #endif
  29. #else
  30. #define READNATIVEWORD(x) (*(UNALIGNED WORD *)x)
  31. #endif
  32. /*
  33.  * StrEndN - Find the end of a string, but no more than n bytes
  34.  * Assumes   lpStart points to start of null terminated string
  35.  *           nBufSize is the maximum length
  36.  * returns ptr to just after the last byte to be included
  37.  */
  38. LPSTR lstrfns_StrEndNA(LPCSTR lpStart, int nBufSize)
  39. {
  40.   LPCSTR lpEnd;
  41.   for (lpEnd = lpStart + nBufSize; *lpStart && OFFSETOF(lpStart) < OFFSETOF(lpEnd);
  42. lpStart = AnsiNext(lpStart))
  43.     continue;   /* just getting to the end of the string */
  44.   if (OFFSETOF(lpStart) > OFFSETOF(lpEnd))
  45.     {
  46.       /* We can only get here if the last byte before lpEnd was a lead byte
  47.        */
  48.       lpStart -= 2;
  49.     }
  50.   return((LPSTR)lpStart);
  51. }
  52. LPWSTR lstrfns_StrEndNW(LPCWSTR lpStart, int nBufSize)
  53. {
  54. #ifdef UNICODE
  55.   LPCWSTR lpEnd;
  56.   for (lpEnd = lpStart + nBufSize; *lpStart && (lpStart < lpEnd);
  57. lpStart++)
  58.     continue;   /* just getting to the end of the string */
  59.   return((LPWSTR)lpStart);
  60. #else
  61.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  62.   return NULL;
  63. #endif
  64. }
  65. // REVIEW WIN32 HACK - Convert to 32bit asm.
  66. #ifndef WIN32
  67. /*
  68.  * ReverseScan - Find last occurrence of a byte in a string
  69.  * Assumes   lpSource points to first byte to check (end of the string)
  70.  *           uLen is the number of bytes to check
  71.  *           bMatch is the byte to match
  72.  * returns ptr to the last occurrence of ch in str, NULL if not found.
  73.  */
  74. LPSTR PASCAL ReverseScan(LPCSTR lpSource, UINT uLen, BYTE bMatch)
  75. {
  76.   _asm
  77.     {
  78. /* Load count */
  79. mov     cx,uLen
  80. jcxz ReverseScanFail    ; count is zero, return failure.
  81. /* Load up es:di, ax */
  82. les     di,lpSource
  83. mov     al,bMatch
  84. /* Set the direction flag based on bBackward
  85.  * Perform the search; return 0 if we reached the end of the string
  86.  * otherwise, return es:di+1
  87.  */
  88. std
  89. repne   scasb
  90. jne     ReverseScanFail     ; check result of last compare.
  91. inc     di
  92. mov     dx,es
  93. mov     ax,di
  94. jmp ReverseScanExit
  95. ReverseScanFail:
  96. xor     ax,ax
  97. xor     dx,dx
  98. /* clear the direction flag and return
  99.  */
  100. ReverseScanExit:
  101. cld
  102.     }
  103.     if (0) return 0;        // suppress warning, optimized out
  104. }
  105. #endif
  106. /*
  107.  * ChrCmp -  Case sensitive character comparison for DBCS
  108.  * Assumes   w1, wMatch are characters to be compared
  109.  * Return    FALSE if they match, TRUE if no match
  110.  */
  111. __inline BOOL ChrCmpA_inline(WORD w1, WORD wMatch)
  112. {
  113.   /* Most of the time this won't match, so test it first for speed.
  114.    */
  115.   if (LOBYTE(w1) == LOBYTE(wMatch))
  116.     {
  117.       if (IsDBCSLeadByte(LOBYTE(w1)))
  118. {
  119.   return(w1 != wMatch);
  120. }
  121.       return FALSE;
  122.     }
  123.   return TRUE;
  124. }
  125. BOOL ChrCmpA(WORD w1, WORD wMatch)
  126. {
  127.   return ChrCmpA_inline(w1, wMatch);
  128. }
  129. #ifdef UNICODE
  130. __inline BOOL ChrCmpW_inline(WCHAR w1, WCHAR wMatch)
  131. {
  132.     return(!(w1 == wMatch));
  133. }
  134. #endif
  135. BOOL ChrCmpW(WCHAR w1, WCHAR wMatch)
  136. {
  137. #ifdef UNICODE
  138.    return ChrCmpW_inline(w1, wMatch);
  139. #else
  140.     SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  141.     return FALSE;
  142. #endif
  143. }
  144. /*
  145.  * ChrCmpI - Case insensitive character comparison for DBCS
  146.  * Assumes   w1, wMatch are characters to be compared;
  147.  *           HIBYTE of wMatch is 0 if not a DBC
  148.  * Return    FALSE if match, TRUE if not
  149.  */
  150. BOOL ChrCmpIA(WORD w1, WORD wMatch)
  151. {
  152.   char sz1[3], sz2[3];
  153.   if (IsDBCSLeadByte(sz1[0] = LOBYTE(w1)))
  154.     {
  155.       sz1[1] = HIBYTE(w1);
  156.       sz1[2] = '';
  157.     }
  158.   else
  159.       sz1[1] = '';
  160. #if defined(BIG_ENDIAN)
  161.   sz2[0] = LOBYTE(wMatch);
  162.   sz2[1] = HIBYTE(wMatch);
  163. #else
  164.   *(WORD FAR *)sz2 = wMatch;
  165. #endif
  166.   sz2[2] = '';
  167.   return lstrcmpiA(sz1, sz2);
  168. }
  169. BOOL ChrCmpIW(WCHAR w1, WCHAR wMatch)
  170. {
  171. #ifdef UNICODE
  172.   WCHAR sz1[2], sz2[2];
  173.   sz1[0] = w1;
  174.   sz1[1] = TEXT('');
  175.   sz2[0] = wMatch;
  176.   sz2[1] = TEXT('');
  177.   return lstrcmpiW(sz1, sz2);
  178. #else
  179.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  180.   return FALSE;
  181. #endif
  182. }
  183. LPWSTR StrCpyW(LPWSTR psz1, LPCWSTR psz2)
  184. {
  185.     LPWSTR psz = psz1;
  186.     do {
  187.         *psz1 = *psz2;
  188.         psz1++;
  189.     } while(*psz2++);
  190.     return psz;
  191. }
  192. LPWSTR StrCpyNW(LPWSTR psz1, LPCWSTR psz2, int cchMax)
  193. {
  194.     LPWSTR psz = psz1;
  195.     ASSERT(psz1);
  196.     ASSERT(psz2);
  197.     if (0 < cchMax)
  198.     {
  199.         // Leave room for the null terminator
  200.         while (0 < --cchMax)
  201.         {
  202.             if ( !(*psz1++ = *psz2++) )
  203.                 break;
  204.         }
  205.         if (0 == cchMax)
  206.             *psz1 = '';
  207.     }
  208.     return psz;
  209. }
  210. /*
  211.  * StrChr - Find first occurrence of character in string
  212.  * Assumes   lpStart points to start of null terminated string
  213.  *           wMatch  is the character to match
  214.  * returns ptr to the first occurrence of ch in str, NULL if not found.
  215.  */
  216. LPSTR FAR PASCAL StrChrA(LPCSTR lpStart, WORD wMatch)
  217. {
  218.   for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  219.     {
  220.       if (!ChrCmpA_inline(READNATIVEWORD(lpStart), wMatch))
  221.       {
  222.   return((LPSTR)lpStart);
  223.       }
  224.    }
  225.    return (NULL);
  226. }
  227. #ifdef ALIGNMENT_SCENARIO
  228. LPWSTR StrChrSlowW(const UNALIGNED WCHAR *lpStart, WCHAR wMatch)
  229. {
  230.     for ( ; *lpStart; lpStart++)
  231.     {
  232.       if (!ChrCmpW_inline(*lpStart, wMatch))
  233.         {
  234.             return((LPWSTR)lpStart);
  235.         }
  236.     }
  237. }
  238. #endif
  239. LPWSTR FAR PASCAL StrChrW(LPCWSTR lpStart, WCHAR wMatch)
  240. {
  241. #ifdef UNICODE
  242.     //
  243.     //  BUGBUG raymondc
  244.     //  Apparently, somebody is passing unaligned strings to StrChrW.
  245.     //  Find out who and make them stop.
  246.     //
  247.     ASSERT(!((ULONG_PTR)lpStart & 1)); // Assert alignedness
  248. #ifdef ALIGNMENT_SCENARIO
  249.     //
  250.     //  Since unaligned strings arrive so rarely, put the slow
  251.     //  version in a separate function so the common case stays
  252.     //  fast.  Believe it or not, we call StrChrW so often that
  253.     //  it is now a performance-sensitive function!
  254.     //
  255.     if ((ULONG_PTR)lpStart & 1)
  256.         return StrChrSlowW(lpStart, wMatch);
  257. #endif
  258.     for ( ; *lpStart; lpStart++)
  259.     {
  260.       if (!ChrCmpW_inline(*lpStart, wMatch))
  261.         {
  262.             return((LPWSTR)lpStart);
  263.         }
  264.     }
  265.   return (NULL);
  266. #else
  267.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  268.   return NULL;
  269. #endif
  270. }
  271. /*
  272.  * StrRChr - Find last occurrence of character in string
  273.  * Assumes   lpStart points to start of string
  274.  *           lpEnd   points to end of string (NOT included in search)
  275.  *           wMatch  is the character to match
  276.  * returns ptr to the last occurrence of ch in str, NULL if not found.
  277.  */
  278. LPSTR FAR PASCAL StrRChrA(LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch)
  279. {
  280.   LPCSTR lpFound = NULL;
  281.   if (!lpEnd)
  282.       lpEnd = lpStart + lstrlenA(lpStart);
  283.   for ( ; OFFSETOF(lpStart) < OFFSETOF(lpEnd); lpStart = AnsiNext(lpStart))
  284.     {
  285.       if (!ChrCmpA_inline(READNATIVEWORD(lpStart), wMatch))
  286.   lpFound = lpStart;
  287.     }
  288.   return ((LPSTR)lpFound);
  289. }
  290. LPWSTR FAR PASCAL StrRChrW(LPCWSTR lpStart, LPCWSTR lpEnd, WCHAR wMatch)
  291. {
  292. #ifdef UNICODE
  293.   LPCWSTR lpFound = NULL;
  294.   if (!lpEnd)
  295.       lpEnd = lpStart + lstrlenW(lpStart);
  296.   for ( ; lpStart < lpEnd; lpStart++)
  297.     {
  298.       if (!ChrCmpW_inline(*lpStart, wMatch))
  299.   lpFound = lpStart;
  300.     }
  301.   return ((LPWSTR)lpFound);
  302. #else
  303.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  304.   return NULL;
  305. #endif
  306. }
  307. /*
  308.  * StrRChrI - Find last occurrence of character in string, case insensitive
  309.  * Assumes   lpStart points to start of string
  310.  *           lpEnd   points to end of string (NOT included in search)
  311.  *           wMatch  is the character to match
  312.  * returns ptr to the last occurrence of ch in str, NULL if not found.
  313.  */
  314. LPSTR FAR PASCAL StrRChrIA(LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch)
  315. {
  316.   LPCSTR lpFound = NULL;
  317.   if (!lpEnd)
  318.       lpEnd = lpStart + lstrlenA(lpStart);
  319.   wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  320.   for ( ; OFFSETOF(lpStart) < OFFSETOF(lpEnd); lpStart = AnsiNext(lpStart))
  321.     {
  322.       if (!ChrCmpIA(READNATIVEWORD(lpStart), wMatch))
  323.           lpFound = lpStart;
  324.     }
  325.   return ((LPSTR)lpFound);
  326. }
  327. LPWSTR FAR PASCAL StrRChrIW(LPCWSTR lpStart, LPCWSTR lpEnd, WCHAR wMatch)
  328. {
  329. #ifdef UNICODE
  330.   LPCWSTR lpFound = NULL;
  331.   if (!lpEnd)
  332.       lpEnd = lpStart + lstrlenW(lpStart);
  333.   for ( ; lpStart < lpEnd; lpStart++)
  334.     {
  335.       if (!ChrCmpIW(*lpStart, wMatch))
  336.           lpFound = lpStart;
  337.     }
  338.   return ((LPWSTR)lpFound);
  339. #else
  340.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  341.   return NULL;
  342. #endif
  343. }
  344. // StrCSpn: return index to first char of lpStr that is present in lpSet.
  345. // Includes the NUL in the comparison; if no lpSet chars are found, returns
  346. // the index to the NUL in lpStr.
  347. // Just like CRT strcspn.
  348. //
  349. int FAR PASCAL StrCSpnA(LPCSTR lpStr, LPCSTR lpSet)
  350. {
  351. // nature of the beast: O(lpStr*lpSet) work
  352. LPCSTR lp = lpStr;
  353. if (!lpStr || !lpSet)
  354. return 0;
  355. while (*lp)
  356. {
  357.   if (StrChrA(lpSet, READNATIVEWORD(lp)))
  358. return (int)(lp-lpStr);
  359. lp = AnsiNext(lp);
  360. }
  361. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  362. }
  363. int FAR PASCAL StrCSpnW(LPCWSTR lpStr, LPCWSTR lpSet)
  364. {
  365. #ifdef UNICODE
  366. // nature of the beast: O(lpStr*lpSet) work
  367. LPCWSTR lp = lpStr;
  368. if (!lpStr || !lpSet)
  369. return 0;
  370. while (*lp)
  371. {
  372. if (StrChrW(lpSet, *lp))
  373. return (int)(lp-lpStr);
  374. lp++;
  375. }
  376. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  377. #else
  378.         SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  379. return -1;
  380. #endif
  381. }
  382. // StrCSpnI: case-insensitive version of StrCSpn.
  383. //
  384. int FAR PASCAL StrCSpnIA(LPCSTR lpStr, LPCSTR lpSet)
  385. {
  386.         // nature of the beast: O(lpStr*lpSet) work
  387.         LPCSTR lp = lpStr;
  388.         if (!lpStr || !lpSet)
  389.                 return 0;
  390.         while (*lp)
  391.         {
  392.                 if (StrChrIA(lpSet, READNATIVEWORD(lp)))
  393.                         return (int)(lp-lpStr);
  394.                 lp = AnsiNext(lp);
  395.         }
  396.         return (int)(lp-lpStr); // ==lstrlen(lpStr)
  397. }
  398. int FAR PASCAL StrCSpnIW(LPCWSTR lpStr, LPCWSTR lpSet)
  399. {
  400. #ifdef UNICODE
  401.         // nature of the beast: O(lpStr*lpSet) work
  402.         LPCWSTR lp = lpStr;
  403.         if (!lpStr || !lpSet)
  404.                 return 0;
  405.         while (*lp)
  406.         {
  407.                 if (StrChrIW(lpSet, *lp))
  408.                         return (int)(lp-lpStr);
  409.                 lp++;
  410.         }
  411.         return (int)(lp-lpStr); // ==lstrlen(lpStr)
  412. #else
  413.         SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  414.         return -1;
  415. #endif
  416. }
  417. /*
  418.  * StrCmpN      - Compare n bytes
  419.  *
  420.  * returns   See lstrcmp return values.
  421.  * BUGBUG, won't work if source strings are in ROM
  422.  */
  423. int FAR PASCAL StrCmpNA(LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
  424. {
  425.     char sz1[4];
  426.     char sz2[4];
  427.     LPCSTR lpszEnd = lpStr1 + nChar;
  428.     //DebugMsg(DM_TRACE, "StrCmpN: %s %s %d returns:", lpStr1, lpStr2, nChar);
  429.     for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1 = AnsiNext(lpStr1), lpStr2 = AnsiNext(lpStr2)) {
  430.         WORD wMatch;
  431.         wMatch = (WORD) (*lpStr2 | (*(lpStr2+1)<<8));
  432.         if (ChrCmpA_inline(READNATIVEWORD(lpStr1), wMatch)) {
  433.             int iRet;
  434.             (*(WORD FAR *)sz1) = READNATIVEWORD(lpStr1);
  435.             (*(WORD FAR *)sz2) = wMatch;
  436. #ifndef UNIX
  437.             *AnsiNext(sz1) = 0;
  438.             *AnsiNext(sz2) = 0;
  439. #else
  440.             *AnsiNext((LPWORD)sz1) = 0;
  441.             *AnsiNext((LPWORD)sz2) = 0;
  442. #endif
  443.             iRet = lstrcmpA(sz1, sz2);
  444.             //DebugMsg(DM_TRACE, ".................... %d", iRet);
  445.             return iRet;
  446.         }
  447.     }
  448.     //DebugMsg(DM_TRACE, ".................... 0");
  449.     return 0;
  450. }
  451. int FAR PASCAL StrCmpNW(LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar)
  452. {
  453. #ifdef UNICODE
  454.     WCHAR sz1[2];
  455.     WCHAR sz2[2];
  456.     int i;
  457.     LPCWSTR lpszEnd = lpStr1 + nChar;
  458.     //DebugMsg(DM_TRACE, "StrCmpN: %s %s %d returns:", lpStr1, lpStr2, nChar);
  459.     for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1++, lpStr2++) {
  460.         i = ChrCmpW_inline(*lpStr1, *lpStr2);
  461.         if (i) {
  462.             int iRet;
  463.             sz1[0] = *lpStr1;
  464.             sz2[0] = *lpStr2;
  465.             sz1[1] = TEXT('');
  466.             sz2[1] = TEXT('');
  467.             iRet = lstrcmpW(sz1, sz2);
  468.             //DebugMsg(DM_TRACE, ".................... %d", iRet);
  469.             return iRet;
  470.         }
  471.     }
  472.     //DebugMsg(DM_TRACE, ".................... 0");
  473.     return 0;
  474. #else
  475.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  476.   return -1;
  477. #endif
  478. }
  479. /*
  480.  * StrCmpNI     - Compare n bytes, case insensitive
  481.  *
  482.  * returns   See lstrcmpi return values.
  483.  */
  484.  #ifndef WINNT
  485. __inline BOOL IsAsciiA(char ch)
  486. {
  487.     return !(ch & 0x80);
  488. }
  489. __inline char Ascii_ToLowerA(char ch)
  490. {
  491.     return (ch >= 'A' && ch <= 'Z') ? (ch - 'A' + 'a') : ch;
  492. }
  493. #ifdef UNICODE
  494. __inline BOOL IsAsciiW(WCHAR ch)
  495. {
  496.     return ch < 128;
  497. }
  498. __inline WCHAR Ascii_ToLowerW(WCHAR ch)
  499. {
  500.     return (ch >= L'A' && ch <= L'Z') ? (ch - L'A' + L'a') : ch;
  501. }
  502. #endif
  503. int FAR PASCAL StrCmpNIA(LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
  504. {
  505.     int i;
  506.     LPCSTR lpszEnd = lpStr1 + nChar;
  507.     //DebugMsg(DM_TRACE, "StrCmpNI: %s %s %d returns:", lpStr1, lpStr2, nChar);
  508.     for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); (lpStr1 = AnsiNext(lpStr1)), (lpStr2 = AnsiNext(lpStr2))) {
  509.         WORD wMatch;
  510.         if (IsAsciiA(*lpStr1) && IsAsciiA(*lpStr2))
  511.         {
  512.             i = Ascii_ToLowerA(*lpStr1) - Ascii_ToLowerA(*lpStr2);
  513.         }
  514.         else
  515.         {
  516. #ifndef UNIX
  517.             wMatch = (UINT)(IsDBCSLeadByte(*lpStr2)) ? *(WORD FAR *)lpStr2 : (WORD)(BYTE)(*lpStr2);
  518. #else
  519.             wMatch = (UINT)(IsDBCSLeadByte(*lpStr2)) ? (*lpStr2 | (*(lpStr2+1)<<8)) : (WORD)(BYTE)(*lpStr2);
  520. #endif
  521.             i = ChrCmpIA(READNATIVEWORD(lpStr1), wMatch);
  522.         }
  523.         if (i) {
  524.             //DebugMsg(DM_TRACE, ".................... %d", i);
  525.             if (i < 0)
  526.             {
  527.                 return -1;
  528.             }
  529.             else
  530.             {
  531.                 return 1;
  532.             }
  533.         }
  534.     }
  535.     //DebugMsg(DM_TRACE, ".................... 0");
  536.     return 0;
  537. }
  538. int FAR PASCAL StrCmpNIW(LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar)
  539. {
  540. #ifdef UNICODE
  541.     int i;
  542.     LPCWSTR lpszEnd = lpStr1 + nChar;
  543.     //DebugMsg(DM_TRACE, "StrCmpNI: %s %s %d returns:", lpStr1, lpStr2, nChar);
  544.     for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1++, lpStr2++) {
  545.         if (IsAsciiW(*lpStr1) && IsAsciiW(*lpStr2))
  546.         {
  547.             i = Ascii_ToLowerW(*lpStr1) - Ascii_ToLowerW(*lpStr2);
  548.         }
  549.         else
  550.         {
  551.             i = ChrCmpIW(*lpStr1, *lpStr2);
  552.         }
  553.         if (i) {
  554.             //DebugMsg(DM_TRACE, ".................... %d", i);
  555.            if (i < 0)
  556.            {
  557.                return -1;
  558.            }
  559.            else
  560.            {
  561.                return 1;
  562.            }
  563.            return i;
  564.         }
  565.     }
  566.     //DebugMsg(DM_TRACE, ".................... 0");
  567.     return 0;
  568. #else
  569.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  570.   return -1;
  571. #endif
  572. }
  573. #else // WINNT
  574. int StrCmpNIA(LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
  575. {
  576.     int i;
  577.     
  578.     //  Win95 doesn't support NORM_STOP_ON_NULL
  579.     i = CompareStringA(GetThreadLocale(), NORM_IGNORECASE | NORM_STOP_ON_NULL, 
  580.                        lpStr1, nChar, lpStr2, nChar);
  581.     if (!i)
  582.     {
  583.         i = CompareStringA(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE | NORM_STOP_ON_NULL, 
  584.                              lpStr1, nChar, lpStr2, nChar);
  585.     }
  586.     return i - CSTR_EQUAL;    
  587. }
  588. int StrCmpNIW(LPCWSTR lpStr1, LPCWSTR lpStr2, int nChar)
  589. {
  590.     int i;
  591.     //  Win95 doesn't support NORM_STOP_ON_NULL
  592.     i = CompareStringW(GetThreadLocale(), NORM_IGNORECASE | NORM_STOP_ON_NULL, 
  593.                        lpStr1, nChar, lpStr2, nChar);
  594.     if (!i)
  595.     {
  596.         i = CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE | NORM_STOP_ON_NULL, 
  597.                              lpStr1, nChar, lpStr2, nChar);
  598.     }
  599.     return i - CSTR_EQUAL;    
  600. }
  601. #endif //   WINNT
  602. /*
  603.  * IntlStrEq
  604.  *
  605.  * returns TRUE if strings are equal, FALSE if not
  606.  */
  607. BOOL IntlStrEqWorkerA(BOOL fCaseSens, LPCSTR lpString1, LPCSTR lpString2, int nChar) {
  608.     int retval;
  609.     DWORD dwFlags = fCaseSens ? LOCALE_USE_CP_ACP : (NORM_IGNORECASE | LOCALE_USE_CP_ACP);
  610. #ifdef WINNT
  611.     //
  612.     // On NT we can tell CompareString to stop at a '' if one is found before nChar chars
  613.     //
  614.     dwFlags |= NORM_STOP_ON_NULL;
  615. #else
  616.     //
  617.     // On Win9x we have to do the check manually
  618.     //
  619.     if (nChar != -1) {
  620.         LPCSTR psz1, psz2;
  621.         int cch = 0;
  622.         psz1 = lpString1;
  623.         psz2 = lpString2;
  624.         while( *psz1 != '' && *psz2 != '' && cch < nChar) {
  625. #ifdef DBCS
  626.             psz1 = CharNextA(psz1);
  627.             psz2 = CharNextA(psz2);
  628.             cch = min(psz1 - lpString1, psz2 - lpString2);
  629. #else
  630.             psz1++;
  631.             psz2++;
  632.             cch++;
  633. #endif
  634.         }
  635.         // add one in for terminating ''
  636.         cch++;
  637.         if (cch < nChar) {
  638.             nChar = cch;
  639.         }
  640.     }
  641. #endif
  642.     retval = CompareStringA( GetThreadLocale(),
  643.                              dwFlags,
  644.                              lpString1,
  645.                              nChar,
  646.                              lpString2,
  647.                              nChar );
  648.     if (retval == 0)
  649.     {
  650.         //
  651.         // The caller is not expecting failure.  Try the system
  652.         // default locale id.
  653.         //
  654.         retval = CompareStringA( GetSystemDefaultLCID(),
  655.                                  dwFlags,
  656.                                  lpString1,
  657.                                  nChar,
  658.                                  lpString2,
  659.                                  nChar );
  660.     }
  661.     if (retval == 0)
  662.     {
  663.         if (lpString1 && lpString2)
  664.         {
  665.             //
  666.             // The caller is not expecting failure.  We've never had a
  667.             // failure indicator before.  We'll do a best guess by calling
  668.             // the C runtimes to do a non-locale sensitive compare.
  669.             //
  670.             if (fCaseSens)
  671.                 retval = StrCmpNA(lpString1, lpString2, nChar) + 2;
  672.             else {
  673.                 retval = StrCmpNIA(lpString1, lpString2, nChar) + 2;
  674.             }
  675.         }
  676.         else
  677.         {
  678.             retval = 2;
  679.         }
  680.     }
  681.     return (retval == 2);
  682. }
  683. BOOL IntlStrEqWorkerW(BOOL fCaseSens, LPCWSTR lpString1, LPCWSTR lpString2, int nChar) {
  684. #ifdef UNICODE
  685.     int retval;
  686.     DWORD dwFlags = fCaseSens ? 0 : NORM_IGNORECASE;
  687. #ifdef WINNT
  688.     //
  689.     // On NT we can tell CompareString to stop at a '' if one is found before nChar chars
  690.     //
  691.     dwFlags |= NORM_STOP_ON_NULL;
  692. #else
  693.     //
  694.     // On Win9x we have to do the check manually
  695.     //
  696.     if (nChar != -1) {
  697.         LPCWSTR psz1, psz2;
  698.         int cch = 0;
  699.         psz1 = lpString1;
  700.         psz2 = lpString2;
  701.         while( *psz1 != TEXT('') && *psz2 != TEXT('') && cch < nChar) {
  702.             psz1++;
  703.             psz2++;
  704.             cch++;
  705.         }
  706.         // add one in for terminating ''
  707.         cch++;
  708.         if (cch < nChar) {
  709.             nChar = cch;
  710.         }
  711.     }
  712. #endif
  713.     retval = CompareStringW( GetThreadLocale(),
  714.                              dwFlags,
  715.                              lpString1,
  716.                              nChar,
  717.                              lpString2,
  718.                              nChar );
  719.     if (retval == 0)
  720.     {
  721.         //
  722.         // The caller is not expecting failure.  Try the system
  723.         // default locale id.
  724.         //
  725.         retval = CompareStringW( GetSystemDefaultLCID(),
  726.                                  dwFlags,
  727.                                  lpString1,
  728.                                  nChar,
  729.                                  lpString2,
  730.                                  nChar );
  731.     }
  732.     if (retval == 0)
  733.     {
  734.         if (lpString1 && lpString2)
  735.         {
  736.             //
  737.             // The caller is not expecting failure.  We've never had a
  738.             // failure indicator before.  We'll do a best guess by calling
  739.             // the C runtimes to do a non-locale sensitive compare.
  740.             //
  741.             if (fCaseSens)
  742.                 retval = StrCmpNW(lpString1, lpString2, nChar) + 2;
  743.             else {
  744.                 retval = StrCmpNIW(lpString1, lpString2, nChar) + 2;
  745.             }
  746.         }
  747.         else
  748.         {
  749.             retval = 2;
  750.         }
  751.     }
  752.     return (retval == 2);
  753. #else
  754.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  755.   return FALSE;
  756. #endif
  757. }
  758. /*
  759.  * StrRStrI      - Search for last occurrence of a substring
  760.  *
  761.  * Assumes   lpSource points to the null terminated source string
  762.  *           lpLast points to where to search from in the source string
  763.  *           lpLast is not included in the search
  764.  *           lpSrch points to string to search for
  765.  * returns   last occurrence of string if successful; NULL otherwise
  766.  */
  767. LPSTR FAR PASCAL StrRStrIA(LPCSTR lpSource, LPCSTR lpLast, LPCSTR lpSrch)
  768. {
  769.     LPCSTR lpFound = NULL;
  770.     LPSTR lpEnd;
  771.     char cHold;
  772.     if (!lpLast)
  773.         lpLast = lpSource + lstrlenA(lpSource);
  774.     if (lpSource >= lpLast || *lpSrch == 0)
  775.         return NULL;
  776.     lpEnd = lstrfns_StrEndNA(lpLast, (UINT)(lstrlenA(lpSrch)-1));
  777.     cHold = *lpEnd;
  778.     *lpEnd = 0;
  779.     while ((lpSource = StrStrIA(lpSource, lpSrch))!=0 &&
  780.           OFFSETOF(lpSource) < OFFSETOF(lpLast))
  781.     {
  782.         lpFound = lpSource;
  783.         lpSource = AnsiNext(lpSource);
  784.     }
  785.     *lpEnd = cHold;
  786.     return((LPSTR)lpFound);
  787. }
  788. LPWSTR FAR PASCAL StrRStrIW(LPCWSTR lpSource, LPCWSTR lpLast, LPCWSTR lpSrch)
  789. {
  790. #ifdef UNICODE
  791.     LPCWSTR lpFound = NULL;
  792.     LPWSTR lpEnd;
  793.     WCHAR cHold;
  794.     if (!lpLast)
  795.         lpLast = lpSource + lstrlenW(lpSource);
  796.     if (lpSource >= lpLast || *lpSrch == 0)
  797.         return NULL;
  798.     lpEnd = lstrfns_StrEndNW(lpLast, (UINT)(lstrlenW(lpSrch)-1));
  799.     cHold = *lpEnd;
  800.     *lpEnd = 0;
  801.     while ((lpSource = StrStrIW(lpSource, lpSrch))!=0 &&
  802.           lpSource < lpLast)
  803.     {
  804.         lpFound = lpSource;
  805.         lpSource++;
  806.     }
  807.     *lpEnd = cHold;
  808.     return((LPWSTR)lpFound);
  809. #else
  810.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  811.   return NULL;
  812. #endif
  813. }
  814. /*
  815.  * StrStr      - Search for first occurrence of a substring
  816.  *
  817.  * Assumes   lpSource points to source string
  818.  *           lpSrch points to string to search for
  819.  * returns   first occurrence of string if successful; NULL otherwise
  820.  */
  821. LPSTR FAR PASCAL StrStrA(LPCSTR lpFirst, LPCSTR lpSrch)
  822. {
  823.   UINT uLen;
  824.   WORD wMatch;
  825.   uLen = (UINT)lstrlenA(lpSrch);
  826.   wMatch = READNATIVEWORD(lpSrch);
  827.   for ( ; (lpFirst=StrChrA(lpFirst, wMatch))!=0 && !IntlStrEqNA(lpFirst, lpSrch, uLen);
  828.         lpFirst=AnsiNext(lpFirst))
  829.     continue; /* continue until we hit the end of the string or get a match */
  830.   return((LPSTR)lpFirst);
  831. }
  832. LPWSTR FAR PASCAL StrStrW(LPCWSTR lpFirst, LPCWSTR lpSrch)
  833. {
  834. #ifdef UNICODE
  835.   UINT uLen;
  836.   WCHAR wMatch;
  837.   uLen = (UINT)lstrlenW(lpSrch);
  838.   wMatch = *lpSrch;
  839.   for ( ; (lpFirst=StrChrW(lpFirst, wMatch))!=0 && !IntlStrEqNW(lpFirst, lpSrch, uLen);
  840.         lpFirst++)
  841.     continue; /* continue until we hit the end of the string or get a match */
  842.   return((LPWSTR)lpFirst);
  843. #else
  844.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  845.   return NULL;
  846. #endif
  847. }
  848. /*
  849.  * StrChrI - Find first occurrence of character in string, case insensitive
  850.  * Assumes   lpStart points to start of null terminated string
  851.  *           wMatch  is the character to match
  852.  * returns ptr to the first occurrence of ch in str, NULL if not found.
  853.  */
  854. LPSTR FAR PASCAL StrChrIA(LPCSTR lpStart, WORD wMatch)
  855. {
  856.   wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  857.   for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  858.     {
  859.       if (!ChrCmpIA(READNATIVEWORD(lpStart), wMatch))
  860.   return((LPSTR)lpStart);
  861.     }
  862.   return (NULL);
  863. }
  864. LPWSTR FAR PASCAL StrChrIW(LPCWSTR lpStart, WCHAR wMatch)
  865. {
  866.   for ( ; *lpStart; lpStart++)
  867.     {
  868.       if (!ChrCmpIW(*lpStart, wMatch))
  869.   return((LPWSTR)lpStart);
  870.     }
  871.   return (NULL);
  872. }
  873. /*
  874.  * StrStrI   - Search for first occurrence of a substring, case insensitive
  875.  *
  876.  * Assumes   lpFirst points to source string
  877.  *           lpSrch points to string to search for
  878.  * returns   first occurrence of string if successful; NULL otherwise
  879.  */
  880. LPSTR FAR PASCAL StrStrIA(LPCSTR lpFirst, LPCSTR lpSrch)
  881. {
  882.   UINT uLen;
  883.   WORD wMatch;
  884.   uLen = (UINT)lstrlenA(lpSrch);
  885.   wMatch = READNATIVEWORD(lpSrch);
  886.   for ( ; (lpFirst = StrChrIA(lpFirst, wMatch)) != 0 && !IntlStrEqNIA(lpFirst, lpSrch, uLen);
  887.         lpFirst=AnsiNext(lpFirst))
  888.       continue; /* continue until we hit the end of the string or get a match */
  889.   return((LPSTR)lpFirst);
  890. }
  891. LPWSTR FAR PASCAL StrStrIW(LPCWSTR lpFirst, LPCWSTR lpSrch)
  892. {
  893. #ifdef UNICODE
  894.   UINT uLen;
  895.   WCHAR wMatch;
  896.   uLen = (UINT)lstrlenW(lpSrch);
  897.   wMatch = *lpSrch;
  898.   for ( ; (lpFirst = StrChrIW(lpFirst, wMatch)) != 0 && !IntlStrEqNIW(lpFirst, lpSrch, uLen);
  899.         lpFirst++)
  900.       continue; /* continue until we hit the end of the string or get a match */
  901.   return((LPWSTR)lpFirst);
  902. #else
  903.   SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
  904.   return NULL;
  905. #endif
  906. }
  907. #ifndef UNICODE
  908. // TruncateString - bugbug: the same logic in shdocvw
  909. //
  910. // purpose: cut a string at the given length in dbcs safe manner
  911. //          the string may be truncated at cch-1 if the sz[cch] points
  912. //          to a lead byte that would result in cutting in the middle
  913. //          of double byte character.
  914. //          It is caller's responsibility to reserve enough buffer for
  915. //          sz so we can put sz[cch]=0 safely.
  916. //
  917. //          *Note this logic is not much perf hit when called with sbcs
  918. //          string, as it just bails out at the tail character always.
  919. //
  920. void  TruncateString(char *sz, int cchBufferSize)
  921. {
  922.     int cch = cchBufferSize - 1;
  923.     LPSTR psz = &sz[cch];
  924.     
  925.     if (!sz || cchBufferSize <= 0) return;
  926.     
  927.     while (psz > sz)
  928.     {
  929.         psz--;
  930.         if (!IsDBCSLeadByte(*psz))
  931.         {
  932.             // Found non-leadbyte for the first time.
  933.             // This is either a trail byte of double byte char
  934.             // or a single byte character we've first seen.
  935.             // Thus, the next pointer must be at either of a leadbyte
  936.             // or &sz[cch]
  937.             psz++;
  938.             break;
  939.         }
  940.     }
  941.     if (((&sz[cch] - psz) & 1) && cch > 0)
  942.     {
  943.         // we're truncating the string in the middle of dbcs
  944.         cch--;
  945.     }
  946.     sz[cch] = '';
  947.     return;
  948. }
  949. #endif