Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 13 Jan 2011 04:37:15 GMT
From:      Pedro Giffuni <giffunip@tutopia.com>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   gnu/153945: Update sort with 15 upstream patches
Message-ID:  <201101130437.p0D4bFgb048294@red.freebsd.org>
Resent-Message-ID: <201101130440.p0D4eBb8010950@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         153945
>Category:       gnu
>Synopsis:       Update sort with 15 upstream patches
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          update
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jan 13 04:40:11 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator:     Pedro Giffuni
>Release:        8.2-RC1
>Organization:
>Environment:
FreeBSD mogwai.giffuni.net 8.2-RC1 FreeBSD 8.2-RC1 #0: Thu Dec 23 15:32:35 UTC 2010     root@almeida.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386

>Description:
Updating GNU sort is very difficult, not only because there are local changes, but because the coreutils keeps a basic library that is usually very linux-centric.

For the time being I just went to the coreutils git repository and tracked the sequence of commits that applied cleanly to our base sort. This is not as correct as taking the last GPLv2 release and redoing our changes but it's very practical way of doing it. feel free to prove me wrong ;).

Hopefully I caught all the critical fixes and performance improvements so that we can through this under the rug for a while ...


>How-To-Repeat:
Here is a small log of the changes, with their dates:

Date: Tue, 7 Sep 2004 05:09:24 +0000
Subject: [PATCH] (main): Emulate Solaris 8 and 9 "sort -y", so that
 "sort -y abc" is like "sort abc" whereas "sort -y 100" is like
 plain "sort".

Date: Tue, 21 Sep 2004 22:13:13 +0000
Subject: [PATCH] Don't include "long-options.h".

Date: Fri, 5 Nov 2004 23:02:09 +0000
Subject: [PATCH] (inittables, sort_buffer_size, getmonth, mergefps,
 first_same_file, merge, sort, main): Use size_t for indexes into arrays.
 This fixes some unlikely havoc-wreaking bugs (e.g., more than INT_MAX
 temporary files).

Date: Sat, 6 Nov 2004 22:37:02 +0000
Subject: [PATCH] (xfclose): Don't close stdout here (just flush it),
 since close_stdout now closes stdout unconditionally.

Date: Sat, 6 Nov 2004 23:46:47 +0000
Subject: [PATCH] (first_same_file): Remove.  Move most of the code to....
 (avoid_trashing_input): New function.
 (merge): Avoid some silly merges, e.g., copying a single file to
 a temporary file when there are exactly 17 input files to merge.
 Take a count of temporary files rather than a max_merge arg.
 All uses changed.

Date: Sun, 7 Nov 2004 07:05:38 +0000
Subject: [PATCH] (merge): Remove declarations of now-unused variables.


Date: Mon, 14 Feb 2005 18:04:22 +0000
Subject: [PATCH] (mergefps): Use binary search rather than linear one
 when comparing new line to lines already in main memory.

Date: Sun, 6 Mar 2005 16:31:51 +0000
Subject: [PATCH] Remove `register' keyword.

Date: Mon, 28 Mar 2005 18:09:51 +0000
Subject: [PATCH] (long_options, mergefps): Use NULL, not `0'.

Date: Sat, 9 Apr 2005 04:57:37 +0000
Subject: [PATCH] (SA_NOCLDSTOP): Define to 0 if not defined.
 All uses changed.
 (siginterrupt) [! HAVE_SIGINTERRUPT]: New macro.
 (main) [! SA_NOCLDSTOP]: Use it.

Date: Tue, 26 Apr 2005 16:42:51 +0000
Subject: [PATCH] Remove posixver.h and its uses.
 (short_options): New constant, which always supports -y arg.
 (COMMON_SHORT_OPTIONS): Remove.

Date: Mon, 13 Nov 2006 15:06:15 +0100
Subject: [PATCH] * src/sort.c (main): Plug a tiny memory leak.
 Move declaration of local "minus" down to be nearer point of use.

