diff options
| -rw-r--r-- | extra/Configs/Config.in | 13 | ||||
| -rw-r--r-- | libc/stdio/_scanf.c | 68 | 
2 files changed, 39 insertions, 42 deletions
| diff --git a/extra/Configs/Config.in b/extra/Configs/Config.in index 10607293c..c2f2fc723 100644 --- a/extra/Configs/Config.in +++ b/extra/Configs/Config.in @@ -1590,19 +1590,6 @@ config UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS  	  Most people will answer 9. - -config UCLIBC_HAS_SCANF_GLIBC_A_FLAG -	bool "Support glibc's 'a' flag for scanf string conversions (not implemented)" -	help -	  NOTE!!!  Currently Not Implemented!!! Just A Place Holder!!  NOTE!!! -	  NOTE!!!  Conflicts with an ANSI/ISO C99 scanf flag!!         NOTE!!! - -	  Answer Y to enable support for glibc's 'a' flag for the scanf string -	  conversions '%s', '%[', '%ls', '%l[', and '%S'.  This is used to -	  auto-allocate sufficient memory to hold the data retrieved. - -	  Most people will answer N. -  choice  	prompt "Stdio buffer size"  	default UCLIBC_HAS_STDIO_BUFSIZ_4096 diff --git a/libc/stdio/_scanf.c b/libc/stdio/_scanf.c index f38e72b5c..952853cfe 100644 --- a/libc/stdio/_scanf.c +++ b/libc/stdio/_scanf.c @@ -77,14 +77,6 @@  #include <bits/uClibc_fpmax.h>  #endif /* __UCLIBC_HAS_FLOATS__ */ -#ifdef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ -#ifdef L_vfscanf -/* only emit this once */ -#warning Forcing undef of __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ until implemented! -#endif -#undef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ -#endif -  #undef __STDIO_HAS_VSSCANF  #if defined(__STDIO_BUFFERS) || !defined(__UCLIBC_HAS_WCHAR__) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)  #define __STDIO_HAS_VSSCANF 1 @@ -433,8 +425,9 @@ libc_hidden_def(vswscanf)  /* float layout          0123456789012345678901  repeat n for "l[" */ -#define SPEC_CHARS		"npxXoudifFeEgGaACSncs[" -/*                       npxXoudif eEgG  CS cs[ */ +#define SPEC_CHARS		"npxXoudifFeEgGaACSnmcs[" +/*                       npxXoudif eEgG  CS  cs[ */ +/* NOTE: the 'm' flag must come before any convs that support it */  /* NOTE: Ordering is important!  In particular, CONV_LEFTBRACKET   * must immediately precede CONV_c. */ @@ -444,7 +437,7 @@ enum {  	CONV_p,  	CONV_x, CONV_X,	CONV_o,	CONV_u,	CONV_d,	CONV_i,  	CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A, -	CONV_C, CONV_S, CONV_LEFTBRACKET, CONV_c, CONV_s, CONV_leftbracket, +	CONV_C, CONV_S, CONV_LEFTBRACKET, CONV_m, CONV_c, CONV_s, CONV_leftbracket,  	CONV_percent, CONV_whitespace /* not in SPEC_* and no flags */  }; @@ -474,7 +467,7 @@ enum {  	FLAG_SURPRESS   =   0x10,	/* MUST BE 1ST!!  See DO_FLAGS. */  	FLAG_THOUSANDS	=	0x20,  	FLAG_I18N		=	0x40,	/* only works for d, i, u */ -	FLAG_MALLOC     =   0x80,	/* only works for s, S, and [ (and l[)*/ +	FLAG_MALLOC     =   0x80,	/* only works for c, s, S, and [ (and l[)*/  }; @@ -491,7 +484,7 @@ enum {  	/* fFeEgGaA */	(0x0c|FLAG_SURPRESS|FLAG_THOUSANDS|FLAG_I18N), \  	/* C */			(   0|FLAG_SURPRESS), \  	/* S and l[ */	(   0|FLAG_SURPRESS|FLAG_MALLOC), \ -	/* c */			(0x04|FLAG_SURPRESS), \ +	/* c */			(0x04|FLAG_SURPRESS|FLAG_MALLOC), \  	/* s and [ */	(0x04|FLAG_SURPRESS|FLAG_MALLOC), \  } @@ -904,17 +897,17 @@ int attribute_hidden __psfs_parse_spec(register psfs_t *psfs)  		if (*psfs->fmt == *p) {  			int p_m_spec_chars = p - spec_chars; -#ifdef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ -#error implement gnu a flag -			if ((*p == 'a') -				&& ((psfs->fmt[1] == '[') || ((psfs->fmt[1]|0x20) == 's')) -				) {		/* Assumes ascii for 's' and 'S' test. */ -				psfs->flags |= FLAG_MALLOC; +			if (*p == 'm' && +				(psfs->fmt[1] == '[' || psfs->fmt[1] == 'c' || +				 /* Assumes ascii for 's' and 'S' test. */ +				 (psfs->fmt[1] | 0x20) == 's')) +			{ +				if (psfs->store) +					psfs->flags |= FLAG_MALLOC;  				++psfs->fmt;  				++p; -				continue; /* The related conversions follow 'a'. */ +				continue; /* The related conversions follow 'm'. */  			} -#endif /* __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ */  			for (p = spec_ranges; p_m_spec_chars > *p ; ++p) {}  			if (((psfs->dataargtype >> 8) | psfs->flags) @@ -1265,12 +1258,6 @@ int VFSCANF (FILE *__restrict fp, const Wchar *__restrict format, va_list arg)  				while (*wf && __isascii(*wf) && (b < buf + sizeof(buf) - 1)) {  					*b++ = *wf++;  				} -#ifdef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ -#error this is wrong... we need to ched in __psfs_parse_spec instead since this checks last char in buffer and conversion my have stopped before it. -				if ((*b == 'a') && ((*wf == '[') || ((*wf|0x20) == 's'))) { -					goto DONE;	/* Spec was excessively long. */ -				} -#endif /* __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ */  				*b = 0;  				if (b == buf) { /* Bad conversion specifier! */  					goto DONE; @@ -1390,13 +1377,36 @@ int VFSCANF (FILE *__restrict fp, const Wchar *__restrict format, va_list arg)  				}  				if (psfs.conv_num == CONV_s) { +					/* We might have to handle the allocation ourselves */ +					int len; +					/* With 'm', we actually got a pointer to a pointer */ +					unsigned char **ptr = (void *)b; + +					i = 0; +					if (psfs.flags & FLAG_MALLOC) { +						len = 0; +						b = NULL; +					} else +						len = -1; +  					/* Yes, believe it or not, a %s conversion can store nuls. */  					while ((__scan_getc(&sc) >= 0) && !isspace(sc.cc)) {  						zero_conversions = 0; -						*b = sc.cc; -						b += psfs.store; +						if (i == len) { +							/* Pick a size that won't trigger a lot of +							 * mallocs early on ... */ +							len += 256; +							b = realloc(b, len + 1); +						} +						b[i] = sc.cc; +						i += psfs.store;  						fail = 0;  					} + +					if (psfs.flags & FLAG_MALLOC) +						*ptr = b; +					/* The code below takes care of terminating NUL */ +					b += i;  				} else {  #ifdef __UCLIBC_HAS_WCHAR__  					assert((psfs.conv_num == CONV_LEFTBRACKET) || \ | 
