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