diff options
Diffstat (limited to 'lib/libc/stdio/vfscanf.c')
-rw-r--r-- | lib/libc/stdio/vfscanf.c | 92 |
1 files changed, 66 insertions, 26 deletions
diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c index 22ed5a0..0df3720 100644 --- a/lib/libc/stdio/vfscanf.c +++ b/lib/libc/stdio/vfscanf.c @@ -35,7 +35,11 @@ */ #if defined(LIBC_SCCS) && !defined(lint) +#if 0 static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93"; +#endif +static const char rcsid[] = + "$Id: vfscanf.c,v 1.10 1997/04/04 19:07:02 ache Exp $"; #endif /* LIBC_SCCS and not lint */ #include <stdio.h> @@ -46,6 +50,9 @@ static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93"; #else #include <varargs.h> #endif +#include <string.h> + +#include "collate.h" #include "local.h" #define FLOATING_POINT @@ -62,6 +69,7 @@ static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93"; #define SUPPRESS 0x08 /* suppress assignment */ #define POINTER 0x10 /* weird %p pointer (`fake hex') */ #define NOSKIP 0x20 /* do not skip blanks */ +#define QUAD 0x400 /* * The following are used in numeric conversions only: @@ -83,17 +91,18 @@ static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93"; #define CT_CHAR 0 /* %c conversion */ #define CT_CCL 1 /* %[...] conversion */ #define CT_STRING 2 /* %s conversion */ -#define CT_INT 3 /* integer, i.e., strtol or strtoul */ +#define CT_INT 3 /* integer, i.e., strtoq or strtouq */ #define CT_FLOAT 4 /* floating, i.e., strtod */ #define u_char unsigned char #define u_long unsigned long -static u_char *__sccl(); +static u_char *__sccl(char *, u_char *); /* * vfscanf */ +int __svfscanf(fp, fmt0, ap) register FILE *fp; char const *fmt0; @@ -107,9 +116,10 @@ __svfscanf(fp, fmt0, ap) register int flags; /* flags as defined above */ register char *p0; /* saves original value of p when necessary */ int nassigned; /* number of fields assigned */ + int nconversions; /* number of conversions */ int nread; /* number of characters consumed from fp */ - int base; /* base argument to strtol/strtoul */ - u_long (*ccfn)(); /* conversion function (strtol/strtoul) */ + int base; /* base argument to strtoq/strtouq */ + u_quad_t(*ccfn)(); /* conversion function (strtoq/strtouq) */ char ccltab[256]; /* character class table for %[...] */ char buf[BUF]; /* buffer for numeric conversions */ @@ -118,6 +128,7 @@ __svfscanf(fp, fmt0, ap) { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; nassigned = 0; + nconversions = 0; nread = 0; base = 0; /* XXX just to keep gcc happy */ ccfn = NULL; /* XXX just to keep gcc happy */ @@ -128,7 +139,7 @@ __svfscanf(fp, fmt0, ap) if (isspace(c)) { for (;;) { if (fp->_r <= 0 && __srefill(fp)) - return (nassigned); + goto input_failure; if (!isspace(*fp->_p)) break; nread++, fp->_r--, fp->_p++; @@ -161,6 +172,9 @@ literal: case 'l': flags |= LONG; goto again; + case 'q': + flags |= QUAD; + goto again; case 'L': flags |= LONGDBL; goto again; @@ -185,13 +199,13 @@ literal: /* FALLTHROUGH */ case 'd': c = CT_INT; - ccfn = (u_long (*)())strtol; + ccfn = (u_quad_t (*)())strtoq; base = 10; break; case 'i': c = CT_INT; - ccfn = (u_long (*)())strtol; + ccfn = (u_quad_t (*)())strtoq; base = 0; break; @@ -200,13 +214,13 @@ literal: /* FALLTHROUGH */ case 'o': c = CT_INT; - ccfn = strtoul; + ccfn = strtouq; base = 8; break; case 'u': c = CT_INT; - ccfn = strtoul; + ccfn = strtouq; base = 10; break; @@ -216,7 +230,7 @@ literal: case 'x': flags |= PFXOK; /* enable 0x prefixing */ c = CT_INT; - ccfn = strtoul; + ccfn = strtouq; base = 16; break; @@ -248,17 +262,20 @@ literal: case 'p': /* pointer format is like hex */ flags |= POINTER | PFXOK; c = CT_INT; - ccfn = strtoul; + ccfn = strtouq; base = 16; break; case 'n': + nconversions++; if (flags & SUPPRESS) /* ??? */ continue; if (flags & SHORT) *va_arg(ap, short *) = nread; else if (flags & LONG) *va_arg(ap, long *) = nread; + else if (flags & QUAD) + *va_arg(ap, quad_t *) = nread; else *va_arg(ap, int *) = nread; continue; @@ -273,7 +290,7 @@ literal: if (isupper(c)) flags |= LONG; c = CT_INT; - ccfn = (u_long (*)())strtol; + ccfn = (u_quad_t (*)())strtoq; base = 10; break; } @@ -341,12 +358,13 @@ literal: nread += r; nassigned++; } + nconversions++; break; case CT_CCL: /* scan a (nonempty) character class (sets NOSKIP) */ if (width == 0) - width = ~0; /* `infinity' */ + width = (size_t)~0; /* `infinity' */ /* take only those things in the class */ if (flags & SUPPRESS) { n = 0; @@ -382,12 +400,13 @@ literal: nassigned++; } nread += n; + nconversions++; break; case CT_STRING: /* like CCL, but zero-length string OK, & no NOSKIP */ if (width == 0) - width = ~0; + width = (size_t)~0; if (flags & SUPPRESS) { n = 0; while (!isspace(*fp->_p)) { @@ -412,10 +431,11 @@ literal: nread += p - p0; nassigned++; } + nconversions++; continue; case CT_INT: - /* scan an integer as if by strtol/strtoul */ + /* scan an integer as if by strtoq/strtouq */ #ifdef hardway if (width == 0 || width > sizeof(buf) - 1) width = sizeof(buf) - 1; @@ -533,21 +553,25 @@ literal: (void) ungetc(c, fp); } if ((flags & SUPPRESS) == 0) { - u_long res; + u_quad_t res; *p = 0; res = (*ccfn)(buf, (char **)NULL, base); if (flags & POINTER) - *va_arg(ap, void **) = (void *)res; + *va_arg(ap, void **) = + (void *)(u_long)res; else if (flags & SHORT) *va_arg(ap, short *) = res; else if (flags & LONG) *va_arg(ap, long *) = res; + else if (flags & QUAD) + *va_arg(ap, quad_t *) = res; else *va_arg(ap, int *) = res; nassigned++; } nread += p - buf; + nconversions++; break; #ifdef FLOATING_POINT @@ -639,12 +663,13 @@ literal: nassigned++; } nread += p - buf; + nconversions++; break; #endif /* FLOATING_POINT */ } } input_failure: - return (nassigned ? nassigned : -1); + return (nconversions != 0 ? nassigned : EOF); match_failure: return (nassigned); } @@ -660,7 +685,7 @@ __sccl(tab, fmt) register char *tab; register u_char *fmt; { - register int c, n, v; + register int c, n, v, i; /* first `clear' the whole table */ c = *fmt++; /* first char hat => negated scanset */ @@ -669,9 +694,10 @@ __sccl(tab, fmt) c = *fmt++; /* get new first char */ } else v = 0; /* default => reject */ - /* should probably use memset here */ - for (n = 0; n < 256; n++) - tab[n] = v; + + /* XXX: Will not work if sizeof(tab*) > sizeof(char) */ + (void) memset(tab, v, 256); + if (c == 0) return (fmt - 1);/* format ended before closing ] */ @@ -712,15 +738,29 @@ doswitch: * we just stored in the table (c). */ n = *fmt; - if (n == ']' || n < c) { + if (n == ']' + || (__collate_load_error ? n < c : + __collate_range_cmp (n, c) < 0 + ) + ) { c = '-'; break; /* resume the for(;;) */ } fmt++; - do { /* fill in the range */ - tab[++c] = v; - } while (c < n); + /* fill in the range */ + if (__collate_load_error) { + do { + tab[++c] = v; + } while (c < n); + } else { + for (i = 0; i < 256; i ++) + if ( __collate_range_cmp (c, i) < 0 + && __collate_range_cmp (i, n) <= 0 + ) + tab[i] = v; + } #if 1 /* XXX another disgusting compatibility hack */ + c = n; /* * Alas, the V7 Unix scanf also treats formats * such as [a-c-e] as `the letters a through e'. |