2 * NTDLL wide-char functions
4 * Copyright 2000 Alexandre Julliard
5 * Copyright 2000 Jon Griffiths
6 * Copyright 2003 Thomas Mertes
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "ntdll_misc.h"
35 static const unsigned short wctypes
[256] =
38 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
39 0x0020, 0x0068, 0x0028, 0x0028, 0x0028, 0x0028, 0x0020, 0x0020,
41 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
42 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
44 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
45 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
47 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084,
48 0x0084, 0x0084, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
50 0x0010, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0101,
51 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
53 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
54 0x0101, 0x0101, 0x0101, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
56 0x0010, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0102,
57 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
59 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
60 0x0102, 0x0102, 0x0102, 0x0010, 0x0010, 0x0010, 0x0010, 0x0020,
62 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
63 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
65 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
66 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
68 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
69 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
71 0x0010, 0x0010, 0x0014, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010,
72 0x0010, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
74 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
75 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
77 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0010,
78 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0102,
80 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
81 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
83 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0010,
84 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102
88 /*********************************************************************
91 int __cdecl
_wcsicmp( LPCWSTR str1
, LPCWSTR str2
)
95 WCHAR ch1
= (*str1
>= 'A' && *str1
<= 'Z') ? *str1
+ 32 : *str1
;
96 WCHAR ch2
= (*str2
>= 'A' && *str2
<= 'Z') ? *str2
+ 32 : *str2
;
97 if (ch1
!= ch2
|| !*str1
) return ch1
- ch2
;
104 /*********************************************************************
107 LPWSTR __cdecl
_wcslwr( LPWSTR str
)
114 if (ch
>= 'A' && ch
<= 'Z') ch
+= 32;
121 /*********************************************************************
122 * _wcsnicmp (NTDLL.@)
124 int __cdecl
_wcsnicmp( LPCWSTR str1
, LPCWSTR str2
, size_t n
)
127 for ( ; n
> 0; n
--, str1
++, str2
++)
129 WCHAR ch1
= (*str1
>= 'A' && *str1
<= 'Z') ? *str1
+ 32 : *str1
;
130 WCHAR ch2
= (*str2
>= 'A' && *str2
<= 'Z') ? *str2
+ 32 : *str2
;
131 if ((ret
= ch1
- ch2
) || !*str1
) break;
137 /*********************************************************************
140 LPWSTR __cdecl
_wcsupr( LPWSTR str
)
147 if (ch
>= 'a' && ch
<= 'z') ch
-= 32;
154 /***********************************************************************
157 LPWSTR __cdecl
wcscpy( LPWSTR dst
, LPCWSTR src
)
160 while ((*p
++ = *src
++));
165 /***********************************************************************
168 size_t __cdecl
wcslen( LPCWSTR str
)
170 const WCHAR
*s
= str
;
176 /***********************************************************************
179 LPWSTR __cdecl
wcscat( LPWSTR dst
, LPCWSTR src
)
181 wcscpy( dst
+ wcslen(dst
), src
);
186 /*********************************************************************
189 LPWSTR __cdecl
wcschr( LPCWSTR str
, WCHAR ch
)
191 do { if (*str
== ch
) return (WCHAR
*)(ULONG_PTR
)str
; } while (*str
++);
196 /*********************************************************************
199 int __cdecl
wcscmp( LPCWSTR str1
, LPCWSTR str2
)
201 while (*str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
202 return *str1
- *str2
;
206 /*********************************************************************
209 size_t __cdecl
wcscspn( LPCWSTR str
, LPCWSTR reject
)
212 for (ptr
= str
; *ptr
; ptr
++) if (wcschr( reject
, *ptr
)) break;
217 /*********************************************************************
220 LPWSTR __cdecl
wcsncat( LPWSTR s1
, LPCWSTR s2
, size_t n
)
224 while (n
-- > 0) if (!(*s1
++ = *s2
++)) return ret
;
230 /*********************************************************************
233 int __cdecl
wcsncmp( LPCWSTR str1
, LPCWSTR str2
, size_t n
)
235 if (n
<= 0) return 0;
236 while ((--n
> 0) && *str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
237 return *str1
- *str2
;
241 /*********************************************************************
245 LPWSTR __cdecl
wcsncpy( LPWSTR s1
, LPCWSTR s2
, size_t n
)
248 for ( ; n
; n
--) if (!(*s1
++ = *s2
++)) break;
249 for ( ; n
; n
--) *s1
++ = 0;
254 /*********************************************************************
257 size_t __cdecl
wcsnlen( const WCHAR
*str
, size_t len
)
259 const WCHAR
*s
= str
;
260 for (s
= str
; len
&& *s
; s
++, len
--) ;
265 /*********************************************************************
268 LPWSTR __cdecl
wcspbrk( LPCWSTR str
, LPCWSTR accept
)
270 for ( ; *str
; str
++) if (wcschr( accept
, *str
)) return (WCHAR
*)(ULONG_PTR
)str
;
275 /*********************************************************************
278 LPWSTR __cdecl
wcsrchr( LPCWSTR str
, WCHAR ch
)
281 do { if (*str
== ch
) ret
= (WCHAR
*)(ULONG_PTR
)str
; } while (*str
++);
286 /*********************************************************************
289 size_t __cdecl
wcsspn( LPCWSTR str
, LPCWSTR accept
)
292 for (ptr
= str
; *ptr
; ptr
++) if (!wcschr( accept
, *ptr
)) break;
297 /*********************************************************************
300 LPWSTR __cdecl
wcsstr( LPCWSTR str
, LPCWSTR sub
)
304 const WCHAR
*p1
= str
, *p2
= sub
;
305 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
306 if (!*p2
) return (WCHAR
*)str
;
313 /*********************************************************************
316 LPWSTR __cdecl
wcstok( LPWSTR str
, LPCWSTR delim
)
318 static LPWSTR next
= NULL
;
322 if (!(str
= next
)) return NULL
;
324 while (*str
&& wcschr( delim
, *str
)) str
++;
325 if (!*str
) return NULL
;
327 while (*str
&& !wcschr( delim
, *str
)) str
++;
328 if (*str
) *str
++ = 0;
334 /*********************************************************************
337 size_t __cdecl
wcstombs( char *dst
, const WCHAR
*src
, size_t n
)
343 RtlUnicodeToMultiByteSize( &len
, src
, wcslen(src
) * sizeof(WCHAR
) );
348 if (n
<= 0) return 0;
349 RtlUnicodeToMultiByteN( dst
, n
, &len
, src
, wcslen(src
) * sizeof(WCHAR
) );
350 if (len
< n
) dst
[len
] = 0;
356 /*********************************************************************
359 size_t __cdecl
mbstowcs( WCHAR
*dst
, const char *src
, size_t n
)
365 RtlMultiByteToUnicodeSize( &len
, src
, strlen(src
) );
369 if (n
<= 0) return 0;
370 RtlMultiByteToUnicodeN( dst
, n
*sizeof(WCHAR
), &len
, src
, strlen(src
) );
371 if (len
/ sizeof(WCHAR
) < n
) dst
[len
/ sizeof(WCHAR
)] = 0;
373 return len
/ sizeof(WCHAR
);
377 /*********************************************************************
380 INT __cdecl
iswctype( WCHAR wc
, unsigned short type
)
382 if (wc
>= 256) return 0;
383 return wctypes
[wc
] & type
;
387 /*********************************************************************
390 INT __cdecl
iswalpha( WCHAR wc
)
392 if (wc
>= 256) return 0;
393 return wctypes
[wc
] & (C1_ALPHA
| C1_UPPER
| C1_LOWER
);
397 /*********************************************************************
400 * Checks if a unicode char wc is a digit
403 * TRUE: The unicode char wc is a digit.
406 INT __cdecl
iswdigit( WCHAR wc
)
408 if (wc
>= 256) return 0;
409 return wctypes
[wc
] & C1_DIGIT
;
413 /*********************************************************************
416 * Checks if a unicode char wc is a lower case letter
419 * TRUE: The unicode char wc is a lower case letter.
422 INT __cdecl
iswlower( WCHAR wc
)
424 if (wc
>= 256) return 0;
425 return wctypes
[wc
] & C1_LOWER
;
429 /*********************************************************************
432 * Checks if a unicode char wc is a white space character
435 * TRUE: The unicode char wc is a white space character.
438 INT __cdecl
iswspace( WCHAR wc
)
440 if (wc
>= 256) return 0;
441 return wctypes
[wc
] & C1_SPACE
;
445 /*********************************************************************
446 * iswxdigit (NTDLL.@)
448 * Checks if a unicode char wc is an extended digit
451 * TRUE: The unicode char wc is an extended digit.
454 INT __cdecl
iswxdigit( WCHAR wc
)
456 if (wc
>= 256) return 0;
457 return wctypes
[wc
] & C1_XDIGIT
;
461 static int wctoint( WCHAR c
)
463 /* NOTE: MAP_FOLDDIGITS supports too many things. */
464 /* Unicode points that contain digits 0-9; keep this sorted! */
465 static const WCHAR zeros
[] =
467 0x0660, 0x06f0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0c66, 0x0ce6,
468 0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x17e0, 0x1810, 0xff10
472 if ('0' <= c
&& c
<= '9') return c
- '0';
473 if ('A' <= c
&& c
<= 'Z') return c
- 'A' + 10;
474 if ('a' <= c
&& c
<= 'z') return c
- 'a' + 10;
475 for (i
= 0; i
< ARRAY_SIZE(zeros
) && c
>= zeros
[i
]; i
++)
476 if (zeros
[i
] <= c
&& c
<= zeros
[i
] + 9) return c
- zeros
[i
];
481 /*********************************************************************
484 __msvcrt_long __cdecl
wcstol(LPCWSTR s
, LPWSTR
*end
, INT base
)
486 BOOL negative
= FALSE
, empty
= TRUE
;
489 if (base
< 0 || base
== 1 || base
> 36) return 0;
490 if (end
) *end
= (WCHAR
*)s
;
491 while (iswspace(*s
)) s
++;
498 else if (*s
== '+') s
++;
500 if ((base
== 0 || base
== 16) && !wctoint( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
505 if (base
== 0) base
= wctoint( *s
) ? 10 : 8;
509 int v
= wctoint( *s
);
510 if (v
< 0 || v
>= base
) break;
511 if (negative
) v
= -v
;
515 if (!negative
&& (ret
> MAXLONG
/ base
|| ret
* base
> MAXLONG
- v
))
517 else if (negative
&& (ret
< (LONG
)MINLONG
/ base
|| ret
* base
< (LONG
)(MINLONG
- v
)))
520 ret
= ret
* base
+ v
;
523 if (end
&& !empty
) *end
= (WCHAR
*)s
;
528 /*********************************************************************
531 __msvcrt_ulong __cdecl
wcstoul(LPCWSTR s
, LPWSTR
*end
, INT base
)
533 BOOL negative
= FALSE
, empty
= TRUE
;
536 if (base
< 0 || base
== 1 || base
> 36) return 0;
537 if (end
) *end
= (WCHAR
*)s
;
538 while (iswspace(*s
)) s
++;
545 else if (*s
== '+') s
++;
547 if ((base
== 0 || base
== 16) && !wctoint( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
552 if (base
== 0) base
= wctoint( *s
) ? 10 : 8;
556 int v
= wctoint( *s
);
557 if (v
< 0 || v
>= base
) break;
561 if (ret
> MAXDWORD
/ base
|| ret
* base
> MAXDWORD
- v
)
564 ret
= ret
* base
+ v
;
567 if (end
&& !empty
) *end
= (WCHAR
*)s
;
568 return negative
? -ret
: ret
;
572 /*********************************************************************
575 * Converts an unsigned long integer to a unicode string.
578 * Always returns str.
581 * Converts value to a '\0' terminated wstring which is copied to str.
582 * The maximum length of the copied str is 33 bytes.
583 * Does not check if radix is in the range of 2 to 36.
584 * If str is NULL it just returns NULL.
586 LPWSTR __cdecl
_ultow( __msvcrt_ulong value
, LPWSTR str
, INT radix
)
596 digit
= value
% radix
;
597 value
= value
/ radix
;
599 *--pos
= '0' + digit
;
601 *--pos
= 'a' + digit
- 10;
603 } while (value
!= 0L);
606 memcpy(str
, pos
, (&buffer
[32] - pos
+ 1) * sizeof(WCHAR
));
612 /*********************************************************************
615 * Converts a long integer to a unicode string.
618 * Always returns str.
621 * Converts value to a '\0' terminated wstring which is copied to str.
622 * The maximum length of the copied str is 33 bytes. If radix
623 * is 10 and value is negative, the value is converted with sign.
624 * Does not check if radix is in the range of 2 to 36.
625 * If str is NULL it just returns NULL.
627 LPWSTR __cdecl
_ltow( __msvcrt_long value
, LPWSTR str
, INT radix
)
635 if (value
< 0 && radix
== 10) {
650 *--pos
= '0' + digit
;
652 *--pos
= 'a' + digit
- 10;
661 memcpy(str
, pos
, (&buffer
[32] - pos
+ 1) * sizeof(WCHAR
));
667 /*********************************************************************
670 * Converts an integer to a unicode string.
673 * Always returns str.
676 * Converts value to a '\0' terminated wstring which is copied to str.
677 * The maximum length of the copied str is 33 bytes. If radix
678 * is 10 and value is negative, the value is converted with sign.
679 * Does not check if radix is in the range of 2 to 36.
680 * If str is NULL it just returns NULL.
683 * - The native function crashes when the string is longer than 19 chars.
684 * This function does not have this bug.
686 LPWSTR __cdecl
_itow(
687 int value
, /* [I] Value to be converted */
688 LPWSTR str
, /* [O] Destination for the converted value */
689 INT radix
) /* [I] Number base for conversion */
691 return _ltow(value
, str
, radix
);
695 /*********************************************************************
698 * Converts a large unsigned integer to a unicode string.
701 * Always returns str.
704 * Converts value to a '\0' terminated wstring which is copied to str.
705 * The maximum length of the copied str is 33 bytes.
706 * Does not check if radix is in the range of 2 to 36.
707 * If str is NULL it just returns NULL.
710 * - This function does not exist in the native DLL (but in msvcrt).
711 * But since the maintenance of all these functions is better done
712 * in one place we implement it here.
714 LPWSTR __cdecl
_ui64tow(
715 ULONGLONG value
, /* [I] Value to be converted */
716 LPWSTR str
, /* [O] Destination for the converted value */
717 INT radix
) /* [I] Number base for conversion */
727 digit
= value
% radix
;
728 value
= value
/ radix
;
730 *--pos
= '0' + digit
;
732 *--pos
= 'a' + digit
- 10;
734 } while (value
!= 0L);
737 memcpy(str
, pos
, (&buffer
[64] - pos
+ 1) * sizeof(WCHAR
));
743 /*********************************************************************
746 * Converts a large integer to a unicode string.
749 * Always returns str.
752 * Converts value to a '\0' terminated wstring which is copied to str.
753 * The maximum length of the copied str is 33 bytes. If radix
754 * is 10 and value is negative, the value is converted with sign.
755 * Does not check if radix is in the range of 2 to 36.
756 * If str is NULL it just returns NULL.
759 * - The native DLL converts negative values (for base 10) wrong:
760 * -1 is converted to -18446744073709551615
761 * -2 is converted to -18446744073709551614
762 * -9223372036854775807 is converted to -9223372036854775809
763 * -9223372036854775808 is converted to -9223372036854775808
764 * The native msvcrt _i64tow function and our ntdll function do
767 LPWSTR __cdecl
_i64tow(
768 LONGLONG value
, /* [I] Value to be converted */
769 LPWSTR str
, /* [O] Destination for the converted value */
770 INT radix
) /* [I] Number base for conversion */
778 if (value
< 0 && radix
== 10) {
793 *--pos
= '0' + digit
;
795 *--pos
= 'a' + digit
- 10;
804 memcpy(str
, pos
, (&buffer
[64] - pos
+ 1) * sizeof(WCHAR
));
810 /*********************************************************************
813 * Converts a unicode string to a long integer.
816 * str [I] Wstring to be converted
819 * On success it returns the integer value otherwise it returns 0.
822 * Accepts: {whitespace} [+|-] {digits}
823 * No check is made for value overflow, only the lower 32 bits are assigned.
824 * If str is NULL it crashes, as the native function does.
826 __msvcrt_long __cdecl
_wtol( LPCWSTR str
)
828 ULONG RunningTotal
= 0;
831 while (iswspace(*str
)) str
++;
835 } else if (*str
== '-') {
840 while (*str
>= '0' && *str
<= '9') {
841 RunningTotal
= RunningTotal
* 10 + *str
- '0';
845 return bMinus
? -RunningTotal
: RunningTotal
;
849 /*********************************************************************
852 * Converts a unicode string to an integer.
855 * str [I] Wstring to be converted
858 * On success it returns the integer value otherwise it returns 0.
861 * Accepts: {whitespace} [+|-] {digits}
862 * No check is made for value overflow, only the lower 32 bits are assigned.
863 * If str is NULL it crashes, as the native function does.
865 int __cdecl
_wtoi( LPCWSTR str
)
871 /*********************************************************************
874 * Converts a unicode string to a large integer.
877 * str [I] Wstring to be converted
880 * On success it returns the integer value otherwise it returns 0.
883 * Accepts: {whitespace} [+|-] {digits}
884 * No check is made for value overflow, only the lower 64 bits are assigned.
885 * If str is NULL it crashes, as the native function does.
887 LONGLONG __cdecl
_wtoi64( LPCWSTR str
)
889 ULONGLONG RunningTotal
= 0;
892 while (iswspace(*str
)) str
++;
896 } else if (*str
== '-') {
901 while (*str
>= '0' && *str
<= '9') {
902 RunningTotal
= RunningTotal
* 10 + *str
- '0';
906 return bMinus
? -RunningTotal
: RunningTotal
;