mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
seq: improve error handling for invalid -f values
Improve the error message produced by `seq` when given invalid format specifiers for the `-f` option. Before this commit: $ seq -f "%" 1 seq: %: invalid conversion specification $ seq -f "%g%" 1 seq: %: invalid conversion specification After this commit: $ seq -f "%" 1 seq: format '%' ends in % $ seq -f "%g%" 1 seq: format '%g%' has too many % directives This matches the behavior of GNU `seq`.
This commit is contained in:
parent
00d1866060
commit
cccab35337
2 changed files with 25 additions and 4 deletions
|
@ -22,7 +22,7 @@
|
||||||
//! 3. Parse both `printf` specifiers and escape sequences (for e.g. `printf`)
|
//! 3. Parse both `printf` specifiers and escape sequences (for e.g. `printf`)
|
||||||
//!
|
//!
|
||||||
//! This module aims to combine all three use cases. An iterator parsing each
|
//! This module aims to combine all three use cases. An iterator parsing each
|
||||||
//! of these cases is provided by [`parse_escape_only`], [`parse_spec_only`]
|
//! of these cases is provided by [`parse_spec_only`], [`parse_escape_only`]
|
||||||
//! and [`parse_spec_and_escape`], respectively.
|
//! and [`parse_spec_and_escape`], respectively.
|
||||||
//!
|
//!
|
||||||
//! There is a special [`Format`] type, which can be used to parse a format
|
//! There is a special [`Format`] type, which can be used to parse a format
|
||||||
|
@ -46,6 +46,8 @@ use std::{
|
||||||
ops::ControlFlow,
|
ops::ControlFlow,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use os_display::Quotable;
|
||||||
|
|
||||||
use crate::error::UError;
|
use crate::error::UError;
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
|
@ -63,6 +65,8 @@ pub enum FormatError {
|
||||||
NeedAtLeastOneSpec(Vec<u8>),
|
NeedAtLeastOneSpec(Vec<u8>),
|
||||||
WrongSpecType,
|
WrongSpecType,
|
||||||
InvalidPrecision(String),
|
InvalidPrecision(String),
|
||||||
|
/// The format specifier ends with a %, as in `%f%`.
|
||||||
|
EndsWithPercent(Vec<u8>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Error for FormatError {}
|
impl Error for FormatError {}
|
||||||
|
@ -92,6 +96,9 @@ impl Display for FormatError {
|
||||||
"format '{}' has no % directive",
|
"format '{}' has no % directive",
|
||||||
String::from_utf8_lossy(s)
|
String::from_utf8_lossy(s)
|
||||||
),
|
),
|
||||||
|
Self::EndsWithPercent(s) => {
|
||||||
|
write!(f, "format {} ends in %", String::from_utf8_lossy(s).quote())
|
||||||
|
}
|
||||||
Self::InvalidPrecision(precision) => write!(f, "invalid precision: '{precision}'"),
|
Self::InvalidPrecision(precision) => write!(f, "invalid precision: '{precision}'"),
|
||||||
// TODO: Error message below needs some work
|
// TODO: Error message below needs some work
|
||||||
Self::WrongSpecType => write!(f, "wrong % directive type was given"),
|
Self::WrongSpecType => write!(f, "wrong % directive type was given"),
|
||||||
|
@ -190,6 +197,7 @@ pub fn parse_spec_only(
|
||||||
let mut current = fmt;
|
let mut current = fmt;
|
||||||
std::iter::from_fn(move || match current {
|
std::iter::from_fn(move || match current {
|
||||||
[] => None,
|
[] => None,
|
||||||
|
[b'%'] => Some(Err(FormatError::EndsWithPercent(fmt.to_vec()))),
|
||||||
[b'%', b'%', rest @ ..] => {
|
[b'%', b'%', rest @ ..] => {
|
||||||
current = rest;
|
current = rest;
|
||||||
Some(Ok(FormatItem::Char(b'%')))
|
Some(Ok(FormatItem::Char(b'%')))
|
||||||
|
@ -323,11 +331,14 @@ impl<F: Formatter> Format<F> {
|
||||||
|
|
||||||
let mut suffix = Vec::new();
|
let mut suffix = Vec::new();
|
||||||
for item in &mut iter {
|
for item in &mut iter {
|
||||||
match item? {
|
match item {
|
||||||
FormatItem::Spec(_) => {
|
// If the `format_string` is of the form `%f%f` or
|
||||||
|
// `%f%`, then return an error.
|
||||||
|
Ok(FormatItem::Spec(_)) | Err(FormatError::EndsWithPercent(_)) => {
|
||||||
return Err(FormatError::TooManySpecs(format_string.as_ref().to_vec()));
|
return Err(FormatError::TooManySpecs(format_string.as_ref().to_vec()));
|
||||||
}
|
}
|
||||||
FormatItem::Char(c) => suffix.push(c),
|
Ok(FormatItem::Char(c)) => suffix.push(c),
|
||||||
|
Err(e) => return Err(e),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -787,6 +787,16 @@ fn test_invalid_format() {
|
||||||
.fails()
|
.fails()
|
||||||
.no_stdout()
|
.no_stdout()
|
||||||
.stderr_contains("format '%g%g' has too many % directives");
|
.stderr_contains("format '%g%g' has too many % directives");
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["-f", "%g%", "1"])
|
||||||
|
.fails()
|
||||||
|
.no_stdout()
|
||||||
|
.stderr_contains("format '%g%' has too many % directives");
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["-f", "%", "1"])
|
||||||
|
.fails()
|
||||||
|
.no_stdout()
|
||||||
|
.stderr_contains("format '%' ends in %");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue