diff options
Diffstat (limited to 'lib/vsprintf.c')
| -rw-r--r-- | lib/vsprintf.c | 139 | 
1 files changed, 67 insertions, 72 deletions
| diff --git a/lib/vsprintf.c b/lib/vsprintf.c index 0e337541f00..39c99fea7c0 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -174,35 +174,25 @@ char *put_dec_trunc8(char *buf, unsigned r)  	unsigned q;  	/* Copy of previous function's body with added early returns */ -	q      = (r * (uint64_t)0x1999999a) >> 32; -	*buf++ = (r - 10 * q) + '0'; /* 2 */ -	if (q == 0) -		return buf; -	r      = (q * (uint64_t)0x1999999a) >> 32; -	*buf++ = (q - 10 * r) + '0'; /* 3 */ -	if (r == 0) -		return buf; -	q      = (r * (uint64_t)0x1999999a) >> 32; -	*buf++ = (r - 10 * q) + '0'; /* 4 */ -	if (q == 0) -		return buf; -	r      = (q * (uint64_t)0x1999999a) >> 32; -	*buf++ = (q - 10 * r) + '0'; /* 5 */ -	if (r == 0) -		return buf; -	q      = (r * 0x199a) >> 16; -	*buf++ = (r - 10 * q)  + '0'; /* 6 */ +	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; -	*buf++ = (q - 10 * r)  + '0'; /* 7 */ +	r      = (q * 0xcd) >> 11;	/* q <= 999 */ +	*buf++ = (q - 10 * r)  + '0';  	if (r == 0)  		return buf; -	q      = (r * 0xcd) >> 11; -	*buf++ = (r - 10 * q) + '0'; /* 8 */ +	q      = (r * 0xcd) >> 11;	/* r <= 99 */ +	*buf++ = (r - 10 * q) + '0';  	if (q == 0)  		return buf; -	*buf++ = q + '0'; /* 9 */ +	*buf++ = q + '0';		 /* q <= 9 */  	return buf;  } @@ -243,18 +233,34 @@ char *put_dec(char *buf, unsigned long long n)  /* Second algorithm: valid only for 64-bit long longs */ +/* See comment in put_dec_full9 for choice of constants */  static noinline_for_stack -char *put_dec_full4(char *buf, unsigned q) +void put_dec_full4(char *buf, unsigned q)  {  	unsigned r; -	r      = (q * 0xcccd) >> 19; -	*buf++ = (q - 10 * r) + '0'; -	q      = (r * 0x199a) >> 16; -	*buf++ = (r - 10 * q)  + '0'; +	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++ = (q - 10 * r)  + '0'; -	*buf++ = r + '0'; -	return buf; +	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). + */ +static +unsigned 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 @@ -276,28 +282,19 @@ char *put_dec(char *buf, unsigned long long n)  	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); -	buf = put_dec_full4(buf, q % 10000); -	q   = q / 10000; - -	d1  = q + 7671 * d3 + 9496 * d2 + 6 * d1; -	buf = put_dec_full4(buf, d1 % 10000); -	q   = d1 / 10000; - -	d2  = q + 4749 * d3 + 42 * d2; -	buf = put_dec_full4(buf, d2 % 10000); -	q   = d2 / 10000; - -	d3  = q + 281 * d3; -	if (!d3) -		goto done; -	buf = put_dec_full4(buf, d3 % 10000); -	q   = d3 / 10000; -	if (!q) -		goto done; -	buf = put_dec_full4(buf, q); - done: -	while (buf[-1] == '0') +	q += 281 * d3; +	buf += 12; +	if (q) +		buf = put_dec_trunc8(buf, q); +	else while (buf[-1] == '0')  		--buf;  	return buf; @@ -990,7 +987,7 @@ int kptr_restrict __read_mostly;   * - 'm' For a 6-byte MAC address, it prints the hex address without colons   * - 'MF' For a 6-byte MAC FDDI address, it prints the address   *       with a dash-separated hex notation - * - '[mM]R For a 6-byte MAC address, Reverse order (Bluetooth) + * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth)   * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way   *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)   *       IPv6 uses colon separated network-order 16 bit hex with leading 0's @@ -1341,7 +1338,10 @@ qualifier:   * %pR output the address range in a struct resource with decoded flags   * %pr output the address range in a struct resource with raw flags   * %pM output a 6-byte MAC address with colons + * %pMR output a 6-byte MAC address with colons in reversed order + * %pMF output a 6-byte MAC address with dashes   * %pm output a 6-byte MAC address without colons + * %pmR output a 6-byte MAC address without colons in reversed order   * %pI4 print an IPv4 address without leading zeros   * %pi4 print an IPv4 address with leading zeros   * %pI6 print an IPv6 address with colons @@ -2017,7 +2017,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args)  	s16 field_width;  	bool is_sign; -	while (*fmt && *str) { +	while (*fmt) {  		/* skip any white space in format */  		/* white space in format matchs any amount of  		 * white space, including none, in the input. @@ -2042,6 +2042,8 @@ int vsscanf(const char *buf, const char *fmt, va_list args)  		 * advance both strings to next white space  		 */  		if (*fmt == '*') { +			if (!*str) +				break;  			while (!isspace(*fmt) && *fmt != '%' && *fmt)  				fmt++;  			while (!isspace(*str) && *str) @@ -2070,7 +2072,17 @@ int vsscanf(const char *buf, const char *fmt, va_list args)  			}  		} -		if (!*fmt || !*str) +		if (!*fmt) +			break; + +		if (*fmt == 'n') { +			/* return number of characters read so far */ +			*va_arg(args, int *) = str - buf; +			++fmt; +			continue; +		} + +		if (!*str)  			break;  		base = 10; @@ -2103,13 +2115,6 @@ int vsscanf(const char *buf, const char *fmt, va_list args)  			num++;  		}  		continue; -		case 'n': -			/* return number of characters read so far */ -		{ -			int *i = (int *)va_arg(args, int*); -			*i = str - buf; -		} -		continue;  		case 'o':  			base = 8;  			break; @@ -2210,16 +2215,6 @@ int vsscanf(const char *buf, const char *fmt, va_list args)  		str = next;  	} -	/* -	 * Now we've come all the way through so either the input string or the -	 * format ended. In the former case, there can be a %n at the current -	 * position in the format that needs to be filled. -	 */ -	if (*fmt == '%' && *(fmt + 1) == 'n') { -		int *p = (int *)va_arg(args, int *); -		*p = str - buf; -	} -  	return num;  }  EXPORT_SYMBOL(vsscanf); | 
