[CRT]
[reactos.git] / lib / sdk / crt / string / wcs.c
1 /*
2 * PROJECT: ReactOS CRT library
3 * LICENSE: LGPL - See COPYING in the top level directory
4 * FILE: lib/sdk/crt/string/wcs.c
5 * PURPOSE: wcs* CRT functions
6 * PROGRAMMERS: Wine team
7 * Ported to ReactOS by Aleksey Bragin (aleksey@reactos.org)
8 */
9
10 /*
11 * msvcrt.dll wide-char functions
12 *
13 * Copyright 1999 Alexandre Julliard
14 * Copyright 2000 Jon Griffiths
15 *
16 * This library is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU Lesser General Public
18 * License as published by the Free Software Foundation; either
19 * version 2.1 of the License, or (at your option) any later version.
20 *
21 * This library is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * Lesser General Public License for more details.
25 *
26 * You should have received a copy of the GNU Lesser General Public
27 * License along with this library; if not, write to the Free Software
28 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
29 */
30 #include <precomp.h>
31 #include <assert.h>
32
33 #ifndef _LIBCNT_
34 #include <internal/wine/msvcrt.h>
35 #endif
36
37 #include "wine/unicode.h"
38 //#include "wine/debug.h"
39
40
41 //WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
42
43 #undef sprintf
44 #undef wsprintf
45 #undef snprintf
46 #undef vsnprintf
47 #undef vprintf
48 #undef vwprintf
49
50 #ifdef _MSC_VER
51 #pragma function(_wcsset)
52 #endif
53
54 #ifndef _LIBCNT_
55 /*********************************************************************
56 * _wcsdup (MSVCRT.@)
57 */
58 wchar_t* CDECL _wcsdup( const wchar_t* str )
59 {
60 wchar_t* ret = NULL;
61 if (str)
62 {
63 int size = (strlenW(str) + 1) * sizeof(wchar_t);
64 ret = malloc( size );
65 if (ret) memcpy( ret, str, size );
66 }
67 return ret;
68 }
69 /*********************************************************************
70 * _wcsicoll (MSVCRT.@)
71 */
72 INT CDECL _wcsicoll( const wchar_t* str1, const wchar_t* str2 )
73 {
74 /* FIXME: handle collates */
75 return strcmpiW( str1, str2 );
76 }
77 #endif
78
79 /*********************************************************************
80 * _wcsnset (MSVCRT.@)
81 */
82 wchar_t* CDECL _wcsnset( wchar_t* str, wchar_t c, size_t n )
83 {
84 wchar_t* ret = str;
85 while ((n-- > 0) && *str) *str++ = c;
86 return ret;
87 }
88
89 /*********************************************************************
90 * _wcsrev (MSVCRT.@)
91 */
92 wchar_t* CDECL _wcsrev( wchar_t* str )
93 {
94 wchar_t* ret = str;
95 wchar_t* end = str + strlenW(str) - 1;
96 while (end > str)
97 {
98 wchar_t t = *end;
99 *end-- = *str;
100 *str++ = t;
101 }
102 return ret;
103 }
104
105 #ifndef _LIBCNT_
106 /*********************************************************************
107 * _wcsset (MSVCRT.@)
108 */
109 wchar_t* CDECL _wcsset( wchar_t* str, wchar_t c )
110 {
111 wchar_t* ret = str;
112 while (*str) *str++ = c;
113 return ret;
114 }
115
116 /******************************************************************
117 * _wcsupr_s (MSVCRT.@)
118 *
119 */
120 INT CDECL _wcsupr_s( wchar_t* str, size_t n )
121 {
122 wchar_t* ptr = str;
123
124 if (!str || !n)
125 {
126 if (str) *str = '\0';
127 __set_errno(EINVAL);
128 return EINVAL;
129 }
130
131 while (n--)
132 {
133 if (!*ptr) return 0;
134 *ptr = toupperW(*ptr);
135 ptr++;
136 }
137
138 /* MSDN claims that the function should return and set errno to
139 * ERANGE, which doesn't seem to be true based on the tests. */
140 *str = '\0';
141 __set_errno(EINVAL);
142 return EINVAL;
143 }
144
145 /*********************************************************************
146 * wcstod (MSVCRT.@)
147 */
148 double CDECL wcstod(const wchar_t* lpszStr, wchar_t** end)
149 {
150 const wchar_t* str = lpszStr;
151 int negative = 0;
152 double ret = 0, divisor = 10.0;
153
154 TRACE("(%s,%p) semi-stub\n", debugstr_w(lpszStr), end);
155
156 /* FIXME:
157 * - Should set errno on failure
158 * - Should fail on overflow
159 * - Need to check which input formats are allowed
160 */
161 while (isspaceW(*str))
162 str++;
163
164 if (*str == '-')
165 {
166 negative = 1;
167 str++;
168 }
169
170 while (isdigitW(*str))
171 {
172 ret = ret * 10.0 + (*str - '0');
173 str++;
174 }
175 if (*str == '.')
176 str++;
177 while (isdigitW(*str))
178 {
179 ret = ret + (*str - '0') / divisor;
180 divisor *= 10;
181 str++;
182 }
183
184 if (*str == 'E' || *str == 'e' || *str == 'D' || *str == 'd')
185 {
186 int negativeExponent = 0;
187 int exponent = 0;
188 if (*(++str) == '-')
189 {
190 negativeExponent = 1;
191 str++;
192 }
193 while (isdigitW(*str))
194 {
195 exponent = exponent * 10 + (*str - '0');
196 str++;
197 }
198 if (exponent != 0)
199 {
200 if (negativeExponent)
201 ret = ret / pow(10.0, exponent);
202 else
203 ret = ret * pow(10.0, exponent);
204 }
205 }
206
207 if (negative)
208 ret = -ret;
209
210 if (end)
211 *end = (wchar_t*)str;
212
213 TRACE("returning %g\n", ret);
214 return ret;
215 }
216
217 typedef struct pf_output_t
218 {
219 int used;
220 int len;
221 BOOL unicode;
222 union {
223 LPWSTR W;
224 LPSTR A;
225 } buf;
226 } pf_output;
227
228 typedef struct pf_flags_t
229 {
230 char Sign, LeftAlign, Alternate, PadZero;
231 int FieldLength, Precision;
232 char IntegerLength, IntegerDouble;
233 char WideString;
234 char Format;
235 } pf_flags;
236
237 /*
238 * writes a string of characters to the output
239 * returns -1 if the string doesn't fit in the output buffer
240 * return the length of the string if all characters were written
241 */
242 static inline int pf_output_stringW( pf_output *out, LPCWSTR str, int len )
243 {
244 int space = out->len - out->used;
245
246 if( len < 0 )
247 len = strlenW( str );
248 if( out->unicode )
249 {
250 LPWSTR p = out->buf.W + out->used;
251
252 if( space >= len )
253 {
254 memcpy( p, str, len*sizeof(WCHAR) );
255 out->used += len;
256 return len;
257 }
258 if( space > 0 )
259 memcpy( p, str, space*sizeof(WCHAR) );
260 out->used += len;
261 }
262 else
263 {
264 int n = WideCharToMultiByte( CP_ACP, 0, str, len, NULL, 0, NULL, NULL );
265 LPSTR p = out->buf.A + out->used;
266
267 if( space >= n )
268 {
269 WideCharToMultiByte( CP_ACP, 0, str, len, p, n, NULL, NULL );
270 out->used += n;
271 return len;
272 }
273 if( space > 0 )
274 WideCharToMultiByte( CP_ACP, 0, str, len, p, space, NULL, NULL );
275 out->used += n;
276 }
277 return -1;
278 }
279
280 static inline int pf_output_stringA( pf_output *out, LPCSTR str, int len )
281 {
282 int space = out->len - out->used;
283
284 if( len < 0 )
285 len = strlen( str );
286 if( !out->unicode )
287 {
288 LPSTR p = out->buf.A + out->used;
289
290 if( space >= len )
291 {
292 memcpy( p, str, len );
293 out->used += len;
294 return len;
295 }
296 if( space > 0 )
297 memcpy( p, str, space );
298 out->used += len;
299 }
300 else
301 {
302 int n = MultiByteToWideChar( CP_ACP, 0, str, len, NULL, 0 );
303 LPWSTR p = out->buf.W + out->used;
304
305 if( space >= n )
306 {
307 MultiByteToWideChar( CP_ACP, 0, str, len, p, n );
308 out->used += n;
309 return len;
310 }
311 if( space > 0 )
312 MultiByteToWideChar( CP_ACP, 0, str, len, p, space );
313 out->used += n;
314 }
315 return -1;
316 }
317
318 /* pf_fill: takes care of signs, alignment, zero and field padding */
319 static inline int pf_fill( pf_output *out, int len, pf_flags *flags, char left )
320 {
321 int i, r = 0;
322
323 if( flags->Sign && !( flags->Format == 'd' || flags->Format == 'i' ) )
324 flags->Sign = 0;
325
326 if( left && flags->Sign )
327 {
328 flags->FieldLength--;
329 if( flags->PadZero )
330 r = pf_output_stringA( out, &flags->Sign, 1 );
331 }
332
333 if( ( !left && flags->LeftAlign ) ||
334 ( left && !flags->LeftAlign ))
335 {
336 for( i=0; (i<(flags->FieldLength-len)) && (r>=0); i++ )
337 {
338 if( left && flags->PadZero )
339 r = pf_output_stringA( out, "0", 1 );
340 else
341 r = pf_output_stringA( out, " ", 1 );
342 }
343 }
344
345 if( left && flags->Sign && !flags->PadZero )
346 r = pf_output_stringA( out, &flags->Sign, 1 );
347
348 return r;
349 }
350
351 static inline int pf_output_format_W( pf_output *out, LPCWSTR str,
352 int len, pf_flags *flags )
353 {
354 int r = 0;
355
356 if( len < 0 )
357 len = strlenW( str );
358
359 if (flags->Precision >= 0 && flags->Precision < len)
360 len = flags->Precision;
361
362 r = pf_fill( out, len, flags, 1 );
363
364 if( r>=0 )
365 r = pf_output_stringW( out, str, len );
366
367 if( r>=0 )
368 r = pf_fill( out, len, flags, 0 );
369
370 return r;
371 }
372
373 static inline int pf_output_format_A( pf_output *out, LPCSTR str,
374 int len, pf_flags *flags )
375 {
376 int r = 0;
377
378 if( len < 0 )
379 len = strlen( str );
380
381 if (flags->Precision >= 0 && flags->Precision < len)
382 len = flags->Precision;
383
384 r = pf_fill( out, len, flags, 1 );
385
386 if( r>=0 )
387 r = pf_output_stringA( out, str, len );
388
389 if( r>=0 )
390 r = pf_fill( out, len, flags, 0 );
391
392 return r;
393 }
394
395 static int pf_handle_string_format( pf_output *out, const void* str, int len,
396 pf_flags *flags, BOOL capital_letter)
397 {
398 if(str == NULL) /* catch NULL pointer */
399 return pf_output_format_A( out, "(null)", -1, flags);
400
401 /* prefixes take priority over %c,%s vs. %C,%S, so we handle them first */
402 if(flags->WideString || flags->IntegerLength == 'l')
403 return pf_output_format_W( out, str, len, flags);
404 if(flags->IntegerLength == 'h')
405 return pf_output_format_A( out, str, len, flags);
406
407 /* %s,%c -> chars in ansi functions & wchars in unicode
408 * %S,%C -> wchars in ansi functions & chars in unicode */
409 if( capital_letter == out->unicode) /* either both TRUE or both FALSE */
410 return pf_output_format_A( out, str, len, flags);
411 else
412 return pf_output_format_W( out, str, len, flags);
413 }
414
415 static inline BOOL pf_is_integer_format( char fmt )
416 {
417 static const char float_fmts[] = "diouxX";
418 if (!fmt)
419 return FALSE;
420 return strchr( float_fmts, fmt ) ? TRUE : FALSE;
421 }
422
423 static inline BOOL pf_is_double_format( char fmt )
424 {
425 static const char float_fmts[] = "aeEfgG";
426 if (!fmt)
427 return FALSE;
428 return strchr( float_fmts, fmt ) ? TRUE : FALSE;
429 }
430
431 static inline BOOL pf_is_valid_format( char fmt )
432 {
433 static const char float_fmts[] = "acCdeEfgGinouxX";
434 if (!fmt)
435 return FALSE;
436 return strchr( float_fmts, fmt ) ? TRUE : FALSE;
437 }
438
439 static void pf_rebuild_format_string( char *p, pf_flags *flags )
440 {
441 *p++ = '%';
442 if( flags->Sign )
443 *p++ = flags->Sign;
444 if( flags->LeftAlign )
445 *p++ = flags->LeftAlign;
446 if( flags->Alternate )
447 *p++ = flags->Alternate;
448 if( flags->PadZero )
449 *p++ = flags->PadZero;
450 if( flags->FieldLength )
451 {
452 lnx_sprintf(p, "%d", flags->FieldLength);
453 p += strlen(p);
454 }
455 if( flags->Precision >= 0 )
456 {
457 lnx_sprintf(p, ".%d", flags->Precision);
458 p += strlen(p);
459 }
460 *p++ = flags->Format;
461 *p++ = 0;
462 }
463
464 /* pf_integer_conv: prints x to buf, including alternate formats and
465 additional precision digits, but not field characters or the sign */
466 static void pf_integer_conv( char *buf, unsigned int buf_len, pf_flags *flags,
467 LONGLONG x )
468 {
469 unsigned int base;
470 const char *digits;
471
472 int i, j, k;
473 char number[40], *tmp = number;
474
475 if( buf_len > sizeof number )
476 tmp = HeapAlloc( GetProcessHeap(), 0, buf_len );
477
478 base = 10;
479 if( flags->Format == 'o' )
480 base = 8;
481 else if( flags->Format == 'x' || flags->Format == 'X' )
482 base = 16;
483
484 if( flags->Format == 'X' )
485 digits = "0123456789ABCDEFX";
486 else
487 digits = "0123456789abcdefx";
488
489 if( x < 0 && ( flags->Format == 'd' || flags->Format == 'i' ) )
490 {
491 x = -x;
492 flags->Sign = '-';
493 }
494
495 /* Do conversion (backwards) */
496 i = 0;
497 if( x == 0 && flags->Precision )
498 tmp[i++] = '0';
499 else
500 while( x != 0 )
501 {
502 j = (ULONGLONG) x % base;
503 x = (ULONGLONG) x / base;
504 tmp[i++] = digits[j];
505 }
506 k = flags->Precision - i;
507 while( k-- > 0 )
508 tmp[i++] = '0';
509 if( flags->Alternate )
510 {
511 if( base == 16 )
512 {
513 tmp[i++] = digits[16];
514 tmp[i++] = '0';
515 }
516 else if( base == 8 && tmp[i-1] != '0' )
517 tmp[i++] = '0';
518 }
519
520 /* Reverse for buf */
521 j = 0;
522 while( i-- > 0 )
523 buf[j++] = tmp[i];
524 buf[j] = '\0';
525
526 /* Adjust precision so pf_fill won't truncate the number later */
527 flags->Precision = strlen( buf );
528
529 if( tmp != number )
530 HeapFree( GetProcessHeap(), 0, tmp );
531
532 return;
533 }
534
535 /*********************************************************************
536 * pf_vsnprintf (INTERNAL)
537 *
538 * implements both A and W vsnprintf functions
539 */
540 static int pf_vsnprintf( pf_output *out, const WCHAR *format, va_list valist )
541 {
542 int r;
543 LPCWSTR q, p = format;
544 pf_flags flags;
545
546 TRACE("format is %s\n",debugstr_w(format));
547 while (*p)
548 {
549 q = strchrW( p, '%' );
550
551 /* there's no % characters left, output the rest of the string */
552 if( !q )
553 {
554 r = pf_output_stringW(out, p, -1);
555 if( r<0 )
556 return r;
557 p += r;
558 continue;
559 }
560
561 /* there's characters before the %, output them */
562 if( q != p )
563 {
564 r = pf_output_stringW(out, p, q - p);
565 if( r<0 )
566 return r;
567 p = q;
568 }
569
570 /* we must be at a % now, skip over it */
571 assert( *p == '%' );
572 p++;
573
574 /* output a single % character */
575 if( *p == '%' )
576 {
577 r = pf_output_stringW(out, p++, 1);
578 if( r<0 )
579 return r;
580 continue;
581 }
582
583 /* parse the flags */
584 memset( &flags, 0, sizeof flags );
585 while (*p)
586 {
587 if( *p == '+' || *p == ' ' )
588 {
589 if ( flags.Sign != '+' )
590 flags.Sign = *p;
591 }
592 else if( *p == '-' )
593 flags.LeftAlign = *p;
594 else if( *p == '0' )
595 flags.PadZero = *p;
596 else if( *p == '#' )
597 flags.Alternate = *p;
598 else
599 break;
600 p++;
601 }
602
603 /* deal with the field width specifier */
604 flags.FieldLength = 0;
605 if( *p == '*' )
606 {
607 flags.FieldLength = va_arg( valist, int );
608 if (flags.FieldLength < 0)
609 {
610 flags.LeftAlign = '-';
611 flags.FieldLength = -flags.FieldLength;
612 }
613 p++;
614 }
615 else while( isdigit(*p) )
616 {
617 flags.FieldLength *= 10;
618 flags.FieldLength += *p++ - '0';
619 }
620
621 /* deal with precision */
622 flags.Precision = -1;
623 if( *p == '.' )
624 {
625 flags.Precision = 0;
626 p++;
627 if( *p == '*' )
628 {
629 flags.Precision = va_arg( valist, int );
630 p++;
631 }
632 else while( isdigit(*p) )
633 {
634 flags.Precision *= 10;
635 flags.Precision += *p++ - '0';
636 }
637 }
638
639 /* deal with integer width modifier */
640 while( *p )
641 {
642 if( *p == 'h' || *p == 'l' || *p == 'L' )
643 {
644 flags.IntegerLength = *p;
645 p++;
646 }
647 else if( *p == 'I' )
648 {
649 if( *(p+1) == '6' && *(p+2) == '4' )
650 {
651 flags.IntegerDouble++;
652 p += 3;
653 }
654 else if( *(p+1) == '3' && *(p+2) == '2' )
655 p += 3;
656 else if( isdigit(*(p+1)) || *(p+1) == 0 )
657 break;
658 else
659 p++;
660 }
661 else if( *p == 'w' )
662 flags.WideString = *p++;
663 else if( *p == 'F' )
664 p++; /* ignore */
665 else
666 break;
667 }
668
669 flags.Format = *p;
670 r = 0;
671
672 /* output a string */
673 if( flags.Format == 's' || flags.Format == 'S' )
674 r = pf_handle_string_format( out, va_arg(valist, const void*), -1,
675 &flags, (flags.Format == 'S') );
676
677 /* output a single character */
678 else if( flags.Format == 'c' || flags.Format == 'C' )
679 {
680 INT ch = va_arg( valist, int );
681
682 r = pf_handle_string_format( out, &ch, 1, &flags, (flags.Format == 'C') );
683 }
684
685 /* output a pointer */
686 else if( flags.Format == 'p' )
687 {
688 char pointer[11];
689
690 flags.PadZero = 0;
691 if( flags.Alternate )
692 lnx_sprintf(pointer, "0X%08lX", va_arg(valist, long));
693 else
694 lnx_sprintf(pointer, "%08lX", va_arg(valist, long));
695 r = pf_output_format_A( out, pointer, -1, &flags );
696 }
697
698 /* deal with %n */
699 else if( flags.Format == 'n' )
700 {
701 int *x = va_arg(valist, int *);
702 *x = out->used;
703 }
704
705 /* deal with 64-bit integers */
706 else if( pf_is_integer_format( flags.Format ) && flags.IntegerDouble )
707 {
708 char number[40], *x = number;
709
710 /* Estimate largest possible required buffer size:
711 * Chooses the larger of the field or precision
712 * Includes extra bytes: 1 byte for null, 1 byte for sign,
713 4 bytes for exponent, 2 bytes for alternate formats, 1 byte
714 for a decimal, and 1 byte for an additional float digit. */
715 unsigned x_len = ((flags.FieldLength > flags.Precision) ?
716 flags.FieldLength : flags.Precision) + 10;
717
718 if( x_len >= sizeof number)
719 x = HeapAlloc( GetProcessHeap(), 0, x_len );
720
721 pf_integer_conv( x, x_len, &flags, va_arg(valist, LONGLONG) );
722
723 r = pf_output_format_A( out, x, -1, &flags );
724 if( x != number )
725 HeapFree( GetProcessHeap(), 0, x );
726 }
727
728 /* deal with integers and floats using libc's printf */
729 else if( pf_is_valid_format( flags.Format ) )
730 {
731 char fmt[20], number[40], *x = number;
732
733 /* Estimate largest possible required buffer size:
734 * Chooses the larger of the field or precision
735 * Includes extra bytes: 1 byte for null, 1 byte for sign,
736 4 bytes for exponent, 2 bytes for alternate formats, 1 byte
737 for a decimal, and 1 byte for an additional float digit. */
738 unsigned x_len = ((flags.FieldLength > flags.Precision) ?
739 flags.FieldLength : flags.Precision) + 10;
740
741 if( x_len >= sizeof number)
742 x = HeapAlloc( GetProcessHeap(), 0, x_len );
743
744 pf_rebuild_format_string( fmt, &flags );
745
746 if( pf_is_double_format( flags.Format ) )
747 lnx_sprintf( x, fmt, va_arg(valist, double) );
748 else
749 lnx_sprintf( x, fmt, va_arg(valist, int) );
750
751 r = pf_output_stringA( out, x, -1 );
752 if( x != number )
753 HeapFree( GetProcessHeap(), 0, x );
754 }
755 else
756 continue;
757
758 if( r<0 )
759 return r;
760 p++;
761 }
762
763 /* check we reached the end, and null terminate the string */
764 assert( *p == 0 );
765 pf_output_stringW( out, p, 1 );
766
767 return out->used - 1;
768 }
769
770 /*********************************************************************
771 * _vsnprintf (MSVCRT.@)
772 */
773 int CDECL _vsnprintf( char *str, size_t len,
774 const char *format, va_list valist )
775 {
776 DWORD sz;
777 LPWSTR formatW = NULL;
778 pf_output out;
779 int r;
780
781 out.unicode = FALSE;
782 out.buf.A = str;
783 out.used = 0;
784 out.len = len;
785
786 if( format )
787 {
788 sz = MultiByteToWideChar( CP_ACP, 0, format, -1, NULL, 0 );
789 formatW = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
790 MultiByteToWideChar( CP_ACP, 0, format, -1, formatW, sz );
791 }
792
793 r = pf_vsnprintf( &out, formatW, valist );
794
795 HeapFree( GetProcessHeap(), 0, formatW );
796
797 return r;
798 }
799
800 /*********************************************************************
801 * vsprintf (MSVCRT.@)
802 */
803 int CDECL vsprintf( char *str, const char *format, va_list valist)
804 {
805 return _vsnprintf(str, INT_MAX, format, valist);
806 }
807
808 /*********************************************************************
809 * _snprintf (MSVCRT.@)
810 */
811 int CDECL _snprintf(char *str, size_t len, const char *format, ...)
812 {
813 int retval;
814 va_list valist;
815 va_start(valist, format);
816 retval = _vsnprintf(str, len, format, valist);
817 va_end(valist);
818 return retval;
819 }
820
821 /*********************************************************************
822 * _vsnwsprintf (MSVCRT.@)
823 */
824 int CDECL _vsnwprintf( wchar_t *str, size_t len,
825 const wchar_t *format, va_list valist )
826 {
827 pf_output out;
828
829 out.unicode = TRUE;
830 out.buf.W = str;
831 out.used = 0;
832 out.len = len;
833
834 return pf_vsnprintf( &out, format, valist );
835 }
836
837 /*********************************************************************
838 * _snwprintf (MSVCRT.@)
839 */
840 int CDECL _snwprintf( wchar_t *str, size_t len, const wchar_t *format, ...)
841 {
842 int retval;
843 va_list valist;
844 va_start(valist, format);
845 retval = _vsnwprintf(str, len, format, valist);
846 va_end(valist);
847 return retval;
848 }
849
850 /*********************************************************************
851 * sprintf (MSVCRT.@)
852 */
853 int CDECL sprintf( char *str, const char *format, ... )
854 {
855 va_list ap;
856 int r;
857
858 va_start( ap, format );
859 r = _vsnprintf( str, INT_MAX, format, ap );
860 va_end( ap );
861 return r;
862 }
863
864 /*********************************************************************
865 * swprintf (MSVCRT.@)
866 */
867 int CDECL swprintf( wchar_t *str, const wchar_t *format, ... )
868 {
869 va_list ap;
870 int r;
871
872 va_start( ap, format );
873 r = _vsnwprintf( str, INT_MAX, format, ap );
874 va_end( ap );
875 return r;
876 }
877
878 /*********************************************************************
879 * vswprintf (MSVCRT.@)
880 */
881 int CDECL vswprintf( wchar_t* str, const wchar_t* format, va_list args )
882 {
883 return _vsnwprintf( str, INT_MAX, format, args );
884 }
885 #endif
886
887 /*********************************************************************
888 * wcscoll (MSVCRT.@)
889 */
890 int CDECL wcscoll( const wchar_t* str1, const wchar_t* str2 )
891 {
892 /* FIXME: handle collates */
893 return strcmpW( str1, str2 );
894 }
895
896 /*********************************************************************
897 * wcspbrk (MSVCRT.@)
898 */
899 wchar_t* CDECL wcspbrk( const wchar_t* str, const wchar_t* accept )
900 {
901 const wchar_t* p;
902 while (*str)
903 {
904 for (p = accept; *p; p++) if (*p == *str) return (wchar_t*)str;
905 str++;
906 }
907 return NULL;
908 }
909
910 #ifndef _LIBCNT_
911 /*********************************************************************
912 * wcstok (MSVCRT.@)
913 */
914 wchar_t * CDECL wcstok( wchar_t *str, const wchar_t *delim )
915 {
916 MSVCRT_thread_data *data = msvcrt_get_thread_data();
917 wchar_t *ret;
918
919 if (!str)
920 if (!(str = data->wcstok_next)) return NULL;
921
922 while (*str && strchrW( delim, *str )) str++;
923 if (!*str) return NULL;
924 ret = str++;
925 while (*str && !strchrW( delim, *str )) str++;
926 if (*str) *str++ = 0;
927 data->wcstok_next = str;
928 return ret;
929 }
930
931 /*********************************************************************
932 * wctomb (MSVCRT.@)
933 */
934 INT CDECL wctomb(char *mbchar, wchar_t wchar)
935 {
936 BOOL bUsedDefaultChar;
937 char chMultiByte[MB_LEN_MAX];
938 int nBytes;
939
940 /* At least one parameter needs to be given, the length of a null character cannot be queried (verified by tests under WinXP SP2) */
941 if(!mbchar && !wchar)
942 return 0;
943
944 /* Use WideCharToMultiByte for doing the conversion using the codepage currently set with setlocale() */
945 nBytes = WideCharToMultiByte(MSVCRT___lc_codepage, 0, &wchar, 1, chMultiByte, MB_LEN_MAX, NULL, &bUsedDefaultChar);
946
947 /* Only copy the character if an 'mbchar' pointer was given.
948
949 The "C" locale is emulated with codepage 1252 here. This codepage has a default character "?", but the "C" locale doesn't have one.
950 Therefore don't copy the character in this case. */
951 if(mbchar && !(MSVCRT_current_lc_all[0] == 'C' && !MSVCRT_current_lc_all[1] && bUsedDefaultChar))
952 memcpy(mbchar, chMultiByte, nBytes);
953
954 /* If the default character was used, set errno to EILSEQ and return -1. */
955 if(bUsedDefaultChar)
956 {
957 __set_errno(EILSEQ);
958 return -1;
959 }
960
961 /* Otherwise return the number of bytes this character occupies. */
962 return nBytes;
963 }
964
965 size_t CDECL wcstombs(char *mbstr, const wchar_t *wcstr, size_t count)
966 {
967 BOOL bUsedDefaultChar;
968 char* p = mbstr;
969 int nResult;
970
971 /* Does the caller query for output buffer size? */
972 if(!mbstr)
973 {
974 int nLength;
975
976 /* If we currently use the "C" locale, the length of the input string is returned (verified by tests under WinXP SP2) */
977 if(MSVCRT_current_lc_all[0] == 'C' && !MSVCRT_current_lc_all[1])
978 return wcslen(wcstr);
979
980 /* Otherwise check the length each character needs and build a final return value out of this */
981 count = wcslen(wcstr);
982 nLength = 0;
983
984 while((int)(--count) >= 0 && *wcstr)
985 {
986 /* Get the length of this character */
987 nResult = wctomb(NULL, *wcstr++);
988
989 /* If this character is not convertible in the current locale, the end result will be -1 */
990 if(nResult == -1)
991 return -1;
992
993 nLength += nResult;
994 }
995
996 /* Return the final length */
997 return nLength;
998 }
999
1000 /* Convert the string then */
1001 bUsedDefaultChar = FALSE;
1002
1003 for(;;)
1004 {
1005 char chMultiByte[MB_LEN_MAX];
1006 UINT uLength;
1007
1008 /* Are we at the terminating null character? */
1009 if(!*wcstr)
1010 {
1011 /* Set the null character, but don't increment the pointer as the returned length never includes the terminating null character */
1012 *p = 0;
1013 break;
1014 }
1015
1016 /* Convert this character into the temporary chMultiByte variable */
1017 ZeroMemory(chMultiByte, MB_LEN_MAX);
1018 nResult = wctomb(chMultiByte, *wcstr++);
1019
1020 /* Check if this was an invalid character */
1021 if(nResult == -1)
1022 bUsedDefaultChar = TRUE;
1023
1024 /* If we got no character, stop the conversion process here */
1025 if(!chMultiByte[0])
1026 break;
1027
1028 /* Determine whether this is a double-byte or a single-byte character */
1029 if(chMultiByte[1])
1030 uLength = 2;
1031 else
1032 uLength = 1;
1033
1034 /* Decrease 'count' by the character length and check if the buffer can still hold the full character */
1035 count -= uLength;
1036
1037 if((int)count < 0)
1038 break;
1039
1040 /* It can, so copy it and move the pointer forward */
1041 memcpy(p, chMultiByte, uLength);
1042 p += uLength;
1043 }
1044
1045 if(bUsedDefaultChar)
1046 return -1;
1047
1048 /* Return the length in bytes of the copied characters (without the terminating null character) */
1049 return p - mbstr;
1050 }
1051 #endif
1052
1053 #ifndef __REACTOS__
1054 /*********************************************************************
1055 * iswalnum (MSVCRT.@)
1056 */
1057 INT CDECL iswalnum( wchar_t wc )
1058 {
1059 return isalnumW( wc );
1060 }
1061
1062 /*********************************************************************
1063 * iswalpha (MSVCRT.@)
1064 */
1065 INT CDECL iswalpha( wchar_t wc )
1066 {
1067 return isalphaW( wc );
1068 }
1069
1070 /*********************************************************************
1071 * iswcntrl (MSVCRT.@)
1072 */
1073 INT CDECL iswcntrl( wchar_t wc )
1074 {
1075 return iscntrlW( wc );
1076 }
1077
1078 /*********************************************************************
1079 * iswdigit (MSVCRT.@)
1080 */
1081 INT CDECL iswdigit( wchar_t wc )
1082 {
1083 return isdigitW( wc );
1084 }
1085
1086 /*********************************************************************
1087 * iswgraph (MSVCRT.@)
1088 */
1089 INT CDECL iswgraph( wchar_t wc )
1090 {
1091 return isgraphW( wc );
1092 }
1093
1094 /*********************************************************************
1095 * iswlower (MSVCRT.@)
1096 */
1097 INT CDECL iswlower( wchar_t wc )
1098 {
1099 return islowerW( wc );
1100 }
1101
1102 /*********************************************************************
1103 * iswprint (MSVCRT.@)
1104 */
1105 INT CDECL iswprint( wchar_t wc )
1106 {
1107 return isprintW( wc );
1108 }
1109
1110 /*********************************************************************
1111 * iswpunct (MSVCRT.@)
1112 */
1113 INT CDECL iswpunct( wchar_t wc )
1114 {
1115 return ispunctW( wc );
1116 }
1117
1118 /*********************************************************************
1119 * iswspace (MSVCRT.@)
1120 */
1121 INT CDECL iswspace( wchar_t wc )
1122 {
1123 return isspaceW( wc );
1124 }
1125
1126 /*********************************************************************
1127 * iswupper (MSVCRT.@)
1128 */
1129 INT CDECL iswupper( wchar_t wc )
1130 {
1131 return isupperW( wc );
1132 }
1133
1134 /*********************************************************************
1135 * iswxdigit (MSVCRT.@)
1136 */
1137 INT CDECL iswxdigit( wchar_t wc )
1138 {
1139 return isxdigitW( wc );
1140 }
1141
1142 #endif
1143
1144 /*********************************************************************
1145 * wcscpy_s (MSVCRT.@)
1146 */
1147 INT CDECL wcscpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc)
1148 {
1149 INT size = 0;
1150
1151 if(!wcDest || !numElement)
1152 return EINVAL;
1153
1154 wcDest[0] = 0;
1155
1156 if(!wcSrc)
1157 {
1158 return EINVAL;
1159 }
1160
1161 size = strlenW(wcSrc) + 1;
1162
1163 if(size > numElement)
1164 {
1165 return ERANGE;
1166 }
1167
1168 memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
1169
1170 return 0;
1171 }
1172
1173 /******************************************************************
1174 * wcsncpy_s (MSVCRT.@)
1175 */
1176 INT CDECL wcsncpy_s( wchar_t* wcDest, size_t numElement, const wchar_t *wcSrc,
1177 size_t count )
1178 {
1179 size_t size = 0;
1180
1181 if (!wcDest || !numElement)
1182 return EINVAL;
1183
1184 wcDest[0] = 0;
1185
1186 if (!wcSrc)
1187 {
1188 return EINVAL;
1189 }
1190
1191 size = min(strlenW(wcSrc), count);
1192
1193 if (size >= numElement)
1194 {
1195 return ERANGE;
1196 }
1197
1198 memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
1199 wcDest[size] = '\0';
1200
1201 return 0;
1202 }
1203
1204