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: stable/11/sys/kern/subr_scanf.c 351760 2019-09-03 16:38:52Z mav $"); 39116182Sobrien 4042680Smsmith#include <sys/param.h> 4142680Smsmith#include <sys/systm.h> 4252843Sphk#include <sys/ctype.h> 43114216Skan#include <sys/limits.h> 44351760Smav#include <sys/stddef.h> 4542680Smsmith 4642680Smsmith/* 4742680Smsmith * Note that stdarg.h and the ANSI style va_start macro is used for both 4842680Smsmith * ANSI and traditional C compilers. 4942680Smsmith */ 5042680Smsmith#include <machine/stdarg.h> 5142680Smsmith 5242680Smsmith#define BUF 32 /* Maximum length of numeric string. */ 5342680Smsmith 5442680Smsmith/* 5542680Smsmith * Flags used during conversion. 5642680Smsmith */ 5742680Smsmith#define LONG 0x01 /* l: long or double */ 5842680Smsmith#define SHORT 0x04 /* h: short */ 5942680Smsmith#define SUPPRESS 0x08 /* suppress assignment */ 6042680Smsmith#define POINTER 0x10 /* weird %p pointer (`fake hex') */ 6142680Smsmith#define NOSKIP 0x20 /* do not skip blanks */ 6242680Smsmith#define QUAD 0x400 63351760Smav#define INTMAXT 0x800 /* j: intmax_t */ 64351760Smav#define PTRDIFFT 0x1000 /* t: ptrdiff_t */ 65351760Smav#define SIZET 0x2000 /* z: size_t */ 66230587Sken#define SHORTSHORT 0x4000 /** hh: char */ 6742680Smsmith 6842680Smsmith/* 6942680Smsmith * The following are used in numeric conversions only: 7042680Smsmith * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; 7142680Smsmith * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. 7242680Smsmith */ 7342680Smsmith#define SIGNOK 0x40 /* +/- is (still) legal */ 7442680Smsmith#define NDIGITS 0x80 /* no digits detected */ 7542680Smsmith 7642680Smsmith#define DPTOK 0x100 /* (float) decimal point is still legal */ 7742680Smsmith#define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */ 7842680Smsmith 7942680Smsmith#define PFXOK 0x100 /* 0x prefix is (still) legal */ 8042680Smsmith#define NZDIGITS 0x200 /* no zero digits detected */ 8142680Smsmith 8242680Smsmith/* 8342680Smsmith * Conversion types. 8442680Smsmith */ 8542680Smsmith#define CT_CHAR 0 /* %c conversion */ 8642680Smsmith#define CT_CCL 1 /* %[...] conversion */ 8742680Smsmith#define CT_STRING 2 /* %s conversion */ 8842680Smsmith#define CT_INT 3 /* integer, i.e., strtoq or strtouq */ 8953648Sarchietypedef u_quad_t (*ccfntype)(const char *, char **, int); 9042680Smsmith 9143300Sdillonstatic const u_char *__sccl(char *, const u_char *); 9242680Smsmith 9342680Smsmithint 9442680Smsmithsscanf(const char *ibuf, const char *fmt, ...) 9542680Smsmith{ 9642680Smsmith va_list ap; 9742680Smsmith int ret; 9842680Smsmith 9942680Smsmith va_start(ap, fmt); 10042680Smsmith ret = vsscanf(ibuf, fmt, ap); 10142680Smsmith va_end(ap); 10242680Smsmith return(ret); 10342680Smsmith} 10442680Smsmith 10542680Smsmithint 10642680Smsmithvsscanf(const char *inp, char const *fmt0, va_list ap) 10742680Smsmith{ 10842680Smsmith int inr; 10943300Sdillon const u_char *fmt = (const u_char *)fmt0; 11042680Smsmith int c; /* character from format, or conversion */ 11142680Smsmith size_t width; /* field width, or 0 */ 11242680Smsmith char *p; /* points into all kinds of strings */ 11342680Smsmith int n; /* handy integer */ 11442680Smsmith int flags; /* flags as defined above */ 11542680Smsmith char *p0; /* saves original value of p when necessary */ 11642680Smsmith int nassigned; /* number of fields assigned */ 11742680Smsmith int nconversions; /* number of conversions */ 11842680Smsmith int nread; /* number of characters consumed from fp */ 11942680Smsmith int base; /* base argument to strtoq/strtouq */ 12042680Smsmith ccfntype ccfn; /* conversion function (strtoq/strtouq) */ 12142680Smsmith char ccltab[256]; /* character class table for %[...] */ 12242680Smsmith char buf[BUF]; /* buffer for numeric conversions */ 12342680Smsmith 12442680Smsmith /* `basefix' is used to avoid `if' tests in the integer scanner */ 12542680Smsmith static short basefix[17] = 12642680Smsmith { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 12742680Smsmith 12842680Smsmith inr = strlen(inp); 12942680Smsmith 13042680Smsmith nassigned = 0; 13142680Smsmith nconversions = 0; 13242680Smsmith nread = 0; 13342680Smsmith base = 0; /* XXX just to keep gcc happy */ 13442680Smsmith ccfn = NULL; /* XXX just to keep gcc happy */ 13542680Smsmith for (;;) { 13642680Smsmith c = *fmt++; 13742680Smsmith if (c == 0) 13842680Smsmith return (nassigned); 13942680Smsmith if (isspace(c)) { 14042680Smsmith while (inr > 0 && isspace(*inp)) 14142680Smsmith nread++, inr--, inp++; 14242680Smsmith continue; 14342680Smsmith } 14442680Smsmith if (c != '%') 14542680Smsmith goto literal; 14642680Smsmith width = 0; 14742680Smsmith flags = 0; 14842680Smsmith /* 14942680Smsmith * switch on the format. continue if done; 15042680Smsmith * break once format type is derived. 15142680Smsmith */ 15242680Smsmithagain: c = *fmt++; 15342680Smsmith switch (c) { 15442680Smsmith case '%': 15542680Smsmithliteral: 15642680Smsmith if (inr <= 0) 15742680Smsmith goto input_failure; 15842680Smsmith if (*inp != c) 15942680Smsmith goto match_failure; 16042680Smsmith inr--, inp++; 16142680Smsmith nread++; 16242680Smsmith continue; 16342680Smsmith 16442680Smsmith case '*': 16542680Smsmith flags |= SUPPRESS; 16642680Smsmith goto again; 167351760Smav case 'j': 168351760Smav flags |= INTMAXT; 169351760Smav goto again; 17042680Smsmith case 'l': 171230587Sken if (flags & LONG){ 172230587Sken flags &= ~LONG; 173230587Sken flags |= QUAD; 174230587Sken } else { 175230587Sken flags |= LONG; 176230587Sken } 17742680Smsmith goto again; 17842680Smsmith case 'q': 17942680Smsmith flags |= QUAD; 18042680Smsmith goto again; 181351760Smav case 't': 182351760Smav flags |= PTRDIFFT; 183351760Smav goto again; 184351760Smav case 'z': 185351760Smav flags |= SIZET; 186351760Smav goto again; 18742680Smsmith case 'h': 188230587Sken if (flags & SHORT){ 189230587Sken flags &= ~SHORT; 190230587Sken flags |= SHORTSHORT; 191230587Sken } else { 192230587Sken flags |= SHORT; 193230587Sken } 19442680Smsmith goto again; 19542680Smsmith 19642680Smsmith case '0': case '1': case '2': case '3': case '4': 19742680Smsmith case '5': case '6': case '7': case '8': case '9': 19842680Smsmith width = width * 10 + c - '0'; 19942680Smsmith goto again; 20042680Smsmith 20142680Smsmith /* 20242680Smsmith * Conversions. 20342680Smsmith * 20442680Smsmith */ 20542680Smsmith case 'd': 20642680Smsmith c = CT_INT; 20742680Smsmith ccfn = (ccfntype)strtoq; 20842680Smsmith base = 10; 20942680Smsmith break; 21042680Smsmith 21142680Smsmith case 'i': 21242680Smsmith c = CT_INT; 21342680Smsmith ccfn = (ccfntype)strtoq; 21442680Smsmith base = 0; 21542680Smsmith break; 21642680Smsmith 21742680Smsmith case 'o': 21842680Smsmith c = CT_INT; 21942680Smsmith ccfn = strtouq; 22042680Smsmith base = 8; 22142680Smsmith break; 22242680Smsmith 22342680Smsmith case 'u': 22442680Smsmith c = CT_INT; 22542680Smsmith ccfn = strtouq; 22642680Smsmith base = 10; 22742680Smsmith break; 22842680Smsmith 22942680Smsmith case 'x': 23042680Smsmith flags |= PFXOK; /* enable 0x prefixing */ 23142680Smsmith c = CT_INT; 23242680Smsmith ccfn = strtouq; 23342680Smsmith base = 16; 23442680Smsmith break; 23542680Smsmith 23642680Smsmith case 's': 23742680Smsmith c = CT_STRING; 23842680Smsmith break; 23942680Smsmith 24042680Smsmith case '[': 24142680Smsmith fmt = __sccl(ccltab, fmt); 24242680Smsmith flags |= NOSKIP; 24342680Smsmith c = CT_CCL; 24442680Smsmith break; 24542680Smsmith 24642680Smsmith case 'c': 24742680Smsmith flags |= NOSKIP; 24842680Smsmith c = CT_CHAR; 24942680Smsmith break; 25042680Smsmith 25142680Smsmith case 'p': /* pointer format is like hex */ 25242680Smsmith flags |= POINTER | PFXOK; 25342680Smsmith c = CT_INT; 25442680Smsmith ccfn = strtouq; 25542680Smsmith base = 16; 25642680Smsmith break; 25742680Smsmith 25842680Smsmith case 'n': 25942680Smsmith nconversions++; 26042680Smsmith if (flags & SUPPRESS) /* ??? */ 26142680Smsmith continue; 262230587Sken if (flags & SHORTSHORT) 263230587Sken *va_arg(ap, char *) = nread; 264230587Sken else if (flags & SHORT) 26542680Smsmith *va_arg(ap, short *) = nread; 26642680Smsmith else if (flags & LONG) 26742680Smsmith *va_arg(ap, long *) = nread; 26842680Smsmith else if (flags & QUAD) 26942680Smsmith *va_arg(ap, quad_t *) = nread; 270351760Smav else if (flags & INTMAXT) 271351760Smav *va_arg(ap, intmax_t *) = nread; 272351760Smav else if (flags & SIZET) 273351760Smav *va_arg(ap, size_t *) = nread; 274351760Smav else if (flags & PTRDIFFT) 275351760Smav *va_arg(ap, ptrdiff_t *) = nread; 27642680Smsmith else 27742680Smsmith *va_arg(ap, int *) = nread; 27842680Smsmith continue; 27942680Smsmith } 28042680Smsmith 28142680Smsmith /* 28242680Smsmith * We have a conversion that requires input. 28342680Smsmith */ 28442680Smsmith if (inr <= 0) 28542680Smsmith goto input_failure; 28642680Smsmith 28742680Smsmith /* 28842680Smsmith * Consume leading white space, except for formats 28942680Smsmith * that suppress this. 29042680Smsmith */ 29142680Smsmith if ((flags & NOSKIP) == 0) { 29242680Smsmith while (isspace(*inp)) { 29342680Smsmith nread++; 29442680Smsmith if (--inr > 0) 29542680Smsmith inp++; 29642680Smsmith else 29742680Smsmith goto input_failure; 29842680Smsmith } 29942680Smsmith /* 30042680Smsmith * Note that there is at least one character in 30142680Smsmith * the buffer, so conversions that do not set NOSKIP 30242680Smsmith * can no longer result in an input failure. 30342680Smsmith */ 30442680Smsmith } 30542680Smsmith 30642680Smsmith /* 30742680Smsmith * Do the conversion. 30842680Smsmith */ 30942680Smsmith switch (c) { 31042680Smsmith 31142680Smsmith case CT_CHAR: 31242680Smsmith /* scan arbitrary characters (sets NOSKIP) */ 31342680Smsmith if (width == 0) 31442680Smsmith width = 1; 31542680Smsmith if (flags & SUPPRESS) { 31642680Smsmith size_t sum = 0; 31742680Smsmith for (;;) { 31842680Smsmith if ((n = inr) < width) { 31942680Smsmith sum += n; 32042680Smsmith width -= n; 32142680Smsmith inp += n; 32242680Smsmith if (sum == 0) 32342680Smsmith goto input_failure; 324104363Sphk break; 32542680Smsmith } else { 32642680Smsmith sum += width; 32742680Smsmith inr -= width; 32842680Smsmith inp += width; 32942680Smsmith break; 33042680Smsmith } 33142680Smsmith } 33242680Smsmith nread += sum; 33342680Smsmith } else { 33442680Smsmith bcopy(inp, va_arg(ap, char *), width); 33542680Smsmith inr -= width; 33642680Smsmith inp += width; 33742680Smsmith nread += width; 33842680Smsmith nassigned++; 33942680Smsmith } 34042680Smsmith nconversions++; 34142680Smsmith break; 34242680Smsmith 34342680Smsmith case CT_CCL: 34442680Smsmith /* scan a (nonempty) character class (sets NOSKIP) */ 34542680Smsmith if (width == 0) 34642680Smsmith width = (size_t)~0; /* `infinity' */ 34742680Smsmith /* take only those things in the class */ 34842680Smsmith if (flags & SUPPRESS) { 34942680Smsmith n = 0; 35044016Sdillon while (ccltab[(unsigned char)*inp]) { 35142680Smsmith n++, inr--, inp++; 35242680Smsmith if (--width == 0) 35342680Smsmith break; 35442680Smsmith if (inr <= 0) { 35542680Smsmith if (n == 0) 35642680Smsmith goto input_failure; 35742680Smsmith break; 35842680Smsmith } 35942680Smsmith } 36042680Smsmith if (n == 0) 36142680Smsmith goto match_failure; 36242680Smsmith } else { 36342680Smsmith p0 = p = va_arg(ap, char *); 36444016Sdillon while (ccltab[(unsigned char)*inp]) { 36542680Smsmith inr--; 36642680Smsmith *p++ = *inp++; 36742680Smsmith if (--width == 0) 36842680Smsmith break; 36942680Smsmith if (inr <= 0) { 37042680Smsmith if (p == p0) 37142680Smsmith goto input_failure; 37242680Smsmith break; 37342680Smsmith } 37442680Smsmith } 37542680Smsmith n = p - p0; 37642680Smsmith if (n == 0) 37742680Smsmith goto match_failure; 37842680Smsmith *p = 0; 37942680Smsmith nassigned++; 38042680Smsmith } 38142680Smsmith nread += n; 38242680Smsmith nconversions++; 38342680Smsmith break; 38442680Smsmith 38542680Smsmith case CT_STRING: 38642680Smsmith /* like CCL, but zero-length string OK, & no NOSKIP */ 38742680Smsmith if (width == 0) 38842680Smsmith width = (size_t)~0; 38942680Smsmith if (flags & SUPPRESS) { 39042680Smsmith n = 0; 39142680Smsmith while (!isspace(*inp)) { 39242680Smsmith n++, inr--, inp++; 39342680Smsmith if (--width == 0) 39442680Smsmith break; 39542680Smsmith if (inr <= 0) 39642680Smsmith break; 39742680Smsmith } 39842680Smsmith nread += n; 39942680Smsmith } else { 40042680Smsmith p0 = p = va_arg(ap, char *); 40142680Smsmith while (!isspace(*inp)) { 40242680Smsmith inr--; 40342680Smsmith *p++ = *inp++; 40442680Smsmith if (--width == 0) 40542680Smsmith break; 40642680Smsmith if (inr <= 0) 40742680Smsmith break; 40842680Smsmith } 40942680Smsmith *p = 0; 41042680Smsmith nread += p - p0; 41142680Smsmith nassigned++; 41242680Smsmith } 41342680Smsmith nconversions++; 41442680Smsmith continue; 41542680Smsmith 41642680Smsmith case CT_INT: 41742680Smsmith /* scan an integer as if by strtoq/strtouq */ 41842680Smsmith#ifdef hardway 41942680Smsmith if (width == 0 || width > sizeof(buf) - 1) 42042680Smsmith width = sizeof(buf) - 1; 42142680Smsmith#else 42242680Smsmith /* size_t is unsigned, hence this optimisation */ 42342680Smsmith if (--width > sizeof(buf) - 2) 42442680Smsmith width = sizeof(buf) - 2; 42542680Smsmith width++; 42642680Smsmith#endif 42742680Smsmith flags |= SIGNOK | NDIGITS | NZDIGITS; 42842680Smsmith for (p = buf; width; width--) { 42942680Smsmith c = *inp; 43042680Smsmith /* 43142680Smsmith * Switch on the character; `goto ok' 43242680Smsmith * if we accept it as a part of number. 43342680Smsmith */ 43442680Smsmith switch (c) { 43542680Smsmith 43642680Smsmith /* 43742680Smsmith * The digit 0 is always legal, but is 43842680Smsmith * special. For %i conversions, if no 43942680Smsmith * digits (zero or nonzero) have been 44042680Smsmith * scanned (only signs), we will have 44142680Smsmith * base==0. In that case, we should set 44242680Smsmith * it to 8 and enable 0x prefixing. 44342680Smsmith * Also, if we have not scanned zero digits 44442680Smsmith * before this, do not turn off prefixing 44542680Smsmith * (someone else will turn it off if we 44642680Smsmith * have scanned any nonzero digits). 44742680Smsmith */ 44842680Smsmith case '0': 44942680Smsmith if (base == 0) { 45042680Smsmith base = 8; 45142680Smsmith flags |= PFXOK; 45242680Smsmith } 45342680Smsmith if (flags & NZDIGITS) 45442680Smsmith flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 45542680Smsmith else 45642680Smsmith flags &= ~(SIGNOK|PFXOK|NDIGITS); 45742680Smsmith goto ok; 45842680Smsmith 45942680Smsmith /* 1 through 7 always legal */ 46042680Smsmith case '1': case '2': case '3': 46142680Smsmith case '4': case '5': case '6': case '7': 46242680Smsmith base = basefix[base]; 46342680Smsmith flags &= ~(SIGNOK | PFXOK | NDIGITS); 46442680Smsmith goto ok; 46542680Smsmith 46642680Smsmith /* digits 8 and 9 ok iff decimal or hex */ 46742680Smsmith case '8': case '9': 46842680Smsmith base = basefix[base]; 46942680Smsmith if (base <= 8) 47042680Smsmith break; /* not legal here */ 47142680Smsmith flags &= ~(SIGNOK | PFXOK | NDIGITS); 47242680Smsmith goto ok; 47342680Smsmith 47442680Smsmith /* letters ok iff hex */ 47542680Smsmith case 'A': case 'B': case 'C': 47642680Smsmith case 'D': case 'E': case 'F': 47742680Smsmith case 'a': case 'b': case 'c': 47842680Smsmith case 'd': case 'e': case 'f': 47942680Smsmith /* no need to fix base here */ 48042680Smsmith if (base <= 10) 48142680Smsmith break; /* not legal here */ 48242680Smsmith flags &= ~(SIGNOK | PFXOK | NDIGITS); 48342680Smsmith goto ok; 48442680Smsmith 48542680Smsmith /* sign ok only as first character */ 48642680Smsmith case '+': case '-': 48742680Smsmith if (flags & SIGNOK) { 48842680Smsmith flags &= ~SIGNOK; 48942680Smsmith goto ok; 49042680Smsmith } 49142680Smsmith break; 49242680Smsmith 49342680Smsmith /* x ok iff flag still set & 2nd char */ 49442680Smsmith case 'x': case 'X': 49542680Smsmith if (flags & PFXOK && p == buf + 1) { 49642680Smsmith base = 16; /* if %i */ 49742680Smsmith flags &= ~PFXOK; 49842680Smsmith goto ok; 49942680Smsmith } 50042680Smsmith break; 50142680Smsmith } 50242680Smsmith 50342680Smsmith /* 50442680Smsmith * If we got here, c is not a legal character 50542680Smsmith * for a number. Stop accumulating digits. 50642680Smsmith */ 50742680Smsmith break; 50842680Smsmith ok: 50942680Smsmith /* 51042680Smsmith * c is legal: store it and look at the next. 51142680Smsmith */ 51242680Smsmith *p++ = c; 51342680Smsmith if (--inr > 0) 51442680Smsmith inp++; 51542680Smsmith else 51642680Smsmith break; /* end of input */ 51742680Smsmith } 51842680Smsmith /* 51942680Smsmith * If we had only a sign, it is no good; push 52042680Smsmith * back the sign. If the number ends in `x', 52142680Smsmith * it was [sign] '0' 'x', so push back the x 52242680Smsmith * and treat it as [sign] '0'. 52342680Smsmith */ 52442680Smsmith if (flags & NDIGITS) { 52542680Smsmith if (p > buf) { 52642680Smsmith inp--; 52742680Smsmith inr++; 52842680Smsmith } 52942680Smsmith goto match_failure; 53042680Smsmith } 53142680Smsmith c = ((u_char *)p)[-1]; 53242680Smsmith if (c == 'x' || c == 'X') { 53342680Smsmith --p; 53442680Smsmith inp--; 53542680Smsmith inr++; 53642680Smsmith } 53742680Smsmith if ((flags & SUPPRESS) == 0) { 53842680Smsmith u_quad_t res; 53942680Smsmith 54042680Smsmith *p = 0; 54153648Sarchie res = (*ccfn)(buf, (char **)NULL, base); 54242680Smsmith if (flags & POINTER) 54342680Smsmith *va_arg(ap, void **) = 54450275Sbde (void *)(uintptr_t)res; 545230587Sken else if (flags & SHORTSHORT) 546230587Sken *va_arg(ap, char *) = res; 54742680Smsmith else if (flags & SHORT) 54842680Smsmith *va_arg(ap, short *) = res; 54942680Smsmith else if (flags & LONG) 55042680Smsmith *va_arg(ap, long *) = res; 55142680Smsmith else if (flags & QUAD) 55242680Smsmith *va_arg(ap, quad_t *) = res; 553351760Smav else if (flags & INTMAXT) 554351760Smav *va_arg(ap, intmax_t *) = res; 555351760Smav else if (flags & PTRDIFFT) 556351760Smav *va_arg(ap, ptrdiff_t *) = res; 557351760Smav else if (flags & SIZET) 558351760Smav *va_arg(ap, size_t *) = res; 55942680Smsmith else 56042680Smsmith *va_arg(ap, int *) = res; 56142680Smsmith nassigned++; 56242680Smsmith } 56342680Smsmith nread += p - buf; 56442680Smsmith nconversions++; 56542680Smsmith break; 56642680Smsmith 56742680Smsmith } 56842680Smsmith } 56942680Smsmithinput_failure: 57042680Smsmith return (nconversions != 0 ? nassigned : -1); 57142680Smsmithmatch_failure: 57242680Smsmith return (nassigned); 57342680Smsmith} 57442680Smsmith 57542680Smsmith/* 57642680Smsmith * Fill in the given table from the scanset at the given format 57742680Smsmith * (just after `['). Return a pointer to the character past the 57842680Smsmith * closing `]'. The table has a 1 wherever characters should be 57942680Smsmith * considered part of the scanset. 58042680Smsmith */ 58143300Sdillonstatic const u_char * 58243300Sdillon__sccl(char *tab, const u_char *fmt) 58342680Smsmith{ 58442680Smsmith int c, n, v; 58542680Smsmith 58642680Smsmith /* first `clear' the whole table */ 58742680Smsmith c = *fmt++; /* first char hat => negated scanset */ 58842680Smsmith if (c == '^') { 58942680Smsmith v = 1; /* default => accept */ 59042680Smsmith c = *fmt++; /* get new first char */ 59142680Smsmith } else 59242680Smsmith v = 0; /* default => reject */ 59342680Smsmith 59442680Smsmith /* XXX: Will not work if sizeof(tab*) > sizeof(char) */ 59542680Smsmith for (n = 0; n < 256; n++) 59642680Smsmith tab[n] = v; /* memset(tab, v, 256) */ 59742680Smsmith 59842680Smsmith if (c == 0) 59942680Smsmith return (fmt - 1);/* format ended before closing ] */ 60042680Smsmith 60142680Smsmith /* 60242680Smsmith * Now set the entries corresponding to the actual scanset 60342680Smsmith * to the opposite of the above. 60442680Smsmith * 60542680Smsmith * The first character may be ']' (or '-') without being special; 60642680Smsmith * the last character may be '-'. 60742680Smsmith */ 60842680Smsmith v = 1 - v; 60942680Smsmith for (;;) { 61042680Smsmith tab[c] = v; /* take character c */ 61142680Smsmithdoswitch: 61242680Smsmith n = *fmt++; /* and examine the next */ 61342680Smsmith switch (n) { 61442680Smsmith 61542680Smsmith case 0: /* format ended too soon */ 61642680Smsmith return (fmt - 1); 61742680Smsmith 61842680Smsmith case '-': 61942680Smsmith /* 62042680Smsmith * A scanset of the form 62142680Smsmith * [01+-] 62242680Smsmith * is defined as `the digit 0, the digit 1, 62342680Smsmith * the character +, the character -', but 62442680Smsmith * the effect of a scanset such as 62542680Smsmith * [a-zA-Z0-9] 62642680Smsmith * is implementation defined. The V7 Unix 62742680Smsmith * scanf treats `a-z' as `the letters a through 62842680Smsmith * z', but treats `a-a' as `the letter a, the 62942680Smsmith * character -, and the letter a'. 63042680Smsmith * 631298819Spfg * For compatibility, the `-' is not considered 63242680Smsmith * to define a range if the character following 63342680Smsmith * it is either a close bracket (required by ANSI) 63442680Smsmith * or is not numerically greater than the character 63542680Smsmith * we just stored in the table (c). 63642680Smsmith */ 63742680Smsmith n = *fmt; 63842680Smsmith if (n == ']' || n < c) { 63942680Smsmith c = '-'; 64042680Smsmith break; /* resume the for(;;) */ 64142680Smsmith } 64242680Smsmith fmt++; 64342680Smsmith /* fill in the range */ 64442680Smsmith do { 64542680Smsmith tab[++c] = v; 64642680Smsmith } while (c < n); 64742680Smsmith c = n; 64842680Smsmith /* 64942680Smsmith * Alas, the V7 Unix scanf also treats formats 65042680Smsmith * such as [a-c-e] as `the letters a through e'. 65142680Smsmith * This too is permitted by the standard.... 65242680Smsmith */ 65342680Smsmith goto doswitch; 65442680Smsmith break; 65542680Smsmith 65642680Smsmith case ']': /* end of scanset */ 65742680Smsmith return (fmt); 65842680Smsmith 65942680Smsmith default: /* just another character */ 66042680Smsmith c = n; 66142680Smsmith break; 66242680Smsmith } 66342680Smsmith } 66442680Smsmith /* NOTREACHED */ 66542680Smsmith} 66642680Smsmith 667