vsprintf.c (fb031937a86874e6d663542bdbd83e310c13610e) | vsprintf.c (6c4bcd8a46a98856c06ca3ba8a80f03a61e23960) |
---|---|
1// SPDX-License-Identifier: GPL-2.0-only 2/* -*- linux-c -*- ------------------------------------------------------- * 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 * Copyright 2007 rPath, Inc. - All Rights Reserved 6 * 7 * ----------------------------------------------------------------------- */ 8 9/* 10 * Oh, it's a waste of space, but oh-so-yummy for debugging. 11 */ 12 13#include <stdarg.h> 14 15#include <linux/compiler.h> 16#include <linux/ctype.h> | 1// SPDX-License-Identifier: GPL-2.0-only 2/* -*- linux-c -*- ------------------------------------------------------- * 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 * Copyright 2007 rPath, Inc. - All Rights Reserved 6 * 7 * ----------------------------------------------------------------------- */ 8 9/* 10 * Oh, it's a waste of space, but oh-so-yummy for debugging. 11 */ 12 13#include <stdarg.h> 14 15#include <linux/compiler.h> 16#include <linux/ctype.h> |
17#include <linux/kernel.h> |
|
17#include <linux/limits.h> 18#include <linux/string.h> 19 | 18#include <linux/limits.h> 19#include <linux/string.h> 20 |
20static int skip_atoi(const char **s) | 21static 22int skip_atoi(const char **s) |
21{ 22 int i = 0; 23 24 while (isdigit(**s)) 25 i = i * 10 + *((*s)++) - '0'; 26 return i; 27} 28 29/* 30 * put_dec_full4 handles numbers in the range 0 <= r < 10000. 31 * The multiplier 0xccd is round(2^15/10), and the approximation 32 * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389. 33 */ 34static | 23{ 24 int i = 0; 25 26 while (isdigit(**s)) 27 i = i * 10 + *((*s)++) - '0'; 28 return i; 29} 30 31/* 32 * put_dec_full4 handles numbers in the range 0 <= r < 10000. 33 * The multiplier 0xccd is round(2^15/10), and the approximation 34 * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389. 35 */ 36static |
35void put_dec_full4(char *buf, unsigned int r) | 37void put_dec_full4(char *end, unsigned int r) |
36{ 37 int i; 38 39 for (i = 0; i < 3; i++) { 40 unsigned int q = (r * 0xccd) >> 15; | 38{ 39 int i; 40 41 for (i = 0; i < 3; i++) { 42 unsigned int q = (r * 0xccd) >> 15; |
41 *buf++ = '0' + (r - q * 10); | 43 *--end = '0' + (r - q * 10); |
42 r = q; 43 } | 44 r = q; 45 } |
44 *buf++ = '0' + r; | 46 *--end = '0' + r; |
45} 46 47/* put_dec is copied from lib/vsprintf.c with small modifications */ 48 49/* 50 * Call put_dec_full4 on x % 10000, return x / 10000. 51 * The approximation x/10000 == (x * 0x346DC5D7) >> 43 52 * holds for all x < 1,128,869,999. The largest value this 53 * helper will ever be asked to convert is 1,125,520,955. 54 * (second call in the put_dec code, assuming n is all-ones). 55 */ 56static | 47} 48 49/* put_dec is copied from lib/vsprintf.c with small modifications */ 50 51/* 52 * Call put_dec_full4 on x % 10000, return x / 10000. 53 * The approximation x/10000 == (x * 0x346DC5D7) >> 43 54 * holds for all x < 1,128,869,999. The largest value this 55 * helper will ever be asked to convert is 1,125,520,955. 56 * (second call in the put_dec code, assuming n is all-ones). 57 */ 58static |
57unsigned int put_dec_helper4(char *buf, unsigned int x) | 59unsigned int put_dec_helper4(char *end, unsigned int x) |
58{ 59 unsigned int q = (x * 0x346DC5D7ULL) >> 43; 60 | 60{ 61 unsigned int q = (x * 0x346DC5D7ULL) >> 43; 62 |
61 put_dec_full4(buf, x - q * 10000); | 63 put_dec_full4(end, x - q * 10000); |
62 return q; 63} 64 65/* Based on code by Douglas W. Jones found at 66 * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour> 67 * (with permission from the author). 68 * Performs no 64-bit division and hence should be fast on 32-bit machines. 69 */ 70static | 64 return q; 65} 66 67/* Based on code by Douglas W. Jones found at 68 * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour> 69 * (with permission from the author). 70 * Performs no 64-bit division and hence should be fast on 32-bit machines. 71 */ 72static |
71int put_dec(char *buf, unsigned long long n) | 73char *put_dec(char *end, unsigned long long n) |
72{ 73 unsigned int d3, d2, d1, q, h; | 74{ 75 unsigned int d3, d2, d1, q, h; |
74 char *p = buf; | 76 char *p = end; |
75 76 d1 = ((unsigned int)n >> 16); /* implicit "& 0xffff" */ 77 h = (n >> 32); 78 d2 = (h ) & 0xffff; 79 d3 = (h >> 16); /* implicit "& 0xffff" */ 80 81 /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0 82 = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */ 83 q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff); 84 q = put_dec_helper4(p, q); | 77 78 d1 = ((unsigned int)n >> 16); /* implicit "& 0xffff" */ 79 h = (n >> 32); 80 d2 = (h ) & 0xffff; 81 d3 = (h >> 16); /* implicit "& 0xffff" */ 82 83 /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0 84 = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */ 85 q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff); 86 q = put_dec_helper4(p, q); |
85 p += 4; | 87 p -= 4; |
86 87 q += 7671 * d3 + 9496 * d2 + 6 * d1; 88 q = put_dec_helper4(p, q); | 88 89 q += 7671 * d3 + 9496 * d2 + 6 * d1; 90 q = put_dec_helper4(p, q); |
89 p += 4; | 91 p -= 4; |
90 91 q += 4749 * d3 + 42 * d2; 92 q = put_dec_helper4(p, q); | 92 93 q += 4749 * d3 + 42 * d2; 94 q = put_dec_helper4(p, q); |
93 p += 4; | 95 p -= 4; |
94 95 q += 281 * d3; 96 q = put_dec_helper4(p, q); | 96 97 q += 281 * d3; 98 q = put_dec_helper4(p, q); |
97 p += 4; | 99 p -= 4; |
98 99 put_dec_full4(p, q); | 100 101 put_dec_full4(p, q); |
100 p += 4; | 102 p -= 4; |
101 102 /* strip off the extra 0's we printed */ | 103 104 /* strip off the extra 0's we printed */ |
103 while (p > buf && p[-1] == '0') 104 --p; | 105 while (p < end && *p == '0') 106 ++p; |
105 | 107 |
106 return p - buf; | 108 return p; |
107} 108 | 109} 110 |
111static 112char *number(char *end, unsigned long long num, int base, char locase) 113{ 114 /* 115 * locase = 0 or 0x20. ORing digits or letters with 'locase' 116 * produces same digits or (maybe lowercased) letters 117 */ 118 119 /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 120 static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 121 122 switch (base) { 123 case 10: 124 if (num != 0) 125 end = put_dec(end, num); 126 break; 127 case 8: 128 for (; num != 0; num >>= 3) 129 *--end = '0' + (num & 07); 130 break; 131 case 16: 132 for (; num != 0; num >>= 4) 133 *--end = digits[num & 0xf] | locase; 134 break; 135 default: 136 unreachable(); 137 }; 138 139 return end; 140} 141 |
|
109#define ZEROPAD 1 /* pad with zero */ 110#define SIGN 2 /* unsigned/signed long */ 111#define PLUS 4 /* show plus */ 112#define SPACE 8 /* space if plus */ 113#define LEFT 16 /* left justified */ 114#define SMALL 32 /* Must be 32 == 0x20 */ 115#define SPECIAL 64 /* 0x */ 116 | 142#define ZEROPAD 1 /* pad with zero */ 143#define SIGN 2 /* unsigned/signed long */ 144#define PLUS 4 /* show plus */ 145#define SPACE 8 /* space if plus */ 146#define LEFT 16 /* left justified */ 147#define SMALL 32 /* Must be 32 == 0x20 */ 148#define SPECIAL 64 /* 0x */ 149 |
117static char *number(char *str, long long num, int base, int size, int precision, 118 int type) 119{ 120 /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 121 static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 122 123 char tmp[66]; 124 char c, sign, locase; 125 int i; 126 127 /* locase = 0 or 0x20. ORing digits or letters with 'locase' 128 * produces same digits or (maybe lowercased) letters */ 129 locase = (type & SMALL); 130 if (type & LEFT) 131 type &= ~ZEROPAD; 132 c = (type & ZEROPAD) ? '0' : ' '; 133 sign = 0; 134 if (type & SIGN) { 135 if (num < 0) { 136 sign = '-'; 137 num = -num; 138 size--; 139 } else if (type & PLUS) { 140 sign = '+'; 141 size--; 142 } else if (type & SPACE) { 143 sign = ' '; 144 size--; 145 } 146 } 147 if (type & SPECIAL) { 148 if (base == 16) 149 size -= 2; 150 else if (base == 8) 151 size--; 152 } 153 i = 0; 154 if (num == 0) 155 tmp[i++] = '0'; 156 else { 157 switch (base) { 158 case 10: 159 i += put_dec(&tmp[i], num); 160 break; 161 case 8: 162 while (num != 0) { 163 tmp[i++] = '0' + (num & 07); 164 num = (unsigned long long)num >> 3; 165 } 166 break; 167 case 16: 168 while (num != 0) { 169 tmp[i++] = digits[num & 0xf] | locase; 170 num = (unsigned long long)num >> 4; 171 } 172 break; 173 default: 174 unreachable(); 175 } 176 } 177 178 if (i > precision) 179 precision = i; 180 size -= precision; 181 if (!(type & (ZEROPAD + LEFT))) 182 while (size-- > 0) 183 *str++ = ' '; 184 if (sign) 185 *str++ = sign; 186 if (type & SPECIAL) { 187 if (base == 8) { 188 *str++ = '0'; 189 } else if (base == 16) { 190 *str++ = '0'; 191 *str++ = ('X' | locase); 192 } 193 } 194 if (!(type & LEFT)) 195 while (size-- > 0) 196 *str++ = c; 197 while (i < precision--) 198 *str++ = '0'; 199 while (i-- > 0) 200 *str++ = tmp[i]; 201 while (size-- > 0) 202 *str++ = ' '; 203 return str; 204} 205 | |
206static 207int get_flags(const char **fmt) 208{ 209 int flags = 0; 210 211 do { 212 switch (**fmt) { 213 case '-': --- 58 unchanged lines hidden (view full) --- 272 case 'H': 273 return (unsigned char)va_arg(*ap, int); 274 default: 275 return va_arg(*ap, unsigned int); 276 } 277 } 278} 279 | 150static 151int get_flags(const char **fmt) 152{ 153 int flags = 0; 154 155 do { 156 switch (**fmt) { 157 case '-': --- 58 unchanged lines hidden (view full) --- 216 case 'H': 217 return (unsigned char)va_arg(*ap, int); 218 default: 219 return va_arg(*ap, unsigned int); 220 } 221 } 222} 223 |
224static 225char get_sign(long long *num, int flags) 226{ 227 if (!(flags & SIGN)) 228 return 0; 229 if (*num < 0) { 230 *num = -(*num); 231 return '-'; 232 } 233 if (flags & PLUS) 234 return '+'; 235 if (flags & SPACE) 236 return ' '; 237 return 0; 238} 239 |
|
280int vsprintf(char *buf, const char *fmt, va_list ap) 281{ | 240int vsprintf(char *buf, const char *fmt, va_list ap) 241{ |
282 int len; 283 unsigned long long num; 284 int i, base; | 242 /* The maximum space required is to print a 64-bit number in octal */ 243 char tmp[(sizeof(unsigned long long) * 8 + 2) / 3]; 244 char *tmp_end = &tmp[ARRAY_SIZE(tmp)]; 245 long long num; 246 int base; |
285 char *str; 286 const char *s; | 247 char *str; 248 const char *s; |
249 int len; 250 char sign; |
|
287 288 int flags; /* flags to number() */ 289 290 int field_width; /* width of output field */ 291 int precision; /* min. # of digits for integers; max 292 number of chars for from string */ 293 int qualifier; /* 'h', 'hh', 'l' or 'll' for integer fields */ 294 --- 26 unchanged lines hidden (view full) --- 321 322 /* get field width */ 323 field_width = get_int(&fmt, &args); 324 if (field_width < 0) { 325 field_width = -field_width; 326 flags |= LEFT; 327 } 328 | 251 252 int flags; /* flags to number() */ 253 254 int field_width; /* width of output field */ 255 int precision; /* min. # of digits for integers; max 256 number of chars for from string */ 257 int qualifier; /* 'h', 'hh', 'l' or 'll' for integer fields */ 258 --- 26 unchanged lines hidden (view full) --- 285 286 /* get field width */ 287 field_width = get_int(&fmt, &args); 288 if (field_width < 0) { 289 field_width = -field_width; 290 flags |= LEFT; 291 } 292 |
293 if (flags & LEFT) 294 flags &= ~ZEROPAD; 295 |
|
329 /* get the precision */ 330 precision = -1; 331 if (*fmt == '.') { 332 ++fmt; 333 precision = get_int(&fmt, &args); 334 if (precision >= 0) 335 flags &= ~ZEROPAD; 336 } --- 4 unchanged lines hidden (view full) --- 341 qualifier = *fmt; 342 ++fmt; 343 if (qualifier == *fmt) { 344 qualifier -= 'a'-'A'; 345 ++fmt; 346 } 347 } 348 | 296 /* get the precision */ 297 precision = -1; 298 if (*fmt == '.') { 299 ++fmt; 300 precision = get_int(&fmt, &args); 301 if (precision >= 0) 302 flags &= ~ZEROPAD; 303 } --- 4 unchanged lines hidden (view full) --- 308 qualifier = *fmt; 309 ++fmt; 310 if (qualifier == *fmt) { 311 qualifier -= 'a'-'A'; 312 ++fmt; 313 } 314 } 315 |
316 sign = 0; 317 |
|
349 switch (*fmt) { 350 case 'c': | 318 switch (*fmt) { 319 case 'c': |
351 if (!(flags & LEFT)) 352 while (--field_width > 0) 353 *str++ = ' '; 354 *str++ = (unsigned char)va_arg(args, int); 355 while (--field_width > 0) 356 *str++ = ' '; 357 continue; | 320 flags &= LEFT; 321 tmp[0] = (unsigned char)va_arg(args, int); 322 s = tmp; 323 precision = len = 1; 324 goto output; |
358 359 case 's': | 325 326 case 's': |
327 flags &= LEFT; |
|
360 if (precision < 0) 361 precision = INT_MAX; 362 s = va_arg(args, char *); 363 if (!s) 364 s = precision < 6 ? "" : "(null)"; | 328 if (precision < 0) 329 precision = INT_MAX; 330 s = va_arg(args, char *); 331 if (!s) 332 s = precision < 6 ? "" : "(null)"; |
365 len = strnlen(s, precision); | 333 precision = len = strnlen(s, precision); 334 goto output; |
366 | 335 |
367 if (!(flags & LEFT)) 368 while (len < field_width--) 369 *str++ = ' '; 370 for (i = 0; i < len; ++i) 371 *str++ = *s++; 372 while (len < field_width--) 373 *str++ = ' '; 374 continue; 375 | |
376 /* integer number formats - set up the flags and "break" */ 377 case 'o': 378 base = 8; 379 break; 380 381 case 'p': 382 if (precision < 0) 383 precision = 2 * sizeof(void *); --- 5 unchanged lines hidden (view full) --- 389 base = 16; 390 break; 391 392 case 'd': 393 case 'i': 394 flags |= SIGN; 395 fallthrough; 396 case 'u': | 336 /* integer number formats - set up the flags and "break" */ 337 case 'o': 338 base = 8; 339 break; 340 341 case 'p': 342 if (precision < 0) 343 precision = 2 * sizeof(void *); --- 5 unchanged lines hidden (view full) --- 349 base = 16; 350 break; 351 352 case 'd': 353 case 'i': 354 flags |= SIGN; 355 fallthrough; 356 case 'u': |
357 flags &= ~SPECIAL; |
|
397 base = 10; 398 break; 399 400 default: 401 *str++ = '%'; 402 if (*fmt) 403 *str++ = *fmt; 404 else 405 --fmt; 406 continue; 407 } 408 if (*fmt == 'p') { 409 num = (unsigned long)va_arg(args, void *); 410 } else { 411 num = get_number(flags & SIGN, qualifier, &args); 412 } | 358 base = 10; 359 break; 360 361 default: 362 *str++ = '%'; 363 if (*fmt) 364 *str++ = *fmt; 365 else 366 --fmt; 367 continue; 368 } 369 if (*fmt == 'p') { 370 num = (unsigned long)va_arg(args, void *); 371 } else { 372 num = get_number(flags & SIGN, qualifier, &args); 373 } |
413 str = number(str, num, base, field_width, precision, flags); | 374 375 sign = get_sign(&num, flags); 376 if (sign) 377 --field_width; 378 379 s = number(tmp_end, num, base, flags & SMALL); 380 len = tmp_end - s; 381 /* default precision is 1 */ 382 if (precision < 0) 383 precision = 1; 384 /* precision is minimum number of digits to print */ 385 if (precision < len) 386 precision = len; 387 if (flags & SPECIAL) { 388 /* 389 * For octal, a leading 0 is printed only if necessary, 390 * i.e. if it's not already there because of the 391 * precision. 392 */ 393 if (base == 8 && precision == len) 394 ++precision; 395 /* 396 * For hexadecimal, the leading 0x is skipped if the 397 * output is empty, i.e. both the number and the 398 * precision are 0. 399 */ 400 if (base == 16 && precision > 0) 401 field_width -= 2; 402 else 403 flags &= ~SPECIAL; 404 } 405 /* 406 * For zero padding, increase the precision to fill the field 407 * width. 408 */ 409 if ((flags & ZEROPAD) && field_width > precision) 410 precision = field_width; 411 412output: 413 /* Calculate the padding necessary */ 414 field_width -= precision; 415 /* Leading padding with ' ' */ 416 if (!(flags & LEFT)) 417 while (field_width-- > 0) 418 *str++ = ' '; 419 /* sign */ 420 if (sign) 421 *str++ = sign; 422 /* 0x/0X for hexadecimal */ 423 if (flags & SPECIAL) { 424 *str++ = '0'; 425 *str++ = 'X' | (flags & SMALL); 426 } 427 /* Zero padding and excess precision */ 428 while (precision-- > len) 429 *str++ = '0'; 430 /* Actual output */ 431 while (len-- > 0) 432 *str++ = *s++; 433 /* Trailing padding with ' ' */ 434 while (field_width-- > 0) 435 *str++ = ' '; |
414 } 415 *str = '\0'; 416 417 va_end(args); 418 419 return str - buf; 420} 421 422int sprintf(char *buf, const char *fmt, ...) 423{ 424 va_list args; 425 int i; 426 427 va_start(args, fmt); 428 i = vsprintf(buf, fmt, args); 429 va_end(args); 430 return i; 431} | 436 } 437 *str = '\0'; 438 439 va_end(args); 440 441 return str - buf; 442} 443 444int sprintf(char *buf, const char *fmt, ...) 445{ 446 va_list args; 447 int i; 448 449 va_start(args, fmt); 450 i = vsprintf(buf, fmt, args); 451 va_end(args); 452 return i; 453} |