update copyright date to 2013
[dpdk.git] / lib / librte_cmdline / cmdline_parse_num.c
1 /*-
2  *   BSD LICENSE
3  * 
4  *   Copyright(c) 2010-2013 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  */
34
35 /*
36  * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
37  * All rights reserved.
38  * Redistribution and use in source and binary forms, with or without
39  * modification, are permitted provided that the following conditions are met:
40  *
41  *     * Redistributions of source code must retain the above copyright
42  *       notice, this list of conditions and the following disclaimer.
43  *     * Redistributions in binary form must reproduce the above copyright
44  *       notice, this list of conditions and the following disclaimer in the
45  *       documentation and/or other materials provided with the distribution.
46  *     * Neither the name of the University of California, Berkeley nor the
47  *       names of its contributors may be used to endorse or promote products
48  *       derived from this software without specific prior written permission.
49  *
50  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
51  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
52  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
53  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
54  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
55  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
56  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
57  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
59  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60  */
61
62 #include <stdio.h>
63 #include <stdint.h>
64 #include <inttypes.h>
65 #include <ctype.h>
66 #include <string.h>
67 #include <stdarg.h>
68 #include <errno.h>
69 #include <rte_string_fns.h>
70
71 #include "cmdline_parse.h"
72 #include "cmdline_parse_num.h"
73
74 #ifdef RTE_LIBRTE_CMDLINE_DEBUG
75 #define debug_printf(args...) printf(args)
76 #else
77 #define debug_printf(args...) do {} while(0)
78 #endif
79
80 struct cmdline_token_ops cmdline_token_num_ops = {
81         .parse = cmdline_parse_num,
82         .complete_get_nb = NULL,
83         .complete_get_elt = NULL,
84         .get_help = cmdline_get_help_num,
85 };
86
87
88 enum num_parse_state_t {
89         START,
90         DEC_NEG,
91         BIN,
92         HEX,
93
94         ERROR,
95
96         FIRST_OK, /* not used */
97         ZERO_OK,
98         HEX_OK,
99         OCTAL_OK,
100         BIN_OK,
101         DEC_NEG_OK,
102         DEC_POS_OK,
103 };
104
105 /* Keep it sync with enum in .h */
106 static const char * num_help[] = {
107         "UINT8", "UINT16", "UINT32", "UINT64",
108         "INT8", "INT16", "INT32", "INT64",
109 };
110
111 static inline int
112 add_to_res(unsigned int c, uint64_t *res, unsigned int base)
113 {
114         /* overflow */
115         if ( (UINT64_MAX - c) / base < *res ) {
116                 return -1;
117         }
118
119         *res = (uint64_t) (*res * base + c);
120         return 0;
121 }
122
123
124 /* parse an int */
125 int
126 cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res)
127 {
128         struct cmdline_token_num_data nd;
129         enum num_parse_state_t st = START;
130         const char * buf;
131         char c;
132         uint64_t res1 = 0;
133
134         if (!tk)
135                 return -1;
136
137         if (!srcbuf || !*srcbuf)
138                 return -1;
139
140         buf = srcbuf;
141         c = *buf;
142
143         memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
144
145         while ( st != ERROR && c && ! cmdline_isendoftoken(c) ) {
146                 debug_printf("%c %x -> ", c, c);
147                 switch (st) {
148                 case START:
149                         if (c == '-') {
150                                 st = DEC_NEG;
151                         }
152                         else if (c == '0') {
153                                 st = ZERO_OK;
154                         }
155                         else if (c >= '1' && c <= '9') {
156                                 if (add_to_res(c - '0', &res1, 10) < 0)
157                                         st = ERROR;
158                                 else
159                                         st = DEC_POS_OK;
160                         }
161                         else  {
162                                 st = ERROR;
163                         }
164                         break;
165
166                 case ZERO_OK:
167                         if (c == 'x') {
168                                 st = HEX;
169                         }
170                         else if (c == 'b') {
171                                 st = BIN;
172                         }
173                         else if (c >= '0' && c <= '7') {
174                                 if (add_to_res(c - '0', &res1, 10) < 0)
175                                         st = ERROR;
176                                 else
177                                         st = OCTAL_OK;
178                         }
179                         else  {
180                                 st = ERROR;
181                         }
182                         break;
183
184                 case DEC_NEG:
185                         if (c >= '0' && c <= '9') {
186                                 if (add_to_res(c - '0', &res1, 10) < 0)
187                                         st = ERROR;
188                                 else
189                                         st = DEC_NEG_OK;
190                         }
191                         else {
192                                 st = ERROR;
193                         }
194                         break;
195
196                 case DEC_NEG_OK:
197                         if (c >= '0' && c <= '9') {
198                                 if (add_to_res(c - '0', &res1, 10) < 0)
199                                         st = ERROR;
200                         }
201                         else {
202                                 st = ERROR;
203                         }
204                         break;
205
206                 case DEC_POS_OK:
207                         if (c >= '0' && c <= '9') {
208                                 if (add_to_res(c - '0', &res1, 10) < 0)
209                                         st = ERROR;
210                         }
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                 default:
261                         debug_printf("not impl ");
262
263                 }
264
265                 debug_printf("(%"PRIu64")\n", res1);
266
267                 buf ++;
268                 c = *buf;
269
270                 /* token too long */
271                 if (buf-srcbuf > 127)
272                         return -1;
273         }
274
275         switch (st) {
276         case ZERO_OK:
277         case DEC_POS_OK:
278         case HEX_OK:
279         case OCTAL_OK:
280         case BIN_OK:
281                 if ( nd.type == INT8 && res1 <= INT8_MAX ) {
282                         if (res) *(int8_t *)res = (int8_t) res1;
283                         return (buf-srcbuf);
284                 }
285                 else if ( nd.type == INT16 && res1 <= INT16_MAX ) {
286                         if (res) *(int16_t *)res = (int16_t) res1;
287                         return (buf-srcbuf);
288                 }
289                 else if ( nd.type == INT32 && res1 <= INT32_MAX ) {
290                         if (res) *(int32_t *)res = (int32_t) res1;
291                         return (buf-srcbuf);
292                 }
293                 else if ( nd.type == INT64 && res1 <= INT64_MAX ) {
294                         if (res) *(int64_t *)res = (int64_t) res1;
295                         return (buf-srcbuf);
296                 }
297                 else if ( nd.type == UINT8 && res1 <= UINT8_MAX ) {
298                         if (res) *(uint8_t *)res = (uint8_t) res1;
299                         return (buf-srcbuf);
300                 }
301                 else if (nd.type == UINT16  && res1 <= UINT16_MAX ) {
302                         if (res) *(uint16_t *)res = (uint16_t) res1;
303                         return (buf-srcbuf);
304                 }
305                 else if ( nd.type == UINT32 && res1 <= UINT32_MAX ) {
306                         if (res) *(uint32_t *)res = (uint32_t) res1;
307                         return (buf-srcbuf);
308                 }
309                 else if ( nd.type == UINT64 ) {
310                         if (res) *(uint64_t *)res = res1;
311                         return (buf-srcbuf);
312                 }
313                 else {
314                         return -1;
315                 }
316                 break;
317
318         case DEC_NEG_OK:
319                 if ( nd.type == INT8 && res1 <= INT8_MAX + 1 ) {
320                         if (res) *(int8_t *)res = (int8_t) (-res1);
321                         return (buf-srcbuf);
322                 }
323                 else if ( nd.type == INT16 && res1 <= (uint16_t)INT16_MAX + 1 ) {
324                         if (res) *(int16_t *)res = (int16_t) (-res1);
325                         return (buf-srcbuf);
326                 }
327                 else if ( nd.type == INT32 && res1 <= (uint32_t)INT32_MAX + 1 ) {
328                         if (res) *(int32_t *)res = (int32_t) (-res1);
329                         return (buf-srcbuf);
330                 }
331                 else if ( nd.type == INT64 && res1 <= (uint64_t)INT64_MAX + 1 ) {
332                         if (res) *(int64_t *)res = (int64_t) (-res1);
333                         return (buf-srcbuf);
334                 }
335                 else {
336                         return -1;
337                 }
338                 break;
339         default:
340                 debug_printf("error\n");
341                 return -1;
342         }
343 }
344
345
346 /* parse an int */
347 int
348 cmdline_get_help_num(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
349 {
350         struct cmdline_token_num_data nd;
351         int ret;
352
353         if (!tk)
354                 return -1;
355
356         memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
357
358         /* should not happen.... don't so this test */
359         /* if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */
360         /* return -1; */
361
362         ret = rte_snprintf(dstbuf, size, "%s", num_help[nd.type]);
363         if (ret < 0)
364                 return -1;
365         dstbuf[size-1] = '\0';
366         return 0;
367 }