2 * Copyright 2019 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
27 #include "kernelbase.h"
28 #include "wine/debug.h"
29 #include "wine/exception.h"
31 WINE_DEFAULT_DEBUG_CHANNEL(string
);
33 static BOOL
char_compare(WORD ch1
, WORD ch2
, DWORD flags
)
35 char str1
[3], str2
[3];
37 str1
[0] = LOBYTE(ch1
);
38 if (IsDBCSLeadByte(str1
[0]))
40 str1
[1] = HIBYTE(ch1
);
46 str2
[0] = LOBYTE(ch2
);
47 if (IsDBCSLeadByte(str2
[0]))
49 str2
[1] = HIBYTE(ch2
);
55 return CompareStringA(GetThreadLocale(), flags
, str1
, -1, str2
, -1) - CSTR_EQUAL
;
58 int WINAPI
lstrcmpA( LPCSTR str1
, LPCSTR str2
)
60 if (!str1
&& !str2
) return 0;
63 return CompareStringA( GetThreadLocale(), LOCALE_USE_CP_ACP
, str1
, -1, str2
, -1 ) - 2;
66 int WINAPI
lstrcmpW(LPCWSTR str1
, LPCWSTR str2
)
68 if (!str1
&& !str2
) return 0;
71 return CompareStringW( GetThreadLocale(), 0, str1
, -1, str2
, -1 ) - 2;
74 int WINAPI
lstrcmpiA(LPCSTR str1
, LPCSTR str2
)
76 if (!str1
&& !str2
) return 0;
79 return CompareStringA( GetThreadLocale(), NORM_IGNORECASE
|LOCALE_USE_CP_ACP
, str1
, -1, str2
, -1 ) - 2;
82 int WINAPI
lstrcmpiW(LPCWSTR str1
, LPCWSTR str2
)
84 if (!str1
&& !str2
) return 0;
87 return CompareStringW( GetThreadLocale(), NORM_IGNORECASE
, str1
, -1, str2
, -1 ) - 2;
90 LPSTR WINAPI
KERNELBASE_lstrcpynA( LPSTR dst
, LPCSTR src
, INT n
)
92 /* Note: this function differs from the UNIX strncpy, it _always_ writes
95 * Note: n is an INT but Windows treats it as unsigned, and will happily
96 * copy a gazillion chars if n is negative.
104 while ((count
> 1) && *s
)
113 SetLastError( ERROR_INVALID_PARAMETER
);
120 LPWSTR WINAPI
KERNELBASE_lstrcpynW( LPWSTR dst
, LPCWSTR src
, INT n
)
122 /* Note: this function differs from the UNIX strncpy, it _always_ writes
125 * Note: n is an INT but Windows treats it as unsigned, and will happily
126 * copy a gazillion chars if n is negative.
134 while ((count
> 1) && *s
)
143 SetLastError( ERROR_INVALID_PARAMETER
);
150 INT WINAPI
KERNELBASE_lstrlenA( LPCSTR str
)
159 SetLastError( ERROR_INVALID_PARAMETER
);
166 INT WINAPI
KERNELBASE_lstrlenW( LPCWSTR str
)
175 SetLastError( ERROR_INVALID_PARAMETER
);
182 DWORD WINAPI
StrCmpCA(const char *str
, const char *cmp
)
184 return lstrcmpA(str
, cmp
);
187 DWORD WINAPI
StrCmpCW(const WCHAR
*str
, const WCHAR
*cmp
)
189 return lstrcmpW(str
, cmp
);
192 DWORD WINAPI
StrCmpICA(const char *str
, const char *cmp
)
194 return lstrcmpiA(str
, cmp
);
197 DWORD WINAPI
StrCmpICW(const WCHAR
*str
, const WCHAR
*cmp
)
199 return lstrcmpiW(str
, cmp
);
202 DWORD WINAPI
StrCmpNICA(const char *str
, const char *cmp
, DWORD len
)
204 return StrCmpNIA(str
, cmp
, len
);
207 DWORD WINAPI
StrCmpNICW(const WCHAR
*str
, const WCHAR
*cmp
, DWORD len
)
209 return StrCmpNIW(str
, cmp
, len
);
212 char * WINAPI
StrChrA(const char *str
, WORD ch
)
214 TRACE("%s, %#x\n", wine_dbgstr_a(str
), ch
);
221 if (!char_compare(*str
, ch
, 0))
223 str
= CharNextA(str
);
229 WCHAR
* WINAPI
StrChrW(const WCHAR
*str
, WCHAR ch
)
231 TRACE("%s, %#x\n", wine_dbgstr_w(str
), ch
);
236 return wcschr(str
, ch
);
239 char * WINAPI
StrChrIA(const char *str
, WORD ch
)
241 TRACE("%s, %i\n", wine_dbgstr_a(str
), ch
);
248 if (!ChrCmpIA(*str
, ch
))
250 str
= CharNextA(str
);
256 WCHAR
* WINAPI
StrChrIW(const WCHAR
*str
, WCHAR ch
)
258 TRACE("%s, %#x\n", wine_dbgstr_w(str
), ch
);
266 if (towupper(*str
) == ch
)
275 WCHAR
* WINAPI
StrChrNW(const WCHAR
*str
, WCHAR ch
, UINT max_len
)
277 TRACE("%s, %#x, %u\n", wine_dbgstr_wn(str
, max_len
), ch
, max_len
);
282 while (*str
&& max_len
-- > 0)
292 char * WINAPI
StrDupA(const char *str
)
297 TRACE("%s\n", wine_dbgstr_a(str
));
299 len
= str
? strlen(str
) + 1 : 1;
300 ret
= LocalAlloc(LMEM_FIXED
, len
);
305 memcpy(ret
, str
, len
);
313 WCHAR
* WINAPI
StrDupW(const WCHAR
*str
)
318 TRACE("%s\n", wine_dbgstr_w(str
));
320 len
= (str
? lstrlenW(str
) + 1 : 1) * sizeof(WCHAR
);
321 ret
= LocalAlloc(LMEM_FIXED
, len
);
326 memcpy(ret
, str
, len
);
334 BOOL WINAPI
ChrCmpIA(WORD ch1
, WORD ch2
)
336 TRACE("%#x, %#x\n", ch1
, ch2
);
338 return char_compare(ch1
, ch2
, NORM_IGNORECASE
);
341 BOOL WINAPI
ChrCmpIW(WCHAR ch1
, WCHAR ch2
)
343 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, &ch1
, 1, &ch2
, 1) - CSTR_EQUAL
;
346 char * WINAPI
StrStrA(const char *str
, const char *search
)
351 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(search
));
353 if (!str
|| !search
|| !*search
) return NULL
;
355 len
= strlen(search
);
356 end
= str
+ strlen(str
);
358 while (str
+ len
<= end
)
360 if (!StrCmpNA(str
, search
, len
)) return (char *)str
;
361 str
= CharNextA(str
);
366 WCHAR
* WINAPI
StrStrW(const WCHAR
*str
, const WCHAR
*search
)
368 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(search
));
370 if (!str
|| !search
|| !*search
)
373 return wcsstr(str
, search
);
376 WCHAR
* WINAPI
StrStrNW(const WCHAR
*str
, const WCHAR
*search
, UINT max_len
)
380 TRACE("%s, %s, %u\n", wine_dbgstr_w(str
), wine_dbgstr_w(search
), max_len
);
382 if (!str
|| !search
|| !*search
|| !max_len
)
385 len
= lstrlenW(search
);
387 for (i
= max_len
; *str
&& (i
> 0); i
--, str
++)
389 if (!wcsncmp(str
, search
, len
))
396 int WINAPI
StrCmpNIA(const char *str
, const char *cmp
, int len
)
398 TRACE("%s, %s, %i\n", wine_dbgstr_a(str
), wine_dbgstr_a(cmp
), len
);
399 return CompareStringA(GetThreadLocale(), NORM_IGNORECASE
, str
, len
, cmp
, len
) - CSTR_EQUAL
;
402 WCHAR
* WINAPI
StrStrNIW(const WCHAR
*str
, const WCHAR
*search
, UINT max_len
)
406 TRACE("%s, %s, %u\n", wine_dbgstr_w(str
), wine_dbgstr_w(search
), max_len
);
408 if (!str
|| !search
|| !*search
|| !max_len
)
411 len
= lstrlenW(search
);
413 for (i
= max_len
; *str
&& (i
> 0); i
--, str
++)
415 if (!StrCmpNIW(str
, search
, len
))
422 int WINAPI
StrCmpNA(const char *str
, const char *comp
, int len
)
424 TRACE("%s, %s, %i\n", wine_dbgstr_a(str
), wine_dbgstr_a(comp
), len
);
425 return CompareStringA(GetThreadLocale(), 0, str
, len
, comp
, len
) - CSTR_EQUAL
;
428 int WINAPI
StrCmpNW(const WCHAR
*str
, const WCHAR
*comp
, int len
)
430 TRACE("%s, %s, %i\n", wine_dbgstr_w(str
), wine_dbgstr_w(comp
), len
);
431 return CompareStringW(GetThreadLocale(), 0, str
, len
, comp
, len
) - CSTR_EQUAL
;
434 DWORD WINAPI
StrCmpNCA(const char *str
, const char *comp
, int len
)
436 return StrCmpNA(str
, comp
, len
);
439 DWORD WINAPI
StrCmpNCW(const WCHAR
*str
, const WCHAR
*comp
, int len
)
441 return StrCmpNW(str
, comp
, len
);
444 int WINAPI
StrCmpNIW(const WCHAR
*str
, const WCHAR
*comp
, int len
)
446 TRACE("%s, %s, %i\n", wine_dbgstr_w(str
), wine_dbgstr_w(comp
), len
);
447 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, str
, len
, comp
, len
) - CSTR_EQUAL
;
450 int WINAPI
StrCmpW(const WCHAR
*str
, const WCHAR
*comp
)
452 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(comp
));
453 return CompareStringW(GetThreadLocale(), 0, str
, -1, comp
, -1) - CSTR_EQUAL
;
456 int WINAPI
StrCmpIW(const WCHAR
*str
, const WCHAR
*comp
)
458 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(comp
));
459 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, str
, -1, comp
, -1) - CSTR_EQUAL
;
462 WCHAR
* WINAPI
StrCpyNW(WCHAR
*dst
, const WCHAR
*src
, int count
)
464 const WCHAR
*s
= src
;
467 TRACE("%p, %s, %i\n", dst
, wine_dbgstr_w(src
), count
);
471 while ((count
> 1) && *s
)
482 char * WINAPI
StrStrIA(const char *str
, const char *search
)
487 TRACE("%s, %s\n", wine_dbgstr_a(str
), debugstr_a(search
));
489 if (!str
|| !search
|| !*search
) return NULL
;
491 len
= strlen(search
);
492 end
= str
+ strlen(str
);
494 while (str
+ len
<= end
)
496 if (!StrCmpNIA(str
, search
, len
)) return (char *)str
;
497 str
= CharNextA(str
);
502 WCHAR
* WINAPI
StrStrIW(const WCHAR
*str
, const WCHAR
*search
)
507 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(search
));
509 if (!str
|| !search
|| !*search
)
512 len
= lstrlenW(search
);
513 end
= str
+ lstrlenW(str
);
515 while (str
+ len
<= end
)
517 if (!StrCmpNIW(str
, search
, len
))
525 int WINAPI
StrSpnA(const char *str
, const char *match
)
527 const char *ptr
= str
;
529 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(match
));
531 if (!str
|| !match
) return 0;
535 if (!StrChrA(match
, *ptr
)) break;
536 ptr
= CharNextA(ptr
);
541 int WINAPI
StrSpnW(const WCHAR
*str
, const WCHAR
*match
)
543 if (!str
|| !match
) return 0;
544 return wcsspn(str
, match
);
547 int WINAPI
StrCSpnA(const char *str
, const char *match
)
549 const char *ptr
= str
;
551 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(match
));
553 if (!str
|| !match
) return 0;
557 if (StrChrA(match
, *ptr
)) break;
558 ptr
= CharNextA(ptr
);
563 int WINAPI
StrCSpnW(const WCHAR
*str
, const WCHAR
*match
)
568 return wcscspn(str
, match
);
571 int WINAPI
StrCSpnIA(const char *str
, const char *match
)
573 const char *ptr
= str
;
575 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(match
));
577 if (!str
|| !match
) return 0;
581 if (StrChrIA(match
, *ptr
)) break;
582 ptr
= CharNextA(ptr
);
587 int WINAPI
StrCSpnIW(const WCHAR
*str
, const WCHAR
*match
)
589 const WCHAR
*ptr
= str
;
591 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(match
));
593 if (!str
|| !*str
|| !match
)
598 if (StrChrIW(match
, *ptr
)) break;
605 char * WINAPI
StrRChrA(const char *str
, const char *end
, WORD ch
)
607 const char *ret
= NULL
;
609 TRACE("%s, %s, %#x\n", wine_dbgstr_a(str
), wine_dbgstr_a(end
), ch
);
611 if (!str
) return NULL
;
612 if (!end
) end
= str
+ lstrlenA(str
);
613 while (*str
&& str
<= end
)
615 WORD ch2
= IsDBCSLeadByte(*str
) ? *str
<< 8 | str
[1] : *str
;
616 if (!char_compare(ch
, ch2
, 0)) ret
= str
;
617 str
= CharNextA(str
);
622 WCHAR
* WINAPI
StrRChrW(const WCHAR
*str
, const WCHAR
*end
, WORD ch
)
626 if (!str
) return NULL
;
627 if (!end
) end
= str
+ lstrlenW(str
);
630 if (*str
== ch
) ret
= (WCHAR
*)str
;
636 char * WINAPI
StrRChrIA(const char *str
, const char *end
, WORD ch
)
638 const char *ret
= NULL
;
640 TRACE("%s, %s, %#x\n", wine_dbgstr_a(str
), wine_dbgstr_a(end
), ch
);
642 if (!str
) return NULL
;
643 if (!end
) end
= str
+ lstrlenA(str
);
645 while (*str
&& str
<= end
)
647 WORD ch2
= IsDBCSLeadByte(*str
) ? *str
<< 8 | str
[1] : *str
;
648 if (!ChrCmpIA(ch
, ch2
)) ret
= str
;
649 str
= CharNextA(str
);
654 WCHAR
* WINAPI
StrRChrIW(const WCHAR
*str
, const WCHAR
*end
, WORD ch
)
658 if (!str
) return NULL
;
659 if (!end
) end
= str
+ lstrlenW(str
);
662 if (!ChrCmpIW(*str
, ch
)) ret
= (WCHAR
*)str
;
668 char * WINAPI
StrRStrIA(const char *str
, const char *end
, const char *search
)
674 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(search
));
676 if (!str
|| !search
|| !*search
)
679 if (IsDBCSLeadByte(*search
))
680 ch1
= *search
<< 8 | (UCHAR
)search
[1];
683 len
= lstrlenA(search
);
686 end
= str
+ lstrlenA(str
);
687 else /* reproduce the broken behaviour on Windows */
688 end
+= min(len
- 1, lstrlenA(end
));
690 while (str
+ len
<= end
&& *str
)
692 ch2
= IsDBCSLeadByte(*str
) ? *str
<< 8 | (UCHAR
)str
[1] : *str
;
693 if (!ChrCmpIA(ch1
, ch2
))
695 if (!StrCmpNIA(str
, search
, len
))
699 str
= CharNextA(str
);
705 WCHAR
* WINAPI
StrRStrIW(const WCHAR
*str
, const WCHAR
*end
, const WCHAR
*search
)
710 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(search
));
712 if (!str
|| !search
|| !*search
)
715 len
= lstrlenW(search
);
718 end
= str
+ lstrlenW(str
);
720 end
+= min(len
- 1, lstrlenW(end
));
722 while (str
+ len
<= end
&& *str
)
724 if (!ChrCmpIW(*search
, *str
))
726 if (!StrCmpNIW(str
, search
, len
))
735 char * WINAPI
StrPBrkA(const char *str
, const char *match
)
737 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(match
));
739 if (!str
|| !match
|| !*match
)
744 if (StrChrA(match
, *str
))
746 str
= CharNextA(str
);
752 WCHAR
* WINAPI
StrPBrkW(const WCHAR
*str
, const WCHAR
*match
)
754 if (!str
|| !match
) return NULL
;
755 return wcspbrk(str
, match
);
758 BOOL WINAPI
StrTrimA(char *str
, const char *trim
)
764 TRACE("%s, %s\n", debugstr_a(str
), debugstr_a(trim
));
769 while (*ptr
&& StrChrA(trim
, *ptr
))
770 ptr
= CharNextA(ptr
); /* Skip leading matches */
776 memmove(str
, ptr
, len
+ 1);
783 while (StrChrA(trim
, ptr
[-1]))
784 ptr
= CharPrevA(str
, ptr
); /* Skip trailing matches */
786 if (ptr
!= str
+ len
)
796 BOOL WINAPI
StrTrimW(WCHAR
*str
, const WCHAR
*trim
)
802 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(trim
));
807 while (*ptr
&& StrChrW(trim
, *ptr
))
814 memmove(str
, ptr
, (len
+ 1) * sizeof(WCHAR
));
821 while (StrChrW(trim
, ptr
[-1]))
822 ptr
--; /* Skip trailing matches */
824 if (ptr
!= str
+ len
)
834 BOOL WINAPI
StrToInt64ExA(const char *str
, DWORD flags
, LONGLONG
*ret
)
836 BOOL negative
= FALSE
;
839 TRACE("%s, %#lx, %p\n", wine_dbgstr_a(str
), flags
, ret
);
844 if (flags
> STIF_SUPPORT_HEX
)
845 WARN("Unknown flags %#lx\n", flags
);
847 /* Skip leading space, '+', '-' */
848 while (*str
== ' ' || *str
== '\t' || *str
== '\n') str
++;
855 else if (*str
== '+')
858 if (flags
& STIF_SUPPORT_HEX
&& *str
== '0' && (str
[1] == 'x' || str
[1] == 'X'))
860 /* Read hex number */
866 while (isxdigit(*str
))
869 if (*str
>= '0' && *str
<= '9')
870 value
+= (*str
- '0');
871 else if (*str
>= 'A' && *str
<= 'F')
872 value
+= 10 + *str
- 'A';
874 value
+= 10 + *str
- 'a';
882 /* Read decimal number */
883 if (*str
< '0' || *str
> '9')
886 while (*str
>= '0' && *str
<= '9')
889 value
+= (*str
- '0');
893 *ret
= negative
? -value
: value
;
897 BOOL WINAPI
StrToInt64ExW(const WCHAR
*str
, DWORD flags
, LONGLONG
*ret
)
899 BOOL negative
= FALSE
;
902 TRACE("%s, %#lx, %p\n", wine_dbgstr_w(str
), flags
, ret
);
907 if (flags
> STIF_SUPPORT_HEX
)
908 WARN("Unknown flags %#lx.\n", flags
);
910 /* Skip leading space, '+', '-' */
911 while (*str
== ' ' || *str
== '\t' || *str
== '\n') str
++;
918 else if (*str
== '+')
921 if (flags
& STIF_SUPPORT_HEX
&& *str
== '0' && (str
[1] == 'x' || str
[1] == 'X'))
923 /* Read hex number */
929 while (isxdigit(*str
))
932 if (*str
>= '0' && *str
<= '9')
933 value
+= (*str
- '0');
934 else if (*str
>= 'A' && *str
<= 'Z')
935 value
+= 10 + (*str
- 'A');
937 value
+= 10 + (*str
- 'a');
945 /* Read decimal number */
946 if (*str
< '0' || *str
> '9')
949 while (*str
>= '0' && *str
<= '9')
952 value
+= (*str
- '0');
956 *ret
= negative
? -value
: value
;
960 BOOL WINAPI
StrToIntExA(const char *str
, DWORD flags
, INT
*ret
)
965 TRACE("%s, %#lx, %p\n", wine_dbgstr_a(str
), flags
, ret
);
967 res
= StrToInt64ExA(str
, flags
, &value
);
968 if (res
) *ret
= value
;
972 BOOL WINAPI
StrToIntExW(const WCHAR
*str
, DWORD flags
, INT
*ret
)
977 TRACE("%s, %#lx, %p\n", wine_dbgstr_w(str
), flags
, ret
);
979 res
= StrToInt64ExW(str
, flags
, &value
);
980 if (res
) *ret
= value
;
984 int WINAPI
StrToIntA(const char *str
)
988 TRACE("%s\n", wine_dbgstr_a(str
));
993 if (*str
== '-' || (*str
>= '0' && *str
<= '9'))
994 StrToIntExA(str
, 0, &value
);
999 int WINAPI
StrToIntW(const WCHAR
*str
)
1003 TRACE("%s\n", wine_dbgstr_w(str
));
1008 if (*str
== '-' || (*str
>= '0' && *str
<= '9'))
1009 StrToIntExW(str
, 0, &value
);
1013 char * WINAPI
StrCpyNXA(char *dst
, const char *src
, int len
)
1015 TRACE("%p, %s, %i\n", dst
, wine_dbgstr_a(src
), len
);
1017 if (dst
&& src
&& len
> 0)
1019 while ((len
-- > 1) && *src
)
1028 WCHAR
* WINAPI
StrCpyNXW(WCHAR
*dst
, const WCHAR
*src
, int len
)
1030 TRACE("%p, %s, %i\n", dst
, wine_dbgstr_w(src
), len
);
1032 if (dst
&& src
&& len
> 0)
1034 while ((len
-- > 1) && *src
)
1043 LPSTR WINAPI
CharLowerA(char *str
)
1045 if (IS_INTRESOURCE(str
))
1047 char ch
= LOWORD(str
);
1048 CharLowerBuffA( &ch
, 1 );
1049 return (LPSTR
)(UINT_PTR
)(BYTE
)ch
;
1054 CharLowerBuffA( str
, strlen(str
) );
1058 SetLastError( ERROR_INVALID_PARAMETER
);
1065 DWORD WINAPI
CharLowerBuffA(char *str
, DWORD len
)
1069 WCHAR
*strW
= buffer
;
1071 if (!str
) return 0; /* YES */
1073 lenW
= MultiByteToWideChar(CP_ACP
, 0, str
, len
, NULL
, 0);
1074 if (lenW
> ARRAY_SIZE(buffer
))
1076 strW
= HeapAlloc(GetProcessHeap(), 0, lenW
* sizeof(WCHAR
));
1077 if (!strW
) return 0;
1079 MultiByteToWideChar(CP_ACP
, 0, str
, len
, strW
, lenW
);
1080 CharLowerBuffW(strW
, lenW
);
1081 len
= WideCharToMultiByte(CP_ACP
, 0, strW
, lenW
, str
, len
, NULL
, NULL
);
1082 if (strW
!= buffer
) HeapFree(GetProcessHeap(), 0, strW
);
1086 DWORD WINAPI
CharLowerBuffW(WCHAR
*str
, DWORD len
)
1088 if (!str
) return 0; /* YES */
1089 return LCMapStringW(LOCALE_USER_DEFAULT
, LCMAP_LOWERCASE
, str
, len
, str
, len
);
1092 LPWSTR WINAPI
CharLowerW(WCHAR
*str
)
1094 if (!IS_INTRESOURCE(str
))
1096 CharLowerBuffW(str
, lstrlenW(str
));
1101 WCHAR ch
= LOWORD(str
);
1102 CharLowerBuffW(&ch
, 1);
1103 return (LPWSTR
)(UINT_PTR
)ch
;
1107 LPSTR WINAPI
CharNextA(const char *ptr
)
1109 if (!*ptr
) return (LPSTR
)ptr
;
1110 if (IsDBCSLeadByte( ptr
[0] ) && ptr
[1]) return (LPSTR
)(ptr
+ 2);
1111 return (LPSTR
)(ptr
+ 1);
1114 LPSTR WINAPI
CharNextExA(WORD codepage
, const char *ptr
, DWORD flags
)
1116 if (!*ptr
) return (LPSTR
)ptr
;
1117 if (IsDBCSLeadByteEx( codepage
, ptr
[0] ) && ptr
[1]) return (LPSTR
)(ptr
+ 2);
1118 return (LPSTR
)(ptr
+ 1);
1121 LPWSTR WINAPI
CharNextW(const WCHAR
*x
)
1128 LPSTR WINAPI
CharPrevA(const char *start
, const char *ptr
)
1130 while (*start
&& (start
< ptr
))
1132 LPCSTR next
= CharNextA(start
);
1133 if (next
>= ptr
) break;
1136 return (LPSTR
)start
;
1139 LPSTR WINAPI
CharPrevExA(WORD codepage
, const char *start
, const char *ptr
, DWORD flags
)
1141 while (*start
&& (start
< ptr
))
1143 LPCSTR next
= CharNextExA(codepage
, start
, flags
);
1144 if (next
>= ptr
) break;
1147 return (LPSTR
)start
;
1150 LPWSTR WINAPI
CharPrevW(const WCHAR
*start
, const WCHAR
*x
)
1152 if (x
> start
) return (LPWSTR
)(x
- 1);
1153 else return (LPWSTR
)x
;
1156 LPSTR WINAPI
CharUpperA(LPSTR str
)
1158 if (IS_INTRESOURCE(str
))
1160 char ch
= LOWORD(str
);
1161 CharUpperBuffA(&ch
, 1);
1162 return (LPSTR
)(UINT_PTR
)(BYTE
)ch
;
1167 CharUpperBuffA(str
, strlen(str
));
1171 SetLastError(ERROR_INVALID_PARAMETER
);
1178 DWORD WINAPI
CharUpperBuffA(LPSTR str
, DWORD len
)
1182 WCHAR
*strW
= buffer
;
1184 if (!str
) return 0; /* YES */
1186 lenW
= MultiByteToWideChar(CP_ACP
, 0, str
, len
, NULL
, 0);
1187 if (lenW
> ARRAY_SIZE(buffer
))
1189 strW
= HeapAlloc(GetProcessHeap(), 0, lenW
* sizeof(WCHAR
));
1190 if (!strW
) return 0;
1192 MultiByteToWideChar(CP_ACP
, 0, str
, len
, strW
, lenW
);
1193 CharUpperBuffW(strW
, lenW
);
1194 len
= WideCharToMultiByte(CP_ACP
, 0, strW
, lenW
, str
, len
, NULL
, NULL
);
1195 if (strW
!= buffer
) HeapFree(GetProcessHeap(), 0, strW
);
1199 DWORD WINAPI
CharUpperBuffW(WCHAR
*str
, DWORD len
)
1201 if (!str
) return 0; /* YES */
1202 return LCMapStringW(LOCALE_USER_DEFAULT
, LCMAP_UPPERCASE
, str
, len
, str
, len
);
1205 LPWSTR WINAPI
CharUpperW(WCHAR
*str
)
1207 if (!IS_INTRESOURCE(str
))
1209 CharUpperBuffW(str
, lstrlenW(str
));
1214 WCHAR ch
= LOWORD(str
);
1215 CharUpperBuffW(&ch
, 1);
1216 return (LPWSTR
)(UINT_PTR
)ch
;
1220 INT WINAPI DECLSPEC_HOTPATCH
LoadStringW(HINSTANCE instance
, UINT resource_id
, LPWSTR buffer
, INT buflen
)
1227 TRACE("instance = %p, id = %04x, buffer = %p, length = %d\n", instance
, resource_id
, buffer
, buflen
);
1232 /* Use loword (incremented by 1) as resourceid */
1233 hrsrc
= FindResourceW(instance
, MAKEINTRESOURCEW((LOWORD(resource_id
) >> 4) + 1), (LPWSTR
)RT_STRING
);
1234 if (!hrsrc
) return 0;
1235 hmem
= LoadResource(instance
, hrsrc
);
1236 if (!hmem
) return 0;
1238 p
= LockResource(hmem
);
1239 string_num
= resource_id
& 0x000f;
1240 for (i
= 0; i
< string_num
; i
++)
1243 TRACE("strlen = %d\n", (int)*p
);
1245 /*if buflen == 0, then return a read-only pointer to the resource itself in buffer
1246 it is assumed that buffer is actually a (LPWSTR *) */
1249 *((LPWSTR
*)buffer
) = p
+ 1;
1253 i
= min(buflen
- 1, *p
);
1256 memcpy(buffer
, p
+ 1, i
* sizeof (WCHAR
));
1268 TRACE("returning %s\n", debugstr_w(buffer
));
1272 INT WINAPI DECLSPEC_HOTPATCH
LoadStringA(HINSTANCE instance
, UINT resource_id
, LPSTR buffer
, INT buflen
)
1278 TRACE("instance = %p, id = %04x, buffer = %p, length = %d\n", instance
, resource_id
, buffer
, buflen
);
1280 if (!buflen
) return -1;
1282 /* Use loword (incremented by 1) as resourceid */
1283 if ((hrsrc
= FindResourceW(instance
, MAKEINTRESOURCEW((LOWORD(resource_id
) >> 4) + 1), (LPWSTR
)RT_STRING
)) &&
1284 (hmem
= LoadResource(instance
, hrsrc
)))
1286 const WCHAR
*p
= LockResource(hmem
);
1287 unsigned int id
= resource_id
& 0x000f;
1289 while (id
--) p
+= *p
+ 1;
1291 RtlUnicodeToMultiByteN(buffer
, buflen
- 1, &retval
, p
+ 1, *p
* sizeof(WCHAR
));
1294 TRACE("returning %s\n", debugstr_a(buffer
));
1298 int WINAPI
StrCmpLogicalW(const WCHAR
*str
, const WCHAR
*comp
)
1300 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(comp
));
1309 else if (*str
>= '0' && *str
<= '9')
1311 int str_value
, comp_value
;
1313 if (*comp
< '0' || *comp
> '9')
1316 /* Compare the numbers */
1317 StrToIntExW(str
, 0, &str_value
);
1318 StrToIntExW(comp
, 0, &comp_value
);
1320 if (str_value
< comp_value
)
1322 else if (str_value
> comp_value
)
1326 while (*str
>= '0' && *str
<= '9') str
++;
1327 while (*comp
>= '0' && *comp
<= '9') comp
++;
1329 else if (*comp
>= '0' && *comp
<= '9')
1333 int diff
= ChrCmpIW(*str
, *comp
);
1350 BOOL WINAPI
StrIsIntlEqualA(BOOL case_sensitive
, const char *str
, const char *cmp
, int len
)
1354 TRACE("%d, %s, %s, %d\n", case_sensitive
, wine_dbgstr_a(str
), wine_dbgstr_a(cmp
), len
);
1356 /* FIXME: This flag is undocumented and unknown by our CompareString.
1357 * We need a define for it.
1360 if (!case_sensitive
)
1361 flags
|= NORM_IGNORECASE
;
1363 return (CompareStringA(GetThreadLocale(), flags
, str
, len
, cmp
, len
) == CSTR_EQUAL
);
1366 BOOL WINAPI
StrIsIntlEqualW(BOOL case_sensitive
, const WCHAR
*str
, const WCHAR
*cmp
, int len
)
1370 TRACE("%d, %s, %s, %d\n", case_sensitive
, debugstr_w(str
), debugstr_w(cmp
), len
);
1372 /* FIXME: This flag is undocumented and unknown by our CompareString.
1373 * We need a define for it.
1376 if (!case_sensitive
)
1377 flags
|= NORM_IGNORECASE
;
1379 return (CompareStringW(GetThreadLocale(), flags
, str
, len
, cmp
, len
) == CSTR_EQUAL
);
1382 char * WINAPI
StrCatBuffA(char *str
, const char *cat
, INT max_len
)
1386 TRACE("%p, %s, %d\n", str
, wine_dbgstr_a(cat
), max_len
);
1394 StrCpyNA(str
+ len
, cat
, max_len
);
1399 WCHAR
* WINAPI
StrCatBuffW(WCHAR
*str
, const WCHAR
*cat
, INT max_len
)
1403 TRACE("%p, %s, %d\n", str
, wine_dbgstr_w(cat
), max_len
);
1408 len
= lstrlenW(str
);
1411 StrCpyNW(str
+ len
, cat
, max_len
);
1416 DWORD WINAPI
StrCatChainW(WCHAR
*str
, DWORD max_len
, DWORD at
, const WCHAR
*cat
)
1418 TRACE("%s, %lu, %ld, %s\n", wine_dbgstr_w(str
), max_len
, at
, wine_dbgstr_w(cat
));
1429 if (cat
&& at
< max_len
)
1432 while (at
< max_len
- 1 && *cat
)
1443 DWORD WINAPI
SHTruncateString(char *str
, DWORD size
)
1450 last_byte
= str
+ size
- 1;
1452 while (str
< last_byte
)
1453 str
+= IsDBCSLeadByte(*str
) ? 2 : 1;
1455 if (str
== last_byte
&& IsDBCSLeadByte(*str
))
1464 HRESULT WINAPI
SHLoadIndirectString(const WCHAR
*src
, WCHAR
*dst
, UINT dst_len
, void **reserved
)
1466 WCHAR
*dllname
= NULL
;
1467 HMODULE hmod
= NULL
;
1468 HRESULT hr
= E_FAIL
;
1470 TRACE("%s, %p, %#x, %p\n", debugstr_w(src
), dst
, dst_len
, reserved
);
1478 dllname
= StrDupW(src
+ 1);
1479 index_str
= wcschr(dllname
, ',');
1481 if(!index_str
) goto end
;
1485 index
= wcstol(index_str
, NULL
, 10);
1487 hmod
= LoadLibraryW(dllname
);
1488 if (!hmod
) goto end
;
1492 if (LoadStringW(hmod
, -index
, dst
, dst_len
))
1496 FIXME("can't handle non-negative indices (%d)\n", index
);
1501 lstrcpynW(dst
, src
, dst_len
);
1505 TRACE("returning %s\n", debugstr_w(dst
));
1507 if (hmod
) FreeLibrary(hmod
);