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