summaryrefslogtreecommitdiffstats
path: root/gnu/usr.bin/sort/sort.c
diff options
context:
space:
mode:
Diffstat (limited to 'gnu/usr.bin/sort/sort.c')
-rw-r--r--gnu/usr.bin/sort/sort.c1003
1 files changed, 380 insertions, 623 deletions
diff --git a/gnu/usr.bin/sort/sort.c b/gnu/usr.bin/sort/sort.c
index dc3addb..a6c7539 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, 1992, 1993, 1994, 1995 Free Software Foundation
+ Copyright (C) 1988, 1991 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,13 +13,22 @@
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.
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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. */
+#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
/* Get isblank from GNU libc. */
#define _GNU_SOURCE
@@ -27,13 +36,13 @@
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
+#ifdef __FreeBSD__
+#include <locale.h>
+#endif
#include "system.h"
-#include "version.h"
#include "long-options.h"
-#include "error.h"
-#include "xstrtod.h"
-#ifdef HAVE_LIMITS_H
+#ifdef _POSIX_VERSION
#include <limits.h>
#else
#ifndef UCHAR_MAX
@@ -46,73 +55,16 @@ char *realloc ();
void free ();
#endif
-/* Undefine, to avoid warning about redefinition on some systems. */
-#undef min
-#define min(a, b) ((a) < (b) ? (a) : (b))
+void error ();
+static void usage ();
+#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;
@@ -133,7 +85,11 @@ static char fold_toupper[UCHAR_LIM];
/* Table mapping 3-letter month names to integers.
Alphabetic order allows binary search. */
-static struct month const monthtab[] =
+static struct month
+{
+ char *name;
+ int val;
+} const monthtab[] =
{
{"APR", 4},
{"AUG", 8},
@@ -154,17 +110,17 @@ static struct month const monthtab[] =
/* Initial buffer size for in core sorting. Will not grow unless a
line longer than this is seen. */
-static int sortalloc = 512 * 1024;
+static int sortalloc = 524288;
/* 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 = 16 * 1024;
+static int mergealloc = 16384;
/* 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 (256 * 1024)
+#define LINEALLOC 262144
/* Prefix for temporary file names. */
static char *temp_file_prefix;
@@ -189,55 +145,49 @@ static int unique;
/* Nonzero if any of the input files are the standard input. */
static int have_read_stdin;
-/* Lists of key field comparisons to be tried. */
-static struct keyfield keyhead;
+/* 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. */
+};
-static void
-usage (int status)
+/* Arrays of lines. */
+struct lines
{
- 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);
-}
+ 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
+{
+ 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;
/* The list of temporary files. */
static struct tempnode
@@ -249,7 +199,7 @@ static struct tempnode
/* Clean up any remaining temporary files. */
static void
-cleanup (void)
+cleanup ()
{
struct tempnode *node;
@@ -259,15 +209,16 @@ cleanup (void)
/* Allocate N bytes of memory dynamically, with error checking. */
-static char *
-xmalloc (unsigned int n)
+char *
+xmalloc (n)
+ unsigned n;
{
char *p;
p = malloc (n);
if (p == 0)
{
- error (0, 0, _("virtual memory exhausted"));
+ error (0, 0, "virtual memory exhausted");
cleanup ();
exit (2);
}
@@ -279,8 +230,10 @@ xmalloc (unsigned int n)
If P is NULL, run xmalloc.
If N is 0, run free and return NULL. */
-static char *
-xrealloc (char *p, unsigned int n)
+char *
+xrealloc (p, n)
+ char *p;
+ unsigned n;
{
if (p == 0)
return xmalloc (n);
@@ -292,7 +245,7 @@ xrealloc (char *p, unsigned int n)
p = realloc (p, n);
if (p == 0)
{
- error (0, 0, _("virtual memory exhausted"));
+ error (0, 0, "virtual memory exhausted");
cleanup ();
exit (2);
}
@@ -300,81 +253,50 @@ xrealloc (char *p, unsigned int n)
}
static FILE *
-xtmpfopen (const char *file)
+xfopen (file, how)
+ char *file, *how;
{
- FILE *fp;
- int fd;
+ FILE *fp = strcmp (file, "-") ? fopen (file, how) : stdin;
- fd = open (file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
- if (fd < 0 || (fp = fdopen (fd, "w")) == NULL)
+ if (fp == 0)
{
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 (FILE *fp)
+xfclose (fp)
+ FILE *fp;
{
- if (fp == stdin)
- {
- /* Allow reading stdin from tty more than once. */
- if (feof (fp))
- clearerr (fp);
- }
- else if (fp == stdout)
- {
- if (fflush (fp) != 0)
- {
- error (0, errno, _("flushing file"));
- cleanup ();
- exit (2);
- }
- }
- else
+ fflush (fp);
+ if (fp != stdin && fp != stdout)
{
if (fclose (fp) != 0)
{
- error (0, errno, _("error closing file"));
+ error (0, errno, "error closing file");
cleanup ();
exit (2);
}
}
+ else
+ /* Allow reading stdin from tty more than once. */
+ clearerr (fp);
}
static void
-xfwrite (const char *buf, int size, int nelem, FILE *fp)
+xfwrite (buf, size, nelem, fp)
+ char *buf;
+ int size, nelem;
+ FILE *fp;
{
if (fwrite (buf, size, nelem, fp) != nelem)
{
- error (0, errno, _("write error"));
+ error (0, errno, "write error");
cleanup ();
exit (2);
}
@@ -383,25 +305,18 @@ xfwrite (const char *buf, int size, int nelem, FILE *fp)
/* Return a name for a temporary file. */
static char *
-tempname (void)
+tempname ()
{
- static unsigned int seq;
+ static int seq;
int len = strlen (temp_file_prefix);
- 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;
+ char *name = xmalloc (len + 16);
+ struct tempnode *node =
+ (struct tempnode *) xmalloc (sizeof (struct tempnode));
+ 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;
@@ -412,7 +327,8 @@ tempname (void)
remove it if it is found on the list. */
static void
-zaptemp (char *name)
+zaptemp (name)
+ char *name;
{
struct tempnode *node, *temp;
@@ -432,7 +348,7 @@ zaptemp (char *name)
/* Initialize the character class tables. */
static void
-inittables (void)
+inittables ()
{
int i;
@@ -456,7 +372,9 @@ inittables (void)
/* Initialize BUF, allocating ALLOC bytes initially. */
static void
-initbuf (struct buffer *buf, int alloc)
+initbuf (buf, alloc)
+ struct buffer *buf;
+ int alloc;
{
buf->alloc = alloc;
buf->buf = xmalloc (buf->alloc);
@@ -469,11 +387,13 @@ initbuf (struct buffer *buf, int alloc)
of bytes buffered. */
static int
-fillbuf (struct buffer *buf, FILE *fp)
+fillbuf (buf, fp)
+ struct buffer *buf;
+ FILE *fp;
{
int cc;
- memmove (buf->buf, buf->buf + buf->used - buf->left, buf->left);
+ bcopy (buf->buf + buf->used - buf->left, buf->buf, buf->left);
buf->used = buf->left;
while (!feof (fp) && (buf->used == 0 || !memchr (buf->buf, '\n', buf->used)))
@@ -486,7 +406,7 @@ fillbuf (struct buffer *buf, FILE *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);
}
@@ -511,7 +431,10 @@ fillbuf (struct buffer *buf, FILE *fp)
for, ever. */
static void
-initlines (struct lines *lines, int alloc, int limit)
+initlines (lines, alloc, limit)
+ struct lines *lines;
+ int alloc;
+ int limit;
{
lines->alloc = alloc;
lines->lines = (struct line *) xmalloc (lines->alloc * sizeof (struct line));
@@ -523,7 +446,9 @@ initlines (struct lines *lines, int alloc, int limit)
by KEY in LINE. */
static char *
-begfield (const struct line *line, const struct keyfield *key)
+begfield (line, key)
+ struct line *line;
+ struct keyfield *key;
{
register char *ptr = line->text, *lim = ptr + line->length;
register int sword = key->sword, schar = key->schar;
@@ -549,10 +474,8 @@ begfield (const struct line *line, const struct keyfield *key)
while (ptr < lim && blanks[UCHAR (*ptr)])
++ptr;
- if (ptr + schar <= lim)
- ptr += schar;
- else
- ptr = lim;
+ while (ptr < lim && schar--)
+ ++ptr;
return ptr;
}
@@ -561,28 +484,19 @@ begfield (const struct line *line, const struct keyfield *key)
in LINE specified by KEY. */
static char *
-limfield (const struct line *line, const struct keyfield *key)
+limfield (line, key)
+ struct line *line;
+ 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 || echar > 0))
+ if (ptr < lim && (eword || key->skipeblanks))
++ptr;
}
else
@@ -594,54 +508,23 @@ limfield (const struct line *line, const struct keyfield *key)
++ptr;
}
- /* 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)
+ if (key->skipeblanks)
while (ptr < lim && blanks[UCHAR (*ptr)])
++ptr;
- /* Advance PTR by ECHAR (if possible), but no further than LIM. */
- if (ptr + echar <= lim)
- ptr += echar;
- else
- ptr = lim;
+ while (ptr < lim && echar--)
+ ++ptr;
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 in BUF with NULs. */
+ Also replace newlines with NULs. */
static void
-findlines (struct buffer *buf, struct lines *lines)
+findlines (buf, lines)
+ struct buffer *buf;
+ struct lines *lines;
{
register char *beg = buf->buf, *lim = buf->buf + buf->used, *ptr;
struct keyfield *key = keyhead.next;
@@ -686,11 +569,6 @@ findlines (struct buffer *buf, struct lines *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
{
@@ -710,7 +588,8 @@ findlines (struct buffer *buf, struct lines *lines)
of the fraction. Strings not of this form are considered to be zero. */
static int
-fraccompare (register const char *a, register const char *b)
+fraccompare (a, b)
+ register char *a, *b;
{
register tmpa = UCHAR (*a), tmpb = UCHAR (*b);
@@ -765,12 +644,12 @@ fraccompare (register const char *a, register const char *b)
hideously fast. */
static int
-numcompare (register const char *a, register const char *b)
+numcompare (a, b)
+ register char *a, *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);
@@ -779,30 +658,19 @@ numcompare (register const char *a, register const char *b)
if (tmpa == '-')
{
- do
- tmpa = UCHAR (*++a);
- while (tmpa == '0');
+ tmpa = UCHAR (*++a);
if (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])
+ if (digits[tmpa] && digits[tmpb])
return -1;
return 0;
}
- do
+ tmpb = UCHAR (*++b);
+
+ while (tmpa == '0')
+ tmpa = UCHAR (*++a);
+ while (tmpb == '0')
tmpb = UCHAR (*++b);
- while (tmpb == '0');
while (tmpa == tmpb && digits[tmpa])
tmpa = UCHAR (*++a), tmpb = UCHAR (*++b);
@@ -832,22 +700,7 @@ numcompare (register const char *a, register const char *b)
}
else if (tmpb == '-')
{
- 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])
+ if (digits[UCHAR (tmpa)] && digits[UCHAR (*++b)])
return 1;
return 0;
}
@@ -886,29 +739,13 @@ 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. */
static int
-getmonth (const char *s, int len)
+getmonth (s, len)
+ char *s;
+ int len;
{
char month[4];
register int i, lo = 0, hi = 12;
@@ -937,7 +774,8 @@ getmonth (const char *s, int len)
are no more keys or a difference is found. */
static int
-keycompare (const struct line *a, const struct line *b)
+keycompare (a, b)
+ struct line *a, *b;
{
register char *texta, *textb, *lima, *limb, *translate;
register int *ignore;
@@ -986,16 +824,6 @@ keycompare (const struct line *a, const struct line *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)
{
@@ -1014,23 +842,6 @@ 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);
@@ -1039,64 +850,38 @@ keycompare (const struct line *a, const struct line *b)
continue;
}
else if (ignore && translate)
-
-#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)]);
+ 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;
+ }
+ }
else if (ignore)
- CMP_WITH_IGNORE (*texta, *textb);
+ 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;
+ }
+ }
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;
}
}
@@ -1116,7 +901,8 @@ keycompare (const struct line *a, const struct line *b)
depending on whether A compares less than, equal to, or greater than B. */
static int
-compare (register const struct line *a, register const struct line *b)
+compare (a, b)
+ register struct line *a, *b;
{
int diff, tmpa, tmpb, mini;
@@ -1155,17 +941,18 @@ compare (register const struct line *a, register const struct line *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.
- FIXME: return number of first out-of-order line if not sorted. */
+ 1 if they do and 0 if there is a disorder. */
static int
-checkfp (FILE *fp)
+checkfp (fp)
+ 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 alloc, sorted = 1;
+ int cmp; /* Result of calling compare. */
+ int alloc, i, success = 1;
initbuf (&buf, mergealloc);
initlines (&lines, mergealloc / linelength + 1,
@@ -1174,69 +961,64 @@ checkfp (FILE *fp)
temp.text = xmalloc (alloc);
cc = fillbuf (&buf, fp);
- if (cc == 0)
- goto finish;
-
findlines (&buf, &lines);
- while (1)
- {
- struct line *prev_line; /* Pointer to previous line. */
- int cmp; /* Result of calling compare. */
- int i;
+ 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;
+ }
+ }
- /* 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;
- }
- }
+ /* 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;
- /* 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;
- }
- }
+ 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);
finish:
xfclose (fp);
free (buf.buf);
free ((char *) lines.lines);
free (temp.text);
- return sorted;
+ return success;
}
/* Merge lines from FPS onto OFP. NFPS cannot be greater than NMERGE.
Close FPS before returning. */
static void
-mergefps (FILE **fps, register int nfps, FILE *ofp)
+mergefps (fps, nfps, ofp)
+ FILE *fps[], *ofp;
+ register int nfps;
{
struct buffer buffer[NMERGE]; /* Input buffers for each file. */
struct lines lines[NMERGE]; /* Line tables for each buffer. */
@@ -1250,10 +1032,6 @@ mergefps (FILE **fps, register int nfps, FILE *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)
{
@@ -1297,7 +1075,7 @@ mergefps (FILE **fps, register int nfps, FILE *ofp)
/* Repeatedly output the smallest line until no input remains. */
while (nfps)
{
- /* If uniqified output is turned on, output only the first of
+ /* If uniqified output is turned out, output only the first of
an identical series of lines. */
if (unique)
{
@@ -1316,7 +1094,7 @@ mergefps (FILE **fps, register int nfps, FILE *ofp)
saved.text = xrealloc (saved.text, savealloc);
}
saved.length = lines[ord[0]].lines[cur[ord[0]]].length;
- memcpy (saved.text, lines[ord[0]].lines[cur[ord[0]]].text,
+ bcopy (lines[ord[0]].lines[cur[ord[0]]].text, saved.text,
saved.length + 1);
if (lines[ord[0]].lines[cur[ord[0]]].keybeg != NULL)
{
@@ -1398,7 +1176,9 @@ mergefps (FILE **fps, register int nfps, FILE *ofp)
/* Sort the array LINES with NLINES members, using TEMP for temporary space. */
static void
-sortlines (struct line *lines, int nlines, struct line *temp)
+sortlines (lines, nlines, temp)
+ struct line *lines, *temp;
+ int nlines;
{
register struct line *lo, *hi, *t;
register int nlo, nhi;
@@ -1439,7 +1219,9 @@ sortlines (struct line *lines, int nlines, struct line *temp)
Return a count of disordered files. */
static int
-check (char **files, int nfiles)
+check (files, nfiles)
+ char *files[];
+ int nfiles;
{
int i, disorders = 0;
FILE *fp;
@@ -1449,7 +1231,7 @@ check (char **files, int nfiles)
fp = xfopen (files[i], "r");
if (!checkfp (fp))
{
- fprintf (stderr, _("%s: disorder on %s\n"), program_name, files[i]);
+ printf ("%s: disorder on %s\n", program_name, files[i]);
++disorders;
}
}
@@ -1459,7 +1241,10 @@ check (char **files, int nfiles)
/* Merge NFILES FILES onto OFP. */
static void
-merge (char **files, int nfiles, FILE *ofp)
+merge (files, nfiles, ofp)
+ char *files[];
+ int nfiles;
+ FILE *ofp;
{
int i, j, t;
char *temp;
@@ -1472,7 +1257,7 @@ merge (char **files, int nfiles, FILE *ofp)
{
for (j = 0; j < NMERGE; ++j)
fps[j] = xfopen (files[i * NMERGE + j], "r");
- tfp = xtmpfopen (temp = tempname ());
+ tfp = xfopen (temp = tempname (), "w");
mergefps (fps, NMERGE, tfp);
xfclose (tfp);
for (j = 0; j < NMERGE; ++j)
@@ -1481,7 +1266,7 @@ merge (char **files, int nfiles, FILE *ofp)
}
for (j = 0; j < nfiles % NMERGE; ++j)
fps[j] = xfopen (files[i * NMERGE + j], "r");
- tfp = xtmpfopen (temp = tempname ());
+ tfp = xfopen (temp = tempname (), "w");
mergefps (fps, nfiles % NMERGE, tfp);
xfclose (tfp);
for (j = 0; j < nfiles % NMERGE; ++j)
@@ -1500,7 +1285,10 @@ merge (char **files, int nfiles, FILE *ofp)
/* Sort NFILES FILES onto OFP. */
static void
-sort (char **files, int nfiles, FILE *ofp)
+sort (files, nfiles, ofp)
+ char **files;
+ int nfiles;
+ FILE *ofp;
{
struct buffer buf;
struct lines lines;
@@ -1508,7 +1296,7 @@ sort (char **files, int nfiles, FILE *ofp)
int i, ntmp;
FILE *fp, *tfp;
struct tempnode *node;
- int n_temp_files = 0;
+ int ntemp = 0;
char **tempfiles;
initbuf (&buf, sortalloc);
@@ -1531,12 +1319,12 @@ sort (char **files, int nfiles, FILE *ofp)
xrealloc ((char *) tmp, ntmp * sizeof (struct line));
}
sortlines (lines.lines, lines.used, tmp);
- if (feof (fp) && !nfiles && !n_temp_files && !buf.left)
+ if (feof (fp) && !nfiles && !ntemp && !buf.left)
tfp = ofp;
else
{
- ++n_temp_files;
- tfp = xtmpfopen (tempname ());
+ ++ntemp;
+ tfp = xfopen (tempname (), "w");
}
for (i = 0; i < lines.used; ++i)
if (!unique || i == 0
@@ -1555,13 +1343,13 @@ sort (char **files, int nfiles, FILE *ofp)
free ((char *) lines.lines);
free ((char *) tmp);
- if (n_temp_files)
+ if (ntemp)
{
- tempfiles = (char **) xmalloc (n_temp_files * sizeof (char *));
- i = n_temp_files;
+ tempfiles = (char **) xmalloc (ntemp * sizeof (char *));
+ i = ntemp;
for (node = temphead.next; i > 0; node = node->next)
tempfiles[--i] = node->name;
- merge (tempfiles, n_temp_files, ofp);
+ merge (tempfiles, ntemp, ofp);
free ((char *) tempfiles);
}
}
@@ -1569,7 +1357,8 @@ sort (char **files, int nfiles, FILE *ofp)
/* Insert key KEY at the end of the list (`keyhead'). */
static void
-insertkey (struct keyfield *key)
+insertkey (key)
+ struct keyfield *key;
{
struct keyfield *k = &keyhead;
@@ -1580,26 +1369,28 @@ insertkey (struct keyfield *key)
}
static void
-badfieldspec (const char *s)
+badfieldspec (s)
+ 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 (int sig)
+sighandler (sig)
+ int sig;
{
-#ifdef SA_INTERRUPT
+#ifdef _POSIX_VERSION
struct sigaction sigact;
sigact.sa_handler = SIG_DFL;
sigemptyset (&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction (sig, &sigact, NULL);
-#else /* !SA_INTERRUPT */
+#else /* !_POSIX_VERSION */
signal (sig, SIG_DFL);
-#endif /* SA_INTERRUPT */
+#endif /* _POSIX_VERSION */
cleanup ();
kill (getpid (), sig);
}
@@ -1610,8 +1401,10 @@ sighandler (int sig)
BLANKTYPE is the kind of blanks that 'b' should skip. */
static char *
-set_ordering (register const char *s, struct keyfield *key,
- enum blanktype blanktype)
+set_ordering (s, key, blanktype)
+ register char *s;
+ struct keyfield *key;
+ enum blanktype blanktype;
{
while (*s)
{
@@ -1629,9 +1422,11 @@ set_ordering (register const char *s, struct keyfield *key,
case 'f':
key->translate = fold_toupper;
break;
+#if 0
case 'g':
- key->general_numeric = 1;
+ /* Reserved for comparing floating-point numbers. */
break;
+#endif
case 'i':
key->ignore = nonprinting;
break;
@@ -1640,24 +1435,22 @@ set_ordering (register const char *s, struct keyfield *key,
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 (char *) s;
+ return s;
}
++s;
}
- return (char *) s;
+ return s;
}
void
-main (int argc, char **argv)
+main (argc, argv)
+ int argc;
+ char *argv[];
{
struct keyfield *key = NULL, gkey;
char *s;
@@ -1665,22 +1458,25 @@ main (int argc, char **argv)
int checkonly = 0, mergeonly = 0, nfiles = 0;
char *minus = "-", *outfile = minus, **files, *tmp;
FILE *ofp;
-#ifdef SA_INTERRUPT
+#ifdef _POSIX_VERSION
struct sigaction oldact, newact;
-#endif /* SA_INTERRUPT */
+#endif /* _POSIX_VERSION */
+#ifdef __FreeBSD__
+ (void) setlocale(LC_CTYPE, "");
+#endif
program_name = argv[0];
- parse_long_options (argc, argv, "sort", version_string, usage);
+ parse_long_options (argc, argv, usage);
have_read_stdin = 0;
inittables ();
temp_file_prefix = getenv ("TMPDIR");
if (temp_file_prefix == NULL)
- temp_file_prefix = DEFAULT_TMPDIR;
+ temp_file_prefix = "/tmp";
-#ifdef SA_INTERRUPT
+#ifdef _POSIX_VERSION
newact.sa_handler = sighandler;
sigemptyset (&newact.sa_mask);
newact.sa_flags = 0;
@@ -1697,7 +1493,7 @@ main (int argc, char **argv)
sigaction (SIGTERM, NULL, &oldact);
if (oldact.sa_handler != SIG_IGN)
sigaction (SIGTERM, &newact, NULL);
-#else /* !SA_INTERRUPT */
+#else /* !_POSIX_VERSION */
if (signal (SIGINT, SIG_IGN) != SIG_IGN)
signal (SIGINT, sighandler);
if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
@@ -1706,12 +1502,12 @@ main (int argc, char **argv)
signal (SIGPIPE, sighandler);
if (signal (SIGTERM, SIG_IGN) != SIG_IGN)
signal (SIGTERM, sighandler);
-#endif /* !SA_INTERRUPT */
+#endif /* !_POSIX_VERSION */
gkey.sword = gkey.eword = -1;
gkey.ignore = NULL;
gkey.translate = NULL;
- gkey.numeric = gkey.general_numeric = gkey.month = gkey.reverse = 0;
+ gkey.numeric = gkey.month = gkey.reverse = 0;
gkey.skipsblanks = gkey.skipeblanks = 0;
files = (char **) xmalloc (sizeof (char *) * argc);
@@ -1727,9 +1523,9 @@ main (int argc, char **argv)
key->ignore = NULL;
key->translate = NULL;
key->skipsblanks = key->skipeblanks = 0;
- key->numeric = key->general_numeric = key->month = key->reverse = 0;
+ key->numeric = key->month = key->reverse = 0;
s = argv[i] + 1;
- if (! (digits[UCHAR (*s)] || (*s == '.' && digits[UCHAR (s[1])])))
+ if (!digits[UCHAR (*s)])
badfieldspec (argv[i]);
for (t = 0; digits[UCHAR (*s)]; ++s)
t = 10 * t + *s - '0';
@@ -1751,7 +1547,7 @@ main (int argc, char **argv)
else if (argv[i][0] == '-' && argv[i][1])
{
s = argv[i] + 1;
- if (digits[UCHAR (*s)] || (*s == '.' && digits[UCHAR (s[1])]))
+ if (digits[UCHAR (*s)])
{
if (!key)
usage (2);
@@ -1786,7 +1582,7 @@ main (int argc, char **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];
}
@@ -1804,34 +1600,15 @@ main (int argc, char **argv)
badfieldspec (argv[i]);
for (t = 0; digits[UCHAR (*s)]; ++s)
t = 10 * t + *s - '0';
- 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;
+ if (t)
+ 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 == 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)
+ t2--;
}
if (t2 || t)
{
@@ -1841,52 +1618,20 @@ argument to the `-k' option\nmust be positive"));
else
key->sword = -1;
s = set_ordering (s, key, bl_start);
- if (*s == 0)
- {
- key->eword = -1;
- key->echar = 0;
- }
- else if (*s != ',')
+ if (*s && *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';
- }
- else
- {
- /* `-k 2,3' is equivalent to `+1 -3'. */
- ++t;
+ if (t2)
+ t--;
}
key->eword = t;
key->echar = t2;
@@ -1906,7 +1651,7 @@ but lacks following character offset"));
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];
}
@@ -1923,20 +1668,19 @@ but lacks following character offset"));
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
+ else if (i < argc - 1)
{
- if (i < argc - 1)
- temp_file_prefix = argv[++i];
- else
- error (2, 0, _("option `-T' requires an argument"));
+ temp_file_prefix = argv[++i];
+ goto outer;
}
- goto outer;
- /* break; */
+ else
+ error (2, 0, "option `-T' requires an argument");
+ break;
case 'u':
unique = 1;
break;
@@ -1945,7 +1689,7 @@ but lacks following character offset"));
Solaris 2. */
goto outer;
default:
- fprintf (stderr, _("%s: unrecognized option `-%c'\n"),
+ fprintf (stderr, "%s: unrecognized option `-%c'\n",
argv[0], *s);
usage (2);
}
@@ -1966,8 +1710,7 @@ but lacks following character offset"));
/* 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->general_numeric)
+ && !key->skipeblanks && !key->month && !key->numeric)
{
key->ignore = gkey.ignore;
key->translate = gkey.translate;
@@ -1975,13 +1718,11 @@ but lacks following character offset"));
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.general_numeric))
+ || gkey.skipeblanks || gkey.month || gkey.numeric))
insertkey (&gkey);
reverse = gkey.reverse;
@@ -1996,61 +1737,32 @@ but lacks following character offset"));
if (strcmp (outfile, "-"))
{
- struct stat outstat;
- if (stat (outfile, &outstat) == 0)
+ for (i = 0; i < nfiles; ++i)
+ if (!strcmp (outfile, files[i]))
+ break;
+ if (i == nfiles)
+ ofp = xfopen (outfile, "w");
+ else
{
- /* 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)
+ 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))
{
- 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;
+ error (0, errno, "%s", outfile);
+ cleanup ();
+ exit (2);
}
+ xfclose (ofp);
+ xfclose (fp);
+ files[i] = tmp;
+ ofp = xfopen (outfile, "w");
}
- ofp = xfopen (outfile, "w");
}
else
ofp = stdout;
@@ -2067,12 +1779,57 @@ but lacks following character offset"));
Solaris, Ultrix, and Irix. This premature fflush makes the output
reappear. --karl@cs.umb.edu */
if (fflush (ofp) < 0)
- error (1, errno, _("%s: write error"), outfile);
+ error (1, errno, "fflush", outfile);
if (have_read_stdin && fclose (stdin) == EOF)
- error (1, errno, outfile);
+ error (1, errno, "-");
if (ferror (stdout) || fclose (stdout) == EOF)
- error (1, errno, _("%s: write error"), outfile);
+ error (1, errno, "write error");
exit (0);
}
+
+static void
+usage (status)
+ int status;
+{
+ if (status != 0)
+ fprintf (stderr, "Try `%s --help' for more information.\n",
+ program_name);
+ else
+ {
+ printf ("\
+Usage: %s [OPTION]... [FILE]...\n\
+",
+ program_name);
+ printf ("\
+\n\
+ +POS1 [-POS2] start a key at POS1, end it before POS2\n\
+ -M compare (unknown) < `JAN' < ... < `DEC', imply -b\n\
+ -T DIRECT use DIRECTfor temporary files, not $TEMPDIR nor /tmp\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\
+ -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\
+");
+ }
+ exit (status);
+}
OpenPOWER on IntegriCloud