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 */
_parse_integer_fixup_radix(const char * s,uint * basep)18 static 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  */
decode_digit(int ch)48 static 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 
simple_strtoul(const char * cp,char ** endp,uint base)58 ulong 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 
hextoul(const char * cp,char ** endp)76 ulong hextoul(const char *cp, char **endp)
77 {
78 	return simple_strtoul(cp, endp, 16);
79 }
80 
hextoull(const char * cp,char ** endp)81 unsigned long long hextoull(const char *cp, char **endp)
82 {
83 	return simple_strtoull(cp, endp, 16);
84 }
85 
dectoul(const char * cp,char ** endp)86 ulong dectoul(const char *cp, char **endp)
87 {
88 	return simple_strtoul(cp, endp, 10);
89 }
90 
strict_strtoul(const char * cp,unsigned int base,unsigned long * res)91 int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
92 {
93 	char *tail;
94 	unsigned long val;
95 	size_t len;
96 
97 	*res = 0;
98 	len = strlen(cp);
99 	if (len == 0)
100 		return -EINVAL;
101 
102 	val = simple_strtoul(cp, &tail, base);
103 	if (tail == cp)
104 		return -EINVAL;
105 
106 	if ((*tail == '\0') ||
107 		((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
108 		*res = val;
109 		return 0;
110 	}
111 
112 	return -EINVAL;
113 }
114 
simple_strtol(const char * cp,char ** endp,unsigned int base)115 long simple_strtol(const char *cp, char **endp, unsigned int base)
116 {
117 	if (*cp == '-')
118 		return -simple_strtoul(cp + 1, endp, base);
119 
120 	return simple_strtoul(cp, endp, base);
121 }
122 
ustrtoul(const char * cp,char ** endp,unsigned int base)123 unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
124 {
125 	unsigned long result = simple_strtoul(cp, endp, base);
126 	switch (tolower(**endp)) {
127 	case 'g':
128 		result *= 1024;
129 		/* fall through */
130 	case 'm':
131 		result *= 1024;
132 		/* fall through */
133 	case 'k':
134 		result *= 1024;
135 		(*endp)++;
136 		if (**endp == 'i')
137 			(*endp)++;
138 		if (**endp == 'B')
139 			(*endp)++;
140 	}
141 	return result;
142 }
143 
ustrtoull(const char * cp,char ** endp,unsigned int base)144 unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
145 {
146 	unsigned long long result = simple_strtoull(cp, endp, base);
147 	switch (tolower(**endp)) {
148 	case 'g':
149 		result *= 1024;
150 		/* fall through */
151 	case 'm':
152 		result *= 1024;
153 		/* fall through */
154 	case 'k':
155 		result *= 1024;
156 		(*endp)++;
157 		if (**endp == 'i')
158 			(*endp)++;
159 		if (**endp == 'B')
160 			(*endp)++;
161 	}
162 	return result;
163 }
164 
simple_strtoull(const char * cp,char ** endp,unsigned int base)165 unsigned long long simple_strtoull(const char *cp, char **endp,
166 					unsigned int base)
167 {
168 	unsigned long long result = 0;
169 	uint value;
170 
171 	cp = _parse_integer_fixup_radix(cp, &base);
172 
173 	while (value = decode_digit(*cp), value < base) {
174 		result = result * base + value;
175 		cp++;
176 	}
177 
178 	if (endp)
179 		*endp = (char *) cp;
180 
181 	return result;
182 }
183 
simple_strtoll(const char * cp,char ** endp,unsigned int base)184 long long simple_strtoll(const char *cp, char **endp, unsigned int base)
185 {
186 	if (*cp == '-')
187 		return -simple_strtoull(cp + 1, endp, base);
188 
189 	return simple_strtoull(cp, endp, base);
190 }
191 
trailing_strtoln_end(const char * str,const char * end,char const ** endp)192 long trailing_strtoln_end(const char *str, const char *end, char const **endp)
193 {
194 	const char *p;
195 
196 	if (!end)
197 		end = str + strlen(str);
198 	p = end - 1;
199 	if (p > str && isdigit(*p)) {
200 		do {
201 			if (!isdigit(p[-1])) {
202 				if (endp)
203 					*endp = p;
204 				return dectoul(p, NULL);
205 			}
206 		} while (--p > str);
207 	}
208 	if (endp)
209 		*endp = end;
210 
211 	return -1;
212 }
213 
trailing_strtoln(const char * str,const char * end)214 long trailing_strtoln(const char *str, const char *end)
215 {
216 	return trailing_strtoln_end(str, end, NULL);
217 }
218 
trailing_strtol(const char * str)219 long trailing_strtol(const char *str)
220 {
221 	return trailing_strtoln(str, NULL);
222 }
223 
str_to_upper(const char * in,char * out,size_t len)224 void str_to_upper(const char *in, char *out, size_t len)
225 {
226 	for (; len > 0 && *in; len--)
227 		*out++ = toupper(*in++);
228 	if (len)
229 		*out = '\0';
230 }
231 
str_to_list(const char * instr)232 const char **str_to_list(const char *instr)
233 {
234 	const char **ptr;
235 	char *str, *p;
236 	int count, i;
237 
238 	/* don't allocate if the string is empty */
239 	str = *instr ? strdup(instr) : (char *)instr;
240 	if (!str)
241 		return NULL;
242 
243 	/* count the number of space-separated strings */
244 	for (count = 0, p = str; *p; p++) {
245 		if (*p == ' ') {
246 			count++;
247 			*p = '\0';
248 		}
249 	}
250 	if (p != str && p[-1])
251 		count++;
252 
253 	/* allocate the pointer array, allowing for a NULL terminator */
254 	ptr = calloc(count + 1, sizeof(char *));
255 	if (!ptr) {
256 		if (*str)
257 			free(str);
258 		return NULL;
259 	}
260 
261 	for (i = 0, p = str; i < count; p += strlen(p) + 1, i++)
262 		ptr[i] = p;
263 
264 	return ptr;
265 }
266 
str_free_list(const char ** ptr)267 void str_free_list(const char **ptr)
268 {
269 	if (ptr)
270 		free((char *)ptr[0]);
271 	free(ptr);
272 }
273