Date: Wed, 13 Dec 2006 22:03:54 +0100
Subject: [PATCH] Remove some arbitrary restrictions on size fields,
 so that commands like "sort -k 18446744073709551616" no longer fail merely
 because 18446744073709551616 doesn't fit in uintmax_t.  The trick is that
 these fields can all be treated as effectively infinity;  their exact
 values don't matter, since no internal buffer can be that long.

Date: Fri, 19 Jan 2007 23:03:18 +0100
Subject: [PATCH] * src/sort.c (cleanup): Clear temphead at the end.
 (exit_cleanup): New function.
 (main): Don't invoke atexit until we're ready.
 Invoke it with exit_cleanup, not with cleanup and close_stdout,
 to avoid a race condition with cleanup and signal handling.  More
 details: http://thread.gmane.org/gmane.comp.gnu.coreutils.bugs/9508

>Fix:
Patch attached.

Patch attached with submission follows:

--- sort.c.orig	2011-01-12 22:37:22.000000000 +0000
+++ sort.c	2011-01-12 22:35:25.000000000 +0000
@@ -1,6 +1,6 @@
 /* $FreeBSD: src/contrib/gnu-sort/src/sort.c,v 1.4.34.1 2010/12/21 17:10:29 kensmith Exp $ */
 /* sort - sort lines of text (with all kinds of options).
-   Copyright (C) 88, 1991-2004 Free Software Foundation, Inc.
+   Copyright (C) 1988, 1991-2005 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
@@ -53,7 +53,6 @@
 #include "error.h"
 #include "hard-locale.h"
 #include "inttostr.h"
-#include "long-options.h"
 #include "physmem.h"
 #include "posixver.h"
 #include "quote.h"
@@ -89,9 +88,15 @@
 # include <langinfo.h>
 #endif
 
+/* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is
+   present.  */
 #ifndef SA_NOCLDSTOP
+# define SA_NOCLDSTOP 0
 # define sigprocmask(How, Set, Oset) /* empty */
 # define sigset_t int
+# if ! HAVE_SIGINTERRUPT
+#  define siginterrupt(sig, flag) /* empty */
+# endif
 #endif
 
 #ifndef STDC_HEADERS
@@ -401,7 +406,7 @@
   exit (status);
 }
 
