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