[SCSI] lib: string_get_size(): don't hang on zero; no decimals on exact
authorH. Peter Anvin <hpa@zytor.com>
Tue, 14 Oct 2008 18:34:21 +0000 (11:34 -0700)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Thu, 23 Oct 2008 16:42:20 +0000 (11:42 -0500)
We would hang forever when passing a zero to string_get_size().
Furthermore, string_get_size() would produce decimals on a value small
enough to be exact.  Finally, a few formatting issues are inconsistent
with standard SI style guidelines.

- If the value is less than the divisor, skip the entire rounding
  step.  This prints out all small values including zero as integers,
  without decimals.
- Add a space between the value and the symbol for the unit,
  consistent with standard SI practice.
- Lower case k in kB since we are talking about powers of 10.
- Finally, change "int" to "unsigned int" in one place to shut up a
  gcc warning when compiling the code out-of-kernel for testing.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
lib/string_helpers.c

index 8347925030ff51a0a98d1a81cb5ae9c0b06413fa..ab431d4cc970d50f4b90b8f0639fcdea417e78a0 100644 (file)
@@ -23,7 +23,7 @@
 int string_get_size(u64 size, const enum string_size_units units,
                    char *buf, int len)
 {
-       const char *units_10[] = { "B", "KB", "MB", "GB", "TB", "PB",
+       const char *units_10[] = { "B", "kB", "MB", "GB", "TB", "PB",
                                   "EB", "ZB", "YB", NULL};
        const char *units_2[] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB",
                                 "EiB", "ZiB", "YiB", NULL };
@@ -31,7 +31,7 @@ int string_get_size(u64 size, const enum string_size_units units,
                [STRING_UNITS_10] =  units_10,
                [STRING_UNITS_2] = units_2,
        };
-       const int divisor[] = {
+       const unsigned int divisor[] = {
                [STRING_UNITS_10] = 1000,
                [STRING_UNITS_2] = 1024,
        };
@@ -40,23 +40,27 @@ int string_get_size(u64 size, const enum string_size_units units,
        char tmp[8];
 
        tmp[0] = '\0';
+       i = 0;
+       if (size >= divisor[units]) {
+               while (size >= divisor[units] && units_str[units][i]) {
+                       remainder = do_div(size, divisor[units]);
+                       i++;
+               }
 
-       for (i = 0; size > divisor[units] && units_str[units][i]; i++)
-               remainder = do_div(size, divisor[units]);
+               sf_cap = size;
+               for (j = 0; sf_cap*10 < 1000; j++)
+                       sf_cap *= 10;
 
-       sf_cap = size;
-       for (j = 0; sf_cap*10 < 1000; j++)
-               sf_cap *= 10;
-
-       if (j) {
-               remainder *= 1000;
-               do_div(remainder, divisor[units]);
-               snprintf(tmp, sizeof(tmp), ".%03lld",
-                        (unsigned long long)remainder);
-               tmp[j+1] = '\0';
+               if (j) {
+                       remainder *= 1000;
+                       do_div(remainder, divisor[units]);
+                       snprintf(tmp, sizeof(tmp), ".%03lld",
+                                (unsigned long long)remainder);
+                       tmp[j+1] = '\0';
+               }
        }
 
-       snprintf(buf, len, "%lld%s%s", (unsigned long long)size,
+       snprintf(buf, len, "%lld%s %s", (unsigned long long)size,
                 tmp, units_str[units][i]);
 
        return 0;