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