po: Update German translation.
[wine.git] / dlls / msvcrt / string.c
blob8d6b48ccec777ae0398e98ea71b2338252f25ea3
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 (MSVCRT.@)
702 char* CDECL MSVCRT_strcpy(char *dst, const char *src)
704 char *ret = dst;
705 while ((*dst++ = *src++));
706 return ret;
709 /*********************************************************************
710 * strcpy_s (MSVCRT.@)
712 int CDECL MSVCRT_strcpy_s( char* dst, MSVCRT_size_t elem, const char* src )
714 MSVCRT_size_t i;
715 if(!elem) return MSVCRT_EINVAL;
716 if(!dst) return MSVCRT_EINVAL;
717 if(!src)
719 dst[0] = '\0';
720 return MSVCRT_EINVAL;
723 for(i = 0; i < elem; i++)
725 if((dst[i] = src[i]) == '\0') return 0;
727 dst[0] = '\0';
728 return MSVCRT_ERANGE;
731 /*********************************************************************
732 * strcat_s (MSVCRT.@)
734 int CDECL MSVCRT_strcat_s( char* dst, MSVCRT_size_t elem, const char* src )
736 MSVCRT_size_t i, j;
737 if(!dst) return MSVCRT_EINVAL;
738 if(elem == 0) return MSVCRT_EINVAL;
739 if(!src)
741 dst[0] = '\0';
742 return MSVCRT_EINVAL;
745 for(i = 0; i < elem; i++)
747 if(dst[i] == '\0')
749 for(j = 0; (j + i) < elem; j++)
751 if((dst[j + i] = src[j]) == '\0') return 0;
755 /* Set the first element to 0, not the first element after the skipped part */
756 dst[0] = '\0';
757 return MSVCRT_ERANGE;
760 /*********************************************************************
761 * strncat_s (MSVCRT.@)
763 int CDECL MSVCRT_strncat_s( char* dst, MSVCRT_size_t elem, const char* src, MSVCRT_size_t count )
765 MSVCRT_size_t i, j;
767 if (!MSVCRT_CHECK_PMT(dst != 0)) return MSVCRT_EINVAL;
768 if (!MSVCRT_CHECK_PMT(elem != 0)) return MSVCRT_EINVAL;
769 if (!MSVCRT_CHECK_PMT(src != 0))
771 dst[0] = '\0';
772 return MSVCRT_EINVAL;
775 for(i = 0; i < elem; i++)
777 if(dst[i] == '\0')
779 for(j = 0; (j + i) < elem; j++)
781 if(count == MSVCRT__TRUNCATE && j + i == elem - 1)
783 dst[j + i] = '\0';
784 return MSVCRT_STRUNCATE;
786 if(j == count || (dst[j + i] = src[j]) == '\0')
788 dst[j + i] = '\0';
789 return 0;
794 /* Set the first element to 0, not the first element after the skipped part */
795 dst[0] = '\0';
796 return MSVCRT_ERANGE;
799 /*********************************************************************
800 * strncat (MSVCRT.@)
802 char* __cdecl MSVCRT_strncat(char *dst, const char *src, MSVCRT_size_t len)
804 return strncat(dst, src, len);
807 /*********************************************************************
808 * _strxfrm_l (MSVCRT.@)
810 MSVCRT_size_t CDECL MSVCRT__strxfrm_l( char *dest, const char *src,
811 MSVCRT_size_t len, MSVCRT__locale_t locale )
813 MSVCRT_pthreadlocinfo locinfo;
814 int ret;
816 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
817 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
819 if(len > INT_MAX) {
820 FIXME("len > INT_MAX not supported\n");
821 len = INT_MAX;
824 if(!locale)
825 locinfo = get_locinfo();
826 else
827 locinfo = locale->locinfo;
829 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE]) {
830 MSVCRT_strncpy(dest, src, len);
831 return strlen(src);
834 ret = LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
835 LCMAP_SORTKEY, src, -1, NULL, 0);
836 if(!ret) {
837 if(len) dest[0] = 0;
838 *MSVCRT__errno() = MSVCRT_EILSEQ;
839 return INT_MAX;
841 if(!len) return ret-1;
843 if(ret > len) {
844 dest[0] = 0;
845 *MSVCRT__errno() = MSVCRT_ERANGE;
846 return ret-1;
849 return LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
850 LCMAP_SORTKEY, src, -1, dest, len) - 1;
853 /*********************************************************************
854 * strxfrm (MSVCRT.@)
856 MSVCRT_size_t CDECL MSVCRT_strxfrm( char *dest, const char *src, MSVCRT_size_t len )
858 return MSVCRT__strxfrm_l(dest, src, len, NULL);
861 /********************************************************************
862 * _atoldbl (MSVCRT.@)
864 int CDECL MSVCRT__atoldbl(MSVCRT__LDOUBLE *value, const char *str)
866 /* FIXME needs error checking for huge/small values */
867 #ifdef HAVE_STRTOLD
868 long double ld;
869 TRACE("str %s value %p\n",str,value);
870 ld = strtold(str,0);
871 memcpy(value, &ld, 10);
872 #else
873 FIXME("stub, str %s value %p\n",str,value);
874 #endif
875 return 0;
878 /********************************************************************
879 * __STRINGTOLD (MSVCRT.@)
881 int CDECL __STRINGTOLD( MSVCRT__LDOUBLE *value, char **endptr, const char *str, int flags )
883 #ifdef HAVE_STRTOLD
884 long double ld;
885 FIXME("%p %p %s %x partial stub\n", value, endptr, str, flags );
886 ld = strtold(str,0);
887 memcpy(value, &ld, 10);
888 #else
889 FIXME("%p %p %s %x stub\n", value, endptr, str, flags );
890 #endif
891 return 0;
894 /*********************************************************************
895 * strlen (MSVCRT.@)
897 MSVCRT_size_t __cdecl MSVCRT_strlen(const char *str)
899 return strlen(str);
902 /******************************************************************
903 * strnlen (MSVCRT.@)
905 MSVCRT_size_t CDECL MSVCRT_strnlen(const char *s, MSVCRT_size_t maxlen)
907 MSVCRT_size_t i;
909 for(i=0; i<maxlen; i++)
910 if(!s[i]) break;
912 return i;
915 /*********************************************************************
916 * _strtoi64_l (MSVCRT.@)
918 * FIXME: locale parameter is ignored
920 __int64 CDECL MSVCRT_strtoi64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
922 const char *p = nptr;
923 BOOL negative = FALSE;
924 BOOL got_digit = FALSE;
925 __int64 ret = 0;
927 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
929 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
930 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
931 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
933 while(isspace(*nptr)) nptr++;
935 if(*nptr == '-') {
936 negative = TRUE;
937 nptr++;
938 } else if(*nptr == '+')
939 nptr++;
941 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
942 base = 16;
943 nptr += 2;
946 if(base == 0) {
947 if(*nptr=='0')
948 base = 8;
949 else
950 base = 10;
953 while(*nptr) {
954 char cur = tolower(*nptr);
955 int v;
957 if(cur>='0' && cur<='9') {
958 if(cur >= '0'+base)
959 break;
960 v = cur-'0';
961 } else {
962 if(cur<'a' || cur>='a'+base-10)
963 break;
964 v = cur-'a'+10;
966 got_digit = TRUE;
968 if(negative)
969 v = -v;
971 nptr++;
973 if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
974 ret = MSVCRT_I64_MAX;
975 *MSVCRT__errno() = MSVCRT_ERANGE;
976 } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
977 ret = MSVCRT_I64_MIN;
978 *MSVCRT__errno() = MSVCRT_ERANGE;
979 } else
980 ret = ret*base + v;
983 if(endptr)
984 *endptr = (char*)(got_digit ? nptr : p);
986 return ret;
989 /*********************************************************************
990 * _strtoi64 (MSVCRT.@)
992 __int64 CDECL MSVCRT_strtoi64(const char *nptr, char **endptr, int base)
994 return MSVCRT_strtoi64_l(nptr, endptr, base, NULL);
997 /*********************************************************************
998 * _atoi_l (MSVCRT.@)
1000 int __cdecl MSVCRT__atoi_l(const char *str, MSVCRT__locale_t locale)
1002 __int64 ret = MSVCRT_strtoi64_l(str, NULL, 10, locale);
1004 if(ret > INT_MAX) {
1005 ret = INT_MAX;
1006 *MSVCRT__errno() = MSVCRT_ERANGE;
1007 } else if(ret < INT_MIN) {
1008 ret = INT_MIN;
1009 *MSVCRT__errno() = MSVCRT_ERANGE;
1011 return ret;
1014 /*********************************************************************
1015 * atoi (MSVCRT.@)
1017 #if _MSVCR_VER == 0
1018 int __cdecl MSVCRT_atoi(const char *str)
1020 BOOL minus = FALSE;
1021 int ret = 0;
1023 if(!str)
1024 return 0;
1026 while(isspace(*str)) str++;
1028 if(*str == '+') {
1029 str++;
1030 }else if(*str == '-') {
1031 minus = TRUE;
1032 str++;
1035 while(*str>='0' && *str<='9') {
1036 ret = ret*10+*str-'0';
1037 str++;
1040 return minus ? -ret : ret;
1042 #else
1043 int CDECL MSVCRT_atoi(const char *str)
1045 return MSVCRT__atoi_l(str, NULL);
1047 #endif
1049 /******************************************************************
1050 * _atoll_l (MSVCR120.@)
1052 MSVCRT_longlong CDECL MSVCRT__atoll_l(const char* str, MSVCRT__locale_t locale)
1054 return MSVCRT_strtoi64_l(str, NULL, 10, locale);
1057 /******************************************************************
1058 * atoll (MSVCR120.@)
1060 MSVCRT_longlong CDECL MSVCRT_atoll(const char* str)
1062 return MSVCRT__atoll_l(str, NULL);
1065 /******************************************************************
1066 * _strtol_l (MSVCRT.@)
1068 MSVCRT_long CDECL MSVCRT__strtol_l(const char* nptr,
1069 char** end, int base, MSVCRT__locale_t locale)
1071 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1073 if(ret > MSVCRT_LONG_MAX) {
1074 ret = MSVCRT_LONG_MAX;
1075 *MSVCRT__errno() = MSVCRT_ERANGE;
1076 } else if(ret < MSVCRT_LONG_MIN) {
1077 ret = MSVCRT_LONG_MIN;
1078 *MSVCRT__errno() = MSVCRT_ERANGE;
1081 return ret;
1084 /******************************************************************
1085 * strtol (MSVCRT.@)
1087 MSVCRT_long CDECL MSVCRT_strtol(const char* nptr, char** end, int base)
1089 return MSVCRT__strtol_l(nptr, end, base, NULL);
1092 /******************************************************************
1093 * _strtoul_l (MSVCRT.@)
1095 MSVCRT_ulong CDECL MSVCRT_strtoul_l(const char* nptr, char** end, int base, MSVCRT__locale_t locale)
1097 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1099 if(ret > MSVCRT_ULONG_MAX) {
1100 ret = MSVCRT_ULONG_MAX;
1101 *MSVCRT__errno() = MSVCRT_ERANGE;
1102 }else if(ret < -(__int64)MSVCRT_ULONG_MAX) {
1103 ret = 1;
1104 *MSVCRT__errno() = MSVCRT_ERANGE;
1107 return ret;
1110 /******************************************************************
1111 * strtoul (MSVCRT.@)
1113 MSVCRT_ulong CDECL MSVCRT_strtoul(const char* nptr, char** end, int base)
1115 return MSVCRT_strtoul_l(nptr, end, base, NULL);
1118 /*********************************************************************
1119 * _strtoui64_l (MSVCRT.@)
1121 * FIXME: locale parameter is ignored
1123 unsigned __int64 CDECL MSVCRT_strtoui64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
1125 const char *p = nptr;
1126 BOOL negative = FALSE;
1127 BOOL got_digit = FALSE;
1128 unsigned __int64 ret = 0;
1130 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1132 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1133 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1134 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1136 while(isspace(*nptr)) nptr++;
1138 if(*nptr == '-') {
1139 negative = TRUE;
1140 nptr++;
1141 } else if(*nptr == '+')
1142 nptr++;
1144 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
1145 base = 16;
1146 nptr += 2;
1149 if(base == 0) {
1150 if(*nptr=='0')
1151 base = 8;
1152 else
1153 base = 10;
1156 while(*nptr) {
1157 char cur = tolower(*nptr);
1158 int v;
1160 if(cur>='0' && cur<='9') {
1161 if(cur >= '0'+base)
1162 break;
1163 v = *nptr-'0';
1164 } else {
1165 if(cur<'a' || cur>='a'+base-10)
1166 break;
1167 v = cur-'a'+10;
1169 got_digit = TRUE;
1171 nptr++;
1173 if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1174 ret = MSVCRT_UI64_MAX;
1175 *MSVCRT__errno() = MSVCRT_ERANGE;
1176 } else
1177 ret = ret*base + v;
1180 if(endptr)
1181 *endptr = (char*)(got_digit ? nptr : p);
1183 return negative ? -ret : ret;
1186 /*********************************************************************
1187 * _strtoui64 (MSVCRT.@)
1189 unsigned __int64 CDECL MSVCRT_strtoui64(const char *nptr, char **endptr, int base)
1191 return MSVCRT_strtoui64_l(nptr, endptr, base, NULL);
1194 static int ltoa_helper(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1196 MSVCRT_ulong val;
1197 unsigned int digit;
1198 BOOL is_negative;
1199 char buffer[33], *pos;
1200 size_t len;
1202 if (value < 0 && radix == 10)
1204 is_negative = TRUE;
1205 val = -value;
1207 else
1209 is_negative = FALSE;
1210 val = value;
1213 pos = buffer + 32;
1214 *pos = '\0';
1218 digit = val % radix;
1219 val /= radix;
1221 if (digit < 10)
1222 *--pos = '0' + digit;
1223 else
1224 *--pos = 'a' + digit - 10;
1226 while (val != 0);
1228 if (is_negative)
1229 *--pos = '-';
1231 len = buffer + 33 - pos;
1232 if (len > size)
1234 size_t i;
1235 char *p = str;
1237 /* Copy the temporary buffer backwards up to the available number of
1238 * characters. Don't copy the negative sign if present. */
1240 if (is_negative)
1242 p++;
1243 size--;
1246 for (pos = buffer + 31, i = 0; i < size; i++)
1247 *p++ = *pos--;
1249 str[0] = '\0';
1250 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1251 return MSVCRT_ERANGE;
1254 memcpy(str, pos, len);
1255 return 0;
1258 /*********************************************************************
1259 * _ltoa_s (MSVCRT.@)
1261 int CDECL MSVCRT__ltoa_s(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1263 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1264 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1265 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1267 str[0] = '\0';
1268 return MSVCRT_EINVAL;
1271 return ltoa_helper(value, str, size, radix);
1274 /*********************************************************************
1275 * _ltow_s (MSVCRT.@)
1277 int CDECL MSVCRT__ltow_s(MSVCRT_long value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1279 MSVCRT_ulong val;
1280 unsigned int digit;
1281 BOOL is_negative;
1282 MSVCRT_wchar_t buffer[33], *pos;
1283 size_t len;
1285 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1286 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1287 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1289 str[0] = '\0';
1290 return MSVCRT_EINVAL;
1293 if (value < 0 && radix == 10)
1295 is_negative = TRUE;
1296 val = -value;
1298 else
1300 is_negative = FALSE;
1301 val = value;
1304 pos = buffer + 32;
1305 *pos = '\0';
1309 digit = val % radix;
1310 val /= radix;
1312 if (digit < 10)
1313 *--pos = '0' + digit;
1314 else
1315 *--pos = 'a' + digit - 10;
1317 while (val != 0);
1319 if (is_negative)
1320 *--pos = '-';
1322 len = buffer + 33 - pos;
1323 if (len > size)
1325 size_t i;
1326 MSVCRT_wchar_t *p = str;
1328 /* Copy the temporary buffer backwards up to the available number of
1329 * characters. Don't copy the negative sign if present. */
1331 if (is_negative)
1333 p++;
1334 size--;
1337 for (pos = buffer + 31, i = 0; i < size; i++)
1338 *p++ = *pos--;
1340 str[0] = '\0';
1341 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1342 return MSVCRT_ERANGE;
1345 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1346 return 0;
1349 /*********************************************************************
1350 * _itoa_s (MSVCRT.@)
1352 int CDECL MSVCRT__itoa_s(int value, char *str, MSVCRT_size_t size, int radix)
1354 return MSVCRT__ltoa_s(value, str, size, radix);
1357 /*********************************************************************
1358 * _itoa (MSVCRT.@)
1360 char* CDECL MSVCRT__itoa(int value, char *str, int radix)
1362 return ltoa_helper(value, str, MSVCRT_SIZE_MAX, radix) ? NULL : str;
1365 /*********************************************************************
1366 * _itow_s (MSVCRT.@)
1368 int CDECL MSVCRT__itow_s(int value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1370 return MSVCRT__ltow_s(value, str, size, radix);
1373 /*********************************************************************
1374 * _ui64toa_s (MSVCRT.@)
1376 int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str,
1377 MSVCRT_size_t size, int radix)
1379 char buffer[65], *pos;
1380 int digit;
1382 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1383 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1384 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1386 str[0] = '\0';
1387 return MSVCRT_EINVAL;
1390 pos = buffer+64;
1391 *pos = '\0';
1393 do {
1394 digit = value%radix;
1395 value /= radix;
1397 if(digit < 10)
1398 *--pos = '0'+digit;
1399 else
1400 *--pos = 'a'+digit-10;
1401 }while(value != 0);
1403 if(buffer-pos+65 > size) {
1404 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1405 return MSVCRT_EINVAL;
1408 memcpy(str, pos, buffer-pos+65);
1409 return 0;
1412 /*********************************************************************
1413 * _ui64tow_s (MSVCRT.@)
1415 int CDECL MSVCRT__ui64tow_s( unsigned __int64 value, MSVCRT_wchar_t *str,
1416 MSVCRT_size_t size, int radix )
1418 MSVCRT_wchar_t buffer[65], *pos;
1419 int digit;
1421 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1422 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1423 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1425 str[0] = '\0';
1426 return MSVCRT_EINVAL;
1429 pos = &buffer[64];
1430 *pos = '\0';
1432 do {
1433 digit = value % radix;
1434 value = value / radix;
1435 if (digit < 10)
1436 *--pos = '0' + digit;
1437 else
1438 *--pos = 'a' + digit - 10;
1439 } while (value != 0);
1441 if(buffer-pos+65 > size) {
1442 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1443 return MSVCRT_EINVAL;
1446 memcpy(str, pos, (buffer-pos+65)*sizeof(MSVCRT_wchar_t));
1447 return 0;
1450 /*********************************************************************
1451 * _ultoa_s (MSVCRT.@)
1453 int CDECL MSVCRT__ultoa_s(MSVCRT_ulong value, char *str, MSVCRT_size_t size, int radix)
1455 MSVCRT_ulong digit;
1456 char buffer[33], *pos;
1457 size_t len;
1459 if (!str || !size || radix < 2 || radix > 36)
1461 if (str && size)
1462 str[0] = '\0';
1464 *MSVCRT__errno() = MSVCRT_EINVAL;
1465 return MSVCRT_EINVAL;
1468 pos = buffer + 32;
1469 *pos = '\0';
1473 digit = value % radix;
1474 value /= radix;
1476 if (digit < 10)
1477 *--pos = '0' + digit;
1478 else
1479 *--pos = 'a' + digit - 10;
1481 while (value != 0);
1483 len = buffer + 33 - pos;
1484 if (len > size)
1486 size_t i;
1487 char *p = str;
1489 /* Copy the temporary buffer backwards up to the available number of
1490 * characters. */
1492 for (pos = buffer + 31, i = 0; i < size; i++)
1493 *p++ = *pos--;
1495 str[0] = '\0';
1496 *MSVCRT__errno() = MSVCRT_ERANGE;
1497 return MSVCRT_ERANGE;
1500 memcpy(str, pos, len);
1501 return 0;
1504 /*********************************************************************
1505 * _ultow_s (MSVCRT.@)
1507 int CDECL MSVCRT__ultow_s(MSVCRT_ulong value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1509 MSVCRT_ulong digit;
1510 WCHAR 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 WCHAR *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 * sizeof(MSVCRT_wchar_t));
1555 return 0;
1558 /*********************************************************************
1559 * _i64toa_s (MSVCRT.@)
1561 int CDECL MSVCRT__i64toa_s(__int64 value, char *str, MSVCRT_size_t size, int radix)
1563 unsigned __int64 val;
1564 unsigned int digit;
1565 BOOL is_negative;
1566 char buffer[65], *pos;
1567 size_t len;
1569 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1570 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1571 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1573 str[0] = '\0';
1574 return MSVCRT_EINVAL;
1577 if (value < 0 && radix == 10)
1579 is_negative = TRUE;
1580 val = -value;
1582 else
1584 is_negative = FALSE;
1585 val = value;
1588 pos = buffer + 64;
1589 *pos = '\0';
1593 digit = val % radix;
1594 val /= radix;
1596 if (digit < 10)
1597 *--pos = '0' + digit;
1598 else
1599 *--pos = 'a' + digit - 10;
1601 while (val != 0);
1603 if (is_negative)
1604 *--pos = '-';
1606 len = buffer + 65 - pos;
1607 if (len > size)
1609 size_t i;
1610 char *p = str;
1612 /* Copy the temporary buffer backwards up to the available number of
1613 * characters. Don't copy the negative sign if present. */
1615 if (is_negative)
1617 p++;
1618 size--;
1621 for (pos = buffer + 63, i = 0; i < size; i++)
1622 *p++ = *pos--;
1624 str[0] = '\0';
1625 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1626 return MSVCRT_ERANGE;
1629 memcpy(str, pos, len);
1630 return 0;
1633 /*********************************************************************
1634 * _i64tow_s (MSVCRT.@)
1636 int CDECL MSVCRT__i64tow_s(__int64 value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1638 unsigned __int64 val;
1639 unsigned int digit;
1640 BOOL is_negative;
1641 MSVCRT_wchar_t buffer[65], *pos;
1642 size_t len;
1644 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1645 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1646 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1648 str[0] = '\0';
1649 return MSVCRT_EINVAL;
1652 if (value < 0 && radix == 10)
1654 is_negative = TRUE;
1655 val = -value;
1657 else
1659 is_negative = FALSE;
1660 val = value;
1663 pos = buffer + 64;
1664 *pos = '\0';
1668 digit = val % radix;
1669 val /= radix;
1671 if (digit < 10)
1672 *--pos = '0' + digit;
1673 else
1674 *--pos = 'a' + digit - 10;
1676 while (val != 0);
1678 if (is_negative)
1679 *--pos = '-';
1681 len = buffer + 65 - pos;
1682 if (len > size)
1684 size_t i;
1685 MSVCRT_wchar_t *p = str;
1687 /* Copy the temporary buffer backwards up to the available number of
1688 * characters. Don't copy the negative sign if present. */
1690 if (is_negative)
1692 p++;
1693 size--;
1696 for (pos = buffer + 63, i = 0; i < size; i++)
1697 *p++ = *pos--;
1699 str[0] = '\0';
1700 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1701 return MSVCRT_ERANGE;
1704 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1705 return 0;
1708 #define I10_OUTPUT_MAX_PREC 21
1709 /* Internal structure used by $I10_OUTPUT */
1710 struct _I10_OUTPUT_DATA {
1711 short pos;
1712 char sign;
1713 BYTE len;
1714 char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */
1717 /*********************************************************************
1718 * $I10_OUTPUT (MSVCRT.@)
1719 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
1720 * prec - precision of part, we're interested in
1721 * flag - 0 for first prec digits, 1 for fractional part
1722 * data - data to be populated
1724 * return value
1725 * 0 if given double is NaN or INF
1726 * 1 otherwise
1728 * FIXME
1729 * Native sets last byte of data->str to '0' or '9', I don't know what
1730 * it means. Current implementation sets it always to '0'.
1732 int CDECL MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data)
1734 static const char inf_str[] = "1#INF";
1735 static const char nan_str[] = "1#QNAN";
1737 /* MS' long double type wants 12 bytes for Intel's 80 bit FP format.
1738 * Some UNIX have sizeof(long double) == 16, yet only 80 bit are used.
1739 * Assume long double uses 80 bit FP, never seen 128 bit FP. */
1740 long double ld = 0;
1741 double d;
1742 char format[8];
1743 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
1744 char *p;
1746 memcpy(&ld, &ld80, 10);
1747 d = ld;
1748 TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
1750 if(d<0) {
1751 data->sign = '-';
1752 d = -d;
1753 } else
1754 data->sign = ' ';
1756 if(isinf(d)) {
1757 data->pos = 1;
1758 data->len = 5;
1759 memcpy(data->str, inf_str, sizeof(inf_str));
1761 return 0;
1764 if(isnan(d)) {
1765 data->pos = 1;
1766 data->len = 6;
1767 memcpy(data->str, nan_str, sizeof(nan_str));
1769 return 0;
1772 if(flag&1) {
1773 int exp = 1+floor(log10(d));
1775 prec += exp;
1776 if(exp < 0)
1777 prec--;
1779 prec--;
1781 if(prec+1 > I10_OUTPUT_MAX_PREC)
1782 prec = I10_OUTPUT_MAX_PREC-1;
1783 else if(prec < 0) {
1784 d = 0.0;
1785 prec = 0;
1788 sprintf(format, "%%.%dle", prec);
1789 sprintf(buf, format, d);
1791 buf[1] = buf[0];
1792 data->pos = atoi(buf+prec+3);
1793 if(buf[1] != '0')
1794 data->pos++;
1796 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
1797 data->len = p-buf;
1799 memcpy(data->str, buf+1, data->len);
1800 data->str[data->len] = '\0';
1802 if(buf[1]!='0' && prec-data->len+1>0)
1803 memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1);
1805 return 1;
1807 #undef I10_OUTPUT_MAX_PREC
1809 /*********************************************************************
1810 * memcmp (MSVCRT.@)
1812 int __cdecl MSVCRT_memcmp(const void *ptr1, const void *ptr2, MSVCRT_size_t n)
1814 return memcmp(ptr1, ptr2, n);
1817 /*********************************************************************
1818 * memcpy (MSVCRT.@)
1820 void * __cdecl MSVCRT_memcpy(void *dst, const void *src, MSVCRT_size_t n)
1822 return memmove(dst, src, n);
1825 /*********************************************************************
1826 * memmove (MSVCRT.@)
1828 void * __cdecl MSVCRT_memmove(void *dst, const void *src, MSVCRT_size_t n)
1830 return memmove(dst, src, n);
1833 /*********************************************************************
1834 * memset (MSVCRT.@)
1836 void* __cdecl MSVCRT_memset(void *dst, int c, MSVCRT_size_t n)
1838 return memset(dst, c, n);
1841 /*********************************************************************
1842 * strchr (MSVCRT.@)
1844 char* __cdecl MSVCRT_strchr(const char *str, int c)
1846 return strchr(str, c);
1849 /*********************************************************************
1850 * strrchr (MSVCRT.@)
1852 char* __cdecl MSVCRT_strrchr(const char *str, int c)
1854 return strrchr(str, c);
1857 /*********************************************************************
1858 * memchr (MSVCRT.@)
1860 void* __cdecl MSVCRT_memchr(const void *ptr, int c, MSVCRT_size_t n)
1862 return memchr(ptr, c, n);
1865 /*********************************************************************
1866 * strcmp (MSVCRT.@)
1868 int __cdecl MSVCRT_strcmp(const char *str1, const char *str2)
1870 return strcmp(str1, str2);
1873 /*********************************************************************
1874 * strncmp (MSVCRT.@)
1876 int __cdecl MSVCRT_strncmp(const char *str1, const char *str2, MSVCRT_size_t len)
1878 return strncmp(str1, str2, len);
1881 /*********************************************************************
1882 * _strnicmp_l (MSVCRT.@)
1884 int __cdecl MSVCRT__strnicmp_l(const char *s1, const char *s2,
1885 MSVCRT_size_t count, MSVCRT__locale_t locale)
1887 MSVCRT_pthreadlocinfo locinfo;
1888 int c1, c2;
1890 if(s1==NULL || s2==NULL)
1891 return MSVCRT__NLSCMPERROR;
1893 if(!count)
1894 return 0;
1896 if(!locale)
1897 locinfo = get_locinfo();
1898 else
1899 locinfo = locale->locinfo;
1901 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
1902 return strncasecmp(s1, s2, count);
1904 do {
1905 c1 = MSVCRT__tolower_l(*s1++, locale);
1906 c2 = MSVCRT__tolower_l(*s2++, locale);
1907 }while(--count && c1 && c1==c2);
1909 return c1-c2;
1912 /*********************************************************************
1913 * _stricmp_l (MSVCRT.@)
1915 int __cdecl MSVCRT__stricmp_l(const char *s1, const char *s2, MSVCRT__locale_t locale)
1917 return MSVCRT__strnicmp_l(s1, s2, -1, locale);
1920 /*********************************************************************
1921 * _strnicmp (MSVCRT.@)
1923 int __cdecl MSVCRT__strnicmp(const char *s1, const char *s2, MSVCRT_size_t count)
1925 return MSVCRT__strnicmp_l(s1, s2, count, NULL);
1928 /*********************************************************************
1929 * _stricmp (MSVCRT.@)
1931 int __cdecl MSVCRT__stricmp(const char *s1, const char *s2)
1933 return MSVCRT__strnicmp_l(s1, s2, -1, NULL);
1936 /*********************************************************************
1937 * strstr (MSVCRT.@)
1939 char* __cdecl MSVCRT_strstr(const char *haystack, const char *needle)
1941 return strstr(haystack, needle);