From 414772ac2825e9a2677c16c1b2165d78c184699d Mon Sep 17 00:00:00 2001 From: Thomas Mertes Date: Wed, 12 Mar 2003 20:16:07 +0000 Subject: [PATCH] Implement _itoa, _ltoa, _ultoa, _i64toa, _ui64toa, _itow, _ltow, _ultow, _i64tow, _ui64tow, _atoi64, _wtoi, _wtol, _wtoi64. --- dlls/ntdll/ntdll.spec | 13 +- dlls/ntdll/string.c | 234 ++++++++++++++++++++++++++++---- dlls/ntdll/wcstring.c | 304 +++++++++++++++++++++++++++++++++++++----- 3 files changed, 491 insertions(+), 60 deletions(-) diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index e11dab90eaf..39e2c848bbd 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -889,14 +889,18 @@ @ stdcall -ret64 _allmul(long long long long) _allmul @ stdcall -register -i386 _alloca_probe() NTDLL_alloca_probe @ stdcall -ret64 _allrem(long long long long) _allrem +@ cdecl -ret64 _atoi64(str) _atoi64 @ stdcall -ret64 _aulldiv(long long long long) _aulldiv @ stdcall -ret64 _aullrem(long long long long) _aullrem @ stdcall -register -i386 _chkstk() NTDLL_chkstk @ stub _fltused @ cdecl _ftol() NTDLL__ftol +@ cdecl _i64toa(long long ptr long) _i64toa +@ cdecl _i64tow(long long ptr long) _i64tow @ cdecl _itoa(long ptr long) _itoa -@ stub _itow #(long ptr long) _itow +@ cdecl _itow(long ptr long) _itow @ cdecl _ltoa(long ptr long) _ltoa +@ cdecl _ltow(long ptr long) _ltow @ cdecl _memccpy(ptr ptr long long) memccpy @ cdecl _memicmp(str str long) NTDLL__memicmp @ varargs _snprintf(ptr long ptr) snprintf @@ -907,6 +911,8 @@ @ cdecl _strlwr(str) _strlwr @ cdecl _strnicmp(str str long) strncasecmp @ cdecl _strupr(str) _strupr +@ cdecl _ui64toa(long long ptr long) _ui64toa +@ cdecl _ui64tow(long long ptr long) _ui64tow @ cdecl _ultoa(long ptr long) _ultoa @ cdecl _ultow(long ptr long) _ultow @ cdecl _vsnprintf(ptr long ptr ptr) vsnprintf @@ -914,8 +920,9 @@ @ cdecl _wcslwr(wstr) NTDLL__wcslwr @ cdecl _wcsnicmp(wstr wstr long) NTDLL__wcsnicmp @ cdecl _wcsupr(wstr) NTDLL__wcsupr -@ cdecl _wtoi(wstr) NTDLL__wtoi -@ cdecl _wtol(wstr) NTDLL__wtol +@ cdecl _wtoi(wstr) _wtoi +@ cdecl _wtoi64(wstr) _wtoi64 +@ cdecl _wtol(wstr) _wtol @ cdecl abs(long) abs @ cdecl atan(double) atan @ cdecl atoi(str) atoi diff --git a/dlls/ntdll/string.c b/dlls/ntdll/string.c index 6a0b5e27487..e841758ee42 100644 --- a/dlls/ntdll/string.c +++ b/dlls/ntdll/string.c @@ -3,6 +3,7 @@ * * Copyright 2000 Alexandre Julliard * Copyright 2000 Jon Griffiths + * Copyright 2003 Thomas Mertes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -25,6 +26,8 @@ #include #include "windef.h" +#include "winternl.h" + /********************************************************************* * _memicmp (NTDLL.@) @@ -41,6 +44,7 @@ INT __cdecl NTDLL__memicmp( LPCSTR s1, LPCSTR s2, DWORD len ) return ret; } + /********************************************************************* * _strupr (NTDLL.@) */ @@ -51,6 +55,7 @@ LPSTR __cdecl _strupr( LPSTR str ) return ret; } + /********************************************************************* * _strlwr (NTDLL.@) * @@ -65,47 +70,224 @@ LPSTR __cdecl _strlwr( LPSTR str ) /********************************************************************* - * _ultoa (NTDLL.@) + * _ultoa (NTDLL.@) + * + * Converts an unsigned long integer to a string. + * + * Assigns a '\0' terminated string to str and returns str. + * Does not check if radix is in the range of 2 to 36 (as native DLL). + * For str == NULL just crashes (as native DLL). */ -LPSTR __cdecl _ultoa( unsigned long x, LPSTR buf, INT radix ) +char * __cdecl _ultoa( unsigned long value, char *str, int radix ) { - char *p, buffer[8*sizeof(unsigned long) + 1]; /* assume 8-bit chars */ + char buffer[33]; + char *pos; + int digit; - p = buffer + sizeof(buffer); - *--p = 0; - do - { - int rem = x % radix; - *--p = (rem <= 9) ? rem + '0' : rem + 'a' - 10; - x /= radix; - } while (x); - strcpy( buf, p ); - return buf; + pos = &buffer[32]; + *pos = '\0'; + + do { + digit = value % radix; + value = value / radix; + if (digit < 10) { + *--pos = '0' + digit; + } else { + *--pos = 'a' + digit - 10; + } /* if */ + } while (value != 0L); + + memcpy(str, pos, &buffer[32] - pos + 1); + return str; } /********************************************************************* - * _ltoa (NTDLL.@) + * _ltoa (NTDLL.@) + * + * Converts a long integer to a string. + * + * Assigns a '\0' terminated string to str and returns str. If radix + * is 10 and value is negative, the value is converted with sign. + * Does not check if radix is in the range of 2 to 36 (as native DLL). + * For str == NULL just crashes (as native DLL). */ -LPSTR __cdecl _ltoa( long x, LPSTR buf, INT radix ) +char * __cdecl _ltoa( long value, char *str, int radix ) { - LPSTR p = buf; - if (x < 0) - { - *p++ = '-'; - x = -x; - } - _ultoa( x, p, radix ); - return buf; + unsigned long val; + int negative; + char buffer[33]; + char *pos; + int digit; + + if (value < 0 && radix == 10) { + negative = 1; + val = -value; + } else { + negative = 0; + val = value; + } /* if */ + + pos = &buffer[32]; + *pos = '\0'; + + do { + digit = val % radix; + val = val / radix; + if (digit < 10) { + *--pos = '0' + digit; + } else { + *--pos = 'a' + digit - 10; + } /* if */ + } while (val != 0L); + + if (negative) { + *--pos = '-'; + } /* if */ + + memcpy(str, pos, &buffer[32] - pos + 1); + return str; } /********************************************************************* - * _itoa (NTDLL.@) + * _itoa (NTDLL.@) + * + * Converts an integer to a string. + * + * Assigns a '\0' terminated wstring to str and returns str. If radix + * is 10 and value is negative, the value is converted with sign. + * Does not check if radix is in the range of 2 to 36 (as native DLL). + * For str == NULL just crashes (as native DLL). */ -LPSTR __cdecl _itoa( int x, LPSTR buf, INT radix ) +char * __cdecl _itoa( int value, char *str, int radix ) { - return _ltoa( x, buf, radix ); + return _ltoa(value, str, radix); +} + + +/********************************************************************* + * _ui64toa (NTDLL.@) + * + * Converts a large unsigned integer to a string. + * + * Assigns a '\0' terminated string to str and returns str. + * Does not check if radix is in the range of 2 to 36 (as native DLL). + * For str == NULL just crashes (as native DLL). + */ +char * __cdecl _ui64toa( ULONGLONG value, char *str, int radix ) +{ + char buffer[65]; + char *pos; + int digit; + + pos = &buffer[64]; + *pos = '\0'; + + do { + digit = value % radix; + value = value / radix; + if (digit < 10) { + *--pos = '0' + digit; + } else { + *--pos = 'a' + digit - 10; + } /* if */ + } while (value != 0L); + + memcpy(str, pos, &buffer[64] - pos + 1); + return str; +} + + +/********************************************************************* + * _i64toa (NTDLL.@) + * + * Converts a large integer to a string. + * + * Assigns a '\0' terminated string to str and returns str. If radix + * is 10 and value is negative, the value is converted with sign. + * Does not check if radix is in the range of 2 to 36 (as native DLL). + * For str == NULL just crashes (as native DLL). + * + * Difference: + * - The native DLL converts negative values (for base 10) wrong: + * -1 is converted to -18446744073709551615 + * -2 is converted to -18446744073709551614 + * -9223372036854775807 is converted to -9223372036854775809 + * -9223372036854775808 is converted to -9223372036854775808 + * The native msvcrt _i64toa function and our ntdll function do + * not have this bug. + */ +char * __cdecl _i64toa( LONGLONG value, char *str, int radix ) +{ + ULONGLONG val; + int negative; + char buffer[65]; + char *pos; + int digit; + + if (value < 0 && radix == 10) { + negative = 1; + val = -value; + } else { + negative = 0; + val = value; + } /* if */ + + pos = &buffer[64]; + *pos = '\0'; + + do { + digit = val % radix; + val = val / radix; + if (digit < 10) { + *--pos = '0' + digit; + } else { + *--pos = 'a' + digit - 10; + } /* if */ + } while (val != 0L); + + if (negative) { + *--pos = '-'; + } /* if */ + + memcpy(str, pos, &buffer[64] - pos + 1); + return str; +} + + +/********************************************************************* + * _atoi64 (NTDLL.@) + * + * Converts a string to a large integer. + * + * On success it returns the integer value otherwise it returns 0. + * Accepts: {whitespace} [+|-] {digits} + * No check of overflow: Just assigns lower 64 bits (as native DLL). + * Does not check for str != NULL (as native DLL). + */ +LONGLONG __cdecl _atoi64( char *str ) +{ + ULONGLONG RunningTotal = 0; + char bMinus = 0; + + while (*str == ' ' || (*str >= '\011' && *str <= '\015')) { + str++; + } /* while */ + + if (*str == '+') { + str++; + } else if (*str == '-') { + bMinus = 1; + str++; + } /* if */ + + while (*str >= '0' && *str <= '9') { + RunningTotal = RunningTotal * 10 + *str - '0'; + str++; + } /* while */ + + return bMinus ? -RunningTotal : RunningTotal; } diff --git a/dlls/ntdll/wcstring.c b/dlls/ntdll/wcstring.c index 0ebe50950d5..787f826b59f 100644 --- a/dlls/ntdll/wcstring.c +++ b/dlls/ntdll/wcstring.c @@ -3,6 +3,7 @@ * * Copyright 2000 Alexandre Julliard * Copyright 2000 Jon Griffiths + * Copyright 2003 Thomas Mertes * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -338,54 +339,295 @@ INT __cdecl NTDLL_iswalpha( WCHAR wc ) /********************************************************************* - * _ultow (NTDLL.@) - * Like _ultoa, but for wide character strings. + * _ultow (NTDLL.@) + * + * Converts an unsigned long integer to an unicode string. + * + * Assigns a '\0' terminated string to str and returns str. + * Does not check if radix is in the range of 2 to 36 (as native DLL). + * For str == NULL just returns NULL (as native DLL). */ -LPWSTR __cdecl _ultow(ULONG value, LPWSTR string, INT radix) +LPWSTR __cdecl _ultow( unsigned long value, LPWSTR str, INT radix ) { - WCHAR tmp[33]; - LPWSTR tp = tmp; - LPWSTR sp; - LONG i; - ULONG v = value; + WCHAR buffer[33]; + PWCHAR pos; + WCHAR digit; - if (radix > 36 || radix <= 1) - return 0; + pos = &buffer[32]; + *pos = '\0'; - while (v || tp == tmp) - { - i = v % radix; - v = v / radix; - if (i < 10) - *tp++ = i + '0'; - else - *tp++ = i + 'a' - 10; - } + do { + digit = value % radix; + value = value / radix; + if (digit < 10) { + *--pos = '0' + digit; + } else { + *--pos = 'a' + digit - 10; + } /* if */ + } while (value != 0L); - sp = string; - while (tp > tmp) - *sp++ = *--tp; - *sp = 0; - return string; + if (str != NULL) { + memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR)); + } /* if */ + return str; } + /********************************************************************* - * _wtol (NTDLL.@) - * Like atol, but for wide character strings. + * _ltow (NTDLL.@) + * + * Converts a long integer to an unicode string. + * + * Assigns a '\0' terminated string to str and returns str. If radix + * is 10 and value is negative, the value is converted with sign. + * Does not check if radix is in the range of 2 to 36 (as native DLL). + * For str == NULL just returns NULL (as native DLL). */ -LONG __cdecl NTDLL__wtol(LPWSTR string) +LPWSTR __cdecl _ltow( long value, LPWSTR str, INT radix ) { - return strtolW( string, NULL, 10 ); + unsigned long val; + int negative; + WCHAR buffer[33]; + PWCHAR pos; + WCHAR digit; + + if (value < 0 && radix == 10) { + negative = 1; + val = -value; + } else { + negative = 0; + val = value; + } /* if */ + + pos = &buffer[32]; + *pos = '\0'; + + do { + digit = val % radix; + val = val / radix; + if (digit < 10) { + *--pos = '0' + digit; + } else { + *--pos = 'a' + digit - 10; + } /* if */ + } while (val != 0L); + + if (negative) { + *--pos = '-'; + } /* if */ + + if (str != NULL) { + memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR)); + } /* if */ + return str; } + /********************************************************************* - * _wtoi (NTDLL.@) + * _itow (NTDLL.@) + * + * Converts an integer to an unicode string. + * + * Assigns a '\0' terminated wstring to str and returns str. If radix + * is 10 and value is negative, the value is converted with sign. + * Does not check if radix is in the range of 2 to 36 (as native DLL). + * For str == NULL just returns NULL (as native DLL). + * + * Difference: + * - The native DLL crashes when the string is longer than 19 chars. + * This function does not have this bug. */ -INT __cdecl NTDLL__wtoi(LPWSTR string) +LPWSTR __cdecl _itow( int value, LPWSTR str, INT radix ) { - return NTDLL__wtol(string); + return _ltow(value, str, radix); } + +/********************************************************************* + * _ui64tow (NTDLL.@) + * + * Converts a large unsigned integer to an unicode string. + * + * Assigns a '\0' terminated wstring to str and returns str. + * Does not check if radix is in the range of 2 to 36 (as native DLL). + * For str == NULL just returns NULL (as native DLL). + * + * Difference: + * - This function does not exist in the native DLL (but in msvcrt). + * But since the maintenance of all these functions is better done + * in one place we implement it here. + */ +LPWSTR __cdecl _ui64tow( ULONGLONG value, LPWSTR str, INT radix ) +{ + WCHAR buffer[65]; + PWCHAR pos; + WCHAR digit; + + pos = &buffer[64]; + *pos = '\0'; + + do { + digit = value % radix; + value = value / radix; + if (digit < 10) { + *--pos = '0' + digit; + } else { + *--pos = 'a' + digit - 10; + } /* if */ + } while (value != 0L); + + if (str != NULL) { + memcpy(str, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR)); + } /* if */ + return str; +} + + +/********************************************************************* + * _i64tow (NTDLL.@) + * + * Converts a large integer to an unicode string. + * + * Assigns a '\0' terminated wstring to str and returns str. If radix + * is 10 and value is negative, the value is converted with sign. + * Does not check if radix is in the range of 2 to 36 (as native DLL). + * For str == NULL just returns NULL (as native DLL). + * + * Difference: + * - The native DLL converts negative values (for base 10) wrong: + * -1 is converted to -18446744073709551615 + * -2 is converted to -18446744073709551614 + * -9223372036854775807 is converted to -9223372036854775809 + * -9223372036854775808 is converted to -9223372036854775808 + * The native msvcrt _i64tow function and our ntdll function do + * not have this bug. + */ +LPWSTR __cdecl _i64tow( LONGLONG value, LPWSTR str, INT radix ) +{ + ULONGLONG val; + int negative; + WCHAR buffer[65]; + PWCHAR pos; + WCHAR digit; + + if (value < 0 && radix == 10) { + negative = 1; + val = -value; + } else { + negative = 0; + val = value; + } /* if */ + + pos = &buffer[64]; + *pos = '\0'; + + do { + digit = val % radix; + val = val / radix; + if (digit < 10) { + *--pos = '0' + digit; + } else { + *--pos = 'a' + digit - 10; + } /* if */ + } while (val != 0L); + + if (negative) { + *--pos = '-'; + } /* if */ + + if (str != NULL) { + memcpy(str, pos, (&buffer[64] - pos + 1) * sizeof(WCHAR)); + } /* if */ + return str; +} + + +/********************************************************************* + * _wtol (NTDLL.@) + * + * Converts an unicode string to a long integer. + * + * On success it returns the integer value otherwise it returns 0. + * Accepts: {whitespace} [+|-] {digits} + * No check of overflow: Just assigns lower 32 bits (as native DLL). + * Does not check for str != NULL (as native DLL). + */ +LONG __cdecl _wtol( LPWSTR str ) +{ + ULONG RunningTotal = 0; + char bMinus = 0; + + while (isspaceW(*str)) { + str++; + } /* while */ + + if (*str == '+') { + str++; + } else if (*str == '-') { + bMinus = 1; + str++; + } /* if */ + + while (*str >= '0' && *str <= '9') { + RunningTotal = RunningTotal * 10 + *str - '0'; + str++; + } /* while */ + + return bMinus ? -RunningTotal : RunningTotal; +} + + +/********************************************************************* + * _wtoi (NTDLL.@) + * + * Converts an unicode string to an integer. + * + * On success it returns the integer value otherwise it returns 0. + * Accepts: {whitespace} [+|-] {digits} + * No check of overflow: Just assigns lower 32 bits (as native DLL). + * Does not check for str != NULL (as native DLL). + */ +int __cdecl _wtoi( LPWSTR string ) +{ + return _wtol(string); +} + + +/********************************************************************* + * _wtoi64 (NTDLL.@) + * + * Converts an unicode string to a large integer. + * + * On success it returns the integer value otherwise it returns 0. + * Accepts: {whitespace} [+|-] {digits} + * No check of overflow: Just assigns lower 64 bits (as native DLL). + * Does not check for str != NULL (as native DLL). + */ +LONGLONG __cdecl _wtoi64( LPWSTR str ) +{ + ULONGLONG RunningTotal = 0; + char bMinus = 0; + + while (isspaceW(*str)) { + str++; + } /* while */ + + if (*str == '+') { + str++; + } else if (*str == '-') { + bMinus = 1; + str++; + } /* if */ + + while (*str >= '0' && *str <= '9') { + RunningTotal = RunningTotal * 10 + *str - '0'; + str++; + } /* while */ + + return bMinus ? -RunningTotal : RunningTotal; +} + + /* INTERNAL: Wide char snprintf * If you fix a bug in this function, fix it in msvcrt/wcs.c also! */