1/*
2 *  linux/lib/vsprintf.c
3 *
4 *  Copyright (C) 1991, 1992  Linus Torvalds
5 */
6
7/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
8/*
9 * Wirzenius wrote this portably, Torvalds fucked it up :-)
10 */
11
12#include <errno.h>
13#include <malloc.h>
14#include <vsprintf.h>
15#include <linux/ctype.h>
16
17/* from lib/kstrtox.c */
18static const char *_parse_integer_fixup_radix(const char *s, uint *basep)
19{
20	/* Look for a 0x prefix */
21	if (s[0] == '0') {
22		int ch = tolower(s[1]);
23
24		if (ch == 'x') {
25			*basep = 16;
26			s += 2;
27		} else if (!*basep) {
28			/* Only select octal if we don't have a base */
29			*basep = 8;
30		}
31	}
32
33	/* Use decimal by default */
34	if (!*basep)
35		*basep = 10;
36
37	return s;
38}
39
40/**
41 * decode_digit() - Decode a single character into its numeric digit value
42 *
43 * This ignore case
44 *
45 * @ch: Character to convert (expects '0'..'9', 'a'..'f' or 'A'..'F')
46 * Return: value of digit (0..0xf) or 255 if the character is invalid
47 */
48static uint decode_digit(int ch)
49{
50	if (!isxdigit(ch))
51		return 256;
52
53	ch = tolower(ch);
54
55	return ch <= '9' ? ch - '0' : ch - 'a' + 0xa;
56}
57
58ulong simple_strtoul(const char *cp, char **endp, uint base)
59{
60	ulong result = 0;
61	uint value;
62
63	cp = _parse_integer_fixup_radix(cp, &base);
64
65	while (value = decode_digit(*cp), value < base) {
66		result = result * base + value;
67		cp++;
68	}
69
70	if (endp)
71		*endp = (char *)cp;
72
73	return result;
74}
75
76ulong hextoul(const char *cp, char **endp)
77{
78	return simple_strtoul(cp, endp, 16);
79}
80
81ulong dectoul(const char *cp, char **endp)
82{
83	return simple_strtoul(cp, endp, 10);
84}
85
86int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
87{
88	char *tail;
89	unsigned long val;
90	size_t len;
91
92	*res = 0;
93	len = strlen(cp);
94	if (len == 0)
95		return -EINVAL;
96
97	val = simple_strtoul(cp, &tail, base);
98	if (tail == cp)
99		return -EINVAL;
100
101	if ((*tail == '\0') ||
102		((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
103		*res = val;
104		return 0;
105	}
106
107	return -EINVAL;
108}
109
110long simple_strtol(const char *cp, char **endp, unsigned int base)
111{
112	if (*cp == '-')
113		return -simple_strtoul(cp + 1, endp, base);
114
115	return simple_strtoul(cp, endp, base);
116}
117
118unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
119{
120	unsigned long result = simple_strtoul(cp, endp, base);
121	switch (tolower(**endp)) {
122	case 'g':
123		result *= 1024;
124		/* fall through */
125	case 'm':
126		result *= 1024;
127		/* fall through */
128	case 'k':
129		result *= 1024;
130		(*endp)++;
131		if (**endp == 'i')
132			(*endp)++;
133		if (**endp == 'B')
134			(*endp)++;
135	}
136	return result;
137}
138
139unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
140{
141	unsigned long long result = simple_strtoull(cp, endp, base);
142	switch (tolower(**endp)) {
143	case 'g':
144		result *= 1024;
145		/* fall through */
146	case 'm':
147		result *= 1024;
148		/* fall through */
149	case 'k':
150		result *= 1024;
151		(*endp)++;
152		if (**endp == 'i')
153			(*endp)++;
154		if (**endp == 'B')
155			(*endp)++;
156	}
157	return result;
158}
159
160unsigned long long simple_strtoull(const char *cp, char **endp,
161					unsigned int base)
162{
163	unsigned long long result = 0;
164	uint value;
165
166	cp = _parse_integer_fixup_radix(cp, &base);
167
168	while (value = decode_digit(*cp), value < base) {
169		result = result * base + value;
170		cp++;
171	}
172
173	if (endp)
174		*endp = (char *) cp;
175
176	return result;
177}
178
179long long simple_strtoll(const char *cp, char **endp, unsigned int base)
180{
181	if (*cp == '-')
182		return -simple_strtoull(cp + 1, endp, base);
183
184	return simple_strtoull(cp, endp, base);
185}
186
187long trailing_strtoln_end(const char *str, const char *end, char const **endp)
188{
189	const char *p;
190
191	if (!end)
192		end = str + strlen(str);
193	p = end - 1;
194	if (p > str && isdigit(*p)) {
195		do {
196			if (!isdigit(p[-1])) {
197				if (endp)
198					*endp = p;
199				return dectoul(p, NULL);
200			}
201		} while (--p > str);
202	}
203	if (endp)
204		*endp = end;
205
206	return -1;
207}
208
209long trailing_strtoln(const char *str, const char *end)
210{
211	return trailing_strtoln_end(str, end, NULL);
212}
213
214long trailing_strtol(const char *str)
215{
216	return trailing_strtoln(str, NULL);
217}
218
219void str_to_upper(const char *in, char *out, size_t len)
220{
221	for (; len > 0 && *in; len--)
222		*out++ = toupper(*in++);
223	if (len)
224		*out = '\0';
225}
226
227const char **str_to_list(const char *instr)
228{
229	const char **ptr;
230	char *str, *p;
231	int count, i;
232
233	/* don't allocate if the string is empty */
234	str = *instr ? strdup(instr) : (char *)instr;
235	if (!str)
236		return NULL;
237
238	/* count the number of space-separated strings */
239	for (count = *str != '\0', p = str; *p; p++) {
240		if (*p == ' ') {
241			count++;
242			*p = '\0';
243		}
244	}
245
246	/* allocate the pointer array, allowing for a NULL terminator */
247	ptr = calloc(count + 1, sizeof(char *));
248	if (!ptr) {
249		if (*str)
250			free(str);
251		return NULL;
252	}
253
254	for (i = 0, p = str; i < count; p += strlen(p) + 1, i++)
255		ptr[i] = p;
256
257	return ptr;
258}
259
260void str_free_list(const char **ptr)
261{
262	if (ptr)
263		free((char *)ptr[0]);
264	free(ptr);
265}
266