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