xref: /dpdk/lib/cmdline/cmdline_parse_num.c (revision 0f1dc8cb671203d52488fd66936f2fe6dcca03cc)
199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation.
399a2dd95SBruce Richardson  * Copyright (c) 2009, Olivier MATZ <zer0@droids-corp.org>
499a2dd95SBruce Richardson  * All rights reserved.
599a2dd95SBruce Richardson  */
699a2dd95SBruce Richardson 
799a2dd95SBruce Richardson #include <stdio.h>
899a2dd95SBruce Richardson #include <stdint.h>
999a2dd95SBruce Richardson #include <inttypes.h>
1099a2dd95SBruce Richardson #include <string.h>
1199a2dd95SBruce Richardson #include <rte_string_fns.h>
1299a2dd95SBruce Richardson 
1399a2dd95SBruce Richardson #include "cmdline_parse.h"
1499a2dd95SBruce Richardson #include "cmdline_parse_num.h"
1599a2dd95SBruce Richardson 
1699a2dd95SBruce Richardson #ifdef RTE_LIBRTE_CMDLINE_DEBUG
17*0f1dc8cbSTyler Retzlaff #define debug_printf(...) printf(__VA_ARGS__)
1899a2dd95SBruce Richardson #else
19*0f1dc8cbSTyler Retzlaff #define debug_printf(...) do {} while (0)
2099a2dd95SBruce Richardson #endif
2199a2dd95SBruce Richardson 
2299a2dd95SBruce Richardson struct cmdline_token_ops cmdline_token_num_ops = {
2399a2dd95SBruce Richardson 	.parse = cmdline_parse_num,
2499a2dd95SBruce Richardson 	.complete_get_nb = NULL,
2599a2dd95SBruce Richardson 	.complete_get_elt = NULL,
2699a2dd95SBruce Richardson 	.get_help = cmdline_get_help_num,
2799a2dd95SBruce Richardson };
2899a2dd95SBruce Richardson 
2999a2dd95SBruce Richardson 
3099a2dd95SBruce Richardson enum num_parse_state_t {
3199a2dd95SBruce Richardson 	START,
3299a2dd95SBruce Richardson 	DEC_NEG,
3399a2dd95SBruce Richardson 	BIN,
3499a2dd95SBruce Richardson 	HEX,
3599a2dd95SBruce Richardson 
3699a2dd95SBruce Richardson 	ERROR,
3799a2dd95SBruce Richardson 
3899a2dd95SBruce Richardson 	FIRST_OK, /* not used */
3999a2dd95SBruce Richardson 	ZERO_OK,
4099a2dd95SBruce Richardson 	HEX_OK,
4199a2dd95SBruce Richardson 	OCTAL_OK,
4299a2dd95SBruce Richardson 	BIN_OK,
4399a2dd95SBruce Richardson 	DEC_NEG_OK,
4499a2dd95SBruce Richardson 	DEC_POS_OK,
4599a2dd95SBruce Richardson };
4699a2dd95SBruce Richardson 
4799a2dd95SBruce Richardson /* Keep it sync with enum in .h */
4899a2dd95SBruce Richardson static const char * num_help[] = {
4999a2dd95SBruce Richardson 	"UINT8", "UINT16", "UINT32", "UINT64",
5099a2dd95SBruce Richardson 	"INT8", "INT16", "INT32", "INT64",
5199a2dd95SBruce Richardson };
5299a2dd95SBruce Richardson 
5399a2dd95SBruce Richardson static inline int
add_to_res(unsigned int c,uint64_t * res,unsigned int base)5499a2dd95SBruce Richardson add_to_res(unsigned int c, uint64_t *res, unsigned int base)
5599a2dd95SBruce Richardson {
5699a2dd95SBruce Richardson 	/* overflow */
5799a2dd95SBruce Richardson 	if ((UINT64_MAX - c) / base < *res)
5899a2dd95SBruce Richardson 		return -1;
5999a2dd95SBruce Richardson 
6099a2dd95SBruce Richardson 	*res = (uint64_t) (*res * base + c);
6199a2dd95SBruce Richardson 	return 0;
6299a2dd95SBruce Richardson }
6399a2dd95SBruce Richardson 
6499a2dd95SBruce Richardson static int
check_res_size(struct cmdline_token_num_data * nd,unsigned ressize)6599a2dd95SBruce Richardson check_res_size(struct cmdline_token_num_data *nd, unsigned ressize)
6699a2dd95SBruce Richardson {
6799a2dd95SBruce Richardson 	switch (nd->type) {
6899a2dd95SBruce Richardson 	case RTE_INT8:
6999a2dd95SBruce Richardson 	case RTE_UINT8:
7099a2dd95SBruce Richardson 		if (ressize < sizeof(int8_t))
7199a2dd95SBruce Richardson 			return -1;
7299a2dd95SBruce Richardson 		break;
7399a2dd95SBruce Richardson 	case RTE_INT16:
7499a2dd95SBruce Richardson 	case RTE_UINT16:
7599a2dd95SBruce Richardson 		if (ressize < sizeof(int16_t))
7699a2dd95SBruce Richardson 			return -1;
7799a2dd95SBruce Richardson 		break;
7899a2dd95SBruce Richardson 	case RTE_INT32:
7999a2dd95SBruce Richardson 	case RTE_UINT32:
8099a2dd95SBruce Richardson 		if (ressize < sizeof(int32_t))
8199a2dd95SBruce Richardson 			return -1;
8299a2dd95SBruce Richardson 		break;
8399a2dd95SBruce Richardson 	case RTE_INT64:
8499a2dd95SBruce Richardson 	case RTE_UINT64:
8599a2dd95SBruce Richardson 		if (ressize < sizeof(int64_t))
8699a2dd95SBruce Richardson 			return -1;
8799a2dd95SBruce Richardson 		break;
8899a2dd95SBruce Richardson 	default:
8999a2dd95SBruce Richardson 		return -1;
9099a2dd95SBruce Richardson 	}
9199a2dd95SBruce Richardson 	return 0;
9299a2dd95SBruce Richardson }
9399a2dd95SBruce Richardson 
9499a2dd95SBruce Richardson /* parse an int */
9599a2dd95SBruce Richardson int
cmdline_parse_num(cmdline_parse_token_hdr_t * tk,const char * srcbuf,void * res,unsigned ressize)9699a2dd95SBruce Richardson cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res,
9799a2dd95SBruce Richardson 	unsigned ressize)
9899a2dd95SBruce Richardson {
9999a2dd95SBruce Richardson 	struct cmdline_token_num_data nd;
10099a2dd95SBruce Richardson 	enum num_parse_state_t st = START;
10199a2dd95SBruce Richardson 	const char * buf;
10299a2dd95SBruce Richardson 	char c;
10399a2dd95SBruce Richardson 	uint64_t res1 = 0;
10499a2dd95SBruce Richardson 
10599a2dd95SBruce Richardson 	if (!tk)
10699a2dd95SBruce Richardson 		return -1;
10799a2dd95SBruce Richardson 
10899a2dd95SBruce Richardson 	if (!srcbuf || !*srcbuf)
10999a2dd95SBruce Richardson 		return -1;
11099a2dd95SBruce Richardson 
11199a2dd95SBruce Richardson 	buf = srcbuf;
11299a2dd95SBruce Richardson 	c = *buf;
11399a2dd95SBruce Richardson 
11499a2dd95SBruce Richardson 	memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
11599a2dd95SBruce Richardson 
11699a2dd95SBruce Richardson 	/* check that we have enough room in res */
11799a2dd95SBruce Richardson 	if (res) {
11899a2dd95SBruce Richardson 		if (check_res_size(&nd, ressize) < 0)
11999a2dd95SBruce Richardson 			return -1;
12099a2dd95SBruce Richardson 	}
12199a2dd95SBruce Richardson 
12299a2dd95SBruce Richardson 	while (st != ERROR && c && !cmdline_isendoftoken(c)) {
12399a2dd95SBruce Richardson 		debug_printf("%c %x -> ", c, c);
12499a2dd95SBruce Richardson 		switch (st) {
12599a2dd95SBruce Richardson 		case START:
12699a2dd95SBruce Richardson 			if (c == '-') {
12799a2dd95SBruce Richardson 				st = DEC_NEG;
12899a2dd95SBruce Richardson 			}
12999a2dd95SBruce Richardson 			else if (c == '0') {
13099a2dd95SBruce Richardson 				st = ZERO_OK;
13199a2dd95SBruce Richardson 			}
13299a2dd95SBruce Richardson 			else if (c >= '1' && c <= '9') {
13399a2dd95SBruce Richardson 				if (add_to_res(c - '0', &res1, 10) < 0)
13499a2dd95SBruce Richardson 					st = ERROR;
13599a2dd95SBruce Richardson 				else
13699a2dd95SBruce Richardson 					st = DEC_POS_OK;
13799a2dd95SBruce Richardson 			}
13899a2dd95SBruce Richardson 			else  {
13999a2dd95SBruce Richardson 				st = ERROR;
14099a2dd95SBruce Richardson 			}
14199a2dd95SBruce Richardson 			break;
14299a2dd95SBruce Richardson 
14399a2dd95SBruce Richardson 		case ZERO_OK:
14499a2dd95SBruce Richardson 			if (c == 'x') {
14599a2dd95SBruce Richardson 				st = HEX;
14699a2dd95SBruce Richardson 			}
14799a2dd95SBruce Richardson 			else if (c == 'b') {
14899a2dd95SBruce Richardson 				st = BIN;
14999a2dd95SBruce Richardson 			}
15099a2dd95SBruce Richardson 			else if (c >= '0' && c <= '7') {
15199a2dd95SBruce Richardson 				if (add_to_res(c - '0', &res1, 10) < 0)
15299a2dd95SBruce Richardson 					st = ERROR;
15399a2dd95SBruce Richardson 				else
15499a2dd95SBruce Richardson 					st = OCTAL_OK;
15599a2dd95SBruce Richardson 			}
15699a2dd95SBruce Richardson 			else  {
15799a2dd95SBruce Richardson 				st = ERROR;
15899a2dd95SBruce Richardson 			}
15999a2dd95SBruce Richardson 			break;
16099a2dd95SBruce Richardson 
16199a2dd95SBruce Richardson 		case DEC_NEG:
16299a2dd95SBruce Richardson 			if (c >= '0' && c <= '9') {
16399a2dd95SBruce Richardson 				if (add_to_res(c - '0', &res1, 10) < 0)
16499a2dd95SBruce Richardson 					st = ERROR;
16599a2dd95SBruce Richardson 				else
16699a2dd95SBruce Richardson 					st = DEC_NEG_OK;
16799a2dd95SBruce Richardson 			}
16899a2dd95SBruce Richardson 			else {
16999a2dd95SBruce Richardson 				st = ERROR;
17099a2dd95SBruce Richardson 			}
17199a2dd95SBruce Richardson 			break;
17299a2dd95SBruce Richardson 
17399a2dd95SBruce Richardson 		case DEC_NEG_OK:
17499a2dd95SBruce Richardson 			if (c >= '0' && c <= '9') {
17599a2dd95SBruce Richardson 				if (add_to_res(c - '0', &res1, 10) < 0)
17699a2dd95SBruce Richardson 					st = ERROR;
17799a2dd95SBruce Richardson 			}
17899a2dd95SBruce Richardson 			else {
17999a2dd95SBruce Richardson 				st = ERROR;
18099a2dd95SBruce Richardson 			}
18199a2dd95SBruce Richardson 			break;
18299a2dd95SBruce Richardson 
18399a2dd95SBruce Richardson 		case DEC_POS_OK:
18499a2dd95SBruce Richardson 			if (c >= '0' && c <= '9') {
18599a2dd95SBruce Richardson 				if (add_to_res(c - '0', &res1, 10) < 0)
18699a2dd95SBruce Richardson 					st = ERROR;
18799a2dd95SBruce Richardson 			}
18899a2dd95SBruce Richardson 			else {
18999a2dd95SBruce Richardson 				st = ERROR;
19099a2dd95SBruce Richardson 			}
19199a2dd95SBruce Richardson 			break;
19299a2dd95SBruce Richardson 
19399a2dd95SBruce Richardson 		case HEX:
19499a2dd95SBruce Richardson 			st = HEX_OK;
19599a2dd95SBruce Richardson 			/* fall-through */
19699a2dd95SBruce Richardson 		case HEX_OK:
19799a2dd95SBruce Richardson 			if (c >= '0' && c <= '9') {
19899a2dd95SBruce Richardson 				if (add_to_res(c - '0', &res1, 16) < 0)
19999a2dd95SBruce Richardson 					st = ERROR;
20099a2dd95SBruce Richardson 			}
20199a2dd95SBruce Richardson 			else if (c >= 'a' && c <= 'f') {
20299a2dd95SBruce Richardson 				if (add_to_res(c - 'a' + 10, &res1, 16) < 0)
20399a2dd95SBruce Richardson 					st = ERROR;
20499a2dd95SBruce Richardson 			}
20599a2dd95SBruce Richardson 			else if (c >= 'A' && c <= 'F') {
20699a2dd95SBruce Richardson 				if (add_to_res(c - 'A' + 10, &res1, 16) < 0)
20799a2dd95SBruce Richardson 					st = ERROR;
20899a2dd95SBruce Richardson 			}
20999a2dd95SBruce Richardson 			else {
21099a2dd95SBruce Richardson 				st = ERROR;
21199a2dd95SBruce Richardson 			}
21299a2dd95SBruce Richardson 			break;
21399a2dd95SBruce Richardson 
21499a2dd95SBruce Richardson 
21599a2dd95SBruce Richardson 		case OCTAL_OK:
21699a2dd95SBruce Richardson 			if (c >= '0' && c <= '7') {
21799a2dd95SBruce Richardson 				if (add_to_res(c - '0', &res1, 8) < 0)
21899a2dd95SBruce Richardson 					st = ERROR;
21999a2dd95SBruce Richardson 			}
22099a2dd95SBruce Richardson 			else {
22199a2dd95SBruce Richardson 				st = ERROR;
22299a2dd95SBruce Richardson 			}
22399a2dd95SBruce Richardson 			break;
22499a2dd95SBruce Richardson 
22599a2dd95SBruce Richardson 		case BIN:
22699a2dd95SBruce Richardson 			st = BIN_OK;
22799a2dd95SBruce Richardson 			/* fall-through */
22899a2dd95SBruce Richardson 		case BIN_OK:
22999a2dd95SBruce Richardson 			if (c >= '0' && c <= '1') {
23099a2dd95SBruce Richardson 				if (add_to_res(c - '0', &res1, 2) < 0)
23199a2dd95SBruce Richardson 					st = ERROR;
23299a2dd95SBruce Richardson 			}
23399a2dd95SBruce Richardson 			else {
23499a2dd95SBruce Richardson 				st = ERROR;
23599a2dd95SBruce Richardson 			}
23699a2dd95SBruce Richardson 			break;
23799a2dd95SBruce Richardson 		default:
23899a2dd95SBruce Richardson 			debug_printf("not impl ");
23999a2dd95SBruce Richardson 
24099a2dd95SBruce Richardson 		}
24199a2dd95SBruce Richardson 
24299a2dd95SBruce Richardson 		debug_printf("(%"PRIu64")\n", res1);
24399a2dd95SBruce Richardson 
24499a2dd95SBruce Richardson 		buf ++;
24599a2dd95SBruce Richardson 		c = *buf;
24699a2dd95SBruce Richardson 
24799a2dd95SBruce Richardson 		/* token too long */
24899a2dd95SBruce Richardson 		if (buf-srcbuf > 127)
24999a2dd95SBruce Richardson 			return -1;
25099a2dd95SBruce Richardson 	}
25199a2dd95SBruce Richardson 
25299a2dd95SBruce Richardson 	switch (st) {
25399a2dd95SBruce Richardson 	case ZERO_OK:
25499a2dd95SBruce Richardson 	case DEC_POS_OK:
25599a2dd95SBruce Richardson 	case HEX_OK:
25699a2dd95SBruce Richardson 	case OCTAL_OK:
25799a2dd95SBruce Richardson 	case BIN_OK:
25899a2dd95SBruce Richardson 		if (nd.type == RTE_INT8 && res1 <= INT8_MAX) {
25999a2dd95SBruce Richardson 			if (res) *(int8_t *)res = (int8_t) res1;
26099a2dd95SBruce Richardson 			return buf-srcbuf;
26199a2dd95SBruce Richardson 		} else if (nd.type == RTE_INT16 && res1 <= INT16_MAX) {
26299a2dd95SBruce Richardson 			if (res) *(int16_t *)res = (int16_t) res1;
26399a2dd95SBruce Richardson 			return buf-srcbuf;
26499a2dd95SBruce Richardson 		} else if (nd.type == RTE_INT32 && res1 <= INT32_MAX) {
26599a2dd95SBruce Richardson 			if (res) *(int32_t *)res = (int32_t) res1;
26699a2dd95SBruce Richardson 			return buf-srcbuf;
26799a2dd95SBruce Richardson 		} else if (nd.type == RTE_INT64 && res1 <= INT64_MAX) {
26899a2dd95SBruce Richardson 			if (res) *(int64_t *)res = (int64_t) res1;
26999a2dd95SBruce Richardson 			return buf-srcbuf;
27099a2dd95SBruce Richardson 		} else if (nd.type == RTE_UINT8 && res1 <= UINT8_MAX) {
27199a2dd95SBruce Richardson 			if (res) *(uint8_t *)res = (uint8_t) res1;
27299a2dd95SBruce Richardson 			return buf-srcbuf;
27399a2dd95SBruce Richardson 		} else if (nd.type == RTE_UINT16  && res1 <= UINT16_MAX) {
27499a2dd95SBruce Richardson 			if (res) *(uint16_t *)res = (uint16_t) res1;
27599a2dd95SBruce Richardson 			return buf-srcbuf;
27699a2dd95SBruce Richardson 		} else if (nd.type == RTE_UINT32 && res1 <= UINT32_MAX) {
27799a2dd95SBruce Richardson 			if (res) *(uint32_t *)res = (uint32_t) res1;
27899a2dd95SBruce Richardson 			return buf-srcbuf;
27999a2dd95SBruce Richardson 		} else if (nd.type == RTE_UINT64) {
28099a2dd95SBruce Richardson 			if (res) *(uint64_t *)res = res1;
28199a2dd95SBruce Richardson 			return buf-srcbuf;
28299a2dd95SBruce Richardson 		} else {
28399a2dd95SBruce Richardson 			return -1;
28499a2dd95SBruce Richardson 		}
28599a2dd95SBruce Richardson 		break;
28699a2dd95SBruce Richardson 
28799a2dd95SBruce Richardson 	case DEC_NEG_OK:
28899a2dd95SBruce Richardson 		if (nd.type == RTE_INT8 &&
28999a2dd95SBruce Richardson 				res1 <= INT8_MAX + 1) {
29099a2dd95SBruce Richardson 			if (res) *(int8_t *)res = (int8_t) (-res1);
29199a2dd95SBruce Richardson 			return buf-srcbuf;
29299a2dd95SBruce Richardson 		} else if (nd.type == RTE_INT16 &&
29399a2dd95SBruce Richardson 				res1 <= (uint16_t)INT16_MAX + 1) {
29499a2dd95SBruce Richardson 			if (res) *(int16_t *)res = (int16_t) (-res1);
29599a2dd95SBruce Richardson 			return buf-srcbuf;
29699a2dd95SBruce Richardson 		} else if (nd.type == RTE_INT32 &&
29799a2dd95SBruce Richardson 				res1 <= (uint32_t)INT32_MAX + 1) {
29899a2dd95SBruce Richardson 			if (res) *(int32_t *)res = (int32_t) (-res1);
29999a2dd95SBruce Richardson 			return buf-srcbuf;
30099a2dd95SBruce Richardson 		} else if (nd.type == RTE_INT64 &&
30199a2dd95SBruce Richardson 				res1 <= (uint64_t)INT64_MAX + 1) {
30299a2dd95SBruce Richardson 			if (res) *(int64_t *)res = (int64_t) (-res1);
30399a2dd95SBruce Richardson 			return buf-srcbuf;
30499a2dd95SBruce Richardson 		} else {
30599a2dd95SBruce Richardson 			return -1;
30699a2dd95SBruce Richardson 		}
30799a2dd95SBruce Richardson 		break;
30899a2dd95SBruce Richardson 	default:
30999a2dd95SBruce Richardson 		debug_printf("error\n");
31099a2dd95SBruce Richardson 		return -1;
31199a2dd95SBruce Richardson 	}
31299a2dd95SBruce Richardson }
31399a2dd95SBruce Richardson 
31499a2dd95SBruce Richardson 
31599a2dd95SBruce Richardson /* parse an int */
31699a2dd95SBruce Richardson int
cmdline_get_help_num(cmdline_parse_token_hdr_t * tk,char * dstbuf,unsigned int size)31799a2dd95SBruce Richardson cmdline_get_help_num(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
31899a2dd95SBruce Richardson {
31999a2dd95SBruce Richardson 	struct cmdline_token_num_data nd;
32099a2dd95SBruce Richardson 	int ret;
32199a2dd95SBruce Richardson 
32299a2dd95SBruce Richardson 	if (!tk)
32399a2dd95SBruce Richardson 		return -1;
32499a2dd95SBruce Richardson 
32599a2dd95SBruce Richardson 	memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
32699a2dd95SBruce Richardson 
32799a2dd95SBruce Richardson 	/* should not happen.... don't so this test */
32899a2dd95SBruce Richardson 	/* if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */
32999a2dd95SBruce Richardson 	/* return -1; */
33099a2dd95SBruce Richardson 
33199a2dd95SBruce Richardson 	ret = strlcpy(dstbuf, num_help[nd.type], size);
33299a2dd95SBruce Richardson 	if (ret < 0)
33399a2dd95SBruce Richardson 		return -1;
33499a2dd95SBruce Richardson 	dstbuf[size-1] = '\0';
33599a2dd95SBruce Richardson 	return 0;
33699a2dd95SBruce Richardson }
337