aboutsummaryrefslogtreecommitdiffstats
path: root/lib/string_helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/string_helpers.c')
-rw-r--r--lib/string_helpers.c261
1 files changed, 128 insertions, 133 deletions
diff --git a/lib/string_helpers.c b/lib/string_helpers.c
index 8f8c4417f228..c98ae818eb4e 100644
--- a/lib/string_helpers.c
+++ b/lib/string_helpers.c
@@ -4,6 +4,7 @@
4 * Copyright 31 August 2008 James Bottomley 4 * Copyright 31 August 2008 James Bottomley
5 * Copyright (C) 2013, Intel Corporation 5 * Copyright (C) 2013, Intel Corporation
6 */ 6 */
7#include <linux/bug.h>
7#include <linux/kernel.h> 8#include <linux/kernel.h>
8#include <linux/math64.h> 9#include <linux/math64.h>
9#include <linux/export.h> 10#include <linux/export.h>
@@ -14,7 +15,8 @@
14 15
15/** 16/**
16 * string_get_size - get the size in the specified units 17 * string_get_size - get the size in the specified units
17 * @size: The size to be converted 18 * @size: The size to be converted in blocks
19 * @blk_size: Size of the block (use 1 for size in bytes)
18 * @units: units to use (powers of 1000 or 1024) 20 * @units: units to use (powers of 1000 or 1024)
19 * @buf: buffer to format to 21 * @buf: buffer to format to
20 * @len: length of buffer 22 * @len: length of buffer
@@ -24,14 +26,14 @@
24 * at least 9 bytes and will always be zero terminated. 26 * at least 9 bytes and will always be zero terminated.
25 * 27 *
26 */ 28 */
27void string_get_size(u64 size, const enum string_size_units units, 29void string_get_size(u64 size, u64 blk_size, const enum string_size_units units,
28 char *buf, int len) 30 char *buf, int len)
29{ 31{
30 static const char *const units_10[] = { 32 static const char *const units_10[] = {
31 "B", "kB", "MB", "GB", "TB", "PB", "EB" 33 "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"
32 }; 34 };
33 static const char *const units_2[] = { 35 static const char *const units_2[] = {
34 "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" 36 "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"
35 }; 37 };
36 static const char *const *const units_str[] = { 38 static const char *const *const units_str[] = {
37 [STRING_UNITS_10] = units_10, 39 [STRING_UNITS_10] = units_10,
@@ -42,31 +44,57 @@ void string_get_size(u64 size, const enum string_size_units units,
42 [STRING_UNITS_2] = 1024, 44 [STRING_UNITS_2] = 1024,
43 }; 45 };
44 int i, j; 46 int i, j;
45 u32 remainder = 0, sf_cap; 47 u32 remainder = 0, sf_cap, exp;
46 char tmp[8]; 48 char tmp[8];
49 const char *unit;
47 50
48 tmp[0] = '\0'; 51 tmp[0] = '\0';
49 i = 0; 52 i = 0;
50 if (size >= divisor[units]) { 53 if (!size)
51 while (size >= divisor[units]) { 54 goto out;
52 remainder = do_div(size, divisor[units]);
53 i++;
54 }
55 55
56 sf_cap = size; 56 while (blk_size >= divisor[units]) {
57 for (j = 0; sf_cap*10 < 1000; j++) 57 remainder = do_div(blk_size, divisor[units]);
58 sf_cap *= 10; 58 i++;
59 }
59 60
60 if (j) { 61 exp = divisor[units] / (u32)blk_size;
61 remainder *= 1000; 62 if (size >= exp) {
62 remainder /= divisor[units]; 63 remainder = do_div(size, divisor[units]);
63 snprintf(tmp, sizeof(tmp), ".%03u", remainder); 64 remainder *= blk_size;
64 tmp[j+1] = '\0'; 65 i++;
65 } 66 } else {
67 remainder *= size;
68 }
69
70 size *= blk_size;
71 size += remainder / divisor[units];
72 remainder %= divisor[units];
73
74 while (size >= divisor[units]) {
75 remainder = do_div(size, divisor[units]);
76 i++;
66 } 77 }
67 78
79 sf_cap = size;
80 for (j = 0; sf_cap*10 < 1000; j++)
81 sf_cap *= 10;
82
83 if (j) {
84 remainder *= 1000;
85 remainder /= divisor[units];
86 snprintf(tmp, sizeof(tmp), ".%03u", remainder);
87 tmp[j+1] = '\0';
88 }
89
90 out:
91 if (i >= ARRAY_SIZE(units_2))
92 unit = "UNK";
93 else
94 unit = units_str[units][i];
95
68 snprintf(buf, len, "%u%s %s", (u32)size, 96 snprintf(buf, len, "%u%s %s", (u32)size,
69 tmp, units_str[units][i]); 97 tmp, unit);
70} 98}
71EXPORT_SYMBOL(string_get_size); 99EXPORT_SYMBOL(string_get_size);
72 100
@@ -239,29 +267,21 @@ int string_unescape(char *src, char *dst, size_t size, unsigned int flags)
239} 267}
240EXPORT_SYMBOL(string_unescape); 268EXPORT_SYMBOL(string_unescape);
241 269
242static int escape_passthrough(unsigned char c, char **dst, size_t *osz) 270static bool escape_passthrough(unsigned char c, char **dst, char *end)
243{ 271{
244 char *out = *dst; 272 char *out = *dst;
245 273
246 if (*osz < 1) 274 if (out < end)
247 return -ENOMEM; 275 *out = c;
248 276 *dst = out + 1;
249 *out++ = c; 277 return true;
250
251 *dst = out;
252 *osz -= 1;
253
254 return 1;
255} 278}
256 279
257static int escape_space(unsigned char c, char **dst, size_t *osz) 280static bool escape_space(unsigned char c, char **dst, char *end)
258{ 281{
259 char *out = *dst; 282 char *out = *dst;
260 unsigned char to; 283 unsigned char to;
261 284
262 if (*osz < 2)
263 return -ENOMEM;
264
265 switch (c) { 285 switch (c) {
266 case '\n': 286 case '\n':
267 to = 'n'; 287 to = 'n';
@@ -279,26 +299,25 @@ static int escape_space(unsigned char c, char **dst, size_t *osz)
279 to = 'f'; 299 to = 'f';
280 break; 300 break;
281 default: 301 default:
282 return 0; 302 return false;
283 } 303 }
284 304
285 *out++ = '\\'; 305 if (out < end)
286 *out++ = to; 306 *out = '\\';
307 ++out;
308 if (out < end)
309 *out = to;
310 ++out;
287 311
288 *dst = out; 312 *dst = out;
289 *osz -= 2; 313 return true;
290
291 return 1;
292} 314}
293 315
294static int escape_special(unsigned char c, char **dst, size_t *osz) 316static bool escape_special(unsigned char c, char **dst, char *end)
295{ 317{
296 char *out = *dst; 318 char *out = *dst;
297 unsigned char to; 319 unsigned char to;
298 320
299 if (*osz < 2)
300 return -ENOMEM;
301
302 switch (c) { 321 switch (c) {
303 case '\\': 322 case '\\':
304 to = '\\'; 323 to = '\\';
@@ -310,71 +329,78 @@ static int escape_special(unsigned char c, char **dst, size_t *osz)
310 to = 'e'; 329 to = 'e';
311 break; 330 break;
312 default: 331 default:
313 return 0; 332 return false;
314 } 333 }
315 334
316 *out++ = '\\'; 335 if (out < end)
317 *out++ = to; 336 *out = '\\';
337 ++out;
338 if (out < end)
339 *out = to;
340 ++out;
318 341
319 *dst = out; 342 *dst = out;
320 *osz -= 2; 343 return true;
321
322 return 1;
323} 344}
324 345
325static int escape_null(unsigned char c, char **dst, size_t *osz) 346static bool escape_null(unsigned char c, char **dst, char *end)
326{ 347{
327 char *out = *dst; 348 char *out = *dst;
328 349
329 if (*osz < 2)
330 return -ENOMEM;
331
332 if (c) 350 if (c)
333 return 0; 351 return false;
334 352
335 *out++ = '\\'; 353 if (out < end)
336 *out++ = '0'; 354 *out = '\\';
355 ++out;
356 if (out < end)
357 *out = '0';
358 ++out;
337 359
338 *dst = out; 360 *dst = out;
339 *osz -= 2; 361 return true;
340
341 return 1;
342} 362}
343 363
344static int escape_octal(unsigned char c, char **dst, size_t *osz) 364static bool escape_octal(unsigned char c, char **dst, char *end)
345{ 365{
346 char *out = *dst; 366 char *out = *dst;
347 367
348 if (*osz < 4) 368 if (out < end)
349 return -ENOMEM; 369 *out = '\\';
350 370 ++out;
351 *out++ = '\\'; 371 if (out < end)
352 *out++ = ((c >> 6) & 0x07) + '0'; 372 *out = ((c >> 6) & 0x07) + '0';
353 *out++ = ((c >> 3) & 0x07) + '0'; 373 ++out;
354 *out++ = ((c >> 0) & 0x07) + '0'; 374 if (out < end)
375 *out = ((c >> 3) & 0x07) + '0';
376 ++out;
377 if (out < end)
378 *out = ((c >> 0) & 0x07) + '0';
379 ++out;
355 380
356 *dst = out; 381 *dst = out;
357 *osz -= 4; 382 return true;
358
359 return 1;
360} 383}
361 384
362static int escape_hex(unsigned char c, char **dst, size_t *osz) 385static bool escape_hex(unsigned char c, char **dst, char *end)
363{ 386{
364 char *out = *dst; 387 char *out = *dst;
365 388
366 if (*osz < 4) 389 if (out < end)
367 return -ENOMEM; 390 *out = '\\';
368 391 ++out;
369 *out++ = '\\'; 392 if (out < end)
370 *out++ = 'x'; 393 *out = 'x';
371 *out++ = hex_asc_hi(c); 394 ++out;
372 *out++ = hex_asc_lo(c); 395 if (out < end)
396 *out = hex_asc_hi(c);
397 ++out;
398 if (out < end)
399 *out = hex_asc_lo(c);
400 ++out;
373 401
374 *dst = out; 402 *dst = out;
375 *osz -= 4; 403 return true;
376
377 return 1;
378} 404}
379 405
380/** 406/**
@@ -426,19 +452,17 @@ static int escape_hex(unsigned char c, char **dst, size_t *osz)
426 * it if needs. 452 * it if needs.
427 * 453 *
428 * Return: 454 * Return:
429 * The amount of the characters processed to the destination buffer, or 455 * The total size of the escaped output that would be generated for
430 * %-ENOMEM if the size of buffer is not enough to put an escaped character is 456 * the given input and flags. To check whether the output was
431 * returned. 457 * truncated, compare the return value to osz. There is room left in
432 * 458 * dst for a '\0' terminator if and only if ret < osz.
433 * Even in the case of error @dst pointer will be updated to point to the byte
434 * after the last processed character.
435 */ 459 */
436int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz, 460int string_escape_mem(const char *src, size_t isz, char *dst, size_t osz,
437 unsigned int flags, const char *esc) 461 unsigned int flags, const char *esc)
438{ 462{
439 char *out = *dst, *p = out; 463 char *p = dst;
464 char *end = p + osz;
440 bool is_dict = esc && *esc; 465 bool is_dict = esc && *esc;
441 int ret = 0;
442 466
443 while (isz--) { 467 while (isz--) {
444 unsigned char c = *src++; 468 unsigned char c = *src++;
@@ -458,55 +482,26 @@ int string_escape_mem(const char *src, size_t isz, char **dst, size_t osz,
458 (is_dict && !strchr(esc, c))) { 482 (is_dict && !strchr(esc, c))) {
459 /* do nothing */ 483 /* do nothing */
460 } else { 484 } else {
461 if (flags & ESCAPE_SPACE) { 485 if (flags & ESCAPE_SPACE && escape_space(c, &p, end))
462 ret = escape_space(c, &p, &osz); 486 continue;
463 if (ret < 0) 487
464 break; 488 if (flags & ESCAPE_SPECIAL && escape_special(c, &p, end))
465 if (ret > 0) 489 continue;
466 continue; 490
467 } 491 if (flags & ESCAPE_NULL && escape_null(c, &p, end))
468 492 continue;
469 if (flags & ESCAPE_SPECIAL) {
470 ret = escape_special(c, &p, &osz);
471 if (ret < 0)
472 break;
473 if (ret > 0)
474 continue;
475 }
476
477 if (flags & ESCAPE_NULL) {
478 ret = escape_null(c, &p, &osz);
479 if (ret < 0)
480 break;
481 if (ret > 0)
482 continue;
483 }
484 493
485 /* ESCAPE_OCTAL and ESCAPE_HEX always go last */ 494 /* ESCAPE_OCTAL and ESCAPE_HEX always go last */
486 if (flags & ESCAPE_OCTAL) { 495 if (flags & ESCAPE_OCTAL && escape_octal(c, &p, end))
487 ret = escape_octal(c, &p, &osz);
488 if (ret < 0)
489 break;
490 continue; 496 continue;
491 } 497
492 if (flags & ESCAPE_HEX) { 498 if (flags & ESCAPE_HEX && escape_hex(c, &p, end))
493 ret = escape_hex(c, &p, &osz);
494 if (ret < 0)
495 break;
496 continue; 499 continue;
497 }
498 } 500 }
499 501
500 ret = escape_passthrough(c, &p, &osz); 502 escape_passthrough(c, &p, end);
501 if (ret < 0)
502 break;
503 } 503 }
504 504
505 *dst = p; 505 return p - dst;
506
507 if (ret < 0)
508 return ret;
509
510 return p - out;
511} 506}
512EXPORT_SYMBOL(string_escape_mem); 507EXPORT_SYMBOL(string_escape_mem);