msvcp140: Implement _Stat and _Lstat.
[wine.git] / dlls / msvcrt / string.c
blob3e765d050d9a743d4d4f96df86c97ea4ab0e297e
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 char *ptr = str;
122 if (!str || !len)
124 *MSVCRT__errno() = MSVCRT_EINVAL;
125 return MSVCRT_EINVAL;
128 while (len && *ptr)
130 len--;
131 ptr++;
134 if (!len)
136 str[0] = '\0';
137 *MSVCRT__errno() = MSVCRT_EINVAL;
138 return MSVCRT_EINVAL;
141 while (*str)
143 *str = MSVCRT__toupper_l((unsigned char)*str, locale);
144 str++;
147 return 0;
150 /*********************************************************************
151 * _strupr_s (MSVCRT.@)
153 int CDECL MSVCRT__strupr_s(char *str, MSVCRT_size_t len)
155 return MSVCRT__strupr_s_l(str, len, NULL);
158 /*********************************************************************
159 * _strupr_l (MSVCRT.@)
161 char* CDECL MSVCRT__strupr_l(char *str, MSVCRT__locale_t locale)
163 MSVCRT__strupr_s_l(str, -1, locale);
164 return str;
167 /*********************************************************************
168 * _strupr (MSVCRT.@)
170 char* CDECL MSVCRT__strupr(char *str)
172 MSVCRT__strupr_s_l(str, -1, NULL);
173 return str;
176 /*********************************************************************
177 * _strnset_s (MSVCRT.@)
179 int CDECL MSVCRT__strnset_s(char *str, MSVCRT_size_t size, int c, MSVCRT_size_t count)
181 MSVCRT_size_t i;
183 if(!str && !size && !count) return 0;
184 if(!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
185 if(!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
187 for(i=0; i<size-1 && i<count; i++) {
188 if(!str[i]) return 0;
189 str[i] = c;
191 for(; i<size; i++)
192 if(!str[i]) return 0;
194 str[0] = 0;
195 MSVCRT__invalid_parameter(NULL, NULL, NULL, 0, 0);
196 *MSVCRT__errno() = MSVCRT_EINVAL;
197 return MSVCRT_EINVAL;
200 /*********************************************************************
201 * _strnset (MSVCRT.@)
203 char* CDECL MSVCRT__strnset(char* str, int value, MSVCRT_size_t len)
205 if (len > 0 && str)
206 while (*str && len--)
207 *str++ = value;
208 return str;
211 /*********************************************************************
212 * _strrev (MSVCRT.@)
214 char* CDECL MSVCRT__strrev(char* str)
216 char * p1;
217 char * p2;
219 if (str && *str)
220 for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
222 *p1 ^= *p2;
223 *p2 ^= *p1;
224 *p1 ^= *p2;
227 return str;
230 /*********************************************************************
231 * _strset (MSVCRT.@)
233 char* CDECL _strset(char* str, int value)
235 char *ptr = str;
236 while (*ptr)
237 *ptr++ = value;
239 return str;
242 /*********************************************************************
243 * strtok (MSVCRT.@)
245 char * CDECL MSVCRT_strtok( char *str, const char *delim )
247 thread_data_t *data = msvcrt_get_thread_data();
248 char *ret;
250 if (!str)
251 if (!(str = data->strtok_next)) return NULL;
253 while (*str && strchr( delim, *str )) str++;
254 if (!*str) return NULL;
255 ret = str++;
256 while (*str && !strchr( delim, *str )) str++;
257 if (*str) *str++ = 0;
258 data->strtok_next = str;
259 return ret;
262 /*********************************************************************
263 * strtok_s (MSVCRT.@)
265 char * CDECL MSVCRT_strtok_s(char *str, const char *delim, char **ctx)
267 if (!MSVCRT_CHECK_PMT(delim != NULL)) return NULL;
268 if (!MSVCRT_CHECK_PMT(ctx != NULL)) return NULL;
269 if (!MSVCRT_CHECK_PMT(str != NULL || *ctx != NULL)) return NULL;
271 if(!str)
272 str = *ctx;
274 while(*str && strchr(delim, *str))
275 str++;
276 if(!*str)
278 *ctx = str;
279 return NULL;
282 *ctx = str+1;
283 while(**ctx && !strchr(delim, **ctx))
284 (*ctx)++;
285 if(**ctx)
286 *(*ctx)++ = 0;
288 return str;
291 /*********************************************************************
292 * _swab (MSVCRT.@)
294 void CDECL MSVCRT__swab(char* src, char* dst, int len)
296 if (len > 1)
298 len = (unsigned)len >> 1;
300 while (len--) {
301 char s0 = src[0];
302 char s1 = src[1];
303 *dst++ = s1;
304 *dst++ = s0;
305 src = src + 2;
310 static double strtod_helper(const char *str, char **end, MSVCRT__locale_t locale, int *err)
312 MSVCRT_pthreadlocinfo locinfo;
313 unsigned __int64 d=0, hlp;
314 unsigned fpcontrol;
315 int exp=0, sign=1;
316 const char *p;
317 double ret;
318 long double lret=1, expcnt = 10;
319 BOOL found_digit = FALSE, negexp;
320 int base = 10;
322 if(err)
323 *err = 0;
324 else if(!MSVCRT_CHECK_PMT(str != NULL)) {
325 if (end)
326 *end = NULL;
327 return 0;
330 if(!locale)
331 locinfo = get_locinfo();
332 else
333 locinfo = locale->locinfo;
335 /* FIXME: use *_l functions */
336 p = str;
337 while(isspace(*p))
338 p++;
340 if(*p == '-') {
341 sign = -1;
342 p++;
343 } else if(*p == '+')
344 p++;
346 #if _MSVCR_VER >= 140
347 if(tolower(p[0]) == 'i' && tolower(p[1]) == 'n' && tolower(p[2]) == 'f') {
348 if(end)
349 *end = (char*) &p[3];
350 if(tolower(p[3]) == 'i' && tolower(p[4]) == 'n' && tolower(p[5]) == 'i' &&
351 tolower(p[6]) == 't' && tolower(p[7]) == 'y' && end)
352 *end = (char*) &p[8];
353 return sign*INFINITY;
355 if(tolower(p[0]) == 'n' &&
356 tolower(p[1]) == 'a' &&
357 tolower(p[2]) == 'n') {
358 if(end)
359 *end = (char*) &p[3];
360 return NAN;
363 if(p[0] == '0' && tolower(p[1]) == 'x') {
364 base = 16;
365 expcnt = 2;
366 p += 2;
368 #endif
370 while((*p>='0' && *p<='9') ||
371 (base == 16 && ((*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))) {
372 char c = *p++;
373 int val;
374 found_digit = TRUE;
375 if (c>='0' && c<='9')
376 val = c - '0';
377 else if (c >= 'a' && c <= 'f')
378 val = 10 + c - 'a';
379 else
380 val = 10 + c - 'A';
381 hlp = d*base+val;
382 if(d>MSVCRT_UI64_MAX/base || hlp<d) {
383 exp++;
384 break;
385 } else
386 d = hlp;
388 while((*p>='0' && *p<='9') ||
389 (base == 16 && ((*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))) {
390 exp++;
391 p++;
394 if(*p == *locinfo->lconv->decimal_point)
395 p++;
397 while((*p>='0' && *p<='9') ||
398 (base == 16 && ((*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F')))) {
399 char c = *p++;
400 int val;
401 found_digit = TRUE;
402 if (c>='0' && c<='9')
403 val = c - '0';
404 else if (c >= 'a' && c <= 'f')
405 val = 10 + c - 'a';
406 else
407 val = 10 + c - 'A';
408 hlp = d*base+val;
409 if(d>MSVCRT_UI64_MAX/base || hlp<d)
410 break;
411 d = hlp;
412 exp--;
414 while((*p>='0' && *p<='9') ||
415 (base == 16 && ((*p >= 'a' && *p <= 'f') || (*p >= 'A' && *p <= 'F'))))
416 p++;
418 if(!found_digit) {
419 if(end)
420 *end = (char*)str;
421 return 0.0;
424 if(base == 16)
425 exp *= 4;
427 if((base == 10 && (*p=='e' || *p=='E' || *p=='d' || *p=='D')) ||
428 (base == 16 && (*p=='p' || *p=='P'))) {
429 int e=0, s=1;
431 p++;
432 if(*p == '-') {
433 s = -1;
434 p++;
435 } else if(*p == '+')
436 p++;
438 if(*p>='0' && *p<='9') {
439 while(*p>='0' && *p<='9') {
440 if(e>INT_MAX/10 || (e=e*10+*p-'0')<0)
441 e = INT_MAX;
442 p++;
444 e *= s;
446 if(exp<0 && e<0 && exp+e>=0) exp = INT_MIN;
447 else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
448 else exp += e;
449 } else {
450 if(*p=='-' || *p=='+')
451 p--;
452 p--;
456 fpcontrol = _control87(0, 0);
457 _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE
458 |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff);
460 negexp = (exp < 0);
461 if(negexp)
462 exp = -exp;
463 while(exp) {
464 if(exp & 1)
465 lret *= expcnt;
466 exp /= 2;
467 expcnt = expcnt*expcnt;
469 ret = (long double)sign * (negexp ? d/lret : d*lret);
471 _control87(fpcontrol, 0xffffffff);
473 if((d && ret==0.0) || isinf(ret)) {
474 if(err)
475 *err = MSVCRT_ERANGE;
476 else
477 *MSVCRT__errno() = MSVCRT_ERANGE;
480 if(end)
481 *end = (char*)p;
483 return ret;
486 /*********************************************************************
487 * strtod_l (MSVCRT.@)
489 double CDECL MSVCRT_strtod_l(const char *str, char **end, MSVCRT__locale_t locale)
491 return strtod_helper(str, end, locale, NULL);
494 /*********************************************************************
495 * strtod (MSVCRT.@)
497 double CDECL MSVCRT_strtod( const char *str, char **end )
499 return MSVCRT_strtod_l( str, end, NULL );
502 /*********************************************************************
503 * strtof_l (MSVCR120.@)
505 float CDECL MSVCRT__strtof_l( const char *str, char **end, MSVCRT__locale_t locale )
507 return MSVCRT_strtod_l(str, end, locale);
510 /*********************************************************************
511 * strtof (MSVCR120.@)
513 float CDECL MSVCRT_strtof( const char *str, char **end )
515 return MSVCRT__strtof_l(str, end, NULL);
518 /*********************************************************************
519 * atof (MSVCRT.@)
521 double CDECL MSVCRT_atof( const char *str )
523 return MSVCRT_strtod_l(str, NULL, NULL);
526 /*********************************************************************
527 * _atof_l (MSVCRT.@)
529 double CDECL MSVCRT__atof_l( const char *str, MSVCRT__locale_t locale)
531 return MSVCRT_strtod_l(str, NULL, locale);
534 /*********************************************************************
535 * _atoflt_l (MSVCRT.@)
537 int CDECL MSVCRT__atoflt_l( MSVCRT__CRT_FLOAT *value, char *str, MSVCRT__locale_t locale)
539 double d;
540 int err;
542 d = strtod_helper(str, NULL, locale, &err);
543 value->f = d;
544 if(isinf(value->f))
545 return MSVCRT__OVERFLOW;
546 if((d!=0 || err) && value->f>-MSVCRT_FLT_MIN && value->f<MSVCRT_FLT_MIN)
547 return MSVCRT__UNDERFLOW;
548 return 0;
551 /*********************************************************************
552 * _atoflt (MSVCR100.@)
554 int CDECL MSVCRT__atoflt(MSVCRT__CRT_FLOAT *value, char *str)
556 return MSVCRT__atoflt_l(value, str, NULL);
559 /*********************************************************************
560 * _atodbl_l (MSVCRT.@)
562 int CDECL MSVCRT__atodbl_l(MSVCRT__CRT_DOUBLE *value, char *str, MSVCRT__locale_t locale)
564 int err;
566 value->x = strtod_helper(str, NULL, locale, &err);
567 if(isinf(value->x))
568 return MSVCRT__OVERFLOW;
569 if((value->x!=0 || err) && value->x>-MSVCRT_DBL_MIN && value->x<MSVCRT_DBL_MIN)
570 return MSVCRT__UNDERFLOW;
571 return 0;
574 /*********************************************************************
575 * _atodbl (MSVCRT.@)
577 int CDECL MSVCRT__atodbl(MSVCRT__CRT_DOUBLE *value, char *str)
579 return MSVCRT__atodbl_l(value, str, NULL);
582 /*********************************************************************
583 * _strcoll_l (MSVCRT.@)
585 int CDECL MSVCRT_strcoll_l( const char* str1, const char* str2, MSVCRT__locale_t locale )
587 MSVCRT_pthreadlocinfo locinfo;
589 if(!locale)
590 locinfo = get_locinfo();
591 else
592 locinfo = locale->locinfo;
594 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
595 return strcmp(str1, str2);
596 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], 0, str1, -1, str2, -1)-CSTR_EQUAL;
599 /*********************************************************************
600 * strcoll (MSVCRT.@)
602 int CDECL MSVCRT_strcoll( const char* str1, const char* str2 )
604 return MSVCRT_strcoll_l(str1, str2, NULL);
607 /*********************************************************************
608 * _stricoll_l (MSVCRT.@)
610 int CDECL MSVCRT__stricoll_l( const char* str1, const char* str2, MSVCRT__locale_t locale )
612 MSVCRT_pthreadlocinfo locinfo;
614 if(!locale)
615 locinfo = get_locinfo();
616 else
617 locinfo = locale->locinfo;
619 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
620 return strcasecmp(str1, str2);
621 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], NORM_IGNORECASE,
622 str1, -1, str2, -1)-CSTR_EQUAL;
625 /*********************************************************************
626 * _stricoll (MSVCRT.@)
628 int CDECL MSVCRT__stricoll( const char* str1, const char* str2 )
630 return MSVCRT__stricoll_l(str1, str2, NULL);
633 /*********************************************************************
634 * _strncoll_l (MSVCRT.@)
636 int CDECL MSVCRT__strncoll_l( const char* str1, const char* str2, MSVCRT_size_t count, MSVCRT__locale_t locale )
638 MSVCRT_pthreadlocinfo locinfo;
640 if(!locale)
641 locinfo = get_locinfo();
642 else
643 locinfo = locale->locinfo;
645 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
646 return strncmp(str1, str2, count);
647 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], 0, str1, count, str2, count)-CSTR_EQUAL;
650 /*********************************************************************
651 * _strncoll (MSVCRT.@)
653 int CDECL MSVCRT__strncoll( const char* str1, const char* str2, MSVCRT_size_t count )
655 return MSVCRT__strncoll_l(str1, str2, count, NULL);
658 /*********************************************************************
659 * _strnicoll_l (MSVCRT.@)
661 int CDECL MSVCRT__strnicoll_l( const char* str1, const char* str2, MSVCRT_size_t count, MSVCRT__locale_t locale )
663 MSVCRT_pthreadlocinfo locinfo;
665 if(!locale)
666 locinfo = get_locinfo();
667 else
668 locinfo = locale->locinfo;
670 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
671 return strncasecmp(str1, str2, count);
672 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], NORM_IGNORECASE,
673 str1, count, str2, count)-CSTR_EQUAL;
676 /*********************************************************************
677 * _strnicoll (MSVCRT.@)
679 int CDECL MSVCRT__strnicoll( const char* str1, const char* str2, MSVCRT_size_t count )
681 return MSVCRT__strnicoll_l(str1, str2, count, NULL);
684 /*********************************************************************
685 * strncpy (MSVCRT.@)
687 char* __cdecl MSVCRT_strncpy(char *dst, const char *src, MSVCRT_size_t len)
689 MSVCRT_size_t i;
691 for(i=0; i<len; i++)
692 if((dst[i] = src[i]) == '\0') break;
694 while (i < len) dst[i++] = 0;
696 return dst;
699 /*********************************************************************
700 * strcpy_s (MSVCRT.@)
702 int CDECL MSVCRT_strcpy_s( char* dst, MSVCRT_size_t elem, const char* src )
704 MSVCRT_size_t i;
705 if(!elem) return MSVCRT_EINVAL;
706 if(!dst) return MSVCRT_EINVAL;
707 if(!src)
709 dst[0] = '\0';
710 return MSVCRT_EINVAL;
713 for(i = 0; i < elem; i++)
715 if((dst[i] = src[i]) == '\0') return 0;
717 dst[0] = '\0';
718 return MSVCRT_ERANGE;
721 /*********************************************************************
722 * strcat_s (MSVCRT.@)
724 int CDECL MSVCRT_strcat_s( char* dst, MSVCRT_size_t elem, const char* src )
726 MSVCRT_size_t i, j;
727 if(!dst) return MSVCRT_EINVAL;
728 if(elem == 0) return MSVCRT_EINVAL;
729 if(!src)
731 dst[0] = '\0';
732 return MSVCRT_EINVAL;
735 for(i = 0; i < elem; i++)
737 if(dst[i] == '\0')
739 for(j = 0; (j + i) < elem; j++)
741 if((dst[j + i] = src[j]) == '\0') return 0;
745 /* Set the first element to 0, not the first element after the skipped part */
746 dst[0] = '\0';
747 return MSVCRT_ERANGE;
750 /*********************************************************************
751 * strncat_s (MSVCRT.@)
753 int CDECL MSVCRT_strncat_s( char* dst, MSVCRT_size_t elem, const char* src, MSVCRT_size_t count )
755 MSVCRT_size_t i, j;
757 if (!MSVCRT_CHECK_PMT(dst != 0)) return MSVCRT_EINVAL;
758 if (!MSVCRT_CHECK_PMT(elem != 0)) return MSVCRT_EINVAL;
759 if (!MSVCRT_CHECK_PMT(src != 0))
761 dst[0] = '\0';
762 return MSVCRT_EINVAL;
765 for(i = 0; i < elem; i++)
767 if(dst[i] == '\0')
769 for(j = 0; (j + i) < elem; j++)
771 if(count == MSVCRT__TRUNCATE && j + i == elem - 1)
773 dst[j + i] = '\0';
774 return MSVCRT_STRUNCATE;
776 if(j == count || (dst[j + i] = src[j]) == '\0')
778 dst[j + i] = '\0';
779 return 0;
784 /* Set the first element to 0, not the first element after the skipped part */
785 dst[0] = '\0';
786 return MSVCRT_ERANGE;
789 /*********************************************************************
790 * strncat (MSVCRT.@)
792 char* __cdecl MSVCRT_strncat(char *dst, const char *src, MSVCRT_size_t len)
794 return strncat(dst, src, len);
797 /*********************************************************************
798 * _strxfrm_l (MSVCRT.@)
800 MSVCRT_size_t CDECL MSVCRT__strxfrm_l( char *dest, const char *src,
801 MSVCRT_size_t len, MSVCRT__locale_t locale )
803 MSVCRT_pthreadlocinfo locinfo;
804 int ret;
806 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
807 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
809 if(len > INT_MAX) {
810 FIXME("len > INT_MAX not supported\n");
811 len = INT_MAX;
814 if(!locale)
815 locinfo = get_locinfo();
816 else
817 locinfo = locale->locinfo;
819 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE]) {
820 MSVCRT_strncpy(dest, src, len);
821 return strlen(src);
824 ret = LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
825 LCMAP_SORTKEY, src, -1, NULL, 0);
826 if(!ret) {
827 if(len) dest[0] = 0;
828 *MSVCRT__errno() = MSVCRT_EILSEQ;
829 return INT_MAX;
831 if(!len) return ret-1;
833 if(ret > len) {
834 dest[0] = 0;
835 *MSVCRT__errno() = MSVCRT_ERANGE;
836 return ret-1;
839 return LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
840 LCMAP_SORTKEY, src, -1, dest, len) - 1;
843 /*********************************************************************
844 * strxfrm (MSVCRT.@)
846 MSVCRT_size_t CDECL MSVCRT_strxfrm( char *dest, const char *src, MSVCRT_size_t len )
848 return MSVCRT__strxfrm_l(dest, src, len, NULL);
851 /********************************************************************
852 * _atoldbl (MSVCRT.@)
854 int CDECL MSVCRT__atoldbl(MSVCRT__LDOUBLE *value, const char *str)
856 /* FIXME needs error checking for huge/small values */
857 #ifdef HAVE_STRTOLD
858 long double ld;
859 TRACE("str %s value %p\n",str,value);
860 ld = strtold(str,0);
861 memcpy(value, &ld, 10);
862 #else
863 FIXME("stub, str %s value %p\n",str,value);
864 #endif
865 return 0;
868 /********************************************************************
869 * __STRINGTOLD (MSVCRT.@)
871 int CDECL __STRINGTOLD( MSVCRT__LDOUBLE *value, char **endptr, const char *str, int flags )
873 #ifdef HAVE_STRTOLD
874 long double ld;
875 FIXME("%p %p %s %x partial stub\n", value, endptr, str, flags );
876 ld = strtold(str,0);
877 memcpy(value, &ld, 10);
878 #else
879 FIXME("%p %p %s %x stub\n", value, endptr, str, flags );
880 #endif
881 return 0;
884 /*********************************************************************
885 * strlen (MSVCRT.@)
887 MSVCRT_size_t __cdecl MSVCRT_strlen(const char *str)
889 return strlen(str);
892 /******************************************************************
893 * strnlen (MSVCRT.@)
895 MSVCRT_size_t CDECL MSVCRT_strnlen(const char *s, MSVCRT_size_t maxlen)
897 MSVCRT_size_t i;
899 for(i=0; i<maxlen; i++)
900 if(!s[i]) break;
902 return i;
905 /*********************************************************************
906 * _strtoi64_l (MSVCRT.@)
908 * FIXME: locale parameter is ignored
910 __int64 CDECL MSVCRT_strtoi64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
912 const char *p = nptr;
913 BOOL negative = FALSE;
914 BOOL got_digit = FALSE;
915 __int64 ret = 0;
917 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
919 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
920 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
921 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
923 while(isspace(*nptr)) nptr++;
925 if(*nptr == '-') {
926 negative = TRUE;
927 nptr++;
928 } else if(*nptr == '+')
929 nptr++;
931 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
932 base = 16;
933 nptr += 2;
936 if(base == 0) {
937 if(*nptr=='0')
938 base = 8;
939 else
940 base = 10;
943 while(*nptr) {
944 char cur = tolower(*nptr);
945 int v;
947 if(cur>='0' && cur<='9') {
948 if(cur >= '0'+base)
949 break;
950 v = cur-'0';
951 } else {
952 if(cur<'a' || cur>='a'+base-10)
953 break;
954 v = cur-'a'+10;
956 got_digit = TRUE;
958 if(negative)
959 v = -v;
961 nptr++;
963 if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
964 ret = MSVCRT_I64_MAX;
965 *MSVCRT__errno() = MSVCRT_ERANGE;
966 } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
967 ret = MSVCRT_I64_MIN;
968 *MSVCRT__errno() = MSVCRT_ERANGE;
969 } else
970 ret = ret*base + v;
973 if(endptr)
974 *endptr = (char*)(got_digit ? nptr : p);
976 return ret;
979 /*********************************************************************
980 * _strtoi64 (MSVCRT.@)
982 __int64 CDECL MSVCRT_strtoi64(const char *nptr, char **endptr, int base)
984 return MSVCRT_strtoi64_l(nptr, endptr, base, NULL);
987 /*********************************************************************
988 * _atoi_l (MSVCRT.@)
990 int __cdecl MSVCRT__atoi_l(const char *str, MSVCRT__locale_t locale)
992 __int64 ret = MSVCRT_strtoi64_l(str, NULL, 10, locale);
994 if(ret > INT_MAX) {
995 ret = INT_MAX;
996 *MSVCRT__errno() = MSVCRT_ERANGE;
997 } else if(ret < INT_MIN) {
998 ret = INT_MIN;
999 *MSVCRT__errno() = MSVCRT_ERANGE;
1001 return ret;
1004 /*********************************************************************
1005 * atoi (MSVCRT.@)
1007 #if _MSVCR_VER == 0
1008 int __cdecl MSVCRT_atoi(const char *str)
1010 BOOL minus = FALSE;
1011 int ret = 0;
1013 if(!str)
1014 return 0;
1016 while(isspace(*str)) str++;
1018 if(*str == '+') {
1019 str++;
1020 }else if(*str == '-') {
1021 minus = TRUE;
1022 str++;
1025 while(*str>='0' && *str<='9') {
1026 ret = ret*10+*str-'0';
1027 str++;
1030 return minus ? -ret : ret;
1032 #else
1033 int CDECL MSVCRT_atoi(const char *str)
1035 return MSVCRT__atoi_l(str, NULL);
1037 #endif
1039 /******************************************************************
1040 * _atoll_l (MSVCR120.@)
1042 MSVCRT_longlong CDECL MSVCRT__atoll_l(const char* str, MSVCRT__locale_t locale)
1044 return MSVCRT_strtoi64_l(str, NULL, 10, locale);
1047 /******************************************************************
1048 * atoll (MSVCR120.@)
1050 MSVCRT_longlong CDECL MSVCRT_atoll(const char* str)
1052 return MSVCRT__atoll_l(str, NULL);
1055 /******************************************************************
1056 * _strtol_l (MSVCRT.@)
1058 MSVCRT_long CDECL MSVCRT__strtol_l(const char* nptr,
1059 char** end, int base, MSVCRT__locale_t locale)
1061 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1063 if(ret > MSVCRT_LONG_MAX) {
1064 ret = MSVCRT_LONG_MAX;
1065 *MSVCRT__errno() = MSVCRT_ERANGE;
1066 } else if(ret < MSVCRT_LONG_MIN) {
1067 ret = MSVCRT_LONG_MIN;
1068 *MSVCRT__errno() = MSVCRT_ERANGE;
1071 return ret;
1074 /******************************************************************
1075 * strtol (MSVCRT.@)
1077 MSVCRT_long CDECL MSVCRT_strtol(const char* nptr, char** end, int base)
1079 return MSVCRT__strtol_l(nptr, end, base, NULL);
1082 /******************************************************************
1083 * _strtoul_l (MSVCRT.@)
1085 MSVCRT_ulong CDECL MSVCRT_strtoul_l(const char* nptr, char** end, int base, MSVCRT__locale_t locale)
1087 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1089 if(ret > MSVCRT_ULONG_MAX) {
1090 ret = MSVCRT_ULONG_MAX;
1091 *MSVCRT__errno() = MSVCRT_ERANGE;
1092 }else if(ret < -(__int64)MSVCRT_ULONG_MAX) {
1093 ret = 1;
1094 *MSVCRT__errno() = MSVCRT_ERANGE;
1097 return ret;
1100 /******************************************************************
1101 * strtoul (MSVCRT.@)
1103 MSVCRT_ulong CDECL MSVCRT_strtoul(const char* nptr, char** end, int base)
1105 return MSVCRT_strtoul_l(nptr, end, base, NULL);
1108 /*********************************************************************
1109 * _strtoui64_l (MSVCRT.@)
1111 * FIXME: locale parameter is ignored
1113 unsigned __int64 CDECL MSVCRT_strtoui64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
1115 const char *p = nptr;
1116 BOOL negative = FALSE;
1117 BOOL got_digit = FALSE;
1118 unsigned __int64 ret = 0;
1120 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1122 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1123 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1124 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1126 while(isspace(*nptr)) nptr++;
1128 if(*nptr == '-') {
1129 negative = TRUE;
1130 nptr++;
1131 } else if(*nptr == '+')
1132 nptr++;
1134 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
1135 base = 16;
1136 nptr += 2;
1139 if(base == 0) {
1140 if(*nptr=='0')
1141 base = 8;
1142 else
1143 base = 10;
1146 while(*nptr) {
1147 char cur = tolower(*nptr);
1148 int v;
1150 if(cur>='0' && cur<='9') {
1151 if(cur >= '0'+base)
1152 break;
1153 v = *nptr-'0';
1154 } else {
1155 if(cur<'a' || cur>='a'+base-10)
1156 break;
1157 v = cur-'a'+10;
1159 got_digit = TRUE;
1161 nptr++;
1163 if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1164 ret = MSVCRT_UI64_MAX;
1165 *MSVCRT__errno() = MSVCRT_ERANGE;
1166 } else
1167 ret = ret*base + v;
1170 if(endptr)
1171 *endptr = (char*)(got_digit ? nptr : p);
1173 return negative ? -ret : ret;
1176 /*********************************************************************
1177 * _strtoui64 (MSVCRT.@)
1179 unsigned __int64 CDECL MSVCRT_strtoui64(const char *nptr, char **endptr, int base)
1181 return MSVCRT_strtoui64_l(nptr, endptr, base, NULL);
1184 static int ltoa_helper(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1186 MSVCRT_ulong val;
1187 unsigned int digit;
1188 BOOL is_negative;
1189 char buffer[33], *pos;
1190 size_t len;
1192 if (value < 0 && radix == 10)
1194 is_negative = TRUE;
1195 val = -value;
1197 else
1199 is_negative = FALSE;
1200 val = value;
1203 pos = buffer + 32;
1204 *pos = '\0';
1208 digit = val % radix;
1209 val /= radix;
1211 if (digit < 10)
1212 *--pos = '0' + digit;
1213 else
1214 *--pos = 'a' + digit - 10;
1216 while (val != 0);
1218 if (is_negative)
1219 *--pos = '-';
1221 len = buffer + 33 - pos;
1222 if (len > size)
1224 size_t i;
1225 char *p = str;
1227 /* Copy the temporary buffer backwards up to the available number of
1228 * characters. Don't copy the negative sign if present. */
1230 if (is_negative)
1232 p++;
1233 size--;
1236 for (pos = buffer + 31, i = 0; i < size; i++)
1237 *p++ = *pos--;
1239 str[0] = '\0';
1240 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1241 return MSVCRT_ERANGE;
1244 memcpy(str, pos, len);
1245 return 0;
1248 /*********************************************************************
1249 * _ltoa_s (MSVCRT.@)
1251 int CDECL MSVCRT__ltoa_s(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1253 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1254 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1255 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1257 str[0] = '\0';
1258 return MSVCRT_EINVAL;
1261 return ltoa_helper(value, str, size, radix);
1264 /*********************************************************************
1265 * _ltow_s (MSVCRT.@)
1267 int CDECL MSVCRT__ltow_s(MSVCRT_long value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1269 MSVCRT_ulong val;
1270 unsigned int digit;
1271 BOOL is_negative;
1272 MSVCRT_wchar_t buffer[33], *pos;
1273 size_t len;
1275 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1276 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1277 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1279 str[0] = '\0';
1280 return MSVCRT_EINVAL;
1283 if (value < 0 && radix == 10)
1285 is_negative = TRUE;
1286 val = -value;
1288 else
1290 is_negative = FALSE;
1291 val = value;
1294 pos = buffer + 32;
1295 *pos = '\0';
1299 digit = val % radix;
1300 val /= radix;
1302 if (digit < 10)
1303 *--pos = '0' + digit;
1304 else
1305 *--pos = 'a' + digit - 10;
1307 while (val != 0);
1309 if (is_negative)
1310 *--pos = '-';
1312 len = buffer + 33 - pos;
1313 if (len > size)
1315 size_t i;
1316 MSVCRT_wchar_t *p = str;
1318 /* Copy the temporary buffer backwards up to the available number of
1319 * characters. Don't copy the negative sign if present. */
1321 if (is_negative)
1323 p++;
1324 size--;
1327 for (pos = buffer + 31, i = 0; i < size; i++)
1328 *p++ = *pos--;
1330 str[0] = '\0';
1331 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1332 return MSVCRT_ERANGE;
1335 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1336 return 0;
1339 /*********************************************************************
1340 * _itoa_s (MSVCRT.@)
1342 int CDECL MSVCRT__itoa_s(int value, char *str, MSVCRT_size_t size, int radix)
1344 return MSVCRT__ltoa_s(value, str, size, radix);
1347 /*********************************************************************
1348 * _itoa (MSVCRT.@)
1350 char* CDECL MSVCRT__itoa(int value, char *str, int radix)
1352 return ltoa_helper(value, str, MSVCRT_SIZE_MAX, radix) ? NULL : str;
1355 /*********************************************************************
1356 * _itow_s (MSVCRT.@)
1358 int CDECL MSVCRT__itow_s(int value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1360 return MSVCRT__ltow_s(value, str, size, radix);
1363 /*********************************************************************
1364 * _ui64toa_s (MSVCRT.@)
1366 int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str,
1367 MSVCRT_size_t size, int radix)
1369 char buffer[65], *pos;
1370 int digit;
1372 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1373 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1374 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1376 str[0] = '\0';
1377 return MSVCRT_EINVAL;
1380 pos = buffer+64;
1381 *pos = '\0';
1383 do {
1384 digit = value%radix;
1385 value /= radix;
1387 if(digit < 10)
1388 *--pos = '0'+digit;
1389 else
1390 *--pos = 'a'+digit-10;
1391 }while(value != 0);
1393 if(buffer-pos+65 > size) {
1394 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1395 return MSVCRT_EINVAL;
1398 memcpy(str, pos, buffer-pos+65);
1399 return 0;
1402 /*********************************************************************
1403 * _ui64tow_s (MSVCRT.@)
1405 int CDECL MSVCRT__ui64tow_s( unsigned __int64 value, MSVCRT_wchar_t *str,
1406 MSVCRT_size_t size, int radix )
1408 MSVCRT_wchar_t buffer[65], *pos;
1409 int digit;
1411 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1412 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1413 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1415 str[0] = '\0';
1416 return MSVCRT_EINVAL;
1419 pos = &buffer[64];
1420 *pos = '\0';
1422 do {
1423 digit = value % radix;
1424 value = value / radix;
1425 if (digit < 10)
1426 *--pos = '0' + digit;
1427 else
1428 *--pos = 'a' + digit - 10;
1429 } while (value != 0);
1431 if(buffer-pos+65 > size) {
1432 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1433 return MSVCRT_EINVAL;
1436 memcpy(str, pos, (buffer-pos+65)*sizeof(MSVCRT_wchar_t));
1437 return 0;
1440 /*********************************************************************
1441 * _ultoa_s (MSVCRT.@)
1443 int CDECL MSVCRT__ultoa_s(MSVCRT_ulong value, char *str, MSVCRT_size_t size, int radix)
1445 MSVCRT_ulong digit;
1446 char buffer[33], *pos;
1447 size_t len;
1449 if (!str || !size || radix < 2 || radix > 36)
1451 if (str && size)
1452 str[0] = '\0';
1454 *MSVCRT__errno() = MSVCRT_EINVAL;
1455 return MSVCRT_EINVAL;
1458 pos = buffer + 32;
1459 *pos = '\0';
1463 digit = value % radix;
1464 value /= radix;
1466 if (digit < 10)
1467 *--pos = '0' + digit;
1468 else
1469 *--pos = 'a' + digit - 10;
1471 while (value != 0);
1473 len = buffer + 33 - pos;
1474 if (len > size)
1476 size_t i;
1477 char *p = str;
1479 /* Copy the temporary buffer backwards up to the available number of
1480 * characters. */
1482 for (pos = buffer + 31, i = 0; i < size; i++)
1483 *p++ = *pos--;
1485 str[0] = '\0';
1486 *MSVCRT__errno() = MSVCRT_ERANGE;
1487 return MSVCRT_ERANGE;
1490 memcpy(str, pos, len);
1491 return 0;
1494 /*********************************************************************
1495 * _ultow_s (MSVCRT.@)
1497 int CDECL MSVCRT__ultow_s(MSVCRT_ulong value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1499 MSVCRT_ulong digit;
1500 WCHAR buffer[33], *pos;
1501 size_t len;
1503 if (!str || !size || radix < 2 || radix > 36)
1505 if (str && size)
1506 str[0] = '\0';
1508 *MSVCRT__errno() = MSVCRT_EINVAL;
1509 return MSVCRT_EINVAL;
1512 pos = buffer + 32;
1513 *pos = '\0';
1517 digit = value % radix;
1518 value /= radix;
1520 if (digit < 10)
1521 *--pos = '0' + digit;
1522 else
1523 *--pos = 'a' + digit - 10;
1525 while (value != 0);
1527 len = buffer + 33 - pos;
1528 if (len > size)
1530 size_t i;
1531 WCHAR *p = str;
1533 /* Copy the temporary buffer backwards up to the available number of
1534 * characters. */
1536 for (pos = buffer + 31, i = 0; i < size; i++)
1537 *p++ = *pos--;
1539 str[0] = '\0';
1540 *MSVCRT__errno() = MSVCRT_ERANGE;
1541 return MSVCRT_ERANGE;
1544 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1545 return 0;
1548 /*********************************************************************
1549 * _i64toa_s (MSVCRT.@)
1551 int CDECL MSVCRT__i64toa_s(__int64 value, char *str, MSVCRT_size_t size, int radix)
1553 unsigned __int64 val;
1554 unsigned int digit;
1555 BOOL is_negative;
1556 char buffer[65], *pos;
1557 size_t len;
1559 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1560 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1561 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1563 str[0] = '\0';
1564 return MSVCRT_EINVAL;
1567 if (value < 0 && radix == 10)
1569 is_negative = TRUE;
1570 val = -value;
1572 else
1574 is_negative = FALSE;
1575 val = value;
1578 pos = buffer + 64;
1579 *pos = '\0';
1583 digit = val % radix;
1584 val /= radix;
1586 if (digit < 10)
1587 *--pos = '0' + digit;
1588 else
1589 *--pos = 'a' + digit - 10;
1591 while (val != 0);
1593 if (is_negative)
1594 *--pos = '-';
1596 len = buffer + 65 - pos;
1597 if (len > size)
1599 size_t i;
1600 char *p = str;
1602 /* Copy the temporary buffer backwards up to the available number of
1603 * characters. Don't copy the negative sign if present. */
1605 if (is_negative)
1607 p++;
1608 size--;
1611 for (pos = buffer + 63, i = 0; i < size; i++)
1612 *p++ = *pos--;
1614 str[0] = '\0';
1615 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1616 return MSVCRT_ERANGE;
1619 memcpy(str, pos, len);
1620 return 0;
1623 /*********************************************************************
1624 * _i64tow_s (MSVCRT.@)
1626 int CDECL MSVCRT__i64tow_s(__int64 value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1628 unsigned __int64 val;
1629 unsigned int digit;
1630 BOOL is_negative;
1631 MSVCRT_wchar_t buffer[65], *pos;
1632 size_t len;
1634 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1635 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1636 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1638 str[0] = '\0';
1639 return MSVCRT_EINVAL;
1642 if (value < 0 && radix == 10)
1644 is_negative = TRUE;
1645 val = -value;
1647 else
1649 is_negative = FALSE;
1650 val = value;
1653 pos = buffer + 64;
1654 *pos = '\0';
1658 digit = val % radix;
1659 val /= radix;
1661 if (digit < 10)
1662 *--pos = '0' + digit;
1663 else
1664 *--pos = 'a' + digit - 10;
1666 while (val != 0);
1668 if (is_negative)
1669 *--pos = '-';
1671 len = buffer + 65 - pos;
1672 if (len > size)
1674 size_t i;
1675 MSVCRT_wchar_t *p = str;
1677 /* Copy the temporary buffer backwards up to the available number of
1678 * characters. Don't copy the negative sign if present. */
1680 if (is_negative)
1682 p++;
1683 size--;
1686 for (pos = buffer + 63, i = 0; i < size; i++)
1687 *p++ = *pos--;
1689 str[0] = '\0';
1690 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1691 return MSVCRT_ERANGE;
1694 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1695 return 0;
1698 #define I10_OUTPUT_MAX_PREC 21
1699 /* Internal structure used by $I10_OUTPUT */
1700 struct _I10_OUTPUT_DATA {
1701 short pos;
1702 char sign;
1703 BYTE len;
1704 char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */
1707 /*********************************************************************
1708 * $I10_OUTPUT (MSVCRT.@)
1709 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
1710 * prec - precision of part, we're interested in
1711 * flag - 0 for first prec digits, 1 for fractional part
1712 * data - data to be populated
1714 * return value
1715 * 0 if given double is NaN or INF
1716 * 1 otherwise
1718 * FIXME
1719 * Native sets last byte of data->str to '0' or '9', I don't know what
1720 * it means. Current implementation sets it always to '0'.
1722 int CDECL MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data)
1724 static const char inf_str[] = "1#INF";
1725 static const char nan_str[] = "1#QNAN";
1727 /* MS' long double type wants 12 bytes for Intel's 80 bit FP format.
1728 * Some UNIX have sizeof(long double) == 16, yet only 80 bit are used.
1729 * Assume long double uses 80 bit FP, never seen 128 bit FP. */
1730 long double ld = 0;
1731 double d;
1732 char format[8];
1733 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
1734 char *p;
1736 memcpy(&ld, &ld80, 10);
1737 d = ld;
1738 TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
1740 if(d<0) {
1741 data->sign = '-';
1742 d = -d;
1743 } else
1744 data->sign = ' ';
1746 if(isinf(d)) {
1747 data->pos = 1;
1748 data->len = 5;
1749 memcpy(data->str, inf_str, sizeof(inf_str));
1751 return 0;
1754 if(isnan(d)) {
1755 data->pos = 1;
1756 data->len = 6;
1757 memcpy(data->str, nan_str, sizeof(nan_str));
1759 return 0;
1762 if(flag&1) {
1763 int exp = 1+floor(log10(d));
1765 prec += exp;
1766 if(exp < 0)
1767 prec--;
1769 prec--;
1771 if(prec+1 > I10_OUTPUT_MAX_PREC)
1772 prec = I10_OUTPUT_MAX_PREC-1;
1773 else if(prec < 0) {
1774 d = 0.0;
1775 prec = 0;
1778 sprintf(format, "%%.%dle", prec);
1779 sprintf(buf, format, d);
1781 buf[1] = buf[0];
1782 data->pos = atoi(buf+prec+3);
1783 if(buf[1] != '0')
1784 data->pos++;
1786 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
1787 data->len = p-buf;
1789 memcpy(data->str, buf+1, data->len);
1790 data->str[data->len] = '\0';
1792 if(buf[1]!='0' && prec-data->len+1>0)
1793 memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1);
1795 return 1;
1797 #undef I10_OUTPUT_MAX_PREC
1799 /*********************************************************************
1800 * memcmp (MSVCRT.@)
1802 int __cdecl MSVCRT_memcmp(const void *ptr1, const void *ptr2, MSVCRT_size_t n)
1804 return memcmp(ptr1, ptr2, n);
1807 /*********************************************************************
1808 * memcpy (MSVCRT.@)
1810 void * __cdecl MSVCRT_memcpy(void *dst, const void *src, MSVCRT_size_t n)
1812 return memmove(dst, src, n);
1815 /*********************************************************************
1816 * memmove (MSVCRT.@)
1818 void * __cdecl MSVCRT_memmove(void *dst, const void *src, MSVCRT_size_t n)
1820 return memmove(dst, src, n);
1823 /*********************************************************************
1824 * memset (MSVCRT.@)
1826 void* __cdecl MSVCRT_memset(void *dst, int c, MSVCRT_size_t n)
1828 return memset(dst, c, n);
1831 /*********************************************************************
1832 * strchr (MSVCRT.@)
1834 char* __cdecl MSVCRT_strchr(const char *str, int c)
1836 return strchr(str, c);
1839 /*********************************************************************
1840 * strrchr (MSVCRT.@)
1842 char* __cdecl MSVCRT_strrchr(const char *str, int c)
1844 return strrchr(str, c);
1847 /*********************************************************************
1848 * memchr (MSVCRT.@)
1850 void* __cdecl MSVCRT_memchr(const void *ptr, int c, MSVCRT_size_t n)
1852 return memchr(ptr, c, n);
1855 /*********************************************************************
1856 * strcmp (MSVCRT.@)
1858 int __cdecl MSVCRT_strcmp(const char *str1, const char *str2)
1860 return strcmp(str1, str2);
1863 /*********************************************************************
1864 * strncmp (MSVCRT.@)
1866 int __cdecl MSVCRT_strncmp(const char *str1, const char *str2, MSVCRT_size_t len)
1868 return strncmp(str1, str2, len);
1871 /*********************************************************************
1872 * _strnicmp_l (MSVCRT.@)
1874 int __cdecl MSVCRT__strnicmp_l(const char *s1, const char *s2,
1875 MSVCRT_size_t count, MSVCRT__locale_t locale)
1877 MSVCRT_pthreadlocinfo locinfo;
1878 int c1, c2;
1880 if(s1==NULL || s2==NULL)
1881 return MSVCRT__NLSCMPERROR;
1883 if(!count)
1884 return 0;
1886 if(!locale)
1887 locinfo = get_locinfo();
1888 else
1889 locinfo = locale->locinfo;
1891 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
1892 return strncasecmp(s1, s2, count);
1894 do {
1895 c1 = MSVCRT__tolower_l(*s1++, locale);
1896 c2 = MSVCRT__tolower_l(*s2++, locale);
1897 }while(--count && c1 && c1==c2);
1899 return c1-c2;
1902 /*********************************************************************
1903 * _stricmp_l (MSVCRT.@)
1905 int __cdecl MSVCRT__stricmp_l(const char *s1, const char *s2, MSVCRT__locale_t locale)
1907 return MSVCRT__strnicmp_l(s1, s2, -1, locale);
1910 /*********************************************************************
1911 * _strnicmp (MSVCRT.@)
1913 int __cdecl MSVCRT__strnicmp(const char *s1, const char *s2, MSVCRT_size_t count)
1915 return MSVCRT__strnicmp_l(s1, s2, count, NULL);
1918 /*********************************************************************
1919 * _stricmp (MSVCRT.@)
1921 int __cdecl MSVCRT__stricmp(const char *s1, const char *s2)
1923 return MSVCRT__strnicmp_l(s1, s2, -1, NULL);
1926 /*********************************************************************
1927 * strstr (MSVCRT.@)
1929 char* __cdecl MSVCRT_strstr(const char *haystack, const char *needle)
1931 return strstr(haystack, needle);