Subject: Re: bug#10983: ready for a release?

From: Pádraig Brady <[email-masked]>
Date: Fri, 09 Mar 2012 23:08:59 +0000

On 03/09/2012 06:18 PM, Pádraig Brady wrote:
> tag 10983 notabug
> 
> On 03/09/2012 05:47 PM, Jim Meyering wrote:
>> There are more than enough new features to justify a release,
>> not to mention the three bug fixes.
>>
>> Anything worth waiting for?
> 
> Well the dirname multi argument processing to
> complement the basename seems simple and
> worth waiting for.

Attached.

cheers,
Pádraig.
>From 28134d1e9a949ccd30710a533528a6a5dbfcf13f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Compostella?=
 <[email-masked]>
Date: Fri, 9 Mar 2012 19:21:42 +0100
Subject: [PATCH] dirname: support more than one argument

* src/dirname.c (main): Handle new -z option and manage more than one
  argument.
* doc/coreutils.texi (dirname invocation): Mention it.
* NEWS (New features): Mention it.
* tests/misc/dirname: Add a two arguments test.
---
 NEWS               |    3 ++
 doc/coreutils.texi |   26 +++++++++++++-----
 src/dirname.c      |   77 +++++++++++++++++++++++++++++++++------------------
 tests/misc/dirname |    3 +-
 4 files changed, 73 insertions(+), 36 deletions(-)

diff --git a/NEWS b/NEWS
index 7f36dc6..829d626 100644
--- a/NEWS
+++ b/NEWS
@@ -35,6 +35,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   of more than one argument at a time.  Also the complementary
   -z option was added to delimit output items with the NUL character.
 
+  dirname now supports more than one argument.  Also the complementary
+  -z option was added to delimit output items with the NUL character.
+
 ** Bug fixes
 
   du --one-file-system (-x) would ignore any non-directory specified on
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index cce9432..49f2141 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -12501,13 +12501,13 @@ basename -a -s .h include/stdio.h include/stdlib.h
 @cindex stripping non-directory suffix
 @cindex non-directory suffix, stripping
 
-@command{dirname} prints all but the final slash-delimited component of
-@var{name}.  Slashes on either side of the final component are also
-removed.  If the string contains no slash, @command{dirname} prints
-@samp{.} (meaning the current directory).  Synopsis:
+@command{dirname} prints all but the final slash-delimited component
+of each @var{name}.  Slashes on either side of the final component are
+also removed.  If the string contains no slash, @command{dirname}
+prints @samp{.} (meaning the current directory).  Synopsis:
 
 @example
-dirname @var{name}
+dirname [@var{option}] @var{name}...
 @end example
 
 @var{name} need not be a file name, but if it is, this operation
