blob: 1bbb5abcbfcad95a02ca184d82fa80b2a15421b0 [file] [log] [blame]
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +00001#include <stdarg.h>
2#include <string.h>
3#include <stdbool.h>
Thomas Martitzac3a7452010-12-02 21:29:05 +00004
5static inline bool my_isspace(char c)
6{
7 return (c == ' ') || (c == '\t') || (c == '\n');
8}
9
10static inline bool my_isdigit(char c)
11{
12 return (c >= '0') && (c <= '9');
13}
14
15static inline bool my_isxdigit(char c)
16{
17 return ((c >= '0') && (c <= '9'))
18 || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'));
19}
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +000020
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;
Karl Kurbjunaec58142007-06-03 22:03:36 +000030
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +000031 if ((*peek)(userp) == '-')
32 {
33 (*pop)(userp);
34 n++;
35 minus = 1;
36 }
37
38 ch = (*peek)(userp);
Thomas Martitzac3a7452010-12-02 21:29:05 +000039 if (!my_isdigit(ch))
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +000040 return -1;
41
42 do
43 {
44 v = v * 10 + ch - '0';
45 (*pop)(userp);
46 n++;
47 ch = (*peek)(userp);
Thomas Martitzac3a7452010-12-02 21:29:05 +000048 } while (my_isdigit(ch));
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +000049
50 *vp = minus ? -v : v;
51 return n;
52}
53
Karl Kurbjun1e0fb022006-12-13 04:55:48 +000054static int parse_chars(int (*peek)(void *userp),
55 void (*pop)(void *userp),
56 void *userp,
Karl Kurbjunaec58142007-06-03 22:03:36 +000057 char *vp,
58 bool fake)
Karl Kurbjun1e0fb022006-12-13 04:55:48 +000059{
60 int n = 0;
Karl Kurbjunaec58142007-06-03 22:03:36 +000061
Karl Kurbjun1e0fb022006-12-13 04:55:48 +000062 char *pt=vp;
63
Thomas Martitzac3a7452010-12-02 21:29:05 +000064 while (!my_isspace((*peek)(userp)))
Karl Kurbjun1e0fb022006-12-13 04:55:48 +000065 {
Karl Kurbjunaec58142007-06-03 22:03:36 +000066 if(fake==false)
67 *(pt++) = (*peek)(userp);
68
Karl Kurbjun1e0fb022006-12-13 04:55:48 +000069 n++;
70 (*pop)(userp);
71 }
72
Karl Kurbjunaec58142007-06-03 22:03:36 +000073 if(fake==false)
74 (*pt)='\0';
Karl Kurbjun1e0fb022006-12-13 04:55:48 +000075
76 return n;
77}
78
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +000079static 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);
Thomas Martitzac3a7452010-12-02 21:29:05 +000089 if (!my_isxdigit(ch))
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +000090 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);
Thomas Martitzac3a7452010-12-02 21:29:05 +0000104 } while (my_isxdigit(ch));
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000105
106 *vp = v;
107 return n;
108}
109
Tomasz Malesinski91f08b52006-02-03 23:39:12 +0000110static int skip_spaces(int (*peek)(void *userp),
111 void (*pop)(void *userp),
112 void *userp)
113{
114 int n = 0;
Thomas Martitzac3a7452010-12-02 21:29:05 +0000115 while (my_isspace((*peek)(userp))) {
Tomasz Malesinski91f08b52006-02-03 23:39:12 +0000116 n++;
117 (*pop)(userp);
118 }
119 return n;
120}
121
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000122static 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;
Karl Kurbjunaec58142007-06-03 22:03:36 +0000133 bool skip=false;
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000134 unsigned long ulval;
135
136 while ((ch = *fmt++) != '\0')
137 {
138 bool literal = false;
Karl Kurbjunaec58142007-06-03 22:03:36 +0000139
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000140 if (ch == '%')
141 {
142 ch = *fmt++;
143
Karl Kurbjunaec58142007-06-03 22:03:36 +0000144 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
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000154 switch (ch)
155 {
156 case 'x':
Tomasz Malesinski91f08b52006-02-03 23:39:12 +0000157 n_chars += skip_spaces(peek, pop, userp);
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000158 if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0)
159 {
Karl Kurbjunaec58142007-06-03 22:03:36 +0000160 if(skip==false)
161 {
162 *(va_arg(ap, unsigned int *)) = ulval;
163 n++;
164 }
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000165 n_chars += r;
166 }
167 else
168 return n;
169 break;
170 case 'd':
Tomasz Malesinski91f08b52006-02-03 23:39:12 +0000171 n_chars += skip_spaces(peek, pop, userp);
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000172 if ((r = parse_dec(peek, pop, userp, &lval)) >= 0)
173 {
Karl Kurbjunaec58142007-06-03 22:03:36 +0000174 if(skip==false)
175 {
176 *(va_arg(ap, int *)) = lval;
177 n++;
178 }
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000179 n_chars += r;
180 }
181 else
182 return n;
183 break;
184 case 'n':
Karl Kurbjunaec58142007-06-03 22:03:36 +0000185 if(skip==false)
186 {
187 *(va_arg(ap, int *)) = n_chars;
188 n++;
189 }
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000190 break;
191 case 'l':
Tomasz Malesinski91f08b52006-02-03 23:39:12 +0000192 n_chars += skip_spaces(peek, pop, userp);
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000193 ch = *fmt++;
194 switch (ch)
195 {
196 case 'x':
197 if ((r = parse_hex(peek, pop, userp, &ulval)) >= 0)
198 {
Karl Kurbjunaec58142007-06-03 22:03:36 +0000199 if(skip==false)
200 {
201 *(va_arg(ap, unsigned long *)) = ulval;
202 n++;
203 }
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000204 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 {
Karl Kurbjunaec58142007-06-03 22:03:36 +0000212 if(skip==false)
213 {
214 *(va_arg(ap, long *)) = lval;
215 n++;
216 }
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000217 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;
Karl Kurbjunaec58142007-06-03 22:03:36 +0000229 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 }
Karl Kurbjun1e0fb022006-12-13 04:55:48 +0000236 break;
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000237 case '\0':
238 return n;
239 default:
240 literal = true;
241 break;
242 }
243 } else
244 literal = true;
245
246 if (literal)
247 {
Tomasz Malesinski91f08b52006-02-03 23:39:12 +0000248 n_chars += skip_spaces(peek, pop, userp);
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000249 if ((*peek)(userp) != ch)
Karl Kurbjun1e0fb022006-12-13 04:55:48 +0000250 continue;
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000251 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;
Karl Kurbjunaec58142007-06-03 22:03:36 +0000276
Tomasz Malesinskie8e0b242006-01-25 01:35:04 +0000277 p = s;
278 va_start(ap, fmt);
279 r = scan(sspeek, sspop, &p, fmt, ap);
280 va_end(ap);
281 return r;
282}