--- du.4111.orig.c	Wed Jul 10 10:09:05 2002
+++ du.4111.c	Sun Sep 22 01:55:00 2002
@@ -99,6 +99,31 @@
 int stat ();
 int lstat ();
 
+/* Linked list structure to hold filepaths and n_blocks,
+   to be used with the -p flag for percentage.  */
+
+struct list_def
+{
+  char * path;				/* Filepath (dynamically allocated) */
+  uintmax_t size;			/* Number of n_blocks ( print_size()'s first argument ) */
+  struct list_def *next;	/* Next node */
+};
+
+/* Nodes in the linked list of filepaths and n_blocks.  */
+struct list_def *first_node, *last_node, *now_node = NULL;
+
+/* If nonzero, suppress printing.  */
+static int suppress = 0;
+
+/* If nonzero, calculate percentages (-p).  */
+static int display_percentage = 0;
+
+/* If nonzero, one of the -kmbB flags has been provided.  */
+static int display_byte_kilo_mega = 0;
+
+/* Holds the output_block_size for human numbers (-h or -H).  */
+static int h_block_size = 0;
+
 /* Name under which this program was invoked.  */
 char *program_name;
 
@@ -168,6 +193,7 @@
   {"kilobytes", no_argument, NULL, 'k'}, /* long form is obsolescent */
   {"max-depth", required_argument, NULL, MAX_DEPTH_OPTION},
   {"megabytes", no_argument, NULL, 'm'}, /* obsolescent */
+  {"percent", no_argument, NULL, 'p'},
   {"one-file-system", no_argument, NULL, 'x'},
   {"separate-dirs", no_argument, NULL, 'S'},
   {"summarize", no_argument, NULL, 's'},
@@ -353,20 +379,94 @@
     }
 }
 
-/* Print N_BLOCKS followed by STRING on a line.  NBLOCKS is the number of
-   ST_NBLOCKSIZE-byte blocks; convert it to OUTPUT_BLOCK_SIZE units before
-   printing.  If OUTPUT_BLOCK_SIZE is negative, use a human readable
-   notation instead.  */
+/* If -p flag was provided we start by accumulating file data and not printing.
+   Printing will be requested by the du_files function after accumulation.
+   Print N_BLOCKS[\thuman_readable\tpercentage]\tSTRING on a line.
+   N_BLOCKS is the number of ST_NBLOCKSIZE-byte blocks; convert it to
+   OUTPUT_BLOCK_SIZE units before printing.  If OUTPUT_BLOCK_SIZE is negative,
+   use a human readable notation instead.  */
 
 static void
 print_size (uintmax_t n_blocks, const char *string)
 {
   char buf[LONGEST_HUMAN_READABLE + 1];
-  printf ("%s\t%s\n",
-	  human_readable_inexact (n_blocks, buf, ST_NBLOCKSIZE,
-				  output_block_size, human_ceiling),
-	  string);
-  fflush (stdout);
+  double prcnt; /* Temporary variable to hold the percent.  */
+  
+  if (suppress != 0)
+    {
+      /* The p flag is on and we are accumulating file data.
+         Thus we don't want to print.  */
+      
+      now_node = malloc (sizeof (struct list_def));
+      if (now_node == NULL)
+        {
+          fprintf (stderr, "%s: %s", program_name, strerror (errno));
+          exit (1);
+        }
+    
+      if (first_node == NULL)
+        {
+          first_node = now_node;
+          now_node->next = NULL;
+        }
+      else
+        {
+          last_node->next = now_node;
+          now_node->next = NULL;
+        }
+    
+      last_node = now_node;
+    
+      now_node->path = malloc (strlen (string) + 1);
+      if (now_node->path == NULL)
+        {
+          fprintf (stderr, "%s: %s", program_name, strerror (errno));
+          exit (1);
+        }
+      
+      strncpy (now_node->path, string, strlen (string) + 1);
+      now_node->size = n_blocks;
+    }
+  else
+    {
+      /* Print.  */
+      if (display_byte_kilo_mega != 0)
+        {
+          /* Bytes, Kilobytes, Megabytes (-kmbB).  */
+          printf ("%s\t",
+            human_readable_inexact (n_blocks, buf, ST_NBLOCKSIZE,
+	  				output_block_size, human_ceiling));
+	    }
+	  if (h_block_size != 0)
+	    {
+	      /* Human form (-hH).  */
+          printf ("%s\t",
+	        human_readable_inexact (n_blocks, buf, ST_NBLOCKSIZE,
+	    			h_block_size, human_ceiling));
+        }
+      if (display_percentage != 0)
+        {
+          /* Percentage (-p).  */
+          prcnt = ( (double)n_blocks / (double)tot_size) * 100;
+          printf ("%.2f%%\t", prcnt);
+        }
+        
+      if (display_byte_kilo_mega == 0 && h_block_size == 0 && display_percentage == 0)
+        {
+          /* No output flags were provided.  */
+          printf ("%s\t%s\n",
+	        human_readable_inexact (n_blocks, buf, ST_NBLOCKSIZE,
+	      			output_block_size, human_ceiling),
+	        string);
+        }
+      else
+        {
+          /* Filepath.  */
+          printf ("%s\n", string);
+        }
+      
+      fflush (stdout);
+    }
 }
 
 /* Restore the previous working directory or exit.
@@ -553,6 +653,17 @@
       count_entry (arg, 1, 0, 0);
     }
 
+  /* If the -p flag was provided,
+     stop suppressing printing and print the accumulated data.  */
+  if (display_percentage != 0)
+    {
+      suppress = 0;
+      for (now_node = first_node; now_node != NULL; now_node = now_node->next)
+        {
+          print_size (now_node->size, now_node->path);
+        }
+    }
+
   if (print_totals)
     print_size (tot_size, _("total"));
 }
@@ -582,7 +693,7 @@
 
   human_block_size (getenv ("DU_BLOCK_SIZE"), 0, &output_block_size);
 
-  while ((c = getopt_long (argc, argv, "abchHklmsxB:DLSX:", long_options, NULL))
+  while ((c = getopt_long (argc, argv, "abchHklmpsxB:DLSX:", long_options, NULL))
 	 != -1)
     {
       long int tmp_long;
@@ -597,22 +708,33 @@
 
 	case 'b':
 	  output_block_size = 1;
+	  display_byte_kilo_mega = 1;
 	  break;
 
 	case 'c':
 	  print_totals = 1;
 	  break;
 
+	case 'p':
+	  suppress = 1;
+	  display_percentage = 1;
+	  break;
+
 	case 'h':
-	  output_block_size = -1024;
+	  h_block_size = -1024;
+	  if(!display_byte_kilo_mega)
+	    output_block_size = -1024;
 	  break;
 
 	case 'H':
-	  output_block_size = -1000;
+	  h_block_size = -1000;
+	  if(!display_byte_kilo_mega)
+	    output_block_size = -1000;
 	  break;
 
 	case 'k':
 	  output_block_size = 1024;
+	  display_byte_kilo_mega = 1;
 	  break;
 
 	case MAX_DEPTH_OPTION:		/* --max-depth=N */
@@ -626,6 +748,7 @@
 
 	case 'm': /* obsolescent */
 	  output_block_size = 1024 * 1024;
+	  display_byte_kilo_mega = 1;
 	  break;
 
 	case 'l':
@@ -642,6 +765,7 @@
 
 	case 'B':
 	  human_block_size (optarg, 1, &output_block_size);
+	  display_byte_kilo_mega = 1;
 	  break;
 
 	case 'D':
