1*ae115bc7Smrj /* 2*ae115bc7Smrj * CDDL HEADER START 3*ae115bc7Smrj * 4*ae115bc7Smrj * The contents of this file are subject to the terms of the 5*ae115bc7Smrj * Common Development and Distribution License (the "License"). 6*ae115bc7Smrj * You may not use this file except in compliance with the License. 7*ae115bc7Smrj * 8*ae115bc7Smrj * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*ae115bc7Smrj * or http://www.opensolaris.org/os/licensing. 10*ae115bc7Smrj * See the License for the specific language governing permissions 11*ae115bc7Smrj * and limitations under the License. 12*ae115bc7Smrj * 13*ae115bc7Smrj * When distributing Covered Code, include this CDDL HEADER in each 14*ae115bc7Smrj * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*ae115bc7Smrj * If applicable, add the following below this CDDL HEADER, with the 16*ae115bc7Smrj * fields enclosed by brackets "[]" replaced with your own identifying 17*ae115bc7Smrj * information: Portions Copyright [yyyy] [name of copyright owner] 18*ae115bc7Smrj * 19*ae115bc7Smrj * CDDL HEADER END 20*ae115bc7Smrj */ 21*ae115bc7Smrj 22*ae115bc7Smrj /* 23*ae115bc7Smrj * Copyright (c) 1990, 1993 24*ae115bc7Smrj * The Regents of the University of California. All rights reserved. 25*ae115bc7Smrj * 26*ae115bc7Smrj * This code is derived from software contributed to Berkeley by 27*ae115bc7Smrj * Chris Torek. 28*ae115bc7Smrj * 29*ae115bc7Smrj * Redistribution and use in source and binary forms, with or without 30*ae115bc7Smrj * modification, are permitted provided that the following conditions 31*ae115bc7Smrj * are met: 32*ae115bc7Smrj * 1. Redistributions of source code must retain the above copyright 33*ae115bc7Smrj * notice, this list of conditions and the following disclaimer. 34*ae115bc7Smrj * 2. Redistributions in binary form must reproduce the above copyright 35*ae115bc7Smrj * notice, this list of conditions and the following disclaimer in the 36*ae115bc7Smrj * documentation and/or other materials provided with the distribution. 37*ae115bc7Smrj * 4. Neither the name of the University nor the names of its contributors 38*ae115bc7Smrj * may be used to endorse or promote products derived from this software 39*ae115bc7Smrj * without specific prior written permission. 40*ae115bc7Smrj * 41*ae115bc7Smrj * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 42*ae115bc7Smrj * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 43*ae115bc7Smrj * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 44*ae115bc7Smrj * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 45*ae115bc7Smrj * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 46*ae115bc7Smrj * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 47*ae115bc7Smrj * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 48*ae115bc7Smrj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 49*ae115bc7Smrj * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 50*ae115bc7Smrj * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 51*ae115bc7Smrj * SUCH DAMAGE. 52*ae115bc7Smrj * 53*ae115bc7Smrj * From: Id: vfscanf.c,v 1.13 1998/09/25 12:20:27 obrien Exp 54*ae115bc7Smrj * From: static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; 55*ae115bc7Smrj * From: static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93"; 56*ae115bc7Smrj */ 57*ae115bc7Smrj 58*ae115bc7Smrj 59*ae115bc7Smrj /* 60*ae115bc7Smrj * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 61*ae115bc7Smrj * Use is subject to license terms. 62*ae115bc7Smrj */ 63*ae115bc7Smrj 64*ae115bc7Smrj #pragma ident "%Z%%M% %I% %E% SMI" 65*ae115bc7Smrj 66*ae115bc7Smrj #include <sys/types.h> 67*ae115bc7Smrj #include <sys/systm.h> 68*ae115bc7Smrj #include <sys/ctype.h> 69*ae115bc7Smrj #include <sys/sunddi.h> 70*ae115bc7Smrj #include <util/sscanf.h> 71*ae115bc7Smrj 72*ae115bc7Smrj #define BUF 32 /* Maximum length of numeric string. */ 73*ae115bc7Smrj 74*ae115bc7Smrj /* 75*ae115bc7Smrj * Flags used during conversion. 76*ae115bc7Smrj */ 77*ae115bc7Smrj #define LONG 0x01 /* l: long or double */ 78*ae115bc7Smrj #define SHORT 0x04 /* h: short */ 79*ae115bc7Smrj #define SUPPRESS 0x08 /* suppress assignment */ 80*ae115bc7Smrj #define POINTER 0x10 /* weird %p pointer (`fake hex') */ 81*ae115bc7Smrj #define NOSKIP 0x20 /* do not skip blanks */ 82*ae115bc7Smrj 83*ae115bc7Smrj /* 84*ae115bc7Smrj * The following are used in numeric conversions only: 85*ae115bc7Smrj * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; 86*ae115bc7Smrj * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. 87*ae115bc7Smrj */ 88*ae115bc7Smrj #define SIGNOK 0x40 /* +/- is (still) legal */ 89*ae115bc7Smrj #define NDIGITS 0x80 /* no digits detected */ 90*ae115bc7Smrj 91*ae115bc7Smrj #define DPTOK 0x100 /* (float) decimal point is still legal */ 92*ae115bc7Smrj #define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */ 93*ae115bc7Smrj 94*ae115bc7Smrj #define PFXOK 0x100 /* 0x prefix is (still) legal */ 95*ae115bc7Smrj #define NZDIGITS 0x200 /* no zero digits detected */ 96*ae115bc7Smrj 97*ae115bc7Smrj /* 98*ae115bc7Smrj * Conversion types. 99*ae115bc7Smrj */ 100*ae115bc7Smrj #define CT_CHAR 0 /* %c conversion */ 101*ae115bc7Smrj #define CT_CCL 1 /* %[...] conversion */ 102*ae115bc7Smrj #define CT_STRING 2 /* %s conversion */ 103*ae115bc7Smrj #define CT_INT 3 /* integer, i.e., strtoq or strtouq */ 104*ae115bc7Smrj 105*ae115bc7Smrj static const uchar_t *set_ccl(char *, const uchar_t *); 106*ae115bc7Smrj 107*ae115bc7Smrj #define isspace(ch) (((ch) == ' ') || ((ch) == '\r') || ((ch) == '\n') || \ 108*ae115bc7Smrj ((ch) == '\t') || ((ch) == '\f')) 109*ae115bc7Smrj 110*ae115bc7Smrj int 111*ae115bc7Smrj vsscanf(const char *inp, char const *fmt0, va_list ap) 112*ae115bc7Smrj { 113*ae115bc7Smrj int inr; 114*ae115bc7Smrj const uchar_t *fmt = (const uchar_t *)fmt0; 115*ae115bc7Smrj int c; /* character from format, or conversion */ 116*ae115bc7Smrj size_t width; /* field width, or 0 */ 117*ae115bc7Smrj char *p; /* points into all kinds of strings */ 118*ae115bc7Smrj int n; /* handy integer */ 119*ae115bc7Smrj int flags; /* flags as defined above */ 120*ae115bc7Smrj char *p0; /* saves original value of p when necessary */ 121*ae115bc7Smrj int nassigned; /* number of fields assigned */ 122*ae115bc7Smrj int nconversions; /* number of conversions */ 123*ae115bc7Smrj int nread; /* number of characters consumed from fp */ 124*ae115bc7Smrj int base; /* base argument to strtoq/strtouq */ 125*ae115bc7Smrj int sconv; /* do signed conversion */ 126*ae115bc7Smrj char ccltab[256]; /* character class table for %[...] */ 127*ae115bc7Smrj char buf[BUF]; /* buffer for numeric conversions */ 128*ae115bc7Smrj 129*ae115bc7Smrj /* `basefix' is used to avoid `if' tests in the integer scanner */ 130*ae115bc7Smrj static short basefix[17] = 131*ae115bc7Smrj { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 132*ae115bc7Smrj 133*ae115bc7Smrj inr = strlen(inp); 134*ae115bc7Smrj 135*ae115bc7Smrj sconv = 0; 136*ae115bc7Smrj nassigned = 0; 137*ae115bc7Smrj nconversions = 0; 138*ae115bc7Smrj nread = 0; 139*ae115bc7Smrj base = 0; 140*ae115bc7Smrj for (;;) { 141*ae115bc7Smrj c = *fmt++; 142*ae115bc7Smrj if (c == 0) 143*ae115bc7Smrj return (nassigned); 144*ae115bc7Smrj if (isspace(c)) { 145*ae115bc7Smrj while (inr > 0 && isspace(*inp)) 146*ae115bc7Smrj nread++, inr--, inp++; 147*ae115bc7Smrj continue; 148*ae115bc7Smrj } 149*ae115bc7Smrj if (c != '%') 150*ae115bc7Smrj goto literal; 151*ae115bc7Smrj width = 0; 152*ae115bc7Smrj flags = 0; 153*ae115bc7Smrj /* 154*ae115bc7Smrj * switch on the format. continue if done; 155*ae115bc7Smrj * break once format type is derived. 156*ae115bc7Smrj */ 157*ae115bc7Smrj again: c = *fmt++; 158*ae115bc7Smrj switch (c) { 159*ae115bc7Smrj case '%': 160*ae115bc7Smrj literal: 161*ae115bc7Smrj if (inr <= 0) 162*ae115bc7Smrj goto input_failure; 163*ae115bc7Smrj if (*inp != c) 164*ae115bc7Smrj goto match_failure; 165*ae115bc7Smrj inr--, inp++; 166*ae115bc7Smrj nread++; 167*ae115bc7Smrj continue; 168*ae115bc7Smrj 169*ae115bc7Smrj case '*': 170*ae115bc7Smrj flags |= SUPPRESS; 171*ae115bc7Smrj goto again; 172*ae115bc7Smrj case 'l': 173*ae115bc7Smrj flags |= LONG; 174*ae115bc7Smrj goto again; 175*ae115bc7Smrj case 'h': 176*ae115bc7Smrj flags |= SHORT; 177*ae115bc7Smrj goto again; 178*ae115bc7Smrj 179*ae115bc7Smrj case '0': case '1': case '2': case '3': case '4': 180*ae115bc7Smrj case '5': case '6': case '7': case '8': case '9': 181*ae115bc7Smrj width = width * 10 + c - '0'; 182*ae115bc7Smrj goto again; 183*ae115bc7Smrj 184*ae115bc7Smrj /* 185*ae115bc7Smrj * Conversions. 186*ae115bc7Smrj * 187*ae115bc7Smrj */ 188*ae115bc7Smrj case 'd': 189*ae115bc7Smrj c = CT_INT; 190*ae115bc7Smrj sconv = 1; 191*ae115bc7Smrj base = 10; 192*ae115bc7Smrj break; 193*ae115bc7Smrj 194*ae115bc7Smrj case 'i': 195*ae115bc7Smrj c = CT_INT; 196*ae115bc7Smrj sconv = 1; 197*ae115bc7Smrj base = 0; 198*ae115bc7Smrj break; 199*ae115bc7Smrj 200*ae115bc7Smrj case 'o': 201*ae115bc7Smrj c = CT_INT; 202*ae115bc7Smrj base = 8; 203*ae115bc7Smrj break; 204*ae115bc7Smrj 205*ae115bc7Smrj case 'u': 206*ae115bc7Smrj c = CT_INT; 207*ae115bc7Smrj base = 10; 208*ae115bc7Smrj break; 209*ae115bc7Smrj 210*ae115bc7Smrj case 'x': 211*ae115bc7Smrj flags |= PFXOK; /* enable 0x prefixing */ 212*ae115bc7Smrj c = CT_INT; 213*ae115bc7Smrj base = 16; 214*ae115bc7Smrj break; 215*ae115bc7Smrj 216*ae115bc7Smrj case 's': 217*ae115bc7Smrj c = CT_STRING; 218*ae115bc7Smrj break; 219*ae115bc7Smrj 220*ae115bc7Smrj case '[': 221*ae115bc7Smrj fmt = set_ccl(ccltab, fmt); 222*ae115bc7Smrj flags |= NOSKIP; 223*ae115bc7Smrj c = CT_CCL; 224*ae115bc7Smrj break; 225*ae115bc7Smrj 226*ae115bc7Smrj case 'c': 227*ae115bc7Smrj flags |= NOSKIP; 228*ae115bc7Smrj c = CT_CHAR; 229*ae115bc7Smrj break; 230*ae115bc7Smrj 231*ae115bc7Smrj case 'p': /* pointer format is like hex */ 232*ae115bc7Smrj flags |= POINTER | PFXOK; 233*ae115bc7Smrj c = CT_INT; 234*ae115bc7Smrj base = 16; 235*ae115bc7Smrj break; 236*ae115bc7Smrj 237*ae115bc7Smrj case 'n': 238*ae115bc7Smrj nconversions++; 239*ae115bc7Smrj if (flags & SUPPRESS) /* ??? */ 240*ae115bc7Smrj continue; 241*ae115bc7Smrj if (flags & SHORT) 242*ae115bc7Smrj *va_arg(ap, short *) = (short)nread; 243*ae115bc7Smrj else if (flags & LONG) 244*ae115bc7Smrj *va_arg(ap, long *) = (long)nread; 245*ae115bc7Smrj else 246*ae115bc7Smrj *va_arg(ap, int *) = nread; 247*ae115bc7Smrj continue; 248*ae115bc7Smrj } 249*ae115bc7Smrj 250*ae115bc7Smrj /* 251*ae115bc7Smrj * We have a conversion that requires input. 252*ae115bc7Smrj */ 253*ae115bc7Smrj if (inr <= 0) 254*ae115bc7Smrj goto input_failure; 255*ae115bc7Smrj 256*ae115bc7Smrj /* 257*ae115bc7Smrj * Consume leading white space, except for formats 258*ae115bc7Smrj * that suppress this. 259*ae115bc7Smrj */ 260*ae115bc7Smrj if ((flags & NOSKIP) == 0) { 261*ae115bc7Smrj while (isspace(*inp)) { 262*ae115bc7Smrj nread++; 263*ae115bc7Smrj if (--inr > 0) 264*ae115bc7Smrj inp++; 265*ae115bc7Smrj else 266*ae115bc7Smrj goto input_failure; 267*ae115bc7Smrj } 268*ae115bc7Smrj /* 269*ae115bc7Smrj * Note that there is at least one character in 270*ae115bc7Smrj * the buffer, so conversions that do not set NOSKIP 271*ae115bc7Smrj * can no longer result in an input failure. 272*ae115bc7Smrj */ 273*ae115bc7Smrj } 274*ae115bc7Smrj 275*ae115bc7Smrj /* 276*ae115bc7Smrj * Do the conversion. 277*ae115bc7Smrj */ 278*ae115bc7Smrj switch (c) { 279*ae115bc7Smrj 280*ae115bc7Smrj case CT_CHAR: 281*ae115bc7Smrj /* scan arbitrary characters (sets NOSKIP) */ 282*ae115bc7Smrj if (width == 0) 283*ae115bc7Smrj width = 1; 284*ae115bc7Smrj if (flags & SUPPRESS) { 285*ae115bc7Smrj size_t sum = 0; 286*ae115bc7Smrj 287*ae115bc7Smrj if ((n = inr) < width) { 288*ae115bc7Smrj sum += n; 289*ae115bc7Smrj width -= n; 290*ae115bc7Smrj inp += n; 291*ae115bc7Smrj if (sum == 0) 292*ae115bc7Smrj goto input_failure; 293*ae115bc7Smrj } else { 294*ae115bc7Smrj sum += width; 295*ae115bc7Smrj inr -= width; 296*ae115bc7Smrj inp += width; 297*ae115bc7Smrj } 298*ae115bc7Smrj nread += sum; 299*ae115bc7Smrj } else { 300*ae115bc7Smrj bcopy(inp, va_arg(ap, char *), width); 301*ae115bc7Smrj inr -= width; 302*ae115bc7Smrj inp += width; 303*ae115bc7Smrj nread += width; 304*ae115bc7Smrj nassigned++; 305*ae115bc7Smrj } 306*ae115bc7Smrj nconversions++; 307*ae115bc7Smrj break; 308*ae115bc7Smrj 309*ae115bc7Smrj case CT_CCL: 310*ae115bc7Smrj /* scan a (nonempty) character class (sets NOSKIP) */ 311*ae115bc7Smrj if (width == 0) 312*ae115bc7Smrj width = (size_t)~0; /* `infinity' */ 313*ae115bc7Smrj /* take only those things in the class */ 314*ae115bc7Smrj if (flags & SUPPRESS) { 315*ae115bc7Smrj n = 0; 316*ae115bc7Smrj while (ccltab[(unsigned char)*inp]) { 317*ae115bc7Smrj n++, inr--, inp++; 318*ae115bc7Smrj if (--width == 0) 319*ae115bc7Smrj break; 320*ae115bc7Smrj if (inr <= 0) { 321*ae115bc7Smrj if (n == 0) 322*ae115bc7Smrj goto input_failure; 323*ae115bc7Smrj break; 324*ae115bc7Smrj } 325*ae115bc7Smrj } 326*ae115bc7Smrj if (n == 0) 327*ae115bc7Smrj goto match_failure; 328*ae115bc7Smrj } else { 329*ae115bc7Smrj p0 = p = va_arg(ap, char *); 330*ae115bc7Smrj while (ccltab[(unsigned char)*inp]) { 331*ae115bc7Smrj inr--; 332*ae115bc7Smrj *p++ = *inp++; 333*ae115bc7Smrj if (--width == 0) 334*ae115bc7Smrj break; 335*ae115bc7Smrj if (inr <= 0) { 336*ae115bc7Smrj if (p == p0) 337*ae115bc7Smrj goto input_failure; 338*ae115bc7Smrj break; 339*ae115bc7Smrj } 340*ae115bc7Smrj } 341*ae115bc7Smrj n = p - p0; 342*ae115bc7Smrj if (n == 0) 343*ae115bc7Smrj goto match_failure; 344*ae115bc7Smrj *p = 0; 345*ae115bc7Smrj nassigned++; 346*ae115bc7Smrj } 347*ae115bc7Smrj nread += n; 348*ae115bc7Smrj nconversions++; 349*ae115bc7Smrj break; 350*ae115bc7Smrj 351*ae115bc7Smrj case CT_STRING: 352*ae115bc7Smrj /* like CCL, but zero-length string OK, & no NOSKIP */ 353*ae115bc7Smrj if (width == 0) 354*ae115bc7Smrj width = (size_t)~0; 355*ae115bc7Smrj if (flags & SUPPRESS) { 356*ae115bc7Smrj n = 0; 357*ae115bc7Smrj while (!isspace(*inp)) { 358*ae115bc7Smrj n++, inr--, inp++; 359*ae115bc7Smrj if (--width == 0) 360*ae115bc7Smrj break; 361*ae115bc7Smrj if (inr <= 0) 362*ae115bc7Smrj break; 363*ae115bc7Smrj } 364*ae115bc7Smrj nread += n; 365*ae115bc7Smrj } else { 366*ae115bc7Smrj p0 = p = va_arg(ap, char *); 367*ae115bc7Smrj while (!isspace(*inp)) { 368*ae115bc7Smrj inr--; 369*ae115bc7Smrj *p++ = *inp++; 370*ae115bc7Smrj if (--width == 0) 371*ae115bc7Smrj break; 372*ae115bc7Smrj if (inr <= 0) 373*ae115bc7Smrj break; 374*ae115bc7Smrj } 375*ae115bc7Smrj *p = 0; 376*ae115bc7Smrj nread += p - p0; 377*ae115bc7Smrj nassigned++; 378*ae115bc7Smrj } 379*ae115bc7Smrj nconversions++; 380*ae115bc7Smrj continue; 381*ae115bc7Smrj 382*ae115bc7Smrj case CT_INT: 383*ae115bc7Smrj /* scan an integer as if by strtoq/strtouq */ 384*ae115bc7Smrj /* size_t is unsigned, hence this optimisation */ 385*ae115bc7Smrj if (--width > sizeof (buf) - 2) 386*ae115bc7Smrj width = sizeof (buf) - 2; 387*ae115bc7Smrj width++; 388*ae115bc7Smrj flags |= SIGNOK | NDIGITS | NZDIGITS; 389*ae115bc7Smrj for (p = buf; width; width--) { 390*ae115bc7Smrj c = *inp; 391*ae115bc7Smrj /* 392*ae115bc7Smrj * Switch on the character; `goto ok' 393*ae115bc7Smrj * if we accept it as a part of number. 394*ae115bc7Smrj */ 395*ae115bc7Smrj switch (c) { 396*ae115bc7Smrj 397*ae115bc7Smrj /* 398*ae115bc7Smrj * The digit 0 is always legal, but is 399*ae115bc7Smrj * special. For %i conversions, if no 400*ae115bc7Smrj * digits (zero or nonzero) have been 401*ae115bc7Smrj * scanned (only signs), we will have 402*ae115bc7Smrj * base==0. In that case, we should set 403*ae115bc7Smrj * it to 8 and enable 0x prefixing. 404*ae115bc7Smrj * Also, if we have not scanned zero digits 405*ae115bc7Smrj * before this, do not turn off prefixing 406*ae115bc7Smrj * (someone else will turn it off if we 407*ae115bc7Smrj * have scanned any nonzero digits). 408*ae115bc7Smrj */ 409*ae115bc7Smrj case '0': 410*ae115bc7Smrj if (base == 0) { 411*ae115bc7Smrj base = 8; 412*ae115bc7Smrj flags |= PFXOK; 413*ae115bc7Smrj } 414*ae115bc7Smrj if (flags & NZDIGITS) 415*ae115bc7Smrj flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 416*ae115bc7Smrj else 417*ae115bc7Smrj flags &= ~(SIGNOK|PFXOK|NDIGITS); 418*ae115bc7Smrj goto ok; 419*ae115bc7Smrj 420*ae115bc7Smrj /* 1 through 7 always legal */ 421*ae115bc7Smrj case '1': case '2': case '3': 422*ae115bc7Smrj case '4': case '5': case '6': case '7': 423*ae115bc7Smrj base = basefix[base]; 424*ae115bc7Smrj flags &= ~(SIGNOK | PFXOK | NDIGITS); 425*ae115bc7Smrj goto ok; 426*ae115bc7Smrj 427*ae115bc7Smrj /* digits 8 and 9 ok iff decimal or hex */ 428*ae115bc7Smrj case '8': case '9': 429*ae115bc7Smrj base = basefix[base]; 430*ae115bc7Smrj if (base <= 8) 431*ae115bc7Smrj break; /* not legal here */ 432*ae115bc7Smrj flags &= ~(SIGNOK | PFXOK | NDIGITS); 433*ae115bc7Smrj goto ok; 434*ae115bc7Smrj 435*ae115bc7Smrj /* letters ok iff hex */ 436*ae115bc7Smrj case 'A': case 'B': case 'C': 437*ae115bc7Smrj case 'D': case 'E': case 'F': 438*ae115bc7Smrj case 'a': case 'b': case 'c': 439*ae115bc7Smrj case 'd': case 'e': case 'f': 440*ae115bc7Smrj /* no need to fix base here */ 441*ae115bc7Smrj if (base <= 10) 442*ae115bc7Smrj break; /* not legal here */ 443*ae115bc7Smrj flags &= ~(SIGNOK | PFXOK | NDIGITS); 444*ae115bc7Smrj goto ok; 445*ae115bc7Smrj 446*ae115bc7Smrj /* sign ok only as first character */ 447*ae115bc7Smrj case '+': case '-': 448*ae115bc7Smrj if (flags & SIGNOK) { 449*ae115bc7Smrj flags &= ~SIGNOK; 450*ae115bc7Smrj goto ok; 451*ae115bc7Smrj } 452*ae115bc7Smrj break; 453*ae115bc7Smrj 454*ae115bc7Smrj /* x ok iff flag still set & 2nd char */ 455*ae115bc7Smrj case 'x': case 'X': 456*ae115bc7Smrj if (flags & PFXOK && p == buf + 1) { 457*ae115bc7Smrj base = 16; /* if %i */ 458*ae115bc7Smrj flags &= ~PFXOK; 459*ae115bc7Smrj goto ok; 460*ae115bc7Smrj } 461*ae115bc7Smrj break; 462*ae115bc7Smrj } 463*ae115bc7Smrj 464*ae115bc7Smrj /* 465*ae115bc7Smrj * If we got here, c is not a legal character 466*ae115bc7Smrj * for a number. Stop accumulating digits. 467*ae115bc7Smrj */ 468*ae115bc7Smrj break; 469*ae115bc7Smrj ok: 470*ae115bc7Smrj /* 471*ae115bc7Smrj * c is legal: store it and look at the next. 472*ae115bc7Smrj */ 473*ae115bc7Smrj *p++ = c; 474*ae115bc7Smrj if (--inr > 0) 475*ae115bc7Smrj inp++; 476*ae115bc7Smrj else 477*ae115bc7Smrj break; /* end of input */ 478*ae115bc7Smrj } 479*ae115bc7Smrj /* 480*ae115bc7Smrj * If we had only a sign, it is no good; push 481*ae115bc7Smrj * back the sign. If the number ends in `x', 482*ae115bc7Smrj * it was [sign] '0' 'x', so push back the x 483*ae115bc7Smrj * and treat it as [sign] '0'. 484*ae115bc7Smrj */ 485*ae115bc7Smrj if (flags & NDIGITS) { 486*ae115bc7Smrj if (p > buf) { 487*ae115bc7Smrj inp--; 488*ae115bc7Smrj inr++; 489*ae115bc7Smrj } 490*ae115bc7Smrj goto match_failure; 491*ae115bc7Smrj } 492*ae115bc7Smrj c = ((uchar_t *)p)[-1]; 493*ae115bc7Smrj if (c == 'x' || c == 'X') { 494*ae115bc7Smrj --p; 495*ae115bc7Smrj inp--; 496*ae115bc7Smrj inr++; 497*ae115bc7Smrj } 498*ae115bc7Smrj if ((flags & SUPPRESS) == 0) { 499*ae115bc7Smrj ulong_t res; 500*ae115bc7Smrj 501*ae115bc7Smrj *p = 0; 502*ae115bc7Smrj if (sconv) 503*ae115bc7Smrj (void) ddi_strtol(buf, (char **)NULL, 504*ae115bc7Smrj base, (long *)(&res)); 505*ae115bc7Smrj else 506*ae115bc7Smrj (void) ddi_strtoul(buf, (char **)NULL, 507*ae115bc7Smrj base, &res); 508*ae115bc7Smrj if (flags & POINTER) 509*ae115bc7Smrj *va_arg(ap, void **) = 510*ae115bc7Smrj (void *)(uintptr_t)res; 511*ae115bc7Smrj else if (flags & SHORT) 512*ae115bc7Smrj *va_arg(ap, short *) = (short)res; 513*ae115bc7Smrj else if (flags & LONG) 514*ae115bc7Smrj *va_arg(ap, long *) = (long)res; 515*ae115bc7Smrj else 516*ae115bc7Smrj *va_arg(ap, int *) = (int)res; 517*ae115bc7Smrj nassigned++; 518*ae115bc7Smrj } 519*ae115bc7Smrj nread += p - buf; 520*ae115bc7Smrj nconversions++; 521*ae115bc7Smrj break; 522*ae115bc7Smrj 523*ae115bc7Smrj } 524*ae115bc7Smrj } 525*ae115bc7Smrj input_failure: 526*ae115bc7Smrj return (nconversions != 0 ? nassigned : -1); 527*ae115bc7Smrj match_failure: 528*ae115bc7Smrj return (nassigned); 529*ae115bc7Smrj } 530*ae115bc7Smrj 531*ae115bc7Smrj /* 532*ae115bc7Smrj * Fill in the given table from the scanset at the given format 533*ae115bc7Smrj * (just after `['). Return a pointer to the character past the 534*ae115bc7Smrj * closing `]'. The table has a 1 wherever characters should be 535*ae115bc7Smrj * considered part of the scanset. 536*ae115bc7Smrj */ 537*ae115bc7Smrj static const uchar_t * 538*ae115bc7Smrj set_ccl(char *tab, const uchar_t *fmt) 539*ae115bc7Smrj { 540*ae115bc7Smrj int c, n, v; 541*ae115bc7Smrj 542*ae115bc7Smrj /* first `clear' the whole table */ 543*ae115bc7Smrj c = *fmt++; /* first char hat => negated scanset */ 544*ae115bc7Smrj if (c == '^') { 545*ae115bc7Smrj v = 1; /* default => accept */ 546*ae115bc7Smrj c = *fmt++; /* get new first char */ 547*ae115bc7Smrj } else 548*ae115bc7Smrj v = 0; /* default => reject */ 549*ae115bc7Smrj 550*ae115bc7Smrj /* XXX: Will not work if sizeof(tab*) > sizeof(char) */ 551*ae115bc7Smrj for (n = 0; n < 256; n++) 552*ae115bc7Smrj tab[n] = v; /* memset(tab, v, 256) */ 553*ae115bc7Smrj 554*ae115bc7Smrj if (c == 0) 555*ae115bc7Smrj return (fmt - 1); /* format ended before closing ] */ 556*ae115bc7Smrj 557*ae115bc7Smrj /* 558*ae115bc7Smrj * Now set the entries corresponding to the actual scanset 559*ae115bc7Smrj * to the opposite of the above. 560*ae115bc7Smrj * 561*ae115bc7Smrj * The first character may be ']' (or '-') without being special; 562*ae115bc7Smrj * the last character may be '-'. 563*ae115bc7Smrj */ 564*ae115bc7Smrj v = 1 - v; 565*ae115bc7Smrj for (;;) { 566*ae115bc7Smrj tab[c] = v; /* take character c */ 567*ae115bc7Smrj doswitch: 568*ae115bc7Smrj n = *fmt++; /* and examine the next */ 569*ae115bc7Smrj switch (n) { 570*ae115bc7Smrj 571*ae115bc7Smrj case 0: /* format ended too soon */ 572*ae115bc7Smrj return (fmt - 1); 573*ae115bc7Smrj 574*ae115bc7Smrj case '-': 575*ae115bc7Smrj /* 576*ae115bc7Smrj * A scanset of the form 577*ae115bc7Smrj * [01+-] 578*ae115bc7Smrj * is defined as `the digit 0, the digit 1, 579*ae115bc7Smrj * the character +, the character -', but 580*ae115bc7Smrj * the effect of a scanset such as 581*ae115bc7Smrj * [a-zA-Z0-9] 582*ae115bc7Smrj * is implementation defined. The V7 Unix 583*ae115bc7Smrj * scanf treats `a-z' as `the letters a through 584*ae115bc7Smrj * z', but treats `a-a' as `the letter a, the 585*ae115bc7Smrj * character -, and the letter a'. 586*ae115bc7Smrj * 587*ae115bc7Smrj * For compatibility, the `-' is not considerd 588*ae115bc7Smrj * to define a range if the character following 589*ae115bc7Smrj * it is either a close bracket (required by ANSI) 590*ae115bc7Smrj * or is not numerically greater than the character 591*ae115bc7Smrj * we just stored in the table (c). 592*ae115bc7Smrj */ 593*ae115bc7Smrj n = *fmt; 594*ae115bc7Smrj if (n == ']' || n < c) { 595*ae115bc7Smrj c = '-'; 596*ae115bc7Smrj break; /* resume the for(;;) */ 597*ae115bc7Smrj } 598*ae115bc7Smrj fmt++; 599*ae115bc7Smrj /* fill in the range */ 600*ae115bc7Smrj do { 601*ae115bc7Smrj tab[++c] = v; 602*ae115bc7Smrj } while (c < n); 603*ae115bc7Smrj c = n; 604*ae115bc7Smrj /* 605*ae115bc7Smrj * Alas, the V7 Unix scanf also treats formats 606*ae115bc7Smrj * such as [a-c-e] as `the letters a through e'. 607*ae115bc7Smrj * This too is permitted by the standard.... 608*ae115bc7Smrj */ 609*ae115bc7Smrj goto doswitch; 610*ae115bc7Smrj /* NOTREACHED */ 611*ae115bc7Smrj 612*ae115bc7Smrj case ']': /* end of scanset */ 613*ae115bc7Smrj return (fmt); 614*ae115bc7Smrj 615*ae115bc7Smrj default: /* just another character */ 616*ae115bc7Smrj c = n; 617*ae115bc7Smrj break; 618*ae115bc7Smrj } 619*ae115bc7Smrj } 620*ae115bc7Smrj /* NOTREACHED */ 621*ae115bc7Smrj } 622*ae115bc7Smrj 623*ae115bc7Smrj int 624*ae115bc7Smrj sscanf(const char *ibuf, const char *fmt, ...) 625*ae115bc7Smrj { 626*ae115bc7Smrj va_list ap; 627*ae115bc7Smrj int ret; 628*ae115bc7Smrj 629*ae115bc7Smrj va_start(ap, fmt); 630*ae115bc7Smrj ret = vsscanf(ibuf, fmt, ap); 631*ae115bc7Smrj va_end(ap); 632*ae115bc7Smrj return (ret); 633*ae115bc7Smrj } 634