]> Dogcows Code - chaz/tar/blobdiff - lib/human.c
Update
[chaz/tar] / lib / human.c
index 5cfbce9df4ddef46b66ab67d8b1216f759344985..a9ccf38c48312e5270889101283f65c35672afb5 100644 (file)
@@ -1,5 +1,7 @@
 /* human.c -- print human readable file size
 /* human.c -- print human readable file size
-   Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.
+
+   Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001 Free Software
+   Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -66,16 +68,51 @@ char *getenv ();
 static const char suffixes[] =
 {
   0,   /* not used */
 static const char suffixes[] =
 {
   0,   /* not used */
-  'k', /* kilo */
-  'M', /* Mega */
-  'G', /* Giga */
-  'T', /* Tera */
-  'P', /* Peta */
-  'E', /* Exa */
-  'Z', /* Zetta */
-  'Y'  /* Yotta */
+  'K', /* kibi ('k' for kilo is a special case) */
+  'M', /* mega or mebi */
+  'G', /* giga or gibi */
+  'T', /* tera or tebi */
+  'P', /* peta or pebi */
+  'E', /* exa or exbi */
+  'Z', /* zetta or 2**70 */
+  'Y'  /* yotta or 2**80 */
 };
 
 };
 
+/* Generate into P[-1] (and possibly P[-2]) the proper suffix for
+   POWER and BASE.  Return the address of the generated suffix.  */
+static char *
+generate_suffix_backwards (char *p, int power, int base)
+{
+  char letter = suffixes[power];
+
+  if (base == 1000)
+    {
+      *--p = 'B';
+      if (power == 1)
+       letter = 'k';
+    }
+
+  *--p = letter;
+  return p;
+}
+
+/* If INEXACT_STYLE is not human_round_to_even, and if easily
+   possible, adjust VALUE according to the style.  */
+static double
+adjust_value (enum human_inexact_style inexact_style, double value)
+{
+  /* Do not use the floor or ceil functions, as that would mean
+     linking with the standard math library, which is a porting pain.
+     So leave the value alone if it is too large to easily round.  */
+  if (inexact_style != human_round_to_even && value < (uintmax_t) -1)
+    {
+      uintmax_t u = value;
+      value = u + (inexact_style == human_ceiling && u != value);
+    }
+
+  return value;
+}
+
 /* Like human_readable_inexact, except always round to even.  */
 char *
 human_readable (uintmax_t n, char *buf,
 /* Like human_readable_inexact, except always round to even.  */
 char *
 human_readable (uintmax_t n, char *buf,
@@ -90,14 +127,13 @@ human_readable (uintmax_t n, char *buf,
    N is expressed in units of FROM_BLOCK_SIZE.  FROM_BLOCK_SIZE must
    be nonnegative.
 
    N is expressed in units of FROM_BLOCK_SIZE.  FROM_BLOCK_SIZE must
    be nonnegative.
 
-   If OUTPUT_BLOCK_SIZE is positive, use units of OUTPUT_BLOCK_SIZE in
-   the output number.  OUTPUT_BLOCK_SIZE must be a multiple of
-   FROM_BLOCK_SIZE or vice versa.
+   OUTPUT_BLOCK_SIZE must be nonzero.  If it is positive, use units of
+   OUTPUT_BLOCK_SIZE in the output number.
 
    Use INEXACT_STYLE to determine whether to take the ceiling or floor
    of any result that cannot be expressed exactly.
 
 
    Use INEXACT_STYLE to determine whether to take the ceiling or floor
    of any result that cannot be expressed exactly.
 
-   If OUTPUT_BLOCK_SIZE is negative, use a format like "127k" if
+   If OUTPUT_BLOCK_SIZE is negative, use a format like "127K" if
    possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use
    ordinary decimal format.  Normally -OUTPUT_BLOCK_SIZE is either
    1000 or 1024; it must be at least 2.  Most people visually process
    possible, using powers of -OUTPUT_BLOCK_SIZE; otherwise, use
    ordinary decimal format.  Normally -OUTPUT_BLOCK_SIZE is either
    1000 or 1024; it must be at least 2.  Most people visually process
@@ -105,9 +141,10 @@ human_readable (uintmax_t n, char *buf,
    more prone to misinterpretation.  Hence, converting to an
    abbreviated form usually improves readability.  Use a suffix
    indicating which power is being used.  For example, assuming
    more prone to misinterpretation.  Hence, converting to an
    abbreviated form usually improves readability.  Use a suffix
    indicating which power is being used.  For example, assuming
-   -OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3k,
+   -OUTPUT_BLOCK_SIZE is 1024, 8500 would be converted to 8.3K,
    133456345 to 127M, 56990456345 to 53G, and so on.  Numbers smaller
    133456345 to 127M, 56990456345 to 53G, and so on.  Numbers smaller
-   than -OUTPUT_BLOCK_SIZE aren't modified.  */
+   than -OUTPUT_BLOCK_SIZE aren't modified.  If -OUTPUT_BLOCK_SIZE is
+   1024, append a "B" after any size letter.  */
 
 char *
 human_readable_inexact (uintmax_t n, char *buf,
 
 char *
 human_readable_inexact (uintmax_t n, char *buf,
@@ -148,57 +185,61 @@ human_readable_inexact (uintmax_t n, char *buf,
 
   /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units.  */
 
 
   /* Adjust AMT out of FROM_BLOCK_SIZE units and into TO_BLOCK_SIZE units.  */
 
-  if (to_block_size <= from_block_size)
-    {
-      int multiplier = from_block_size / to_block_size;
-      amt = n * multiplier;
-
-      if (amt / multiplier != n)
-       {
-         /* Overflow occurred during multiplication.  We should use
-            multiple precision arithmetic here, but we'll be lazy and
-            resort to floating point.  This can yield answers that
-            are slightly off.  In practice it is quite rare to
-            overflow uintmax_t, so this is good enough for now.  */
-
-         double damt = n * (double) multiplier;
-
-         if (! base)
-           sprintf (buf, "%.0f", damt);
-         else
-           {
-             double e = 1;
-             power = 0;
-
-             do
-               {
-                 e *= base;
-                 power++;
-               }
-             while (e * base <= damt && power < sizeof suffixes - 1);
-
-             damt /= e;
-
-             sprintf (buf, "%.1f%c", damt, suffixes[power]);
-             if (4 < strlen (buf))
-               sprintf (buf, "%.0f%c", damt, suffixes[power]);
-           }
-
-         return buf;
-       }
-    }
-  else if (from_block_size == 0)
-    amt = 0;
-  else
-    {
-      int divisor = to_block_size / from_block_size;
-      int r10 = (n % divisor) * 10;
-      int r2 = (r10 % divisor) * 2;
-      amt = n / divisor;
-      tenths = r10 / divisor;
-      rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2);
-    }
-
+  {
+    int multiplier;
+    int divisor;
+    int r2;
+    int r10;
+    if (to_block_size <= from_block_size
+       ? (from_block_size % to_block_size != 0
+          || (multiplier = from_block_size / to_block_size,
+              (amt = n * multiplier) / multiplier != n))
+       : (from_block_size == 0
+          || to_block_size % from_block_size != 0
+          || (divisor = to_block_size / from_block_size,
+              r10 = (n % divisor) * 10,
+              r2 = (r10 % divisor) * 2,
+              amt = n / divisor,
+              tenths = r10 / divisor,
+              rounding = r2 < divisor ? 0 < r2 : 2 + (divisor < r2),
+              0)))
+      {
+       /* Either the result cannot be computed easily using uintmax_t,
+          or from_block_size is zero.  Fall back on floating point.
+          FIXME: This can yield answers that are slightly off.  */
+
+       double damt = n * (from_block_size / (double) to_block_size);
+
+       if (! base)
+         sprintf (buf, "%.0f", adjust_value (inexact_style, damt));
+       else
+         {
+           char suffix[3];
+           char const *psuffix;
+           double e = 1;
+           power = 0;
+
+           do
+             {
+               e *= base;
+               power++;
+             }
+           while (e * base <= damt && power < sizeof suffixes - 1);
+
+           damt /= e;
+
+           suffix[2] = '\0';
+           psuffix = generate_suffix_backwards (suffix + 2, power, base);
+           sprintf (buf, "%.1f%s",
+                    adjust_value (inexact_style, damt), psuffix);
+           if (4 + (base == 1000) < strlen (buf))
+             sprintf (buf, "%.0f%s",
+                      adjust_value (inexact_style, damt * 10) / 10, psuffix);
+         }
+
+       return buf;
+      }
+  }
 
   /* Use power of BASE notation if adjusted AMT is large enough.  */
 
 
   /* Use power of BASE notation if adjusted AMT is large enough.  */
 
@@ -219,7 +260,7 @@ human_readable_inexact (uintmax_t n, char *buf,
        }
       while (base <= amt && power < sizeof suffixes - 1);
 
        }
       while (base <= amt && power < sizeof suffixes - 1);
 
-      *--p = suffixes[power];
+      p = generate_suffix_backwards (p, power, base);
 
       if (amt < 10)
        {
 
       if (amt < 10)
        {
This page took 0.029272 seconds and 4 git commands to generate.