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

Annotation of src/lib/libc/stdio/vfscanf.c, Revision 1.24

1.24    ! lukem       1: /*     $NetBSD: vfscanf.c,v 1.23 1999/09/16 11:45:31 lukem Exp $       */
1.12      jtc         2:
1.1       cgd         3: /*-
1.12      jtc         4:  * Copyright (c) 1990, 1993
                      5:  *     The Regents of the University of California.  All rights reserved.
1.1       cgd         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:
1.16      christos   39: #include <sys/cdefs.h>
1.1       cgd        40: #if defined(LIBC_SCCS) && !defined(lint)
1.12      jtc        41: #if 0
                     42: static char sccsid[] = "@(#)vfscanf.c  8.1 (Berkeley) 6/4/93";
1.16      christos   43: #else
1.24    ! lukem      44: __RCSID("$NetBSD: vfscanf.c,v 1.23 1999/09/16 11:45:31 lukem Exp $");
1.12      jtc        45: #endif
1.1       cgd        46: #endif /* LIBC_SCCS and not lint */
                     47:
1.16      christos   48: #include "namespace.h"
1.23      lukem      49:
                     50: #include <assert.h>
                     51: #include <errno.h>
1.1       cgd        52: #include <stdio.h>
                     53: #include <stdlib.h>
                     54: #include <ctype.h>
                     55: #if __STDC__
                     56: #include <stdarg.h>
                     57: #else
                     58: #include <varargs.h>
                     59: #endif
1.23      lukem      60:
1.1       cgd        61: #include "local.h"
                     62:
1.8       mycroft    63: #ifdef FLOATING_POINT
                     64: #include "floatio.h"
                     65: #endif
1.1       cgd        66:
1.3       cgd        67: #define        BUF             513     /* Maximum length of numeric string. */
1.1       cgd        68:
                     69: /*
                     70:  * Flags used during conversion.
                     71:  */
                     72: #define        LONG            0x01    /* l: long or double */
                     73: #define        LONGDBL         0x02    /* L: long double; unimplemented */
                     74: #define        SHORT           0x04    /* h: short */
1.10      jtc        75: #define QUAD           0x08    /* q: quad */
                     76: #define        SUPPRESS        0x10    /* suppress assignment */
                     77: #define        POINTER         0x20    /* weird %p pointer (`fake hex') */
                     78: #define        NOSKIP          0x40    /* do not skip blanks */
1.1       cgd        79:
                     80: /*
                     81:  * The following are used in numeric conversions only:
                     82:  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
                     83:  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
                     84:  */
1.10      jtc        85: #define        SIGNOK          0x080   /* +/- is (still) legal */
                     86: #define        NDIGITS         0x100   /* no digits detected */
1.1       cgd        87:
1.10      jtc        88: #define        DPTOK           0x200   /* (float) decimal point is still legal */
                     89: #define        EXPOK           0x400   /* (float) exponent (e+3, etc) still legal */
1.1       cgd        90:
1.10      jtc        91: #define        PFXOK           0x200   /* 0x prefix is (still) legal */
                     92: #define        NZDIGITS        0x400   /* no zero digits detected */
1.1       cgd        93:
                     94: /*
                     95:  * Conversion types.
                     96:  */
                     97: #define        CT_CHAR         0       /* %c conversion */
                     98: #define        CT_CCL          1       /* %[...] conversion */
                     99: #define        CT_STRING       2       /* %s conversion */
1.10      jtc       100: #define        CT_INT          3       /* integer, i.e., strtoq or strtouq */
1.1       cgd       101: #define        CT_FLOAT        4       /* floating, i.e., strtod */
                    102:
                    103: #define u_char unsigned char
                    104: #define u_long unsigned long
                    105:
1.20      mycroft   106: static const u_char *__sccl __P((char *, const u_char *));
1.1       cgd       107:
                    108: /*
                    109:  * vfscanf
                    110:  */
