home *** CD-ROM | disk | FTP | other *** search
/ Aminet 18 / aminetcdnumber181997.iso / Aminet / dev / gcc / ixemulsrc.lha / ixemul / stdio / vfscanf.c < prev    next >
C/C++ Source or Header  |  1996-12-11  |  18KB  |  774 lines

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