Implement _itoa, _ltoa, _ultoa, _i64toa, _ui64toa, _itow, _ltow,
[wine] / dlls / ntdll / wcstring.c
1 /*
2  * NTDLL wide-char functions
3  *
4  * Copyright 2000 Alexandre Julliard
5  * Copyright 2000 Jon Griffiths
6  * Copyright 2003 Thomas Mertes
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "config.h"
24
25 #include <ctype.h>
26 #include <limits.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <stdio.h>
30
31 #include "winternl.h"
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
36
37
38 /*********************************************************************
39  *           _wcsicmp    (NTDLL.@)
40  */
41 INT __cdecl NTDLL__wcsicmp( LPCWSTR str1, LPCWSTR str2 )
42 {
43     return strcmpiW( str1, str2 );
44 }
45
46
47 /*********************************************************************
48  *           _wcslwr    (NTDLL.@)
49  */
50 LPWSTR __cdecl NTDLL__wcslwr( LPWSTR str )
51 {
52     return strlwrW( str );
53 }
54
55
56 /*********************************************************************
57  *           _wcsnicmp    (NTDLL.@)
58  */
59 INT __cdecl NTDLL__wcsnicmp( LPCWSTR str1, LPCWSTR str2, INT n )
60 {
61     return strncmpiW( str1, str2, n );
62 }
63
64
65 /*********************************************************************
66  *           _wcsupr    (NTDLL.@)
67  */
68 LPWSTR __cdecl NTDLL__wcsupr( LPWSTR str )
69 {
70     return struprW( str );
71 }
72
73
74 /*********************************************************************
75  *           towlower    (NTDLL.@)
76  */
77 WCHAR __cdecl NTDLL_towlower( WCHAR ch )
78 {
79     return tolowerW(ch);
80 }
81
82
83 /*********************************************************************
84  *           towupper    (NTDLL.@)
85  */
86 WCHAR __cdecl NTDLL_towupper( WCHAR ch )
87 {
88     return toupperW(ch);
89 }
90
91
92 /***********************************************************************
93  *           wcscat    (NTDLL.@)
94  */
95 LPWSTR __cdecl NTDLL_wcscat( LPWSTR dst, LPCWSTR src )
96 {
97     return strcatW( dst, src );
98 }
99
100
101 /*********************************************************************
102  *           wcschr    (NTDLL.@)
103  */
104 LPWSTR __cdecl NTDLL_wcschr( LPCWSTR str, WCHAR ch )
105 {
106     return strchrW( str, ch );
107 }
108
109
110 /*********************************************************************
111  *           wcscmp    (NTDLL.@)
112  */
113 INT __cdecl NTDLL_wcscmp( LPCWSTR str1, LPCWSTR str2 )
114 {
115     return strcmpW( str1, str2 );
116 }
117
118
119 /***********************************************************************
120  *           wcscpy    (NTDLL.@)
121  */
122 LPWSTR __cdecl NTDLL_wcscpy( LPWSTR dst, LPCWSTR src )
123 {
124     return strcpyW( dst, src );
125 }
126
127
128 /*********************************************************************
129  *           wcscspn    (NTDLL.@)
130  */
131 INT __cdecl NTDLL_wcscspn( LPCWSTR str, LPCWSTR reject )
132 {
133     LPCWSTR start = str;
134     while (*str)
135     {
136         LPCWSTR p = reject;
137         while (*p && (*p != *str)) p++;
138         if (*p) break;
139         str++;
140     }
141     return str - start;
142 }
143
144
145 /***********************************************************************
146  *           wcslen    (NTDLL.@)
147  */
148 INT __cdecl NTDLL_wcslen( LPCWSTR str )
149 {
150     return strlenW( str );
151 }
152
153
154 /*********************************************************************
155  *           wcsncat    (NTDLL.@)
156  */
157 LPWSTR __cdecl NTDLL_wcsncat( LPWSTR s1, LPCWSTR s2, INT n )
158 {
159     LPWSTR ret = s1;
160     while (*s1) s1++;
161     while (n-- > 0) if (!(*s1++ = *s2++)) return ret;
162     *s1 = 0;
163     return ret;
164 }
165
166
167 /*********************************************************************
168  *           wcsncmp    (NTDLL.@)
169  */
170 INT __cdecl NTDLL_wcsncmp( LPCWSTR str1, LPCWSTR str2, INT n )
171 {
172     return strncmpW( str1, str2, n );
173 }
174
175
176 /*********************************************************************
177  *           wcsncpy    (NTDLL.@)
178  */
179 LPWSTR __cdecl NTDLL_wcsncpy( LPWSTR s1, LPCWSTR s2, INT n )
180 {
181     return strncpyW( s1, s2, n );
182 }
183
184
185 /*********************************************************************
186  *           wcspbrk    (NTDLL.@)
187  */
188 LPWSTR __cdecl NTDLL_wcspbrk( LPCWSTR str, LPCWSTR accept )
189 {
190     LPCWSTR p;
191     while (*str)
192     {
193         for (p = accept; *p; p++) if (*p == *str) return (LPWSTR)str;
194         str++;
195     }
196     return NULL;
197 }
198
199
200 /*********************************************************************
201  *           wcsrchr    (NTDLL.@)
202  */
203 LPWSTR __cdecl NTDLL_wcsrchr( LPWSTR str, WCHAR ch )
204 {
205     LPWSTR last = NULL;
206     while (*str)
207     {
208         if (*str == ch) last = str;
209         str++;
210     }
211     return last;
212 }
213
214
215 /*********************************************************************
216  *           wcsspn    (NTDLL.@)
217  */
218 INT __cdecl NTDLL_wcsspn( LPCWSTR str, LPCWSTR accept )
219 {
220     LPCWSTR start = str;
221     while (*str)
222     {
223         LPCWSTR p = accept;
224         while (*p && (*p != *str)) p++;
225         if (!*p) break;
226         str++;
227     }
228     return str - start;
229 }
230
231
232 /*********************************************************************
233  *           wcsstr    (NTDLL.@)
234  */
235 LPWSTR __cdecl NTDLL_wcsstr( LPCWSTR str, LPCWSTR sub )
236 {
237     return strstrW( str, sub );
238 }
239
240
241 /*********************************************************************
242  *           wcstok    (NTDLL.@)
243  */
244 LPWSTR __cdecl NTDLL_wcstok( LPWSTR str, LPCWSTR delim )
245 {
246     static LPWSTR next = NULL;
247     LPWSTR ret;
248
249     if (!str)
250         if (!(str = next)) return NULL;
251
252     while (*str && NTDLL_wcschr( delim, *str )) str++;
253     if (!*str) return NULL;
254     ret = str++;
255     while (*str && !NTDLL_wcschr( delim, *str )) str++;
256     if (*str) *str++ = 0;
257     next = str;
258     return ret;
259 }
260
261
262 /*********************************************************************
263  *           wcstombs    (NTDLL.@)
264  */
265 INT __cdecl NTDLL_wcstombs( LPSTR dst, LPCWSTR src, INT n )
266 {
267     DWORD len;
268
269     if (!dst)
270     {
271         RtlUnicodeToMultiByteSize( &len, src, strlenW(src)*sizeof(WCHAR) );
272         return len;
273     }
274     else
275     {
276         if (n <= 0) return 0;
277         RtlUnicodeToMultiByteN( dst, n, &len, src, strlenW(src)*sizeof(WCHAR) );
278         if (len < n) dst[len] = 0;
279     }
280     return len;
281 }
282
283
284 /*********************************************************************
285  *           mbstowcs    (NTDLL.@)
286  */
287 INT __cdecl NTDLL_mbstowcs( LPWSTR dst, LPCSTR src, INT n )
288 {
289     DWORD len;
290
291     if (!dst)
292     {
293         RtlMultiByteToUnicodeSize( &len, src, strlen(src) );
294     }
295     else
296     {
297         if (n <= 0) return 0;
298         RtlMultiByteToUnicodeN( dst, n*sizeof(WCHAR), &len, src, strlen(src) );
299         if (len / sizeof(WCHAR) < n) dst[len / sizeof(WCHAR)] = 0;
300     }
301     return len / sizeof(WCHAR);
302 }
303
304
305 /*********************************************************************
306  *                  wcstol  (NTDLL.@)
307  */
308 long __cdecl NTDLL_wcstol(LPCWSTR s,LPWSTR *end,INT base)
309 {
310     return strtolW( s, end, base );
311 }
312
313
314 /*********************************************************************
315  *                  wcstoul  (NTDLL.@)
316  */
317 unsigned long __cdecl NTDLL_wcstoul(LPCWSTR s,LPWSTR *end,INT base)
318 {
319     return strtoulW( s, end, base );
320 }
321
322
323 /*********************************************************************
324  *           iswctype    (NTDLL.@)
325  */
326 INT __cdecl NTDLL_iswctype( WCHAR wc, WCHAR wct )
327 {
328     return (get_char_typeW(wc) & 0xfff) & wct;
329 }
330
331
332 /*********************************************************************
333  *           iswalpha    (NTDLL.@)
334  */
335 INT __cdecl NTDLL_iswalpha( WCHAR wc )
336 {
337     return get_char_typeW(wc) & C1_ALPHA;
338 }
339
340
341 /*********************************************************************
342  *      _ultow   (NTDLL.@)
343  *
344  * Converts an unsigned long integer to an unicode string.
345  *
346  * Assigns a '\0' terminated string to str and returns str.
347  * Does not check if radix is in the range of 2 to 36 (as native DLL).
348  * For str == NULL just returns NULL (as native DLL).
349  */
350 LPWSTR __cdecl _ultow( unsigned long value, LPWSTR str, INT radix )
351 {
352     WCHAR buffer[33];
353     PWCHAR pos;
354     WCHAR digit;
355
356     pos = &buffer[32];
357     *pos = '\0';
358
359     do {
360         digit = value % radix;
361         value = value / radix;
362         if (digit < 10) {
363             *--pos = '0' + digit;
364         } else {
365             *--pos = 'a' + digit - 10;
366         } /* if */
367     } while (value != 0L);
368
369     if (str != NULL) {
370         memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR));
371     } /* if */
372     return str;
373 }
374
375
376 /*********************************************************************
377  *      _ltow   (NTDLL.@)
378  *
379  * Converts a long integer to an unicode string.
380  *
381  * Assigns a '\0' terminated string to str and returns str. If radix
382  * is 10 and value is negative, the value is converted with sign.
383  * Does not check if radix is in the range of 2 to 36 (as native DLL).
384  * For str == NULL just returns NULL (as native DLL).
385  */
386 LPWSTR __cdecl _ltow( long value, LPWSTR str, INT radix )
387 {
388     unsigned long val;
389     int negative;
390     WCHAR buffer[33];
391     PWCHAR pos;
392     WCHAR digit;
393
394     if (value < 0 && radix == 10) {
395         negative = 1;
396         val = -value;
397     } else {
398         negative = 0;
399         val = value;
400     } /* if */
401
402     pos = &buffer[32];
403     *pos = '\0';
404
405     do {
406         digit = val % radix;
407         val = val / radix;
408         if (digit < 10) {
409             *--pos = '0' + digit;
410         } else {
411             *--pos = 'a' + digit - 10;
412         } /* if */
413     } while (val != 0L);
414
415     if (negative) {
416         *--pos = '-';
417     } /* if */
418
419     if (str != NULL) {
420         memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR));
421     } /* if */
422     return str;
423 }
424
425
426 /*********************************************************************
427  *      _itow    (NTDLL.@)
428  *
429  * Converts an integer to an unicode string.
430  *
431  * Assigns a '\0' terminated wstring to str and returns str. If radix
432  * is 10 and value is negative, the value is converted with sign.
433  * Does not check if radix is in the range of 2 to 36 (as native DLL).
434  * For str == NULL just returns NULL (as native DLL).
435  *
436  * Difference:
437  * - The native DLL crashes when the string is longer than 19 chars.
438  *   This function does not have this bug.
439  */
440 LPWSTR __cdecl _itow( int value, LPWSTR str, INT radix )
441 {
442     return _ltow(value, str, radix);
443 }
444
445
446 /*********************************************************************
447  *      _ui64tow   (NTDLL.@)
448  *
449  * Converts a large unsigned integer to an unicode string.
450  *
451  * Assigns a '\0' terminated wstring to str and returns str.
452  * Does not check if radix is in the range of 2 to 36 (as native DLL).
453  * For str == NULL just returns NULL (as native DLL).
454  *
455  * Difference:
456  * - This function does not exist in the native DLL (but in msvcrt).
457  *   But since the maintenance of all these functions is better done
458  *   in one place we implement it here.
459  */
460 LPWSTR __cdecl _ui64tow( ULONGLONG value, LPWSTR str, INT radix )
461 {
462     WCHAR buffer[65];
463     PWCHAR pos;
464     WCHAR digit;
465
466     pos = &buffer[64];
467     *pos = '\0';
468
469     do {
470         digit = value % radix;
471         value = value / radix;
472         if (digit < 10) {
473             *--pos = '0' + digit;
474         } else {
475             *--pos = 'a' + digit - 10;
476         } /* if */
477     } while (value != 0L);
478
479     if (str != NULL) {
480         memcpy(str, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR));
481     } /* if */
482     return str;
483 }
484
485
486 /*********************************************************************
487  *      _i64tow   (NTDLL.@)
488  *
489  * Converts a large integer to an unicode string.
490  *
491  * Assigns a '\0' terminated wstring to str and returns str. If radix
492  * is 10 and value is negative, the value is converted with sign.
493  * Does not check if radix is in the range of 2 to 36 (as native DLL).
494  * For str == NULL just returns NULL (as native DLL).
495  *
496  * Difference:
497  * - The native DLL converts negative values (for base 10) wrong:
498  *                     -1 is converted to -18446744073709551615
499  *                     -2 is converted to -18446744073709551614
500  *   -9223372036854775807 is converted to  -9223372036854775809
501  *   -9223372036854775808 is converted to  -9223372036854775808
502  *   The native msvcrt _i64tow function and our ntdll function do
503  *   not have this bug.
504  */
505 LPWSTR __cdecl _i64tow( LONGLONG value, LPWSTR str, INT radix )
506 {
507     ULONGLONG val;
508     int negative;
509     WCHAR buffer[65];
510     PWCHAR pos;
511     WCHAR digit;
512
513     if (value < 0 && radix == 10) {
514         negative = 1;
515         val = -value;
516     } else {
517         negative = 0;
518         val = value;
519     } /* if */
520
521     pos = &buffer[64];
522     *pos = '\0';
523
524     do {
525         digit = val % radix;
526         val = val / radix;
527         if (digit < 10) {
528             *--pos = '0' + digit;
529         } else {
530             *--pos = 'a' + digit - 10;
531         } /* if */
532     } while (val != 0L);
533
534     if (negative) {
535         *--pos = '-';
536     } /* if */
537
538     if (str != NULL) {
539         memcpy(str, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR));
540     } /* if */
541     return str;
542 }
543
544
545 /*********************************************************************
546  *      _wtol    (NTDLL.@)
547  *
548  * Converts an unicode string to a long integer.
549  *
550  * On success it returns the integer value otherwise it returns 0.
551  * Accepts: {whitespace} [+|-] {digits}
552  * No check of overflow: Just assigns lower 32 bits (as native DLL).
553  * Does not check for str != NULL (as native DLL).
554  */
555 LONG __cdecl _wtol( LPWSTR str )
556 {
557     ULONG RunningTotal = 0;
558     char bMinus = 0;
559
560     while (isspaceW(*str)) {
561         str++;
562     } /* while */
563
564     if (*str == '+') {
565         str++;
566     } else if (*str == '-') {
567         bMinus = 1;
568         str++;
569     } /* if */
570
571     while (*str >= '0' && *str <= '9') {
572         RunningTotal = RunningTotal * 10 + *str - '0';
573         str++;
574     } /* while */
575
576     return bMinus ? -RunningTotal : RunningTotal;
577 }
578
579
580 /*********************************************************************
581  *      _wtoi    (NTDLL.@)
582  *
583  * Converts an unicode string to an integer.
584  *
585  * On success it returns the integer value otherwise it returns 0.
586  * Accepts: {whitespace} [+|-] {digits}
587  * No check of overflow: Just assigns lower 32 bits (as native DLL).
588  * Does not check for str != NULL (as native DLL).
589  */
590 int __cdecl _wtoi( LPWSTR string )
591 {
592     return _wtol(string);
593 }
594
595
596 /*********************************************************************
597  *      _wtoi64   (NTDLL.@)
598  *
599  * Converts an unicode string to a large integer.
600  *
601  * On success it returns the integer value otherwise it returns 0.
602  * Accepts: {whitespace} [+|-] {digits}
603  * No check of overflow: Just assigns lower 64 bits (as native DLL).
604  * Does not check for str != NULL (as native DLL).
605  */
606 LONGLONG  __cdecl _wtoi64( LPWSTR str )
607 {
608     ULONGLONG RunningTotal = 0;
609     char bMinus = 0;
610
611     while (isspaceW(*str)) {
612         str++;
613     } /* while */
614
615     if (*str == '+') {
616         str++;
617     } else if (*str == '-') {
618         bMinus = 1;
619         str++;
620     } /* if */
621
622     while (*str >= '0' && *str <= '9') {
623         RunningTotal = RunningTotal * 10 + *str - '0';
624         str++;
625     } /* while */
626
627     return bMinus ? -RunningTotal : RunningTotal;
628 }
629
630
631 /* INTERNAL: Wide char snprintf
632  * If you fix a bug in this function, fix it in msvcrt/wcs.c also!
633  */
634 static int __cdecl NTDLL_vsnwprintf(WCHAR *str, unsigned int len,
635                                     const WCHAR *format, va_list valist)
636 {
637   unsigned int written = 0;
638   const WCHAR *iter = format;
639   char bufa[256], fmtbufa[64], *fmta;
640
641   TRACE("(%d,%s)\n",len,debugstr_w(format));
642
643   while (*iter)
644   {
645     while (*iter && *iter != (WCHAR)L'%')
646     {
647      if (written++ >= len)
648        return -1;
649      *str++ = *iter++;
650     }
651     if (*iter == (WCHAR)L'%')
652     {
653       fmta = fmtbufa;
654       *fmta++ = *iter++;
655       while (*iter == (WCHAR)L'0' ||
656              *iter == (WCHAR)L'+' ||
657              *iter == (WCHAR)L'-' ||
658              *iter == (WCHAR)L' ' ||
659              *iter == (WCHAR)L'0' ||
660              *iter == (WCHAR)L'*' ||
661              *iter == (WCHAR)L'#')
662       {
663         if (*iter == (WCHAR)L'*')
664         {
665           char *buffiter = bufa;
666           int fieldlen = va_arg(valist, int);
667           sprintf(buffiter, "%d", fieldlen);
668           while (*buffiter)
669             *fmta++ = *buffiter++;
670         }
671         else
672           *fmta++ = *iter;
673         iter++;
674       }
675
676       while (isdigit(*iter))
677         *fmta++ = *iter++;
678
679       if (*iter == (WCHAR)L'.')
680       {
681         *fmta++ = *iter++;
682         if (*iter == (WCHAR)L'*')
683         {
684           char *buffiter = bufa;
685           int fieldlen = va_arg(valist, int);
686           sprintf(buffiter, "%d", fieldlen);
687           while (*buffiter)
688             *fmta++ = *buffiter++;
689         }
690         else
691           while (isdigit(*iter))
692             *fmta++ = *iter++;
693       }
694       if (*iter == (WCHAR)L'h' ||
695           *iter == (WCHAR)L'l')
696           *fmta++ = *iter++;
697
698       switch (*iter)
699       {
700       case (WCHAR)L's':
701         {
702           static const WCHAR none[] = { '(', 'n', 'u', 'l', 'l', ')', 0 };
703           const WCHAR *wstr = va_arg(valist, const WCHAR *);
704           const WCHAR *striter = wstr ? wstr : none;
705           while (*striter)
706           {
707             if (written++ >= len)
708               return -1;
709             *str++ = *striter++;
710           }
711           iter++;
712           break;
713         }
714
715       case (WCHAR)L'c':
716         if (written++ >= len)
717           return -1;
718         *str++ = (WCHAR)va_arg(valist, int);
719         iter++;
720         break;
721
722       default:
723         {
724           /* For non wc types, use system sprintf and append to wide char output */
725           /* FIXME: for unrecognised types, should ignore % when printing */
726           char *bufaiter = bufa;
727           if (*iter == (WCHAR)L'p')
728             sprintf(bufaiter, "%08lX", va_arg(valist, long));
729           else
730           {
731             *fmta++ = *iter;
732             *fmta = '\0';
733             if (*iter == (WCHAR)L'f')
734               sprintf(bufaiter, fmtbufa, va_arg(valist, double));
735             else
736               sprintf(bufaiter, fmtbufa, va_arg(valist, void *));
737           }
738           while (*bufaiter)
739           {
740             if (written++ >= len)
741               return -1;
742             *str++ = *bufaiter++;
743           }
744           iter++;
745           break;
746         }
747       }
748     }
749   }
750   if (written >= len)
751     return -1;
752   *str++ = (WCHAR)L'\0';
753   return (int)written;
754 }
755
756
757 /***********************************************************************
758  *        _snwprintf (NTDLL.@)
759  */
760 int __cdecl _snwprintf(WCHAR *str, unsigned int len, const WCHAR *format, ...)
761 {
762   int retval;
763   va_list valist;
764   va_start(valist, format);
765   retval = NTDLL_vsnwprintf(str, len, format, valist);
766   va_end(valist);
767   return retval;
768 }
769
770
771 /***********************************************************************
772  *        swprintf (NTDLL.@)
773  */
774 int __cdecl NTDLL_swprintf(WCHAR *str, const WCHAR *format, ...)
775 {
776   int retval;
777   va_list valist;
778   va_start(valist, format);
779   retval = NTDLL_vsnwprintf(str, INT_MAX, format, valist);
780   va_end(valist);
781   return retval;
782 }