]> git.saurik.com Git - apple/libc.git/blobdiff - stdio/FreeBSD/vfwscanf.c
Libc-825.24.tar.gz
[apple/libc.git] / stdio / FreeBSD / vfwscanf.c
index 79b54692b66ab48cc1c71a076e10093da987a5af..bba07f2735cc72ceb1752514da8513e7a48e8ca4 100644 (file)
@@ -38,6 +38,8 @@ static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93";
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwscanf.c,v 1.17 2009/01/19 06:19:51 das Exp $");
 
 #include <sys/cdefs.h>
 __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwscanf.c,v 1.17 2009/01/19 06:19:51 das Exp $");
 
+#include "xlocale_private.h"
+
 #include "namespace.h"
 #include <ctype.h>
 #include <inttypes.h>
 #include "namespace.h"
 #include <ctype.h>
 #include <inttypes.h>
@@ -96,7 +98,7 @@ __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwscanf.c,v 1.17 2009/01/19 06:19:51 das
 #define        CT_FLOAT        4       /* %[efgEFG] conversion */
 
 #ifndef NO_FLOATING_POINT
 #define        CT_FLOAT        4       /* %[efgEFG] conversion */
 
 #ifndef NO_FLOATING_POINT
-static int parsefloat(FILE *, wchar_t *, wchar_t *);
+static int parsefloat(FILE *, wchar_t **, size_t, locale_t loc);
 #endif
 
 #define        INCCL(_c)       \
 #endif
 
 #define        INCCL(_c)       \
@@ -115,7 +117,21 @@ vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
 
        FLOCKFILE(fp);
        ORIENT(fp, 1);
 
        FLOCKFILE(fp);
        ORIENT(fp, 1);
-       ret = __vfwscanf(fp, fmt, ap);
+       ret = __vfwscanf(fp, __current_locale(), fmt, ap);
+       FUNLOCKFILE(fp);
+       return (ret);
+}
+
+int
+vfwscanf_l(FILE * __restrict fp, locale_t loc, const wchar_t * __restrict fmt,
+    va_list ap)
+{
+       int ret;
+
+       NORMALIZE_LOCALE(loc);
+       FLOCKFILE(fp);
+       ORIENT(fp, 1);
+       ret = __vfwscanf(fp, loc, fmt, ap);
        FUNLOCKFILE(fp);
        return (ret);
 }
        FUNLOCKFILE(fp);
        return (ret);
 }
@@ -123,8 +139,9 @@ vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
 /*
  * Non-MT-safe version.
  */
 /*
  * Non-MT-safe version.
  */
