bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: rebased patches?


From: Jim Meyering
Subject: Re: rebased patches?
Date: Thu, 12 Jun 2008 21:40:48 +0200

Bo Borgerson <address@hidden> wrote:
> Jim Meyering wrote:
>> P.S. no need to send the tarball.
>> I like using repo.or.cz.
>>
>> Also, I think you made it so your new decl,
>>
>>   /* Output columns will be delimited with this string, which may be set
>>      on the command-line with --output-delimiter=STR.  The default is a
>>      single TAB character. */
>>   static char *delimiter;
>>
>> has two empty lines after it.
>> Just one is better.
>
> Hi Jim,
>
> I've re-pushed the comm branch with the changes you suggested.

Hi Bo,

Thanks!
I've made some minor editing changes, e.g.,
[better to use an active voice than a passive one]

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index ff6bbb0..d05577d 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -4476,8 +4476,8 @@ Do not check that both input files are in sorted order.
 Other options are:

 @item address@hidden
-Columns will be delimited by @var{str} in output, rather than the default
-single TAB character.
+Print @var{str} between adjacent output columns,
+rather than the default of a single TAB character.

 The delimiter @var{str} may not be empty.

and tweaked the log messages.
Also, I made some syntactic changes to fit with my policy
preferences (no ">" operators, and adjusted "const" placement):

Here are your two adjusted change sets, then mine at the end.

>From 98a96822d9dac92de719fa340fe326e1fe0427fe Mon Sep 17 00:00:00 2001
From: Bo Borgerson <address@hidden>
Date: Sun, 20 Apr 2008 21:24:16 -0400
Subject: [PATCH] comm: ensure that input files are sorted

* NEWS: List new behavior.
* doc/coreutils.texi (checkOrderOption) New macro for
describing `--check-order' and `--nocheck-order', used in
both join and comm.
* src/comm.c (main): Initialize new options.
(usage): Describe new options.
(compare_files): Keep an extra pair of buffers for the previous
line from each file to check the internal order.
(check_order): If an order-check is required, compare and handle
the result appropriately.
(copylinebuffer): Copy a linebuffer; used for copy before read.
* tests/misc/Makefile.am: List new test.
* tests/misc/comm: Tests for the comm program, including the
new order-checking functionality and attendant command-line options.
---
 NEWS               |    3 +
 doc/coreutils.texi |   39 ++++++++----
 src/comm.c         |  168 +++++++++++++++++++++++++++++++++++++++++++++------
 tests/Makefile.am  |    1 +
 tests/misc/comm    |  124 ++++++++++++++++++++++++++++++++++++++
 5 files changed, 303 insertions(+), 32 deletions(-)
 create mode 100755 tests/misc/comm

diff --git a/NEWS b/NEWS
index 97f3162..ba39d2f 100644
--- a/NEWS
+++ b/NEWS
@@ -9,6 +9,9 @@ GNU coreutils NEWS                                    -*- 
outline -*-

 ** New features

+  comm now verifies that the inputs are in sorted order.  This check can
+  be turned off with the --nocheck-order option.
+
   md5sum now accepts the new option, --quiet, to suppress the printing of
   'OK' messages.  sha1sum, sha224sum, sha384sum, and sha512sum accept it, too.

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index a626b45..3bedd73 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -4449,6 +4449,32 @@ status that does not depend on the result of the 
comparison.
 Upon normal completion @command{comm} produces an exit code of zero.
 If there is an error it exits with nonzero status.

address@hidden checkOrderOption{cmd}
+If the @option{--check-order} option is given, unsorted inputs will
+cause a fatal error message.  If the option @option{--nocheck-order}
+is given, unsorted inputs will never cause an error message.  If
+neither of these options is given, wrongly sorted inputs are diagnosed
+only if an input file is found to contain unpairable lines.  If an
+input file is diagnosed as being unsorted, the @command{\cmd\} command
+will exit with a nonzero status (and the output should not be used).
+
+Forcing @command{\cmd\} to process wrongly sorted input files
+containing unpairable lines by specifying @option{--nocheck-order} is
+not guaranteed to produce any particular output.  The output will
+probably not correspond with whatever you hoped it would be.
address@hidden macro
address@hidden
+
address@hidden @samp
+
address@hidden --check-order
+Fail with an error message if either input file is wrongly ordered.
+
address@hidden --nocheck-order
+Do not check that both input files are in sorted order.
+
address@hidden table
+

 @node tsort invocation
 @section @command{tsort}: Topological sort
