wineconsole: Try harder to get a scalable font.
[wine.git] / dlls / msvcrt / string.c
blobb58d56bd2088024aad4672108c63616701299063
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 * _atol_l (MSVCRT.@)
1085 MSVCRT_long CDECL MSVCRT__atol_l(const char *str, MSVCRT__locale_t locale)
1087 __int64 ret = MSVCRT_strtoi64_l(str, NULL, 10, locale);
1089 if(ret > LONG_MAX) {
1090 ret = LONG_MAX;
1091 *MSVCRT__errno() = MSVCRT_ERANGE;
1092 } else if(ret < LONG_MIN) {
1093 ret = LONG_MIN;
1094 *MSVCRT__errno() = MSVCRT_ERANGE;
1096 return ret;
1099 #if _MSVCR_VER>=120
1101 /******************************************************************
1102 * _atoll_l (MSVCR120.@)
1104 MSVCRT_longlong CDECL MSVCRT__atoll_l(const char* str, MSVCRT__locale_t locale)
1106 return MSVCRT_strtoi64_l(str, NULL, 10, locale);
1109 /******************************************************************
1110 * atoll (MSVCR120.@)
1112 MSVCRT_longlong CDECL MSVCRT_atoll(const char* str)
1114 return MSVCRT__atoll_l(str, NULL);
1117 #endif /* if _MSVCR_VER>=120 */
1119 /******************************************************************
1120 * _strtol_l (MSVCRT.@)
1122 MSVCRT_long CDECL MSVCRT__strtol_l(const char* nptr,
1123 char** end, int base, MSVCRT__locale_t locale)
1125 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1127 if(ret > MSVCRT_LONG_MAX) {
1128 ret = MSVCRT_LONG_MAX;
1129 *MSVCRT__errno() = MSVCRT_ERANGE;
1130 } else if(ret < MSVCRT_LONG_MIN) {
1131 ret = MSVCRT_LONG_MIN;
1132 *MSVCRT__errno() = MSVCRT_ERANGE;
1135 return ret;
1138 /******************************************************************
1139 * strtol (MSVCRT.@)
1141 MSVCRT_long CDECL MSVCRT_strtol(const char* nptr, char** end, int base)
1143 return MSVCRT__strtol_l(nptr, end, base, NULL);
1146 /******************************************************************
1147 * _strtoul_l (MSVCRT.@)
1149 MSVCRT_ulong CDECL MSVCRT_strtoul_l(const char* nptr, char** end, int base, MSVCRT__locale_t locale)
1151 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1153 if(ret > MSVCRT_ULONG_MAX) {
1154 ret = MSVCRT_ULONG_MAX;
1155 *MSVCRT__errno() = MSVCRT_ERANGE;
1156 }else if(ret < -(__int64)MSVCRT_ULONG_MAX) {
1157 ret = 1;
1158 *MSVCRT__errno() = MSVCRT_ERANGE;
1161 return ret;
1164 /******************************************************************
1165 * strtoul (MSVCRT.@)
1167 MSVCRT_ulong CDECL MSVCRT_strtoul(const char* nptr, char** end, int base)
1169 return MSVCRT_strtoul_l(nptr, end, base, NULL);
1172 /*********************************************************************
1173 * _strtoui64_l (MSVCRT.@)
1175 * FIXME: locale parameter is ignored
1177 unsigned __int64 CDECL MSVCRT_strtoui64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
1179 const char *p = nptr;
1180 BOOL negative = FALSE;
1181 BOOL got_digit = FALSE;
1182 unsigned __int64 ret = 0;
1184 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1186 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1187 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1188 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1190 while(isspace(*nptr)) nptr++;
1192 if(*nptr == '-') {
1193 negative = TRUE;
1194 nptr++;
1195 } else if(*nptr == '+')
1196 nptr++;
1198 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
1199 base = 16;
1200 nptr += 2;
1203 if(base == 0) {
1204 if(*nptr=='0')
1205 base = 8;
1206 else
1207 base = 10;
1210 while(*nptr) {
1211 char cur = tolower(*nptr);
1212 int v;
1214 if(cur>='0' && cur<='9') {
1215 if(cur >= '0'+base)
1216 break;
1217 v = *nptr-'0';
1218 } else {
1219 if(cur<'a' || cur>='a'+base-10)
1220 break;
1221 v = cur-'a'+10;
1223 got_digit = TRUE;
1225 nptr++;
1227 if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1228 ret = MSVCRT_UI64_MAX;
1229 *MSVCRT__errno() = MSVCRT_ERANGE;
1230 } else
1231 ret = ret*base + v;
1234 if(endptr)
1235 *endptr = (char*)(got_digit ? nptr : p);
1237 return negative ? -ret : ret;
1240 /*********************************************************************
1241 * _strtoui64 (MSVCRT.@)
1243 unsigned __int64 CDECL MSVCRT_strtoui64(const char *nptr, char **endptr, int base)
1245 return MSVCRT_strtoui64_l(nptr, endptr, base, NULL);
1248 static int ltoa_helper(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1250 MSVCRT_ulong val;
1251 unsigned int digit;
1252 BOOL is_negative;
1253 char buffer[33], *pos;
1254 size_t len;
1256 if (value < 0 && radix == 10)
1258 is_negative = TRUE;
1259 val = -value;
1261 else
1263 is_negative = FALSE;
1264 val = value;
1267 pos = buffer + 32;
1268 *pos = '\0';
1272 digit = val % radix;
1273 val /= radix;
1275 if (digit < 10)
1276 *--pos = '0' + digit;
1277 else
1278 *--pos = 'a' + digit - 10;
1280 while (val != 0);
1282 if (is_negative)
1283 *--pos = '-';
1285 len = buffer + 33 - pos;
1286 if (len > size)
1288 size_t i;
1289 char *p = str;
1291 /* Copy the temporary buffer backwards up to the available number of
1292 * characters. Don't copy the negative sign if present. */
1294 if (is_negative)
1296 p++;
1297 size--;
1300 for (pos = buffer + 31, i = 0; i < size; i++)
1301 *p++ = *pos--;
1303 str[0] = '\0';
1304 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1305 return MSVCRT_ERANGE;
1308 memcpy(str, pos, len);
1309 return 0;
1312 /*********************************************************************
1313 * _ltoa_s (MSVCRT.@)
1315 int CDECL MSVCRT__ltoa_s(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1317 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1318 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1319 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1321 str[0] = '\0';
1322 return MSVCRT_EINVAL;
1325 return ltoa_helper(value, str, size, radix);
1328 /*********************************************************************
1329 * _ltow_s (MSVCRT.@)
1331 int CDECL MSVCRT__ltow_s(MSVCRT_long value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1333 MSVCRT_ulong val;
1334 unsigned int digit;
1335 BOOL is_negative;
1336 MSVCRT_wchar_t buffer[33], *pos;
1337 size_t len;
1339 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1340 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1341 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1343 str[0] = '\0';
1344 return MSVCRT_EINVAL;
1347 if (value < 0 && radix == 10)
1349 is_negative = TRUE;
1350 val = -value;
1352 else
1354 is_negative = FALSE;
1355 val = value;
1358 pos = buffer + 32;
1359 *pos = '\0';
1363 digit = val % radix;
1364 val /= radix;
1366 if (digit < 10)
1367 *--pos = '0' + digit;
1368 else
1369 *--pos = 'a' + digit - 10;
1371 while (val != 0);
1373 if (is_negative)
1374 *--pos = '-';
1376 len = buffer + 33 - pos;
1377 if (len > size)
1379 size_t i;
1380 MSVCRT_wchar_t *p = str;
1382 /* Copy the temporary buffer backwards up to the available number of
1383 * characters. Don't copy the negative sign if present. */
1385 if (is_negative)
1387 p++;
1388 size--;
1391 for (pos = buffer + 31, i = 0; i < size; i++)
1392 *p++ = *pos--;
1394 str[0] = '\0';
1395 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1396 return MSVCRT_ERANGE;
1399 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1400 return 0;
1403 /*********************************************************************
1404 * _itoa_s (MSVCRT.@)
1406 int CDECL MSVCRT__itoa_s(int value, char *str, MSVCRT_size_t size, int radix)
1408 return MSVCRT__ltoa_s(value, str, size, radix);
1411 /*********************************************************************
1412 * _itoa (MSVCRT.@)
1414 char* CDECL MSVCRT__itoa(int value, char *str, int radix)
1416 return ltoa_helper(value, str, MSVCRT_SIZE_MAX, radix) ? NULL : str;
1419 /*********************************************************************
1420 * _itow_s (MSVCRT.@)
1422 int CDECL MSVCRT__itow_s(int value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1424 return MSVCRT__ltow_s(value, str, size, radix);
1427 /*********************************************************************
1428 * _ui64toa_s (MSVCRT.@)
1430 int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str,
1431 MSVCRT_size_t size, int radix)
1433 char buffer[65], *pos;
1434 int digit;
1436 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1437 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1438 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1440 str[0] = '\0';
1441 return MSVCRT_EINVAL;
1444 pos = buffer+64;
1445 *pos = '\0';
1447 do {
1448 digit = value%radix;
1449 value /= radix;
1451 if(digit < 10)
1452 *--pos = '0'+digit;
1453 else
1454 *--pos = 'a'+digit-10;
1455 }while(value != 0);
1457 if(buffer-pos+65 > size) {
1458 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1459 return MSVCRT_EINVAL;
1462 memcpy(str, pos, buffer-pos+65);
1463 return 0;
1466 /*********************************************************************
1467 * _ui64tow_s (MSVCRT.@)
1469 int CDECL MSVCRT__ui64tow_s( unsigned __int64 value, MSVCRT_wchar_t *str,
1470 MSVCRT_size_t size, int radix )
1472 MSVCRT_wchar_t buffer[65], *pos;
1473 int digit;
1475 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1476 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1477 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1479 str[0] = '\0';
1480 return MSVCRT_EINVAL;
1483 pos = &buffer[64];
1484 *pos = '\0';
1486 do {
1487 digit = value % radix;
1488 value = value / radix;
1489 if (digit < 10)
1490 *--pos = '0' + digit;
1491 else
1492 *--pos = 'a' + digit - 10;
1493 } while (value != 0);
1495 if(buffer-pos+65 > size) {
1496 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1497 return MSVCRT_EINVAL;
1500 memcpy(str, pos, (buffer-pos+65)*sizeof(MSVCRT_wchar_t));
1501 return 0;
1504 /*********************************************************************
1505 * _ultoa_s (MSVCRT.@)
1507 int CDECL MSVCRT__ultoa_s(MSVCRT_ulong value, char *str, MSVCRT_size_t size, int radix)
1509 MSVCRT_ulong digit;
1510 char buffer[33], *pos;
1511 size_t len;
1513 if (!str || !size || radix < 2 || radix > 36)
1515 if (str && size)
1516 str[0] = '\0';
1518 *MSVCRT__errno() = MSVCRT_EINVAL;
1519 return MSVCRT_EINVAL;
1522 pos = buffer + 32;
1523 *pos = '\0';
1527 digit = value % radix;
1528 value /= radix;
1530 if (digit < 10)
1531 *--pos = '0' + digit;
1532 else
1533 *--pos = 'a' + digit - 10;
1535 while (value != 0);
1537 len = buffer + 33 - pos;
1538 if (len > size)
1540 size_t i;
1541 char *p = str;
1543 /* Copy the temporary buffer backwards up to the available number of
1544 * characters. */
1546 for (pos = buffer + 31, i = 0; i < size; i++)
1547 *p++ = *pos--;
1549 str[0] = '\0';
1550 *MSVCRT__errno() = MSVCRT_ERANGE;
1551 return MSVCRT_ERANGE;
1554 memcpy(str, pos, len);
1555 return 0;
1558 /*********************************************************************
1559 * _ultow_s (MSVCRT.@)
1561 int CDECL MSVCRT__ultow_s(MSVCRT_ulong value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1563 MSVCRT_ulong digit;
1564 WCHAR buffer[33], *pos;
1565 size_t len;
1567 if (!str || !size || radix < 2 || radix > 36)
1569 if (str && size)
1570 str[0] = '\0';
1572 *MSVCRT__errno() = MSVCRT_EINVAL;
1573 return MSVCRT_EINVAL;
1576 pos = buffer + 32;
1577 *pos = '\0';
1581 digit = value % radix;
1582 value /= radix;
1584 if (digit < 10)
1585 *--pos = '0' + digit;
1586 else
1587 *--pos = 'a' + digit - 10;
1589 while (value != 0);
1591 len = buffer + 33 - pos;
1592 if (len > size)
1594 size_t i;
1595 WCHAR *p = str;
1597 /* Copy the temporary buffer backwards up to the available number of
1598 * characters. */
1600 for (pos = buffer + 31, i = 0; i < size; i++)
1601 *p++ = *pos--;
1603 str[0] = '\0';
1604 *MSVCRT__errno() = MSVCRT_ERANGE;
1605 return MSVCRT_ERANGE;
1608 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1609 return 0;
1612 /*********************************************************************
1613 * _i64toa_s (MSVCRT.@)
1615 int CDECL MSVCRT__i64toa_s(__int64 value, char *str, MSVCRT_size_t size, int radix)
1617 unsigned __int64 val;
1618 unsigned int digit;
1619 BOOL is_negative;
1620 char buffer[65], *pos;
1621 size_t len;
1623 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1624 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1625 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1627 str[0] = '\0';
1628 return MSVCRT_EINVAL;
1631 if (value < 0 && radix == 10)
1633 is_negative = TRUE;
1634 val = -value;
1636 else
1638 is_negative = FALSE;
1639 val = value;
1642 pos = buffer + 64;
1643 *pos = '\0';
1647 digit = val % radix;
1648 val /= radix;
1650 if (digit < 10)
1651 *--pos = '0' + digit;
1652 else
1653 *--pos = 'a' + digit - 10;
1655 while (val != 0);
1657 if (is_negative)
1658 *--pos = '-';
1660 len = buffer + 65 - pos;
1661 if (len > size)
1663 size_t i;
1664 char *p = str;
1666 /* Copy the temporary buffer backwards up to the available number of
1667 * characters. Don't copy the negative sign if present. */
1669 if (is_negative)
1671 p++;
1672 size--;
1675 for (pos = buffer + 63, i = 0; i < size; i++)
1676 *p++ = *pos--;
1678 str[0] = '\0';
1679 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1680 return MSVCRT_ERANGE;
1683 memcpy(str, pos, len);
1684 return 0;
1687 /*********************************************************************
1688 * _i64tow_s (MSVCRT.@)
1690 int CDECL MSVCRT__i64tow_s(__int64 value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1692 unsigned __int64 val;
1693 unsigned int digit;
1694 BOOL is_negative;
1695 MSVCRT_wchar_t buffer[65], *pos;
1696 size_t len;
1698 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1699 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1700 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1702 str[0] = '\0';
1703 return MSVCRT_EINVAL;
1706 if (value < 0 && radix == 10)
1708 is_negative = TRUE;
1709 val = -value;
1711 else
1713 is_negative = FALSE;
1714 val = value;
1717 pos = buffer + 64;
1718 *pos = '\0';
1722 digit = val % radix;
1723 val /= radix;
1725 if (digit < 10)
1726 *--pos = '0' + digit;
1727 else
1728 *--pos = 'a' + digit - 10;
1730 while (val != 0);
1732 if (is_negative)
1733 *--pos = '-';
1735 len = buffer + 65 - pos;
1736 if (len > size)
1738 size_t i;
1739 MSVCRT_wchar_t *p = str;
1741 /* Copy the temporary buffer backwards up to the available number of
1742 * characters. Don't copy the negative sign if present. */
1744 if (is_negative)
1746 p++;
1747 size--;
1750 for (pos = buffer + 63, i = 0; i < size; i++)
1751 *p++ = *pos--;
1753 str[0] = '\0';
1754 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1755 return MSVCRT_ERANGE;
1758 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1759 return 0;
1762 #define I10_OUTPUT_MAX_PREC 21
1763 /* Internal structure used by $I10_OUTPUT */
1764 struct _I10_OUTPUT_DATA {
1765 short pos;
1766 char sign;
1767 BYTE len;
1768 char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */
1771 /*********************************************************************
1772 * $I10_OUTPUT (MSVCRT.@)
1773 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
1774 * prec - precision of part, we're interested in
1775 * flag - 0 for first prec digits, 1 for fractional part
1776 * data - data to be populated
1778 * return value
1779 * 0 if given double is NaN or INF
1780 * 1 otherwise
1782 * FIXME
1783 * Native sets last byte of data->str to '0' or '9', I don't know what
1784 * it means. Current implementation sets it always to '0'.
1786 int CDECL MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data)
1788 static const char inf_str[] = "1#INF";
1789 static const char nan_str[] = "1#QNAN";
1791 /* MS' long double type wants 12 bytes for Intel's 80 bit FP format.
1792 * Some UNIX have sizeof(long double) == 16, yet only 80 bit are used.
1793 * Assume long double uses 80 bit FP, never seen 128 bit FP. */
1794 long double ld = 0;
1795 double d;
1796 char format[8];
1797 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
1798 char *p;
1800 memcpy(&ld, &ld80, 10);
1801 d = ld;
1802 TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
1804 if(d<0) {
1805 data->sign = '-';
1806 d = -d;
1807 } else
1808 data->sign = ' ';
1810 if(isinf(d)) {
1811 data->pos = 1;
1812 data->len = 5;
1813 memcpy(data->str, inf_str, sizeof(inf_str));
1815 return 0;
1818 if(isnan(d)) {
1819 data->pos = 1;
1820 data->len = 6;
1821 memcpy(data->str, nan_str, sizeof(nan_str));
1823 return 0;
1826 if(flag&1) {
1827 int exp = 1+floor(log10(d));
1829 prec += exp;
1830 if(exp < 0)
1831 prec--;
1833 prec--;
1835 if(prec+1 > I10_OUTPUT_MAX_PREC)
1836 prec = I10_OUTPUT_MAX_PREC-1;
1837 else if(prec < 0) {
1838 d = 0.0;
1839 prec = 0;
1842 sprintf(format, "%%.%dle", prec);
1843 sprintf(buf, format, d);
1845 buf[1] = buf[0];
1846 data->pos = atoi(buf+prec+3);
1847 if(buf[1] != '0')
1848 data->pos++;
1850 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
1851 data->len = p-buf;
1853 memcpy(data->str, buf+1, data->len);
1854 data->str[data->len] = '\0';
1856 if(buf[1]!='0' && prec-data->len+1>0)
1857 memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1);
1859 return 1;
1861 #undef I10_OUTPUT_MAX_PREC
1863 /*********************************************************************
1864 * memcmp (MSVCRT.@)
1866 int __cdecl MSVCRT_memcmp(const void *ptr1, const void *ptr2, MSVCRT_size_t n)
1868 return memcmp(ptr1, ptr2, n);
1871 /*********************************************************************
1872 * memcpy (MSVCRT.@)
1874 void * __cdecl MSVCRT_memcpy(void *dst, const void *src, MSVCRT_size_t n)
1876 return memmove(dst, src, n);
1879 /*********************************************************************
1880 * memmove (MSVCRT.@)
1882 void * __cdecl MSVCRT_memmove(void *dst, const void *src, MSVCRT_size_t n)
1884 return memmove(dst, src, n);
1887 /*********************************************************************
1888 * memset (MSVCRT.@)
1890 void* __cdecl MSVCRT_memset(void *dst, int c, MSVCRT_size_t n)
1892 return memset(dst, c, n);
1895 /*********************************************************************
1896 * strchr (MSVCRT.@)
1898 char* __cdecl MSVCRT_strchr(const char *str, int c)
1900 return strchr(str, c);
1903 /*********************************************************************
1904 * strrchr (MSVCRT.@)
1906 char* __cdecl MSVCRT_strrchr(const char *str, int c)
1908 return strrchr(str, c);
1911 /*********************************************************************
1912 * memchr (MSVCRT.@)
1914 void* __cdecl MSVCRT_memchr(const void *ptr, int c, MSVCRT_size_t n)
1916 return memchr(ptr, c, n);
1919 /*********************************************************************
1920 * strcmp (MSVCRT.@)
1922 int __cdecl MSVCRT_strcmp(const char *str1, const char *str2)
1924 return strcmp(str1, str2);
1927 /*********************************************************************
1928 * strncmp (MSVCRT.@)
1930 int __cdecl MSVCRT_strncmp(const char *str1, const char *str2, MSVCRT_size_t len)
1932 return strncmp(str1, str2, len);
1935 /*********************************************************************
1936 * _strnicmp_l (MSVCRT.@)
1938 int __cdecl MSVCRT__strnicmp_l(const char *s1, const char *s2,
1939 MSVCRT_size_t count, MSVCRT__locale_t locale)
1941 MSVCRT_pthreadlocinfo locinfo;
1942 int c1, c2;
1944 if(s1==NULL || s2==NULL)
1945 return MSVCRT__NLSCMPERROR;
1947 if(!count)
1948 return 0;
1950 if(!locale)
1951 locinfo = get_locinfo();
1952 else
1953 locinfo = locale->locinfo;
1955 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
1956 return strncasecmp(s1, s2, count);
1958 do {
1959 c1 = MSVCRT__tolower_l(*s1++, locale);
1960 c2 = MSVCRT__tolower_l(*s2++, locale);
1961 }while(--count && c1 && c1==c2);
1963 return c1-c2;
1966 /*********************************************************************
1967 * _stricmp_l (MSVCRT.@)
1969 int __cdecl MSVCRT__stricmp_l(const char *s1, const char *s2, MSVCRT__locale_t locale)
1971 return MSVCRT__strnicmp_l(s1, s2, -1, locale);
1974 /*********************************************************************
1975 * _strnicmp (MSVCRT.@)
1977 int __cdecl MSVCRT__strnicmp(const char *s1, const char *s2, MSVCRT_size_t count)
1979 return MSVCRT__strnicmp_l(s1, s2, count, NULL);
1982 /*********************************************************************
1983 * _stricmp (MSVCRT.@)
1985 int __cdecl MSVCRT__stricmp(const char *s1, const char *s2)
1987 return MSVCRT__strnicmp_l(s1, s2, -1, NULL);
1990 /*********************************************************************
1991 * strstr (MSVCRT.@)
1993 char* __cdecl MSVCRT_strstr(const char *haystack, const char *needle)
1995 return strstr(haystack, needle);
1998 /*********************************************************************
1999 * _memicmp_l (MSVCRT.@)
2001 int __cdecl MSVCRT__memicmp_l(const char *s1, const char *s2, MSVCRT_size_t len, MSVCRT__locale_t locale)
2003 int ret = 0;
2005 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
2006 if (!s1 || !s2)
2008 if (len)
2009 MSVCRT_INVALID_PMT(NULL, EINVAL);
2010 return len ? MSVCRT__NLSCMPERROR : 0;
2012 #endif
2014 while (len--)
2016 if ((ret = MSVCRT__tolower_l(*s1, locale) - MSVCRT__tolower_l(*s2, locale)))
2017 break;
2018 s1++;
2019 s2++;
2021 return ret;
2024 /*********************************************************************
2025 * _memicmp (MSVCRT.@)
2027 int __cdecl MSVCRT__memicmp(const char *s1, const char *s2, MSVCRT_size_t len)
2029 return MSVCRT__memicmp_l(s1, s2, len, NULL);