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