diff options
-rw-r--r-- | gnu/usr.bin/sort/config.h | 123 | ||||
-rw-r--r-- | gnu/usr.bin/sort/error.c | 110 | ||||
-rw-r--r-- | gnu/usr.bin/sort/error.h | 44 | ||||
-rw-r--r-- | gnu/usr.bin/sort/getopt.c | 271 | ||||
-rw-r--r-- | gnu/usr.bin/sort/getopt.h | 12 | ||||
-rw-r--r-- | gnu/usr.bin/sort/getopt1.c | 11 | ||||
-rw-r--r-- | gnu/usr.bin/sort/long-options.c | 22 | ||||
-rw-r--r-- | gnu/usr.bin/sort/long-options.h | 11 | ||||
-rw-r--r-- | gnu/usr.bin/sort/sort.1 | 15 | ||||
-rw-r--r-- | gnu/usr.bin/sort/sort.c | 966 | ||||
-rw-r--r-- | gnu/usr.bin/sort/system.h | 117 | ||||
-rw-r--r-- | gnu/usr.bin/sort/version.c | 12 | ||||
-rw-r--r-- | gnu/usr.bin/sort/xstrtod.c | 48 | ||||
-rw-r--r-- | gnu/usr.bin/sort/xstrtod.h | 15 |
14 files changed, 1192 insertions, 585 deletions
diff --git a/gnu/usr.bin/sort/config.h b/gnu/usr.bin/sort/config.h new file mode 100644 index 0000000..27f201bb --- /dev/null +++ b/gnu/usr.bin/sort/config.h @@ -0,0 +1,123 @@ +/* config.h. Generated automatically by configure. */ +/* config.h.in. Generated automatically from configure.in by autoheader. */ + +/* Define if on AIX 3. + System headers sometimes define this. + We just want to avoid a redefinition error message. */ +#ifndef _ALL_SOURCE +/* #undef _ALL_SOURCE */ +#endif + +/* Define if using alloca.c. */ +/* #undef C_ALLOCA */ + +/* Define to empty if the keyword does not work. */ +/* #undef const */ + +/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems. + This function is required for alloca.c support on those systems. */ +/* #undef CRAY_STACKSEG_END */ + +/* Define if you have alloca, as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define if you have <alloca.h> and it should be used (not on Ultrix). */ +/* #undef HAVE_ALLOCA_H */ + +/* Define if you don't have vprintf but do have _doprnt. */ +/* #undef HAVE_DOPRNT */ + +/* Define if the `long double' type works. */ +#define HAVE_LONG_DOUBLE 1 + +/* Define if your struct stat has st_blksize. */ +#define HAVE_ST_BLKSIZE 1 + +/* Define if you have the vprintf function. */ +#define HAVE_VPRINTF 1 + +/* Define as __inline if that's what the C compiler calls it. */ +/* #undef inline */ + +/* Define if on MINIX. */ +/* #undef _MINIX */ + +/* Define to `long' if <sys/types.h> doesn't define. */ +/* #undef off_t */ + +/* Define if the system does not provide POSIX.1 features except + with this defined. */ +/* #undef _POSIX_1_SOURCE */ + +/* Define if you need to in order for stat and other things to work. */ +/* #undef _POSIX_SOURCE */ + +/* Define as the return type of signal handlers (int or void). */ +#define RETSIGTYPE void + +/* Define to `unsigned' if <sys/types.h> doesn't define. */ +/* #undef size_t */ + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at run-time. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown + */ +/* #undef STACK_DIRECTION */ + +/* Define if the `S_IS*' macros in <sys/stat.h> do not work properly. */ +/* #undef STAT_MACROS_BROKEN */ + +/* Define if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define if your processor stores words with the most significant + byte first (like Motorola and SPARC, unlike Intel and VAX). */ +/* #undef WORDS_BIGENDIAN */ + +/* Define to 1 if ANSI function prototypes are usable. */ +#define PROTOTYPES 1 + +/* Define to 1 if GNU regex should be used instead of GNU rx. */ +/* #undef WITH_REGEX */ + +/* Define if you have the isascii function. */ +#define HAVE_ISASCII 1 + +/* Define if you have the strchr function. */ +#define HAVE_STRCHR 1 + +/* Define if you have the strerror function. */ +#define HAVE_STRERROR 1 + +/* Define if you have the strrchr function. */ +#define HAVE_STRRCHR 1 + +/* Define if you have the <dirent.h> header file. */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the <fcntl.h> header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the <limits.h> header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the <memory.h> header file. */ +#define HAVE_MEMORY_H 1 + +/* Define if you have the <ndir.h> header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the <string.h> header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the <sys/dir.h> header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the <sys/ndir.h> header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the <unistd.h> header file. */ +#define HAVE_UNISTD_H 1 diff --git a/gnu/usr.bin/sort/error.c b/gnu/usr.bin/sort/error.c index e849c5b..a36198b 100644 --- a/gnu/usr.bin/sort/error.c +++ b/gnu/usr.bin/sort/error.c @@ -1,5 +1,5 @@ /* error.c -- error handler for noninteractive utilities - Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. + Copyright (C) 1990, 91, 92, 93, 94, 95 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 @@ -15,42 +15,55 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -/* Written by David MacKenzie. */ +/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ -#include <stdio.h> - -#ifdef HAVE_VPRINTF +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif -#if __STDC__ -#include <stdarg.h> -#define VA_START(args, lastarg) va_start(args, lastarg) -#else /* !__STDC__ */ -#include <varargs.h> -#define VA_START(args, lastarg) va_start(args) -#endif /* !__STDC__ */ +#include <stdio.h> -#else /* !HAVE_VPRINTF */ +#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC +# if __STDC__ +# include <stdarg.h> +# define VA_START(args, lastarg) va_start(args, lastarg) +# else +# include <varargs.h> +# define VA_START(args, lastarg) va_start(args) +# endif +#else +# define va_alist a1, a2, a3, a4, a5, a6, a7, a8 +# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; +#endif + +#if STDC_HEADERS || _LIBC +# include <stdlib.h> +# include <string.h> +#else +void exit (); +#endif -#ifdef HAVE_DOPRNT -#define va_alist args -#define va_dcl int args; -#else /* !HAVE_DOPRNT */ -#define va_alist a1, a2, a3, a4, a5, a6, a7, a8 -#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; -#endif /* !HAVE_DOPRNT */ +/* This variable is incremented each time `error' is called. */ +unsigned int error_message_count; -#endif /* !HAVE_VPRINTF */ +/* If NULL, error will flush stdout, then print on stderr the program + name, a colon and a space. Otherwise, error will call this + function without parameters instead. */ +void (*error_print_progname) () = NULL; -#ifdef STDC_HEADERS -#include <stdlib.h> -#include <string.h> -#else /* !STDC_HEADERS */ -void exit (); -#endif /* !STDC_HEADERS */ +#ifdef _LIBC +#define program_name program_invocation_name +#endif +/* The calling program should define program_name and set it to the + name of the executing program. */ extern char *program_name; -#ifndef HAVE_STRERROR +#if HAVE_STRERROR || _LIBC +# ifndef strerror /* On some systems, strerror is a macro */ +char *strerror (); +# endif +#else static char * private_strerror (errnum) int errnum; @@ -63,40 +76,51 @@ private_strerror (errnum) return "Unknown system error"; } #define strerror private_strerror -#endif /* !HAVE_STRERROR */ +#endif /* Print the program name and error message MESSAGE, which is a printf-style format string with optional args. If ERRNUM is nonzero, print its corresponding system error message. Exit with status STATUS if it is nonzero. */ /* VARARGS */ + void -#if defined (HAVE_VPRINTF) && __STDC__ -error (int status, int errnum, char *message, ...) -#else /* !HAVE_VPRINTF or !__STDC__ */ +#if defined(VA_START) && __STDC__ +error (int status, int errnum, const char *message, ...) +#else error (status, errnum, message, va_alist) int status; int errnum; char *message; va_dcl -#endif /* !HAVE_VPRINTF or !__STDC__ */ +#endif { -#ifdef HAVE_VPRINTF +#ifdef VA_START va_list args; -#endif /* HAVE_VPRINTF */ +#endif + + if (error_print_progname) + (*error_print_progname) (); + else + { + fflush (stdout); + fprintf (stderr, "%s: ", program_name); + } - fprintf (stderr, "%s: ", program_name); -#ifdef HAVE_VPRINTF +#ifdef VA_START VA_START (args, message); +# if HAVE_VPRINTF || _LIBC vfprintf (stderr, message, args); +# else + _doprnt (message, args, stderr); +# endif va_end (args); -#else /* !HAVE_VPRINTF */ -#ifdef HAVE_DOPRNT - _doprnt (message, &args, stderr); -#else /* !HAVE_DOPRNT */ +#else fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8); -#endif /* !HAVE_DOPRNT */ -#endif /* !HAVE_VPRINTF */ +#endif + + ++error_message_count; + if (errnum) fprintf (stderr, ": %s", strerror (errnum)); putc ('\n', stderr); diff --git a/gnu/usr.bin/sort/error.h b/gnu/usr.bin/sort/error.h new file mode 100644 index 0000000..481c54d --- /dev/null +++ b/gnu/usr.bin/sort/error.h @@ -0,0 +1,44 @@ +/* error.h -- declaration for error-reporting function + Copyright (C) 1995 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 + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef _error_h_ +#define _error_h_ + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __format__ format +# define __printf__ printf +# endif +#endif + +#if __STDC__ +void error (int, int, const char *, ...) \ + __attribute__ ((__format__ (__printf__, 3, 4))); +#else +void error (); +#endif + +/* This variable is incremented each time `error' is called. */ +extern unsigned int error_message_count; + +#endif /* _error_h_ */ diff --git a/gnu/usr.bin/sort/getopt.c b/gnu/usr.bin/sort/getopt.c index 7a4673b..8bcf559 100644 --- a/gnu/usr.bin/sort/getopt.c +++ b/gnu/usr.bin/sort/getopt.c @@ -3,7 +3,7 @@ "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu before changing it! - Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 + Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it @@ -20,18 +20,17 @@ along with this program; if not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. + Ditto for AIX 3.2 and <stdlib.h>. */ +#ifndef _NO_PROTO +#define _NO_PROTO +#endif + #ifdef HAVE_CONFIG_H -#if defined (emacs) || defined (CONFIG_BROKETS) -/* We use <config.h> instead of "config.h" so that a compilation - using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h - (which it would do because it found this file in $srcdir). */ #include <config.h> -#else -#include "config.h" -#endif #endif -#ifndef __STDC__ +#if !defined (__STDC__) || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const @@ -39,11 +38,6 @@ #endif #endif -/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>. */ -#ifndef _NO_PROTO -#define _NO_PROTO -#endif - #include <stdio.h> /* Comment out all this code if we are using the GNU C Library, and are not @@ -65,10 +59,16 @@ #include <stdlib.h> #endif /* GNU C library. */ -/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a - long-named option. Because this is not POSIX.2 compliant, it is - being phased out. */ -/* #define GETOPT_COMPAT */ +#ifndef _ +/* This is for other GNU distributions with internationalized messages. + When compiling libc, the _ macro is predefined. */ +#ifdef HAVE_LIBINTL_H +# include <libintl.h> +# define _(msgid) gettext (msgid) +#else +# define _(msgid) (msgid) +#endif +#endif /* This version of `getopt' appears to the caller like standard Unix `getopt' but it behaves differently for the user, since it allows the user @@ -92,7 +92,7 @@ Also, when `ordering' is RETURN_IN_ORDER, each non-option ARGV-element is returned here. */ -char *optarg = 0; +char *optarg = NULL; /* Index in ARGV of the next element to be scanned. This is used for communication to and from the caller @@ -162,6 +162,9 @@ static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering; + +/* Value of POSIXLY_CORRECT environment variable. */ +static char *posixly_correct; #ifdef __GNU_LIBRARY__ /* We want to avoid inclusion of string.h with non-GNU libraries @@ -192,19 +195,18 @@ my_index (str, chr) } /* If using GCC, we can safely declare strlen this way. - If not using GCC, it is ok not to declare it. - (Supposedly there are some machines where it might get a warning, - but changing this conditional to __STDC__ is too risky.) */ + If not using GCC, it is ok not to declare it. */ #ifdef __GNUC__ -#ifdef IN_GCC -#include "gstddef.h" -#else -#include <stddef.h> -#endif -extern size_t strlen (const char *); -#endif - -#endif /* GNU C library. */ +/* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h. + That was relevant to code that was here before. */ +#if !defined (__STDC__) || !__STDC__ +/* gcc with -traditional declares the built-in strlen to return int, + and has done so at least since version 2.4.5. -- rms. */ +extern int strlen (const char *); +#endif /* not __STDC__ */ +#endif /* __GNUC__ */ + +#endif /* not __GNU_LIBRARY__ */ /* Handle permutation of arguments. */ @@ -279,6 +281,42 @@ exchange (argv) first_nonopt += (optind - last_nonopt); last_nonopt = optind; } + +/* Initialize the internal data when the first call is made. */ + +static const char * +_getopt_initialize (optstring) + const char *optstring; +{ + /* Start processing options with ARGV-element 1 (since ARGV-element 0 + is the program name); the sequence of previously skipped + non-option ARGV-elements is empty. */ + + first_nonopt = last_nonopt = optind = 1; + + nextchar = NULL; + + posixly_correct = getenv ("POSIXLY_CORRECT"); + + /* Determine how to handle the ordering of options and nonoptions. */ + + if (optstring[0] == '-') + { + ordering = RETURN_IN_ORDER; + ++optstring; + } + else if (optstring[0] == '+') + { + ordering = REQUIRE_ORDER; + ++optstring; + } + else if (posixly_correct != NULL) + ordering = REQUIRE_ORDER; + else + ordering = PERMUTE; + + return optstring; +} /* Scan elements of ARGV (whose length is ARGC) for option characters given in OPTSTRING. @@ -345,41 +383,18 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) int *longind; int long_only; { - int option_index; - - optarg = 0; - - /* Initialize the internal data when the first call is made. - Start processing options with ARGV-element 1 (since ARGV-element 0 - is the program name); the sequence of previously skipped - non-option ARGV-elements is empty. */ + optarg = NULL; if (optind == 0) { - first_nonopt = last_nonopt = optind = 1; - - nextchar = NULL; - - /* Determine how to handle the ordering of options and nonoptions. */ - - if (optstring[0] == '-') - { - ordering = RETURN_IN_ORDER; - ++optstring; - } - else if (optstring[0] == '+') - { - ordering = REQUIRE_ORDER; - ++optstring; - } - else if (getenv ("POSIXLY_CORRECT") != NULL) - ordering = REQUIRE_ORDER; - else - ordering = PERMUTE; + optstring = _getopt_initialize (optstring); + optind = 1; /* Don't scan ARGV[0], the program name. */ } if (nextchar == NULL || *nextchar == '\0') { + /* Advance to the next ARGV-element. */ + if (ordering == PERMUTE) { /* If we have just processed some options following some non-options, @@ -390,21 +405,16 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) else if (last_nonopt != optind) first_nonopt = optind; - /* Now skip any additional non-options + /* Skip any additional non-options and extend the range of non-options previously skipped. */ while (optind < argc - && (argv[optind][0] != '-' || argv[optind][1] == '\0') -#ifdef GETOPT_COMPAT - && (longopts == NULL - || argv[optind][0] != '+' || argv[optind][1] == '\0') -#endif /* GETOPT_COMPAT */ - ) + && (argv[optind][0] != '-' || argv[optind][1] == '\0')) optind++; last_nonopt = optind; } - /* Special ARGV-element `--' means premature end of options. + /* The special ARGV-element `--' means premature end of options. Skip it like a null option, then exchange with previous non-options as if it were an option, then skip everything else like a non-option. */ @@ -437,12 +447,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) /* If we have come to a non-option and did not permute it, either stop the scan or describe it to the caller and pass it by. */ - if ((argv[optind][0] != '-' || argv[optind][1] == '\0') -#ifdef GETOPT_COMPAT - && (longopts == NULL - || argv[optind][0] != '+' || argv[optind][1] == '\0') -#endif /* GETOPT_COMPAT */ - ) + if ((argv[optind][0] != '-' || argv[optind][1] == '\0')) { if (ordering == REQUIRE_ORDER) return EOF; @@ -451,36 +456,53 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) } /* We have found another option-ARGV-element. - Start decoding its characters. */ + Skip the initial punctuation. */ nextchar = (argv[optind] + 1 + (longopts != NULL && argv[optind][1] == '-')); } + /* Decode the current option-ARGV-element. */ + + /* Check whether the ARGV-element is a long option. + + If long_only and the ARGV-element has the form "-f", where f is + a valid short option, don't consider it an abbreviated form of + a long option that starts with f. Otherwise there would be no + way to give the -f short option. + + On the other hand, if there's a long option "fubar" and + the ARGV-element is "-fu", do consider that an abbreviation of + the long option, just like "--fu", and not "-f" with arg "u". + + This distinction seems to be the most useful approach. */ + if (longopts != NULL - && ((argv[optind][0] == '-' - && (argv[optind][1] == '-' || long_only)) -#ifdef GETOPT_COMPAT - || argv[optind][0] == '+' -#endif /* GETOPT_COMPAT */ - )) + && (argv[optind][1] == '-' + || (long_only && (argv[optind][2] + || !my_index (optstring, argv[optind][1]))))) { + char *nameend; const struct option *p; - char *s = nextchar; + const struct option *pfound = NULL; int exact = 0; int ambig = 0; - const struct option *pfound = NULL; int indfound; + int option_index; + + for (nameend = nextchar; *nameend && *nameend != '='; nameend++) + /* Do nothing. */ ; - while (*s && *s != '=') - s++; +#ifdef lint + indfound = 0; /* Avoid spurious compiler warning. */ +#endif - /* Test all options for either exact match or abbreviated matches. */ - for (p = longopts, option_index = 0; p->name; - p++, option_index++) - if (!strncmp (p->name, nextchar, s - nextchar)) + /* Test all long options for either exact match + or abbreviated matches. */ + for (p = longopts, option_index = 0; p->name; p++, option_index++) + if (!strncmp (p->name, nextchar, nameend - nextchar)) { - if (s - nextchar == strlen (p->name)) + if (nameend - nextchar == strlen (p->name)) { /* Exact match found. */ pfound = p; @@ -495,14 +517,14 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) indfound = option_index; } else - /* Second nonexact match found. */ + /* Second or later nonexact match found. */ ambig = 1; } if (ambig && !exact) { if (opterr) - fprintf (stderr, "%s: option `%s' is ambiguous\n", + fprintf (stderr, _("%s: option `%s' is ambiguous\n"), argv[0], argv[optind]); nextchar += strlen (nextchar); optind++; @@ -513,27 +535,26 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { option_index = indfound; optind++; - if (*s) + if (*nameend) { /* Don't test has_arg with >, because some C compilers don't allow it to be used on enums. */ if (pfound->has_arg) - optarg = s + 1; + optarg = nameend + 1; else { if (opterr) - { - if (argv[optind - 1][1] == '-') - /* --option */ - fprintf (stderr, - "%s: option `--%s' doesn't allow an argument\n", - argv[0], pfound->name); - else - /* +option or -option */ - fprintf (stderr, - "%s: option `%c%s' doesn't allow an argument\n", - argv[0], argv[optind - 1][0], pfound->name); - } + if (argv[optind - 1][1] == '-') + /* --option */ + fprintf (stderr, + _("%s: option `--%s' doesn't allow an argument\n"), + argv[0], pfound->name); + else + /* +option or -option */ + fprintf (stderr, + _("%s: option `%c%s' doesn't allow an argument\n"), + argv[0], argv[optind - 1][0], pfound->name); + nextchar += strlen (nextchar); return '?'; } @@ -545,8 +566,9 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) else { if (opterr) - fprintf (stderr, "%s: option `%s' requires an argument\n", - argv[0], argv[optind - 1]); + fprintf (stderr, + _("%s: option `%s' requires an argument\n"), + argv[0], argv[optind - 1]); nextchar += strlen (nextchar); return optstring[0] == ':' ? ':' : '?'; } @@ -561,25 +583,23 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) } return pfound->val; } + /* Can't find it as a long option. If this is not getopt_long_only, or the option starts with '--' or is not a valid short option, then it's an error. Otherwise interpret it as a short option. */ if (!long_only || argv[optind][1] == '-' -#ifdef GETOPT_COMPAT - || argv[optind][0] == '+' -#endif /* GETOPT_COMPAT */ || my_index (optstring, *nextchar) == NULL) { if (opterr) { if (argv[optind][1] == '-') /* --option */ - fprintf (stderr, "%s: unrecognized option `--%s'\n", + fprintf (stderr, _("%s: unrecognized option `--%s'\n"), argv[0], nextchar); else /* +option or -option */ - fprintf (stderr, "%s: unrecognized option `%c%s'\n", + fprintf (stderr, _("%s: unrecognized option `%c%s'\n"), argv[0], argv[optind][0], nextchar); } nextchar = (char *) ""; @@ -588,7 +608,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) } } - /* Look at and handle the next option-character. */ + /* Look at and handle the next short option-character. */ { char c = *nextchar++; @@ -602,16 +622,13 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (opterr) { -#if 0 - if (c < 040 || c >= 0177) - fprintf (stderr, "%s: unrecognized option, character code 0%o\n", + if (posixly_correct) + /* 1003.2 specifies the format of this message. */ + fprintf (stderr, _("%s: illegal option -- %c\n"), argv[0], c); else - fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c); -#else - /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c); -#endif + fprintf (stderr, _("%s: invalid option -- %c\n"), + argv[0], c); } optopt = c; return '?'; @@ -627,7 +644,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) optind++; } else - optarg = 0; + optarg = NULL; nextchar = NULL; } else @@ -644,14 +661,10 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) { if (opterr) { -#if 0 - fprintf (stderr, "%s: option `-%c' requires an argument\n", - argv[0], c); -#else /* 1003.2 specifies the format of this message. */ - fprintf (stderr, "%s: option requires an argument -- %c\n", - argv[0], c); -#endif + fprintf (stderr, + _("%s: option requires an argument -- %c\n"), + argv[0], c); } optopt = c; if (optstring[0] == ':') diff --git a/gnu/usr.bin/sort/getopt.h b/gnu/usr.bin/sort/getopt.h index 45541f5..4ac33b7 100644 --- a/gnu/usr.bin/sort/getopt.h +++ b/gnu/usr.bin/sort/getopt.h @@ -1,5 +1,5 @@ /* Declarations for getopt. - Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc. + Copyright (C) 1989, 90, 91, 92, 93, 94 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 the @@ -76,7 +76,7 @@ extern int optopt; struct option { -#if __STDC__ +#if defined (__STDC__) && __STDC__ const char *name; #else char *name; @@ -94,15 +94,15 @@ struct option #define required_argument 1 #define optional_argument 2 -#if __STDC__ -#if defined(__GNU_LIBRARY__) +#if defined (__STDC__) && __STDC__ +#ifdef __GNU_LIBRARY__ /* Many other libraries have conflicting prototypes for getopt, with differences in the consts, in stdlib.h. To avoid compilation errors, only prototype getopt for the GNU C library. */ extern int getopt (int argc, char *const *argv, const char *shortopts); #else /* not __GNU_LIBRARY__ */ extern int getopt (); -#endif /* not __GNU_LIBRARY__ */ +#endif /* __GNU_LIBRARY__ */ extern int getopt_long (int argc, char *const *argv, const char *shortopts, const struct option *longopts, int *longind); extern int getopt_long_only (int argc, char *const *argv, @@ -120,7 +120,7 @@ extern int getopt_long (); extern int getopt_long_only (); extern int _getopt_internal (); -#endif /* not __STDC__ */ +#endif /* __STDC__ */ #ifdef __cplusplus } diff --git a/gnu/usr.bin/sort/getopt1.c b/gnu/usr.bin/sort/getopt1.c index f784b57..4580211 100644 --- a/gnu/usr.bin/sort/getopt1.c +++ b/gnu/usr.bin/sort/getopt1.c @@ -1,5 +1,5 @@ /* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987, 88, 89, 90, 91, 92, 1993 + Copyright (C) 1987, 88, 89, 90, 91, 92, 1993, 1994 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it @@ -17,19 +17,12 @@ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifdef HAVE_CONFIG_H -#if defined (emacs) || defined (CONFIG_BROKETS) -/* We use <config.h> instead of "config.h" so that a compilation - using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h - (which it would do because it found this file in $srcdir). */ #include <config.h> -#else -#include "config.h" -#endif #endif #include "getopt.h" -#ifndef __STDC__ +#if !defined (__STDC__) || !__STDC__ /* This is a separate conditional since some stdc systems reject `defined (const)'. */ #ifndef const diff --git a/gnu/usr.bin/sort/long-options.c b/gnu/usr.bin/sort/long-options.c index 03305aa..dd7a8ca 100644 --- a/gnu/usr.bin/sort/long-options.c +++ b/gnu/usr.bin/sort/long-options.c @@ -1,5 +1,5 @@ /* Utility to accept --help and --version options as unobtrusively as possible. - Copyright (C) 1993 Free Software Foundation, Inc. + Copyright (C) 1993, 1994 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 @@ -18,21 +18,11 @@ /* Jim Meyering (meyering@comco.com) */ #ifdef HAVE_CONFIG_H -#if defined (CONFIG_BROKETS) -/* We use <config.h> instead of "config.h" so that a compilation - using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h - (which it would do because it found this file in $srcdir). */ #include <config.h> -#else -#include "config.h" -#endif #endif #include <stdio.h> #include <getopt.h> -#include <sys/types.h> -#include "system.h" -#include "version.h" #include "long-options.h" static struct option const long_options[] = @@ -46,9 +36,11 @@ static struct option const long_options[] = Be careful not to gobble up `--'. */ void -parse_long_options (argc, argv, usage) +parse_long_options (argc, argv, command_name, version_string, usage) int argc; char **argv; + const char *command_name; + const char *version_string; void (*usage)(); { int c; @@ -67,12 +59,12 @@ parse_long_options (argc, argv, usage) switch (c) { case 'h': - usage (0); + (*usage) (0); case 'v': - printf ("%s\n", version_string); + printf ("%s - %s\n", command_name, version_string); exit (0); - + default: /* Don't process any other long-named options. */ break; diff --git a/gnu/usr.bin/sort/long-options.h b/gnu/usr.bin/sort/long-options.h index 9d1a9c7..986a52d 100644 --- a/gnu/usr.bin/sort/long-options.h +++ b/gnu/usr.bin/sort/long-options.h @@ -1 +1,10 @@ -void parse_long_options (); +#undef __P +#if defined (__STDC__) && __STDC__ +#define __P(args) args +#else +#define __P(args) () +#endif + +void + parse_long_options __P ((int _argc, char **_argv, const char *_command_name, + const char *_version_string, void (*_usage) (int))); diff --git a/gnu/usr.bin/sort/sort.1 b/gnu/usr.bin/sort/sort.1 index 3acc398..e9f4b1e 100644 --- a/gnu/usr.bin/sort/sort.1 +++ b/gnu/usr.bin/sort/sort.1 @@ -1,10 +1,13 @@ -.TH SORT 1L \" -*- nroff -*- +.TH SORT 1 "GNU Text Utilities" "FSF" \" -*- nroff -*- .SH NAME sort \- sort lines of text files .SH SYNOPSIS .B sort [\-cmus] [\-t separator] [\-o output-file] [\-T tempdir] [\-bdfiMnr] [+POS1 [\-POS2]] [\-k POS1[,POS2]] [file...] +.br +.B sort +{\-\-help,\-\-version} .SH DESCRIPTION This manual page documents the GNU version of @@ -187,6 +190,16 @@ option, the .I \-b option is taken to apply to both the \fI+pos\fP and the \fI\-pos\fP parts of a key specification. Keys may span multiple fields. +.PP +In addition, when GNU +.B sort +is invoked with exactly one argument, the following options are recognized: +.TP +.I "\-\-help" +Print a usage message on standard output and exit successfully. +.TP +.I "\-\-version" +Print version information on standard output then exit successfully. .SH COMPATIBILITY .PP Historical (BSD and System V) implementations of diff --git a/gnu/usr.bin/sort/sort.c b/gnu/usr.bin/sort/sort.c index 42e0b8e..dc3addb 100644 --- a/gnu/usr.bin/sort/sort.c +++ b/gnu/usr.bin/sort/sort.c @@ -1,5 +1,5 @@ /* sort - sort lines of text (with all kinds of options). - Copyright (C) 1988, 1991 Free Software Foundation + Copyright (C) 1988, 1991, 1992, 1993, 1994, 1995 Free Software Foundation 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 @@ -13,12 +13,14 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Written December 1988 by Mike Haertel. 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. */ +#include <config.h> + /* Get isblank from GNU libc. */ #define _GNU_SOURCE @@ -26,7 +28,12 @@ #include <signal.h> #include <stdio.h> #include "system.h" -#ifdef _POSIX_VERSION +#include "version.h" +#include "long-options.h" +#include "error.h" +#include "xstrtod.h" + +#ifdef HAVE_LIMITS_H #include <limits.h> #else #ifndef UCHAR_MAX @@ -39,16 +46,73 @@ char *realloc (); void free (); #endif -void error (); -static void usage (); - +/* Undefine, to avoid warning about redefinition on some systems. */ +#undef min #define min(a, b) ((a) < (b) ? (a) : (b)) + #define UCHAR_LIM (UCHAR_MAX + 1) #define UCHAR(c) ((unsigned char) (c)) +#ifndef DEFAULT_TMPDIR +#define DEFAULT_TMPDIR "/tmp" +#endif + /* The kind of blanks for '-b' to skip in various options. */ enum blanktype { bl_start, bl_end, bl_both }; +/* Lines are held in core as counted strings. */ +struct line +{ + char *text; /* Text of the line. */ + int length; /* Length not including final newline. */ + char *keybeg; /* Start of first key. */ + char *keylim; /* Limit of first key. */ +}; + +/* Arrays of lines. */ +struct lines +{ + struct line *lines; /* Dynamically allocated array of lines. */ + int used; /* Number of slots used. */ + int alloc; /* Number of slots allocated. */ + int limit; /* Max number of slots to allocate. */ +}; + +/* Input buffers. */ +struct buffer +{ + char *buf; /* Dynamically allocated buffer. */ + int used; /* Number of bytes used. */ + int alloc; /* Number of bytes allocated. */ + int left; /* Number of bytes left after line parsing. */ +}; + +struct keyfield +{ + int sword; /* Zero-origin 'word' to start at. */ + int schar; /* Additional characters to skip. */ + int skipsblanks; /* Skip leading white space at start. */ + int eword; /* Zero-origin first word after field. */ + int echar; /* Additional characters in field. */ + 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. 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. */ +}; + +struct month +{ + char *name; + int val; +}; + /* The name this program was run with. */ char *program_name; @@ -69,11 +133,7 @@ static char fold_toupper[UCHAR_LIM]; /* Table mapping 3-letter month names to integers. Alphabetic order allows binary search. */ -static struct month -{ - char *name; - int val; -} const monthtab[] = +static struct month const monthtab[] = { {"APR", 4}, {"AUG", 8}, @@ -94,17 +154,17 @@ static struct month /* Initial buffer size for in core sorting. Will not grow unless a line longer than this is seen. */ -static int sortalloc = 524288; +static int sortalloc = 512 * 1024; /* Initial buffer size for in core merge buffers. Bear in mind that up to NMERGE * mergealloc bytes may be allocated for merge buffers. */ -static int mergealloc = 16384; +static int mergealloc = 16 * 1024; /* Guess of average line length. */ static int linelength = 30; /* Maximum number of elements for the array(s) of struct line's, in bytes. */ -#define LINEALLOC 262144 +#define LINEALLOC (256 * 1024) /* Prefix for temporary file names. */ static char *temp_file_prefix; @@ -129,49 +189,55 @@ static int unique; /* Nonzero if any of the input files are the standard input. */ static int have_read_stdin; -/* Lines are held in core as counted strings. */ -struct line -{ - char *text; /* Text of the line. */ - int length; /* Length not including final newline. */ - char *keybeg; /* Start of first key. */ - char *keylim; /* Limit of first key. */ -}; - -/* Arrays of lines. */ -struct lines -{ - struct line *lines; /* Dynamically allocated array of lines. */ - int used; /* Number of slots used. */ - int alloc; /* Number of slots allocated. */ - int limit; /* Max number of slots to allocate. */ -}; - -/* Input buffers. */ -struct buffer -{ - char *buf; /* Dynamically allocated buffer. */ - int used; /* Number of bytes used. */ - int alloc; /* Number of bytes allocated. */ - int left; /* Number of bytes left after line parsing. */ -}; - /* Lists of key field comparisons to be tried. */ -static struct keyfield +static struct keyfield keyhead; + +static void +usage (int status) { - int sword; /* Zero-origin 'word' to start at. */ - int schar; /* Additional characters to skip. */ - int skipsblanks; /* Skip leading white space at start. */ - int eword; /* Zero-origin first word after field. */ - int echar; /* Additional characters in field. */ - 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 month; /* Flag for comparison by month name. */ - int reverse; /* Reverse the sense of comparison. */ - struct keyfield *next; /* Next keyfield to try. */ -} keyhead; + if (status != 0) + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + else + { + printf (_("\ +Usage: %s [OPTION]... [FILE]...\n\ +"), + program_name); + printf (_("\ +Write sorted concatenation of all FILE(s) to standard output.\n\ +\n\ + +POS1 [-POS2] start a key at POS1, end it before POS2\n\ + -M compare (unknown) < `JAN' < ... < `DEC', imply -b\n\ + -T DIRECT use DIRECT for temporary files, not $TMPDIR or %s\n\ + -b ignore leading blanks in sort fields or keys\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\ + -n compare according to string numerical value, imply -b\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\ + -t SEP use SEParator instead of non- to whitespace transition\n\ + -u with -c, check for strict ordering\n\ + -u with -m, only output the first of an equal sequence\n\ + --help display this help and exit\n\ + --version output version information and exit\n\ +\n\ +POS is F[.C][OPTS], where F is the field number and C the character\n\ +position in the field, both counted from zero. OPTS is made up of one\n\ +or more of Mbdfinr, this effectively disable global -Mbdfinr settings\n\ +for that key. If no key given, use the entire line as key. With no\n\ +FILE, or when FILE is -, read standard input.\n\ +") + , DEFAULT_TMPDIR); + } + exit (status); +} /* The list of temporary files. */ static struct tempnode @@ -183,7 +249,7 @@ static struct tempnode /* Clean up any remaining temporary files. */ static void -cleanup () +cleanup (void) { struct tempnode *node; @@ -193,16 +259,15 @@ cleanup () /* Allocate N bytes of memory dynamically, with error checking. */ -char * -xmalloc (n) - unsigned n; +static char * +xmalloc (unsigned int n) { char *p; p = malloc (n); if (p == 0) { - error (0, 0, "virtual memory exhausted"); + error (0, 0, _("virtual memory exhausted")); cleanup (); exit (2); } @@ -214,10 +279,8 @@ xmalloc (n) If P is NULL, run xmalloc. If N is 0, run free and return NULL. */ -char * -xrealloc (p, n) - char *p; - unsigned n; +static char * +xrealloc (char *p, unsigned int n) { if (p == 0) return xmalloc (n); @@ -229,7 +292,7 @@ xrealloc (p, n) p = realloc (p, n); if (p == 0) { - error (0, 0, "virtual memory exhausted"); + error (0, 0, _("virtual memory exhausted")); cleanup (); exit (2); } @@ -237,50 +300,81 @@ xrealloc (p, n) } static FILE * -xfopen (file, how) - char *file, *how; +xtmpfopen (const char *file) { - FILE *fp = strcmp (file, "-") ? fopen (file, how) : stdin; + FILE *fp; + int fd; - if (fp == 0) + fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd < 0 || (fp = fdopen (fd, "w")) == NULL) { error (0, errno, "%s", file); cleanup (); exit (2); } + + return fp; +} + +static FILE * +xfopen (const char *file, const char *how) +{ + FILE *fp; + + if (strcmp (file, "-") == 0) + { + fp = stdin; + } + else + { + if ((fp = fopen (file, how)) == NULL) + { + error (0, errno, "%s", file); + cleanup (); + exit (2); + } + } + if (fp == stdin) have_read_stdin = 1; return fp; } static void -xfclose (fp) - FILE *fp; +xfclose (FILE *fp) { - fflush (fp); - if (fp != stdin && fp != stdout) + if (fp == stdin) { - if (fclose (fp) != 0) + /* Allow reading stdin from tty more than once. */ + if (feof (fp)) + clearerr (fp); + } + else if (fp == stdout) + { + if (fflush (fp) != 0) { - error (0, errno, "error closing file"); + error (0, errno, _("flushing file")); cleanup (); exit (2); } } else - /* Allow reading stdin from tty more than once. */ - clearerr (fp); + { + if (fclose (fp) != 0) + { + error (0, errno, _("error closing file")); + cleanup (); + exit (2); + } + } } static void -xfwrite (buf, size, nelem, fp) - char *buf; - int size, nelem; - FILE *fp; +xfwrite (const char *buf, int size, int nelem, FILE *fp) { if (fwrite (buf, size, nelem, fp) != nelem) { - error (0, errno, "write error"); + error (0, errno, _("write error")); cleanup (); exit (2); } @@ -289,18 +383,25 @@ xfwrite (buf, size, nelem, fp) /* Return a name for a temporary file. */ static char * -tempname () +tempname (void) { - static int seq; + static unsigned int seq; int len = strlen (temp_file_prefix); - char *name = xmalloc (len + 16); - struct tempnode *node = - (struct tempnode *) xmalloc (sizeof (struct tempnode)); + char *name = xmalloc (len + 1 + sizeof ("sort") - 1 + 5 + 5 + 1); + struct tempnode *node; + + node = (struct tempnode *) xmalloc (sizeof (struct tempnode)); + sprintf (name, + "%s%ssort%5.5d%5.5d", + temp_file_prefix, + (len && temp_file_prefix[len - 1] != '/') ? "/" : "", + (unsigned int) getpid () & 0xffff, seq); + + /* Make sure that SEQ's value fits in 5 digits. */ + ++seq; + if (seq >= 100000) + seq = 0; - if (len && temp_file_prefix[len - 1] != '/') - sprintf (name, "%s/sort%5.5d%5.5d", temp_file_prefix, getpid (), ++seq); - else - sprintf (name, "%ssort%5.5d%5.5d", temp_file_prefix, getpid (), ++seq); node->name = name; node->next = temphead.next; temphead.next = node; @@ -311,8 +412,7 @@ tempname () remove it if it is found on the list. */ static void -zaptemp (name) - char *name; +zaptemp (char *name) { struct tempnode *node, *temp; @@ -332,7 +432,7 @@ zaptemp (name) /* Initialize the character class tables. */ static void -inittables () +inittables (void) { int i; @@ -356,9 +456,7 @@ inittables () /* Initialize BUF, allocating ALLOC bytes initially. */ static void -initbuf (buf, alloc) - struct buffer *buf; - int alloc; +initbuf (struct buffer *buf, int alloc) { buf->alloc = alloc; buf->buf = xmalloc (buf->alloc); @@ -371,13 +469,11 @@ initbuf (buf, alloc) of bytes buffered. */ static int -fillbuf (buf, fp) - struct buffer *buf; - FILE *fp; +fillbuf (struct buffer *buf, FILE *fp) { int cc; - bcopy (buf->buf + buf->used - buf->left, buf->buf, buf->left); + memmove (buf->buf, buf->buf + buf->used - buf->left, buf->left); buf->used = buf->left; while (!feof (fp) && (buf->used == 0 || !memchr (buf->buf, '\n', buf->used))) @@ -390,7 +486,7 @@ fillbuf (buf, fp) cc = fread (buf->buf + buf->used, 1, buf->alloc - buf->used, fp); if (ferror (fp)) { - error (0, errno, "read error"); + error (0, errno, _("read error")); cleanup (); exit (2); } @@ -415,10 +511,7 @@ fillbuf (buf, fp) for, ever. */ static void -initlines (lines, alloc, limit) - struct lines *lines; - int alloc; - int limit; +initlines (struct lines *lines, int alloc, int limit) { lines->alloc = alloc; lines->lines = (struct line *) xmalloc (lines->alloc * sizeof (struct line)); @@ -430,9 +523,7 @@ initlines (lines, alloc, limit) by KEY in LINE. */ static char * -begfield (line, key) - struct line *line; - struct keyfield *key; +begfield (const struct line *line, const struct keyfield *key) { register char *ptr = line->text, *lim = ptr + line->length; register int sword = key->sword, schar = key->schar; @@ -458,8 +549,10 @@ begfield (line, key) while (ptr < lim && blanks[UCHAR (*ptr)]) ++ptr; - while (ptr < lim && schar--) - ++ptr; + if (ptr + schar <= lim) + ptr += schar; + else + ptr = lim; return ptr; } @@ -468,19 +561,28 @@ begfield (line, key) in LINE specified by KEY. */ static char * -limfield (line, key) - struct line *line; - struct keyfield *key; +limfield (const struct line *line, const struct keyfield *key) { register char *ptr = line->text, *lim = ptr + line->length; register int eword = key->eword, echar = key->echar; + /* Note: from the POSIX spec: + The leading field separator itself is included in + a field when -t is not used. FIXME: move this comment up... */ + + /* Move PTR past EWORD fields or to one past the last byte on LINE, + whichever comes first. If there are more than EWORD fields, leave + PTR pointing at the beginning of the field having zero-based index, + EWORD. If a delimiter character was specified (via -t), then that + `beginning' is the first character following the delimiting TAB. + Otherwise, leave PTR pointing at the first `blank' character after + the preceding field. */ if (tab) while (ptr < lim && eword--) { while (ptr < lim && *ptr != tab) ++ptr; - if (ptr < lim && (eword || key->skipeblanks)) + if (ptr < lim && (eword || echar > 0)) ++ptr; } else @@ -492,23 +594,54 @@ limfield (line, key) ++ptr; } - if (key->skipeblanks) + /* Make LIM point to the end of (one byte past) the current field. */ + if (tab) + { + char *newlim; + newlim = memchr (ptr, tab, lim - ptr); + if (newlim) + lim = newlim; + } + else + { + char *newlim; + newlim = ptr; + while (newlim < lim && blanks[UCHAR (*newlim)]) + ++newlim; + while (newlim < lim && !blanks[UCHAR (*newlim)]) + ++newlim; + lim = newlim; + } + + /* If we're skipping leading blanks, don't start counting characters + until after skipping past any leading blanks. */ + if (key->skipsblanks) while (ptr < lim && blanks[UCHAR (*ptr)]) ++ptr; - while (ptr < lim && echar--) - ++ptr; + /* Advance PTR by ECHAR (if possible), but no further than LIM. */ + if (ptr + echar <= lim) + ptr += echar; + else + ptr = lim; return ptr; } +/* FIXME */ + +void +trim_trailing_blanks (const char *a_start, char **a_end) +{ + while (*a_end > a_start && blanks[UCHAR (*(*a_end - 1))]) + --(*a_end); +} + /* Find the lines in BUF, storing pointers and lengths in LINES. - Also replace newlines with NULs. */ + Also replace newlines in BUF with NULs. */ static void -findlines (buf, lines) - struct buffer *buf; - struct lines *lines; +findlines (struct buffer *buf, struct lines *lines) { register char *beg = buf->buf, *lim = buf->buf + buf->used, *ptr; struct keyfield *key = keyhead.next; @@ -553,6 +686,11 @@ findlines (buf, lines) ++beg; lines->lines[lines->used].keybeg = beg; } + if (key->skipeblanks) + { + trim_trailing_blanks (lines->lines[lines->used].keybeg, + &lines->lines[lines->used].keylim); + } } else { @@ -572,8 +710,7 @@ findlines (buf, lines) of the fraction. Strings not of this form are considered to be zero. */ static int -fraccompare (a, b) - register char *a, *b; +fraccompare (register const char *a, register const char *b) { register tmpa = UCHAR (*a), tmpb = UCHAR (*b); @@ -628,12 +765,12 @@ fraccompare (a, b) hideously fast. */ static int -numcompare (a, b) - register char *a, *b; +numcompare (register const char *a, register const char *b) { register int tmpa, tmpb, loga, logb, tmp; - tmpa = UCHAR (*a), tmpb = UCHAR (*b); + tmpa = UCHAR (*a); + tmpb = UCHAR (*b); while (blanks[tmpa]) tmpa = UCHAR (*++a); @@ -642,19 +779,30 @@ numcompare (a, b) if (tmpa == '-') { - tmpa = UCHAR (*++a); + do + tmpa = UCHAR (*++a); + while (tmpa == '0'); if (tmpb != '-') { - if (digits[tmpa] && digits[tmpb]) + if (tmpa == '.') + do + tmpa = UCHAR (*++a); + while (tmpa == '0'); + if (digits[tmpa]) + return -1; + while (tmpb == '0') + tmpb = UCHAR (*++b); + if (tmpb == '.') + do + tmpb = *++b; + while (tmpb == '0'); + if (digits[tmpb]) return -1; return 0; } - tmpb = UCHAR (*++b); - - while (tmpa == '0') - tmpa = UCHAR (*++a); - while (tmpb == '0') + do tmpb = UCHAR (*++b); + while (tmpb == '0'); while (tmpa == tmpb && digits[tmpa]) tmpa = UCHAR (*++a), tmpb = UCHAR (*++b); @@ -684,7 +832,22 @@ numcompare (a, b) } else if (tmpb == '-') { - if (digits[UCHAR (tmpa)] && digits[UCHAR (*++b)]) + do + tmpb = UCHAR (*++b); + while (tmpb == '0'); + if (tmpb == '.') + do + tmpb = *++b; + while (tmpb == '0'); + if (digits[tmpb]) + return 1; + while (tmpa == '0') + tmpa = UCHAR (*++a); + if (tmpa == '.') + do + tmpa = UCHAR (*++a); + while (tmpa == '0'); + if (digits[tmpa]) return 1; return 0; } @@ -723,13 +886,29 @@ numcompare (a, 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. */ static int -getmonth (s, len) - char *s; - int len; +getmonth (const char *s, int len) { char month[4]; register int i, lo = 0, hi = 12; @@ -758,8 +937,7 @@ getmonth (s, len) are no more keys or a difference is found. */ static int -keycompare (a, b) - struct line *a, *b; +keycompare (const struct line *a, const struct line *b) { register char *texta, *textb, *lima, *limb, *translate; register int *ignore; @@ -808,6 +986,16 @@ keycompare (a, b) if (lenb < 0) lenb = 0; + if (key->skipeblanks) + { + char *a_end = texta + lena; + char *b_end = textb + lenb; + trim_trailing_blanks (texta, &a_end); + trim_trailing_blanks (textb, &b_end); + lena = a_end - texta; + lenb = b_end - textb; + } + /* Actually compare the fields. */ if (key->numeric) { @@ -826,6 +1014,23 @@ keycompare (a, 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); @@ -834,38 +1039,64 @@ keycompare (a, b) continue; } else if (ignore && translate) - while (texta < lima && textb < limb) - { - while (texta < lima && ignore[UCHAR (*texta)]) - ++texta; - while (textb < limb && ignore[UCHAR (*textb)]) - ++textb; - if (texta < lima && textb < limb && - translate[UCHAR (*texta++)] != translate[UCHAR (*textb++)]) - { - diff = translate[UCHAR (*--texta)] - translate[UCHAR (*--textb)]; - break; - } - } + +#define CMP_WITH_IGNORE(A, B) \ + do \ + { \ + while (texta < lima && textb < limb) \ + { \ + while (texta < lima && ignore[UCHAR (*texta)]) \ + ++texta; \ + while (textb < limb && ignore[UCHAR (*textb)]) \ + ++textb; \ + if (texta < lima && textb < limb) \ + { \ + if ((A) != (B)) \ + { \ + diff = (A) - (B); \ + break; \ + } \ + ++texta; \ + ++textb; \ + } \ + \ + if (texta == lima && textb < limb && !ignore[UCHAR (*textb)]) \ + diff = -1; \ + else if (texta < lima && textb == limb \ + && !ignore[UCHAR (*texta)]) \ + diff = 1; \ + } \ + \ + if (diff == 0) \ + { \ + while (texta < lima && ignore[UCHAR (*texta)]) \ + ++texta; \ + while (textb < limb && ignore[UCHAR (*textb)]) \ + ++textb; \ + \ + if (texta == lima && textb < limb) \ + diff = -1; \ + else if (texta < lima && textb == limb) \ + diff = 1; \ + } \ + /* Relative lengths are meaningless if characters were ignored. \ + Handling this case here avoids what might be an invalid length \ + comparison below. */ \ + if (diff == 0 && texta == lima && textb == limb) \ + return 0; \ + } \ + while (0) + + CMP_WITH_IGNORE (translate[UCHAR (*texta)], translate[UCHAR (*textb)]); else if (ignore) - while (texta < lima && textb < limb) - { - while (texta < lima && ignore[UCHAR (*texta)]) - ++texta; - while (textb < limb && ignore[UCHAR (*textb)]) - ++textb; - if (texta < lima && textb < limb && *texta++ != *textb++) - { - diff = *--texta - *--textb; - break; - } - } + CMP_WITH_IGNORE (*texta, *textb); else if (translate) while (texta < lima && textb < limb) { if (translate[UCHAR (*texta++)] != translate[UCHAR (*textb++)]) { - diff = translate[UCHAR (*--texta)] - translate[UCHAR (*--textb)]; + diff = (translate[UCHAR (*--texta)] + - translate[UCHAR (*--textb)]); break; } } @@ -885,8 +1116,7 @@ keycompare (a, b) depending on whether A compares less than, equal to, or greater than B. */ static int -compare (a, b) - register struct line *a, *b; +compare (register const struct line *a, register const struct line *b) { int diff, tmpa, tmpb, mini; @@ -925,18 +1155,17 @@ compare (a, b) } /* Check that the lines read from the given FP come in order. Return - 1 if they do and 0 if there is a disorder. */ + 1 if they do and 0 if there is a disorder. + FIXME: return number of first out-of-order line if not sorted. */ static int -checkfp (fp) - FILE *fp; +checkfp (FILE *fp) { struct buffer buf; /* Input buffer. */ struct lines lines; /* Lines scanned from the buffer. */ struct line temp; /* Copy of previous line. */ int cc; /* Character count. */ - int cmp; /* Result of calling compare. */ - int alloc, i, success = 1; + int alloc, sorted = 1; initbuf (&buf, mergealloc); initlines (&lines, mergealloc / linelength + 1, @@ -945,64 +1174,69 @@ checkfp (fp) temp.text = xmalloc (alloc); cc = fillbuf (&buf, fp); + if (cc == 0) + goto finish; + findlines (&buf, &lines); - if (cc) - do - { - /* Compare each line in the buffer with its successor. */ - for (i = 0; i < lines.used - 1; ++i) - { - cmp = compare (&lines.lines[i], &lines.lines[i + 1]); - if ((unique && cmp >= 0) || (cmp > 0)) - { - success = 0; - goto finish; - } - } + while (1) + { + struct line *prev_line; /* Pointer to previous line. */ + int cmp; /* Result of calling compare. */ + int i; - /* Save the last line of the buffer and refill the buffer. */ - if (lines.lines[lines.used - 1].length > alloc) - { - while (lines.lines[lines.used - 1].length + 1 > alloc) - alloc *= 2; - temp.text = xrealloc (temp.text, alloc); - } - bcopy (lines.lines[lines.used - 1].text, temp.text, - lines.lines[lines.used - 1].length + 1); - temp.length = lines.lines[lines.used - 1].length; + /* Compare each line in the buffer with its successor. */ + for (i = 0; i < lines.used - 1; ++i) + { + cmp = compare (&lines.lines[i], &lines.lines[i + 1]); + if ((unique && cmp >= 0) || (cmp > 0)) + { + sorted = 0; + goto finish; + } + } - cc = fillbuf (&buf, fp); - if (cc) - { - findlines (&buf, &lines); - /* Make sure the line saved from the old buffer contents is - less than or equal to the first line of the new buffer. */ - cmp = compare (&temp, &lines.lines[0]); - if ((unique && cmp >= 0) || (cmp > 0)) - { - success = 0; - break; - } - } - } - while (cc); + /* Save the last line of the buffer and refill the buffer. */ + prev_line = lines.lines + (lines.used - 1); + if (prev_line->length > alloc) + { + while (prev_line->length + 1 > alloc) + alloc *= 2; + temp.text = xrealloc (temp.text, alloc); + } + memcpy (temp.text, prev_line->text, prev_line->length + 1); + temp.length = prev_line->length; + temp.keybeg = temp.text + (prev_line->keybeg - prev_line->text); + temp.keylim = temp.text + (prev_line->keylim - prev_line->text); + + cc = fillbuf (&buf, fp); + if (cc == 0) + break; + + findlines (&buf, &lines); + /* Make sure the line saved from the old buffer contents is + less than or equal to the first line of the new buffer. */ + cmp = compare (&temp, &lines.lines[0]); + if ((unique && cmp >= 0) || (cmp > 0)) + { + sorted = 0; + break; + } + } finish: xfclose (fp); free (buf.buf); free ((char *) lines.lines); free (temp.text); - return success; + return sorted; } /* Merge lines from FPS onto OFP. NFPS cannot be greater than NMERGE. Close FPS before returning. */ static void -mergefps (fps, nfps, ofp) - FILE *fps[], *ofp; - register int nfps; +mergefps (FILE **fps, register int nfps, FILE *ofp) { struct buffer buffer[NMERGE]; /* Input buffers for each file. */ struct lines lines[NMERGE]; /* Line tables for each buffer. */ @@ -1016,6 +1250,10 @@ mergefps (fps, nfps, ofp) output. */ register int i, j, t; +#ifdef lint /* Suppress `used before initialized' warning. */ + savealloc = 0; +#endif + /* Allocate space for a saved line if necessary. */ if (unique) { @@ -1059,7 +1297,7 @@ mergefps (fps, nfps, ofp) /* Repeatedly output the smallest line until no input remains. */ while (nfps) { - /* If uniqified output is turned out, output only the first of + /* If uniqified output is turned on, output only the first of an identical series of lines. */ if (unique) { @@ -1078,7 +1316,7 @@ mergefps (fps, nfps, ofp) saved.text = xrealloc (saved.text, savealloc); } saved.length = lines[ord[0]].lines[cur[ord[0]]].length; - bcopy (lines[ord[0]].lines[cur[ord[0]]].text, saved.text, + memcpy (saved.text, lines[ord[0]].lines[cur[ord[0]]].text, saved.length + 1); if (lines[ord[0]].lines[cur[ord[0]]].keybeg != NULL) { @@ -1160,9 +1398,7 @@ mergefps (fps, nfps, ofp) /* Sort the array LINES with NLINES members, using TEMP for temporary space. */ static void -sortlines (lines, nlines, temp) - struct line *lines, *temp; - int nlines; +sortlines (struct line *lines, int nlines, struct line *temp) { register struct line *lo, *hi, *t; register int nlo, nhi; @@ -1203,9 +1439,7 @@ sortlines (lines, nlines, temp) Return a count of disordered files. */ static int -check (files, nfiles) - char *files[]; - int nfiles; +check (char **files, int nfiles) { int i, disorders = 0; FILE *fp; @@ -1215,7 +1449,7 @@ check (files, nfiles) fp = xfopen (files[i], "r"); if (!checkfp (fp)) { - printf ("%s: disorder on %s\n", program_name, files[i]); + fprintf (stderr, _("%s: disorder on %s\n"), program_name, files[i]); ++disorders; } } @@ -1225,10 +1459,7 @@ check (files, nfiles) /* Merge NFILES FILES onto OFP. */ static void -merge (files, nfiles, ofp) - char *files[]; - int nfiles; - FILE *ofp; +merge (char **files, int nfiles, FILE *ofp) { int i, j, t; char *temp; @@ -1241,7 +1472,7 @@ merge (files, nfiles, ofp) { for (j = 0; j < NMERGE; ++j) fps[j] = xfopen (files[i * NMERGE + j], "r"); - tfp = xfopen (temp = tempname (), "w"); + tfp = xtmpfopen (temp = tempname ()); mergefps (fps, NMERGE, tfp); xfclose (tfp); for (j = 0; j < NMERGE; ++j) @@ -1250,7 +1481,7 @@ merge (files, nfiles, ofp) } for (j = 0; j < nfiles % NMERGE; ++j) fps[j] = xfopen (files[i * NMERGE + j], "r"); - tfp = xfopen (temp = tempname (), "w"); + tfp = xtmpfopen (temp = tempname ()); mergefps (fps, nfiles % NMERGE, tfp); xfclose (tfp); for (j = 0; j < nfiles % NMERGE; ++j) @@ -1269,10 +1500,7 @@ merge (files, nfiles, ofp) /* Sort NFILES FILES onto OFP. */ static void -sort (files, nfiles, ofp) - char **files; - int nfiles; - FILE *ofp; +sort (char **files, int nfiles, FILE *ofp) { struct buffer buf; struct lines lines; @@ -1280,7 +1508,7 @@ sort (files, nfiles, ofp) int i, ntmp; FILE *fp, *tfp; struct tempnode *node; - int ntemp = 0; + int n_temp_files = 0; char **tempfiles; initbuf (&buf, sortalloc); @@ -1303,12 +1531,12 @@ sort (files, nfiles, ofp) xrealloc ((char *) tmp, ntmp * sizeof (struct line)); } sortlines (lines.lines, lines.used, tmp); - if (feof (fp) && !nfiles && !ntemp && !buf.left) + if (feof (fp) && !nfiles && !n_temp_files && !buf.left) tfp = ofp; else { - ++ntemp; - tfp = xfopen (tempname (), "w"); + ++n_temp_files; + tfp = xtmpfopen (tempname ()); } for (i = 0; i < lines.used; ++i) if (!unique || i == 0 @@ -1327,13 +1555,13 @@ sort (files, nfiles, ofp) free ((char *) lines.lines); free ((char *) tmp); - if (ntemp) + if (n_temp_files) { - tempfiles = (char **) xmalloc (ntemp * sizeof (char *)); - i = ntemp; + tempfiles = (char **) xmalloc (n_temp_files * sizeof (char *)); + i = n_temp_files; for (node = temphead.next; i > 0; node = node->next) tempfiles[--i] = node->name; - merge (tempfiles, ntemp, ofp); + merge (tempfiles, n_temp_files, ofp); free ((char *) tempfiles); } } @@ -1341,8 +1569,7 @@ sort (files, nfiles, ofp) /* Insert key KEY at the end of the list (`keyhead'). */ static void -insertkey (key) - struct keyfield *key; +insertkey (struct keyfield *key) { struct keyfield *k = &keyhead; @@ -1353,28 +1580,26 @@ insertkey (key) } static void -badfieldspec (s) - char *s; +badfieldspec (const char *s) { - error (2, 0, "invalid field specification `%s'", s); + error (2, 0, _("invalid field specification `%s'"), s); } /* Handle interrupts and hangups. */ static void -sighandler (sig) - int sig; +sighandler (int sig) { -#ifdef _POSIX_VERSION +#ifdef SA_INTERRUPT struct sigaction sigact; sigact.sa_handler = SIG_DFL; sigemptyset (&sigact.sa_mask); sigact.sa_flags = 0; sigaction (sig, &sigact, NULL); -#else /* !_POSIX_VERSION */ +#else /* !SA_INTERRUPT */ signal (sig, SIG_DFL); -#endif /* _POSIX_VERSION */ +#endif /* SA_INTERRUPT */ cleanup (); kill (getpid (), sig); } @@ -1385,10 +1610,8 @@ sighandler (sig) BLANKTYPE is the kind of blanks that 'b' should skip. */ static char * -set_ordering (s, key, blanktype) - register char *s; - struct keyfield *key; - enum blanktype blanktype; +set_ordering (register const char *s, struct keyfield *key, + enum blanktype blanktype) { while (*s) { @@ -1406,11 +1629,9 @@ set_ordering (s, key, blanktype) 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; @@ -1419,22 +1640,24 @@ set_ordering (s, key, blanktype) break; case 'n': key->numeric = 1; + if (blanktype == bl_start || blanktype == bl_both) + key->skipsblanks = 1; + if (blanktype == bl_end || blanktype == bl_both) + key->skipeblanks = 1; break; case 'r': key->reverse = 1; break; default: - return s; + return (char *) s; } ++s; } - return s; + return (char *) s; } void -main (argc, argv) - int argc; - char *argv[]; +main (int argc, char **argv) { struct keyfield *key = NULL, gkey; char *s; @@ -1442,19 +1665,22 @@ main (argc, argv) int checkonly = 0, mergeonly = 0, nfiles = 0; char *minus = "-", *outfile = minus, **files, *tmp; FILE *ofp; -#ifdef _POSIX_VERSION +#ifdef SA_INTERRUPT struct sigaction oldact, newact; -#endif /* _POSIX_VERSION */ +#endif /* SA_INTERRUPT */ program_name = argv[0]; + + parse_long_options (argc, argv, "sort", version_string, usage); + have_read_stdin = 0; inittables (); temp_file_prefix = getenv ("TMPDIR"); if (temp_file_prefix == NULL) - temp_file_prefix = "/tmp"; + temp_file_prefix = DEFAULT_TMPDIR; -#ifdef _POSIX_VERSION +#ifdef SA_INTERRUPT newact.sa_handler = sighandler; sigemptyset (&newact.sa_mask); newact.sa_flags = 0; @@ -1471,7 +1697,7 @@ main (argc, argv) sigaction (SIGTERM, NULL, &oldact); if (oldact.sa_handler != SIG_IGN) sigaction (SIGTERM, &newact, NULL); -#else /* !_POSIX_VERSION */ +#else /* !SA_INTERRUPT */ if (signal (SIGINT, SIG_IGN) != SIG_IGN) signal (SIGINT, sighandler); if (signal (SIGHUP, SIG_IGN) != SIG_IGN) @@ -1480,12 +1706,12 @@ main (argc, argv) signal (SIGPIPE, sighandler); if (signal (SIGTERM, SIG_IGN) != SIG_IGN) signal (SIGTERM, sighandler); -#endif /* !_POSIX_VERSION */ +#endif /* !SA_INTERRUPT */ 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); @@ -1501,9 +1727,9 @@ main (argc, 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)]) + if (! (digits[UCHAR (*s)] || (*s == '.' && digits[UCHAR (s[1])]))) badfieldspec (argv[i]); for (t = 0; digits[UCHAR (*s)]; ++s) t = 10 * t + *s - '0'; @@ -1525,10 +1751,10 @@ main (argc, argv) else if (argv[i][0] == '-' && argv[i][1]) { s = argv[i] + 1; - if (digits[UCHAR (*s)]) + if (digits[UCHAR (*s)] || (*s == '.' && digits[UCHAR (s[1])])) { if (!key) - usage (); + usage (2); for (t = 0; digits[UCHAR (*s)]; ++s) t = t * 10 + *s - '0'; t2 = 0; @@ -1560,7 +1786,7 @@ main (argc, argv) else { if (i == argc - 1) - error (2, 0, "option `-k' requires an argument"); + error (2, 0, _("option `-k' requires an argument")); else s = argv[++i]; } @@ -1578,15 +1804,34 @@ main (argc, argv) badfieldspec (argv[i]); for (t = 0; digits[UCHAR (*s)]; ++s) t = 10 * t + *s - '0'; - if (t) - t--; + if (t == 0) + { + /* Provoke with `sort -k0' */ + error (0, 0, _("the starting field number argument \ +to the `-k' option must be positive")); + badfieldspec (argv[i]); + } + --t; t2 = 0; if (*s == '.') { + if (!digits[UCHAR (s[1])]) + { + /* Provoke with `sort -k1.' */ + error (0, 0, _("starting field spec has `.' but \ +lacks following character offset")); + badfieldspec (argv[i]); + } for (++s; digits[UCHAR (*s)]; ++s) t2 = 10 * t2 + *s - '0'; - if (t2) - t2--; + if (t2 == 0) + { + /* Provoke with `sort -k1.0' */ + error (0, 0, _("starting field character offset \ +argument to the `-k' option\nmust be positive")); + badfieldspec (argv[i]); + } + --t2; } if (t2 || t) { @@ -1596,20 +1841,52 @@ main (argc, argv) else key->sword = -1; s = set_ordering (s, key, bl_start); - if (*s && *s != ',') + if (*s == 0) + { + key->eword = -1; + key->echar = 0; + } + else if (*s != ',') badfieldspec (argv[i]); - else if (*s++) + else if (*s == ',') { + /* Skip over comma. */ + ++s; + if (*s == 0) + { + /* Provoke with `sort -k1,' */ + error (0, 0, _("field specification has `,' but \ +lacks following field spec")); + badfieldspec (argv[i]); + } /* Get POS2. */ for (t = 0; digits[UCHAR (*s)]; ++s) t = t * 10 + *s - '0'; + if (t == 0) + { + /* Provoke with `sort -k1,0' */ + error (0, 0, _("ending field number argument \ +to the `-k' option must be positive")); + badfieldspec (argv[i]); + } + --t; t2 = 0; if (*s == '.') { + if (!digits[UCHAR (s[1])]) + { + /* Provoke with `sort -k1,1.' */ + error (0, 0, _("ending field spec has `.' \ +but lacks following character offset")); + badfieldspec (argv[i]); + } for (++s; digits[UCHAR (*s)]; ++s) t2 = t2 * 10 + *s - '0'; - if (t2) - t--; + } + else + { + /* `-k 2,3' is equivalent to `+1 -3'. */ + ++t; } key->eword = t; key->echar = t2; @@ -1629,7 +1906,7 @@ main (argc, argv) else { if (i == argc - 1) - error (2, 0, "option `-o' requires an argument"); + error (2, 0, _("option `-o' requires an argument")); else outfile = argv[++i]; } @@ -1646,26 +1923,31 @@ main (argc, argv) goto outer; } else - error (2, 0, "option `-t' requires an argument"); + error (2, 0, _("option `-t' requires an argument")); break; case 'T': if (s[1]) temp_file_prefix = ++s; - else if (i < argc - 1) + else { - temp_file_prefix = argv[++i]; - goto outer; + if (i < argc - 1) + temp_file_prefix = argv[++i]; + else + error (2, 0, _("option `-T' requires an argument")); } - else - error (2, 0, "option `-T' requires an argument"); - break; + goto outer; + /* break; */ case 'u': unique = 1; break; + case 'y': + /* Accept and ignore e.g. -y0 for compatibility with + Solaris 2. */ + goto outer; default: - fprintf (stderr, "%s: unrecognized option `-%c'\n", + fprintf (stderr, _("%s: unrecognized option `-%c'\n"), argv[0], *s); - usage (); + usage (2); } if (*s) ++s; @@ -1684,7 +1966,8 @@ main (argc, 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; @@ -1692,11 +1975,13 @@ main (argc, 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; @@ -1711,32 +1996,61 @@ main (argc, argv) if (strcmp (outfile, "-")) { - for (i = 0; i < nfiles; ++i) - if (!strcmp (outfile, files[i])) - break; - if (i == nfiles) - ofp = xfopen (outfile, "w"); - else + struct stat outstat; + if (stat (outfile, &outstat) == 0) { - char buf[8192]; - FILE *fp = xfopen (outfile, "r"); - int cc; - - tmp = tempname (); - ofp = xfopen (tmp, "w"); - while ((cc = fread (buf, 1, sizeof buf, fp)) > 0) - xfwrite (buf, 1, cc, ofp); - if (ferror (fp)) + /* The following code prevents a race condition when + people use the brain dead shell programming idiom: + cat file | sort -o file + This feature is provided for historical compatibility, + but we strongly discourage ever relying on this in + new shell programs. */ + + /* Temporarily copy each input file that might be another name + for the output file. When in doubt (e.g. a pipe), copy. */ + for (i = 0; i < nfiles; ++i) { - error (0, errno, "%s", outfile); - cleanup (); - exit (2); + char buf[8192]; + FILE *fp; + int cc; + + if (S_ISREG (outstat.st_mode) && strcmp (outfile, files[i])) + { + struct stat instat; + if ((strcmp (files[i], "-") + ? stat (files[i], &instat) + : fstat (fileno (stdin), &instat)) != 0) + { + error (0, errno, "%s", files[i]); + cleanup (); + exit (2); + } + if (S_ISREG (instat.st_mode) + && (instat.st_ino != outstat.st_ino + || instat.st_dev != outstat.st_dev)) + { + /* We know the files are distinct. */ + continue; + } + } + + fp = xfopen (files[i], "r"); + tmp = tempname (); + ofp = xtmpfopen (tmp); + while ((cc = fread (buf, 1, sizeof buf, fp)) > 0) + xfwrite (buf, 1, cc, ofp); + if (ferror (fp)) + { + error (0, errno, "%s", files[i]); + cleanup (); + exit (2); + } + xfclose (ofp); + xfclose (fp); + files[i] = tmp; } - xfclose (ofp); - xfclose (fp); - files[i] = tmp; - ofp = xfopen (outfile, "w"); } + ofp = xfopen (outfile, "w"); } else ofp = stdout; @@ -1753,22 +2067,12 @@ main (argc, argv) Solaris, Ultrix, and Irix. This premature fflush makes the output reappear. --karl@cs.umb.edu */ if (fflush (ofp) < 0) - error (1, errno, "fflush", outfile); + error (1, errno, _("%s: write error"), outfile); if (have_read_stdin && fclose (stdin) == EOF) - error (1, errno, "-"); + error (1, errno, outfile); if (ferror (stdout) || fclose (stdout) == EOF) - error (1, errno, "write error"); + error (1, errno, _("%s: write error"), outfile); exit (0); } - -static void -usage () -{ - fprintf (stderr, "\ -Usage: %s [-cmus] [-t separator] [-o output-file] [-T tempdir] [-bdfiMnr]\n\ - [+POS1 [-POS2]] [-k POS1[,POS2]] [file...]\n", - program_name); - exit (2); -} diff --git a/gnu/usr.bin/sort/system.h b/gnu/usr.bin/sort/system.h index 2e03ea8..bfb19e1 100644 --- a/gnu/usr.bin/sort/system.h +++ b/gnu/usr.bin/sort/system.h @@ -13,14 +13,25 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Include sys/types.h before this file. */ #include <sys/stat.h> -#ifndef S_ISREG /* Doesn't have POSIX.1 stat stuff. */ -#define mode_t unsigned short -#endif + +#ifdef STAT_MACROS_BROKEN +#undef S_ISBLK +#undef S_ISCHR +#undef S_ISDIR +#undef S_ISFIFO +#undef S_ISLNK +#undef S_ISMPB +#undef S_ISMPC +#undef S_ISNWK +#undef S_ISREG +#undef S_ISSOCK +#endif /* STAT_MACROS_BROKEN. */ + #if !defined(S_ISBLK) && defined(S_IFBLK) #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) #endif @@ -56,42 +67,56 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif + #ifndef _POSIX_VERSION off_t lseek (); #endif -#if defined(HAVE_STRING_H) || defined(STDC_HEADERS) -#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H) -#include <memory.h> -#endif -#include <string.h> -#ifndef index -#define index strchr +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 #endif -#ifndef rindex -#define rindex strrchr -#endif -/* Don't define bcopy; we need one that can handle overlaps. */ -#ifndef bzero -#define bzero(s, n) memset ((s), 0, (n)) + +#ifndef STDOUT_FILENO +#define STDOUT_FILENO 1 #endif -#ifndef bcmp -#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n)) + +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 #endif + +/* Don't use bcopy! Use memmove if source and destination may overlap, + memcpy otherwise. */ + +#ifdef HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include <memory.h> +# endif +# include <string.h> #else -#include <strings.h> +# include <strings.h> char *memchr (); #endif #include <errno.h> +#ifndef errno +extern int errno; +#endif + #ifdef STDC_HEADERS #include <stdlib.h> #else char *getenv (); -extern int errno; #endif -#if defined(HAVE_FCNTL_H) || defined(_POSIX_VERSION) +#ifndef EXIT_FAILURE +# define EXIT_FAILURE 1 +#endif + +#ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +#endif + +#ifdef HAVE_FCNTL_H #include <fcntl.h> #else #include <sys/file.h> @@ -139,28 +164,42 @@ extern int errno; #include <ctype.h> -#ifndef isascii -#define isascii(c) 1 +#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII)) +#define ISASCII(c) 1 +#else +#define ISASCII(c) isascii(c) #endif #ifdef isblank -#define ISBLANK(c) (isascii (c) && isblank (c)) +#define ISBLANK(c) (ISASCII (c) && isblank (c)) #else #define ISBLANK(c) ((c) == ' ' || (c) == '\t') #endif #ifdef isgraph -#define ISGRAPH(c) (isascii (c) && isgraph (c)) +#define ISGRAPH(c) (ISASCII (c) && isgraph (c)) #else -#define ISGRAPH(c) (isascii (c) && isprint (c) && !isspace (c)) -#endif - -#define ISPRINT(c) (isascii (c) && isprint (c)) -#define ISDIGIT(c) (isascii (c) && isdigit (c)) -#define ISALNUM(c) (isascii (c) && isalnum (c)) -#define ISALPHA(c) (isascii (c) && isalpha (c)) -#define ISCNTRL(c) (isascii (c) && iscntrl (c)) -#define ISLOWER(c) (isascii (c) && islower (c)) -#define ISPUNCT(c) (isascii (c) && ispunct (c)) -#define ISSPACE(c) (isascii (c) && isspace (c)) -#define ISUPPER(c) (isascii (c) && isupper (c)) -#define ISXDIGIT(c) (isascii (c) && isxdigit (c)) +#define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) +#endif + +#define ISPRINT(c) (ISASCII (c) && isprint (c)) +#define ISDIGIT(c) (ISASCII (c) && isdigit (c)) +#define ISALNUM(c) (ISASCII (c) && isalnum (c)) +#define ISALPHA(c) (ISASCII (c) && isalpha (c)) +#define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) +#define ISLOWER(c) (ISASCII (c) && islower (c)) +#define ISPUNCT(c) (ISASCII (c) && ispunct (c)) +#define ISSPACE(c) (ISASCII (c) && isspace (c)) +#define ISUPPER(c) (ISASCII (c) && isupper (c)) +#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) + +/* Disable string localization for the time being. */ +#undef _ +#define _(String) String + +#ifndef __P +# if PROTOTYPES +# define __P(Args) Args +# else +# define __P(Args) () +# endif +#endif diff --git a/gnu/usr.bin/sort/version.c b/gnu/usr.bin/sort/version.c index 64c62b19..0289fcb 100644 --- a/gnu/usr.bin/sort/version.c +++ b/gnu/usr.bin/sort/version.c @@ -1,13 +1,3 @@ -#ifdef HAVE_CONFIG_H -#if defined (CONFIG_BROKETS) -/* We use <config.h> instead of "config.h" so that a compilation - using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h - (which it would do because it found this file in $srcdir). */ #include <config.h> -#else -#include "config.h" -#endif -#endif - #include "version.h" -const char *version_string = "GNU textutils 1.9"; +const char *version_string = "GNU textutils 1.14"; diff --git a/gnu/usr.bin/sort/xstrtod.c b/gnu/usr.bin/sort/xstrtod.c new file mode 100644 index 0000000..838c5c4 --- /dev/null +++ b/gnu/usr.bin/sort/xstrtod.c @@ -0,0 +1,48 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef STDC_HEADERS +#include <stdlib.h> +#else +double strtod (); +#endif + +#include <errno.h> +#include <stdio.h> +#include <limits.h> +#include <ctype.h> +#include "xstrtod.h" + +int +xstrtod (str, ptr, result) + const char *str; + const char **ptr; + double *result; +{ + double val; + char *terminator; + int fail; + + fail = 0; + errno = 0; + val = strtod (str, &terminator); + + /* Having a non-zero terminator is an error only when PTR is NULL. */ + if (terminator == str || (ptr == NULL && *terminator != '\0')) + fail = 1; + else + { + /* Allow underflow (in which case strtod returns zero), + but flag overflow as an error. */ + if (val != 0.0 && errno == ERANGE) + fail = 1; + } + + if (ptr != NULL) + *ptr = terminator; + + *result = val; + return fail; +} + diff --git a/gnu/usr.bin/sort/xstrtod.h b/gnu/usr.bin/sort/xstrtod.h new file mode 100644 index 0000000..15b85f4 --- /dev/null +++ b/gnu/usr.bin/sort/xstrtod.h @@ -0,0 +1,15 @@ +#ifndef XSTRTOD_H +#define XSTRTOD_H 1 + +#ifndef __P +# if defined (__GNUC__) || (defined (__STDC__) && __STDC__) +# define __P(args) args +# else +# define __P(args) () +# endif /* GCC. */ +#endif /* Not __P. */ + +int + xstrtod __P ((const char *str, const char **ptr, double *result)); + +#endif /* XSTRTOD_H */ |