string: Quit early if --quiet is satisfied

E.g. if we do `string match -q`, and we find a match, nothing about
the input can change anything, so we quit early.

This is mainly useful for performance, but it also allows `string`
with `-q` to be used with infinite input (e.g. `yes`).

Alternative to #7495.
This commit is contained in:
Fabian Homborg 2020-11-29 12:06:48 +01:00
parent 8f165ab26b
commit 720982a3cb
3 changed files with 29 additions and 1 deletions

View file

@ -34,7 +34,7 @@ STRING arguments are taken from the command line unless standard input is connec
Arguments beginning with ``-`` are normally interpreted as switches; ``--`` causes the following arguments not to be treated as switches even if they begin with ``-``. Switches and required arguments are recognized only on the command line.
Most subcommands accept a ``-q`` or ``--quiet`` switch, which suppresses the usual output but exits with the documented status.
Most subcommands accept a ``-q`` or ``--quiet`` switch, which suppresses the usual output but exits with the documented status. In this case these commands will quit early, without reading all of the available input.
The following subcommands are available.

View file

@ -675,6 +675,8 @@ static int string_join_maybe0(parser_t &parser, io_streams_t &streams, int argc,
streams.out.append(sep);
}
streams.out.append(*arg);
} else if (nargs > 1) {
return STATUS_CMD_OK;
}
nargs++;
}
@ -710,6 +712,8 @@ static int string_length(parser_t &parser, io_streams_t &streams, int argc, wcha
if (!opts.quiet) {
streams.out.append(to_string(n));
streams.out.append(L'\n');
} else if (nnonempty > 0) {
return STATUS_CMD_OK;
}
}
@ -1134,6 +1138,7 @@ static int string_match(parser_t &parser, io_streams_t &streams, int argc, wchar
if (!matcher->report_matches(*arg)) {
return STATUS_INVALID_ARGS;
}
if (opts.quiet && matcher->match_count() > 0) return STATUS_CMD_OK;
}
return matcher->match_count() > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR;
@ -1387,6 +1392,7 @@ static int string_replace(parser_t &parser, io_streams_t &streams, int argc, wch
arg_iterator_t aiter(argv, optind, streams);
while (const wcstring *arg = aiter.nextstr()) {
if (!replacer->replace_matches(*arg)) return STATUS_INVALID_ARGS;
if (opts.quiet && replacer->replace_count() > 0) return STATUS_CMD_OK;
}
return replacer->replace_count() > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR;
@ -1429,6 +1435,8 @@ static int string_split_maybe0(parser_t &parser, io_streams_t &streams, int argc
opts.no_empty);
}
all_splits.push_back(splits);
// If we're quiet, we return early if we've found something to split.
if (opts.quiet && splits.size() > 1) return STATUS_CMD_OK;
split_count += splits.size();
arg_count++;
}
@ -1557,6 +1565,8 @@ static int string_repeat(parser_t &parser, io_streams_t &streams, int argc, wcha
if (!opts.quiet && !is_empty) {
streams.out.append(repeated);
if (!opts.no_newline) streams.out.append(L"\n");
} else if (opts.quiet && !is_empty) {
return STATUS_CMD_OK;
}
}
@ -1621,6 +1631,7 @@ static int string_sub(parser_t &parser, io_streams_t &streams, int argc, wchar_t
streams.out.append(L'\n');
}
nsub++;
if (opts.quiet) return STATUS_CMD_OK;
}
return nsub > 0 ? STATUS_CMD_OK : STATUS_CMD_ERROR;
@ -1661,6 +1672,8 @@ static int string_trim(parser_t &parser, io_streams_t &streams, int argc, wchar_
if (!opts.quiet) {
streams.out.append(wcstring(*arg, begin, end - begin));
streams.out.append(L'\n');
} else if (ntrim > 0) {
return STATUS_CMD_OK;
}
}
@ -1685,6 +1698,8 @@ static int string_transform(parser_t &parser, io_streams_t &streams, int argc, w
if (!opts.quiet) {
streams.out.append(transformed);
streams.out.append(L'\n');
} else if (n_transformed > 0) {
return STATUS_CMD_OK;
}
}

View file

@ -668,3 +668,16 @@ echo $status
# Unmatched capturing groups are treated as empty
echo az | string replace -r -- 'a(b.+)?z' 'a:$1z'
# CHECK: a:z
# --quiet should quit early
echo "Checking that --quiet quits early - if this is broken it hangs"
# CHECK: Checking that --quiet quits early - if this is broken it hangs
yes | string match -q y
echo $status
# CHECK: 0
yes | string length -q
echo $status
# CHECK: 0
yes | string replace -q y n
echo $status
# CHECK: 0