wow64: In wow64_NtSetInformationToken forward TokenIntegrityLevel.
[wine.git] / dlls / msvcrt / string.c
blob571ca34b84723f1bbac63849675064a3502b260f
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 #include <assert.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <math.h>
28 #include <limits.h>
29 #include <locale.h>
30 #include <float.h>
31 #include "msvcrt.h"
32 #include "bnum.h"
33 #include "winnls.h"
34 #include "wine/asm.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
39 /*********************************************************************
40 * _mbsdup (MSVCRT.@)
41 * _strdup (MSVCRT.@)
43 char* CDECL _strdup(const char* str)
45 if(str)
47 char * ret = malloc(strlen(str)+1);
48 if (ret) strcpy( ret, str );
49 return ret;
51 else return 0;
54 /*********************************************************************
55 * _strlwr_s_l (MSVCRT.@)
57 int CDECL _strlwr_s_l(char *str, size_t len, _locale_t locale)
59 pthreadlocinfo locinfo;
60 char *ptr = str;
62 if (!str || !len)
64 *_errno() = EINVAL;
65 return EINVAL;
68 while (len && *ptr)
70 len--;
71 ptr++;
74 if (!len)
76 str[0] = '\0';
77 *_errno() = EINVAL;
78 return EINVAL;
81 if(!locale)
82 locinfo = get_locinfo();
83 else
84 locinfo = locale->locinfo;
86 if(!locinfo->lc_handle[LC_CTYPE])
88 while (*str)
90 if (*str >= 'A' && *str <= 'Z')
91 *str -= 'A' - 'a';
92 str++;
95 else
97 while (*str)
99 *str = _tolower_l((unsigned char)*str, locale);
100 str++;
104 return 0;
107 /*********************************************************************
108 * _strlwr_s (MSVCRT.@)
110 int CDECL _strlwr_s(char *str, size_t len)
112 return _strlwr_s_l(str, len, NULL);
115 /*********************************************************************
116 * _strlwr_l (MSVCRT.@)
118 char* CDECL _strlwr_l(char *str, _locale_t locale)
120 _strlwr_s_l(str, -1, locale);
121 return str;
124 /*********************************************************************
125 * _strlwr (MSVCRT.@)
127 char* CDECL _strlwr(char *str)
129 _strlwr_s_l(str, -1, NULL);
130 return str;
133 /*********************************************************************
134 * _strupr_s_l (MSVCRT.@)
136 int CDECL _strupr_s_l(char *str, size_t len, _locale_t locale)
138 pthreadlocinfo locinfo;
139 char *ptr = str;
141 if (!str || !len)
143 *_errno() = EINVAL;
144 return EINVAL;
147 while (len && *ptr)
149 len--;
150 ptr++;
153 if (!len)
155 str[0] = '\0';
156 *_errno() = EINVAL;
157 return EINVAL;
160 if(!locale)
161 locinfo = get_locinfo();
162 else
163 locinfo = locale->locinfo;
165 if(!locinfo->lc_handle[LC_CTYPE])
167 while (*str)
169 if (*str >= 'a' && *str <= 'z')
170 *str -= 'a' - 'A';
171 str++;
174 else
176 while (*str)
178 *str = _toupper_l((unsigned char)*str, locale);
179 str++;
183 return 0;
186 /*********************************************************************
187 * _strupr_s (MSVCRT.@)
189 int CDECL _strupr_s(char *str, size_t len)
191 return _strupr_s_l(str, len, NULL);
194 /*********************************************************************
195 * _strupr_l (MSVCRT.@)
197 char* CDECL _strupr_l(char *str, _locale_t locale)
199 _strupr_s_l(str, -1, locale);
200 return str;
203 /*********************************************************************
204 * _strupr (MSVCRT.@)
206 char* CDECL _strupr(char *str)
208 _strupr_s_l(str, -1, NULL);
209 return str;
212 /*********************************************************************
213 * _strnset_s (MSVCRT.@)
215 int CDECL _strnset_s(char *str, size_t size, int c, size_t count)
217 size_t i;
219 if(!str && !size && !count) return 0;
220 if(!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
221 if(!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
223 for(i=0; i<size-1 && i<count; i++) {
224 if(!str[i]) return 0;
225 str[i] = c;
227 for(; i<size; i++)
228 if(!str[i]) return 0;
230 str[0] = 0;
231 _invalid_parameter(NULL, NULL, NULL, 0, 0);
232 *_errno() = EINVAL;
233 return EINVAL;
236 /*********************************************************************
237 * _strnset (MSVCRT.@)
239 char* CDECL _strnset(char* str, int value, size_t len)
241 if (len > 0 && str)
242 while (*str && len--)
243 *str++ = value;
244 return str;
247 /*********************************************************************
248 * _strrev (MSVCRT.@)
250 char* CDECL _strrev(char* str)
252 char * p1;
253 char * p2;
255 if (str && *str)
256 for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
258 *p1 ^= *p2;
259 *p2 ^= *p1;
260 *p1 ^= *p2;
263 return str;
266 /*********************************************************************
267 * _strset (MSVCRT.@)
269 char* CDECL _strset(char* str, int value)
271 char *ptr = str;
272 while (*ptr)
273 *ptr++ = value;
275 return str;
278 /*********************************************************************
279 * strtok (MSVCRT.@)
281 char * CDECL strtok( char *str, const char *delim )
283 thread_data_t *data = msvcrt_get_thread_data();
284 char *ret;
286 if (!str)
287 if (!(str = data->strtok_next)) return NULL;
289 while (*str && strchr( delim, *str )) str++;
290 if (!*str)
292 data->strtok_next = str;
293 return NULL;
295 ret = str++;
296 while (*str && !strchr( delim, *str )) str++;
297 if (*str) *str++ = 0;
298 data->strtok_next = str;
299 return ret;
302 /*********************************************************************
303 * strtok_s (MSVCRT.@)
305 char * CDECL strtok_s(char *str, const char *delim, char **ctx)
307 if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL;
308 if (!MSVCRT_CHECK_PMT(ctx != NULL)) return NULL;
309 if (!MSVCRT_CHECK_PMT(str != NULL || *ctx != NULL)) return NULL;
311 if(!str)
312 str = *ctx;
314 while(*str && strchr(delim, *str))
315 str++;
316 if(!*str)
318 *ctx = str;
319 return NULL;
322 *ctx = str+1;
323 while(**ctx && !strchr(delim, **ctx))
324 (*ctx)++;
325 if(**ctx)
326 *(*ctx)++ = 0;
328 return str;
331 /*********************************************************************
332 * _swab (MSVCRT.@)
334 void CDECL _swab(char* src, char* dst, int len)
336 if (len > 1)
338 len = (unsigned)len >> 1;
340 while (len--) {
341 char s0 = src[0];
342 char s1 = src[1];
343 *dst++ = s1;
344 *dst++ = s0;
345 src = src + 2;
350 static struct fpnum fpnum(int sign, int exp, ULONGLONG m, enum fpmod mod)
352 struct fpnum ret;
354 ret.sign = sign;
355 ret.exp = exp;
356 ret.m = m;
357 ret.mod = mod;
358 return ret;
361 int fpnum_double(struct fpnum *fp, double *d)
363 ULONGLONG bits = 0;
365 if (fp->mod == FP_VAL_INFINITY)
367 *d = fp->sign * INFINITY;
368 return 0;
371 if (fp->mod == FP_VAL_NAN)
373 bits = ~0;
374 if (fp->sign == 1)
375 bits &= ~((ULONGLONG)1 << (MANT_BITS + EXP_BITS - 1));
376 *d = *(double*)&bits;
377 return 0;
380 TRACE("%c %#I64x *2^%d (round %d)\n", fp->sign == -1 ? '-' : '+',
381 fp->m, fp->exp, fp->mod);
382 if (!fp->m)
384 *d = fp->sign * 0.0;
385 return 0;
388 /* make sure that we don't overflow modifying exponent */
389 if (fp->exp > 1<<EXP_BITS)
391 *d = fp->sign * INFINITY;
392 return ERANGE;
394 if (fp->exp < -(1<<EXP_BITS))
396 *d = fp->sign * 0.0;
397 return ERANGE;
399 fp->exp += MANT_BITS - 1;
401 /* normalize mantissa */
402 while(fp->m < (ULONGLONG)1 << (MANT_BITS-1))
404 fp->m <<= 1;
405 fp->exp--;
407 while(fp->m >= (ULONGLONG)1 << MANT_BITS)
409 if (fp->m & 1 || fp->mod != FP_ROUND_ZERO)
411 if (!(fp->m & 1)) fp->mod = FP_ROUND_DOWN;
412 else if(fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
413 else fp->mod = FP_ROUND_UP;
415 fp->m >>= 1;
416 fp->exp++;
418 fp->exp += (1 << (EXP_BITS-1)) - 1;
420 /* handle subnormals */
421 if (fp->exp <= 0)
423 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
424 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
425 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
426 fp->m >>= 1;
428 while(fp->m && fp->exp<0)
430 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
431 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
432 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
433 fp->m >>= 1;
434 fp->exp++;
437 /* round mantissa */
438 if (fp->mod == FP_ROUND_UP || (fp->mod == FP_ROUND_EVEN && fp->m & 1))
440 fp->m++;
442 /* handle subnormal that falls into regular range due to rounding */
443 if (fp->m == (ULONGLONG)1 << (MANT_BITS - 1))
445 fp->exp++;
447 else if (fp->m >= (ULONGLONG)1 << MANT_BITS)
449 fp->exp++;
450 fp->m >>= 1;
454 if (fp->exp >= (1<<EXP_BITS)-1)
456 *d = fp->sign * INFINITY;
457 return ERANGE;
459 if (!fp->m || fp->exp < 0)
461 *d = fp->sign * 0.0;
462 return ERANGE;
465 if (fp->sign == -1)
466 bits |= (ULONGLONG)1 << (MANT_BITS + EXP_BITS - 1);
467 bits |= (ULONGLONG)fp->exp << (MANT_BITS - 1);
468 bits |= fp->m & (((ULONGLONG)1 << (MANT_BITS - 1)) - 1);
470 TRACE("returning %#I64x\n", bits);
471 *d = *(double*)&bits;
472 return 0;
475 #define LDBL_EXP_BITS 15
476 #define LDBL_MANT_BITS 64
477 int fpnum_ldouble(struct fpnum *fp, MSVCRT__LDOUBLE *d)
479 if (fp->mod == FP_VAL_INFINITY)
481 d->x80[0] = 0;
482 d->x80[1] = 0x80000000;
483 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
484 if (fp->sign == -1)
485 d->x80[2] |= 1 << LDBL_EXP_BITS;
486 return 0;
489 if (fp->mod == FP_VAL_NAN)
491 d->x80[0] = ~0;
492 d->x80[1] = ~0;
493 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
494 if (fp->sign == -1)
495 d->x80[2] |= 1 << LDBL_EXP_BITS;
496 return 0;
499 TRACE("%c %#I64x *2^%d (round %d)\n", fp->sign == -1 ? '-' : '+',
500 fp->m, fp->exp, fp->mod);
501 if (!fp->m)
503 d->x80[0] = 0;
504 d->x80[1] = 0;
505 d->x80[2] = 0;
506 if (fp->sign == -1)
507 d->x80[2] |= 1 << LDBL_EXP_BITS;
508 return 0;
511 /* make sure that we don't overflow modifying exponent */
512 if (fp->exp > 1<<LDBL_EXP_BITS)
514 d->x80[0] = 0;
515 d->x80[1] = 0x80000000;
516 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
517 if (fp->sign == -1)
518 d->x80[2] |= 1 << LDBL_EXP_BITS;
519 return ERANGE;
521 if (fp->exp < -(1<<LDBL_EXP_BITS))
523 d->x80[0] = 0;
524 d->x80[1] = 0;
525 d->x80[2] = 0;
526 if (fp->sign == -1)
527 d->x80[2] |= 1 << LDBL_EXP_BITS;
528 return ERANGE;
530 fp->exp += LDBL_MANT_BITS - 1;
532 /* normalize mantissa */
533 while(fp->m < (ULONGLONG)1 << (LDBL_MANT_BITS-1))
535 fp->m <<= 1;
536 fp->exp--;
538 fp->exp += (1 << (LDBL_EXP_BITS-1)) - 1;
540 /* handle subnormals */
541 if (fp->exp <= 0)
543 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
544 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
545 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
546 fp->m >>= 1;
548 while(fp->m && fp->exp<0)
550 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
551 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
552 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
553 fp->m >>= 1;
554 fp->exp++;
557 /* round mantissa */
558 if (fp->mod == FP_ROUND_UP || (fp->mod == FP_ROUND_EVEN && fp->m & 1))
560 if (fp->m == UI64_MAX)
562 fp->m = (ULONGLONG)1 << (LDBL_MANT_BITS - 1);
563 fp->exp++;
565 else
567 fp->m++;
569 /* handle subnormal that falls into regular range due to rounding */
570 if ((fp->m ^ (fp->m - 1)) & ((ULONGLONG)1 << (LDBL_MANT_BITS - 1))) fp->exp++;
574 if (fp->exp >= (1<<LDBL_EXP_BITS)-1)
576 d->x80[0] = 0;
577 d->x80[1] = 0x80000000;
578 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
579 if (fp->sign == -1)
580 d->x80[2] |= 1 << LDBL_EXP_BITS;
581 return ERANGE;
583 if (!fp->m || fp->exp < 0)
585 d->x80[0] = 0;
586 d->x80[1] = 0;
587 d->x80[2] = 0;
588 if (fp->sign == -1)
589 d->x80[2] |= 1 << LDBL_EXP_BITS;
590 return ERANGE;
593 d->x80[0] = fp->m;
594 d->x80[1] = fp->m >> 32;
595 d->x80[2] = fp->exp;
596 if (fp->sign == -1)
597 d->x80[2] |= 1 << LDBL_EXP_BITS;
598 return 0;
601 #if _MSVCR_VER >= 140
603 static inline int hex2int(char c)
605 if (c >= '0' && c <= '9')
606 return c - '0';
607 else if (c >= 'a' && c <= 'f')
608 return c - 'a' + 10;
609 else if (c >= 'A' && c <= 'F')
610 return c - 'A' + 10;
611 return -1;
614 static struct fpnum fpnum_parse16(wchar_t get(void *ctx), void unget(void *ctx),
615 void *ctx, int sign, pthreadlocinfo locinfo)
617 BOOL found_digit = FALSE, found_dp = FALSE;
618 enum fpmod round = FP_ROUND_ZERO;
619 wchar_t nch;
620 ULONGLONG m = 0;
621 int val, exp = 0;
623 nch = get(ctx);
624 while(m < UI64_MAX/16)
626 val = hex2int(nch);
627 if (val == -1) break;
628 found_digit = TRUE;
629 nch = get(ctx);
631 m = m*16 + val;
633 while(1)
635 val = hex2int(nch);
636 if (val == -1) break;
637 nch = get(ctx);
638 exp += 4;
640 if (val || round != FP_ROUND_ZERO)
642 if (val < 8) round = FP_ROUND_DOWN;
643 else if (val == 8 && round == FP_ROUND_ZERO) round = FP_ROUND_EVEN;
644 else round = FP_ROUND_UP;
648 if(nch == *locinfo->lconv->decimal_point)
650 found_dp = TRUE;
651 nch = get(ctx);
653 else if (!found_digit)
655 if(nch!=WEOF) unget(ctx);
656 unget(ctx);
657 return fpnum(0, 0, 0, 0);
660 while(m <= UI64_MAX/16)
662 val = hex2int(nch);
663 if (val == -1) break;
664 found_digit = TRUE;
665 nch = get(ctx);
667 m = m*16 + val;
668 exp -= 4;
670 while(1)
672 val = hex2int(nch);
673 if (val == -1) break;
674 nch = get(ctx);
676 if (val || round != FP_ROUND_ZERO)
678 if (val < 8) round = FP_ROUND_DOWN;
679 else if (val == 8 && round == FP_ROUND_ZERO) round = FP_ROUND_EVEN;
680 else round = FP_ROUND_UP;
684 if (!found_digit)
686 if (nch != WEOF) unget(ctx);
687 if (found_dp) unget(ctx);
688 unget(ctx);
689 return fpnum(0, 0, 0, 0);
692 if(nch=='p' || nch=='P') {
693 BOOL found_sign = FALSE;
694 int e=0, s=1;
696 nch = get(ctx);
697 if(nch == '-') {
698 found_sign = TRUE;
699 s = -1;
700 nch = get(ctx);
701 } else if(nch == '+') {
702 found_sign = TRUE;
703 nch = get(ctx);
705 if(nch>='0' && nch<='9') {
706 while(nch>='0' && nch<='9') {
707 if(e>INT_MAX/10 || e*10>INT_MAX-nch+'0')
708 e = INT_MAX;
709 else
710 e = e*10+nch-'0';
711 nch = get(ctx);
713 if((nch!=WEOF) && (nch < '0' || nch > '9')) unget(ctx);
714 e *= s;
716 if(e<0 && exp<INT_MIN-e) exp = INT_MIN;
717 else if(e>0 && exp>INT_MAX-e) exp = INT_MAX;
718 else exp += e;
719 } else {
720 if(nch != WEOF) unget(ctx);
721 if(found_sign) unget(ctx);
722 unget(ctx);
726 return fpnum(sign, exp, m, round);
728 #endif
730 /* Converts first 3 limbs to ULONGLONG */
731 /* Return FALSE on overflow */
732 static inline BOOL bnum_to_mant(struct bnum *b, ULONGLONG *m)
734 if(UI64_MAX / LIMB_MAX / LIMB_MAX < b->data[bnum_idx(b, b->e-1)]) return FALSE;
735 *m = (ULONGLONG)b->data[bnum_idx(b, b->e-1)] * LIMB_MAX * LIMB_MAX;
736 if(b->b == b->e-1) return TRUE;
737 if(UI64_MAX - *m < (ULONGLONG)b->data[bnum_idx(b, b->e-2)] * LIMB_MAX) return FALSE;
738 *m += (ULONGLONG)b->data[bnum_idx(b, b->e-2)] * LIMB_MAX;
739 if(b->b == b->e-2) return TRUE;
740 if(UI64_MAX - *m < b->data[bnum_idx(b, b->e-3)]) return FALSE;
741 *m += b->data[bnum_idx(b, b->e-3)];
742 return TRUE;
745 static struct fpnum fpnum_parse_bnum(wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
746 void *ctx, pthreadlocinfo locinfo, BOOL ldouble, struct bnum *b)
748 #if _MSVCR_VER >= 140
749 const wchar_t _infinity[] = L"infinity";
750 const wchar_t _nan[] = L"nan";
751 const wchar_t *str_match = NULL;
752 int matched=0;
753 #endif
754 BOOL found_digit = FALSE, found_dp = FALSE, found_sign = FALSE;
755 int e2 = 0, dp=0, sign=1, off, limb_digits = 0, i;
756 enum fpmod round = FP_ROUND_ZERO;
757 wchar_t nch;
758 ULONGLONG m;
760 nch = get(ctx);
761 if(nch == '-') {
762 found_sign = TRUE;
763 sign = -1;
764 nch = get(ctx);
765 } else if(nch == '+') {
766 found_sign = TRUE;
767 nch = get(ctx);
770 #if _MSVCR_VER >= 140
771 if(nch == _infinity[0] || nch == _toupper(_infinity[0]))
772 str_match = _infinity;
773 if(nch == _nan[0] || nch == _toupper(_nan[0]))
774 str_match = _nan;
775 while(str_match && nch != WEOF &&
776 (nch == str_match[matched] || nch == _toupper(str_match[matched]))) {
777 nch = get(ctx);
778 matched++;
780 if(str_match) {
781 int keep = 0;
782 if(matched >= 8) keep = 8;
783 else if(matched >= 3) keep = 3;
784 if(nch != WEOF) unget(ctx);
785 for (; matched > keep; matched--) {
786 unget(ctx);
788 if(keep) {
789 if (str_match == _infinity)
790 return fpnum(sign, 0, 0, FP_VAL_INFINITY);
791 if (str_match == _nan)
792 return fpnum(sign, 0, 0, FP_VAL_NAN);
793 } else if(found_sign) {
794 unget(ctx);
797 return fpnum(0, 0, 0, 0);
800 if(nch == '0') {
801 found_digit = TRUE;
802 nch = get(ctx);
803 if(nch == 'x' || nch == 'X')
804 return fpnum_parse16(get, unget, ctx, sign, locinfo);
806 #endif
808 while(nch == '0') {
809 found_digit = TRUE;
810 nch = get(ctx);
813 b->b = 0;
814 b->e = 1;
815 b->data[0] = 0;
816 while(nch>='0' && nch<='9') {
817 found_digit = TRUE;
818 if(limb_digits == LIMB_DIGITS) {
819 if(bnum_idx(b, b->b-1) == bnum_idx(b, b->e)) break;
820 else {
821 b->b--;
822 b->data[bnum_idx(b, b->b)] = 0;
823 limb_digits = 0;
827 b->data[bnum_idx(b, b->b)] = b->data[bnum_idx(b, b->b)] * 10 + nch - '0';
828 limb_digits++;
829 nch = get(ctx);
830 dp++;
832 while(nch>='0' && nch<='9') {
833 if(nch != '0') b->data[bnum_idx(b, b->b)] |= 1;
834 nch = get(ctx);
835 dp++;
838 if(nch == *locinfo->lconv->decimal_point) {
839 found_dp = TRUE;
840 nch = get(ctx);
843 /* skip leading '0' */
844 if(nch=='0' && !limb_digits && !b->b) {
845 found_digit = TRUE;
846 while(nch == '0') {
847 nch = get(ctx);
848 dp--;
852 while(nch>='0' && nch<='9') {
853 found_digit = TRUE;
854 if(limb_digits == LIMB_DIGITS) {
855 if(bnum_idx(b, b->b-1) == bnum_idx(b, b->e)) break;
856 else {
857 b->b--;
858 b->data[bnum_idx(b, b->b)] = 0;
859 limb_digits = 0;
863 b->data[bnum_idx(b, b->b)] = b->data[bnum_idx(b, b->b)] * 10 + nch - '0';
864 limb_digits++;
865 nch = get(ctx);
867 while(nch>='0' && nch<='9') {
868 if(nch != '0') b->data[bnum_idx(b, b->b)] |= 1;
869 nch = get(ctx);
872 if(!found_digit) {
873 if(nch != WEOF) unget(ctx);
874 if(found_dp) unget(ctx);
875 if(found_sign) unget(ctx);
876 return fpnum(0, 0, 0, 0);
879 if(nch=='e' || nch=='E' || nch=='d' || nch=='D') {
880 int e=0, s=1;
882 nch = get(ctx);
883 if(nch == '-') {
884 found_sign = TRUE;
885 s = -1;
886 nch = get(ctx);
887 } else if(nch == '+') {
888 found_sign = TRUE;
889 nch = get(ctx);
890 } else {
891 found_sign = FALSE;
894 if(nch>='0' && nch<='9') {
895 while(nch>='0' && nch<='9') {
896 if(e>INT_MAX/10 || e*10>INT_MAX-nch+'0')
897 e = INT_MAX;
898 else
899 e = e*10+nch-'0';
900 nch = get(ctx);
902 if(nch != WEOF) unget(ctx);
903 e *= s;
905 if(e<0 && dp<INT_MIN-e) dp = INT_MIN;
906 else if(e>0 && dp>INT_MAX-e) dp = INT_MAX;
907 else dp += e;
908 } else {
909 if(nch != WEOF) unget(ctx);
910 if(found_sign) unget(ctx);
911 unget(ctx);
913 } else if(nch != WEOF) {
914 unget(ctx);
917 if(!b->data[bnum_idx(b, b->e-1)])
918 return fpnum(sign, 0, 0, 0);
920 /* Fill last limb with 0 if needed */
921 if(b->b+1 != b->e) {
922 for(; limb_digits != LIMB_DIGITS; limb_digits++)
923 b->data[bnum_idx(b, b->b)] *= 10;
925 for(; bnum_idx(b, b->b) < bnum_idx(b, b->e); b->b++) {
926 if(b->data[bnum_idx(b, b->b)]) break;
929 /* move decimal point to limb boundary */
930 if(limb_digits==dp && b->b==b->e-1)
931 return fpnum(sign, 0, b->data[bnum_idx(b, b->e-1)], FP_ROUND_ZERO);
932 off = (dp - limb_digits) % LIMB_DIGITS;
933 if(off < 0) off += LIMB_DIGITS;
934 if(off) bnum_mult(b, p10s[off]);
936 if(dp-1 > (ldouble ? DBL80_MAX_10_EXP : DBL_MAX_10_EXP))
937 return fpnum(sign, INT_MAX, 1, FP_ROUND_ZERO);
938 /* Count part of exponent stored in denormalized mantissa. */
939 /* Increase exponent range to handle subnormals. */
940 if(dp-1 < (ldouble ? DBL80_MIN_10_EXP : DBL_MIN_10_EXP-DBL_DIG-18))
941 return fpnum(sign, INT_MIN, 1, FP_ROUND_ZERO);
943 while(dp > 3*LIMB_DIGITS) {
944 if(bnum_rshift(b, 9)) dp -= LIMB_DIGITS;
945 e2 += 9;
947 while(dp <= 2*LIMB_DIGITS) {
948 if(bnum_lshift(b, 29)) dp += LIMB_DIGITS;
949 e2 -= 29;
951 /* Make sure most significant mantissa bit will be set */
952 while(b->data[bnum_idx(b, b->e-1)] <= 9) {
953 bnum_lshift(b, 1);
954 e2--;
956 while(!bnum_to_mant(b, &m)) {
957 bnum_rshift(b, 1);
958 e2++;
961 if(b->e-4 >= b->b && b->data[bnum_idx(b, b->e-4)]) {
962 if(b->data[bnum_idx(b, b->e-4)] > LIMB_MAX/2) round = FP_ROUND_UP;
963 else if(b->data[bnum_idx(b, b->e-4)] == LIMB_MAX/2) round = FP_ROUND_EVEN;
964 else round = FP_ROUND_DOWN;
966 if(round == FP_ROUND_ZERO || round == FP_ROUND_EVEN) {
967 for(i=b->e-5; i>=b->b; i--) {
968 if(!b->data[bnum_idx(b, b->b)]) continue;
969 if(round == FP_ROUND_EVEN) round = FP_ROUND_UP;
970 else round = FP_ROUND_DOWN;
974 return fpnum(sign, e2, m, round);
977 struct fpnum fpnum_parse(wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
978 void *ctx, pthreadlocinfo locinfo, BOOL ldouble)
980 if(!ldouble) {
981 BYTE bnum_data[FIELD_OFFSET(struct bnum, data[BNUM_PREC64])];
982 struct bnum *b = (struct bnum*)bnum_data;
984 b->size = BNUM_PREC64;
985 return fpnum_parse_bnum(get, unget, ctx, locinfo, ldouble, b);
986 } else {
987 BYTE bnum_data[FIELD_OFFSET(struct bnum, data[BNUM_PREC80])];
988 struct bnum *b = (struct bnum*)bnum_data;
990 b->size = BNUM_PREC80;
991 return fpnum_parse_bnum(get, unget, ctx, locinfo, ldouble, b);
995 static wchar_t strtod_str_get(void *ctx)
997 const char **p = ctx;
998 if (!**p) return WEOF;
999 return *(*p)++;
1002 static void strtod_str_unget(void *ctx)
1004 const char **p = ctx;
1005 (*p)--;
1008 static inline double strtod_helper(const char *str, char **end, _locale_t locale, int *perr)
1010 pthreadlocinfo locinfo;
1011 const char *beg, *p;
1012 struct fpnum fp;
1013 double ret;
1014 int err;
1016 if (perr) *perr = 0;
1017 #if _MSVCR_VER == 0
1018 else *_errno() = 0;
1019 #endif
1021 if (!MSVCRT_CHECK_PMT(str != NULL)) {
1022 if (end) *end = NULL;
1023 return 0;
1026 if (!locale)
1027 locinfo = get_locinfo();
1028 else
1029 locinfo = locale->locinfo;
1031 p = str;
1032 while(_isspace_l((unsigned char)*p, locale))
1033 p++;
1034 beg = p;
1036 fp = fpnum_parse(strtod_str_get, strtod_str_unget, &p, locinfo, FALSE);
1037 if (end) *end = (p == beg ? (char*)str : (char*)p);
1039 err = fpnum_double(&fp, &ret);
1040 if (perr) *perr = err;
1041 else if(err) *_errno() = err;
1042 return ret;
1045 /*********************************************************************
1046 * _strtod_l (MSVCRT.@)
1048 double CDECL _strtod_l(const char *str, char **end, _locale_t locale)
1050 return strtod_helper(str, end, locale, NULL);
1053 /*********************************************************************
1054 * strtod (MSVCRT.@)
1056 double CDECL strtod( const char *str, char **end )
1058 return _strtod_l( str, end, NULL );
1061 #if _MSVCR_VER>=120
1063 /*********************************************************************
1064 * strtof_l (MSVCR120.@)
1066 float CDECL _strtof_l( const char *str, char **end, _locale_t locale )
1068 double ret = _strtod_l(str, end, locale);
1069 if (ret && isfinite(ret)) {
1070 float f = ret;
1071 if (!f || !isfinite(f))
1072 *_errno() = ERANGE;
1074 return ret;
1077 /*********************************************************************
1078 * strtof (MSVCR120.@)
1080 float CDECL strtof( const char *str, char **end )
1082 return _strtof_l(str, end, NULL);
1085 #endif /* _MSVCR_VER>=120 */
1087 /*********************************************************************
1088 * atof (MSVCRT.@)
1090 double CDECL atof( const char *str )
1092 return _strtod_l(str, NULL, NULL);
1095 /*********************************************************************
1096 * _atof_l (MSVCRT.@)
1098 double CDECL _atof_l( const char *str, _locale_t locale)
1100 return _strtod_l(str, NULL, locale);
1103 /*********************************************************************
1104 * _atoflt_l (MSVCRT.@)
1106 int CDECL _atoflt_l(_CRT_FLOAT *value, char *str, _locale_t locale)
1108 double d;
1109 int err;
1111 d = strtod_helper(str, NULL, locale, &err);
1112 value->f = d;
1113 if(isinf(value->f))
1114 return _OVERFLOW;
1115 if((d!=0 || err) && value->f>-FLT_MIN && value->f<FLT_MIN)
1116 return _UNDERFLOW;
1117 return 0;
1120 /*********************************************************************
1121 * _atoflt (MSVCR100.@)
1123 int CDECL _atoflt(_CRT_FLOAT *value, char *str)
1125 return _atoflt_l(value, str, NULL);
1128 /*********************************************************************
1129 * _atodbl_l (MSVCRT.@)
1131 int CDECL _atodbl_l(_CRT_DOUBLE *value, char *str, _locale_t locale)
1133 int err;
1135 value->x = strtod_helper(str, NULL, locale, &err);
1136 if(isinf(value->x))
1137 return _OVERFLOW;
1138 if((value->x!=0 || err) && value->x>-DBL_MIN && value->x<DBL_MIN)
1139 return _UNDERFLOW;
1140 return 0;
1143 /*********************************************************************
1144 * _atodbl (MSVCRT.@)
1146 int CDECL _atodbl(_CRT_DOUBLE *value, char *str)
1148 return _atodbl_l(value, str, NULL);
1151 /*********************************************************************
1152 * _strcoll_l (MSVCRT.@)
1154 int CDECL _strcoll_l( const char* str1, const char* str2, _locale_t locale )
1156 pthreadlocinfo locinfo;
1158 if(!locale)
1159 locinfo = get_locinfo();
1160 else
1161 locinfo = locale->locinfo;
1163 if(!locinfo->lc_handle[LC_COLLATE])
1164 return strcmp(str1, str2);
1165 return CompareStringA(locinfo->lc_handle[LC_COLLATE], SORT_STRINGSORT,
1166 str1, -1, str2, -1)-CSTR_EQUAL;
1169 /*********************************************************************
1170 * strcoll (MSVCRT.@)
1172 int CDECL strcoll( const char* str1, const char* str2 )
1174 return _strcoll_l(str1, str2, NULL);
1177 /*********************************************************************
1178 * _stricoll_l (MSVCRT.@)
1180 int CDECL _stricoll_l( const char* str1, const char* str2, _locale_t locale )
1182 pthreadlocinfo locinfo;
1184 if(!locale)
1185 locinfo = get_locinfo();
1186 else
1187 locinfo = locale->locinfo;
1189 if(!locinfo->lc_handle[LC_COLLATE])
1190 return _stricmp(str1, str2);
1191 return CompareStringA(locinfo->lc_handle[LC_COLLATE], NORM_IGNORECASE,
1192 str1, -1, str2, -1)-CSTR_EQUAL;
1195 /*********************************************************************
1196 * _stricoll (MSVCRT.@)
1198 int CDECL _stricoll( const char* str1, const char* str2 )
1200 return _stricoll_l(str1, str2, NULL);
1203 /*********************************************************************
1204 * _strncoll_l (MSVCRT.@)
1206 int CDECL _strncoll_l( const char* str1, const char* str2, size_t count, _locale_t locale )
1208 pthreadlocinfo locinfo;
1210 if(!locale)
1211 locinfo = get_locinfo();
1212 else
1213 locinfo = locale->locinfo;
1215 if(!locinfo->lc_handle[LC_COLLATE])
1216 return strncmp(str1, str2, count);
1217 return CompareStringA(locinfo->lc_handle[LC_COLLATE], SORT_STRINGSORT,
1218 str1, strnlen(str1, count),
1219 str2, strnlen(str2, count))-CSTR_EQUAL;
1222 /*********************************************************************
1223 * _strncoll (MSVCRT.@)
1225 int CDECL _strncoll( const char* str1, const char* str2, size_t count )
1227 return _strncoll_l(str1, str2, count, NULL);
1230 /*********************************************************************
1231 * _strnicoll_l (MSVCRT.@)
1233 int CDECL _strnicoll_l( const char* str1, const char* str2, size_t count, _locale_t locale )
1235 pthreadlocinfo locinfo;
1237 if(!locale)
1238 locinfo = get_locinfo();
1239 else
1240 locinfo = locale->locinfo;
1242 if(!locinfo->lc_handle[LC_COLLATE])
1243 return _strnicmp(str1, str2, count);
1244 return CompareStringA(locinfo->lc_handle[LC_COLLATE], NORM_IGNORECASE,
1245 str1, strnlen(str1, count),
1246 str2, strnlen(str2, count))-CSTR_EQUAL;
1249 /*********************************************************************
1250 * _strnicoll (MSVCRT.@)
1252 int CDECL _strnicoll( const char* str1, const char* str2, size_t count )
1254 return _strnicoll_l(str1, str2, count, NULL);
1257 /*********************************************************************
1258 * strncpy (MSVCRT.@)
1260 char* __cdecl strncpy(char *dst, const char *src, size_t len)
1262 size_t i;
1264 for(i=0; i<len; i++)
1265 if((dst[i] = src[i]) == '\0') break;
1267 while (i < len) dst[i++] = 0;
1269 return dst;
1272 /******************************************************************
1273 * strncpy_s (MSVCRT.@)
1275 int __cdecl strncpy_s( char *dst, size_t elem, const char *src, size_t count )
1277 char *p = dst;
1278 BOOL truncate = (count == _TRUNCATE);
1280 TRACE("(%p %Iu %s %Iu)\n", dst, elem, debugstr_a(src), count);
1282 if (!count)
1284 if (dst && elem) *dst = 0;
1285 return 0;
1288 if (!MSVCRT_CHECK_PMT(dst != NULL)) return EINVAL;
1289 if (!MSVCRT_CHECK_PMT(elem != 0)) return EINVAL;
1290 if (!MSVCRT_CHECK_PMT(src != NULL))
1292 *dst = 0;
1293 return EINVAL;
1296 while (elem && count && *src)
1298 *p++ = *src++;
1299 elem--;
1300 count--;
1302 if (!elem && truncate)
1304 *(p-1) = 0;
1305 return STRUNCATE;
1307 else if (!elem)
1309 *dst = 0;
1310 return ERANGE;
1312 *p = 0;
1313 return 0;
1316 /*********************************************************************
1317 * strcpy (MSVCRT.@)
1319 char* CDECL strcpy(char *dst, const char *src)
1321 char *ret = dst;
1322 while ((*dst++ = *src++));
1323 return ret;
1326 /*********************************************************************
1327 * strcpy_s (MSVCRT.@)
1329 int CDECL strcpy_s( char* dst, size_t elem, const char* src )
1331 size_t i;
1332 if (!MSVCRT_CHECK_PMT(dst != 0)) return EINVAL;
1333 if (!MSVCRT_CHECK_PMT(elem != 0)) return EINVAL;
1334 if (!MSVCRT_CHECK_PMT(src != NULL))
1336 dst[0] = '\0';
1337 return EINVAL;
1340 for(i = 0; i < elem; i++)
1342 if((dst[i] = src[i]) == '\0') return 0;
1344 MSVCRT_INVALID_PMT("dst[elem] is too small", ERANGE);
1345 dst[0] = '\0';
1346 return ERANGE;
1349 /*********************************************************************
1350 * strcat_s (MSVCRT.@)
1352 int CDECL strcat_s( char* dst, size_t elem, const char* src )
1354 size_t i, j;
1355 if (!MSVCRT_CHECK_PMT(dst != 0)) return EINVAL;
1356 if (!MSVCRT_CHECK_PMT(elem != 0)) return EINVAL;
1357 if (!MSVCRT_CHECK_PMT(src != NULL))
1359 dst[0] = '\0';
1360 return EINVAL;
1363 for(i = 0; i < elem; i++)
1365 if(dst[i] == '\0')
1367 for(j = 0; (j + i) < elem; j++)
1369 if((dst[j + i] = src[j]) == '\0') return 0;
1373 /* Set the first element to 0, not the first element after the skipped part */
1374 MSVCRT_INVALID_PMT("dst[elem] is too small", ERANGE);
1375 dst[0] = '\0';
1376 return ERANGE;
1379 /*********************************************************************
1380 * strcat (MSVCRT.@)
1382 char* __cdecl strcat( char *dst, const char *src )
1384 char *d = dst;
1385 while (*d) d++;
1386 while ((*d++ = *src++));
1387 return dst;
1390 /*********************************************************************
1391 * strncat_s (MSVCRT.@)
1393 int CDECL strncat_s( char* dst, size_t elem, const char* src, size_t count )
1395 size_t i, j;
1397 if (!MSVCRT_CHECK_PMT(dst != 0)) return EINVAL;
1398 if (!MSVCRT_CHECK_PMT(elem != 0)) return EINVAL;
1399 if (count == 0) return 0;
1401 if (!MSVCRT_CHECK_PMT(src != NULL))
1403 *dst = 0;
1404 return EINVAL;
1407 for (i = 0; i < elem; i++) if (!dst[i]) break;
1409 if (i == elem)
1411 MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n", EINVAL);
1412 *dst = 0;
1413 return EINVAL;
1416 for (j = 0; (j + i) < elem; j++)
1418 if(count == _TRUNCATE && j + i == elem - 1)
1420 dst[j + i] = '\0';
1421 return STRUNCATE;
1423 if(j == count || (dst[j + i] = src[j]) == '\0')
1425 dst[j + i] = '\0';
1426 return 0;
1430 MSVCRT_INVALID_PMT("dst[elem] is too small", ERANGE);
1431 dst[0] = '\0';
1432 return ERANGE;
1435 /*********************************************************************
1436 * strncat (MSVCRT.@)
1438 char* __cdecl strncat(char *dst, const char *src, size_t len)
1440 char *d = dst;
1441 while (*d) d++;
1442 for ( ; len && *src; d++, src++, len--) *d = *src;
1443 *d = 0;
1444 return dst;
1447 /*********************************************************************
1448 * _strxfrm_l (MSVCRT.@)
1450 size_t CDECL _strxfrm_l( char *dest, const char *src,
1451 size_t len, _locale_t locale )
1453 pthreadlocinfo locinfo;
1454 int ret;
1456 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
1457 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
1459 if(len > INT_MAX) {
1460 FIXME("len > INT_MAX not supported\n");
1461 len = INT_MAX;
1464 if(!locale)
1465 locinfo = get_locinfo();
1466 else
1467 locinfo = locale->locinfo;
1469 if(!locinfo->lc_handle[LC_COLLATE]) {
1470 strncpy(dest, src, len);
1471 return strlen(src);
1474 ret = LCMapStringA(locinfo->lc_handle[LC_COLLATE],
1475 LCMAP_SORTKEY, src, -1, NULL, 0);
1476 if(!ret) {
1477 if(len) dest[0] = 0;
1478 *_errno() = EILSEQ;
1479 return INT_MAX;
1481 if(!len) return ret-1;
1483 if(ret > len) {
1484 dest[0] = 0;
1485 *_errno() = ERANGE;
1486 return ret-1;
1489 return LCMapStringA(locinfo->lc_handle[LC_COLLATE],
1490 LCMAP_SORTKEY, src, -1, dest, len) - 1;
1493 /*********************************************************************
1494 * strxfrm (MSVCRT.@)
1496 size_t CDECL strxfrm( char *dest, const char *src, size_t len )
1498 return _strxfrm_l(dest, src, len, NULL);
1501 /********************************************************************
1502 * __STRINGTOLD_L (MSVCR80.@)
1504 int CDECL __STRINGTOLD_L( MSVCRT__LDOUBLE *value, char **endptr,
1505 const char *str, int flags, _locale_t locale )
1507 pthreadlocinfo locinfo;
1508 const char *beg, *p;
1509 int err, ret = 0;
1510 struct fpnum fp;
1512 if (flags) FIXME("flags not supported: %x\n", flags);
1514 if (!locale)
1515 locinfo = get_locinfo();
1516 else
1517 locinfo = locale->locinfo;
1519 p = str;
1520 while (_isspace_l((unsigned char)*p, locale))
1521 p++;
1522 beg = p;
1524 fp = fpnum_parse(strtod_str_get, strtod_str_unget, &p, locinfo, TRUE);
1525 if (endptr) *endptr = (p == beg ? (char*)str : (char*)p);
1526 if (p == beg) ret = 4;
1528 err = fpnum_ldouble(&fp, value);
1529 if (err) ret = (value->x80[2] & 0x7fff ? 2 : 1);
1530 return ret;
1533 /********************************************************************
1534 * __STRINGTOLD (MSVCRT.@)
1536 int CDECL __STRINGTOLD( MSVCRT__LDOUBLE *value, char **endptr, const char *str, int flags )
1538 return __STRINGTOLD_L( value, endptr, str, flags, NULL );
1541 /********************************************************************
1542 * _atoldbl_l (MSVCRT.@)
1544 int CDECL _atoldbl_l( MSVCRT__LDOUBLE *value, char *str, _locale_t locale )
1546 char *endptr;
1547 switch(__STRINGTOLD_L( value, &endptr, str, 0, locale ))
1549 case 1: return _UNDERFLOW;
1550 case 2: return _OVERFLOW;
1551 default: return 0;
1555 /********************************************************************
1556 * _atoldbl (MSVCRT.@)
1558 int CDECL _atoldbl(_LDOUBLE *value, char *str)
1560 return _atoldbl_l( (MSVCRT__LDOUBLE*)value, str, NULL );
1563 /*********************************************************************
1564 * strlen (MSVCRT.@)
1566 size_t __cdecl strlen(const char *str)
1568 const char *s = str;
1569 while (*s) s++;
1570 return s - str;
1573 /******************************************************************
1574 * strnlen (MSVCRT.@)
1576 size_t CDECL strnlen(const char *s, size_t maxlen)
1578 size_t i;
1580 for(i=0; i<maxlen; i++)
1581 if(!s[i]) break;
1583 return i;
1586 /*********************************************************************
1587 * _strtoi64_l (MSVCRT.@)
1589 * FIXME: locale parameter is ignored
1591 __int64 CDECL _strtoi64_l(const char *nptr, char **endptr, int base, _locale_t locale)
1593 const char *p = nptr;
1594 BOOL negative = FALSE;
1595 BOOL got_digit = FALSE;
1596 __int64 ret = 0;
1598 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1600 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1601 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1602 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1604 while(_isspace_l((unsigned char)*nptr, locale)) nptr++;
1606 if(*nptr == '-') {
1607 negative = TRUE;
1608 nptr++;
1609 } else if(*nptr == '+')
1610 nptr++;
1612 if((base==0 || base==16) && *nptr=='0' && _tolower_l(*(nptr+1), locale)=='x') {
1613 base = 16;
1614 nptr += 2;
1617 if(base == 0) {
1618 if(*nptr=='0')
1619 base = 8;
1620 else
1621 base = 10;
1624 while(*nptr) {
1625 char cur = _tolower_l(*nptr, locale);
1626 int v;
1628 if(cur>='0' && cur<='9') {
1629 if(cur >= '0'+base)
1630 break;
1631 v = cur-'0';
1632 } else {
1633 if(cur<'a' || cur>='a'+base-10)
1634 break;
1635 v = cur-'a'+10;
1637 got_digit = TRUE;
1639 if(negative)
1640 v = -v;
1642 nptr++;
1644 if(!negative && (ret>I64_MAX/base || ret*base>I64_MAX-v)) {
1645 ret = I64_MAX;
1646 *_errno() = ERANGE;
1647 } else if(negative && (ret<I64_MIN/base || ret*base<I64_MIN-v)) {
1648 ret = I64_MIN;
1649 *_errno() = ERANGE;
1650 } else
1651 ret = ret*base + v;
1654 if(endptr)
1655 *endptr = (char*)(got_digit ? nptr : p);
1657 return ret;
1660 /*********************************************************************
1661 * _strtoi64 (MSVCRT.@)
1663 __int64 CDECL _strtoi64(const char *nptr, char **endptr, int base)
1665 return _strtoi64_l(nptr, endptr, base, NULL);
1668 /*********************************************************************
1669 * _atoi_l (MSVCRT.@)
1671 int __cdecl _atoi_l(const char *str, _locale_t locale)
1673 __int64 ret = _strtoi64_l(str, NULL, 10, locale);
1675 if(ret > INT_MAX) {
1676 ret = INT_MAX;
1677 *_errno() = ERANGE;
1678 } else if(ret < INT_MIN) {
1679 ret = INT_MIN;
1680 *_errno() = ERANGE;
1682 return ret;
1685 /*********************************************************************
1686 * atoi (MSVCRT.@)
1688 #if _MSVCR_VER == 0
1689 int __cdecl atoi(const char *str)
1691 BOOL minus = FALSE;
1692 int ret = 0;
1694 if(!str)
1695 return 0;
1697 while(_isspace_l((unsigned char)*str, NULL)) str++;
1699 if(*str == '+') {
1700 str++;
1701 }else if(*str == '-') {
1702 minus = TRUE;
1703 str++;
1706 while(*str>='0' && *str<='9') {
1707 ret = ret*10+*str-'0';
1708 str++;
1711 return minus ? -ret : ret;
1713 #else
1714 int CDECL atoi(const char *str)
1716 return _atoi_l(str, NULL);
1718 #endif
1720 /******************************************************************
1721 * _atoi64_l (MSVCRT.@)
1723 __int64 CDECL _atoi64_l(const char *str, _locale_t locale)
1725 return _strtoi64_l(str, NULL, 10, locale);
1728 /******************************************************************
1729 * _atoi64 (MSVCRT.@)
1731 __int64 CDECL _atoi64(const char *str)
1733 return _strtoi64_l(str, NULL, 10, NULL);
1736 /******************************************************************
1737 * _atol_l (MSVCRT.@)
1739 __msvcrt_long CDECL _atol_l(const char *str, _locale_t locale)
1741 __int64 ret = _strtoi64_l(str, NULL, 10, locale);
1743 if(ret > LONG_MAX) {
1744 ret = LONG_MAX;
1745 *_errno() = ERANGE;
1746 } else if(ret < LONG_MIN) {
1747 ret = LONG_MIN;
1748 *_errno() = ERANGE;
1750 return ret;
1753 /******************************************************************
1754 * atol (MSVCRT.@)
1756 __msvcrt_long CDECL atol(const char *str)
1758 #if _MSVCR_VER == 0
1759 return atoi(str);
1760 #else
1761 return _atol_l(str, NULL);
1762 #endif
1765 #if _MSVCR_VER>=120
1767 /******************************************************************
1768 * _atoll_l (MSVCR120.@)
1770 __int64 CDECL _atoll_l(const char* str, _locale_t locale)
1772 return _strtoi64_l(str, NULL, 10, locale);
1775 /******************************************************************
1776 * atoll (MSVCR120.@)
1778 __int64 CDECL atoll(const char* str)
1780 return _atoll_l(str, NULL);
1783 #endif /* _MSVCR_VER>=120 */
1785 /******************************************************************
1786 * _strtol_l (MSVCRT.@)
1788 __msvcrt_long CDECL _strtol_l(const char* nptr,
1789 char** end, int base, _locale_t locale)
1791 __int64 ret = _strtoi64_l(nptr, end, base, locale);
1793 if(ret > LONG_MAX) {
1794 ret = LONG_MAX;
1795 *_errno() = ERANGE;
1796 } else if(ret < LONG_MIN) {
1797 ret = LONG_MIN;
1798 *_errno() = ERANGE;
1801 return ret;
1804 /******************************************************************
1805 * strtol (MSVCRT.@)
1807 __msvcrt_long CDECL strtol(const char* nptr, char** end, int base)
1809 return _strtol_l(nptr, end, base, NULL);
1812 /******************************************************************
1813 * _strtoul_l (MSVCRT.@)
1815 __msvcrt_ulong CDECL _strtoul_l(const char* nptr, char** end, int base, _locale_t locale)
1817 __int64 ret = _strtoi64_l(nptr, end, base, locale);
1819 if(ret > ULONG_MAX) {
1820 ret = ULONG_MAX;
1821 *_errno() = ERANGE;
1822 }else if(ret < -(__int64)ULONG_MAX) {
1823 ret = 1;
1824 *_errno() = ERANGE;
1827 return ret;
1830 /******************************************************************
1831 * strtoul (MSVCRT.@)
1833 __msvcrt_ulong CDECL strtoul(const char* nptr, char** end, int base)
1835 return _strtoul_l(nptr, end, base, NULL);
1838 /*********************************************************************
1839 * _strtoui64_l (MSVCRT.@)
1841 * FIXME: locale parameter is ignored
1843 unsigned __int64 CDECL _strtoui64_l(const char *nptr, char **endptr, int base, _locale_t locale)
1845 const char *p = nptr;
1846 BOOL negative = FALSE;
1847 BOOL got_digit = FALSE;
1848 unsigned __int64 ret = 0;
1850 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1852 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1853 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1854 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1856 while(_isspace_l((unsigned char)*nptr, locale)) nptr++;
1858 if(*nptr == '-') {
1859 negative = TRUE;
1860 nptr++;
1861 } else if(*nptr == '+')
1862 nptr++;
1864 if((base==0 || base==16) && *nptr=='0' && _tolower_l(*(nptr+1), locale)=='x') {
1865 base = 16;
1866 nptr += 2;
1869 if(base == 0) {
1870 if(*nptr=='0')
1871 base = 8;
1872 else
1873 base = 10;
1876 while(*nptr) {
1877 char cur = _tolower_l(*nptr, locale);
1878 int v;
1880 if(cur>='0' && cur<='9') {
1881 if(cur >= '0'+base)
1882 break;
1883 v = *nptr-'0';
1884 } else {
1885 if(cur<'a' || cur>='a'+base-10)
1886 break;
1887 v = cur-'a'+10;
1889 got_digit = TRUE;
1891 nptr++;
1893 if(ret>UI64_MAX/base || ret*base>UI64_MAX-v) {
1894 ret = UI64_MAX;
1895 *_errno() = ERANGE;
1896 } else
1897 ret = ret*base + v;
1900 if(endptr)
1901 *endptr = (char*)(got_digit ? nptr : p);
1903 return negative ? -ret : ret;
1906 /*********************************************************************
1907 * _strtoui64 (MSVCRT.@)
1909 unsigned __int64 CDECL _strtoui64(const char *nptr, char **endptr, int base)
1911 return _strtoui64_l(nptr, endptr, base, NULL);
1914 static int ltoa_helper(__msvcrt_long value, char *str, size_t size, int radix)
1916 __msvcrt_ulong val;
1917 unsigned int digit;
1918 BOOL is_negative;
1919 char buffer[33], *pos;
1920 size_t len;
1922 if (value < 0 && radix == 10)
1924 is_negative = TRUE;
1925 val = -value;
1927 else
1929 is_negative = FALSE;
1930 val = value;
1933 pos = buffer + 32;
1934 *pos = '\0';
1938 digit = val % radix;
1939 val /= radix;
1941 if (digit < 10)
1942 *--pos = '0' + digit;
1943 else
1944 *--pos = 'a' + digit - 10;
1946 while (val != 0);
1948 if (is_negative)
1949 *--pos = '-';
1951 len = buffer + 33 - pos;
1952 if (len > size)
1954 size_t i;
1955 char *p = str;
1957 /* Copy the temporary buffer backwards up to the available number of
1958 * characters. Don't copy the negative sign if present. */
1960 if (is_negative)
1962 p++;
1963 size--;
1966 for (pos = buffer + 31, i = 0; i < size; i++)
1967 *p++ = *pos--;
1969 str[0] = '\0';
1970 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE);
1971 return ERANGE;
1974 memcpy(str, pos, len);
1975 return 0;
1978 static int ltow_helper(__msvcrt_long value, wchar_t *str, size_t size, int radix)
1980 __msvcrt_ulong val;
1981 unsigned int digit;
1982 BOOL is_negative;
1983 wchar_t buffer[33], *pos;
1984 size_t len;
1986 if (value < 0 && radix == 10)
1988 is_negative = TRUE;
1989 val = -value;
1991 else
1993 is_negative = FALSE;
1994 val = value;
1997 pos = buffer + 32;
1998 *pos = '\0';
2002 digit = val % radix;
2003 val /= radix;
2005 if (digit < 10)
2006 *--pos = '0' + digit;
2007 else
2008 *--pos = 'a' + digit - 10;
2010 while (val != 0);
2012 if (is_negative)
2013 *--pos = '-';
2015 len = buffer + 33 - pos;
2016 if (len > size)
2018 size_t i;
2019 wchar_t *p = str;
2021 /* Copy the temporary buffer backwards up to the available number of
2022 * characters. Don't copy the negative sign if present. */
2024 if (is_negative)
2026 p++;
2027 size--;
2030 for (pos = buffer + 31, i = 0; i < size; i++)
2031 *p++ = *pos--;
2033 str[0] = '\0';
2034 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE);
2035 return ERANGE;
2038 memcpy(str, pos, len * sizeof(wchar_t));
2039 return 0;
2042 /*********************************************************************
2043 * _ltoa_s (MSVCRT.@)
2045 int CDECL _ltoa_s(__msvcrt_long value, char *str, size_t size, int radix)
2047 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
2048 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
2049 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2051 str[0] = '\0';
2052 return EINVAL;
2055 return ltoa_helper(value, str, size, radix);
2058 /*********************************************************************
2059 * _ltow_s (MSVCRT.@)
2061 int CDECL _ltow_s(__msvcrt_long value, wchar_t *str, size_t size, int radix)
2063 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
2064 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
2065 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2067 str[0] = '\0';
2068 return EINVAL;
2071 return ltow_helper(value, str, size, radix);
2074 /*********************************************************************
2075 * _itoa_s (MSVCRT.@)
2077 int CDECL _itoa_s(int value, char *str, size_t size, int radix)
2079 return _ltoa_s(value, str, size, radix);
2082 /*********************************************************************
2083 * _itoa (MSVCRT.@)
2085 char* CDECL _itoa(int value, char *str, int radix)
2087 return ltoa_helper(value, str, SIZE_MAX, radix) ? NULL : str;
2090 /*********************************************************************
2091 * _ltoa (MSVCRT.@)
2093 char* CDECL _ltoa(__msvcrt_long value, char *str, int radix)
2095 return ltoa_helper(value, str, SIZE_MAX, radix) ? NULL : str;
2098 /*********************************************************************
2099 * _itow_s (MSVCRT.@)
2101 int CDECL _itow_s(int value, wchar_t *str, size_t size, int radix)
2103 return _ltow_s(value, str, size, radix);
2106 /*********************************************************************
2107 * _itow (MSVCRT.@)
2109 wchar_t* CDECL _itow(int value, wchar_t *str, int radix)
2111 return ltow_helper(value, str, SIZE_MAX, radix) ? NULL : str;
2114 /*********************************************************************
2115 * _ltow (MSVCRT.@)
2117 wchar_t* CDECL _ltow(__msvcrt_long value, wchar_t *str, int radix)
2119 return ltow_helper(value, str, SIZE_MAX, radix) ? NULL : str;
2122 /*********************************************************************
2123 * _ultoa (MSVCRT.@)
2125 char* CDECL _ultoa(__msvcrt_ulong value, char *str, int radix)
2127 char buffer[33], *pos;
2129 pos = &buffer[32];
2130 *pos = '\0';
2132 do {
2133 int digit = value % radix;
2134 value /= radix;
2136 if (digit < 10)
2137 *--pos = '0' + digit;
2138 else
2139 *--pos = 'a' + digit - 10;
2140 } while (value != 0);
2142 memcpy(str, pos, buffer + 33 - pos);
2143 return str;
2146 /*********************************************************************
2147 * _ui64toa (MSVCRT.@)
2149 char* CDECL _ui64toa(unsigned __int64 value, char *str, int radix)
2151 char buffer[65], *pos;
2153 pos = &buffer[64];
2154 *pos = '\0';
2156 do {
2157 int digit = value % radix;
2158 value /= radix;
2160 if (digit < 10)
2161 *--pos = '0' + digit;
2162 else
2163 *--pos = 'a' + digit - 10;
2164 } while (value != 0);
2166 memcpy(str, pos, buffer + 65 - pos);
2167 return str;
2170 /*********************************************************************
2171 * _ultow (MSVCRT.@)
2173 wchar_t* CDECL _ultow(__msvcrt_ulong value, wchar_t *str, int radix)
2175 wchar_t buffer[33], *pos;
2177 pos = &buffer[32];
2178 *pos = '\0';
2180 do {
2181 int digit = value % radix;
2182 value /= radix;
2184 if (digit < 10)
2185 *--pos = '0' + digit;
2186 else
2187 *--pos = 'a' + digit - 10;
2188 } while (value != 0);
2190 memcpy(str, pos, (buffer + 33 - pos) * sizeof(wchar_t));
2191 return str;
2194 /*********************************************************************
2195 * _ui64tow (MSVCRT.@)
2197 wchar_t* CDECL _ui64tow(unsigned __int64 value, wchar_t *str, int radix)
2199 wchar_t buffer[65], *pos;
2201 pos = &buffer[64];
2202 *pos = '\0';
2204 do {
2205 int digit = value % radix;
2206 value /= radix;
2208 if (digit < 10)
2209 *--pos = '0' + digit;
2210 else
2211 *--pos = 'a' + digit - 10;
2212 } while (value != 0);
2214 memcpy(str, pos, (buffer + 65 - pos) * sizeof(wchar_t));
2215 return str;
2218 /*********************************************************************
2219 * _i64toa (MSVCRT.@)
2221 char* CDECL _i64toa(__int64 value, char *str, int radix)
2223 unsigned __int64 val;
2224 BOOL is_negative;
2225 char buffer[65], *pos;
2227 if (value < 0 && radix == 10)
2229 is_negative = TRUE;
2230 val = -value;
2232 else
2234 is_negative = FALSE;
2235 val = value;
2238 pos = buffer + 64;
2239 *pos = '\0';
2243 int digit = val % radix;
2244 val /= radix;
2246 if (digit < 10)
2247 *--pos = '0' + digit;
2248 else
2249 *--pos = 'a' + digit - 10;
2251 while (val != 0);
2253 if (is_negative)
2254 *--pos = '-';
2256 memcpy(str, pos, buffer + 65 - pos);
2257 return str;
2260 /*********************************************************************
2261 * _i64tow (MSVCRT.@)
2263 wchar_t* CDECL _i64tow(__int64 value, wchar_t *str, int radix)
2265 unsigned __int64 val;
2266 BOOL is_negative;
2267 wchar_t buffer[65], *pos;
2269 if (value < 0 && radix == 10)
2271 is_negative = TRUE;
2272 val = -value;
2274 else
2276 is_negative = FALSE;
2277 val = value;
2280 pos = buffer + 64;
2281 *pos = '\0';
2285 int digit = val % radix;
2286 val /= radix;
2288 if (digit < 10)
2289 *--pos = '0' + digit;
2290 else
2291 *--pos = 'a' + digit - 10;
2293 while (val != 0);
2295 if (is_negative)
2296 *--pos = '-';
2298 memcpy(str, pos, (buffer + 65 - pos) * sizeof(wchar_t));
2299 return str;
2302 /*********************************************************************
2303 * _ui64toa_s (MSVCRT.@)
2305 int CDECL _ui64toa_s(unsigned __int64 value, char *str,
2306 size_t size, int radix)
2308 char buffer[65], *pos;
2309 int digit;
2311 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
2312 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
2313 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2315 str[0] = '\0';
2316 return EINVAL;
2319 pos = buffer+64;
2320 *pos = '\0';
2322 do {
2323 digit = value%radix;
2324 value /= radix;
2326 if(digit < 10)
2327 *--pos = '0'+digit;
2328 else
2329 *--pos = 'a'+digit-10;
2330 }while(value != 0);
2332 if(buffer-pos+65 > size) {
2333 MSVCRT_INVALID_PMT("str[size] is too small", EINVAL);
2334 return EINVAL;
2337 memcpy(str, pos, buffer-pos+65);
2338 return 0;
2341 /*********************************************************************
2342 * _ui64tow_s (MSVCRT.@)
2344 int CDECL _ui64tow_s( unsigned __int64 value, wchar_t *str,
2345 size_t size, int radix )
2347 wchar_t buffer[65], *pos;
2348 int digit;
2350 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
2351 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
2352 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2354 str[0] = '\0';
2355 return EINVAL;
2358 pos = &buffer[64];
2359 *pos = '\0';
2361 do {
2362 digit = value % radix;
2363 value = value / radix;
2364 if (digit < 10)
2365 *--pos = '0' + digit;
2366 else
2367 *--pos = 'a' + digit - 10;
2368 } while (value != 0);
2370 if(buffer-pos+65 > size) {
2371 MSVCRT_INVALID_PMT("str[size] is too small", EINVAL);
2372 return EINVAL;
2375 memcpy(str, pos, (buffer-pos+65)*sizeof(wchar_t));
2376 return 0;
2379 /*********************************************************************
2380 * _ultoa_s (MSVCRT.@)
2382 int CDECL _ultoa_s(__msvcrt_ulong value, char *str, size_t size, int radix)
2384 __msvcrt_ulong digit;
2385 char buffer[33], *pos;
2386 size_t len;
2388 if (!str || !size || radix < 2 || radix > 36)
2390 if (str && size)
2391 str[0] = '\0';
2393 *_errno() = EINVAL;
2394 return EINVAL;
2397 pos = buffer + 32;
2398 *pos = '\0';
2402 digit = value % radix;
2403 value /= radix;
2405 if (digit < 10)
2406 *--pos = '0' + digit;
2407 else
2408 *--pos = 'a' + digit - 10;
2410 while (value != 0);
2412 len = buffer + 33 - pos;
2413 if (len > size)
2415 size_t i;
2416 char *p = str;
2418 /* Copy the temporary buffer backwards up to the available number of
2419 * characters. */
2421 for (pos = buffer + 31, i = 0; i < size; i++)
2422 *p++ = *pos--;
2424 str[0] = '\0';
2425 *_errno() = ERANGE;
2426 return ERANGE;
2429 memcpy(str, pos, len);
2430 return 0;
2433 /*********************************************************************
2434 * _ultow_s (MSVCRT.@)
2436 int CDECL _ultow_s(__msvcrt_ulong value, wchar_t *str, size_t size, int radix)
2438 __msvcrt_ulong digit;
2439 WCHAR buffer[33], *pos;
2440 size_t len;
2442 if (!str || !size || radix < 2 || radix > 36)
2444 if (str && size)
2445 str[0] = '\0';
2447 *_errno() = EINVAL;
2448 return EINVAL;
2451 pos = buffer + 32;
2452 *pos = '\0';
2456 digit = value % radix;
2457 value /= radix;
2459 if (digit < 10)
2460 *--pos = '0' + digit;
2461 else
2462 *--pos = 'a' + digit - 10;
2464 while (value != 0);
2466 len = buffer + 33 - pos;
2467 if (len > size)
2469 size_t i;
2470 WCHAR *p = str;
2472 /* Copy the temporary buffer backwards up to the available number of
2473 * characters. */
2475 for (pos = buffer + 31, i = 0; i < size; i++)
2476 *p++ = *pos--;
2478 str[0] = '\0';
2479 *_errno() = ERANGE;
2480 return ERANGE;
2483 memcpy(str, pos, len * sizeof(wchar_t));
2484 return 0;
2487 /*********************************************************************
2488 * _i64toa_s (MSVCRT.@)
2490 int CDECL _i64toa_s(__int64 value, char *str, size_t size, int radix)
2492 unsigned __int64 val;
2493 unsigned int digit;
2494 BOOL is_negative;
2495 char buffer[65], *pos;
2496 size_t len;
2498 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
2499 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
2500 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2502 str[0] = '\0';
2503 return EINVAL;
2506 if (value < 0 && radix == 10)
2508 is_negative = TRUE;
2509 val = -value;
2511 else
2513 is_negative = FALSE;
2514 val = value;
2517 pos = buffer + 64;
2518 *pos = '\0';
2522 digit = val % radix;
2523 val /= radix;
2525 if (digit < 10)
2526 *--pos = '0' + digit;
2527 else
2528 *--pos = 'a' + digit - 10;
2530 while (val != 0);
2532 if (is_negative)
2533 *--pos = '-';
2535 len = buffer + 65 - pos;
2536 if (len > size)
2538 size_t i;
2539 char *p = str;
2541 /* Copy the temporary buffer backwards up to the available number of
2542 * characters. Don't copy the negative sign if present. */
2544 if (is_negative)
2546 p++;
2547 size--;
2550 for (pos = buffer + 63, i = 0; i < size; i++)
2551 *p++ = *pos--;
2553 str[0] = '\0';
2554 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE);
2555 return ERANGE;
2558 memcpy(str, pos, len);
2559 return 0;
2562 /*********************************************************************
2563 * _i64tow_s (MSVCRT.@)
2565 int CDECL _i64tow_s(__int64 value, wchar_t *str, size_t size, int radix)
2567 unsigned __int64 val;
2568 unsigned int digit;
2569 BOOL is_negative;
2570 wchar_t buffer[65], *pos;
2571 size_t len;
2573 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
2574 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
2575 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2577 str[0] = '\0';
2578 return EINVAL;
2581 if (value < 0 && radix == 10)
2583 is_negative = TRUE;
2584 val = -value;
2586 else
2588 is_negative = FALSE;
2589 val = value;
2592 pos = buffer + 64;
2593 *pos = '\0';
2597 digit = val % radix;
2598 val /= radix;
2600 if (digit < 10)
2601 *--pos = '0' + digit;
2602 else
2603 *--pos = 'a' + digit - 10;
2605 while (val != 0);
2607 if (is_negative)
2608 *--pos = '-';
2610 len = buffer + 65 - pos;
2611 if (len > size)
2613 size_t i;
2614 wchar_t *p = str;
2616 /* Copy the temporary buffer backwards up to the available number of
2617 * characters. Don't copy the negative sign if present. */
2619 if (is_negative)
2621 p++;
2622 size--;
2625 for (pos = buffer + 63, i = 0; i < size; i++)
2626 *p++ = *pos--;
2628 str[0] = '\0';
2629 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE);
2630 return ERANGE;
2633 memcpy(str, pos, len * sizeof(wchar_t));
2634 return 0;
2637 #define I10_OUTPUT_MAX_PREC 21
2638 /* Internal structure used by $I10_OUTPUT */
2639 struct _I10_OUTPUT_DATA {
2640 short pos;
2641 char sign;
2642 BYTE len;
2643 char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */
2646 /*********************************************************************
2647 * $I10_OUTPUT (MSVCRT.@)
2648 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
2649 * prec - precision of part, we're interested in
2650 * flag - 0 for first prec digits, 1 for fractional part
2651 * data - data to be populated
2653 * return value
2654 * 0 if given double is NaN or INF
2655 * 1 otherwise
2657 * FIXME
2658 * Native sets last byte of data->str to '0' or '9', I don't know what
2659 * it means. Current implementation sets it always to '0'.
2661 int CDECL I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data)
2663 struct fpnum num;
2664 double d;
2665 char format[8];
2666 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
2667 char *p;
2669 if ((ld80.x80[2] & 0x7fff) == 0x7fff)
2671 if (ld80.x80[0] == 0 && ld80.x80[1] == 0x80000000)
2672 strcpy( data->str, "1#INF" );
2673 else
2674 strcpy( data->str, (ld80.x80[1] & 0x40000000) ? "1#QNAN" : "1#SNAN" );
2675 data->pos = 1;
2676 data->sign = (ld80.x80[2] & 0x8000) ? '-' : ' ';
2677 data->len = strlen(data->str);
2678 return 0;
2681 num.sign = (ld80.x80[2] & 0x8000) ? -1 : 1;
2682 num.exp = (ld80.x80[2] & 0x7fff) - 0x3fff - 63;
2683 num.m = ld80.x80[0] | ((ULONGLONG)ld80.x80[1] << 32);
2684 num.mod = FP_ROUND_EVEN;
2685 fpnum_double( &num, &d );
2686 TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
2688 if(d<0) {
2689 data->sign = '-';
2690 d = -d;
2691 } else
2692 data->sign = ' ';
2694 if(flag&1) {
2695 int exp = 1 + floor(log10(d));
2697 prec += exp;
2698 if(exp < 0)
2699 prec--;
2701 prec--;
2703 if(prec+1 > I10_OUTPUT_MAX_PREC)
2704 prec = I10_OUTPUT_MAX_PREC-1;
2705 else if(prec < 0) {
2706 d = 0.0;
2707 prec = 0;
2710 sprintf(format, "%%.%dle", prec);
2711 sprintf(buf, format, d);
2713 buf[1] = buf[0];
2714 data->pos = atoi(buf+prec+3);
2715 if(buf[1] != '0')
2716 data->pos++;
2718 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
2719 data->len = p-buf;
2721 memcpy(data->str, buf+1, data->len);
2722 data->str[data->len] = '\0';
2724 if(buf[1]!='0' && prec-data->len+1>0)
2725 memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1);
2727 return 1;
2729 #undef I10_OUTPUT_MAX_PREC
2731 static inline int memcmp_bytes(const void *ptr1, const void *ptr2, size_t n)
2733 const unsigned char *p1, *p2;
2735 for (p1 = ptr1, p2 = ptr2; n; n--, p1++, p2++)
2737 if (*p1 != *p2)
2738 return *p1 > *p2 ? 1 : -1;
2740 return 0;
2743 static inline int memcmp_blocks(const void *ptr1, const void *ptr2, size_t size)
2745 typedef uint64_t DECLSPEC_ALIGN(1) unaligned_ui64;
2747 const uint64_t *p1 = ptr1;
2748 const unaligned_ui64 *p2 = ptr2;
2749 size_t remainder = size & (sizeof(uint64_t) - 1);
2750 size_t block_count = size / sizeof(uint64_t);
2752 while (block_count)
2754 if (*p1 != *p2)
2755 return memcmp_bytes(p1, p2, sizeof(uint64_t));
2757 p1++;
2758 p2++;
2759 block_count--;
2762 return memcmp_bytes(p1, p2, remainder);
2765 /*********************************************************************
2766 * memcmp (MSVCRT.@)
2768 int __cdecl memcmp(const void *ptr1, const void *ptr2, size_t n)
2770 const unsigned char *p1 = ptr1, *p2 = ptr2;
2771 size_t align;
2772 int result;
2774 if (n < sizeof(uint64_t))
2775 return memcmp_bytes(p1, p2, n);
2777 align = -(size_t)p1 & (sizeof(uint64_t) - 1);
2779 if ((result = memcmp_bytes(p1, p2, align)))
2780 return result;
2782 p1 += align;
2783 p2 += align;
2784 n -= align;
2786 return memcmp_blocks(p1, p2, n);
2789 #if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__))
2791 #ifdef __i386__
2793 #define DEST_REG "%edi"
2794 #define SRC_REG "%esi"
2795 #define LEN_REG "%ecx"
2796 #define TMP_REG "%edx"
2798 #define MEMMOVE_INIT \
2799 "pushl " SRC_REG "\n\t" \
2800 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
2801 "pushl " DEST_REG "\n\t" \
2802 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
2803 "movl 12(%esp), " DEST_REG "\n\t" \
2804 "movl 16(%esp), " SRC_REG "\n\t" \
2805 "movl 20(%esp), " LEN_REG "\n\t"
2807 #define MEMMOVE_CLEANUP \
2808 "movl 12(%esp), %eax\n\t" \
2809 "popl " DEST_REG "\n\t" \
2810 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") \
2811 "popl " SRC_REG "\n\t" \
2812 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
2814 #else
2816 #define DEST_REG "%rdi"
2817 #define SRC_REG "%rsi"
2818 #define LEN_REG "%r8"
2819 #define TMP_REG "%r9"
2821 #define MEMMOVE_INIT \
2822 "pushq " SRC_REG "\n\t" \
2823 __ASM_SEH(".seh_pushreg " SRC_REG "\n\t") \
2824 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") \
2825 "pushq " DEST_REG "\n\t" \
2826 __ASM_SEH(".seh_pushreg " DEST_REG "\n\t") \
2827 __ASM_SEH(".seh_endprologue\n\t") \
2828 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") \
2829 "movq %rcx, " DEST_REG "\n\t" \
2830 "movq %rdx, " SRC_REG "\n\t"
2832 #define MEMMOVE_CLEANUP \
2833 "movq %rcx, %rax\n\t" \
2834 "popq " DEST_REG "\n\t" \
2835 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") \
2836 "popq " SRC_REG "\n\t" \
2837 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
2838 #endif
2840 void * __cdecl sse2_memmove(void *dst, const void *src, size_t n);
2841 __ASM_GLOBAL_FUNC( sse2_memmove,
2842 MEMMOVE_INIT
2843 "mov " DEST_REG ", " TMP_REG "\n\t" /* check copying direction */
2844 "sub " SRC_REG ", " TMP_REG "\n\t"
2845 "cmp " LEN_REG ", " TMP_REG "\n\t"
2846 "jb copy_bwd\n\t"
2847 /* copy forwards */
2848 "cmp $4, " LEN_REG "\n\t" /* 4-bytes align */
2849 "jb copy_fwd3\n\t"
2850 "mov " DEST_REG ", " TMP_REG "\n\t"
2851 "shr $1, " TMP_REG "\n\t"
2852 "jnc 1f\n\t"
2853 "movsb\n\t"
2854 "dec " LEN_REG "\n\t"
2855 "inc " TMP_REG "\n\t"
2856 "1:\n\t"
2857 "shr $1, " TMP_REG "\n\t"
2858 "jnc 1f\n\t"
2859 "movsw\n\t"
2860 "sub $2, " LEN_REG "\n\t"
2861 "inc " TMP_REG "\n\t"
2862 "1:\n\t" /* 16-bytes align */
2863 "cmp $16, " LEN_REG "\n\t"
2864 "jb copy_fwd15\n\t"
2865 "shr $1, " TMP_REG "\n\t"
2866 "jnc 1f\n\t"
2867 "movsl\n\t"
2868 "sub $4, " LEN_REG "\n\t"
2869 "inc " TMP_REG "\n\t"
2870 "1:\n\t"
2871 "shr $1, " TMP_REG "\n\t"
2872 "jnc 1f\n\t"
2873 "movsl\n\t"
2874 "movsl\n\t"
2875 "sub $8, " LEN_REG "\n\t"
2876 "1:\n\t"
2877 "cmp $64, " LEN_REG "\n\t"
2878 "jb copy_fwd63\n\t"
2879 "1:\n\t" /* copy 64-bytes blocks in loop, dest 16-bytes aligned */
2880 "movdqu 0x00(" SRC_REG "), %xmm0\n\t"
2881 "movdqu 0x10(" SRC_REG "), %xmm1\n\t"
2882 "movdqu 0x20(" SRC_REG "), %xmm2\n\t"
2883 "movdqu 0x30(" SRC_REG "), %xmm3\n\t"
2884 "movdqa %xmm0, 0x00(" DEST_REG ")\n\t"
2885 "movdqa %xmm1, 0x10(" DEST_REG ")\n\t"
2886 "movdqa %xmm2, 0x20(" DEST_REG ")\n\t"
2887 "movdqa %xmm3, 0x30(" DEST_REG ")\n\t"
2888 "add $64, " SRC_REG "\n\t"
2889 "add $64, " DEST_REG "\n\t"
2890 "sub $64, " LEN_REG "\n\t"
2891 "cmp $64, " LEN_REG "\n\t"
2892 "jae 1b\n\t"
2893 "copy_fwd63:\n\t" /* copy last 63 bytes, dest 16-bytes aligned */
2894 "mov " LEN_REG ", " TMP_REG "\n\t"
2895 "and $15, " LEN_REG "\n\t"
2896 "shr $5, " TMP_REG "\n\t"
2897 "jnc 1f\n\t"
2898 "movdqu 0(" SRC_REG "), %xmm0\n\t"
2899 "movdqa %xmm0, 0(" DEST_REG ")\n\t"
2900 "add $16, " SRC_REG "\n\t"
2901 "add $16, " DEST_REG "\n\t"
2902 "1:\n\t"
2903 "shr $1, " TMP_REG "\n\t"
2904 "jnc copy_fwd15\n\t"
2905 "movdqu 0x00(" SRC_REG "), %xmm0\n\t"
2906 "movdqu 0x10(" SRC_REG "), %xmm1\n\t"
2907 "movdqa %xmm0, 0x00(" DEST_REG ")\n\t"
2908 "movdqa %xmm1, 0x10(" DEST_REG ")\n\t"
2909 "add $32, " SRC_REG "\n\t"
2910 "add $32, " DEST_REG "\n\t"
2911 "copy_fwd15:\n\t" /* copy last 15 bytes, dest 4-bytes aligned */
2912 "mov " LEN_REG ", " TMP_REG "\n\t"
2913 "and $3, " LEN_REG "\n\t"
2914 "shr $3, " TMP_REG "\n\t"
2915 "jnc 1f\n\t"
2916 "movsl\n\t"
2917 "1:\n\t"
2918 "shr $1, " TMP_REG "\n\t"
2919 "jnc copy_fwd3\n\t"
2920 "movsl\n\t"
2921 "movsl\n\t"
2922 "copy_fwd3:\n\t" /* copy last 3 bytes */
2923 "shr $1, " LEN_REG "\n\t"
2924 "jnc 1f\n\t"
2925 "movsb\n\t"
2926 "1:\n\t"
2927 "shr $1, " LEN_REG "\n\t"
2928 "jnc 1f\n\t"
2929 "movsw\n\t"
2930 "1:\n\t"
2931 MEMMOVE_CLEANUP
2932 "ret\n\t"
2933 "copy_bwd:\n\t"
2934 "lea (" DEST_REG ", " LEN_REG "), " DEST_REG "\n\t"
2935 "lea (" SRC_REG ", " LEN_REG "), " SRC_REG "\n\t"
2936 "cmp $4, " LEN_REG "\n\t" /* 4-bytes align */
2937 "jb copy_bwd3\n\t"
2938 "mov " DEST_REG ", " TMP_REG "\n\t"
2939 "shr $1, " TMP_REG "\n\t"
2940 "jnc 1f\n\t"
2941 "dec " SRC_REG "\n\t"
2942 "dec " DEST_REG "\n\t"
2943 "movb (" SRC_REG "), %al\n\t"
2944 "movb %al, (" DEST_REG ")\n\t"
2945 "dec " LEN_REG "\n\t"
2946 "1:\n\t"
2947 "shr $1, " TMP_REG "\n\t"
2948 "jnc 1f\n\t"
2949 "sub $2, " SRC_REG "\n\t"
2950 "sub $2, " DEST_REG "\n\t"
2951 "movw (" SRC_REG "), %ax\n\t"
2952 "movw %ax, (" DEST_REG ")\n\t"
2953 "sub $2, " LEN_REG "\n\t"
2954 "1:\n\t" /* 16-bytes align */
2955 "cmp $16, " LEN_REG "\n\t"
2956 "jb copy_bwd15\n\t"
2957 "shr $1, " TMP_REG "\n\t"
2958 "jnc 1f\n\t"
2959 "sub $4, " SRC_REG "\n\t"
2960 "sub $4, " DEST_REG "\n\t"
2961 "movl (" SRC_REG "), %eax\n\t"
2962 "movl %eax, (" DEST_REG ")\n\t"
2963 "sub $4, " LEN_REG "\n\t"
2964 "1:\n\t"
2965 "shr $1, " TMP_REG "\n\t"
2966 "jnc 1f\n\t"
2967 "sub $8, " SRC_REG "\n\t"
2968 "sub $8, " DEST_REG "\n\t"
2969 "movl 4(" SRC_REG "), %eax\n\t"
2970 "movl %eax, 4(" DEST_REG ")\n\t"
2971 "movl (" SRC_REG "), %eax\n\t"
2972 "movl %eax, (" DEST_REG ")\n\t"
2973 "sub $8, " LEN_REG "\n\t"
2974 "1:\n\t"
2975 "cmp $64, " LEN_REG "\n\t"
2976 "jb copy_bwd63\n\t"
2977 "1:\n\t" /* copy 64-bytes blocks in loop, dest 16-bytes aligned */
2978 "sub $64, " SRC_REG "\n\t"
2979 "sub $64, " DEST_REG "\n\t"
2980 "movdqu 0x00(" SRC_REG "), %xmm0\n\t"
2981 "movdqu 0x10(" SRC_REG "), %xmm1\n\t"
2982 "movdqu 0x20(" SRC_REG "), %xmm2\n\t"
2983 "movdqu 0x30(" SRC_REG "), %xmm3\n\t"
2984 "movdqa %xmm0, 0x00(" DEST_REG ")\n\t"
2985 "movdqa %xmm1, 0x10(" DEST_REG ")\n\t"
2986 "movdqa %xmm2, 0x20(" DEST_REG ")\n\t"
2987 "movdqa %xmm3, 0x30(" DEST_REG ")\n\t"
2988 "sub $64, " LEN_REG "\n\t"
2989 "cmp $64, " LEN_REG "\n\t"
2990 "jae 1b\n\t"
2991 "copy_bwd63:\n\t" /* copy last 63 bytes, dest 16-bytes aligned */
2992 "mov " LEN_REG ", " TMP_REG "\n\t"
2993 "and $15, " LEN_REG "\n\t"
2994 "shr $5, " TMP_REG "\n\t"
2995 "jnc 1f\n\t"
2996 "sub $16, " SRC_REG "\n\t"
2997 "sub $16, " DEST_REG "\n\t"
2998 "movdqu (" SRC_REG "), %xmm0\n\t"
2999 "movdqa %xmm0, (" DEST_REG ")\n\t"
3000 "1:\n\t"
3001 "shr $1, " TMP_REG "\n\t"
3002 "jnc copy_bwd15\n\t"
3003 "sub $32, " SRC_REG "\n\t"
3004 "sub $32, " DEST_REG "\n\t"
3005 "movdqu 0x00(" SRC_REG "), %xmm0\n\t"
3006 "movdqu 0x10(" SRC_REG "), %xmm1\n\t"
3007 "movdqa %xmm0, 0x00(" DEST_REG ")\n\t"
3008 "movdqa %xmm1, 0x10(" DEST_REG ")\n\t"
3009 "copy_bwd15:\n\t" /* copy last 15 bytes, dest 4-bytes aligned */
3010 "mov " LEN_REG ", " TMP_REG "\n\t"
3011 "and $3, " LEN_REG "\n\t"
3012 "shr $3, " TMP_REG "\n\t"
3013 "jnc 1f\n\t"
3014 "sub $4, " SRC_REG "\n\t"
3015 "sub $4, " DEST_REG "\n\t"
3016 "movl (" SRC_REG "), %eax\n\t"
3017 "movl %eax, (" DEST_REG ")\n\t"
3018 "1:\n\t"
3019 "shr $1, " TMP_REG "\n\t"
3020 "jnc copy_bwd3\n\t"
3021 "sub $8, " SRC_REG "\n\t"
3022 "sub $8, " DEST_REG "\n\t"
3023 "movl 4(" SRC_REG "), %eax\n\t"
3024 "movl %eax, 4(" DEST_REG ")\n\t"
3025 "movl (" SRC_REG "), %eax\n\t"
3026 "movl %eax, (" DEST_REG ")\n\t"
3027 "copy_bwd3:\n\t" /* copy last 3 bytes */
3028 "shr $1, " LEN_REG "\n\t"
3029 "jnc 1f\n\t"
3030 "dec " SRC_REG "\n\t"
3031 "dec " DEST_REG "\n\t"
3032 "movb (" SRC_REG "), %al\n\t"
3033 "movb %al, (" DEST_REG ")\n\t"
3034 "1:\n\t"
3035 "shr $1, " LEN_REG "\n\t"
3036 "jnc 1f\n\t"
3037 "movw -2(" SRC_REG "), %ax\n\t"
3038 "movw %ax, -2(" DEST_REG ")\n\t"
3039 "1:\n\t"
3040 MEMMOVE_CLEANUP
3041 "ret" )
3043 #endif
3045 /*********************************************************************
3046 * memmove (MSVCRT.@)
3048 #ifdef WORDS_BIGENDIAN
3049 # define MERGE(w1, sh1, w2, sh2) ((w1 << sh1) | (w2 >> sh2))
3050 #else
3051 # define MERGE(w1, sh1, w2, sh2) ((w1 >> sh1) | (w2 << sh2))
3052 #endif
3053 void * __cdecl memmove(void *dst, const void *src, size_t n)
3055 #if defined(__x86_64__) && !defined(__arm64ec__)
3056 return sse2_memmove(dst, src, n);
3057 #else
3058 unsigned char *d = dst;
3059 const unsigned char *s = src;
3060 int sh1;
3062 #ifdef __i386__
3063 if (sse2_supported)
3064 return sse2_memmove(dst, src, n);
3065 #endif
3067 if (!n) return dst;
3069 if ((size_t)dst - (size_t)src >= n)
3071 for (; (size_t)d % sizeof(size_t) && n; n--) *d++ = *s++;
3073 sh1 = 8 * ((size_t)s % sizeof(size_t));
3074 if (!sh1)
3076 while (n >= sizeof(size_t))
3078 *(size_t*)d = *(size_t*)s;
3079 s += sizeof(size_t);
3080 d += sizeof(size_t);
3081 n -= sizeof(size_t);
3084 else if (n >= 2 * sizeof(size_t))
3086 int sh2 = 8 * sizeof(size_t) - sh1;
3087 size_t x, y;
3089 s -= sh1 / 8;
3090 x = *(size_t*)s;
3093 s += sizeof(size_t);
3094 y = *(size_t*)s;
3095 *(size_t*)d = MERGE(x, sh1, y, sh2);
3096 d += sizeof(size_t);
3098 s += sizeof(size_t);
3099 x = *(size_t*)s;
3100 *(size_t*)d = MERGE(y, sh1, x, sh2);
3101 d += sizeof(size_t);
3103 n -= 2 * sizeof(size_t);
3104 } while (n >= 2 * sizeof(size_t));
3105 s += sh1 / 8;
3107 while (n--) *d++ = *s++;
3108 return dst;
3110 else
3112 d += n;
3113 s += n;
3115 for (; (size_t)d % sizeof(size_t) && n; n--) *--d = *--s;
3117 sh1 = 8 * ((size_t)s % sizeof(size_t));
3118 if (!sh1)
3120 while (n >= sizeof(size_t))
3122 s -= sizeof(size_t);
3123 d -= sizeof(size_t);
3124 *(size_t*)d = *(size_t*)s;
3125 n -= sizeof(size_t);
3128 else if (n >= 2 * sizeof(size_t))
3130 int sh2 = 8 * sizeof(size_t) - sh1;
3131 size_t x, y;
3133 s -= sh1 / 8;
3134 x = *(size_t*)s;
3137 s -= sizeof(size_t);
3138 y = *(size_t*)s;
3139 d -= sizeof(size_t);
3140 *(size_t*)d = MERGE(y, sh1, x, sh2);
3142 s -= sizeof(size_t);
3143 x = *(size_t*)s;
3144 d -= sizeof(size_t);
3145 *(size_t*)d = MERGE(x, sh1, y, sh2);
3147 n -= 2 * sizeof(size_t);
3148 } while (n >= 2 * sizeof(size_t));
3149 s += sh1 / 8;
3151 while (n--) *--d = *--s;
3153 return dst;
3154 #endif
3156 #undef MERGE
3158 /*********************************************************************
3159 * memcpy (MSVCRT.@)
3161 void * __cdecl memcpy(void *dst, const void *src, size_t n)
3163 return memmove(dst, src, n);
3166 /*********************************************************************
3167 * _memccpy (MSVCRT.@)
3169 void * __cdecl _memccpy(void *dst, const void *src, int c, size_t n)
3171 unsigned char *d = dst;
3172 const unsigned char *s = src;
3173 while (n--) if ((*d++ = *s++) == (unsigned char)c) return d;
3174 return NULL;
3178 static inline void memset_aligned_32(unsigned char *d, uint64_t v, size_t n)
3180 unsigned char *end = d + n;
3181 while (d < end)
3183 *(uint64_t *)(d + 0) = v;
3184 *(uint64_t *)(d + 8) = v;
3185 *(uint64_t *)(d + 16) = v;
3186 *(uint64_t *)(d + 24) = v;
3187 d += 32;
3191 /*********************************************************************
3192 * memset (MSVCRT.@)
3194 void *__cdecl memset(void *dst, int c, size_t n)
3196 typedef uint64_t DECLSPEC_ALIGN(1) unaligned_ui64;
3197 typedef uint32_t DECLSPEC_ALIGN(1) unaligned_ui32;
3198 typedef uint16_t DECLSPEC_ALIGN(1) unaligned_ui16;
3200 uint64_t v = 0x101010101010101ull * (unsigned char)c;
3201 unsigned char *d = (unsigned char *)dst;
3202 size_t a = 0x20 - ((uintptr_t)d & 0x1f);
3204 if (n >= 16)
3206 *(unaligned_ui64 *)(d + 0) = v;
3207 *(unaligned_ui64 *)(d + 8) = v;
3208 *(unaligned_ui64 *)(d + n - 16) = v;
3209 *(unaligned_ui64 *)(d + n - 8) = v;
3210 if (n <= 32) return dst;
3211 *(unaligned_ui64 *)(d + 16) = v;
3212 *(unaligned_ui64 *)(d + 24) = v;
3213 *(unaligned_ui64 *)(d + n - 32) = v;
3214 *(unaligned_ui64 *)(d + n - 24) = v;
3215 if (n <= 64) return dst;
3217 n = (n - a) & ~0x1f;
3218 memset_aligned_32(d + a, v, n);
3219 return dst;
3221 if (n >= 8)
3223 *(unaligned_ui64 *)d = v;
3224 *(unaligned_ui64 *)(d + n - 8) = v;
3225 return dst;
3227 if (n >= 4)
3229 *(unaligned_ui32 *)d = v;
3230 *(unaligned_ui32 *)(d + n - 4) = v;
3231 return dst;
3233 if (n >= 2)
3235 *(unaligned_ui16 *)d = v;
3236 *(unaligned_ui16 *)(d + n - 2) = v;
3237 return dst;
3239 if (n >= 1)
3241 *(uint8_t *)d = v;
3242 return dst;
3244 return dst;
3247 /*********************************************************************
3248 * strchr (MSVCRT.@)
3250 char* __cdecl strchr(const char *str, int c)
3254 if (*str == (char)c) return (char*)str;
3255 } while (*str++);
3256 return NULL;
3259 /*********************************************************************
3260 * strrchr (MSVCRT.@)
3262 char* __cdecl strrchr(const char *str, int c)
3264 char *ret = NULL;
3265 do { if (*str == (char)c) ret = (char*)str; } while (*str++);
3266 return ret;
3269 /*********************************************************************
3270 * memchr (MSVCRT.@)
3272 void* __cdecl memchr(const void *ptr, int c, size_t n)
3274 const unsigned char *p = ptr;
3276 for (p = ptr; n; n--, p++) if (*p == (unsigned char)c) return (void *)(ULONG_PTR)p;
3277 return NULL;
3280 /*********************************************************************
3281 * strcmp (MSVCRT.@)
3283 int __cdecl strcmp(const char *str1, const char *str2)
3285 while (*str1 && *str1 == *str2) { str1++; str2++; }
3286 if ((unsigned char)*str1 > (unsigned char)*str2) return 1;
3287 if ((unsigned char)*str1 < (unsigned char)*str2) return -1;
3288 return 0;
3291 /*********************************************************************
3292 * strncmp (MSVCRT.@)
3294 int __cdecl strncmp(const char *str1, const char *str2, size_t len)
3296 if (!len) return 0;
3297 while (--len && *str1 && *str1 == *str2) { str1++; str2++; }
3299 #if defined(_WIN64) || defined(_UCRT) || _MSVCR_VER == 70 || _MSVCR_VER == 71 || _MSVCR_VER >= 110
3300 if ((unsigned char)*str1 > (unsigned char)*str2) return 1;
3301 if ((unsigned char)*str1 < (unsigned char)*str2) return -1;
3302 return 0;
3303 #else
3304 return (unsigned char)*str1 - (unsigned char)*str2;
3305 #endif
3308 /*********************************************************************
3309 * _strnicmp_l (MSVCRT.@)
3311 int __cdecl _strnicmp_l(const char *s1, const char *s2,
3312 size_t count, _locale_t locale)
3314 pthreadlocinfo locinfo;
3315 int c1, c2;
3317 if(!count)
3318 return 0;
3319 #if _MSVCR_VER>=80
3320 if(!MSVCRT_CHECK_PMT(s1 && s2 && count <= INT_MAX))
3321 #else
3322 /* Old versions of msvcrt.dll didn't have count <= INT_MAX check */
3323 if(!MSVCRT_CHECK_PMT(s1 && s2))
3324 #endif /* _MSVCR_VER>=140 */
3325 return _NLSCMPERROR;
3327 if(!locale)
3328 locinfo = get_locinfo();
3329 else
3330 locinfo = locale->locinfo;
3332 if(!locinfo->lc_handle[LC_CTYPE])
3334 do {
3335 if ((c1 = *s1++) >= 'A' && c1 <= 'Z')
3336 c1 -= 'A' - 'a';
3337 if ((c2 = *s2++) >= 'A' && c2 <= 'Z')
3338 c2 -= 'A' - 'a';
3339 }while(--count && c1 && c1==c2);
3341 return c1-c2;
3344 do {
3345 c1 = _tolower_l((unsigned char)*s1++, locale);
3346 c2 = _tolower_l((unsigned char)*s2++, locale);
3347 }while(--count && c1 && c1==c2);
3349 return c1-c2;
3352 /*********************************************************************
3353 * _stricmp_l (MSVCRT.@)
3355 int __cdecl _stricmp_l(const char *s1, const char *s2, _locale_t locale)
3357 return _strnicmp_l(s1, s2, INT_MAX, locale);
3360 /*********************************************************************
3361 * _strnicmp (MSVCRT.@)
3363 int __cdecl _strnicmp(const char *s1, const char *s2, size_t count)
3365 return _strnicmp_l(s1, s2, count, NULL);
3368 /*********************************************************************
3369 * _stricmp (MSVCRT.@)
3371 int __cdecl _stricmp(const char *s1, const char *s2)
3373 return _strnicmp_l(s1, s2, INT_MAX, NULL);
3376 /*********************************************************************
3377 * strstr (MSVCRT.@)
3379 char* __cdecl strstr(const char *haystack, const char *needle)
3381 size_t i, j, len, needle_len, lps_len;
3382 BYTE lps[256];
3384 needle_len = strlen(needle);
3385 if (!needle_len) return (char*)haystack;
3386 lps_len = needle_len > ARRAY_SIZE(lps) ? ARRAY_SIZE(lps) : needle_len;
3388 lps[0] = 0;
3389 len = 0;
3390 i = 1;
3391 while (i < lps_len)
3393 if (needle[i] == needle[len]) lps[i++] = ++len;
3394 else if (len) len = lps[len-1];
3395 else lps[i++] = 0;
3398 i = j = 0;
3399 while (haystack[i])
3401 while (j < lps_len && haystack[i] && haystack[i] == needle[j])
3403 i++;
3404 j++;
3407 if (j == needle_len) return (char*)haystack + i - j;
3408 else if (j)
3410 if (j == ARRAY_SIZE(lps) && !strncmp(haystack + i, needle + j, needle_len - j))
3411 return (char*)haystack + i - j;
3412 j = lps[j-1];
3414 else if (haystack[i]) i++;
3416 return NULL;
3419 /*********************************************************************
3420 * _memicmp_l (MSVCRT.@)
3422 int __cdecl _memicmp_l(const void *v1, const void *v2, size_t len, _locale_t locale)
3424 const char *s1 = v1, *s2 = v2;
3425 int ret = 0;
3427 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
3428 if (!s1 || !s2)
3430 if (len)
3431 MSVCRT_INVALID_PMT(NULL, EINVAL);
3432 return len ? _NLSCMPERROR : 0;
3434 #endif
3436 while (len--)
3438 if ((ret = _tolower_l(*s1, locale) - _tolower_l(*s2, locale)))
3439 break;
3440 s1++;
3441 s2++;
3443 return ret;
3446 /*********************************************************************
3447 * _memicmp (MSVCRT.@)
3449 int __cdecl _memicmp(const void *s1, const void *s2, size_t len)
3451 return _memicmp_l(s1, s2, len, NULL);
3454 /*********************************************************************
3455 * strcspn (MSVCRT.@)
3457 size_t __cdecl strcspn(const char *str, const char *reject)
3459 BOOL rejects[256];
3460 const char *p;
3462 memset(rejects, 0, sizeof(rejects));
3464 p = reject;
3465 while(*p)
3467 rejects[(unsigned char)*p] = TRUE;
3468 p++;
3471 p = str;
3472 while(*p && !rejects[(unsigned char)*p]) p++;
3473 return p - str;
3476 /*********************************************************************
3477 * strspn (MSVCRT.@)
3479 size_t __cdecl strspn(const char *str, const char *accept)
3481 const char *ptr;
3482 for (ptr = str; *ptr; ptr++) if (!strchr( accept, *ptr )) break;
3483 return ptr - str;
3486 /*********************************************************************
3487 * strpbrk (MSVCRT.@)
3489 char* __cdecl strpbrk(const char *str, const char *accept)
3491 for (; *str; str++) if (strchr( accept, *str )) return (char*)str;
3492 return NULL;
3495 /*********************************************************************
3496 * __strncnt (MSVCRT.@)
3498 size_t __cdecl __strncnt(const char *str, size_t size)
3500 size_t ret = 0;
3502 #if _MSVCR_VER >= 140
3503 while (*str++ && size--)
3504 #else
3505 while (size-- && *str++)
3506 #endif
3508 ret++;
3511 return ret;
3515 #ifdef _CRTDLL
3516 /*********************************************************************
3517 * _strdec (CRTDLL.@)
3519 char * CDECL _strdec(const char *str1, const char *str2)
3521 return (char *)(str2 - 1);
3524 /*********************************************************************
3525 * _strinc (CRTDLL.@)
3527 char * CDECL _strinc(const char *str)
3529 return (char *)(str + 1);
3532 /*********************************************************************
3533 * _strnextc (CRTDLL.@)
3535 unsigned int CDECL _strnextc(const char *str)
3537 return (unsigned char)str[0];
3540 /*********************************************************************
3541 * _strninc (CRTDLL.@)
3543 char * CDECL _strninc(const char *str, size_t len)
3545 return (char *)(str + len);
3548 /*********************************************************************
3549 * _strspnp (CRTDLL.@)
3551 char * CDECL _strspnp( const char *str1, const char *str2)
3553 str1 += strspn( str1, str2 );
3554 return *str1 ? (char*)str1 : NULL;
3556 #endif