12c7d1e30SArvind Sankar // SPDX-License-Identifier: GPL-2.0-only 22c7d1e30SArvind Sankar /* -*- linux-c -*- ------------------------------------------------------- * 32c7d1e30SArvind Sankar * 42c7d1e30SArvind Sankar * Copyright (C) 1991, 1992 Linus Torvalds 52c7d1e30SArvind Sankar * Copyright 2007 rPath, Inc. - All Rights Reserved 62c7d1e30SArvind Sankar * 72c7d1e30SArvind Sankar * ----------------------------------------------------------------------- */ 82c7d1e30SArvind Sankar 92c7d1e30SArvind Sankar /* 102c7d1e30SArvind Sankar * Oh, it's a waste of space, but oh-so-yummy for debugging. This 112c7d1e30SArvind Sankar * version of printf() does not include 64-bit support. "Live with 122c7d1e30SArvind Sankar * it." 132c7d1e30SArvind Sankar * 142c7d1e30SArvind Sankar */ 152c7d1e30SArvind Sankar 162c7d1e30SArvind Sankar #include <stdarg.h> 172c7d1e30SArvind Sankar 182c7d1e30SArvind Sankar #include <linux/compiler.h> 192c7d1e30SArvind Sankar #include <linux/ctype.h> 202c7d1e30SArvind Sankar #include <linux/string.h> 212c7d1e30SArvind Sankar 222c7d1e30SArvind Sankar static int skip_atoi(const char **s) 232c7d1e30SArvind Sankar { 242c7d1e30SArvind Sankar int i = 0; 252c7d1e30SArvind Sankar 262c7d1e30SArvind Sankar while (isdigit(**s)) 272c7d1e30SArvind Sankar i = i * 10 + *((*s)++) - '0'; 282c7d1e30SArvind Sankar return i; 292c7d1e30SArvind Sankar } 302c7d1e30SArvind Sankar 312c7d1e30SArvind Sankar #define ZEROPAD 1 /* pad with zero */ 322c7d1e30SArvind Sankar #define SIGN 2 /* unsigned/signed long */ 332c7d1e30SArvind Sankar #define PLUS 4 /* show plus */ 342c7d1e30SArvind Sankar #define SPACE 8 /* space if plus */ 352c7d1e30SArvind Sankar #define LEFT 16 /* left justified */ 362c7d1e30SArvind Sankar #define SMALL 32 /* Must be 32 == 0x20 */ 372c7d1e30SArvind Sankar #define SPECIAL 64 /* 0x */ 382c7d1e30SArvind Sankar 392c7d1e30SArvind Sankar #define __do_div(n, base) ({ \ 402c7d1e30SArvind Sankar int __res; \ 412c7d1e30SArvind Sankar __res = ((unsigned long) n) % (unsigned) base; \ 422c7d1e30SArvind Sankar n = ((unsigned long) n) / (unsigned) base; \ 432c7d1e30SArvind Sankar __res; }) 442c7d1e30SArvind Sankar 452c7d1e30SArvind Sankar static char *number(char *str, long num, int base, int size, int precision, 462c7d1e30SArvind Sankar int type) 472c7d1e30SArvind Sankar { 482c7d1e30SArvind Sankar /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 492c7d1e30SArvind Sankar static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 502c7d1e30SArvind Sankar 512c7d1e30SArvind Sankar char tmp[66]; 522c7d1e30SArvind Sankar char c, sign, locase; 532c7d1e30SArvind Sankar int i; 542c7d1e30SArvind Sankar 552c7d1e30SArvind Sankar /* locase = 0 or 0x20. ORing digits or letters with 'locase' 562c7d1e30SArvind Sankar * produces same digits or (maybe lowercased) letters */ 572c7d1e30SArvind Sankar locase = (type & SMALL); 582c7d1e30SArvind Sankar if (type & LEFT) 592c7d1e30SArvind Sankar type &= ~ZEROPAD; 602c7d1e30SArvind Sankar if (base < 2 || base > 16) 612c7d1e30SArvind Sankar return NULL; 622c7d1e30SArvind Sankar c = (type & ZEROPAD) ? '0' : ' '; 632c7d1e30SArvind Sankar sign = 0; 642c7d1e30SArvind Sankar if (type & SIGN) { 652c7d1e30SArvind Sankar if (num < 0) { 662c7d1e30SArvind Sankar sign = '-'; 672c7d1e30SArvind Sankar num = -num; 682c7d1e30SArvind Sankar size--; 692c7d1e30SArvind Sankar } else if (type & PLUS) { 702c7d1e30SArvind Sankar sign = '+'; 712c7d1e30SArvind Sankar size--; 722c7d1e30SArvind Sankar } else if (type & SPACE) { 732c7d1e30SArvind Sankar sign = ' '; 742c7d1e30SArvind Sankar size--; 752c7d1e30SArvind Sankar } 762c7d1e30SArvind Sankar } 772c7d1e30SArvind Sankar if (type & SPECIAL) { 782c7d1e30SArvind Sankar if (base == 16) 792c7d1e30SArvind Sankar size -= 2; 802c7d1e30SArvind Sankar else if (base == 8) 812c7d1e30SArvind Sankar size--; 822c7d1e30SArvind Sankar } 832c7d1e30SArvind Sankar i = 0; 842c7d1e30SArvind Sankar if (num == 0) 852c7d1e30SArvind Sankar tmp[i++] = '0'; 862c7d1e30SArvind Sankar else 872c7d1e30SArvind Sankar while (num != 0) 882c7d1e30SArvind Sankar tmp[i++] = (digits[__do_div(num, base)] | locase); 892c7d1e30SArvind Sankar if (i > precision) 902c7d1e30SArvind Sankar precision = i; 912c7d1e30SArvind Sankar size -= precision; 922c7d1e30SArvind Sankar if (!(type & (ZEROPAD + LEFT))) 932c7d1e30SArvind Sankar while (size-- > 0) 942c7d1e30SArvind Sankar *str++ = ' '; 952c7d1e30SArvind Sankar if (sign) 962c7d1e30SArvind Sankar *str++ = sign; 972c7d1e30SArvind Sankar if (type & SPECIAL) { 982c7d1e30SArvind Sankar if (base == 8) { 992c7d1e30SArvind Sankar *str++ = '0'; 1002c7d1e30SArvind Sankar } else if (base == 16) { 1012c7d1e30SArvind Sankar *str++ = '0'; 1022c7d1e30SArvind Sankar *str++ = ('X' | locase); 1032c7d1e30SArvind Sankar } 1042c7d1e30SArvind Sankar } 1052c7d1e30SArvind Sankar if (!(type & LEFT)) 1062c7d1e30SArvind Sankar while (size-- > 0) 1072c7d1e30SArvind Sankar *str++ = c; 1082c7d1e30SArvind Sankar while (i < precision--) 1092c7d1e30SArvind Sankar *str++ = '0'; 1102c7d1e30SArvind Sankar while (i-- > 0) 1112c7d1e30SArvind Sankar *str++ = tmp[i]; 1122c7d1e30SArvind Sankar while (size-- > 0) 1132c7d1e30SArvind Sankar *str++ = ' '; 1142c7d1e30SArvind Sankar return str; 1152c7d1e30SArvind Sankar } 1162c7d1e30SArvind Sankar 1172c7d1e30SArvind Sankar int vsprintf(char *buf, const char *fmt, va_list args) 1182c7d1e30SArvind Sankar { 1192c7d1e30SArvind Sankar int len; 1202c7d1e30SArvind Sankar unsigned long num; 1212c7d1e30SArvind Sankar int i, base; 1222c7d1e30SArvind Sankar char *str; 1232c7d1e30SArvind Sankar const char *s; 1242c7d1e30SArvind Sankar 1252c7d1e30SArvind Sankar int flags; /* flags to number() */ 1262c7d1e30SArvind Sankar 1272c7d1e30SArvind Sankar int field_width; /* width of output field */ 1282c7d1e30SArvind Sankar int precision; /* min. # of digits for integers; max 1292c7d1e30SArvind Sankar number of chars for from string */ 130*29a28066SArvind Sankar int qualifier; /* 'h' or 'l' for integer fields */ 1312c7d1e30SArvind Sankar 1322c7d1e30SArvind Sankar for (str = buf; *fmt; ++fmt) { 1332c7d1e30SArvind Sankar if (*fmt != '%') { 1342c7d1e30SArvind Sankar *str++ = *fmt; 1352c7d1e30SArvind Sankar continue; 1362c7d1e30SArvind Sankar } 1372c7d1e30SArvind Sankar 1382c7d1e30SArvind Sankar /* process flags */ 1392c7d1e30SArvind Sankar flags = 0; 1402c7d1e30SArvind Sankar repeat: 1412c7d1e30SArvind Sankar ++fmt; /* this also skips first '%' */ 1422c7d1e30SArvind Sankar switch (*fmt) { 1432c7d1e30SArvind Sankar case '-': 1442c7d1e30SArvind Sankar flags |= LEFT; 1452c7d1e30SArvind Sankar goto repeat; 1462c7d1e30SArvind Sankar case '+': 1472c7d1e30SArvind Sankar flags |= PLUS; 1482c7d1e30SArvind Sankar goto repeat; 1492c7d1e30SArvind Sankar case ' ': 1502c7d1e30SArvind Sankar flags |= SPACE; 1512c7d1e30SArvind Sankar goto repeat; 1522c7d1e30SArvind Sankar case '#': 1532c7d1e30SArvind Sankar flags |= SPECIAL; 1542c7d1e30SArvind Sankar goto repeat; 1552c7d1e30SArvind Sankar case '0': 1562c7d1e30SArvind Sankar flags |= ZEROPAD; 1572c7d1e30SArvind Sankar goto repeat; 1582c7d1e30SArvind Sankar } 1592c7d1e30SArvind Sankar 1602c7d1e30SArvind Sankar /* get field width */ 1612c7d1e30SArvind Sankar field_width = -1; 1622c7d1e30SArvind Sankar if (isdigit(*fmt)) { 1632c7d1e30SArvind Sankar field_width = skip_atoi(&fmt); 1642c7d1e30SArvind Sankar } else if (*fmt == '*') { 1652c7d1e30SArvind Sankar ++fmt; 1662c7d1e30SArvind Sankar /* it's the next argument */ 1672c7d1e30SArvind Sankar field_width = va_arg(args, int); 1682c7d1e30SArvind Sankar if (field_width < 0) { 1692c7d1e30SArvind Sankar field_width = -field_width; 1702c7d1e30SArvind Sankar flags |= LEFT; 1712c7d1e30SArvind Sankar } 1722c7d1e30SArvind Sankar } 1732c7d1e30SArvind Sankar 1742c7d1e30SArvind Sankar /* get the precision */ 1752c7d1e30SArvind Sankar precision = -1; 1762c7d1e30SArvind Sankar if (*fmt == '.') { 1772c7d1e30SArvind Sankar ++fmt; 1782c7d1e30SArvind Sankar if (isdigit(*fmt)) { 1792c7d1e30SArvind Sankar precision = skip_atoi(&fmt); 1802c7d1e30SArvind Sankar } else if (*fmt == '*') { 1812c7d1e30SArvind Sankar ++fmt; 1822c7d1e30SArvind Sankar /* it's the next argument */ 1832c7d1e30SArvind Sankar precision = va_arg(args, int); 1842c7d1e30SArvind Sankar } 1852c7d1e30SArvind Sankar if (precision < 0) 1862c7d1e30SArvind Sankar precision = 0; 1872c7d1e30SArvind Sankar } 1882c7d1e30SArvind Sankar 1892c7d1e30SArvind Sankar /* get the conversion qualifier */ 1902c7d1e30SArvind Sankar qualifier = -1; 191*29a28066SArvind Sankar if (*fmt == 'h' || *fmt == 'l') { 1922c7d1e30SArvind Sankar qualifier = *fmt; 1932c7d1e30SArvind Sankar ++fmt; 1942c7d1e30SArvind Sankar } 1952c7d1e30SArvind Sankar 1962c7d1e30SArvind Sankar /* default base */ 1972c7d1e30SArvind Sankar base = 10; 1982c7d1e30SArvind Sankar 1992c7d1e30SArvind Sankar switch (*fmt) { 2002c7d1e30SArvind Sankar case 'c': 2012c7d1e30SArvind Sankar if (!(flags & LEFT)) 2022c7d1e30SArvind Sankar while (--field_width > 0) 2032c7d1e30SArvind Sankar *str++ = ' '; 2042c7d1e30SArvind Sankar *str++ = (unsigned char)va_arg(args, int); 2052c7d1e30SArvind Sankar while (--field_width > 0) 2062c7d1e30SArvind Sankar *str++ = ' '; 2072c7d1e30SArvind Sankar continue; 2082c7d1e30SArvind Sankar 2092c7d1e30SArvind Sankar case 's': 2102c7d1e30SArvind Sankar s = va_arg(args, char *); 2112c7d1e30SArvind Sankar len = strnlen(s, precision); 2122c7d1e30SArvind Sankar 2132c7d1e30SArvind Sankar if (!(flags & LEFT)) 2142c7d1e30SArvind Sankar while (len < field_width--) 2152c7d1e30SArvind Sankar *str++ = ' '; 2162c7d1e30SArvind Sankar for (i = 0; i < len; ++i) 2172c7d1e30SArvind Sankar *str++ = *s++; 2182c7d1e30SArvind Sankar while (len < field_width--) 2192c7d1e30SArvind Sankar *str++ = ' '; 2202c7d1e30SArvind Sankar continue; 2212c7d1e30SArvind Sankar 2222c7d1e30SArvind Sankar case 'p': 2232c7d1e30SArvind Sankar if (field_width == -1) { 2242c7d1e30SArvind Sankar field_width = 2 * sizeof(void *); 2252c7d1e30SArvind Sankar flags |= ZEROPAD; 2262c7d1e30SArvind Sankar } 2272c7d1e30SArvind Sankar str = number(str, 2282c7d1e30SArvind Sankar (unsigned long)va_arg(args, void *), 16, 2292c7d1e30SArvind Sankar field_width, precision, flags); 2302c7d1e30SArvind Sankar continue; 2312c7d1e30SArvind Sankar 2322c7d1e30SArvind Sankar case '%': 2332c7d1e30SArvind Sankar *str++ = '%'; 2342c7d1e30SArvind Sankar continue; 2352c7d1e30SArvind Sankar 2362c7d1e30SArvind Sankar /* integer number formats - set up the flags and "break" */ 2372c7d1e30SArvind Sankar case 'o': 2382c7d1e30SArvind Sankar base = 8; 2392c7d1e30SArvind Sankar break; 2402c7d1e30SArvind Sankar 2412c7d1e30SArvind Sankar case 'x': 2422c7d1e30SArvind Sankar flags |= SMALL; 2432c7d1e30SArvind Sankar fallthrough; 2442c7d1e30SArvind Sankar case 'X': 2452c7d1e30SArvind Sankar base = 16; 2462c7d1e30SArvind Sankar break; 2472c7d1e30SArvind Sankar 2482c7d1e30SArvind Sankar case 'd': 2492c7d1e30SArvind Sankar case 'i': 2502c7d1e30SArvind Sankar flags |= SIGN; 2512c7d1e30SArvind Sankar fallthrough; 2522c7d1e30SArvind Sankar case 'u': 2532c7d1e30SArvind Sankar break; 2542c7d1e30SArvind Sankar 2552c7d1e30SArvind Sankar default: 2562c7d1e30SArvind Sankar *str++ = '%'; 2572c7d1e30SArvind Sankar if (*fmt) 2582c7d1e30SArvind Sankar *str++ = *fmt; 2592c7d1e30SArvind Sankar else 2602c7d1e30SArvind Sankar --fmt; 2612c7d1e30SArvind Sankar continue; 2622c7d1e30SArvind Sankar } 2632c7d1e30SArvind Sankar if (qualifier == 'l') { 2642c7d1e30SArvind Sankar num = va_arg(args, unsigned long); 2652c7d1e30SArvind Sankar } else if (qualifier == 'h') { 2662c7d1e30SArvind Sankar num = (unsigned short)va_arg(args, int); 2672c7d1e30SArvind Sankar if (flags & SIGN) 2682c7d1e30SArvind Sankar num = (short)num; 2692c7d1e30SArvind Sankar } else if (flags & SIGN) { 2702c7d1e30SArvind Sankar num = va_arg(args, int); 2712c7d1e30SArvind Sankar } else { 2722c7d1e30SArvind Sankar num = va_arg(args, unsigned int); 2732c7d1e30SArvind Sankar } 2742c7d1e30SArvind Sankar str = number(str, num, base, field_width, precision, flags); 2752c7d1e30SArvind Sankar } 2762c7d1e30SArvind Sankar *str = '\0'; 2772c7d1e30SArvind Sankar return str - buf; 2782c7d1e30SArvind Sankar } 2792c7d1e30SArvind Sankar 2802c7d1e30SArvind Sankar int sprintf(char *buf, const char *fmt, ...) 2812c7d1e30SArvind Sankar { 2822c7d1e30SArvind Sankar va_list args; 2832c7d1e30SArvind Sankar int i; 2842c7d1e30SArvind Sankar 2852c7d1e30SArvind Sankar va_start(args, fmt); 2862c7d1e30SArvind Sankar i = vsprintf(buf, fmt, args); 2872c7d1e30SArvind Sankar va_end(args); 2882c7d1e30SArvind Sankar return i; 2892c7d1e30SArvind Sankar } 290