diff options
author | Jakub Jelinek <jakub@redhat.com> | 2007-02-21 11:15:54 +0000 |
---|---|---|
committer | Jakub Jelinek <jakub@redhat.com> | 2007-02-21 11:15:54 +0000 |
commit | b428b742cf54d423e5a7a68fcbec9473303eeafa (patch) | |
tree | a7eb4bb9273b2c48c1d4deacb5458f5075d902ef /stdio-common | |
parent | 6c8cc2d3042d0585741452006c29cb21fbba39ea (diff) | |
download | glibc-b428b742cf54d423e5a7a68fcbec9473303eeafa.tar glibc-b428b742cf54d423e5a7a68fcbec9473303eeafa.tar.gz glibc-b428b742cf54d423e5a7a68fcbec9473303eeafa.tar.bz2 glibc-b428b742cf54d423e5a7a68fcbec9473303eeafa.zip |
Updated to fedora-glibc-20070221T1011cvs/fedora-glibc-2_5_90-18
Diffstat (limited to 'stdio-common')
-rw-r--r-- | stdio-common/Makefile | 2 | ||||
-rw-r--r-- | stdio-common/printf_fp.c | 94 | ||||
-rw-r--r-- | stdio-common/tfformat.c | 15 | ||||
-rw-r--r-- | stdio-common/tst-sscanf.c | 125 | ||||
-rw-r--r-- | stdio-common/tst-swscanf.c | 5 | ||||
-rw-r--r-- | stdio-common/vfscanf.c | 424 |
6 files changed, 437 insertions, 228 deletions
diff --git a/stdio-common/Makefile b/stdio-common/Makefile index 98220550f4..709a5730fb 100644 --- a/stdio-common/Makefile +++ b/stdio-common/Makefile @@ -54,7 +54,7 @@ tests := tstscanf test_rdwr test-popen tstgetln test-fseek \ tst-swprintf tst-fseek tst-fmemopen test-vfprintf tst-gets \ tst-perror tst-sprintf tst-rndseek tst-fdopen tst-fphex bug14 bug15 \ tst-popen tst-unlockedio tst-fmemopen2 tst-put-error tst-fgets \ - tst-fwrite bug16 bug17 + tst-fwrite bug16 bug17 tst-swscanf test-srcs = tst-unbputc tst-printf diff --git a/stdio-common/printf_fp.c b/stdio-common/printf_fp.c index e4e32f9c28..c27c0d496c 100644 --- a/stdio-common/printf_fp.c +++ b/stdio-common/printf_fp.c @@ -1,6 +1,6 @@ /* Floating point output for `printf'. - Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2006 - Free Software Foundation, Inc. + Copyright (C) 1995-2003, 2006, 2007 Free Software Foundation, Inc. + This file is part of the GNU C Library. Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995. @@ -811,12 +811,14 @@ ___printf_fp (FILE *fp, int chars_needed; int expscale; int intdig_max, intdig_no = 0; - int fracdig_min, fracdig_max, fracdig_no = 0; + int fracdig_min; + int fracdig_max; int dig_max; int significant; int ngroups = 0; + char spec = _tolower (info->spec); - if (_tolower (info->spec) == 'e') + if (spec == 'e') { type = info->spec; intdig_max = 1; @@ -826,7 +828,7 @@ ___printf_fp (FILE *fp, dig_max = INT_MAX; /* Unlimited. */ significant = 1; /* Does not matter here. */ } - else if (_tolower (info->spec) == 'f') + else if (spec == 'f') { type = 'f'; fracdig_min = fracdig_max = info->prec < 0 ? 6 : info->prec; @@ -887,7 +889,7 @@ ___printf_fp (FILE *fp, other output. If the amount of memory we have to allocate is too large use `malloc' instead of `alloca'. */ buffer_malloced = ! __libc_use_alloca (chars_needed * 2 * sizeof (wchar_t)); - if (buffer_malloced) + if (__builtin_expect (buffer_malloced, 0)) { wbuffer = (wchar_t *) malloc ((2 + chars_needed) * sizeof (wchar_t)); if (wbuffer == NULL) @@ -923,7 +925,9 @@ ___printf_fp (FILE *fp, } /* Generate the needed number of fractional digits. */ - while (fracdig_no < fracdig_min + int fracdig_no = 0; + int added_zeros = 0; + while (fracdig_no < fracdig_min + added_zeros || (fracdig_no < fracdig_max && (fracsize > 1 || frac[0] != 0))) { ++fracdig_no; @@ -934,7 +938,7 @@ ___printf_fp (FILE *fp, { ++fracdig_max; if (fracdig_min > 0) - ++fracdig_min; + ++added_zeros; } } @@ -971,11 +975,23 @@ ___printf_fp (FILE *fp, { /* Process fractional digits. Terminate if not rounded or radix character is reached. */ + int removed = 0; while (*--wtp != decimalwc && *wtp == L'9') - *wtp = '0'; + { + *wtp = L'0'; + ++removed; + } + if (removed == fracdig_min && added_zeros > 0) + --added_zeros; if (*wtp != decimalwc) /* Round up. */ (*wtp)++; + else if (__builtin_expect (spec == 'g' && type == 'f' && info->alt, + 0)) + /* This is a special case: the rounded number is 1.0, + the format is 'g' or 'G', and the alternative format + is selected. This means the result mist be "1.". */ + --added_zeros; } if (fracdig_no == 0 || *wtp == decimalwc) @@ -1042,7 +1058,7 @@ ___printf_fp (FILE *fp, do_expo: /* Now remove unnecessary '0' at the end of the string. */ - while (fracdig_no > fracdig_min && *(wcp - 1) == L'0') + while (fracdig_no > fracdig_min + added_zeros && *(wcp - 1) == L'0') { --wcp; --fracdig_no; @@ -1060,26 +1076,41 @@ ___printf_fp (FILE *fp, /* Write the exponent if it is needed. */ if (type != 'f') { - *wcp++ = (wchar_t) type; - *wcp++ = expsign ? L'-' : L'+'; + if (__builtin_expect (expsign != 0 && exponent == 4 && spec == 'g', 0)) + { + /* This is another special case. The exponent of the number is + really smaller than -4, which requires the 'e'/'E' format. + But after rounding the number has an exponent of -4. */ + assert (wcp >= wstartp + 2); + assert (wstartp[0] == L'1'); + __wmemcpy (wstartp, L"0.0001", 6); + wstartp[1] = decimalwc; + wmemset (wstartp + 6, L'0', wcp - (wstartp + 2)); + wcp += 4; + } + else + { + *wcp++ = (wchar_t) type; + *wcp++ = expsign ? L'-' : L'+'; - /* Find the magnitude of the exponent. */ - expscale = 10; - while (expscale <= exponent) - expscale *= 10; + /* Find the magnitude of the exponent. */ + expscale = 10; + while (expscale <= exponent) + expscale *= 10; - if (exponent < 10) - /* Exponent always has at least two digits. */ - *wcp++ = L'0'; - else - do - { - expscale /= 10; - *wcp++ = L'0' + (exponent / expscale); - exponent %= expscale; - } - while (expscale > 10); - *wcp++ = L'0' + exponent; + if (exponent < 10) + /* Exponent always has at least two digits. */ + *wcp++ = L'0'; + else + do + { + expscale /= 10; + *wcp++ = L'0' + (exponent / expscale); + exponent %= expscale; + } + while (expscale > 10); + *wcp++ = L'0' + exponent; + } } /* Compute number of characters which must be filled with the padding @@ -1120,15 +1151,14 @@ ___printf_fp (FILE *fp, else thousands_sep_len = strlen (thousands_sep); - if (buffer_malloced) + if (__builtin_expect (buffer_malloced, 0)) { buffer = (char *) malloc (2 + chars_needed + decimal_len + ngroups * thousands_sep_len); if (buffer == NULL) { /* Signal an error to the caller. */ - if (buffer_malloced) - free (wbuffer); + free (wbuffer); return -1; } } @@ -1162,7 +1192,7 @@ ___printf_fp (FILE *fp, PRINT (tmpptr, wstartp, wide ? wcp - wstartp : cp - tmpptr); /* Free the memory if necessary. */ - if (buffer_malloced) + if (__builtin_expect (buffer_malloced, 0)) { free (buffer); free (wbuffer); diff --git a/stdio-common/tfformat.c b/stdio-common/tfformat.c index ea7365b2c9..0370834e9f 100644 --- a/stdio-common/tfformat.c +++ b/stdio-common/tfformat.c @@ -4012,6 +4012,14 @@ sprint_double_type sprint_doubles[] = {__LINE__, 16, "0x1.0p+4", "%.1a"}, {__LINE__, 16, "0x1.00000000000000000000p+4", "%.20a"}, {__LINE__, 4444.88888888, "4445", "%2.F"}, + {__LINE__, 0.956, "1", "%.0g"}, + {__LINE__, 1.0956, "1.", "%#.0g"}, + {__LINE__, 0.956, "1.", "%#.0g"}, + {__LINE__, 0.0956, "0.1", "%#.0g"}, + {__LINE__, 0.00956, "0.01", "%#.0g"}, + {__LINE__, 0.000956, "0.001", "%#.0g"}, + {__LINE__, 0.000098, "0.0001", "%#.0g"}, + {__LINE__, 0.0000996, "0.00010", "%#.2g"}, {0 } @@ -4023,13 +4031,8 @@ sprint_double_type sprint_doubles[] = int required_precision = 13; -#if defined(__STDC__) || defined(__cplusplus) static int matches (register char *result, register const char *desired) -#else -int matches(result, desired) - register char *result; register const char *desired; -#endif { int digits_seen = 0; for (;; result++, desired++) { @@ -4080,7 +4083,7 @@ int main(int argc, char *argv[]) /* And one special test. */ { - const char ref[] = "1.7763568394002504646778106689453125e-15"; + static const char ref[] = "1.7763568394002504646778106689453125e-15"; int i; d = 1.0; for (i = 1; i < 50; ++i) diff --git a/stdio-common/tst-sscanf.c b/stdio-common/tst-sscanf.c index e710e190d7..a987e87797 100644 --- a/stdio-common/tst-sscanf.c +++ b/stdio-common/tst-sscanf.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2000, 2002, 2004 Free Software Foundation, Inc. +/* Copyright (C) 2000, 2002, 2004, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Jakub Jelinek <jakub@redhat.com>, 2000. @@ -21,12 +21,18 @@ #include <stdio.h> #include <locale.h> -const char *str_double[] = +#ifndef CHAR +# define CHAR char +# define L(str) str +# define SSCANF sscanf +#endif + +const CHAR *str_double[] = { - "-.10000E+020.20000E+020.25000E+010.40000E+010.50000E+010.12500E+01", - "0.10000E+020.20000E+020.25000E+010.40000E+010.50000E+010.12500E+01", - "-1234567E0198765432E0912345678901987654321091234567890198765432109", - "-0.1000E+020.20000E+020.25000E+010.40000E+010.50000E+010.12500E+01" + L("-.10000E+020.20000E+020.25000E+010.40000E+010.50000E+010.12500E+01"), + L("0.10000E+020.20000E+020.25000E+010.40000E+010.50000E+010.12500E+01"), + L("-1234567E0198765432E0912345678901987654321091234567890198765432109"), + L("-0.1000E+020.20000E+020.25000E+010.40000E+010.50000E+010.12500E+01") }; const double val_double[] = @@ -38,20 +44,20 @@ const double val_double[] = -0.1000E+02, 0.20000E+02, 0.25000E+01, 0.40000E+01, 0.50000E+01, 0.12500E+01 }; -const char *str_long[] = +const CHAR *str_long[] = { - "-12345678987654321123456789987654321123456789987654321", - "-12345678987654321123456789987654321123456789987654321", - "-12,345,678987,654,321123,456,789987,654,321123,456,789987,654,321", - "-12,345,678987,654,321123,456,789987,654,321123,456,789987,654,321" + L("-12345678987654321123456789987654321123456789987654321"), + L("-12345678987654321123456789987654321123456789987654321"), + L("-12,345,678987,654,321123,456,789987,654,321123,456,789987,654,321"), + L("-12,345,678987,654,321123,456,789987,654,321123,456,789987,654,321") }; -const char *fmt_long[] = +const CHAR *fmt_long[] = { - "%9ld%9ld%9ld%9ld%9ld%9ld", - "%I9ld%I9ld%I9ld%I9ld%I9ld%I9ld", - "%'11ld%'11ld%'11ld%'11ld%'11ld%'11ld", - "%I'11ld%I'11ld%I'11ld%I'11ld%I'11ld%I'11ld" + L("%9ld%9ld%9ld%9ld%9ld%9ld"), + L("%I9ld%I9ld%I9ld%I9ld%I9ld%I9ld"), + L("%'11ld%'11ld%'11ld%'11ld%'11ld%'11ld"), + L("%I'11ld%I'11ld%I'11ld%I'11ld%I'11ld%I'11ld") }; const long int val_long[] = @@ -59,38 +65,49 @@ const long int val_long[] = -12345678, 987654321, 123456789, 987654321, 123456789, 987654321 }; -struct int_test +struct test { - const char *str; - const char *fmt; + const CHAR *str; + const CHAR *fmt; int retval; -} int_tests[] = +} int_tests[] = { - { "foo\n", "foo\nbar", -1 }, - { "foo\n", "foo bar", -1 }, - { "foo\n", "foo %d", -1 }, - { "foo\n", "foo\n%d", -1 }, - { "foon", "foonbar", -1 }, - { "foon", "foon%d", -1 }, - { "foo ", "foo bar", -1 }, - { "foo ", "foo %d", -1 }, - { "foo\t", "foo\tbar", -1 }, - { "foo\t", "foo bar", -1 }, - { "foo\t", "foo %d", -1 }, - { "foo\t", "foo\t%d", -1 }, - { "foo", "foo", 0 }, - { "foon", "foo bar", 0 }, - { "foon", "foo %d", 0 }, - { "foo ", "fooxbar", 0 }, - { "foo ", "foox%d", 0 }, - { "foo bar", "foon", 0 }, - { "foo bar", "foo bar", 0 }, - { "foo bar", "foo %d", 0 }, - { "foo bar", "foon%d", 0 }, - { "foo ", "foo %n", 0 }, - { "foo%bar1", "foo%%bar%d", 1 }, + { L("foo\n"), L("foo\nbar"), -1 }, + { L("foo\n"), L("foo bar"), -1 }, + { L("foo\n"), L("foo %d"), -1 }, + { L("foo\n"), L("foo\n%d"), -1 }, + { L("foon"), L("foonbar"), -1 }, + { L("foon"), L("foon%d"), -1 }, + { L("foo "), L("foo bar"), -1 }, + { L("foo "), L("foo %d"), -1 }, + { L("foo\t"), L("foo\tbar"), -1 }, + { L("foo\t"), L("foo bar"), -1 }, + { L("foo\t"), L("foo %d"), -1 }, + { L("foo\t"), L("foo\t%d"), -1 }, + { L("foo"), L("foo"), 0 }, + { L("foon"), L("foo bar"), 0 }, + { L("foon"), L("foo %d"), 0 }, + { L("foo "), L("fooxbar"), 0 }, + { L("foo "), L("foox%d"), 0 }, + { L("foo bar"), L("foon"), 0 }, + { L("foo bar"), L("foo bar"), 0 }, + { L("foo bar"), L("foo %d"), 0 }, + { L("foo bar"), L("foon%d"), 0 }, + { L("foo "), L("foo %n"), 0 }, + { L("foo%bar1"), L("foo%%bar%d"), 1 }, /* Some OSes skip whitespace here while others don't. */ - { "foo \t %bar1", "foo%%bar%d", 1 } + { L("foo \t %bar1"), L("foo%%bar%d"), 1 } +}; + +struct test double_tests[] = +{ + { L("-1"), L("%1g"), 0 }, + { L("-.1"), L("%2g"), 0 }, + { L("-inf"), L("%3g"), 0 }, + { L("+0"), L("%1g"), }, + { L("-0x1p0"), L("%2g"), 1 }, + { L("-..1"), L("%g"), 0 }, + { L("-inf"), L("%g"), 1 } }; int @@ -112,7 +129,7 @@ main (void) for (i = 0; i < 4; ++i) { - if (sscanf (str_double[i], "%11lf%11lf%11lf%11lf%11lf%11lf", + if (SSCANF (str_double[i], L("%11lf%11lf%11lf%11lf%11lf%11lf"), &d[0], &d[1], &d[2], &d[3], &d[4], &d[5]) != 6) { printf ("Double sscanf test %d wrong number of " @@ -132,7 +149,7 @@ main (void) for (i = 0; i < 4; ++i) { - if (sscanf (str_long[i], fmt_long[i], + if (SSCANF (str_long[i], fmt_long[i], &l[0], &l[1], &l[2], &l[3], &l[4], &l[5]) != 6) { printf ("Integer sscanf test %d wrong number of " @@ -157,7 +174,7 @@ main (void) { int dummy, ret; - if ((ret = sscanf (int_tests[i].str, int_tests[i].fmt, + if ((ret = SSCANF (int_tests[i].str, int_tests[i].fmt, &dummy)) != int_tests[i].retval) { printf ("int_tests[%d] returned %d != %d\n", @@ -166,5 +183,19 @@ main (void) } } + for (i = 0; i < sizeof (double_tests) / sizeof (double_tests[0]); ++i) + { + double dummy; + int ret; + + if ((ret = SSCANF (double_tests[i].str, double_tests[i].fmt, + &dummy)) != double_tests[i].retval) + { + printf ("double_tests[%d] returned %d != %d\n", + i, ret, double_tests[i].retval); + result = 1; + } + } + return result; } diff --git a/stdio-common/tst-swscanf.c b/stdio-common/tst-swscanf.c new file mode 100644 index 0000000000..6ec1c8e6c7 --- /dev/null +++ b/stdio-common/tst-swscanf.c @@ -0,0 +1,5 @@ +#define CHAR wchar_t +#define L(str) L##str +#define SSCANF swscanf +#include <wchar.h> +#include "tst-sscanf.c" diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c index 1ea9bc4e07..0daf4ae0dd 100644 --- a/stdio-common/vfscanf.c +++ b/stdio-common/vfscanf.c @@ -1,5 +1,4 @@ -/* Copyright (C) 1991-2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. +/* Copyright (C) 1991-2006, 2007 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -53,17 +52,19 @@ #endif /* Those are flags in the conversion format. */ -#define LONG 0x001 /* l: long or double */ -#define LONGDBL 0x002 /* L: long long or long double */ -#define SHORT 0x004 /* h: short */ -#define SUPPRESS 0x008 /* *: suppress assignment */ -#define POINTER 0x010 /* weird %p pointer (`fake hex') */ -#define NOSKIP 0x020 /* do not skip blanks */ -#define WIDTH 0x040 /* width was given */ -#define GROUP 0x080 /* ': group numbers */ -#define MALLOC 0x100 /* a: malloc strings */ -#define CHAR 0x200 /* hh: char */ -#define I18N 0x400 /* I: use locale's digits */ +#define LONG 0x0001 /* l: long or double */ +#define LONGDBL 0x0002 /* L: long long or long double */ +#define SHORT 0x0004 /* h: short */ +#define SUPPRESS 0x0008 /* *: suppress assignment */ +#define POINTER 0x0010 /* weird %p pointer (`fake hex') */ +#define NOSKIP 0x0020 /* do not skip blanks */ +#define NUMBER_SIGNED 0x0040 /* signed integer */ +#define GROUP 0x0080 /* ': group numbers */ +#define MALLOC 0x0100 /* a: malloc strings */ +#define CHAR 0x0200 /* hh: char */ +#define I18N 0x0400 /* I: use locale's digits */ +#define HEXA_FLOAT 0x0800 /* hexadecimal float */ +#define READ_POINTER 0x1000 /* this is a pointer value */ #include <locale/localeinfo.h> @@ -205,9 +206,6 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, #define exp_char not_in /* Base for integral numbers. */ int base; - /* Signedness for integral numbers. */ - int number_signed; -#define is_hexa number_signed /* Decimal point character. */ #ifdef COMPILE_WSCANF wint_t decimal; @@ -239,8 +237,6 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, possibly be matched even if in the input stream no character is available anymore. */ int skip_space = 0; - /* Nonzero if we are reading a pointer. */ - int read_pointer; /* Workspace. */ CHAR_T *tw; /* Temporary pointer. */ CHAR_T *wp = NULL; /* Workspace. */ @@ -403,9 +399,6 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, /* This is the start of the conversion string. */ flags = 0; - /* Not yet decided whether we read a pointer or not. */ - read_pointer = 0; - /* Initialize state of modifiers. */ argpos = 0; @@ -424,7 +417,6 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, { /* Oops; that was actually the field width. */ width = argpos; - flags |= WIDTH; argpos = 0; goto got_width; } @@ -439,17 +431,18 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, flags |= SUPPRESS; break; case L_('\''): - flags |= GROUP; +#ifdef COMPILE_WSCANF + if (thousands != L'\0') +#else + if (thousands != NULL) +#endif + flags |= GROUP; break; case L_('I'): flags |= I18N; break; } - /* We have seen width. */ - if (ISDIGIT ((UCHAR_T) *f)) - flags |= WIDTH; - /* Find the maximum field width. */ width = 0; while (ISDIGIT ((UCHAR_T) *f)) @@ -1083,27 +1076,24 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, case L_('x'): /* Hexadecimal integer. */ case L_('X'): /* Ditto. */ base = 16; - number_signed = 0; goto number; case L_('o'): /* Octal integer. */ base = 8; - number_signed = 0; goto number; case L_('u'): /* Unsigned decimal integer. */ base = 10; - number_signed = 0; goto number; case L_('d'): /* Signed decimal integer. */ base = 10; - number_signed = 1; + flags |= NUMBER_SIGNED; goto number; case L_('i'): /* Generic number. */ base = 0; - number_signed = 1; + flags |= NUMBER_SIGNED; number: c = inchar (); @@ -1270,13 +1260,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, mbdigits[n] = strchr (mbdigits[n], '\0') + 1; cmpp = mbdigits[n]; - while ((unsigned char) *cmpp == c && avail > 0) + while ((unsigned char) *cmpp == c && avail >= 0) { if (*++cmpp == '\0') break; else { - if ((c = inchar ()) == EOF) + if (avail == 0 || inchar () == EOF) break; --avail; } @@ -1323,13 +1313,13 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, int avail = width > 0 ? width : INT_MAX; cmpp = mbdigits[n]; - while ((unsigned char) *cmpp == c && avail > 0) + while ((unsigned char) *cmpp == c && avail >= 0) { if (*++cmpp == '\0') break; else { - if ((c = inchar ()) == EOF) + if (avail == 0 || inchar () == EOF) break; --avail; } @@ -1368,13 +1358,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (n < 10) c = L_('0') + n; - else if ((flags & GROUP) -#ifdef COMPILE_WSCANF - && thousands != L'\0' -#else - && thousands != NULL -#endif - ) + else if (flags & GROUP) { /* Try matching against the thousands separator. */ #ifdef COMPILE_WSCANF @@ -1384,14 +1368,14 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, const char *cmpp = thousands; int avail = width > 0 ? width : INT_MAX; - while ((unsigned char) *cmpp == c && avail > 0) + while ((unsigned char) *cmpp == c && avail >= 0) { ADDW (c); if (*++cmpp == '\0') break; else { - if ((c = inchar ()) == EOF) + if (avail == 0 || inchar () == EOF) break; --avail; } @@ -1440,13 +1424,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, } else if (!ISDIGIT (c) || (int) (c - L_('0')) >= base) { - if (base == 10 && (flags & GROUP) -#ifdef COMPILE_WSCANF - && thousands != L'\0' -#else - && thousands != NULL -#endif - ) + if (base == 10 && (flags & GROUP)) { /* Try matching against the thousands separator. */ #ifdef COMPILE_WSCANF @@ -1456,14 +1434,14 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, const char *cmpp = thousands; int avail = width > 0 ? width : INT_MAX; - while ((unsigned char) *cmpp == c && avail > 0) + while ((unsigned char) *cmpp == c && avail >= 0) { ADDW (c); if (*++cmpp == '\0') break; else { - if ((c = inchar ()) == EOF) + if (avail == 0 || inchar () == EOF) break; --avail; } @@ -1507,7 +1485,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, /* There was no number. If we are supposed to read a pointer we must recognize "(nil)" as well. */ if (__builtin_expect (wpsize == 0 - && read_pointer + && (flags & READ_POINTER) && (width < 0 || width >= 0) && c == '(' && TOLOWER (inchar ()) == L_('n') @@ -1534,14 +1512,14 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, ADDW (L_('\0')); if (need_longlong && (flags & LONGDBL)) { - if (number_signed) + if (flags & NUMBER_SIGNED) num.q = __strtoll_internal (wp, &tw, base, flags & GROUP); else num.uq = __strtoull_internal (wp, &tw, base, flags & GROUP); } else { - if (number_signed) + if (flags & NUMBER_SIGNED) num.l = __strtol_internal (wp, &tw, base, flags & GROUP); else num.ul = __strtoul_internal (wp, &tw, base, flags & GROUP); @@ -1551,32 +1529,32 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (!(flags & SUPPRESS)) { - if (! number_signed) + if (flags & NUMBER_SIGNED) { if (need_longlong && (flags & LONGDBL)) - *ARG (unsigned LONGLONG int *) = num.uq; + *ARG (LONGLONG int *) = num.q; else if (need_long && (flags & LONG)) - *ARG (unsigned long int *) = num.ul; + *ARG (long int *) = num.l; else if (flags & SHORT) - *ARG (unsigned short int *) - = (unsigned short int) num.ul; + *ARG (short int *) = (short int) num.l; else if (!(flags & CHAR)) - *ARG (unsigned int *) = (unsigned int) num.ul; + *ARG (int *) = (int) num.l; else - *ARG (unsigned char *) = (unsigned char) num.ul; + *ARG (signed char *) = (signed char) num.ul; } else { if (need_longlong && (flags & LONGDBL)) - *ARG (LONGLONG int *) = num.q; + *ARG (unsigned LONGLONG int *) = num.uq; else if (need_long && (flags & LONG)) - *ARG (long int *) = num.l; + *ARG (unsigned long int *) = num.ul; else if (flags & SHORT) - *ARG (short int *) = (short int) num.l; + *ARG (unsigned short int *) + = (unsigned short int) num.ul; else if (!(flags & CHAR)) - *ARG (int *) = (int) num.l; + *ARG (unsigned int *) = (unsigned int) num.ul; else - *ARG (signed char *) = (signed char) num.ul; + *ARG (unsigned char *) = (unsigned char) num.ul; } ++done; } @@ -1591,6 +1569,8 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, case L_('a'): case L_('A'): c = inchar (); + if (width > 0) + --width; if (__builtin_expect (c == EOF, 0)) input_error (); @@ -1603,63 +1583,6 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (__builtin_expect (width == 0 || inchar () == EOF, 0)) /* EOF is only an input error before we read any chars. */ conv_error (); - if (! ISDIGIT (c) && TOLOWER (c) != L_('i') - && TOLOWER (c) != L_('n')) - { -#ifdef COMPILE_WSCANF - if (__builtin_expect (c != decimal, 0)) - { - /* This is no valid number. */ - ungetc (c, s); - conv_error (); - } -#else - /* Match against the decimal point. At this point - we are taking advantage of the fact that we can - push more than one character back. This is - (almost) never necessary since the decimal point - string hopefully never contains more than one - byte. */ - const char *cmpp = decimal; - int avail = width > 0 ? width : INT_MAX; - - while ((unsigned char) *cmpp == c && avail-- > 0) - if (*++cmpp == '\0') - break; - else - { - if (inchar () == EOF) - break; - } - - if (__builtin_expect (*cmpp != '\0', 0)) - { - /* This is no valid number. */ - while (1) - { - ungetc (c, s); - if (cmpp == decimal) - break; - c = (unsigned char) *--cmpp; - } - - conv_error (); - } - else - { - /* Add all the characters. */ - for (cmpp = decimal; *cmpp != '\0'; ++cmpp) - ADDW ((unsigned char) *cmpp); - if (width > 0) - width = avail; - got_dot = 1; - - c = inchar (); - } - if (width > 0) - width = avail; -#endif - } if (width > 0) --width; } @@ -1751,7 +1674,6 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, goto scan_float; } - is_hexa = 0; exp_char = L_('e'); if (width != 0 && c == L_('0')) { @@ -1764,7 +1686,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, /* It is a number in hexadecimal format. */ ADDW (c); - is_hexa = 1; + flags |= HEXA_FLOAT; exp_char = L_('p'); /* Grouping is not allowed. */ @@ -1775,11 +1697,11 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, } } - do + while (1) { if (ISDIGIT (c)) ADDW (c); - else if (!got_e && is_hexa && ISXDIGIT (c)) + else if (!got_e && (flags & HEXA_FLOAT) && ISXDIGIT (c)) ADDW (c); else if (got_e && wp[wpsize - 1] == exp_char && (c == L_('-') || c == L_('+'))) @@ -1798,8 +1720,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, ADDW (c); got_dot = 1; } - else if ((flags & GROUP) != 0 && thousands != L'\0' - && ! got_dot && c == thousands) + else if ((flags & GROUP) != 0 && ! got_dot && c == thousands) ADDW (c); else { @@ -1814,12 +1735,12 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, if (! got_dot) { - while ((unsigned char) *cmpp == c && avail > 0) + while ((unsigned char) *cmpp == c && avail >= 0) if (*++cmpp == '\0') break; else { - if (inchar () == EOF) + if (avail == 0 || inchar () == EOF) break; --avail; } @@ -1843,20 +1764,19 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, we can compare against it. */ const char *cmp2p = thousands; - if ((flags & GROUP) != 0 && thousands != NULL - && ! got_dot) + if ((flags & GROUP) != 0 && ! got_dot) { while (cmp2p - thousands < cmpp - decimal && *cmp2p == decimal[cmp2p - thousands]) ++cmp2p; if (cmp2p - thousands == cmpp - decimal) { - while ((unsigned char) *cmp2p == c && avail > 0) + while ((unsigned char) *cmp2p == c && avail >= 0) if (*++cmp2p == '\0') break; else { - if (inchar () == EOF) + if (avail == 0 || inchar () == EOF) break; --avail; } @@ -1881,16 +1801,237 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, } #endif } + + if (width == 0 || inchar () == EOF) + break; + if (width > 0) --width; } - while (width != 0 && inchar () != EOF); + + wctrans_t map; + if (__builtin_expect ((flags & I18N) != 0, 0) + /* Hexadecimal floats make no sense, fixing localized + digits with ASCII letters. */ + && !(flags & HEXA_FLOAT) + /* Minimum requirement. */ + && (wpsize == 0 || got_dot) + && (map = __wctrans ("to_inpunct")) != NULL) + { + /* Reget the first character. */ + inchar (); + + /* Localized digits, decimal points, and thousands + separator. */ + wint_t wcdigits[12]; + + /* First get decimal equivalent to check if we read it + or not. */ + wcdigits[11] = __towctrans (L'.', map); + + /* If we have not read any character or have just read + locale decimal point which matches the decimal point + for localized FP numbers, then we may have localized + digits. Note, we test GOT_DOT above. */ +#ifdef COMPILE_WSCANF + if (wpsize == 0 || (wpsize == 1 && wcdigits[11] == decimal)) +#else + char mbdigits[12][MB_LEN_MAX + 1]; + + mbstate_t state; + memset (&state, '\0', sizeof (state)); + + bool match_so_far = wpsize == 0; + size_t mblen = __wcrtomb (mbdigits[11], wcdigits[11], &state); + if (mblen != (size_t) -1) + { + mbdigits[11][mblen] = '\0'; + match_so_far |= (wpsize == strlen (decimal) + && strcmp (decimal, mbdigits[11]) == 0); + } + else + { + size_t decimal_len = strlen (decimal); + /* This should always be the case but the data comes + from a file. */ + if (decimal_len <= MB_LEN_MAX) + { + match_so_far |= wpsize == decimal_len; + memcpy (mbdigits[11], decimal, decimal_len + 1); + } + else + match_so_far = false; + } + + if (match_so_far) +#endif + { + bool have_locthousands = (flags & GROUP) != 0; + + /* Now get the digits and the thousands-sep equivalents. */ + for (int n = 0; n < 11; ++n) + { + if (n < 10) + wcdigits[n] = __towctrans (L'0' + n, map); + else if (n == 10) + { + wcdigits[10] = __towctrans (L',', map); + have_locthousands &= wcdigits[10] != L'\0'; + } + +#ifndef COMPILE_WSCANF + memset (&state, '\0', sizeof (state)); + + size_t mblen = __wcrtomb (mbdigits[n], wcdigits[n], + &state); + if (mblen == (size_t) -1) + { + if (n == 10) + { + if (have_locthousands) + { + size_t thousands_len = strlen (thousands); + if (thousands_len <= MB_LEN_MAX) + memcpy (mbdigits[10], thousands, + thousands_len + 1); + else + have_locthousands = false; + } + } + else + /* Ignore checking against localized digits. */ + goto no_i18nflt; + } + else + mbdigits[n][mblen] = '\0'; +#endif + } + + /* Start checking against localized digits, if + convertion is done correctly. */ + while (1) + { + if (got_e && wp[wpsize - 1] == exp_char + && (c == L_('-') || c == L_('+'))) + ADDW (c); + else if (wpsize > 0 && !got_e + && (CHAR_T) TOLOWER (c) == exp_char) + { + ADDW (exp_char); + got_e = got_dot = 1; + } + else + { + /* Check against localized digits, decimal point, + and thousands separator. */ + int n; + for (n = 0; n < 12; ++n) + { +#ifdef COMPILE_WSCANF + if (c == wcdigits[n]) + { + if (n < 10) + ADDW (L_('0') + n); + else if (n == 11 && !got_dot) + { + ADDW (decimal); + got_dot = 1; + } + else if (n == 10 && have_locthousands + && ! got_dot) + ADDW (thousands); + else + /* The last read character is not part + of the number anymore. */ + n = 12; + + break; + } +#else + const char *cmpp = mbdigits[n]; + int avail = width > 0 ? width : INT_MAX; + + while ((unsigned char) *cmpp == c && avail >= 0) + if (*++cmpp == '\0') + break; + else + { + if (avail == 0 || inchar () == EOF) + break; + --avail; + } + if (*cmpp == '\0') + { + if (width > 0) + width = avail; + + if (n < 10) + ADDW (L_('0') + n); + else if (n == 11 && !got_dot) + { + /* Add all the characters. */ + for (cmpp = decimal; *cmpp != '\0'; + ++cmpp) + ADDW ((unsigned char) *cmpp); + + got_dot = 1; + } + else if (n == 10 && (flags & GROUP) != 0 + && ! got_dot) + { + /* Add all the characters. */ + for (cmpp = thousands; *cmpp != '\0'; + ++cmpp) + ADDW ((unsigned char) *cmpp); + } + else + /* The last read character is not part + of the number anymore. */ + n = 12; + + break; + } + + /* We are pushing all read characters back. */ + if (cmpp > mbdigits[n]) + { + ungetc (c, s); + while (--cmpp > mbdigits[n]) + ungetc_not_eof ((unsigned char) *cmpp, s); + c = (unsigned char) *cmpp; + } +#endif + } + + if (n >= 12) + { + /* The last read character is not part + of the number anymore. */ + ungetc (c, s); + break; + } + } + + if (width == 0 || inchar () == EOF) + break; + + if (width > 0) + --width; + } + } + +#ifndef COMPILE_WSCANF + no_i18nflt: + ; +#endif + } /* Have we read any character? If we try to read a number in hexadecimal notation and we have read only the `0x' prefix or no exponent this is an error. */ if (__builtin_expect (wpsize == 0 - || (is_hexa && (wpsize == 2 || ! got_e)), 0)) + || ((flags & HEXA_FLOAT) + && (wpsize == 2 || ! got_e)), 0)) conv_error (); scan_float: @@ -2429,8 +2570,7 @@ _IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr, flags &= ~(SHORT|LONGDBL); if (need_long) flags |= LONG; - number_signed = 0; - read_pointer = 1; + flags |= READ_POINTER; goto number; default: |