On 7/26/21 8:00 AM, Pádraig Brady wrote:
So I'd have a slight preference for --zero.
Also what about having --zero imply:
--quoting-style=literal --show-control-chars --format=single-column
That seems like a fine shortcut given that would be correct in the vast
majority of cases,
and that the need for the above may not be obvious to users.
Also a small point; should --dired disable --null as it may then be non
parseable?
Thanks, all good suggestions. For --dired vs --zero I thought it better
simply to prohibit the combination since neither should be in 'ls' shell
aliases, and prohibiting means we can add it later if we like. I
installed the attached patches to do this (plus the other stuff I
mentioned in my reply to Berny).
The first patch is a cleanup because I had a bit of trouble following
the forest of 'if's inside of ls.c's decode_switches function and I
thought it better to avoid unnecessary syscalls while I was at it.
The second patch does the real work.
>From 9e4a6101f239b8168144078edd04843dea4dc69f Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Tue, 27 Jul 2021 14:27:00 -0700
Subject: [PATCH 1/2] ls: compute defaults more lazily
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* src/ls.c (enum time_type, enum sort_type, enum indicator_style)
(enum Dereference_symlink, ignore_mode):
Put ‘= 0’ after default values, since the code relies
on static storage defaulting to zero.
(enum sort_type): Reorder so that -1 can be used to represent unset.
(main): Test print_with_color after parse_ls_color may have reset it.
(decode_line_length): Return the line length instead of setting
static storage. All uses changed. Treat line lengths exceeding
PTRDIFF_MAX as infinite, to avoid pointer-subtraction glitches.
(stdout_isatty): New function, to avoid calling isatty twice.
(decode_switches): Calculate defaults more lazily, to avoid using
syscalls or getenv during startup unless the results are more
likely to be needed. Use -1 to indicate options that haven’t been
set on the command line yet. Move print_with_color test from
here to ‘main’. Suppress bogus GCC warning.
(getenv_quoting_style): Return the quoting style instead of
setting static storage.
(init_column_info): New arg MAX_COLS, to avoid recalculating it.
Caller changed.
---
src/ls.c | 395 ++++++++++++++++++++++++++++---------------------------
1 file changed, 200 insertions(+), 195 deletions(-)
diff --git a/src/ls.c b/src/ls.c
index 61759fde9..42333978e 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -304,7 +304,7 @@ static void queue_directory (char const *name, char const *realname,
static void sort_files (void);
static void parse_ls_color (void);
-static void getenv_quoting_style (void);
+static int getenv_quoting_style (void);
static size_t quote_name_width (char const *name,
struct quoting_options const *options,
@@ -463,7 +463,7 @@ ARGMATCH_VERIFY (time_style_args, time_style_types);
enum time_type
{
- time_mtime, /* default */
+ time_mtime = 0, /* default */
time_ctime, /* -c */
time_atime, /* -u */
time_btime, /* birth time */
@@ -478,13 +478,13 @@ static enum time_type time_type;
enum sort_type
{
- sort_none = -1, /* -U */
- sort_name, /* default */
+ sort_name = 0, /* default */
sort_extension, /* -X */
sort_width,
sort_size, /* -S */
sort_version, /* -v */
- sort_time, /* -t */
+ sort_time, /* -t; must be second to last */
+ sort_none, /* -U; must be last */
sort_numtypes /* the number of elements of this enum */
};
@@ -543,7 +543,7 @@ static bool dired;
enum indicator_style
{
- none, /* --indicator-style=none */
+ none = 0, /* --indicator-style=none (default) */
slash, /* -p, --indicator-style=slash */
file_type, /* --indicator-style=file-type */
classify /* -F, --indicator-style=classify */
@@ -585,7 +585,7 @@ enum when_type
enum Dereference_symlink
{
- DEREF_UNDEFINED = 1,
+ DEREF_UNDEFINED = 0, /* default */
DEREF_NEVER,
DEREF_COMMAND_LINE_ARGUMENTS, /* -H */
DEREF_COMMAND_LINE_SYMLINK_TO_DIR, /* the default, in certain cases */
@@ -683,7 +683,7 @@ static enum
{
/* Ignore files whose names start with '.', and files specified by
--hide and --ignore. */
- IGNORE_DEFAULT,
+ IGNORE_DEFAULT = 0,
/* Ignore '.', '..', and files specified by --ignore. */
IGNORE_DOT_AND_DOTDOT,
@@ -734,7 +734,7 @@ static size_t tabsize;
static bool print_dir_name;
/* The line length to use for breaking lines in many-per-line format.
- Can be set with -w. */
+ Can be set with -w. If zero, there is no limit. */
static size_t line_length;
@@ -1671,6 +1671,15 @@ main (int argc, char **argv)
/* Test print_with_color again, because the call to parse_ls_color
may have just reset it -- e.g., if LS_COLORS is invalid. */
+
+ if (print_with_color)
+ {
+ /* Don't use TAB characters in output. Some terminal
+ emulators can't handle the combination of tabs and
+ color codes on the same line. */
+ tabsize = 0;
+ }
+
if (directories_first)
check_symlink_mode = true;
else if (print_with_color)
@@ -1850,31 +1859,41 @@ main (int argc, char **argv)
return exit_status;
}
-/* Set the line length to the value given by SPEC. Return true if
- successful. 0 means no limit on line length. */
+/* Return the line length indicated by the value given by SPEC, or -1
+ if unsuccessful. 0 means no limit on line length. */
-static bool
-set_line_length (char const *spec)
+static ptrdiff_t
+decode_line_length (char const *spec)
{
uintmax_t val;
- /* Treat too-large values as if they were SIZE_MAX, which is
+ /* Treat too-large values as if they were 0, which is
effectively infinity. */
switch (xstrtoumax (spec, NULL, 0, &val, ""))
{
case LONGINT_OK:
- line_length = MIN (val, SIZE_MAX);
- return true;
+ return val <= MIN (PTRDIFF_MAX, SIZE_MAX) ? val : 0;
case LONGINT_OVERFLOW:
- line_length = SIZE_MAX;
- return true;
+ return 0;
default:
- return false;
+ return -1;
}
}
+/* Return true if standard output is a tty, caching the result. */
+
+static bool
+stdout_isatty (void)
+{
+ static signed char out_tty = -1;
+ if (out_tty < 0)
+ out_tty = isatty (STDOUT_FILENO);
+ assume (out_tty == 0 || out_tty == 1);
+ return out_tty;
+}
+
/* Set all the option flags according to the switches specified.
Return the index of the first non-option argument. */
@@ -1883,99 +1902,14 @@ decode_switches (int argc, char **argv)
{
char *time_style_option = NULL;
- bool sort_type_specified = false;
+ /* These variables are false or -1 unless a switch says otherwise. */
bool kibibytes_specified = false;
-
- qmark_funny_chars = false;
-
- /* initialize all switches to default settings */
-
- switch (ls_mode)
- {
- case LS_MULTI_COL:
- /* This is for the 'dir' program. */
- format = many_per_line;
- set_quoting_style (NULL, escape_quoting_style);
- break;
-
- case LS_LONG_FORMAT:
- /* This is for the 'vdir' program. */
- format = long_format;
- set_quoting_style (NULL, escape_quoting_style);
- break;
-
- case LS_LS:
- /* This is for the 'ls' program. */
- if (isatty (STDOUT_FILENO))
- {
- format = many_per_line;
- set_quoting_style (NULL, shell_escape_quoting_style);
- /* See description of qmark_funny_chars, above. */
- qmark_funny_chars = true;
- }
- else
- {
- format = one_per_line;
- qmark_funny_chars = false;
- }
- break;
-
- default:
- abort ();
- }
-
- time_type = time_mtime;
- sort_type = sort_name;
- sort_reverse = false;
- numeric_ids = false;
- print_block_size = false;
- indicator_style = none;
- print_inode = false;
- dereference = DEREF_UNDEFINED;
- recursive = false;
- immediate_dirs = false;
- ignore_mode = IGNORE_DEFAULT;
- ignore_patterns = NULL;
- hide_patterns = NULL;
- print_scontext = false;
-
- getenv_quoting_style ();
-
- line_length = 80;
- {
- char const *p = getenv ("COLUMNS");
- if (p && *p && ! set_line_length (p))
- error (0, 0,
- _("ignoring invalid width in environment variable COLUMNS: %s"),
- quote (p));
- }
-
-#ifdef TIOCGWINSZ
- {
- struct winsize ws;
-
- if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws) != -1
- && 0 < ws.ws_col && ws.ws_col == (size_t) ws.ws_col)
- line_length = ws.ws_col;
- }
-#endif
-
- {
- char const *p = getenv ("TABSIZE");
- tabsize = 8;
- if (p)
- {
- uintmax_t tmp;
- if (xstrtoumax (p, NULL, 0, &tmp, "") == LONGINT_OK
- && tmp <= SIZE_MAX)
- tabsize = tmp;
- else
- error (0, 0,
- _("ignoring invalid tab size in environment variable TABSIZE:"
- " %s"),
- quote (p));
- }
- }
+ int format_opt = -1;
+ int hide_control_chars_opt = -1;
+ int quoting_style_opt = -1;
+ int sort_opt = -1;
+ ptrdiff_t tabsize_opt = -1;
+ ptrdiff_t width_opt = -1;
while (true)
{
@@ -1993,7 +1927,7 @@ decode_switches (int argc, char **argv)
break;
case 'b':
- set_quoting_style (NULL, escape_quoting_style);
+ quoting_style_opt = escape_quoting_style;
break;
case 'c':
@@ -2007,11 +1941,10 @@ decode_switches (int argc, char **argv)
case 'f':
/* Same as enabling -a -U and disabling -l -s. */
ignore_mode = IGNORE_MINIMAL;
- sort_type = sort_none;
- sort_type_specified = true;
+ sort_opt = sort_none;
/* disable -l */
- if (format == long_format)
- format = (isatty (STDOUT_FILENO) ? many_per_line : one_per_line);
+ if (format_opt == long_format)
+ format_opt = -1;
print_block_size = false; /* disable -s */
print_with_color = false; /* disable --color */
print_hyperlink = false; /* disable --hyperlink */
@@ -2022,7 +1955,7 @@ decode_switches (int argc, char **argv)
break;
case 'g':
- format = long_format;
+ format_opt = long_format;
print_owner = false;
break;
@@ -2041,20 +1974,20 @@ decode_switches (int argc, char **argv)
break;
case 'l':
- format = long_format;
+ format_opt = long_format;
break;
case 'm':
- format = with_commas;
+ format_opt = with_commas;
break;
case 'n':
numeric_ids = true;
- format = long_format;
+ format_opt = long_format;
break;
case 'o': /* Just like -l, but don't display group info. */
- format = long_format;
+ format_opt = long_format;
print_group = false;
break;
@@ -2063,7 +1996,7 @@ decode_switches (int argc, char **argv)
break;
case 'q':
- qmark_funny_chars = true;
+ hide_control_chars_opt = true;
break;
case 'r':
@@ -2075,8 +2008,7 @@ decode_switches (int argc, char **argv)
break;
case 't':
- sort_type = sort_time;
- sort_type_specified = true;
+ sort_opt = sort_time;
break;
case 'u':
@@ -2084,18 +2016,18 @@ decode_switches (int argc, char **argv)
break;
case 'v':
- sort_type = sort_version;
- sort_type_specified = true;
+ sort_opt = sort_version;
break;
case 'w':
- if (! set_line_length (optarg))
+ width_opt = decode_line_length (optarg);
+ if (width_opt < 0)
die (LS_FAILURE, 0, "%s: %s", _("invalid line width"),
quote (optarg));
break;
case 'x':
- format = horizontal;
+ format_opt = horizontal;
break;
case 'A':
@@ -2108,7 +2040,7 @@ decode_switches (int argc, char **argv)
break;
case 'C':
- format = many_per_line;
+ format_opt = many_per_line;
break;
case 'D':
@@ -2125,8 +2057,7 @@ decode_switches (int argc, char **argv)
--classify=always. */
i = when_always;
- if (i == when_always
- || (i == when_if_tty && isatty (STDOUT_FILENO)))
+ if (i == when_always || (i == when_if_tty && stdout_isatty ()))
indicator_style = classify;
break;
}
@@ -2152,11 +2083,11 @@ decode_switches (int argc, char **argv)
break;
case 'N':
- set_quoting_style (NULL, literal_quoting_style);
+ quoting_style_opt = literal_quoting_style;
break;
case 'Q':
- set_quoting_style (NULL, c_quoting_style);
+ quoting_style_opt = c_quoting_style;
break;
case 'R':
@@ -2164,29 +2095,26 @@ decode_switches (int argc, char **argv)
break;
case 'S':
- sort_type = sort_size;
- sort_type_specified = true;
+ sort_opt = sort_size;
break;
case 'T':
- tabsize = xnumtoumax (optarg, 0, 0, SIZE_MAX, "",
- _("invalid tab size"), LS_FAILURE);
+ tabsize_opt = xnumtoumax (optarg, 0, 0, MIN (PTRDIFF_MAX, SIZE_MAX),
+ "", _("invalid tab size"), LS_FAILURE);
break;
case 'U':
- sort_type = sort_none;
- sort_type_specified = true;
+ sort_opt = sort_none;
break;
case 'X':
- sort_type = sort_extension;
- sort_type_specified = true;
+ sort_opt = sort_extension;
break;
case '1':
/* -1 has no effect after -l. */
- if (format != long_format)
- format = one_per_line;
+ if (format_opt != long_format)
+ format_opt = one_per_line;
break;
case AUTHOR_OPTION:
@@ -2203,8 +2131,7 @@ decode_switches (int argc, char **argv)
break;
case SORT_OPTION:
- sort_type = XARGMATCH ("--sort", optarg, sort_args, sort_types);
- sort_type_specified = true;
+ sort_opt = XARGMATCH ("--sort", optarg, sort_args, sort_types);
break;
case GROUP_DIRECTORIES_FIRST_OPTION:
@@ -2216,11 +2143,12 @@ decode_switches (int argc, char **argv)
break;
case FORMAT_OPTION:
- format = XARGMATCH ("--format", optarg, format_args, format_types);
+ format_opt = XARGMATCH ("--format", optarg, format_args,
+ format_types);
break;
case FULL_TIME_OPTION:
- format = long_format;
+ format_opt = long_format;
time_style_option = bad_cast ("full-iso");
break;
@@ -2235,16 +2163,7 @@ decode_switches (int argc, char **argv)
i = when_always;
print_with_color = (i == when_always
- || (i == when_if_tty
- && isatty (STDOUT_FILENO)));
-
- if (print_with_color)
- {
- /* Don't use TAB characters in output. Some terminal
- emulators can't handle the combination of tabs and
- color codes on the same line. */
- tabsize = 0;
- }
+ || (i == when_if_tty && stdout_isatty ()));
break;
}
@@ -2259,8 +2178,7 @@ decode_switches (int argc, char **argv)
i = when_always;
print_hyperlink = (i == when_always
- || (i == when_if_tty
- && isatty (STDOUT_FILENO)));
+ || (i == when_if_tty && stdout_isatty ()));
break;
}
@@ -2275,10 +2193,9 @@ decode_switches (int argc, char **argv)
break;
case QUOTING_STYLE_OPTION:
- set_quoting_style (NULL,
- XARGMATCH ("--quoting-style", optarg,
- quoting_style_args,
- quoting_style_vals));
+ quoting_style_opt = XARGMATCH ("--quoting-style", optarg,
+ quoting_style_args,
+ quoting_style_vals);
break;
case TIME_STYLE_OPTION:
@@ -2286,7 +2203,7 @@ decode_switches (int argc, char **argv)
break;
case SHOW_CONTROL_CHARS_OPTION:
- qmark_funny_chars = false;
+ hide_control_chars_opt = false;
break;
case BLOCK_SIZE_OPTION:
@@ -2336,19 +2253,106 @@ decode_switches (int argc, char **argv)
}
}
+
+ static signed char const default_format[] =
+ {
+ [LS_LS] = -1,
+ [LS_MULTI_COL] = many_per_line,
+ [LS_LONG_FORMAT] = long_format,
+ };
+ int form = format_opt < 0 ? default_format[ls_mode] : format_opt;
+ format = form < 0 ? (stdout_isatty () ? many_per_line : one_per_line) : form;
+
+ /* If the line length was not set by a switch but is needed to determine
+ output, go to the work of obtaining it from the environment. */
+ ptrdiff_t linelen = width_opt;
+ if (format == many_per_line || format == horizontal || format == with_commas
+ || print_with_color)
+ {
+#ifdef TIOCGWINSZ
+ if (linelen < 0)
+ {
+ /* Suppress bogus warning re comparing ws.ws_col to big integer. */
+# if __GNUC_PREREQ (4, 6)
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Wtype-limits"
+# endif
+ struct winsize ws;
+ if (stdout_isatty ()
+ && 0 <= ioctl (STDOUT_FILENO, TIOCGWINSZ, &ws)
+ && 0 < ws.ws_col)
+ linelen = ws.ws_col <= MIN (PTRDIFF_MAX, SIZE_MAX) ? ws.ws_col : 0;
+# if __GNUC_PREREQ (4, 6)
+# pragma GCC diagnostic pop
+# endif
+ }
+#endif
+ if (linelen < 0)
+ {
+ char const *p = getenv ("COLUMNS");
+ if (p && *p)
+ {
+ linelen = decode_line_length (p);
+ if (linelen < 0)
+ error (0, 0,
+ _("ignoring invalid width"
+ " in environment variable COLUMNS: %s"),
+ quote (p));
+ }
+ }
+ }
+
+ line_length = linelen < 0 ? 80 : linelen;
+
/* Determine the max possible number of display columns. */
max_idx = line_length / MIN_COLUMN_WIDTH;
/* Account for first display column not having a separator,
or line_lengths shorter than MIN_COLUMN_WIDTH. */
max_idx += line_length % MIN_COLUMN_WIDTH != 0;
- enum quoting_style qs = get_quoting_style (NULL);
- align_variable_outer_quotes = format != with_commas
- && format != one_per_line
- && (line_length || format == long_format)
- && (qs == shell_quoting_style
- || qs == shell_escape_quoting_style
- || qs == c_maybe_quoting_style);
+ if (format == many_per_line || format == horizontal || format == with_commas)
+ {
+ if (0 <= tabsize_opt)
+ tabsize = tabsize_opt;
+ else
+ {
+ tabsize = 8;
+ char const *p = getenv ("TABSIZE");
+ if (p)
+ {
+ uintmax_t tmp;
+ if (xstrtoumax (p, NULL, 0, &tmp, "") == LONGINT_OK
+ && tmp <= SIZE_MAX)
+ tabsize = tmp;
+ else
+ error (0, 0,
+ _("ignoring invalid tab size"
+ " in environment variable TABSIZE: %s"),
+ quote (p));
+ }
+ }
+ }
+
+ qmark_funny_chars = (hide_control_chars_opt < 0
+ ? ls_mode == LS_LS && stdout_isatty ()
+ : hide_control_chars_opt);
+
+ int qs = quoting_style_opt;
+ if (qs < 0)
+ qs = getenv_quoting_style ();
+ if (qs < 0)
+ qs = (ls_mode == LS_LS
+ ? (stdout_isatty () ? shell_escape_quoting_style : -1)
+ : escape_quoting_style);
+ if (0 <= qs)
+ set_quoting_style (NULL, qs);
+ qs = get_quoting_style (NULL);
+ align_variable_outer_quotes
+ = ((format == long_format
+ || ((format == many_per_line || format == horizontal) && line_length))
+ && (qs == shell_quoting_style
+ || qs == shell_escape_quoting_style
+ || qs == c_maybe_quoting_style));
filename_quoting_options = clone_quoting_options (NULL);
if (qs == escape_quoting_style)
set_char_quoting (filename_quoting_options, ' ', 1);
@@ -2376,12 +2380,11 @@ decode_switches (int argc, char **argv)
-lu means show atime and sort by name, -lut means show atime and sort
by atime. */
- if ((time_type == time_ctime || time_type == time_atime
- || time_type == time_btime)
- && !sort_type_specified && format != long_format)
- {
- sort_type = sort_time;
- }
+ sort_type = (0 <= sort_opt ? sort_opt
+ : (format != long_format
+ && (time_type == time_ctime || time_type == time_atime
+ || time_type == time_btime))
+ ? sort_time : sort_name);
if (format == long_format)
{
@@ -2856,23 +2859,25 @@ parse_ls_color (void)
color_symlink_as_referent = true;
}
-/* Set the quoting style default if the environment variable
- QUOTING_STYLE is set. */
+/* Return the quoting style specified by the environment variable
+ QUOTING_STYLE if set and valid, -1 otherwise. */
-static void
+static int
getenv_quoting_style (void)
{
char const *q_style = getenv ("QUOTING_STYLE");
- if (q_style)
+ if (!q_style)
+ return -1;
+ int i = ARGMATCH (q_style, quoting_style_args, quoting_style_vals);
+ if (i < 0)
{
- int i = ARGMATCH (q_style, quoting_style_args, quoting_style_vals);
- if (0 <= i)
- set_quoting_style (NULL, quoting_style_vals[i]);
- else
- error (0, 0,
- _("ignoring invalid value of environment variable QUOTING_STYLE: %s"),
- quote (q_style));
+ error (0, 0,
+ _("ignoring invalid value"
+ " of environment variable QUOTING_STYLE: %s"),
+ quote (q_style));
+ return -1;
}
+ return quoting_style_vals[i];
}
/* Set the exit status to report a failure. If SERIOUS, it is a
@@ -4022,14 +4027,15 @@ static qsortFunc const sort_functions[][2][2][2] =
/* The number of sort keys is calculated as the sum of
the number of elements in the sort_type enum (i.e., sort_numtypes)
- the number of elements in the time_type enum (i.e., time_numtypes) - 1
+ -2 because neither sort_time nor sort_none use entries themselves
+ the number of elements in the time_type enum (i.e., time_numtypes)
This is because when sort_type==sort_time, we have up to
time_numtypes possible sort keys.
This line verifies at compile-time that the array of sort functions has been
initialized for all possible sort keys. */
verify (ARRAY_CARDINALITY (sort_functions)
- == sort_numtypes + time_numtypes - 1 );
+ == sort_numtypes - 2 + time_numtypes);
/* Set up SORTED_FILE to point to the in-use entries in CWD_FILE, in order. */
@@ -5263,10 +5269,9 @@ attach (char *dest, char const *dirname, char const *name)
narrowest possible columns. */
static void
-init_column_info (void)
+init_column_info (size_t max_cols)
{
size_t i;
- size_t max_cols = MIN (max_idx, cwd_n_used);
/* Currently allocated columns in column_info. */
static size_t column_info_alloc;
@@ -5276,7 +5281,7 @@ init_column_info (void)
size_t new_column_info_alloc;
size_t *p;
- if (max_cols < max_idx / 2)
+ if (!max_idx || max_cols < max_idx / 2)
{
/* The number of columns is far less than the display width
allows. Grow the allocation, but only so that it's
@@ -5339,9 +5344,9 @@ calculate_columns (bool by_columns)
/* Normally the maximum number of columns is determined by the
screen width. But if few files are available this might limit it
as well. */
- size_t max_cols = MIN (max_idx, cwd_n_used);
+ size_t max_cols = 0 < max_idx && max_idx < cwd_n_used ? max_idx : cwd_n_used;
- init_column_info ();
+ init_column_info (max_cols);
/* Compute the maximum number of possible columns. */
for (filesno = 0; filesno < cwd_n_used; ++filesno)
--
2.30.2
>From c75779cac3abec6e6072c0ac77dced85d1c44370 Mon Sep 17 00:00:00 2001
From: Paul Eggert <egg...@cs.ucla.edu>
Date: Tue, 27 Jul 2021 17:34:43 -0700
Subject: [PATCH 2/2] ls: rename --null to --zero (Bug#49716)
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* NEWS, doc/coreutils.texi (General output formatting):
* src/ls.c (usage):
Document this.
* src/ls.c (ZERO_OPTION): Rename from NULL_OPTION.
All uses changed.
(long_options): Rename --null to --zero.
(dired_dump_obstack, main, print_dir): Use '\n' instead of
eolbyte where eolbyte must equal '\n'.
(decode_switches): Decode --zero instead of --null.
--zero also implies -1, -N, --color=none, --show-control-chars.
Use easier-to-decipher code to set ‘format’ and ‘dired’.
Reject attempts to combine --dired and --zero.
* tests/local.mk: Adjust to test script renaming.
* tests/ls/zero-option.sh: Rename from tests/ls/null-option.sh,
and test --zero instead of --null.
---
NEWS | 2 +-
doc/coreutils.texi | 10 +++-
src/ls.c | 57 +++++++++++----------
tests/local.mk | 4 +-
tests/ls/{null-option.sh => zero-option.sh} | 4 +-
5 files changed, 42 insertions(+), 35 deletions(-)
rename tests/ls/{null-option.sh => zero-option.sh} (92%)
diff --git a/NEWS b/NEWS
index 8de0c31bd..49ee083e4 100644
--- a/NEWS
+++ b/NEWS
@@ -83,7 +83,7 @@ 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
+ ls now accepts the --zero option, to terminate each output line with
NUL instead of newline.
nl --line-increment can now take a negative number to decrement the count.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index a7e5ecb92..2d2770864 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -8137,8 +8137,14 @@ 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
+@item --zero
+@opindex --zero
+This option is incompatible with the @option{-D} or @option{--dired} option.
+This option also implies the options
+@option{--show-control-chars},
+@option{-1} or @option{--format=single-column},
+@option{--color=none}, and
+@option{-N} or @option{--quoting-style=literal}.
@outputNUL
@item -p
diff --git a/src/ls.c b/src/ls.c
index 42333978e..7ea956227 100644
--- a/src/ls.c
+++ b/src/ls.c
@@ -838,13 +838,13 @@ enum
HIDE_OPTION,
HYPERLINK_OPTION,
INDICATOR_STYLE_OPTION,
- NULL_OPTION,
QUOTING_STYLE_OPTION,
SHOW_CONTROL_CHARS_OPTION,
SI_OPTION,
SORT_OPTION,
TIME_OPTION,
- TIME_STYLE_OPTION
+ TIME_STYLE_OPTION,
+ ZERO_OPTION,
};
static struct option const long_options[] =
@@ -859,7 +859,6 @@ 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'},
@@ -888,6 +887,7 @@ static struct option const long_options[] =
{"tabsize", required_argument, NULL, 'T'},
{"time", required_argument, NULL, TIME_OPTION},
{"time-style", required_argument, NULL, TIME_STYLE_OPTION},
+ {"zero", no_argument, NULL, ZERO_OPTION},
{"color", optional_argument, NULL, COLOR_OPTION},
{"hyperlink", optional_argument, NULL, HYPERLINK_OPTION},
{"block-size", required_argument, NULL, BLOCK_SIZE_OPTION},
@@ -1087,7 +1087,7 @@ dired_dump_obstack (char const *prefix, struct obstack *os)
intmax_t p = pos[i];
printf (" %"PRIdMAX, p);
}
- putchar (eolbyte);
+ putchar ('\n');
}
}
@@ -1777,7 +1777,7 @@ main (int argc, char **argv)
{
print_current_files ();
if (pending_dirs)
- dired_outbyte (eolbyte);
+ dired_outbyte ('\n');
}
else if (n_files <= 1 && pending_dirs && pending_dirs->next == 0)
print_dir_name = false;
@@ -1845,9 +1845,8 @@ 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%c",
- quoting_style_args[get_quoting_style (filename_quoting_options)],
- eolbyte);
+ printf ("//DIRED-OPTIONS// --quoting-style=%s\n",
+ quoting_style_args[get_quoting_style (filename_quoting_options)]);
}
if (LOOP_DETECT)
@@ -2188,10 +2187,6 @@ decode_switches (int argc, char **argv)
indicator_style_types);
break;
- case NULL_OPTION:
- eolbyte = 0;
- break;
-
case QUOTING_STYLE_OPTION:
quoting_style_opt = XARGMATCH ("--quoting-style", optarg,
quoting_style_args,
@@ -2227,6 +2222,15 @@ decode_switches (int argc, char **argv)
print_scontext = true;
break;
+ case ZERO_OPTION:
+ eolbyte = 0;
+ hide_control_chars_opt = false;
+ if (format_opt != long_format)
+ format_opt = one_per_line;
+ print_with_color = false;
+ quoting_style_opt = literal_quoting_style;
+ break;
+
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -2253,15 +2257,11 @@ decode_switches (int argc, char **argv)
}
}
-
- static signed char const default_format[] =
- {
- [LS_LS] = -1,
- [LS_MULTI_COL] = many_per_line,
- [LS_LONG_FORMAT] = long_format,
- };
- int form = format_opt < 0 ? default_format[ls_mode] : format_opt;
- format = form < 0 ? (stdout_isatty () ? many_per_line : one_per_line) : form;
+ format = (0 <= format_opt ? format_opt
+ : ls_mode == LS_LS ? (stdout_isatty ()
+ ? many_per_line : one_per_line)
+ : ls_mode == LS_MULTI_COL ? many_per_line
+ : /* ls_mode == LS_LONG_FORMAT */ long_format);
/* If the line length was not set by a switch but is needed to determine
output, go to the work of obtaining it from the environment. */
@@ -2366,11 +2366,13 @@ decode_switches (int argc, char **argv)
dirname_quoting_options = clone_quoting_options (NULL);
set_char_quoting (dirname_quoting_options, ':', 1);
- /* --dired is meaningful only with --format=long (-l).
+ /* --dired is meaningful only with --format=long (-l) and sans --hyperlink.
Otherwise, ignore it. FIXME: warn about this?
Alternatively, make --dired imply --format=long? */
- if (dired && (format != long_format || print_hyperlink))
- dired = false;
+ dired &= (format == long_format) & !print_hyperlink;
+
+ if (eolbyte < dired)
+ die (LS_FAILURE, 0, _("--dired and --zero are incompatible"));
/* If -c or -u is specified and not -l (or any other option that implies -l),
and no sort-type was specified, then sort by the ctime (-c) or atime (-u).
@@ -2980,7 +2982,7 @@ print_dir (char const *name, char const *realname, bool command_line_arg)
if (recursive || print_dir_name)
{
if (!first)
- dired_outbyte (eolbyte);
+ dired_outbyte ('\n');
first = false;
dired_indent ();
@@ -2997,8 +2999,7 @@ print_dir (char const *name, char const *realname, bool command_line_arg)
free (absolute_name);
- dired_outbyte (':');
- dired_outbyte (eolbyte);
+ dired_outstring (":\n");
}
/* Read the directory entries, and insert the subfiles into the 'cwd_file'
@@ -5488,7 +5489,6 @@ 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\
@@ -5542,6 +5542,7 @@ Sort entries alphabetically if none of -cftuvSUX nor --sort is specified.\n\
-x list entries by lines instead of by columns\n\
-X sort alphabetically by entry extension\n\
-Z, --context print any security context of each file\n\
+ --zero end each output line with NUL, not newline\n\
-1 list one file per line. Avoid '\\n' with -q or -b\
\n\
"), stdout);
diff --git a/tests/local.mk b/tests/local.mk
index 441edc1be..4a08147df 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -609,10 +609,10 @@ all_tests = \
tests/ls/getxattr-speedup.sh \
tests/ls/group-dirs.sh \
tests/ls/hex-option.sh \
+ tests/ls/hyperlink.sh \
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 \
@@ -635,7 +635,7 @@ all_tests = \
tests/ls/time-style-diag.sh \
tests/ls/sort-width-option.sh \
tests/ls/x-option.sh \
- tests/ls/hyperlink.sh \
+ tests/ls/zero-option.sh \
tests/mkdir/p-1.sh \
tests/mkdir/p-2.sh \
tests/mkdir/p-3.sh \
diff --git a/tests/ls/null-option.sh b/tests/ls/zero-option.sh
similarity index 92%
rename from tests/ls/null-option.sh
rename to tests/ls/zero-option.sh
index fbf64e16d..a6883917f 100755
--- a/tests/ls/null-option.sh
+++ b/tests/ls/zero-option.sh
@@ -1,5 +1,5 @@
#!/bin/sh
-# Verify behavior of ls --null.
+# Verify behavior of ls --zero.
# Copyright 2021 Free Software Foundation, Inc.
@@ -21,7 +21,7 @@ print_ver_ ls
mkdir dir && touch dir/a dir/b dir/cc || framework_failure_
-LC_ALL=C ls --null dir >out || fail=1
+LC_ALL=C ls --zero dir >out || fail=1
tr '\n' '\0' <<EOF >exp
a
b
--
2.30.2