msvcrt: Don't forward _wcsicmp to ntdll.
[wine] / dlls / msvcrt / wcs.c
1 /*
2  * msvcrt.dll wide-char functions
3  *
4  * Copyright 1999 Alexandre Julliard
5  * Copyright 2000 Jon Griffiths
6  *
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.
11  *
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.
16  *
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
20  */
21 #include "config.h"
22 #include "wine/port.h"
23
24 #include <limits.h>
25 #include <stdio.h>
26 #include <math.h>
27 #include <assert.h>
28 #include "msvcrt.h"
29 #include "winnls.h"
30 #include "wtypes.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
35
36 static BOOL n_format_enabled = TRUE;
37
38 #include "printf.h"
39 #define PRINTF_WIDE
40 #include "printf.h"
41 #undef PRINTF_WIDE
42
43 /* _get_printf_count_output - not exported in native msvcrt */
44 int CDECL MSVCRT__get_printf_count_output( void )
45 {
46     return n_format_enabled ? 1 : 0;
47 }
48
49 /* _set_printf_count_output - not exported in native msvcrt */
50 int CDECL MSVCRT__set_printf_count_output( int enable )
51 {
52     BOOL old = n_format_enabled;
53     n_format_enabled = enable != 0;
54     return old ? 1 : 0;
55 }
56
57 /*********************************************************************
58  *              _wcsdup (MSVCRT.@)
59  */
60 MSVCRT_wchar_t* CDECL MSVCRT__wcsdup( const MSVCRT_wchar_t* str )
61 {
62   MSVCRT_wchar_t* ret = NULL;
63   if (str)
64   {
65     int size = (strlenW(str) + 1) * sizeof(MSVCRT_wchar_t);
66     ret = MSVCRT_malloc( size );
67     if (ret) memcpy( ret, str, size );
68   }
69   return ret;
70 }
71
72 /*********************************************************************
73  *              _wcsicmp (MSVCRT.@)
74  */
75 INT CDECL MSVCRT__wcsicmp( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
76 {
77     return strcmpiW( str1, str2 );
78 }
79
80 /*********************************************************************
81  *              _wcsicoll (MSVCRT.@)
82  */
83 INT CDECL MSVCRT__wcsicoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
84 {
85     return CompareStringW(get_locinfo()->lc_handle[MSVCRT_LC_COLLATE],
86             NORM_IGNORECASE, str1, -1, str2, -1)-CSTR_EQUAL;
87 }
88
89 /*********************************************************************
90  *              _wcsnicoll (MSVCRT.@)
91  */
92 INT CDECL MSVCRT__wcsnicoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2, MSVCRT_size_t count )
93 {
94     return CompareStringW(get_locinfo()->lc_handle[MSVCRT_LC_COLLATE],
95             NORM_IGNORECASE, str1, count, str2, count)-CSTR_EQUAL;
96 }
97
98 /*********************************************************************
99  *              _wcsnset (MSVCRT.@)
100  */
101 MSVCRT_wchar_t* CDECL MSVCRT__wcsnset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c, MSVCRT_size_t n )
102 {
103   MSVCRT_wchar_t* ret = str;
104   while ((n-- > 0) && *str) *str++ = c;
105   return ret;
106 }
107
108 /*********************************************************************
109  *              _wcsrev (MSVCRT.@)
110  */
111 MSVCRT_wchar_t* CDECL MSVCRT__wcsrev( MSVCRT_wchar_t* str )
112 {
113   MSVCRT_wchar_t* ret = str;
114   MSVCRT_wchar_t* end = str + strlenW(str) - 1;
115   while (end > str)
116   {
117     MSVCRT_wchar_t t = *end;
118     *end--  = *str;
119     *str++  = t;
120   }
121   return ret;
122 }
123
124 /*********************************************************************
125  *              _wcsset (MSVCRT.@)
126  */
127 MSVCRT_wchar_t* CDECL MSVCRT__wcsset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c )
128 {
129   MSVCRT_wchar_t* ret = str;
130   while (*str) *str++ = c;
131   return ret;
132 }
133
134 /******************************************************************
135  *              _wcsupr_s_l (MSVCRT.@)
136  */
137 int CDECL MSVCRT__wcsupr_s_l( MSVCRT_wchar_t* str, MSVCRT_size_t n,
138    MSVCRT__locale_t locale )
139 {
140   MSVCRT_wchar_t* ptr = str;
141
142   if (!str || !n)
143   {
144     if (str) *str = '\0';
145     *MSVCRT__errno() = MSVCRT_EINVAL;
146     return MSVCRT_EINVAL;
147   }
148
149   while (n--)
150   {
151     if (!*ptr) return 0;
152     /* FIXME: add locale support */
153     *ptr = toupperW(*ptr);
154     ptr++;
155   }
156
157   /* MSDN claims that the function should return and set errno to
158    * ERANGE, which doesn't seem to be true based on the tests. */
159   *str = '\0';
160   *MSVCRT__errno() = MSVCRT_EINVAL;
161   return MSVCRT_EINVAL;
162 }
163
164 /******************************************************************
165  *              _wcsupr_s (MSVCRT.@)
166  *
167  */
168 INT CDECL MSVCRT__wcsupr_s( MSVCRT_wchar_t* str, MSVCRT_size_t n )
169 {
170   return MSVCRT__wcsupr_s_l( str, n, NULL );
171 }
172
173 /******************************************************************
174  *              _wcslwr_s (MSVCRT.@)
175  */
176 int CDECL MSVCRT__wcslwr_s( MSVCRT_wchar_t* str, MSVCRT_size_t n )
177 {
178   MSVCRT_wchar_t* ptr = str;
179
180   if (!str || !n)
181   {
182     if (str) *str = '\0';
183     *MSVCRT__errno() = MSVCRT_EINVAL;
184     return MSVCRT_EINVAL;
185   }
186
187   while (n--)
188   {
189     if (!*ptr) return 0;
190     *ptr = tolowerW(*ptr);
191     ptr++;
192   }
193
194   /* MSDN claims that the function should return and set errno to
195    * ERANGE, which doesn't seem to be true based on the tests. */
196   *str = '\0';
197   *MSVCRT__errno() = MSVCRT_EINVAL;
198   return MSVCRT_EINVAL;
199 }
200
201 /*********************************************************************
202  * _wcstod_l - not exported in native msvcrt
203  */
204 double CDECL MSVCRT__wcstod_l(const MSVCRT_wchar_t* str, MSVCRT_wchar_t** end,
205         MSVCRT__locale_t locale)
206 {
207     MSVCRT_pthreadlocinfo locinfo;
208     unsigned __int64 d=0, hlp;
209     unsigned fpcontrol;
210     int exp=0, sign=1;
211     const MSVCRT_wchar_t *p;
212     double ret;
213     long double lret=1, expcnt = 10;
214     BOOL found_digit = FALSE, negexp;
215
216     if (!MSVCRT_CHECK_PMT(str != NULL)) return 0;
217
218     if(!locale)
219         locinfo = get_locinfo();
220     else
221         locinfo = locale->locinfo;
222
223     p = str;
224     while(isspaceW(*p))
225         p++;
226
227     if(*p == '-') {
228         sign = -1;
229         p++;
230     } else  if(*p == '+')
231         p++;
232
233     while(isdigitW(*p)) {
234         found_digit = TRUE;
235         hlp = d*10+*(p++)-'0';
236         if(d>MSVCRT_UI64_MAX/10 || hlp<d) {
237             exp++;
238             break;
239         } else
240             d = hlp;
241     }
242     while(isdigitW(*p)) {
243         exp++;
244         p++;
245     }
246     if(*p == *locinfo->lconv->decimal_point)
247         p++;
248
249     while(isdigitW(*p)) {
250         found_digit = TRUE;
251         hlp = d*10+*(p++)-'0';
252         if(d>MSVCRT_UI64_MAX/10 || hlp<d)
253             break;
254
255         d = hlp;
256         exp--;
257     }
258     while(isdigitW(*p))
259         p++;
260
261     if(!found_digit) {
262         if(end)
263             *end = (MSVCRT_wchar_t*)str;
264         return 0.0;
265     }
266
267     if(*p=='e' || *p=='E' || *p=='d' || *p=='D') {
268         int e=0, s=1;
269
270         p++;
271         if(*p == '-') {
272             s = -1;
273             p++;
274         } else if(*p == '+')
275             p++;
276
277         if(isdigitW(*p)) {
278             while(isdigitW(*p)) {
279                 if(e>INT_MAX/10 || (e=e*10+*p-'0')<0)
280                     e = INT_MAX;
281                 p++;
282             }
283             e *= s;
284
285             if(exp<0 && e<0 && exp+e>=0) exp = INT_MIN;
286             else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
287             else exp += e;
288         } else {
289             if(*p=='-' || *p=='+')
290                 p--;
291             p--;
292         }
293     }
294
295     fpcontrol = _control87(0, 0);
296     _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE
297             |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff);
298
299     negexp = (exp < 0);
300     if(negexp)
301         exp = -exp;
302     while(exp) {
303         if(exp & 1)
304             lret *= expcnt;
305         exp /= 2;
306         expcnt = expcnt*expcnt;
307     }
308     ret = (long double)sign * (negexp ? d/lret : d*lret);
309
310     _control87(fpcontrol, 0xffffffff);
311
312     if((d && ret==0.0) || isinf(ret))
313         *MSVCRT__errno() = MSVCRT_ERANGE;
314
315     if(end)
316         *end = (MSVCRT_wchar_t*)p;
317
318     return ret;
319 }
320
321 /*********************************************************************
322  * wcsrtombs_l (INTERNAL)
323  */
324 static MSVCRT_size_t CDECL MSVCRT_wcsrtombs_l(char *mbstr, const MSVCRT_wchar_t **wcstr,
325         MSVCRT_size_t count, MSVCRT__locale_t locale)
326 {
327     MSVCRT_pthreadlocinfo locinfo;
328     MSVCRT_size_t tmp = 0;
329     BOOL used_default;
330
331     if(!locale)
332         locinfo = get_locinfo();
333     else
334         locinfo = locale->locinfo;
335
336     if(!mbstr) {
337         tmp = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
338                 *wcstr, -1, NULL, 0, NULL, &used_default)-1;
339         if(used_default)
340             return -1;
341         return tmp;
342     }
343
344     while(**wcstr) {
345         char buf[3];
346         MSVCRT_size_t i, size;
347
348         size = WideCharToMultiByte(locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
349                 *wcstr, 1, buf, 3, NULL, &used_default);
350         if(used_default)
351             return -1;
352         if(tmp+size > count)
353             return tmp;
354
355         for(i=0; i<size; i++)
356             mbstr[tmp++] = buf[i];
357         (*wcstr)++;
358     }
359
360     if(tmp < count) {
361         mbstr[tmp] = '\0';
362         *wcstr = NULL;
363     }
364     return tmp;
365 }
366
367 /*********************************************************************
368  *              _wcstombs_l (MSVCRT.@)
369  */
370 MSVCRT_size_t CDECL MSVCRT__wcstombs_l(char *mbstr, const MSVCRT_wchar_t *wcstr,
371         MSVCRT_size_t count, MSVCRT__locale_t locale)
372 {
373     return MSVCRT_wcsrtombs_l(mbstr, &wcstr, count, locale);
374 }
375
376 /*********************************************************************
377  *              wcstombs (MSVCRT.@)
378  */
379 MSVCRT_size_t CDECL MSVCRT_wcstombs(char *mbstr, const MSVCRT_wchar_t *wcstr,
380         MSVCRT_size_t count)
381 {
382     return MSVCRT_wcsrtombs_l(mbstr, &wcstr, count, NULL);
383 }
384
385 /*********************************************************************
386  *              wcsrtombs (MSVCRT.@)
387  */
388 MSVCRT_size_t CDECL MSVCRT_wcsrtombs(char *mbstr, const MSVCRT_wchar_t **wcstr,
389         MSVCRT_size_t count, MSVCRT_mbstate_t *mbstate)
390 {
391     if(mbstate)
392         *mbstate = 0;
393
394     return MSVCRT_wcsrtombs_l(mbstr, wcstr, count, NULL);
395 }
396
397 /*********************************************************************
398  * MSVCRT_wcsrtombs_s_l (INTERNAL)
399  */
400 static int MSVCRT_wcsrtombs_s_l(MSVCRT_size_t *ret, char *mbstr,
401         MSVCRT_size_t size, const MSVCRT_wchar_t **wcstr,
402         MSVCRT_size_t count, MSVCRT__locale_t locale)
403 {
404     MSVCRT_size_t conv;
405
406     if(!mbstr && !size && wcstr) {
407         conv = MSVCRT_wcsrtombs_l(NULL, wcstr, 0, locale);
408         if(ret)
409             *ret = conv+1;
410         return 0;
411     }
412
413     if (!MSVCRT_CHECK_PMT(mbstr != NULL)) return MSVCRT_EINVAL;
414     if (size) mbstr[0] = '\0';
415     if (!MSVCRT_CHECK_PMT(wcstr != NULL)) return MSVCRT_EINVAL;
416     if (!MSVCRT_CHECK_PMT(*wcstr != NULL)) return MSVCRT_EINVAL;
417
418     if(count==MSVCRT__TRUNCATE || size<count)
419         conv = size;
420     else
421         conv = count;
422
423     conv = MSVCRT_wcsrtombs_l(mbstr, wcstr, conv, locale);
424     if(conv<size)
425         mbstr[conv++] = '\0';
426     else if(conv==size && (count==MSVCRT__TRUNCATE || mbstr[conv-1]=='\0'))
427         mbstr[conv-1] = '\0';
428     else {
429         MSVCRT_INVALID_PMT("mbstr[size] is too small", MSVCRT_ERANGE);
430         if(size)
431             mbstr[0] = '\0';
432         return MSVCRT_ERANGE;
433     }
434
435     if(ret)
436         *ret = conv;
437     return 0;
438 }
439
440 /*********************************************************************
441  *              _wcstombs_s_l (MSVCRT.@)
442  */
443 int CDECL MSVCRT__wcstombs_s_l(MSVCRT_size_t *ret, char *mbstr,
444         MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr,
445         MSVCRT_size_t count, MSVCRT__locale_t locale)
446 {
447     return MSVCRT_wcsrtombs_s_l(ret, mbstr, size, &wcstr,count, locale);
448 }
449
450 /*********************************************************************
451  *              wcstombs_s (MSVCRT.@)
452  */
453 int CDECL MSVCRT_wcstombs_s(MSVCRT_size_t *ret, char *mbstr,
454         MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr, MSVCRT_size_t count)
455 {
456     return MSVCRT_wcsrtombs_s_l(ret, mbstr, size, &wcstr, count, NULL);
457 }
458
459 /*********************************************************************
460  *              wcsrtombs_s (MSVCRT.@)
461  */
462 int CDECL MSVCRT_wcsrtombs_s(MSVCRT_size_t *ret, char *mbstr, MSVCRT_size_t size,
463         const MSVCRT_wchar_t **wcstr, MSVCRT_size_t count, MSVCRT_mbstate_t *mbstate)
464 {
465     if(mbstate)
466         *mbstate = 0;
467
468     return MSVCRT_wcsrtombs_s_l(ret, mbstr, size, wcstr, count, NULL);
469 }
470
471 /*********************************************************************
472  *              wcstod (MSVCRT.@)
473  */
474 double CDECL MSVCRT_wcstod(const MSVCRT_wchar_t* lpszStr, MSVCRT_wchar_t** end)
475 {
476     return MSVCRT__wcstod_l(lpszStr, end, NULL);
477 }
478
479 /*********************************************************************
480  *              _wtof (MSVCRT.@)
481  */
482 double CDECL MSVCRT__wtof(const MSVCRT_wchar_t *str)
483 {
484     return MSVCRT__wcstod_l(str, NULL, NULL);
485 }
486
487 /*********************************************************************
488  *              _wtof_l (MSVCRT.@)
489  */
490 double CDECL MSVCRT__wtof_l(const MSVCRT_wchar_t *str, MSVCRT__locale_t locale)
491 {
492     return MSVCRT__wcstod_l(str, NULL, locale);
493 }
494
495 /*********************************************************************
496  * arg_clbk_valist (INTERNAL)
497  */
498 printf_arg arg_clbk_valist(void *ctx, int arg_pos, int type, __ms_va_list *valist)
499 {
500     printf_arg ret;
501
502     if(type == VT_I8)
503         ret.get_longlong = va_arg(*valist, LONGLONG);
504     else if(type == VT_INT)
505         ret.get_int = va_arg(*valist, int);
506     else if(type == VT_R8)
507         ret.get_double = va_arg(*valist, double);
508     else if(type == VT_PTR)
509         ret.get_ptr = va_arg(*valist, void*);
510     else {
511         ERR("Incorrect type\n");
512         ret.get_int = 0;
513     }
514
515     return ret;
516 }
517
518 /*********************************************************************
519  * arg_clbk_positional (INTERNAL)
520  */
521 static printf_arg arg_clbk_positional(void *ctx, int pos, int type, __ms_va_list *valist)
522 {
523     printf_arg *args = ctx;
524     return args[pos];
525 }
526
527 /*********************************************************************
528  *              _vsnprintf (MSVCRT.@)
529  */
530 int CDECL MSVCRT_vsnprintf( char *str, MSVCRT_size_t len,
531                             const char *format, __ms_va_list valist )
532 {
533     static const char nullbyte = '\0';
534     struct _str_ctx_a ctx = {len, str};
535     int ret;
536
537     ret = pf_printf_a(puts_clbk_str_a, &ctx, format, NULL, FALSE, FALSE,
538             arg_clbk_valist, NULL, &valist);
539     puts_clbk_str_a(&ctx, 1, &nullbyte);
540     return ret;
541 }
542
543 /*********************************************************************
544 *               _vsnprintf_l (MSVCRT.@)
545  */
546 int CDECL MSVCRT_vsnprintf_l( char *str, MSVCRT_size_t len, const char *format,
547                             MSVCRT__locale_t locale, __ms_va_list valist )
548 {
549     static const char nullbyte = '\0';
550     struct _str_ctx_a ctx = {len, str};
551     int ret;
552
553     ret = pf_printf_a(puts_clbk_str_a, &ctx, format, locale, FALSE, FALSE,
554             arg_clbk_valist, NULL, &valist);
555     puts_clbk_str_a(&ctx, 1, &nullbyte);
556     return ret;
557 }
558
559 /*********************************************************************
560  *              _vsnprintf_s_l (MSVCRT.@)
561  */
562 int CDECL MSVCRT_vsnprintf_s_l( char *str, MSVCRT_size_t sizeOfBuffer,
563         MSVCRT_size_t count, const char *format,
564         MSVCRT__locale_t locale, __ms_va_list valist )
565 {
566     static const char nullbyte = '\0';
567     struct _str_ctx_a ctx;
568     int len, ret;
569
570     if(sizeOfBuffer<count+1 || count==-1)
571         len = sizeOfBuffer;
572     else
573         len = count+1;
574
575     ctx.len = len;
576     ctx.buf = str;
577     ret = pf_printf_a(puts_clbk_str_a, &ctx, format, locale, FALSE, TRUE,
578             arg_clbk_valist, NULL, &valist);
579     puts_clbk_str_a(&ctx, 1, &nullbyte);
580
581     if(ret<0 || ret==len) {
582         if(count!=MSVCRT__TRUNCATE && count>sizeOfBuffer) {
583             MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small", MSVCRT_ERANGE);
584             memset(str, 0, sizeOfBuffer);
585         } else
586             str[len-1] = '\0';
587
588         return -1;
589     }
590
591     return ret;
592 }
593
594 /*********************************************************************
595  *              _vsnprintf_s (MSVCRT.@)
596  */
597 int CDECL MSVCRT_vsnprintf_s( char *str, MSVCRT_size_t sizeOfBuffer,
598         MSVCRT_size_t count, const char *format, __ms_va_list valist )
599 {
600     return MSVCRT_vsnprintf_s_l(str,sizeOfBuffer, count, format, NULL, valist);
601 }
602
603 /*********************************************************************
604  *              vsprintf (MSVCRT.@)
605  */
606 int CDECL MSVCRT_vsprintf( char *str, const char *format, __ms_va_list valist)
607 {
608     return MSVCRT_vsnprintf(str, INT_MAX, format, valist);
609 }
610
611 /*********************************************************************
612  *              vsprintf_s (MSVCRT.@)
613  */
614 int CDECL MSVCRT_vsprintf_s( char *str, MSVCRT_size_t num, const char *format, __ms_va_list valist)
615 {
616     return MSVCRT_vsnprintf(str, num, format, valist);
617 }
618
619 /*********************************************************************
620  *              _vscprintf (MSVCRT.@)
621  */
622 int CDECL MSVCRT__vscprintf( const char *format, __ms_va_list valist )
623 {
624     return MSVCRT_vsnprintf( NULL, INT_MAX, format, valist );
625 }
626
627 /*********************************************************************
628  *              _snprintf (MSVCRT.@)
629  */
630 int CDECL MSVCRT__snprintf(char *str, unsigned int len, const char *format, ...)
631 {
632     int retval;
633     __ms_va_list valist;
634     __ms_va_start(valist, format);
635     retval = MSVCRT_vsnprintf(str, len, format, valist);
636     __ms_va_end(valist);
637     return retval;
638 }
639
640 /*********************************************************************
641  *              _snprintf_s (MSVCRT.@)
642  */
643 int CDECL MSVCRT__snprintf_s(char *str, unsigned int len, unsigned int count,
644     const char *format, ...)
645 {
646     int retval;
647     __ms_va_list valist;
648     __ms_va_start(valist, format);
649     retval = MSVCRT_vsnprintf_s_l(str, len, count, format, NULL, valist);
650     __ms_va_end(valist);
651     return retval;
652 }
653
654 /*********************************************************************
655  *              _scprintf (MSVCRT.@)
656  */
657 int CDECL MSVCRT__scprintf(const char *format, ...)
658 {
659     int retval;
660     __ms_va_list valist;
661     __ms_va_start(valist, format);
662     retval = MSVCRT__vscprintf(format, valist);
663     __ms_va_end(valist);
664     return retval;
665 }
666
667 /*********************************************************************
668  *              _vsnwprintf (MSVCRT.@)
669  */
670 int CDECL MSVCRT_vsnwprintf(MSVCRT_wchar_t *str, MSVCRT_size_t len,
671         const MSVCRT_wchar_t *format, __ms_va_list valist)
672 {
673     static const MSVCRT_wchar_t nullbyte = '\0';
674     struct _str_ctx_w ctx = {len, str};
675     int ret;
676
677     ret = pf_printf_w(puts_clbk_str_w, &ctx, format, NULL, FALSE, FALSE,
678             arg_clbk_valist, NULL, &valist);
679     puts_clbk_str_w(&ctx, 1, &nullbyte);
680     return ret;
681 }
682
683 /*********************************************************************
684  *              _vsnwprintf_l (MSVCRT.@)
685  */
686 int CDECL MSVCRT_vsnwprintf_l(MSVCRT_wchar_t *str, MSVCRT_size_t len,
687         const MSVCRT_wchar_t *format, MSVCRT__locale_t locale,
688         __ms_va_list valist)
689 {
690     static const MSVCRT_wchar_t nullbyte = '\0';
691     struct _str_ctx_w ctx = {len, str};
692     int ret;
693
694     ret = pf_printf_w(puts_clbk_str_w, &ctx, format, locale, FALSE, FALSE,
695             arg_clbk_valist, NULL, &valist);
696     puts_clbk_str_w(&ctx, 1, &nullbyte);
697     return ret;
698 }
699
700 /*********************************************************************
701  *              _vswprintf_p_l (MSVCRT.@)
702  */
703 int CDECL MSVCRT_vswprintf_p_l(MSVCRT_wchar_t *buffer, MSVCRT_size_t length,
704         const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list args)
705 {
706     static const MSVCRT_wchar_t nullbyte = '\0';
707     printf_arg args_ctx[MSVCRT__ARGMAX+1];
708     struct _str_ctx_w puts_ctx = {length, buffer};
709     int ret;
710
711     memset(args_ctx, 0, sizeof(args_ctx));
712
713     ret = create_positional_ctx_w(args_ctx, format, args);
714     if(ret < 0)  {
715         MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
716         *MSVCRT__errno() = MSVCRT_EINVAL;
717         return ret;
718     } else if(ret == 0)
719         ret = pf_printf_w(puts_clbk_str_w, &puts_ctx, format, locale, FALSE, TRUE,
720                 arg_clbk_valist, NULL, &args);
721     else
722         ret = pf_printf_w(puts_clbk_str_w, &puts_ctx, format, locale, TRUE, TRUE,
723                 arg_clbk_positional, args_ctx, NULL);
724
725     puts_clbk_str_w(&puts_ctx, 1, &nullbyte);
726     return ret;
727 }
728
729 /*********************************************************************
730  *              _vsnwprintf_s_l (MSVCRT.@)
731  */
732 int CDECL MSVCRT_vsnwprintf_s_l( MSVCRT_wchar_t *str, MSVCRT_size_t sizeOfBuffer,
733         MSVCRT_size_t count, const MSVCRT_wchar_t *format,
734         MSVCRT__locale_t locale, __ms_va_list valist)
735 {
736     static const MSVCRT_wchar_t nullbyte = '\0';
737     struct _str_ctx_w ctx;
738     int len, ret;
739
740     len = sizeOfBuffer;
741     if(count!=-1 && len>count+1)
742         len = count+1;
743
744     ctx.len = len;
745     ctx.buf = str;
746     ret = pf_printf_w(puts_clbk_str_w, &ctx, format, locale, FALSE, TRUE,
747             arg_clbk_valist, NULL, &valist);
748     puts_clbk_str_w(&ctx, 1, &nullbyte);
749
750     if(ret<0 || ret==len) {
751         if(count!=MSVCRT__TRUNCATE && count>sizeOfBuffer) {
752             MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small", MSVCRT_ERANGE);
753             memset(str, 0, sizeOfBuffer*sizeof(MSVCRT_wchar_t));
754         } else
755             str[len-1] = '\0';
756
757         return -1;
758     }
759
760     return ret;
761 }
762
763 /*********************************************************************
764  *              _vsnwprintf_s (MSVCRT.@)
765  */
766 int CDECL MSVCRT_vsnwprintf_s(MSVCRT_wchar_t *str, MSVCRT_size_t sizeOfBuffer,
767         MSVCRT_size_t count, const MSVCRT_wchar_t *format, __ms_va_list valist)
768 {
769     return MSVCRT_vsnwprintf_s_l(str, sizeOfBuffer, count,
770             format, NULL, valist);
771 }
772
773 /*********************************************************************
774  *              _snwprintf (MSVCRT.@)
775  */
776 int CDECL MSVCRT__snwprintf( MSVCRT_wchar_t *str, unsigned int len, const MSVCRT_wchar_t *format, ...)
777 {
778     int retval;
779     __ms_va_list valist;
780     __ms_va_start(valist, format);
781     retval = MSVCRT_vsnwprintf(str, len, format, valist);
782     __ms_va_end(valist);
783     return retval;
784 }
785
786 /*********************************************************************
787  *              _snwprintf_l (MSVCRT.@)
788  */
789 int CDECL MSVCRT__snwprintf_l( MSVCRT_wchar_t *str, unsigned int len, const MSVCRT_wchar_t *format,
790         MSVCRT__locale_t locale, ...)
791 {
792     int retval;
793     __ms_va_list valist;
794     __ms_va_start(valist, locale);
795     retval = MSVCRT_vsnwprintf_l(str, len, format, locale, valist);
796     __ms_va_end(valist);
797     return retval;
798 }
799
800 /*********************************************************************
801  *              _snwprintf_s (MSVCRT.@)
802  */
803 int CDECL MSVCRT__snwprintf_s( MSVCRT_wchar_t *str, unsigned int len, unsigned int count,
804     const MSVCRT_wchar_t *format, ...)
805 {
806     int retval;
807     __ms_va_list valist;
808     __ms_va_start(valist, format);
809     retval = MSVCRT_vsnwprintf_s_l(str, len, count, format, NULL, valist);
810     __ms_va_end(valist);
811     return retval;
812 }
813
814 /*********************************************************************
815  *              sprintf (MSVCRT.@)
816  */
817 int CDECL MSVCRT_sprintf( char *str, const char *format, ... )
818 {
819     __ms_va_list ap;
820     int r;
821
822     __ms_va_start( ap, format );
823     r = MSVCRT_vsnprintf( str, INT_MAX, format, ap );
824     __ms_va_end( ap );
825     return r;
826 }
827
828 /*********************************************************************
829  *              sprintf_s (MSVCRT.@)
830  */
831 int CDECL MSVCRT_sprintf_s( char *str, MSVCRT_size_t num, const char *format, ... )
832 {
833     __ms_va_list ap;
834     int r;
835
836     __ms_va_start( ap, format );
837     r = MSVCRT_vsnprintf( str, num, format, ap );
838     __ms_va_end( ap );
839     return r;
840 }
841
842 /*********************************************************************
843  *              _scwprintf (MSVCRT.@)
844  */
845 int CDECL MSVCRT__scwprintf( const MSVCRT_wchar_t *format, ... )
846 {
847     __ms_va_list ap;
848     int r;
849
850     __ms_va_start( ap, format );
851     r = MSVCRT_vsnwprintf( NULL, INT_MAX, format, ap );
852     __ms_va_end( ap );
853     return r;
854 }
855
856 /*********************************************************************
857  *              swprintf (MSVCRT.@)
858  */
859 int CDECL MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
860 {
861     __ms_va_list ap;
862     int r;
863
864     __ms_va_start( ap, format );
865     r = MSVCRT_vsnwprintf( str, INT_MAX, format, ap );
866     __ms_va_end( ap );
867     return r;
868 }
869
870 /*********************************************************************
871  *              swprintf_s (MSVCRT.@)
872  */
873 int CDECL MSVCRT_swprintf_s(MSVCRT_wchar_t *str, MSVCRT_size_t numberOfElements,
874         const MSVCRT_wchar_t *format, ... )
875 {
876     __ms_va_list ap;
877     int r;
878
879     __ms_va_start(ap, format);
880     r = MSVCRT_vsnwprintf_s(str, numberOfElements, INT_MAX, format, ap);
881     __ms_va_end(ap);
882
883     return r;
884 }
885
886 /*********************************************************************
887  *              _vswprintf (MSVCRT.@)
888  */
889 int CDECL MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, __ms_va_list args )
890 {
891     return MSVCRT_vsnwprintf( str, INT_MAX, format, args );
892 }
893
894 /*********************************************************************
895  *              _vswprintf (MSVCRT.@)
896  */
897 int CDECL MSVCRT_vswprintf_l( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format,
898         MSVCRT__locale_t locale, __ms_va_list args )
899 {
900     return MSVCRT_vsnwprintf_l( str, INT_MAX, format, locale, args );
901 }
902
903 /*********************************************************************
904  *              _vscwprintf (MSVCRT.@)
905  */
906 int CDECL MSVCRT__vscwprintf( const MSVCRT_wchar_t *format, __ms_va_list args )
907 {
908     return MSVCRT_vsnwprintf( NULL, INT_MAX, format, args );
909 }
910
911 /*********************************************************************
912  *              _vscwprintf_l (MSVCRT.@)
913  */
914 int CDECL MSVCRT__vscwprintf_l( const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list args )
915 {
916     return MSVCRT_vsnwprintf_l( NULL, INT_MAX, format, locale, args );
917 }
918
919 /*********************************************************************
920  *              _vscwprintf_p_l (MSVCRT.@)
921  */
922 int CDECL MSVCRT__vscwprintf_p_l( const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, __ms_va_list args )
923 {
924     return MSVCRT_vswprintf_p_l( NULL, INT_MAX, format, locale, args );
925 }
926
927 /*********************************************************************
928  *              vswprintf_s (MSVCRT.@)
929  */
930 int CDECL MSVCRT_vswprintf_s(MSVCRT_wchar_t* str, MSVCRT_size_t numberOfElements,
931         const MSVCRT_wchar_t* format, __ms_va_list args)
932 {
933     return MSVCRT_vsnwprintf_s(str, numberOfElements, INT_MAX, format, args );
934 }
935
936 /*********************************************************************
937  *              _vswprintf_s_l (MSVCRT.@)
938  */
939 int CDECL MSVCRT_vswprintf_s_l(MSVCRT_wchar_t* str, MSVCRT_size_t numberOfElements,
940         const MSVCRT_wchar_t* format, MSVCRT__locale_t locale, __ms_va_list args)
941 {
942     return MSVCRT_vsnwprintf_s_l(str, numberOfElements, INT_MAX,
943             format, locale, args );
944 }
945
946 /*********************************************************************
947  *              _vsprintf_p_l (MSVCRT.@)
948  */
949 int CDECL MSVCRT_vsprintf_p_l(char *buffer, MSVCRT_size_t length, const char *format,
950         MSVCRT__locale_t locale, __ms_va_list args)
951 {
952     static const char nullbyte = '\0';
953     printf_arg args_ctx[MSVCRT__ARGMAX+1];
954     struct _str_ctx_a puts_ctx = {length, buffer};
955     int ret;
956
957     memset(args_ctx, 0, sizeof(args_ctx));
958
959     ret = create_positional_ctx_a(args_ctx, format, args);
960     if(ret < 0) {
961         MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
962         *MSVCRT__errno() = MSVCRT_EINVAL;
963         return ret;
964     } else if(ret == 0)
965         ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale, FALSE, TRUE,
966                 arg_clbk_valist, NULL, &args);
967     else
968         ret = pf_printf_a(puts_clbk_str_a, &puts_ctx, format, locale, TRUE, TRUE,
969                 arg_clbk_positional, args_ctx, NULL);
970
971     puts_clbk_str_a(&puts_ctx, 1, &nullbyte);
972     return ret;
973 }
974
975 /*********************************************************************
976  *              _vsprintf_p (MSVCRT.@)
977  */
978 int CDECL MSVCRT_vsprintf_p(char *buffer, MSVCRT_size_t length,
979         const char *format, __ms_va_list args)
980 {
981     return MSVCRT_vsprintf_p_l(buffer, length, format, NULL, args);
982 }
983
984 /*********************************************************************
985  *              _sprintf_p_l (MSVCRT.@)
986  */
987 int CDECL MSVCRT_sprintf_p_l(char *buffer, MSVCRT_size_t length,
988         const char *format, MSVCRT__locale_t locale, ...)
989 {
990     __ms_va_list valist;
991     int r;
992
993     __ms_va_start(valist, locale);
994     r = MSVCRT_vsprintf_p_l(buffer, length, format, locale, valist);
995     __ms_va_end(valist);
996
997     return r;
998 }
999
1000 /*********************************************************************
1001  *              _swprintf_p_l (MSVCRT.@)
1002  */
1003 int CDECL MSVCRT_swprintf_p_l(MSVCRT_wchar_t *buffer, MSVCRT_size_t length,
1004         const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, ...)
1005 {
1006     __ms_va_list valist;
1007     int r;
1008
1009     __ms_va_start(valist, locale);
1010     r = MSVCRT_vswprintf_p_l(buffer, length, format, locale, valist);
1011     __ms_va_end(valist);
1012
1013     return r;
1014 }
1015
1016 /*********************************************************************
1017  *              wcscoll (MSVCRT.@)
1018  */
1019 int CDECL MSVCRT_wcscoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
1020 {
1021     return CompareStringW(get_locinfo()->lc_handle[MSVCRT_LC_COLLATE],
1022             0, str1, -1, str2, -1)-CSTR_EQUAL;
1023 }
1024
1025 /*********************************************************************
1026  *              wcspbrk (MSVCRT.@)
1027  */
1028 MSVCRT_wchar_t* CDECL MSVCRT_wcspbrk( const MSVCRT_wchar_t* str, const MSVCRT_wchar_t* accept )
1029 {
1030     const MSVCRT_wchar_t* p;
1031
1032     while (*str)
1033     {
1034         for (p = accept; *p; p++) if (*p == *str) return (MSVCRT_wchar_t*)str;
1035         str++;
1036     }
1037     return NULL;
1038 }
1039
1040 /*********************************************************************
1041  *              wcstok_s  (MSVCRT.@)
1042  */
1043 MSVCRT_wchar_t * CDECL wcstok_s( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim,
1044                                  MSVCRT_wchar_t **next_token )
1045 {
1046     MSVCRT_wchar_t *ret;
1047
1048     if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL;
1049     if (!MSVCRT_CHECK_PMT(next_token != NULL)) return NULL;
1050     if (!MSVCRT_CHECK_PMT(str != NULL || *next_token != NULL)) return NULL;
1051
1052     if (!str) str = *next_token;
1053
1054     while (*str && strchrW( delim, *str )) str++;
1055     if (!*str) return NULL;
1056     ret = str++;
1057     while (*str && !strchrW( delim, *str )) str++;
1058     if (*str) *str++ = 0;
1059     *next_token = str;
1060     return ret;
1061 }
1062
1063 /*********************************************************************
1064  *              wcstok  (MSVCRT.@)
1065  */
1066 MSVCRT_wchar_t * CDECL MSVCRT_wcstok( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim )
1067 {
1068     return wcstok_s(str, delim, &msvcrt_get_thread_data()->wcstok_next);
1069 }
1070
1071 /*********************************************************************
1072  *              wctob (MSVCRT.@)
1073  */
1074 INT CDECL MSVCRT_wctob( MSVCRT_wint_t wchar )
1075 {
1076     char out;
1077     BOOL error;
1078     UINT codepage = get_locinfo()->lc_codepage;
1079
1080     if(!codepage) {
1081         if (wchar < 0xff)
1082             return (signed char)wchar;
1083         else
1084             return MSVCRT_EOF;
1085     } else if(WideCharToMultiByte( codepage, 0, &wchar, 1, &out, 1, NULL, &error ) && !error)
1086         return (INT)out;
1087     return MSVCRT_EOF;
1088 }
1089
1090 /*********************************************************************
1091  *              wctomb (MSVCRT.@)
1092  */
1093 INT CDECL MSVCRT_wctomb( char *dst, MSVCRT_wchar_t ch )
1094 {
1095     BOOL error;
1096     INT size;
1097
1098     size = WideCharToMultiByte(get_locinfo()->lc_codepage, 0, &ch, 1, dst, dst ? 6 : 0, NULL, &error);
1099     if(!size || error) {
1100         *MSVCRT__errno() = MSVCRT_EINVAL;
1101         return MSVCRT_EOF;
1102     }
1103     return size;
1104 }
1105
1106 /*********************************************************************
1107  *              wcrtomb (MSVCRT.@)
1108  */
1109 MSVCRT_size_t CDECL MSVCRT_wcrtomb( char *dst, MSVCRT_wchar_t ch, MSVCRT_mbstate_t *s)
1110 {
1111     if(s)
1112         *s = 0;
1113     return MSVCRT_wctomb(dst, ch);
1114 }
1115
1116 /*********************************************************************
1117  *              iswalnum (MSVCRT.@)
1118  */
1119 INT CDECL MSVCRT_iswalnum( MSVCRT_wchar_t wc )
1120 {
1121     return isalnumW( wc );
1122 }
1123
1124 /*********************************************************************
1125  *              iswalpha (MSVCRT.@)
1126  */
1127 INT CDECL MSVCRT_iswalpha( MSVCRT_wchar_t wc )
1128 {
1129     return isalphaW( wc );
1130 }
1131
1132 /*********************************************************************
1133  *              iswalpha_l (MSVCRT.@)
1134  */
1135 INT CDECL MSVCRT__iswalpha_l( MSVCRT_wchar_t wc, MSVCRT__locale_t locale )
1136 {
1137     return isalphaW( wc );
1138 }
1139
1140 /*********************************************************************
1141  *              iswcntrl (MSVCRT.@)
1142  */
1143 INT CDECL MSVCRT_iswcntrl( MSVCRT_wchar_t wc )
1144 {
1145     return iscntrlW( wc );
1146 }
1147
1148 /*********************************************************************
1149  *              iswdigit (MSVCRT.@)
1150  */
1151 INT CDECL MSVCRT_iswdigit( MSVCRT_wchar_t wc )
1152 {
1153     return isdigitW( wc );
1154 }
1155
1156 /*********************************************************************
1157  *              _iswdigit_l (MSVCRT.@)
1158  */
1159 INT CDECL MSVCRT__iswdigit_l( MSVCRT_wchar_t wc, MSVCRT__locale_t locale )
1160 {
1161     return isdigitW( wc );
1162 }
1163
1164 /*********************************************************************
1165  *              iswgraph (MSVCRT.@)
1166  */
1167 INT CDECL MSVCRT_iswgraph( MSVCRT_wchar_t wc )
1168 {
1169     return isgraphW( wc );
1170 }
1171
1172 /*********************************************************************
1173  *              iswlower (MSVCRT.@)
1174  */
1175 INT CDECL MSVCRT_iswlower( MSVCRT_wchar_t wc )
1176 {
1177     return islowerW( wc );
1178 }
1179
1180 /*********************************************************************
1181  *              iswprint (MSVCRT.@)
1182  */
1183 INT CDECL MSVCRT_iswprint( MSVCRT_wchar_t wc )
1184 {
1185     return isprintW( wc );
1186 }
1187
1188 /*********************************************************************
1189  *              iswpunct (MSVCRT.@)
1190  */
1191 INT CDECL MSVCRT_iswpunct( MSVCRT_wchar_t wc )
1192 {
1193     return ispunctW( wc );
1194 }
1195
1196 /*********************************************************************
1197  *              iswspace (MSVCRT.@)
1198  */
1199 INT CDECL MSVCRT_iswspace( MSVCRT_wchar_t wc )
1200 {
1201     return isspaceW( wc );
1202 }
1203
1204 /*********************************************************************
1205  *              iswupper (MSVCRT.@)
1206  */
1207 INT CDECL MSVCRT_iswupper( MSVCRT_wchar_t wc )
1208 {
1209     return isupperW( wc );
1210 }
1211
1212 /*********************************************************************
1213  *              iswxdigit (MSVCRT.@)
1214  */
1215 INT CDECL MSVCRT_iswxdigit( MSVCRT_wchar_t wc )
1216 {
1217     return isxdigitW( wc );
1218 }
1219
1220 /*********************************************************************
1221  *              wcscpy_s (MSVCRT.@)
1222  */
1223 INT CDECL MSVCRT_wcscpy_s( MSVCRT_wchar_t* wcDest, MSVCRT_size_t numElement, const  MSVCRT_wchar_t *wcSrc)
1224 {
1225     MSVCRT_size_t size = 0;
1226
1227     if(!wcDest || !numElement)
1228         return MSVCRT_EINVAL;
1229
1230     wcDest[0] = 0;
1231
1232     if(!wcSrc)
1233     {
1234         return MSVCRT_EINVAL;
1235     }
1236
1237     size = strlenW(wcSrc) + 1;
1238
1239     if(size > numElement)
1240     {
1241         return MSVCRT_ERANGE;
1242     }
1243
1244     memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
1245
1246     return 0;
1247 }
1248
1249 /******************************************************************
1250  *              wcsncpy_s (MSVCRT.@)
1251  */
1252 INT CDECL MSVCRT_wcsncpy_s( MSVCRT_wchar_t* wcDest, MSVCRT_size_t numElement, const MSVCRT_wchar_t *wcSrc,
1253                             MSVCRT_size_t count )
1254 {
1255     WCHAR *p = wcDest;
1256     BOOL truncate = (count == MSVCRT__TRUNCATE);
1257
1258     if(!wcDest && !numElement && !count)
1259         return 0;
1260
1261     if (!wcDest || !numElement)
1262         return MSVCRT_EINVAL;
1263
1264     if (!wcSrc)
1265     {
1266         *wcDest = 0;
1267         return count ? MSVCRT_EINVAL : 0;
1268     }
1269
1270     while (numElement && count && *wcSrc)
1271     {
1272         *p++ = *wcSrc++;
1273         numElement--;
1274         count--;
1275     }
1276     if (!numElement && truncate)
1277     {
1278         *(p-1) = 0;
1279         return MSVCRT_STRUNCATE;
1280     }
1281     else if (!numElement)
1282     {
1283         *wcDest = 0;
1284         return MSVCRT_ERANGE;
1285     }
1286
1287     *p = 0;
1288     return 0;
1289 }
1290
1291 /******************************************************************
1292  *              wcscat_s (MSVCRT.@)
1293  *
1294  */
1295 INT CDECL MSVCRT_wcscat_s(MSVCRT_wchar_t* dst, MSVCRT_size_t elem, const MSVCRT_wchar_t* src)
1296 {
1297     MSVCRT_wchar_t* ptr = dst;
1298
1299     if (!dst || elem == 0) return MSVCRT_EINVAL;
1300     if (!src)
1301     {
1302         dst[0] = '\0';
1303         return MSVCRT_EINVAL;
1304     }
1305
1306     /* seek to end of dst string (or elem if no end of string is found */
1307     while (ptr < dst + elem && *ptr != '\0') ptr++;
1308     while (ptr < dst + elem)
1309     {
1310         if ((*ptr++ = *src++) == '\0') return 0;
1311     }
1312     /* not enough space */
1313     dst[0] = '\0';
1314     return MSVCRT_ERANGE;
1315 }
1316
1317 /*********************************************************************
1318  *  wcsncat_s (MSVCRT.@)
1319  *
1320  */
1321 INT CDECL MSVCRT_wcsncat_s(MSVCRT_wchar_t *dst, MSVCRT_size_t elem,
1322         const MSVCRT_wchar_t *src, MSVCRT_size_t count)
1323 {
1324     MSVCRT_size_t srclen;
1325     MSVCRT_wchar_t dststart;
1326     INT ret = 0;
1327
1328     if (!MSVCRT_CHECK_PMT(dst != NULL)) return MSVCRT_EINVAL;
1329     if (!MSVCRT_CHECK_PMT(elem > 0)) return MSVCRT_EINVAL;
1330     if (!MSVCRT_CHECK_PMT(src != NULL || count == 0)) return MSVCRT_EINVAL;
1331
1332     if (count == 0)
1333         return 0;
1334
1335     for (dststart = 0; dststart < elem; dststart++)
1336     {
1337         if (dst[dststart] == '\0')
1338             break;
1339     }
1340     if (dststart == elem)
1341     {
1342         MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n", MSVCRT_EINVAL);
1343         return MSVCRT_EINVAL;
1344     }
1345
1346     if (count == MSVCRT__TRUNCATE)
1347     {
1348         srclen = strlenW(src);
1349         if (srclen >= (elem - dststart))
1350         {
1351             srclen = elem - dststart - 1;
1352             ret = MSVCRT_STRUNCATE;
1353         }
1354     }
1355     else
1356         srclen = min(strlenW(src), count);
1357     if (srclen < (elem - dststart))
1358     {
1359         memcpy(&dst[dststart], src, srclen*sizeof(MSVCRT_wchar_t));
1360         dst[dststart+srclen] = '\0';
1361         return ret;
1362     }
1363     MSVCRT_INVALID_PMT("dst[elem] is too small", MSVCRT_ERANGE);
1364     dst[0] = '\0';
1365     return MSVCRT_ERANGE;
1366 }
1367
1368 /*********************************************************************
1369  *  _wcstoi64_l (MSVCRT.@)
1370  *
1371  * FIXME: locale parameter is ignored
1372  */
1373 __int64 CDECL MSVCRT__wcstoi64_l(const MSVCRT_wchar_t *nptr,
1374         MSVCRT_wchar_t **endptr, int base, MSVCRT__locale_t locale)
1375 {
1376     BOOL negative = FALSE;
1377     __int64 ret = 0;
1378
1379     TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
1380
1381     if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1382     if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1383     if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1384
1385     while(isspaceW(*nptr)) nptr++;
1386
1387     if(*nptr == '-') {
1388         negative = TRUE;
1389         nptr++;
1390     } else if(*nptr == '+')
1391         nptr++;
1392
1393     if((base==0 || base==16) && *nptr=='0' && tolowerW(*(nptr+1))=='x') {
1394         base = 16;
1395         nptr += 2;
1396     }
1397
1398     if(base == 0) {
1399         if(*nptr=='0')
1400             base = 8;
1401         else
1402             base = 10;
1403     }
1404
1405     while(*nptr) {
1406         MSVCRT_wchar_t cur = tolowerW(*nptr);
1407         int v;
1408
1409         if(isdigitW(cur)) {
1410             if(cur >= '0'+base)
1411                 break;
1412             v = cur-'0';
1413         } else {
1414             if(cur<'a' || cur>='a'+base-10)
1415                 break;
1416             v = cur-'a'+10;
1417         }
1418
1419         if(negative)
1420             v = -v;
1421
1422         nptr++;
1423
1424         if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
1425             ret = MSVCRT_I64_MAX;
1426             *MSVCRT__errno() = MSVCRT_ERANGE;
1427         } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
1428             ret = MSVCRT_I64_MIN;
1429             *MSVCRT__errno() = MSVCRT_ERANGE;
1430         } else
1431             ret = ret*base + v;
1432     }
1433
1434     if(endptr)
1435         *endptr = (MSVCRT_wchar_t*)nptr;
1436
1437     return ret;
1438 }
1439
1440 /*********************************************************************
1441  *  _wcstoi64 (MSVCRT.@)
1442  */
1443 __int64 CDECL MSVCRT__wcstoi64(const MSVCRT_wchar_t *nptr,
1444         MSVCRT_wchar_t **endptr, int base)
1445 {
1446     return MSVCRT__wcstoi64_l(nptr, endptr, base, NULL);
1447 }
1448
1449 /*********************************************************************
1450  *  _wtoi_l (MSVCRT.@)
1451  */
1452 int MSVCRT__wtoi_l(const MSVCRT_wchar_t *str, MSVCRT__locale_t locale)
1453 {
1454     __int64 ret = MSVCRT__wcstoi64_l(str, NULL, 10, locale);
1455
1456     if(ret > INT_MAX) {
1457         ret = INT_MAX;
1458         *MSVCRT__errno() = MSVCRT_ERANGE;
1459     } else if(ret < INT_MIN) {
1460         ret = INT_MIN;
1461         *MSVCRT__errno() = MSVCRT_ERANGE;
1462     }
1463     return ret;
1464 }
1465
1466 /*********************************************************************
1467  *  _wcstoui64_l (MSVCRT.@)
1468  *
1469  * FIXME: locale parameter is ignored
1470  */
1471 unsigned __int64 CDECL MSVCRT__wcstoui64_l(const MSVCRT_wchar_t *nptr,
1472         MSVCRT_wchar_t **endptr, int base, MSVCRT__locale_t locale)
1473 {
1474     BOOL negative = FALSE;
1475     unsigned __int64 ret = 0;
1476
1477     TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
1478
1479     if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1480     if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1481     if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1482
1483     while(isspaceW(*nptr)) nptr++;
1484
1485     if(*nptr == '-') {
1486         negative = TRUE;
1487         nptr++;
1488     } else if(*nptr == '+')
1489         nptr++;
1490
1491     if((base==0 || base==16) && *nptr=='0' && tolowerW(*(nptr+1))=='x') {
1492         base = 16;
1493         nptr += 2;
1494     }
1495
1496     if(base == 0) {
1497         if(*nptr=='0')
1498             base = 8;
1499         else
1500             base = 10;
1501     }
1502
1503     while(*nptr) {
1504         MSVCRT_wchar_t cur = tolowerW(*nptr);
1505         int v;
1506
1507         if(isdigitW(cur)) {
1508             if(cur >= '0'+base)
1509                 break;
1510             v = *nptr-'0';
1511         } else {
1512             if(cur<'a' || cur>='a'+base-10)
1513                 break;
1514             v = cur-'a'+10;
1515         }
1516
1517         nptr++;
1518
1519         if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1520             ret = MSVCRT_UI64_MAX;
1521             *MSVCRT__errno() = MSVCRT_ERANGE;
1522         } else
1523             ret = ret*base + v;
1524     }
1525
1526     if(endptr)
1527         *endptr = (MSVCRT_wchar_t*)nptr;
1528
1529     return negative ? -ret : ret;
1530 }
1531
1532 /*********************************************************************
1533  *  _wcstoui64 (MSVCRT.@)
1534  */
1535 unsigned __int64 CDECL MSVCRT__wcstoui64(const MSVCRT_wchar_t *nptr,
1536         MSVCRT_wchar_t **endptr, int base)
1537 {
1538     return MSVCRT__wcstoui64_l(nptr, endptr, base, NULL);
1539 }
1540
1541 /******************************************************************
1542  *  wcsnlen (MSVCRT.@)
1543  */
1544 MSVCRT_size_t CDECL MSVCRT_wcsnlen(const MSVCRT_wchar_t *s, MSVCRT_size_t maxlen)
1545 {
1546     MSVCRT_size_t i;
1547
1548     for (i = 0; i < maxlen; i++)
1549         if (!s[i]) break;
1550     return i;
1551 }
1552
1553 /*********************************************************************
1554  *              _towupper_l (MSVCRT.@)
1555  */
1556 int CDECL MSVCRT__towupper_l(MSVCRT_wint_t c, MSVCRT__locale_t locale)
1557 {
1558     return toupperW(c);
1559 }
1560
1561 /*********************************************************************
1562  *              _towlower_l (MSVCRT.@)
1563  */
1564 int CDECL MSVCRT__towlower_l(MSVCRT_wint_t c, MSVCRT__locale_t locale)
1565 {
1566     return tolowerW(c);
1567 }