diff options
| author | wdenk <wdenk> | 2002-08-30 11:07:04 +0000 | 
|---|---|---|
| committer | wdenk <wdenk> | 2002-08-30 11:07:04 +0000 | 
| commit | 153d511e36917ee67d52d36d5d5e9ca41406610a (patch) | |
| tree | c82d3d0c6501ea007d748a295e210e9be81cc248 /lib_generic/vsprintf.c | |
| parent | b6a6460b7dfa1629ecf187c2091737c0ed2585bf (diff) | |
| download | olio-uboot-2014.01-153d511e36917ee67d52d36d5d5e9ca41406610a.tar.xz olio-uboot-2014.01-153d511e36917ee67d52d36d5d5e9ca41406610a.zip | |
Initial revision
Diffstat (limited to 'lib_generic/vsprintf.c')
| -rw-r--r-- | lib_generic/vsprintf.c | 341 | 
1 files changed, 341 insertions, 0 deletions
| diff --git a/lib_generic/vsprintf.c b/lib_generic/vsprintf.c new file mode 100644 index 000000000..d7a766157 --- /dev/null +++ b/lib_generic/vsprintf.c @@ -0,0 +1,341 @@ +/* + *  linux/lib/vsprintf.c + * + *  Copyright (C) 1991, 1992  Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include <stdarg.h> +#include <linux/types.h> +#include <linux/string.h> +#include <linux/ctype.h> + +#include <common.h> +#if !defined (CONFIG_PANIC_HANG) +#include <command.h> +#include <cmd_boot.h>		/* for do_reset() prototype */ +#endif + +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) +{ +	unsigned long result = 0,value; + +	if (*cp == '0') { +		cp++; +		if ((*cp == 'x') && isxdigit(cp[1])) { +			base = 16; +			cp++; +		} +		if (!base) { +			base = 8; +		} +	} +	if (!base) { +		base = 10; +	} +	while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) +	    ? toupper(*cp) : *cp)-'A'+10) < base) { +		result = result*base + value; +		cp++; +	} +	if (endp) +		*endp = (char *)cp; +	return result; +} + +long simple_strtol(const char *cp,char **endp,unsigned int base) +{ +	if(*cp=='-') +		return -simple_strtoul(cp+1,endp,base); +	return simple_strtoul(cp,endp,base); +} + +/* we use this so that we can do without the ctype library */ +#define is_digit(c)	((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ +	int i=0; + +	while (is_digit(**s)) +		i = i*10 + *((*s)++) - '0'; +	return i; +} + +#define ZEROPAD	1		/* pad with zero */ +#define SIGN	2		/* unsigned/signed long */ +#define PLUS	4		/* show plus */ +#define SPACE	8		/* space if plus */ +#define LEFT	16		/* left justified */ +#define SPECIAL	32		/* 0x */ +#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */ + +#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) +{ +	char c,sign,tmp[66]; +	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; +	int i; + +	if (type & LARGE) +		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; +	if (type & LEFT) +		type &= ~ZEROPAD; +	if (base < 2 || base > 36) +		return 0; +	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; +		else if (base == 8) +			size--; +	} +	i = 0; +	if (num == 0) +		tmp[i++]='0'; +	else while (num != 0) +		tmp[i++] = digits[do_div(num,base)]; +	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'; +		else if (base==16) { +			*str++ = '0'; +			*str++ = digits[33]; +		} +	} +	if (!(type & LEFT)) +		while (size-- > 0) +			*str++ = c; +	while (i < precision--) +		*str++ = '0'; +	while (i-- > 0) +		*str++ = tmp[i]; +	while (size-- > 0) +		*str++ = ' '; +	return str; +} + +/* Forward decl. needed for IP address printing stuff... */ +int sprintf(char * buf, const char *fmt, ...); + +int vsprintf(char *buf, const char *fmt, va_list args) +{ +	int len; +	unsigned long num; +	int i, base; +	char * str; +	const char *s; + +	int flags;		/* flags to number() */ + +	int field_width;	/* width of output field */ +	int precision;		/* min. # of digits for integers; max +				   number of chars for from string */ +	int qualifier;		/* '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; goto repeat; +				case '+': flags |= PLUS; goto repeat; +				case ' ': flags |= SPACE; goto repeat; +				case '#': flags |= SPECIAL; goto repeat; +				case '0': flags |= ZEROPAD; goto repeat; +				} + +		/* get field width */ +		field_width = -1; +		if (is_digit(*fmt)) +			field_width = skip_atoi(&fmt); +		else if (*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 (is_digit(*fmt)) +				precision = skip_atoi(&fmt); +			else if (*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 *); +			if (!s) +				s = "<NULL>"; + +			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 |= LARGE; +		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); +		else if (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'; +	return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ +	va_list args; +	int i; + +	va_start(args, fmt); +	i=vsprintf(buf,fmt,args); +	va_end(args); +	return i; +} + +void panic(const char *fmt, ...) +{ +	va_list	args; +	va_start(args, fmt); +	printf(fmt); +	putc('\n'); +	va_end(args); +#if defined (CONFIG_PANIC_HANG) +	hang(); +#else +	udelay (100000);	/* allow messages to go out */ +	do_reset (NULL, 0, 0, NULL); +#endif +} |