twinapi.appcore: Implement Windows.System.Profile.AnalyticsInfo_get_DeviceFamily.
[wine.git] / dlls / msvcrt / wcs.c
blob60a15dfc29cac3682cb9495aa29a7d589991d2cb
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 size_t 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 * _scprintf_l (MSVCRT.@)
1322 int WINAPIV _scprintf_l(const char *format, _locale_t locale, ...)
1324 int retval;
1325 va_list valist;
1326 va_start(valist, locale);
1327 retval = _vscprintf_l(format, locale, valist);
1328 va_end(valist);
1329 return retval;
1332 /*********************************************************************
1333 * _scprintf_p (MSVCRT.@)
1335 int WINAPIV _scprintf_p(const char *format, ...)
1337 int retval;
1338 va_list valist;
1339 va_start(valist, format);
1340 retval = _vscprintf_p_l(format, NULL, valist);
1341 va_end(valist);
1342 return retval;
1345 /*********************************************************************
1346 * _scprintf_p_l (MSVCRT.@)
1348 int WINAPIV _scprintf_p_l(const char *format, _locale_t locale, ...)
1350 int retval;
1351 va_list valist;
1352 va_start(valist, locale);
1353 retval = _vscprintf_p_l(format, locale, valist);
1354 va_end(valist);
1355 return retval;
1358 /*********************************************************************
1359 * _vsnwprintf (MSVCRT.@)
1361 int CDECL _vsnwprintf(wchar_t *str, size_t len,
1362 const wchar_t *format, va_list valist)
1364 struct _str_ctx_w ctx = {len, str};
1365 int ret;
1367 ret = pf_printf_w(puts_clbk_str_w, &ctx, format, NULL, 0,
1368 arg_clbk_valist, NULL, &valist);
1369 puts_clbk_str_w(&ctx, 1, L"");
1370 return ret;
1373 /*********************************************************************
1374 * _vsnwprintf_l (MSVCRT.@)
1376 int CDECL _vsnwprintf_l(wchar_t *str, size_t len, const wchar_t *format,
1377 _locale_t locale, va_list valist)
1379 struct _str_ctx_w ctx = {len, str};
1380 int ret;
1382 ret = pf_printf_w(puts_clbk_str_w, &ctx, format, locale, 0,
1383 arg_clbk_valist, NULL, &valist);
1384 puts_clbk_str_w(&ctx, 1, L"");
1385 return ret;
1388 /*********************************************************************
1389 * _vswprintf_c_l (MSVCRT.@)
1391 int CDECL _vswprintf_c_l(wchar_t *str, size_t len, const wchar_t *format,
1392 _locale_t locale, va_list valist)
1394 return vsnwprintf_s_l_opt(str, len, len, format, 0, locale, valist);
1397 /*********************************************************************
1398 * _vswprintf_c (MSVCRT.@)
1400 int CDECL _vswprintf_c(wchar_t *str, size_t len,
1401 const wchar_t *format, va_list valist)
1403 return _vswprintf_c_l(str, len, format, NULL, valist);
1406 static int vswprintf_p_l_opt(wchar_t *buffer, size_t length,
1407 const wchar_t *format, DWORD options, _locale_t locale, va_list args)
1409 printf_arg args_ctx[_ARGMAX+1];
1410 struct _str_ctx_w puts_ctx = {length, buffer};
1411 int ret;
1413 memset(args_ctx, 0, sizeof(args_ctx));
1415 ret = create_positional_ctx_w(args_ctx, format, args);
1416 if(ret < 0) {
1417 _invalid_parameter(NULL, NULL, NULL, 0, 0);
1418 *_errno() = EINVAL;
1419 return ret;
1420 } else if(ret == 0)
1421 ret = pf_printf_w(puts_clbk_str_w, &puts_ctx, format, locale, MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
1422 arg_clbk_valist, NULL, &args);
1423 else
1424 ret = pf_printf_w(puts_clbk_str_w, &puts_ctx, format, locale,
1425 MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
1426 arg_clbk_positional, args_ctx, NULL);
1428 puts_clbk_str_w(&puts_ctx, 1, L"");
1429 return ret;
1432 /*********************************************************************
1433 * _vswprintf_p_l (MSVCRT.@)
1435 int CDECL _vswprintf_p_l(wchar_t *buffer, size_t length,
1436 const wchar_t *format, _locale_t locale, va_list args)
1438 return vswprintf_p_l_opt(buffer, length, format, 0, locale, args);
1441 #if _MSVCR_VER>=80
1442 /*********************************************************************
1443 * _vswprintf_p (MSVCR80.@)
1445 int CDECL _vswprintf_p(wchar_t *buffer, size_t length,
1446 const wchar_t *format, va_list args)
1448 return vswprintf_p_l_opt(buffer, length, format, 0, NULL, args);
1450 #endif
1452 #if _MSVCR_VER>=140
1453 /*********************************************************************
1454 * __stdio_common_vswprintf_p (UCRTBASE.@)
1456 int CDECL __stdio_common_vswprintf_p( unsigned __int64 options,
1457 wchar_t *str, size_t count, const wchar_t *format,
1458 _locale_t locale, va_list valist )
1460 if (options & ~UCRTBASE_PRINTF_MASK)
1461 FIXME("options %#I64x not handled\n", options);
1462 return vswprintf_p_l_opt(str, count, format, options & UCRTBASE_PRINTF_MASK, locale, valist);
1464 #endif
1466 /*********************************************************************
1467 * _vsnwprintf_s_l (MSVCRT.@)
1469 int CDECL _vsnwprintf_s_l( wchar_t *str, size_t sizeOfBuffer,
1470 size_t count, const wchar_t *format,
1471 _locale_t locale, va_list valist)
1473 return vsnwprintf_s_l_opt(str, sizeOfBuffer, count, format, 0, locale, valist);
1476 /*********************************************************************
1477 * _vsnwprintf_s (MSVCRT.@)
1479 int CDECL _vsnwprintf_s(wchar_t *str, size_t sizeOfBuffer,
1480 size_t count, const wchar_t *format, va_list valist)
1482 return _vsnwprintf_s_l(str, sizeOfBuffer, count,
1483 format, NULL, valist);
1486 /*********************************************************************
1487 * _snwprintf (MSVCRT.@)
1489 int WINAPIV _snwprintf( wchar_t *str, size_t len, const wchar_t *format, ...)
1491 int retval;
1492 va_list valist;
1493 va_start(valist, format);
1494 retval = _vsnwprintf(str, len, format, valist);
1495 va_end(valist);
1496 return retval;
1499 /*********************************************************************
1500 * _snwprintf_l (MSVCRT.@)
1502 int WINAPIV _snwprintf_l( wchar_t *str, size_t len, const wchar_t *format,
1503 _locale_t locale, ...)
1505 int retval;
1506 va_list valist;
1507 va_start(valist, locale);
1508 retval = _vsnwprintf_l(str, len, format, locale, valist);
1509 va_end(valist);
1510 return retval;
1513 /*********************************************************************
1514 * _snwprintf_s (MSVCRT.@)
1516 int WINAPIV _snwprintf_s( wchar_t *str, size_t len, size_t count,
1517 const wchar_t *format, ...)
1519 int retval;
1520 va_list valist;
1521 va_start(valist, format);
1522 retval = _vsnwprintf_s_l(str, len, count, format, NULL, valist);
1523 va_end(valist);
1524 return retval;
1527 /*********************************************************************
1528 * _snwprintf_s_l (MSVCRT.@)
1530 int WINAPIV _snwprintf_s_l( wchar_t *str, size_t len, size_t count,
1531 const wchar_t *format, _locale_t locale, ... )
1533 int retval;
1534 va_list valist;
1535 va_start(valist, locale);
1536 retval = _vsnwprintf_s_l(str, len, count, format, locale, valist);
1537 va_end(valist);
1538 return retval;
1541 #if _MSVCR_VER>=140
1543 static int puts_clbk_str_c99_w(void *ctx, int len, const wchar_t *str)
1545 struct _str_ctx_w *out = ctx;
1547 if(!out->buf)
1548 return len;
1550 if(out->len < len) {
1551 memcpy(out->buf, str, out->len*sizeof(wchar_t));
1552 out->buf += out->len;
1553 out->len = 0;
1554 return len;
1557 memcpy(out->buf, str, len*sizeof(wchar_t));
1558 out->buf += len;
1559 out->len -= len;
1560 return len;
1563 /*********************************************************************
1564 * __stdio_common_vswprintf (UCRTBASE.@)
1566 int CDECL __stdio_common_vswprintf( unsigned __int64 options,
1567 wchar_t *str, size_t len, const wchar_t *format,
1568 _locale_t locale, va_list valist )
1570 struct _str_ctx_w ctx = {len, str};
1571 int ret;
1573 if (options & ~UCRTBASE_PRINTF_MASK)
1574 FIXME("options %#I64x not handled\n", options);
1575 ret = pf_printf_w(puts_clbk_str_c99_w,
1576 &ctx, format, locale, options & UCRTBASE_PRINTF_MASK, arg_clbk_valist, NULL, &valist);
1577 puts_clbk_str_w(&ctx, 1, L"");
1579 if(!str)
1580 return ret;
1581 if(options & _CRT_INTERNAL_PRINTF_LEGACY_VSPRINTF_NULL_TERMINATION)
1582 return ret>len ? -1 : ret;
1583 if(ret>=len) {
1584 if(len) str[len-1] = 0;
1585 if(options & _CRT_INTERNAL_PRINTF_STANDARD_SNPRINTF_BEHAVIOR)
1586 return ret;
1587 return len > 0 ? -2 : -1;
1589 return ret;
1592 #endif /* _MSVCR_VER>=140 */
1594 /*********************************************************************
1595 * sprintf (MSVCRT.@)
1597 int WINAPIV sprintf( char *str, const char *format, ... )
1599 va_list ap;
1600 int r;
1602 va_start( ap, format );
1603 r = vsnprintf( str, INT_MAX, format, ap );
1604 va_end( ap );
1605 return r;
1608 /*********************************************************************
1609 * sprintf_s (MSVCRT.@)
1611 int WINAPIV sprintf_s( char *str, size_t num, const char *format, ... )
1613 va_list ap;
1614 int r;
1616 va_start( ap, format );
1617 r = vsnprintf( str, num, format, ap );
1618 va_end( ap );
1619 return r;
1622 /*********************************************************************
1623 * _scwprintf_l (MSVCRT.@)
1625 int WINAPIV _scwprintf_l( const wchar_t *format, _locale_t locale, ... )
1627 va_list ap;
1628 int r;
1630 va_start( ap, locale );
1631 r = _vsnwprintf_l( NULL, INT_MAX, format, locale, ap );
1632 va_end( ap );
1633 return r;
1636 /*********************************************************************
1637 * _scwprintf_p_l (MSVCRT.@)
1639 int WINAPIV _scwprintf_p_l( const wchar_t *format, _locale_t locale, ... )
1641 va_list ap;
1642 int r;
1644 va_start( ap, locale );
1645 r = vswprintf_p_l_opt( NULL, INT_MAX, format, 0, locale, ap );
1646 va_end( ap );
1647 return r;
1650 #if _MSVCR_VER>=80
1651 /*********************************************************************
1652 * _scwprintf_p (MSVCRT.@)
1654 int WINAPIV _scwprintf_p( const wchar_t *format, ... )
1656 va_list ap;
1657 int r;
1659 va_start( ap, format );
1660 r = vswprintf_p_l_opt( NULL, INT_MAX, format, 0, NULL, ap );
1661 va_end( ap );
1662 return r;
1664 #endif
1666 /*********************************************************************
1667 * _scwprintf (MSVCRT.@)
1669 int WINAPIV _scwprintf( const wchar_t *format, ... )
1671 va_list ap;
1672 int r;
1674 va_start( ap, format );
1675 r = _vsnwprintf( NULL, INT_MAX, format, ap );
1676 va_end( ap );
1677 return r;
1680 /*********************************************************************
1681 * swprintf (MSVCRT.@)
1683 int WINAPIV _swprintf( wchar_t *str, const wchar_t *format, ... )
1685 va_list ap;
1686 int r;
1688 va_start( ap, format );
1689 r = _vsnwprintf( str, INT_MAX, format, ap );
1690 va_end( ap );
1691 return r;
1694 /*********************************************************************
1695 * swprintf_s (MSVCRT.@)
1697 int WINAPIV swprintf_s(wchar_t *str, size_t numberOfElements,
1698 const wchar_t *format, ... )
1700 va_list ap;
1701 int r;
1703 va_start(ap, format);
1704 r = _vsnwprintf_s(str, numberOfElements, INT_MAX, format, ap);
1705 va_end(ap);
1707 return r;
1710 /*********************************************************************
1711 * _swprintf_s_l (MSVCRT.@)
1713 int WINAPIV _swprintf_s_l(wchar_t *str, size_t numberOfElements,
1714 const wchar_t *format, _locale_t locale, ... )
1716 va_list ap;
1717 int r;
1719 va_start(ap, locale);
1720 r = _vsnwprintf_s_l(str, numberOfElements, INT_MAX, format, locale, ap);
1721 va_end(ap);
1723 return r;
1726 /*********************************************************************
1727 * _swprintf_c_l (MSVCRT.@)
1729 int WINAPIV _swprintf_c_l(wchar_t *str, size_t len,
1730 const wchar_t *format, _locale_t locale, ... )
1732 va_list ap;
1733 int r;
1735 va_start(ap, locale);
1736 r = _vswprintf_c_l(str, len, format, locale, ap);
1737 va_end(ap);
1739 return r;
1742 /*********************************************************************
1743 * _swprintf_c (MSVCRT.@)
1745 int WINAPIV _swprintf_c(wchar_t *str, size_t len,
1746 const wchar_t *format, ... )
1748 va_list ap;
1749 int r;
1751 va_start(ap, format);
1752 r = _vswprintf_c(str, len, format, ap);
1753 va_end(ap);
1755 return r;
1758 /*********************************************************************
1759 * _vswprintf (MSVCRT.@)
1761 int CDECL _vswprintf( wchar_t* str, const wchar_t* format, va_list args )
1763 return _vsnwprintf( str, INT_MAX, format, args );
1766 /*********************************************************************
1767 * _vswprintf (MSVCRT.@)
1769 int CDECL _vswprintf_l( wchar_t* str, const wchar_t* format,
1770 _locale_t locale, va_list args )
1772 return _vsnwprintf_l( str, INT_MAX, format, locale, args );
1775 /*********************************************************************
1776 * _vscwprintf (MSVCRT.@)
1778 int CDECL _vscwprintf( const wchar_t *format, va_list args )
1780 return _vsnwprintf( NULL, INT_MAX, format, args );
1783 /*********************************************************************
1784 * _vscwprintf_l (MSVCRT.@)
1786 int CDECL _vscwprintf_l( const wchar_t *format, _locale_t locale, va_list args )
1788 return _vsnwprintf_l( NULL, INT_MAX, format, locale, args );
1791 /*********************************************************************
1792 * _vscwprintf_p_l (MSVCRT.@)
1794 int CDECL _vscwprintf_p_l( const wchar_t *format, _locale_t locale, va_list args )
1796 return vswprintf_p_l_opt( NULL, INT_MAX, format, 0, locale, args );
1799 #if _MSVCR_VER>=80
1800 /*********************************************************************
1801 * _vscwprintf_p (MSVCR80.@)
1803 int CDECL _vscwprintf_p(const wchar_t *format, va_list args)
1805 return vswprintf_p_l_opt(NULL, INT_MAX, format, 0, NULL, args);
1807 #endif
1809 /*********************************************************************
1810 * vswprintf_s (MSVCRT.@)
1812 int CDECL vswprintf_s(wchar_t* str, size_t numberOfElements,
1813 const wchar_t* format, va_list args)
1815 return _vsnwprintf_s(str, numberOfElements, INT_MAX, format, args );
1818 /*********************************************************************
1819 * _vswprintf_s_l (MSVCRT.@)
1821 int CDECL _vswprintf_s_l(wchar_t* str, size_t numberOfElements,
1822 const wchar_t* format, _locale_t locale, va_list args)
1824 return _vsnwprintf_s_l(str, numberOfElements, INT_MAX,
1825 format, locale, args );
1828 static int vsprintf_p_l_opt(char *buffer, size_t length, const char *format,
1829 DWORD options, _locale_t locale, va_list args)
1831 static const char nullbyte = '\0';
1832 printf_arg args_ctx[_ARGMAX+1];
1833 struct _str_ctx_a puts_ctx = {length, buffer};
1834 int ret;
1836 memset(args_ctx, 0, sizeof(args_ctx));
1838 ret = create_positional_ctx_a(args_ctx, format, args);
1839 if(ret < 0) {
1840 _invalid_parameter(NULL, NULL, NULL, 0, 0);
1841 *_errno() = EINVAL;
1842 return ret;
1843 } else if(ret == 0)
1844 ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale,
1845 MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options, arg_clbk_valist, NULL, &args);
1846 else
1847 ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale,
1848 MSVCRT_PRINTF_POSITIONAL_PARAMS | MSVCRT_PRINTF_INVOKE_INVALID_PARAM_HANDLER | options,
1849 arg_clbk_positional, args_ctx, NULL);
1851 puts_clbk_str_a(&puts_ctx, 1, &nullbyte);
1852 return ret;
1855 /*********************************************************************
1856 * _vsprintf_p_l (MSVCRT.@)
1858 int CDECL _vsprintf_p_l(char *buffer, size_t length, const char *format,
1859 _locale_t locale, va_list args)
1861 return vsprintf_p_l_opt(buffer, length, format, 0, locale, args);
1864 /*********************************************************************
1865 * _vsprintf_p (MSVCRT.@)
1867 int CDECL _vsprintf_p(char *buffer, size_t length,
1868 const char *format, va_list args)
1870 return _vsprintf_p_l(buffer, length, format, NULL, args);
1873 #if _MSVCR_VER>=140
1874 /*********************************************************************
1875 * __stdio_common_vsprintf_p (UCRTBASE.@)
1877 int CDECL __stdio_common_vsprintf_p(unsigned __int64 options, char *buffer, size_t length,
1878 const char *format, _locale_t locale, va_list args)
1880 if (options & ~UCRTBASE_PRINTF_MASK)
1881 FIXME("options %#I64x not handled\n", options);
1882 return vsprintf_p_l_opt(buffer, length, format, options & UCRTBASE_PRINTF_MASK, locale, args);
1884 #endif
1886 /*********************************************************************
1887 * _sprintf_p_l (MSVCRT.@)
1889 int WINAPIV _sprintf_p_l(char *buffer, size_t length,
1890 const char *format, _locale_t locale, ...)
1892 va_list valist;
1893 int r;
1895 va_start(valist, locale);
1896 r = _vsprintf_p_l(buffer, length, format, locale, valist);
1897 va_end(valist);
1899 return r;
1902 /*********************************************************************
1903 * __swprintf_l (MSVCRT.@)
1905 int WINAPIV __swprintf_l( wchar_t *str, const wchar_t *format,
1906 _locale_t locale, ...)
1908 int retval;
1909 va_list valist;
1910 va_start(valist, locale);
1911 retval = _vswprintf_l(str, format, locale, valist);
1912 va_end(valist);
1913 return retval;
1916 #if _MSVCR_VER>=80
1917 /*********************************************************************
1918 * _sprintf_p (MSVCR80.@)
1920 int WINAPIV _sprintf_p(char *buffer, size_t length, const char *format, ...)
1922 va_list valist;
1923 int r;
1925 va_start(valist, format);
1926 r = _vsprintf_p_l(buffer, length, format, NULL, valist);
1927 va_end(valist);
1929 return r;
1931 #endif
1933 /*********************************************************************
1934 * _swprintf_p (MSVCRT.@)
1936 int WINAPIV _swprintf_p(wchar_t *buffer, size_t length,
1937 const wchar_t *format, ...)
1939 va_list valist;
1940 int r;
1942 va_start(valist, format);
1943 r = vswprintf_p_l_opt(buffer, length, format, 0, NULL, valist);
1944 va_end(valist);
1946 return r;
1949 /*********************************************************************
1950 * _swprintf_p_l (MSVCRT.@)
1952 int WINAPIV _swprintf_p_l(wchar_t *buffer, size_t length,
1953 const wchar_t *format, _locale_t locale, ...)
1955 va_list valist;
1956 int r;
1958 va_start(valist, locale);
1959 r = vswprintf_p_l_opt(buffer, length, format, 0, locale, valist);
1960 va_end(valist);
1962 return r;
1965 /*********************************************************************
1966 * wcscmp (MSVCRT.@)
1968 int CDECL wcscmp(const wchar_t *str1, const wchar_t *str2)
1970 while (*str1 && (*str1 == *str2))
1972 str1++;
1973 str2++;
1976 if (*str1 < *str2)
1977 return -1;
1978 if (*str1 > *str2)
1979 return 1;
1980 return 0;
1983 /*********************************************************************
1984 * _wcscoll_l (MSVCRT.@)
1986 int CDECL _wcscoll_l(const wchar_t* str1, const wchar_t* str2, _locale_t locale)
1988 pthreadlocinfo locinfo;
1990 if(!locale)
1991 locinfo = get_locinfo();
1992 else
1993 locinfo = locale->locinfo;
1995 if(!locinfo->lc_handle[LC_COLLATE])
1996 return wcscmp(str1, str2);
1997 return CompareStringW(locinfo->lc_handle[LC_COLLATE], 0, str1, -1, str2, -1)-CSTR_EQUAL;
2000 /*********************************************************************
2001 * wcscoll (MSVCRT.@)
2003 int CDECL wcscoll( const wchar_t* str1, const wchar_t* str2 )
2005 return _wcscoll_l(str1, str2, NULL);
2008 /*********************************************************************
2009 * wcspbrk (MSVCRT.@)
2011 wchar_t* CDECL wcspbrk( const wchar_t* str, const wchar_t* accept )
2013 const wchar_t* p;
2015 while (*str)
2017 for (p = accept; *p; p++) if (*p == *str) return (wchar_t*)str;
2018 str++;
2020 return NULL;
2023 /*********************************************************************
2024 * wcstok_s (MSVCRT.@)
2026 wchar_t * CDECL wcstok_s( wchar_t *str, const wchar_t *delim,
2027 wchar_t **next_token )
2029 wchar_t *ret;
2031 if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL;
2032 if (!MSVCRT_CHECK_PMT(next_token != NULL)) return NULL;
2033 if (!MSVCRT_CHECK_PMT(str != NULL || *next_token != NULL)) return NULL;
2035 if (!str) str = *next_token;
2037 while (*str && wcschr( delim, *str )) str++;
2038 if (!*str) ret = NULL;
2039 else
2041 ret = str++;
2042 while (*str && !wcschr( delim, *str )) str++;
2043 if (*str) *str++ = 0;
2045 *next_token = str;
2046 return ret;
2049 /*********************************************************************
2050 * wcstok (MSVCRT.@)
2052 #if _MSVCR_VER>=140
2053 wchar_t * CDECL wcstok( wchar_t *str, const wchar_t *delim, wchar_t **ctx )
2055 if (!ctx)
2056 ctx = &msvcrt_get_thread_data()->wcstok_next;
2057 return wcstok_s(str, delim, ctx);
2059 #else
2060 wchar_t * CDECL wcstok( wchar_t *str, const wchar_t *delim )
2062 return wcstok_s(str, delim, &msvcrt_get_thread_data()->wcstok_next);
2064 #endif
2066 /*********************************************************************
2067 * _wctomb_s_l (MSVCRT.@)
2069 int CDECL _wctomb_s_l(int *len, char *mbchar, size_t size,
2070 wchar_t wch, _locale_t locale)
2072 pthreadlocinfo locinfo;
2073 BOOL error = FALSE;
2074 BOOL *perror;
2075 int mblen;
2077 if(!mbchar && size>0) {
2078 if(len)
2079 *len = 0;
2080 return 0;
2083 if(len)
2084 *len = -1;
2086 if(!MSVCRT_CHECK_PMT(size <= INT_MAX))
2087 return EINVAL;
2089 if(!locale)
2090 locinfo = get_locinfo();
2091 else
2092 locinfo = locale->locinfo;
2094 if(!locinfo->lc_codepage) {
2095 if(wch > 0xff) {
2096 if(mbchar && size>0)
2097 memset(mbchar, 0, size);
2098 *_errno() = EILSEQ;
2099 return EILSEQ;
2102 if(!MSVCRT_CHECK_PMT_ERR(size >= 1, ERANGE))
2103 return ERANGE;
2105 *mbchar = wch;
2106 if(len)
2107 *len = 1;
2108 return 0;
2111 perror = (locinfo->lc_codepage != CP_UTF8 ? &error : NULL);
2112 mblen = WideCharToMultiByte(locinfo->lc_codepage, 0, &wch, 1, mbchar, size, NULL, perror);
2113 if(!mblen || error) {
2114 if(!mblen && GetLastError()==ERROR_INSUFFICIENT_BUFFER) {
2115 if(mbchar && size>0)
2116 memset(mbchar, 0, size);
2118 MSVCRT_INVALID_PMT("insufficient buffer size", ERANGE);
2119 return ERANGE;
2122 *_errno() = EILSEQ;
2123 return EILSEQ;
2126 if(len)
2127 *len = mblen;
2128 return 0;
2131 /*********************************************************************
2132 * wctomb_s (MSVCRT.@)
2134 int CDECL wctomb_s(int *len, char *mbchar, size_t size, wchar_t wch)
2136 return _wctomb_s_l(len, mbchar, size, wch, NULL);
2139 /*********************************************************************
2140 * _wctomb_l (MSVCRT.@)
2142 int CDECL _wctomb_l(char *dst, wchar_t ch, _locale_t locale)
2144 int len;
2146 _wctomb_s_l(&len, dst, dst ? MB_LEN_MAX : 0, ch, locale);
2147 return len;
2150 /*********************************************************************
2151 * wctomb (MSVCRT.@)
2153 INT CDECL wctomb( char *dst, wchar_t ch )
2155 return _wctomb_l(dst, ch, NULL);
2158 /*********************************************************************
2159 * wctob (MSVCRT.@)
2161 INT CDECL wctob( wint_t wchar )
2163 char out;
2164 BOOL error = FALSE;
2165 BOOL *perror;
2166 UINT codepage = get_locinfo()->lc_codepage;
2168 perror = (codepage != CP_UTF8 ? &error : NULL);
2170 if(!codepage) {
2171 if (wchar < 0xff)
2172 return (signed char)wchar;
2173 else
2174 return EOF;
2175 } else if(WideCharToMultiByte( codepage, 0, &wchar, 1, &out, 1, NULL, perror ) && !error)
2176 return (INT)out;
2177 return EOF;
2180 /*********************************************************************
2181 * wcrtomb_s (MSVCRT.@)
2183 INT CDECL wcrtomb_s(size_t *len, char *mbchar,
2184 size_t size, wchar_t wch, mbstate_t *s)
2186 int ilen, ret;
2188 if (s) *s = 0;
2189 ret = wctomb_s(&ilen, mbchar, size, wch);
2190 if (len) *len = ilen;
2191 return ret;
2194 /*********************************************************************
2195 * wcrtomb (MSVCRT.@)
2197 size_t CDECL wcrtomb( char *dst, wchar_t ch, mbstate_t *s)
2199 if(s)
2200 *s = 0;
2201 return wctomb(dst, ch);
2204 /*********************************************************************
2205 * _iswctype_l (MSVCRT.@)
2207 INT CDECL _iswctype_l( wchar_t wc, wctype_t type, _locale_t locale )
2209 WORD ct;
2211 if (wc == WEOF) return 0;
2212 if (wc < 256) return MSVCRT__pwctype[wc] & type;
2214 if (!GetStringTypeW(CT_CTYPE1, &wc, 1, &ct))
2216 ERR("GetStringTypeW failed for %x\n", wc);
2217 return 0;
2219 return ct & type;
2222 /*********************************************************************
2223 * iswctype (MSVCRT.@)
2225 INT CDECL iswctype( wchar_t wc, wctype_t type )
2227 return _iswctype_l( wc, type, NULL );
2230 /*********************************************************************
2231 * _iswalnum_l (MSVCRT.@)
2233 int CDECL _iswalnum_l( wchar_t wc, _locale_t locale )
2235 return _iswctype_l( wc, _ALPHA | _DIGIT, locale );
2238 /*********************************************************************
2239 * iswalnum (MSVCRT.@)
2241 INT CDECL iswalnum( wchar_t wc )
2243 return _iswalnum_l( wc, NULL );
2246 /*********************************************************************
2247 * iswalpha_l (MSVCRT.@)
2249 INT CDECL _iswalpha_l( wchar_t wc, _locale_t locale )
2251 return _iswctype_l( wc, _ALPHA, locale );
2254 /*********************************************************************
2255 * iswalpha (MSVCRT.@)
2257 INT CDECL iswalpha( wchar_t wc )
2259 return _iswalpha_l( wc, NULL );
2262 /*********************************************************************
2263 * _iswcntrl_l (MSVCRT.@)
2265 int CDECL _iswcntrl_l( wchar_t wc, _locale_t locale )
2267 return _iswctype_l( wc, _CONTROL, locale );
2270 /*********************************************************************
2271 * iswcntrl (MSVCRT.@)
2273 INT CDECL iswcntrl( wchar_t wc )
2275 return _iswcntrl_l( wc, NULL );
2278 /*********************************************************************
2279 * _iswdigit_l (MSVCRT.@)
2281 INT CDECL _iswdigit_l( wchar_t wc, _locale_t locale )
2283 return _iswctype_l( wc, _DIGIT, locale );
2286 /*********************************************************************
2287 * iswdigit (MSVCRT.@)
2289 INT CDECL iswdigit( wchar_t wc )
2291 return _iswdigit_l( wc, NULL );
2294 /*********************************************************************
2295 * _iswgraph_l (MSVCRT.@)
2297 int CDECL _iswgraph_l( wchar_t wc, _locale_t locale )
2299 return _iswctype_l( wc, _ALPHA | _DIGIT | _PUNCT, locale );
2302 /*********************************************************************
2303 * iswgraph (MSVCRT.@)
2305 INT CDECL iswgraph( wchar_t wc )
2307 return _iswgraph_l( wc, NULL );
2310 /*********************************************************************
2311 * _iswlower_l (MSVCRT.@)
2313 int CDECL _iswlower_l( wchar_t wc, _locale_t locale )
2315 return _iswctype_l( wc, _LOWER, locale );
2318 /*********************************************************************
2319 * iswlower (MSVCRT.@)
2321 INT CDECL iswlower( wchar_t wc )
2323 return _iswlower_l( wc, NULL );
2326 /*********************************************************************
2327 * _iswprint_l (MSVCRT.@)
2329 int CDECL _iswprint_l( wchar_t wc, _locale_t locale )
2331 return _iswctype_l( wc, _ALPHA | _BLANK | _DIGIT | _PUNCT, locale );
2334 /*********************************************************************
2335 * iswprint (MSVCRT.@)
2337 INT CDECL iswprint( wchar_t wc )
2339 return _iswprint_l( wc, NULL );
2342 /*********************************************************************
2343 * _iswpunct_l (MSVCRT.@)
2345 INT CDECL _iswpunct_l( wchar_t wc, _locale_t locale )
2347 return _iswctype_l( wc, _PUNCT, locale );
2350 /*********************************************************************
2351 * iswpunct (MSVCRT.@)
2353 INT CDECL iswpunct( wchar_t wc )
2355 return _iswpunct_l( wc, NULL );
2358 /*********************************************************************
2359 * _iswspace_l (MSVCRT.@)
2361 INT CDECL _iswspace_l( wchar_t wc, _locale_t locale )
2363 return _iswctype_l( wc, _SPACE, locale );
2366 /*********************************************************************
2367 * iswspace (MSVCRT.@)
2369 INT CDECL iswspace( wchar_t wc )
2371 return _iswspace_l( wc, NULL );
2374 /*********************************************************************
2375 * _iswupper_l (MSVCRT.@)
2377 int CDECL _iswupper_l( wchar_t wc, _locale_t locale )
2379 return _iswctype_l( wc, _UPPER, locale );
2382 /*********************************************************************
2383 * iswupper (MSVCRT.@)
2385 INT CDECL iswupper( wchar_t wc )
2387 return _iswupper_l( wc, NULL );
2390 /*********************************************************************
2391 * _iswxdigit_l (MSVCRT.@)
2393 int CDECL _iswxdigit_l( wchar_t wc, _locale_t locale )
2395 return _iswctype_l( wc, _HEX, locale );
2398 /*********************************************************************
2399 * iswxdigit (MSVCRT.@)
2401 INT CDECL iswxdigit( wchar_t wc )
2403 return _iswxdigit_l( wc, NULL );
2406 /*********************************************************************
2407 * _iswblank_l (MSVCRT.@)
2409 INT CDECL _iswblank_l( wchar_t wc, _locale_t locale )
2411 return wc == '\t' || _iswctype_l( wc, _BLANK, locale );
2414 /*********************************************************************
2415 * iswblank (MSVCRT.@)
2417 INT CDECL iswblank( wchar_t wc )
2419 return wc == '\t' || _iswctype_l( wc, _BLANK, NULL );
2422 /*********************************************************************
2423 * wcscpy_s (MSVCRT.@)
2425 INT CDECL wcscpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc)
2427 size_t size = 0;
2429 if(!MSVCRT_CHECK_PMT(wcDest)) return EINVAL;
2430 if(!MSVCRT_CHECK_PMT(numElement)) return EINVAL;
2432 if(!MSVCRT_CHECK_PMT(wcSrc))
2434 wcDest[0] = 0;
2435 return EINVAL;
2438 size = wcslen(wcSrc) + 1;
2440 if(!MSVCRT_CHECK_PMT_ERR(size <= numElement, ERANGE))
2442 wcDest[0] = 0;
2443 return ERANGE;
2446 memmove( wcDest, wcSrc, size*sizeof(WCHAR) );
2448 return 0;
2451 /***********************************************************************
2452 * wcscpy (MSVCRT.@)
2454 wchar_t* __cdecl wcscpy( wchar_t *dst, const wchar_t *src )
2456 WCHAR *p = dst;
2457 while ((*p++ = *src++));
2458 return dst;
2461 /******************************************************************
2462 * wcsncpy (MSVCRT.@)
2464 wchar_t* __cdecl wcsncpy( wchar_t* s1, const wchar_t *s2, size_t n )
2466 size_t i;
2468 for(i=0; i<n; i++)
2469 if(!(s1[i] = s2[i])) break;
2470 for(; i<n; i++)
2471 s1[i] = 0;
2472 return s1;
2475 /******************************************************************
2476 * wcsncpy_s (MSVCRT.@)
2478 INT CDECL wcsncpy_s( wchar_t *dst, size_t elem, const wchar_t *src, size_t count )
2480 WCHAR *p = dst;
2481 BOOL truncate = (count == _TRUNCATE);
2483 if (!count)
2485 if (dst && elem) *dst = 0;
2486 return 0;
2489 if (!MSVCRT_CHECK_PMT(dst != NULL)) return EINVAL;
2490 if (!MSVCRT_CHECK_PMT(elem != 0)) return EINVAL;
2491 if (!MSVCRT_CHECK_PMT(src != NULL))
2493 *dst = 0;
2494 return EINVAL;
2497 while (elem && count && *src)
2499 *p++ = *src++;
2500 elem--;
2501 count--;
2503 if (!elem && truncate)
2505 *(p-1) = 0;
2506 return STRUNCATE;
2508 else if (!elem)
2510 *dst = 0;
2511 return ERANGE;
2513 *p = 0;
2514 return 0;
2517 /******************************************************************
2518 * wcscat_s (MSVCRT.@)
2521 INT CDECL wcscat_s(wchar_t* dst, size_t elem, const wchar_t* src)
2523 wchar_t* ptr = dst;
2525 if (!dst || elem == 0) return EINVAL;
2526 if (!src)
2528 dst[0] = '\0';
2529 return EINVAL;
2532 /* seek to end of dst string (or elem if no end of string is found */
2533 while (ptr < dst + elem && *ptr != '\0') ptr++;
2534 while (ptr < dst + elem)
2536 if ((*ptr++ = *src++) == '\0') return 0;
2538 /* not enough space */
2539 dst[0] = '\0';
2540 return ERANGE;
2543 /***********************************************************************
2544 * wcscat (MSVCRT.@)
2546 wchar_t* __cdecl wcscat( wchar_t *dst, const wchar_t *src )
2548 wcscpy( dst + wcslen(dst), src );
2549 return dst;
2552 /*********************************************************************
2553 * wcsncat_s (MSVCRT.@)
2555 errno_t CDECL wcsncat_s(wchar_t *dst, size_t elem, const wchar_t *src, size_t count)
2557 size_t i, j;
2559 if (!MSVCRT_CHECK_PMT(dst != NULL)) return EINVAL;
2560 if (!MSVCRT_CHECK_PMT(elem > 0)) return EINVAL;
2561 if (count == 0) return 0;
2562 if (!MSVCRT_CHECK_PMT(src != NULL))
2564 *dst = 0;
2565 return EINVAL;
2568 for (i = 0; i < elem; i++) if (!dst[i]) break;
2570 if (i == elem)
2572 MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n", EINVAL);
2573 *dst = 0;
2574 return EINVAL;
2577 for (j = 0; (j + i) < elem; j++)
2579 if(count == _TRUNCATE && j + i == elem - 1)
2581 dst[j + i] = '\0';
2582 return STRUNCATE;
2584 if(j == count || (dst[j + i] = src[j]) == '\0')
2586 dst[j + i] = '\0';
2587 return 0;
2591 MSVCRT_INVALID_PMT("dst[elem] is too small", ERANGE);
2592 dst[0] = '\0';
2593 return ERANGE;
2596 /*********************************************************************
2597 * wcsncat (NTDLL.@)
2599 wchar_t * __cdecl wcsncat(wchar_t *s1, const wchar_t *s2, size_t n)
2601 wchar_t *ret = s1;
2602 while (*s1) s1++;
2603 while (n-- > 0) if (!(*s1++ = *s2++)) return ret;
2604 *s1 = 0;
2605 return ret;
2608 /*********************************************************************
2609 * wctoint (INTERNAL)
2611 static int wctoint(WCHAR c, int base)
2613 int v = -1;
2614 if ('0' <= c && c <= '9')
2615 v = c - '0';
2616 else if ('A' <= c && c <= 'Z')
2617 v = c - 'A' + 10;
2618 else if ('a' <= c && c <= 'z')
2619 v = c - 'a' + 10;
2620 else {
2621 /* NOTE: MAP_FOLDDIGITS supports too many things. */
2622 /* Unicode points that contain digits 0-9; keep this sorted! */
2623 static const WCHAR zeros[] = {
2624 0x660, 0x6f0, 0x966, 0x9e6, 0xa66, 0xae6, 0xb66, 0xc66, 0xce6,
2625 0xd66, 0xe50, 0xed0, 0xf20, 0x1040, 0x17e0, 0x1810, 0xff10
2627 int i;
2628 for (i = 0; i < ARRAY_SIZE(zeros) && c >= zeros[i]; ++i) {
2629 if (zeros[i] <= c && c <= zeros[i] + 9) {
2630 v = c - zeros[i];
2631 break;
2635 return v < base ? v : -1;
2638 /*********************************************************************
2639 * _wcstoi64_l (MSVCRT.@)
2641 __int64 CDECL _wcstoi64_l(const wchar_t *nptr,
2642 wchar_t **endptr, int base, _locale_t locale)
2644 BOOL negative = FALSE, empty = TRUE;
2645 __int64 ret = 0;
2647 TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
2649 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
2650 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
2651 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
2653 if(endptr)
2654 *endptr = (wchar_t*)nptr;
2656 while(_iswspace_l(*nptr, locale)) nptr++;
2658 if(*nptr == '-') {
2659 negative = TRUE;
2660 nptr++;
2661 } else if(*nptr == '+')
2662 nptr++;
2664 if((base==0 || base==16) && wctoint(*nptr, 1)==0 && (nptr[1]=='x' || nptr[1]=='X')) {
2665 base = 16;
2666 nptr += 2;
2669 if(base == 0) {
2670 if(wctoint(*nptr, 1)==0)
2671 base = 8;
2672 else
2673 base = 10;
2676 while(*nptr) {
2677 int v = wctoint(*nptr, base);
2678 if(v<0)
2679 break;
2681 if(negative)
2682 v = -v;
2684 nptr++;
2685 empty = FALSE;
2687 if(!negative && (ret>I64_MAX/base || ret*base>I64_MAX-v)) {
2688 ret = I64_MAX;
2689 *_errno() = ERANGE;
2690 } else if(negative && (ret<I64_MIN/base || ret*base<I64_MIN-v)) {
2691 ret = I64_MIN;
2692 *_errno() = ERANGE;
2693 } else
2694 ret = ret*base + v;
2697 if(endptr && !empty)
2698 *endptr = (wchar_t*)nptr;
2700 return ret;
2703 /*********************************************************************
2704 * _wcstoi64 (MSVCRT.@)
2706 __int64 CDECL _wcstoi64(const wchar_t *nptr,
2707 wchar_t **endptr, int base)
2709 return _wcstoi64_l(nptr, endptr, base, NULL);
2712 /*********************************************************************
2713 * _wcstol_l (MSVCRT.@)
2715 __msvcrt_long CDECL _wcstol_l(const wchar_t *s,
2716 wchar_t **end, int base, _locale_t locale)
2718 __int64 ret = _wcstoi64_l(s, end, base, locale);
2720 if(ret > LONG_MAX) {
2721 ret = LONG_MAX;
2722 *_errno() = ERANGE;
2723 }else if(ret < LONG_MIN) {
2724 ret = LONG_MIN;
2725 *_errno() = ERANGE;
2727 return ret;
2730 /*********************************************************************
2731 * wcstol (MSVCRT.@)
2733 __msvcrt_long CDECL wcstol(const wchar_t *s,
2734 wchar_t **end, int base)
2736 return _wcstol_l(s, end, base, NULL);
2739 /*********************************************************************
2740 * _wtoi_l (MSVCRT.@)
2742 int __cdecl _wtoi_l(const wchar_t *str, _locale_t locale)
2744 __int64 ret = _wcstoi64_l(str, NULL, 10, locale);
2746 if(ret > INT_MAX) {
2747 ret = INT_MAX;
2748 *_errno() = ERANGE;
2749 } else if(ret < INT_MIN) {
2750 ret = INT_MIN;
2751 *_errno() = ERANGE;
2753 return ret;
2756 /*********************************************************************
2757 * _wtoi (MSVCRT.@)
2759 int __cdecl _wtoi(const wchar_t *str)
2761 return _wtoi_l(str, NULL);
2764 /*********************************************************************
2765 * _wtol_l (MSVCRT.@)
2767 __msvcrt_long __cdecl _wtol_l(const wchar_t *str, _locale_t locale)
2769 __int64 ret = _wcstoi64_l(str, NULL, 10, locale);
2771 if(ret > LONG_MAX) {
2772 ret = LONG_MAX;
2773 *_errno() = ERANGE;
2774 } else if(ret < LONG_MIN) {
2775 ret = LONG_MIN;
2776 *_errno() = ERANGE;
2778 return ret;
2781 /*********************************************************************
2782 * _wtol (MSVCRT.@)
2784 __msvcrt_long __cdecl _wtol(const wchar_t *str)
2786 return _wtol_l(str, NULL);
2789 #if _MSVCR_VER>=120
2791 /*********************************************************************
2792 * _wtoll_l (MSVCR120.@)
2794 __int64 __cdecl _wtoll_l(const wchar_t *str, _locale_t locale)
2796 return _wcstoi64_l(str, NULL, 10, locale);
2799 /*********************************************************************
2800 * _wtoll (MSVCR120.@)
2802 __int64 __cdecl _wtoll(const wchar_t *str)
2804 return _wtoll_l(str, NULL);
2807 #endif /* _MSVCR_VER>=120 */
2809 /*********************************************************************
2810 * _wcstoui64_l (MSVCRT.@)
2812 unsigned __int64 CDECL _wcstoui64_l(const wchar_t *nptr,
2813 wchar_t **endptr, int base, _locale_t locale)
2815 BOOL negative = FALSE, empty = TRUE;
2816 unsigned __int64 ret = 0;
2818 TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
2820 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
2821 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
2822 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
2824 if(endptr)
2825 *endptr = (wchar_t*)nptr;
2827 while(_iswspace_l(*nptr, locale)) nptr++;
2829 if(*nptr == '-') {
2830 negative = TRUE;
2831 nptr++;
2832 } else if(*nptr == '+')
2833 nptr++;
2835 if((base==0 || base==16) && wctoint(*nptr, 1)==0 && (nptr[1]=='x' || nptr[1]=='X')) {
2836 base = 16;
2837 nptr += 2;
2840 if(base == 0) {
2841 if(wctoint(*nptr, 1)==0)
2842 base = 8;
2843 else
2844 base = 10;
2847 while(*nptr) {
2848 int v = wctoint(*nptr, base);
2849 if(v<0)
2850 break;
2852 nptr++;
2853 empty = FALSE;
2855 if(ret>UI64_MAX/base || ret*base>UI64_MAX-v) {
2856 ret = UI64_MAX;
2857 *_errno() = ERANGE;
2858 } else
2859 ret = ret*base + v;
2862 if(endptr && !empty)
2863 *endptr = (wchar_t*)nptr;
2865 return negative ? -ret : ret;
2868 /*********************************************************************
2869 * _wcstoui64 (MSVCRT.@)
2871 unsigned __int64 CDECL _wcstoui64(const wchar_t *nptr,
2872 wchar_t **endptr, int base)
2874 return _wcstoui64_l(nptr, endptr, base, NULL);
2877 /*********************************************************************
2878 * _wcstoul_l (MSVCRT.@)
2880 __msvcrt_ulong __cdecl _wcstoul_l(const wchar_t *s,
2881 wchar_t **end, int base, _locale_t locale)
2883 __int64 ret = _wcstoi64_l(s, end, base, locale);
2885 if(ret > ULONG_MAX) {
2886 ret = ULONG_MAX;
2887 *_errno() = ERANGE;
2888 }else if(ret < -(__int64)ULONG_MAX) {
2889 ret = 1;
2890 *_errno() = ERANGE;
2892 return ret;
2895 /*********************************************************************
2896 * wcstoul (MSVCRT.@)
2898 __msvcrt_ulong __cdecl wcstoul(const wchar_t *s, wchar_t **end, int base)
2900 return _wcstoul_l(s, end, base, NULL);
2903 /******************************************************************
2904 * wcsnlen (MSVCRT.@)
2906 size_t CDECL wcsnlen(const wchar_t *s, size_t maxlen)
2908 size_t i;
2910 for (i = 0; i < maxlen; i++)
2911 if (!s[i]) break;
2912 return i;
2915 /*********************************************************************
2916 * _towupper_l (MSVCRT.@)
2918 wint_t CDECL _towupper_l(wint_t c, _locale_t locale)
2920 pthreadlocinfo locinfo;
2921 wchar_t ret;
2923 if(!locale)
2924 locinfo = get_locinfo();
2925 else
2926 locinfo = locale->locinfo;
2928 if(!locinfo->lc_handle[LC_CTYPE]) {
2929 if(c >= 'a' && c <= 'z')
2930 return c + 'A' - 'a';
2931 return c;
2934 if(!LCMapStringW(locinfo->lc_handle[LC_CTYPE], LCMAP_UPPERCASE, &c, 1, &ret, 1))
2935 return c;
2936 return ret;
2939 /*********************************************************************
2940 * towupper (MSVCRT.@)
2942 wint_t CDECL towupper(wint_t c)
2944 return _towupper_l(c, NULL);
2947 /*********************************************************************
2948 * wcschr (MSVCRT.@)
2950 wchar_t* CDECL wcschr(const wchar_t *str, wchar_t ch)
2952 do { if (*str == ch) return (WCHAR *)(ULONG_PTR)str; } while (*str++);
2953 return NULL;
2956 /*********************************************************************
2957 * wcsrchr (MSVCRT.@)
2959 wchar_t* CDECL wcsrchr(const wchar_t *str, wchar_t ch)
2961 WCHAR *ret = NULL;
2962 do { if (*str == ch) ret = (WCHAR *)(ULONG_PTR)str; } while (*str++);
2963 return ret;
2966 /***********************************************************************
2967 * wcslen (MSVCRT.@)
2969 size_t CDECL wcslen(const wchar_t *str)
2971 const wchar_t *s = str;
2972 while (*s) s++;
2973 return s - str;
2976 /*********************************************************************
2977 * wcsstr (MSVCRT.@)
2979 wchar_t* CDECL wcsstr(const wchar_t *str, const wchar_t *sub)
2981 while(*str)
2983 const wchar_t *p1 = str, *p2 = sub;
2984 while(*p1 && *p2 && *p1 == *p2)
2986 p1++;
2987 p2++;
2989 if(!*p2)
2990 return (wchar_t*)str;
2991 str++;
2993 return NULL;
2996 /*********************************************************************
2997 * _wtoi64_l (MSVCRT.@)
2999 __int64 CDECL _wtoi64_l(const wchar_t *str, _locale_t locale)
3001 ULONGLONG RunningTotal = 0;
3002 BOOL bMinus = FALSE;
3004 while (_iswspace_l(*str, locale)) {
3005 str++;
3006 } /* while */
3008 if (*str == '+') {
3009 str++;
3010 } else if (*str == '-') {
3011 bMinus = TRUE;
3012 str++;
3013 } /* if */
3015 while (*str >= '0' && *str <= '9') {
3016 RunningTotal = RunningTotal * 10 + *str - '0';
3017 str++;
3018 } /* while */
3020 return bMinus ? -RunningTotal : RunningTotal;
3023 /*********************************************************************
3024 * _wtoi64 (MSVCRT.@)
3026 __int64 CDECL _wtoi64(const wchar_t *str)
3028 return _wtoi64_l(str, NULL);
3031 /*********************************************************************
3032 * _wcsxfrm_l (MSVCRT.@)
3034 size_t CDECL _wcsxfrm_l(wchar_t *dest, const wchar_t *src,
3035 size_t len, _locale_t locale)
3037 pthreadlocinfo locinfo;
3038 int i, ret;
3040 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
3041 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
3043 if(len > INT_MAX) {
3044 FIXME("len > INT_MAX not supported\n");
3045 len = INT_MAX;
3048 if(!locale)
3049 locinfo = get_locinfo();
3050 else
3051 locinfo = locale->locinfo;
3053 if(!locinfo->lc_handle[LC_COLLATE]) {
3054 wcsncpy(dest, src, len);
3055 return wcslen(src);
3058 ret = LCMapStringW(locinfo->lc_handle[LC_COLLATE],
3059 LCMAP_SORTKEY, src, -1, NULL, 0);
3060 if(!ret) {
3061 if(len) dest[0] = 0;
3062 *_errno() = EILSEQ;
3063 return INT_MAX;
3065 if(!len) return ret-1;
3067 if(ret > len) {
3068 dest[0] = 0;
3069 *_errno() = ERANGE;
3070 return ret-1;
3073 ret = LCMapStringW(locinfo->lc_handle[LC_COLLATE],
3074 LCMAP_SORTKEY, src, -1, dest, len) - 1;
3075 for(i=ret; i>=0; i--)
3076 dest[i] = ((unsigned char*)dest)[i];
3077 return ret;
3080 /*********************************************************************
3081 * wcsxfrm (MSVCRT.@)
3083 size_t CDECL wcsxfrm(wchar_t *dest, const wchar_t *src, size_t len)
3085 return _wcsxfrm_l(dest, src, len, NULL);