Hello Here are implementations of some ntdll functions. Well, not all this functions are new, but I implemented them in a uniform way. I have tested the functions a lot on w2k (see part2: tests). Changelog: * dlls/ntdll/ntdll.spec, dlls/ntdll/string.c, dlls/ntdll/wcstring.c: Thomas Mertes <thomas.mertes@t-mobile.at> - Implement _itoa, _ltoa, _ultoa, _i64toa, _ui64toa, _itow, _ltow, _ultow, _i64tow, _ui64tow, _atoi64, _wtoi, _wtol, _wtoi64 Greetings Thomas Mertes -- +++ GMX - Mail, Messaging & more http://www.gmx.net +++ Bitte lächeln! Fotogalerie online mit GMX ohne eigene Homepage!
diff -urN old_wine-20030219/dlls/ntdll/ntdll.spec new_wine-20030219/dlls/ntdll/ntdll.spec --- old_wine-20030219/dlls/ntdll/ntdll.spec Wed Feb 19 04:39:46 2003 +++ new_wine-20030219/dlls/ntdll/ntdll.spec Thu Mar 6 09:32:46 2003 @@ -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 -urN old_wine-20030219/dlls/ntdll/string.c new_wine-20030219/dlls/ntdll/string.c --- old_wine-20030219/dlls/ntdll/string.c Wed Oct 9 22:27:33 2002 +++ new_wine-20030219/dlls/ntdll/string.c Thu Mar 6 09:32:33 2003 @@ -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 <string.h> #include "windef.h" +#include "winternl.h" + /********************************************************************* * _memicmp (NTDLL.@) @@ -41,6 +44,7 @@ return ret; } + /********************************************************************* * _strupr (NTDLL.@) */ @@ -51,6 +55,7 @@ return ret; } + /********************************************************************* * _strlwr (NTDLL.@) * @@ -65,47 +70,269 @@ /********************************************************************* - * _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). + * + * Difference: + * - Does not crash on str == NULL (as native DLL). + * Instead requests the needed memory with RtlAllocateHeap. + * When RtlAllocateHeap fails: return NULL. */ -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; + + 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); + + if (str != NULL || + (str = RtlAllocateHeap(GetProcessHeap(), 0, &buffer[32] - pos + 1))) { + memcpy(str, pos, &buffer[32] - pos + 1); + } /* if */ + return str; +} - 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; + +/********************************************************************* + * _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). + * + * Difference: + * - Does not crash on str == NULL (as native DLL). + * Instead requests the needed memory with RtlAllocateHeap. + * When RtlAllocateHeap fails: return NULL. + * - For negative radix it converts negative values with sign for + * every radix (not just for radix 10 as with positive radix). + */ +char * __cdecl _ltoa( long value, char *str, int radix ) +{ + unsigned long val; + int negative; + char buffer[34]; + char *pos; + int digit; + + if (value < 0 && (radix == 10 || radix < 0)) { + negative = 1; + val = -value; + } else { + negative = 0; + val = value; + } /* if */ + + if (radix < 0) { + radix = -radix; + } /* if */ + + pos = &buffer[33]; + *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 || + (str = RtlAllocateHeap(GetProcessHeap(), 0, &buffer[33] - pos + 1))) { + memcpy(str, pos, &buffer[33] - pos + 1); + } /* if */ + return str; } /********************************************************************* - * _ltoa (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). + * + * Difference: + * - Does not return NULL on str == NULL (as native DLL). + * Instead requests the needed memory with RtlAllocateHeap. + * When RtlAllocateHeap fails: return NULL. + * - For negative radix it converts negative values with sign for + * every radix (not just for radix 10 as with positive radix). */ -LPSTR __cdecl _ltoa( long x, LPSTR buf, INT radix ) +char * __cdecl _itoa( int value, char *str, int radix ) { - LPSTR p = buf; - if (x < 0) - { - *p++ = '-'; - x = -x; - } - _ultoa( x, p, radix ); - return buf; + 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). + * + * Difference: + * - Does not crash on str == NULL (as native DLL). + * Instead requests the needed memory with RtlAllocateHeap. + * When RtlAllocateHeap fails: return NULL. + */ +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); + + if (str != NULL || + (str = RtlAllocateHeap(GetProcessHeap(), 0, &buffer[64] - pos + 1))) { + memcpy(str, pos, &buffer[64] - pos + 1); + } /* if */ + return str; } /********************************************************************* - * _itoa (NTDLL.@) + * _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). + * + * 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. + * - Does not crash on str == NULL (as native DLL). + * Instead requests the needed memory with RtlAllocateHeap. + * When RtlAllocateHeap fails: return NULL. + * - For negative radix it converts negative values with sign for + * every radix (not just for radix 10 as with positive radix). */ -LPSTR __cdecl _itoa( int x, LPSTR buf, INT radix ) +char * __cdecl _i64toa( LONGLONG value, char *str, int radix ) { - return _ltoa( x, buf, radix ); + ULONGLONG val; + int negative; + char buffer[66]; + char *pos; + int digit; + + if (value < 0 && (radix == 10 || radix < 0)) { + negative = 1; + val = -value; + } else { + negative = 0; + val = value; + } /* if */ + + if (radix < 0) { + radix = -radix; + } /* if */ + + pos = &buffer[65]; + *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 || + (str = RtlAllocateHeap(GetProcessHeap(), 0, &buffer[65] - pos + 1))) { + memcpy(str, pos, &buffer[65] - pos + 1); + } /* if */ + 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 -urN old_wine-20030219/dlls/ntdll/wcstring.c new_wine-20030219/dlls/ntdll/wcstring.c --- old_wine-20030219/dlls/ntdll/wcstring.c Fri Sep 13 00:07:03 2002 +++ new_wine-20030219/dlls/ntdll/wcstring.c Thu Mar 6 09:32:40 2003 @@ -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,53 +339,327 @@ /********************************************************************* - * _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). + * + * Difference: + * - Does not return NULL on str == NULL (as native DLL). + * Instead requests the needed memory with RtlAllocateHeap. + * When RtlAllocateHeap fails: return NULL. */ -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); + + if (str != NULL || + (str = RtlAllocateHeap(GetProcessHeap(), 0, (&buffer[32] - pos + 1) * sizeof(WCHAR)))) { + memcpy(str, pos, (&buffer[32] - pos + 1) * sizeof(WCHAR)); + } /* if */ + return str; +} - sp = string; - while (tp > tmp) - *sp++ = *--tp; - *sp = 0; - return string; + +/********************************************************************* + * _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). + * + * Difference: + * - Does not return NULL on str == NULL (as native DLL). + * Instead requests the needed memory with RtlAllocateHeap. + * When RtlAllocateHeap fails: return NULL. + * - For negative radix it converts negative values with sign for + * every radix (not just for radix 10 as with positive radix). + */ +LPWSTR __cdecl _ltow( long value, LPWSTR str, INT radix ) +{ + unsigned long val; + int negative; + WCHAR buffer[34]; + PWCHAR pos; + WCHAR digit; + + if (value < 0 && (radix == 10 || radix < 0)) { + negative = 1; + val = -value; + } else { + negative = 0; + val = value; + } /* if */ + + if (radix < 0) { + radix = -radix; + } /* if */ + + pos = &buffer[33]; + *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 || + (str = RtlAllocateHeap(GetProcessHeap(), 0, (&buffer[33] - pos + 1) * sizeof(WCHAR)))) { + memcpy(str, pos, (&buffer[33] - pos + 1) * sizeof(WCHAR)); + } /* if */ + return str; } + /********************************************************************* - * _wtol (NTDLL.@) - * Like atol, but for wide character strings. + * _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). + * + * Difference: + * - The native DLL crashes when the string is longer than 19 chars. + * This function does not have this bug. + * - Does not return NULL on str == NULL (as native DLL). + * Instead requests the needed memory with RtlAllocateHeap. + * When RtlAllocateHeap fails: return NULL. + * - For negative radix it converts negative values with sign for + * every radix (not just for radix 10 as with positive radix). */ -LONG __cdecl NTDLL__wtol(LPWSTR string) +LPWSTR __cdecl _itow( int value, LPWSTR str, INT radix ) { - return strtolW( string, NULL, 10 ); + return _ltow(value, str, radix); } + /********************************************************************* - * _wtoi (NTDLL.@) + * _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). + * + * 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. + * - Does not return NULL on str == NULL (as native DLL). + * Instead requests the needed memory with RtlAllocateHeap. + * When RtlAllocateHeap fails: return NULL. + */ +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 || + (str = RtlAllocateHeap(GetProcessHeap(), 0, (&buffer[64] - pos + 1) * sizeof(WCHAR)))) { + 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). + * + * 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. + * - Does not return NULL on str == NULL (as native DLL). + * Instead requests the needed memory with RtlAllocateHeap. + * When RtlAllocateHeap fails: return NULL. + * - For negative radix it converts negative values with sign for + * every radix (not just for radix 10 as with positive radix). + */ +LPWSTR __cdecl _i64tow( LONGLONG value, LPWSTR str, INT radix ) +{ + ULONGLONG val; + int negative; + WCHAR buffer[66]; + PWCHAR pos; + WCHAR digit; + + if (value < 0 && (radix == 10 || radix < 0)) { + negative = 1; + val = -value; + } else { + negative = 0; + val = value; + } /* if */ + + if (radix < 0) { + radix = -radix; + } /* if */ + + pos = &buffer[65]; + *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 || + (str = RtlAllocateHeap(GetProcessHeap(), 0, (&buffer[65] - pos + 1) * sizeof(WCHAR)))) { + memcpy(str, pos, (&buffer[65] - 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 NTDLL__wtoi(LPWSTR string) +int __cdecl _wtoi( LPWSTR string ) { - return NTDLL__wtol(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!