@@ -5290,18 +5316,7 @@ c c1 c2
 b b1 b2
 @end example

-If the @option{--check-order} option is given, unsorted inputs will
-cause a fatal error message.  If the option @option{--nocheck-order}
-is given, unsorted inputs will never cause an error message.  If
-neither of these options is given, wrongly sorted inputs are diagnosed
-only if an input file is found to contain unpairable lines.  If an
-input file is diagnosed as being unsorted, the @command{join} command
-will exit with a nonzero status (and the output should not be used).
-
-Forcing @command{join} to process wrongly sorted input files
-containing unpairable lines by specifying @option{--nocheck-order} is
-not guaranteed to produce any particular output.  The output will
-probably not correspond with whatever you hoped it would be.
address@hidden

 The defaults are:
 @itemize
diff --git a/src/comm.c b/src/comm.c
index a71d61a..01c0b8c 100644
--- a/src/comm.c
+++ b/src/comm.c
@@ -51,8 +51,31 @@ static bool only_file_2;
 /* If true, print lines that are found in both files. */
 static bool both;

+/* If nonzero, we have seen at least one unpairable line. */
+static bool seen_unpairable;
+
+/* If nonzero, we have warned about disorder in that file. */
+static bool issued_disorder_warning[2];
+
+/* If nonzero, check that the input is correctly ordered. */
+static enum
+  {
+    CHECK_ORDER_DEFAULT,
+    CHECK_ORDER_ENABLED,
+    CHECK_ORDER_DISABLED
+  } check_input_order;
+
+enum
+{
+  CHECK_ORDER_OPTION = CHAR_MAX + 1,
+  NOCHECK_ORDER_OPTION
+};
+
+
 static struct option const long_options[] =
 {
+  {"check-order", no_argument, NULL, CHECK_ORDER_OPTION},
+  {"nocheck-order", no_argument, NULL, NOCHECK_ORDER_OPTION},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -87,6 +110,12 @@ and column three contains lines common to both files.\n\
   -2              suppress lines unique to FILE2\n\
   -3              suppress lines that appear in both files\n\
 "), stdout);
+      fputs (_("\
+\n\
+  --check-order     check that the input is correctly sorted, even\n\
+                      if all input lines are pairable\n\
+  --nocheck-order   do not check that the input is correctly sorted\n\
+"), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
       emit_bug_reporting_address ();
@@ -132,6 +161,53 @@ writeline (const struct linebuffer *line, FILE *stream, 
int class)
   fwrite (line->buffer, sizeof (char), line->length, stream);
 }

+/* Check that successive input lines PREV and CURRENT from input file
+   WHATFILE are presented in order.
+
+   If the user specified --nocheck-order, the check is not made.
+   If the user specified --check-order, the problem is fatal.
+   Otherwise (the default), the message is simply a warning.
+
+   A message is printed at most once per input file.
+
+   This funtion was copied (nearly) verbatim from `src/join.c'. */
+
+static void
+check_order (const struct linebuffer *prev,
+            const struct linebuffer *current,
+            int whatfile)
+{
+
+  if (check_input_order != CHECK_ORDER_DISABLED
+      && ((check_input_order == CHECK_ORDER_ENABLED) || seen_unpairable))
+    {
+      if (!issued_disorder_warning[whatfile - 1])
+       {
+         int order;
+
+         if (hard_LC_COLLATE)
+           order = xmemcoll (prev->buffer, prev->length - 1,
+                             current->buffer, current->length - 1);
+         else
+           {
+             size_t len = min (prev->length, current->length) - 1;
+             order = memcmp (prev->buffer, current->buffer, len);
+           }
+
+         if (order > 0)
+           {
+             error ((check_input_order == CHECK_ORDER_ENABLED
+                     ? EXIT_FAILURE : 0),
+                    0, _("file %d is not in sorted order"), whatfile);
+
+             /* If we get to here, the message was just a warning, but we
+                want only to issue it once. */
+             issued_disorder_warning[whatfile - 1] = true;
+           }
+       }
+    }
+}
+
 /* Compare INFILES[0] and INFILES[1].
    If either is "-", use the standard input for that file.
    Assume that each input file is sorted;
@@ -140,28 +216,42 @@ writeline (const struct linebuffer *line, FILE *stream, 
int class)
 static void
 compare_files (char **infiles)
 {
-  /* For each file, we have one linebuffer in lb1.  */
-  struct linebuffer lb1[2];
+  /* For each file, we have four linebuffers in lba. */
+  struct linebuffer lba[2][4];

   /* thisline[i] points to the linebuffer holding the next available line
      in file i, or is NULL if there are no lines left in that file.  */
   struct linebuffer *thisline[2];

+  /* all_line[i][alt[i][0]] also points to the linebuffer holding the
+     current line in file i. We keep two buffers of history around so we
+     can look two lines back when we get to the end of a file. */
+  struct linebuffer *all_line[2][4];
+
+  /* This is used to rotate through the buffers for each input file. */
+  int alt[2][3];
+
   /* streams[i] holds the input stream for file i.  */
   FILE *streams[2];

-  int i;
+  int i, j;

   /* Initialize the storage. */
   for (i = 0; i < 2; i++)
     {
-      initbuffer (&lb1[i]);
-      thisline[i] = &lb1[i];
+      for (j = 0; j < 4; j++)
+       {
+         initbuffer (&lba[i][j]);
+         all_line[i][j] = &lba[i][j];
+       }
+      alt[i][0] = 0;
+      alt[i][1] = 0;
+      alt[i][2] = 0;
       streams[i] = (STREQ (infiles[i], "-") ? stdin : fopen (infiles[i], "r"));
       if (!streams[i])
        error (EXIT_FAILURE, errno, "%s", infiles[i]);

-      thisline[i] = readlinebuffer (thisline[i], streams[i]);
+      thisline[i] = readlinebuffer (all_line[i][alt[i][0]], streams[i]);
       if (ferror (streams[i]))
        error (EXIT_FAILURE, errno, "%s", infiles[i]);
     }
@@ -169,6 +259,7 @@ compare_files (char **infiles)
   while (thisline[0] || thisline[1])
     {
       int order;
+      bool fill_up[2] = { false, false };

       /* Compare the next available lines of the two files.  */

@@ -195,25 +286,47 @@ compare_files (char **infiles)
       /* Output the line that is lesser. */
       if (order == 0)
        writeline (thisline[1], stdout, 3);
-      else if (order > 0)
-       writeline (thisline[1], stdout, 2);
       else
-       writeline (thisline[0], stdout, 1);
+       {
+         seen_unpairable = true;
+         if (order > 0)
+           writeline (thisline[1], stdout, 2);
+         else
+           writeline (thisline[0], stdout, 1);
+       }

       /* Step the file the line came from.
         If the files match, step both files.  */
       if (order >= 0)
-       {
-         thisline[1] = readlinebuffer (thisline[1], streams[1]);
-         if (ferror (streams[1]))
-           error (EXIT_FAILURE, errno, "%s", infiles[1]);
-       }
+       fill_up[1] = true;
       if (order <= 0)
-       {
-         thisline[0] = readlinebuffer (thisline[0], streams[0]);
-         if (ferror (streams[0]))
-           error (EXIT_FAILURE, errno, "%s", infiles[0]);
-       }
+       fill_up[0] = true;
+
+      for (i = 0; i < 2; i++)
+       if (fill_up[i])
+         {
+           /* Rotate the buffers for this file. */
+           alt[i][2] = alt[i][1];
+           alt[i][1] = alt[i][0];
+           alt[i][0] = (alt[i][0] + 1) & 0x03;
+
+           thisline[i] = readlinebuffer (all_line[i][alt[i][0]], streams[i]);
+
+           if (thisline[i])
+             check_order (all_line[i][alt[i][1]], thisline[i], i + 1);
+
+           /* If this is the end of the file we may need to re-check
+              the order of the previous two lines, since we might have
+              discovered an unpairable match since we checked before. */
+           else if (all_line[i][alt[i][2]]->buffer)
+             check_order (all_line[i][alt[i][2]],
+                          all_line[i][alt[i][1]], i + 1);
+
+           if (ferror (streams[i]))
+             error (EXIT_FAILURE, errno, "%s", infiles[i]);
+
+           fill_up[i] = false;
+         }
     }

   for (i = 0; i < 2; i++)
@@ -239,6 +352,10 @@ main (int argc, char **argv)
   only_file_2 = true;
   both = true;

+  seen_unpairable = false;
+  issued_disorder_warning[0] = issued_disorder_warning[1] = false;
+  check_input_order = CHECK_ORDER_DEFAULT;
+
   while ((c = getopt_long (argc, argv, "123", long_options, NULL)) != -1)
     switch (c)
       {
@@ -254,6 +371,14 @@ main (int argc, char **argv)
        both = false;
        break;

+      case NOCHECK_ORDER_OPTION:
+       check_input_order = CHECK_ORDER_DISABLED;
+       break;
+
+      case CHECK_ORDER_OPTION:
+       check_input_order = CHECK_ORDER_ENABLED;
+       break;
+
       case_GETOPT_HELP_CHAR;

       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -279,5 +404,8 @@ main (int argc, char **argv)

   compare_files (argv + optind);

-  exit (EXIT_SUCCESS);
+  if (issued_disorder_warning[0] || issued_disorder_warning[1])
+    exit (EXIT_FAILURE);
+  else
+    exit (EXIT_SUCCESS);
 }
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d33005a..f07837b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -146,6 +146,7 @@ TESTS =                                             \
   misc/base64                                  \
   misc/basename                                        \
   misc/close-stdout                            \
+  misc/comm                                    \
   misc/csplit                                  \
   misc/date-sec                                        \
   misc/dircolors                               \
diff --git a/tests/misc/comm b/tests/misc/comm
new file mode 100755
index 0000000..39557d2
--- /dev/null
+++ b/tests/misc/comm
@@ -0,0 +1,124 @@
+#!/usr/bin/perl
+# -*- perl -*-
+# Test comm
+
+# Copyright (C) 2008 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
+
+require 5.003;
+use strict;
+
+(my $program_name = $0) =~ s|.*/||;
+
+my $prog = 'comm';
+
+# Turn off localization of executable's ouput.
address@hidden(LANGUAGE LANG LC_ALL)} = ('C') x 3;
+
+my @inputs = ({IN=>{a=>"1\n3"}}, {IN=>{b=>"2\n3"}});
+
+my @Tests =
+  (
+   # basic operation
+   ['basic', @inputs, {OUT=>"1\n\t2\n\t\t3\n"} ],
+
+   # supress lines unique to file 1
+   ['opt-1', '-1', @inputs, {OUT=>"2\n\t3\n"} ],
+
+   # supress lines unique to file 2
+   ['opt-2', '-2', @inputs, {OUT=>"1\n\t3\n"} ],
+
+   # supress lines that appear in both files
+   ['opt-3', '-3', @inputs, {OUT=>"1\n\t2\n"} ],
+
+   # supress lines unique to file 1 and lines unique to file 2
+   ['opt-12', '-1', '-2', @inputs, {OUT=>"3\n"} ],
+
+   # supress lines unique to file 1 and those that appear in both files
+   ['opt-13', '-1', '-3', @inputs, {OUT=>"2\n"} ],
+
+   # supress lines unique to file 2 and those that appear in both files
+   ['opt-23', '-2', '-3', @inputs, {OUT=>"1\n"} ],
+
+   # supress all output (really?)
+   ['opt-123', '-1', '-2', '-3', @inputs, {OUT=>""} ],
+
+   # invalid missing command line argument (1)
+   ['missing-arg1', $inputs[0], {EXIT=>1},
+    {ERR => "$prog: missing operand after `a'\n"
+       . "Try `$prog --help' for more information.\n"}],
+
+   # invalid missing command line argument (both)
+   ['missing-arg2', {EXIT=>1},
+    {ERR => "$prog: missing operand\n"
+       . "Try `$prog --help' for more information.\n"}],
+
+   # invalid extra command line argument
+   ['extra-arg', @inputs, 'no-such', {EXIT=>1},
+    {ERR => "$prog: extra operand `no-such'\n"
+       . "Try `$prog --help' for more information.\n"}],
+
+   # out-of-order input
+   ['ooo', {IN=>{a=>"1\n3"}}, {IN=>{b=>"3\n2"}}, {EXIT=>1},
+    {OUT => "1\n\t\t3\n\t2\n"},
+    {ERR => "$prog: file 2 is not in sorted order\n"}],
+
+   # out-of-order input, fatal
+   ['ooo2', '--check-order', {IN=>{a=>"1\n3"}}, {IN=>{b=>"3\n2"}}, {EXIT=>1},
+    {OUT => "1\n\t\t3\n"},
+    {ERR => "$prog: file 2 is not in sorted order\n"}],
+
+   # out-of-order input, ignored
+   ['ooo3', '--nocheck-order', {IN=>{a=>"1\n3"}}, {IN=>{b=>"3\n2"}},
+    {OUT => "1\n\t\t3\n\t2\n"}],
+
+   # both inputs out-of-order
+   ['ooo4', {IN=>{a=>"3\n1\n0"}}, {IN=>{b=>"3\n2\n0"}}, {EXIT=>1},
+    {OUT => "\t\t3\n1\n0\n\t2\n\t0\n"},
+    {ERR => "$prog: file 1 is not in sorted order\n".
+           "$prog: file 2 is not in sorted order\n" }],
+
+   # both inputs out-of-order on last pair
+   ['ooo5', {IN=>{a=>"3\n1"}}, {IN=>{b=>"3\n2"}}, {EXIT=>1},
+    {OUT => "\t\t3\n1\n\t2\n"},
+    {ERR => "$prog: file 1 is not in sorted order\n".
+           "$prog: file 2 is not in sorted order\n" }],
+
+   # first input out-of-order extended
+   ['ooo5b', {IN=>{a=>"0\n3\n1"}}, {IN=>{b=>"2\n3"}}, {EXIT=>1},
+    {OUT => "0\n\t2\n\t\t3\n1\n"},
+    {ERR => "$prog: file 1 is not in sorted order\n"}],
+
+   # second input out-of-order extended
+   ['ooo5c', {IN=>{a=>"0\n3"}}, {IN=>{b=>"2\n3\n1"}}, {EXIT=>1},
+    {OUT => "0\n\t2\n\t\t3\n\t1\n"},
+    {ERR => "$prog: file 2 is not in sorted order\n"}],
+
+   # both inputs out-of-order, but fully pairable
+   ['ooo6', {IN=>{a=>"2\n1\n0"}}, {IN=>{b=>"2\n1\n0"}}, {EXIT=>0},
+    {OUT => "\t\t2\n\t\t1\n\t\t0\n"}],
+
+   # both inputs out-of-order, fully pairable, but forced to fail
+   ['ooo7', '--check-order', {IN=>{a=>"2\n1\n0"}}, {IN=>{b=>"2\n1\n0"}},
+    {EXIT=>1},
+    {OUT => "\t\t2\n"},
+    {ERR => "$prog: file 1 is not in sorted order\n"}],
+ );
+
+my $save_temps = $ENV{DEBUG};
+my $verbose = $ENV{VERBOSE};
+
+my $fail = run_tests ($program_name, $prog, address@hidden, $save_temps, 
$verbose);
+exit $fail;
--
1.5.6.rc2.17.ge9e7


