string repeat: allow omission of -n (#10282)

This commit is contained in:
Himadri Bhattacharjee 2024-02-11 11:19:02 +00:00 committed by GitHub
parent 662fde7b71
commit 4e6e897781
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 59 additions and 16 deletions

View file

@ -3,8 +3,8 @@ use crate::wutil::fish_wcstol;
#[derive(Default)] #[derive(Default)]
pub struct Repeat { pub struct Repeat {
count: usize, count: Option<usize>,
max: usize, max: Option<usize>,
quiet: bool, quiet: bool,
no_newline: bool, no_newline: bool,
} }
@ -21,14 +21,17 @@ impl StringSubCommand<'_> for Repeat {
fn parse_opt(&mut self, name: &wstr, c: char, arg: Option<&wstr>) -> Result<(), StringError> { fn parse_opt(&mut self, name: &wstr, c: char, arg: Option<&wstr>) -> Result<(), StringError> {
match c { match c {
'n' => { 'n' => {
self.count = fish_wcstol(arg.unwrap())? self.count =
.try_into() Some(fish_wcstol(arg.unwrap())?.try_into().map_err(|_| {
.map_err(|_| invalid_args!("%ls: Invalid count value '%ls'\n", name, arg))? invalid_args!("%ls: Invalid count value '%ls'\n", name, arg)
})?)
} }
'm' => { 'm' => {
self.max = fish_wcstol(arg.unwrap())? self.max = Some(
.try_into() fish_wcstol(arg.unwrap())?
.map_err(|_| invalid_args!("%ls: Invalid max value '%ls'\n", name, arg))? .try_into()
.map_err(|_| invalid_args!("%ls: Invalid max value '%ls'\n", name, arg))?,
)
} }
'q' => self.quiet = true, 'q' => self.quiet = true,
'N' => self.no_newline = true, 'N' => self.no_newline = true,
@ -37,6 +40,33 @@ impl StringSubCommand<'_> for Repeat {
return Ok(()); return Ok(());
} }
fn take_args(
&mut self,
optind: &mut usize,
args: &[&'_ wstr],
streams: &mut IoStreams,
) -> Option<c_int> {
if self.count.is_some() || self.max.is_some() {
return STATUS_CMD_OK;
}
let name = args[0];
let Some(arg) = args.get(*optind) else {
string_error!(streams, BUILTIN_ERR_ARG_COUNT0, name);
return STATUS_INVALID_ARGS;
};
*optind += 1;
let Ok(Ok(count)) = fish_wcstol(arg).map(|count| count.try_into()) else {
string_error!(streams, "%ls: Invalid count value '%ls'\n", name, arg);
return STATUS_INVALID_ARGS;
};
self.count = Some(count);
return STATUS_CMD_OK;
}
fn handle( fn handle(
&mut self, &mut self,
_parser: &Parser, _parser: &Parser,
@ -44,7 +74,10 @@ impl StringSubCommand<'_> for Repeat {
optind: &mut usize, optind: &mut usize,
args: &[&wstr], args: &[&wstr],
) -> Option<libc::c_int> { ) -> Option<libc::c_int> {
if self.max == 0 && self.count == 0 { let max = self.max.unwrap_or_default();
let count = self.count.unwrap_or_default();
if max == 0 && count == 0 {
// XXX: This used to be allowed, but returned 1. // XXX: This used to be allowed, but returned 1.
// Keep it that way for now instead of adding an error. // Keep it that way for now instead of adding an error.
// streams.err.append(L"Count or max must be greater than zero"); // streams.err.append(L"Count or max must be greater than zero");
@ -75,13 +108,12 @@ impl StringSubCommand<'_> for Repeat {
// The maximum size of the string is either the "max" characters, // The maximum size of the string is either the "max" characters,
// or it's the "count" repetitions, whichever ends up lower. // or it's the "count" repetitions, whichever ends up lower.
let max = if self.max == 0 let max_repeat_len = w.len().wrapping_mul(count);
|| (self.count > 0 && w.len().wrapping_mul(self.count) < self.max) let max = if max == 0 || (count > 0 && max_repeat_len < max) {
{
// TODO: we should disallow overflowing unless max <= w.len().checked_mul(self.count).unwrap_or(usize::MAX) // TODO: we should disallow overflowing unless max <= w.len().checked_mul(self.count).unwrap_or(usize::MAX)
w.len().wrapping_mul(self.count) max_repeat_len
} else { } else {
self.max max
}; };
// Reserve a string to avoid writing constantly. // Reserve a string to avoid writing constantly.

View file

@ -468,9 +468,21 @@ string repeat -n 2 foo
string repeat --count 2 foo string repeat --count 2 foo
# CHECK: foofoo # CHECK: foofoo
string repeat 2 foo
# CHECK: foofoo
string repeat 2 -n 3
# CHECK: 222
echo foo | string repeat -n 2 echo foo | string repeat -n 2
# CHECK: foofoo # CHECK: foofoo
echo foo | string repeat 2
# CHECK: foofoo
string repeat foo
# CHECKERR: string repeat: Invalid count value 'foo'
string repeat -n2 -q foo; and echo "exit 0" string repeat -n2 -q foo; and echo "exit 0"
# CHECK: exit 0 # CHECK: exit 0
@ -566,8 +578,7 @@ string repeat -n; and echo "exit 0"
# DONTCHECKERR: string repeat: Unknown option '-l' # DONTCHECKERR: string repeat: Unknown option '-l'
string repeat "" string repeat ""
or echo string repeat empty string failed # CHECKERR: string repeat: Invalid count value ''
# CHECK: string repeat empty string failed
string repeat -n3 "" string repeat -n3 ""
or echo string repeat empty string failed or echo string repeat empty string failed