1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * Copyright (c) 2000-2001, 2004 Sendmail, Inc. and its suppliers. 3*7c478bd9Sstevel@tonic-gate * All rights reserved. 4*7c478bd9Sstevel@tonic-gate * Copyright (c) 1990, 1993 5*7c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 6*7c478bd9Sstevel@tonic-gate * 7*7c478bd9Sstevel@tonic-gate * This code is derived from software contributed to Berkeley by 8*7c478bd9Sstevel@tonic-gate * Chris Torek. 9*7c478bd9Sstevel@tonic-gate * 10*7c478bd9Sstevel@tonic-gate * By using this file, you agree to the terms and conditions set 11*7c478bd9Sstevel@tonic-gate * forth in the LICENSE file which can be found at the top level of 12*7c478bd9Sstevel@tonic-gate * the sendmail distribution. 13*7c478bd9Sstevel@tonic-gate */ 14*7c478bd9Sstevel@tonic-gate 15*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 16*7c478bd9Sstevel@tonic-gate 17*7c478bd9Sstevel@tonic-gate #include <sm/gen.h> 18*7c478bd9Sstevel@tonic-gate SM_IDSTR(id, "@(#)$Id: vfscanf.c,v 1.52 2004/08/03 20:56:32 ca Exp $") 19*7c478bd9Sstevel@tonic-gate 20*7c478bd9Sstevel@tonic-gate #include <ctype.h> 21*7c478bd9Sstevel@tonic-gate #include <stdlib.h> 22*7c478bd9Sstevel@tonic-gate #include <errno.h> 23*7c478bd9Sstevel@tonic-gate #include <setjmp.h> 24*7c478bd9Sstevel@tonic-gate #include <sys/time.h> 25*7c478bd9Sstevel@tonic-gate #include <sm/varargs.h> 26*7c478bd9Sstevel@tonic-gate #include <sm/config.h> 27*7c478bd9Sstevel@tonic-gate #include <sm/io.h> 28*7c478bd9Sstevel@tonic-gate #include <sm/signal.h> 29*7c478bd9Sstevel@tonic-gate #include <sm/clock.h> 30*7c478bd9Sstevel@tonic-gate #include <sm/string.h> 31*7c478bd9Sstevel@tonic-gate #include "local.h" 32*7c478bd9Sstevel@tonic-gate 33*7c478bd9Sstevel@tonic-gate #define BUF 513 /* Maximum length of numeric string. */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate /* Flags used during conversion. */ 36*7c478bd9Sstevel@tonic-gate #define LONG 0x01 /* l: long or double */ 37*7c478bd9Sstevel@tonic-gate #define SHORT 0x04 /* h: short */ 38*7c478bd9Sstevel@tonic-gate #define QUAD 0x08 /* q: quad (same as ll) */ 39*7c478bd9Sstevel@tonic-gate #define SUPPRESS 0x10 /* suppress assignment */ 40*7c478bd9Sstevel@tonic-gate #define POINTER 0x20 /* weird %p pointer (`fake hex') */ 41*7c478bd9Sstevel@tonic-gate #define NOSKIP 0x40 /* do not skip blanks */ 42*7c478bd9Sstevel@tonic-gate 43*7c478bd9Sstevel@tonic-gate /* 44*7c478bd9Sstevel@tonic-gate ** The following are used in numeric conversions only: 45*7c478bd9Sstevel@tonic-gate ** SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; 46*7c478bd9Sstevel@tonic-gate ** SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. 47*7c478bd9Sstevel@tonic-gate */ 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate #define SIGNOK 0x080 /* +/- is (still) legal */ 50*7c478bd9Sstevel@tonic-gate #define NDIGITS 0x100 /* no digits detected */ 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate #define DPTOK 0x200 /* (float) decimal point is still legal */ 53*7c478bd9Sstevel@tonic-gate #define EXPOK 0x400 /* (float) exponent (e+3, etc) still legal */ 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate #define PFXOK 0x200 /* 0x prefix is (still) legal */ 56*7c478bd9Sstevel@tonic-gate #define NZDIGITS 0x400 /* no zero digits detected */ 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate /* Conversion types. */ 59*7c478bd9Sstevel@tonic-gate #define CT_CHAR 0 /* %c conversion */ 60*7c478bd9Sstevel@tonic-gate #define CT_CCL 1 /* %[...] conversion */ 61*7c478bd9Sstevel@tonic-gate #define CT_STRING 2 /* %s conversion */ 62*7c478bd9Sstevel@tonic-gate #define CT_INT 3 /* integer, i.e., strtoll or strtoull */ 63*7c478bd9Sstevel@tonic-gate #define CT_FLOAT 4 /* floating, i.e., strtod */ 64*7c478bd9Sstevel@tonic-gate 65*7c478bd9Sstevel@tonic-gate static void scanalrm __P((int)); 66*7c478bd9Sstevel@tonic-gate static unsigned char *sm_sccl __P((char *, unsigned char *)); 67*7c478bd9Sstevel@tonic-gate static jmp_buf ScanTimeOut; 68*7c478bd9Sstevel@tonic-gate 69*7c478bd9Sstevel@tonic-gate /* 70*7c478bd9Sstevel@tonic-gate ** SCANALRM -- handler when timeout activated for sm_io_vfscanf() 71*7c478bd9Sstevel@tonic-gate ** 72*7c478bd9Sstevel@tonic-gate ** Returns flow of control to where setjmp(ScanTimeOut) was set. 73*7c478bd9Sstevel@tonic-gate ** 74*7c478bd9Sstevel@tonic-gate ** Parameters: 75*7c478bd9Sstevel@tonic-gate ** sig -- unused 76*7c478bd9Sstevel@tonic-gate ** 77*7c478bd9Sstevel@tonic-gate ** Returns: 78*7c478bd9Sstevel@tonic-gate ** does not return 79*7c478bd9Sstevel@tonic-gate ** 80*7c478bd9Sstevel@tonic-gate ** Side Effects: 81*7c478bd9Sstevel@tonic-gate ** returns flow of control to setjmp(ScanTimeOut). 82*7c478bd9Sstevel@tonic-gate ** 83*7c478bd9Sstevel@tonic-gate ** NOTE: THIS CAN BE CALLED FROM A SIGNAL HANDLER. DO NOT ADD 84*7c478bd9Sstevel@tonic-gate ** ANYTHING TO THIS ROUTINE UNLESS YOU KNOW WHAT YOU ARE 85*7c478bd9Sstevel@tonic-gate ** DOING. 86*7c478bd9Sstevel@tonic-gate */ 87*7c478bd9Sstevel@tonic-gate 88*7c478bd9Sstevel@tonic-gate /* ARGSUSED0 */ 89*7c478bd9Sstevel@tonic-gate static void 90*7c478bd9Sstevel@tonic-gate scanalrm(sig) 91*7c478bd9Sstevel@tonic-gate int sig; 92*7c478bd9Sstevel@tonic-gate { 93*7c478bd9Sstevel@tonic-gate longjmp(ScanTimeOut, 1); 94*7c478bd9Sstevel@tonic-gate } 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate /* 97*7c478bd9Sstevel@tonic-gate ** SM_VFSCANF -- convert input into data units 98*7c478bd9Sstevel@tonic-gate ** 99*7c478bd9Sstevel@tonic-gate ** Parameters: 100*7c478bd9Sstevel@tonic-gate ** fp -- file pointer for input data 101*7c478bd9Sstevel@tonic-gate ** timeout -- time intvl allowed to complete (milliseconds) 102*7c478bd9Sstevel@tonic-gate ** fmt0 -- format for finding data units 103*7c478bd9Sstevel@tonic-gate ** ap -- vectors for memory location for storing data units 104*7c478bd9Sstevel@tonic-gate ** 105*7c478bd9Sstevel@tonic-gate ** Results: 106*7c478bd9Sstevel@tonic-gate ** Success: number of data units assigned 107*7c478bd9Sstevel@tonic-gate ** Failure: SM_IO_EOF 108*7c478bd9Sstevel@tonic-gate */ 109*7c478bd9Sstevel@tonic-gate 110*7c478bd9Sstevel@tonic-gate int 111*7c478bd9Sstevel@tonic-gate sm_vfscanf(fp, timeout, fmt0, ap) 112*7c478bd9Sstevel@tonic-gate register SM_FILE_T *fp; 113*7c478bd9Sstevel@tonic-gate int SM_NONVOLATILE timeout; 114*7c478bd9Sstevel@tonic-gate char const *fmt0; 115*7c478bd9Sstevel@tonic-gate va_list SM_NONVOLATILE ap; 116*7c478bd9Sstevel@tonic-gate { 117*7c478bd9Sstevel@tonic-gate register unsigned char *SM_NONVOLATILE fmt = (unsigned char *) fmt0; 118*7c478bd9Sstevel@tonic-gate register int c; /* character from format, or conversion */ 119*7c478bd9Sstevel@tonic-gate register size_t width; /* field width, or 0 */ 120*7c478bd9Sstevel@tonic-gate register char *p; /* points into all kinds of strings */ 121*7c478bd9Sstevel@tonic-gate register int n; /* handy integer */ 122*7c478bd9Sstevel@tonic-gate register int flags; /* flags as defined above */ 123*7c478bd9Sstevel@tonic-gate register char *p0; /* saves original value of p when necessary */ 124*7c478bd9Sstevel@tonic-gate int nassigned; /* number of fields assigned */ 125*7c478bd9Sstevel@tonic-gate int nread; /* number of characters consumed from fp */ 126*7c478bd9Sstevel@tonic-gate int base; /* base argument to strtoll/strtoull */ 127*7c478bd9Sstevel@tonic-gate ULONGLONG_T (*ccfn)(); /* conversion function (strtoll/strtoull) */ 128*7c478bd9Sstevel@tonic-gate char ccltab[256]; /* character class table for %[...] */ 129*7c478bd9Sstevel@tonic-gate char buf[BUF]; /* buffer for numeric conversions */ 130*7c478bd9Sstevel@tonic-gate SM_EVENT *evt = NULL; 131*7c478bd9Sstevel@tonic-gate 132*7c478bd9Sstevel@tonic-gate /* `basefix' is used to avoid `if' tests in the integer scanner */ 133*7c478bd9Sstevel@tonic-gate static short basefix[17] = 134*7c478bd9Sstevel@tonic-gate { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate if (timeout == SM_TIME_DEFAULT) 137*7c478bd9Sstevel@tonic-gate timeout = fp->f_timeout; 138*7c478bd9Sstevel@tonic-gate if (timeout == SM_TIME_IMMEDIATE) 139*7c478bd9Sstevel@tonic-gate { 140*7c478bd9Sstevel@tonic-gate /* 141*7c478bd9Sstevel@tonic-gate ** Filling the buffer will take time and we are wanted to 142*7c478bd9Sstevel@tonic-gate ** return immediately. So... 143*7c478bd9Sstevel@tonic-gate */ 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate errno = EAGAIN; 146*7c478bd9Sstevel@tonic-gate return SM_IO_EOF; 147*7c478bd9Sstevel@tonic-gate } 148*7c478bd9Sstevel@tonic-gate 149*7c478bd9Sstevel@tonic-gate if (timeout != SM_TIME_FOREVER) 150*7c478bd9Sstevel@tonic-gate { 151*7c478bd9Sstevel@tonic-gate if (setjmp(ScanTimeOut) != 0) 152*7c478bd9Sstevel@tonic-gate { 153*7c478bd9Sstevel@tonic-gate errno = EAGAIN; 154*7c478bd9Sstevel@tonic-gate return SM_IO_EOF; 155*7c478bd9Sstevel@tonic-gate } 156*7c478bd9Sstevel@tonic-gate 157*7c478bd9Sstevel@tonic-gate evt = sm_seteventm(timeout, scanalrm, 0); 158*7c478bd9Sstevel@tonic-gate } 159*7c478bd9Sstevel@tonic-gate 160*7c478bd9Sstevel@tonic-gate nassigned = 0; 161*7c478bd9Sstevel@tonic-gate nread = 0; 162*7c478bd9Sstevel@tonic-gate base = 0; /* XXX just to keep gcc happy */ 163*7c478bd9Sstevel@tonic-gate ccfn = NULL; /* XXX just to keep gcc happy */ 164*7c478bd9Sstevel@tonic-gate for (;;) 165*7c478bd9Sstevel@tonic-gate { 166*7c478bd9Sstevel@tonic-gate c = *fmt++; 167*7c478bd9Sstevel@tonic-gate if (c == 0) 168*7c478bd9Sstevel@tonic-gate { 169*7c478bd9Sstevel@tonic-gate if (evt != NULL) 170*7c478bd9Sstevel@tonic-gate sm_clrevent(evt); /* undo our timeout */ 171*7c478bd9Sstevel@tonic-gate return nassigned; 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate if (isspace(c)) 174*7c478bd9Sstevel@tonic-gate { 175*7c478bd9Sstevel@tonic-gate while ((fp->f_r > 0 || sm_refill(fp, SM_TIME_FOREVER) 176*7c478bd9Sstevel@tonic-gate == 0) && 177*7c478bd9Sstevel@tonic-gate isspace(*fp->f_p)) 178*7c478bd9Sstevel@tonic-gate nread++, fp->f_r--, fp->f_p++; 179*7c478bd9Sstevel@tonic-gate continue; 180*7c478bd9Sstevel@tonic-gate } 181*7c478bd9Sstevel@tonic-gate if (c != '%') 182*7c478bd9Sstevel@tonic-gate goto literal; 183*7c478bd9Sstevel@tonic-gate width = 0; 184*7c478bd9Sstevel@tonic-gate flags = 0; 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate /* 187*7c478bd9Sstevel@tonic-gate ** switch on the format. continue if done; 188*7c478bd9Sstevel@tonic-gate ** break once format type is derived. 189*7c478bd9Sstevel@tonic-gate */ 190*7c478bd9Sstevel@tonic-gate 191*7c478bd9Sstevel@tonic-gate again: c = *fmt++; 192*7c478bd9Sstevel@tonic-gate switch (c) 193*7c478bd9Sstevel@tonic-gate { 194*7c478bd9Sstevel@tonic-gate case '%': 195*7c478bd9Sstevel@tonic-gate literal: 196*7c478bd9Sstevel@tonic-gate if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER)) 197*7c478bd9Sstevel@tonic-gate goto input_failure; 198*7c478bd9Sstevel@tonic-gate if (*fp->f_p != c) 199*7c478bd9Sstevel@tonic-gate goto match_failure; 200*7c478bd9Sstevel@tonic-gate fp->f_r--, fp->f_p++; 201*7c478bd9Sstevel@tonic-gate nread++; 202*7c478bd9Sstevel@tonic-gate continue; 203*7c478bd9Sstevel@tonic-gate 204*7c478bd9Sstevel@tonic-gate case '*': 205*7c478bd9Sstevel@tonic-gate flags |= SUPPRESS; 206*7c478bd9Sstevel@tonic-gate goto again; 207*7c478bd9Sstevel@tonic-gate case 'h': 208*7c478bd9Sstevel@tonic-gate flags |= SHORT; 209*7c478bd9Sstevel@tonic-gate goto again; 210*7c478bd9Sstevel@tonic-gate case 'l': 211*7c478bd9Sstevel@tonic-gate if (*fmt == 'l') 212*7c478bd9Sstevel@tonic-gate { 213*7c478bd9Sstevel@tonic-gate fmt++; 214*7c478bd9Sstevel@tonic-gate flags |= QUAD; 215*7c478bd9Sstevel@tonic-gate } 216*7c478bd9Sstevel@tonic-gate else 217*7c478bd9Sstevel@tonic-gate { 218*7c478bd9Sstevel@tonic-gate flags |= LONG; 219*7c478bd9Sstevel@tonic-gate } 220*7c478bd9Sstevel@tonic-gate goto again; 221*7c478bd9Sstevel@tonic-gate case 'q': 222*7c478bd9Sstevel@tonic-gate flags |= QUAD; 223*7c478bd9Sstevel@tonic-gate goto again; 224*7c478bd9Sstevel@tonic-gate 225*7c478bd9Sstevel@tonic-gate case '0': case '1': case '2': case '3': case '4': 226*7c478bd9Sstevel@tonic-gate case '5': case '6': case '7': case '8': case '9': 227*7c478bd9Sstevel@tonic-gate width = width * 10 + c - '0'; 228*7c478bd9Sstevel@tonic-gate goto again; 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* 231*7c478bd9Sstevel@tonic-gate ** Conversions. 232*7c478bd9Sstevel@tonic-gate ** Those marked `compat' are for 4.[123]BSD compatibility. 233*7c478bd9Sstevel@tonic-gate ** 234*7c478bd9Sstevel@tonic-gate ** (According to ANSI, E and X formats are supposed 235*7c478bd9Sstevel@tonic-gate ** to the same as e and x. Sorry about that.) 236*7c478bd9Sstevel@tonic-gate */ 237*7c478bd9Sstevel@tonic-gate 238*7c478bd9Sstevel@tonic-gate case 'D': /* compat */ 239*7c478bd9Sstevel@tonic-gate flags |= LONG; 240*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 241*7c478bd9Sstevel@tonic-gate case 'd': 242*7c478bd9Sstevel@tonic-gate c = CT_INT; 243*7c478bd9Sstevel@tonic-gate ccfn = (ULONGLONG_T (*)())sm_strtoll; 244*7c478bd9Sstevel@tonic-gate base = 10; 245*7c478bd9Sstevel@tonic-gate break; 246*7c478bd9Sstevel@tonic-gate 247*7c478bd9Sstevel@tonic-gate case 'i': 248*7c478bd9Sstevel@tonic-gate c = CT_INT; 249*7c478bd9Sstevel@tonic-gate ccfn = (ULONGLONG_T (*)())sm_strtoll; 250*7c478bd9Sstevel@tonic-gate base = 0; 251*7c478bd9Sstevel@tonic-gate break; 252*7c478bd9Sstevel@tonic-gate 253*7c478bd9Sstevel@tonic-gate case 'O': /* compat */ 254*7c478bd9Sstevel@tonic-gate flags |= LONG; 255*7c478bd9Sstevel@tonic-gate /* FALLTHROUGH */ 256*7c478bd9Sstevel@tonic-gate case 'o': 257*7c478bd9Sstevel@tonic-gate c = CT_INT; 258*7c478bd9Sstevel@tonic-gate ccfn = sm_strtoull; 259*7c478bd9Sstevel@tonic-gate base = 8; 260*7c478bd9Sstevel@tonic-gate break; 261*7c478bd9Sstevel@tonic-gate 262*7c478bd9Sstevel@tonic-gate case 'u': 263*7c478bd9Sstevel@tonic-gate c = CT_INT; 264*7c478bd9Sstevel@tonic-gate ccfn = sm_strtoull; 265*7c478bd9Sstevel@tonic-gate base = 10; 266*7c478bd9Sstevel@tonic-gate break; 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate case 'X': 269*7c478bd9Sstevel@tonic-gate case 'x': 270*7c478bd9Sstevel@tonic-gate flags |= PFXOK; /* enable 0x prefixing */ 271*7c478bd9Sstevel@tonic-gate c = CT_INT; 272*7c478bd9Sstevel@tonic-gate ccfn = sm_strtoull; 273*7c478bd9Sstevel@tonic-gate base = 16; 274*7c478bd9Sstevel@tonic-gate break; 275*7c478bd9Sstevel@tonic-gate 276*7c478bd9Sstevel@tonic-gate case 'E': 277*7c478bd9Sstevel@tonic-gate case 'G': 278*7c478bd9Sstevel@tonic-gate case 'e': 279*7c478bd9Sstevel@tonic-gate case 'f': 280*7c478bd9Sstevel@tonic-gate case 'g': 281*7c478bd9Sstevel@tonic-gate c = CT_FLOAT; 282*7c478bd9Sstevel@tonic-gate break; 283*7c478bd9Sstevel@tonic-gate 284*7c478bd9Sstevel@tonic-gate case 's': 285*7c478bd9Sstevel@tonic-gate c = CT_STRING; 286*7c478bd9Sstevel@tonic-gate break; 287*7c478bd9Sstevel@tonic-gate 288*7c478bd9Sstevel@tonic-gate case '[': 289*7c478bd9Sstevel@tonic-gate fmt = sm_sccl(ccltab, fmt); 290*7c478bd9Sstevel@tonic-gate flags |= NOSKIP; 291*7c478bd9Sstevel@tonic-gate c = CT_CCL; 292*7c478bd9Sstevel@tonic-gate break; 293*7c478bd9Sstevel@tonic-gate 294*7c478bd9Sstevel@tonic-gate case 'c': 295*7c478bd9Sstevel@tonic-gate flags |= NOSKIP; 296*7c478bd9Sstevel@tonic-gate c = CT_CHAR; 297*7c478bd9Sstevel@tonic-gate break; 298*7c478bd9Sstevel@tonic-gate 299*7c478bd9Sstevel@tonic-gate case 'p': /* pointer format is like hex */ 300*7c478bd9Sstevel@tonic-gate flags |= POINTER | PFXOK; 301*7c478bd9Sstevel@tonic-gate c = CT_INT; 302*7c478bd9Sstevel@tonic-gate ccfn = sm_strtoull; 303*7c478bd9Sstevel@tonic-gate base = 16; 304*7c478bd9Sstevel@tonic-gate break; 305*7c478bd9Sstevel@tonic-gate 306*7c478bd9Sstevel@tonic-gate case 'n': 307*7c478bd9Sstevel@tonic-gate if (flags & SUPPRESS) /* ??? */ 308*7c478bd9Sstevel@tonic-gate continue; 309*7c478bd9Sstevel@tonic-gate if (flags & SHORT) 310*7c478bd9Sstevel@tonic-gate *SM_VA_ARG(ap, short *) = nread; 311*7c478bd9Sstevel@tonic-gate else if (flags & LONG) 312*7c478bd9Sstevel@tonic-gate *SM_VA_ARG(ap, long *) = nread; 313*7c478bd9Sstevel@tonic-gate else 314*7c478bd9Sstevel@tonic-gate *SM_VA_ARG(ap, int *) = nread; 315*7c478bd9Sstevel@tonic-gate continue; 316*7c478bd9Sstevel@tonic-gate 317*7c478bd9Sstevel@tonic-gate /* Disgusting backwards compatibility hacks. XXX */ 318*7c478bd9Sstevel@tonic-gate case '\0': /* compat */ 319*7c478bd9Sstevel@tonic-gate if (evt != NULL) 320*7c478bd9Sstevel@tonic-gate sm_clrevent(evt); /* undo our timeout */ 321*7c478bd9Sstevel@tonic-gate return SM_IO_EOF; 322*7c478bd9Sstevel@tonic-gate 323*7c478bd9Sstevel@tonic-gate default: /* compat */ 324*7c478bd9Sstevel@tonic-gate if (isupper(c)) 325*7c478bd9Sstevel@tonic-gate flags |= LONG; 326*7c478bd9Sstevel@tonic-gate c = CT_INT; 327*7c478bd9Sstevel@tonic-gate ccfn = (ULONGLONG_T (*)()) sm_strtoll; 328*7c478bd9Sstevel@tonic-gate base = 10; 329*7c478bd9Sstevel@tonic-gate break; 330*7c478bd9Sstevel@tonic-gate } 331*7c478bd9Sstevel@tonic-gate 332*7c478bd9Sstevel@tonic-gate /* We have a conversion that requires input. */ 333*7c478bd9Sstevel@tonic-gate if (fp->f_r <= 0 && sm_refill(fp, SM_TIME_FOREVER)) 334*7c478bd9Sstevel@tonic-gate goto input_failure; 335*7c478bd9Sstevel@tonic-gate 336*7c478bd9Sstevel@tonic-gate /* 337*7c478bd9Sstevel@tonic-gate ** Consume leading white space, except for formats 338*7c478bd9Sstevel@tonic-gate ** that suppress this. 339*7c478bd9Sstevel@tonic-gate */ 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate if ((flags & NOSKIP) == 0) 342*7c478bd9Sstevel@tonic-gate { 343*7c478bd9Sstevel@tonic-gate while (isspace(*fp->f_p)) 344*7c478bd9Sstevel@tonic-gate { 345*7c478bd9Sstevel@tonic-gate nread++; 346*7c478bd9Sstevel@tonic-gate if (--fp->f_r > 0) 347*7c478bd9Sstevel@tonic-gate fp->f_p++; 348*7c478bd9Sstevel@tonic-gate else if (sm_refill(fp, SM_TIME_FOREVER)) 349*7c478bd9Sstevel@tonic-gate goto input_failure; 350*7c478bd9Sstevel@tonic-gate } 351*7c478bd9Sstevel@tonic-gate /* 352*7c478bd9Sstevel@tonic-gate ** Note that there is at least one character in 353*7c478bd9Sstevel@tonic-gate ** the buffer, so conversions that do not set NOSKIP 354*7c478bd9Sstevel@tonic-gate ** can no longer result in an input failure. 355*7c478bd9Sstevel@tonic-gate */ 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate /* Do the conversion. */ 359*7c478bd9Sstevel@tonic-gate switch (c) 360*7c478bd9Sstevel@tonic-gate { 361*7c478bd9Sstevel@tonic-gate case CT_CHAR: 362*7c478bd9Sstevel@tonic-gate /* scan arbitrary characters (sets NOSKIP) */ 363*7c478bd9Sstevel@tonic-gate if (width == 0) 364*7c478bd9Sstevel@tonic-gate width = 1; 365*7c478bd9Sstevel@tonic-gate if (flags & SUPPRESS) 366*7c478bd9Sstevel@tonic-gate { 367*7c478bd9Sstevel@tonic-gate size_t sum = 0; 368*7c478bd9Sstevel@tonic-gate for (;;) 369*7c478bd9Sstevel@tonic-gate { 370*7c478bd9Sstevel@tonic-gate if ((size_t) (n = fp->f_r) < width) 371*7c478bd9Sstevel@tonic-gate { 372*7c478bd9Sstevel@tonic-gate sum += n; 373*7c478bd9Sstevel@tonic-gate width -= n; 374*7c478bd9Sstevel@tonic-gate fp->f_p += n; 375*7c478bd9Sstevel@tonic-gate if (sm_refill(fp, 376*7c478bd9Sstevel@tonic-gate SM_TIME_FOREVER)) 377*7c478bd9Sstevel@tonic-gate { 378*7c478bd9Sstevel@tonic-gate if (sum == 0) 379*7c478bd9Sstevel@tonic-gate goto input_failure; 380*7c478bd9Sstevel@tonic-gate break; 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate } 383*7c478bd9Sstevel@tonic-gate else 384*7c478bd9Sstevel@tonic-gate { 385*7c478bd9Sstevel@tonic-gate sum += width; 386*7c478bd9Sstevel@tonic-gate fp->f_r -= width; 387*7c478bd9Sstevel@tonic-gate fp->f_p += width; 388*7c478bd9Sstevel@tonic-gate break; 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate } 391*7c478bd9Sstevel@tonic-gate nread += sum; 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate else 394*7c478bd9Sstevel@tonic-gate { 395*7c478bd9Sstevel@tonic-gate size_t r; 396*7c478bd9Sstevel@tonic-gate 397*7c478bd9Sstevel@tonic-gate r = sm_io_read(fp, SM_TIME_FOREVER, 398*7c478bd9Sstevel@tonic-gate (void *) SM_VA_ARG(ap, char *), 399*7c478bd9Sstevel@tonic-gate width); 400*7c478bd9Sstevel@tonic-gate if (r == 0) 401*7c478bd9Sstevel@tonic-gate goto input_failure; 402*7c478bd9Sstevel@tonic-gate nread += r; 403*7c478bd9Sstevel@tonic-gate nassigned++; 404*7c478bd9Sstevel@tonic-gate } 405*7c478bd9Sstevel@tonic-gate break; 406*7c478bd9Sstevel@tonic-gate 407*7c478bd9Sstevel@tonic-gate case CT_CCL: 408*7c478bd9Sstevel@tonic-gate /* scan a (nonempty) character class (sets NOSKIP) */ 409*7c478bd9Sstevel@tonic-gate if (width == 0) 410*7c478bd9Sstevel@tonic-gate width = (size_t)~0; /* `infinity' */ 411*7c478bd9Sstevel@tonic-gate 412*7c478bd9Sstevel@tonic-gate /* take only those things in the class */ 413*7c478bd9Sstevel@tonic-gate if (flags & SUPPRESS) 414*7c478bd9Sstevel@tonic-gate { 415*7c478bd9Sstevel@tonic-gate n = 0; 416*7c478bd9Sstevel@tonic-gate while (ccltab[*fp->f_p] != '\0') 417*7c478bd9Sstevel@tonic-gate { 418*7c478bd9Sstevel@tonic-gate n++, fp->f_r--, fp->f_p++; 419*7c478bd9Sstevel@tonic-gate if (--width == 0) 420*7c478bd9Sstevel@tonic-gate break; 421*7c478bd9Sstevel@tonic-gate if (fp->f_r <= 0 && 422*7c478bd9Sstevel@tonic-gate sm_refill(fp, SM_TIME_FOREVER)) 423*7c478bd9Sstevel@tonic-gate { 424*7c478bd9Sstevel@tonic-gate if (n == 0) /* XXX how? */ 425*7c478bd9Sstevel@tonic-gate goto input_failure; 426*7c478bd9Sstevel@tonic-gate break; 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate } 429*7c478bd9Sstevel@tonic-gate if (n == 0) 430*7c478bd9Sstevel@tonic-gate goto match_failure; 431*7c478bd9Sstevel@tonic-gate } 432*7c478bd9Sstevel@tonic-gate else 433*7c478bd9Sstevel@tonic-gate { 434*7c478bd9Sstevel@tonic-gate p0 = p = SM_VA_ARG(ap, char *); 435*7c478bd9Sstevel@tonic-gate while (ccltab[*fp->f_p] != '\0') 436*7c478bd9Sstevel@tonic-gate { 437*7c478bd9Sstevel@tonic-gate fp->f_r--; 438*7c478bd9Sstevel@tonic-gate *p++ = *fp->f_p++; 439*7c478bd9Sstevel@tonic-gate if (--width == 0) 440*7c478bd9Sstevel@tonic-gate break; 441*7c478bd9Sstevel@tonic-gate if (fp->f_r <= 0 && 442*7c478bd9Sstevel@tonic-gate sm_refill(fp, SM_TIME_FOREVER)) 443*7c478bd9Sstevel@tonic-gate { 444*7c478bd9Sstevel@tonic-gate if (p == p0) 445*7c478bd9Sstevel@tonic-gate goto input_failure; 446*7c478bd9Sstevel@tonic-gate break; 447*7c478bd9Sstevel@tonic-gate } 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate n = p - p0; 450*7c478bd9Sstevel@tonic-gate if (n == 0) 451*7c478bd9Sstevel@tonic-gate goto match_failure; 452*7c478bd9Sstevel@tonic-gate *p = 0; 453*7c478bd9Sstevel@tonic-gate nassigned++; 454*7c478bd9Sstevel@tonic-gate } 455*7c478bd9Sstevel@tonic-gate nread += n; 456*7c478bd9Sstevel@tonic-gate break; 457*7c478bd9Sstevel@tonic-gate 458*7c478bd9Sstevel@tonic-gate case CT_STRING: 459*7c478bd9Sstevel@tonic-gate /* like CCL, but zero-length string OK, & no NOSKIP */ 460*7c478bd9Sstevel@tonic-gate if (width == 0) 461*7c478bd9Sstevel@tonic-gate width = (size_t)~0; 462*7c478bd9Sstevel@tonic-gate if (flags & SUPPRESS) 463*7c478bd9Sstevel@tonic-gate { 464*7c478bd9Sstevel@tonic-gate n = 0; 465*7c478bd9Sstevel@tonic-gate while (!isspace(*fp->f_p)) 466*7c478bd9Sstevel@tonic-gate { 467*7c478bd9Sstevel@tonic-gate n++, fp->f_r--, fp->f_p++; 468*7c478bd9Sstevel@tonic-gate if (--width == 0) 469*7c478bd9Sstevel@tonic-gate break; 470*7c478bd9Sstevel@tonic-gate if (fp->f_r <= 0 && 471*7c478bd9Sstevel@tonic-gate sm_refill(fp, SM_TIME_FOREVER)) 472*7c478bd9Sstevel@tonic-gate break; 473*7c478bd9Sstevel@tonic-gate } 474*7c478bd9Sstevel@tonic-gate nread += n; 475*7c478bd9Sstevel@tonic-gate } 476*7c478bd9Sstevel@tonic-gate else 477*7c478bd9Sstevel@tonic-gate { 478*7c478bd9Sstevel@tonic-gate p0 = p = SM_VA_ARG(ap, char *); 479*7c478bd9Sstevel@tonic-gate while (!isspace(*fp->f_p)) 480*7c478bd9Sstevel@tonic-gate { 481*7c478bd9Sstevel@tonic-gate fp->f_r--; 482*7c478bd9Sstevel@tonic-gate *p++ = *fp->f_p++; 483*7c478bd9Sstevel@tonic-gate if (--width == 0) 484*7c478bd9Sstevel@tonic-gate break; 485*7c478bd9Sstevel@tonic-gate if (fp->f_r <= 0 && 486*7c478bd9Sstevel@tonic-gate sm_refill(fp, SM_TIME_FOREVER)) 487*7c478bd9Sstevel@tonic-gate break; 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate *p = 0; 490*7c478bd9Sstevel@tonic-gate nread += p - p0; 491*7c478bd9Sstevel@tonic-gate nassigned++; 492*7c478bd9Sstevel@tonic-gate } 493*7c478bd9Sstevel@tonic-gate continue; 494*7c478bd9Sstevel@tonic-gate 495*7c478bd9Sstevel@tonic-gate case CT_INT: 496*7c478bd9Sstevel@tonic-gate /* scan an integer as if by strtoll/strtoull */ 497*7c478bd9Sstevel@tonic-gate #if SM_CONF_BROKEN_SIZE_T 498*7c478bd9Sstevel@tonic-gate if (width == 0 || width > sizeof(buf) - 1) 499*7c478bd9Sstevel@tonic-gate width = sizeof(buf) - 1; 500*7c478bd9Sstevel@tonic-gate #else /* SM_CONF_BROKEN_SIZE_T */ 501*7c478bd9Sstevel@tonic-gate /* size_t is unsigned, hence this optimisation */ 502*7c478bd9Sstevel@tonic-gate if (--width > sizeof(buf) - 2) 503*7c478bd9Sstevel@tonic-gate width = sizeof(buf) - 2; 504*7c478bd9Sstevel@tonic-gate width++; 505*7c478bd9Sstevel@tonic-gate #endif /* SM_CONF_BROKEN_SIZE_T */ 506*7c478bd9Sstevel@tonic-gate flags |= SIGNOK | NDIGITS | NZDIGITS; 507*7c478bd9Sstevel@tonic-gate for (p = buf; width > 0; width--) 508*7c478bd9Sstevel@tonic-gate { 509*7c478bd9Sstevel@tonic-gate c = *fp->f_p; 510*7c478bd9Sstevel@tonic-gate 511*7c478bd9Sstevel@tonic-gate /* 512*7c478bd9Sstevel@tonic-gate ** Switch on the character; `goto ok' 513*7c478bd9Sstevel@tonic-gate ** if we accept it as a part of number. 514*7c478bd9Sstevel@tonic-gate */ 515*7c478bd9Sstevel@tonic-gate 516*7c478bd9Sstevel@tonic-gate switch (c) 517*7c478bd9Sstevel@tonic-gate { 518*7c478bd9Sstevel@tonic-gate 519*7c478bd9Sstevel@tonic-gate /* 520*7c478bd9Sstevel@tonic-gate ** The digit 0 is always legal, but is 521*7c478bd9Sstevel@tonic-gate ** special. For %i conversions, if no 522*7c478bd9Sstevel@tonic-gate ** digits (zero or nonzero) have been 523*7c478bd9Sstevel@tonic-gate ** scanned (only signs), we will have 524*7c478bd9Sstevel@tonic-gate ** base==0. In that case, we should set 525*7c478bd9Sstevel@tonic-gate ** it to 8 and enable 0x prefixing. 526*7c478bd9Sstevel@tonic-gate ** Also, if we have not scanned zero digits 527*7c478bd9Sstevel@tonic-gate ** before this, do not turn off prefixing 528*7c478bd9Sstevel@tonic-gate ** (someone else will turn it off if we 529*7c478bd9Sstevel@tonic-gate ** have scanned any nonzero digits). 530*7c478bd9Sstevel@tonic-gate */ 531*7c478bd9Sstevel@tonic-gate 532*7c478bd9Sstevel@tonic-gate case '0': 533*7c478bd9Sstevel@tonic-gate if (base == 0) 534*7c478bd9Sstevel@tonic-gate { 535*7c478bd9Sstevel@tonic-gate base = 8; 536*7c478bd9Sstevel@tonic-gate flags |= PFXOK; 537*7c478bd9Sstevel@tonic-gate } 538*7c478bd9Sstevel@tonic-gate if (flags & NZDIGITS) 539*7c478bd9Sstevel@tonic-gate flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 540*7c478bd9Sstevel@tonic-gate else 541*7c478bd9Sstevel@tonic-gate flags &= ~(SIGNOK|PFXOK|NDIGITS); 542*7c478bd9Sstevel@tonic-gate goto ok; 543*7c478bd9Sstevel@tonic-gate 544*7c478bd9Sstevel@tonic-gate /* 1 through 7 always legal */ 545*7c478bd9Sstevel@tonic-gate case '1': case '2': case '3': 546*7c478bd9Sstevel@tonic-gate case '4': case '5': case '6': case '7': 547*7c478bd9Sstevel@tonic-gate base = basefix[base]; 548*7c478bd9Sstevel@tonic-gate flags &= ~(SIGNOK | PFXOK | NDIGITS); 549*7c478bd9Sstevel@tonic-gate goto ok; 550*7c478bd9Sstevel@tonic-gate 551*7c478bd9Sstevel@tonic-gate /* digits 8 and 9 ok iff decimal or hex */ 552*7c478bd9Sstevel@tonic-gate case '8': case '9': 553*7c478bd9Sstevel@tonic-gate base = basefix[base]; 554*7c478bd9Sstevel@tonic-gate if (base <= 8) 555*7c478bd9Sstevel@tonic-gate break; /* not legal here */ 556*7c478bd9Sstevel@tonic-gate flags &= ~(SIGNOK | PFXOK | NDIGITS); 557*7c478bd9Sstevel@tonic-gate goto ok; 558*7c478bd9Sstevel@tonic-gate 559*7c478bd9Sstevel@tonic-gate /* letters ok iff hex */ 560*7c478bd9Sstevel@tonic-gate case 'A': case 'B': case 'C': 561*7c478bd9Sstevel@tonic-gate case 'D': case 'E': case 'F': 562*7c478bd9Sstevel@tonic-gate case 'a': case 'b': case 'c': 563*7c478bd9Sstevel@tonic-gate case 'd': case 'e': case 'f': 564*7c478bd9Sstevel@tonic-gate 565*7c478bd9Sstevel@tonic-gate /* no need to fix base here */ 566*7c478bd9Sstevel@tonic-gate if (base <= 10) 567*7c478bd9Sstevel@tonic-gate break; /* not legal here */ 568*7c478bd9Sstevel@tonic-gate flags &= ~(SIGNOK | PFXOK | NDIGITS); 569*7c478bd9Sstevel@tonic-gate goto ok; 570*7c478bd9Sstevel@tonic-gate 571*7c478bd9Sstevel@tonic-gate /* sign ok only as first character */ 572*7c478bd9Sstevel@tonic-gate case '+': case '-': 573*7c478bd9Sstevel@tonic-gate if (flags & SIGNOK) 574*7c478bd9Sstevel@tonic-gate { 575*7c478bd9Sstevel@tonic-gate flags &= ~SIGNOK; 576*7c478bd9Sstevel@tonic-gate goto ok; 577*7c478bd9Sstevel@tonic-gate } 578*7c478bd9Sstevel@tonic-gate break; 579*7c478bd9Sstevel@tonic-gate 580*7c478bd9Sstevel@tonic-gate /* x ok iff flag still set & 2nd char */ 581*7c478bd9Sstevel@tonic-gate case 'x': case 'X': 582*7c478bd9Sstevel@tonic-gate if (flags & PFXOK && p == buf + 1) 583*7c478bd9Sstevel@tonic-gate { 584*7c478bd9Sstevel@tonic-gate base = 16; /* if %i */ 585*7c478bd9Sstevel@tonic-gate flags &= ~PFXOK; 586*7c478bd9Sstevel@tonic-gate goto ok; 587*7c478bd9Sstevel@tonic-gate } 588*7c478bd9Sstevel@tonic-gate break; 589*7c478bd9Sstevel@tonic-gate } 590*7c478bd9Sstevel@tonic-gate 591*7c478bd9Sstevel@tonic-gate /* 592*7c478bd9Sstevel@tonic-gate ** If we got here, c is not a legal character 593*7c478bd9Sstevel@tonic-gate ** for a number. Stop accumulating digits. 594*7c478bd9Sstevel@tonic-gate */ 595*7c478bd9Sstevel@tonic-gate 596*7c478bd9Sstevel@tonic-gate break; 597*7c478bd9Sstevel@tonic-gate ok: 598*7c478bd9Sstevel@tonic-gate /* c is legal: store it and look at the next. */ 599*7c478bd9Sstevel@tonic-gate *p++ = c; 600*7c478bd9Sstevel@tonic-gate if (--fp->f_r > 0) 601*7c478bd9Sstevel@tonic-gate fp->f_p++; 602*7c478bd9Sstevel@tonic-gate else if (sm_refill(fp, SM_TIME_FOREVER)) 603*7c478bd9Sstevel@tonic-gate break; /* SM_IO_EOF */ 604*7c478bd9Sstevel@tonic-gate } 605*7c478bd9Sstevel@tonic-gate 606*7c478bd9Sstevel@tonic-gate /* 607*7c478bd9Sstevel@tonic-gate ** If we had only a sign, it is no good; push 608*7c478bd9Sstevel@tonic-gate ** back the sign. If the number ends in `x', 609*7c478bd9Sstevel@tonic-gate ** it was [sign] '0' 'x', so push back the x 610*7c478bd9Sstevel@tonic-gate ** and treat it as [sign] '0'. 611*7c478bd9Sstevel@tonic-gate */ 612*7c478bd9Sstevel@tonic-gate 613*7c478bd9Sstevel@tonic-gate if (flags & NDIGITS) 614*7c478bd9Sstevel@tonic-gate { 615*7c478bd9Sstevel@tonic-gate if (p > buf) 616*7c478bd9Sstevel@tonic-gate (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, 617*7c478bd9Sstevel@tonic-gate *(unsigned char *)--p); 618*7c478bd9Sstevel@tonic-gate goto match_failure; 619*7c478bd9Sstevel@tonic-gate } 620*7c478bd9Sstevel@tonic-gate c = ((unsigned char *)p)[-1]; 621*7c478bd9Sstevel@tonic-gate if (c == 'x' || c == 'X') 622*7c478bd9Sstevel@tonic-gate { 623*7c478bd9Sstevel@tonic-gate --p; 624*7c478bd9Sstevel@tonic-gate (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); 625*7c478bd9Sstevel@tonic-gate } 626*7c478bd9Sstevel@tonic-gate if ((flags & SUPPRESS) == 0) 627*7c478bd9Sstevel@tonic-gate { 628*7c478bd9Sstevel@tonic-gate ULONGLONG_T res; 629*7c478bd9Sstevel@tonic-gate 630*7c478bd9Sstevel@tonic-gate *p = 0; 631*7c478bd9Sstevel@tonic-gate res = (*ccfn)(buf, (char **)NULL, base); 632*7c478bd9Sstevel@tonic-gate if (flags & POINTER) 633*7c478bd9Sstevel@tonic-gate *SM_VA_ARG(ap, void **) = 634*7c478bd9Sstevel@tonic-gate (void *)(long) res; 635*7c478bd9Sstevel@tonic-gate else if (flags & QUAD) 636*7c478bd9Sstevel@tonic-gate *SM_VA_ARG(ap, LONGLONG_T *) = res; 637*7c478bd9Sstevel@tonic-gate else if (flags & LONG) 638*7c478bd9Sstevel@tonic-gate *SM_VA_ARG(ap, long *) = res; 639*7c478bd9Sstevel@tonic-gate else if (flags & SHORT) 640*7c478bd9Sstevel@tonic-gate *SM_VA_ARG(ap, short *) = res; 641*7c478bd9Sstevel@tonic-gate else 642*7c478bd9Sstevel@tonic-gate *SM_VA_ARG(ap, int *) = res; 643*7c478bd9Sstevel@tonic-gate nassigned++; 644*7c478bd9Sstevel@tonic-gate } 645*7c478bd9Sstevel@tonic-gate nread += p - buf; 646*7c478bd9Sstevel@tonic-gate break; 647*7c478bd9Sstevel@tonic-gate 648*7c478bd9Sstevel@tonic-gate case CT_FLOAT: 649*7c478bd9Sstevel@tonic-gate /* scan a floating point number as if by strtod */ 650*7c478bd9Sstevel@tonic-gate if (width == 0 || width > sizeof(buf) - 1) 651*7c478bd9Sstevel@tonic-gate width = sizeof(buf) - 1; 652*7c478bd9Sstevel@tonic-gate flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; 653*7c478bd9Sstevel@tonic-gate for (p = buf; width; width--) 654*7c478bd9Sstevel@tonic-gate { 655*7c478bd9Sstevel@tonic-gate c = *fp->f_p; 656*7c478bd9Sstevel@tonic-gate 657*7c478bd9Sstevel@tonic-gate /* 658*7c478bd9Sstevel@tonic-gate ** This code mimicks the integer conversion 659*7c478bd9Sstevel@tonic-gate ** code, but is much simpler. 660*7c478bd9Sstevel@tonic-gate */ 661*7c478bd9Sstevel@tonic-gate 662*7c478bd9Sstevel@tonic-gate switch (c) 663*7c478bd9Sstevel@tonic-gate { 664*7c478bd9Sstevel@tonic-gate 665*7c478bd9Sstevel@tonic-gate case '0': case '1': case '2': case '3': 666*7c478bd9Sstevel@tonic-gate case '4': case '5': case '6': case '7': 667*7c478bd9Sstevel@tonic-gate case '8': case '9': 668*7c478bd9Sstevel@tonic-gate flags &= ~(SIGNOK | NDIGITS); 669*7c478bd9Sstevel@tonic-gate goto fok; 670*7c478bd9Sstevel@tonic-gate 671*7c478bd9Sstevel@tonic-gate case '+': case '-': 672*7c478bd9Sstevel@tonic-gate if (flags & SIGNOK) 673*7c478bd9Sstevel@tonic-gate { 674*7c478bd9Sstevel@tonic-gate flags &= ~SIGNOK; 675*7c478bd9Sstevel@tonic-gate goto fok; 676*7c478bd9Sstevel@tonic-gate } 677*7c478bd9Sstevel@tonic-gate break; 678*7c478bd9Sstevel@tonic-gate case '.': 679*7c478bd9Sstevel@tonic-gate if (flags & DPTOK) 680*7c478bd9Sstevel@tonic-gate { 681*7c478bd9Sstevel@tonic-gate flags &= ~(SIGNOK | DPTOK); 682*7c478bd9Sstevel@tonic-gate goto fok; 683*7c478bd9Sstevel@tonic-gate } 684*7c478bd9Sstevel@tonic-gate break; 685*7c478bd9Sstevel@tonic-gate case 'e': case 'E': 686*7c478bd9Sstevel@tonic-gate 687*7c478bd9Sstevel@tonic-gate /* no exponent without some digits */ 688*7c478bd9Sstevel@tonic-gate if ((flags&(NDIGITS|EXPOK)) == EXPOK) 689*7c478bd9Sstevel@tonic-gate { 690*7c478bd9Sstevel@tonic-gate flags = 691*7c478bd9Sstevel@tonic-gate (flags & ~(EXPOK|DPTOK)) | 692*7c478bd9Sstevel@tonic-gate SIGNOK | NDIGITS; 693*7c478bd9Sstevel@tonic-gate goto fok; 694*7c478bd9Sstevel@tonic-gate } 695*7c478bd9Sstevel@tonic-gate break; 696*7c478bd9Sstevel@tonic-gate } 697*7c478bd9Sstevel@tonic-gate break; 698*7c478bd9Sstevel@tonic-gate fok: 699*7c478bd9Sstevel@tonic-gate *p++ = c; 700*7c478bd9Sstevel@tonic-gate if (--fp->f_r > 0) 701*7c478bd9Sstevel@tonic-gate fp->f_p++; 702*7c478bd9Sstevel@tonic-gate else if (sm_refill(fp, SM_TIME_FOREVER)) 703*7c478bd9Sstevel@tonic-gate break; /* SM_IO_EOF */ 704*7c478bd9Sstevel@tonic-gate } 705*7c478bd9Sstevel@tonic-gate 706*7c478bd9Sstevel@tonic-gate /* 707*7c478bd9Sstevel@tonic-gate ** If no digits, might be missing exponent digits 708*7c478bd9Sstevel@tonic-gate ** (just give back the exponent) or might be missing 709*7c478bd9Sstevel@tonic-gate ** regular digits, but had sign and/or decimal point. 710*7c478bd9Sstevel@tonic-gate */ 711*7c478bd9Sstevel@tonic-gate 712*7c478bd9Sstevel@tonic-gate if (flags & NDIGITS) 713*7c478bd9Sstevel@tonic-gate { 714*7c478bd9Sstevel@tonic-gate if (flags & EXPOK) 715*7c478bd9Sstevel@tonic-gate { 716*7c478bd9Sstevel@tonic-gate /* no digits at all */ 717*7c478bd9Sstevel@tonic-gate while (p > buf) 718*7c478bd9Sstevel@tonic-gate (void) sm_io_ungetc(fp, 719*7c478bd9Sstevel@tonic-gate SM_TIME_DEFAULT, 720*7c478bd9Sstevel@tonic-gate *(unsigned char *)--p); 721*7c478bd9Sstevel@tonic-gate goto match_failure; 722*7c478bd9Sstevel@tonic-gate } 723*7c478bd9Sstevel@tonic-gate 724*7c478bd9Sstevel@tonic-gate /* just a bad exponent (e and maybe sign) */ 725*7c478bd9Sstevel@tonic-gate c = *(unsigned char *) --p; 726*7c478bd9Sstevel@tonic-gate if (c != 'e' && c != 'E') 727*7c478bd9Sstevel@tonic-gate { 728*7c478bd9Sstevel@tonic-gate (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, 729*7c478bd9Sstevel@tonic-gate c); /* sign */ 730*7c478bd9Sstevel@tonic-gate c = *(unsigned char *)--p; 731*7c478bd9Sstevel@tonic-gate } 732*7c478bd9Sstevel@tonic-gate (void) sm_io_ungetc(fp, SM_TIME_DEFAULT, c); 733*7c478bd9Sstevel@tonic-gate } 734*7c478bd9Sstevel@tonic-gate if ((flags & SUPPRESS) == 0) 735*7c478bd9Sstevel@tonic-gate { 736*7c478bd9Sstevel@tonic-gate double res; 737*7c478bd9Sstevel@tonic-gate 738*7c478bd9Sstevel@tonic-gate *p = 0; 739*7c478bd9Sstevel@tonic-gate res = strtod(buf, (char **) NULL); 740*7c478bd9Sstevel@tonic-gate if (flags & LONG) 741*7c478bd9Sstevel@tonic-gate *SM_VA_ARG(ap, double *) = res; 742*7c478bd9Sstevel@tonic-gate else 743*7c478bd9Sstevel@tonic-gate *SM_VA_ARG(ap, float *) = res; 744*7c478bd9Sstevel@tonic-gate nassigned++; 745*7c478bd9Sstevel@tonic-gate } 746*7c478bd9Sstevel@tonic-gate nread += p - buf; 747*7c478bd9Sstevel@tonic-gate break; 748*7c478bd9Sstevel@tonic-gate } 749*7c478bd9Sstevel@tonic-gate } 750*7c478bd9Sstevel@tonic-gate input_failure: 751*7c478bd9Sstevel@tonic-gate if (evt != NULL) 752*7c478bd9Sstevel@tonic-gate sm_clrevent(evt); /* undo our timeout */ 753*7c478bd9Sstevel@tonic-gate return nassigned ? nassigned : -1; 754*7c478bd9Sstevel@tonic-gate match_failure: 755*7c478bd9Sstevel@tonic-gate if (evt != NULL) 756*7c478bd9Sstevel@tonic-gate sm_clrevent(evt); /* undo our timeout */ 757*7c478bd9Sstevel@tonic-gate return nassigned; 758*7c478bd9Sstevel@tonic-gate } 759*7c478bd9Sstevel@tonic-gate 760*7c478bd9Sstevel@tonic-gate /* 761*7c478bd9Sstevel@tonic-gate ** SM_SCCL -- sequenced character comparison list 762*7c478bd9Sstevel@tonic-gate ** 763*7c478bd9Sstevel@tonic-gate ** Fill in the given table from the scanset at the given format 764*7c478bd9Sstevel@tonic-gate ** (just after `['). Return a pointer to the character past the 765*7c478bd9Sstevel@tonic-gate ** closing `]'. The table has a 1 wherever characters should be 766*7c478bd9Sstevel@tonic-gate ** considered part of the scanset. 767*7c478bd9Sstevel@tonic-gate ** 768*7c478bd9Sstevel@tonic-gate ** Parameters: 769*7c478bd9Sstevel@tonic-gate ** tab -- array flagging "active" char's to match (returned) 770*7c478bd9Sstevel@tonic-gate ** fmt -- character list (within "[]") 771*7c478bd9Sstevel@tonic-gate ** 772*7c478bd9Sstevel@tonic-gate ** Results: 773*7c478bd9Sstevel@tonic-gate */ 774*7c478bd9Sstevel@tonic-gate 775*7c478bd9Sstevel@tonic-gate static unsigned char * 776*7c478bd9Sstevel@tonic-gate sm_sccl(tab, fmt) 777*7c478bd9Sstevel@tonic-gate register char *tab; 778*7c478bd9Sstevel@tonic-gate register unsigned char *fmt; 779*7c478bd9Sstevel@tonic-gate { 780*7c478bd9Sstevel@tonic-gate register int c, n, v; 781*7c478bd9Sstevel@tonic-gate 782*7c478bd9Sstevel@tonic-gate /* first `clear' the whole table */ 783*7c478bd9Sstevel@tonic-gate c = *fmt++; /* first char hat => negated scanset */ 784*7c478bd9Sstevel@tonic-gate if (c == '^') 785*7c478bd9Sstevel@tonic-gate { 786*7c478bd9Sstevel@tonic-gate v = 1; /* default => accept */ 787*7c478bd9Sstevel@tonic-gate c = *fmt++; /* get new first char */ 788*7c478bd9Sstevel@tonic-gate } 789*7c478bd9Sstevel@tonic-gate else 790*7c478bd9Sstevel@tonic-gate v = 0; /* default => reject */ 791*7c478bd9Sstevel@tonic-gate 792*7c478bd9Sstevel@tonic-gate /* should probably use memset here */ 793*7c478bd9Sstevel@tonic-gate for (n = 0; n < 256; n++) 794*7c478bd9Sstevel@tonic-gate tab[n] = v; 795*7c478bd9Sstevel@tonic-gate if (c == 0) 796*7c478bd9Sstevel@tonic-gate return fmt - 1; /* format ended before closing ] */ 797*7c478bd9Sstevel@tonic-gate 798*7c478bd9Sstevel@tonic-gate /* 799*7c478bd9Sstevel@tonic-gate ** Now set the entries corresponding to the actual scanset 800*7c478bd9Sstevel@tonic-gate ** to the opposite of the above. 801*7c478bd9Sstevel@tonic-gate ** 802*7c478bd9Sstevel@tonic-gate ** The first character may be ']' (or '-') without being special; 803*7c478bd9Sstevel@tonic-gate ** the last character may be '-'. 804*7c478bd9Sstevel@tonic-gate */ 805*7c478bd9Sstevel@tonic-gate 806*7c478bd9Sstevel@tonic-gate v = 1 - v; 807*7c478bd9Sstevel@tonic-gate for (;;) 808*7c478bd9Sstevel@tonic-gate { 809*7c478bd9Sstevel@tonic-gate tab[c] = v; /* take character c */ 810*7c478bd9Sstevel@tonic-gate doswitch: 811*7c478bd9Sstevel@tonic-gate n = *fmt++; /* and examine the next */ 812*7c478bd9Sstevel@tonic-gate switch (n) 813*7c478bd9Sstevel@tonic-gate { 814*7c478bd9Sstevel@tonic-gate 815*7c478bd9Sstevel@tonic-gate case 0: /* format ended too soon */ 816*7c478bd9Sstevel@tonic-gate return fmt - 1; 817*7c478bd9Sstevel@tonic-gate 818*7c478bd9Sstevel@tonic-gate case '-': 819*7c478bd9Sstevel@tonic-gate /* 820*7c478bd9Sstevel@tonic-gate ** A scanset of the form 821*7c478bd9Sstevel@tonic-gate ** [01+-] 822*7c478bd9Sstevel@tonic-gate ** is defined as `the digit 0, the digit 1, 823*7c478bd9Sstevel@tonic-gate ** the character +, the character -', but 824*7c478bd9Sstevel@tonic-gate ** the effect of a scanset such as 825*7c478bd9Sstevel@tonic-gate ** [a-zA-Z0-9] 826*7c478bd9Sstevel@tonic-gate ** is implementation defined. The V7 Unix 827*7c478bd9Sstevel@tonic-gate ** scanf treats `a-z' as `the letters a through 828*7c478bd9Sstevel@tonic-gate ** z', but treats `a-a' as `the letter a, the 829*7c478bd9Sstevel@tonic-gate ** character -, and the letter a'. 830*7c478bd9Sstevel@tonic-gate ** 831*7c478bd9Sstevel@tonic-gate ** For compatibility, the `-' is not considerd 832*7c478bd9Sstevel@tonic-gate ** to define a range if the character following 833*7c478bd9Sstevel@tonic-gate ** it is either a close bracket (required by ANSI) 834*7c478bd9Sstevel@tonic-gate ** or is not numerically greater than the character 835*7c478bd9Sstevel@tonic-gate ** we just stored in the table (c). 836*7c478bd9Sstevel@tonic-gate */ 837*7c478bd9Sstevel@tonic-gate 838*7c478bd9Sstevel@tonic-gate n = *fmt; 839*7c478bd9Sstevel@tonic-gate if (n == ']' || n < c) 840*7c478bd9Sstevel@tonic-gate { 841*7c478bd9Sstevel@tonic-gate c = '-'; 842*7c478bd9Sstevel@tonic-gate break; /* resume the for(;;) */ 843*7c478bd9Sstevel@tonic-gate } 844*7c478bd9Sstevel@tonic-gate fmt++; 845*7c478bd9Sstevel@tonic-gate do 846*7c478bd9Sstevel@tonic-gate { 847*7c478bd9Sstevel@tonic-gate /* fill in the range */ 848*7c478bd9Sstevel@tonic-gate tab[++c] = v; 849*7c478bd9Sstevel@tonic-gate } while (c < n); 850*7c478bd9Sstevel@tonic-gate #if 1 /* XXX another disgusting compatibility hack */ 851*7c478bd9Sstevel@tonic-gate 852*7c478bd9Sstevel@tonic-gate /* 853*7c478bd9Sstevel@tonic-gate ** Alas, the V7 Unix scanf also treats formats 854*7c478bd9Sstevel@tonic-gate ** such as [a-c-e] as `the letters a through e'. 855*7c478bd9Sstevel@tonic-gate ** This too is permitted by the standard.... 856*7c478bd9Sstevel@tonic-gate */ 857*7c478bd9Sstevel@tonic-gate 858*7c478bd9Sstevel@tonic-gate goto doswitch; 859*7c478bd9Sstevel@tonic-gate #else 860*7c478bd9Sstevel@tonic-gate c = *fmt++; 861*7c478bd9Sstevel@tonic-gate if (c == 0) 862*7c478bd9Sstevel@tonic-gate return fmt - 1; 863*7c478bd9Sstevel@tonic-gate if (c == ']') 864*7c478bd9Sstevel@tonic-gate return fmt; 865*7c478bd9Sstevel@tonic-gate break; 866*7c478bd9Sstevel@tonic-gate #endif 867*7c478bd9Sstevel@tonic-gate 868*7c478bd9Sstevel@tonic-gate case ']': /* end of scanset */ 869*7c478bd9Sstevel@tonic-gate return fmt; 870*7c478bd9Sstevel@tonic-gate 871*7c478bd9Sstevel@tonic-gate default: /* just another character */ 872*7c478bd9Sstevel@tonic-gate c = n; 873*7c478bd9Sstevel@tonic-gate break; 874*7c478bd9Sstevel@tonic-gate } 875*7c478bd9Sstevel@tonic-gate } 876*7c478bd9Sstevel@tonic-gate /* NOTREACHED */ 877*7c478bd9Sstevel@tonic-gate } 878