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
++;
290 if (!*str
) return NULL
;
292 while (*str
&& !strchr( delim
, *str
)) str
++;
293 if (*str
) *str
++ = 0;
294 data
->strtok_next
= str
;
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
;
310 while(*str
&& strchr(delim
, *str
))
319 while(**ctx
&& !strchr(delim
, **ctx
))
327 /*********************************************************************
330 void CDECL
_swab(char* src
, char* dst
, int len
)
334 len
= (unsigned)len
>> 1;
346 static struct fpnum
fpnum(int sign
, int exp
, ULONGLONG m
, enum fpmod mod
)
357 int fpnum_double(struct fpnum
*fp
, double *d
)
361 if (fp
->mod
== FP_VAL_INFINITY
)
363 *d
= fp
->sign
* INFINITY
;
367 if (fp
->mod
== FP_VAL_NAN
)
371 bits
&= ~((ULONGLONG
)1 << (MANT_BITS
+ EXP_BITS
- 1));
372 *d
= *(double*)&bits
;
376 TRACE("%c %s *2^%d (round %d)\n", fp
->sign
== -1 ? '-' : '+',
377 wine_dbgstr_longlong(fp
->m
), fp
->exp
, fp
->mod
);
384 /* make sure that we don't overflow modifying exponent */
385 if (fp
->exp
> 1<<EXP_BITS
)
387 *d
= fp
->sign
* INFINITY
;
390 if (fp
->exp
< -(1<<EXP_BITS
))
395 fp
->exp
+= MANT_BITS
- 1;
397 /* normalize mantissa */
398 while(fp
->m
< (ULONGLONG
)1 << (MANT_BITS
-1))
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
;
414 fp
->exp
+= (1 << (EXP_BITS
-1)) - 1;
416 /* handle subnormals */
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
;
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
;
434 if (fp
->mod
== FP_ROUND_UP
|| (fp
->mod
== FP_ROUND_EVEN
&& fp
->m
& 1))
438 /* handle subnormal that falls into regular range due to rounding */
439 if (fp
->m
== (ULONGLONG
)1 << (MANT_BITS
- 1))
443 else if (fp
->m
>= (ULONGLONG
)1 << MANT_BITS
)
450 if (fp
->exp
>= (1<<EXP_BITS
)-1)
452 *d
= fp
->sign
* INFINITY
;
455 if (!fp
->m
|| fp
->exp
< 0)
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
;
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
)
478 d
->x80
[1] = 0x80000000;
479 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
481 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
485 if (fp
->mod
== FP_VAL_NAN
)
489 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
491 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
495 TRACE("%c %s *2^%d (round %d)\n", fp
->sign
== -1 ? '-' : '+',
496 wine_dbgstr_longlong(fp
->m
), fp
->exp
, fp
->mod
);
503 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
507 /* make sure that we don't overflow modifying exponent */
508 if (fp
->exp
> 1<<LDBL_EXP_BITS
)
511 d
->x80
[1] = 0x80000000;
512 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
514 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
517 if (fp
->exp
< -(1<<LDBL_EXP_BITS
))
523 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
526 fp
->exp
+= LDBL_MANT_BITS
- 1;
528 /* normalize mantissa */
529 while(fp
->m
< (ULONGLONG
)1 << (LDBL_MANT_BITS
-1))
534 fp
->exp
+= (1 << (LDBL_EXP_BITS
-1)) - 1;
536 /* handle subnormals */
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
;
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
;
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);
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)
573 d
->x80
[1] = 0x80000000;
574 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
576 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
579 if (!fp
->m
|| fp
->exp
< 0)
585 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
590 d
->x80
[1] = fp
->m
>> 32;
593 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
597 #if _MSVCR_VER >= 140
599 static inline int hex2int(char c
)
601 if (c
>= '0' && c
<= '9')
603 else if (c
>= 'a' && c
<= 'f')
605 else if (c
>= 'A' && c
<= 'F')
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
;
620 while(m
< UI64_MAX
/16)
623 if (val
== -1) break;
632 if (val
== -1) break;
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
)
649 else if (!found_digit
)
651 if(nch
!=WEOF
) unget(ctx
);
653 return fpnum(0, 0, 0, 0);
656 while(m
<= UI64_MAX
/16)
659 if (val
== -1) break;
669 if (val
== -1) break;
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
;
682 if (nch
!= WEOF
) unget(ctx
);
683 if (found_dp
) unget(ctx
);
685 return fpnum(0, 0, 0, 0);
688 if(nch
=='p' || nch
=='P') {
689 BOOL found_sign
= FALSE
;
697 } else if(nch
== '+') {
701 if(nch
>='0' && nch
<='9') {
702 while(nch
>='0' && nch
<='9') {
703 if(e
>INT_MAX
/10 || e
*10>INT_MAX
-nch
+'0')
709 if((nch
!=WEOF
) && (nch
< '0' || nch
> '9')) unget(ctx
);
712 if(e
<0 && exp
<INT_MIN
-e
) exp
= INT_MIN
;
713 else if(e
>0 && exp
>INT_MAX
-e
) exp
= INT_MAX
;
716 if(nch
!= WEOF
) unget(ctx
);
717 if(found_sign
) unget(ctx
);
722 return fpnum(sign
, exp
, m
, round
);
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)];
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
;
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
;
761 } else if(nch
== '+') {
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]))
771 while(str_match
&& nch
!= WEOF
&&
772 (nch
== str_match
[matched
] || nch
== _toupper(str_match
[matched
]))) {
778 if(matched
>= 8) keep
= 8;
779 else if(matched
>= 3) keep
= 3;
780 if(nch
!= WEOF
) unget(ctx
);
781 for (; matched
> keep
; matched
--) {
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
) {
793 return fpnum(0, 0, 0, 0);
799 if(nch
== 'x' || nch
== 'X')
800 return fpnum_parse16(get
, unget
, ctx
, sign
, locinfo
);
812 while(nch
>='0' && nch
<='9') {
814 if(limb_digits
== LIMB_DIGITS
) {
815 if(bnum_idx(b
, b
->b
-1) == bnum_idx(b
, b
->e
)) break;
818 b
->data
[bnum_idx(b
, b
->b
)] = 0;
823 b
->data
[bnum_idx(b
, b
->b
)] = b
->data
[bnum_idx(b
, b
->b
)] * 10 + nch
- '0';
828 while(nch
>='0' && nch
<='9') {
829 if(nch
!= '0') b
->data
[bnum_idx(b
, b
->b
)] |= 1;
834 if(nch
== *locinfo
->lconv
->decimal_point
) {
839 /* skip leading '0' */
840 if(nch
=='0' && !limb_digits
&& !b
->b
) {
848 while(nch
>='0' && nch
<='9') {
850 if(limb_digits
== LIMB_DIGITS
) {
851 if(bnum_idx(b
, b
->b
-1) == bnum_idx(b
, b
->e
)) break;
854 b
->data
[bnum_idx(b
, b
->b
)] = 0;
859 b
->data
[bnum_idx(b
, b
->b
)] = b
->data
[bnum_idx(b
, b
->b
)] * 10 + nch
- '0';
863 while(nch
>='0' && nch
<='9') {
864 if(nch
!= '0') b
->data
[bnum_idx(b
, b
->b
)] |= 1;
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') {
883 } else if(nch
== '+') {
890 if(nch
>='0' && nch
<='9') {
891 while(nch
>='0' && nch
<='9') {
892 if(e
>INT_MAX
/10 || e
*10>INT_MAX
-nch
+'0')
898 if(nch
!= WEOF
) unget(ctx
);
901 if(e
<0 && dp
<INT_MIN
-e
) dp
= INT_MIN
;
902 else if(e
>0 && dp
>INT_MAX
-e
) dp
= INT_MAX
;
905 if(nch
!= WEOF
) unget(ctx
);
906 if(found_sign
) unget(ctx
);
909 } else if(nch
!= WEOF
) {
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 */
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
;
943 while(dp
<= 2*LIMB_DIGITS
) {
944 if(bnum_lshift(b
, 29)) dp
+= LIMB_DIGITS
;
947 /* Make sure most significant mantissa bit will be set */
948 while(b
->data
[bnum_idx(b
, b
->e
-1)] <= 9) {
952 while(!bnum_to_mant(b
, &m
)) {
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
)
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
);
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
;
998 static void strtod_str_unget(void *ctx
)
1000 const char **p
= ctx
;
1004 static inline double strtod_helper(const char *str
, char **end
, _locale_t locale
, int *perr
)
1006 pthreadlocinfo locinfo
;
1007 const char *beg
, *p
;
1012 if (perr
) *perr
= 0;
1017 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) {
1018 if (end
) *end
= NULL
;
1023 locinfo
= get_locinfo();
1025 locinfo
= locale
->locinfo
;
1028 while(_isspace_l((unsigned char)*p
, locale
))
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
;
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 /*********************************************************************
1052 double CDECL
strtod( const char *str
, char **end
)
1054 return _strtod_l( str
, end
, NULL
);
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 /*********************************************************************
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
)
1101 d
= strtod_helper(str
, NULL
, locale
, &err
);
1105 if((d
!=0 || err
) && value
->f
>-FLT_MIN
&& value
->f
<FLT_MIN
)
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
)
1125 value
->x
= strtod_helper(str
, NULL
, locale
, &err
);
1128 if((value
->x
!=0 || err
) && value
->x
>-DBL_MIN
&& value
->x
<DBL_MIN
)
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
;
1149 locinfo
= get_locinfo();
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
;
1174 locinfo
= get_locinfo();
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
;
1200 locinfo
= get_locinfo();
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
;
1227 locinfo
= get_locinfo();
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
)
1253 for(i
=0; i
<len
; i
++)
1254 if((dst
[i
] = src
[i
]) == '\0') break;
1256 while (i
< len
) dst
[i
++] = 0;
1261 /*********************************************************************
1264 char* CDECL
strcpy(char *dst
, const char *src
)
1267 while ((*dst
++ = *src
++));
1271 /*********************************************************************
1272 * strcpy_s (MSVCRT.@)
1274 int CDECL
strcpy_s( char* dst
, size_t elem
, const char* src
)
1277 if(!elem
) return EINVAL
;
1278 if(!dst
) return EINVAL
;
1285 for(i
= 0; i
< elem
; i
++)
1287 if((dst
[i
] = src
[i
]) == '\0') return 0;
1293 /*********************************************************************
1294 * strcat_s (MSVCRT.@)
1296 int CDECL
strcat_s( char* dst
, size_t elem
, const char* src
)
1299 if(!dst
) return EINVAL
;
1300 if(elem
== 0) return EINVAL
;
1307 for(i
= 0; i
< elem
; i
++)
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 */
1322 /*********************************************************************
1325 char* __cdecl
strcat( char *dst
, const char *src
)
1329 while ((*d
++ = *src
++));
1333 /*********************************************************************
1334 * strncat_s (MSVCRT.@)
1336 int CDECL
strncat_s( char* dst
, size_t elem
, const char* src
, size_t count
)
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))
1348 for(i
= 0; i
< elem
; i
++)
1352 for(j
= 0; (j
+ i
) < elem
; j
++)
1354 if(count
== _TRUNCATE
&& j
+ i
== elem
- 1)
1359 if(j
== count
|| (dst
[j
+ i
] = src
[j
]) == '\0')
1367 /* Set the first element to 0, not the first element after the skipped part */
1372 /*********************************************************************
1373 * strncat (MSVCRT.@)
1375 char* __cdecl
strncat(char *dst
, const char *src
, size_t len
)
1379 for ( ; len
&& *src
; d
++, src
++, len
--) *d
= *src
;
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
;
1393 if(!MSVCRT_CHECK_PMT(src
)) return INT_MAX
;
1394 if(!MSVCRT_CHECK_PMT(dest
|| !len
)) return INT_MAX
;
1397 FIXME("len > INT_MAX not supported\n");
1402 locinfo
= get_locinfo();
1404 locinfo
= locale
->locinfo
;
1406 if(!locinfo
->lc_handle
[LC_COLLATE
]) {
1407 strncpy(dest
, src
, len
);
1411 ret
= LCMapStringA(locinfo
->lc_handle
[LC_COLLATE
],
1412 LCMAP_SORTKEY
, src
, -1, NULL
, 0);
1414 if(len
) dest
[0] = 0;
1418 if(!len
) 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
;
1449 if (flags
) FIXME("flags not supported: %x\n", flags
);
1452 locinfo
= get_locinfo();
1454 locinfo
= locale
->locinfo
;
1457 while (_isspace_l((unsigned char)*p
, locale
))
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);
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
)
1484 switch(__STRINGTOLD_L( value
, &endptr
, str
, 0, locale
))
1486 case 1: return _UNDERFLOW
;
1487 case 2: return _OVERFLOW
;
1492 /********************************************************************
1493 * _atoldbl (MSVCRT.@)
1495 int CDECL
_atoldbl(_LDOUBLE
*value
, char *str
)
1497 return _atoldbl_l( (MSVCRT__LDOUBLE
*)value
, str
, NULL
);
1500 /*********************************************************************
1503 size_t __cdecl
strlen(const char *str
)
1505 const char *s
= str
;
1510 /******************************************************************
1511 * strnlen (MSVCRT.@)
1513 size_t CDECL
strnlen(const char *s
, size_t maxlen
)
1517 for(i
=0; i
<maxlen
; 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
;
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
++;
1546 } else if(*nptr
== '+')
1549 if((base
==0 || base
==16) && *nptr
=='0' && _tolower_l(*(nptr
+1), locale
)=='x') {
1562 char cur
= _tolower_l(*nptr
, locale
);
1565 if(cur
>='0' && cur
<='9') {
1570 if(cur
<'a' || cur
>='a'+base
-10)
1581 if(!negative
&& (ret
>I64_MAX
/base
|| ret
*base
>I64_MAX
-v
)) {
1584 } else if(negative
&& (ret
<I64_MIN
/base
|| ret
*base
<I64_MIN
-v
)) {
1592 *endptr
= (char*)(got_digit
? nptr
: p
);
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
);
1615 } else if(ret
< INT_MIN
) {
1622 /*********************************************************************
1626 int __cdecl
atoi(const char *str
)
1634 while(_isspace_l((unsigned char)*str
, NULL
)) str
++;
1638 }else if(*str
== '-') {
1643 while(*str
>='0' && *str
<='9') {
1644 ret
= ret
*10+*str
-'0';
1648 return minus
? -ret
: ret
;
1651 int CDECL
atoi(const char *str
)
1653 return _atoi_l(str
, NULL
);
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
) {
1683 } else if(ret
< LONG_MIN
) {
1690 /******************************************************************
1693 __msvcrt_long CDECL
atol(const char *str
)
1698 return _atol_l(str
, NULL
);
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
) {
1733 } else if(ret
< LONG_MIN
) {
1741 /******************************************************************
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
) {
1759 }else if(ret
< -(__int64
)ULONG_MAX
) {
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
++;
1798 } else if(*nptr
== '+')
1801 if((base
==0 || base
==16) && *nptr
=='0' && _tolower_l(*(nptr
+1), locale
)=='x') {
1814 char cur
= _tolower_l(*nptr
, locale
);
1817 if(cur
>='0' && cur
<='9') {
1822 if(cur
<'a' || cur
>='a'+base
-10)
1830 if(ret
>UI64_MAX
/base
|| ret
*base
>UI64_MAX
-v
) {
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
)
1856 char buffer
[33], *pos
;
1859 if (value
< 0 && radix
== 10)
1866 is_negative
= FALSE
;
1875 digit
= val
% radix
;
1879 *--pos
= '0' + digit
;
1881 *--pos
= 'a' + digit
- 10;
1888 len
= buffer
+ 33 - pos
;
1894 /* Copy the temporary buffer backwards up to the available number of
1895 * characters. Don't copy the negative sign if present. */
1903 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
1907 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
1911 memcpy(str
, pos
, len
);
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))
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
)
1939 wchar_t buffer
[33], *pos
;
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))
1950 if (value
< 0 && radix
== 10)
1957 is_negative
= FALSE
;
1966 digit
= val
% radix
;
1970 *--pos
= '0' + digit
;
1972 *--pos
= 'a' + digit
- 10;
1979 len
= buffer
+ 33 - pos
;
1985 /* Copy the temporary buffer backwards up to the available number of
1986 * characters. Don't copy the negative sign if present. */
1994 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
1998 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
2002 memcpy(str
, pos
, len
* sizeof(wchar_t));
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 /*********************************************************************
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
;
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))
2051 digit
= value
%radix
;
2057 *--pos
= 'a'+digit
-10;
2060 if(buffer
-pos
+65 > size
) {
2061 MSVCRT_INVALID_PMT("str[size] is too small", EINVAL
);
2065 memcpy(str
, pos
, buffer
-pos
+65);
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
;
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))
2090 digit
= value
% radix
;
2091 value
= value
/ radix
;
2093 *--pos
= '0' + digit
;
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
);
2103 memcpy(str
, pos
, (buffer
-pos
+65)*sizeof(wchar_t));
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
;
2116 if (!str
|| !size
|| radix
< 2 || radix
> 36)
2130 digit
= value
% radix
;
2134 *--pos
= '0' + digit
;
2136 *--pos
= 'a' + digit
- 10;
2140 len
= buffer
+ 33 - pos
;
2146 /* Copy the temporary buffer backwards up to the available number of
2149 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2157 memcpy(str
, pos
, len
);
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
;
2170 if (!str
|| !size
|| radix
< 2 || radix
> 36)
2184 digit
= value
% radix
;
2188 *--pos
= '0' + digit
;
2190 *--pos
= 'a' + digit
- 10;
2194 len
= buffer
+ 33 - pos
;
2200 /* Copy the temporary buffer backwards up to the available number of
2203 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2211 memcpy(str
, pos
, len
* sizeof(wchar_t));
2215 /*********************************************************************
2216 * _i64toa_s (MSVCRT.@)
2218 int CDECL
_i64toa_s(__int64 value
, char *str
, size_t size
, int radix
)
2220 unsigned __int64 val
;
2223 char buffer
[65], *pos
;
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))
2234 if (value
< 0 && radix
== 10)
2241 is_negative
= FALSE
;
2250 digit
= val
% radix
;
2254 *--pos
= '0' + digit
;
2256 *--pos
= 'a' + digit
- 10;
2263 len
= buffer
+ 65 - pos
;
2269 /* Copy the temporary buffer backwards up to the available number of
2270 * characters. Don't copy the negative sign if present. */
2278 for (pos
= buffer
+ 63, i
= 0; i
< size
; i
++)
2282 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
2286 memcpy(str
, pos
, len
);
2290 /*********************************************************************
2291 * _i64tow_s (MSVCRT.@)
2293 int CDECL
_i64tow_s(__int64 value
, wchar_t *str
, size_t size
, int radix
)
2295 unsigned __int64 val
;
2298 wchar_t buffer
[65], *pos
;
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))
2309 if (value
< 0 && radix
== 10)
2316 is_negative
= FALSE
;
2325 digit
= val
% radix
;
2329 *--pos
= '0' + digit
;
2331 *--pos
= 'a' + digit
- 10;
2338 len
= buffer
+ 65 - pos
;
2344 /* Copy the temporary buffer backwards up to the available number of
2345 * characters. Don't copy the negative sign if present. */
2353 for (pos
= buffer
+ 63, i
= 0; i
< size
; i
++)
2357 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
2361 memcpy(str
, pos
, len
* sizeof(wchar_t));
2365 #define I10_OUTPUT_MAX_PREC 21
2366 /* Internal structure used by $I10_OUTPUT */
2367 struct _I10_OUTPUT_DATA
{
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
2382 * 0 if given double is NaN or INF
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
)
2394 char buf
[I10_OUTPUT_MAX_PREC
+9]; /* 9 = strlen("0.e+0000") + '\0' */
2397 if ((ld80
.x80
[2] & 0x7fff) == 0x7fff)
2399 if (ld80
.x80
[0] == 0 && ld80
.x80
[1] == 0x80000000)
2400 strcpy( data
->str
, "1#INF" );
2402 strcpy( data
->str
, (ld80
.x80
[1] & 0x40000000) ? "1#QNAN" : "1#SNAN" );
2404 data
->sign
= (ld80
.x80
[2] & 0x8000) ? '-' : ' ';
2405 data
->len
= strlen(data
->str
);
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
);
2423 int exp
= 1 + floor(log10(d
));
2431 if(prec
+1 > I10_OUTPUT_MAX_PREC
)
2432 prec
= I10_OUTPUT_MAX_PREC
-1;
2438 sprintf(format
, "%%.%dle", prec
);
2439 sprintf(buf
, format
, d
);
2442 data
->pos
= atoi(buf
+prec
+3);
2446 for(p
= buf
+prec
+1; p
>buf
+1 && *p
=='0'; p
--);
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);
2457 #undef I10_OUTPUT_MAX_PREC
2459 /*********************************************************************
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;
2474 #if defined(__i386__) || defined(__x86_64__)
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")
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")
2522 void * __cdecl
sse2_memmove(void *dst
, const void *src
, size_t n
);
2523 __ASM_GLOBAL_FUNC( sse2_memmove
,
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"
2530 "cmp $4, " LEN_REG
"\n\t" /* 4-bytes align */
2532 "mov " DEST_REG
", " TMP_REG
"\n\t"
2533 "shr $1, " TMP_REG
"\n\t"
2536 "dec " LEN_REG
"\n\t"
2537 "inc " TMP_REG
"\n\t"
2539 "shr $1, " TMP_REG
"\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"
2547 "shr $1, " TMP_REG
"\n\t"
2550 "sub $4, " LEN_REG
"\n\t"
2551 "inc " TMP_REG
"\n\t"
2553 "shr $1, " TMP_REG
"\n\t"
2557 "sub $8, " LEN_REG
"\n\t"
2559 "cmp $64, " LEN_REG
"\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"
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"
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"
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"
2600 "shr $1, " TMP_REG
"\n\t"
2604 "copy_fwd3:\n\t" /* copy last 3 bytes */
2605 "shr $1, " LEN_REG
"\n\t"
2609 "shr $1, " LEN_REG
"\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 */
2620 "mov " DEST_REG
", " TMP_REG
"\n\t"
2621 "shr $1, " TMP_REG
"\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"
2629 "shr $1, " TMP_REG
"\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"
2639 "shr $1, " TMP_REG
"\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"
2647 "shr $1, " TMP_REG
"\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"
2657 "cmp $64, " LEN_REG
"\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"
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"
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"
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"
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"
2701 "shr $1, " TMP_REG
"\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"
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"
2717 "shr $1, " LEN_REG
"\n\t"
2719 "movw -2(" SRC_REG
"), %ax\n\t"
2720 "movw %ax, -2(" DEST_REG
")\n\t"
2727 /*********************************************************************
2728 * memmove (MSVCRT.@)
2730 #ifdef WORDS_BIGENDIAN
2731 # define MERGE(w1, sh1, w2, sh2) ((w1 << sh1) | (w2 >> sh2))
2733 # define MERGE(w1, sh1, w2, sh2) ((w1 >> sh1) | (w2 << sh2))
2735 void * __cdecl
memmove(void *dst
, const void *src
, size_t n
)
2738 return sse2_memmove(dst
, src
, n
);
2740 unsigned char *d
= dst
;
2741 const unsigned char *s
= src
;
2746 return sse2_memmove(dst
, src
, n
);
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));
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
;
2775 s
+= sizeof(size_t);
2777 *(size_t*)d
= MERGE(x
, sh1
, y
, sh2
);
2778 d
+= sizeof(size_t);
2780 s
+= sizeof(size_t);
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));
2789 while (n
--) *d
++ = *s
++;
2797 for (; (size_t)d
% sizeof(size_t) && n
; n
--) *--d
= *--s
;
2799 sh1
= 8 * ((size_t)s
% sizeof(size_t));
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
;
2819 s
-= sizeof(size_t);
2821 d
-= sizeof(size_t);
2822 *(size_t*)d
= MERGE(y
, sh1
, x
, sh2
);
2824 s
-= sizeof(size_t);
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));
2833 while (n
--) *--d
= *--s
;
2840 /*********************************************************************
2843 void * __cdecl
memcpy(void *dst
, const void *src
, size_t n
)
2845 return memmove(dst
, src
, n
);
2848 /*********************************************************************
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
;
2858 /*********************************************************************
2861 char* __cdecl
strchr(const char *str
, int c
)
2865 if (*str
== (char)c
) return (char*)str
;
2870 /*********************************************************************
2871 * strrchr (MSVCRT.@)
2873 char* __cdecl
strrchr(const char *str
, int c
)
2876 do { if (*str
== (char)c
) ret
= (char*)str
; } while (*str
++);
2880 /*********************************************************************
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
;
2891 /*********************************************************************
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;
2902 /*********************************************************************
2903 * strncmp (MSVCRT.@)
2905 int __cdecl
strncmp(const char *str1
, const char *str2
, size_t len
)
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
;
2921 if(s1
==NULL
|| s2
==NULL
)
2922 return _NLSCMPERROR
;
2928 locinfo
= get_locinfo();
2930 locinfo
= locale
->locinfo
;
2932 if(!locinfo
->lc_handle
[LC_CTYPE
])
2935 if ((c1
= *s1
++) >= 'A' && c1
<= 'Z')
2937 if ((c2
= *s2
++) >= 'A' && c2
<= 'Z')
2939 }while(--count
&& c1
&& c1
==c2
);
2945 c1
= _tolower_l((unsigned char)*s1
++, locale
);
2946 c2
= _tolower_l((unsigned char)*s2
++, locale
);
2947 }while(--count
&& c1
&& 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 /*********************************************************************
2979 char* __cdecl
strstr(const char *haystack
, const char *needle
)
2981 size_t i
, j
, len
, needle_len
, lps_len
;
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
;
2993 if (needle
[i
] == needle
[len
]) lps
[i
++] = ++len
;
2994 else if (len
) len
= lps
[len
-1];
3001 while (j
< lps_len
&& haystack
[i
] && haystack
[i
] == needle
[j
])
3007 if (j
== needle_len
) return (char*)haystack
+ i
- j
;
3010 if (j
== ARRAY_SIZE(lps
) && !strncmp(haystack
+ i
, needle
+ j
, needle_len
- j
))
3011 return (char*)haystack
+ i
- j
;
3014 else if (haystack
[i
]) i
++;
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
;
3027 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
3031 MSVCRT_INVALID_PMT(NULL
, EINVAL
);
3032 return len
? _NLSCMPERROR
: 0;
3038 if ((ret
= _tolower_l(*s1
, locale
) - _tolower_l(*s2
, locale
)))
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
)
3062 memset(rejects
, 0, sizeof(rejects
));
3067 rejects
[(unsigned char)*p
] = TRUE
;
3072 while(*p
&& !rejects
[(unsigned char)*p
]) p
++;
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
;
3085 /*********************************************************************
3086 * __strncnt (MSVCRT.@)
3088 size_t __cdecl
__strncnt(const char *str
, size_t size
)
3092 #if _MSVCR_VER >= 140
3093 while (*str
++ && size
--)
3095 while (size
-- && *str
++)
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
;