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 <zer0@droids-corp.org>
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
79struct 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
87enum 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 */
105static const char * num_help[] = {
106	"UINT8", "UINT16", "UINT32", "UINT64",
107	"INT8", "INT16", "INT32", "INT64",
108};
109
110static inline int
111add_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
122static int
123check_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 */
153int
154cmdline_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			/* 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			/* no break */
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 */
382int
383cmdline_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