Merge git://git.kernel.org/pub/scm/linux/kernel/git/mason/btrfs-unstable
[linux-2.6] / lib / string_helpers.c
1 /*
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>
8 #include <linux/module.h>
9 #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  */
23 int string_get_size(u64 size, const enum string_size_units units,
24                     char *buf, int len)
25 {
26         const char *units_10[] = { "B", "kB", "MB", "GB", "TB", "PB",
27                                    "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         };
34         const unsigned int divisor[] = {
35                 [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';
43         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                 }
49
50                 sf_cap = size;
51                 for (j = 0; sf_cap*10 < 1000; j++)
52                         sf_cap *= 10;
53
54                 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                 }
61         }
62
63         snprintf(buf, len, "%lld%s %s", (unsigned long long)size,
64                  tmp, units_str[units][i]);
65
66         return 0;
67 }
68 EXPORT_SYMBOL(string_get_size);