Rev 1408 | Rev 1871 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 1408 | Rev 1869 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | /* |
1 | /* |
- | 2 | * linux/lib/vsprintf.c |
|
- | 3 | * |
|
- | 4 | * Copyright (C) 1991, 1992 Linus Torvalds |
|
- | 5 | */ |
|
- | 6 | ||
2 | * vsprintf - print formatted output without ellipsis on an array |
7 | /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ |
- | 8 | /* |
|
- | 9 | * Wirzenius wrote this portably, Torvalds fucked it up :-) |
|
- | 10 | */ |
|
- | 11 | ||
- | 12 | /* |
|
- | 13 | * Fri Jul 13 2001 Crutcher Dunnavant |
|
- | 14 | * - changed to provide snprintf and vsnprintf functions |
|
- | 15 | * So Feb 1 16:51:32 CET 2004 Juergen Quade |
|
- | 16 | * - scnprintf and vscnprintf |
|
3 | */ |
17 | */ |
4 | /* $Header$ */ |
- | |
Line 5... | Line -... | ||
5 | - | ||
6 | #include "stdio.h" |
18 | |
- | 19 | #include |
|
7 | #include |
20 | #include |
- | 21 | #include |
|
- | 22 | #include |
|
- | 23 | #include |
|
- | 24 | #include |
|
- | 25 | #include |
|
- | 26 | #include |
|
8 | #include |
27 | |
- | 28 | #include |
|
- | 29 | ||
- | 30 | struct va_format { |
|
- | 31 | const char *fmt; |
|
- | 32 | va_list *va; |
|
- | 33 | }; |
|
- | 34 | ||
- | 35 | #ifndef dereference_function_descriptor |
|
- | 36 | #define dereference_function_descriptor(p) (p) |
|
- | 37 | #endif |
|
- | 38 | ||
- | 39 | const char hex_asc[] = "0123456789abcdef"; |
|
- | 40 | ||
- | 41 | /* Works only for digits and letters, but small and fast */ |
|
- | 42 | #define TOLOWER(x) ((x) | 0x20) |
|
- | 43 | ||
- | 44 | static unsigned int simple_guess_base(const char *cp) |
|
- | 45 | { |
|
- | 46 | if (cp[0] == '0') { |
|
- | 47 | if (TOLOWER(cp[1]) == 'x' && isxdigit(cp[2])) |
|
- | 48 | return 16; |
|
- | 49 | else |
|
- | 50 | return 8; |
|
- | 51 | } else { |
|
- | 52 | return 10; |
|
- | 53 | } |
|
- | 54 | } |
|
- | 55 | ||
- | 56 | /** |
|
- | 57 | * simple_strtoull - convert a string to an unsigned long long |
|
- | 58 | * @cp: The start of the string |
|
- | 59 | * @endp: A pointer to the end of the parsed string will be placed here |
|
- | 60 | * @base: The number base to use |
|
- | 61 | */ |
|
- | 62 | unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base) |
|
- | 63 | { |
|
Line 9... | Line 64... | ||
9 | #include "loc_incl.h" |
64 | unsigned long long result = 0; |
10 | 65 | ||
Line -... | Line 66... | ||
- | 66 | if (!base) |
|
- | 67 | base = simple_guess_base(cp); |
|
- | 68 | ||
- | 69 | if (base == 16 && cp[0] == '0' && TOLOWER(cp[1]) == 'x') |
|
- | 70 | cp += 2; |
|
- | 71 | ||
- | 72 | while (isxdigit(*cp)) { |
|
- | 73 | unsigned int value; |
|
- | 74 | ||
- | 75 | value = isdigit(*cp) ? *cp - '0' : TOLOWER(*cp) - 'a' + 10; |
|
- | 76 | if (value >= base) |
|
- | 77 | break; |
|
- | 78 | result = result * base + value; |
|
- | 79 | cp++; |
|
- | 80 | } |
|
- | 81 | if (endp) |
|
- | 82 | *endp = (char *)cp; |
|
- | 83 | ||
- | 84 | return result; |
|
- | 85 | } |
|
- | 86 | EXPORT_SYMBOL(simple_strtoull); |
|
- | 87 | ||
- | 88 | /** |
|
- | 89 | * simple_strtoul - convert a string to an unsigned long |
|
- | 90 | * @cp: The start of the string |
|
- | 91 | * @endp: A pointer to the end of the parsed string will be placed here |
|
- | 92 | * @base: The number base to use |
|
- | 93 | */ |
|
- | 94 | unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base) |
|
- | 95 | { |
|
- | 96 | return simple_strtoull(cp, endp, base); |
|
- | 97 | } |
|
- | 98 | EXPORT_SYMBOL(simple_strtoul); |
|
- | 99 | ||
- | 100 | /** |
|
- | 101 | * simple_strtol - convert a string to a signed long |
|
11 | #define putc(c, p) (--(p)->_count >= 0 ? \ |
102 | * @cp: The start of the string |
12 | (int) (*(p)->_ptr++ = (c)) : EOF) |
103 | * @endp: A pointer to the end of the parsed string will be placed here |
13 | 104 | * @base: The number base to use |
|
14 | int |
105 | */ |
15 | vsnprintf(char *s, unsigned n, const char *format, va_list arg) |
106 | long simple_strtol(const char *cp, char **endp, unsigned int base) |
Line 16... | Line -... | ||
16 | { |
- | |
17 | int retval; |
- | |
18 | FILE tmp_stream; |
- | |
19 | 107 | { |
|
- | 108 | if (*cp == '-') |
|
20 | tmp_stream._fd = -1; |
109 | return -simple_strtoul(cp + 1, endp, base); |
Line -... | Line 110... | ||
- | 110 | ||
- | 111 | return simple_strtoul(cp, endp, base); |
|
21 | tmp_stream._flags = _IOWRITE + _IONBF + _IOWRITING; |
112 | } |
- | 113 | EXPORT_SYMBOL(simple_strtol); |
|
22 | tmp_stream._buf = (unsigned char *) s; |
114 | |
- | 115 | /** |
|
- | 116 | * simple_strtoll - convert a string to a signed long long |
|
- | 117 | * @cp: The start of the string |
|
23 | tmp_stream._ptr = (unsigned char *) s; |
118 | * @endp: A pointer to the end of the parsed string will be placed here |
- | 119 | * @base: The number base to use |
|
Line 24... | Line 120... | ||
24 | tmp_stream._count = n-1; |
120 | */ |
25 | 121 | long long simple_strtoll(const char *cp, char **endp, unsigned int base) |
|
- | 122 | { |
|
Line 26... | Line 123... | ||
26 | retval = _doprnt(format, arg, &tmp_stream); |
123 | if (*cp == '-') |
- | 124 | return -simple_strtoull(cp + 1, endp, base); |
|
- | 125 | ||
- | 126 | return simple_strtoull(cp, endp, base); |
|
- | 127 | } |
|
- | 128 | EXPORT_SYMBOL(simple_strtoll); |
|
- | 129 | ||
- | 130 | /** |
|
- | 131 | * strict_strtoul - convert a string to an unsigned long strictly |
|
- | 132 | * @cp: The string to be converted |
|
- | 133 | * @base: The number base to use |
|
- | 134 | * @res: The converted result value |
|
- | 135 | * |
|
- | 136 | * strict_strtoul converts a string to an unsigned long only if the |
|
- | 137 | * string is really an unsigned long string, any string containing |
|
- | 138 | * any invalid char at the tail will be rejected and -EINVAL is returned, |
|
- | 139 | * only a newline char at the tail is acceptible because people generally |
|
- | 140 | * change a module parameter in the following way: |
|
- | 141 | * |
|
- | 142 | * echo 1024 > /sys/module/e1000/parameters/copybreak |
|
27 | tmp_stream._count = 1; |
143 | * |
- | 144 | * echo will append a newline to the tail. |
|
- | 145 | * |
|
28 | putc('\0',&tmp_stream); |
146 | * It returns 0 if conversion is successful and *res is set to the converted |
- | 147 | * value, otherwise it returns -EINVAL and *res is set to 0. |
|
- | 148 | * |
|
- | 149 | * simple_strtoul just ignores the successive invalid characters and |
|
- | 150 | * return the converted value of prefix part of the string. |
|
- | 151 | */ |
|
- | 152 | int strict_strtoul(const char *cp, unsigned int base, unsigned long *res) |
|
- | 153 | { |
|
29 | 154 | char *tail; |
|
- | 155 | unsigned long val; |
|
- | 156 | ||
- | 157 | *res = 0; |
|
- | 158 | if (!*cp) |
|
- | 159 | return -EINVAL; |
|
- | 160 | ||
- | 161 | val = simple_strtoul(cp, &tail, base); |
|
- | 162 | if (tail == cp) |
|
- | 163 | return -EINVAL; |
|
- | 164 | ||
- | 165 | if ((tail[0] == '\0') || (tail[0] == '\n' && tail[1] == '\0')) { |
|
- | 166 | *res = val; |
|
- | 167 | return 0; |
|
- | 168 | } |
|
- | 169 | ||
- | 170 | return -EINVAL; |
|
- | 171 | } |
|
- | 172 | EXPORT_SYMBOL(strict_strtoul); |
|
- | 173 | ||
- | 174 | /** |
|
- | 175 | * strict_strtol - convert a string to a long strictly |
|
- | 176 | * @cp: The string to be converted |
|
- | 177 | * @base: The number base to use |
|
- | 178 | * @res: The converted result value |
|
- | 179 | * |
|
- | 180 | * strict_strtol is similiar to strict_strtoul, but it allows the first |
|
- | 181 | * character of a string is '-'. |
|
- | 182 | * |
|
- | 183 | * It returns 0 if conversion is successful and *res is set to the converted |
|
- | 184 | * value, otherwise it returns -EINVAL and *res is set to 0. |
|
- | 185 | */ |
|
- | 186 | int strict_strtol(const char *cp, unsigned int base, long *res) |
|
- | 187 | { |
|
- | 188 | int ret; |
|
- | 189 | if (*cp == '-') { |
|
- | 190 | ret = strict_strtoul(cp + 1, base, (unsigned long *)res); |
|
- | 191 | if (!ret) |
|
- | 192 | *res = -(*res); |
|
- | 193 | } else { |
|
- | 194 | ret = strict_strtoul(cp, base, (unsigned long *)res); |
|
- | 195 | } |
|
- | 196 | ||
- | 197 | return ret; |
|
- | 198 | } |
|
- | 199 | EXPORT_SYMBOL(strict_strtol); |
|
- | 200 | ||
- | 201 | /** |
|
- | 202 | * strict_strtoull - convert a string to an unsigned long long strictly |
|
- | 203 | * @cp: The string to be converted |
|
- | 204 | * @base: The number base to use |
|
- | 205 | * @res: The converted result value |
|
- | 206 | * |
|
- | 207 | * strict_strtoull converts a string to an unsigned long long only if the |
|
- | 208 | * string is really an unsigned long long string, any string containing |
|
- | 209 | * any invalid char at the tail will be rejected and -EINVAL is returned, |
|
- | 210 | * only a newline char at the tail is acceptible because people generally |
|
- | 211 | * change a module parameter in the following way: |
|
- | 212 | * |
|
- | 213 | * echo 1024 > /sys/module/e1000/parameters/copybreak |
|
- | 214 | * |
|
- | 215 | * echo will append a newline to the tail of the string. |
|
- | 216 | * |
|
- | 217 | * It returns 0 if conversion is successful and *res is set to the converted |
|
- | 218 | * value, otherwise it returns -EINVAL and *res is set to 0. |
|
- | 219 | * |
|
- | 220 | * simple_strtoull just ignores the successive invalid characters and |
|
- | 221 | * return the converted value of prefix part of the string. |
|
- | 222 | */ |
|
- | 223 | int strict_strtoull(const char *cp, unsigned int base, unsigned long long *res) |
|
- | 224 | { |
|
- | 225 | char *tail; |
|
- | 226 | unsigned long long val; |
|
- | 227 | ||
- | 228 | *res = 0; |
|
- | 229 | if (!*cp) |
|
- | 230 | return -EINVAL; |
|
- | 231 | ||
- | 232 | val = simple_strtoull(cp, &tail, base); |
|
- | 233 | if (tail == cp) |
|
- | 234 | return -EINVAL; |
|
- | 235 | if ((tail[0] == '\0') || (tail[0] == '\n' && tail[1] == '\0')) { |
|
- | 236 | *res = val; |
|
- | 237 | return 0; |
|
- | 238 | } |
|
- | 239 | ||
- | 240 | return -EINVAL; |
|
- | 241 | } |
|
- | 242 | EXPORT_SYMBOL(strict_strtoull); |
|
- | 243 | ||
- | 244 | /** |
|
- | 245 | * strict_strtoll - convert a string to a long long strictly |
|
- | 246 | * @cp: The string to be converted |
|
- | 247 | * @base: The number base to use |
|
- | 248 | * @res: The converted result value |
|
- | 249 | * |
|
- | 250 | * strict_strtoll is similiar to strict_strtoull, but it allows the first |
|
- | 251 | * character of a string is '-'. |
|
- | 252 | * |
|
- | 253 | * It returns 0 if conversion is successful and *res is set to the converted |
|
- | 254 | * value, otherwise it returns -EINVAL and *res is set to 0. |
|
- | 255 | */ |
|
- | 256 | int strict_strtoll(const char *cp, unsigned int base, long long *res) |
|
- | 257 | { |
|
- | 258 | int ret; |
|
- | 259 | if (*cp == '-') { |
|
- | 260 | ret = strict_strtoull(cp + 1, base, (unsigned long long *)res); |
|
- | 261 | if (!ret) |
|
- | 262 | *res = -(*res); |
|
- | 263 | } else { |
|
- | 264 | ret = strict_strtoull(cp, base, (unsigned long long *)res); |
|
- | 265 | } |
|
- | 266 | ||
- | 267 | return ret; |
|
- | 268 | } |
|
- | 269 | EXPORT_SYMBOL(strict_strtoll); |
|
- | 270 | ||
- | 271 | static noinline_for_stack |
|
- | 272 | int skip_atoi(const char **s) |
|
- | 273 | { |
|
- | 274 | int i = 0; |
|
- | 275 | ||
- | 276 | while (isdigit(**s)) |
|
- | 277 | i = i*10 + *((*s)++) - '0'; |
|
- | 278 | ||
- | 279 | return i; |
|
- | 280 | } |
|
- | 281 | ||
- | 282 | /* Decimal conversion is by far the most typical, and is used |
|
- | 283 | * for /proc and /sys data. This directly impacts e.g. top performance |
|
- | 284 | * with many processes running. We optimize it for speed |
|
- | 285 | * using code from |
|
- | 286 | * http://www.cs.uiowa.edu/~jones/bcd/decimal.html |
|
- | 287 | * (with permission from the author, Douglas W. Jones). */ |
|
- | 288 | ||
- | 289 | /* Formats correctly any integer in [0,99999]. |
|
- | 290 | * Outputs from one to five digits depending on input. |
|
- | 291 | * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */ |
|
- | 292 | static noinline_for_stack |
|
- | 293 | char *put_dec_trunc(char *buf, unsigned q) |
|
- | 294 | { |
|
- | 295 | unsigned d3, d2, d1, d0; |
|
- | 296 | d1 = (q>>4) & 0xf; |
|
- | 297 | d2 = (q>>8) & 0xf; |
|
- | 298 | d3 = (q>>12); |
|
- | 299 | ||
- | 300 | d0 = 6*(d3 + d2 + d1) + (q & 0xf); |
|
- | 301 | q = (d0 * 0xcd) >> 11; |
|
- | 302 | d0 = d0 - 10*q; |
|
- | 303 | *buf++ = d0 + '0'; /* least significant digit */ |
|
- | 304 | d1 = q + 9*d3 + 5*d2 + d1; |
|
- | 305 | if (d1 != 0) { |
|
- | 306 | q = (d1 * 0xcd) >> 11; |
|
- | 307 | d1 = d1 - 10*q; |
|
- | 308 | *buf++ = d1 + '0'; /* next digit */ |
|
- | 309 | ||
- | 310 | d2 = q + 2*d2; |
|
- | 311 | if ((d2 != 0) || (d3 != 0)) { |
|
- | 312 | q = (d2 * 0xd) >> 7; |
|
- | 313 | d2 = d2 - 10*q; |
|
- | 314 | *buf++ = d2 + '0'; /* next digit */ |
|
- | 315 | ||
- | 316 | d3 = q + 4*d3; |
|
30 | return retval; |
317 | if (d3 != 0) { |
- | 318 | q = (d3 * 0xcd) >> 11; |
|
- | 319 | d3 = d3 - 10*q; |
|
- | 320 | *buf++ = d3 + '0'; /* next digit */ |
|
- | 321 | if (q != 0) |
|
- | 322 | *buf++ = q + '0'; /* most sign. digit */ |
|
- | 323 | } |
|
- | 324 | } |
|
- | 325 | } |
|
- | 326 | ||
- | 327 | return buf; |
|
- | 328 | } |
|
- | 329 | /* Same with if's removed. Always emits five digits */ |
|
- | 330 | static noinline_for_stack |
|
- | 331 | char *put_dec_full(char *buf, unsigned q) |
|
- | 332 | { |
|
- | 333 | /* BTW, if q is in [0,9999], 8-bit ints will be enough, */ |
|
- | 334 | /* but anyway, gcc produces better code with full-sized ints */ |
|
- | 335 | unsigned d3, d2, d1, d0; |
|
- | 336 | d1 = (q>>4) & 0xf; |
|
- | 337 | d2 = (q>>8) & 0xf; |
|
- | 338 | d3 = (q>>12); |
|
- | 339 | ||
- | 340 | /* |
|
- | 341 | * Possible ways to approx. divide by 10 |
|
- | 342 | * gcc -O2 replaces multiply with shifts and adds |
|
- | 343 | * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386) |
|
- | 344 | * (x * 0x67) >> 10: 1100111 |
|
- | 345 | * (x * 0x34) >> 9: 110100 - same |
|
- | 346 | * (x * 0x1a) >> 8: 11010 - same |
|
- | 347 | * (x * 0x0d) >> 7: 1101 - same, shortest code (on i386) |
|
- | 348 | */ |
|
- | 349 | d0 = 6*(d3 + d2 + d1) + (q & 0xf); |
|
- | 350 | q = (d0 * 0xcd) >> 11; |
|
- | 351 | d0 = d0 - 10*q; |
|
- | 352 | *buf++ = d0 + '0'; |
|
- | 353 | d1 = q + 9*d3 + 5*d2 + d1; |
|
- | 354 | q = (d1 * 0xcd) >> 11; |
|
- | 355 | d1 = d1 - 10*q; |
|
- | 356 | *buf++ = d1 + '0'; |
|
- | 357 | ||
- | 358 | d2 = q + 2*d2; |
|
- | 359 | q = (d2 * 0xd) >> 7; |
|
- | 360 | d2 = d2 - 10*q; |
|
- | 361 | *buf++ = d2 + '0'; |
|
- | 362 | ||
- | 363 | d3 = q + 4*d3; |
|
- | 364 | q = (d3 * 0xcd) >> 11; /* - shorter code */ |
|
- | 365 | /* q = (d3 * 0x67) >> 10; - would also work */ |
|
- | 366 | d3 = d3 - 10*q; |
|
- | 367 | *buf++ = d3 + '0'; |
|
- | 368 | *buf++ = q + '0'; |
|
- | 369 | ||
- | 370 | return buf; |
|
- | 371 | } |
|
- | 372 | /* No inlining helps gcc to use registers better */ |
|
- | 373 | static noinline_for_stack |
|
- | 374 | char *put_dec(char *buf, unsigned long long num) |
|
- | 375 | { |
|
- | 376 | while (1) { |
|
- | 377 | unsigned rem; |
|
- | 378 | if (num < 100000) |
|
- | 379 | return put_dec_trunc(buf, num); |
|
- | 380 | rem = do_div(num, 100000); |
|
- | 381 | buf = put_dec_full(buf, rem); |
|
- | 382 | } |
|
- | 383 | } |
|
- | 384 | ||
- | 385 | #define ZEROPAD 1 /* pad with zero */ |
|
- | 386 | #define SIGN 2 /* unsigned/signed long */ |
|
- | 387 | #define PLUS 4 /* show plus */ |
|
- | 388 | #define SPACE 8 /* space if plus */ |
|
- | 389 | #define LEFT 16 /* left justified */ |
|
- | 390 | #define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */ |
|
- | 391 | #define SPECIAL 64 /* prefix hex with "0x", octal with "0" */ |
|
- | 392 | ||
- | 393 | enum format_type { |
|
- | 394 | FORMAT_TYPE_NONE, /* Just a string part */ |
|
- | 395 | FORMAT_TYPE_WIDTH, |
|
- | 396 | FORMAT_TYPE_PRECISION, |
|
- | 397 | FORMAT_TYPE_CHAR, |
|
- | 398 | FORMAT_TYPE_STR, |
|
- | 399 | FORMAT_TYPE_PTR, |
|
- | 400 | FORMAT_TYPE_PERCENT_CHAR, |
|
- | 401 | FORMAT_TYPE_INVALID, |
|
- | 402 | FORMAT_TYPE_LONG_LONG, |
|
- | 403 | FORMAT_TYPE_ULONG, |
|
- | 404 | FORMAT_TYPE_LONG, |
|
- | 405 | FORMAT_TYPE_UBYTE, |
|
- | 406 | FORMAT_TYPE_BYTE, |
|
- | 407 | FORMAT_TYPE_USHORT, |
|
- | 408 | FORMAT_TYPE_SHORT, |
|
- | 409 | FORMAT_TYPE_UINT, |
|
- | 410 | FORMAT_TYPE_INT, |
|
- | 411 | FORMAT_TYPE_NRCHARS, |
|
- | 412 | FORMAT_TYPE_SIZE_T, |
|
- | 413 | FORMAT_TYPE_PTRDIFF |
|
- | 414 | }; |
|
- | 415 | ||
- | 416 | struct printf_spec { |
|
- | 417 | u8 type; /* format_type enum */ |
|
- | 418 | u8 flags; /* flags to number() */ |
|
- | 419 | u8 base; /* number base, 8, 10 or 16 only */ |
|
- | 420 | u8 qualifier; /* number qualifier, one of 'hHlLtzZ' */ |
|
- | 421 | s16 field_width; /* width of output field */ |
|
- | 422 | s16 precision; /* # of digits/chars */ |
|
- | 423 | }; |
|
- | 424 | ||
- | 425 | static noinline_for_stack |
|
- | 426 | char *number(char *buf, char *end, unsigned long long num, |
|
- | 427 | struct printf_spec spec) |
|
- | 428 | { |
|
- | 429 | /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ |
|
- | 430 | static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ |
|
- | 431 | ||
- | 432 | char tmp[66]; |
|
- | 433 | char sign; |
|
- | 434 | char locase; |
|
- | 435 | int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); |
|
- | 436 | int i; |
|
- | 437 | ||
- | 438 | /* locase = 0 or 0x20. ORing digits or letters with 'locase' |
|
- | 439 | * produces same digits or (maybe lowercased) letters */ |
|
- | 440 | locase = (spec.flags & SMALL); |
|
- | 441 | if (spec.flags & LEFT) |
|
- | 442 | spec.flags &= ~ZEROPAD; |
|
- | 443 | sign = 0; |
|
- | 444 | if (spec.flags & SIGN) { |
|
- | 445 | if ((signed long long)num < 0) { |
|
- | 446 | sign = '-'; |
|
- | 447 | num = -(signed long long)num; |
|
- | 448 | spec.field_width--; |
|
- | 449 | } else if (spec.flags & PLUS) { |
|
- | 450 | sign = '+'; |
|
- | 451 | spec.field_width--; |
|
- | 452 | } else if (spec.flags & SPACE) { |
|
- | 453 | sign = ' '; |
|
- | 454 | spec.field_width--; |
|
- | 455 | } |
|
- | 456 | } |
|
- | 457 | if (need_pfx) { |
|
- | 458 | spec.field_width--; |
|
- | 459 | if (spec.base == 16) |
|
- | 460 | spec.field_width--; |
|
- | 461 | } |
|
- | 462 | ||
- | 463 | /* generate full string in tmp[], in reverse order */ |
|
- | 464 | i = 0; |
|
- | 465 | if (num == 0) |
|
- | 466 | tmp[i++] = '0'; |
|
- | 467 | /* Generic code, for any base: |
|
- | 468 | else do { |
|
- | 469 | tmp[i++] = (digits[do_div(num,base)] | locase); |
|
- | 470 | } while (num != 0); |
|
- | 471 | */ |
|
- | 472 | else if (spec.base != 10) { /* 8 or 16 */ |
|
- | 473 | int mask = spec.base - 1; |
|
- | 474 | int shift = 3; |
|
- | 475 | ||
- | 476 | if (spec.base == 16) |
|
- | 477 | shift = 4; |
|
- | 478 | do { |
|
- | 479 | tmp[i++] = (digits[((unsigned char)num) & mask] | locase); |
|
- | 480 | num >>= shift; |
|
- | 481 | } while (num); |
|
- | 482 | } else { /* base 10 */ |
|
- | 483 | i = put_dec(tmp, num) - tmp; |
|
- | 484 | } |
|
- | 485 | ||
- | 486 | /* printing 100 using %2d gives "100", not "00" */ |
|
- | 487 | if (i > spec.precision) |
|
- | 488 | spec.precision = i; |
|
- | 489 | /* leading space padding */ |
|
- | 490 | spec.field_width -= spec.precision; |
|
- | 491 | if (!(spec.flags & (ZEROPAD+LEFT))) { |
|
- | 492 | while (--spec.field_width >= 0) { |
|
- | 493 | if (buf < end) |
|
- | 494 | *buf = ' '; |
|
- | 495 | ++buf; |
|
- | 496 | } |
|
- | 497 | } |
|
- | 498 | /* sign */ |
|
- | 499 | if (sign) { |
|
- | 500 | if (buf < end) |
|
- | 501 | *buf = sign; |
|
- | 502 | ++buf; |
|
- | 503 | } |
|
- | 504 | /* "0x" / "0" prefix */ |
|
- | 505 | if (need_pfx) { |
|
- | 506 | if (buf < end) |
|
- | 507 | *buf = '0'; |
|
- | 508 | ++buf; |
|
- | 509 | if (spec.base == 16) { |
|
- | 510 | if (buf < end) |
|
- | 511 | *buf = ('X' | locase); |
|
- | 512 | ++buf; |
|
- | 513 | } |
|
- | 514 | } |
|
- | 515 | /* zero or space padding */ |
|
- | 516 | if (!(spec.flags & LEFT)) { |
|
- | 517 | char c = (spec.flags & ZEROPAD) ? '0' : ' '; |
|
- | 518 | while (--spec.field_width >= 0) { |
|
- | 519 | if (buf < end) |
|
- | 520 | *buf = c; |
|
- | 521 | ++buf; |
|
- | 522 | } |
|
- | 523 | } |
|
- | 524 | /* hmm even more zero padding? */ |
|
- | 525 | while (i <= --spec.precision) { |
|
- | 526 | if (buf < end) |
|
- | 527 | *buf = '0'; |
|
- | 528 | ++buf; |
|
- | 529 | } |
|
- | 530 | /* actual digits of result */ |
|
- | 531 | while (--i >= 0) { |
|
- | 532 | if (buf < end) |
|
- | 533 | *buf = tmp[i]; |
|
- | 534 | ++buf; |
|
- | 535 | } |
|
- | 536 | /* trailing space padding */ |
|
- | 537 | while (--spec.field_width >= 0) { |
|
- | 538 | if (buf < end) |
|
- | 539 | *buf = ' '; |
|
- | 540 | ++buf; |
|
- | 541 | } |
|
- | 542 | ||
- | 543 | return buf; |
|
- | 544 | } |
|
- | 545 | ||
- | 546 | static noinline_for_stack |
|
- | 547 | char *string(char *buf, char *end, const char *s, struct printf_spec spec) |
|
- | 548 | { |
|
- | 549 | int len, i; |
|
- | 550 | ||
- | 551 | if ((unsigned long)s < PAGE_SIZE) |
|
- | 552 | s = "(null)"; |
|
- | 553 | ||
- | 554 | len = strnlen(s, spec.precision); |
|
- | 555 | ||
- | 556 | if (!(spec.flags & LEFT)) { |
|
- | 557 | while (len < spec.field_width--) { |
|
- | 558 | if (buf < end) |
|
- | 559 | *buf = ' '; |
|
- | 560 | ++buf; |
|
- | 561 | } |
|
- | 562 | } |
|
- | 563 | for (i = 0; i < len; ++i) { |
|
- | 564 | if (buf < end) |
|
- | 565 | *buf = *s; |
|
- | 566 | ++buf; ++s; |
|
- | 567 | } |
|
- | 568 | while (len < spec.field_width--) { |
|
- | 569 | if (buf < end) |
|
- | 570 | *buf = ' '; |
|
- | 571 | ++buf; |
|
- | 572 | } |
|
- | 573 | ||
- | 574 | return buf; |
|
- | 575 | } |
|
- | 576 | ||
- | 577 | static noinline_for_stack |
|
- | 578 | char *symbol_string(char *buf, char *end, void *ptr, |
|
- | 579 | struct printf_spec spec, char ext) |
|
- | 580 | { |
|
- | 581 | unsigned long value = (unsigned long) ptr; |
|
- | 582 | #ifdef CONFIG_KALLSYMS |
|
- | 583 | char sym[KSYM_SYMBOL_LEN]; |
|
- | 584 | if (ext != 'f' && ext != 's') |
|
- | 585 | sprint_symbol(sym, value); |
|
- | 586 | else |
|
- | 587 | kallsyms_lookup(value, NULL, NULL, NULL, sym); |
|
- | 588 | ||
- | 589 | return string(buf, end, sym, spec); |
|
- | 590 | #else |
|
- | 591 | spec.field_width = 2 * sizeof(void *); |
|
- | 592 | spec.flags |= SPECIAL | SMALL | ZEROPAD; |
|
- | 593 | spec.base = 16; |
|
- | 594 | ||
- | 595 | return number(buf, end, value, spec); |
|
- | 596 | #endif |
|
- | 597 | } |
|
- | 598 | ||
- | 599 | static noinline_for_stack |
|
- | 600 | char *resource_string(char *buf, char *end, struct resource *res, |
|
- | 601 | struct printf_spec spec, const char *fmt) |
|
- | 602 | { |
|
- | 603 | #ifndef IO_RSRC_PRINTK_SIZE |
|
- | 604 | #define IO_RSRC_PRINTK_SIZE 6 |
|
- | 605 | #endif |
|
- | 606 | ||
- | 607 | #ifndef MEM_RSRC_PRINTK_SIZE |
|
- | 608 | #define MEM_RSRC_PRINTK_SIZE 10 |
|
- | 609 | #endif |
|
- | 610 | static const struct printf_spec io_spec = { |
|
- | 611 | .base = 16, |
|
- | 612 | .field_width = IO_RSRC_PRINTK_SIZE, |
|
- | 613 | .precision = -1, |
|
- | 614 | .flags = SPECIAL | SMALL | ZEROPAD, |
|
- | 615 | }; |
|
- | 616 | static const struct printf_spec mem_spec = { |
|
- | 617 | .base = 16, |
|
- | 618 | .field_width = MEM_RSRC_PRINTK_SIZE, |
|
- | 619 | .precision = -1, |
|
- | 620 | .flags = SPECIAL | SMALL | ZEROPAD, |
|
- | 621 | }; |
|
- | 622 | static const struct printf_spec bus_spec = { |
|
- | 623 | .base = 16, |
|
- | 624 | .field_width = 2, |
|
- | 625 | .precision = -1, |
|
- | 626 | .flags = SMALL | ZEROPAD, |
|
- | 627 | }; |
|
- | 628 | static const struct printf_spec dec_spec = { |
|
- | 629 | .base = 10, |
|
- | 630 | .precision = -1, |
|
- | 631 | .flags = 0, |
|
- | 632 | }; |
|
- | 633 | static const struct printf_spec str_spec = { |
|
- | 634 | .field_width = -1, |
|
- | 635 | .precision = 10, |
|
- | 636 | .flags = LEFT, |
|
- | 637 | }; |
|
- | 638 | static const struct printf_spec flag_spec = { |
|
- | 639 | .base = 16, |
|
- | 640 | .precision = -1, |
|
- | 641 | .flags = SPECIAL | SMALL, |
|
- | 642 | }; |
|
- | 643 | ||
- | 644 | /* 32-bit res (sizeof==4): 10 chars in dec, 10 in hex ("0x" + 8) |
|
- | 645 | * 64-bit res (sizeof==8): 20 chars in dec, 18 in hex ("0x" + 16) */ |
|
- | 646 | #define RSRC_BUF_SIZE ((2 * sizeof(resource_size_t)) + 4) |
|
- | 647 | #define FLAG_BUF_SIZE (2 * sizeof(res->flags)) |
|
- | 648 | #define DECODED_BUF_SIZE sizeof("[mem - 64bit pref window disabled]") |
|
- | 649 | #define RAW_BUF_SIZE sizeof("[mem - flags 0x]") |
|
- | 650 | char sym[max(2*RSRC_BUF_SIZE + DECODED_BUF_SIZE, |
|
- | 651 | 2*RSRC_BUF_SIZE + FLAG_BUF_SIZE + RAW_BUF_SIZE)]; |
|
- | 652 | ||
- | 653 | char *p = sym, *pend = sym + sizeof(sym); |
|
- | 654 | int decode = (fmt[0] == 'R') ? 1 : 0; |
|
- | 655 | const struct printf_spec *specp; |
|
- | 656 | ||
- | 657 | *p++ = '['; |
|
- | 658 | if (res->flags & IORESOURCE_IO) { |
|
- | 659 | p = string(p, pend, "io ", str_spec); |
|
- | 660 | specp = &io_spec; |
|
- | 661 | } else if (res->flags & IORESOURCE_MEM) { |
|
- | 662 | p = string(p, pend, "mem ", str_spec); |
|
- | 663 | specp = &mem_spec; |
|
- | 664 | } else if (res->flags & IORESOURCE_IRQ) { |
|
- | 665 | p = string(p, pend, "irq ", str_spec); |
|
- | 666 | specp = &dec_spec; |
|
- | 667 | } else if (res->flags & IORESOURCE_DMA) { |
|
- | 668 | p = string(p, pend, "dma ", str_spec); |
|
- | 669 | specp = &dec_spec; |
|
- | 670 | } else if (res->flags & IORESOURCE_BUS) { |
|
- | 671 | p = string(p, pend, "bus ", str_spec); |
|
- | 672 | specp = &bus_spec; |
|
- | 673 | } else { |
|
- | 674 | p = string(p, pend, "??? ", str_spec); |
|
- | 675 | specp = &mem_spec; |
|
- | 676 | decode = 0; |
|
- | 677 | } |
|
- | 678 | p = number(p, pend, res->start, *specp); |
|
- | 679 | if (res->start != res->end) { |
|
- | 680 | *p++ = '-'; |
|
- | 681 | p = number(p, pend, res->end, *specp); |
|
- | 682 | } |
|
- | 683 | if (decode) { |
|
- | 684 | if (res->flags & IORESOURCE_MEM_64) |
|
- | 685 | p = string(p, pend, " 64bit", str_spec); |
|
- | 686 | if (res->flags & IORESOURCE_PREFETCH) |
|
- | 687 | p = string(p, pend, " pref", str_spec); |
|
- | 688 | if (res->flags & IORESOURCE_WINDOW) |
|
- | 689 | p = string(p, pend, " window", str_spec); |
|
- | 690 | if (res->flags & IORESOURCE_DISABLED) |
|
- | 691 | p = string(p, pend, " disabled", str_spec); |
|
- | 692 | } else { |
|
- | 693 | p = string(p, pend, " flags ", str_spec); |
|
- | 694 | p = number(p, pend, res->flags, flag_spec); |
|
- | 695 | } |
|
- | 696 | *p++ = ']'; |
|
- | 697 | *p = '\0'; |
|
- | 698 | ||
- | 699 | return string(buf, end, sym, spec); |
|
- | 700 | } |
|
- | 701 | ||
- | 702 | static noinline_for_stack |
|
- | 703 | char *mac_address_string(char *buf, char *end, u8 *addr, |
|
- | 704 | struct printf_spec spec, const char *fmt) |
|
- | 705 | { |
|
- | 706 | char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; |
|
- | 707 | char *p = mac_addr; |
|
- | 708 | int i; |
|
- | 709 | char separator; |
|
- | 710 | ||
- | 711 | if (fmt[1] == 'F') { /* FDDI canonical format */ |
|
- | 712 | separator = '-'; |
|
- | 713 | } else { |
|
- | 714 | separator = ':'; |
|
- | 715 | } |
|
- | 716 | ||
- | 717 | for (i = 0; i < 6; i++) { |
|
- | 718 | p = pack_hex_byte(p, addr[i]); |
|
- | 719 | if (fmt[0] == 'M' && i != 5) |
|
- | 720 | *p++ = separator; |
|
- | 721 | } |
|
- | 722 | *p = '\0'; |
|
- | 723 | ||
- | 724 | return string(buf, end, mac_addr, spec); |
|
- | 725 | } |
|
- | 726 | ||
- | 727 | static noinline_for_stack |
|
- | 728 | char *ip4_string(char *p, const u8 *addr, const char *fmt) |
|
- | 729 | { |
|
- | 730 | int i; |
|
- | 731 | bool leading_zeros = (fmt[0] == 'i'); |
|
- | 732 | int index; |
|
- | 733 | int step; |
|
- | 734 | ||
- | 735 | switch (fmt[2]) { |
|
- | 736 | case 'h': |
|
- | 737 | #ifdef __BIG_ENDIAN |
|
- | 738 | index = 0; |
|
- | 739 | step = 1; |
|
- | 740 | #else |
|
- | 741 | index = 3; |
|
- | 742 | step = -1; |
|
- | 743 | #endif |
|
- | 744 | break; |
|
- | 745 | case 'l': |
|
- | 746 | index = 3; |
|
- | 747 | step = -1; |
|
- | 748 | break; |
|
- | 749 | case 'n': |
|
- | 750 | case 'b': |
|
- | 751 | default: |
|
- | 752 | index = 0; |
|
- | 753 | step = 1; |
|
- | 754 | break; |
|
- | 755 | } |
|
- | 756 | for (i = 0; i < 4; i++) { |
|
- | 757 | char temp[3]; /* hold each IP quad in reverse order */ |
|
- | 758 | int digits = put_dec_trunc(temp, addr[index]) - temp; |
|
- | 759 | if (leading_zeros) { |
|
- | 760 | if (digits < 3) |
|
- | 761 | *p++ = '0'; |
|
- | 762 | if (digits < 2) |
|
- | 763 | *p++ = '0'; |
|
- | 764 | } |
|
- | 765 | /* reverse the digits in the quad */ |
|
- | 766 | while (digits--) |
|
- | 767 | *p++ = temp[digits]; |
|
- | 768 | if (i < 3) |
|
- | 769 | *p++ = '.'; |
|
- | 770 | index += step; |
|
- | 771 | } |
|
- | 772 | *p = '\0'; |
|
- | 773 | ||
- | 774 | return p; |
|
- | 775 | } |
|
- | 776 | ||
- | 777 | ||
- | 778 | static noinline_for_stack |
|
- | 779 | char *ip4_addr_string(char *buf, char *end, const u8 *addr, |
|
- | 780 | struct printf_spec spec, const char *fmt) |
|
- | 781 | { |
|
- | 782 | char ip4_addr[sizeof("255.255.255.255")]; |
|
- | 783 | ||
- | 784 | ip4_string(ip4_addr, addr, fmt); |
|
- | 785 | ||
- | 786 | return string(buf, end, ip4_addr, spec); |
|
- | 787 | } |
|
- | 788 | ||
- | 789 | ||
- | 790 | int kptr_restrict = 1; |
|
- | 791 | ||
- | 792 | /* |
|
- | 793 | * Show a '%p' thing. A kernel extension is that the '%p' is followed |
|
- | 794 | * by an extra set of alphanumeric characters that are extended format |
|
- | 795 | * specifiers. |
|
- | 796 | * |
|
- | 797 | * Right now we handle: |
|
- | 798 | * |
|
- | 799 | * - 'F' For symbolic function descriptor pointers with offset |
|
- | 800 | * - 'f' For simple symbolic function names without offset |
|
- | 801 | * - 'S' For symbolic direct pointers with offset |
|
- | 802 | * - 's' For symbolic direct pointers without offset |
|
- | 803 | * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref] |
|
- | 804 | * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201] |
|
- | 805 | * - 'M' For a 6-byte MAC address, it prints the address in the |
|
- | 806 | * usual colon-separated hex notation |
|
- | 807 | * - 'm' For a 6-byte MAC address, it prints the hex address without colons |
|
- | 808 | * - 'MF' For a 6-byte MAC FDDI address, it prints the address |
|
- | 809 | * with a dash-separated hex notation |
|
- | 810 | * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way |
|
- | 811 | * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) |
|
- | 812 | * IPv6 uses colon separated network-order 16 bit hex with leading 0's |
|
- | 813 | * - 'i' [46] for 'raw' IPv4/IPv6 addresses |
|
- | 814 | * IPv6 omits the colons (01020304...0f) |
|
- | 815 | * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006) |
|
- | 816 | * - '[Ii]4[hnbl]' IPv4 addresses in host, network, big or little endian order |
|
- | 817 | * - 'I6c' for IPv6 addresses printed as specified by |
|
- | 818 | * http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00 |
|
- | 819 | * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form |
|
- | 820 | * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" |
|
- | 821 | * Options for %pU are: |
|
- | 822 | * b big endian lower case hex (default) |
|
- | 823 | * B big endian UPPER case hex |
|
- | 824 | * l little endian lower case hex |
|
- | 825 | * L little endian UPPER case hex |
|
- | 826 | * big endian output byte order is: |
|
- | 827 | * [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15] |
|
- | 828 | * little endian output byte order is: |
|
- | 829 | * [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15] |
|
- | 830 | * - 'V' For a struct va_format which contains a format string * and va_list *, |
|
- | 831 | * call vsnprintf(->format, *->va_list). |
|
- | 832 | * Implements a "recursive vsnprintf". |
|
- | 833 | * Do not use this feature without some mechanism to verify the |
|
- | 834 | * correctness of the format string and va_list arguments. |
|
- | 835 | * - 'K' For a kernel pointer that should be hidden from unprivileged users |
|
- | 836 | * |
|
- | 837 | * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 |
|
- | 838 | * function pointers are really function descriptors, which contain a |
|
- | 839 | * pointer to the real address. |
|
- | 840 | */ |
|
- | 841 | static noinline_for_stack |
|
- | 842 | char *pointer(const char *fmt, char *buf, char *end, void *ptr, |
|
- | 843 | struct printf_spec spec) |
|
- | 844 | { |
|
- | 845 | if (!ptr) { |
|
- | 846 | /* |
|
- | 847 | * Print (null) with the same width as a pointer so it makes |
|
- | 848 | * tabular output look nice. |
|
- | 849 | */ |
|
- | 850 | if (spec.field_width == -1) |
|
- | 851 | spec.field_width = 2 * sizeof(void *); |
|
- | 852 | return string(buf, end, "(null)", spec); |
|
- | 853 | } |
|
- | 854 | ||
- | 855 | switch (*fmt) { |
|
- | 856 | case 'F': |
|
- | 857 | case 'f': |
|
- | 858 | ptr = dereference_function_descriptor(ptr); |
|
- | 859 | /* Fallthrough */ |
|
- | 860 | case 'S': |
|
- | 861 | case 's': |
|
- | 862 | return symbol_string(buf, end, ptr, spec, *fmt); |
|
- | 863 | case 'R': |
|
- | 864 | case 'r': |
|
- | 865 | return resource_string(buf, end, ptr, spec, fmt); |
|
- | 866 | case 'M': /* Colon separated: 00:01:02:03:04:05 */ |
|
- | 867 | case 'm': /* Contiguous: 000102030405 */ |
|
- | 868 | /* [mM]F (FDDI, bit reversed) */ |
|
- | 869 | return mac_address_string(buf, end, ptr, spec, fmt); |
|
- | 870 | case 'I': /* Formatted IP supported |
|
- | 871 | * 4: 1.2.3.4 |
|
- | 872 | * 6: 0001:0203:...:0708 |
|
- | 873 | * 6c: 1::708 or 1::1.2.3.4 |
|
- | 874 | */ |
|
- | 875 | case 'i': /* Contiguous: |
|
- | 876 | * 4: 001.002.003.004 |
|
- | 877 | * 6: 000102...0f |
|
- | 878 | */ |
|
- | 879 | switch (fmt[1]) { |
|
- | 880 | case '4': |
|
- | 881 | return ip4_addr_string(buf, end, ptr, spec, fmt); |
|
- | 882 | } |
|
- | 883 | break; |
|
- | 884 | case 'V': |
|
- | 885 | return buf + vsnprintf(buf, end - buf, |
|
- | 886 | ((struct va_format *)ptr)->fmt, |
|
- | 887 | *(((struct va_format *)ptr)->va)); |
|
- | 888 | } |
|
- | 889 | spec.flags |= SMALL; |
|
- | 890 | if (spec.field_width == -1) { |
|
- | 891 | spec.field_width = 2 * sizeof(void *); |
|
- | 892 | spec.flags |= ZEROPAD; |
|
- | 893 | } |
|
- | 894 | spec.base = 16; |
|
- | 895 | ||
- | 896 | return number(buf, end, (unsigned long) ptr, spec); |
|
- | 897 | } |
|
- | 898 | ||
- | 899 | /* |
|
- | 900 | * Helper function to decode printf style format. |
|
- | 901 | * Each call decode a token from the format and return the |
|
- | 902 | * number of characters read (or likely the delta where it wants |
|
- | 903 | * to go on the next call). |
|
- | 904 | * The decoded token is returned through the parameters |
|
- | 905 | * |
|
- | 906 | * 'h', 'l', or 'L' for integer fields |
|
- | 907 | * 'z' support added 23/7/1999 S.H. |
|
- | 908 | * 'z' changed to 'Z' --davidm 1/25/99 |
|
- | 909 | * 't' added for ptrdiff_t |
|
- | 910 | * |
|
- | 911 | * @fmt: the format string |
|
- | 912 | * @type of the token returned |
|
- | 913 | * @flags: various flags such as +, -, # tokens.. |
|
- | 914 | * @field_width: overwritten width |
|
- | 915 | * @base: base of the number (octal, hex, ...) |
|
- | 916 | * @precision: precision of a number |
|
- | 917 | * @qualifier: qualifier of a number (long, size_t, ...) |
|
- | 918 | */ |
|
- | 919 | static noinline_for_stack |
|
- | 920 | int format_decode(const char *fmt, struct printf_spec *spec) |
|
- | 921 | { |
|
- | 922 | const char *start = fmt; |
|
- | 923 | ||
- | 924 | /* we finished early by reading the field width */ |
|
- | 925 | if (spec->type == FORMAT_TYPE_WIDTH) { |
|
- | 926 | if (spec->field_width < 0) { |
|
- | 927 | spec->field_width = -spec->field_width; |
|
- | 928 | spec->flags |= LEFT; |
|
- | 929 | } |
|
- | 930 | spec->type = FORMAT_TYPE_NONE; |
|
- | 931 | goto precision; |
|
- | 932 | } |
|
- | 933 | ||
- | 934 | /* we finished early by reading the precision */ |
|
- | 935 | if (spec->type == FORMAT_TYPE_PRECISION) { |
|
- | 936 | if (spec->precision < 0) |
|
- | 937 | spec->precision = 0; |
|
- | 938 | ||
- | 939 | spec->type = FORMAT_TYPE_NONE; |
|
- | 940 | goto qualifier; |
|
- | 941 | } |
|
- | 942 | ||
- | 943 | /* By default */ |
|
- | 944 | spec->type = FORMAT_TYPE_NONE; |
|
- | 945 | ||
- | 946 | for (; *fmt ; ++fmt) { |
|
- | 947 | if (*fmt == '%') |
|
- | 948 | break; |
|
- | 949 | } |
|
- | 950 | ||
- | 951 | /* Return the current non-format string */ |
|
- | 952 | if (fmt != start || !*fmt) |
|
- | 953 | return fmt - start; |
|
- | 954 | ||
- | 955 | /* Process flags */ |
|
- | 956 | spec->flags = 0; |
|
- | 957 | ||
- | 958 | while (1) { /* this also skips first '%' */ |
|
- | 959 | bool found = true; |
|
- | 960 | ||
- | 961 | ++fmt; |
|
- | 962 | ||
- | 963 | switch (*fmt) { |
|
- | 964 | case '-': spec->flags |= LEFT; break; |
|
- | 965 | case '+': spec->flags |= PLUS; break; |
|
- | 966 | case ' ': spec->flags |= SPACE; break; |
|
- | 967 | case '#': spec->flags |= SPECIAL; break; |
|
- | 968 | case '0': spec->flags |= ZEROPAD; break; |
|
- | 969 | default: found = false; |
|
- | 970 | } |
|
- | 971 | ||
- | 972 | if (!found) |
|
- | 973 | break; |
|
- | 974 | } |
|
- | 975 | ||
- | 976 | /* get field width */ |
|
- | 977 | spec->field_width = -1; |
|
- | 978 | ||
- | 979 | if (isdigit(*fmt)) |
|
- | 980 | spec->field_width = skip_atoi(&fmt); |
|
- | 981 | else if (*fmt == '*') { |
|
- | 982 | /* it's the next argument */ |
|
- | 983 | spec->type = FORMAT_TYPE_WIDTH; |
|
- | 984 | return ++fmt - start; |
|
- | 985 | } |
|
- | 986 | ||
- | 987 | precision: |
|
- | 988 | /* get the precision */ |
|
- | 989 | spec->precision = -1; |
|
- | 990 | if (*fmt == '.') { |
|
- | 991 | ++fmt; |
|
- | 992 | if (isdigit(*fmt)) { |
|
- | 993 | spec->precision = skip_atoi(&fmt); |
|
- | 994 | if (spec->precision < 0) |
|
- | 995 | spec->precision = 0; |
|
- | 996 | } else if (*fmt == '*') { |
|
- | 997 | /* it's the next argument */ |
|
- | 998 | spec->type = FORMAT_TYPE_PRECISION; |
|
- | 999 | return ++fmt - start; |
|
- | 1000 | } |
|
- | 1001 | } |
|
- | 1002 | ||
- | 1003 | qualifier: |
|
- | 1004 | /* get the conversion qualifier */ |
|
- | 1005 | spec->qualifier = -1; |
|
- | 1006 | if (*fmt == 'h' || TOLOWER(*fmt) == 'l' || |
|
- | 1007 | TOLOWER(*fmt) == 'z' || *fmt == 't') { |
|
- | 1008 | spec->qualifier = *fmt++; |
|
- | 1009 | if (unlikely(spec->qualifier == *fmt)) { |
|
- | 1010 | if (spec->qualifier == 'l') { |
|
- | 1011 | spec->qualifier = 'L'; |
|
- | 1012 | ++fmt; |
|
- | 1013 | } else if (spec->qualifier == 'h') { |
|
- | 1014 | spec->qualifier = 'H'; |
|
- | 1015 | ++fmt; |
|
- | 1016 | } |
|
- | 1017 | } |
|
- | 1018 | } |
|
- | 1019 | ||
- | 1020 | /* default base */ |
|
- | 1021 | spec->base = 10; |
|
- | 1022 | switch (*fmt) { |
|
- | 1023 | case 'c': |
|
- | 1024 | spec->type = FORMAT_TYPE_CHAR; |
|
- | 1025 | return ++fmt - start; |
|
- | 1026 | ||
- | 1027 | case 's': |
|
- | 1028 | spec->type = FORMAT_TYPE_STR; |
|
- | 1029 | return ++fmt - start; |
|
- | 1030 | ||
- | 1031 | case 'p': |
|
- | 1032 | spec->type = FORMAT_TYPE_PTR; |
|
- | 1033 | return fmt - start; |
|
- | 1034 | /* skip alnum */ |
|
- | 1035 | ||
- | 1036 | case 'n': |
|
- | 1037 | spec->type = FORMAT_TYPE_NRCHARS; |
|
- | 1038 | return ++fmt - start; |
|
- | 1039 | ||
- | 1040 | case '%': |
|
- | 1041 | spec->type = FORMAT_TYPE_PERCENT_CHAR; |
|
- | 1042 | return ++fmt - start; |
|
- | 1043 | ||
- | 1044 | /* integer number formats - set up the flags and "break" */ |
|
- | 1045 | case 'o': |
|
- | 1046 | spec->base = 8; |
|
- | 1047 | break; |
|
- | 1048 | ||
- | 1049 | case 'x': |
|
- | 1050 | spec->flags |= SMALL; |
|
- | 1051 | ||
- | 1052 | case 'X': |
|
- | 1053 | spec->base = 16; |
|
- | 1054 | break; |
|
- | 1055 | ||
- | 1056 | case 'd': |
|
- | 1057 | case 'i': |
|
- | 1058 | spec->flags |= SIGN; |
|
- | 1059 | case 'u': |
|
- | 1060 | break; |
|
- | 1061 | ||
- | 1062 | default: |
|
- | 1063 | spec->type = FORMAT_TYPE_INVALID; |
|
- | 1064 | return fmt - start; |
|
- | 1065 | } |
|
- | 1066 | ||
- | 1067 | if (spec->qualifier == 'L') |
|
- | 1068 | spec->type = FORMAT_TYPE_LONG_LONG; |
|
- | 1069 | else if (spec->qualifier == 'l') { |
|
- | 1070 | if (spec->flags & SIGN) |
|
- | 1071 | spec->type = FORMAT_TYPE_LONG; |
|
- | 1072 | else |
|
- | 1073 | spec->type = FORMAT_TYPE_ULONG; |
|
- | 1074 | } else if (TOLOWER(spec->qualifier) == 'z') { |
|
- | 1075 | spec->type = FORMAT_TYPE_SIZE_T; |
|
- | 1076 | } else if (spec->qualifier == 't') { |
|
- | 1077 | spec->type = FORMAT_TYPE_PTRDIFF; |
|
- | 1078 | } else if (spec->qualifier == 'H') { |
|
- | 1079 | if (spec->flags & SIGN) |
|
- | 1080 | spec->type = FORMAT_TYPE_BYTE; |
|
- | 1081 | else |
|
- | 1082 | spec->type = FORMAT_TYPE_UBYTE; |
|
- | 1083 | } else if (spec->qualifier == 'h') { |
|
- | 1084 | if (spec->flags & SIGN) |
|
- | 1085 | spec->type = FORMAT_TYPE_SHORT; |
|
- | 1086 | else |
|
- | 1087 | spec->type = FORMAT_TYPE_USHORT; |
|
- | 1088 | } else { |
|
- | 1089 | if (spec->flags & SIGN) |
|
- | 1090 | spec->type = FORMAT_TYPE_INT; |
|
- | 1091 | else |
|
- | 1092 | spec->type = FORMAT_TYPE_UINT; |
|
- | 1093 | } |
|
- | 1094 | ||
- | 1095 | return ++fmt - start; |
|
- | 1096 | } |
|
- | 1097 | ||
- | 1098 | /** |
|
- | 1099 | * vsnprintf - Format a string and place it in a buffer |
|
- | 1100 | * @buf: The buffer to place the result into |
|
- | 1101 | * @size: The size of the buffer, including the trailing null space |
|
- | 1102 | * @fmt: The format string to use |
|
- | 1103 | * @args: Arguments for the format string |
|
- | 1104 | * |
|
- | 1105 | * This function follows C99 vsnprintf, but has some extensions: |
|
- | 1106 | * %pS output the name of a text symbol with offset |
|
- | 1107 | * %ps output the name of a text symbol without offset |
|
- | 1108 | * %pF output the name of a function pointer with its offset |
|
- | 1109 | * %pf output the name of a function pointer without its offset |
|
- | 1110 | * %pR output the address range in a struct resource with decoded flags |
|
- | 1111 | * %pr output the address range in a struct resource with raw flags |
|
- | 1112 | * %pM output a 6-byte MAC address with colons |
|
- | 1113 | * %pm output a 6-byte MAC address without colons |
|
- | 1114 | * %pI4 print an IPv4 address without leading zeros |
|
- | 1115 | * %pi4 print an IPv4 address with leading zeros |
|
- | 1116 | * %pI6 print an IPv6 address with colons |
|
- | 1117 | * %pi6 print an IPv6 address without colons |
|
- | 1118 | * %pI6c print an IPv6 address as specified by |
|
- | 1119 | * http://tools.ietf.org/html/draft-ietf-6man-text-addr-representation-00 |
|
- | 1120 | * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper |
|
- | 1121 | * case. |
|
- | 1122 | * %n is ignored |
|
- | 1123 | * |
|
- | 1124 | * The return value is the number of characters which would |
|
- | 1125 | * be generated for the given input, excluding the trailing |
|
- | 1126 | * '\0', as per ISO C99. If you want to have the exact |
|
- | 1127 | * number of characters written into @buf as return value |
|
- | 1128 | * (not including the trailing '\0'), use vscnprintf(). If the |
|
- | 1129 | * return is greater than or equal to @size, the resulting |
|
- | 1130 | * string is truncated. |
|
- | 1131 | * |
|
- | 1132 | * Call this function if you are already dealing with a va_list. |
|
- | 1133 | * You probably want snprintf() instead. |
|
- | 1134 | */ |
|
- | 1135 | int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) |
|
- | 1136 | { |
|
- | 1137 | unsigned long long num; |
|
- | 1138 | char *str, *end; |
|
- | 1139 | struct printf_spec spec = {0}; |
|
- | 1140 | ||
- | 1141 | /* Reject out-of-range values early. Large positive sizes are |
|
- | 1142 | used for unknown buffer sizes. */ |
|
- | 1143 | if ((int)size < 0) |
|
- | 1144 | return 0; |
|
- | 1145 | ||
- | 1146 | str = buf; |
|
- | 1147 | end = buf + size; |
|
- | 1148 | ||
- | 1149 | /* Make sure end is always >= buf */ |
|
- | 1150 | if (end < buf) { |
|
- | 1151 | end = ((void *)-1); |
|
- | 1152 | size = end - buf; |
|
- | 1153 | } |
|
- | 1154 | ||
- | 1155 | while (*fmt) { |
|
- | 1156 | const char *old_fmt = fmt; |
|
- | 1157 | int read = format_decode(fmt, &spec); |
|
- | 1158 | ||
- | 1159 | fmt += read; |
|
- | 1160 | ||
- | 1161 | switch (spec.type) { |
|
- | 1162 | case FORMAT_TYPE_NONE: { |
|
- | 1163 | int copy = read; |
|
- | 1164 | if (str < end) { |
|
- | 1165 | if (copy > end - str) |
|
- | 1166 | copy = end - str; |
|
- | 1167 | memcpy(str, old_fmt, copy); |
|
- | 1168 | } |
|
- | 1169 | str += read; |
|
- | 1170 | break; |
|
- | 1171 | } |
|
- | 1172 | ||
- | 1173 | case FORMAT_TYPE_WIDTH: |
|
- | 1174 | spec.field_width = va_arg(args, int); |
|
- | 1175 | break; |
|
- | 1176 | ||
- | 1177 | case FORMAT_TYPE_PRECISION: |
|
- | 1178 | spec.precision = va_arg(args, int); |
|
- | 1179 | break; |
|
- | 1180 | ||
- | 1181 | case FORMAT_TYPE_CHAR: { |
|
- | 1182 | char c; |
|
- | 1183 | ||
- | 1184 | if (!(spec.flags & LEFT)) { |
|
- | 1185 | while (--spec.field_width > 0) { |
|
- | 1186 | if (str < end) |
|
- | 1187 | *str = ' '; |
|
- | 1188 | ++str; |
|
- | 1189 | ||
- | 1190 | } |
|
- | 1191 | } |
|
- | 1192 | c = (unsigned char) va_arg(args, int); |
|
- | 1193 | if (str < end) |
|
- | 1194 | *str = c; |
|
- | 1195 | ++str; |
|
- | 1196 | while (--spec.field_width > 0) { |
|
- | 1197 | if (str < end) |
|
- | 1198 | *str = ' '; |
|
- | 1199 | ++str; |
|
- | 1200 | } |
|
- | 1201 | break; |
|
- | 1202 | } |
|
- | 1203 | ||
- | 1204 | case FORMAT_TYPE_STR: |
|
- | 1205 | str = string(str, end, va_arg(args, char *), spec); |
|
- | 1206 | break; |
|
- | 1207 | ||
- | 1208 | case FORMAT_TYPE_PTR: |
|
- | 1209 | str = pointer(fmt+1, str, end, va_arg(args, void *), |
|
- | 1210 | spec); |
|
- | 1211 | while (isalnum(*fmt)) |
|
- | 1212 | fmt++; |
|
- | 1213 | break; |
|
- | 1214 | ||
- | 1215 | case FORMAT_TYPE_PERCENT_CHAR: |
|
- | 1216 | if (str < end) |
|
- | 1217 | *str = '%'; |
|
- | 1218 | ++str; |
|
- | 1219 | break; |
|
- | 1220 | ||
- | 1221 | case FORMAT_TYPE_INVALID: |
|
- | 1222 | if (str < end) |
|
- | 1223 | *str = '%'; |
|
- | 1224 | ++str; |
|
- | 1225 | break; |
|
- | 1226 | ||
- | 1227 | case FORMAT_TYPE_NRCHARS: { |
|
- | 1228 | u8 qualifier = spec.qualifier; |
|
- | 1229 | ||
- | 1230 | if (qualifier == 'l') { |
|
- | 1231 | long *ip = va_arg(args, long *); |
|
- | 1232 | *ip = (str - buf); |
|
- | 1233 | } else if (TOLOWER(qualifier) == 'z') { |
|
- | 1234 | size_t *ip = va_arg(args, size_t *); |
|
- | 1235 | *ip = (str - buf); |
|
- | 1236 | } else { |
|
- | 1237 | int *ip = va_arg(args, int *); |
|
- | 1238 | *ip = (str - buf); |
|
- | 1239 | } |
|
- | 1240 | break; |
|
- | 1241 | } |
|
- | 1242 | ||
- | 1243 | default: |
|
- | 1244 | switch (spec.type) { |
|
- | 1245 | case FORMAT_TYPE_LONG_LONG: |
|
- | 1246 | num = va_arg(args, long long); |
|
- | 1247 | break; |
|
- | 1248 | case FORMAT_TYPE_ULONG: |
|
- | 1249 | num = va_arg(args, unsigned long); |
|
- | 1250 | break; |
|
- | 1251 | case FORMAT_TYPE_LONG: |
|
- | 1252 | num = va_arg(args, long); |
|
- | 1253 | break; |
|
- | 1254 | case FORMAT_TYPE_SIZE_T: |
|
- | 1255 | num = va_arg(args, size_t); |
|
- | 1256 | break; |
|
- | 1257 | case FORMAT_TYPE_PTRDIFF: |
|
- | 1258 | num = va_arg(args, ptrdiff_t); |
|
- | 1259 | break; |
|
- | 1260 | case FORMAT_TYPE_UBYTE: |
|
- | 1261 | num = (unsigned char) va_arg(args, int); |
|
- | 1262 | break; |
|
- | 1263 | case FORMAT_TYPE_BYTE: |
|
- | 1264 | num = (signed char) va_arg(args, int); |
|
- | 1265 | break; |
|
- | 1266 | case FORMAT_TYPE_USHORT: |
|
- | 1267 | num = (unsigned short) va_arg(args, int); |
|
- | 1268 | break; |
|
- | 1269 | case FORMAT_TYPE_SHORT: |
|
- | 1270 | num = (short) va_arg(args, int); |
|
- | 1271 | break; |
|
- | 1272 | case FORMAT_TYPE_INT: |
|
- | 1273 | num = (int) va_arg(args, int); |
|
- | 1274 | break; |
|
- | 1275 | default: |
|
- | 1276 | num = va_arg(args, unsigned int); |
|
- | 1277 | } |
|
- | 1278 | ||
- | 1279 | str = number(str, end, num, spec); |
|
- | 1280 | } |
|
- | 1281 | } |
|
- | 1282 | ||
- | 1283 | if (size > 0) { |
|
- | 1284 | if (str < end) |
|
- | 1285 | *str = '\0'; |
|
- | 1286 | else |
|
- | 1287 | end[-1] = '\0'; |
|
- | 1288 | } |
|
- | 1289 | ||
- | 1290 | /* the trailing null byte doesn't count towards the total */ |
|
- | 1291 | return str-buf; |
|
- | 1292 | ||
- | 1293 | } |
|
- | 1294 | EXPORT_SYMBOL(vsnprintf); |
|
- | 1295 | ||
- | 1296 | int vsprintf(char *buf, const char *fmt, va_list args) |
|
- | 1297 | { |
|
- | 1298 | return vsnprintf(buf, INT_MAX, fmt, args); |
|
- | 1299 | } |
|
- | 1300 | ||
- | 1301 | ||
- | 1302 | /** |
|
- | 1303 | * snprintf - Format a string and place it in a buffer |
|
- | 1304 | * @buf: The buffer to place the result into |
|
- | 1305 | * @size: The size of the buffer, including the trailing null space |
|
- | 1306 | * @fmt: The format string to use |
|
- | 1307 | * @...: Arguments for the format string |
|
- | 1308 | * |
|
- | 1309 | * The return value is the number of characters which would be |
|
- | 1310 | * generated for the given input, excluding the trailing null, |
|
- | 1311 | * as per ISO C99. If the return is greater than or equal to |
|
- | 1312 | * @size, the resulting string is truncated. |
|
- | 1313 | * |
|
- | 1314 | * See the vsnprintf() documentation for format string extensions over C99. |
|
- | 1315 | */ |
|
- | 1316 | int snprintf(char *buf, size_t size, const char *fmt, ...) |
|
- | 1317 | { |
|
- | 1318 | va_list args; |
|
- | 1319 | int i; |
|
- | 1320 | ||
- | 1321 | va_start(args, fmt); |
|
- | 1322 | i = vsnprintf(buf, size, fmt, args); |
|
- | 1323 | va_end(args); |
|
- | 1324 | ||
- | 1325 | return i; |
|
- | 1326 | } |
|
- | 1327 | EXPORT_SYMBOL(snprintf); |
|
- | 1328 | ||
- | 1329 | ||
- | 1330 | /** |
|
- | 1331 | * sprintf - Format a string and place it in a buffer |
|
- | 1332 | * @buf: The buffer to place the result into |
|
- | 1333 | * @fmt: The format string to use |
|
- | 1334 | * @...: Arguments for the format string |
|
- | 1335 | * |
|
- | 1336 | * The function returns the number of characters written |
|
- | 1337 | * into @buf. Use snprintf() or scnprintf() in order to avoid |
|
- | 1338 | * buffer overflows. |
|
- | 1339 | * |
|
- | 1340 | * See the vsnprintf() documentation for format string extensions over C99. |
|
- | 1341 | */ |
|
- | 1342 | int sprintf(char *buf, const char *fmt, ...) |
|
- | 1343 | { |
|
- | 1344 | va_list args; |
|
- | 1345 | int i; |
|
- | 1346 |