blob: dd4ece372699e5b717626ff0a558d919a118d60e [file] [log] [blame]
James Bottomley3c9f3682008-08-31 10:13:54 -05001/*
2 * Helpers for formatting and printing strings
3 *
4 * Copyright 31 August 2008 James Bottomley
5 */
6#include <linux/kernel.h>
7#include <linux/math64.h>
Paul Gortmaker8bc3bcc2011-11-16 21:29:17 -05008#include <linux/export.h>
James Bottomley3c9f3682008-08-31 10:13:54 -05009#include <linux/string_helpers.h>
10
11/**
12 * string_get_size - get the size in the specified units
13 * @size: The size to be converted
14 * @units: units to use (powers of 1000 or 1024)
15 * @buf: buffer to format to
16 * @len: length of buffer
17 *
18 * This function returns a string formatted to 3 significant figures
19 * giving the size in the required units. Returns 0 on success or
20 * error on failure. @buf is always zero terminated.
21 *
22 */
23int string_get_size(u64 size, const enum string_size_units units,
24 char *buf, int len)
25{
H. Peter Anvina8659592008-10-14 11:34:21 -070026 const char *units_10[] = { "B", "kB", "MB", "GB", "TB", "PB",
James Bottomley3c9f3682008-08-31 10:13:54 -050027 "EB", "ZB", "YB", NULL};
28 const char *units_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB",
29 "EiB", "ZiB", "YiB", NULL };
30 const char **units_str[] = {
31 [STRING_UNITS_10] = units_10,
32 [STRING_UNITS_2] = units_2,
33 };
H. Peter Anvina8659592008-10-14 11:34:21 -070034 const unsigned int divisor[] = {
James Bottomley3c9f3682008-08-31 10:13:54 -050035 [STRING_UNITS_10] = 1000,
36 [STRING_UNITS_2] = 1024,
37 };
38 int i, j;
39 u64 remainder = 0, sf_cap;
40 char tmp[8];
41
42 tmp[0] = '\0';
H. Peter Anvina8659592008-10-14 11:34:21 -070043 i = 0;
44 if (size >= divisor[units]) {
45 while (size >= divisor[units] && units_str[units][i]) {
46 remainder = do_div(size, divisor[units]);
47 i++;
48 }
James Bottomley3c9f3682008-08-31 10:13:54 -050049
H. Peter Anvina8659592008-10-14 11:34:21 -070050 sf_cap = size;
51 for (j = 0; sf_cap*10 < 1000; j++)
52 sf_cap *= 10;
James Bottomley3c9f3682008-08-31 10:13:54 -050053
H. Peter Anvina8659592008-10-14 11:34:21 -070054 if (j) {
55 remainder *= 1000;
56 do_div(remainder, divisor[units]);
57 snprintf(tmp, sizeof(tmp), ".%03lld",
58 (unsigned long long)remainder);
59 tmp[j+1] = '\0';
60 }
James Bottomley3c9f3682008-08-31 10:13:54 -050061 }
62
H. Peter Anvina8659592008-10-14 11:34:21 -070063 snprintf(buf, len, "%lld%s %s", (unsigned long long)size,
James Bottomley3c9f3682008-08-31 10:13:54 -050064 tmp, units_str[units][i]);
65
66 return 0;
67}
68EXPORT_SYMBOL(string_get_size);