1.15      jtc       111: int
1.1       cgd       112: __svfscanf(fp, fmt0, ap)
1.18      perry     113:        FILE *fp;
1.20      mycroft   114:        const char *fmt0;
1.7       cgd       115:        _BSD_VA_LIST_ ap;
1.1       cgd       116: {
1.22      christos  117:        const u_char *fmt = (const u_char *)fmt0;
1.18      perry     118:        int c;          /* character from format, or conversion */
                    119:        size_t width;   /* field width, or 0 */
                    120:        char *p;        /* points into all kinds of strings */
                    121:        int n;          /* handy integer */
                    122:        int flags;      /* flags as defined above */
                    123:        char *p0;       /* saves original value of p when necessary */
1.1       cgd       124:        int nassigned;          /* number of fields assigned */
                    125:        int nread;              /* number of characters consumed from fp */
1.10      jtc       126:        int base;               /* base argument to strtoq/strtouq */
1.16      christos  127:        u_quad_t (*ccfn) __P((const char *, char **, int));
                    128:                                /* conversion function (strtoq/strtouq) */
1.1       cgd       129:        char ccltab[256];       /* character class table for %[...] */
                    130:        char buf[BUF];          /* buffer for numeric conversions */
                    131:
                    132:        /* `basefix' is used to avoid `if' tests in the integer scanner */
1.19      mycroft   133:        static const short basefix[17] =
1.1       cgd       134:                { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
                    135:
1.23      lukem     136:        _DIAGASSERT(fp != NULL);
                    137:        _DIAGASSERT(fmt0 != NULL);
                    138:
1.1       cgd       139:        nassigned = 0;
                    140:        nread = 0;
                    141:        base = 0;               /* XXX just to keep gcc happy */
                    142:        ccfn = NULL;            /* XXX just to keep gcc happy */
                    143:        for (;;) {
                    144:                c = *fmt++;
                    145:                if (c == 0)
                    146:                        return (nassigned);
                    147:                if (isspace(c)) {
1.21      kleink    148:                        while ((fp->_r > 0 || __srefill(fp) == 0) &&
                    149:                            isspace(*fp->_p))
1.1       cgd       150:                                nread++, fp->_r--, fp->_p++;
                    151:                        continue;
                    152:                }
                    153:                if (c != '%')
                    154:                        goto literal;
                    155:                width = 0;
                    156:                flags = 0;
                    157:                /*
                    158:                 * switch on the format.  continue if done;
                    159:                 * break once format type is derived.
                    160:                 */
                    161: again:         c = *fmt++;
                    162:                switch (c) {
                    163:                case '%':
                    164: literal:
                    165:                        if (fp->_r <= 0 && __srefill(fp))
                    166:                                goto input_failure;
                    167:                        if (*fp->_p != c)
                    168:                                goto match_failure;
                    169:                        fp->_r--, fp->_p++;
                    170:                        nread++;
                    171:                        continue;
                    172:
                    173:                case '*':
                    174:                        flags |= SUPPRESS;
                    175:                        goto again;
                    176:                case 'L':
                    177:                        flags |= LONGDBL;
                    178:                        goto again;
                    179:                case 'h':
                    180:                        flags |= SHORT;
                    181:                        goto again;
1.10      jtc       182:                case 'l':
1.14      jtc       183:                        if (*fmt == 'l') {
                    184:                                fmt++;
                    185:                                flags |= QUAD;
                    186:                        } else {
                    187:                                flags |= LONG;
                    188:                        }
1.10      jtc       189:                        goto again;
                    190:                case 'q':
                    191:                        flags |= QUAD;
                    192:                        goto again;
1.1       cgd       193:
                    194:                case '0': case '1': case '2': case '3': case '4':
                    195:                case '5': case '6': case '7': case '8': case '9':
                    196:                        width = width * 10 + c - '0';
                    197:                        goto again;
                    198:
                    199:                /*
                    200:                 * Conversions.
                    201:                 * Those marked `compat' are for 4.[123]BSD compatibility.
                    202:                 *
                    203:                 * (According to ANSI, E and X formats are supposed
                    204:                 * to the same as e and x.  Sorry about that.)
                    205:                 */
                    206:                case 'D':       /* compat */
                    207:                        flags |= LONG;
                    208:                        /* FALLTHROUGH */
                    209:                case 'd':
                    210:                        c = CT_INT;
1.16      christos  211:                        ccfn = (u_quad_t (*) __P((const char *, char **, int)))strtoq;
1.1       cgd       212:                        base = 10;
                    213:                        break;
                    214:
                    215:                case 'i':
                    216:                        c = CT_INT;
1.16      christos  217:                        ccfn = (u_quad_t (*) __P((const char *, char **, int)))strtoq;
1.1       cgd       218:                        base = 0;
                    219:                        break;
                    220:
                    221:                case 'O':       /* compat */
                    222:                        flags |= LONG;
                    223:                        /* FALLTHROUGH */
                    224:                case 'o':
                    225:                        c = CT_INT;
1.10      jtc       226:                        ccfn = strtouq;
1.1       cgd       227:                        base = 8;
                    228:                        break;
                    229:
                    230:                case 'u':
                    231:                        c = CT_INT;
1.10      jtc       232:                        ccfn = strtouq;
1.1       cgd       233:                        base = 10;
                    234:                        break;
                    235:
1.9       jtc       236:                case 'X':
1.1       cgd       237:                case 'x':
                    238:                        flags |= PFXOK; /* enable 0x prefixing */
                    239:                        c = CT_INT;
1.10      jtc       240:                        ccfn = strtouq;
1.1       cgd       241:                        base = 16;
                    242:                        break;
                    243:
                    244: #ifdef FLOATING_POINT
1.9       jtc       245:                case 'E':
                    246:                case 'G':
                    247:                case 'e':
1.10      jtc       248:                case 'f':
1.9       jtc       249:                case 'g':
1.1       cgd       250:                        c = CT_FLOAT;
                    251:                        break;
                    252: #endif
                    253:
                    254:                case 's':
                    255:                        c = CT_STRING;
                    256:                        break;
                    257:
                    258:                case '[':
                    259:                        fmt = __sccl(ccltab, fmt);
                    260:                        flags |= NOSKIP;
                    261:                        c = CT_CCL;
                    262:                        break;
                    263:
                    264:                case 'c':
                    265:                        flags |= NOSKIP;
                    266:                        c = CT_CHAR;
                    267:                        break;
                    268:
                    269:                case 'p':       /* pointer format is like hex */
                    270:                        flags |= POINTER | PFXOK;
                    271:                        c = CT_INT;
1.10      jtc       272:                        ccfn = strtouq;
1.1       cgd       273:                        base = 16;
                    274:                        break;
                    275:
                    276:                case 'n':
                    277:                        if (flags & SUPPRESS)   /* ??? */
                    278:                                continue;
                    279:                        if (flags & SHORT)
                    280:                                *va_arg(ap, short *) = nread;
                    281:                        else if (flags & LONG)
                    282:                                *va_arg(ap, long *) = nread;
                    283:                        else
                    284:                                *va_arg(ap, int *) = nread;
                    285:                        continue;
                    286:
                    287:                /*
                    288:                 * Disgusting backwards compatibility hacks.    XXX
                    289:                 */
                    290:                case '\0':      /* compat */
                    291:                        return (EOF);
                    292:
                    293:                default:        /* compat */
                    294:                        if (isupper(c))
                    295:                                flags |= LONG;
                    296:                        c = CT_INT;
1.16      christos  297:                        ccfn = (u_quad_t (*) __P((const char *, char **, int)))strtoq;
1.1       cgd       298:                        base = 10;
                    299:                        break;
                    300:                }
                    301:
                    302:                /*
                    303:                 * We have a conversion that requires input.
                    304:                 */
                    305:                if (fp->_r <= 0 && __srefill(fp))
                    306:                        goto input_failure;
                    307:
                    308:                /*
                    309:                 * Consume leading white space, except for formats
                    310:                 * that suppress this.
                    311:                 */
                    312:                if ((flags & NOSKIP) == 0) {
                    313:                        while (isspace(*fp->_p)) {
                    314:                                nread++;
                    315:                                if (--fp->_r > 0)
                    316:                                        fp->_p++;
                    317:                                else if (__srefill(fp))
                    318:                                        goto input_failure;
                    319:                        }
                    320:                        /*
                    321:                         * Note that there is at least one character in
                    322:                         * the buffer, so conversions that do not set NOSKIP
                    323:                         * ca no longer result in an input failure.
                    324:                         */
                    325:                }
                    326:
                    327:                /*
                    328:                 * Do the conversion.
                    329:                 */
                    330:                switch (c) {
                    331:
                    332:                case CT_CHAR:
                    333:                        /* scan arbitrary characters (sets NOSKIP) */
                    334:                        if (width == 0)
                    335:                                width = 1;
                    336:                        if (flags & SUPPRESS) {
                    337:                                size_t sum = 0;
                    338:                                for (;;) {
                    339:                                        if ((n = fp->_r) < width) {
                    340:                                                sum += n;
                    341:                                                width -= n;
                    342:                                                fp->_p += n;
                    343:                                                if (__srefill(fp)) {
                    344:                                                        if (sum == 0)
                    345:                                                            goto input_failure;
                    346:                                                        break;
                    347:                                                }
                    348:                                        } else {
                    349:                                                sum += width;
                    350:                                                fp->_r -= width;
                    351:                                                fp->_p += width;
                    352:                                                break;
                    353:                                        }
                    354:                                }
                    355:                                nread += sum;
                    356:                        } else {
                    357:                                size_t r = fread((void *)va_arg(ap, char *), 1,
                    358:                                    width, fp);
                    359:
                    360:                                if (r == 0)
                    361:                                        goto input_failure;
                    362:                                nread += r;
                    363:                                nassigned++;
                    364:                        }
                    365:                        break;
                    366:
                    367:                case CT_CCL:
                    368:                        /* scan a (nonempty) character class (sets NOSKIP) */
                    369:                        if (width == 0)
1.20      mycroft   370:                                width = ~0U;    /* `infinity' */
1.1       cgd       371:                        /* take only those things in the class */
                    372:                        if (flags & SUPPRESS) {
                    373:                                n = 0;
                    374:                                while (ccltab[*fp->_p]) {
                    375:                                        n++, fp->_r--, fp->_p++;
                    376:                                        if (--width == 0)
                    377:                                                break;
                    378:                                        if (fp->_r <= 0 && __srefill(fp)) {
                    379:                                                if (n == 0)
                    380:                                                        goto input_failure;
                    381:                                                break;
                    382:                                        }
                    383:                                }
                    384:                                if (n == 0)
                    385:                                        goto match_failure;
                    386:                        } else {
                    387:                                p0 = p = va_arg(ap, char *);
                    388:                                while (ccltab[*fp->_p]) {
                    389:                                        fp->_r--;
                    390:                                        *p++ = *fp->_p++;
                    391:                                        if (--width == 0)
                    392:                                                break;
                    393:                                        if (fp->_r <= 0 && __srefill(fp)) {
                    394:                                                if (p == p0)
                    395:                                                        goto input_failure;
                    396:                                                break;
                    397:                                        }
                    398:                                }
                    399:                                n = p - p0;
                    400:                                if (n == 0)
                    401:                                        goto match_failure;
                    402:                                *p = 0;
                    403:                                nassigned++;
                    404:                        }
                    405:                        nread += n;
                    406:                        break;
                    407:
                    408:                case CT_STRING:
                    409:                        /* like CCL, but zero-length string OK, & no NOSKIP */
                    410:                        if (width == 0)
1.20      mycroft   411:                                width = ~0U;
1.1       cgd       412:                        if (flags & SUPPRESS) {
                    413:                                n = 0;
                    414:                                while (!isspace(*fp->_p)) {
                    415:                                        n++, fp->_r--, fp->_p++;
                    416:                                        if (--width == 0)
                    417:                                                break;
                    418:                                        if (fp->_r <= 0 && __srefill(fp))
                    419:                                                break;
                    420:                                }
                    421:                                nread += n;
                    422:                        } else {
                    423:                                p0 = p = va_arg(ap, char *);
                    424:                                while (!isspace(*fp->_p)) {
                    425:                                        fp->_r--;
                    426:                                        *p++ = *fp->_p++;
                    427:                                        if (--width == 0)
                    428:                                                break;
                    429:                                        if (fp->_r <= 0 && __srefill(fp))
                    430:                                                break;
                    431:                                }
                    432:                                *p = 0;
                    433:                                nread += p - p0;
                    434:                                nassigned++;
                    435:                        }
                    436:                        continue;
                    437:
                    438:                case CT_INT:
1.10      jtc       439:                        /* scan an integer as if by strtoq/strtouq */
1.1       cgd       440: #ifdef hardway
                    441:                        if (width == 0 || width > sizeof(buf) - 1)
                    442:                                width = sizeof(buf) - 1;
                    443: #else
                    444:                        /* size_t is unsigned, hence this optimisation */
                    445:                        if (--width > sizeof(buf) - 2)
                    446:                                width = sizeof(buf) - 2;
                    447:                        width++;
                    448: #endif
                    449:                        flags |= SIGNOK | NDIGITS | NZDIGITS;
                    450:                        for (p = buf; width; width--) {
                    451:                                c = *fp->_p;
                    452:                                /*
                    453:                                 * Switch on the character; `goto ok'
                    454:                                 * if we accept it as a part of number.
                    455:                                 */
                    456:                                switch (c) {
                    457:
                    458:                                /*
                    459:                                 * The digit 0 is always legal, but is
                    460:                                 * special.  For %i conversions, if no
                    461:                                 * digits (zero or nonzero) have been
                    462:                                 * scanned (only signs), we will have
                    463:                                 * base==0.  In that case, we should set
                    464:                                 * it to 8 and enable 0x prefixing.
                    465:                                 * Also, if we have not scanned zero digits
                    466:                                 * before this, do not turn off prefixing
                    467:                                 * (someone else will turn it off if we
                    468:                                 * have scanned any nonzero digits).
                    469:                                 */
                    470:                                case '0':
                    471:                                        if (base == 0) {
                    472:                                                base = 8;
                    473:                                                flags |= PFXOK;
                    474:                                        }
                    475:                                        if (flags & NZDIGITS)
                    476:                                            flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
                    477:                                        else
                    478:                                            flags &= ~(SIGNOK|PFXOK|NDIGITS);
                    479:                                        goto ok;
                    480:
                    481:                                /* 1 through 7 always legal */
                    482:                                case '1': case '2': case '3':
                    483:                                case '4': case '5': case '6': case '7':
                    484:                                        base = basefix[base];
                    485:                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
                    486:                                        goto ok;
                    487:
                    488:                                /* digits 8 and 9 ok iff decimal or hex */
                    489:                                case '8': case '9':
                    490:                                        base = basefix[base];
                    491:                                        if (base <= 8)
                    492:                                                break;  /* not legal here */
                    493:                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
                    494:                                        goto ok;
                    495:
                    496:                                /* letters ok iff hex */
                    497:                                case 'A': case 'B': case 'C':
                    498:                                case 'D': case 'E': case 'F':
                    499:                                case 'a': case 'b': case 'c':
                    500:                                case 'd': case 'e': case 'f':
                    501:                                        /* no need to fix base here */
                    502:                                        if (base <= 10)
                    503:                                                break;  /* not legal here */
                    504:                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
                    505:                                        goto ok;
                    506:
                    507:                                /* sign ok only as first character */
                    508:                                case '+': case '-':
                    509:                                        if (flags & SIGNOK) {
                    510:                                                flags &= ~SIGNOK;
                    511:                                                goto ok;
                    512:                                        }
                    513:                                        break;
                    514:
                    515:                                /* x ok iff flag still set & 2nd char */
                    516:                                case 'x': case 'X':
                    517:                                        if (flags & PFXOK && p == buf + 1) {
                    518:                                                base = 16;      /* if %i */
                    519:                                                flags &= ~PFXOK;
                    520:                                                goto ok;
                    521:                                        }
                    522:                                        break;
                    523:                                }
                    524:
                    525:                                /*
                    526:                                 * If we got here, c is not a legal character
                    527:                                 * for a number.  Stop accumulating digits.
                    528:                                 */
                    529:                                break;
                    530:                ok:
                    531:                                /*
                    532:                                 * c is legal: store it and look at the next.
                    533:                                 */
                    534:                                *p++ = c;
                    535:                                if (--fp->_r > 0)
                    536:                                        fp->_p++;
                    537:                                else if (__srefill(fp))
                    538:                                        break;          /* EOF */
                    539:                        }
                    540:                        /*
                    541:                         * If we had only a sign, it is no good; push
                    542:                         * back the sign.  If the number ends in `x',
                    543:                         * it was [sign] '0' 'x', so push back the x
                    544:                         * and treat it as [sign] '0'.
                    545:                         */
                    546:                        if (flags & NDIGITS) {
                    547:                                if (p > buf)
                    548:                                        (void) ungetc(*(u_char *)--p, fp);
                    549:                                goto match_failure;
                    550:                        }
                    551:                        c = ((u_char *)p)[-1];
                    552:                        if (c == 'x' || c == 'X') {
                    553:                                --p;
                    554:                                (void) ungetc(c, fp);
                    555:                        }
                    556:                        if ((flags & SUPPRESS) == 0) {
1.10      jtc       557:                                u_quad_t res;
1.1       cgd       558:
                    559:                                *p = 0;
                    560:                                res = (*ccfn)(buf, (char **)NULL, base);
                    561:                                if (flags & POINTER)
1.13      cgd       562:                                        *va_arg(ap, void **) =
                    563:                                            (void *)(long)res;
1.10      jtc       564:                                else if (flags & QUAD)
                    565:                                        *va_arg(ap, quad_t *) = res;
                    566:                                else if (flags & LONG)
1.22      christos  567:                                        *va_arg(ap, long *) = (long)res;
1.1       cgd       568:                                else if (flags & SHORT)
1.22      christos  569:                                        *va_arg(ap, short *) = (short)res;
1.1       cgd       570:                                else
1.22      christos  571:                                        *va_arg(ap, int *) = (int)res;
1.1       cgd       572:                                nassigned++;
                    573:                        }
                    574:                        nread += p - buf;
                    575:                        break;
                    576:
                    577: #ifdef FLOATING_POINT
                    578:                case CT_FLOAT:
                    579:                        /* scan a floating point number as if by strtod */
                    580: #ifdef hardway
                    581:                        if (width == 0 || width > sizeof(buf) - 1)
                    582:                                width = sizeof(buf) - 1;
                    583: #else
                    584:                        /* size_t is unsigned, hence this optimisation */
                    585:                        if (--width > sizeof(buf) - 2)
                    586:                                width = sizeof(buf) - 2;
                    587:                        width++;
                    588: #endif
                    589:                        flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
                    590:                        for (p = buf; width; width--) {
                    591:                                c = *fp->_p;
                    592:                                /*
                    593:                                 * This code mimicks the integer conversion
                    594:                                 * code, but is much simpler.
                    595:                                 */
                    596:                                switch (c) {
                    597:
                    598:                                case '0': case '1': case '2': case '3':
                    599:                                case '4': case '5': case '6': case '7':
                    600:                                case '8': case '9':
                    601:                                        flags &= ~(SIGNOK | NDIGITS);
                    602:                                        goto fok;
                    603:
                    604:                                case '+': case '-':
                    605:                                        if (flags & SIGNOK) {
                    606:                                                flags &= ~SIGNOK;
                    607:                                                goto fok;
                    608:                                        }
                    609:                                        break;
                    610:                                case '.':
                    611:                                        if (flags & DPTOK) {
                    612:                                                flags &= ~(SIGNOK | DPTOK);
                    613:                                                goto fok;
                    614:                                        }
                    615:                                        break;
                    616:                                case 'e': case 'E':
                    617:                                        /* no exponent without some digits */
                    618:                                        if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
                    619:                                                flags =
                    620:                                                    (flags & ~(EXPOK|DPTOK)) |
                    621:                                                    SIGNOK | NDIGITS;
                    622:                                                goto fok;
                    623:                                        }
                    624:                                        break;
                    625:                                }
                    626:                                break;
                    627:                fok:
                    628:                                *p++ = c;
                    629:                                if (--fp->_r > 0)
                    630:                                        fp->_p++;
                    631:                                else if (__srefill(fp))
                    632:                                        break;  /* EOF */
                    633:                        }
                    634:                        /*
                    635:                         * If no digits, might be missing exponent digits
                    636:                         * (just give back the exponent) or might be missing
                    637:                         * regular digits, but had sign and/or decimal point.
                    638:                         */
                    639:                        if (flags & NDIGITS) {
                    640:                                if (flags & EXPOK) {
                    641:                                        /* no digits at all */
                    642:                                        while (p > buf)
                    643:                                                ungetc(*(u_char *)--p, fp);
                    644:                                        goto match_failure;
                    645:                                }
                    646:                                /* just a bad exponent (e and maybe sign) */
                    647:                                c = *(u_char *)--p;
                    648:                                if (c != 'e' && c != 'E') {
                    649:                                        (void) ungetc(c, fp);/* sign */
                    650:                                        c = *(u_char *)--p;
                    651:                                }
                    652:                                (void) ungetc(c, fp);
                    653:                        }
                    654:                        if ((flags & SUPPRESS) == 0) {
                    655:                                double res;
                    656:
                    657:                                *p = 0;
1.3       cgd       658:                                res = strtod(buf, (char **) NULL);
1.11      jtc       659:                                if (flags & LONGDBL)
                    660:                                        *va_arg(ap, long double *) = res;
                    661:                                else if (flags & LONG)
1.1       cgd       662:                                        *va_arg(ap, double *) = res;
                    663:                                else
                    664:                                        *va_arg(ap, float *) = res;
                    665:                                nassigned++;
                    666:                        }
                    667:                        nread += p - buf;
                    668:                        break;
                    669: #endif /* FLOATING_POINT */
                    670:                }
                    671:        }
                    672: input_failure:
1.17      kleink    673:        return (nassigned ? nassigned : EOF);
1.1       cgd       674: match_failure:
                    675:        return (nassigned);
                    676: }
                    677:
                    678: /*
                    679:  * Fill in the given table from the scanset at the given format
                    680:  * (just after `[').  Return a pointer to the character past the
                    681:  * closing `]'.  The table has a 1 wherever characters should be
                    682:  * considered part of the scanset.
                    683:  */
