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
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
38 /*********************************************************************
42 char* CDECL
_strdup(const char* str
)
46 char * ret
= malloc(strlen(str
)+1);
47 if (ret
) strcpy( ret
, str
);
53 /*********************************************************************
54 * _strlwr_s_l (MSVCRT.@)
56 int CDECL
_strlwr_s_l(char *str
, size_t len
, _locale_t locale
)
58 pthreadlocinfo locinfo
;
81 locinfo
= get_locinfo();
83 locinfo
= locale
->locinfo
;
85 if(!locinfo
->lc_handle
[LC_CTYPE
])
89 if (*str
>= 'A' && *str
<= 'Z')
98 *str
= _tolower_l((unsigned char)*str
, locale
);
106 /*********************************************************************
107 * _strlwr_s (MSVCRT.@)
109 int CDECL
_strlwr_s(char *str
, size_t len
)
111 return _strlwr_s_l(str
, len
, NULL
);
114 /*********************************************************************
115 * _strlwr_l (MSVCRT.@)
117 char* CDECL
_strlwr_l(char *str
, _locale_t locale
)
119 _strlwr_s_l(str
, -1, locale
);
123 /*********************************************************************
126 char* CDECL
_strlwr(char *str
)
128 _strlwr_s_l(str
, -1, NULL
);
132 /*********************************************************************
133 * _strupr_s_l (MSVCRT.@)
135 int CDECL
_strupr_s_l(char *str
, size_t len
, _locale_t locale
)
137 pthreadlocinfo locinfo
;
160 locinfo
= get_locinfo();
162 locinfo
= locale
->locinfo
;
164 if(!locinfo
->lc_handle
[LC_CTYPE
])
168 if (*str
>= 'a' && *str
<= 'z')
177 *str
= _toupper_l((unsigned char)*str
, locale
);
185 /*********************************************************************
186 * _strupr_s (MSVCRT.@)
188 int CDECL
_strupr_s(char *str
, size_t len
)
190 return _strupr_s_l(str
, len
, NULL
);
193 /*********************************************************************
194 * _strupr_l (MSVCRT.@)
196 char* CDECL
_strupr_l(char *str
, _locale_t locale
)
198 _strupr_s_l(str
, -1, locale
);
202 /*********************************************************************
205 char* CDECL
_strupr(char *str
)
207 _strupr_s_l(str
, -1, NULL
);
211 /*********************************************************************
212 * _strnset_s (MSVCRT.@)
214 int CDECL
_strnset_s(char *str
, size_t size
, int c
, size_t count
)
218 if(!str
&& !size
&& !count
) return 0;
219 if(!MSVCRT_CHECK_PMT(str
!= NULL
)) return EINVAL
;
220 if(!MSVCRT_CHECK_PMT(size
> 0)) return EINVAL
;
222 for(i
=0; i
<size
-1 && i
<count
; i
++) {
223 if(!str
[i
]) return 0;
227 if(!str
[i
]) return 0;
230 _invalid_parameter(NULL
, NULL
, NULL
, 0, 0);
235 /*********************************************************************
236 * _strnset (MSVCRT.@)
238 char* CDECL
_strnset(char* str
, int value
, size_t len
)
241 while (*str
&& len
--)
246 /*********************************************************************
249 char* CDECL
_strrev(char* str
)
255 for (p1
= str
, p2
= str
+ strlen(str
) - 1; p2
> p1
; ++p1
, --p2
)
265 /*********************************************************************
268 char* CDECL
_strset(char* str
, int value
)
277 /*********************************************************************
280 char * CDECL
strtok( char *str
, const char *delim
)
282 thread_data_t
*data
= msvcrt_get_thread_data();
286 if (!(str
= data
->strtok_next
)) return NULL
;
288 while (*str
&& strchr( delim
, *str
)) str
++;
289 if (!*str
) return NULL
;
291 while (*str
&& !strchr( delim
, *str
)) str
++;
292 if (*str
) *str
++ = 0;
293 data
->strtok_next
= str
;
297 /*********************************************************************
298 * strtok_s (MSVCRT.@)
300 char * CDECL
strtok_s(char *str
, const char *delim
, char **ctx
)
302 if (!MSVCRT_CHECK_PMT(delim
!= NULL
)) return NULL
;
303 if (!MSVCRT_CHECK_PMT(ctx
!= NULL
)) return NULL
;
304 if (!MSVCRT_CHECK_PMT(str
!= NULL
|| *ctx
!= NULL
)) return NULL
;
309 while(*str
&& strchr(delim
, *str
))
318 while(**ctx
&& !strchr(delim
, **ctx
))
326 /*********************************************************************
329 void CDECL
_swab(char* src
, char* dst
, int len
)
333 len
= (unsigned)len
>> 1;
345 static struct fpnum
fpnum(int sign
, int exp
, ULONGLONG m
, enum fpmod mod
)
356 int fpnum_double(struct fpnum
*fp
, double *d
)
360 if (fp
->mod
== FP_VAL_INFINITY
)
362 *d
= fp
->sign
* INFINITY
;
366 if (fp
->mod
== FP_VAL_NAN
)
370 bits
&= ~((ULONGLONG
)1 << (MANT_BITS
+ EXP_BITS
- 1));
371 *d
= *(double*)&bits
;
375 TRACE("%c %s *2^%d (round %d)\n", fp
->sign
== -1 ? '-' : '+',
376 wine_dbgstr_longlong(fp
->m
), fp
->exp
, fp
->mod
);
383 /* make sure that we don't overflow modifying exponent */
384 if (fp
->exp
> 1<<EXP_BITS
)
386 *d
= fp
->sign
* INFINITY
;
389 if (fp
->exp
< -(1<<EXP_BITS
))
394 fp
->exp
+= MANT_BITS
- 1;
396 /* normalize mantissa */
397 while(fp
->m
< (ULONGLONG
)1 << (MANT_BITS
-1))
402 while(fp
->m
>= (ULONGLONG
)1 << MANT_BITS
)
404 if (fp
->m
& 1 || fp
->mod
!= FP_ROUND_ZERO
)
406 if (!(fp
->m
& 1)) fp
->mod
= FP_ROUND_DOWN
;
407 else if(fp
->mod
== FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_EVEN
;
408 else fp
->mod
= FP_ROUND_UP
;
413 fp
->exp
+= (1 << (EXP_BITS
-1)) - 1;
415 /* handle subnormals */
418 if (fp
->m
& 1 && fp
->mod
== FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_EVEN
;
419 else if (fp
->m
& 1) fp
->mod
= FP_ROUND_UP
;
420 else if (fp
->mod
!= FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_DOWN
;
423 while(fp
->m
&& fp
->exp
<0)
425 if (fp
->m
& 1 && fp
->mod
== FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_EVEN
;
426 else if (fp
->m
& 1) fp
->mod
= FP_ROUND_UP
;
427 else if (fp
->mod
!= FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_DOWN
;
433 if (fp
->mod
== FP_ROUND_UP
|| (fp
->mod
== FP_ROUND_EVEN
&& fp
->m
& 1))
437 /* handle subnormal that falls into regular range due to rounding */
438 if (fp
->m
== (ULONGLONG
)1 << (MANT_BITS
- 1))
442 else if (fp
->m
>= (ULONGLONG
)1 << MANT_BITS
)
449 if (fp
->exp
>= (1<<EXP_BITS
)-1)
451 *d
= fp
->sign
* INFINITY
;
454 if (!fp
->m
|| fp
->exp
< 0)
461 bits
|= (ULONGLONG
)1 << (MANT_BITS
+ EXP_BITS
- 1);
462 bits
|= (ULONGLONG
)fp
->exp
<< (MANT_BITS
- 1);
463 bits
|= fp
->m
& (((ULONGLONG
)1 << (MANT_BITS
- 1)) - 1);
465 TRACE("returning %s\n", wine_dbgstr_longlong(bits
));
466 *d
= *(double*)&bits
;
470 #define LDBL_EXP_BITS 15
471 #define LDBL_MANT_BITS 64
472 int fpnum_ldouble(struct fpnum
*fp
, MSVCRT__LDOUBLE
*d
)
474 if (fp
->mod
== FP_VAL_INFINITY
)
477 d
->x80
[1] = 0x80000000;
478 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
480 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
484 if (fp
->mod
== FP_VAL_NAN
)
488 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
490 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
494 TRACE("%c %s *2^%d (round %d)\n", fp
->sign
== -1 ? '-' : '+',
495 wine_dbgstr_longlong(fp
->m
), fp
->exp
, fp
->mod
);
502 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
506 /* make sure that we don't overflow modifying exponent */
507 if (fp
->exp
> 1<<LDBL_EXP_BITS
)
510 d
->x80
[1] = 0x80000000;
511 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
513 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
516 if (fp
->exp
< -(1<<LDBL_EXP_BITS
))
522 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
525 fp
->exp
+= LDBL_MANT_BITS
- 1;
527 /* normalize mantissa */
528 while(fp
->m
< (ULONGLONG
)1 << (LDBL_MANT_BITS
-1))
533 fp
->exp
+= (1 << (LDBL_EXP_BITS
-1)) - 1;
535 /* handle subnormals */
538 if (fp
->m
& 1 && fp
->mod
== FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_EVEN
;
539 else if (fp
->m
& 1) fp
->mod
= FP_ROUND_UP
;
540 else if (fp
->mod
!= FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_DOWN
;
543 while(fp
->m
&& fp
->exp
<0)
545 if (fp
->m
& 1 && fp
->mod
== FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_EVEN
;
546 else if (fp
->m
& 1) fp
->mod
= FP_ROUND_UP
;
547 else if (fp
->mod
!= FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_DOWN
;
553 if (fp
->mod
== FP_ROUND_UP
|| (fp
->mod
== FP_ROUND_EVEN
&& fp
->m
& 1))
555 if (fp
->m
== UI64_MAX
)
557 fp
->m
= (ULONGLONG
)1 << (LDBL_MANT_BITS
- 1);
564 /* handle subnormal that falls into regular range due to rounding */
565 if ((fp
->m
^ (fp
->m
- 1)) & ((ULONGLONG
)1 << (LDBL_MANT_BITS
- 1))) fp
->exp
++;
569 if (fp
->exp
>= (1<<LDBL_EXP_BITS
)-1)
572 d
->x80
[1] = 0x80000000;
573 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
575 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
578 if (!fp
->m
|| fp
->exp
< 0)
584 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
589 d
->x80
[1] = fp
->m
>> 32;
592 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
596 #if _MSVCR_VER >= 140
598 static inline int hex2int(char c
)
600 if (c
>= '0' && c
<= '9')
602 else if (c
>= 'a' && c
<= 'f')
604 else if (c
>= 'A' && c
<= 'F')
609 static struct fpnum
fpnum_parse16(wchar_t get(void *ctx
), void unget(void *ctx
),
610 void *ctx
, int sign
, pthreadlocinfo locinfo
)
612 BOOL found_digit
= FALSE
, found_dp
= FALSE
;
613 enum fpmod round
= FP_ROUND_ZERO
;
619 while(m
< UI64_MAX
/16)
622 if (val
== -1) break;
631 if (val
== -1) break;
635 if (val
|| round
!= FP_ROUND_ZERO
)
637 if (val
< 8) round
= FP_ROUND_DOWN
;
638 else if (val
== 8 && round
== FP_ROUND_ZERO
) round
= FP_ROUND_EVEN
;
639 else round
= FP_ROUND_UP
;
643 if(nch
== *locinfo
->lconv
->decimal_point
)
648 else if (!found_digit
)
650 if(nch
!=WEOF
) unget(ctx
);
652 return fpnum(0, 0, 0, 0);
655 while(m
<= UI64_MAX
/16)
658 if (val
== -1) break;
668 if (val
== -1) break;
671 if (val
|| round
!= FP_ROUND_ZERO
)
673 if (val
< 8) round
= FP_ROUND_DOWN
;
674 else if (val
== 8 && round
== FP_ROUND_ZERO
) round
= FP_ROUND_EVEN
;
675 else round
= FP_ROUND_UP
;
681 if (nch
!= WEOF
) unget(ctx
);
682 if (found_dp
) unget(ctx
);
684 return fpnum(0, 0, 0, 0);
687 if(nch
=='p' || nch
=='P') {
688 BOOL found_sign
= FALSE
;
696 } else if(nch
== '+') {
700 if(nch
>='0' && nch
<='9') {
701 while(nch
>='0' && nch
<='9') {
702 if(e
>INT_MAX
/10 || e
*10>INT_MAX
-nch
+'0')
708 if((nch
!=WEOF
) && (nch
< '0' || nch
> '9')) unget(ctx
);
711 if(e
<0 && exp
<INT_MIN
-e
) exp
= INT_MIN
;
712 else if(e
>0 && exp
>INT_MAX
-e
) exp
= INT_MAX
;
715 if(nch
!= WEOF
) unget(ctx
);
716 if(found_sign
) unget(ctx
);
721 return fpnum(sign
, exp
, m
, round
);
725 /* Converts first 3 limbs to ULONGLONG */
726 /* Return FALSE on overflow */
727 static inline BOOL
bnum_to_mant(struct bnum
*b
, ULONGLONG
*m
)
729 if(UI64_MAX
/ LIMB_MAX
/ LIMB_MAX
< b
->data
[bnum_idx(b
, b
->e
-1)]) return FALSE
;
730 *m
= (ULONGLONG
)b
->data
[bnum_idx(b
, b
->e
-1)] * LIMB_MAX
* LIMB_MAX
;
731 if(b
->b
== b
->e
-1) return TRUE
;
732 if(UI64_MAX
- *m
< (ULONGLONG
)b
->data
[bnum_idx(b
, b
->e
-2)] * LIMB_MAX
) return FALSE
;
733 *m
+= (ULONGLONG
)b
->data
[bnum_idx(b
, b
->e
-2)] * LIMB_MAX
;
734 if(b
->b
== b
->e
-2) return TRUE
;
735 if(UI64_MAX
- *m
< b
->data
[bnum_idx(b
, b
->e
-3)]) return FALSE
;
736 *m
+= b
->data
[bnum_idx(b
, b
->e
-3)];
740 static struct fpnum
fpnum_parse_bnum(wchar_t (*get
)(void *ctx
), void (*unget
)(void *ctx
),
741 void *ctx
, pthreadlocinfo locinfo
, BOOL ldouble
, struct bnum
*b
)
743 #if _MSVCR_VER >= 140
744 const wchar_t _infinity
[] = L
"infinity";
745 const wchar_t _nan
[] = L
"nan";
746 const wchar_t *str_match
= NULL
;
749 BOOL found_digit
= FALSE
, found_dp
= FALSE
, found_sign
= FALSE
;
750 int e2
= 0, dp
=0, sign
=1, off
, limb_digits
= 0, i
;
751 enum fpmod round
= FP_ROUND_ZERO
;
760 } else if(nch
== '+') {
765 #if _MSVCR_VER >= 140
766 if(nch
== _infinity
[0] || nch
== _toupper(_infinity
[0]))
767 str_match
= _infinity
;
768 if(nch
== _nan
[0] || nch
== _toupper(_nan
[0]))
770 while(str_match
&& nch
!= WEOF
&&
771 (nch
== str_match
[matched
] || nch
== _toupper(str_match
[matched
]))) {
777 if(matched
>= 8) keep
= 8;
778 else if(matched
>= 3) keep
= 3;
779 if(nch
!= WEOF
) unget(ctx
);
780 for (; matched
> keep
; matched
--) {
784 if (str_match
== _infinity
)
785 return fpnum(sign
, 0, 0, FP_VAL_INFINITY
);
786 if (str_match
== _nan
)
787 return fpnum(sign
, 0, 0, FP_VAL_NAN
);
788 } else if(found_sign
) {
792 return fpnum(0, 0, 0, 0);
798 if(nch
== 'x' || nch
== 'X')
799 return fpnum_parse16(get
, unget
, ctx
, sign
, locinfo
);
811 while(nch
>='0' && nch
<='9') {
813 if(limb_digits
== LIMB_DIGITS
) {
814 if(bnum_idx(b
, b
->b
-1) == bnum_idx(b
, b
->e
)) break;
817 b
->data
[bnum_idx(b
, b
->b
)] = 0;
822 b
->data
[bnum_idx(b
, b
->b
)] = b
->data
[bnum_idx(b
, b
->b
)] * 10 + nch
- '0';
827 while(nch
>='0' && nch
<='9') {
828 if(nch
!= '0') b
->data
[bnum_idx(b
, b
->b
)] |= 1;
833 if(nch
== *locinfo
->lconv
->decimal_point
) {
838 /* skip leading '0' */
839 if(nch
=='0' && !limb_digits
&& !b
->b
) {
847 while(nch
>='0' && nch
<='9') {
849 if(limb_digits
== LIMB_DIGITS
) {
850 if(bnum_idx(b
, b
->b
-1) == bnum_idx(b
, b
->e
)) break;
853 b
->data
[bnum_idx(b
, b
->b
)] = 0;
858 b
->data
[bnum_idx(b
, b
->b
)] = b
->data
[bnum_idx(b
, b
->b
)] * 10 + nch
- '0';
862 while(nch
>='0' && nch
<='9') {
863 if(nch
!= '0') b
->data
[bnum_idx(b
, b
->b
)] |= 1;
868 if(nch
!= WEOF
) unget(ctx
);
869 if(found_dp
) unget(ctx
);
870 if(found_sign
) unget(ctx
);
871 return fpnum(0, 0, 0, 0);
874 if(nch
=='e' || nch
=='E' || nch
=='d' || nch
=='D') {
882 } else if(nch
== '+') {
889 if(nch
>='0' && nch
<='9') {
890 while(nch
>='0' && nch
<='9') {
891 if(e
>INT_MAX
/10 || e
*10>INT_MAX
-nch
+'0')
897 if(nch
!= WEOF
) unget(ctx
);
900 if(e
<0 && dp
<INT_MIN
-e
) dp
= INT_MIN
;
901 else if(e
>0 && dp
>INT_MAX
-e
) dp
= INT_MAX
;
904 if(nch
!= WEOF
) unget(ctx
);
905 if(found_sign
) unget(ctx
);
908 } else if(nch
!= WEOF
) {
912 if(!b
->data
[bnum_idx(b
, b
->e
-1)])
913 return fpnum(sign
, 0, 0, 0);
915 /* Fill last limb with 0 if needed */
917 for(; limb_digits
!= LIMB_DIGITS
; limb_digits
++)
918 b
->data
[bnum_idx(b
, b
->b
)] *= 10;
920 for(; bnum_idx(b
, b
->b
) < bnum_idx(b
, b
->e
); b
->b
++) {
921 if(b
->data
[bnum_idx(b
, b
->b
)]) break;
924 /* move decimal point to limb boundary */
925 if(limb_digits
==dp
&& b
->b
==b
->e
-1)
926 return fpnum(sign
, 0, b
->data
[bnum_idx(b
, b
->e
-1)], FP_ROUND_ZERO
);
927 off
= (dp
- limb_digits
) % LIMB_DIGITS
;
928 if(off
< 0) off
+= LIMB_DIGITS
;
929 if(off
) bnum_mult(b
, p10s
[off
]);
931 if(dp
-1 > (ldouble
? DBL80_MAX_10_EXP
: DBL_MAX_10_EXP
))
932 return fpnum(sign
, INT_MAX
, 1, FP_ROUND_ZERO
);
933 /* Count part of exponent stored in denormalized mantissa. */
934 /* Increase exponent range to handle subnormals. */
935 if(dp
-1 < (ldouble
? DBL80_MIN_10_EXP
: DBL_MIN_10_EXP
-DBL_DIG
-18))
936 return fpnum(sign
, INT_MIN
, 1, FP_ROUND_ZERO
);
938 while(dp
> 3*LIMB_DIGITS
) {
939 if(bnum_rshift(b
, 9)) dp
-= LIMB_DIGITS
;
942 while(dp
<= 2*LIMB_DIGITS
) {
943 if(bnum_lshift(b
, 29)) dp
+= LIMB_DIGITS
;
946 /* Make sure most significant mantissa bit will be set */
947 while(b
->data
[bnum_idx(b
, b
->e
-1)] <= 9) {
951 while(!bnum_to_mant(b
, &m
)) {
956 if(b
->e
-4 >= b
->b
&& b
->data
[bnum_idx(b
, b
->e
-4)]) {
957 if(b
->data
[bnum_idx(b
, b
->e
-4)] > LIMB_MAX
/2) round
= FP_ROUND_UP
;
958 else if(b
->data
[bnum_idx(b
, b
->e
-4)] == LIMB_MAX
/2) round
= FP_ROUND_EVEN
;
959 else round
= FP_ROUND_DOWN
;
961 if(round
== FP_ROUND_ZERO
|| round
== FP_ROUND_EVEN
) {
962 for(i
=b
->e
-5; i
>=b
->b
; i
--) {
963 if(!b
->data
[bnum_idx(b
, b
->b
)]) continue;
964 if(round
== FP_ROUND_EVEN
) round
= FP_ROUND_UP
;
965 else round
= FP_ROUND_DOWN
;
969 return fpnum(sign
, e2
, m
, round
);
972 struct fpnum
fpnum_parse(wchar_t (*get
)(void *ctx
), void (*unget
)(void *ctx
),
973 void *ctx
, pthreadlocinfo locinfo
, BOOL ldouble
)
976 BYTE bnum_data
[FIELD_OFFSET(struct bnum
, data
[BNUM_PREC64
])];
977 struct bnum
*b
= (struct bnum
*)bnum_data
;
979 b
->size
= BNUM_PREC64
;
980 return fpnum_parse_bnum(get
, unget
, ctx
, locinfo
, ldouble
, b
);
982 BYTE bnum_data
[FIELD_OFFSET(struct bnum
, data
[BNUM_PREC80
])];
983 struct bnum
*b
= (struct bnum
*)bnum_data
;
985 b
->size
= BNUM_PREC80
;
986 return fpnum_parse_bnum(get
, unget
, ctx
, locinfo
, ldouble
, b
);
990 static wchar_t strtod_str_get(void *ctx
)
992 const char **p
= ctx
;
993 if (!**p
) return WEOF
;
997 static void strtod_str_unget(void *ctx
)
999 const char **p
= ctx
;
1003 static inline double strtod_helper(const char *str
, char **end
, _locale_t locale
, int *perr
)
1005 pthreadlocinfo locinfo
;
1006 const char *beg
, *p
;
1011 if (perr
) *perr
= 0;
1016 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) {
1017 if (end
) *end
= NULL
;
1022 locinfo
= get_locinfo();
1024 locinfo
= locale
->locinfo
;
1027 while(_isspace_l((unsigned char)*p
, locale
))
1031 fp
= fpnum_parse(strtod_str_get
, strtod_str_unget
, &p
, locinfo
, FALSE
);
1032 if (end
) *end
= (p
== beg
? (char*)str
: (char*)p
);
1034 err
= fpnum_double(&fp
, &ret
);
1035 if (perr
) *perr
= err
;
1036 else if(err
) *_errno() = err
;
1040 /*********************************************************************
1041 * _strtod_l (MSVCRT.@)
1043 double CDECL
_strtod_l(const char *str
, char **end
, _locale_t locale
)
1045 return strtod_helper(str
, end
, locale
, NULL
);
1048 /*********************************************************************
1051 double CDECL
strtod( const char *str
, char **end
)
1053 return _strtod_l( str
, end
, NULL
);
1058 /*********************************************************************
1059 * strtof_l (MSVCR120.@)
1061 float CDECL
_strtof_l( const char *str
, char **end
, _locale_t locale
)
1063 return _strtod_l(str
, end
, locale
);
1066 /*********************************************************************
1067 * strtof (MSVCR120.@)
1069 float CDECL
strtof( const char *str
, char **end
)
1071 return _strtof_l(str
, end
, NULL
);
1074 #endif /* _MSVCR_VER>=120 */
1076 /*********************************************************************
1079 double CDECL
atof( const char *str
)
1081 return _strtod_l(str
, NULL
, NULL
);
1084 /*********************************************************************
1085 * _atof_l (MSVCRT.@)
1087 double CDECL
_atof_l( const char *str
, _locale_t locale
)
1089 return _strtod_l(str
, NULL
, locale
);
1092 /*********************************************************************
1093 * _atoflt_l (MSVCRT.@)
1095 int CDECL
_atoflt_l(_CRT_FLOAT
*value
, char *str
, _locale_t locale
)
1100 d
= strtod_helper(str
, NULL
, locale
, &err
);
1104 if((d
!=0 || err
) && value
->f
>-FLT_MIN
&& value
->f
<FLT_MIN
)
1109 /*********************************************************************
1110 * _atoflt (MSVCR100.@)
1112 int CDECL
_atoflt(_CRT_FLOAT
*value
, char *str
)
1114 return _atoflt_l(value
, str
, NULL
);
1117 /*********************************************************************
1118 * _atodbl_l (MSVCRT.@)
1120 int CDECL
_atodbl_l(_CRT_DOUBLE
*value
, char *str
, _locale_t locale
)
1124 value
->x
= strtod_helper(str
, NULL
, locale
, &err
);
1127 if((value
->x
!=0 || err
) && value
->x
>-DBL_MIN
&& value
->x
<DBL_MIN
)
1132 /*********************************************************************
1133 * _atodbl (MSVCRT.@)
1135 int CDECL
_atodbl(_CRT_DOUBLE
*value
, char *str
)
1137 return _atodbl_l(value
, str
, NULL
);
1140 /*********************************************************************
1141 * _strcoll_l (MSVCRT.@)
1143 int CDECL
_strcoll_l( const char* str1
, const char* str2
, _locale_t locale
)
1145 pthreadlocinfo locinfo
;
1148 locinfo
= get_locinfo();
1150 locinfo
= locale
->locinfo
;
1152 if(!locinfo
->lc_handle
[LC_COLLATE
])
1153 return strcmp(str1
, str2
);
1154 return CompareStringA(locinfo
->lc_handle
[LC_COLLATE
], 0, str1
, -1, str2
, -1)-CSTR_EQUAL
;
1157 /*********************************************************************
1158 * strcoll (MSVCRT.@)
1160 int CDECL
strcoll( const char* str1
, const char* str2
)
1162 return _strcoll_l(str1
, str2
, NULL
);
1165 /*********************************************************************
1166 * _stricoll_l (MSVCRT.@)
1168 int CDECL
_stricoll_l( const char* str1
, const char* str2
, _locale_t locale
)
1170 pthreadlocinfo locinfo
;
1173 locinfo
= get_locinfo();
1175 locinfo
= locale
->locinfo
;
1177 if(!locinfo
->lc_handle
[LC_COLLATE
])
1178 return _stricmp(str1
, str2
);
1179 return CompareStringA(locinfo
->lc_handle
[LC_COLLATE
], NORM_IGNORECASE
,
1180 str1
, -1, str2
, -1)-CSTR_EQUAL
;
1183 /*********************************************************************
1184 * _stricoll (MSVCRT.@)
1186 int CDECL
_stricoll( const char* str1
, const char* str2
)
1188 return _stricoll_l(str1
, str2
, NULL
);
1191 /*********************************************************************
1192 * _strncoll_l (MSVCRT.@)
1194 int CDECL
_strncoll_l( const char* str1
, const char* str2
, size_t count
, _locale_t locale
)
1196 pthreadlocinfo locinfo
;
1199 locinfo
= get_locinfo();
1201 locinfo
= locale
->locinfo
;
1203 if(!locinfo
->lc_handle
[LC_COLLATE
])
1204 return strncmp(str1
, str2
, count
);
1205 return CompareStringA(locinfo
->lc_handle
[LC_COLLATE
], 0,
1206 str1
, strnlen(str1
, count
),
1207 str2
, strnlen(str2
, count
))-CSTR_EQUAL
;
1210 /*********************************************************************
1211 * _strncoll (MSVCRT.@)
1213 int CDECL
_strncoll( const char* str1
, const char* str2
, size_t count
)
1215 return _strncoll_l(str1
, str2
, count
, NULL
);
1218 /*********************************************************************
1219 * _strnicoll_l (MSVCRT.@)
1221 int CDECL
_strnicoll_l( const char* str1
, const char* str2
, size_t count
, _locale_t locale
)
1223 pthreadlocinfo locinfo
;
1226 locinfo
= get_locinfo();
1228 locinfo
= locale
->locinfo
;
1230 if(!locinfo
->lc_handle
[LC_COLLATE
])
1231 return _strnicmp(str1
, str2
, count
);
1232 return CompareStringA(locinfo
->lc_handle
[LC_COLLATE
], NORM_IGNORECASE
,
1233 str1
, strnlen(str1
, count
),
1234 str2
, strnlen(str2
, count
))-CSTR_EQUAL
;
1237 /*********************************************************************
1238 * _strnicoll (MSVCRT.@)
1240 int CDECL
_strnicoll( const char* str1
, const char* str2
, size_t count
)
1242 return _strnicoll_l(str1
, str2
, count
, NULL
);
1245 /*********************************************************************
1246 * strncpy (MSVCRT.@)
1248 char* __cdecl
strncpy(char *dst
, const char *src
, size_t len
)
1252 for(i
=0; i
<len
; i
++)
1253 if((dst
[i
] = src
[i
]) == '\0') break;
1255 while (i
< len
) dst
[i
++] = 0;
1260 /*********************************************************************
1263 char* CDECL
strcpy(char *dst
, const char *src
)
1266 while ((*dst
++ = *src
++));
1270 /*********************************************************************
1271 * strcpy_s (MSVCRT.@)
1273 int CDECL
strcpy_s( char* dst
, size_t elem
, const char* src
)
1276 if(!elem
) return EINVAL
;
1277 if(!dst
) return EINVAL
;
1284 for(i
= 0; i
< elem
; i
++)
1286 if((dst
[i
] = src
[i
]) == '\0') return 0;
1292 /*********************************************************************
1293 * strcat_s (MSVCRT.@)
1295 int CDECL
strcat_s( char* dst
, size_t elem
, const char* src
)
1298 if(!dst
) return EINVAL
;
1299 if(elem
== 0) return EINVAL
;
1306 for(i
= 0; i
< elem
; i
++)
1310 for(j
= 0; (j
+ i
) < elem
; j
++)
1312 if((dst
[j
+ i
] = src
[j
]) == '\0') return 0;
1316 /* Set the first element to 0, not the first element after the skipped part */
1321 /*********************************************************************
1324 char* __cdecl
strcat( char *dst
, const char *src
)
1328 while ((*d
++ = *src
++));
1332 /*********************************************************************
1333 * strncat_s (MSVCRT.@)
1335 int CDECL
strncat_s( char* dst
, size_t elem
, const char* src
, size_t count
)
1339 if (!MSVCRT_CHECK_PMT(dst
!= 0)) return EINVAL
;
1340 if (!MSVCRT_CHECK_PMT(elem
!= 0)) return EINVAL
;
1341 if (!MSVCRT_CHECK_PMT(src
!= 0))
1347 for(i
= 0; i
< elem
; i
++)
1351 for(j
= 0; (j
+ i
) < elem
; j
++)
1353 if(count
== MSVCRT__TRUNCATE
&& j
+ i
== elem
- 1)
1358 if(j
== count
|| (dst
[j
+ i
] = src
[j
]) == '\0')
1366 /* Set the first element to 0, not the first element after the skipped part */
1371 /*********************************************************************
1372 * strncat (MSVCRT.@)
1374 char* __cdecl
strncat(char *dst
, const char *src
, size_t len
)
1378 for ( ; len
&& *src
; d
++, src
++, len
--) *d
= *src
;
1383 /*********************************************************************
1384 * _strxfrm_l (MSVCRT.@)
1386 size_t CDECL
_strxfrm_l( char *dest
, const char *src
,
1387 size_t len
, _locale_t locale
)
1389 pthreadlocinfo locinfo
;
1392 if(!MSVCRT_CHECK_PMT(src
)) return INT_MAX
;
1393 if(!MSVCRT_CHECK_PMT(dest
|| !len
)) return INT_MAX
;
1396 FIXME("len > INT_MAX not supported\n");
1401 locinfo
= get_locinfo();
1403 locinfo
= locale
->locinfo
;
1405 if(!locinfo
->lc_handle
[LC_COLLATE
]) {
1406 strncpy(dest
, src
, len
);
1410 ret
= LCMapStringA(locinfo
->lc_handle
[LC_COLLATE
],
1411 LCMAP_SORTKEY
, src
, -1, NULL
, 0);
1413 if(len
) dest
[0] = 0;
1417 if(!len
) return ret
-1;
1425 return LCMapStringA(locinfo
->lc_handle
[LC_COLLATE
],
1426 LCMAP_SORTKEY
, src
, -1, dest
, len
) - 1;
1429 /*********************************************************************
1430 * strxfrm (MSVCRT.@)
1432 size_t CDECL
strxfrm( char *dest
, const char *src
, size_t len
)
1434 return _strxfrm_l(dest
, src
, len
, NULL
);
1437 /********************************************************************
1438 * __STRINGTOLD_L (MSVCR80.@)
1440 int CDECL
__STRINGTOLD_L( MSVCRT__LDOUBLE
*value
, char **endptr
,
1441 const char *str
, int flags
, _locale_t locale
)
1443 pthreadlocinfo locinfo
;
1444 const char *beg
, *p
;
1448 if (flags
) FIXME("flags not supported: %x\n", flags
);
1451 locinfo
= get_locinfo();
1453 locinfo
= locale
->locinfo
;
1456 while (_isspace_l((unsigned char)*p
, locale
))
1460 fp
= fpnum_parse(strtod_str_get
, strtod_str_unget
, &p
, locinfo
, TRUE
);
1461 if (endptr
) *endptr
= (p
== beg
? (char*)str
: (char*)p
);
1462 if (p
== beg
) ret
= 4;
1464 err
= fpnum_ldouble(&fp
, value
);
1465 if (err
) ret
= (value
->x80
[2] & 0x7fff ? 2 : 1);
1469 /********************************************************************
1470 * __STRINGTOLD (MSVCRT.@)
1472 int CDECL
__STRINGTOLD( MSVCRT__LDOUBLE
*value
, char **endptr
, const char *str
, int flags
)
1474 return __STRINGTOLD_L( value
, endptr
, str
, flags
, NULL
);
1477 /********************************************************************
1478 * _atoldbl_l (MSVCRT.@)
1480 int CDECL
_atoldbl_l( MSVCRT__LDOUBLE
*value
, char *str
, _locale_t locale
)
1483 switch(__STRINGTOLD_L( value
, &endptr
, str
, 0, locale
))
1485 case 1: return _UNDERFLOW
;
1486 case 2: return _OVERFLOW
;
1491 /********************************************************************
1492 * _atoldbl (MSVCRT.@)
1494 int CDECL
_atoldbl(_LDOUBLE
*value
, char *str
)
1496 return _atoldbl_l( (MSVCRT__LDOUBLE
*)value
, str
, NULL
);
1499 /*********************************************************************
1502 size_t __cdecl
strlen(const char *str
)
1504 const char *s
= str
;
1509 /******************************************************************
1510 * strnlen (MSVCRT.@)
1512 size_t CDECL
strnlen(const char *s
, size_t maxlen
)
1516 for(i
=0; i
<maxlen
; i
++)
1522 /*********************************************************************
1523 * _strtoi64_l (MSVCRT.@)
1525 * FIXME: locale parameter is ignored
1527 __int64 CDECL
_strtoi64_l(const char *nptr
, char **endptr
, int base
, _locale_t locale
)
1529 const char *p
= nptr
;
1530 BOOL negative
= FALSE
;
1531 BOOL got_digit
= FALSE
;
1534 TRACE("(%s %p %d %p)\n", debugstr_a(nptr
), endptr
, base
, locale
);
1536 if (!MSVCRT_CHECK_PMT(nptr
!= NULL
)) return 0;
1537 if (!MSVCRT_CHECK_PMT(base
== 0 || base
>= 2)) return 0;
1538 if (!MSVCRT_CHECK_PMT(base
<= 36)) return 0;
1540 while(_isspace_l((unsigned char)*nptr
, locale
)) nptr
++;
1545 } else if(*nptr
== '+')
1548 if((base
==0 || base
==16) && *nptr
=='0' && _tolower_l(*(nptr
+1), locale
)=='x') {
1561 char cur
= _tolower_l(*nptr
, locale
);
1564 if(cur
>='0' && cur
<='9') {
1569 if(cur
<'a' || cur
>='a'+base
-10)
1580 if(!negative
&& (ret
>I64_MAX
/base
|| ret
*base
>I64_MAX
-v
)) {
1583 } else if(negative
&& (ret
<I64_MIN
/base
|| ret
*base
<I64_MIN
-v
)) {
1591 *endptr
= (char*)(got_digit
? nptr
: p
);
1596 /*********************************************************************
1597 * _strtoi64 (MSVCRT.@)
1599 __int64 CDECL
_strtoi64(const char *nptr
, char **endptr
, int base
)
1601 return _strtoi64_l(nptr
, endptr
, base
, NULL
);
1604 /*********************************************************************
1605 * _atoi_l (MSVCRT.@)
1607 int __cdecl
_atoi_l(const char *str
, _locale_t locale
)
1609 __int64 ret
= _strtoi64_l(str
, NULL
, 10, locale
);
1614 } else if(ret
< INT_MIN
) {
1621 /*********************************************************************
1625 int __cdecl
atoi(const char *str
)
1633 while(_isspace_l((unsigned char)*str
, NULL
)) str
++;
1637 }else if(*str
== '-') {
1642 while(*str
>='0' && *str
<='9') {
1643 ret
= ret
*10+*str
-'0';
1647 return minus
? -ret
: ret
;
1650 int CDECL
atoi(const char *str
)
1652 return _atoi_l(str
, NULL
);
1656 /******************************************************************
1657 * _atoi64_l (MSVCRT.@)
1659 __int64 CDECL
_atoi64_l(const char *str
, _locale_t locale
)
1661 return _strtoi64_l(str
, NULL
, 10, locale
);
1664 /******************************************************************
1665 * _atoi64 (MSVCRT.@)
1667 __int64 CDECL
_atoi64(const char *str
)
1669 return _strtoi64_l(str
, NULL
, 10, NULL
);
1672 /******************************************************************
1673 * _atol_l (MSVCRT.@)
1675 __msvcrt_long CDECL
_atol_l(const char *str
, _locale_t locale
)
1677 __int64 ret
= _strtoi64_l(str
, NULL
, 10, locale
);
1679 if(ret
> LONG_MAX
) {
1682 } else if(ret
< LONG_MIN
) {
1689 /******************************************************************
1692 __msvcrt_long CDECL
atol(const char *str
)
1697 return _atol_l(str
, NULL
);
1703 /******************************************************************
1704 * _atoll_l (MSVCR120.@)
1706 __int64 CDECL
_atoll_l(const char* str
, _locale_t locale
)
1708 return _strtoi64_l(str
, NULL
, 10, locale
);
1711 /******************************************************************
1712 * atoll (MSVCR120.@)
1714 __int64 CDECL
atoll(const char* str
)
1716 return _atoll_l(str
, NULL
);
1719 #endif /* _MSVCR_VER>=120 */
1721 /******************************************************************
1722 * _strtol_l (MSVCRT.@)
1724 __msvcrt_long CDECL
_strtol_l(const char* nptr
,
1725 char** end
, int base
, _locale_t locale
)
1727 __int64 ret
= _strtoi64_l(nptr
, end
, base
, locale
);
1729 if(ret
> LONG_MAX
) {
1732 } else if(ret
< LONG_MIN
) {
1740 /******************************************************************
1743 __msvcrt_long CDECL
strtol(const char* nptr
, char** end
, int base
)
1745 return _strtol_l(nptr
, end
, base
, NULL
);
1748 /******************************************************************
1749 * _strtoul_l (MSVCRT.@)
1751 __msvcrt_ulong CDECL
_strtoul_l(const char* nptr
, char** end
, int base
, _locale_t locale
)
1753 __int64 ret
= _strtoi64_l(nptr
, end
, base
, locale
);
1755 if(ret
> ULONG_MAX
) {
1758 }else if(ret
< -(__int64
)ULONG_MAX
) {
1766 /******************************************************************
1767 * strtoul (MSVCRT.@)
1769 __msvcrt_ulong CDECL
strtoul(const char* nptr
, char** end
, int base
)
1771 return _strtoul_l(nptr
, end
, base
, NULL
);
1774 /*********************************************************************
1775 * _strtoui64_l (MSVCRT.@)
1777 * FIXME: locale parameter is ignored
1779 unsigned __int64 CDECL
_strtoui64_l(const char *nptr
, char **endptr
, int base
, _locale_t locale
)
1781 const char *p
= nptr
;
1782 BOOL negative
= FALSE
;
1783 BOOL got_digit
= FALSE
;
1784 unsigned __int64 ret
= 0;
1786 TRACE("(%s %p %d %p)\n", debugstr_a(nptr
), endptr
, base
, locale
);
1788 if (!MSVCRT_CHECK_PMT(nptr
!= NULL
)) return 0;
1789 if (!MSVCRT_CHECK_PMT(base
== 0 || base
>= 2)) return 0;
1790 if (!MSVCRT_CHECK_PMT(base
<= 36)) return 0;
1792 while(_isspace_l((unsigned char)*nptr
, locale
)) nptr
++;
1797 } else if(*nptr
== '+')
1800 if((base
==0 || base
==16) && *nptr
=='0' && _tolower_l(*(nptr
+1), locale
)=='x') {
1813 char cur
= _tolower_l(*nptr
, locale
);
1816 if(cur
>='0' && cur
<='9') {
1821 if(cur
<'a' || cur
>='a'+base
-10)
1829 if(ret
>UI64_MAX
/base
|| ret
*base
>UI64_MAX
-v
) {
1837 *endptr
= (char*)(got_digit
? nptr
: p
);
1839 return negative
? -ret
: ret
;
1842 /*********************************************************************
1843 * _strtoui64 (MSVCRT.@)
1845 unsigned __int64 CDECL
_strtoui64(const char *nptr
, char **endptr
, int base
)
1847 return _strtoui64_l(nptr
, endptr
, base
, NULL
);
1850 static int ltoa_helper(__msvcrt_long value
, char *str
, size_t size
, int radix
)
1855 char buffer
[33], *pos
;
1858 if (value
< 0 && radix
== 10)
1865 is_negative
= FALSE
;
1874 digit
= val
% radix
;
1878 *--pos
= '0' + digit
;
1880 *--pos
= 'a' + digit
- 10;
1887 len
= buffer
+ 33 - pos
;
1893 /* Copy the temporary buffer backwards up to the available number of
1894 * characters. Don't copy the negative sign if present. */
1902 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
1906 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
1910 memcpy(str
, pos
, len
);
1914 /*********************************************************************
1915 * _ltoa_s (MSVCRT.@)
1917 int CDECL
_ltoa_s(__msvcrt_long value
, char *str
, size_t size
, int radix
)
1919 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return EINVAL
;
1920 if (!MSVCRT_CHECK_PMT(size
> 0)) return EINVAL
;
1921 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
1927 return ltoa_helper(value
, str
, size
, radix
);
1930 /*********************************************************************
1931 * _ltow_s (MSVCRT.@)
1933 int CDECL
_ltow_s(__msvcrt_long value
, wchar_t *str
, size_t size
, int radix
)
1938 wchar_t buffer
[33], *pos
;
1941 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return EINVAL
;
1942 if (!MSVCRT_CHECK_PMT(size
> 0)) return EINVAL
;
1943 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
1949 if (value
< 0 && radix
== 10)
1956 is_negative
= FALSE
;
1965 digit
= val
% radix
;
1969 *--pos
= '0' + digit
;
1971 *--pos
= 'a' + digit
- 10;
1978 len
= buffer
+ 33 - pos
;
1984 /* Copy the temporary buffer backwards up to the available number of
1985 * characters. Don't copy the negative sign if present. */
1993 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
1997 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
2001 memcpy(str
, pos
, len
* sizeof(wchar_t));
2005 /*********************************************************************
2006 * _itoa_s (MSVCRT.@)
2008 int CDECL
_itoa_s(int value
, char *str
, size_t size
, int radix
)
2010 return _ltoa_s(value
, str
, size
, radix
);
2013 /*********************************************************************
2016 char* CDECL
_itoa(int value
, char *str
, int radix
)
2018 return ltoa_helper(value
, str
, SIZE_MAX
, radix
) ? NULL
: str
;
2021 /*********************************************************************
2022 * _itow_s (MSVCRT.@)
2024 int CDECL
_itow_s(int value
, wchar_t *str
, size_t size
, int radix
)
2026 return _ltow_s(value
, str
, size
, radix
);
2029 /*********************************************************************
2030 * _ui64toa_s (MSVCRT.@)
2032 int CDECL
_ui64toa_s(unsigned __int64 value
, char *str
,
2033 size_t size
, int radix
)
2035 char buffer
[65], *pos
;
2038 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return EINVAL
;
2039 if (!MSVCRT_CHECK_PMT(size
> 0)) return EINVAL
;
2040 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
2050 digit
= value
%radix
;
2056 *--pos
= 'a'+digit
-10;
2059 if(buffer
-pos
+65 > size
) {
2060 MSVCRT_INVALID_PMT("str[size] is too small", EINVAL
);
2064 memcpy(str
, pos
, buffer
-pos
+65);
2068 /*********************************************************************
2069 * _ui64tow_s (MSVCRT.@)
2071 int CDECL
_ui64tow_s( unsigned __int64 value
, wchar_t *str
,
2072 size_t size
, int radix
)
2074 wchar_t buffer
[65], *pos
;
2077 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return EINVAL
;
2078 if (!MSVCRT_CHECK_PMT(size
> 0)) return EINVAL
;
2079 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
2089 digit
= value
% radix
;
2090 value
= value
/ radix
;
2092 *--pos
= '0' + digit
;
2094 *--pos
= 'a' + digit
- 10;
2095 } while (value
!= 0);
2097 if(buffer
-pos
+65 > size
) {
2098 MSVCRT_INVALID_PMT("str[size] is too small", EINVAL
);
2102 memcpy(str
, pos
, (buffer
-pos
+65)*sizeof(wchar_t));
2106 /*********************************************************************
2107 * _ultoa_s (MSVCRT.@)
2109 int CDECL
_ultoa_s(__msvcrt_ulong value
, char *str
, size_t size
, int radix
)
2111 __msvcrt_ulong digit
;
2112 char buffer
[33], *pos
;
2115 if (!str
|| !size
|| radix
< 2 || radix
> 36)
2129 digit
= value
% radix
;
2133 *--pos
= '0' + digit
;
2135 *--pos
= 'a' + digit
- 10;
2139 len
= buffer
+ 33 - pos
;
2145 /* Copy the temporary buffer backwards up to the available number of
2148 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2156 memcpy(str
, pos
, len
);
2160 /*********************************************************************
2161 * _ultow_s (MSVCRT.@)
2163 int CDECL
_ultow_s(__msvcrt_ulong value
, wchar_t *str
, size_t size
, int radix
)
2165 __msvcrt_ulong digit
;
2166 WCHAR buffer
[33], *pos
;
2169 if (!str
|| !size
|| radix
< 2 || radix
> 36)
2183 digit
= value
% radix
;
2187 *--pos
= '0' + digit
;
2189 *--pos
= 'a' + digit
- 10;
2193 len
= buffer
+ 33 - pos
;
2199 /* Copy the temporary buffer backwards up to the available number of
2202 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2210 memcpy(str
, pos
, len
* sizeof(wchar_t));
2214 /*********************************************************************
2215 * _i64toa_s (MSVCRT.@)
2217 int CDECL
_i64toa_s(__int64 value
, char *str
, size_t size
, int radix
)
2219 unsigned __int64 val
;
2222 char buffer
[65], *pos
;
2225 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return EINVAL
;
2226 if (!MSVCRT_CHECK_PMT(size
> 0)) return EINVAL
;
2227 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
2233 if (value
< 0 && radix
== 10)
2240 is_negative
= FALSE
;
2249 digit
= val
% radix
;
2253 *--pos
= '0' + digit
;
2255 *--pos
= 'a' + digit
- 10;
2262 len
= buffer
+ 65 - pos
;
2268 /* Copy the temporary buffer backwards up to the available number of
2269 * characters. Don't copy the negative sign if present. */
2277 for (pos
= buffer
+ 63, i
= 0; i
< size
; i
++)
2281 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
2285 memcpy(str
, pos
, len
);
2289 /*********************************************************************
2290 * _i64tow_s (MSVCRT.@)
2292 int CDECL
_i64tow_s(__int64 value
, wchar_t *str
, size_t size
, int radix
)
2294 unsigned __int64 val
;
2297 wchar_t buffer
[65], *pos
;
2300 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return EINVAL
;
2301 if (!MSVCRT_CHECK_PMT(size
> 0)) return EINVAL
;
2302 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
2308 if (value
< 0 && radix
== 10)
2315 is_negative
= FALSE
;
2324 digit
= val
% radix
;
2328 *--pos
= '0' + digit
;
2330 *--pos
= 'a' + digit
- 10;
2337 len
= buffer
+ 65 - pos
;
2343 /* Copy the temporary buffer backwards up to the available number of
2344 * characters. Don't copy the negative sign if present. */
2352 for (pos
= buffer
+ 63, i
= 0; i
< size
; i
++)
2356 MSVCRT_INVALID_PMT("str[size] is too small", ERANGE
);
2360 memcpy(str
, pos
, len
* sizeof(wchar_t));
2364 #define I10_OUTPUT_MAX_PREC 21
2365 /* Internal structure used by $I10_OUTPUT */
2366 struct _I10_OUTPUT_DATA
{
2370 char str
[I10_OUTPUT_MAX_PREC
+1]; /* add space for '\0' */
2373 /*********************************************************************
2374 * $I10_OUTPUT (MSVCRT.@)
2375 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
2376 * prec - precision of part, we're interested in
2377 * flag - 0 for first prec digits, 1 for fractional part
2378 * data - data to be populated
2381 * 0 if given double is NaN or INF
2385 * Native sets last byte of data->str to '0' or '9', I don't know what
2386 * it means. Current implementation sets it always to '0'.
2388 int CDECL
I10_OUTPUT(MSVCRT__LDOUBLE ld80
, int prec
, int flag
, struct _I10_OUTPUT_DATA
*data
)
2393 char buf
[I10_OUTPUT_MAX_PREC
+9]; /* 9 = strlen("0.e+0000") + '\0' */
2396 if ((ld80
.x80
[2] & 0x7fff) == 0x7fff)
2398 if (ld80
.x80
[0] == 0 && ld80
.x80
[1] == 0x80000000)
2399 strcpy( data
->str
, "1#INF" );
2401 strcpy( data
->str
, (ld80
.x80
[1] & 0x40000000) ? "1#QNAN" : "1#SNAN" );
2403 data
->sign
= (ld80
.x80
[2] & 0x8000) ? '-' : ' ';
2404 data
->len
= strlen(data
->str
);
2408 num
.sign
= (ld80
.x80
[2] & 0x8000) ? -1 : 1;
2409 num
.exp
= (ld80
.x80
[2] & 0x7fff) - 0x3fff - 63;
2410 num
.m
= ld80
.x80
[0] | ((ULONGLONG
)ld80
.x80
[1] << 32);
2411 num
.mod
= FP_ROUND_EVEN
;
2412 fpnum_double( &num
, &d
);
2413 TRACE("(%lf %d %x %p)\n", d
, prec
, flag
, data
);
2422 int exp
= 1 + MSVCRT_floor(MSVCRT_log10(d
));
2430 if(prec
+1 > I10_OUTPUT_MAX_PREC
)
2431 prec
= I10_OUTPUT_MAX_PREC
-1;
2437 MSVCRT_sprintf(format
, "%%.%dle", prec
);
2438 MSVCRT_sprintf(buf
, format
, d
);
2441 data
->pos
= atoi(buf
+prec
+3);
2445 for(p
= buf
+prec
+1; p
>buf
+1 && *p
=='0'; p
--);
2448 memcpy(data
->str
, buf
+1, data
->len
);
2449 data
->str
[data
->len
] = '\0';
2451 if(buf
[1]!='0' && prec
-data
->len
+1>0)
2452 memcpy(data
->str
+data
->len
+1, buf
+data
->len
+1, prec
-data
->len
+1);
2456 #undef I10_OUTPUT_MAX_PREC
2458 /*********************************************************************
2461 int __cdecl
memcmp(const void *ptr1
, const void *ptr2
, size_t n
)
2463 const unsigned char *p1
, *p2
;
2465 for (p1
= ptr1
, p2
= ptr2
; n
; n
--, p1
++, p2
++)
2467 if (*p1
< *p2
) return -1;
2468 if (*p1
> *p2
) return 1;
2473 /*********************************************************************
2474 * memmove (MSVCRT.@)
2476 #ifdef WORDS_BIGENDIAN
2477 # define MERGE(w1, sh1, w2, sh2) ((w1 << sh1) | (w2 >> sh2))
2479 # define MERGE(w1, sh1, w2, sh2) ((w1 >> sh1) | (w2 << sh2))
2481 void * __cdecl
memmove(void *dst
, const void *src
, size_t n
)
2483 unsigned char *d
= dst
;
2484 const unsigned char *s
= src
;
2489 if ((size_t)dst
- (size_t)src
>= n
)
2491 for (; (size_t)d
% sizeof(size_t) && n
; n
--) *d
++ = *s
++;
2493 sh1
= 8 * ((size_t)s
% sizeof(size_t));
2496 while (n
>= sizeof(size_t))
2498 *(size_t*)d
= *(size_t*)s
;
2499 s
+= sizeof(size_t);
2500 d
+= sizeof(size_t);
2501 n
-= sizeof(size_t);
2504 else if (n
>= 2 * sizeof(size_t))
2506 int sh2
= 8 * sizeof(size_t) - sh1
;
2513 s
+= sizeof(size_t);
2515 *(size_t*)d
= MERGE(x
, sh1
, y
, sh2
);
2516 d
+= sizeof(size_t);
2518 s
+= sizeof(size_t);
2520 *(size_t*)d
= MERGE(y
, sh1
, x
, sh2
);
2521 d
+= sizeof(size_t);
2523 n
-= 2 * sizeof(size_t);
2524 } while (n
>= 2 * sizeof(size_t));
2527 while (n
--) *d
++ = *s
++;
2535 for (; (size_t)d
% sizeof(size_t) && n
; n
--) *--d
= *--s
;
2537 sh1
= 8 * ((size_t)s
% sizeof(size_t));
2540 while (n
>= sizeof(size_t))
2542 s
-= sizeof(size_t);
2543 d
-= sizeof(size_t);
2544 *(size_t*)d
= *(size_t*)s
;
2545 n
-= sizeof(size_t);
2548 else if (n
>= 2 * sizeof(size_t))
2550 int sh2
= 8 * sizeof(size_t) - sh1
;
2557 s
-= sizeof(size_t);
2559 d
-= sizeof(size_t);
2560 *(size_t*)d
= MERGE(y
, sh1
, x
, sh2
);
2562 s
-= sizeof(size_t);
2564 d
-= sizeof(size_t);
2565 *(size_t*)d
= MERGE(x
, sh1
, y
, sh2
);
2567 n
-= 2 * sizeof(size_t);
2568 } while (n
>= 2 * sizeof(size_t));
2571 while (n
--) *--d
= *--s
;
2577 /*********************************************************************
2580 void * __cdecl
memcpy(void *dst
, const void *src
, size_t n
)
2582 return memmove(dst
, src
, n
);
2585 /*********************************************************************
2588 void* __cdecl
memset(void *dst
, int c
, size_t n
)
2590 volatile unsigned char *d
= dst
; /* avoid gcc optimizations */
2591 while (n
--) *d
++ = c
;
2595 /*********************************************************************
2598 char* __cdecl
strchr(const char *str
, int c
)
2602 if (*str
== (char)c
) return (char*)str
;
2607 /*********************************************************************
2608 * strrchr (MSVCRT.@)
2610 char* __cdecl
strrchr(const char *str
, int c
)
2613 do { if (*str
== (char)c
) ret
= (char*)str
; } while (*str
++);
2617 /*********************************************************************
2620 void* __cdecl
memchr(const void *ptr
, int c
, size_t n
)
2622 const unsigned char *p
= ptr
;
2624 for (p
= ptr
; n
; n
--, p
++) if (*p
== c
) return (void *)(ULONG_PTR
)p
;
2628 /*********************************************************************
2631 int __cdecl
strcmp(const char *str1
, const char *str2
)
2633 while (*str1
&& *str1
== *str2
) { str1
++; str2
++; }
2634 if ((unsigned char)*str1
> (unsigned char)*str2
) return 1;
2635 if ((unsigned char)*str1
< (unsigned char)*str2
) return -1;
2639 /*********************************************************************
2640 * strncmp (MSVCRT.@)
2642 int __cdecl
strncmp(const char *str1
, const char *str2
, size_t len
)
2645 while (--len
&& *str1
&& *str1
== *str2
) { str1
++; str2
++; }
2646 return (unsigned char)*str1
- (unsigned char)*str2
;
2649 /*********************************************************************
2650 * _strnicmp_l (MSVCRT.@)
2652 int __cdecl
_strnicmp_l(const char *s1
, const char *s2
,
2653 size_t count
, _locale_t locale
)
2655 pthreadlocinfo locinfo
;
2658 if(s1
==NULL
|| s2
==NULL
)
2659 return MSVCRT__NLSCMPERROR
;
2665 locinfo
= get_locinfo();
2667 locinfo
= locale
->locinfo
;
2669 if(!locinfo
->lc_handle
[LC_CTYPE
])
2672 if ((c1
= *s1
++) >= 'A' && c1
<= 'Z')
2674 if ((c2
= *s2
++) >= 'A' && c2
<= 'Z')
2676 }while(--count
&& c1
&& c1
==c2
);
2682 c1
= _tolower_l((unsigned char)*s1
++, locale
);
2683 c2
= _tolower_l((unsigned char)*s2
++, locale
);
2684 }while(--count
&& c1
&& c1
==c2
);
2689 /*********************************************************************
2690 * _stricmp_l (MSVCRT.@)
2692 int __cdecl
_stricmp_l(const char *s1
, const char *s2
, _locale_t locale
)
2694 return _strnicmp_l(s1
, s2
, -1, locale
);
2697 /*********************************************************************
2698 * _strnicmp (MSVCRT.@)
2700 int __cdecl
_strnicmp(const char *s1
, const char *s2
, size_t count
)
2702 return _strnicmp_l(s1
, s2
, count
, NULL
);
2705 /*********************************************************************
2706 * _stricmp (MSVCRT.@)
2708 int __cdecl
_stricmp(const char *s1
, const char *s2
)
2710 return _strnicmp_l(s1
, s2
, -1, NULL
);
2713 /*********************************************************************
2716 char* __cdecl
strstr(const char *haystack
, const char *needle
)
2718 size_t i
, j
, len
, needle_len
, lps_len
;
2721 needle_len
= strlen(needle
);
2722 if (!needle_len
) return (char*)haystack
;
2723 lps_len
= needle_len
> ARRAY_SIZE(lps
) ? ARRAY_SIZE(lps
) : needle_len
;
2730 if (needle
[i
] == needle
[len
]) lps
[i
++] = ++len
;
2731 else if (len
) len
= lps
[len
-1];
2738 while (j
< lps_len
&& haystack
[i
] && haystack
[i
] == needle
[j
])
2744 if (j
== needle_len
) return (char*)haystack
+ i
- j
;
2747 if (j
== ARRAY_SIZE(lps
) && !strncmp(haystack
+ i
, needle
+ j
, needle_len
- j
))
2748 return (char*)haystack
+ i
- j
;
2751 else if (haystack
[i
]) i
++;
2756 /*********************************************************************
2757 * _memicmp_l (MSVCRT.@)
2759 int __cdecl
_memicmp_l(const void *v1
, const void *v2
, size_t len
, _locale_t locale
)
2761 const char *s1
= v1
, *s2
= v2
;
2764 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
2768 MSVCRT_INVALID_PMT(NULL
, EINVAL
);
2769 return len
? MSVCRT__NLSCMPERROR
: 0;
2775 if ((ret
= _tolower_l(*s1
, locale
) - _tolower_l(*s2
, locale
)))
2783 /*********************************************************************
2784 * _memicmp (MSVCRT.@)
2786 int __cdecl
_memicmp(const void *s1
, const void *s2
, size_t len
)
2788 return _memicmp_l(s1
, s2
, len
, NULL
);
2791 /*********************************************************************
2792 * strcspn (MSVCRT.@)
2794 size_t __cdecl
strcspn(const char *str
, const char *reject
)
2799 memset(rejects
, 0, sizeof(rejects
));
2804 rejects
[(unsigned char)*p
] = TRUE
;
2809 while(*p
&& !rejects
[(unsigned char)*p
]) p
++;
2813 /*********************************************************************
2814 * strpbrk (MSVCRT.@)
2816 char* __cdecl
strpbrk(const char *str
, const char *accept
)
2818 for (; *str
; str
++) if (strchr( accept
, *str
)) return (char*)str
;
2822 /*********************************************************************
2823 * __strncnt (MSVCRT.@)
2825 size_t __cdecl
__strncnt(const char *str
, size_t size
)
2829 #if _MSVCR_VER >= 140
2830 while (*str
++ && size
--)
2832 while (size
-- && *str
++)
2843 /*********************************************************************
2844 * _strdec (CRTDLL.@)
2846 char * CDECL
_strdec(const char *str1
, const char *str2
)
2848 return (char *)(str2
- 1);
2851 /*********************************************************************
2852 * _strinc (CRTDLL.@)
2854 char * CDECL
_strinc(const char *str
)
2856 return (char *)(str
+ 1);
2859 /*********************************************************************
2860 * _strnextc (CRTDLL.@)
2862 unsigned int CDECL
_strnextc(const char *str
)
2864 return (unsigned char)str
[0];
2867 /*********************************************************************
2868 * _strninc (CRTDLL.@)
2870 char * CDECL
_strninc(const char *str
, size_t len
)
2872 return (char *)(str
+ len
);
2875 /*********************************************************************
2876 * _strspnp (CRTDLL.@)
2878 char * CDECL
_strspnp( const char *str1
, const char *str2
)
2880 str1
+= strspn( str1
, str2
);
2881 return *str1
? (char*)str1
: NULL
;