1*46077Sbostic /*- 2*46077Sbostic * Copyright (c) 1990 The Regents of the University of California. 3*46077Sbostic * All rights reserved. 4*46077Sbostic * 5*46077Sbostic * This code is derived from software contributed to Berkeley by 6*46077Sbostic * Chris Torek. 7*46077Sbostic * 8*46077Sbostic * %sccs.include.redist.c% 9*46077Sbostic */ 10*46077Sbostic 1126640Sdonn #if defined(LIBC_SCCS) && !defined(lint) 12*46077Sbostic static char sccsid[] = "@(#)vfscanf.c 5.3 (Berkeley) 01/20/91"; 13*46077Sbostic #endif /* LIBC_SCCS and not lint */ 149415Smckusick 15*46077Sbostic #include <sys/stdc.h> 169415Smckusick #include <stdio.h> 17*46077Sbostic #include <ctype.h> 18*46077Sbostic #include <stdlib.h> 19*46077Sbostic #if __STDC__ 20*46077Sbostic #include <stdarg.h> 21*46077Sbostic #else 22*46077Sbostic #include <varargs.h> 23*46077Sbostic #endif 24*46077Sbostic #include "local.h" 259415Smckusick 26*46077Sbostic #define FLOATING_POINT 279415Smckusick 28*46077Sbostic #ifdef FLOATING_POINT 29*46077Sbostic #include "floatio.h" 30*46077Sbostic #define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */ 31*46077Sbostic #else 32*46077Sbostic #define BUF 40 33*46077Sbostic #endif 349415Smckusick 35*46077Sbostic /* 36*46077Sbostic * Flags used during conversion. 37*46077Sbostic */ 38*46077Sbostic #define LONG 0x01 /* l: long or double */ 39*46077Sbostic #define LONGDBL 0x02 /* L: long double; unimplemented */ 40*46077Sbostic #define SHORT 0x04 /* h: short */ 41*46077Sbostic #define SUPPRESS 0x08 /* suppress assignment */ 42*46077Sbostic #define POINTER 0x10 /* weird %p pointer (`fake hex') */ 43*46077Sbostic #define NOSKIP 0x20 /* do not skip blanks */ 449415Smckusick 45*46077Sbostic /* 46*46077Sbostic * The following are used in numeric conversions only: 47*46077Sbostic * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; 48*46077Sbostic * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. 49*46077Sbostic */ 50*46077Sbostic #define SIGNOK 0x40 /* +/- is (still) legal */ 51*46077Sbostic #define NDIGITS 0x80 /* no digits detected */ 529415Smckusick 53*46077Sbostic #define DPTOK 0x100 /* (float) decimal point is still legal */ 54*46077Sbostic #define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */ 55*46077Sbostic 56*46077Sbostic #define PFXOK 0x100 /* 0x prefix is (still) legal */ 57*46077Sbostic #define NZDIGITS 0x200 /* no zero digits detected */ 58*46077Sbostic 59*46077Sbostic /* 60*46077Sbostic * Conversion types. 61*46077Sbostic */ 62*46077Sbostic #define CT_CHAR 0 /* %c conversion */ 63*46077Sbostic #define CT_CCL 1 /* %[...] conversion */ 64*46077Sbostic #define CT_STRING 2 /* %s conversion */ 65*46077Sbostic #define CT_INT 3 /* integer, i.e., strtol or strtoul */ 66*46077Sbostic #define CT_FLOAT 4 /* floating, i.e., strtod */ 67*46077Sbostic 68*46077Sbostic #define u_char unsigned char 69*46077Sbostic #define u_long unsigned long 70*46077Sbostic 71*46077Sbostic static u_char *__sccl(); 72*46077Sbostic 73*46077Sbostic /* 74*46077Sbostic * vfscanf 75*46077Sbostic */ 76*46077Sbostic __svfscanf(fp, fmt0, ap) 77*46077Sbostic register FILE *fp; 78*46077Sbostic char const *fmt0; 79*46077Sbostic va_list ap; 809415Smckusick { 81*46077Sbostic register u_char *fmt = (u_char *)fmt0; 82*46077Sbostic register int c; /* character from format, or conversion */ 83*46077Sbostic register size_t width; /* field width, or 0 */ 84*46077Sbostic register char *p; /* points into all kinds of strings */ 85*46077Sbostic register int n; /* handy integer */ 86*46077Sbostic register int flags; /* flags as defined above */ 87*46077Sbostic register char *p0; /* saves original value of p when necessary */ 88*46077Sbostic int nassigned; /* number of fields assigned */ 89*46077Sbostic int nread; /* number of characters consumed from fp */ 90*46077Sbostic int base; /* base argument to strtol/strtoul */ 91*46077Sbostic u_long (*ccfn)(); /* conversion function (strtol/strtoul) */ 92*46077Sbostic char ccltab[256]; /* character class table for %[...] */ 93*46077Sbostic char buf[BUF]; /* buffer for numeric conversions */ 949415Smckusick 95*46077Sbostic /* `basefix' is used to avoid `if' tests in the integer scanner */ 96*46077Sbostic static short basefix[17] = 97*46077Sbostic { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 98*46077Sbostic 99*46077Sbostic nassigned = 0; 100*46077Sbostic nread = 0; 101*46077Sbostic for (;;) { 102*46077Sbostic c = *fmt++; 103*46077Sbostic if (c == 0) 104*46077Sbostic return (nassigned); 105*46077Sbostic if (isspace(c)) { 106*46077Sbostic for (;;) { 107*46077Sbostic if (fp->_r <= 0 && __srefill(fp)) 108*46077Sbostic return (nassigned); 109*46077Sbostic if (!isspace(*fp->_p)) 110*46077Sbostic break; 111*46077Sbostic nread++, fp->_r--, fp->_p++; 112*46077Sbostic } 113*46077Sbostic continue; 1149415Smckusick } 115*46077Sbostic if (c != '%') 116*46077Sbostic goto literal; 117*46077Sbostic width = 0; 118*46077Sbostic flags = 0; 119*46077Sbostic /* 120*46077Sbostic * switch on the format. continue if done; 121*46077Sbostic * break once format type is derived. 122*46077Sbostic */ 123*46077Sbostic again: c = *fmt++; 124*46077Sbostic switch (c) { 125*46077Sbostic case '%': 126*46077Sbostic literal: 127*46077Sbostic if (fp->_r <= 0 && __srefill(fp)) 128*46077Sbostic goto input_failure; 129*46077Sbostic if (*fp->_p != c) 130*46077Sbostic goto match_failure; 131*46077Sbostic fp->_r--, fp->_p++; 132*46077Sbostic nread++; 133*46077Sbostic continue; 134*46077Sbostic 135*46077Sbostic case '*': 136*46077Sbostic flags |= SUPPRESS; 137*46077Sbostic goto again; 138*46077Sbostic case 'l': 139*46077Sbostic flags |= LONG; 140*46077Sbostic goto again; 141*46077Sbostic case 'L': 142*46077Sbostic flags |= LONGDBL; 143*46077Sbostic goto again; 144*46077Sbostic case 'h': 145*46077Sbostic flags |= SHORT; 146*46077Sbostic goto again; 147*46077Sbostic 148*46077Sbostic case '0': case '1': case '2': case '3': case '4': 149*46077Sbostic case '5': case '6': case '7': case '8': case '9': 150*46077Sbostic width = width * 10 + c - '0'; 151*46077Sbostic goto again; 152*46077Sbostic 153*46077Sbostic /* 154*46077Sbostic * Conversions. 155*46077Sbostic * Those marked `compat' are for 4.[123]BSD compatibility. 156*46077Sbostic * 157*46077Sbostic * (According to ANSI, E and X formats are supposed 158*46077Sbostic * to the same as e and x. Sorry about that.) 159*46077Sbostic */ 160*46077Sbostic case 'D': /* compat */ 161*46077Sbostic flags |= LONG; 162*46077Sbostic /* FALLTHROUGH */ 163*46077Sbostic case 'd': 164*46077Sbostic c = CT_INT; 165*46077Sbostic ccfn = (u_long (*)())strtol; 166*46077Sbostic base = 10; 167*46077Sbostic break; 168*46077Sbostic 169*46077Sbostic case 'i': 170*46077Sbostic c = CT_INT; 171*46077Sbostic ccfn = (u_long (*)())strtol; 172*46077Sbostic base = 0; 173*46077Sbostic break; 174*46077Sbostic 175*46077Sbostic case 'O': /* compat */ 176*46077Sbostic flags |= LONG; 177*46077Sbostic /* FALLTHROUGH */ 178*46077Sbostic case 'o': 179*46077Sbostic c = CT_INT; 180*46077Sbostic ccfn = strtoul; 181*46077Sbostic base = 8; 182*46077Sbostic break; 183*46077Sbostic 184*46077Sbostic case 'u': 185*46077Sbostic c = CT_INT; 186*46077Sbostic ccfn = strtoul; 187*46077Sbostic base = 10; 188*46077Sbostic break; 189*46077Sbostic 190*46077Sbostic case 'X': /* compat XXX */ 191*46077Sbostic flags |= LONG; 192*46077Sbostic /* FALLTHROUGH */ 193*46077Sbostic case 'x': 194*46077Sbostic flags |= PFXOK; /* enable 0x prefixing */ 195*46077Sbostic c = CT_INT; 196*46077Sbostic ccfn = strtoul; 197*46077Sbostic base = 16; 198*46077Sbostic break; 199*46077Sbostic 200*46077Sbostic #ifdef FLOATING_POINT 201*46077Sbostic case 'E': /* compat XXX */ 202*46077Sbostic case 'F': /* compat */ 203*46077Sbostic flags |= LONG; 204*46077Sbostic /* FALLTHROUGH */ 205*46077Sbostic case 'e': case 'f': case 'g': 206*46077Sbostic c = CT_FLOAT; 207*46077Sbostic break; 208*46077Sbostic #endif 209*46077Sbostic 210*46077Sbostic case 's': 211*46077Sbostic c = CT_STRING; 212*46077Sbostic break; 213*46077Sbostic 214*46077Sbostic case '[': 215*46077Sbostic fmt = __sccl(ccltab, fmt); 216*46077Sbostic flags |= NOSKIP; 217*46077Sbostic c = CT_CCL; 218*46077Sbostic break; 219*46077Sbostic 220*46077Sbostic case 'c': 221*46077Sbostic flags |= NOSKIP; 222*46077Sbostic c = CT_CHAR; 223*46077Sbostic break; 224*46077Sbostic 225*46077Sbostic case 'p': /* pointer format is like hex */ 226*46077Sbostic flags |= POINTER | PFXOK; 227*46077Sbostic c = CT_INT; 228*46077Sbostic ccfn = strtoul; 229*46077Sbostic base = 16; 230*46077Sbostic break; 231*46077Sbostic 232*46077Sbostic case 'n': 233*46077Sbostic if (flags & SUPPRESS) /* ??? */ 234*46077Sbostic continue; 235*46077Sbostic if (flags & SHORT) 236*46077Sbostic *va_arg(ap, short *) = nread; 237*46077Sbostic else if (flags & LONG) 238*46077Sbostic *va_arg(ap, long *) = nread; 239*46077Sbostic else 240*46077Sbostic *va_arg(ap, int *) = nread; 241*46077Sbostic continue; 242*46077Sbostic 243*46077Sbostic /* 244*46077Sbostic * Disgusting backwards compatibility hacks. XXX 245*46077Sbostic */ 246*46077Sbostic case '\0': /* compat */ 247*46077Sbostic return (EOF); 248*46077Sbostic 249*46077Sbostic default: /* compat */ 250*46077Sbostic if (isupper(c)) 251*46077Sbostic flags |= LONG; 252*46077Sbostic c = CT_INT; 253*46077Sbostic ccfn = (u_long (*)())strtol; 254*46077Sbostic base = 10; 255*46077Sbostic break; 2569415Smckusick } 2579415Smckusick 258*46077Sbostic /* 259*46077Sbostic * We have a conversion that requires input. 260*46077Sbostic */ 261*46077Sbostic if (fp->_r <= 0 && __srefill(fp)) 262*46077Sbostic goto input_failure; 2639415Smckusick 264*46077Sbostic /* 265*46077Sbostic * Consume leading white space, except for formats 266*46077Sbostic * that suppress this. 267*46077Sbostic */ 268*46077Sbostic if ((flags & NOSKIP) == 0) { 269*46077Sbostic while (isspace(*fp->_p)) { 270*46077Sbostic nread++; 271*46077Sbostic if (--fp->_r > 0) 272*46077Sbostic fp->_p++; 273*46077Sbostic else if (__srefill(fp)) 274*46077Sbostic goto input_failure; 275*46077Sbostic } 276*46077Sbostic /* 277*46077Sbostic * Note that there is at least one character in 278*46077Sbostic * the buffer, so conversions that do not set NOSKIP 279*46077Sbostic * ca no longer result in an input failure. 280*46077Sbostic */ 2819415Smckusick } 2829415Smckusick 283*46077Sbostic /* 284*46077Sbostic * Do the conversion. 285*46077Sbostic */ 286*46077Sbostic switch (c) { 2879415Smckusick 288*46077Sbostic case CT_CHAR: 289*46077Sbostic /* scan arbitrary characters (sets NOSKIP) */ 290*46077Sbostic if (width == 0) 291*46077Sbostic width = 1; 292*46077Sbostic if (flags & SUPPRESS) { 293*46077Sbostic size_t sum = 0; 294*46077Sbostic for (;;) { 295*46077Sbostic if ((n = fp->_r) < width) { 296*46077Sbostic sum += n; 297*46077Sbostic width -= n; 298*46077Sbostic fp->_p += n; 299*46077Sbostic if (__srefill(fp)) { 300*46077Sbostic if (sum == 0) 301*46077Sbostic goto input_failure; 302*46077Sbostic break; 303*46077Sbostic } 304*46077Sbostic } else { 305*46077Sbostic sum += width; 306*46077Sbostic fp->_r -= width; 307*46077Sbostic fp->_p += width; 308*46077Sbostic break; 309*46077Sbostic } 310*46077Sbostic } 311*46077Sbostic nread += sum; 312*46077Sbostic } else { 313*46077Sbostic size_t r = fread((void *)va_arg(ap, char *), 1, 314*46077Sbostic width, fp); 315*46077Sbostic 316*46077Sbostic if (r == 0) 317*46077Sbostic goto input_failure; 318*46077Sbostic nread += r; 319*46077Sbostic nassigned++; 320*46077Sbostic } 321*46077Sbostic break; 322*46077Sbostic 323*46077Sbostic case CT_CCL: 324*46077Sbostic /* scan a (nonempty) character class (sets NOSKIP) */ 325*46077Sbostic if (width == 0) 326*46077Sbostic width = ~0; /* `infinity' */ 327*46077Sbostic /* take only those things in the class */ 328*46077Sbostic if (flags & SUPPRESS) { 329*46077Sbostic n = 0; 330*46077Sbostic while (ccltab[*fp->_p]) { 331*46077Sbostic n++, fp->_r--, fp->_p++; 332*46077Sbostic if (--width == 0) 333*46077Sbostic break; 334*46077Sbostic if (fp->_r <= 0 && __srefill(fp)) { 335*46077Sbostic if (n == 0) 336*46077Sbostic goto input_failure; 337*46077Sbostic break; 338*46077Sbostic } 339*46077Sbostic } 340*46077Sbostic if (n == 0) 341*46077Sbostic goto match_failure; 342*46077Sbostic } else { 343*46077Sbostic p0 = p = va_arg(ap, char *); 344*46077Sbostic while (ccltab[*fp->_p]) { 345*46077Sbostic fp->_r--; 346*46077Sbostic *p++ = *fp->_p++; 347*46077Sbostic if (--width == 0) 348*46077Sbostic break; 349*46077Sbostic if (fp->_r <= 0 && __srefill(fp)) { 350*46077Sbostic if (p == p0) 351*46077Sbostic goto input_failure; 352*46077Sbostic break; 353*46077Sbostic } 354*46077Sbostic } 355*46077Sbostic n = p - p0; 356*46077Sbostic if (n == 0) 357*46077Sbostic goto match_failure; 358*46077Sbostic *p = 0; 359*46077Sbostic nassigned++; 360*46077Sbostic } 361*46077Sbostic nread += n; 362*46077Sbostic break; 363*46077Sbostic 364*46077Sbostic case CT_STRING: 365*46077Sbostic /* like CCL, but zero-length string OK, & no NOSKIP */ 366*46077Sbostic if (width == 0) 367*46077Sbostic width = ~0; 368*46077Sbostic if (flags & SUPPRESS) { 369*46077Sbostic n = 0; 370*46077Sbostic while (!isspace(*fp->_p)) { 371*46077Sbostic n++, fp->_r--, fp->_p++; 372*46077Sbostic if (--width == 0) 373*46077Sbostic break; 374*46077Sbostic if (fp->_r <= 0 && __srefill(fp)) 375*46077Sbostic break; 376*46077Sbostic } 377*46077Sbostic nread += n; 378*46077Sbostic } else { 379*46077Sbostic p0 = p = va_arg(ap, char *); 380*46077Sbostic while (!isspace(*fp->_p)) { 381*46077Sbostic fp->_r--; 382*46077Sbostic *p++ = *fp->_p++; 383*46077Sbostic if (--width == 0) 384*46077Sbostic break; 385*46077Sbostic if (fp->_r <= 0 && __srefill(fp)) 386*46077Sbostic break; 387*46077Sbostic } 388*46077Sbostic *p = 0; 389*46077Sbostic nread += p - p0; 390*46077Sbostic nassigned++; 391*46077Sbostic } 3929415Smckusick continue; 393*46077Sbostic 394*46077Sbostic case CT_INT: 395*46077Sbostic /* scan an integer as if by strtol/strtoul */ 396*46077Sbostic #ifdef hardway 397*46077Sbostic if (width == 0 || width > sizeof(buf) - 1) 398*46077Sbostic width = sizeof(buf) - 1; 399*46077Sbostic #else 400*46077Sbostic /* size_t is unsigned, hence this optimisation */ 401*46077Sbostic if (--width > sizeof(buf) - 2) 402*46077Sbostic width = sizeof(buf) - 2; 403*46077Sbostic width++; 404*46077Sbostic #endif 405*46077Sbostic flags |= SIGNOK | NDIGITS | NZDIGITS; 406*46077Sbostic for (p = buf; width; width--) { 407*46077Sbostic c = *fp->_p; 408*46077Sbostic /* 409*46077Sbostic * Switch on the character; `goto ok' 410*46077Sbostic * if we accept it as a part of number. 411*46077Sbostic */ 412*46077Sbostic switch (c) { 413*46077Sbostic 414*46077Sbostic /* 415*46077Sbostic * The digit 0 is always legal, but is 416*46077Sbostic * special. For %i conversions, if no 417*46077Sbostic * digits (zero or nonzero) have been 418*46077Sbostic * scanned (only signs), we will have 419*46077Sbostic * base==0. In that case, we should set 420*46077Sbostic * it to 8 and enable 0x prefixing. 421*46077Sbostic * Also, if we have not scanned zero digits 422*46077Sbostic * before this, do not turn off prefixing 423*46077Sbostic * (someone else will turn it off if we 424*46077Sbostic * have scanned any nonzero digits). 425*46077Sbostic */ 426*46077Sbostic case '0': 427*46077Sbostic if (base == 0) { 428*46077Sbostic base = 8; 429*46077Sbostic flags |= PFXOK; 430*46077Sbostic } 431*46077Sbostic if (flags & NZDIGITS) 432*46077Sbostic flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 433*46077Sbostic else 434*46077Sbostic flags &= ~(SIGNOK|PFXOK|NDIGITS); 435*46077Sbostic goto ok; 436*46077Sbostic 437*46077Sbostic /* 1 through 7 always legal */ 438*46077Sbostic case '1': case '2': case '3': 439*46077Sbostic case '4': case '5': case '6': case '7': 440*46077Sbostic base = basefix[base]; 441*46077Sbostic flags &= ~(SIGNOK | PFXOK | NDIGITS); 442*46077Sbostic goto ok; 443*46077Sbostic 444*46077Sbostic /* digits 8 and 9 ok iff decimal or hex */ 445*46077Sbostic case '8': case '9': 446*46077Sbostic base = basefix[base]; 447*46077Sbostic if (base <= 8) 448*46077Sbostic break; /* not legal here */ 449*46077Sbostic flags &= ~(SIGNOK | PFXOK | NDIGITS); 450*46077Sbostic goto ok; 451*46077Sbostic 452*46077Sbostic /* letters ok iff hex */ 453*46077Sbostic case 'A': case 'B': case 'C': 454*46077Sbostic case 'D': case 'E': case 'F': 455*46077Sbostic case 'a': case 'b': case 'c': 456*46077Sbostic case 'd': case 'e': case 'f': 457*46077Sbostic /* no need to fix base here */ 458*46077Sbostic if (base <= 10) 459*46077Sbostic break; /* not legal here */ 460*46077Sbostic flags &= ~(SIGNOK | PFXOK | NDIGITS); 461*46077Sbostic goto ok; 462*46077Sbostic 463*46077Sbostic /* sign ok only as first character */ 464*46077Sbostic case '+': case '-': 465*46077Sbostic if (flags & SIGNOK) { 466*46077Sbostic flags &= ~SIGNOK; 467*46077Sbostic goto ok; 468*46077Sbostic } 469*46077Sbostic break; 470*46077Sbostic 471*46077Sbostic /* x ok iff flag still set & 2nd char */ 472*46077Sbostic case 'x': case 'X': 473*46077Sbostic if (flags & PFXOK && p == buf + 1) { 474*46077Sbostic base = 16; /* if %i */ 475*46077Sbostic flags &= ~PFXOK; 476*46077Sbostic goto ok; 477*46077Sbostic } 478*46077Sbostic break; 479*46077Sbostic } 480*46077Sbostic 481*46077Sbostic /* 482*46077Sbostic * If we got here, c is not a legal character 483*46077Sbostic * for a number. Stop accumulating digits. 484*46077Sbostic */ 4859415Smckusick break; 486*46077Sbostic ok: 487*46077Sbostic /* 488*46077Sbostic * c is legal: store it and look at the next. 489*46077Sbostic */ 490*46077Sbostic *p++ = c; 491*46077Sbostic if (--fp->_r > 0) 492*46077Sbostic fp->_p++; 493*46077Sbostic else if (__srefill(fp)) 494*46077Sbostic break; /* EOF */ 495*46077Sbostic } 496*46077Sbostic /* 497*46077Sbostic * If we had only a sign, it is no good; push 498*46077Sbostic * back the sign. If the number ends in `x', 499*46077Sbostic * it was [sign] '0' 'x', so push back the x 500*46077Sbostic * and treat it as [sign] '0'. 501*46077Sbostic */ 502*46077Sbostic if (flags & NDIGITS) { 503*46077Sbostic if (p > buf) 504*46077Sbostic (void) ungetc(*(u_char *)--p, fp); 505*46077Sbostic goto match_failure; 506*46077Sbostic } 507*46077Sbostic c = ((u_char *)p)[-1]; 508*46077Sbostic if (c == 'x' || c == 'X') { 509*46077Sbostic --p; 510*46077Sbostic (void) ungetc(c, fp); 511*46077Sbostic } 512*46077Sbostic if ((flags & SUPPRESS) == 0) { 513*46077Sbostic u_long res; 514*46077Sbostic 515*46077Sbostic *p = 0; 516*46077Sbostic res = (*ccfn)(buf, (char **)NULL, base); 517*46077Sbostic if (flags & POINTER) 518*46077Sbostic *va_arg(ap, void **) = (void *)res; 519*46077Sbostic else if (flags & SHORT) 520*46077Sbostic *va_arg(ap, short *) = res; 521*46077Sbostic else if (flags & LONG) 522*46077Sbostic *va_arg(ap, long *) = res; 523*46077Sbostic else 524*46077Sbostic *va_arg(ap, int *) = res; 525*46077Sbostic nassigned++; 526*46077Sbostic } 527*46077Sbostic nread += p - buf; 5289415Smckusick break; 5299415Smckusick 530*46077Sbostic #ifdef FLOATING_POINT 531*46077Sbostic case CT_FLOAT: 532*46077Sbostic /* scan a floating point number as if by strtod */ 533*46077Sbostic #ifdef hardway 534*46077Sbostic if (width == 0 || width > sizeof(buf) - 1) 535*46077Sbostic width = sizeof(buf) - 1; 536*46077Sbostic #else 537*46077Sbostic /* size_t is unsigned, hence this optimisation */ 538*46077Sbostic if (--width > sizeof(buf) - 2) 539*46077Sbostic width = sizeof(buf) - 2; 540*46077Sbostic width++; 541*46077Sbostic #endif 542*46077Sbostic flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; 543*46077Sbostic for (p = buf; width; width--) { 544*46077Sbostic c = *fp->_p; 545*46077Sbostic /* 546*46077Sbostic * This code mimicks the integer conversion 547*46077Sbostic * code, but is much simpler. 548*46077Sbostic */ 549*46077Sbostic switch (c) { 5509415Smckusick 551*46077Sbostic case '0': case '1': case '2': case '3': 552*46077Sbostic case '4': case '5': case '6': case '7': 553*46077Sbostic case '8': case '9': 554*46077Sbostic flags &= ~(SIGNOK | NDIGITS); 555*46077Sbostic goto fok; 5569415Smckusick 557*46077Sbostic case '+': case '-': 558*46077Sbostic if (flags & SIGNOK) { 559*46077Sbostic flags &= ~SIGNOK; 560*46077Sbostic goto fok; 561*46077Sbostic } 562*46077Sbostic break; 563*46077Sbostic case '.': 564*46077Sbostic if (flags & DPTOK) { 565*46077Sbostic flags &= ~(SIGNOK | DPTOK); 566*46077Sbostic goto fok; 567*46077Sbostic } 568*46077Sbostic break; 569*46077Sbostic case 'e': case 'E': 570*46077Sbostic /* no exponent without some digits */ 571*46077Sbostic if ((flags&(NDIGITS|EXPOK)) == EXPOK) { 572*46077Sbostic flags = 573*46077Sbostic (flags & ~(EXPOK|DPTOK)) | 574*46077Sbostic SIGNOK | NDIGITS; 575*46077Sbostic goto fok; 576*46077Sbostic } 577*46077Sbostic break; 578*46077Sbostic } 579*46077Sbostic break; 580*46077Sbostic fok: 581*46077Sbostic *p++ = c; 582*46077Sbostic if (--fp->_r > 0) 583*46077Sbostic fp->_p++; 584*46077Sbostic else if (__srefill(fp)) 585*46077Sbostic break; /* EOF */ 586*46077Sbostic } 587*46077Sbostic /* 588*46077Sbostic * If no digits, might be missing exponent digits 589*46077Sbostic * (just give back the exponent) or might be missing 590*46077Sbostic * regular digits, but had sign and/or decimal point. 591*46077Sbostic */ 592*46077Sbostic if (flags & NDIGITS) { 593*46077Sbostic if (flags & EXPOK) { 594*46077Sbostic /* no digits at all */ 595*46077Sbostic while (p > buf) 596*46077Sbostic ungetc(*(u_char *)--p, fp); 597*46077Sbostic goto match_failure; 598*46077Sbostic } 599*46077Sbostic /* just a bad exponent (e and maybe sign) */ 600*46077Sbostic c = *(u_char *)--p; 601*46077Sbostic if (c != 'e' && c != 'E') { 602*46077Sbostic (void) ungetc(c, fp);/* sign */ 603*46077Sbostic c = *(u_char *)--p; 604*46077Sbostic } 605*46077Sbostic (void) ungetc(c, fp); 606*46077Sbostic } 607*46077Sbostic if ((flags & SUPPRESS) == 0) { 608*46077Sbostic double res; 6099415Smckusick 610*46077Sbostic *p = 0; 611*46077Sbostic res = atof(buf); 612*46077Sbostic if (flags & LONG) 613*46077Sbostic *va_arg(ap, double *) = res; 614*46077Sbostic else 615*46077Sbostic *va_arg(ap, float *) = res; 616*46077Sbostic nassigned++; 617*46077Sbostic } 618*46077Sbostic nread += p - buf; 619*46077Sbostic break; 620*46077Sbostic #endif /* FLOATING_POINT */ 621*46077Sbostic } 6229415Smckusick } 623*46077Sbostic input_failure: 624*46077Sbostic return (nassigned ? nassigned : -1); 625*46077Sbostic match_failure: 626*46077Sbostic return (nassigned); 6279415Smckusick } 6289415Smckusick 629*46077Sbostic /* 630*46077Sbostic * Fill in the given table from the scanset at the given format 631*46077Sbostic * (just after `['). Return a pointer to the character past the 632*46077Sbostic * closing `]'. The table has a 1 wherever characters should be 633*46077Sbostic * considered part of the scanset. 634*46077Sbostic */ 635*46077Sbostic static u_char * 636*46077Sbostic __sccl(tab, fmt) 637*46077Sbostic register char *tab; 638*46077Sbostic register u_char *fmt; 6399415Smckusick { 640*46077Sbostic register int c, n, v; 6419415Smckusick 642*46077Sbostic /* first `clear' the whole table */ 643*46077Sbostic c = *fmt++; /* first char hat => negated scanset */ 644*46077Sbostic if (c == '^') { 645*46077Sbostic v = 1; /* default => accept */ 646*46077Sbostic c = *fmt++; /* get new first char */ 6479415Smckusick } else 648*46077Sbostic v = 0; /* default => reject */ 649*46077Sbostic /* should probably use memset here */ 650*46077Sbostic for (n = 0; n < 256; n++) 651*46077Sbostic tab[n] = v; 652*46077Sbostic if (c == 0) 653*46077Sbostic return (fmt - 1);/* format ended before closing ] */ 6549415Smckusick 655*46077Sbostic /* 656*46077Sbostic * Now set the entries corresponding to the actual scanset 657*46077Sbostic * to the opposite of the above. 658*46077Sbostic * 659*46077Sbostic * The first character may be ']' (or '-') without being special; 660*46077Sbostic * the last character may be '-'. 661*46077Sbostic */ 662*46077Sbostic v = 1 - v; 663*46077Sbostic for (;;) { 664*46077Sbostic tab[c] = v; /* take character c */ 665*46077Sbostic doswitch: 666*46077Sbostic n = *fmt++; /* and examine the next */ 667*46077Sbostic switch (n) { 6689415Smckusick 669*46077Sbostic case 0: /* format ended too soon */ 670*46077Sbostic return (fmt - 1); 671*46077Sbostic 672*46077Sbostic case '-': 673*46077Sbostic /* 674*46077Sbostic * A scanset of the form 675*46077Sbostic * [01+-] 676*46077Sbostic * is defined as `the digit 0, the digit 1, 677*46077Sbostic * the character +, the character -', but 678*46077Sbostic * the effect of a scanset such as 679*46077Sbostic * [a-zA-Z0-9] 680*46077Sbostic * is implementation defined. The V7 Unix 681*46077Sbostic * scanf treats `a-z' as `the letters a through 682*46077Sbostic * z', but treats `a-a' as `the letter a, the 683*46077Sbostic * character -, and the letter a'. 684*46077Sbostic * 685*46077Sbostic * For compatibility, the `-' is not considerd 686*46077Sbostic * to define a range if the character following 687*46077Sbostic * it is either a close bracket (required by ANSI) 688*46077Sbostic * or is not numerically greater than the character 689*46077Sbostic * we just stored in the table (c). 690*46077Sbostic */ 691*46077Sbostic n = *fmt; 692*46077Sbostic if (n == ']' || n < c) { 693*46077Sbostic c = '-'; 694*46077Sbostic break; /* resume the for(;;) */ 695*46077Sbostic } 696*46077Sbostic fmt++; 697*46077Sbostic do { /* fill in the range */ 698*46077Sbostic tab[++c] = v; 699*46077Sbostic } while (c < n); 700*46077Sbostic #if 1 /* XXX another disgusting compatibility hack */ 701*46077Sbostic /* 702*46077Sbostic * Alas, the V7 Unix scanf also treats formats 703*46077Sbostic * such as [a-c-e] as `the letters a through e'. 704*46077Sbostic * This too is permitted by the standard.... 705*46077Sbostic */ 706*46077Sbostic goto doswitch; 707*46077Sbostic #else 708*46077Sbostic c = *fmt++; 709*46077Sbostic if (c == 0) 710*46077Sbostic return (fmt - 1); 711*46077Sbostic if (c == ']') 712*46077Sbostic return (fmt); 713*46077Sbostic #endif 714*46077Sbostic break; 715*46077Sbostic 716*46077Sbostic case ']': /* end of scanset */ 717*46077Sbostic return (fmt); 718*46077Sbostic 719*46077Sbostic default: /* just another character */ 720*46077Sbostic c = n; 721*46077Sbostic break; 722*46077Sbostic } 7239415Smckusick } 724*46077Sbostic /* NOTREACHED */ 7259415Smckusick } 726