blob: 3d77115d4d813af05713380dafdccbc14aaf1804 [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') {
21 if (tolower(s[1]) == 'x' && isxdigit(s[2]))
22 *base = 16;
23 else
24 *base = 8;
Michal Simek04864972020-02-07 13:04:10 +010025 } else {
26 int i = 0;
27 char var;
28
Rob Clark2e794612017-09-11 16:53:08 -040029 *base = 10;
Michal Simek04864972020-02-07 13:04:10 +010030
31 do {
32 var = tolower(s[i++]);
33 if (var >= 'a' && var <= 'f') {
34 *base = 16;
35 break;
36 }
Michal Simek4b485892020-04-08 10:09:16 +020037
38 if (!(var >= '0' && var <= '9'))
39 break;
Michal Simek04864972020-02-07 13:04:10 +010040 } while (var);
41 }
Rob Clark2e794612017-09-11 16:53:08 -040042 }
Michal Simek04864972020-02-07 13:04:10 +010043
Rob Clark2e794612017-09-11 16:53:08 -040044 if (*base == 16 && s[0] == '0' && tolower(s[1]) == 'x')
45 s += 2;
46 return s;
47}
48
Sjoerd Simonse4c53832015-12-04 23:27:39 +010049unsigned long simple_strtoul(const char *cp, char **endp,
50 unsigned int base)
51{
52 unsigned long result = 0;
53 unsigned long value;
54
Rob Clark2e794612017-09-11 16:53:08 -040055 cp = _parse_integer_fixup_radix(cp, &base);
Sjoerd Simonse4c53832015-12-04 23:27:39 +010056
57 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
58 ? toupper(*cp) : *cp)-'A'+10) < base) {
59 result = result*base + value;
60 cp++;
61 }
62
63 if (endp)
64 *endp = (char *)cp;
65
66 return result;
67}
68
69int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
70{
71 char *tail;
72 unsigned long val;
73 size_t len;
74
75 *res = 0;
76 len = strlen(cp);
77 if (len == 0)
78 return -EINVAL;
79
80 val = simple_strtoul(cp, &tail, base);
81 if (tail == cp)
82 return -EINVAL;
83
84 if ((*tail == '\0') ||
85 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
86 *res = val;
87 return 0;
88 }
89
90 return -EINVAL;
91}
92
93long simple_strtol(const char *cp, char **endp, unsigned int base)
94{
95 if (*cp == '-')
96 return -simple_strtoul(cp + 1, endp, base);
97
98 return simple_strtoul(cp, endp, base);
99}
100
101unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
102{
103 unsigned long result = simple_strtoul(cp, endp, base);
Miquel Raynala353e6a2018-09-06 09:08:43 +0200104 switch (tolower(**endp)) {
105 case 'g':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100106 result *= 1024;
107 /* fall through */
Miquel Raynala353e6a2018-09-06 09:08:43 +0200108 case 'm':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100109 result *= 1024;
110 /* fall through */
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100111 case 'k':
112 result *= 1024;
Miquel Raynalb87b0d82018-09-06 09:08:44 +0200113 (*endp)++;
114 if (**endp == 'i')
115 (*endp)++;
116 if (**endp == 'B')
117 (*endp)++;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100118 }
119 return result;
120}
121
122unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
123{
124 unsigned long long result = simple_strtoull(cp, endp, base);
Miquel Raynala353e6a2018-09-06 09:08:43 +0200125 switch (tolower(**endp)) {
126 case 'g':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100127 result *= 1024;
128 /* fall through */
Miquel Raynala353e6a2018-09-06 09:08:43 +0200129 case 'm':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100130 result *= 1024;
131 /* fall through */
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100132 case 'k':
133 result *= 1024;
Miquel Raynalb87b0d82018-09-06 09:08:44 +0200134 (*endp)++;
135 if (**endp == 'i')
136 (*endp)++;
137 if (**endp == 'B')
138 (*endp)++;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100139 }
140 return result;
141}
142
143unsigned long long simple_strtoull(const char *cp, char **endp,
144 unsigned int base)
145{
146 unsigned long long result = 0, value;
147
Rob Clark2e794612017-09-11 16:53:08 -0400148 cp = _parse_integer_fixup_radix(cp, &base);
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100149
150 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0'
151 : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) {
152 result = result * base + value;
153 cp++;
154 }
155
156 if (endp)
157 *endp = (char *) cp;
158
159 return result;
160}
161
162long trailing_strtoln(const char *str, const char *end)
163{
164 const char *p;
165
166 if (!end)
167 end = str + strlen(str);
Simon Glassb91c6a12016-10-05 20:42:11 -0600168 if (isdigit(end[-1])) {
169 for (p = end - 1; p > str; p--) {
170 if (!isdigit(*p))
171 return simple_strtoul(p + 1, NULL, 10);
172 }
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100173 }
174
175 return -1;
176}
177
178long trailing_strtol(const char *str)
179{
180 return trailing_strtoln(str, NULL);
181}
Simon Glassfdc79a62020-04-08 08:32:56 -0600182
183void str_to_upper(const char *in, char *out, size_t len)
184{
185 for (; len > 0 && *in; len--)
186 *out++ = toupper(*in++);
187 if (len)
188 *out = '\0';
189}