subr_scanf.c revision 104363
142680Smsmith/*- 242680Smsmith * Copyright (c) 1990, 1993 342680Smsmith * The Regents of the University of California. All rights reserved. 442680Smsmith * 542680Smsmith * This code is derived from software contributed to Berkeley by 642680Smsmith * Chris Torek. 742680Smsmith * 842680Smsmith * Redistribution and use in source and binary forms, with or without 942680Smsmith * modification, are permitted provided that the following conditions 1042680Smsmith * are met: 1142680Smsmith * 1. Redistributions of source code must retain the above copyright 1242680Smsmith * notice, this list of conditions and the following disclaimer. 1342680Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1442680Smsmith * notice, this list of conditions and the following disclaimer in the 1542680Smsmith * documentation and/or other materials provided with the distribution. 1642680Smsmith * 3. All advertising materials mentioning features or use of this software 1742680Smsmith * must display the following acknowledgement: 1842680Smsmith * This product includes software developed by the University of 1942680Smsmith * California, Berkeley and its contributors. 2042680Smsmith * 4. Neither the name of the University nor the names of its contributors 2142680Smsmith * may be used to endorse or promote products derived from this software 2242680Smsmith * without specific prior written permission. 2342680Smsmith * 2442680Smsmith * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2542680Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2642680Smsmith * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2742680Smsmith * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2842680Smsmith * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2942680Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3042680Smsmith * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3142680Smsmith * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3242680Smsmith * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3342680Smsmith * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3442680Smsmith * SUCH DAMAGE. 3542680Smsmith * 3650477Speter * $FreeBSD: head/sys/kern/subr_scanf.c 104363 2002-10-02 09:09:25Z phk $ 3742680Smsmith * From: Id: vfscanf.c,v 1.13 1998/09/25 12:20:27 obrien Exp 3852757Sphk * From: static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; 3952757Sphk * From: static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93"; 4042680Smsmith */ 4142680Smsmith 4242680Smsmith#include <sys/param.h> 4342680Smsmith#include <sys/systm.h> 4452843Sphk#include <sys/ctype.h> 4542680Smsmith#include <machine/limits.h> 4642680Smsmith 4742680Smsmith/* 4842680Smsmith * Note that stdarg.h and the ANSI style va_start macro is used for both 4942680Smsmith * ANSI and traditional C compilers. 5042680Smsmith */ 5142680Smsmith#include <machine/stdarg.h> 5242680Smsmith 5342680Smsmith#define BUF 32 /* Maximum length of numeric string. */ 5442680Smsmith 5542680Smsmith/* 5642680Smsmith * Flags used during conversion. 5742680Smsmith */ 5842680Smsmith#define LONG 0x01 /* l: long or double */ 5942680Smsmith#define SHORT 0x04 /* h: short */ 6042680Smsmith#define SUPPRESS 0x08 /* suppress assignment */ 6142680Smsmith#define POINTER 0x10 /* weird %p pointer (`fake hex') */ 6242680Smsmith#define NOSKIP 0x20 /* do not skip blanks */ 6342680Smsmith#define QUAD 0x400 6442680Smsmith 6542680Smsmith/* 6642680Smsmith * The following are used in numeric conversions only: 6742680Smsmith * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; 6842680Smsmith * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. 6942680Smsmith */ 7042680Smsmith#define SIGNOK 0x40 /* +/- is (still) legal */ 7142680Smsmith#define NDIGITS 0x80 /* no digits detected */ 7242680Smsmith 7342680Smsmith#define DPTOK 0x100 /* (float) decimal point is still legal */ 7442680Smsmith#define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */ 7542680Smsmith 7642680Smsmith#define PFXOK 0x100 /* 0x prefix is (still) legal */ 7742680Smsmith#define NZDIGITS 0x200 /* no zero digits detected */ 7842680Smsmith 7942680Smsmith/* 8042680Smsmith * Conversion types. 8142680Smsmith */ 8242680Smsmith#define CT_CHAR 0 /* %c conversion */ 8342680Smsmith#define CT_CCL 1 /* %[...] conversion */ 8442680Smsmith#define CT_STRING 2 /* %s conversion */ 8542680Smsmith#define CT_INT 3 /* integer, i.e., strtoq or strtouq */ 8653648Sarchietypedef u_quad_t (*ccfntype)(const char *, char **, int); 8742680Smsmith 8843300Sdillonstatic const u_char *__sccl(char *, const u_char *); 8942680Smsmith 9042680Smsmithint 9142680Smsmithsscanf(const char *ibuf, const char *fmt, ...) 9242680Smsmith{ 9342680Smsmith va_list ap; 9442680Smsmith int ret; 9542680Smsmith 9642680Smsmith va_start(ap, fmt); 9742680Smsmith ret = vsscanf(ibuf, fmt, ap); 9842680Smsmith va_end(ap); 9942680Smsmith return(ret); 10042680Smsmith} 10142680Smsmith 10242680Smsmithint 10342680Smsmithvsscanf(const char *inp, char const *fmt0, va_list ap) 10442680Smsmith{ 10542680Smsmith int inr; 10643300Sdillon const u_char *fmt = (const u_char *)fmt0; 10742680Smsmith int c; /* character from format, or conversion */ 10842680Smsmith size_t width; /* field width, or 0 */ 10942680Smsmith char *p; /* points into all kinds of strings */ 11042680Smsmith int n; /* handy integer */ 11142680Smsmith int flags; /* flags as defined above */ 11242680Smsmith char *p0; /* saves original value of p when necessary */ 11342680Smsmith int nassigned; /* number of fields assigned */ 11442680Smsmith int nconversions; /* number of conversions */ 11542680Smsmith int nread; /* number of characters consumed from fp */ 11642680Smsmith int base; /* base argument to strtoq/strtouq */ 11742680Smsmith ccfntype ccfn; /* conversion function (strtoq/strtouq) */ 11842680Smsmith char ccltab[256]; /* character class table for %[...] */ 11942680Smsmith char buf[BUF]; /* buffer for numeric conversions */ 12042680Smsmith 12142680Smsmith /* `basefix' is used to avoid `if' tests in the integer scanner */ 12242680Smsmith static short basefix[17] = 12342680Smsmith { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 12442680Smsmith 12542680Smsmith inr = strlen(inp); 12642680Smsmith 12742680Smsmith nassigned = 0; 12842680Smsmith nconversions = 0; 12942680Smsmith nread = 0; 13042680Smsmith base = 0; /* XXX just to keep gcc happy */ 13142680Smsmith ccfn = NULL; /* XXX just to keep gcc happy */ 13242680Smsmith for (;;) { 13342680Smsmith c = *fmt++; 13442680Smsmith if (c == 0) 13542680Smsmith return (nassigned); 13642680Smsmith if (isspace(c)) { 13742680Smsmith while (inr > 0 && isspace(*inp)) 13842680Smsmith nread++, inr--, inp++; 13942680Smsmith continue; 14042680Smsmith } 14142680Smsmith if (c != '%') 14242680Smsmith goto literal; 14342680Smsmith width = 0; 14442680Smsmith flags = 0; 14542680Smsmith /* 14642680Smsmith * switch on the format. continue if done; 14742680Smsmith * break once format type is derived. 14842680Smsmith */ 14942680Smsmithagain: c = *fmt++; 15042680Smsmith switch (c) { 15142680Smsmith case '%': 15242680Smsmithliteral: 15342680Smsmith if (inr <= 0) 15442680Smsmith goto input_failure; 15542680Smsmith if (*inp != c) 15642680Smsmith goto match_failure; 15742680Smsmith inr--, inp++; 15842680Smsmith nread++; 15942680Smsmith continue; 16042680Smsmith 16142680Smsmith case '*': 16242680Smsmith flags |= SUPPRESS; 16342680Smsmith goto again; 16442680Smsmith case 'l': 16542680Smsmith flags |= LONG; 16642680Smsmith goto again; 16742680Smsmith case 'q': 16842680Smsmith flags |= QUAD; 16942680Smsmith goto again; 17042680Smsmith case 'h': 17142680Smsmith flags |= SHORT; 17242680Smsmith goto again; 17342680Smsmith 17442680Smsmith case '0': case '1': case '2': case '3': case '4': 17542680Smsmith case '5': case '6': case '7': case '8': case '9': 17642680Smsmith width = width * 10 + c - '0'; 17742680Smsmith goto again; 17842680Smsmith 17942680Smsmith /* 18042680Smsmith * Conversions. 18142680Smsmith * 18242680Smsmith */ 18342680Smsmith case 'd': 18442680Smsmith c = CT_INT; 18542680Smsmith ccfn = (ccfntype)strtoq; 18642680Smsmith base = 10; 18742680Smsmith break; 18842680Smsmith 18942680Smsmith case 'i': 19042680Smsmith c = CT_INT; 19142680Smsmith ccfn = (ccfntype)strtoq; 19242680Smsmith base = 0; 19342680Smsmith break; 19442680Smsmith 19542680Smsmith case 'o': 19642680Smsmith c = CT_INT; 19742680Smsmith ccfn = strtouq; 19842680Smsmith base = 8; 19942680Smsmith break; 20042680Smsmith 20142680Smsmith case 'u': 20242680Smsmith c = CT_INT; 20342680Smsmith ccfn = strtouq; 20442680Smsmith base = 10; 20542680Smsmith break; 20642680Smsmith 20742680Smsmith case 'x': 20842680Smsmith flags |= PFXOK; /* enable 0x prefixing */ 20942680Smsmith c = CT_INT; 21042680Smsmith ccfn = strtouq; 21142680Smsmith base = 16; 21242680Smsmith break; 21342680Smsmith 21442680Smsmith case 's': 21542680Smsmith c = CT_STRING; 21642680Smsmith break; 21742680Smsmith 21842680Smsmith case '[': 21942680Smsmith fmt = __sccl(ccltab, fmt); 22042680Smsmith flags |= NOSKIP; 22142680Smsmith c = CT_CCL; 22242680Smsmith break; 22342680Smsmith 22442680Smsmith case 'c': 22542680Smsmith flags |= NOSKIP; 22642680Smsmith c = CT_CHAR; 22742680Smsmith break; 22842680Smsmith 22942680Smsmith case 'p': /* pointer format is like hex */ 23042680Smsmith flags |= POINTER | PFXOK; 23142680Smsmith c = CT_INT; 23242680Smsmith ccfn = strtouq; 23342680Smsmith base = 16; 23442680Smsmith break; 23542680Smsmith 23642680Smsmith case 'n': 23742680Smsmith nconversions++; 23842680Smsmith if (flags & SUPPRESS) /* ??? */ 23942680Smsmith continue; 24042680Smsmith if (flags & SHORT) 24142680Smsmith *va_arg(ap, short *) = nread; 24242680Smsmith else if (flags & LONG) 24342680Smsmith *va_arg(ap, long *) = nread; 24442680Smsmith else if (flags & QUAD) 24542680Smsmith *va_arg(ap, quad_t *) = nread; 24642680Smsmith else 24742680Smsmith *va_arg(ap, int *) = nread; 24842680Smsmith continue; 24942680Smsmith } 25042680Smsmith 25142680Smsmith /* 25242680Smsmith * We have a conversion that requires input. 25342680Smsmith */ 25442680Smsmith if (inr <= 0) 25542680Smsmith goto input_failure; 25642680Smsmith 25742680Smsmith /* 25842680Smsmith * Consume leading white space, except for formats 25942680Smsmith * that suppress this. 26042680Smsmith */ 26142680Smsmith if ((flags & NOSKIP) == 0) { 26242680Smsmith while (isspace(*inp)) { 26342680Smsmith nread++; 26442680Smsmith if (--inr > 0) 26542680Smsmith inp++; 26642680Smsmith else 26742680Smsmith goto input_failure; 26842680Smsmith } 26942680Smsmith /* 27042680Smsmith * Note that there is at least one character in 27142680Smsmith * the buffer, so conversions that do not set NOSKIP 27242680Smsmith * can no longer result in an input failure. 27342680Smsmith */ 27442680Smsmith } 27542680Smsmith 27642680Smsmith /* 27742680Smsmith * Do the conversion. 27842680Smsmith */ 27942680Smsmith switch (c) { 28042680Smsmith 28142680Smsmith case CT_CHAR: 28242680Smsmith /* scan arbitrary characters (sets NOSKIP) */ 28342680Smsmith if (width == 0) 28442680Smsmith width = 1; 28542680Smsmith if (flags & SUPPRESS) { 28642680Smsmith size_t sum = 0; 28742680Smsmith for (;;) { 28842680Smsmith if ((n = inr) < width) { 28942680Smsmith sum += n; 29042680Smsmith width -= n; 29142680Smsmith inp += n; 29242680Smsmith if (sum == 0) 29342680Smsmith goto input_failure; 294104363Sphk break; 29542680Smsmith } else { 29642680Smsmith sum += width; 29742680Smsmith inr -= width; 29842680Smsmith inp += width; 29942680Smsmith break; 30042680Smsmith } 30142680Smsmith } 30242680Smsmith nread += sum; 30342680Smsmith } else { 30442680Smsmith bcopy(inp, va_arg(ap, char *), width); 30542680Smsmith inr -= width; 30642680Smsmith inp += width; 30742680Smsmith nread += width; 30842680Smsmith nassigned++; 30942680Smsmith } 31042680Smsmith nconversions++; 31142680Smsmith break; 31242680Smsmith 31342680Smsmith case CT_CCL: 31442680Smsmith /* scan a (nonempty) character class (sets NOSKIP) */ 31542680Smsmith if (width == 0) 31642680Smsmith width = (size_t)~0; /* `infinity' */ 31742680Smsmith /* take only those things in the class */ 31842680Smsmith if (flags & SUPPRESS) { 31942680Smsmith n = 0; 32044016Sdillon while (ccltab[(unsigned char)*inp]) { 32142680Smsmith n++, inr--, inp++; 32242680Smsmith if (--width == 0) 32342680Smsmith break; 32442680Smsmith if (inr <= 0) { 32542680Smsmith if (n == 0) 32642680Smsmith goto input_failure; 32742680Smsmith break; 32842680Smsmith } 32942680Smsmith } 33042680Smsmith if (n == 0) 33142680Smsmith goto match_failure; 33242680Smsmith } else { 33342680Smsmith p0 = p = va_arg(ap, char *); 33444016Sdillon while (ccltab[(unsigned char)*inp]) { 33542680Smsmith inr--; 33642680Smsmith *p++ = *inp++; 33742680Smsmith if (--width == 0) 33842680Smsmith break; 33942680Smsmith if (inr <= 0) { 34042680Smsmith if (p == p0) 34142680Smsmith goto input_failure; 34242680Smsmith break; 34342680Smsmith } 34442680Smsmith } 34542680Smsmith n = p - p0; 34642680Smsmith if (n == 0) 34742680Smsmith goto match_failure; 34842680Smsmith *p = 0; 34942680Smsmith nassigned++; 35042680Smsmith } 35142680Smsmith nread += n; 35242680Smsmith nconversions++; 35342680Smsmith break; 35442680Smsmith 35542680Smsmith case CT_STRING: 35642680Smsmith /* like CCL, but zero-length string OK, & no NOSKIP */ 35742680Smsmith if (width == 0) 35842680Smsmith width = (size_t)~0; 35942680Smsmith if (flags & SUPPRESS) { 36042680Smsmith n = 0; 36142680Smsmith while (!isspace(*inp)) { 36242680Smsmith n++, inr--, inp++; 36342680Smsmith if (--width == 0) 36442680Smsmith break; 36542680Smsmith if (inr <= 0) 36642680Smsmith break; 36742680Smsmith } 36842680Smsmith nread += n; 36942680Smsmith } else { 37042680Smsmith p0 = p = va_arg(ap, char *); 37142680Smsmith while (!isspace(*inp)) { 37242680Smsmith inr--; 37342680Smsmith *p++ = *inp++; 37442680Smsmith if (--width == 0) 37542680Smsmith break; 37642680Smsmith if (inr <= 0) 37742680Smsmith break; 37842680Smsmith } 37942680Smsmith *p = 0; 38042680Smsmith nread += p - p0; 38142680Smsmith nassigned++; 38242680Smsmith } 38342680Smsmith nconversions++; 38442680Smsmith continue; 38542680Smsmith 38642680Smsmith case CT_INT: 38742680Smsmith /* scan an integer as if by strtoq/strtouq */ 38842680Smsmith#ifdef hardway 38942680Smsmith if (width == 0 || width > sizeof(buf) - 1) 39042680Smsmith width = sizeof(buf) - 1; 39142680Smsmith#else 39242680Smsmith /* size_t is unsigned, hence this optimisation */ 39342680Smsmith if (--width > sizeof(buf) - 2) 39442680Smsmith width = sizeof(buf) - 2; 39542680Smsmith width++; 39642680Smsmith#endif 39742680Smsmith flags |= SIGNOK | NDIGITS | NZDIGITS; 39842680Smsmith for (p = buf; width; width--) { 39942680Smsmith c = *inp; 40042680Smsmith /* 40142680Smsmith * Switch on the character; `goto ok' 40242680Smsmith * if we accept it as a part of number. 40342680Smsmith */ 40442680Smsmith switch (c) { 40542680Smsmith 40642680Smsmith /* 40742680Smsmith * The digit 0 is always legal, but is 40842680Smsmith * special. For %i conversions, if no 40942680Smsmith * digits (zero or nonzero) have been 41042680Smsmith * scanned (only signs), we will have 41142680Smsmith * base==0. In that case, we should set 41242680Smsmith * it to 8 and enable 0x prefixing. 41342680Smsmith * Also, if we have not scanned zero digits 41442680Smsmith * before this, do not turn off prefixing 41542680Smsmith * (someone else will turn it off if we 41642680Smsmith * have scanned any nonzero digits). 41742680Smsmith */ 41842680Smsmith case '0': 41942680Smsmith if (base == 0) { 42042680Smsmith base = 8; 42142680Smsmith flags |= PFXOK; 42242680Smsmith } 42342680Smsmith if (flags & NZDIGITS) 42442680Smsmith flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 42542680Smsmith else 42642680Smsmith flags &= ~(SIGNOK|PFXOK|NDIGITS); 42742680Smsmith goto ok; 42842680Smsmith 42942680Smsmith /* 1 through 7 always legal */ 43042680Smsmith case '1': case '2': case '3': 43142680Smsmith case '4': case '5': case '6': case '7': 43242680Smsmith base = basefix[base]; 43342680Smsmith flags &= ~(SIGNOK | PFXOK | NDIGITS); 43442680Smsmith goto ok; 43542680Smsmith 43642680Smsmith /* digits 8 and 9 ok iff decimal or hex */ 43742680Smsmith case '8': case '9': 43842680Smsmith base = basefix[base]; 43942680Smsmith if (base <= 8) 44042680Smsmith break; /* not legal here */ 44142680Smsmith flags &= ~(SIGNOK | PFXOK | NDIGITS); 44242680Smsmith goto ok; 44342680Smsmith 44442680Smsmith /* letters ok iff hex */ 44542680Smsmith case 'A': case 'B': case 'C': 44642680Smsmith case 'D': case 'E': case 'F': 44742680Smsmith case 'a': case 'b': case 'c': 44842680Smsmith case 'd': case 'e': case 'f': 44942680Smsmith /* no need to fix base here */ 45042680Smsmith if (base <= 10) 45142680Smsmith break; /* not legal here */ 45242680Smsmith flags &= ~(SIGNOK | PFXOK | NDIGITS); 45342680Smsmith goto ok; 45442680Smsmith 45542680Smsmith /* sign ok only as first character */ 45642680Smsmith case '+': case '-': 45742680Smsmith if (flags & SIGNOK) { 45842680Smsmith flags &= ~SIGNOK; 45942680Smsmith goto ok; 46042680Smsmith } 46142680Smsmith break; 46242680Smsmith 46342680Smsmith /* x ok iff flag still set & 2nd char */ 46442680Smsmith case 'x': case 'X': 46542680Smsmith if (flags & PFXOK && p == buf + 1) { 46642680Smsmith base = 16; /* if %i */ 46742680Smsmith flags &= ~PFXOK; 46842680Smsmith goto ok; 46942680Smsmith } 47042680Smsmith break; 47142680Smsmith } 47242680Smsmith 47342680Smsmith /* 47442680Smsmith * If we got here, c is not a legal character 47542680Smsmith * for a number. Stop accumulating digits. 47642680Smsmith */ 47742680Smsmith break; 47842680Smsmith ok: 47942680Smsmith /* 48042680Smsmith * c is legal: store it and look at the next. 48142680Smsmith */ 48242680Smsmith *p++ = c; 48342680Smsmith if (--inr > 0) 48442680Smsmith inp++; 48542680Smsmith else 48642680Smsmith break; /* end of input */ 48742680Smsmith } 48842680Smsmith /* 48942680Smsmith * If we had only a sign, it is no good; push 49042680Smsmith * back the sign. If the number ends in `x', 49142680Smsmith * it was [sign] '0' 'x', so push back the x 49242680Smsmith * and treat it as [sign] '0'. 49342680Smsmith */ 49442680Smsmith if (flags & NDIGITS) { 49542680Smsmith if (p > buf) { 49642680Smsmith inp--; 49742680Smsmith inr++; 49842680Smsmith } 49942680Smsmith goto match_failure; 50042680Smsmith } 50142680Smsmith c = ((u_char *)p)[-1]; 50242680Smsmith if (c == 'x' || c == 'X') { 50342680Smsmith --p; 50442680Smsmith inp--; 50542680Smsmith inr++; 50642680Smsmith } 50742680Smsmith if ((flags & SUPPRESS) == 0) { 50842680Smsmith u_quad_t res; 50942680Smsmith 51042680Smsmith *p = 0; 51153648Sarchie res = (*ccfn)(buf, (char **)NULL, base); 51242680Smsmith if (flags & POINTER) 51342680Smsmith *va_arg(ap, void **) = 51450275Sbde (void *)(uintptr_t)res; 51542680Smsmith else if (flags & SHORT) 51642680Smsmith *va_arg(ap, short *) = res; 51742680Smsmith else if (flags & LONG) 51842680Smsmith *va_arg(ap, long *) = res; 51942680Smsmith else if (flags & QUAD) 52042680Smsmith *va_arg(ap, quad_t *) = res; 52142680Smsmith else 52242680Smsmith *va_arg(ap, int *) = res; 52342680Smsmith nassigned++; 52442680Smsmith } 52542680Smsmith nread += p - buf; 52642680Smsmith nconversions++; 52742680Smsmith break; 52842680Smsmith 52942680Smsmith } 53042680Smsmith } 53142680Smsmithinput_failure: 53242680Smsmith return (nconversions != 0 ? nassigned : -1); 53342680Smsmithmatch_failure: 53442680Smsmith return (nassigned); 53542680Smsmith} 53642680Smsmith 53742680Smsmith/* 53842680Smsmith * Fill in the given table from the scanset at the given format 53942680Smsmith * (just after `['). Return a pointer to the character past the 54042680Smsmith * closing `]'. The table has a 1 wherever characters should be 54142680Smsmith * considered part of the scanset. 54242680Smsmith */ 54343300Sdillonstatic const u_char * 54443300Sdillon__sccl(char *tab, const u_char *fmt) 54542680Smsmith{ 54642680Smsmith int c, n, v; 54742680Smsmith 54842680Smsmith /* first `clear' the whole table */ 54942680Smsmith c = *fmt++; /* first char hat => negated scanset */ 55042680Smsmith if (c == '^') { 55142680Smsmith v = 1; /* default => accept */ 55242680Smsmith c = *fmt++; /* get new first char */ 55342680Smsmith } else 55442680Smsmith v = 0; /* default => reject */ 55542680Smsmith 55642680Smsmith /* XXX: Will not work if sizeof(tab*) > sizeof(char) */ 55742680Smsmith for (n = 0; n < 256; n++) 55842680Smsmith tab[n] = v; /* memset(tab, v, 256) */ 55942680Smsmith 56042680Smsmith if (c == 0) 56142680Smsmith return (fmt - 1);/* format ended before closing ] */ 56242680Smsmith 56342680Smsmith /* 56442680Smsmith * Now set the entries corresponding to the actual scanset 56542680Smsmith * to the opposite of the above. 56642680Smsmith * 56742680Smsmith * The first character may be ']' (or '-') without being special; 56842680Smsmith * the last character may be '-'. 56942680Smsmith */ 57042680Smsmith v = 1 - v; 57142680Smsmith for (;;) { 57242680Smsmith tab[c] = v; /* take character c */ 57342680Smsmithdoswitch: 57442680Smsmith n = *fmt++; /* and examine the next */ 57542680Smsmith switch (n) { 57642680Smsmith 57742680Smsmith case 0: /* format ended too soon */ 57842680Smsmith return (fmt - 1); 57942680Smsmith 58042680Smsmith case '-': 58142680Smsmith /* 58242680Smsmith * A scanset of the form 58342680Smsmith * [01+-] 58442680Smsmith * is defined as `the digit 0, the digit 1, 58542680Smsmith * the character +, the character -', but 58642680Smsmith * the effect of a scanset such as 58742680Smsmith * [a-zA-Z0-9] 58842680Smsmith * is implementation defined. The V7 Unix 58942680Smsmith * scanf treats `a-z' as `the letters a through 59042680Smsmith * z', but treats `a-a' as `the letter a, the 59142680Smsmith * character -, and the letter a'. 59242680Smsmith * 59342680Smsmith * For compatibility, the `-' is not considerd 59442680Smsmith * to define a range if the character following 59542680Smsmith * it is either a close bracket (required by ANSI) 59642680Smsmith * or is not numerically greater than the character 59742680Smsmith * we just stored in the table (c). 59842680Smsmith */ 59942680Smsmith n = *fmt; 60042680Smsmith if (n == ']' || n < c) { 60142680Smsmith c = '-'; 60242680Smsmith break; /* resume the for(;;) */ 60342680Smsmith } 60442680Smsmith fmt++; 60542680Smsmith /* fill in the range */ 60642680Smsmith do { 60742680Smsmith tab[++c] = v; 60842680Smsmith } while (c < n); 60942680Smsmith c = n; 61042680Smsmith /* 61142680Smsmith * Alas, the V7 Unix scanf also treats formats 61242680Smsmith * such as [a-c-e] as `the letters a through e'. 61342680Smsmith * This too is permitted by the standard.... 61442680Smsmith */ 61542680Smsmith goto doswitch; 61642680Smsmith break; 61742680Smsmith 61842680Smsmith case ']': /* end of scanset */ 61942680Smsmith return (fmt); 62042680Smsmith 62142680Smsmith default: /* just another character */ 62242680Smsmith c = n; 62342680Smsmith break; 62442680Smsmith } 62542680Smsmith } 62642680Smsmith /* NOTREACHED */ 62742680Smsmith} 62842680Smsmith 629