From eac4282fa6325e5633bdfee7a6afd9f943b34b1a Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Fri, 28 Jul 2000 17:45:15 +0000 Subject: Update. 2000-07-27 Jakub Jelinek * locale/indigits.h (indigit_value): Correct. * locale/indigitswc.h (indigitwc_value): Correct. * stdio-common/vfscanf.c (__vfscanf): Fix I18N number conversion, add GROUP checking for it, fix GROUP number conversion with strlen(thousands) > 1. Honour width correctly in the presence of floating decimal points and thousands separators. * stdio-common/tst-sscanf.c: New test. * stdio-common/Makefile: Add it to tests. * sysdeps/generic/strtol.c (strtol): Fix conversion if there are thousands separators and group argument is non-zero. Reported by Andi Kleen . --- stdio-common/vfscanf.c | 269 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 186 insertions(+), 83 deletions(-) (limited to 'stdio-common/vfscanf.c') diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c index 9457c4c17e..d618851a89 100644 --- a/stdio-common/vfscanf.c +++ b/stdio-common/vfscanf.c @@ -1213,6 +1213,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) { int from_level; int to_level; + int level; #ifdef COMPILE_WSCANF const wchar_t *wcdigits[10]; #else @@ -1229,99 +1230,196 @@ __vfscanf (FILE *s, const char *format, va_list argptr) _NL_CTYPE_INDIGITS_MB_LEN) - 1; #endif - /* In this round we get the pointer to the digit strings - and also perform the first round of comparisons. */ - for (n = 0; n < 10; ++n) + /* Read the number into workspace. */ + while (c != EOF && width != 0) { - /* Get the string for the digits with value N. */ + /* In this round we get the pointer to the digit strings + and also perform the first round of comparisons. */ + for (n = 0; n < 10; ++n) + { + /* Get the string for the digits with value N. */ #ifdef COMPILE_WSCANF - wcdigits[n] = (const wchar_t *) - _NL_CURRENT (LC_CTYPE, _NL_CTYPE_INDIGITS0_WC + n); - if (c == *wcdigits[n]) - break; + wcdigits[n] = (const wchar_t *) + _NL_CURRENT (LC_CTYPE, _NL_CTYPE_INDIGITS0_WC + n); + wcdigits[n] += from_level; - /* Advance the pointer to the next string. */ - ++wcdigits[n]; + if (c == *wcdigits[n]) + { + to_level = from_level; + break; + } + + /* Advance the pointer to the next string. */ + ++wcdigits[n]; #else - size_t dlen; - size_t dcnt; + const char *cmpp; + int avail = width > 0 ? width : INT_MAX; - mbdigits[n] = _NL_CURRENT (LC_CTYPE, - _NL_CTYPE_INDIGITS0_MB + n); - dlen = strlen (mbdigits[n]); + mbdigits[n] = _NL_CURRENT (LC_CTYPE, + _NL_CTYPE_INDIGITS0_MB + n); - dcnt = 0; - do - { - if (c != mbdigits[n][dcnt]) - break; - c = inchar (); - } - while (--dcnt > 0); + for (level = 0; level < from_level; level++) + mbdigits[n] = strchr (mbdigits[n], '\0') + 1; - if (dcnt == 0) - /* We found it. */ - break; + cmpp = mbdigits[n]; + while (*cmpp == c && avail > 0) + { + if (*++cmpp == '\0') + break; + else + { + if ((c = inchar ()) == EOF) + break; + --avail; + } + } + + if (*cmpp == '\0') + { + if (width > 0) + width = avail; + to_level = from_level; + break; + } - /* Advance the pointer to the next string. */ - mbdigits[n] += dlen + 1; + /* We are pushing all read characters back. */ + if (cmpp > mbdigits[n]) + { + ungetc (c, s); + while (--cmpp > mbdigits[n]) + ungetc (*cmpp, s); + c = *cmpp; + } + + /* Advance the pointer to the next string. */ + mbdigits[n] = strchr (mbdigits[n], '\0') + 1; #endif - } + } - if (n == 10) - { - /* Have not yet found the digit. */ - while (++from_level <= to_level) + if (n == 10) { - /* Search all ten digits of this level. */ - for (n = 0; n < 10; ++n) + /* Have not yet found the digit. */ + for (level = from_level + 1; level <= to_level; ++level) { + /* Search all ten digits of this level. */ + for (n = 0; n < 10; ++n) + { #ifdef COMPILE_WSCANF - if (c == *wcdigits[n]) - break; + if (c == *wcdigits[n]) + break; - /* Advance the pointer to the next string. */ - ++wcdigits[n]; + /* Advance the pointer to the next string. */ + ++wcdigits[n]; #else - size_t dlen = strlen (mbdigits[n]); - size_t dcnt; + const char *cmpp; + int avail = width > 0 ? width : INT_MAX; + + cmpp = mbdigits[n]; + while (*cmpp == c && avail > 0) + { + if (*++cmpp == '\0') + break; + else + { + if ((c = inchar ()) == EOF) + break; + --avail; + } + } - dcnt = 0; - do + if (*cmpp == '\0') + { + if (width > 0) + width = avail; + break; + } + + /* We are pushing all read characters back. */ + if (cmpp > mbdigits[n]) + { + ungetc (c, s); + while (--cmpp > mbdigits[n]) + ungetc (*cmpp, s); + c = *cmpp; + } + + /* Advance the pointer to the next string. */ + mbdigits[n] = strchr (mbdigits[n], '\0') + 1; +#endif + } + + if (n < 10) { - if (c != mbdigits[n][dcnt]) - break; - c = inchar (); + /* Found it. */ + from_level = level; + to_level = level; + break; } - while (--dcnt > 0); + } + } - if (dcnt == 0) - /* We found it. */ + if (n < 10) + c = L_('0') + n; + else if ((flags & GROUP) +#ifdef COMPILE_WSCANF + && thousands != L'\0' +#else + && thousands != NULL +#endif + ) + { + /* Try matching against the thousands separator. */ +#ifdef COMPILE_WSCANF + if (c != thousands) + break; +#else + const char *cmpp = thousands; + int avail = width > 0 ? width : INT_MAX; + + while (*cmpp == c && avail > 0) + { + ADDW (c); + if (*++cmpp == '\0') break; + else + { + if ((c = inchar ()) == EOF) + break; + --avail; + } + } - /* Advance the pointer to the next string. */ - mbdigits[n] += dlen + 1; -#endif + if (*cmpp != '\0') + { + /* We are pushing all read characters back. */ + if (cmpp > thousands) + { + wpsize -= cmpp - thousands; + ungetc (c, s); + while (--cmpp > thousands) + ungetc (*cmpp, s); + c = *cmpp; + } + break; } - if (n < 10) - /* Found it. */ - break; + if (width > 0) + width = avail; - /* Next level. */ - ++from_level; + /* The last thousands character will be added back by + the ADDW below. */ + --wpsize; +#endif } - } + else + break; - if (n == 10) - { - /* Haven't found anything. Push the last character back - and return an error. */ - ungetc (c, s); - input_error (); - } + ADDW (c); + if (width > 0) + --width; - ADDW (L_('0') + n); + c = inchar (); + } } else /* Read the number into workspace. */ @@ -1351,20 +1449,24 @@ __vfscanf (FILE *s, const char *format, va_list argptr) int avail = width > 0 ? width : INT_MAX; while (*cmpp == c && avail > 0) - if (*++cmpp == '\0') - break; - else - { - if (inchar () == EOF) - break; - --avail; - } + { + ADDW (c); + if (*++cmpp == '\0') + break; + else + { + if ((c = inchar ()) == EOF) + break; + --avail; + } + } if (*cmpp != '\0') { - /* We are pushing all read character back. */ + /* We are pushing all read characters back. */ if (cmpp > thousands) { + wpsize -= cmpp - thousands; ungetc (c, s); while (--cmpp > thousands) ungetc (*cmpp, s); @@ -1372,9 +1474,13 @@ __vfscanf (FILE *s, const char *format, va_list argptr) } break; } + if (width > 0) - /* +1 because we substract below. */ - width = avail + 1; + width = avail; + + /* The last thousands character will be added back by + the ADDW below. */ + --wpsize; #endif } else @@ -1527,8 +1633,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) conv_error (); } if (width > 0) - /* +1 because we substract below. */ - width = avail + 1; + width = avail; #endif } if (width > 0) @@ -1689,8 +1794,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) for (cmpp = decimal; *cmpp != '\0'; ++cmpp) ADDW (*cmpp); if (width > 0) - /* +1 because we substract below. */ - width = avail + 1; + width = avail; got_dot = 1; } else @@ -1727,8 +1831,7 @@ __vfscanf (FILE *s, const char *format, va_list argptr) for (cmpp = thousands; *cmpp != '\0'; ++cmpp) ADDW (*cmpp); if (width > 0) - /* +1 because we substract below. */ - width = avail + 1; + width = avail; } else { -- cgit v1.2.3