--- textutils-2.0/lib/Makefile.am Sun Jul 4 06:16:53 1999 +++ textutils/lib/Makefile.am Wed Mar 8 18:44:08 2000 @@ -10,7 +10,8 @@ getopt1.c hard-locale.c human.c \ linebuffer.c long-options.c md5.c memcasecmp.c memcoll.c \ obstack.c quotearg.c readtokens.c safe-read.c \ - version-etc.c xmalloc.c xstrdup.c xstrtod.c xstrtol.c xstrtoul.c xstrtoumax.c + version-etc.c xmalloc.c xstrdup.c xstrtod.c xstrtol.c xstrtoul.c xstrtoumax.c \ + strnatcmp.c libtu_a_LIBADD = @LIBOBJS@ @ALLOCA@ libtu_a_DEPENDENCIES = $(libtu_a_LIBADD) @@ -21,7 +22,8 @@ lchown.h linebuffer.h long-options.h md5.h \ memcasecmp.h memcoll.h obstack.h quotearg.h \ readtokens.h regex.h safe-read.h \ - version-etc.h xalloc.h xstrtod.h xstrtol.h + version-etc.h xalloc.h xstrtod.h xstrtol.h \ + strnatcmp.h BUILT_SOURCES = lstat.c stat.c --- textutils-2.0/src/sort.c Thu Aug 5 03:42:49 1999 +++ textutils/src/sort.c Fri Mar 10 15:00:35 2000 @@ -1,5 +1,5 @@ /* sort - sort lines of text (with all kinds of options). - Copyright (C) 88, 1991-1999 Free Software Foundation, Inc. + Copyright (C) 1988, 1991-2000 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 @@ -19,7 +19,9 @@ The author may be reached (Email) at the address mike@gnu.ai.mit.edu, or (US mail) as Mike Haertel c/o Free Software Foundation. - Ørn E. Hansen added NLS support in 1997. */ + Ørn E. Hansen added NLS support in 1997. + + Martin Pool added natural order sorting in 2000. */ #include @@ -33,17 +35,18 @@ #include "hard-locale.h" #include "memcoll.h" #include "xalloc.h" +#include "strnatcmp.h" /* The official name of this program (e.g., no `g' prefix). */ #define PROGRAM_NAME "sort" #define AUTHORS "Mike Haertel" -#if defined ENABLE_NLS && HAVE_LANGINFO_H +#if defined(ENABLE_NLS) && HAVE_LANGINFO_H # include #endif -#if HAVE_PATHCONF && defined _PC_NAME_MAX +#if HAVE_PATHCONF && defined(_PC_NAME_MAX) # define NAME_MAX_IN_DIR(Dir) pathconf (Dir, _PC_NAME_MAX) #else # define NAME_MAX_IN_DIR(Dir) 255 @@ -150,6 +153,8 @@ Handle numbers in exponential notation. */ int month; /* Flag for comparison by month name. */ int reverse; /* Reverse the sense of comparison. */ + int natural; /* Natural sort that handles strings + containing integer substrings. */ struct keyfield *next; /* Next keyfield to try. */ }; @@ -177,7 +182,7 @@ #define MONTHS_PER_YEAR 12 -#if defined ENABLE_NLS && HAVE_NL_LANGINFO +#if defined(ENABLE_NLS) && HAVE_NL_LANGINFO # define MONTHTAB_CONST /* empty */ #else # define MONTHTAB_CONST const @@ -274,6 +279,7 @@ -m merge already sorted files, do not sort\n\ -M compare (unknown) < `JAN' < ... < `DEC', imply -b\n\ -n compare according to string numerical value, imply -b\n\ + -N natural sort order for numbers in strings\n\ -o FILE write result on FILE instead of standard output\n\ -r reverse the result of comparisons\n\ -s stabilize sort by disabling last resort comparison\n\ @@ -290,8 +296,8 @@ printf (_("\ POS is F[.C][OPTS], where F is the field number and C the character position\n\ in the field, both counted from one with -k, from zero with the obsolescent\n\ -form. OPTS is made up of one or more of Mbdfinr; this effectively disables\n\ -global -Mbdfinr settings for that key. If no key is given, use the entire\n\ +form. OPTS is made up of one or more of MbdfinrN; this effectively disables\n\ +global -MbdfinrN settings for that key. If no key is given, use the entire\n\ line as the key. With no FILE, or when FILE is -, read standard input.\n\ ") ); @@ -497,7 +503,7 @@ fold_toupper[i] = i; } -#if defined ENABLE_NLS && HAVE_NL_LANGINFO +#if defined(ENABLE_NLS) && HAVE_NL_LANGINFO /* If we're not in the "C" locale, read different names for months. */ if (hard_LC_TIME) { @@ -1039,6 +1045,44 @@ : memcmp ((char *) &a, (char *) &b, sizeof a)); } + +static int +natural_compare (const char *texta, int lena, const char *textb, int lenb, + int const *ignore, char const *translate) +{ + if (ignore || translate) + { + char *copy_a = (char *) alloca (lena + 1); + char *copy_b = (char *) alloca (lenb + 1); + int new_len_a, new_len_b, i; + + /* Ignore and/or translate chars before comparing. */ + for (new_len_a = new_len_b = i = 0; i < max (lena, lenb); i++) + { + if (i < lena) + { + copy_a[new_len_a] = (translate + ? translate[UCHAR (texta[i])] + : texta[i]); + if (!ignore || !ignore[UCHAR (texta[i])]) + ++new_len_a; + } + if (i < lenb) + { + copy_b[new_len_b] = (translate + ? translate[UCHAR (textb[i])] + : textb [i]); + if (!ignore || !ignore[UCHAR (textb[i])]) + ++new_len_b; + } + } + + return memcoll (copy_a, new_len_a, copy_b, new_len_b); + } + else + return strnatcmp (texta, textb); +} + /* Return an integer in 1..12 of the month name S with length LEN. Return 0 if the name in S is not recognized. */ @@ -1178,6 +1222,16 @@ return key->reverse ? -diff : diff; continue; } + else if (key->natural) + { + diff = natural_compare (texta, lena, textb, lenb, ignore, translate); + if (diff) + return key->reverse ? -diff : diff; + + /* if this didn't match, then we continue on to try other + fields. */ + continue; + } #ifdef ENABLE_NLS /* Sorting like this may become slow, so in a simple locale the user @@ -1872,6 +1926,9 @@ case 'n': key->numeric = 1; break; + case 'N': + key->natural = 1; + break; case 'r': key->reverse = 1; break; @@ -1981,6 +2038,7 @@ gkey.ignore = NULL; gkey.translate = NULL; gkey.numeric = gkey.general_numeric = gkey.month = gkey.reverse = 0; + gkey.natural = 0; gkey.skipsblanks = gkey.skipeblanks = 0; files = (char **) xmalloc (sizeof (char *) * argc); @@ -2239,7 +2297,7 @@ /* 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->natural && !key->general_numeric) { key->ignore = gkey.ignore; @@ -2250,11 +2308,12 @@ key->numeric = gkey.numeric; key->general_numeric = gkey.general_numeric; key->reverse = gkey.reverse; + key->natural = gkey.natural; } if (!keyhead.next && (gkey.ignore || gkey.translate || gkey.skipsblanks || gkey.skipeblanks || gkey.month || gkey.numeric - || gkey.general_numeric)) + || gkey.natural || gkey.general_numeric)) insertkey (&gkey); reverse = gkey.reverse;