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 static 206 int get_flags(const char **fmt) 207 { 208 int flags = 0; 209 210 do { 211 switch (**fmt) { 212 case '-': 213 flags |= LEFT; 214 break; 215 case '+': 216 flags |= PLUS; 217 break; 218 case ' ': 219 flags |= SPACE; 220 break; 221 case '#': 222 flags |= SPECIAL; 223 break; 224 case '0': 225 flags |= ZEROPAD; 226 break; 227 default: 228 return flags; 229 } 230 ++(*fmt); 231 } while (1); 232 } 233 234 int vsprintf(char *buf, const char *fmt, va_list args) 235 { 236 int len; 237 unsigned long long num; 238 int i, base; 239 char *str; 240 const char *s; 241 242 int flags; /* flags to number() */ 243 244 int field_width; /* width of output field */ 245 int precision; /* min. # of digits for integers; max 246 number of chars for from string */ 247 int qualifier; /* 'h', 'hh', 'l' or 'll' for integer fields */ 248 249 for (str = buf; *fmt; ++fmt) { 250 if (*fmt != '%' || *++fmt == '%') { 251 *str++ = *fmt; 252 continue; 253 } 254 255 /* process flags */ 256 flags = get_flags(&fmt); 257 258 /* get field width */ 259 field_width = -1; 260 if (isdigit(*fmt)) { 261 field_width = skip_atoi(&fmt); 262 } else if (*fmt == '*') { 263 ++fmt; 264 /* it's the next argument */ 265 field_width = va_arg(args, int); 266 if (field_width < 0) { 267 field_width = -field_width; 268 flags |= LEFT; 269 } 270 } 271 272 /* get the precision */ 273 precision = -1; 274 if (*fmt == '.') { 275 ++fmt; 276 if (isdigit(*fmt)) { 277 precision = skip_atoi(&fmt); 278 } else if (*fmt == '*') { 279 ++fmt; 280 /* it's the next argument */ 281 precision = va_arg(args, int); 282 } 283 if (precision < 0) 284 precision = 0; 285 } 286 287 /* get the conversion qualifier */ 288 qualifier = -1; 289 if (*fmt == 'h' || *fmt == 'l') { 290 qualifier = *fmt; 291 ++fmt; 292 if (qualifier == *fmt) { 293 qualifier -= 'a'-'A'; 294 ++fmt; 295 } 296 } 297 298 /* default base */ 299 base = 10; 300 301 switch (*fmt) { 302 case 'c': 303 if (!(flags & LEFT)) 304 while (--field_width > 0) 305 *str++ = ' '; 306 *str++ = (unsigned char)va_arg(args, int); 307 while (--field_width > 0) 308 *str++ = ' '; 309 continue; 310 311 case 's': 312 s = va_arg(args, char *); 313 len = strnlen(s, precision); 314 315 if (!(flags & LEFT)) 316 while (len < field_width--) 317 *str++ = ' '; 318 for (i = 0; i < len; ++i) 319 *str++ = *s++; 320 while (len < field_width--) 321 *str++ = ' '; 322 continue; 323 324 case 'p': 325 if (field_width == -1) { 326 field_width = 2 * sizeof(void *); 327 flags |= ZEROPAD; 328 } 329 str = number(str, 330 (unsigned long)va_arg(args, void *), 16, 331 field_width, precision, flags); 332 continue; 333 334 /* integer number formats - set up the flags and "break" */ 335 case 'o': 336 base = 8; 337 break; 338 339 case 'x': 340 flags |= SMALL; 341 fallthrough; 342 case 'X': 343 base = 16; 344 break; 345 346 case 'd': 347 case 'i': 348 flags |= SIGN; 349 fallthrough; 350 case 'u': 351 break; 352 353 default: 354 *str++ = '%'; 355 if (*fmt) 356 *str++ = *fmt; 357 else 358 --fmt; 359 continue; 360 } 361 if (flags & SIGN) { 362 switch (qualifier) { 363 case 'L': 364 num = va_arg(args, long long); 365 break; 366 case 'l': 367 num = va_arg(args, long); 368 break; 369 case 'h': 370 num = (short)va_arg(args, int); 371 break; 372 case 'H': 373 num = (signed char)va_arg(args, int); 374 break; 375 default: 376 num = va_arg(args, int); 377 } 378 } else { 379 switch (qualifier) { 380 case 'L': 381 num = va_arg(args, unsigned long long); 382 break; 383 case 'l': 384 num = va_arg(args, unsigned long); 385 break; 386 case 'h': 387 num = (unsigned short)va_arg(args, int); 388 break; 389 case 'H': 390 num = (unsigned char)va_arg(args, int); 391 break; 392 default: 393 num = va_arg(args, unsigned int); 394 } 395 } 396 str = number(str, num, base, field_width, precision, flags); 397 } 398 *str = '\0'; 399 return str - buf; 400 } 401 402 int sprintf(char *buf, const char *fmt, ...) 403 { 404 va_list args; 405 int i; 406 407 va_start(args, fmt); 408 i = vsprintf(buf, fmt, args); 409 va_end(args); 410 return i; 411 } 412