ntdll: Block async signals during process init and thread creation.
[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             p++;
575         }
576         else while( isdigit(*p) )
577         {
578             flags.FieldLength *= 10;
579             flags.FieldLength += *p++ - '0';
580         }
581
582         /* deal with precision */
583         flags.Precision = -1;
584         if( *p == '.' )
585         {
586             flags.Precision = 0;
587             p++;
588             if( *p == '*' )
589             {
590                 flags.Precision = va_arg( valist, int );
591                 p++;
592             }
593             else while( isdigit(*p) )
594             {
595                 flags.Precision *= 10;
596                 flags.Precision += *p++ - '0';
597             }
598         }
599
600         /* deal with integer width modifier */
601         while( *p )
602         {
603             if( *p == 'h' || *p == 'l' || *p == 'L' )
604             {
605                 flags.IntegerLength = *p;
606                 p++;
607             }
608             else if( *p == 'I' )
609             {
610                 if( *(p+1) == '6' && *(p+2) == '4' )
611                 {
612                     flags.IntegerDouble++;
613                     p += 3;
614                 }
615                 else if( *(p+1) == '3' && *(p+2) == '2' )
616                     p += 3;
617                 else if( isdigit(*(p+1)) || *(p+1) == 0 )
618                     break;
619                 else
620                     p++;
621             }
622             else if( *p == 'w' )
623                 flags.WideString = *p++;
624             else if( *p == 'F' )
625                 p++; /* ignore */
626             else
627                 break;
628         }
629
630         flags.Format = *p;
631         r = 0;
632
633         /* output a string */
634         if(  flags.Format == 's' || flags.Format == 'S' )
635             r = pf_handle_string_format( out, va_arg(valist, const void*), -1,
636                                          &flags, (flags.Format == 'S') );
637
638         /* output a single character */
639         else if( flags.Format == 'c' || flags.Format == 'C' )
640         {
641             INT ch = va_arg( valist, int );
642
643             r = pf_handle_string_format( out, &ch, 1, &flags, (flags.Format == 'C') );
644         }
645
646         /* output a pointer */
647         else if( flags.Format == 'p' )
648         {
649             char pointer[11];
650
651             flags.PadZero = 0;
652             if( flags.Alternate )
653                 sprintf(pointer, "0X%08lX", va_arg(valist, long));
654             else
655                 sprintf(pointer, "%08lX", va_arg(valist, long));
656             r = pf_output_format_A( out, pointer, -1, &flags );
657         }
658
659         /* deal with %n */
660         else if( flags.Format == 'n' )
661         {
662             int *x = va_arg(valist, int *);
663             *x = out->used;
664         }
665
666         /* deal with 64-bit integers */
667         else if( pf_is_integer_format( flags.Format ) && flags.IntegerDouble )
668         {
669             char number[40], *x = number;
670
671             /* Estimate largest possible required buffer size:
672                * Chooses the larger of the field or precision
673                * Includes extra bytes: 1 byte for null, 1 byte for sign,
674                  4 bytes for exponent, 2 bytes for alternate formats, 1 byte 
675                  for a decimal, and 1 byte for an additional float digit. */
676             int x_len = ((flags.FieldLength > flags.Precision) ? 
677                         flags.FieldLength : flags.Precision) + 10;
678
679             if( x_len >= sizeof number)
680                 x = HeapAlloc( GetProcessHeap(), 0, x_len );
681
682             pf_integer_conv( x, x_len, &flags, va_arg(valist, LONGLONG) );
683
684             r = pf_output_format_A( out, x, -1, &flags );
685             if( x != number )
686                 HeapFree( GetProcessHeap(), 0, x );
687         }
688
689         /* deal with integers and floats using libc's printf */
690         else if( pf_is_valid_format( flags.Format ) )
691         {
692             char fmt[20], number[40], *x = number;
693
694             /* Estimate largest possible required buffer size:
695                * Chooses the larger of the field or precision
696                * Includes extra bytes: 1 byte for null, 1 byte for sign,
697                  4 bytes for exponent, 2 bytes for alternate formats, 1 byte 
698                  for a decimal, and 1 byte for an additional float digit. */
699             int x_len = ((flags.FieldLength > flags.Precision) ? 
700                         flags.FieldLength : flags.Precision) + 10;
701
702             if( x_len >= sizeof number)
703                 x = HeapAlloc( GetProcessHeap(), 0, x_len );
704
705             pf_rebuild_format_string( fmt, &flags );
706
707             if( pf_is_double_format( flags.Format ) )
708                 sprintf( x, fmt, va_arg(valist, double) );
709             else
710                 sprintf( x, fmt, va_arg(valist, int) );
711
712             r = pf_output_stringA( out, x, -1 );
713             if( x != number )
714                 HeapFree( GetProcessHeap(), 0, x );
715         }
716         else
717             continue;
718
719         if( r<0 )
720             return r;
721         p++;
722     }
723
724     /* check we reached the end, and null terminate the string */
725     assert( *p == 0 );
726     pf_output_stringW( out, p, 1 );
727
728     return out->used - 1;
729 }
730
731 /*********************************************************************
732  *              _vsnprintf (MSVCRT.@)
733  */
734 int CDECL MSVCRT_vsnprintf( char *str, unsigned int len,
735                             const char *format, va_list valist )
736 {
737     DWORD sz;
738     LPWSTR formatW = NULL;
739     pf_output out;
740     int r;
741
742     out.unicode = FALSE;
743     out.buf.A = str;
744     out.used = 0;
745     out.len = len;
746
747     if( format )
748     {
749         sz = MultiByteToWideChar( CP_ACP, 0, format, -1, NULL, 0 );
750         formatW = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
751         MultiByteToWideChar( CP_ACP, 0, format, -1, formatW, sz );
752     }
753
754     r = pf_vsnprintf( &out, formatW, valist );
755
756     HeapFree( GetProcessHeap(), 0, formatW );
757
758     return r;
759 }
760
761 /*********************************************************************
762  *              vsprintf (MSVCRT.@)
763  */
764 int CDECL MSVCRT_vsprintf( char *str, const char *format, va_list valist)
765 {
766     return MSVCRT_vsnprintf(str, INT_MAX, format, valist);
767 }
768
769 /*********************************************************************
770  *              _snprintf (MSVCRT.@)
771  */
772 int CDECL MSVCRT__snprintf(char *str, unsigned int len, const char *format, ...)
773 {
774     int retval;
775     va_list valist;
776     va_start(valist, format);
777     retval = MSVCRT_vsnprintf(str, len, format, valist);
778     va_end(valist);
779     return retval;
780 }
781
782 /*********************************************************************
783  *              _vsnwsprintf (MSVCRT.@)
784  */
785 int CDECL MSVCRT_vsnwprintf( MSVCRT_wchar_t *str, unsigned int len,
786                              const MSVCRT_wchar_t *format, va_list valist )
787 {
788     pf_output out;
789
790     out.unicode = TRUE;
791     out.buf.W = str;
792     out.used = 0;
793     out.len = len;
794
795     return pf_vsnprintf( &out, format, valist );
796 }
797
798 /*********************************************************************
799  *              _snwprintf (MSVCRT.@)
800  */
801 int CDECL MSVCRT__snwprintf( MSVCRT_wchar_t *str, unsigned int len, const MSVCRT_wchar_t *format, ...)
802 {
803     int retval;
804     va_list valist;
805     va_start(valist, format);
806     retval = MSVCRT_vsnwprintf(str, len, format, valist);
807     va_end(valist);
808     return retval;
809 }
810
811 /*********************************************************************
812  *              sprintf (MSVCRT.@)
813  */
814 int CDECL MSVCRT_sprintf( char *str, const char *format, ... )
815 {
816     va_list ap;
817     int r;
818
819     va_start( ap, format );
820     r = MSVCRT_vsnprintf( str, INT_MAX, format, ap );
821     va_end( ap );
822     return r;
823 }
824
825 /*********************************************************************
826  *              swprintf (MSVCRT.@)
827  */
828 int CDECL MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
829 {
830     va_list ap;
831     int r;
832
833     va_start( ap, format );
834     r = MSVCRT_vsnwprintf( str, INT_MAX, format, ap );
835     va_end( ap );
836     return r;
837 }
838
839 /*********************************************************************
840  *              vswprintf (MSVCRT.@)
841  */
842 int CDECL MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, va_list args )
843 {
844     return MSVCRT_vsnwprintf( str, INT_MAX, format, args );
845 }
846
847 /*********************************************************************
848  *              wcscoll (MSVCRT.@)
849  */
850 int CDECL MSVCRT_wcscoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
851 {
852   /* FIXME: handle collates */
853   return strcmpW( str1, str2 );
854 }
855
856 /*********************************************************************
857  *              wcspbrk (MSVCRT.@)
858  */
859 MSVCRT_wchar_t* CDECL MSVCRT_wcspbrk( const MSVCRT_wchar_t* str, const MSVCRT_wchar_t* accept )
860 {
861   const MSVCRT_wchar_t* p;
862   while (*str)
863   {
864     for (p = accept; *p; p++) if (*p == *str) return (MSVCRT_wchar_t*)str;
865       str++;
866   }
867   return NULL;
868 }
869
870 /*********************************************************************
871  *              wcstok  (MSVCRT.@)
872  */
873 MSVCRT_wchar_t * CDECL MSVCRT_wcstok( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim )
874 {
875     thread_data_t *data = msvcrt_get_thread_data();
876     MSVCRT_wchar_t *ret;
877
878     if (!str)
879         if (!(str = data->wcstok_next)) return NULL;
880
881     while (*str && strchrW( delim, *str )) str++;
882     if (!*str) return NULL;
883     ret = str++;
884     while (*str && !strchrW( delim, *str )) str++;
885     if (*str) *str++ = 0;
886     data->wcstok_next = str;
887     return ret;
888 }
889
890
891 /*********************************************************************
892  *              wctomb (MSVCRT.@)
893  */
894 INT CDECL MSVCRT_wctomb( char *dst, MSVCRT_wchar_t ch )
895 {
896   return WideCharToMultiByte( CP_ACP, 0, &ch, 1, dst, 6, NULL, NULL );
897 }
898
899 /*********************************************************************
900  *              iswalnum (MSVCRT.@)
901  */
902 INT CDECL MSVCRT_iswalnum( MSVCRT_wchar_t wc )
903 {
904     return isalnumW( wc );
905 }
906
907 /*********************************************************************
908  *              iswalpha (MSVCRT.@)
909  */
910 INT CDECL MSVCRT_iswalpha( MSVCRT_wchar_t wc )
911 {
912     return isalphaW( wc );
913 }
914
915 /*********************************************************************
916  *              iswcntrl (MSVCRT.@)
917  */
918 INT CDECL MSVCRT_iswcntrl( MSVCRT_wchar_t wc )
919 {
920     return iscntrlW( wc );
921 }
922
923 /*********************************************************************
924  *              iswdigit (MSVCRT.@)
925  */
926 INT CDECL MSVCRT_iswdigit( MSVCRT_wchar_t wc )
927 {
928     return isdigitW( wc );
929 }
930
931 /*********************************************************************
932  *              iswgraph (MSVCRT.@)
933  */
934 INT CDECL MSVCRT_iswgraph( MSVCRT_wchar_t wc )
935 {
936     return isgraphW( wc );
937 }
938
939 /*********************************************************************
940  *              iswlower (MSVCRT.@)
941  */
942 INT CDECL MSVCRT_iswlower( MSVCRT_wchar_t wc )
943 {
944     return islowerW( wc );
945 }
946
947 /*********************************************************************
948  *              iswprint (MSVCRT.@)
949  */
950 INT CDECL MSVCRT_iswprint( MSVCRT_wchar_t wc )
951 {
952     return isprintW( wc );
953 }
954
955 /*********************************************************************
956  *              iswpunct (MSVCRT.@)
957  */
958 INT CDECL MSVCRT_iswpunct( MSVCRT_wchar_t wc )
959 {
960     return ispunctW( wc );
961 }
962
963 /*********************************************************************
964  *              iswspace (MSVCRT.@)
965  */
966 INT CDECL MSVCRT_iswspace( MSVCRT_wchar_t wc )
967 {
968     return isspaceW( wc );
969 }
970
971 /*********************************************************************
972  *              iswupper (MSVCRT.@)
973  */
974 INT CDECL MSVCRT_iswupper( MSVCRT_wchar_t wc )
975 {
976     return isupperW( wc );
977 }
978
979 /*********************************************************************
980  *              iswxdigit (MSVCRT.@)
981  */
982 INT CDECL MSVCRT_iswxdigit( MSVCRT_wchar_t wc )
983 {
984     return isxdigitW( wc );
985 }