gonzui


Format: Advanced Search

t2ex/bsd_source/lib/libc/src_bsd/stdio/vfscanf.cbare sourcepermlink (0.06 seconds)

Search this content:

    1: /* Use __sungetc() and __sfread() to avoid deadlock */
    2: 
    3: /*      $OpenBSD: vfscanf.c,v 1.29 2012/01/18 14:01:38 stsp Exp $ */
    4: /*-
    5:  * Copyright (c) 1990, 1993
    6:  *      The Regents of the University of California.  All rights reserved.
    7:  *
    8:  * This code is derived from software contributed to Berkeley by
    9:  * Chris Torek.
   10:  *
   11:  * Redistribution and use in source and binary forms, with or without
   12:  * modification, are permitted provided that the following conditions
   13:  * are met:
   14:  * 1. Redistributions of source code must retain the above copyright
   15:  *    notice, this list of conditions and the following disclaimer.
   16:  * 2. Redistributions in binary form must reproduce the above copyright
   17:  *    notice, this list of conditions and the following disclaimer in the
   18:  *    documentation and/or other materials provided with the distribution.
   19:  * 3. Neither the name of the University nor the names of its contributors
   20:  *    may be used to endorse or promote products derived from this software
   21:  *    without specific prior written permission.
   22:  *
   23:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   24:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   25:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   26:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   27:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   28:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   29:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   30:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   31:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   32:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   33:  * SUCH DAMAGE.
   34:  */
   35: #define FLOATING_POINT
   36: #include <ctype.h>
   37: #include <inttypes.h>
   38: #include <stdarg.h>
   39: #include <stddef.h>
   40: #include <stdio.h>
   41: #include <stdlib.h>
   42: #include <string.h>
   43: #include "local.h"
   44: 
   45: #ifdef FLOATING_POINT
   46: #include "floatio.h"
   47: #endif
   48: 
   49: #define BUF             513        /* Maximum length of numeric string. */
   50: 
   51: /*
   52:  * Flags used during conversion.
   53:  */
   54: #define LONG            0x00001   /* l: long or double */
   55: #define LONGDBL         0x00002        /* L: long double */
   56: #define SHORT           0x00004  /* h: short */
   57: #define SHORTSHORT      0x00008      /* hh: 8 bit integer */
   58: #define LLONG           0x00010  /* ll: long long (+ deprecated q: quad) */
   59: #define POINTER         0x00020        /* p: void * (as hex) */
   60: #define SIZEINT         0x00040        /* z: (signed) size_t */
   61: #define MAXINT          0x00080 /* j: intmax_t */
   62: #define PTRINT          0x00100 /* t: ptrdiff_t */
   63: #define NOSKIP          0x00200 /* [ or c: do not skip blanks */
   64: #define SUPPRESS        0x00400        /* *: suppress assignment */
   65: #define UNSIGNED        0x00800        /* %[oupxX] conversions */
   66: 
   67: /*
   68:  * The following are used in numeric conversions only:
   69:  * SIGNOK, HAVESIGN, NDIGITS, DPTOK, and EXPOK are for floating point;
   70:  * SIGNOK, HAVESIGN, NDIGITS, PFXOK, and NZDIGITS are for integral.
   71:  */
   72: #define SIGNOK          0x01000 /* +/- is (still) legal */
   73: #define HAVESIGN        0x02000        /* sign detected */
   74: #define NDIGITS         0x04000        /* no digits detected */
   75: 
   76: #define DPTOK           0x08000  /* (float) decimal point is still legal */
   77: #define EXPOK           0x10000  /* (float) exponent (e+3, etc) still legal */
   78: 
   79: #define PFXOK           0x08000  /* 0x prefix is (still) legal */
   80: #define NZDIGITS        0x10000        /* no zero digits detected */
   81: 
   82: /*
   83:  * Conversion types.
   84:  */
   85: #define CT_CHAR         0      /* %c conversion */
   86: #define CT_CCL          1       /* %[...] conversion */
   87: #define CT_STRING       2     /* %s conversion */
   88: #define CT_INT          3       /* integer, i.e., strtoimax or strtoumax */
   89: #define CT_FLOAT        4      /* floating, i.e., strtod */
   90: 
   91: #define u_char unsigned char
   92: #define u_long unsigned long
   93: 
   94: static u_char *__sccl(char *, u_char *);
   95: 
   96: /*
   97:  * Internal, unlocked version of vfscanf
   98:  */
   99: int
  100: __svfscanf(FILE *fp, const char *fmt0, __va_list ap)
  101: {
  102:         u_char *fmt = (u_char *)fmt0;
  103:         int c;         /* character from format, or conversion */
  104:         size_t width;  /* field width, or 0 */
  105:         char *p;       /* points into all kinds of strings */
  106:         int n;         /* handy integer */
  107:         int flags;     /* flags as defined above */
  108:         char *p0;      /* saves original value of p when necessary */
  109:         int nassigned;         /* number of fields assigned */
  110:         int nread;             /* number of characters consumed from fp */
  111:         int base;              /* base argument to strtoimax/strtouimax */
  112:         char ccltab[256];      /* character class table for %[...] */
  113:         char buf[BUF];         /* buffer for numeric conversions */
  114: #ifdef SCANF_WIDE_CHAR
  115:         wchar_t *wcp;          /* handy wide character pointer */
  116:         size_t nconv;          /* length of multibyte sequence converted */
  117:         mbstate_t mbs;
  118: #endif
  119: 
  120:         /* `basefix' is used to avoid `if' tests in the integer scanner */
  121:         static short basefix[17] =
  122:                 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
  123: 
  124:         _SET_ORIENTATION(fp, -1);
  125: 
  126:         nassigned = 0;
  127:         nread = 0;
  128:         base = 0;              /* XXX just to keep gcc happy */
  129:         for (;;) {
  130:                 c = *fmt++;
  131:                 if (c == 0)
  132:                         return (nassigned);
  133:                 if (isspace(c)) {
  134:                         while ((fp->_r > 0 || __srefill(fp) == 0) &&
  135:                             isspace(*fp->_p))
  136:                                 nread++, fp->_r--, fp->_p++;
  137:                         continue;
  138:                 }
  139:                 if (c != '%')
  140:                         goto literal;
  141:                 width = 0;
  142:                 flags = 0;
  143:                 /*
  144:                  * switch on the format.  continue if done;
  145:                  * break once format type is derived.
  146:                  */
  147: again:          c = *fmt++;
  148:                 switch (c) {
  149:                 case '%':
  150: literal:
  151:                         if (fp->_r <= 0 && __srefill(fp))
  152:                                 goto input_failure;
  153:                         if (*fp->_p != c)
  154:                                 goto match_failure;
  155:                         fp->_r--, fp->_p++;
  156:                         nread++;
  157:                         continue;
  158: 
  159:                 case '*':
  160:                         flags |= SUPPRESS;
  161:                         goto again;
  162:                 case 'j':
  163:                         flags |= MAXINT;
  164:                         goto again;
  165:                 case 'L':
  166:                         flags |= LONGDBL;
  167:                         goto again;
  168:                 case 'h':
  169:                         if (*fmt == 'h') {
  170:                                 fmt++;
  171:                                 flags |= SHORTSHORT;
  172:                         } else {
  173:                                 flags |= SHORT;
  174:                         }
  175:                         goto again;
  176:                 case 'l':
  177:                         if (*fmt == 'l') {
  178:                                 fmt++;
  179:                                 flags |= LLONG;
  180:                         } else {
  181:                                 flags |= LONG;
  182:                         }
  183:                         goto again;
  184:                 case 'q':
  185:                         flags |= LLONG;              /* deprecated */
  186:                         goto again;
  187:                 case 't':
  188:                         flags |= PTRINT;
  189:                         goto again;
  190:                 case 'z':
  191:                         flags |= SIZEINT;
  192:                         goto again;
  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;
  211:                         base = 10;
  212:                         break;
  213: 
  214:                 case 'i':
  215:                         c = CT_INT;
  216:                         base = 0;
  217:                         break;
  218: 
  219:                 case 'O':     /* compat */
  220:                         flags |= LONG;
  221:                         /* FALLTHROUGH */
  222:                 case 'o':
  223:                         c = CT_INT;
  224:                         flags |= UNSIGNED;
  225:                         base = 8;
  226:                         break;
  227: 
  228:                 case 'u':
  229:                         c = CT_INT;
  230:                         flags |= UNSIGNED;
  231:                         base = 10;
  232:                         break;
  233: 
  234:                 case 'X':
  235:                 case 'x':
  236:                         flags |= PFXOK;      /* enable 0x prefixing */
  237:                         c = CT_INT;
  238:                         flags |= UNSIGNED;
  239:                         base = 16;
  240:                         break;
  241: 
  242: #ifdef FLOATING_POINT
  243:                 case 'e': case 'E':
  244:                 case 'f': case 'F':
  245:                 case 'g': case 'G':
  246:                 case 'a': case 'A':
  247:                         c = CT_FLOAT;
  248:                         break;
  249: #endif
  250: 
  251:                 case 's':
  252:                         c = CT_STRING;
  253:                         break;
  254: 
  255:                 case '[':
  256:                         fmt = __sccl(ccltab, fmt);
  257:                         flags |= NOSKIP;
  258:                         c = CT_CCL;
  259:                         break;
  260: 
  261:                 case 'c':
  262:                         flags |= NOSKIP;
  263:                         c = CT_CHAR;
  264:                         break;
  265: 
  266:                 case 'p':     /* pointer format is like hex */
  267:                         flags |= POINTER | PFXOK;
  268:                         c = CT_INT;
  269:                         flags |= UNSIGNED;
  270:                         base = 16;
  271:                         break;
  272: 
  273:                 case 'n':
  274:                         if (flags & SUPPRESS)
  275:                                 continue;
  276:                         if (flags & SHORTSHORT)
  277:                                 *va_arg(ap, __signed char *) = nread;
  278:                         else if (flags & SHORT)
  279:                                 *va_arg(ap, short *) = nread;
  280:                         else if (flags & LONG)
  281:                                 *va_arg(ap, long *) = nread;
  282:                         else if (flags & SIZEINT)
  283:                                 *va_arg(ap, ssize_t *) = nread;
  284:                         else if (flags & PTRINT)
  285:                                 *va_arg(ap, ptrdiff_t *) = nread;
  286:                         else if (flags & LLONG)
  287:                                 *va_arg(ap, long long *) = nread;
  288:                         else if (flags & MAXINT)
  289:                                 *va_arg(ap, intmax_t *) = nread;
  290:                         else
  291:                                 *va_arg(ap, int *) = nread;
  292:                         continue;
  293: 
  294:                 /*
  295:                  * Disgusting backwards compatibility hacks.  XXX
  296:                  */
  297:                 case '\0':    /* compat */
  298:                         return (EOF);
  299: 
  300:                 default:      /* compat */
  301:                         if (isupper(c))
  302:                                 flags |= LONG;
  303:                         c = CT_INT;
  304:                         base = 10;
  305:                         break;
  306:                 }
  307: 
  308:                 /*
  309:                  * We have a conversion that requires input.
  310:                  */
  311:                 if (fp->_r <= 0 && __srefill(fp))
  312:                         goto input_failure;
  313: 
  314:                 /*
  315:                  * Consume leading white space, except for formats
  316:                  * that suppress this.
  317:                  */
  318:                 if ((flags & NOSKIP) == 0) {
  319:                         while (isspace(*fp->_p)) {
  320:                                 nread++;
  321:                                 if (--fp->_r > 0)
  322:                                         fp->_p++;
  323:                                 else if (__srefill(fp))
  324:                                         goto input_failure;
  325:                         }
  326:                         /*
  327:                          * Note that there is at least one character in
  328:                          * the buffer, so conversions that do not set NOSKIP
  329:                          * ca no longer result in an input failure.
  330:                          */
  331:                 }
  332: 
  333:                 /*
  334:                  * Do the conversion.
  335:                  */
  336:                 switch (c) {
  337: 
  338:                 case CT_CHAR:
  339:                         /* scan arbitrary characters (sets NOSKIP) */
  340:                         if (width == 0)
  341:                                 width = 1;
  342: #ifdef SCANF_WIDE_CHAR
  343:                         if (flags & LONG) {
  344:                                 if ((flags & SUPPRESS) == 0)
  345:                                         wcp = va_arg(ap, wchar_t *);
  346:                                 else
  347:                                         wcp = NULL;
  348:                                 n = 0;
  349:                                 while (width != 0) {
  350:                                         if (n == MB_CUR_MAX) {
  351:                                                 fp->_flags |= __SERR;
  352:                                                 goto input_failure;
  353:                                         }
  354:                                         buf[n++] = *fp->_p;
  355:                                         fp->_p++;
  356:                                         fp->_r--;
  357:                                         bzero(&mbs, sizeof(mbs));
  358:                                         nconv = mbrtowc(wcp, buf, n, &mbs);
  359:                                         if (nconv == (size_t)-1) {
  360:                                                 fp->_flags |= __SERR;
  361:                                                 goto input_failure;
  362:                                         }
  363:                                         if (nconv == 0 && !(flags & SUPPRESS))
  364:                                                 *wcp = L'\0';
  365:                                         if (nconv != (size_t)-2) {
  366:                                                 nread += n;
  367:                                                 width--;
  368:                                                 if (!(flags & SUPPRESS))
  369:                                                         wcp++;
  370:                                                 n = 0;
  371:                                         }
  372:                                         if (fp->_r <= 0 && __srefill(fp)) {
  373:                                                 if (n != 0) {
  374:                                                         fp->_flags |= __SERR;
  375:                                                         goto input_failure;
  376:                                                 }
  377:                                                 break;
  378:                                         }
  379:                                 }
  380:                                 if (!(flags & SUPPRESS))
  381:                                         nassigned++;
  382:                         } else
  383: #endif /* SCANF_WIDE_CHAR */
  384:                         if (flags & SUPPRESS) {
  385:                                 size_t sum = 0;
  386:                                 for (;;) {
  387:                                         if ((n = fp->_r) < width) {
  388:                                                 sum += n;
  389:                                                 width -= n;
  390:                                                 fp->_p += n;
  391:                                                 if (__srefill(fp)) {
  392:                                                         if (sum == 0)
  393:                                                             goto input_failure;
  394:                                                         break;
  395:                                                 }
  396:                                         } else {
  397:                                                 sum += width;
  398:                                                 fp->_r -= width;
  399:                                                 fp->_p += width;
  400:                                                 break;
  401:                                         }
  402:                                 }
  403:                                 nread += sum;
  404:                         } else {
  405:                                 size_t r = __sfread((void *)va_arg(ap, char *), 1,
  406:                                     width, fp);
  407: 
  408:                                 if (r == 0)
  409:                                         goto input_failure;
  410:                                 nread += r;
  411:                                 nassigned++;
  412:                         }
  413:                         break;
  414: 
  415:                 case CT_CCL:
  416:                         /* scan a (nonempty) character class (sets NOSKIP) */
  417:                         if (width == 0)
  418:                                 width = (size_t)~0; /* `infinity' */
  419: #ifdef SCANF_WIDE_CHAR
  420:                         /* take only those things in the class */
  421:                         if (flags & LONG) {
  422:                                 wchar_t twc;
  423:                                 int nchars;
  424: 
  425:                                 if ((flags & SUPPRESS) == 0)
  426:                                         wcp = va_arg(ap, wchar_t *);
  427:                                 else
  428:                                         wcp = &twc;
  429:                                 n = 0;
  430:                                 nchars = 0;
  431:                                 while (width != 0) {
  432:                                         if (n == MB_CUR_MAX) {
  433:                                                 fp->_flags |= __SERR;
  434:                                                 goto input_failure;
  435:                                         }
  436:                                         buf[n++] = *fp->_p;
  437:                                         fp->_p++;
  438:                                         fp->_r--;
  439:                                         bzero(&mbs, sizeof(mbs));
  440:                                         nconv = mbrtowc(wcp, buf, n, &mbs);
  441:                                         if (nconv == (size_t)-1) {
  442:                                                 fp->_flags |= __SERR;
  443:                                                 goto input_failure;
  444:                                         }
  445:                                         if (nconv == 0)
  446:                                                 *wcp = L'\0';
  447:                                         if (nconv != (size_t)-2) {
  448:                                                 if (wctob(*wcp) != EOF &&
  449:                                                     !ccltab[wctob(*wcp)]) {
  450:                                                         while (n != 0) {
  451:                                                                 n--;
  452:                                                                 __sungetc(buf[n],
  453:                                                                 fp);
  454:                                                         }
  455:                                                         break;
  456:                                                 }
  457:                                                 nread += n;
  458:                                                 width--;
  459:                                                 if (!(flags & SUPPRESS))
  460:                                                         wcp++;
  461:                                                 nchars++;
  462:                                                 n = 0;
  463:                                         }
  464:                                         if (fp->_r <= 0 && __srefill(fp)) {
  465:                                                 if (n != 0) {
  466:                                                         fp->_flags |= __SERR;
  467:                                                         goto input_failure;
  468:                                                 }
  469:                                                 break;
  470:                                         }
  471:                                 }
  472:                                 if (n != 0) {
  473:                                         fp->_flags |= __SERR;
  474:                                         goto input_failure;
  475:                                 }
  476:                                 n = nchars;
  477:                                 if (n == 0)
  478:                                         goto match_failure;
  479:                                 if (!(flags & SUPPRESS)) {
  480:                                         *wcp = L'\0';
  481:                                         nassigned++;
  482:                                 }
  483:                         } else
  484: #endif /* SCANF_WIDE_CHAR */
  485:                         /* take only those things in the class */
  486:                         if (flags & SUPPRESS) {
  487:                                 n = 0;
  488:                                 while (ccltab[*fp->_p]) {
  489:                                         n++, fp->_r--, fp->_p++;
  490:                                         if (--width == 0)
  491:                                                 break;
  492:                                         if (fp->_r <= 0 && __srefill(fp)) {
  493:                                                 if (n == 0)
  494:                                                         goto input_failure;
  495:                                                 break;
  496:                                         }
  497:                                 }
  498:                                 if (n == 0)
  499:                                         goto match_failure;
  500:                         } else {
  501:                                 p0 = p = va_arg(ap, char *);
  502:                                 while (ccltab[*fp->_p]) {
  503:                                         fp->_r--;
  504:                                         *p++ = *fp->_p++;
  505:                                         if (--width == 0)
  506:                                                 break;
  507:                                         if (fp->_r <= 0 && __srefill(fp)) {
  508:                                                 if (p == p0)
  509:                                                         goto input_failure;
  510:                                                 break;
  511:                                         }
  512:                                 }
  513:                                 n = p - p0;
  514:                                 if (n == 0)
  515:                                         goto match_failure;
  516:                                 *p = '\0';
  517:                                 nassigned++;
  518:                         }
  519:                         nread += n;
  520:                         break;
  521: 
  522:                 case CT_STRING:
  523:                         /* like CCL, but zero-length string OK, & no NOSKIP */
  524:                         if (width == 0)
  525:                                 width = (size_t)~0;
  526: #ifdef SCANF_WIDE_CHAR
  527:                         if (flags & LONG) {
  528:                                 wchar_t twc;
  529: 
  530:                                 if ((flags & SUPPRESS) == 0)
  531:                                         wcp = va_arg(ap, wchar_t *);
  532:                                 else
  533:                                         wcp = &twc;
  534:                                 n = 0;
  535:                                 while (!isspace(*fp->_p) && width != 0) {
  536:                                         if (n == MB_CUR_MAX) {
  537:                                                 fp->_flags |= __SERR;
  538:                                                 goto input_failure;
  539:                                         }
  540:                                         buf[n++] = *fp->_p;
  541:                                         fp->_p++;
  542:                                         fp->_r--;
  543:                                         bzero(&mbs, sizeof(mbs));
  544:                                         nconv = mbrtowc(wcp, buf, n, &mbs);
  545:                                         if (nconv == (size_t)-1) {
  546:                                                 fp->_flags |= __SERR;
  547:                                                 goto input_failure;
  548:                                         }
  549:                                         if (nconv == 0)
  550:                                                 *wcp = L'\0';
  551:                                         if (nconv != (size_t)-2) {
  552:                                                 if (iswspace(*wcp)) {
  553:                                                         while (n != 0) {
  554:                                                                 n--;
  555:                                                                 __sungetc(buf[n],
  556:                                                                     fp);
  557:                                                         }
  558:                                                         break;
  559:                                                 }
  560:                                                 nread += n;
  561:                                                 width--;
  562:                                                 if (!(flags & SUPPRESS))
  563:                                                         wcp++;
  564:                                                 n = 0;
  565:                                         }
  566:                                         if (fp->_r <= 0 && __srefill(fp)) {
  567:                                                 if (n != 0) {
  568:                                                         fp->_flags |= __SERR;
  569:                                                         goto input_failure;
  570:                                                 }
  571:                                                 break;
  572:                                         }
  573:                                 }
  574:                                 if (!(flags & SUPPRESS)) {
  575:                                         *wcp = L'\0';
  576:                                         nassigned++;
  577:                                 }
  578:                         } else
  579: #endif /* SCANF_WIDE_CHAR */
  580:                         if (flags & SUPPRESS) {
  581:                                 n = 0;
  582:                                 while (!isspace(*fp->_p)) {
  583:                                         n++, fp->_r--, fp->_p++;
  584:                                         if (--width == 0)
  585:                                                 break;
  586:                                         if (fp->_r <= 0 && __srefill(fp))
  587:                                                 break;
  588:                                 }
  589:                                 nread += n;
  590:                         } else {
  591:                                 p0 = p = va_arg(ap, char *);
  592:                                 while (!isspace(*fp->_p)) {
  593:                                         fp->_r--;
  594:                                         *p++ = *fp->_p++;
  595:                                         if (--width == 0)
  596:                                                 break;
  597:                                         if (fp->_r <= 0 && __srefill(fp))
  598:                                                 break;
  599:                                 }
  600:                                 *p = '\0';
  601:                                 nread += p - p0;
  602:                                 nassigned++;
  603:                         }
  604:                         continue;
  605: 
  606:                 case CT_INT:
  607:                         /* scan an integer as if by strtoimax/strtoumax */
  608: #ifdef hardway
  609:                         if (width == 0 || width > sizeof(buf) - 1)
  610:                                 width = sizeof(buf) - 1;
  611: #else
  612:                         /* size_t is unsigned, hence this optimisation */
  613:                         if (--width > sizeof(buf) - 2)
  614:                                 width = sizeof(buf) - 2;
  615:                         width++;
  616: #endif
  617:                         flags |= SIGNOK | NDIGITS | NZDIGITS;
  618:                         for (p = buf; width; width--) {
  619:                                 c = *fp->_p;
  620:                                 /*
  621:                                  * Switch on the character; `goto ok'
  622:                                  * if we accept it as a part of number.
  623:                                  */
  624:                                 switch (c) {
  625: 
  626:                                 /*
  627:                                  * The digit 0 is always legal, but is
  628:                                  * special.  For %i conversions, if no
  629:                                  * digits (zero or nonzero) have been
  630:                                  * scanned (only signs), we will have
  631:                                  * base==0.  In that case, we should set
  632:                                  * it to 8 and enable 0x prefixing.
  633:                                  * Also, if we have not scanned zero digits
  634:                                  * before this, do not turn off prefixing
  635:                                  * (someone else will turn it off if we
  636:                                  * have scanned any nonzero digits).
  637:                                  */
  638:                                 case '0':
  639:                                         if (base == 0) {
  640:                                                 base = 8;
  641:                                                 flags |= PFXOK;
  642:                                         }
  643:                                         if (flags & NZDIGITS)
  644:                                             flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
  645:                                         else
  646:                                             flags &= ~(SIGNOK|PFXOK|NDIGITS);
  647:                                         goto ok;
  648: 
  649:                                 /* 1 through 7 always legal */
  650:                                 case '1': case '2': case '3':
  651:                                 case '4': case '5': case '6': case '7':
  652:                                         base = basefix[base];
  653:                                         flags &= ~(SIGNOK | PFXOK | NDIGITS);
  654:                                         goto ok;
  655: 
  656:                                 /* digits 8 and 9 ok iff decimal or hex */
  657:                                 case '8': case '9':
  658:                                         base = basefix[base];
  659:                                         if (base <= 8)
  660:                                                 break;    /* not legal here */
  661:                                         flags &= ~(SIGNOK | PFXOK | NDIGITS);
  662:                                         goto ok;
  663: 
  664:                                 /* letters ok iff hex */
  665:                                 case 'A': case 'B': case 'C':
  666:                                 case 'D': case 'E': case 'F':
  667:                                 case 'a': case 'b': case 'c':
  668:                                 case 'd': case 'e': case 'f':
  669:                                         /* no need to fix base here */
  670:                                         if (base <= 10)
  671:                                                 break;    /* not legal here */
  672:                                         flags &= ~(SIGNOK | PFXOK | NDIGITS);
  673:                                         goto ok;
  674: 
  675:                                 /* sign ok only as first character */
  676:                                 case '+': case '-':
  677:                                         if (flags & SIGNOK) {
  678:                                                 flags &= ~SIGNOK;
  679:                                                 flags |= HAVESIGN;
  680:                                                 goto ok;
  681:                                         }
  682:                                         break;
  683: 
  684:                                 /*
  685:                                  * x ok iff flag still set and 2nd char (or
  686:                                  * 3rd char if we have a sign).
  687:                                  */
  688:                                 case 'x': case 'X':
  689:                                         if ((flags & PFXOK) && p ==
  690:                                             buf + 1 + !!(flags & HAVESIGN)) {
  691:                                                 base = 16;        /* if %i */
  692:                                                 flags &= ~PFXOK;
  693:                                                 goto ok;
  694:                                         }
  695:                                         break;
  696:                                 }
  697: 
  698:                                 /*
  699:                                  * If we got here, c is not a legal character
  700:                                  * for a number.  Stop accumulating digits.
  701:                                  */
  702:                                 break;
  703:                 ok:
  704:                                 /*
  705:                                  * c is legal: store it and look at the next.
  706:                                  */
  707:                                 *p++ = c;
  708:                                 if (--fp->_r > 0)
  709:                                         fp->_p++;
  710:                                 else if (__srefill(fp))
  711:                                         break;             /* EOF */
  712:                         }
  713:                         /*
  714:                          * If we had only a sign, it is no good; push
  715:                          * back the sign.  If the number ends in `x',
  716:                          * it was [sign] '0' 'x', so push back the x
  717:                          * and treat it as [sign] '0'.
  718:                          */
  719:                         if (flags & NDIGITS) {
  720:                                 if (p > buf)
  721:                                         (void) __sungetc(*(u_char *)--p, fp);
  722:                                 goto match_failure;
  723:                         }
  724:                         c = ((u_char *)p)[-1];
  725:                         if (c == 'x' || c == 'X') {
  726:                                 --p;
  727:                                 (void) __sungetc(c, fp);
  728:                         }
  729:                         if ((flags & SUPPRESS) == 0) {
  730:                                 uintmax_t res;
  731: 
  732:                                 *p = '\0';
  733:                                 if (flags & UNSIGNED)
  734:                                         res = strtoumax(buf, NULL, base);
  735:                                 else
  736:                                         res = strtoimax(buf, NULL, base);
  737:                                 if (flags & POINTER)
  738:                                         *va_arg(ap, void **) =
  739:                                             (void *)(uintptr_t)res;
  740:                                 else if (flags & MAXINT)
  741:                                         *va_arg(ap, intmax_t *) = res;
  742:                                 else if (flags & LLONG)
  743:                                         *va_arg(ap, long long *) = res;
  744:                                 else if (flags & SIZEINT)
  745:                                         *va_arg(ap, ssize_t *) = res;
  746:                                 else if (flags & PTRINT)
  747:                                         *va_arg(ap, ptrdiff_t *) = res;
  748:                                 else if (flags & LONG)
  749:                                         *va_arg(ap, long *) = res;
  750:                                 else if (flags & SHORT)
  751:                                         *va_arg(ap, short *) = res;
  752:                                 else if (flags & SHORTSHORT)
  753:                                         *va_arg(ap, __signed char *) = res;
  754:                                 else
  755:                                         *va_arg(ap, int *) = res;
  756:                                 nassigned++;
  757:                         }
  758:                         nread += p - buf;
  759:                         break;
  760: 
  761: #ifdef FLOATING_POINT
  762:                 case CT_FLOAT:
  763:                         /* scan a floating point number as if by strtod */
  764: #ifdef hardway
  765:                         if (width == 0 || width > sizeof(buf) - 1)
  766:                                 width = sizeof(buf) - 1;
  767: #else
  768:                         /* size_t is unsigned, hence this optimisation */
  769:                         if (--width > sizeof(buf) - 2)
  770:                                 width = sizeof(buf) - 2;
  771:                         width++;
  772: #endif
  773:                         flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
  774:                         for (p = buf; width; width--) {
  775:                                 c = *fp->_p;
  776:                                 /*
  777:                                  * This code mimicks the integer conversion
  778:                                  * code, but is much simpler.
  779:                                  */
  780:                                 switch (c) {
  781: 
  782:                                 case '0': case '1': case '2': case '3':
  783:                                 case '4': case '5': case '6': case '7':
  784:                                 case '8': case '9':
  785:                                         flags &= ~(SIGNOK | NDIGITS);
  786:                                         goto fok;
  787: 
  788:                                 case '+': case '-':
  789:                                         if (flags & SIGNOK) {
  790:                                                 flags &= ~SIGNOK;
  791:                                                 goto fok;
  792:                                         }
  793:                                         break;
  794:                                 case '.':
  795:                                         if (flags & DPTOK) {
  796:                                                 flags &= ~(SIGNOK | DPTOK);
  797:                                                 goto fok;
  798:                                         }
  799:                                         break;
  800:                                 case 'e': case 'E':
  801:                                         /* no exponent without some digits */
  802:                                         if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
  803:                                                 flags =
  804:                                                     (flags & ~(EXPOK|DPTOK)) |
  805:                                                     SIGNOK | NDIGITS;
  806:                                                 goto fok;
  807:                                         }
  808:                                         break;
  809:                                 }
  810:                                 break;
  811:                 fok:
  812:                                 *p++ = c;
  813:                                 if (--fp->_r > 0)
  814:                                         fp->_p++;
  815:                                 else if (__srefill(fp))
  816:                                         break;     /* EOF */
  817:                         }
  818:                         /*
  819:                          * If no digits, might be missing exponent digits
  820:                          * (just give back the exponent) or might be missing
  821:                          * regular digits, but had sign and/or decimal point.
  822:                          */
  823:                         if (flags & NDIGITS) {
  824:                                 if (flags & EXPOK) {
  825:                                         /* no digits at all */
  826:                                         while (p > buf)
  827:                                                 __sungetc(*(u_char *)--p, fp);
  828:                                         goto match_failure;
  829:                                 }
  830:                                 /* just a bad exponent (e and maybe sign) */
  831:                                 c = *(u_char *)--p;
  832:                                 if (c != 'e' && c != 'E') {
  833:                                         (void) __sungetc(c, fp);/* sign */
  834:                                         c = *(u_char *)--p;
  835:                                 }
  836:                                 (void) __sungetc(c, fp);
  837:                         }
  838:                         if ((flags & SUPPRESS) == 0) {
  839:                                 *p = '\0';
  840:                                 if (flags & LONGDBL) {
  841:                                         long double res = strtold(buf,
  842:                                             (char **)NULL);
  843:                                         *va_arg(ap, long double *) = res;
  844:                                 } else if (flags & LONG) {
  845:                                         double res = strtod(buf, (char **)NULL);
  846:                                         *va_arg(ap, double *) = res;
  847:                                 } else {
  848:                                         float res = strtof(buf, (char **)NULL);
  849:                                         *va_arg(ap, float *) = res;
  850:                                 }
  851:                                 nassigned++;
  852:                         }
  853:                         nread += p - buf;
  854:                         break;
  855: #endif /* FLOATING_POINT */
  856:                 }
  857:         }
  858: input_failure:
  859:         if (nassigned == 0)
  860:                 nassigned = -1;
  861: match_failure:
  862:         return (nassigned);
  863: }
  864: 
  865: /*
  866:  * Fill in the given table from the scanset at the given format
  867:  * (just after `[').  Return a pointer to the character past the
  868:  * closing `]'.  The table has a 1 wherever characters should be
  869:  * considered part of the scanset.
  870:  */
  871: static u_char *
  872: __sccl(char *tab, u_char *fmt)
  873: {
  874:         int c, n, v;
  875: 
  876:         /* first `clear' the whole table */
  877:         c = *fmt++;            /* first char hat => negated scanset */
  878:         if (c == '^') {
  879:                 v = 1;                /* default => accept */
  880:                 c = *fmt++;   /* get new first char */
  881:         } else
  882:                 v = 0;                /* default => reject */
  883:         /* should probably use memset here */
  884:         for (n = 0; n < 256; n++)
  885:                 tab[n] = v;
  886:         if (c == 0)
  887:                 return (fmt - 1);/* format ended before closing ] */
  888: 
  889:         /*
  890:          * Now set the entries corresponding to the actual scanset
  891:          * to the opposite of the above.
  892:          *
  893:          * The first character may be ']' (or '-') without being special;
  894:          * the last character may be '-'.
  895:          */
  896:         v = 1 - v;
  897:         for (;;) {
  898:                 tab[c] = v;           /* take character c */
  899: doswitch:
  900:                 n = *fmt++;           /* and examine the next */
  901:                 switch (n) {
  902: 
  903:                 case 0:                       /* format ended too soon */
  904:                         return (fmt - 1);
  905: 
  906:                 case '-':
  907:                         /*
  908:                          * A scanset of the form
  909:                          *   [01+-]
  910:                          * is defined as `the digit 0, the digit 1,
  911:                          * the character +, the character -', but
  912:                          * the effect of a scanset such as
  913:                          *   [a-zA-Z0-9]
  914:                          * is implementation defined.  The V7 Unix
  915:                          * scanf treats `a-z' as `the letters a through
  916:                          * z', but treats `a-a' as `the letter a, the
  917:                          * character -, and the letter a'.
  918:                          *
  919:                          * For compatibility, the `-' is not considerd
  920:                          * to define a range if the character following
  921:                          * it is either a close bracket (required by ANSI)
  922:                          * or is not numerically greater than the character
  923:                          * we just stored in the table (c).
  924:                          */
  925:                         n = *fmt;
  926:                         if (n == ']' || n < c) {
  927:                                 c = '-';
  928:                                 break;      /* resume the for(;;) */
  929:                         }
  930:                         fmt++;
  931:                         do {         /* fill in the range */
  932:                                 tab[++c] = v;
  933:                         } while (c < n);
  934: #if 1   /* XXX another disgusting compatibility hack */
  935:                         /*
  936:                          * Alas, the V7 Unix scanf also treats formats
  937:                          * such as [a-c-e] as `the letters a through e'.
  938:                          * This too is permitted by the standard....
  939:                          */
  940:                         goto doswitch;
  941: #else
  942:                         c = *fmt++;
  943:                         if (c == 0)
  944:                                 return (fmt - 1);
  945:                         if (c == ']')
  946:                                 return (fmt);
  947: #endif
  948:                         break;
  949: 
  950:                 case ']':             /* end of scanset */
  951:                         return (fmt);
  952: 
  953:                 default:              /* just another character */
  954:                         c = n;
  955:                         break;
  956:                 }
  957:         }
  958:         /* NOTREACHED */
  959: }
  960: 
  961: int
  962: vfscanf(FILE *fp, const char *fmt0, __va_list ap)
  963: {
  964:         int r;
  965: 
  966:         FLOCKFILE(fp);
  967:         r = __svfscanf(fp, fmt0, ap);
  968:         FUNLOCKFILE(fp);
  969:         return (r);
  970: }