Hey Pádraig,

I'm 99% sure you meant to do 'dirname' as well in your recent patches.
But I haven't pushed this yet in case there was some reason you
avoided this one. It is mostly a copy of your 'basename' changes.

-- 8< --

* doc/coreutils.texi (terminalQuoted): New macro.
(readlink invocation, basename invocation, dirname invocation): Use it.
* src/dirname.c (quote_output): New variable.
(main): Quote output when appropriate.
* src/system.h (quoteN_mem): New macro.
* tests/misc/dirname.pl: Add test cases based on the ones added for
basename in commit e897dfd02 (basename: quote problematic names on tty,
2026-07-30). Copy some logic from tests/misc/basename.pl to test the -z
option.
* NEWS: Mention the improvement.
---
 NEWS                  |  6 +++---
 doc/coreutils.texi    | 14 +++++++++-----
 src/dirname.c         | 22 +++++++++++++++++++++-
 src/system.h          |  2 ++
 tests/misc/dirname.pl | 15 ++++++++++++++-
 5 files changed, 49 insertions(+), 10 deletions(-)

diff --git a/NEWS b/NEWS
index 3a7b175e3..a85b0ada9 100644
--- a/NEWS
+++ b/NEWS
@@ -84,9 +84,9 @@ GNU coreutils NEWS                                    -*- 
outline -*-
   'install -C' will now avoid updating file metadata when the destination
   already has the appropriate ownership and permissions.
 
-  'basename', 'du', 'readlink', and 'realpath' now quote output in shell-escape
-  style when standard output is a terminal.  The QUOTING_STYLE environment
-  variable can be used to adjust or disable the quoting.
+  'basename', 'dirname', 'du', 'readlink', and 'realpath' now quote output in
+  shell-escape style when standard output is a terminal.  The QUOTING_STYLE
+  environment variable can be used to adjust or disable the quoting.
 
   'ls -m' now quotes files names containing commas when appropriate,
   so users can better distinguish separating commas.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 441b80c3c..939b0ccae 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -11100,10 +11100,15 @@ @node readlink invocation
 
 @end table
 
+@c This is also used by basename and dirname.
+@macro terminalQuoted
 When standard output is a terminal, output is quoted using the
 @samp{shell-escape} style.  The environment variable
-@env{QUOTING_STYLE} can select the quoting style. Valid quoting styles are:
+@env{QUOTING_STYLE} specifies the quoting style.  Valid quoting styles
+are:
 @quotingStyles
+@end macro
+@terminalQuoted
 
 The @command{readlink} utility first appeared in OpenBSD 2.1.
 
@@ -14203,10 +14208,7 @@ @node basename invocation
 
 @end table
 
-When standard output is a terminal, output is quoted using the
-@samp{shell-escape} style.  The environment variable
-@env{QUOTING_STYLE} specifies the quoting style.  Valid quoting styles are:
-@quotingStyles
+@terminalQuoted
 
 @exitstatus
 
@@ -14263,6 +14265,8 @@ @node dirname invocation
 
 @end table
 
+@terminalQuoted
+
 @exitstatus
 
 Examples:
diff --git a/src/dirname.c b/src/dirname.c
index dbd21d683..1a7c61bdb 100644
--- a/src/dirname.c
+++ b/src/dirname.c
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <sys/types.h>
 
+#include "argmatch.h"  /* argmatch($QUOTING_STYLE).  */
 #include "system.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
@@ -31,6 +32,8 @@
   proper_name ("David MacKenzie"), \
   proper_name ("Jim Meyering")
 
+static bool quote_output;
+
 static struct option const longopts[] =
 {
   {"zero", no_argument, NULL, 'z'},
@@ -114,6 +117,19 @@ main (int argc, char **argv)
       usage (EXIT_FAILURE);
     }
 
+
+  if (!use_nuls && isatty (STDOUT_FILENO))
+    {
+      int qs = getenv_quoting_style ();
+      if (qs < 0)
+        qs = shell_escape_quoting_style;
+      if (qs != literal_quoting_style)
+        {
+          set_quoting_style (NULL, qs);
+          quote_output = true;
+        }
+    }
+
   for (; optind < argc; optind++)
     {
       char const *result = argv[optind];
@@ -125,7 +141,11 @@ main (int argc, char **argv)
           result = &dot;
           len = 1;
         }
-
+      if (quote_output)
+        {
+          result = quoteN_mem (result, len);
+          len = strlen (result);
+        }
       fwrite (result, 1, len, stdout);
       putchar (use_nuls ? '\0' :'\n');
     }
diff --git a/src/system.h b/src/system.h
index 7efc78972..017491d98 100644
--- a/src/system.h
+++ b/src/system.h
@@ -1004,6 +1004,8 @@ is_ENOTSUP (int err)
 
 /* Equivalent to quotearg(), but explicit to avoid syntax checks.  */
 #define quoteN(x) quotearg_style (get_quoting_style (NULL), x)
+#define quoteN_mem(x, size)                                     \
+  quotearg_style_mem (get_quoting_style (NULL), x, size)
 
 #ifdef ARGMATCH
 /* Return the quoting style specified by the environment variable
diff --git a/tests/misc/dirname.pl b/tests/misc/dirname.pl
index 47701750f..0b79cdee9 100755
--- a/tests/misc/dirname.pl
+++ b/tests/misc/dirname.pl
@@ -50,9 +50,21 @@ my @Tests =
      ['l', qw(///a//b/),   {OUT => '///a'}],
      ['m', qw(''),         {OUT => '.'}],
      ['n', qw(a/b c/d),    {OUT => "a\nc"}],
+
+     # QUOTING_STYLE does not affect redirected output.
+     ['q-lit', q{'q name/f'}, {ENV => 'QUOTING_STYLE=literal'},
+      {OUT => 'q name'}],
+     ['q-shell', q{'q name/f'}, {ENV => 'QUOTING_STYLE=shell-always'},
+      {OUT => 'q name'}],
+     ['q-invalid', q{'q name/f'}, {ENV => 'QUOTING_STYLE=invalid'},
+      {OUT => 'q name'}],
+
+     ['z-quote', q{-z 'q name/f'}, {ENV => 'QUOTING_STYLE=invalid'},
+      {OUT => "q name\0"}],
     );
 
 # Append a newline to end of each expected 'OUT' string.
+# Skip -z tests, i.e., those whose 'OUT' string has a trailing '\0'.
 my $t;
 foreach $t (@Tests)
   {
@@ -61,7 +73,8 @@ foreach $t (@Tests)
     foreach $e (@$t)
       {
         $e->{OUT} = "$e->{OUT}\n"
-          if ref $e eq 'HASH' and exists $e->{OUT};
+          if ref $e eq 'HASH' and exists $e->{OUT}
+            and not $e->{OUT} =~ /\0$/;
       }
   }
 
-- 
2.55.0


Reply via email to