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