lib: strto: parse all lowercase metric prefixes in ustrtoul[l]
[platform/kernel/u-boot.git] / lib / strto.c
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 */
17 static 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;
25                 } else
26                         *base = 10;
27         }
28         if (*base == 16 && s[0] == '0' && tolower(s[1]) == 'x')
29                 s += 2;
30         return s;
31 }
32
33 unsigned long simple_strtoul(const char *cp, char **endp,
34                                 unsigned int base)
35 {
36         unsigned long result = 0;
37         unsigned long value;
38
39         cp = _parse_integer_fixup_radix(cp, &base);
40
41         while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
42             ? toupper(*cp) : *cp)-'A'+10) < base) {
43                 result = result*base + value;
44                 cp++;
45         }
46
47         if (endp)
48                 *endp = (char *)cp;
49
50         return result;
51 }
52
53 int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
54 {
55         char *tail;
56         unsigned long val;
57         size_t len;
58
59         *res = 0;
60         len = strlen(cp);
61         if (len == 0)
62                 return -EINVAL;
63
64         val = simple_strtoul(cp, &tail, base);
65         if (tail == cp)
66                 return -EINVAL;
67
68         if ((*tail == '\0') ||
69                 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {
70                 *res = val;
71                 return 0;
72         }
73
74         return -EINVAL;
75 }
76
77 long simple_strtol(const char *cp, char **endp, unsigned int base)
78 {
79         if (*cp == '-')
80                 return -simple_strtoul(cp + 1, endp, base);
81
82         return simple_strtoul(cp, endp, base);
83 }
84
85 unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
86 {
87         unsigned long result = simple_strtoul(cp, endp, base);
88         switch (tolower(**endp)) {
89         case 'g':
90                 result *= 1024;
91                 /* fall through */
92         case 'm':
93                 result *= 1024;
94                 /* fall through */
95         case 'k':
96                 result *= 1024;
97                 if ((*endp)[1] == 'i') {
98                         if ((*endp)[2] == 'B')
99                                 (*endp) += 3;
100                         else
101                                 (*endp) += 2;
102                 }
103         }
104         return result;
105 }
106
107 unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
108 {
109         unsigned long long result = simple_strtoull(cp, endp, base);
110         switch (tolower(**endp)) {
111         case 'g':
112                 result *= 1024;
113                 /* fall through */
114         case 'm':
115                 result *= 1024;
116                 /* fall through */
117         case 'k':
118                 result *= 1024;
119                 if ((*endp)[1] == 'i') {
120                         if ((*endp)[2] == 'B')
121                                 (*endp) += 3;
122                         else
123                                 (*endp) += 2;
124                 }
125         }
126         return result;
127 }
128
129 unsigned long long simple_strtoull(const char *cp, char **endp,
130                                         unsigned int base)
131 {
132         unsigned long long result = 0, value;
133
134         cp = _parse_integer_fixup_radix(cp, &base);
135
136         while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0'
137                 : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) {
138                 result = result * base + value;
139                 cp++;
140         }
141
142         if (endp)
143                 *endp = (char *) cp;
144
145         return result;
146 }
147
148 long trailing_strtoln(const char *str, const char *end)
149 {
150         const char *p;
151
152         if (!end)
153                 end = str + strlen(str);
154         if (isdigit(end[-1])) {
155                 for (p = end - 1; p > str; p--) {
156                         if (!isdigit(*p))
157                                 return simple_strtoul(p + 1, NULL, 10);
158                 }
159         }
160
161         return -1;
162 }
163
164 long trailing_strtol(const char *str)
165 {
166         return trailing_strtoln(str, NULL);
167 }