From f8c9c470ef1d7f247e9e3591c22f41f572cfa68f Mon Sep 17 00:00:00 2001 From: Alexandru Sima Date: Thu, 11 Jan 2024 11:47:21 +0000 Subject: [PATCH 1/4] Fix printf infinite loop --- src/uu/printf/src/printf.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/uu/printf/src/printf.rs b/src/uu/printf/src/printf.rs index ad42e38941f..302d1ffba23 100644 --- a/src/uu/printf/src/printf.rs +++ b/src/uu/printf/src/printf.rs @@ -10,8 +10,8 @@ use std::io::stdout; use std::ops::ControlFlow; use clap::{crate_version, Arg, ArgAction, Command}; -use uucore::error::{UResult, UUsageError}; -use uucore::format::{parse_spec_and_escape, FormatArgument}; +use uucore::error::{UResult, USimpleError, UUsageError}; +use uucore::format::{parse_spec_and_escape, ArgumentIter, FormatArgument}; use uucore::{format_usage, help_about, help_section, help_usage}; const VERSION: &str = "version"; @@ -46,13 +46,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; } - while args.peek().is_some() { - for item in parse_spec_and_escape(format_string.as_ref()) { - match item?.write(stdout(), &mut args)? { - ControlFlow::Continue(()) => {} - ControlFlow::Break(()) => return Ok(()), - }; - } + if args.peek().is_some() { + let warning_message = format!( + "warning: ignoring excess arguments, starting with '{}'", + args.get_str() + ); + return Err(USimpleError::new(0, warning_message.as_str())); } Ok(()) } From 3dcc4c73a4af6d0570aa8c4d395ea3cd411bbee3 Mon Sep 17 00:00:00 2001 From: Alexandru Sima Date: Fri, 12 Jan 2024 16:24:22 +0200 Subject: [PATCH 2/4] printf: Print remaining arguments reusing format --- src/uu/printf/src/printf.rs | 26 ++++++++++++++----- .../src/lib/features/format/argument.rs | 2 +- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/uu/printf/src/printf.rs b/src/uu/printf/src/printf.rs index 302d1ffba23..bd935fcf159 100644 --- a/src/uu/printf/src/printf.rs +++ b/src/uu/printf/src/printf.rs @@ -39,6 +39,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; let mut args = values.iter().peekable(); + let first_arg = args.peek().cloned(); for item in parse_spec_and_escape(format_string.as_ref()) { match item?.write(stdout(), &mut args)? { ControlFlow::Continue(()) => {} @@ -46,13 +47,26 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { }; } - if args.peek().is_some() { - let warning_message = format!( - "warning: ignoring excess arguments, starting with '{}'", - args.get_str() - ); - return Err(USimpleError::new(0, warning_message.as_str())); + if let Some(arg) = args.peek() { + // Check if no arguments were used while parsing the format. + if Some(arg) == first_arg.as_ref() { + let warning_message = format!( + "warning: ignoring excess arguments, starting with '{}'", + args.get_str() + ); + return Err(USimpleError::new(0, warning_message.as_str())); + } } + + while args.peek().is_some() { + for item in parse_spec_and_escape(format_string.as_ref()) { + match item?.write(stdout(), &mut args)? { + ControlFlow::Continue(()) => {} + ControlFlow::Break(()) => return Ok(()), + }; + } + } + Ok(()) } diff --git a/src/uucore/src/lib/features/format/argument.rs b/src/uucore/src/lib/features/format/argument.rs index db18cf51890..f711b4364f7 100644 --- a/src/uucore/src/lib/features/format/argument.rs +++ b/src/uucore/src/lib/features/format/argument.rs @@ -14,7 +14,7 @@ use crate::{error::set_exit_code, show_warning}; /// /// The [`FormatArgument::Unparsed`] variant contains a string that can be /// parsed into other types. This is used by the `printf` utility. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub enum FormatArgument { Char(char), String(String), From c17fc904209542b6429fa124e2f9fcd806af7501 Mon Sep 17 00:00:00 2001 From: Alexandru Sima Date: Tue, 16 Jan 2024 12:56:32 +0200 Subject: [PATCH 3/4] Fix warning output --- src/uu/printf/src/printf.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/uu/printf/src/printf.rs b/src/uu/printf/src/printf.rs index bd935fcf159..090573c538e 100644 --- a/src/uu/printf/src/printf.rs +++ b/src/uu/printf/src/printf.rs @@ -6,10 +6,11 @@ // spell-checker:ignore (change!) each's // spell-checker:ignore (ToDO) LONGHELP FORMATSTRING templating parameterizing formatstr -use std::io::stdout; +use std::io::{stdout, Write}; use std::ops::ControlFlow; use clap::{crate_version, Arg, ArgAction, Command}; +use uucore::display::Quotable; use uucore::error::{UResult, USimpleError, UUsageError}; use uucore::format::{parse_spec_and_escape, ArgumentIter, FormatArgument}; use uucore::{format_usage, help_about, help_section, help_usage}; @@ -50,9 +51,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if let Some(arg) = args.peek() { // Check if no arguments were used while parsing the format. if Some(arg) == first_arg.as_ref() { + stdout().flush()?; let warning_message = format!( - "warning: ignoring excess arguments, starting with '{}'", - args.get_str() + "warning: ignoring excess arguments, starting with {}", + args.get_str().quote() ); return Err(USimpleError::new(0, warning_message.as_str())); } From 6fff22f36e3a3bc73c76ef474895dfab05648a5a Mon Sep 17 00:00:00 2001 From: Alexandru Sima Date: Tue, 16 Jan 2024 13:06:23 +0200 Subject: [PATCH 4/4] Add test for feature --- tests/by-util/test_printf.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/by-util/test_printf.rs b/tests/by-util/test_printf.rs index dfd13159043..808f908002c 100644 --- a/tests/by-util/test_printf.rs +++ b/tests/by-util/test_printf.rs @@ -72,6 +72,15 @@ fn escaped_unrecognized() { new_ucmd!().args(&["c\\d"]).succeeds().stdout_only("c\\d"); } +#[test] +fn ignore_excess_arguments() { + new_ucmd!() + .args(&["a", "b"]) + .succeeds() + .stdout_is("a") + .stderr_is("printf: warning: ignoring excess arguments, starting with 'b'\n"); +} + #[test] fn sub_string() { new_ucmd!()