cmdline (merge-intel): fix whitespaces
[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 NO_PARSE_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, res2=0, res3=1;
114
115         memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
116
117         while ( st != ERROR && c && ! cmdline_isendoftoken(c) ) {
118                 debug_printf("%c %x -> ", c, c);
119                 switch (st) {
120                 case START:
121                         if (c == '-') {
122                                 st = DEC_NEG;
123                         }
124                         else if (c == '0') {
125                                 st = ZERO_OK;
126                         }
127 #ifndef NO_PARSE_FLOAT
128                         else if (c == '.') {
129                                 st = FLOAT_POS;
130                                 res1 = 0;
131                         }
132 #endif
133                         else if (c >= '1' && c <= '9') {
134                                 if (add_to_res(c - '0', &res1, 10) < 0)
135                                         st = ERROR;
136                                 else
137                                         st = DEC_POS_OK;
138                         }
139                         else  {
140                                 st = ERROR;
141                         }
142                         break;
143
144                 case ZERO_OK:
145                         if (c == 'x') {
146                                 st = HEX;
147                         }
148                         else if (c == 'b') {
149                                 st = BIN;
150                         }
151 #ifndef NO_PARSE_FLOAT
152                         else if (c == '.') {
153                                 st = FLOAT_POS;
154                                 res1 = 0;
155                         }
156 #endif
157                         else if (c >= '0' && c <= '7') {
158                                 if (add_to_res(c - '0', &res1, 10) < 0)
159                                         st = ERROR;
160                                 else
161                                         st = OCTAL_OK;
162                         }
163                         else  {
164                                 st = ERROR;
165                         }
166                         break;
167
168                 case DEC_NEG:
169                         if (c >= '0' && c <= '9') {
170                                 if (add_to_res(c - '0', &res1, 10) < 0)
171                                         st = ERROR;
172                                 else
173                                         st = DEC_NEG_OK;
174                         }
175 #ifndef NO_PARSE_FLOAT
176                         else if (c == '.') {
177                                 res1 = 0;
178                                 st = FLOAT_NEG;
179                         }
180 #endif
181                         else {
182                                 st = ERROR;
183                         }
184                         break;
185
186                 case DEC_NEG_OK:
187                         if (c >= '0' && c <= '9') {
188                                 if (add_to_res(c - '0', &res1, 10) < 0)
189                                         st = ERROR;
190                         }
191 #ifndef NO_PARSE_FLOAT
192                         else if (c == '.') {
193                                 st = FLOAT_NEG;
194                         }
195 #endif
196                         else {
197                                 st = ERROR;
198                         }
199                         break;
200
201                 case DEC_POS_OK:
202                         if (c >= '0' && c <= '9') {
203                                 if (add_to_res(c - '0', &res1, 10) < 0)
204                                         st = ERROR;
205                         }
206 #ifndef NO_PARSE_FLOAT
207                         else if (c == '.') {
208                                 st = FLOAT_POS;
209                         }
210 #endif
211                         else {
212                                 st = ERROR;
213                         }
214                         break;
215
216                 case HEX:
217                         st = HEX_OK;
218                         /* no break */
219                 case HEX_OK:
220                         if (c >= '0' && c <= '9') {
221                                 if (add_to_res(c - '0', &res1, 16) < 0)
222                                         st = ERROR;
223                         }
224                         else if (c >= 'a' && c <= 'f') {
225                                 if (add_to_res(c - 'a' + 10, &res1, 16) < 0)
226                                         st = ERROR;
227                         }
228                         else if (c >= 'A' && c <= 'F') {
229                                 if (add_to_res(c - 'A' + 10, &res1, 16) < 0)
230                                         st = ERROR;
231                         }
232                         else {
233                                 st = ERROR;
234                         }
235                         break;
236
237
238                 case OCTAL_OK:
239                         if (c >= '0' && c <= '7') {
240                                 if (add_to_res(c - '0', &res1, 8) < 0)
241                                         st = ERROR;
242                         }
243                         else {
244                                 st = ERROR;
245                         }
246                         break;
247
248                 case BIN:
249                         st = BIN_OK;
250                         /* no break */
251                 case BIN_OK:
252                         if (c >= '0' && c <= '1') {
253                                 if (add_to_res(c - '0', &res1, 2) < 0)
254                                         st = ERROR;
255                         }
256                         else {
257                                 st = ERROR;
258                         }
259                         break;
260
261 #ifndef NO_PARSE_FLOAT
262                 case FLOAT_POS:
263                         if (c >= '0' && c <= '9') {
264                                 if (add_to_res(c - '0', &res2, 10) < 0)
265                                         st = ERROR;
266                                 else
267                                         st = FLOAT_POS_OK;
268                                 res3 = 10;
269                         }
270                         else {
271                                 st = ERROR;
272                         }
273                         break;
274
275                 case FLOAT_NEG:
276                         if (c >= '0' && c <= '9') {
277                                 if (add_to_res(c - '0', &res2, 10) < 0)
278                                         st = ERROR;
279                                 else
280                                         st = FLOAT_NEG_OK;
281                                 res3 = 10;
282                         }
283                         else {
284                                 st = ERROR;
285                         }
286                         break;
287
288                 case FLOAT_POS_OK:
289                         if (c >= '0' && c <= '9') {
290                                 if (add_to_res(c - '0', &res2, 10) < 0)
291                                         st = ERROR;
292                                 if (add_to_res(0, &res3, 10) < 0)
293                                         st = ERROR;
294                         }
295                         else {
296                                 st = ERROR;
297                         }
298                         break;
299
300                 case FLOAT_NEG_OK:
301                         if (c >= '0' && c <= '9') {
302                                 if (add_to_res(c - '0', &res2, 10) < 0)
303                                         st = ERROR;
304                                 if (add_to_res(0, &res3, 10) < 0)
305                                         st = ERROR;
306                         }
307                         else {
308                                 st = ERROR;
309                         }
310                         break;
311 #endif
312
313                 default:
314                         debug_printf("not impl ");
315
316                 }
317
318                 /* XXX uint32_t et %d */
319                 debug_printf("(%d)  (%d)  (%d)\n", res1, res2, res3);
320
321                 buf ++;
322                 c = *buf;
323
324                 /* token too long */
325                 if (buf-srcbuf > 127)
326                         return -1;
327         }
328
329         switch (st) {
330         case ZERO_OK:
331         case DEC_POS_OK:
332         case HEX_OK:
333         case OCTAL_OK:
334         case BIN_OK:
335                 if ( nd.type == INT8 && res1 <= S08_MAX ) {
336                         if (res)
337                                 *(int8_t *)res = (int8_t) res1;
338                         return (buf-srcbuf);
339                 }
340                 else if ( nd.type == INT16 && res1 <= S16_MAX ) {
341                         if (res)
342                                 *(int16_t *)res = (int16_t) res1;
343                         return (buf-srcbuf);
344                 }
345                 else if ( nd.type == INT32 && res1 <= S32_MAX ) {
346                         if (res)
347                                 *(int32_t *)res = (int32_t) res1;
348                         return (buf-srcbuf);
349                 }
350                 else if ( nd.type == UINT8 && res1 <= U08_MAX ) {
351                         if (res)
352                                 *(uint8_t *)res = (uint8_t) res1;
353                         return (buf-srcbuf);
354                 }
355                 else if (nd.type == UINT16  && res1 <= U16_MAX ) {
356                         if (res)
357                                 *(uint16_t *)res = (uint16_t) res1;
358                         return (buf-srcbuf);
359                 }
360                 else if ( nd.type == UINT32 ) {
361                         if (res)
362                                 *(uint32_t *)res = (uint32_t) res1;
363                         return (buf-srcbuf);
364                 }
365 #ifndef NO_PARSE_FLOAT
366                 else if ( nd.type == FLOAT ) {
367                         if (res)
368                                 *(float *)res = (float)res1;
369                         return (buf-srcbuf);
370                 }
371 #endif
372                 else {
373                         return -1;
374                 }
375                 break;
376
377         case DEC_NEG_OK:
378                 if ( nd.type == INT8 && res1 <= S08_MAX + 1 ) {
379                         if (res)
380                                 *(int8_t *)res = - (int8_t) res1;
381                         return (buf-srcbuf);
382                 }
383                 else if ( nd.type == INT16 && res1 <= (uint16_t)S16_MAX + 1 ) {
384                         if (res)
385                                 *(int16_t *)res = - (int16_t) res1;
386                         return (buf-srcbuf);
387                 }
388                 else if ( nd.type == INT32 && res1 <= (uint32_t)S32_MAX + 1 ) {
389                         if (res)
390                                 *(int32_t *)res = - (int32_t) res1;
391                         return (buf-srcbuf);
392                 }
393 #ifndef NO_PARSE_FLOAT
394                 else if ( nd.type == FLOAT ) {
395                         if (res)
396                                 *(float *)res = - (float)res1;
397                         return (buf-srcbuf);
398                 }
399 #endif
400                 else {
401                         return -1;
402                 }
403                 break;
404
405 #ifndef NO_PARSE_FLOAT
406         case FLOAT_POS:
407         case FLOAT_POS_OK:
408                 if ( nd.type == FLOAT ) {
409                         if (res)
410                                 *(float *)res = (float)res1 + ((float)res2 / (float)res3);
411                         return (buf-srcbuf);
412
413                 }
414                 else {
415                         return -1;
416                 }
417                 break;
418
419         case FLOAT_NEG:
420         case FLOAT_NEG_OK:
421                 if ( nd.type == FLOAT ) {
422                         if (res)
423                                 *(float *)res = - ((float)res1 + ((float)res2 / (float)res3));
424                         return (buf-srcbuf);
425
426                 }
427                 else {
428                         return -1;
429                 }
430                 break;
431 #endif
432         default:
433                 debug_printf("error\n");
434                 return -1;
435         }
436         return -1;
437 }
438
439
440 /* parse an int or a float */
441 int
442 cmdline_get_help_num(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
443 {
444         struct cmdline_token_num_data nd;
445
446         memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
447
448         /* should not happen.... don't so this test */
449 /*      if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */
450 /*              return -1; */
451
452         strncpy(dstbuf, num_help[nd.type], size);
453         dstbuf[size-1] = '\0';
454         return 0;
455 }