riched20: Use cell ptrs in the rtf parsing code.
[wine/zf.git] / dlls / msvcrt / string.c
blob3343f1e3ccf5605e5b6df5a0639195524eb51418
1 /*
2 * MSVCRT string functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define _ISOC99_SOURCE
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <limits.h>
33 #include <errno.h>
34 #include "msvcrt.h"
35 #include "bnum.h"
36 #include "winnls.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
41 /*********************************************************************
42 * _mbsdup (MSVCRT.@)
43 * _strdup (MSVCRT.@)
45 char* CDECL MSVCRT__strdup(const char* str)
47 if(str)
49 char * ret = MSVCRT_malloc(strlen(str)+1);
50 if (ret) strcpy( ret, str );
51 return ret;
53 else return 0;
56 /*********************************************************************
57 * _strlwr_s_l (MSVCRT.@)
59 int CDECL MSVCRT__strlwr_s_l(char *str, MSVCRT_size_t len, MSVCRT__locale_t locale)
61 MSVCRT_pthreadlocinfo locinfo;
62 char *ptr = str;
64 if (!str || !len)
66 *MSVCRT__errno() = MSVCRT_EINVAL;
67 return MSVCRT_EINVAL;
70 while (len && *ptr)
72 len--;
73 ptr++;
76 if (!len)
78 str[0] = '\0';
79 *MSVCRT__errno() = MSVCRT_EINVAL;
80 return MSVCRT_EINVAL;
83 if(!locale)
84 locinfo = get_locinfo();
85 else
86 locinfo = locale->locinfo;
88 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
90 while (*str)
92 if (*str >= 'A' && *str <= 'Z')
93 *str -= 'A' - 'a';
94 str++;
97 else
99 while (*str)
101 *str = MSVCRT__tolower_l((unsigned char)*str, locale);
102 str++;
106 return 0;
109 /*********************************************************************
110 * _strlwr_s (MSVCRT.@)
112 int CDECL MSVCRT__strlwr_s(char *str, MSVCRT_size_t len)
114 return MSVCRT__strlwr_s_l(str, len, NULL);
117 /*********************************************************************
118 * _strlwr_l (MSVCRT.@)
120 char* CDECL _strlwr_l(char *str, MSVCRT__locale_t locale)
122 MSVCRT__strlwr_s_l(str, -1, locale);
123 return str;
126 /*********************************************************************
127 * _strlwr (MSVCRT.@)
129 char* CDECL MSVCRT__strlwr(char *str)
131 MSVCRT__strlwr_s_l(str, -1, NULL);
132 return str;
135 /*********************************************************************
136 * _strupr_s_l (MSVCRT.@)
138 int CDECL MSVCRT__strupr_s_l(char *str, MSVCRT_size_t len, MSVCRT__locale_t locale)
140 MSVCRT_pthreadlocinfo locinfo;
141 char *ptr = str;
143 if (!str || !len)
145 *MSVCRT__errno() = MSVCRT_EINVAL;
146 return MSVCRT_EINVAL;
149 while (len && *ptr)
151 len--;
152 ptr++;
155 if (!len)
157 str[0] = '\0';
158 *MSVCRT__errno() = MSVCRT_EINVAL;
159 return MSVCRT_EINVAL;
162 if(!locale)
163 locinfo = get_locinfo();
164 else
165 locinfo = locale->locinfo;
167 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
169 while (*str)
171 if (*str >= 'a' && *str <= 'z')
172 *str -= 'a' - 'A';
173 str++;
176 else
178 while (*str)
180 *str = MSVCRT__toupper_l((unsigned char)*str, locale);
181 str++;
185 return 0;
188 /*********************************************************************
189 * _strupr_s (MSVCRT.@)
191 int CDECL MSVCRT__strupr_s(char *str, MSVCRT_size_t len)
193 return MSVCRT__strupr_s_l(str, len, NULL);
196 /*********************************************************************
197 * _strupr_l (MSVCRT.@)
199 char* CDECL MSVCRT__strupr_l(char *str, MSVCRT__locale_t locale)
201 MSVCRT__strupr_s_l(str, -1, locale);
202 return str;
205 /*********************************************************************
206 * _strupr (MSVCRT.@)
208 char* CDECL MSVCRT__strupr(char *str)
210 MSVCRT__strupr_s_l(str, -1, NULL);
211 return str;
214 /*********************************************************************
215 * _strnset_s (MSVCRT.@)
217 int CDECL MSVCRT__strnset_s(char *str, MSVCRT_size_t size, int c, MSVCRT_size_t count)
219 MSVCRT_size_t i;
221 if(!str && !size && !count) return 0;
222 if(!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
223 if(!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
225 for(i=0; i<size-1 && i<count; i++) {
226 if(!str[i]) return 0;
227 str[i] = c;
229 for(; i<size; i++)
230 if(!str[i]) return 0;
232 str[0] = 0;
233 MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
234 *MSVCRT__errno() = MSVCRT_EINVAL;
235 return MSVCRT_EINVAL;
238 /*********************************************************************
239 * _strnset (MSVCRT.@)
241 char* CDECL MSVCRT__strnset(char* str, int value, MSVCRT_size_t len)
243 if (len > 0 && str)
244 while (*str && len--)
245 *str++ = value;
246 return str;
249 /*********************************************************************
250 * _strrev (MSVCRT.@)
252 char* CDECL MSVCRT__strrev(char* str)
254 char * p1;
255 char * p2;
257 if (str && *str)
258 for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
260 *p1 ^= *p2;
261 *p2 ^= *p1;
262 *p1 ^= *p2;
265 return str;
268 /*********************************************************************
269 * _strset (MSVCRT.@)
271 char* CDECL _strset(char* str, int value)
273 char *ptr = str;
274 while (*ptr)
275 *ptr++ = value;
277 return str;
280 /*********************************************************************
281 * strtok (MSVCRT.@)
283 char * CDECL MSVCRT_strtok( char *str, const char *delim )
285 thread_data_t *data = msvcrt_get_thread_data();
286 char *ret;
288 if (!str)
289 if (!(str = data->strtok_next)) return NULL;
291 while (*str && strchr( delim, *str )) str++;
292 if (!*str) return NULL;
293 ret = str++;
294 while (*str && !strchr( delim, *str )) str++;
295 if (*str) *str++ = 0;
296 data->strtok_next = str;
297 return ret;
300 /*********************************************************************
301 * strtok_s (MSVCRT.@)
303 char * CDECL MSVCRT_strtok_s(char *str, const char *delim, char **ctx)
305 if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL;
306 if (!MSVCRT_CHECK_PMT(ctx != NULL)) return NULL;
307 if (!MSVCRT_CHECK_PMT(str != NULL || *ctx != NULL)) return NULL;
309 if(!str)
310 str = *ctx;
312 while(*str && strchr(delim, *str))
313 str++;
314 if(!*str)
316 *ctx = str;
317 return NULL;
320 *ctx = str+1;
321 while(**ctx && !strchr(delim, **ctx))
322 (*ctx)++;
323 if(**ctx)
324 *(*ctx)++ = 0;
326 return str;
329 /*********************************************************************
330 * _swab (MSVCRT.@)
332 void CDECL MSVCRT__swab(char* src, char* dst, int len)
334 if (len > 1)
336 len = (unsigned)len >> 1;
338 while (len--) {
339 char s0 = src[0];
340 char s1 = src[1];
341 *dst++ = s1;
342 *dst++ = s0;
343 src = src + 2;
348 static struct fpnum fpnum(int sign, int exp, ULONGLONG m, enum fpmod mod)
350 struct fpnum ret;
352 ret.sign = sign;
353 ret.exp = exp;
354 ret.m = m;
355 ret.mod = mod;
356 return ret;
359 int fpnum_double(struct fpnum *fp, double *d)
361 ULONGLONG bits = 0;
363 if (fp->mod == FP_VAL_INFINITY)
365 *d = fp->sign * INFINITY;
366 return 0;
369 if (fp->mod == FP_VAL_NAN)
371 bits = ~0;
372 if (fp->sign == 1)
373 bits &= ~((ULONGLONG)1 << (MANT_BITS + EXP_BITS - 1));
374 *d = *(double*)&bits;
375 return 0;
378 TRACE("%c %s *2^%d (round %d)\n", fp->sign == -1 ? '-' : '+',
379 wine_dbgstr_longlong(fp->m), fp->exp, fp->mod);
380 if (!fp->m)
382 *d = fp->sign * 0.0;
383 return 0;
386 /* make sure that we don't overflow modifying exponent */
387 if (fp->exp > 1<<EXP_BITS)
389 *d = fp->sign * INFINITY;
390 return MSVCRT_ERANGE;
392 if (fp->exp < -(1<<EXP_BITS))
394 *d = fp->sign * 0.0;
395 return MSVCRT_ERANGE;
397 fp->exp += MANT_BITS - 1;
399 /* normalize mantissa */
400 while(fp->m < (ULONGLONG)1 << (MANT_BITS-1))
402 fp->m <<= 1;
403 fp->exp--;
405 while(fp->m >= (ULONGLONG)1 << MANT_BITS)
407 if (fp->m & 1 || fp->mod != FP_ROUND_ZERO)
409 if (!(fp->m & 1)) fp->mod = FP_ROUND_DOWN;
410 else if(fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
411 else fp->mod = FP_ROUND_UP;
413 fp->m >>= 1;
414 fp->exp++;
416 fp->exp += (1 << (EXP_BITS-1)) - 1;
418 /* handle subnormals */
419 if (fp->exp <= 0)
421 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
422 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
423 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
424 fp->m >>= 1;
426 while(fp->m && fp->exp<0)
428 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
429 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
430 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
431 fp->m >>= 1;
432 fp->exp++;
435 /* round mantissa */
436 if (fp->mod == FP_ROUND_UP || (fp->mod == FP_ROUND_EVEN && fp->m & 1))
438 fp->m++;
440 /* handle subnormal that falls into regular range due to rounding */
441 if (fp->m == (ULONGLONG)1 << (MANT_BITS - 1))
443 fp->exp++;
445 else if (fp->m >= (ULONGLONG)1 << MANT_BITS)
447 fp->exp++;
448 fp->m >>= 1;
452 if (fp->exp >= (1<<EXP_BITS)-1)
454 *d = fp->sign * INFINITY;
455 return MSVCRT_ERANGE;
457 if (!fp->m || fp->exp < 0)
459 *d = fp->sign * 0.0;
460 return MSVCRT_ERANGE;
463 if (fp->sign == -1)
464 bits |= (ULONGLONG)1 << (MANT_BITS + EXP_BITS - 1);
465 bits |= (ULONGLONG)fp->exp << (MANT_BITS - 1);
466 bits |= fp->m & (((ULONGLONG)1 << (MANT_BITS - 1)) - 1);
468 TRACE("returning %s\n", wine_dbgstr_longlong(bits));
469 *d = *(double*)&bits;
470 return 0;
473 #define LDBL_EXP_BITS 15
474 #define LDBL_MANT_BITS 64
475 int fpnum_ldouble(struct fpnum *fp, MSVCRT__LDOUBLE *d)
477 if (fp->mod == FP_VAL_INFINITY)
479 d->x80[0] = 0;
480 d->x80[1] = 0x80000000;
481 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
482 if (fp->sign == -1)
483 d->x80[2] |= 1 << LDBL_EXP_BITS;
484 return 0;
487 if (fp->mod == FP_VAL_NAN)
489 d->x80[0] = ~0;
490 d->x80[1] = ~0;
491 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
492 if (fp->sign == -1)
493 d->x80[2] |= 1 << LDBL_EXP_BITS;
494 return 0;
497 TRACE("%c %s *2^%d (round %d)\n", fp->sign == -1 ? '-' : '+',
498 wine_dbgstr_longlong(fp->m), fp->exp, fp->mod);
499 if (!fp->m)
501 d->x80[0] = 0;
502 d->x80[1] = 0;
503 d->x80[2] = 0;
504 if (fp->sign == -1)
505 d->x80[2] |= 1 << LDBL_EXP_BITS;
506 return 0;
509 /* make sure that we don't overflow modifying exponent */
510 if (fp->exp > 1<<LDBL_EXP_BITS)
512 d->x80[0] = 0;
513 d->x80[1] = 0x80000000;
514 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
515 if (fp->sign == -1)
516 d->x80[2] |= 1 << LDBL_EXP_BITS;
517 return MSVCRT_ERANGE;
519 if (fp->exp < -(1<<LDBL_EXP_BITS))
521 d->x80[0] = 0;
522 d->x80[1] = 0;
523 d->x80[2] = 0;
524 if (fp->sign == -1)
525 d->x80[2] |= 1 << LDBL_EXP_BITS;
526 return MSVCRT_ERANGE;
528 fp->exp += LDBL_MANT_BITS - 1;
530 /* normalize mantissa */
531 while(fp->m < (ULONGLONG)1 << (LDBL_MANT_BITS-1))
533 fp->m <<= 1;
534 fp->exp--;
536 fp->exp += (1 << (LDBL_EXP_BITS-1)) - 1;
538 /* handle subnormals */
539 if (fp->exp <= 0)
541 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
542 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
543 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
544 fp->m >>= 1;
546 while(fp->m && fp->exp<0)
548 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
549 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
550 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
551 fp->m >>= 1;
552 fp->exp++;
555 /* round mantissa */
556 if (fp->mod == FP_ROUND_UP || (fp->mod == FP_ROUND_EVEN && fp->m & 1))
558 if (fp->m == MSVCRT_UI64_MAX)
560 fp->m = (ULONGLONG)1 << (LDBL_MANT_BITS - 1);
561 fp->exp++;
563 else
565 fp->m++;
567 /* handle subnormal that falls into regular range due to rounding */
568 if ((fp->m ^ (fp->m - 1)) & ((ULONGLONG)1 << (LDBL_MANT_BITS - 1))) fp->exp++;
572 if (fp->exp >= (1<<LDBL_EXP_BITS)-1)
574 d->x80[0] = 0;
575 d->x80[1] = 0x80000000;
576 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
577 if (fp->sign == -1)
578 d->x80[2] |= 1 << LDBL_EXP_BITS;
579 return MSVCRT_ERANGE;
581 if (!fp->m || fp->exp < 0)
583 d->x80[0] = 0;
584 d->x80[1] = 0;
585 d->x80[2] = 0;
586 if (fp->sign == -1)
587 d->x80[2] |= 1 << LDBL_EXP_BITS;
588 return MSVCRT_ERANGE;
591 d->x80[0] = fp->m;
592 d->x80[1] = fp->m >> 32;
593 d->x80[2] = fp->exp;
594 if (fp->sign == -1)
595 d->x80[2] |= 1 << LDBL_EXP_BITS;
596 return 0;
599 #if _MSVCR_VER >= 140
601 static inline int hex2int(char c)
603 if (c >= '0' && c <= '9')
604 return c - '0';
605 else if (c >= 'a' && c <= 'f')
606 return c - 'a' + 10;
607 else if (c >= 'A' && c <= 'F')
608 return c - 'A' + 10;
609 return -1;
612 static struct fpnum fpnum_parse16(MSVCRT_wchar_t get(void *ctx), void unget(void *ctx),
613 void *ctx, int sign, MSVCRT_pthreadlocinfo locinfo)
615 BOOL found_digit = FALSE, found_dp = FALSE;
616 enum fpmod round = FP_ROUND_ZERO;
617 MSVCRT_wchar_t nch;
618 ULONGLONG m = 0;
619 int val, exp = 0;
621 nch = get(ctx);
622 while(m < MSVCRT_UI64_MAX/16)
624 val = hex2int(nch);
625 if (val == -1) break;
626 found_digit = TRUE;
627 nch = get(ctx);
629 m = m*16 + val;
631 while(1)
633 val = hex2int(nch);
634 if (val == -1) break;
635 nch = get(ctx);
636 exp += 4;
638 if (val || round != FP_ROUND_ZERO)
640 if (val < 8) round = FP_ROUND_DOWN;
641 else if (val == 8 && round == FP_ROUND_ZERO) round = FP_ROUND_EVEN;
642 else round = FP_ROUND_UP;
646 if(nch == *locinfo->lconv->decimal_point)
648 found_dp = TRUE;
649 nch = get(ctx);
651 else if (!found_digit)
653 if(nch!=MSVCRT_WEOF) unget(ctx);
654 unget(ctx);
655 return fpnum(0, 0, 0, 0);
658 while(m <= MSVCRT_UI64_MAX/16)
660 val = hex2int(nch);
661 if (val == -1) break;
662 found_digit = TRUE;
663 nch = get(ctx);
665 m = m*16 + val;
666 exp -= 4;
668 while(1)
670 val = hex2int(nch);
671 if (val == -1) break;
672 nch = get(ctx);
674 if (val || round != FP_ROUND_ZERO)
676 if (val < 8) round = FP_ROUND_DOWN;
677 else if (val == 8 && round == FP_ROUND_ZERO) round = FP_ROUND_EVEN;
678 else round = FP_ROUND_UP;
682 if (!found_digit)
684 if (nch != MSVCRT_WEOF) unget(ctx);
685 if (found_dp) unget(ctx);
686 unget(ctx);
687 return fpnum(0, 0, 0, 0);
690 if(nch=='p' || nch=='P') {
691 BOOL found_sign = FALSE;
692 int e=0, s=1;
694 nch = get(ctx);
695 if(nch == '-') {
696 found_sign = TRUE;
697 s = -1;
698 nch = get(ctx);
699 } else if(nch == '+') {
700 found_sign = TRUE;
701 nch = get(ctx);
703 if(nch>='0' && nch<='9') {
704 while(nch>='0' && nch<='9') {
705 if(e>INT_MAX/10 || e*10>INT_MAX-nch+'0')
706 e = INT_MAX;
707 else
708 e = e*10+nch-'0';
709 nch = get(ctx);
711 if((nch!=MSVCRT_WEOF) && (nch < '0' || nch > '9')) unget(ctx);
712 e *= s;
714 if(e<0 && exp<INT_MIN-e) exp = INT_MIN;
715 else if(e>0 && exp>INT_MAX-e) exp = INT_MAX;
716 else exp += e;
717 } else {
718 if(nch != MSVCRT_WEOF) unget(ctx);
719 if(found_sign) unget(ctx);
720 unget(ctx);
724 return fpnum(sign, exp, m, round);
726 #endif
728 /* Converts first 3 limbs to ULONGLONG */
729 /* Return FALSE on overflow */
730 static inline BOOL bnum_to_mant(struct bnum *b, ULONGLONG *m)
732 if(MSVCRT_UI64_MAX / LIMB_MAX / LIMB_MAX < b->data[bnum_idx(b, b->e-1)]) return FALSE;
733 *m = (ULONGLONG)b->data[bnum_idx(b, b->e-1)] * LIMB_MAX * LIMB_MAX;
734 if(b->b == b->e-1) return TRUE;
735 if(MSVCRT_UI64_MAX - *m < (ULONGLONG)b->data[bnum_idx(b, b->e-2)] * LIMB_MAX) return FALSE;
736 *m += (ULONGLONG)b->data[bnum_idx(b, b->e-2)] * LIMB_MAX;
737 if(b->b == b->e-2) return TRUE;
738 if(MSVCRT_UI64_MAX - *m < b->data[bnum_idx(b, b->e-3)]) return FALSE;
739 *m += b->data[bnum_idx(b, b->e-3)];
740 return TRUE;
743 static struct fpnum fpnum_parse_bnum(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
744 void *ctx, MSVCRT_pthreadlocinfo locinfo, BOOL ldouble, struct bnum *b)
746 #if _MSVCR_VER >= 140
747 MSVCRT_wchar_t _infinity[] = { 'i', 'n', 'f', 'i', 'n', 'i', 't', 'y', 0 };
748 MSVCRT_wchar_t _nan[] = { 'n', 'a', 'n', 0 };
749 MSVCRT_wchar_t *str_match = NULL;
750 int matched=0;
751 #endif
752 BOOL found_digit = FALSE, found_dp = FALSE, found_sign = FALSE;
753 int e2 = 0, dp=0, sign=1, off, limb_digits = 0, i;
754 enum fpmod round = FP_ROUND_ZERO;
755 MSVCRT_wchar_t nch;
756 ULONGLONG m;
758 nch = get(ctx);
759 if(nch == '-') {
760 found_sign = TRUE;
761 sign = -1;
762 nch = get(ctx);
763 } else if(nch == '+') {
764 found_sign = TRUE;
765 nch = get(ctx);
768 #if _MSVCR_VER >= 140
769 if(nch == _infinity[0] || nch == MSVCRT__toupper(_infinity[0]))
770 str_match = _infinity;
771 if(nch == _nan[0] || nch == MSVCRT__toupper(_nan[0]))
772 str_match = _nan;
773 while(str_match && nch != MSVCRT_WEOF &&
774 (nch == str_match[matched] || nch == MSVCRT__toupper(str_match[matched]))) {
775 nch = get(ctx);
776 matched++;
778 if(str_match) {
779 int keep = 0;
780 if(matched >= 8) keep = 8;
781 else if(matched >= 3) keep = 3;
782 if(nch != MSVCRT_WEOF) unget(ctx);
783 for (; matched > keep; matched--) {
784 unget(ctx);
786 if(keep) {
787 if (str_match == _infinity)
788 return fpnum(sign, 0, 0, FP_VAL_INFINITY);
789 if (str_match == _nan)
790 return fpnum(sign, 0, 0, FP_VAL_NAN);
791 } else if(found_sign) {
792 unget(ctx);
795 return fpnum(0, 0, 0, 0);
798 if(nch == '0') {
799 found_digit = TRUE;
800 nch = get(ctx);
801 if(nch == 'x' || nch == 'X')
802 return fpnum_parse16(get, unget, ctx, sign, locinfo);
804 #endif
806 while(nch == '0') {
807 found_digit = TRUE;
808 nch = get(ctx);
811 b->b = 0;
812 b->e = 1;
813 b->data[0] = 0;
814 while(nch>='0' && nch<='9') {
815 found_digit = TRUE;
816 if(limb_digits == LIMB_DIGITS) {
817 if(bnum_idx(b, b->b-1) == bnum_idx(b, b->e)) break;
818 else {
819 b->b--;
820 b->data[bnum_idx(b, b->b)] = 0;
821 limb_digits = 0;
825 b->data[bnum_idx(b, b->b)] = b->data[bnum_idx(b, b->b)] * 10 + nch - '0';
826 limb_digits++;
827 nch = get(ctx);
828 dp++;
830 while(nch>='0' && nch<='9') {
831 if(nch != '0') b->data[bnum_idx(b, b->b)] |= 1;
832 nch = get(ctx);
833 dp++;
836 if(nch == *locinfo->lconv->decimal_point) {
837 found_dp = TRUE;
838 nch = get(ctx);
841 /* skip leading '0' */
842 if(nch=='0' && !limb_digits && !b->b) {
843 found_digit = TRUE;
844 while(nch == '0') {
845 nch = get(ctx);
846 dp--;
850 while(nch>='0' && nch<='9') {
851 found_digit = TRUE;
852 if(limb_digits == LIMB_DIGITS) {
853 if(bnum_idx(b, b->b-1) == bnum_idx(b, b->e)) break;
854 else {
855 b->b--;
856 b->data[bnum_idx(b, b->b)] = 0;
857 limb_digits = 0;
861 b->data[bnum_idx(b, b->b)] = b->data[bnum_idx(b, b->b)] * 10 + nch - '0';
862 limb_digits++;
863 nch = get(ctx);
865 while(nch>='0' && nch<='9') {
866 if(nch != '0') b->data[bnum_idx(b, b->b)] |= 1;
867 nch = get(ctx);
870 if(!found_digit) {
871 if(nch != MSVCRT_WEOF) unget(ctx);
872 if(found_dp) unget(ctx);
873 if(found_sign) unget(ctx);
874 return fpnum(0, 0, 0, 0);
877 if(nch=='e' || nch=='E' || nch=='d' || nch=='D') {
878 int e=0, s=1;
880 nch = get(ctx);
881 if(nch == '-') {
882 found_sign = TRUE;
883 s = -1;
884 nch = get(ctx);
885 } else if(nch == '+') {
886 found_sign = TRUE;
887 nch = get(ctx);
888 } else {
889 found_sign = FALSE;
892 if(nch>='0' && nch<='9') {
893 while(nch>='0' && nch<='9') {
894 if(e>INT_MAX/10 || e*10>INT_MAX-nch+'0')
895 e = INT_MAX;
896 else
897 e = e*10+nch-'0';
898 nch = get(ctx);
900 if(nch != MSVCRT_WEOF) unget(ctx);
901 e *= s;
903 if(e<0 && dp<INT_MIN-e) dp = INT_MIN;
904 else if(e>0 && dp>INT_MAX-e) dp = INT_MAX;
905 else dp += e;
906 } else {
907 if(nch != MSVCRT_WEOF) unget(ctx);
908 if(found_sign) unget(ctx);
909 unget(ctx);
911 } else if(nch != MSVCRT_WEOF) {
912 unget(ctx);
915 if(!b->data[bnum_idx(b, b->e-1)])
916 return fpnum(sign, 0, 0, 0);
918 /* Fill last limb with 0 if needed */
919 if(b->b+1 != b->e) {
920 for(; limb_digits != LIMB_DIGITS; limb_digits++)
921 b->data[bnum_idx(b, b->b)] *= 10;
923 for(; bnum_idx(b, b->b) < bnum_idx(b, b->e); b->b++) {
924 if(b->data[bnum_idx(b, b->b)]) break;
927 /* move decimal point to limb boundary */
928 if(limb_digits==dp && b->b==b->e-1)
929 return fpnum(sign, 0, b->data[bnum_idx(b, b->e-1)], FP_ROUND_ZERO);
930 off = (dp - limb_digits) % LIMB_DIGITS;
931 if(off < 0) off += LIMB_DIGITS;
932 if(off) bnum_mult(b, p10s[off]);
934 if(dp-1 > (ldouble ? DBL80_MAX_10_EXP : MSVCRT_DBL_MAX_10_EXP))
935 return fpnum(sign, INT_MAX, 1, FP_ROUND_ZERO);
936 /* Count part of exponent stored in denormalized mantissa. */
937 /* Increase exponent range to handle subnormals. */
938 if(dp-1 < (ldouble ? DBL80_MIN_10_EXP : MSVCRT_DBL_MIN_10_EXP-MSVCRT_DBL_DIG-18))
939 return fpnum(sign, INT_MIN, 1, FP_ROUND_ZERO);
941 while(dp > 3*LIMB_DIGITS) {
942 if(bnum_rshift(b, 9)) dp -= LIMB_DIGITS;
943 e2 += 9;
945 while(dp <= 2*LIMB_DIGITS) {
946 if(bnum_lshift(b, 29)) dp += LIMB_DIGITS;
947 e2 -= 29;
949 /* Make sure most significant mantissa bit will be set */
950 while(b->data[bnum_idx(b, b->e-1)] <= 9) {
951 bnum_lshift(b, 1);
952 e2--;
954 while(!bnum_to_mant(b, &m)) {
955 bnum_rshift(b, 1);
956 e2++;
959 if(b->e-4 >= b->b && b->data[bnum_idx(b, b->e-4)]) {
960 if(b->data[bnum_idx(b, b->e-4)] > LIMB_MAX/2) round = FP_ROUND_UP;
961 else if(b->data[bnum_idx(b, b->e-4)] == LIMB_MAX/2) round = FP_ROUND_EVEN;
962 else round = FP_ROUND_DOWN;
964 if(round == FP_ROUND_ZERO || round == FP_ROUND_EVEN) {
965 for(i=b->e-5; i>=b->b; i--) {
966 if(!b->data[bnum_idx(b, b->b)]) continue;
967 if(round == FP_ROUND_EVEN) round = FP_ROUND_UP;
968 else round = FP_ROUND_DOWN;
972 return fpnum(sign, e2, m, round);
975 struct fpnum fpnum_parse(MSVCRT_wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
976 void *ctx, MSVCRT_pthreadlocinfo locinfo, BOOL ldouble)
978 if(!ldouble) {
979 BYTE bnum_data[FIELD_OFFSET(struct bnum, data[BNUM_PREC64])];
980 struct bnum *b = (struct bnum*)bnum_data;
982 b->size = BNUM_PREC64;
983 return fpnum_parse_bnum(get, unget, ctx, locinfo, ldouble, b);
984 } else {
985 BYTE bnum_data[FIELD_OFFSET(struct bnum, data[BNUM_PREC80])];
986 struct bnum *b = (struct bnum*)bnum_data;
988 b->size = BNUM_PREC80;
989 return fpnum_parse_bnum(get, unget, ctx, locinfo, ldouble, b);
993 static MSVCRT_wchar_t strtod_str_get(void *ctx)
995 const char **p = ctx;
996 if (!**p) return MSVCRT_WEOF;
997 return *(*p)++;
1000 static void strtod_str_unget(void *ctx)
1002 const char **p = ctx;
1003 (*p)--;
1006 static inline double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale, int *perr)
1008 MSVCRT_pthreadlocinfo locinfo;
1009 const char *beg, *p;
1010 struct fpnum fp;
1011 double ret;
1012 int err;
1014 if (perr) *perr = 0;
1015 #if _MSVCR_VER == 0
1016 else *MSVCRT__errno() = 0;
1017 #endif
1019 if (!MSVCRT_CHECK_PMT(str != NULL)) {
1020 if (end) *end = NULL;
1021 return 0;
1024 if (!locale)
1025 locinfo = get_locinfo();
1026 else
1027 locinfo = locale->locinfo;
1029 p = str;
1030 while(MSVCRT__isspace_l((unsigned char)*p, locale))
1031 p++;
1032 beg = p;
1034 fp = fpnum_parse(strtod_str_get, strtod_str_unget, &p, locinfo, FALSE);
1035 if (end) *end = (p == beg ? (char*)str : (char*)p);
1037 err = fpnum_double(&fp, &ret);
1038 if (perr) *perr = err;
1039 else if(err) *MSVCRT__errno() = err;
1040 return ret;
1043 /*********************************************************************
1044 * strtod_l (MSVCRT.@)
1046 double CDECL MSVCRT_strtod_l(const char *str, char **end, MSVCRT__locale_t locale)
1048 return strtod_helper(str, end, locale, NULL);
1051 /*********************************************************************
1052 * strtod (MSVCRT.@)
1054 double CDECL MSVCRT_strtod( const char *str, char **end )
1056 return MSVCRT_strtod_l( str, end, NULL );
1059 #if _MSVCR_VER>=120
1061 /*********************************************************************
1062 * strtof_l (MSVCR120.@)
1064 float CDECL MSVCRT__strtof_l( const char *str, char **end, MSVCRT__locale_t locale )
1066 return MSVCRT_strtod_l(str, end, locale);
1069 /*********************************************************************
1070 * strtof (MSVCR120.@)
1072 float CDECL MSVCRT_strtof( const char *str, char **end )
1074 return MSVCRT__strtof_l(str, end, NULL);
1077 #endif /* _MSVCR_VER>=120 */
1079 /*********************************************************************
1080 * atof (MSVCRT.@)
1082 double CDECL MSVCRT_atof( const char *str )
1084 return MSVCRT_strtod_l(str, NULL, NULL);
1087 /*********************************************************************
1088 * _atof_l (MSVCRT.@)
1090 double CDECL MSVCRT__atof_l( const char *str, MSVCRT__locale_t locale)
1092 return MSVCRT_strtod_l(str, NULL, locale);
1095 /*********************************************************************
1096 * _atoflt_l (MSVCRT.@)
1098 int CDECL MSVCRT__atoflt_l( MSVCRT__CRT_FLOAT *value, char *str, MSVCRT__locale_t locale)
1100 double d;
1101 int err;
1103 d = strtod_helper(str, NULL, locale, &err);
1104 value->f = d;
1105 if(isinf(value->f))
1106 return MSVCRT__OVERFLOW;
1107 if((d!=0 || err) && value->f>-MSVCRT_FLT_MIN && value->f<MSVCRT_FLT_MIN)
1108 return MSVCRT__UNDERFLOW;
1109 return 0;
1112 /*********************************************************************
1113 * _atoflt (MSVCR100.@)
1115 int CDECL MSVCRT__atoflt(MSVCRT__CRT_FLOAT *value, char *str)
1117 return MSVCRT__atoflt_l(value, str, NULL);
1120 /*********************************************************************
1121 * _atodbl_l (MSVCRT.@)
1123 int CDECL MSVCRT__atodbl_l(MSVCRT__CRT_DOUBLE *value, char *str, MSVCRT__locale_t locale)
1125 int err;
1127 value->x = strtod_helper(str, NULL, locale, &err);
1128 if(isinf(value->x))
1129 return MSVCRT__OVERFLOW;
1130 if((value->x!=0 || err) && value->x>-MSVCRT_DBL_MIN && value->x<MSVCRT_DBL_MIN)
1131 return MSVCRT__UNDERFLOW;
1132 return 0;
1135 /*********************************************************************
1136 * _atodbl (MSVCRT.@)
1138 int CDECL MSVCRT__atodbl(MSVCRT__CRT_DOUBLE *value, char *str)
1140 return MSVCRT__atodbl_l(value, str, NULL);
1143 /*********************************************************************
1144 * _strcoll_l (MSVCRT.@)
1146 int CDECL MSVCRT_strcoll_l( const char* str1, const char* str2, MSVCRT__locale_t locale )
1148 MSVCRT_pthreadlocinfo locinfo;
1150 if(!locale)
1151 locinfo = get_locinfo();
1152 else
1153 locinfo = locale->locinfo;
1155 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
1156 return MSVCRT_strcmp(str1, str2);
1157 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], 0, str1, -1, str2, -1)-CSTR_EQUAL;
1160 /*********************************************************************
1161 * strcoll (MSVCRT.@)
1163 int CDECL MSVCRT_strcoll( const char* str1, const char* str2 )
1165 return MSVCRT_strcoll_l(str1, str2, NULL);
1168 /*********************************************************************
1169 * _stricoll_l (MSVCRT.@)
1171 int CDECL MSVCRT__stricoll_l( const char* str1, const char* str2, MSVCRT__locale_t locale )
1173 MSVCRT_pthreadlocinfo locinfo;
1175 if(!locale)
1176 locinfo = get_locinfo();
1177 else
1178 locinfo = locale->locinfo;
1180 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
1181 return MSVCRT__stricmp(str1, str2);
1182 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], NORM_IGNORECASE,
1183 str1, -1, str2, -1)-CSTR_EQUAL;
1186 /*********************************************************************
1187 * _stricoll (MSVCRT.@)
1189 int CDECL MSVCRT__stricoll( const char* str1, const char* str2 )
1191 return MSVCRT__stricoll_l(str1, str2, NULL);
1194 /*********************************************************************
1195 * _strncoll_l (MSVCRT.@)
1197 int CDECL MSVCRT__strncoll_l( const char* str1, const char* str2, MSVCRT_size_t count, MSVCRT__locale_t locale )
1199 MSVCRT_pthreadlocinfo locinfo;
1201 if(!locale)
1202 locinfo = get_locinfo();
1203 else
1204 locinfo = locale->locinfo;
1206 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
1207 return MSVCRT_strncmp(str1, str2, count);
1208 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], 0,
1209 str1, MSVCRT_strnlen(str1, count),
1210 str2, MSVCRT_strnlen(str2, count))-CSTR_EQUAL;
1213 /*********************************************************************
1214 * _strncoll (MSVCRT.@)
1216 int CDECL MSVCRT__strncoll( const char* str1, const char* str2, MSVCRT_size_t count )
1218 return MSVCRT__strncoll_l(str1, str2, count, NULL);
1221 /*********************************************************************
1222 * _strnicoll_l (MSVCRT.@)
1224 int CDECL MSVCRT__strnicoll_l( const char* str1, const char* str2, MSVCRT_size_t count, MSVCRT__locale_t locale )
1226 MSVCRT_pthreadlocinfo locinfo;
1228 if(!locale)
1229 locinfo = get_locinfo();
1230 else
1231 locinfo = locale->locinfo;
1233 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
1234 return MSVCRT__strnicmp(str1, str2, count);
1235 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], NORM_IGNORECASE,
1236 str1, MSVCRT_strnlen(str1, count),
1237 str2, MSVCRT_strnlen(str2, count))-CSTR_EQUAL;
1240 /*********************************************************************
1241 * _strnicoll (MSVCRT.@)
1243 int CDECL MSVCRT__strnicoll( const char* str1, const char* str2, MSVCRT_size_t count )
1245 return MSVCRT__strnicoll_l(str1, str2, count, NULL);
1248 /*********************************************************************
1249 * strncpy (MSVCRT.@)
1251 char* __cdecl MSVCRT_strncpy(char *dst, const char *src, MSVCRT_size_t len)
1253 MSVCRT_size_t i;
1255 for(i=0; i<len; i++)
1256 if((dst[i] = src[i]) == '\0') break;
1258 while (i < len) dst[i++] = 0;
1260 return dst;
1263 /*********************************************************************
1264 * strcpy (MSVCRT.@)
1266 char* CDECL MSVCRT_strcpy(char *dst, const char *src)
1268 char *ret = dst;
1269 while ((*dst++ = *src++));
1270 return ret;
1273 /*********************************************************************
1274 * strcpy_s (MSVCRT.@)
1276 int CDECL MSVCRT_strcpy_s( char* dst, MSVCRT_size_t elem, const char* src )
1278 MSVCRT_size_t i;
1279 if(!elem) return MSVCRT_EINVAL;
1280 if(!dst) return MSVCRT_EINVAL;
1281 if(!src)
1283 dst[0] = '\0';
1284 return MSVCRT_EINVAL;
1287 for(i = 0; i < elem; i++)
1289 if((dst[i] = src[i]) == '\0') return 0;
1291 dst[0] = '\0';
1292 return MSVCRT_ERANGE;
1295 /*********************************************************************
1296 * strcat_s (MSVCRT.@)
1298 int CDECL MSVCRT_strcat_s( char* dst, MSVCRT_size_t elem, const char* src )
1300 MSVCRT_size_t i, j;
1301 if(!dst) return MSVCRT_EINVAL;
1302 if(elem == 0) return MSVCRT_EINVAL;
1303 if(!src)
1305 dst[0] = '\0';
1306 return MSVCRT_EINVAL;
1309 for(i = 0; i < elem; i++)
1311 if(dst[i] == '\0')
1313 for(j = 0; (j + i) < elem; j++)
1315 if((dst[j + i] = src[j]) == '\0') return 0;
1319 /* Set the first element to 0, not the first element after the skipped part */
1320 dst[0] = '\0';
1321 return MSVCRT_ERANGE;
1324 /*********************************************************************
1325 * strcat (MSVCRT.@)
1327 char* __cdecl MSVCRT_strcat( char *dst, const char *src )
1329 char *d = dst;
1330 while (*d) d++;
1331 while ((*d++ = *src++));
1332 return dst;
1335 /*********************************************************************
1336 * strncat_s (MSVCRT.@)
1338 int CDECL MSVCRT_strncat_s( char* dst, MSVCRT_size_t elem, const char* src, MSVCRT_size_t count )
1340 MSVCRT_size_t i, j;
1342 if (!MSVCRT_CHECK_PMT(dst != 0)) return MSVCRT_EINVAL;
1343 if (!MSVCRT_CHECK_PMT(elem != 0)) return MSVCRT_EINVAL;
1344 if (!MSVCRT_CHECK_PMT(src != 0))
1346 dst[0] = '\0';
1347 return MSVCRT_EINVAL;
1350 for(i = 0; i < elem; i++)
1352 if(dst[i] == '\0')
1354 for(j = 0; (j + i) < elem; j++)
1356 if(count == MSVCRT__TRUNCATE && j + i == elem - 1)
1358 dst[j + i] = '\0';
1359 return MSVCRT_STRUNCATE;
1361 if(j == count || (dst[j + i] = src[j]) == '\0')
1363 dst[j + i] = '\0';
1364 return 0;
1369 /* Set the first element to 0, not the first element after the skipped part */
1370 dst[0] = '\0';
1371 return MSVCRT_ERANGE;
1374 /*********************************************************************
1375 * strncat (MSVCRT.@)
1377 char* __cdecl MSVCRT_strncat(char *dst, const char *src, MSVCRT_size_t len)
1379 char *d = dst;
1380 while (*d) d++;
1381 for ( ; len && *src; d++, src++, len--) *d = *src;
1382 *d = 0;
1383 return dst;
1386 /*********************************************************************
1387 * _strxfrm_l (MSVCRT.@)
1389 MSVCRT_size_t CDECL MSVCRT__strxfrm_l( char *dest, const char *src,
1390 MSVCRT_size_t len, MSVCRT__locale_t locale )
1392 MSVCRT_pthreadlocinfo locinfo;
1393 int ret;
1395 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
1396 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
1398 if(len > INT_MAX) {
1399 FIXME("len > INT_MAX not supported\n");
1400 len = INT_MAX;
1403 if(!locale)
1404 locinfo = get_locinfo();
1405 else
1406 locinfo = locale->locinfo;
1408 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE]) {
1409 MSVCRT_strncpy(dest, src, len);
1410 return strlen(src);
1413 ret = LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
1414 LCMAP_SORTKEY, src, -1, NULL, 0);
1415 if(!ret) {
1416 if(len) dest[0] = 0;
1417 *MSVCRT__errno() = MSVCRT_EILSEQ;
1418 return INT_MAX;
1420 if(!len) return ret-1;
1422 if(ret > len) {
1423 dest[0] = 0;
1424 *MSVCRT__errno() = MSVCRT_ERANGE;
1425 return ret-1;
1428 return LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
1429 LCMAP_SORTKEY, src, -1, dest, len) - 1;
1432 /*********************************************************************
1433 * strxfrm (MSVCRT.@)
1435 MSVCRT_size_t CDECL MSVCRT_strxfrm( char *dest, const char *src, MSVCRT_size_t len )
1437 return MSVCRT__strxfrm_l(dest, src, len, NULL);
1440 /********************************************************************
1441 * __STRINGTOLD_L (MSVCR80.@)
1443 int CDECL __STRINGTOLD_L( MSVCRT__LDOUBLE *value, char **endptr,
1444 const char *str, int flags, MSVCRT__locale_t locale )
1446 MSVCRT_pthreadlocinfo locinfo;
1447 const char *beg, *p;
1448 int err, ret = 0;
1449 struct fpnum fp;
1451 if (flags) FIXME("flags not supported: %x\n", flags);
1453 if (!locale)
1454 locinfo = get_locinfo();
1455 else
1456 locinfo = locale->locinfo;
1458 p = str;
1459 while (MSVCRT__isspace_l((unsigned char)*p, locale))
1460 p++;
1461 beg = p;
1463 fp = fpnum_parse(strtod_str_get, strtod_str_unget, &p, locinfo, TRUE);
1464 if (endptr) *endptr = (p == beg ? (char*)str : (char*)p);
1465 if (p == beg) ret = 4;
1467 err = fpnum_ldouble(&fp, value);
1468 if (err) ret = (value->x80[2] & 0x7fff ? 2 : 1);
1469 return ret;
1472 /********************************************************************
1473 * __STRINGTOLD (MSVCRT.@)
1475 int CDECL __STRINGTOLD( MSVCRT__LDOUBLE *value, char **endptr, const char *str, int flags )
1477 return __STRINGTOLD_L( value, endptr, str, flags, NULL );
1480 /********************************************************************
1481 * _atoldbl_l (MSVCRT.@)
1483 int CDECL MSVCRT__atoldbl_l( MSVCRT__LDOUBLE *value, const char *str, MSVCRT__locale_t locale )
1485 char *endptr;
1486 switch(__STRINGTOLD_L( value, &endptr, str, 0, locale ))
1488 case 1: return MSVCRT__UNDERFLOW;
1489 case 2: return MSVCRT__OVERFLOW;
1490 default: return 0;
1494 /********************************************************************
1495 * _atoldbl (MSVCRT.@)
1497 int CDECL MSVCRT__atoldbl(MSVCRT__LDOUBLE *value, const char *str)
1499 return MSVCRT__atoldbl_l( value, str, NULL );
1502 /*********************************************************************
1503 * strlen (MSVCRT.@)
1505 MSVCRT_size_t __cdecl MSVCRT_strlen(const char *str)
1507 const char *s = str;
1508 while (*s) s++;
1509 return s - str;
1512 /******************************************************************
1513 * strnlen (MSVCRT.@)
1515 MSVCRT_size_t CDECL MSVCRT_strnlen(const char *s, MSVCRT_size_t maxlen)
1517 MSVCRT_size_t i;
1519 for(i=0; i<maxlen; i++)
1520 if(!s[i]) break;
1522 return i;
1525 /*********************************************************************
1526 * _strtoi64_l (MSVCRT.@)
1528 * FIXME: locale parameter is ignored
1530 __int64 CDECL MSVCRT_strtoi64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
1532 const char *p = nptr;
1533 BOOL negative = FALSE;
1534 BOOL got_digit = FALSE;
1535 __int64 ret = 0;
1537 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1539 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1540 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1541 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1543 while(MSVCRT__isspace_l((unsigned char)*nptr, locale)) nptr++;
1545 if(*nptr == '-') {
1546 negative = TRUE;
1547 nptr++;
1548 } else if(*nptr == '+')
1549 nptr++;
1551 if((base==0 || base==16) && *nptr=='0' && MSVCRT__tolower_l(*(nptr+1), locale)=='x') {
1552 base = 16;
1553 nptr += 2;
1556 if(base == 0) {
1557 if(*nptr=='0')
1558 base = 8;
1559 else
1560 base = 10;
1563 while(*nptr) {
1564 char cur = MSVCRT__tolower_l(*nptr, locale);
1565 int v;
1567 if(cur>='0' && cur<='9') {
1568 if(cur >= '0'+base)
1569 break;
1570 v = cur-'0';
1571 } else {
1572 if(cur<'a' || cur>='a'+base-10)
1573 break;
1574 v = cur-'a'+10;
1576 got_digit = TRUE;
1578 if(negative)
1579 v = -v;
1581 nptr++;
1583 if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
1584 ret = MSVCRT_I64_MAX;
1585 *MSVCRT__errno() = MSVCRT_ERANGE;
1586 } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
1587 ret = MSVCRT_I64_MIN;
1588 *MSVCRT__errno() = MSVCRT_ERANGE;
1589 } else
1590 ret = ret*base + v;
1593 if(endptr)
1594 *endptr = (char*)(got_digit ? nptr : p);
1596 return ret;
1599 /*********************************************************************
1600 * _strtoi64 (MSVCRT.@)
1602 __int64 CDECL MSVCRT_strtoi64(const char *nptr, char **endptr, int base)
1604 return MSVCRT_strtoi64_l(nptr, endptr, base, NULL);
1607 /*********************************************************************
1608 * _atoi_l (MSVCRT.@)
1610 int __cdecl MSVCRT__atoi_l(const char *str, MSVCRT__locale_t locale)
1612 __int64 ret = MSVCRT_strtoi64_l(str, NULL, 10, locale);
1614 if(ret > INT_MAX) {
1615 ret = INT_MAX;
1616 *MSVCRT__errno() = MSVCRT_ERANGE;
1617 } else if(ret < INT_MIN) {
1618 ret = INT_MIN;
1619 *MSVCRT__errno() = MSVCRT_ERANGE;
1621 return ret;
1624 /*********************************************************************
1625 * atoi (MSVCRT.@)
1627 #if _MSVCR_VER == 0
1628 int __cdecl MSVCRT_atoi(const char *str)
1630 BOOL minus = FALSE;
1631 int ret = 0;
1633 if(!str)
1634 return 0;
1636 while(MSVCRT__isspace_l((unsigned char)*str, NULL)) str++;
1638 if(*str == '+') {
1639 str++;
1640 }else if(*str == '-') {
1641 minus = TRUE;
1642 str++;
1645 while(*str>='0' && *str<='9') {
1646 ret = ret*10+*str-'0';
1647 str++;
1650 return minus ? -ret : ret;
1652 #else
1653 int CDECL MSVCRT_atoi(const char *str)
1655 return MSVCRT__atoi_l(str, NULL);
1657 #endif
1659 /******************************************************************
1660 * _atoi64_l (MSVCRT.@)
1662 __int64 CDECL MSVCRT__atoi64_l(const char *str, MSVCRT__locale_t locale)
1664 return MSVCRT_strtoi64_l(str, NULL, 10, locale);
1667 /******************************************************************
1668 * _atoi64 (MSVCRT.@)
1670 __int64 CDECL MSVCRT__atoi64(const char *str)
1672 return MSVCRT_strtoi64_l(str, NULL, 10, NULL);
1675 /******************************************************************
1676 * _atol_l (MSVCRT.@)
1678 MSVCRT_long CDECL MSVCRT__atol_l(const char *str, MSVCRT__locale_t locale)
1680 __int64 ret = MSVCRT_strtoi64_l(str, NULL, 10, locale);
1682 if(ret > MSVCRT_LONG_MAX) {
1683 ret = MSVCRT_LONG_MAX;
1684 *MSVCRT__errno() = MSVCRT_ERANGE;
1685 } else if(ret < MSVCRT_LONG_MIN) {
1686 ret = MSVCRT_LONG_MIN;
1687 *MSVCRT__errno() = MSVCRT_ERANGE;
1689 return ret;
1692 /******************************************************************
1693 * atol (MSVCRT.@)
1695 MSVCRT_long CDECL MSVCRT_atol(const char *str)
1697 #if _MSVCR_VER == 0
1698 return MSVCRT_atoi(str);
1699 #else
1700 return MSVCRT__atol_l(str, NULL);
1701 #endif
1704 #if _MSVCR_VER>=120
1706 /******************************************************************
1707 * _atoll_l (MSVCR120.@)
1709 MSVCRT_longlong CDECL MSVCRT__atoll_l(const char* str, MSVCRT__locale_t locale)
1711 return MSVCRT_strtoi64_l(str, NULL, 10, locale);
1714 /******************************************************************
1715 * atoll (MSVCR120.@)
1717 MSVCRT_longlong CDECL MSVCRT_atoll(const char* str)
1719 return MSVCRT__atoll_l(str, NULL);
1722 #endif /* if _MSVCR_VER>=120 */
1724 /******************************************************************
1725 * _strtol_l (MSVCRT.@)
1727 MSVCRT_long CDECL MSVCRT__strtol_l(const char* nptr,
1728 char** end, int base, MSVCRT__locale_t locale)
1730 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1732 if(ret > MSVCRT_LONG_MAX) {
1733 ret = MSVCRT_LONG_MAX;
1734 *MSVCRT__errno() = MSVCRT_ERANGE;
1735 } else if(ret < MSVCRT_LONG_MIN) {
1736 ret = MSVCRT_LONG_MIN;
1737 *MSVCRT__errno() = MSVCRT_ERANGE;
1740 return ret;
1743 /******************************************************************
1744 * strtol (MSVCRT.@)
1746 MSVCRT_long CDECL MSVCRT_strtol(const char* nptr, char** end, int base)
1748 return MSVCRT__strtol_l(nptr, end, base, NULL);
1751 /******************************************************************
1752 * _strtoul_l (MSVCRT.@)
1754 MSVCRT_ulong CDECL MSVCRT_strtoul_l(const char* nptr, char** end, int base, MSVCRT__locale_t locale)
1756 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1758 if(ret > MSVCRT_ULONG_MAX) {
1759 ret = MSVCRT_ULONG_MAX;
1760 *MSVCRT__errno() = MSVCRT_ERANGE;
1761 }else if(ret < -(__int64)MSVCRT_ULONG_MAX) {
1762 ret = 1;
1763 *MSVCRT__errno() = MSVCRT_ERANGE;
1766 return ret;
1769 /******************************************************************
1770 * strtoul (MSVCRT.@)
1772 MSVCRT_ulong CDECL MSVCRT_strtoul(const char* nptr, char** end, int base)
1774 return MSVCRT_strtoul_l(nptr, end, base, NULL);
1777 /*********************************************************************
1778 * _strtoui64_l (MSVCRT.@)
1780 * FIXME: locale parameter is ignored
1782 unsigned __int64 CDECL MSVCRT_strtoui64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
1784 const char *p = nptr;
1785 BOOL negative = FALSE;
1786 BOOL got_digit = FALSE;
1787 unsigned __int64 ret = 0;
1789 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1791 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1792 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1793 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1795 while(MSVCRT__isspace_l((unsigned char)*nptr, locale)) nptr++;
1797 if(*nptr == '-') {
1798 negative = TRUE;
1799 nptr++;
1800 } else if(*nptr == '+')
1801 nptr++;
1803 if((base==0 || base==16) && *nptr=='0' && MSVCRT__tolower_l(*(nptr+1), locale)=='x') {
1804 base = 16;
1805 nptr += 2;
1808 if(base == 0) {
1809 if(*nptr=='0')
1810 base = 8;
1811 else
1812 base = 10;
1815 while(*nptr) {
1816 char cur = MSVCRT__tolower_l(*nptr, locale);
1817 int v;
1819 if(cur>='0' && cur<='9') {
1820 if(cur >= '0'+base)
1821 break;
1822 v = *nptr-'0';
1823 } else {
1824 if(cur<'a' || cur>='a'+base-10)
1825 break;
1826 v = cur-'a'+10;
1828 got_digit = TRUE;
1830 nptr++;
1832 if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1833 ret = MSVCRT_UI64_MAX;
1834 *MSVCRT__errno() = MSVCRT_ERANGE;
1835 } else
1836 ret = ret*base + v;
1839 if(endptr)
1840 *endptr = (char*)(got_digit ? nptr : p);
1842 return negative ? -ret : ret;
1845 /*********************************************************************
1846 * _strtoui64 (MSVCRT.@)
1848 unsigned __int64 CDECL MSVCRT_strtoui64(const char *nptr, char **endptr, int base)
1850 return MSVCRT_strtoui64_l(nptr, endptr, base, NULL);
1853 static int ltoa_helper(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1855 MSVCRT_ulong val;
1856 unsigned int digit;
1857 BOOL is_negative;
1858 char buffer[33], *pos;
1859 size_t len;
1861 if (value < 0 && radix == 10)
1863 is_negative = TRUE;
1864 val = -value;
1866 else
1868 is_negative = FALSE;
1869 val = value;
1872 pos = buffer + 32;
1873 *pos = '\0';
1877 digit = val % radix;
1878 val /= radix;
1880 if (digit < 10)
1881 *--pos = '0' + digit;
1882 else
1883 *--pos = 'a' + digit - 10;
1885 while (val != 0);
1887 if (is_negative)
1888 *--pos = '-';
1890 len = buffer + 33 - pos;
1891 if (len > size)
1893 size_t i;
1894 char *p = str;
1896 /* Copy the temporary buffer backwards up to the available number of
1897 * characters. Don't copy the negative sign if present. */
1899 if (is_negative)
1901 p++;
1902 size--;
1905 for (pos = buffer + 31, i = 0; i < size; i++)
1906 *p++ = *pos--;
1908 str[0] = '\0';
1909 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1910 return MSVCRT_ERANGE;
1913 memcpy(str, pos, len);
1914 return 0;
1917 /*********************************************************************
1918 * _ltoa_s (MSVCRT.@)
1920 int CDECL MSVCRT__ltoa_s(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1922 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1923 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1924 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1926 str[0] = '\0';
1927 return MSVCRT_EINVAL;
1930 return ltoa_helper(value, str, size, radix);
1933 /*********************************************************************
1934 * _ltow_s (MSVCRT.@)
1936 int CDECL MSVCRT__ltow_s(MSVCRT_long value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1938 MSVCRT_ulong val;
1939 unsigned int digit;
1940 BOOL is_negative;
1941 MSVCRT_wchar_t buffer[33], *pos;
1942 size_t len;
1944 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1945 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1946 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1948 str[0] = '\0';
1949 return MSVCRT_EINVAL;
1952 if (value < 0 && radix == 10)
1954 is_negative = TRUE;
1955 val = -value;
1957 else
1959 is_negative = FALSE;
1960 val = value;
1963 pos = buffer + 32;
1964 *pos = '\0';
1968 digit = val % radix;
1969 val /= radix;
1971 if (digit < 10)
1972 *--pos = '0' + digit;
1973 else
1974 *--pos = 'a' + digit - 10;
1976 while (val != 0);
1978 if (is_negative)
1979 *--pos = '-';
1981 len = buffer + 33 - pos;
1982 if (len > size)
1984 size_t i;
1985 MSVCRT_wchar_t *p = str;
1987 /* Copy the temporary buffer backwards up to the available number of
1988 * characters. Don't copy the negative sign if present. */
1990 if (is_negative)
1992 p++;
1993 size--;
1996 for (pos = buffer + 31, i = 0; i < size; i++)
1997 *p++ = *pos--;
1999 str[0] = '\0';
2000 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
2001 return MSVCRT_ERANGE;
2004 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
2005 return 0;
2008 /*********************************************************************
2009 * _itoa_s (MSVCRT.@)
2011 int CDECL MSVCRT__itoa_s(int value, char *str, MSVCRT_size_t size, int radix)
2013 return MSVCRT__ltoa_s(value, str, size, radix);
2016 /*********************************************************************
2017 * _itoa (MSVCRT.@)
2019 char* CDECL MSVCRT__itoa(int value, char *str, int radix)
2021 return ltoa_helper(value, str, MSVCRT_SIZE_MAX, radix) ? NULL : str;
2024 /*********************************************************************
2025 * _itow_s (MSVCRT.@)
2027 int CDECL MSVCRT__itow_s(int value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
2029 return MSVCRT__ltow_s(value, str, size, radix);
2032 /*********************************************************************
2033 * _ui64toa_s (MSVCRT.@)
2035 int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str,
2036 MSVCRT_size_t size, int radix)
2038 char buffer[65], *pos;
2039 int digit;
2041 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
2042 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
2043 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2045 str[0] = '\0';
2046 return MSVCRT_EINVAL;
2049 pos = buffer+64;
2050 *pos = '\0';
2052 do {
2053 digit = value%radix;
2054 value /= radix;
2056 if(digit < 10)
2057 *--pos = '0'+digit;
2058 else
2059 *--pos = 'a'+digit-10;
2060 }while(value != 0);
2062 if(buffer-pos+65 > size) {
2063 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
2064 return MSVCRT_EINVAL;
2067 memcpy(str, pos, buffer-pos+65);
2068 return 0;
2071 /*********************************************************************
2072 * _ui64tow_s (MSVCRT.@)
2074 int CDECL MSVCRT__ui64tow_s( unsigned __int64 value, MSVCRT_wchar_t *str,
2075 MSVCRT_size_t size, int radix )
2077 MSVCRT_wchar_t buffer[65], *pos;
2078 int digit;
2080 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
2081 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
2082 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2084 str[0] = '\0';
2085 return MSVCRT_EINVAL;
2088 pos = &buffer[64];
2089 *pos = '\0';
2091 do {
2092 digit = value % radix;
2093 value = value / radix;
2094 if (digit < 10)
2095 *--pos = '0' + digit;
2096 else
2097 *--pos = 'a' + digit - 10;
2098 } while (value != 0);
2100 if(buffer-pos+65 > size) {
2101 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
2102 return MSVCRT_EINVAL;
2105 memcpy(str, pos, (buffer-pos+65)*sizeof(MSVCRT_wchar_t));
2106 return 0;
2109 /*********************************************************************
2110 * _ultoa_s (MSVCRT.@)
2112 int CDECL MSVCRT__ultoa_s(MSVCRT_ulong value, char *str, MSVCRT_size_t size, int radix)
2114 MSVCRT_ulong digit;
2115 char buffer[33], *pos;
2116 size_t len;
2118 if (!str || !size || radix < 2 || radix > 36)
2120 if (str && size)
2121 str[0] = '\0';
2123 *MSVCRT__errno() = MSVCRT_EINVAL;
2124 return MSVCRT_EINVAL;
2127 pos = buffer + 32;
2128 *pos = '\0';
2132 digit = value % radix;
2133 value /= radix;
2135 if (digit < 10)
2136 *--pos = '0' + digit;
2137 else
2138 *--pos = 'a' + digit - 10;
2140 while (value != 0);
2142 len = buffer + 33 - pos;
2143 if (len > size)
2145 size_t i;
2146 char *p = str;
2148 /* Copy the temporary buffer backwards up to the available number of
2149 * characters. */
2151 for (pos = buffer + 31, i = 0; i < size; i++)
2152 *p++ = *pos--;
2154 str[0] = '\0';
2155 *MSVCRT__errno() = MSVCRT_ERANGE;
2156 return MSVCRT_ERANGE;
2159 memcpy(str, pos, len);
2160 return 0;
2163 /*********************************************************************
2164 * _ultow_s (MSVCRT.@)
2166 int CDECL MSVCRT__ultow_s(MSVCRT_ulong value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
2168 MSVCRT_ulong digit;
2169 WCHAR buffer[33], *pos;
2170 size_t len;
2172 if (!str || !size || radix < 2 || radix > 36)
2174 if (str && size)
2175 str[0] = '\0';
2177 *MSVCRT__errno() = MSVCRT_EINVAL;
2178 return MSVCRT_EINVAL;
2181 pos = buffer + 32;
2182 *pos = '\0';
2186 digit = value % radix;
2187 value /= radix;
2189 if (digit < 10)
2190 *--pos = '0' + digit;
2191 else
2192 *--pos = 'a' + digit - 10;
2194 while (value != 0);
2196 len = buffer + 33 - pos;
2197 if (len > size)
2199 size_t i;
2200 WCHAR *p = str;
2202 /* Copy the temporary buffer backwards up to the available number of
2203 * characters. */
2205 for (pos = buffer + 31, i = 0; i < size; i++)
2206 *p++ = *pos--;
2208 str[0] = '\0';
2209 *MSVCRT__errno() = MSVCRT_ERANGE;
2210 return MSVCRT_ERANGE;
2213 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
2214 return 0;
2217 /*********************************************************************
2218 * _i64toa_s (MSVCRT.@)
2220 int CDECL MSVCRT__i64toa_s(__int64 value, char *str, MSVCRT_size_t size, int radix)
2222 unsigned __int64 val;
2223 unsigned int digit;
2224 BOOL is_negative;
2225 char buffer[65], *pos;
2226 size_t len;
2228 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
2229 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
2230 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2232 str[0] = '\0';
2233 return MSVCRT_EINVAL;
2236 if (value < 0 && radix == 10)
2238 is_negative = TRUE;
2239 val = -value;
2241 else
2243 is_negative = FALSE;
2244 val = value;
2247 pos = buffer + 64;
2248 *pos = '\0';
2252 digit = val % radix;
2253 val /= radix;
2255 if (digit < 10)
2256 *--pos = '0' + digit;
2257 else
2258 *--pos = 'a' + digit - 10;
2260 while (val != 0);
2262 if (is_negative)
2263 *--pos = '-';
2265 len = buffer + 65 - pos;
2266 if (len > size)
2268 size_t i;
2269 char *p = str;
2271 /* Copy the temporary buffer backwards up to the available number of
2272 * characters. Don't copy the negative sign if present. */
2274 if (is_negative)
2276 p++;
2277 size--;
2280 for (pos = buffer + 63, i = 0; i < size; i++)
2281 *p++ = *pos--;
2283 str[0] = '\0';
2284 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
2285 return MSVCRT_ERANGE;
2288 memcpy(str, pos, len);
2289 return 0;
2292 /*********************************************************************
2293 * _i64tow_s (MSVCRT.@)
2295 int CDECL MSVCRT__i64tow_s(__int64 value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
2297 unsigned __int64 val;
2298 unsigned int digit;
2299 BOOL is_negative;
2300 MSVCRT_wchar_t buffer[65], *pos;
2301 size_t len;
2303 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
2304 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
2305 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2307 str[0] = '\0';
2308 return MSVCRT_EINVAL;
2311 if (value < 0 && radix == 10)
2313 is_negative = TRUE;
2314 val = -value;
2316 else
2318 is_negative = FALSE;
2319 val = value;
2322 pos = buffer + 64;
2323 *pos = '\0';
2327 digit = val % radix;
2328 val /= radix;
2330 if (digit < 10)
2331 *--pos = '0' + digit;
2332 else
2333 *--pos = 'a' + digit - 10;
2335 while (val != 0);
2337 if (is_negative)
2338 *--pos = '-';
2340 len = buffer + 65 - pos;
2341 if (len > size)
2343 size_t i;
2344 MSVCRT_wchar_t *p = str;
2346 /* Copy the temporary buffer backwards up to the available number of
2347 * characters. Don't copy the negative sign if present. */
2349 if (is_negative)
2351 p++;
2352 size--;
2355 for (pos = buffer + 63, i = 0; i < size; i++)
2356 *p++ = *pos--;
2358 str[0] = '\0';
2359 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
2360 return MSVCRT_ERANGE;
2363 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
2364 return 0;
2367 #define I10_OUTPUT_MAX_PREC 21
2368 /* Internal structure used by $I10_OUTPUT */
2369 struct _I10_OUTPUT_DATA {
2370 short pos;
2371 char sign;
2372 BYTE len;
2373 char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */
2376 /*********************************************************************
2377 * $I10_OUTPUT (MSVCRT.@)
2378 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
2379 * prec - precision of part, we're interested in
2380 * flag - 0 for first prec digits, 1 for fractional part
2381 * data - data to be populated
2383 * return value
2384 * 0 if given double is NaN or INF
2385 * 1 otherwise
2387 * FIXME
2388 * Native sets last byte of data->str to '0' or '9', I don't know what
2389 * it means. Current implementation sets it always to '0'.
2391 int CDECL MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data)
2393 static const char inf_str[] = "1#INF";
2394 static const char nan_str[] = "1#QNAN";
2396 /* MS' long double type wants 12 bytes for Intel's 80 bit FP format.
2397 * Some UNIX have sizeof(long double) == 16, yet only 80 bit are used.
2398 * Assume long double uses 80 bit FP, never seen 128 bit FP. */
2399 long double ld = 0;
2400 double d;
2401 char format[8];
2402 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
2403 char *p;
2405 memcpy(&ld, &ld80, 10);
2406 d = ld;
2407 TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
2409 if(d<0) {
2410 data->sign = '-';
2411 d = -d;
2412 } else
2413 data->sign = ' ';
2415 if(isinf(d)) {
2416 data->pos = 1;
2417 data->len = 5;
2418 memcpy(data->str, inf_str, sizeof(inf_str));
2420 return 0;
2423 if(isnan(d)) {
2424 data->pos = 1;
2425 data->len = 6;
2426 memcpy(data->str, nan_str, sizeof(nan_str));
2428 return 0;
2431 if(flag&1) {
2432 int exp = 1+floor(log10(d));
2434 prec += exp;
2435 if(exp < 0)
2436 prec--;
2438 prec--;
2440 if(prec+1 > I10_OUTPUT_MAX_PREC)
2441 prec = I10_OUTPUT_MAX_PREC-1;
2442 else if(prec < 0) {
2443 d = 0.0;
2444 prec = 0;
2447 MSVCRT_sprintf(format, "%%.%dle", prec);
2448 MSVCRT_sprintf(buf, format, d);
2450 buf[1] = buf[0];
2451 data->pos = atoi(buf+prec+3);
2452 if(buf[1] != '0')
2453 data->pos++;
2455 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
2456 data->len = p-buf;
2458 memcpy(data->str, buf+1, data->len);
2459 data->str[data->len] = '\0';
2461 if(buf[1]!='0' && prec-data->len+1>0)
2462 memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1);
2464 return 1;
2466 #undef I10_OUTPUT_MAX_PREC
2468 /*********************************************************************
2469 * memcmp (MSVCRT.@)
2471 int __cdecl MSVCRT_memcmp(const void *ptr1, const void *ptr2, MSVCRT_size_t n)
2473 const unsigned char *p1, *p2;
2475 for (p1 = ptr1, p2 = ptr2; n; n--, p1++, p2++)
2477 if (*p1 < *p2) return -1;
2478 if (*p1 > *p2) return 1;
2480 return 0;
2483 /*********************************************************************
2484 * memmove (MSVCRT.@)
2486 #ifdef WORDS_BIGENDIAN
2487 # define MERGE(w1, sh1, w2, sh2) ((w1 << sh1) | (w2 >> sh2))
2488 #else
2489 # define MERGE(w1, sh1, w2, sh2) ((w1 >> sh1) | (w2 << sh2))
2490 #endif
2491 void * __cdecl MSVCRT_memmove(void *dst, const void *src, MSVCRT_size_t n)
2493 unsigned char *d = dst;
2494 const unsigned char *s = src;
2495 int sh1;
2497 if (!n) return dst;
2499 if ((MSVCRT_size_t)dst - (MSVCRT_size_t)src >= n)
2501 for (; (MSVCRT_size_t)d % sizeof(MSVCRT_size_t) && n; n--) *d++ = *s++;
2503 sh1 = 8 * ((MSVCRT_size_t)s % sizeof(MSVCRT_size_t));
2504 if (!sh1)
2506 while (n >= sizeof(MSVCRT_size_t))
2508 *(MSVCRT_size_t*)d = *(MSVCRT_size_t*)s;
2509 s += sizeof(MSVCRT_size_t);
2510 d += sizeof(MSVCRT_size_t);
2511 n -= sizeof(MSVCRT_size_t);
2514 else if (n >= 2 * sizeof(MSVCRT_size_t))
2516 int sh2 = 8 * sizeof(MSVCRT_size_t) - sh1;
2517 MSVCRT_size_t x, y;
2519 s -= sh1 / 8;
2520 x = *(MSVCRT_size_t*)s;
2523 s += sizeof(MSVCRT_size_t);
2524 y = *(MSVCRT_size_t*)s;
2525 *(MSVCRT_size_t*)d = MERGE(x, sh1, y, sh2);
2526 d += sizeof(MSVCRT_size_t);
2528 s += sizeof(MSVCRT_size_t);
2529 x = *(MSVCRT_size_t*)s;
2530 *(MSVCRT_size_t*)d = MERGE(y, sh1, x, sh2);
2531 d += sizeof(MSVCRT_size_t);
2533 n -= 2 * sizeof(MSVCRT_size_t);
2534 } while (n >= 2 * sizeof(MSVCRT_size_t));
2535 s += sh1 / 8;
2537 while (n--) *d++ = *s++;
2538 return dst;
2540 else
2542 d += n;
2543 s += n;
2545 for (; (MSVCRT_size_t)d % sizeof(MSVCRT_size_t) && n; n--) *--d = *--s;
2547 sh1 = 8 * ((MSVCRT_size_t)s % sizeof(MSVCRT_size_t));
2548 if (!sh1)
2550 while (n >= sizeof(MSVCRT_size_t))
2552 s -= sizeof(MSVCRT_size_t);
2553 d -= sizeof(MSVCRT_size_t);
2554 *(MSVCRT_size_t*)d = *(MSVCRT_size_t*)s;
2555 n -= sizeof(MSVCRT_size_t);
2558 else if (n >= 2 * sizeof(MSVCRT_size_t))
2560 int sh2 = 8 * sizeof(MSVCRT_size_t) - sh1;
2561 MSVCRT_size_t x, y;
2563 s -= sh1 / 8;
2564 x = *(MSVCRT_size_t*)s;
2567 s -= sizeof(MSVCRT_size_t);
2568 y = *(MSVCRT_size_t*)s;
2569 d -= sizeof(MSVCRT_size_t);
2570 *(MSVCRT_size_t*)d = MERGE(y, sh1, x, sh2);
2572 s -= sizeof(MSVCRT_size_t);
2573 x = *(MSVCRT_size_t*)s;
2574 d -= sizeof(MSVCRT_size_t);
2575 *(MSVCRT_size_t*)d = MERGE(x, sh1, y, sh2);
2577 n -= 2 * sizeof(MSVCRT_size_t);
2578 } while (n >= 2 * sizeof(MSVCRT_size_t));
2579 s += sh1 / 8;
2581 while (n--) *--d = *--s;
2583 return dst;
2585 #undef MERGE
2587 /*********************************************************************
2588 * memcpy (MSVCRT.@)
2590 void * __cdecl MSVCRT_memcpy(void *dst, const void *src, MSVCRT_size_t n)
2592 return MSVCRT_memmove(dst, src, n);
2595 /*********************************************************************
2596 * memset (MSVCRT.@)
2598 void* __cdecl MSVCRT_memset(void *dst, int c, MSVCRT_size_t n)
2600 volatile unsigned char *d = dst; /* avoid gcc optimizations */
2601 while (n--) *d++ = c;
2602 return dst;
2605 /*********************************************************************
2606 * strchr (MSVCRT.@)
2608 char* __cdecl MSVCRT_strchr(const char *str, int c)
2612 if (*str == (char)c) return (char*)str;
2613 } while (*str++);
2614 return NULL;
2617 /*********************************************************************
2618 * strrchr (MSVCRT.@)
2620 char* __cdecl MSVCRT_strrchr(const char *str, int c)
2622 char *ret = NULL;
2623 do { if (*str == (char)c) ret = (char*)str; } while (*str++);
2624 return ret;
2627 /*********************************************************************
2628 * memchr (MSVCRT.@)
2630 void* __cdecl MSVCRT_memchr(const void *ptr, int c, MSVCRT_size_t n)
2632 const unsigned char *p = ptr;
2634 for (p = ptr; n; n--, p++) if (*p == c) return (void *)(ULONG_PTR)p;
2635 return NULL;
2638 /*********************************************************************
2639 * strcmp (MSVCRT.@)
2641 int __cdecl MSVCRT_strcmp(const char *str1, const char *str2)
2643 while (*str1 && *str1 == *str2) { str1++; str2++; }
2644 if ((unsigned char)*str1 > (unsigned char)*str2) return 1;
2645 if ((unsigned char)*str1 < (unsigned char)*str2) return -1;
2646 return 0;
2649 /*********************************************************************
2650 * strncmp (MSVCRT.@)
2652 int __cdecl MSVCRT_strncmp(const char *str1, const char *str2, MSVCRT_size_t len)
2654 if (!len) return 0;
2655 while (--len && *str1 && *str1 == *str2) { str1++; str2++; }
2656 return (unsigned char)*str1 - (unsigned char)*str2;
2659 /*********************************************************************
2660 * _strnicmp_l (MSVCRT.@)
2662 int __cdecl MSVCRT__strnicmp_l(const char *s1, const char *s2,
2663 MSVCRT_size_t count, MSVCRT__locale_t locale)
2665 MSVCRT_pthreadlocinfo locinfo;
2666 int c1, c2;
2668 if(s1==NULL || s2==NULL)
2669 return MSVCRT__NLSCMPERROR;
2671 if(!count)
2672 return 0;
2674 if(!locale)
2675 locinfo = get_locinfo();
2676 else
2677 locinfo = locale->locinfo;
2679 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
2681 do {
2682 if ((c1 = *s1++) >= 'A' && c1 <= 'Z')
2683 c1 -= 'A' - 'a';
2684 if ((c2 = *s2++) >= 'A' && c2 <= 'Z')
2685 c2 -= 'A' - 'a';
2686 }while(--count && c1 && c1==c2);
2688 return c1-c2;
2691 do {
2692 c1 = MSVCRT__tolower_l((unsigned char)*s1++, locale);
2693 c2 = MSVCRT__tolower_l((unsigned char)*s2++, locale);
2694 }while(--count && c1 && c1==c2);
2696 return c1-c2;
2699 /*********************************************************************
2700 * _stricmp_l (MSVCRT.@)
2702 int __cdecl MSVCRT__stricmp_l(const char *s1, const char *s2, MSVCRT__locale_t locale)
2704 return MSVCRT__strnicmp_l(s1, s2, -1, locale);
2707 /*********************************************************************
2708 * _strnicmp (MSVCRT.@)
2710 int __cdecl MSVCRT__strnicmp(const char *s1, const char *s2, MSVCRT_size_t count)
2712 return MSVCRT__strnicmp_l(s1, s2, count, NULL);
2715 /*********************************************************************
2716 * _stricmp (MSVCRT.@)
2718 int __cdecl MSVCRT__stricmp(const char *s1, const char *s2)
2720 return MSVCRT__strnicmp_l(s1, s2, -1, NULL);
2723 /*********************************************************************
2724 * strstr (MSVCRT.@)
2726 char* __cdecl MSVCRT_strstr(const char *haystack, const char *needle)
2728 MSVCRT_size_t i, j, len, needle_len, lps_len;
2729 BYTE lps[256];
2731 needle_len = MSVCRT_strlen(needle);
2732 if (!needle_len) return (char*)haystack;
2733 lps_len = needle_len > ARRAY_SIZE(lps) ? ARRAY_SIZE(lps) : needle_len;
2735 lps[0] = 0;
2736 len = 0;
2737 i = 1;
2738 while (i < lps_len)
2740 if (needle[i] == needle[len]) lps[i++] = ++len;
2741 else if (len) len = lps[len-1];
2742 else lps[i++] = 0;
2745 i = j = 0;
2746 while (haystack[i])
2748 while (j < lps_len && haystack[i] && haystack[i] == needle[j])
2750 i++;
2751 j++;
2754 if (j == needle_len) return (char*)haystack + i - j;
2755 else if (j)
2757 if (j == ARRAY_SIZE(lps) && !MSVCRT_strncmp(haystack + i, needle + j, needle_len - j))
2758 return (char*)haystack + i - j;
2759 j = lps[j-1];
2761 else if (haystack[i]) i++;
2763 return NULL;
2766 /*********************************************************************
2767 * _memicmp_l (MSVCRT.@)
2769 int __cdecl MSVCRT__memicmp_l(const char *s1, const char *s2, MSVCRT_size_t len, MSVCRT__locale_t locale)
2771 int ret = 0;
2773 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
2774 if (!s1 || !s2)
2776 if (len)
2777 MSVCRT_INVALID_PMT(NULL, EINVAL);
2778 return len ? MSVCRT__NLSCMPERROR : 0;
2780 #endif
2782 while (len--)
2784 if ((ret = MSVCRT__tolower_l(*s1, locale) - MSVCRT__tolower_l(*s2, locale)))
2785 break;
2786 s1++;
2787 s2++;
2789 return ret;
2792 /*********************************************************************
2793 * _memicmp (MSVCRT.@)
2795 int __cdecl MSVCRT__memicmp(const char *s1, const char *s2, MSVCRT_size_t len)
2797 return MSVCRT__memicmp_l(s1, s2, len, NULL);
2800 /*********************************************************************
2801 * strcspn (MSVCRT.@)
2803 MSVCRT_size_t __cdecl MSVCRT_strcspn(const char *str, const char *reject)
2805 BOOL rejects[256];
2806 const char *p;
2808 memset(rejects, 0, sizeof(rejects));
2810 p = reject;
2811 while(*p)
2813 rejects[(unsigned char)*p] = TRUE;
2814 p++;
2817 p = str;
2818 while(*p && !rejects[(unsigned char)*p]) p++;
2819 return p - str;
2822 /*********************************************************************
2823 * strpbrk (MSVCRT.@)
2825 char* __cdecl MSVCRT_strpbrk(const char *str, const char *accept)
2827 for (; *str; str++) if (strchr( accept, *str )) return (char*)str;
2828 return NULL;
2831 /*********************************************************************
2832 * __strncnt (MSVCRT.@)
2834 MSVCRT_size_t __cdecl MSVCRT___strncnt(const char *str, MSVCRT_size_t size)
2836 MSVCRT_size_t ret = 0;
2838 #if _MSVCR_VER >= 140
2839 while (*str++ && size--)
2840 #else
2841 while (size-- && *str++)
2842 #endif
2844 ret++;
2847 return ret;
2851 #ifdef _CRTDLL
2852 /*********************************************************************
2853 * _strdec (CRTDLL.@)
2855 char * CDECL _strdec(const char *str1, const char *str2)
2857 return (char *)(str2 - 1);
2860 /*********************************************************************
2861 * _strinc (CRTDLL.@)
2863 char * CDECL _strinc(const char *str)
2865 return (char *)(str + 1);
2868 /*********************************************************************
2869 * _strnextc (CRTDLL.@)
2871 unsigned int CDECL _strnextc(const char *str)
2873 return (unsigned char)str[0];
2876 /*********************************************************************
2877 * _strninc (CRTDLL.@)
2879 char * CDECL _strninc(const char *str, size_t len)
2881 return (char *)(str + len);
2884 /*********************************************************************
2885 * _strspnp (CRTDLL.@)
2887 char * CDECL _strspnp( const char *str1, const char *str2)
2889 str1 += strspn( str1, str2 );
2890 return *str1 ? (char*)str1 : NULL;
2892 #endif