]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
ls: add --null option (Bug#49716)
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 26 Jul 2021 04:24:02 +0000 (21:24 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 26 Jul 2021 07:59:37 +0000 (00:59 -0700)
* NEWS, doc/coreutils.texi (General output formatting):
* src/ls.c (usage): Document this.
* src/ls.c (NULL_OPTION): New constant.
(long_options): Add --null.
(eolbyte): New static var.
(dired_dump_obstack, main, print_dir, print_current_files)
(print_many_per_line, print_horizontal, print_with_separator):
Output eolbyte instead of '\n'.
(decode_switches): Decode --null.
* tests/ls/null-option.sh: New file.
* tests/local.mk (all_tests): Add it.

NEWS
doc/coreutils.texi
src/ls.c
tests/local.mk
tests/ls/null-option.sh [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index 5a1a98acebf5dfa143b3b4848a1bfeb44f7a61fe..8de0c31bd66159280045c6f2d55fab69beec5ab3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -83,6 +83,9 @@ GNU coreutils NEWS                                    -*- outline -*-
   ls now accepts the --sort=width option, to sort by file name width.
   This is useful to more compactly organize the default vertical column output.
 
+  ls now accepts the --null option, to terminate each output line with
+  NUL instead of newline.
+
   nl --line-increment can now take a negative number to decrement the count.
 
   stat supports more formats for representing decomposed device numbers.
index ea040458e0b33a8d239e4e16a4d55f90ee7778ec..a7e5ecb9257b103e540c716ad1f5a36d017f5998 100644 (file)
@@ -8137,6 +8137,10 @@ option.  It does not affect the file size written by @option{-l}.
 List files horizontally, with as many as will fit on each line,
 separated by @samp{, } (a comma and a space).
 
+@item --null
+@opindex --null
+@outputNUL
+
 @item -p
 @itemx --indicator-style=slash
 @opindex -p
index e442118ece44bb8f491037479896c8967266e803..61759fde913e666cd69b44b046338fd6704b60c4 100644 (file)
--- a/src/ls.c
+++ b/src/ls.c
@@ -838,6 +838,7 @@ enum
   HIDE_OPTION,
   HYPERLINK_OPTION,
   INDICATOR_STYLE_OPTION,
+  NULL_OPTION,
   QUOTING_STYLE_OPTION,
   SHOW_CONTROL_CHARS_OPTION,
   SI_OPTION,
@@ -858,6 +859,7 @@ static struct option const long_options[] =
   {"human-readable", no_argument, NULL, 'h'},
   {"inode", no_argument, NULL, 'i'},
   {"kibibytes", no_argument, NULL, 'k'},
+  {"null", no_argument, NULL, NULL_OPTION},
   {"numeric-uid-gid", no_argument, NULL, 'n'},
   {"no-group", no_argument, NULL, 'G'},
   {"hide-control-chars", no_argument, NULL, 'q'},
@@ -1065,6 +1067,8 @@ assert_matching_dev_ino (char const *name, struct dev_ino di)
   assert (sb.st_ino == di.st_ino);
 }
 
+static char eolbyte = '\n';
+
 /* Write to standard output PREFIX, followed by the quoting style and
    a space-separated list of the integers stored in OS all on one line.  */
 
@@ -1083,7 +1087,7 @@ dired_dump_obstack (char const *prefix, struct obstack *os)
           intmax_t p = pos[i];
           printf (" %"PRIdMAX, p);
         }
-      putchar ('\n');
+      putchar (eolbyte);
     }
 }
 
@@ -1764,7 +1768,7 @@ main (int argc, char **argv)
     {
       print_current_files ();
       if (pending_dirs)
-        dired_outbyte ('\n');
+        dired_outbyte (eolbyte);
     }
   else if (n_files <= 1 && pending_dirs && pending_dirs->next == 0)
     print_dir_name = false;
@@ -1832,8 +1836,9 @@ main (int argc, char **argv)
       /* No need to free these since we're about to exit.  */
       dired_dump_obstack ("//DIRED//", &dired_obstack);
       dired_dump_obstack ("//SUBDIRED//", &subdired_obstack);
-      printf ("//DIRED-OPTIONS// --quoting-style=%s\n",
-              quoting_style_args[get_quoting_style (filename_quoting_options)]);
+      printf ("//DIRED-OPTIONS// --quoting-style=%s%c",
+              quoting_style_args[get_quoting_style (filename_quoting_options)],
+              eolbyte);
     }
 
   if (LOOP_DETECT)
@@ -2265,6 +2270,10 @@ decode_switches (int argc, char **argv)
                                        indicator_style_types);
           break;
 
