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 #define isxdigit(ch) (((ch) >= '0' && (ch) <= '9') || \
34 ((ch) >= 'A' && (ch) <= 'F') || \
35 ((ch) >= 'a' && (ch) <= 'f'))
37 static BOOL
char_compare(WORD ch1
, WORD ch2
, DWORD flags
)
39 char str1
[3], str2
[3];
41 str1
[0] = LOBYTE(ch1
);
42 if (IsDBCSLeadByte(str1
[0]))
44 str1
[1] = HIBYTE(ch1
);
50 str2
[0] = LOBYTE(ch2
);
51 if (IsDBCSLeadByte(str2
[0]))
53 str2
[1] = HIBYTE(ch2
);
59 return CompareStringA(GetThreadLocale(), flags
, str1
, -1, str2
, -1) - CSTR_EQUAL
;
62 int WINAPI
lstrcmpA( LPCSTR str1
, LPCSTR str2
)
64 if (!str1
&& !str2
) return 0;
67 return CompareStringA( GetThreadLocale(), LOCALE_USE_CP_ACP
, str1
, -1, str2
, -1 ) - 2;
70 int WINAPI
lstrcmpW(LPCWSTR str1
, LPCWSTR str2
)
72 if (!str1
&& !str2
) return 0;
75 return CompareStringW( GetThreadLocale(), 0, str1
, -1, str2
, -1 ) - 2;
78 int WINAPI
lstrcmpiA(LPCSTR str1
, LPCSTR str2
)
80 if (!str1
&& !str2
) return 0;
83 return CompareStringA( GetThreadLocale(), NORM_IGNORECASE
|LOCALE_USE_CP_ACP
, str1
, -1, str2
, -1 ) - 2;
86 int WINAPI
lstrcmpiW(LPCWSTR str1
, LPCWSTR str2
)
88 if (!str1
&& !str2
) return 0;
91 return CompareStringW( GetThreadLocale(), NORM_IGNORECASE
, str1
, -1, str2
, -1 ) - 2;
94 LPSTR WINAPI
KERNELBASE_lstrcpynA( LPSTR dst
, LPCSTR src
, INT n
)
96 /* Note: this function differs from the UNIX strncpy, it _always_ writes
99 * Note: n is an INT but Windows treats it as unsigned, and will happily
100 * copy a gazillion chars if n is negative.
108 while ((count
> 1) && *s
)
117 SetLastError( ERROR_INVALID_PARAMETER
);
124 LPWSTR WINAPI
KERNELBASE_lstrcpynW( LPWSTR dst
, LPCWSTR src
, INT n
)
126 /* Note: this function differs from the UNIX strncpy, it _always_ writes
129 * Note: n is an INT but Windows treats it as unsigned, and will happily
130 * copy a gazillion chars if n is negative.
138 while ((count
> 1) && *s
)
147 SetLastError( ERROR_INVALID_PARAMETER
);
154 INT WINAPI
KERNELBASE_lstrlenA( LPCSTR str
)
163 SetLastError( ERROR_INVALID_PARAMETER
);
170 INT WINAPI
KERNELBASE_lstrlenW( LPCWSTR str
)
179 SetLastError( ERROR_INVALID_PARAMETER
);
186 DWORD WINAPI
StrCmpCA(const char *str
, const char *cmp
)
188 return lstrcmpA(str
, cmp
);
191 DWORD WINAPI
StrCmpCW(const WCHAR
*str
, const WCHAR
*cmp
)
193 return lstrcmpW(str
, cmp
);
196 DWORD WINAPI
StrCmpICA(const char *str
, const char *cmp
)
198 return lstrcmpiA(str
, cmp
);
201 DWORD WINAPI
StrCmpICW(const WCHAR
*str
, const WCHAR
*cmp
)
203 return lstrcmpiW(str
, cmp
);
206 DWORD WINAPI
StrCmpNICA(const char *str
, const char *cmp
, DWORD len
)
208 return StrCmpNIA(str
, cmp
, len
);
211 DWORD WINAPI
StrCmpNICW(const WCHAR
*str
, const WCHAR
*cmp
, DWORD len
)
213 return StrCmpNIW(str
, cmp
, len
);
216 char * WINAPI
StrChrA(const char *str
, WORD ch
)
218 TRACE("%s, %#x\n", wine_dbgstr_a(str
), ch
);
225 if (!char_compare(*str
, ch
, 0))
227 str
= CharNextA(str
);
233 WCHAR
* WINAPI
StrChrW(const WCHAR
*str
, WCHAR ch
)
235 TRACE("%s, %#x\n", wine_dbgstr_w(str
), ch
);
240 return wcschr(str
, ch
);
243 char * WINAPI
StrChrIA(const char *str
, WORD ch
)
245 TRACE("%s, %i\n", wine_dbgstr_a(str
), ch
);
252 if (!ChrCmpIA(*str
, ch
))
254 str
= CharNextA(str
);
260 WCHAR
* WINAPI
StrChrIW(const WCHAR
*str
, WCHAR ch
)
262 TRACE("%s, %#x\n", wine_dbgstr_w(str
), ch
);
270 if (towupper(*str
) == ch
)
279 WCHAR
* WINAPI
StrChrNW(const WCHAR
*str
, WCHAR ch
, UINT max_len
)
281 TRACE("%s, %#x, %u\n", wine_dbgstr_wn(str
, max_len
), ch
, max_len
);
286 while (*str
&& max_len
-- > 0)
296 char * WINAPI
StrDupA(const char *str
)
301 TRACE("%s\n", wine_dbgstr_a(str
));
303 len
= str
? strlen(str
) + 1 : 1;
304 ret
= LocalAlloc(LMEM_FIXED
, len
);
309 memcpy(ret
, str
, len
);
317 WCHAR
* WINAPI
StrDupW(const WCHAR
*str
)
322 TRACE("%s\n", wine_dbgstr_w(str
));
324 len
= (str
? lstrlenW(str
) + 1 : 1) * sizeof(WCHAR
);
325 ret
= LocalAlloc(LMEM_FIXED
, len
);
330 memcpy(ret
, str
, len
);
338 BOOL WINAPI
ChrCmpIA(WORD ch1
, WORD ch2
)
340 TRACE("%#x, %#x\n", ch1
, ch2
);
342 return char_compare(ch1
, ch2
, NORM_IGNORECASE
);
345 BOOL WINAPI
ChrCmpIW(WCHAR ch1
, WCHAR ch2
)
347 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, &ch1
, 1, &ch2
, 1) - CSTR_EQUAL
;
350 char * WINAPI
StrStrA(const char *str
, const char *search
)
355 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(search
));
357 if (!str
|| !search
|| !*search
) return NULL
;
359 len
= strlen(search
);
360 end
= str
+ strlen(str
);
362 while (str
+ len
<= end
)
364 if (!StrCmpNA(str
, search
, len
)) return (char *)str
;
365 str
= CharNextA(str
);
370 WCHAR
* WINAPI
StrStrW(const WCHAR
*str
, const WCHAR
*search
)
372 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(search
));
374 if (!str
|| !search
|| !*search
)
377 return wcsstr(str
, search
);
380 WCHAR
* WINAPI
StrStrNW(const WCHAR
*str
, const WCHAR
*search
, UINT max_len
)
384 TRACE("%s, %s, %u\n", wine_dbgstr_w(str
), wine_dbgstr_w(search
), max_len
);
386 if (!str
|| !search
|| !*search
|| !max_len
)
389 len
= lstrlenW(search
);
391 for (i
= max_len
; *str
&& (i
> 0); i
--, str
++)
393 if (!wcsncmp(str
, search
, len
))
400 int WINAPI
StrCmpNIA(const char *str
, const char *cmp
, int len
)
402 TRACE("%s, %s, %i\n", wine_dbgstr_a(str
), wine_dbgstr_a(cmp
), len
);
403 return CompareStringA(GetThreadLocale(), NORM_IGNORECASE
, str
, len
, cmp
, len
) - CSTR_EQUAL
;
406 WCHAR
* WINAPI
StrStrNIW(const WCHAR
*str
, const WCHAR
*search
, UINT max_len
)
410 TRACE("%s, %s, %u\n", wine_dbgstr_w(str
), wine_dbgstr_w(search
), max_len
);
412 if (!str
|| !search
|| !*search
|| !max_len
)
415 len
= lstrlenW(search
);
417 for (i
= max_len
; *str
&& (i
> 0); i
--, str
++)
419 if (!StrCmpNIW(str
, search
, len
))
426 int WINAPI
StrCmpNA(const char *str
, const char *comp
, int len
)
428 TRACE("%s, %s, %i\n", wine_dbgstr_a(str
), wine_dbgstr_a(comp
), len
);
429 return CompareStringA(GetThreadLocale(), 0, str
, len
, comp
, len
) - CSTR_EQUAL
;
432 int WINAPI
StrCmpNW(const WCHAR
*str
, const WCHAR
*comp
, int len
)
434 TRACE("%s, %s, %i\n", wine_dbgstr_w(str
), wine_dbgstr_w(comp
), len
);
435 return CompareStringW(GetThreadLocale(), 0, str
, len
, comp
, len
) - CSTR_EQUAL
;
438 DWORD WINAPI
StrCmpNCA(const char *str
, const char *comp
, int len
)
440 return StrCmpNA(str
, comp
, len
);
443 DWORD WINAPI
StrCmpNCW(const WCHAR
*str
, const WCHAR
*comp
, int len
)
445 return StrCmpNW(str
, comp
, len
);
448 int WINAPI
StrCmpNIW(const WCHAR
*str
, const WCHAR
*comp
, int len
)
450 TRACE("%s, %s, %i\n", wine_dbgstr_w(str
), wine_dbgstr_w(comp
), len
);
451 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, str
, len
, comp
, len
) - CSTR_EQUAL
;
454 int WINAPI
StrCmpW(const WCHAR
*str
, const WCHAR
*comp
)
456 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(comp
));
457 return CompareStringW(GetThreadLocale(), 0, str
, -1, comp
, -1) - CSTR_EQUAL
;
460 int WINAPI
StrCmpIW(const WCHAR
*str
, const WCHAR
*comp
)
462 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(comp
));
463 return CompareStringW(GetThreadLocale(), NORM_IGNORECASE
, str
, -1, comp
, -1) - CSTR_EQUAL
;
466 WCHAR
* WINAPI
StrCpyNW(WCHAR
*dst
, const WCHAR
*src
, int count
)
468 const WCHAR
*s
= src
;
471 TRACE("%p, %s, %i\n", dst
, wine_dbgstr_w(src
), count
);
475 while ((count
> 1) && *s
)
486 char * WINAPI
StrStrIA(const char *str
, const char *search
)
491 TRACE("%s, %s\n", wine_dbgstr_a(str
), debugstr_a(search
));
493 if (!str
|| !search
|| !*search
) return NULL
;
495 len
= strlen(search
);
496 end
= str
+ strlen(str
);
498 while (str
+ len
<= end
)
500 if (!StrCmpNIA(str
, search
, len
)) return (char *)str
;
501 str
= CharNextA(str
);
506 WCHAR
* WINAPI
StrStrIW(const WCHAR
*str
, const WCHAR
*search
)
511 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(search
));
513 if (!str
|| !search
|| !*search
)
516 len
= lstrlenW(search
);
517 end
= str
+ lstrlenW(str
);
519 while (str
+ len
<= end
)
521 if (!StrCmpNIW(str
, search
, len
))
529 int WINAPI
StrSpnA(const char *str
, const char *match
)
531 const char *ptr
= str
;
533 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(match
));
535 if (!str
|| !match
) return 0;
539 if (!StrChrA(match
, *ptr
)) break;
540 ptr
= CharNextA(ptr
);
545 int WINAPI
StrSpnW(const WCHAR
*str
, const WCHAR
*match
)
547 if (!str
|| !match
) return 0;
548 return wcsspn(str
, match
);
551 int WINAPI
StrCSpnA(const char *str
, const char *match
)
553 const char *ptr
= str
;
555 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(match
));
557 if (!str
|| !match
) return 0;
561 if (StrChrA(match
, *ptr
)) break;
562 ptr
= CharNextA(ptr
);
567 int WINAPI
StrCSpnW(const WCHAR
*str
, const WCHAR
*match
)
572 return wcscspn(str
, match
);
575 int WINAPI
StrCSpnIA(const char *str
, const char *match
)
577 const char *ptr
= str
;
579 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(match
));
581 if (!str
|| !match
) return 0;
585 if (StrChrIA(match
, *ptr
)) break;
586 ptr
= CharNextA(ptr
);
591 int WINAPI
StrCSpnIW(const WCHAR
*str
, const WCHAR
*match
)
593 const WCHAR
*ptr
= str
;
595 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(match
));
597 if (!str
|| !*str
|| !match
)
602 if (StrChrIW(match
, *ptr
)) break;
609 char * WINAPI
StrRChrA(const char *str
, const char *end
, WORD ch
)
611 const char *ret
= NULL
;
613 TRACE("%s, %s, %#x\n", wine_dbgstr_a(str
), wine_dbgstr_a(end
), ch
);
615 if (!str
) return NULL
;
616 if (!end
) end
= str
+ lstrlenA(str
);
617 while (*str
&& str
<= end
)
619 WORD ch2
= IsDBCSLeadByte(*str
) ? *str
<< 8 | str
[1] : *str
;
620 if (!char_compare(ch
, ch2
, 0)) ret
= str
;
621 str
= CharNextA(str
);
626 WCHAR
* WINAPI
StrRChrW(const WCHAR
*str
, const WCHAR
*end
, WORD ch
)
630 if (!str
) return NULL
;
631 if (!end
) end
= str
+ lstrlenW(str
);
634 if (*str
== ch
) ret
= (WCHAR
*)str
;
640 char * WINAPI
StrRChrIA(const char *str
, const char *end
, WORD ch
)
642 const char *ret
= NULL
;
644 TRACE("%s, %s, %#x\n", wine_dbgstr_a(str
), wine_dbgstr_a(end
), ch
);
646 if (!str
) return NULL
;
647 if (!end
) end
= str
+ lstrlenA(str
);
649 while (*str
&& str
<= end
)
651 WORD ch2
= IsDBCSLeadByte(*str
) ? *str
<< 8 | str
[1] : *str
;
652 if (!ChrCmpIA(ch
, ch2
)) ret
= str
;
653 str
= CharNextA(str
);
658 WCHAR
* WINAPI
StrRChrIW(const WCHAR
*str
, const WCHAR
*end
, WORD ch
)
662 if (!str
) return NULL
;
663 if (!end
) end
= str
+ lstrlenW(str
);
666 if (!ChrCmpIW(*str
, ch
)) ret
= (WCHAR
*)str
;
672 char * WINAPI
StrRStrIA(const char *str
, const char *end
, const char *search
)
678 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(search
));
680 if (!str
|| !search
|| !*search
)
683 if (IsDBCSLeadByte(*search
))
684 ch1
= *search
<< 8 | (UCHAR
)search
[1];
687 len
= lstrlenA(search
);
690 end
= str
+ lstrlenA(str
);
691 else /* reproduce the broken behaviour on Windows */
692 end
+= min(len
- 1, lstrlenA(end
));
694 while (str
+ len
<= end
&& *str
)
696 ch2
= IsDBCSLeadByte(*str
) ? *str
<< 8 | (UCHAR
)str
[1] : *str
;
697 if (!ChrCmpIA(ch1
, ch2
))
699 if (!StrCmpNIA(str
, search
, len
))
703 str
= CharNextA(str
);
709 WCHAR
* WINAPI
StrRStrIW(const WCHAR
*str
, const WCHAR
*end
, const WCHAR
*search
)
714 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(search
));
716 if (!str
|| !search
|| !*search
)
719 len
= lstrlenW(search
);
722 end
= str
+ lstrlenW(str
);
724 end
+= min(len
- 1, lstrlenW(end
));
726 while (str
+ len
<= end
&& *str
)
728 if (!ChrCmpIW(*search
, *str
))
730 if (!StrCmpNIW(str
, search
, len
))
739 char * WINAPI
StrPBrkA(const char *str
, const char *match
)
741 TRACE("%s, %s\n", wine_dbgstr_a(str
), wine_dbgstr_a(match
));
743 if (!str
|| !match
|| !*match
)
748 if (StrChrA(match
, *str
))
750 str
= CharNextA(str
);
756 WCHAR
* WINAPI
StrPBrkW(const WCHAR
*str
, const WCHAR
*match
)
758 if (!str
|| !match
) return NULL
;
759 return wcspbrk(str
, match
);
762 BOOL WINAPI
StrTrimA(char *str
, const char *trim
)
768 TRACE("%s, %s\n", debugstr_a(str
), debugstr_a(trim
));
773 while (*ptr
&& StrChrA(trim
, *ptr
))
774 ptr
= CharNextA(ptr
); /* Skip leading matches */
780 memmove(str
, ptr
, len
+ 1);
787 while (StrChrA(trim
, ptr
[-1]))
788 ptr
= CharPrevA(str
, ptr
); /* Skip trailing matches */
790 if (ptr
!= str
+ len
)
800 BOOL WINAPI
StrTrimW(WCHAR
*str
, const WCHAR
*trim
)
806 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(trim
));
811 while (*ptr
&& StrChrW(trim
, *ptr
))
818 memmove(str
, ptr
, (len
+ 1) * sizeof(WCHAR
));
825 while (StrChrW(trim
, ptr
[-1]))
826 ptr
--; /* Skip trailing matches */
828 if (ptr
!= str
+ len
)
838 BOOL WINAPI
StrToInt64ExA(const char *str
, DWORD flags
, LONGLONG
*ret
)
840 BOOL negative
= FALSE
;
843 TRACE("%s, %#x, %p\n", wine_dbgstr_a(str
), flags
, ret
);
848 if (flags
> STIF_SUPPORT_HEX
)
849 WARN("Unknown flags %#x\n", flags
);
851 /* Skip leading space, '+', '-' */
852 while (*str
== ' ' || *str
== '\t' || *str
== '\n') str
++;
859 else if (*str
== '+')
862 if (flags
& STIF_SUPPORT_HEX
&& *str
== '0' && (str
[1] == 'x' || str
[1] == 'X'))
864 /* Read hex number */
870 while (isxdigit(*str
))
873 if (*str
>= '0' && *str
<= '9')
874 value
+= (*str
- '0');
875 else if (*str
>= 'A' && *str
<= 'F')
876 value
+= 10 + *str
- 'A';
878 value
+= 10 + *str
- 'a';
886 /* Read decimal number */
887 if (*str
< '0' || *str
> '9')
890 while (*str
>= '0' && *str
<= '9')
893 value
+= (*str
- '0');
897 *ret
= negative
? -value
: value
;
901 BOOL WINAPI
StrToInt64ExW(const WCHAR
*str
, DWORD flags
, LONGLONG
*ret
)
903 BOOL negative
= FALSE
;
906 TRACE("%s, %#x, %p\n", wine_dbgstr_w(str
), flags
, ret
);
911 if (flags
> STIF_SUPPORT_HEX
)
912 WARN("Unknown flags %#x.\n", flags
);
914 /* Skip leading space, '+', '-' */
915 while (*str
== ' ' || *str
== '\t' || *str
== '\n') str
++;
922 else if (*str
== '+')
925 if (flags
& STIF_SUPPORT_HEX
&& *str
== '0' && (str
[1] == 'x' || str
[1] == 'X'))
927 /* Read hex number */
933 while (isxdigit(*str
))
936 if (*str
>= '0' && *str
<= '9')
937 value
+= (*str
- '0');
938 else if (*str
>= 'A' && *str
<= 'Z')
939 value
+= 10 + (*str
- 'A');
941 value
+= 10 + (*str
- 'a');
949 /* Read decimal number */
950 if (*str
< '0' || *str
> '9')
953 while (*str
>= '0' && *str
<= '9')
956 value
+= (*str
- '0');
960 *ret
= negative
? -value
: value
;
964 BOOL WINAPI
StrToIntExA(const char *str
, DWORD flags
, INT
*ret
)
969 TRACE("%s, %#x, %p\n", wine_dbgstr_a(str
), flags
, ret
);
971 res
= StrToInt64ExA(str
, flags
, &value
);
972 if (res
) *ret
= value
;
976 BOOL WINAPI
StrToIntExW(const WCHAR
*str
, DWORD flags
, INT
*ret
)
981 TRACE("%s, %#x, %p\n", wine_dbgstr_w(str
), flags
, ret
);
983 res
= StrToInt64ExW(str
, flags
, &value
);
984 if (res
) *ret
= value
;
988 int WINAPI
StrToIntA(const char *str
)
992 TRACE("%s\n", wine_dbgstr_a(str
));
997 if (*str
== '-' || (*str
>= '0' && *str
<= '9'))
998 StrToIntExA(str
, 0, &value
);
1003 int WINAPI
StrToIntW(const WCHAR
*str
)
1007 TRACE("%s\n", wine_dbgstr_w(str
));
1012 if (*str
== '-' || (*str
>= '0' && *str
<= '9'))
1013 StrToIntExW(str
, 0, &value
);
1017 char * WINAPI
StrCpyNXA(char *dst
, const char *src
, int len
)
1019 TRACE("%p, %s, %i\n", dst
, wine_dbgstr_a(src
), len
);
1021 if (dst
&& src
&& len
> 0)
1023 while ((len
-- > 1) && *src
)
1032 WCHAR
* WINAPI
StrCpyNXW(WCHAR
*dst
, const WCHAR
*src
, int len
)
1034 TRACE("%p, %s, %i\n", dst
, wine_dbgstr_w(src
), len
);
1036 if (dst
&& src
&& len
> 0)
1038 while ((len
-- > 1) && *src
)
1047 LPSTR WINAPI
CharLowerA(char *str
)
1049 if (IS_INTRESOURCE(str
))
1051 char ch
= LOWORD(str
);
1052 CharLowerBuffA( &ch
, 1 );
1053 return (LPSTR
)(UINT_PTR
)(BYTE
)ch
;
1058 CharLowerBuffA( str
, strlen(str
) );
1062 SetLastError( ERROR_INVALID_PARAMETER
);
1069 DWORD WINAPI
CharLowerBuffA(char *str
, DWORD len
)
1073 WCHAR
*strW
= buffer
;
1075 if (!str
) return 0; /* YES */
1077 lenW
= MultiByteToWideChar(CP_ACP
, 0, str
, len
, NULL
, 0);
1078 if (lenW
> ARRAY_SIZE(buffer
))
1080 strW
= HeapAlloc(GetProcessHeap(), 0, lenW
* sizeof(WCHAR
));
1081 if (!strW
) return 0;
1083 MultiByteToWideChar(CP_ACP
, 0, str
, len
, strW
, lenW
);
1084 CharLowerBuffW(strW
, lenW
);
1085 len
= WideCharToMultiByte(CP_ACP
, 0, strW
, lenW
, str
, len
, NULL
, NULL
);
1086 if (strW
!= buffer
) HeapFree(GetProcessHeap(), 0, strW
);
1090 DWORD WINAPI
CharLowerBuffW(WCHAR
*str
, DWORD len
)
1092 if (!str
) return 0; /* YES */
1093 return LCMapStringW(LOCALE_USER_DEFAULT
, LCMAP_LOWERCASE
, str
, len
, str
, len
);
1096 LPWSTR WINAPI
CharLowerW(WCHAR
*str
)
1098 if (!IS_INTRESOURCE(str
))
1100 CharLowerBuffW(str
, lstrlenW(str
));
1105 WCHAR ch
= LOWORD(str
);
1106 CharLowerBuffW(&ch
, 1);
1107 return (LPWSTR
)(UINT_PTR
)ch
;
1111 LPSTR WINAPI
CharNextA(const char *ptr
)
1113 if (!*ptr
) return (LPSTR
)ptr
;
1114 if (IsDBCSLeadByte( ptr
[0] ) && ptr
[1]) return (LPSTR
)(ptr
+ 2);
1115 return (LPSTR
)(ptr
+ 1);
1118 LPSTR WINAPI
CharNextExA(WORD codepage
, const char *ptr
, DWORD flags
)
1120 if (!*ptr
) return (LPSTR
)ptr
;
1121 if (IsDBCSLeadByteEx( codepage
, ptr
[0] ) && ptr
[1]) return (LPSTR
)(ptr
+ 2);
1122 return (LPSTR
)(ptr
+ 1);
1125 LPWSTR WINAPI
CharNextW(const WCHAR
*x
)
1132 LPSTR WINAPI
CharPrevA(const char *start
, const char *ptr
)
1134 while (*start
&& (start
< ptr
))
1136 LPCSTR next
= CharNextA(start
);
1137 if (next
>= ptr
) break;
1140 return (LPSTR
)start
;
1143 LPSTR WINAPI
CharPrevExA(WORD codepage
, const char *start
, const char *ptr
, DWORD flags
)
1145 while (*start
&& (start
< ptr
))
1147 LPCSTR next
= CharNextExA(codepage
, start
, flags
);
1148 if (next
>= ptr
) break;
1151 return (LPSTR
)start
;
1154 LPWSTR WINAPI
CharPrevW(const WCHAR
*start
, const WCHAR
*x
)
1156 if (x
> start
) return (LPWSTR
)(x
- 1);
1157 else return (LPWSTR
)x
;
1160 LPSTR WINAPI
CharUpperA(LPSTR str
)
1162 if (IS_INTRESOURCE(str
))
1164 char ch
= LOWORD(str
);
1165 CharUpperBuffA(&ch
, 1);
1166 return (LPSTR
)(UINT_PTR
)(BYTE
)ch
;
1171 CharUpperBuffA(str
, strlen(str
));
1175 SetLastError(ERROR_INVALID_PARAMETER
);
1182 DWORD WINAPI
CharUpperBuffA(LPSTR str
, DWORD len
)
1186 WCHAR
*strW
= buffer
;
1188 if (!str
) return 0; /* YES */
1190 lenW
= MultiByteToWideChar(CP_ACP
, 0, str
, len
, NULL
, 0);
1191 if (lenW
> ARRAY_SIZE(buffer
))
1193 strW
= HeapAlloc(GetProcessHeap(), 0, lenW
* sizeof(WCHAR
));
1194 if (!strW
) return 0;
1196 MultiByteToWideChar(CP_ACP
, 0, str
, len
, strW
, lenW
);
1197 CharUpperBuffW(strW
, lenW
);
1198 len
= WideCharToMultiByte(CP_ACP
, 0, strW
, lenW
, str
, len
, NULL
, NULL
);
1199 if (strW
!= buffer
) HeapFree(GetProcessHeap(), 0, strW
);
1203 DWORD WINAPI
CharUpperBuffW(WCHAR
*str
, DWORD len
)
1205 if (!str
) return 0; /* YES */
1206 return LCMapStringW(LOCALE_USER_DEFAULT
, LCMAP_UPPERCASE
, str
, len
, str
, len
);
1209 LPWSTR WINAPI
CharUpperW(WCHAR
*str
)
1211 if (!IS_INTRESOURCE(str
))
1213 CharUpperBuffW(str
, lstrlenW(str
));
1218 WCHAR ch
= LOWORD(str
);
1219 CharUpperBuffW(&ch
, 1);
1220 return (LPWSTR
)(UINT_PTR
)ch
;
1224 INT WINAPI DECLSPEC_HOTPATCH
LoadStringW(HINSTANCE instance
, UINT resource_id
, LPWSTR buffer
, INT buflen
)
1231 TRACE("instance = %p, id = %04x, buffer = %p, length = %d\n", instance
, resource_id
, buffer
, buflen
);
1236 /* Use loword (incremented by 1) as resourceid */
1237 hrsrc
= FindResourceW(instance
, MAKEINTRESOURCEW((LOWORD(resource_id
) >> 4) + 1), (LPWSTR
)RT_STRING
);
1238 if (!hrsrc
) return 0;
1239 hmem
= LoadResource(instance
, hrsrc
);
1240 if (!hmem
) return 0;
1242 p
= LockResource(hmem
);
1243 string_num
= resource_id
& 0x000f;
1244 for (i
= 0; i
< string_num
; i
++)
1247 TRACE("strlen = %d\n", (int)*p
);
1249 /*if buflen == 0, then return a read-only pointer to the resource itself in buffer
1250 it is assumed that buffer is actually a (LPWSTR *) */
1253 *((LPWSTR
*)buffer
) = p
+ 1;
1257 i
= min(buflen
- 1, *p
);
1260 memcpy(buffer
, p
+ 1, i
* sizeof (WCHAR
));
1272 TRACE("returning %s\n", debugstr_w(buffer
));
1276 INT WINAPI DECLSPEC_HOTPATCH
LoadStringA(HINSTANCE instance
, UINT resource_id
, LPSTR buffer
, INT buflen
)
1282 TRACE("instance = %p, id = %04x, buffer = %p, length = %d\n", instance
, resource_id
, buffer
, buflen
);
1284 if (!buflen
) return -1;
1286 /* Use loword (incremented by 1) as resourceid */
1287 if ((hrsrc
= FindResourceW(instance
, MAKEINTRESOURCEW((LOWORD(resource_id
) >> 4) + 1), (LPWSTR
)RT_STRING
)) &&
1288 (hmem
= LoadResource(instance
, hrsrc
)))
1290 const WCHAR
*p
= LockResource(hmem
);
1291 unsigned int id
= resource_id
& 0x000f;
1293 while (id
--) p
+= *p
+ 1;
1295 RtlUnicodeToMultiByteN(buffer
, buflen
- 1, &retval
, p
+ 1, *p
* sizeof(WCHAR
));
1298 TRACE("returning %s\n", debugstr_a(buffer
));
1302 int WINAPI
StrCmpLogicalW(const WCHAR
*str
, const WCHAR
*comp
)
1304 TRACE("%s, %s\n", wine_dbgstr_w(str
), wine_dbgstr_w(comp
));
1313 else if (*str
>= '0' && *str
<= '9')
1315 int str_value
, comp_value
;
1317 if (*comp
< '0' || *comp
> '9')
1320 /* Compare the numbers */
1321 StrToIntExW(str
, 0, &str_value
);
1322 StrToIntExW(comp
, 0, &comp_value
);
1324 if (str_value
< comp_value
)
1326 else if (str_value
> comp_value
)
1330 while (*str
>= '0' && *str
<= '9') str
++;
1331 while (*comp
>= '0' && *comp
<= '9') comp
++;
1333 else if (*comp
>= '0' && *comp
<= '9')
1337 int diff
= ChrCmpIW(*str
, *comp
);
1354 BOOL WINAPI
StrIsIntlEqualA(BOOL case_sensitive
, const char *str
, const char *cmp
, int len
)
1358 TRACE("%d, %s, %s, %d\n", case_sensitive
, wine_dbgstr_a(str
), wine_dbgstr_a(cmp
), len
);
1360 /* FIXME: This flag is undocumented and unknown by our CompareString.
1361 * We need a define for it.
1364 if (!case_sensitive
)
1365 flags
|= NORM_IGNORECASE
;
1367 return (CompareStringA(GetThreadLocale(), flags
, str
, len
, cmp
, len
) == CSTR_EQUAL
);
1370 BOOL WINAPI
StrIsIntlEqualW(BOOL case_sensitive
, const WCHAR
*str
, const WCHAR
*cmp
, int len
)
1374 TRACE("%d, %s, %s, %d\n", case_sensitive
, debugstr_w(str
), debugstr_w(cmp
), len
);
1376 /* FIXME: This flag is undocumented and unknown by our CompareString.
1377 * We need a define for it.
1380 if (!case_sensitive
)
1381 flags
|= NORM_IGNORECASE
;
1383 return (CompareStringW(GetThreadLocale(), flags
, str
, len
, cmp
, len
) == CSTR_EQUAL
);
1386 char * WINAPI
StrCatBuffA(char *str
, const char *cat
, INT max_len
)
1390 TRACE("%p, %s, %d\n", str
, wine_dbgstr_a(cat
), max_len
);
1398 StrCpyNA(str
+ len
, cat
, max_len
);
1403 WCHAR
* WINAPI
StrCatBuffW(WCHAR
*str
, const WCHAR
*cat
, INT max_len
)
1407 TRACE("%p, %s, %d\n", str
, wine_dbgstr_w(cat
), max_len
);
1412 len
= lstrlenW(str
);
1415 StrCpyNW(str
+ len
, cat
, max_len
);
1420 DWORD WINAPI
StrCatChainW(WCHAR
*str
, DWORD max_len
, DWORD at
, const WCHAR
*cat
)
1422 TRACE("%s, %u, %d, %s\n", wine_dbgstr_w(str
), max_len
, at
, wine_dbgstr_w(cat
));
1433 if (cat
&& at
< max_len
)
1436 while (at
< max_len
- 1 && *cat
)
1447 DWORD WINAPI
SHTruncateString(char *str
, DWORD size
)
1454 last_byte
= str
+ size
- 1;
1456 while (str
< last_byte
)
1457 str
+= IsDBCSLeadByte(*str
) ? 2 : 1;
1459 if (str
== last_byte
&& IsDBCSLeadByte(*str
))
1468 HRESULT WINAPI
SHLoadIndirectString(const WCHAR
*src
, WCHAR
*dst
, UINT dst_len
, void **reserved
)
1470 WCHAR
*dllname
= NULL
;
1471 HMODULE hmod
= NULL
;
1472 HRESULT hr
= E_FAIL
;
1474 TRACE("%s, %p, %#x, %p\n", debugstr_w(src
), dst
, dst_len
, reserved
);
1482 dllname
= StrDupW(src
+ 1);
1483 index_str
= wcschr(dllname
, ',');
1485 if(!index_str
) goto end
;
1489 index
= wcstol(index_str
, NULL
, 10);
1491 hmod
= LoadLibraryW(dllname
);
1492 if (!hmod
) goto end
;
1496 if (LoadStringW(hmod
, -index
, dst
, dst_len
))
1500 FIXME("can't handle non-negative indices (%d)\n", index
);
1505 lstrcpynW(dst
, src
, dst_len
);
1509 TRACE("returning %s\n", debugstr_w(dst
));
1511 if (hmod
) FreeLibrary(hmod
);