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