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