From 7d44ac224c93940d1a708442c1edf1a927be7057 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 25 Jul 2021 21:24:02 -0700 Subject: [PATCH 7/7] ls: add --null option (Bug#49716) * 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 | 3 +++ doc/coreutils.texi | 4 ++++ src/ls.c | 39 +++++++++++++++++++++++++-------------- tests/local.mk | 1 + tests/ls/null-option.sh | 33 +++++++++++++++++++++++++++++++++ 5 files changed, 66 insertions(+), 14 deletions(-) create mode 100755 tests/ls/null-option.sh diff --git a/NEWS b/NEWS index 5a1a98ace..8de0c31bd 100644 --- 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. diff --git a/doc/coreutils.texi b/doc/coreutils.texi index ea040458e..a7e5ecb92 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -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 diff --git a/src/ls.c b/src/ls.c index e442118ec..61759fde9 100644 --- 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\ diff --git a/tests/local.mk b/tests/local.mk index 81be52a34..441edc1be 100644 --- a/tests/local.mk +++ b/tests/local.mk @@ -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 index 000000000..fbf64e16d --- /dev/null +++ b/tests/ls/null-option.sh @@ -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 . + +. "${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' <exp +a +b +cc +EOF + +compare exp out || fail=1 + +Exit $fail -- 2.30.2