diff options
Diffstat (limited to 'lib/vsprintf.c')
| -rw-r--r-- | lib/vsprintf.c | 109 | 
1 files changed, 65 insertions, 44 deletions
| diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 39c99fea7c03..fab33a9c5318 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -23,12 +23,12 @@  #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/div64.h>  #include <asm/sections.h>	/* for dereference_function_descriptor() */  #include "kstrtox.h" @@ -38,6 +38,8 @@   * @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)  { @@ -61,6 +63,8 @@ EXPORT_SYMBOL(simple_strtoull);   * @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)  { @@ -73,6 +77,8 @@ EXPORT_SYMBOL(simple_strtoul);   * @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)  { @@ -88,6 +94,8 @@ EXPORT_SYMBOL(simple_strtol);   * @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)  { @@ -1485,7 +1493,10 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)  				num = va_arg(args, long);  				break;  			case FORMAT_TYPE_SIZE_T: -				num = va_arg(args, size_t); +				if (spec.flags & SIGN) +					num = va_arg(args, ssize_t); +				else +					num = va_arg(args, size_t);  				break;  			case FORMAT_TYPE_PTRDIFF:  				num = va_arg(args, ptrdiff_t); @@ -2013,7 +2024,11 @@ int vsscanf(const char *buf, const char *fmt, va_list args)  	char digit;  	int num = 0;  	u8 qualifier; -	u8 base; +	unsigned int base; +	union { +		long long s; +		unsigned long long u; +	} val;  	s16 field_width;  	bool is_sign; @@ -2053,8 +2068,11 @@ int vsscanf(const char *buf, const char *fmt, va_list args)  		/* get field width */  		field_width = -1; -		if (isdigit(*fmt)) +		if (isdigit(*fmt)) {  			field_width = skip_atoi(&fmt); +			if (field_width <= 0) +				break; +		}  		/* get conversion qualifier */  		qualifier = -1; @@ -2154,58 +2172,61 @@ int vsscanf(const char *buf, const char *fmt, va_list args)  		    || (base == 0 && !isdigit(digit)))  			break; +		if (is_sign) +			val.s = qualifier != 'L' ? +				simple_strtol(str, &next, base) : +				simple_strtoll(str, &next, base); +		else +			val.u = qualifier != 'L' ? +				simple_strtoul(str, &next, base) : +				simple_strtoull(str, &next, base); + +		if (field_width > 0 && next - str > field_width) { +			if (base == 0) +				_parse_integer_fixup_radix(str, &base); +			while (next - str > field_width) { +				if (is_sign) +					val.s = div_s64(val.s, base); +				else +					val.u = div_u64(val.u, base); +				--next; +			} +		} +  		switch (qualifier) {  		case 'H':	/* that's 'hh' in format */ -			if (is_sign) { -				signed char *s = (signed char *)va_arg(args, signed char *); -				*s = (signed char)simple_strtol(str, &next, base); -			} else { -				unsigned char *s = (unsigned char *)va_arg(args, unsigned char *); -				*s = (unsigned char)simple_strtoul(str, &next, base); -			} +			if (is_sign) +				*va_arg(args, signed char *) = val.s; +			else +				*va_arg(args, unsigned char *) = val.u;  			break;  		case 'h': -			if (is_sign) { -				short *s = (short *)va_arg(args, short *); -				*s = (short)simple_strtol(str, &next, base); -			} else { -				unsigned short *s = (unsigned short *)va_arg(args, unsigned short *); -				*s = (unsigned short)simple_strtoul(str, &next, base); -			} +			if (is_sign) +				*va_arg(args, short *) = val.s; +			else +				*va_arg(args, unsigned short *) = val.u;  			break;  		case 'l': -			if (is_sign) { -				long *l = (long *)va_arg(args, long *); -				*l = simple_strtol(str, &next, base); -			} else { -				unsigned long *l = (unsigned long *)va_arg(args, unsigned long *); -				*l = simple_strtoul(str, &next, base); -			} +			if (is_sign) +				*va_arg(args, long *) = val.s; +			else +				*va_arg(args, unsigned long *) = val.u;  			break;  		case 'L': -			if (is_sign) { -				long long *l = (long long *)va_arg(args, long long *); -				*l = simple_strtoll(str, &next, base); -			} else { -				unsigned long long *l = (unsigned long long *)va_arg(args, unsigned long long *); -				*l = simple_strtoull(str, &next, base); -			} +			if (is_sign) +				*va_arg(args, long long *) = val.s; +			else +				*va_arg(args, unsigned long long *) = val.u;  			break;  		case 'Z':  		case 'z': -		{ -			size_t *s = (size_t *)va_arg(args, size_t *); -			*s = (size_t)simple_strtoul(str, &next, base); -		} -		break; +			*va_arg(args, size_t *) = val.u; +			break;  		default: -			if (is_sign) { -				int *i = (int *)va_arg(args, int *); -				*i = (int)simple_strtol(str, &next, base); -			} else { -				unsigned int *i = (unsigned int *)va_arg(args, unsigned int*); -				*i = (unsigned int)simple_strtoul(str, &next, base); -			} +			if (is_sign) +				*va_arg(args, int *) = val.s; +			else +				*va_arg(args, unsigned int *) = val.u;  			break;  		}  		num++; |