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
35 #include "ntdll_misc.h"
37 static const unsigned short wctypes
[256] =
40 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
41 0x0020, 0x0068, 0x0028, 0x0028, 0x0028, 0x0028, 0x0020, 0x0020,
43 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
44 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
46 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
47 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
49 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084,
50 0x0084, 0x0084, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
52 0x0010, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0101,
53 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
55 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
56 0x0101, 0x0101, 0x0101, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
58 0x0010, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0102,
59 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
61 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
62 0x0102, 0x0102, 0x0102, 0x0010, 0x0010, 0x0010, 0x0010, 0x0020,
64 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
65 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
67 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
68 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
70 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
71 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
73 0x0010, 0x0010, 0x0014, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010,
74 0x0010, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
76 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
77 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
79 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0010,
80 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0102,
82 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
83 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
85 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0010,
86 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102
90 /*********************************************************************
93 int __cdecl
_wcsicmp( LPCWSTR str1
, LPCWSTR str2
)
97 WCHAR ch1
= (*str1
>= 'A' && *str1
<= 'Z') ? *str1
+ 32 : *str1
;
98 WCHAR ch2
= (*str2
>= 'A' && *str2
<= 'Z') ? *str2
+ 32 : *str2
;
99 if (ch1
!= ch2
|| !*str1
) return ch1
- ch2
;
106 /*********************************************************************
109 LPWSTR __cdecl
_wcslwr( LPWSTR str
)
112 for ( ; *str
; str
++) if (*str
>= 'A' && *str
<= 'Z') *str
+= 'a' - 'A';
117 /*********************************************************************
118 * _wcslwr_s (NTDLL.@)
120 errno_t __cdecl
_wcslwr_s( wchar_t *str
, size_t len
)
122 if (!str
) return EINVAL
;
124 if (wcsnlen( str
, len
) == len
)
135 /*********************************************************************
136 * _wcsnicmp (NTDLL.@)
138 int __cdecl
_wcsnicmp( LPCWSTR str1
, LPCWSTR str2
, size_t n
)
141 for ( ; n
> 0; n
--, str1
++, str2
++)
143 WCHAR ch1
= (*str1
>= 'A' && *str1
<= 'Z') ? *str1
+ 32 : *str1
;
144 WCHAR ch2
= (*str2
>= 'A' && *str2
<= 'Z') ? *str2
+ 32 : *str2
;
145 if ((ret
= ch1
- ch2
) || !*str1
) break;
151 /*********************************************************************
154 LPWSTR __cdecl
_wcsupr( LPWSTR str
)
158 for ( ; *str
; str
++) if (*str
>= 'a' && *str
<= 'z') *str
+= 'A' - 'a';
163 /*********************************************************************
164 * _wcsupr_s (NTDLL.@)
166 errno_t __cdecl
_wcsupr_s( wchar_t *str
, size_t len
)
168 if (!str
) return EINVAL
;
170 if (wcsnlen( str
, len
) == len
)
181 /***********************************************************************
184 LPWSTR __cdecl
wcscpy( LPWSTR dst
, LPCWSTR src
)
187 while ((*p
++ = *src
++));
192 /*********************************************************************
195 errno_t __cdecl
wcscpy_s( wchar_t *dst
, size_t len
, const wchar_t *src
)
199 if (!dst
|| !len
) return EINVAL
;
206 for (i
= 0; i
< len
; i
++) if (!(dst
[i
] = src
[i
])) return 0;
212 /***********************************************************************
215 size_t __cdecl
wcslen( LPCWSTR str
)
217 const WCHAR
*s
= str
;
223 /***********************************************************************
226 LPWSTR __cdecl
wcscat( LPWSTR dst
, LPCWSTR src
)
228 wcscpy( dst
+ wcslen(dst
), src
);
233 /*********************************************************************
236 errno_t __cdecl
wcscat_s( wchar_t *dst
, size_t len
, const wchar_t *src
)
240 if (!dst
|| !len
) return EINVAL
;
246 for (i
= 0; i
< len
; i
++) if (!dst
[i
]) break;
247 for (j
= 0; (j
+ i
) < len
; j
++) if (!(dst
[j
+ i
] = src
[j
])) return 0;
253 /*********************************************************************
256 LPWSTR __cdecl
wcschr( LPCWSTR str
, WCHAR ch
)
258 do { if (*str
== ch
) return (WCHAR
*)(ULONG_PTR
)str
; } while (*str
++);
263 /*********************************************************************
266 int __cdecl
wcscmp( LPCWSTR str1
, LPCWSTR str2
)
268 while (*str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
269 return *str1
- *str2
;
273 /*********************************************************************
276 size_t __cdecl
wcscspn( LPCWSTR str
, LPCWSTR reject
)
279 for (ptr
= str
; *ptr
; ptr
++) if (wcschr( reject
, *ptr
)) break;
284 /*********************************************************************
287 LPWSTR __cdecl
wcsncat( LPWSTR s1
, LPCWSTR s2
, size_t n
)
291 while (n
-- > 0) if (!(*s1
++ = *s2
++)) return ret
;
297 /*********************************************************************
298 * wcsncat_s (NTDLL.@)
300 errno_t __cdecl
wcsncat_s( wchar_t *dst
, size_t len
, const wchar_t *src
, size_t count
)
304 if (!dst
|| !len
) return EINVAL
;
305 if (!count
) return 0;
312 for (i
= 0; i
< len
; i
++) if (!dst
[i
]) break;
320 for (j
= 0; (j
+ i
) < len
; j
++)
322 if (count
== _TRUNCATE
&& j
+ i
== len
- 1)
327 if (j
== count
|| !(dst
[j
+ i
] = src
[j
]))
338 /*********************************************************************
341 int __cdecl
wcsncmp( LPCWSTR str1
, LPCWSTR str2
, size_t n
)
343 if (n
<= 0) return 0;
344 while ((--n
> 0) && *str1
&& (*str1
== *str2
)) { str1
++; str2
++; }
345 return *str1
- *str2
;
349 /*********************************************************************
353 LPWSTR __cdecl
wcsncpy( LPWSTR s1
, LPCWSTR s2
, size_t n
)
356 for ( ; n
; n
--) if (!(*s1
++ = *s2
++)) break;
357 for ( ; n
; n
--) *s1
++ = 0;
362 /*********************************************************************
363 * wcsncpy_s (NTDLL.@)
365 errno_t __cdecl
wcsncpy_s( wchar_t *dst
, size_t len
, const wchar_t *src
, size_t count
)
371 if (dst
&& len
) *dst
= 0;
374 if (!dst
|| !len
) return EINVAL
;
381 if (count
!= _TRUNCATE
&& count
< len
)
386 for (i
= 0; i
< end
; i
++)
387 if (!(dst
[i
] = src
[i
])) return 0;
389 if (count
== _TRUNCATE
)
404 /*********************************************************************
407 size_t __cdecl
wcsnlen( const WCHAR
*str
, size_t len
)
410 for (s
= str
; len
&& *s
; s
++, len
--) ;
415 /*********************************************************************
418 LPWSTR __cdecl
wcspbrk( LPCWSTR str
, LPCWSTR accept
)
420 for ( ; *str
; str
++) if (wcschr( accept
, *str
)) return (WCHAR
*)(ULONG_PTR
)str
;
425 /*********************************************************************
428 LPWSTR __cdecl
wcsrchr( LPCWSTR str
, WCHAR ch
)
431 do { if (*str
== ch
) ret
= (WCHAR
*)(ULONG_PTR
)str
; } while (*str
++);
436 /*********************************************************************
439 size_t __cdecl
wcsspn( LPCWSTR str
, LPCWSTR accept
)
442 for (ptr
= str
; *ptr
; ptr
++) if (!wcschr( accept
, *ptr
)) break;
447 /*********************************************************************
450 LPWSTR __cdecl
wcsstr( LPCWSTR str
, LPCWSTR sub
)
454 const WCHAR
*p1
= str
, *p2
= sub
;
455 while (*p1
&& *p2
&& *p1
== *p2
) { p1
++; p2
++; }
456 if (!*p2
) return (WCHAR
*)str
;
463 /*********************************************************************
466 LPWSTR __cdecl
wcstok( LPWSTR str
, LPCWSTR delim
)
468 static LPWSTR next
= NULL
;
472 if (!(str
= next
)) return NULL
;
474 while (*str
&& wcschr( delim
, *str
)) str
++;
475 if (!*str
) return NULL
;
477 while (*str
&& !wcschr( delim
, *str
)) str
++;
478 if (*str
) *str
++ = 0;
484 /*********************************************************************
487 wchar_t * __cdecl
wcstok_s( wchar_t *str
, const wchar_t *delim
, wchar_t **ctx
)
491 if (!delim
|| !ctx
) return NULL
;
495 if (!str
) return NULL
;
497 while (*str
&& wcschr( delim
, *str
)) str
++;
504 while (*next
&& !wcschr( delim
, *next
)) next
++;
505 if (*next
) *next
++ = 0;
511 /*********************************************************************
514 size_t __cdecl
wcstombs( char *dst
, const WCHAR
*src
, size_t n
)
520 RtlUnicodeToMultiByteSize( &len
, src
, wcslen(src
) * sizeof(WCHAR
) );
525 if (n
<= 0) return 0;
526 RtlUnicodeToMultiByteN( dst
, n
, &len
, src
, wcslen(src
) * sizeof(WCHAR
) );
527 if (len
< n
) dst
[len
] = 0;
533 /*********************************************************************
536 size_t __cdecl
mbstowcs( WCHAR
*dst
, const char *src
, size_t n
)
542 RtlMultiByteToUnicodeSize( &len
, src
, strlen(src
) );
546 if (n
<= 0) return 0;
547 RtlMultiByteToUnicodeN( dst
, n
*sizeof(WCHAR
), &len
, src
, strlen(src
) );
548 if (len
/ sizeof(WCHAR
) < n
) dst
[len
/ sizeof(WCHAR
)] = 0;
550 return len
/ sizeof(WCHAR
);
554 /*********************************************************************
557 INT __cdecl
iswctype( WCHAR wc
, unsigned short type
)
559 if (wc
>= 256) return 0;
560 return wctypes
[wc
] & type
;
564 /*********************************************************************
567 INT __cdecl
iswalnum( WCHAR wc
)
569 return iswctype( wc
, C1_ALPHA
| C1_UPPER
| C1_LOWER
| C1_DIGIT
);
573 /*********************************************************************
576 INT __cdecl
iswalpha( WCHAR wc
)
578 return iswctype( wc
, C1_ALPHA
| C1_UPPER
| C1_LOWER
);
582 /*********************************************************************
585 INT __cdecl
iswascii( WCHAR wc
)
591 /*********************************************************************
594 INT __cdecl
iswdigit( WCHAR wc
)
596 return iswctype( wc
, C1_DIGIT
);
600 /*********************************************************************
603 INT __cdecl
iswgraph( WCHAR wc
)
605 return iswctype( wc
, C1_ALPHA
| C1_UPPER
| C1_LOWER
| C1_DIGIT
| C1_PUNCT
);
609 /*********************************************************************
612 INT __cdecl
iswlower( WCHAR wc
)
614 return iswctype( wc
, C1_LOWER
);
618 /*********************************************************************
621 INT __cdecl
iswprint( WCHAR wc
)
623 return iswctype( wc
, C1_ALPHA
| C1_UPPER
| C1_LOWER
| C1_DIGIT
| C1_PUNCT
| C1_BLANK
);
627 /*********************************************************************
630 INT __cdecl
iswspace( WCHAR wc
)
632 return iswctype( wc
, C1_SPACE
);
636 /*********************************************************************
637 * iswxdigit (NTDLL.@)
639 INT __cdecl
iswxdigit( WCHAR wc
)
641 return iswctype( wc
, C1_XDIGIT
);
645 static int wctoint( WCHAR c
)
647 /* NOTE: MAP_FOLDDIGITS supports too many things. */
648 /* Unicode points that contain digits 0-9; keep this sorted! */
649 static const WCHAR zeros
[] =
651 0x0660, 0x06f0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0c66, 0x0ce6,
652 0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x17e0, 0x1810, 0xff10
656 if ('0' <= c
&& c
<= '9') return c
- '0';
657 if ('A' <= c
&& c
<= 'Z') return c
- 'A' + 10;
658 if ('a' <= c
&& c
<= 'z') return c
- 'a' + 10;
659 for (i
= 0; i
< ARRAY_SIZE(zeros
) && c
>= zeros
[i
]; i
++)
660 if (zeros
[i
] <= c
&& c
<= zeros
[i
] + 9) return c
- zeros
[i
];
665 /*********************************************************************
668 __msvcrt_long __cdecl
wcstol(LPCWSTR s
, LPWSTR
*end
, INT base
)
670 BOOL negative
= FALSE
, empty
= TRUE
;
673 if (base
< 0 || base
== 1 || base
> 36) return 0;
674 if (end
) *end
= (WCHAR
*)s
;
675 while (iswspace(*s
)) s
++;
682 else if (*s
== '+') s
++;
684 if ((base
== 0 || base
== 16) && !wctoint( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
689 if (base
== 0) base
= wctoint( *s
) ? 10 : 8;
693 int v
= wctoint( *s
);
694 if (v
< 0 || v
>= base
) break;
695 if (negative
) v
= -v
;
699 if (!negative
&& (ret
> MAXLONG
/ base
|| ret
* base
> MAXLONG
- v
))
701 else if (negative
&& (ret
< (LONG
)MINLONG
/ base
|| ret
* base
< (LONG
)(MINLONG
- v
)))
704 ret
= ret
* base
+ v
;
707 if (end
&& !empty
) *end
= (WCHAR
*)s
;
712 /*********************************************************************
715 __msvcrt_ulong __cdecl
wcstoul(LPCWSTR s
, LPWSTR
*end
, INT base
)
717 BOOL negative
= FALSE
, empty
= TRUE
;
720 if (base
< 0 || base
== 1 || base
> 36) return 0;
721 if (end
) *end
= (WCHAR
*)s
;
722 while (iswspace(*s
)) s
++;
729 else if (*s
== '+') s
++;
731 if ((base
== 0 || base
== 16) && !wctoint( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
736 if (base
== 0) base
= wctoint( *s
) ? 10 : 8;
740 int v
= wctoint( *s
);
741 if (v
< 0 || v
>= base
) break;
745 if (ret
> MAXDWORD
/ base
|| ret
* base
> MAXDWORD
- v
)
748 ret
= ret
* base
+ v
;
751 if (end
&& !empty
) *end
= (WCHAR
*)s
;
752 return negative
? -ret
: ret
;
756 /*********************************************************************
757 * _wcstoi64 (NTDLL.@)
759 __int64 __cdecl
_wcstoi64( const wchar_t *s
, wchar_t **end
, int base
)
761 BOOL negative
= FALSE
, empty
= TRUE
;
764 if (base
< 0 || base
== 1 || base
> 36) return 0;
765 if (end
) *end
= (wchar_t *)s
;
766 while (iswspace(*s
)) s
++;
773 else if (*s
== '+') s
++;
775 if ((base
== 0 || base
== 16) && !wctoint( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
780 if (base
== 0) base
= wctoint( *s
) ? 10 : 8;
784 int v
= wctoint( *s
);
785 if (v
< 0 || v
>= base
) break;
786 if (negative
) v
= -v
;
790 if (!negative
&& (ret
> I64_MAX
/ base
|| ret
* base
> I64_MAX
- v
))
792 else if (negative
&& (ret
< I64_MIN
/ base
|| ret
* base
< I64_MIN
- v
))
795 ret
= ret
* base
+ v
;
798 if (end
&& !empty
) *end
= (wchar_t *)s
;
803 /*********************************************************************
804 * _wcstoui64 (NTDLL.@)
806 unsigned __int64 __cdecl
_wcstoui64( const wchar_t *s
, wchar_t **end
, int base
)
808 BOOL negative
= FALSE
, empty
= TRUE
;
809 unsigned __int64 ret
= 0;
811 if (base
< 0 || base
== 1 || base
> 36) return 0;
812 if (end
) *end
= (wchar_t *)s
;
813 while (iswspace(*s
)) s
++;
820 else if (*s
== '+') s
++;
822 if ((base
== 0 || base
== 16) && !wctoint( *s
) && (s
[1] == 'x' || s
[1] == 'X'))
827 if (base
== 0) base
= wctoint( *s
) ? 10 : 8;
831 int v
= wctoint( *s
);
832 if (v
< 0 || v
>= base
) break;
836 if (ret
> UI64_MAX
/ base
|| ret
* base
> UI64_MAX
- v
)
839 ret
= ret
* base
+ v
;
842 if (end
&& !empty
) *end
= (wchar_t *)s
;
843 return negative
? -ret
: ret
;
847 /*********************************************************************
850 * Converts an unsigned long integer to a unicode string.
853 * Always returns str.
856 * Converts value to a '\0' terminated wstring which is copied to str.
857 * The maximum length of the copied str is 33 bytes.
858 * Does not check if radix is in the range of 2 to 36.
859 * If str is NULL it just returns NULL.
861 LPWSTR __cdecl
_ultow( __msvcrt_ulong value
, LPWSTR str
, INT radix
)
871 digit
= value
% radix
;
872 value
= value
/ radix
;
874 *--pos
= '0' + digit
;
876 *--pos
= 'a' + digit
- 10;
878 } while (value
!= 0L);
881 memcpy(str
, pos
, (&buffer
[32] - pos
+ 1) * sizeof(WCHAR
));
887 /*********************************************************************
890 * Converts a long integer to a unicode string.
893 * Always returns str.
896 * Converts value to a '\0' terminated wstring which is copied to str.
897 * The maximum length of the copied str is 33 bytes. If radix
898 * is 10 and value is negative, the value is converted with sign.
899 * Does not check if radix is in the range of 2 to 36.
900 * If str is NULL it just returns NULL.
902 LPWSTR __cdecl
_ltow( __msvcrt_long value
, LPWSTR str
, INT radix
)
910 if (value
< 0 && radix
== 10) {
925 *--pos
= '0' + digit
;
927 *--pos
= 'a' + digit
- 10;
936 memcpy(str
, pos
, (&buffer
[32] - pos
+ 1) * sizeof(WCHAR
));
942 /*********************************************************************
945 * Converts an integer to a unicode string.
948 * Always returns str.
951 * Converts value to a '\0' terminated wstring which is copied to str.
952 * The maximum length of the copied str is 33 bytes. If radix
953 * is 10 and value is negative, the value is converted with sign.
954 * Does not check if radix is in the range of 2 to 36.
955 * If str is NULL it just returns NULL.
958 * - The native function crashes when the string is longer than 19 chars.
959 * This function does not have this bug.
961 LPWSTR __cdecl
_itow(
962 int value
, /* [I] Value to be converted */
963 LPWSTR str
, /* [O] Destination for the converted value */
964 INT radix
) /* [I] Number base for conversion */
966 return _ltow(value
, str
, radix
);
970 /*********************************************************************
973 * Converts a large unsigned integer to a unicode string.
976 * Always returns str.
979 * Converts value to a '\0' terminated wstring which is copied to str.
980 * The maximum length of the copied str is 33 bytes.
981 * Does not check if radix is in the range of 2 to 36.
982 * If str is NULL it just returns NULL.
985 * - This function does not exist in the native DLL (but in msvcrt).
986 * But since the maintenance of all these functions is better done
987 * in one place we implement it here.
989 LPWSTR __cdecl
_ui64tow(
990 ULONGLONG value
, /* [I] Value to be converted */
991 LPWSTR str
, /* [O] Destination for the converted value */
992 INT radix
) /* [I] Number base for conversion */
1002 digit
= value
% radix
;
1003 value
= value
/ radix
;
1005 *--pos
= '0' + digit
;
1007 *--pos
= 'a' + digit
- 10;
1009 } while (value
!= 0L);
1012 memcpy(str
, pos
, (&buffer
[64] - pos
+ 1) * sizeof(WCHAR
));
1018 /*********************************************************************
1021 * Converts a large integer to a unicode string.
1024 * Always returns str.
1027 * Converts value to a '\0' terminated wstring which is copied to str.
1028 * The maximum length of the copied str is 33 bytes. If radix
1029 * is 10 and value is negative, the value is converted with sign.
1030 * Does not check if radix is in the range of 2 to 36.
1031 * If str is NULL it just returns NULL.
1034 * - The native DLL converts negative values (for base 10) wrong:
1035 * -1 is converted to -18446744073709551615
1036 * -2 is converted to -18446744073709551614
1037 * -9223372036854775807 is converted to -9223372036854775809
1038 * -9223372036854775808 is converted to -9223372036854775808
1039 * The native msvcrt _i64tow function and our ntdll function do
1040 * not have this bug.
1042 LPWSTR __cdecl
_i64tow(
1043 LONGLONG value
, /* [I] Value to be converted */
1044 LPWSTR str
, /* [O] Destination for the converted value */
1045 INT radix
) /* [I] Number base for conversion */
1053 if (value
< 0 && radix
== 10) {
1065 digit
= val
% radix
;
1068 *--pos
= '0' + digit
;
1070 *--pos
= 'a' + digit
- 10;
1072 } while (val
!= 0L);
1079 memcpy(str
, pos
, (&buffer
[64] - pos
+ 1) * sizeof(WCHAR
));
1085 /*********************************************************************
1086 * _ui64tow_s (NTDLL.@)
1088 errno_t __cdecl
_ui64tow_s( unsigned __int64 value
, wchar_t *str
, size_t size
, int radix
)
1090 wchar_t buffer
[65], *pos
;
1092 if (!str
|| !size
) return EINVAL
;
1093 if (radix
< 2 || radix
> 36)
1103 int digit
= value
% radix
;
1104 value
= value
/ radix
;
1106 *--pos
= '0' + digit
;
1108 *--pos
= 'a' + digit
- 10;
1109 } while (value
!= 0);
1111 if (buffer
- pos
+ 65 > size
)
1116 memcpy( str
, pos
, (buffer
- pos
+ 65) * sizeof(wchar_t) );
1121 /*********************************************************************
1122 * _ultow_s (NTDLL.@)
1124 errno_t __cdecl
_ultow_s( __msvcrt_ulong value
, wchar_t *str
, size_t size
, int radix
)
1126 return _ui64tow_s( value
, str
, size
, radix
);
1130 /*********************************************************************
1131 * _i64tow_s (NTDLL.@)
1133 errno_t __cdecl
_i64tow_s( __int64 value
, wchar_t *str
, size_t size
, int radix
)
1135 unsigned __int64 val
;
1137 wchar_t buffer
[65], *pos
;
1139 if (!str
|| !size
) return EINVAL
;
1140 if (radix
< 2 || radix
> 36)
1146 if (value
< 0 && radix
== 10)
1153 is_negative
= FALSE
;
1162 unsigned int digit
= val
% radix
;
1166 *--pos
= '0' + digit
;
1168 *--pos
= 'a' + digit
- 10;
1172 if (is_negative
) *--pos
= '-';
1174 if (buffer
- pos
+ 65 > size
)
1179 memcpy( str
, pos
, (buffer
- pos
+ 65) * sizeof(wchar_t) );
1184 /*********************************************************************
1187 errno_t __cdecl
_ltow_s( __msvcrt_long value
, wchar_t *str
, size_t size
, int radix
)
1189 if (value
< 0 && radix
== 10) return _i64tow_s( value
, str
, size
, radix
);
1190 return _ui64tow_s( (__msvcrt_ulong
)value
, str
, size
, radix
);
1194 /*********************************************************************
1197 errno_t __cdecl
_itow_s( int value
, wchar_t *str
, size_t size
, int radix
)
1199 if (value
< 0 && radix
== 10) return _i64tow_s( value
, str
, size
, radix
);
1200 return _ui64tow_s( (unsigned int)value
, str
, size
, radix
);
1204 /*********************************************************************
1207 * Converts a unicode string to a long integer.
1210 * str [I] Wstring to be converted
1213 * On success it returns the integer value otherwise it returns 0.
1216 * Accepts: {whitespace} [+|-] {digits}
1217 * No check is made for value overflow, only the lower 32 bits are assigned.
1218 * If str is NULL it crashes, as the native function does.
1220 __msvcrt_long __cdecl
_wtol( LPCWSTR str
)
1222 ULONG RunningTotal
= 0;
1223 BOOL bMinus
= FALSE
;
1225 while (iswspace(*str
)) str
++;
1229 } else if (*str
== '-') {
1234 while (*str
>= '0' && *str
<= '9') {
1235 RunningTotal
= RunningTotal
* 10 + *str
- '0';
1239 return bMinus
? -RunningTotal
: RunningTotal
;
1243 /*********************************************************************
1246 * Converts a unicode string to an integer.
1249 * str [I] Wstring to be converted
1252 * On success it returns the integer value otherwise it returns 0.
1255 * Accepts: {whitespace} [+|-] {digits}
1256 * No check is made for value overflow, only the lower 32 bits are assigned.
1257 * If str is NULL it crashes, as the native function does.
1259 int __cdecl
_wtoi( LPCWSTR str
)
1265 /*********************************************************************
1268 * Converts a unicode string to a large integer.
1271 * str [I] Wstring to be converted
1274 * On success it returns the integer value otherwise it returns 0.
1277 * Accepts: {whitespace} [+|-] {digits}
1278 * No check is made for value overflow, only the lower 64 bits are assigned.
1279 * If str is NULL it crashes, as the native function does.
1281 LONGLONG __cdecl
_wtoi64( LPCWSTR str
)
1283 ULONGLONG RunningTotal
= 0;
1284 BOOL bMinus
= FALSE
;
1286 while (iswspace(*str
)) str
++;
1290 } else if (*str
== '-') {
1295 while (*str
>= '0' && *str
<= '9') {
1296 RunningTotal
= RunningTotal
* 10 + *str
- '0';
1300 return bMinus
? -RunningTotal
: RunningTotal
;
1304 /******************************************************************
1305 * _wsplitpath_s (NTDLL.@)
1307 errno_t __cdecl
_wsplitpath_s( const wchar_t *inpath
, wchar_t *drive
, size_t sz_drive
,
1308 wchar_t *dir
, size_t sz_dir
, wchar_t *fname
, size_t sz_fname
,
1309 wchar_t *ext
, size_t sz_ext
)
1311 const wchar_t *p
, *end
;
1313 if (!inpath
|| (!drive
&& sz_drive
) ||
1314 (drive
&& !sz_drive
) ||
1317 (!fname
&& sz_fname
) ||
1318 (fname
&& !sz_fname
) ||
1323 if (inpath
[0] && inpath
[1] == ':')
1327 if (sz_drive
<= 2) goto error
;
1328 drive
[0] = inpath
[0];
1329 drive
[1] = inpath
[1];
1334 else if (drive
) drive
[0] = '\0';
1336 /* look for end of directory part */
1338 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1340 if (end
) /* got a directory */
1344 if (sz_dir
<= end
- inpath
) goto error
;
1345 memcpy( dir
, inpath
, (end
- inpath
) * sizeof(wchar_t) );
1346 dir
[end
- inpath
] = 0;
1350 else if (dir
) dir
[0] = 0;
1352 /* look for extension: what's after the last dot */
1354 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1356 if (!end
) end
= p
; /* there's no extension */
1360 if (sz_fname
<= end
- inpath
) goto error
;
1361 memcpy( fname
, inpath
, (end
- inpath
) * sizeof(wchar_t) );
1362 fname
[end
- inpath
] = 0;
1366 if (sz_ext
<= wcslen(end
)) goto error
;
1372 if (drive
) drive
[0] = 0;
1373 if (dir
) dir
[0] = 0;
1374 if (fname
) fname
[0]= 0;
1380 /*********************************************************************
1381 * _wmakepath_s (NTDLL.@)
1383 errno_t __cdecl
_wmakepath_s( wchar_t *path
, size_t size
, const wchar_t *drive
,
1384 const wchar_t *directory
, const wchar_t *filename
,
1385 const wchar_t *extension
)
1389 if (!path
|| !size
) return EINVAL
;
1391 if (drive
&& drive
[0])
1393 if (size
<= 2) goto range
;
1399 if (directory
&& directory
[0])
1401 unsigned int len
= wcslen(directory
);
1402 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1403 unsigned int copylen
= min(size
- 1, len
);
1405 if (size
< 2) goto range
;
1406 memmove(p
, directory
, copylen
* sizeof(wchar_t));
1407 if (size
<= len
) goto range
;
1410 if (needs_separator
)
1412 if (size
< 2) goto range
;
1418 if (filename
&& filename
[0])
1420 unsigned int len
= wcslen(filename
);
1421 unsigned int copylen
= min(size
- 1, len
);
1423 if (size
< 2) goto range
;
1424 memmove(p
, filename
, copylen
* sizeof(wchar_t));
1425 if (size
<= len
) goto range
;
1430 if (extension
&& extension
[0])
1432 unsigned int len
= wcslen(extension
);
1433 unsigned int needs_period
= extension
[0] != '.';
1434 unsigned int copylen
;
1436 if (size
< 2) goto range
;
1442 copylen
= min(size
- 1, len
);
1443 memcpy(p
, extension
, copylen
* sizeof(wchar_t));
1444 if (size
<= len
) goto range
;