>From 81d0c8f367c89a52e41bbd89e7c45d2b1ac495f2 Mon Sep 17 00:00:00 2001
From: Bo Borgerson <address@hidden>
Date: Tue, 22 Apr 2008 23:47:42 -0400
Subject: [PATCH] comm: accept new option: --output-delimiter=STR

* src/comm.c (delimiter): New global.
(writeline): Use delimiter string instead of single TAB character.
(main): Initialize delimiter.
* tests/misc/comm: Add tests for comm output delimiter specification.
* doc/coreutils.texi: Document new option.
* NEWS: Advertise new option.
* TODO: Remove associated item.
---
 NEWS               |    3 +++
 TODO               |    5 -----
 doc/coreutils.texi |    9 ++++++++-
 src/comm.c         |   41 ++++++++++++++++++++++++++++++++++-------
 tests/misc/comm    |   21 +++++++++++++++++++++
 5 files changed, 66 insertions(+), 13 deletions(-)

diff --git a/NEWS b/NEWS
index ba39d2f..ce14695 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,9 @@ GNU coreutils NEWS                                    -*- 
outline -*-
   comm now verifies that the inputs are in sorted order.  This check can
   be turned off with the --nocheck-order option.

+  comm accepts new option, --output-delimiter=STR, that allows specification
+  of an output delimiter other than the default single TAB.
+
   md5sum now accepts the new option, --quiet, to suppress the printing of
   'OK' messages.  sha1sum, sha224sum, sha384sum, and sha512sum accept it, too.

