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