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