-#define COMMON_SHORT_OPTIONS "-bcdfgik:mMno:rsS:t:T:uz"
+static char const short_options[] = "-bcdfgik:mMno:rsS:t:T:uy:z";
 
 static struct option const long_options[] =
 {
@@ -425,7 +430,7 @@
   {"zero-terminated", no_argument, NULL, 'z'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
-  {0, 0, 0, 0},
+  {NULL, 0, NULL, 0},
 };
 
 /* The set of signals that are caught.  */
@@ -488,6 +493,25 @@
 
   for (node = temphead; node; node = node->next)
     unlink (node->name);
+  temphead = NULL;
+}
+
+/* Cleanup actions to take when exiting.  */
+
+static void
+exit_cleanup (void)
+{
+  if (temphead)
+    {
+      /* Clean up any remaining temporary files in a critical section so
+	 that a signal handler does not try to clean them too.  */
+      sigset_t oldset;
+      sigprocmask (SIG_BLOCK, &caught_signals, &oldset);
+      cleanup ();
+      sigprocmask (SIG_SETMASK, &oldset, NULL);
+    }
+
+  close_stdout ();
 }
 
 /* Report MESSAGE for FILE, then clean up and exit.
@@ -576,6 +600,12 @@
       if (feof (fp))
 	clearerr (fp);
     }
+  else if (fp == stdout)
+    {
+      /* Don't close stdout just yet.  close_stdout does that.  */
+      if (fflush (fp) != 0)
+	die (_("fflush failed"), file);
+    }
   else
     {
       if (fclose (fp) != 0)
@@ -636,7 +666,7 @@
 static void
 inittables_uni (void)
 {
-  int i;
+  size_t i;
 
   for (i = 0; i < UCHAR_LIM; ++i)
     {
@@ -840,8 +870,8 @@
    not specified by the user, use a default.  */
 
 static size_t
-sort_buffer_size (FILE *const *fps, int nfps,
-		  char *const *files, int nfiles,
+sort_buffer_size (FILE *const *fps, size_t nfps,
+		  char *const *files, size_t nfiles,
 		  size_t line_bytes)
 {
   /* A bound on the input size.  If zero, the bound hasn't been
@@ -855,7 +885,7 @@
      This extra room might be needed when preparing to read EOF.  */
   size_t size = worst_case_per_input_byte + 1;
 
-  int i;
+  size_t i;
 
   for (i = 0; i < nfiles; i++)
     {
@@ -942,10 +972,10 @@
 static char *
 begfield_uni (const struct line *line, const struct keyfield *key)
 {
-  register char *ptr = line->text, *lim = ptr + line->length - 1;
-  register size_t sword = key->sword;
-  register size_t schar = key->schar;
-  register size_t remaining_bytes;
+  char *ptr = line->text, *lim = ptr + line->length - 1;
+  size_t sword = key->sword;
+  size_t schar = key->schar;
+  size_t remaining_bytes;
 
   /* The leading field separator itself is included in a field when -t
      is absent.  */
@@ -1046,9 +1076,9 @@
 static char *
 limfield_uni (const struct line *line, const struct keyfield *key)
 {
-  register char *ptr = line->text, *lim = ptr + line->length - 1;
-  register size_t eword = key->eword, echar = key->echar;
-  register size_t remaining_bytes;
+  char *ptr = line->text, *lim = ptr + line->length - 1;
+  size_t eword = key->eword, echar = key->echar;
+  size_t remaining_bytes;
 
   /* 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
@@ -1250,7 +1280,7 @@
    Return true if some input was read.  */
 
 static bool
-fillbuf (struct buffer *buf, register FILE *fp, char const *file)
+fillbuf (struct buffer *buf, FILE *fp, char const *file)
 {
   struct keyfield const *key = keylist;
   char eol = eolchar;
@@ -1315,7 +1345,7 @@
 	      if (key)
 		{
 		  /* Precompute the position of the first key for
-                     efficiency. */
+		     efficiency.  */
 		  line->keylim = (key->eword == SIZE_MAX
 				  ? p
 				  : limfield (line, key));
@@ -1401,7 +1431,7 @@
    return 0 */
 
 static int
-fraccompare (register const char *a, register const char *b)
+fraccompare (const char *a, const char *b)
 {
   if (*a == decimal_point && *b == decimal_point)
     {
@@ -1438,7 +1468,7 @@
    hideously fast. */
 
 static int
-numcompare (register const char *a, register const char *b)
+numcompare (const char *a, const char *b)
 {
   char tmpa;
   char tmpb;
@@ -1785,17 +1815,17 @@
 
   /* For the first iteration only, the key positions have been
      precomputed for us. */
-  register char *texta = a->keybeg;
-  register char *textb = b->keybeg;
-  register char *lima = a->keylim;
-  register char *limb = b->keylim;
+  char *texta = a->keybeg;
+  char *textb = b->keybeg;
+  char *lima = a->keylim;
+  char *limb = b->keylim;
 
   int diff;
 
   for (;;)
     {
-      register char const *translate = key->translate;
-      register bool const *ignore = key->ignore;
+      char const *translate = key->translate;
+      bool const *ignore = key->ignore;
 
       /* Find the lengths. */
       size_t lena = lima <= texta ? 0 : lima - texta;
@@ -1814,12 +1844,14 @@
       else if (key->month)
 	diff = getmonth (texta, lena) - getmonth (textb, lenb);
       /* Sorting like this may become slow, so in a simple locale the user
-         can select a faster sort that is similar to ascii sort  */
+	 can select a faster sort that is similar to ascii sort.  */
       else if (HAVE_SETLOCALE && hard_LC_COLLATE)
 	{
 	  if (ignore || translate)
 	    {
-	      char *copy_a = alloca (lena + 1 + lenb + 1);
+	      char buf[4000];
+	      size_t size = lena + 1 + lenb + 1;
+	      char *copy_a = (size <= sizeof buf ? buf : xmalloc (size));
 	      char *copy_b = copy_a + lena + 1;
 	      size_t new_len_a, new_len_b, i;
 
@@ -1845,6 +1877,9 @@
 		}
 
 	      diff = xmemcoll (copy_a, new_len_a, copy_b, new_len_b);
+
+	      if (sizeof buf < size)
+		free (copy_a);
 	    }
 	  else if (lena == 0)
 	    diff = - NONZERO (lenb);
@@ -2119,7 +2154,7 @@
    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 (const struct line *a, const struct line *b)
 {
   int diff;
   size_t alen, blen;
@@ -2130,7 +2165,6 @@
   if (keylist)
     {
       diff = keycompare (a, b);
-      alloca (0);
       if (diff | unique | stable)
 	return diff;
     }
@@ -2243,8 +2277,7 @@
    file has not been opened yet (or written to, if standard output).  */
 
 static void
-mergefps (char **files, register int nfiles,
-	  FILE *ofp, const char *output_file)
+mergefps (char **files, size_t nfiles, FILE *ofp, char const *output_file)
 {
   FILE *fps[NMERGE];		/* Input streams for each file.  */
   struct buffer buffer[NMERGE];	/* Input buffers for each file. */
@@ -2254,10 +2287,12 @@
   size_t savealloc = 0;		/* Size allocated for the saved line. */
   struct line const *cur[NMERGE]; /* Current line in each line table. */
   struct line const *base[NMERGE]; /* Base of each line table.  */
-  int ord[NMERGE];		/* Table representing a permutation of fps,
+  size_t ord[NMERGE];		/* Table representing a permutation of fps,
 				   such that cur[ord[0]] is the smallest line
 				   and will be next output. */
-  register int i, j, t;
+  size_t i;
+  size_t j;
+  size_t t;
   struct keyfield const *key = keylist;
   saved.text = NULL;
 
@@ -2309,7 +2344,7 @@
 	{
 	  if (savedline && compare (savedline, smallest))
 	    {
-	      savedline = 0;
+	      savedline = NULL;
 	      write_bytes (saved.text, saved.length, ofp, output_file);
 	    }
 	  if (!savedline)
@@ -2354,7 +2389,7 @@
 	    }
 	  else
 	    {
-	      /* We reached EOF on fps[ord[0]]. */
+	      /* We reached EOF on fps[ord[0]].  */
 	      for (i = 1; i < nfiles; ++i)
 		if (ord[i] > ord[0])
 		  --ord[i];
@@ -2377,20 +2412,31 @@
 	}
 
       /* The new line just read in may be larger than other lines
-	 already in core; push it back in the queue until we encounter
-	 a line larger than it. */
-      for (i = 1; i < nfiles; ++i)
-	{
-	  t = compare (cur[ord[0]], cur[ord[i]]);
-	  if (!t)
-	    t = ord[0] - ord[i];
-	  if (t < 0)
-	    break;
-	}
-      t = ord[0];
-      for (j = 1; j < i; ++j)
-	ord[j - 1] = ord[j];
-      ord[i - 1] = t;
+	 already in main memory; push it back in the queue until we
+	 encounter a line larger than it.  Optimize for the common
+	 case where the new line is smallest.  */
+      {
+	size_t lo = 1;
+	size_t hi = nfiles;
+	size_t probe = lo;
+	size_t ord0 = ord[0];
+	size_t count_of_smaller_lines;
+
+	while (lo < hi)
+	  {
+	    int cmp = compare (cur[ord0], cur[ord[probe]]);
+	    if (cmp < 0 || (cmp == 0 && ord0 < ord[probe]))
+	      hi = probe;
+	    else
+	      lo = probe + 1;
+	    probe = (lo + hi) / 2;
+	  }
+
+	count_of_smaller_lines = lo - 1;
+	for (j = 0; j < count_of_smaller_lines; j++)
+	  ord[j] = ord[j + 1];
+	ord[count_of_smaller_lines] = ord0;
+      }
     }
 
   if (unique && savedline)
@@ -2508,8 +2554,12 @@
     }
 }
 
-/* Return the index of the first of NFILES FILES that is the same file
-   as OUTFILE.  If none can be the same, return NFILES.
+/* Scan through FILES[N_TEMP_FILES .. NFILES-1] looking for a file that is
+   the same as OUTFILE.  If found, merge the found instances (and perhaps
+   some other files) into a temporary file so that it can in turn be
+   merged into OUTFILE without destroying OUTFILE before it is completely
+   read.  Return the new value of NFILES, which differs from the old if
+   some merging occurred.
 
    This test ensures that an otherwise-erroneous use like
    "sort -m -o FILE ... FILE ..." copies FILE before writing to it.
@@ -2521,77 +2571,121 @@
    Catching these obscure cases would slow down performance in
    common cases.  */
 
-static int
-first_same_file (char * const *files, int nfiles, char const *outfile)
+static size_t
+avoid_trashing_input (char **files, size_t n_temp_files, size_t nfiles,
+		      char const *outfile)
 {
-  int i;
+  size_t i;
   bool got_outstat = false;
-  struct stat instat, outstat;
+  struct stat outstat;
 
-  for (i = 0; i < nfiles; i++)
+  for (i = n_temp_files; i < nfiles; i++)
     {
       bool standard_input = STREQ (files[i], "-");
+      bool same;
+      struct stat instat;
 
       if (outfile && STREQ (outfile, files[i]) && ! standard_input)
-	return i;
-
-      if (! got_outstat)
+	same = true;
+      else
 	{
-	  got_outstat = true;
-	  if ((outfile
-	       ? stat (outfile, &outstat)
-	       : fstat (STDOUT_FILENO, &outstat))
-	      != 0)
-	    return nfiles;
-	}
-
-      if (((standard_input
-	    ? fstat (STDIN_FILENO, &instat)
-	    : stat (files[i], &instat))
-	   == 0)
-	  && SAME_INODE (instat, outstat))
-	return i;
+	  if (! got_outstat)
+	    {
+	      if ((outfile
+		   ? stat (outfile, &outstat)
+		   : fstat (STDOUT_FILENO, &outstat))
+		  != 0)
+		break;
+	      got_outstat = true;
+	    }
+
+	  same = (((standard_input
+		    ? fstat (STDIN_FILENO, &instat)
+		    : stat (files[i], &instat))
+		   == 0)
+		  && SAME_INODE (instat, outstat));
+	}
+
+      if (same)
+	{
+	  FILE *tftp;
+	  char *temp = create_temp_file (&tftp);
+	  mergefps (&files[i], nfiles - i, tftp, temp);
+	  files[i] = temp;
+	  return i + 1;
+	}
     }
 
   return nfiles;
 }
 
-/* Merge NFILES FILES onto OUTPUT_FILE.  However, merge at most
-   MAX_MERGE input files directly onto OUTPUT_FILE.  MAX_MERGE cannot
-   exceed NMERGE.  A null OUTPUT_FILE stands for standard output.  */
+/* Merge the input FILES.  N_TEMP_FILES is the number of files at the
+   start of FILES that are temporary; it is zero at the top level.
+   NFILES is the total number of files.  Put the output in
+   OUTPUT_FILE; a null OUTPUT_FILE stands for standard output.  */
 
 static void
-merge (char **files, int nfiles, int max_merge, char const *output_file)
+merge (char **files, size_t n_temp_files, size_t nfiles,
+       char const *output_file)
 {
-  while (max_merge < nfiles)
+  while (NMERGE < nfiles)
     {
-      FILE *tfp;
-      int i, t = 0;
-      char *temp;
-      for (i = 0; i < nfiles / NMERGE; ++i)
-	{
-	  temp = create_temp_file (&tfp);
-	  mergefps (&files[i * NMERGE], NMERGE, tfp, temp);
-	  files[t++] = temp;
-	}
-      temp = create_temp_file (&tfp);
-      mergefps (&files[i * NMERGE], nfiles % NMERGE, tfp, temp);
-      files[t++] = temp;
-      nfiles = t;
-      if (nfiles == 1)
-	break;
+      /* Number of input files processed so far.  */
+      size_t in;
+
+      /* Number of output files generated so far.  */
+      size_t out;
+
+      /* nfiles % NMERGE; this counts input files that are left over
+	 after all full-sized merges have been done.  */
+      size_t remainder;
+
+      /* Number of easily-available slots at the next loop iteration.  */
+      size_t cheap_slots;
+
+      /* Do as many NMERGE-size merges as possible.  */
+      for (out = in = 0; out < nfiles / NMERGE; out++, in += NMERGE)
+	{
+	  FILE *tfp;
+	  char *temp = create_temp_file (&tfp);
+	  mergefps (&files[in], NMERGE, tfp, temp);
+	  files[out] = temp;
+	}
+
+      remainder = nfiles - in;
+      cheap_slots = NMERGE - out % NMERGE;
+
+      if (cheap_slots < remainder)
+	{
+	  /* So many files remain that they can't all be put into the last
+	     NMERGE-sized output window.  Do one more merge.  Merge as few
+	     files as possible, to avoid needless I/O.  */
+	  size_t n_shortmerge = remainder - cheap_slots + 1;
+	  FILE *tfp;
+	  char *temp = create_temp_file (&tfp);
+	  mergefps (&files[in], n_shortmerge, tfp, temp);
+	  files[out++] = temp;
+	  in += n_shortmerge;
+	}
+
+      /* Put the remaining input files into the last NMERGE-sized output
+	 window, so they will be merged in the next pass.  */
+      memmove(&files[out], &files[in], (nfiles - in) * sizeof *files);
+      n_temp_files = out + (in < n_temp_files ? n_temp_files - in : 0);
+      nfiles -= in - out;
     }
 
+  nfiles = avoid_trashing_input (files, n_temp_files, nfiles, output_file);
   mergefps (files, nfiles, NULL, output_file);
 }
 
 /* Sort NFILES FILES onto OUTPUT_FILE. */
 
 static void
-sort (char * const *files, int nfiles, char const *output_file)
+sort (char * const *files, size_t nfiles, char const *output_file)
 {
   struct buffer buf;
-  int n_temp_files = 0;
+  size_t n_temp_files = 0;
   bool output_file_created = false;
 
   buf.alloc = 0;
@@ -2668,12 +2762,12 @@
 
   if (! output_file_created)
     {
-      int i = n_temp_files;
+      size_t i = n_temp_files;
       struct tempnode *node;
       char **tempfiles = xnmalloc (n_temp_files, sizeof *tempfiles);
       for (node = temphead; i > 0; node = node->next)
 	tempfiles[--i] = node->name;
-      merge (tempfiles, n_temp_files, NMERGE, output_file);
+      merge (tempfiles, n_temp_files, n_temp_files, output_file);
       free (tempfiles);
     }
 }
@@ -2705,7 +2799,8 @@
 
 /* Parse the leading integer in STRING and store the resulting value
    (which must fit into size_t) into *VAL.  Return the address of the
-   suffix after the integer.  If MSGID is NULL, return NULL after
+   suffix after the integer.  If the value is too large, silently
+   substitute SIZE_MAX.  If MSGID is NULL, return NULL after
    failure; otherwise, report MSGID and exit on failure.  */
 
 static char const *
@@ -2724,10 +2819,8 @@
       /* Fall through.  */
     case LONGINT_OVERFLOW:
     case LONGINT_OVERFLOW | LONGINT_INVALID_SUFFIX_CHAR:
-      if (msgid)
-	error (SORT_FAILURE, 0, _("%s: count `%.*s' too large"),
-	       _(msgid), (int) (suffix - string), string);
-      return NULL;
+      *val = SIZE_MAX;
+      break;
 
     case LONGINT_INVALID:
       if (msgid)
@@ -2744,9 +2837,8 @@
 static void
 sighandler (int sig)
 {
-#ifndef SA_NOCLDSTOP
-  signal (sig, SIG_IGN);
-#endif
+  if (! SA_NOCLDSTOP)
+    signal (sig, SIG_IGN);
 
   cleanup ();
 
@@ -2760,8 +2852,7 @@
    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 (const char *s, struct keyfield *key, enum blanktype blanktype)
 {
   while (*s)
     {
@@ -2822,13 +2913,10 @@
   int c = 0;
   bool checkonly = false;
   bool mergeonly = false;
-  int nfiles = 0;
+  size_t nfiles = 0;
   bool posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
   bool obsolete_usage = (posix2_version () < 200112);
-  char const *short_options = (obsolete_usage
-			       ? COMMON_SHORT_OPTIONS "y::"
-			       : COMMON_SHORT_OPTIONS "y:");
-  char *minus = "-", **files;
+  char **files;
   char const *outfile = NULL;
 
   initialize_main (&argc, &argv);
@@ -2837,10 +2925,7 @@
   bindtextdomain (PACKAGE, LOCALEDIR);
   textdomain (PACKAGE);
 
-  atexit (cleanup);
-
   initialize_exit_failure (SORT_FAILURE);
-  atexit (close_stdout);
 
   hard_LC_COLLATE = hard_locale (LC_COLLATE);
 #if HAVE_NL_LANGINFO
@@ -2894,11 +2979,11 @@
   inittables ();
 
   {
-    int i;
+    size_t i;
     static int const sig[] = { SIGHUP, SIGINT, SIGPIPE, SIGTERM };
     enum { nsigs = sizeof sig / sizeof sig[0] };
 
-#ifdef SA_NOCLDSTOP
+#if SA_NOCLDSTOP
     struct sigaction act;
 
     sigemptyset (&caught_signals);
@@ -2919,10 +3004,16 @@
 #else
     for (i = 0; i < nsigs; i++)
       if (signal (sig[i], SIG_IGN) != SIG_IGN)
-	signal (sig[i], sighandler);
+	{
+	  signal (sig[i], sighandler);
+	  siginterrupt (sig[i], 1);
+	}
 #endif
   }
 
+  /* The signal mask is known, so it is safe to invoke exit_cleanup.  */
+  atexit (exit_cleanup);
+
   gkey.sword = gkey.eword = SIZE_MAX;
   gkey.ignore = NULL;
   gkey.translate = NULL;
@@ -2934,9 +3025,9 @@
   for (;;)
     {
       /* Parse an operand as a file after "--" was seen; or if
-         pedantic and a file was seen, unless the POSIX version
-         predates 1003.1-2001 and -c was not seen and the operand is
-         "-o FILE" or "-oFILE".  */
+	 pedantic and a file was seen, unless the POSIX version
+	 predates 1003.1-2001 and -c was not seen and the operand is
+	 "-o FILE" or "-oFILE".  */
 
       if (c == -1
 	  || (posixly_correct && nfiles != 0
@@ -3155,9 +3246,23 @@
 	  break;
 
 	case 'y':
-	  /* Accept and ignore e.g. -y0 for compatibility with Solaris
-	     2.x through Solaris 7.  -y is marked as obsolete starting
-	     with Solaris 8.  */
+	  /* Accept and ignore e.g. -y0 for compatibility with Solaris 2.x
+	     through Solaris 7.  It is also accepted by many non-Solaris
+	     "sort" implementations, e.g., AIX 5.2, HP-UX 11i v2, IRIX 6.5.
+	     -y is marked as obsolete starting with Solaris 8 (1999), but is
+	     still accepted as of Solaris 10 prerelease (2004).
+
+	     Solaris 2.5.1 "sort -y 100" reads the input file "100", but
+	     emulate Solaris 8 and 9 "sort -y 100" which ignores the "100",
+	     and which in general ignores the argument after "-y" if it
+	     consists entirely of digits (it can even be empty).  */
+	  if (optarg == argv[optind - 1])
+	    {
+	      char const *p;
+	      for (p = optarg; ISDIGIT (*p); p++)
+		continue;
+	      optind -= (*p != '\0');
+	    }
 	  break;
 
 	case 'z':
@@ -3204,7 +3309,9 @@
 
   if (nfiles == 0)
     {
+      static char *minus = "-";
       nfiles = 1;
+      free (files);
       files = &minus;
     }
 
@@ -3223,10 +3330,7 @@
     }
 
   if (mergeonly)
-    {
-      int max_merge = first_same_file (files, MIN (nfiles, NMERGE), outfile);
-      merge (files, nfiles, max_merge, outfile);
-    }
+    merge (files, 0, nfiles, outfile);
   else
     sort (files, nfiles, outfile);
 


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201101130437.p0D4bFgb048294>