summaryrefslogtreecommitdiffstats
path: root/lib/libc/stdio/vfscanf.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libc/stdio/vfscanf.c')
-rw-r--r--lib/libc/stdio/vfscanf.c92
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'.
OpenPOWER on IntegriCloud