Revert "gdi32: Make AddFontToList skip adding a face into global lists if the font...
[wine.git] / dlls / msvcrt / wcs.c
blob48831b25d5de950063e52480edfd55eb4f273a97
1 /*
2 * msvcrt.dll wide-char functions
4 * Copyright 1999 Alexandre Julliard
5 * Copyright 2000 Jon Griffiths
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.
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.
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
21 #include "config.h"
22 #include "wine/port.h"
24 #include <limits.h>
25 #include <stdio.h>
26 #include <math.h>
27 #include <assert.h>
28 #include "msvcrt.h"
29 #include "winnls.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
36 /*********************************************************************
37 * _wcsdup (MSVCRT.@)
39 MSVCRT_wchar_t* CDECL _wcsdup( const MSVCRT_wchar_t* str )
41 MSVCRT_wchar_t* ret = NULL;
42 if (str)
44 int size = (strlenW(str) + 1) * sizeof(MSVCRT_wchar_t);
45 ret = MSVCRT_malloc( size );
46 if (ret) memcpy( ret, str, size );
48 return ret;
51 /*********************************************************************
52 * _wcsicoll (MSVCRT.@)
54 INT CDECL _wcsicoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
56 /* FIXME: handle collates */
57 return strcmpiW( str1, str2 );
60 /*********************************************************************
61 * _wcsnset (MSVCRT.@)
63 MSVCRT_wchar_t* CDECL MSVCRT__wcsnset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c, MSVCRT_size_t n )
65 MSVCRT_wchar_t* ret = str;
66 while ((n-- > 0) && *str) *str++ = c;
67 return ret;
70 /*********************************************************************
71 * _wcsrev (MSVCRT.@)
73 MSVCRT_wchar_t* CDECL _wcsrev( MSVCRT_wchar_t* str )
75 MSVCRT_wchar_t* ret = str;
76 MSVCRT_wchar_t* end = str + strlenW(str) - 1;
77 while (end > str)
79 MSVCRT_wchar_t t = *end;
80 *end-- = *str;
81 *str++ = t;
83 return ret;
86 /*********************************************************************
87 * _wcsset (MSVCRT.@)
89 MSVCRT_wchar_t* CDECL _wcsset( MSVCRT_wchar_t* str, MSVCRT_wchar_t c )
91 MSVCRT_wchar_t* ret = str;
92 while (*str) *str++ = c;
93 return ret;
96 /******************************************************************
97 * _wcsupr_s (MSVCRT.@)
100 INT CDECL MSVCRT__wcsupr_s( MSVCRT_wchar_t* str, MSVCRT_size_t n )
102 MSVCRT_wchar_t* ptr = str;
104 if (!str || !n)
106 if (str) *str = '\0';
107 *MSVCRT__errno() = MSVCRT_EINVAL;
108 return MSVCRT_EINVAL;
111 while (n--)
113 if (!*ptr) return 0;
114 *ptr = toupperW(*ptr);
115 ptr++;
118 /* MSDN claims that the function should return and set errno to
119 * ERANGE, which doesn't seem to be true based on the tests. */
120 *str = '\0';
121 *MSVCRT__errno() = MSVCRT_EINVAL;
122 return MSVCRT_EINVAL;
125 /*********************************************************************
126 * _wcstod_l - not exported in native msvcrt
128 double CDECL MSVCRT__wcstod_l(const MSVCRT_wchar_t* str, MSVCRT_wchar_t** end,
129 MSVCRT__locale_t locale)
131 unsigned __int64 d=0, hlp;
132 unsigned fpcontrol;
133 int exp=0, sign=1;
134 const MSVCRT_wchar_t *p;
135 double ret;
136 BOOL found_digit = FALSE;
138 if (!MSVCRT_CHECK_PMT(str != NULL)) {
139 *MSVCRT__errno() = MSVCRT_EINVAL;
140 return 0;
143 if(!locale)
144 locale = get_locale();
146 p = str;
147 while(isspaceW(*p))
148 p++;
150 if(*p == '-') {
151 sign = -1;
152 p++;
153 } else if(*p == '+')
154 p++;
156 while(isdigitW(*p)) {
157 found_digit = TRUE;
158 hlp = d*10+*(p++)-'0';
159 if(d>MSVCRT_UI64_MAX/10 || hlp<d) {
160 exp++;
161 break;
162 } else
163 d = hlp;
165 while(isdigitW(*p)) {
166 exp++;
167 p++;
169 if(*p == *locale->locinfo->lconv->decimal_point)
170 p++;
172 while(isdigitW(*p)) {
173 found_digit = TRUE;
174 hlp = d*10+*(p++)-'0';
175 if(d>MSVCRT_UI64_MAX/10 || hlp<d)
176 break;
178 d = hlp;
179 exp--;
181 while(isdigitW(*p))
182 p++;
184 if(!found_digit) {
185 if(end)
186 *end = (MSVCRT_wchar_t*)str;
187 return 0.0;
190 if(*p=='e' || *p=='E' || *p=='d' || *p=='D') {
191 int e=0, s=1;
193 p++;
194 if(*p == '-') {
195 s = -1;
196 p++;
197 } else if(*p == '+')
198 p++;
200 if(isdigitW(*p)) {
201 while(isdigitW(*p)) {
202 if(e>INT_MAX/10 || (e=e*10+*p-'0')<0)
203 e = INT_MAX;
204 p++;
206 e *= s;
208 if(exp<0 && e<0 && exp+e>=0) exp = INT_MIN;
209 else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
210 else exp += e;
211 } else {
212 if(*p=='-' || *p=='+')
213 p--;
214 p--;
218 fpcontrol = _control87(0, 0);
219 _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE
220 |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff);
222 if(exp>0)
223 ret = (double)sign*d*pow(10, exp);
224 else
225 ret = (double)sign*d/pow(10, -exp);
227 _control87(fpcontrol, 0xffffffff);
229 if((d && ret==0.0) || isinf(ret))
230 *MSVCRT__errno() = MSVCRT_ERANGE;
232 if(end)
233 *end = (MSVCRT_wchar_t*)p;
235 return ret;
238 /*********************************************************************
239 * _wcstombs_l (MSVCRT.@)
241 MSVCRT_size_t CDECL MSVCRT__wcstombs_l(char *mbstr, const MSVCRT_wchar_t *wcstr,
242 MSVCRT_size_t count, MSVCRT__locale_t locale)
244 char default_char = '\0';
245 MSVCRT_size_t tmp = 0;
246 BOOL used_default;
248 if(!locale)
249 locale = get_locale();
251 if(!mbstr)
252 return WideCharToMultiByte(locale->locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
253 wcstr, -1, NULL, 0, &default_char, &used_default)-1;
255 while(*wcstr) {
256 char buf[3];
257 MSVCRT_size_t i, size;
259 size = WideCharToMultiByte(locale->locinfo->lc_codepage, WC_NO_BEST_FIT_CHARS,
260 wcstr, 1, buf, 3, &default_char, &used_default);
261 if(used_default)
262 return -1;
263 if(tmp+size > count)
264 return tmp;
266 for(i=0; i<size; i++)
267 mbstr[tmp++] = buf[i];
268 wcstr++;
271 if(tmp < count)
272 mbstr[tmp] = '\0';
273 return tmp;
276 /*********************************************************************
277 * wcstombs (MSVCRT.@)
279 MSVCRT_size_t CDECL MSVCRT_wcstombs(char *mbstr, const MSVCRT_wchar_t *wcstr,
280 MSVCRT_size_t count)
282 return MSVCRT__wcstombs_l(mbstr, wcstr, count, NULL);
285 /*********************************************************************
286 * _wcstombs_s_l (MSVCRT.@)
288 MSVCRT_size_t CDECL MSVCRT__wcstombs_s_l(MSVCRT_size_t *ret, char *mbstr,
289 MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr,
290 MSVCRT_size_t count, MSVCRT__locale_t locale)
292 MSVCRT_size_t conv;
294 if(!mbstr && !size) {
295 conv = MSVCRT__wcstombs_l(NULL, wcstr, 0, locale);
296 if(ret)
297 *ret = conv;
298 return 0;
301 if (!MSVCRT_CHECK_PMT(wcstr != NULL) || !MSVCRT_CHECK_PMT(mbstr != NULL)) {
302 if(mbstr && size)
303 mbstr[0] = '\0';
304 *MSVCRT__errno() = MSVCRT_EINVAL;
305 return MSVCRT_EINVAL;
308 if(count==MSVCRT__TRUNCATE || size<count)
309 conv = size;
310 else
311 conv = count;
313 conv = MSVCRT__wcstombs_l(mbstr, wcstr, conv, locale);
314 if(conv<size)
315 mbstr[conv++] = '\0';
316 else if(conv==size && (count==MSVCRT__TRUNCATE || mbstr[conv-1]=='\0'))
317 mbstr[conv-1] = '\0';
318 else {
319 MSVCRT_INVALID_PMT("mbstr[size] is too small");
320 if(size)
321 mbstr[0] = '\0';
322 *MSVCRT__errno() = MSVCRT_ERANGE;
323 return MSVCRT_ERANGE;
326 if(ret)
327 *ret = conv;
328 return 0;
331 /*********************************************************************
332 * wcstombs_s (MSVCRT.@)
334 MSVCRT_size_t CDECL MSVCRT_wcstombs_s(MSVCRT_size_t *ret, char *mbstr,
335 MSVCRT_size_t size, const MSVCRT_wchar_t *wcstr, MSVCRT_size_t count)
337 return MSVCRT__wcstombs_s_l(ret, mbstr, size, wcstr, count, NULL);
340 /*********************************************************************
341 * wcstod (MSVCRT.@)
343 double CDECL MSVCRT_wcstod(const MSVCRT_wchar_t* lpszStr, MSVCRT_wchar_t** end)
345 return MSVCRT__wcstod_l(lpszStr, end, NULL);
348 /*********************************************************************
349 * _wtof (MSVCRT.@)
351 double CDECL MSVCRT__wtof(const MSVCRT_wchar_t *str)
353 return MSVCRT__wcstod_l(str, NULL, NULL);
356 /*********************************************************************
357 * _wtof_l (MSVCRT.@)
359 double CDECL MSVCRT__wtof_l(const MSVCRT_wchar_t *str, MSVCRT__locale_t locale)
361 return MSVCRT__wcstod_l(str, NULL, locale);
364 typedef struct pf_output_t
366 int used;
367 int len;
368 BOOL unicode;
369 union {
370 LPWSTR W;
371 LPSTR A;
372 } buf;
373 } pf_output;
375 typedef struct pf_flags_t
377 char Sign, LeftAlign, Alternate, PadZero;
378 int FieldLength, Precision;
379 char IntegerLength, IntegerDouble;
380 char WideString;
381 char Format;
382 } pf_flags;
385 * writes a string of characters to the output
386 * returns -1 if the string doesn't fit in the output buffer
387 * return the length of the string if all characters were written
389 static inline int pf_output_stringW( pf_output *out, LPCWSTR str, int len )
391 int space = out->len - out->used;
393 if( len < 0 )
394 len = strlenW( str );
395 if( out->unicode )
397 LPWSTR p = out->buf.W + out->used;
399 if( space >= len )
401 if (out->buf.W) memcpy( p, str, len*sizeof(WCHAR) );
402 out->used += len;
403 return len;
405 if( space > 0 && out->buf.W )
406 memcpy( p, str, space*sizeof(WCHAR) );
407 out->used += len;
409 else
411 int n = WideCharToMultiByte( CP_ACP, 0, str, len, NULL, 0, NULL, NULL );
412 LPSTR p = out->buf.A + out->used;
414 if( space >= n )
416 if (out->buf.A) WideCharToMultiByte( CP_ACP, 0, str, len, p, n, NULL, NULL );
417 out->used += n;
418 return len;
420 if( space > 0 && out->buf.A )
421 WideCharToMultiByte( CP_ACP, 0, str, len, p, space, NULL, NULL );
422 out->used += n;
424 return -1;
427 static inline int pf_output_stringA( pf_output *out, LPCSTR str, int len )
429 int space = out->len - out->used;
431 if( len < 0 )
432 len = strlen( str );
433 if( !out->unicode )
435 LPSTR p = out->buf.A + out->used;
437 if( space >= len )
439 if (out->buf.A) memcpy( p, str, len );
440 out->used += len;
441 return len;
443 if( space > 0 && out->buf.A )
444 memcpy( p, str, space );
445 out->used += len;
447 else
449 int n = MultiByteToWideChar( CP_ACP, 0, str, len, NULL, 0 );
450 LPWSTR p = out->buf.W + out->used;
452 if( space >= n )
454 if (out->buf.W) MultiByteToWideChar( CP_ACP, 0, str, len, p, n );
455 out->used += n;
456 return len;
458 if( space > 0 && out->buf.W )
459 MultiByteToWideChar( CP_ACP, 0, str, len, p, space );
460 out->used += n;
462 return -1;
465 /* pf_fill: takes care of signs, alignment, zero and field padding */
466 static inline int pf_fill( pf_output *out, int len, pf_flags *flags, char left )
468 int i, r = 0;
470 if( flags->Sign && !( flags->Format == 'd' || flags->Format == 'i' ) )
471 flags->Sign = 0;
473 if( left && flags->Sign )
475 flags->FieldLength--;
476 if( flags->PadZero )
477 r = pf_output_stringA( out, &flags->Sign, 1 );
480 if( ( !left && flags->LeftAlign ) ||
481 ( left && !flags->LeftAlign ))
483 for( i=0; (i<(flags->FieldLength-len)) && (r>=0); i++ )
485 if( left && flags->PadZero )
486 r = pf_output_stringA( out, "0", 1 );
487 else
488 r = pf_output_stringA( out, " ", 1 );
492 if( left && flags->Sign && !flags->PadZero )
493 r = pf_output_stringA( out, &flags->Sign, 1 );
495 return r;
498 static inline int pf_output_format_W( pf_output *out, LPCWSTR str,
499 int len, pf_flags *flags )
501 int r = 0;
503 if( len < 0 )
504 len = strlenW( str );
506 if (flags->Precision >= 0 && flags->Precision < len)
507 len = flags->Precision;
509 r = pf_fill( out, len, flags, 1 );
511 if( r>=0 )
512 r = pf_output_stringW( out, str, len );
514 if( r>=0 )
515 r = pf_fill( out, len, flags, 0 );
517 return r;
520 static inline int pf_output_format_A( pf_output *out, LPCSTR str,
521 int len, pf_flags *flags )
523 int r = 0;
525 if( len < 0 )
526 len = strlen( str );
528 if (flags->Precision >= 0 && flags->Precision < len)
529 len = flags->Precision;
531 r = pf_fill( out, len, flags, 1 );
533 if( r>=0 )
534 r = pf_output_stringA( out, str, len );
536 if( r>=0 )
537 r = pf_fill( out, len, flags, 0 );
539 return r;
542 static int pf_handle_string_format( pf_output *out, const void* str, int len,
543 pf_flags *flags, BOOL capital_letter)
545 if(str == NULL) /* catch NULL pointer */
546 return pf_output_format_A( out, "(null)", -1, flags);
548 /* prefixes take priority over %c,%s vs. %C,%S, so we handle them first */
549 if(flags->WideString || flags->IntegerLength == 'l')
550 return pf_output_format_W( out, str, len, flags);
551 if(flags->IntegerLength == 'h')
552 return pf_output_format_A( out, str, len, flags);
554 /* %s,%c -> chars in ansi functions & wchars in unicode
555 * %S,%C -> wchars in ansi functions & chars in unicode */
556 if( capital_letter == out->unicode) /* either both TRUE or both FALSE */
557 return pf_output_format_A( out, str, len, flags);
558 else
559 return pf_output_format_W( out, str, len, flags);
562 static inline BOOL pf_is_integer_format( char fmt )
564 static const char float_fmts[] = "diouxX";
565 if (!fmt)
566 return FALSE;
567 return strchr( float_fmts, fmt ) ? TRUE : FALSE;
570 static inline BOOL pf_is_double_format( char fmt )
572 static const char float_fmts[] = "aeEfgG";
573 if (!fmt)
574 return FALSE;
575 return strchr( float_fmts, fmt ) ? TRUE : FALSE;
578 static inline BOOL pf_is_valid_format( char fmt )
580 static const char float_fmts[] = "acCdeEfgGinouxX";
581 if (!fmt)
582 return FALSE;
583 return strchr( float_fmts, fmt ) ? TRUE : FALSE;
586 static void pf_rebuild_format_string( char *p, pf_flags *flags )
588 *p++ = '%';
589 if( flags->Sign )
590 *p++ = flags->Sign;
591 if( flags->LeftAlign )
592 *p++ = flags->LeftAlign;
593 if( flags->Alternate )
594 *p++ = flags->Alternate;
595 if( flags->PadZero )
596 *p++ = flags->PadZero;
597 if( flags->FieldLength )
599 sprintf(p, "%d", flags->FieldLength);
600 p += strlen(p);
602 if( flags->Precision >= 0 )
604 sprintf(p, ".%d", flags->Precision);
605 p += strlen(p);
607 *p++ = flags->Format;
608 *p++ = 0;
611 /* pf_integer_conv: prints x to buf, including alternate formats and
612 additional precision digits, but not field characters or the sign */
613 static void pf_integer_conv( char *buf, int buf_len, pf_flags *flags,
614 LONGLONG x )
616 unsigned int base;
617 const char *digits;
619 int i, j, k;
620 char number[40], *tmp = number;
622 if( buf_len > sizeof number )
623 tmp = HeapAlloc( GetProcessHeap(), 0, buf_len );
625 base = 10;
626 if( flags->Format == 'o' )
627 base = 8;
628 else if( flags->Format == 'x' || flags->Format == 'X' )
629 base = 16;
631 if( flags->Format == 'X' )
632 digits = "0123456789ABCDEFX";
633 else
634 digits = "0123456789abcdefx";
636 if( x < 0 && ( flags->Format == 'd' || flags->Format == 'i' ) )
638 x = -x;
639 flags->Sign = '-';
642 /* Do conversion (backwards) */
643 i = 0;
644 if( x == 0 && flags->Precision )
645 tmp[i++] = '0';
646 else
647 while( x != 0 )
649 j = (ULONGLONG) x % base;
650 x = (ULONGLONG) x / base;
651 tmp[i++] = digits[j];
653 k = flags->Precision - i;
654 while( k-- > 0 )
655 tmp[i++] = '0';
656 if( flags->Alternate )
658 if( base == 16 )
660 tmp[i++] = digits[16];
661 tmp[i++] = '0';
663 else if( base == 8 && tmp[i-1] != '0' )
664 tmp[i++] = '0';
667 /* Reverse for buf */
668 j = 0;
669 while( i-- > 0 )
670 buf[j++] = tmp[i];
671 buf[j] = '\0';
673 /* Adjust precision so pf_fill won't truncate the number later */
674 flags->Precision = strlen( buf );
676 if( tmp != number )
677 HeapFree( GetProcessHeap(), 0, tmp );
679 return;
682 /* pf_fixup_exponent: convert a string containing a 2 digit exponent
683 to 3 digits, accounting for padding, in place. Needed to match
684 the native printf's which always use 3 digits. */
685 static void pf_fixup_exponent( char *buf )
687 char* tmp = buf;
689 while (tmp[0] && toupper(tmp[0]) != 'E')
690 tmp++;
692 if (tmp[0] && (tmp[1] == '+' || tmp[1] == '-') &&
693 isdigit(tmp[2]) && isdigit(tmp[3]))
695 char final;
697 if (isdigit(tmp[4]))
698 return; /* Exponent already 3 digits */
700 /* We have a 2 digit exponent. Prepend '0' to make it 3 */
701 tmp += 2;
702 final = tmp[2];
703 tmp[2] = tmp[1];
704 tmp[1] = tmp[0];
705 tmp[0] = '0';
706 if (final == '\0')
708 /* We didn't expand into trailing space, so this string isn't left
709 * justified. Terminate the string and strip a ' ' at the start of
710 * the string if there is one (as there may be if the string is
711 * right justified).
713 tmp[3] = '\0';
714 if (buf[0] == ' ')
715 memmove(buf, buf + 1, (tmp - buf) + 3);
717 /* Otherwise, we expanded into trailing space -> nothing to do */
721 /*********************************************************************
722 * pf_vsnprintf (INTERNAL)
724 * implements both A and W vsnprintf functions
726 static int pf_vsnprintf( pf_output *out, const WCHAR *format,
727 MSVCRT__locale_t locale, BOOL valid, __ms_va_list valist )
729 int r;
730 LPCWSTR q, p = format;
731 pf_flags flags;
733 if(!locale)
734 locale = get_locale();
736 TRACE("format is %s\n",debugstr_w(format));
737 while (*p)
739 q = strchrW( p, '%' );
741 /* there's no % characters left, output the rest of the string */
742 if( !q )
744 r = pf_output_stringW(out, p, -1);
745 if( r<0 )
746 return r;
747 p += r;
748 continue;
751 /* there's characters before the %, output them */
752 if( q != p )
754 r = pf_output_stringW(out, p, q - p);
755 if( r<0 )
756 return r;
757 p = q;
760 /* we must be at a % now, skip over it */
761 assert( *p == '%' );
762 p++;
764 /* output a single % character */
765 if( *p == '%' )
767 r = pf_output_stringW(out, p++, 1);
768 if( r<0 )
769 return r;
770 continue;
773 /* parse the flags */
774 memset( &flags, 0, sizeof flags );
775 while (*p)
777 if( *p == '+' || *p == ' ' )
779 if ( flags.Sign != '+' )
780 flags.Sign = *p;
782 else if( *p == '-' )
783 flags.LeftAlign = *p;
784 else if( *p == '0' )
785 flags.PadZero = *p;
786 else if( *p == '#' )
787 flags.Alternate = *p;
788 else
789 break;
790 p++;
793 /* deal with the field width specifier */
794 flags.FieldLength = 0;
795 if( *p == '*' )
797 flags.FieldLength = va_arg( valist, int );
798 if (flags.FieldLength < 0)
800 flags.LeftAlign = '-';
801 flags.FieldLength = -flags.FieldLength;
803 p++;
805 else while( isdigit(*p) )
807 flags.FieldLength *= 10;
808 flags.FieldLength += *p++ - '0';
811 /* deal with precision */
812 flags.Precision = -1;
813 if( *p == '.' )
815 flags.Precision = 0;
816 p++;
817 if( *p == '*' )
819 flags.Precision = va_arg( valist, int );
820 p++;
822 else while( isdigit(*p) )
824 flags.Precision *= 10;
825 flags.Precision += *p++ - '0';
829 /* deal with integer width modifier */
830 while( *p )
832 if( *p == 'l' && *(p+1) == 'l' )
834 flags.IntegerDouble++;
835 p += 2;
837 else if( *p == 'h' || *p == 'l' || *p == 'L' )
839 flags.IntegerLength = *p;
840 p++;
842 else if( *p == 'I' )
844 if( *(p+1) == '6' && *(p+2) == '4' )
846 flags.IntegerDouble++;
847 p += 3;
849 else if( *(p+1) == '3' && *(p+2) == '2' )
850 p += 3;
851 else if( isdigit(*(p+1)) || *(p+1) == 0 )
852 break;
853 else
854 p++;
856 else if( *p == 'w' )
857 flags.WideString = *p++;
858 else if( *p == 'F' )
859 p++; /* ignore */
860 else
861 break;
864 flags.Format = *p;
865 r = 0;
867 if (flags.Format == '$')
869 FIXME("Positional parameters are not supported (%s)\n", wine_dbgstr_w(format));
870 return -1;
872 /* output a string */
873 if( flags.Format == 's' || flags.Format == 'S' )
874 r = pf_handle_string_format( out, va_arg(valist, const void*), -1,
875 &flags, (flags.Format == 'S') );
877 /* output a single character */
878 else if( flags.Format == 'c' || flags.Format == 'C' )
880 INT ch = va_arg( valist, int );
882 r = pf_handle_string_format( out, &ch, 1, &flags, (flags.Format == 'C') );
885 /* output a pointer */
886 else if( flags.Format == 'p' )
888 char pointer[32];
889 void *ptr = va_arg( valist, void * );
891 flags.PadZero = 0;
892 if( flags.Alternate )
893 sprintf(pointer, "0X%0*lX", 2 * (int)sizeof(ptr), (ULONG_PTR)ptr);
894 else
895 sprintf(pointer, "%0*lX", 2 * (int)sizeof(ptr), (ULONG_PTR)ptr);
896 r = pf_output_format_A( out, pointer, -1, &flags );
899 /* deal with %n */
900 else if( flags.Format == 'n' )
902 int *x = va_arg(valist, int *);
903 *x = out->used;
906 /* deal with 64-bit integers */
907 else if( pf_is_integer_format( flags.Format ) && flags.IntegerDouble )
909 char number[40], *x = number;
911 /* Estimate largest possible required buffer size:
912 * Chooses the larger of the field or precision
913 * Includes extra bytes: 1 byte for null, 1 byte for sign,
914 4 bytes for exponent, 2 bytes for alternate formats, 1 byte
915 for a decimal, and 1 byte for an additional float digit. */
916 int x_len = ((flags.FieldLength > flags.Precision) ?
917 flags.FieldLength : flags.Precision) + 10;
919 if( x_len >= sizeof number)
920 x = HeapAlloc( GetProcessHeap(), 0, x_len );
922 pf_integer_conv( x, x_len, &flags, va_arg(valist, LONGLONG) );
924 r = pf_output_format_A( out, x, -1, &flags );
925 if( x != number )
926 HeapFree( GetProcessHeap(), 0, x );
929 /* deal with integers and floats using libc's printf */
930 else if( pf_is_valid_format( flags.Format ) )
932 char fmt[20], number[40], *x = number, *decimal_point;
934 /* Estimate largest possible required buffer size:
935 * Chooses the larger of the field or precision
936 * Includes extra bytes: 1 byte for null, 1 byte for sign,
937 4 bytes for exponent, 2 bytes for alternate formats, 1 byte
938 for a decimal, and 1 byte for an additional float digit. */
939 int x_len = ((flags.FieldLength > flags.Precision) ?
940 flags.FieldLength : flags.Precision) + 10;
942 if( x_len >= sizeof number)
943 x = HeapAlloc( GetProcessHeap(), 0, x_len );
945 pf_rebuild_format_string( fmt, &flags );
947 if( pf_is_double_format( flags.Format ) )
949 sprintf( x, fmt, va_arg(valist, double) );
950 if (toupper(flags.Format) == 'E' || toupper(flags.Format) == 'G')
951 pf_fixup_exponent( x );
953 else
954 sprintf( x, fmt, va_arg(valist, int) );
956 decimal_point = strchr(x, '.');
957 if(decimal_point)
958 *decimal_point = *locale->locinfo->lconv->decimal_point;
960 r = pf_output_stringA( out, x, -1 );
961 if( x != number )
962 HeapFree( GetProcessHeap(), 0, x );
963 if(r < 0)
964 return r;
966 else
968 if( valid )
970 MSVCRT__invalid_parameter( NULL, NULL, NULL, 0, 0 );
971 *MSVCRT__errno() = MSVCRT_EINVAL;
972 return -1;
975 continue;
978 if( r<0 )
979 return r;
980 p++;
983 /* check we reached the end, and null terminate the string */
984 assert( *p == 0 );
985 pf_output_stringW( out, p, 1 );
987 return out->used - 1;
990 /*********************************************************************
991 * vsnprintf_internal (INTERNAL)
993 static inline int vsnprintf_internal( char *str, MSVCRT_size_t len, const char *format,
994 MSVCRT__locale_t locale, BOOL valid, __ms_va_list valist )
996 DWORD sz;
997 LPWSTR formatW = NULL;
998 pf_output out;
999 int r;
1001 out.unicode = FALSE;
1002 out.buf.A = str;
1003 out.used = 0;
1004 out.len = len;
1006 sz = MultiByteToWideChar( CP_ACP, 0, format, -1, NULL, 0 );
1007 formatW = HeapAlloc( GetProcessHeap(), 0, sz*sizeof(WCHAR) );
1008 MultiByteToWideChar( CP_ACP, 0, format, -1, formatW, sz );
1010 r = pf_vsnprintf( &out, formatW, locale, valid, valist );
1012 HeapFree( GetProcessHeap(), 0, formatW );
1014 return r;
1017 /*********************************************************************
1018 * _vsnprintf (MSVCRT.@)
1020 int CDECL MSVCRT_vsnprintf( char *str, MSVCRT_size_t len,
1021 const char *format, __ms_va_list valist )
1023 return vsnprintf_internal(str, len, format, NULL, FALSE, valist);
1026 /*********************************************************************
1027 * _vsnprintf_l (MSVCRT.@)
1029 int CDECL MSVCRT_vsnprintf_l( char *str, MSVCRT_size_t len, const char *format,
1030 MSVCRT__locale_t locale, __ms_va_list valist )
1032 return vsnprintf_internal(str, len, format, locale, FALSE, valist);
1035 /*********************************************************************
1036 * _vsnprintf_s_l (MSVCRT.@)
1038 int CDECL MSVCRT_vsnprintf_s_l( char *str, MSVCRT_size_t sizeOfBuffer,
1039 MSVCRT_size_t count, const char *format,
1040 MSVCRT__locale_t locale, __ms_va_list valist )
1042 int len, ret;
1044 if(sizeOfBuffer<count+1 || count==-1)
1045 len = sizeOfBuffer;
1046 else
1047 len = count+1;
1049 ret = vsnprintf_internal(str, len, format, locale, TRUE, valist);
1051 if(ret<0 || ret==len) {
1052 if(count!=MSVCRT__TRUNCATE && count>sizeOfBuffer) {
1053 MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small");
1054 *MSVCRT__errno() = MSVCRT_ERANGE;
1055 memset(str, 0, sizeOfBuffer);
1056 } else
1057 str[len-1] = '\0';
1059 return -1;
1062 return ret;
1065 /*********************************************************************
1066 * _vsnprintf_s (MSVCRT.@)
1068 int CDECL MSVCRT_vsnprintf_s( char *str, MSVCRT_size_t sizeOfBuffer,
1069 MSVCRT_size_t count, const char *format, __ms_va_list valist )
1071 return MSVCRT_vsnprintf_s_l(str,sizeOfBuffer, count, format, NULL, valist);
1074 /*********************************************************************
1075 * vsprintf (MSVCRT.@)
1077 int CDECL MSVCRT_vsprintf( char *str, const char *format, __ms_va_list valist)
1079 return MSVCRT_vsnprintf(str, INT_MAX, format, valist);
1082 /*********************************************************************
1083 * vsprintf_s (MSVCRT.@)
1085 int CDECL MSVCRT_vsprintf_s( char *str, MSVCRT_size_t num, const char *format, __ms_va_list valist)
1087 return MSVCRT_vsnprintf(str, num, format, valist);
1090 /*********************************************************************
1091 * _vscprintf (MSVCRT.@)
1093 int CDECL _vscprintf( const char *format, __ms_va_list valist )
1095 return MSVCRT_vsnprintf( NULL, INT_MAX, format, valist );
1098 /*********************************************************************
1099 * _snprintf (MSVCRT.@)
1101 int CDECL MSVCRT__snprintf(char *str, unsigned int len, const char *format, ...)
1103 int retval;
1104 __ms_va_list valist;
1105 __ms_va_start(valist, format);
1106 retval = MSVCRT_vsnprintf(str, len, format, valist);
1107 __ms_va_end(valist);
1108 return retval;
1111 /*********************************************************************
1112 * _snprintf_s (MSVCRT.@)
1114 int CDECL MSVCRT__snprintf_s(char *str, unsigned int len, unsigned int count,
1115 const char *format, ...)
1117 int retval;
1118 __ms_va_list valist;
1119 __ms_va_start(valist, format);
1120 retval = MSVCRT_vsnprintf_s_l(str, len, count, format, NULL, valist);
1121 __ms_va_end(valist);
1122 return retval;
1125 /*********************************************************************
1126 * _scprintf (MSVCRT.@)
1128 int CDECL MSVCRT__scprintf(const char *format, ...)
1130 int retval;
1131 __ms_va_list valist;
1132 __ms_va_start(valist, format);
1133 retval = _vscprintf(format, valist);
1134 __ms_va_end(valist);
1135 return retval;
1138 /*********************************************************************
1139 * vsnwprintf_internal (INTERNAL)
1141 static inline int vsnwprintf_internal(MSVCRT_wchar_t *str, MSVCRT_size_t len,
1142 const MSVCRT_wchar_t *format, MSVCRT__locale_t locale, BOOL valid,
1143 __ms_va_list valist)
1145 pf_output out;
1147 out.unicode = TRUE;
1148 out.buf.W = str;
1149 out.used = 0;
1150 out.len = len;
1152 return pf_vsnprintf( &out, format, locale, valid, valist );
1155 /*********************************************************************
1156 * _vsnwprintf (MSVCRT.@)
1158 int CDECL MSVCRT_vsnwprintf(MSVCRT_wchar_t *str, MSVCRT_size_t len,
1159 const MSVCRT_wchar_t *format, __ms_va_list valist)
1161 return vsnwprintf_internal(str, len, format, NULL, FALSE, valist);
1164 /*********************************************************************
1165 * _vsnwprintf_l (MSVCRT.@)
1167 int CDECL MSVCRT_vsnwprintf_l(MSVCRT_wchar_t *str, MSVCRT_size_t len,
1168 const MSVCRT_wchar_t *format, MSVCRT__locale_t locale,
1169 __ms_va_list valist)
1171 return vsnwprintf_internal(str, len, format, locale, FALSE, valist);
1174 /*********************************************************************
1175 * _vsnwprintf_s_l (MSVCRT.@)
1177 int CDECL MSVCRT_vsnwprintf_s_l( MSVCRT_wchar_t *str, MSVCRT_size_t sizeOfBuffer,
1178 MSVCRT_size_t count, const MSVCRT_wchar_t *format,
1179 MSVCRT__locale_t locale, __ms_va_list valist)
1181 int len, ret;
1183 len = sizeOfBuffer;
1184 if(count!=-1 && len>count+1)
1185 len = count+1;
1187 ret = vsnwprintf_internal(str, len, format, locale, TRUE, valist);
1189 if(ret<0 || ret==len) {
1190 if(count!=MSVCRT__TRUNCATE && count>sizeOfBuffer) {
1191 MSVCRT_INVALID_PMT("str[sizeOfBuffer] is too small");
1192 *MSVCRT__errno() = MSVCRT_ERANGE;
1193 memset(str, 0, sizeOfBuffer*sizeof(MSVCRT_wchar_t));
1194 } else
1195 str[len-1] = '\0';
1197 return -1;
1200 return ret;
1203 /*********************************************************************
1204 * _vsnwprintf_s (MSVCRT.@)
1206 int CDECL MSVCRT_vsnwprintf_s(MSVCRT_wchar_t *str, MSVCRT_size_t sizeOfBuffer,
1207 MSVCRT_size_t count, const MSVCRT_wchar_t *format, __ms_va_list valist)
1209 return MSVCRT_vsnwprintf_s_l(str, sizeOfBuffer, count,
1210 format, NULL, valist);
1213 /*********************************************************************
1214 * _snwprintf (MSVCRT.@)
1216 int CDECL MSVCRT__snwprintf( MSVCRT_wchar_t *str, unsigned int len, const MSVCRT_wchar_t *format, ...)
1218 int retval;
1219 __ms_va_list valist;
1220 __ms_va_start(valist, format);
1221 retval = MSVCRT_vsnwprintf(str, len, format, valist);
1222 __ms_va_end(valist);
1223 return retval;
1226 /*********************************************************************
1227 * _snwprintf_s (MSVCRT.@)
1229 int CDECL MSVCRT__snwprintf_s( MSVCRT_wchar_t *str, unsigned int len, unsigned int count,
1230 const MSVCRT_wchar_t *format, ...)
1232 int retval;
1233 __ms_va_list valist;
1234 __ms_va_start(valist, format);
1235 retval = MSVCRT_vsnwprintf_s_l(str, len, count, format, NULL, valist);
1236 __ms_va_end(valist);
1237 return retval;
1240 /*********************************************************************
1241 * sprintf (MSVCRT.@)
1243 int CDECL MSVCRT_sprintf( char *str, const char *format, ... )
1245 __ms_va_list ap;
1246 int r;
1248 __ms_va_start( ap, format );
1249 r = MSVCRT_vsnprintf( str, INT_MAX, format, ap );
1250 __ms_va_end( ap );
1251 return r;
1254 /*********************************************************************
1255 * sprintf_s (MSVCRT.@)
1257 int CDECL MSVCRT_sprintf_s( char *str, MSVCRT_size_t num, const char *format, ... )
1259 __ms_va_list ap;
1260 int r;
1262 __ms_va_start( ap, format );
1263 r = MSVCRT_vsnprintf( str, num, format, ap );
1264 __ms_va_end( ap );
1265 return r;
1268 /*********************************************************************
1269 * _scwprintf (MSVCRT.@)
1271 int CDECL MSVCRT__scwprintf( const MSVCRT_wchar_t *format, ... )
1273 __ms_va_list ap;
1274 int r;
1276 __ms_va_start( ap, format );
1277 r = MSVCRT_vsnwprintf( NULL, INT_MAX, format, ap );
1278 __ms_va_end( ap );
1279 return r;
1282 /*********************************************************************
1283 * swprintf (MSVCRT.@)
1285 int CDECL MSVCRT_swprintf( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *format, ... )
1287 __ms_va_list ap;
1288 int r;
1290 __ms_va_start( ap, format );
1291 r = MSVCRT_vsnwprintf( str, INT_MAX, format, ap );
1292 __ms_va_end( ap );
1293 return r;
1296 /*********************************************************************
1297 * swprintf_s (MSVCRT.@)
1299 int CDECL MSVCRT_swprintf_s(MSVCRT_wchar_t *str, MSVCRT_size_t numberOfElements,
1300 const MSVCRT_wchar_t *format, ... )
1302 __ms_va_list ap;
1303 int r;
1305 __ms_va_start(ap, format);
1306 r = MSVCRT_vsnwprintf_s(str, numberOfElements, INT_MAX, format, ap);
1307 __ms_va_end(ap);
1309 return r;
1312 /*********************************************************************
1313 * vswprintf (MSVCRT.@)
1315 int CDECL MSVCRT_vswprintf( MSVCRT_wchar_t* str, const MSVCRT_wchar_t* format, __ms_va_list args )
1317 return MSVCRT_vsnwprintf( str, INT_MAX, format, args );
1320 /*********************************************************************
1321 * _vscwprintf (MSVCRT.@)
1323 int CDECL _vscwprintf( const MSVCRT_wchar_t *format, __ms_va_list args )
1325 return MSVCRT_vsnwprintf( NULL, INT_MAX, format, args );
1328 /*********************************************************************
1329 * vswprintf_s (MSVCRT.@)
1331 int CDECL MSVCRT_vswprintf_s(MSVCRT_wchar_t* str, MSVCRT_size_t numberOfElements,
1332 const MSVCRT_wchar_t* format, __ms_va_list args)
1334 return MSVCRT_vsnwprintf_s(str, numberOfElements, INT_MAX, format, args );
1337 /*********************************************************************
1338 * _vswprintf_s_l (MSVCRT.@)
1340 int CDECL MSVCRT_vswprintf_s_l(MSVCRT_wchar_t* str, MSVCRT_size_t numberOfElements,
1341 const MSVCRT_wchar_t* format, MSVCRT__locale_t locale, __ms_va_list args)
1343 return MSVCRT_vsnwprintf_s_l(str, numberOfElements, INT_MAX,
1344 format, locale, args );
1347 /*********************************************************************
1348 * wcscoll (MSVCRT.@)
1350 int CDECL MSVCRT_wcscoll( const MSVCRT_wchar_t* str1, const MSVCRT_wchar_t* str2 )
1352 /* FIXME: handle collates */
1353 return strcmpW( str1, str2 );
1356 /*********************************************************************
1357 * wcspbrk (MSVCRT.@)
1359 MSVCRT_wchar_t* CDECL MSVCRT_wcspbrk( const MSVCRT_wchar_t* str, const MSVCRT_wchar_t* accept )
1361 const MSVCRT_wchar_t* p;
1362 while (*str)
1364 for (p = accept; *p; p++) if (*p == *str) return (MSVCRT_wchar_t*)str;
1365 str++;
1367 return NULL;
1370 /*********************************************************************
1371 * wcstok_s (MSVCRT.@)
1373 MSVCRT_wchar_t * CDECL wcstok_s( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim,
1374 MSVCRT_wchar_t **next_token )
1376 MSVCRT_wchar_t *ret;
1378 if (!MSVCRT_CHECK_PMT(delim != NULL) || !MSVCRT_CHECK_PMT(next_token != NULL) ||
1379 !MSVCRT_CHECK_PMT(str != NULL || *next_token != NULL))
1381 *MSVCRT__errno() = MSVCRT_EINVAL;
1382 return NULL;
1384 if (!str) str = *next_token;
1386 while (*str && strchrW( delim, *str )) str++;
1387 if (!*str) return NULL;
1388 ret = str++;
1389 while (*str && !strchrW( delim, *str )) str++;
1390 if (*str) *str++ = 0;
1391 *next_token = str;
1392 return ret;
1395 /*********************************************************************
1396 * wcstok (MSVCRT.@)
1398 MSVCRT_wchar_t * CDECL MSVCRT_wcstok( MSVCRT_wchar_t *str, const MSVCRT_wchar_t *delim )
1400 return wcstok_s(str, delim, &msvcrt_get_thread_data()->wcstok_next);
1403 /*********************************************************************
1404 * wctomb (MSVCRT.@)
1406 INT CDECL MSVCRT_wctomb( char *dst, MSVCRT_wchar_t ch )
1408 return WideCharToMultiByte( CP_ACP, 0, &ch, 1, dst, 6, NULL, NULL );
1411 /*********************************************************************
1412 * iswalnum (MSVCRT.@)
1414 INT CDECL MSVCRT_iswalnum( MSVCRT_wchar_t wc )
1416 return isalnumW( wc );
1419 /*********************************************************************
1420 * iswalpha (MSVCRT.@)
1422 INT CDECL MSVCRT_iswalpha( MSVCRT_wchar_t wc )
1424 return isalphaW( wc );
1427 /*********************************************************************
1428 * iswalpha_l (MSVCRT.@)
1430 INT CDECL MSVCRT__iswalpha_l( MSVCRT_wchar_t wc, MSVCRT__locale_t locale )
1432 return isalphaW( wc );
1435 /*********************************************************************
1436 * iswcntrl (MSVCRT.@)
1438 INT CDECL MSVCRT_iswcntrl( MSVCRT_wchar_t wc )
1440 return iscntrlW( wc );
1443 /*********************************************************************
1444 * iswdigit (MSVCRT.@)
1446 INT CDECL MSVCRT_iswdigit( MSVCRT_wchar_t wc )
1448 return isdigitW( wc );
1451 /*********************************************************************
1452 * iswgraph (MSVCRT.@)
1454 INT CDECL MSVCRT_iswgraph( MSVCRT_wchar_t wc )
1456 return isgraphW( wc );
1459 /*********************************************************************
1460 * iswlower (MSVCRT.@)
1462 INT CDECL MSVCRT_iswlower( MSVCRT_wchar_t wc )
1464 return islowerW( wc );
1467 /*********************************************************************
1468 * iswprint (MSVCRT.@)
1470 INT CDECL MSVCRT_iswprint( MSVCRT_wchar_t wc )
1472 return isprintW( wc );
1475 /*********************************************************************
1476 * iswpunct (MSVCRT.@)
1478 INT CDECL MSVCRT_iswpunct( MSVCRT_wchar_t wc )
1480 return ispunctW( wc );
1483 /*********************************************************************
1484 * iswspace (MSVCRT.@)
1486 INT CDECL MSVCRT_iswspace( MSVCRT_wchar_t wc )
1488 return isspaceW( wc );
1491 /*********************************************************************
1492 * iswupper (MSVCRT.@)
1494 INT CDECL MSVCRT_iswupper( MSVCRT_wchar_t wc )
1496 return isupperW( wc );
1499 /*********************************************************************
1500 * iswxdigit (MSVCRT.@)
1502 INT CDECL MSVCRT_iswxdigit( MSVCRT_wchar_t wc )
1504 return isxdigitW( wc );
1507 /*********************************************************************
1508 * wcscpy_s (MSVCRT.@)
1510 INT CDECL MSVCRT_wcscpy_s( MSVCRT_wchar_t* wcDest, MSVCRT_size_t numElement, const MSVCRT_wchar_t *wcSrc)
1512 MSVCRT_size_t size = 0;
1514 if(!wcDest || !numElement)
1515 return MSVCRT_EINVAL;
1517 wcDest[0] = 0;
1519 if(!wcSrc)
1521 return MSVCRT_EINVAL;
1524 size = strlenW(wcSrc) + 1;
1526 if(size > numElement)
1528 return MSVCRT_ERANGE;
1531 memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
1533 return 0;
1536 /******************************************************************
1537 * wcsncpy_s (MSVCRT.@)
1539 INT CDECL MSVCRT_wcsncpy_s( MSVCRT_wchar_t* wcDest, MSVCRT_size_t numElement, const MSVCRT_wchar_t *wcSrc,
1540 MSVCRT_size_t count )
1542 MSVCRT_size_t size = 0;
1544 if (!wcDest || !numElement)
1545 return MSVCRT_EINVAL;
1547 wcDest[0] = 0;
1549 if (!wcSrc)
1551 return MSVCRT_EINVAL;
1554 size = min(strlenW(wcSrc), count);
1556 if (size >= numElement)
1558 return MSVCRT_ERANGE;
1561 memcpy( wcDest, wcSrc, size*sizeof(WCHAR) );
1562 wcDest[size] = '\0';
1564 return 0;
1567 /******************************************************************
1568 * wcscat_s (MSVCRT.@)
1571 INT CDECL MSVCRT_wcscat_s(MSVCRT_wchar_t* dst, MSVCRT_size_t elem, const MSVCRT_wchar_t* src)
1573 MSVCRT_wchar_t* ptr = dst;
1575 if (!dst || elem == 0) return MSVCRT_EINVAL;
1576 if (!src)
1578 dst[0] = '\0';
1579 return MSVCRT_EINVAL;
1582 /* seek to end of dst string (or elem if no end of string is found */
1583 while (ptr < dst + elem && *ptr != '\0') ptr++;
1584 while (ptr < dst + elem)
1586 if ((*ptr++ = *src++) == '\0') return 0;
1588 /* not enough space */
1589 dst[0] = '\0';
1590 return MSVCRT_ERANGE;
1593 /*********************************************************************
1594 * wcsncat_s (MSVCRT.@)
1597 INT CDECL MSVCRT_wcsncat_s(MSVCRT_wchar_t *dst, MSVCRT_size_t elem,
1598 const MSVCRT_wchar_t *src, MSVCRT_size_t count)
1600 MSVCRT_size_t srclen;
1601 MSVCRT_wchar_t dststart;
1602 INT ret = 0;
1604 if (src == NULL && count > 0)
1605 return MSVCRT_EINVAL;
1606 if (dst == NULL)
1607 return MSVCRT_EINVAL;
1608 if (elem == 0)
1609 return MSVCRT_EINVAL;
1610 if (count == 0)
1611 return 0;
1613 for (dststart = 0; dststart < elem; dststart++)
1615 if (dst[dststart] == '\0')
1616 break;
1618 if (dststart == elem)
1619 return MSVCRT_EINVAL;
1621 if (count == MSVCRT__TRUNCATE)
1623 srclen = strlenW(src);
1624 if (srclen >= (elem - dststart))
1626 srclen = elem - dststart - 1;
1627 ret = MSVCRT_STRUNCATE;
1630 else
1631 srclen = min(strlenW(src), count);
1632 if (srclen < (elem - dststart))
1634 memcpy(&dst[dststart], src, srclen*sizeof(MSVCRT_wchar_t));
1635 dst[srclen] = '\0';
1636 return ret;
1638 dst[0] = '\0';
1639 return MSVCRT_ERANGE;
1642 /*********************************************************************
1643 * _wcstoi64_l (MSVCRT.@)
1645 * FIXME: locale parameter is ignored
1647 __int64 CDECL MSVCRT__wcstoi64_l(const MSVCRT_wchar_t *nptr,
1648 MSVCRT_wchar_t **endptr, int base, MSVCRT__locale_t locale)
1650 BOOL negative = FALSE;
1651 __int64 ret = 0;
1653 TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
1655 if (!MSVCRT_CHECK_PMT(nptr != NULL) || !MSVCRT_CHECK_PMT(base == 0 || base >= 2) ||
1656 !MSVCRT_CHECK_PMT(base <= 36)) {
1657 *MSVCRT__errno() = MSVCRT_EINVAL;
1658 return 0;
1661 while(isspaceW(*nptr)) nptr++;
1663 if(*nptr == '-') {
1664 negative = TRUE;
1665 nptr++;
1666 } else if(*nptr == '+')
1667 nptr++;
1669 if((base==0 || base==16) && *nptr=='0' && tolowerW(*(nptr+1))=='x') {
1670 base = 16;
1671 nptr += 2;
1674 if(base == 0) {
1675 if(*nptr=='0')
1676 base = 8;
1677 else
1678 base = 10;
1681 while(*nptr) {
1682 char cur = tolowerW(*nptr);
1683 int v;
1685 if(isdigitW(cur)) {
1686 if(cur >= '0'+base)
1687 break;
1688 v = cur-'0';
1689 } else {
1690 if(cur<'a' || cur>='a'+base-10)
1691 break;
1692 v = cur-'a'+10;
1695 if(negative)
1696 v = -v;
1698 nptr++;
1700 if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
1701 ret = MSVCRT_I64_MAX;
1702 *MSVCRT__errno() = MSVCRT_ERANGE;
1703 } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
1704 ret = MSVCRT_I64_MIN;
1705 *MSVCRT__errno() = MSVCRT_ERANGE;
1706 } else
1707 ret = ret*base + v;
1710 if(endptr)
1711 *endptr = (MSVCRT_wchar_t*)nptr;
1713 return ret;
1716 /*********************************************************************
1717 * _wcstoi64 (MSVCRT.@)
1719 __int64 CDECL MSVCRT__wcstoi64(const MSVCRT_wchar_t *nptr,
1720 MSVCRT_wchar_t **endptr, int base)
1722 return MSVCRT__wcstoi64_l(nptr, endptr, base, NULL);
1725 /*********************************************************************
1726 * _wcstoui64_l (MSVCRT.@)
1728 * FIXME: locale parameter is ignored
1730 unsigned __int64 CDECL MSVCRT__wcstoui64_l(const MSVCRT_wchar_t *nptr,
1731 MSVCRT_wchar_t **endptr, int base, MSVCRT__locale_t locale)
1733 BOOL negative = FALSE;
1734 unsigned __int64 ret = 0;
1736 TRACE("(%s %p %d %p)\n", debugstr_w(nptr), endptr, base, locale);
1738 if (!MSVCRT_CHECK_PMT(nptr != NULL) || !MSVCRT_CHECK_PMT(base == 0 || base >= 2) ||
1739 !MSVCRT_CHECK_PMT(base <= 36)) {
1740 *MSVCRT__errno() = MSVCRT_EINVAL;
1741 return 0;
1744 while(isspaceW(*nptr)) nptr++;
1746 if(*nptr == '-') {
1747 negative = TRUE;
1748 nptr++;
1749 } else if(*nptr == '+')
1750 nptr++;
1752 if((base==0 || base==16) && *nptr=='0' && tolowerW(*(nptr+1))=='x') {
1753 base = 16;
1754 nptr += 2;
1757 if(base == 0) {
1758 if(*nptr=='0')
1759 base = 8;
1760 else
1761 base = 10;
1764 while(*nptr) {
1765 char cur = tolowerW(*nptr);
1766 int v;
1768 if(isdigit(cur)) {
1769 if(cur >= '0'+base)
1770 break;
1771 v = *nptr-'0';
1772 } else {
1773 if(cur<'a' || cur>='a'+base-10)
1774 break;
1775 v = cur-'a'+10;
1778 nptr++;
1780 if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1781 ret = MSVCRT_UI64_MAX;
1782 *MSVCRT__errno() = MSVCRT_ERANGE;
1783 } else
1784 ret = ret*base + v;
1787 if(endptr)
1788 *endptr = (MSVCRT_wchar_t*)nptr;
1790 return negative ? -ret : ret;
1793 /*********************************************************************
1794 * _wcstoui64 (MSVCRT.@)
1796 unsigned __int64 CDECL MSVCRT__wcstoui64(const MSVCRT_wchar_t *nptr,
1797 MSVCRT_wchar_t **endptr, int base)
1799 return MSVCRT__wcstoui64_l(nptr, endptr, base, NULL);
1802 /******************************************************************
1803 * wcsnlen (MSVCRT.@)
1805 MSVCRT_size_t CDECL MSVCRT_wcsnlen(const MSVCRT_wchar_t *s, MSVCRT_size_t maxlen)
1807 MSVCRT_size_t i;
1809 for (i = 0; i < maxlen; i++)
1810 if (!s[i]) break;
1811 return i;