cmdline: use SPDX tags
[dpdk.git] / lib / librte_cmdline / cmdline_parse_num.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation.
3  * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
4  * All rights reserved.
5  */
6
7 #include <stdio.h>
8 #include <stdint.h>
9 #include <inttypes.h>
10 #include <ctype.h>
11 #include <string.h>
12 #include <stdarg.h>
13 #include <errno.h>
14 #include <rte_string_fns.h>
15
16 #include "cmdline_parse.h"
17 #include "cmdline_parse_num.h"
18
19 #ifdef RTE_LIBRTE_CMDLINE_DEBUG
20 #define debug_printf(args...) printf(args)
21 #else
22 #define debug_printf(args...) do {} while(0)
23 #endif
24
25 struct cmdline_token_ops cmdline_token_num_ops = {
26         .parse = cmdline_parse_num,
27         .complete_get_nb = NULL,
28         .complete_get_elt = NULL,
29         .get_help = cmdline_get_help_num,
30 };
31
32
33 enum num_parse_state_t {
34         START,
35         DEC_NEG,
36         BIN,
37         HEX,
38
39         ERROR,
40
41         FIRST_OK, /* not used */
42         ZERO_OK,
43         HEX_OK,
44         OCTAL_OK,
45         BIN_OK,
46         DEC_NEG_OK,
47         DEC_POS_OK,
48 };
49
50 /* Keep it sync with enum in .h */
51 static const char * num_help[] = {
52         "UINT8", "UINT16", "UINT32", "UINT64",
53         "INT8", "INT16", "INT32", "INT64",
54 };
55
56 static inline int
57 add_to_res(unsigned int c, uint64_t *res, unsigned int base)
58 {
59         /* overflow */
60         if ( (UINT64_MAX - c) / base < *res ) {
61                 return -1;
62         }
63
64         *res = (uint64_t) (*res * base + c);
65         return 0;
66 }
67
68 static int
69 check_res_size(struct cmdline_token_num_data *nd, unsigned ressize)
70 {
71         switch (nd->type) {
72         case INT8:
73         case UINT8:
74                 if (ressize < sizeof(int8_t))
75                         return -1;
76                 break;
77         case INT16:
78         case UINT16:
79                 if (ressize < sizeof(int16_t))
80                         return -1;
81                 break;
82         case INT32:
83         case UINT32:
84                 if (ressize < sizeof(int32_t))
85                         return -1;
86                 break;
87         case INT64:
88         case UINT64:
89                 if (ressize < sizeof(int64_t))
90                         return -1;
91                 break;
92         default:
93                 return -1;
94         }
95         return 0;
96 }
97
98 /* parse an int */
99 int
100 cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res,
101         unsigned ressize)
102 {
103         struct cmdline_token_num_data nd;
104         enum num_parse_state_t st = START;
105         const char * buf;
106         char c;
107         uint64_t res1 = 0;
108
109         if (!tk)
110                 return -1;
111
112         if (!srcbuf || !*srcbuf)
113                 return -1;
114
115         buf = srcbuf;
116         c = *buf;
117
118         memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
119
120         /* check that we have enough room in res */
121         if (res) {
122                 if (check_res_size(&nd, ressize) < 0)
123                         return -1;
124         }
125
126         while ( st != ERROR && c && ! cmdline_isendoftoken(c) ) {
127                 debug_printf("%c %x -> ", c, c);
128                 switch (st) {
129                 case START:
130                         if (c == '-') {
131                                 st = DEC_NEG;
132                         }
133                         else if (c == '0') {
134                                 st = ZERO_OK;
135                         }
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                         else if (c >= '0' && c <= '7') {
155                                 if (add_to_res(c - '0', &res1, 10) < 0)
156                                         st = ERROR;
157                                 else
158                                         st = OCTAL_OK;
159                         }
160                         else  {
161                                 st = ERROR;
162                         }
163                         break;
164
165                 case DEC_NEG:
166                         if (c >= '0' && c <= '9') {
167                                 if (add_to_res(c - '0', &res1, 10) < 0)
168                                         st = ERROR;
169                                 else
170                                         st = DEC_NEG_OK;
171                         }
172                         else {
173                                 st = ERROR;
174                         }
175                         break;
176
177                 case DEC_NEG_OK:
178                         if (c >= '0' && c <= '9') {
179                                 if (add_to_res(c - '0', &res1, 10) < 0)
180                                         st = ERROR;
181                         }
182                         else {
183                                 st = ERROR;
184                         }
185                         break;
186
187                 case DEC_POS_OK:
188                         if (c >= '0' && c <= '9') {
189                                 if (add_to_res(c - '0', &res1, 10) < 0)
190                                         st = ERROR;
191                         }
192                         else {
193                                 st = ERROR;
194                         }
195                         break;
196
197                 case HEX:
198                         st = HEX_OK;
199                         /* fall-through no break */
200                 case HEX_OK:
201                         if (c >= '0' && c <= '9') {
202                                 if (add_to_res(c - '0', &res1, 16) < 0)
203                                         st = ERROR;
204                         }
205                         else if (c >= 'a' && c <= 'f') {
206                                 if (add_to_res(c - 'a' + 10, &res1, 16) < 0)
207                                         st = ERROR;
208                         }
209                         else if (c >= 'A' && c <= 'F') {
210                                 if (add_to_res(c - 'A' + 10, &res1, 16) < 0)
211                                         st = ERROR;
212                         }
213                         else {
214                                 st = ERROR;
215                         }
216                         break;
217
218
219                 case OCTAL_OK:
220                         if (c >= '0' && c <= '7') {
221                                 if (add_to_res(c - '0', &res1, 8) < 0)
222                                         st = ERROR;
223                         }
224                         else {
225                                 st = ERROR;
226                         }
227                         break;
228
229                 case BIN:
230                         st = BIN_OK;
231                         /* fall-through */
232                 case BIN_OK:
233                         if (c >= '0' && c <= '1') {
234                                 if (add_to_res(c - '0', &res1, 2) < 0)
235                                         st = ERROR;
236                         }
237                         else {
238                                 st = ERROR;
239                         }
240                         break;
241                 default:
242                         debug_printf("not impl ");
243
244                 }
245
246                 debug_printf("(%"PRIu64")\n", res1);
247
248                 buf ++;
249                 c = *buf;
250
251                 /* token too long */
252                 if (buf-srcbuf > 127)
253                         return -1;
254         }
255
256         switch (st) {
257         case ZERO_OK:
258         case DEC_POS_OK:
259         case HEX_OK:
260         case OCTAL_OK:
261         case BIN_OK:
262                 if ( nd.type == INT8 && res1 <= INT8_MAX ) {
263                         if (res) *(int8_t *)res = (int8_t) res1;
264                         return buf-srcbuf;
265                 }
266                 else if ( nd.type == INT16 && res1 <= INT16_MAX ) {
267                         if (res) *(int16_t *)res = (int16_t) res1;
268                         return buf-srcbuf;
269                 }
270                 else if ( nd.type == INT32 && res1 <= INT32_MAX ) {
271                         if (res) *(int32_t *)res = (int32_t) res1;
272                         return buf-srcbuf;
273                 }
274                 else if ( nd.type == INT64 && res1 <= INT64_MAX ) {
275                         if (res) *(int64_t *)res = (int64_t) res1;
276                         return buf-srcbuf;
277                 }
278                 else if ( nd.type == UINT8 && res1 <= UINT8_MAX ) {
279                         if (res) *(uint8_t *)res = (uint8_t) res1;
280                         return buf-srcbuf;
281                 }
282                 else if (nd.type == UINT16  && res1 <= UINT16_MAX ) {
283                         if (res) *(uint16_t *)res = (uint16_t) res1;
284                         return buf-srcbuf;
285                 }
286                 else if ( nd.type == UINT32 && res1 <= UINT32_MAX ) {
287                         if (res) *(uint32_t *)res = (uint32_t) res1;
288                         return buf-srcbuf;
289                 }
290                 else if ( nd.type == UINT64 ) {
291                         if (res) *(uint64_t *)res = res1;
292                         return buf-srcbuf;
293                 }
294                 else {
295                         return -1;
296                 }
297                 break;
298
299         case DEC_NEG_OK:
300                 if ( nd.type == INT8 && res1 <= INT8_MAX + 1 ) {
301                         if (res) *(int8_t *)res = (int8_t) (-res1);
302                         return buf-srcbuf;
303                 }
304                 else if ( nd.type == INT16 && res1 <= (uint16_t)INT16_MAX + 1 ) {
305                         if (res) *(int16_t *)res = (int16_t) (-res1);
306                         return buf-srcbuf;
307                 }
308                 else if ( nd.type == INT32 && res1 <= (uint32_t)INT32_MAX + 1 ) {
309                         if (res) *(int32_t *)res = (int32_t) (-res1);
310                         return buf-srcbuf;
311                 }
312                 else if ( nd.type == INT64 && res1 <= (uint64_t)INT64_MAX + 1 ) {
313                         if (res) *(int64_t *)res = (int64_t) (-res1);
314                         return buf-srcbuf;
315                 }
316                 else {
317                         return -1;
318                 }
319                 break;
320         default:
321                 debug_printf("error\n");
322                 return -1;
323         }
324 }
325
326
327 /* parse an int */
328 int
329 cmdline_get_help_num(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
330 {
331         struct cmdline_token_num_data nd;
332         int ret;
333
334         if (!tk)
335                 return -1;
336
337         memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
338
339         /* should not happen.... don't so this test */
340         /* if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */
341         /* return -1; */
342
343         ret = snprintf(dstbuf, size, "%s", num_help[nd.type]);
344         if (ret < 0)
345                 return -1;
346         dstbuf[size-1] = '\0';
347         return 0;
348 }