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