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 } else { 283 precision = 0; 284 } 285 if (precision >= 0) 286 flags &= ~ZEROPAD; 287 } 288 289 /* get the conversion qualifier */ 290 qualifier = -1; 291 if (*fmt == 'h' || *fmt == 'l') { 292 qualifier = *fmt; 293 ++fmt; 294 if (qualifier == *fmt) { 295 qualifier -= 'a'-'A'; 296 ++fmt; 297 } 298 } 299 300 /* default base */ 301 base = 10; 302 303 switch (*fmt) { 304 case 'c': 305 if (!(flags & LEFT)) 306 while (--field_width > 0) 307 *str++ = ' '; 308 *str++ = (unsigned char)va_arg(args, int); 309 while (--field_width > 0) 310 *str++ = ' '; 311 continue; 312 313 case 's': 314 s = va_arg(args, char *); 315 len = strnlen(s, precision); 316 317 if (!(flags & LEFT)) 318 while (len < field_width--) 319 *str++ = ' '; 320 for (i = 0; i < len; ++i) 321 *str++ = *s++; 322 while (len < field_width--) 323 *str++ = ' '; 324 continue; 325 326 case 'p': 327 if (field_width == -1) { 328 field_width = 2 * sizeof(void *); 329 flags |= ZEROPAD; 330 } 331 str = number(str, 332 (unsigned long)va_arg(args, void *), 16, 333 field_width, precision, flags); 334 continue; 335 336 /* integer number formats - set up the flags and "break" */ 337 case 'o': 338 base = 8; 339 break; 340 341 case 'x': 342 flags |= SMALL; 343 fallthrough; 344 case 'X': 345 base = 16; 346 break; 347 348 case 'd': 349 case 'i': 350 flags |= SIGN; 351 fallthrough; 352 case 'u': 353 break; 354 355 default: 356 *str++ = '%'; 357 if (*fmt) 358 *str++ = *fmt; 359 else 360 --fmt; 361 continue; 362 } 363 if (flags & SIGN) { 364 switch (qualifier) { 365 case 'L': 366 num = va_arg(args, long long); 367 break; 368 case 'l': 369 num = va_arg(args, long); 370 break; 371 case 'h': 372 num = (short)va_arg(args, int); 373 break; 374 case 'H': 375 num = (signed char)va_arg(args, int); 376 break; 377 default: 378 num = va_arg(args, int); 379 } 380 } else { 381 switch (qualifier) { 382 case 'L': 383 num = va_arg(args, unsigned long long); 384 break; 385 case 'l': 386 num = va_arg(args, unsigned long); 387 break; 388 case 'h': 389 num = (unsigned short)va_arg(args, int); 390 break; 391 case 'H': 392 num = (unsigned char)va_arg(args, int); 393 break; 394 default: 395 num = va_arg(args, unsigned int); 396 } 397 } 398 str = number(str, num, base, field_width, precision, flags); 399 } 400 *str = '\0'; 401 return str - buf; 402 } 403 404 int sprintf(char *buf, const char *fmt, ...) 405 { 406 va_list args; 407 int i; 408 409 va_start(args, fmt); 410 i = vsprintf(buf, fmt, args); 411 va_end(args); 412 return i; 413 } 414