From ccc118bbe5c47fbbef46af31aa8064c4df69ed6a Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Sun, 25 May 2014 14:30:54 +0000 Subject: [PATCH] [CRT] * Partial update of scanf routines. Focus was on the case of reading a float. * Don't inline float processing, introduce _internal_handle_float() and co to take care of this. Brought to you by Timo. * Msvcrt scanf tests are now green. CORE-7005 #resolve #comment Should be fixed in r63443. Thanks Dmitry ;) CORE-8080 svn path=/trunk/; revision=63443 --- reactos/lib/sdk/crt/crt.cmake | 1 + reactos/lib/sdk/crt/libcntpr.cmake | 1 + reactos/lib/sdk/crt/string/scanf.c | 57 ++++---- reactos/lib/sdk/crt/string/scanf.h | 187 ++++++++++++++++++--------- reactos/lib/sdk/crt/string/winesup.c | 102 +++++++++++++++ reactos/lib/sdk/crt/string/winesup.h | 45 +++++++ 6 files changed, 307 insertions(+), 86 deletions(-) create mode 100644 reactos/lib/sdk/crt/string/winesup.c create mode 100644 reactos/lib/sdk/crt/string/winesup.h diff --git a/reactos/lib/sdk/crt/crt.cmake b/reactos/lib/sdk/crt/crt.cmake index eae70e5d520..60aeb56b642 100644 --- a/reactos/lib/sdk/crt/crt.cmake +++ b/reactos/lib/sdk/crt/crt.cmake @@ -306,6 +306,7 @@ list(APPEND CRT_SOURCE string/wtoi.c string/wtoi64.c string/wtol.c + string/winesup.c sys_stat/systime.c time/asctime.c time/clock.c diff --git a/reactos/lib/sdk/crt/libcntpr.cmake b/reactos/lib/sdk/crt/libcntpr.cmake index 487c92e3a60..6477dfeea38 100644 --- a/reactos/lib/sdk/crt/libcntpr.cmake +++ b/reactos/lib/sdk/crt/libcntpr.cmake @@ -59,6 +59,7 @@ list(APPEND LIBCNTPR_SOURCE string/wtoi64.c string/wtoi.c string/wtol.c + string/winesup.c wstring/wcsicmp.c wstring/wcslwr.c wstring/wcsnicmp.c diff --git a/reactos/lib/sdk/crt/string/scanf.c b/reactos/lib/sdk/crt/string/scanf.c index 57c56d0c263..9ab876fcdcb 100644 --- a/reactos/lib/sdk/crt/string/scanf.c +++ b/reactos/lib/sdk/crt/string/scanf.c @@ -23,13 +23,15 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ -#include -#include +#include +#include -// HACK for LIBCNT -#ifndef debugstr_a -#define debugstr_a -#endif +#include +#include + +#include "winesup.h" + +WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); //extern FILE _iob[]; @@ -56,49 +58,54 @@ static int wchar2digit(wchar_t c, int base) { } #ifndef _LIBCNT_ -/* vfscanf */ +/* vfscanf_l */ #undef WIDE_SCANF #undef CONSOLE #undef STRING +#undef SECURE #include "scanf.h" -/* vfwscanf */ +/* vfwscanf_l */ #define WIDE_SCANF 1 #undef CONSOLE #undef STRING +#undef SECURE #include "scanf.h" -#endif +#endif /* !_LIBCNT_ */ -/* vsscanf */ +/* vsscanf_l */ #undef WIDE_SCANF #undef CONSOLE #define STRING 1 +#undef SECURE #include "scanf.h" -/* vswscanf */ +/* vswscanf_l */ #define WIDE_SCANF 1 #undef CONSOLE #define STRING 1 +#undef SECURE #include "scanf.h" #ifndef _LIBCNT_ -/* vcscanf */ +/* vcscanf_l */ #undef WIDE_SCANF #define CONSOLE 1 #undef STRING +#undef SECURE #include "scanf.h" /********************************************************************* * fscanf (MSVCRT.@) */ -int fscanf(FILE *file, const char *format, ...) +int CDECL fscanf(FILE *file, const char *format, ...) { va_list valist; int res; va_start(valist, format); - res = vfscanf(file, format, valist); + res = vfscanf_l(file, format, NULL, valist); va_end(valist); return res; } @@ -106,13 +113,13 @@ int fscanf(FILE *file, const char *format, ...) /********************************************************************* * scanf (MSVCRT.@) */ -int scanf(const char *format, ...) +int CDECL scanf(const char *format, ...) { va_list valist; int res; va_start(valist, format); - res = vfscanf(stdin, format, valist); + res = vfscanf_l(stdin, format, NULL, valist); va_end(valist); return res; } @@ -120,13 +127,13 @@ int scanf(const char *format, ...) /********************************************************************* * fwscanf (MSVCRT.@) */ -int fwscanf(FILE *file, const wchar_t *format, ...) +int CDECL fwscanf(FILE *file, const wchar_t *format, ...) { va_list valist; int res; va_start(valist, format); - res = vfwscanf(file, format, valist); + res = vfwscanf_l(file, format, NULL, valist); va_end(valist); return res; } @@ -135,29 +142,29 @@ int fwscanf(FILE *file, const wchar_t *format, ...) /********************************************************************* * wscanf (MSVCRT.@) */ -int wscanf(const wchar_t *format, ...) +int CDECL wscanf(const wchar_t *format, ...) { va_list valist; int res; va_start(valist, format); - res = vfwscanf(stdin, format, valist); + res = vfwscanf_l(stdin, format, NULL, valist); va_end(valist); return res; } -#endif +#endif /* !_LIBCNT_ */ /********************************************************************* * sscanf (MSVCRT.@) */ -int sscanf(const char *str, const char *format, ...) +int CDECL sscanf(const char *str, const char *format, ...) { va_list valist; int res; va_start(valist, format); - res = vsscanf(str, format, valist); + res = vsscanf_l(str, format, NULL, valist); va_end(valist); return res; } @@ -172,7 +179,7 @@ int CDECL swscanf(const wchar_t *str, const wchar_t *format, ...) int res; va_start(valist, format); - res = vswscanf(str, format, valist); + res = vswscanf_l(str, format, NULL, valist); va_end(valist); return res; } @@ -187,7 +194,7 @@ int CDECL _cscanf(const char *format, ...) int res; va_start(valist, format); - res = vcscanf(format, valist); + res = vcscanf_l(format, NULL, valist); va_end(valist); return res; } diff --git a/reactos/lib/sdk/crt/string/scanf.h b/reactos/lib/sdk/crt/string/scanf.h index 4aada82b6b9..cb37ed9fee1 100644 --- a/reactos/lib/sdk/crt/string/scanf.h +++ b/reactos/lib/sdk/crt/string/scanf.h @@ -48,7 +48,11 @@ #ifdef CONSOLE #define _GETC_(file) (consumed++, _getch()) #define _UNGETC_(nch, file) do { _ungetch(nch); consumed--; } while(0) -#define _FUNCTION_ int vcscanf(const char *format, va_list ap) +#ifdef SECURE +#define _FUNCTION_ static int vcscanf_s_l(const char *format, _locale_t locale, __ms_va_list ap) +#else /* SECURE */ +#define _FUNCTION_ static int vcscanf_l(const char *format, _locale_t locale, __ms_va_list ap) +#endif /* SECURE */ #else #ifdef STRING #undef _EOF_ @@ -56,24 +60,41 @@ #define _GETC_(file) (consumed++, *file++) #define _UNGETC_(nch, file) do { file--; consumed--; } while(0) #ifdef WIDE_SCANF -#define _FUNCTION_ int vswscanf(const wchar_t *file, const wchar_t *format, va_list ap) +#ifdef SECURE +#define _FUNCTION_ static int vswscanf_s_l(const wchar_t *file, const wchar_t *format, _locale_t locale, __ms_va_list ap) +#else /* SECURE */ +#define _FUNCTION_ static int vswscanf_l(const wchar_t *file, const wchar_t *format, _locale_t locale, __ms_va_list ap) +#endif /* SECURE */ #else /* WIDE_SCANF */ -#define _FUNCTION_ int vsscanf(const char *file, const char *format, va_list ap) +#ifdef SECURE +#define _FUNCTION_ static int vsscanf_s_l(const char *file, const char *format, _locale_t locale, __ms_va_list ap) +#else /* SECURE */ +#define _FUNCTION_ static int vsscanf_l(const char *file, const char *format, _locale_t locale, __ms_va_list ap) +#endif /* SECURE */ #endif /* WIDE_SCANF */ #else /* STRING */ #ifdef WIDE_SCANF #define _GETC_(file) (consumed++, fgetwc(file)) #define _UNGETC_(nch, file) do { ungetwc(nch, file); consumed--; } while(0) -#define _FUNCTION_ int vfwscanf(FILE* file, const wchar_t *format, va_list ap) +#ifdef SECURE +#define _FUNCTION_ static int vfwscanf_s_l(FILE* file, const wchar_t *format, _locale_t locale, __ms_va_list ap) +#else /* SECURE */ +#define _FUNCTION_ static int vfwscanf_l(FILE* file, const wchar_t *format, _locale_t locale, __ms_va_list ap) +#endif /* SECURE */ #else /* WIDE_SCANF */ #define _GETC_(file) (consumed++, fgetc(file)) #define _UNGETC_(nch, file) do { ungetc(nch, file); consumed--; } while(0) -#define _FUNCTION_ int vfscanf(FILE* file, const char *format, va_list ap) +#ifdef SECURE +#define _FUNCTION_ static int vfscanf_s_l(FILE* file, const char *format, _locale_t locale, __ms_va_list ap) +#else /* SECURE */ +#define _FUNCTION_ static int vfscanf_l(FILE* file, const char *format, _locale_t locale, __ms_va_list ap) +#endif /* SECURE */ #endif /* WIDE_SCANF */ #endif /* STRING */ #endif /* CONSOLE */ _FUNCTION_ { + pthreadlocinfo locinfo; int rd = 0, consumed = 0; int nch; if (!*format) return 0; @@ -94,6 +115,11 @@ _FUNCTION_ { return _EOF_RET; } + if(!locale) + locinfo = get_locinfo(); + else + locinfo = locale->locinfo; + while (*format) { /* a whitespace character in the format string causes scanf to read, * but not store, all consecutive white-space characters in the input @@ -246,8 +272,12 @@ _FUNCTION_ { case 'f': case 'g': case 'G': { /* read a float */ - long double cur = 0; - int negative = 0; + //long double cur = 1, expcnt = 10; + ULONGLONG d, hlp; + int exp = 0, negative = 0; + //unsigned fpcontrol; + //BOOL negexp; + /* skip initial whitespace */ while ((nch!=_EOF_) && _ISSPACE_(nch)) nch = _GETC_(file); @@ -259,69 +289,112 @@ _FUNCTION_ { if (width==0) break; nch = _GETC_(file); } - /* get first digit. */ - if ('.' != nch) { - if (!_ISDIGIT_(nch)) break; - cur = (nch - '0'); - nch = _GETC_(file); - if (width>0) width--; - /* read until no more digits */ - while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { - cur = cur*10 + (nch - '0'); - nch = _GETC_(file); - if (width>0) width--; - } - } else { - cur = 0; /* MaxPayneDemo Fix: .8 -> 0.8 */ - } - /* handle decimals */ - if (width!=0 && nch == '.') { - long double dec = 1; + + /* get first digit. */ + if (*locinfo->lconv->decimal_point != nch) { + if (!_ISDIGIT_(nch)) break; + d = nch - '0'; nch = _GETC_(file); if (width>0) width--; + /* read until no more digits */ + while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { + hlp = d*10 + nch - '0'; + nch = _GETC_(file); + if (width>0) width--; + if(d > (ULONGLONG)-1/10 || hlp0) width--; + } + } else { + d = 0; /* Fix: .8 -> 0.8 */ + } + + /* handle decimals */ + if (width!=0 && nch == *locinfo->lconv->decimal_point) { + nch = _GETC_(file); + if (width>0) width--; + + while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { + hlp = d*10 + nch - '0'; + nch = _GETC_(file); + if (width>0) width--; + if(d > (ULONGLONG)-1/10 || hlp0) width--; } } - /* handle exponent */ - if (width!=0 && (nch == 'e' || nch == 'E')) { - int exponent = 0, negexp = 0; - double expcnt, shift; + + /* handle exponent */ + if (width!=0 && (nch == 'e' || nch == 'E')) { + int sign = 1, e = 0; + nch = _GETC_(file); if (width>0) width--; - /* possible sign on the exponent */ - if (width!=0 && (nch=='+' || nch=='-')) { - negexp = (nch=='-'); - nch = _GETC_(file); - if (width>0) width--; - } - /* exponent digits */ - while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { - exponent *= 10; - exponent += (nch - '0'); + if (width!=0 && (nch=='+' || nch=='-')) { + if(nch == '-') + sign = -1; nch = _GETC_(file); if (width>0) width--; } - /* update 'cur' with this exponent. */ - expcnt = 10; - shift = 1.0; - while (exponent!=0) { - if (exponent&1) - shift *= expcnt; - exponent/=2; - expcnt=expcnt*expcnt; - } - cur = (negexp ? cur / shift : cur * shift); - } + + /* exponent digits */ + while (width!=0 && (nch!=_EOF_) && _ISDIGIT_(nch)) { + if(e > INT_MAX/10 || (e = e*10 + nch - '0')<0) + e = INT_MAX; + nch = _GETC_(file); + if (width>0) width--; + } + e *= sign; + + if(exp<0 && e<0 && e+exp>0) exp = INT_MIN; + else if(exp>0 && e>0 && e+exp<0) exp = INT_MAX; + else exp += e; + } + +#ifdef __REACTOS__ + /* ReactOS: don't inline float processing (kernel/freeldr don't like that! */ + _internal_handle_float(negative, exp, suppress, d, l_prefix || L_prefix, &ap); + st = 1; +#else + fpcontrol = _control87(0, 0); + _control87(MSVCRT__EM_DENORMAL|MSVCRT__EM_INVALID|MSVCRT__EM_ZERODIVIDE + |MSVCRT__EM_OVERFLOW|MSVCRT__EM_UNDERFLOW|MSVCRT__EM_INEXACT, 0xffffffff); + + negexp = (exp < 0); + if(negexp) + exp = -exp; + /* update 'cur' with this exponent. */ + while(exp) { + if(exp & 1) + cur *= expcnt; + exp /= 2; + expcnt = expcnt*expcnt; + } + cur = (negexp ? d/cur : d*cur); + + _control87(fpcontrol, 0xffffffff); + st = 1; if (!suppress) { - if (L_prefix) _SET_NUMBER_(long double); + if (L_prefix) _SET_NUMBER_(double); else if (l_prefix) _SET_NUMBER_(double); else _SET_NUMBER_(float); } +#endif /* __REACTOS__ */ } break; /* According to msdn, @@ -448,11 +521,7 @@ _FUNCTION_ { int invert = 0; /* Set if we are NOT to find the chars */ /* Init our bitmap */ -#ifdef _LIBCNT_ - Mask = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8); -#else Mask = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _BITMAPSIZE_/8); -#endif RtlInitializeBitMap(&bitMask, Mask, _BITMAPSIZE_); /* Read the format */ @@ -497,11 +566,7 @@ _FUNCTION_ { } /* terminate */ if (!suppress) *sptr = 0; -#ifdef _LIBCNT_ - RtlFreeHeap(RtlGetProcessHeap(), 0, Mask); -#else HeapFree(GetProcessHeap(), 0, Mask); -#endif } break; default: diff --git a/reactos/lib/sdk/crt/string/winesup.c b/reactos/lib/sdk/crt/string/winesup.c new file mode 100644 index 00000000000..860fe85cdb4 --- /dev/null +++ b/reactos/lib/sdk/crt/string/winesup.c @@ -0,0 +1,102 @@ + +#include "precomp.h" +#include "winesup.h" + +#ifdef _LIBCNT_ + +static struct lconv _LIBCNT_lconv = +{ + ".", // char* decimal_point; + ",", // char* thousands_sep; + " ", // char* grouping; + "$", // char* int_curr_symbol; + "$", // char* currency_symbol; + ".", // char* mon_decimal_point; + "?", // char* mon_thousands_sep; + "/", // char* mon_grouping; + "+", // char* positive_sign; + "-", // char* negative_sign; + 4, // char int_frac_digits; + 4, // char frac_digits; + 4, // char p_cs_precedes; + 1, // char p_sep_by_space; + 0, // char n_cs_precedes; + 1, // char n_sep_by_space; + 1, // char p_sign_posn; + 1, // char n_sign_posn; +}; + +threadlocinfo _LIBCNT_locinfo = +{ + 2, // LONG refcount; + 0, // CP_ACP, // unsigned int lc_codepage; + 0, // unsigned int lc_collate_cp; + {0}, // unsigned long lc_handle[6]; + {{0}}, // LC_ID lc_id[6]; + + // struct { + // char *locale; + // wchar_t *wlocale; + // int *refcount; + // int *wrefcount; + // } lc_category[6]; + {{0}}, + + 0, // int lc_clike; + 2, // int mb_cur_max; + 0, // int *lconv_intl_refcount; + 0, // int *lconv_num_refcount; + 0, // int *lconv_mon_refcount; + &_LIBCNT_lconv, // struct MSVCRT_lconv *lconv; + 0, // int *ctype1_refcount; + 0, // unsigned short *ctype1; + 0, // const unsigned short *pctype; + 0, // unsigned char *pclmap; + 0, // unsigned char *pcumap; + 0, // struct __lc_time_data *lc_time_curr; +}; + +#define get_locinfo() (&_LIBCNT_locinfo) + +#endif + +#define _SET_NUMBER_(type) *va_arg((*ap), type*) = negative ? -cur : cur + +void +__declspec(noinline) +_internal_handle_float( + int negative, + int exp, + int suppress, + ULONGLONG d, + int l_or_L_prefix, + va_list *ap) +{ + long double cur = 1, expcnt = 10; + unsigned fpcontrol; + BOOL negexp; + + fpcontrol = _control87(0, 0); + _control87(_EM_DENORMAL|_EM_INVALID|_EM_ZERODIVIDE + |_EM_OVERFLOW|_EM_UNDERFLOW|_EM_INEXACT, 0xffffffff); + + negexp = (exp < 0); + if(negexp) + exp = -exp; + /* update 'cur' with this exponent. */ + while(exp) { + if(exp & 1) + cur *= expcnt; + exp /= 2; + expcnt = expcnt*expcnt; + } + cur = (negexp ? d/cur : d*cur); + + _control87(fpcontrol, 0xffffffff); + + if (!suppress) { + if (l_or_L_prefix) _SET_NUMBER_(double); + else _SET_NUMBER_(float); + } +} +#undef _SET_NUMBER_ diff --git a/reactos/lib/sdk/crt/string/winesup.h b/reactos/lib/sdk/crt/string/winesup.h new file mode 100644 index 00000000000..7bc3ed7810a --- /dev/null +++ b/reactos/lib/sdk/crt/string/winesup.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include +#include +#include + +#undef NtCurrentPeb +#define NtCurrentPeb() (NtCurrentTeb()->Peb) +#define GetProcessHeap() (NtCurrentPeb()->ProcessHeap) + +#define HeapAlloc(_Heap, _Flags, _Size) RtlAllocateHeap(_Heap, _Flags, _Size) +#define HeapFree(_Heap, _Flags, _Ptr) RtlFreeHeap(_Heap, _Flags, _Ptr) + +#ifdef _LIBCNT_ +static inline unsigned int __control87(unsigned int new, unsigned int mask) +{ + return 0; +} +#define _control87 __control87 +extern threadlocinfo _LIBCNT_locinfo; +#define get_locinfo() (&_LIBCNT_locinfo) +#else +#define get_locinfo() ((pthreadlocinfo)get_locinfo()) +#endif + +void +__declspec(noinline) +_internal_handle_float( + int negative, + int exp, + int suppress, + ULONGLONG d, + int l_or_L_prefix, + va_list *ap); + +//#include + +#define __WINE_DEBUG_H +#undef WINE_DEFAULT_DEBUG_CHANNEL +#define WINE_DEFAULT_DEBUG_CHANNEL(_Ch) +#undef TRACE +#define TRACE(...) /* DPRINT(__VA_ARGS__) */ +#define debugstr_a(format) format