|
@@ -0,0 +1,184 @@
|
|
|
+From 8cfb43de636faa401634340d1a18404844f9ba5a Mon Sep 17 00:00:00 2001
|
|
|
+From: Mike Frysinger <[email protected]>
|
|
|
+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 <[email protected]>
|
|
|
+Signed-off-by: Felix Fietkau <[email protected]>
|
|
|
+---
|
|
|
+ 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) || \
|