diff options
author | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2008-02-17 21:51:42 -0500 |
---|---|---|
committer | Lachlan McIlroy <lachlan@redback.melbourne.sgi.com> | 2008-02-17 21:51:42 -0500 |
commit | c58310bf4933986513020fa90b4190c7492995ae (patch) | |
tree | 143f2c7578d02ebef5db8fc57ae69e951ae0e2ee /lib/vsprintf.c | |
parent | 269cdfaf769f5cd831284cc831790c7c5038040f (diff) | |
parent | 1309d4e68497184d2fd87e892ddf14076c2bda98 (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6 into for-linus
Diffstat (limited to 'lib/vsprintf.c')
-rw-r--r-- | lib/vsprintf.c | 172 |
1 files changed, 150 insertions, 22 deletions
diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 7b481cea54ae..fd987b17bda7 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -26,6 +26,9 @@ | |||
26 | #include <asm/page.h> /* for PAGE_SIZE */ | 26 | #include <asm/page.h> /* for PAGE_SIZE */ |
27 | #include <asm/div64.h> | 27 | #include <asm/div64.h> |
28 | 28 | ||
29 | /* Works only for digits and letters, but small and fast */ | ||
30 | #define TOLOWER(x) ((x) | 0x20) | ||
31 | |||
29 | /** | 32 | /** |
30 | * simple_strtoul - convert a string to an unsigned long | 33 | * simple_strtoul - convert a string to an unsigned long |
31 | * @cp: The start of the string | 34 | * @cp: The start of the string |
@@ -41,17 +44,17 @@ unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) | |||
41 | if (*cp == '0') { | 44 | if (*cp == '0') { |
42 | base = 8; | 45 | base = 8; |
43 | cp++; | 46 | cp++; |
44 | if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { | 47 | if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) { |
45 | cp++; | 48 | cp++; |
46 | base = 16; | 49 | base = 16; |
47 | } | 50 | } |
48 | } | 51 | } |
49 | } else if (base == 16) { | 52 | } else if (base == 16) { |
50 | if (cp[0] == '0' && toupper(cp[1]) == 'X') | 53 | if (cp[0] == '0' && TOLOWER(cp[1]) == 'x') |
51 | cp += 2; | 54 | cp += 2; |
52 | } | 55 | } |
53 | while (isxdigit(*cp) && | 56 | while (isxdigit(*cp) && |
54 | (value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) { | 57 | (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) { |
55 | result = result*base + value; | 58 | result = result*base + value; |
56 | cp++; | 59 | cp++; |
57 | } | 60 | } |
@@ -92,17 +95,17 @@ unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base) | |||
92 | if (*cp == '0') { | 95 | if (*cp == '0') { |
93 | base = 8; | 96 | base = 8; |
94 | cp++; | 97 | cp++; |
95 | if ((toupper(*cp) == 'X') && isxdigit(cp[1])) { | 98 | if ((TOLOWER(*cp) == 'x') && isxdigit(cp[1])) { |
96 | cp++; | 99 | cp++; |
97 | base = 16; | 100 | base = 16; |
98 | } | 101 | } |
99 | } | 102 | } |
100 | } else if (base == 16) { | 103 | } else if (base == 16) { |
101 | if (cp[0] == '0' && toupper(cp[1]) == 'X') | 104 | if (cp[0] == '0' && TOLOWER(cp[1]) == 'x') |
102 | cp += 2; | 105 | cp += 2; |
103 | } | 106 | } |
104 | while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) | 107 | while (isxdigit(*cp) |
105 | ? toupper(*cp) : *cp)-'A'+10) < base) { | 108 | && (value = isdigit(*cp) ? *cp-'0' : TOLOWER(*cp)-'a'+10) < base) { |
106 | result = result*base + value; | 109 | result = result*base + value; |
107 | cp++; | 110 | cp++; |
108 | } | 111 | } |
@@ -126,6 +129,129 @@ long long simple_strtoll(const char *cp,char **endp,unsigned int base) | |||
126 | return simple_strtoull(cp,endp,base); | 129 | return simple_strtoull(cp,endp,base); |
127 | } | 130 | } |
128 | 131 | ||
132 | |||
133 | /** | ||
134 | * strict_strtoul - convert a string to an unsigned long strictly | ||
135 | * @cp: The string to be converted | ||
136 | * @base: The number base to use | ||
137 | * @res: The converted result value | ||
138 | * | ||
139 | * strict_strtoul converts a string to an unsigned long only if the | ||
140 | * string is really an unsigned long string, any string containing | ||
141 | * any invalid char at the tail will be rejected and -EINVAL is returned, | ||
142 | * only a newline char at the tail is acceptible because people generally | ||
143 | * change a module parameter in the following way: | ||
144 | * | ||
145 | * echo 1024 > /sys/module/e1000/parameters/copybreak | ||
146 | * | ||
147 | * echo will append a newline to the tail. | ||
148 | * | ||
149 | * It returns 0 if conversion is successful and *res is set to the converted | ||
150 | * value, otherwise it returns -EINVAL and *res is set to 0. | ||
151 | * | ||
152 | * simple_strtoul just ignores the successive invalid characters and | ||
153 | * return the converted value of prefix part of the string. | ||
154 | */ | ||
155 | int strict_strtoul(const char *cp, unsigned int base, unsigned long *res); | ||
156 | |||
157 | /** | ||
158 | * strict_strtol - convert a string to a long strictly | ||
159 | * @cp: The string to be converted | ||
160 | * @base: The number base to use | ||
161 | * @res: The converted result value | ||
162 | * | ||
163 | * strict_strtol is similiar to strict_strtoul, but it allows the first | ||
164 | * character of a string is '-'. | ||
165 | * | ||
166 | * It returns 0 if conversion is successful and *res is set to the converted | ||
167 | * value, otherwise it returns -EINVAL and *res is set to 0. | ||
168 | */ | ||
169 | int strict_strtol(const char *cp, unsigned int base, long *res); | ||
170 | |||
171 | /** | ||
172 | * strict_strtoull - convert a string to an unsigned long long strictly | ||
173 | * @cp: The string to be converted | ||
174 | * @base: The number base to use | ||
175 | * @res: The converted result value | ||
176 | * | ||
177 | * strict_strtoull converts a string to an unsigned long long only if the | ||
178 | * string is really an unsigned long long string, any string containing | ||
179 | * any invalid char at the tail will be rejected and -EINVAL is returned, | ||
180 | * only a newline char at the tail is acceptible because people generally | ||
181 | * change a module parameter in the following way: | ||
182 | * | ||
183 | * echo 1024 > /sys/module/e1000/parameters/copybreak | ||
184 | * | ||
185 | * echo will append a newline to the tail of the string. | ||
186 | * | ||
187 | * It returns 0 if conversion is successful and *res is set to the converted | ||
188 | * value, otherwise it returns -EINVAL and *res is set to 0. | ||
189 | * | ||
190 | * simple_strtoull just ignores the successive invalid characters and | ||
191 | * return the converted value of prefix part of the string. | ||
192 | */ | ||
193 | int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res); | ||
194 | |||
195 | /** | ||
196 | * strict_strtoll - convert a string to a long long strictly | ||
197 | * @cp: The string to be converted | ||
198 | * @base: The number base to use | ||
199 | * @res: The converted result value | ||
200 | * | ||
201 | * strict_strtoll is similiar to strict_strtoull, but it allows the first | ||
202 | * character of a string is '-'. | ||
203 | * | ||
204 | * It returns 0 if conversion is successful and *res is set to the converted | ||
205 | * value, otherwise it returns -EINVAL and *res is set to 0. | ||
206 | */ | ||
207 | int strict_strtoll(const char *cp, unsigned int base, long long *res); | ||
208 | |||
209 | #define define_strict_strtoux(type, valtype) \ | ||
210 | int strict_strtou##type(const char *cp, unsigned int base, valtype *res)\ | ||
211 | { \ | ||
212 | char *tail; \ | ||
213 | valtype val; \ | ||
214 | size_t len; \ | ||
215 | \ | ||
216 | *res = 0; \ | ||
217 | len = strlen(cp); \ | ||
218 | if (len == 0) \ | ||
219 | return -EINVAL; \ | ||
220 | \ | ||
221 | val = simple_strtoul(cp, &tail, base); \ | ||
222 | if ((*tail == '\0') || \ | ||
223 | ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) {\ | ||
224 | *res = val; \ | ||
225 | return 0; \ | ||
226 | } \ | ||
227 | \ | ||
228 | return -EINVAL; \ | ||
229 | } \ | ||
230 | |||
231 | #define define_strict_strtox(type, valtype) \ | ||
232 | int strict_strto##type(const char *cp, unsigned int base, valtype *res) \ | ||
233 | { \ | ||
234 | int ret; \ | ||
235 | if (*cp == '-') { \ | ||
236 | ret = strict_strtou##type(cp+1, base, res); \ | ||
237 | if (ret != 0) \ | ||
238 | *res = -(*res); \ | ||
239 | } else \ | ||
240 | ret = strict_strtou##type(cp, base, res); \ | ||
241 | \ | ||
242 | return ret; \ | ||
243 | } \ | ||
244 | |||
245 | define_strict_strtoux(l, unsigned long) | ||
246 | define_strict_strtox(l, long) | ||
247 | define_strict_strtoux(ll, unsigned long long) | ||
248 | define_strict_strtox(ll, long long) | ||
249 | |||
250 | EXPORT_SYMBOL(strict_strtoul); | ||
251 | EXPORT_SYMBOL(strict_strtol); | ||
252 | EXPORT_SYMBOL(strict_strtoll); | ||
253 | EXPORT_SYMBOL(strict_strtoull); | ||
254 | |||
129 | static int skip_atoi(const char **s) | 255 | static int skip_atoi(const char **s) |
130 | { | 256 | { |
131 | int i=0; | 257 | int i=0; |
@@ -237,24 +363,25 @@ static noinline char* put_dec(char *buf, unsigned long long num) | |||
237 | #define PLUS 4 /* show plus */ | 363 | #define PLUS 4 /* show plus */ |
238 | #define SPACE 8 /* space if plus */ | 364 | #define SPACE 8 /* space if plus */ |
239 | #define LEFT 16 /* left justified */ | 365 | #define LEFT 16 /* left justified */ |
240 | #define SPECIAL 32 /* 0x */ | 366 | #define SMALL 32 /* Must be 32 == 0x20 */ |
241 | #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ | 367 | #define SPECIAL 64 /* 0x */ |
242 | 368 | ||
243 | static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type) | 369 | static char *number(char *buf, char *end, unsigned long long num, int base, int size, int precision, int type) |
244 | { | 370 | { |
245 | char sign,tmp[66]; | 371 | /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ |
246 | const char *digits; | 372 | static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ |
247 | /* we are called with base 8, 10 or 16, only, thus don't need "g..." */ | 373 | |
248 | static const char small_digits[] = "0123456789abcdefx"; /* "ghijklmnopqrstuvwxyz"; */ | 374 | char tmp[66]; |
249 | static const char large_digits[] = "0123456789ABCDEFX"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ | 375 | char sign; |
376 | char locase; | ||
250 | int need_pfx = ((type & SPECIAL) && base != 10); | 377 | int need_pfx = ((type & SPECIAL) && base != 10); |
251 | int i; | 378 | int i; |
252 | 379 | ||
253 | digits = (type & LARGE) ? large_digits : small_digits; | 380 | /* locase = 0 or 0x20. ORing digits or letters with 'locase' |
381 | * produces same digits or (maybe lowercased) letters */ | ||
382 | locase = (type & SMALL); | ||
254 | if (type & LEFT) | 383 | if (type & LEFT) |
255 | type &= ~ZEROPAD; | 384 | type &= ~ZEROPAD; |
256 | if (base < 2 || base > 36) | ||
257 | return NULL; | ||
258 | sign = 0; | 385 | sign = 0; |
259 | if (type & SIGN) { | 386 | if (type & SIGN) { |
260 | if ((signed long long) num < 0) { | 387 | if ((signed long long) num < 0) { |
@@ -281,7 +408,7 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
281 | tmp[i++] = '0'; | 408 | tmp[i++] = '0'; |
282 | /* Generic code, for any base: | 409 | /* Generic code, for any base: |
283 | else do { | 410 | else do { |
284 | tmp[i++] = digits[do_div(num,base)]; | 411 | tmp[i++] = (digits[do_div(num,base)] | locase); |
285 | } while (num != 0); | 412 | } while (num != 0); |
286 | */ | 413 | */ |
287 | else if (base != 10) { /* 8 or 16 */ | 414 | else if (base != 10) { /* 8 or 16 */ |
@@ -289,7 +416,7 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
289 | int shift = 3; | 416 | int shift = 3; |
290 | if (base == 16) shift = 4; | 417 | if (base == 16) shift = 4; |
291 | do { | 418 | do { |
292 | tmp[i++] = digits[((unsigned char)num) & mask]; | 419 | tmp[i++] = (digits[((unsigned char)num) & mask] | locase); |
293 | num >>= shift; | 420 | num >>= shift; |
294 | } while (num); | 421 | } while (num); |
295 | } else { /* base 10 */ | 422 | } else { /* base 10 */ |
@@ -321,7 +448,7 @@ static char *number(char *buf, char *end, unsigned long long num, int base, int | |||
321 | ++buf; | 448 | ++buf; |
322 | if (base == 16) { | 449 | if (base == 16) { |
323 | if (buf < end) | 450 | if (buf < end) |
324 | *buf = digits[16]; /* for arbitrary base: digits[33]; */ | 451 | *buf = ('X' | locase); |
325 | ++buf; | 452 | ++buf; |
326 | } | 453 | } |
327 | } | 454 | } |
@@ -521,6 +648,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | |||
521 | continue; | 648 | continue; |
522 | 649 | ||
523 | case 'p': | 650 | case 'p': |
651 | flags |= SMALL; | ||
524 | if (field_width == -1) { | 652 | if (field_width == -1) { |
525 | field_width = 2*sizeof(void *); | 653 | field_width = 2*sizeof(void *); |
526 | flags |= ZEROPAD; | 654 | flags |= ZEROPAD; |
@@ -557,9 +685,9 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) | |||
557 | base = 8; | 685 | base = 8; |
558 | break; | 686 | break; |
559 | 687 | ||
560 | case 'X': | ||
561 | flags |= LARGE; | ||
562 | case 'x': | 688 | case 'x': |
689 | flags |= SMALL; | ||
690 | case 'X': | ||
563 | base = 16; | 691 | base = 16; |
564 | break; | 692 | break; |
565 | 693 | ||