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