summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authordas <das@FreeBSD.org>2009-01-19 06:19:51 +0000
committerdas <das@FreeBSD.org>2009-01-19 06:19:51 +0000
commit97494c6c591e709d63c82a2b4cc7fd06df6a540f (patch)
tree5c8e24a9f6796b29eb3e538fd7acb9c2956fc8a7 /lib
parentdf3bc34671810c7f72a3bcd6c81d9a53ff3607da (diff)
downloadFreeBSD-src-97494c6c591e709d63c82a2b4cc7fd06df6a540f.zip
FreeBSD-src-97494c6c591e709d63c82a2b4cc7fd06df6a540f.tar.gz
- Add support for multibyte decimal_point encodings, e.g., U+066B.
A forthcoming gdtoa import is needed to make this fully work. - Improve the way "nan(...)" is parsed.
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/stdio/vfscanf.c46
-rw-r--r--lib/libc/stdio/vfwscanf.c26
2 files changed, 49 insertions, 23 deletions
diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c
index 9d724eb..bce4481 100644
--- a/lib/libc/stdio/vfscanf.c
+++ b/lib/libc/stdio/vfscanf.c
@@ -911,13 +911,13 @@ static int
parsefloat(FILE *fp, char *buf, char *end)
{
char *commit, *p;
- int infnanpos = 0;
+ int infnanpos = 0, decptpos = 0;
enum {
- S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
- S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
+ S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX,
+ S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS
} state = S_START;
unsigned char c;
- char decpt = *localeconv()->decimal_point;
+ const char *decpt = localeconv()->decimal_point;
_Bool gotmantdig = 0, ishex = 0;
/*
@@ -970,8 +970,6 @@ reswitch:
break;
case S_NAN:
switch (infnanpos) {
- case -1: /* XXX kludge to deal with nan(...) */
- goto parsedone;
case 0:
if (c != 'A' && c != 'a')
goto parsedone;
@@ -989,13 +987,15 @@ reswitch:
default:
if (c == ')') {
commit = p;
- infnanpos = -2;
+ state = S_DONE;
} else if (!isalnum(c) && c != '_')
goto parsedone;
break;
}
infnanpos++;
break;
+ case S_DONE:
+ goto parsedone;
case S_MAYBEHEX:
state = S_DIGITS;
if (c == 'X' || c == 'x') {
@@ -1006,16 +1006,34 @@ reswitch:
goto reswitch;
}
case S_DIGITS:
- if ((ishex && isxdigit(c)) || isdigit(c))
+ if ((ishex && isxdigit(c)) || isdigit(c)) {
gotmantdig = 1;
- else {
+ commit = p;
+ break;
+ } else {
+ state = S_DECPT;
+ goto reswitch;
+ }
+ case S_DECPT:
+ if (c == decpt[decptpos]) {
+ if (decpt[++decptpos] == '\0') {
+ /* We read the complete decpt seq. */
+ state = S_FRAC;
+ if (gotmantdig)
+ commit = p;
+ }
+ break;
+ } else if (!decptpos) {
+ /* We didn't read any decpt characters. */
state = S_FRAC;
- if (c != decpt)
- goto reswitch;
+ goto reswitch;
+ } else {
+ /*
+ * We read part of a multibyte decimal point,
+ * but the rest is invalid, so bail.
+ */
+ goto parsedone;
}
- if (gotmantdig)
- commit = p;
- break;
case S_FRAC:
if (((c == 'E' || c == 'e') && !ishex) ||
((c == 'P' || c == 'p') && ishex)) {
diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c
index 8a62a8f7..60c7c71 100644
--- a/lib/libc/stdio/vfwscanf.c
+++ b/lib/libc/stdio/vfwscanf.c
@@ -103,6 +103,8 @@ static int parsefloat(FILE *, wchar_t *, wchar_t *);
(cclcompl ? (wmemchr(ccls, (_c), ccle - ccls) == NULL) : \
(wmemchr(ccls, (_c), ccle - ccls) != NULL))
+static const mbstate_t initial_mbs;
+
/*
* MT-safe version.
*/
@@ -142,7 +144,6 @@ __vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
char *mbp; /* multibyte string pointer for %c %s %[ */
size_t nconv; /* number of bytes in mb. conversion */
char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */
- static const mbstate_t initial;
mbstate_t mbs;
/* `basefix' is used to avoid `if' tests in the integer scanner */
@@ -375,7 +376,7 @@ literal:
if (!(flags & SUPPRESS))
mbp = va_arg(ap, char *);
n = 0;
- mbs = initial;
+ mbs = initial_mbs;
while (width != 0 &&
(wi = __fgetwc(fp)) != WEOF) {
if (width >= MB_CUR_MAX &&
@@ -440,7 +441,7 @@ literal:
if (!(flags & SUPPRESS))
mbp = va_arg(ap, char *);
n = 0;
- mbs = initial;
+ mbs = initial_mbs;
while ((wi = __fgetwc(fp)) != WEOF &&
width != 0 && INCCL(wi)) {
if (width >= MB_CUR_MAX &&
@@ -501,7 +502,7 @@ literal:
} else {
if (!(flags & SUPPRESS))
mbp = va_arg(ap, char *);
- mbs = initial;
+ mbs = initial_mbs;
while ((wi = __fgetwc(fp)) != WEOF &&
width != 0 &&
!iswspace(wi)) {
@@ -721,16 +722,23 @@ match_failure:
static int
parsefloat(FILE *fp, wchar_t *buf, wchar_t *end)
{
+ mbstate_t mbs;
+ size_t nconv;
wchar_t *commit, *p;
int infnanpos = 0;
enum {
- S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
+ S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX,
S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
} state = S_START;
wchar_t c;
- wchar_t decpt = (wchar_t)(unsigned char)*localeconv()->decimal_point;
+ wchar_t decpt;
_Bool gotmantdig = 0, ishex = 0;
+ mbs = initial_mbs;
+ nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs);
+ if (nconv == (size_t)-1 || nconv == (size_t)-2)
+ decpt = '.'; /* failsafe */
+
/*
* We set commit = p whenever the string we have read so far
* constitutes a valid representation of a floating point
@@ -783,8 +791,6 @@ reswitch:
break;
case S_NAN:
switch (infnanpos) {
- case -1: /* XXX kludge to deal with nan(...) */
- goto parsedone;
case 0:
if (c != 'A' && c != 'a')
goto parsedone;
@@ -802,13 +808,15 @@ reswitch:
default:
if (c == ')') {
commit = p;
- infnanpos = -2;
+ state = S_DONE;
} else if (!iswalnum(c) && c != '_')
goto parsedone;
break;
}
infnanpos++;
break;
+ case S_DONE:
+ goto parsedone;
case S_MAYBEHEX:
state = S_DIGITS;
if (c == 'X' || c == 'x') {
OpenPOWER on IntegriCloud