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