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