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