1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
5  *   All rights reserved.
6  *
7  *   Redistribution and use in source and binary forms, with or without
8  *   modification, are permitted provided that the following conditions
9  *   are met:
10  *
11  *     * Redistributions of source code must retain the above copyright
12  *       notice, this list of conditions and the following disclaimer.
13  *     * Redistributions in binary form must reproduce the above copyright
14  *       notice, this list of conditions and the following disclaimer in
15  *       the documentation and/or other materials provided with the
16  *       distribution.
17  *     * Neither the name of Intel Corporation nor the names of its
18  *       contributors may be used to endorse or promote products derived
19  *       from this software without specific prior written permission.
20  *
21  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*
35  * Copyright (c) 2009, Olivier MATZ <[email protected]>
36  * All rights reserved.
37  * Redistribution and use in source and binary forms, with or without
38  * modification, are permitted provided that the following conditions are met:
39  *
40  *     * Redistributions of source code must retain the above copyright
41  *       notice, this list of conditions and the following disclaimer.
42  *     * Redistributions in binary form must reproduce the above copyright
43  *       notice, this list of conditions and the following disclaimer in the
44  *       documentation and/or other materials provided with the distribution.
45  *     * Neither the name of the University of California, Berkeley nor the
46  *       names of its contributors may be used to endorse or promote products
47  *       derived from this software without specific prior written permission.
48  *
49  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
50  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
51  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
52  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
53  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
54  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
55  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
56  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
57  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
58  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
59  */
60 
61 #include <stdio.h>
62 #include <stdint.h>
63 #include <inttypes.h>
64 #include <ctype.h>
65 #include <string.h>
66 #include <stdarg.h>
67 #include <errno.h>
68 #include <rte_string_fns.h>
69 
70 #include "cmdline_parse.h"
71 #include "cmdline_parse_num.h"
72 
73 #ifdef RTE_LIBRTE_CMDLINE_DEBUG
74 #define debug_printf(args...) printf(args)
75 #else
76 #define debug_printf(args...) do {} while(0)
77 #endif
78 
79 struct cmdline_token_ops cmdline_token_num_ops = {
80 	.parse = cmdline_parse_num,
81 	.complete_get_nb = NULL,
82 	.complete_get_elt = NULL,
83 	.get_help = cmdline_get_help_num,
84 };
85 
86 
87 enum num_parse_state_t {
88 	START,
89 	DEC_NEG,
90 	BIN,
91 	HEX,
92 
93 	ERROR,
94 
95 	FIRST_OK, /* not used */
96 	ZERO_OK,
97 	HEX_OK,
98 	OCTAL_OK,
99 	BIN_OK,
100 	DEC_NEG_OK,
101 	DEC_POS_OK,
102 };
103 
104 /* Keep it sync with enum in .h */
105 static const char * num_help[] = {
106 	"UINT8", "UINT16", "UINT32", "UINT64",
107 	"INT8", "INT16", "INT32", "INT64",
108 };
109 
110 static inline int
111 add_to_res(unsigned int c, uint64_t *res, unsigned int base)
112 {
113 	/* overflow */
114 	if ( (UINT64_MAX - c) / base < *res ) {
115 		return -1;
116 	}
117 
118 	*res = (uint64_t) (*res * base + c);
119 	return 0;
120 }
121 
122 static int
123 check_res_size(struct cmdline_token_num_data *nd, unsigned ressize)
124 {
125 	switch (nd->type) {
126 	case INT8:
127 	case UINT8:
128 		if (ressize < sizeof(int8_t))
129 			return -1;
130 		break;
131 	case INT16:
132 	case UINT16:
133 		if (ressize < sizeof(int16_t))
134 			return -1;
135 		break;
136 	case INT32:
137 	case UINT32:
138 		if (ressize < sizeof(int32_t))
139 			return -1;
140 		break;
141 	case INT64:
142 	case UINT64:
143 		if (ressize < sizeof(int64_t))
144 			return -1;
145 		break;
146 	default:
147 		return -1;
148 	}
149 	return 0;
150 }
151 
152 /* parse an int */
153 int
154 cmdline_parse_num(cmdline_parse_token_hdr_t *tk, const char *srcbuf, void *res,
155 	unsigned ressize)
156 {
157 	struct cmdline_token_num_data nd;
158 	enum num_parse_state_t st = START;
159 	const char * buf;
160 	char c;
161 	uint64_t res1 = 0;
162 
163 	if (!tk)
164 		return -1;
165 
166 	if (!srcbuf || !*srcbuf)
167 		return -1;
168 
169 	buf = srcbuf;
170 	c = *buf;
171 
172 	memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
173 
174 	/* check that we have enough room in res */
175 	if (res) {
176 		if (check_res_size(&nd, ressize) < 0)
177 			return -1;
178 	}
179 
180 	while ( st != ERROR && c && ! cmdline_isendoftoken(c) ) {
181 		debug_printf("%c %x -> ", c, c);
182 		switch (st) {
183 		case START:
184 			if (c == '-') {
185 				st = DEC_NEG;
186 			}
187 			else if (c == '0') {
188 				st = ZERO_OK;
189 			}
190 			else if (c >= '1' && c <= '9') {
191 				if (add_to_res(c - '0', &res1, 10) < 0)
192 					st = ERROR;
193 				else
194 					st = DEC_POS_OK;
195 			}
196 			else  {
197 				st = ERROR;
198 			}
199 			break;
200 
201 		case ZERO_OK:
202 			if (c == 'x') {
203 				st = HEX;
204 			}
205 			else if (c == 'b') {
206 				st = BIN;
207 			}
208 			else if (c >= '0' && c <= '7') {
209 				if (add_to_res(c - '0', &res1, 10) < 0)
210 					st = ERROR;
211 				else
212 					st = OCTAL_OK;
213 			}
214 			else  {
215 				st = ERROR;
216 			}
217 			break;
218 
219 		case DEC_NEG:
220 			if (c >= '0' && c <= '9') {
221 				if (add_to_res(c - '0', &res1, 10) < 0)
222 					st = ERROR;
223 				else
224 					st = DEC_NEG_OK;
225 			}
226 			else {
227 				st = ERROR;
228 			}
229 			break;
230 
231 		case DEC_NEG_OK:
232 			if (c >= '0' && c <= '9') {
233 				if (add_to_res(c - '0', &res1, 10) < 0)
234 					st = ERROR;
235 			}
236 			else {
237 				st = ERROR;
238 			}
239 			break;
240 
241 		case DEC_POS_OK:
242 			if (c >= '0' && c <= '9') {
243 				if (add_to_res(c - '0', &res1, 10) < 0)
244 					st = ERROR;
245 			}
246 			else {
247 				st = ERROR;
248 			}
249 			break;
250 
251 		case HEX:
252 			st = HEX_OK;
253 			/* fall-through no break */
254 		case HEX_OK:
255 			if (c >= '0' && c <= '9') {
256 				if (add_to_res(c - '0', &res1, 16) < 0)
257 					st = ERROR;
258 			}
259 			else if (c >= 'a' && c <= 'f') {
260 				if (add_to_res(c - 'a' + 10, &res1, 16) < 0)
261 					st = ERROR;
262 			}
263 			else if (c >= 'A' && c <= 'F') {
264 				if (add_to_res(c - 'A' + 10, &res1, 16) < 0)
265 					st = ERROR;
266 			}
267 			else {
268 				st = ERROR;
269 			}
270 			break;
271 
272 
273 		case OCTAL_OK:
274 			if (c >= '0' && c <= '7') {
275 				if (add_to_res(c - '0', &res1, 8) < 0)
276 					st = ERROR;
277 			}
278 			else {
279 				st = ERROR;
280 			}
281 			break;
282 
283 		case BIN:
284 			st = BIN_OK;
285 			/* fall-through */
286 		case BIN_OK:
287 			if (c >= '0' && c <= '1') {
288 				if (add_to_res(c - '0', &res1, 2) < 0)
289 					st = ERROR;
290 			}
291 			else {
292 				st = ERROR;
293 			}
294 			break;
295 		default:
296 			debug_printf("not impl ");
297 
298 		}
299 
300 		debug_printf("(%"PRIu64")\n", res1);
301 
302 		buf ++;
303 		c = *buf;
304 
305 		/* token too long */
306 		if (buf-srcbuf > 127)
307 			return -1;
308 	}
309 
310 	switch (st) {
311 	case ZERO_OK:
312 	case DEC_POS_OK:
313 	case HEX_OK:
314 	case OCTAL_OK:
315 	case BIN_OK:
316 		if ( nd.type == INT8 && res1 <= INT8_MAX ) {
317 			if (res) *(int8_t *)res = (int8_t) res1;
318 			return buf-srcbuf;
319 		}
320 		else if ( nd.type == INT16 && res1 <= INT16_MAX ) {
321 			if (res) *(int16_t *)res = (int16_t) res1;
322 			return buf-srcbuf;
323 		}
324 		else if ( nd.type == INT32 && res1 <= INT32_MAX ) {
325 			if (res) *(int32_t *)res = (int32_t) res1;
326 			return buf-srcbuf;
327 		}
328 		else if ( nd.type == INT64 && res1 <= INT64_MAX ) {
329 			if (res) *(int64_t *)res = (int64_t) res1;
330 			return buf-srcbuf;
331 		}
332 		else if ( nd.type == UINT8 && res1 <= UINT8_MAX ) {
333 			if (res) *(uint8_t *)res = (uint8_t) res1;
334 			return buf-srcbuf;
335 		}
336 		else if (nd.type == UINT16  && res1 <= UINT16_MAX ) {
337 			if (res) *(uint16_t *)res = (uint16_t) res1;
338 			return buf-srcbuf;
339 		}
340 		else if ( nd.type == UINT32 && res1 <= UINT32_MAX ) {
341 			if (res) *(uint32_t *)res = (uint32_t) res1;
342 			return buf-srcbuf;
343 		}
344 		else if ( nd.type == UINT64 ) {
345 			if (res) *(uint64_t *)res = res1;
346 			return buf-srcbuf;
347 		}
348 		else {
349 			return -1;
350 		}
351 		break;
352 
353 	case DEC_NEG_OK:
354 		if ( nd.type == INT8 && res1 <= INT8_MAX + 1 ) {
355 			if (res) *(int8_t *)res = (int8_t) (-res1);
356 			return buf-srcbuf;
357 		}
358 		else if ( nd.type == INT16 && res1 <= (uint16_t)INT16_MAX + 1 ) {
359 			if (res) *(int16_t *)res = (int16_t) (-res1);
360 			return buf-srcbuf;
361 		}
362 		else if ( nd.type == INT32 && res1 <= (uint32_t)INT32_MAX + 1 ) {
363 			if (res) *(int32_t *)res = (int32_t) (-res1);
364 			return buf-srcbuf;
365 		}
366 		else if ( nd.type == INT64 && res1 <= (uint64_t)INT64_MAX + 1 ) {
367 			if (res) *(int64_t *)res = (int64_t) (-res1);
368 			return buf-srcbuf;
369 		}
370 		else {
371 			return -1;
372 		}
373 		break;
374 	default:
375 		debug_printf("error\n");
376 		return -1;
377 	}
378 }
379 
380 
381 /* parse an int */
382 int
383 cmdline_get_help_num(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
384 {
385 	struct cmdline_token_num_data nd;
386 	int ret;
387 
388 	if (!tk)
389 		return -1;
390 
391 	memcpy(&nd, &((struct cmdline_token_num *)tk)->num_data, sizeof(nd));
392 
393 	/* should not happen.... don't so this test */
394 	/* if (nd.type >= (sizeof(num_help)/sizeof(const char *))) */
395 	/* return -1; */
396 
397 	ret = snprintf(dstbuf, size, "%s", num_help[nd.type]);
398 	if (ret < 0)
399 		return -1;
400 	dstbuf[size-1] = '\0';
401 	return 0;
402 }
403