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