xref: /dpdk/lib/cmdline/cmdline_parse_num.c (revision daa02b5cddbb8e11b31d41e2bf7bb1ae64dcae2f)
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 	*res = (uint64_t) (*res * base + c);
64 	return 0;
65 }
66 
67 static int
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
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
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