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
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
39 /*********************************************************************
43 char* CDECL
_strdup(const char* str
)
47 char * ret
= malloc(strlen(str
)+1);
48 if (ret
) strcpy( ret
, str
);
54 /*********************************************************************
55 * _strlwr_s_l (MSVCRT.@)
57 int CDECL
_strlwr_s_l(char *str
, size_t len
, _locale_t locale
)
59 pthreadlocinfo locinfo
;
82 locinfo
= get_locinfo();
84 locinfo
= locale
->locinfo
;
86 if(!locinfo
->lc_handle
[LC_CTYPE
])
90 if (*str
>= 'A' && *str
<= 'Z')
99 *str
= _tolower_l((unsigned char)*str
, locale
);
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
);
124 /*********************************************************************
127 char* CDECL
_strlwr(char *str
)
129 _strlwr_s_l(str
, -1, NULL
);
133 /*********************************************************************
134 * _strupr_s_l (MSVCRT.@)
136 int CDECL
_strupr_s_l(char *str
, size_t len
, _locale_t locale
)
138 pthreadlocinfo locinfo
;
161 locinfo
= get_locinfo();
163 locinfo
= locale
->locinfo
;
165 if(!locinfo
->lc_handle
[LC_CTYPE
])
169 if (*str
>= 'a' && *str
<= 'z')
178 *str
= _toupper_l((unsigned char)*str
, locale
);
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
);
203 /*********************************************************************
206 char* CDECL
_strupr(char *str
)
208 _strupr_s_l(str
, -1, NULL
);
212 /*********************************************************************
213 * _strnset_s (MSVCRT.@)
215 int CDECL
_strnset_s(char *str
, size_t size
, int c
, size_t count
)
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;
228 if(!str
[i
]) return 0;
231 _invalid_parameter(NULL
, NULL
, NULL
, 0, 0);
236 /*********************************************************************
237 * _strnset (MSVCRT.@)
239 char* CDECL
_strnset(char* str
, int value
, size_t len
)
242 while (*str
&& len
--)
247 /*********************************************************************
250 char* CDECL
_strrev(char* str
)
256 for (p1
= str
, p2
= str
+ strlen(str
) - 1; p2
> p1
; ++p1
, --p2
)
266 /*********************************************************************
269 char* CDECL
_strset(char* str
, int value
)
278 /*********************************************************************
281 char * CDECL
strtok( char *str
, const char *delim
)
283 thread_data_t
*data
= msvcrt_get_thread_data();
287 if (!(str
= data
->strtok_next
)) return NULL
;
289 while (*str
&& strchr( delim
, *str
)) str
++;
292 data
->strtok_next
= str
;
296 while (*str
&& !strchr( delim
, *str
)) str
++;
297 if (*str
) *str
++ = 0;
298 data
->strtok_next
= str
;
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
;
314 while(*str
&& strchr(delim
, *str
))
323 while(**ctx
&& !strchr(delim
, **ctx
))
331 /*********************************************************************
334 void CDECL
_swab(char* src
, char* dst
, int len
)
338 len
= (unsigned)len
>> 1;
350 static struct fpnum
fpnum(int sign
, int exp
, ULONGLONG m
, enum fpmod mod
)
361 int fpnum_double(struct fpnum
*fp
, double *d
)
365 if (fp
->mod
== FP_VAL_INFINITY
)
367 *d
= fp
->sign
* INFINITY
;
371 if (fp
->mod
== FP_VAL_NAN
)
375 bits
&= ~((ULONGLONG
)1 << (MANT_BITS
+ EXP_BITS
- 1));
376 *d
= *(double*)&bits
;
380 TRACE("%c %#I64x *2^%d (round %d)\n", fp
->sign
== -1 ? '-' : '+',
381 fp
->m
, fp
->exp
, fp
->mod
);
388 /* make sure that we don't overflow modifying exponent */
389 if (fp
->exp
> 1<<EXP_BITS
)
391 *d
= fp
->sign
* INFINITY
;
394 if (fp
->exp
< -(1<<EXP_BITS
))
399 fp
->exp
+= MANT_BITS
- 1;
401 /* normalize mantissa */
402 while(fp
->m
< (ULONGLONG
)1 << (MANT_BITS
-1))
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
;
418 fp
->exp
+= (1 << (EXP_BITS
-1)) - 1;
420 /* handle subnormals */
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
;
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
;
438 if (fp
->mod
== FP_ROUND_UP
|| (fp
->mod
== FP_ROUND_EVEN
&& fp
->m
& 1))
442 /* handle subnormal that falls into regular range due to rounding */
443 if (fp
->m
== (ULONGLONG
)1 << (MANT_BITS
- 1))
447 else if (fp
->m
>= (ULONGLONG
)1 << MANT_BITS
)
454 if (fp
->exp
>= (1<<EXP_BITS
)-1)
456 *d
= fp
->sign
* INFINITY
;
459 if (!fp
->m
|| fp
->exp
< 0)
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
;
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
)
482 d
->x80
[1] = 0x80000000;
483 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
485 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
489 if (fp
->mod
== FP_VAL_NAN
)
493 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
495 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
499 TRACE("%c %#I64x *2^%d (round %d)\n", fp
->sign
== -1 ? '-' : '+',
500 fp
->m
, fp
->exp
, fp
->mod
);
507 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
511 /* make sure that we don't overflow modifying exponent */
512 if (fp
->exp
> 1<<LDBL_EXP_BITS
)
515 d
->x80
[1] = 0x80000000;
516 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
518 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
521 if (fp
->exp
< -(1<<LDBL_EXP_BITS
))
527 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
530 fp
->exp
+= LDBL_MANT_BITS
- 1;
532 /* normalize mantissa */
533 while(fp
->m
< (ULONGLONG
)1 << (LDBL_MANT_BITS
-1))
538 fp
->exp
+= (1 << (LDBL_EXP_BITS
-1)) - 1;
540 /* handle subnormals */
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
;
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
;
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);
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)
577 d
->x80
[1] = 0x80000000;
578 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
580 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
583 if (!fp
->m
|| fp
->exp
< 0)
589 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
594 d
->x80
[1] = fp
->m
>> 32;
597 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
601 #if _MSVCR_VER >= 140
603 static inline int hex2int(char c
)
605 if (c
>= '0' && c
<= '9')
607 else if (c
>= 'a' && c
<= 'f')
609 else if (c
>= 'A' && c
<= 'F')
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
;
624 while(m
< UI64_MAX
/16)
627 if (val
== -1) break;
636 if (val
== -1) break;
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
)
653 else if (!found_digit
)
655 if(nch
!=WEOF
) unget(ctx
);
657 return fpnum(0, 0, 0, 0);
660 while(m
<= UI64_MAX
/16)
663 if (val
== -1) break;
673 if (val
== -1) break;
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
;
686 if (nch
!= WEOF
) unget(ctx
);
687 if (found_dp
) unget(ctx
);
689 return fpnum(0, 0, 0, 0);
692 if(nch
=='p' || nch
=='P') {
693 BOOL found_sign
= FALSE
;
701 } else if(nch
== '+') {
705 if(nch
>='0' && nch
<='9') {
706 while(nch
>='0' && nch
<='9') {
707 if(e
>INT_MAX
/10 || e
*10>INT_MAX
-nch
+'0')
713 if((nch
!=WEOF
) && (nch
< '0' || nch
> '9')) unget(ctx
);
716 if(e
<0 && exp
<INT_MIN
-e
) exp
= INT_MIN
;
717 else if(e
>0 && exp
>INT_MAX
-e
) exp
= INT_MAX
;
720 if(nch
!= WEOF
) unget(ctx
);
721 if(found_sign
) unget(ctx
);
726 return fpnum(sign
, exp
, m
, round
);
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)];
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
;
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
;
765 } else if(nch
== '+') {
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]))
775 while(str_match
&& nch
!= WEOF
&&
776 (nch
== str_match
[matched
] || nch
== _toupper(str_match
[matched
]))) {
782 if(matched
>= 8) keep
= 8;
783 else if(matched
>= 3) keep
= 3;
784 if(nch
!= WEOF
) unget(ctx
);
785 for (; matched
> keep
; matched
--) {
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
) {
797 return fpnum(0, 0, 0, 0);
803 if(nch
== 'x' || nch
== 'X')
804 return fpnum_parse16(get
, unget
, ctx
, sign
, locinfo
);
816 while(nch
>='0' && nch
<='9') {
818 if(limb_digits
== LIMB_DIGITS
) {
819 if(bnum_idx(b
, b
->b
-1) == bnum_idx(b
, b
->e
)) break;
822 b
->data
[bnum_idx(b
, b
->b
)] = 0;
827 b
->data
[bnum_idx(b
, b
->b
)] = b
->data
[bnum_idx(b
, b
->b
)] * 10 + nch
- '0';
832 while(nch
>='0' && nch
<='9') {
833 if(nch
!= '0') b
->data
[bnum_idx(b
, b
->b
)] |= 1;
838 if(nch
== *locinfo
->lconv
->decimal_point
) {
843 /* skip leading '0' */
844 if(nch
=='0' && !limb_digits
&& !b
->b
) {
852 while(nch
>='0' && nch
<='9') {
854 if(limb_digits
== LIMB_DIGITS
) {
855 if(bnum_idx(b
, b
->b
-1) == bnum_idx(b
, b
->e
)) break;
858 b
->data
[bnum_idx(b
, b
->b
)] = 0;
863 b
->data
[bnum_idx(b
, b
->b
)] = b
->data
[bnum_idx(b
, b
->b
)] * 10 + nch
- '0';
867 while(nch
>='0' && nch
<='9') {
868 if(nch
!= '0') b
->data
[bnum_idx(b
, b
->b
)] |= 1;
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') {
887 } else if(nch
== '+') {
894 if(nch
>='0' && nch
<='9') {
895 while(nch
>='0' && nch
<='9') {
896 if(e
>INT_MAX
/10 || e
*10>INT_MAX
-nch
+'0')
902 if(nch
!= WEOF
) unget(ctx
);
905 if(e
<0 && dp
<INT_MIN
-e
) dp
= INT_MIN
;
906 else if(e
>0 && dp
>INT_MAX
-e
) dp
= INT_MAX
;
909 if(nch
!= WEOF
) unget(ctx
);
910 if(found_sign
) unget(ctx
);
913 } else if(nch
!= WEOF
) {
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 */
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
;
947 while(dp
<= 2*LIMB_DIGITS
) {
948 if(bnum_lshift(b
, 29)) dp
+= LIMB_DIGITS
;
951 /* Make sure most significant mantissa bit will be set */
952 while(b
->data
[bnum_idx(b
, b
->e
-1)] <= 9) {
956 while(!bnum_to_mant(b
, &m
)) {
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
)
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
);
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
;
1002 static void strtod_str_unget(void *ctx
)
1004 const char **p
= ctx
;
1008 static inline double strtod_helper(const char *str
, char **end
, _locale_t locale
, int *perr
)
1010 pthreadlocinfo locinfo
;
1011 const char *beg
, *p
;
1016 if (perr
) *perr
= 0;
1021 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) {
1022 if (end
) *end
= NULL
;
1027 locinfo
= get_locinfo();
1029 locinfo
= locale
->locinfo
;
1032 while(_isspace_l((unsigned char)*p
, locale
))
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
;
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 /*********************************************************************
1056 double CDECL
strtod( const char *str
, char **end
)
1058 return _strtod_l( str
, end
, NULL
);
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
)) {
1071 if (!f
|| !isfinite(f
))
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 /*********************************************************************
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
)
1111 d
= strtod_helper(str
, NULL
, locale
, &err
);
1115 if((d
!=0 || err
) && value
->f
>-FLT_MIN
&& value
->f
<FLT_MIN
)
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
)
1135 value
->x
= strtod_helper(str
, NULL
, locale
, &err
);
1138 if((value
->x
!=0 || err
) && value
->x
>-DBL_MIN
&& value
->x
<DBL_MIN
)
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
;
1159 locinfo
= get_locinfo();
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
;
1185 locinfo
= get_locinfo();
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
;
1211 locinfo
= get_locinfo();
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
;
1238 locinfo
= get_locinfo();
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
)
1264 for(i
=0; i
<len
; i
++)
1265 if((dst
[i
] = src
[i
]) == '\0') break;
1267 while (i
< len
) dst
[i
++] = 0;
1272 /******************************************************************
1273 * strncpy_s (MSVCRT.@)
1275 int __cdecl
strncpy_s( char *dst
, size_t elem
, const char *src
, size_t count
)
1278 BOOL truncate
= (count
== _TRUNCATE
);
1280 TRACE("(%p %Iu %s %Iu)\n", dst
, elem
, debugstr_a(src
), count
);
1284 if (dst
&& elem
) *dst
= 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
))
1296 while (elem
&& count
&& *src
)
1302 if (!elem
&& truncate
)
1316 /*********************************************************************
1319 char* CDECL
strcpy(char *dst
, const char *src
)
1322 while ((*dst
++ = *src
++));
1326 /*********************************************************************
1327 * strcpy_s (MSVCRT.@)
1329 int CDECL
strcpy_s( char* dst
, size_t elem
, const char* src
)
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
))
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
);
1349 /*********************************************************************
1350 * strcat_s (MSVCRT.@)
1352 int CDECL
strcat_s( char* dst
, size_t elem
, const char* src
)
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
))
1363 for(i
= 0; i
< elem
; i
++)
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
);
1379 /*********************************************************************
1382 char* __cdecl
strcat( char *dst
, const char *src
)
1386 while ((*d
++ = *src
++));
1390 /*********************************************************************
1391 * strncat_s (MSVCRT.@)
1393 int CDECL
strncat_s( char* dst
, size_t elem
, const char* src
, size_t count
)
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
))
1407 for (i
= 0; i
< elem
; i
++) if (!dst
[i
]) break;
1411 MSVCRT_INVALID_PMT("dst[elem] is not NULL terminated\n", EINVAL
);
1416 for (j
= 0; (j
+ i
) < elem
; j
++)
1418 if(count
== _TRUNCATE
&& j
+ i
== elem
- 1)
1423 if(j
== count
|| (dst
[j
+ i
] = src
[j
]) == '\0')
1430 MSVCRT_INVALID_PMT("dst[elem] is too small", ERANGE
);
1435 /*********************************************************************
1436 * strncat (MSVCRT.@)
1438 char* __cdecl
strncat(char *dst
, const char *src
, size_t len
)
1442 for ( ; len
&& *src
; d
++, src
++, len
--) *d
= *src
;
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
;
1456 if(!MSVCRT_CHECK_PMT(src
)) return INT_MAX
;
1457 if(!MSVCRT_CHECK_PMT(dest
|| !len
)) return INT_MAX
;
1460 FIXME("len > INT_MAX not supported\n");
1465 locinfo
= get_locinfo();
1467 locinfo
= locale
->locinfo
;
1469 if(!locinfo
->lc_handle
[LC_COLLATE
]) {
1470 strncpy(dest
, src
, len
);
1474 ret
= LCMapStringA(locinfo
->lc_handle
[LC_COLLATE
],
1475 LCMAP_SORTKEY
, src
, -1, NULL
, 0);
1477 if(len
) dest
[0] = 0;
1481 if(!len
) 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
;
1512 if (flags
) FIXME("flags not supported: %x\n", flags
);
1515 locinfo
= get_locinfo();
1517 locinfo
= locale
->locinfo
;
1520 while (_isspace_l((unsigned char)*p
, locale
))
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);
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
)
1547 switch(__STRINGTOLD_L( value
, &endptr
, str
, 0, locale
))
1549 case 1: return _UNDERFLOW
;
1550 case 2: return _OVERFLOW
;
1555 /********************************************************************
1556 * _atoldbl (MSVCRT.@)
1558 int CDECL
_atoldbl(_LDOUBLE
*value
, char *str
)
1560 return _atoldbl_l( (MSVCRT__LDOUBLE
*)value
, str
, NULL
);
1563 /*********************************************************************
1566 size_t __cdecl
strlen(const char *str
)
1568 const char *s
= str
;
1573 /******************************************************************
1574 * strnlen (MSVCRT.@)
1576 size_t CDECL
strnlen(const char *s
, size_t maxlen
)
1580 for(i
=0; i
<maxlen
; 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
;
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
++;
1609 } else if(*nptr
== '+')
1612 if((base
==0 || base
==16) && *nptr
=='0' && _tolower_l(*(nptr
+1), locale
)=='x') {
1625 char cur
= _tolower_l(*nptr
, locale
);
1628 if(cur
>='0' && cur
<='9') {
1633 if(cur
<'a' || cur
>='a'+base
-10)
1644 if(!negative
&& (ret
>I64_MAX
/base
|| ret
*base
>I64_MAX
-v
)) {
1647 } else if(negative
&& (ret
<I64_MIN
/base
|| ret
*base
<I64_MIN
-v
)) {
1655 *endptr
= (char*)(got_digit
? nptr
: p
);
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
);
1678 } else if(ret
< INT_MIN
) {
1685 /*********************************************************************
1689 int __cdecl
atoi(const char *str
)
1697 while(_isspace_l((unsigned char)*str
, NULL
)) str
++;
1701 }else if(*str
== '-') {
1706 while(*str
>='0' && *str
<='9') {
1707 ret
= ret
*10+*str
-'0';
1711 return minus
? -ret
: ret
;
1714 int CDECL
atoi(const char *str
)
1716 return _atoi_l(str
, NULL
);
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
) {
1746 } else if(ret
< LONG_MIN
) {
1753 /******************************************************************
1756 __msvcrt_long CDECL
atol(const char *str
)
1761 return _atol_l(str
, NULL
);
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
) {
1796 } else if(ret
< LONG_MIN
) {
1804 /******************************************************************
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
) {
1822 }else if(ret
< -(__int64
)ULONG_MAX
) {
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
++;
1861 } else if(*nptr
== '+')
1864 if((base
==0 || base
==16) && *nptr
=='0' && _tolower_l(*(nptr
+1), locale
)=='x') {
1877 char cur
= _tolower_l(*nptr
, locale
);
1880 if(cur
>='0' && cur
<='9') {
1885 if(cur
<'a' || cur
>='a'+base
-10)
1893 if(ret
>UI64_MAX
/base
|| ret
*base
>UI64_MAX
-v
) {
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
)
1919 char buffer
[33], *pos
;
1922 if (value
< 0 && radix
== 10)
1929 is_negative
= FALSE
;
1938 digit
= val
% radix
;
1942 *--pos
= '0' + digit
;
1944 *--pos
= 'a' + digit
- 10;
1951 len
= buffer
+ 33 - pos
;
1957 /* Copy the temporary buffer backwards up to the available number of
1958 * characters. Don't copy the negative sign if present. */
1966 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
1970 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
1974 memcpy(str
, pos
, len
);
1978 static int ltow_helper(__msvcrt_long value
, wchar_t *str
, size_t size
, int radix
)
1983 wchar_t buffer
[33], *pos
;
1986 if (value
< 0 && radix
== 10)
1993 is_negative
= FALSE
;
2002 digit
= val
% radix
;
2006 *--pos
= '0' + digit
;
2008 *--pos
= 'a' + digit
- 10;
2015 len
= buffer
+ 33 - pos
;
2021 /* Copy the temporary buffer backwards up to the available number of
2022 * characters. Don't copy the negative sign if present. */
2030 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2034 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
2038 memcpy(str
, pos
, len
* sizeof(wchar_t));
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))
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))
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 /*********************************************************************
2085 char* CDECL
_itoa(int value
, char *str
, int radix
)
2087 return ltoa_helper(value
, str
, SIZE_MAX
, radix
) ? NULL
: str
;
2090 /*********************************************************************
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 /*********************************************************************
2109 wchar_t* CDECL
_itow(int value
, wchar_t *str
, int radix
)
2111 return ltow_helper(value
, str
, SIZE_MAX
, radix
) ? NULL
: str
;
2114 /*********************************************************************
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 /*********************************************************************
2125 char* CDECL
_ultoa(__msvcrt_ulong value
, char *str
, int radix
)
2127 char buffer
[33], *pos
;
2133 int digit
= value
% radix
;
2137 *--pos
= '0' + digit
;
2139 *--pos
= 'a' + digit
- 10;
2140 } while (value
!= 0);
2142 memcpy(str
, pos
, buffer
+ 33 - pos
);
2146 /*********************************************************************
2147 * _ui64toa (MSVCRT.@)
2149 char* CDECL
_ui64toa(unsigned __int64 value
, char *str
, int radix
)
2151 char buffer
[65], *pos
;
2157 int digit
= value
% radix
;
2161 *--pos
= '0' + digit
;
2163 *--pos
= 'a' + digit
- 10;
2164 } while (value
!= 0);
2166 memcpy(str
, pos
, buffer
+ 65 - pos
);
2170 /*********************************************************************
2173 wchar_t* CDECL
_ultow(__msvcrt_ulong value
, wchar_t *str
, int radix
)
2175 wchar_t buffer
[33], *pos
;
2181 int digit
= value
% radix
;
2185 *--pos
= '0' + digit
;
2187 *--pos
= 'a' + digit
- 10;
2188 } while (value
!= 0);
2190 memcpy(str
, pos
, (buffer
+ 33 - pos
) * sizeof(wchar_t));
2194 /*********************************************************************
2195 * _ui64tow (MSVCRT.@)
2197 wchar_t* CDECL
_ui64tow(unsigned __int64 value
, wchar_t *str
, int radix
)
2199 wchar_t buffer
[65], *pos
;
2205 int digit
= value
% radix
;
2209 *--pos
= '0' + digit
;
2211 *--pos
= 'a' + digit
- 10;
2212 } while (value
!= 0);
2214 memcpy(str
, pos
, (buffer
+ 65 - pos
) * sizeof(wchar_t));
2218 /*********************************************************************
2219 * _i64toa (MSVCRT.@)
2221 char* CDECL
_i64toa(__int64 value
, char *str
, int radix
)
2223 unsigned __int64 val
;
2225 char buffer
[65], *pos
;
2227 if (value
< 0 && radix
== 10)
2234 is_negative
= FALSE
;
2243 int digit
= val
% radix
;
2247 *--pos
= '0' + digit
;
2249 *--pos
= 'a' + digit
- 10;
2256 memcpy(str
, pos
, buffer
+ 65 - pos
);
2260 /*********************************************************************
2261 * _i64tow (MSVCRT.@)
2263 wchar_t* CDECL
_i64tow(__int64 value
, wchar_t *str
, int radix
)
2265 unsigned __int64 val
;
2267 wchar_t buffer
[65], *pos
;
2269 if (value
< 0 && radix
== 10)
2276 is_negative
= FALSE
;
2285 int digit
= val
% radix
;
2289 *--pos
= '0' + digit
;
2291 *--pos
= 'a' + digit
- 10;
2298 memcpy(str
, pos
, (buffer
+ 65 - pos
) * sizeof(wchar_t));
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
;
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))
2323 digit
= value
%radix
;
2329 *--pos
= 'a'+digit
-10;
2332 if(buffer
-pos
+65 > size
) {
2333 MSVCRT_INVALID_PMT("str[size] is too small", EINVAL
);
2337 memcpy(str
, pos
, buffer
-pos
+65);
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
;
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))
2362 digit
= value
% radix
;
2363 value
= value
/ radix
;
2365 *--pos
= '0' + digit
;
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
);
2375 memcpy(str
, pos
, (buffer
-pos
+65)*sizeof(wchar_t));
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
;
2388 if (!str
|| !size
|| radix
< 2 || radix
> 36)
2402 digit
= value
% radix
;
2406 *--pos
= '0' + digit
;
2408 *--pos
= 'a' + digit
- 10;
2412 len
= buffer
+ 33 - pos
;
2418 /* Copy the temporary buffer backwards up to the available number of
2421 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2429 memcpy(str
, pos
, len
);
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
;
2442 if (!str
|| !size
|| radix
< 2 || radix
> 36)
2456 digit
= value
% radix
;
2460 *--pos
= '0' + digit
;
2462 *--pos
= 'a' + digit
- 10;
2466 len
= buffer
+ 33 - pos
;
2472 /* Copy the temporary buffer backwards up to the available number of
2475 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2483 memcpy(str
, pos
, len
* sizeof(wchar_t));
2487 /*********************************************************************
2488 * _i64toa_s (MSVCRT.@)
2490 int CDECL
_i64toa_s(__int64 value
, char *str
, size_t size
, int radix
)
2492 unsigned __int64 val
;
2495 char buffer
[65], *pos
;
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))
2506 if (value
< 0 && radix
== 10)
2513 is_negative
= FALSE
;
2522 digit
= val
% radix
;
2526 *--pos
= '0' + digit
;
2528 *--pos
= 'a' + digit
- 10;
2535 len
= buffer
+ 65 - pos
;
2541 /* Copy the temporary buffer backwards up to the available number of
2542 * characters. Don't copy the negative sign if present. */
2550 for (pos
= buffer
+ 63, i
= 0; i
< size
; i
++)
2554 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
2558 memcpy(str
, pos
, len
);
2562 /*********************************************************************
2563 * _i64tow_s (MSVCRT.@)
2565 int CDECL
_i64tow_s(__int64 value
, wchar_t *str
, size_t size
, int radix
)
2567 unsigned __int64 val
;
2570 wchar_t buffer
[65], *pos
;
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))
2581 if (value
< 0 && radix
== 10)
2588 is_negative
= FALSE
;
2597 digit
= val
% radix
;
2601 *--pos
= '0' + digit
;
2603 *--pos
= 'a' + digit
- 10;
2610 len
= buffer
+ 65 - pos
;
2616 /* Copy the temporary buffer backwards up to the available number of
2617 * characters. Don't copy the negative sign if present. */
2625 for (pos
= buffer
+ 63, i
= 0; i
< size
; i
++)
2629 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
2633 memcpy(str
, pos
, len
* sizeof(wchar_t));
2637 #define I10_OUTPUT_MAX_PREC 21
2638 /* Internal structure used by $I10_OUTPUT */
2639 struct _I10_OUTPUT_DATA
{
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
2654 * 0 if given double is NaN or INF
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
)
2666 char buf
[I10_OUTPUT_MAX_PREC
+9]; /* 9 = strlen("0.e+0000") + '\0' */
2669 if ((ld80
.x80
[2] & 0x7fff) == 0x7fff)
2671 if (ld80
.x80
[0] == 0 && ld80
.x80
[1] == 0x80000000)
2672 strcpy( data
->str
, "1#INF" );
2674 strcpy( data
->str
, (ld80
.x80
[1] & 0x40000000) ? "1#QNAN" : "1#SNAN" );
2676 data
->sign
= (ld80
.x80
[2] & 0x8000) ? '-' : ' ';
2677 data
->len
= strlen(data
->str
);
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
);
2695 int exp
= 1 + floor(log10(d
));
2703 if(prec
+1 > I10_OUTPUT_MAX_PREC
)
2704 prec
= I10_OUTPUT_MAX_PREC
-1;
2710 sprintf(format
, "%%.%dle", prec
);
2711 sprintf(buf
, format
, d
);
2714 data
->pos
= atoi(buf
+prec
+3);
2718 for(p
= buf
+prec
+1; p
>buf
+1 && *p
=='0'; p
--);
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);
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
++)
2738 return *p1
> *p2
? 1 : -1;
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);
2755 return memcmp_bytes(p1
, p2
, sizeof(uint64_t));
2762 return memcmp_bytes(p1
, p2
, remainder
);
2765 /*********************************************************************
2768 int __cdecl
memcmp(const void *ptr1
, const void *ptr2
, size_t n
)
2770 const unsigned char *p1
= ptr1
, *p2
= ptr2
;
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
)))
2786 return memcmp_blocks(p1
, p2
, n
);
2789 #if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__))
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")
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")
2840 void * __cdecl
sse2_memmove(void *dst
, const void *src
, size_t n
);
2841 __ASM_GLOBAL_FUNC( sse2_memmove
,
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"
2848 "cmp $4, " LEN_REG
"\n\t" /* 4-bytes align */
2850 "mov " DEST_REG
", " TMP_REG
"\n\t"
2851 "shr $1, " TMP_REG
"\n\t"
2854 "dec " LEN_REG
"\n\t"
2855 "inc " TMP_REG
"\n\t"
2857 "shr $1, " TMP_REG
"\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"
2865 "shr $1, " TMP_REG
"\n\t"
2868 "sub $4, " LEN_REG
"\n\t"
2869 "inc " TMP_REG
"\n\t"
2871 "shr $1, " TMP_REG
"\n\t"
2875 "sub $8, " LEN_REG
"\n\t"
2877 "cmp $64, " LEN_REG
"\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"
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"
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"
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"
2918 "shr $1, " TMP_REG
"\n\t"
2922 "copy_fwd3:\n\t" /* copy last 3 bytes */
2923 "shr $1, " LEN_REG
"\n\t"
2927 "shr $1, " LEN_REG
"\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 */
2938 "mov " DEST_REG
", " TMP_REG
"\n\t"
2939 "shr $1, " TMP_REG
"\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"
2947 "shr $1, " TMP_REG
"\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"
2957 "shr $1, " TMP_REG
"\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"
2965 "shr $1, " TMP_REG
"\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"
2975 "cmp $64, " LEN_REG
"\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"
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"
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"
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"
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"
3019 "shr $1, " TMP_REG
"\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"
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"
3035 "shr $1, " LEN_REG
"\n\t"
3037 "movw -2(" SRC_REG
"), %ax\n\t"
3038 "movw %ax, -2(" DEST_REG
")\n\t"
3045 /*********************************************************************
3046 * memmove (MSVCRT.@)
3048 #ifdef WORDS_BIGENDIAN
3049 # define MERGE(w1, sh1, w2, sh2) ((w1 << sh1) | (w2 >> sh2))
3051 # define MERGE(w1, sh1, w2, sh2) ((w1 >> sh1) | (w2 << sh2))
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
);
3058 unsigned char *d
= dst
;
3059 const unsigned char *s
= src
;
3064 return sse2_memmove(dst
, src
, n
);
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));
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
;
3093 s
+= sizeof(size_t);
3095 *(size_t*)d
= MERGE(x
, sh1
, y
, sh2
);
3096 d
+= sizeof(size_t);
3098 s
+= sizeof(size_t);
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));
3107 while (n
--) *d
++ = *s
++;
3115 for (; (size_t)d
% sizeof(size_t) && n
; n
--) *--d
= *--s
;
3117 sh1
= 8 * ((size_t)s
% sizeof(size_t));
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
;
3137 s
-= sizeof(size_t);
3139 d
-= sizeof(size_t);
3140 *(size_t*)d
= MERGE(y
, sh1
, x
, sh2
);
3142 s
-= sizeof(size_t);
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));
3151 while (n
--) *--d
= *--s
;
3158 /*********************************************************************
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
;
3178 static inline void memset_aligned_32(unsigned char *d
, uint64_t v
, size_t n
)
3180 unsigned char *end
= d
+ n
;
3183 *(uint64_t *)(d
+ 0) = v
;
3184 *(uint64_t *)(d
+ 8) = v
;
3185 *(uint64_t *)(d
+ 16) = v
;
3186 *(uint64_t *)(d
+ 24) = v
;
3191 /*********************************************************************
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);
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
);
3223 *(unaligned_ui64
*)d
= v
;
3224 *(unaligned_ui64
*)(d
+ n
- 8) = v
;
3229 *(unaligned_ui32
*)d
= v
;
3230 *(unaligned_ui32
*)(d
+ n
- 4) = v
;
3235 *(unaligned_ui16
*)d
= v
;
3236 *(unaligned_ui16
*)(d
+ n
- 2) = v
;
3247 /*********************************************************************
3250 char* __cdecl
strchr(const char *str
, int c
)
3254 if (*str
== (char)c
) return (char*)str
;
3259 /*********************************************************************
3260 * strrchr (MSVCRT.@)
3262 char* __cdecl
strrchr(const char *str
, int c
)
3265 do { if (*str
== (char)c
) ret
= (char*)str
; } while (*str
++);
3269 /*********************************************************************
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
;
3280 /*********************************************************************
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;
3291 /*********************************************************************
3292 * strncmp (MSVCRT.@)
3294 int __cdecl
strncmp(const char *str1
, const char *str2
, size_t len
)
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;
3304 return (unsigned char)*str1
- (unsigned char)*str2
;
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
;
3320 if(!MSVCRT_CHECK_PMT(s1
&& s2
&& count
<= INT_MAX
))
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
;
3328 locinfo
= get_locinfo();
3330 locinfo
= locale
->locinfo
;
3332 if(!locinfo
->lc_handle
[LC_CTYPE
])
3335 if ((c1
= *s1
++) >= 'A' && c1
<= 'Z')
3337 if ((c2
= *s2
++) >= 'A' && c2
<= 'Z')
3339 }while(--count
&& c1
&& c1
==c2
);
3345 c1
= _tolower_l((unsigned char)*s1
++, locale
);
3346 c2
= _tolower_l((unsigned char)*s2
++, locale
);
3347 }while(--count
&& c1
&& 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 /*********************************************************************
3379 char* __cdecl
strstr(const char *haystack
, const char *needle
)
3381 size_t i
, j
, len
, needle_len
, lps_len
;
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
;
3393 if (needle
[i
] == needle
[len
]) lps
[i
++] = ++len
;
3394 else if (len
) len
= lps
[len
-1];
3401 while (j
< lps_len
&& haystack
[i
] && haystack
[i
] == needle
[j
])
3407 if (j
== needle_len
) return (char*)haystack
+ i
- j
;
3410 if (j
== ARRAY_SIZE(lps
) && !strncmp(haystack
+ i
, needle
+ j
, needle_len
- j
))
3411 return (char*)haystack
+ i
- j
;
3414 else if (haystack
[i
]) i
++;
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
;
3427 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
3431 MSVCRT_INVALID_PMT(NULL
, EINVAL
);
3432 return len
? _NLSCMPERROR
: 0;
3438 if ((ret
= _tolower_l(*s1
, locale
) - _tolower_l(*s2
, locale
)))
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
)
3462 memset(rejects
, 0, sizeof(rejects
));
3467 rejects
[(unsigned char)*p
] = TRUE
;
3472 while(*p
&& !rejects
[(unsigned char)*p
]) p
++;
3476 /*********************************************************************
3479 size_t __cdecl
strspn(const char *str
, const char *accept
)
3482 for (ptr
= str
; *ptr
; ptr
++) if (!strchr( accept
, *ptr
)) break;
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
;
3495 /*********************************************************************
3496 * __strncnt (MSVCRT.@)
3498 size_t __cdecl
__strncnt(const char *str
, size_t size
)
3502 #if _MSVCR_VER >= 140
3503 while (*str
++ && size
--)
3505 while (size
-- && *str
++)
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
;