wined3d: Always use np2 repacking if no native np2 support is available.
[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 <limits.h>
22 #include <stdio.h>
23 #include <math.h>
24 #include <assert.h>
25 #include "msvcrt.h"
26 #include "winnls.h"
27 #include "wine/unicode.h"
28 #include "wine/debug.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
31
32
33 /* INTERNAL: MSVCRT_malloc() based wstrndup */
34 MSVCRT_wchar_t* msvcrt_wstrndup(const MSVCRT_wchar_t *buf, unsigned int size)
35 {
36   MSVCRT_wchar_t* ret;
37   unsigned int len = strlenW(buf), max_len;
38
39   max_len = size <= len? size : len + 1;
40
41   ret = MSVCRT_malloc(max_len * sizeof (MSVCRT_wchar_t));
42   if (ret)
43   {
44     memcpy(ret,buf,max_len * sizeof (MSVCRT_wchar_t));
45     ret[max_len] = 0;
46   }
47   return ret;
48 }
49
50 /*********************************************************************
51  *              _wcsdup (MSVCRT.@)
52  */
53 MSVCRT_wchar_t* CDECL _wcsdup( const MSVCRT_wchar_t* str )
54 {
55   MSVCRT_wchar_t* ret = NULL;
56   if (str)
57   {
58     int size = (strlenW(str) + 1) * sizeof(MSVCRT_wchar_t);
59     ret = MSVCRT_malloc( size );
60     if (ret) memcpy( ret, str, size );
61   }
62   return ret;
63 }
64
65 /*********************************************************************
66  *              _wcsicoll (MSVCRT.@)
67  */
68 INT CDECL _wcsicoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
69 {
70   /* FIXME: handle collates */
71   return strcmpiW( str1, str2 );
72 }
73
74 /*********************************************************************
75  *              _wcsnset (MSVCRT.@)
76  */
77 MSVCRT_wchar_t* CDECL _wcsnset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c, MSVCRT_size_t n )
78 {
79   MSVCRT_wchar_t* ret = str;
80   while ((n-- > 0) && *str) *str++ = c;
81   return ret;
82 }
83
84 /*********************************************************************
85  *              _wcsrev (MSVCRT.@)
86  */
87 MSVCRT_wchar_t* CDECL _wcsrev( MSVCRT_wchar_t* str )
88 {
89   MSVCRT_wchar_t* ret = str;
90   MSVCRT_wchar_t* end = str + strlenW(str) - 1;
91   while (end > str)
92   {
93     MSVCRT_wchar_t t = *end;
94     *end--  = *str;
95     *str++  = t;
96   }
97   return ret;
98 }
99
100 /*********************************************************************
101  *              _wcsset (MSVCRT.@)
102  */
103 MSVCRT_wchar_t* CDECL _wcsset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c )
104 {
105   MSVCRT_wchar_t* ret = str;
106   while (*str) *str++ = c;
107   return ret;
108 }
109
110 /*********************************************************************
111  *              wcstod (MSVCRT.@)
112  */
113 double CDECL MSVCRT_wcstod(const MSVCRT_wchar_t* lpszStr, MSVCRT_wchar_t** end)
114 {
115   const MSVCRT_wchar_t* str = lpszStr;
116   int negative = 0;
117   double ret = 0, divisor = 10.0;
118
119   TRACE("(%s,%p) semi-stub\n", debugstr_w(lpszStr), end);
120
121   /* FIXME:
122    * - Should set errno on failure
123    * - Should fail on overflow
124    * - Need to check which input formats are allowed
125    */
126   while (isspaceW(*str))
127     str++;
128
129   if (*str == '-')
130   {
131     negative = 1;
132     str++;
133   }
134
135   while (isdigitW(*str))
136   {
137     ret = ret * 10.0 + (*str - '0');
138     str++;
139   }
140   if (*str == '.')
141     str++;
142   while (isdigitW(*str))
143   {
144     ret = ret + (*str - '0') / divisor;
145     divisor *= 10;
146     str++;
147   }
148
149   if (*str == 'E' || *str == 'e' || *str == 'D' || *str == 'd')
150   {
151     int negativeExponent = 0;
152     int exponent = 0;
153     if (*(++str) == '-')
154     {
155       negativeExponent = 1;
156       str++;
157     }
158     while (isdigitW(*str))
159     {
160       exponent = exponent * 10 + (*str - '0');
161       str++;
162     }
163     if (exponent != 0)
164     {
165       if (negativeExponent)
166         ret = ret / pow(10.0, exponent);
167       else
168         ret = ret * pow(10.0, exponent);
169     }
170   }
171
172   if (negative)
173     ret = -ret;
174
175   if (end)
176     *end = (MSVCRT_wchar_t*)str;
177
178   TRACE("returning %g\n", ret);
179   return ret;
180 }
181
182
183 typedef struct pf_output_t
184 {
185     int used;
186     int len;
187     BOOL unicode;
188     union {
189         LPWSTR W;
190         LPSTR  A;
191     } buf;
192 } pf_output;
193
194 typedef struct pf_flags_t
195 {
196     char Sign, LeftAlign, Alternate, PadZero;
197     int FieldLength, Precision;
198     char IntegerLength, IntegerDouble;
199     char WideString;
200     char Format;
201 } pf_flags;
202
203 /*
204  * writes a string of characters to the output
205  * returns -1 if the string doesn't fit in the output buffer
206  * return the length of the string if all characters were written
207  */
208 static inline int pf_output_stringW( pf_output *out, LPCWSTR str, int len )
209 {
210     int space = out->len - out->used;
211
212     if( len < 0 )
213         len = strlenW( str );
214     if( out->unicode )
215     {
216         LPWSTR p = out->buf.W + out->used;
217
218         if( space >= len )
219         {
220             memcpy( p, str, len*sizeof(WCHAR) );
221             out->used += len;
222             return len;
223         }
224         if( space > 0 )
225             memcpy( p, str, space*sizeof(WCHAR) );
226         out->used += len;
227     }
228     else
229     {
230         int n = WideCharToMultiByte( CP_ACP, 0, str, len, NULL, 0, NULL, NULL );
231         LPSTR p = out->buf.A + out->used;
232
233         if( space >= n )
234         {
235             WideCharToMultiByte( CP_ACP, 0, str, len, p, n, NULL, NULL );
236             out->used += n;
237             return len;
238         }
239         if( space > 0 )
240             WideCharToMultiByte( CP_ACP, 0, str, len, p, space, NULL, NULL );
241         out->used += n;
242     }
243     return -1;
244 }
245
246 static inline int pf_output_stringA( pf_output *out, LPCSTR str, int len )
247 {
248     int space = out->len - out->used;
249
250     if( len < 0 )
251         len = strlen( str );
252     if( !out->unicode )
253     {
254         LPSTR p = out->buf.A + out->used;
255
256         if( space >= len )
257         {
258             memcpy( p, str, len );
259             out->used += len;
260             return len;
261         }
262         if( space > 0 )
263             memcpy( p, str, space );
264         out->used += len;
265     }
266     else
267     {
268         int n = MultiByteToWideChar( CP_ACP, 0, str, len, NULL, 0 );
269         LPWSTR p = out->buf.W + out->used;
270
271         if( space >= n )
272         {
273             MultiByteToWideChar( CP_ACP, 0, str, len, p, n );
274             out->used += n;
275             return len;
276         }
277         if( space > 0 )
278             MultiByteToWideChar( CP_ACP, 0, str, len, p, space );
279         out->used += n;
280     }
281     return -1;
282 }
283
284 /* pf_fill: takes care of signs, alignment, zero and field padding */
285 static inline int pf_fill( pf_output *out, int len, pf_flags *flags, char left )
286 {
287     int i, r = 0;
288
289     if( flags->Sign && !( flags->Format == 'd' || flags->Format == 'i' ) )
290         flags->Sign = 0;
291
292     if( left && flags->Sign )
293     {
294         flags->FieldLength--;
295         if( flags->PadZero )
296             r = pf_output_stringA( out, &flags->Sign, 1 );
297     }
298
299     if( ( !left &&  flags->LeftAlign ) || 
300         (  left && !flags->LeftAlign ))
301     {
302         for( i=0; (i<(flags->FieldLength-len)) && (r>=0); i++ )
303         {
304             if( left && flags->PadZero )
305                 r = pf_output_stringA( out, "0", 1 );
306             else
307                 r = pf_output_stringA( out, " ", 1 );
308         }
309     }
310
311     if( left && flags->Sign && !flags->PadZero )
312         r = pf_output_stringA( out, &flags->Sign, 1 );
313
314     return r;
315 }
316
317 static inline int pf_output_format_W( pf_output *out, LPCWSTR str,
318                                       int len, pf_flags *flags )
319 {
320     int r = 0;
321
322     if( len < 0 )
323         len = strlenW( str );
324
325     if (flags->Precision >= 0 && flags->Precision < len)
326         len = flags->Precision;
327
328     r = pf_fill( out, len, flags, 1 );
329
330     if( r>=0 )
331         r = pf_output_stringW( out, str, len );
332
333     if( r>=0 )
334         r = pf_fill( out, len, flags, 0 );
335
336     return r;
337 }
338
339 static inline int pf_output_format_A( pf_output *out, LPCSTR str,
340                                       int len, pf_flags *flags )
341 {
342     int r = 0;
343
344     if( len < 0 )
345         len = strlen( str );
346
347     if (flags->Precision >= 0 && flags->Precision < len)
348         len = flags->Precision;
349
350     r = pf_fill( out, len, flags, 1 );
351
352     if( r>=0 )
353         r = pf_output_stringA( out, str, len );
354
355     if( r>=0 )
356         r = pf_fill( out, len, flags, 0 );
357
358     return r;
359 }
360
361 static int pf_handle_string_format( pf_output *out, const void* str, int len,
362                              pf_flags *flags, BOOL capital_letter)
363 {
364      if(str == NULL)  /* catch NULL pointer */
365         return pf_output_format_A( out, "(null)", -1, flags);
366
367      /* prefixes take priority over %c,%s vs. %C,%S, so we handle them first */
368     if(flags->WideString || flags->IntegerLength == 'l')
369         return pf_output_format_W( out, str, len, flags);
370     if(flags->IntegerLength == 'h')
371         return pf_output_format_A( out, str, len, flags);
372
373     /* %s,%c ->  chars in ansi functions & wchars in unicode
374      * %S,%C -> wchars in ansi functions &  chars in unicode */
375     if( capital_letter == out->unicode) /* either both TRUE or both FALSE */
376         return pf_output_format_A( out, str, len, flags);
377     else
378         return pf_output_format_W( out, str, len, flags);
379 }
380
381 static inline BOOL pf_is_integer_format( char fmt )
382 {
383     static const char float_fmts[] = "diouxX";
384     if (!fmt)
385         return FALSE;
386     return strchr( float_fmts, fmt ) ? TRUE : FALSE;
387 }
388
389 static inline BOOL pf_is_double_format( char fmt )
390 {
391     static const char float_fmts[] = "aeEfgG";
392     if (!fmt)
393         return FALSE;
394     return strchr( float_fmts, fmt ) ? TRUE : FALSE;
395 }
396
397 static inline BOOL pf_is_valid_format( char fmt )
398 {
399     static const char float_fmts[] = "acCdeEfgGinouxX";
400     if (!fmt)
401         return FALSE;
402     return strchr( float_fmts, fmt ) ? TRUE : FALSE;
403 }
404
405 static void pf_rebuild_format_string( char *p, pf_flags *flags )
406 {
407     *p++ = '%';
408     if( flags->Sign )
409         *p++ = flags->Sign;
410     if( flags->LeftAlign )
411         *p++ = flags->LeftAlign;
412     if( flags->Alternate )
413         *p++ = flags->Alternate;
414     if( flags->PadZero )
415         *p++ = flags->PadZero;
416     if( flags->FieldLength )
417     {
418         sprintf(p, "%d", flags->FieldLength);
419         p += strlen(p);
420     }
421     if( flags->Precision >= 0 )
422     {
423         sprintf(p, ".%d", flags->Precision);
424         p += strlen(p);
425     }
426     *p++ = flags->Format;
427     *p++ = 0;
428 }
429
430 /* pf_integer_conv:  prints x to buf, including alternate formats and
431    additional precision digits, but not field characters or the sign */
432 static void pf_integer_conv( char *buf, int buf_len, pf_flags *flags,
433                              LONGLONG x )
434 {
435     unsigned int base;
436     const char *digits;
437
438     int i, j, k;
439     char number[40], *tmp = number;
440
441     if( buf_len > sizeof number )
442         tmp = HeapAlloc( GetProcessHeap(), 0, buf_len );
443
444     base = 10;
445     if( flags->Format == 'o' )
446         base = 8;
447     else if( flags->Format == 'x' || flags->Format == 'X' )
448         base = 16;
449
450     if( flags->Format == 'X' )
451         digits = "0123456789ABCDEFX";
452     else
453         digits = "0123456789abcdefx";
454
455     if( x < 0 && ( flags->Format == 'd' || flags->Format == 'i' ) )
456     {
457         x = -x;
458         flags->Sign = '-';
459     }
460
461     /* Do conversion (backwards) */
462     i = 0;
463     if( x == 0 && flags->Precision )
464         tmp[i++] = '0';
465     else
466         while( x != 0 )
467         {
468             j = (ULONGLONG) x % base;
469             x = (ULONGLONG) x / base;
470             tmp[i++] = digits[j];
471         }
472     k = flags->Precision - i;
473     while( k-- > 0 )
474         tmp[i++] = '0';
475     if( flags->Alternate )
476     {
477         if( base == 16 )
478         {
479             tmp[i++] = digits[16];
480             tmp[i++] = '0';
481         }
482         else if( base == 8 && tmp[i-1] != '0' )
483             tmp[i++] = '0';
484     }
485
486     /* Reverse for buf */
487     j = 0;
488     while( i-- > 0 )
489         buf[j++] = tmp[i];
490     buf[j] = '\0';
491
492     /* Adjust precision so pf_fill won't truncate the number later */
493     flags->Precision = strlen( buf );
494
495     if( tmp != number )
496         HeapFree( GetProcessHeap(), 0, tmp );
497
498     return;
499 }
500
501 /*********************************************************************
502  *  pf_vsnprintf  (INTERNAL)
503  *
504  *  implements both A and W vsnprintf functions
505  */
506 static int pf_vsnprintf( pf_output *out, const WCHAR *format, va_list valist )
507 {
508     int r;
509     LPCWSTR q, p = format;
510     pf_flags flags;
511
512     TRACE("format is %s\n",debugstr_w(format));
513     while (*p)
514     {
515         q = strchrW( p, '%' );
516
517         /* there's no % characters left, output the rest of the string */
518         if( !q )
519         {
520             r = pf_output_stringW(out, p, -1);
521             if( r<0 )
522                 return r;
523             p += r;
524             continue;
525         }
526
527         /* there's characters before the %, output them */
528         if( q != p )
529         {
530             r = pf_output_stringW(out, p, q - p);
531             if( r<0 )
532                 return r;
533             p = q;
534         }
535
536         /* we must be at a % now, skip over it */
537         assert( *p == '%' );
538         p++;
539
540         /* output a single % character */
541         if( *p == '%' )
542         {
543             r = pf_output_stringW(out, p++, 1);
544             if( r<0 )
545                 return r;
546             continue;
547         }
548
549         /* parse the flags */
550         memset( &flags, 0, sizeof flags );
551         while (*p)
552         {
553             if( *p == '+' || *p == ' ' )
554             {
555                 if ( flags.Sign != '+' )
556                     flags.Sign = *p;
557             }
558             else if( *p == '-' )
559                 flags.LeftAlign = *p;
560             else if( *p == '0' )
561                 flags.PadZero = *p;
562             else if( *p == '#' )
563                 flags.Alternate = *p;
564             else
565                 break;
566             p++;
567         }
568
569         /* deal with the field width specifier */
570         flags.FieldLength = 0;
571         if( *p == '*' )
572         {
573             flags.FieldLength = va_arg( valist, int );
574             if (flags.FieldLength < 0)
575             {
576                 flags.LeftAlign = '-';
577                 flags.FieldLength = -flags.FieldLength;
578             }
579             p++;
580         }
581         else while( isdigit(*p) )
582         {
583             flags.FieldLength *= 10;
584             flags.FieldLength += *p++ - '0';
585         }
586
587         /* deal with precision */
588         flags.Precision = -1;
589         if( *p == '.' )
590         {
591             flags.Precision = 0;
592             p++;
593             if( *p == '*' )
594             {
595                 flags.Precision = va_arg( valist, int );
596                 p++;
597             }
598             else while( isdigit(*p) )
599             {
600                 flags.Precision *= 10;
601                 flags.Precision += *p++ - '0';
602             }
603         }
604
605         /* deal with integer width modifier */
606         while( *p )
607         {
608             if( *p == 'h' || *p == 'l' || *p == 'L' )
609             {
610                 flags.IntegerLength = *p;
611                 p++;
612             }
613             else if( *p == 'I' )
614             {
615                 if( *(p+1) == '6' && *(p+2) == '4' )
616                 {
617                     flags.IntegerDouble++;
618                     p += 3;
619                 }
620                 else if( *(p+1) == '3' && *(p+2) == '2' )
621                     p += 3;
622                 else if( isdigit(*(p+1)) || *(p+1) == 0 )
623                     break;
624                 else
625                     p++;
626             }
627             else if( *p == 'w' )
628                 flags.WideString = *p++;
629             else if( *p == 'F' )
630                 p++; /* ignore */
631             else
632                 break;
633         }
634
635         flags.Format = *p;
636         r = 0;
637
638         /* output a string */
639         if(  flags.Format == 's' || flags.Format == 'S' )
640             r = pf_handle_string_format( out, va_arg(valist, const void*), -1,
641                                          &flags, (flags.Format == 'S') );
642
643         /* output a single character */
644         else if( flags.Format == 'c' || flags.Format == 'C' )
645         {
646             INT ch = va_arg( valist, int );
647
648             r = pf_handle_string_format( out, &ch, 1, &flags, (flags.Format == 'C') );
649         }
650
651         /* output a pointer */
652         else if( flags.Format == 'p' )
653         {
654             char pointer[11];
655
656             flags.PadZero = 0;
657             if( flags.Alternate )
658                 sprintf(pointer, "0X%08lX", va_arg(valist, long));
659             else
660                 sprintf(pointer, "%08lX", va_arg(valist, long));
661             r = pf_output_format_A( out, pointer, -1, &flags );
662         }
663
664         /* deal with %n */
665         else if( flags.Format == 'n' )
666         {
667             int *x = va_arg(valist, int *);
668             *x = out->used;
669         }
670
671         /* deal with 64-bit integers */
672         else if( pf_is_integer_format( flags.Format ) && flags.IntegerDouble )
673         {
674             char number[40], *x = number;
675
676             /* Estimate largest possible required buffer size:
677                * Chooses the larger of the field or precision
678                * Includes extra bytes: 1 byte for null, 1 byte for sign,
679                  4 bytes for exponent, 2 bytes for alternate formats, 1 byte 
680                  for a decimal, and 1 byte for an additional float digit. */
681             int x_len = ((flags.FieldLength > flags.Precision) ? 
682                         flags.FieldLength : flags.Precision) + 10;
683
684             if( x_len >= sizeof number)
685                 x = HeapAlloc( GetProcessHeap(), 0, x_len );
686
687             pf_integer_conv( x, x_len, &flags, va_arg(valist, LONGLONG) );
688
689             r = pf_output_format_A( out, x, -1, &flags );
690             if( x != number )
691                 HeapFree( GetProcessHeap(), 0, x );
692         }
693
694         /* deal with integers and floats using libc's printf */
695         else if( pf_is_valid_format( flags.Format ) )
696         {
697             char fmt[20], number[40], *x = number;
698
699             /* Estimate largest possible required buffer size:
700                * Chooses the larger of the field or precision
701                * Includes extra bytes: 1 byte for null, 1 byte for sign,
702                  4 bytes for exponent, 2 bytes for alternate formats, 1 byte 
703                  for a decimal, and 1 byte for an additional float digit. */
704             int x_len = ((flags.FieldLength > flags.Precision) ? 
705                         flags.FieldLength : flags.Precision) + 10;
706
707             if( x_len >= sizeof number)
708                 x = HeapAlloc( GetProcessHeap(), 0, x_len );
709
710             pf_rebuild_format_string( fmt, &flags );
711
712             if( pf_is_double_format( flags.Format ) )
713                 sprintf( x, fmt, va_arg(valist, double) );
714             else
715                 sprintf( x, fmt, va_arg(valist, int) );
716
717             r = pf_output_stringA( out, x, -1 );
718             if( x != number )
719                 HeapFree( GetProcessHeap(), 0, x );
720         }
721         else
722             continue;
723
724         if( r<0 )
725             return r;
726         p++;
727     }
728
729     /* check we reached the end, and null terminate the string */
730     assert( *p == 0 );
731     pf_output_stringW( out, p, 1 );
732
733     return out->used - 1;
734 }
735
736 /*********************************************************************
737  *              _vsnprintf (MSVCRT.@)
738  */
739 int CDECL MSVCRT_vsnprintf( char *str, unsigned int len,
740                             const char *format, va_list valist )
741 {
742     DWORD sz;
743     LPWSTR formatW = NULL;
744     pf_output out;
745     int r;
746
747     out.unicode = FALSE;
748     out.buf.A = str;
749     out.used = 0;
750     out.len = len;
751
752     if( format )
753     {
754         sz = MultiByteToWideChar( CP_ACP, 0, format, -1, NULL, 0 );
755         formatW = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
756         MultiByteToWideChar( CP_ACP, 0, format, -1, formatW, sz );
757     }
758
759     r = pf_vsnprintf( &out, formatW, valist );
760
761     HeapFree( GetProcessHeap(), 0, formatW );
762
763     return r;
764 }
765
766 /*********************************************************************
767  *              vsprintf (MSVCRT.@)
768  */
769 int CDECL MSVCRT_vsprintf( char *str, const char *format, va_list valist)
770 {
771     return MSVCRT_vsnprintf(str, INT_MAX, format, valist);
772 }
773
774 /*********************************************************************
775  *              _snprintf (MSVCRT.@)
776  */
777 int CDECL MSVCRT__snprintf(char *str, unsigned int len, const char *format, ...)
778 {
779     int retval;
780     va_list valist;
781     va_start(valist, format);
782     retval = MSVCRT_vsnprintf(str, len, format, valist);
783     va_end(valist);
784     return retval;
785 }
786
787 /*********************************************************************
788  *              _vsnwsprintf (MSVCRT.@)
789  */
790 int CDECL MSVCRT_vsnwprintf( MSVCRT_wchar_t *str, unsigned int len,
791                              const MSVCRT_wchar_t *format, va_list valist )
792 {
793     pf_output out;
794
795     out.unicode = TRUE;
796     out.buf.W = str;
797     out.used = 0;
798     out.len = len;
799
800     return pf_vsnprintf( &out, format, valist );
801 }
802
803 /*********************************************************************
804  *              _snwprintf (MSVCRT.@)
805  */
806 int CDECL MSVCRT__snwprintf( MSVCRT_wchar_t *str, unsigned int len, const MSVCRT_wchar_t *format, ...)
807 {
808     int retval;
809     va_list valist;
810     va_start(valist, format);
811     retval = MSVCRT_vsnwprintf(str, len, format, valist);
812     va_end(valist);
813     return retval;
814 }
815
816 /*********************************************************************
817  *              sprintf (MSVCRT.@)
818  */
819 int CDECL MSVCRT_sprintf( char *str, const char *format, ... )
820 {
821     va_list ap;
822     int r;
823
824     va_start( ap, format );
825     r = MSVCRT_vsnprintf( str, INT_MAX, format, ap );
826     va_end( ap );
827     return r;
828 }
829
830 /*********************************************************************
831  *              swprintf (MSVCRT.@)
832  */
833 int CDECL MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
834 {
835     va_list ap;
836     int r;
837
838     va_start( ap, format );
839     r = MSVCRT_vsnwprintf( str, INT_MAX, format, ap );
840     va_end( ap );
841     return r;
842 }
843
844 /*********************************************************************
845  *              vswprintf (MSVCRT.@)
846  */
847 int CDECL MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, va_list args )
848 {
849     return MSVCRT_vsnwprintf( str, INT_MAX, format, args );
850 }
851
852 /*********************************************************************
853  *              wcscoll (MSVCRT.@)
854  */
855 int CDECL MSVCRT_wcscoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
856 {
857   /* FIXME: handle collates */
858   return strcmpW( str1, str2 );
859 }
860
861 /*********************************************************************
862  *              wcspbrk (MSVCRT.@)
863  */
864 MSVCRT_wchar_t* CDECL MSVCRT_wcspbrk( const MSVCRT_wchar_t* str, const MSVCRT_wchar_t* accept )
865 {
866   const MSVCRT_wchar_t* p;
867   while (*str)
868   {
869     for (p = accept; *p; p++) if (*p == *str) return (MSVCRT_wchar_t*)str;
870       str++;
871   }
872   return NULL;
873 }
874
875 /*********************************************************************
876  *              wcstok  (MSVCRT.@)
877  */
878 MSVCRT_wchar_t * CDECL MSVCRT_wcstok( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim )
879 {
880     thread_data_t *data = msvcrt_get_thread_data();
881     MSVCRT_wchar_t *ret;
882
883     if (!str)
884         if (!(str = data->wcstok_next)) return NULL;
885
886     while (*str && strchrW( delim, *str )) str++;
887     if (!*str) return NULL;
888     ret = str++;
889     while (*str && !strchrW( delim, *str )) str++;
890     if (*str) *str++ = 0;
891     data->wcstok_next = str;
892     return ret;
893 }
894
895
896 /*********************************************************************
897  *              wctomb (MSVCRT.@)
898  */
899 INT CDECL MSVCRT_wctomb( char *dst, MSVCRT_wchar_t ch )
900 {
901   return WideCharToMultiByte( CP_ACP, 0, &ch, 1, dst, 6, NULL, NULL );
902 }
903
904 /*********************************************************************
905  *              iswalnum (MSVCRT.@)
906  */
907 INT CDECL MSVCRT_iswalnum( MSVCRT_wchar_t wc )
908 {
909     return isalnumW( wc );
910 }
911
912 /*********************************************************************
913  *              iswalpha (MSVCRT.@)
914  */
915 INT CDECL MSVCRT_iswalpha( MSVCRT_wchar_t wc )
916 {
917     return isalphaW( wc );
918 }
919
920 /*********************************************************************
921  *              iswcntrl (MSVCRT.@)
922  */
923 INT CDECL MSVCRT_iswcntrl( MSVCRT_wchar_t wc )
924 {
925     return iscntrlW( wc );
926 }
927
928 /*********************************************************************
929  *              iswdigit (MSVCRT.@)
930  */
931 INT CDECL MSVCRT_iswdigit( MSVCRT_wchar_t wc )
932 {
933     return isdigitW( wc );
934 }
935
936 /*********************************************************************
937  *              iswgraph (MSVCRT.@)
938  */
939 INT CDECL MSVCRT_iswgraph( MSVCRT_wchar_t wc )
940 {
941     return isgraphW( wc );
942 }
943
944 /*********************************************************************
945  *              iswlower (MSVCRT.@)
946  */
947 INT CDECL MSVCRT_iswlower( MSVCRT_wchar_t wc )
948 {
949     return islowerW( wc );
950 }
951
952 /*********************************************************************
953  *              iswprint (MSVCRT.@)
954  */
955 INT CDECL MSVCRT_iswprint( MSVCRT_wchar_t wc )
956 {
957     return isprintW( wc );
958 }
959
960 /*********************************************************************
961  *              iswpunct (MSVCRT.@)
962  */
963 INT CDECL MSVCRT_iswpunct( MSVCRT_wchar_t wc )
964 {
965     return ispunctW( wc );
966 }
967
968 /*********************************************************************
969  *              iswspace (MSVCRT.@)
970  */
971 INT CDECL MSVCRT_iswspace( MSVCRT_wchar_t wc )
972 {
973     return isspaceW( wc );
974 }
975
976 /*********************************************************************
977  *              iswupper (MSVCRT.@)
978  */
979 INT CDECL MSVCRT_iswupper( MSVCRT_wchar_t wc )
980 {
981     return isupperW( wc );
982 }
983
984 /*********************************************************************
985  *              iswxdigit (MSVCRT.@)
986  */
987 INT CDECL MSVCRT_iswxdigit( MSVCRT_wchar_t wc )
988 {
989     return isxdigitW( wc );
990 }