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