blob: 6462d4fddf1a71fef6231d3ffa8b73fe2f91031e [file] [log] [blame]
Sjoerd Simonse4c53832015-12-04 23:27:39 +01001/*
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
Rob Clark2e794612017-09-11 16:53:08 -040016/* from lib/kstrtox.c */
Simon Glasse6951132021-07-24 09:03:38 -060017static const char *_parse_integer_fixup_radix(const char *s, uint *basep)
Rob Clark2e794612017-09-11 16:53:08 -040018{
Simon Glasse6951132021-07-24 09:03:38 -060019 /* 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 }
Rob Clark2e794612017-09-11 16:53:08 -040030 }
Simon Glasse6951132021-07-24 09:03:38 -060031
32 /* Use decimal by default */
33 if (!*basep)
34 *basep = 10;
35
Rob Clark2e794612017-09-11 16:53:08 -040036 return s;
37}
38
Simon Glass5a945462021-07-24 09:03:35 -060039/**
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')
Heinrich Schuchardt185f8122022-01-19 18:05:50 +010045 * Return: value of digit (0..0xf) or 255 if the character is invalid
Simon Glass5a945462021-07-24 09:03:35 -060046 */
47static 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
Simon Glass7e5f4602021-07-24 09:03:29 -060057ulong simple_strtoul(const char *cp, char **endp, uint base)
Sjoerd Simonse4c53832015-12-04 23:27:39 +010058{
Simon Glass7e5f4602021-07-24 09:03:29 -060059 ulong result = 0;
Simon Glass5a945462021-07-24 09:03:35 -060060 uint value;
Sjoerd Simonse4c53832015-12-04 23:27:39 +010061
Rob Clark2e794612017-09-11 16:53:08 -040062 cp = _parse_integer_fixup_radix(cp, &base);
Sjoerd Simonse4c53832015-12-04 23:27:39 +010063
Simon Glass5a945462021-07-24 09:03:35 -060064 while (value = decode_digit(*cp), value < base) {
65 result = result * base + value;
Sjoerd Simonse4c53832015-12-04 23:27:39 +010066 cp++;
67 }
68
69 if (endp)
70 *endp = (char *)cp;
71
72 return result;
73}
74
Simon Glass7e5f4602021-07-24 09:03:29 -060075ulong hextoul(const char *cp, char **endp)
76{
77 return simple_strtoul(cp, endp, 16);
78}
79
Simon Glass0b1284e2021-07-24 09:03:30 -060080ulong dectoul(const char *cp, char **endp)
81{
82 return simple_strtoul(cp, endp, 10);
83}
84
Sjoerd Simonse4c53832015-12-04 23:27:39 +010085int 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
109long 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
117unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
118{
119 unsigned long result = simple_strtoul(cp, endp, base);
Miquel Raynala353e6a2018-09-06 09:08:43 +0200120 switch (tolower(**endp)) {
121 case 'g':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100122 result *= 1024;
123 /* fall through */
Miquel Raynala353e6a2018-09-06 09:08:43 +0200124 case 'm':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100125 result *= 1024;
126 /* fall through */
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100127 case 'k':
128 result *= 1024;
Miquel Raynalb87b0d82018-09-06 09:08:44 +0200129 (*endp)++;
130 if (**endp == 'i')
131 (*endp)++;
132 if (**endp == 'B')
133 (*endp)++;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100134 }
135 return result;
136}
137
138unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
139{
140 unsigned long long result = simple_strtoull(cp, endp, base);
Miquel Raynala353e6a2018-09-06 09:08:43 +0200141 switch (tolower(**endp)) {
142 case 'g':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100143 result *= 1024;
144 /* fall through */
Miquel Raynala353e6a2018-09-06 09:08:43 +0200145 case 'm':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100146 result *= 1024;
147 /* fall through */
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100148 case 'k':
149 result *= 1024;
Miquel Raynalb87b0d82018-09-06 09:08:44 +0200150 (*endp)++;
151 if (**endp == 'i')
152 (*endp)++;
153 if (**endp == 'B')
154 (*endp)++;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100155 }
156 return result;
157}
158
159unsigned long long simple_strtoull(const char *cp, char **endp,
160 unsigned int base)
161{
Simon Glass5a945462021-07-24 09:03:35 -0600162 unsigned long long result = 0;
163 uint value;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100164
Rob Clark2e794612017-09-11 16:53:08 -0400165 cp = _parse_integer_fixup_radix(cp, &base);
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100166
Simon Glass5a945462021-07-24 09:03:35 -0600167 while (value = decode_digit(*cp), value < base) {
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100168 result = result * base + value;
169 cp++;
170 }
171
172 if (endp)
173 *endp = (char *) cp;
174
175 return result;
176}
177
Roland Gaudig0b016422021-07-23 12:29:18 +0000178long 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
Simon Glass8565efd2022-04-24 23:30:58 -0600186long trailing_strtoln_end(const char *str, const char *end, char const **endp)
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100187{
188 const char *p;
189
190 if (!end)
191 end = str + strlen(str);
Simon Glassd667a0d2022-04-24 23:30:57 -0600192 p = end - 1;
193 if (p > str && isdigit(*p)) {
194 do {
Simon Glass8565efd2022-04-24 23:30:58 -0600195 if (!isdigit(p[-1])) {
196 if (endp)
197 *endp = p;
Simon Glassd667a0d2022-04-24 23:30:57 -0600198 return dectoul(p, NULL);
Simon Glass8565efd2022-04-24 23:30:58 -0600199 }
Simon Glassd667a0d2022-04-24 23:30:57 -0600200 } while (--p > str);
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100201 }
Simon Glass8565efd2022-04-24 23:30:58 -0600202 if (endp)
203 *endp = end;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100204
205 return -1;
206}
207
Simon Glass8565efd2022-04-24 23:30:58 -0600208long trailing_strtoln(const char *str, const char *end)
209{
210 return trailing_strtoln_end(str, end, NULL);
211}
212
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100213long trailing_strtol(const char *str)
214{
215 return trailing_strtoln(str, NULL);
216}
Simon Glassfdc79a62020-04-08 08:32:56 -0600217
218void str_to_upper(const char *in, char *out, size_t len)
219{
220 for (; len > 0 && *in; len--)
221 *out++ = toupper(*in++);
222 if (len)
223 *out = '\0';
224}