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