+        case NULL_OPTION:
+          eolbyte = 0;
+          break;
+
         case QUOTING_STYLE_OPTION:
           set_quoting_style (NULL,
                              XARGMATCH ("--quoting-style", optarg,
@@ -2966,7 +2975,7 @@ print_dir (char const *name, char const *realname, bool command_line_arg)
   if (recursive || print_dir_name)
     {
       if (!first)
-        dired_outbyte ('\n');
+        dired_outbyte (eolbyte);
       first = false;
       dired_indent ();
 
@@ -2983,7 +2992,8 @@ print_dir (char const *name, char const *realname, bool command_line_arg)
 
       free (absolute_name);
 
-      dired_outstring (":\n");
+      dired_outbyte (':');
+      dired_outbyte (eolbyte);
     }
 
   /* Read the directory entries, and insert the subfiles into the 'cwd_file'
@@ -3073,7 +3083,7 @@ print_dir (char const *name, char const *realname, bool command_line_arg)
                                 ST_NBLOCKSIZE, output_block_size);
       char *pend = p + strlen (p);
       *--p = ' ';
-      *pend++ = '\n';
+      *pend++ = eolbyte;
       dired_indent ();
       dired_outstring (_("total"));
       dired_outbuf (p, pend - p);
@@ -4103,7 +4113,7 @@ print_current_files (void)
       for (i = 0; i < cwd_n_used; i++)
         {
           print_file_name_and_frills (sorted_file[i], 0);
-          putchar ('\n');
+          putchar (eolbyte);
         }
       break;
 
@@ -4130,7 +4140,7 @@ print_current_files (void)
         {
           set_normal_color ();
           print_long_format (sorted_file[i]);
-          dired_outbyte ('\n');
+          dired_outbyte (eolbyte);
         }
       break;
     }
@@ -5121,7 +5131,7 @@ print_many_per_line (void)
           indent (pos + name_length, pos + max_name_length);
           pos += max_name_length;
         }
-      putchar ('\n');
+      putchar (eolbyte);
     }
 }
 
@@ -5146,7 +5156,7 @@ print_horizontal (void)
 
       if (col == 0)
         {
-          putchar ('\n');
+          putchar (eolbyte);
           pos = 0;
         }
       else
@@ -5161,7 +5171,7 @@ print_horizontal (void)
       name_length = length_of_file_name_and_frills (f);
       max_name_length = line_fmt->col_arr[col];
     }
-  putchar ('\n');
+  putchar (eolbyte);
 }
 
 /* Output name + SEP + ' '.  */
@@ -5191,7 +5201,7 @@ print_with_separator (char sep)
           else
             {
               pos = 0;
-              separator = '\n';
+              separator = eolbyte;
             }
 
           putchar (sep);
@@ -5201,7 +5211,7 @@ print_with_separator (char sep)
       print_file_name_and_frills (f, pos);
       pos += len;
     }
-  putchar ('\n');
+  putchar (eolbyte);
 }
 
 /* Assuming cursor is at position FROM, indent up to position TO.
@@ -5473,6 +5483,7 @@ Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\n\
 \n\
 "), stdout);
       fputs (_("\
+      --null                 end each output line with NUL, not newline\n\
   -n, --numeric-uid-gid      like -l, but list numeric user and group IDs\n\
   -N, --literal              print entry names without quoting\n\
   -o                         like -l, but do not list group information\n\
index 81be52a345e2f2da46b40e50088f4eaf94a9dbe1..441edc1be0f0a3617320f648dda802e14a742b38 100644 (file)
@@ -612,6 +612,7 @@ all_tests =                                 \
   tests/ls/infloop.sh                          \
   tests/ls/inode.sh                            \
   tests/ls/m-option.sh                         \
+  tests/ls/null-option.sh                      \
   tests/ls/w-option.sh                         \
   tests/ls/multihardlink.sh                    \
   tests/ls/no-arg.sh                           \
diff --git a/tests/ls/null-option.sh b/tests/ls/null-option.sh
new file mode 100755 (executable)
index 0000000..fbf64e1
--- /dev/null
@@ -0,0 +1,33 @@
+#!/bin/sh
+# Verify behavior of ls --null.
+
+# Copyright 2021 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 <https://www.gnu.org/licenses/>.
+
+. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
+print_ver_ ls
+
+mkdir dir && touch dir/a dir/b dir/cc || framework_failure_
+
+LC_ALL=C ls --null dir >out || fail=1
+tr '\n' '\0' <<EOF >exp
+a
+b
+cc
+EOF
+
+compare exp out || fail=1
+
+Exit $fail