146077Sbostic /*- 246077Sbostic * Copyright (c) 1990 The Regents of the University of California. 346077Sbostic * All rights reserved. 446077Sbostic * 546077Sbostic * This code is derived from software contributed to Berkeley by 646077Sbostic * Chris Torek. 746077Sbostic * 846077Sbostic * %sccs.include.redist.c% 946077Sbostic */ 1046077Sbostic 1126640Sdonn #if defined(LIBC_SCCS) && !defined(lint) 12*46273Storek static char sccsid[] = "@(#)vfscanf.c 5.5 (Berkeley) 02/05/91"; 1346077Sbostic #endif /* LIBC_SCCS and not lint */ 149415Smckusick 1546220Sbostic #include <sys/cdefs.h> 169415Smckusick #include <stdio.h> 1746077Sbostic #include <ctype.h> 1846077Sbostic #include <stdlib.h> 1946077Sbostic #if __STDC__ 2046077Sbostic #include <stdarg.h> 2146077Sbostic #else 2246077Sbostic #include <varargs.h> 2346077Sbostic #endif 2446077Sbostic #include "local.h" 259415Smckusick 2646077Sbostic #define FLOATING_POINT 279415Smckusick 2846077Sbostic #ifdef FLOATING_POINT 2946077Sbostic #include "floatio.h" 3046077Sbostic #define BUF (MAXEXP+MAXFRACT+3) /* 3 = sign + decimal point + NUL */ 3146077Sbostic #else 3246077Sbostic #define BUF 40 3346077Sbostic #endif 349415Smckusick 3546077Sbostic /* 3646077Sbostic * Flags used during conversion. 3746077Sbostic */ 3846077Sbostic #define LONG 0x01 /* l: long or double */ 3946077Sbostic #define LONGDBL 0x02 /* L: long double; unimplemented */ 4046077Sbostic #define SHORT 0x04 /* h: short */ 4146077Sbostic #define SUPPRESS 0x08 /* suppress assignment */ 4246077Sbostic #define POINTER 0x10 /* weird %p pointer (`fake hex') */ 4346077Sbostic #define NOSKIP 0x20 /* do not skip blanks */ 449415Smckusick 4546077Sbostic /* 4646077Sbostic * The following are used in numeric conversions only: 4746077Sbostic * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; 4846077Sbostic * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. 4946077Sbostic */ 5046077Sbostic #define SIGNOK 0x40 /* +/- is (still) legal */ 5146077Sbostic #define NDIGITS 0x80 /* no digits detected */ 529415Smckusick 5346077Sbostic #define DPTOK 0x100 /* (float) decimal point is still legal */ 5446077Sbostic #define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */ 5546077Sbostic 5646077Sbostic #define PFXOK 0x100 /* 0x prefix is (still) legal */ 5746077Sbostic #define NZDIGITS 0x200 /* no zero digits detected */ 5846077Sbostic 5946077Sbostic /* 6046077Sbostic * Conversion types. 6146077Sbostic */ 6246077Sbostic #define CT_CHAR 0 /* %c conversion */ 6346077Sbostic #define CT_CCL 1 /* %[...] conversion */ 6446077Sbostic #define CT_STRING 2 /* %s conversion */ 6546077Sbostic #define CT_INT 3 /* integer, i.e., strtol or strtoul */ 6646077Sbostic #define CT_FLOAT 4 /* floating, i.e., strtod */ 6746077Sbostic 6846077Sbostic #define u_char unsigned char 6946077Sbostic #define u_long unsigned long 7046077Sbostic 7146077Sbostic static u_char *__sccl(); 7246077Sbostic 7346077Sbostic /* 7446077Sbostic * vfscanf 7546077Sbostic */ 7646077Sbostic __svfscanf(fp, fmt0, ap) 7746077Sbostic register FILE *fp; 7846077Sbostic char const *fmt0; 7946077Sbostic va_list ap; 809415Smckusick { 8146077Sbostic register u_char *fmt = (u_char *)fmt0; 8246077Sbostic register int c; /* character from format, or conversion */ 8346077Sbostic register size_t width; /* field width, or 0 */ 8446077Sbostic register char *p; /* points into all kinds of strings */ 8546077Sbostic register int n; /* handy integer */ 8646077Sbostic register int flags; /* flags as defined above */ 8746077Sbostic register char *p0; /* saves original value of p when necessary */ 8846077Sbostic int nassigned; /* number of fields assigned */ 8946077Sbostic int nread; /* number of characters consumed from fp */ 9046077Sbostic int base; /* base argument to strtol/strtoul */ 9146077Sbostic u_long (*ccfn)(); /* conversion function (strtol/strtoul) */ 9246077Sbostic char ccltab[256]; /* character class table for %[...] */ 9346077Sbostic char buf[BUF]; /* buffer for numeric conversions */ 949415Smckusick 9546077Sbostic /* `basefix' is used to avoid `if' tests in the integer scanner */ 9646077Sbostic static short basefix[17] = 9746077Sbostic { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 9846077Sbostic 9946077Sbostic nassigned = 0; 10046077Sbostic nread = 0; 101*46273Storek base = 0; /* XXX just to keep gcc happy */ 102*46273Storek ccfn = NULL; /* XXX just to keep gcc happy */ 10346077Sbostic for (;;) { 10446077Sbostic c = *fmt++; 10546077Sbostic if (c == 0) 10646077Sbostic return (nassigned); 10746077Sbostic if (isspace(c)) { 10846077Sbostic for (;;) { 10946077Sbostic if (fp->_r <= 0 && __srefill(fp)) 11046077Sbostic return (nassigned); 11146077Sbostic if (!isspace(*fp->_p)) 11246077Sbostic break; 11346077Sbostic nread++, fp->_r--, fp->_p++; 11446077Sbostic } 11546077Sbostic continue; 1169415Smckusick } 11746077Sbostic if (c != '%') 11846077Sbostic goto literal; 11946077Sbostic width = 0; 12046077Sbostic flags = 0; 12146077Sbostic /* 12246077Sbostic * switch on the format. continue if done; 12346077Sbostic * break once format type is derived. 12446077Sbostic */ 12546077Sbostic again: c = *fmt++; 12646077Sbostic switch (c) { 12746077Sbostic case '%': 12846077Sbostic literal: 12946077Sbostic if (fp->_r <= 0 && __srefill(fp)) 13046077Sbostic goto input_failure; 13146077Sbostic if (*fp->_p != c) 13246077Sbostic goto match_failure; 13346077Sbostic fp->_r--, fp->_p++; 13446077Sbostic nread++; 13546077Sbostic continue; 13646077Sbostic 13746077Sbostic case '*': 13846077Sbostic flags |= SUPPRESS; 13946077Sbostic goto again; 14046077Sbostic case 'l': 14146077Sbostic flags |= LONG; 14246077Sbostic goto again; 14346077Sbostic case 'L': 14446077Sbostic flags |= LONGDBL; 14546077Sbostic goto again; 14646077Sbostic case 'h': 14746077Sbostic flags |= SHORT; 14846077Sbostic goto again; 14946077Sbostic 15046077Sbostic case '0': case '1': case '2': case '3': case '4': 15146077Sbostic case '5': case '6': case '7': case '8': case '9': 15246077Sbostic width = width * 10 + c - '0'; 15346077Sbostic goto again; 15446077Sbostic 15546077Sbostic /* 15646077Sbostic * Conversions. 15746077Sbostic * Those marked `compat' are for 4.[123]BSD compatibility. 15846077Sbostic * 15946077Sbostic * (According to ANSI, E and X formats are supposed 16046077Sbostic * to the same as e and x. Sorry about that.) 16146077Sbostic */ 16246077Sbostic case 'D': /* compat */ 16346077Sbostic flags |= LONG; 16446077Sbostic /* FALLTHROUGH */ 16546077Sbostic case 'd': 16646077Sbostic c = CT_INT; 16746077Sbostic ccfn = (u_long (*)())strtol; 16846077Sbostic base = 10; 16946077Sbostic break; 17046077Sbostic 17146077Sbostic case 'i': 17246077Sbostic c = CT_INT; 17346077Sbostic ccfn = (u_long (*)())strtol; 17446077Sbostic base = 0; 17546077Sbostic break; 17646077Sbostic 17746077Sbostic case 'O': /* compat */ 17846077Sbostic flags |= LONG; 17946077Sbostic /* FALLTHROUGH */ 18046077Sbostic case 'o': 18146077Sbostic c = CT_INT; 18246077Sbostic ccfn = strtoul; 18346077Sbostic base = 8; 18446077Sbostic break; 18546077Sbostic 18646077Sbostic case 'u': 18746077Sbostic c = CT_INT; 18846077Sbostic ccfn = strtoul; 18946077Sbostic base = 10; 19046077Sbostic break; 19146077Sbostic 19246077Sbostic case 'X': /* compat XXX */ 19346077Sbostic flags |= LONG; 19446077Sbostic /* FALLTHROUGH */ 19546077Sbostic case 'x': 19646077Sbostic flags |= PFXOK; /* enable 0x prefixing */ 19746077Sbostic c = CT_INT; 19846077Sbostic ccfn = strtoul; 19946077Sbostic base = 16; 20046077Sbostic break; 20146077Sbostic 20246077Sbostic #ifdef FLOATING_POINT 20346077Sbostic case 'E': /* compat XXX */ 20446077Sbostic case 'F': /* compat */ 20546077Sbostic flags |= LONG; 20646077Sbostic /* FALLTHROUGH */ 20746077Sbostic case 'e': case 'f': case 'g': 20846077Sbostic c = CT_FLOAT; 20946077Sbostic break; 21046077Sbostic #endif 21146077Sbostic 21246077Sbostic case 's': 21346077Sbostic c = CT_STRING; 21446077Sbostic break; 21546077Sbostic 21646077Sbostic case '[': 21746077Sbostic fmt = __sccl(ccltab, fmt); 21846077Sbostic flags |= NOSKIP; 21946077Sbostic c = CT_CCL; 22046077Sbostic break; 22146077Sbostic 22246077Sbostic case 'c': 22346077Sbostic flags |= NOSKIP; 22446077Sbostic c = CT_CHAR; 22546077Sbostic break; 22646077Sbostic 22746077Sbostic case 'p': /* pointer format is like hex */ 22846077Sbostic flags |= POINTER | PFXOK; 22946077Sbostic c = CT_INT; 23046077Sbostic ccfn = strtoul; 23146077Sbostic base = 16; 23246077Sbostic break; 23346077Sbostic 23446077Sbostic case 'n': 23546077Sbostic if (flags & SUPPRESS) /* ??? */ 23646077Sbostic continue; 23746077Sbostic if (flags & SHORT) 23846077Sbostic *va_arg(ap, short *) = nread; 23946077Sbostic else if (flags & LONG) 24046077Sbostic *va_arg(ap, long *) = nread; 24146077Sbostic else 24246077Sbostic *va_arg(ap, int *) = nread; 24346077Sbostic continue; 24446077Sbostic 24546077Sbostic /* 24646077Sbostic * Disgusting backwards compatibility hacks. XXX 24746077Sbostic */ 24846077Sbostic case '\0': /* compat */ 24946077Sbostic return (EOF); 25046077Sbostic 25146077Sbostic default: /* compat */ 25246077Sbostic if (isupper(c)) 25346077Sbostic flags |= LONG; 25446077Sbostic c = CT_INT; 25546077Sbostic ccfn = (u_long (*)())strtol; 25646077Sbostic base = 10; 25746077Sbostic break; 2589415Smckusick } 2599415Smckusick 26046077Sbostic /* 26146077Sbostic * We have a conversion that requires input. 26246077Sbostic */ 26346077Sbostic if (fp->_r <= 0 && __srefill(fp)) 26446077Sbostic goto input_failure; 2659415Smckusick 26646077Sbostic /* 26746077Sbostic * Consume leading white space, except for formats 26846077Sbostic * that suppress this. 26946077Sbostic */ 27046077Sbostic if ((flags & NOSKIP) == 0) { 27146077Sbostic while (isspace(*fp->_p)) { 27246077Sbostic nread++; 27346077Sbostic if (--fp->_r > 0) 27446077Sbostic fp->_p++; 27546077Sbostic else if (__srefill(fp)) 27646077Sbostic goto input_failure; 27746077Sbostic } 27846077Sbostic /* 27946077Sbostic * Note that there is at least one character in 28046077Sbostic * the buffer, so conversions that do not set NOSKIP 28146077Sbostic * ca no longer result in an input failure. 28246077Sbostic */ 2839415Smckusick } 2849415Smckusick 28546077Sbostic /* 28646077Sbostic * Do the conversion. 28746077Sbostic */ 28846077Sbostic switch (c) { 2899415Smckusick 29046077Sbostic case CT_CHAR: 29146077Sbostic /* scan arbitrary characters (sets NOSKIP) */ 29246077Sbostic if (width == 0) 29346077Sbostic width = 1; 29446077Sbostic if (flags & SUPPRESS) { 29546077Sbostic size_t sum = 0; 29646077Sbostic for (;;) { 29746077Sbostic if ((n = fp->_r) < width) { 29846077Sbostic sum += n; 29946077Sbostic width -= n; 30046077Sbostic fp->_p += n; 30146077Sbostic if (__srefill(fp)) { 30246077Sbostic if (sum == 0) 30346077Sbostic goto input_failure; 30446077Sbostic break; 30546077Sbostic } 30646077Sbostic } else { 30746077Sbostic sum += width; 30846077Sbostic fp->_r -= width; 30946077Sbostic fp->_p += width; 31046077Sbostic break; 31146077Sbostic } 31246077Sbostic } 31346077Sbostic nread += sum; 31446077Sbostic } else { 31546077Sbostic size_t r = fread((void *)va_arg(ap, char *), 1, 31646077Sbostic width, fp); 31746077Sbostic 31846077Sbostic if (r == 0) 31946077Sbostic goto input_failure; 32046077Sbostic nread += r; 32146077Sbostic nassigned++; 32246077Sbostic } 32346077Sbostic break; 32446077Sbostic 32546077Sbostic case CT_CCL: 32646077Sbostic /* scan a (nonempty) character class (sets NOSKIP) */ 32746077Sbostic if (width == 0) 32846077Sbostic width = ~0; /* `infinity' */ 32946077Sbostic /* take only those things in the class */ 33046077Sbostic if (flags & SUPPRESS) { 33146077Sbostic n = 0; 33246077Sbostic while (ccltab[*fp->_p]) { 33346077Sbostic n++, fp->_r--, fp->_p++; 33446077Sbostic if (--width == 0) 33546077Sbostic break; 33646077Sbostic if (fp->_r <= 0 && __srefill(fp)) { 33746077Sbostic if (n == 0) 33846077Sbostic goto input_failure; 33946077Sbostic break; 34046077Sbostic } 34146077Sbostic } 34246077Sbostic if (n == 0) 34346077Sbostic goto match_failure; 34446077Sbostic } else { 34546077Sbostic p0 = p = va_arg(ap, char *); 34646077Sbostic while (ccltab[*fp->_p]) { 34746077Sbostic fp->_r--; 34846077Sbostic *p++ = *fp->_p++; 34946077Sbostic if (--width == 0) 35046077Sbostic break; 35146077Sbostic if (fp->_r <= 0 && __srefill(fp)) { 35246077Sbostic if (p == p0) 35346077Sbostic goto input_failure; 35446077Sbostic break; 35546077Sbostic } 35646077Sbostic } 35746077Sbostic n = p - p0; 35846077Sbostic if (n == 0) 35946077Sbostic goto match_failure; 36046077Sbostic *p = 0; 36146077Sbostic nassigned++; 36246077Sbostic } 36346077Sbostic nread += n; 36446077Sbostic break; 36546077Sbostic 36646077Sbostic case CT_STRING: 36746077Sbostic /* like CCL, but zero-length string OK, & no NOSKIP */ 36846077Sbostic if (width == 0) 36946077Sbostic width = ~0; 37046077Sbostic if (flags & SUPPRESS) { 37146077Sbostic n = 0; 37246077Sbostic while (!isspace(*fp->_p)) { 37346077Sbostic n++, fp->_r--, fp->_p++; 37446077Sbostic if (--width == 0) 37546077Sbostic break; 37646077Sbostic if (fp->_r <= 0 && __srefill(fp)) 37746077Sbostic break; 37846077Sbostic } 37946077Sbostic nread += n; 38046077Sbostic } else { 38146077Sbostic p0 = p = va_arg(ap, char *); 38246077Sbostic while (!isspace(*fp->_p)) { 38346077Sbostic fp->_r--; 38446077Sbostic *p++ = *fp->_p++; 38546077Sbostic if (--width == 0) 38646077Sbostic break; 38746077Sbostic if (fp->_r <= 0 && __srefill(fp)) 38846077Sbostic break; 38946077Sbostic } 39046077Sbostic *p = 0; 39146077Sbostic nread += p - p0; 39246077Sbostic nassigned++; 39346077Sbostic } 3949415Smckusick continue; 39546077Sbostic 39646077Sbostic case CT_INT: 39746077Sbostic /* scan an integer as if by strtol/strtoul */ 39846077Sbostic #ifdef hardway 39946077Sbostic if (width == 0 || width > sizeof(buf) - 1) 40046077Sbostic width = sizeof(buf) - 1; 40146077Sbostic #else 40246077Sbostic /* size_t is unsigned, hence this optimisation */ 40346077Sbostic if (--width > sizeof(buf) - 2) 40446077Sbostic width = sizeof(buf) - 2; 40546077Sbostic width++; 40646077Sbostic #endif 40746077Sbostic flags |= SIGNOK | NDIGITS | NZDIGITS; 40846077Sbostic for (p = buf; width; width--) { 40946077Sbostic c = *fp->_p; 41046077Sbostic /* 41146077Sbostic * Switch on the character; `goto ok' 41246077Sbostic * if we accept it as a part of number. 41346077Sbostic */ 41446077Sbostic switch (c) { 41546077Sbostic 41646077Sbostic /* 41746077Sbostic * The digit 0 is always legal, but is 41846077Sbostic * special. For %i conversions, if no 41946077Sbostic * digits (zero or nonzero) have been 42046077Sbostic * scanned (only signs), we will have 42146077Sbostic * base==0. In that case, we should set 42246077Sbostic * it to 8 and enable 0x prefixing. 42346077Sbostic * Also, if we have not scanned zero digits 42446077Sbostic * before this, do not turn off prefixing 42546077Sbostic * (someone else will turn it off if we 42646077Sbostic * have scanned any nonzero digits). 42746077Sbostic */ 42846077Sbostic case '0': 42946077Sbostic if (base == 0) { 43046077Sbostic base = 8; 43146077Sbostic flags |= PFXOK; 43246077Sbostic } 43346077Sbostic if (flags & NZDIGITS) 43446077Sbostic flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 43546077Sbostic else 43646077Sbostic flags &= ~(SIGNOK|PFXOK|NDIGITS); 43746077Sbostic goto ok; 43846077Sbostic 43946077Sbostic /* 1 through 7 always legal */ 44046077Sbostic case '1': case '2': case '3': 44146077Sbostic case '4': case '5': case '6': case '7': 44246077Sbostic base = basefix[base]; 44346077Sbostic flags &= ~(SIGNOK | PFXOK | NDIGITS); 44446077Sbostic goto ok; 44546077Sbostic 44646077Sbostic /* digits 8 and 9 ok iff decimal or hex */ 44746077Sbostic case '8': case '9': 44846077Sbostic base = basefix[base]; 44946077Sbostic if (base <= 8) 45046077Sbostic break; /* not legal here */ 45146077Sbostic flags &= ~(SIGNOK | PFXOK | NDIGITS); 45246077Sbostic goto ok; 45346077Sbostic 45446077Sbostic /* letters ok iff hex */ 45546077Sbostic case 'A': case 'B': case 'C': 45646077Sbostic case 'D': case 'E': case 'F': 45746077Sbostic case 'a': case 'b': case 'c': 45846077Sbostic case 'd': case 'e': case 'f': 45946077Sbostic /* no need to fix base here */ 46046077Sbostic if (base <= 10) 46146077Sbostic break; /* not legal here */ 46246077Sbostic flags &= ~(SIGNOK | PFXOK | NDIGITS); 46346077Sbostic goto ok; 46446077Sbostic 46546077Sbostic /* sign ok only as first character */ 46646077Sbostic case '+': case '-': 46746077Sbostic if (flags & SIGNOK) { 46846077Sbostic flags &= ~SIGNOK; 46946077Sbostic goto ok; 47046077Sbostic } 47146077Sbostic break; 47246077Sbostic 47346077Sbostic /* x ok iff flag still set & 2nd char */ 47446077Sbostic case 'x': case 'X': 47546077Sbostic if (flags & PFXOK && p == buf + 1) { 47646077Sbostic base = 16; /* if %i */ 47746077Sbostic flags &= ~PFXOK; 47846077Sbostic goto ok; 47946077Sbostic } 48046077Sbostic break; 48146077Sbostic } 48246077Sbostic 48346077Sbostic /* 48446077Sbostic * If we got here, c is not a legal character 48546077Sbostic * for a number. Stop accumulating digits. 48646077Sbostic */ 4879415Smckusick break; 48846077Sbostic ok: 48946077Sbostic /* 49046077Sbostic * c is legal: store it and look at the next. 49146077Sbostic */ 49246077Sbostic *p++ = c; 49346077Sbostic if (--fp->_r > 0) 49446077Sbostic fp->_p++; 49546077Sbostic else if (__srefill(fp)) 49646077Sbostic break; /* EOF */ 49746077Sbostic } 49846077Sbostic /* 49946077Sbostic * If we had only a sign, it is no good; push 50046077Sbostic * back the sign. If the number ends in `x', 50146077Sbostic * it was [sign] '0' 'x', so push back the x 50246077Sbostic * and treat it as [sign] '0'. 50346077Sbostic */ 50446077Sbostic if (flags & NDIGITS) { 50546077Sbostic if (p > buf) 50646077Sbostic (void) ungetc(*(u_char *)--p, fp); 50746077Sbostic goto match_failure; 50846077Sbostic } 50946077Sbostic c = ((u_char *)p)[-1]; 51046077Sbostic if (c == 'x' || c == 'X') { 51146077Sbostic --p; 51246077Sbostic (void) ungetc(c, fp); 51346077Sbostic } 51446077Sbostic if ((flags & SUPPRESS) == 0) { 51546077Sbostic u_long res; 51646077Sbostic 51746077Sbostic *p = 0; 51846077Sbostic res = (*ccfn)(buf, (char **)NULL, base); 51946077Sbostic if (flags & POINTER) 52046077Sbostic *va_arg(ap, void **) = (void *)res; 52146077Sbostic else if (flags & SHORT) 52246077Sbostic *va_arg(ap, short *) = res; 52346077Sbostic else if (flags & LONG) 52446077Sbostic *va_arg(ap, long *) = res; 52546077Sbostic else 52646077Sbostic *va_arg(ap, int *) = res; 52746077Sbostic nassigned++; 52846077Sbostic } 52946077Sbostic nread += p - buf; 5309415Smckusick break; 5319415Smckusick 53246077Sbostic #ifdef FLOATING_POINT 53346077Sbostic case CT_FLOAT: 53446077Sbostic /* scan a floating point number as if by strtod */ 53546077Sbostic #ifdef hardway 53646077Sbostic if (width == 0 || width > sizeof(buf) - 1) 53746077Sbostic width = sizeof(buf) - 1; 53846077Sbostic #else 53946077Sbostic /* size_t is unsigned, hence this optimisation */ 54046077Sbostic if (--width > sizeof(buf) - 2) 54146077Sbostic width = sizeof(buf) - 2; 54246077Sbostic width++; 54346077Sbostic #endif 54446077Sbostic flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; 54546077Sbostic for (p = buf; width; width--) { 54646077Sbostic c = *fp->_p; 54746077Sbostic /* 54846077Sbostic * This code mimicks the integer conversion 54946077Sbostic * code, but is much simpler. 55046077Sbostic */ 55146077Sbostic switch (c) { 5529415Smckusick 55346077Sbostic case '0': case '1': case '2': case '3': 55446077Sbostic case '4': case '5': case '6': case '7': 55546077Sbostic case '8': case '9': 55646077Sbostic flags &= ~(SIGNOK | NDIGITS); 55746077Sbostic goto fok; 5589415Smckusick 55946077Sbostic case '+': case '-': 56046077Sbostic if (flags & SIGNOK) { 56146077Sbostic flags &= ~SIGNOK; 56246077Sbostic goto fok; 56346077Sbostic } 56446077Sbostic break; 56546077Sbostic case '.': 56646077Sbostic if (flags & DPTOK) { 56746077Sbostic flags &= ~(SIGNOK | DPTOK); 56846077Sbostic goto fok; 56946077Sbostic } 57046077Sbostic break; 57146077Sbostic case 'e': case 'E': 57246077Sbostic /* no exponent without some digits */ 57346077Sbostic if ((flags&(NDIGITS|EXPOK)) == EXPOK) { 57446077Sbostic flags = 57546077Sbostic (flags & ~(EXPOK|DPTOK)) | 57646077Sbostic SIGNOK | NDIGITS; 57746077Sbostic goto fok; 57846077Sbostic } 57946077Sbostic break; 58046077Sbostic } 58146077Sbostic break; 58246077Sbostic fok: 58346077Sbostic *p++ = c; 58446077Sbostic if (--fp->_r > 0) 58546077Sbostic fp->_p++; 58646077Sbostic else if (__srefill(fp)) 58746077Sbostic break; /* EOF */ 58846077Sbostic } 58946077Sbostic /* 59046077Sbostic * If no digits, might be missing exponent digits 59146077Sbostic * (just give back the exponent) or might be missing 59246077Sbostic * regular digits, but had sign and/or decimal point. 59346077Sbostic */ 59446077Sbostic if (flags & NDIGITS) { 59546077Sbostic if (flags & EXPOK) { 59646077Sbostic /* no digits at all */ 59746077Sbostic while (p > buf) 59846077Sbostic ungetc(*(u_char *)--p, fp); 59946077Sbostic goto match_failure; 60046077Sbostic } 60146077Sbostic /* just a bad exponent (e and maybe sign) */ 60246077Sbostic c = *(u_char *)--p; 60346077Sbostic if (c != 'e' && c != 'E') { 60446077Sbostic (void) ungetc(c, fp);/* sign */ 60546077Sbostic c = *(u_char *)--p; 60646077Sbostic } 60746077Sbostic (void) ungetc(c, fp); 60846077Sbostic } 60946077Sbostic if ((flags & SUPPRESS) == 0) { 61046077Sbostic double res; 6119415Smckusick 61246077Sbostic *p = 0; 61346077Sbostic res = atof(buf); 61446077Sbostic if (flags & LONG) 61546077Sbostic *va_arg(ap, double *) = res; 61646077Sbostic else 61746077Sbostic *va_arg(ap, float *) = res; 61846077Sbostic nassigned++; 61946077Sbostic } 62046077Sbostic nread += p - buf; 62146077Sbostic break; 62246077Sbostic #endif /* FLOATING_POINT */ 62346077Sbostic } 6249415Smckusick } 62546077Sbostic input_failure: 62646077Sbostic return (nassigned ? nassigned : -1); 62746077Sbostic match_failure: 62846077Sbostic return (nassigned); 6299415Smckusick } 6309415Smckusick 63146077Sbostic /* 63246077Sbostic * Fill in the given table from the scanset at the given format 63346077Sbostic * (just after `['). Return a pointer to the character past the 63446077Sbostic * closing `]'. The table has a 1 wherever characters should be 63546077Sbostic * considered part of the scanset. 63646077Sbostic */ 63746077Sbostic static u_char * 63846077Sbostic __sccl(tab, fmt) 63946077Sbostic register char *tab; 64046077Sbostic register u_char *fmt; 6419415Smckusick { 64246077Sbostic register int c, n, v; 6439415Smckusick 64446077Sbostic /* first `clear' the whole table */ 64546077Sbostic c = *fmt++; /* first char hat => negated scanset */ 64646077Sbostic if (c == '^') { 64746077Sbostic v = 1; /* default => accept */ 64846077Sbostic c = *fmt++; /* get new first char */ 6499415Smckusick } else 65046077Sbostic v = 0; /* default => reject */ 65146077Sbostic /* should probably use memset here */ 65246077Sbostic for (n = 0; n < 256; n++) 65346077Sbostic tab[n] = v; 65446077Sbostic if (c == 0) 65546077Sbostic return (fmt - 1);/* format ended before closing ] */ 6569415Smckusick 65746077Sbostic /* 65846077Sbostic * Now set the entries corresponding to the actual scanset 65946077Sbostic * to the opposite of the above. 66046077Sbostic * 66146077Sbostic * The first character may be ']' (or '-') without being special; 66246077Sbostic * the last character may be '-'. 66346077Sbostic */ 66446077Sbostic v = 1 - v; 66546077Sbostic for (;;) { 66646077Sbostic tab[c] = v; /* take character c */ 66746077Sbostic doswitch: 66846077Sbostic n = *fmt++; /* and examine the next */ 66946077Sbostic switch (n) { 6709415Smckusick 67146077Sbostic case 0: /* format ended too soon */ 67246077Sbostic return (fmt - 1); 67346077Sbostic 67446077Sbostic case '-': 67546077Sbostic /* 67646077Sbostic * A scanset of the form 67746077Sbostic * [01+-] 67846077Sbostic * is defined as `the digit 0, the digit 1, 67946077Sbostic * the character +, the character -', but 68046077Sbostic * the effect of a scanset such as 68146077Sbostic * [a-zA-Z0-9] 68246077Sbostic * is implementation defined. The V7 Unix 68346077Sbostic * scanf treats `a-z' as `the letters a through 68446077Sbostic * z', but treats `a-a' as `the letter a, the 68546077Sbostic * character -, and the letter a'. 68646077Sbostic * 68746077Sbostic * For compatibility, the `-' is not considerd 68846077Sbostic * to define a range if the character following 68946077Sbostic * it is either a close bracket (required by ANSI) 69046077Sbostic * or is not numerically greater than the character 69146077Sbostic * we just stored in the table (c). 69246077Sbostic */ 69346077Sbostic n = *fmt; 69446077Sbostic if (n == ']' || n < c) { 69546077Sbostic c = '-'; 69646077Sbostic break; /* resume the for(;;) */ 69746077Sbostic } 69846077Sbostic fmt++; 69946077Sbostic do { /* fill in the range */ 70046077Sbostic tab[++c] = v; 70146077Sbostic } while (c < n); 70246077Sbostic #if 1 /* XXX another disgusting compatibility hack */ 70346077Sbostic /* 70446077Sbostic * Alas, the V7 Unix scanf also treats formats 70546077Sbostic * such as [a-c-e] as `the letters a through e'. 70646077Sbostic * This too is permitted by the standard.... 70746077Sbostic */ 70846077Sbostic goto doswitch; 70946077Sbostic #else 71046077Sbostic c = *fmt++; 71146077Sbostic if (c == 0) 71246077Sbostic return (fmt - 1); 71346077Sbostic if (c == ']') 71446077Sbostic return (fmt); 71546077Sbostic #endif 71646077Sbostic break; 71746077Sbostic 71846077Sbostic case ']': /* end of scanset */ 71946077Sbostic return (fmt); 72046077Sbostic 72146077Sbostic default: /* just another character */ 72246077Sbostic c = n; 72346077Sbostic break; 72446077Sbostic } 7259415Smckusick } 72646077Sbostic /* NOTREACHED */ 7279415Smckusick } 728