2 * String manipulation functions
4 * Copyright 1998 Eric Kohl
5 * 1998 Juergen Schmied <j.schmied@metronet.de>
6 * 2000 Eric Kohl for CodeWeavers
7 * Copyright 2002 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
26 #include "wine/port.h"
30 #include <stdlib.h> /* atoi */
37 #include "wine/unicode.h"
39 #include "wine/debug.h"
41 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
43 /*************************************************************************
44 * COMCTL32_ChrCmpHelperA
46 * Internal helper for ChrCmpA/COMCTL32_ChrCmpIA.
49 * Both this function and its Unicode counterpart are very inneficient. To
50 * fix this, CompareString must be completely implemented and optimised
51 * first. Then the core character test can be taken out of that function and
52 * placed here, so that it need never be called at all. Until then, do not
53 * attempt to optimise this code unless you are willing to test that it
54 * still performs correctly.
56 static BOOL COMCTL32_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
58 char str1[3], str2[3];
60 str1[0] = LOBYTE(ch1);
61 if (IsDBCSLeadByte(str1[0]))
63 str1[1] = HIBYTE(ch1);
69 str2[0] = LOBYTE(ch2);
70 if (IsDBCSLeadByte(str2[0]))
72 str2[1] = HIBYTE(ch2);
78 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
81 /*************************************************************************
82 * COMCTL32_ChrCmpHelperW
84 * Internal helper for COMCTL32_ChrCmpW/ChrCmpIW.
86 static BOOL COMCTL32_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
88 WCHAR str1[2], str2[2];
94 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
97 /*************************************************************************
98 * COMCTL32_ChrCmpA (internal)
100 * Internal helper function.
102 static BOOL COMCTL32_ChrCmpA(WORD ch1, WORD ch2)
104 return COMCTL32_ChrCmpHelperA(ch1, ch2, 0);
107 /*************************************************************************
108 * COMCTL32_ChrCmpIA (internal)
110 * Compare two characters, ignoring case.
113 * ch1 [I] First character to compare
114 * ch2 [I] Second character to compare
117 * FALSE, if the characters are equal.
118 * Non-zero otherwise.
120 static BOOL COMCTL32_ChrCmpIA(WORD ch1, WORD ch2)
122 TRACE("(%d,%d)\n", ch1, ch2);
124 return COMCTL32_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
127 /*************************************************************************
130 * Internal helper function.
132 static BOOL COMCTL32_ChrCmpW(WCHAR ch1, WCHAR ch2)
134 return COMCTL32_ChrCmpHelperW(ch1, ch2, 0);
137 /*************************************************************************
140 * Internal helper function.
142 static BOOL COMCTL32_ChrCmpIW(WCHAR ch1, WCHAR ch2)
144 return COMCTL32_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
147 /**************************************************************************
148 * StrChrA [COMCTL32.350]
150 * Find a given character in a string.
153 * lpszStr [I] String to search in.
154 * ch [I] Character to search for.
157 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
159 * Failure: NULL, if any arguments are invalid.
161 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
163 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
169 if (!COMCTL32_ChrCmpA(*lpszStr, ch))
170 return (LPSTR)lpszStr;
171 lpszStr = CharNextA(lpszStr);
177 /**************************************************************************
178 * StrCmpNIA [COMCTL32.353]
180 * Compare two strings, up to a maximum length, ignoring case.
183 * lpszStr [I] First string to compare
184 * lpszComp [I] Second string to compare
185 * iLen [I] Maximum number of chars to compare.
188 * An integer less than, equal to or greater than 0, indicating that
189 * lpszStr is less than, the same, or greater than lpszComp.
191 INT WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
195 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
197 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
198 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
201 /*************************************************************************
202 * StrCmpNIW [COMCTL32.361]
206 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
210 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
212 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
213 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
216 /*************************************************************************
217 * COMCTL32_StrStrHelperA
219 * Internal implementation of StrStrA/StrStrIA
221 static LPSTR COMCTL32_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
222 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
226 if (!lpszStr || !lpszSearch || !*lpszSearch)
229 iLen = strlen(lpszSearch);
233 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
234 return (LPSTR)lpszStr;
235 lpszStr = CharNextA(lpszStr);
240 /*************************************************************************
241 * COMCTL32_StrStrHelperW
243 * Internal implementation of StrStrW/StrStrIW
245 static LPWSTR COMCTL32_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
246 INT (WINAPI *pStrCmpFn)(LPCWSTR,LPCWSTR,INT))
250 if (!lpszStr || !lpszSearch || !*lpszSearch)
253 iLen = strlenW(lpszSearch);
257 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
258 return (LPWSTR)lpszStr;
259 lpszStr = CharNextW(lpszStr);
264 /**************************************************************************
265 * StrStrIA [COMCTL32.355]
267 * Find a substring within a string, ignoring case.
270 * lpszStr [I] String to search in
271 * lpszSearch [I] String to look for
274 * The start of lpszSearch within lpszStr, or NULL if not found.
276 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
278 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
280 return COMCTL32_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
283 /**************************************************************************
284 * StrToIntA [COMCTL32.357]
286 * Read a signed integer from a string.
289 * lpszStr [I] String to read integer from
292 * The signed integer value represented by the string, or 0 if no integer is
295 INT WINAPI StrToIntA (LPSTR lpszStr)
297 return atoi(lpszStr);
300 /**************************************************************************
301 * StrStrIW [COMCTL32.363]
305 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
307 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
309 return COMCTL32_StrStrHelperW(lpszStr, lpszSearch, StrCmpNIW);
312 /**************************************************************************
313 * StrToIntW [COMCTL32.365]
317 INT WINAPI StrToIntW (LPWSTR lpString)
319 return atoiW(lpString);
322 /*************************************************************************
323 * COMCTL32_StrSpnHelperA (internal)
325 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
327 static int COMCTL32_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
328 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
331 LPCSTR lpszRead = lpszStr;
332 if (lpszStr && *lpszStr && lpszMatch)
336 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
338 if (!bInvert && !lpszTest)
340 if (bInvert && lpszTest)
342 lpszRead = CharNextA(lpszRead);
345 return lpszRead - lpszStr;
348 /**************************************************************************
349 * StrCSpnA [COMCTL32.356]
351 * Find the length of the start of a string that does not contain certain
355 * lpszStr [I] String to search
356 * lpszMatch [I] Characters that cannot be in the substring
359 * The length of the part of lpszStr containing only chars not in lpszMatch,
360 * or 0 if any parameter is invalid.
362 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
364 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
366 return COMCTL32_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
369 /**************************************************************************
370 * StrChrW [COMCTL32.358]
374 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
376 LPWSTR lpszRet = NULL;
378 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
381 lpszRet = strchrW(lpszStr, ch);
385 /**************************************************************************
386 * StrCmpNA [COMCTL32.352]
388 * Compare two strings, up to a maximum length.
391 * lpszStr [I] First string to compare
392 * lpszComp [I] Second string to compare
393 * iLen [I] Maximum number of chars to compare.
396 * An integer less than, equal to or greater than 0, indicating that
397 * lpszStr is less than, the same, or greater than lpszComp.
399 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
403 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
405 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
406 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
409 /**************************************************************************
410 * StrCmpNW [COMCTL32.360]
414 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
418 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
420 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
421 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
424 /**************************************************************************
425 * StrRChrA [COMCTL32.351]
427 * Find the last occurrence of a character in string.
430 * lpszStr [I] String to search in
431 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
432 * ch [I] Character to search for.
435 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
436 * or NULL if not found.
437 * Failure: NULL, if any arguments are invalid.
439 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
441 LPCSTR lpszRet = NULL;
443 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
450 lpszEnd = lpszStr + lstrlenA(lpszStr);
452 while (*lpszStr && lpszStr <= lpszEnd)
454 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
456 if (!COMCTL32_ChrCmpA(ch, ch2))
458 lpszStr = CharNextA(lpszStr);
461 return (LPSTR)lpszRet;
465 /**************************************************************************
466 * StrRChrW [COMCTL32.359]
470 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
472 LPCWSTR lpszRet = NULL;
474 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
479 lpszEnd = lpszStr + strlenW(lpszStr);
481 while (*lpszStr && lpszStr <= lpszEnd)
483 if (!COMCTL32_ChrCmpW(ch, *lpszStr))
485 lpszStr = CharNextW(lpszStr);
488 return (LPWSTR)lpszRet;
491 /**************************************************************************
492 * StrStrA [COMCTL32.354]
494 * Find a substring within a string.
497 * lpszStr [I] String to search in
498 * lpszSearch [I] String to look for
501 * The start of lpszSearch within lpszStr, or NULL if not found.
503 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
505 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
507 return COMCTL32_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
510 /**************************************************************************
511 * StrStrW [COMCTL32.362]
515 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
517 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
519 return COMCTL32_StrStrHelperW(lpszStr, lpszSearch, StrCmpNW);
522 /*************************************************************************
523 * StrChrIA [COMCTL32.366]
525 * Find a given character in a string, ignoring case.
528 * lpszStr [I] String to search in.
529 * ch [I] Character to search for.
532 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
534 * Failure: NULL, if any arguments are invalid.
536 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
538 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
544 if (!COMCTL32_ChrCmpIA(*lpszStr, ch))
545 return (LPSTR)lpszStr;
546 lpszStr = CharNextA(lpszStr);
552 /*************************************************************************
553 * StrChrIW [COMCTL32.367]
557 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
559 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
566 if (toupperW(*lpszStr) == ch)
567 return (LPWSTR)lpszStr;
568 lpszStr = CharNextW(lpszStr);
572 return (LPWSTR)lpszStr;
575 /*************************************************************************
576 * StrRStrIA [COMCTL32.372]
578 * Find the last occurrence of a substring within a string.
581 * lpszStr [I] String to search in
582 * lpszEnd [I] End of lpszStr
583 * lpszSearch [I] String to look for
586 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
588 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
590 LPSTR lpszRet = NULL;
594 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
596 if (!lpszStr || !lpszSearch || !*lpszSearch)
600 lpszEnd = lpszStr + lstrlenA(lpszStr);
602 if (IsDBCSLeadByte(*lpszSearch))
603 ch1 = *lpszSearch << 8 | lpszSearch[1];
606 iLen = lstrlenA(lpszSearch);
608 while (lpszStr <= lpszEnd && *lpszStr)
610 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
611 if (!COMCTL32_ChrCmpIA(ch1, ch2))
613 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
614 lpszRet = (LPSTR)lpszStr;
616 lpszStr = CharNextA(lpszStr);
621 /*************************************************************************
622 * StrRStrIW [COMCTL32.373]
626 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
628 LPWSTR lpszRet = NULL;
631 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
633 if (!lpszStr || !lpszSearch || !*lpszSearch)
637 lpszEnd = lpszStr + strlenW(lpszStr);
639 iLen = strlenW(lpszSearch);
641 while (lpszStr <= lpszEnd && *lpszStr)
643 if (!COMCTL32_ChrCmpIW(*lpszSearch, *lpszStr))
645 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
646 lpszRet = (LPWSTR)lpszStr;
648 lpszStr = CharNextW(lpszStr);
653 /*************************************************************************
654 * COMCTL32_StrSpnHelperW
656 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
658 static int COMCTL32_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
659 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
662 LPCWSTR lpszRead = lpszStr;
663 if (lpszStr && *lpszStr && lpszMatch)
667 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
669 if (!bInvert && !lpszTest)
671 if (bInvert && lpszTest)
673 lpszRead = CharNextW(lpszRead);
676 return lpszRead - lpszStr;
679 /*************************************************************************
680 * StrCSpnIA [COMCTL32.374]
682 * Find the length of the start of a string that does not contain certain
683 * characters, ignoring case.
686 * lpszStr [I] String to search
687 * lpszMatch [I] Characters that cannot be in the substring
690 * The length of the part of lpszStr containing only chars not in lpszMatch,
691 * or 0 if any parameter is invalid.
693 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
695 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
697 return COMCTL32_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
700 /*************************************************************************
701 * StrCSpnIW [COMCTL32.375]
705 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
707 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
709 return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
712 /**************************************************************************
713 * StrRChrIA [COMCTL32.368]
715 * Find the last occurrence of a character in string, ignoring case.
718 * lpszStr [I] String to search in
719 * lpszEnd [I] Place to end search, or NULL to search until the end of lpszStr
720 * ch [I] Character to search for.
723 * Success: A pointer to the last occurrence of ch in lpszStr before lpszEnd,
724 * or NULL if not found.
725 * Failure: NULL, if any arguments are invalid.
727 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
729 LPCSTR lpszRet = NULL;
731 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
738 lpszEnd = lpszStr + lstrlenA(lpszStr);
740 while (*lpszStr && lpszStr <= lpszEnd)
742 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
746 lpszStr = CharNextA(lpszStr);
749 return (LPSTR)lpszRet;
752 /**************************************************************************
753 * StrRChrIW [COMCTL32.369]
757 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
759 LPCWSTR lpszRet = NULL;
761 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
766 lpszEnd = lpszStr + strlenW(lpszStr);
768 while (*lpszStr && lpszStr <= lpszEnd)
772 lpszStr = CharNextW(lpszStr);
775 return (LPWSTR)lpszRet;
778 /*************************************************************************
779 * StrCSpnW [COMCTL32.364]
783 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
785 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
787 return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
790 /*************************************************************************
791 * IntlStrEqWorkerA [COMCTL32.376]
793 * Compare two strings.
796 * bCase [I] Whether to compare case sensitively
797 * lpszStr [I] First string to compare
798 * lpszComp [I] Second string to compare
799 * iLen [I] Length to compare
802 * TRUE If the strings are equal.
805 BOOL WINAPI IntlStrEqWorkerA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
808 DWORD dwFlags = LOCALE_USE_CP_ACP;
811 TRACE("(%d,%s,%s,%d)\n", bCase,
812 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
814 /* FIXME: These flags are undocumented and unknown by our CompareString.
815 * We need defines for them.
817 dwFlags |= bCase ? 0x10000000 : 0x10000001;
819 iRet = CompareStringA(GetThreadLocale(),
820 dwFlags, lpszStr, iLen, lpszComp, iLen);
823 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
825 return iRet == 2 ? TRUE : FALSE;
828 /*************************************************************************
829 * IntlStrEqWorkerW [COMCTL32.377]
831 * See IntlStrEqWorkerA.
833 BOOL WINAPI IntlStrEqWorkerW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
839 TRACE("(%d,%s,%s,%d)\n", bCase,
840 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
842 /* FIXME: These flags are undocumented and unknown by our CompareString.
843 * We need defines for them.
845 dwFlags = bCase ? 0x10000000 : 0x10000001;
847 iRet = CompareStringW(GetThreadLocale(),
848 dwFlags, lpszStr, iLen, lpszComp, iLen);
851 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
853 return iRet == 2 ? TRUE : FALSE;