196ae6ea0SThomas Gleixner /* -*- linux-c -*- ------------------------------------------------------- * 296ae6ea0SThomas Gleixner * 396ae6ea0SThomas Gleixner * Copyright (C) 1991, 1992 Linus Torvalds 496ae6ea0SThomas Gleixner * Copyright 2007 rPath, Inc. - All Rights Reserved 596ae6ea0SThomas Gleixner * 696ae6ea0SThomas Gleixner * This file is part of the Linux kernel, and is made available under 796ae6ea0SThomas Gleixner * the terms of the GNU General Public License version 2. 896ae6ea0SThomas Gleixner * 996ae6ea0SThomas Gleixner * ----------------------------------------------------------------------- */ 1096ae6ea0SThomas Gleixner 1196ae6ea0SThomas Gleixner /* 1296ae6ea0SThomas Gleixner * arch/i386/boot/printf.c 1396ae6ea0SThomas Gleixner * 1496ae6ea0SThomas Gleixner * Oh, it's a waste of space, but oh-so-yummy for debugging. This 1596ae6ea0SThomas Gleixner * version of printf() does not include 64-bit support. "Live with 1696ae6ea0SThomas Gleixner * it." 1796ae6ea0SThomas Gleixner * 1896ae6ea0SThomas Gleixner */ 1996ae6ea0SThomas Gleixner 2096ae6ea0SThomas Gleixner #include "boot.h" 2196ae6ea0SThomas Gleixner 2296ae6ea0SThomas Gleixner static int skip_atoi(const char **s) 2396ae6ea0SThomas Gleixner { 2496ae6ea0SThomas Gleixner int i = 0; 2596ae6ea0SThomas Gleixner 2696ae6ea0SThomas Gleixner while (isdigit(**s)) 2796ae6ea0SThomas Gleixner i = i * 10 + *((*s)++) - '0'; 2896ae6ea0SThomas Gleixner return i; 2996ae6ea0SThomas Gleixner } 3096ae6ea0SThomas Gleixner 3196ae6ea0SThomas Gleixner #define ZEROPAD 1 /* pad with zero */ 3296ae6ea0SThomas Gleixner #define SIGN 2 /* unsigned/signed long */ 3396ae6ea0SThomas Gleixner #define PLUS 4 /* show plus */ 3496ae6ea0SThomas Gleixner #define SPACE 8 /* space if plus */ 3596ae6ea0SThomas Gleixner #define LEFT 16 /* left justified */ 36*9b706aeeSDenys Vlasenko #define SMALL 32 /* Must be 32 == 0x20 */ 37*9b706aeeSDenys Vlasenko #define SPECIAL 64 /* 0x */ 3896ae6ea0SThomas Gleixner 3996ae6ea0SThomas Gleixner #define do_div(n,base) ({ \ 4096ae6ea0SThomas Gleixner int __res; \ 4196ae6ea0SThomas Gleixner __res = ((unsigned long) n) % (unsigned) base; \ 4296ae6ea0SThomas Gleixner n = ((unsigned long) n) / (unsigned) base; \ 4396ae6ea0SThomas Gleixner __res; }) 4496ae6ea0SThomas Gleixner 4596ae6ea0SThomas Gleixner static char *number(char *str, long num, int base, int size, int precision, 4696ae6ea0SThomas Gleixner int type) 4796ae6ea0SThomas Gleixner { 48*9b706aeeSDenys Vlasenko /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 49*9b706aeeSDenys Vlasenko static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 50*9b706aeeSDenys Vlasenko 51*9b706aeeSDenys Vlasenko char tmp[66]; 52*9b706aeeSDenys Vlasenko char c, sign, locase; 5396ae6ea0SThomas Gleixner int i; 5496ae6ea0SThomas Gleixner 55*9b706aeeSDenys Vlasenko /* locase = 0 or 0x20. ORing digits or letters with 'locase' 56*9b706aeeSDenys Vlasenko * produces same digits or (maybe lowercased) letters */ 57*9b706aeeSDenys Vlasenko locase = (type & SMALL); 5896ae6ea0SThomas Gleixner if (type & LEFT) 5996ae6ea0SThomas Gleixner type &= ~ZEROPAD; 6096ae6ea0SThomas Gleixner if (base < 2 || base > 36) 6196ae6ea0SThomas Gleixner return 0; 6296ae6ea0SThomas Gleixner c = (type & ZEROPAD) ? '0' : ' '; 6396ae6ea0SThomas Gleixner sign = 0; 6496ae6ea0SThomas Gleixner if (type & SIGN) { 6596ae6ea0SThomas Gleixner if (num < 0) { 6696ae6ea0SThomas Gleixner sign = '-'; 6796ae6ea0SThomas Gleixner num = -num; 6896ae6ea0SThomas Gleixner size--; 6996ae6ea0SThomas Gleixner } else if (type & PLUS) { 7096ae6ea0SThomas Gleixner sign = '+'; 7196ae6ea0SThomas Gleixner size--; 7296ae6ea0SThomas Gleixner } else if (type & SPACE) { 7396ae6ea0SThomas Gleixner sign = ' '; 7496ae6ea0SThomas Gleixner size--; 7596ae6ea0SThomas Gleixner } 7696ae6ea0SThomas Gleixner } 7796ae6ea0SThomas Gleixner if (type & SPECIAL) { 7896ae6ea0SThomas Gleixner if (base == 16) 7996ae6ea0SThomas Gleixner size -= 2; 8096ae6ea0SThomas Gleixner else if (base == 8) 8196ae6ea0SThomas Gleixner size--; 8296ae6ea0SThomas Gleixner } 8396ae6ea0SThomas Gleixner i = 0; 8496ae6ea0SThomas Gleixner if (num == 0) 8596ae6ea0SThomas Gleixner tmp[i++] = '0'; 8696ae6ea0SThomas Gleixner else 8796ae6ea0SThomas Gleixner while (num != 0) 88*9b706aeeSDenys Vlasenko tmp[i++] = (digits[do_div(num, base)] | locase); 8996ae6ea0SThomas Gleixner if (i > precision) 9096ae6ea0SThomas Gleixner precision = i; 9196ae6ea0SThomas Gleixner size -= precision; 9296ae6ea0SThomas Gleixner if (!(type & (ZEROPAD + LEFT))) 9396ae6ea0SThomas Gleixner while (size-- > 0) 9496ae6ea0SThomas Gleixner *str++ = ' '; 9596ae6ea0SThomas Gleixner if (sign) 9696ae6ea0SThomas Gleixner *str++ = sign; 9796ae6ea0SThomas Gleixner if (type & SPECIAL) { 9896ae6ea0SThomas Gleixner if (base == 8) 9996ae6ea0SThomas Gleixner *str++ = '0'; 10096ae6ea0SThomas Gleixner else if (base == 16) { 10196ae6ea0SThomas Gleixner *str++ = '0'; 102*9b706aeeSDenys Vlasenko *str++ = ('X' | locase); 10396ae6ea0SThomas Gleixner } 10496ae6ea0SThomas Gleixner } 10596ae6ea0SThomas Gleixner if (!(type & LEFT)) 10696ae6ea0SThomas Gleixner while (size-- > 0) 10796ae6ea0SThomas Gleixner *str++ = c; 10896ae6ea0SThomas Gleixner while (i < precision--) 10996ae6ea0SThomas Gleixner *str++ = '0'; 11096ae6ea0SThomas Gleixner while (i-- > 0) 11196ae6ea0SThomas Gleixner *str++ = tmp[i]; 11296ae6ea0SThomas Gleixner while (size-- > 0) 11396ae6ea0SThomas Gleixner *str++ = ' '; 11496ae6ea0SThomas Gleixner return str; 11596ae6ea0SThomas Gleixner } 11696ae6ea0SThomas Gleixner 11796ae6ea0SThomas Gleixner int vsprintf(char *buf, const char *fmt, va_list args) 11896ae6ea0SThomas Gleixner { 11996ae6ea0SThomas Gleixner int len; 12096ae6ea0SThomas Gleixner unsigned long num; 12196ae6ea0SThomas Gleixner int i, base; 12296ae6ea0SThomas Gleixner char *str; 12396ae6ea0SThomas Gleixner const char *s; 12496ae6ea0SThomas Gleixner 12596ae6ea0SThomas Gleixner int flags; /* flags to number() */ 12696ae6ea0SThomas Gleixner 12796ae6ea0SThomas Gleixner int field_width; /* width of output field */ 12896ae6ea0SThomas Gleixner int precision; /* min. # of digits for integers; max 12996ae6ea0SThomas Gleixner number of chars for from string */ 13096ae6ea0SThomas Gleixner int qualifier; /* 'h', 'l', or 'L' for integer fields */ 13196ae6ea0SThomas Gleixner 13296ae6ea0SThomas Gleixner for (str = buf; *fmt; ++fmt) { 13396ae6ea0SThomas Gleixner if (*fmt != '%') { 13496ae6ea0SThomas Gleixner *str++ = *fmt; 13596ae6ea0SThomas Gleixner continue; 13696ae6ea0SThomas Gleixner } 13796ae6ea0SThomas Gleixner 13896ae6ea0SThomas Gleixner /* process flags */ 13996ae6ea0SThomas Gleixner flags = 0; 14096ae6ea0SThomas Gleixner repeat: 14196ae6ea0SThomas Gleixner ++fmt; /* this also skips first '%' */ 14296ae6ea0SThomas Gleixner switch (*fmt) { 14396ae6ea0SThomas Gleixner case '-': 14496ae6ea0SThomas Gleixner flags |= LEFT; 14596ae6ea0SThomas Gleixner goto repeat; 14696ae6ea0SThomas Gleixner case '+': 14796ae6ea0SThomas Gleixner flags |= PLUS; 14896ae6ea0SThomas Gleixner goto repeat; 14996ae6ea0SThomas Gleixner case ' ': 15096ae6ea0SThomas Gleixner flags |= SPACE; 15196ae6ea0SThomas Gleixner goto repeat; 15296ae6ea0SThomas Gleixner case '#': 15396ae6ea0SThomas Gleixner flags |= SPECIAL; 15496ae6ea0SThomas Gleixner goto repeat; 15596ae6ea0SThomas Gleixner case '0': 15696ae6ea0SThomas Gleixner flags |= ZEROPAD; 15796ae6ea0SThomas Gleixner goto repeat; 15896ae6ea0SThomas Gleixner } 15996ae6ea0SThomas Gleixner 16096ae6ea0SThomas Gleixner /* get field width */ 16196ae6ea0SThomas Gleixner field_width = -1; 16296ae6ea0SThomas Gleixner if (isdigit(*fmt)) 16396ae6ea0SThomas Gleixner field_width = skip_atoi(&fmt); 16496ae6ea0SThomas Gleixner else if (*fmt == '*') { 16596ae6ea0SThomas Gleixner ++fmt; 16696ae6ea0SThomas Gleixner /* it's the next argument */ 16796ae6ea0SThomas Gleixner field_width = va_arg(args, int); 16896ae6ea0SThomas Gleixner if (field_width < 0) { 16996ae6ea0SThomas Gleixner field_width = -field_width; 17096ae6ea0SThomas Gleixner flags |= LEFT; 17196ae6ea0SThomas Gleixner } 17296ae6ea0SThomas Gleixner } 17396ae6ea0SThomas Gleixner 17496ae6ea0SThomas Gleixner /* get the precision */ 17596ae6ea0SThomas Gleixner precision = -1; 17696ae6ea0SThomas Gleixner if (*fmt == '.') { 17796ae6ea0SThomas Gleixner ++fmt; 17896ae6ea0SThomas Gleixner if (isdigit(*fmt)) 17996ae6ea0SThomas Gleixner precision = skip_atoi(&fmt); 18096ae6ea0SThomas Gleixner else if (*fmt == '*') { 18196ae6ea0SThomas Gleixner ++fmt; 18296ae6ea0SThomas Gleixner /* it's the next argument */ 18396ae6ea0SThomas Gleixner precision = va_arg(args, int); 18496ae6ea0SThomas Gleixner } 18596ae6ea0SThomas Gleixner if (precision < 0) 18696ae6ea0SThomas Gleixner precision = 0; 18796ae6ea0SThomas Gleixner } 18896ae6ea0SThomas Gleixner 18996ae6ea0SThomas Gleixner /* get the conversion qualifier */ 19096ae6ea0SThomas Gleixner qualifier = -1; 19196ae6ea0SThomas Gleixner if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { 19296ae6ea0SThomas Gleixner qualifier = *fmt; 19396ae6ea0SThomas Gleixner ++fmt; 19496ae6ea0SThomas Gleixner } 19596ae6ea0SThomas Gleixner 19696ae6ea0SThomas Gleixner /* default base */ 19796ae6ea0SThomas Gleixner base = 10; 19896ae6ea0SThomas Gleixner 19996ae6ea0SThomas Gleixner switch (*fmt) { 20096ae6ea0SThomas Gleixner case 'c': 20196ae6ea0SThomas Gleixner if (!(flags & LEFT)) 20296ae6ea0SThomas Gleixner while (--field_width > 0) 20396ae6ea0SThomas Gleixner *str++ = ' '; 20496ae6ea0SThomas Gleixner *str++ = (unsigned char)va_arg(args, int); 20596ae6ea0SThomas Gleixner while (--field_width > 0) 20696ae6ea0SThomas Gleixner *str++ = ' '; 20796ae6ea0SThomas Gleixner continue; 20896ae6ea0SThomas Gleixner 20996ae6ea0SThomas Gleixner case 's': 21096ae6ea0SThomas Gleixner s = va_arg(args, char *); 21196ae6ea0SThomas Gleixner len = strnlen(s, precision); 21296ae6ea0SThomas Gleixner 21396ae6ea0SThomas Gleixner if (!(flags & LEFT)) 21496ae6ea0SThomas Gleixner while (len < field_width--) 21596ae6ea0SThomas Gleixner *str++ = ' '; 21696ae6ea0SThomas Gleixner for (i = 0; i < len; ++i) 21796ae6ea0SThomas Gleixner *str++ = *s++; 21896ae6ea0SThomas Gleixner while (len < field_width--) 21996ae6ea0SThomas Gleixner *str++ = ' '; 22096ae6ea0SThomas Gleixner continue; 22196ae6ea0SThomas Gleixner 22296ae6ea0SThomas Gleixner case 'p': 22396ae6ea0SThomas Gleixner if (field_width == -1) { 22496ae6ea0SThomas Gleixner field_width = 2 * sizeof(void *); 22596ae6ea0SThomas Gleixner flags |= ZEROPAD; 22696ae6ea0SThomas Gleixner } 22796ae6ea0SThomas Gleixner str = number(str, 22896ae6ea0SThomas Gleixner (unsigned long)va_arg(args, void *), 16, 22996ae6ea0SThomas Gleixner field_width, precision, flags); 23096ae6ea0SThomas Gleixner continue; 23196ae6ea0SThomas Gleixner 23296ae6ea0SThomas Gleixner case 'n': 23396ae6ea0SThomas Gleixner if (qualifier == 'l') { 23496ae6ea0SThomas Gleixner long *ip = va_arg(args, long *); 23596ae6ea0SThomas Gleixner *ip = (str - buf); 23696ae6ea0SThomas Gleixner } else { 23796ae6ea0SThomas Gleixner int *ip = va_arg(args, int *); 23896ae6ea0SThomas Gleixner *ip = (str - buf); 23996ae6ea0SThomas Gleixner } 24096ae6ea0SThomas Gleixner continue; 24196ae6ea0SThomas Gleixner 24296ae6ea0SThomas Gleixner case '%': 24396ae6ea0SThomas Gleixner *str++ = '%'; 24496ae6ea0SThomas Gleixner continue; 24596ae6ea0SThomas Gleixner 24696ae6ea0SThomas Gleixner /* integer number formats - set up the flags and "break" */ 24796ae6ea0SThomas Gleixner case 'o': 24896ae6ea0SThomas Gleixner base = 8; 24996ae6ea0SThomas Gleixner break; 25096ae6ea0SThomas Gleixner 25196ae6ea0SThomas Gleixner case 'x': 252*9b706aeeSDenys Vlasenko flags |= SMALL; 253*9b706aeeSDenys Vlasenko case 'X': 25496ae6ea0SThomas Gleixner base = 16; 25596ae6ea0SThomas Gleixner break; 25696ae6ea0SThomas Gleixner 25796ae6ea0SThomas Gleixner case 'd': 25896ae6ea0SThomas Gleixner case 'i': 25996ae6ea0SThomas Gleixner flags |= SIGN; 26096ae6ea0SThomas Gleixner case 'u': 26196ae6ea0SThomas Gleixner break; 26296ae6ea0SThomas Gleixner 26396ae6ea0SThomas Gleixner default: 26496ae6ea0SThomas Gleixner *str++ = '%'; 26596ae6ea0SThomas Gleixner if (*fmt) 26696ae6ea0SThomas Gleixner *str++ = *fmt; 26796ae6ea0SThomas Gleixner else 26896ae6ea0SThomas Gleixner --fmt; 26996ae6ea0SThomas Gleixner continue; 27096ae6ea0SThomas Gleixner } 27196ae6ea0SThomas Gleixner if (qualifier == 'l') 27296ae6ea0SThomas Gleixner num = va_arg(args, unsigned long); 27396ae6ea0SThomas Gleixner else if (qualifier == 'h') { 27496ae6ea0SThomas Gleixner num = (unsigned short)va_arg(args, int); 27596ae6ea0SThomas Gleixner if (flags & SIGN) 27696ae6ea0SThomas Gleixner num = (short)num; 27796ae6ea0SThomas Gleixner } else if (flags & SIGN) 27896ae6ea0SThomas Gleixner num = va_arg(args, int); 27996ae6ea0SThomas Gleixner else 28096ae6ea0SThomas Gleixner num = va_arg(args, unsigned int); 28196ae6ea0SThomas Gleixner str = number(str, num, base, field_width, precision, flags); 28296ae6ea0SThomas Gleixner } 28396ae6ea0SThomas Gleixner *str = '\0'; 28496ae6ea0SThomas Gleixner return str - buf; 28596ae6ea0SThomas Gleixner } 28696ae6ea0SThomas Gleixner 28796ae6ea0SThomas Gleixner int sprintf(char *buf, const char *fmt, ...) 28896ae6ea0SThomas Gleixner { 28996ae6ea0SThomas Gleixner va_list args; 29096ae6ea0SThomas Gleixner int i; 29196ae6ea0SThomas Gleixner 29296ae6ea0SThomas Gleixner va_start(args, fmt); 29396ae6ea0SThomas Gleixner i = vsprintf(buf, fmt, args); 29496ae6ea0SThomas Gleixner va_end(args); 29596ae6ea0SThomas Gleixner return i; 29696ae6ea0SThomas Gleixner } 29796ae6ea0SThomas Gleixner 29896ae6ea0SThomas Gleixner int printf(const char *fmt, ...) 29996ae6ea0SThomas Gleixner { 30096ae6ea0SThomas Gleixner char printf_buf[1024]; 30196ae6ea0SThomas Gleixner va_list args; 30296ae6ea0SThomas Gleixner int printed; 30396ae6ea0SThomas Gleixner 30496ae6ea0SThomas Gleixner va_start(args, fmt); 30596ae6ea0SThomas Gleixner printed = vsprintf(printf_buf, fmt, args); 30696ae6ea0SThomas Gleixner va_end(args); 30796ae6ea0SThomas Gleixner 30896ae6ea0SThomas Gleixner puts(printf_buf); 30996ae6ea0SThomas Gleixner 31096ae6ea0SThomas Gleixner return printed; 31196ae6ea0SThomas Gleixner } 312