diff --git a/TODO b/TODO
index a48a8e6..81add20 100644
--- a/TODO
+++ b/TODO
@@ -20,11 +20,6 @@ cp --recursive: use fts and *at functions to perform 
directory traversals
   become very long, and requires space and time that is quadratic in the
   depth of the hierarchy.  [Bo Borgerson is working on this]

-comm: add an option, --output-delimiter=STR
-  Files to change: src/comm.c, ChangeLog, NEWS, doc/coreutils.texi,
-  Add a new file, tests/misc/comm (use another file in that directory as
-  a template), to exercise the new option.  Suggestion from Dan Jacobson.
-
 printf:
   Now that gnulib supports *printf("%a"), import one of the
   *printf-posix modules so that printf(1) will support %a even on
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 3bedd73..d05577d 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -4473,8 +4473,15 @@ Fail with an error message if either input file is 
wrongly ordered.
 @item --nocheck-order
 Do not check that both input files are in sorted order.

address@hidden table
+Other options are:
+
address@hidden address@hidden
+Print @var{str} between adjacent output columns,
+rather than the default of a single TAB character.

+The delimiter @var{str} may not be empty.
+
address@hidden table

 @node tsort invocation
 @section @command{tsort}: Topological sort
diff --git a/src/comm.c b/src/comm.c
index 01c0b8c..9742fb3 100644
--- a/src/comm.c
+++ b/src/comm.c
@@ -65,10 +65,18 @@ static enum
     CHECK_ORDER_DISABLED
   } check_input_order;

