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