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