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