1.20      mycroft   684: static const u_char *
1.1       cgd       685: __sccl(tab, fmt)
1.18      perry     686:        char *tab;
1.20      mycroft   687:        const u_char *fmt;
1.1       cgd       688: {
1.18      perry     689:        int c, n, v;
1.23      lukem     690:
                    691:        _DIAGASSERT(tab != NULL);
                    692:        _DIAGASSERT(fmt != NULL);
1.1       cgd       693:
                    694:        /* first `clear' the whole table */
                    695:        c = *fmt++;             /* first char hat => negated scanset */
                    696:        if (c == '^') {
                    697:                v = 1;          /* default => accept */
                    698:                c = *fmt++;     /* get new first char */
                    699:        } else
                    700:                v = 0;          /* default => reject */
                    701:        /* should probably use memset here */
                    702:        for (n = 0; n < 256; n++)
                    703:                tab[n] = v;
                    704:        if (c == 0)
                    705:                return (fmt - 1);/* format ended before closing ] */
                    706:
                    707:        /*
                    708:         * Now set the entries corresponding to the actual scanset
                    709:         * to the opposite of the above.
                    710:         *
                    711:         * The first character may be ']' (or '-') without being special;
                    712:         * the last character may be '-'.
                    713:         */
                    714:        v = 1 - v;
                    715:        for (;;) {
                    716:                tab[c] = v;             /* take character c */
                    717: doswitch:
                    718:                n = *fmt++;             /* and examine the next */
                    719:                switch (n) {
                    720:
                    721:                case 0:                 /* format ended too soon */
                    722:                        return (fmt - 1);
                    723:
                    724:                case '-':
                    725:                        /*
                    726:                         * A scanset of the form
                    727:                         *      [01+-]
                    728:                         * is defined as `the digit 0, the digit 1,
                    729:                         * the character +, the character -', but
                    730:                         * the effect of a scanset such as
                    731:                         *      [a-zA-Z0-9]
                    732:                         * is implementation defined.  The V7 Unix
                    733:                         * scanf treats `a-z' as `the letters a through
                    734:                         * z', but treats `a-a' as `the letter a, the
                    735:                         * character -, and the letter a'.
                    736:                         *
                    737:                         * For compatibility, the `-' is not considerd
                    738:                         * to define a range if the character following
                    739:                         * it is either a close bracket (required by ANSI)
                    740:                         * or is not numerically greater than the character
                    741:                         * we just stored in the table (c).
                    742:                         */
                    743:                        n = *fmt;
                    744:                        if (n == ']' || n < c) {
                    745:                                c = '-';
                    746:                                break;  /* resume the for(;;) */
                    747:                        }
                    748:                        fmt++;
                    749:                        do {            /* fill in the range */
                    750:                                tab[++c] = v;
                    751:                        } while (c < n);
                    752: #if 1  /* XXX another disgusting compatibility hack */
                    753:                        /*
                    754:                         * Alas, the V7 Unix scanf also treats formats
                    755:                         * such as [a-c-e] as `the letters a through e'.
                    756:                         * This too is permitted by the standard....
                    757:                         */
                    758:                        goto doswitch;
                    759: #else
                    760:                        c = *fmt++;
                    761:                        if (c == 0)
                    762:                                return (fmt - 1);
                    763:                        if (c == ']')
                    764:                                return (fmt);
1.20      mycroft   765:                        break;
1.1       cgd       766: #endif
                    767:
                    768:                case ']':               /* end of scanset */
                    769:                        return (fmt);
                    770:
                    771:                default:                /* just another character */
                    772:                        c = n;
                    773:                        break;
                    774:                }
                    775:        }
                    776:        /* NOTREACHED */
                    777: }

CVSweb <webmaster@jp.NetBSD.org>