diff -urpN coreutils-5.0/doc/coreutils.texi cwg-coreutils-5.0/doc/coreutils.texi
--- coreutils-5.0/doc/coreutils.texi	2003-04-02 20:19:11.000000000 +0200
+++ cwg-coreutils-5.0/doc/coreutils.texi	2004-02-02 21:44:15.000000000 +0100
@@ -2948,6 +2948,23 @@ Use this option only if there is no alte
 @option{--numeric-sort} (@option{-n}) and it can lose information when
 converting to floating point.
 
+@item -h
+@itemx --human-numeric-sort
+@opindex -h
+@opindex --human-numeric-sort
+@cindex human numeric sort
+@vindex LC_NUMERIC
+Sort human readable file sizes numerically, using the standard C
+function @code{strtod} to convert a prefix of each line to a
+double-precision floating point number, and multiplying by postfixed
+K, G, or T.  This allows output from du -h to be sorted meaningfully.
+Since this option uses the same approach as
+@option{--general-numeric-sort} (@option{-g}), this option results in
+the same collating sequence as the @option{--general-numeric-sort}
+(@option{-g}).  It also is much slower than @option{--numeric-sort}
+(@option{-n}).
+
+
 @item -i
 @itemx --ignore-nonprinting
 @opindex -i
diff -urpN coreutils-5.0/man/sort.1 cwg-coreutils-5.0/man/sort.1
--- coreutils-5.0/man/sort.1	2003-03-30 14:13:41.000000000 +0200
+++ cwg-coreutils-5.0/man/sort.1	2004-02-02 21:44:42.000000000 +0100
@@ -25,6 +25,9 @@ fold lower case to upper case characters
 \fB\-g\fR, \fB\-\-general\-numeric\-sort\fR
 compare according to general numerical value
 .TP
+\fB\-h\fR, \fB\-\-human\-numeric\-sort\fR
+compare human readable file sizes (e.g., 1K 234M 2G)
+.TP
 \fB\-i\fR, \fB\-\-ignore\-nonprinting\fR
 consider only printable characters
 .TP
diff -urpN coreutils-5.0/src/sort.c cwg-coreutils-5.0/src/sort.c
--- coreutils-5.0/src/sort.c	2002-12-15 15:36:12.000000000 +0100
+++ cwg-coreutils-5.0/src/sort.c	2004-02-02 21:45:14.000000000 +0100
@@ -159,6 +159,8 @@ struct keyfield
 				   point, but no exponential notation. */
   int general_numeric;		/* Flag for general, numeric comparison.
 				   Handle numbers in exponential notation. */
+  int human_numeric;		/* Flag for human readable file size
+				   comparison (e.g., 1K 234M 2G). */
   int month;			/* Flag for comparison by month name. */
   int reverse;			/* Reverse the sense of comparison. */
   struct keyfield *next;	/* Next keyfield to try. */
