summaryrefslogtreecommitdiffstats
path: root/toolchain/uClibc/uClibc-0.9.33.2-scanf.patch
blob: 5b779db86ae3e875c5ca46b01aad4e73f093179d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
From 8cfb43de636faa401634340d1a18404844f9ba5a Mon Sep 17 00:00:00 2001
From: Mike Frysinger <vapier@gentoo.org>
Date: Sun, 06 May 2012 07:50:44 +0000
Subject: 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>
---
(limited to 'libc/stdio/_scanf.c')

diff --git a/libc/stdio/_scanf.c b/libc/stdio/_scanf.c
index f38e72b..952853c 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) || \
--
cgit v0.9.0.1-2-gef13