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