msvcrt: Fix a couple of spelling errors in comments.
[wine.git] / dlls / msvcrt / string.c
blob7baf8eee8e81c2b091309842666e98541e5f543f
1 /*
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
25 #include "config.h"
26 #include "wine/port.h"
28 #include <assert.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <limits.h>
33 #include <errno.h>
34 #include "msvcrt.h"
35 #include "winnls.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
40 /*********************************************************************
41 * _mbsdup (MSVCRT.@)
42 * _strdup (MSVCRT.@)
44 char* CDECL MSVCRT__strdup(const char* str)
46 if(str)
48 char * ret = MSVCRT_malloc(strlen(str)+1);
49 if (ret) strcpy( ret, str );
50 return ret;
52 else return 0;
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;
61 char *ptr = str;
63 if (!str || !len)
65 *MSVCRT__errno() = MSVCRT_EINVAL;
66 return MSVCRT_EINVAL;
69 while (len && *ptr)
71 len--;
72 ptr++;
75 if (!len)
77 str[0] = '\0';
78 *MSVCRT__errno() = MSVCRT_EINVAL;
79 return MSVCRT_EINVAL;
82 if(!locale)
83 locinfo = get_locinfo();
84 else
85 locinfo = locale->locinfo;
87 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
89 while (*str)
91 if (*str >= 'A' && *str <= 'Z')
92 *str -= 'A' - 'a';
93 str++;
96 else
98 while (*str)
100 *str = MSVCRT__tolower_l((unsigned char)*str, locale);
101 str++;
105 return 0;
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);
122 return str;
125 /*********************************************************************
126 * _strlwr (MSVCRT.@)
128 char* CDECL MSVCRT__strlwr(char *str)
130 MSVCRT__strlwr_s_l(str, -1, NULL);
131 return str;
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;
140 char *ptr = str;
142 if (!str || !len)
144 *MSVCRT__errno() = MSVCRT_EINVAL;
145 return MSVCRT_EINVAL;
148 while (len && *ptr)
150 len--;
151 ptr++;
154 if (!len)
156 str[0] = '\0';
157 *MSVCRT__errno() = MSVCRT_EINVAL;
158 return MSVCRT_EINVAL;
161 if(!locale)
162 locinfo = get_locinfo();
163 else
164 locinfo = locale->locinfo;
166 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
168 while (*str)
170 if (*str >= 'a' && *str <= 'z')
171 *str -= 'a' - 'A';
172 str++;
175 else
177 while (*str)
179 *str = MSVCRT__toupper_l((unsigned char)*str, locale);
180 str++;
184 return 0;
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);
201 return str;
204 /*********************************************************************
205 * _strupr (MSVCRT.@)
207 char* CDECL MSVCRT__strupr(char *str)
209 MSVCRT__strupr_s_l(str, -1, NULL);
210 return str;
213 /*********************************************************************
214 * _strnset_s (MSVCRT.@)
216 int CDECL MSVCRT__strnset_s(char *str, MSVCRT_size_t size, int c, MSVCRT_size_t count)
218 MSVCRT_size_t i;
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;
226 str[i] = c;
228 for(; i<size; i++)
229 if(!str[i]) return 0;
231 str[0] = 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)
242 if (len > 0 && str)
243 while (*str && len--)
244 *str++ = value;
245 return str;
248 /*********************************************************************
249 * _strrev (MSVCRT.@)
251 char* CDECL MSVCRT__strrev(char* str)
253 char * p1;
254 char * p2;
256 if (str && *str)
257 for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
259 *p1 ^= *p2;
260 *p2 ^= *p1;
261 *p1 ^= *p2;
264 return str;
267 /*********************************************************************
268 * _strset (MSVCRT.@)
270 char* CDECL _strset(char* str, int value)
272 char *ptr = str;
273 while (*ptr)
274 *ptr++ = value;
276 return str;
279 /*********************************************************************
280 * strtok (MSVCRT.@)
282 char * CDECL MSVCRT_strtok( char *str, const char *delim )
284 thread_data_t *data = msvcrt_get_thread_data();
285 char *ret;
287 if (!str)
288 if (!(str = data->strtok_next)) return NULL;
290 while (*str && strchr( delim, *str )) str++;
291 if (!*str) return NULL;
292 ret = str++;
293 while (*str && !strchr( delim, *str )) str++;
294 if (*str) *str++ = 0;
295 data->strtok_next = str;
296 return ret;
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;
308 if(!str)
309 str = *ctx;
311 while(*str && strchr(delim, *str))
312 str++;
313 if(!*str)
315 *ctx = str;
316 return NULL;
319 *ctx = str+1;
320 while(**ctx && !strchr(delim, **ctx))
321 (*ctx)++;
322 if(**ctx)
323 *(*ctx)++ = 0;
325 return str;
328 /*********************************************************************
329 * _swab (MSVCRT.@)
331 void CDECL MSVCRT__swab(char* src, char* dst, int len)
333 if (len > 1)
335 len = (unsigned)len >> 1;
337 while (len--) {
338 char s0 = src[0];
339 char s1 = src[1];
340 *dst++ = s1;
341 *dst++ = s0;
342 src = src + 2;
347 enum round {
348 ROUND_ZERO, /* only used when dropped part contains only zeros */
349 ROUND_DOWN,
350 ROUND_EVEN,
351 ROUND_UP
354 static double make_double(int sign, int exp, ULONGLONG m, enum round round, int *err)
356 #define EXP_BITS 11
357 #define MANT_BITS 53
358 ULONGLONG bits = 0;
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;
372 return sign * 0.0;
374 exp += MANT_BITS - 1;
376 /* normalize mantissa */
377 while(m < (ULONGLONG)1 << (MANT_BITS-1))
379 m <<= 1;
380 exp--;
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;
390 m >>= 1;
391 exp++;
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)
400 m++;
401 m >>= 1;
402 exp++;
403 round = ROUND_DOWN;
407 /* handle subnormals */
408 if (exp <= 0)
409 m >>= 1;
410 while(m && exp<0)
412 m >>= 1;
413 exp++;
416 /* round mantissa */
417 if (round == ROUND_UP || (round == ROUND_EVEN && m & 1))
419 m++;
420 if (m >= (ULONGLONG)1 << MANT_BITS)
422 exp++;
423 m >>= 1;
427 if (exp >= 1<<EXP_BITS)
429 if (err) *err = MSVCRT_ERANGE;
430 return sign * INFINITY;
432 if (!m || exp < 0)
434 if (err) *err = MSVCRT_ERANGE;
435 return sign * 0.0;
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')
451 return c - '0';
452 else if (c >= 'a' && c <= 'f')
453 return c - 'a' + 10;
454 else if (c >= 'A' && c <= 'F')
455 return c - 'A' + 10;
456 return -1;
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;
464 MSVCRT_wchar_t nch;
465 ULONGLONG m = 0;
466 int val, exp = 0;
468 nch = get(ctx);
469 while(m < MSVCRT_UI64_MAX/16)
471 val = hex2int(nch);
472 if (val == -1) break;
473 found_digit = TRUE;
474 nch = get(ctx);
476 m = m*16 + val;
478 while(1)
480 val = hex2int(nch);
481 if (val == -1) break;
482 nch = get(ctx);
483 exp += 4;
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)
495 found_dp = TRUE;
496 nch = get(ctx);
498 else if (!found_digit)
500 if(nch!=MSVCRT_WEOF) unget(ctx);
501 unget(ctx);
502 return 0.0;
505 while(m <= MSVCRT_UI64_MAX/16)
507 val = hex2int(nch);
508 if (val == -1) break;
509 found_digit = TRUE;
510 nch = get(ctx);
512 m = m*16 + val;
513 exp -= 4;
515 while(1)
517 val = hex2int(nch);
518 if (val == -1) break;
519 nch = get(ctx);
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;
529 if (!found_digit)
531 if (nch != MSVCRT_WEOF) unget(ctx);
532 if (found_dp) unget(ctx);
533 unget(ctx);
534 return 0.0;
537 if(nch=='p' || nch=='P') {
538 BOOL found_sign = FALSE;
539 int e=0, s=1;
541 nch = get(ctx);
542 if(nch == '-') {
543 found_sign = TRUE;
544 s = -1;
545 nch = get(ctx);
546 } else if(nch == '+') {
547 found_sign = TRUE;
548 nch = get(ctx);
550 if(nch>='0' && nch<='9') {
551 while(nch>='0' && nch<='9') {
552 if(e>INT_MAX/10 || e*10>INT_MAX-nch+'0')
553 e = INT_MAX;
554 else
555 e = e*10+nch-'0';
556 nch = get(ctx);
558 if((nch!=MSVCRT_WEOF) && (nch < '0' || nch > '9')) unget(ctx);
559 e *= s;
561 if(e<0 && exp<INT_MIN-e) exp = INT_MIN;
562 else if(e>0 && exp>INT_MAX-e) exp = INT_MAX;
563 else exp += e;
564 } else {
565 if(nch != MSVCRT_WEOF) unget(ctx);
566 if(found_sign) unget(ctx);
567 unget(ctx);
571 return make_double(sign, exp, m, round, err);
573 #endif
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) */
579 struct bnum {
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)];
590 return ret;
593 /* Returns TRUE if new most significant limb was added */
594 static inline BOOL bnum_lshift(struct bnum *b, int shift)
596 DWORD rest = 0;
597 ULONGLONG tmp;
598 int i;
600 /* The limbs number can change by up to 1 so shift <= 29 */
601 assert(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)])
609 b->b++;
612 if(rest) {
613 b->data[BNUM_IDX(b->e)] = rest;
614 b->e++;
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;
618 b->b++;
620 return TRUE;
622 return FALSE;
625 /* Returns TRUE if most significant limb was removed */
626 static inline BOOL bnum_rshift(struct bnum *b, int shift)
628 DWORD tmp, rest = 0;
629 BOOL ret = FALSE;
630 int i;
632 /* Compute LIMB_MAX << shift without accuracy loss */
633 assert(shift <= 9);
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)]) {
640 b->e--;
641 ret = TRUE;
645 if(rest) {
646 if(BNUM_IDX(b->b-1) == BNUM_IDX(b->e)) {
647 if(rest) b->data[BNUM_IDX(b->b)] |= 1;
648 } else {
649 b->b--;
650 b->data[BNUM_IDX(b->b)] = rest;
653 return ret;
656 static inline void bnum_mult(struct bnum *b, int mult)
658 DWORD rest = 0;
659 ULONGLONG tmp;
660 int i;
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)])
670 b->b++;
673 if(rest) {
674 b->data[BNUM_IDX(b->e)] = rest;
675 b->e++;
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;
679 b->b++;
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;
693 int matched=0;
694 #endif
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;
698 MSVCRT_wchar_t nch;
699 struct bnum b;
701 nch = get(ctx);
702 if(nch == '-') {
703 found_sign = TRUE;
704 sign = -1;
705 nch = get(ctx);
706 } else if(nch == '+') {
707 found_sign = TRUE;
708 nch = get(ctx);
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]))
715 str_match = _nan;
716 while(str_match && nch != MSVCRT_WEOF &&
717 (nch == str_match[matched] || nch == MSVCRT__toupper(str_match[matched]))) {
718 nch = get(ctx);
719 matched++;
721 if(str_match) {
722 int keep = 0;
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--) {
727 unget(ctx);
729 if(keep) {
730 if (str_match == _infinity) return sign*INFINITY;
731 if (str_match == _nan) return sign*NAN;
732 } else if(found_sign) {
733 unget(ctx);
736 return 0.0;
739 if(nch == '0') {
740 found_digit = TRUE;
741 nch = get(ctx);
742 if(nch == 'x' || nch == 'X')
743 return strtod16(get, unget, ctx, sign, locinfo, err);
745 #endif
747 while(nch == '0') {
748 found_digit = TRUE;
749 nch = get(ctx);
752 b.data[0] = 0;
753 b.b = 0;
754 b.e = 1;
755 while(nch>='0' && nch<='9') {
756 found_digit = TRUE;
757 if(limb_digits == LIMB_DIGITS) {
758 if(BNUM_IDX(b.b-1) == BNUM_IDX(b.e)) break;
759 else {
760 b.b--;
761 b.data[BNUM_IDX(b.b)] = 0;
762 limb_digits = 0;
766 b.data[BNUM_IDX(b.b)] = b.data[BNUM_IDX(b.b)] * 10 + nch - '0';
767 limb_digits++;
768 nch = get(ctx);
769 dp++;
771 while(nch>='0' && nch<='9') {
772 if(nch != '0') b.data[BNUM_IDX(b.b)] |= 1;
773 nch = get(ctx);
774 dp++;
777 if(nch == *locinfo->lconv->decimal_point) {
778 found_dp = TRUE;
779 nch = get(ctx);
782 /* skip leading '0' */
783 if(nch=='0' && !limb_digits && !b.b) {
784 found_digit = TRUE;
785 while(nch == '0') {
786 nch = get(ctx);
787 dp--;
791 while(nch>='0' && nch<='9') {
792 found_digit = TRUE;
793 if(limb_digits == LIMB_DIGITS) {
794 if(BNUM_IDX(b.b-1) == BNUM_IDX(b.e)) break;
795 else {
796 b.b--;
797 b.data[BNUM_IDX(b.b)] = 0;
798 limb_digits = 0;
802 b.data[BNUM_IDX(b.b)] = b.data[BNUM_IDX(b.b)] * 10 + nch - '0';
803 limb_digits++;
804 nch = get(ctx);
806 while(nch>='0' && nch<='9') {
807 if(nch != '0') b.data[BNUM_IDX(b.b)] |= 1;
808 nch = get(ctx);
811 if(!found_digit) {
812 if(nch != MSVCRT_WEOF) unget(ctx);
813 if(found_dp) unget(ctx);
814 if(found_sign) unget(ctx);
815 return 0.0;
818 if(nch=='e' || nch=='E' || nch=='d' || nch=='D') {
819 int e=0, s=1;
821 nch = get(ctx);
822 if(nch == '-') {
823 found_sign = TRUE;
824 s = -1;
825 nch = get(ctx);
826 } else if(nch == '+') {
827 found_sign = TRUE;
828 nch = get(ctx);
829 } else {
830 found_sign = FALSE;
833 if(nch>='0' && nch<='9') {
834 while(nch>='0' && nch<='9') {
835 if(e>INT_MAX/10 || e*10>INT_MAX-nch+'0')
836 e = INT_MAX;
837 else
838 e = e*10+nch-'0';
839 nch = get(ctx);
841 if(nch != MSVCRT_WEOF) unget(ctx);
842 e *= s;
844 if(e<0 && dp<INT_MIN-e) dp = INT_MIN;
845 else if(e>0 && dp>INT_MAX-e) dp = INT_MAX;
846 else dp += e;
847 } else {
848 if(nch != MSVCRT_WEOF) unget(ctx);
849 if(found_sign) unget(ctx);
850 unget(ctx);
852 } else if(nch != MSVCRT_WEOF) {
853 unget(ctx);
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 */
859 if(b.b+1 != b.e) {
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;
884 e2 += 9;
886 while(dp <= LIMB_DIGITS) {
887 if(bnum_lshift(&b, 29)) dp += LIMB_DIGITS;
888 e2 -= 29;
890 while(b.data[BNUM_IDX(b.e-1)] < LIMB_MAX/10) {
891 bnum_lshift(&b, 1);
892 e2--;
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;
899 round = ROUND_DOWN;
900 break;
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;
910 return *(*p)++;
913 static void strtod_str_unget(void *ctx)
915 const char **p = ctx;
916 (*p)--;
919 static inline double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale, int *err)
921 MSVCRT_pthreadlocinfo locinfo;
922 const char *beg, *p;
923 double ret;
925 if (err) *err = 0;
926 if (!MSVCRT_CHECK_PMT(str != NULL)) {
927 if (end) *end = NULL;
928 return 0;
931 if (!locale)
932 locinfo = get_locinfo();
933 else
934 locinfo = locale->locinfo;
936 p = str;
937 while(MSVCRT__isspace_l((unsigned char)*p, locale))
938 p++;
939 beg = p;
941 ret = parse_double(strtod_str_get, strtod_str_unget, &p, locinfo, err);
942 if (end) *end = (p == beg ? (char*)str : (char*)p);
943 return ret;
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 /*********************************************************************
955 * strtod (MSVCRT.@)
957 double CDECL MSVCRT_strtod( const char *str, char **end )
959 return MSVCRT_strtod_l( str, end, NULL );
962 #if _MSVCR_VER>=120
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 /*********************************************************************
983 * atof (MSVCRT.@)
985 double CDECL MSVCRT_atof( const char *str )
987 return MSVCRT_strtod_l(str, NULL, NULL);
990 /*********************************************************************
991 * _atof_l (MSVCRT.@)
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)
1003 double d;
1004 int err;
1006 d = strtod_helper(str, NULL, locale, &err);
1007 value->f = d;
1008 if(isinf(value->f))
1009 return MSVCRT__OVERFLOW;
1010 if((d!=0 || err) && value->f>-MSVCRT_FLT_MIN && value->f<MSVCRT_FLT_MIN)
1011 return MSVCRT__UNDERFLOW;
1012 return 0;
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)
1028 int err;
1030 value->x = strtod_helper(str, NULL, locale, &err);
1031 if(isinf(value->x))
1032 return MSVCRT__OVERFLOW;
1033 if((value->x!=0 || err) && value->x>-MSVCRT_DBL_MIN && value->x<MSVCRT_DBL_MIN)
1034 return MSVCRT__UNDERFLOW;
1035 return 0;
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;
1053 if(!locale)
1054 locinfo = get_locinfo();
1055 else
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;
1078 if(!locale)
1079 locinfo = get_locinfo();
1080 else
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;
1104 if(!locale)
1105 locinfo = get_locinfo();
1106 else
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;
1131 if(!locale)
1132 locinfo = get_locinfo();
1133 else
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)
1156 MSVCRT_size_t i;
1158 for(i=0; i<len; i++)
1159 if((dst[i] = src[i]) == '\0') break;
1161 while (i < len) dst[i++] = 0;
1163 return dst;
1166 /*********************************************************************
1167 * strcpy (MSVCRT.@)
1169 char* CDECL MSVCRT_strcpy(char *dst, const char *src)
1171 char *ret = dst;
1172 while ((*dst++ = *src++));
1173 return ret;
1176 /*********************************************************************
1177 * strcpy_s (MSVCRT.@)
1179 int CDECL MSVCRT_strcpy_s( char* dst, MSVCRT_size_t elem, const char* src )
1181 MSVCRT_size_t i;
1182 if(!elem) return MSVCRT_EINVAL;
1183 if(!dst) return MSVCRT_EINVAL;
1184 if(!src)
1186 dst[0] = '\0';
1187 return MSVCRT_EINVAL;
1190 for(i = 0; i < elem; i++)
1192 if((dst[i] = src[i]) == '\0') return 0;
1194 dst[0] = '\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 )
1203 MSVCRT_size_t i, j;
1204 if(!dst) return MSVCRT_EINVAL;
1205 if(elem == 0) return MSVCRT_EINVAL;
1206 if(!src)
1208 dst[0] = '\0';
1209 return MSVCRT_EINVAL;
1212 for(i = 0; i < elem; i++)
1214 if(dst[i] == '\0')
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 */
1223 dst[0] = '\0';
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 )
1232 MSVCRT_size_t i, j;
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))
1238 dst[0] = '\0';
1239 return MSVCRT_EINVAL;
1242 for(i = 0; i < elem; i++)
1244 if(dst[i] == '\0')
1246 for(j = 0; (j + i) < elem; j++)
1248 if(count == MSVCRT__TRUNCATE && j + i == elem - 1)
1250 dst[j + i] = '\0';
1251 return MSVCRT_STRUNCATE;
1253 if(j == count || (dst[j + i] = src[j]) == '\0')
1255 dst[j + i] = '\0';
1256 return 0;
1261 /* Set the first element to 0, not the first element after the skipped part */
1262 dst[0] = '\0';
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;
1281 int ret;
1283 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
1284 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
1286 if(len > INT_MAX) {
1287 FIXME("len > INT_MAX not supported\n");
1288 len = INT_MAX;
1291 if(!locale)
1292 locinfo = get_locinfo();
1293 else
1294 locinfo = locale->locinfo;
1296 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE]) {
1297 MSVCRT_strncpy(dest, src, len);
1298 return strlen(src);
1301 ret = LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
1302 LCMAP_SORTKEY, src, -1, NULL, 0);
1303 if(!ret) {
1304 if(len) dest[0] = 0;
1305 *MSVCRT__errno() = MSVCRT_EILSEQ;
1306 return INT_MAX;
1308 if(!len) return ret-1;
1310 if(ret > len) {
1311 dest[0] = 0;
1312 *MSVCRT__errno() = MSVCRT_ERANGE;
1313 return ret-1;
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 */
1334 #ifdef HAVE_STRTOLD
1335 long double ld;
1336 TRACE("str %s value %p\n",str,value);
1337 ld = strtold(str,0);
1338 memcpy(value, &ld, 10);
1339 #else
1340 FIXME("stub, str %s value %p\n",str,value);
1341 #endif
1342 return 0;
1345 /********************************************************************
1346 * __STRINGTOLD (MSVCRT.@)
1348 int CDECL __STRINGTOLD( MSVCRT__LDOUBLE *value, char **endptr, const char *str, int flags )
1350 #ifdef HAVE_STRTOLD
1351 long double ld;
1352 FIXME("%p %p %s %x partial stub\n", value, endptr, str, flags );
1353 ld = strtold(str,0);
1354 memcpy(value, &ld, 10);
1355 #else
1356 FIXME("%p %p %s %x stub\n", value, endptr, str, flags );
1357 #endif
1358 return 0;
1361 /*********************************************************************
1362 * strlen (MSVCRT.@)
1364 MSVCRT_size_t __cdecl MSVCRT_strlen(const char *str)
1366 return strlen(str);
1369 /******************************************************************
1370 * strnlen (MSVCRT.@)
1372 MSVCRT_size_t CDECL MSVCRT_strnlen(const char *s, MSVCRT_size_t maxlen)
1374 MSVCRT_size_t i;
1376 for(i=0; i<maxlen; i++)
1377 if(!s[i]) break;
1379 return 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;
1392 __int64 ret = 0;
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++;
1402 if(*nptr == '-') {
1403 negative = TRUE;
1404 nptr++;
1405 } else if(*nptr == '+')
1406 nptr++;
1408 if((base==0 || base==16) && *nptr=='0' && MSVCRT__tolower_l(*(nptr+1), locale)=='x') {
1409 base = 16;
1410 nptr += 2;
1413 if(base == 0) {
1414 if(*nptr=='0')
1415 base = 8;
1416 else
1417 base = 10;
1420 while(*nptr) {
1421 char cur = MSVCRT__tolower_l(*nptr, locale);
1422 int v;
1424 if(cur>='0' && cur<='9') {
1425 if(cur >= '0'+base)
1426 break;
1427 v = cur-'0';
1428 } else {
1429 if(cur<'a' || cur>='a'+base-10)
1430 break;
1431 v = cur-'a'+10;
1433 got_digit = TRUE;
1435 if(negative)
1436 v = -v;
1438 nptr++;
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;
1446 } else
1447 ret = ret*base + v;
1450 if(endptr)
1451 *endptr = (char*)(got_digit ? nptr : p);
1453 return ret;
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);
1471 if(ret > INT_MAX) {
1472 ret = INT_MAX;
1473 *MSVCRT__errno() = MSVCRT_ERANGE;
1474 } else if(ret < INT_MIN) {
1475 ret = INT_MIN;
1476 *MSVCRT__errno() = MSVCRT_ERANGE;
1478 return ret;
1481 /*********************************************************************
1482 * atoi (MSVCRT.@)
1484 #if _MSVCR_VER == 0
1485 int __cdecl MSVCRT_atoi(const char *str)
1487 BOOL minus = FALSE;
1488 int ret = 0;
1490 if(!str)
1491 return 0;
1493 while(MSVCRT__isspace_l((unsigned char)*str, NULL)) str++;
1495 if(*str == '+') {
1496 str++;
1497 }else if(*str == '-') {
1498 minus = TRUE;
1499 str++;
1502 while(*str>='0' && *str<='9') {
1503 ret = ret*10+*str-'0';
1504 str++;
1507 return minus ? -ret : ret;
1509 #else
1510 int CDECL MSVCRT_atoi(const char *str)
1512 return MSVCRT__atoi_l(str, NULL);
1514 #endif
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;
1546 return ret;
1549 /******************************************************************
1550 * atol (MSVCRT.@)
1552 MSVCRT_long CDECL MSVCRT_atol(const char *str)
1554 #if _MSVCR_VER == 0
1555 return MSVCRT_atoi(str);
1556 #else
1557 return MSVCRT__atol_l(str, NULL);
1558 #endif
1561 #if _MSVCR_VER>=120
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;
1597 return ret;
1600 /******************************************************************
1601 * strtol (MSVCRT.@)
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) {
1619 ret = 1;
1620 *MSVCRT__errno() = MSVCRT_ERANGE;
1623 return ret;
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++;
1654 if(*nptr == '-') {
1655 negative = TRUE;
1656 nptr++;
1657 } else if(*nptr == '+')
1658 nptr++;
1660 if((base==0 || base==16) && *nptr=='0' && MSVCRT__tolower_l(*(nptr+1), locale)=='x') {
1661 base = 16;
1662 nptr += 2;
1665 if(base == 0) {
1666 if(*nptr=='0')
1667 base = 8;
1668 else
1669 base = 10;
1672 while(*nptr) {
1673 char cur = MSVCRT__tolower_l(*nptr, locale);
1674 int v;
1676 if(cur>='0' && cur<='9') {
1677 if(cur >= '0'+base)
1678 break;
1679 v = *nptr-'0';
1680 } else {
1681 if(cur<'a' || cur>='a'+base-10)
1682 break;
1683 v = cur-'a'+10;
1685 got_digit = TRUE;
1687 nptr++;
1689 if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1690 ret = MSVCRT_UI64_MAX;
1691 *MSVCRT__errno() = MSVCRT_ERANGE;
1692 } else
1693 ret = ret*base + v;
1696 if(endptr)
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)
1712 MSVCRT_ulong val;
1713 unsigned int digit;
1714 BOOL is_negative;
1715 char buffer[33], *pos;
1716 size_t len;
1718 if (value < 0 && radix == 10)
1720 is_negative = TRUE;
1721 val = -value;
1723 else
1725 is_negative = FALSE;
1726 val = value;
1729 pos = buffer + 32;
1730 *pos = '\0';
1734 digit = val % radix;
1735 val /= radix;
1737 if (digit < 10)
1738 *--pos = '0' + digit;
1739 else
1740 *--pos = 'a' + digit - 10;
1742 while (val != 0);
1744 if (is_negative)
1745 *--pos = '-';
1747 len = buffer + 33 - pos;
1748 if (len > size)
1750 size_t i;
1751 char *p = str;
1753 /* Copy the temporary buffer backwards up to the available number of
1754 * characters. Don't copy the negative sign if present. */
1756 if (is_negative)
1758 p++;
1759 size--;
1762 for (pos = buffer + 31, i = 0; i < size; i++)
1763 *p++ = *pos--;
1765 str[0] = '\0';
1766 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1767 return MSVCRT_ERANGE;
1770 memcpy(str, pos, len);
1771 return 0;
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))
1783 str[0] = '\0';
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)
1795 MSVCRT_ulong val;
1796 unsigned int digit;
1797 BOOL is_negative;
1798 MSVCRT_wchar_t buffer[33], *pos;
1799 size_t len;
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))
1805 str[0] = '\0';
1806 return MSVCRT_EINVAL;
1809 if (value < 0 && radix == 10)
1811 is_negative = TRUE;
1812 val = -value;
1814 else
1816 is_negative = FALSE;
1817 val = value;
1820 pos = buffer + 32;
1821 *pos = '\0';
1825 digit = val % radix;
1826 val /= radix;
1828 if (digit < 10)
1829 *--pos = '0' + digit;
1830 else
1831 *--pos = 'a' + digit - 10;
1833 while (val != 0);
1835 if (is_negative)
1836 *--pos = '-';
1838 len = buffer + 33 - pos;
1839 if (len > size)
1841 size_t i;
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. */
1847 if (is_negative)
1849 p++;
1850 size--;
1853 for (pos = buffer + 31, i = 0; i < size; i++)
1854 *p++ = *pos--;
1856 str[0] = '\0';
1857 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1858 return MSVCRT_ERANGE;
1861 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1862 return 0;
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 /*********************************************************************
1874 * _itoa (MSVCRT.@)
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;
1896 int digit;
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))
1902 str[0] = '\0';
1903 return MSVCRT_EINVAL;
1906 pos = buffer+64;
1907 *pos = '\0';
1909 do {
1910 digit = value%radix;
1911 value /= radix;
1913 if(digit < 10)
1914 *--pos = '0'+digit;
1915 else
1916 *--pos = 'a'+digit-10;
1917 }while(value != 0);
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);
1925 return 0;
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;
1935 int digit;
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))
1941 str[0] = '\0';
1942 return MSVCRT_EINVAL;
1945 pos = &buffer[64];
1946 *pos = '\0';
1948 do {
1949 digit = value % radix;
1950 value = value / radix;
1951 if (digit < 10)
1952 *--pos = '0' + digit;
1953 else
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));
1963 return 0;
1966 /*********************************************************************
1967 * _ultoa_s (MSVCRT.@)
1969 int CDECL MSVCRT__ultoa_s(MSVCRT_ulong value, char *str, MSVCRT_size_t size, int radix)
1971 MSVCRT_ulong digit;
1972 char buffer[33], *pos;
1973 size_t len;
1975 if (!str || !size || radix < 2 || radix > 36)
1977 if (str && size)
1978 str[0] = '\0';
1980 *MSVCRT__errno() = MSVCRT_EINVAL;
1981 return MSVCRT_EINVAL;
1984 pos = buffer + 32;
1985 *pos = '\0';
1989 digit = value % radix;
1990 value /= radix;
1992 if (digit < 10)
1993 *--pos = '0' + digit;
1994 else
1995 *--pos = 'a' + digit - 10;
1997 while (value != 0);
1999 len = buffer + 33 - pos;
2000 if (len > size)
2002 size_t i;
2003 char *p = str;
2005 /* Copy the temporary buffer backwards up to the available number of
2006 * characters. */
2008 for (pos = buffer + 31, i = 0; i < size; i++)
2009 *p++ = *pos--;
2011 str[0] = '\0';
2012 *MSVCRT__errno() = MSVCRT_ERANGE;
2013 return MSVCRT_ERANGE;
2016 memcpy(str, pos, len);
2017 return 0;
2020 /*********************************************************************
2021 * _ultow_s (MSVCRT.@)
2023 int CDECL MSVCRT__ultow_s(MSVCRT_ulong value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
2025 MSVCRT_ulong digit;
2026 WCHAR buffer[33], *pos;
2027 size_t len;
2029 if (!str || !size || radix < 2 || radix > 36)
2031 if (str && size)
2032 str[0] = '\0';
2034 *MSVCRT__errno() = MSVCRT_EINVAL;
2035 return MSVCRT_EINVAL;
2038 pos = buffer + 32;
2039 *pos = '\0';
2043 digit = value % radix;
2044 value /= radix;
2046 if (digit < 10)
2047 *--pos = '0' + digit;
2048 else
2049 *--pos = 'a' + digit - 10;
2051 while (value != 0);
2053 len = buffer + 33 - pos;
2054 if (len > size)
2056 size_t i;
2057 WCHAR *p = str;
2059 /* Copy the temporary buffer backwards up to the available number of
2060 * characters. */
2062 for (pos = buffer + 31, i = 0; i < size; i++)
2063 *p++ = *pos--;
2065 str[0] = '\0';
2066 *MSVCRT__errno() = MSVCRT_ERANGE;
2067 return MSVCRT_ERANGE;
2070 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
2071 return 0;
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;
2080 unsigned int digit;
2081 BOOL is_negative;
2082 char buffer[65], *pos;
2083 size_t len;
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))
2089 str[0] = '\0';
2090 return MSVCRT_EINVAL;
2093 if (value < 0 && radix == 10)
2095 is_negative = TRUE;
2096 val = -value;
2098 else
2100 is_negative = FALSE;
2101 val = value;
2104 pos = buffer + 64;
2105 *pos = '\0';
2109 digit = val % radix;
2110 val /= radix;
2112 if (digit < 10)
2113 *--pos = '0' + digit;
2114 else
2115 *--pos = 'a' + digit - 10;
2117 while (val != 0);
2119 if (is_negative)
2120 *--pos = '-';
2122 len = buffer + 65 - pos;
2123 if (len > size)
2125 size_t i;
2126 char *p = str;
2128 /* Copy the temporary buffer backwards up to the available number of
2129 * characters. Don't copy the negative sign if present. */
2131 if (is_negative)
2133 p++;
2134 size--;
2137 for (pos = buffer + 63, i = 0; i < size; i++)
2138 *p++ = *pos--;
2140 str[0] = '\0';
2141 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
2142 return MSVCRT_ERANGE;
2145 memcpy(str, pos, len);
2146 return 0;
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;
2155 unsigned int digit;
2156 BOOL is_negative;
2157 MSVCRT_wchar_t buffer[65], *pos;
2158 size_t len;
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))
2164 str[0] = '\0';
2165 return MSVCRT_EINVAL;
2168 if (value < 0 && radix == 10)
2170 is_negative = TRUE;
2171 val = -value;
2173 else
2175 is_negative = FALSE;
2176 val = value;
2179 pos = buffer + 64;
2180 *pos = '\0';
2184 digit = val % radix;
2185 val /= radix;
2187 if (digit < 10)
2188 *--pos = '0' + digit;
2189 else
2190 *--pos = 'a' + digit - 10;
2192 while (val != 0);
2194 if (is_negative)
2195 *--pos = '-';
2197 len = buffer + 65 - pos;
2198 if (len > size)
2200 size_t i;
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. */
2206 if (is_negative)
2208 p++;
2209 size--;
2212 for (pos = buffer + 63, i = 0; i < size; i++)
2213 *p++ = *pos--;
2215 str[0] = '\0';
2216 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
2217 return MSVCRT_ERANGE;
2220 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
2221 return 0;
2224 #define I10_OUTPUT_MAX_PREC 21
2225 /* Internal structure used by $I10_OUTPUT */
2226 struct _I10_OUTPUT_DATA {
2227 short pos;
2228 char sign;
2229 BYTE len;
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
2240 * return value
2241 * 0 if given double is NaN or INF
2242 * 1 otherwise
2244 * FIXME
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. */
2256 long double ld = 0;
2257 double d;
2258 char format[8];
2259 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
2260 char *p;
2262 memcpy(&ld, &ld80, 10);
2263 d = ld;
2264 TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
2266 if(d<0) {
2267 data->sign = '-';
2268 d = -d;
2269 } else
2270 data->sign = ' ';
2272 if(isinf(d)) {
2273 data->pos = 1;
2274 data->len = 5;
2275 memcpy(data->str, inf_str, sizeof(inf_str));
2277 return 0;
2280 if(isnan(d)) {
2281 data->pos = 1;
2282 data->len = 6;
2283 memcpy(data->str, nan_str, sizeof(nan_str));
2285 return 0;
2288 if(flag&1) {
2289 int exp = 1+floor(log10(d));
2291 prec += exp;
2292 if(exp < 0)
2293 prec--;
2295 prec--;
2297 if(prec+1 > I10_OUTPUT_MAX_PREC)
2298 prec = I10_OUTPUT_MAX_PREC-1;
2299 else if(prec < 0) {
2300 d = 0.0;
2301 prec = 0;
2304 sprintf(format, "%%.%dle", prec);
2305 sprintf(buf, format, d);
2307 buf[1] = buf[0];
2308 data->pos = atoi(buf+prec+3);
2309 if(buf[1] != '0')
2310 data->pos++;
2312 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
2313 data->len = p-buf;
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);
2321 return 1;
2323 #undef I10_OUTPUT_MAX_PREC
2325 /*********************************************************************
2326 * memcmp (MSVCRT.@)
2328 int __cdecl MSVCRT_memcmp(const void *ptr1, const void *ptr2, MSVCRT_size_t n)
2330 return memcmp(ptr1, ptr2, n);
2333 /*********************************************************************
2334 * memcpy (MSVCRT.@)
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 /*********************************************************************
2350 * memset (MSVCRT.@)
2352 void* __cdecl MSVCRT_memset(void *dst, int c, MSVCRT_size_t n)
2354 return memset(dst, c, n);
2357 /*********************************************************************
2358 * strchr (MSVCRT.@)
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 /*********************************************************************
2374 * memchr (MSVCRT.@)
2376 void* __cdecl MSVCRT_memchr(const void *ptr, int c, MSVCRT_size_t n)
2378 return memchr(ptr, c, n);
2381 /*********************************************************************
2382 * strcmp (MSVCRT.@)
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;
2389 return 0;
2392 /*********************************************************************
2393 * strncmp (MSVCRT.@)
2395 int __cdecl MSVCRT_strncmp(const char *str1, const char *str2, MSVCRT_size_t len)
2397 if (!len) return 0;
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;
2409 int c1, c2;
2411 if(s1==NULL || s2==NULL)
2412 return MSVCRT__NLSCMPERROR;
2414 if(!count)
2415 return 0;
2417 if(!locale)
2418 locinfo = get_locinfo();
2419 else
2420 locinfo = locale->locinfo;
2422 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
2424 do {
2425 if ((c1 = *s1++) >= 'A' && c1 <= 'Z')
2426 c1 -= 'A' - 'a';
2427 if ((c2 = *s2++) >= 'A' && c2 <= 'Z')
2428 c2 -= 'A' - 'a';
2429 }while(--count && c1 && c1==c2);
2431 return c1-c2;
2434 do {
2435 c1 = MSVCRT__tolower_l((unsigned char)*s1++, locale);
2436 c2 = MSVCRT__tolower_l((unsigned char)*s2++, locale);
2437 }while(--count && c1 && c1==c2);
2439 return 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 /*********************************************************************
2467 * strstr (MSVCRT.@)
2469 char* __cdecl MSVCRT_strstr(const char *haystack, const char *needle)
2471 MSVCRT_size_t i, j, len, needle_len, lps_len;
2472 BYTE lps[256];
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;
2478 lps[0] = 0;
2479 len = 0;
2480 i = 1;
2481 while (i < lps_len)
2483 if (needle[i] == needle[len]) lps[i++] = ++len;
2484 else if (len) len = lps[len-1];
2485 else lps[i++] = 0;
2488 i = j = 0;
2489 while (haystack[i])
2491 while (j < lps_len && haystack[i] && haystack[i] == needle[j])
2493 i++;
2494 j++;
2497 if (j == needle_len) return (char*)haystack + i - j;
2498 else if (j)
2500 if (j == ARRAY_SIZE(lps) && !MSVCRT_strncmp(haystack + i, needle + j, needle_len - j))
2501 return (char*)haystack + i - j;
2502 j = lps[j-1];
2504 else if (haystack[i]) i++;
2506 return NULL;
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)
2514 int ret = 0;
2516 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
2517 if (!s1 || !s2)
2519 if (len)
2520 MSVCRT_INVALID_PMT(NULL, EINVAL);
2521 return len ? MSVCRT__NLSCMPERROR : 0;
2523 #endif
2525 while (len--)
2527 if ((ret = MSVCRT__tolower_l(*s1, locale) - MSVCRT__tolower_l(*s2, locale)))
2528 break;
2529 s1++;
2530 s2++;
2532 return ret;
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)
2548 BOOL rejects[256];
2549 const char *p;
2551 memset(rejects, 0, sizeof(rejects));
2553 p = reject;
2554 while(*p)
2556 rejects[(unsigned char)*p] = TRUE;
2557 p++;
2560 p = str;
2561 while(*p && !rejects[(unsigned char)*p]) p++;
2562 return p - str;
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--)
2582 #else
2583 while (size-- && *str++)
2584 #endif
2586 ret++;
2589 return ret;
2593 #ifdef _CRTDLL
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;
2634 #endif