kernel32: Add some parameter checking to FileTimeToDosDateTime.
[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 "wine/unicode.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
34
35
36 /*********************************************************************
37  *              _wcsdup (MSVCRT.@)
38  */
39 MSVCRT_wchar_t* CDECL _wcsdup( const MSVCRT_wchar_t* str )
40 {
41   MSVCRT_wchar_t* ret = NULL;
42   if (str)
43   {
44     int size = (strlenW(str) + 1) * sizeof(MSVCRT_wchar_t);
45     ret = MSVCRT_malloc( size );
46     if (ret) memcpy( ret, str, size );
47   }
48   return ret;
49 }
50
51 /*********************************************************************
52  *              _wcsicoll (MSVCRT.@)
53  */
54 INT CDECL _wcsicoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
55 {
56   /* FIXME: handle collates */
57   return strcmpiW( str1, str2 );
58 }
59
60 /*********************************************************************
61  *              _wcsnicoll (MSVCRT.@)
62  */
63 INT CDECL _wcsnicoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2, MSVCRT_size_t count )
64 {
65   /* FIXME: handle collates */
66   return strncmpiW( str1, str2, count );
67 }
68
69 /*********************************************************************
70  *              _wcsnset (MSVCRT.@)
71  */
72 MSVCRT_wchar_t* CDECL MSVCRT__wcsnset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c, MSVCRT_size_t n )
73 {
74   MSVCRT_wchar_t* ret = str;
75   while ((n-- > 0) && *str) *str++ = c;
76   return ret;
77 }
78
79 /*********************************************************************
80  *              _wcsrev (MSVCRT.@)
81  */
82 MSVCRT_wchar_t* CDECL _wcsrev( MSVCRT_wchar_t* str )
83 {
84   MSVCRT_wchar_t* ret = str;
85   MSVCRT_wchar_t* end = str + strlenW(str) - 1;
86   while (end > str)
87   {
88     MSVCRT_wchar_t t = *end;
89     *end--  = *str;
90     *str++  = t;
91   }
92   return ret;
93 }
94
95 /*********************************************************************
96  *              _wcsset (MSVCRT.@)
97  */
98 MSVCRT_wchar_t* CDECL _wcsset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c )
99 {
100   MSVCRT_wchar_t* ret = str;
101   while (*str) *str++ = c;
102   return ret;
103 }
104
105 /******************************************************************
106  *              _wcsupr_s_l (MSVCRT.@)
107  */
108 int CDECL MSVCRT__wcsupr_s_l( MSVCRT_wchar_t* str, MSVCRT_size_t n,
109    MSVCRT__locale_t locale )
110 {
111   MSVCRT_wchar_t* ptr = str;
112
113   if (!str || !n)
114   {
115     if (str) *str = '\0';
116     *MSVCRT__errno() = MSVCRT_EINVAL;
117     return MSVCRT_EINVAL;
118   }
119
120   while (n--)
121   {
122     if (!*ptr) return 0;
123     /* FIXME: add locale support */
124     *ptr = toupperW(*ptr);
125     ptr++;
126   }
127
128   /* MSDN claims that the function should return and set errno to
129    * ERANGE, which doesn't seem to be true based on the tests. */
130   *str = '\0';
131   *MSVCRT__errno() = MSVCRT_EINVAL;
132   return MSVCRT_EINVAL;
133 }
134
135 /******************************************************************
136  *              _wcsupr_s (MSVCRT.@)
137  *
138  */
139 INT CDECL MSVCRT__wcsupr_s( MSVCRT_wchar_t* str, MSVCRT_size_t n )
140 {
141   return MSVCRT__wcsupr_s_l( str, n, NULL );
142 }
143
144 /******************************************************************
145  *              _wcslwr_s (MSVCRT.@)
146  */
147 int CDECL MSVCRT__wcslwr_s( MSVCRT_wchar_t* str, MSVCRT_size_t n )
148 {
149   MSVCRT_wchar_t* ptr = str;
150
151   if (!str || !n)
152   {
153     if (str) *str = '\0';
154     *MSVCRT__errno() = MSVCRT_EINVAL;
155     return MSVCRT_EINVAL;
156   }
157
158   while (n--)
159   {
160     if (!*ptr) return 0;
161     *ptr = tolowerW(*ptr);
162     ptr++;
163   }
164
165   /* MSDN claims that the function should return and set errno to
166    * ERANGE, which doesn't seem to be true based on the tests. */
167   *str = '\0';
168   *MSVCRT__errno() = MSVCRT_EINVAL;
169   return MSVCRT_EINVAL;
170 }
171
172 /*********************************************************************
173  * _wcstod_l - not exported in native msvcrt
174  */
175 double CDECL MSVCRT__wcstod_l(const MSVCRT_wchar_t* str, MSVCRT_wchar_t** end,
176         MSVCRT__locale_t locale)
177 {
178     unsigned __int64 d=0, hlp;
179     unsigned fpcontrol;
180     int exp=0, sign=1;
181     const MSVCRT_wchar_t *p;
182     double ret;
183     BOOL found_digit = FALSE;
184
185     if (!MSVCRT_CHECK_PMT(str != NULL)) {
186         *MSVCRT__errno() = MSVCRT_EINVAL;
187         return 0;
188     }
189
190     if(!locale)
191         locale = get_locale();
192
193     p = str;
194     while(isspaceW(*p))
195         p++;
196
197     if(*p == '-') {
198         sign = -1;
199         p++;
200     } else  if(*p == '+')
201         p++;
202
203     while(isdigitW(*p)) {
204         found_digit = TRUE;
205         hlp = d*10+*(p++)-'0';
206         if(d>MSVCRT_UI64_MAX/10 || hlp<d) {
207             exp++;
208             break;
209         } else
210             d = hlp;
211     }
212     while(isdigitW(*p)) {
213         exp++;
214         p++;
215     }
216     if(*p == *locale->locinfo->lconv->decimal_point)
217         p++;
218
219     while(isdigitW(*p)) {
220         found_digit = TRUE;
221         hlp = d*10+*(p++)-'0';
222         if(d>MSVCRT_UI64_MAX/10 || hlp<d)
223             break;
224
225         d = hlp;
226         exp--;
227     }
228     while(isdigitW(*p))
229         p++;
230
231     if(!found_digit) {
232         if(end)
233             *end = (MSVCRT_wchar_t*)str;
234         return 0.0;
235     }
236
237     if(*p=='e' || *p=='E' || *p=='d' || *p=='D') {
238         int e=0, s=1;
239
240         p++;
241         if(*p == '-') {
242             s = -1;
243             p++;
244         } else if(*p == '+')
245             p++;
246
247         if(isdigitW(*p)) {
248             while(isdigitW(*p)) {
249                 if(e>INT_MAX/10 || (e=e*10+*p-'0')<0)
250                     e = INT_MAX;
251                 p++;
252             }
253             e *= s;
254
255             if(exp<0 && e<0 && exp+e>=0) exp = INT_MIN;
256             else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
257             else exp += e;
258         } else {
259             if(*p=='-' || *p=='+')
260                 p--;
261             p--;
262         }
263     }
264
265     fpcontrol = _control87(0, 0);
266     _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE
267             |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff);
268
269     if(exp>0)
270         ret = (double)sign*d*pow(10, exp);
271     else
272         ret = (double)sign*d/pow(10, -exp);
273
274     _control87(fpcontrol, 0xffffffff);
275
276     if((d && ret==0.0) || isinf(ret))
277         *MSVCRT__errno() = MSVCRT_ERANGE;
278
279     if(end)
280         *end = (MSVCRT_wchar_t*)p;
281
282     return ret;
283 }
284
285 /*********************************************************************
286  *              _wcstombs_l (MSVCRT.@)
287  */
288 MSVCRT_size_t CDECL MSVCRT__wcstombs_l(char *mbstr, const MSVCRT_wchar_t *wcstr,
289         MSVCRT_size_t count, MSVCRT__locale_t locale)
290 {
291     char default_char = '\0';
292     MSVCRT_size_t tmp = 0;
293     BOOL used_default;
294
295     if(!locale)
296         locale = get_locale();
297
298     if(!mbstr)
299         return WideCharToMultiByte(locale->locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
300                 wcstr, -1, NULL, 0, &default_char, &used_default)-1;
301
302     while(*wcstr) {
303         char buf[3];
304         MSVCRT_size_t i, size;
305
306         size = WideCharToMultiByte(locale->locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
307                 wcstr, 1, buf, 3, &default_char, &used_default);
308         if(used_default)
309             return -1;
310         if(tmp+size > count)
311             return tmp;
312
313         for(i=0; i<size; i++)
314             mbstr[tmp++] = buf[i];
315         wcstr++;
316     }
317
318     if(tmp < count)
319         mbstr[tmp] = '\0';
320     return tmp;
321 }
322
323 /*********************************************************************
324  *              wcstombs (MSVCRT.@)
325  */
326 MSVCRT_size_t CDECL MSVCRT_wcstombs(char *mbstr, const MSVCRT_wchar_t *wcstr,
327         MSVCRT_size_t count)
328 {
329     return MSVCRT__wcstombs_l(mbstr, wcstr, count, NULL);
330 }
331
332 /*********************************************************************
333  *              _wcstombs_s_l (MSVCRT.@)
334  */
335 MSVCRT_size_t CDECL MSVCRT__wcstombs_s_l(MSVCRT_size_t *ret, char *mbstr,
336         MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr,
337         MSVCRT_size_t count, MSVCRT__locale_t locale)
338 {
339     MSVCRT_size_t conv;
340
341     if(!mbstr && !size) {
342         conv = MSVCRT__wcstombs_l(NULL, wcstr, 0, locale);
343         if(ret)
344             *ret = conv;
345         return 0;
346     }
347
348     if (!MSVCRT_CHECK_PMT(wcstr != NULL) || !MSVCRT_CHECK_PMT(mbstr != NULL)) {
349         if(mbstr && size)
350             mbstr[0] = '\0';
351         *MSVCRT__errno() = MSVCRT_EINVAL;
352         return MSVCRT_EINVAL;
353     }
354
355     if(count==MSVCRT__TRUNCATE || size<count)
356         conv = size;
357     else
358         conv = count;
359
360     conv = MSVCRT__wcstombs_l(mbstr, wcstr, conv, locale);
361     if(conv<size)
362         mbstr[conv++] = '\0';
363     else if(conv==size && (count==MSVCRT__TRUNCATE || mbstr[conv-1]=='\0'))
364         mbstr[conv-1] = '\0';
365     else {
366         MSVCRT_INVALID_PMT("mbstr[size] is too small");
367         if(size)
368             mbstr[0] = '\0';
369         *MSVCRT__errno() = MSVCRT_ERANGE;
370         return MSVCRT_ERANGE;
371     }
372
373     if(ret)
374         *ret = conv;
375     return 0;
376 }
377
378 /*********************************************************************
379  *              wcstombs_s (MSVCRT.@)
380  */
381 MSVCRT_size_t CDECL MSVCRT_wcstombs_s(MSVCRT_size_t *ret, char *mbstr,
382         MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr, MSVCRT_size_t count)
383 {
384     return MSVCRT__wcstombs_s_l(ret, mbstr, size, wcstr, count, NULL);
385 }
386
387 /*********************************************************************
388  *              wcstod (MSVCRT.@)
389  */
390 double CDECL MSVCRT_wcstod(const MSVCRT_wchar_t* lpszStr, MSVCRT_wchar_t** end)
391 {
392     return MSVCRT__wcstod_l(lpszStr, end, NULL);
393 }
394
395 /*********************************************************************
396  *              _wtof (MSVCRT.@)
397  */
398 double CDECL MSVCRT__wtof(const MSVCRT_wchar_t *str)
399 {
400     return MSVCRT__wcstod_l(str, NULL, NULL);
401 }
402
403 /*********************************************************************
404  *              _wtof_l (MSVCRT.@)
405  */
406 double CDECL MSVCRT__wtof_l(const MSVCRT_wchar_t *str, MSVCRT__locale_t locale)
407 {
408     return MSVCRT__wcstod_l(str, NULL, locale);
409 }
410
411 typedef struct pf_flags_t
412 {
413     char Sign, LeftAlign, Alternate, PadZero;
414     int FieldLength, Precision;
415     char IntegerLength, IntegerDouble;
416     char WideString;
417     char Format;
418 } pf_flags;
419
420 static inline BOOL pf_is_auto_grow(pf_output *out)
421 {
422     return (out->unicode) ? !!out->grow.W : !!out->grow.A;
423 }
424
425 static inline int pf_check_auto_grow(pf_output *out, unsigned delta)
426 {
427     if (pf_is_auto_grow(out) && out->used + delta > out->len)
428     {
429         out->len = max(out->len * 2, out->used + delta);
430         if (out->unicode)
431         {
432             if (out->buf.W != out->grow.W)
433                 out->buf.W = MSVCRT_realloc(out->buf.W, out->len * sizeof(WCHAR));
434             else
435                 out->buf.W = MSVCRT_malloc(out->len * sizeof(WCHAR));
436             if (!out->buf.W) return -1;
437         }
438         else
439         {
440             if (out->buf.A != out->grow.A)
441                 out->buf.A = MSVCRT_realloc(out->buf.A, out->len * sizeof(char));
442             else
443                 out->buf.A = MSVCRT_malloc(out->len * sizeof(char));
444             if (!out->buf.A) return -1;
445         }
446     }
447     return 0;
448 }
449
450 /*
451  * writes a string of characters to the output
452  * returns -1 if the string doesn't fit in the output buffer
453  * return the length of the string if all characters were written
454  */
455 static inline int pf_output_stringW( pf_output *out, LPCWSTR str, int len )
456 {
457     int space;
458
459     if( len < 0 )
460         len = strlenW( str );
461     if( out->unicode )
462     {
463         LPWSTR p;
464
465         if(pf_check_auto_grow(out, len) == -1) return -1;
466         space = out->len - out->used;
467         p = out->buf.W + out->used;
468         if( space >= len )
469         {
470             if (out->buf.W) memcpy( p, str, len*sizeof(WCHAR) );
471             out->used += len;
472             return len;
473         }
474         if( space > 0 && out->buf.W )
475             memcpy( p, str, space*sizeof(WCHAR) );
476         out->used += len;
477     }
478     else
479     {
480         int n = WideCharToMultiByte( CP_ACP, 0, str, len, NULL, 0, NULL, NULL );
481         LPSTR p;
482
483         if(pf_check_auto_grow(out, n) == -1) return -1;
484         space = out->len - out->used;
485         p = out->buf.A + out->used;
486         if( space >= n )
487         {
488             if (out->buf.A) WideCharToMultiByte( CP_ACP, 0, str, len, p, n, NULL, NULL );
489             out->used += n;
490             return len;
491         }
492         if( space > 0 && out->buf.A )
493             WideCharToMultiByte( CP_ACP, 0, str, len, p, space, NULL, NULL );
494         out->used += n;
495     }
496     return -1;
497 }
498
499 static inline int pf_output_stringA( pf_output *out, LPCSTR str, int len )
500 {
501     int space;
502
503     if( len < 0 )
504         len = strlen( str );
505     if( !out->unicode )
506     {
507         LPSTR p;
508
509         if (pf_check_auto_grow(out, len) == -1) return -1;
510         p = out->buf.A + out->used;
511         space = out->len - out->used;
512         if( space >= len )
513         {
514             if (out->buf.A) memcpy( p, str, len );
515             out->used += len;
516             return len;
517         }
518         if( space > 0 && out->buf.A )
519             memcpy( p, str, space );
520         out->used += len;
521     }
522     else
523     {
524         int n = MultiByteToWideChar( CP_ACP, 0, str, len, NULL, 0 );
525         LPWSTR p;
526
527         if (pf_check_auto_grow(out, n) == -1) return -1;
528         p = out->buf.W + out->used;
529         space = out->len - out->used;
530         if( space >= n )
531         {
532             if (out->buf.W) MultiByteToWideChar( CP_ACP, 0, str, len, p, n );
533             out->used += n;
534             return len;
535         }
536         if( space > 0 && out->buf.W )
537             MultiByteToWideChar( CP_ACP, 0, str, len, p, space );
538         out->used += n;
539     }
540     return -1;
541 }
542
543 /* pf_fill: takes care of signs, alignment, zero and field padding */
544 static inline int pf_fill( pf_output *out, int len, pf_flags *flags, char left )
545 {
546     int i, r = 0;
547
548     if( flags->Sign && !( flags->Format == 'd' || flags->Format == 'i' ) )
549         flags->Sign = 0;
550
551     if( left && flags->Sign )
552     {
553         flags->FieldLength--;
554         if( flags->PadZero )
555             r = pf_output_stringA( out, &flags->Sign, 1 );
556     }
557
558     if( ( !left &&  flags->LeftAlign ) || 
559         (  left && !flags->LeftAlign ))
560     {
561         for( i=0; (i<(flags->FieldLength-len)) && (r>=0); i++ )
562         {
563             if( left && flags->PadZero )
564                 r = pf_output_stringA( out, "0", 1 );
565             else
566                 r = pf_output_stringA( out, " ", 1 );
567         }
568     }
569
570     if( left && flags->Sign && !flags->PadZero )
571         r = pf_output_stringA( out, &flags->Sign, 1 );
572
573     return r;
574 }
575
576 static inline int pf_output_format_W( pf_output *out, LPCWSTR str,
577                                       int len, pf_flags *flags )
578 {
579     int r = 0;
580
581     if( len < 0 )
582         len = strlenW( str );
583
584     if (flags->Precision >= 0 && flags->Precision < len)
585         len = flags->Precision;
586
587     r = pf_fill( out, len, flags, 1 );
588
589     if( r>=0 )
590         r = pf_output_stringW( out, str, len );
591
592     if( r>=0 )
593         r = pf_fill( out, len, flags, 0 );
594
595     return r;
596 }
597
598 static inline int pf_output_format_A( pf_output *out, LPCSTR str,
599                                       int len, pf_flags *flags )
600 {
601     int r = 0;
602
603     if( len < 0 )
604         len = strlen( str );
605
606     if (flags->Precision >= 0 && flags->Precision < len)
607         len = flags->Precision;
608
609     r = pf_fill( out, len, flags, 1 );
610
611     if( r>=0 )
612         r = pf_output_stringA( out, str, len );
613
614     if( r>=0 )
615         r = pf_fill( out, len, flags, 0 );
616
617     return r;
618 }
619
620 static int pf_handle_string_format( pf_output *out, const void* str, int len,
621                              pf_flags *flags, BOOL capital_letter)
622 {
623      if(str == NULL)  /* catch NULL pointer */
624         return pf_output_format_A( out, "(null)", -1, flags);
625
626      /* prefixes take priority over %c,%s vs. %C,%S, so we handle them first */
627     if(flags->WideString || flags->IntegerLength == 'l')
628         return pf_output_format_W( out, str, len, flags);
629     if(flags->IntegerLength == 'h')
630         return pf_output_format_A( out, str, len, flags);
631
632     /* %s,%c ->  chars in ansi functions & wchars in unicode
633      * %S,%C -> wchars in ansi functions &  chars in unicode */
634     if( capital_letter == out->unicode) /* either both TRUE or both FALSE */
635         return pf_output_format_A( out, str, len, flags);
636     else
637         return pf_output_format_W( out, str, len, flags);
638 }
639
640 static inline BOOL pf_is_integer_format( char fmt )
641 {
642     static const char float_fmts[] = "diouxX";
643     if (!fmt)
644         return FALSE;
645     return strchr( float_fmts, fmt ) ? TRUE : FALSE;
646 }
647
648 static inline BOOL pf_is_double_format( char fmt )
649 {
650     static const char float_fmts[] = "aeEfgG";
651     if (!fmt)
652         return FALSE;
653     return strchr( float_fmts, fmt ) ? TRUE : FALSE;
654 }
655
656 static inline BOOL pf_is_valid_format( char fmt )
657 {
658     static const char float_fmts[] = "acCdeEfgGinouxX";
659     if (!fmt)
660         return FALSE;
661     return strchr( float_fmts, fmt ) ? TRUE : FALSE;
662 }
663
664 static void pf_rebuild_format_string( char *p, pf_flags *flags )
665 {
666     *p++ = '%';
667     if( flags->Sign )
668         *p++ = flags->Sign;
669     if( flags->LeftAlign )
670         *p++ = flags->LeftAlign;
671     if( flags->Alternate )
672         *p++ = flags->Alternate;
673     if( flags->PadZero )
674         *p++ = flags->PadZero;
675     if( flags->FieldLength )
676     {
677         sprintf(p, "%d", flags->FieldLength);
678         p += strlen(p);
679     }
680     if( flags->Precision >= 0 )
681     {
682         sprintf(p, ".%d", flags->Precision);
683         p += strlen(p);
684     }
685     *p++ = flags->Format;
686     *p++ = 0;
687 }
688
689 /* pf_integer_conv:  prints x to buf, including alternate formats and
690    additional precision digits, but not field characters or the sign */
691 static void pf_integer_conv( char *buf, int buf_len, pf_flags *flags,
692                              LONGLONG x )
693 {
694     unsigned int base;
695     const char *digits;
696
697     int i, j, k;
698     char number[40], *tmp = number;
699
700     if( buf_len > sizeof number )
701         tmp = HeapAlloc( GetProcessHeap(), 0, buf_len );
702
703     base = 10;
704     if( flags->Format == 'o' )
705         base = 8;
706     else if( flags->Format == 'x' || flags->Format == 'X' )
707         base = 16;
708
709     if( flags->Format == 'X' )
710         digits = "0123456789ABCDEFX";
711     else
712         digits = "0123456789abcdefx";
713
714     if( x < 0 && ( flags->Format == 'd' || flags->Format == 'i' ) )
715     {
716         x = -x;
717         flags->Sign = '-';
718     }
719
720     /* Do conversion (backwards) */
721     i = 0;
722     if( x == 0 && flags->Precision )
723         tmp[i++] = '0';
724     else
725         while( x != 0 )
726         {
727             j = (ULONGLONG) x % base;
728             x = (ULONGLONG) x / base;
729             tmp[i++] = digits[j];
730         }
731     k = flags->Precision - i;
732     while( k-- > 0 )
733         tmp[i++] = '0';
734     if( flags->Alternate )
735     {
736         if( base == 16 )
737         {
738             tmp[i++] = digits[16];
739             tmp[i++] = '0';
740         }
741         else if( base == 8 && tmp[i-1] != '0' )
742             tmp[i++] = '0';
743     }
744
745     /* Reverse for buf */
746     j = 0;
747     while( i-- > 0 )
748         buf[j++] = tmp[i];
749     buf[j] = '\0';
750
751     /* Adjust precision so pf_fill won't truncate the number later */
752     flags->Precision = strlen( buf );
753
754     if( tmp != number )
755         HeapFree( GetProcessHeap(), 0, tmp );
756
757     return;
758 }
759
760 /* pf_fixup_exponent: convert a string containing a 2 digit exponent
761    to 3 digits, accounting for padding, in place. Needed to match
762    the native printf's which always use 3 digits. */
763 static void pf_fixup_exponent( char *buf )
764 {
765     char* tmp = buf;
766
767     while (tmp[0] && toupper(tmp[0]) != 'E')
768         tmp++;
769
770     if (tmp[0] && (tmp[1] == '+' || tmp[1] == '-') &&
771         isdigit(tmp[2]) && isdigit(tmp[3]))
772     {
773         char final;
774
775         if (isdigit(tmp[4]))
776             return; /* Exponent already 3 digits */
777
778         /* We have a 2 digit exponent. Prepend '0' to make it 3 */
779         tmp += 2;
780         final = tmp[2];
781         tmp[2] = tmp[1];
782         tmp[1] = tmp[0];
783         tmp[0] = '0';
784         if (final == '\0')
785         {
786             /* We didn't expand into trailing space, so this string isn't left
787              * justified. Terminate the string and strip a ' ' at the start of
788              * the string if there is one (as there may be if the string is
789              * right justified).
790              */
791             tmp[3] = '\0';
792             if (buf[0] == ' ')
793                 memmove(buf, buf + 1, (tmp - buf) + 3);
794         }
795         /* Otherwise, we expanded into trailing space -> nothing to do */
796     }
797 }
798
799 /*********************************************************************
800  *  pf_vsnprintf  (INTERNAL)
801  *
802  *  implements both A and W vsnprintf functions
803  */
804 int pf_vsnprintf( pf_output *out, const WCHAR *format,
805                   MSVCRT__locale_t locale, BOOL valid, __ms_va_list valist )
806 {
807     int r;
808     LPCWSTR q, p = format;
809     pf_flags flags;
810
811     if(!locale)
812         locale = get_locale();
813
814     TRACE("format is %s\n",debugstr_w(format));
815     while (*p)
816     {
817         q = strchrW( p, '%' );
818
819         /* there's no % characters left, output the rest of the string */
820         if( !q )
821         {
822             r = pf_output_stringW(out, p, -1);
823             if( r<0 )
824                 return r;
825             p += r;
826             continue;
827         }
828
829         /* there's characters before the %, output them */
830         if( q != p )
831         {
832             r = pf_output_stringW(out, p, q - p);
833             if( r<0 )
834                 return r;
835             p = q;
836         }
837
838         /* we must be at a % now, skip over it */
839         assert( *p == '%' );
840         p++;
841
842         /* output a single % character */
843         if( *p == '%' )
844         {
845             r = pf_output_stringW(out, p++, 1);
846             if( r<0 )
847                 return r;
848             continue;
849         }
850
851         /* parse the flags */
852         memset( &flags, 0, sizeof flags );
853         while (*p)
854         {
855             if( *p == '+' || *p == ' ' )
856             {
857                 if ( flags.Sign != '+' )
858                     flags.Sign = *p;
859             }
860             else if( *p == '-' )
861                 flags.LeftAlign = *p;
862             else if( *p == '0' )
863                 flags.PadZero = *p;
864             else if( *p == '#' )
865                 flags.Alternate = *p;
866             else
867                 break;
868             p++;
869         }
870
871         /* deal with the field width specifier */
872         flags.FieldLength = 0;
873         if( *p == '*' )
874         {
875             flags.FieldLength = va_arg( valist, int );
876             if (flags.FieldLength < 0)
877             {
878                 flags.LeftAlign = '-';
879                 flags.FieldLength = -flags.FieldLength;
880             }
881             p++;
882         }
883         else while( isdigit(*p) )
884         {
885             flags.FieldLength *= 10;
886             flags.FieldLength += *p++ - '0';
887         }
888
889         /* deal with precision */
890         flags.Precision = -1;
891         if( *p == '.' )
892         {
893             flags.Precision = 0;
894             p++;
895             if( *p == '*' )
896             {
897                 flags.Precision = va_arg( valist, int );
898                 p++;
899             }
900             else while( isdigit(*p) )
901             {
902                 flags.Precision *= 10;
903                 flags.Precision += *p++ - '0';
904             }
905         }
906
907         /* deal with integer width modifier */
908         while( *p )
909         {
910             if( *p == 'l' && *(p+1) == 'l' )
911             {
912                 flags.IntegerDouble++;
913                 p += 2;
914             }
915             else if( *p == 'h' || *p == 'l' || *p == 'L' )
916             {
917                 flags.IntegerLength = *p;
918                 p++;
919             }
920             else if( *p == 'I' )
921             {
922                 if( *(p+1) == '6' && *(p+2) == '4' )
923                 {
924                     flags.IntegerDouble++;
925                     p += 3;
926                 }
927                 else if( *(p+1) == '3' && *(p+2) == '2' )
928                     p += 3;
929                 else if( isdigit(*(p+1)) || *(p+1) == 0 )
930                     break;
931                 else
932                     p++;
933             }
934             else if( *p == 'w' )
935                 flags.WideString = *p++;
936             else if( *p == 'F' )
937                 p++; /* ignore */
938             else
939                 break;
940         }
941
942         flags.Format = *p;
943         r = 0;
944
945         if (flags.Format == '$')
946         {
947             FIXME("Positional parameters are not supported (%s)\n", wine_dbgstr_w(format));
948             return -1;
949         }
950         /* output a string */
951         if(  flags.Format == 's' || flags.Format == 'S' )
952             r = pf_handle_string_format( out, va_arg(valist, const void*), -1,
953                                          &flags, (flags.Format == 'S') );
954
955         /* output a single character */
956         else if( flags.Format == 'c' || flags.Format == 'C' )
957         {
958             INT ch = va_arg( valist, int );
959
960             r = pf_handle_string_format( out, &ch, 1, &flags, (flags.Format == 'C') );
961         }
962
963         /* output a pointer */
964         else if( flags.Format == 'p' )
965         {
966             char pointer[32];
967             void *ptr = va_arg( valist, void * );
968
969             flags.PadZero = 0;
970             if( flags.Alternate )
971                 sprintf(pointer, "0X%0*lX", 2 * (int)sizeof(ptr), (ULONG_PTR)ptr);
972             else
973                 sprintf(pointer, "%0*lX", 2 * (int)sizeof(ptr), (ULONG_PTR)ptr);
974             r = pf_output_format_A( out, pointer, -1, &flags );
975         }
976
977         /* deal with %n */
978         else if( flags.Format == 'n' )
979         {
980             int *x = va_arg(valist, int *);
981             *x = out->used;
982         }
983
984         /* deal with 64-bit integers */
985         else if( pf_is_integer_format( flags.Format ) && flags.IntegerDouble )
986         {
987             char number[40], *x = number;
988
989             /* Estimate largest possible required buffer size:
990                * Chooses the larger of the field or precision
991                * Includes extra bytes: 1 byte for null, 1 byte for sign,
992                  4 bytes for exponent, 2 bytes for alternate formats, 1 byte 
993                  for a decimal, and 1 byte for an additional float digit. */
994             int x_len = ((flags.FieldLength > flags.Precision) ? 
995                         flags.FieldLength : flags.Precision) + 10;
996
997             if( x_len >= sizeof number)
998                 x = HeapAlloc( GetProcessHeap(), 0, x_len );
999
1000             pf_integer_conv( x, x_len, &flags, va_arg(valist, LONGLONG) );
1001
1002             r = pf_output_format_A( out, x, -1, &flags );
1003             if( x != number )
1004                 HeapFree( GetProcessHeap(), 0, x );
1005         }
1006
1007         /* deal with integers and floats using libc's printf */
1008         else if( pf_is_valid_format( flags.Format ) )
1009         {
1010             char fmt[20], number[40], *x = number, *decimal_point;
1011
1012             /* Estimate largest possible required buffer size:
1013                * Chooses the larger of the field or precision
1014                * Includes extra bytes: 1 byte for null, 1 byte for sign,
1015                  4 bytes for exponent, 2 bytes for alternate formats, 1 byte 
1016                  for a decimal, and 1 byte for an additional float digit. */
1017             int x_len = ((flags.FieldLength > flags.Precision) ? 
1018                         flags.FieldLength : flags.Precision) + 10;
1019
1020             if( x_len >= sizeof number)
1021                 x = HeapAlloc( GetProcessHeap(), 0, x_len );
1022
1023             pf_rebuild_format_string( fmt, &flags );
1024
1025             if( pf_is_double_format( flags.Format ) )
1026             {
1027                 sprintf( x, fmt, va_arg(valist, double) );
1028                 if (toupper(flags.Format) == 'E' || toupper(flags.Format) == 'G')
1029                     pf_fixup_exponent( x );
1030             }
1031             else
1032                 sprintf( x, fmt, va_arg(valist, int) );
1033
1034             decimal_point = strchr(x, '.');
1035             if(decimal_point)
1036                 *decimal_point = *locale->locinfo->lconv->decimal_point;
1037
1038             r = pf_output_stringA( out, x, -1 );
1039             if( x != number )
1040                 HeapFree( GetProcessHeap(), 0, x );
1041             if(r < 0)
1042                 return r;
1043         }
1044         else
1045         {
1046             if( valid )
1047             {
1048                 MSVCRT__invalid_parameter( NULL, NULL, NULL, 0, 0 );
1049                 *MSVCRT__errno() = MSVCRT_EINVAL;
1050                 return -1;
1051             }
1052
1053             continue;
1054         }
1055
1056         if( r<0 )
1057             return r;
1058         p++;
1059     }
1060
1061     /* check we reached the end, and null terminate the string */
1062     assert( *p == 0 );
1063     pf_output_stringW( out, p, 1 );
1064
1065     return out->used - 1;
1066 }
1067
1068 /*********************************************************************
1069  * vsnprintf_internal (INTERNAL)
1070  */
1071 static inline int vsnprintf_internal( char *str, MSVCRT_size_t len, const char *format,
1072         MSVCRT__locale_t locale, BOOL valid, __ms_va_list valist )
1073 {
1074     DWORD sz;
1075     LPWSTR formatW = NULL;
1076     pf_output out;
1077     int r;
1078
1079     out.unicode = FALSE;
1080     out.buf.A = str;
1081     out.grow.A = NULL;
1082     out.used = 0;
1083     out.len = len;
1084
1085     sz = MultiByteToWideChar( CP_ACP, 0, format, -1, NULL, 0 );
1086     formatW = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
1087     MultiByteToWideChar( CP_ACP, 0, format, -1, formatW, sz );
1088
1089     r = pf_vsnprintf( &out, formatW, locale, valid, valist );
1090
1091     HeapFree( GetProcessHeap(), 0, formatW );
1092
1093     return r;
1094 }
1095
1096 /*********************************************************************
1097  *              _vsnprintf (MSVCRT.@)
1098  */
1099 int CDECL MSVCRT_vsnprintf( char *str, MSVCRT_size_t len,
1100                             const char *format, __ms_va_list valist )
1101 {
1102     return vsnprintf_internal(str, len, format, NULL, FALSE, valist);
1103 }
1104
1105 /*********************************************************************
1106 *               _vsnprintf_l (MSVCRT.@)
1107  */
1108 int CDECL MSVCRT_vsnprintf_l( char *str, MSVCRT_size_t len, const char *format,
1109                             MSVCRT__locale_t locale, __ms_va_list valist )
1110 {
1111     return vsnprintf_internal(str, len, format, locale, FALSE, valist);
1112 }
1113
1114 /*********************************************************************
1115  *              _vsnprintf_s_l (MSVCRT.@)
1116  */
1117 int CDECL MSVCRT_vsnprintf_s_l( char *str, MSVCRT_size_t sizeOfBuffer,
1118         MSVCRT_size_t count, const char *format,
1119         MSVCRT__locale_t locale, __ms_va_list valist )
1120 {
1121     int len, ret;
1122
1123     if(sizeOfBuffer<count+1 || count==-1)
1124         len = sizeOfBuffer;
1125     else
1126         len = count+1;
1127
1128     ret = vsnprintf_internal(str, len, format, locale, TRUE, valist);
1129
1130     if(ret<0 || ret==len) {
1131         if(count!=MSVCRT__TRUNCATE && count>sizeOfBuffer) {
1132             MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small");
1133             *MSVCRT__errno() = MSVCRT_ERANGE;
1134             memset(str, 0, sizeOfBuffer);
1135         } else
1136             str[len-1] = '\0';
1137
1138         return -1;
1139     }
1140
1141     return ret;
1142 }
1143
1144 /*********************************************************************
1145  *              _vsnprintf_s (MSVCRT.@)
1146  */
1147 int CDECL MSVCRT_vsnprintf_s( char *str, MSVCRT_size_t sizeOfBuffer,
1148         MSVCRT_size_t count, const char *format, __ms_va_list valist )
1149 {
1150     return MSVCRT_vsnprintf_s_l(str,sizeOfBuffer, count, format, NULL, valist);
1151 }
1152
1153 /*********************************************************************
1154  *              vsprintf (MSVCRT.@)
1155  */
1156 int CDECL MSVCRT_vsprintf( char *str, const char *format, __ms_va_list valist)
1157 {
1158     return MSVCRT_vsnprintf(str, INT_MAX, format, valist);
1159 }
1160
1161 /*********************************************************************
1162  *              vsprintf_s (MSVCRT.@)
1163  */
1164 int CDECL MSVCRT_vsprintf_s( char *str, MSVCRT_size_t num, const char *format, __ms_va_list valist)
1165 {
1166     return MSVCRT_vsnprintf(str, num, format, valist);
1167 }
1168
1169 /*********************************************************************
1170  *              _vscprintf (MSVCRT.@)
1171  */
1172 int CDECL _vscprintf( const char *format, __ms_va_list valist )
1173 {
1174     return MSVCRT_vsnprintf( NULL, INT_MAX, format, valist );
1175 }
1176
1177 /*********************************************************************
1178  *              _snprintf (MSVCRT.@)
1179  */
1180 int CDECL MSVCRT__snprintf(char *str, unsigned int len, const char *format, ...)
1181 {
1182     int retval;
1183     __ms_va_list valist;
1184     __ms_va_start(valist, format);
1185     retval = MSVCRT_vsnprintf(str, len, format, valist);
1186     __ms_va_end(valist);
1187     return retval;
1188 }
1189
1190 /*********************************************************************
1191  *              _snprintf_s (MSVCRT.@)
1192  */
1193 int CDECL MSVCRT__snprintf_s(char *str, unsigned int len, unsigned int count,
1194     const char *format, ...)
1195 {
1196     int retval;
1197     __ms_va_list valist;
1198     __ms_va_start(valist, format);
1199     retval = MSVCRT_vsnprintf_s_l(str, len, count, format, NULL, valist);
1200     __ms_va_end(valist);
1201     return retval;
1202 }
1203
1204 /*********************************************************************
1205  *              _scprintf (MSVCRT.@)
1206  */
1207 int CDECL MSVCRT__scprintf(const char *format, ...)
1208 {
1209     int retval;
1210     __ms_va_list valist;
1211     __ms_va_start(valist, format);
1212     retval = _vscprintf(format, valist);
1213     __ms_va_end(valist);
1214     return retval;
1215 }
1216
1217 /*********************************************************************
1218  * vsnwprintf_internal (INTERNAL)
1219  */
1220 static inline int vsnwprintf_internal(MSVCRT_wchar_t *str, MSVCRT_size_t len,
1221         const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, BOOL valid,
1222         __ms_va_list valist)
1223 {
1224     pf_output out;
1225
1226     out.unicode = TRUE;
1227     out.buf.W = str;
1228     out.grow.W = NULL;
1229     out.used = 0;
1230     out.len = len;
1231
1232     return pf_vsnprintf( &out, format, locale, valid, valist );
1233 }
1234
1235 /*********************************************************************
1236  *              _vsnwprintf (MSVCRT.@)
1237  */
1238 int CDECL MSVCRT_vsnwprintf(MSVCRT_wchar_t *str, MSVCRT_size_t len,
1239         const MSVCRT_wchar_t *format, __ms_va_list valist)
1240 {
1241     return vsnwprintf_internal(str, len, format, NULL, FALSE, valist);
1242 }
1243
1244 /*********************************************************************
1245  *              _vsnwprintf_l (MSVCRT.@)
1246  */
1247 int CDECL MSVCRT_vsnwprintf_l(MSVCRT_wchar_t *str, MSVCRT_size_t len,
1248         const MSVCRT_wchar_t *format, MSVCRT__locale_t locale,
1249         __ms_va_list valist)
1250 {
1251         return vsnwprintf_internal(str, len, format, locale, FALSE, valist);
1252 }
1253
1254 /*********************************************************************
1255  *              _vsnwprintf_s_l (MSVCRT.@)
1256  */
1257 int CDECL MSVCRT_vsnwprintf_s_l( MSVCRT_wchar_t *str, MSVCRT_size_t sizeOfBuffer,
1258         MSVCRT_size_t count, const MSVCRT_wchar_t *format,
1259         MSVCRT__locale_t locale, __ms_va_list valist)
1260 {
1261     int len, ret;
1262
1263     len = sizeOfBuffer;
1264     if(count!=-1 && len>count+1)
1265         len = count+1;
1266
1267     ret = vsnwprintf_internal(str, len, format, locale, TRUE, valist);
1268
1269     if(ret<0 || ret==len) {
1270         if(count!=MSVCRT__TRUNCATE && count>sizeOfBuffer) {
1271             MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small");
1272             *MSVCRT__errno() = MSVCRT_ERANGE;
1273             memset(str, 0, sizeOfBuffer*sizeof(MSVCRT_wchar_t));
1274         } else
1275             str[len-1] = '\0';
1276
1277         return -1;
1278     }
1279
1280     return ret;
1281 }
1282
1283 /*********************************************************************
1284  *              _vsnwprintf_s (MSVCRT.@)
1285  */
1286 int CDECL MSVCRT_vsnwprintf_s(MSVCRT_wchar_t *str, MSVCRT_size_t sizeOfBuffer,
1287         MSVCRT_size_t count, const MSVCRT_wchar_t *format, __ms_va_list valist)
1288 {
1289     return MSVCRT_vsnwprintf_s_l(str, sizeOfBuffer, count,
1290             format, NULL, valist);
1291 }
1292
1293 /*********************************************************************
1294  *              _snwprintf (MSVCRT.@)
1295  */
1296 int CDECL MSVCRT__snwprintf( MSVCRT_wchar_t *str, unsigned int len, const MSVCRT_wchar_t *format, ...)
1297 {
1298     int retval;
1299     __ms_va_list valist;
1300     __ms_va_start(valist, format);
1301     retval = MSVCRT_vsnwprintf(str, len, format, valist);
1302     __ms_va_end(valist);
1303     return retval;
1304 }
1305
1306 /*********************************************************************
1307  *              _snwprintf_s (MSVCRT.@)
1308  */
1309 int CDECL MSVCRT__snwprintf_s( MSVCRT_wchar_t *str, unsigned int len, unsigned int count,
1310     const MSVCRT_wchar_t *format, ...)
1311 {
1312     int retval;
1313     __ms_va_list valist;
1314     __ms_va_start(valist, format);
1315     retval = MSVCRT_vsnwprintf_s_l(str, len, count, format, NULL, valist);
1316     __ms_va_end(valist);
1317     return retval;
1318 }
1319
1320 /*********************************************************************
1321  *              sprintf (MSVCRT.@)
1322  */
1323 int CDECL MSVCRT_sprintf( char *str, const char *format, ... )
1324 {
1325     __ms_va_list ap;
1326     int r;
1327
1328     __ms_va_start( ap, format );
1329     r = MSVCRT_vsnprintf( str, INT_MAX, format, ap );
1330     __ms_va_end( ap );
1331     return r;
1332 }
1333
1334 /*********************************************************************
1335  *              sprintf_s (MSVCRT.@)
1336  */
1337 int CDECL MSVCRT_sprintf_s( char *str, MSVCRT_size_t num, const char *format, ... )
1338 {
1339     __ms_va_list ap;
1340     int r;
1341
1342     __ms_va_start( ap, format );
1343     r = MSVCRT_vsnprintf( str, num, format, ap );
1344     __ms_va_end( ap );
1345     return r;
1346 }
1347
1348 /*********************************************************************
1349  *              _scwprintf (MSVCRT.@)
1350  */
1351 int CDECL MSVCRT__scwprintf( const MSVCRT_wchar_t *format, ... )
1352 {
1353     __ms_va_list ap;
1354     int r;
1355
1356     __ms_va_start( ap, format );
1357     r = MSVCRT_vsnwprintf( NULL, INT_MAX, format, ap );
1358     __ms_va_end( ap );
1359     return r;
1360 }
1361
1362 /*********************************************************************
1363  *              swprintf (MSVCRT.@)
1364  */
1365 int CDECL MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
1366 {
1367     __ms_va_list ap;
1368     int r;
1369
1370     __ms_va_start( ap, format );
1371     r = MSVCRT_vsnwprintf( str, INT_MAX, format, ap );
1372     __ms_va_end( ap );
1373     return r;
1374 }
1375
1376 /*********************************************************************
1377  *              swprintf_s (MSVCRT.@)
1378  */
1379 int CDECL MSVCRT_swprintf_s(MSVCRT_wchar_t *str, MSVCRT_size_t numberOfElements,
1380         const MSVCRT_wchar_t *format, ... )
1381 {
1382     __ms_va_list ap;
1383     int r;
1384
1385     __ms_va_start(ap, format);
1386     r = MSVCRT_vsnwprintf_s(str, numberOfElements, INT_MAX, format, ap);
1387     __ms_va_end(ap);
1388
1389     return r;
1390 }
1391
1392 /*********************************************************************
1393  *              vswprintf (MSVCRT.@)
1394  */
1395 int CDECL MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, __ms_va_list args )
1396 {
1397     return MSVCRT_vsnwprintf( str, INT_MAX, format, args );
1398 }
1399
1400 /*********************************************************************
1401  *              _vscwprintf (MSVCRT.@)
1402  */
1403 int CDECL _vscwprintf( const MSVCRT_wchar_t *format, __ms_va_list args )
1404 {
1405     return MSVCRT_vsnwprintf( NULL, INT_MAX, format, args );
1406 }
1407
1408 /*********************************************************************
1409  *              vswprintf_s (MSVCRT.@)
1410  */
1411 int CDECL MSVCRT_vswprintf_s(MSVCRT_wchar_t* str, MSVCRT_size_t numberOfElements,
1412         const MSVCRT_wchar_t* format, __ms_va_list args)
1413 {
1414     return MSVCRT_vsnwprintf_s(str, numberOfElements, INT_MAX, format, args );
1415 }
1416
1417 /*********************************************************************
1418  *              _vswprintf_s_l (MSVCRT.@)
1419  */
1420 int CDECL MSVCRT_vswprintf_s_l(MSVCRT_wchar_t* str, MSVCRT_size_t numberOfElements,
1421         const MSVCRT_wchar_t* format, MSVCRT__locale_t locale, __ms_va_list args)
1422 {
1423     return MSVCRT_vsnwprintf_s_l(str, numberOfElements, INT_MAX,
1424             format, locale, args );
1425 }
1426
1427 /*********************************************************************
1428  *              wcscoll (MSVCRT.@)
1429  */
1430 int CDECL MSVCRT_wcscoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
1431 {
1432   /* FIXME: handle collates */
1433   return strcmpW( str1, str2 );
1434 }
1435
1436 /*********************************************************************
1437  *              wcspbrk (MSVCRT.@)
1438  */
1439 MSVCRT_wchar_t* CDECL MSVCRT_wcspbrk( const MSVCRT_wchar_t* str, const MSVCRT_wchar_t* accept )
1440 {
1441   const MSVCRT_wchar_t* p;
1442   while (*str)
1443   {
1444     for (p = accept; *p; p++) if (*p == *str) return (MSVCRT_wchar_t*)str;
1445       str++;
1446   }
1447   return NULL;
1448 }
1449
1450 /*********************************************************************
1451  *              wcstok_s  (MSVCRT.@)
1452  */
1453 MSVCRT_wchar_t * CDECL wcstok_s( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim,
1454                                  MSVCRT_wchar_t **next_token )
1455 {
1456     MSVCRT_wchar_t *ret;
1457
1458     if (!MSVCRT_CHECK_PMT(delim != NULL) || !MSVCRT_CHECK_PMT(next_token != NULL) ||
1459         !MSVCRT_CHECK_PMT(str != NULL || *next_token != NULL))
1460     {
1461         *MSVCRT__errno() = MSVCRT_EINVAL;
1462         return NULL;
1463     }
1464     if (!str) str = *next_token;
1465
1466     while (*str && strchrW( delim, *str )) str++;
1467     if (!*str) return NULL;
1468     ret = str++;
1469     while (*str && !strchrW( delim, *str )) str++;
1470     if (*str) *str++ = 0;
1471     *next_token = str;
1472     return ret;
1473 }
1474
1475 /*********************************************************************
1476  *              wcstok  (MSVCRT.@)
1477  */
1478 MSVCRT_wchar_t * CDECL MSVCRT_wcstok( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim )
1479 {
1480     return wcstok_s(str, delim, &msvcrt_get_thread_data()->wcstok_next);
1481 }
1482
1483 /*********************************************************************
1484  *              wctomb (MSVCRT.@)
1485  */
1486 INT CDECL MSVCRT_wctomb( char *dst, MSVCRT_wchar_t ch )
1487 {
1488   return WideCharToMultiByte( CP_ACP, 0, &ch, 1, dst, 6, NULL, NULL );
1489 }
1490
1491 /*********************************************************************
1492  *              iswalnum (MSVCRT.@)
1493  */
1494 INT CDECL MSVCRT_iswalnum( MSVCRT_wchar_t wc )
1495 {
1496     return isalnumW( wc );
1497 }
1498
1499 /*********************************************************************
1500  *              iswalpha (MSVCRT.@)
1501  */
1502 INT CDECL MSVCRT_iswalpha( MSVCRT_wchar_t wc )
1503 {
1504     return isalphaW( wc );
1505 }
1506
1507 /*********************************************************************
1508  *              iswalpha_l (MSVCRT.@)
1509  */
1510 INT CDECL MSVCRT__iswalpha_l( MSVCRT_wchar_t wc, MSVCRT__locale_t locale )
1511 {
1512     return isalphaW( wc );
1513 }
1514
1515 /*********************************************************************
1516  *              iswcntrl (MSVCRT.@)
1517  */
1518 INT CDECL MSVCRT_iswcntrl( MSVCRT_wchar_t wc )
1519 {
1520     return iscntrlW( wc );
1521 }
1522
1523 /*********************************************************************
1524  *              iswdigit (MSVCRT.@)
1525  */
1526 INT CDECL MSVCRT_iswdigit( MSVCRT_wchar_t wc )
1527 {
1528     return isdigitW( wc );
1529 }
1530
1531 /*********************************************************************
1532  *              iswgraph (MSVCRT.@)
1533  */
1534 INT CDECL MSVCRT_iswgraph( MSVCRT_wchar_t wc )
1535 {
1536     return isgraphW( wc );
1537 }
1538
1539 /*********************************************************************
1540  *              iswlower (MSVCRT.@)
1541  */
1542 INT CDECL MSVCRT_iswlower( MSVCRT_wchar_t wc )
1543 {
1544     return islowerW( wc );
1545 }
1546
1547 /*********************************************************************
1548  *              iswprint (MSVCRT.@)
1549  */
1550 INT CDECL MSVCRT_iswprint( MSVCRT_wchar_t wc )
1551 {
1552     return isprintW( wc );
1553 }
1554
1555 /*********************************************************************
1556  *              iswpunct (MSVCRT.@)
1557  */
1558 INT CDECL MSVCRT_iswpunct( MSVCRT_wchar_t wc )
1559 {
1560     return ispunctW( wc );
1561 }
1562
1563 /*********************************************************************
1564  *              iswspace (MSVCRT.@)
1565  */
1566 INT CDECL MSVCRT_iswspace( MSVCRT_wchar_t wc )
1567 {
1568     return isspaceW( wc );
1569 }
1570
1571 /*********************************************************************
1572  *              iswupper (MSVCRT.@)
1573  */
1574 INT CDECL MSVCRT_iswupper( MSVCRT_wchar_t wc )
1575 {
1576     return isupperW( wc );
1577 }
1578
1579 /*********************************************************************
1580  *              iswxdigit (MSVCRT.@)
1581  */
1582 INT CDECL MSVCRT_iswxdigit( MSVCRT_wchar_t wc )
1583 {
1584     return isxdigitW( wc );
1585 }
1586
1587 /*********************************************************************
1588  *              wcscpy_s (MSVCRT.@)
1589  */
1590 INT CDECL MSVCRT_wcscpy_s( MSVCRT_wchar_t* wcDest, MSVCRT_size_t numElement, const  MSVCRT_wchar_t *wcSrc)
1591 {
1592     MSVCRT_size_t size = 0;
1593
1594     if(!wcDest || !numElement)
1595         return MSVCRT_EINVAL;
1596
1597     wcDest[0] = 0;
1598
1599     if(!wcSrc)
1600     {
1601         return MSVCRT_EINVAL;
1602     }
1603
1604     size = strlenW(wcSrc) + 1;
1605
1606     if(size > numElement)
1607     {
1608         return MSVCRT_ERANGE;
1609     }
1610
1611     memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
1612
1613     return 0;
1614 }
1615
1616 /******************************************************************
1617  *              wcsncpy_s (MSVCRT.@)
1618  */
1619 INT CDECL MSVCRT_wcsncpy_s( MSVCRT_wchar_t* wcDest, MSVCRT_size_t numElement, const MSVCRT_wchar_t *wcSrc,
1620                             MSVCRT_size_t count )
1621 {
1622     MSVCRT_size_t size = 0;
1623
1624     if (!wcDest || !numElement)
1625         return MSVCRT_EINVAL;
1626
1627     wcDest[0] = 0;
1628
1629     if (!wcSrc)
1630     {
1631         return MSVCRT_EINVAL;
1632     }
1633
1634     size = min(strlenW(wcSrc), count);
1635
1636     if (size >= numElement)
1637     {
1638         return MSVCRT_ERANGE;
1639     }
1640
1641     memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
1642     wcDest[size] = '\0';
1643
1644     return 0;
1645 }
1646
1647 /******************************************************************
1648  *              wcscat_s (MSVCRT.@)
1649  *
1650  */
1651 INT CDECL MSVCRT_wcscat_s(MSVCRT_wchar_t* dst, MSVCRT_size_t elem, const MSVCRT_wchar_t* src)
1652 {
1653     MSVCRT_wchar_t* ptr = dst;
1654
1655     if (!dst || elem == 0) return MSVCRT_EINVAL;
1656     if (!src)
1657     {
1658         dst[0] = '\0';
1659         return MSVCRT_EINVAL;
1660     }
1661
1662     /* seek to end of dst string (or elem if no end of string is found */
1663     while (ptr < dst + elem && *ptr != '\0') ptr++;
1664     while (ptr < dst + elem)
1665     {
1666         if ((*ptr++ = *src++) == '\0') return 0;
1667     }
1668     /* not enough space */
1669     dst[0] = '\0';
1670     return MSVCRT_ERANGE;
1671 }
1672
1673 /*********************************************************************
1674  *  wcsncat_s (MSVCRT.@)
1675  *
1676  */
1677 INT CDECL MSVCRT_wcsncat_s(MSVCRT_wchar_t *dst, MSVCRT_size_t elem,
1678         const MSVCRT_wchar_t *src, MSVCRT_size_t count)
1679 {
1680     MSVCRT_size_t srclen;
1681     MSVCRT_wchar_t dststart;
1682     INT ret = 0;
1683
1684     if (!MSVCRT_CHECK_PMT(dst != NULL) || !MSVCRT_CHECK_PMT(elem > 0))
1685     {
1686         *MSVCRT__errno() = MSVCRT_EINVAL;
1687         return MSVCRT_EINVAL;
1688     }
1689     if (!MSVCRT_CHECK_PMT(src != NULL || count == 0))
1690         return MSVCRT_EINVAL;
1691     if (count == 0)
1692         return 0;
1693
1694     for (dststart = 0; dststart < elem; dststart++)
1695     {
1696         if (dst[dststart] == '\0')
1697             break;
1698     }
1699     if (dststart == elem)
1700     {
1701         MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n");
1702         return MSVCRT_EINVAL;
1703     }
1704
1705     if (count == MSVCRT__TRUNCATE)
1706     {
1707         srclen = strlenW(src);
1708         if (srclen >= (elem - dststart))
1709         {
1710             srclen = elem - dststart - 1;
1711             ret = MSVCRT_STRUNCATE;
1712         }
1713     }
1714     else
1715         srclen = min(strlenW(src), count);
1716     if (srclen < (elem - dststart))
1717     {
1718         memcpy(&dst[dststart], src, srclen*sizeof(MSVCRT_wchar_t));
1719         dst[srclen] = '\0';
1720         return ret;
1721     }
1722     MSVCRT_INVALID_PMT("dst[elem] is too small");
1723     dst[0] = '\0';
1724     return MSVCRT_ERANGE;
1725 }
1726
1727 /*********************************************************************
1728  *  _wcstoi64_l (MSVCRT.@)
1729  *
1730  * FIXME: locale parameter is ignored
1731  */
1732 __int64 CDECL MSVCRT__wcstoi64_l(const MSVCRT_wchar_t *nptr,
1733         MSVCRT_wchar_t **endptr, int base, MSVCRT__locale_t locale)
1734 {
1735     BOOL negative = FALSE;
1736     __int64 ret = 0;
1737
1738     TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
1739
1740     if (!MSVCRT_CHECK_PMT(nptr != NULL) || !MSVCRT_CHECK_PMT(base == 0 || base >= 2) ||
1741         !MSVCRT_CHECK_PMT(base <= 36)) {
1742         *MSVCRT__errno() = MSVCRT_EINVAL;
1743         return 0;
1744     }
1745
1746     while(isspaceW(*nptr)) nptr++;
1747
1748     if(*nptr == '-') {
1749         negative = TRUE;
1750         nptr++;
1751     } else if(*nptr == '+')
1752         nptr++;
1753
1754     if((base==0 || base==16) && *nptr=='0' && tolowerW(*(nptr+1))=='x') {
1755         base = 16;
1756         nptr += 2;
1757     }
1758
1759     if(base == 0) {
1760         if(*nptr=='0')
1761             base = 8;
1762         else
1763             base = 10;
1764     }
1765
1766     while(*nptr) {
1767         char cur = tolowerW(*nptr);
1768         int v;
1769
1770         if(isdigitW(cur)) {
1771             if(cur >= '0'+base)
1772                 break;
1773             v = cur-'0';
1774         } else {
1775             if(cur<'a' || cur>='a'+base-10)
1776                 break;
1777             v = cur-'a'+10;
1778         }
1779
1780         if(negative)
1781             v = -v;
1782
1783         nptr++;
1784
1785         if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
1786             ret = MSVCRT_I64_MAX;
1787             *MSVCRT__errno() = MSVCRT_ERANGE;
1788         } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
1789             ret = MSVCRT_I64_MIN;
1790             *MSVCRT__errno() = MSVCRT_ERANGE;
1791         } else
1792             ret = ret*base + v;
1793     }
1794
1795     if(endptr)
1796         *endptr = (MSVCRT_wchar_t*)nptr;
1797
1798     return ret;
1799 }
1800
1801 /*********************************************************************
1802  *  _wcstoi64 (MSVCRT.@)
1803  */
1804 __int64 CDECL MSVCRT__wcstoi64(const MSVCRT_wchar_t *nptr,
1805         MSVCRT_wchar_t **endptr, int base)
1806 {
1807     return MSVCRT__wcstoi64_l(nptr, endptr, base, NULL);
1808 }
1809
1810 /*********************************************************************
1811  *  _wcstoui64_l (MSVCRT.@)
1812  *
1813  * FIXME: locale parameter is ignored
1814  */
1815 unsigned __int64 CDECL MSVCRT__wcstoui64_l(const MSVCRT_wchar_t *nptr,
1816         MSVCRT_wchar_t **endptr, int base, MSVCRT__locale_t locale)
1817 {
1818     BOOL negative = FALSE;
1819     unsigned __int64 ret = 0;
1820
1821     TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
1822
1823     if (!MSVCRT_CHECK_PMT(nptr != NULL) || !MSVCRT_CHECK_PMT(base == 0 || base >= 2) ||
1824         !MSVCRT_CHECK_PMT(base <= 36)) {
1825         *MSVCRT__errno() = MSVCRT_EINVAL;
1826         return 0;
1827     }
1828
1829     while(isspaceW(*nptr)) nptr++;
1830
1831     if(*nptr == '-') {
1832         negative = TRUE;
1833         nptr++;
1834     } else if(*nptr == '+')
1835         nptr++;
1836
1837     if((base==0 || base==16) && *nptr=='0' && tolowerW(*(nptr+1))=='x') {
1838         base = 16;
1839         nptr += 2;
1840     }
1841
1842     if(base == 0) {
1843         if(*nptr=='0')
1844             base = 8;
1845         else
1846             base = 10;
1847     }
1848
1849     while(*nptr) {
1850         char cur = tolowerW(*nptr);
1851         int v;
1852
1853         if(isdigit(cur)) {
1854             if(cur >= '0'+base)
1855                 break;
1856             v = *nptr-'0';
1857         } else {
1858             if(cur<'a' || cur>='a'+base-10)
1859                 break;
1860             v = cur-'a'+10;
1861         }
1862
1863         nptr++;
1864
1865         if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1866             ret = MSVCRT_UI64_MAX;
1867             *MSVCRT__errno() = MSVCRT_ERANGE;
1868         } else
1869             ret = ret*base + v;
1870     }
1871
1872     if(endptr)
1873         *endptr = (MSVCRT_wchar_t*)nptr;
1874
1875     return negative ? -ret : ret;
1876 }
1877
1878 /*********************************************************************
1879  *  _wcstoui64 (MSVCRT.@)
1880  */
1881 unsigned __int64 CDECL MSVCRT__wcstoui64(const MSVCRT_wchar_t *nptr,
1882         MSVCRT_wchar_t **endptr, int base)
1883 {
1884     return MSVCRT__wcstoui64_l(nptr, endptr, base, NULL);
1885 }
1886
1887 /******************************************************************
1888  *  wcsnlen (MSVCRT.@)
1889  */
1890 MSVCRT_size_t CDECL MSVCRT_wcsnlen(const MSVCRT_wchar_t *s, MSVCRT_size_t maxlen)
1891 {
1892     MSVCRT_size_t i;
1893
1894     for (i = 0; i < maxlen; i++)
1895         if (!s[i]) break;
1896     return i;
1897 }