msvcrtd: Fix _CrtDbgReport calling convention.
[wine.git] / dlls / msvcrt / string.c
blobc8cd390688f08f86665e16284a8f977174b30343
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 <stdlib.h>
29 #include <stdio.h>
30 #include <math.h>
31 #include <limits.h>
32 #include <errno.h>
33 #include "msvcrt.h"
34 #include "winnls.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
39 /*********************************************************************
40 * _mbsdup (MSVCRT.@)
41 * _strdup (MSVCRT.@)
43 char* CDECL MSVCRT__strdup(const char* str)
45 if(str)
47 char * ret = MSVCRT_malloc(strlen(str)+1);
48 if (ret) strcpy( ret, str );
49 return ret;
51 else return 0;
54 /*********************************************************************
55 * _strlwr_s_l (MSVCRT.@)
57 int CDECL MSVCRT__strlwr_s_l(char *str, MSVCRT_size_t len, MSVCRT__locale_t locale)
59 char *ptr = str;
61 if (!str || !len)
63 *MSVCRT__errno() = MSVCRT_EINVAL;
64 return MSVCRT_EINVAL;
67 while (len && *ptr)
69 len--;
70 ptr++;
73 if (!len)
75 str[0] = '\0';
76 *MSVCRT__errno() = MSVCRT_EINVAL;
77 return MSVCRT_EINVAL;
80 while (*str)
82 *str = MSVCRT__tolower_l((unsigned char)*str, locale);
83 str++;
86 return 0;
89 /*********************************************************************
90 * _strlwr_s (MSVCRT.@)
92 int CDECL MSVCRT__strlwr_s(char *str, MSVCRT_size_t len)
94 return MSVCRT__strlwr_s_l(str, len, NULL);
97 /*********************************************************************
98 * _strlwr_l (MSVCRT.@)
100 char* CDECL _strlwr_l(char *str, MSVCRT__locale_t locale)
102 MSVCRT__strlwr_s_l(str, -1, locale);
103 return str;
106 /*********************************************************************
107 * _strlwr (MSVCRT.@)
109 char* CDECL MSVCRT__strlwr(char *str)
111 MSVCRT__strlwr_s_l(str, -1, NULL);
112 return str;
115 /*********************************************************************
116 * _strupr_s_l (MSVCRT.@)
118 int CDECL MSVCRT__strupr_s_l(char *str, MSVCRT_size_t len, MSVCRT__locale_t locale)
120 MSVCRT_pthreadlocinfo locinfo;
121 char *ptr = str;
123 if (!str || !len)
125 *MSVCRT__errno() = MSVCRT_EINVAL;
126 return MSVCRT_EINVAL;
129 while (len && *ptr)
131 len--;
132 ptr++;
135 if (!len)
137 str[0] = '\0';
138 *MSVCRT__errno() = MSVCRT_EINVAL;
139 return MSVCRT_EINVAL;
142 if(!locale)
143 locinfo = get_locinfo();
144 else
145 locinfo = locale->locinfo;
147 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
149 while (*str)
151 if (*str >= 'a' && *str <= 'z')
152 *str -= 'a' - 'A';
153 str++;
156 else
158 while (*str)
160 *str = MSVCRT__toupper_l((unsigned char)*str, locale);
161 str++;
165 return 0;
168 /*********************************************************************
169 * _strupr_s (MSVCRT.@)
171 int CDECL MSVCRT__strupr_s(char *str, MSVCRT_size_t len)
173 return MSVCRT__strupr_s_l(str, len, NULL);
176 /*********************************************************************
177 * _strupr_l (MSVCRT.@)
179 char* CDECL MSVCRT__strupr_l(char *str, MSVCRT__locale_t locale)
181 MSVCRT__strupr_s_l(str, -1, locale);
182 return str;
185 /*********************************************************************
186 * _strupr (MSVCRT.@)
188 char* CDECL MSVCRT__strupr(char *str)
190 MSVCRT__strupr_s_l(str, -1, NULL);
191 return str;
194 /*********************************************************************
195 * _strnset_s (MSVCRT.@)
197 int CDECL MSVCRT__strnset_s(char *str, MSVCRT_size_t size, int c, MSVCRT_size_t count)
199 MSVCRT_size_t i;
201 if(!str && !size && !count) return 0;
202 if(!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
203 if(!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
205 for(i=0; i<size-1 && i<count; i++) {
206 if(!str[i]) return 0;
207 str[i] = c;
209 for(; i<size; i++)
210 if(!str[i]) return 0;
212 str[0] = 0;
213 MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
214 *MSVCRT__errno() = MSVCRT_EINVAL;
215 return MSVCRT_EINVAL;
218 /*********************************************************************
219 * _strnset (MSVCRT.@)
221 char* CDECL MSVCRT__strnset(char* str, int value, MSVCRT_size_t len)
223 if (len > 0 && str)
224 while (*str && len--)
225 *str++ = value;
226 return str;
229 /*********************************************************************
230 * _strrev (MSVCRT.@)
232 char* CDECL MSVCRT__strrev(char* str)
234 char * p1;
235 char * p2;
237 if (str && *str)
238 for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
240 *p1 ^= *p2;
241 *p2 ^= *p1;
242 *p1 ^= *p2;
245 return str;
248 /*********************************************************************
249 * _strset (MSVCRT.@)
251 char* CDECL _strset(char* str, int value)
253 char *ptr = str;
254 while (*ptr)
255 *ptr++ = value;
257 return str;
260 /*********************************************************************
261 * strtok (MSVCRT.@)
263 char * CDECL MSVCRT_strtok( char *str, const char *delim )
265 thread_data_t *data = msvcrt_get_thread_data();
266 char *ret;
268 if (!str)
269 if (!(str = data->strtok_next)) return NULL;
271 while (*str && strchr( delim, *str )) str++;
272 if (!*str) return NULL;
273 ret = str++;
274 while (*str && !strchr( delim, *str )) str++;
275 if (*str) *str++ = 0;
276 data->strtok_next = str;
277 return ret;
280 /*********************************************************************
281 * strtok_s (MSVCRT.@)
283 char * CDECL MSVCRT_strtok_s(char *str, const char *delim, char **ctx)
285 if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL;
286 if (!MSVCRT_CHECK_PMT(ctx != NULL)) return NULL;
287 if (!MSVCRT_CHECK_PMT(str != NULL || *ctx != NULL)) return NULL;
289 if(!str)
290 str = *ctx;
292 while(*str && strchr(delim, *str))
293 str++;
294 if(!*str)
296 *ctx = str;
297 return NULL;
300 *ctx = str+1;
301 while(**ctx && !strchr(delim, **ctx))
302 (*ctx)++;
303 if(**ctx)
304 *(*ctx)++ = 0;
306 return str;
309 /*********************************************************************
310 * _swab (MSVCRT.@)
312 void CDECL MSVCRT__swab(char* src, char* dst, int len)
314 if (len > 1)
316 len = (unsigned)len >> 1;
318 while (len--) {
319 char s0 = src[0];
320 char s1 = src[1];
321 *dst++ = s1;
322 *dst++ = s0;
323 src = src + 2;
328 static double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale, int *err)
330 MSVCRT_pthreadlocinfo locinfo;
331 unsigned __int64 d=0, hlp;
332 unsigned fpcontrol;
333 int exp=0, sign=1;
334 const char *p;
335 double ret;
336 long double lret=1, expcnt = 10;
337 BOOL found_digit = FALSE, negexp;
338 int base = 10;
340 if(err)
341 *err = 0;
342 else if(!MSVCRT_CHECK_PMT(str != NULL)) {
343 if (end)
344 *end = NULL;
345 return 0;
348 if(!locale)
349 locinfo = get_locinfo();
350 else
351 locinfo = locale->locinfo;
353 /* FIXME: use *_l functions */
354 p = str;
355 while(isspace(*p))
356 p++;
358 if(*p == '-') {
359 sign = -1;
360 p++;
361 } else if(*p == '+')
362 p++;
364 #if _MSVCR_VER >= 140
365 if(tolower(p[0]) == 'i' && tolower(p[1]) == 'n' && tolower(p[2]) == 'f') {
366 if(end)
367 *end = (char*) &p[3];
368 if(tolower(p[3]) == 'i' && tolower(p[4]) == 'n' && tolower(p[5]) == 'i' &&
369 tolower(p[6]) == 't' && tolower(p[7]) == 'y' && end)
370 *end = (char*) &p[8];
371 return sign*INFINITY;
373 if(tolower(p[0]) == 'n' &&
374 tolower(p[1]) == 'a' &&
375 tolower(p[2]) == 'n') {
376 if(end)
377 *end = (char*) &p[3];
378 return NAN;
381 if(p[0] == '0' && tolower(p[1]) == 'x') {
382 base = 16;
383 expcnt = 2;
384 p += 2;
386 #endif
388 while((*p>='0' && *p<='9') ||
389 (base == 16 && ((*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))) {
390 char c = *p++;
391 int val;
392 found_digit = TRUE;
393 if (c>='0' && c<='9')
394 val = c - '0';
395 else if (c >= 'a' && c <= 'f')
396 val = 10 + c - 'a';
397 else
398 val = 10 + c - 'A';
399 hlp = d*base+val;
400 if(d>MSVCRT_UI64_MAX/base || hlp<d) {
401 exp++;
402 break;
403 } else
404 d = hlp;
406 while((*p>='0' && *p<='9') ||
407 (base == 16 && ((*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))) {
408 exp++;
409 p++;
412 if(*p == *locinfo->lconv->decimal_point)
413 p++;
415 while((*p>='0' && *p<='9') ||
416 (base == 16 && ((*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))) {
417 char c = *p++;
418 int val;
419 found_digit = TRUE;
420 if (c>='0' && c<='9')
421 val = c - '0';
422 else if (c >= 'a' && c <= 'f')
423 val = 10 + c - 'a';
424 else
425 val = 10 + c - 'A';
426 hlp = d*base+val;
427 if(d>MSVCRT_UI64_MAX/base || hlp<d)
428 break;
429 d = hlp;
430 exp--;
432 while((*p>='0' && *p<='9') ||
433 (base == 16 && ((*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))))
434 p++;
436 if(!found_digit) {
437 if(end)
438 *end = (char*)str;
439 return 0.0;
442 if(base == 16)
443 exp *= 4;
445 if((base == 10 && (*p=='e' || *p=='E' || *p=='d' || *p=='D')) ||
446 (base == 16 && (*p=='p' || *p=='P'))) {
447 int e=0, s=1;
449 p++;
450 if(*p == '-') {
451 s = -1;
452 p++;
453 } else if(*p == '+')
454 p++;
456 if(*p>='0' && *p<='9') {
457 while(*p>='0' && *p<='9') {
458 if(e>INT_MAX/10 || (e=e*10+*p-'0')<0)
459 e = INT_MAX;
460 p++;
462 e *= s;
464 if(exp<0 && e<0 && exp+e>=0) exp = INT_MIN;
465 else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
466 else exp += e;
467 } else {
468 if(*p=='-' || *p=='+')
469 p--;
470 p--;
474 fpcontrol = _control87(0, 0);
475 _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE
476 |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff);
478 negexp = (exp < 0);
479 if(negexp)
480 exp = -exp;
481 while(exp) {
482 if(exp & 1)
483 lret *= expcnt;
484 exp /= 2;
485 expcnt = expcnt*expcnt;
487 ret = (long double)sign * (negexp ? d/lret : d*lret);
489 _control87(fpcontrol, 0xffffffff);
491 if((d && ret==0.0) || isinf(ret)) {
492 if(err)
493 *err = MSVCRT_ERANGE;
494 else
495 *MSVCRT__errno() = MSVCRT_ERANGE;
498 if(end)
499 *end = (char*)p;
501 return ret;
504 /*********************************************************************
505 * strtod_l (MSVCRT.@)
507 double CDECL MSVCRT_strtod_l(const char *str, char **end, MSVCRT__locale_t locale)
509 return strtod_helper(str, end, locale, NULL);
512 /*********************************************************************
513 * strtod (MSVCRT.@)
515 double CDECL MSVCRT_strtod( const char *str, char **end )
517 return MSVCRT_strtod_l( str, end, NULL );
520 #if _MSVCR_VER>=120
522 /*********************************************************************
523 * strtof_l (MSVCR120.@)
525 float CDECL MSVCRT__strtof_l( const char *str, char **end, MSVCRT__locale_t locale )
527 return MSVCRT_strtod_l(str, end, locale);
530 /*********************************************************************
531 * strtof (MSVCR120.@)
533 float CDECL MSVCRT_strtof( const char *str, char **end )
535 return MSVCRT__strtof_l(str, end, NULL);
538 #endif /* _MSVCR_VER>=120 */
540 /*********************************************************************
541 * atof (MSVCRT.@)
543 double CDECL MSVCRT_atof( const char *str )
545 return MSVCRT_strtod_l(str, NULL, NULL);
548 /*********************************************************************
549 * _atof_l (MSVCRT.@)
551 double CDECL MSVCRT__atof_l( const char *str, MSVCRT__locale_t locale)
553 return MSVCRT_strtod_l(str, NULL, locale);
556 /*********************************************************************
557 * _atoflt_l (MSVCRT.@)
559 int CDECL MSVCRT__atoflt_l( MSVCRT__CRT_FLOAT *value, char *str, MSVCRT__locale_t locale)
561 double d;
562 int err;
564 d = strtod_helper(str, NULL, locale, &err);
565 value->f = d;
566 if(isinf(value->f))
567 return MSVCRT__OVERFLOW;
568 if((d!=0 || err) && value->f>-MSVCRT_FLT_MIN && value->f<MSVCRT_FLT_MIN)
569 return MSVCRT__UNDERFLOW;
570 return 0;
573 /*********************************************************************
574 * _atoflt (MSVCR100.@)
576 int CDECL MSVCRT__atoflt(MSVCRT__CRT_FLOAT *value, char *str)
578 return MSVCRT__atoflt_l(value, str, NULL);
581 /*********************************************************************
582 * _atodbl_l (MSVCRT.@)
584 int CDECL MSVCRT__atodbl_l(MSVCRT__CRT_DOUBLE *value, char *str, MSVCRT__locale_t locale)
586 int err;
588 value->x = strtod_helper(str, NULL, locale, &err);
589 if(isinf(value->x))
590 return MSVCRT__OVERFLOW;
591 if((value->x!=0 || err) && value->x>-MSVCRT_DBL_MIN && value->x<MSVCRT_DBL_MIN)
592 return MSVCRT__UNDERFLOW;
593 return 0;
596 /*********************************************************************
597 * _atodbl (MSVCRT.@)
599 int CDECL MSVCRT__atodbl(MSVCRT__CRT_DOUBLE *value, char *str)
601 return MSVCRT__atodbl_l(value, str, NULL);
604 /*********************************************************************
605 * _strcoll_l (MSVCRT.@)
607 int CDECL MSVCRT_strcoll_l( const char* str1, const char* str2, MSVCRT__locale_t locale )
609 MSVCRT_pthreadlocinfo locinfo;
611 if(!locale)
612 locinfo = get_locinfo();
613 else
614 locinfo = locale->locinfo;
616 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
617 return strcmp(str1, str2);
618 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], 0, str1, -1, str2, -1)-CSTR_EQUAL;
621 /*********************************************************************
622 * strcoll (MSVCRT.@)
624 int CDECL MSVCRT_strcoll( const char* str1, const char* str2 )
626 return MSVCRT_strcoll_l(str1, str2, NULL);
629 /*********************************************************************
630 * _stricoll_l (MSVCRT.@)
632 int CDECL MSVCRT__stricoll_l( const char* str1, const char* str2, MSVCRT__locale_t locale )
634 MSVCRT_pthreadlocinfo locinfo;
636 if(!locale)
637 locinfo = get_locinfo();
638 else
639 locinfo = locale->locinfo;
641 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
642 return strcasecmp(str1, str2);
643 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], NORM_IGNORECASE,
644 str1, -1, str2, -1)-CSTR_EQUAL;
647 /*********************************************************************
648 * _stricoll (MSVCRT.@)
650 int CDECL MSVCRT__stricoll( const char* str1, const char* str2 )
652 return MSVCRT__stricoll_l(str1, str2, NULL);
655 /*********************************************************************
656 * _strncoll_l (MSVCRT.@)
658 int CDECL MSVCRT__strncoll_l( const char* str1, const char* str2, MSVCRT_size_t count, MSVCRT__locale_t locale )
660 MSVCRT_pthreadlocinfo locinfo;
662 if(!locale)
663 locinfo = get_locinfo();
664 else
665 locinfo = locale->locinfo;
667 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
668 return strncmp(str1, str2, count);
669 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], 0, str1, count, str2, count)-CSTR_EQUAL;
672 /*********************************************************************
673 * _strncoll (MSVCRT.@)
675 int CDECL MSVCRT__strncoll( const char* str1, const char* str2, MSVCRT_size_t count )
677 return MSVCRT__strncoll_l(str1, str2, count, NULL);
680 /*********************************************************************
681 * _strnicoll_l (MSVCRT.@)
683 int CDECL MSVCRT__strnicoll_l( const char* str1, const char* str2, MSVCRT_size_t count, MSVCRT__locale_t locale )
685 MSVCRT_pthreadlocinfo locinfo;
687 if(!locale)
688 locinfo = get_locinfo();
689 else
690 locinfo = locale->locinfo;
692 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
693 return strncasecmp(str1, str2, count);
694 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], NORM_IGNORECASE,
695 str1, count, str2, count)-CSTR_EQUAL;
698 /*********************************************************************
699 * _strnicoll (MSVCRT.@)
701 int CDECL MSVCRT__strnicoll( const char* str1, const char* str2, MSVCRT_size_t count )
703 return MSVCRT__strnicoll_l(str1, str2, count, NULL);
706 /*********************************************************************
707 * strncpy (MSVCRT.@)
709 char* __cdecl MSVCRT_strncpy(char *dst, const char *src, MSVCRT_size_t len)
711 MSVCRT_size_t i;
713 for(i=0; i<len; i++)
714 if((dst[i] = src[i]) == '\0') break;
716 while (i < len) dst[i++] = 0;
718 return dst;
721 /*********************************************************************
722 * strcpy (MSVCRT.@)
724 char* CDECL MSVCRT_strcpy(char *dst, const char *src)
726 char *ret = dst;
727 while ((*dst++ = *src++));
728 return ret;
731 /*********************************************************************
732 * strcpy_s (MSVCRT.@)
734 int CDECL MSVCRT_strcpy_s( char* dst, MSVCRT_size_t elem, const char* src )
736 MSVCRT_size_t i;
737 if(!elem) return MSVCRT_EINVAL;
738 if(!dst) return MSVCRT_EINVAL;
739 if(!src)
741 dst[0] = '\0';
742 return MSVCRT_EINVAL;
745 for(i = 0; i < elem; i++)
747 if((dst[i] = src[i]) == '\0') return 0;
749 dst[0] = '\0';
750 return MSVCRT_ERANGE;
753 /*********************************************************************
754 * strcat_s (MSVCRT.@)
756 int CDECL MSVCRT_strcat_s( char* dst, MSVCRT_size_t elem, const char* src )
758 MSVCRT_size_t i, j;
759 if(!dst) return MSVCRT_EINVAL;
760 if(elem == 0) return MSVCRT_EINVAL;
761 if(!src)
763 dst[0] = '\0';
764 return MSVCRT_EINVAL;
767 for(i = 0; i < elem; i++)
769 if(dst[i] == '\0')
771 for(j = 0; (j + i) < elem; j++)
773 if((dst[j + i] = src[j]) == '\0') return 0;
777 /* Set the first element to 0, not the first element after the skipped part */
778 dst[0] = '\0';
779 return MSVCRT_ERANGE;
782 /*********************************************************************
783 * strncat_s (MSVCRT.@)
785 int CDECL MSVCRT_strncat_s( char* dst, MSVCRT_size_t elem, const char* src, MSVCRT_size_t count )
787 MSVCRT_size_t i, j;
789 if (!MSVCRT_CHECK_PMT(dst != 0)) return MSVCRT_EINVAL;
790 if (!MSVCRT_CHECK_PMT(elem != 0)) return MSVCRT_EINVAL;
791 if (!MSVCRT_CHECK_PMT(src != 0))
793 dst[0] = '\0';
794 return MSVCRT_EINVAL;
797 for(i = 0; i < elem; i++)
799 if(dst[i] == '\0')
801 for(j = 0; (j + i) < elem; j++)
803 if(count == MSVCRT__TRUNCATE && j + i == elem - 1)
805 dst[j + i] = '\0';
806 return MSVCRT_STRUNCATE;
808 if(j == count || (dst[j + i] = src[j]) == '\0')
810 dst[j + i] = '\0';
811 return 0;
816 /* Set the first element to 0, not the first element after the skipped part */
817 dst[0] = '\0';
818 return MSVCRT_ERANGE;
821 /*********************************************************************
822 * strncat (MSVCRT.@)
824 char* __cdecl MSVCRT_strncat(char *dst, const char *src, MSVCRT_size_t len)
826 return strncat(dst, src, len);
829 /*********************************************************************
830 * _strxfrm_l (MSVCRT.@)
832 MSVCRT_size_t CDECL MSVCRT__strxfrm_l( char *dest, const char *src,
833 MSVCRT_size_t len, MSVCRT__locale_t locale )
835 MSVCRT_pthreadlocinfo locinfo;
836 int ret;
838 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
839 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
841 if(len > INT_MAX) {
842 FIXME("len > INT_MAX not supported\n");
843 len = INT_MAX;
846 if(!locale)
847 locinfo = get_locinfo();
848 else
849 locinfo = locale->locinfo;
851 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE]) {
852 MSVCRT_strncpy(dest, src, len);
853 return strlen(src);
856 ret = LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
857 LCMAP_SORTKEY, src, -1, NULL, 0);
858 if(!ret) {
859 if(len) dest[0] = 0;
860 *MSVCRT__errno() = MSVCRT_EILSEQ;
861 return INT_MAX;
863 if(!len) return ret-1;
865 if(ret > len) {
866 dest[0] = 0;
867 *MSVCRT__errno() = MSVCRT_ERANGE;
868 return ret-1;
871 return LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
872 LCMAP_SORTKEY, src, -1, dest, len) - 1;
875 /*********************************************************************
876 * strxfrm (MSVCRT.@)
878 MSVCRT_size_t CDECL MSVCRT_strxfrm( char *dest, const char *src, MSVCRT_size_t len )
880 return MSVCRT__strxfrm_l(dest, src, len, NULL);
883 /********************************************************************
884 * _atoldbl (MSVCRT.@)
886 int CDECL MSVCRT__atoldbl(MSVCRT__LDOUBLE *value, const char *str)
888 /* FIXME needs error checking for huge/small values */
889 #ifdef HAVE_STRTOLD
890 long double ld;
891 TRACE("str %s value %p\n",str,value);
892 ld = strtold(str,0);
893 memcpy(value, &ld, 10);
894 #else
895 FIXME("stub, str %s value %p\n",str,value);
896 #endif
897 return 0;
900 /********************************************************************
901 * __STRINGTOLD (MSVCRT.@)
903 int CDECL __STRINGTOLD( MSVCRT__LDOUBLE *value, char **endptr, const char *str, int flags )
905 #ifdef HAVE_STRTOLD
906 long double ld;
907 FIXME("%p %p %s %x partial stub\n", value, endptr, str, flags );
908 ld = strtold(str,0);
909 memcpy(value, &ld, 10);
910 #else
911 FIXME("%p %p %s %x stub\n", value, endptr, str, flags );
912 #endif
913 return 0;
916 /*********************************************************************
917 * strlen (MSVCRT.@)
919 MSVCRT_size_t __cdecl MSVCRT_strlen(const char *str)
921 return strlen(str);
924 /******************************************************************
925 * strnlen (MSVCRT.@)
927 MSVCRT_size_t CDECL MSVCRT_strnlen(const char *s, MSVCRT_size_t maxlen)
929 MSVCRT_size_t i;
931 for(i=0; i<maxlen; i++)
932 if(!s[i]) break;
934 return i;
937 /*********************************************************************
938 * _strtoi64_l (MSVCRT.@)
940 * FIXME: locale parameter is ignored
942 __int64 CDECL MSVCRT_strtoi64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
944 const char *p = nptr;
945 BOOL negative = FALSE;
946 BOOL got_digit = FALSE;
947 __int64 ret = 0;
949 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
951 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
952 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
953 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
955 while(isspace(*nptr)) nptr++;
957 if(*nptr == '-') {
958 negative = TRUE;
959 nptr++;
960 } else if(*nptr == '+')
961 nptr++;
963 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
964 base = 16;
965 nptr += 2;
968 if(base == 0) {
969 if(*nptr=='0')
970 base = 8;
971 else
972 base = 10;
975 while(*nptr) {
976 char cur = tolower(*nptr);
977 int v;
979 if(cur>='0' && cur<='9') {
980 if(cur >= '0'+base)
981 break;
982 v = cur-'0';
983 } else {
984 if(cur<'a' || cur>='a'+base-10)
985 break;
986 v = cur-'a'+10;
988 got_digit = TRUE;
990 if(negative)
991 v = -v;
993 nptr++;
995 if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
996 ret = MSVCRT_I64_MAX;
997 *MSVCRT__errno() = MSVCRT_ERANGE;
998 } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
999 ret = MSVCRT_I64_MIN;
1000 *MSVCRT__errno() = MSVCRT_ERANGE;
1001 } else
1002 ret = ret*base + v;
1005 if(endptr)
1006 *endptr = (char*)(got_digit ? nptr : p);
1008 return ret;
1011 /*********************************************************************
1012 * _strtoi64 (MSVCRT.@)
1014 __int64 CDECL MSVCRT_strtoi64(const char *nptr, char **endptr, int base)
1016 return MSVCRT_strtoi64_l(nptr, endptr, base, NULL);
1019 /*********************************************************************
1020 * _atoi_l (MSVCRT.@)
1022 int __cdecl MSVCRT__atoi_l(const char *str, MSVCRT__locale_t locale)
1024 __int64 ret = MSVCRT_strtoi64_l(str, NULL, 10, locale);
1026 if(ret > INT_MAX) {
1027 ret = INT_MAX;
1028 *MSVCRT__errno() = MSVCRT_ERANGE;
1029 } else if(ret < INT_MIN) {
1030 ret = INT_MIN;
1031 *MSVCRT__errno() = MSVCRT_ERANGE;
1033 return ret;
1036 /*********************************************************************
1037 * atoi (MSVCRT.@)
1039 #if _MSVCR_VER == 0
1040 int __cdecl MSVCRT_atoi(const char *str)
1042 BOOL minus = FALSE;
1043 int ret = 0;
1045 if(!str)
1046 return 0;
1048 while(isspace(*str)) str++;
1050 if(*str == '+') {
1051 str++;
1052 }else if(*str == '-') {
1053 minus = TRUE;
1054 str++;
1057 while(*str>='0' && *str<='9') {
1058 ret = ret*10+*str-'0';
1059 str++;
1062 return minus ? -ret : ret;
1064 #else
1065 int CDECL MSVCRT_atoi(const char *str)
1067 return MSVCRT__atoi_l(str, NULL);
1069 #endif
1071 /******************************************************************
1072 * _atoi64_l (MSVCRT.@)
1074 __int64 CDECL MSVCRT__atoi64_l(const char *str, MSVCRT__locale_t locale)
1076 return MSVCRT_strtoi64_l(str, NULL, 10, locale);
1079 /******************************************************************
1080 * _atol_l (MSVCRT.@)
1082 MSVCRT_long CDECL MSVCRT__atol_l(const char *str, MSVCRT__locale_t locale)
1084 __int64 ret = MSVCRT_strtoi64_l(str, NULL, 10, locale);
1086 if(ret > LONG_MAX) {
1087 ret = LONG_MAX;
1088 *MSVCRT__errno() = MSVCRT_ERANGE;
1089 } else if(ret < LONG_MIN) {
1090 ret = LONG_MIN;
1091 *MSVCRT__errno() = MSVCRT_ERANGE;
1093 return ret;
1096 #if _MSVCR_VER>=120
1098 /******************************************************************
1099 * _atoll_l (MSVCR120.@)
1101 MSVCRT_longlong CDECL MSVCRT__atoll_l(const char* str, MSVCRT__locale_t locale)
1103 return MSVCRT_strtoi64_l(str, NULL, 10, locale);
1106 /******************************************************************
1107 * atoll (MSVCR120.@)
1109 MSVCRT_longlong CDECL MSVCRT_atoll(const char* str)
1111 return MSVCRT__atoll_l(str, NULL);
1114 #endif /* if _MSVCR_VER>=120 */
1116 /******************************************************************
1117 * _strtol_l (MSVCRT.@)
1119 MSVCRT_long CDECL MSVCRT__strtol_l(const char* nptr,
1120 char** end, int base, MSVCRT__locale_t locale)
1122 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1124 if(ret > MSVCRT_LONG_MAX) {
1125 ret = MSVCRT_LONG_MAX;
1126 *MSVCRT__errno() = MSVCRT_ERANGE;
1127 } else if(ret < MSVCRT_LONG_MIN) {
1128 ret = MSVCRT_LONG_MIN;
1129 *MSVCRT__errno() = MSVCRT_ERANGE;
1132 return ret;
1135 /******************************************************************
1136 * strtol (MSVCRT.@)
1138 MSVCRT_long CDECL MSVCRT_strtol(const char* nptr, char** end, int base)
1140 return MSVCRT__strtol_l(nptr, end, base, NULL);
1143 /******************************************************************
1144 * _strtoul_l (MSVCRT.@)
1146 MSVCRT_ulong CDECL MSVCRT_strtoul_l(const char* nptr, char** end, int base, MSVCRT__locale_t locale)
1148 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1150 if(ret > MSVCRT_ULONG_MAX) {
1151 ret = MSVCRT_ULONG_MAX;
1152 *MSVCRT__errno() = MSVCRT_ERANGE;
1153 }else if(ret < -(__int64)MSVCRT_ULONG_MAX) {
1154 ret = 1;
1155 *MSVCRT__errno() = MSVCRT_ERANGE;
1158 return ret;
1161 /******************************************************************
1162 * strtoul (MSVCRT.@)
1164 MSVCRT_ulong CDECL MSVCRT_strtoul(const char* nptr, char** end, int base)
1166 return MSVCRT_strtoul_l(nptr, end, base, NULL);
1169 /*********************************************************************
1170 * _strtoui64_l (MSVCRT.@)
1172 * FIXME: locale parameter is ignored
1174 unsigned __int64 CDECL MSVCRT_strtoui64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
1176 const char *p = nptr;
1177 BOOL negative = FALSE;
1178 BOOL got_digit = FALSE;
1179 unsigned __int64 ret = 0;
1181 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1183 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1184 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1185 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1187 while(isspace(*nptr)) nptr++;
1189 if(*nptr == '-') {
1190 negative = TRUE;
1191 nptr++;
1192 } else if(*nptr == '+')
1193 nptr++;
1195 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
1196 base = 16;
1197 nptr += 2;
1200 if(base == 0) {
1201 if(*nptr=='0')
1202 base = 8;
1203 else
1204 base = 10;
1207 while(*nptr) {
1208 char cur = tolower(*nptr);
1209 int v;
1211 if(cur>='0' && cur<='9') {
1212 if(cur >= '0'+base)
1213 break;
1214 v = *nptr-'0';
1215 } else {
1216 if(cur<'a' || cur>='a'+base-10)
1217 break;
1218 v = cur-'a'+10;
1220 got_digit = TRUE;
1222 nptr++;
1224 if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1225 ret = MSVCRT_UI64_MAX;
1226 *MSVCRT__errno() = MSVCRT_ERANGE;
1227 } else
1228 ret = ret*base + v;
1231 if(endptr)
1232 *endptr = (char*)(got_digit ? nptr : p);
1234 return negative ? -ret : ret;
1237 /*********************************************************************
1238 * _strtoui64 (MSVCRT.@)
1240 unsigned __int64 CDECL MSVCRT_strtoui64(const char *nptr, char **endptr, int base)
1242 return MSVCRT_strtoui64_l(nptr, endptr, base, NULL);
1245 static int ltoa_helper(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1247 MSVCRT_ulong val;
1248 unsigned int digit;
1249 BOOL is_negative;
1250 char buffer[33], *pos;
1251 size_t len;
1253 if (value < 0 && radix == 10)
1255 is_negative = TRUE;
1256 val = -value;
1258 else
1260 is_negative = FALSE;
1261 val = value;
1264 pos = buffer + 32;
1265 *pos = '\0';
1269 digit = val % radix;
1270 val /= radix;
1272 if (digit < 10)
1273 *--pos = '0' + digit;
1274 else
1275 *--pos = 'a' + digit - 10;
1277 while (val != 0);
1279 if (is_negative)
1280 *--pos = '-';
1282 len = buffer + 33 - pos;
1283 if (len > size)
1285 size_t i;
1286 char *p = str;
1288 /* Copy the temporary buffer backwards up to the available number of
1289 * characters. Don't copy the negative sign if present. */
1291 if (is_negative)
1293 p++;
1294 size--;
1297 for (pos = buffer + 31, i = 0; i < size; i++)
1298 *p++ = *pos--;
1300 str[0] = '\0';
1301 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1302 return MSVCRT_ERANGE;
1305 memcpy(str, pos, len);
1306 return 0;
1309 /*********************************************************************
1310 * _ltoa_s (MSVCRT.@)
1312 int CDECL MSVCRT__ltoa_s(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1314 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1315 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1316 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1318 str[0] = '\0';
1319 return MSVCRT_EINVAL;
1322 return ltoa_helper(value, str, size, radix);
1325 /*********************************************************************
1326 * _ltow_s (MSVCRT.@)
1328 int CDECL MSVCRT__ltow_s(MSVCRT_long value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1330 MSVCRT_ulong val;
1331 unsigned int digit;
1332 BOOL is_negative;
1333 MSVCRT_wchar_t buffer[33], *pos;
1334 size_t len;
1336 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1337 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1338 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1340 str[0] = '\0';
1341 return MSVCRT_EINVAL;
1344 if (value < 0 && radix == 10)
1346 is_negative = TRUE;
1347 val = -value;
1349 else
1351 is_negative = FALSE;
1352 val = value;
1355 pos = buffer + 32;
1356 *pos = '\0';
1360 digit = val % radix;
1361 val /= radix;
1363 if (digit < 10)
1364 *--pos = '0' + digit;
1365 else
1366 *--pos = 'a' + digit - 10;
1368 while (val != 0);
1370 if (is_negative)
1371 *--pos = '-';
1373 len = buffer + 33 - pos;
1374 if (len > size)
1376 size_t i;
1377 MSVCRT_wchar_t *p = str;
1379 /* Copy the temporary buffer backwards up to the available number of
1380 * characters. Don't copy the negative sign if present. */
1382 if (is_negative)
1384 p++;
1385 size--;
1388 for (pos = buffer + 31, i = 0; i < size; i++)
1389 *p++ = *pos--;
1391 str[0] = '\0';
1392 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1393 return MSVCRT_ERANGE;
1396 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1397 return 0;
1400 /*********************************************************************
1401 * _itoa_s (MSVCRT.@)
1403 int CDECL MSVCRT__itoa_s(int value, char *str, MSVCRT_size_t size, int radix)
1405 return MSVCRT__ltoa_s(value, str, size, radix);
1408 /*********************************************************************
1409 * _itoa (MSVCRT.@)
1411 char* CDECL MSVCRT__itoa(int value, char *str, int radix)
1413 return ltoa_helper(value, str, MSVCRT_SIZE_MAX, radix) ? NULL : str;
1416 /*********************************************************************
1417 * _itow_s (MSVCRT.@)
1419 int CDECL MSVCRT__itow_s(int value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1421 return MSVCRT__ltow_s(value, str, size, radix);
1424 /*********************************************************************
1425 * _ui64toa_s (MSVCRT.@)
1427 int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str,
1428 MSVCRT_size_t size, int radix)
1430 char buffer[65], *pos;
1431 int digit;
1433 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1434 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1435 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1437 str[0] = '\0';
1438 return MSVCRT_EINVAL;
1441 pos = buffer+64;
1442 *pos = '\0';
1444 do {
1445 digit = value%radix;
1446 value /= radix;
1448 if(digit < 10)
1449 *--pos = '0'+digit;
1450 else
1451 *--pos = 'a'+digit-10;
1452 }while(value != 0);
1454 if(buffer-pos+65 > size) {
1455 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1456 return MSVCRT_EINVAL;
1459 memcpy(str, pos, buffer-pos+65);
1460 return 0;
1463 /*********************************************************************
1464 * _ui64tow_s (MSVCRT.@)
1466 int CDECL MSVCRT__ui64tow_s( unsigned __int64 value, MSVCRT_wchar_t *str,
1467 MSVCRT_size_t size, int radix )
1469 MSVCRT_wchar_t buffer[65], *pos;
1470 int digit;
1472 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1473 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1474 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1476 str[0] = '\0';
1477 return MSVCRT_EINVAL;
1480 pos = &buffer[64];
1481 *pos = '\0';
1483 do {
1484 digit = value % radix;
1485 value = value / radix;
1486 if (digit < 10)
1487 *--pos = '0' + digit;
1488 else
1489 *--pos = 'a' + digit - 10;
1490 } while (value != 0);
1492 if(buffer-pos+65 > size) {
1493 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1494 return MSVCRT_EINVAL;
1497 memcpy(str, pos, (buffer-pos+65)*sizeof(MSVCRT_wchar_t));
1498 return 0;
1501 /*********************************************************************
1502 * _ultoa_s (MSVCRT.@)
1504 int CDECL MSVCRT__ultoa_s(MSVCRT_ulong value, char *str, MSVCRT_size_t size, int radix)
1506 MSVCRT_ulong digit;
1507 char buffer[33], *pos;
1508 size_t len;
1510 if (!str || !size || radix < 2 || radix > 36)
1512 if (str && size)
1513 str[0] = '\0';
1515 *MSVCRT__errno() = MSVCRT_EINVAL;
1516 return MSVCRT_EINVAL;
1519 pos = buffer + 32;
1520 *pos = '\0';
1524 digit = value % radix;
1525 value /= radix;
1527 if (digit < 10)
1528 *--pos = '0' + digit;
1529 else
1530 *--pos = 'a' + digit - 10;
1532 while (value != 0);
1534 len = buffer + 33 - pos;
1535 if (len > size)
1537 size_t i;
1538 char *p = str;
1540 /* Copy the temporary buffer backwards up to the available number of
1541 * characters. */
1543 for (pos = buffer + 31, i = 0; i < size; i++)
1544 *p++ = *pos--;
1546 str[0] = '\0';
1547 *MSVCRT__errno() = MSVCRT_ERANGE;
1548 return MSVCRT_ERANGE;
1551 memcpy(str, pos, len);
1552 return 0;
1555 /*********************************************************************
1556 * _ultow_s (MSVCRT.@)
1558 int CDECL MSVCRT__ultow_s(MSVCRT_ulong value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1560 MSVCRT_ulong digit;
1561 WCHAR buffer[33], *pos;
1562 size_t len;
1564 if (!str || !size || radix < 2 || radix > 36)
1566 if (str && size)
1567 str[0] = '\0';
1569 *MSVCRT__errno() = MSVCRT_EINVAL;
1570 return MSVCRT_EINVAL;
1573 pos = buffer + 32;
1574 *pos = '\0';
1578 digit = value % radix;
1579 value /= radix;
1581 if (digit < 10)
1582 *--pos = '0' + digit;
1583 else
1584 *--pos = 'a' + digit - 10;
1586 while (value != 0);
1588 len = buffer + 33 - pos;
1589 if (len > size)
1591 size_t i;
1592 WCHAR *p = str;
1594 /* Copy the temporary buffer backwards up to the available number of
1595 * characters. */
1597 for (pos = buffer + 31, i = 0; i < size; i++)
1598 *p++ = *pos--;
1600 str[0] = '\0';
1601 *MSVCRT__errno() = MSVCRT_ERANGE;
1602 return MSVCRT_ERANGE;
1605 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1606 return 0;
1609 /*********************************************************************
1610 * _i64toa_s (MSVCRT.@)
1612 int CDECL MSVCRT__i64toa_s(__int64 value, char *str, MSVCRT_size_t size, int radix)
1614 unsigned __int64 val;
1615 unsigned int digit;
1616 BOOL is_negative;
1617 char buffer[65], *pos;
1618 size_t len;
1620 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1621 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1622 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1624 str[0] = '\0';
1625 return MSVCRT_EINVAL;
1628 if (value < 0 && radix == 10)
1630 is_negative = TRUE;
1631 val = -value;
1633 else
1635 is_negative = FALSE;
1636 val = value;
1639 pos = buffer + 64;
1640 *pos = '\0';
1644 digit = val % radix;
1645 val /= radix;
1647 if (digit < 10)
1648 *--pos = '0' + digit;
1649 else
1650 *--pos = 'a' + digit - 10;
1652 while (val != 0);
1654 if (is_negative)
1655 *--pos = '-';
1657 len = buffer + 65 - pos;
1658 if (len > size)
1660 size_t i;
1661 char *p = str;
1663 /* Copy the temporary buffer backwards up to the available number of
1664 * characters. Don't copy the negative sign if present. */
1666 if (is_negative)
1668 p++;
1669 size--;
1672 for (pos = buffer + 63, i = 0; i < size; i++)
1673 *p++ = *pos--;
1675 str[0] = '\0';
1676 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1677 return MSVCRT_ERANGE;
1680 memcpy(str, pos, len);
1681 return 0;
1684 /*********************************************************************
1685 * _i64tow_s (MSVCRT.@)
1687 int CDECL MSVCRT__i64tow_s(__int64 value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1689 unsigned __int64 val;
1690 unsigned int digit;
1691 BOOL is_negative;
1692 MSVCRT_wchar_t buffer[65], *pos;
1693 size_t len;
1695 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1696 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1697 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1699 str[0] = '\0';
1700 return MSVCRT_EINVAL;
1703 if (value < 0 && radix == 10)
1705 is_negative = TRUE;
1706 val = -value;
1708 else
1710 is_negative = FALSE;
1711 val = value;
1714 pos = buffer + 64;
1715 *pos = '\0';
1719 digit = val % radix;
1720 val /= radix;
1722 if (digit < 10)
1723 *--pos = '0' + digit;
1724 else
1725 *--pos = 'a' + digit - 10;
1727 while (val != 0);
1729 if (is_negative)
1730 *--pos = '-';
1732 len = buffer + 65 - pos;
1733 if (len > size)
1735 size_t i;
1736 MSVCRT_wchar_t *p = str;
1738 /* Copy the temporary buffer backwards up to the available number of
1739 * characters. Don't copy the negative sign if present. */
1741 if (is_negative)
1743 p++;
1744 size--;
1747 for (pos = buffer + 63, i = 0; i < size; i++)
1748 *p++ = *pos--;
1750 str[0] = '\0';
1751 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1752 return MSVCRT_ERANGE;
1755 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1756 return 0;
1759 #define I10_OUTPUT_MAX_PREC 21
1760 /* Internal structure used by $I10_OUTPUT */
1761 struct _I10_OUTPUT_DATA {
1762 short pos;
1763 char sign;
1764 BYTE len;
1765 char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */
1768 /*********************************************************************
1769 * $I10_OUTPUT (MSVCRT.@)
1770 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
1771 * prec - precision of part, we're interested in
1772 * flag - 0 for first prec digits, 1 for fractional part
1773 * data - data to be populated
1775 * return value
1776 * 0 if given double is NaN or INF
1777 * 1 otherwise
1779 * FIXME
1780 * Native sets last byte of data->str to '0' or '9', I don't know what
1781 * it means. Current implementation sets it always to '0'.
1783 int CDECL MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data)
1785 static const char inf_str[] = "1#INF";
1786 static const char nan_str[] = "1#QNAN";
1788 /* MS' long double type wants 12 bytes for Intel's 80 bit FP format.
1789 * Some UNIX have sizeof(long double) == 16, yet only 80 bit are used.
1790 * Assume long double uses 80 bit FP, never seen 128 bit FP. */
1791 long double ld = 0;
1792 double d;
1793 char format[8];
1794 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
1795 char *p;
1797 memcpy(&ld, &ld80, 10);
1798 d = ld;
1799 TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
1801 if(d<0) {
1802 data->sign = '-';
1803 d = -d;
1804 } else
1805 data->sign = ' ';
1807 if(isinf(d)) {
1808 data->pos = 1;
1809 data->len = 5;
1810 memcpy(data->str, inf_str, sizeof(inf_str));
1812 return 0;
1815 if(isnan(d)) {
1816 data->pos = 1;
1817 data->len = 6;
1818 memcpy(data->str, nan_str, sizeof(nan_str));
1820 return 0;
1823 if(flag&1) {
1824 int exp = 1+floor(log10(d));
1826 prec += exp;
1827 if(exp < 0)
1828 prec--;
1830 prec--;
1832 if(prec+1 > I10_OUTPUT_MAX_PREC)
1833 prec = I10_OUTPUT_MAX_PREC-1;
1834 else if(prec < 0) {
1835 d = 0.0;
1836 prec = 0;
1839 sprintf(format, "%%.%dle", prec);
1840 sprintf(buf, format, d);
1842 buf[1] = buf[0];
1843 data->pos = atoi(buf+prec+3);
1844 if(buf[1] != '0')
1845 data->pos++;
1847 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
1848 data->len = p-buf;
1850 memcpy(data->str, buf+1, data->len);
1851 data->str[data->len] = '\0';
1853 if(buf[1]!='0' && prec-data->len+1>0)
1854 memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1);
1856 return 1;
1858 #undef I10_OUTPUT_MAX_PREC
1860 /*********************************************************************
1861 * memcmp (MSVCRT.@)
1863 int __cdecl MSVCRT_memcmp(const void *ptr1, const void *ptr2, MSVCRT_size_t n)
1865 return memcmp(ptr1, ptr2, n);
1868 /*********************************************************************
1869 * memcpy (MSVCRT.@)
1871 void * __cdecl MSVCRT_memcpy(void *dst, const void *src, MSVCRT_size_t n)
1873 return memmove(dst, src, n);
1876 /*********************************************************************
1877 * memmove (MSVCRT.@)
1879 void * __cdecl MSVCRT_memmove(void *dst, const void *src, MSVCRT_size_t n)
1881 return memmove(dst, src, n);
1884 /*********************************************************************
1885 * memset (MSVCRT.@)
1887 void* __cdecl MSVCRT_memset(void *dst, int c, MSVCRT_size_t n)
1889 return memset(dst, c, n);
1892 /*********************************************************************
1893 * strchr (MSVCRT.@)
1895 char* __cdecl MSVCRT_strchr(const char *str, int c)
1897 return strchr(str, c);
1900 /*********************************************************************
1901 * strrchr (MSVCRT.@)
1903 char* __cdecl MSVCRT_strrchr(const char *str, int c)
1905 return strrchr(str, c);
1908 /*********************************************************************
1909 * memchr (MSVCRT.@)
1911 void* __cdecl MSVCRT_memchr(const void *ptr, int c, MSVCRT_size_t n)
1913 return memchr(ptr, c, n);
1916 /*********************************************************************
1917 * strcmp (MSVCRT.@)
1919 int __cdecl MSVCRT_strcmp(const char *str1, const char *str2)
1921 return strcmp(str1, str2);
1924 /*********************************************************************
1925 * strncmp (MSVCRT.@)
1927 int __cdecl MSVCRT_strncmp(const char *str1, const char *str2, MSVCRT_size_t len)
1929 return strncmp(str1, str2, len);
1932 /*********************************************************************
1933 * _strnicmp_l (MSVCRT.@)
1935 int __cdecl MSVCRT__strnicmp_l(const char *s1, const char *s2,
1936 MSVCRT_size_t count, MSVCRT__locale_t locale)
1938 MSVCRT_pthreadlocinfo locinfo;
1939 int c1, c2;
1941 if(s1==NULL || s2==NULL)
1942 return MSVCRT__NLSCMPERROR;
1944 if(!count)
1945 return 0;
1947 if(!locale)
1948 locinfo = get_locinfo();
1949 else
1950 locinfo = locale->locinfo;
1952 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
1953 return strncasecmp(s1, s2, count);
1955 do {
1956 c1 = MSVCRT__tolower_l(*s1++, locale);
1957 c2 = MSVCRT__tolower_l(*s2++, locale);
1958 }while(--count && c1 && c1==c2);
1960 return c1-c2;
1963 /*********************************************************************
1964 * _stricmp_l (MSVCRT.@)
1966 int __cdecl MSVCRT__stricmp_l(const char *s1, const char *s2, MSVCRT__locale_t locale)
1968 return MSVCRT__strnicmp_l(s1, s2, -1, locale);
1971 /*********************************************************************
1972 * _strnicmp (MSVCRT.@)
1974 int __cdecl MSVCRT__strnicmp(const char *s1, const char *s2, MSVCRT_size_t count)
1976 return MSVCRT__strnicmp_l(s1, s2, count, NULL);
1979 /*********************************************************************
1980 * _stricmp (MSVCRT.@)
1982 int __cdecl MSVCRT__stricmp(const char *s1, const char *s2)
1984 return MSVCRT__strnicmp_l(s1, s2, -1, NULL);
1987 /*********************************************************************
1988 * strstr (MSVCRT.@)
1990 char* __cdecl MSVCRT_strstr(const char *haystack, const char *needle)
1992 return strstr(haystack, needle);
1995 /*********************************************************************
1996 * _memicmp_l (MSVCRT.@)
1998 int __cdecl MSVCRT__memicmp_l(const char *s1, const char *s2, MSVCRT_size_t len, MSVCRT__locale_t locale)
2000 int ret = 0;
2002 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
2003 if (!s1 || !s2)
2005 if (len)
2006 MSVCRT_INVALID_PMT(NULL, EINVAL);
2007 return len ? MSVCRT__NLSCMPERROR : 0;
2009 #endif
2011 while (len--)
2013 if ((ret = MSVCRT__tolower_l(*s1, locale) - MSVCRT__tolower_l(*s2, locale)))
2014 break;
2015 s1++;
2016 s2++;
2018 return ret;
2021 /*********************************************************************
2022 * _memicmp (MSVCRT.@)
2024 int __cdecl MSVCRT__memicmp(const char *s1, const char *s2, MSVCRT_size_t len)
2026 return MSVCRT__memicmp_l(s1, s2, len, NULL);