1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2010-2014 Intel Corporation.
3 * Copyright (c) 2009, Olivier MATZ <[email protected]>
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
add_to_res(unsigned int c,uint64_t * res,unsigned int base)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 *res = (uint64_t) (*res * base + c);
64 return 0;
65 }
66
67 static int
check_res_size(struct cmdline_token_num_data * nd,unsigned ressize)68 check_res_size(struct cmdline_token_num_data *nd, unsigned ressize)
69 {
70 switch (nd->type) {
71 case RTE_INT8:
72 case RTE_UINT8:
73 if (ressize < sizeof(int8_t))
74 return -1;
75 break;
76 case RTE_INT16:
77 case RTE_UINT16:
78 if (ressize < sizeof(int16_t))
79 return -1;
80 break;
81 case RTE_INT32:
82 case RTE_UINT32:
83 if (ressize < sizeof(int32_t))
84 return -1;
85 break;
86 case RTE_INT64:
87 case RTE_UINT64:
88 if (ressize < sizeof(int64_t))
89 return -1;
90 break;
91 default:
92 return -1;
93 }
94 return 0;
95 }
96
97 /* parse an int */
98 int
cmdline_parse_num(cmdline_parse_token_hdr_t * tk,const char * srcbuf,void * res,unsigned ressize)99 cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res,
100 unsigned ressize)
101 {
102 struct cmdline_token_num_data nd;
103 enum num_parse_state_t st = START;
104 const char * buf;
105 char c;
106 uint64_t res1 = 0;
107
108 if (!tk)
109 return -1;
110
111 if (!srcbuf || !*srcbuf)
112 return -1;
113
114 buf = srcbuf;
115 c = *buf;
116
117 memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
118
119 /* check that we have enough room in res */
120 if (res) {
121 if (check_res_size(&nd, ressize) < 0)
122 return -1;
123 }
124
125 while (st != ERROR && c && !cmdline_isendoftoken(c)) {
126 debug_printf("%c %x -> ", c, c);
127 switch (st) {
128 case START:
129 if (c == '-') {
130 st = DEC_NEG;
131 }
132 else if (c == '0') {
133 st = ZERO_OK;
134 }
135 else if (c >= '1' && c <= '9') {
136 if (add_to_res(c - '0', &res1, 10) < 0)
137 st = ERROR;
138 else
139 st = DEC_POS_OK;
140 }
141 else {
142 st = ERROR;
143 }
144 break;
145
146 case ZERO_OK:
147 if (c == 'x') {
148 st = HEX;
149 }
150 else if (c == 'b') {
151 st = BIN;
152 }
153 else if (c >= '0' && c <= '7') {
154 if (add_to_res(c - '0', &res1, 10) < 0)
155 st = ERROR;
156 else
157 st = OCTAL_OK;
158 }
159 else {
160 st = ERROR;
161 }
162 break;
163
164 case DEC_NEG:
165 if (c >= '0' && c <= '9') {
166 if (add_to_res(c - '0', &res1, 10) < 0)
167 st = ERROR;
168 else
169 st = DEC_NEG_OK;
170 }
171 else {
172 st = ERROR;
173 }
174 break;
175
176 case DEC_NEG_OK:
177 if (c >= '0' && c <= '9') {
178 if (add_to_res(c - '0', &res1, 10) < 0)
179 st = ERROR;
180 }
181 else {
182 st = ERROR;
183 }
184 break;
185
186 case DEC_POS_OK:
187 if (c >= '0' && c <= '9') {
188 if (add_to_res(c - '0', &res1, 10) < 0)
189 st = ERROR;
190 }
191 else {
192 st = ERROR;
193 }
194 break;
195
196 case HEX:
197 st = HEX_OK;
198 /* fall-through */
199 case HEX_OK:
200 if (c >= '0' && c <= '9') {
201 if (add_to_res(c - '0', &res1, 16) < 0)
202 st = ERROR;
203 }
204 else if (c >= 'a' && c <= 'f') {
205 if (add_to_res(c - 'a' + 10, &res1, 16) < 0)
206 st = ERROR;
207 }
208 else if (c >= 'A' && c <= 'F') {
209 if (add_to_res(c - 'A' + 10, &res1, 16) < 0)
210 st = ERROR;
211 }
212 else {
213 st = ERROR;
214 }
215 break;
216
217
218 case OCTAL_OK:
219 if (c >= '0' && c <= '7') {
220 if (add_to_res(c - '0', &res1, 8) < 0)
221 st = ERROR;
222 }
223 else {
224 st = ERROR;
225 }
226 break;
227
228 case BIN:
229 st = BIN_OK;
230 /* fall-through */
231 case BIN_OK:
232 if (c >= '0' && c <= '1') {
233 if (add_to_res(c - '0', &res1, 2) < 0)
234 st = ERROR;
235 }
236 else {
237 st = ERROR;
238 }
239 break;
240 default:
241 debug_printf("not impl ");
242
243 }
244
245 debug_printf("(%"PRIu64")\n", res1);
246
247 buf ++;
248 c = *buf;
249
250 /* token too long */
251 if (buf-srcbuf > 127)
252 return -1;
253 }
254
255 switch (st) {
256 case ZERO_OK:
257 case DEC_POS_OK:
258 case HEX_OK:
259 case OCTAL_OK:
260 case BIN_OK:
261 if (nd.type == RTE_INT8 && res1 <= INT8_MAX) {
262 if (res) *(int8_t *)res = (int8_t) res1;
263 return buf-srcbuf;
264 } else if (nd.type == RTE_INT16 && res1 <= INT16_MAX) {
265 if (res) *(int16_t *)res = (int16_t) res1;
266 return buf-srcbuf;
267 } else if (nd.type == RTE_INT32 && res1 <= INT32_MAX) {
268 if (res) *(int32_t *)res = (int32_t) res1;
269 return buf-srcbuf;
270 } else if (nd.type == RTE_INT64 && res1 <= INT64_MAX) {
271 if (res) *(int64_t *)res = (int64_t) res1;
272 return buf-srcbuf;
273 } else if (nd.type == RTE_UINT8 && res1 <= UINT8_MAX) {
274 if (res) *(uint8_t *)res = (uint8_t) res1;
275 return buf-srcbuf;
276 } else if (nd.type == RTE_UINT16 && res1 <= UINT16_MAX) {
277 if (res) *(uint16_t *)res = (uint16_t) res1;
278 return buf-srcbuf;
279 } else if (nd.type == RTE_UINT32 && res1 <= UINT32_MAX) {
280 if (res) *(uint32_t *)res = (uint32_t) res1;
281 return buf-srcbuf;
282 } else if (nd.type == RTE_UINT64) {
283 if (res) *(uint64_t *)res = res1;
284 return buf-srcbuf;
285 } else {
286 return -1;
287 }
288 break;
289
290 case DEC_NEG_OK:
291 if (nd.type == RTE_INT8 &&
292 res1 <= INT8_MAX + 1) {
293 if (res) *(int8_t *)res = (int8_t) (-res1);
294 return buf-srcbuf;
295 } else if (nd.type == RTE_INT16 &&
296 res1 <= (uint16_t)INT16_MAX + 1) {
297 if (res) *(int16_t *)res = (int16_t) (-res1);
298 return buf-srcbuf;
299 } else if (nd.type == RTE_INT32 &&
300 res1 <= (uint32_t)INT32_MAX + 1) {
301 if (res) *(int32_t *)res = (int32_t) (-res1);
302 return buf-srcbuf;
303 } else if (nd.type == RTE_INT64 &&
304 res1 <= (uint64_t)INT64_MAX + 1) {
305 if (res) *(int64_t *)res = (int64_t) (-res1);
306 return buf-srcbuf;
307 } else {
308 return -1;
309 }
310 break;
311 default:
312 debug_printf("error\n");
313 return -1;
314 }
315 }
316
317
318 /* parse an int */
319 int
cmdline_get_help_num(cmdline_parse_token_hdr_t * tk,char * dstbuf,unsigned int size)320 cmdline_get_help_num(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
321 {
322 struct cmdline_token_num_data nd;
323 int ret;
324
325 if (!tk)
326 return -1;
327
328 memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
329
330 /* should not happen.... don't so this test */
331 /* if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */
332 /* return -1; */
333
334 ret = strlcpy(dstbuf, num_help[nd.type], size);
335 if (ret < 0)
336 return -1;
337 dstbuf[size-1] = '\0';
338 return 0;
339 }
340