Skip to content

Commit

Permalink
format: parse as many characters as possible in numbers
Browse files Browse the repository at this point in the history
  • Loading branch information
samueltardieu committed Jan 4, 2024
1 parent 15ae059 commit a7897d5
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 30 deletions.
73 changes: 43 additions & 30 deletions src/uucore/src/lib/features/format/argument.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

use os_display::Quotable;

use crate::{error::set_exit_code, show_warning};
use crate::{
error::set_exit_code,
quoting_style::{escape_name, Quotes, QuotingStyle},
show_error,
};
use std::{ffi::OsStr, ops::ControlFlow, str::FromStr};

/// An argument for formatting
///
Expand Down Expand Up @@ -40,9 +43,7 @@ impl<'a, T: Iterator<Item = &'a FormatArgument>> ArgumentIter<'a> for T {
};
match next {
FormatArgument::Char(c) => *c,
FormatArgument::Unparsed(s) => {
s.chars().next().unwrap_or('\0')
}
FormatArgument::Unparsed(s) => s.chars().next().unwrap_or('\0'),
_ => '\0',
}
}
Expand All @@ -63,14 +64,7 @@ impl<'a, T: Iterator<Item = &'a FormatArgument>> ArgumentIter<'a> for T {
} else {
s.parse().ok()
};
match opt {
Some(n) => n,
None => {
show_warning!("{}: expected a numeric value", s.quote());
set_exit_code(1);
0
}
}
num_or_partial(opt, s)
}
_ => 0,
}
Expand All @@ -96,14 +90,7 @@ impl<'a, T: Iterator<Item = &'a FormatArgument>> ArgumentIter<'a> for T {
} else {
s.parse().ok()
};
match opt {
Some(n) => n,
None => {
show_warning!("{}: expected a numeric value", s.quote());
set_exit_code(1);
0
}
}
num_or_partial(opt, s)
}
_ => 0,
}
Expand All @@ -123,14 +110,7 @@ impl<'a, T: Iterator<Item = &'a FormatArgument>> ArgumentIter<'a> for T {
} else {
s.parse().ok()
};
match opt {
Some(n) => n,
None => {
show_warning!("{}: expected a numeric value", s.quote());
set_exit_code(1);
0.0
}
}
num_or_partial(opt, s)
}
_ => 0.0,
}
Expand All @@ -143,3 +123,36 @@ impl<'a, T: Iterator<Item = &'a FormatArgument>> ArgumentIter<'a> for T {
}
}
}

/// Return the previously `parsed` argument, or in the case of `None` try to do a partial
/// parsing and return the value after showing an error.
fn num_or_partial<T: FromStr + Default>(parsed: Option<T>, arg: &str) -> T {
if let Some(parsed) = parsed {
parsed
} else {
set_exit_code(1);
let m = arg
.char_indices()
.try_fold(None, |a, (i, _)| match (a, arg[..i].parse()) {
(_, Ok(v)) => ControlFlow::Continue(Some(v)),
(Some(v), Err(_)) => ControlFlow::Break(v),
(None, Err(_)) => ControlFlow::Continue(None),
});
let escaped = escape_name(
&OsStr::new(arg),

Check failure on line 142 in src/uucore/src/lib/features/format/argument.rs

View workflow job for this annotation

GitHub Actions / Style and Lint (ubuntu-22.04, unix)

ERROR: `cargo clippy`: this expression creates a reference which is immediately dereferenced by the compiler (file:'src/uucore/src/lib/features/format/argument.rs', line:142)
&QuotingStyle::C {
quotes: Quotes::None,
},
);
match m {
ControlFlow::Continue(Some(v)) | ControlFlow::Break(v) => {
show_error!("‘{escaped}’: value not completely converted");
v
}
ControlFlow::Continue(None) => {
show_error!("‘{escaped}’: expected a numeric value");
Default::default()
}
}
}
}
20 changes: 20 additions & 0 deletions tests/by-util/test_printf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -599,3 +599,23 @@ fn sub_general_round_float_leading_zeroes() {
.succeeds()
.stdout_only("1.00001");
}

#[test]
fn partial_float() {
new_ucmd!()
.args(&["%.2f is %s", "42.03x", "a lot"])
.fails()
.code_is(1)
.stdout_is("42.03 is a lot")
.stderr_is("printf: '42.03x': value not completely converted\n");
}

#[test]
fn partial_integer() {
new_ucmd!()
.args(&["%d is %s", "42x23", "a lot"])
.fails()
.code_is(1)
.stdout_is("42 is a lot")
.stderr_is("printf: '42x23': value not completely converted\n");
}

0 comments on commit a7897d5

Please sign in to comment.