Skip to content

Commit 3ea679a

Browse files
committed
echo: print help if not posixly corrent and only argument is --help
1 parent f1436f3 commit 3ea679a

File tree

3 files changed

+30
-32
lines changed

3 files changed

+30
-32
lines changed

Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,6 @@ unused_qualifications = "warn"
626626
all = { level = "warn", priority = -1 }
627627
cargo = { level = "warn", priority = -1 }
628628
pedantic = { level = "warn", priority = -1 }
629-
match_bool = "allow" # 8310
630629
cargo_common_metadata = "allow" # 3240
631630
multiple_crate_versions = "allow" # 2314
632631
missing_errors_doc = "allow" # 1504

src/uu/echo/src/echo.rs

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::io::{self, StdoutLock, Write};
1111
use uucore::error::{UResult, USimpleError};
1212
use uucore::format::{FormatChar, OctalParsing, parse_escape_only};
1313
use uucore::format_usage;
14+
use uucore::os_str_as_bytes;
1415

1516
use uucore::locale::get_message;
1617

@@ -99,7 +100,7 @@ fn is_flag(arg: &OsStr, options: &mut Options) -> bool {
99100
///
100101
/// - Vector of non-flag arguments.
101102
/// - [`Options`], describing how teh arguments should be interpreted.
102-
fn filter_flags(mut args: impl uucore::Args) -> (Vec<OsString>, Options) {
103+
fn filter_flags(mut args: impl Iterator<Item = OsString>) -> (Vec<OsString>, Options) {
103104
let mut arguments = Vec::with_capacity(args.size_hint().0);
104105
let mut options = Options::default();
105106

@@ -124,7 +125,7 @@ fn filter_flags(mut args: impl uucore::Args) -> (Vec<OsString>, Options) {
124125
#[uucore::main]
125126
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
126127
// args[0] is the name of the binary.
127-
let mut args = args.skip(1).peekable();
128+
let args: Vec<OsString> = args.skip(1).collect();
128129

129130
// Check POSIX compatibility mode
130131
//
@@ -139,28 +140,36 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
139140
// > representation. For example, echo -e '\x2dn'.
140141
let is_posixly_correct = env::var_os("POSIXLY_CORRECT").is_some();
141142

142-
let (args, options) = match is_posixly_correct {
143-
// if POSIXLY_CORRECT is not set we filter the flags normally
144-
false => filter_flags(args),
145-
146-
true if args.peek().is_some_and(|arg| arg == "-n") => {
143+
let (args, options) = if is_posixly_correct {
144+
if args.first().is_some_and(|arg| arg == "-n") {
147145
// if POSIXLY_CORRECT is set and the first argument is the "-n" flag
148146
// we filter flags normally but 'escaped' is activated nonetheless.
149-
let (args, _) = filter_flags(args);
147+
let (args, _) = filter_flags(args.into_iter());
150148
(
151149
args,
152150
Options {
153151
trailing_newline: false,
154152
..Options::posixly_correct_default()
155153
},
156154
)
157-
}
158-
159-
true => {
155+
} else {
160156
// if POSIXLY_CORRECT is set and the first argument is not the "-n" flag
161-
// we just collect all arguments as every argument is considered an argument.
162-
(args.collect(), Options::posixly_correct_default())
157+
// we just collect all arguments as no arguments are interpreted as flags.
158+
(args, Options::posixly_correct_default())
163159
}
160+
} else if args.len() == 1 && args[0] == "--help" {
161+
// If POSIXLY_CORRECT is not set and the first argument
162+
// is `--help`, GNU coreutils prints the help message.
163+
//
164+
// Verify this using:
165+
//
166+
// POSIXLY_CORRECT=1 echo --help
167+
// echo --help
168+
uu_app().print_help()?;
169+
return Ok(());
170+
} else {
171+
// if POSIXLY_CORRECT is not set we filter the flags normally
172+
filter_flags(args.into_iter())
164173
};
165174

166175
execute(&mut io::stdout().lock(), args, options)?;
@@ -211,9 +220,8 @@ pub fn uu_app() -> Command {
211220

212221
fn execute(stdout: &mut StdoutLock, args: Vec<OsString>, options: Options) -> UResult<()> {
213222
for (i, arg) in args.into_iter().enumerate() {
214-
let Some(bytes) = bytes_from_os_string(arg.as_os_str()) else {
215-
return Err(USimpleError::new(1, get_message("echo-error-non-utf8")));
216-
};
223+
let bytes = os_str_as_bytes(arg.as_os_str())
224+
.map_err(|_| USimpleError::new(1, get_message("echo-error-non-utf8")))?;
217225

218226
if i > 0 {
219227
stdout.write_all(b" ")?;
@@ -236,18 +244,3 @@ fn execute(stdout: &mut StdoutLock, args: Vec<OsString>, options: Options) -> UR
236244

237245
Ok(())
238246
}
239-
240-
fn bytes_from_os_string(input: &OsStr) -> Option<&[u8]> {
241-
#[cfg(target_family = "unix")]
242-
{
243-
use std::os::unix::ffi::OsStrExt;
244-
245-
Some(input.as_bytes())
246-
}
247-
248-
#[cfg(not(target_family = "unix"))]
249-
{
250-
// TODO: Verify that this works correctly on these platforms
251-
input.to_str().map(|st| st.as_bytes())
252-
}
253-
}

tests/by-util/test_echo.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,12 @@ fn partial_help_argument() {
514514
new_ucmd!().arg("--he").succeeds().stdout_is("--he\n");
515515
}
516516

517+
#[test]
518+
fn only_help_argument_prints_help() {
519+
assert_ne!(new_ucmd!().arg("--help").succeeds().stdout(), b"--help\n");
520+
assert_ne!(new_ucmd!().arg("--help").succeeds().stdout(), b"--help"); // This one is just in case.
521+
}
522+
517523
#[test]
518524
fn multibyte_escape_unicode() {
519525
// spell-checker:disable-next-line

0 commit comments

Comments
 (0)