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