ddraw/tests: Add another invalid arguments test for surface QI.
[wine.git] / dlls / msvcrt / string.c
blob2c05e3714939cbd8aa5ca40ea616b938bc79d5a9
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 #if _MSVCR_VER>=120
504 /*********************************************************************
505 * strtof_l (MSVCR120.@)
507 float CDECL MSVCRT__strtof_l( const char *str, char **end, MSVCRT__locale_t locale )
509 return MSVCRT_strtod_l(str, end, locale);
512 /*********************************************************************
513 * strtof (MSVCR120.@)
515 float CDECL MSVCRT_strtof( const char *str, char **end )
517 return MSVCRT__strtof_l(str, end, NULL);
520 #endif /* _MSVCR_VER>=120 */
522 /*********************************************************************
523 * atof (MSVCRT.@)
525 double CDECL MSVCRT_atof( const char *str )
527 return MSVCRT_strtod_l(str, NULL, NULL);
530 /*********************************************************************
531 * _atof_l (MSVCRT.@)
533 double CDECL MSVCRT__atof_l( const char *str, MSVCRT__locale_t locale)
535 return MSVCRT_strtod_l(str, NULL, locale);
538 /*********************************************************************
539 * _atoflt_l (MSVCRT.@)
541 int CDECL MSVCRT__atoflt_l( MSVCRT__CRT_FLOAT *value, char *str, MSVCRT__locale_t locale)
543 double d;
544 int err;
546 d = strtod_helper(str, NULL, locale, &err);
547 value->f = d;
548 if(isinf(value->f))
549 return MSVCRT__OVERFLOW;
550 if((d!=0 || err) && value->f>-MSVCRT_FLT_MIN && value->f<MSVCRT_FLT_MIN)
551 return MSVCRT__UNDERFLOW;
552 return 0;
555 /*********************************************************************
556 * _atoflt (MSVCR100.@)
558 int CDECL MSVCRT__atoflt(MSVCRT__CRT_FLOAT *value, char *str)
560 return MSVCRT__atoflt_l(value, str, NULL);
563 /*********************************************************************
564 * _atodbl_l (MSVCRT.@)
566 int CDECL MSVCRT__atodbl_l(MSVCRT__CRT_DOUBLE *value, char *str, MSVCRT__locale_t locale)
568 int err;
570 value->x = strtod_helper(str, NULL, locale, &err);
571 if(isinf(value->x))
572 return MSVCRT__OVERFLOW;
573 if((value->x!=0 || err) && value->x>-MSVCRT_DBL_MIN && value->x<MSVCRT_DBL_MIN)
574 return MSVCRT__UNDERFLOW;
575 return 0;
578 /*********************************************************************
579 * _atodbl (MSVCRT.@)
581 int CDECL MSVCRT__atodbl(MSVCRT__CRT_DOUBLE *value, char *str)
583 return MSVCRT__atodbl_l(value, str, NULL);
586 /*********************************************************************
587 * _strcoll_l (MSVCRT.@)
589 int CDECL MSVCRT_strcoll_l( const char* str1, const char* str2, MSVCRT__locale_t locale )
591 MSVCRT_pthreadlocinfo locinfo;
593 if(!locale)
594 locinfo = get_locinfo();
595 else
596 locinfo = locale->locinfo;
598 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
599 return strcmp(str1, str2);
600 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], 0, str1, -1, str2, -1)-CSTR_EQUAL;
603 /*********************************************************************
604 * strcoll (MSVCRT.@)
606 int CDECL MSVCRT_strcoll( const char* str1, const char* str2 )
608 return MSVCRT_strcoll_l(str1, str2, NULL);
611 /*********************************************************************
612 * _stricoll_l (MSVCRT.@)
614 int CDECL MSVCRT__stricoll_l( const char* str1, const char* str2, MSVCRT__locale_t locale )
616 MSVCRT_pthreadlocinfo locinfo;
618 if(!locale)
619 locinfo = get_locinfo();
620 else
621 locinfo = locale->locinfo;
623 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
624 return strcasecmp(str1, str2);
625 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], NORM_IGNORECASE,
626 str1, -1, str2, -1)-CSTR_EQUAL;
629 /*********************************************************************
630 * _stricoll (MSVCRT.@)
632 int CDECL MSVCRT__stricoll( const char* str1, const char* str2 )
634 return MSVCRT__stricoll_l(str1, str2, NULL);
637 /*********************************************************************
638 * _strncoll_l (MSVCRT.@)
640 int CDECL MSVCRT__strncoll_l( const char* str1, const char* str2, MSVCRT_size_t count, MSVCRT__locale_t locale )
642 MSVCRT_pthreadlocinfo locinfo;
644 if(!locale)
645 locinfo = get_locinfo();
646 else
647 locinfo = locale->locinfo;
649 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
650 return strncmp(str1, str2, count);
651 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], 0, str1, count, str2, count)-CSTR_EQUAL;
654 /*********************************************************************
655 * _strncoll (MSVCRT.@)
657 int CDECL MSVCRT__strncoll( const char* str1, const char* str2, MSVCRT_size_t count )
659 return MSVCRT__strncoll_l(str1, str2, count, NULL);
662 /*********************************************************************
663 * _strnicoll_l (MSVCRT.@)
665 int CDECL MSVCRT__strnicoll_l( const char* str1, const char* str2, MSVCRT_size_t count, MSVCRT__locale_t locale )
667 MSVCRT_pthreadlocinfo locinfo;
669 if(!locale)
670 locinfo = get_locinfo();
671 else
672 locinfo = locale->locinfo;
674 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE])
675 return strncasecmp(str1, str2, count);
676 return CompareStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE], NORM_IGNORECASE,
677 str1, count, str2, count)-CSTR_EQUAL;
680 /*********************************************************************
681 * _strnicoll (MSVCRT.@)
683 int CDECL MSVCRT__strnicoll( const char* str1, const char* str2, MSVCRT_size_t count )
685 return MSVCRT__strnicoll_l(str1, str2, count, NULL);
688 /*********************************************************************
689 * strncpy (MSVCRT.@)
691 char* __cdecl MSVCRT_strncpy(char *dst, const char *src, MSVCRT_size_t len)
693 MSVCRT_size_t i;
695 for(i=0; i<len; i++)
696 if((dst[i] = src[i]) == '\0') break;
698 while (i < len) dst[i++] = 0;
700 return dst;
703 /*********************************************************************
704 * strcpy (MSVCRT.@)
706 char* CDECL MSVCRT_strcpy(char *dst, const char *src)
708 char *ret = dst;
709 while ((*dst++ = *src++));
710 return ret;
713 /*********************************************************************
714 * strcpy_s (MSVCRT.@)
716 int CDECL MSVCRT_strcpy_s( char* dst, MSVCRT_size_t elem, const char* src )
718 MSVCRT_size_t i;
719 if(!elem) return MSVCRT_EINVAL;
720 if(!dst) return MSVCRT_EINVAL;
721 if(!src)
723 dst[0] = '\0';
724 return MSVCRT_EINVAL;
727 for(i = 0; i < elem; i++)
729 if((dst[i] = src[i]) == '\0') return 0;
731 dst[0] = '\0';
732 return MSVCRT_ERANGE;
735 /*********************************************************************
736 * strcat_s (MSVCRT.@)
738 int CDECL MSVCRT_strcat_s( char* dst, MSVCRT_size_t elem, const char* src )
740 MSVCRT_size_t i, j;
741 if(!dst) return MSVCRT_EINVAL;
742 if(elem == 0) return MSVCRT_EINVAL;
743 if(!src)
745 dst[0] = '\0';
746 return MSVCRT_EINVAL;
749 for(i = 0; i < elem; i++)
751 if(dst[i] == '\0')
753 for(j = 0; (j + i) < elem; j++)
755 if((dst[j + i] = src[j]) == '\0') return 0;
759 /* Set the first element to 0, not the first element after the skipped part */
760 dst[0] = '\0';
761 return MSVCRT_ERANGE;
764 /*********************************************************************
765 * strncat_s (MSVCRT.@)
767 int CDECL MSVCRT_strncat_s( char* dst, MSVCRT_size_t elem, const char* src, MSVCRT_size_t count )
769 MSVCRT_size_t i, j;
771 if (!MSVCRT_CHECK_PMT(dst != 0)) return MSVCRT_EINVAL;
772 if (!MSVCRT_CHECK_PMT(elem != 0)) return MSVCRT_EINVAL;
773 if (!MSVCRT_CHECK_PMT(src != 0))
775 dst[0] = '\0';
776 return MSVCRT_EINVAL;
779 for(i = 0; i < elem; i++)
781 if(dst[i] == '\0')
783 for(j = 0; (j + i) < elem; j++)
785 if(count == MSVCRT__TRUNCATE && j + i == elem - 1)
787 dst[j + i] = '\0';
788 return MSVCRT_STRUNCATE;
790 if(j == count || (dst[j + i] = src[j]) == '\0')
792 dst[j + i] = '\0';
793 return 0;
798 /* Set the first element to 0, not the first element after the skipped part */
799 dst[0] = '\0';
800 return MSVCRT_ERANGE;
803 /*********************************************************************
804 * strncat (MSVCRT.@)
806 char* __cdecl MSVCRT_strncat(char *dst, const char *src, MSVCRT_size_t len)
808 return strncat(dst, src, len);
811 /*********************************************************************
812 * _strxfrm_l (MSVCRT.@)
814 MSVCRT_size_t CDECL MSVCRT__strxfrm_l( char *dest, const char *src,
815 MSVCRT_size_t len, MSVCRT__locale_t locale )
817 MSVCRT_pthreadlocinfo locinfo;
818 int ret;
820 if(!MSVCRT_CHECK_PMT(src)) return INT_MAX;
821 if(!MSVCRT_CHECK_PMT(dest || !len)) return INT_MAX;
823 if(len > INT_MAX) {
824 FIXME("len > INT_MAX not supported\n");
825 len = INT_MAX;
828 if(!locale)
829 locinfo = get_locinfo();
830 else
831 locinfo = locale->locinfo;
833 if(!locinfo->lc_handle[MSVCRT_LC_COLLATE]) {
834 MSVCRT_strncpy(dest, src, len);
835 return strlen(src);
838 ret = LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
839 LCMAP_SORTKEY, src, -1, NULL, 0);
840 if(!ret) {
841 if(len) dest[0] = 0;
842 *MSVCRT__errno() = MSVCRT_EILSEQ;
843 return INT_MAX;
845 if(!len) return ret-1;
847 if(ret > len) {
848 dest[0] = 0;
849 *MSVCRT__errno() = MSVCRT_ERANGE;
850 return ret-1;
853 return LCMapStringA(locinfo->lc_handle[MSVCRT_LC_COLLATE],
854 LCMAP_SORTKEY, src, -1, dest, len) - 1;
857 /*********************************************************************
858 * strxfrm (MSVCRT.@)
860 MSVCRT_size_t CDECL MSVCRT_strxfrm( char *dest, const char *src, MSVCRT_size_t len )
862 return MSVCRT__strxfrm_l(dest, src, len, NULL);
865 /********************************************************************
866 * _atoldbl (MSVCRT.@)
868 int CDECL MSVCRT__atoldbl(MSVCRT__LDOUBLE *value, const char *str)
870 /* FIXME needs error checking for huge/small values */
871 #ifdef HAVE_STRTOLD
872 long double ld;
873 TRACE("str %s value %p\n",str,value);
874 ld = strtold(str,0);
875 memcpy(value, &ld, 10);
876 #else
877 FIXME("stub, str %s value %p\n",str,value);
878 #endif
879 return 0;
882 /********************************************************************
883 * __STRINGTOLD (MSVCRT.@)
885 int CDECL __STRINGTOLD( MSVCRT__LDOUBLE *value, char **endptr, const char *str, int flags )
887 #ifdef HAVE_STRTOLD
888 long double ld;
889 FIXME("%p %p %s %x partial stub\n", value, endptr, str, flags );
890 ld = strtold(str,0);
891 memcpy(value, &ld, 10);
892 #else
893 FIXME("%p %p %s %x stub\n", value, endptr, str, flags );
894 #endif
895 return 0;
898 /*********************************************************************
899 * strlen (MSVCRT.@)
901 MSVCRT_size_t __cdecl MSVCRT_strlen(const char *str)
903 return strlen(str);
906 /******************************************************************
907 * strnlen (MSVCRT.@)
909 MSVCRT_size_t CDECL MSVCRT_strnlen(const char *s, MSVCRT_size_t maxlen)
911 MSVCRT_size_t i;
913 for(i=0; i<maxlen; i++)
914 if(!s[i]) break;
916 return i;
919 /*********************************************************************
920 * _strtoi64_l (MSVCRT.@)
922 * FIXME: locale parameter is ignored
924 __int64 CDECL MSVCRT_strtoi64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
926 const char *p = nptr;
927 BOOL negative = FALSE;
928 BOOL got_digit = FALSE;
929 __int64 ret = 0;
931 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
933 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
934 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
935 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
937 while(isspace(*nptr)) nptr++;
939 if(*nptr == '-') {
940 negative = TRUE;
941 nptr++;
942 } else if(*nptr == '+')
943 nptr++;
945 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
946 base = 16;
947 nptr += 2;
950 if(base == 0) {
951 if(*nptr=='0')
952 base = 8;
953 else
954 base = 10;
957 while(*nptr) {
958 char cur = tolower(*nptr);
959 int v;
961 if(cur>='0' && cur<='9') {
962 if(cur >= '0'+base)
963 break;
964 v = cur-'0';
965 } else {
966 if(cur<'a' || cur>='a'+base-10)
967 break;
968 v = cur-'a'+10;
970 got_digit = TRUE;
972 if(negative)
973 v = -v;
975 nptr++;
977 if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
978 ret = MSVCRT_I64_MAX;
979 *MSVCRT__errno() = MSVCRT_ERANGE;
980 } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
981 ret = MSVCRT_I64_MIN;
982 *MSVCRT__errno() = MSVCRT_ERANGE;
983 } else
984 ret = ret*base + v;
987 if(endptr)
988 *endptr = (char*)(got_digit ? nptr : p);
990 return ret;
993 /*********************************************************************
994 * _strtoi64 (MSVCRT.@)
996 __int64 CDECL MSVCRT_strtoi64(const char *nptr, char **endptr, int base)
998 return MSVCRT_strtoi64_l(nptr, endptr, base, NULL);
1001 /*********************************************************************
1002 * _atoi_l (MSVCRT.@)
1004 int __cdecl MSVCRT__atoi_l(const char *str, MSVCRT__locale_t locale)
1006 __int64 ret = MSVCRT_strtoi64_l(str, NULL, 10, locale);
1008 if(ret > INT_MAX) {
1009 ret = INT_MAX;
1010 *MSVCRT__errno() = MSVCRT_ERANGE;
1011 } else if(ret < INT_MIN) {
1012 ret = INT_MIN;
1013 *MSVCRT__errno() = MSVCRT_ERANGE;
1015 return ret;
1018 /*********************************************************************
1019 * atoi (MSVCRT.@)
1021 #if _MSVCR_VER == 0
1022 int __cdecl MSVCRT_atoi(const char *str)
1024 BOOL minus = FALSE;
1025 int ret = 0;
1027 if(!str)
1028 return 0;
1030 while(isspace(*str)) str++;
1032 if(*str == '+') {
1033 str++;
1034 }else if(*str == '-') {
1035 minus = TRUE;
1036 str++;
1039 while(*str>='0' && *str<='9') {
1040 ret = ret*10+*str-'0';
1041 str++;
1044 return minus ? -ret : ret;
1046 #else
1047 int CDECL MSVCRT_atoi(const char *str)
1049 return MSVCRT__atoi_l(str, NULL);
1051 #endif
1053 #if _MSVCR_VER>=120
1055 /******************************************************************
1056 * _atoll_l (MSVCR120.@)
1058 MSVCRT_longlong CDECL MSVCRT__atoll_l(const char* str, MSVCRT__locale_t locale)
1060 return MSVCRT_strtoi64_l(str, NULL, 10, locale);
1063 /******************************************************************
1064 * atoll (MSVCR120.@)
1066 MSVCRT_longlong CDECL MSVCRT_atoll(const char* str)
1068 return MSVCRT__atoll_l(str, NULL);
1071 #endif /* if _MSVCR_VER>=120 */
1073 /******************************************************************
1074 * _strtol_l (MSVCRT.@)
1076 MSVCRT_long CDECL MSVCRT__strtol_l(const char* nptr,
1077 char** end, int base, MSVCRT__locale_t locale)
1079 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1081 if(ret > MSVCRT_LONG_MAX) {
1082 ret = MSVCRT_LONG_MAX;
1083 *MSVCRT__errno() = MSVCRT_ERANGE;
1084 } else if(ret < MSVCRT_LONG_MIN) {
1085 ret = MSVCRT_LONG_MIN;
1086 *MSVCRT__errno() = MSVCRT_ERANGE;
1089 return ret;
1092 /******************************************************************
1093 * strtol (MSVCRT.@)
1095 MSVCRT_long CDECL MSVCRT_strtol(const char* nptr, char** end, int base)
1097 return MSVCRT__strtol_l(nptr, end, base, NULL);
1100 /******************************************************************
1101 * _strtoul_l (MSVCRT.@)
1103 MSVCRT_ulong CDECL MSVCRT_strtoul_l(const char* nptr, char** end, int base, MSVCRT__locale_t locale)
1105 __int64 ret = MSVCRT_strtoi64_l(nptr, end, base, locale);
1107 if(ret > MSVCRT_ULONG_MAX) {
1108 ret = MSVCRT_ULONG_MAX;
1109 *MSVCRT__errno() = MSVCRT_ERANGE;
1110 }else if(ret < -(__int64)MSVCRT_ULONG_MAX) {
1111 ret = 1;
1112 *MSVCRT__errno() = MSVCRT_ERANGE;
1115 return ret;
1118 /******************************************************************
1119 * strtoul (MSVCRT.@)
1121 MSVCRT_ulong CDECL MSVCRT_strtoul(const char* nptr, char** end, int base)
1123 return MSVCRT_strtoul_l(nptr, end, base, NULL);
1126 /*********************************************************************
1127 * _strtoui64_l (MSVCRT.@)
1129 * FIXME: locale parameter is ignored
1131 unsigned __int64 CDECL MSVCRT_strtoui64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
1133 const char *p = nptr;
1134 BOOL negative = FALSE;
1135 BOOL got_digit = FALSE;
1136 unsigned __int64 ret = 0;
1138 TRACE("(%s %p %d %p)\n", debugstr_a(nptr), endptr, base, locale);
1140 if (!MSVCRT_CHECK_PMT(nptr != NULL)) return 0;
1141 if (!MSVCRT_CHECK_PMT(base == 0 || base >= 2)) return 0;
1142 if (!MSVCRT_CHECK_PMT(base <= 36)) return 0;
1144 while(isspace(*nptr)) nptr++;
1146 if(*nptr == '-') {
1147 negative = TRUE;
1148 nptr++;
1149 } else if(*nptr == '+')
1150 nptr++;
1152 if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
1153 base = 16;
1154 nptr += 2;
1157 if(base == 0) {
1158 if(*nptr=='0')
1159 base = 8;
1160 else
1161 base = 10;
1164 while(*nptr) {
1165 char cur = tolower(*nptr);
1166 int v;
1168 if(cur>='0' && cur<='9') {
1169 if(cur >= '0'+base)
1170 break;
1171 v = *nptr-'0';
1172 } else {
1173 if(cur<'a' || cur>='a'+base-10)
1174 break;
1175 v = cur-'a'+10;
1177 got_digit = TRUE;
1179 nptr++;
1181 if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
1182 ret = MSVCRT_UI64_MAX;
1183 *MSVCRT__errno() = MSVCRT_ERANGE;
1184 } else
1185 ret = ret*base + v;
1188 if(endptr)
1189 *endptr = (char*)(got_digit ? nptr : p);
1191 return negative ? -ret : ret;
1194 /*********************************************************************
1195 * _strtoui64 (MSVCRT.@)
1197 unsigned __int64 CDECL MSVCRT_strtoui64(const char *nptr, char **endptr, int base)
1199 return MSVCRT_strtoui64_l(nptr, endptr, base, NULL);
1202 static int ltoa_helper(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1204 MSVCRT_ulong val;
1205 unsigned int digit;
1206 BOOL is_negative;
1207 char buffer[33], *pos;
1208 size_t len;
1210 if (value < 0 && radix == 10)
1212 is_negative = TRUE;
1213 val = -value;
1215 else
1217 is_negative = FALSE;
1218 val = value;
1221 pos = buffer + 32;
1222 *pos = '\0';
1226 digit = val % radix;
1227 val /= radix;
1229 if (digit < 10)
1230 *--pos = '0' + digit;
1231 else
1232 *--pos = 'a' + digit - 10;
1234 while (val != 0);
1236 if (is_negative)
1237 *--pos = '-';
1239 len = buffer + 33 - pos;
1240 if (len > size)
1242 size_t i;
1243 char *p = str;
1245 /* Copy the temporary buffer backwards up to the available number of
1246 * characters. Don't copy the negative sign if present. */
1248 if (is_negative)
1250 p++;
1251 size--;
1254 for (pos = buffer + 31, i = 0; i < size; i++)
1255 *p++ = *pos--;
1257 str[0] = '\0';
1258 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1259 return MSVCRT_ERANGE;
1262 memcpy(str, pos, len);
1263 return 0;
1266 /*********************************************************************
1267 * _ltoa_s (MSVCRT.@)
1269 int CDECL MSVCRT__ltoa_s(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
1271 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1272 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1273 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1275 str[0] = '\0';
1276 return MSVCRT_EINVAL;
1279 return ltoa_helper(value, str, size, radix);
1282 /*********************************************************************
1283 * _ltow_s (MSVCRT.@)
1285 int CDECL MSVCRT__ltow_s(MSVCRT_long value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1287 MSVCRT_ulong val;
1288 unsigned int digit;
1289 BOOL is_negative;
1290 MSVCRT_wchar_t buffer[33], *pos;
1291 size_t len;
1293 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1294 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1295 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1297 str[0] = '\0';
1298 return MSVCRT_EINVAL;
1301 if (value < 0 && radix == 10)
1303 is_negative = TRUE;
1304 val = -value;
1306 else
1308 is_negative = FALSE;
1309 val = value;
1312 pos = buffer + 32;
1313 *pos = '\0';
1317 digit = val % radix;
1318 val /= radix;
1320 if (digit < 10)
1321 *--pos = '0' + digit;
1322 else
1323 *--pos = 'a' + digit - 10;
1325 while (val != 0);
1327 if (is_negative)
1328 *--pos = '-';
1330 len = buffer + 33 - pos;
1331 if (len > size)
1333 size_t i;
1334 MSVCRT_wchar_t *p = str;
1336 /* Copy the temporary buffer backwards up to the available number of
1337 * characters. Don't copy the negative sign if present. */
1339 if (is_negative)
1341 p++;
1342 size--;
1345 for (pos = buffer + 31, i = 0; i < size; i++)
1346 *p++ = *pos--;
1348 str[0] = '\0';
1349 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1350 return MSVCRT_ERANGE;
1353 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1354 return 0;
1357 /*********************************************************************
1358 * _itoa_s (MSVCRT.@)
1360 int CDECL MSVCRT__itoa_s(int value, char *str, MSVCRT_size_t size, int radix)
1362 return MSVCRT__ltoa_s(value, str, size, radix);
1365 /*********************************************************************
1366 * _itoa (MSVCRT.@)
1368 char* CDECL MSVCRT__itoa(int value, char *str, int radix)
1370 return ltoa_helper(value, str, MSVCRT_SIZE_MAX, radix) ? NULL : str;
1373 /*********************************************************************
1374 * _itow_s (MSVCRT.@)
1376 int CDECL MSVCRT__itow_s(int value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1378 return MSVCRT__ltow_s(value, str, size, radix);
1381 /*********************************************************************
1382 * _ui64toa_s (MSVCRT.@)
1384 int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str,
1385 MSVCRT_size_t size, int radix)
1387 char buffer[65], *pos;
1388 int digit;
1390 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1391 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1392 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1394 str[0] = '\0';
1395 return MSVCRT_EINVAL;
1398 pos = buffer+64;
1399 *pos = '\0';
1401 do {
1402 digit = value%radix;
1403 value /= radix;
1405 if(digit < 10)
1406 *--pos = '0'+digit;
1407 else
1408 *--pos = 'a'+digit-10;
1409 }while(value != 0);
1411 if(buffer-pos+65 > size) {
1412 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1413 return MSVCRT_EINVAL;
1416 memcpy(str, pos, buffer-pos+65);
1417 return 0;
1420 /*********************************************************************
1421 * _ui64tow_s (MSVCRT.@)
1423 int CDECL MSVCRT__ui64tow_s( unsigned __int64 value, MSVCRT_wchar_t *str,
1424 MSVCRT_size_t size, int radix )
1426 MSVCRT_wchar_t buffer[65], *pos;
1427 int digit;
1429 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1430 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1431 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1433 str[0] = '\0';
1434 return MSVCRT_EINVAL;
1437 pos = &buffer[64];
1438 *pos = '\0';
1440 do {
1441 digit = value % radix;
1442 value = value / radix;
1443 if (digit < 10)
1444 *--pos = '0' + digit;
1445 else
1446 *--pos = 'a' + digit - 10;
1447 } while (value != 0);
1449 if(buffer-pos+65 > size) {
1450 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_EINVAL);
1451 return MSVCRT_EINVAL;
1454 memcpy(str, pos, (buffer-pos+65)*sizeof(MSVCRT_wchar_t));
1455 return 0;
1458 /*********************************************************************
1459 * _ultoa_s (MSVCRT.@)
1461 int CDECL MSVCRT__ultoa_s(MSVCRT_ulong value, char *str, MSVCRT_size_t size, int radix)
1463 MSVCRT_ulong digit;
1464 char buffer[33], *pos;
1465 size_t len;
1467 if (!str || !size || radix < 2 || radix > 36)
1469 if (str && size)
1470 str[0] = '\0';
1472 *MSVCRT__errno() = MSVCRT_EINVAL;
1473 return MSVCRT_EINVAL;
1476 pos = buffer + 32;
1477 *pos = '\0';
1481 digit = value % radix;
1482 value /= radix;
1484 if (digit < 10)
1485 *--pos = '0' + digit;
1486 else
1487 *--pos = 'a' + digit - 10;
1489 while (value != 0);
1491 len = buffer + 33 - pos;
1492 if (len > size)
1494 size_t i;
1495 char *p = str;
1497 /* Copy the temporary buffer backwards up to the available number of
1498 * characters. */
1500 for (pos = buffer + 31, i = 0; i < size; i++)
1501 *p++ = *pos--;
1503 str[0] = '\0';
1504 *MSVCRT__errno() = MSVCRT_ERANGE;
1505 return MSVCRT_ERANGE;
1508 memcpy(str, pos, len);
1509 return 0;
1512 /*********************************************************************
1513 * _ultow_s (MSVCRT.@)
1515 int CDECL MSVCRT__ultow_s(MSVCRT_ulong value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1517 MSVCRT_ulong digit;
1518 WCHAR buffer[33], *pos;
1519 size_t len;
1521 if (!str || !size || radix < 2 || radix > 36)
1523 if (str && size)
1524 str[0] = '\0';
1526 *MSVCRT__errno() = MSVCRT_EINVAL;
1527 return MSVCRT_EINVAL;
1530 pos = buffer + 32;
1531 *pos = '\0';
1535 digit = value % radix;
1536 value /= radix;
1538 if (digit < 10)
1539 *--pos = '0' + digit;
1540 else
1541 *--pos = 'a' + digit - 10;
1543 while (value != 0);
1545 len = buffer + 33 - pos;
1546 if (len > size)
1548 size_t i;
1549 WCHAR *p = str;
1551 /* Copy the temporary buffer backwards up to the available number of
1552 * characters. */
1554 for (pos = buffer + 31, i = 0; i < size; i++)
1555 *p++ = *pos--;
1557 str[0] = '\0';
1558 *MSVCRT__errno() = MSVCRT_ERANGE;
1559 return MSVCRT_ERANGE;
1562 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1563 return 0;
1566 /*********************************************************************
1567 * _i64toa_s (MSVCRT.@)
1569 int CDECL MSVCRT__i64toa_s(__int64 value, char *str, MSVCRT_size_t size, int radix)
1571 unsigned __int64 val;
1572 unsigned int digit;
1573 BOOL is_negative;
1574 char buffer[65], *pos;
1575 size_t len;
1577 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1578 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1579 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1581 str[0] = '\0';
1582 return MSVCRT_EINVAL;
1585 if (value < 0 && radix == 10)
1587 is_negative = TRUE;
1588 val = -value;
1590 else
1592 is_negative = FALSE;
1593 val = value;
1596 pos = buffer + 64;
1597 *pos = '\0';
1601 digit = val % radix;
1602 val /= radix;
1604 if (digit < 10)
1605 *--pos = '0' + digit;
1606 else
1607 *--pos = 'a' + digit - 10;
1609 while (val != 0);
1611 if (is_negative)
1612 *--pos = '-';
1614 len = buffer + 65 - pos;
1615 if (len > size)
1617 size_t i;
1618 char *p = str;
1620 /* Copy the temporary buffer backwards up to the available number of
1621 * characters. Don't copy the negative sign if present. */
1623 if (is_negative)
1625 p++;
1626 size--;
1629 for (pos = buffer + 63, i = 0; i < size; i++)
1630 *p++ = *pos--;
1632 str[0] = '\0';
1633 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1634 return MSVCRT_ERANGE;
1637 memcpy(str, pos, len);
1638 return 0;
1641 /*********************************************************************
1642 * _i64tow_s (MSVCRT.@)
1644 int CDECL MSVCRT__i64tow_s(__int64 value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1646 unsigned __int64 val;
1647 unsigned int digit;
1648 BOOL is_negative;
1649 MSVCRT_wchar_t buffer[65], *pos;
1650 size_t len;
1652 if (!MSVCRT_CHECK_PMT(str != NULL)) return MSVCRT_EINVAL;
1653 if (!MSVCRT_CHECK_PMT(size > 0)) return MSVCRT_EINVAL;
1654 if (!MSVCRT_CHECK_PMT(radix >= 2 && radix <= 36))
1656 str[0] = '\0';
1657 return MSVCRT_EINVAL;
1660 if (value < 0 && radix == 10)
1662 is_negative = TRUE;
1663 val = -value;
1665 else
1667 is_negative = FALSE;
1668 val = value;
1671 pos = buffer + 64;
1672 *pos = '\0';
1676 digit = val % radix;
1677 val /= radix;
1679 if (digit < 10)
1680 *--pos = '0' + digit;
1681 else
1682 *--pos = 'a' + digit - 10;
1684 while (val != 0);
1686 if (is_negative)
1687 *--pos = '-';
1689 len = buffer + 65 - pos;
1690 if (len > size)
1692 size_t i;
1693 MSVCRT_wchar_t *p = str;
1695 /* Copy the temporary buffer backwards up to the available number of
1696 * characters. Don't copy the negative sign if present. */
1698 if (is_negative)
1700 p++;
1701 size--;
1704 for (pos = buffer + 63, i = 0; i < size; i++)
1705 *p++ = *pos--;
1707 str[0] = '\0';
1708 MSVCRT_INVALID_PMT("str[size] is too small", MSVCRT_ERANGE);
1709 return MSVCRT_ERANGE;
1712 memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1713 return 0;
1716 #define I10_OUTPUT_MAX_PREC 21
1717 /* Internal structure used by $I10_OUTPUT */
1718 struct _I10_OUTPUT_DATA {
1719 short pos;
1720 char sign;
1721 BYTE len;
1722 char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */
1725 /*********************************************************************
1726 * $I10_OUTPUT (MSVCRT.@)
1727 * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
1728 * prec - precision of part, we're interested in
1729 * flag - 0 for first prec digits, 1 for fractional part
1730 * data - data to be populated
1732 * return value
1733 * 0 if given double is NaN or INF
1734 * 1 otherwise
1736 * FIXME
1737 * Native sets last byte of data->str to '0' or '9', I don't know what
1738 * it means. Current implementation sets it always to '0'.
1740 int CDECL MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data)
1742 static const char inf_str[] = "1#INF";
1743 static const char nan_str[] = "1#QNAN";
1745 /* MS' long double type wants 12 bytes for Intel's 80 bit FP format.
1746 * Some UNIX have sizeof(long double) == 16, yet only 80 bit are used.
1747 * Assume long double uses 80 bit FP, never seen 128 bit FP. */
1748 long double ld = 0;
1749 double d;
1750 char format[8];
1751 char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
1752 char *p;
1754 memcpy(&ld, &ld80, 10);
1755 d = ld;
1756 TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
1758 if(d<0) {
1759 data->sign = '-';
1760 d = -d;
1761 } else
1762 data->sign = ' ';
1764 if(isinf(d)) {
1765 data->pos = 1;
1766 data->len = 5;
1767 memcpy(data->str, inf_str, sizeof(inf_str));
1769 return 0;
1772 if(isnan(d)) {
1773 data->pos = 1;
1774 data->len = 6;
1775 memcpy(data->str, nan_str, sizeof(nan_str));
1777 return 0;
1780 if(flag&1) {
1781 int exp = 1+floor(log10(d));
1783 prec += exp;
1784 if(exp < 0)
1785 prec--;
1787 prec--;
1789 if(prec+1 > I10_OUTPUT_MAX_PREC)
1790 prec = I10_OUTPUT_MAX_PREC-1;
1791 else if(prec < 0) {
1792 d = 0.0;
1793 prec = 0;
1796 sprintf(format, "%%.%dle", prec);
1797 sprintf(buf, format, d);
1799 buf[1] = buf[0];
1800 data->pos = atoi(buf+prec+3);
1801 if(buf[1] != '0')
1802 data->pos++;
1804 for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
1805 data->len = p-buf;
1807 memcpy(data->str, buf+1, data->len);
1808 data->str[data->len] = '\0';
1810 if(buf[1]!='0' && prec-data->len+1>0)
1811 memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1);
1813 return 1;
1815 #undef I10_OUTPUT_MAX_PREC
1817 /*********************************************************************
1818 * memcmp (MSVCRT.@)
1820 int __cdecl MSVCRT_memcmp(const void *ptr1, const void *ptr2, MSVCRT_size_t n)
1822 return memcmp(ptr1, ptr2, n);
1825 /*********************************************************************
1826 * memcpy (MSVCRT.@)
1828 void * __cdecl MSVCRT_memcpy(void *dst, const void *src, MSVCRT_size_t n)
1830 return memmove(dst, src, n);
1833 /*********************************************************************
1834 * memmove (MSVCRT.@)
1836 void * __cdecl MSVCRT_memmove(void *dst, const void *src, MSVCRT_size_t n)
1838 return memmove(dst, src, n);
1841 /*********************************************************************
1842 * memset (MSVCRT.@)
1844 void* __cdecl MSVCRT_memset(void *dst, int c, MSVCRT_size_t n)
1846 return memset(dst, c, n);
1849 /*********************************************************************
1850 * strchr (MSVCRT.@)
1852 char* __cdecl MSVCRT_strchr(const char *str, int c)
1854 return strchr(str, c);
1857 /*********************************************************************
1858 * strrchr (MSVCRT.@)
1860 char* __cdecl MSVCRT_strrchr(const char *str, int c)
1862 return strrchr(str, c);
1865 /*********************************************************************
1866 * memchr (MSVCRT.@)
1868 void* __cdecl MSVCRT_memchr(const void *ptr, int c, MSVCRT_size_t n)
1870 return memchr(ptr, c, n);
1873 /*********************************************************************
1874 * strcmp (MSVCRT.@)
1876 int __cdecl MSVCRT_strcmp(const char *str1, const char *str2)
1878 return strcmp(str1, str2);
1881 /*********************************************************************
1882 * strncmp (MSVCRT.@)
1884 int __cdecl MSVCRT_strncmp(const char *str1, const char *str2, MSVCRT_size_t len)
1886 return strncmp(str1, str2, len);
1889 /*********************************************************************
1890 * _strnicmp_l (MSVCRT.@)
1892 int __cdecl MSVCRT__strnicmp_l(const char *s1, const char *s2,
1893 MSVCRT_size_t count, MSVCRT__locale_t locale)
1895 MSVCRT_pthreadlocinfo locinfo;
1896 int c1, c2;
1898 if(s1==NULL || s2==NULL)
1899 return MSVCRT__NLSCMPERROR;
1901 if(!count)
1902 return 0;
1904 if(!locale)
1905 locinfo = get_locinfo();
1906 else
1907 locinfo = locale->locinfo;
1909 if(!locinfo->lc_handle[MSVCRT_LC_CTYPE])
1910 return strncasecmp(s1, s2, count);
1912 do {
1913 c1 = MSVCRT__tolower_l(*s1++, locale);
1914 c2 = MSVCRT__tolower_l(*s2++, locale);
1915 }while(--count && c1 && c1==c2);
1917 return c1-c2;
1920 /*********************************************************************
1921 * _stricmp_l (MSVCRT.@)
1923 int __cdecl MSVCRT__stricmp_l(const char *s1, const char *s2, MSVCRT__locale_t locale)
1925 return MSVCRT__strnicmp_l(s1, s2, -1, locale);
1928 /*********************************************************************
1929 * _strnicmp (MSVCRT.@)
1931 int __cdecl MSVCRT__strnicmp(const char *s1, const char *s2, MSVCRT_size_t count)
1933 return MSVCRT__strnicmp_l(s1, s2, count, NULL);
1936 /*********************************************************************
1937 * _stricmp (MSVCRT.@)
1939 int __cdecl MSVCRT__stricmp(const char *s1, const char *s2)
1941 return MSVCRT__strnicmp_l(s1, s2, -1, NULL);
1944 /*********************************************************************
1945 * strstr (MSVCRT.@)
1947 char* __cdecl MSVCRT_strstr(const char *haystack, const char *needle)
1949 return strstr(haystack, needle);
1952 /*********************************************************************
1953 * _memicmp_l (MSVCRT.@)
1955 int __cdecl MSVCRT__memicmp_l(const char *s1, const char *s2, MSVCRT_size_t len, MSVCRT__locale_t locale)
1957 int ret = 0;
1959 #if _MSVCR_VER == 0 || _MSVCR_VER >= 80
1960 if (!s1 || !s2)
1962 if (len)
1963 MSVCRT_INVALID_PMT(NULL, EINVAL);
1964 return len ? MSVCRT__NLSCMPERROR : 0;
1966 #endif
1968 while (len--)
1970 if ((ret = MSVCRT__tolower_l(*s1, locale) - MSVCRT__tolower_l(*s2, locale)))
1971 break;
1972 s1++;
1973 s2++;
1975 return ret;
1978 /*********************************************************************
1979 * _memicmp (MSVCRT.@)
1981 int __cdecl MSVCRT__memicmp(const char *s1, const char *s2, MSVCRT_size_t len)
1983 return MSVCRT__memicmp_l(s1, s2, len, NULL);