+/* Output columns will be delimited with this string, which may be set
+   on the command-line with --output-delimiter=STR.  The default is a
+   single TAB character. */
+static char const *delimiter;
+
+/* For long options that have no equivalent short option, use a
+   non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
 enum
 {
   CHECK_ORDER_OPTION = CHAR_MAX + 1,
-  NOCHECK_ORDER_OPTION
+  NOCHECK_ORDER_OPTION,
+  OUTPUT_DELIMITER_OPTION
 };


@@ -76,6 +84,7 @@ static struct option const long_options[] =
 {
   {"check-order", no_argument, NULL, CHECK_ORDER_OPTION},
   {"nocheck-order", no_argument, NULL, NOCHECK_ORDER_OPTION},
+  {"output-delimiter", required_argument, NULL, OUTPUT_DELIMITER_OPTION},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -116,6 +125,9 @@ and column three contains lines common to both files.\n\
                       if all input lines are pairable\n\
   --nocheck-order   do not check that the input is correctly sorted\n\
 "), stdout);
+      fputs (_("\
+  --output-delimiter=STR  separate columns with STR\n\
+"), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
       emit_bug_reporting_address ();
@@ -141,20 +153,20 @@ writeline (const struct linebuffer *line, FILE *stream, 
int class)
     case 2:
       if (!only_file_2)
        return;
-      /* Print a TAB if we are printing lines from file 1.  */
+      /* Print a delimiter if we are printing lines from file 1.  */
       if (only_file_1)
