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 <common.h>
13 #include <errno.h>
14 #include <linux/ctype.h>
15 
16 /* from lib/kstrtox.c */
_parse_integer_fixup_radix(const char * s,uint * basep)17 static const char *_parse_integer_fixup_radix(const char *s, uint *basep)
18 {
19 	/* Look for a 0x prefix */
20 	if (s[0] == '0') {
21 		int ch = tolower(s[1]);
22 
23 		if (ch == 'x') {
24 			*basep = 16;
25 			s += 2;
26 		} else if (!*basep) {
27 			/* Only select octal if we don't have a base */
28 			*basep = 8;
29 		}
30 	}
31 
32 	/* Use decimal by default */
33 	if (!*basep)
34 		*basep = 10;
35 
36 	return s;
37 }
38 
39 /**
40  * decode_digit() - Decode a single character into its numeric digit value
41  *
42  * This ignore case
43  *
44  * @ch: Character to convert (expects '0'..'9', 'a'..'f' or 'A'..'F')
45  * @return value of digit (0..0xf) or 255 if the character is invalid
46  */
decode_digit(int ch)47 static uint decode_digit(int ch)
48 {
49 	if (!isxdigit(ch))
50 		return 256;
51 
52 	ch = tolower(ch);
53 
54 	return ch <= '9' ? ch - '0' : ch - 'a' + 0xa;
55 }
56 
simple_strtoul(const char * cp,char ** endp,uint base)57 ulong simple_strtoul(const char *cp, char **endp, uint base)
58 {
59 	ulong result = 0;
60 	uint value;
61 
62 	cp = _parse_integer_fixup_radix(cp, &base);
63 
64 	while (value = decode_digit(*cp), value < base) {
65 		result = result * base + value;
66 		cp++;
67 	}
68 
69 	if (endp)
70 		*endp = (char *)cp;
71 
72 	return result;
73 }
74 
hextoul(const char * cp,char ** endp)75 ulong hextoul(const char *cp, char **endp)
76 {
77 	return simple_strtoul(cp, endp, 16);
78 }
79 
dectoul(const char * cp,char ** endp)80 ulong dectoul(const char *cp, char **endp)
81 {
82 	return simple_strtoul(cp, endp, 10);
83 }
84 
strict_strtoul(const char * cp,unsigned int base,unsigned long * res)85 int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
86 {
87 	char *tail;
88 	unsigned long val;
89 	size_t len;
90 
91 	*res = 0;
92 	len = strlen(cp);
93 	if (len == 0)
94 		return -EINVAL;
95 
96 	val = simple_strtoul(cp, &tail, base);
97 	if (tail == cp)
98 		return -EINVAL;
99 
100 	if ((*tail == '\0') ||
101 		((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
102 		*res = val;
103 		return 0;
104 	}
105 
106 	return -EINVAL;
107 }
108 
simple_strtol(const char * cp,char ** endp,unsigned int base)109 long simple_strtol(const char *cp, char **endp, unsigned int base)
110 {
111 	if (*cp == '-')
112 		return -simple_strtoul(cp + 1, endp, base);
113 
114 	return simple_strtoul(cp, endp, base);
115 }
116 
ustrtoul(const char * cp,char ** endp,unsigned int base)117 unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
118 {
119 	unsigned long result = simple_strtoul(cp, endp, base);
120 	switch (tolower(**endp)) {
121 	case 'g':
122 		result *= 1024;
123 		/* fall through */
124 	case 'm':
125 		result *= 1024;
126 		/* fall through */
127 	case 'k':
128 		result *= 1024;
129 		(*endp)++;
130 		if (**endp == 'i')
131 			(*endp)++;
132 		if (**endp == 'B')
133 			(*endp)++;
134 	}
135 	return result;
136 }
137 
ustrtoull(const char * cp,char ** endp,unsigned int base)138 unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
139 {
140 	unsigned long long result = simple_strtoull(cp, endp, base);
141 	switch (tolower(**endp)) {
142 	case 'g':
143 		result *= 1024;
144 		/* fall through */
145 	case 'm':
146 		result *= 1024;
147 		/* fall through */
148 	case 'k':
149 		result *= 1024;
150 		(*endp)++;
151 		if (**endp == 'i')
152 			(*endp)++;
153 		if (**endp == 'B')
154 			(*endp)++;
155 	}
156 	return result;
157 }
158 
simple_strtoull(const char * cp,char ** endp,unsigned int base)159 unsigned long long simple_strtoull(const char *cp, char **endp,
160 					unsigned int base)
161 {
162 	unsigned long long result = 0;
163 	uint value;
164 
165 	cp = _parse_integer_fixup_radix(cp, &base);
166 
167 	while (value = decode_digit(*cp), value < base) {
168 		result = result * base + value;
169 		cp++;
170 	}
171 
172 	if (endp)
173 		*endp = (char *) cp;
174 
175 	return result;
176 }
177 
simple_strtoll(const char * cp,char ** endp,unsigned int base)178 long long simple_strtoll(const char *cp, char **endp, unsigned int base)
179 {
180 	if (*cp == '-')
181 		return -simple_strtoull(cp + 1, endp, base);
182 
183 	return simple_strtoull(cp, endp, base);
184 }
185 
trailing_strtoln(const char * str,const char * end)186 long trailing_strtoln(const char *str, const char *end)
187 {
188 	const char *p;
189 
190 	if (!end)
191 		end = str + strlen(str);
192 	if (isdigit(end[-1])) {
193 		for (p = end - 1; p > str; p--) {
194 			if (!isdigit(*p))
195 				return dectoul(p + 1, NULL);
196 		}
197 	}
198 
199 	return -1;
200 }
201 
trailing_strtol(const char * str)202 long trailing_strtol(const char *str)
203 {
204 	return trailing_strtoln(str, NULL);
205 }
206 
str_to_upper(const char * in,char * out,size_t len)207 void str_to_upper(const char *in, char *out, size_t len)
208 {
209 	for (; len > 0 && *in; len--)
210 		*out++ = toupper(*in++);
211 	if (len)
212 		*out = '\0';
213 }
214