summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2013-12-18 19:23:33 +0000
committerCorinna Vinschen <corinna@vinschen.de>2013-12-18 19:23:33 +0000
commit576b7804d63caaae29b7a6ae007f10c0d2c0e58a (patch)
treec5ae72f229ffe0b57fd5b2c3edf9489a5b927d91
parent5730605d5597ef0fb24a7626d1c2da4fc8529eaa (diff)
downloadcygnal-576b7804d63caaae29b7a6ae007f10c0d2c0e58a.tar.gz
cygnal-576b7804d63caaae29b7a6ae007f10c0d2c0e58a.tar.bz2
cygnal-576b7804d63caaae29b7a6ae007f10c0d2c0e58a.zip
* vfscanf.c (BUF): Change definition to take multibyte decimal point
into account. (__SVFSCANF_R): Handle radix char language-dependent per POSIX. (__SVFWSCANF_R): Ditto.
-rw-r--r--newlib/ChangeLog8
-rw-r--r--newlib/libc/stdio/vfscanf.c66
-rw-r--r--newlib/libc/stdio/vfwscanf.c41
3 files changed, 94 insertions, 21 deletions
diff --git a/newlib/ChangeLog b/newlib/ChangeLog
index bf3a40ae6..5454e587d 100644
--- a/newlib/ChangeLog
+++ b/newlib/ChangeLog
@@ -1,3 +1,11 @@
+2013-12-18 Corinna Vinschen <vinschen@redhat.com>
+
+ * vfscanf.c (BUF): Change definition to take multibyte decimal point
+ into account.
+ (__SVFSCANF_R): Handle radix char language-dependent
+ per POSIX.
+ (__SVFWSCANF_R): Ditto.
+
2013-12-10 Jeff Johnston <jjohnstn@redhat.com>
* acconfig.h: Add _HAVE_CC_INHIBIT_LOOP_TO_LIBCALL.
diff --git a/newlib/libc/stdio/vfscanf.c b/newlib/libc/stdio/vfscanf.c
index ae94cea3f..5fd153de6 100644
--- a/newlib/libc/stdio/vfscanf.c
+++ b/newlib/libc/stdio/vfscanf.c
@@ -162,6 +162,7 @@ Supporting OS subroutines required:
#ifdef FLOATING_POINT
#include <math.h>
#include <float.h>
+#include <locale.h>
/* Currently a test is made to see if long double processing is warranted.
This could be changed in the future should the _ldtoa_r code be
@@ -174,11 +175,7 @@ extern _LONG_DOUBLE _strtold _PARAMS((char *s, char **sptr));
#include "floatio.h"
-#if ((MAXEXP+MAXFRACT+3) > MB_LEN_MAX)
-# define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */
-#else
-# define BUF MB_LEN_MAX
-#endif
+#define BUF (MAXEXP+MAXFRACT+MB_LEN_MAX+2) /* decimal point + sign + NUL */
/* An upper bound for how long a long prints in decimal. 4 / 13 approximates
log (2). Add one char for roundoff compensation and one for the sign. */
@@ -1288,6 +1285,10 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
unsigned width_left = 0;
char nancount = 0;
char infcount = 0;
+ const char *decpt = _localeconv_r (rptr)->decimal_point;
+#ifdef _MB_CAPABLE
+ int decptpos = 0;
+#endif
#ifdef hardway
if (width == 0 || width > sizeof (buf) - 1)
#else
@@ -1416,14 +1417,6 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
goto fok;
}
break;
- case '.':
- if (flags & DPTOK)
- {
- flags &= ~(SIGNOK | DPTOK);
- leading_zeroes = zeroes;
- goto fok;
- }
- break;
case 'e':
case 'E':
/* no exponent without some digits */
@@ -1442,6 +1435,53 @@ _DEFUN(__SVFSCANF_R, (rptr, fp, fmt0, ap),
goto fok;
}
break;
+ default:
+#ifndef _MB_CAPABLE
+ if ((unsigned char) c == (unsigned char) decpt[0]
+ && (flags & DPTOK))
+ {
+ flags &= ~(SIGNOK | DPTOK);
+ leading_zeroes = zeroes;
+ goto fok;
+ }
+ break;
+#else
+ if (flags & DPTOK)
+ {
+ while ((unsigned char) c
+ == (unsigned char) decpt[decptpos])
+ {
+ if (decpt[++decptpos] == '\0')
+ {
+ /* We read the complete decpt seq. */
+ flags &= ~(SIGNOK | DPTOK);
+ leading_zeroes = zeroes;
+ p = stpncpy (p, decpt, decptpos);
+ decptpos = 0;
+ goto fskip;
+ }
+ ++nread;
+ if (--fp->_r > 0)
+ fp->_p++;
+ else if (__srefill_r (rptr, fp))
+ break; /* EOF */
+ c = *fp->_p;
+ }
+ if (decptpos > 0)
+ {
+ /* We read part of a multibyte decimal point,
+ but the rest is invalid or we're at EOF,
+ so back off. */
+ while (decptpos-- > 0)
+ {
+ _ungetc_r (rptr, (unsigned char) decpt[decptpos],
+ fp);
+ --nread;
+ }
+ }
+ }
+ break;
+#endif
}
break;
fok:
diff --git a/newlib/libc/stdio/vfwscanf.c b/newlib/libc/stdio/vfwscanf.c
index d86594ef6..731197a1c 100644
--- a/newlib/libc/stdio/vfwscanf.c
+++ b/newlib/libc/stdio/vfwscanf.c
@@ -161,6 +161,9 @@ C99, POSIX-1.2008
#ifdef FLOATING_POINT
#include <math.h>
#include <float.h>
+#ifdef __HAVE_LOCALE_INFO_EXTENDED__
+#include "../locale/lnumeric.h"
+#endif
/* Currently a test is made to see if long double processing is warranted.
This could be changed in the future should the _ldtoa_r code be
@@ -414,6 +417,7 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
float *flp;
_LONG_DOUBLE *ldp;
double *dp;
+ wchar_t decpt;
#endif
long *lp;
#ifndef _NO_LONGLONG
@@ -440,6 +444,27 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
# define GET_ARG(n, ap, type) (va_arg (ap, type))
#endif
+#ifdef FLOATING_POINT
+#ifdef _MB_CAPABLE
+#ifdef __HAVE_LOCALE_INFO_EXTENDED__
+ decpt = *__get_current_numeric_locale ()->wdecimal_point;
+#else
+ {
+ size_t nconv;
+
+ memset (&state, '\0', sizeof (state));
+ nconv = _mbrtowc_r (data, &decpt,
+ _localeconv_r (data)->decimal_point,
+ MB_CUR_MAX, &state);
+ if (nconv == (size_t) -1 || nconv == (size_t) -2)
+ decpt = L'.';
+ }
+#endif /* !__HAVE_LOCALE_INFO_EXTENDED__ */
+#else
+ decpt = (wchar_t) *_localeconv_r (data)->decimal_point;
+#endif /* !_MB_CAPABLE */
+#endif /* FLOATING_POINT */
+
_newlib_flockfile_start (fp);
ORIENT (fp, 1);
@@ -1271,14 +1296,6 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
goto fok;
}
break;
- case L'.':
- if (flags & DPTOK)
- {
- flags &= ~(SIGNOK | DPTOK);
- leading_zeroes = zeroes;
- goto fok;
- }
- break;
case L'e':
case L'E':
/* no exponent without some digits */
@@ -1297,6 +1314,14 @@ _DEFUN(__SVFWSCANF_R, (rptr, fp, fmt0, ap),
goto fok;
}
break;
+ default:
+ if ((wchar_t) c == decpt && (flags & DPTOK))
+ {
+ flags &= ~(SIGNOK | DPTOK);
+ leading_zeroes = zeroes;
+ goto fok;
+ }
+ break;
}
if (c != WEOF)
_ungetwc_r (rptr, c, fp);