-       putc ('\t', stream);
+       fputs (delimiter, stream);
       break;

     case 3:
       if (!both)
        return;
-      /* Print a TAB if we are printing lines from file 1.  */
+      /* Print a delimiter if we are printing lines from file 1.  */
       if (only_file_1)
-       putc ('\t', stream);
-      /* Print a TAB if we are printing lines from file 2.  */
+       fputs (delimiter, stream);
+      /* Print a delimiter if we are printing lines from file 2.  */
       if (only_file_2)
-       putc ('\t', stream);
+       fputs (delimiter, stream);
       break;
     }

@@ -379,6 +391,17 @@ main (int argc, char **argv)
        check_input_order = CHECK_ORDER_ENABLED;
        break;

+      case OUTPUT_DELIMITER_OPTION:
+       if (delimiter && !STREQ (delimiter, optarg))
+         error (EXIT_FAILURE, 0, _("multiple delimiters specified"));
+       delimiter = optarg;
+       if (!*delimiter)
+         {
+           error (EXIT_FAILURE, 0, _("empty %s not allowed"),
+                  quote ("--output-delimiter"));
+         }
+       break;
+
       case_GETOPT_HELP_CHAR;

       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -402,6 +425,10 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }

+  /* The default delimiter is a TAB. */
+  if (!delimiter)
+    delimiter = "\t";
+
   compare_files (argv + optind);

   if (issued_disorder_warning[0] || issued_disorder_warning[1])
