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 0e337541f005..39c99fea7c03 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c | |||
@@ -174,35 +174,25 @@ char *put_dec_trunc8(char *buf, unsigned r) | |||
174 | unsigned q; | 174 | unsigned q; |
175 | 175 | ||
176 | /* Copy of previous function's body with added early returns */ | 176 | /* Copy of previous function's body with added early returns */ |
177 | q = (r * (uint64_t)0x1999999a) >> 32; | 177 | while (r >= 10000) { |
178 | *buf++ = (r - 10 * q) + '0'; /* 2 */ | 178 | q = r + '0'; |
179 | if (q == 0) | 179 | r = (r * (uint64_t)0x1999999a) >> 32; |
180 | return buf; | 180 | *buf++ = q - 10*r; |
181 | r = (q * (uint64_t)0x1999999a) >> 32; | 181 | } |
182 | *buf++ = (q - 10 * r) + '0'; /* 3 */ | 182 | |
183 | if (r == 0) | 183 | q = (r * 0x199a) >> 16; /* r <= 9999 */ |
184 | return buf; | 184 | *buf++ = (r - 10 * q) + '0'; |
185 | q = (r * (uint64_t)0x1999999a) >> 32; | ||
186 | *buf++ = (r - 10 * q) + '0'; /* 4 */ | ||
187 | if (q == 0) | ||
188 | return buf; | ||
189 | r = (q * (uint64_t)0x1999999a) >> 32; | ||
190 | *buf++ = (q - 10 * r) + '0'; /* 5 */ | ||
191 | if (r == 0) | ||
192 | return buf; | ||
193 | q = (r * 0x199a) >> 16; | ||
194 | *buf++ = (r - 10 * q) + '0'; /* 6 */ | ||
195 | if (q == 0) | 185 | if (q == 0) |
196 | return buf; | 186 | return buf; |
197 | r = (q * 0xcd) >> 11; | 187 | r = (q * 0xcd) >> 11; /* q <= 999 */ |
198 | *buf++ = (q - 10 * r) + '0'; /* 7 */ | 188 | *buf++ = (q - 10 * r) + '0'; |
199 | if (r == 0) | 189 | if (r == 0) |
200 | return buf; | 190 | return buf; |
201 | q = (r * 0xcd) >> 11; | 191 | q = (r * 0xcd) >> 11; /* r <= 99 */ |
202 | *buf++ = (r - 10 * q) + '0'; /* 8 */ | 192 | *buf++ = (r - 10 * q) + '0'; |
203 | if (q == 0) | 193 | if (q == 0) |
204 | return buf; | 194 | return buf; |
205 | *buf++ = q + '0'; /* 9 */ | 195 | *buf++ = q + '0'; /* q <= 9 */ |
206 | return buf; | 196 | return buf; |
207 | } | 197 | } |
208 | 198 | ||
@@ -243,18 +233,34 @@ char *put_dec(char *buf, unsigned long long n) | |||
243 | 233 | ||
244 | /* Second algorithm: valid only for 64-bit long longs */ | 234 | /* Second algorithm: valid only for 64-bit long longs */ |
245 | 235 | ||
236 | /* See comment in put_dec_full9 for choice of constants */ | ||
246 | static noinline_for_stack | 237 | static noinline_for_stack |
247 | char *put_dec_full4(char *buf, unsigned q) | 238 | void put_dec_full4(char *buf, unsigned q) |
248 | { | 239 | { |
249 | unsigned r; | 240 | unsigned r; |
250 | r = (q * 0xcccd) >> 19; | 241 | r = (q * 0xccd) >> 15; |
251 | *buf++ = (q - 10 * r) + '0'; | 242 | buf[0] = (q - 10 * r) + '0'; |
252 | q = (r * 0x199a) >> 16; | 243 | q = (r * 0xcd) >> 11; |
253 | *buf++ = (r - 10 * q) + '0'; | 244 | buf[1] = (r - 10 * q) + '0'; |
254 | r = (q * 0xcd) >> 11; | 245 | r = (q * 0xcd) >> 11; |
255 | *buf++ = (q - 10 * r) + '0'; | 246 | buf[2] = (q - 10 * r) + '0'; |
256 | *buf++ = r + '0'; | 247 | buf[3] = r + '0'; |
257 | return buf; | 248 | } |
249 | |||
250 | /* | ||
251 | * Call put_dec_full4 on x % 10000, return x / 10000. | ||
252 | * The approximation x/10000 == (x * 0x346DC5D7) >> 43 | ||
253 | * holds for all x < 1,128,869,999. The largest value this | ||
254 | * helper will ever be asked to convert is 1,125,520,955. | ||
255 | * (d1 in the put_dec code, assuming n is all-ones). | ||
256 | */ | ||
257 | static | ||
258 | unsigned put_dec_helper4(char *buf, unsigned x) | ||
259 | { | ||
260 | uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43; | ||
261 | |||
262 | put_dec_full4(buf, x - q * 10000); | ||
263 | return q; | ||
258 | } | 264 | } |
259 | 265 | ||
260 | /* Based on code by Douglas W. Jones found at | 266 | /* Based on code by Douglas W. Jones found at |
@@ -276,28 +282,19 @@ char *put_dec(char *buf, unsigned long long n) | |||
276 | d3 = (h >> 16); /* implicit "& 0xffff" */ | 282 | d3 = (h >> 16); /* implicit "& 0xffff" */ |
277 | 283 | ||
278 | q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); | 284 | q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff); |
285 | q = put_dec_helper4(buf, q); | ||
286 | |||
287 | q += 7671 * d3 + 9496 * d2 + 6 * d1; | ||
288 | q = put_dec_helper4(buf+4, q); | ||
289 | |||
290 | q += 4749 * d3 + 42 * d2; | ||
291 | q = put_dec_helper4(buf+8, q); | ||
279 | 292 | ||
280 | buf = put_dec_full4(buf, q % 10000); | 293 | q += 281 * d3; |
281 | q = q / 10000; | 294 | buf += 12; |
282 | 295 | if (q) | |
283 | d1 = q + 7671 * d3 + 9496 * d2 + 6 * d1; | 296 | buf = put_dec_trunc8(buf, q); |
284 | buf = put_dec_full4(buf, d1 % 10000); | 297 | else while (buf[-1] == '0') |
285 | q = d1 / 10000; | ||
286 | |||
287 | d2 = q + 4749 * d3 + 42 * d2; | ||
288 | buf = put_dec_full4(buf, d2 % 10000); | ||
289 | q = d2 / 10000; | ||
290 | |||
291 | d3 = q + 281 * d3; | ||
292 | if (!d3) | ||
293 | goto done; | ||
294 | buf = put_dec_full4(buf, d3 % 10000); | ||
295 | q = d3 / 10000; | ||
296 | if (!q) | ||
297 | goto done; | ||
298 | buf = put_dec_full4(buf, q); | ||
299 | done: | ||
300 | while (buf[-1] == '0') | ||
301 | --buf; | 298 | --buf; |
302 | 299 | ||
303 | return buf; | 300 | return buf; |
@@ -990,7 +987,7 @@ int kptr_restrict __read_mostly; | |||
990 | * - 'm' For a 6-byte MAC address, it prints the hex address without colons | 987 | * - 'm' For a 6-byte MAC address, it prints the hex address without colons |
991 | * - 'MF' For a 6-byte MAC FDDI address, it prints the address | 988 | * - 'MF' For a 6-byte MAC FDDI address, it prints the address |
992 | * with a dash-separated hex notation | 989 | * with a dash-separated hex notation |
993 | * - '[mM]R For a 6-byte MAC address, Reverse order (Bluetooth) | 990 | * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth) |
994 | * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way | 991 | * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way |
995 | * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) | 992 | * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) |
996 | * IPv6 uses colon separated network-order 16 bit hex with leading 0's | 993 | * IPv6 uses colon separated network-order 16 bit hex with leading 0's |
@@ -1341,7 +1338,10 @@ qualifier: | |||
1341 | * %pR output the address range in a struct resource with decoded flags | 1338 | * %pR output the address range in a struct resource with decoded flags |
1342 | * %pr output the address range in a struct resource with raw flags | 1339 | * %pr output the address range in a struct resource with raw flags |
1343 | * %pM output a 6-byte MAC address with colons | 1340 | * %pM output a 6-byte MAC address with colons |
1341 | * %pMR output a 6-byte MAC address with colons in reversed order | ||
1342 | * %pMF output a 6-byte MAC address with dashes | ||
1344 | * %pm output a 6-byte MAC address without colons | 1343 | * %pm output a 6-byte MAC address without colons |
1344 | * %pmR output a 6-byte MAC address without colons in reversed order | ||
1345 | * %pI4 print an IPv4 address without leading zeros | 1345 | * %pI4 print an IPv4 address without leading zeros |
1346 | * %pi4 print an IPv4 address with leading zeros | 1346 | * %pi4 print an IPv4 address with leading zeros |
1347 | * %pI6 print an IPv6 address with colons | 1347 | * %pI6 print an IPv6 address with colons |
@@ -2017,7 +2017,7 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2017 | s16 field_width; | 2017 | s16 field_width; |
2018 | bool is_sign; | 2018 | bool is_sign; |
2019 | 2019 | ||
2020 | while (*fmt && *str) { | 2020 | while (*fmt) { |
2021 | /* skip any white space in format */ | 2021 | /* skip any white space in format */ |
2022 | /* white space in format matchs any amount of | 2022 | /* white space in format matchs any amount of |
2023 | * white space, including none, in the input. | 2023 | * white space, including none, in the input. |
@@ -2042,6 +2042,8 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2042 | * advance both strings to next white space | 2042 | * advance both strings to next white space |
2043 | */ | 2043 | */ |
2044 | if (*fmt == '*') { | 2044 | if (*fmt == '*') { |
2045 | if (!*str) | ||
2046 | break; | ||
2045 | while (!isspace(*fmt) && *fmt != '%' && *fmt) | 2047 | while (!isspace(*fmt) && *fmt != '%' && *fmt) |
2046 | fmt++; | 2048 | fmt++; |
2047 | while (!isspace(*str) && *str) | 2049 | while (!isspace(*str) && *str) |
@@ -2070,7 +2072,17 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2070 | } | 2072 | } |
2071 | } | 2073 | } |
2072 | 2074 | ||
2073 | if (!*fmt || !*str) | 2075 | if (!*fmt) |
2076 | break; | ||
2077 | |||
2078 | if (*fmt == 'n') { | ||
2079 | /* return number of characters read so far */ | ||
2080 | *va_arg(args, int *) = str - buf; | ||
2081 | ++fmt; | ||
2082 | continue; | ||
2083 | } | ||
2084 | |||
2085 | if (!*str) | ||
2074 | break; | 2086 | break; |
2075 | 2087 | ||
2076 | base = 10; | 2088 | base = 10; |
@@ -2103,13 +2115,6 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2103 | num++; | 2115 | num++; |
2104 | } | 2116 | } |
2105 | continue; | 2117 | continue; |
2106 | case 'n': | ||
2107 | /* return number of characters read so far */ | ||
2108 | { | ||
2109 | int *i = (int *)va_arg(args, int*); | ||
2110 | *i = str - buf; | ||
2111 | } | ||
2112 | continue; | ||
2113 | case 'o': | 2118 | case 'o': |
2114 | base = 8; | 2119 | base = 8; |
2115 | break; | 2120 | break; |
@@ -2210,16 +2215,6 @@ int vsscanf(const char *buf, const char *fmt, va_list args) | |||
2210 | str = next; | 2215 | str = next; |
2211 | } | 2216 | } |
2212 | 2217 | ||
2213 | /* | ||
2214 | * Now we've come all the way through so either the input string or the | ||
2215 | * format ended. In the former case, there can be a %n at the current | ||
2216 | * position in the format that needs to be filled. | ||
2217 | */ | ||
2218 | if (*fmt == '%' && *(fmt + 1) == 'n') { | ||
2219 | int *p = (int *)va_arg(args, int *); | ||
2220 | *p = str - buf; | ||
2221 | } | ||
2222 | |||
2223 | return num; | 2218 | return num; |
2224 | } | 2219 | } |
2225 | EXPORT_SYMBOL(vsscanf); | 2220 | EXPORT_SYMBOL(vsscanf); |