Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/uu/tail/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,13 +428,15 @@ fn parse_num(src: &str) -> Result<Signum, ParseSizeError> {
pub fn parse_args(args: impl uucore::Args) -> UResult<Settings> {
let args_vec: Vec<OsString> = args.collect();
let clap_args = uu_app().try_get_matches_from(args_vec.clone());
let mut settings_failed = false;
let clap_result = match clap_args {
// Kept for the caret in size diagnostics, which needs the value as
// typed.
Ok(matches) => Ok(Settings::from_with_diagnostics(
Ok(matches) => Settings::from_with_diagnostics(
&matches,
uucore::diagnostics::capture(&args_vec).as_deref(),
)?),
)
.inspect_err(|_| settings_failed = true),
Err(err) => Err(err.into()),
};

Expand Down Expand Up @@ -465,6 +467,14 @@ pub fn parse_args(args: impl uucore::Args) -> UResult<Settings> {
if clap_result.is_ok() && possible_obsolete_args.as_encoded_bytes().first() != Some(&b'+') {
return clap_result;
}
// `tail -cf` is obsolete syntax even though clap reads it as `-c f`,
// but in `tail -c f` the separate argument is always the count.
// A bare short option such as `-c` is two bytes long: no value is
// attached to it, so the value came from the next argument.
let no_value_attached = possible_obsolete_args.len() <= "-c".len();
if settings_failed && no_value_attached {
return clap_result;
}
match parse_obsolete(possible_obsolete_args, args_vec.get(2))? {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please run the GNU tail tests too? tail.pl has lots of obsolete syntax cases
setup: git clone https://github.com/coreutils/coreutils.git ../gnu
run: bash util/build-gnu.sh && bash util/run-gnu-test.sh tests/tail/tail.pl

Some(settings) => Ok(settings),
None => clap_result,
Expand Down
12 changes: 9 additions & 3 deletions src/uu/tail/src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ pub fn parse_obsolete(src: &OsString) -> Option<Result<ObsoleteArgs, ParseError>
'l'
};

let follow = rest.contains('f');
if !rest.chars().all(|f| f == 'f') {
// GNU allows an arbitrary amount of following fs, but nothing else
let follow = rest == "f";
if !follow && !rest.is_empty() {
// At most one trailing 'f' is allowed
if sign == '-' && has_num {
return Some(Err(ParseError::Context));
}
Expand Down Expand Up @@ -168,11 +168,17 @@ mod tests {
parse_obsolete(&OsString::from("-1vzqvq")), // spell-checker:disable-line
Some(Err(ParseError::Context))
);
assert_eq!(
parse_obsolete(&OsString::from("-5ff")),
Some(Err(ParseError::Context))
);
}
#[test]
fn test_parse_obsolete_no_match() {
assert_eq!(parse_obsolete(&OsString::from("-k")), None);
assert_eq!(parse_obsolete(&OsString::from("asd")), None);
assert_eq!(parse_obsolete(&OsString::from("-cc")), None);
assert_eq!(parse_obsolete(&OsString::from("-cff")), None);
assert_eq!(parse_obsolete(&OsString::from("+ff")), None);
}
}
41 changes: 41 additions & 0 deletions tests/by-util/test_tail.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5141,6 +5141,47 @@
p.kill().make_assertion().with_all_output().no_output();
}

#[test]
#[cfg_attr(wasi_runner, ignore = "WASI: tail follow mode disabled")]
fn test_tail_obsolete_bytes_follow_stdin() {
// `-f` is ignored when stdin is a pipe, so tail exits after printing.
new_ucmd!()
.arg("-cf")
.pipe_in("abcdefghijklmnop\n")
.succeeds()
.stdout_only("hijklmnop\n");
}

#[test]
#[cfg_attr(wasi_runner, ignore = "WASI: tail follow mode disabled")]
fn test_tail_obsolete_bytes_follow() {
let scene = TestScenario::new(util_name!());
let at = &scene.fixtures;

at.write("file", "abcdefghijklmnop\n");
let mut p = scene.ucmd().args(&["-cf", "file"]).run_no_wait();
p.make_assertion_with_delay(500).is_alive();
p.kill()
.make_assertion()
.with_all_output()
.stdout_only("hijklmnop\n");

Check warning on line 5168 in tests/by-util/test_tail.rs

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

WARNING: `cspell`: Unknown word 'hijklmnop' (file:'tests/by-util/test_tail.rs', line:5168)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could you please also add the stdin case (-cf without a file)? it is in the issue

scene
.ucmd()
.arg("-c")
.arg("f")
.fails_with_code(1)
.no_stdout()
.stderr_is("tail: invalid number of bytes: 'f'\n");

scene
.ucmd()
.args(&["-5ff", "file"])
.fails_with_code(1)
.no_stdout()
.stderr_is("tail: option used in invalid context -- 5\n");
}

Check warning on line 5183 in tests/by-util/test_tail.rs

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

WARNING: `cspell`: Unknown word 'hijklmnop' (file:'tests/by-util/test_tail.rs', line:5183)

#[test]
#[cfg(unix)]
#[cfg_attr(wasi_runner, ignore = "WASI: argv/filenames must be valid UTF-8")]
Expand Down Expand Up @@ -5506,7 +5547,7 @@
.fails_with_code(1)
.stderr_is("tail: invalid number of bytes: '0fb'\n");
new_ucmd!()
.args(&["-n", "000ff", "/dev/null"])

Check warning on line 5550 in tests/by-util/test_tail.rs

View workflow job for this annotation

GitHub Actions / Style/spelling (ubuntu-latest, feat_os_unix)

WARNING: `cspell`: Unknown word 'retargeted' (file:'tests/by-util/test_tail.rs', line:5550)
.fails_with_code(1)
.stderr_is("tail: invalid number of lines: '000ff'\n");
// The sign is not put back with them: GNU reports `-c-0fb` as '0fb'.
Expand Down
Loading