dwrite: Always initialize output glyph count in GetGlyphs().
[wine.git] / dlls / msvcrt / string.c
blobd335fce49922653d2d6bdcc43959a1ab2b7a83f5
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) return NULL;
291 ret = str++;
292 while (*str && !strchr( delim, *str )) str++;
293 if (*str) *str++ = 0;
294 data->strtok_next = str;
295 return ret;
298 /*********************************************************************
299 * strtok_s (MSVCRT.@)
301 char * CDECL strtok_s(char *str, const char *delim, char **ctx)
303 if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL;
304 if (!MSVCRT_CHECK_PMT(ctx != NULL)) return NULL;
305 if (!MSVCRT_CHECK_PMT(str != NULL || *ctx != NULL)) return NULL;
307 if(!str)
308 str = *ctx;
310 while(*str && strchr(delim, *str))
311 str++;
312 if(!*str)
314 *ctx = str;
315 return NULL;
318 *ctx = str+1;
319 while(**ctx && !strchr(delim, **ctx))
320 (*ctx)++;
321 if(**ctx)
322 *(*ctx)++ = 0;
324 return str;
327 /*********************************************************************
328 * _swab (MSVCRT.@)
330 void CDECL _swab(char* src, char* dst, int len)
332 if (len > 1)
334 len = (unsigned)len >> 1;
336 while (len--) {
337 char s0 = src[0];
338 char s1 = src[1];
339 *dst++ = s1;
340 *dst++ = s0;
341 src = src + 2;
346 static struct fpnum fpnum(int sign, int exp, ULONGLONG m, enum fpmod mod)
348 struct fpnum ret;
350 ret.sign = sign;
351 ret.exp = exp;
352 ret.m = m;
353 ret.mod = mod;
354 return ret;
357 int fpnum_double(struct fpnum *fp, double *d)
359 ULONGLONG bits = 0;
361 if (fp->mod == FP_VAL_INFINITY)
363 *d = fp->sign * INFINITY;
364 return 0;
367 if (fp->mod == FP_VAL_NAN)
369 bits = ~0;
370 if (fp->sign == 1)
371 bits &= ~((ULONGLONG)1 << (MANT_BITS + EXP_BITS - 1));
372 *d = *(double*)&bits;
373 return 0;
376 TRACE("%c %s *2^%d (round %d)\n", fp->sign == -1 ? '-' : '+',
377 wine_dbgstr_longlong(fp->m), fp->exp, fp->mod);
378 if (!fp->m)
380 *d = fp->sign * 0.0;
381 return 0;
384 /* make sure that we don't overflow modifying exponent */
385 if (fp->exp > 1<<EXP_BITS)
387 *d = fp->sign * INFINITY;
388 return ERANGE;
390 if (fp->exp < -(1<<EXP_BITS))
392 *d = fp->sign * 0.0;
393 return ERANGE;
395 fp->exp += MANT_BITS - 1;
397 /* normalize mantissa */
398 while(fp->m < (ULONGLONG)1 << (MANT_BITS-1))
400 fp->m <<= 1;
401 fp->exp--;
403 while(fp->m >= (ULONGLONG)1 << MANT_BITS)
405 if (fp->m & 1 || fp->mod != FP_ROUND_ZERO)
407 if (!(fp->m & 1)) fp->mod = FP_ROUND_DOWN;
408 else if(fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
409 else fp->mod = FP_ROUND_UP;
411 fp->m >>= 1;
412 fp->exp++;
414 fp->exp += (1 << (EXP_BITS-1)) - 1;
416 /* handle subnormals */
417 if (fp->exp <= 0)
419 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
420 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
421 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
422 fp->m >>= 1;
424 while(fp->m && fp->exp<0)
426 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
427 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
428 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
429 fp->m >>= 1;
430 fp->exp++;
433 /* round mantissa */
434 if (fp->mod == FP_ROUND_UP || (fp->mod == FP_ROUND_EVEN && fp->m & 1))
436 fp->m++;
438 /* handle subnormal that falls into regular range due to rounding */
439 if (fp->m == (ULONGLONG)1 << (MANT_BITS - 1))
441 fp->exp++;
443 else if (fp->m >= (ULONGLONG)1 << MANT_BITS)
445 fp->exp++;
446 fp->m >>= 1;
450 if (fp->exp >= (1<<EXP_BITS)-1)
452 *d = fp->sign * INFINITY;
453 return ERANGE;
455 if (!fp->m || fp->exp < 0)
457 *d = fp->sign * 0.0;
458 return ERANGE;
461 if (fp->sign == -1)
462 bits |= (ULONGLONG)1 << (MANT_BITS + EXP_BITS - 1);
463 bits |= (ULONGLONG)fp->exp << (MANT_BITS - 1);
464 bits |= fp->m & (((ULONGLONG)1 << (MANT_BITS - 1)) - 1);
466 TRACE("returning %s\n", wine_dbgstr_longlong(bits));
467 *d = *(double*)&bits;
468 return 0;
471 #define LDBL_EXP_BITS 15
472 #define LDBL_MANT_BITS 64
473 int fpnum_ldouble(struct fpnum *fp, MSVCRT__LDOUBLE *d)
475 if (fp->mod == FP_VAL_INFINITY)
477 d->x80[0] = 0;
478 d->x80[1] = 0x80000000;
479 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
480 if (fp->sign == -1)
481 d->x80[2] |= 1 << LDBL_EXP_BITS;
482 return 0;
485 if (fp->mod == FP_VAL_NAN)
487 d->x80[0] = ~0;
488 d->x80[1] = ~0;
489 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
490 if (fp->sign == -1)
491 d->x80[2] |= 1 << LDBL_EXP_BITS;
492 return 0;
495 TRACE("%c %s *2^%d (round %d)\n", fp->sign == -1 ? '-' : '+',
496 wine_dbgstr_longlong(fp->m), fp->exp, fp->mod);
497 if (!fp->m)
499 d->x80[0] = 0;
500 d->x80[1] = 0;
501 d->x80[2] = 0;
502 if (fp->sign == -1)
503 d->x80[2] |= 1 << LDBL_EXP_BITS;
504 return 0;
507 /* make sure that we don't overflow modifying exponent */
508 if (fp->exp > 1<<LDBL_EXP_BITS)
510 d->x80[0] = 0;
511 d->x80[1] = 0x80000000;
512 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
513 if (fp->sign == -1)
514 d->x80[2] |= 1 << LDBL_EXP_BITS;
515 return ERANGE;
517 if (fp->exp < -(1<<LDBL_EXP_BITS))
519 d->x80[0] = 0;
520 d->x80[1] = 0;
521 d->x80[2] = 0;
522 if (fp->sign == -1)
523 d->x80[2] |= 1 << LDBL_EXP_BITS;
524 return ERANGE;
526 fp->exp += LDBL_MANT_BITS - 1;
528 /* normalize mantissa */
529 while(fp->m < (ULONGLONG)1 << (LDBL_MANT_BITS-1))
531 fp->m <<= 1;
532 fp->exp--;
534 fp->exp += (1 << (LDBL_EXP_BITS-1)) - 1;
536 /* handle subnormals */
537 if (fp->exp <= 0)
539 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
540 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
541 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
542 fp->m >>= 1;
544 while(fp->m && fp->exp<0)
546 if (fp->m & 1 && fp->mod == FP_ROUND_ZERO) fp->mod = FP_ROUND_EVEN;
547 else if (fp->m & 1) fp->mod = FP_ROUND_UP;
548 else if (fp->mod != FP_ROUND_ZERO) fp->mod = FP_ROUND_DOWN;
549 fp->m >>= 1;
550 fp->exp++;
553 /* round mantissa */
554 if (fp->mod == FP_ROUND_UP || (fp->mod == FP_ROUND_EVEN && fp->m & 1))
556 if (fp->m == UI64_MAX)
558 fp->m = (ULONGLONG)1 << (LDBL_MANT_BITS - 1);
559 fp->exp++;
561 else
563 fp->m++;
565 /* handle subnormal that falls into regular range due to rounding */
566 if ((fp->m ^ (fp->m - 1)) & ((ULONGLONG)1 << (LDBL_MANT_BITS - 1))) fp->exp++;
570 if (fp->exp >= (1<<LDBL_EXP_BITS)-1)
572 d->x80[0] = 0;
573 d->x80[1] = 0x80000000;
574 d->x80[2] = (1 << LDBL_EXP_BITS) - 1;
575 if (fp->sign == -1)
576 d->x80[2] |= 1 << LDBL_EXP_BITS;
577 return ERANGE;
579 if (!fp->m || fp->exp < 0)
581 d->x80[0] = 0;
582 d->x80[1] = 0;
583 d->x80[2] = 0;
584 if (fp->sign == -1)
585 d->x80[2] |= 1 << LDBL_EXP_BITS;
586 return ERANGE;
589 d->x80[0] = fp->m;
590 d->x80[1] = fp->m >> 32;
591 d->x80[2] = fp->exp;
592 if (fp->sign == -1)
593 d->x80[2] |= 1 << LDBL_EXP_BITS;
594 return 0;
597 #if _MSVCR_VER >= 140
599 static inline int hex2int(char c)
601 if (c >= '0' && c <= '9')
602 return c - '0';
603 else if (c >= 'a' && c <= 'f')
604 return c - 'a' + 10;
605 else if (c >= 'A' && c <= 'F')
606 return c - 'A' + 10;
607 return -1;
610 static struct fpnum fpnum_parse16(wchar_t get(void *ctx), void unget(void *ctx),
611 void *ctx, int sign, pthreadlocinfo locinfo)
613 BOOL found_digit = FALSE, found_dp = FALSE;
614 enum fpmod round = FP_ROUND_ZERO;
615 wchar_t nch;
616 ULONGLONG m = 0;
617 int val, exp = 0;
619 nch = get(ctx);
620 while(m < UI64_MAX/16)
622 val = hex2int(nch);
623 if (val == -1) break;
624 found_digit = TRUE;
625 nch = get(ctx);
627 m = m*16 + val;
629 while(1)
631 val = hex2int(nch);
632 if (val == -1) break;
633 nch = get(ctx);
634 exp += 4;
636 if (val || round != FP_ROUND_ZERO)
638 if (val < 8) round = FP_ROUND_DOWN;
639 else if (val == 8 && round == FP_ROUND_ZERO) round = FP_ROUND_EVEN;
640 else round = FP_ROUND_UP;
644 if(nch == *locinfo->lconv->decimal_point)
646 found_dp = TRUE;
647 nch = get(ctx);
649 else if (!found_digit)
651 if(nch!=WEOF) unget(ctx);
652 unget(ctx);
653 return fpnum(0, 0, 0, 0);
656 while(m <= UI64_MAX/16)
658 val = hex2int(nch);
659 if (val == -1) break;
660 found_digit = TRUE;
661 nch = get(ctx);
663 m = m*16 + val;
664 exp -= 4;
666 while(1)
668 val = hex2int(nch);
669 if (val == -1) break;
670 nch = get(ctx);
672 if (val || round != FP_ROUND_ZERO)
674 if (val < 8) round = FP_ROUND_DOWN;
675 else if (val == 8 && round == FP_ROUND_ZERO) round = FP_ROUND_EVEN;
676 else round = FP_ROUND_UP;
680 if (!found_digit)
682 if (nch != WEOF) unget(ctx);
683 if (found_dp) unget(ctx);
684 unget(ctx);
685 return fpnum(0, 0, 0, 0);
688 if(nch=='p' || nch=='P') {
689 BOOL found_sign = FALSE;
690 int e=0, s=1;
692 nch = get(ctx);
693 if(nch == '-') {
694 found_sign = TRUE;
695 s = -1;
696 nch = get(ctx);
697 } else if(nch == '+') {
698 found_sign = TRUE;
699 nch = get(ctx);
701 if(nch>='0' && nch<='9') {
702 while(nch>='0' && nch<='9') {
703 if(e>INT_MAX/10 || e*10>INT_MAX-nch+'0')
704 e = INT_MAX;
705 else
706 e = e*10+nch-'0';
707 nch = get(ctx);
709 if((nch!=WEOF) && (nch < '0' || nch > '9')) unget(ctx);
710 e *= s;
712 if(e<0 && exp<INT_MIN-e) exp = INT_MIN;
713 else if(e>0 && exp>INT_MAX-e) exp = INT_MAX;
714 else exp += e;
715 } else {
716 if(nch != WEOF) unget(ctx);
717 if(found_sign) unget(ctx);
718 unget(ctx);
722 return fpnum(sign, exp, m, round);
724 #endif
726 /* Converts first 3 limbs to ULONGLONG */
727 /* Return FALSE on overflow */
728 static inline BOOL bnum_to_mant(struct bnum *b, ULONGLONG *m)
730 if(UI64_MAX / LIMB_MAX / LIMB_MAX < b->data[bnum_idx(b, b->e-1)]) return FALSE;
731 *m = (ULONGLONG)b->data[bnum_idx(b, b->e-1)] * LIMB_MAX * LIMB_MAX;
732 if(b->b == b->e-1) return TRUE;
733 if(UI64_MAX - *m < (ULONGLONG)b->data[bnum_idx(b, b->e-2)] * LIMB_MAX) return FALSE;
734 *m += (ULONGLONG)b->data[bnum_idx(b, b->e-2)] * LIMB_MAX;
735 if(b->b == b->e-2) return TRUE;
736 if(UI64_MAX - *m < b->data[bnum_idx(b, b->e-3)]) return FALSE;
737 *m += b->data[bnum_idx(b, b->e-3)];
738 return TRUE;
741 static struct fpnum fpnum_parse_bnum(wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
742 void *ctx, pthreadlocinfo locinfo, BOOL ldouble, struct bnum *b)
744 #if _MSVCR_VER >= 140
745 const wchar_t _infinity[] = L"infinity";
746 const wchar_t _nan[] = L"nan";
747 const wchar_t *str_match = NULL;
748 int matched=0;
749 #endif
750 BOOL found_digit = FALSE, found_dp = FALSE, found_sign = FALSE;
751 int e2 = 0, dp=0, sign=1, off, limb_digits = 0, i;
752 enum fpmod round = FP_ROUND_ZERO;
753 wchar_t nch;
754 ULONGLONG m;
756 nch = get(ctx);
757 if(nch == '-') {
758 found_sign = TRUE;
759 sign = -1;
760 nch = get(ctx);
761 } else if(nch == '+') {
762 found_sign = TRUE;
763 nch = get(ctx);
766 #if _MSVCR_VER >= 140
767 if(nch == _infinity[0] || nch == _toupper(_infinity[0]))
768 str_match = _infinity;
769 if(nch == _nan[0] || nch == _toupper(_nan[0]))
770 str_match = _nan;
771 while(str_match && nch != WEOF &&
772 (nch == str_match[matched] || nch == _toupper(str_match[matched]))) {
773 nch = get(ctx);
774 matched++;
776 if(str_match) {
777 int keep = 0;
778 if(matched >= 8) keep = 8;
779 else if(matched >= 3) keep = 3;
780 if(nch != WEOF) unget(ctx);
781 for (; matched > keep; matched--) {
782 unget(ctx);
784 if(keep) {
785 if (str_match == _infinity)
786 return fpnum(sign, 0, 0, FP_VAL_INFINITY);
787 if (str_match == _nan)
788 return fpnum(sign, 0, 0, FP_VAL_NAN);
789 } else if(found_sign) {
790 unget(ctx);
793 return fpnum(0, 0, 0, 0);
796 if(nch == '0') {
797 found_digit = TRUE;
798 nch = get(ctx);
799 if(nch == 'x' || nch == 'X')
800 return fpnum_parse16(get, unget, ctx, sign, locinfo);
802 #endif
804 while(nch == '0') {
805 found_digit = TRUE;
806 nch = get(ctx);
809 b->b = 0;
810 b->e = 1;
811 b->data[0] = 0;
812 while(nch>='0' && nch<='9') {
813 found_digit = TRUE;
814 if(limb_digits == LIMB_DIGITS) {
815 if(bnum_idx(b, b->b-1) == bnum_idx(b, b->e)) break;
816 else {
817 b->b--;
818 b->data[bnum_idx(b, b->b)] = 0;
819 limb_digits = 0;
823 b->data[bnum_idx(b, b->b)] = b->data[bnum_idx(b, b->b)] * 10 + nch - '0';
824 limb_digits++;
825 nch = get(ctx);
826 dp++;
828 while(nch>='0' && nch<='9') {
829 if(nch != '0') b->data[bnum_idx(b, b->b)] |= 1;
830 nch = get(ctx);
831 dp++;
834 if(nch == *locinfo->lconv->decimal_point) {
835 found_dp = TRUE;
836 nch = get(ctx);
839 /* skip leading '0' */
840 if(nch=='0' && !limb_digits && !b->b) {
841 found_digit = TRUE;
842 while(nch == '0') {
843 nch = get(ctx);
844 dp--;
848 while(nch>='0' && nch<='9') {
849 found_digit = TRUE;
850 if(limb_digits == LIMB_DIGITS) {
851 if(bnum_idx(b, b->b-1) == bnum_idx(b, b->e)) break;
852 else {
853 b->b--;
854 b->data[bnum_idx(b, b->b)] = 0;
855 limb_digits = 0;
859 b->data[bnum_idx(b, b->b)] = b->data[bnum_idx(b, b->b)] * 10 + nch - '0';
860 limb_digits++;
861 nch = get(ctx);
863 while(nch>='0' && nch<='9') {
864 if(nch != '0') b->data[bnum_idx(b, b->b)] |= 1;
865 nch = get(ctx);
868 if(!found_digit) {
869 if(nch != WEOF) unget(ctx);
870 if(found_dp) unget(ctx);
871 if(found_sign) unget(ctx);
872 return fpnum(0, 0, 0, 0);
875 if(nch=='e' || nch=='E' || nch=='d' || nch=='D') {
876 int e=0, s=1;
878 nch = get(ctx);
879 if(nch == '-') {
880 found_sign = TRUE;
881 s = -1;
882 nch = get(ctx);
883 } else if(nch == '+') {
884 found_sign = TRUE;
885 nch = get(ctx);
886 } else {
887 found_sign = FALSE;
890 if(nch>='0' && nch<='9') {
891 while(nch>='0' && nch<='9') {
892 if(e>INT_MAX/10 || e*10>INT_MAX-nch+'0')
893 e = INT_MAX;
894 else
895 e = e*10+nch-'0';
896 nch = get(ctx);
898 if(nch != WEOF) unget(ctx);
899 e *= s;
901 if(e<0 && dp<INT_MIN-e) dp = INT_MIN;
902 else if(e>0 && dp>INT_MAX-e) dp = INT_MAX;
903 else dp += e;
904 } else {
905 if(nch != WEOF) unget(ctx);
906 if(found_sign) unget(ctx);
907 unget(ctx);
909 } else if(nch != WEOF) {
910 unget(ctx);
913 if(!b->data[bnum_idx(b, b->e-1)])
914 return fpnum(sign, 0, 0, 0);
916 /* Fill last limb with 0 if needed */
917 if(b->b+1 != b->e) {
918 for(; limb_digits != LIMB_DIGITS; limb_digits++)
919 b->data[bnum_idx(b, b->b)] *= 10;
921 for(; bnum_idx(b, b->b) < bnum_idx(b, b->e); b->b++) {
922 if(b->data[bnum_idx(b, b->b)]) break;
925 /* move decimal point to limb boundary */
926 if(limb_digits==dp && b->b==b->e-1)
927 return fpnum(sign, 0, b->data[bnum_idx(b, b->e-1)], FP_ROUND_ZERO);
928 off = (dp - limb_digits) % LIMB_DIGITS;
929 if(off < 0) off += LIMB_DIGITS;
930 if(off) bnum_mult(b, p10s[off]);
932 if(dp-1 > (ldouble ? DBL80_MAX_10_EXP : DBL_MAX_10_EXP))
933 return fpnum(sign, INT_MAX, 1, FP_ROUND_ZERO);
934 /* Count part of exponent stored in denormalized mantissa. */
935 /* Increase exponent range to handle subnormals. */
936 if(dp-1 < (ldouble ? DBL80_MIN_10_EXP : DBL_MIN_10_EXP-DBL_DIG-18))
937 return fpnum(sign, INT_MIN, 1, FP_ROUND_ZERO);
939 while(dp > 3*LIMB_DIGITS) {
940 if(bnum_rshift(b, 9)) dp -= LIMB_DIGITS;
941 e2 += 9;
943 while(dp <= 2*LIMB_DIGITS) {
944 if(bnum_lshift(b, 29)) dp += LIMB_DIGITS;
945 e2 -= 29;
947 /* Make sure most significant mantissa bit will be set */
948 while(b->data[bnum_idx(b, b->e-1)] <= 9) {
949 bnum_lshift(b, 1);
950 e2--;
952 while(!bnum_to_mant(b, &m)) {
953 bnum_rshift(b, 1);
954 e2++;
957 if(b->e-4 >= b->b && b->data[bnum_idx(b, b->e-4)]) {
958 if(b->data[bnum_idx(b, b->e-4)] > LIMB_MAX/2) round = FP_ROUND_UP;
959 else if(b->data[bnum_idx(b, b->e-4)] == LIMB_MAX/2) round = FP_ROUND_EVEN;
960 else round = FP_ROUND_DOWN;
962 if(round == FP_ROUND_ZERO || round == FP_ROUND_EVEN) {
963 for(i=b->e-5; i>=b->b; i--) {
964 if(!b->data[bnum_idx(b, b->b)]) continue;
965 if(round == FP_ROUND_EVEN) round = FP_ROUND_UP;
966 else round = FP_ROUND_DOWN;
970 return fpnum(sign, e2, m, round);
973 struct fpnum fpnum_parse(wchar_t (*get)(void *ctx), void (*unget)(void *ctx),
974 void *ctx, pthreadlocinfo locinfo, BOOL ldouble)
976 if(!ldouble) {
977 BYTE bnum_data[FIELD_OFFSET(struct bnum, data[BNUM_PREC64])];
978 struct bnum *b = (struct bnum*)bnum_data;
980 b->size = BNUM_PREC64;
981 return fpnum_parse_bnum(get, unget, ctx, locinfo, ldouble, b);
982 } else {
983 BYTE bnum_data[FIELD_OFFSET(struct bnum, data[BNUM_PREC80])];
984 struct bnum *b = (struct bnum*)bnum_data;
986 b->size = BNUM_PREC80;
987 return fpnum_parse_bnum(get, unget, ctx, locinfo, ldouble, b);
991 static wchar_t strtod_str_get(void *ctx)
993 const char **p = ctx;
994 if (!**p) return WEOF;
995 return *(*p)++;
998 static void strtod_str_unget(void *ctx)
1000 const char **p = ctx;
1001 (*p)--;
1004 static inline double strtod_helper(const char *str, char **end, _locale_t locale, int *perr)
1006 pthreadlocinfo locinfo;
1007 const char *beg, *p;
1008 struct fpnum fp;
1009 double ret;
1010 int err;
1012 if (perr) *perr = 0;
1013 #if _MSVCR_VER == 0
1014 else *_errno() = 0;
1015 #endif
1017 if (!MSVCRT_CHECK_PMT(str != NULL)) {
1018 if (end) *end = NULL;
1019 return 0;
1022 if (!locale)
1023 locinfo = get_locinfo();
1024 else
1025 locinfo = locale->locinfo;
1027 p = str;
1028 while(_isspace_l((unsigned char)*p, locale))
1029 p++;
1030 beg = p;
1032 fp = fpnum_parse(strtod_str_get, strtod_str_unget, &p, locinfo, FALSE);
1033 if (end) *end = (p == beg ? (char*)str : (char*)p);
1035 err = fpnum_double(&fp, &ret);
1036 if (perr) *perr = err;
1037 else if(err) *_errno() = err;
1038 return ret;
1041 /*********************************************************************
1042 * _strtod_l (MSVCRT.@)
1044 double CDECL _strtod_l(const char *str, char **end, _locale_t locale)
1046 return strtod_helper(str, end, locale, NULL);
1049 /*********************************************************************
1050 * strtod (MSVCRT.@)
1052 double CDECL strtod( const char *str, char **end )
1054 return _strtod_l( str, end, NULL );
1057 #if _MSVCR_VER>=120
1059 /*********************************************************************
1060 * strtof_l (MSVCR120.@)
1062 float CDECL _strtof_l( const char *str, char **end, _locale_t locale )
1064 return _strtod_l(str, end, locale);
1067 /*********************************************************************
1068 * strtof (MSVCR120.@)
1070 float CDECL strtof( const char *str, char **end )
1072 return _strtof_l(str, end, NULL);
1075 #endif /* _MSVCR_VER>=120 */
1077 /*********************************************************************
1078 * atof (MSVCRT.@)
1080 double CDECL atof( const char *str )
1082 return _strtod_l(str, NULL, NULL);
1085 /*********************************************************************
1086 * _atof_l (MSVCRT.@)
1088 double CDECL _atof_l( const char *str, _locale_t locale)
1090 return _strtod_l(str, NULL, locale);
1093 /*********************************************************************
1094 * _atoflt_l (MSVCRT.@)
1096 int CDECL _atoflt_l(_CRT_FLOAT *value, char *str, _locale_t locale)
1098 double d;
1099 int err;
1101 d = strtod_helper(str, NULL, locale, &err);
1102 value->f = d;
1103 if(isinf(value->f))
1104 return _OVERFLOW;
1105 if((d!=0 || err) && value->f>-FLT_MIN && value->f<FLT_MIN)
1106 return _UNDERFLOW;
1107 return 0;
1110 /*********************************************************************
1111 * _atoflt (MSVCR100.@)
1113 int CDECL _atoflt(_CRT_FLOAT *value, char *str)
1115 return _atoflt_l(value, str, NULL);
1118 /*********************************************************************
1119 * _atodbl_l (MSVCRT.@)
1121 int CDECL _atodbl_l(_CRT_DOUBLE *value, char *str, _locale_t locale)
1123 int err;
1125 value->x = strtod_helper(str, NULL, locale, &err);
1126 if(isinf(value->x))
1127 return _OVERFLOW;
1128 if((value->x!=0 || err) && value->x>-DBL_MIN && value->x<DBL_MIN)
1129 return _UNDERFLOW;
1130 return 0;
1133 /*********************************************************************
1134 * _atodbl (MSVCRT.@)
1136 int CDECL _atodbl(_CRT_DOUBLE *value, char *str)
1138 return _atodbl_l(value, str, NULL);
1141 /*********************************************************************
1142 * _strcoll_l (MSVCRT.@)
1144 int CDECL _strcoll_l( const char* str1, const char* str2, _locale_t locale )
1146 pthreadlocinfo locinfo;
1148 if(!locale)
1149 locinfo = get_locinfo();
1150 else
1151 locinfo = locale->locinfo;
1153 if(!locinfo->lc_handle[LC_COLLATE])
1154 return strcmp(str1, str2);
1155 return CompareStringA(locinfo->lc_handle[LC_COLLATE], 0, str1, -1, str2, -1)-CSTR_EQUAL;
1158 /*********************************************************************
1159 * strcoll (MSVCRT.@)
1161 int CDECL strcoll( const char* str1, const char* str2 )
1163 return _strcoll_l(str1, str2, NULL);
1166 /*********************************************************************
1167 * _stricoll_l (MSVCRT.@)
1169 int CDECL _stricoll_l( const char* str1, const char* str2, _locale_t locale )
1171 pthreadlocinfo locinfo;
1173 if(!locale)
1174 locinfo = get_locinfo();
1175 else
1176 locinfo = locale->locinfo;
1178 if(!locinfo->lc_handle[LC_COLLATE])
1179 return _stricmp(str1, str2);
1180 return CompareStringA(locinfo->lc_handle[LC_COLLATE], NORM_IGNORECASE,
1181 str1, -1, str2, -1)-CSTR_EQUAL;
1184 /*********************************************************************
1185 * _stricoll (MSVCRT.@)
1187 int CDECL _stricoll( const char* str1, const char* str2 )
1189 return _stricoll_l(str1, str2, NULL);
1192 /*********************************************************************
1193 * _strncoll_l (MSVCRT.@)
1195 int CDECL _strncoll_l( const char* str1, const char* str2, size_t count, _locale_t locale )
1197 pthreadlocinfo locinfo;
1199 if(!locale)
1200 locinfo = get_locinfo();
1201 else
1202 locinfo = locale->locinfo;
1204 if(!locinfo->lc_handle[LC_COLLATE])
1205 return strncmp(str1, str2, count);
1206 return CompareStringA(locinfo->lc_handle[LC_COLLATE], 0,
1207 str1, strnlen(str1, count),
1208 str2, strnlen(str2, count))-CSTR_EQUAL;
1211 /*********************************************************************
1212 * _strncoll (MSVCRT.@)
1214 int CDECL _strncoll( const char* str1, const char* str2, size_t count )
1216 return _strncoll_l(str1, str2, count, NULL);
1219 /*********************************************************************
1220 * _strnicoll_l (MSVCRT.@)
1222 int CDECL _strnicoll_l( const char* str1, const char* str2, size_t count, _locale_t locale )
1224 pthreadlocinfo locinfo;
1226 if(!locale)
1227 locinfo = get_locinfo();
1228 else
1229 locinfo = locale->locinfo;
1231 if(!locinfo->lc_handle[LC_COLLATE])
1232 return _strnicmp(str1, str2, count);
1233 return CompareStringA(locinfo->lc_handle[LC_COLLATE], NORM_IGNORECASE,
1234 str1, strnlen(str1, count),
1235 str2, strnlen(str2, count))-CSTR_EQUAL;
1238 /*********************************************************************
1239 * _strnicoll (MSVCRT.@)
1241 int CDECL _strnicoll( const char* str1, const char* str2, size_t count )
1243 return _strnicoll_l(str1, str2, count, NULL);
1246 /*********************************************************************
1247 * strncpy (MSVCRT.@)
1249 char* __cdecl strncpy(char *dst, const char *src, size_t len)
1251 size_t i;
1253 for(i=0; i<len; i++)
1254 if((dst[i] = src[i]) == '\0') break;
1256 while (i < len) dst[i++] = 0;
1258 return dst;
1261 /*********************************************************************
1262 * strcpy (MSVCRT.@)
1264 char* CDECL strcpy(char *dst, const char *src)
1266 char *ret = dst;
1267 while ((*dst++ = *src++));
1268 return ret;
1271 /*********************************************************************
1272 * strcpy_s (MSVCRT.@)
1274 int CDECL strcpy_s( char* dst, size_t elem, const char* src )
1276 size_t i;
1277 if(!elem) return EINVAL;
1278 if(!dst) return EINVAL;
1279 if(!src)
1281 dst[0] = '\0';
1282 return EINVAL;
1285 for(i = 0; i < elem; i++)
1287 if((dst[i] = src[i]) == '\0') return 0;
1289 dst[0] = '\0';
1290 return ERANGE;
1293 /*********************************************************************
1294 * strcat_s (MSVCRT.@)
1296 int CDECL strcat_s( char* dst, size_t elem, const char* src )
1298 size_t i, j;
1299 if(!dst) return EINVAL;
1300 if(elem == 0) return EINVAL;
1301 if(!src)
1303 dst[0] = '\0';
1304 return EINVAL;
1307 for(i = 0; i < elem; i++)
1309 if(dst[i] == '\0')
1311 for(j = 0; (j + i) < elem; j++)
1313 if((dst[j + i] = src[j]) == '\0') return 0;
1317 /* Set the first element to 0, not the first element after the skipped part */
1318 dst[0] = '\0';
1319 return ERANGE;
1322 /*********************************************************************
1323 * strcat (MSVCRT.@)
1325 char* __cdecl strcat( char *dst, const char *src )
1327 char *d = dst;
1328 while (*d) d++;
1329 while ((*d++ = *src++));
1330 return dst;
1333 /*********************************************************************
1334 * strncat_s (MSVCRT.@)
1336 int CDECL strncat_s( char* dst, size_t elem, const char* src, size_t count )
1338 size_t i, j;
1340 if (!MSVCRT_CHECK_PMT(dst != 0)) return EINVAL;
1341 if (!MSVCRT_CHECK_PMT(elem != 0)) return EINVAL;
1342 if (!MSVCRT_CHECK_PMT(src != 0))
1344 dst[0] = '\0';
1345 return EINVAL;
1348 for(i = 0; i < elem; i++)
1350 if(dst[i] == '\0')
1352 for(j = 0; (j + i) < elem; j++)
1354 if(count == _TRUNCATE && j + i == elem - 1)
1356 dst[j + i] = '\0';
1357 return STRUNCATE;
1359 if(j == count || (dst[j + i] = src[j]) == '\0')
1361 dst[j + i] = '\0';
1362 return 0;
1367 /* Set the first element to 0, not the first element after the skipped part */
1368 dst[0] = '\0';
1369 return ERANGE;
1372 /*********************************************************************
1373 * strncat (MSVCRT.@)
1375 char* __cdecl strncat(char *dst, const char *src, size_t len)
1377 char *d = dst;
1378 while (*d) d++;
1379 for ( ; len && *src; d++, src++, len--) *d = *src;
1380 *d = 0;
1381 return dst;
1384 /*********************************************************************
1385 * _strxfrm_l (MSVCRT.@)
1387 size_t CDECL _strxfrm_l( char *dest, const char *src,
1388 size_t len, _locale_t locale )
1390 pthreadlocinfo locinfo;
1391 int ret;
1393 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
1394 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
1396 if(len > INT_MAX) {
1397 FIXME("len > INT_MAX not supported\n");
1398 len = INT_MAX;
1401 if(!locale)
1402 locinfo = get_locinfo();
1403 else
1404 locinfo = locale->locinfo;
1406 if(!locinfo->lc_handle[LC_COLLATE]) {
1407 strncpy(dest, src, len);
1408 return strlen(src);
1411 ret = LCMapStringA(locinfo->lc_handle[LC_COLLATE],
1412 LCMAP_SORTKEY, src, -1, NULL, 0);
1413 if(!ret) {
1414 if(len) dest[0] = 0;
1415 *_errno() = EILSEQ;
1416 return INT_MAX;
1418 if(!len) return ret-1;
1420 if(ret > len) {
1421 dest[0] = 0;
1422 *_errno() = ERANGE;
1423 return ret-1;
1426 return LCMapStringA(locinfo->lc_handle[LC_COLLATE],
1427 LCMAP_SORTKEY, src, -1, dest, len) - 1;
1430 /*********************************************************************
1431 * strxfrm (MSVCRT.@)
1433 size_t CDECL strxfrm( char *dest, const char *src, size_t len )
1435 return _strxfrm_l(dest, src, len, NULL);
1438 /********************************************************************
1439 * __STRINGTOLD_L (MSVCR80.@)
1441 int CDECL __STRINGTOLD_L( MSVCRT__LDOUBLE *value, char **endptr,
1442 const char *str, int flags, _locale_t locale )
1444 pthreadlocinfo locinfo;
1445 const char *beg, *p;
1446 int err, ret = 0;
1447 struct fpnum fp;
1449 if (flags) FIXME("flags not supported: %x\n", flags);
1451 if (!locale)
1452 locinfo = get_locinfo();
1453 else
1454 locinfo = locale->locinfo;
1456 p = str;
1457 while (_isspace_l((unsigned char)*p, locale))
1458 p++;
1459 beg = p;
1461 fp = fpnum_parse(strtod_str_get, strtod_str_unget, &p, locinfo, TRUE);
1462 if (endptr) *endptr = (p == beg ? (char*)str : (char*)p);
1463 if (p == beg) ret = 4;
1465 err = fpnum_ldouble(&fp, value);
1466 if (err) ret = (value->x80[2] & 0x7fff ? 2 : 1);
1467 return ret;
1470 /********************************************************************
1471 * __STRINGTOLD (MSVCRT.@)
1473 int CDECL __STRINGTOLD( MSVCRT__LDOUBLE *value, char **endptr, const char *str, int flags )
1475 return __STRINGTOLD_L( value, endptr, str, flags, NULL );
1478 /********************************************************************
1479 * _atoldbl_l (MSVCRT.@)
1481 int CDECL _atoldbl_l( MSVCRT__LDOUBLE *value, char *str, _locale_t locale )
1483 char *endptr;
1484 switch(__STRINGTOLD_L( value, &endptr, str, 0, locale ))
1486 case 1: return _UNDERFLOW;
1487 case 2: return _OVERFLOW;
1488 default: return 0;
1492 /********************************************************************
1493 * _atoldbl (MSVCRT.@)
1495 int CDECL _atoldbl(_LDOUBLE *value, char *str)
1497 return _atoldbl_l( (MSVCRT__LDOUBLE*)value, str, NULL );
1500 /*********************************************************************
1501 * strlen (MSVCRT.@)
1503 size_t __cdecl strlen(const char *str)
1505 const char *s = str;
1506 while (*s) s++;
1507 return s - str;
1510 /******************************************************************
1511 * strnlen (MSVCRT.@)
1513 size_t CDECL strnlen(const char *s, size_t maxlen)
1515 size_t i;
1517 for(i=0; i<maxlen; i++)
1518 if(!s[i]) break;
1520 return i;
1523 /*********************************************************************
1524 * _strtoi64_l (MSVCRT.@)
1526 * FIXME: locale parameter is ignored
1528 __int64 CDECL _strtoi64_l(const char *nptr, char **endptr, int base, _locale_t locale)
1530 const char *p = nptr;
1531 BOOL negative = FALSE;
1532 BOOL got_digit = FALSE;
1533 __int64 ret = 0;
1535 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1537 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1538 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1539 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1541 while(_isspace_l((unsigned char)*nptr, locale)) nptr++;
1543 if(*nptr == '-') {
1544 negative = TRUE;
1545 nptr++;
1546 } else if(*nptr == '+')
1547 nptr++;
1549 if((base==0 || base==16) && *nptr=='0' && _tolower_l(*(nptr+1), locale)=='x') {
1550 base = 16;
1551 nptr += 2;
1554 if(base == 0) {
1555 if(*nptr=='0')
1556 base = 8;
1557 else
1558 base = 10;
1561 while(*nptr) {
1562 char cur = _tolower_l(*nptr, locale);
1563 int v;
1565 if(cur>='0' && cur<='9') {
1566 if(cur >= '0'+base)
1567 break;
1568 v = cur-'0';
1569 } else {
1570 if(cur<'a' || cur>='a'+base-10)
1571 break;
1572 v = cur-'a'+10;
1574 got_digit = TRUE;
1576 if(negative)
1577 v = -v;
1579 nptr++;
1581 if(!negative && (ret>I64_MAX/base || ret*base>I64_MAX-v)) {
1582 ret = I64_MAX;
1583 *_errno() = ERANGE;
1584 } else if(negative && (ret<I64_MIN/base || ret*base<I64_MIN-v)) {
1585 ret = I64_MIN;
1586 *_errno() = ERANGE;
1587 } else
1588 ret = ret*base + v;
1591 if(endptr)
1592 *endptr = (char*)(got_digit ? nptr : p);
1594 return ret;
1597 /*********************************************************************
1598 * _strtoi64 (MSVCRT.@)
1600 __int64 CDECL _strtoi64(const char *nptr, char **endptr, int base)
1602 return _strtoi64_l(nptr, endptr, base, NULL);
1605 /*********************************************************************
1606 * _atoi_l (MSVCRT.@)
1608 int __cdecl _atoi_l(const char *str, _locale_t locale)
1610 __int64 ret = _strtoi64_l(str, NULL, 10, locale);
1612 if(ret > INT_MAX) {
1613 ret = INT_MAX;
1614 *_errno() = ERANGE;
1615 } else if(ret < INT_MIN) {
1616 ret = INT_MIN;
1617 *_errno() = ERANGE;
1619 return ret;
1622 /*********************************************************************
1623 * atoi (MSVCRT.@)
1625 #if _MSVCR_VER == 0
1626 int __cdecl atoi(const char *str)
1628 BOOL minus = FALSE;
1629 int ret = 0;
1631 if(!str)
1632 return 0;
1634 while(_isspace_l((unsigned char)*str, NULL)) str++;
1636 if(*str == '+') {
1637 str++;
1638 }else if(*str == '-') {
1639 minus = TRUE;
1640 str++;
1643 while(*str>='0' && *str<='9') {
1644 ret = ret*10+*str-'0';
1645 str++;
1648 return minus ? -ret : ret;
1650 #else
1651 int CDECL atoi(const char *str)
1653 return _atoi_l(str, NULL);
1655 #endif
1657 /******************************************************************
1658 * _atoi64_l (MSVCRT.@)
1660 __int64 CDECL _atoi64_l(const char *str, _locale_t locale)
1662 return _strtoi64_l(str, NULL, 10, locale);
1665 /******************************************************************
1666 * _atoi64 (MSVCRT.@)
1668 __int64 CDECL _atoi64(const char *str)
1670 return _strtoi64_l(str, NULL, 10, NULL);
1673 /******************************************************************
1674 * _atol_l (MSVCRT.@)
1676 __msvcrt_long CDECL _atol_l(const char *str, _locale_t locale)
1678 __int64 ret = _strtoi64_l(str, NULL, 10, locale);
1680 if(ret > LONG_MAX) {
1681 ret = LONG_MAX;
1682 *_errno() = ERANGE;
1683 } else if(ret < LONG_MIN) {
1684 ret = LONG_MIN;
1685 *_errno() = ERANGE;
1687 return ret;
1690 /******************************************************************
1691 * atol (MSVCRT.@)
1693 __msvcrt_long CDECL atol(const char *str)
1695 #if _MSVCR_VER == 0
1696 return atoi(str);
1697 #else
1698 return _atol_l(str, NULL);
1699 #endif
1702 #if _MSVCR_VER>=120
1704 /******************************************************************
1705 * _atoll_l (MSVCR120.@)
1707 __int64 CDECL _atoll_l(const char* str, _locale_t locale)
1709 return _strtoi64_l(str, NULL, 10, locale);
1712 /******************************************************************
1713 * atoll (MSVCR120.@)
1715 __int64 CDECL atoll(const char* str)
1717 return _atoll_l(str, NULL);
1720 #endif /* _MSVCR_VER>=120 */
1722 /******************************************************************
1723 * _strtol_l (MSVCRT.@)
1725 __msvcrt_long CDECL _strtol_l(const char* nptr,
1726 char** end, int base, _locale_t locale)
1728 __int64 ret = _strtoi64_l(nptr, end, base, locale);
1730 if(ret > LONG_MAX) {
1731 ret = LONG_MAX;
1732 *_errno() = ERANGE;
1733 } else if(ret < LONG_MIN) {
1734 ret = LONG_MIN;
1735 *_errno() = ERANGE;
1738 return ret;
1741 /******************************************************************
1742 * strtol (MSVCRT.@)
1744 __msvcrt_long CDECL strtol(const char* nptr, char** end, int base)
1746 return _strtol_l(nptr, end, base, NULL);
1749 /******************************************************************
1750 * _strtoul_l (MSVCRT.@)
1752 __msvcrt_ulong CDECL _strtoul_l(const char* nptr, char** end, int base, _locale_t locale)
1754 __int64 ret = _strtoi64_l(nptr, end, base, locale);
1756 if(ret > ULONG_MAX) {
1757 ret = ULONG_MAX;
1758 *_errno() = ERANGE;
1759 }else if(ret < -(__int64)ULONG_MAX) {
1760 ret = 1;
1761 *_errno() = ERANGE;
1764 return ret;
1767 /******************************************************************
1768 * strtoul (MSVCRT.@)
1770 __msvcrt_ulong CDECL strtoul(const char* nptr, char** end, int base)
1772 return _strtoul_l(nptr, end, base, NULL);
1775 /*********************************************************************
1776 * _strtoui64_l (MSVCRT.@)
1778 * FIXME: locale parameter is ignored
1780 unsigned __int64 CDECL _strtoui64_l(const char *nptr, char **endptr, int base, _locale_t locale)
1782 const char *p = nptr;
1783 BOOL negative = FALSE;
1784 BOOL got_digit = FALSE;
1785 unsigned __int64 ret = 0;
1787 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1789 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1790 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1791 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1793 while(_isspace_l((unsigned char)*nptr, locale)) nptr++;
1795 if(*nptr == '-') {
1796 negative = TRUE;
1797 nptr++;
1798 } else if(*nptr == '+')
1799 nptr++;
1801 if((base==0 || base==16) && *nptr=='0' && _tolower_l(*(nptr+1), locale)=='x') {
1802 base = 16;
1803 nptr += 2;
1806 if(base == 0) {
1807 if(*nptr=='0')
1808 base = 8;
1809 else
1810 base = 10;
1813 while(*nptr) {
1814 char cur = _tolower_l(*nptr, locale);
1815 int v;
1817 if(cur>='0' && cur<='9') {
1818 if(cur >= '0'+base)
1819 break;
1820 v = *nptr-'0';
1821 } else {
1822 if(cur<'a' || cur>='a'+base-10)
1823 break;
1824 v = cur-'a'+10;
1826 got_digit = TRUE;
1828 nptr++;
1830 if(ret>UI64_MAX/base || ret*base>UI64_MAX-v) {
1831 ret = UI64_MAX;
1832 *_errno() = ERANGE;
1833 } else
1834 ret = ret*base + v;
1837 if(endptr)
1838 *endptr = (char*)(got_digit ? nptr : p);
1840 return negative ? -ret : ret;
1843 /*********************************************************************
1844 * _strtoui64 (MSVCRT.@)
1846 unsigned __int64 CDECL _strtoui64(const char *nptr, char **endptr, int base)
1848 return _strtoui64_l(nptr, endptr, base, NULL);
1851 static int ltoa_helper(__msvcrt_long value, char *str, size_t size, int radix)
1853 __msvcrt_ulong val;
1854 unsigned int digit;
1855 BOOL is_negative;
1856 char buffer[33], *pos;
1857 size_t len;
1859 if (value < 0 && radix == 10)
1861 is_negative = TRUE;
1862 val = -value;
1864 else
1866 is_negative = FALSE;
1867 val = value;
1870 pos = buffer + 32;
1871 *pos = '\0';
1875 digit = val % radix;
1876 val /= radix;
1878 if (digit < 10)
1879 *--pos = '0' + digit;
1880 else
1881 *--pos = 'a' + digit - 10;
1883 while (val != 0);
1885 if (is_negative)
1886 *--pos = '-';
1888 len = buffer + 33 - pos;
1889 if (len > size)
1891 size_t i;
1892 char *p = str;
1894 /* Copy the temporary buffer backwards up to the available number of
1895 * characters. Don't copy the negative sign if present. */
1897 if (is_negative)
1899 p++;
1900 size--;
1903 for (pos = buffer + 31, i = 0; i < size; i++)
1904 *p++ = *pos--;
1906 str[0] = '\0';
1907 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE);
1908 return ERANGE;
1911 memcpy(str, pos, len);
1912 return 0;
1915 /*********************************************************************
1916 * _ltoa_s (MSVCRT.@)
1918 int CDECL _ltoa_s(__msvcrt_long value, char *str, size_t size, int radix)
1920 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
1921 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
1922 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1924 str[0] = '\0';
1925 return EINVAL;
1928 return ltoa_helper(value, str, size, radix);
1931 /*********************************************************************
1932 * _ltow_s (MSVCRT.@)
1934 int CDECL _ltow_s(__msvcrt_long value, wchar_t *str, size_t size, int radix)
1936 __msvcrt_ulong val;
1937 unsigned int digit;
1938 BOOL is_negative;
1939 wchar_t buffer[33], *pos;
1940 size_t len;
1942 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
1943 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
1944 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1946 str[0] = '\0';
1947 return EINVAL;
1950 if (value < 0 && radix == 10)
1952 is_negative = TRUE;
1953 val = -value;
1955 else
1957 is_negative = FALSE;
1958 val = value;
1961 pos = buffer + 32;
1962 *pos = '\0';
1966 digit = val % radix;
1967 val /= radix;
1969 if (digit < 10)
1970 *--pos = '0' + digit;
1971 else
1972 *--pos = 'a' + digit - 10;
1974 while (val != 0);
1976 if (is_negative)
1977 *--pos = '-';
1979 len = buffer + 33 - pos;
1980 if (len > size)
1982 size_t i;
1983 wchar_t *p = str;
1985 /* Copy the temporary buffer backwards up to the available number of
1986 * characters. Don't copy the negative sign if present. */
1988 if (is_negative)
1990 p++;
1991 size--;
1994 for (pos = buffer + 31, i = 0; i < size; i++)
1995 *p++ = *pos--;
1997 str[0] = '\0';
1998 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE);
1999 return ERANGE;
2002 memcpy(str, pos, len * sizeof(wchar_t));
2003 return 0;
2006 /*********************************************************************
2007 * _itoa_s (MSVCRT.@)
2009 int CDECL _itoa_s(int value, char *str, size_t size, int radix)
2011 return _ltoa_s(value, str, size, radix);
2014 /*********************************************************************
2015 * _itoa (MSVCRT.@)
2017 char* CDECL _itoa(int value, char *str, int radix)
2019 return ltoa_helper(value, str, SIZE_MAX, radix) ? NULL : str;
2022 /*********************************************************************
2023 * _itow_s (MSVCRT.@)
2025 int CDECL _itow_s(int value, wchar_t *str, size_t size, int radix)
2027 return _ltow_s(value, str, size, radix);
2030 /*********************************************************************
2031 * _ui64toa_s (MSVCRT.@)
2033 int CDECL _ui64toa_s(unsigned __int64 value, char *str,
2034 size_t size, int radix)
2036 char buffer[65], *pos;
2037 int digit;
2039 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
2040 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
2041 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2043 str[0] = '\0';
2044 return EINVAL;
2047 pos = buffer+64;
2048 *pos = '\0';
2050 do {
2051 digit = value%radix;
2052 value /= radix;
2054 if(digit < 10)
2055 *--pos = '0'+digit;
2056 else
2057 *--pos = 'a'+digit-10;
2058 }while(value != 0);
2060 if(buffer-pos+65 > size) {
2061 MSVCRT_INVALID_PMT("str[size] is too small", EINVAL);
2062 return EINVAL;
2065 memcpy(str, pos, buffer-pos+65);
2066 return 0;
2069 /*********************************************************************
2070 * _ui64tow_s (MSVCRT.@)
2072 int CDECL _ui64tow_s( unsigned __int64 value, wchar_t *str,
2073 size_t size, int radix )
2075 wchar_t buffer[65], *pos;
2076 int digit;
2078 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
2079 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
2080 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2082 str[0] = '\0';
2083 return EINVAL;
2086 pos = &buffer[64];
2087 *pos = '\0';
2089 do {
2090 digit = value % radix;
2091 value = value / radix;
2092 if (digit < 10)
2093 *--pos = '0' + digit;
2094 else
2095 *--pos = 'a' + digit - 10;
2096 } while (value != 0);
2098 if(buffer-pos+65 > size) {
2099 MSVCRT_INVALID_PMT("str[size] is too small", EINVAL);
2100 return EINVAL;
2103 memcpy(str, pos, (buffer-pos+65)*sizeof(wchar_t));
2104 return 0;
2107 /*********************************************************************
2108 * _ultoa_s (MSVCRT.@)
2110 int CDECL _ultoa_s(__msvcrt_ulong value, char *str, size_t size, int radix)
2112 __msvcrt_ulong digit;
2113 char buffer[33], *pos;
2114 size_t len;
2116 if (!str || !size || radix < 2 || radix > 36)
2118 if (str && size)
2119 str[0] = '\0';
2121 *_errno() = EINVAL;
2122 return EINVAL;
2125 pos = buffer + 32;
2126 *pos = '\0';
2130 digit = value % radix;
2131 value /= radix;
2133 if (digit < 10)
2134 *--pos = '0' + digit;
2135 else
2136 *--pos = 'a' + digit - 10;
2138 while (value != 0);
2140 len = buffer + 33 - pos;
2141 if (len > size)
2143 size_t i;
2144 char *p = str;
2146 /* Copy the temporary buffer backwards up to the available number of
2147 * characters. */
2149 for (pos = buffer + 31, i = 0; i < size; i++)
2150 *p++ = *pos--;
2152 str[0] = '\0';
2153 *_errno() = ERANGE;
2154 return ERANGE;
2157 memcpy(str, pos, len);
2158 return 0;
2161 /*********************************************************************
2162 * _ultow_s (MSVCRT.@)
2164 int CDECL _ultow_s(__msvcrt_ulong value, wchar_t *str, size_t size, int radix)
2166 __msvcrt_ulong digit;
2167 WCHAR buffer[33], *pos;
2168 size_t len;
2170 if (!str || !size || radix < 2 || radix > 36)
2172 if (str && size)
2173 str[0] = '\0';
2175 *_errno() = EINVAL;
2176 return EINVAL;
2179 pos = buffer + 32;
2180 *pos = '\0';
2184 digit = value % radix;
2185 value /= radix;
2187 if (digit < 10)
2188 *--pos = '0' + digit;
2189 else
2190 *--pos = 'a' + digit - 10;
2192 while (value != 0);
2194 len = buffer + 33 - pos;
2195 if (len > size)
2197 size_t i;
2198 WCHAR *p = str;
2200 /* Copy the temporary buffer backwards up to the available number of
2201 * characters. */
2203 for (pos = buffer + 31, i = 0; i < size; i++)
2204 *p++ = *pos--;
2206 str[0] = '\0';
2207 *_errno() = ERANGE;
2208 return ERANGE;
2211 memcpy(str, pos, len * sizeof(wchar_t));
2212 return 0;
2215 /*********************************************************************
2216 * _i64toa_s (MSVCRT.@)
2218 int CDECL _i64toa_s(__int64 value, char *str, size_t size, int radix)
2220 unsigned __int64 val;
2221 unsigned int digit;
2222 BOOL is_negative;
2223 char buffer[65], *pos;
2224 size_t len;
2226 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
2227 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
2228 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2230 str[0] = '\0';
2231 return EINVAL;
2234 if (value < 0 && radix == 10)
2236 is_negative = TRUE;
2237 val = -value;
2239 else
2241 is_negative = FALSE;
2242 val = value;
2245 pos = buffer + 64;
2246 *pos = '\0';
2250 digit = val % radix;
2251 val /= radix;
2253 if (digit < 10)
2254 *--pos = '0' + digit;
2255 else
2256 *--pos = 'a' + digit - 10;
2258 while (val != 0);
2260 if (is_negative)
2261 *--pos = '-';
2263 len = buffer + 65 - pos;
2264 if (len > size)
2266 size_t i;
2267 char *p = str;
2269 /* Copy the temporary buffer backwards up to the available number of
2270 * characters. Don't copy the negative sign if present. */
2272 if (is_negative)
2274 p++;
2275 size--;
2278 for (pos = buffer + 63, i = 0; i < size; i++)
2279 *p++ = *pos--;
2281 str[0] = '\0';
2282 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE);
2283 return ERANGE;
2286 memcpy(str, pos, len);
2287 return 0;
2290 /*********************************************************************
2291 * _i64tow_s (MSVCRT.@)
2293 int CDECL _i64tow_s(__int64 value, wchar_t *str, size_t size, int radix)
2295 unsigned __int64 val;
2296 unsigned int digit;
2297 BOOL is_negative;
2298 wchar_t buffer[65], *pos;
2299 size_t len;
2301 if (!MSVCRT_CHECK_PMT(str != NULL)) return EINVAL;
2302 if (!MSVCRT_CHECK_PMT(size > 0)) return EINVAL;
2303 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
2305 str[0] = '\0';
2306 return EINVAL;
2309 if (value < 0 && radix == 10)
2311 is_negative = TRUE;
2312 val = -value;
2314 else
2316 is_negative = FALSE;
2317 val = value;
2320 pos = buffer + 64;
2321 *pos = '\0';
2325 digit = val % radix;
2326 val /= radix;
2328 if (digit < 10)
2329 *--pos = '0' + digit;
2330 else
2331 *--pos = 'a' + digit - 10;
2333 while (val != 0);
2335 if (is_negative)
2336 *--pos = '-';
2338 len = buffer + 65 - pos;
2339 if (len > size)
2341 size_t i;
2342 wchar_t *p = str;
2344 /* Copy the temporary buffer backwards up to the available number of
2345 * characters. Don't copy the negative sign if present. */
2347 if (is_negative)
2349 p++;
2350 size--;
2353 for (pos = buffer + 63, i = 0; i < size; i++)
2354 *p++ = *pos--;
2356 str[0] = '\0';
2357 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE);
2358 return ERANGE;
2361 memcpy(str, pos, len * sizeof(wchar_t));
2362 return 0;
2365 #define I10_OUTPUT_MAX_PREC 21
2366 /* Internal structure used by $I10_OUTPUT */
2367 struct _I10_OUTPUT_DATA {
2368 short pos;
2369 char sign;
2370 BYTE len;
2371 char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */
2374 /*********************************************************************
2375 * $I10_OUTPUT (MSVCRT.@)
2376 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
2377 * prec - precision of part, we're interested in
2378 * flag - 0 for first prec digits, 1 for fractional part
2379 * data - data to be populated
2381 * return value
2382 * 0 if given double is NaN or INF
2383 * 1 otherwise
2385 * FIXME
2386 * Native sets last byte of data->str to '0' or '9', I don't know what
2387 * it means. Current implementation sets it always to '0'.
2389 int CDECL I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data)
2391 struct fpnum num;
2392 double d;
2393 char format[8];
2394 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
2395 char *p;
2397 if ((ld80.x80[2] & 0x7fff) == 0x7fff)
2399 if (ld80.x80[0] == 0 && ld80.x80[1] == 0x80000000)
2400 strcpy( data->str, "1#INF" );
2401 else
2402 strcpy( data->str, (ld80.x80[1] & 0x40000000) ? "1#QNAN" : "1#SNAN" );
2403 data->pos = 1;
2404 data->sign = (ld80.x80[2] & 0x8000) ? '-' : ' ';
2405 data->len = strlen(data->str);
2406 return 0;
2409 num.sign = (ld80.x80[2] & 0x8000) ? -1 : 1;
2410 num.exp = (ld80.x80[2] & 0x7fff) - 0x3fff - 63;
2411 num.m = ld80.x80[0] | ((ULONGLONG)ld80.x80[1] << 32);
2412 num.mod = FP_ROUND_EVEN;
2413 fpnum_double( &num, &d );
2414 TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
2416 if(d<0) {
2417 data->sign = '-';
2418 d = -d;
2419 } else
2420 data->sign = ' ';
2422 if(flag&1) {
2423 int exp = 1 + floor(log10(d));
2425 prec += exp;
2426 if(exp < 0)
2427 prec--;
2429 prec--;
2431 if(prec+1 > I10_OUTPUT_MAX_PREC)
2432 prec = I10_OUTPUT_MAX_PREC-1;
2433 else if(prec < 0) {
2434 d = 0.0;
2435 prec = 0;
2438 sprintf(format, "%%.%dle", prec);
2439 sprintf(buf, format, d);
2441 buf[1] = buf[0];
2442 data->pos = atoi(buf+prec+3);
2443 if(buf[1] != '0')
2444 data->pos++;
2446 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
2447 data->len = p-buf;
2449 memcpy(data->str, buf+1, data->len);
2450 data->str[data->len] = '\0';
2452 if(buf[1]!='0' && prec-data->len+1>0)
2453 memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1);
2455 return 1;
2457 #undef I10_OUTPUT_MAX_PREC
2459 /*********************************************************************
2460 * memcmp (MSVCRT.@)
2462 int __cdecl memcmp(const void *ptr1, const void *ptr2, size_t n)
2464 const unsigned char *p1, *p2;
2466 for (p1 = ptr1, p2 = ptr2; n; n--, p1++, p2++)
2468 if (*p1 < *p2) return -1;
2469 if (*p1 > *p2) return 1;
2471 return 0;
2474 #if defined(__i386__) || defined(__x86_64__)
2476 #ifdef __i386__
2478 #define DEST_REG "%edi"
2479 #define SRC_REG "%esi"
2480 #define LEN_REG "%ecx"
2481 #define TMP_REG "%edx"
2483 #define MEMMOVE_INIT \
2484 "pushl " SRC_REG "\n\t" \
2485 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
2486 "pushl " DEST_REG "\n\t" \
2487 __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \
2488 "movl 12(%esp), " DEST_REG "\n\t" \
2489 "movl 16(%esp), " SRC_REG "\n\t" \
2490 "movl 20(%esp), " LEN_REG "\n\t"
2492 #define MEMMOVE_CLEANUP \
2493 "movl 12(%esp), %eax\n\t" \
2494 "popl " DEST_REG "\n\t" \
2495 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") \
2496 "popl " SRC_REG "\n\t" \
2497 __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t")
2499 #else
2501 #define DEST_REG "%rdi"
2502 #define SRC_REG "%rsi"
2503 #define LEN_REG "%r8"
2504 #define TMP_REG "%r9"
2506 #define MEMMOVE_INIT \
2507 "pushq " SRC_REG "\n\t" \
2508 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") \
2509 "pushq " DEST_REG "\n\t" \
2510 __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") \
2511 "movq %rcx, " DEST_REG "\n\t" \
2512 "movq %rdx, " SRC_REG "\n\t"
2514 #define MEMMOVE_CLEANUP \
2515 "movq %rcx, %rax\n\t" \
2516 "popq " DEST_REG "\n\t" \
2517 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") \
2518 "popq " SRC_REG "\n\t" \
2519 __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t")
2520 #endif
2522 void * __cdecl sse2_memmove(void *dst, const void *src, size_t n);
2523 __ASM_GLOBAL_FUNC( sse2_memmove,
2524 MEMMOVE_INIT
2525 "mov " DEST_REG ", " TMP_REG "\n\t" /* check copying direction */
2526 "sub " SRC_REG ", " TMP_REG "\n\t"
2527 "cmp " LEN_REG ", " TMP_REG "\n\t"
2528 "jb copy_bwd\n\t"
2529 /* copy forwards */
2530 "cmp $4, " LEN_REG "\n\t" /* 4-bytes align */
2531 "jb copy_fwd3\n\t"
2532 "mov " DEST_REG ", " TMP_REG "\n\t"
2533 "shr $1, " TMP_REG "\n\t"
2534 "jnc 1f\n\t"
2535 "movsb\n\t"
2536 "dec " LEN_REG "\n\t"
2537 "inc " TMP_REG "\n\t"
2538 "1:\n\t"
2539 "shr $1, " TMP_REG "\n\t"
2540 "jnc 1f\n\t"
2541 "movsw\n\t"
2542 "sub $2, " LEN_REG "\n\t"
2543 "inc " TMP_REG "\n\t"
2544 "1:\n\t" /* 16-bytes align */
2545 "cmp $16, " LEN_REG "\n\t"
2546 "jb copy_fwd15\n\t"
2547 "shr $1, " TMP_REG "\n\t"
2548 "jnc 1f\n\t"
2549 "movsl\n\t"
2550 "sub $4, " LEN_REG "\n\t"
2551 "inc " TMP_REG "\n\t"
2552 "1:\n\t"
2553 "shr $1, " TMP_REG "\n\t"
2554 "jnc 1f\n\t"
2555 "movsl\n\t"
2556 "movsl\n\t"
2557 "sub $8, " LEN_REG "\n\t"
2558 "1:\n\t"
2559 "cmp $64, " LEN_REG "\n\t"
2560 "jb copy_fwd63\n\t"
2561 "1:\n\t" /* copy 64-bytes blocks in loop, dest 16-bytes aligned */
2562 "movdqu 0x00(" SRC_REG "), %xmm0\n\t"
2563 "movdqu 0x10(" SRC_REG "), %xmm1\n\t"
2564 "movdqu 0x20(" SRC_REG "), %xmm2\n\t"
2565 "movdqu 0x30(" SRC_REG "), %xmm3\n\t"
2566 "movdqa %xmm0, 0x00(" DEST_REG ")\n\t"
2567 "movdqa %xmm1, 0x10(" DEST_REG ")\n\t"
2568 "movdqa %xmm2, 0x20(" DEST_REG ")\n\t"
2569 "movdqa %xmm3, 0x30(" DEST_REG ")\n\t"
2570 "add $64, " SRC_REG "\n\t"
2571 "add $64, " DEST_REG "\n\t"
2572 "sub $64, " LEN_REG "\n\t"
2573 "cmp $64, " LEN_REG "\n\t"
2574 "jae 1b\n\t"
2575 "copy_fwd63:\n\t" /* copy last 63 bytes, dest 16-bytes aligned */
2576 "mov " LEN_REG ", " TMP_REG "\n\t"
2577 "and $15, " LEN_REG "\n\t"
2578 "shr $5, " TMP_REG "\n\t"
2579 "jnc 1f\n\t"
2580 "movdqu 0(" SRC_REG "), %xmm0\n\t"
2581 "movdqa %xmm0, 0(" DEST_REG ")\n\t"
2582 "add $16, " SRC_REG "\n\t"
2583 "add $16, " DEST_REG "\n\t"
2584 "1:\n\t"
2585 "shr $1, " TMP_REG "\n\t"
2586 "jnc copy_fwd15\n\t"
2587 "movdqu 0x00(" SRC_REG "), %xmm0\n\t"
2588 "movdqu 0x10(" SRC_REG "), %xmm1\n\t"
2589 "movdqa %xmm0, 0x00(" DEST_REG ")\n\t"
2590 "movdqa %xmm1, 0x10(" DEST_REG ")\n\t"
2591 "add $32, " SRC_REG "\n\t"
2592 "add $32, " DEST_REG "\n\t"
2593 "copy_fwd15:\n\t" /* copy last 15 bytes, dest 4-bytes aligned */
2594 "mov " LEN_REG ", " TMP_REG "\n\t"
2595 "and $3, " LEN_REG "\n\t"
2596 "shr $3, " TMP_REG "\n\t"
2597 "jnc 1f\n\t"
2598 "movsl\n\t"
2599 "1:\n\t"
2600 "shr $1, " TMP_REG "\n\t"
2601 "jnc copy_fwd3\n\t"
2602 "movsl\n\t"
2603 "movsl\n\t"
2604 "copy_fwd3:\n\t" /* copy last 3 bytes */
2605 "shr $1, " LEN_REG "\n\t"
2606 "jnc 1f\n\t"
2607 "movsb\n\t"
2608 "1:\n\t"
2609 "shr $1, " LEN_REG "\n\t"
2610 "jnc 1f\n\t"
2611 "movsw\n\t"
2612 "1:\n\t"
2613 MEMMOVE_CLEANUP
2614 "ret\n\t"
2615 "copy_bwd:\n\t"
2616 "lea (" DEST_REG ", " LEN_REG "), " DEST_REG "\n\t"
2617 "lea (" SRC_REG ", " LEN_REG "), " SRC_REG "\n\t"
2618 "cmp $4, " LEN_REG "\n\t" /* 4-bytes align */
2619 "jb copy_bwd3\n\t"
2620 "mov " DEST_REG ", " TMP_REG "\n\t"
2621 "shr $1, " TMP_REG "\n\t"
2622 "jnc 1f\n\t"
2623 "dec " SRC_REG "\n\t"
2624 "dec " DEST_REG "\n\t"
2625 "movb (" SRC_REG "), %al\n\t"
2626 "movb %al, (" DEST_REG ")\n\t"
2627 "dec " LEN_REG "\n\t"
2628 "1:\n\t"
2629 "shr $1, " TMP_REG "\n\t"
2630 "jnc 1f\n\t"
2631 "sub $2, " SRC_REG "\n\t"
2632 "sub $2, " DEST_REG "\n\t"
2633 "movw (" SRC_REG "), %ax\n\t"
2634 "movw %ax, (" DEST_REG ")\n\t"
2635 "sub $2, " LEN_REG "\n\t"
2636 "1:\n\t" /* 16-bytes align */
2637 "cmp $16, " LEN_REG "\n\t"
2638 "jb copy_bwd15\n\t"
2639 "shr $1, " TMP_REG "\n\t"
2640 "jnc 1f\n\t"
2641 "sub $4, " SRC_REG "\n\t"
2642 "sub $4, " DEST_REG "\n\t"
2643 "movl (" SRC_REG "), %eax\n\t"
2644 "movl %eax, (" DEST_REG ")\n\t"
2645 "sub $4, " LEN_REG "\n\t"
2646 "1:\n\t"
2647 "shr $1, " TMP_REG "\n\t"
2648 "jnc 1f\n\t"
2649 "sub $8, " SRC_REG "\n\t"
2650 "sub $8, " DEST_REG "\n\t"
2651 "movl 4(" SRC_REG "), %eax\n\t"
2652 "movl %eax, 4(" DEST_REG ")\n\t"
2653 "movl (" SRC_REG "), %eax\n\t"
2654 "movl %eax, (" DEST_REG ")\n\t"
2655 "sub $8, " LEN_REG "\n\t"
2656 "1:\n\t"
2657 "cmp $64, " LEN_REG "\n\t"
2658 "jb copy_bwd63\n\t"
2659 "1:\n\t" /* copy 64-bytes blocks in loop, dest 16-bytes aligned */
2660 "sub $64, " SRC_REG "\n\t"
2661 "sub $64, " DEST_REG "\n\t"
2662 "movdqu 0x00(" SRC_REG "), %xmm0\n\t"
2663 "movdqu 0x10(" SRC_REG "), %xmm1\n\t"
2664 "movdqu 0x20(" SRC_REG "), %xmm2\n\t"
2665 "movdqu 0x30(" SRC_REG "), %xmm3\n\t"
2666 "movdqa %xmm0, 0x00(" DEST_REG ")\n\t"
2667 "movdqa %xmm1, 0x10(" DEST_REG ")\n\t"
2668 "movdqa %xmm2, 0x20(" DEST_REG ")\n\t"
2669 "movdqa %xmm3, 0x30(" DEST_REG ")\n\t"
2670 "sub $64, " LEN_REG "\n\t"
2671 "cmp $64, " LEN_REG "\n\t"
2672 "jae 1b\n\t"
2673 "copy_bwd63:\n\t" /* copy last 63 bytes, dest 16-bytes aligned */
2674 "mov " LEN_REG ", " TMP_REG "\n\t"
2675 "and $15, " LEN_REG "\n\t"
2676 "shr $5, " TMP_REG "\n\t"
2677 "jnc 1f\n\t"
2678 "sub $16, " SRC_REG "\n\t"
2679 "sub $16, " DEST_REG "\n\t"
2680 "movdqu (" SRC_REG "), %xmm0\n\t"
2681 "movdqa %xmm0, (" DEST_REG ")\n\t"
2682 "1:\n\t"
2683 "shr $1, " TMP_REG "\n\t"
2684 "jnc copy_bwd15\n\t"
2685 "sub $32, " SRC_REG "\n\t"
2686 "sub $32, " DEST_REG "\n\t"
2687 "movdqu 0x00(" SRC_REG "), %xmm0\n\t"
2688 "movdqu 0x10(" SRC_REG "), %xmm1\n\t"
2689 "movdqa %xmm0, 0x00(" DEST_REG ")\n\t"
2690 "movdqa %xmm1, 0x10(" DEST_REG ")\n\t"
2691 "copy_bwd15:\n\t" /* copy last 15 bytes, dest 4-bytes aligned */
2692 "mov " LEN_REG ", " TMP_REG "\n\t"
2693 "and $3, " LEN_REG "\n\t"
2694 "shr $3, " TMP_REG "\n\t"
2695 "jnc 1f\n\t"
2696 "sub $4, " SRC_REG "\n\t"
2697 "sub $4, " DEST_REG "\n\t"
2698 "movl (" SRC_REG "), %eax\n\t"
2699 "movl %eax, (" DEST_REG ")\n\t"
2700 "1:\n\t"
2701 "shr $1, " TMP_REG "\n\t"
2702 "jnc copy_bwd3\n\t"
2703 "sub $8, " SRC_REG "\n\t"
2704 "sub $8, " DEST_REG "\n\t"
2705 "movl 4(" SRC_REG "), %eax\n\t"
2706 "movl %eax, 4(" DEST_REG ")\n\t"
2707 "movl (" SRC_REG "), %eax\n\t"
2708 "movl %eax, (" DEST_REG ")\n\t"
2709 "copy_bwd3:\n\t" /* copy last 3 bytes */
2710 "shr $1, " LEN_REG "\n\t"
2711 "jnc 1f\n\t"
2712 "dec " SRC_REG "\n\t"
2713 "dec " DEST_REG "\n\t"
2714 "movb (" SRC_REG "), %al\n\t"
2715 "movb %al, (" DEST_REG ")\n\t"
2716 "1:\n\t"
2717 "shr $1, " LEN_REG "\n\t"
2718 "jnc 1f\n\t"
2719 "movw -2(" SRC_REG "), %ax\n\t"
2720 "movw %ax, -2(" DEST_REG ")\n\t"
2721 "1:\n\t"
2722 MEMMOVE_CLEANUP
2723 "ret" )
2725 #endif
2727 /*********************************************************************
2728 * memmove (MSVCRT.@)
2730 #ifdef WORDS_BIGENDIAN
2731 # define MERGE(w1, sh1, w2, sh2) ((w1 << sh1) | (w2 >> sh2))
2732 #else
2733 # define MERGE(w1, sh1, w2, sh2) ((w1 >> sh1) | (w2 << sh2))
2734 #endif
2735 void * __cdecl memmove(void *dst, const void *src, size_t n)
2737 #ifdef __x86_64__
2738 return sse2_memmove(dst, src, n);
2739 #else
2740 unsigned char *d = dst;
2741 const unsigned char *s = src;
2742 int sh1;
2744 #ifdef __i386__
2745 if (sse2_supported)
2746 return sse2_memmove(dst, src, n);
2747 #endif
2749 if (!n) return dst;
2751 if ((size_t)dst - (size_t)src >= n)
2753 for (; (size_t)d % sizeof(size_t) && n; n--) *d++ = *s++;
2755 sh1 = 8 * ((size_t)s % sizeof(size_t));
2756 if (!sh1)
2758 while (n >= sizeof(size_t))
2760 *(size_t*)d = *(size_t*)s;
2761 s += sizeof(size_t);
2762 d += sizeof(size_t);
2763 n -= sizeof(size_t);
2766 else if (n >= 2 * sizeof(size_t))
2768 int sh2 = 8 * sizeof(size_t) - sh1;
2769 size_t x, y;
2771 s -= sh1 / 8;
2772 x = *(size_t*)s;
2775 s += sizeof(size_t);
2776 y = *(size_t*)s;
2777 *(size_t*)d = MERGE(x, sh1, y, sh2);
2778 d += sizeof(size_t);
2780 s += sizeof(size_t);
2781 x = *(size_t*)s;
2782 *(size_t*)d = MERGE(y, sh1, x, sh2);
2783 d += sizeof(size_t);
2785 n -= 2 * sizeof(size_t);
2786 } while (n >= 2 * sizeof(size_t));
2787 s += sh1 / 8;
2789 while (n--) *d++ = *s++;
2790 return dst;
2792 else
2794 d += n;
2795 s += n;
2797 for (; (size_t)d % sizeof(size_t) && n; n--) *--d = *--s;
2799 sh1 = 8 * ((size_t)s % sizeof(size_t));
2800 if (!sh1)
2802 while (n >= sizeof(size_t))
2804 s -= sizeof(size_t);
2805 d -= sizeof(size_t);
2806 *(size_t*)d = *(size_t*)s;
2807 n -= sizeof(size_t);
2810 else if (n >= 2 * sizeof(size_t))
2812 int sh2 = 8 * sizeof(size_t) - sh1;
2813 size_t x, y;
2815 s -= sh1 / 8;
2816 x = *(size_t*)s;
2819 s -= sizeof(size_t);
2820 y = *(size_t*)s;
2821 d -= sizeof(size_t);
2822 *(size_t*)d = MERGE(y, sh1, x, sh2);
2824 s -= sizeof(size_t);
2825 x = *(size_t*)s;
2826 d -= sizeof(size_t);
2827 *(size_t*)d = MERGE(x, sh1, y, sh2);
2829 n -= 2 * sizeof(size_t);
2830 } while (n >= 2 * sizeof(size_t));
2831 s += sh1 / 8;
2833 while (n--) *--d = *--s;
2835 return dst;
2836 #endif
2838 #undef MERGE
2840 /*********************************************************************
2841 * memcpy (MSVCRT.@)
2843 void * __cdecl memcpy(void *dst, const void *src, size_t n)
2845 return memmove(dst, src, n);
2848 /*********************************************************************
2849 * memset (MSVCRT.@)
2851 void* __cdecl memset(void *dst, int c, size_t n)
2853 volatile unsigned char *d = dst; /* avoid gcc optimizations */
2854 while (n--) *d++ = c;
2855 return dst;
2858 /*********************************************************************
2859 * strchr (MSVCRT.@)
2861 char* __cdecl strchr(const char *str, int c)
2865 if (*str == (char)c) return (char*)str;
2866 } while (*str++);
2867 return NULL;
2870 /*********************************************************************
2871 * strrchr (MSVCRT.@)
2873 char* __cdecl strrchr(const char *str, int c)
2875 char *ret = NULL;
2876 do { if (*str == (char)c) ret = (char*)str; } while (*str++);
2877 return ret;
2880 /*********************************************************************
2881 * memchr (MSVCRT.@)
2883 void* __cdecl memchr(const void *ptr, int c, size_t n)
2885 const unsigned char *p = ptr;
2887 for (p = ptr; n; n--, p++) if (*p == (unsigned char)c) return (void *)(ULONG_PTR)p;
2888 return NULL;
2891 /*********************************************************************
2892 * strcmp (MSVCRT.@)
2894 int __cdecl strcmp(const char *str1, const char *str2)
2896 while (*str1 && *str1 == *str2) { str1++; str2++; }
2897 if ((unsigned char)*str1 > (unsigned char)*str2) return 1;
2898 if ((unsigned char)*str1 < (unsigned char)*str2) return -1;
2899 return 0;
2902 /*********************************************************************
2903 * strncmp (MSVCRT.@)
2905 int __cdecl strncmp(const char *str1, const char *str2, size_t len)
2907 if (!len) return 0;
2908 while (--len && *str1 && *str1 == *str2) { str1++; str2++; }
2909 return (unsigned char)*str1 - (unsigned char)*str2;
2912 /*********************************************************************
2913 * _strnicmp_l (MSVCRT.@)
2915 int __cdecl _strnicmp_l(const char *s1, const char *s2,
2916 size_t count, _locale_t locale)
2918 pthreadlocinfo locinfo;
2919 int c1, c2;
2921 if(s1==NULL || s2==NULL)
2922 return _NLSCMPERROR;
2924 if(!count)
2925 return 0;
2927 if(!locale)
2928 locinfo = get_locinfo();
2929 else
2930 locinfo = locale->locinfo;
2932 if(!locinfo->lc_handle[LC_CTYPE])
2934 do {
2935 if ((c1 = *s1++) >= 'A' && c1 <= 'Z')
2936 c1 -= 'A' - 'a';
2937 if ((c2 = *s2++) >= 'A' && c2 <= 'Z')
2938 c2 -= 'A' - 'a';
2939 }while(--count && c1 && c1==c2);
2941 return c1-c2;
2944 do {
2945 c1 = _tolower_l((unsigned char)*s1++, locale);
2946 c2 = _tolower_l((unsigned char)*s2++, locale);
2947 }while(--count && c1 && c1==c2);
2949 return c1-c2;
2952 /*********************************************************************
2953 * _stricmp_l (MSVCRT.@)
2955 int __cdecl _stricmp_l(const char *s1, const char *s2, _locale_t locale)
2957 return _strnicmp_l(s1, s2, -1, locale);
2960 /*********************************************************************
2961 * _strnicmp (MSVCRT.@)
2963 int __cdecl _strnicmp(const char *s1, const char *s2, size_t count)
2965 return _strnicmp_l(s1, s2, count, NULL);
2968 /*********************************************************************
2969 * _stricmp (MSVCRT.@)
2971 int __cdecl _stricmp(const char *s1, const char *s2)
2973 return _strnicmp_l(s1, s2, -1, NULL);
2976 /*********************************************************************
2977 * strstr (MSVCRT.@)
2979 char* __cdecl strstr(const char *haystack, const char *needle)
2981 size_t i, j, len, needle_len, lps_len;
2982 BYTE lps[256];
2984 needle_len = strlen(needle);
2985 if (!needle_len) return (char*)haystack;
2986 lps_len = needle_len > ARRAY_SIZE(lps) ? ARRAY_SIZE(lps) : needle_len;
2988 lps[0] = 0;
2989 len = 0;
2990 i = 1;
2991 while (i < lps_len)
2993 if (needle[i] == needle[len]) lps[i++] = ++len;
2994 else if (len) len = lps[len-1];
2995 else lps[i++] = 0;
2998 i = j = 0;
2999 while (haystack[i])
3001 while (j < lps_len && haystack[i] && haystack[i] == needle[j])
3003 i++;
3004 j++;
3007 if (j == needle_len) return (char*)haystack + i - j;
3008 else if (j)
3010 if (j == ARRAY_SIZE(lps) && !strncmp(haystack + i, needle + j, needle_len - j))
3011 return (char*)haystack + i - j;
3012 j = lps[j-1];
3014 else if (haystack[i]) i++;
3016 return NULL;
3019 /*********************************************************************
3020 * _memicmp_l (MSVCRT.@)
3022 int __cdecl _memicmp_l(const void *v1, const void *v2, size_t len, _locale_t locale)
3024 const char *s1 = v1, *s2 = v2;
3025 int ret = 0;
3027 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
3028 if (!s1 || !s2)
3030 if (len)
3031 MSVCRT_INVALID_PMT(NULL, EINVAL);
3032 return len ? _NLSCMPERROR : 0;
3034 #endif
3036 while (len--)
3038 if ((ret = _tolower_l(*s1, locale) - _tolower_l(*s2, locale)))
3039 break;
3040 s1++;
3041 s2++;
3043 return ret;
3046 /*********************************************************************
3047 * _memicmp (MSVCRT.@)
3049 int __cdecl _memicmp(const void *s1, const void *s2, size_t len)
3051 return _memicmp_l(s1, s2, len, NULL);
3054 /*********************************************************************
3055 * strcspn (MSVCRT.@)
3057 size_t __cdecl strcspn(const char *str, const char *reject)
3059 BOOL rejects[256];
3060 const char *p;
3062 memset(rejects, 0, sizeof(rejects));
3064 p = reject;
3065 while(*p)
3067 rejects[(unsigned char)*p] = TRUE;
3068 p++;
3071 p = str;
3072 while(*p && !rejects[(unsigned char)*p]) p++;
3073 return p - str;
3076 /*********************************************************************
3077 * strpbrk (MSVCRT.@)
3079 char* __cdecl strpbrk(const char *str, const char *accept)
3081 for (; *str; str++) if (strchr( accept, *str )) return (char*)str;
3082 return NULL;
3085 /*********************************************************************
3086 * __strncnt (MSVCRT.@)
3088 size_t __cdecl __strncnt(const char *str, size_t size)
3090 size_t ret = 0;
3092 #if _MSVCR_VER >= 140
3093 while (*str++ && size--)
3094 #else
3095 while (size-- && *str++)
3096 #endif
3098 ret++;
3101 return ret;
3105 #ifdef _CRTDLL
3106 /*********************************************************************
3107 * _strdec (CRTDLL.@)
3109 char * CDECL _strdec(const char *str1, const char *str2)
3111 return (char *)(str2 - 1);
3114 /*********************************************************************
3115 * _strinc (CRTDLL.@)
3117 char * CDECL _strinc(const char *str)
3119 return (char *)(str + 1);
3122 /*********************************************************************
3123 * _strnextc (CRTDLL.@)
3125 unsigned int CDECL _strnextc(const char *str)
3127 return (unsigned char)str[0];
3130 /*********************************************************************
3131 * _strninc (CRTDLL.@)
3133 char * CDECL _strninc(const char *str, size_t len)
3135 return (char *)(str + len);
3138 /*********************************************************************
3139 * _strspnp (CRTDLL.@)
3141 char * CDECL _strspnp( const char *str1, const char *str2)
3143 str1 += strspn( str1, str2 );
3144 return *str1 ? (char*)str1 : NULL;
3146 #endif