From 2fa5d250e78bb59ef2204c1dc648741bf73027a4 Mon Sep 17 00:00:00 2001 From: emirmrkaljevic <93012621+emirmrkaljevic@users.noreply.github.com> Date: Wed, 21 Oct 2026 15:04:04 +0200 Subject: [PATCH] sort: keep numeric-looking file names verbatim in errors The error messages passed file names to translate!, which hands any value that parses as a number to Fluent as a number, so "1e3" was reported as "1000" and an output directory named "007" as "7". Use translate_text! for the messages that carry a file name, so they are printed as given, like GNU sort. Found with behave (https://github.com/emirmrkaljevic/behave). --- src/uu/sort/src/sort.rs | 20 ++++++++++---------- tests/by-util/test_sort.rs | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/uu/sort/src/sort.rs b/src/uu/sort/src/sort.rs index 4a8505509e1..94edeaa8ca2 100644 --- a/src/uu/sort/src/sort.rs +++ b/src/uu/sort/src/sort.rs @@ -143,19 +143,19 @@ pub enum SortError { silent: bool, }, - #[error("{}", translate!("sort-open-failed", "path" => format!("{}", .path.maybe_quote()), "error" => strip_errno(.error)))] + #[error("{}", translate_text!("sort-open-failed", "path" => format!("{}", .path.maybe_quote()), "error" => strip_errno(.error)))] OpenFailed { path: PathBuf, error: std::io::Error, }, - #[error("{}", translate!("sort-truncate-failed", "path" => format!("{}", .path.maybe_quote()), "error" => strip_errno(.error)))] + #[error("{}", translate_text!("sort-truncate-failed", "path" => format!("{}", .path.maybe_quote()), "error" => strip_errno(.error)))] TruncateFailed { path: PathBuf, error: std::io::Error, }, - #[error("{}", translate!("sort-cannot-read", "path" => format!("{}", .path.maybe_quote()), "error" => strip_errno(.error)))] + #[error("{}", translate_text!("sort-cannot-read", "path" => format!("{}", .path.maybe_quote()), "error" => strip_errno(.error)))] ReadFailed { path: PathBuf, error: std::io::Error, @@ -170,10 +170,10 @@ pub enum SortError { #[error("{}", translate!("sort-compress-prog-terminated-abnormally", "prog" => .prog.quote()))] CompressProgTerminatedAbnormally { prog: String }, - #[error("{}", translate!("sort-cannot-create-tmp-file", "path" => format!("{}", .path.quote())))] + #[error("{}", translate_text!("sort-cannot-create-tmp-file", "path" => format!("{}", .path.quote())))] TmpFileCreationFailed { path: PathBuf }, - #[error("{}", translate!("sort-file-operands-combined", "file" => format!("{}", .file.quote()), "help" => uucore::execution_phrase()))] + #[error("{}", translate_text!("sort-file-operands-combined", "file" => format!("{}", .file.quote()), "help" => uucore::execution_phrase()))] FileOperandsCombined { file: PathBuf }, #[error("{error}")] @@ -185,13 +185,13 @@ pub enum SortError { #[error("{}", translate!("sort-minus-in-stdin"))] MinusInStdIn, - #[error("{}", translate!("sort-no-input-from", "file" => format!("{}", .file.quote())))] + #[error("{}", translate_text!("sort-no-input-from", "file" => format!("{}", .file.quote())))] EmptyInputFile { file: PathBuf }, - #[error("{}", translate!("sort-random-source-end-of-file", "path" => format!("{}", .path.quote())))] + #[error("{}", translate_text!("sort-random-source-end-of-file", "path" => format!("{}", .path.quote())))] RandomSourceEndOfFile { path: PathBuf }, - #[error("{}", translate!("sort-invalid-zero-length-filename", "file" => .file.maybe_quote(), "line_num" => .line_num))] + #[error("{}", translate_text!("sort-invalid-zero-length-filename", "file" => .file.maybe_quote(), "line_num" => .line_num))] ZeroLengthFileName { file: PathBuf, line_num: usize }, } @@ -289,7 +289,7 @@ impl Output { .as_output_name() .unwrap_or(OsStr::new("standard output")) .to_owned(); - move || translate!("sort-error-write-failed", "output" => output_name.maybe_quote()) + move || translate_text!("sort-error-write-failed", "output" => output_name.maybe_quote()) } } @@ -2416,7 +2416,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { } else if settings.check && files.len() != 1 { return Err(UUsageError::new( 2, - translate!("sort-extra-operand-not-allowed-with-c", "operand" => files[1].quote()), + translate_text!("sort-extra-operand-not-allowed-with-c", "operand" => files[1].quote()), )); } diff --git a/tests/by-util/test_sort.rs b/tests/by-util/test_sort.rs index ab13c33251e..23dd109dd12 100644 --- a/tests/by-util/test_sort.rs +++ b/tests/by-util/test_sort.rs @@ -3942,3 +3942,20 @@ fn test_control_whitespace(#[case] args: &[&str], #[case] input: &str, #[case] e .succeeds() .stdout_only(expected); } + +#[rstest::rstest] +#[case(&["1e3"], "sort: cannot read: 1e3: No such file or directory\n")] +#[case(&["-o", "007", "empty"], "sort: open failed: 007: Is a directory\n")] +#[case(&["--files0-from=2.50"], "sort: open failed: 2.50: No such file or directory\n")] +#[cfg(not(windows))] +fn test_numeric_looking_file_names_are_kept_verbatim( + #[case] args: &[&str], + #[case] expected: &str, +) { + // File names such as "007" or "1e3" must not be reformatted as numbers + // in error messages. + let (at, mut ucmd) = at_and_ucmd!(); + at.mkdir("007"); + at.touch("empty"); + ucmd.args(args).fails_with_code(2).stderr_is(expected); +}