kernel32/tests: Add a test to check some fields in fake dlls.
[wine.git] / dlls / msvcrt / string.c
blobfc827d809365384403c6e15bfbc254476666cca0
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,
670 str1, MSVCRT_strnlen(str1, count),
671 str2, MSVCRT_strnlen(str2, count))-CSTR_EQUAL;
674 /*********************************************************************
675 * _strncoll (MSVCRT.@)
677 int CDECL MSVCRT__strncoll( const char* str1, const char* str2, MSVCRT_size_t count )
679 return MSVCRT__strncoll_l(str1, str2, count, NULL);
682 /*********************************************************************
683 * _strnicoll_l (MSVCRT.@)
685 int CDECL MSVCRT__strnicoll_l( const char* str1, const char* str2, MSVCRT_size_t count, MSVCRT__locale_t locale )
687 MSVCRT_pthreadlocinfo locinfo;
689 if(!locale)
690 locinfo = get_locinfo();
691 else
692 locinfo = locale->locinfo;
694 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
695 return strncasecmp(str1, str2, count);
696 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], NORM_IGNORECASE,
697 str1, MSVCRT_strnlen(str1, count),
698 str2, MSVCRT_strnlen(str2, count))-CSTR_EQUAL;
701 /*********************************************************************
702 * _strnicoll (MSVCRT.@)
704 int CDECL MSVCRT__strnicoll( const char* str1, const char* str2, MSVCRT_size_t count )
706 return MSVCRT__strnicoll_l(str1, str2, count, NULL);
709 /*********************************************************************
710 * strncpy (MSVCRT.@)
712 char* __cdecl MSVCRT_strncpy(char *dst, const char *src, MSVCRT_size_t len)
714 MSVCRT_size_t i;
716 for(i=0; i<len; i++)
717 if((dst[i] = src[i]) == '\0') break;
719 while (i < len) dst[i++] = 0;
721 return dst;
724 /*********************************************************************
725 * strcpy (MSVCRT.@)
727 char* CDECL MSVCRT_strcpy(char *dst, const char *src)
729 char *ret = dst;
730 while ((*dst++ = *src++));
731 return ret;
734 /*********************************************************************
735 * strcpy_s (MSVCRT.@)
737 int CDECL MSVCRT_strcpy_s( char* dst, MSVCRT_size_t elem, const char* src )
739 MSVCRT_size_t i;
740 if(!elem) return MSVCRT_EINVAL;
741 if(!dst) return MSVCRT_EINVAL;
742 if(!src)
744 dst[0] = '\0';
745 return MSVCRT_EINVAL;
748 for(i = 0; i < elem; i++)
750 if((dst[i] = src[i]) == '\0') return 0;
752 dst[0] = '\0';
753 return MSVCRT_ERANGE;
756 /*********************************************************************
757 * strcat_s (MSVCRT.@)
759 int CDECL MSVCRT_strcat_s( char* dst, MSVCRT_size_t elem, const char* src )
761 MSVCRT_size_t i, j;
762 if(!dst) return MSVCRT_EINVAL;
763 if(elem == 0) return MSVCRT_EINVAL;
764 if(!src)
766 dst[0] = '\0';
767 return MSVCRT_EINVAL;
770 for(i = 0; i < elem; i++)
772 if(dst[i] == '\0')
774 for(j = 0; (j + i) < elem; j++)
776 if((dst[j + i] = src[j]) == '\0') return 0;
780 /* Set the first element to 0, not the first element after the skipped part */
781 dst[0] = '\0';
782 return MSVCRT_ERANGE;
785 /*********************************************************************
786 * strncat_s (MSVCRT.@)
788 int CDECL MSVCRT_strncat_s( char* dst, MSVCRT_size_t elem, const char* src, MSVCRT_size_t count )
790 MSVCRT_size_t i, j;
792 if (!MSVCRT_CHECK_PMT(dst != 0)) return MSVCRT_EINVAL;
793 if (!MSVCRT_CHECK_PMT(elem != 0)) return MSVCRT_EINVAL;
794 if (!MSVCRT_CHECK_PMT(src != 0))
796 dst[0] = '\0';
797 return MSVCRT_EINVAL;
800 for(i = 0; i < elem; i++)
802 if(dst[i] == '\0')
804 for(j = 0; (j + i) < elem; j++)
806 if(count == MSVCRT__TRUNCATE && j + i == elem - 1)
808 dst[j + i] = '\0';
809 return MSVCRT_STRUNCATE;
811 if(j == count || (dst[j + i] = src[j]) == '\0')
813 dst[j + i] = '\0';
814 return 0;
819 /* Set the first element to 0, not the first element after the skipped part */
820 dst[0] = '\0';
821 return MSVCRT_ERANGE;
824 /*********************************************************************
825 * strncat (MSVCRT.@)
827 char* __cdecl MSVCRT_strncat(char *dst, const char *src, MSVCRT_size_t len)
829 return strncat(dst, src, len);
832 /*********************************************************************
833 * _strxfrm_l (MSVCRT.@)
835 MSVCRT_size_t CDECL MSVCRT__strxfrm_l( char *dest, const char *src,
836 MSVCRT_size_t len, MSVCRT__locale_t locale )
838 MSVCRT_pthreadlocinfo locinfo;
839 int ret;
841 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
842 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
844 if(len > INT_MAX) {
845 FIXME("len > INT_MAX not supported\n");
846 len = INT_MAX;
849 if(!locale)
850 locinfo = get_locinfo();
851 else
852 locinfo = locale->locinfo;
854 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE]) {
855 MSVCRT_strncpy(dest, src, len);
856 return strlen(src);
859 ret = LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
860 LCMAP_SORTKEY, src, -1, NULL, 0);
861 if(!ret) {
862 if(len) dest[0] = 0;
863 *MSVCRT__errno() = MSVCRT_EILSEQ;
864 return INT_MAX;
866 if(!len) return ret-1;
868 if(ret > len) {
869 dest[0] = 0;
870 *MSVCRT__errno() = MSVCRT_ERANGE;
871 return ret-1;
874 return LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
875 LCMAP_SORTKEY, src, -1, dest, len) - 1;
878 /*********************************************************************
879 * strxfrm (MSVCRT.@)
881 MSVCRT_size_t CDECL MSVCRT_strxfrm( char *dest, const char *src, MSVCRT_size_t len )
883 return MSVCRT__strxfrm_l(dest, src, len, NULL);
886 /********************************************************************
887 * _atoldbl (MSVCRT.@)
889 int CDECL MSVCRT__atoldbl(MSVCRT__LDOUBLE *value, const char *str)
891 /* FIXME needs error checking for huge/small values */
892 #ifdef HAVE_STRTOLD
893 long double ld;
894 TRACE("str %s value %p\n",str,value);
895 ld = strtold(str,0);
896 memcpy(value, &ld, 10);
897 #else
898 FIXME("stub, str %s value %p\n",str,value);
899 #endif
900 return 0;
903 /********************************************************************
904 * __STRINGTOLD (MSVCRT.@)
906 int CDECL __STRINGTOLD( MSVCRT__LDOUBLE *value, char **endptr, const char *str, int flags )
908 #ifdef HAVE_STRTOLD
909 long double ld;
910 FIXME("%p %p %s %x partial stub\n", value, endptr, str, flags );
911 ld = strtold(str,0);
912 memcpy(value, &ld, 10);
913 #else
914 FIXME("%p %p %s %x stub\n", value, endptr, str, flags );
915 #endif
916 return 0;
919 /*********************************************************************
920 * strlen (MSVCRT.@)
922 MSVCRT_size_t __cdecl MSVCRT_strlen(const char *str)
924 return strlen(str);
927 /******************************************************************
928 * strnlen (MSVCRT.@)
930 MSVCRT_size_t CDECL MSVCRT_strnlen(const char *s, MSVCRT_size_t maxlen)
932 MSVCRT_size_t i;
934 for(i=0; i<maxlen; i++)
935 if(!s[i]) break;
937 return i;
940 /*********************************************************************
941 * _strtoi64_l (MSVCRT.@)
943 * FIXME: locale parameter is ignored
945 __int64 CDECL MSVCRT_strtoi64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
947 const char *p = nptr;
948 BOOL negative = FALSE;
949 BOOL got_digit = FALSE;
950 __int64 ret = 0;
952 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
954 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
955 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
956 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
958 while(isspace(*nptr)) nptr++;
960 if(*nptr == '-') {
961 negative = TRUE;
962 nptr++;
963 } else if(*nptr == '+')
964 nptr++;
966 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
967 base = 16;
968 nptr += 2;
971 if(base == 0) {
972 if(*nptr=='0')
973 base = 8;
974 else
975 base = 10;
978 while(*nptr) {
979 char cur = tolower(*nptr);
980 int v;
982 if(cur>='0' && cur<='9') {
983 if(cur >= '0'+base)
984 break;
985 v = cur-'0';
986 } else {
987 if(cur<'a' || cur>='a'+base-10)
988 break;
989 v = cur-'a'+10;
991 got_digit = TRUE;
993 if(negative)
994 v = -v;
996 nptr++;
998 if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
999 ret = MSVCRT_I64_MAX;
1000 *MSVCRT__errno() = MSVCRT_ERANGE;
1001 } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
1002 ret = MSVCRT_I64_MIN;
1003 *MSVCRT__errno() = MSVCRT_ERANGE;
1004 } else
1005 ret = ret*base + v;
1008 if(endptr)
1009 *endptr = (char*)(got_digit ? nptr : p);
1011 return ret;
1014 /*********************************************************************
1015 * _strtoi64 (MSVCRT.@)
1017 __int64 CDECL MSVCRT_strtoi64(const char *nptr, char **endptr, int base)
1019 return MSVCRT_strtoi64_l(nptr, endptr, base, NULL);
1022 /*********************************************************************
1023 * _atoi_l (MSVCRT.@)
1025 int __cdecl MSVCRT__atoi_l(const char *str, MSVCRT__locale_t locale)
1027 __int64 ret = MSVCRT_strtoi64_l(str, NULL, 10, locale);
1029 if(ret > INT_MAX) {
1030 ret = INT_MAX;
1031 *MSVCRT__errno() = MSVCRT_ERANGE;
1032 } else if(ret < INT_MIN) {
1033 ret = INT_MIN;
1034 *MSVCRT__errno() = MSVCRT_ERANGE;
1036 return ret;
1039 /*********************************************************************
1040 * atoi (MSVCRT.@)
1042 #if _MSVCR_VER == 0
1043 int __cdecl MSVCRT_atoi(const char *str)
1045 BOOL minus = FALSE;
1046 int ret = 0;
1048 if(!str)
1049 return 0;
1051 while(isspace(*str)) str++;
1053 if(*str == '+') {
1054 str++;
1055 }else if(*str == '-') {
1056 minus = TRUE;
1057 str++;
1060 while(*str>='0' && *str<='9') {
1061 ret = ret*10+*str-'0';
1062 str++;
1065 return minus ? -ret : ret;
1067 #else
1068 int CDECL MSVCRT_atoi(const char *str)
1070 return MSVCRT__atoi_l(str, NULL);
1072 #endif
1074 /******************************************************************
1075 * _atoi64_l (MSVCRT.@)
1077 __int64 CDECL MSVCRT__atoi64_l(const char *str, MSVCRT__locale_t locale)
1079 return MSVCRT_strtoi64_l(str, NULL, 10, locale);
1082 /******************************************************************
1083 * _atoi64 (MSVCRT.@)
1085 __int64 CDECL MSVCRT__atoi64(const char *str)
1087 return MSVCRT_strtoi64_l(str, NULL, 10, NULL);
1090 /******************************************************************
1091 * _atol_l (MSVCRT.@)
1093 MSVCRT_long CDECL MSVCRT__atol_l(const char *str, MSVCRT__locale_t locale)
1095 __int64 ret = MSVCRT_strtoi64_l(str, NULL, 10, locale);
1097 if(ret > LONG_MAX) {
1098 ret = LONG_MAX;
1099 *MSVCRT__errno() = MSVCRT_ERANGE;
1100 } else if(ret < LONG_MIN) {
1101 ret = LONG_MIN;
1102 *MSVCRT__errno() = MSVCRT_ERANGE;
1104 return ret;
1107 /******************************************************************
1108 * atol (MSVCRT.@)
1110 MSVCRT_long CDECL MSVCRT_atol(const char *str)
1112 return MSVCRT__atol_l(str, NULL);
1115 #if _MSVCR_VER>=120
1117 /******************************************************************
1118 * _atoll_l (MSVCR120.@)
1120 MSVCRT_longlong CDECL MSVCRT__atoll_l(const char* str, MSVCRT__locale_t locale)
1122 return MSVCRT_strtoi64_l(str, NULL, 10, locale);
1125 /******************************************************************
1126 * atoll (MSVCR120.@)
1128 MSVCRT_longlong CDECL MSVCRT_atoll(const char* str)
1130 return MSVCRT__atoll_l(str, NULL);
1133 #endif /* if _MSVCR_VER>=120 */
1135 /******************************************************************
1136 * _strtol_l (MSVCRT.@)
1138 MSVCRT_long CDECL MSVCRT__strtol_l(const char* nptr,
1139 char** end, int base, MSVCRT__locale_t locale)
1141 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1143 if(ret > MSVCRT_LONG_MAX) {
1144 ret = MSVCRT_LONG_MAX;
1145 *MSVCRT__errno() = MSVCRT_ERANGE;
1146 } else if(ret < MSVCRT_LONG_MIN) {
1147 ret = MSVCRT_LONG_MIN;
1148 *MSVCRT__errno() = MSVCRT_ERANGE;
1151 return ret;
1154 /******************************************************************
1155 * strtol (MSVCRT.@)
1157 MSVCRT_long CDECL MSVCRT_strtol(const char* nptr, char** end, int base)
1159 return MSVCRT__strtol_l(nptr, end, base, NULL);
1162 /******************************************************************
1163 * _strtoul_l (MSVCRT.@)
1165 MSVCRT_ulong CDECL MSVCRT_strtoul_l(const char* nptr, char** end, int base, MSVCRT__locale_t locale)
1167 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1169 if(ret > MSVCRT_ULONG_MAX) {
1170 ret = MSVCRT_ULONG_MAX;
1171 *MSVCRT__errno() = MSVCRT_ERANGE;
1172 }else if(ret < -(__int64)MSVCRT_ULONG_MAX) {
1173 ret = 1;
1174 *MSVCRT__errno() = MSVCRT_ERANGE;
1177 return ret;
1180 /******************************************************************
1181 * strtoul (MSVCRT.@)
1183 MSVCRT_ulong CDECL MSVCRT_strtoul(const char* nptr, char** end, int base)
1185 return MSVCRT_strtoul_l(nptr, end, base, NULL);
1188 /*********************************************************************
1189 * _strtoui64_l (MSVCRT.@)
1191 * FIXME: locale parameter is ignored
1193 unsigned __int64 CDECL MSVCRT_strtoui64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
1195 const char *p = nptr;
1196 BOOL negative = FALSE;
1197 BOOL got_digit = FALSE;
1198 unsigned __int64 ret = 0;
1200 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1202 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1203 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1204 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1206 while(isspace(*nptr)) nptr++;
1208 if(*nptr == '-') {
1209 negative = TRUE;
1210 nptr++;
1211 } else if(*nptr == '+')
1212 nptr++;
1214 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
1215 base = 16;
1216 nptr += 2;
1219 if(base == 0) {
1220 if(*nptr=='0')
1221 base = 8;
1222 else
1223 base = 10;
1226 while(*nptr) {
1227 char cur = tolower(*nptr);
1228 int v;
1230 if(cur>='0' && cur<='9') {
1231 if(cur >= '0'+base)
1232 break;
1233 v = *nptr-'0';
1234 } else {
1235 if(cur<'a' || cur>='a'+base-10)
1236 break;
1237 v = cur-'a'+10;
1239 got_digit = TRUE;
1241 nptr++;
1243 if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1244 ret = MSVCRT_UI64_MAX;
1245 *MSVCRT__errno() = MSVCRT_ERANGE;
1246 } else
1247 ret = ret*base + v;
1250 if(endptr)
1251 *endptr = (char*)(got_digit ? nptr : p);
1253 return negative ? -ret : ret;
1256 /*********************************************************************
1257 * _strtoui64 (MSVCRT.@)
1259 unsigned __int64 CDECL MSVCRT_strtoui64(const char *nptr, char **endptr, int base)
1261 return MSVCRT_strtoui64_l(nptr, endptr, base, NULL);
1264 static int ltoa_helper(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1266 MSVCRT_ulong val;
1267 unsigned int digit;
1268 BOOL is_negative;
1269 char buffer[33], *pos;
1270 size_t len;
1272 if (value < 0 && radix == 10)
1274 is_negative = TRUE;
1275 val = -value;
1277 else
1279 is_negative = FALSE;
1280 val = value;
1283 pos = buffer + 32;
1284 *pos = '\0';
1288 digit = val % radix;
1289 val /= radix;
1291 if (digit < 10)
1292 *--pos = '0' + digit;
1293 else
1294 *--pos = 'a' + digit - 10;
1296 while (val != 0);
1298 if (is_negative)
1299 *--pos = '-';
1301 len = buffer + 33 - pos;
1302 if (len > size)
1304 size_t i;
1305 char *p = str;
1307 /* Copy the temporary buffer backwards up to the available number of
1308 * characters. Don't copy the negative sign if present. */
1310 if (is_negative)
1312 p++;
1313 size--;
1316 for (pos = buffer + 31, i = 0; i < size; i++)
1317 *p++ = *pos--;
1319 str[0] = '\0';
1320 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1321 return MSVCRT_ERANGE;
1324 memcpy(str, pos, len);
1325 return 0;
1328 /*********************************************************************
1329 * _ltoa_s (MSVCRT.@)
1331 int CDECL MSVCRT__ltoa_s(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1333 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1334 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1335 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1337 str[0] = '\0';
1338 return MSVCRT_EINVAL;
1341 return ltoa_helper(value, str, size, radix);
1344 /*********************************************************************
1345 * _ltow_s (MSVCRT.@)
1347 int CDECL MSVCRT__ltow_s(MSVCRT_long value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1349 MSVCRT_ulong val;
1350 unsigned int digit;
1351 BOOL is_negative;
1352 MSVCRT_wchar_t buffer[33], *pos;
1353 size_t len;
1355 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1356 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1357 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1359 str[0] = '\0';
1360 return MSVCRT_EINVAL;
1363 if (value < 0 && radix == 10)
1365 is_negative = TRUE;
1366 val = -value;
1368 else
1370 is_negative = FALSE;
1371 val = value;
1374 pos = buffer + 32;
1375 *pos = '\0';
1379 digit = val % radix;
1380 val /= radix;
1382 if (digit < 10)
1383 *--pos = '0' + digit;
1384 else
1385 *--pos = 'a' + digit - 10;
1387 while (val != 0);
1389 if (is_negative)
1390 *--pos = '-';
1392 len = buffer + 33 - pos;
1393 if (len > size)
1395 size_t i;
1396 MSVCRT_wchar_t *p = str;
1398 /* Copy the temporary buffer backwards up to the available number of
1399 * characters. Don't copy the negative sign if present. */
1401 if (is_negative)
1403 p++;
1404 size--;
1407 for (pos = buffer + 31, i = 0; i < size; i++)
1408 *p++ = *pos--;
1410 str[0] = '\0';
1411 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1412 return MSVCRT_ERANGE;
1415 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1416 return 0;
1419 /*********************************************************************
1420 * _itoa_s (MSVCRT.@)
1422 int CDECL MSVCRT__itoa_s(int value, char *str, MSVCRT_size_t size, int radix)
1424 return MSVCRT__ltoa_s(value, str, size, radix);
1427 /*********************************************************************
1428 * _itoa (MSVCRT.@)
1430 char* CDECL MSVCRT__itoa(int value, char *str, int radix)
1432 return ltoa_helper(value, str, MSVCRT_SIZE_MAX, radix) ? NULL : str;
1435 /*********************************************************************
1436 * _itow_s (MSVCRT.@)
1438 int CDECL MSVCRT__itow_s(int value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1440 return MSVCRT__ltow_s(value, str, size, radix);
1443 /*********************************************************************
1444 * _ui64toa_s (MSVCRT.@)
1446 int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str,
1447 MSVCRT_size_t size, int radix)
1449 char buffer[65], *pos;
1450 int digit;
1452 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1453 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1454 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1456 str[0] = '\0';
1457 return MSVCRT_EINVAL;
1460 pos = buffer+64;
1461 *pos = '\0';
1463 do {
1464 digit = value%radix;
1465 value /= radix;
1467 if(digit < 10)
1468 *--pos = '0'+digit;
1469 else
1470 *--pos = 'a'+digit-10;
1471 }while(value != 0);
1473 if(buffer-pos+65 > size) {
1474 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1475 return MSVCRT_EINVAL;
1478 memcpy(str, pos, buffer-pos+65);
1479 return 0;
1482 /*********************************************************************
1483 * _ui64tow_s (MSVCRT.@)
1485 int CDECL MSVCRT__ui64tow_s( unsigned __int64 value, MSVCRT_wchar_t *str,
1486 MSVCRT_size_t size, int radix )
1488 MSVCRT_wchar_t buffer[65], *pos;
1489 int digit;
1491 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1492 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1493 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1495 str[0] = '\0';
1496 return MSVCRT_EINVAL;
1499 pos = &buffer[64];
1500 *pos = '\0';
1502 do {
1503 digit = value % radix;
1504 value = value / radix;
1505 if (digit < 10)
1506 *--pos = '0' + digit;
1507 else
1508 *--pos = 'a' + digit - 10;
1509 } while (value != 0);
1511 if(buffer-pos+65 > size) {
1512 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1513 return MSVCRT_EINVAL;
1516 memcpy(str, pos, (buffer-pos+65)*sizeof(MSVCRT_wchar_t));
1517 return 0;
1520 /*********************************************************************
1521 * _ultoa_s (MSVCRT.@)
1523 int CDECL MSVCRT__ultoa_s(MSVCRT_ulong value, char *str, MSVCRT_size_t size, int radix)
1525 MSVCRT_ulong digit;
1526 char buffer[33], *pos;
1527 size_t len;
1529 if (!str || !size || radix < 2 || radix > 36)
1531 if (str && size)
1532 str[0] = '\0';
1534 *MSVCRT__errno() = MSVCRT_EINVAL;
1535 return MSVCRT_EINVAL;
1538 pos = buffer + 32;
1539 *pos = '\0';
1543 digit = value % radix;
1544 value /= radix;
1546 if (digit < 10)
1547 *--pos = '0' + digit;
1548 else
1549 *--pos = 'a' + digit - 10;
1551 while (value != 0);
1553 len = buffer + 33 - pos;
1554 if (len > size)
1556 size_t i;
1557 char *p = str;
1559 /* Copy the temporary buffer backwards up to the available number of
1560 * characters. */
1562 for (pos = buffer + 31, i = 0; i < size; i++)
1563 *p++ = *pos--;
1565 str[0] = '\0';
1566 *MSVCRT__errno() = MSVCRT_ERANGE;
1567 return MSVCRT_ERANGE;
1570 memcpy(str, pos, len);
1571 return 0;
1574 /*********************************************************************
1575 * _ultow_s (MSVCRT.@)
1577 int CDECL MSVCRT__ultow_s(MSVCRT_ulong value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1579 MSVCRT_ulong digit;
1580 WCHAR buffer[33], *pos;
1581 size_t len;
1583 if (!str || !size || radix < 2 || radix > 36)
1585 if (str && size)
1586 str[0] = '\0';
1588 *MSVCRT__errno() = MSVCRT_EINVAL;
1589 return MSVCRT_EINVAL;
1592 pos = buffer + 32;
1593 *pos = '\0';
1597 digit = value % radix;
1598 value /= radix;
1600 if (digit < 10)
1601 *--pos = '0' + digit;
1602 else
1603 *--pos = 'a' + digit - 10;
1605 while (value != 0);
1607 len = buffer + 33 - pos;
1608 if (len > size)
1610 size_t i;
1611 WCHAR *p = str;
1613 /* Copy the temporary buffer backwards up to the available number of
1614 * characters. */
1616 for (pos = buffer + 31, i = 0; i < size; i++)
1617 *p++ = *pos--;
1619 str[0] = '\0';
1620 *MSVCRT__errno() = MSVCRT_ERANGE;
1621 return MSVCRT_ERANGE;
1624 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1625 return 0;
1628 /*********************************************************************
1629 * _i64toa_s (MSVCRT.@)
1631 int CDECL MSVCRT__i64toa_s(__int64 value, char *str, MSVCRT_size_t size, int radix)
1633 unsigned __int64 val;
1634 unsigned int digit;
1635 BOOL is_negative;
1636 char buffer[65], *pos;
1637 size_t len;
1639 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1640 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1641 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1643 str[0] = '\0';
1644 return MSVCRT_EINVAL;
1647 if (value < 0 && radix == 10)
1649 is_negative = TRUE;
1650 val = -value;
1652 else
1654 is_negative = FALSE;
1655 val = value;
1658 pos = buffer + 64;
1659 *pos = '\0';
1663 digit = val % radix;
1664 val /= radix;
1666 if (digit < 10)
1667 *--pos = '0' + digit;
1668 else
1669 *--pos = 'a' + digit - 10;
1671 while (val != 0);
1673 if (is_negative)
1674 *--pos = '-';
1676 len = buffer + 65 - pos;
1677 if (len > size)
1679 size_t i;
1680 char *p = str;
1682 /* Copy the temporary buffer backwards up to the available number of
1683 * characters. Don't copy the negative sign if present. */
1685 if (is_negative)
1687 p++;
1688 size--;
1691 for (pos = buffer + 63, i = 0; i < size; i++)
1692 *p++ = *pos--;
1694 str[0] = '\0';
1695 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1696 return MSVCRT_ERANGE;
1699 memcpy(str, pos, len);
1700 return 0;
1703 /*********************************************************************
1704 * _i64tow_s (MSVCRT.@)
1706 int CDECL MSVCRT__i64tow_s(__int64 value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1708 unsigned __int64 val;
1709 unsigned int digit;
1710 BOOL is_negative;
1711 MSVCRT_wchar_t buffer[65], *pos;
1712 size_t len;
1714 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1715 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1716 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1718 str[0] = '\0';
1719 return MSVCRT_EINVAL;
1722 if (value < 0 && radix == 10)
1724 is_negative = TRUE;
1725 val = -value;
1727 else
1729 is_negative = FALSE;
1730 val = value;
1733 pos = buffer + 64;
1734 *pos = '\0';
1738 digit = val % radix;
1739 val /= radix;
1741 if (digit < 10)
1742 *--pos = '0' + digit;
1743 else
1744 *--pos = 'a' + digit - 10;
1746 while (val != 0);
1748 if (is_negative)
1749 *--pos = '-';
1751 len = buffer + 65 - pos;
1752 if (len > size)
1754 size_t i;
1755 MSVCRT_wchar_t *p = str;
1757 /* Copy the temporary buffer backwards up to the available number of
1758 * characters. Don't copy the negative sign if present. */
1760 if (is_negative)
1762 p++;
1763 size--;
1766 for (pos = buffer + 63, i = 0; i < size; i++)
1767 *p++ = *pos--;
1769 str[0] = '\0';
1770 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1771 return MSVCRT_ERANGE;
1774 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1775 return 0;
1778 #define I10_OUTPUT_MAX_PREC 21
1779 /* Internal structure used by $I10_OUTPUT */
1780 struct _I10_OUTPUT_DATA {
1781 short pos;
1782 char sign;
1783 BYTE len;
1784 char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */
1787 /*********************************************************************
1788 * $I10_OUTPUT (MSVCRT.@)
1789 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
1790 * prec - precision of part, we're interested in
1791 * flag - 0 for first prec digits, 1 for fractional part
1792 * data - data to be populated
1794 * return value
1795 * 0 if given double is NaN or INF
1796 * 1 otherwise
1798 * FIXME
1799 * Native sets last byte of data->str to '0' or '9', I don't know what
1800 * it means. Current implementation sets it always to '0'.
1802 int CDECL MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data)
1804 static const char inf_str[] = "1#INF";
1805 static const char nan_str[] = "1#QNAN";
1807 /* MS' long double type wants 12 bytes for Intel's 80 bit FP format.
1808 * Some UNIX have sizeof(long double) == 16, yet only 80 bit are used.
1809 * Assume long double uses 80 bit FP, never seen 128 bit FP. */
1810 long double ld = 0;
1811 double d;
1812 char format[8];
1813 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
1814 char *p;
1816 memcpy(&ld, &ld80, 10);
1817 d = ld;
1818 TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
1820 if(d<0) {
1821 data->sign = '-';
1822 d = -d;
1823 } else
1824 data->sign = ' ';
1826 if(isinf(d)) {
1827 data->pos = 1;
1828 data->len = 5;
1829 memcpy(data->str, inf_str, sizeof(inf_str));
1831 return 0;
1834 if(isnan(d)) {
1835 data->pos = 1;
1836 data->len = 6;
1837 memcpy(data->str, nan_str, sizeof(nan_str));
1839 return 0;
1842 if(flag&1) {
1843 int exp = 1+floor(log10(d));
1845 prec += exp;
1846 if(exp < 0)
1847 prec--;
1849 prec--;
1851 if(prec+1 > I10_OUTPUT_MAX_PREC)
1852 prec = I10_OUTPUT_MAX_PREC-1;
1853 else if(prec < 0) {
1854 d = 0.0;
1855 prec = 0;
1858 sprintf(format, "%%.%dle", prec);
1859 sprintf(buf, format, d);
1861 buf[1] = buf[0];
1862 data->pos = atoi(buf+prec+3);
1863 if(buf[1] != '0')
1864 data->pos++;
1866 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
1867 data->len = p-buf;
1869 memcpy(data->str, buf+1, data->len);
1870 data->str[data->len] = '\0';
1872 if(buf[1]!='0' && prec-data->len+1>0)
1873 memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1);
1875 return 1;
1877 #undef I10_OUTPUT_MAX_PREC
1879 /*********************************************************************
1880 * memcmp (MSVCRT.@)
1882 int __cdecl MSVCRT_memcmp(const void *ptr1, const void *ptr2, MSVCRT_size_t n)
1884 return memcmp(ptr1, ptr2, n);
1887 /*********************************************************************
1888 * memcpy (MSVCRT.@)
1890 void * __cdecl MSVCRT_memcpy(void *dst, const void *src, MSVCRT_size_t n)
1892 return memmove(dst, src, n);
1895 /*********************************************************************
1896 * memmove (MSVCRT.@)
1898 void * __cdecl MSVCRT_memmove(void *dst, const void *src, MSVCRT_size_t n)
1900 return memmove(dst, src, n);
1903 /*********************************************************************
1904 * memset (MSVCRT.@)
1906 void* __cdecl MSVCRT_memset(void *dst, int c, MSVCRT_size_t n)
1908 return memset(dst, c, n);
1911 /*********************************************************************
1912 * strchr (MSVCRT.@)
1914 char* __cdecl MSVCRT_strchr(const char *str, int c)
1916 return strchr(str, c);
1919 /*********************************************************************
1920 * strrchr (MSVCRT.@)
1922 char* __cdecl MSVCRT_strrchr(const char *str, int c)
1924 return strrchr(str, c);
1927 /*********************************************************************
1928 * memchr (MSVCRT.@)
1930 void* __cdecl MSVCRT_memchr(const void *ptr, int c, MSVCRT_size_t n)
1932 return memchr(ptr, c, n);
1935 /*********************************************************************
1936 * strcmp (MSVCRT.@)
1938 int __cdecl MSVCRT_strcmp(const char *str1, const char *str2)
1940 return strcmp(str1, str2);
1943 /*********************************************************************
1944 * strncmp (MSVCRT.@)
1946 int __cdecl MSVCRT_strncmp(const char *str1, const char *str2, MSVCRT_size_t len)
1948 return strncmp(str1, str2, len);
1951 /*********************************************************************
1952 * _strnicmp_l (MSVCRT.@)
1954 int __cdecl MSVCRT__strnicmp_l(const char *s1, const char *s2,
1955 MSVCRT_size_t count, MSVCRT__locale_t locale)
1957 MSVCRT_pthreadlocinfo locinfo;
1958 int c1, c2;
1960 if(s1==NULL || s2==NULL)
1961 return MSVCRT__NLSCMPERROR;
1963 if(!count)
1964 return 0;
1966 if(!locale)
1967 locinfo = get_locinfo();
1968 else
1969 locinfo = locale->locinfo;
1971 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
1972 return strncasecmp(s1, s2, count);
1974 do {
1975 c1 = MSVCRT__tolower_l(*s1++, locale);
1976 c2 = MSVCRT__tolower_l(*s2++, locale);
1977 }while(--count && c1 && c1==c2);
1979 return c1-c2;
1982 /*********************************************************************
1983 * _stricmp_l (MSVCRT.@)
1985 int __cdecl MSVCRT__stricmp_l(const char *s1, const char *s2, MSVCRT__locale_t locale)
1987 return MSVCRT__strnicmp_l(s1, s2, -1, locale);
1990 /*********************************************************************
1991 * _strnicmp (MSVCRT.@)
1993 int __cdecl MSVCRT__strnicmp(const char *s1, const char *s2, MSVCRT_size_t count)
1995 return MSVCRT__strnicmp_l(s1, s2, count, NULL);
1998 /*********************************************************************
1999 * _stricmp (MSVCRT.@)
2001 int __cdecl MSVCRT__stricmp(const char *s1, const char *s2)
2003 return MSVCRT__strnicmp_l(s1, s2, -1, NULL);
2006 /*********************************************************************
2007 * strstr (MSVCRT.@)
2009 char* __cdecl MSVCRT_strstr(const char *haystack, const char *needle)
2011 return strstr(haystack, needle);
2014 /*********************************************************************
2015 * _memicmp_l (MSVCRT.@)
2017 int __cdecl MSVCRT__memicmp_l(const char *s1, const char *s2, MSVCRT_size_t len, MSVCRT__locale_t locale)
2019 int ret = 0;
2021 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
2022 if (!s1 || !s2)
2024 if (len)
2025 MSVCRT_INVALID_PMT(NULL, EINVAL);
2026 return len ? MSVCRT__NLSCMPERROR : 0;
2028 #endif
2030 while (len--)
2032 if ((ret = MSVCRT__tolower_l(*s1, locale) - MSVCRT__tolower_l(*s2, locale)))
2033 break;
2034 s1++;
2035 s2++;
2037 return ret;
2040 /*********************************************************************
2041 * _memicmp (MSVCRT.@)
2043 int __cdecl MSVCRT__memicmp(const char *s1, const char *s2, MSVCRT_size_t len)
2045 return MSVCRT__memicmp_l(s1, s2, len, NULL);
2048 /*********************************************************************
2049 * strcspn (MSVCRT.@)
2051 MSVCRT_size_t __cdecl MSVCRT_strcspn(const char *str, const char *reject)
2053 return strcspn( str, reject );
2056 /*********************************************************************
2057 * strpbrk (MSVCRT.@)
2059 char* __cdecl MSVCRT_strpbrk(const char *str, const char *accept)
2061 return strpbrk(str, accept);
2064 /*********************************************************************
2065 * __strncnt (MSVCRT.@)
2067 MSVCRT_size_t __cdecl MSVCRT___strncnt(const char *str, MSVCRT_size_t size)
2069 MSVCRT_size_t ret = 0;
2071 #if _MSVCR_VER >= 140
2072 while (*str++ && size--)
2073 #else
2074 while (size-- && *str++)
2075 #endif
2077 ret++;
2080 return ret;