1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 11:07:44 +00:00

echo: print help if not posixly corrent and only argument is --help

This commit is contained in:
RGBCube 2025-07-03 21:37:10 +03:00
parent f1436f3949
commit 3ea679a29e
Signed by: RGBCube
SSH key fingerprint: SHA256:CzqbPcfwt+GxFYNnFVCqoN5Itn4YFrshg1TrnACpA5M
3 changed files with 30 additions and 32 deletions

View file

@ -626,7 +626,6 @@ unused_qualifications = "warn"
all = { level = "warn", priority = -1 }
cargo = { level = "warn", priority = -1 }
pedantic = { level = "warn", priority = -1 }
match_bool = "allow" # 8310
cargo_common_metadata = "allow" # 3240
multiple_crate_versions = "allow" # 2314
missing_errors_doc = "allow" # 1504

View file

@ -11,6 +11,7 @@ use std::io::{self, StdoutLock, Write};
use uucore::error::{UResult, USimpleError};
use uucore::format::{FormatChar, OctalParsing, parse_escape_only};
use uucore::format_usage;
use uucore::os_str_as_bytes;
use uucore::locale::get_message;
@ -99,7 +100,7 @@ fn is_flag(arg: &OsStr, options: &mut Options) -> bool {
///
/// - Vector of non-flag arguments.
/// - [`Options`], describing how teh arguments should be interpreted.
fn filter_flags(mut args: impl uucore::Args) -> (Vec<OsString>, Options) {
fn filter_flags(mut args: impl Iterator<Item = OsString>) -> (Vec<OsString>, Options) {
let mut arguments = Vec::with_capacity(args.size_hint().0);
let mut options = Options::default();
@ -124,7 +125,7 @@ fn filter_flags(mut args: impl uucore::Args) -> (Vec<OsString>, Options) {
#[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// args[0] is the name of the binary.
let mut args = args.skip(1).peekable();
let args: Vec<OsString> = args.skip(1).collect();
// Check POSIX compatibility mode
//
@ -139,14 +140,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// > representation. For example, echo -e '\x2dn'.
let is_posixly_correct = env::var_os("POSIXLY_CORRECT").is_some();
let (args, options) = match is_posixly_correct {
// if POSIXLY_CORRECT is not set we filter the flags normally
false => filter_flags(args),
true if args.peek().is_some_and(|arg| arg == "-n") => {
let (args, options) = if is_posixly_correct {
if args.first().is_some_and(|arg| arg == "-n") {
// if POSIXLY_CORRECT is set and the first argument is the "-n" flag
// we filter flags normally but 'escaped' is activated nonetheless.
let (args, _) = filter_flags(args);
let (args, _) = filter_flags(args.into_iter());
(
args,
Options {
@ -154,13 +152,24 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
..Options::posixly_correct_default()
},
)
}
true => {
} else {
// if POSIXLY_CORRECT is set and the first argument is not the "-n" flag
// we just collect all arguments as every argument is considered an argument.
(args.collect(), Options::posixly_correct_default())
// we just collect all arguments as no arguments are interpreted as flags.
(args, Options::posixly_correct_default())
}
} else if args.len() == 1 && args[0] == "--help" {
// If POSIXLY_CORRECT is not set and the first argument
// is `--help`, GNU coreutils prints the help message.
//
// Verify this using:
//
// POSIXLY_CORRECT=1 echo --help
// echo --help
uu_app().print_help()?;
return Ok(());
} else {
// if POSIXLY_CORRECT is not set we filter the flags normally
filter_flags(args.into_iter())
};
execute(&mut io::stdout().lock(), args, options)?;
@ -211,9 +220,8 @@ pub fn uu_app() -> Command {
fn execute(stdout: &mut StdoutLock, args: Vec<OsString>, options: Options) -> UResult<()> {
for (i, arg) in args.into_iter().enumerate() {
let Some(bytes) = bytes_from_os_string(arg.as_os_str()) else {
return Err(USimpleError::new(1, get_message("echo-error-non-utf8")));
};
let bytes = os_str_as_bytes(arg.as_os_str())
.map_err(|_| USimpleError::new(1, get_message("echo-error-non-utf8")))?;
if i > 0 {
stdout.write_all(b" ")?;
@ -236,18 +244,3 @@ fn execute(stdout: &mut StdoutLock, args: Vec<OsString>, options: Options) -> UR
Ok(())
}
fn bytes_from_os_string(input: &OsStr) -> Option<&[u8]> {
#[cfg(target_family = "unix")]
{
use std::os::unix::ffi::OsStrExt;
Some(input.as_bytes())
}
#[cfg(not(target_family = "unix"))]
{
// TODO: Verify that this works correctly on these platforms
input.to_str().map(|st| st.as_bytes())
}
}

View file

@ -514,6 +514,12 @@ fn partial_help_argument() {
new_ucmd!().arg("--he").succeeds().stdout_is("--he\n");
}
#[test]
fn only_help_argument_prints_help() {
assert_ne!(new_ucmd!().arg("--help").succeeds().stdout(), b"--help\n");
assert_ne!(new_ucmd!().arg("--help").succeeds().stdout(), b"--help"); // This one is just in case.
}
#[test]
fn multibyte_escape_unicode() {
// spell-checker:disable-next-line