cmdline (merge-intel): cmdline: disable float parsing
[libcmdline.git] / src / lib / cmdline_parse_num.c
1 /*
2  * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
3  * All rights reserved.
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <stdio.h>
29 #include <inttypes.h>
30 #include <ctype.h>
31 #include <string.h>
32
33 #include "cmdline_parse.h"
34 #include "cmdline_parse_num.h"
35
36 //#define debug_printf(args...) printf(args)
37 #define debug_printf(args...) do {} while(0)
38
39 /* XXX to remove ? there should be something better */
40 #define U08_MIN 0x00
41 #define U08_MAX 0xFF
42 #define U16_MIN 0x0000
43 #define U16_MAX 0xFFFF
44 #define U32_MIN 0x00000000
45 #define U32_MAX 0xFFFFFFFF
46 #define S08_MIN 0x80
47 #define S08_MAX 0x7F
48 #define S16_MIN 0x8000
49 #define S16_MAX 0x7FFF
50 #define S32_MIN 0x80000000
51 #define S32_MAX 0x7FFFFFFF
52
53
54 struct cmdline_token_ops cmdline_token_num_ops = {
55         .parse = cmdline_parse_num,
56         .complete_get_nb = NULL,
57         .complete_get_elt = NULL,
58         .get_help = cmdline_get_help_num,
59 };
60
61
62 enum num_parse_state_t {
63         START,
64         DEC_NEG,
65         BIN,
66         HEX,
67         FLOAT_POS,
68         FLOAT_NEG,
69
70         ERROR,
71
72         FIRST_OK, /* not used */
73         ZERO_OK,
74         HEX_OK,
75         OCTAL_OK,
76         BIN_OK,
77         DEC_NEG_OK,
78         DEC_POS_OK,
79         FLOAT_POS_OK,
80         FLOAT_NEG_OK,
81 };
82
83 /* Keep it sync with enum in .h */
84 static const char * num_help[] = {
85         "UINT8", "UINT16", "UINT32",
86         "INT8", "INT16", "INT32",
87 #ifndef CMDLINE_NO_FLOAT
88         "FLOAT",
89 #endif
90 };
91
92 static inline int
93 add_to_res(unsigned int c, unsigned int *res, unsigned int base)
94 {
95         /* overflow */
96         if ( (U32_MAX - c) / base < *res ) {
97                 return -1;
98         }
99
100         *res = *res * base + c ;
101         return 0;
102 }
103
104
105 /* parse an int or a float */
106 int
107 cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res)
108 {
109         struct cmdline_token_num_data nd;
110         enum num_parse_state_t st = START;
111         const char * buf = srcbuf;
112         char c = *buf;
113         uint32_t res1 = 0;
114 #ifndef CMDLINE_NO_FLOAT
115         uint32_t res2 = 0, res3 = 1;
116 #endif
117
118         memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
119
120         while ( st != ERROR && c && ! cmdline_isendoftoken(c) ) {
121                 debug_printf("%c %x -> ", c, c);
122                 switch (st) {
123                 case START:
124                         if (c == '-') {
125                                 st = DEC_NEG;
126                         }
127                         else if (c == '0') {
128                                 st = ZERO_OK;
129                         }
130 #ifndef CMDLINE_NO_FLOAT
131                         else if (c == '.') {
132                                 st = FLOAT_POS;
133                                 res1 = 0;
134                         }
135 #endif
136                         else if (c >= '1' && c <= '9') {
137                                 if (add_to_res(c - '0', &res1, 10) < 0)
138                                         st = ERROR;
139                                 else
140                                         st = DEC_POS_OK;
141                         }
142                         else  {
143                                 st = ERROR;
144                         }
145                         break;
146
147                 case ZERO_OK:
148                         if (c == 'x') {
149                                 st = HEX;
150                         }
151                         else if (c == 'b') {
152                                 st = BIN;
153                         }
154 #ifndef CMDLINE_NO_FLOAT
155                         else if (c == '.') {
156                                 st = FLOAT_POS;
157                                 res1 = 0;
158                         }
159 #endif
160                         else if (c >= '0' && c <= '7') {
161                                 if (add_to_res(c - '0', &res1, 10) < 0)
162                                         st = ERROR;
163                                 else
164                                         st = OCTAL_OK;
165                         }
166                         else  {
167                                 st = ERROR;
168                         }
169                         break;
170
171                 case DEC_NEG:
172                         if (c >= '0' && c <= '9') {
173                                 if (add_to_res(c - '0', &res1, 10) < 0)
174                                         st = ERROR;
175                                 else
176                                         st = DEC_NEG_OK;
177                         }
178 #ifndef CMDLINE_NO_FLOAT
179                         else if (c == '.') {
180                                 res1 = 0;
181                                 st = FLOAT_NEG;
182                         }
183 #endif
184                         else {
185                                 st = ERROR;
186                         }
187                         break;
188
189                 case DEC_NEG_OK:
190                         if (c >= '0' && c <= '9') {
191                                 if (add_to_res(c - '0', &res1, 10) < 0)
192                                         st = ERROR;
193                         }
194 #ifndef CMDLINE_NO_FLOAT
195                         else if (c == '.') {
196                                 st = FLOAT_NEG;
197                         }
198 #endif
199                         else {
200                                 st = ERROR;
201                         }
202                         break;
203
204                 case DEC_POS_OK:
205                         if (c >= '0' && c <= '9') {
206                                 if (add_to_res(c - '0', &res1, 10) < 0)
207                                         st = ERROR;
208                         }
209 #ifndef CMDLINE_NO_FLOAT
210                         else if (c == '.') {
211                                 st = FLOAT_POS;
212                         }
213 #endif
214                         else {
215                                 st = ERROR;
216                         }
217                         break;
218
219                 case HEX:
220                         st = HEX_OK;
221                         /* no break */
222                 case HEX_OK:
223                         if (c >= '0' && c <= '9') {
224                                 if (add_to_res(c - '0', &res1, 16) < 0)
225                                         st = ERROR;
226                         }
227                         else if (c >= 'a' && c <= 'f') {
228                                 if (add_to_res(c - 'a' + 10, &res1, 16) < 0)
229                                         st = ERROR;
230                         }
231                         else if (c >= 'A' && c <= 'F') {
232                                 if (add_to_res(c - 'A' + 10, &res1, 16) < 0)
233                                         st = ERROR;
234                         }
235                         else {
236                                 st = ERROR;
237                         }
238                         break;
239
240
241                 case OCTAL_OK:
242                         if (c >= '0' && c <= '7') {
243                                 if (add_to_res(c - '0', &res1, 8) < 0)
244                                         st = ERROR;
245                         }
246                         else {
247                                 st = ERROR;
248                         }
249                         break;
250
251                 case BIN:
252                         st = BIN_OK;
253                         /* no break */
254                 case BIN_OK:
255                         if (c >= '0' && c <= '1') {
256                                 if (add_to_res(c - '0', &res1, 2) < 0)
257                                         st = ERROR;
258                         }
259                         else {
260                                 st = ERROR;
261                         }
262                         break;
263
264 #ifndef CMDLINE_NO_FLOAT
265                 case FLOAT_POS:
266                         if (c >= '0' && c <= '9') {
267                                 if (add_to_res(c - '0', &res2, 10) < 0)
268                                         st = ERROR;
269                                 else
270                                         st = FLOAT_POS_OK;
271                                 res3 = 10;
272                         }
273                         else {
274                                 st = ERROR;
275                         }
276                         break;
277
278                 case FLOAT_NEG:
279                         if (c >= '0' && c <= '9') {
280                                 if (add_to_res(c - '0', &res2, 10) < 0)
281                                         st = ERROR;
282                                 else
283                                         st = FLOAT_NEG_OK;
284                                 res3 = 10;
285                         }
286                         else {
287                                 st = ERROR;
288                         }
289                         break;
290
291                 case FLOAT_POS_OK:
292                         if (c >= '0' && c <= '9') {
293                                 if (add_to_res(c - '0', &res2, 10) < 0)
294                                         st = ERROR;
295                                 if (add_to_res(0, &res3, 10) < 0)
296                                         st = ERROR;
297                         }
298                         else {
299                                 st = ERROR;
300                         }
301                         break;
302
303                 case FLOAT_NEG_OK:
304                         if (c >= '0' && c <= '9') {
305                                 if (add_to_res(c - '0', &res2, 10) < 0)
306                                         st = ERROR;
307                                 if (add_to_res(0, &res3, 10) < 0)
308                                         st = ERROR;
309                         }
310                         else {
311                                 st = ERROR;
312                         }
313                         break;
314 #endif
315
316                 default:
317                         debug_printf("not impl ");
318
319                 }
320
321 #ifdef CMDLINE_NO_FLOAT
322                 debug_printf("(%"PRIu32")\n", res1);
323 #else
324                 debug_printf("(%"PRIu32")  (%"PRIu32")  (%"PRIu32")\n",
325                              res1, res2, res3);
326 #endif
327
328                 buf ++;
329                 c = *buf;
330
331                 /* token too long */
332                 if (buf-srcbuf > 127)
333                         return -1;
334         }
335
336         switch (st) {
337         case ZERO_OK:
338         case DEC_POS_OK:
339         case HEX_OK:
340         case OCTAL_OK:
341         case BIN_OK:
342                 if ( nd.type == INT8 && res1 <= S08_MAX ) {
343                         if (res)
344                                 *(int8_t *)res = (int8_t) res1;
345                         return (buf-srcbuf);
346                 }
347                 else if ( nd.type == INT16 && res1 <= S16_MAX ) {
348                         if (res)
349                                 *(int16_t *)res = (int16_t) res1;
350                         return (buf-srcbuf);
351                 }
352                 else if ( nd.type == INT32 && res1 <= S32_MAX ) {
353                         if (res)
354                                 *(int32_t *)res = (int32_t) res1;
355                         return (buf-srcbuf);
356                 }
357                 else if ( nd.type == UINT8 && res1 <= U08_MAX ) {
358                         if (res)
359                                 *(uint8_t *)res = (uint8_t) res1;
360                         return (buf-srcbuf);
361                 }
362                 else if (nd.type == UINT16  && res1 <= U16_MAX ) {
363                         if (res)
364                                 *(uint16_t *)res = (uint16_t) res1;
365                         return (buf-srcbuf);
366                 }
367                 else if ( nd.type == UINT32 ) {
368                         if (res)
369                                 *(uint32_t *)res = (uint32_t) res1;
370                         return (buf-srcbuf);
371                 }
372 #ifndef CMDLINE_NO_FLOAT
373                 else if ( nd.type == FLOAT ) {
374                         if (res)
375                                 *(float *)res = (float)res1;
376                         return (buf-srcbuf);
377                 }
378 #endif
379                 else {
380                         return -1;
381                 }
382                 break;
383
384         case DEC_NEG_OK:
385                 if ( nd.type == INT8 && res1 <= S08_MAX + 1 ) {
386                         if (res)
387                                 *(int8_t *)res = - (int8_t) res1;
388                         return (buf-srcbuf);
389                 }
390                 else if ( nd.type == INT16 && res1 <= (uint16_t)S16_MAX + 1 ) {
391                         if (res)
392                                 *(int16_t *)res = - (int16_t) res1;
393                         return (buf-srcbuf);
394                 }
395                 else if ( nd.type == INT32 && res1 <= (uint32_t)S32_MAX + 1 ) {
396                         if (res)
397                                 *(int32_t *)res = - (int32_t) res1;
398                         return (buf-srcbuf);
399                 }
400 #ifndef CMDLINE_NO_FLOAT
401                 else if ( nd.type == FLOAT ) {
402                         if (res)
403                                 *(float *)res = - (float)res1;
404                         return (buf-srcbuf);
405                 }
406 #endif
407                 else {
408                         return -1;
409                 }
410                 break;
411
412 #ifndef CMDLINE_NO_FLOAT
413         case FLOAT_POS:
414         case FLOAT_POS_OK:
415                 if ( nd.type == FLOAT ) {
416                         if (res)
417                                 *(float *)res = (float)res1 + ((float)res2 / (float)res3);
418                         return (buf-srcbuf);
419
420                 }
421                 else {
422                         return -1;
423                 }
424                 break;
425
426         case FLOAT_NEG:
427         case FLOAT_NEG_OK:
428                 if ( nd.type == FLOAT ) {
429                         if (res)
430                                 *(float *)res = - ((float)res1 + ((float)res2 / (float)res3));
431                         return (buf-srcbuf);
432
433                 }
434                 else {
435                         return -1;
436                 }
437                 break;
438 #endif
439         default:
440                 debug_printf("error\n");
441                 return -1;
442         }
443         return -1;
444 }
445
446
447 /* parse an int or a float */
448 int
449 cmdline_get_help_num(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
450 {
451         struct cmdline_token_num_data nd;
452
453         memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
454
455         /* should not happen.... don't so this test */
456         /* if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */
457         /* return -1; */
458
459         strncpy(dstbuf, num_help[nd.type], size);
460         dstbuf[size-1] = '\0';
461         return 0;
462 }