blob: b056b205c856321c965249adfa86a5399c3b5709 [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 */
17static const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
18{
19 if (*base == 0) {
20 if (s[0] == '0') {
Simon Glass96b23442021-07-24 09:03:32 -060021 if (tolower(s[1]) == 'x')
Rob Clark2e794612017-09-11 16:53:08 -040022 *base = 16;
23 else
24 *base = 8;
Sean Anderson1fae7412020-06-07 01:36:45 -040025 } else
Rob Clark2e794612017-09-11 16:53:08 -040026 *base = 10;
27 }
28 if (*base == 16 && s[0] == '0' && tolower(s[1]) == 'x')
29 s += 2;
30 return s;
31}
32
Simon Glass5a945462021-07-24 09:03:35 -060033/**
34 * decode_digit() - Decode a single character into its numeric digit value
35 *
36 * This ignore case
37 *
38 * @ch: Character to convert (expects '0'..'9', 'a'..'f' or 'A'..'F')
39 * @return value of digit (0..0xf) or 255 if the character is invalid
40 */
41static uint decode_digit(int ch)
42{
43 if (!isxdigit(ch))
44 return 256;
45
46 ch = tolower(ch);
47
48 return ch <= '9' ? ch - '0' : ch - 'a' + 0xa;
49}
50
Simon Glass7e5f4602021-07-24 09:03:29 -060051ulong simple_strtoul(const char *cp, char **endp, uint base)
Sjoerd Simonse4c53832015-12-04 23:27:39 +010052{
Simon Glass7e5f4602021-07-24 09:03:29 -060053 ulong result = 0;
Simon Glass5a945462021-07-24 09:03:35 -060054 uint value;
Sjoerd Simonse4c53832015-12-04 23:27:39 +010055
Rob Clark2e794612017-09-11 16:53:08 -040056 cp = _parse_integer_fixup_radix(cp, &base);
Sjoerd Simonse4c53832015-12-04 23:27:39 +010057
Simon Glass5a945462021-07-24 09:03:35 -060058 while (value = decode_digit(*cp), value < base) {
59 result = result * base + value;
Sjoerd Simonse4c53832015-12-04 23:27:39 +010060 cp++;
61 }
62
63 if (endp)
64 *endp = (char *)cp;
65
66 return result;
67}
68
Simon Glass7e5f4602021-07-24 09:03:29 -060069ulong hextoul(const char *cp, char **endp)
70{
71 return simple_strtoul(cp, endp, 16);
72}
73
Simon Glass0b1284e2021-07-24 09:03:30 -060074ulong dectoul(const char *cp, char **endp)
75{
76 return simple_strtoul(cp, endp, 10);
77}
78
Sjoerd Simonse4c53832015-12-04 23:27:39 +010079int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
80{
81 char *tail;
82 unsigned long val;
83 size_t len;
84
85 *res = 0;
86 len = strlen(cp);
87 if (len == 0)
88 return -EINVAL;
89
90 val = simple_strtoul(cp, &tail, base);
91 if (tail == cp)
92 return -EINVAL;
93
94 if ((*tail == '\0') ||
95 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
96 *res = val;
97 return 0;
98 }
99
100 return -EINVAL;
101}
102
103long simple_strtol(const char *cp, char **endp, unsigned int base)
104{
105 if (*cp == '-')
106 return -simple_strtoul(cp + 1, endp, base);
107
108 return simple_strtoul(cp, endp, base);
109}
110
111unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
112{
113 unsigned long result = simple_strtoul(cp, endp, base);
Miquel Raynala353e6a2018-09-06 09:08:43 +0200114 switch (tolower(**endp)) {
115 case 'g':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100116 result *= 1024;
117 /* fall through */
Miquel Raynala353e6a2018-09-06 09:08:43 +0200118 case 'm':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100119 result *= 1024;
120 /* fall through */
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100121 case 'k':
122 result *= 1024;
Miquel Raynalb87b0d82018-09-06 09:08:44 +0200123 (*endp)++;
124 if (**endp == 'i')
125 (*endp)++;
126 if (**endp == 'B')
127 (*endp)++;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100128 }
129 return result;
130}
131
132unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
133{
134 unsigned long long result = simple_strtoull(cp, endp, base);
Miquel Raynala353e6a2018-09-06 09:08:43 +0200135 switch (tolower(**endp)) {
136 case 'g':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100137 result *= 1024;
138 /* fall through */
Miquel Raynala353e6a2018-09-06 09:08:43 +0200139 case 'm':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100140 result *= 1024;
141 /* fall through */
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100142 case 'k':
143 result *= 1024;
Miquel Raynalb87b0d82018-09-06 09:08:44 +0200144 (*endp)++;
145 if (**endp == 'i')
146 (*endp)++;
147 if (**endp == 'B')
148 (*endp)++;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100149 }
150 return result;
151}
152
153unsigned long long simple_strtoull(const char *cp, char **endp,
154 unsigned int base)
155{
Simon Glass5a945462021-07-24 09:03:35 -0600156 unsigned long long result = 0;
157 uint value;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100158
Rob Clark2e794612017-09-11 16:53:08 -0400159 cp = _parse_integer_fixup_radix(cp, &base);
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100160
Simon Glass5a945462021-07-24 09:03:35 -0600161 while (value = decode_digit(*cp), value < base) {
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100162 result = result * base + value;
163 cp++;
164 }
165
166 if (endp)
167 *endp = (char *) cp;
168
169 return result;
170}
171
Roland Gaudig0b016422021-07-23 12:29:18 +0000172long long simple_strtoll(const char *cp, char **endp, unsigned int base)
173{
174 if (*cp == '-')
175 return -simple_strtoull(cp + 1, endp, base);
176
177 return simple_strtoull(cp, endp, base);
178}
179
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100180long trailing_strtoln(const char *str, const char *end)
181{
182 const char *p;
183
184 if (!end)
185 end = str + strlen(str);
Simon Glassb91c6a12016-10-05 20:42:11 -0600186 if (isdigit(end[-1])) {
187 for (p = end - 1; p > str; p--) {
188 if (!isdigit(*p))
Simon Glass0b1284e2021-07-24 09:03:30 -0600189 return dectoul(p + 1, NULL);
Simon Glassb91c6a12016-10-05 20:42:11 -0600190 }
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100191 }
192
193 return -1;
194}
195
196long trailing_strtol(const char *str)
197{
198 return trailing_strtoln(str, NULL);
199}
Simon Glassfdc79a62020-04-08 08:32:56 -0600200
201void str_to_upper(const char *in, char *out, size_t len)
202{
203 for (; len > 0 && *in; len--)
204 *out++ = toupper(*in++);
205 if (len)
206 *out = '\0';
207}