-int
-__vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
+__private_extern__ int
+__vfwscanf(FILE * __restrict fp, locale_t loc, const wchar_t * __restrict fmt,
+    va_list ap)
 {
        wint_t c;               /* character from format, or conversion */
        size_t width;           /* field width, or 0 */
 {
        wint_t c;               /* character from format, or conversion */
        size_t width;           /* field width, or 0 */
@@ -133,7 +150,6 @@ __vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
        int flags;              /* flags as defined above */
        wchar_t *p0;            /* saves original value of p when necessary */
        int nassigned;          /* number of fields assigned */
        int flags;              /* flags as defined above */
        wchar_t *p0;            /* saves original value of p when necessary */
        int nassigned;          /* number of fields assigned */
-       int nconversions;       /* number of conversions */
        int nread;              /* number of characters consumed from fp */
        int base;               /* base argument to conversion function */
        wchar_t buf[BUF];       /* buffer for numeric conversions */
        int nread;              /* number of characters consumed from fp */
        int base;               /* base argument to conversion function */
        wchar_t buf[BUF];       /* buffer for numeric conversions */
@@ -144,30 +160,36 @@ __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 */
        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 */
+       int index;              /* for %index$ */
+       va_list ap_orig;        /* to reset ap to first argument */
        mbstate_t mbs;
        mbstate_t mbs;
+       int mb_cur_max = MB_CUR_MAX_L(loc);
 
        /* `basefix' is used to avoid `if' tests in the integer scanner */
        static short basefix[17] =
                { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
 
        nassigned = 0;
 
        /* `basefix' is used to avoid `if' tests in the integer scanner */
        static short basefix[17] =
                { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
 
        nassigned = 0;
-       nconversions = 0;
        nread = 0;
        ccls = ccle = NULL;
        nread = 0;
        ccls = ccle = NULL;
+       va_copy(ap_orig, ap);
        for (;;) {
                c = *fmt++;
                if (c == 0)
                        return (nassigned);
        for (;;) {
                c = *fmt++;
                if (c == 0)
                        return (nassigned);
-               if (iswspace(c)) {
-                       while ((c = __fgetwc(fp)) != WEOF &&
-                           iswspace(c))
+               if (iswspace_l(c, loc)) {
+                       while ((c = __fgetwc(fp, loc)) != WEOF &&
+                           iswspace_l(c, loc))
                                ;
                        if (c != WEOF)
                                ;
                        if (c != WEOF)
-                               __ungetwc(c, fp);
+                               __ungetwc(c, fp, loc);
                        continue;
                }
                        continue;
                }
-               if (c != '%')
+               if (c != '%') {
+                       if ((wi = __fgetwc(fp, loc)) == WEOF)
+                               goto input_failure;
                        goto literal;
                        goto literal;
+               }
                width = 0;
                flags = 0;
                /*
                width = 0;
                flags = 0;
                /*
@@ -177,16 +199,34 @@ __vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
 again:         c = *fmt++;
                switch (c) {
                case '%':
 again:         c = *fmt++;
                switch (c) {
                case '%':
+               /* Consume leading white space */
+                       for(;;) {
+                               if ((wi = __fgetwc(fp, loc)) == WEOF)
+                                       goto input_failure;
+                               if (!iswspace_l(wi, loc))
+                                       break;
+                               nread++;
+                       }
 literal:
 literal:
-                       if ((wi = __fgetwc(fp)) == WEOF)
-                               goto input_failure;
                        if (wi != c) {
                        if (wi != c) {
-                               __ungetwc(wi, fp);
-                               goto input_failure;
+                               __ungetwc(wi, fp, loc);
+                               goto match_failure;
                        }
                        nread++;
                        continue;
 
                        }
                        nread++;
                        continue;
 
+               case '$':
+                       index = width;
+                       if (index < 1 || index > NL_ARGMAX || fmt[-3] != '%') {
+                               goto input_failure;
+                       }
+                       width = 0;
+                       va_end(ap);
+                       va_copy(ap, ap_orig); /* reset to %1$ */
+                       for (; index > 1; index--) {
+                               va_arg(ap, void*);
+                       }
+                       goto again;
                case '*':
                        flags |= SUPPRESS;
                        goto again;
                case '*':
                        flags |= SUPPRESS;
                        goto again;
@@ -305,27 +345,28 @@ literal:
                        break;
 
                case 'n':
                        break;
 
                case 'n':
-                       nconversions++;
-                       if (flags & SUPPRESS)   /* ??? */
+               {
+                       void *ptr = va_arg(ap, void *);
+                       if ((ptr == NULL) || (flags & SUPPRESS))        /* ??? */
                                continue;
                                continue;
-                       if (flags & SHORTSHORT)
-                               *va_arg(ap, char *) = nread;
+                       else if (flags & SHORTSHORT)
+                               *(char *)ptr = nread;
                        else if (flags & SHORT)
                        else if (flags & SHORT)
-                               *va_arg(ap, short *) = nread;
+                               *(short *)ptr = nread;
                        else if (flags & LONG)
                        else if (flags & LONG)
-                               *va_arg(ap, long *) = nread;
+                               *(long *)ptr = nread;
                        else if (flags & LONGLONG)
                        else if (flags & LONGLONG)
-                               *va_arg(ap, long long *) = nread;
+                               *(long long *)ptr = nread;
                        else if (flags & INTMAXT)
                        else if (flags & INTMAXT)
-                               *va_arg(ap, intmax_t *) = nread;
+                               *(intmax_t *)ptr = nread;
                        else if (flags & SIZET)
                        else if (flags & SIZET)
-                               *va_arg(ap, size_t *) = nread;
+                               *(size_t *)ptr = nread;
                        else if (flags & PTRDIFFT)
                        else if (flags & PTRDIFFT)
-                               *va_arg(ap, ptrdiff_t *) = nread;
+                               *(ptrdiff_t *)ptr = nread;
                        else
                        else
-                               *va_arg(ap, int *) = nread;
+                               *(int *)ptr = nread;
                        continue;
                        continue;
-
+               }
                default:
                        goto match_failure;
 
                default:
                        goto match_failure;
 
@@ -341,11 +382,11 @@ literal:
                 * that suppress this.
                 */
                if ((flags & NOSKIP) == 0) {
                 * that suppress this.
                 */
                if ((flags & NOSKIP) == 0) {
-                       while ((wi = __fgetwc(fp)) != WEOF && iswspace(wi))
+                       while ((wi = __fgetwc(fp, loc)) != WEOF && iswspace_l(wi, loc))
                                nread++;
                        if (wi == WEOF)
                                goto input_failure;
                                nread++;
                        if (wi == WEOF)
                                goto input_failure;
-                       __ungetwc(wi, fp);
+                       __ungetwc(wi, fp, loc);
                }
 
                /*
                }
 
                /*
@@ -362,7 +403,7 @@ literal:
                                        p = va_arg(ap, wchar_t *);
                                n = 0;
                                while (width-- != 0 &&
                                        p = va_arg(ap, wchar_t *);
                                n = 0;
                                while (width-- != 0 &&
-                                   (wi = __fgetwc(fp)) != WEOF) {
+                                   (wi = __fgetwc(fp, loc)) != WEOF) {
                                        if (!(flags & SUPPRESS))
                                                *p++ = (wchar_t)wi;
                                        n++;
                                        if (!(flags & SUPPRESS))
                                                *p++ = (wchar_t)wi;
                                        n++;
@@ -378,19 +419,19 @@ literal:
                                n = 0;
                                mbs = initial_mbs;
                                while (width != 0 &&
                                n = 0;
                                mbs = initial_mbs;
                                while (width != 0 &&
-                                   (wi = __fgetwc(fp)) != WEOF) {
-                                       if (width >= MB_CUR_MAX &&
+                                   (wi = __fgetwc(fp, loc)) != WEOF) {
+                                       if (width >= mb_cur_max &&
                                            !(flags & SUPPRESS)) {
                                            !(flags & SUPPRESS)) {
-                                               nconv = wcrtomb(mbp, wi, &mbs);
+                                               nconv = wcrtomb_l(mbp, wi, &mbs, loc);
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                        } else {
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                        } else {
-                                               nconv = wcrtomb(mbbuf, wi,
-                                                   &mbs);
+                                               nconv = wcrtomb_l(mbbuf, wi,
+                                                   &mbs, loc);
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                                if (nconv > width) {
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                                if (nconv > width) {
-                                                       __ungetwc(wi, fp);
+                                                       __ungetwc(wi, fp, loc);
                                                        break;
                                                }
                                                if (!(flags & SUPPRESS))
                                                        break;
                                                }
                                                if (!(flags & SUPPRESS))
@@ -408,7 +449,6 @@ literal:
                                if (!(flags & SUPPRESS))
                                        nassigned++;
                        }
                                if (!(flags & SUPPRESS))
                                        nassigned++;
                        }
-                       nconversions++;
                        break;
 
                case CT_CCL:
                        break;
 
                case CT_CCL:
@@ -418,20 +458,20 @@ literal:
                        /* take only those things in the class */
                        if ((flags & SUPPRESS) && (flags & LONG)) {
                                n = 0;
                        /* take only those things in the class */
                        if ((flags & SUPPRESS) && (flags & LONG)) {
                                n = 0;
-                               while ((wi = __fgetwc(fp)) != WEOF &&
+                               while ((wi = __fgetwc(fp, loc)) != WEOF &&
                                    width-- != 0 && INCCL(wi))
                                        n++;
                                if (wi != WEOF)
                                    width-- != 0 && INCCL(wi))
                                        n++;
                                if (wi != WEOF)
-                                       __ungetwc(wi, fp);
+                                       __ungetwc(wi, fp, loc);
                                if (n == 0)
                                        goto match_failure;
                        } else if (flags & LONG) {
                                p0 = p = va_arg(ap, wchar_t *);
                                if (n == 0)
                                        goto match_failure;
                        } else if (flags & LONG) {
                                p0 = p = va_arg(ap, wchar_t *);
-                               while ((wi = __fgetwc(fp)) != WEOF &&
+                               while ((wi = __fgetwc(fp, loc)) != WEOF &&
                                    width-- != 0 && INCCL(wi))
                                        *p++ = (wchar_t)wi;
                                if (wi != WEOF)
                                    width-- != 0 && INCCL(wi))
                                        *p++ = (wchar_t)wi;
                                if (wi != WEOF)
-                                       __ungetwc(wi, fp);
+                                       __ungetwc(wi, fp, loc);
                                n = p - p0;
                                if (n == 0)
                                        goto match_failure;
                                n = p - p0;
                                if (n == 0)
                                        goto match_failure;
@@ -442,16 +482,16 @@ literal:
                                        mbp = va_arg(ap, char *);
                                n = 0;
                                mbs = initial_mbs;
                                        mbp = va_arg(ap, char *);
                                n = 0;
                                mbs = initial_mbs;
-                               while ((wi = __fgetwc(fp)) != WEOF &&
+                               while ((wi = __fgetwc(fp, loc)) != WEOF &&
                                    width != 0 && INCCL(wi)) {
                                    width != 0 && INCCL(wi)) {
-                                       if (width >= MB_CUR_MAX &&
+                                       if (width >= mb_cur_max &&
                                           !(flags & SUPPRESS)) {
                                           !(flags & SUPPRESS)) {
-                                               nconv = wcrtomb(mbp, wi, &mbs);
+                                               nconv = wcrtomb_l(mbp, wi, &mbs, loc);
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                        } else {
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                        } else {
-                                               nconv = wcrtomb(mbbuf, wi,
-                                                   &mbs);
+                                               nconv = wcrtomb_l(mbbuf, wi,
+                                                   &mbs, loc);
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                                if (nconv > width)
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                                if (nconv > width)
@@ -466,14 +506,15 @@ literal:
                                        n++;
                                }
                                if (wi != WEOF)
                                        n++;
                                }
                                if (wi != WEOF)
-                                       __ungetwc(wi, fp);
+                                       __ungetwc(wi, fp, loc);
+                               if (n == 0)
+                                       goto match_failure;
                                if (!(flags & SUPPRESS)) {
                                        *mbp = 0;
                                        nassigned++;
                                }
                        }
                        nread += n;
                                if (!(flags & SUPPRESS)) {
                                        *mbp = 0;
                                        nassigned++;
                                }
                        }
                        nread += n;
-                       nconversions++;
                        break;
 
                case CT_STRING:
                        break;
 
                case CT_STRING:
@@ -481,39 +522,39 @@ literal:
                        if (width == 0)
                                width = (size_t)~0;
                        if ((flags & SUPPRESS) && (flags & LONG)) {
                        if (width == 0)
                                width = (size_t)~0;
                        if ((flags & SUPPRESS) && (flags & LONG)) {
-                               while ((wi = __fgetwc(fp)) != WEOF &&
+                               while ((wi = __fgetwc(fp, loc)) != WEOF &&
                                    width-- != 0 &&
                                    width-- != 0 &&
-                                   !iswspace(wi))
+                                   !iswspace_l(wi, loc))
                                        nread++;
                                if (wi != WEOF)
                                        nread++;
                                if (wi != WEOF)
-                                       __ungetwc(wi, fp);
+                                       __ungetwc(wi, fp, loc);
                        } else if (flags & LONG) {
                                p0 = p = va_arg(ap, wchar_t *);
                        } else if (flags & LONG) {
                                p0 = p = va_arg(ap, wchar_t *);
-                               while ((wi = __fgetwc(fp)) != WEOF &&
+                               while ((wi = __fgetwc(fp, loc)) != WEOF &&
                                    width-- != 0 &&
                                    width-- != 0 &&
-                                   !iswspace(wi)) {
+                                   !iswspace_l(wi, loc)) {
                                        *p++ = (wchar_t)wi;
                                        nread++;
                                }
                                if (wi != WEOF)
                                        *p++ = (wchar_t)wi;
                                        nread++;
                                }
                                if (wi != WEOF)
-                                       __ungetwc(wi, fp);
+                                       __ungetwc(wi, fp, loc);
                                *p = '\0';
                                nassigned++;
                        } else {
                                if (!(flags & SUPPRESS))
                                        mbp = va_arg(ap, char *);
                                mbs = initial_mbs;
                                *p = '\0';
                                nassigned++;
                        } else {
                                if (!(flags & SUPPRESS))
                                        mbp = va_arg(ap, char *);
                                mbs = initial_mbs;
-                               while ((wi = __fgetwc(fp)) != WEOF &&
+                               while ((wi = __fgetwc(fp, loc)) != WEOF &&
                                    width != 0 &&
                                    width != 0 &&
-                                   !iswspace(wi)) {
-                                       if (width >= MB_CUR_MAX &&
+                                   !iswspace_l(wi, loc)) {
+                                       if (width >= mb_cur_max &&
                                            !(flags & SUPPRESS)) {
                                            !(flags & SUPPRESS)) {
-                                               nconv = wcrtomb(mbp, wi, &mbs);
+                                               nconv = wcrtomb_l(mbp, wi, &mbs, loc);
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                        } else {
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                        } else {
-                                               nconv = wcrtomb(mbbuf, wi,
-                                                   &mbs);
+                                               nconv = wcrtomb_l(mbbuf, wi,
+                                                   &mbs, loc);
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                                if (nconv > width)
                                                if (nconv == (size_t)-1)
                                                        goto input_failure;
                                                if (nconv > width)
@@ -528,13 +569,12 @@ literal:
                                        nread++;
                                }
                                if (wi != WEOF)
                                        nread++;
                                }
                                if (wi != WEOF)
-                                       __ungetwc(wi, fp);
+                                       __ungetwc(wi, fp, loc);
                                if (!(flags & SUPPRESS)) {
                                        *mbp = 0;
                                        nassigned++;
                                }
                        }
                                if (!(flags & SUPPRESS)) {
                                        *mbp = 0;
                                        nassigned++;
                                }
                        }
-                       nconversions++;
                        continue;
 
                case CT_INT:
                        continue;
 
                case CT_INT:
@@ -544,7 +584,7 @@ literal:
                                width = sizeof(buf) / sizeof(*buf) - 1;
                        flags |= SIGNOK | NDIGITS | NZDIGITS;
                        for (p = buf; width; width--) {
                                width = sizeof(buf) / sizeof(*buf) - 1;
                        flags |= SIGNOK | NDIGITS | NZDIGITS;
                        for (p = buf; width; width--) {
-                               c = __fgetwc(fp);
+                               c = __fgetwc(fp, loc);
                                /*
                                 * Switch on the character; `goto ok'
                                 * if we accept it as a part of number.
                                /*
                                 * Switch on the character; `goto ok'
                                 * if we accept it as a part of number.
@@ -628,7 +668,7 @@ literal:
                                 * for a number.  Stop accumulating digits.
                                 */
                                if (c != WEOF)
                                 * for a number.  Stop accumulating digits.
                                 */
                                if (c != WEOF)
-                                       __ungetwc(c, fp);
+                                       __ungetwc(c, fp, loc);
                                break;
                ok:
                                /*
                                break;
                ok:
                                /*
@@ -644,22 +684,22 @@ literal:
                         */
                        if (flags & NDIGITS) {
                                if (p > buf)
                         */
                        if (flags & NDIGITS) {
                                if (p > buf)
-                                       __ungetwc(*--p, fp);
+                                       __ungetwc(*--p, fp, loc);
                                goto match_failure;
                        }
                        c = p[-1];
                        if (c == 'x' || c == 'X') {
                                --p;
                                goto match_failure;
                        }
                        c = p[-1];
                        if (c == 'x' || c == 'X') {
                                --p;
-                               __ungetwc(c, fp);
+                               __ungetwc(c, fp, loc);
                        }
                        if ((flags & SUPPRESS) == 0) {
                                uintmax_t res;
 
                                *p = 0;
                                if ((flags & UNSIGNED) == 0)
                        }
                        if ((flags & SUPPRESS) == 0) {
                                uintmax_t res;
 
                                *p = 0;
                                if ((flags & UNSIGNED) == 0)
-                                   res = wcstoimax(buf, NULL, base);
+                                   res = wcstoimax_l(buf, NULL, base, loc);
                                else
                                else
-                                   res = wcstoumax(buf, NULL, base);
+                                   res = wcstoumax_l(buf, NULL, base, loc);
                                if (flags & POINTER)
                                        *va_arg(ap, void **) =
                                                        (void *)(uintptr_t)res;
                                if (flags & POINTER)
                                        *va_arg(ap, void **) =
                                                        (void *)(uintptr_t)res;
@@ -682,45 +722,45 @@ literal:
                                nassigned++;
                        }
                        nread += p - buf;
                                nassigned++;
                        }
                        nread += p - buf;
-                       nconversions++;
                        break;
 
 #ifndef NO_FLOATING_POINT
                case CT_FLOAT:
                        break;
 
 #ifndef NO_FLOATING_POINT
                case CT_FLOAT:
+               {
+                       wchar_t *pbuf;
                        /* scan a floating point number as if by strtod */
                        /* scan a floating point number as if by strtod */
-                       if (width == 0 || width > sizeof(buf) /
-                           sizeof(*buf) - 1)
-                               width = sizeof(buf) / sizeof(*buf) - 1;
-                       if ((width = parsefloat(fp, buf, buf + width)) == 0)
+                       if ((width = parsefloat(fp, &pbuf, width, loc)) == 0)
                                goto match_failure;
                        if ((flags & SUPPRESS) == 0) {
                                if (flags & LONGDBL) {
                                goto match_failure;
                        if ((flags & SUPPRESS) == 0) {
                                if (flags & LONGDBL) {
-                                       long double res = wcstold(buf, &p);
+                                       long double res = wcstold_l(pbuf, &p, loc);
                                        *va_arg(ap, long double *) = res;
                                } else if (flags & LONG) {
                                        *va_arg(ap, long double *) = res;
                                } else if (flags & LONG) {
-                                       double res = wcstod(buf, &p);
+                                       double res = wcstod_l(pbuf, &p, loc);
                                        *va_arg(ap, double *) = res;
                                } else {
                                        *va_arg(ap, double *) = res;
                                } else {
-                                       float res = wcstof(buf, &p);
+                                       float res = wcstof_l(pbuf, &p, loc);
                                        *va_arg(ap, float *) = res;
                                }
                                nassigned++;
                        }
                        nread += width;
                                        *va_arg(ap, float *) = res;
                                }
                                nassigned++;
                        }
                        nread += width;
-                       nconversions++;
                        break;
                        break;
+               }
 #endif /* !NO_FLOATING_POINT */
                }
        }
 input_failure:
 #endif /* !NO_FLOATING_POINT */
                }
        }
 input_failure:
-       return (nconversions != 0 ? nassigned : EOF);
+       return (nassigned ? nassigned : EOF);
 match_failure:
        return (nassigned);
 }
 
 #ifndef NO_FLOATING_POINT
 match_failure:
        return (nassigned);
 }
 
 #ifndef NO_FLOATING_POINT
+extern char *__parsefloat_buf(size_t s);  /* see vfscanf-fbsd.c */
+
 static int
 static int
-parsefloat(FILE *fp, wchar_t *buf, wchar_t *end)
+parsefloat(FILE *fp, wchar_t **buf, size_t width, locale_t loc)
 {
        mbstate_t mbs;
        size_t nconv;
 {
        mbstate_t mbs;
        size_t nconv;
@@ -733,12 +773,22 @@ parsefloat(FILE *fp, wchar_t *buf, wchar_t *end)
        wchar_t c;
        wchar_t decpt;
        _Bool gotmantdig = 0, ishex = 0;
        wchar_t c;
        wchar_t decpt;
        _Bool gotmantdig = 0, ishex = 0;
+       wchar_t *b;
+       wchar_t *e;
+       size_t s;
 
        mbs = initial_mbs;
 
        mbs = initial_mbs;
-       nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs);
+
+       nconv = mbrtowc_l(&decpt, localeconv()->decimal_point, MB_CUR_MAX_L(loc), &mbs, loc);
        if (nconv == (size_t)-1 || nconv == (size_t)-2)
        if (nconv == (size_t)-1 || nconv == (size_t)-2)
-               decpt = '.';    /* failsafe */
+               decpt = '.';    /* failsafe */
 
 
+       s = (width == 0 ? BUF : (width + 1));
+       if ((b = (wchar_t *)__parsefloat_buf(s * sizeof(wchar_t))) == NULL) {
+               *buf = NULL;
+               return 0;
+       }
+       e = b + (s - 1);
        /*
         * We set commit = p whenever the string we have read so far
         * constitutes a valid representation of a floating point
        /*
         * We set commit = p whenever the string we have read so far
         * constitutes a valid representation of a floating point
@@ -748,10 +798,10 @@ parsefloat(FILE *fp, wchar_t *buf, wchar_t *end)
         * always necessary to read at least one character that doesn't
         * match; thus, we can't short-circuit "infinity" or "nan(...)".
         */
         * always necessary to read at least one character that doesn't
         * match; thus, we can't short-circuit "infinity" or "nan(...)".
         */
-       commit = buf - 1;
+       commit = b - 1;
        c = WEOF;
        c = WEOF;
-       for (p = buf; p < end; ) {
-               if ((c = __fgetwc(fp)) == WEOF)
+       for (p = b; width == 0 || p < e; ) {
+               if ((c = __fgetwc(fp, loc)) == WEOF)
                        break;
 reswitch:
                switch (state) {
                        break;
 reswitch:
                switch (state) {
@@ -809,7 +859,7 @@ reswitch:
                                if (c == ')') {
                                        commit = p;
                                        state = S_DONE;
                                if (c == ')') {
                                        commit = p;
                                        state = S_DONE;
-                               } else if (!iswalnum(c) && c != '_')
+                               } else if (!iswalnum_l(c, loc) && c != '_')
                                        goto parsedone;
                                break;
                        }
                                        goto parsedone;
                                break;
                        }
@@ -827,7 +877,7 @@ reswitch:
                                goto reswitch;
                        }
                case S_DIGITS:
                                goto reswitch;
                        }
                case S_DIGITS:
-                       if ((ishex && iswxdigit(c)) || iswdigit(c))
+                       if ((ishex && iswxdigit_l(c, loc)) || iswdigit_l(c, loc))
                                gotmantdig = 1;
                        else {
                                state = S_FRAC;
                                gotmantdig = 1;
                        else {
                                state = S_FRAC;
@@ -844,7 +894,7 @@ reswitch:
                                        goto parsedone;
                                else
                                        state = S_EXP;
                                        goto parsedone;
                                else
                                        state = S_EXP;
-                       } else if ((ishex && iswxdigit(c)) || iswdigit(c)) {
+                       } else if ((ishex && iswxdigit_l(c, loc)) || iswdigit_l(c, loc)) {
                                commit = p;
                                gotmantdig = 1;
                        } else
                                commit = p;
                                gotmantdig = 1;
                        } else
@@ -857,13 +907,26 @@ reswitch:
                        else
                                goto reswitch;
                case S_EXPDIGITS:
                        else
                                goto reswitch;
                case S_EXPDIGITS:
-                       if (iswdigit(c))
+                       if (iswdigit_l(c, loc))
                                commit = p;
                        else
                                goto parsedone;
                        break;
                default:
                                commit = p;
                        else
                                goto parsedone;
                        break;
                default:
-                       abort();
+                       LIBC_ABORT("unknown state %d", state);
+               }
+               if (p >= e) {
+                       ssize_t diff = (p - b);
+                       ssize_t com = (commit - b);
+                       s += BUF;
+                       b = (wchar_t *)__parsefloat_buf(s * sizeof(wchar_t));
+                       if (b == NULL) {
+                               *buf = NULL;
+                               return 0;
+                       }
+                       e = b + (s - 1);
+                       p = b + diff;
+                       commit = b + com;
                }
                *p++ = c;
                c = WEOF;
                }
                *p++ = c;
                c = WEOF;
@@ -871,10 +934,11 @@ reswitch:
 
 parsedone:
        if (c != WEOF)
 
 parsedone:
        if (c != WEOF)
-               __ungetwc(c, fp);
+               __ungetwc(c, fp, loc);
        while (commit < --p)
        while (commit < --p)
-               __ungetwc(*p, fp);
+               __ungetwc(*p, fp, loc);
        *++commit = '\0';
        *++commit = '\0';
-       return (commit - buf);
+       *buf = b;
+       return (commit - b);
 }
 #endif
 }
 #endif