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