@@ -12521,8 +12521,17 @@ including the case when the final component is itself a directory.
 result is @samp{//} on platforms where @var{//} is distinct from
 @var{/}, and @samp{/} on platforms where there is no difference.
 
-The only options are @option{--help} and @option{--version}.  @xref{Common
-options}.
+The program accepts the following option.  Also see @ref{Common options}.
+
+@table @samp
+
+@item -z
+@itemx --zero
+@opindex -z
+@opindex --zero
+Separate output items with @sc{nul} characters.
+
+@end table
 
 @exitstatus
 
@@ -12533,6 +12542,9 @@ Examples:
 dirname /usr/bin/sort
 dirname /usr/bin//.//
 
+# Output "dir1" followed by "dir2"
+dirname dir1/str dir2/str
+
 # Output ".".
 dirname stdio.h
 @end smallexample
diff --git a/src/dirname.c b/src/dirname.c
index 3637a04..ac218d5 100644
--- a/src/dirname.c
+++ b/src/dirname.c
@@ -23,9 +23,7 @@
 #include <sys/types.h>
 
 #include "system.h"
-#include "long-options.h"
 #include "error.h"
-#include "quote.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
 #define PROGRAM_NAME "dirname"
@@ -34,6 +32,14 @@
   proper_name ("David MacKenzie"), \
   proper_name ("Jim Meyering")
 
+static struct option const longopts[] =
+{
+  {"zero", no_argument, NULL, 'z'},
+  {GETOPT_HELP_OPTION_DECL},
+  {GETOPT_VERSION_OPTION_DECL},
+  {NULL, 0, NULL, 0}
+};
+
 void
 usage (int status)
 {
@@ -42,24 +48,27 @@ usage (int status)
   else
     {
       printf (_("\
-Usage: %s NAME\n\
-  or:  %s OPTION\n\
+Usage: %s [OPTION] NAME...\n\
 "),
-              program_name, program_name);
+              program_name);
       fputs (_("\
-Output NAME with its last non-slash component and trailing slashes removed;\n\
-if NAME contains no /'s, output '.' (meaning the current directory).\n\
+Output each NAME with its last non-slash component and trailing slashes\n\
+removed; if NAME contains no /'s, output '.' (meaning the current directory).\n\
 \n\
 "), stdout);
+      fputs (_("\
+  -z, --zero     separate output with NUL rather than newline\n\
+"), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
       printf (_("\
 \n\
 Examples:\n\
-  %s /usr/bin/      Output \"/usr\".\n\
-  %s stdio.h        Output \".\".\n\
+  %s /usr/bin/          -> \"/usr\"\n\
+  %s dir1/str dir2/str  -> \"dir1\" followed by \"dir2\"\n\
+  %s stdio.h            -> \".\"\n\
 "),
-              program_name, program_name);
+              program_name, program_name, program_name);
       emit_ancillary_info ();
     }
   exit (status);
@@ -69,6 +78,7 @@ int
 main (int argc, char **argv)
 {
   static char const dot = '.';
+  bool use_nuls = false;
   char const *result;
   size_t len;
 
@@ -80,10 +90,26 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, Version,
-                      usage, AUTHORS, (char const *) NULL);
-  if (getopt_long (argc, argv, "+", NULL, NULL) != -1)
-    usage (EXIT_FAILURE);
+  while (true)
+    {
+      int c = getopt_long (argc, argv, "z", longopts, NULL);
+
+      if (c == -1)
+        break;
+
+      switch (c)
+        {
+        case 'z':
+          use_nuls = true;
+          break;
+
+        case_GETOPT_HELP_CHAR;
+        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+
+        default:
+          usage (EXIT_FAILURE);
+        }
+    }
 
   if (argc < optind + 1)
     {
@@ -91,23 +117,20 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
-  if (optind + 1 < argc)
+  for (; optind < argc; optind++)
     {
-      error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
-      usage (EXIT_FAILURE);
-    }
+      result = argv[optind];
+      len = dir_len (result);
 
-  result = argv[optind];
-  len = dir_len (result);
+      if (! len)
+        {
+          result = &dot;
+          len = 1;
+        }
 
-  if (! len)
-    {
-      result = &dot;
-      len = 1;
+      fwrite (result, 1, len, stdout);
+      putchar (use_nuls ? '\0' :'\n');
     }
 
-  fwrite (result, 1, len, stdout);
-  putchar ('\n');
-
   exit (EXIT_SUCCESS);
 }
diff --git a/tests/misc/dirname b/tests/misc/dirname
index 37cf7cf..0021836 100755
--- a/tests/misc/dirname
+++ b/tests/misc/dirname
@@ -35,8 +35,6 @@ my @Tests =
     (
      ['fail-1', {ERR => "$prog: missing operand\n"
        . "Try '$prog --help' for more information.\n"}, {EXIT => '1'}],
-     ['fail-2', qw(a b), {ERR => "$prog: extra operand 'b'\n"
-       . "Try '$prog --help' for more information.\n"}, {EXIT => '1'}],
 
      ['a', qw(d/f),        {OUT => 'd'}],
      ['b', qw(/d/f),       {OUT => '/d'}],
@@ -51,6 +49,7 @@ my @Tests =
      ['k', qw(///a///b),   {OUT => '///a'}],
      ['l', qw(///a//b/),   {OUT => '///a'}],
      ['m', qw(''),         {OUT => '.'}],
+     ['n', qw(a/b c/d),    {OUT => "a\nc"}],
     );
 
 # Append a newline to end of each expected 'OUT' string.
-- 
1.7.6.4