I have rewritten the patch to add the --total option to df, that
was still missing.  It compiled and run successfully for me with the
latest CVS snapshot (about Sat Aug 19 01:45:57 UTC 2006).  I hope
it is coded correctly.  I tried to follow Eric's advices this time.

Cheers,
Gustavo

diff -u -r coreutils.orig/NEWS coreutils/NEWS
--- coreutils.orig/NEWS 2006-08-18 21:48:55.000000000 -0300
+++ coreutils/NEWS      2006-08-18 22:30:08.000000000 -0300
@@ -2,6 +2,11 @@
 
 * Major changes in release 6.1-cvs (2006-??-??) [unstable]
 
+** New features
+
+  df now supports a --total (-c) option which prints a grand total
+  (total capability, usage and availability) of processed filesystems.
+
 ** Bug fixes
 
   df (with a command line argument) once again prints its header
diff -u -r coreutils.orig/TODO coreutils/TODO
--- coreutils.orig/TODO 2006-08-18 21:48:55.000000000 -0300
+++ coreutils/TODO      2006-08-18 22:30:05.000000000 -0300
@@ -37,8 +37,6 @@
 
 printf: consider adapting builtins/printf.def from bash
 
-df: add `--total' option, suggested here http://bugs.debian.org/186007
-
 seq: give better diagnostics for invalid formats:
    e.g. no or too many % directives
 seq: consider allowing format string to contain no %-directives
diff -u -r coreutils.orig/doc/coreutils.texi coreutils/doc/coreutils.texi
--- coreutils.orig/doc/coreutils.texi   2006-08-18 21:48:55.000000000 -0300
+++ coreutils/doc/coreutils.texi        2006-08-18 22:30:23.000000000 -0300
@@ -9288,6 +9288,15 @@
 Scale sizes by @var{size} before printing them (@pxref{Block size}).
 For example, @option{-BG} prints sizes in units of 1,073,741,824 bytes.
 
[EMAIL PROTECTED] -c
[EMAIL PROTECTED] --total
[EMAIL PROTECTED] -c
[EMAIL PROTECTED] --total
[EMAIL PROTECTED] grand total of disk usage
+Print a grand total of capability, usage and availability.  Every filesystem
+that has been processed contributes to the sum.  By default totals are not
+printed.
+
 @optHumanReadable
 
 @item -H
diff -u -r coreutils.orig/src/df.c coreutils/src/df.c
--- coreutils.orig/src/df.c     2006-08-18 21:48:55.000000000 -0300
+++ coreutils/src/df.c  2006-08-18 22:30:33.000000000 -0300
@@ -112,6 +112,25 @@
 /* If true, print file system type as well.  */
 static bool print_type;
 
+/* If true, print total usage and availability.  */
+static bool print_total;
+
+/* Grand total: amount of blocks and its sign.  */
+struct grand_total
+{
+  uintmax_t n;
+  bool negate;         /* TRUE if N is negative.  */
+};
+
+/* Total blocks.  */
+static struct grand_total total_blocks;
+
+/* Used blocks.  */
+static struct grand_total total_used;
+
+/* Available (free) blocks.  */
+static struct grand_total total_available;
+
 /* For long options that have no equivalent short option, use a
    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
 enum
@@ -126,6 +145,7 @@
 {
   {"all", no_argument, NULL, 'a'},
   {"block-size", required_argument, NULL, 'B'},
+  {"total", no_argument, NULL, 'c'},
   {"inodes", no_argument, NULL, 'i'},
   {"human-readable", no_argument, NULL, 'h'},
   {"si", no_argument, NULL, 'H'},
@@ -231,6 +251,41 @@
   return false;
 }
 
+/* Convert N, which is represented in blocks of FROM_UNIT bytes,
+   to a representation in blocks of TO_UNIT bytes.  It is assumed
+   that FROM_UNIT and TO_UNIT are valid block sizes.  If N is negative
+   then NEGATE must be TRUE, FLASE otherwise.  */
+
+static uintmax_t
+convert_units (uintmax_t n, bool negate,
+              uintmax_t from_unit, uintmax_t to_unit)
+{
+  if (from_unit == to_unit || n == 0)
+    return n;
+  else
+    {
+      uintmax_t converted;
+      
+      if (negate)
+       n = -n;
+      
+      if (from_unit % to_unit == 0)
+       converted = n * (from_unit / to_unit);
+      else if (n % to_unit == 0)
+       converted = (n / to_unit) * from_unit;
+      else
+       /* Floating point is necessary.  To avoid errors it would
+          be necessary to use multiple precision arithmetic.  */
+       {
+         converted = n * ((long double) from_unit / to_unit);
+         if (converted != TYPE_MAXIMUM (uintmax_t))
+               converted++;
+       }
+
+      return (negate ? -converted : converted);
+    }
+}
+
 /* Like human_readable (N, BUF, human_output_opts, INPUT_UNITS, OUTPUT_UNITS),
    except:
 
@@ -254,6 +309,52 @@
     }
 }
 
+/* Return how much is used out of total.  Total is USED + AVAILABLE.
+   This code was originally in `show_dev', but since it is needed by
+   `show_total' this function was created.  */
+
+static double
+percentage_calc (uintmax_t used, bool negate_used,
+                uintmax_t available, bool negate_available)
+{
+  double pct = -1;
+  
+  if (used == UINTMAX_MAX || available == UINTMAX_MAX)
+    ;
+  else if (!negate_used
+          && used <= TYPE_MAXIMUM (uintmax_t) / 100
+          && used + available != 0
+          && (used + available < used) == negate_available)
+    {
+      uintmax_t u100 = used * 100;
+      uintmax_t nonroot_total = used + available;
+      pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
+    }
+  else
+    {
+      /* The calculation cannot be done easily with integer
+        arithmetic.  Fall back on floating point.  This can suffer
+        from minor rounding errors, but doing it exactly requires
+        multiple precision arithmetic, and it's not worth the
+        aggravation.  */
+      double u = negate_used ? - (double) - used : used;
+      double a = negate_available ? - (double) - available : available;
+      double nonroot_total = u + a;
+      if (nonroot_total)
+       {
+         long int lipct = pct = u * 100 / nonroot_total;
+         double ipct = lipct;
+
+         /* Like `pct = ceil (dpct);', but avoid ceil so that
+            the math library needn't be linked.  */
+         if (ipct - 1 < pct && pct <= ipct + 1)
+           pct = ipct + (ipct < pct);
+       }
+    }
+
+  return pct;
+}
+
 /* Display a space listing for the disk device with absolute file name DISK.
    If MOUNT_POINT is non-NULL, it is the name of the root of the
    file system on DISK.
@@ -284,7 +385,7 @@
   uintmax_t available_to_root;
   uintmax_t used;
   bool negate_used;
-  double pct = -1;
+  double pct;
 
   if (me_remote & show_local_fs)
     return;
@@ -378,7 +479,7 @@
       used = total - available_to_root;
       negate_used = (total < available_to_root);
     }
-
+  
   printf (" %*s %*s %*s ",
          width, df_readable (false, total,
                              buf[0], input_units, output_units),
@@ -387,39 +488,43 @@
          width, df_readable (negate_available, available,
                              buf[2], input_units, output_units));
 
-  if (used == UINTMAX_MAX || available == UINTMAX_MAX)
-    ;
-  else if (!negate_used
-          && used <= TYPE_MAXIMUM (uintmax_t) / 100
-          && used + available != 0
-          && (used + available < used) == negate_available)
-    {
-      uintmax_t u100 = used * 100;
-      uintmax_t nonroot_total = used + available;
-      pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
-    }
-  else
-    {
-      /* The calculation cannot be done easily with integer
-        arithmetic.  Fall back on floating point.  This can suffer
-        from minor rounding errors, but doing it exactly requires
-        multiple precision arithmetic, and it's not worth the
-        aggravation.  */
-      double u = negate_used ? - (double) - used : used;
-      double a = negate_available ? - (double) - available : available;
-      double nonroot_total = u + a;
-      if (nonroot_total)
-       {
-         long int lipct = pct = u * 100 / nonroot_total;
-         double ipct = lipct;
+  if (print_total)
+    /* Add this filesystem's info to the grand total.  We have to be
+       careful with the signs.  */
+    {
+      uintmax_t u = negate_used ? (-used) : used;
+      uintmax_t a = negate_available ? (-available) : available;
+      uintmax_t tu = total_used.negate ? (-total_used.n) : total_used.n;
+      uintmax_t ta = (total_available.negate
+                     ? (-total_available.n)
+                     : total_available.n);      
+      
+      /* It is not possible just to add the values to the grand total.
+        Before computing the sum it is needed to convert the values to
+        a common block size, which happens to be the same as
+        OUTPUT_BLOCK_SIZE.  Following this approach it is possible to
+        avoid major rounding errors.  */
+
+      uintmax_t default_bsize = inode_format ? 1 : output_block_size;
+      
+      total_blocks.negate = false;
+      total_blocks.n += convert_units (total, false, input_units,
+                                      default_bsize);
+
+      total_used.negate = ((negate_used && !(u < tu))
+                          || (total_used.negate && (u < tu)));
+      
+      total_used.n += convert_units(used, negate_used, input_units,
+                                   default_bsize);
 
-         /* Like `pct = ceil (dpct);', but avoid ceil so that
-            the math library needn't be linked.  */
-         if (ipct - 1 < pct && pct <= ipct + 1)
-           pct = ipct + (ipct < pct);
-       }
-    }
+      total_available.negate = ((negate_available && !(a < ta))
+                               || (total_available.negate && (a < ta)));
 
