summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1995-11-15 21:42:47 +0000
committerJim Meyering <jim@meyering.net>1995-11-15 21:42:47 +0000
commit34fc818d7edaefcc4a420f1da3b7002d35aa4103 (patch)
tree690945839d28a02676d977ad613980926902809b /src
parentf1e1eb58bef89b3eae1210d46fb0d88f73b5a409 (diff)
downloadcoreutils-34fc818d7edaefcc4a420f1da3b7002d35aa4103.tar.xz
Add support for sorting numbers in scientific notation.
Include xstrtod.h. (struct keyfield): Add field: general_numeric. (usage): Describe -g option. (general_numcompare): New function. (keycompare): Use new comparison function when general_numeric flag is set. (set_ordering): Honor `g' flag. (main): Initialize and use new field. From Marcus Daniels <marcus@sysc.pdx.edu>.
Diffstat (limited to 'src')
-rw-r--r--src/sort.c58
1 files changed, 50 insertions, 8 deletions
diff --git a/src/sort.c b/src/sort.c
index 1631b65dd..30a5ecad9 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -31,6 +31,7 @@
#include "version.h"
#include "long-options.h"
#include "error.h"
+#include "xstrtod.h"
#ifdef HAVE_LIMITS_H
#include <limits.h>
@@ -96,7 +97,11 @@ struct keyfield
int skipeblanks; /* Skip trailing white space at finish. */
int *ignore; /* Boolean array of characters to ignore. */
char *translate; /* Translation applied to characters. */
- int numeric; /* Flag for numeric comparison. */
+ int numeric; /* Flag for numeric comparison. Handle
+ strings of digits with optional decimal
+ point, but no exponential notation. */
+ int general_numeric; /* Flag for general, numeric comparison.
+ Handle numbers in exponential notation. */
int month; /* Flag for comparison by month name. */
int reverse; /* Reverse the sense of comparison. */
struct keyfield *next; /* Next keyfield to try. */
@@ -209,6 +214,7 @@ Write sorted concatenation of all FILE(s) to standard output.\n\
-c check if given files already sorted, do not sort\n\
-d consider only [a-zA-Z0-9 ] characters in keys\n\
-f fold lower case to upper case characters in keys\n\
+ -g compare according to general numerical value, imply -b\n\
-i consider only [\\040-\\0176] characters in keys\n\
-k POS1[,POS2] same as +POS1 [-POS2], but all positions counted from 1\n\
-m merge already sorted files, do not sort\n\
@@ -803,6 +809,24 @@ numcompare (register const char *a, register const char *b)
}
}
+static int
+general_numcompare (const char *sa, const char *sb)
+{
+ double a, b;
+ /* 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. */
+ if (xstrtod (sa, NULL, &a))
+ {
+ a = 0;
+ }
+ if (xstrtod (sb, NULL, &b))
+ {
+ b = 0;
+ }
+ return a == b ? 0 : a < b ? -1 : 1;
+}
+
/* Return an integer <= 12 associated with month name S with length LEN,
0 if the name in S is not recognized. */
@@ -903,6 +927,23 @@ keycompare (const struct line *a, const struct line *b)
return key->reverse ? -diff : diff;
continue;
}
+ else if (key->general_numeric)
+ {
+ if (*lima || *limb)
+ {
+ char savea = *lima, saveb = *limb;
+
+ *lima = *limb = '\0';
+ diff = general_numcompare (texta, textb);
+ *lima = savea, *limb = saveb;
+ }
+ else
+ diff = general_numcompare (texta, textb);
+
+ if (diff)
+ return key->reverse ? -diff : diff;
+ continue;
+ }
else if (key->month)
{
diff = getmonth (texta, lena) - getmonth (textb, lenb);
@@ -1479,11 +1520,9 @@ set_ordering (register const char *s, struct keyfield *key,
case 'f':
key->translate = fold_toupper;
break;
-#if 0
case 'g':
- /* Reserved for comparing floating-point numbers. */
+ key->general_numeric = 1;
break;
-#endif
case 'i':
key->ignore = nonprinting;
break;
@@ -1563,7 +1602,7 @@ main (int argc, char **argv)
gkey.sword = gkey.eword = -1;
gkey.ignore = NULL;
gkey.translate = NULL;
- gkey.numeric = gkey.month = gkey.reverse = 0;
+ gkey.numeric = gkey.general_numeric = gkey.month = gkey.reverse = 0;
gkey.skipsblanks = gkey.skipeblanks = 0;
files = (char **) xmalloc (sizeof (char *) * argc);
@@ -1579,7 +1618,7 @@ main (int argc, char **argv)
key->ignore = NULL;
key->translate = NULL;
key->skipsblanks = key->skipeblanks = 0;
- key->numeric = key->month = key->reverse = 0;
+ key->numeric = key->general_numeric = key->month = key->reverse = 0;
s = argv[i] + 1;
if (! (digits[UCHAR (*s)] || (*s == '.' && digits[UCHAR (s[1])])))
badfieldspec (argv[i]);
@@ -1776,7 +1815,8 @@ main (int argc, char **argv)
/* Inheritance of global options to individual keys. */
for (key = keyhead.next; key; key = key->next)
if (!key->ignore && !key->translate && !key->skipsblanks && !key->reverse
- && !key->skipeblanks && !key->month && !key->numeric)
+ && !key->skipeblanks && !key->month && !key->numeric
+ && !key->general_numeric)
{
key->ignore = gkey.ignore;
key->translate = gkey.translate;
@@ -1784,11 +1824,13 @@ main (int argc, char **argv)
key->skipeblanks = gkey.skipeblanks;
key->month = gkey.month;
key->numeric = gkey.numeric;
+ key->general_numeric = gkey.general_numeric;
key->reverse = gkey.reverse;
}
if (!keyhead.next && (gkey.ignore || gkey.translate || gkey.skipsblanks
- || gkey.skipeblanks || gkey.month || gkey.numeric))
+ || gkey.skipeblanks || gkey.month || gkey.numeric
+ || gkey.general_numeric))
insertkey (&gkey);
reverse = gkey.reverse;