123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184 |
- 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) || \
|