user32/tests: Test pending redraw state with owner-drawn list box.
[wine.git] / dlls / kernelbase / string.c
blob29cc158202ffc1f055a45b7a86f0543ad0ea5131
1 /*
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
19 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "winnls.h"
24 #include "shlwapi.h"
25 #include "winternl.h"
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);
45 str1[2] = '\0';
47 else
48 str1[1] = '\0';
50 str2[0] = LOBYTE(ch2);
51 if (IsDBCSLeadByte(str2[0]))
53 str2[1] = HIBYTE(ch2);
54 str2[2] = '\0';
56 else
57 str2[1] = '\0';
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;
65 if (!str1) return -1;
66 if (!str2) return 1;
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;
73 if (!str1) return -1;
74 if (!str2) return 1;
75 return CompareStringW( GetThreadLocale(), 0, str1, -1, str2, -1 ) - 2;
78 int WINAPI lstrcmpiA(LPCSTR str1, LPCSTR str2)
80 if (!str1 && !str2) return 0;
81 if (!str1) return -1;
82 if (!str2) return 1;
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;
89 if (!str1) return -1;
90 if (!str2) return 1;
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
97 * a terminating \0.
99 * Note: n is an INT but Windows treats it as unsigned, and will happily
100 * copy a gazillion chars if n is negative.
102 __TRY
104 LPSTR d = dst;
105 LPCSTR s = src;
106 UINT count = n;
108 while ((count > 1) && *s)
110 count--;
111 *d++ = *s++;
113 if (count) *d = 0;
115 __EXCEPT_PAGE_FAULT
117 SetLastError( ERROR_INVALID_PARAMETER );
118 return 0;
120 __ENDTRY
121 return dst;
124 LPWSTR WINAPI KERNELBASE_lstrcpynW( LPWSTR dst, LPCWSTR src, INT n )
126 /* Note: this function differs from the UNIX strncpy, it _always_ writes
127 * a terminating \0
129 * Note: n is an INT but Windows treats it as unsigned, and will happily
130 * copy a gazillion chars if n is negative.
132 __TRY
134 LPWSTR d = dst;
135 LPCWSTR s = src;
136 UINT count = n;
138 while ((count > 1) && *s)
140 count--;
141 *d++ = *s++;
143 if (count) *d = 0;
145 __EXCEPT_PAGE_FAULT
147 SetLastError( ERROR_INVALID_PARAMETER );
148 return 0;
150 __ENDTRY
151 return dst;
154 INT WINAPI KERNELBASE_lstrlenA( LPCSTR str )
156 INT ret;
157 __TRY
159 ret = strlen(str);
161 __EXCEPT_PAGE_FAULT
163 SetLastError( ERROR_INVALID_PARAMETER );
164 return 0;
166 __ENDTRY
167 return ret;
170 INT WINAPI KERNELBASE_lstrlenW( LPCWSTR str )
172 INT ret;
173 __TRY
175 ret = wcslen(str);
177 __EXCEPT_PAGE_FAULT
179 SetLastError( ERROR_INVALID_PARAMETER );
180 return 0;
182 __ENDTRY
183 return ret;
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);
220 if (!str)
221 return NULL;
223 while (*str)
225 if (!char_compare(*str, ch, 0))
226 return (char *)str;
227 str = CharNextA(str);
230 return NULL;
233 WCHAR * WINAPI StrChrW(const WCHAR *str, WCHAR ch)
235 TRACE("%s, %#x\n", wine_dbgstr_w(str), ch);
237 if (!str)
238 return NULL;
240 return wcschr(str, ch);
243 char * WINAPI StrChrIA(const char *str, WORD ch)
245 TRACE("%s, %i\n", wine_dbgstr_a(str), ch);
247 if (!str)
248 return NULL;
250 while (*str)
252 if (!ChrCmpIA(*str, ch))
253 return (char *)str;
254 str = CharNextA(str);
257 return NULL;
260 WCHAR * WINAPI StrChrIW(const WCHAR *str, WCHAR ch)
262 TRACE("%s, %#x\n", wine_dbgstr_w(str), ch);
264 if (!str)
265 return NULL;
267 ch = towupper(ch);
268 while (*str)
270 if (towupper(*str) == ch)
271 return (WCHAR *)str;
272 str++;
274 str = NULL;
276 return (WCHAR *)str;
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);
283 if (!str)
284 return NULL;
286 while (*str && max_len-- > 0)
288 if (*str == ch)
289 return (WCHAR *)str;
290 str++;
293 return NULL;
296 char * WINAPI StrDupA(const char *str)
298 unsigned int len;
299 char *ret;
301 TRACE("%s\n", wine_dbgstr_a(str));
303 len = str ? strlen(str) + 1 : 1;
304 ret = LocalAlloc(LMEM_FIXED, len);
306 if (ret)
308 if (str)
309 memcpy(ret, str, len);
310 else
311 *ret = '\0';
314 return ret;
317 WCHAR * WINAPI StrDupW(const WCHAR *str)
319 unsigned int len;
320 WCHAR *ret;
322 TRACE("%s\n", wine_dbgstr_w(str));
324 len = (str ? lstrlenW(str) + 1 : 1) * sizeof(WCHAR);
325 ret = LocalAlloc(LMEM_FIXED, len);
327 if (ret)
329 if (str)
330 memcpy(ret, str, len);
331 else
332 *ret = '\0';
335 return ret;
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)
352 const char *end;
353 size_t len;
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);
367 return NULL;
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)
375 return NULL;
377 return wcsstr(str, search);
380 WCHAR * WINAPI StrStrNW(const WCHAR *str, const WCHAR *search, UINT max_len)
382 unsigned int i, len;
384 TRACE("%s, %s, %u\n", wine_dbgstr_w(str), wine_dbgstr_w(search), max_len);
386 if (!str || !search || !*search || !max_len)
387 return NULL;
389 len = lstrlenW(search);
391 for (i = max_len; *str && (i > 0); i--, str++)
393 if (!wcsncmp(str, search, len))
394 return (WCHAR *)str;
397 return NULL;
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)
408 unsigned int i, len;
410 TRACE("%s, %s, %u\n", wine_dbgstr_w(str), wine_dbgstr_w(search), max_len);
412 if (!str || !search || !*search || !max_len)
413 return NULL;
415 len = lstrlenW(search);
417 for (i = max_len; *str && (i > 0); i--, str++)
419 if (!StrCmpNIW(str, search, len))
420 return (WCHAR *)str;
423 return NULL;
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;
469 WCHAR *d = dst;
471 TRACE("%p, %s, %i\n", dst, wine_dbgstr_w(src), count);
473 if (s)
475 while ((count > 1) && *s)
477 count--;
478 *d++ = *s++;
481 if (count) *d = 0;
483 return dst;
486 char * WINAPI StrStrIA(const char *str, const char *search)
488 const char *end;
489 size_t len;
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);
503 return NULL;
506 WCHAR * WINAPI StrStrIW(const WCHAR *str, const WCHAR *search)
508 unsigned int len;
509 const WCHAR *end;
511 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search));
513 if (!str || !search || !*search)
514 return NULL;
516 len = lstrlenW(search);
517 end = str + lstrlenW(str);
519 while (str + len <= end)
521 if (!StrCmpNIW(str, search, len))
522 return (WCHAR *)str;
523 str++;
526 return NULL;
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;
537 while (*ptr)
539 if (!StrChrA(match, *ptr)) break;
540 ptr = CharNextA(ptr);
542 return ptr - str;
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;
559 while (*ptr)
561 if (StrChrA(match, *ptr)) break;
562 ptr = CharNextA(ptr);
564 return ptr - str;
567 int WINAPI StrCSpnW(const WCHAR *str, const WCHAR *match)
569 if (!str || !match)
570 return 0;
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;
583 while (*ptr)
585 if (StrChrIA(match, *ptr)) break;
586 ptr = CharNextA(ptr);
588 return ptr - str;
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)
598 return 0;
600 while (*ptr)
602 if (StrChrIW(match, *ptr)) break;
603 ptr++;
606 return ptr - str;
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);
623 return (char *)ret;
626 WCHAR * WINAPI StrRChrW(const WCHAR *str, const WCHAR *end, WORD ch)
628 WCHAR *ret = NULL;
630 if (!str) return NULL;
631 if (!end) end = str + lstrlenW(str);
632 while (str < end)
634 if (*str == ch) ret = (WCHAR *)str;
635 str++;
637 return ret;
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);
655 return (char *)ret;
658 WCHAR * WINAPI StrRChrIW(const WCHAR *str, const WCHAR *end, WORD ch)
660 WCHAR *ret = NULL;
662 if (!str) return NULL;
663 if (!end) end = str + lstrlenW(str);
664 while (str < end)
666 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
667 str++;
669 return ret;
672 char * WINAPI StrRStrIA(const char *str, const char *end, const char *search)
674 char *ret = NULL;
675 WORD ch1, ch2;
676 int len;
678 TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(search));
680 if (!str || !search || !*search)
681 return NULL;
683 if (IsDBCSLeadByte(*search))
684 ch1 = *search << 8 | (UCHAR)search[1];
685 else
686 ch1 = *search;
687 len = lstrlenA(search);
689 if (!end)
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))
700 ret = (char *)str;
703 str = CharNextA(str);
706 return ret;
709 WCHAR * WINAPI StrRStrIW(const WCHAR *str, const WCHAR *end, const WCHAR *search)
711 WCHAR *ret = NULL;
712 int len;
714 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search));
716 if (!str || !search || !*search)
717 return NULL;
719 len = lstrlenW(search);
721 if (!end)
722 end = str + lstrlenW(str);
723 else
724 end += min(len - 1, lstrlenW(end));
726 while (str + len <= end && *str)
728 if (!ChrCmpIW(*search, *str))
730 if (!StrCmpNIW(str, search, len))
731 ret = (WCHAR *)str;
733 str++;
736 return ret;
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)
744 return NULL;
746 while (*str)
748 if (StrChrA(match, *str))
749 return (char *)str;
750 str = CharNextA(str);
753 return NULL;
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)
764 unsigned int len;
765 BOOL ret = FALSE;
766 char *ptr = str;
768 TRACE("%s, %s\n", debugstr_a(str), debugstr_a(trim));
770 if (!str || !*str)
771 return FALSE;
773 while (*ptr && StrChrA(trim, *ptr))
774 ptr = CharNextA(ptr); /* Skip leading matches */
776 len = strlen(ptr);
778 if (ptr != str)
780 memmove(str, ptr, len + 1);
781 ret = TRUE;
784 if (len > 0)
786 ptr = str + len;
787 while (StrChrA(trim, ptr[-1]))
788 ptr = CharPrevA(str, ptr); /* Skip trailing matches */
790 if (ptr != str + len)
792 *ptr = '\0';
793 ret = TRUE;
797 return ret;
800 BOOL WINAPI StrTrimW(WCHAR *str, const WCHAR *trim)
802 unsigned int len;
803 WCHAR *ptr = str;
804 BOOL ret = FALSE;
806 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(trim));
808 if (!str || !*str)
809 return FALSE;
811 while (*ptr && StrChrW(trim, *ptr))
812 ptr++;
814 len = lstrlenW(ptr);
816 if (ptr != str)
818 memmove(str, ptr, (len + 1) * sizeof(WCHAR));
819 ret = TRUE;
822 if (len > 0)
824 ptr = str + len;
825 while (StrChrW(trim, ptr[-1]))
826 ptr--; /* Skip trailing matches */
828 if (ptr != str + len)
830 *ptr = '\0';
831 ret = TRUE;
835 return ret;
838 BOOL WINAPI StrToInt64ExA(const char *str, DWORD flags, LONGLONG *ret)
840 BOOL negative = FALSE;
841 LONGLONG value = 0;
843 TRACE("%s, %#x, %p\n", wine_dbgstr_a(str), flags, ret);
845 if (!str || !ret)
846 return FALSE;
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++;
854 if (*str == '-')
856 negative = TRUE;
857 str++;
859 else if (*str == '+')
860 str++;
862 if (flags & STIF_SUPPORT_HEX && *str == '0' && (str[1] == 'x' || str[1] == 'X'))
864 /* Read hex number */
865 str += 2;
867 if (!isxdigit(*str))
868 return FALSE;
870 while (isxdigit(*str))
872 value *= 16;
873 if (*str >= '0' && *str <= '9')
874 value += (*str - '0');
875 else if (*str >= 'A' && *str <= 'F')
876 value += 10 + *str - 'A';
877 else
878 value += 10 + *str - 'a';
879 str++;
882 *ret = value;
883 return TRUE;
886 /* Read decimal number */
887 if (*str < '0' || *str > '9')
888 return FALSE;
890 while (*str >= '0' && *str <= '9')
892 value *= 10;
893 value += (*str - '0');
894 str++;
897 *ret = negative ? -value : value;
898 return TRUE;
901 BOOL WINAPI StrToInt64ExW(const WCHAR *str, DWORD flags, LONGLONG *ret)
903 BOOL negative = FALSE;
904 LONGLONG value = 0;
906 TRACE("%s, %#x, %p\n", wine_dbgstr_w(str), flags, ret);
908 if (!str || !ret)
909 return FALSE;
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++;
917 if (*str == '-')
919 negative = TRUE;
920 str++;
922 else if (*str == '+')
923 str++;
925 if (flags & STIF_SUPPORT_HEX && *str == '0' && (str[1] == 'x' || str[1] == 'X'))
927 /* Read hex number */
928 str += 2;
930 if (!isxdigit(*str))
931 return FALSE;
933 while (isxdigit(*str))
935 value *= 16;
936 if (*str >= '0' && *str <= '9')
937 value += (*str - '0');
938 else if (*str >= 'A' && *str <= 'Z')
939 value += 10 + (*str - 'A');
940 else
941 value += 10 + (*str - 'a');
942 str++;
945 *ret = value;
946 return TRUE;
949 /* Read decimal number */
950 if (*str < '0' || *str > '9')
951 return FALSE;
953 while (*str >= '0' && *str <= '9')
955 value *= 10;
956 value += (*str - '0');
957 str++;
960 *ret = negative ? -value : value;
961 return TRUE;
964 BOOL WINAPI StrToIntExA(const char *str, DWORD flags, INT *ret)
966 LONGLONG value;
967 BOOL res;
969 TRACE("%s, %#x, %p\n", wine_dbgstr_a(str), flags, ret);
971 res = StrToInt64ExA(str, flags, &value);
972 if (res) *ret = value;
973 return res;
976 BOOL WINAPI StrToIntExW(const WCHAR *str, DWORD flags, INT *ret)
978 LONGLONG value;
979 BOOL res;
981 TRACE("%s, %#x, %p\n", wine_dbgstr_w(str), flags, ret);
983 res = StrToInt64ExW(str, flags, &value);
984 if (res) *ret = value;
985 return res;
988 int WINAPI StrToIntA(const char *str)
990 int value = 0;
992 TRACE("%s\n", wine_dbgstr_a(str));
994 if (!str)
995 return 0;
997 if (*str == '-' || (*str >= '0' && *str <= '9'))
998 StrToIntExA(str, 0, &value);
1000 return value;
1003 int WINAPI StrToIntW(const WCHAR *str)
1005 int value = 0;
1007 TRACE("%s\n", wine_dbgstr_w(str));
1009 if (!str)
1010 return 0;
1012 if (*str == '-' || (*str >= '0' && *str <= '9'))
1013 StrToIntExW(str, 0, &value);
1014 return 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)
1024 *dst++ = *src++;
1025 if (len >= 0)
1026 *dst = '\0';
1029 return dst;
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)
1039 *dst++ = *src++;
1040 if (len >= 0)
1041 *dst = '\0';
1044 return dst;
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;
1056 __TRY
1058 CharLowerBuffA( str, strlen(str) );
1060 __EXCEPT_PAGE_FAULT
1062 SetLastError( ERROR_INVALID_PARAMETER );
1063 return NULL;
1065 __ENDTRY
1066 return str;
1069 DWORD WINAPI CharLowerBuffA(char *str, DWORD len)
1071 DWORD lenW;
1072 WCHAR buffer[32];
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);
1087 return len;
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));
1101 return str;
1103 else
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)
1127 if (*x) x++;
1129 return (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;
1138 start = next;
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;
1149 start = next;
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;
1169 __TRY
1171 CharUpperBuffA(str, strlen(str));
1173 __EXCEPT_PAGE_FAULT
1175 SetLastError(ERROR_INVALID_PARAMETER);
1176 return NULL;
1178 __ENDTRY
1179 return str;
1182 DWORD WINAPI CharUpperBuffA(LPSTR str, DWORD len)
1184 DWORD lenW;
1185 WCHAR buffer[32];
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);
1200 return len;
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));
1214 return str;
1216 else
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)
1226 int string_num, i;
1227 HGLOBAL hmem;
1228 HRSRC hrsrc;
1229 WCHAR *p;
1231 TRACE("instance = %p, id = %04x, buffer = %p, length = %d\n", instance, resource_id, buffer, buflen);
1233 if (!buffer)
1234 return 0;
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++)
1245 p += *p + 1;
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 *) */
1251 if (buflen == 0)
1253 *((LPWSTR *)buffer) = p + 1;
1254 return *p;
1257 i = min(buflen - 1, *p);
1258 if (i > 0)
1260 memcpy(buffer, p + 1, i * sizeof (WCHAR));
1261 buffer[i] = 0;
1263 else
1265 if (buflen > 1)
1267 buffer[0] = 0;
1268 return 0;
1272 TRACE("returning %s\n", debugstr_w(buffer));
1273 return i;
1276 INT WINAPI DECLSPEC_HOTPATCH LoadStringA(HINSTANCE instance, UINT resource_id, LPSTR buffer, INT buflen)
1278 DWORD retval = 0;
1279 HGLOBAL hmem;
1280 HRSRC hrsrc;
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));
1297 buffer[retval] = 0;
1298 TRACE("returning %s\n", debugstr_a(buffer));
1299 return retval;
1302 int WINAPI StrCmpLogicalW(const WCHAR *str, const WCHAR *comp)
1304 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(comp));
1306 if (!str || !comp)
1307 return 0;
1309 while (*str)
1311 if (!*comp)
1312 return 1;
1313 else if (*str >= '0' && *str <= '9')
1315 int str_value, comp_value;
1317 if (*comp < '0' || *comp > '9')
1318 return -1;
1320 /* Compare the numbers */
1321 StrToIntExW(str, 0, &str_value);
1322 StrToIntExW(comp, 0, &comp_value);
1324 if (str_value < comp_value)
1325 return -1;
1326 else if (str_value > comp_value)
1327 return 1;
1329 /* Skip */
1330 while (*str >= '0' && *str <= '9') str++;
1331 while (*comp >= '0' && *comp <= '9') comp++;
1333 else if (*comp >= '0' && *comp <= '9')
1334 return 1;
1335 else
1337 int diff = ChrCmpIW(*str, *comp);
1338 if (diff > 0)
1339 return 1;
1340 else if (diff < 0)
1341 return -1;
1343 str++;
1344 comp++;
1348 if (*comp)
1349 return -1;
1351 return 0;
1354 BOOL WINAPI StrIsIntlEqualA(BOOL case_sensitive, const char *str, const char *cmp, int len)
1356 DWORD flags;
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.
1363 flags = 0x10000000;
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)
1372 DWORD flags;
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.
1379 flags = 0x10000000;
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)
1388 INT len;
1390 TRACE("%p, %s, %d\n", str, wine_dbgstr_a(cat), max_len);
1392 if (!str)
1393 return NULL;
1395 len = strlen(str);
1396 max_len -= len;
1397 if (max_len > 0)
1398 StrCpyNA(str + len, cat, max_len);
1400 return str;
1403 WCHAR * WINAPI StrCatBuffW(WCHAR *str, const WCHAR *cat, INT max_len)
1405 INT len;
1407 TRACE("%p, %s, %d\n", str, wine_dbgstr_w(cat), max_len);
1409 if (!str)
1410 return NULL;
1412 len = lstrlenW(str);
1413 max_len -= len;
1414 if (max_len > 0)
1415 StrCpyNW(str + len, cat, max_len);
1417 return str;
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));
1424 if (at == -1)
1425 at = lstrlenW(str);
1427 if (!max_len)
1428 return at;
1430 if (at == max_len)
1431 at--;
1433 if (cat && at < max_len)
1435 str += at;
1436 while (at < max_len - 1 && *cat)
1438 *str++ = *cat++;
1439 at++;
1441 *str = 0;
1444 return at;
1447 DWORD WINAPI SHTruncateString(char *str, DWORD size)
1449 char *last_byte;
1451 if (!str || !size)
1452 return 0;
1454 last_byte = str + size - 1;
1456 while (str < last_byte)
1457 str += IsDBCSLeadByte(*str) ? 2 : 1;
1459 if (str == last_byte && IsDBCSLeadByte(*str))
1461 *str = '\0';
1462 size--;
1465 return size;
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);
1476 if (src[0] == '@')
1478 WCHAR *index_str;
1479 int index;
1481 dst[0] = 0;
1482 dllname = StrDupW(src + 1);
1483 index_str = wcschr(dllname, ',');
1485 if(!index_str) goto end;
1487 *index_str = 0;
1488 index_str++;
1489 index = wcstol(index_str, NULL, 10);
1491 hmod = LoadLibraryW(dllname);
1492 if (!hmod) goto end;
1494 if (index < 0)
1496 if (LoadStringW(hmod, -index, dst, dst_len))
1497 hr = S_OK;
1499 else
1500 FIXME("can't handle non-negative indices (%d)\n", index);
1502 else
1504 if (dst != src)
1505 lstrcpynW(dst, src, dst_len);
1506 hr = S_OK;
1509 TRACE("returning %s\n", debugstr_w(dst));
1510 end:
1511 if (hmod) FreeLibrary(hmod);
1512 LocalFree(dllname);
1513 return hr;