From 96f31bf6ae531310ce2dae265b4ab4fa6b220a9f Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@openwrt.org>
Date: Mon, 29 Oct 2012 19:25:38 +0000
Subject: [PATCH] uClibc: backport support for assignment-allocation character
 %m in sscanf

SVN-Revision: 34001
---
 .../010-backport_sscanf_alloc.patch           | 184 ++++++++++++++++++
 1 file changed, 184 insertions(+)
 create mode 100644 toolchain/uClibc/patches-0.9.33.2/010-backport_sscanf_alloc.patch

diff --git a/toolchain/uClibc/patches-0.9.33.2/010-backport_sscanf_alloc.patch b/toolchain/uClibc/patches-0.9.33.2/010-backport_sscanf_alloc.patch
new file mode 100644
index 0000000000..f5f3cc4d4e
--- /dev/null
+++ b/toolchain/uClibc/patches-0.9.33.2/010-backport_sscanf_alloc.patch
@@ -0,0 +1,184 @@
+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
+@@ -1597,19 +1597,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) || \
-- 
2.30.2