+      total_available.n += convert_units (available, negate_available,
+                                         input_units, default_bsize);
+    }
+  
+  pct = percentage_calc (used, negate_used, available, negate_available);
   if (0 <= pct)
     printf ("%*.0f%%", use_width - 1, pct);
   else
@@ -692,6 +797,54 @@
              me->me_dummy, me->me_remote);
 }
 
+/* Show total usage and availability.  Every displayed filesystem
+   contributes with the grand total.  */
+
+static void
+show_total (void)
+{
+  char buf[3][LONGEST_HUMAN_READABLE + 2];
+  int width;
+  int use_width;
+  uintmax_t bsize = inode_format ? 1 : output_block_size;
+  double pct;
+
+  printf("%-20s", _("total"));
+  
+  /* Same code used by `show_dev' to determine the correct widths.  */
+  if (inode_format)
+    {
+      width = 7;
+      use_width = 5;
+    }
+  else
+    {
+      width = (human_output_opts & human_autoscale
+              ? 5 + ! (human_output_opts & human_base_1024)
+              : 9);
+      use_width = ((posix_format
+                   && ! (human_output_opts & human_autoscale))
+                  ? 8 : 4);
+    }
+  
+  printf (" %*s %*s %*s ",
+         width, df_readable (total_blocks.negate, total_blocks.n,
+                             buf[0], bsize, bsize),
+         width, df_readable (total_used.negate, total_used.n,
+                             buf[1], bsize, bsize),
+         width, df_readable (total_available.negate, total_available.n,
+                             buf[2], bsize, bsize));
+
+  pct = percentage_calc (total_used.n, total_used.negate,
+                        total_available.n, total_available.negate);
+  if (0 <= pct)
+    printf ("%*.0f%%", use_width - 1, pct);
+  else
+    printf ("%*s", use_width, "- ");
+
+  putchar ('\n');
+}
+
 /* Add FSTYPE to the list of file system types to display. */
 
 static void