diff --git a/tests/misc/comm b/tests/misc/comm
index 39557d2..81a8529 100755
--- a/tests/misc/comm
+++ b/tests/misc/comm
@@ -115,6 +115,27 @@ my @Tests =
     {EXIT=>1},
     {OUT => "\t\t2\n"},
     {ERR => "$prog: file 1 is not in sorted order\n"}],
+
+   # alternate delimiter: ','
+   ['delim-comma', '--output-delimiter=,', @inputs,
+    {OUT=>"1\n,2\n,,3\n"} ],
+
+   # two-character alternate delimiter: '++'
+   ['delim-2char', '--output-delimiter=++', @inputs,
+    {OUT=>"1\n++2\n++++3\n"} ],
+
+   # invalid empty delimiter
+   ['delim-empty', '--output-delimiter=', @inputs, {EXIT=>1},
+    {ERR => "$prog: empty `--output-delimiter' not allowed\n"}],
+
+   # invalid dual delimiter
+   ['delim-dual', '--output-delimiter=,', '--output-delimiter=+',
+    @inputs, {EXIT=>1}, {ERR => "$prog: multiple delimiters specified\n"}],
+
+   # valid dual delimiter specification
+   ['delim-dual2', '--output-delimiter=,', '--output-delimiter=,', @inputs,
+    {OUT=>"1\n,2\n,,3\n"} ],
+
  );

 my $save_temps = $ENV{DEBUG};
--
1.5.6.rc2.17.ge9e7


>From 3808eccbbf7086f1289fe391fe861ec1966645d6 Mon Sep 17 00:00:00 2001
From: Jim Meyering <address@hidden>
Date: Thu, 12 Jun 2008 21:38:17 +0200
Subject: [PATCH] tweak to conform with syntax policy

Use "<" or "<=" rather than ">" or ">=".
Use "Type const *", rather than "const Type *".
---
 src/comm.c |   16 ++++++++--------
 1 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/comm.c b/src/comm.c
index 9742fb3..2bf8761 100644
--- a/src/comm.c
+++ b/src/comm.c
@@ -141,7 +141,7 @@ and column three contains lines common to both files.\n\
    2 for a line only in file 2, 3 for a line in both. */

 static void
-writeline (const struct linebuffer *line, FILE *stream, int class)
+writeline (struct linebuffer const *line, FILE *stream, int class)
 {
   switch (class)
     {
@@ -185,8 +185,8 @@ writeline (const struct linebuffer *line, FILE *stream, int 
class)
    This funtion was copied (nearly) verbatim from `src/join.c'. */

 static void
-check_order (const struct linebuffer *prev,
-            const struct linebuffer *current,
+check_order (struct linebuffer const *prev,
+            struct linebuffer const *current,
             int whatfile)
 {

@@ -206,7 +206,7 @@ check_order (const struct linebuffer *prev,
              order = memcmp (prev->buffer, current->buffer, len);
            }

-         if (order > 0)
+         if (0 < order)
            {
              error ((check_input_order == CHECK_ORDER_ENABLED
                      ? EXIT_FAILURE : 0),
@@ -301,15 +301,15 @@ compare_files (char **infiles)
       else
        {
          seen_unpairable = true;
-         if (order > 0)
-           writeline (thisline[1], stdout, 2);
-         else
+         if (order <= 0)
            writeline (thisline[0], stdout, 1);
+         else
+           writeline (thisline[1], stdout, 2);
        }

       /* Step the file the line came from.
         If the files match, step both files.  */
-      if (order >= 0)
+      if (0 <= order)
        fill_up[1] = true;
       if (order <= 0)
        fill_up[0] = true;
--
1.5.6.rc2.17.ge9e7




reply via email to

[Prev in Thread] Current Thread [Next in Thread]