/* -*- linux-c -*-------------------------------------------------------- *
*
* Copyright (C) 1991, 1992 Linus Torvalds
* Copyright 2007 rPath, Inc. - All Rights Reserved
*
* Thisfile is part of the Linux kernel, and is made available under
* theterms of the GNU General Public License version 2.
*
*----------------------------------------------------------------------- */
/*
*Oh, it's a waste of space, but oh-so-yummy for debugging. This
*version of printf() does not include 64-bit support. "Live with
*it."
*
*/
#include "boot.h"
static int skip_atoi(const char **s)
{
inti = 0;
while(isdigit(**s))
i= i * 10 + *((*s)++) - '0';
returni;
}
#define ZEROPAD 1 /* pad withzero */
#define SIGN 2 /*unsigned/signed long */
#define PLUS 4 /* showplus */
#define SPACE 8 /* space ifplus */
#define LEFT 16 /* leftjustified */
#define SMALL 32 /*Must be 32 == 0x20 */
#define SPECIAL 64 /* 0x */
#define __do_div(n, base) ({ \
int __res; \
__res = ((unsigned long) n) % (unsigned)base; \
n = ((unsigned long) n) / (unsigned) base;\
__res; })
static char *number(char *str, long num,int base, int size, int precision,
int type)
{
/*we are called with base 8, 10 or 16, only, thus don't need"G..." */
staticconst char digits[16] = "0123456789ABCDEF"; /*"GHIJKLMNOPQRSTUVWXYZ"; */
chartmp[66];
charc, sign, locase;
inti;
/*locase = 0 or 0x20. ORing digits or letters with 'locase'
* produces same digits or (maybe lowercased)letters */
locase= (type & SMALL);
if(type & LEFT)
type&= ~ZEROPAD;
if(base < 2 || base > 36)
returnNULL;
c= (type & ZEROPAD) ? '0' : ' ';
sign= 0;
if(type & SIGN) {
if(num < 0) {
sign= '-';
num= -num;
size--;
}else if (type & PLUS) {
sign= '+';
size--;
}else if (type & SPACE) {
sign= ' ';
size--;
}
}
if(type & SPECIAL) {
if(base == 16)
size-= 2;
elseif (base == 8)
size--;
}
i= 0;
if(num == 0)
tmp[i++]= '0';
else
while(num != 0)
tmp[i++]= (digits[__do_div(num, base)] | locase);
if(i > precision)
precision= i;
size-= precision;
if(!(type & (ZEROPAD + LEFT)))
while(size-- > 0)
*str++= ' ';
if(sign)
*str++= sign;
if(type & SPECIAL) {
if(base == 8)
*str++= '0';
elseif (base == 16) {
*str++= '0';
*str++= ('X' | locase);
}
}
if(!(type & LEFT))
while(size-- > 0)
*str++= c;
while(i < precision--)
*str++= '0';
while(i-- > 0)
*str++= tmp[i];
while(size-- > 0)
*str++= ' ';
returnstr;
}
int vsprintf(char *buf, const char *fmt,va_list args)
{
intlen;
unsignedlong num;
inti, base;
char*str;
constchar *s;
intflags; /* flags to number() */
intfield_width; /* width of outputfield */
intprecision; /* min. # of digitsfor integers; max
number of chars for from string */
intqualifier; /* 'h', 'l', or'L' for integer fields */
for(str = buf; *fmt; ++fmt) {
if(*fmt != '%') {
*str++= *fmt;
continue;
}
/*process flags */
flags= 0;
repeat:
++fmt; /* this also skips first '%' */
switch(*fmt) {
case'-':
flags|= LEFT;
gotorepeat;
case'+':
flags|= PLUS;
gotorepeat;
case' ':
flags|= SPACE;
gotorepeat;
case'#':
flags|= SPECIAL;
gotorepeat;
case'0':
flags|= ZEROPAD;
gotorepeat;
}
/*get field width */
field_width= -1;
if(isdigit(*fmt))
field_width= skip_atoi(&fmt);
elseif (*fmt == '*') {
++fmt;
/*it's the next argument */
field_width= va_arg(args, int);
if(field_width < 0) {
field_width= -field_width;
flags|= LEFT;
}
}
/*get the precision */
precision= -1;
if(*fmt == '.') {
++fmt;
if(isdigit(*fmt))
precision= skip_atoi(&fmt);
elseif (*fmt == '*') {
++fmt;
/*it's the next argument */
precision= va_arg(args, int);
}
if(precision < 0)
precision= 0;
}
/*get the conversion qualifier */
qualifier= -1;
if(*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
qualifier= *fmt;
++fmt;
}
/*default base */
base= 10;
switch(*fmt) {
case'c':
if(!(flags & LEFT))
while(--field_width > 0)
*str++= ' ';
*str++= (unsigned char)va_arg(args, int);
while(--field_width > 0)
*str++= ' ';
continue;
case's':
s= va_arg(args, char *);
len= strnlen(s, precision);
if(!(flags & LEFT))
while(len < field_width--)
*str++= ' ';
for(i = 0; i < len; ++i)
*str++= *s++;
while(len < field_width--)
*str++= ' ';
continue;
case'p':
if(field_width == -1) {
field_width= 2 * sizeof(void *);
flags|= ZEROPAD;
}
str= number(str,
(unsigned long)va_arg(args, void *), 16,
field_width, precision, flags);
continue;
case'n':
if(qualifier == 'l') {
long*ip = va_arg(args, long *);
*ip= (str - buf);
}else {
int*ip = va_arg(args, int *);
*ip= (str - buf);
}
continue;
case'%':
*str++= '%';
continue;
/*integer number formats - set up the flags and "break" */
case'o':
base= 8;
break;
case'x':
flags|= SMALL;
case'X':
base= 16;
break;
case'd':
case'i':
flags|= SIGN;
case'u':
break;
default:
*str++= '%';
if(*fmt)
*str++= *fmt;
else
--fmt;
continue;
}
if(qualifier == 'l')
num= va_arg(args, unsigned long);
elseif (qualifier == 'h') {
num= (unsigned short)va_arg(args, int);
if(flags & SIGN)
num= (short)num;
}else if (flags & SIGN)
num= va_arg(args, int);
else
num= va_arg(args, unsigned int);
str= number(str, num, base, field_width, precision, flags);
}
*str= '\0';
returnstr - buf;
}
int sprintf(char *buf, const char *fmt,...)
{
va_listargs;
inti;
va_start(args,fmt);
i= vsprintf(buf, fmt, args);
va_end(args);
returni;
}
int printf(const char *fmt, ...)
{
charprintf_buf[1024];
va_listargs;
intprinted;
va_start(args,fmt);
printed= vsprintf(printf_buf, fmt, args);
va_end(args);
puts(printf_buf);
returnprinted;
}