2267 lines · 53.0 KB · C
RawDownload
/* *  linux/lib/vsprintf.c * *  Copyright (C) 1991, 1992  Linus Torvalds */ /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. *//* * Wirzenius wrote this portably, Torvalds fucked it up :-) */ /* * Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com> * - changed to provide snprintf and vsnprintf functions * So Feb  1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de> * - scnprintf and vscnprintf */ #include <stdarg.h>#include <linux/module.h>	/* for KSYM_SYMBOL_LEN */#include <linux/types.h>#include <linux/string.h>#include <linux/ctype.h>#include <linux/kernel.h>#include <linux/kallsyms.h>#include <linux/math64.h>#include <linux/uaccess.h>#include <linux/ioport.h>#include <net/addrconf.h> #include <asm/page.h>		/* for PAGE_SIZE */#include <asm/sections.h>	/* for dereference_function_descriptor() */ #include "kstrtox.h" /** * simple_strtoull - convert a string to an unsigned long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtoull instead. */unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base){	unsigned long long result;	unsigned int rv; 	cp = _parse_integer_fixup_radix(cp, &base);	rv = _parse_integer(cp, base, &result);	/* FIXME */	cp += (rv & ~KSTRTOX_OVERFLOW); 	if (endp)		*endp = (char *)cp; 	return result;}EXPORT_SYMBOL(simple_strtoull); /** * simple_strtoul - convert a string to an unsigned long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtoul instead. */unsigned long simple_strtoul(const char *cp, char **endp, unsigned int base){	return simple_strtoull(cp, endp, base);}EXPORT_SYMBOL(simple_strtoul); /** * simple_strtol - convert a string to a signed long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtol instead. */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);}EXPORT_SYMBOL(simple_strtol); /** * simple_strtoll - convert a string to a signed long long * @cp: The start of the string * @endp: A pointer to the end of the parsed string will be placed here * @base: The number base to use * * This function is obsolete. Please use kstrtoll instead. */long long simple_strtoll(const char *cp, char **endp, unsigned int base){	if (*cp == '-')		return -simple_strtoull(cp + 1, endp, base); 	return simple_strtoull(cp, endp, base);}EXPORT_SYMBOL(simple_strtoll); static noinline_for_stackint skip_atoi(const char **s){	int i = 0; 	while (isdigit(**s))		i = i*10 + *((*s)++) - '0'; 	return i;} /* Decimal conversion is by far the most typical, and is used * for /proc and /sys data. This directly impacts e.g. top performance * with many processes running. We optimize it for speed * using ideas described at <http://www.cs.uiowa.edu/~jones/bcd/divide.html> * (with permission from the author, Douglas W. Jones). */ #if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64/* Formats correctly any integer in [0, 999999999] */static noinline_for_stackchar *put_dec_full9(char *buf, unsigned q){	unsigned r; 	/*	 * Possible ways to approx. divide by 10	 * (x * 0x1999999a) >> 32 x < 1073741829 (multiply must be 64-bit)	 * (x * 0xcccd) >> 19     x <      81920 (x < 262149 when 64-bit mul)	 * (x * 0x6667) >> 18     x <      43699	 * (x * 0x3334) >> 17     x <      16389	 * (x * 0x199a) >> 16     x <      16389	 * (x * 0x0ccd) >> 15     x <      16389	 * (x * 0x0667) >> 14     x <       2739	 * (x * 0x0334) >> 13     x <       1029	 * (x * 0x019a) >> 12     x <       1029	 * (x * 0x00cd) >> 11     x <       1029 shorter code than * 0x67 (on i386)	 * (x * 0x0067) >> 10     x <        179	 * (x * 0x0034) >>  9     x <         69 same	 * (x * 0x001a) >>  8     x <         69 same	 * (x * 0x000d) >>  7     x <         69 same, shortest code (on i386)	 * (x * 0x0007) >>  6     x <         19	 * See <http://www.cs.uiowa.edu/~jones/bcd/divide.html>	 */	r      = (q * (uint64_t)0x1999999a) >> 32;	*buf++ = (q - 10 * r) + '0'; /* 1 */	q      = (r * (uint64_t)0x1999999a) >> 32;	*buf++ = (r - 10 * q) + '0'; /* 2 */	r      = (q * (uint64_t)0x1999999a) >> 32;	*buf++ = (q - 10 * r) + '0'; /* 3 */	q      = (r * (uint64_t)0x1999999a) >> 32;	*buf++ = (r - 10 * q) + '0'; /* 4 */	r      = (q * (uint64_t)0x1999999a) >> 32;	*buf++ = (q - 10 * r) + '0'; /* 5 */	/* Now value is under 10000, can avoid 64-bit multiply */	q      = (r * 0x199a) >> 16;	*buf++ = (r - 10 * q)  + '0'; /* 6 */	r      = (q * 0xcd) >> 11;	*buf++ = (q - 10 * r)  + '0'; /* 7 */	q      = (r * 0xcd) >> 11;	*buf++ = (r - 10 * q) + '0'; /* 8 */	*buf++ = q + '0'; /* 9 */	return buf;}#endif /* Similar to above but do not pad with zeros. * Code can be easily arranged to print 9 digits too, but our callers * always call put_dec_full9() instead when the number has 9 decimal digits. */static noinline_for_stackchar *put_dec_trunc8(char *buf, unsigned r){	unsigned q; 	/* Copy of previous function's body with added early returns */	while (r >= 10000) {		q = r + '0';		r  = (r * (uint64_t)0x1999999a) >> 32;		*buf++ = q - 10*r;	} 	q      = (r * 0x199a) >> 16;	/* r <= 9999 */	*buf++ = (r - 10 * q)  + '0';	if (q == 0)		return buf;	r      = (q * 0xcd) >> 11;	/* q <= 999 */	*buf++ = (q - 10 * r)  + '0';	if (r == 0)		return buf;	q      = (r * 0xcd) >> 11;	/* r <= 99 */	*buf++ = (r - 10 * q) + '0';	if (q == 0)		return buf;	*buf++ = q + '0';		 /* q <= 9 */	return buf;} /* There are two algorithms to print larger numbers. * One is generic: divide by 1000000000 and repeatedly print * groups of (up to) 9 digits. It's conceptually simple, * but requires a (unsigned long long) / 1000000000 division. * * Second algorithm splits 64-bit unsigned long long into 16-bit chunks, * manipulates them cleverly and generates groups of 4 decimal digits. * It so happens that it does NOT require long long division. * * If long is > 32 bits, division of 64-bit values is relatively easy, * and we will use the first algorithm. * If long long is > 64 bits (strange architecture with VERY large long long), * second algorithm can't be used, and we again use the first one. * * Else (if long is 32 bits and long long is 64 bits) we use second one. */ #if BITS_PER_LONG != 32 || BITS_PER_LONG_LONG != 64 /* First algorithm: generic */ staticchar *put_dec(char *buf, unsigned long long n){	if (n >= 100*1000*1000) {		while (n >= 1000*1000*1000)			buf = put_dec_full9(buf, do_div(n, 1000*1000*1000));		if (n >= 100*1000*1000)			return put_dec_full9(buf, n);	}	return put_dec_trunc8(buf, n);} #else /* Second algorithm: valid only for 64-bit long longs */ /* See comment in put_dec_full9 for choice of constants */static noinline_for_stackvoid put_dec_full4(char *buf, unsigned q){	unsigned r;	r      = (q * 0xccd) >> 15;	buf[0] = (q - 10 * r) + '0';	q      = (r * 0xcd) >> 11;	buf[1] = (r - 10 * q)  + '0';	r      = (q * 0xcd) >> 11;	buf[2] = (q - 10 * r)  + '0';	buf[3] = r + '0';} /* * Call put_dec_full4 on x % 10000, return x / 10000. * The approximation x/10000 == (x * 0x346DC5D7) >> 43 * holds for all x < 1,128,869,999.  The largest value this * helper will ever be asked to convert is 1,125,520,955. * (d1 in the put_dec code, assuming n is all-ones). */staticunsigned put_dec_helper4(char *buf, unsigned x){        uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43;         put_dec_full4(buf, x - q * 10000);        return q;} /* Based on code by Douglas W. Jones found at * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour> * (with permission from the author). * Performs no 64-bit division and hence should be fast on 32-bit machines. */staticchar *put_dec(char *buf, unsigned long long n){	uint32_t d3, d2, d1, q, h; 	if (n < 100*1000*1000)		return put_dec_trunc8(buf, n); 	d1  = ((uint32_t)n >> 16); /* implicit "& 0xffff" */	h   = (n >> 32);	d2  = (h      ) & 0xffff;	d3  = (h >> 16); /* implicit "& 0xffff" */ 	q   = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff);	q = put_dec_helper4(buf, q); 	q += 7671 * d3 + 9496 * d2 + 6 * d1;	q = put_dec_helper4(buf+4, q); 	q += 4749 * d3 + 42 * d2;	q = put_dec_helper4(buf+8, q); 	q += 281 * d3;	buf += 12;	if (q)		buf = put_dec_trunc8(buf, q);	else while (buf[-1] == '0')		--buf; 	return buf;} #endif /* * Convert passed number to decimal string. * Returns the length of string.  On buffer overflow, returns 0. * * If speed is not important, use snprintf(). It's easy to read the code. */int num_to_str(char *buf, int size, unsigned long long num){	char tmp[sizeof(num) * 3];	int idx, len; 	/* put_dec() may work incorrectly for num = 0 (generate "", not "0") */	if (num <= 9) {		tmp[0] = '0' + num;		len = 1;	} else {		len = put_dec(tmp, num) - tmp;	} 	if (len > size)		return 0;	for (idx = 0; idx < len; ++idx)		buf[idx] = tmp[len - idx - 1];	return len;} #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 SMALL	32		/* use lowercase in hex (must be 32 == 0x20) */#define SPECIAL	64		/* prefix hex with "0x", octal with "0" */ enum format_type {	FORMAT_TYPE_NONE, /* Just a string part */	FORMAT_TYPE_WIDTH,	FORMAT_TYPE_PRECISION,	FORMAT_TYPE_CHAR,	FORMAT_TYPE_STR,	FORMAT_TYPE_PTR,	FORMAT_TYPE_PERCENT_CHAR,	FORMAT_TYPE_INVALID,	FORMAT_TYPE_LONG_LONG,	FORMAT_TYPE_ULONG,	FORMAT_TYPE_LONG,	FORMAT_TYPE_UBYTE,	FORMAT_TYPE_BYTE,	FORMAT_TYPE_USHORT,	FORMAT_TYPE_SHORT,	FORMAT_TYPE_UINT,	FORMAT_TYPE_INT,	FORMAT_TYPE_NRCHARS,	FORMAT_TYPE_SIZE_T,	FORMAT_TYPE_PTRDIFF}; struct printf_spec {	u8	type;		/* format_type enum */	u8	flags;		/* flags to number() */	u8	base;		/* number base, 8, 10 or 16 only */	u8	qualifier;	/* number qualifier, one of 'hHlLtzZ' */	s16	field_width;	/* width of output field */	s16	precision;	/* # of digits/chars */}; static noinline_for_stackchar *number(char *buf, char *end, unsigned long long num,	     struct printf_spec spec){	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */	static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */ 	char tmp[66];	char sign;	char locase;	int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);	int i;	bool is_zero = num == 0LL; 	/* locase = 0 or 0x20. ORing digits or letters with 'locase'	 * produces same digits or (maybe lowercased) letters */	locase = (spec.flags & SMALL);	if (spec.flags & LEFT)		spec.flags &= ~ZEROPAD;	sign = 0;	if (spec.flags & SIGN) {		if ((signed long long)num < 0) {			sign = '-';			num = -(signed long long)num;			spec.field_width--;		} else if (spec.flags & PLUS) {			sign = '+';			spec.field_width--;		} else if (spec.flags & SPACE) {			sign = ' ';			spec.field_width--;		}	}	if (need_pfx) {		if (spec.base == 16)			spec.field_width -= 2;		else if (!is_zero)			spec.field_width--;	} 	/* generate full string in tmp[], in reverse order */	i = 0;	if (num < spec.base)		tmp[i++] = digits[num] | locase;	/* Generic code, for any base:	else do {		tmp[i++] = (digits[do_div(num,base)] | locase);	} while (num != 0);	*/	else if (spec.base != 10) { /* 8 or 16 */		int mask = spec.base - 1;		int shift = 3; 		if (spec.base == 16)			shift = 4;		do {			tmp[i++] = (digits[((unsigned char)num) & mask] | locase);			num >>= shift;		} while (num);	} else { /* base 10 */		i = put_dec(tmp, num) - tmp;	} 	/* printing 100 using %2d gives "100", not "00" */	if (i > spec.precision)		spec.precision = i;	/* leading space padding */	spec.field_width -= spec.precision;	if (!(spec.flags & (ZEROPAD+LEFT))) {		while (--spec.field_width >= 0) {			if (buf < end)				*buf = ' ';			++buf;		}	}	/* sign */	if (sign) {		if (buf < end)			*buf = sign;		++buf;	}	/* "0x" / "0" prefix */	if (need_pfx) {		if (spec.base == 16 || !is_zero) {			if (buf < end)				*buf = '0';			++buf;		}		if (spec.base == 16) {			if (buf < end)				*buf = ('X' | locase);			++buf;		}	}	/* zero or space padding */	if (!(spec.flags & LEFT)) {		char c = (spec.flags & ZEROPAD) ? '0' : ' ';		while (--spec.field_width >= 0) {			if (buf < end)				*buf = c;			++buf;		}	}	/* hmm even more zero padding? */	while (i <= --spec.precision) {		if (buf < end)			*buf = '0';		++buf;	}	/* actual digits of result */	while (--i >= 0) {		if (buf < end)			*buf = tmp[i];		++buf;	}	/* trailing space padding */	while (--spec.field_width >= 0) {		if (buf < end)			*buf = ' ';		++buf;	} 

Lines 1–500 of 2267.