[BACK]Return to vfwscanf.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libc / stdio

Annotation of src/lib/libc/stdio/vfwscanf.c, Revision 1.1

1.1     ! christos    1: /*     $NetBSD$        */
        !             2:
        !             3: /*-
        !             4:  * Copyright (c) 1990, 1993
        !             5:  *     The Regents of the University of California.  All rights reserved.
        !             6:  *
        !             7:  * This code is derived from software contributed to Berkeley by
        !             8:  * Chris Torek.
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. All advertising materials mentioning features or use of this software
        !            19:  *    must display the following acknowledgement:
        !            20:  *     This product includes software developed by the University of
        !            21:  *     California, Berkeley and its contributors.
        !            22:  * 4. Neither the name of the University nor the names of its contributors
        !            23:  *    may be used to endorse or promote products derived from this software
        !            24:  *    without specific prior written permission.
        !            25:  *
        !            26:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            27:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            28:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            29:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            30:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            31:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            32:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            33:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            34:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            35:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            36:  * SUCH DAMAGE.
        !            37:  */
        !            38:
        !            39: #include <sys/cdefs.h>
        !            40: #if defined(LIBC_SCCS) && !defined(lint)
        !            41: #if 0
        !            42: static char sccsid[] = "@(#)ftell.c    8.2 (Berkeley) 5/4/95";
        !            43: __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwscanf.c,v 1.12 2004/05/02 20:13:29 obrien Exp $");
        !            44: #else
        !            45: __RCSID("$NetBSD: ftell.c,v 1.15 2003/08/07 16:43:25 agc Exp $");
        !            46: #endif
        !            47: #endif /* LIBC_SCCS and not lint */
        !            48:
        !            49: #include "namespace.h"
        !            50: #include <ctype.h>
        !            51: #include <inttypes.h>
        !            52: #include <stdio.h>
        !            53: #include <stdlib.h>
        !            54: #include <stddef.h>
        !            55: #include <stdarg.h>
        !            56: #include <string.h>
        !            57: #include <limits.h>
        !            58: #include <wchar.h>
        !            59: #include <wctype.h>
        !            60:
        !            61: #include "reentrant.h"
        !            62: #include "local.h"
        !            63:
        !            64: #ifndef NO_FLOATING_POINT
        !            65: #include <locale.h>
        !            66: #endif
        !            67:
        !            68: #define        BUF             513     /* Maximum length of numeric string. */
        !            69:
        !            70: /*
        !            71:  * Flags used during conversion.
        !            72:  */
        !            73: #define        LONG            0x01    /* l: long or double */
        !            74: #define        LONGDBL         0x02    /* L: long double */
        !            75: #define        SHORT           0x04    /* h: short */
        !            76: #define        SUPPRESS        0x08    /* *: suppress assignment */
        !            77: #define        POINTER         0x10    /* p: void * (as hex) */
        !            78: #define        NOSKIP          0x20    /* [ or c: do not skip blanks */
        !            79: #define        LONGLONG        0x400   /* ll: quad_t (+ deprecated q: quad) */
        !            80: #define        INTMAXT         0x800   /* j: intmax_t */
        !            81: #define        PTRDIFFT        0x1000  /* t: ptrdiff_t */
        !            82: #define        SIZET           0x2000  /* z: size_t */
        !            83: #define        SHORTSHORT      0x4000  /* hh: char */
        !            84: #define        UNSIGNED        0x8000  /* %[oupxX] conversions */
        !            85:
        !            86: /*
        !            87:  * The following are used in integral conversions only:
        !            88:  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS
        !            89:  */
        !            90: #define        SIGNOK          0x40    /* +/- is (still) legal */
        !            91: #define        NDIGITS         0x80    /* no digits detected */
        !            92: #define        PFXOK           0x100   /* 0x prefix is (still) legal */
        !            93: #define        NZDIGITS        0x200   /* no zero digits detected */
        !            94: #define        HAVESIGN        0x10000 /* sign detected */
        !            95:
        !            96: /*
        !            97:  * Conversion types.
        !            98:  */
        !            99: #define        CT_CHAR         0       /* %c conversion */
        !           100: #define        CT_CCL          1       /* %[...] conversion */
        !           101: #define        CT_STRING       2       /* %s conversion */
        !           102: #define        CT_INT          3       /* %[dioupxX] conversion */
        !           103: #define        CT_FLOAT        4       /* %[efgEFG] conversion */
        !           104:
        !           105: static int parsefloat(FILE *, wchar_t *, wchar_t *);
        !           106:
        !           107: #define        INCCL(_c)       \
        !           108:        (cclcompl ? (wmemchr(ccls, (_c), (size_t)(ccle - ccls)) == NULL) : \
        !           109:        (wmemchr(ccls, (_c), (size_t)(ccle - ccls)) != NULL))
        !           110:
        !           111: /*
        !           112:  * MT-safe version.
        !           113:  */
        !           114: int
        !           115: vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
        !           116: {
        !           117:        int ret;
        !           118:
        !           119:        FLOCKFILE(fp);
        !           120:        _SET_ORIENTATION(fp, 1);
        !           121:        ret = __vfwscanf_unlocked(fp, fmt, ap);
        !           122:        FUNLOCKFILE(fp);
        !           123:        return (ret);
        !           124: }
        !           125:
        !           126: /*
        !           127:  * Non-MT-safe version.
        !           128:  */
        !           129: int
        !           130: __vfwscanf_unlocked(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
        !           131: {
        !           132:        wint_t c;               /* character from format, or conversion */
        !           133:        size_t width;           /* field width, or 0 */
        !           134:        wchar_t *p;             /* points into all kinds of strings */
        !           135:        int n;                  /* handy integer */
        !           136:        int flags;              /* flags as defined above */
        !           137:        wchar_t *p0;            /* saves original value of p when necessary */
        !           138:        int nassigned;          /* number of fields assigned */
        !           139:        int nconversions;       /* number of conversions */
        !           140:        int nread;              /* number of characters consumed from fp */
        !           141:        int base;               /* base argument to conversion function */
        !           142:        wchar_t buf[BUF];       /* buffer for numeric conversions */
        !           143:        const wchar_t *ccls;    /* character class start */
        !           144:        const wchar_t *ccle;    /* character class end */
        !           145:        int cclcompl;           /* ccl is complemented? */
        !           146:        wint_t wi;              /* handy wint_t */
        !           147:        char *mbp;              /* multibyte string pointer for %c %s %[ */
        !           148:        size_t nconv;           /* number of bytes in mb. conversion */
        !           149:        char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */
        !           150:        static const mbstate_t initial;
        !           151:        mbstate_t mbs;
        !           152:
        !           153:        /* `basefix' is used to avoid `if' tests in the integer scanner */
        !           154:        static short basefix[17] =
        !           155:                { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
        !           156:
        !           157:        nassigned = 0;
        !           158:        nconversions = 0;
        !           159:        nread = 0;
        !           160:        ccls = ccle = NULL;
        !           161:        for (;;) {
        !           162:                c = *fmt++;
        !           163:                if (c == 0)
        !           164:                        return (nassigned);
        !           165:                if (iswspace(c)) {
        !           166:                        while ((c = __fgetwc_unlock(fp)) != WEOF &&
        !           167:                            iswspace(c))
        !           168:                                ;
        !           169:                        if (c != WEOF)
        !           170:                                ungetwc(c, fp);
        !           171:                        continue;
        !           172:                }
        !           173:                if (c != '%')
        !           174:                        goto literal;
        !           175:                width = 0;
        !           176:                flags = 0;
        !           177:                /*
        !           178:                 * switch on the format.  continue if done;
        !           179:                 * break once format type is derived.
        !           180:                 */
        !           181: again:         c = *fmt++;
        !           182:                switch (c) {
        !           183:                case '%':
        !           184: literal:
        !           185:                        if ((wi = __fgetwc_unlock(fp)) == WEOF)
        !           186:                                goto input_failure;
        !           187:                        if (wi != c) {
        !           188:                                ungetwc(wi, fp);
        !           189:                                goto input_failure;
        !           190:                        }
        !           191:                        nread++;
        !           192:                        continue;
        !           193:
        !           194:                case '*':
        !           195:                        flags |= SUPPRESS;
        !           196:                        goto again;
        !           197:                case 'j':
        !           198:                        flags |= INTMAXT;
        !           199:                        goto again;
        !           200:                case 'l':
        !           201:                        if (flags & LONG) {
        !           202:                                flags &= ~LONG;
        !           203:                                flags |= LONGLONG;
        !           204:                        } else
        !           205:                                flags |= LONG;
        !           206:                        goto again;
        !           207:                case 'q':
        !           208:                        flags |= LONGLONG;      /* not quite */
        !           209:                        goto again;
        !           210:                case 't':
        !           211:                        flags |= PTRDIFFT;
        !           212:                        goto again;
        !           213:                case 'z':
        !           214:                        flags |= SIZET;
        !           215:                        goto again;
        !           216:                case 'L':
        !           217:                        flags |= LONGDBL;
        !           218:                        goto again;
        !           219:                case 'h':
        !           220:                        if (flags & SHORT) {
        !           221:                                flags &= ~SHORT;
        !           222:                                flags |= SHORTSHORT;
        !           223:                        } else
        !           224:                                flags |= SHORT;
        !           225:                        goto again;
        !           226:
        !           227:                case '0': case '1': case '2': case '3': case '4':
        !           228:                case '5': case '6': case '7': case '8': case '9':
        !           229:                        width = width * 10 + c - '0';
        !           230:                        goto again;
        !           231:
        !           232:                /*
        !           233:                 * Conversions.
        !           234:                 */
        !           235:                case 'd':
        !           236:                        c = CT_INT;
        !           237:                        base = 10;
        !           238:                        break;
        !           239:
        !           240:                case 'i':
        !           241:                        c = CT_INT;
        !           242:                        base = 0;
        !           243:                        break;
        !           244:
        !           245:                case 'o':
        !           246:                        c = CT_INT;
        !           247:                        flags |= UNSIGNED;
        !           248:                        base = 8;
        !           249:                        break;
        !           250:
        !           251:                case 'u':
        !           252:                        c = CT_INT;
        !           253:                        flags |= UNSIGNED;
        !           254:                        base = 10;
        !           255:                        break;
        !           256:
        !           257:                case 'X':
        !           258:                case 'x':
        !           259:                        flags |= PFXOK; /* enable 0x prefixing */
        !           260:                        c = CT_INT;
        !           261:                        flags |= UNSIGNED;
        !           262:                        base = 16;
        !           263:                        break;
        !           264:
        !           265: #ifndef NO_FLOATING_POINT
        !           266:                case 'A': case 'E': case 'F': case 'G':
        !           267:                case 'a': case 'e': case 'f': case 'g':
        !           268:                        c = CT_FLOAT;
        !           269:                        break;
        !           270: #endif
        !           271:
        !           272:                case 'S':
        !           273:                        flags |= LONG;
        !           274:                        /* FALLTHROUGH */
        !           275:                case 's':
        !           276:                        c = CT_STRING;
        !           277:                        break;
        !           278:
        !           279:                case '[':
        !           280:                        ccls = fmt;
        !           281:                        if (*fmt == '^') {
        !           282:                                cclcompl = 1;
        !           283:                                fmt++;
        !           284:                        } else
        !           285:                                cclcompl = 0;
        !           286:                        if (*fmt == ']')
        !           287:                                fmt++;
        !           288:                        while (*fmt != '\0' && *fmt != ']')
        !           289:                                fmt++;
        !           290:                        ccle = fmt;
        !           291:                        fmt++;
        !           292:                        flags |= NOSKIP;
        !           293:                        c = CT_CCL;
        !           294:                        break;
        !           295:
        !           296:                case 'C':
        !           297:                        flags |= LONG;
        !           298:                        /* FALLTHROUGH */
        !           299:                case 'c':
        !           300:                        flags |= NOSKIP;
        !           301:                        c = CT_CHAR;
        !           302:                        break;
        !           303:
        !           304:                case 'p':       /* pointer format is like hex */
        !           305:                        flags |= POINTER | PFXOK;
        !           306:                        c = CT_INT;             /* assumes sizeof(uintmax_t) */
        !           307:                        flags |= UNSIGNED;      /*      >= sizeof(uintptr_t) */
        !           308:                        base = 16;
        !           309:                        break;
        !           310:
        !           311:                case 'n':
        !           312:                        nconversions++;
        !           313:                        if (flags & SUPPRESS)   /* ??? */
        !           314:                                continue;
        !           315:                        if (flags & SHORTSHORT)
        !           316:                                *va_arg(ap, char *) = nread;
        !           317:                        else if (flags & SHORT)
        !           318:                                *va_arg(ap, short *) = nread;
        !           319:                        else if (flags & LONG)
        !           320:                                *va_arg(ap, long *) = nread;
        !           321:                        else if (flags & LONGLONG)
        !           322:                                *va_arg(ap, quad_t *) = nread;
        !           323:                        else if (flags & INTMAXT)
        !           324:                                *va_arg(ap, intmax_t *) = nread;
        !           325:                        else if (flags & SIZET)
        !           326:                                *va_arg(ap, size_t *) = nread;
        !           327:                        else if (flags & PTRDIFFT)
        !           328:                                *va_arg(ap, ptrdiff_t *) = nread;
        !           329:                        else
        !           330:                                *va_arg(ap, int *) = nread;
        !           331:                        continue;
        !           332:
        !           333:                default:
        !           334:                        goto match_failure;
        !           335:
        !           336:                /*
        !           337:                 * Disgusting backwards compatibility hack.     XXX
        !           338:                 */
        !           339:                case '\0':      /* compat */
        !           340:                        return (EOF);
        !           341:                }
        !           342:
        !           343:                /*
        !           344:                 * Consume leading white space, except for formats
        !           345:                 * that suppress this.
        !           346:                 */
        !           347:                if ((flags & NOSKIP) == 0) {
        !           348:                        while ((wi = __fgetwc_unlock(fp)) != WEOF && iswspace(wi))
        !           349:                                nread++;
        !           350:                        if (wi == WEOF)
        !           351:                                goto input_failure;
        !           352:                        ungetwc(wi, fp);
        !           353:                }
        !           354:
        !           355:                /*
        !           356:                 * Do the conversion.
        !           357:                 */
        !           358:                switch (c) {
        !           359:
        !           360:                case CT_CHAR:
        !           361:                        /* scan arbitrary characters (sets NOSKIP) */
        !           362:                        if (width == 0)
        !           363:                                width = 1;
        !           364:                        if (flags & LONG) {
        !           365:                                if (!(flags & SUPPRESS))
        !           366:                                        p = va_arg(ap, wchar_t *);
        !           367:                                n = 0;
        !           368:                                while (width-- != 0 &&
        !           369:                                    (wi = __fgetwc_unlock(fp)) != WEOF) {
        !           370:                                        if (!(flags & SUPPRESS))
        !           371:                                                *p++ = (wchar_t)wi;
        !           372:                                        n++;
        !           373:                                }
        !           374:                                if (n == 0)
        !           375:                                        goto input_failure;
        !           376:                                nread += n;
        !           377:                                if (!(flags & SUPPRESS))
        !           378:                                        nassigned++;
        !           379:                        } else {
        !           380:                                if (!(flags & SUPPRESS))
        !           381:                                        mbp = va_arg(ap, char *);
        !           382:                                n = 0;
        !           383:                                mbs = initial;
        !           384:                                while (width != 0 &&
        !           385:                                    (wi = __fgetwc_unlock(fp)) != WEOF) {
        !           386:                                        if (width >= MB_CUR_MAX &&
        !           387:                                            !(flags & SUPPRESS)) {
        !           388:                                                nconv = wcrtomb(mbp, wi, &mbs);
        !           389:                                                if (nconv == (size_t)-1)
        !           390:                                                        goto input_failure;
        !           391:                                        } else {
        !           392:                                                nconv = wcrtomb(mbbuf, wi,
        !           393:                                                    &mbs);
        !           394:                                                if (nconv == (size_t)-1)
        !           395:                                                        goto input_failure;
        !           396:                                                if (nconv > width) {
        !           397:                                                        ungetwc(wi, fp);
        !           398:                                                        break;
        !           399:                                                }
        !           400:                                                if (!(flags & SUPPRESS))
        !           401:                                                        memcpy(mbp, mbbuf,
        !           402:                                                            nconv);
        !           403:                                        }
        !           404:                                        if (!(flags & SUPPRESS))
        !           405:                                                mbp += nconv;
        !           406:                                        width -= nconv;
        !           407:                                        n++;
        !           408:                                }
        !           409:                                if (n == 0)
        !           410:                                        goto input_failure;
        !           411:                                nread += n;
        !           412:                                if (!(flags & SUPPRESS))
        !           413:                                        nassigned++;
        !           414:                        }
        !           415:                        nconversions++;
        !           416:                        break;
        !           417:
        !           418:                case CT_CCL:
        !           419:                        /* scan a (nonempty) character class (sets NOSKIP) */
        !           420:                        if (width == 0)
        !           421:                                width = (size_t)~0;     /* `infinity' */
        !           422:                        /* take only those things in the class */
        !           423:                        if ((flags & SUPPRESS) && (flags & LONG)) {
        !           424:                                n = 0;
        !           425:                                while ((wi = __fgetwc_unlock(fp)) != WEOF &&
        !           426:                                    width-- != 0 && INCCL(wi))
        !           427:                                        n++;
        !           428:                                if (wi != WEOF)
        !           429:                                        ungetwc(wi, fp);
        !           430:                                if (n == 0)
        !           431:                                        goto match_failure;
        !           432:                        } else if (flags & LONG) {
        !           433:                                p0 = p = va_arg(ap, wchar_t *);
        !           434:                                while ((wi = __fgetwc_unlock(fp)) != WEOF &&
        !           435:                                    width-- != 0 && INCCL(wi))
        !           436:                                        *p++ = (wchar_t)wi;
        !           437:                                if (wi != WEOF)
        !           438:                                        ungetwc(wi, fp);
        !           439:                                n = p - p0;
        !           440:                                if (n == 0)
        !           441:                                        goto match_failure;
        !           442:                                *p = 0;
        !           443:                                nassigned++;
        !           444:                        } else {
        !           445:                                if (!(flags & SUPPRESS))
        !           446:                                        mbp = va_arg(ap, char *);
        !           447:                                n = 0;
        !           448:                                mbs = initial;
        !           449:                                while ((wi = __fgetwc_unlock(fp)) != WEOF &&
        !           450:                                    width != 0 && INCCL(wi)) {
        !           451:                                        if (width >= MB_CUR_MAX &&
        !           452:                                           !(flags & SUPPRESS)) {
        !           453:                                                nconv = wcrtomb(mbp, wi, &mbs);
        !           454:                                                if (nconv == (size_t)-1)
        !           455:                                                        goto input_failure;
        !           456:                                        } else {
        !           457:                                                nconv = wcrtomb(mbbuf, wi,
        !           458:                                                    &mbs);
        !           459:                                                if (nconv == (size_t)-1)
        !           460:                                                        goto input_failure;
        !           461:                                                if (nconv > width)
        !           462:                                                        break;
        !           463:                                                if (!(flags & SUPPRESS))
        !           464:                                                        memcpy(mbp, mbbuf,
        !           465:                                                            nconv);
        !           466:                                        }
        !           467:                                        if (!(flags & SUPPRESS))
        !           468:                                                mbp += nconv;
        !           469:                                        width -= nconv;
        !           470:                                        n++;
        !           471:                                }
        !           472:                                if (wi != WEOF)
        !           473:                                        ungetwc(wi, fp);
        !           474:                                if (!(flags & SUPPRESS)) {
        !           475:                                        *mbp = 0;
        !           476:                                        nassigned++;
        !           477:                                }
        !           478:                        }
        !           479:                        nread += n;
        !           480:                        nconversions++;
        !           481:                        break;
        !           482:
        !           483:                case CT_STRING:
        !           484:                        /* like CCL, but zero-length string OK, & no NOSKIP */
        !           485:                        if (width == 0)
        !           486:                                width = (size_t)~0;
        !           487:                        if ((flags & SUPPRESS) && (flags & LONG)) {
        !           488:                                while ((wi = __fgetwc_unlock(fp)) != WEOF &&
        !           489:                                    width-- != 0 &&
        !           490:                                    !iswspace(wi))
        !           491:                                        nread++;
        !           492:                                if (wi != WEOF)
        !           493:                                        ungetwc(wi, fp);
        !           494:                        } else if (flags & LONG) {
        !           495:                                p0 = p = va_arg(ap, wchar_t *);
        !           496:                                while ((wi = __fgetwc_unlock(fp)) != WEOF &&
        !           497:                                    width-- != 0 &&
        !           498:                                    !iswspace(wi)) {
        !           499:                                        *p++ = (wchar_t)wi;
        !           500:                                        nread++;
        !           501:                                }
        !           502:                                if (wi != WEOF)
        !           503:                                        ungetwc(wi, fp);
        !           504:                                *p = '\0';
        !           505:                                nassigned++;
        !           506:                        } else {
        !           507:                                if (!(flags & SUPPRESS))
        !           508:                                        mbp = va_arg(ap, char *);
        !           509:                                mbs = initial;
        !           510:                                while ((wi = __fgetwc_unlock(fp)) != WEOF &&
        !           511:                                    width != 0 &&
        !           512:                                    !iswspace(wi)) {
        !           513:                                        if (width >= MB_CUR_MAX &&
        !           514:                                            !(flags & SUPPRESS)) {
        !           515:                                                nconv = wcrtomb(mbp, wi, &mbs);
        !           516:                                                if (nconv == (size_t)-1)
        !           517:                                                        goto input_failure;
        !           518:                                        } else {
        !           519:                                                nconv = wcrtomb(mbbuf, wi,
        !           520:                                                    &mbs);
        !           521:                                                if (nconv == (size_t)-1)
        !           522:                                                        goto input_failure;
        !           523:                                                if (nconv > width)
        !           524:                                                        break;
        !           525:                                                if (!(flags & SUPPRESS))
        !           526:                                                        memcpy(mbp, mbbuf,
        !           527:                                                            nconv);
        !           528:                                        }
        !           529:                                        if (!(flags & SUPPRESS))
        !           530:                                                mbp += nconv;
        !           531:                                        width -= nconv;
        !           532:                                        nread++;
        !           533:                                }
        !           534:                                if (wi != WEOF)
        !           535:                                        ungetwc(wi, fp);
        !           536:                                if (!(flags & SUPPRESS)) {
        !           537:                                        *mbp = 0;
        !           538:                                        nassigned++;
        !           539:                                }
        !           540:                        }
        !           541:                        nconversions++;
        !           542:                        continue;
        !           543:
        !           544:                case CT_INT:
        !           545:                        /* scan an integer as if by the conversion function */
        !           546:                        if (width == 0 || width > sizeof(buf) /
        !           547:                            sizeof(*buf) - 1)
        !           548:                                width = sizeof(buf) / sizeof(*buf) - 1;
        !           549:                        flags |= SIGNOK | NDIGITS | NZDIGITS;
        !           550:                        for (p = buf; width; width--) {
        !           551:                                c = __fgetwc_unlock(fp);
        !           552:                                /*
        !           553:                                 * Switch on the character; `goto ok'
        !           554:                                 * if we accept it as a part of number.
        !           555:                                 */
        !           556:                                switch (c) {
        !           557:
        !           558:                                /*
        !           559:                                 * The digit 0 is always legal, but is
        !           560:                                 * special.  For %i conversions, if no
        !           561:                                 * digits (zero or nonzero) have been
        !           562:                                 * scanned (only signs), we will have
        !           563:                                 * base==0.  In that case, we should set
        !           564:                                 * it to 8 and enable 0x prefixing.
        !           565:                                 * Also, if we have not scanned zero digits
        !           566:                                 * before this, do not turn off prefixing
        !           567:                                 * (someone else will turn it off if we
        !           568:                                 * have scanned any nonzero digits).
        !           569:                                 */
        !           570:                                case '0':
        !           571:                                        if (base == 0) {
        !           572:                                                base = 8;
        !           573:                                                flags |= PFXOK;
        !           574:                                        }
        !           575:                                        if (flags & NZDIGITS)
        !           576:                                            flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
        !           577:                                        else
        !           578:                                            flags &= ~(SIGNOK|PFXOK|NDIGITS);
        !           579:                                        goto ok;
        !           580:
        !           581:                                /* 1 through 7 always legal */
        !           582:                                case '1': case '2': case '3':
        !           583:                                case '4': case '5': case '6': case '7':
        !           584:                                        base = basefix[base];
        !           585:                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
        !           586:                                        goto ok;
        !           587:
        !           588:                                /* digits 8 and 9 ok iff decimal or hex */
        !           589:                                case '8': case '9':
        !           590:                                        base = basefix[base];
        !           591:                                        if (base <= 8)
        !           592:                                                break;  /* not legal here */
        !           593:                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
        !           594:                                        goto ok;
        !           595:
        !           596:                                /* letters ok iff hex */
        !           597:                                case 'A': case 'B': case 'C':
        !           598:                                case 'D': case 'E': case 'F':
        !           599:                                case 'a': case 'b': case 'c':
        !           600:                                case 'd': case 'e': case 'f':
        !           601:                                        /* no need to fix base here */
        !           602:                                        if (base <= 10)
        !           603:                                                break;  /* not legal here */
        !           604:                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
        !           605:                                        goto ok;
        !           606:
        !           607:                                /* sign ok only as first character */
        !           608:                                case '+': case '-':
        !           609:                                        if (flags & SIGNOK) {
        !           610:                                                flags &= ~SIGNOK;
        !           611:                                                flags |= HAVESIGN;
        !           612:                                                goto ok;
        !           613:                                        }
        !           614:                                        break;
        !           615:
        !           616:                                /*
        !           617:                                 * x ok iff flag still set & 2nd char (or
        !           618:                                 * 3rd char if we have a sign).
        !           619:                                 */
        !           620:                                case 'x': case 'X':
        !           621:                                        if (flags & PFXOK && p ==
        !           622:                                            buf + 1 + !!(flags & HAVESIGN)) {
        !           623:                                                base = 16;      /* if %i */
        !           624:                                                flags &= ~PFXOK;
        !           625:                                                goto ok;
        !           626:                                        }
        !           627:                                        break;
        !           628:                                }
        !           629:
        !           630:                                /*
        !           631:                                 * If we got here, c is not a legal character
        !           632:                                 * for a number.  Stop accumulating digits.
        !           633:                                 */
        !           634:                                if (c != WEOF)
        !           635:                                        ungetwc(c, fp);
        !           636:                                break;
        !           637:                ok:
        !           638:                                /*
        !           639:                                 * c is legal: store it and look at the next.
        !           640:                                 */
        !           641:                                *p++ = (wchar_t)c;
        !           642:                        }
        !           643:                        /*
        !           644:                         * If we had only a sign, it is no good; push
        !           645:                         * back the sign.  If the number ends in `x',
        !           646:                         * it was [sign] '0' 'x', so push back the x
        !           647:                         * and treat it as [sign] '0'.
        !           648:                         */
        !           649:                        if (flags & NDIGITS) {
        !           650:                                if (p > buf)
        !           651:                                        ungetwc(*--p, fp);
        !           652:                                goto match_failure;
        !           653:                        }
        !           654:                        c = p[-1];
        !           655:                        if (c == 'x' || c == 'X') {
        !           656:                                --p;
        !           657:                                ungetwc(c, fp);
        !           658:                        }
        !           659:                        if ((flags & SUPPRESS) == 0) {
        !           660:                                uintmax_t res;
        !           661:
        !           662:                                *p = 0;
        !           663:                                if ((flags & UNSIGNED) == 0)
        !           664:                                    res = wcstoimax(buf, NULL, base);
        !           665:                                else
        !           666:                                    res = wcstoumax(buf, NULL, base);
        !           667:                                if (flags & POINTER)
        !           668:                                        *va_arg(ap, void **) =
        !           669:                                                        (void *)(uintptr_t)res;
        !           670:                                else if (flags & SHORTSHORT)
        !           671:                                        *va_arg(ap, char *) = (char)res;
        !           672:                                else if (flags & SHORT)
        !           673:                                        *va_arg(ap, short *) = (short)res;
        !           674:                                else if (flags & LONG)
        !           675:                                        *va_arg(ap, long *) = (long)res;
        !           676:                                else if (flags & LONGLONG)
        !           677:                                        *va_arg(ap, quad_t *) = res;
        !           678:                                else if (flags & INTMAXT)
        !           679:                                        *va_arg(ap, intmax_t *) = res;
        !           680:                                else if (flags & PTRDIFFT)
        !           681:                                        *va_arg(ap, ptrdiff_t *) = (ptrdiff_t)res;
        !           682:                                else if (flags & SIZET)
        !           683:                                        *va_arg(ap, size_t *) = (size_t)res;
        !           684:                                else
        !           685:                                        *va_arg(ap, int *) = (int)res;
        !           686:                                nassigned++;
        !           687:                        }
        !           688:                        nread += p - buf;
        !           689:                        nconversions++;
        !           690:                        break;
        !           691:
        !           692: #ifndef NO_FLOATING_POINT
        !           693:                case CT_FLOAT:
        !           694:                        /* scan a floating point number as if by strtod */
        !           695:                        if (width == 0 || width > sizeof(buf) /
        !           696:                            sizeof(*buf) - 1)
        !           697:                                width = sizeof(buf) / sizeof(*buf) - 1;
        !           698:                        if ((width = parsefloat(fp, buf, buf + width)) == 0)
        !           699:                                goto match_failure;
        !           700:                        if ((flags & SUPPRESS) == 0) {
        !           701: #ifdef notyet
        !           702:                                if (flags & LONGDBL) {
        !           703:                                        long double res = wcstold(buf, &p);
        !           704:                                        *va_arg(ap, long double *) = res;
        !           705:                                } else
        !           706: #endif
        !           707:                                if (flags & LONG) {
        !           708:                                        double res = wcstod(buf, &p);
        !           709:                                        *va_arg(ap, double *) = res;
        !           710: #ifdef notyet
        !           711:                                } else {
        !           712:                                        float res = wcstof(buf, &p);
        !           713:                                        *va_arg(ap, float *) = res;
        !           714: #endif
        !           715:                                }
        !           716: #ifdef DEBUG
        !           717:                                if (p - buf != width)
        !           718:                                        abort();
        !           719: #endif
        !           720:                                nassigned++;
        !           721:                        }
        !           722:                        nread += width;
        !           723:                        nconversions++;
        !           724:                        break;
        !           725: #endif /* !NO_FLOATING_POINT */
        !           726:                }
        !           727:        }
        !           728: input_failure:
        !           729:        return (nconversions != 0 ? nassigned : EOF);
        !           730: match_failure:
        !           731:        return (nassigned);
        !           732: }
        !           733:
        !           734: #ifndef NO_FLOATING_POINT
        !           735: static int
        !           736: parsefloat(FILE *fp, wchar_t *buf, wchar_t *end)
        !           737: {
        !           738:        wchar_t *commit, *p;
        !           739:        int infnanpos = 0;
        !           740:        enum {
        !           741:                S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
        !           742:                S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
        !           743:        } state = S_START;
        !           744:        wchar_t c;
        !           745:        wchar_t decpt = (wchar_t)(unsigned char)*localeconv()->decimal_point;
        !           746:        int gotmantdig = 0, ishex = 0;
        !           747:
        !           748:        /*
        !           749:         * We set commit = p whenever the string we have read so far
        !           750:         * constitutes a valid representation of a floating point
        !           751:         * number by itself.  At some point, the parse will complete
        !           752:         * or fail, and we will ungetc() back to the last commit point.
        !           753:         * To ensure that the file offset gets updated properly, it is
        !           754:         * always necessary to read at least one character that doesn't
        !           755:         * match; thus, we can't short-circuit "infinity" or "nan(...)".
        !           756:         */
        !           757:        commit = buf - 1;
        !           758:        c = WEOF;
        !           759:        for (p = buf; p < end; ) {
        !           760:                if ((c = __fgetwc_unlock(fp)) == WEOF)
        !           761:                        break;
        !           762: reswitch:
        !           763:                switch (state) {
        !           764:                case S_START:
        !           765:                        state = S_GOTSIGN;
        !           766:                        if (c == '-' || c == '+')
        !           767:                                break;
        !           768:                        else
        !           769:                                goto reswitch;
        !           770:                case S_GOTSIGN:
        !           771:                        switch (c) {
        !           772:                        case '0':
        !           773:                                state = S_MAYBEHEX;
        !           774:                                commit = p;
        !           775:                                break;
        !           776:                        case 'I':
        !           777:                        case 'i':
        !           778:                                state = S_INF;
        !           779:                                break;
        !           780:                        case 'N':
        !           781:                        case 'n':
        !           782:                                state = S_NAN;
        !           783:                                break;
        !           784:                        default:
        !           785:                                state = S_DIGITS;
        !           786:                                goto reswitch;
        !           787:                        }
        !           788:                        break;
        !           789:                case S_INF:
        !           790:                        if (infnanpos > 6 ||
        !           791:                            (c != "nfinity"[infnanpos] &&
        !           792:                             c != "NFINITY"[infnanpos]))
        !           793:                                goto parsedone;
        !           794:                        if (infnanpos == 1 || infnanpos == 6)
        !           795:                                commit = p;     /* inf or infinity */
        !           796:                        infnanpos++;
        !           797:                        break;
        !           798:                case S_NAN:
        !           799:                        switch (infnanpos) {
        !           800:                        case -1:        /* XXX kludge to deal with nan(...) */
        !           801:                                goto parsedone;
        !           802:                        case 0:
        !           803:                                if (c != 'A' && c != 'a')
        !           804:                                        goto parsedone;
        !           805:                                break;
        !           806:                        case 1:
        !           807:                                if (c != 'N' && c != 'n')
        !           808:                                        goto parsedone;
        !           809:                                else
        !           810:                                        commit = p;
        !           811:                                break;
        !           812:                        case 2:
        !           813:                                if (c != '(')
        !           814:                                        goto parsedone;
        !           815:                                break;
        !           816:                        default:
        !           817:                                if (c == ')') {
        !           818:                                        commit = p;
        !           819:                                        infnanpos = -2;
        !           820:                                } else if (!iswalnum(c) && c != '_')
        !           821:                                        goto parsedone;
        !           822:                                break;
        !           823:                        }
        !           824:                        infnanpos++;
        !           825:                        break;
        !           826:                case S_MAYBEHEX:
        !           827:                        state = S_DIGITS;
        !           828:                        if (c == 'X' || c == 'x') {
        !           829:                                ishex = 1;
        !           830:                                break;
        !           831:                        } else {        /* we saw a '0', but no 'x' */
        !           832:                                gotmantdig = 1;
        !           833:                                goto reswitch;
        !           834:                        }
        !           835:                case S_DIGITS:
        !           836:                        if ((ishex && iswxdigit(c)) || iswdigit(c))
        !           837:                                gotmantdig = 1;
        !           838:                        else {
        !           839:                                state = S_FRAC;
        !           840:                                if (c != decpt)
        !           841:                                        goto reswitch;
        !           842:                        }
        !           843:                        if (gotmantdig)
        !           844:                                commit = p;
        !           845:                        break;
        !           846:                case S_FRAC:
        !           847:                        if (((c == 'E' || c == 'e') && !ishex) ||
        !           848:                            ((c == 'P' || c == 'p') && ishex)) {
        !           849:                                if (!gotmantdig)
        !           850:                                        goto parsedone;
        !           851:                                else
        !           852:                                        state = S_EXP;
        !           853:                        } else if ((ishex && iswxdigit(c)) || iswdigit(c)) {
        !           854:                                commit = p;
        !           855:                                gotmantdig = 1;
        !           856:                        } else
        !           857:                                goto parsedone;
        !           858:                        break;
        !           859:                case S_EXP:
        !           860:                        state = S_EXPDIGITS;
        !           861:                        if (c == '-' || c == '+')
        !           862:                                break;
        !           863:                        else
        !           864:                                goto reswitch;
        !           865:                case S_EXPDIGITS:
        !           866:                        if (iswdigit(c))
        !           867:                                commit = p;
        !           868:                        else
        !           869:                                goto parsedone;
        !           870:                        break;
        !           871:                default:
        !           872:                        abort();
        !           873:                }
        !           874:                *p++ = c;
        !           875:                c = WEOF;
        !           876:        }
        !           877:
        !           878: parsedone:
        !           879:        if (c != WEOF)
        !           880:                ungetwc(c, fp);
        !           881:        while (commit < --p)
        !           882:                ungetwc(*p, fp);
        !           883:        *++commit = '\0';
        !           884:        return (commit - buf);
        !           885: }
        !           886: #endif

CVSweb <webmaster@jp.NetBSD.org>