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/string.h> 18 19 static int skip_atoi(const char **s) 20 { 21 int i = 0; 22 23 while (isdigit(**s)) 24 i = i * 10 + *((*s)++) - '0'; 25 return i; 26 } 27 28 /* 29 * put_dec_full4 handles numbers in the range 0 <= r < 10000. 30 * The multiplier 0xccd is round(2^15/10), and the approximation 31 * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389. 32 */ 33 static 34 void put_dec_full4(char *buf, unsigned int r) 35 { 36 int i; 37 38 for (i = 0; i < 3; i++) { 39 unsigned int q = (r * 0xccd) >> 15; 40 *buf++ = '0' + (r - q * 10); 41 r = q; 42 } 43 *buf++ = '0' + r; 44 } 45 46 /* put_dec is copied from lib/vsprintf.c with small modifications */ 47 48 /* 49 * Call put_dec_full4 on x % 10000, return x / 10000. 50 * The approximation x/10000 == (x * 0x346DC5D7) >> 43 51 * holds for all x < 1,128,869,999. The largest value this 52 * helper will ever be asked to convert is 1,125,520,955. 53 * (second call in the put_dec code, assuming n is all-ones). 54 */ 55 static 56 unsigned int put_dec_helper4(char *buf, unsigned int x) 57 { 58 unsigned int q = (x * 0x346DC5D7ULL) >> 43; 59 60 put_dec_full4(buf, x - q * 10000); 61 return q; 62 } 63 64 /* Based on code by Douglas W. Jones found at 65 * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour> 66 * (with permission from the author). 67 * Performs no 64-bit division and hence should be fast on 32-bit machines. 68 */ 69 static 70 int put_dec(char *buf, unsigned long long n) 71 { 72 unsigned int d3, d2, d1, q, h; 73 char *p = buf; 74 75 d1 = ((unsigned int)n >> 16); /* implicit "& 0xffff" */ 76 h = (n >> 32); 77 d2 = (h ) & 0xffff; 78 d3 = (h >> 16); /* implicit "& 0xffff" */ 79 80 /* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0 81 = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */ 82 q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff); 83 q = put_dec_helper4(p, q); 84 p += 4; 85 86 q += 7671 * d3 + 9496 * d2 + 6 * d1; 87 q = put_dec_helper4(p, q); 88 p += 4; 89 90 q += 4749 * d3 + 42 * d2; 91 q = put_dec_helper4(p, q); 92 p += 4; 93 94 q += 281 * d3; 95 q = put_dec_helper4(p, q); 96 p += 4; 97 98 put_dec_full4(p, q); 99 p += 4; 100 101 /* strip off the extra 0's we printed */ 102 while (p > buf && p[-1] == '0') 103 --p; 104 105 return p - buf; 106 } 107 108 #define ZEROPAD 1 /* pad with zero */ 109 #define SIGN 2 /* unsigned/signed long */ 110 #define PLUS 4 /* show plus */ 111 #define SPACE 8 /* space if plus */ 112 #define LEFT 16 /* left justified */ 113 #define SMALL 32 /* Must be 32 == 0x20 */ 114 #define SPECIAL 64 /* 0x */ 115 116 static char *number(char *str, long long num, int base, int size, int precision, 117 int type) 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 char tmp[66]; 123 char c, sign, locase; 124 int i; 125 126 /* locase = 0 or 0x20. ORing digits or letters with 'locase' 127 * produces same digits or (maybe lowercased) letters */ 128 locase = (type & SMALL); 129 if (type & LEFT) 130 type &= ~ZEROPAD; 131 c = (type & ZEROPAD) ? '0' : ' '; 132 sign = 0; 133 if (type & SIGN) { 134 if (num < 0) { 135 sign = '-'; 136 num = -num; 137 size--; 138 } else if (type & PLUS) { 139 sign = '+'; 140 size--; 141 } else if (type & SPACE) { 142 sign = ' '; 143 size--; 144 } 145 } 146 if (type & SPECIAL) { 147 if (base == 16) 148 size -= 2; 149 else if (base == 8) 150 size--; 151 } 152 i = 0; 153 if (num == 0) 154 tmp[i++] = '0'; 155 else { 156 switch (base) { 157 case 10: 158 i += put_dec(&tmp[i], num); 159 break; 160 case 8: 161 while (num != 0) { 162 tmp[i++] = '0' + (num & 07); 163 num = (unsigned long long)num >> 3; 164 } 165 break; 166 case 16: 167 while (num != 0) { 168 tmp[i++] = digits[num & 0xf] | locase; 169 num = (unsigned long long)num >> 4; 170 } 171 break; 172 default: 173 unreachable(); 174 } 175 } 176 177 if (i > precision) 178 precision = i; 179 size -= precision; 180 if (!(type & (ZEROPAD + LEFT))) 181 while (size-- > 0) 182 *str++ = ' '; 183 if (sign) 184 *str++ = sign; 185 if (type & SPECIAL) { 186 if (base == 8) { 187 *str++ = '0'; 188 } else if (base == 16) { 189 *str++ = '0'; 190 *str++ = ('X' | locase); 191 } 192 } 193 if (!(type & LEFT)) 194 while (size-- > 0) 195 *str++ = c; 196 while (i < precision--) 197 *str++ = '0'; 198 while (i-- > 0) 199 *str++ = tmp[i]; 200 while (size-- > 0) 201 *str++ = ' '; 202 return str; 203 } 204 205 int vsprintf(char *buf, const char *fmt, va_list args) 206 { 207 int len; 208 unsigned long long num; 209 int i, base; 210 char *str; 211 const char *s; 212 213 int flags; /* flags to number() */ 214 215 int field_width; /* width of output field */ 216 int precision; /* min. # of digits for integers; max 217 number of chars for from string */ 218 int qualifier; /* 'h', 'hh', 'l' or 'll' for integer fields */ 219 220 for (str = buf; *fmt; ++fmt) { 221 if (*fmt != '%') { 222 *str++ = *fmt; 223 continue; 224 } 225 226 /* process flags */ 227 flags = 0; 228 repeat: 229 ++fmt; /* this also skips first '%' */ 230 switch (*fmt) { 231 case '-': 232 flags |= LEFT; 233 goto repeat; 234 case '+': 235 flags |= PLUS; 236 goto repeat; 237 case ' ': 238 flags |= SPACE; 239 goto repeat; 240 case '#': 241 flags |= SPECIAL; 242 goto repeat; 243 case '0': 244 flags |= ZEROPAD; 245 goto repeat; 246 } 247 248 /* get field width */ 249 field_width = -1; 250 if (isdigit(*fmt)) { 251 field_width = skip_atoi(&fmt); 252 } else if (*fmt == '*') { 253 ++fmt; 254 /* it's the next argument */ 255 field_width = va_arg(args, int); 256 if (field_width < 0) { 257 field_width = -field_width; 258 flags |= LEFT; 259 } 260 } 261 262 /* get the precision */ 263 precision = -1; 264 if (*fmt == '.') { 265 ++fmt; 266 if (isdigit(*fmt)) { 267 precision = skip_atoi(&fmt); 268 } else if (*fmt == '*') { 269 ++fmt; 270 /* it's the next argument */ 271 precision = va_arg(args, int); 272 } 273 if (precision < 0) 274 precision = 0; 275 } 276 277 /* get the conversion qualifier */ 278 qualifier = -1; 279 if (*fmt == 'h' || *fmt == 'l') { 280 qualifier = *fmt; 281 ++fmt; 282 if (qualifier == *fmt) { 283 qualifier -= 'a'-'A'; 284 ++fmt; 285 } 286 } 287 288 /* default base */ 289 base = 10; 290 291 switch (*fmt) { 292 case 'c': 293 if (!(flags & LEFT)) 294 while (--field_width > 0) 295 *str++ = ' '; 296 *str++ = (unsigned char)va_arg(args, int); 297 while (--field_width > 0) 298 *str++ = ' '; 299 continue; 300 301 case 's': 302 s = va_arg(args, char *); 303 len = strnlen(s, precision); 304 305 if (!(flags & LEFT)) 306 while (len < field_width--) 307 *str++ = ' '; 308 for (i = 0; i < len; ++i) 309 *str++ = *s++; 310 while (len < field_width--) 311 *str++ = ' '; 312 continue; 313 314 case 'p': 315 if (field_width == -1) { 316 field_width = 2 * sizeof(void *); 317 flags |= ZEROPAD; 318 } 319 str = number(str, 320 (unsigned long)va_arg(args, void *), 16, 321 field_width, precision, flags); 322 continue; 323 324 case '%': 325 *str++ = '%'; 326 continue; 327 328 /* integer number formats - set up the flags and "break" */ 329 case 'o': 330 base = 8; 331 break; 332 333 case 'x': 334 flags |= SMALL; 335 fallthrough; 336 case 'X': 337 base = 16; 338 break; 339 340 case 'd': 341 case 'i': 342 flags |= SIGN; 343 fallthrough; 344 case 'u': 345 break; 346 347 default: 348 *str++ = '%'; 349 if (*fmt) 350 *str++ = *fmt; 351 else 352 --fmt; 353 continue; 354 } 355 if (flags & SIGN) { 356 switch (qualifier) { 357 case 'L': 358 num = va_arg(args, long long); 359 break; 360 case 'l': 361 num = va_arg(args, long); 362 break; 363 case 'h': 364 num = (short)va_arg(args, int); 365 break; 366 case 'H': 367 num = (signed char)va_arg(args, int); 368 break; 369 default: 370 num = va_arg(args, int); 371 } 372 } else { 373 switch (qualifier) { 374 case 'L': 375 num = va_arg(args, unsigned long long); 376 break; 377 case 'l': 378 num = va_arg(args, unsigned long); 379 break; 380 case 'h': 381 num = (unsigned short)va_arg(args, int); 382 break; 383 case 'H': 384 num = (unsigned char)va_arg(args, int); 385 break; 386 default: 387 num = va_arg(args, unsigned int); 388 } 389 } 390 str = number(str, num, base, field_width, precision, flags); 391 } 392 *str = '\0'; 393 return str - buf; 394 } 395 396 int sprintf(char *buf, const char *fmt, ...) 397 { 398 va_list args; 399 int i; 400 401 va_start(args, fmt); 402 i = vsprintf(buf, fmt, args); 403 va_end(args); 404 return i; 405 } 406