mmdevapi/tests: Add tests for IAudioClient::GetCurrentPadding.
[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 "wtypes.h"
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
35
36 #include "printf.h"
37 #define PRINTF_WIDE
38 #include "printf.h"
39 #undef PRINTF_WIDE
40
41 /*********************************************************************
42  *              _wcsdup (MSVCRT.@)
43  */
44 MSVCRT_wchar_t* CDECL _wcsdup( const MSVCRT_wchar_t* str )
45 {
46   MSVCRT_wchar_t* ret = NULL;
47   if (str)
48   {
49     int size = (strlenW(str) + 1) * sizeof(MSVCRT_wchar_t);
50     ret = MSVCRT_malloc( size );
51     if (ret) memcpy( ret, str, size );
52   }
53   return ret;
54 }
55
56 /*********************************************************************
57  *              _wcsicoll (MSVCRT.@)
58  */
59 INT CDECL _wcsicoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
60 {
61   /* FIXME: handle collates */
62   return strcmpiW( str1, str2 );
63 }
64
65 /*********************************************************************
66  *              _wcsnicoll (MSVCRT.@)
67  */
68 INT CDECL _wcsnicoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2, MSVCRT_size_t count )
69 {
70   /* FIXME: handle collates */
71   return strncmpiW( str1, str2, count );
72 }
73
74 /*********************************************************************
75  *              _wcsnset (MSVCRT.@)
76  */
77 MSVCRT_wchar_t* CDECL MSVCRT__wcsnset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c, MSVCRT_size_t n )
78 {
79   MSVCRT_wchar_t* ret = str;
80   while ((n-- > 0) && *str) *str++ = c;
81   return ret;
82 }
83
84 /*********************************************************************
85  *              _wcsrev (MSVCRT.@)
86  */
87 MSVCRT_wchar_t* CDECL _wcsrev( MSVCRT_wchar_t* str )
88 {
89   MSVCRT_wchar_t* ret = str;
90   MSVCRT_wchar_t* end = str + strlenW(str) - 1;
91   while (end > str)
92   {
93     MSVCRT_wchar_t t = *end;
94     *end--  = *str;
95     *str++  = t;
96   }
97   return ret;
98 }
99
100 /*********************************************************************
101  *              _wcsset (MSVCRT.@)
102  */
103 MSVCRT_wchar_t* CDECL _wcsset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c )
104 {
105   MSVCRT_wchar_t* ret = str;
106   while (*str) *str++ = c;
107   return ret;
108 }
109
110 /******************************************************************
111  *              _wcsupr_s_l (MSVCRT.@)
112  */
113 int CDECL MSVCRT__wcsupr_s_l( MSVCRT_wchar_t* str, MSVCRT_size_t n,
114    MSVCRT__locale_t locale )
115 {
116   MSVCRT_wchar_t* ptr = str;
117
118   if (!str || !n)
119   {
120     if (str) *str = '\0';
121     *MSVCRT__errno() = MSVCRT_EINVAL;
122     return MSVCRT_EINVAL;
123   }
124
125   while (n--)
126   {
127     if (!*ptr) return 0;
128     /* FIXME: add locale support */
129     *ptr = toupperW(*ptr);
130     ptr++;
131   }
132
133   /* MSDN claims that the function should return and set errno to
134    * ERANGE, which doesn't seem to be true based on the tests. */
135   *str = '\0';
136   *MSVCRT__errno() = MSVCRT_EINVAL;
137   return MSVCRT_EINVAL;
138 }
139
140 /******************************************************************
141  *              _wcsupr_s (MSVCRT.@)
142  *
143  */
144 INT CDECL MSVCRT__wcsupr_s( MSVCRT_wchar_t* str, MSVCRT_size_t n )
145 {
146   return MSVCRT__wcsupr_s_l( str, n, NULL );
147 }
148
149 /******************************************************************
150  *              _wcslwr_s (MSVCRT.@)
151  */
152 int CDECL MSVCRT__wcslwr_s( MSVCRT_wchar_t* str, MSVCRT_size_t n )
153 {
154   MSVCRT_wchar_t* ptr = str;
155
156   if (!str || !n)
157   {
158     if (str) *str = '\0';
159     *MSVCRT__errno() = MSVCRT_EINVAL;
160     return MSVCRT_EINVAL;
161   }
162
163   while (n--)
164   {
165     if (!*ptr) return 0;
166     *ptr = tolowerW(*ptr);
167     ptr++;
168   }
169
170   /* MSDN claims that the function should return and set errno to
171    * ERANGE, which doesn't seem to be true based on the tests. */
172   *str = '\0';
173   *MSVCRT__errno() = MSVCRT_EINVAL;
174   return MSVCRT_EINVAL;
175 }
176
177 /*********************************************************************
178  * _wcstod_l - not exported in native msvcrt
179  */
180 double CDECL MSVCRT__wcstod_l(const MSVCRT_wchar_t* str, MSVCRT_wchar_t** end,
181         MSVCRT__locale_t locale)
182 {
183     unsigned __int64 d=0, hlp;
184     unsigned fpcontrol;
185     int exp=0, sign=1;
186     const MSVCRT_wchar_t *p;
187     double ret;
188     BOOL found_digit = FALSE;
189
190     if (!MSVCRT_CHECK_PMT(str != NULL)) {
191         *MSVCRT__errno() = MSVCRT_EINVAL;
192         return 0;
193     }
194
195     if(!locale)
196         locale = get_locale();
197
198     p = str;
199     while(isspaceW(*p))
200         p++;
201
202     if(*p == '-') {
203         sign = -1;
204         p++;
205     } else  if(*p == '+')
206         p++;
207
208     while(isdigitW(*p)) {
209         found_digit = TRUE;
210         hlp = d*10+*(p++)-'0';
211         if(d>MSVCRT_UI64_MAX/10 || hlp<d) {
212             exp++;
213             break;
214         } else
215             d = hlp;
216     }
217     while(isdigitW(*p)) {
218         exp++;
219         p++;
220     }
221     if(*p == *locale->locinfo->lconv->decimal_point)
222         p++;
223
224     while(isdigitW(*p)) {
225         found_digit = TRUE;
226         hlp = d*10+*(p++)-'0';
227         if(d>MSVCRT_UI64_MAX/10 || hlp<d)
228             break;
229
230         d = hlp;
231         exp--;
232     }
233     while(isdigitW(*p))
234         p++;
235
236     if(!found_digit) {
237         if(end)
238             *end = (MSVCRT_wchar_t*)str;
239         return 0.0;
240     }
241
242     if(*p=='e' || *p=='E' || *p=='d' || *p=='D') {
243         int e=0, s=1;
244
245         p++;
246         if(*p == '-') {
247             s = -1;
248             p++;
249         } else if(*p == '+')
250             p++;
251
252         if(isdigitW(*p)) {
253             while(isdigitW(*p)) {
254                 if(e>INT_MAX/10 || (e=e*10+*p-'0')<0)
255                     e = INT_MAX;
256                 p++;
257             }
258             e *= s;
259
260             if(exp<0 && e<0 && exp+e>=0) exp = INT_MIN;
261             else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
262             else exp += e;
263         } else {
264             if(*p=='-' || *p=='+')
265                 p--;
266             p--;
267         }
268     }
269
270     fpcontrol = _control87(0, 0);
271     _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE
272             |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff);
273
274     if(exp>0)
275         ret = (double)sign*d*pow(10, exp);
276     else
277         ret = (double)sign*d/pow(10, -exp);
278
279     _control87(fpcontrol, 0xffffffff);
280
281     if((d && ret==0.0) || isinf(ret))
282         *MSVCRT__errno() = MSVCRT_ERANGE;
283
284     if(end)
285         *end = (MSVCRT_wchar_t*)p;
286
287     return ret;
288 }
289
290 /*********************************************************************
291  *              _wcstombs_l (MSVCRT.@)
292  */
293 MSVCRT_size_t CDECL MSVCRT__wcstombs_l(char *mbstr, const MSVCRT_wchar_t *wcstr,
294         MSVCRT_size_t count, MSVCRT__locale_t locale)
295 {
296     char default_char = '\0';
297     MSVCRT_size_t tmp = 0;
298     BOOL used_default;
299
300     if(!locale)
301         locale = get_locale();
302
303     if(!mbstr)
304         return WideCharToMultiByte(locale->locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
305                 wcstr, -1, NULL, 0, &default_char, &used_default)-1;
306
307     while(*wcstr) {
308         char buf[3];
309         MSVCRT_size_t i, size;
310
311         size = WideCharToMultiByte(locale->locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
312                 wcstr, 1, buf, 3, &default_char, &used_default);
313         if(used_default)
314             return -1;
315         if(tmp+size > count)
316             return tmp;
317
318         for(i=0; i<size; i++)
319             mbstr[tmp++] = buf[i];
320         wcstr++;
321     }
322
323     if(tmp < count)
324         mbstr[tmp] = '\0';
325     return tmp;
326 }
327
328 /*********************************************************************
329  *              wcstombs (MSVCRT.@)
330  */
331 MSVCRT_size_t CDECL MSVCRT_wcstombs(char *mbstr, const MSVCRT_wchar_t *wcstr,
332         MSVCRT_size_t count)
333 {
334     return MSVCRT__wcstombs_l(mbstr, wcstr, count, NULL);
335 }
336
337 /*********************************************************************
338  *              _wcstombs_s_l (MSVCRT.@)
339  */
340 MSVCRT_size_t CDECL MSVCRT__wcstombs_s_l(MSVCRT_size_t *ret, char *mbstr,
341         MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr,
342         MSVCRT_size_t count, MSVCRT__locale_t locale)
343 {
344     MSVCRT_size_t conv;
345
346     if(!mbstr && !size) {
347         conv = MSVCRT__wcstombs_l(NULL, wcstr, 0, locale);
348         if(ret)
349             *ret = conv+1;
350         return 0;
351     }
352
353     if (!MSVCRT_CHECK_PMT(wcstr != NULL) || !MSVCRT_CHECK_PMT(mbstr != NULL)) {
354         if(mbstr && size)
355             mbstr[0] = '\0';
356         *MSVCRT__errno() = MSVCRT_EINVAL;
357         return MSVCRT_EINVAL;
358     }
359
360     if(count==MSVCRT__TRUNCATE || size<count)
361         conv = size;
362     else
363         conv = count;
364
365     conv = MSVCRT__wcstombs_l(mbstr, wcstr, conv, locale);
366     if(conv<size)
367         mbstr[conv++] = '\0';
368     else if(conv==size && (count==MSVCRT__TRUNCATE || mbstr[conv-1]=='\0'))
369         mbstr[conv-1] = '\0';
370     else {
371         MSVCRT_INVALID_PMT("mbstr[size] is too small");
372         if(size)
373             mbstr[0] = '\0';
374         *MSVCRT__errno() = MSVCRT_ERANGE;
375         return MSVCRT_ERANGE;
376     }
377
378     if(ret)
379         *ret = conv;
380     return 0;
381 }
382
383 /*********************************************************************
384  *              wcstombs_s (MSVCRT.@)
385  */
386 MSVCRT_size_t CDECL MSVCRT_wcstombs_s(MSVCRT_size_t *ret, char *mbstr,
387         MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr, MSVCRT_size_t count)
388 {
389     return MSVCRT__wcstombs_s_l(ret, mbstr, size, wcstr, count, NULL);
390 }
391
392 /*********************************************************************
393  *              wcstod (MSVCRT.@)
394  */
395 double CDECL MSVCRT_wcstod(const MSVCRT_wchar_t* lpszStr, MSVCRT_wchar_t** end)
396 {
397     return MSVCRT__wcstod_l(lpszStr, end, NULL);
398 }
399
400 /*********************************************************************
401  *              _wtof (MSVCRT.@)
402  */
403 double CDECL MSVCRT__wtof(const MSVCRT_wchar_t *str)
404 {
405     return MSVCRT__wcstod_l(str, NULL, NULL);
406 }
407
408 /*********************************************************************
409  *              _wtof_l (MSVCRT.@)
410  */
411 double CDECL MSVCRT__wtof_l(const MSVCRT_wchar_t *str, MSVCRT__locale_t locale)
412 {
413     return MSVCRT__wcstod_l(str, NULL, locale);
414 }
415
416 /*********************************************************************
417  * arg_clbk_valist (INTERNAL)
418  */
419 printf_arg arg_clbk_valist(void *ctx, int arg_pos, int type, __ms_va_list *valist)
420 {
421     printf_arg ret;
422
423     if(type == VT_I8)
424         ret.get_longlong = va_arg(*valist, LONGLONG);
425     else if(type == VT_INT)
426         ret.get_int = va_arg(*valist, int);
427     else if(type == VT_R8)
428         ret.get_double = va_arg(*valist, double);
429     else if(type == VT_PTR)
430         ret.get_ptr = va_arg(*valist, void*);
431     else {
432         ERR("Incorrect type\n");
433         ret.get_int = 0;
434     }
435
436     return ret;
437 }
438
439 /*********************************************************************
440  *              _vsnprintf (MSVCRT.@)
441  */
442 int CDECL MSVCRT_vsnprintf( char *str, MSVCRT_size_t len,
443                             const char *format, __ms_va_list valist )
444 {
445     static const char nullbyte = '\0';
446     struct _str_ctx_a ctx = {len, str};
447     int ret;
448
449     ret = pf_printf_a(puts_clbk_str_a, &ctx, format, NULL, FALSE, FALSE,
450             arg_clbk_valist, NULL, valist);
451     puts_clbk_str_a(&ctx, 1, &nullbyte);
452     return ret;
453 }
454
455 /*********************************************************************
456 *               _vsnprintf_l (MSVCRT.@)
457  */
458 int CDECL MSVCRT_vsnprintf_l( char *str, MSVCRT_size_t len, const char *format,
459                             MSVCRT__locale_t locale, __ms_va_list valist )
460 {
461     static const char nullbyte = '\0';
462     struct _str_ctx_a ctx = {len, str};
463     int ret;
464
465     ret = pf_printf_a(puts_clbk_str_a, &ctx, format, locale, FALSE, FALSE,
466             arg_clbk_valist, NULL, valist);
467     puts_clbk_str_a(&ctx, 1, &nullbyte);
468     return ret;
469 }
470
471 /*********************************************************************
472  *              _vsnprintf_s_l (MSVCRT.@)
473  */
474 int CDECL MSVCRT_vsnprintf_s_l( char *str, MSVCRT_size_t sizeOfBuffer,
475         MSVCRT_size_t count, const char *format,
476         MSVCRT__locale_t locale, __ms_va_list valist )
477 {
478     static const char nullbyte = '\0';
479     struct _str_ctx_a ctx;
480     int len, ret;
481
482     if(sizeOfBuffer<count+1 || count==-1)
483         len = sizeOfBuffer;
484     else
485         len = count+1;
486
487     ctx.len = len;
488     ctx.buf = str;
489     ret = pf_printf_a(puts_clbk_str_a, &ctx, format, locale, FALSE, TRUE,
490             arg_clbk_valist, NULL, valist);
491     puts_clbk_str_a(&ctx, 1, &nullbyte);
492
493     if(ret<0 || ret==len) {
494         if(count!=MSVCRT__TRUNCATE && count>sizeOfBuffer) {
495             MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small");
496             *MSVCRT__errno() = MSVCRT_ERANGE;
497             memset(str, 0, sizeOfBuffer);
498         } else
499             str[len-1] = '\0';
500
501         return -1;
502     }
503
504     return ret;
505 }
506
507 /*********************************************************************
508  *              _vsnprintf_s (MSVCRT.@)
509  */
510 int CDECL MSVCRT_vsnprintf_s( char *str, MSVCRT_size_t sizeOfBuffer,
511         MSVCRT_size_t count, const char *format, __ms_va_list valist )
512 {
513     return MSVCRT_vsnprintf_s_l(str,sizeOfBuffer, count, format, NULL, valist);
514 }
515
516 /*********************************************************************
517  *              vsprintf (MSVCRT.@)
518  */
519 int CDECL MSVCRT_vsprintf( char *str, const char *format, __ms_va_list valist)
520 {
521     return MSVCRT_vsnprintf(str, INT_MAX, format, valist);
522 }
523
524 /*********************************************************************
525  *              vsprintf_s (MSVCRT.@)
526  */
527 int CDECL MSVCRT_vsprintf_s( char *str, MSVCRT_size_t num, const char *format, __ms_va_list valist)
528 {
529     return MSVCRT_vsnprintf(str, num, format, valist);
530 }
531
532 /*********************************************************************
533  *              _vscprintf (MSVCRT.@)
534  */
535 int CDECL _vscprintf( const char *format, __ms_va_list valist )
536 {
537     return MSVCRT_vsnprintf( NULL, INT_MAX, format, valist );
538 }
539
540 /*********************************************************************
541  *              _snprintf (MSVCRT.@)
542  */
543 int CDECL MSVCRT__snprintf(char *str, unsigned int len, const char *format, ...)
544 {
545     int retval;
546     __ms_va_list valist;
547     __ms_va_start(valist, format);
548     retval = MSVCRT_vsnprintf(str, len, format, valist);
549     __ms_va_end(valist);
550     return retval;
551 }
552
553 /*********************************************************************
554  *              _snprintf_s (MSVCRT.@)
555  */
556 int CDECL MSVCRT__snprintf_s(char *str, unsigned int len, unsigned int count,
557     const char *format, ...)
558 {
559     int retval;
560     __ms_va_list valist;
561     __ms_va_start(valist, format);
562     retval = MSVCRT_vsnprintf_s_l(str, len, count, format, NULL, valist);
563     __ms_va_end(valist);
564     return retval;
565 }
566
567 /*********************************************************************
568  *              _scprintf (MSVCRT.@)
569  */
570 int CDECL MSVCRT__scprintf(const char *format, ...)
571 {
572     int retval;
573     __ms_va_list valist;
574     __ms_va_start(valist, format);
575     retval = _vscprintf(format, valist);
576     __ms_va_end(valist);
577     return retval;
578 }
579
580 /*********************************************************************
581  *              _vsnwprintf (MSVCRT.@)
582  */
583 int CDECL MSVCRT_vsnwprintf(MSVCRT_wchar_t *str, MSVCRT_size_t len,
584         const MSVCRT_wchar_t *format, __ms_va_list valist)
585 {
586     static const MSVCRT_wchar_t nullbyte = '\0';
587     struct _str_ctx_w ctx = {len, str};
588     int ret;
589
590     ret = pf_printf_w(puts_clbk_str_w, &ctx, format, NULL, FALSE, FALSE,
591             arg_clbk_valist, NULL, valist);
592     puts_clbk_str_w(&ctx, 1, &nullbyte);
593     return ret;
594 }
595
596 /*********************************************************************
597  *              _vsnwprintf_l (MSVCRT.@)
598  */
599 int CDECL MSVCRT_vsnwprintf_l(MSVCRT_wchar_t *str, MSVCRT_size_t len,
600         const MSVCRT_wchar_t *format, MSVCRT__locale_t locale,
601         __ms_va_list valist)
602 {
603     static const MSVCRT_wchar_t nullbyte = '\0';
604     struct _str_ctx_w ctx = {len, str};
605     int ret;
606
607     ret = pf_printf_w(puts_clbk_str_w, &ctx, format, locale, FALSE, FALSE,
608             arg_clbk_valist, NULL, valist);
609     puts_clbk_str_w(&ctx, 1, &nullbyte);
610     return ret;
611 }
612
613 /*********************************************************************
614  *              _vsnwprintf_s_l (MSVCRT.@)
615  */
616 int CDECL MSVCRT_vsnwprintf_s_l( MSVCRT_wchar_t *str, MSVCRT_size_t sizeOfBuffer,
617         MSVCRT_size_t count, const MSVCRT_wchar_t *format,
618         MSVCRT__locale_t locale, __ms_va_list valist)
619 {
620     static const MSVCRT_wchar_t nullbyte = '\0';
621     struct _str_ctx_w ctx;
622     int len, ret;
623
624     len = sizeOfBuffer;
625     if(count!=-1 && len>count+1)
626         len = count+1;
627
628     ctx.len = len;
629     ctx.buf = str;
630     ret = pf_printf_w(puts_clbk_str_w, &ctx, format, locale, FALSE, TRUE,
631             arg_clbk_valist, NULL, valist);
632     puts_clbk_str_w(&ctx, 1, &nullbyte);
633
634     if(ret<0 || ret==len) {
635         if(count!=MSVCRT__TRUNCATE && count>sizeOfBuffer) {
636             MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small");
637             *MSVCRT__errno() = MSVCRT_ERANGE;
638             memset(str, 0, sizeOfBuffer*sizeof(MSVCRT_wchar_t));
639         } else
640             str[len-1] = '\0';
641
642         return -1;
643     }
644
645     return ret;
646 }
647
648 /*********************************************************************
649  *              _vsnwprintf_s (MSVCRT.@)
650  */
651 int CDECL MSVCRT_vsnwprintf_s(MSVCRT_wchar_t *str, MSVCRT_size_t sizeOfBuffer,
652         MSVCRT_size_t count, const MSVCRT_wchar_t *format, __ms_va_list valist)
653 {
654     return MSVCRT_vsnwprintf_s_l(str, sizeOfBuffer, count,
655             format, NULL, valist);
656 }
657
658 /*********************************************************************
659  *              _snwprintf (MSVCRT.@)
660  */
661 int CDECL MSVCRT__snwprintf( MSVCRT_wchar_t *str, unsigned int len, const MSVCRT_wchar_t *format, ...)
662 {
663     int retval;
664     __ms_va_list valist;
665     __ms_va_start(valist, format);
666     retval = MSVCRT_vsnwprintf(str, len, format, valist);
667     __ms_va_end(valist);
668     return retval;
669 }
670
671 /*********************************************************************
672  *              _snwprintf_s (MSVCRT.@)
673  */
674 int CDECL MSVCRT__snwprintf_s( MSVCRT_wchar_t *str, unsigned int len, unsigned int count,
675     const MSVCRT_wchar_t *format, ...)
676 {
677     int retval;
678     __ms_va_list valist;
679     __ms_va_start(valist, format);
680     retval = MSVCRT_vsnwprintf_s_l(str, len, count, format, NULL, valist);
681     __ms_va_end(valist);
682     return retval;
683 }
684
685 /*********************************************************************
686  *              sprintf (MSVCRT.@)
687  */
688 int CDECL MSVCRT_sprintf( char *str, const char *format, ... )
689 {
690     __ms_va_list ap;
691     int r;
692
693     __ms_va_start( ap, format );
694     r = MSVCRT_vsnprintf( str, INT_MAX, format, ap );
695     __ms_va_end( ap );
696     return r;
697 }
698
699 /*********************************************************************
700  *              sprintf_s (MSVCRT.@)
701  */
702 int CDECL MSVCRT_sprintf_s( char *str, MSVCRT_size_t num, const char *format, ... )
703 {
704     __ms_va_list ap;
705     int r;
706
707     __ms_va_start( ap, format );
708     r = MSVCRT_vsnprintf( str, num, format, ap );
709     __ms_va_end( ap );
710     return r;
711 }
712
713 /*********************************************************************
714  *              _scwprintf (MSVCRT.@)
715  */
716 int CDECL MSVCRT__scwprintf( const MSVCRT_wchar_t *format, ... )
717 {
718     __ms_va_list ap;
719     int r;
720
721     __ms_va_start( ap, format );
722     r = MSVCRT_vsnwprintf( NULL, INT_MAX, format, ap );
723     __ms_va_end( ap );
724     return r;
725 }
726
727 /*********************************************************************
728  *              swprintf (MSVCRT.@)
729  */
730 int CDECL MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
731 {
732     __ms_va_list ap;
733     int r;
734
735     __ms_va_start( ap, format );
736     r = MSVCRT_vsnwprintf( str, INT_MAX, format, ap );
737     __ms_va_end( ap );
738     return r;
739 }
740
741 /*********************************************************************
742  *              swprintf_s (MSVCRT.@)
743  */
744 int CDECL MSVCRT_swprintf_s(MSVCRT_wchar_t *str, MSVCRT_size_t numberOfElements,
745         const MSVCRT_wchar_t *format, ... )
746 {
747     __ms_va_list ap;
748     int r;
749
750     __ms_va_start(ap, format);
751     r = MSVCRT_vsnwprintf_s(str, numberOfElements, INT_MAX, format, ap);
752     __ms_va_end(ap);
753
754     return r;
755 }
756
757 /*********************************************************************
758  *              vswprintf (MSVCRT.@)
759  */
760 int CDECL MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, __ms_va_list args )
761 {
762     return MSVCRT_vsnwprintf( str, INT_MAX, format, args );
763 }
764
765 /*********************************************************************
766  *              _vscwprintf (MSVCRT.@)
767  */
768 int CDECL _vscwprintf( const MSVCRT_wchar_t *format, __ms_va_list args )
769 {
770     return MSVCRT_vsnwprintf( NULL, INT_MAX, format, args );
771 }
772
773 /*********************************************************************
774  *              vswprintf_s (MSVCRT.@)
775  */
776 int CDECL MSVCRT_vswprintf_s(MSVCRT_wchar_t* str, MSVCRT_size_t numberOfElements,
777         const MSVCRT_wchar_t* format, __ms_va_list args)
778 {
779     return MSVCRT_vsnwprintf_s(str, numberOfElements, INT_MAX, format, args );
780 }
781
782 /*********************************************************************
783  *              _vswprintf_s_l (MSVCRT.@)
784  */
785 int CDECL MSVCRT_vswprintf_s_l(MSVCRT_wchar_t* str, MSVCRT_size_t numberOfElements,
786         const MSVCRT_wchar_t* format, MSVCRT__locale_t locale, __ms_va_list args)
787 {
788     return MSVCRT_vsnwprintf_s_l(str, numberOfElements, INT_MAX,
789             format, locale, args );
790 }
791
792 /*********************************************************************
793  *              wcscoll (MSVCRT.@)
794  */
795 int CDECL MSVCRT_wcscoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
796 {
797   /* FIXME: handle collates */
798   return strcmpW( str1, str2 );
799 }
800
801 /*********************************************************************
802  *              wcspbrk (MSVCRT.@)
803  */
804 MSVCRT_wchar_t* CDECL MSVCRT_wcspbrk( const MSVCRT_wchar_t* str, const MSVCRT_wchar_t* accept )
805 {
806   const MSVCRT_wchar_t* p;
807   while (*str)
808   {
809     for (p = accept; *p; p++) if (*p == *str) return (MSVCRT_wchar_t*)str;
810       str++;
811   }
812   return NULL;
813 }
814
815 /*********************************************************************
816  *              wcstok_s  (MSVCRT.@)
817  */
818 MSVCRT_wchar_t * CDECL wcstok_s( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim,
819                                  MSVCRT_wchar_t **next_token )
820 {
821     MSVCRT_wchar_t *ret;
822
823     if (!MSVCRT_CHECK_PMT(delim != NULL) || !MSVCRT_CHECK_PMT(next_token != NULL) ||
824         !MSVCRT_CHECK_PMT(str != NULL || *next_token != NULL))
825     {
826         *MSVCRT__errno() = MSVCRT_EINVAL;
827         return NULL;
828     }
829     if (!str) str = *next_token;
830
831     while (*str && strchrW( delim, *str )) str++;
832     if (!*str) return NULL;
833     ret = str++;
834     while (*str && !strchrW( delim, *str )) str++;
835     if (*str) *str++ = 0;
836     *next_token = str;
837     return ret;
838 }
839
840 /*********************************************************************
841  *              wcstok  (MSVCRT.@)
842  */
843 MSVCRT_wchar_t * CDECL MSVCRT_wcstok( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim )
844 {
845     return wcstok_s(str, delim, &msvcrt_get_thread_data()->wcstok_next);
846 }
847
848 /*********************************************************************
849  *              wctob (MSVCRT.@)
850  */
851 INT CDECL MSVCRT_wctob( MSVCRT_wint_t wchar )
852 {
853     MSVCRT__locale_t locale = get_locale();
854     char out;
855     BOOL error;
856
857     if(WideCharToMultiByte( locale->locinfo->lc_codepage, 0, &wchar, 1, &out, 1, NULL, &error ) && !error)
858         return (INT)out;
859     return MSVCRT_EOF;
860 }
861
862 /*********************************************************************
863  *              wctomb (MSVCRT.@)
864  */
865 INT CDECL MSVCRT_wctomb( char *dst, MSVCRT_wchar_t ch )
866 {
867     MSVCRT__locale_t locale = get_locale();
868     return WideCharToMultiByte( locale->locinfo->lc_codepage, 0, &ch, 1, dst, 6, NULL, NULL );
869 }
870
871 /*********************************************************************
872  *              iswalnum (MSVCRT.@)
873  */
874 INT CDECL MSVCRT_iswalnum( MSVCRT_wchar_t wc )
875 {
876     return isalnumW( wc );
877 }
878
879 /*********************************************************************
880  *              iswalpha (MSVCRT.@)
881  */
882 INT CDECL MSVCRT_iswalpha( MSVCRT_wchar_t wc )
883 {
884     return isalphaW( wc );
885 }
886
887 /*********************************************************************
888  *              iswalpha_l (MSVCRT.@)
889  */
890 INT CDECL MSVCRT__iswalpha_l( MSVCRT_wchar_t wc, MSVCRT__locale_t locale )
891 {
892     return isalphaW( wc );
893 }
894
895 /*********************************************************************
896  *              iswcntrl (MSVCRT.@)
897  */
898 INT CDECL MSVCRT_iswcntrl( MSVCRT_wchar_t wc )
899 {
900     return iscntrlW( wc );
901 }
902
903 /*********************************************************************
904  *              iswdigit (MSVCRT.@)
905  */
906 INT CDECL MSVCRT_iswdigit( MSVCRT_wchar_t wc )
907 {
908     return isdigitW( wc );
909 }
910
911 /*********************************************************************
912  *              iswgraph (MSVCRT.@)
913  */
914 INT CDECL MSVCRT_iswgraph( MSVCRT_wchar_t wc )
915 {
916     return isgraphW( wc );
917 }
918
919 /*********************************************************************
920  *              iswlower (MSVCRT.@)
921  */
922 INT CDECL MSVCRT_iswlower( MSVCRT_wchar_t wc )
923 {
924     return islowerW( wc );
925 }
926
927 /*********************************************************************
928  *              iswprint (MSVCRT.@)
929  */
930 INT CDECL MSVCRT_iswprint( MSVCRT_wchar_t wc )
931 {
932     return isprintW( wc );
933 }
934
935 /*********************************************************************
936  *              iswpunct (MSVCRT.@)
937  */
938 INT CDECL MSVCRT_iswpunct( MSVCRT_wchar_t wc )
939 {
940     return ispunctW( wc );
941 }
942
943 /*********************************************************************
944  *              iswspace (MSVCRT.@)
945  */
946 INT CDECL MSVCRT_iswspace( MSVCRT_wchar_t wc )
947 {
948     return isspaceW( wc );
949 }
950
951 /*********************************************************************
952  *              iswupper (MSVCRT.@)
953  */
954 INT CDECL MSVCRT_iswupper( MSVCRT_wchar_t wc )
955 {
956     return isupperW( wc );
957 }
958
959 /*********************************************************************
960  *              iswxdigit (MSVCRT.@)
961  */
962 INT CDECL MSVCRT_iswxdigit( MSVCRT_wchar_t wc )
963 {
964     return isxdigitW( wc );
965 }
966
967 /*********************************************************************
968  *              wcscpy_s (MSVCRT.@)
969  */
970 INT CDECL MSVCRT_wcscpy_s( MSVCRT_wchar_t* wcDest, MSVCRT_size_t numElement, const  MSVCRT_wchar_t *wcSrc)
971 {
972     MSVCRT_size_t size = 0;
973
974     if(!wcDest || !numElement)
975         return MSVCRT_EINVAL;
976
977     wcDest[0] = 0;
978
979     if(!wcSrc)
980     {
981         return MSVCRT_EINVAL;
982     }
983
984     size = strlenW(wcSrc) + 1;
985
986     if(size > numElement)
987     {
988         return MSVCRT_ERANGE;
989     }
990
991     memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
992
993     return 0;
994 }
995
996 /******************************************************************
997  *              wcsncpy_s (MSVCRT.@)
998  */
999 INT CDECL MSVCRT_wcsncpy_s( MSVCRT_wchar_t* wcDest, MSVCRT_size_t numElement, const MSVCRT_wchar_t *wcSrc,
1000                             MSVCRT_size_t count )
1001 {
1002     MSVCRT_size_t size = 0;
1003
1004     if (!wcDest || !numElement)
1005         return MSVCRT_EINVAL;
1006
1007     wcDest[0] = 0;
1008
1009     if (!wcSrc)
1010     {
1011         return MSVCRT_EINVAL;
1012     }
1013
1014     size = min(strlenW(wcSrc), count);
1015
1016     if (size >= numElement)
1017     {
1018         return MSVCRT_ERANGE;
1019     }
1020
1021     memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
1022     wcDest[size] = '\0';
1023
1024     return 0;
1025 }
1026
1027 /******************************************************************
1028  *              wcscat_s (MSVCRT.@)
1029  *
1030  */
1031 INT CDECL MSVCRT_wcscat_s(MSVCRT_wchar_t* dst, MSVCRT_size_t elem, const MSVCRT_wchar_t* src)
1032 {
1033     MSVCRT_wchar_t* ptr = dst;
1034
1035     if (!dst || elem == 0) return MSVCRT_EINVAL;
1036     if (!src)
1037     {
1038         dst[0] = '\0';
1039         return MSVCRT_EINVAL;
1040     }
1041
1042     /* seek to end of dst string (or elem if no end of string is found */
1043     while (ptr < dst + elem && *ptr != '\0') ptr++;
1044     while (ptr < dst + elem)
1045     {
1046         if ((*ptr++ = *src++) == '\0') return 0;
1047     }
1048     /* not enough space */
1049     dst[0] = '\0';
1050     return MSVCRT_ERANGE;
1051 }
1052
1053 /*********************************************************************
1054  *  wcsncat_s (MSVCRT.@)
1055  *
1056  */
1057 INT CDECL MSVCRT_wcsncat_s(MSVCRT_wchar_t *dst, MSVCRT_size_t elem,
1058         const MSVCRT_wchar_t *src, MSVCRT_size_t count)
1059 {
1060     MSVCRT_size_t srclen;
1061     MSVCRT_wchar_t dststart;
1062     INT ret = 0;
1063
1064     if (!MSVCRT_CHECK_PMT(dst != NULL) || !MSVCRT_CHECK_PMT(elem > 0))
1065     {
1066         *MSVCRT__errno() = MSVCRT_EINVAL;
1067         return MSVCRT_EINVAL;
1068     }
1069     if (!MSVCRT_CHECK_PMT(src != NULL || count == 0))
1070         return MSVCRT_EINVAL;
1071     if (count == 0)
1072         return 0;
1073
1074     for (dststart = 0; dststart < elem; dststart++)
1075     {
1076         if (dst[dststart] == '\0')
1077             break;
1078     }
1079     if (dststart == elem)
1080     {
1081         MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n");
1082         return MSVCRT_EINVAL;
1083     }
1084
1085     if (count == MSVCRT__TRUNCATE)
1086     {
1087         srclen = strlenW(src);
1088         if (srclen >= (elem - dststart))
1089         {
1090             srclen = elem - dststart - 1;
1091             ret = MSVCRT_STRUNCATE;
1092         }
1093     }
1094     else
1095         srclen = min(strlenW(src), count);
1096     if (srclen < (elem - dststart))
1097     {
1098         memcpy(&dst[dststart], src, srclen*sizeof(MSVCRT_wchar_t));
1099         dst[dststart+srclen] = '\0';
1100         return ret;
1101     }
1102     MSVCRT_INVALID_PMT("dst[elem] is too small");
1103     dst[0] = '\0';
1104     return MSVCRT_ERANGE;
1105 }
1106
1107 /*********************************************************************
1108  *  _wcstoi64_l (MSVCRT.@)
1109  *
1110  * FIXME: locale parameter is ignored
1111  */
1112 __int64 CDECL MSVCRT__wcstoi64_l(const MSVCRT_wchar_t *nptr,
1113         MSVCRT_wchar_t **endptr, int base, MSVCRT__locale_t locale)
1114 {
1115     BOOL negative = FALSE;
1116     __int64 ret = 0;
1117
1118     TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
1119
1120     if (!MSVCRT_CHECK_PMT(nptr != NULL) || !MSVCRT_CHECK_PMT(base == 0 || base >= 2) ||
1121         !MSVCRT_CHECK_PMT(base <= 36)) {
1122         *MSVCRT__errno() = MSVCRT_EINVAL;
1123         return 0;
1124     }
1125
1126     while(isspaceW(*nptr)) nptr++;
1127
1128     if(*nptr == '-') {
1129         negative = TRUE;
1130         nptr++;
1131     } else if(*nptr == '+')
1132         nptr++;
1133
1134     if((base==0 || base==16) && *nptr=='0' && tolowerW(*(nptr+1))=='x') {
1135         base = 16;
1136         nptr += 2;
1137     }
1138
1139     if(base == 0) {
1140         if(*nptr=='0')
1141             base = 8;
1142         else
1143             base = 10;
1144     }
1145
1146     while(*nptr) {
1147         char cur = tolowerW(*nptr);
1148         int v;
1149
1150         if(isdigitW(cur)) {
1151             if(cur >= '0'+base)
1152                 break;
1153             v = cur-'0';
1154         } else {
1155             if(cur<'a' || cur>='a'+base-10)
1156                 break;
1157             v = cur-'a'+10;
1158         }
1159
1160         if(negative)
1161             v = -v;
1162
1163         nptr++;
1164
1165         if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
1166             ret = MSVCRT_I64_MAX;
1167             *MSVCRT__errno() = MSVCRT_ERANGE;
1168         } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
1169             ret = MSVCRT_I64_MIN;
1170             *MSVCRT__errno() = MSVCRT_ERANGE;
1171         } else
1172             ret = ret*base + v;
1173     }
1174
1175     if(endptr)
1176         *endptr = (MSVCRT_wchar_t*)nptr;
1177
1178     return ret;
1179 }
1180
1181 /*********************************************************************
1182  *  _wcstoi64 (MSVCRT.@)
1183  */
1184 __int64 CDECL MSVCRT__wcstoi64(const MSVCRT_wchar_t *nptr,
1185         MSVCRT_wchar_t **endptr, int base)
1186 {
1187     return MSVCRT__wcstoi64_l(nptr, endptr, base, NULL);
1188 }
1189
1190 /*********************************************************************
1191  *  _wcstoui64_l (MSVCRT.@)
1192  *
1193  * FIXME: locale parameter is ignored
1194  */
1195 unsigned __int64 CDECL MSVCRT__wcstoui64_l(const MSVCRT_wchar_t *nptr,
1196         MSVCRT_wchar_t **endptr, int base, MSVCRT__locale_t locale)
1197 {
1198     BOOL negative = FALSE;
1199     unsigned __int64 ret = 0;
1200
1201     TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
1202
1203     if (!MSVCRT_CHECK_PMT(nptr != NULL) || !MSVCRT_CHECK_PMT(base == 0 || base >= 2) ||
1204         !MSVCRT_CHECK_PMT(base <= 36)) {
1205         *MSVCRT__errno() = MSVCRT_EINVAL;
1206         return 0;
1207     }
1208
1209     while(isspaceW(*nptr)) nptr++;
1210
1211     if(*nptr == '-') {
1212         negative = TRUE;
1213         nptr++;
1214     } else if(*nptr == '+')
1215         nptr++;
1216
1217     if((base==0 || base==16) && *nptr=='0' && tolowerW(*(nptr+1))=='x') {
1218         base = 16;
1219         nptr += 2;
1220     }
1221
1222     if(base == 0) {
1223         if(*nptr=='0')
1224             base = 8;
1225         else
1226             base = 10;
1227     }
1228
1229     while(*nptr) {
1230         char cur = tolowerW(*nptr);
1231         int v;
1232
1233         if(isdigit(cur)) {
1234             if(cur >= '0'+base)
1235                 break;
1236             v = *nptr-'0';
1237         } else {
1238             if(cur<'a' || cur>='a'+base-10)
1239                 break;
1240             v = cur-'a'+10;
1241         }
1242
1243         nptr++;
1244
1245         if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1246             ret = MSVCRT_UI64_MAX;
1247             *MSVCRT__errno() = MSVCRT_ERANGE;
1248         } else
1249             ret = ret*base + v;
1250     }
1251
1252     if(endptr)
1253         *endptr = (MSVCRT_wchar_t*)nptr;
1254
1255     return negative ? -ret : ret;
1256 }
1257
1258 /*********************************************************************
1259  *  _wcstoui64 (MSVCRT.@)
1260  */
1261 unsigned __int64 CDECL MSVCRT__wcstoui64(const MSVCRT_wchar_t *nptr,
1262         MSVCRT_wchar_t **endptr, int base)
1263 {
1264     return MSVCRT__wcstoui64_l(nptr, endptr, base, NULL);
1265 }
1266
1267 /******************************************************************
1268  *  wcsnlen (MSVCRT.@)
1269  */
1270 MSVCRT_size_t CDECL MSVCRT_wcsnlen(const MSVCRT_wchar_t *s, MSVCRT_size_t maxlen)
1271 {
1272     MSVCRT_size_t i;
1273
1274     for (i = 0; i < maxlen; i++)
1275         if (!s[i]) break;
1276     return i;
1277 }