|
@@ -1,3 +1,25 @@
|
|
|
+
|
|
|
+
|
|
|
+ * Modified by Manuel Novoa III Mar 13, 2001
|
|
|
+ *
|
|
|
+ * The vfscanf routine was completely rewritten to add features and remove
|
|
|
+ * bugs. The function __strtold, based on my strtod code in stdlib, was
|
|
|
+ * added to provide floating point support for the scanf functions.
|
|
|
+ *
|
|
|
+ * So far they pass the test cases from glibc-2.1.3, except in two instances.
|
|
|
+ * In one case, the test appears to be broken. The other case is something
|
|
|
+ * I need to research further. This version of scanf assumes it can only
|
|
|
+ * peek one character ahead. Apparently, glibc looks further. The difference
|
|
|
+ * can be seen when parsing a floating point value in the character
|
|
|
+ * sequence "100ergs". glibc is able to back up before the 'e' and return
|
|
|
+ * a value of 100, whereas this scanf reports a bad match with the stream
|
|
|
+ * pointer at 'r'. A similar situation can also happen when parsing hex
|
|
|
+ * values prefixed by 0x or 0X; a failure would occur for "0xg". In order to
|
|
|
+ * fix this, I need to rework the "ungetc" machinery in stdio.c again.
|
|
|
+ * I do have one reference though, that seems to imply scanf has a single
|
|
|
+ * character of lookahead.
|
|
|
+ */
|
|
|
+
|
|
|
#include <stdlib.h>
|
|
|
#include <unistd.h>
|
|
|
#include <stdio.h>
|
|
@@ -94,431 +116,576 @@ int vsscanf(__const char *sp, __const char *fmt, va_list ap)
|
|
|
|
|
|
#ifdef L_vfscanf
|
|
|
|
|
|
-#if FLOATS
|
|
|
-int _vfscanf_fp_ref = 1;
|
|
|
-#else
|
|
|
-int _vfscanf_fp_ref = 0;
|
|
|
-#endif
|
|
|
-
|
|
|
-
|
|
|
+#include <assert.h>
|
|
|
+#include <ctype.h>
|
|
|
+#include <limits.h>
|
|
|
|
|
|
-#define skip() while(isspace(c)) { if ((c=getc(fp))<1) goto done; }
|
|
|
-
|
|
|
-#if FLOATS
|
|
|
-
|
|
|
-#define F_NADA 0
|
|
|
-#define F_SIGN 1
|
|
|
-#define F_ESIGN 2
|
|
|
-#define F_INT 3
|
|
|
-#define F_FRAC 4
|
|
|
-#define F_EXP 5
|
|
|
-#define F_QUIT 6
|
|
|
-
|
|
|
-#define NSTATE 8
|
|
|
-#define FS_INIT 0
|
|
|
-#define FS_SIGNED 1
|
|
|
-#define FS_DIGS 2
|
|
|
-#define FS_DOT 3
|
|
|
-#define FS_DD 4
|
|
|
-#define FS_E 5
|
|
|
-#define FS_ESIGN 6
|
|
|
-#define FS_EDIGS 7
|
|
|
-
|
|
|
-#define FC_DIG 0
|
|
|
-#define FC_DOT 1
|
|
|
-#define FC_E 2
|
|
|
-#define FC_SIGN 3
|
|
|
-
|
|
|
-
|
|
|
-int fp_do[][NSTATE] = {
|
|
|
- {F_INT, F_INT, F_INT,
|
|
|
- F_FRAC, F_FRAC,
|
|
|
- F_EXP, F_EXP, F_EXP},
|
|
|
- {F_NADA, F_NADA, F_NADA,
|
|
|
- F_QUIT, F_QUIT, F_QUIT, F_QUIT, F_QUIT},
|
|
|
- {F_QUIT, F_QUIT,
|
|
|
- F_NADA, F_QUIT, F_NADA,
|
|
|
- F_QUIT, F_QUIT, F_QUIT},
|
|
|
- {F_SIGN, F_QUIT, F_QUIT, F_QUIT, F_QUIT,
|
|
|
- F_ESIGN, F_QUIT, F_QUIT},
|
|
|
-};
|
|
|
+static int valid_digit(char c, char base)
|
|
|
+{
|
|
|
+ if (base == 16) {
|
|
|
+ return isxdigit(c);
|
|
|
+ } else {
|
|
|
+ return (isdigit(c) && (c < '0' + base));
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-
|
|
|
-int fp_ns[][NSTATE] = {
|
|
|
- {FS_DIGS, FS_DIGS, FS_DIGS,
|
|
|
- FS_DD, FS_DD,
|
|
|
- FS_EDIGS, FS_EDIGS, FS_EDIGS},
|
|
|
- {FS_DOT, FS_DOT, FS_DD,
|
|
|
- },
|
|
|
- {0, 0,
|
|
|
- FS_E, 0, FS_E,
|
|
|
- },
|
|
|
- {FS_SIGNED, 0, 0, 0, 0,
|
|
|
- FS_ESIGN, 0, 0},
|
|
|
-};
|
|
|
+extern unsigned long long
|
|
|
+_strto_ll(const char *str, char **endptr, int base, int uflag);
|
|
|
|
|
|
-
|
|
|
-int fp_sval[NSTATE] = {
|
|
|
- 0, 0, 1, 0, 1, 0, 0, 1
|
|
|
-};
|
|
|
-#endif
|
|
|
+extern unsigned long
|
|
|
+_strto_l(const char *str, char **endptr, int base, int uflag);
|
|
|
|
|
|
-int vfscanf(fp, fmt, ap)
|
|
|
-register FILE *fp;
|
|
|
-register const char *fmt;
|
|
|
-va_list ap;
|
|
|
+
|
|
|
|
|
|
-{
|
|
|
-#if WANT_LONG_LONG
|
|
|
- long long n;
|
|
|
+#if WANT_LONG_LONG || WANT_LONG_LONG_ERROR
|
|
|
+static const char qual[] = "hl" "Lq";
|
|
|
+
|
|
|
+static const char qsz[] = { -1, 1, 2, 2 };
|
|
|
#else
|
|
|
- register long n;
|
|
|
-#endif
|
|
|
- register int c, width, lval, cnt = 0;
|
|
|
- int store, neg, base, wide1, endnull, rngflag, c2;
|
|
|
- register unsigned char *p;
|
|
|
- unsigned char delim[128], digits[17], *q;
|
|
|
-
|
|
|
-#if FLOATS
|
|
|
- long frac, expo;
|
|
|
- int eneg, fraclen, fstate, trans;
|
|
|
- double fx, fp_scan();
|
|
|
+static const char qual[] = "hl" ;
|
|
|
+static const char qsz[] = { -1, 1, };
|
|
|
#endif
|
|
|
|
|
|
- if (!*fmt)
|
|
|
- return (0);
|
|
|
-
|
|
|
- c = getc(fp);
|
|
|
- while (c > 0) {
|
|
|
- store = 0;
|
|
|
- if (*fmt == '%') {
|
|
|
- n = 0;
|
|
|
- width = -1;
|
|
|
- wide1 = 1;
|
|
|
- base = 10;
|
|
|
- lval = (sizeof(long) == sizeof(int));
|
|
|
-
|
|
|
- store = 1;
|
|
|
- endnull = 1;
|
|
|
- neg = -1;
|
|
|
-
|
|
|
- strcpy(delim, "\011\012\013\014\015 ");
|
|
|
- strcpy(digits, "0123456789ABCDEF");
|
|
|
-
|
|
|
- if (*++fmt == '*') {
|
|
|
- endnull = store = 0;
|
|
|
- ++fmt;
|
|
|
- }
|
|
|
-
|
|
|
- while (isdigit(*fmt)) {
|
|
|
- if (width == -1)
|
|
|
- width = 0;
|
|
|
- wide1 = width = (width * 10) + (*fmt - '0');
|
|
|
- ++fmt;
|
|
|
- }
|
|
|
- --fmt;
|
|
|
- fmtnxt:
|
|
|
- ++fmt;
|
|
|
- switch (tolower(*fmt)) {
|
|
|
- case '*':
|
|
|
- endnull = store = 0;
|
|
|
- goto fmtnxt;
|
|
|
- case 'l':
|
|
|
- lval = 1;
|
|
|
-#if WANT_LONG_LONG
|
|
|
- if (*fmt == 'L') {
|
|
|
- lval = 2;
|
|
|
- }
|
|
|
+#if WANT_DOUBLE || WANT_DOUBLE_ERROR
|
|
|
+
|
|
|
+static const char spec[] = "%n[csoupxXidfeEgG";
|
|
|
+#else
|
|
|
+static const char spec[] = "%n[csoupxXid";
|
|
|
#endif
|
|
|
- goto fmtnxt;
|
|
|
- case 'h':
|
|
|
- lval = 0;
|
|
|
- goto fmtnxt;
|
|
|
+
|
|
|
+static const char radix[] = { 8, 10, 16, 16, 16, 0, 10 };
|
|
|
+
|
|
|
+struct scan_cookie {
|
|
|
+ FILE *fp;
|
|
|
+ int nread;
|
|
|
+ int width;
|
|
|
+ int ungot_char;
|
|
|
+ int ungot_flag;
|
|
|
+};
|
|
|
|
|
|
- case 'i':
|
|
|
- base = 0;
|
|
|
- goto numfmt;
|
|
|
+static int __strtold(long double *ld, struct scan_cookie *sc);
|
|
|
|
|
|
- case 'b':
|
|
|
- base = 2;
|
|
|
- goto numfmt;
|
|
|
+static void init_scan_cookie(struct scan_cookie *sc, FILE *fp)
|
|
|
+{
|
|
|
+ sc->fp = fp;
|
|
|
+ sc->nread = 0;
|
|
|
+ sc->ungot_flag = 0;
|
|
|
+ if ((sc->ungot_char = getc(fp)) > 0) {
|
|
|
+ sc->ungot_flag = 1;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- case 'o':
|
|
|
- base = 8;
|
|
|
- goto numfmt;
|
|
|
+static int scan_getc_nw(struct scan_cookie *sc)
|
|
|
+{
|
|
|
+ if (sc->ungot_flag == 0) {
|
|
|
+ sc->ungot_char = getc(sc->fp);
|
|
|
+ } else {
|
|
|
+ sc->ungot_flag = 0;
|
|
|
+ }
|
|
|
+ if (sc->ungot_char > 0) {
|
|
|
+ ++sc->nread;
|
|
|
+ }
|
|
|
+ return sc->ungot_char;
|
|
|
+}
|
|
|
|
|
|
- case 'x':
|
|
|
- base = 16;
|
|
|
- goto numfmt;
|
|
|
+static int scan_getc(struct scan_cookie *sc)
|
|
|
+{
|
|
|
+ if (sc->ungot_flag == 0) {
|
|
|
+ sc->ungot_char = getc(sc->fp);
|
|
|
+ }
|
|
|
+ if (--sc->width < 0) {
|
|
|
+ sc->ungot_flag = 1;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ sc->ungot_flag = 0;
|
|
|
+ if (sc->ungot_char > 0) {
|
|
|
+ ++sc->nread;
|
|
|
+ }
|
|
|
+ return sc->ungot_char;
|
|
|
+}
|
|
|
|
|
|
- case 'd':
|
|
|
- neg = 0;
|
|
|
-
|
|
|
+static void scan_ungetc(struct scan_cookie *sc)
|
|
|
+{
|
|
|
+ if (sc->ungot_flag != 0) {
|
|
|
+ assert(sc->width < 0);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ sc->ungot_flag = 1;
|
|
|
+ if (sc->ungot_char > 0) {
|
|
|
+ --sc->nread;
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
- case 'u':
|
|
|
- numfmt:skip();
|
|
|
+static void kill_scan_cookie(struct scan_cookie *sc)
|
|
|
+{
|
|
|
+ if (sc->ungot_flag) {
|
|
|
+ ungetc(sc->ungot_char,sc->fp);
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
-#if 0
|
|
|
- if (isupper(*fmt))
|
|
|
- lval = 1;
|
|
|
+int vfscanf(fp, format, ap)
|
|
|
+FILE *fp;
|
|
|
+const char *format;
|
|
|
+va_list ap;
|
|
|
+{
|
|
|
+#if WANT_LONG_LONG
|
|
|
+#define STRTO_L_(s,e,b,u) _strto_ll(s,e,b,u)
|
|
|
+#define MAX_DIGITS 64
|
|
|
+#define UV_TYPE unsigned long long
|
|
|
+#define V_TYPE long long
|
|
|
+#else
|
|
|
+#define STRTO_L_(s,e,b,u) _strto_l(s,e,b,u)
|
|
|
+#define MAX_DIGITS 32
|
|
|
+#define UV_TYPE unsigned long
|
|
|
+#define V_TYPE long
|
|
|
#endif
|
|
|
-
|
|
|
- if (!base) {
|
|
|
- base = 10;
|
|
|
- neg = 0;
|
|
|
- if (c == '%') {
|
|
|
- base = 2;
|
|
|
- goto skip1;
|
|
|
- } else if (c == '0') {
|
|
|
- c = getc(fp);
|
|
|
- if (c < 1)
|
|
|
- goto savnum;
|
|
|
- if ((c != 'x')
|
|
|
- && (c != 'X')) {
|
|
|
- base = 8;
|
|
|
- digits[8] = '\0';
|
|
|
- goto zeroin;
|
|
|
- }
|
|
|
- base = 16;
|
|
|
- goto skip1;
|
|
|
+#if WANT_DOUBLE
|
|
|
+ long double ld;
|
|
|
+#endif
|
|
|
+ UV_TYPE uv;
|
|
|
+ struct scan_cookie sc;
|
|
|
+ unsigned const char *fmt;
|
|
|
+ const char *p;
|
|
|
+ unsigned char *b;
|
|
|
+ void *vp;
|
|
|
+ int cc, i, cnt;
|
|
|
+ signed char lval;
|
|
|
+ unsigned char store, usflag, base, invert, r0, r1;
|
|
|
+ unsigned char buf[MAX_DIGITS+2];
|
|
|
+ unsigned char scanset[UCHAR_MAX + 1];
|
|
|
+
|
|
|
+ init_scan_cookie(&sc,fp);
|
|
|
+
|
|
|
+ fmt = (unsigned const char *) format;
|
|
|
+ cnt = 0;
|
|
|
+
|
|
|
+ while (*fmt) {
|
|
|
+ store = 1;
|
|
|
+ lval = 0;
|
|
|
+ sc.width = INT_MAX;
|
|
|
+ if (*fmt == '%') {
|
|
|
+ ++fmt;
|
|
|
+ if (*fmt == '*') {
|
|
|
+ store = 0;
|
|
|
+ ++fmt;
|
|
|
+ }
|
|
|
+ for (i = 0 ; isdigit(*fmt) ; sc.width = i) {
|
|
|
+ i = (i * 10) + (*fmt++ - '0');
|
|
|
+ }
|
|
|
+ for (i = 0 ; i < sizeof(qual) ; i++) {
|
|
|
+ if (qual[i] == *fmt) {
|
|
|
+ ++fmt;
|
|
|
+ lval += qsz[i];
|
|
|
+ if ((i < 2) && (qual[i] == *fmt)) {
|
|
|
+ ++fmt;
|
|
|
+ lval += qsz[i];
|
|
|
}
|
|
|
+ break;
|
|
|
}
|
|
|
-
|
|
|
- if ((neg == 0) && (base == 10)
|
|
|
- && ((neg = (c == '-')) || (c == '+'))) {
|
|
|
- skip1:
|
|
|
- c = getc(fp);
|
|
|
- if (c < 1)
|
|
|
- goto done;
|
|
|
+ }
|
|
|
+ for (p = spec ; *p ; p++) {
|
|
|
+ if (*fmt != *p) continue;
|
|
|
+ if (p-spec < 1) {
|
|
|
+ goto matchchar;
|
|
|
}
|
|
|
-
|
|
|
- digits[base] = '\0';
|
|
|
- p = ((unsigned char *)
|
|
|
- strchr(digits, toupper(c)));
|
|
|
-
|
|
|
- if ((!c || !p) && width)
|
|
|
+ if (p-spec < 2) {
|
|
|
+ *(va_arg(ap, int *)) = sc.nread;
|
|
|
+ scan_getc_nw(&sc);
|
|
|
+ goto nextfmt;
|
|
|
+ }
|
|
|
+ if (p-spec > 3) {
|
|
|
+ while (isspace(scan_getc_nw(&sc)))
|
|
|
+ {}
|
|
|
+ scan_ungetc(&sc);
|
|
|
+ }
|
|
|
+ if (p-spec < 5) {
|
|
|
+ if ((*p == 'c') && (sc.width == INT_MAX)) {
|
|
|
+ sc.width = 1;
|
|
|
+ }
|
|
|
+ invert = 0;
|
|
|
+ for (i=0 ; i<= UCHAR_MAX ; i++) {
|
|
|
+ scanset[i] = ((*p == 's') ? (isspace(i) == 0) : 0);
|
|
|
+ }
|
|
|
+ if (*p == '[') {
|
|
|
+ if (*++fmt == '^') {
|
|
|
+ invert = 1;
|
|
|
+ ++fmt;
|
|
|
+ }
|
|
|
+ if (*fmt == ']') {
|
|
|
+ scanset[(int)']'] = 1;
|
|
|
+ ++fmt;
|
|
|
+ }
|
|
|
+ r0 = 0;
|
|
|
+ while (*fmt && *fmt !=']') {
|
|
|
+ if ((*fmt == '-') && r0 && (fmt[1] != ']')) {
|
|
|
+
|
|
|
+ ++fmt;
|
|
|
+ if (*fmt < r0) {
|
|
|
+ r1 = r0;
|
|
|
+ r0 = *fmt;
|
|
|
+ } else {
|
|
|
+ r1 = *fmt;
|
|
|
+ }
|
|
|
+ for (i=r0 ; i<= r1 ; i++) {
|
|
|
+ scanset[i] = 1;
|
|
|
+ }
|
|
|
+ r0 = 0;
|
|
|
+ } else {
|
|
|
+ r0 = *fmt;
|
|
|
+ scanset[r0] = 1;
|
|
|
+ }
|
|
|
+ ++fmt;
|
|
|
+ }
|
|
|
+ if (!*fmt) {
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sc.width <= 0) {
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ if (store) {
|
|
|
+ b = va_arg(ap, unsigned char *);
|
|
|
+ } else {
|
|
|
+ b = buf;
|
|
|
+ }
|
|
|
+ i = 0;
|
|
|
+ cc = scan_getc(&sc);
|
|
|
+ while ((cc>0) && (scanset[cc] != invert)) {
|
|
|
+ i = store;
|
|
|
+ *b = cc;
|
|
|
+ b += store;
|
|
|
+ cc = scan_getc(&sc);
|
|
|
+ }
|
|
|
+ if (*p != 'c') {
|
|
|
+ *b = 0;
|
|
|
+ cnt += i;
|
|
|
+ goto nextfmt;
|
|
|
+ } else if (sc.width < 0) {
|
|
|
+ cnt += store;
|
|
|
+ goto nextfmt;
|
|
|
+ }
|
|
|
+ scan_ungetc(&sc);
|
|
|
goto done;
|
|
|
-
|
|
|
- while (p && width-- && c) {
|
|
|
- n = (n * base) + (p - digits);
|
|
|
- c = getc(fp);
|
|
|
- zeroin:
|
|
|
- p = ((unsigned char *)
|
|
|
- strchr(digits, toupper(c)));
|
|
|
}
|
|
|
- savnum:
|
|
|
- if (store) {
|
|
|
- if (neg == 1)
|
|
|
- n = -n;
|
|
|
+ if (p-spec < 12) {
|
|
|
+ if (*p == 'p') {
|
|
|
+
|
|
|
+ lval = (sizeof(char *) == sizeof(long));
|
|
|
+ }
|
|
|
+ usflag = ((p-spec) < 10);
|
|
|
+ base = radix[(int)(p-spec) - 5];
|
|
|
+ b = buf;
|
|
|
+ if (sc.width <= 0) {
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ cc = scan_getc(&sc);
|
|
|
+ if ((cc == '+') || (cc == '-')) {
|
|
|
+ *b++ = cc;
|
|
|
+ cc = scan_getc(&sc);
|
|
|
+ }
|
|
|
+ if (cc == '0') {
|
|
|
+ if ((base == 0) || (base == 16)) {
|
|
|
+ cc = scan_getc(&sc);
|
|
|
+ if ((cc == 'x') || (cc == 'X')) {
|
|
|
+
|
|
|
+ base = 16;
|
|
|
+ cc = scan_getc(&sc);
|
|
|
+ } else {
|
|
|
+ scan_ungetc(&sc);
|
|
|
+ cc = '0';
|
|
|
+ if (base == 0) {
|
|
|
+ base = 8;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (cc == '0') {
|
|
|
+ *b++ = cc;
|
|
|
+ do {
|
|
|
+ cc = scan_getc(&sc);
|
|
|
+ } while (cc == '0');
|
|
|
+ }
|
|
|
+ while (valid_digit(cc,base)) {
|
|
|
+ if (b - buf < MAX_DIGITS) {
|
|
|
+ *b++ = cc;
|
|
|
+ }
|
|
|
+ cc = scan_getc(&sc);
|
|
|
+ }
|
|
|
+ *b = 0;
|
|
|
+ if ((b == buf) || (*--b == '+') || (*b == '-')) {
|
|
|
+ scan_ungetc(&sc);
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ if (store) {
|
|
|
+ if (*buf == '-') {
|
|
|
+ usflag = 0;
|
|
|
+ }
|
|
|
+ uv = STRTO_L_(buf, NULL, base, usflag);
|
|
|
+ vp = va_arg(ap, void *);
|
|
|
+ switch (lval) {
|
|
|
+ case 2:
|
|
|
#if WANT_LONG_LONG
|
|
|
- if (lval == 2)
|
|
|
- *va_arg(ap, long long *) = n;
|
|
|
-
|
|
|
- else
|
|
|
+ *((unsigned long long *)vp) = uv;
|
|
|
+ break;
|
|
|
#endif
|
|
|
- if (lval == 1)
|
|
|
- *va_arg(ap, long *) = n;
|
|
|
-
|
|
|
- else
|
|
|
- *va_arg(ap, short *) = n;
|
|
|
-
|
|
|
- ++cnt;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
-#if FLOATS
|
|
|
- case 'e':
|
|
|
- case 'f':
|
|
|
- case 'g':
|
|
|
- skip();
|
|
|
- fprintf(stderr, "LIBM:SCANF");
|
|
|
-#if 0
|
|
|
- if (isupper(*fmt))
|
|
|
- lval = 1;
|
|
|
+ case 1:
|
|
|
+#if ULONG_MAX == UINT_MAX
|
|
|
+ case 0:
|
|
|
#endif
|
|
|
-
|
|
|
- fstate = FS_INIT;
|
|
|
- neg = 0;
|
|
|
- eneg = 0;
|
|
|
- n = 0;
|
|
|
- frac = 0;
|
|
|
- expo = 0;
|
|
|
- fraclen = 0;
|
|
|
-
|
|
|
- while (c && width--) {
|
|
|
- if (c >= '0' && c <= '9')
|
|
|
- trans = FC_DIG;
|
|
|
- else if (c == '.')
|
|
|
- trans = FC_DOT;
|
|
|
- else if (c == '+' || c == '-')
|
|
|
- trans = FC_SIGN;
|
|
|
- else if (tolower(c) == 'e')
|
|
|
- trans = FC_E;
|
|
|
- else
|
|
|
- goto fdone;
|
|
|
-
|
|
|
- switch (fp_do[trans][fstate]) {
|
|
|
- case F_SIGN:
|
|
|
- neg = (c == '-');
|
|
|
- break;
|
|
|
- case F_ESIGN:
|
|
|
- eneg = (c == '-');
|
|
|
- break;
|
|
|
- case F_INT:
|
|
|
- n = 10 * n + (c - '0');
|
|
|
- break;
|
|
|
- case F_FRAC:
|
|
|
- frac = 10 * frac + (c - '0');
|
|
|
- fraclen++;
|
|
|
- break;
|
|
|
- case F_EXP:
|
|
|
- expo = 10 * expo + (c - '0');
|
|
|
- break;
|
|
|
- case F_QUIT:
|
|
|
- goto fdone;
|
|
|
+#if WANT_LONG_LONG
|
|
|
+ if (usflag) {
|
|
|
+ if (uv > ULONG_MAX) {
|
|
|
+ uv = ULONG_MAX;
|
|
|
+ }
|
|
|
+ } else if (((V_TYPE)uv) > LONG_MAX) {
|
|
|
+ uv = LONG_MAX;
|
|
|
+ } else if (((V_TYPE)uv) < LONG_MIN) {
|
|
|
+ uv = (UV_TYPE) LONG_MIN;
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ *((unsigned long *)vp) = (unsigned long)uv;
|
|
|
+ break;
|
|
|
+#if ULONG_MAX != UINT_MAX
|
|
|
+ case 0:
|
|
|
+ if (usflag) {
|
|
|
+ if (uv > UINT_MAX) {
|
|
|
+ uv = UINT_MAX;
|
|
|
+ }
|
|
|
+ } else if (((V_TYPE)uv) > INT_MAX) {
|
|
|
+ uv = INT_MAX;
|
|
|
+ } else if (((V_TYPE)uv) < INT_MIN) {
|
|
|
+ uv = (UV_TYPE) INT_MIN;
|
|
|
+ }
|
|
|
+ *((unsigned int *)vp) = (unsigned int)uv;
|
|
|
+ break;
|
|
|
+#endif
|
|
|
+ case -1:
|
|
|
+ if (usflag) {
|
|
|
+ if (uv > USHRT_MAX) {
|
|
|
+ uv = USHRT_MAX;
|
|
|
+ }
|
|
|
+ } else if (((V_TYPE)uv) > SHRT_MAX) {
|
|
|
+ uv = SHRT_MAX;
|
|
|
+ } else if (((V_TYPE)uv) < SHRT_MIN) {
|
|
|
+ uv = (UV_TYPE) SHRT_MIN;
|
|
|
+ }
|
|
|
+ *((unsigned short *)vp) = (unsigned short)uv;
|
|
|
+ break;
|
|
|
+ case -2:
|
|
|
+ if (usflag) {
|
|
|
+ if (uv > UCHAR_MAX) {
|
|
|
+ uv = UCHAR_MAX;
|
|
|
+ }
|
|
|
+ } else if (((V_TYPE)uv) > CHAR_MAX) {
|
|
|
+ uv = CHAR_MAX;
|
|
|
+ } else if (((V_TYPE)uv) < CHAR_MIN) {
|
|
|
+ uv = (UV_TYPE) CHAR_MIN;
|
|
|
+ }
|
|
|
+ *((unsigned char *)vp) = (unsigned char) uv;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ assert(0);
|
|
|
+ }
|
|
|
+ ++cnt;
|
|
|
}
|
|
|
- fstate = fp_ns[trans][fstate];
|
|
|
- c = getc(fp);
|
|
|
+ goto nextfmt;
|
|
|
}
|
|
|
-
|
|
|
- fdone:
|
|
|
- if (!fp_sval[fstate])
|
|
|
- goto done;
|
|
|
- if (store) {
|
|
|
- fx = fp_scan(neg, eneg, n, frac, expo, fraclen);
|
|
|
- if (lval)
|
|
|
- *va_arg(ap, double *) = fx;
|
|
|
-
|
|
|
- else
|
|
|
- *va_arg(ap, float *) = fx;
|
|
|
-
|
|
|
- ++cnt;
|
|
|
+#if WANT_DOUBLE
|
|
|
+ else {
|
|
|
+ if (sc.width <= 0) {
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ if (__strtold(&ld, &sc)) {
|
|
|
+ if (store) {
|
|
|
+ vp = va_arg(ap, void *);
|
|
|
+ switch (lval) {
|
|
|
+ case 2:
|
|
|
+ *((long double *)vp) = ld;
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ *((double *)vp) = (double) ld;
|
|
|
+ break;
|
|
|
+ case 0:
|
|
|
+ *((float *)vp) = (float) ld;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ assert(0);
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ ++cnt;
|
|
|
+ }
|
|
|
+ goto nextfmt;
|
|
|
+ }
|
|
|
}
|
|
|
- break;
|
|
|
#else
|
|
|
- case 'e':
|
|
|
- case 'f':
|
|
|
- case 'g':
|
|
|
- fprintf(stderr, "LIBC:SCANF");
|
|
|
- exit(-1);
|
|
|
+ assert(0);
|
|
|
#endif
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ goto done;
|
|
|
+ } if (isspace(*fmt)) {
|
|
|
+ while (isspace(scan_getc_nw(&sc)))
|
|
|
+ {}
|
|
|
+ } else {
|
|
|
+ matchchar:
|
|
|
+ if (scan_getc_nw(&sc) != *fmt) {
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+ scan_getc_nw(&sc);
|
|
|
+ }
|
|
|
+ nextfmt:
|
|
|
+ scan_ungetc(&sc);
|
|
|
+ ++fmt;
|
|
|
+ }
|
|
|
|
|
|
- case 'c':
|
|
|
- width = wide1;
|
|
|
- lval = endnull = 0;
|
|
|
- delim[0] = '\0';
|
|
|
- goto strproc;
|
|
|
-
|
|
|
- case '[':
|
|
|
+ done:
|
|
|
+ kill_scan_cookie(&sc);
|
|
|
|
|
|
-
|
|
|
- p = delim;
|
|
|
+ if ((sc.ungot_char <= 0) && (cnt == 0) && (*fmt)) {
|
|
|
+ return (EOF);
|
|
|
+ }
|
|
|
|
|
|
- if (*++fmt == '^') {
|
|
|
- fmt++;
|
|
|
- lval = 0;
|
|
|
- } else
|
|
|
- lval = 1;
|
|
|
+ return (cnt);
|
|
|
+}
|
|
|
|
|
|
- rngflag = 2;
|
|
|
- if ((*fmt == ']') || (*fmt == '-')) {
|
|
|
- *p++ = *fmt++;
|
|
|
- rngflag = 0;
|
|
|
- }
|
|
|
+
|
|
|
+#if WANT_DOUBLE
|
|
|
|
|
|
- while (*fmt != ']') {
|
|
|
- if (*fmt == '\0')
|
|
|
- goto done;
|
|
|
- switch (rngflag) {
|
|
|
- case 1:
|
|
|
- c2 = *(p - 2);
|
|
|
- if (c2 <= *fmt) {
|
|
|
- p -= 2;
|
|
|
- while (c2 < *fmt)
|
|
|
- *p++ = c2++;
|
|
|
- rngflag = 2;
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
+#include <float.h>
|
|
|
|
|
|
- case 0:
|
|
|
- rngflag = (*fmt == '-');
|
|
|
- break;
|
|
|
+#define MAX_SIG_DIGITS 20
|
|
|
+#define MAX_IGNORED_DIGITS 2000
|
|
|
+#define MAX_ALLOWED_EXP (MAX_SIG_DIGITS + MAX_IGNORED_DIGITS + LDBL_MAX_10_EXP)
|
|
|
|
|
|
- case 2:
|
|
|
- rngflag = 0;
|
|
|
- }
|
|
|
+#if LDBL_DIG > MAX_SIG_DIGITS
|
|
|
+#error need to adjust MAX_SIG_DIGITS
|
|
|
+#endif
|
|
|
|
|
|
- *p++ = *fmt++;
|
|
|
- }
|
|
|
+#include <limits.h>
|
|
|
+#if MAX_ALLOWED_EXP > INT_MAX
|
|
|
+#error size assumption violated for MAX_ALLOWED_EXP
|
|
|
+#endif
|
|
|
|
|
|
- *p = '\0';
|
|
|
- goto strproc;
|
|
|
-
|
|
|
- case 's':
|
|
|
- lval = 0;
|
|
|
- skip();
|
|
|
- strproc:
|
|
|
-
|
|
|
- p = va_arg(ap, unsigned char *);
|
|
|
-
|
|
|
-
|
|
|
- if (width) {
|
|
|
- q = ((unsigned char *)
|
|
|
- strchr(delim, c));
|
|
|
- if ((c < 1) || lval == (q == 0)) {
|
|
|
- if (endnull)
|
|
|
- *p = '\0';
|
|
|
- goto done;
|
|
|
- }
|
|
|
- }
|
|
|
+int __strtold(long double *ld, struct scan_cookie *sc)
|
|
|
+{
|
|
|
+ long double number;
|
|
|
+ long double p10;
|
|
|
+ int exponent_power;
|
|
|
+ int exponent_temp;
|
|
|
+ int negative;
|
|
|
+ int num_digits;
|
|
|
+ int since_decimal;
|
|
|
+ int c;
|
|
|
+
|
|
|
+ c = scan_getc(sc);
|
|
|
+
|
|
|
+ negative = 0;
|
|
|
+ switch(c) {
|
|
|
+ case '-': negative = 1;
|
|
|
+ case '+': c = scan_getc(sc);
|
|
|
+ }
|
|
|
+
|
|
|
+ number = 0.;
|
|
|
+ num_digits = -1;
|
|
|
+ exponent_power = 0;
|
|
|
+ since_decimal = INT_MIN;
|
|
|
+
|
|
|
+ LOOP:
|
|
|
+ while (isdigit(c)) {
|
|
|
+ ++since_decimal;
|
|
|
+ if (num_digits < 0) {
|
|
|
+ ++num_digits;
|
|
|
+ }
|
|
|
+ if (num_digits || (c != '0')) {
|
|
|
+ ++num_digits;
|
|
|
+ if (num_digits <= MAX_SIG_DIGITS) {
|
|
|
+ number = number * 10. + (c - '0');
|
|
|
+ }
|
|
|
+ }
|
|
|
+ c = scan_getc(sc);
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((c == '.') && (since_decimal < 0)) {
|
|
|
+ since_decimal = 0;
|
|
|
+ c = scan_getc(sc);
|
|
|
+ goto LOOP;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (num_digits<0) {
|
|
|
+ goto FAIL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (num_digits > MAX_SIG_DIGITS) {
|
|
|
+ exponent_power += num_digits - MAX_SIG_DIGITS;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (since_decimal >= 0) {
|
|
|
+ exponent_power -= since_decimal;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (negative) {
|
|
|
+ number = -number;
|
|
|
+ negative = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ if (c == 'e' || c == 'E') {
|
|
|
+ c = scan_getc(sc);
|
|
|
+ switch(c) {
|
|
|
+ case '-': negative = 1;
|
|
|
+ case '+': c = scan_getc(sc);
|
|
|
+ }
|
|
|
|
|
|
- for (;;) {
|
|
|
- if (store)
|
|
|
- *p++ = c;
|
|
|
- if (((c = getc(fp)) < 1) || (--width == 0))
|
|
|
- break;
|
|
|
+ num_digits = 0;
|
|
|
+ exponent_temp = 0;
|
|
|
+ while (isdigit(c)) {
|
|
|
+ if (exponent_temp < MAX_ALLOWED_EXP) {
|
|
|
+ exponent_temp = exponent_temp * 10 + (c - '0');
|
|
|
+ }
|
|
|
+ c = scan_getc(sc);
|
|
|
+ ++num_digits;
|
|
|
+ }
|
|
|
|
|
|
- q = ((unsigned char *)
|
|
|
- strchr(delim, c));
|
|
|
- if (lval == (q == 0))
|
|
|
- break;
|
|
|
- }
|
|
|
+ if (num_digits == 0) {
|
|
|
+ goto FAIL;
|
|
|
+ }
|
|
|
+ if (negative) {
|
|
|
+ exponent_power -= exponent_temp;
|
|
|
+ } else {
|
|
|
+ exponent_power += exponent_temp;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- if (store) {
|
|
|
- if (endnull)
|
|
|
- *p = '\0';
|
|
|
- ++cnt;
|
|
|
- }
|
|
|
- break;
|
|
|
+ if (number != 0.) {
|
|
|
+
|
|
|
+ exponent_temp = exponent_power;
|
|
|
+ p10 = 10.;
|
|
|
|
|
|
- case '\0':
|
|
|
- --fmt;
|
|
|
-
|
|
|
+ if (exponent_temp < 0) {
|
|
|
+ exponent_temp = -exponent_temp;
|
|
|
+ }
|
|
|
|
|
|
- default:
|
|
|
- goto cmatch;
|
|
|
+ while (exponent_temp) {
|
|
|
+ if (exponent_temp & 1) {
|
|
|
+ if (exponent_power < 0) {
|
|
|
+ number /= p10;
|
|
|
+ } else {
|
|
|
+ number *= p10;
|
|
|
+ }
|
|
|
}
|
|
|
- } else if (isspace(*fmt)) {
|
|
|
- skip();
|
|
|
- } else {
|
|
|
- cmatch:
|
|
|
- if (c != *fmt)
|
|
|
- break;
|
|
|
- c = getc(fp);
|
|
|
+ exponent_temp >>= 1;
|
|
|
+ p10 *= p10;
|
|
|
}
|
|
|
-
|
|
|
- if (!*++fmt)
|
|
|
- break;
|
|
|
}
|
|
|
+ *ld = number;
|
|
|
+ return 1;
|
|
|
|
|
|
- done:
|
|
|
- if ((c == EOF) && (cnt == 0))
|
|
|
- return (EOF);
|
|
|
-
|
|
|
- if (c != EOF)
|
|
|
- ungetc(c, fp);
|
|
|
- return (cnt);
|
|
|
+ FAIL:
|
|
|
+ scan_ungetc(sc);
|
|
|
+ return 0;
|
|
|
}
|
|
|
-
|
|
|
+#endif
|
|
|
#endif
|