1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-30 12:37:49 +00:00

Merge pull request #3112 from ndd7xv/err_conv-to-result

uucore(memo): replace err_conv with result
This commit is contained in:
Terts Diepraam 2022-02-19 01:29:07 +01:00 committed by GitHub
commit 625c771d14
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 78 additions and 41 deletions

View file

@ -284,7 +284,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
None => vec![], None => vec![],
}; };
memo::Memo::run_all(format_string, &values[..]); memo::Memo::run_all(format_string, &values[..])?;
Ok(()) Ok(())
} }

View file

@ -5,6 +5,7 @@
// TODO: Support -f flag // TODO: Support -f flag
// spell-checker:ignore (ToDO) istr chiter argptr ilen extendedbigdecimal extendedbigint numberparse // spell-checker:ignore (ToDO) istr chiter argptr ilen extendedbigdecimal extendedbigint numberparse
use std::io::{stdout, ErrorKind, Write}; use std::io::{stdout, ErrorKind, Write};
use std::process::exit;
use clap::{crate_version, App, AppSettings, Arg}; use clap::{crate_version, App, AppSettings, Arg};
use num_traits::Zero; use num_traits::Zero;
@ -12,6 +13,7 @@ use num_traits::Zero;
use uucore::error::FromIo; use uucore::error::FromIo;
use uucore::error::UResult; use uucore::error::UResult;
use uucore::memo::Memo; use uucore::memo::Memo;
use uucore::show;
mod error; mod error;
mod extendedbigdecimal; mod extendedbigdecimal;
@ -287,7 +289,10 @@ fn print_seq(
match format { match format {
Some(f) => { Some(f) => {
let s = format!("{}", value); let s = format!("{}", value);
Memo::run_all(f, &[s]); if let Err(x) = Memo::run_all(f, &[s]) {
show!(x);
exit(1);
}
} }
None => write_value_float( None => write_value_float(
&mut stdout, &mut stdout,
@ -349,7 +354,10 @@ fn print_seq_integers(
match format { match format {
Some(f) => { Some(f) => {
let s = format!("{}", value); let s = format!("{}", value);
Memo::run_all(f, &[s]); if let Err(x) = Memo::run_all(f, &[s]) {
show!(x);
exit(1);
}
} }
None => write_value_int(&mut stdout, &value, padding, pad, is_first_iteration)?, None => write_value_int(&mut stdout, &value, padding, pad, is_first_iteration)?,
} }

View file

@ -6,6 +6,7 @@
//! that prints tokens. //! that prints tokens.
use crate::display::Quotable; use crate::display::Quotable;
use crate::error::UResult;
use crate::features::tokenize::sub::Sub; use crate::features::tokenize::sub::Sub;
use crate::features::tokenize::token::{Token, Tokenizer}; use crate::features::tokenize::token::{Token, Tokenizer};
use crate::features::tokenize::unescaped_text::UnescapedText; use crate::features::tokenize::unescaped_text::UnescapedText;
@ -26,17 +27,17 @@ fn warn_excess_args(first_arg: &str) {
} }
impl Memo { impl Memo {
pub fn new(pf_string: &str, pf_args_it: &mut Peekable<Iter<String>>) -> Self { pub fn new(pf_string: &str, pf_args_it: &mut Peekable<Iter<String>>) -> UResult<Self> {
let mut pm = Self { tokens: Vec::new() }; let mut pm = Self { tokens: Vec::new() };
let mut tmp_token: Option<Box<dyn Token>>; let mut tmp_token: Option<Box<dyn Token>>;
let mut it = put_back_n(pf_string.chars()); let mut it = put_back_n(pf_string.chars());
let mut has_sub = false; let mut has_sub = false;
loop { loop {
tmp_token = UnescapedText::from_it(&mut it, pf_args_it); tmp_token = UnescapedText::from_it(&mut it, pf_args_it)?;
if let Some(x) = tmp_token { if let Some(x) = tmp_token {
pm.tokens.push(x); pm.tokens.push(x);
} }
tmp_token = Sub::from_it(&mut it, pf_args_it); tmp_token = Sub::from_it(&mut it, pf_args_it)?;
if let Some(x) = tmp_token { if let Some(x) = tmp_token {
if !has_sub { if !has_sub {
has_sub = true; has_sub = true;
@ -64,19 +65,19 @@ impl Memo {
} }
} }
} }
pm Ok(pm)
} }
pub fn apply(&self, pf_args_it: &mut Peekable<Iter<String>>) { pub fn apply(&self, pf_args_it: &mut Peekable<Iter<String>>) {
for tkn in &self.tokens { for tkn in &self.tokens {
tkn.print(pf_args_it); tkn.print(pf_args_it);
} }
} }
pub fn run_all(pf_string: &str, pf_args: &[String]) { pub fn run_all(pf_string: &str, pf_args: &[String]) -> UResult<()> {
let mut arg_it = pf_args.iter().peekable(); let mut arg_it = pf_args.iter().peekable();
let pm = Self::new(pf_string, &mut arg_it); let pm = Self::new(pf_string, &mut arg_it)?;
loop { loop {
if arg_it.peek().is_none() { if arg_it.peek().is_none() {
break; return Ok(());
} }
pm.apply(&mut arg_it); pm.apply(&mut arg_it);
} }

View file

@ -5,8 +5,10 @@
//! it is created by Sub's implementation of the Tokenizer trait //! it is created by Sub's implementation of the Tokenizer trait
//! Subs which have numeric field chars make use of the num_format //! Subs which have numeric field chars make use of the num_format
//! submodule //! submodule
use crate::show_error; use crate::error::{UError, UResult};
use itertools::{put_back_n, PutBackN}; use itertools::{put_back_n, PutBackN};
use std::error::Error;
use std::fmt::Display;
use std::iter::Peekable; use std::iter::Peekable;
use std::process::exit; use std::process::exit;
use std::slice::Iter; use std::slice::Iter;
@ -20,11 +22,23 @@ use super::unescaped_text::UnescapedText;
const EXIT_ERR: i32 = 1; const EXIT_ERR: i32 = 1;
fn err_conv(sofar: &str) { #[derive(Debug)]
show_error!("%{}: invalid conversion specification", sofar); pub enum SubError {
exit(EXIT_ERR); InvalidSpec(String),
} }
impl Display for SubError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
Self::InvalidSpec(s) => write!(f, "%{}: invalid conversion specification", s),
}
}
}
impl Error for SubError {}
impl UError for SubError {}
fn convert_asterisk_arg_int(asterisk_arg: &str) -> isize { fn convert_asterisk_arg_int(asterisk_arg: &str) -> isize {
// this is a costly way to parse the // this is a costly way to parse the
// args used for asterisk values into integers // args used for asterisk values into integers
@ -116,14 +130,14 @@ impl SubParser {
fn from_it( fn from_it(
it: &mut PutBackN<Chars>, it: &mut PutBackN<Chars>,
args: &mut Peekable<Iter<String>>, args: &mut Peekable<Iter<String>>,
) -> Option<Box<dyn token::Token>> { ) -> UResult<Option<Box<dyn token::Token>>> {
let mut parser = Self::new(); let mut parser = Self::new();
if parser.sub_vals_retrieved(it) { if parser.sub_vals_retrieved(it)? {
let t: Box<dyn token::Token> = Self::build_token(parser); let t: Box<dyn token::Token> = Self::build_token(parser);
t.print(args); t.print(args);
Some(t) Ok(Some(t))
} else { } else {
None Ok(None)
} }
} }
fn build_token(parser: Self) -> Box<dyn token::Token> { fn build_token(parser: Self) -> Box<dyn token::Token> {
@ -151,9 +165,9 @@ impl SubParser {
)); ));
t t
} }
fn sub_vals_retrieved(&mut self, it: &mut PutBackN<Chars>) -> bool { fn sub_vals_retrieved(&mut self, it: &mut PutBackN<Chars>) -> UResult<bool> {
if !Self::successfully_eat_prefix(it, &mut self.text_so_far) { if !Self::successfully_eat_prefix(it, &mut self.text_so_far)? {
return false; return Ok(false);
} }
// this fn in particular is much longer than it needs to be // this fn in particular is much longer than it needs to be
// .could get a lot // .could get a lot
@ -177,7 +191,7 @@ impl SubParser {
'-' | '*' | '0'..='9' => { '-' | '*' | '0'..='9' => {
if !self.past_decimal { if !self.past_decimal {
if self.min_width_is_asterisk || self.specifiers_found { if self.min_width_is_asterisk || self.specifiers_found {
err_conv(&self.text_so_far); return Err(SubError::InvalidSpec(self.text_so_far.clone()).into());
} }
if self.min_width_tmp.is_none() { if self.min_width_tmp.is_none() {
self.min_width_tmp = Some(String::new()); self.min_width_tmp = Some(String::new());
@ -185,7 +199,9 @@ impl SubParser {
match self.min_width_tmp.as_mut() { match self.min_width_tmp.as_mut() {
Some(x) => { Some(x) => {
if (ch == '-' || ch == '*') && !x.is_empty() { if (ch == '-' || ch == '*') && !x.is_empty() {
err_conv(&self.text_so_far); return Err(
SubError::InvalidSpec(self.text_so_far.clone()).into()
);
} }
if ch == '*' { if ch == '*' {
self.min_width_is_asterisk = true; self.min_width_is_asterisk = true;
@ -200,7 +216,7 @@ impl SubParser {
// second field should never have a // second field should never have a
// negative value // negative value
if self.second_field_is_asterisk || ch == '-' || self.specifiers_found { if self.second_field_is_asterisk || ch == '-' || self.specifiers_found {
err_conv(&self.text_so_far); return Err(SubError::InvalidSpec(self.text_so_far.clone()).into());
} }
if self.second_field_tmp.is_none() { if self.second_field_tmp.is_none() {
self.second_field_tmp = Some(String::new()); self.second_field_tmp = Some(String::new());
@ -208,7 +224,9 @@ impl SubParser {
match self.second_field_tmp.as_mut() { match self.second_field_tmp.as_mut() {
Some(x) => { Some(x) => {
if ch == '*' && !x.is_empty() { if ch == '*' && !x.is_empty() {
err_conv(&self.text_so_far); return Err(
SubError::InvalidSpec(self.text_so_far.clone()).into()
);
} }
if ch == '*' { if ch == '*' {
self.second_field_is_asterisk = true; self.second_field_is_asterisk = true;
@ -225,7 +243,7 @@ impl SubParser {
if !self.past_decimal { if !self.past_decimal {
self.past_decimal = true; self.past_decimal = true;
} else { } else {
err_conv(&self.text_so_far); return Err(SubError::InvalidSpec(self.text_so_far.clone()).into());
} }
} }
x if legal_fields.binary_search(&x).is_ok() => { x if legal_fields.binary_search(&x).is_ok() => {
@ -242,18 +260,18 @@ impl SubParser {
} }
} }
_ => { _ => {
err_conv(&self.text_so_far); return Err(SubError::InvalidSpec(self.text_so_far.clone()).into());
} }
} }
} }
if self.field_char.is_none() { if self.field_char.is_none() {
err_conv(&self.text_so_far); return Err(SubError::InvalidSpec(self.text_so_far.clone()).into());
} }
let field_char_retrieved = self.field_char.unwrap(); let field_char_retrieved = self.field_char.unwrap();
if self.past_decimal && self.second_field_tmp.is_none() { if self.past_decimal && self.second_field_tmp.is_none() {
self.second_field_tmp = Some(String::from("0")); self.second_field_tmp = Some(String::from("0"));
} }
self.validate_field_params(field_char_retrieved); self.validate_field_params(field_char_retrieved)?;
// if the dot is provided without a second field // if the dot is provided without a second field
// printf interprets it as 0. // printf interprets it as 0.
if let Some(x) = self.second_field_tmp.as_mut() { if let Some(x) = self.second_field_tmp.as_mut() {
@ -262,9 +280,12 @@ impl SubParser {
} }
} }
true Ok(true)
} }
fn successfully_eat_prefix(it: &mut PutBackN<Chars>, text_so_far: &mut String) -> bool { fn successfully_eat_prefix(
it: &mut PutBackN<Chars>,
text_so_far: &mut String,
) -> UResult<bool> {
// get next two chars, // get next two chars,
// if they're '%%' we're not tokenizing it // if they're '%%' we're not tokenizing it
// else put chars back // else put chars back
@ -274,12 +295,11 @@ impl SubParser {
match n_ch { match n_ch {
Some(x) => { Some(x) => {
it.put_back(x); it.put_back(x);
true Ok(true)
} }
None => { None => {
text_so_far.push('%'); text_so_far.push('%');
err_conv(text_so_far); Err(SubError::InvalidSpec(text_so_far.clone()).into())
false
} }
} }
} else { } else {
@ -289,10 +309,10 @@ impl SubParser {
if let Some(x) = preface { if let Some(x) = preface {
it.put_back(x); it.put_back(x);
}; };
false Ok(false)
} }
} }
fn validate_field_params(&self, field_char: char) { fn validate_field_params(&self, field_char: char) -> UResult<()> {
// check for illegal combinations here when possible vs // check for illegal combinations here when possible vs
// on each application so we check less per application // on each application so we check less per application
// to do: move these checks to Sub::new // to do: move these checks to Sub::new
@ -304,8 +324,12 @@ impl SubParser {
|| self.past_decimal || self.past_decimal
|| self.second_field_tmp.is_some())) || self.second_field_tmp.is_some()))
{ {
err_conv(&self.text_so_far); // invalid string substitution
// to do: include information about an invalid
// string substitution
return Err(SubError::InvalidSpec(self.text_so_far.clone()).into());
} }
Ok(())
} }
} }
@ -313,7 +337,7 @@ impl token::Tokenizer for Sub {
fn from_it( fn from_it(
it: &mut PutBackN<Chars>, it: &mut PutBackN<Chars>,
args: &mut Peekable<Iter<String>>, args: &mut Peekable<Iter<String>>,
) -> Option<Box<dyn token::Token>> { ) -> UResult<Option<Box<dyn token::Token>>> {
SubParser::from_it(it, args) SubParser::from_it(it, args)
} }
} }

View file

@ -4,6 +4,8 @@ use std::iter::Peekable;
use std::slice::Iter; use std::slice::Iter;
use std::str::Chars; use std::str::Chars;
use crate::error::UResult;
// A token object is an object that can print the expected output // A token object is an object that can print the expected output
// of a contiguous segment of the format string, and // of a contiguous segment of the format string, and
// requires at most 1 argument // requires at most 1 argument
@ -27,5 +29,5 @@ pub trait Tokenizer {
fn from_it( fn from_it(
it: &mut PutBackN<Chars>, it: &mut PutBackN<Chars>,
args: &mut Peekable<Iter<String>>, args: &mut Peekable<Iter<String>>,
) -> Option<Box<dyn Token>>; ) -> UResult<Option<Box<dyn Token>>>;
} }

View file

@ -13,6 +13,8 @@ use std::process::exit;
use std::slice::Iter; use std::slice::Iter;
use std::str::Chars; use std::str::Chars;
use crate::error::UResult;
use super::token; use super::token;
const EXIT_OK: i32 = 0; const EXIT_OK: i32 = 0;
@ -266,8 +268,8 @@ impl token::Tokenizer for UnescapedText {
fn from_it( fn from_it(
it: &mut PutBackN<Chars>, it: &mut PutBackN<Chars>,
_: &mut Peekable<Iter<String>>, _: &mut Peekable<Iter<String>>,
) -> Option<Box<dyn token::Token>> { ) -> UResult<Option<Box<dyn token::Token>>> {
Self::from_it_core(it, false) Ok(Self::from_it_core(it, false))
} }
} }
impl token::Token for UnescapedText { impl token::Token for UnescapedText {