ntdll: Make sure we don't try to attach the main exe a second time.
[wine/zf.git] / dlls / ntdll / wcstring.c
blob1a6d9c1c975f3d6b4f024633b3542f78757d6bd7
1 /*
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
23 #include "config.h"
25 #include <ctype.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdarg.h>
29 #include <stdio.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winnls.h"
34 #include "winternl.h"
35 #include "ntdll_misc.h"
37 static const unsigned short wctypes[256] =
39 /* 00 */
40 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
41 0x0020, 0x0068, 0x0028, 0x0028, 0x0028, 0x0028, 0x0020, 0x0020,
42 /* 10 */
43 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
44 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
45 /* 20 */
46 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
47 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
48 /* 30 */
49 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084,
50 0x0084, 0x0084, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
51 /* 40 */
52 0x0010, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0101,
53 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
54 /* 50 */
55 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
56 0x0101, 0x0101, 0x0101, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
57 /* 60 */
58 0x0010, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0102,
59 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
60 /* 70 */
61 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
62 0x0102, 0x0102, 0x0102, 0x0010, 0x0010, 0x0010, 0x0010, 0x0020,
63 /* 80 */
64 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
65 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
66 /* 90 */
67 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
68 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
69 /* a0 */
70 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
71 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
72 /* b0 */
73 0x0010, 0x0010, 0x0014, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010,
74 0x0010, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
75 /* c0 */
76 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
77 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
78 /* d0 */
79 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0010,
80 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0102,
81 /* e0 */
82 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
83 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
84 /* f0 */
85 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0010,
86 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102
90 /*********************************************************************
91 * _wcsicmp (NTDLL.@)
93 int __cdecl NTDLL__wcsicmp( LPCWSTR str1, LPCWSTR str2 )
95 for (;;)
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;
100 str1++;
101 str2++;
106 /*********************************************************************
107 * _wcslwr (NTDLL.@)
109 LPWSTR __cdecl NTDLL__wcslwr( LPWSTR str )
111 WCHAR *ret = str;
113 while (*str)
115 WCHAR ch = *str;
116 if (ch >= 'A' && ch <= 'Z') ch += 32;
117 *str++ = ch;
119 return ret;
123 /*********************************************************************
124 * _wcsnicmp (NTDLL.@)
126 int __cdecl NTDLL__wcsnicmp( LPCWSTR str1, LPCWSTR str2, size_t n )
128 int ret = 0;
129 for ( ; n > 0; n--, str1++, str2++)
131 WCHAR ch1 = (*str1 >= 'A' && *str1 <= 'Z') ? *str1 + 32 : *str1;
132 WCHAR ch2 = (*str2 >= 'A' && *str2 <= 'Z') ? *str2 + 32 : *str2;
133 if ((ret = ch1 - ch2) || !*str1) break;
135 return ret;
139 /*********************************************************************
140 * _wcsupr (NTDLL.@)
142 LPWSTR __cdecl NTDLL__wcsupr( LPWSTR str )
144 WCHAR *ret = str;
146 while (*str)
148 WCHAR ch = *str;
149 if (ch >= 'a' && ch <= 'z') ch -= 32;
150 *str++ = ch;
152 return ret;
156 /***********************************************************************
157 * wcscpy (NTDLL.@)
159 LPWSTR __cdecl NTDLL_wcscpy( LPWSTR dst, LPCWSTR src )
161 WCHAR *p = dst;
162 while ((*p++ = *src++));
163 return dst;
167 /***********************************************************************
168 * wcslen (NTDLL.@)
170 size_t __cdecl NTDLL_wcslen( LPCWSTR str )
172 const WCHAR *s = str;
173 while (*s) s++;
174 return s - str;
178 /***********************************************************************
179 * wcscat (NTDLL.@)
181 LPWSTR __cdecl NTDLL_wcscat( LPWSTR dst, LPCWSTR src )
183 NTDLL_wcscpy( dst + NTDLL_wcslen(dst), src );
184 return dst;
188 /*********************************************************************
189 * wcschr (NTDLL.@)
191 LPWSTR __cdecl NTDLL_wcschr( LPCWSTR str, WCHAR ch )
193 do { if (*str == ch) return (WCHAR *)(ULONG_PTR)str; } while (*str++);
194 return NULL;
198 /*********************************************************************
199 * wcscmp (NTDLL.@)
201 int __cdecl NTDLL_wcscmp( LPCWSTR str1, LPCWSTR str2 )
203 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
204 return *str1 - *str2;
208 /*********************************************************************
209 * wcscspn (NTDLL.@)
211 size_t __cdecl NTDLL_wcscspn( LPCWSTR str, LPCWSTR reject )
213 const WCHAR *ptr;
214 for (ptr = str; *ptr; ptr++) if (NTDLL_wcschr( reject, *ptr )) break;
215 return ptr - str;
219 /*********************************************************************
220 * wcsncat (NTDLL.@)
222 LPWSTR __cdecl NTDLL_wcsncat( LPWSTR s1, LPCWSTR s2, size_t n )
224 LPWSTR ret = s1;
225 while (*s1) s1++;
226 while (n-- > 0) if (!(*s1++ = *s2++)) return ret;
227 *s1 = 0;
228 return ret;
232 /*********************************************************************
233 * wcsncmp (NTDLL.@)
235 int __cdecl NTDLL_wcsncmp( LPCWSTR str1, LPCWSTR str2, size_t n )
237 if (n <= 0) return 0;
238 while ((--n > 0) && *str1 && (*str1 == *str2)) { str1++; str2++; }
239 return *str1 - *str2;
243 /*********************************************************************
244 * wcsncpy (NTDLL.@)
246 LPWSTR __cdecl NTDLL_wcsncpy( LPWSTR s1, LPCWSTR s2, size_t n )
248 WCHAR *ret = s1;
249 while (n-- > 0) if (!(*s1++ = *s2++)) break;
250 while (n-- > 0) *s1++ = 0;
251 return ret;
255 /*********************************************************************
256 * wcspbrk (NTDLL.@)
258 LPWSTR __cdecl NTDLL_wcspbrk( LPCWSTR str, LPCWSTR accept )
260 for ( ; *str; str++) if (NTDLL_wcschr( accept, *str )) return (WCHAR *)(ULONG_PTR)str;
261 return NULL;
265 /*********************************************************************
266 * wcsrchr (NTDLL.@)
268 LPWSTR __cdecl NTDLL_wcsrchr( LPCWSTR str, WCHAR ch )
270 WCHAR *ret = NULL;
271 do { if (*str == ch) ret = (WCHAR *)(ULONG_PTR)str; } while (*str++);
272 return ret;
276 /*********************************************************************
277 * wcsspn (NTDLL.@)
279 size_t __cdecl NTDLL_wcsspn( LPCWSTR str, LPCWSTR accept )
281 const WCHAR *ptr;
282 for (ptr = str; *ptr; ptr++) if (!NTDLL_wcschr( accept, *ptr )) break;
283 return ptr - str;
287 /*********************************************************************
288 * wcsstr (NTDLL.@)
290 LPWSTR __cdecl NTDLL_wcsstr( LPCWSTR str, LPCWSTR sub )
292 while (*str)
294 const WCHAR *p1 = str, *p2 = sub;
295 while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
296 if (!*p2) return (WCHAR *)str;
297 str++;
299 return NULL;
303 /*********************************************************************
304 * wcstok (NTDLL.@)
306 LPWSTR __cdecl NTDLL_wcstok( LPWSTR str, LPCWSTR delim )
308 static LPWSTR next = NULL;
309 LPWSTR ret;
311 if (!str)
312 if (!(str = next)) return NULL;
314 while (*str && NTDLL_wcschr( delim, *str )) str++;
315 if (!*str) return NULL;
316 ret = str++;
317 while (*str && !NTDLL_wcschr( delim, *str )) str++;
318 if (*str) *str++ = 0;
319 next = str;
320 return ret;
324 /*********************************************************************
325 * wcstombs (NTDLL.@)
327 INT __cdecl NTDLL_wcstombs( LPSTR dst, LPCWSTR src, INT n )
329 DWORD len;
331 if (!dst)
333 RtlUnicodeToMultiByteSize( &len, src, NTDLL_wcslen(src) * sizeof(WCHAR) );
334 return len;
336 else
338 if (n <= 0) return 0;
339 RtlUnicodeToMultiByteN( dst, n, &len, src, NTDLL_wcslen(src) * sizeof(WCHAR) );
340 if (len < n) dst[len] = 0;
342 return len;
346 /*********************************************************************
347 * mbstowcs (NTDLL.@)
349 INT __cdecl NTDLL_mbstowcs( LPWSTR dst, LPCSTR src, INT n )
351 DWORD len;
353 if (!dst)
355 RtlMultiByteToUnicodeSize( &len, src, strlen(src) );
357 else
359 if (n <= 0) return 0;
360 RtlMultiByteToUnicodeN( dst, n*sizeof(WCHAR), &len, src, strlen(src) );
361 if (len / sizeof(WCHAR) < n) dst[len / sizeof(WCHAR)] = 0;
363 return len / sizeof(WCHAR);
367 /*********************************************************************
368 * iswctype (NTDLL.@)
370 INT __cdecl NTDLL_iswctype( WCHAR wc, unsigned short type )
372 if (wc >= 256) return 0;
373 return wctypes[wc] & type;
377 /*********************************************************************
378 * iswalpha (NTDLL.@)
380 INT __cdecl NTDLL_iswalpha( WCHAR wc )
382 if (wc >= 256) return 0;
383 return wctypes[wc] & (C1_ALPHA | C1_UPPER | C1_LOWER);
387 /*********************************************************************
388 * iswdigit (NTDLL.@)
390 * Checks if a unicode char wc is a digit
392 * RETURNS
393 * TRUE: The unicode char wc is a digit.
394 * FALSE: Otherwise
396 INT __cdecl NTDLL_iswdigit( WCHAR wc )
398 if (wc >= 256) return 0;
399 return wctypes[wc] & C1_DIGIT;
403 /*********************************************************************
404 * iswlower (NTDLL.@)
406 * Checks if a unicode char wc is a lower case letter
408 * RETURNS
409 * TRUE: The unicode char wc is a lower case letter.
410 * FALSE: Otherwise
412 INT __cdecl NTDLL_iswlower( WCHAR wc )
414 if (wc >= 256) return 0;
415 return wctypes[wc] & C1_LOWER;
419 /*********************************************************************
420 * iswspace (NTDLL.@)
422 * Checks if a unicode char wc is a white space character
424 * RETURNS
425 * TRUE: The unicode char wc is a white space character.
426 * FALSE: Otherwise
428 INT __cdecl NTDLL_iswspace( WCHAR wc )
430 if (wc >= 256) return 0;
431 return wctypes[wc] & C1_SPACE;
435 /*********************************************************************
436 * iswxdigit (NTDLL.@)
438 * Checks if a unicode char wc is an extended digit
440 * RETURNS
441 * TRUE: The unicode char wc is an extended digit.
442 * FALSE: Otherwise
444 INT __cdecl NTDLL_iswxdigit( WCHAR wc )
446 if (wc >= 256) return 0;
447 return wctypes[wc] & C1_XDIGIT;
451 static int wctoint( WCHAR c )
453 /* NOTE: MAP_FOLDDIGITS supports too many things. */
454 /* Unicode points that contain digits 0-9; keep this sorted! */
455 static const WCHAR zeros[] =
457 0x0660, 0x06f0, 0x0966, 0x09e6, 0x0a66, 0x0ae6, 0x0b66, 0x0c66, 0x0ce6,
458 0x0d66, 0x0e50, 0x0ed0, 0x0f20, 0x1040, 0x17e0, 0x1810, 0xff10
460 int i;
462 if ('0' <= c && c <= '9') return c - '0';
463 if ('A' <= c && c <= 'Z') return c - 'A' + 10;
464 if ('a' <= c && c <= 'z') return c - 'a' + 10;
465 for (i = 0; i < ARRAY_SIZE(zeros) && c >= zeros[i]; i++)
466 if (zeros[i] <= c && c <= zeros[i] + 9) return c - zeros[i];
468 return -1;
471 /*********************************************************************
472 * wcstol (NTDLL.@)
474 LONG __cdecl NTDLL_wcstol(LPCWSTR s, LPWSTR *end, INT base)
476 BOOL negative = FALSE, empty = TRUE;
477 LONG ret = 0;
479 if (base < 0 || base == 1 || base > 36) return 0;
480 if (end) *end = (WCHAR *)s;
481 while (NTDLL_iswspace(*s)) s++;
483 if (*s == '-')
485 negative = TRUE;
486 s++;
488 else if (*s == '+') s++;
490 if ((base == 0 || base == 16) && !wctoint( *s ) && (s[1] == 'x' || s[1] == 'X'))
492 base = 16;
493 s += 2;
495 if (base == 0) base = wctoint( *s ) ? 10 : 8;
497 while (*s)
499 int v = wctoint( *s );
500 if (v < 0 || v >= base) break;
501 if (negative) v = -v;
502 s++;
503 empty = FALSE;
505 if (!negative && (ret > MAXLONG / base || ret * base > MAXLONG - v))
506 ret = MAXLONG;
507 else if (negative && (ret < (LONG)MINLONG / base || ret * base < (LONG)(MINLONG - v)))
508 ret = MINLONG;
509 else
510 ret = ret * base + v;
513 if (end && !empty) *end = (WCHAR *)s;
514 return ret;
518 /*********************************************************************
519 * wcstoul (NTDLL.@)
521 ULONG __cdecl NTDLL_wcstoul(LPCWSTR s, LPWSTR *end, INT base)
523 BOOL negative = FALSE, empty = TRUE;
524 ULONG ret = 0;
526 if (base < 0 || base == 1 || base > 36) return 0;
527 if (end) *end = (WCHAR *)s;
528 while (NTDLL_iswspace(*s)) s++;
530 if (*s == '-')
532 negative = TRUE;
533 s++;
535 else if (*s == '+') s++;
537 if ((base == 0 || base == 16) && !wctoint( *s ) && (s[1] == 'x' || s[1] == 'X'))
539 base = 16;
540 s += 2;
542 if (base == 0) base = wctoint( *s ) ? 10 : 8;
544 while (*s)
546 int v = wctoint( *s );
547 if (v < 0 || v >= base) break;
548 s++;
549 empty = FALSE;
551 if (ret > MAXDWORD / base || ret * base > MAXDWORD - v)
552 ret = MAXDWORD;
553 else
554 ret = ret * base + v;
557 if (end && !empty) *end = (WCHAR *)s;
558 return negative ? -ret : ret;
562 /*********************************************************************
563 * _ultow (NTDLL.@)
565 * Converts an unsigned long integer to a unicode string.
567 * RETURNS
568 * Always returns str.
570 * NOTES
571 * Converts value to a '\0' terminated wstring which is copied to str.
572 * The maximum length of the copied str is 33 bytes.
573 * Does not check if radix is in the range of 2 to 36.
574 * If str is NULL it just returns NULL.
576 LPWSTR __cdecl _ultow(
577 ULONG value, /* [I] Value to be converted */
578 LPWSTR str, /* [O] Destination for the converted value */
579 INT radix) /* [I] Number base for conversion */
581 WCHAR buffer[33];
582 PWCHAR pos;
583 WCHAR digit;
585 pos = &buffer[32];
586 *pos = '\0';
588 do {
589 digit = value % radix;
590 value = value / radix;
591 if (digit < 10) {
592 *--pos = '0' + digit;
593 } else {
594 *--pos = 'a' + digit - 10;
595 } /* if */
596 } while (value != 0L);
598 if (str != NULL) {
599 memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR));
600 } /* if */
601 return str;
605 /*********************************************************************
606 * _ltow (NTDLL.@)
608 * Converts a long integer to a unicode string.
610 * RETURNS
611 * Always returns str.
613 * NOTES
614 * Converts value to a '\0' terminated wstring which is copied to str.
615 * The maximum length of the copied str is 33 bytes. If radix
616 * is 10 and value is negative, the value is converted with sign.
617 * Does not check if radix is in the range of 2 to 36.
618 * If str is NULL it just returns NULL.
620 LPWSTR __cdecl _ltow(
621 LONG value, /* [I] Value to be converted */
622 LPWSTR str, /* [O] Destination for the converted value */
623 INT radix) /* [I] Number base for conversion */
625 ULONG val;
626 int negative;
627 WCHAR buffer[33];
628 PWCHAR pos;
629 WCHAR digit;
631 if (value < 0 && radix == 10) {
632 negative = 1;
633 val = -value;
634 } else {
635 negative = 0;
636 val = value;
637 } /* if */
639 pos = &buffer[32];
640 *pos = '\0';
642 do {
643 digit = val % radix;
644 val = val / radix;
645 if (digit < 10) {
646 *--pos = '0' + digit;
647 } else {
648 *--pos = 'a' + digit - 10;
649 } /* if */
650 } while (val != 0L);
652 if (negative) {
653 *--pos = '-';
654 } /* if */
656 if (str != NULL) {
657 memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR));
658 } /* if */
659 return str;
663 /*********************************************************************
664 * _itow (NTDLL.@)
666 * Converts an integer to a unicode string.
668 * RETURNS
669 * Always returns str.
671 * NOTES
672 * Converts value to a '\0' terminated wstring which is copied to str.
673 * The maximum length of the copied str is 33 bytes. If radix
674 * is 10 and value is negative, the value is converted with sign.
675 * Does not check if radix is in the range of 2 to 36.
676 * If str is NULL it just returns NULL.
678 * DIFFERENCES
679 * - The native function crashes when the string is longer than 19 chars.
680 * This function does not have this bug.
682 LPWSTR __cdecl _itow(
683 int value, /* [I] Value to be converted */
684 LPWSTR str, /* [O] Destination for the converted value */
685 INT radix) /* [I] Number base for conversion */
687 return _ltow(value, str, radix);
691 /*********************************************************************
692 * _ui64tow (NTDLL.@)
694 * Converts a large unsigned integer to a unicode string.
696 * RETURNS
697 * Always returns str.
699 * NOTES
700 * Converts value to a '\0' terminated wstring which is copied to str.
701 * The maximum length of the copied str is 33 bytes.
702 * Does not check if radix is in the range of 2 to 36.
703 * If str is NULL it just returns NULL.
705 * DIFFERENCES
706 * - This function does not exist in the native DLL (but in msvcrt).
707 * But since the maintenance of all these functions is better done
708 * in one place we implement it here.
710 LPWSTR __cdecl _ui64tow(
711 ULONGLONG value, /* [I] Value to be converted */
712 LPWSTR str, /* [O] Destination for the converted value */
713 INT radix) /* [I] Number base for conversion */
715 WCHAR buffer[65];
716 PWCHAR pos;
717 WCHAR digit;
719 pos = &buffer[64];
720 *pos = '\0';
722 do {
723 digit = value % radix;
724 value = value / radix;
725 if (digit < 10) {
726 *--pos = '0' + digit;
727 } else {
728 *--pos = 'a' + digit - 10;
729 } /* if */
730 } while (value != 0L);
732 if (str != NULL) {
733 memcpy(str, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR));
734 } /* if */
735 return str;
739 /*********************************************************************
740 * _i64tow (NTDLL.@)
742 * Converts a large integer to a unicode string.
744 * RETURNS
745 * Always returns str.
747 * NOTES
748 * Converts value to a '\0' terminated wstring which is copied to str.
749 * The maximum length of the copied str is 33 bytes. If radix
750 * is 10 and value is negative, the value is converted with sign.
751 * Does not check if radix is in the range of 2 to 36.
752 * If str is NULL it just returns NULL.
754 * DIFFERENCES
755 * - The native DLL converts negative values (for base 10) wrong:
756 * -1 is converted to -18446744073709551615
757 * -2 is converted to -18446744073709551614
758 * -9223372036854775807 is converted to -9223372036854775809
759 * -9223372036854775808 is converted to -9223372036854775808
760 * The native msvcrt _i64tow function and our ntdll function do
761 * not have this bug.
763 LPWSTR __cdecl _i64tow(
764 LONGLONG value, /* [I] Value to be converted */
765 LPWSTR str, /* [O] Destination for the converted value */
766 INT radix) /* [I] Number base for conversion */
768 ULONGLONG val;
769 int negative;
770 WCHAR buffer[65];
771 PWCHAR pos;
772 WCHAR digit;
774 if (value < 0 && radix == 10) {
775 negative = 1;
776 val = -value;
777 } else {
778 negative = 0;
779 val = value;
780 } /* if */
782 pos = &buffer[64];
783 *pos = '\0';
785 do {
786 digit = val % radix;
787 val = val / radix;
788 if (digit < 10) {
789 *--pos = '0' + digit;
790 } else {
791 *--pos = 'a' + digit - 10;
792 } /* if */
793 } while (val != 0L);
795 if (negative) {
796 *--pos = '-';
797 } /* if */
799 if (str != NULL) {
800 memcpy(str, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR));
801 } /* if */
802 return str;
806 /*********************************************************************
807 * _wtol (NTDLL.@)
809 * Converts a unicode string to a long integer.
811 * PARAMS
812 * str [I] Wstring to be converted
814 * RETURNS
815 * On success it returns the integer value otherwise it returns 0.
817 * NOTES
818 * Accepts: {whitespace} [+|-] {digits}
819 * No check is made for value overflow, only the lower 32 bits are assigned.
820 * If str is NULL it crashes, as the native function does.
822 LONG __cdecl _wtol( LPCWSTR str )
824 ULONG RunningTotal = 0;
825 BOOL bMinus = FALSE;
827 while (NTDLL_iswspace(*str)) str++;
829 if (*str == '+') {
830 str++;
831 } else if (*str == '-') {
832 bMinus = TRUE;
833 str++;
834 } /* if */
836 while (*str >= '0' && *str <= '9') {
837 RunningTotal = RunningTotal * 10 + *str - '0';
838 str++;
839 } /* while */
841 return bMinus ? -RunningTotal : RunningTotal;
845 /*********************************************************************
846 * _wtoi (NTDLL.@)
848 * Converts a unicode string to an integer.
850 * PARAMS
851 * str [I] Wstring to be converted
853 * RETURNS
854 * On success it returns the integer value otherwise it returns 0.
856 * NOTES
857 * Accepts: {whitespace} [+|-] {digits}
858 * No check is made for value overflow, only the lower 32 bits are assigned.
859 * If str is NULL it crashes, as the native function does.
861 int __cdecl _wtoi( LPCWSTR str )
863 return _wtol(str);
867 /*********************************************************************
868 * _wtoi64 (NTDLL.@)
870 * Converts a unicode string to a large integer.
872 * PARAMS
873 * str [I] Wstring to be converted
875 * RETURNS
876 * On success it returns the integer value otherwise it returns 0.
878 * NOTES
879 * Accepts: {whitespace} [+|-] {digits}
880 * No check is made for value overflow, only the lower 64 bits are assigned.
881 * If str is NULL it crashes, as the native function does.
883 LONGLONG __cdecl _wtoi64( LPCWSTR str )
885 ULONGLONG RunningTotal = 0;
886 BOOL bMinus = FALSE;
888 while (NTDLL_iswspace(*str)) str++;
890 if (*str == '+') {
891 str++;
892 } else if (*str == '-') {
893 bMinus = TRUE;
894 str++;
895 } /* if */
897 while (*str >= '0' && *str <= '9') {
898 RunningTotal = RunningTotal * 10 + *str - '0';
899 str++;
900 } /* while */
902 return bMinus ? -RunningTotal : RunningTotal;