opengl32: Preserve the remainder of the version string when limiting the version...
[wine.git] / dlls / kernelbase / string.c
blob798bc1f3d6388d80b870c17095860acd4b9caa5a
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 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);
41 str1[2] = '\0';
43 else
44 str1[1] = '\0';
46 str2[0] = LOBYTE(ch2);
47 if (IsDBCSLeadByte(str2[0]))
49 str2[1] = HIBYTE(ch2);
50 str2[2] = '\0';
52 else
53 str2[1] = '\0';
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;
61 if (!str1) return -1;
62 if (!str2) return 1;
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;
69 if (!str1) return -1;
70 if (!str2) return 1;
71 return CompareStringW( GetThreadLocale(), 0, str1, -1, str2, -1 ) - 2;
74 int WINAPI lstrcmpiA(LPCSTR str1, LPCSTR str2)
76 if (!str1 && !str2) return 0;
77 if (!str1) return -1;
78 if (!str2) return 1;
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;
85 if (!str1) return -1;
86 if (!str2) return 1;
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
93 * a terminating \0.
95 * Note: n is an INT but Windows treats it as unsigned, and will happily
96 * copy a gazillion chars if n is negative.
98 __TRY
100 LPSTR d = dst;
101 LPCSTR s = src;
102 UINT count = n;
104 while ((count > 1) && *s)
106 count--;
107 *d++ = *s++;
109 if (count) *d = 0;
111 __EXCEPT_PAGE_FAULT
113 SetLastError( ERROR_INVALID_PARAMETER );
114 return 0;
116 __ENDTRY
117 return dst;
120 LPWSTR WINAPI KERNELBASE_lstrcpynW( LPWSTR dst, LPCWSTR src, INT n )
122 /* Note: this function differs from the UNIX strncpy, it _always_ writes
123 * a terminating \0
125 * Note: n is an INT but Windows treats it as unsigned, and will happily
126 * copy a gazillion chars if n is negative.
128 __TRY
130 LPWSTR d = dst;
131 LPCWSTR s = src;
132 UINT count = n;
134 while ((count > 1) && *s)
136 count--;
137 *d++ = *s++;
139 if (count) *d = 0;
141 __EXCEPT_PAGE_FAULT
143 SetLastError( ERROR_INVALID_PARAMETER );
144 return 0;
146 __ENDTRY
147 return dst;
150 INT WINAPI KERNELBASE_lstrlenA( LPCSTR str )
152 INT ret;
153 __TRY
155 ret = strlen(str);
157 __EXCEPT_PAGE_FAULT
159 SetLastError( ERROR_INVALID_PARAMETER );
160 return 0;
162 __ENDTRY
163 return ret;
166 INT WINAPI KERNELBASE_lstrlenW( LPCWSTR str )
168 INT ret;
169 __TRY
171 ret = wcslen(str);
173 __EXCEPT_PAGE_FAULT
175 SetLastError( ERROR_INVALID_PARAMETER );
176 return 0;
178 __ENDTRY
179 return ret;
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);
216 if (!str)
217 return NULL;
219 while (*str)
221 if (!char_compare(*str, ch, 0))
222 return (char *)str;
223 str = CharNextA(str);
226 return NULL;
229 WCHAR * WINAPI StrChrW(const WCHAR *str, WCHAR ch)
231 TRACE("%s, %#x\n", wine_dbgstr_w(str), ch);
233 if (!str)
234 return NULL;
236 return wcschr(str, ch);
239 char * WINAPI StrChrIA(const char *str, WORD ch)
241 TRACE("%s, %i\n", wine_dbgstr_a(str), ch);
243 if (!str)
244 return NULL;
246 while (*str)
248 if (!ChrCmpIA(*str, ch))
249 return (char *)str;
250 str = CharNextA(str);
253 return NULL;
256 WCHAR * WINAPI StrChrIW(const WCHAR *str, WCHAR ch)
258 TRACE("%s, %#x\n", wine_dbgstr_w(str), ch);
260 if (!str)
261 return NULL;
263 ch = towupper(ch);
264 while (*str)
266 if (towupper(*str) == ch)
267 return (WCHAR *)str;
268 str++;
270 str = NULL;
272 return (WCHAR *)str;
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);
279 if (!str)
280 return NULL;
282 while (*str && max_len-- > 0)
284 if (*str == ch)
285 return (WCHAR *)str;
286 str++;
289 return NULL;
292 char * WINAPI StrDupA(const char *str)
294 unsigned int len;
295 char *ret;
297 TRACE("%s\n", wine_dbgstr_a(str));
299 len = str ? strlen(str) + 1 : 1;
300 ret = LocalAlloc(LMEM_FIXED, len);
302 if (ret)
304 if (str)
305 memcpy(ret, str, len);
306 else
307 *ret = '\0';
310 return ret;
313 WCHAR * WINAPI StrDupW(const WCHAR *str)
315 unsigned int len;
316 WCHAR *ret;
318 TRACE("%s\n", wine_dbgstr_w(str));
320 len = (str ? lstrlenW(str) + 1 : 1) * sizeof(WCHAR);
321 ret = LocalAlloc(LMEM_FIXED, len);
323 if (ret)
325 if (str)
326 memcpy(ret, str, len);
327 else
328 *ret = '\0';
331 return ret;
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)
348 const char *end;
349 size_t len;
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);
363 return NULL;
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)
371 return NULL;
373 return wcsstr(str, search);
376 WCHAR * WINAPI StrStrNW(const WCHAR *str, const WCHAR *search, UINT max_len)
378 unsigned int i, len;
380 TRACE("%s, %s, %u\n", wine_dbgstr_w(str), wine_dbgstr_w(search), max_len);
382 if (!str || !search || !*search || !max_len)
383 return NULL;
385 len = lstrlenW(search);
387 for (i = max_len; *str && (i > 0); i--, str++)
389 if (!wcsncmp(str, search, len))
390 return (WCHAR *)str;
393 return NULL;
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)
404 unsigned int i, len;
406 TRACE("%s, %s, %u\n", wine_dbgstr_w(str), wine_dbgstr_w(search), max_len);
408 if (!str || !search || !*search || !max_len)
409 return NULL;
411 len = lstrlenW(search);
413 for (i = max_len; *str && (i > 0); i--, str++)
415 if (!StrCmpNIW(str, search, len))
416 return (WCHAR *)str;
419 return NULL;
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;
465 WCHAR *d = dst;
467 TRACE("%p, %s, %i\n", dst, wine_dbgstr_w(src), count);
469 if (s)
471 while ((count > 1) && *s)
473 count--;
474 *d++ = *s++;
477 if (count) *d = 0;
479 return dst;
482 char * WINAPI StrStrIA(const char *str, const char *search)
484 const char *end;
485 size_t len;
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);
499 return NULL;
502 WCHAR * WINAPI StrStrIW(const WCHAR *str, const WCHAR *search)
504 unsigned int len;
505 const WCHAR *end;
507 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search));
509 if (!str || !search || !*search)
510 return NULL;
512 len = lstrlenW(search);
513 end = str + lstrlenW(str);
515 while (str + len <= end)
517 if (!StrCmpNIW(str, search, len))
518 return (WCHAR *)str;
519 str++;
522 return NULL;
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;
533 while (*ptr)
535 if (!StrChrA(match, *ptr)) break;
536 ptr = CharNextA(ptr);
538 return ptr - str;
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;
555 while (*ptr)
557 if (StrChrA(match, *ptr)) break;
558 ptr = CharNextA(ptr);
560 return ptr - str;
563 int WINAPI StrCSpnW(const WCHAR *str, const WCHAR *match)
565 if (!str || !match)
566 return 0;
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;
579 while (*ptr)
581 if (StrChrIA(match, *ptr)) break;
582 ptr = CharNextA(ptr);
584 return ptr - str;
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)
594 return 0;
596 while (*ptr)
598 if (StrChrIW(match, *ptr)) break;
599 ptr++;
602 return ptr - str;
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);
619 return (char *)ret;
622 WCHAR * WINAPI StrRChrW(const WCHAR *str, const WCHAR *end, WORD ch)
624 WCHAR *ret = NULL;
626 if (!str) return NULL;
627 if (!end) end = str + lstrlenW(str);
628 while (str < end)
630 if (*str == ch) ret = (WCHAR *)str;
631 str++;
633 return ret;
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);
651 return (char *)ret;
654 WCHAR * WINAPI StrRChrIW(const WCHAR *str, const WCHAR *end, WORD ch)
656 WCHAR *ret = NULL;
658 if (!str) return NULL;
659 if (!end) end = str + lstrlenW(str);
660 while (str < end)
662 if (!ChrCmpIW(*str, ch)) ret = (WCHAR *)str;
663 str++;
665 return ret;
668 char * WINAPI StrRStrIA(const char *str, const char *end, const char *search)
670 char *ret = NULL;
671 WORD ch1, ch2;
672 int len;
674 TRACE("%s, %s\n", wine_dbgstr_a(str), wine_dbgstr_a(search));
676 if (!str || !search || !*search)
677 return NULL;
679 if (IsDBCSLeadByte(*search))
680 ch1 = *search << 8 | (UCHAR)search[1];
681 else
682 ch1 = *search;
683 len = lstrlenA(search);
685 if (!end)
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))
696 ret = (char *)str;
699 str = CharNextA(str);
702 return ret;
705 WCHAR * WINAPI StrRStrIW(const WCHAR *str, const WCHAR *end, const WCHAR *search)
707 WCHAR *ret = NULL;
708 int len;
710 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(search));
712 if (!str || !search || !*search)
713 return NULL;
715 len = lstrlenW(search);
717 if (!end)
718 end = str + lstrlenW(str);
719 else
720 end += min(len - 1, lstrlenW(end));
722 while (str + len <= end && *str)
724 if (!ChrCmpIW(*search, *str))
726 if (!StrCmpNIW(str, search, len))
727 ret = (WCHAR *)str;
729 str++;
732 return ret;
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)
740 return NULL;
742 while (*str)
744 if (StrChrA(match, *str))
745 return (char *)str;
746 str = CharNextA(str);
749 return NULL;
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)
760 unsigned int len;
761 BOOL ret = FALSE;
762 char *ptr = str;
764 TRACE("%s, %s\n", debugstr_a(str), debugstr_a(trim));
766 if (!str || !*str)
767 return FALSE;
769 while (*ptr && StrChrA(trim, *ptr))
770 ptr = CharNextA(ptr); /* Skip leading matches */
772 len = strlen(ptr);
774 if (ptr != str)
776 memmove(str, ptr, len + 1);
777 ret = TRUE;
780 if (len > 0)
782 ptr = str + len;
783 while (StrChrA(trim, ptr[-1]))
784 ptr = CharPrevA(str, ptr); /* Skip trailing matches */
786 if (ptr != str + len)
788 *ptr = '\0';
789 ret = TRUE;
793 return ret;
796 BOOL WINAPI StrTrimW(WCHAR *str, const WCHAR *trim)
798 unsigned int len;
799 WCHAR *ptr = str;
800 BOOL ret = FALSE;
802 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(trim));
804 if (!str || !*str)
805 return FALSE;
807 while (*ptr && StrChrW(trim, *ptr))
808 ptr++;
810 len = lstrlenW(ptr);
812 if (ptr != str)
814 memmove(str, ptr, (len + 1) * sizeof(WCHAR));
815 ret = TRUE;
818 if (len > 0)
820 ptr = str + len;
821 while (StrChrW(trim, ptr[-1]))
822 ptr--; /* Skip trailing matches */
824 if (ptr != str + len)
826 *ptr = '\0';
827 ret = TRUE;
831 return ret;
834 BOOL WINAPI StrToInt64ExA(const char *str, DWORD flags, LONGLONG *ret)
836 BOOL negative = FALSE;
837 LONGLONG value = 0;
839 TRACE("%s, %#lx, %p\n", wine_dbgstr_a(str), flags, ret);
841 if (!str || !ret)
842 return FALSE;
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++;
850 if (*str == '-')
852 negative = TRUE;
853 str++;
855 else if (*str == '+')
856 str++;
858 if (flags & STIF_SUPPORT_HEX && *str == '0' && (str[1] == 'x' || str[1] == 'X'))
860 /* Read hex number */
861 str += 2;
863 if (!isxdigit(*str))
864 return FALSE;
866 while (isxdigit(*str))
868 value *= 16;
869 if (*str >= '0' && *str <= '9')
870 value += (*str - '0');
871 else if (*str >= 'A' && *str <= 'F')
872 value += 10 + *str - 'A';
873 else
874 value += 10 + *str - 'a';
875 str++;
878 *ret = value;
879 return TRUE;
882 /* Read decimal number */
883 if (*str < '0' || *str > '9')
884 return FALSE;
886 while (*str >= '0' && *str <= '9')
888 value *= 10;
889 value += (*str - '0');
890 str++;
893 *ret = negative ? -value : value;
894 return TRUE;
897 BOOL WINAPI StrToInt64ExW(const WCHAR *str, DWORD flags, LONGLONG *ret)
899 BOOL negative = FALSE;
900 LONGLONG value = 0;
902 TRACE("%s, %#lx, %p\n", wine_dbgstr_w(str), flags, ret);
904 if (!str || !ret)
905 return FALSE;
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++;
913 if (*str == '-')
915 negative = TRUE;
916 str++;
918 else if (*str == '+')
919 str++;
921 if (flags & STIF_SUPPORT_HEX && *str == '0' && (str[1] == 'x' || str[1] == 'X'))
923 /* Read hex number */
924 str += 2;
926 if (!isxdigit(*str))
927 return FALSE;
929 while (isxdigit(*str))
931 value *= 16;
932 if (*str >= '0' && *str <= '9')
933 value += (*str - '0');
934 else if (*str >= 'A' && *str <= 'Z')
935 value += 10 + (*str - 'A');
936 else
937 value += 10 + (*str - 'a');
938 str++;
941 *ret = value;
942 return TRUE;
945 /* Read decimal number */
946 if (*str < '0' || *str > '9')
947 return FALSE;
949 while (*str >= '0' && *str <= '9')
951 value *= 10;
952 value += (*str - '0');
953 str++;
956 *ret = negative ? -value : value;
957 return TRUE;
960 BOOL WINAPI StrToIntExA(const char *str, DWORD flags, INT *ret)
962 LONGLONG value;
963 BOOL res;
965 TRACE("%s, %#lx, %p\n", wine_dbgstr_a(str), flags, ret);
967 res = StrToInt64ExA(str, flags, &value);
968 if (res) *ret = value;
969 return res;
972 BOOL WINAPI StrToIntExW(const WCHAR *str, DWORD flags, INT *ret)
974 LONGLONG value;
975 BOOL res;
977 TRACE("%s, %#lx, %p\n", wine_dbgstr_w(str), flags, ret);
979 res = StrToInt64ExW(str, flags, &value);
980 if (res) *ret = value;
981 return res;
984 int WINAPI StrToIntA(const char *str)
986 int value = 0;
988 TRACE("%s\n", wine_dbgstr_a(str));
990 if (!str)
991 return 0;
993 if (*str == '-' || (*str >= '0' && *str <= '9'))
994 StrToIntExA(str, 0, &value);
996 return value;
999 int WINAPI StrToIntW(const WCHAR *str)
1001 int value = 0;
1003 TRACE("%s\n", wine_dbgstr_w(str));
1005 if (!str)
1006 return 0;
1008 if (*str == '-' || (*str >= '0' && *str <= '9'))
1009 StrToIntExW(str, 0, &value);
1010 return 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)
1020 *dst++ = *src++;
1021 if (len >= 0)
1022 *dst = '\0';
1025 return dst;
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)
1035 *dst++ = *src++;
1036 if (len >= 0)
1037 *dst = '\0';
1040 return dst;
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;
1052 __TRY
1054 CharLowerBuffA( str, strlen(str) );
1056 __EXCEPT_PAGE_FAULT
1058 SetLastError( ERROR_INVALID_PARAMETER );
1059 return NULL;
1061 __ENDTRY
1062 return str;
1065 DWORD WINAPI CharLowerBuffA(char *str, DWORD len)
1067 DWORD lenW;
1068 WCHAR buffer[32];
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);
1083 return len;
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));
1097 return str;
1099 else
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)
1123 if (*x) x++;
1125 return (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;
1134 start = next;
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;
1145 start = next;
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;
1165 __TRY
1167 CharUpperBuffA(str, strlen(str));
1169 __EXCEPT_PAGE_FAULT
1171 SetLastError(ERROR_INVALID_PARAMETER);
1172 return NULL;
1174 __ENDTRY
1175 return str;
1178 DWORD WINAPI CharUpperBuffA(LPSTR str, DWORD len)
1180 DWORD lenW;
1181 WCHAR buffer[32];
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);
1196 return len;
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));
1210 return str;
1212 else
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)
1222 int string_num, i;
1223 HGLOBAL hmem;
1224 HRSRC hrsrc;
1225 WCHAR *p;
1227 TRACE("instance = %p, id = %04x, buffer = %p, length = %d\n", instance, resource_id, buffer, buflen);
1229 if (!buffer)
1230 return 0;
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++)
1241 p += *p + 1;
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 *) */
1247 if (buflen == 0)
1249 *((LPWSTR *)buffer) = p + 1;
1250 return *p;
1253 i = min(buflen - 1, *p);
1254 if (i > 0)
1256 memcpy(buffer, p + 1, i * sizeof (WCHAR));
1257 buffer[i] = 0;
1259 else
1261 if (buflen > 1)
1263 buffer[0] = 0;
1264 return 0;
1268 TRACE("returning %s\n", debugstr_w(buffer));
1269 return i;
1272 INT WINAPI DECLSPEC_HOTPATCH LoadStringA(HINSTANCE instance, UINT resource_id, LPSTR buffer, INT buflen)
1274 DWORD retval = 0;
1275 HGLOBAL hmem;
1276 HRSRC hrsrc;
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));
1293 buffer[retval] = 0;
1294 TRACE("returning %s\n", debugstr_a(buffer));
1295 return retval;
1298 int WINAPI StrCmpLogicalW(const WCHAR *str, const WCHAR *comp)
1300 TRACE("%s, %s\n", wine_dbgstr_w(str), wine_dbgstr_w(comp));
1302 if (!str || !comp)
1303 return 0;
1305 while (*str)
1307 if (!*comp)
1308 return 1;
1309 else if (*str >= '0' && *str <= '9')
1311 int str_value, comp_value;
1313 if (*comp < '0' || *comp > '9')
1314 return -1;
1316 /* Compare the numbers */
1317 StrToIntExW(str, 0, &str_value);
1318 StrToIntExW(comp, 0, &comp_value);
1320 if (str_value < comp_value)
1321 return -1;
1322 else if (str_value > comp_value)
1323 return 1;
1325 /* Skip */
1326 while (*str >= '0' && *str <= '9') str++;
1327 while (*comp >= '0' && *comp <= '9') comp++;
1329 else if (*comp >= '0' && *comp <= '9')
1330 return 1;
1331 else
1333 int diff = ChrCmpIW(*str, *comp);
1334 if (diff > 0)
1335 return 1;
1336 else if (diff < 0)
1337 return -1;
1339 str++;
1340 comp++;
1344 if (*comp)
1345 return -1;
1347 return 0;
1350 BOOL WINAPI StrIsIntlEqualA(BOOL case_sensitive, const char *str, const char *cmp, int len)
1352 DWORD flags;
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.
1359 flags = 0x10000000;
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)
1368 DWORD flags;
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.
1375 flags = 0x10000000;
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)
1384 INT len;
1386 TRACE("%p, %s, %d\n", str, wine_dbgstr_a(cat), max_len);
1388 if (!str)
1389 return NULL;
1391 len = strlen(str);
1392 max_len -= len;
1393 if (max_len > 0)
1394 StrCpyNA(str + len, cat, max_len);
1396 return str;
1399 WCHAR * WINAPI StrCatBuffW(WCHAR *str, const WCHAR *cat, INT max_len)
1401 INT len;
1403 TRACE("%p, %s, %d\n", str, wine_dbgstr_w(cat), max_len);
1405 if (!str)
1406 return NULL;
1408 len = lstrlenW(str);
1409 max_len -= len;
1410 if (max_len > 0)
1411 StrCpyNW(str + len, cat, max_len);
1413 return str;
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));
1420 if (at == -1)
1421 at = lstrlenW(str);
1423 if (!max_len)
1424 return at;
1426 if (at == max_len)
1427 at--;
1429 if (cat && at < max_len)
1431 str += at;
1432 while (at < max_len - 1 && *cat)
1434 *str++ = *cat++;
1435 at++;
1437 *str = 0;
1440 return at;
1443 DWORD WINAPI SHTruncateString(char *str, DWORD size)
1445 char *last_byte;
1447 if (!str || !size)
1448 return 0;
1450 last_byte = str + size - 1;
1452 while (str < last_byte)
1453 str += IsDBCSLeadByte(*str) ? 2 : 1;
1455 if (str == last_byte && IsDBCSLeadByte(*str))
1457 *str = '\0';
1458 size--;
1461 return size;
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);
1472 if (src[0] == '@')
1474 WCHAR *index_str;
1475 int index;
1477 dst[0] = 0;
1478 dllname = StrDupW(src + 1);
1479 index_str = wcschr(dllname, ',');
1481 if(!index_str) goto end;
1483 *index_str = 0;
1484 index_str++;
1485 index = wcstol(index_str, NULL, 10);
1487 hmod = LoadLibraryW(dllname);
1488 if (!hmod) goto end;
1490 if (index < 0)
1492 if (LoadStringW(hmod, -index, dst, dst_len))
1493 hr = S_OK;
1495 else
1496 FIXME("can't handle non-negative indices (%d)\n", index);
1498 else
1500 if (dst != src)
1501 lstrcpynW(dst, src, dst_len);
1502 hr = S_OK;
1505 TRACE("returning %s\n", debugstr_w(dst));
1506 end:
1507 if (hmod) FreeLibrary(hmod);
1508 LocalFree(dllname);
1509 return hr;