mirror of
				git://git.openwrt.org/openwrt/openwrt.git
				synced 2025-11-04 06:54:27 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			185 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
			
		
		
	
	
			185 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Diff
		
	
	
	
	
	
From 8cfb43de636faa401634340d1a18404844f9ba5a Mon Sep 17 00:00:00 2001
 | 
						|
From: Mike Frysinger <vapier@gentoo.org>
 | 
						|
Date: Sun, 6 May 2012 03:50:44 -0400
 | 
						|
Subject: [PATCH] stdio: implement assignment-allocation "m" character
 | 
						|
 | 
						|
The latest POSIX spec introduces a "m" character to allocate buffers for
 | 
						|
the user when using scanf type functions.  This is like the old glibc "a"
 | 
						|
flag, but now standardized.  With packages starting to use these, we need
 | 
						|
to implement it.
 | 
						|
 | 
						|
for example:
 | 
						|
	char *s;
 | 
						|
	sscanf("foo", "%ms", &s);
 | 
						|
	printf("%s\n", s);
 | 
						|
	free(s);
 | 
						|
This will automatically allocate storage for "s", read in "foo" to it,
 | 
						|
and then display it.
 | 
						|
 | 
						|
I'm not terribly familiar with the stdio layer, so this could be wrong.
 | 
						|
But it seems to work for me.
 | 
						|
 | 
						|
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
 | 
						|
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
 | 
						|
---
 | 
						|
 extra/Configs/Config.in | 13 ----------
 | 
						|
 libc/stdio/_scanf.c     | 68 ++++++++++++++++++++++++++++---------------------
 | 
						|
 2 files changed, 39 insertions(+), 42 deletions(-)
 | 
						|
 | 
						|
--- a/extra/Configs/Config.in
 | 
						|
+++ b/extra/Configs/Config.in
 | 
						|
@@ -1590,19 +1590,6 @@ config UCLIBC_PRINTF_SCANF_POSITIONAL_AR
 | 
						|
 
 | 
						|
 	  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
 | 
						|
--- 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(r
 | 
						|
 		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
 | 
						|
 				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
 | 
						|
 				}
 | 
						|
 
 | 
						|
 				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) || \
 |