dbghelp: Fix memory leak on error path in dwarf2_read_range (cppcheck).
[wine.git] / dlls / ntdll / wcstring.c
blob9422e4f676c2450d4fedc74438ba1f5ab2002455
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 <ctype.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdarg.h>
27 #include <stdio.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winnls.h"
32 #include "winternl.h"
33 #include "ntdll_misc.h"
35 static const unsigned short wctypes[256] =
37 /* 00 */
38 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
39 0x0020, 0x0068, 0x0028, 0x0028, 0x0028, 0x0028, 0x0020, 0x0020,
40 /* 10 */
41 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
42 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
43 /* 20 */
44 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
45 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
46 /* 30 */
47 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084, 0x0084,
48 0x0084, 0x0084, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
49 /* 40 */
50 0x0010, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0181, 0x0101,
51 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
52 /* 50 */
53 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
54 0x0101, 0x0101, 0x0101, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
55 /* 60 */
56 0x0010, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0182, 0x0102,
57 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
58 /* 70 */
59 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
60 0x0102, 0x0102, 0x0102, 0x0010, 0x0010, 0x0010, 0x0010, 0x0020,
61 /* 80 */
62 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
63 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
64 /* 90 */
65 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
66 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020, 0x0020,
67 /* a0 */
68 0x0048, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
69 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
70 /* b0 */
71 0x0010, 0x0010, 0x0014, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010,
72 0x0010, 0x0014, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
73 /* c0 */
74 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
75 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101,
76 /* d0 */
77 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0010,
78 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0101, 0x0102,
79 /* e0 */
80 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
81 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102,
82 /* f0 */
83 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0010,
84 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102, 0x0102
88 /*********************************************************************
89 * _wcsicmp (NTDLL.@)
91 int __cdecl _wcsicmp( LPCWSTR str1, LPCWSTR str2 )
93 for (;;)
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;
98 str1++;
99 str2++;
104 /*********************************************************************
105 * _wcslwr (NTDLL.@)
107 LPWSTR __cdecl _wcslwr( LPWSTR str )
109 WCHAR *ret = str;
111 while (*str)
113 WCHAR ch = *str;
114 if (ch >= 'A' && ch <= 'Z') ch += 32;
115 *str++ = ch;
117 return ret;
121 /*********************************************************************
122 * _wcsnicmp (NTDLL.@)
124 int __cdecl _wcsnicmp( LPCWSTR str1, LPCWSTR str2, size_t n )
126 int ret = 0;
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;
133 return ret;
137 /*********************************************************************
138 * _wcsupr (NTDLL.@)
140 LPWSTR __cdecl _wcsupr( LPWSTR str )
142 WCHAR *ret = str;
144 while (*str)
146 WCHAR ch = *str;
147 if (ch >= 'a' && ch <= 'z') ch -= 32;
148 *str++ = ch;
150 return ret;
154 /***********************************************************************
155 * wcscpy (NTDLL.@)
157 LPWSTR __cdecl wcscpy( LPWSTR dst, LPCWSTR src )
159 WCHAR *p = dst;
160 while ((*p++ = *src++));
161 return dst;
165 /***********************************************************************
166 * wcslen (NTDLL.@)
168 size_t __cdecl wcslen( LPCWSTR str )
170 const WCHAR *s = str;
171 while (*s) s++;
172 return s - str;
176 /***********************************************************************
177 * wcscat (NTDLL.@)
179 LPWSTR __cdecl wcscat( LPWSTR dst, LPCWSTR src )
181 wcscpy( dst + wcslen(dst), src );
182 return dst;
186 /*********************************************************************
187 * wcschr (NTDLL.@)
189 LPWSTR __cdecl wcschr( LPCWSTR str, WCHAR ch )
191 do { if (*str == ch) return (WCHAR *)(ULONG_PTR)str; } while (*str++);
192 return NULL;
196 /*********************************************************************
197 * wcscmp (NTDLL.@)
199 int __cdecl wcscmp( LPCWSTR str1, LPCWSTR str2 )
201 while (*str1 && (*str1 == *str2)) { str1++; str2++; }
202 return *str1 - *str2;
206 /*********************************************************************
207 * wcscspn (NTDLL.@)
209 size_t __cdecl wcscspn( LPCWSTR str, LPCWSTR reject )
211 const WCHAR *ptr;
212 for (ptr = str; *ptr; ptr++) if (wcschr( reject, *ptr )) break;
213 return ptr - str;
217 /*********************************************************************
218 * wcsncat (NTDLL.@)
220 LPWSTR __cdecl wcsncat( LPWSTR s1, LPCWSTR s2, size_t n )
222 LPWSTR ret = s1;
223 while (*s1) s1++;
224 while (n-- > 0) if (!(*s1++ = *s2++)) return ret;
225 *s1 = 0;
226 return ret;
230 /*********************************************************************
231 * wcsncmp (NTDLL.@)
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 /*********************************************************************
242 * wcsncpy (NTDLL.@)
244 #undef wcsncpy
245 LPWSTR __cdecl wcsncpy( LPWSTR s1, LPCWSTR s2, size_t n )
247 WCHAR *ret = s1;
248 for ( ; n; n--) if (!(*s1++ = *s2++)) break;
249 for ( ; n; n--) *s1++ = 0;
250 return ret;
254 /*********************************************************************
255 * wcsnlen (NTDLL.@)
257 size_t __cdecl wcsnlen( const WCHAR *str, size_t len )
259 const WCHAR *s = str;
260 for (s = str; len && *s; s++, len--) ;
261 return s - str;
265 /*********************************************************************
266 * wcspbrk (NTDLL.@)
268 LPWSTR __cdecl wcspbrk( LPCWSTR str, LPCWSTR accept )
270 for ( ; *str; str++) if (wcschr( accept, *str )) return (WCHAR *)(ULONG_PTR)str;
271 return NULL;
275 /*********************************************************************
276 * wcsrchr (NTDLL.@)
278 LPWSTR __cdecl wcsrchr( LPCWSTR str, WCHAR ch )
280 WCHAR *ret = NULL;
281 do { if (*str == ch) ret = (WCHAR *)(ULONG_PTR)str; } while (*str++);
282 return ret;
286 /*********************************************************************
287 * wcsspn (NTDLL.@)
289 size_t __cdecl wcsspn( LPCWSTR str, LPCWSTR accept )
291 const WCHAR *ptr;
292 for (ptr = str; *ptr; ptr++) if (!wcschr( accept, *ptr )) break;
293 return ptr - str;
297 /*********************************************************************
298 * wcsstr (NTDLL.@)
300 LPWSTR __cdecl wcsstr( LPCWSTR str, LPCWSTR sub )
302 while (*str)
304 const WCHAR *p1 = str, *p2 = sub;
305 while (*p1 && *p2 && *p1 == *p2) { p1++; p2++; }
306 if (!*p2) return (WCHAR *)str;
307 str++;
309 return NULL;
313 /*********************************************************************
314 * wcstok (NTDLL.@)
316 LPWSTR __cdecl wcstok( LPWSTR str, LPCWSTR delim )
318 static LPWSTR next = NULL;
319 LPWSTR ret;
321 if (!str)
322 if (!(str = next)) return NULL;
324 while (*str && wcschr( delim, *str )) str++;
325 if (!*str) return NULL;
326 ret = str++;
327 while (*str && !wcschr( delim, *str )) str++;
328 if (*str) *str++ = 0;
329 next = str;
330 return ret;
334 /*********************************************************************
335 * wcstombs (NTDLL.@)
337 size_t __cdecl wcstombs( char *dst, const WCHAR *src, size_t n )
339 DWORD len;
341 if (!dst)
343 RtlUnicodeToMultiByteSize( &len, src, wcslen(src) * sizeof(WCHAR) );
344 return len;
346 else
348 if (n <= 0) return 0;
349 RtlUnicodeToMultiByteN( dst, n, &len, src, wcslen(src) * sizeof(WCHAR) );
350 if (len < n) dst[len] = 0;
352 return len;
356 /*********************************************************************
357 * mbstowcs (NTDLL.@)
359 size_t __cdecl mbstowcs( WCHAR *dst, const char *src, size_t n )
361 DWORD len;
363 if (!dst)
365 RtlMultiByteToUnicodeSize( &len, src, strlen(src) );
367 else
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 /*********************************************************************
378 * iswctype (NTDLL.@)
380 INT __cdecl iswctype( WCHAR wc, unsigned short type )
382 if (wc >= 256) return 0;
383 return wctypes[wc] & type;
387 /*********************************************************************
388 * iswalpha (NTDLL.@)
390 INT __cdecl iswalpha( WCHAR wc )
392 if (wc >= 256) return 0;
393 return wctypes[wc] & (C1_ALPHA | C1_UPPER | C1_LOWER);
397 /*********************************************************************
398 * iswdigit (NTDLL.@)
400 * Checks if a unicode char wc is a digit
402 * RETURNS
403 * TRUE: The unicode char wc is a digit.
404 * FALSE: Otherwise
406 INT __cdecl iswdigit( WCHAR wc )
408 if (wc >= 256) return 0;
409 return wctypes[wc] & C1_DIGIT;
413 /*********************************************************************
414 * iswlower (NTDLL.@)
416 * Checks if a unicode char wc is a lower case letter
418 * RETURNS
419 * TRUE: The unicode char wc is a lower case letter.
420 * FALSE: Otherwise
422 INT __cdecl iswlower( WCHAR wc )
424 if (wc >= 256) return 0;
425 return wctypes[wc] & C1_LOWER;
429 /*********************************************************************
430 * iswspace (NTDLL.@)
432 * Checks if a unicode char wc is a white space character
434 * RETURNS
435 * TRUE: The unicode char wc is a white space character.
436 * FALSE: Otherwise
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
450 * RETURNS
451 * TRUE: The unicode char wc is an extended digit.
452 * FALSE: Otherwise
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
470 int i;
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];
478 return -1;
481 /*********************************************************************
482 * wcstol (NTDLL.@)
484 __msvcrt_long __cdecl wcstol(LPCWSTR s, LPWSTR *end, INT base)
486 BOOL negative = FALSE, empty = TRUE;
487 LONG ret = 0;
489 if (base < 0 || base == 1 || base > 36) return 0;
490 if (end) *end = (WCHAR *)s;
491 while (iswspace(*s)) s++;
493 if (*s == '-')
495 negative = TRUE;
496 s++;
498 else if (*s == '+') s++;
500 if ((base == 0 || base == 16) && !wctoint( *s ) && (s[1] == 'x' || s[1] == 'X'))
502 base = 16;
503 s += 2;
505 if (base == 0) base = wctoint( *s ) ? 10 : 8;
507 while (*s)
509 int v = wctoint( *s );
510 if (v < 0 || v >= base) break;
511 if (negative) v = -v;
512 s++;
513 empty = FALSE;
515 if (!negative && (ret > MAXLONG / base || ret * base > MAXLONG - v))
516 ret = MAXLONG;
517 else if (negative && (ret < (LONG)MINLONG / base || ret * base < (LONG)(MINLONG - v)))
518 ret = MINLONG;
519 else
520 ret = ret * base + v;
523 if (end && !empty) *end = (WCHAR *)s;
524 return ret;
528 /*********************************************************************
529 * wcstoul (NTDLL.@)
531 __msvcrt_ulong __cdecl wcstoul(LPCWSTR s, LPWSTR *end, INT base)
533 BOOL negative = FALSE, empty = TRUE;
534 ULONG ret = 0;
536 if (base < 0 || base == 1 || base > 36) return 0;
537 if (end) *end = (WCHAR *)s;
538 while (iswspace(*s)) s++;
540 if (*s == '-')
542 negative = TRUE;
543 s++;
545 else if (*s == '+') s++;
547 if ((base == 0 || base == 16) && !wctoint( *s ) && (s[1] == 'x' || s[1] == 'X'))
549 base = 16;
550 s += 2;
552 if (base == 0) base = wctoint( *s ) ? 10 : 8;
554 while (*s)
556 int v = wctoint( *s );
557 if (v < 0 || v >= base) break;
558 s++;
559 empty = FALSE;
561 if (ret > MAXDWORD / base || ret * base > MAXDWORD - v)
562 ret = MAXDWORD;
563 else
564 ret = ret * base + v;
567 if (end && !empty) *end = (WCHAR *)s;
568 return negative ? -ret : ret;
572 /*********************************************************************
573 * _ultow (NTDLL.@)
575 * Converts an unsigned long integer to a unicode string.
577 * RETURNS
578 * Always returns str.
580 * NOTES
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 )
588 WCHAR buffer[33];
589 PWCHAR pos;
590 WCHAR digit;
592 pos = &buffer[32];
593 *pos = '\0';
595 do {
596 digit = value % radix;
597 value = value / radix;
598 if (digit < 10) {
599 *--pos = '0' + digit;
600 } else {
601 *--pos = 'a' + digit - 10;
602 } /* if */
603 } while (value != 0L);
605 if (str != NULL) {
606 memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR));
607 } /* if */
608 return str;
612 /*********************************************************************
613 * _ltow (NTDLL.@)
615 * Converts a long integer to a unicode string.
617 * RETURNS
618 * Always returns str.
620 * NOTES
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 )
629 ULONG val;
630 int negative;
631 WCHAR buffer[33];
632 PWCHAR pos;
633 WCHAR digit;
635 if (value < 0 && radix == 10) {
636 negative = 1;
637 val = -value;
638 } else {
639 negative = 0;
640 val = value;
641 } /* if */
643 pos = &buffer[32];
644 *pos = '\0';
646 do {
647 digit = val % radix;
648 val = val / radix;
649 if (digit < 10) {
650 *--pos = '0' + digit;
651 } else {
652 *--pos = 'a' + digit - 10;
653 } /* if */
654 } while (val != 0L);
656 if (negative) {
657 *--pos = '-';
658 } /* if */
660 if (str != NULL) {
661 memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR));
662 } /* if */
663 return str;
667 /*********************************************************************
668 * _itow (NTDLL.@)
670 * Converts an integer to a unicode string.
672 * RETURNS
673 * Always returns str.
675 * NOTES
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.
682 * DIFFERENCES
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 /*********************************************************************
696 * _ui64tow (NTDLL.@)
698 * Converts a large unsigned integer to a unicode string.
700 * RETURNS
701 * Always returns str.
703 * NOTES
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.
709 * DIFFERENCES
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 */
719 WCHAR buffer[65];
720 PWCHAR pos;
721 WCHAR digit;
723 pos = &buffer[64];
724 *pos = '\0';
726 do {
727 digit = value % radix;
728 value = value / radix;
729 if (digit < 10) {
730 *--pos = '0' + digit;
731 } else {
732 *--pos = 'a' + digit - 10;
733 } /* if */
734 } while (value != 0L);
736 if (str != NULL) {
737 memcpy(str, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR));
738 } /* if */
739 return str;
743 /*********************************************************************
744 * _i64tow (NTDLL.@)
746 * Converts a large integer to a unicode string.
748 * RETURNS
749 * Always returns str.
751 * NOTES
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.
758 * DIFFERENCES
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
765 * not have this bug.
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 */
772 ULONGLONG val;
773 int negative;
774 WCHAR buffer[65];
775 PWCHAR pos;
776 WCHAR digit;
778 if (value < 0 && radix == 10) {
779 negative = 1;
780 val = -value;
781 } else {
782 negative = 0;
783 val = value;
784 } /* if */
786 pos = &buffer[64];
787 *pos = '\0';
789 do {
790 digit = val % radix;
791 val = val / radix;
792 if (digit < 10) {
793 *--pos = '0' + digit;
794 } else {
795 *--pos = 'a' + digit - 10;
796 } /* if */
797 } while (val != 0L);
799 if (negative) {
800 *--pos = '-';
801 } /* if */
803 if (str != NULL) {
804 memcpy(str, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR));
805 } /* if */
806 return str;
810 /*********************************************************************
811 * _wtol (NTDLL.@)
813 * Converts a unicode string to a long integer.
815 * PARAMS
816 * str [I] Wstring to be converted
818 * RETURNS
819 * On success it returns the integer value otherwise it returns 0.
821 * NOTES
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;
829 BOOL bMinus = FALSE;
831 while (iswspace(*str)) str++;
833 if (*str == '+') {
834 str++;
835 } else if (*str == '-') {
836 bMinus = TRUE;
837 str++;
838 } /* if */
840 while (*str >= '0' && *str <= '9') {
841 RunningTotal = RunningTotal * 10 + *str - '0';
842 str++;
843 } /* while */
845 return bMinus ? -RunningTotal : RunningTotal;
849 /*********************************************************************
850 * _wtoi (NTDLL.@)
852 * Converts a unicode string to an integer.
854 * PARAMS
855 * str [I] Wstring to be converted
857 * RETURNS
858 * On success it returns the integer value otherwise it returns 0.
860 * NOTES
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 )
867 return _wtol(str);
871 /*********************************************************************
872 * _wtoi64 (NTDLL.@)
874 * Converts a unicode string to a large integer.
876 * PARAMS
877 * str [I] Wstring to be converted
879 * RETURNS
880 * On success it returns the integer value otherwise it returns 0.
882 * NOTES
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;
890 BOOL bMinus = FALSE;
892 while (iswspace(*str)) str++;
894 if (*str == '+') {
895 str++;
896 } else if (*str == '-') {
897 bMinus = TRUE;
898 str++;
899 } /* if */
901 while (*str >= '0' && *str <= '9') {
902 RunningTotal = RunningTotal * 10 + *str - '0';
903 str++;
904 } /* while */
906 return bMinus ? -RunningTotal : RunningTotal;