|  | @@ -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
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/* #define	skip()	do{c=getc(fp); if (c<1) goto done;}while(isspace(c))*/
 | 
	
		
			
				|  |  | +#include <assert.h>
 | 
	
		
			
				|  |  | +#include <ctype.h>
 | 
	
		
			
				|  |  | +#include <limits.h>
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -#define	skip()	while(isspace(c)) { if ((c=getc(fp))<1) goto done; }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#if FLOATS
 | 
	
		
			
				|  |  | -/* fp scan actions */
 | 
	
		
			
				|  |  | -#define F_NADA	0				/* just change state */
 | 
	
		
			
				|  |  | -#define F_SIGN	1				/* set sign */
 | 
	
		
			
				|  |  | -#define F_ESIGN	2				/* set exponent's sign */
 | 
	
		
			
				|  |  | -#define F_INT	3				/* adjust integer part */
 | 
	
		
			
				|  |  | -#define F_FRAC	4				/* adjust fraction part */
 | 
	
		
			
				|  |  | -#define F_EXP	5				/* adjust exponent part */
 | 
	
		
			
				|  |  | -#define F_QUIT	6
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#define NSTATE	8
 | 
	
		
			
				|  |  | -#define FS_INIT		0			/* initial state */
 | 
	
		
			
				|  |  | -#define FS_SIGNED	1			/* saw sign */
 | 
	
		
			
				|  |  | -#define FS_DIGS		2			/* saw digits, no . */
 | 
	
		
			
				|  |  | -#define FS_DOT		3			/* saw ., no digits */
 | 
	
		
			
				|  |  | -#define FS_DD		4			/* saw digits and . */
 | 
	
		
			
				|  |  | -#define FS_E		5			/* saw 'e' */
 | 
	
		
			
				|  |  | -#define FS_ESIGN	6			/* saw exp's sign */
 | 
	
		
			
				|  |  | -#define FS_EDIGS	7			/* saw exp's digits */
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -#define FC_DIG		0
 | 
	
		
			
				|  |  | -#define FC_DOT		1
 | 
	
		
			
				|  |  | -#define FC_E		2
 | 
	
		
			
				|  |  | -#define FC_SIGN		3
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -/* given transition,state do what action? */
 | 
	
		
			
				|  |  | -int fp_do[][NSTATE] = {
 | 
	
		
			
				|  |  | -	{F_INT, F_INT, F_INT,
 | 
	
		
			
				|  |  | -	 F_FRAC, F_FRAC,
 | 
	
		
			
				|  |  | -	 F_EXP, F_EXP, F_EXP},		/* see digit */
 | 
	
		
			
				|  |  | -	{F_NADA, F_NADA, F_NADA,
 | 
	
		
			
				|  |  | -	 F_QUIT, F_QUIT, F_QUIT, F_QUIT, F_QUIT},	/* see '.' */
 | 
	
		
			
				|  |  | -	{F_QUIT, F_QUIT,
 | 
	
		
			
				|  |  | -	 F_NADA, F_QUIT, F_NADA,
 | 
	
		
			
				|  |  | -	 F_QUIT, F_QUIT, F_QUIT},	/* see e/E */
 | 
	
		
			
				|  |  | -	{F_SIGN, F_QUIT, F_QUIT, F_QUIT, F_QUIT,
 | 
	
		
			
				|  |  | -	 F_ESIGN, F_QUIT, F_QUIT},	/* see sign */
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | +static int valid_digit(char c, char base)
 | 
	
		
			
				|  |  | +{
 | 
	
		
			
				|  |  | +	if (base == 16) {
 | 
	
		
			
				|  |  | +		return isxdigit(c);
 | 
	
		
			
				|  |  | +	} else {
 | 
	
		
			
				|  |  | +		return (isdigit(c) && (c < '0' + base));
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/* given transition,state what is new state? */
 | 
	
		
			
				|  |  | -int fp_ns[][NSTATE] = {
 | 
	
		
			
				|  |  | -	{FS_DIGS, FS_DIGS, FS_DIGS,
 | 
	
		
			
				|  |  | -	 FS_DD, FS_DD,
 | 
	
		
			
				|  |  | -	 FS_EDIGS, FS_EDIGS, FS_EDIGS},	/* see digit */
 | 
	
		
			
				|  |  | -	{FS_DOT, FS_DOT, FS_DD,
 | 
	
		
			
				|  |  | -	 },							/* see '.' */
 | 
	
		
			
				|  |  | -	{0, 0,
 | 
	
		
			
				|  |  | -	 FS_E, 0, FS_E,
 | 
	
		
			
				|  |  | -	 },							/* see e/E */
 | 
	
		
			
				|  |  | -	{FS_SIGNED, 0, 0, 0, 0,
 | 
	
		
			
				|  |  | -	 FS_ESIGN, 0, 0},			/* see sign */
 | 
	
		
			
				|  |  | -};
 | 
	
		
			
				|  |  | +extern unsigned long long
 | 
	
		
			
				|  |  | +_strto_ll(const char *str, char **endptr, int base, int uflag);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -/* which states are valid terminators? */
 | 
	
		
			
				|  |  | -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;
 | 
	
		
			
				|  |  | +/* #define	skip()	do{c=getc(fp); if (c<1) goto done;}while(isspace(c))*/
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -{
 | 
	
		
			
				|  |  | -#if WANT_LONG_LONG
 | 
	
		
			
				|  |  | -	long long n;
 | 
	
		
			
				|  |  | +#if WANT_LONG_LONG || WANT_LONG_LONG_ERROR
 | 
	
		
			
				|  |  | +static const char qual[] = "hl" /* "jtz" */ "Lq";
 | 
	
		
			
				|  |  | +/* char = -2, short = -1, int = 0, long = 1, long long = 2 */
 | 
	
		
			
				|  |  | +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" /* "jtz" */;
 | 
	
		
			
				|  |  | +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)) {	/* width digit(s) */
 | 
	
		
			
				|  |  | -				if (width == -1)
 | 
	
		
			
				|  |  | -					width = 0;
 | 
	
		
			
				|  |  | -				wide1 = width = (width * 10) + (*fmt - '0');
 | 
	
		
			
				|  |  | -				++fmt;
 | 
	
		
			
				|  |  | -			}
 | 
	
		
			
				|  |  | -			--fmt;
 | 
	
		
			
				|  |  | -		  fmtnxt:
 | 
	
		
			
				|  |  | -			++fmt;
 | 
	
		
			
				|  |  | -			switch (tolower(*fmt)) {	/* tolower() is a MACRO! */
 | 
	
		
			
				|  |  | -			case '*':
 | 
	
		
			
				|  |  | -				endnull = store = 0;
 | 
	
		
			
				|  |  | -				goto fmtnxt;
 | 
	
		
			
				|  |  | -			case 'l':			/* long data */
 | 
	
		
			
				|  |  | -				lval = 1;
 | 
	
		
			
				|  |  | -#if WANT_LONG_LONG
 | 
	
		
			
				|  |  | -			    if (*fmt == 'L') { /* long long data */
 | 
	
		
			
				|  |  | -					lval = 2;
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | +#if WANT_DOUBLE || WANT_DOUBLE_ERROR
 | 
	
		
			
				|  |  | +						   /*01234567890123456 */
 | 
	
		
			
				|  |  | +static const char spec[]  = "%n[csoupxXidfeEgG";
 | 
	
		
			
				|  |  | +#else
 | 
	
		
			
				|  |  | +static const char spec[]  = "%n[csoupxXid";
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  | -				goto fmtnxt;
 | 
	
		
			
				|  |  | -			case 'h':			/* short data */
 | 
	
		
			
				|  |  | -				lval = 0;
 | 
	
		
			
				|  |  | -				goto fmtnxt;
 | 
	
		
			
				|  |  | +/* radix[i] <-> spec[i+5]     o   u   p   x   X  i   d */
 | 
	
		
			
				|  |  | +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':			/* any-base numeric */
 | 
	
		
			
				|  |  | -				base = 0;
 | 
	
		
			
				|  |  | -				goto numfmt;
 | 
	
		
			
				|  |  | +static int __strtold(long double *ld, struct scan_cookie *sc);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -			case 'b':			/* unsigned binary */
 | 
	
		
			
				|  |  | -				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) { /* not EOF or EOS */
 | 
	
		
			
				|  |  | +		sc->ungot_flag = 1;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -			case 'o':			/* unsigned octal */
 | 
	
		
			
				|  |  | -				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':			/* unsigned hexadecimal */
 | 
	
		
			
				|  |  | -				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':			/* SIGNED decimal */
 | 
	
		
			
				|  |  | -				neg = 0;
 | 
	
		
			
				|  |  | -				/* FALL-THRU */
 | 
	
		
			
				|  |  | +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) {	/* not EOF or EOS */
 | 
	
		
			
				|  |  | +		--sc->nread;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  | +}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -			case 'u':			/* unsigned decimal */
 | 
	
		
			
				|  |  | -			  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 == '%') {		/* Conversion specification. */
 | 
	
		
			
				|  |  | +			++fmt;
 | 
	
		
			
				|  |  | +			if (*fmt == '*') {	/* Suppress assignment. */
 | 
	
		
			
				|  |  | +				store = 0;
 | 
	
		
			
				|  |  | +				++fmt;
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +			for (i = 0 ; isdigit(*fmt) ; sc.width = i) {
 | 
	
		
			
				|  |  | +				i = (i * 10) + (*fmt++ - '0'); /* Get specified width. */
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +			for (i = 0 ; i < sizeof(qual) ; i++) { /* Optional qualifier. */
 | 
	
		
			
				|  |  | +				if (qual[i] == *fmt) {
 | 
	
		
			
				|  |  | +					++fmt;
 | 
	
		
			
				|  |  | +					lval += qsz[i];
 | 
	
		
			
				|  |  | +					if ((i < 2) && (qual[i] == *fmt)) {	/* Double h or l. */
 | 
	
		
			
				|  |  | +						++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++) {	/* Process format specifier. */
 | 
	
		
			
				|  |  | +				if (*fmt != *p) continue;
 | 
	
		
			
				|  |  | +				if (p-spec < 1) { /* % - match a '%'*/
 | 
	
		
			
				|  |  | +					goto matchchar;
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				digits[base] = '\0';
 | 
	
		
			
				|  |  | -				p = ((unsigned char *)
 | 
	
		
			
				|  |  | -					 strchr(digits, toupper(c)));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				if ((!c || !p) && width)
 | 
	
		
			
				|  |  | +				if (p-spec < 2) { /* n - store number of chars read */
 | 
	
		
			
				|  |  | +					*(va_arg(ap, int *)) = sc.nread;
 | 
	
		
			
				|  |  | +					scan_getc_nw(&sc);
 | 
	
		
			
				|  |  | +					goto nextfmt;
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +				if (p-spec > 3) { /* skip white space if not c or [ */
 | 
	
		
			
				|  |  | +					while (isspace(scan_getc_nw(&sc)))
 | 
	
		
			
				|  |  | +						{}
 | 
	
		
			
				|  |  | +					scan_ungetc(&sc);
 | 
	
		
			
				|  |  | +				}
 | 
	
		
			
				|  |  | +				if (p-spec < 5) { /* [,c,s - string conversions */
 | 
	
		
			
				|  |  | +					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 == '[') { /* need to build a scanset */
 | 
	
		
			
				|  |  | +						if (*++fmt == '^') {
 | 
	
		
			
				|  |  | +							invert = 1;
 | 
	
		
			
				|  |  | +							++fmt;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +						if (*fmt == ']') {
 | 
	
		
			
				|  |  | +							scanset[(int)']'] = 1;
 | 
	
		
			
				|  |  | +							++fmt;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +						r0 = 0;
 | 
	
		
			
				|  |  | +						while (*fmt && *fmt !=']') { /* build scanset */
 | 
	
		
			
				|  |  | +							if ((*fmt == '-') && r0 && (fmt[1] != ']')) {
 | 
	
		
			
				|  |  | +								/* range */
 | 
	
		
			
				|  |  | +								++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) { /* format string exhausted! */
 | 
	
		
			
				|  |  | +							goto done;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					/* ok -- back to common work */
 | 
	
		
			
				|  |  | +					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; /* yes, we stored something */
 | 
	
		
			
				|  |  | +						*b = cc;
 | 
	
		
			
				|  |  | +						b += store;
 | 
	
		
			
				|  |  | +						cc = scan_getc(&sc);
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					if (*p != 'c') { /* nul-terminate the stored string */
 | 
	
		
			
				|  |  | +						*b = 0;
 | 
	
		
			
				|  |  | +						cnt += i;
 | 
	
		
			
				|  |  | +						goto nextfmt;
 | 
	
		
			
				|  |  | +					} else if (sc.width < 0) { /* case 'c' */
 | 
	
		
			
				|  |  | +						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) { /* o,u,p,x,X,i,d - (un)signed integer */
 | 
	
		
			
				|  |  | +					if (*p == 'p') {
 | 
	
		
			
				|  |  | +						/* assume pointer same size as int or long. */
 | 
	
		
			
				|  |  | +						lval = (sizeof(char *) == sizeof(long));
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					usflag = ((p-spec) < 10); /* (1)0 if (un)signed */
 | 
	
		
			
				|  |  | +					base = radix[(int)(p-spec) - 5];
 | 
	
		
			
				|  |  | +					b = buf;
 | 
	
		
			
				|  |  | +					if (sc.width <= 0) {
 | 
	
		
			
				|  |  | +						goto done;
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					cc = scan_getc(&sc);
 | 
	
		
			
				|  |  | +					if ((cc == '+') || (cc == '-')) { /* Handle leading sign.*/
 | 
	
		
			
				|  |  | +						*b++ = cc;
 | 
	
		
			
				|  |  | +						cc = scan_getc(&sc);
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					if (cc == '0') { /* Possibly set base and handle prefix. */
 | 
	
		
			
				|  |  | +						if ((base == 0) || (base == 16)) {
 | 
	
		
			
				|  |  | +							cc = scan_getc(&sc);
 | 
	
		
			
				|  |  | +							if ((cc == 'x') || (cc == 'X')) {
 | 
	
		
			
				|  |  | +								/* We're committed to base 16 now. */
 | 
	
		
			
				|  |  | +								base = 16;
 | 
	
		
			
				|  |  | +								cc = scan_getc(&sc);
 | 
	
		
			
				|  |  | +							} else { /* oops... back up */
 | 
	
		
			
				|  |  | +								scan_ungetc(&sc);
 | 
	
		
			
				|  |  | +								cc = '0';
 | 
	
		
			
				|  |  | +								if (base == 0) {
 | 
	
		
			
				|  |  | +									base = 8;
 | 
	
		
			
				|  |  | +								}
 | 
	
		
			
				|  |  | +							}
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					/* At this point, we're ready to start reading digits. */
 | 
	
		
			
				|  |  | +					if (cc == '0') {
 | 
	
		
			
				|  |  | +						*b++ = cc; /* Store first leading 0 */
 | 
	
		
			
				|  |  | +						do {	/*     but ignore others. */
 | 
	
		
			
				|  |  | +							cc = scan_getc(&sc);
 | 
	
		
			
				|  |  | +						} while (cc == '0');
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					while (valid_digit(cc,base)) { /* Now for nonzero digits.*/
 | 
	
		
			
				|  |  | +						if (b - buf < MAX_DIGITS) {
 | 
	
		
			
				|  |  | +							*b++ = cc;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +						cc = scan_getc(&sc);
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					*b = 0;	/* null-terminate */
 | 
	
		
			
				|  |  | +					if ((b == buf) || (*--b == '+') || (*b == '-')) {
 | 
	
		
			
				|  |  | +						scan_ungetc(&sc);
 | 
	
		
			
				|  |  | +						goto done; /* No digits! */
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					if (store) {
 | 
	
		
			
				|  |  | +						if (*buf == '-') {
 | 
	
		
			
				|  |  | +							usflag = 0;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +						uv = STRTO_L_(buf, NULL, base, usflag);
 | 
	
		
			
				|  |  | +						vp = va_arg(ap, void *);
 | 
	
		
			
				|  |  | +						switch (lval) {
 | 
	
		
			
				|  |  | +							case 2:	/* If no long long, treat as long . */
 | 
	
		
			
				|  |  |  #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':			/* float */
 | 
	
		
			
				|  |  | -			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:	/* int and long int are the same */
 | 
	
		
			
				|  |  |  #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:	/* int and long int are different */
 | 
	
		
			
				|  |  | +								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 {			/* floating point */
 | 
	
		
			
				|  |  | +					if (sc.width <= 0) {
 | 
	
		
			
				|  |  | +						goto done;
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  | +					if (__strtold(&ld, &sc)) { /* Success! */
 | 
	
		
			
				|  |  | +						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: /* Illegal qualifier! */
 | 
	
		
			
				|  |  | +									assert(0);
 | 
	
		
			
				|  |  | +									goto done;
 | 
	
		
			
				|  |  | +							}
 | 
	
		
			
				|  |  | +							++cnt;
 | 
	
		
			
				|  |  | +						}
 | 
	
		
			
				|  |  | +						goto nextfmt;
 | 
	
		
			
				|  |  | +					}
 | 
	
		
			
				|  |  |  				}
 | 
	
		
			
				|  |  | -				break;
 | 
	
		
			
				|  |  |  #else
 | 
	
		
			
				|  |  | -			case 'e':			/* float */
 | 
	
		
			
				|  |  | -			case 'f':
 | 
	
		
			
				|  |  | -			case 'g':
 | 
	
		
			
				|  |  | -				fprintf(stderr, "LIBC:SCANF");
 | 
	
		
			
				|  |  | -				exit(-1);
 | 
	
		
			
				|  |  | +				assert(0);
 | 
	
		
			
				|  |  |  #endif
 | 
	
		
			
				|  |  | +				goto done;
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +			/* Unrecognized specifier! */
 | 
	
		
			
				|  |  | +			goto done;
 | 
	
		
			
				|  |  | +		} if (isspace(*fmt)) {	/* Consume all whitespace. */
 | 
	
		
			
				|  |  | +			while (isspace(scan_getc_nw(&sc)))
 | 
	
		
			
				|  |  | +				{}
 | 
	
		
			
				|  |  | +		} else {				/* Match the current fmt char. */
 | 
	
		
			
				|  |  | +		matchchar:
 | 
	
		
			
				|  |  | +			if (scan_getc_nw(&sc) != *fmt) {
 | 
	
		
			
				|  |  | +				goto done;
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +			scan_getc_nw(&sc);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +	nextfmt:
 | 
	
		
			
				|  |  | +		scan_ungetc(&sc);
 | 
	
		
			
				|  |  | +		++fmt;
 | 
	
		
			
				|  |  | +	}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -			case 'c':			/* character data */
 | 
	
		
			
				|  |  | -				width = wide1;
 | 
	
		
			
				|  |  | -				lval = endnull = 0;
 | 
	
		
			
				|  |  | -				delim[0] = '\0';
 | 
	
		
			
				|  |  | -				goto strproc;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -			case '[':			/* string w/ delimiter set */
 | 
	
		
			
				|  |  | +  done:						/* end of scan */
 | 
	
		
			
				|  |  | +	kill_scan_cookie(&sc);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -				/* get delimiters */
 | 
	
		
			
				|  |  | -				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;
 | 
	
		
			
				|  |  | -						}
 | 
	
		
			
				|  |  | -						/* fall thru intentional */
 | 
	
		
			
				|  |  | +#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':			/* string data */
 | 
	
		
			
				|  |  | -				lval = 0;
 | 
	
		
			
				|  |  | -				skip();
 | 
	
		
			
				|  |  | -			  strproc:
 | 
	
		
			
				|  |  | -				/* process string */
 | 
	
		
			
				|  |  | -				p = va_arg(ap, unsigned char *);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -				/* if the 1st char fails, match fails */
 | 
	
		
			
				|  |  | -				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);				/* Decrements width. */
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    negative = 0;
 | 
	
		
			
				|  |  | +    switch(c) {					/* Handle optional sign. */
 | 
	
		
			
				|  |  | +		case '-': negative = 1;	/* Fall through to get next char. */
 | 
	
		
			
				|  |  | +		case '+': c = scan_getc(sc);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    number = 0.;
 | 
	
		
			
				|  |  | +    num_digits = -1;
 | 
	
		
			
				|  |  | +    exponent_power = 0;
 | 
	
		
			
				|  |  | +    since_decimal = INT_MIN;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | + LOOP:
 | 
	
		
			
				|  |  | +    while (isdigit(c)) {		/* Process string of digits. */
 | 
	
		
			
				|  |  | +		++since_decimal;
 | 
	
		
			
				|  |  | +		if (num_digits < 0) {	/* First time through? */
 | 
	
		
			
				|  |  | +			++num_digits;		/* We've now seen a digit. */
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		if (num_digits || (c != '0')) { /* had/have nonzero */
 | 
	
		
			
				|  |  | +			++num_digits;
 | 
	
		
			
				|  |  | +			if (num_digits <= MAX_SIG_DIGITS) { /* Is digit significant? */
 | 
	
		
			
				|  |  | +				number = number * 10. + (c - '0');
 | 
	
		
			
				|  |  | +			}
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +		c = scan_getc(sc);
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if ((c == '.') && (since_decimal < 0)) { /* If no previous decimal pt, */
 | 
	
		
			
				|  |  | +		since_decimal = 0;		/* save position of decimal point */
 | 
	
		
			
				|  |  | +		c = scan_getc(sc);			/* and process rest of digits */
 | 
	
		
			
				|  |  | +		goto LOOP;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (num_digits<0) {			/* Must have at least one digit. */
 | 
	
		
			
				|  |  | +		goto FAIL;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (num_digits > MAX_SIG_DIGITS) { /* Adjust exp for skipped digits. */
 | 
	
		
			
				|  |  | +		exponent_power += num_digits - MAX_SIG_DIGITS;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (since_decimal >= 0) {		/* Adjust exponent for decimal point. */
 | 
	
		
			
				|  |  | +		exponent_power -= since_decimal;
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    if (negative) {				/* Correct for sign. */
 | 
	
		
			
				|  |  | +		number = -number;
 | 
	
		
			
				|  |  | +		negative = 0;			/* Reset for exponent processing below. */
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    /* Process an exponent string. */
 | 
	
		
			
				|  |  | +    if (c == 'e' || c == 'E') {
 | 
	
		
			
				|  |  | +		c = scan_getc(sc);
 | 
	
		
			
				|  |  | +		switch(c) {				/* Handle optional sign. */
 | 
	
		
			
				|  |  | +			case '-': negative = 1;	/* Fall through to get next char. */
 | 
	
		
			
				|  |  | +			case '+': c = scan_getc(sc);
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -				for (;;) {		/* FOREVER */
 | 
	
		
			
				|  |  | -					if (store)
 | 
	
		
			
				|  |  | -						*p++ = c;
 | 
	
		
			
				|  |  | -					if (((c = getc(fp)) < 1) || (--width == 0))
 | 
	
		
			
				|  |  | -						break;
 | 
	
		
			
				|  |  | +		num_digits = 0;
 | 
	
		
			
				|  |  | +		exponent_temp = 0;
 | 
	
		
			
				|  |  | +		while (isdigit(c)) {	/* Process string of digits. */
 | 
	
		
			
				|  |  | +			if (exponent_temp < MAX_ALLOWED_EXP) { /* overflow check */
 | 
	
		
			
				|  |  | +				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) {	/* Were there no exp digits? */
 | 
	
		
			
				|  |  | +			goto FAIL;
 | 
	
		
			
				|  |  | +		} /* else */
 | 
	
		
			
				|  |  | +		if (negative) {
 | 
	
		
			
				|  |  | +			exponent_power -= exponent_temp;
 | 
	
		
			
				|  |  | +		} else {
 | 
	
		
			
				|  |  | +			exponent_power += exponent_temp;
 | 
	
		
			
				|  |  | +		}
 | 
	
		
			
				|  |  | +    }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -				if (store) {
 | 
	
		
			
				|  |  | -					if (endnull)
 | 
	
		
			
				|  |  | -						*p = '\0';
 | 
	
		
			
				|  |  | -					++cnt;
 | 
	
		
			
				|  |  | -				}
 | 
	
		
			
				|  |  | -				break;
 | 
	
		
			
				|  |  | +    if (number != 0.) {
 | 
	
		
			
				|  |  | +		/* Now scale the result. */
 | 
	
		
			
				|  |  | +		exponent_temp = exponent_power;
 | 
	
		
			
				|  |  | +		p10 = 10.;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -			case '\0':			/* early EOS */
 | 
	
		
			
				|  |  | -				--fmt;
 | 
	
		
			
				|  |  | -				/* FALL THRU */
 | 
	
		
			
				|  |  | +		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 whitespace */
 | 
	
		
			
				|  |  | -			skip();
 | 
	
		
			
				|  |  | -		} else {				/* normal match char */
 | 
	
		
			
				|  |  | -		  cmatch:
 | 
	
		
			
				|  |  | -			if (c != *fmt)
 | 
	
		
			
				|  |  | -				break;
 | 
	
		
			
				|  |  | -			c = getc(fp);
 | 
	
		
			
				|  |  | +			exponent_temp >>= 1;
 | 
	
		
			
				|  |  | +			p10 *= p10;
 | 
	
		
			
				|  |  |  		}
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -		if (!*++fmt)
 | 
	
		
			
				|  |  | -			break;
 | 
	
		
			
				|  |  |  	}
 | 
	
		
			
				|  |  | +	*ld = number;
 | 
	
		
			
				|  |  | +	return 1;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -  done:						/* end of scan */
 | 
	
		
			
				|  |  | -	if ((c == EOF) && (cnt == 0))
 | 
	
		
			
				|  |  | -		return (EOF);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -	if (c != EOF)
 | 
	
		
			
				|  |  | -		ungetc(c, fp);
 | 
	
		
			
				|  |  | -	return (cnt);
 | 
	
		
			
				|  |  | + FAIL:
 | 
	
		
			
				|  |  | +	scan_ungetc(sc);
 | 
	
		
			
				|  |  | +	return 0;
 | 
	
		
			
				|  |  |  }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | +#endif /* WANT_DOUBLE */
 | 
	
		
			
				|  |  |  #endif
 |