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