1*2c7d1e30SArvind Sankar // SPDX-License-Identifier: GPL-2.0-only 2*2c7d1e30SArvind Sankar /* -*- linux-c -*- ------------------------------------------------------- * 3*2c7d1e30SArvind Sankar * 4*2c7d1e30SArvind Sankar * Copyright (C) 1991, 1992 Linus Torvalds 5*2c7d1e30SArvind Sankar * Copyright 2007 rPath, Inc. - All Rights Reserved 6*2c7d1e30SArvind Sankar * 7*2c7d1e30SArvind Sankar * ----------------------------------------------------------------------- */ 8*2c7d1e30SArvind Sankar 9*2c7d1e30SArvind Sankar /* 10*2c7d1e30SArvind Sankar * Oh, it's a waste of space, but oh-so-yummy for debugging. This 11*2c7d1e30SArvind Sankar * version of printf() does not include 64-bit support. "Live with 12*2c7d1e30SArvind Sankar * it." 13*2c7d1e30SArvind Sankar * 14*2c7d1e30SArvind Sankar */ 15*2c7d1e30SArvind Sankar 16*2c7d1e30SArvind Sankar #include <stdarg.h> 17*2c7d1e30SArvind Sankar 18*2c7d1e30SArvind Sankar #include <linux/compiler.h> 19*2c7d1e30SArvind Sankar #include <linux/ctype.h> 20*2c7d1e30SArvind Sankar #include <linux/string.h> 21*2c7d1e30SArvind Sankar 22*2c7d1e30SArvind Sankar static int skip_atoi(const char **s) 23*2c7d1e30SArvind Sankar { 24*2c7d1e30SArvind Sankar int i = 0; 25*2c7d1e30SArvind Sankar 26*2c7d1e30SArvind Sankar while (isdigit(**s)) 27*2c7d1e30SArvind Sankar i = i * 10 + *((*s)++) - '0'; 28*2c7d1e30SArvind Sankar return i; 29*2c7d1e30SArvind Sankar } 30*2c7d1e30SArvind Sankar 31*2c7d1e30SArvind Sankar #define ZEROPAD 1 /* pad with zero */ 32*2c7d1e30SArvind Sankar #define SIGN 2 /* unsigned/signed long */ 33*2c7d1e30SArvind Sankar #define PLUS 4 /* show plus */ 34*2c7d1e30SArvind Sankar #define SPACE 8 /* space if plus */ 35*2c7d1e30SArvind Sankar #define LEFT 16 /* left justified */ 36*2c7d1e30SArvind Sankar #define SMALL 32 /* Must be 32 == 0x20 */ 37*2c7d1e30SArvind Sankar #define SPECIAL 64 /* 0x */ 38*2c7d1e30SArvind Sankar 39*2c7d1e30SArvind Sankar #define __do_div(n, base) ({ \ 40*2c7d1e30SArvind Sankar int __res; \ 41*2c7d1e30SArvind Sankar __res = ((unsigned long) n) % (unsigned) base; \ 42*2c7d1e30SArvind Sankar n = ((unsigned long) n) / (unsigned) base; \ 43*2c7d1e30SArvind Sankar __res; }) 44*2c7d1e30SArvind Sankar 45*2c7d1e30SArvind Sankar static char *number(char *str, long num, int base, int size, int precision, 46*2c7d1e30SArvind Sankar int type) 47*2c7d1e30SArvind Sankar { 48*2c7d1e30SArvind Sankar /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 49*2c7d1e30SArvind Sankar static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 50*2c7d1e30SArvind Sankar 51*2c7d1e30SArvind Sankar char tmp[66]; 52*2c7d1e30SArvind Sankar char c, sign, locase; 53*2c7d1e30SArvind Sankar int i; 54*2c7d1e30SArvind Sankar 55*2c7d1e30SArvind Sankar /* locase = 0 or 0x20. ORing digits or letters with 'locase' 56*2c7d1e30SArvind Sankar * produces same digits or (maybe lowercased) letters */ 57*2c7d1e30SArvind Sankar locase = (type & SMALL); 58*2c7d1e30SArvind Sankar if (type & LEFT) 59*2c7d1e30SArvind Sankar type &= ~ZEROPAD; 60*2c7d1e30SArvind Sankar if (base < 2 || base > 16) 61*2c7d1e30SArvind Sankar return NULL; 62*2c7d1e30SArvind Sankar c = (type & ZEROPAD) ? '0' : ' '; 63*2c7d1e30SArvind Sankar sign = 0; 64*2c7d1e30SArvind Sankar if (type & SIGN) { 65*2c7d1e30SArvind Sankar if (num < 0) { 66*2c7d1e30SArvind Sankar sign = '-'; 67*2c7d1e30SArvind Sankar num = -num; 68*2c7d1e30SArvind Sankar size--; 69*2c7d1e30SArvind Sankar } else if (type & PLUS) { 70*2c7d1e30SArvind Sankar sign = '+'; 71*2c7d1e30SArvind Sankar size--; 72*2c7d1e30SArvind Sankar } else if (type & SPACE) { 73*2c7d1e30SArvind Sankar sign = ' '; 74*2c7d1e30SArvind Sankar size--; 75*2c7d1e30SArvind Sankar } 76*2c7d1e30SArvind Sankar } 77*2c7d1e30SArvind Sankar if (type & SPECIAL) { 78*2c7d1e30SArvind Sankar if (base == 16) 79*2c7d1e30SArvind Sankar size -= 2; 80*2c7d1e30SArvind Sankar else if (base == 8) 81*2c7d1e30SArvind Sankar size--; 82*2c7d1e30SArvind Sankar } 83*2c7d1e30SArvind Sankar i = 0; 84*2c7d1e30SArvind Sankar if (num == 0) 85*2c7d1e30SArvind Sankar tmp[i++] = '0'; 86*2c7d1e30SArvind Sankar else 87*2c7d1e30SArvind Sankar while (num != 0) 88*2c7d1e30SArvind Sankar tmp[i++] = (digits[__do_div(num, base)] | locase); 89*2c7d1e30SArvind Sankar if (i > precision) 90*2c7d1e30SArvind Sankar precision = i; 91*2c7d1e30SArvind Sankar size -= precision; 92*2c7d1e30SArvind Sankar if (!(type & (ZEROPAD + LEFT))) 93*2c7d1e30SArvind Sankar while (size-- > 0) 94*2c7d1e30SArvind Sankar *str++ = ' '; 95*2c7d1e30SArvind Sankar if (sign) 96*2c7d1e30SArvind Sankar *str++ = sign; 97*2c7d1e30SArvind Sankar if (type & SPECIAL) { 98*2c7d1e30SArvind Sankar if (base == 8) { 99*2c7d1e30SArvind Sankar *str++ = '0'; 100*2c7d1e30SArvind Sankar } else if (base == 16) { 101*2c7d1e30SArvind Sankar *str++ = '0'; 102*2c7d1e30SArvind Sankar *str++ = ('X' | locase); 103*2c7d1e30SArvind Sankar } 104*2c7d1e30SArvind Sankar } 105*2c7d1e30SArvind Sankar if (!(type & LEFT)) 106*2c7d1e30SArvind Sankar while (size-- > 0) 107*2c7d1e30SArvind Sankar *str++ = c; 108*2c7d1e30SArvind Sankar while (i < precision--) 109*2c7d1e30SArvind Sankar *str++ = '0'; 110*2c7d1e30SArvind Sankar while (i-- > 0) 111*2c7d1e30SArvind Sankar *str++ = tmp[i]; 112*2c7d1e30SArvind Sankar while (size-- > 0) 113*2c7d1e30SArvind Sankar *str++ = ' '; 114*2c7d1e30SArvind Sankar return str; 115*2c7d1e30SArvind Sankar } 116*2c7d1e30SArvind Sankar 117*2c7d1e30SArvind Sankar int vsprintf(char *buf, const char *fmt, va_list args) 118*2c7d1e30SArvind Sankar { 119*2c7d1e30SArvind Sankar int len; 120*2c7d1e30SArvind Sankar unsigned long num; 121*2c7d1e30SArvind Sankar int i, base; 122*2c7d1e30SArvind Sankar char *str; 123*2c7d1e30SArvind Sankar const char *s; 124*2c7d1e30SArvind Sankar 125*2c7d1e30SArvind Sankar int flags; /* flags to number() */ 126*2c7d1e30SArvind Sankar 127*2c7d1e30SArvind Sankar int field_width; /* width of output field */ 128*2c7d1e30SArvind Sankar int precision; /* min. # of digits for integers; max 129*2c7d1e30SArvind Sankar number of chars for from string */ 130*2c7d1e30SArvind Sankar int qualifier; /* 'h', 'l', or 'L' for integer fields */ 131*2c7d1e30SArvind Sankar 132*2c7d1e30SArvind Sankar for (str = buf; *fmt; ++fmt) { 133*2c7d1e30SArvind Sankar if (*fmt != '%') { 134*2c7d1e30SArvind Sankar *str++ = *fmt; 135*2c7d1e30SArvind Sankar continue; 136*2c7d1e30SArvind Sankar } 137*2c7d1e30SArvind Sankar 138*2c7d1e30SArvind Sankar /* process flags */ 139*2c7d1e30SArvind Sankar flags = 0; 140*2c7d1e30SArvind Sankar repeat: 141*2c7d1e30SArvind Sankar ++fmt; /* this also skips first '%' */ 142*2c7d1e30SArvind Sankar switch (*fmt) { 143*2c7d1e30SArvind Sankar case '-': 144*2c7d1e30SArvind Sankar flags |= LEFT; 145*2c7d1e30SArvind Sankar goto repeat; 146*2c7d1e30SArvind Sankar case '+': 147*2c7d1e30SArvind Sankar flags |= PLUS; 148*2c7d1e30SArvind Sankar goto repeat; 149*2c7d1e30SArvind Sankar case ' ': 150*2c7d1e30SArvind Sankar flags |= SPACE; 151*2c7d1e30SArvind Sankar goto repeat; 152*2c7d1e30SArvind Sankar case '#': 153*2c7d1e30SArvind Sankar flags |= SPECIAL; 154*2c7d1e30SArvind Sankar goto repeat; 155*2c7d1e30SArvind Sankar case '0': 156*2c7d1e30SArvind Sankar flags |= ZEROPAD; 157*2c7d1e30SArvind Sankar goto repeat; 158*2c7d1e30SArvind Sankar } 159*2c7d1e30SArvind Sankar 160*2c7d1e30SArvind Sankar /* get field width */ 161*2c7d1e30SArvind Sankar field_width = -1; 162*2c7d1e30SArvind Sankar if (isdigit(*fmt)) { 163*2c7d1e30SArvind Sankar field_width = skip_atoi(&fmt); 164*2c7d1e30SArvind Sankar } else if (*fmt == '*') { 165*2c7d1e30SArvind Sankar ++fmt; 166*2c7d1e30SArvind Sankar /* it's the next argument */ 167*2c7d1e30SArvind Sankar field_width = va_arg(args, int); 168*2c7d1e30SArvind Sankar if (field_width < 0) { 169*2c7d1e30SArvind Sankar field_width = -field_width; 170*2c7d1e30SArvind Sankar flags |= LEFT; 171*2c7d1e30SArvind Sankar } 172*2c7d1e30SArvind Sankar } 173*2c7d1e30SArvind Sankar 174*2c7d1e30SArvind Sankar /* get the precision */ 175*2c7d1e30SArvind Sankar precision = -1; 176*2c7d1e30SArvind Sankar if (*fmt == '.') { 177*2c7d1e30SArvind Sankar ++fmt; 178*2c7d1e30SArvind Sankar if (isdigit(*fmt)) { 179*2c7d1e30SArvind Sankar precision = skip_atoi(&fmt); 180*2c7d1e30SArvind Sankar } else if (*fmt == '*') { 181*2c7d1e30SArvind Sankar ++fmt; 182*2c7d1e30SArvind Sankar /* it's the next argument */ 183*2c7d1e30SArvind Sankar precision = va_arg(args, int); 184*2c7d1e30SArvind Sankar } 185*2c7d1e30SArvind Sankar if (precision < 0) 186*2c7d1e30SArvind Sankar precision = 0; 187*2c7d1e30SArvind Sankar } 188*2c7d1e30SArvind Sankar 189*2c7d1e30SArvind Sankar /* get the conversion qualifier */ 190*2c7d1e30SArvind Sankar qualifier = -1; 191*2c7d1e30SArvind Sankar if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { 192*2c7d1e30SArvind Sankar qualifier = *fmt; 193*2c7d1e30SArvind Sankar ++fmt; 194*2c7d1e30SArvind Sankar } 195*2c7d1e30SArvind Sankar 196*2c7d1e30SArvind Sankar /* default base */ 197*2c7d1e30SArvind Sankar base = 10; 198*2c7d1e30SArvind Sankar 199*2c7d1e30SArvind Sankar switch (*fmt) { 200*2c7d1e30SArvind Sankar case 'c': 201*2c7d1e30SArvind Sankar if (!(flags & LEFT)) 202*2c7d1e30SArvind Sankar while (--field_width > 0) 203*2c7d1e30SArvind Sankar *str++ = ' '; 204*2c7d1e30SArvind Sankar *str++ = (unsigned char)va_arg(args, int); 205*2c7d1e30SArvind Sankar while (--field_width > 0) 206*2c7d1e30SArvind Sankar *str++ = ' '; 207*2c7d1e30SArvind Sankar continue; 208*2c7d1e30SArvind Sankar 209*2c7d1e30SArvind Sankar case 's': 210*2c7d1e30SArvind Sankar s = va_arg(args, char *); 211*2c7d1e30SArvind Sankar len = strnlen(s, precision); 212*2c7d1e30SArvind Sankar 213*2c7d1e30SArvind Sankar if (!(flags & LEFT)) 214*2c7d1e30SArvind Sankar while (len < field_width--) 215*2c7d1e30SArvind Sankar *str++ = ' '; 216*2c7d1e30SArvind Sankar for (i = 0; i < len; ++i) 217*2c7d1e30SArvind Sankar *str++ = *s++; 218*2c7d1e30SArvind Sankar while (len < field_width--) 219*2c7d1e30SArvind Sankar *str++ = ' '; 220*2c7d1e30SArvind Sankar continue; 221*2c7d1e30SArvind Sankar 222*2c7d1e30SArvind Sankar case 'p': 223*2c7d1e30SArvind Sankar if (field_width == -1) { 224*2c7d1e30SArvind Sankar field_width = 2 * sizeof(void *); 225*2c7d1e30SArvind Sankar flags |= ZEROPAD; 226*2c7d1e30SArvind Sankar } 227*2c7d1e30SArvind Sankar str = number(str, 228*2c7d1e30SArvind Sankar (unsigned long)va_arg(args, void *), 16, 229*2c7d1e30SArvind Sankar field_width, precision, flags); 230*2c7d1e30SArvind Sankar continue; 231*2c7d1e30SArvind Sankar 232*2c7d1e30SArvind Sankar case 'n': 233*2c7d1e30SArvind Sankar if (qualifier == 'l') { 234*2c7d1e30SArvind Sankar long *ip = va_arg(args, long *); 235*2c7d1e30SArvind Sankar *ip = (str - buf); 236*2c7d1e30SArvind Sankar } else { 237*2c7d1e30SArvind Sankar int *ip = va_arg(args, int *); 238*2c7d1e30SArvind Sankar *ip = (str - buf); 239*2c7d1e30SArvind Sankar } 240*2c7d1e30SArvind Sankar continue; 241*2c7d1e30SArvind Sankar 242*2c7d1e30SArvind Sankar case '%': 243*2c7d1e30SArvind Sankar *str++ = '%'; 244*2c7d1e30SArvind Sankar continue; 245*2c7d1e30SArvind Sankar 246*2c7d1e30SArvind Sankar /* integer number formats - set up the flags and "break" */ 247*2c7d1e30SArvind Sankar case 'o': 248*2c7d1e30SArvind Sankar base = 8; 249*2c7d1e30SArvind Sankar break; 250*2c7d1e30SArvind Sankar 251*2c7d1e30SArvind Sankar case 'x': 252*2c7d1e30SArvind Sankar flags |= SMALL; 253*2c7d1e30SArvind Sankar fallthrough; 254*2c7d1e30SArvind Sankar case 'X': 255*2c7d1e30SArvind Sankar base = 16; 256*2c7d1e30SArvind Sankar break; 257*2c7d1e30SArvind Sankar 258*2c7d1e30SArvind Sankar case 'd': 259*2c7d1e30SArvind Sankar case 'i': 260*2c7d1e30SArvind Sankar flags |= SIGN; 261*2c7d1e30SArvind Sankar fallthrough; 262*2c7d1e30SArvind Sankar case 'u': 263*2c7d1e30SArvind Sankar break; 264*2c7d1e30SArvind Sankar 265*2c7d1e30SArvind Sankar default: 266*2c7d1e30SArvind Sankar *str++ = '%'; 267*2c7d1e30SArvind Sankar if (*fmt) 268*2c7d1e30SArvind Sankar *str++ = *fmt; 269*2c7d1e30SArvind Sankar else 270*2c7d1e30SArvind Sankar --fmt; 271*2c7d1e30SArvind Sankar continue; 272*2c7d1e30SArvind Sankar } 273*2c7d1e30SArvind Sankar if (qualifier == 'l') { 274*2c7d1e30SArvind Sankar num = va_arg(args, unsigned long); 275*2c7d1e30SArvind Sankar } else if (qualifier == 'h') { 276*2c7d1e30SArvind Sankar num = (unsigned short)va_arg(args, int); 277*2c7d1e30SArvind Sankar if (flags & SIGN) 278*2c7d1e30SArvind Sankar num = (short)num; 279*2c7d1e30SArvind Sankar } else if (flags & SIGN) { 280*2c7d1e30SArvind Sankar num = va_arg(args, int); 281*2c7d1e30SArvind Sankar } else { 282*2c7d1e30SArvind Sankar num = va_arg(args, unsigned int); 283*2c7d1e30SArvind Sankar } 284*2c7d1e30SArvind Sankar str = number(str, num, base, field_width, precision, flags); 285*2c7d1e30SArvind Sankar } 286*2c7d1e30SArvind Sankar *str = '\0'; 287*2c7d1e30SArvind Sankar return str - buf; 288*2c7d1e30SArvind Sankar } 289*2c7d1e30SArvind Sankar 290*2c7d1e30SArvind Sankar int sprintf(char *buf, const char *fmt, ...) 291*2c7d1e30SArvind Sankar { 292*2c7d1e30SArvind Sankar va_list args; 293*2c7d1e30SArvind Sankar int i; 294*2c7d1e30SArvind Sankar 295*2c7d1e30SArvind Sankar va_start(args, fmt); 296*2c7d1e30SArvind Sankar i = vsprintf(buf, fmt, args); 297*2c7d1e30SArvind Sankar va_end(args); 298*2c7d1e30SArvind Sankar return i; 299*2c7d1e30SArvind Sankar } 300