msvcrt/tests: sizeof(long double) is 12 with MS.
[wine] / dlls / msvcrt / string.c
1 /*
2  * MSVCRT string functions
3  *
4  * Copyright 1996,1998 Marcus Meissner
5  * Copyright 1996 Jukka Iivonen
6  * Copyright 1997,2000 Uwe Bonnes
7  * Copyright 2000 Jon Griffiths
8  *
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.
13  *
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.
18  *
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
22  */
23
24 #define _ISOC99_SOURCE
25 #include "config.h"
26 #include "wine/port.h"
27
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 "wine/debug.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
37
38 /*********************************************************************
39  *              _mbsdup (MSVCRT.@)
40  *              _strdup (MSVCRT.@)
41  */
42 char* CDECL _strdup(const char* str)
43 {
44     if(str)
45     {
46       char * ret = MSVCRT_malloc(strlen(str)+1);
47       if (ret) strcpy( ret, str );
48       return ret;
49     }
50     else return 0;
51 }
52
53 /*********************************************************************
54  *              _strlwr_s (MSVCRT.@)
55  */
56 int CDECL _strlwr_s(char *str, MSVCRT_size_t len)
57 {
58     char *ptr = str;
59
60     if (!str || !len)
61     {
62         *MSVCRT__errno() = MSVCRT_EINVAL;
63         return MSVCRT_EINVAL;
64     }
65
66     while (len && *ptr)
67     {
68         len--;
69         ptr++;
70     }
71
72     if (!len)
73     {
74         str[0] = '\0';
75         *MSVCRT__errno() = MSVCRT_EINVAL;
76         return MSVCRT_EINVAL;
77     }
78
79     while (*str)
80     {
81         *str = tolower(*str);
82         str++;
83     }
84
85     return 0;
86 }
87
88 /*********************************************************************
89  *              _strnset (MSVCRT.@)
90  */
91 char* CDECL MSVCRT__strnset(char* str, int value, MSVCRT_size_t len)
92 {
93   if (len > 0 && str)
94     while (*str && len--)
95       *str++ = value;
96   return str;
97 }
98
99 /*********************************************************************
100  *              _strrev (MSVCRT.@)
101  */
102 char* CDECL _strrev(char* str)
103 {
104   char * p1;
105   char * p2;
106
107   if (str && *str)
108     for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2)
109     {
110       *p1 ^= *p2;
111       *p2 ^= *p1;
112       *p1 ^= *p2;
113     }
114
115   return str;
116 }
117
118 /*********************************************************************
119  *              _strset (MSVCRT.@)
120  */
121 char* CDECL _strset(char* str, int value)
122 {
123   char *ptr = str;
124   while (*ptr)
125     *ptr++ = value;
126
127   return str;
128 }
129
130 /*********************************************************************
131  *              strtok  (MSVCRT.@)
132  */
133 char * CDECL MSVCRT_strtok( char *str, const char *delim )
134 {
135     thread_data_t *data = msvcrt_get_thread_data();
136     char *ret;
137
138     if (!str)
139         if (!(str = data->strtok_next)) return NULL;
140
141     while (*str && strchr( delim, *str )) str++;
142     if (!*str) return NULL;
143     ret = str++;
144     while (*str && !strchr( delim, *str )) str++;
145     if (*str) *str++ = 0;
146     data->strtok_next = str;
147     return ret;
148 }
149
150 /*********************************************************************
151  *              strtok_s  (MSVCRT.@)
152  */
153 char * CDECL MSVCRT_strtok_s(char *str, const char *delim, char **ctx)
154 {
155     if (!MSVCRT_CHECK_PMT(delim != NULL) || !MSVCRT_CHECK_PMT(ctx != NULL) ||
156         !MSVCRT_CHECK_PMT(str != NULL || *ctx != NULL)) {
157         *MSVCRT__errno() = MSVCRT_EINVAL;
158         return NULL;
159     }
160
161     if(!str)
162         str = *ctx;
163
164     while(*str && strchr(delim, *str))
165         str++;
166     if(!*str)
167         return NULL;
168
169     *ctx = str+1;
170     while(**ctx && !strchr(delim, **ctx))
171         (*ctx)++;
172     if(**ctx)
173         *(*ctx)++ = 0;
174
175     return str;
176 }
177
178 /*********************************************************************
179  *              _swab (MSVCRT.@)
180  */
181 void CDECL MSVCRT__swab(char* src, char* dst, int len)
182 {
183   if (len > 1)
184   {
185     len = (unsigned)len >> 1;
186
187     while (len--) {
188       char s0 = src[0];
189       char s1 = src[1];
190       *dst++ = s1;
191       *dst++ = s0;
192       src = src + 2;
193     }
194   }
195 }
196
197 /*********************************************************************
198  *              strtod_l  (MSVCRT.@)
199  */
200 double CDECL MSVCRT_strtod_l( const char *str, char **end, MSVCRT__locale_t locale)
201 {
202     unsigned __int64 d=0, hlp;
203     unsigned fpcontrol;
204     int exp=0, sign=1;
205     const char *p;
206     double ret;
207     BOOL found_digit = FALSE;
208
209     if (!MSVCRT_CHECK_PMT(str != NULL)) {
210         *MSVCRT__errno() = MSVCRT_EINVAL;
211         return 0;
212     }
213
214     if(!locale)
215         locale = get_locale();
216
217     /* FIXME: use *_l functions */
218     p = str;
219     while(isspace(*p))
220         p++;
221
222     if(*p == '-') {
223         sign = -1;
224         p++;
225     } else  if(*p == '+')
226         p++;
227
228     while(isdigit(*p)) {
229         found_digit = TRUE;
230         hlp = d*10+*(p++)-'0';
231         if(d>MSVCRT_UI64_MAX/10 || hlp<d) {
232             exp++;
233             break;
234         } else
235             d = hlp;
236     }
237     while(isdigit(*p)) {
238         exp++;
239         p++;
240     }
241
242     if(*p == *locale->locinfo->lconv->decimal_point)
243         p++;
244
245     while(isdigit(*p)) {
246         found_digit = TRUE;
247         hlp = d*10+*(p++)-'0';
248         if(d>MSVCRT_UI64_MAX/10 || hlp<d)
249             break;
250
251         d = hlp;
252         exp--;
253     }
254     while(isdigit(*p))
255         p++;
256
257     if(!found_digit) {
258         if(end)
259             *end = (char*)str;
260         return 0.0;
261     }
262
263     if(*p=='e' || *p=='E' || *p=='d' || *p=='D') {
264         int e=0, s=1;
265
266         p++;
267         if(*p == '-') {
268             s = -1;
269             p++;
270         } else if(*p == '+')
271             p++;
272
273         if(isdigit(*p)) {
274             while(isdigit(*p)) {
275                 if(e>INT_MAX/10 || (e=e*10+*p-'0')<0)
276                     e = INT_MAX;
277                 p++;
278             }
279             e *= s;
280
281             if(exp<0 && e<0 && exp+e>=0) exp = INT_MIN;
282             else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
283             else exp += e;
284         } else {
285             if(*p=='-' || *p=='+')
286                 p--;
287             p--;
288         }
289     }
290
291     fpcontrol = _control87(0, 0);
292     _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE
293             |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff);
294
295     if(exp>0)
296         ret = (double)sign*d*pow(10, exp);
297     else
298         ret = (double)sign*d/pow(10, -exp);
299
300     _control87(fpcontrol, 0xffffffff);
301
302     if((d && ret==0.0) || isinf(ret))
303         *MSVCRT__errno() = MSVCRT_ERANGE;
304
305     if(end)
306         *end = (char*)p;
307
308     return ret;
309 }
310
311 /*********************************************************************
312  *              strtod  (MSVCRT.@)
313  */
314 double CDECL MSVCRT_strtod( const char *str, char **end )
315 {
316     return MSVCRT_strtod_l( str, end, NULL );
317 }
318
319 /*********************************************************************
320  *              atof  (MSVCRT.@)
321  */
322 double CDECL MSVCRT_atof( const char *str )
323 {
324     return MSVCRT_strtod_l(str, NULL, NULL);
325 }
326
327 /*********************************************************************
328  *              _atof_l  (MSVCRT.@)
329  */
330 double CDECL MSVCRT__atof_l( const char *str, MSVCRT__locale_t locale)
331 {
332     return MSVCRT_strtod_l(str, NULL, locale);
333 }
334
335 /*********************************************************************
336  *              _atoflt_l  (MSVCRT.@)
337  */
338 int CDECL MSVCRT__atoflt_l( MSVCRT__CRT_FLOAT *value, char *str, MSVCRT__locale_t locale)
339 {
340     unsigned __int64 d=0, hlp;
341     unsigned fpcontrol;
342     int exp=0, sign=1;
343     const char *p;
344     int ret=0;
345     BOOL found_digit = FALSE;
346
347     if(!locale)
348         locale = get_locale();
349
350     /* FIXME: use *_l functions */
351     p = str;
352     while(isspace(*p))
353         p++;
354
355     if(*p == '-') {
356         sign = -1;
357         p++;
358     } else if(*p == '+')
359         p++;
360
361     while(isdigit(*p)) {
362         found_digit = TRUE;
363         hlp = d*10+*(p++)-'0';
364         if(d>MSVCRT_UI64_MAX/10 || hlp<d) {
365             exp++;
366             break;
367         } else
368             d = hlp;
369     }
370     while(isdigit(*p)) {
371         exp++;
372         p++;
373     }
374
375     if(*p == *locale->locinfo->lconv->decimal_point)
376         p++;
377
378     while(isdigit(*p)) {
379         found_digit = TRUE;
380         hlp = d*10+*(p++)-'0';
381         if(d>MSVCRT_UI64_MAX/10 || hlp<d)
382             break;
383
384         d = hlp;
385         exp--;
386     }
387     while(isdigit(*p))
388         p++;
389
390     if(!found_digit) {
391         value->f = 0.0;
392         return 0;
393     }
394
395     if(*p=='e' || *p=='E' || *p=='d' || *p=='D') {
396         int e=0, s=1;
397
398         p++;
399         if(*p == '-') {
400             s = -1;
401             p++;
402         } else if(*p == '+')
403             p++;
404
405         if(isdigit(*p)) {
406             while(isdigit(*p)) {
407                 if(e>INT_MAX/10 || (e=e*10+*p-'0')<0)
408                     e = INT_MAX;
409                 p++;
410             }
411             e *= s;
412
413             if(exp<0 && e<0 && exp+e>=0) exp = INT_MIN;
414             else if(exp>0 && e>0 && exp+e<0) exp = INT_MAX;
415             else exp += e;
416         } else {
417             if(*p=='-' || *p=='+')
418                 p--;
419             p--;
420         }
421     }
422
423     fpcontrol = _control87(0, 0);
424     _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE
425             |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff);
426
427     if(exp>0)
428         value->f = (float)sign*d*powf(10, exp);
429     else
430         value->f = (float)sign*d/powf(10, -exp);
431
432     _control87(fpcontrol, 0xffffffff);
433
434     if((d && value->f==0.0) || isinf(value->f))
435         ret = exp > 0 ? MSVCRT__OVERFLOW : MSVCRT__UNDERFLOW;
436
437     return ret;
438 }
439
440 /*********************************************************************
441  *              strcoll (MSVCRT.@)
442  */
443 int CDECL MSVCRT_strcoll( const char* str1, const char* str2 )
444 {
445     /* FIXME: handle Windows locale */
446     return strcoll( str1, str2 );
447 }
448
449 /*********************************************************************
450  *      strcpy_s (MSVCRT.@)
451  */
452 int CDECL MSVCRT_strcpy_s( char* dst, MSVCRT_size_t elem, const char* src )
453 {
454     MSVCRT_size_t i;
455     if(!elem) return MSVCRT_EINVAL;
456     if(!dst) return MSVCRT_EINVAL;
457     if(!src)
458     {
459         dst[0] = '\0';
460         return MSVCRT_EINVAL;
461     }
462
463     for(i = 0; i < elem; i++)
464     {
465         if((dst[i] = src[i]) == '\0') return 0;
466     }
467     dst[0] = '\0';
468     return MSVCRT_ERANGE;
469 }
470
471 /*********************************************************************
472  *      strcat_s (MSVCRT.@)
473  */
474 int CDECL MSVCRT_strcat_s( char* dst, MSVCRT_size_t elem, const char* src )
475 {
476     MSVCRT_size_t i, j;
477     if(!dst) return MSVCRT_EINVAL;
478     if(elem == 0) return MSVCRT_EINVAL;
479     if(!src)
480     {
481         dst[0] = '\0';
482         return MSVCRT_EINVAL;
483     }
484
485     for(i = 0; i < elem; i++)
486     {
487         if(dst[i] == '\0')
488         {
489             for(j = 0; (j + i) < elem; j++)
490             {
491                 if((dst[j + i] = src[j]) == '\0') return 0;
492             }
493         }
494     }
495     /* Set the first element to 0, not the first element after the skipped part */
496     dst[0] = '\0';
497     return MSVCRT_ERANGE;
498 }
499
500 /*********************************************************************
501  *      strncat_s (MSVCRT.@)
502  */
503 int CDECL MSVCRT_strncat_s( char* dst, MSVCRT_size_t elem, const char* src, MSVCRT_size_t count )
504 {
505     MSVCRT_size_t i, j;
506     if(!MSVCRT_CHECK_PMT(dst != 0) || !MSVCRT_CHECK_PMT(elem != 0))
507         return MSVCRT_EINVAL;
508     if(!MSVCRT_CHECK_PMT(src != 0))
509     {
510         dst[0] = '\0';
511         return MSVCRT_EINVAL;
512     }
513
514     for(i = 0; i < elem; i++)
515     {
516         if(dst[i] == '\0')
517         {
518             for(j = 0; (j + i) < elem; j++)
519             {
520                 if(count == MSVCRT__TRUNCATE && j + i == elem - 1)
521                 {
522                     dst[j + i] = '\0';
523                     return MSVCRT_STRUNCATE;
524                 }
525                 if(j == count || (dst[j + i] = src[j]) == '\0')
526                 {
527                     dst[j + i] = '\0';
528                     return 0;
529                 }
530             }
531         }
532     }
533     /* Set the first element to 0, not the first element after the skipped part */
534     dst[0] = '\0';
535     return MSVCRT_ERANGE;
536 }
537
538 /*********************************************************************
539  *              strxfrm (MSVCRT.@)
540  */
541 MSVCRT_size_t CDECL MSVCRT_strxfrm( char *dest, const char *src, MSVCRT_size_t len )
542 {
543     /* FIXME: handle Windows locale */
544     return strxfrm( dest, src, len );
545 }
546
547 /*********************************************************************
548  *              _stricoll (MSVCRT.@)
549  */
550 int CDECL MSVCRT__stricoll( const char* str1, const char* str2 )
551 {
552   /* FIXME: handle collates */
553   TRACE("str1 %s str2 %s\n", debugstr_a(str1), debugstr_a(str2));
554   return lstrcmpiA( str1, str2 );
555 }
556
557 /********************************************************************
558  *              _atoldbl (MSVCRT.@)
559  */
560 int CDECL MSVCRT__atoldbl(MSVCRT__LDOUBLE *value, const char *str)
561 {
562   /* FIXME needs error checking for huge/small values */
563 #ifdef HAVE_STRTOLD
564   long double ld;
565   TRACE("str %s value %p\n",str,value);
566   ld = strtold(str,0);
567   memcpy(value, &ld, 10);
568 #else
569   FIXME("stub, str %s value %p\n",str,value);
570 #endif
571   return 0;
572 }
573
574 /********************************************************************
575  *              __STRINGTOLD (MSVCRT.@)
576  */
577 int CDECL __STRINGTOLD( MSVCRT__LDOUBLE *value, char **endptr, const char *str, int flags )
578 {
579 #ifdef HAVE_STRTOLD
580     long double ld;
581     FIXME("%p %p %s %x partial stub\n", value, endptr, str, flags );
582     ld = strtold(str,0);
583     memcpy(value, &ld, 10);
584 #else
585     FIXME("%p %p %s %x stub\n", value, endptr, str, flags );
586 #endif
587     return 0;
588 }
589
590 /******************************************************************
591  *              strtol (MSVCRT.@)
592  */
593 MSVCRT_long CDECL MSVCRT_strtol(const char* nptr, char** end, int base)
594 {
595     /* wrapper to forward libc error code to msvcrt's error codes */
596     long ret;
597
598     errno = 0;
599     ret = strtol(nptr, end, base);
600     switch (errno)
601     {
602     case ERANGE:        *MSVCRT__errno() = MSVCRT_ERANGE;       break;
603     case EINVAL:        *MSVCRT__errno() = MSVCRT_EINVAL;       break;
604     default:
605         /* cope with the fact that we may use 64bit long integers on libc
606          * while msvcrt always uses 32bit long integers
607          */
608         if (ret > MSVCRT_LONG_MAX)
609         {
610             ret = MSVCRT_LONG_MAX;
611             *MSVCRT__errno() = MSVCRT_ERANGE;
612         }
613         else if (ret < -MSVCRT_LONG_MAX - 1)
614         {
615             ret = -MSVCRT_LONG_MAX - 1;
616             *MSVCRT__errno() = MSVCRT_ERANGE;
617         }
618         break;
619     }
620
621     return ret;
622 }
623
624 /******************************************************************
625  *              strtoul (MSVCRT.@)
626  */
627 MSVCRT_ulong CDECL MSVCRT_strtoul(const char* nptr, char** end, int base)
628 {
629     /* wrapper to forward libc error code to msvcrt's error codes */
630     unsigned long ret;
631
632     errno = 0;
633     ret = strtoul(nptr, end, base);
634     switch (errno)
635     {
636     case ERANGE:        *MSVCRT__errno() = MSVCRT_ERANGE;       break;
637     case EINVAL:        *MSVCRT__errno() = MSVCRT_EINVAL;       break;
638     default:
639         /* cope with the fact that we may use 64bit long integers on libc
640          * while msvcrt always uses 32bit long integers
641          */
642         if (ret > MSVCRT_ULONG_MAX)
643         {
644             ret = MSVCRT_ULONG_MAX;
645             *MSVCRT__errno() = MSVCRT_ERANGE;
646         }
647         break;
648     }
649
650     return ret;
651 }
652
653 /******************************************************************
654  *              strnlen (MSVCRT.@)
655  */
656 MSVCRT_size_t CDECL MSVCRT_strnlen(const char *s, MSVCRT_size_t maxlen)
657 {
658     MSVCRT_size_t i;
659
660     for(i=0; i<maxlen; i++)
661         if(!s[i]) break;
662
663     return i;
664 }
665
666 /*********************************************************************
667  *  _strtoi64_l (MSVCRT.@)
668  *
669  * FIXME: locale parameter is ignored
670  */
671 __int64 CDECL MSVCRT_strtoi64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
672 {
673     BOOL negative = FALSE;
674     __int64 ret = 0;
675
676     TRACE("(%s %p %d %p)\n", nptr, endptr, base, locale);
677
678     if (!MSVCRT_CHECK_PMT(nptr != NULL) || !MSVCRT_CHECK_PMT(base == 0 || base >= 2) ||
679         !MSVCRT_CHECK_PMT(base <= 36)) {
680         return 0;
681     }
682
683     while(isspace(*nptr)) nptr++;
684
685     if(*nptr == '-') {
686         negative = TRUE;
687         nptr++;
688     } else if(*nptr == '+')
689         nptr++;
690
691     if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
692         base = 16;
693         nptr += 2;
694     }
695
696     if(base == 0) {
697         if(*nptr=='0')
698             base = 8;
699         else
700             base = 10;
701     }
702
703     while(*nptr) {
704         char cur = tolower(*nptr);
705         int v;
706
707         if(isdigit(cur)) {
708             if(cur >= '0'+base)
709                 break;
710             v = cur-'0';
711         } else {
712             if(cur<'a' || cur>='a'+base-10)
713                 break;
714             v = cur-'a'+10;
715         }
716
717         if(negative)
718             v = -v;
719
720         nptr++;
721
722         if(!negative && (ret>MSVCRT_I64_MAX/base || ret*base>MSVCRT_I64_MAX-v)) {
723             ret = MSVCRT_I64_MAX;
724             *MSVCRT__errno() = MSVCRT_ERANGE;
725         } else if(negative && (ret<MSVCRT_I64_MIN/base || ret*base<MSVCRT_I64_MIN-v)) {
726             ret = MSVCRT_I64_MIN;
727             *MSVCRT__errno() = MSVCRT_ERANGE;
728         } else
729             ret = ret*base + v;
730     }
731
732     if(endptr)
733         *endptr = (char*)nptr;
734
735     return ret;
736 }
737
738 /*********************************************************************
739  *  _strtoi64 (MSVCRT.@)
740  */
741 __int64 CDECL MSVCRT_strtoi64(const char *nptr, char **endptr, int base)
742 {
743     return MSVCRT_strtoi64_l(nptr, endptr, base, NULL);
744 }
745
746 /*********************************************************************
747  *  _strtoui64_l (MSVCRT.@)
748  *
749  * FIXME: locale parameter is ignored
750  */
751 unsigned __int64 CDECL MSVCRT_strtoui64_l(const char *nptr, char **endptr, int base, MSVCRT__locale_t locale)
752 {
753     BOOL negative = FALSE;
754     unsigned __int64 ret = 0;
755
756     TRACE("(%s %p %d %p)\n", nptr, endptr, base, locale);
757
758     if (!MSVCRT_CHECK_PMT(nptr != NULL) || !MSVCRT_CHECK_PMT(base == 0 || base >= 2) ||
759         !MSVCRT_CHECK_PMT(base <= 36)) {
760         return 0;
761     }
762
763     while(isspace(*nptr)) nptr++;
764
765     if(*nptr == '-') {
766         negative = TRUE;
767         nptr++;
768     } else if(*nptr == '+')
769         nptr++;
770
771     if((base==0 || base==16) && *nptr=='0' && tolower(*(nptr+1))=='x') {
772         base = 16;
773         nptr += 2;
774     }
775
776     if(base == 0) {
777         if(*nptr=='0')
778             base = 8;
779         else
780             base = 10;
781     }
782
783     while(*nptr) {
784         char cur = tolower(*nptr);
785         int v;
786
787         if(isdigit(cur)) {
788             if(cur >= '0'+base)
789                 break;
790             v = *nptr-'0';
791         } else {
792             if(cur<'a' || cur>='a'+base-10)
793                 break;
794             v = cur-'a'+10;
795         }
796
797         nptr++;
798
799         if(ret>MSVCRT_UI64_MAX/base || ret*base>MSVCRT_UI64_MAX-v) {
800             ret = MSVCRT_UI64_MAX;
801             *MSVCRT__errno() = MSVCRT_ERANGE;
802         } else
803             ret = ret*base + v;
804     }
805
806     if(endptr)
807         *endptr = (char*)nptr;
808
809     return negative ? -ret : ret;
810 }
811
812 /*********************************************************************
813  *  _strtoui64 (MSVCRT.@)
814  */
815 unsigned __int64 CDECL MSVCRT_strtoui64(const char *nptr, char **endptr, int base)
816 {
817     return MSVCRT_strtoui64_l(nptr, endptr, base, NULL);
818 }
819
820 /*********************************************************************
821  *  _ltoa_s (MSVCRT.@)
822  */
823 int CDECL _ltoa_s(MSVCRT_long value, char *str, MSVCRT_size_t size, int radix)
824 {
825     MSVCRT_ulong val;
826     unsigned int digit;
827     int is_negative;
828     char buffer[33], *pos;
829     size_t len;
830
831     if (!MSVCRT_CHECK_PMT(str != NULL) || !MSVCRT_CHECK_PMT(size > 0) ||
832         !MSVCRT_CHECK_PMT(radix >= 2) || !MSVCRT_CHECK_PMT(radix <= 36))
833     {
834         if (str && size)
835             str[0] = '\0';
836
837         *MSVCRT__errno() = MSVCRT_EINVAL;
838         return MSVCRT_EINVAL;
839     }
840
841     if (value < 0 && radix == 10)
842     {
843         is_negative = 1;
844         val = -value;
845     }
846     else
847     {
848         is_negative = 0;
849         val = value;
850     }
851
852     pos = buffer + 32;
853     *pos = '\0';
854
855     do
856     {
857         digit = val % radix;
858         val /= radix;
859
860         if (digit < 10)
861             *--pos = '0' + digit;
862         else
863             *--pos = 'a' + digit - 10;
864     }
865     while (val != 0);
866
867     if (is_negative)
868         *--pos = '-';
869
870     len = buffer + 33 - pos;
871     if (len > size)
872     {
873         size_t i;
874         char *p = str;
875
876         /* Copy the temporary buffer backwards up to the available number of
877          * characters. Don't copy the negative sign if present. */
878
879         if (is_negative)
880         {
881             p++;
882             size--;
883         }
884
885         for (pos = buffer + 31, i = 0; i < size; i++)
886             *p++ = *pos--;
887
888         str[0] = '\0';
889         MSVCRT_INVALID_PMT("str[size] is too small");
890         *MSVCRT__errno() = MSVCRT_ERANGE;
891         return MSVCRT_ERANGE;
892     }
893
894     memcpy(str, pos, len);
895     return 0;
896 }
897
898 /*********************************************************************
899  *  _ltow_s (MSVCRT.@)
900  */
901 int CDECL _ltow_s(MSVCRT_long value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
902 {
903     MSVCRT_ulong val;
904     unsigned int digit;
905     int is_negative;
906     MSVCRT_wchar_t buffer[33], *pos;
907     size_t len;
908
909     if (!MSVCRT_CHECK_PMT(str != NULL) || !MSVCRT_CHECK_PMT(size > 0) ||
910         !MSVCRT_CHECK_PMT(radix >= 2) || !MSVCRT_CHECK_PMT(radix <= 36))
911     {
912         if (str && size)
913             str[0] = '\0';
914
915         *MSVCRT__errno() = MSVCRT_EINVAL;
916         return MSVCRT_EINVAL;
917     }
918
919     if (value < 0 && radix == 10)
920     {
921         is_negative = 1;
922         val = -value;
923     }
924     else
925     {
926         is_negative = 0;
927         val = value;
928     }
929
930     pos = buffer + 32;
931     *pos = '\0';
932
933     do
934     {
935         digit = val % radix;
936         val /= radix;
937
938         if (digit < 10)
939             *--pos = '0' + digit;
940         else
941             *--pos = 'a' + digit - 10;
942     }
943     while (val != 0);
944
945     if (is_negative)
946         *--pos = '-';
947
948     len = buffer + 33 - pos;
949     if (len > size)
950     {
951         size_t i;
952         MSVCRT_wchar_t *p = str;
953
954         /* Copy the temporary buffer backwards up to the available number of
955          * characters. Don't copy the negative sign if present. */
956
957         if (is_negative)
958         {
959             p++;
960             size--;
961         }
962
963         for (pos = buffer + 31, i = 0; i < size; i++)
964             *p++ = *pos--;
965
966         MSVCRT_INVALID_PMT("str[size] is too small");
967         str[0] = '\0';
968         *MSVCRT__errno() = MSVCRT_ERANGE;
969         return MSVCRT_ERANGE;
970     }
971
972     memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
973     return 0;
974 }
975
976 /*********************************************************************
977  *  _itoa_s (MSVCRT.@)
978  */
979 int CDECL _itoa_s(int value, char *str, MSVCRT_size_t size, int radix)
980 {
981     return _ltoa_s(value, str, size, radix);
982 }
983
984 /*********************************************************************
985  *  _itow_s (MSVCRT.@)
986  */
987 int CDECL _itow_s(int value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
988 {
989     return _ltow_s(value, str, size, radix);
990 }
991
992 /*********************************************************************
993  *  _ui64toa_s (MSVCRT.@)
994  */
995 int CDECL MSVCRT__ui64toa_s(unsigned __int64 value, char *str,
996         MSVCRT_size_t size, int radix)
997 {
998     char buffer[65], *pos;
999     int digit;
1000
1001     if (!MSVCRT_CHECK_PMT(str != NULL) || !MSVCRT_CHECK_PMT(size > 0) ||
1002         !MSVCRT_CHECK_PMT(radix>=2) || !MSVCRT_CHECK_PMT(radix<=36)) {
1003         *MSVCRT__errno() = MSVCRT_EINVAL;
1004         return MSVCRT_EINVAL;
1005     }
1006
1007     pos = buffer+64;
1008     *pos = '\0';
1009
1010     do {
1011         digit = value%radix;
1012         value /= radix;
1013
1014         if(digit < 10)
1015             *--pos = '0'+digit;
1016         else
1017             *--pos = 'a'+digit-10;
1018     }while(value != 0);
1019
1020     if(buffer-pos+65 > size) {
1021         MSVCRT_INVALID_PMT("str[size] is too small");
1022         *MSVCRT__errno() = MSVCRT_EINVAL;
1023         return MSVCRT_EINVAL;
1024     }
1025
1026     memcpy(str, pos, buffer-pos+65);
1027     return 0;
1028 }
1029
1030 /*********************************************************************
1031  *      _ui64tow_s  (MSVCRT.@)
1032  */
1033 int CDECL MSVCRT__ui64tow_s( unsigned __int64 value, MSVCRT_wchar_t *str,
1034                              MSVCRT_size_t size, int radix )
1035 {
1036     MSVCRT_wchar_t buffer[65], *pos;
1037     int digit;
1038
1039     if (!MSVCRT_CHECK_PMT(str != NULL) || !MSVCRT_CHECK_PMT(size > 0) ||
1040         !MSVCRT_CHECK_PMT(radix>=2) || !MSVCRT_CHECK_PMT(radix<=36)) {
1041         *MSVCRT__errno() = MSVCRT_EINVAL;
1042         return MSVCRT_EINVAL;
1043     }
1044
1045     pos = &buffer[64];
1046     *pos = '\0';
1047
1048     do {
1049         digit = value % radix;
1050         value = value / radix;
1051         if (digit < 10)
1052             *--pos = '0' + digit;
1053         else
1054             *--pos = 'a' + digit - 10;
1055     } while (value != 0);
1056
1057     if(buffer-pos+65 > size) {
1058         MSVCRT_INVALID_PMT("str[size] is too small");
1059         *MSVCRT__errno() = MSVCRT_EINVAL;
1060         return MSVCRT_EINVAL;
1061     }
1062
1063     memcpy(str, pos, buffer-pos+65);
1064     return 0;
1065 }
1066
1067 /*********************************************************************
1068  *  _ultoa_s (MSVCRT.@)
1069  */
1070 int CDECL _ultoa_s(MSVCRT_ulong value, char *str, MSVCRT_size_t size, int radix)
1071 {
1072     MSVCRT_ulong digit;
1073     char buffer[33], *pos;
1074     size_t len;
1075
1076     if (!str || !size || radix < 2 || radix > 36)
1077     {
1078         if (str && size)
1079             str[0] = '\0';
1080
1081         *MSVCRT__errno() = MSVCRT_EINVAL;
1082         return MSVCRT_EINVAL;
1083     }
1084
1085     pos = buffer + 32;
1086     *pos = '\0';
1087
1088     do
1089     {
1090         digit = value % radix;
1091         value /= radix;
1092
1093         if (digit < 10)
1094             *--pos = '0' + digit;
1095         else
1096             *--pos = 'a' + digit - 10;
1097     }
1098     while (value != 0);
1099
1100     len = buffer + 33 - pos;
1101     if (len > size)
1102     {
1103         size_t i;
1104         char *p = str;
1105
1106         /* Copy the temporary buffer backwards up to the available number of
1107          * characters. */
1108
1109         for (pos = buffer + 31, i = 0; i < size; i++)
1110             *p++ = *pos--;
1111
1112         str[0] = '\0';
1113         *MSVCRT__errno() = MSVCRT_ERANGE;
1114         return MSVCRT_ERANGE;
1115     }
1116
1117     memcpy(str, pos, len);
1118     return 0;
1119 }
1120
1121 /*********************************************************************
1122  *  _i64toa_s (MSVCRT.@)
1123  */
1124 int CDECL _i64toa_s(__int64 value, char *str, MSVCRT_size_t size, int radix)
1125 {
1126     unsigned __int64 val;
1127     unsigned int digit;
1128     int is_negative;
1129     char buffer[65], *pos;
1130     size_t len;
1131
1132     if (!MSVCRT_CHECK_PMT(str != NULL) || !MSVCRT_CHECK_PMT(size > 0) ||
1133         !MSVCRT_CHECK_PMT(radix >= 2) || !MSVCRT_CHECK_PMT(radix <= 36))
1134     {
1135         if (str && size)
1136             str[0] = '\0';
1137
1138         *MSVCRT__errno() = MSVCRT_EINVAL;
1139         return MSVCRT_EINVAL;
1140     }
1141
1142     if (value < 0 && radix == 10)
1143     {
1144         is_negative = 1;
1145         val = -value;
1146     }
1147     else
1148     {
1149         is_negative = 0;
1150         val = value;
1151     }
1152
1153     pos = buffer + 64;
1154     *pos = '\0';
1155
1156     do
1157     {
1158         digit = val % radix;
1159         val /= radix;
1160
1161         if (digit < 10)
1162             *--pos = '0' + digit;
1163         else
1164             *--pos = 'a' + digit - 10;
1165     }
1166     while (val != 0);
1167
1168     if (is_negative)
1169         *--pos = '-';
1170
1171     len = buffer + 65 - pos;
1172     if (len > size)
1173     {
1174         size_t i;
1175         char *p = str;
1176
1177         /* Copy the temporary buffer backwards up to the available number of
1178          * characters. Don't copy the negative sign if present. */
1179
1180         if (is_negative)
1181         {
1182             p++;
1183             size--;
1184         }
1185
1186         for (pos = buffer + 63, i = 0; i < size; i++)
1187             *p++ = *pos--;
1188
1189         str[0] = '\0';
1190         MSVCRT_INVALID_PMT("str[size] is too small");
1191         *MSVCRT__errno() = MSVCRT_ERANGE;
1192         return MSVCRT_ERANGE;
1193     }
1194
1195     memcpy(str, pos, len);
1196     return 0;
1197 }
1198
1199 /*********************************************************************
1200  *  _i64tow_s (MSVCRT.@)
1201  */
1202 int CDECL _i64tow_s(__int64 value, MSVCRT_wchar_t *str, MSVCRT_size_t size, int radix)
1203 {
1204     unsigned __int64 val;
1205     unsigned int digit;
1206     int is_negative;
1207     MSVCRT_wchar_t buffer[65], *pos;
1208     size_t len;
1209
1210     if (!MSVCRT_CHECK_PMT(str != NULL) || !MSVCRT_CHECK_PMT(size > 0) ||
1211         !MSVCRT_CHECK_PMT(radix >= 2) || !MSVCRT_CHECK_PMT(radix <= 36))
1212     {
1213         if (str && size)
1214             str[0] = '\0';
1215
1216         *MSVCRT__errno() = MSVCRT_EINVAL;
1217         return MSVCRT_EINVAL;
1218     }
1219
1220     if (value < 0 && radix == 10)
1221     {
1222         is_negative = 1;
1223         val = -value;
1224     }
1225     else
1226     {
1227         is_negative = 0;
1228         val = value;
1229     }
1230
1231     pos = buffer + 64;
1232     *pos = '\0';
1233
1234     do
1235     {
1236         digit = val % radix;
1237         val /= radix;
1238
1239         if (digit < 10)
1240             *--pos = '0' + digit;
1241         else
1242             *--pos = 'a' + digit - 10;
1243     }
1244     while (val != 0);
1245
1246     if (is_negative)
1247         *--pos = '-';
1248
1249     len = buffer + 65 - pos;
1250     if (len > size)
1251     {
1252         size_t i;
1253         MSVCRT_wchar_t *p = str;
1254
1255         /* Copy the temporary buffer backwards up to the available number of
1256          * characters. Don't copy the negative sign if present. */
1257
1258         if (is_negative)
1259         {
1260             p++;
1261             size--;
1262         }
1263
1264         for (pos = buffer + 63, i = 0; i < size; i++)
1265             *p++ = *pos--;
1266
1267         MSVCRT_INVALID_PMT("str[size] is too small");
1268         str[0] = '\0';
1269         *MSVCRT__errno() = MSVCRT_ERANGE;
1270         return MSVCRT_ERANGE;
1271     }
1272
1273     memcpy(str, pos, len * sizeof(MSVCRT_wchar_t));
1274     return 0;
1275 }
1276
1277 #define I10_OUTPUT_MAX_PREC 21
1278 /* Internal structure used by $I10_OUTPUT */
1279 struct _I10_OUTPUT_DATA {
1280     short pos;
1281     char sign;
1282     BYTE len;
1283     char str[I10_OUTPUT_MAX_PREC+1]; /* add space for '\0' */
1284 };
1285
1286 /*********************************************************************
1287  *              $I10_OUTPUT (MSVCRT.@)
1288  * ld80 - long double (Intel 80 bit FP in 12 bytes) to be printed to data
1289  * prec - precision of part, we're interested in
1290  * flag - 0 for first prec digits, 1 for fractional part
1291  * data - data to be populated
1292  *
1293  * return value
1294  *      0 if given double is NaN or INF
1295  *      1 otherwise
1296  *
1297  * FIXME
1298  *      Native sets last byte of data->str to '0' or '9', I don't know what
1299  *      it means. Current implementation sets it always to '0'.
1300  */
1301 int CDECL MSVCRT_I10_OUTPUT(MSVCRT__LDOUBLE ld80, int prec, int flag, struct _I10_OUTPUT_DATA *data)
1302 {
1303     static const char inf_str[] = "1#INF";
1304     static const char nan_str[] = "1#QNAN";
1305
1306     /* MS' long double type wants 12 bytes for Intel's 80 bit FP format.
1307      * Some UNIX have sizeof(long double) == 16, yet only 80 bit are used.
1308      * Assume long double uses 80 bit FP, never seen 128 bit FP. */
1309     long double ld = 0;
1310     double d;
1311     char format[8];
1312     char buf[I10_OUTPUT_MAX_PREC+9]; /* 9 = strlen("0.e+0000") + '\0' */
1313     char *p;
1314
1315     memcpy(&ld, &ld80, 10);
1316     d = ld;
1317     TRACE("(%lf %d %x %p)\n", d, prec, flag, data);
1318
1319     if(d<0) {
1320         data->sign = '-';
1321         d = -d;
1322     } else
1323         data->sign = ' ';
1324
1325     if(isinf(d)) {
1326         data->pos = 1;
1327         data->len = 5;
1328         memcpy(data->str, inf_str, sizeof(inf_str));
1329
1330         return 0;
1331     }
1332
1333     if(isnan(d)) {
1334         data->pos = 1;
1335         data->len = 6;
1336         memcpy(data->str, nan_str, sizeof(nan_str));
1337
1338         return 0;
1339     }
1340
1341     if(flag&1) {
1342         int exp = 1+floor(log10(d));
1343
1344         prec += exp;
1345         if(exp < 0)
1346             prec--;
1347     }
1348     prec--;
1349
1350     if(prec+1 > I10_OUTPUT_MAX_PREC)
1351         prec = I10_OUTPUT_MAX_PREC-1;
1352     else if(prec < 0) {
1353         d = 0.0;
1354         prec = 0;
1355     }
1356
1357     sprintf(format, "%%.%dle", prec);
1358     sprintf(buf, format, d);
1359
1360     buf[1] = buf[0];
1361     data->pos = atoi(buf+prec+3);
1362     if(buf[1] != '0')
1363         data->pos++;
1364
1365     for(p = buf+prec+1; p>buf+1 && *p=='0'; p--);
1366     data->len = p-buf;
1367
1368     memcpy(data->str, buf+1, data->len);
1369     data->str[data->len] = '\0';
1370
1371     if(buf[1]!='0' && prec-data->len+1>0)
1372         memcpy(data->str+data->len+1, buf+data->len+1, prec-data->len+1);
1373
1374     return 1;
1375 }
1376 #undef I10_OUTPUT_MAX_PREC