2 * MSVCRT string functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define _ISOC99_SOURCE
26 #include "wine/port.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
40 /*********************************************************************
44 char* CDECL
MSVCRT__strdup(const char* str
)
48 char * ret
= MSVCRT_malloc(strlen(str
)+1);
49 if (ret
) strcpy( ret
, str
);
55 /*********************************************************************
56 * _strlwr_s_l (MSVCRT.@)
58 int CDECL
MSVCRT__strlwr_s_l(char *str
, MSVCRT_size_t len
, MSVCRT__locale_t locale
)
60 MSVCRT_pthreadlocinfo locinfo
;
65 *MSVCRT__errno() = MSVCRT_EINVAL
;
78 *MSVCRT__errno() = MSVCRT_EINVAL
;
83 locinfo
= get_locinfo();
85 locinfo
= locale
->locinfo
;
87 if(!locinfo
->lc_handle
[MSVCRT_LC_CTYPE
])
91 if (*str
>= 'A' && *str
<= 'Z')
100 *str
= MSVCRT__tolower_l((unsigned char)*str
, locale
);
108 /*********************************************************************
109 * _strlwr_s (MSVCRT.@)
111 int CDECL
MSVCRT__strlwr_s(char *str
, MSVCRT_size_t len
)
113 return MSVCRT__strlwr_s_l(str
, len
, NULL
);
116 /*********************************************************************
117 * _strlwr_l (MSVCRT.@)
119 char* CDECL
_strlwr_l(char *str
, MSVCRT__locale_t locale
)
121 MSVCRT__strlwr_s_l(str
, -1, locale
);
125 /*********************************************************************
128 char* CDECL
MSVCRT__strlwr(char *str
)
130 MSVCRT__strlwr_s_l(str
, -1, NULL
);
134 /*********************************************************************
135 * _strupr_s_l (MSVCRT.@)
137 int CDECL
MSVCRT__strupr_s_l(char *str
, MSVCRT_size_t len
, MSVCRT__locale_t locale
)
139 MSVCRT_pthreadlocinfo locinfo
;
144 *MSVCRT__errno() = MSVCRT_EINVAL
;
145 return MSVCRT_EINVAL
;
157 *MSVCRT__errno() = MSVCRT_EINVAL
;
158 return MSVCRT_EINVAL
;
162 locinfo
= get_locinfo();
164 locinfo
= locale
->locinfo
;
166 if(!locinfo
->lc_handle
[MSVCRT_LC_CTYPE
])
170 if (*str
>= 'a' && *str
<= 'z')
179 *str
= MSVCRT__toupper_l((unsigned char)*str
, locale
);
187 /*********************************************************************
188 * _strupr_s (MSVCRT.@)
190 int CDECL
MSVCRT__strupr_s(char *str
, MSVCRT_size_t len
)
192 return MSVCRT__strupr_s_l(str
, len
, NULL
);
195 /*********************************************************************
196 * _strupr_l (MSVCRT.@)
198 char* CDECL
MSVCRT__strupr_l(char *str
, MSVCRT__locale_t locale
)
200 MSVCRT__strupr_s_l(str
, -1, locale
);
204 /*********************************************************************
207 char* CDECL
MSVCRT__strupr(char *str
)
209 MSVCRT__strupr_s_l(str
, -1, NULL
);
213 /*********************************************************************
214 * _strnset_s (MSVCRT.@)
216 int CDECL
MSVCRT__strnset_s(char *str
, MSVCRT_size_t size
, int c
, MSVCRT_size_t count
)
220 if(!str
&& !size
&& !count
) return 0;
221 if(!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
222 if(!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
224 for(i
=0; i
<size
-1 && i
<count
; i
++) {
225 if(!str
[i
]) return 0;
229 if(!str
[i
]) return 0;
232 MSVCRT__invalid_parameter(NULL
, NULL
, NULL
, 0, 0);
233 *MSVCRT__errno() = MSVCRT_EINVAL
;
234 return MSVCRT_EINVAL
;
237 /*********************************************************************
238 * _strnset (MSVCRT.@)
240 char* CDECL
MSVCRT__strnset(char* str
, int value
, MSVCRT_size_t len
)
243 while (*str
&& len
--)
248 /*********************************************************************
251 char* CDECL
MSVCRT__strrev(char* str
)
257 for (p1
= str
, p2
= str
+ strlen(str
) - 1; p2
> p1
; ++p1
, --p2
)
267 /*********************************************************************
270 char* CDECL
_strset(char* str
, int value
)
279 /*********************************************************************
282 char * CDECL
MSVCRT_strtok( char *str
, const char *delim
)
284 thread_data_t
*data
= msvcrt_get_thread_data();
288 if (!(str
= data
->strtok_next
)) return NULL
;
290 while (*str
&& strchr( delim
, *str
)) str
++;
291 if (!*str
) return NULL
;
293 while (*str
&& !strchr( delim
, *str
)) str
++;
294 if (*str
) *str
++ = 0;
295 data
->strtok_next
= str
;
299 /*********************************************************************
300 * strtok_s (MSVCRT.@)
302 char * CDECL
MSVCRT_strtok_s(char *str
, const char *delim
, char **ctx
)
304 if (!MSVCRT_CHECK_PMT(delim
!= NULL
)) return NULL
;
305 if (!MSVCRT_CHECK_PMT(ctx
!= NULL
)) return NULL
;
306 if (!MSVCRT_CHECK_PMT(str
!= NULL
|| *ctx
!= NULL
)) return NULL
;
311 while(*str
&& strchr(delim
, *str
))
320 while(**ctx
&& !strchr(delim
, **ctx
))
328 /*********************************************************************
331 void CDECL
MSVCRT__swab(char* src
, char* dst
, int len
)
335 len
= (unsigned)len
>> 1;
348 ROUND_ZERO
, /* only used when dropped part contains only zeros */
354 static double make_double(int sign
, int exp
, ULONGLONG m
, enum round round
, int *err
)
360 TRACE("%c %s *2^%d (round %d)\n", sign
== -1 ? '-' : '+', wine_dbgstr_longlong(m
), exp
, round
);
361 if (!m
) return sign
* 0.0;
363 /* make sure that we don't overflow modifying exponent */
364 if (exp
> 1<<EXP_BITS
)
366 if (err
) *err
= MSVCRT_ERANGE
;
367 return sign
* INFINITY
;
369 if (exp
< -(1<<EXP_BITS
))
371 if (err
) *err
= MSVCRT_ERANGE
;
374 exp
+= MANT_BITS
- 1;
376 /* normalize mantissa */
377 while(m
< (ULONGLONG
)1 << (MANT_BITS
-1))
382 while(m
>= (ULONGLONG
)1 << MANT_BITS
)
384 if (m
& 1 || round
!= ROUND_ZERO
)
386 if (!(m
& 1)) round
= ROUND_DOWN
;
387 else if(round
== ROUND_ZERO
) round
= ROUND_EVEN
;
388 else round
= ROUND_UP
;
394 /* handle subnormal that falls into regular range due to rounding */
395 exp
+= (1 << (EXP_BITS
-1)) - 1;
396 if (!exp
&& (round
== ROUND_UP
|| (round
== ROUND_EVEN
&& m
& 1)))
398 if (m
+ 1 >= (ULONGLONG
)1 << MANT_BITS
)
407 /* handle subnormals */
417 if (round
== ROUND_UP
|| (round
== ROUND_EVEN
&& m
& 1))
420 if (m
>= (ULONGLONG
)1 << MANT_BITS
)
427 if (exp
>= 1<<EXP_BITS
)
429 if (err
) *err
= MSVCRT_ERANGE
;
430 return sign
* INFINITY
;
434 if (err
) *err
= MSVCRT_ERANGE
;
438 if (sign
== -1) bits
|= (ULONGLONG
)1 << (MANT_BITS
+ EXP_BITS
- 1);
439 bits
|= (ULONGLONG
)exp
<< (MANT_BITS
- 1);
440 bits
|= m
& (((ULONGLONG
)1 << (MANT_BITS
- 1)) - 1);
442 TRACE("returning %s\n", wine_dbgstr_longlong(bits
));
443 return *((double*)&bits
);
446 #if _MSVCR_VER >= 140
448 static inline int hex2int(char c
)
450 if (c
>= '0' && c
<= '9')
452 else if (c
>= 'a' && c
<= 'f')
454 else if (c
>= 'A' && c
<= 'F')
459 static double strtod16(MSVCRT_wchar_t
get(void *ctx
), void unget(void *ctx
),
460 void *ctx
, int sign
, MSVCRT_pthreadlocinfo locinfo
, int *err
)
462 BOOL found_digit
= FALSE
, found_dp
= FALSE
;
463 enum round round
= ROUND_ZERO
;
469 while(m
< MSVCRT_UI64_MAX
/16)
472 if (val
== -1) break;
481 if (val
== -1) break;
485 if (val
|| round
!= ROUND_ZERO
)
487 if (val
< 8) round
= ROUND_DOWN
;
488 else if (val
== 8 && round
== ROUND_ZERO
) round
= ROUND_EVEN
;
489 else round
= ROUND_UP
;
493 if(nch
== *locinfo
->lconv
->decimal_point
)
498 else if (!found_digit
)
500 if(nch
!=MSVCRT_WEOF
) unget(ctx
);
505 while(m
<= MSVCRT_UI64_MAX
/16)
508 if (val
== -1) break;
518 if (val
== -1) break;
521 if (val
|| round
!= ROUND_ZERO
)
523 if (val
< 8) round
= ROUND_DOWN
;
524 else if (val
== 8 && round
== ROUND_ZERO
) round
= ROUND_EVEN
;
525 else round
= ROUND_UP
;
531 if (nch
!= MSVCRT_WEOF
) unget(ctx
);
532 if (found_dp
) unget(ctx
);
537 if(nch
=='p' || nch
=='P') {
538 BOOL found_sign
= FALSE
;
546 } else if(nch
== '+') {
550 if(nch
>='0' && nch
<='9') {
551 while(nch
>='0' && nch
<='9') {
552 if(e
>INT_MAX
/10 || e
*10>INT_MAX
-nch
+'0')
558 if((nch
!=MSVCRT_WEOF
) && (nch
< '0' || nch
> '9')) unget(ctx
);
561 if(e
<0 && exp
<INT_MIN
-e
) exp
= INT_MIN
;
562 else if(e
>0 && exp
>INT_MAX
-e
) exp
= INT_MAX
;
565 if(nch
!= MSVCRT_WEOF
) unget(ctx
);
566 if(found_sign
) unget(ctx
);
571 return make_double(sign
, exp
, m
, round
, err
);
575 #define LIMB_DIGITS 9 /* each DWORD stores up to 9 digits */
576 #define LIMB_MAX 1000000000 /* 10^9 */
577 #define BNUM_IDX(i) ((i) & 127)
578 /* bnum represents real number with fixed decimal point (after 2 limbs) */
580 DWORD data
[128]; /* circular buffer, base 10 number */
581 int b
; /* least significant digit position */
582 int e
; /* most significant digit position + 1 */
585 /* Returns integral part of bnum */
586 static inline ULONGLONG
bnum_to_mant(struct bnum
*b
)
588 ULONGLONG ret
= (ULONGLONG
)b
->data
[BNUM_IDX(b
->e
-1)] * LIMB_MAX
;
589 if(b
->b
!= b
->e
-1) ret
+= b
->data
[BNUM_IDX(b
->e
-2)];
593 /* Returns TRUE if new most significant limb was added */
594 static inline BOOL
bnum_lshift(struct bnum
*b
, int shift
)
600 /* The limbs number can change by up to 1 so shift <= 29 */
603 for(i
=b
->b
; i
<b
->e
; i
++) {
604 tmp
= ((ULONGLONG
)b
->data
[BNUM_IDX(i
)] << shift
) + rest
;
605 rest
= tmp
/ LIMB_MAX
;
606 b
->data
[BNUM_IDX(i
)] = tmp
% LIMB_MAX
;
608 if(i
== b
->b
&& !b
->data
[BNUM_IDX(i
)])
613 b
->data
[BNUM_IDX(b
->e
)] = rest
;
616 if(BNUM_IDX(b
->b
) == BNUM_IDX(b
->e
)) {
617 if(b
->data
[BNUM_IDX(b
->b
)]) b
->data
[BNUM_IDX(b
->b
+1)] |= 1;
625 /* Returns TRUE if most significant limb was removed */
626 static inline BOOL
bnum_rshift(struct bnum
*b
, int shift
)
632 /* Compute LIMB_MAX << shift without accuracy loss */
635 for(i
=b
->e
-1; i
>=b
->b
; i
--) {
636 tmp
= b
->data
[BNUM_IDX(i
)] & ((1<<shift
)-1);
637 b
->data
[BNUM_IDX(i
)] = (b
->data
[BNUM_IDX(i
)] >> shift
) + rest
;
638 rest
= (LIMB_MAX
>> shift
) * tmp
;
639 if(i
==b
->e
-1 && !b
->data
[BNUM_IDX(i
)]) {
646 if(BNUM_IDX(b
->b
-1) == BNUM_IDX(b
->e
)) {
647 if(rest
) b
->data
[BNUM_IDX(b
->b
)] |= 1;
650 b
->data
[BNUM_IDX(b
->b
)] = rest
;
656 static inline void bnum_mult(struct bnum
*b
, int mult
)
662 assert(mult
<= LIMB_MAX
);
664 for(i
=b
->b
; i
<b
->e
; i
++) {
665 tmp
= ((ULONGLONG
)b
->data
[BNUM_IDX(i
)] * mult
) + rest
;
666 rest
= tmp
/ LIMB_MAX
;
667 b
->data
[BNUM_IDX(i
)] = tmp
% LIMB_MAX
;
669 if(i
== b
->b
&& !b
->data
[BNUM_IDX(i
)])
674 b
->data
[BNUM_IDX(b
->e
)] = rest
;
677 if(BNUM_IDX(b
->b
) == BNUM_IDX(b
->e
)) {
678 if(b
->data
[BNUM_IDX(b
->b
)]) b
->data
[BNUM_IDX(b
->b
+1)] |= 1;
684 double parse_double(MSVCRT_wchar_t (*get
)(void *ctx
), void (*unget
)(void *ctx
),
685 void *ctx
, MSVCRT_pthreadlocinfo locinfo
, int *err
)
687 static const int p10s
[] = { 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000 };
689 #if _MSVCR_VER >= 140
690 MSVCRT_wchar_t _infinity
[] = { 'i', 'n', 'f', 'i', 'n', 'i', 't', 'y', 0 };
691 MSVCRT_wchar_t _nan
[] = { 'n', 'a', 'n', 0 };
692 MSVCRT_wchar_t
*str_match
= NULL
;
695 BOOL found_digit
= FALSE
, found_dp
= FALSE
, found_sign
= FALSE
;
696 int e2
= 0, dp
=0, sign
=1, off
, limb_digits
= 0, i
;
697 enum round round
= ROUND_ZERO
;
706 } else if(nch
== '+') {
711 #if _MSVCR_VER >= 140
712 if(nch
== _infinity
[0] || nch
== MSVCRT__toupper(_infinity
[0]))
713 str_match
= _infinity
;
714 if(nch
== _nan
[0] || nch
== MSVCRT__toupper(_nan
[0]))
716 while(str_match
&& nch
!= MSVCRT_WEOF
&&
717 (nch
== str_match
[matched
] || nch
== MSVCRT__toupper(str_match
[matched
]))) {
723 if(matched
>= 8) keep
= 8;
724 else if(matched
>= 3) keep
= 3;
725 if(nch
!= MSVCRT_WEOF
) unget(ctx
);
726 for (; matched
> keep
; matched
--) {
730 if (str_match
== _infinity
) return sign
*INFINITY
;
731 if (str_match
== _nan
) return sign
*NAN
;
732 } else if(found_sign
) {
742 if(nch
== 'x' || nch
== 'X')
743 return strtod16(get
, unget
, ctx
, sign
, locinfo
, err
);
755 while(nch
>='0' && nch
<='9') {
757 if(limb_digits
== LIMB_DIGITS
) {
758 if(BNUM_IDX(b
.b
-1) == BNUM_IDX(b
.e
)) break;
761 b
.data
[BNUM_IDX(b
.b
)] = 0;
766 b
.data
[BNUM_IDX(b
.b
)] = b
.data
[BNUM_IDX(b
.b
)] * 10 + nch
- '0';
771 while(nch
>='0' && nch
<='9') {
772 if(nch
!= '0') b
.data
[BNUM_IDX(b
.b
)] |= 1;
777 if(nch
== *locinfo
->lconv
->decimal_point
) {
782 /* skip leading '0' */
783 if(nch
=='0' && !limb_digits
&& !b
.b
) {
791 while(nch
>='0' && nch
<='9') {
793 if(limb_digits
== LIMB_DIGITS
) {
794 if(BNUM_IDX(b
.b
-1) == BNUM_IDX(b
.e
)) break;
797 b
.data
[BNUM_IDX(b
.b
)] = 0;
802 b
.data
[BNUM_IDX(b
.b
)] = b
.data
[BNUM_IDX(b
.b
)] * 10 + nch
- '0';
806 while(nch
>='0' && nch
<='9') {
807 if(nch
!= '0') b
.data
[BNUM_IDX(b
.b
)] |= 1;
812 if(nch
!= MSVCRT_WEOF
) unget(ctx
);
813 if(found_dp
) unget(ctx
);
814 if(found_sign
) unget(ctx
);
818 if(nch
=='e' || nch
=='E' || nch
=='d' || nch
=='D') {
826 } else if(nch
== '+') {
833 if(nch
>='0' && nch
<='9') {
834 while(nch
>='0' && nch
<='9') {
835 if(e
>INT_MAX
/10 || e
*10>INT_MAX
-nch
+'0')
841 if(nch
!= MSVCRT_WEOF
) unget(ctx
);
844 if(e
<0 && dp
<INT_MIN
-e
) dp
= INT_MIN
;
845 else if(e
>0 && dp
>INT_MAX
-e
) dp
= INT_MAX
;
848 if(nch
!= MSVCRT_WEOF
) unget(ctx
);
849 if(found_sign
) unget(ctx
);
852 } else if(nch
!= MSVCRT_WEOF
) {
856 if(!b
.data
[BNUM_IDX(b
.e
-1)]) return make_double(sign
, 0, 0, ROUND_ZERO
, err
);
858 /* Fill last limb with 0 if needed */
860 for(; limb_digits
!= LIMB_DIGITS
; limb_digits
++)
861 b
.data
[BNUM_IDX(b
.b
)] *= 10;
863 for(; BNUM_IDX(b
.b
) < BNUM_IDX(b
.e
); b
.b
++) {
864 if(b
.data
[BNUM_IDX(b
.b
)]) break;
867 /* move decimal point to limb boundary */
868 if(limb_digits
==dp
&& b
.b
==b
.e
-1)
869 return make_double(sign
, 0, b
.data
[BNUM_IDX(b
.e
-1)], ROUND_ZERO
, err
);
870 off
= (dp
- limb_digits
) % LIMB_DIGITS
;
871 if(off
< 0) off
+= LIMB_DIGITS
;
872 if(off
) bnum_mult(&b
, p10s
[off
-1]);
874 if(!err
) err
= MSVCRT__errno();
875 if(dp
-1 > MSVCRT_DBL_MAX_10_EXP
)
876 return make_double(sign
, INT_MAX
, 1, ROUND_ZERO
, err
);
877 /* Count part of exponent stored in denormalized mantissa. */
878 /* Increase exponent range to handle subnormals. */
879 if(dp
-1 < MSVCRT_DBL_MIN_10_EXP
-MSVCRT_DBL_DIG
-18)
880 return make_double(sign
, INT_MIN
, 1, ROUND_ZERO
, err
);
882 while(dp
> 2*LIMB_DIGITS
) {
883 if(bnum_rshift(&b
, 9)) dp
-= LIMB_DIGITS
;
886 while(dp
<= LIMB_DIGITS
) {
887 if(bnum_lshift(&b
, 29)) dp
+= LIMB_DIGITS
;
890 while(b
.data
[BNUM_IDX(b
.e
-1)] < LIMB_MAX
/10) {
895 /* Check if fractional part is non-zero */
896 /* Caution: it's only correct because bnum_to_mant returns more than 53 bits */
897 for(i
=b
.e
-3; i
>=b
.b
; i
--) {
898 if (!b
.data
[BNUM_IDX(b
.b
)]) continue;
903 return make_double(sign
, e2
, bnum_to_mant(&b
), round
, err
);
906 static MSVCRT_wchar_t
strtod_str_get(void *ctx
)
908 const char **p
= ctx
;
909 if (!**p
) return MSVCRT_WEOF
;
913 static void strtod_str_unget(void *ctx
)
915 const char **p
= ctx
;
919 static inline double strtod_helper(const char *str
, char **end
, MSVCRT__locale_t locale
, int *err
)
921 MSVCRT_pthreadlocinfo locinfo
;
926 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) {
927 if (end
) *end
= NULL
;
932 locinfo
= get_locinfo();
934 locinfo
= locale
->locinfo
;
937 while(MSVCRT__isspace_l((unsigned char)*p
, locale
))
941 ret
= parse_double(strtod_str_get
, strtod_str_unget
, &p
, locinfo
, err
);
942 if (end
) *end
= (p
== beg
? (char*)str
: (char*)p
);
946 /*********************************************************************
947 * strtod_l (MSVCRT.@)
949 double CDECL
MSVCRT_strtod_l(const char *str
, char **end
, MSVCRT__locale_t locale
)
951 return strtod_helper(str
, end
, locale
, NULL
);
954 /*********************************************************************
957 double CDECL
MSVCRT_strtod( const char *str
, char **end
)
959 return MSVCRT_strtod_l( str
, end
, NULL
);
964 /*********************************************************************
965 * strtof_l (MSVCR120.@)
967 float CDECL
MSVCRT__strtof_l( const char *str
, char **end
, MSVCRT__locale_t locale
)
969 return MSVCRT_strtod_l(str
, end
, locale
);
972 /*********************************************************************
973 * strtof (MSVCR120.@)
975 float CDECL
MSVCRT_strtof( const char *str
, char **end
)
977 return MSVCRT__strtof_l(str
, end
, NULL
);
980 #endif /* _MSVCR_VER>=120 */
982 /*********************************************************************
985 double CDECL
MSVCRT_atof( const char *str
)
987 return MSVCRT_strtod_l(str
, NULL
, NULL
);
990 /*********************************************************************
993 double CDECL
MSVCRT__atof_l( const char *str
, MSVCRT__locale_t locale
)
995 return MSVCRT_strtod_l(str
, NULL
, locale
);
998 /*********************************************************************
999 * _atoflt_l (MSVCRT.@)
1001 int CDECL
MSVCRT__atoflt_l( MSVCRT__CRT_FLOAT
*value
, char *str
, MSVCRT__locale_t locale
)
1006 d
= strtod_helper(str
, NULL
, locale
, &err
);
1009 return MSVCRT__OVERFLOW
;
1010 if((d
!=0 || err
) && value
->f
>-MSVCRT_FLT_MIN
&& value
->f
<MSVCRT_FLT_MIN
)
1011 return MSVCRT__UNDERFLOW
;
1015 /*********************************************************************
1016 * _atoflt (MSVCR100.@)
1018 int CDECL
MSVCRT__atoflt(MSVCRT__CRT_FLOAT
*value
, char *str
)
1020 return MSVCRT__atoflt_l(value
, str
, NULL
);
1023 /*********************************************************************
1024 * _atodbl_l (MSVCRT.@)
1026 int CDECL
MSVCRT__atodbl_l(MSVCRT__CRT_DOUBLE
*value
, char *str
, MSVCRT__locale_t locale
)
1030 value
->x
= strtod_helper(str
, NULL
, locale
, &err
);
1032 return MSVCRT__OVERFLOW
;
1033 if((value
->x
!=0 || err
) && value
->x
>-MSVCRT_DBL_MIN
&& value
->x
<MSVCRT_DBL_MIN
)
1034 return MSVCRT__UNDERFLOW
;
1038 /*********************************************************************
1039 * _atodbl (MSVCRT.@)
1041 int CDECL
MSVCRT__atodbl(MSVCRT__CRT_DOUBLE
*value
, char *str
)
1043 return MSVCRT__atodbl_l(value
, str
, NULL
);
1046 /*********************************************************************
1047 * _strcoll_l (MSVCRT.@)
1049 int CDECL
MSVCRT_strcoll_l( const char* str1
, const char* str2
, MSVCRT__locale_t locale
)
1051 MSVCRT_pthreadlocinfo locinfo
;
1054 locinfo
= get_locinfo();
1056 locinfo
= locale
->locinfo
;
1058 if(!locinfo
->lc_handle
[MSVCRT_LC_COLLATE
])
1059 return MSVCRT_strcmp(str1
, str2
);
1060 return CompareStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
], 0, str1
, -1, str2
, -1)-CSTR_EQUAL
;
1063 /*********************************************************************
1064 * strcoll (MSVCRT.@)
1066 int CDECL
MSVCRT_strcoll( const char* str1
, const char* str2
)
1068 return MSVCRT_strcoll_l(str1
, str2
, NULL
);
1071 /*********************************************************************
1072 * _stricoll_l (MSVCRT.@)
1074 int CDECL
MSVCRT__stricoll_l( const char* str1
, const char* str2
, MSVCRT__locale_t locale
)
1076 MSVCRT_pthreadlocinfo locinfo
;
1079 locinfo
= get_locinfo();
1081 locinfo
= locale
->locinfo
;
1083 if(!locinfo
->lc_handle
[MSVCRT_LC_COLLATE
])
1084 return MSVCRT__stricmp(str1
, str2
);
1085 return CompareStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
], NORM_IGNORECASE
,
1086 str1
, -1, str2
, -1)-CSTR_EQUAL
;
1089 /*********************************************************************
1090 * _stricoll (MSVCRT.@)
1092 int CDECL
MSVCRT__stricoll( const char* str1
, const char* str2
)
1094 return MSVCRT__stricoll_l(str1
, str2
, NULL
);
1097 /*********************************************************************
1098 * _strncoll_l (MSVCRT.@)
1100 int CDECL
MSVCRT__strncoll_l( const char* str1
, const char* str2
, MSVCRT_size_t count
, MSVCRT__locale_t locale
)
1102 MSVCRT_pthreadlocinfo locinfo
;
1105 locinfo
= get_locinfo();
1107 locinfo
= locale
->locinfo
;
1109 if(!locinfo
->lc_handle
[MSVCRT_LC_COLLATE
])
1110 return MSVCRT_strncmp(str1
, str2
, count
);
1111 return CompareStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
], 0,
1112 str1
, MSVCRT_strnlen(str1
, count
),
1113 str2
, MSVCRT_strnlen(str2
, count
))-CSTR_EQUAL
;
1116 /*********************************************************************
1117 * _strncoll (MSVCRT.@)
1119 int CDECL
MSVCRT__strncoll( const char* str1
, const char* str2
, MSVCRT_size_t count
)
1121 return MSVCRT__strncoll_l(str1
, str2
, count
, NULL
);
1124 /*********************************************************************
1125 * _strnicoll_l (MSVCRT.@)
1127 int CDECL
MSVCRT__strnicoll_l( const char* str1
, const char* str2
, MSVCRT_size_t count
, MSVCRT__locale_t locale
)
1129 MSVCRT_pthreadlocinfo locinfo
;
1132 locinfo
= get_locinfo();
1134 locinfo
= locale
->locinfo
;
1136 if(!locinfo
->lc_handle
[MSVCRT_LC_COLLATE
])
1137 return MSVCRT__strnicmp(str1
, str2
, count
);
1138 return CompareStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
], NORM_IGNORECASE
,
1139 str1
, MSVCRT_strnlen(str1
, count
),
1140 str2
, MSVCRT_strnlen(str2
, count
))-CSTR_EQUAL
;
1143 /*********************************************************************
1144 * _strnicoll (MSVCRT.@)
1146 int CDECL
MSVCRT__strnicoll( const char* str1
, const char* str2
, MSVCRT_size_t count
)
1148 return MSVCRT__strnicoll_l(str1
, str2
, count
, NULL
);
1151 /*********************************************************************
1152 * strncpy (MSVCRT.@)
1154 char* __cdecl
MSVCRT_strncpy(char *dst
, const char *src
, MSVCRT_size_t len
)
1158 for(i
=0; i
<len
; i
++)
1159 if((dst
[i
] = src
[i
]) == '\0') break;
1161 while (i
< len
) dst
[i
++] = 0;
1166 /*********************************************************************
1169 char* CDECL
MSVCRT_strcpy(char *dst
, const char *src
)
1172 while ((*dst
++ = *src
++));
1176 /*********************************************************************
1177 * strcpy_s (MSVCRT.@)
1179 int CDECL
MSVCRT_strcpy_s( char* dst
, MSVCRT_size_t elem
, const char* src
)
1182 if(!elem
) return MSVCRT_EINVAL
;
1183 if(!dst
) return MSVCRT_EINVAL
;
1187 return MSVCRT_EINVAL
;
1190 for(i
= 0; i
< elem
; i
++)
1192 if((dst
[i
] = src
[i
]) == '\0') return 0;
1195 return MSVCRT_ERANGE
;
1198 /*********************************************************************
1199 * strcat_s (MSVCRT.@)
1201 int CDECL
MSVCRT_strcat_s( char* dst
, MSVCRT_size_t elem
, const char* src
)
1204 if(!dst
) return MSVCRT_EINVAL
;
1205 if(elem
== 0) return MSVCRT_EINVAL
;
1209 return MSVCRT_EINVAL
;
1212 for(i
= 0; i
< elem
; i
++)
1216 for(j
= 0; (j
+ i
) < elem
; j
++)
1218 if((dst
[j
+ i
] = src
[j
]) == '\0') return 0;
1222 /* Set the first element to 0, not the first element after the skipped part */
1224 return MSVCRT_ERANGE
;
1227 /*********************************************************************
1228 * strncat_s (MSVCRT.@)
1230 int CDECL
MSVCRT_strncat_s( char* dst
, MSVCRT_size_t elem
, const char* src
, MSVCRT_size_t count
)
1234 if (!MSVCRT_CHECK_PMT(dst
!= 0)) return MSVCRT_EINVAL
;
1235 if (!MSVCRT_CHECK_PMT(elem
!= 0)) return MSVCRT_EINVAL
;
1236 if (!MSVCRT_CHECK_PMT(src
!= 0))
1239 return MSVCRT_EINVAL
;
1242 for(i
= 0; i
< elem
; i
++)
1246 for(j
= 0; (j
+ i
) < elem
; j
++)
1248 if(count
== MSVCRT__TRUNCATE
&& j
+ i
== elem
- 1)
1251 return MSVCRT_STRUNCATE
;
1253 if(j
== count
|| (dst
[j
+ i
] = src
[j
]) == '\0')
1261 /* Set the first element to 0, not the first element after the skipped part */
1263 return MSVCRT_ERANGE
;
1266 /*********************************************************************
1267 * strncat (MSVCRT.@)
1269 char* __cdecl
MSVCRT_strncat(char *dst
, const char *src
, MSVCRT_size_t len
)
1271 return strncat(dst
, src
, len
);
1274 /*********************************************************************
1275 * _strxfrm_l (MSVCRT.@)
1277 MSVCRT_size_t CDECL
MSVCRT__strxfrm_l( char *dest
, const char *src
,
1278 MSVCRT_size_t len
, MSVCRT__locale_t locale
)
1280 MSVCRT_pthreadlocinfo locinfo
;
1283 if(!MSVCRT_CHECK_PMT(src
)) return INT_MAX
;
1284 if(!MSVCRT_CHECK_PMT(dest
|| !len
)) return INT_MAX
;
1287 FIXME("len > INT_MAX not supported\n");
1292 locinfo
= get_locinfo();
1294 locinfo
= locale
->locinfo
;
1296 if(!locinfo
->lc_handle
[MSVCRT_LC_COLLATE
]) {
1297 MSVCRT_strncpy(dest
, src
, len
);
1301 ret
= LCMapStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
],
1302 LCMAP_SORTKEY
, src
, -1, NULL
, 0);
1304 if(len
) dest
[0] = 0;
1305 *MSVCRT__errno() = MSVCRT_EILSEQ
;
1308 if(!len
) return ret
-1;
1312 *MSVCRT__errno() = MSVCRT_ERANGE
;
1316 return LCMapStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
],
1317 LCMAP_SORTKEY
, src
, -1, dest
, len
) - 1;
1320 /*********************************************************************
1321 * strxfrm (MSVCRT.@)
1323 MSVCRT_size_t CDECL
MSVCRT_strxfrm( char *dest
, const char *src
, MSVCRT_size_t len
)
1325 return MSVCRT__strxfrm_l(dest
, src
, len
, NULL
);
1328 /********************************************************************
1329 * _atoldbl (MSVCRT.@)
1331 int CDECL
MSVCRT__atoldbl(MSVCRT__LDOUBLE
*value
, const char *str
)
1333 /* FIXME needs error checking for huge/small values */
1336 TRACE("str %s value %p\n",str
,value
);
1337 ld
= strtold(str
,0);
1338 memcpy(value
, &ld
, 10);
1340 FIXME("stub, str %s value %p\n",str
,value
);
1345 /********************************************************************
1346 * __STRINGTOLD (MSVCRT.@)
1348 int CDECL
__STRINGTOLD( MSVCRT__LDOUBLE
*value
, char **endptr
, const char *str
, int flags
)
1352 FIXME("%p %p %s %x partial stub\n", value
, endptr
, str
, flags
);
1353 ld
= strtold(str
,0);
1354 memcpy(value
, &ld
, 10);
1356 FIXME("%p %p %s %x stub\n", value
, endptr
, str
, flags
);
1361 /*********************************************************************
1364 MSVCRT_size_t __cdecl
MSVCRT_strlen(const char *str
)
1369 /******************************************************************
1370 * strnlen (MSVCRT.@)
1372 MSVCRT_size_t CDECL
MSVCRT_strnlen(const char *s
, MSVCRT_size_t maxlen
)
1376 for(i
=0; i
<maxlen
; i
++)
1382 /*********************************************************************
1383 * _strtoi64_l (MSVCRT.@)
1385 * FIXME: locale parameter is ignored
1387 __int64 CDECL
MSVCRT_strtoi64_l(const char *nptr
, char **endptr
, int base
, MSVCRT__locale_t locale
)
1389 const char *p
= nptr
;
1390 BOOL negative
= FALSE
;
1391 BOOL got_digit
= FALSE
;
1394 TRACE("(%s %p %d %p)\n", debugstr_a(nptr
), endptr
, base
, locale
);
1396 if (!MSVCRT_CHECK_PMT(nptr
!= NULL
)) return 0;
1397 if (!MSVCRT_CHECK_PMT(base
== 0 || base
>= 2)) return 0;
1398 if (!MSVCRT_CHECK_PMT(base
<= 36)) return 0;
1400 while(MSVCRT__isspace_l((unsigned char)*nptr
, locale
)) nptr
++;
1405 } else if(*nptr
== '+')
1408 if((base
==0 || base
==16) && *nptr
=='0' && MSVCRT__tolower_l(*(nptr
+1), locale
)=='x') {
1421 char cur
= MSVCRT__tolower_l(*nptr
, locale
);
1424 if(cur
>='0' && cur
<='9') {
1429 if(cur
<'a' || cur
>='a'+base
-10)
1440 if(!negative
&& (ret
>MSVCRT_I64_MAX
/base
|| ret
*base
>MSVCRT_I64_MAX
-v
)) {
1441 ret
= MSVCRT_I64_MAX
;
1442 *MSVCRT__errno() = MSVCRT_ERANGE
;
1443 } else if(negative
&& (ret
<MSVCRT_I64_MIN
/base
|| ret
*base
<MSVCRT_I64_MIN
-v
)) {
1444 ret
= MSVCRT_I64_MIN
;
1445 *MSVCRT__errno() = MSVCRT_ERANGE
;
1451 *endptr
= (char*)(got_digit
? nptr
: p
);
1456 /*********************************************************************
1457 * _strtoi64 (MSVCRT.@)
1459 __int64 CDECL
MSVCRT_strtoi64(const char *nptr
, char **endptr
, int base
)
1461 return MSVCRT_strtoi64_l(nptr
, endptr
, base
, NULL
);
1464 /*********************************************************************
1465 * _atoi_l (MSVCRT.@)
1467 int __cdecl
MSVCRT__atoi_l(const char *str
, MSVCRT__locale_t locale
)
1469 __int64 ret
= MSVCRT_strtoi64_l(str
, NULL
, 10, locale
);
1473 *MSVCRT__errno() = MSVCRT_ERANGE
;
1474 } else if(ret
< INT_MIN
) {
1476 *MSVCRT__errno() = MSVCRT_ERANGE
;
1481 /*********************************************************************
1485 int __cdecl
MSVCRT_atoi(const char *str
)
1493 while(MSVCRT__isspace_l((unsigned char)*str
, NULL
)) str
++;
1497 }else if(*str
== '-') {
1502 while(*str
>='0' && *str
<='9') {
1503 ret
= ret
*10+*str
-'0';
1507 return minus
? -ret
: ret
;
1510 int CDECL
MSVCRT_atoi(const char *str
)
1512 return MSVCRT__atoi_l(str
, NULL
);
1516 /******************************************************************
1517 * _atoi64_l (MSVCRT.@)
1519 __int64 CDECL
MSVCRT__atoi64_l(const char *str
, MSVCRT__locale_t locale
)
1521 return MSVCRT_strtoi64_l(str
, NULL
, 10, locale
);
1524 /******************************************************************
1525 * _atoi64 (MSVCRT.@)
1527 __int64 CDECL
MSVCRT__atoi64(const char *str
)
1529 return MSVCRT_strtoi64_l(str
, NULL
, 10, NULL
);
1532 /******************************************************************
1533 * _atol_l (MSVCRT.@)
1535 MSVCRT_long CDECL
MSVCRT__atol_l(const char *str
, MSVCRT__locale_t locale
)
1537 __int64 ret
= MSVCRT_strtoi64_l(str
, NULL
, 10, locale
);
1539 if(ret
> MSVCRT_LONG_MAX
) {
1540 ret
= MSVCRT_LONG_MAX
;
1541 *MSVCRT__errno() = MSVCRT_ERANGE
;
1542 } else if(ret
< MSVCRT_LONG_MIN
) {
1543 ret
= MSVCRT_LONG_MIN
;
1544 *MSVCRT__errno() = MSVCRT_ERANGE
;
1549 /******************************************************************
1552 MSVCRT_long CDECL
MSVCRT_atol(const char *str
)
1555 return MSVCRT_atoi(str
);
1557 return MSVCRT__atol_l(str
, NULL
);
1563 /******************************************************************
1564 * _atoll_l (MSVCR120.@)
1566 MSVCRT_longlong CDECL
MSVCRT__atoll_l(const char* str
, MSVCRT__locale_t locale
)
1568 return MSVCRT_strtoi64_l(str
, NULL
, 10, locale
);
1571 /******************************************************************
1572 * atoll (MSVCR120.@)
1574 MSVCRT_longlong CDECL
MSVCRT_atoll(const char* str
)
1576 return MSVCRT__atoll_l(str
, NULL
);
1579 #endif /* if _MSVCR_VER>=120 */
1581 /******************************************************************
1582 * _strtol_l (MSVCRT.@)
1584 MSVCRT_long CDECL
MSVCRT__strtol_l(const char* nptr
,
1585 char** end
, int base
, MSVCRT__locale_t locale
)
1587 __int64 ret
= MSVCRT_strtoi64_l(nptr
, end
, base
, locale
);
1589 if(ret
> MSVCRT_LONG_MAX
) {
1590 ret
= MSVCRT_LONG_MAX
;
1591 *MSVCRT__errno() = MSVCRT_ERANGE
;
1592 } else if(ret
< MSVCRT_LONG_MIN
) {
1593 ret
= MSVCRT_LONG_MIN
;
1594 *MSVCRT__errno() = MSVCRT_ERANGE
;
1600 /******************************************************************
1603 MSVCRT_long CDECL
MSVCRT_strtol(const char* nptr
, char** end
, int base
)
1605 return MSVCRT__strtol_l(nptr
, end
, base
, NULL
);
1608 /******************************************************************
1609 * _strtoul_l (MSVCRT.@)
1611 MSVCRT_ulong CDECL
MSVCRT_strtoul_l(const char* nptr
, char** end
, int base
, MSVCRT__locale_t locale
)
1613 __int64 ret
= MSVCRT_strtoi64_l(nptr
, end
, base
, locale
);
1615 if(ret
> MSVCRT_ULONG_MAX
) {
1616 ret
= MSVCRT_ULONG_MAX
;
1617 *MSVCRT__errno() = MSVCRT_ERANGE
;
1618 }else if(ret
< -(__int64
)MSVCRT_ULONG_MAX
) {
1620 *MSVCRT__errno() = MSVCRT_ERANGE
;
1626 /******************************************************************
1627 * strtoul (MSVCRT.@)
1629 MSVCRT_ulong CDECL
MSVCRT_strtoul(const char* nptr
, char** end
, int base
)
1631 return MSVCRT_strtoul_l(nptr
, end
, base
, NULL
);
1634 /*********************************************************************
1635 * _strtoui64_l (MSVCRT.@)
1637 * FIXME: locale parameter is ignored
1639 unsigned __int64 CDECL
MSVCRT_strtoui64_l(const char *nptr
, char **endptr
, int base
, MSVCRT__locale_t locale
)
1641 const char *p
= nptr
;
1642 BOOL negative
= FALSE
;
1643 BOOL got_digit
= FALSE
;
1644 unsigned __int64 ret
= 0;
1646 TRACE("(%s %p %d %p)\n", debugstr_a(nptr
), endptr
, base
, locale
);
1648 if (!MSVCRT_CHECK_PMT(nptr
!= NULL
)) return 0;
1649 if (!MSVCRT_CHECK_PMT(base
== 0 || base
>= 2)) return 0;
1650 if (!MSVCRT_CHECK_PMT(base
<= 36)) return 0;
1652 while(MSVCRT__isspace_l((unsigned char)*nptr
, locale
)) nptr
++;
1657 } else if(*nptr
== '+')
1660 if((base
==0 || base
==16) && *nptr
=='0' && MSVCRT__tolower_l(*(nptr
+1), locale
)=='x') {
1673 char cur
= MSVCRT__tolower_l(*nptr
, locale
);
1676 if(cur
>='0' && cur
<='9') {
1681 if(cur
<'a' || cur
>='a'+base
-10)
1689 if(ret
>MSVCRT_UI64_MAX
/base
|| ret
*base
>MSVCRT_UI64_MAX
-v
) {
1690 ret
= MSVCRT_UI64_MAX
;
1691 *MSVCRT__errno() = MSVCRT_ERANGE
;
1697 *endptr
= (char*)(got_digit
? nptr
: p
);
1699 return negative
? -ret
: ret
;
1702 /*********************************************************************
1703 * _strtoui64 (MSVCRT.@)
1705 unsigned __int64 CDECL
MSVCRT_strtoui64(const char *nptr
, char **endptr
, int base
)
1707 return MSVCRT_strtoui64_l(nptr
, endptr
, base
, NULL
);
1710 static int ltoa_helper(MSVCRT_long value
, char *str
, MSVCRT_size_t size
, int radix
)
1715 char buffer
[33], *pos
;
1718 if (value
< 0 && radix
== 10)
1725 is_negative
= FALSE
;
1734 digit
= val
% radix
;
1738 *--pos
= '0' + digit
;
1740 *--pos
= 'a' + digit
- 10;
1747 len
= buffer
+ 33 - pos
;
1753 /* Copy the temporary buffer backwards up to the available number of
1754 * characters. Don't copy the negative sign if present. */
1762 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
1766 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE
);
1767 return MSVCRT_ERANGE
;
1770 memcpy(str
, pos
, len
);
1774 /*********************************************************************
1775 * _ltoa_s (MSVCRT.@)
1777 int CDECL
MSVCRT__ltoa_s(MSVCRT_long value
, char *str
, MSVCRT_size_t size
, int radix
)
1779 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
1780 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
1781 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
1784 return MSVCRT_EINVAL
;
1787 return ltoa_helper(value
, str
, size
, radix
);
1790 /*********************************************************************
1791 * _ltow_s (MSVCRT.@)
1793 int CDECL
MSVCRT__ltow_s(MSVCRT_long value
, MSVCRT_wchar_t
*str
, MSVCRT_size_t size
, int radix
)
1798 MSVCRT_wchar_t buffer
[33], *pos
;
1801 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
1802 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
1803 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
1806 return MSVCRT_EINVAL
;
1809 if (value
< 0 && radix
== 10)
1816 is_negative
= FALSE
;
1825 digit
= val
% radix
;
1829 *--pos
= '0' + digit
;
1831 *--pos
= 'a' + digit
- 10;
1838 len
= buffer
+ 33 - pos
;
1842 MSVCRT_wchar_t
*p
= str
;
1844 /* Copy the temporary buffer backwards up to the available number of
1845 * characters. Don't copy the negative sign if present. */
1853 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
1857 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE
);
1858 return MSVCRT_ERANGE
;
1861 memcpy(str
, pos
, len
* sizeof(MSVCRT_wchar_t
));
1865 /*********************************************************************
1866 * _itoa_s (MSVCRT.@)
1868 int CDECL
MSVCRT__itoa_s(int value
, char *str
, MSVCRT_size_t size
, int radix
)
1870 return MSVCRT__ltoa_s(value
, str
, size
, radix
);
1873 /*********************************************************************
1876 char* CDECL
MSVCRT__itoa(int value
, char *str
, int radix
)
1878 return ltoa_helper(value
, str
, MSVCRT_SIZE_MAX
, radix
) ? NULL
: str
;
1881 /*********************************************************************
1882 * _itow_s (MSVCRT.@)
1884 int CDECL
MSVCRT__itow_s(int value
, MSVCRT_wchar_t
*str
, MSVCRT_size_t size
, int radix
)
1886 return MSVCRT__ltow_s(value
, str
, size
, radix
);
1889 /*********************************************************************
1890 * _ui64toa_s (MSVCRT.@)
1892 int CDECL
MSVCRT__ui64toa_s(unsigned __int64 value
, char *str
,
1893 MSVCRT_size_t size
, int radix
)
1895 char buffer
[65], *pos
;
1898 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
1899 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
1900 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
1903 return MSVCRT_EINVAL
;
1910 digit
= value
%radix
;
1916 *--pos
= 'a'+digit
-10;
1919 if(buffer
-pos
+65 > size
) {
1920 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL
);
1921 return MSVCRT_EINVAL
;
1924 memcpy(str
, pos
, buffer
-pos
+65);
1928 /*********************************************************************
1929 * _ui64tow_s (MSVCRT.@)
1931 int CDECL
MSVCRT__ui64tow_s( unsigned __int64 value
, MSVCRT_wchar_t
*str
,
1932 MSVCRT_size_t size
, int radix
)
1934 MSVCRT_wchar_t buffer
[65], *pos
;
1937 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
1938 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
1939 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
1942 return MSVCRT_EINVAL
;
1949 digit
= value
% radix
;
1950 value
= value
/ radix
;
1952 *--pos
= '0' + digit
;
1954 *--pos
= 'a' + digit
- 10;
1955 } while (value
!= 0);
1957 if(buffer
-pos
+65 > size
) {
1958 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL
);
1959 return MSVCRT_EINVAL
;
1962 memcpy(str
, pos
, (buffer
-pos
+65)*sizeof(MSVCRT_wchar_t
));
1966 /*********************************************************************
1967 * _ultoa_s (MSVCRT.@)
1969 int CDECL
MSVCRT__ultoa_s(MSVCRT_ulong value
, char *str
, MSVCRT_size_t size
, int radix
)
1972 char buffer
[33], *pos
;
1975 if (!str
|| !size
|| radix
< 2 || radix
> 36)
1980 *MSVCRT__errno() = MSVCRT_EINVAL
;
1981 return MSVCRT_EINVAL
;
1989 digit
= value
% radix
;
1993 *--pos
= '0' + digit
;
1995 *--pos
= 'a' + digit
- 10;
1999 len
= buffer
+ 33 - pos
;
2005 /* Copy the temporary buffer backwards up to the available number of
2008 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2012 *MSVCRT__errno() = MSVCRT_ERANGE
;
2013 return MSVCRT_ERANGE
;
2016 memcpy(str
, pos
, len
);
2020 /*********************************************************************
2021 * _ultow_s (MSVCRT.@)
2023 int CDECL
MSVCRT__ultow_s(MSVCRT_ulong value
, MSVCRT_wchar_t
*str
, MSVCRT_size_t size
, int radix
)
2026 WCHAR buffer
[33], *pos
;
2029 if (!str
|| !size
|| radix
< 2 || radix
> 36)
2034 *MSVCRT__errno() = MSVCRT_EINVAL
;
2035 return MSVCRT_EINVAL
;
2043 digit
= value
% radix
;
2047 *--pos
= '0' + digit
;
2049 *--pos
= 'a' + digit
- 10;
2053 len
= buffer
+ 33 - pos
;
2059 /* Copy the temporary buffer backwards up to the available number of
2062 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2066 *MSVCRT__errno() = MSVCRT_ERANGE
;
2067 return MSVCRT_ERANGE
;
2070 memcpy(str
, pos
, len
* sizeof(MSVCRT_wchar_t
));
2074 /*********************************************************************
2075 * _i64toa_s (MSVCRT.@)
2077 int CDECL
MSVCRT__i64toa_s(__int64 value
, char *str
, MSVCRT_size_t size
, int radix
)
2079 unsigned __int64 val
;
2082 char buffer
[65], *pos
;
2085 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
2086 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
2087 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
2090 return MSVCRT_EINVAL
;
2093 if (value
< 0 && radix
== 10)
2100 is_negative
= FALSE
;
2109 digit
= val
% radix
;
2113 *--pos
= '0' + digit
;
2115 *--pos
= 'a' + digit
- 10;
2122 len
= buffer
+ 65 - pos
;
2128 /* Copy the temporary buffer backwards up to the available number of
2129 * characters. Don't copy the negative sign if present. */
2137 for (pos
= buffer
+ 63, i
= 0; i
< size
; i
++)
2141 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE
);
2142 return MSVCRT_ERANGE
;
2145 memcpy(str
, pos
, len
);
2149 /*********************************************************************
2150 * _i64tow_s (MSVCRT.@)
2152 int CDECL
MSVCRT__i64tow_s(__int64 value
, MSVCRT_wchar_t
*str
, MSVCRT_size_t size
, int radix
)
2154 unsigned __int64 val
;
2157 MSVCRT_wchar_t buffer
[65], *pos
;
2160 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
2161 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
2162 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
2165 return MSVCRT_EINVAL
;
2168 if (value
< 0 && radix
== 10)
2175 is_negative
= FALSE
;
2184 digit
= val
% radix
;
2188 *--pos
= '0' + digit
;
2190 *--pos
= 'a' + digit
- 10;
2197 len
= buffer
+ 65 - pos
;
2201 MSVCRT_wchar_t
*p
= str
;
2203 /* Copy the temporary buffer backwards up to the available number of
2204 * characters. Don't copy the negative sign if present. */
2212 for (pos
= buffer
+ 63, i
= 0; i
< size
; i
++)
2216 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE
);
2217 return MSVCRT_ERANGE
;
2220 memcpy(str
, pos
, len
* sizeof(MSVCRT_wchar_t
));
2224 #define I10_OUTPUT_MAX_PREC 21
2225 /* Internal structure used by $I10_OUTPUT */
2226 struct _I10_OUTPUT_DATA
{
2230 char str
[I10_OUTPUT_MAX_PREC
+1]; /* add space for '\0' */
2233 /*********************************************************************
2234 * $I10_OUTPUT (MSVCRT.@)
2235 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
2236 * prec - precision of part, we're interested in
2237 * flag - 0 for first prec digits, 1 for fractional part
2238 * data - data to be populated
2241 * 0 if given double is NaN or INF
2245 * Native sets last byte of data->str to '0' or '9', I don't know what
2246 * it means. Current implementation sets it always to '0'.
2248 int CDECL
MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld80
, int prec
, int flag
, struct _I10_OUTPUT_DATA
*data
)
2250 static const char inf_str
[] = "1#INF";
2251 static const char nan_str
[] = "1#QNAN";
2253 /* MS' long double type wants 12 bytes for Intel's 80 bit FP format.
2254 * Some UNIX have sizeof(long double) == 16, yet only 80 bit are used.
2255 * Assume long double uses 80 bit FP, never seen 128 bit FP. */
2259 char buf
[I10_OUTPUT_MAX_PREC
+9]; /* 9 = strlen("0.e+0000") + '\0' */
2262 memcpy(&ld
, &ld80
, 10);
2264 TRACE("(%lf %d %x %p)\n", d
, prec
, flag
, data
);
2275 memcpy(data
->str
, inf_str
, sizeof(inf_str
));
2283 memcpy(data
->str
, nan_str
, sizeof(nan_str
));
2289 int exp
= 1+floor(log10(d
));
2297 if(prec
+1 > I10_OUTPUT_MAX_PREC
)
2298 prec
= I10_OUTPUT_MAX_PREC
-1;
2304 sprintf(format
, "%%.%dle", prec
);
2305 sprintf(buf
, format
, d
);
2308 data
->pos
= atoi(buf
+prec
+3);
2312 for(p
= buf
+prec
+1; p
>buf
+1 && *p
=='0'; p
--);
2315 memcpy(data
->str
, buf
+1, data
->len
);
2316 data
->str
[data
->len
] = '\0';
2318 if(buf
[1]!='0' && prec
-data
->len
+1>0)
2319 memcpy(data
->str
+data
->len
+1, buf
+data
->len
+1, prec
-data
->len
+1);
2323 #undef I10_OUTPUT_MAX_PREC
2325 /*********************************************************************
2328 int __cdecl
MSVCRT_memcmp(const void *ptr1
, const void *ptr2
, MSVCRT_size_t n
)
2330 return memcmp(ptr1
, ptr2
, n
);
2333 /*********************************************************************
2336 void * __cdecl
MSVCRT_memcpy(void *dst
, const void *src
, MSVCRT_size_t n
)
2338 return memmove(dst
, src
, n
);
2341 /*********************************************************************
2342 * memmove (MSVCRT.@)
2344 void * __cdecl
MSVCRT_memmove(void *dst
, const void *src
, MSVCRT_size_t n
)
2346 return memmove(dst
, src
, n
);
2349 /*********************************************************************
2352 void* __cdecl
MSVCRT_memset(void *dst
, int c
, MSVCRT_size_t n
)
2354 return memset(dst
, c
, n
);
2357 /*********************************************************************
2360 char* __cdecl
MSVCRT_strchr(const char *str
, int c
)
2362 return strchr(str
, c
);
2365 /*********************************************************************
2366 * strrchr (MSVCRT.@)
2368 char* __cdecl
MSVCRT_strrchr(const char *str
, int c
)
2370 return strrchr(str
, c
);
2373 /*********************************************************************
2376 void* __cdecl
MSVCRT_memchr(const void *ptr
, int c
, MSVCRT_size_t n
)
2378 return memchr(ptr
, c
, n
);
2381 /*********************************************************************
2384 int __cdecl
MSVCRT_strcmp(const char *str1
, const char *str2
)
2386 while (*str1
&& *str1
== *str2
) { str1
++; str2
++; }
2387 if ((unsigned char)*str1
> (unsigned char)*str2
) return 1;
2388 if ((unsigned char)*str1
< (unsigned char)*str2
) return -1;
2392 /*********************************************************************
2393 * strncmp (MSVCRT.@)
2395 int __cdecl
MSVCRT_strncmp(const char *str1
, const char *str2
, MSVCRT_size_t len
)
2398 while (--len
&& *str1
&& *str1
== *str2
) { str1
++; str2
++; }
2399 return (unsigned char)*str1
- (unsigned char)*str2
;
2402 /*********************************************************************
2403 * _strnicmp_l (MSVCRT.@)
2405 int __cdecl
MSVCRT__strnicmp_l(const char *s1
, const char *s2
,
2406 MSVCRT_size_t count
, MSVCRT__locale_t locale
)
2408 MSVCRT_pthreadlocinfo locinfo
;
2411 if(s1
==NULL
|| s2
==NULL
)
2412 return MSVCRT__NLSCMPERROR
;
2418 locinfo
= get_locinfo();
2420 locinfo
= locale
->locinfo
;
2422 if(!locinfo
->lc_handle
[MSVCRT_LC_CTYPE
])
2425 if ((c1
= *s1
++) >= 'A' && c1
<= 'Z')
2427 if ((c2
= *s2
++) >= 'A' && c2
<= 'Z')
2429 }while(--count
&& c1
&& c1
==c2
);
2435 c1
= MSVCRT__tolower_l((unsigned char)*s1
++, locale
);
2436 c2
= MSVCRT__tolower_l((unsigned char)*s2
++, locale
);
2437 }while(--count
&& c1
&& c1
==c2
);
2442 /*********************************************************************
2443 * _stricmp_l (MSVCRT.@)
2445 int __cdecl
MSVCRT__stricmp_l(const char *s1
, const char *s2
, MSVCRT__locale_t locale
)
2447 return MSVCRT__strnicmp_l(s1
, s2
, -1, locale
);
2450 /*********************************************************************
2451 * _strnicmp (MSVCRT.@)
2453 int __cdecl
MSVCRT__strnicmp(const char *s1
, const char *s2
, MSVCRT_size_t count
)
2455 return MSVCRT__strnicmp_l(s1
, s2
, count
, NULL
);
2458 /*********************************************************************
2459 * _stricmp (MSVCRT.@)
2461 int __cdecl
MSVCRT__stricmp(const char *s1
, const char *s2
)
2463 return MSVCRT__strnicmp_l(s1
, s2
, -1, NULL
);
2466 /*********************************************************************
2469 char* __cdecl
MSVCRT_strstr(const char *haystack
, const char *needle
)
2471 MSVCRT_size_t i
, j
, len
, needle_len
, lps_len
;
2474 needle_len
= MSVCRT_strlen(needle
);
2475 if (!needle_len
) return (char*)haystack
;
2476 lps_len
= needle_len
> ARRAY_SIZE(lps
) ? ARRAY_SIZE(lps
) : needle_len
;
2483 if (needle
[i
] == needle
[len
]) lps
[i
++] = ++len
;
2484 else if (len
) len
= lps
[len
-1];
2491 while (j
< lps_len
&& haystack
[i
] && haystack
[i
] == needle
[j
])
2497 if (j
== needle_len
) return (char*)haystack
+ i
- j
;
2500 if (j
== ARRAY_SIZE(lps
) && !MSVCRT_strncmp(haystack
+ i
, needle
+ j
, needle_len
- j
))
2501 return (char*)haystack
+ i
- j
;
2504 else if (haystack
[i
]) i
++;
2509 /*********************************************************************
2510 * _memicmp_l (MSVCRT.@)
2512 int __cdecl
MSVCRT__memicmp_l(const char *s1
, const char *s2
, MSVCRT_size_t len
, MSVCRT__locale_t locale
)
2516 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
2520 MSVCRT_INVALID_PMT(NULL
, EINVAL
);
2521 return len
? MSVCRT__NLSCMPERROR
: 0;
2527 if ((ret
= MSVCRT__tolower_l(*s1
, locale
) - MSVCRT__tolower_l(*s2
, locale
)))
2535 /*********************************************************************
2536 * _memicmp (MSVCRT.@)
2538 int __cdecl
MSVCRT__memicmp(const char *s1
, const char *s2
, MSVCRT_size_t len
)
2540 return MSVCRT__memicmp_l(s1
, s2
, len
, NULL
);
2543 /*********************************************************************
2544 * strcspn (MSVCRT.@)
2546 MSVCRT_size_t __cdecl
MSVCRT_strcspn(const char *str
, const char *reject
)
2551 memset(rejects
, 0, sizeof(rejects
));
2556 rejects
[(unsigned char)*p
] = TRUE
;
2561 while(*p
&& !rejects
[(unsigned char)*p
]) p
++;
2565 /*********************************************************************
2566 * strpbrk (MSVCRT.@)
2568 char* __cdecl
MSVCRT_strpbrk(const char *str
, const char *accept
)
2570 return strpbrk(str
, accept
);
2573 /*********************************************************************
2574 * __strncnt (MSVCRT.@)
2576 MSVCRT_size_t __cdecl
MSVCRT___strncnt(const char *str
, MSVCRT_size_t size
)
2578 MSVCRT_size_t ret
= 0;
2580 #if _MSVCR_VER >= 140
2581 while (*str
++ && size
--)
2583 while (size
-- && *str
++)
2594 /*********************************************************************
2595 * _strdec (CRTDLL.@)
2597 char * CDECL
_strdec(const char *str1
, const char *str2
)
2599 return (char *)(str2
- 1);
2602 /*********************************************************************
2603 * _strinc (CRTDLL.@)
2605 char * CDECL
_strinc(const char *str
)
2607 return (char *)(str
+ 1);
2610 /*********************************************************************
2611 * _strnextc (CRTDLL.@)
2613 unsigned int CDECL
_strnextc(const char *str
)
2615 return (unsigned char)str
[0];
2618 /*********************************************************************
2619 * _strninc (CRTDLL.@)
2621 char * CDECL
_strninc(const char *str
, size_t len
)
2623 return (char *)(str
+ len
);
2626 /*********************************************************************
2627 * _strspnp (CRTDLL.@)
2629 char * CDECL
_strspnp( const char *str1
, const char *str2
)
2631 str1
+= strspn( str1
, str2
);
2632 return *str1
? (char*)str1
: NULL
;