1651f885d0178f9669fd36974e02d30f2c211435
[aversive.git] / modules / ihm / parse / parse_num.c
1 #include <stdio.h>
2 #include <inttypes.h>
3 #include <ctype.h>
4 #include <string.h>
5
6 #include "parse.h"
7 #include "parse_num.h"
8
9 //#define debug_printf(args...) printf(args)
10 #define debug_printf(args...) do {} while(0)
11
12 /* XXX to remove ?? */
13 #define U08_MIN 0x00
14 #define U08_MAX 0xFF
15 #define U16_MIN 0x0000
16 #define U16_MAX 0xFFFF
17 #define U32_MIN 0x00000000
18 #define U32_MAX 0xFFFFFFFF
19 #define S08_MIN 0x80
20 #define S08_MAX 0x7F
21 #define S16_MIN 0x8000
22 #define S16_MAX 0x7FFF
23 #define S32_MIN 0x80000000
24 #define S32_MAX 0x7FFFFFFF
25
26
27 struct token_ops token_num_ops = {
28         .parse = parse_num,
29         .complete_get_nb = NULL,
30         .complete_get_elt = NULL,
31         .get_help = get_help_num,
32 };
33
34
35 enum num_parse_state_t {
36         START,
37         DEC_NEG,
38         BIN,
39         HEX,
40         FLOAT_POS,
41         FLOAT_NEG,
42         ERROR,
43
44         FIRST_OK, /* not used */
45         ZERO_OK,
46         HEX_OK,
47         OCTAL_OK,
48         BIN_OK,
49         DEC_NEG_OK,
50         DEC_POS_OK,
51         FLOAT_POS_OK,
52         FLOAT_NEG_OK,
53 };
54
55 /* Keep it sync with enum in .h */
56 static const char PROGMEM help1[] = "UINT8";
57 static const char PROGMEM help2[] = "UINT16";
58 static const char PROGMEM help3[] = "UINT32";
59 static const char PROGMEM help4[] = "INT8";
60 static const char PROGMEM help5[] = "INT16";
61 static const char PROGMEM help6[] = "INT32";
62 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
63 static const char PROGMEM help7[] = "FLOAT";
64 #endif
65 static PGM_P num_help[] = {
66         help1, help2, help3, help4,
67         help5, help6,
68 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
69         help7,
70 #endif
71 };
72
73 static inline int8_t 
74 add_to_res(uint8_t c, uint32_t * res, uint8_t base)
75 {
76         /* overflow */
77         if ( (U32_MAX - c) / base < *res ) {
78                 return -1;
79         }
80
81         *res = *res * base + c ;
82         return 0;
83 }
84
85
86 /* parse an int or a float */
87 int8_t
88 parse_num(PGM_P tk, const char * srcbuf, void * res)
89 {
90         struct token_num_data nd;
91         enum num_parse_state_t st = START;
92         const char * buf = srcbuf;
93         char c = *buf;
94         uint32_t res1=0, res2=0, res3=1;
95
96         memcpy_P(&nd, &((struct token_num *)tk)->num_data, sizeof(nd));
97
98         while ( st != ERROR && c && ! isendoftoken(c) ) {
99                 debug_printf("%c %x -> ", c, c);
100                 switch (st) {
101                 case START:
102                         if (c == '-') {
103                                 st = DEC_NEG;
104                         }
105                         else if (c == '0') {
106                                 st = ZERO_OK;
107                         }
108 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
109                         else if (c == '.') {
110                                 st = FLOAT_POS;
111                                 res1 = 0;
112                         }
113 #endif
114                         else if (c >= '1' && c <= '9') {
115                                 if (add_to_res(c - '0', &res1, 10) < 0)
116                                         st = ERROR;
117                                 else
118                                         st = DEC_POS_OK;
119                         }
120                         else  {
121                                 st = ERROR;
122                         }
123                         break;
124
125                 case ZERO_OK:
126                         if (c == 'x') {
127                                 st = HEX;
128                         }
129                         else if (c == 'b') {
130                                 st = BIN;
131                         }
132 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
133                         else if (c == '.') {
134                                 st = FLOAT_POS;
135                                 res1 = 0;
136                         }
137 #endif
138                         else if (c >= '0' && c <= '7') {
139                                 if (add_to_res(c - '0', &res1, 10) < 0)
140                                         st = ERROR;
141                                 else
142                                         st = OCTAL_OK;
143                         }                       
144                         else  {
145                                 st = ERROR;
146                         }
147                         break;
148
149                 case DEC_NEG:
150                         if (c >= '0' && c <= '9') {
151                                 if (add_to_res(c - '0', &res1, 10) < 0)
152                                         st = ERROR;
153                                 else
154                                         st = DEC_NEG_OK;
155                         }
156 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
157                         else if (c == '.') {
158                                 res1 = 0;
159                                 st = FLOAT_NEG;
160                         }
161 #endif
162                         else {
163                                 st = ERROR;
164                         }
165                         break;
166
167                 case DEC_NEG_OK:
168                         if (c >= '0' && c <= '9') {
169                                 if (add_to_res(c - '0', &res1, 10) < 0)
170                                         st = ERROR;
171                         }
172 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
173                         else if (c == '.') {
174                                 st = FLOAT_NEG;
175                         }
176 #endif
177                         else {
178                                 st = ERROR;
179                         }
180                         break;
181
182                 case DEC_POS_OK:
183                         if (c >= '0' && c <= '9') {
184                                 if (add_to_res(c - '0', &res1, 10) < 0)
185                                         st = ERROR;
186                         }
187 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
188                         else if (c == '.') {
189                                 st = FLOAT_POS;
190                         }
191 #endif
192                         else {
193                                 st = ERROR;
194                         }
195                         break;
196
197                 case HEX:
198                         st = HEX_OK;
199                         /* no break */
200                 case HEX_OK:
201                         if (c >= '0' && c <= '9') {
202                                 if (add_to_res(c - '0', &res1, 16) < 0)
203                                         st = ERROR;
204                         }
205                         else if (c >= 'a' && c <= 'f') {
206                                 if (add_to_res(c - 'a' + 10, &res1, 16) < 0)
207                                         st = ERROR;
208                         }
209                         else if (c >= 'A' && c <= 'F') {
210                                 if (add_to_res(c - 'A' + 10, &res1, 16) < 0)
211                                         st = ERROR;
212                         }
213                         else {
214                                 st = ERROR;
215                         }
216                         break;
217
218
219                 case OCTAL_OK:
220                         if (c >= '0' && c <= '7') {
221                                 if (add_to_res(c - '0', &res1, 8) < 0)
222                                         st = ERROR;
223                         }
224                         else {
225                                 st = ERROR;
226                         }
227                         break;
228
229                 case BIN:
230                         st = BIN_OK; 
231                         /* no break */
232                 case BIN_OK:
233                         if (c >= '0' && c <= '1') {
234                                 if (add_to_res(c - '0', &res1, 2) < 0)
235                                         st = ERROR;
236                         }
237                         else {
238                                 st = ERROR;
239                         }
240                         break;
241
242 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
243                 case FLOAT_POS:
244                         if (c >= '0' && c <= '9') {
245                                 if (add_to_res(c - '0', &res2, 10) < 0)
246                                         st = ERROR;
247                                 else 
248                                         st = FLOAT_POS_OK;
249                                 res3 = 10;
250                         }
251                         else {
252                                 st = ERROR;
253                         }
254                         break;
255
256                 case FLOAT_NEG:
257                         if (c >= '0' && c <= '9') {
258                                 if (add_to_res(c - '0', &res2, 10) < 0)
259                                         st = ERROR;
260                                 else 
261                                         st = FLOAT_NEG_OK;
262                                 res3 = 10;
263                         }
264                         else {
265                                 st = ERROR;
266                         }
267                         break;
268
269                 case FLOAT_POS_OK:
270                         if (c >= '0' && c <= '9') {
271                                 if (add_to_res(c - '0', &res2, 10) < 0)
272                                         st = ERROR;
273                                 if (add_to_res(0, &res3, 10) < 0)
274                                         st = ERROR;
275                         }
276                         else {
277                                 st = ERROR;
278                         }
279                         break;
280
281                 case FLOAT_NEG_OK:
282                         if (c >= '0' && c <= '9') {
283                                 if (add_to_res(c - '0', &res2, 10) < 0)
284                                         st = ERROR;
285                                 if (add_to_res(0, &res3, 10) < 0)
286                                         st = ERROR;
287                         }
288                         else {
289                                 st = ERROR;
290                         }
291                         break;
292 #endif
293
294                 default:
295                         debug_printf("not impl ");
296                         
297                 }
298
299                 /* XXX uint32_t et %d */
300                 debug_printf("(%d)  (%d)  (%d)\n", res1, res2, res3);
301
302                 buf ++;
303                 c = *buf;
304
305                 /* token too long */
306                 if (buf-srcbuf > 127)
307                         return -1;
308         }
309         
310         switch (st) {
311         case ZERO_OK:
312         case DEC_POS_OK:
313         case HEX_OK:
314         case OCTAL_OK:
315         case BIN_OK:
316                 if ( nd.type == INT8 && res1 <= S08_MAX ) {
317                         if (res)
318                                 *(int8_t *)res = (int8_t) res1;
319                         return (buf-srcbuf);
320                 }
321                 else if ( nd.type == INT16 && res1 <= S16_MAX ) {
322                         if (res)
323                                 *(int16_t *)res = (int16_t) res1;
324                         return (buf-srcbuf);
325                 }
326                 else if ( nd.type == INT32 && res1 <= S32_MAX ) {
327                         if (res)
328                                 *(int32_t *)res = (int32_t) res1;
329                         return (buf-srcbuf);
330                 }
331                 else if ( nd.type == UINT8 && res1 <= U08_MAX ) {
332                         if (res)
333                                 *(uint8_t *)res = (uint8_t) res1;
334                         return (buf-srcbuf);
335                 }
336                 else if (nd.type == UINT16  && res1 <= U16_MAX ) {
337                         if (res)
338                                 *(uint16_t *)res = (uint16_t) res1;
339                         return (buf-srcbuf);
340                 }
341                 else if ( nd.type == UINT32 ) {
342                         if (res)
343                                 *(uint32_t *)res = (uint32_t) res1;
344                         return (buf-srcbuf);
345                 }
346 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
347                 else if ( nd.type == FLOAT ) {
348                         if (res)
349                                 *(float *)res = (float)res1;
350                         return (buf-srcbuf);
351                 }
352 #endif
353                 else {
354                         return -1;
355                 }
356                 break;
357
358         case DEC_NEG_OK:
359                 if ( nd.type == INT8 && res1 <= S08_MAX + 1 ) {
360                         if (res)
361                                 *(int8_t *)res = - (int8_t) res1;
362                         return (buf-srcbuf);
363                 }
364                 else if ( nd.type == INT16 && res1 <= (uint16_t)S16_MAX + 1 ) {
365                         if (res)
366                                 *(int16_t *)res = - (int16_t) res1;
367                         return (buf-srcbuf);
368                 }
369                 else if ( nd.type == INT32 && res1 <= (uint32_t)S32_MAX + 1 ) {
370                         if (res)
371                                 *(int32_t *)res = - (int32_t) res1;
372                         return (buf-srcbuf);
373                 }
374 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
375                 else if ( nd.type == FLOAT ) {
376                         if (res)
377                                 *(float *)res = - (float)res1;
378                         return (buf-srcbuf);
379                 }
380 #endif
381                 else {
382                         return -1;
383                 }
384                 break;
385
386 #ifndef CONFIG_MODULE_PARSE_NO_FLOAT
387         case FLOAT_POS:
388         case FLOAT_POS_OK:
389                 if ( nd.type == FLOAT ) {
390                         if (res)
391                                 *(float *)res = (float)res1 + ((float)res2 / (float)res3);
392                         return (buf-srcbuf);
393                         
394                 }
395                 else {
396                         return -1;
397                 }
398                 break;
399
400         case FLOAT_NEG:
401         case FLOAT_NEG_OK:
402                 if ( nd.type == FLOAT ) {
403                         if (res)
404                                 *(float *)res = - ((float)res1 + ((float)res2 / (float)res3));
405                         return (buf-srcbuf);
406                         
407                 }
408                 else {
409                         return -1;
410                 }
411                 break;
412 #endif
413         default:
414                 debug_printf("error\n");
415                 return -1;
416         }
417         return -1;
418 }
419
420
421 /* parse an int or a float */
422 int8_t
423 get_help_num(PGM_P tk, char * dstbuf, uint8_t size)
424 {
425         struct token_num_data nd;
426
427         memcpy_P(&nd, &((struct token_num *)tk)->num_data, sizeof(nd));
428         
429         /* should not happen.... don't so this test */
430 /*      if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */
431 /*              return -1; */
432
433         strncpy_P(dstbuf, num_help[nd.type], size);
434         dstbuf[size-1] = '\0';
435         return 0;
436 }