@@ -738,6 +891,7 @@
       fputs (_("\
   -a, --all             include dummy file systems\n\
   -B, --block-size=SIZE use SIZE-byte blocks\n\
+  -c, --total           print total usage and availability\n\
   -h, --human-readable  print sizes in human readable format (e.g., 1K 234M 
2G)\n\
   -H, --si              likewise, but use powers of 1000 not 1024\n\
 "), stdout);
@@ -790,11 +944,12 @@
                                     &output_block_size);
 
   print_type = false;
+  print_total = false;
   file_systems_processed = false;
   posix_format = false;
   exit_status = EXIT_SUCCESS;
 
-  while ((c = getopt_long (argc, argv, "aB:iF:hHklmPTt:vx:", long_options, 
NULL))
+  while ((c = getopt_long (argc, argv, "aB:ciF:hHklmPTt:vx:", long_options, 
NULL))
         != -1)
     {
       switch (c)
@@ -805,6 +960,9 @@
        case 'B':
          human_output_opts = human_options (optarg, true, &output_block_size);
          break;
+       case 'c':
+         print_total = true;
+         break;
        case 'i':
          inode_format = true;
          break;
@@ -943,5 +1101,8 @@
   if (! file_systems_processed)
     error (EXIT_FAILURE, 0, _("no file systems processed"));
 
+  if (print_total)
+    show_total ();
+
   exit (exit_status);
 }
_______________________________________________
Bug-coreutils mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/bug-coreutils

Reply via email to