@@ -293,6 +295,7 @@ Mandatory arguments to long options are 
 "), stdout);
       fputs (_("\
   -g, --general-numeric-sort  compare according to general numerical value\n\
+  -h, --human-numeric-sort    compare human readable file sizes (e.g., 1K 234M 2G)\n\
   -i, --ignore-nonprinting    consider only printable characters\n\
   -M, --month-sort            compare (unknown) < `JAN' < ... < `DEC'\n\
   -n, --numeric-sort          compare according to string numerical value\n\
@@ -349,7 +352,7 @@ native byte values.\n\
   exit (status);
 }
 
-#define COMMON_SHORT_OPTIONS "-bcdfgik:mMno:rsS:t:T:uz"
+#define COMMON_SHORT_OPTIONS "-bcdfghik:mMno:rsS:t:T:uz"
 
 static struct option const long_options[] =
 {
@@ -363,6 +366,7 @@ static struct option const long_options[
   {"merge", no_argument, NULL, 'm'},
   {"month-sort", no_argument, NULL, 'M'},
   {"numeric-sort", no_argument, NULL, 'n'},
+  {"human-numeric-sort", no_argument, NULL, 'h'},
   {"output", required_argument, NULL, 'o'},
   {"reverse", no_argument, NULL, 'r'},
   {"stable", no_argument, NULL, 's'},
@@ -1274,6 +1278,71 @@ general_numcompare (const char *sa, cons
 	  : memcmp ((char *) &a, (char *) &b, sizeof a));
 }
 
+static int
+human_numcompare (const char *sa, const char *sb)
+{
+  /* FIXME: add option to warn about failed conversions.  */
+  /* FIXME: maybe add option to try expensive FP conversion
+     only if A and B can't be compared more cheaply/accurately.  */
+  char *ea;
+  char *eb;
+  double a = strtod (sa, &ea);
+  double b = strtod (sb, &eb);
+
+  /* Put conversion errors at the start of the collating sequence.  */
+  if (sa == ea)
+    return sb == eb ? 0 : -1;
+  if (sb == eb)
+    return 1;
+
+  if (ea != NULL) {
+    switch (*ea) {
+    case 'K':
+    case 'k':
+      a *= 1024.0;
+      break;
+    case 'M':
+      a *= 1048576.0;
+      break;
+    case 'G':
+      a *= 1073741824.0;
+      break;
+    case 'T':
+      a *= 1099511627776.0;
+      break;
+    }
+  }
+
+
+  if (eb != NULL) {
+    switch (*eb) {
+    case 'K':
+    case 'k':
+      b *= 1024.0;
+      break;
+    case 'M':
+      b *= 1048576.0;
+      break;
+    case 'G':
+      b *= 1073741824.0;
+      break;
+    case 'T':
+      b *= 1099511627776.0;
+      break;
+    }
+  }
+
+  /* Sort numbers in the usual way, where -0 == +0.  Put NaNs after
+     conversion errors but before numbers; sort them by internal
+     bit-pattern, for lack of a more portable alternative.  */
+  return (a < b ? -1
+	  : a > b ? 1
+	  : a == b ? 0
+	  : b == b ? -1
+	  : a == a ? 1
+	  : memcmp ((char *) &a, (char *) &b, sizeof a));
+}
+
 /* Return an integer in 1..12 of the month name S with length LEN.
    Return 0 if the name in S is not recognized.  */
 
@@ -1354,13 +1423,17 @@ keycompare (const struct line *a, const 
 	}
 
       /* Actually compare the fields. */
-      if (key->numeric | key->general_numeric)
+      if (key->numeric | key->general_numeric | key->human_numeric)
 	{
 	  char savea = *lima, saveb = *limb;
 
 	  *lima = *limb = '\0';
-	  diff = ((key->numeric ? numcompare : general_numcompare)
-		  (texta, textb));
+/* 	  diff = ((key->numeric ? numcompare : general_numcompare) */
+/* 		  (texta, textb)); */
+	  diff = ((key->numeric ? numcompare : 
+		   (key->general_numeric ? general_numcompare : 
+		    human_numcompare ) ) (texta, textb));
+
 	  *lima = savea, *limb = saveb;
 	}
       else if (key->month)
@@ -2124,6 +2197,9 @@ set_ordering (register const char *s, st
 	case 'g':
 	  key->general_numeric = 1;
 	  break;
+	case 'h':
+	  key->human_numeric = 1;
+	  break;
 	case 'i':
 	  key->ignore = nonprinting;
 	  break;
@@ -2242,7 +2318,7 @@ main (int argc, char **argv)
   gkey.sword = gkey.eword = -1;
   gkey.ignore = NULL;
   gkey.translate = NULL;
-  gkey.numeric = gkey.general_numeric = gkey.month = gkey.reverse = 0;
+  gkey.numeric = gkey.general_numeric = gkey.human_numeric = gkey.month = gkey.reverse = 0;
   gkey.skipsblanks = gkey.skipeblanks = 0;
 
   files = (char **) xmalloc (sizeof (char *) * argc);
@@ -2314,6 +2390,7 @@ main (int argc, char **argv)
 	case 'd':
 	case 'f':
 	case 'g':
+	case 'h':
 	case 'i':
 	case 'M':
 	case 'n':
@@ -2452,12 +2529,13 @@ main (int argc, char **argv)
 	key->month = gkey.month;
 	key->numeric = gkey.numeric;
 	key->general_numeric = gkey.general_numeric;
+	key->human_numeric = gkey.human_numeric;
 	key->reverse = gkey.reverse;
       }
 
   if (!keylist && (gkey.ignore || gkey.translate || gkey.skipsblanks
 		   || gkey.skipeblanks || gkey.month || gkey.numeric
-		   || gkey.general_numeric))
+		   || gkey.general_numeric || gkey.human_numeric))
     insertkey (&gkey);
   reverse = gkey.reverse;
 
