shlwapi/tests: Link directly to Url*() functions.
[wine.git] / dlls / msvcrt / wcs.c
blob86875954551a0bb10ddf032745ec873ba7588c27
1 /*
2 * msvcrt.dll wide-char functions
4 * Copyright 1999 Alexandre Julliard
5 * Copyright 2000 Jon Griffiths
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #define _NO_CRT_STDIO_INLINE
23 #include <limits.h>
24 #include <locale.h>
25 #include <math.h>
26 #include <assert.h>
27 #include <wchar.h>
28 #include <wctype.h>
29 #include "msvcrt.h"
30 #include "winnls.h"
31 #include "wtypes.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
36 typedef struct
38 enum { LEN_DEFAULT, LEN_SHORT, LEN_LONG } IntegerLength;
39 BOOLEAN IntegerDouble, IntegerNative, LeftAlign, Alternate, PadZero;
40 BOOLEAN WideString, NaturalString;
41 int FieldLength, Precision;
42 char Sign, Format;
43 } pf_flags;
45 static BOOL n_format_enabled = TRUE;
47 #include "printf.h"
48 #define PRINTF_WIDE
49 #include "printf.h"
50 #undef PRINTF_WIDE
52 #if _MSVCR_VER>=80
54 /*********************************************************************
55 * _get_printf_count_output (MSVCR80.@)
57 int CDECL _get_printf_count_output( void )
59 return n_format_enabled ? 1 : 0;
62 /*********************************************************************
63 * _set_printf_count_output (MSVCR80.@)
65 int CDECL _set_printf_count_output( int enable )
67 BOOL old = n_format_enabled;
68 n_format_enabled = enable != 0;
69 return old ? 1 : 0;
72 #endif /* _MSVCR_VER>=80 */
74 /*********************************************************************
75 * _wcsdup (MSVCRT.@)
77 wchar_t* CDECL _wcsdup( const wchar_t* str )
79 wchar_t* ret = NULL;
80 if (str)
82 int size = (wcslen(str) + 1) * sizeof(wchar_t);
83 ret = malloc( size );
84 if (ret) memcpy( ret, str, size );
86 return ret;
89 /*********************************************************************
90 * _towlower_l (MSVCRT.@)
92 wint_t CDECL _towlower_l(wint_t c, _locale_t locale)
94 pthreadlocinfo locinfo;
95 wchar_t ret;
97 if(!locale)
98 locinfo = get_locinfo();
99 else
100 locinfo = locale->locinfo;
102 if(!locinfo->lc_handle[LC_CTYPE]) {
103 if(c >= 'A' && c <= 'Z')
104 return c + 'a' - 'A';
105 return c;
108 if(!LCMapStringW(locinfo->lc_handle[LC_CTYPE], LCMAP_LOWERCASE, &c, 1, &ret, 1))
109 return c;
110 return ret;
113 /*********************************************************************
114 * towlower (MSVCRT.@)
116 wint_t CDECL towlower(wint_t c)
118 return _towlower_l(c, NULL);
121 INT CDECL _wcsicmp_l(const wchar_t *str1, const wchar_t *str2, _locale_t locale)
123 _locale_tstruct tmp = {0};
124 wchar_t c1, c2;
126 if(!MSVCRT_CHECK_PMT(str1 != NULL) || !MSVCRT_CHECK_PMT(str2 != NULL))
127 return _NLSCMPERROR;
129 if(!locale)
130 locale = get_current_locale_noalloc(&tmp);
134 c1 = _towlower_l(*str1++, locale);
135 c2 = _towlower_l(*str2++, locale);
136 } while(c1 && (c1 == c2));
138 free_locale_noalloc(&tmp);
139 return c1 - c2;
142 /*********************************************************************
143 * towctrans (MSVCR120.@)
145 wint_t CDECL towctrans(wint_t c, wctrans_t category)
147 if(category == 1)
148 return _towupper_l(c, NULL);
149 return _towlower_l(c, NULL);
152 /*********************************************************************
153 * _wcsicmp (MSVCRT.@)
155 INT CDECL _wcsicmp( const wchar_t* str1, const wchar_t* str2 )
157 return _wcsicmp_l(str1, str2, NULL);
160 /*********************************************************************
161 * _wcsnicmp_l (MSVCRT.@)
163 INT CDECL _wcsnicmp_l(const wchar_t *str1, const wchar_t *str2,
164 size_t n, _locale_t locale)
166 _locale_tstruct tmp = {0};
167 wchar_t c1, c2;
169 if (!n)
170 return 0;
172 if(!MSVCRT_CHECK_PMT(str1 != NULL) || !MSVCRT_CHECK_PMT(str2 != NULL))
173 return _NLSCMPERROR;
175 if(!locale)
176 locale = get_current_locale_noalloc(&tmp);
180 c1 = _towlower_l(*str1++, locale);
181 c2 = _towlower_l(*str2++, locale);
182 } while(--n && c1 && (c1 == c2));
184 free_locale_noalloc(&tmp);
185 return c1 - c2;
188 /*********************************************************************
189 * _wcsnicmp (MSVCRT.@)
191 INT CDECL _wcsnicmp(const wchar_t *str1, const wchar_t *str2, size_t n)
193 return _wcsnicmp_l(str1, str2, n, NULL);
196 /*********************************************************************
197 * _wcsicoll_l (MSVCRT.@)
199 int CDECL _wcsicoll_l(const wchar_t* str1, const wchar_t* str2, _locale_t locale)
201 pthreadlocinfo locinfo;
203 if(!locale)
204 locinfo = get_locinfo();
205 else
206 locinfo = locale->locinfo;
208 if(!locinfo->lc_handle[LC_COLLATE])
210 wchar_t c1, c2;
214 c1 = *str1++;
215 if (c1 >= 'A' && c1 <= 'Z')
216 c1 += 'a' - 'A';
218 c2 = *str2++;
219 if (c2 >= 'A' && c2 <= 'Z')
220 c2 += 'a' - 'A';
221 } while(c1 && (c1 == c2));
222 return c1 - c2;
225 return CompareStringW(locinfo->lc_handle[LC_COLLATE], NORM_IGNORECASE,
226 str1, -1, str2, -1)-CSTR_EQUAL;
229 /*********************************************************************
230 * _wcsicoll (MSVCRT.@)
232 INT CDECL _wcsicoll( const wchar_t* str1, const wchar_t* str2 )
234 return _wcsicoll_l(str1, str2, NULL);
237 /*********************************************************************
238 * _wcsnicoll_l (MSVCRT.@)
240 int CDECL _wcsnicoll_l(const wchar_t* str1, const wchar_t* str2,
241 size_t count, _locale_t locale)
243 pthreadlocinfo locinfo;
245 if(!locale)
246 locinfo = get_locinfo();
247 else
248 locinfo = locale->locinfo;
250 if(!locinfo->lc_handle[LC_COLLATE])
252 wchar_t c1, c2;
254 if (!count)
255 return 0;
259 c1 = *str1++;
260 if (c1 >= 'A' && c1 <= 'Z')
261 c1 += 'a' - 'A';
263 c2 = *str2++;
264 if (c2 >= 'A' && c2 <= 'Z')
265 c2 += 'a' - 'A';
266 } while(--count && c1 && (c1 == c2));
267 return c1 - c2;
270 return CompareStringW(locinfo->lc_handle[LC_COLLATE], NORM_IGNORECASE,
271 str1, wcsnlen(str1, count),
272 str2, wcsnlen(str2, count))-CSTR_EQUAL;
275 /*********************************************************************
276 * _wcsnicoll (MSVCRT.@)
278 INT CDECL _wcsnicoll( const wchar_t* str1, const wchar_t* str2, size_t count )
280 return _wcsnicoll_l(str1, str2, count, NULL);
283 /*********************************************************************
284 * _wcsnset (MSVCRT.@)
286 wchar_t* CDECL _wcsnset( wchar_t* str, wchar_t c, size_t n )
288 wchar_t* ret = str;
289 while ((n-- > 0) && *str) *str++ = c;
290 return ret;
293 /*********************************************************************
294 * _wcsnset_s (MSVCRT.@)
296 int CDECL _wcsnset_s( wchar_t *str, size_t size, wchar_t c, size_t count )
298 size_t i;
300 if(!str && !size && !count) return 0;
301 if(!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
302 if(!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
304 for(i=0; i<size-1 && i<count; i++) {
305 if(!str[i]) return 0;
306 str[i] = c;
308 for(; i<size; i++)
309 if(!str[i]) return 0;
311 str[0] = 0;
312 _invalid_parameter(NULL, NULL, NULL, 0, 0);
313 *_errno() = EINVAL;
314 return EINVAL;
317 /*********************************************************************
318 * _wcsrev (MSVCRT.@)
320 wchar_t* CDECL _wcsrev( wchar_t* str )
322 wchar_t* ret = str;
323 wchar_t* end = str + wcslen(str) - 1;
324 while (end > str)
326 wchar_t t = *end;
327 *end-- = *str;
328 *str++ = t;
330 return ret;
333 /*********************************************************************
334 * _wcsset_s (MSVCRT.@)
336 int CDECL _wcsset_s( wchar_t *str, size_t n, wchar_t c )
338 wchar_t *p = str;
340 if(!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
341 if(!MSVCRT_CHECK_PMT(n)) return EINVAL;
343 while(*p && --n) *p++ = c;
344 if(!n) {
345 str[0] = 0;
346 _invalid_parameter(NULL, NULL, NULL, 0, 0);
347 *_errno() = EINVAL;
348 return EINVAL;
350 return 0;
353 /*********************************************************************
354 * _wcsset (MSVCRT.@)
356 wchar_t* CDECL _wcsset( wchar_t* str, wchar_t c )
358 wchar_t* ret = str;
359 while (*str) *str++ = c;
360 return ret;
363 /******************************************************************
364 * _wcsupr_s_l (MSVCRT.@)
366 int CDECL _wcsupr_s_l( wchar_t* str, size_t n, _locale_t locale )
368 _locale_tstruct tmp = {0};
369 wchar_t* ptr = str;
371 if (!str || !n)
373 if (str) *str = '\0';
374 *_errno() = EINVAL;
375 return EINVAL;
378 if(!locale)
379 locale = get_current_locale_noalloc(&tmp);
381 while (n--)
383 if (!*ptr)
385 free_locale_noalloc(&tmp);
386 return 0;
388 *ptr = _towupper_l(*ptr, locale);
389 ptr++;
392 free_locale_noalloc(&tmp);
394 /* MSDN claims that the function should return and set errno to
395 * ERANGE, which doesn't seem to be true based on the tests. */
396 *str = '\0';
397 *_errno() = EINVAL;
398 return EINVAL;
401 /******************************************************************
402 * _wcsupr_s (MSVCRT.@)
405 INT CDECL _wcsupr_s( wchar_t* str, size_t n )
407 return _wcsupr_s_l( str, n, NULL );
410 /******************************************************************
411 * _wcsupr_l (MSVCRT.@)
413 wchar_t* CDECL _wcsupr_l( wchar_t *str, _locale_t locale )
415 _wcsupr_s_l( str, -1, locale);
416 return str;
419 /******************************************************************
420 * _wcsupr (MSVCRT.@)
422 wchar_t* CDECL _wcsupr( wchar_t *str )
424 return _wcsupr_l(str, NULL);
427 /******************************************************************
428 * _wcslwr_s_l (MSVCRT.@)
430 int CDECL _wcslwr_s_l( wchar_t* str, size_t n, _locale_t locale )
432 _locale_tstruct tmp = {0};
433 wchar_t* ptr = str;
435 if (!str || !n)
437 if (str) *str = '\0';
438 *_errno() = EINVAL;
439 return EINVAL;
442 if(!locale)
443 locale = get_current_locale_noalloc(&tmp);
445 while (n--)
447 if (!*ptr)
449 free_locale_noalloc(&tmp);
450 return 0;
452 *ptr = _towlower_l(*ptr, locale);
453 ptr++;
456 free_locale_noalloc(&tmp);
458 /* MSDN claims that the function should return and set errno to
459 * ERANGE, which doesn't seem to be true based on the tests. */
460 *str = '\0';
461 *_errno() = EINVAL;
462 return EINVAL;
465 /******************************************************************
466 * _wcslwr_s (MSVCRT.@)
468 int CDECL _wcslwr_s( wchar_t* str, size_t n )
470 return _wcslwr_s_l(str, n, NULL);
473 /******************************************************************
474 * _wcslwr_l (MSVCRT.@)
476 wchar_t* CDECL _wcslwr_l( wchar_t* str, _locale_t locale )
478 _wcslwr_s_l(str, -1, locale);
479 return str;
482 /******************************************************************
483 * _wcslwr (MSVCRT.@)
485 wchar_t* CDECL _wcslwr( wchar_t* str )
487 _wcslwr_s_l(str, -1, NULL);
488 return str;
491 /*********************************************************************
492 * wcscspn (MSVCRT.@)
494 size_t __cdecl wcscspn(const wchar_t *str, const wchar_t *reject)
496 const wchar_t *ptr;
497 for (ptr = str; *ptr; ptr++) if (wcschr( reject, *ptr )) break;
498 return ptr - str;
501 /*********************************************************************
502 * wcsspn (MSVCRT.@)
504 size_t __cdecl wcsspn(const wchar_t *str, const wchar_t *accept)
506 const wchar_t *ptr;
507 for (ptr = str; *ptr; ptr++) if (!wcschr( accept, *ptr )) break;
508 return ptr - str;
511 /*********************************************************************
512 * wcsncmp (MSVCRT.@)
514 int CDECL wcsncmp(const wchar_t *str1, const wchar_t *str2, size_t n)
516 if (!n)
517 return 0;
518 while(--n && *str1 && (*str1 == *str2))
520 str1++;
521 str2++;
523 return *str1 - *str2;
526 /*********************************************************************
527 * _wcsncoll_l (MSVCRT.@)
529 int CDECL _wcsncoll_l(const wchar_t* str1, const wchar_t* str2,
530 size_t count, _locale_t locale)
532 pthreadlocinfo locinfo;
534 if(!locale)
535 locinfo = get_locinfo();
536 else
537 locinfo = locale->locinfo;
539 if(!locinfo->lc_handle[LC_COLLATE])
540 return wcsncmp(str1, str2, count);
541 return CompareStringW(locinfo->lc_handle[LC_COLLATE], 0,
542 str1, wcsnlen(str1, count),
543 str2, wcsnlen(str2, count))-CSTR_EQUAL;
546 /*********************************************************************
547 * _wcsncoll (MSVCRT.@)
549 int CDECL _wcsncoll(const wchar_t* str1, const wchar_t* str2, size_t count)
551 return _wcsncoll_l(str1, str2, count, NULL);
554 static wchar_t strtod_wstr_get(void *ctx)
556 const wchar_t **p = ctx;
557 if (!**p) return WEOF;
558 return *(*p)++;
561 static void strtod_wstr_unget(void *ctx)
563 const wchar_t **p = ctx;
564 (*p)--;
567 /*********************************************************************
568 * _wcstod_l (MSVCRT.@)
570 double CDECL _wcstod_l(const wchar_t* str, wchar_t** end,
571 _locale_t locale)
573 pthreadlocinfo locinfo;
574 const wchar_t *beg, *p;
575 struct fpnum fp;
576 double ret;
577 int err;
579 if (!MSVCRT_CHECK_PMT(str != NULL)) {
580 if (end) *end = NULL;
581 return 0;
584 if (!locale)
585 locinfo = get_locinfo();
586 else
587 locinfo = locale->locinfo;
589 p = str;
590 while(_iswspace_l(*p, locale))
591 p++;
592 beg = p;
594 fp = fpnum_parse(strtod_wstr_get, strtod_wstr_unget, &p, locinfo, FALSE);
595 if (end) *end = (p == beg ? (wchar_t*)str : (wchar_t*)p);
597 err = fpnum_double(&fp, &ret);
598 if(err) *_errno() = err;
599 return ret;
602 /*********************************************************************
603 * wcsrtombs_l (INTERNAL)
605 static size_t wcsrtombs_l(char *mbstr, const wchar_t **wcstr,
606 size_t count, _locale_t locale)
608 pthreadlocinfo locinfo;
609 size_t tmp = 0;
610 BOOL used_default = FALSE;
611 BOOL *pused_default;
613 if(!locale)
614 locinfo = get_locinfo();
615 else
616 locinfo = locale->locinfo;
618 if(!locinfo->lc_codepage) {
619 size_t i;
621 if(!mbstr)
622 return wcslen(*wcstr);
624 for(i=0; i<count; i++) {
625 if((*wcstr)[i] > 255) {
626 *_errno() = EILSEQ;
627 return -1;
630 mbstr[i] = (*wcstr)[i];
631 if(!(*wcstr)[i]) break;
634 if(i < count) *wcstr = NULL;
635 else *wcstr += i;
636 return i;
639 pused_default = (locinfo->lc_codepage != CP_UTF8 ? &used_default : NULL);
641 if(!mbstr) {
642 tmp = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
643 *wcstr, -1, NULL, 0, NULL, pused_default);
644 if(!tmp || used_default) {
645 *_errno() = EILSEQ;
646 return -1;
648 return tmp-1;
651 while(**wcstr) {
652 char buf[3];
653 size_t i, size;
655 size = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
656 *wcstr, 1, buf, 3, NULL, pused_default);
657 if(!size || used_default) {
658 *_errno() = EILSEQ;
659 return -1;
661 if(tmp+size > count)
662 return tmp;
664 for(i=0; i<size; i++)
665 mbstr[tmp++] = buf[i];
666 (*wcstr)++;
669 if(tmp < count) {
670 mbstr[tmp] = '\0';
671 *wcstr = NULL;
673 return tmp;
676 /*********************************************************************
677 * _wcstombs_l (MSVCRT.@)
679 size_t CDECL _wcstombs_l(char *mbstr, const wchar_t *wcstr,
680 size_t count, _locale_t locale)
682 return wcsrtombs_l(mbstr, &wcstr, count, locale);
685 /*********************************************************************
686 * wcstombs (MSVCRT.@)
688 size_t CDECL wcstombs(char *mbstr, const wchar_t *wcstr,
689 size_t count)
691 return wcsrtombs_l(mbstr, &wcstr, count, NULL);
694 /*********************************************************************
695 * wcsrtombs (MSVCRT.@)
697 size_t CDECL wcsrtombs(char *mbstr, const wchar_t **wcstr,
698 size_t count, mbstate_t *mbstate)
700 if(mbstate)
701 *mbstate = 0;
703 return wcsrtombs_l(mbstr, wcstr, count, NULL);
706 /*********************************************************************
707 * wcsrtombs_s_l (INTERNAL)
709 static int wcsrtombs_s_l(size_t *ret, char *mbstr, size_t size,
710 const wchar_t **wcstr, size_t count, _locale_t locale)
712 size_t conv;
713 int err;
715 if(!mbstr && !size && wcstr) {
716 conv = wcsrtombs_l(NULL, wcstr, 0, locale);
717 if(ret)
718 *ret = conv+1;
719 if(conv == -1)
720 return *_errno();
721 return 0;
724 if (!MSVCRT_CHECK_PMT(mbstr != NULL)) return EINVAL;
725 if (size) mbstr[0] = '\0';
726 if (!MSVCRT_CHECK_PMT(wcstr != NULL)) return EINVAL;
727 if (!MSVCRT_CHECK_PMT(*wcstr != NULL)) return EINVAL;
729 if(count==_TRUNCATE || size<count)
730 conv = size;
731 else
732 conv = count;
734 err = 0;
735 conv = wcsrtombs_l(mbstr, wcstr, conv, locale);
736 if(conv == -1) {
737 conv = 0;
738 if(size)
739 mbstr[0] = '\0';
740 err = *_errno();
741 }else if(conv < size)
742 mbstr[conv++] = '\0';
743 else if(conv==size && (count==_TRUNCATE || mbstr[conv-1]=='\0')) {
744 mbstr[conv-1] = '\0';
745 if(count==_TRUNCATE)
746 err = STRUNCATE;
747 }else {
748 MSVCRT_INVALID_PMT("mbstr[size] is too small", ERANGE);
749 conv = 0;
750 if(size)
751 mbstr[0] = '\0';
752 err = ERANGE;
755 if(ret)
756 *ret = conv;
757 return err;
760 /*********************************************************************
761 * _wcstombs_s_l (MSVCRT.@)
763 int CDECL _wcstombs_s_l(size_t *ret, char *mbstr, size_t size,
764 const wchar_t *wcstr, size_t count, _locale_t locale)
766 return wcsrtombs_s_l(ret, mbstr, size, &wcstr,count, locale);
769 /*********************************************************************
770 * wcstombs_s (MSVCRT.@)
772 int CDECL wcstombs_s(size_t *ret, char *mbstr, size_t size,
773 const wchar_t *wcstr, size_t count)
775 return wcsrtombs_s_l(ret, mbstr, size, &wcstr, count, NULL);
778 /*********************************************************************
779 * wcsrtombs_s (MSVCRT.@)
781 int CDECL wcsrtombs_s(size_t *ret, char *mbstr, size_t size,
782 const wchar_t **wcstr, size_t count, mbstate_t *mbstate)
784 if(mbstate)
785 *mbstate = 0;
787 return wcsrtombs_s_l(ret, mbstr, size, wcstr, count, NULL);
790 /*********************************************************************
791 * wcstod (MSVCRT.@)
793 double CDECL wcstod(const wchar_t* lpszStr, wchar_t** end)
795 return _wcstod_l(lpszStr, end, NULL);
798 /*********************************************************************
799 * _wtof (MSVCRT.@)
801 double CDECL _wtof(const wchar_t *str)
803 return _wcstod_l(str, NULL, NULL);
806 /*********************************************************************
807 * _wtof_l (MSVCRT.@)
809 double CDECL _wtof_l(const wchar_t *str, _locale_t locale)
811 return _wcstod_l(str, NULL, locale);
814 #if _MSVCR_VER>=120
816 /*********************************************************************
817 * _wcstof_l (MSVCR120.@)
819 float CDECL _wcstof_l( const wchar_t *str, wchar_t **end, _locale_t locale )
821 double ret = _wcstod_l(str, end, locale);
822 if (ret && isfinite(ret)) {
823 float f = ret;
824 if (!f || !isfinite(f))
825 *_errno() = ERANGE;
827 return ret;
830 /*********************************************************************
831 * wcstof (MSVCR120.@)
833 float CDECL wcstof( const wchar_t *str, wchar_t **end )
835 return _wcstof_l(str, end, NULL);
838 #endif /* _MSVCR_VER>=120 */
840 /*********************************************************************
841 * arg_clbk_valist (INTERNAL)
843 printf_arg arg_clbk_valist(void *ctx, int arg_pos, int type, va_list *valist)
845 printf_arg ret;
847 if(type == VT_I8)
848 ret.get_longlong = va_arg(*valist, LONGLONG);
849 else if(type == VT_INT)
850 ret.get_int = va_arg(*valist, int);
851 else if(type == VT_R8)
852 ret.get_double = va_arg(*valist, double);
853 else if(type == VT_PTR)
854 ret.get_ptr = va_arg(*valist, void*);
855 else {
856 ERR("Incorrect type\n");
857 ret.get_int = 0;
860 return ret;
863 /*********************************************************************
864 * arg_clbk_positional (INTERNAL)
866 printf_arg arg_clbk_positional(void *ctx, int pos, int type, va_list *valist)
868 printf_arg *args = ctx;
869 return args[pos];
872 #if _MSVCR_VER < 140
874 /*********************************************************************
875 * _vsnprintf (MSVCRT.@)
877 int CDECL _vsnprintf( char *str, size_t len, const char *format, va_list valist )
879 static const char nullbyte = '\0';
880 struct _str_ctx_a ctx = {len, str};
881 int ret;
883 ret = pf_printf_a(puts_clbk_str_a, &ctx, format, NULL, 0,
884 arg_clbk_valist, NULL, &valist);
885 puts_clbk_str_a(&ctx, 1, &nullbyte);
886 return ret;
889 #else
891 static int puts_clbk_str_c99_a(void *ctx, int len, const char *str)
893 struct _str_ctx_a *out = ctx;
895 if(!out->buf)
896 return len;
898 if(out->len < len) {
899 memmove(out->buf, str, out->len);
900 out->buf += out->len;
901 out->len = 0;
902 return len;
905 memmove(out->buf, str, len);
906 out->buf += len;
907 out->len -= len;
908 return len;
911 /*********************************************************************
912 * __stdio_common_vsprintf (UCRTBASE.@)
914 int CDECL __stdio_common_vsprintf( unsigned __int64 options, char *str, size_t len, const char *format,
915 _locale_t locale, va_list valist )
917 static const char nullbyte = '\0';
918 struct _str_ctx_a ctx = {len, str};
919 int ret;
921 if (options & ~UCRTBASE_PRINTF_MASK)
922 FIXME("options %#I64x not handled\n", options);
923 ret = pf_printf_a(puts_clbk_str_c99_a,
924 &ctx, format, (_locale_t)locale, options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
925 puts_clbk_str_a(&ctx, 1, &nullbyte);
927 if(!str)
928 return ret;
929 if(options & _CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION)
930 return ret>len ? -1 : ret;
931 if(ret>=len) {
932 if(len) str[len-1] = 0;
933 if(options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR)
934 return ret;
935 return len > 0 ? -2 : -1;
937 return ret;
940 #endif /* _MSVCR_VER>=140 */
942 /*********************************************************************
943 * _vsnprintf_l (MSVCRT.@)
945 int CDECL _vsnprintf_l( char *str, size_t len, const char *format,
946 _locale_t locale, va_list valist )
948 static const char nullbyte = '\0';
949 struct _str_ctx_a ctx = {len, str};
950 int ret;
952 ret = pf_printf_a(puts_clbk_str_a, &ctx, format, locale, 0,
953 arg_clbk_valist, NULL, &valist);
954 puts_clbk_str_a(&ctx, 1, &nullbyte);
955 return ret;
958 /*********************************************************************
959 * _vsprintf_l (MSVCRT.@)
961 int CDECL _vsprintf_l( char *str, const char *format,
962 _locale_t locale, va_list valist )
964 return _vsnprintf_l(str, INT_MAX, format, locale, valist);
967 /*********************************************************************
968 * _sprintf_l (MSVCRT.@)
970 int WINAPIV _sprintf_l(char *str, const char *format,
971 _locale_t locale, ...)
973 int retval;
974 va_list valist;
975 va_start(valist, locale);
976 retval = _vsnprintf_l(str, INT_MAX, format, locale, valist);
977 va_end(valist);
978 return retval;
981 static int CDECL vsnprintf_s_l_opt( char *str, size_t sizeOfBuffer,
982 size_t count, const char *format, DWORD options,
983 _locale_t locale, va_list valist )
985 static const char nullbyte = '\0';
986 struct _str_ctx_a ctx;
987 int len, ret;
989 if(sizeOfBuffer<count+1 || count==-1)
990 len = sizeOfBuffer;
991 else
992 len = count+1;
994 ctx.len = len;
995 ctx.buf = str;
996 ret = pf_printf_a(puts_clbk_str_a, &ctx, format, locale, MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
997 arg_clbk_valist, NULL, &valist);
998 puts_clbk_str_a(&ctx, 1, &nullbyte);
1000 if(ret<0 || ret==len) {
1001 if(count!=_TRUNCATE && count>sizeOfBuffer) {
1002 MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small", ERANGE);
1003 memset(str, 0, sizeOfBuffer);
1004 } else
1005 str[len-1] = '\0';
1007 return -1;
1010 return ret;
1013 static int vsnwprintf_s_l_opt( wchar_t *str, size_t sizeOfBuffer,
1014 size_t count, const wchar_t *format, DWORD options,
1015 _locale_t locale, va_list valist)
1017 struct _str_ctx_w ctx;
1018 int len, ret;
1020 len = sizeOfBuffer;
1021 if(count!=-1 && len>count+1)
1022 len = count+1;
1024 ctx.len = len;
1025 ctx.buf = str;
1026 ret = pf_printf_w(puts_clbk_str_w, &ctx, format, locale, MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
1027 arg_clbk_valist, NULL, &valist);
1028 puts_clbk_str_w(&ctx, 1, L"");
1030 if(ret<0 || ret==len) {
1031 if(count!=_TRUNCATE && count>sizeOfBuffer) {
1032 MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small", ERANGE);
1033 memset(str, 0, sizeOfBuffer*sizeof(wchar_t));
1034 } else
1035 str[len-1] = '\0';
1037 return -1;
1040 return ret;
1043 /*********************************************************************
1044 * _vsnprintf_s_l (MSVCRT.@)
1046 int CDECL _vsnprintf_s_l( char *str, size_t sizeOfBuffer,
1047 size_t count, const char *format,
1048 _locale_t locale, va_list valist )
1050 return vsnprintf_s_l_opt(str, sizeOfBuffer, count, format, 0, locale, valist);
1053 /*********************************************************************
1054 * _vsprintf_s_l (MSVCRT.@)
1056 int CDECL _vsprintf_s_l( char *str, size_t count, const char *format,
1057 _locale_t locale, va_list valist )
1059 return _vsnprintf_s_l(str, INT_MAX, count, format, locale, valist);
1062 /*********************************************************************
1063 * _sprintf_s_l (MSVCRT.@)
1065 int WINAPIV _sprintf_s_l( char *str, size_t count, const char *format,
1066 _locale_t locale, ...)
1068 int retval;
1069 va_list valist;
1070 va_start(valist, locale);
1071 retval = _vsnprintf_s_l(str, INT_MAX, count, format, locale, valist);
1072 va_end(valist);
1073 return retval;
1076 /*********************************************************************
1077 * _vsnprintf_s (MSVCRT.@)
1079 int CDECL _vsnprintf_s( char *str, size_t sizeOfBuffer,
1080 size_t count, const char *format, va_list valist )
1082 return _vsnprintf_s_l(str,sizeOfBuffer, count, format, NULL, valist);
1085 /*********************************************************************
1086 * _vsnprintf_c_l (MSVCRT.@)
1088 int CDECL _vsnprintf_c_l(char *str, size_t len, const char *format,
1089 _locale_t locale, va_list valist)
1091 return vsnprintf_s_l_opt(str, len, len, format, 0, locale, valist);
1094 /*********************************************************************
1095 * _vsnprintf_c (MSVCRT.@)
1097 int CDECL _vsnprintf_c(char *str, size_t len,
1098 const char *format, va_list valist)
1100 return _vsnprintf_c_l(str, len, format, NULL, valist);
1103 #if _MSVCR_VER>=140
1105 /*********************************************************************
1106 * __stdio_common_vsnprintf_s (UCRTBASE.@)
1108 int CDECL __stdio_common_vsnprintf_s( unsigned __int64 options,
1109 char *str, size_t sizeOfBuffer, size_t count,
1110 const char *format, _locale_t locale, va_list valist )
1112 if (options & ~UCRTBASE_PRINTF_MASK)
1113 FIXME("options %#I64x not handled\n", options);
1114 return vsnprintf_s_l_opt(str, sizeOfBuffer, count, format, options & UCRTBASE_PRINTF_MASK, locale, valist);
1117 /*********************************************************************
1118 * __stdio_common_vsnwprintf_s (UCRTBASE.@)
1120 int CDECL __stdio_common_vsnwprintf_s( unsigned __int64 options,
1121 wchar_t *str, size_t sizeOfBuffer, size_t count,
1122 const wchar_t *format, _locale_t locale, va_list valist )
1124 if (options & ~UCRTBASE_PRINTF_MASK)
1125 FIXME("options %#I64x not handled\n", options);
1126 return vsnwprintf_s_l_opt(str, sizeOfBuffer, count, format, options & UCRTBASE_PRINTF_MASK, locale, valist);
1129 /*********************************************************************
1130 * __stdio_common_vswprintf_s (UCRTBASE.@)
1132 int CDECL __stdio_common_vswprintf_s( unsigned __int64 options,
1133 wchar_t *str, size_t count, const wchar_t *format,
1134 _locale_t locale, va_list valist )
1136 return __stdio_common_vsnwprintf_s(options, str, INT_MAX, count, format, locale, valist);
1139 /*********************************************************************
1140 * __stdio_common_vsprintf_s (UCRTBASE.@)
1142 int CDECL __stdio_common_vsprintf_s( unsigned __int64 options,
1143 char *str, size_t count, const char *format,
1144 _locale_t locale, va_list valist )
1146 if (options & ~UCRTBASE_PRINTF_MASK)
1147 FIXME("options %#I64x not handled\n", options);
1148 return vsnprintf_s_l_opt(str, INT_MAX, count, format, options & UCRTBASE_PRINTF_MASK, locale, valist);
1151 #endif /* _MSVCR_VER>=140 */
1153 /*********************************************************************
1154 * vsprintf (MSVCRT.@)
1156 int CDECL vsprintf( char *str, const char *format, va_list valist)
1158 return vsnprintf(str, INT_MAX, format, valist);
1161 /*********************************************************************
1162 * vsprintf_s (MSVCRT.@)
1164 int CDECL vsprintf_s( char *str, size_t num, const char *format, va_list valist)
1166 return vsnprintf(str, num, format, valist);
1169 /*********************************************************************
1170 * _vscprintf (MSVCRT.@)
1172 int CDECL _vscprintf( const char *format, va_list valist )
1174 return _vsnprintf_l( NULL, INT_MAX, format, NULL, valist );
1177 /*********************************************************************
1178 * _vscprintf_l (MSVCRT.@)
1180 int CDECL _vscprintf_l(const char *format,
1181 _locale_t locale, va_list valist)
1183 return _vsnprintf_l(NULL, INT_MAX, format, locale, valist);
1186 /*********************************************************************
1187 * _vscprintf_p_l (MSVCRT.@)
1189 int CDECL _vscprintf_p_l(const char *format,
1190 _locale_t locale, va_list args)
1192 printf_arg args_ctx[_ARGMAX+1];
1193 struct _str_ctx_a puts_ctx = {INT_MAX, NULL};
1194 int ret;
1196 memset(args_ctx, 0, sizeof(args_ctx));
1198 ret = create_positional_ctx_a(args_ctx, format, args);
1199 if(ret < 0) {
1200 _invalid_parameter(NULL, NULL, NULL, 0, 0);
1201 *_errno() = EINVAL;
1202 return ret;
1203 } else if(ret == 0) {
1204 ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale,
1205 MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
1206 arg_clbk_valist, NULL, &args);
1207 } else {
1208 ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale,
1209 MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER,
1210 arg_clbk_positional, args_ctx, NULL);
1213 return ret;
1216 /*********************************************************************
1217 * _vscprintf_p (MSVCR80.@)
1219 int CDECL _vscprintf_p(const char *format, va_list argptr)
1221 return _vscprintf_p_l(format, NULL, argptr);
1224 /*********************************************************************
1225 * _snprintf (MSVCRT.@)
1227 int WINAPIV _snprintf(char *str, size_t len, const char *format, ...)
1229 int retval;
1230 va_list valist;
1231 va_start(valist, format);
1232 retval = vsnprintf(str, len, format, valist);
1233 va_end(valist);
1234 return retval;
1237 /*********************************************************************
1238 * _snprintf_l (MSVCRT.@)
1240 int WINAPIV _snprintf_l(char *str, size_t count, const char *format,
1241 _locale_t locale, ...)
1243 int retval;
1244 va_list valist;
1245 va_start(valist, locale);
1246 retval = _vsnprintf_l(str, count, format, locale, valist);
1247 va_end(valist);
1248 return retval;
1251 /*********************************************************************
1252 * _snprintf_c_l (MSVCRT.@)
1254 int WINAPIV _snprintf_c_l(char *str, size_t count, const char *format,
1255 _locale_t locale, ...)
1257 int retval;
1258 va_list valist;
1259 va_start(valist, locale);
1260 retval = _vsnprintf_c_l(str, count, format, locale, valist);
1261 va_end(valist);
1262 return retval;
1265 /*********************************************************************
1266 * _snprintf_c (MSVCRT.@)
1268 int WINAPIV _snprintf_c(char *str, size_t count, const char *format, ...)
1270 int retval;
1271 va_list valist;
1272 va_start(valist, format);
1273 retval = _vsnprintf_c(str, count, format, valist);
1274 va_end(valist);
1275 return retval;
1278 /*********************************************************************
1279 * _snprintf_s_l (MSVCRT.@)
1281 int WINAPIV _snprintf_s_l(char *str, size_t len, size_t count,
1282 const char *format, _locale_t locale, ...)
1284 int retval;
1285 va_list valist;
1286 va_start(valist, locale);
1287 retval = _vsnprintf_s_l(str, len, count, format, locale, valist);
1288 va_end(valist);
1289 return retval;
1292 /*********************************************************************
1293 * _snprintf_s (MSVCRT.@)
1295 int WINAPIV _snprintf_s(char *str, size_t len, size_t count,
1296 const char *format, ...)
1298 int retval;
1299 va_list valist;
1300 va_start(valist, format);
1301 retval = _vsnprintf_s_l(str, len, count, format, NULL, valist);
1302 va_end(valist);
1303 return retval;
1306 /*********************************************************************
1307 * _scprintf (MSVCRT.@)
1309 int WINAPIV _scprintf(const char *format, ...)
1311 int retval;
1312 va_list valist;
1313 va_start(valist, format);
1314 retval = _vscprintf(format, valist);
1315 va_end(valist);
1316 return retval;
1319 /*********************************************************************
1320 * _vsnwprintf (MSVCRT.@)
1322 int CDECL _vsnwprintf(wchar_t *str, size_t len,
1323 const wchar_t *format, va_list valist)
1325 struct _str_ctx_w ctx = {len, str};
1326 int ret;
1328 ret = pf_printf_w(puts_clbk_str_w, &ctx, format, NULL, 0,
1329 arg_clbk_valist, NULL, &valist);
1330 puts_clbk_str_w(&ctx, 1, L"");
1331 return ret;
1334 /*********************************************************************
1335 * _vsnwprintf_l (MSVCRT.@)
1337 int CDECL _vsnwprintf_l(wchar_t *str, size_t len, const wchar_t *format,
1338 _locale_t locale, va_list valist)
1340 struct _str_ctx_w ctx = {len, str};
1341 int ret;
1343 ret = pf_printf_w(puts_clbk_str_w, &ctx, format, locale, 0,
1344 arg_clbk_valist, NULL, &valist);
1345 puts_clbk_str_w(&ctx, 1, L"");
1346 return ret;
1349 /*********************************************************************
1350 * _vswprintf_c_l (MSVCRT.@)
1352 int CDECL _vswprintf_c_l(wchar_t *str, size_t len, const wchar_t *format,
1353 _locale_t locale, va_list valist)
1355 return vsnwprintf_s_l_opt(str, len, len, format, 0, locale, valist);
1358 /*********************************************************************
1359 * _vswprintf_c (MSVCRT.@)
1361 int CDECL _vswprintf_c(wchar_t *str, size_t len,
1362 const wchar_t *format, va_list valist)
1364 return _vswprintf_c_l(str, len, format, NULL, valist);
1367 static int vswprintf_p_l_opt(wchar_t *buffer, size_t length,
1368 const wchar_t *format, DWORD options, _locale_t locale, va_list args)
1370 printf_arg args_ctx[_ARGMAX+1];
1371 struct _str_ctx_w puts_ctx = {length, buffer};
1372 int ret;
1374 memset(args_ctx, 0, sizeof(args_ctx));
1376 ret = create_positional_ctx_w(args_ctx, format, args);
1377 if(ret < 0) {
1378 _invalid_parameter(NULL, NULL, NULL, 0, 0);
1379 *_errno() = EINVAL;
1380 return ret;
1381 } else if(ret == 0)
1382 ret = pf_printf_w(puts_clbk_str_w, &puts_ctx, format, locale, MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
1383 arg_clbk_valist, NULL, &args);
1384 else
1385 ret = pf_printf_w(puts_clbk_str_w, &puts_ctx, format, locale,
1386 MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
1387 arg_clbk_positional, args_ctx, NULL);
1389 puts_clbk_str_w(&puts_ctx, 1, L"");
1390 return ret;
1393 /*********************************************************************
1394 * _vswprintf_p_l (MSVCRT.@)
1396 int CDECL _vswprintf_p_l(wchar_t *buffer, size_t length,
1397 const wchar_t *format, _locale_t locale, va_list args)
1399 return vswprintf_p_l_opt(buffer, length, format, 0, locale, args);
1402 #if _MSVCR_VER>=80
1403 /*********************************************************************
1404 * _vswprintf_p (MSVCR80.@)
1406 int CDECL _vswprintf_p(wchar_t *buffer, size_t length,
1407 const wchar_t *format, va_list args)
1409 return vswprintf_p_l_opt(buffer, length, format, 0, NULL, args);
1411 #endif
1413 #if _MSVCR_VER>=140
1414 /*********************************************************************
1415 * __stdio_common_vswprintf_p (UCRTBASE.@)
1417 int CDECL __stdio_common_vswprintf_p( unsigned __int64 options,
1418 wchar_t *str, size_t count, const wchar_t *format,
1419 _locale_t locale, va_list valist )
1421 if (options & ~UCRTBASE_PRINTF_MASK)
1422 FIXME("options %#I64x not handled\n", options);
1423 return vswprintf_p_l_opt(str, count, format, options & UCRTBASE_PRINTF_MASK, locale, valist);
1425 #endif
1427 /*********************************************************************
1428 * _vsnwprintf_s_l (MSVCRT.@)
1430 int CDECL _vsnwprintf_s_l( wchar_t *str, size_t sizeOfBuffer,
1431 size_t count, const wchar_t *format,
1432 _locale_t locale, va_list valist)
1434 return vsnwprintf_s_l_opt(str, sizeOfBuffer, count, format, 0, locale, valist);
1437 /*********************************************************************
1438 * _vsnwprintf_s (MSVCRT.@)
1440 int CDECL _vsnwprintf_s(wchar_t *str, size_t sizeOfBuffer,
1441 size_t count, const wchar_t *format, va_list valist)
1443 return _vsnwprintf_s_l(str, sizeOfBuffer, count,
1444 format, NULL, valist);
1447 /*********************************************************************
1448 * _snwprintf (MSVCRT.@)
1450 int WINAPIV _snwprintf( wchar_t *str, size_t len, const wchar_t *format, ...)
1452 int retval;
1453 va_list valist;
1454 va_start(valist, format);
1455 retval = _vsnwprintf(str, len, format, valist);
1456 va_end(valist);
1457 return retval;
1460 /*********************************************************************
1461 * _snwprintf_l (MSVCRT.@)
1463 int WINAPIV _snwprintf_l( wchar_t *str, size_t len, const wchar_t *format,
1464 _locale_t locale, ...)
1466 int retval;
1467 va_list valist;
1468 va_start(valist, locale);
1469 retval = _vsnwprintf_l(str, len, format, locale, valist);
1470 va_end(valist);
1471 return retval;
1474 /*********************************************************************
1475 * _snwprintf_s (MSVCRT.@)
1477 int WINAPIV _snwprintf_s( wchar_t *str, size_t len, size_t count,
1478 const wchar_t *format, ...)
1480 int retval;
1481 va_list valist;
1482 va_start(valist, format);
1483 retval = _vsnwprintf_s_l(str, len, count, format, NULL, valist);
1484 va_end(valist);
1485 return retval;
1488 /*********************************************************************
1489 * _snwprintf_s_l (MSVCRT.@)
1491 int WINAPIV _snwprintf_s_l( wchar_t *str, size_t len, size_t count,
1492 const wchar_t *format, _locale_t locale, ... )
1494 int retval;
1495 va_list valist;
1496 va_start(valist, locale);
1497 retval = _vsnwprintf_s_l(str, len, count, format, locale, valist);
1498 va_end(valist);
1499 return retval;
1502 #if _MSVCR_VER>=140
1504 static int puts_clbk_str_c99_w(void *ctx, int len, const wchar_t *str)
1506 struct _str_ctx_w *out = ctx;
1508 if(!out->buf)
1509 return len;
1511 if(out->len < len) {
1512 memcpy(out->buf, str, out->len*sizeof(wchar_t));
1513 out->buf += out->len;
1514 out->len = 0;
1515 return len;
1518 memcpy(out->buf, str, len*sizeof(wchar_t));
1519 out->buf += len;
1520 out->len -= len;
1521 return len;
1524 /*********************************************************************
1525 * __stdio_common_vswprintf (UCRTBASE.@)
1527 int CDECL __stdio_common_vswprintf( unsigned __int64 options,
1528 wchar_t *str, size_t len, const wchar_t *format,
1529 _locale_t locale, va_list valist )
1531 struct _str_ctx_w ctx = {len, str};
1532 int ret;
1534 if (options & ~UCRTBASE_PRINTF_MASK)
1535 FIXME("options %#I64x not handled\n", options);
1536 ret = pf_printf_w(puts_clbk_str_c99_w,
1537 &ctx, format, locale, options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
1538 puts_clbk_str_w(&ctx, 1, L"");
1540 if(!str)
1541 return ret;
1542 if(options & _CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION)
1543 return ret>len ? -1 : ret;
1544 if(ret>=len) {
1545 if(len) str[len-1] = 0;
1546 if(options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR)
1547 return ret;
1548 return len > 0 ? -2 : -1;
1550 return ret;
1553 #endif /* _MSVCR_VER>=140 */
1555 /*********************************************************************
1556 * sprintf (MSVCRT.@)
1558 int WINAPIV sprintf( char *str, const char *format, ... )
1560 va_list ap;
1561 int r;
1563 va_start( ap, format );
1564 r = vsnprintf( str, INT_MAX, format, ap );
1565 va_end( ap );
1566 return r;
1569 /*********************************************************************
1570 * sprintf_s (MSVCRT.@)
1572 int WINAPIV sprintf_s( char *str, size_t num, const char *format, ... )
1574 va_list ap;
1575 int r;
1577 va_start( ap, format );
1578 r = vsnprintf( str, num, format, ap );
1579 va_end( ap );
1580 return r;
1583 /*********************************************************************
1584 * _scwprintf (MSVCRT.@)
1586 int WINAPIV _scwprintf( const wchar_t *format, ... )
1588 va_list ap;
1589 int r;
1591 va_start( ap, format );
1592 r = _vsnwprintf( NULL, INT_MAX, format, ap );
1593 va_end( ap );
1594 return r;
1597 /*********************************************************************
1598 * swprintf (MSVCRT.@)
1600 int WINAPIV _swprintf( wchar_t *str, const wchar_t *format, ... )
1602 va_list ap;
1603 int r;
1605 va_start( ap, format );
1606 r = _vsnwprintf( str, INT_MAX, format, ap );
1607 va_end( ap );
1608 return r;
1611 /*********************************************************************
1612 * swprintf_s (MSVCRT.@)
1614 int WINAPIV swprintf_s(wchar_t *str, size_t numberOfElements,
1615 const wchar_t *format, ... )
1617 va_list ap;
1618 int r;
1620 va_start(ap, format);
1621 r = _vsnwprintf_s(str, numberOfElements, INT_MAX, format, ap);
1622 va_end(ap);
1624 return r;
1627 /*********************************************************************
1628 * _swprintf_s_l (MSVCRT.@)
1630 int WINAPIV _swprintf_s_l(wchar_t *str, size_t numberOfElements,
1631 const wchar_t *format, _locale_t locale, ... )
1633 va_list ap;
1634 int r;
1636 va_start(ap, locale);
1637 r = _vsnwprintf_s_l(str, numberOfElements, INT_MAX, format, locale, ap);
1638 va_end(ap);
1640 return r;
1643 /*********************************************************************
1644 * _swprintf_c_l (MSVCRT.@)
1646 int WINAPIV _swprintf_c_l(wchar_t *str, size_t len,
1647 const wchar_t *format, _locale_t locale, ... )
1649 va_list ap;
1650 int r;
1652 va_start(ap, locale);
1653 r = _vswprintf_c_l(str, len, format, locale, ap);
1654 va_end(ap);
1656 return r;
1659 /*********************************************************************
1660 * _swprintf_c (MSVCRT.@)
1662 int WINAPIV _swprintf_c(wchar_t *str, size_t len,
1663 const wchar_t *format, ... )
1665 va_list ap;
1666 int r;
1668 va_start(ap, format);
1669 r = _vswprintf_c(str, len, format, ap);
1670 va_end(ap);
1672 return r;
1675 /*********************************************************************
1676 * _vswprintf (MSVCRT.@)
1678 int CDECL _vswprintf( wchar_t* str, const wchar_t* format, va_list args )
1680 return _vsnwprintf( str, INT_MAX, format, args );
1683 /*********************************************************************
1684 * _vswprintf (MSVCRT.@)
1686 int CDECL _vswprintf_l( wchar_t* str, const wchar_t* format,
1687 _locale_t locale, va_list args )
1689 return _vsnwprintf_l( str, INT_MAX, format, locale, args );
1692 /*********************************************************************
1693 * _vscwprintf (MSVCRT.@)
1695 int CDECL _vscwprintf( const wchar_t *format, va_list args )
1697 return _vsnwprintf( NULL, INT_MAX, format, args );
1700 /*********************************************************************
1701 * _vscwprintf_l (MSVCRT.@)
1703 int CDECL _vscwprintf_l( const wchar_t *format, _locale_t locale, va_list args )
1705 return _vsnwprintf_l( NULL, INT_MAX, format, locale, args );
1708 /*********************************************************************
1709 * _vscwprintf_p_l (MSVCRT.@)
1711 int CDECL _vscwprintf_p_l( const wchar_t *format, _locale_t locale, va_list args )
1713 return vswprintf_p_l_opt( NULL, INT_MAX, format, 0, locale, args );
1716 #if _MSVCR_VER>=80
1717 /*********************************************************************
1718 * _vscwprintf_p (MSVCR80.@)
1720 int CDECL _vscwprintf_p(const wchar_t *format, va_list args)
1722 return vswprintf_p_l_opt(NULL, INT_MAX, format, 0, NULL, args);
1724 #endif
1726 /*********************************************************************
1727 * vswprintf_s (MSVCRT.@)
1729 int CDECL vswprintf_s(wchar_t* str, size_t numberOfElements,
1730 const wchar_t* format, va_list args)
1732 return _vsnwprintf_s(str, numberOfElements, INT_MAX, format, args );
1735 /*********************************************************************
1736 * _vswprintf_s_l (MSVCRT.@)
1738 int CDECL _vswprintf_s_l(wchar_t* str, size_t numberOfElements,
1739 const wchar_t* format, _locale_t locale, va_list args)
1741 return _vsnwprintf_s_l(str, numberOfElements, INT_MAX,
1742 format, locale, args );
1745 static int vsprintf_p_l_opt(char *buffer, size_t length, const char *format,
1746 DWORD options, _locale_t locale, va_list args)
1748 static const char nullbyte = '\0';
1749 printf_arg args_ctx[_ARGMAX+1];
1750 struct _str_ctx_a puts_ctx = {length, buffer};
1751 int ret;
1753 memset(args_ctx, 0, sizeof(args_ctx));
1755 ret = create_positional_ctx_a(args_ctx, format, args);
1756 if(ret < 0) {
1757 _invalid_parameter(NULL, NULL, NULL, 0, 0);
1758 *_errno() = EINVAL;
1759 return ret;
1760 } else if(ret == 0)
1761 ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale,
1762 MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options, arg_clbk_valist, NULL, &args);
1763 else
1764 ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale,
1765 MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
1766 arg_clbk_positional, args_ctx, NULL);
1768 puts_clbk_str_a(&puts_ctx, 1, &nullbyte);
1769 return ret;
1772 /*********************************************************************
1773 * _vsprintf_p_l (MSVCRT.@)
1775 int CDECL _vsprintf_p_l(char *buffer, size_t length, const char *format,
1776 _locale_t locale, va_list args)
1778 return vsprintf_p_l_opt(buffer, length, format, 0, locale, args);
1781 /*********************************************************************
1782 * _vsprintf_p (MSVCRT.@)
1784 int CDECL _vsprintf_p(char *buffer, size_t length,
1785 const char *format, va_list args)
1787 return _vsprintf_p_l(buffer, length, format, NULL, args);
1790 #if _MSVCR_VER>=140
1791 /*********************************************************************
1792 * __stdio_common_vsprintf_p (UCRTBASE.@)
1794 int CDECL __stdio_common_vsprintf_p(unsigned __int64 options, char *buffer, size_t length,
1795 const char *format, _locale_t locale, va_list args)
1797 if (options & ~UCRTBASE_PRINTF_MASK)
1798 FIXME("options %#I64x not handled\n", options);
1799 return vsprintf_p_l_opt(buffer, length, format, options & UCRTBASE_PRINTF_MASK, locale, args);
1801 #endif
1803 /*********************************************************************
1804 * _sprintf_p_l (MSVCRT.@)
1806 int WINAPIV _sprintf_p_l(char *buffer, size_t length,
1807 const char *format, _locale_t locale, ...)
1809 va_list valist;
1810 int r;
1812 va_start(valist, locale);
1813 r = _vsprintf_p_l(buffer, length, format, locale, valist);
1814 va_end(valist);
1816 return r;
1819 /*********************************************************************
1820 * __swprintf_l (MSVCRT.@)
1822 int WINAPIV __swprintf_l( wchar_t *str, const wchar_t *format,
1823 _locale_t locale, ...)
1825 int retval;
1826 va_list valist;
1827 va_start(valist, locale);
1828 retval = _vswprintf_l(str, format, locale, valist);
1829 va_end(valist);
1830 return retval;
1833 #if _MSVCR_VER>=80
1834 /*********************************************************************
1835 * _sprintf_p (MSVCR80.@)
1837 int WINAPIV _sprintf_p(char *buffer, size_t length, const char *format, ...)
1839 va_list valist;
1840 int r;
1842 va_start(valist, format);
1843 r = _vsprintf_p_l(buffer, length, format, NULL, valist);
1844 va_end(valist);
1846 return r;
1848 #endif
1850 /*********************************************************************
1851 * _swprintf_p_l (MSVCRT.@)
1853 int WINAPIV _swprintf_p_l(wchar_t *buffer, size_t length,
1854 const wchar_t *format, _locale_t locale, ...)
1856 va_list valist;
1857 int r;
1859 va_start(valist, locale);
1860 r = vswprintf_p_l_opt(buffer, length, format, 0, locale, valist);
1861 va_end(valist);
1863 return r;
1866 /*********************************************************************
1867 * wcscmp (MSVCRT.@)
1869 int CDECL wcscmp(const wchar_t *str1, const wchar_t *str2)
1871 while (*str1 && (*str1 == *str2))
1873 str1++;
1874 str2++;
1877 if (*str1 < *str2)
1878 return -1;
1879 if (*str1 > *str2)
1880 return 1;
1881 return 0;
1884 /*********************************************************************
1885 * _wcscoll_l (MSVCRT.@)
1887 int CDECL _wcscoll_l(const wchar_t* str1, const wchar_t* str2, _locale_t locale)
1889 pthreadlocinfo locinfo;
1891 if(!locale)
1892 locinfo = get_locinfo();
1893 else
1894 locinfo = locale->locinfo;
1896 if(!locinfo->lc_handle[LC_COLLATE])
1897 return wcscmp(str1, str2);
1898 return CompareStringW(locinfo->lc_handle[LC_COLLATE], 0, str1, -1, str2, -1)-CSTR_EQUAL;
1901 /*********************************************************************
1902 * wcscoll (MSVCRT.@)
1904 int CDECL wcscoll( const wchar_t* str1, const wchar_t* str2 )
1906 return _wcscoll_l(str1, str2, NULL);
1909 /*********************************************************************
1910 * wcspbrk (MSVCRT.@)
1912 wchar_t* CDECL wcspbrk( const wchar_t* str, const wchar_t* accept )
1914 const wchar_t* p;
1916 while (*str)
1918 for (p = accept; *p; p++) if (*p == *str) return (wchar_t*)str;
1919 str++;
1921 return NULL;
1924 /*********************************************************************
1925 * wcstok_s (MSVCRT.@)
1927 wchar_t * CDECL wcstok_s( wchar_t *str, const wchar_t *delim,
1928 wchar_t **next_token )
1930 wchar_t *ret;
1932 if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL;
1933 if (!MSVCRT_CHECK_PMT(next_token != NULL)) return NULL;
1934 if (!MSVCRT_CHECK_PMT(str != NULL || *next_token != NULL)) return NULL;
1936 if (!str) str = *next_token;
1938 while (*str && wcschr( delim, *str )) str++;
1939 if (!*str) ret = NULL;
1940 else
1942 ret = str++;
1943 while (*str && !wcschr( delim, *str )) str++;
1944 if (*str) *str++ = 0;
1946 *next_token = str;
1947 return ret;
1950 /*********************************************************************
1951 * wcstok (MSVCRT.@)
1953 #if _MSVCR_VER>=140
1954 wchar_t * CDECL wcstok( wchar_t *str, const wchar_t *delim, wchar_t **ctx )
1956 if (!ctx)
1957 ctx = &msvcrt_get_thread_data()->wcstok_next;
1958 return wcstok_s(str, delim, ctx);
1960 #else
1961 wchar_t * CDECL wcstok( wchar_t *str, const wchar_t *delim )
1963 return wcstok_s(str, delim, &msvcrt_get_thread_data()->wcstok_next);
1965 #endif
1967 /*********************************************************************
1968 * _wctomb_s_l (MSVCRT.@)
1970 int CDECL _wctomb_s_l(int *len, char *mbchar, size_t size,
1971 wchar_t wch, _locale_t locale)
1973 pthreadlocinfo locinfo;
1974 BOOL error = FALSE;
1975 BOOL *perror;
1976 int mblen;
1978 if(!mbchar && size>0) {
1979 if(len)
1980 *len = 0;
1981 return 0;
1984 if(len)
1985 *len = -1;
1987 if(!MSVCRT_CHECK_PMT(size <= INT_MAX))
1988 return EINVAL;
1990 if(!locale)
1991 locinfo = get_locinfo();
1992 else
1993 locinfo = locale->locinfo;
1995 if(!locinfo->lc_codepage) {
1996 if(wch > 0xff) {
1997 if(mbchar && size>0)
1998 memset(mbchar, 0, size);
1999 *_errno() = EILSEQ;
2000 return EILSEQ;
2003 if(!MSVCRT_CHECK_PMT_ERR(size >= 1, ERANGE))
2004 return ERANGE;
2006 *mbchar = wch;
2007 if(len)
2008 *len = 1;
2009 return 0;
2012 perror = (locinfo->lc_codepage != CP_UTF8 ? &error : NULL);
2013 mblen = WideCharToMultiByte(locinfo->lc_codepage, 0, &wch, 1, mbchar, size, NULL, perror);
2014 if(!mblen || error) {
2015 if(!mblen && GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
2016 if(mbchar && size>0)
2017 memset(mbchar, 0, size);
2019 MSVCRT_INVALID_PMT("insufficient buffer size", ERANGE);
2020 return ERANGE;
2023 *_errno() = EILSEQ;
2024 return EILSEQ;
2027 if(len)
2028 *len = mblen;
2029 return 0;
2032 /*********************************************************************
2033 * wctomb_s (MSVCRT.@)
2035 int CDECL wctomb_s(int *len, char *mbchar, size_t size, wchar_t wch)
2037 return _wctomb_s_l(len, mbchar, size, wch, NULL);
2040 /*********************************************************************
2041 * _wctomb_l (MSVCRT.@)
2043 int CDECL _wctomb_l(char *dst, wchar_t ch, _locale_t locale)
2045 int len;
2047 _wctomb_s_l(&len, dst, dst ? MB_LEN_MAX : 0, ch, locale);
2048 return len;
2051 /*********************************************************************
2052 * wctomb (MSVCRT.@)
2054 INT CDECL wctomb( char *dst, wchar_t ch )
2056 return _wctomb_l(dst, ch, NULL);
2059 /*********************************************************************
2060 * wctob (MSVCRT.@)
2062 INT CDECL wctob( wint_t wchar )
2064 char out;
2065 BOOL error = FALSE;
2066 BOOL *perror;
2067 UINT codepage = get_locinfo()->lc_codepage;
2069 perror = (codepage != CP_UTF8 ? &error : NULL);
2071 if(!codepage) {
2072 if (wchar < 0xff)
2073 return (signed char)wchar;
2074 else
2075 return EOF;
2076 } else if(WideCharToMultiByte( codepage, 0, &wchar, 1, &out, 1, NULL, perror ) && !error)
2077 return (INT)out;
2078 return EOF;
2081 /*********************************************************************
2082 * wcrtomb_s (MSVCRT.@)
2084 INT CDECL wcrtomb_s(size_t *len, char *mbchar,
2085 size_t size, wchar_t wch, mbstate_t *s)
2087 int ilen, ret;
2089 if (s) *s = 0;
2090 ret = wctomb_s(&ilen, mbchar, size, wch);
2091 if (len) *len = ilen;
2092 return ret;
2095 /*********************************************************************
2096 * wcrtomb (MSVCRT.@)
2098 size_t CDECL wcrtomb( char *dst, wchar_t ch, mbstate_t *s)
2100 if(s)
2101 *s = 0;
2102 return wctomb(dst, ch);
2105 /*********************************************************************
2106 * _iswctype_l (MSVCRT.@)
2108 INT CDECL _iswctype_l( wchar_t wc, wctype_t type, _locale_t locale )
2110 WORD ct;
2112 if (wc == WEOF) return 0;
2113 if (wc < 256) return MSVCRT__pwctype[wc] & type;
2115 if (!GetStringTypeW(CT_CTYPE1, &wc, 1, &ct))
2117 ERR("GetStringTypeW failed for %x\n", wc);
2118 return 0;
2120 return ct & type;
2123 /*********************************************************************
2124 * iswctype (MSVCRT.@)
2126 INT CDECL iswctype( wchar_t wc, wctype_t type )
2128 return _iswctype_l( wc, type, NULL );
2131 /*********************************************************************
2132 * _iswalnum_l (MSVCRT.@)
2134 int CDECL _iswalnum_l( wchar_t wc, _locale_t locale )
2136 return _iswctype_l( wc, _ALPHA | _DIGIT, locale );
2139 /*********************************************************************
2140 * iswalnum (MSVCRT.@)
2142 INT CDECL iswalnum( wchar_t wc )
2144 return _iswalnum_l( wc, NULL );
2147 /*********************************************************************
2148 * iswalpha_l (MSVCRT.@)
2150 INT CDECL _iswalpha_l( wchar_t wc, _locale_t locale )
2152 return _iswctype_l( wc, _ALPHA, locale );
2155 /*********************************************************************
2156 * iswalpha (MSVCRT.@)
2158 INT CDECL iswalpha( wchar_t wc )
2160 return _iswalpha_l( wc, NULL );
2163 /*********************************************************************
2164 * _iswcntrl_l (MSVCRT.@)
2166 int CDECL _iswcntrl_l( wchar_t wc, _locale_t locale )
2168 return _iswctype_l( wc, _CONTROL, locale );
2171 /*********************************************************************
2172 * iswcntrl (MSVCRT.@)
2174 INT CDECL iswcntrl( wchar_t wc )
2176 return _iswcntrl_l( wc, NULL );
2179 /*********************************************************************
2180 * _iswdigit_l (MSVCRT.@)
2182 INT CDECL _iswdigit_l( wchar_t wc, _locale_t locale )
2184 return _iswctype_l( wc, _DIGIT, locale );
2187 /*********************************************************************
2188 * iswdigit (MSVCRT.@)
2190 INT CDECL iswdigit( wchar_t wc )
2192 return _iswdigit_l( wc, NULL );
2195 /*********************************************************************
2196 * _iswgraph_l (MSVCRT.@)
2198 int CDECL _iswgraph_l( wchar_t wc, _locale_t locale )
2200 return _iswctype_l( wc, _ALPHA | _DIGIT | _PUNCT, locale );
2203 /*********************************************************************
2204 * iswgraph (MSVCRT.@)
2206 INT CDECL iswgraph( wchar_t wc )
2208 return _iswgraph_l( wc, NULL );
2211 /*********************************************************************
2212 * _iswlower_l (MSVCRT.@)
2214 int CDECL _iswlower_l( wchar_t wc, _locale_t locale )
2216 return _iswctype_l( wc, _LOWER, locale );
2219 /*********************************************************************
2220 * iswlower (MSVCRT.@)
2222 INT CDECL iswlower( wchar_t wc )
2224 return _iswlower_l( wc, NULL );
2227 /*********************************************************************
2228 * _iswprint_l (MSVCRT.@)
2230 int CDECL _iswprint_l( wchar_t wc, _locale_t locale )
2232 return _iswctype_l( wc, _ALPHA | _BLANK | _DIGIT | _PUNCT, locale );
2235 /*********************************************************************
2236 * iswprint (MSVCRT.@)
2238 INT CDECL iswprint( wchar_t wc )
2240 return _iswprint_l( wc, NULL );
2243 /*********************************************************************
2244 * _iswpunct_l (MSVCRT.@)
2246 INT CDECL _iswpunct_l( wchar_t wc, _locale_t locale )
2248 return _iswctype_l( wc, _PUNCT, locale );
2251 /*********************************************************************
2252 * iswpunct (MSVCRT.@)
2254 INT CDECL iswpunct( wchar_t wc )
2256 return _iswpunct_l( wc, NULL );
2259 /*********************************************************************
2260 * _iswspace_l (MSVCRT.@)
2262 INT CDECL _iswspace_l( wchar_t wc, _locale_t locale )
2264 return _iswctype_l( wc, _SPACE, locale );
2267 /*********************************************************************
2268 * iswspace (MSVCRT.@)
2270 INT CDECL iswspace( wchar_t wc )
2272 return _iswspace_l( wc, NULL );
2275 /*********************************************************************
2276 * _iswupper_l (MSVCRT.@)
2278 int CDECL _iswupper_l( wchar_t wc, _locale_t locale )
2280 return _iswctype_l( wc, _UPPER, locale );
2283 /*********************************************************************
2284 * iswupper (MSVCRT.@)
2286 INT CDECL iswupper( wchar_t wc )
2288 return _iswupper_l( wc, NULL );
2291 /*********************************************************************
2292 * _iswxdigit_l (MSVCRT.@)
2294 int CDECL _iswxdigit_l( wchar_t wc, _locale_t locale )
2296 return _iswctype_l( wc, _HEX, locale );
2299 /*********************************************************************
2300 * iswxdigit (MSVCRT.@)
2302 INT CDECL iswxdigit( wchar_t wc )
2304 return _iswxdigit_l( wc, NULL );
2307 /*********************************************************************
2308 * _iswblank_l (MSVCRT.@)
2310 INT CDECL _iswblank_l( wchar_t wc, _locale_t locale )
2312 return wc == '\t' || _iswctype_l( wc, _BLANK, locale );
2315 /*********************************************************************
2316 * iswblank (MSVCRT.@)
2318 INT CDECL iswblank( wchar_t wc )
2320 return wc == '\t' || _iswctype_l( wc, _BLANK, NULL );
2323 /*********************************************************************
2324 * wcscpy_s (MSVCRT.@)
2326 INT CDECL wcscpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc)
2328 size_t size = 0;
2330 if(!MSVCRT_CHECK_PMT(wcDest)) return EINVAL;
2331 if(!MSVCRT_CHECK_PMT(numElement)) return EINVAL;
2333 if(!MSVCRT_CHECK_PMT(wcSrc))
2335 wcDest[0] = 0;
2336 return EINVAL;
2339 size = wcslen(wcSrc) + 1;
2341 if(!MSVCRT_CHECK_PMT_ERR(size <= numElement, ERANGE))
2343 wcDest[0] = 0;
2344 return ERANGE;
2347 memmove( wcDest, wcSrc, size*sizeof(WCHAR) );
2349 return 0;
2352 /***********************************************************************
2353 * wcscpy (MSVCRT.@)
2355 wchar_t* __cdecl wcscpy( wchar_t *dst, const wchar_t *src )
2357 WCHAR *p = dst;
2358 while ((*p++ = *src++));
2359 return dst;
2362 /******************************************************************
2363 * wcsncpy (MSVCRT.@)
2365 wchar_t* __cdecl wcsncpy( wchar_t* s1, const wchar_t *s2, size_t n )
2367 size_t i;
2369 for(i=0; i<n; i++)
2370 if(!(s1[i] = s2[i])) break;
2371 for(; i<n; i++)
2372 s1[i] = 0;
2373 return s1;
2376 /******************************************************************
2377 * wcsncpy_s (MSVCRT.@)
2379 INT CDECL wcsncpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc,
2380 size_t count )
2382 WCHAR *p = wcDest;
2383 BOOL truncate = (count == _TRUNCATE);
2385 if(!wcDest && !numElement && !count)
2386 return 0;
2388 if (!wcDest || !numElement)
2389 return EINVAL;
2391 if (!wcSrc)
2393 *wcDest = 0;
2394 return count ? EINVAL : 0;
2397 while (numElement && count && *wcSrc)
2399 *p++ = *wcSrc++;
2400 numElement--;
2401 count--;
2403 if (!numElement && truncate)
2405 *(p-1) = 0;
2406 return STRUNCATE;
2408 else if (!numElement)
2410 *wcDest = 0;
2411 return ERANGE;
2414 *p = 0;
2415 return 0;
2418 /******************************************************************
2419 * wcscat_s (MSVCRT.@)
2422 INT CDECL wcscat_s(wchar_t* dst, size_t elem, const wchar_t* src)
2424 wchar_t* ptr = dst;
2426 if (!dst || elem == 0) return EINVAL;
2427 if (!src)
2429 dst[0] = '\0';
2430 return EINVAL;
2433 /* seek to end of dst string (or elem if no end of string is found */
2434 while (ptr < dst + elem && *ptr != '\0') ptr++;
2435 while (ptr < dst + elem)
2437 if ((*ptr++ = *src++) == '\0') return 0;
2439 /* not enough space */
2440 dst[0] = '\0';
2441 return ERANGE;
2444 /***********************************************************************
2445 * wcscat (MSVCRT.@)
2447 wchar_t* __cdecl wcscat( wchar_t *dst, const wchar_t *src )
2449 wcscpy( dst + wcslen(dst), src );
2450 return dst;
2453 /*********************************************************************
2454 * wcsncat_s (MSVCRT.@)
2457 INT CDECL wcsncat_s(wchar_t *dst, size_t elem,
2458 const wchar_t *src, size_t count)
2460 size_t srclen;
2461 wchar_t dststart;
2462 INT ret = 0;
2464 if (!MSVCRT_CHECK_PMT(dst != NULL)) return EINVAL;
2465 if (!MSVCRT_CHECK_PMT(elem > 0)) return EINVAL;
2466 if (!MSVCRT_CHECK_PMT(src != NULL || count == 0)) return EINVAL;
2468 if (count == 0)
2469 return 0;
2471 for (dststart = 0; dststart < elem; dststart++)
2473 if (dst[dststart] == '\0')
2474 break;
2476 if (dststart == elem)
2478 MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n", EINVAL);
2479 return EINVAL;
2482 if (count == _TRUNCATE)
2484 srclen = wcslen(src);
2485 if (srclen >= (elem - dststart))
2487 srclen = elem - dststart - 1;
2488 ret = STRUNCATE;
2491 else
2492 srclen = min(wcslen(src), count);
2493 if (srclen < (elem - dststart))
2495 memcpy(&dst[dststart], src, srclen*sizeof(wchar_t));
2496 dst[dststart+srclen] = '\0';
2497 return ret;
2499 MSVCRT_INVALID_PMT("dst[elem] is too small", ERANGE);
2500 dst[0] = '\0';
2501 return ERANGE;
2504 /*********************************************************************
2505 * wcsncat (NTDLL.@)
2507 wchar_t * __cdecl wcsncat(wchar_t *s1, const wchar_t *s2, size_t n)
2509 wchar_t *ret = s1;
2510 while (*s1) s1++;
2511 while (n-- > 0) if (!(*s1++ = *s2++)) return ret;
2512 *s1 = 0;
2513 return ret;
2516 /*********************************************************************
2517 * wctoint (INTERNAL)
2519 static int wctoint(WCHAR c, int base)
2521 int v = -1;
2522 if ('0' <= c && c <= '9')
2523 v = c - '0';
2524 else if ('A' <= c && c <= 'Z')
2525 v = c - 'A' + 10;
2526 else if ('a' <= c && c <= 'z')
2527 v = c - 'a' + 10;
2528 else {
2529 /* NOTE: wine_fold_string(MAP_FOLDDIGITS) supports too many things. */
2530 /* Unicode points that contain digits 0-9; keep this sorted! */
2531 static const WCHAR zeros[] = {
2532 0x660, 0x6f0, 0x966, 0x9e6, 0xa66, 0xae6, 0xb66, 0xc66, 0xce6,
2533 0xd66, 0xe50, 0xed0, 0xf20, 0x1040, 0x17e0, 0x1810, 0xff10
2535 int i;
2536 for (i = 0; i < ARRAY_SIZE(zeros) && c >= zeros[i]; ++i) {
2537 if (zeros[i] <= c && c <= zeros[i] + 9) {
2538 v = c - zeros[i];
2539 break;
2543 return v < base ? v : -1;
2546 /*********************************************************************
2547 * _wcstoi64_l (MSVCRT.@)
2549 __int64 CDECL _wcstoi64_l(const wchar_t *nptr,
2550 wchar_t **endptr, int base, _locale_t locale)
2552 BOOL negative = FALSE, empty = TRUE;
2553 __int64 ret = 0;
2555 TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
2557 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
2558 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
2559 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
2561 if(endptr)
2562 *endptr = (wchar_t*)nptr;
2564 while(_iswspace_l(*nptr, locale)) nptr++;
2566 if(*nptr == '-') {
2567 negative = TRUE;
2568 nptr++;
2569 } else if(*nptr == '+')
2570 nptr++;
2572 if((base==0 || base==16) && wctoint(*nptr, 1)==0 && (nptr[1]=='x' || nptr[1]=='X')) {
2573 base = 16;
2574 nptr += 2;
2577 if(base == 0) {
2578 if(wctoint(*nptr, 1)==0)
2579 base = 8;
2580 else
2581 base = 10;
2584 while(*nptr) {
2585 int v = wctoint(*nptr, base);
2586 if(v<0)
2587 break;
2589 if(negative)
2590 v = -v;
2592 nptr++;
2593 empty = FALSE;
2595 if(!negative && (ret>I64_MAX/base || ret*base>I64_MAX-v)) {
2596 ret = I64_MAX;
2597 *_errno() = ERANGE;
2598 } else if(negative && (ret<I64_MIN/base || ret*base<I64_MIN-v)) {
2599 ret = I64_MIN;
2600 *_errno() = ERANGE;
2601 } else
2602 ret = ret*base + v;
2605 if(endptr && !empty)
2606 *endptr = (wchar_t*)nptr;
2608 return ret;
2611 /*********************************************************************
2612 * _wcstoi64 (MSVCRT.@)
2614 __int64 CDECL _wcstoi64(const wchar_t *nptr,
2615 wchar_t **endptr, int base)
2617 return _wcstoi64_l(nptr, endptr, base, NULL);
2620 /*********************************************************************
2621 * _wcstol_l (MSVCRT.@)
2623 __msvcrt_long CDECL _wcstol_l(const wchar_t *s,
2624 wchar_t **end, int base, _locale_t locale)
2626 __int64 ret = _wcstoi64_l(s, end, base, locale);
2628 if(ret > LONG_MAX) {
2629 ret = LONG_MAX;
2630 *_errno() = ERANGE;
2631 }else if(ret < LONG_MIN) {
2632 ret = LONG_MIN;
2633 *_errno() = ERANGE;
2635 return ret;
2638 /*********************************************************************
2639 * wcstol (MSVCRT.@)
2641 __msvcrt_long CDECL wcstol(const wchar_t *s,
2642 wchar_t **end, int base)
2644 return _wcstol_l(s, end, base, NULL);
2647 /*********************************************************************
2648 * _wtoi_l (MSVCRT.@)
2650 int __cdecl _wtoi_l(const wchar_t *str, _locale_t locale)
2652 __int64 ret = _wcstoi64_l(str, NULL, 10, locale);
2654 if(ret > INT_MAX) {
2655 ret = INT_MAX;
2656 *_errno() = ERANGE;
2657 } else if(ret < INT_MIN) {
2658 ret = INT_MIN;
2659 *_errno() = ERANGE;
2661 return ret;
2664 /*********************************************************************
2665 * _wtoi (MSVCRT.@)
2667 int __cdecl _wtoi(const wchar_t *str)
2669 return _wtoi_l(str, NULL);
2672 /*********************************************************************
2673 * _wtol_l (MSVCRT.@)
2675 __msvcrt_long __cdecl _wtol_l(const wchar_t *str, _locale_t locale)
2677 __int64 ret = _wcstoi64_l(str, NULL, 10, locale);
2679 if(ret > LONG_MAX) {
2680 ret = LONG_MAX;
2681 *_errno() = ERANGE;
2682 } else if(ret < LONG_MIN) {
2683 ret = LONG_MIN;
2684 *_errno() = ERANGE;
2686 return ret;
2689 /*********************************************************************
2690 * _wtol (MSVCRT.@)
2692 __msvcrt_long __cdecl _wtol(const wchar_t *str)
2694 return _wtol_l(str, NULL);
2697 #if _MSVCR_VER>=120
2699 /*********************************************************************
2700 * _wtoll_l (MSVCR120.@)
2702 __int64 __cdecl _wtoll_l(const wchar_t *str, _locale_t locale)
2704 return _wcstoi64_l(str, NULL, 10, locale);
2707 /*********************************************************************
2708 * _wtoll (MSVCR120.@)
2710 __int64 __cdecl _wtoll(const wchar_t *str)
2712 return _wtoll_l(str, NULL);
2715 #endif /* _MSVCR_VER>=120 */
2717 /*********************************************************************
2718 * _wcstoui64_l (MSVCRT.@)
2720 unsigned __int64 CDECL _wcstoui64_l(const wchar_t *nptr,
2721 wchar_t **endptr, int base, _locale_t locale)
2723 BOOL negative = FALSE, empty = TRUE;
2724 unsigned __int64 ret = 0;
2726 TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
2728 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
2729 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
2730 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
2732 if(endptr)
2733 *endptr = (wchar_t*)nptr;
2735 while(_iswspace_l(*nptr, locale)) nptr++;
2737 if(*nptr == '-') {
2738 negative = TRUE;
2739 nptr++;
2740 } else if(*nptr == '+')
2741 nptr++;
2743 if((base==0 || base==16) && wctoint(*nptr, 1)==0 && (nptr[1]=='x' || nptr[1]=='X')) {
2744 base = 16;
2745 nptr += 2;
2748 if(base == 0) {
2749 if(wctoint(*nptr, 1)==0)
2750 base = 8;
2751 else
2752 base = 10;
2755 while(*nptr) {
2756 int v = wctoint(*nptr, base);
2757 if(v<0)
2758 break;
2760 nptr++;
2761 empty = FALSE;
2763 if(ret>UI64_MAX/base || ret*base>UI64_MAX-v) {
2764 ret = UI64_MAX;
2765 *_errno() = ERANGE;
2766 } else
2767 ret = ret*base + v;
2770 if(endptr && !empty)
2771 *endptr = (wchar_t*)nptr;
2773 return negative ? -ret : ret;
2776 /*********************************************************************
2777 * _wcstoui64 (MSVCRT.@)
2779 unsigned __int64 CDECL _wcstoui64(const wchar_t *nptr,
2780 wchar_t **endptr, int base)
2782 return _wcstoui64_l(nptr, endptr, base, NULL);
2785 /*********************************************************************
2786 * _wcstoul_l (MSVCRT.@)
2788 __msvcrt_ulong __cdecl _wcstoul_l(const wchar_t *s,
2789 wchar_t **end, int base, _locale_t locale)
2791 __int64 ret = _wcstoi64_l(s, end, base, locale);
2793 if(ret > ULONG_MAX) {
2794 ret = ULONG_MAX;
2795 *_errno() = ERANGE;
2796 }else if(ret < -(__int64)ULONG_MAX) {
2797 ret = 1;
2798 *_errno() = ERANGE;
2800 return ret;
2803 /*********************************************************************
2804 * wcstoul (MSVCRT.@)
2806 __msvcrt_ulong __cdecl wcstoul(const wchar_t *s, wchar_t **end, int base)
2808 return _wcstoul_l(s, end, base, NULL);
2811 /******************************************************************
2812 * wcsnlen (MSVCRT.@)
2814 size_t CDECL wcsnlen(const wchar_t *s, size_t maxlen)
2816 size_t i;
2818 for (i = 0; i < maxlen; i++)
2819 if (!s[i]) break;
2820 return i;
2823 /*********************************************************************
2824 * _towupper_l (MSVCRT.@)
2826 wint_t CDECL _towupper_l(wint_t c, _locale_t locale)
2828 pthreadlocinfo locinfo;
2829 wchar_t ret;
2831 if(!locale)
2832 locinfo = get_locinfo();
2833 else
2834 locinfo = locale->locinfo;
2836 if(!locinfo->lc_handle[LC_CTYPE]) {
2837 if(c >= 'a' && c <= 'z')
2838 return c + 'A' - 'a';
2839 return c;
2842 if(!LCMapStringW(locinfo->lc_handle[LC_CTYPE], LCMAP_UPPERCASE, &c, 1, &ret, 1))
2843 return c;
2844 return ret;
2847 /*********************************************************************
2848 * towupper (MSVCRT.@)
2850 wint_t CDECL towupper(wint_t c)
2852 return _towupper_l(c, NULL);
2855 /*********************************************************************
2856 * wcschr (MSVCRT.@)
2858 wchar_t* CDECL wcschr(const wchar_t *str, wchar_t ch)
2860 do { if (*str == ch) return (WCHAR *)(ULONG_PTR)str; } while (*str++);
2861 return NULL;
2864 /*********************************************************************
2865 * wcsrchr (MSVCRT.@)
2867 wchar_t* CDECL wcsrchr(const wchar_t *str, wchar_t ch)
2869 WCHAR *ret = NULL;
2870 do { if (*str == ch) ret = (WCHAR *)(ULONG_PTR)str; } while (*str++);
2871 return ret;
2874 /***********************************************************************
2875 * wcslen (MSVCRT.@)
2877 size_t CDECL wcslen(const wchar_t *str)
2879 const wchar_t *s = str;
2880 while (*s) s++;
2881 return s - str;
2884 /*********************************************************************
2885 * wcsstr (MSVCRT.@)
2887 wchar_t* CDECL wcsstr(const wchar_t *str, const wchar_t *sub)
2889 while(*str)
2891 const wchar_t *p1 = str, *p2 = sub;
2892 while(*p1 && *p2 && *p1 == *p2)
2894 p1++;
2895 p2++;
2897 if(!*p2)
2898 return (wchar_t*)str;
2899 str++;
2901 return NULL;
2904 /*********************************************************************
2905 * _wtoi64_l (MSVCRT.@)
2907 __int64 CDECL _wtoi64_l(const wchar_t *str, _locale_t locale)
2909 ULONGLONG RunningTotal = 0;
2910 BOOL bMinus = FALSE;
2912 while (_iswspace_l(*str, locale)) {
2913 str++;
2914 } /* while */
2916 if (*str == '+') {
2917 str++;
2918 } else if (*str == '-') {
2919 bMinus = TRUE;
2920 str++;
2921 } /* if */
2923 while (*str >= '0' && *str <= '9') {
2924 RunningTotal = RunningTotal * 10 + *str - '0';
2925 str++;
2926 } /* while */
2928 return bMinus ? -RunningTotal : RunningTotal;
2931 /*********************************************************************
2932 * _wtoi64 (MSVCRT.@)
2934 __int64 CDECL _wtoi64(const wchar_t *str)
2936 return _wtoi64_l(str, NULL);
2939 /*********************************************************************
2940 * _wcsxfrm_l (MSVCRT.@)
2942 size_t CDECL _wcsxfrm_l(wchar_t *dest, const wchar_t *src,
2943 size_t len, _locale_t locale)
2945 pthreadlocinfo locinfo;
2946 int i, ret;
2948 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
2949 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
2951 if(len > INT_MAX) {
2952 FIXME("len > INT_MAX not supported\n");
2953 len = INT_MAX;
2956 if(!locale)
2957 locinfo = get_locinfo();
2958 else
2959 locinfo = locale->locinfo;
2961 if(!locinfo->lc_handle[LC_COLLATE]) {
2962 wcsncpy(dest, src, len);
2963 return wcslen(src);
2966 ret = LCMapStringW(locinfo->lc_handle[LC_COLLATE],
2967 LCMAP_SORTKEY, src, -1, NULL, 0);
2968 if(!ret) {
2969 if(len) dest[0] = 0;
2970 *_errno() = EILSEQ;
2971 return INT_MAX;
2973 if(!len) return ret-1;
2975 if(ret > len) {
2976 dest[0] = 0;
2977 *_errno() = ERANGE;
2978 return ret-1;
2981 ret = LCMapStringW(locinfo->lc_handle[LC_COLLATE],
2982 LCMAP_SORTKEY, src, -1, dest, len) - 1;
2983 for(i=ret; i>=0; i--)
2984 dest[i] = ((unsigned char*)dest)[i];
2985 return ret;
2988 /*********************************************************************
2989 * wcsxfrm (MSVCRT.@)
2991 size_t CDECL wcsxfrm(wchar_t *dest, const wchar_t *src, size_t len)
2993 return _wcsxfrm_l(dest, src, len, NULL);