summaryrefslogtreecommitdiff
path: root/firmware/libc/sscanf.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/libc/sscanf.c')
-rw-r--r--firmware/libc/sscanf.c282
1 files changed, 282 insertions, 0 deletions
diff --git a/firmware/libc/sscanf.c b/firmware/libc/sscanf.c
new file mode 100644
index 0000000000..5fbe81f3e0
--- /dev/null
+++ b/firmware/libc/sscanf.c
@@ -0,0 +1,282 @@
1#include <stdarg.h>
2#include <string.h>
3#include <stdbool.h>
4
5static inline bool isspace(char c)
6{
7 return (c == ' ') || (c == '\t') || (c == '\n');
8}
9
10static inline bool isdigit(char c)
11{
12 return (c >= '0') && (c <= '9');
13}
14
15static inline bool isxdigit(char c)
16{
17 return ((c >= '0') && (c <= '9'))
18 || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));
19}
20
21static int parse_dec(int (*peek)(void *userp),
22 void (*pop)(void *userp),
23 void *userp,
24 long *vp)
25{
26 long v = 0;
27 int n = 0;
28 int minus = 0;
29 char ch;
30
31 if ((*peek)(userp) == '-')
32 {
33 (*pop)(userp);
34 n++;
35 minus = 1;
36 }
37
38 ch = (*peek)(userp);
39 if (!isdigit(ch))
40 return -1;
41
42 do
43 {
44 v = v * 10 + ch - '0';
45 (*pop)(userp);
46 n++;
47 ch = (*peek)(userp);
48 } while (isdigit(ch));
49
50 *vp = minus ? -v : v;
51 return n;
52}
53
54static int parse_chars(int (*peek)(void *userp),
55 void (*pop)(void *userp),
56 void *userp,
57 char *vp,
58 bool fake)
59{
60 int n = 0;
61
62 char *pt=vp;
63
64 while (!isspace((*peek)(userp)))
65 {
66 if(fake==false)
67 *(pt++) = (*peek)(userp);
68
69 n++;
70 (*pop)(userp);
71 }
72
73 if(fake==false)
74 (*pt)='\0';
75
76 return n;
77}
78
79static int parse_hex(int (*peek)(void *userp),
80 void (*pop)(void *userp),
81 void *userp,
82 unsigned long *vp)
83{
84 unsigned long v = 0;
85 int n = 0;
86 char ch;
87
88 ch = (*peek)(userp);
89 if (!isxdigit(ch))
90 return -1;
91
92 do
93 {
94 if (ch >= 'a')
95 ch = ch - 'a' + 10;
96 else if (ch >= 'A')
97 ch = ch - 'A' + 10;
98 else
99 ch = ch - '0';
100 v = v * 16 + ch;
101 (*pop)(userp);
102 n++;
103 ch = (*peek)(userp);
104 } while (isxdigit(ch));
105
106 *vp = v;
107 return n;
108}
109
110static int skip_spaces(int (*peek)(void *userp),
111 void (*pop)(void *userp),
112 void *userp)
113{
114 int n = 0;
115 while (isspace((*peek)(userp))) {
116 n++;
117 (*pop)(userp);
118 }
119 return n;
120}
121
122static int scan(int (*peek)(void *userp),
123 void (*pop)(void *userp),
124 void *userp,
125 const char *fmt,
126 va_list ap)
127{
128 char ch;
129 int n = 0;
130 int n_chars = 0;
131 int r;
132 long lval;
133 bool skip=false;
134 unsigned long ulval;
135
136 while ((ch = *fmt++) != '\0')
137 {
138 bool literal = false;
139
140 if (ch == '%')
141 {
142 ch = *fmt++;
143
144 if(ch== '*') /* We should process this, but not store it in an arguement */
145 {
146 ch=*fmt++;
147 skip=true;
148 }
149 else
150 {
151 skip=false;
152 }
153
154 switch (ch)
155 {
156 case 'x':
157 n_chars += skip_spaces(peek, pop, userp);
158 if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0)
159 {
160 if(skip==false)
161 {
162 *(va_arg(ap, unsigned int *)) = ulval;
163 n++;
164 }
165 n_chars += r;
166 }
167 else
168 return n;
169 break;
170 case 'd':
171 n_chars += skip_spaces(peek, pop, userp);
172 if ((r = parse_dec(peek, pop, userp, &lval)) >= 0)
173 {
174 if(skip==false)
175 {
176 *(va_arg(ap, int *)) = lval;
177 n++;
178 }
179 n_chars += r;
180 }
181 else
182 return n;
183 break;
184 case 'n':
185 if(skip==false)
186 {
187 *(va_arg(ap, int *)) = n_chars;
188 n++;
189 }
190 break;
191 case 'l':
192 n_chars += skip_spaces(peek, pop, userp);
193 ch = *fmt++;
194 switch (ch)
195 {
196 case 'x':
197 if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0)
198 {
199 if(skip==false)
200 {
201 *(va_arg(ap, unsigned long *)) = ulval;
202 n++;
203 }
204 n_chars += r;
205 }
206 else
207 return n;
208 break;
209 case 'd':
210 if ((r = parse_dec(peek, pop, userp, &lval)) >= 0)
211 {
212 if(skip==false)
213 {
214 *(va_arg(ap, long *)) = lval;
215 n++;
216 }
217 n_chars += r;
218 }
219 else
220 return n;
221 break;
222 case '\0':
223 return n;
224 default:
225 literal = true;
226 break;
227 }
228 break;
229 case 's':
230 n_chars += skip_spaces(peek, pop, userp);
231 n_chars += parse_chars(peek,pop, userp,skip?0:va_arg(ap, char *), skip );
232 if(skip==false)
233 {
234 n++;
235 }
236 break;
237 case '\0':
238 return n;
239 default:
240 literal = true;
241 break;
242 }
243 } else
244 literal = true;
245
246 if (literal)
247 {
248 n_chars += skip_spaces(peek, pop, userp);
249 if ((*peek)(userp) != ch)
250 continue;
251 else
252 {
253 (*pop)(userp);
254 n_chars++;
255 }
256 }
257 }
258 return n;
259}
260
261static int sspeek(void *userp)
262{
263 return **((char **)userp);
264}
265
266static void sspop(void *userp)
267{
268 (*((char **)userp))++;
269}
270
271int sscanf(const char *s, const char *fmt, ...)
272{
273 int r;
274 va_list ap;
275 const char *p;
276
277 p = s;
278 va_start(ap, fmt);
279 r = scan(sspeek, sspop, &p, fmt, ap);
280 va_end(ap);
281 return r;
282}