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