reshuffling of dlls
[reactos.git] / reactos / dll / win32 / comctl32 / string.c
1 /*
2 * String manipulation functions
3 *
4 * Copyright 1998 Eric Kohl
5 * 1998 Juergen Schmied <j.schmied@metronet.de>
6 * 2000 Eric Kohl for CodeWeavers
7 * Copyright 2002 Jon Griffiths
8 *
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.
13 *
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.
18 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 */
24
25 #include "config.h"
26 #include "wine/port.h"
27
28 #include <stdarg.h>
29 #include <string.h>
30 #include <stdlib.h> /* atoi */
31
32 #include "windef.h"
33 #include "winbase.h"
34 #include "winuser.h"
35 #include "winnls.h"
36
37 #include "wine/unicode.h"
38
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(commctrl);
42
43 /*************************************************************************
44 * COMCTL32_ChrCmpHelperA
45 *
46 * Internal helper for ChrCmpA/COMCTL32_ChrCmpIA.
47 *
48 * NOTES
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.
55 */
56 static BOOL COMCTL32_ChrCmpHelperA(WORD ch1, WORD ch2, DWORD dwFlags)
57 {
58 char str1[3], str2[3];
59
60 str1[0] = LOBYTE(ch1);
61 if (IsDBCSLeadByte(str1[0]))
62 {
63 str1[1] = HIBYTE(ch1);
64 str1[2] = '\0';
65 }
66 else
67 str1[1] = '\0';
68
69 str2[0] = LOBYTE(ch2);
70 if (IsDBCSLeadByte(str2[0]))
71 {
72 str2[1] = HIBYTE(ch2);
73 str2[2] = '\0';
74 }
75 else
76 str2[1] = '\0';
77
78 return CompareStringA(GetThreadLocale(), dwFlags, str1, -1, str2, -1) - 2;
79 }
80
81 /*************************************************************************
82 * COMCTL32_ChrCmpHelperW
83 *
84 * Internal helper for COMCTL32_ChrCmpW/ChrCmpIW.
85 */
86 static BOOL COMCTL32_ChrCmpHelperW(WCHAR ch1, WCHAR ch2, DWORD dwFlags)
87 {
88 WCHAR str1[2], str2[2];
89
90 str1[0] = ch1;
91 str1[1] = '\0';
92 str2[0] = ch2;
93 str2[1] = '\0';
94 return CompareStringW(GetThreadLocale(), dwFlags, str1, 2, str2, 2) - 2;
95 }
96
97 /*************************************************************************
98 * COMCTL32_ChrCmpA (internal)
99 *
100 * Internal helper function.
101 */
102 static BOOL COMCTL32_ChrCmpA(WORD ch1, WORD ch2)
103 {
104 return COMCTL32_ChrCmpHelperA(ch1, ch2, 0);
105 }
106
107 /*************************************************************************
108 * COMCTL32_ChrCmpIA (internal)
109 *
110 * Compare two characters, ignoring case.
111 *
112 * PARAMS
113 * ch1 [I] First character to compare
114 * ch2 [I] Second character to compare
115 *
116 * RETURNS
117 * FALSE, if the characters are equal.
118 * Non-zero otherwise.
119 */
120 static BOOL COMCTL32_ChrCmpIA(WORD ch1, WORD ch2)
121 {
122 TRACE("(%d,%d)\n", ch1, ch2);
123
124 return COMCTL32_ChrCmpHelperA(ch1, ch2, NORM_IGNORECASE);
125 }
126
127 /*************************************************************************
128 * COMCTL32_ChrCmpW
129 *
130 * Internal helper function.
131 */
132 static BOOL COMCTL32_ChrCmpW(WCHAR ch1, WCHAR ch2)
133 {
134 return COMCTL32_ChrCmpHelperW(ch1, ch2, 0);
135 }
136
137 /*************************************************************************
138 * COMCTL32_ChrCmpIW
139 *
140 * Internal helper function.
141 */
142 static BOOL COMCTL32_ChrCmpIW(WCHAR ch1, WCHAR ch2)
143 {
144 return COMCTL32_ChrCmpHelperW(ch1, ch2, NORM_IGNORECASE);
145 }
146
147 /**************************************************************************
148 * StrChrA [COMCTL32.350]
149 *
150 * Find a given character in a string.
151 *
152 * PARAMS
153 * lpszStr [I] String to search in.
154 * ch [I] Character to search for.
155 *
156 * RETURNS
157 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
158 * not found.
159 * Failure: NULL, if any arguments are invalid.
160 */
161 LPSTR WINAPI StrChrA(LPCSTR lpszStr, WORD ch)
162 {
163 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
164
165 if (lpszStr)
166 {
167 while (*lpszStr)
168 {
169 if (!COMCTL32_ChrCmpA(*lpszStr, ch))
170 return (LPSTR)lpszStr;
171 lpszStr = CharNextA(lpszStr);
172 }
173 }
174 return NULL;
175 }
176
177 /**************************************************************************
178 * StrCmpNIA [COMCTL32.353]
179 *
180 * Compare two strings, up to a maximum length, ignoring case.
181 *
182 * PARAMS
183 * lpszStr [I] First string to compare
184 * lpszComp [I] Second string to compare
185 * iLen [I] Maximum number of chars to compare.
186 *
187 * RETURNS
188 * An integer less than, equal to or greater than 0, indicating that
189 * lpszStr is less than, the same, or greater than lpszComp.
190 */
191 INT WINAPI StrCmpNIA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
192 {
193 INT iRet;
194
195 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
196
197 iRet = CompareStringA(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
198 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
199 }
200
201 /*************************************************************************
202 * StrCmpNIW [COMCTL32.361]
203 *
204 * See StrCmpNIA.
205 */
206 INT WINAPI StrCmpNIW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
207 {
208 INT iRet;
209
210 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
211
212 iRet = CompareStringW(GetThreadLocale(), NORM_IGNORECASE, lpszStr, iLen, lpszComp, iLen);
213 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
214 }
215
216 /*************************************************************************
217 * COMCTL32_StrStrHelperA
218 *
219 * Internal implementation of StrStrA/StrStrIA
220 */
221 static LPSTR COMCTL32_StrStrHelperA(LPCSTR lpszStr, LPCSTR lpszSearch,
222 INT (WINAPI *pStrCmpFn)(LPCSTR,LPCSTR,INT))
223 {
224 size_t iLen;
225
226 if (!lpszStr || !lpszSearch || !*lpszSearch)
227 return NULL;
228
229 iLen = strlen(lpszSearch);
230
231 while (*lpszStr)
232 {
233 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
234 return (LPSTR)lpszStr;
235 lpszStr = CharNextA(lpszStr);
236 }
237 return NULL;
238 }
239
240 /*************************************************************************
241 * COMCTL32_StrStrHelperW
242 *
243 * Internal implementation of StrStrW/StrStrIW
244 */
245 static LPWSTR COMCTL32_StrStrHelperW(LPCWSTR lpszStr, LPCWSTR lpszSearch,
246 INT (WINAPI *pStrCmpFn)(LPCWSTR,LPCWSTR,INT))
247 {
248 int iLen;
249
250 if (!lpszStr || !lpszSearch || !*lpszSearch)
251 return NULL;
252
253 iLen = strlenW(lpszSearch);
254
255 while (*lpszStr)
256 {
257 if (!pStrCmpFn(lpszStr, lpszSearch, iLen))
258 return (LPWSTR)lpszStr;
259 lpszStr = CharNextW(lpszStr);
260 }
261 return NULL;
262 }
263
264 /**************************************************************************
265 * StrStrIA [COMCTL32.355]
266 *
267 * Find a substring within a string, ignoring case.
268 *
269 * PARAMS
270 * lpszStr [I] String to search in
271 * lpszSearch [I] String to look for
272 *
273 * RETURNS
274 * The start of lpszSearch within lpszStr, or NULL if not found.
275 */
276 LPSTR WINAPI StrStrIA(LPCSTR lpszStr, LPCSTR lpszSearch)
277 {
278 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
279
280 return COMCTL32_StrStrHelperA(lpszStr, lpszSearch, StrCmpNIA);
281 }
282
283 /**************************************************************************
284 * StrToIntA [COMCTL32.357]
285 *
286 * Read a signed integer from a string.
287 *
288 * PARAMS
289 * lpszStr [I] String to read integer from
290 *
291 * RETURNS
292 * The signed integer value represented by the string, or 0 if no integer is
293 * present.
294 */
295 INT WINAPI StrToIntA (LPSTR lpszStr)
296 {
297 return atoi(lpszStr);
298 }
299
300 /**************************************************************************
301 * StrStrIW [COMCTL32.363]
302 *
303 * See StrStrIA.
304 */
305 LPWSTR WINAPI StrStrIW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
306 {
307 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
308
309 return COMCTL32_StrStrHelperW(lpszStr, lpszSearch, StrCmpNIW);
310 }
311
312 /**************************************************************************
313 * StrToIntW [COMCTL32.365]
314 *
315 * See StrToIntA.
316 */
317 INT WINAPI StrToIntW (LPWSTR lpString)
318 {
319 return atoiW(lpString);
320 }
321
322 /*************************************************************************
323 * COMCTL32_StrSpnHelperA (internal)
324 *
325 * Internal implementation of StrSpnA/StrCSpnA/StrCSpnIA
326 */
327 static int COMCTL32_StrSpnHelperA(LPCSTR lpszStr, LPCSTR lpszMatch,
328 LPSTR (WINAPI *pStrChrFn)(LPCSTR,WORD),
329 BOOL bInvert)
330 {
331 LPCSTR lpszRead = lpszStr;
332 if (lpszStr && *lpszStr && lpszMatch)
333 {
334 while (*lpszRead)
335 {
336 LPCSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
337
338 if (!bInvert && !lpszTest)
339 break;
340 if (bInvert && lpszTest)
341 break;
342 lpszRead = CharNextA(lpszRead);
343 };
344 }
345 return lpszRead - lpszStr;
346 }
347
348 /**************************************************************************
349 * StrCSpnA [COMCTL32.356]
350 *
351 * Find the length of the start of a string that does not contain certain
352 * characters.
353 *
354 * PARAMS
355 * lpszStr [I] String to search
356 * lpszMatch [I] Characters that cannot be in the substring
357 *
358 * RETURNS
359 * The length of the part of lpszStr containing only chars not in lpszMatch,
360 * or 0 if any parameter is invalid.
361 */
362 int WINAPI StrCSpnA(LPCSTR lpszStr, LPCSTR lpszMatch)
363 {
364 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
365
366 return COMCTL32_StrSpnHelperA(lpszStr, lpszMatch, StrChrA, TRUE);
367 }
368
369 /**************************************************************************
370 * StrChrW [COMCTL32.358]
371 *
372 * See StrChrA.
373 */
374 LPWSTR WINAPI StrChrW(LPCWSTR lpszStr, WCHAR ch)
375 {
376 LPWSTR lpszRet = NULL;
377
378 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
379
380 if (lpszStr)
381 lpszRet = strchrW(lpszStr, ch);
382 return lpszRet;
383 }
384
385 /**************************************************************************
386 * StrCmpNA [COMCTL32.352]
387 *
388 * Compare two strings, up to a maximum length.
389 *
390 * PARAMS
391 * lpszStr [I] First string to compare
392 * lpszComp [I] Second string to compare
393 * iLen [I] Maximum number of chars to compare.
394 *
395 * RETURNS
396 * An integer less than, equal to or greater than 0, indicating that
397 * lpszStr is less than, the same, or greater than lpszComp.
398 */
399 INT WINAPI StrCmpNA(LPCSTR lpszStr, LPCSTR lpszComp, INT iLen)
400 {
401 INT iRet;
402
403 TRACE("(%s,%s,%i)\n", debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
404
405 iRet = CompareStringA(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
406 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
407 }
408
409 /**************************************************************************
410 * StrCmpNW [COMCTL32.360]
411 *
412 * See StrCmpNA.
413 */
414 INT WINAPI StrCmpNW(LPCWSTR lpszStr, LPCWSTR lpszComp, INT iLen)
415 {
416 INT iRet;
417
418 TRACE("(%s,%s,%i)\n", debugstr_w(lpszStr), debugstr_w(lpszComp), iLen);
419
420 iRet = CompareStringW(GetThreadLocale(), 0, lpszStr, iLen, lpszComp, iLen);
421 return iRet == CSTR_LESS_THAN ? -1 : iRet == CSTR_GREATER_THAN ? 1 : 0;
422 }
423
424 /**************************************************************************
425 * StrRChrA [COMCTL32.351]
426 *
427 * Find the last occurrence of a character in string.
428 *
429 * PARAMS
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.
433 *
434 * RETURNS
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.
438 */
439 LPSTR WINAPI StrRChrA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
440 {
441 LPCSTR lpszRet = NULL;
442
443 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
444
445 if (lpszStr)
446 {
447 WORD ch2;
448
449 if (!lpszEnd)
450 lpszEnd = lpszStr + lstrlenA(lpszStr);
451
452 while (*lpszStr && lpszStr <= lpszEnd)
453 {
454 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
455
456 if (!COMCTL32_ChrCmpA(ch, ch2))
457 lpszRet = lpszStr;
458 lpszStr = CharNextA(lpszStr);
459 }
460 }
461 return (LPSTR)lpszRet;
462 }
463
464
465 /**************************************************************************
466 * StrRChrW [COMCTL32.359]
467 *
468 * See StrRChrA.
469 */
470 LPWSTR WINAPI StrRChrW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
471 {
472 LPCWSTR lpszRet = NULL;
473
474 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
475
476 if (lpszStr)
477 {
478 if (!lpszEnd)
479 lpszEnd = lpszStr + strlenW(lpszStr);
480
481 while (*lpszStr && lpszStr <= lpszEnd)
482 {
483 if (!COMCTL32_ChrCmpW(ch, *lpszStr))
484 lpszRet = lpszStr;
485 lpszStr = CharNextW(lpszStr);
486 }
487 }
488 return (LPWSTR)lpszRet;
489 }
490
491 /**************************************************************************
492 * StrStrA [COMCTL32.354]
493 *
494 * Find a substring within a string.
495 *
496 * PARAMS
497 * lpszStr [I] String to search in
498 * lpszSearch [I] String to look for
499 *
500 * RETURNS
501 * The start of lpszSearch within lpszStr, or NULL if not found.
502 */
503 LPSTR WINAPI StrStrA(LPCSTR lpszStr, LPCSTR lpszSearch)
504 {
505 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
506
507 return COMCTL32_StrStrHelperA(lpszStr, lpszSearch, StrCmpNA);
508 }
509
510 /**************************************************************************
511 * StrStrW [COMCTL32.362]
512 *
513 * See StrStrA.
514 */
515 LPWSTR WINAPI StrStrW(LPCWSTR lpszStr, LPCWSTR lpszSearch)
516 {
517 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
518
519 return COMCTL32_StrStrHelperW(lpszStr, lpszSearch, StrCmpNW);
520 }
521
522 /*************************************************************************
523 * StrChrIA [COMCTL32.366]
524 *
525 * Find a given character in a string, ignoring case.
526 *
527 * PARAMS
528 * lpszStr [I] String to search in.
529 * ch [I] Character to search for.
530 *
531 * RETURNS
532 * Success: A pointer to the first occurrence of ch in lpszStr, or NULL if
533 * not found.
534 * Failure: NULL, if any arguments are invalid.
535 */
536 LPSTR WINAPI StrChrIA(LPCSTR lpszStr, WORD ch)
537 {
538 TRACE("(%s,%i)\n", debugstr_a(lpszStr), ch);
539
540 if (lpszStr)
541 {
542 while (*lpszStr)
543 {
544 if (!COMCTL32_ChrCmpIA(*lpszStr, ch))
545 return (LPSTR)lpszStr;
546 lpszStr = CharNextA(lpszStr);
547 }
548 }
549 return NULL;
550 }
551
552 /*************************************************************************
553 * StrChrIW [COMCTL32.367]
554 *
555 * See StrChrA.
556 */
557 LPWSTR WINAPI StrChrIW(LPCWSTR lpszStr, WCHAR ch)
558 {
559 TRACE("(%s,%i)\n", debugstr_w(lpszStr), ch);
560
561 if (lpszStr)
562 {
563 ch = toupperW(ch);
564 while (*lpszStr)
565 {
566 if (toupperW(*lpszStr) == ch)
567 return (LPWSTR)lpszStr;
568 lpszStr = CharNextW(lpszStr);
569 }
570 lpszStr = NULL;
571 }
572 return (LPWSTR)lpszStr;
573 }
574
575 /*************************************************************************
576 * StrRStrIA [COMCTL32.372]
577 *
578 * Find the last occurrence of a substring within a string.
579 *
580 * PARAMS
581 * lpszStr [I] String to search in
582 * lpszEnd [I] End of lpszStr
583 * lpszSearch [I] String to look for
584 *
585 * RETURNS
586 * The last occurrence lpszSearch within lpszStr, or NULL if not found.
587 */
588 LPSTR WINAPI StrRStrIA(LPCSTR lpszStr, LPCSTR lpszEnd, LPCSTR lpszSearch)
589 {
590 LPSTR lpszRet = NULL;
591 WORD ch1, ch2;
592 INT iLen;
593
594 TRACE("(%s,%s)\n", debugstr_a(lpszStr), debugstr_a(lpszSearch));
595
596 if (!lpszStr || !lpszSearch || !*lpszSearch)
597 return NULL;
598
599 if (!lpszEnd)
600 lpszEnd = lpszStr + lstrlenA(lpszStr);
601
602 if (IsDBCSLeadByte(*lpszSearch))
603 ch1 = *lpszSearch << 8 | lpszSearch[1];
604 else
605 ch1 = *lpszSearch;
606 iLen = lstrlenA(lpszSearch);
607
608 while (lpszStr <= lpszEnd && *lpszStr)
609 {
610 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
611 if (!COMCTL32_ChrCmpIA(ch1, ch2))
612 {
613 if (!StrCmpNIA(lpszStr, lpszSearch, iLen))
614 lpszRet = (LPSTR)lpszStr;
615 }
616 lpszStr = CharNextA(lpszStr);
617 }
618 return lpszRet;
619 }
620
621 /*************************************************************************
622 * StrRStrIW [COMCTL32.373]
623 *
624 * See StrRStrIA.
625 */
626 LPWSTR WINAPI StrRStrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, LPCWSTR lpszSearch)
627 {
628 LPWSTR lpszRet = NULL;
629 INT iLen;
630
631 TRACE("(%s,%s)\n", debugstr_w(lpszStr), debugstr_w(lpszSearch));
632
633 if (!lpszStr || !lpszSearch || !*lpszSearch)
634 return NULL;
635
636 if (!lpszEnd)
637 lpszEnd = lpszStr + strlenW(lpszStr);
638
639 iLen = strlenW(lpszSearch);
640
641 while (lpszStr <= lpszEnd && *lpszStr)
642 {
643 if (!COMCTL32_ChrCmpIW(*lpszSearch, *lpszStr))
644 {
645 if (!StrCmpNIW(lpszStr, lpszSearch, iLen))
646 lpszRet = (LPWSTR)lpszStr;
647 }
648 lpszStr = CharNextW(lpszStr);
649 }
650 return lpszRet;
651 }
652
653 /*************************************************************************
654 * COMCTL32_StrSpnHelperW
655 *
656 * Internal implementation of StrSpnW/StrCSpnW/StrCSpnIW
657 */
658 static int COMCTL32_StrSpnHelperW(LPCWSTR lpszStr, LPCWSTR lpszMatch,
659 LPWSTR (WINAPI *pStrChrFn)(LPCWSTR,WCHAR),
660 BOOL bInvert)
661 {
662 LPCWSTR lpszRead = lpszStr;
663 if (lpszStr && *lpszStr && lpszMatch)
664 {
665 while (*lpszRead)
666 {
667 LPCWSTR lpszTest = pStrChrFn(lpszMatch, *lpszRead);
668
669 if (!bInvert && !lpszTest)
670 break;
671 if (bInvert && lpszTest)
672 break;
673 lpszRead = CharNextW(lpszRead);
674 };
675 }
676 return lpszRead - lpszStr;
677 }
678
679 /*************************************************************************
680 * StrCSpnIA [COMCTL32.374]
681 *
682 * Find the length of the start of a string that does not contain certain
683 * characters, ignoring case.
684 *
685 * PARAMS
686 * lpszStr [I] String to search
687 * lpszMatch [I] Characters that cannot be in the substring
688 *
689 * RETURNS
690 * The length of the part of lpszStr containing only chars not in lpszMatch,
691 * or 0 if any parameter is invalid.
692 */
693 int WINAPI StrCSpnIA(LPCSTR lpszStr, LPCSTR lpszMatch)
694 {
695 TRACE("(%s,%s)\n",debugstr_a(lpszStr), debugstr_a(lpszMatch));
696
697 return COMCTL32_StrSpnHelperA(lpszStr, lpszMatch, StrChrIA, TRUE);
698 }
699
700 /*************************************************************************
701 * StrCSpnIW [COMCTL32.375]
702 *
703 * See StrCSpnIA.
704 */
705 int WINAPI StrCSpnIW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
706 {
707 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
708
709 return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrIW, TRUE);
710 }
711
712 /**************************************************************************
713 * StrRChrIA [COMCTL32.368]
714 *
715 * Find the last occurrence of a character in string, ignoring case.
716 *
717 * PARAMS
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.
721 *
722 * RETURNS
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.
726 */
727 LPSTR WINAPI StrRChrIA(LPCSTR lpszStr, LPCSTR lpszEnd, WORD ch)
728 {
729 LPCSTR lpszRet = NULL;
730
731 TRACE("(%s,%s,%x)\n", debugstr_a(lpszStr), debugstr_a(lpszEnd), ch);
732
733 if (lpszStr)
734 {
735 WORD ch2;
736
737 if (!lpszEnd)
738 lpszEnd = lpszStr + lstrlenA(lpszStr);
739
740 while (*lpszStr && lpszStr <= lpszEnd)
741 {
742 ch2 = IsDBCSLeadByte(*lpszStr)? *lpszStr << 8 | lpszStr[1] : *lpszStr;
743
744 if (ch == ch2)
745 lpszRet = lpszStr;
746 lpszStr = CharNextA(lpszStr);
747 }
748 }
749 return (LPSTR)lpszRet;
750 }
751
752 /**************************************************************************
753 * StrRChrIW [COMCTL32.369]
754 *
755 * See StrRChrIA.
756 */
757 LPWSTR WINAPI StrRChrIW(LPCWSTR lpszStr, LPCWSTR lpszEnd, WORD ch)
758 {
759 LPCWSTR lpszRet = NULL;
760
761 TRACE("(%s,%s,%x)\n", debugstr_w(lpszStr), debugstr_w(lpszEnd), ch);
762
763 if (lpszStr)
764 {
765 if (!lpszEnd)
766 lpszEnd = lpszStr + strlenW(lpszStr);
767
768 while (*lpszStr && lpszStr <= lpszEnd)
769 {
770 if (ch == *lpszStr)
771 lpszRet = lpszStr;
772 lpszStr = CharNextW(lpszStr);
773 }
774 }
775 return (LPWSTR)lpszRet;
776 }
777
778 /*************************************************************************
779 * StrCSpnW [COMCTL32.364]
780 *
781 * See StrCSpnA.
782 */
783 int WINAPI StrCSpnW(LPCWSTR lpszStr, LPCWSTR lpszMatch)
784 {
785 TRACE("(%s,%s)\n",debugstr_w(lpszStr), debugstr_w(lpszMatch));
786
787 return COMCTL32_StrSpnHelperW(lpszStr, lpszMatch, StrChrW, TRUE);
788 }
789
790 /*************************************************************************
791 * IntlStrEqWorkerA [COMCTL32.376]
792 *
793 * Compare two strings.
794 *
795 * PARAMS
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
800 *
801 * RETURNS
802 * TRUE If the strings are equal.
803 * FALSE Otherwise.
804 */
805 BOOL WINAPI IntlStrEqWorkerA(BOOL bCase, LPCSTR lpszStr, LPCSTR lpszComp,
806 int iLen)
807 {
808 DWORD dwFlags = LOCALE_USE_CP_ACP;
809 int iRet;
810
811 TRACE("(%d,%s,%s,%d)\n", bCase,
812 debugstr_a(lpszStr), debugstr_a(lpszComp), iLen);
813
814 /* FIXME: These flags are undocumented and unknown by our CompareString.
815 * We need defines for them.
816 */
817 dwFlags |= bCase ? 0x10000000 : 0x10000001;
818
819 iRet = CompareStringA(GetThreadLocale(),
820 dwFlags, lpszStr, iLen, lpszComp, iLen);
821
822 if (!iRet)
823 iRet = CompareStringA(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
824
825 return iRet == 2 ? TRUE : FALSE;
826 }
827
828 /*************************************************************************
829 * IntlStrEqWorkerW [COMCTL32.377]
830 *
831 * See IntlStrEqWorkerA.
832 */
833 BOOL WINAPI IntlStrEqWorkerW(BOOL bCase, LPCWSTR lpszStr, LPCWSTR lpszComp,
834 int iLen)
835 {
836 DWORD dwFlags;
837 int iRet;
838
839 TRACE("(%d,%s,%s,%d)\n", bCase,
840 debugstr_w(lpszStr),debugstr_w(lpszComp), iLen);
841
842 /* FIXME: These flags are undocumented and unknown by our CompareString.
843 * We need defines for them.
844 */
845 dwFlags = bCase ? 0x10000000 : 0x10000001;
846
847 iRet = CompareStringW(GetThreadLocale(),
848 dwFlags, lpszStr, iLen, lpszComp, iLen);
849
850 if (!iRet)
851 iRet = CompareStringW(2048, dwFlags, lpszStr, iLen, lpszComp, iLen);
852
853 return iRet == 2 ? TRUE : FALSE;
854 }