home *** CD-ROM | disk | FTP | other *** search
/ The CDPD Public Domain Collection for CDTV 3 / CDPDIII.bin / pd / programming / gnuc / stdio_2 / rcs / vfscanf.c,v < prev    next >
Encoding:
Text File  |  1992-07-04  |  17.9 KB  |  784 lines

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