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