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

Windows Kernel

Development Platform:

Visual C++

  1. //============================================================================
  2. //
  3. // DBCS aware string routines...
  4. //
  5. //
  6. //============================================================================
  7. #include "ctlspriv.h"
  8. // WARNING: all of these APIs do not setup DS, so you can not access
  9. // any data in the default data seg of this DLL.
  10. //
  11. // do not create any global variables... talk to chrisg if you don't
  12. // understand thid
  13. #ifdef DBCS
  14. #define FASTCALL PASCAL
  15. #else
  16. #define FASTCALL _fastcall
  17. #endif
  18. /*
  19.  * StrEndN - Find the end of a string, but no more than n bytes
  20.  * Assumes   lpStart points to start of null terminated string
  21.  *           nBufSize is the maximum length
  22.  * returns ptr to just after the last byte to be included
  23.  */
  24. LPSTR NEAR FASTCALL lstrfns_StrEndN(LPCSTR lpStart, int nBufSize)
  25. {
  26.   LPCSTR lpEnd;
  27.   for (lpEnd = lpStart + nBufSize; *lpStart && OFFSETOF(lpStart) < OFFSETOF(lpEnd);
  28. lpStart = AnsiNext(lpStart))
  29.     continue;   /* just getting to the end of the string */
  30.   if (OFFSETOF(lpStart) > OFFSETOF(lpEnd))
  31.     {
  32.       /* We can only get here if the last byte before lpEnd was a lead byte
  33.        */
  34.       lpStart -= 2;
  35.     }
  36.   return((LPSTR)lpStart);
  37. }
  38. // REVIEW WIN32 HACK - Convert to 32bit asm.
  39. #ifndef WIN32
  40. /*
  41.  * ReverseScan - Find last occurrence of a byte in a string
  42.  * Assumes   lpSource points to first byte to check (end of the string)
  43.  *           uLen is the number of bytes to check
  44.  *           bMatch is the byte to match
  45.  * returns ptr to the last occurrence of ch in str, NULL if not found.
  46.  */
  47. LPSTR NEAR PASCAL ReverseScan(LPCSTR lpSource, UINT uLen, BYTE bMatch)
  48. {
  49.   _asm
  50.     {
  51. /* Load count */
  52. mov cx,uLen
  53. jcxz ReverseScanFail    ; count is zero, return failure.
  54. /* Load up es:di, ax */
  55. les di,lpSource
  56. mov al,bMatch
  57. /* Set the direction flag based on bBackward
  58.  * Perform the search; return 0 if we reached the end of the string
  59.  * otherwise, return es:di+1
  60.  */
  61. std
  62. repne scasb
  63. jne ReverseScanFail     ; check result of last compare.
  64. inc di
  65. mov dx,es
  66. mov ax,di
  67. jmp ReverseScanExit
  68. ReverseScanFail:
  69. xor ax,ax
  70. xor dx,dx
  71. /* clear the direction flag and return
  72.  */
  73. ReverseScanExit:
  74. cld
  75.     }
  76.     if (0) return 0;     // suppress warning, optimized out
  77. }
  78. #endif
  79. /*
  80.  * ChrCmp -  Case sensitive character comparison for DBCS
  81.  * Assumes   w1, wMatch are characters to be compared
  82.  * Return    FALSE if they match, TRUE if no match
  83.  */
  84. BOOL NEAR FASTCALL ChrCmp(WORD w1, WORD wMatch)
  85. {
  86.   /* Most of the time this won't match, so test it first for speed.
  87.    */
  88.   if (LOBYTE(w1) == LOBYTE(wMatch))
  89.     {
  90.       if (IsDBCSLeadByte(LOBYTE(w1)))
  91.         {
  92.           return(w1 != wMatch);
  93.         }
  94.       return FALSE;
  95.     }
  96.   return TRUE;
  97. }
  98. /*
  99.  * ChrCmpI - Case insensitive character comparison for DBCS
  100.  * Assumes   w1, wMatch are characters to be compared;
  101.  *           HIBYTE of wMatch is 0 if not a DBC
  102.  * Return    FALSE if match, TRUE if not
  103.  */
  104. BOOL NEAR FASTCALL ChrCmpI(WORD w1, WORD wMatch)
  105. {
  106.   char sz1[3], sz2[3];
  107.   if (IsDBCSLeadByte(sz1[0] = LOBYTE(w1)))
  108.     {
  109.       sz1[1] = HIBYTE(w1);
  110.       sz1[2] = '';
  111.     }
  112.   else
  113.       sz1[1] = '';
  114.   *(WORD FAR *)sz2 = wMatch;
  115.   sz2[2] = '';
  116.   return lstrcmpi(sz1, sz2);
  117. }
  118. /*
  119.  * StrChr - Find first occurrence of character in string
  120.  * Assumes   lpStart points to start of null terminated string
  121.  *           wMatch  is the character to match
  122.  * returns ptr to the first occurrence of ch in str, NULL if not found.
  123.  */
  124. LPSTR FAR PASCAL StrChr(LPCSTR lpStart, WORD wMatch)
  125. {
  126.   for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  127.     {
  128.       if (!ChrCmp(*(WORD FAR *)lpStart, wMatch))
  129.           return((LPSTR)lpStart);
  130.     }
  131.   return (NULL);
  132. }
  133. /*
  134.  * StrRChr - Find last occurrence of character in string
  135.  * Assumes   lpStart points to start of string
  136.  *           lpEnd   points to end of string (NOT included in search)
  137.  *           wMatch  is the character to match
  138.  * returns ptr to the last occurrence of ch in str, NULL if not found.
  139.  */
  140. LPSTR FAR PASCAL StrRChr(LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch)
  141. {
  142.   LPCSTR lpFound = NULL;
  143.   if (!lpEnd)
  144.       lpEnd = lpStart + lstrlen(lpStart);
  145.   for ( ; OFFSETOF(lpStart) < OFFSETOF(lpEnd); lpStart = AnsiNext(lpStart))
  146.     {
  147.       if (!ChrCmp(*(WORD FAR *)lpStart, wMatch))
  148.           lpFound = lpStart;
  149.     }
  150.   return ((LPSTR)lpFound);
  151. }
  152. /*
  153.  * StrChrI - Find first occurrence of character in string, case insensitive
  154.  * Assumes   lpStart points to start of null terminated string
  155.  *           wMatch  is the character to match
  156.  * returns ptr to the first occurrence of ch in str, NULL if not found.
  157.  */
  158. LPSTR FAR PASCAL StrChrI(LPCSTR lpStart, WORD wMatch)
  159. {
  160.   wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  161.   for ( ; *lpStart; lpStart = AnsiNext(lpStart))
  162.     {
  163.       if (!ChrCmpI(*(WORD FAR *)lpStart, wMatch))
  164.           return((LPSTR)lpStart);
  165.     }
  166.   return (NULL);
  167. }
  168. /*
  169.  * StrRChrI - Find last occurrence of character in string, case insensitive
  170.  * Assumes   lpStart points to start of string
  171.  *           lpEnd   points to end of string (NOT included in search)
  172.  *           wMatch  is the character to match
  173.  * returns ptr to the last occurrence of ch in str, NULL if not found.
  174.  */
  175. LPSTR FAR PASCAL StrRChrI(LPCSTR lpStart, LPCSTR lpEnd, WORD wMatch)
  176. {
  177.   LPCSTR lpFound = NULL;
  178.   if (!lpEnd)
  179.       lpEnd = lpStart + lstrlen(lpStart);
  180.   wMatch = (UINT)(IsDBCSLeadByte(LOBYTE(wMatch)) ? wMatch : LOBYTE(wMatch));
  181.   for ( ; OFFSETOF(lpStart) < OFFSETOF(lpEnd); lpStart = AnsiNext(lpStart))
  182.     {
  183.       if (!ChrCmpI(*(WORD FAR *)lpStart, wMatch))
  184.           lpFound = lpStart;
  185.     }
  186.   return ((LPSTR)lpFound);
  187. }
  188. // StrCSpn: return index to first char of lpStr that is present in lpSet.
  189. // Includes the NUL in the comparison; if no lpSet chars are found, returns
  190. // the index to the NUL in lpStr.
  191. // Just like CRT strcspn.
  192. //
  193. int FAR PASCAL StrCSpn(LPCSTR lpStr, LPCSTR lpSet)
  194. {
  195. // nature of the beast: O(lpStr*lpSet) work
  196. LPCSTR lp = lpStr;
  197. if (!lpStr || !lpSet)
  198. return 0;
  199. while (*lp)
  200. {
  201. if (StrChr(lpSet, *(WORD FAR *)lp))
  202. return (int)(lp-lpStr);
  203. lp = AnsiNext(lp);
  204. }
  205. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  206. }
  207. // StrCSpnI: case-insensitive version of StrCSpn.
  208. //
  209. int FAR PASCAL StrCSpnI(LPCSTR lpStr, LPCSTR lpSet)
  210. {
  211. // nature of the beast: O(lpStr*lpSet) work
  212. LPCSTR lp = lpStr;
  213. if (!lpStr || !lpSet)
  214. return 0;
  215. while (*lp)
  216. {
  217. if (StrChrI(lpSet, *(WORD FAR *)lp))
  218. return (int)(lp-lpStr);
  219. lp = AnsiNext(lp);
  220. }
  221. return (int)(lp-lpStr); // ==lstrlen(lpStr)
  222. }
  223. /*
  224.  * StrCmpN      - Compare n bytes
  225.  *
  226.  * returns   See lstrcmp return values.
  227.  * BUGBUG, won't work if source strings are in ROM
  228.  */
  229. int FAR PASCAL StrCmpN(LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
  230. {
  231.     TCHAR sz1[4]; 
  232.     TCHAR sz2[4];
  233.     int i;
  234.     LPSTR lpszEnd = (LPSTR)(((LPBYTE)lpStr1) + nChar);
  235.     //DebugMsg(DM_TRACE, "StrCmpN: %s %s %d returns:", lpStr1, lpStr2, nChar);
  236.     
  237.     for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); lpStr1 = AnsiNext(lpStr1), lpStr2 = AnsiNext(lpStr2)) {
  238.         WORD wMatch;
  239.         wMatch = (UINT)(IsDBCSLeadByte(*lpStr2)) ? *(WORD FAR *)lpStr2 : (WORD)(BYTE)(*lpStr2);
  240.         i = ChrCmp(*(WORD FAR *)lpStr1, wMatch);
  241.         if (i) {
  242.             int iRet;
  243.             
  244.             (*(WORD FAR *)sz1) = *(WORD FAR *)lpStr1;
  245.             (*(WORD FAR *)sz2) = *(WORD FAR *)lpStr2;
  246.             *AnsiNext(sz1) = 0;
  247.             *AnsiNext(sz2) = 0;
  248.             iRet = lstrcmp(sz1, sz2);
  249.             //DebugMsg(DM_TRACE, ".................... %d", iRet);
  250.             return iRet;
  251.         }
  252.     }
  253.     
  254.     //DebugMsg(DM_TRACE, ".................... 0");
  255.     return 0;
  256. }
  257. /*
  258.  * StrCmpNI     - Compare n bytes, case insensitive
  259.  *
  260.  * returns   See lstrcmpi return values.
  261.  */
  262. int FAR PASCAL StrCmpNI(LPCSTR lpStr1, LPCSTR lpStr2, int nChar)
  263. {
  264.     int i;
  265.     LPSTR lpszEnd = (LPSTR)(((LPBYTE)lpStr1) + nChar);
  266.     //DebugMsg(DM_TRACE, "StrCmpNI: %s %s %d returns:", lpStr1, lpStr2, nChar);
  267.     for ( ; (lpszEnd > lpStr1) && (*lpStr1 || *lpStr2); (lpStr1 = AnsiNext(lpStr1)), (lpStr2 = AnsiNext(lpStr2))) {
  268.         WORD wMatch;
  269.         wMatch = (UINT)(IsDBCSLeadByte(*lpStr2)) ? *(WORD FAR *)lpStr2 : (WORD)(BYTE)(*lpStr2);
  270.         i = ChrCmpI(*(WORD FAR *)lpStr1, wMatch);
  271.         if (i) {
  272.             //DebugMsg(DM_TRACE, ".................... %d", i);
  273.             return i;
  274.         }
  275.     }
  276.     //DebugMsg(DM_TRACE, ".................... 0");
  277.     return 0;
  278. }
  279. // REVIEW WIN32 HACK - Cut a dependancy on ReverseScan (it's in asm).
  280. #ifndef WIN32
  281. /*
  282.  * StrRStr      - Search for last occurrence of a substring
  283.  *
  284.  * Assumes   lpSource points to the null terminated source string
  285.  *           lpLast points to where to search from in the source string
  286.  *           lpLast is not included in the search
  287.  *           lpSrch points to string to search for
  288.  * returns   last occurrence of string if successful; NULL otherwise
  289.  */
  290. LPSTR FAR PASCAL StrRStr(LPCSTR lpSource, LPCSTR lpLast, LPCSTR lpSrch)
  291. {
  292.   UINT uLen;
  293.   BYTE bMatch;
  294.   uLen = (UINT)lstrlen(lpSrch);
  295.   bMatch = *lpSrch;
  296.   if (!lpLast)
  297.       lpLast = lpSource + lstrlen(lpSource);
  298.   for ( ; ; )
  299.     {
  300.       /* Return NULL if we hit the exact beginning of the string
  301.        */
  302.       if (lpLast == lpSource)
  303.   return(NULL);
  304.       --lpLast;
  305.       /* Break if we hit the beginning of the string
  306.        */
  307.       if ((lpLast=ReverseScan(lpLast, (UINT)(OFFSETOF(lpLast)-OFFSETOF(lpSource)+1),
  308.     bMatch)) == 0)
  309.   break;
  310.       /* Break if we found the string, and its first byte is not a tail byte
  311.        */
  312.       if (!StrCmpN(lpLast, lpSrch, uLen) &&
  313.     (lpLast==lstrfns_StrEndN(lpSource, (int)(OFFSETOF(lpLast)-OFFSETOF(lpSource)))))
  314.   break;
  315.     }
  316.   return((LPSTR)lpLast);
  317. }
  318. #endif
  319. /*
  320.  * StrRStrI      - Search for last occurrence of a substring
  321.  *
  322.  * Assumes   lpSource points to the null terminated source string
  323.  *           lpLast points to where to search from in the source string
  324.  *           lpLast is not included in the search
  325.  *           lpSrch points to string to search for
  326.  * returns   last occurrence of string if successful; NULL otherwise
  327.  */
  328. LPSTR FAR PASCAL StrRStrI(LPCSTR lpSource, LPCSTR lpLast, LPCSTR lpSrch)
  329. {
  330.     LPCSTR lpFound = NULL;
  331.     LPSTR lpEnd;
  332.     char cHold;
  333.     if (!lpLast)
  334.         lpLast = lpSource + lstrlen(lpSource);
  335.     if (lpSource >= lpLast || *lpSrch == 0)
  336.         return NULL;
  337.     lpEnd = lstrfns_StrEndN(lpLast, (UINT)(lstrlen(lpSrch)-1));
  338.     cHold = *lpEnd;
  339.     *lpEnd = 0;
  340.     while ((lpSource = StrStrI(lpSource, lpSrch))!=0 &&
  341.           OFFSETOF(lpSource) < OFFSETOF(lpLast))
  342.     {
  343.         lpFound = lpSource;
  344.         lpSource = AnsiNext(lpSource);
  345.     }
  346.     *lpEnd = cHold;
  347.     return((LPSTR)lpFound);
  348. }
  349. /*
  350.  * StrStr      - Search for first occurrence of a substring
  351.  *
  352.  * Assumes   lpSource points to source string
  353.  *           lpSrch points to string to search for
  354.  * returns   first occurrence of string if successful; NULL otherwise
  355.  */
  356. LPSTR FAR PASCAL StrStr(LPCSTR lpFirst, LPCSTR lpSrch)
  357. {
  358.   UINT uLen;
  359.   WORD wMatch;
  360.   uLen = (UINT)lstrlen(lpSrch);
  361.   wMatch = *(WORD FAR *)lpSrch;
  362.   for ( ; (lpFirst=StrChr(lpFirst, wMatch))!=0 && StrCmpN(lpFirst, lpSrch, uLen);
  363. lpFirst=AnsiNext(lpFirst))
  364.     continue; /* continue until we hit the end of the string or get a match */
  365.   return((LPSTR)lpFirst);
  366. }
  367. /*
  368.  * StrStrI   - Search for first occurrence of a substring, case insensitive
  369.  *
  370.  * Assumes   lpFirst points to source string
  371.  *           lpSrch points to string to search for
  372.  * returns   first occurrence of string if successful; NULL otherwise
  373.  */
  374. LPSTR FAR PASCAL StrStrI(LPCSTR lpFirst, LPCSTR lpSrch)
  375. {
  376.   UINT uLen;
  377.   WORD wMatch;
  378.   uLen = (UINT)lstrlen(lpSrch);
  379.   wMatch = *(WORD FAR *)lpSrch;
  380.   for ( ; (lpFirst = StrChrI(lpFirst, wMatch)) != 0 && StrCmpNI(lpFirst, lpSrch, uLen);
  381. lpFirst=AnsiNext(lpFirst))
  382.       continue; /* continue until we hit the end of the string or get a match */
  383.   return((LPSTR)lpFirst);
  384. }