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"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
41 /*********************************************************************
45 char* CDECL
MSVCRT__strdup(const char* str
)
49 char * ret
= MSVCRT_malloc(strlen(str
)+1);
50 if (ret
) strcpy( ret
, str
);
56 /*********************************************************************
57 * _strlwr_s_l (MSVCRT.@)
59 int CDECL
MSVCRT__strlwr_s_l(char *str
, MSVCRT_size_t len
, MSVCRT__locale_t locale
)
61 MSVCRT_pthreadlocinfo locinfo
;
66 *MSVCRT__errno() = MSVCRT_EINVAL
;
79 *MSVCRT__errno() = MSVCRT_EINVAL
;
84 locinfo
= get_locinfo();
86 locinfo
= locale
->locinfo
;
88 if(!locinfo
->lc_handle
[MSVCRT_LC_CTYPE
])
92 if (*str
>= 'A' && *str
<= 'Z')
101 *str
= MSVCRT__tolower_l((unsigned char)*str
, locale
);
109 /*********************************************************************
110 * _strlwr_s (MSVCRT.@)
112 int CDECL
MSVCRT__strlwr_s(char *str
, MSVCRT_size_t len
)
114 return MSVCRT__strlwr_s_l(str
, len
, NULL
);
117 /*********************************************************************
118 * _strlwr_l (MSVCRT.@)
120 char* CDECL
_strlwr_l(char *str
, MSVCRT__locale_t locale
)
122 MSVCRT__strlwr_s_l(str
, -1, locale
);
126 /*********************************************************************
129 char* CDECL
MSVCRT__strlwr(char *str
)
131 MSVCRT__strlwr_s_l(str
, -1, NULL
);
135 /*********************************************************************
136 * _strupr_s_l (MSVCRT.@)
138 int CDECL
MSVCRT__strupr_s_l(char *str
, MSVCRT_size_t len
, MSVCRT__locale_t locale
)
140 MSVCRT_pthreadlocinfo locinfo
;
145 *MSVCRT__errno() = MSVCRT_EINVAL
;
146 return MSVCRT_EINVAL
;
158 *MSVCRT__errno() = MSVCRT_EINVAL
;
159 return MSVCRT_EINVAL
;
163 locinfo
= get_locinfo();
165 locinfo
= locale
->locinfo
;
167 if(!locinfo
->lc_handle
[MSVCRT_LC_CTYPE
])
171 if (*str
>= 'a' && *str
<= 'z')
180 *str
= MSVCRT__toupper_l((unsigned char)*str
, locale
);
188 /*********************************************************************
189 * _strupr_s (MSVCRT.@)
191 int CDECL
MSVCRT__strupr_s(char *str
, MSVCRT_size_t len
)
193 return MSVCRT__strupr_s_l(str
, len
, NULL
);
196 /*********************************************************************
197 * _strupr_l (MSVCRT.@)
199 char* CDECL
MSVCRT__strupr_l(char *str
, MSVCRT__locale_t locale
)
201 MSVCRT__strupr_s_l(str
, -1, locale
);
205 /*********************************************************************
208 char* CDECL
MSVCRT__strupr(char *str
)
210 MSVCRT__strupr_s_l(str
, -1, NULL
);
214 /*********************************************************************
215 * _strnset_s (MSVCRT.@)
217 int CDECL
MSVCRT__strnset_s(char *str
, MSVCRT_size_t size
, int c
, MSVCRT_size_t count
)
221 if(!str
&& !size
&& !count
) return 0;
222 if(!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
223 if(!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
225 for(i
=0; i
<size
-1 && i
<count
; i
++) {
226 if(!str
[i
]) return 0;
230 if(!str
[i
]) return 0;
233 MSVCRT__invalid_parameter(NULL
, NULL
, NULL
, 0, 0);
234 *MSVCRT__errno() = MSVCRT_EINVAL
;
235 return MSVCRT_EINVAL
;
238 /*********************************************************************
239 * _strnset (MSVCRT.@)
241 char* CDECL
MSVCRT__strnset(char* str
, int value
, MSVCRT_size_t len
)
244 while (*str
&& len
--)
249 /*********************************************************************
252 char* CDECL
MSVCRT__strrev(char* str
)
258 for (p1
= str
, p2
= str
+ strlen(str
) - 1; p2
> p1
; ++p1
, --p2
)
268 /*********************************************************************
271 char* CDECL
_strset(char* str
, int value
)
280 /*********************************************************************
283 char * CDECL
MSVCRT_strtok( char *str
, const char *delim
)
285 thread_data_t
*data
= msvcrt_get_thread_data();
289 if (!(str
= data
->strtok_next
)) return NULL
;
291 while (*str
&& strchr( delim
, *str
)) str
++;
292 if (!*str
) return NULL
;
294 while (*str
&& !strchr( delim
, *str
)) str
++;
295 if (*str
) *str
++ = 0;
296 data
->strtok_next
= str
;
300 /*********************************************************************
301 * strtok_s (MSVCRT.@)
303 char * CDECL
MSVCRT_strtok_s(char *str
, const char *delim
, char **ctx
)
305 if (!MSVCRT_CHECK_PMT(delim
!= NULL
)) return NULL
;
306 if (!MSVCRT_CHECK_PMT(ctx
!= NULL
)) return NULL
;
307 if (!MSVCRT_CHECK_PMT(str
!= NULL
|| *ctx
!= NULL
)) return NULL
;
312 while(*str
&& strchr(delim
, *str
))
321 while(**ctx
&& !strchr(delim
, **ctx
))
329 /*********************************************************************
332 void CDECL
MSVCRT__swab(char* src
, char* dst
, int len
)
336 len
= (unsigned)len
>> 1;
348 static struct fpnum
fpnum(int sign
, int exp
, ULONGLONG m
, enum fpmod mod
)
359 int fpnum_double(struct fpnum
*fp
, double *d
)
363 if (fp
->mod
== FP_VAL_INFINITY
)
365 *d
= fp
->sign
* INFINITY
;
369 if (fp
->mod
== FP_VAL_NAN
)
373 bits
&= ~((ULONGLONG
)1 << (MANT_BITS
+ EXP_BITS
- 1));
374 *d
= *(double*)&bits
;
378 TRACE("%c %s *2^%d (round %d)\n", fp
->sign
== -1 ? '-' : '+',
379 wine_dbgstr_longlong(fp
->m
), fp
->exp
, fp
->mod
);
386 /* make sure that we don't overflow modifying exponent */
387 if (fp
->exp
> 1<<EXP_BITS
)
389 *d
= fp
->sign
* INFINITY
;
390 return MSVCRT_ERANGE
;
392 if (fp
->exp
< -(1<<EXP_BITS
))
395 return MSVCRT_ERANGE
;
397 fp
->exp
+= MANT_BITS
- 1;
399 /* normalize mantissa */
400 while(fp
->m
< (ULONGLONG
)1 << (MANT_BITS
-1))
405 while(fp
->m
>= (ULONGLONG
)1 << MANT_BITS
)
407 if (fp
->m
& 1 || fp
->mod
!= FP_ROUND_ZERO
)
409 if (!(fp
->m
& 1)) fp
->mod
= FP_ROUND_DOWN
;
410 else if(fp
->mod
== FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_EVEN
;
411 else fp
->mod
= FP_ROUND_UP
;
416 fp
->exp
+= (1 << (EXP_BITS
-1)) - 1;
418 /* handle subnormals */
421 if (fp
->m
& 1 && fp
->mod
== FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_EVEN
;
422 else if (fp
->m
& 1) fp
->mod
= FP_ROUND_UP
;
423 else if (fp
->mod
!= FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_DOWN
;
426 while(fp
->m
&& fp
->exp
<0)
428 if (fp
->m
& 1 && fp
->mod
== FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_EVEN
;
429 else if (fp
->m
& 1) fp
->mod
= FP_ROUND_UP
;
430 else if (fp
->mod
!= FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_DOWN
;
436 if (fp
->mod
== FP_ROUND_UP
|| (fp
->mod
== FP_ROUND_EVEN
&& fp
->m
& 1))
440 /* handle subnormal that falls into regular range due to rounding */
441 if (fp
->m
== (ULONGLONG
)1 << (MANT_BITS
- 1))
445 else if (fp
->m
>= (ULONGLONG
)1 << MANT_BITS
)
452 if (fp
->exp
>= (1<<EXP_BITS
)-1)
454 *d
= fp
->sign
* INFINITY
;
455 return MSVCRT_ERANGE
;
457 if (!fp
->m
|| fp
->exp
< 0)
460 return MSVCRT_ERANGE
;
464 bits
|= (ULONGLONG
)1 << (MANT_BITS
+ EXP_BITS
- 1);
465 bits
|= (ULONGLONG
)fp
->exp
<< (MANT_BITS
- 1);
466 bits
|= fp
->m
& (((ULONGLONG
)1 << (MANT_BITS
- 1)) - 1);
468 TRACE("returning %s\n", wine_dbgstr_longlong(bits
));
469 *d
= *(double*)&bits
;
473 #define LDBL_EXP_BITS 15
474 #define LDBL_MANT_BITS 64
475 int fpnum_ldouble(struct fpnum
*fp
, MSVCRT__LDOUBLE
*d
)
477 if (fp
->mod
== FP_VAL_INFINITY
)
480 d
->x80
[1] = 0x80000000;
481 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
483 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
487 if (fp
->mod
== FP_VAL_NAN
)
491 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
493 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
497 TRACE("%c %s *2^%d (round %d)\n", fp
->sign
== -1 ? '-' : '+',
498 wine_dbgstr_longlong(fp
->m
), fp
->exp
, fp
->mod
);
505 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
509 /* make sure that we don't overflow modifying exponent */
510 if (fp
->exp
> 1<<LDBL_EXP_BITS
)
513 d
->x80
[1] = 0x80000000;
514 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
516 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
517 return MSVCRT_ERANGE
;
519 if (fp
->exp
< -(1<<LDBL_EXP_BITS
))
525 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
526 return MSVCRT_ERANGE
;
528 fp
->exp
+= LDBL_MANT_BITS
- 1;
530 /* normalize mantissa */
531 while(fp
->m
< (ULONGLONG
)1 << (LDBL_MANT_BITS
-1))
536 fp
->exp
+= (1 << (LDBL_EXP_BITS
-1)) - 1;
538 /* handle subnormals */
541 if (fp
->m
& 1 && fp
->mod
== FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_EVEN
;
542 else if (fp
->m
& 1) fp
->mod
= FP_ROUND_UP
;
543 else if (fp
->mod
!= FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_DOWN
;
546 while(fp
->m
&& fp
->exp
<0)
548 if (fp
->m
& 1 && fp
->mod
== FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_EVEN
;
549 else if (fp
->m
& 1) fp
->mod
= FP_ROUND_UP
;
550 else if (fp
->mod
!= FP_ROUND_ZERO
) fp
->mod
= FP_ROUND_DOWN
;
556 if (fp
->mod
== FP_ROUND_UP
|| (fp
->mod
== FP_ROUND_EVEN
&& fp
->m
& 1))
558 if (fp
->m
== MSVCRT_UI64_MAX
)
560 fp
->m
= (ULONGLONG
)1 << (LDBL_MANT_BITS
- 1);
567 /* handle subnormal that falls into regular range due to rounding */
568 if ((fp
->m
^ (fp
->m
- 1)) & ((ULONGLONG
)1 << (LDBL_MANT_BITS
- 1))) fp
->exp
++;
572 if (fp
->exp
>= (1<<LDBL_EXP_BITS
)-1)
575 d
->x80
[1] = 0x80000000;
576 d
->x80
[2] = (1 << LDBL_EXP_BITS
) - 1;
578 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
579 return MSVCRT_ERANGE
;
581 if (!fp
->m
|| fp
->exp
< 0)
587 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
588 return MSVCRT_ERANGE
;
592 d
->x80
[1] = fp
->m
>> 32;
595 d
->x80
[2] |= 1 << LDBL_EXP_BITS
;
599 #if _MSVCR_VER >= 140
601 static inline int hex2int(char c
)
603 if (c
>= '0' && c
<= '9')
605 else if (c
>= 'a' && c
<= 'f')
607 else if (c
>= 'A' && c
<= 'F')
612 static struct fpnum
fpnum_parse16(MSVCRT_wchar_t
get(void *ctx
), void unget(void *ctx
),
613 void *ctx
, int sign
, MSVCRT_pthreadlocinfo locinfo
)
615 BOOL found_digit
= FALSE
, found_dp
= FALSE
;
616 enum fpmod round
= FP_ROUND_ZERO
;
622 while(m
< MSVCRT_UI64_MAX
/16)
625 if (val
== -1) break;
634 if (val
== -1) break;
638 if (val
|| round
!= FP_ROUND_ZERO
)
640 if (val
< 8) round
= FP_ROUND_DOWN
;
641 else if (val
== 8 && round
== FP_ROUND_ZERO
) round
= FP_ROUND_EVEN
;
642 else round
= FP_ROUND_UP
;
646 if(nch
== *locinfo
->lconv
->decimal_point
)
651 else if (!found_digit
)
653 if(nch
!=MSVCRT_WEOF
) unget(ctx
);
655 return fpnum(0, 0, 0, 0);
658 while(m
<= MSVCRT_UI64_MAX
/16)
661 if (val
== -1) break;
671 if (val
== -1) break;
674 if (val
|| round
!= FP_ROUND_ZERO
)
676 if (val
< 8) round
= FP_ROUND_DOWN
;
677 else if (val
== 8 && round
== FP_ROUND_ZERO
) round
= FP_ROUND_EVEN
;
678 else round
= FP_ROUND_UP
;
684 if (nch
!= MSVCRT_WEOF
) unget(ctx
);
685 if (found_dp
) unget(ctx
);
687 return fpnum(0, 0, 0, 0);
690 if(nch
=='p' || nch
=='P') {
691 BOOL found_sign
= FALSE
;
699 } else if(nch
== '+') {
703 if(nch
>='0' && nch
<='9') {
704 while(nch
>='0' && nch
<='9') {
705 if(e
>INT_MAX
/10 || e
*10>INT_MAX
-nch
+'0')
711 if((nch
!=MSVCRT_WEOF
) && (nch
< '0' || nch
> '9')) unget(ctx
);
714 if(e
<0 && exp
<INT_MIN
-e
) exp
= INT_MIN
;
715 else if(e
>0 && exp
>INT_MAX
-e
) exp
= INT_MAX
;
718 if(nch
!= MSVCRT_WEOF
) unget(ctx
);
719 if(found_sign
) unget(ctx
);
724 return fpnum(sign
, exp
, m
, round
);
728 /* Converts first 3 limbs to ULONGLONG */
729 /* Return FALSE on overflow */
730 static inline BOOL
bnum_to_mant(struct bnum
*b
, ULONGLONG
*m
)
732 if(MSVCRT_UI64_MAX
/ LIMB_MAX
/ LIMB_MAX
< b
->data
[bnum_idx(b
, b
->e
-1)]) return FALSE
;
733 *m
= (ULONGLONG
)b
->data
[bnum_idx(b
, b
->e
-1)] * LIMB_MAX
* LIMB_MAX
;
734 if(b
->b
== b
->e
-1) return TRUE
;
735 if(MSVCRT_UI64_MAX
- *m
< (ULONGLONG
)b
->data
[bnum_idx(b
, b
->e
-2)] * LIMB_MAX
) return FALSE
;
736 *m
+= (ULONGLONG
)b
->data
[bnum_idx(b
, b
->e
-2)] * LIMB_MAX
;
737 if(b
->b
== b
->e
-2) return TRUE
;
738 if(MSVCRT_UI64_MAX
- *m
< b
->data
[bnum_idx(b
, b
->e
-3)]) return FALSE
;
739 *m
+= b
->data
[bnum_idx(b
, b
->e
-3)];
743 static struct fpnum
fpnum_parse_bnum(MSVCRT_wchar_t (*get
)(void *ctx
), void (*unget
)(void *ctx
),
744 void *ctx
, MSVCRT_pthreadlocinfo locinfo
, BOOL ldouble
, struct bnum
*b
)
746 #if _MSVCR_VER >= 140
747 MSVCRT_wchar_t _infinity
[] = { 'i', 'n', 'f', 'i', 'n', 'i', 't', 'y', 0 };
748 MSVCRT_wchar_t _nan
[] = { 'n', 'a', 'n', 0 };
749 MSVCRT_wchar_t
*str_match
= NULL
;
752 BOOL found_digit
= FALSE
, found_dp
= FALSE
, found_sign
= FALSE
;
753 int e2
= 0, dp
=0, sign
=1, off
, limb_digits
= 0, i
;
754 enum fpmod round
= FP_ROUND_ZERO
;
763 } else if(nch
== '+') {
768 #if _MSVCR_VER >= 140
769 if(nch
== _infinity
[0] || nch
== MSVCRT__toupper(_infinity
[0]))
770 str_match
= _infinity
;
771 if(nch
== _nan
[0] || nch
== MSVCRT__toupper(_nan
[0]))
773 while(str_match
&& nch
!= MSVCRT_WEOF
&&
774 (nch
== str_match
[matched
] || nch
== MSVCRT__toupper(str_match
[matched
]))) {
780 if(matched
>= 8) keep
= 8;
781 else if(matched
>= 3) keep
= 3;
782 if(nch
!= MSVCRT_WEOF
) unget(ctx
);
783 for (; matched
> keep
; matched
--) {
787 if (str_match
== _infinity
)
788 return fpnum(sign
, 0, 0, FP_VAL_INFINITY
);
789 if (str_match
== _nan
)
790 return fpnum(sign
, 0, 0, FP_VAL_NAN
);
791 } else if(found_sign
) {
795 return fpnum(0, 0, 0, 0);
801 if(nch
== 'x' || nch
== 'X')
802 return fpnum_parse16(get
, unget
, ctx
, sign
, locinfo
);
814 while(nch
>='0' && nch
<='9') {
816 if(limb_digits
== LIMB_DIGITS
) {
817 if(bnum_idx(b
, b
->b
-1) == bnum_idx(b
, b
->e
)) break;
820 b
->data
[bnum_idx(b
, b
->b
)] = 0;
825 b
->data
[bnum_idx(b
, b
->b
)] = b
->data
[bnum_idx(b
, b
->b
)] * 10 + nch
- '0';
830 while(nch
>='0' && nch
<='9') {
831 if(nch
!= '0') b
->data
[bnum_idx(b
, b
->b
)] |= 1;
836 if(nch
== *locinfo
->lconv
->decimal_point
) {
841 /* skip leading '0' */
842 if(nch
=='0' && !limb_digits
&& !b
->b
) {
850 while(nch
>='0' && nch
<='9') {
852 if(limb_digits
== LIMB_DIGITS
) {
853 if(bnum_idx(b
, b
->b
-1) == bnum_idx(b
, b
->e
)) break;
856 b
->data
[bnum_idx(b
, b
->b
)] = 0;
861 b
->data
[bnum_idx(b
, b
->b
)] = b
->data
[bnum_idx(b
, b
->b
)] * 10 + nch
- '0';
865 while(nch
>='0' && nch
<='9') {
866 if(nch
!= '0') b
->data
[bnum_idx(b
, b
->b
)] |= 1;
871 if(nch
!= MSVCRT_WEOF
) unget(ctx
);
872 if(found_dp
) unget(ctx
);
873 if(found_sign
) unget(ctx
);
874 return fpnum(0, 0, 0, 0);
877 if(nch
=='e' || nch
=='E' || nch
=='d' || nch
=='D') {
885 } else if(nch
== '+') {
892 if(nch
>='0' && nch
<='9') {
893 while(nch
>='0' && nch
<='9') {
894 if(e
>INT_MAX
/10 || e
*10>INT_MAX
-nch
+'0')
900 if(nch
!= MSVCRT_WEOF
) unget(ctx
);
903 if(e
<0 && dp
<INT_MIN
-e
) dp
= INT_MIN
;
904 else if(e
>0 && dp
>INT_MAX
-e
) dp
= INT_MAX
;
907 if(nch
!= MSVCRT_WEOF
) unget(ctx
);
908 if(found_sign
) unget(ctx
);
911 } else if(nch
!= MSVCRT_WEOF
) {
915 if(!b
->data
[bnum_idx(b
, b
->e
-1)])
916 return fpnum(sign
, 0, 0, 0);
918 /* Fill last limb with 0 if needed */
920 for(; limb_digits
!= LIMB_DIGITS
; limb_digits
++)
921 b
->data
[bnum_idx(b
, b
->b
)] *= 10;
923 for(; bnum_idx(b
, b
->b
) < bnum_idx(b
, b
->e
); b
->b
++) {
924 if(b
->data
[bnum_idx(b
, b
->b
)]) break;
927 /* move decimal point to limb boundary */
928 if(limb_digits
==dp
&& b
->b
==b
->e
-1)
929 return fpnum(sign
, 0, b
->data
[bnum_idx(b
, b
->e
-1)], FP_ROUND_ZERO
);
930 off
= (dp
- limb_digits
) % LIMB_DIGITS
;
931 if(off
< 0) off
+= LIMB_DIGITS
;
932 if(off
) bnum_mult(b
, p10s
[off
]);
934 if(dp
-1 > (ldouble
? DBL80_MAX_10_EXP
: MSVCRT_DBL_MAX_10_EXP
))
935 return fpnum(sign
, INT_MAX
, 1, FP_ROUND_ZERO
);
936 /* Count part of exponent stored in denormalized mantissa. */
937 /* Increase exponent range to handle subnormals. */
938 if(dp
-1 < (ldouble
? DBL80_MIN_10_EXP
: MSVCRT_DBL_MIN_10_EXP
-MSVCRT_DBL_DIG
-18))
939 return fpnum(sign
, INT_MIN
, 1, FP_ROUND_ZERO
);
941 while(dp
> 3*LIMB_DIGITS
) {
942 if(bnum_rshift(b
, 9)) dp
-= LIMB_DIGITS
;
945 while(dp
<= 2*LIMB_DIGITS
) {
946 if(bnum_lshift(b
, 29)) dp
+= LIMB_DIGITS
;
949 /* Make sure most significant mantissa bit will be set */
950 while(b
->data
[bnum_idx(b
, b
->e
-1)] <= 9) {
954 while(!bnum_to_mant(b
, &m
)) {
959 if(b
->e
-4 >= b
->b
&& b
->data
[bnum_idx(b
, b
->e
-4)]) {
960 if(b
->data
[bnum_idx(b
, b
->e
-4)] > LIMB_MAX
/2) round
= FP_ROUND_UP
;
961 else if(b
->data
[bnum_idx(b
, b
->e
-4)] == LIMB_MAX
/2) round
= FP_ROUND_EVEN
;
962 else round
= FP_ROUND_DOWN
;
964 if(round
== FP_ROUND_ZERO
|| round
== FP_ROUND_EVEN
) {
965 for(i
=b
->e
-5; i
>=b
->b
; i
--) {
966 if(!b
->data
[bnum_idx(b
, b
->b
)]) continue;
967 if(round
== FP_ROUND_EVEN
) round
= FP_ROUND_UP
;
968 else round
= FP_ROUND_DOWN
;
972 return fpnum(sign
, e2
, m
, round
);
975 struct fpnum
fpnum_parse(MSVCRT_wchar_t (*get
)(void *ctx
), void (*unget
)(void *ctx
),
976 void *ctx
, MSVCRT_pthreadlocinfo locinfo
, BOOL ldouble
)
979 BYTE bnum_data
[FIELD_OFFSET(struct bnum
, data
[BNUM_PREC64
])];
980 struct bnum
*b
= (struct bnum
*)bnum_data
;
982 b
->size
= BNUM_PREC64
;
983 return fpnum_parse_bnum(get
, unget
, ctx
, locinfo
, ldouble
, b
);
985 BYTE bnum_data
[FIELD_OFFSET(struct bnum
, data
[BNUM_PREC80
])];
986 struct bnum
*b
= (struct bnum
*)bnum_data
;
988 b
->size
= BNUM_PREC80
;
989 return fpnum_parse_bnum(get
, unget
, ctx
, locinfo
, ldouble
, b
);
993 static MSVCRT_wchar_t
strtod_str_get(void *ctx
)
995 const char **p
= ctx
;
996 if (!**p
) return MSVCRT_WEOF
;
1000 static void strtod_str_unget(void *ctx
)
1002 const char **p
= ctx
;
1006 static inline double strtod_helper(const char *str
, char **end
, MSVCRT__locale_t locale
, int *perr
)
1008 MSVCRT_pthreadlocinfo locinfo
;
1009 const char *beg
, *p
;
1014 if (perr
) *perr
= 0;
1016 else *MSVCRT__errno() = 0;
1019 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) {
1020 if (end
) *end
= NULL
;
1025 locinfo
= get_locinfo();
1027 locinfo
= locale
->locinfo
;
1030 while(MSVCRT__isspace_l((unsigned char)*p
, locale
))
1034 fp
= fpnum_parse(strtod_str_get
, strtod_str_unget
, &p
, locinfo
, FALSE
);
1035 if (end
) *end
= (p
== beg
? (char*)str
: (char*)p
);
1037 err
= fpnum_double(&fp
, &ret
);
1038 if (perr
) *perr
= err
;
1039 else if(err
) *MSVCRT__errno() = err
;
1043 /*********************************************************************
1044 * strtod_l (MSVCRT.@)
1046 double CDECL
MSVCRT_strtod_l(const char *str
, char **end
, MSVCRT__locale_t locale
)
1048 return strtod_helper(str
, end
, locale
, NULL
);
1051 /*********************************************************************
1054 double CDECL
MSVCRT_strtod( const char *str
, char **end
)
1056 return MSVCRT_strtod_l( str
, end
, NULL
);
1061 /*********************************************************************
1062 * strtof_l (MSVCR120.@)
1064 float CDECL
MSVCRT__strtof_l( const char *str
, char **end
, MSVCRT__locale_t locale
)
1066 return MSVCRT_strtod_l(str
, end
, locale
);
1069 /*********************************************************************
1070 * strtof (MSVCR120.@)
1072 float CDECL
MSVCRT_strtof( const char *str
, char **end
)
1074 return MSVCRT__strtof_l(str
, end
, NULL
);
1077 #endif /* _MSVCR_VER>=120 */
1079 /*********************************************************************
1082 double CDECL
MSVCRT_atof( const char *str
)
1084 return MSVCRT_strtod_l(str
, NULL
, NULL
);
1087 /*********************************************************************
1088 * _atof_l (MSVCRT.@)
1090 double CDECL
MSVCRT__atof_l( const char *str
, MSVCRT__locale_t locale
)
1092 return MSVCRT_strtod_l(str
, NULL
, locale
);
1095 /*********************************************************************
1096 * _atoflt_l (MSVCRT.@)
1098 int CDECL
MSVCRT__atoflt_l( MSVCRT__CRT_FLOAT
*value
, char *str
, MSVCRT__locale_t locale
)
1103 d
= strtod_helper(str
, NULL
, locale
, &err
);
1106 return MSVCRT__OVERFLOW
;
1107 if((d
!=0 || err
) && value
->f
>-MSVCRT_FLT_MIN
&& value
->f
<MSVCRT_FLT_MIN
)
1108 return MSVCRT__UNDERFLOW
;
1112 /*********************************************************************
1113 * _atoflt (MSVCR100.@)
1115 int CDECL
MSVCRT__atoflt(MSVCRT__CRT_FLOAT
*value
, char *str
)
1117 return MSVCRT__atoflt_l(value
, str
, NULL
);
1120 /*********************************************************************
1121 * _atodbl_l (MSVCRT.@)
1123 int CDECL
MSVCRT__atodbl_l(MSVCRT__CRT_DOUBLE
*value
, char *str
, MSVCRT__locale_t locale
)
1127 value
->x
= strtod_helper(str
, NULL
, locale
, &err
);
1129 return MSVCRT__OVERFLOW
;
1130 if((value
->x
!=0 || err
) && value
->x
>-MSVCRT_DBL_MIN
&& value
->x
<MSVCRT_DBL_MIN
)
1131 return MSVCRT__UNDERFLOW
;
1135 /*********************************************************************
1136 * _atodbl (MSVCRT.@)
1138 int CDECL
MSVCRT__atodbl(MSVCRT__CRT_DOUBLE
*value
, char *str
)
1140 return MSVCRT__atodbl_l(value
, str
, NULL
);
1143 /*********************************************************************
1144 * _strcoll_l (MSVCRT.@)
1146 int CDECL
MSVCRT_strcoll_l( const char* str1
, const char* str2
, MSVCRT__locale_t locale
)
1148 MSVCRT_pthreadlocinfo locinfo
;
1151 locinfo
= get_locinfo();
1153 locinfo
= locale
->locinfo
;
1155 if(!locinfo
->lc_handle
[MSVCRT_LC_COLLATE
])
1156 return MSVCRT_strcmp(str1
, str2
);
1157 return CompareStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
], 0, str1
, -1, str2
, -1)-CSTR_EQUAL
;
1160 /*********************************************************************
1161 * strcoll (MSVCRT.@)
1163 int CDECL
MSVCRT_strcoll( const char* str1
, const char* str2
)
1165 return MSVCRT_strcoll_l(str1
, str2
, NULL
);
1168 /*********************************************************************
1169 * _stricoll_l (MSVCRT.@)
1171 int CDECL
MSVCRT__stricoll_l( const char* str1
, const char* str2
, MSVCRT__locale_t locale
)
1173 MSVCRT_pthreadlocinfo locinfo
;
1176 locinfo
= get_locinfo();
1178 locinfo
= locale
->locinfo
;
1180 if(!locinfo
->lc_handle
[MSVCRT_LC_COLLATE
])
1181 return MSVCRT__stricmp(str1
, str2
);
1182 return CompareStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
], NORM_IGNORECASE
,
1183 str1
, -1, str2
, -1)-CSTR_EQUAL
;
1186 /*********************************************************************
1187 * _stricoll (MSVCRT.@)
1189 int CDECL
MSVCRT__stricoll( const char* str1
, const char* str2
)
1191 return MSVCRT__stricoll_l(str1
, str2
, NULL
);
1194 /*********************************************************************
1195 * _strncoll_l (MSVCRT.@)
1197 int CDECL
MSVCRT__strncoll_l( const char* str1
, const char* str2
, MSVCRT_size_t count
, MSVCRT__locale_t locale
)
1199 MSVCRT_pthreadlocinfo locinfo
;
1202 locinfo
= get_locinfo();
1204 locinfo
= locale
->locinfo
;
1206 if(!locinfo
->lc_handle
[MSVCRT_LC_COLLATE
])
1207 return MSVCRT_strncmp(str1
, str2
, count
);
1208 return CompareStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
], 0,
1209 str1
, MSVCRT_strnlen(str1
, count
),
1210 str2
, MSVCRT_strnlen(str2
, count
))-CSTR_EQUAL
;
1213 /*********************************************************************
1214 * _strncoll (MSVCRT.@)
1216 int CDECL
MSVCRT__strncoll( const char* str1
, const char* str2
, MSVCRT_size_t count
)
1218 return MSVCRT__strncoll_l(str1
, str2
, count
, NULL
);
1221 /*********************************************************************
1222 * _strnicoll_l (MSVCRT.@)
1224 int CDECL
MSVCRT__strnicoll_l( const char* str1
, const char* str2
, MSVCRT_size_t count
, MSVCRT__locale_t locale
)
1226 MSVCRT_pthreadlocinfo locinfo
;
1229 locinfo
= get_locinfo();
1231 locinfo
= locale
->locinfo
;
1233 if(!locinfo
->lc_handle
[MSVCRT_LC_COLLATE
])
1234 return MSVCRT__strnicmp(str1
, str2
, count
);
1235 return CompareStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
], NORM_IGNORECASE
,
1236 str1
, MSVCRT_strnlen(str1
, count
),
1237 str2
, MSVCRT_strnlen(str2
, count
))-CSTR_EQUAL
;
1240 /*********************************************************************
1241 * _strnicoll (MSVCRT.@)
1243 int CDECL
MSVCRT__strnicoll( const char* str1
, const char* str2
, MSVCRT_size_t count
)
1245 return MSVCRT__strnicoll_l(str1
, str2
, count
, NULL
);
1248 /*********************************************************************
1249 * strncpy (MSVCRT.@)
1251 char* __cdecl
MSVCRT_strncpy(char *dst
, const char *src
, MSVCRT_size_t len
)
1255 for(i
=0; i
<len
; i
++)
1256 if((dst
[i
] = src
[i
]) == '\0') break;
1258 while (i
< len
) dst
[i
++] = 0;
1263 /*********************************************************************
1266 char* CDECL
MSVCRT_strcpy(char *dst
, const char *src
)
1269 while ((*dst
++ = *src
++));
1273 /*********************************************************************
1274 * strcpy_s (MSVCRT.@)
1276 int CDECL
MSVCRT_strcpy_s( char* dst
, MSVCRT_size_t elem
, const char* src
)
1279 if(!elem
) return MSVCRT_EINVAL
;
1280 if(!dst
) return MSVCRT_EINVAL
;
1284 return MSVCRT_EINVAL
;
1287 for(i
= 0; i
< elem
; i
++)
1289 if((dst
[i
] = src
[i
]) == '\0') return 0;
1292 return MSVCRT_ERANGE
;
1295 /*********************************************************************
1296 * strcat_s (MSVCRT.@)
1298 int CDECL
MSVCRT_strcat_s( char* dst
, MSVCRT_size_t elem
, const char* src
)
1301 if(!dst
) return MSVCRT_EINVAL
;
1302 if(elem
== 0) return MSVCRT_EINVAL
;
1306 return MSVCRT_EINVAL
;
1309 for(i
= 0; i
< elem
; i
++)
1313 for(j
= 0; (j
+ i
) < elem
; j
++)
1315 if((dst
[j
+ i
] = src
[j
]) == '\0') return 0;
1319 /* Set the first element to 0, not the first element after the skipped part */
1321 return MSVCRT_ERANGE
;
1324 /*********************************************************************
1327 char* __cdecl
MSVCRT_strcat( char *dst
, const char *src
)
1331 while ((*d
++ = *src
++));
1335 /*********************************************************************
1336 * strncat_s (MSVCRT.@)
1338 int CDECL
MSVCRT_strncat_s( char* dst
, MSVCRT_size_t elem
, const char* src
, MSVCRT_size_t count
)
1342 if (!MSVCRT_CHECK_PMT(dst
!= 0)) return MSVCRT_EINVAL
;
1343 if (!MSVCRT_CHECK_PMT(elem
!= 0)) return MSVCRT_EINVAL
;
1344 if (!MSVCRT_CHECK_PMT(src
!= 0))
1347 return MSVCRT_EINVAL
;
1350 for(i
= 0; i
< elem
; i
++)
1354 for(j
= 0; (j
+ i
) < elem
; j
++)
1356 if(count
== MSVCRT__TRUNCATE
&& j
+ i
== elem
- 1)
1359 return MSVCRT_STRUNCATE
;
1361 if(j
== count
|| (dst
[j
+ i
] = src
[j
]) == '\0')
1369 /* Set the first element to 0, not the first element after the skipped part */
1371 return MSVCRT_ERANGE
;
1374 /*********************************************************************
1375 * strncat (MSVCRT.@)
1377 char* __cdecl
MSVCRT_strncat(char *dst
, const char *src
, MSVCRT_size_t len
)
1381 for ( ; len
&& *src
; d
++, src
++, len
--) *d
= *src
;
1386 /*********************************************************************
1387 * _strxfrm_l (MSVCRT.@)
1389 MSVCRT_size_t CDECL
MSVCRT__strxfrm_l( char *dest
, const char *src
,
1390 MSVCRT_size_t len
, MSVCRT__locale_t locale
)
1392 MSVCRT_pthreadlocinfo locinfo
;
1395 if(!MSVCRT_CHECK_PMT(src
)) return INT_MAX
;
1396 if(!MSVCRT_CHECK_PMT(dest
|| !len
)) return INT_MAX
;
1399 FIXME("len > INT_MAX not supported\n");
1404 locinfo
= get_locinfo();
1406 locinfo
= locale
->locinfo
;
1408 if(!locinfo
->lc_handle
[MSVCRT_LC_COLLATE
]) {
1409 MSVCRT_strncpy(dest
, src
, len
);
1413 ret
= LCMapStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
],
1414 LCMAP_SORTKEY
, src
, -1, NULL
, 0);
1416 if(len
) dest
[0] = 0;
1417 *MSVCRT__errno() = MSVCRT_EILSEQ
;
1420 if(!len
) return ret
-1;
1424 *MSVCRT__errno() = MSVCRT_ERANGE
;
1428 return LCMapStringA(locinfo
->lc_handle
[MSVCRT_LC_COLLATE
],
1429 LCMAP_SORTKEY
, src
, -1, dest
, len
) - 1;
1432 /*********************************************************************
1433 * strxfrm (MSVCRT.@)
1435 MSVCRT_size_t CDECL
MSVCRT_strxfrm( char *dest
, const char *src
, MSVCRT_size_t len
)
1437 return MSVCRT__strxfrm_l(dest
, src
, len
, NULL
);
1440 /********************************************************************
1441 * __STRINGTOLD_L (MSVCR80.@)
1443 int CDECL
__STRINGTOLD_L( MSVCRT__LDOUBLE
*value
, char **endptr
,
1444 const char *str
, int flags
, MSVCRT__locale_t locale
)
1446 MSVCRT_pthreadlocinfo locinfo
;
1447 const char *beg
, *p
;
1451 if (flags
) FIXME("flags not supported: %x\n", flags
);
1454 locinfo
= get_locinfo();
1456 locinfo
= locale
->locinfo
;
1459 while (MSVCRT__isspace_l((unsigned char)*p
, locale
))
1463 fp
= fpnum_parse(strtod_str_get
, strtod_str_unget
, &p
, locinfo
, TRUE
);
1464 if (endptr
) *endptr
= (p
== beg
? (char*)str
: (char*)p
);
1465 if (p
== beg
) ret
= 4;
1467 err
= fpnum_ldouble(&fp
, value
);
1468 if (err
) ret
= (value
->x80
[2] & 0x7fff ? 2 : 1);
1472 /********************************************************************
1473 * __STRINGTOLD (MSVCRT.@)
1475 int CDECL
__STRINGTOLD( MSVCRT__LDOUBLE
*value
, char **endptr
, const char *str
, int flags
)
1477 return __STRINGTOLD_L( value
, endptr
, str
, flags
, NULL
);
1480 /********************************************************************
1481 * _atoldbl_l (MSVCRT.@)
1483 int CDECL
MSVCRT__atoldbl_l( MSVCRT__LDOUBLE
*value
, const char *str
, MSVCRT__locale_t locale
)
1486 switch(__STRINGTOLD_L( value
, &endptr
, str
, 0, locale
))
1488 case 1: return MSVCRT__UNDERFLOW
;
1489 case 2: return MSVCRT__OVERFLOW
;
1494 /********************************************************************
1495 * _atoldbl (MSVCRT.@)
1497 int CDECL
MSVCRT__atoldbl(MSVCRT__LDOUBLE
*value
, const char *str
)
1499 return MSVCRT__atoldbl_l( value
, str
, NULL
);
1502 /*********************************************************************
1505 MSVCRT_size_t __cdecl
MSVCRT_strlen(const char *str
)
1507 const char *s
= str
;
1512 /******************************************************************
1513 * strnlen (MSVCRT.@)
1515 MSVCRT_size_t CDECL
MSVCRT_strnlen(const char *s
, MSVCRT_size_t maxlen
)
1519 for(i
=0; i
<maxlen
; i
++)
1525 /*********************************************************************
1526 * _strtoi64_l (MSVCRT.@)
1528 * FIXME: locale parameter is ignored
1530 __int64 CDECL
MSVCRT_strtoi64_l(const char *nptr
, char **endptr
, int base
, MSVCRT__locale_t locale
)
1532 const char *p
= nptr
;
1533 BOOL negative
= FALSE
;
1534 BOOL got_digit
= FALSE
;
1537 TRACE("(%s %p %d %p)\n", debugstr_a(nptr
), endptr
, base
, locale
);
1539 if (!MSVCRT_CHECK_PMT(nptr
!= NULL
)) return 0;
1540 if (!MSVCRT_CHECK_PMT(base
== 0 || base
>= 2)) return 0;
1541 if (!MSVCRT_CHECK_PMT(base
<= 36)) return 0;
1543 while(MSVCRT__isspace_l((unsigned char)*nptr
, locale
)) nptr
++;
1548 } else if(*nptr
== '+')
1551 if((base
==0 || base
==16) && *nptr
=='0' && MSVCRT__tolower_l(*(nptr
+1), locale
)=='x') {
1564 char cur
= MSVCRT__tolower_l(*nptr
, locale
);
1567 if(cur
>='0' && cur
<='9') {
1572 if(cur
<'a' || cur
>='a'+base
-10)
1583 if(!negative
&& (ret
>MSVCRT_I64_MAX
/base
|| ret
*base
>MSVCRT_I64_MAX
-v
)) {
1584 ret
= MSVCRT_I64_MAX
;
1585 *MSVCRT__errno() = MSVCRT_ERANGE
;
1586 } else if(negative
&& (ret
<MSVCRT_I64_MIN
/base
|| ret
*base
<MSVCRT_I64_MIN
-v
)) {
1587 ret
= MSVCRT_I64_MIN
;
1588 *MSVCRT__errno() = MSVCRT_ERANGE
;
1594 *endptr
= (char*)(got_digit
? nptr
: p
);
1599 /*********************************************************************
1600 * _strtoi64 (MSVCRT.@)
1602 __int64 CDECL
MSVCRT_strtoi64(const char *nptr
, char **endptr
, int base
)
1604 return MSVCRT_strtoi64_l(nptr
, endptr
, base
, NULL
);
1607 /*********************************************************************
1608 * _atoi_l (MSVCRT.@)
1610 int __cdecl
MSVCRT__atoi_l(const char *str
, MSVCRT__locale_t locale
)
1612 __int64 ret
= MSVCRT_strtoi64_l(str
, NULL
, 10, locale
);
1616 *MSVCRT__errno() = MSVCRT_ERANGE
;
1617 } else if(ret
< INT_MIN
) {
1619 *MSVCRT__errno() = MSVCRT_ERANGE
;
1624 /*********************************************************************
1628 int __cdecl
MSVCRT_atoi(const char *str
)
1636 while(MSVCRT__isspace_l((unsigned char)*str
, NULL
)) str
++;
1640 }else if(*str
== '-') {
1645 while(*str
>='0' && *str
<='9') {
1646 ret
= ret
*10+*str
-'0';
1650 return minus
? -ret
: ret
;
1653 int CDECL
MSVCRT_atoi(const char *str
)
1655 return MSVCRT__atoi_l(str
, NULL
);
1659 /******************************************************************
1660 * _atoi64_l (MSVCRT.@)
1662 __int64 CDECL
MSVCRT__atoi64_l(const char *str
, MSVCRT__locale_t locale
)
1664 return MSVCRT_strtoi64_l(str
, NULL
, 10, locale
);
1667 /******************************************************************
1668 * _atoi64 (MSVCRT.@)
1670 __int64 CDECL
MSVCRT__atoi64(const char *str
)
1672 return MSVCRT_strtoi64_l(str
, NULL
, 10, NULL
);
1675 /******************************************************************
1676 * _atol_l (MSVCRT.@)
1678 MSVCRT_long CDECL
MSVCRT__atol_l(const char *str
, MSVCRT__locale_t locale
)
1680 __int64 ret
= MSVCRT_strtoi64_l(str
, NULL
, 10, locale
);
1682 if(ret
> MSVCRT_LONG_MAX
) {
1683 ret
= MSVCRT_LONG_MAX
;
1684 *MSVCRT__errno() = MSVCRT_ERANGE
;
1685 } else if(ret
< MSVCRT_LONG_MIN
) {
1686 ret
= MSVCRT_LONG_MIN
;
1687 *MSVCRT__errno() = MSVCRT_ERANGE
;
1692 /******************************************************************
1695 MSVCRT_long CDECL
MSVCRT_atol(const char *str
)
1698 return MSVCRT_atoi(str
);
1700 return MSVCRT__atol_l(str
, NULL
);
1706 /******************************************************************
1707 * _atoll_l (MSVCR120.@)
1709 MSVCRT_longlong CDECL
MSVCRT__atoll_l(const char* str
, MSVCRT__locale_t locale
)
1711 return MSVCRT_strtoi64_l(str
, NULL
, 10, locale
);
1714 /******************************************************************
1715 * atoll (MSVCR120.@)
1717 MSVCRT_longlong CDECL
MSVCRT_atoll(const char* str
)
1719 return MSVCRT__atoll_l(str
, NULL
);
1722 #endif /* if _MSVCR_VER>=120 */
1724 /******************************************************************
1725 * _strtol_l (MSVCRT.@)
1727 MSVCRT_long CDECL
MSVCRT__strtol_l(const char* nptr
,
1728 char** end
, int base
, MSVCRT__locale_t locale
)
1730 __int64 ret
= MSVCRT_strtoi64_l(nptr
, end
, base
, locale
);
1732 if(ret
> MSVCRT_LONG_MAX
) {
1733 ret
= MSVCRT_LONG_MAX
;
1734 *MSVCRT__errno() = MSVCRT_ERANGE
;
1735 } else if(ret
< MSVCRT_LONG_MIN
) {
1736 ret
= MSVCRT_LONG_MIN
;
1737 *MSVCRT__errno() = MSVCRT_ERANGE
;
1743 /******************************************************************
1746 MSVCRT_long CDECL
MSVCRT_strtol(const char* nptr
, char** end
, int base
)
1748 return MSVCRT__strtol_l(nptr
, end
, base
, NULL
);
1751 /******************************************************************
1752 * _strtoul_l (MSVCRT.@)
1754 MSVCRT_ulong CDECL
MSVCRT_strtoul_l(const char* nptr
, char** end
, int base
, MSVCRT__locale_t locale
)
1756 __int64 ret
= MSVCRT_strtoi64_l(nptr
, end
, base
, locale
);
1758 if(ret
> MSVCRT_ULONG_MAX
) {
1759 ret
= MSVCRT_ULONG_MAX
;
1760 *MSVCRT__errno() = MSVCRT_ERANGE
;
1761 }else if(ret
< -(__int64
)MSVCRT_ULONG_MAX
) {
1763 *MSVCRT__errno() = MSVCRT_ERANGE
;
1769 /******************************************************************
1770 * strtoul (MSVCRT.@)
1772 MSVCRT_ulong CDECL
MSVCRT_strtoul(const char* nptr
, char** end
, int base
)
1774 return MSVCRT_strtoul_l(nptr
, end
, base
, NULL
);
1777 /*********************************************************************
1778 * _strtoui64_l (MSVCRT.@)
1780 * FIXME: locale parameter is ignored
1782 unsigned __int64 CDECL
MSVCRT_strtoui64_l(const char *nptr
, char **endptr
, int base
, MSVCRT__locale_t locale
)
1784 const char *p
= nptr
;
1785 BOOL negative
= FALSE
;
1786 BOOL got_digit
= FALSE
;
1787 unsigned __int64 ret
= 0;
1789 TRACE("(%s %p %d %p)\n", debugstr_a(nptr
), endptr
, base
, locale
);
1791 if (!MSVCRT_CHECK_PMT(nptr
!= NULL
)) return 0;
1792 if (!MSVCRT_CHECK_PMT(base
== 0 || base
>= 2)) return 0;
1793 if (!MSVCRT_CHECK_PMT(base
<= 36)) return 0;
1795 while(MSVCRT__isspace_l((unsigned char)*nptr
, locale
)) nptr
++;
1800 } else if(*nptr
== '+')
1803 if((base
==0 || base
==16) && *nptr
=='0' && MSVCRT__tolower_l(*(nptr
+1), locale
)=='x') {
1816 char cur
= MSVCRT__tolower_l(*nptr
, locale
);
1819 if(cur
>='0' && cur
<='9') {
1824 if(cur
<'a' || cur
>='a'+base
-10)
1832 if(ret
>MSVCRT_UI64_MAX
/base
|| ret
*base
>MSVCRT_UI64_MAX
-v
) {
1833 ret
= MSVCRT_UI64_MAX
;
1834 *MSVCRT__errno() = MSVCRT_ERANGE
;
1840 *endptr
= (char*)(got_digit
? nptr
: p
);
1842 return negative
? -ret
: ret
;
1845 /*********************************************************************
1846 * _strtoui64 (MSVCRT.@)
1848 unsigned __int64 CDECL
MSVCRT_strtoui64(const char *nptr
, char **endptr
, int base
)
1850 return MSVCRT_strtoui64_l(nptr
, endptr
, base
, NULL
);
1853 static int ltoa_helper(MSVCRT_long value
, char *str
, MSVCRT_size_t size
, int radix
)
1858 char buffer
[33], *pos
;
1861 if (value
< 0 && radix
== 10)
1868 is_negative
= FALSE
;
1877 digit
= val
% radix
;
1881 *--pos
= '0' + digit
;
1883 *--pos
= 'a' + digit
- 10;
1890 len
= buffer
+ 33 - pos
;
1896 /* Copy the temporary buffer backwards up to the available number of
1897 * characters. Don't copy the negative sign if present. */
1905 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
1909 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE
);
1910 return MSVCRT_ERANGE
;
1913 memcpy(str
, pos
, len
);
1917 /*********************************************************************
1918 * _ltoa_s (MSVCRT.@)
1920 int CDECL
MSVCRT__ltoa_s(MSVCRT_long value
, char *str
, MSVCRT_size_t size
, int radix
)
1922 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
1923 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
1924 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
1927 return MSVCRT_EINVAL
;
1930 return ltoa_helper(value
, str
, size
, radix
);
1933 /*********************************************************************
1934 * _ltow_s (MSVCRT.@)
1936 int CDECL
MSVCRT__ltow_s(MSVCRT_long value
, MSVCRT_wchar_t
*str
, MSVCRT_size_t size
, int radix
)
1941 MSVCRT_wchar_t buffer
[33], *pos
;
1944 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
1945 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
1946 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
1949 return MSVCRT_EINVAL
;
1952 if (value
< 0 && radix
== 10)
1959 is_negative
= FALSE
;
1968 digit
= val
% radix
;
1972 *--pos
= '0' + digit
;
1974 *--pos
= 'a' + digit
- 10;
1981 len
= buffer
+ 33 - pos
;
1985 MSVCRT_wchar_t
*p
= str
;
1987 /* Copy the temporary buffer backwards up to the available number of
1988 * characters. Don't copy the negative sign if present. */
1996 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2000 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE
);
2001 return MSVCRT_ERANGE
;
2004 memcpy(str
, pos
, len
* sizeof(MSVCRT_wchar_t
));
2008 /*********************************************************************
2009 * _itoa_s (MSVCRT.@)
2011 int CDECL
MSVCRT__itoa_s(int value
, char *str
, MSVCRT_size_t size
, int radix
)
2013 return MSVCRT__ltoa_s(value
, str
, size
, radix
);
2016 /*********************************************************************
2019 char* CDECL
MSVCRT__itoa(int value
, char *str
, int radix
)
2021 return ltoa_helper(value
, str
, MSVCRT_SIZE_MAX
, radix
) ? NULL
: str
;
2024 /*********************************************************************
2025 * _itow_s (MSVCRT.@)
2027 int CDECL
MSVCRT__itow_s(int value
, MSVCRT_wchar_t
*str
, MSVCRT_size_t size
, int radix
)
2029 return MSVCRT__ltow_s(value
, str
, size
, radix
);
2032 /*********************************************************************
2033 * _ui64toa_s (MSVCRT.@)
2035 int CDECL
MSVCRT__ui64toa_s(unsigned __int64 value
, char *str
,
2036 MSVCRT_size_t size
, int radix
)
2038 char buffer
[65], *pos
;
2041 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
2042 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
2043 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
2046 return MSVCRT_EINVAL
;
2053 digit
= value
%radix
;
2059 *--pos
= 'a'+digit
-10;
2062 if(buffer
-pos
+65 > size
) {
2063 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL
);
2064 return MSVCRT_EINVAL
;
2067 memcpy(str
, pos
, buffer
-pos
+65);
2071 /*********************************************************************
2072 * _ui64tow_s (MSVCRT.@)
2074 int CDECL
MSVCRT__ui64tow_s( unsigned __int64 value
, MSVCRT_wchar_t
*str
,
2075 MSVCRT_size_t size
, int radix
)
2077 MSVCRT_wchar_t buffer
[65], *pos
;
2080 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
2081 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
2082 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
2085 return MSVCRT_EINVAL
;
2092 digit
= value
% radix
;
2093 value
= value
/ radix
;
2095 *--pos
= '0' + digit
;
2097 *--pos
= 'a' + digit
- 10;
2098 } while (value
!= 0);
2100 if(buffer
-pos
+65 > size
) {
2101 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL
);
2102 return MSVCRT_EINVAL
;
2105 memcpy(str
, pos
, (buffer
-pos
+65)*sizeof(MSVCRT_wchar_t
));
2109 /*********************************************************************
2110 * _ultoa_s (MSVCRT.@)
2112 int CDECL
MSVCRT__ultoa_s(MSVCRT_ulong value
, char *str
, MSVCRT_size_t size
, int radix
)
2115 char buffer
[33], *pos
;
2118 if (!str
|| !size
|| radix
< 2 || radix
> 36)
2123 *MSVCRT__errno() = MSVCRT_EINVAL
;
2124 return MSVCRT_EINVAL
;
2132 digit
= value
% radix
;
2136 *--pos
= '0' + digit
;
2138 *--pos
= 'a' + digit
- 10;
2142 len
= buffer
+ 33 - pos
;
2148 /* Copy the temporary buffer backwards up to the available number of
2151 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2155 *MSVCRT__errno() = MSVCRT_ERANGE
;
2156 return MSVCRT_ERANGE
;
2159 memcpy(str
, pos
, len
);
2163 /*********************************************************************
2164 * _ultow_s (MSVCRT.@)
2166 int CDECL
MSVCRT__ultow_s(MSVCRT_ulong value
, MSVCRT_wchar_t
*str
, MSVCRT_size_t size
, int radix
)
2169 WCHAR buffer
[33], *pos
;
2172 if (!str
|| !size
|| radix
< 2 || radix
> 36)
2177 *MSVCRT__errno() = MSVCRT_EINVAL
;
2178 return MSVCRT_EINVAL
;
2186 digit
= value
% radix
;
2190 *--pos
= '0' + digit
;
2192 *--pos
= 'a' + digit
- 10;
2196 len
= buffer
+ 33 - pos
;
2202 /* Copy the temporary buffer backwards up to the available number of
2205 for (pos
= buffer
+ 31, i
= 0; i
< size
; i
++)
2209 *MSVCRT__errno() = MSVCRT_ERANGE
;
2210 return MSVCRT_ERANGE
;
2213 memcpy(str
, pos
, len
* sizeof(MSVCRT_wchar_t
));
2217 /*********************************************************************
2218 * _i64toa_s (MSVCRT.@)
2220 int CDECL
MSVCRT__i64toa_s(__int64 value
, char *str
, MSVCRT_size_t size
, int radix
)
2222 unsigned __int64 val
;
2225 char buffer
[65], *pos
;
2228 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
2229 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
2230 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
2233 return MSVCRT_EINVAL
;
2236 if (value
< 0 && radix
== 10)
2243 is_negative
= FALSE
;
2252 digit
= val
% radix
;
2256 *--pos
= '0' + digit
;
2258 *--pos
= 'a' + digit
- 10;
2265 len
= buffer
+ 65 - pos
;
2271 /* Copy the temporary buffer backwards up to the available number of
2272 * characters. Don't copy the negative sign if present. */
2280 for (pos
= buffer
+ 63, i
= 0; i
< size
; i
++)
2284 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE
);
2285 return MSVCRT_ERANGE
;
2288 memcpy(str
, pos
, len
);
2292 /*********************************************************************
2293 * _i64tow_s (MSVCRT.@)
2295 int CDECL
MSVCRT__i64tow_s(__int64 value
, MSVCRT_wchar_t
*str
, MSVCRT_size_t size
, int radix
)
2297 unsigned __int64 val
;
2300 MSVCRT_wchar_t buffer
[65], *pos
;
2303 if (!MSVCRT_CHECK_PMT(str
!= NULL
)) return MSVCRT_EINVAL
;
2304 if (!MSVCRT_CHECK_PMT(size
> 0)) return MSVCRT_EINVAL
;
2305 if (!MSVCRT_CHECK_PMT(radix
>= 2 && radix
<= 36))
2308 return MSVCRT_EINVAL
;
2311 if (value
< 0 && radix
== 10)
2318 is_negative
= FALSE
;
2327 digit
= val
% radix
;
2331 *--pos
= '0' + digit
;
2333 *--pos
= 'a' + digit
- 10;
2340 len
= buffer
+ 65 - pos
;
2344 MSVCRT_wchar_t
*p
= str
;
2346 /* Copy the temporary buffer backwards up to the available number of
2347 * characters. Don't copy the negative sign if present. */
2355 for (pos
= buffer
+ 63, i
= 0; i
< size
; i
++)
2359 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE
);
2360 return MSVCRT_ERANGE
;
2363 memcpy(str
, pos
, len
* sizeof(MSVCRT_wchar_t
));
2367 #define I10_OUTPUT_MAX_PREC 21
2368 /* Internal structure used by $I10_OUTPUT */
2369 struct _I10_OUTPUT_DATA
{
2373 char str
[I10_OUTPUT_MAX_PREC
+1]; /* add space for '\0' */
2376 /*********************************************************************
2377 * $I10_OUTPUT (MSVCRT.@)
2378 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
2379 * prec - precision of part, we're interested in
2380 * flag - 0 for first prec digits, 1 for fractional part
2381 * data - data to be populated
2384 * 0 if given double is NaN or INF
2388 * Native sets last byte of data->str to '0' or '9', I don't know what
2389 * it means. Current implementation sets it always to '0'.
2391 int CDECL
MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld80
, int prec
, int flag
, struct _I10_OUTPUT_DATA
*data
)
2393 static const char inf_str
[] = "1#INF";
2394 static const char nan_str
[] = "1#QNAN";
2396 /* MS' long double type wants 12 bytes for Intel's 80 bit FP format.
2397 * Some UNIX have sizeof(long double) == 16, yet only 80 bit are used.
2398 * Assume long double uses 80 bit FP, never seen 128 bit FP. */
2402 char buf
[I10_OUTPUT_MAX_PREC
+9]; /* 9 = strlen("0.e+0000") + '\0' */
2405 memcpy(&ld
, &ld80
, 10);
2407 TRACE("(%lf %d %x %p)\n", d
, prec
, flag
, data
);
2418 memcpy(data
->str
, inf_str
, sizeof(inf_str
));
2426 memcpy(data
->str
, nan_str
, sizeof(nan_str
));
2432 int exp
= 1+floor(log10(d
));
2440 if(prec
+1 > I10_OUTPUT_MAX_PREC
)
2441 prec
= I10_OUTPUT_MAX_PREC
-1;
2447 MSVCRT_sprintf(format
, "%%.%dle", prec
);
2448 MSVCRT_sprintf(buf
, format
, d
);
2451 data
->pos
= atoi(buf
+prec
+3);
2455 for(p
= buf
+prec
+1; p
>buf
+1 && *p
=='0'; p
--);
2458 memcpy(data
->str
, buf
+1, data
->len
);
2459 data
->str
[data
->len
] = '\0';
2461 if(buf
[1]!='0' && prec
-data
->len
+1>0)
2462 memcpy(data
->str
+data
->len
+1, buf
+data
->len
+1, prec
-data
->len
+1);
2466 #undef I10_OUTPUT_MAX_PREC
2468 /*********************************************************************
2471 int __cdecl
MSVCRT_memcmp(const void *ptr1
, const void *ptr2
, MSVCRT_size_t n
)
2473 const unsigned char *p1
, *p2
;
2475 for (p1
= ptr1
, p2
= ptr2
; n
; n
--, p1
++, p2
++)
2477 if (*p1
< *p2
) return -1;
2478 if (*p1
> *p2
) return 1;
2483 /*********************************************************************
2484 * memmove (MSVCRT.@)
2486 #ifdef WORDS_BIGENDIAN
2487 # define MERGE(w1, sh1, w2, sh2) ((w1 << sh1) | (w2 >> sh2))
2489 # define MERGE(w1, sh1, w2, sh2) ((w1 >> sh1) | (w2 << sh2))
2491 void * __cdecl
MSVCRT_memmove(void *dst
, const void *src
, MSVCRT_size_t n
)
2493 unsigned char *d
= dst
;
2494 const unsigned char *s
= src
;
2499 if ((MSVCRT_size_t
)dst
- (MSVCRT_size_t
)src
>= n
)
2501 for (; (MSVCRT_size_t
)d
% sizeof(MSVCRT_size_t
) && n
; n
--) *d
++ = *s
++;
2503 sh1
= 8 * ((MSVCRT_size_t
)s
% sizeof(MSVCRT_size_t
));
2506 while (n
>= sizeof(MSVCRT_size_t
))
2508 *(MSVCRT_size_t
*)d
= *(MSVCRT_size_t
*)s
;
2509 s
+= sizeof(MSVCRT_size_t
);
2510 d
+= sizeof(MSVCRT_size_t
);
2511 n
-= sizeof(MSVCRT_size_t
);
2514 else if (n
>= 2 * sizeof(MSVCRT_size_t
))
2516 int sh2
= 8 * sizeof(MSVCRT_size_t
) - sh1
;
2520 x
= *(MSVCRT_size_t
*)s
;
2523 s
+= sizeof(MSVCRT_size_t
);
2524 y
= *(MSVCRT_size_t
*)s
;
2525 *(MSVCRT_size_t
*)d
= MERGE(x
, sh1
, y
, sh2
);
2526 d
+= sizeof(MSVCRT_size_t
);
2528 s
+= sizeof(MSVCRT_size_t
);
2529 x
= *(MSVCRT_size_t
*)s
;
2530 *(MSVCRT_size_t
*)d
= MERGE(y
, sh1
, x
, sh2
);
2531 d
+= sizeof(MSVCRT_size_t
);
2533 n
-= 2 * sizeof(MSVCRT_size_t
);
2534 } while (n
>= 2 * sizeof(MSVCRT_size_t
));
2537 while (n
--) *d
++ = *s
++;
2545 for (; (MSVCRT_size_t
)d
% sizeof(MSVCRT_size_t
) && n
; n
--) *--d
= *--s
;
2547 sh1
= 8 * ((MSVCRT_size_t
)s
% sizeof(MSVCRT_size_t
));
2550 while (n
>= sizeof(MSVCRT_size_t
))
2552 s
-= sizeof(MSVCRT_size_t
);
2553 d
-= sizeof(MSVCRT_size_t
);
2554 *(MSVCRT_size_t
*)d
= *(MSVCRT_size_t
*)s
;
2555 n
-= sizeof(MSVCRT_size_t
);
2558 else if (n
>= 2 * sizeof(MSVCRT_size_t
))
2560 int sh2
= 8 * sizeof(MSVCRT_size_t
) - sh1
;
2564 x
= *(MSVCRT_size_t
*)s
;
2567 s
-= sizeof(MSVCRT_size_t
);
2568 y
= *(MSVCRT_size_t
*)s
;
2569 d
-= sizeof(MSVCRT_size_t
);
2570 *(MSVCRT_size_t
*)d
= MERGE(y
, sh1
, x
, sh2
);
2572 s
-= sizeof(MSVCRT_size_t
);
2573 x
= *(MSVCRT_size_t
*)s
;
2574 d
-= sizeof(MSVCRT_size_t
);
2575 *(MSVCRT_size_t
*)d
= MERGE(x
, sh1
, y
, sh2
);
2577 n
-= 2 * sizeof(MSVCRT_size_t
);
2578 } while (n
>= 2 * sizeof(MSVCRT_size_t
));
2581 while (n
--) *--d
= *--s
;
2587 /*********************************************************************
2590 void * __cdecl
MSVCRT_memcpy(void *dst
, const void *src
, MSVCRT_size_t n
)
2592 return MSVCRT_memmove(dst
, src
, n
);
2595 /*********************************************************************
2598 void* __cdecl
MSVCRT_memset(void *dst
, int c
, MSVCRT_size_t n
)
2600 volatile unsigned char *d
= dst
; /* avoid gcc optimizations */
2601 while (n
--) *d
++ = c
;
2605 /*********************************************************************
2608 char* __cdecl
MSVCRT_strchr(const char *str
, int c
)
2612 if (*str
== (char)c
) return (char*)str
;
2617 /*********************************************************************
2618 * strrchr (MSVCRT.@)
2620 char* __cdecl
MSVCRT_strrchr(const char *str
, int c
)
2623 do { if (*str
== (char)c
) ret
= (char*)str
; } while (*str
++);
2627 /*********************************************************************
2630 void* __cdecl
MSVCRT_memchr(const void *ptr
, int c
, MSVCRT_size_t n
)
2632 const unsigned char *p
= ptr
;
2634 for (p
= ptr
; n
; n
--, p
++) if (*p
== c
) return (void *)(ULONG_PTR
)p
;
2638 /*********************************************************************
2641 int __cdecl
MSVCRT_strcmp(const char *str1
, const char *str2
)
2643 while (*str1
&& *str1
== *str2
) { str1
++; str2
++; }
2644 if ((unsigned char)*str1
> (unsigned char)*str2
) return 1;
2645 if ((unsigned char)*str1
< (unsigned char)*str2
) return -1;
2649 /*********************************************************************
2650 * strncmp (MSVCRT.@)
2652 int __cdecl
MSVCRT_strncmp(const char *str1
, const char *str2
, MSVCRT_size_t len
)
2655 while (--len
&& *str1
&& *str1
== *str2
) { str1
++; str2
++; }
2656 return (unsigned char)*str1
- (unsigned char)*str2
;
2659 /*********************************************************************
2660 * _strnicmp_l (MSVCRT.@)
2662 int __cdecl
MSVCRT__strnicmp_l(const char *s1
, const char *s2
,
2663 MSVCRT_size_t count
, MSVCRT__locale_t locale
)
2665 MSVCRT_pthreadlocinfo locinfo
;
2668 if(s1
==NULL
|| s2
==NULL
)
2669 return MSVCRT__NLSCMPERROR
;
2675 locinfo
= get_locinfo();
2677 locinfo
= locale
->locinfo
;
2679 if(!locinfo
->lc_handle
[MSVCRT_LC_CTYPE
])
2682 if ((c1
= *s1
++) >= 'A' && c1
<= 'Z')
2684 if ((c2
= *s2
++) >= 'A' && c2
<= 'Z')
2686 }while(--count
&& c1
&& c1
==c2
);
2692 c1
= MSVCRT__tolower_l((unsigned char)*s1
++, locale
);
2693 c2
= MSVCRT__tolower_l((unsigned char)*s2
++, locale
);
2694 }while(--count
&& c1
&& c1
==c2
);
2699 /*********************************************************************
2700 * _stricmp_l (MSVCRT.@)
2702 int __cdecl
MSVCRT__stricmp_l(const char *s1
, const char *s2
, MSVCRT__locale_t locale
)
2704 return MSVCRT__strnicmp_l(s1
, s2
, -1, locale
);
2707 /*********************************************************************
2708 * _strnicmp (MSVCRT.@)
2710 int __cdecl
MSVCRT__strnicmp(const char *s1
, const char *s2
, MSVCRT_size_t count
)
2712 return MSVCRT__strnicmp_l(s1
, s2
, count
, NULL
);
2715 /*********************************************************************
2716 * _stricmp (MSVCRT.@)
2718 int __cdecl
MSVCRT__stricmp(const char *s1
, const char *s2
)
2720 return MSVCRT__strnicmp_l(s1
, s2
, -1, NULL
);
2723 /*********************************************************************
2726 char* __cdecl
MSVCRT_strstr(const char *haystack
, const char *needle
)
2728 MSVCRT_size_t i
, j
, len
, needle_len
, lps_len
;
2731 needle_len
= MSVCRT_strlen(needle
);
2732 if (!needle_len
) return (char*)haystack
;
2733 lps_len
= needle_len
> ARRAY_SIZE(lps
) ? ARRAY_SIZE(lps
) : needle_len
;
2740 if (needle
[i
] == needle
[len
]) lps
[i
++] = ++len
;
2741 else if (len
) len
= lps
[len
-1];
2748 while (j
< lps_len
&& haystack
[i
] && haystack
[i
] == needle
[j
])
2754 if (j
== needle_len
) return (char*)haystack
+ i
- j
;
2757 if (j
== ARRAY_SIZE(lps
) && !MSVCRT_strncmp(haystack
+ i
, needle
+ j
, needle_len
- j
))
2758 return (char*)haystack
+ i
- j
;
2761 else if (haystack
[i
]) i
++;
2766 /*********************************************************************
2767 * _memicmp_l (MSVCRT.@)
2769 int __cdecl
MSVCRT__memicmp_l(const char *s1
, const char *s2
, MSVCRT_size_t len
, MSVCRT__locale_t locale
)
2773 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
2777 MSVCRT_INVALID_PMT(NULL
, EINVAL
);
2778 return len
? MSVCRT__NLSCMPERROR
: 0;
2784 if ((ret
= MSVCRT__tolower_l(*s1
, locale
) - MSVCRT__tolower_l(*s2
, locale
)))
2792 /*********************************************************************
2793 * _memicmp (MSVCRT.@)
2795 int __cdecl
MSVCRT__memicmp(const char *s1
, const char *s2
, MSVCRT_size_t len
)
2797 return MSVCRT__memicmp_l(s1
, s2
, len
, NULL
);
2800 /*********************************************************************
2801 * strcspn (MSVCRT.@)
2803 MSVCRT_size_t __cdecl
MSVCRT_strcspn(const char *str
, const char *reject
)
2808 memset(rejects
, 0, sizeof(rejects
));
2813 rejects
[(unsigned char)*p
] = TRUE
;
2818 while(*p
&& !rejects
[(unsigned char)*p
]) p
++;
2822 /*********************************************************************
2823 * strpbrk (MSVCRT.@)
2825 char* __cdecl
MSVCRT_strpbrk(const char *str
, const char *accept
)
2827 for (; *str
; str
++) if (strchr( accept
, *str
)) return (char*)str
;
2831 /*********************************************************************
2832 * __strncnt (MSVCRT.@)
2834 MSVCRT_size_t __cdecl
MSVCRT___strncnt(const char *str
, MSVCRT_size_t size
)
2836 MSVCRT_size_t ret
= 0;
2838 #if _MSVCR_VER >= 140
2839 while (*str
++ && size
--)
2841 while (size
-- && *str
++)
2852 /*********************************************************************
2853 * _strdec (CRTDLL.@)
2855 char * CDECL
_strdec(const char *str1
, const char *str2
)
2857 return (char *)(str2
- 1);
2860 /*********************************************************************
2861 * _strinc (CRTDLL.@)
2863 char * CDECL
_strinc(const char *str
)
2865 return (char *)(str
+ 1);
2868 /*********************************************************************
2869 * _strnextc (CRTDLL.@)
2871 unsigned int CDECL
_strnextc(const char *str
)
2873 return (unsigned char)str
[0];
2876 /*********************************************************************
2877 * _strninc (CRTDLL.@)
2879 char * CDECL
_strninc(const char *str
, size_t len
)
2881 return (char *)(str
+ len
);
2884 /*********************************************************************
2885 * _strspnp (CRTDLL.@)
2887 char * CDECL
_strspnp( const char *str1
, const char *str2
)
2889 str1
+= strspn( str1
, str2
);
2890 return *str1
? (char*)str1
: NULL
;