blob: 1ac2b09c725ca24c788b819f679fac9e772642c2 [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 }
37 } while (var);
38 }
Rob Clark2e794612017-09-11 16:53:08 -040039 }
Michal Simek04864972020-02-07 13:04:10 +010040
Rob Clark2e794612017-09-11 16:53:08 -040041 if (*base == 16 && s[0] == '0' && tolower(s[1]) == 'x')
42 s += 2;
43 return s;
44}
45
Sjoerd Simonse4c53832015-12-04 23:27:39 +010046unsigned long simple_strtoul(const char *cp, char **endp,
47 unsigned int base)
48{
49 unsigned long result = 0;
50 unsigned long value;
51
Rob Clark2e794612017-09-11 16:53:08 -040052 cp = _parse_integer_fixup_radix(cp, &base);
Sjoerd Simonse4c53832015-12-04 23:27:39 +010053
54 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
55 ? toupper(*cp) : *cp)-'A'+10) < base) {
56 result = result*base + value;
57 cp++;
58 }
59
60 if (endp)
61 *endp = (char *)cp;
62
63 return result;
64}
65
66int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
67{
68 char *tail;
69 unsigned long val;
70 size_t len;
71
72 *res = 0;
73 len = strlen(cp);
74 if (len == 0)
75 return -EINVAL;
76
77 val = simple_strtoul(cp, &tail, base);
78 if (tail == cp)
79 return -EINVAL;
80
81 if ((*tail == '\0') ||
82 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
83 *res = val;
84 return 0;
85 }
86
87 return -EINVAL;
88}
89
90long simple_strtol(const char *cp, char **endp, unsigned int base)
91{
92 if (*cp == '-')
93 return -simple_strtoul(cp + 1, endp, base);
94
95 return simple_strtoul(cp, endp, base);
96}
97
98unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
99{
100 unsigned long result = simple_strtoul(cp, endp, base);
Miquel Raynala353e6a2018-09-06 09:08:43 +0200101 switch (tolower(**endp)) {
102 case 'g':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100103 result *= 1024;
104 /* fall through */
Miquel Raynala353e6a2018-09-06 09:08:43 +0200105 case 'm':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100106 result *= 1024;
107 /* fall through */
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100108 case 'k':
109 result *= 1024;
Miquel Raynalb87b0d82018-09-06 09:08:44 +0200110 (*endp)++;
111 if (**endp == 'i')
112 (*endp)++;
113 if (**endp == 'B')
114 (*endp)++;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100115 }
116 return result;
117}
118
119unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
120{
121 unsigned long long result = simple_strtoull(cp, endp, base);
Miquel Raynala353e6a2018-09-06 09:08:43 +0200122 switch (tolower(**endp)) {
123 case 'g':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100124 result *= 1024;
125 /* fall through */
Miquel Raynala353e6a2018-09-06 09:08:43 +0200126 case 'm':
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100127 result *= 1024;
128 /* fall through */
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100129 case 'k':
130 result *= 1024;
Miquel Raynalb87b0d82018-09-06 09:08:44 +0200131 (*endp)++;
132 if (**endp == 'i')
133 (*endp)++;
134 if (**endp == 'B')
135 (*endp)++;
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100136 }
137 return result;
138}
139
140unsigned long long simple_strtoull(const char *cp, char **endp,
141 unsigned int base)
142{
143 unsigned long long result = 0, value;
144
Rob Clark2e794612017-09-11 16:53:08 -0400145 cp = _parse_integer_fixup_radix(cp, &base);
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100146
147 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0'
148 : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) {
149 result = result * base + value;
150 cp++;
151 }
152
153 if (endp)
154 *endp = (char *) cp;
155
156 return result;
157}
158
159long trailing_strtoln(const char *str, const char *end)
160{
161 const char *p;
162
163 if (!end)
164 end = str + strlen(str);
Simon Glassb91c6a12016-10-05 20:42:11 -0600165 if (isdigit(end[-1])) {
166 for (p = end - 1; p > str; p--) {
167 if (!isdigit(*p))
168 return simple_strtoul(p + 1, NULL, 10);
169 }
Sjoerd Simonse4c53832015-12-04 23:27:39 +0100170 }
171
172 return -1;
173}
174
175long trailing_strtol(const char *str)
176{
177 return trailing_strtoln(str, NULL);
178}