mirror of
https://github.com/uutils/coreutils
synced 2024-12-15 07:42:48 +00:00
printf rewrite: fix compilation
This commit is contained in:
parent
28810906a3
commit
f117fc1bab
7 changed files with 85 additions and 49 deletions
|
@ -13,8 +13,8 @@ use std::io::Write;
|
||||||
use std::sync::mpsc;
|
use std::sync::mpsc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use uucore::error::UResult;
|
|
||||||
use uucore::format::sprintf;
|
use uucore::format::sprintf;
|
||||||
|
use uucore::{error::UResult, format::FormatArgument};
|
||||||
|
|
||||||
use crate::numbers::{to_magnitude_and_suffix, SuffixType};
|
use crate::numbers::{to_magnitude_and_suffix, SuffixType};
|
||||||
|
|
||||||
|
@ -152,7 +152,9 @@ impl ProgUpdate {
|
||||||
let (carriage_return, newline) = if rewrite { ("\r", "") } else { ("", "\n") };
|
let (carriage_return, newline) = if rewrite { ("\r", "") } else { ("", "\n") };
|
||||||
|
|
||||||
// The duration should be formatted as in `printf %g`.
|
// The duration should be formatted as in `printf %g`.
|
||||||
let duration_str = sprintf("%g", &[duration.to_string()])?;
|
// TODO: remove unwrap and make FormatError implement UError
|
||||||
|
let duration_str = sprintf("%g", &[FormatArgument::Float(duration)])?;
|
||||||
|
let duration_str = std::str::from_utf8(&duration_str).unwrap();
|
||||||
|
|
||||||
// If the number of bytes written is sufficiently large, then
|
// If the number of bytes written is sufficiently large, then
|
||||||
// print a more concise representation of the number, like
|
// print a more concise representation of the number, like
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
use clap::{crate_version, Arg, ArgAction, Command};
|
use clap::{crate_version, Arg, ArgAction, Command};
|
||||||
use uucore::error::{UResult, UUsageError};
|
use uucore::error::{UResult, UUsageError};
|
||||||
use uucore::format::printf;
|
use uucore::format::{printf, FormatArgument};
|
||||||
use uucore::{format_usage, help_about, help_section, help_usage};
|
use uucore::{format_usage, help_about, help_section, help_usage};
|
||||||
|
|
||||||
const VERSION: &str = "version";
|
const VERSION: &str = "version";
|
||||||
|
@ -30,12 +30,12 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
let format_string = matches
|
let format_string = matches
|
||||||
.get_one::<String>(options::FORMATSTRING)
|
.get_one::<String>(options::FORMATSTRING)
|
||||||
.ok_or_else(|| UUsageError::new(1, "missing operand"))?;
|
.ok_or_else(|| UUsageError::new(1, "missing operand"))?;
|
||||||
let values: Vec<String> = match matches.get_many::<String>(options::ARGUMENT) {
|
let values: Vec<_> = match matches.get_many::<String>(options::ARGUMENT) {
|
||||||
Some(s) => s.map(|s| s.to_string()).collect(),
|
Some(s) => s.map(|s| FormatArgument::Unparsed(s.to_string())).collect(),
|
||||||
None => vec![],
|
None => vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
printf(format_string, &values[..])?;
|
printf(format_string, &values)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use clap::{crate_version, Arg, ArgAction, Command};
|
||||||
use num_traits::Zero;
|
use num_traits::Zero;
|
||||||
|
|
||||||
use uucore::error::UResult;
|
use uucore::error::UResult;
|
||||||
use uucore::format::printf;
|
use uucore::format::{printf, FormatArgument};
|
||||||
use uucore::{format_usage, help_about, help_usage};
|
use uucore::{format_usage, help_about, help_usage};
|
||||||
|
|
||||||
mod error;
|
mod error;
|
||||||
|
@ -144,8 +144,9 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
};
|
};
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) if err.kind() == ErrorKind::BrokenPipe => Ok(()),
|
_ => todo!(),
|
||||||
Err(e) => Err(e.map_err_context(|| "write error".into())),
|
// Err(err) if err.kind() == ErrorKind::BrokenPipe => Ok(()),
|
||||||
|
// Err(e) => Err(e.map_err_context(|| "write error".into())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,7 +271,7 @@ fn print_seq(
|
||||||
match format {
|
match format {
|
||||||
Some(f) => {
|
Some(f) => {
|
||||||
let s = format!("{value}");
|
let s = format!("{value}");
|
||||||
printf(f, &[s])?;
|
printf(f, &[FormatArgument::String(s)])?;
|
||||||
}
|
}
|
||||||
None => write_value_float(&mut stdout, &value, padding, largest_dec)?,
|
None => write_value_float(&mut stdout, &value, padding, largest_dec)?,
|
||||||
}
|
}
|
||||||
|
@ -326,7 +327,7 @@ fn print_seq_integers(
|
||||||
match format {
|
match format {
|
||||||
Some(f) => {
|
Some(f) => {
|
||||||
let s = format!("{value}");
|
let s = format!("{value}");
|
||||||
printf(f, &[s])?;
|
printf(f, &[FormatArgument::String(s)])?;
|
||||||
}
|
}
|
||||||
None => write_value_int(&mut stdout, &value, padding, pad)?,
|
None => write_value_int(&mut stdout, &value, padding, pad)?,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,16 +8,14 @@
|
||||||
pub mod backup_control;
|
pub mod backup_control;
|
||||||
#[cfg(feature = "encoding")]
|
#[cfg(feature = "encoding")]
|
||||||
pub mod encoding;
|
pub mod encoding;
|
||||||
|
#[cfg(feature = "format")]
|
||||||
|
pub mod format;
|
||||||
#[cfg(feature = "fs")]
|
#[cfg(feature = "fs")]
|
||||||
pub mod fs;
|
pub mod fs;
|
||||||
#[cfg(feature = "fsext")]
|
#[cfg(feature = "fsext")]
|
||||||
pub mod fsext;
|
pub mod fsext;
|
||||||
#[cfg(feature = "lines")]
|
#[cfg(feature = "lines")]
|
||||||
pub mod lines;
|
pub mod lines;
|
||||||
#[cfg(feature = "format")]
|
|
||||||
pub mod format;
|
|
||||||
#[cfg(feature = "memo")]
|
|
||||||
pub mod memo;
|
|
||||||
#[cfg(feature = "quoting-style")]
|
#[cfg(feature = "quoting-style")]
|
||||||
pub mod quoting_style;
|
pub mod quoting_style;
|
||||||
#[cfg(feature = "ranges")]
|
#[cfg(feature = "ranges")]
|
||||||
|
@ -26,8 +24,6 @@ pub mod ranges;
|
||||||
pub mod ringbuffer;
|
pub mod ringbuffer;
|
||||||
#[cfg(feature = "sum")]
|
#[cfg(feature = "sum")]
|
||||||
pub mod sum;
|
pub mod sum;
|
||||||
#[cfg(feature = "memo")]
|
|
||||||
mod tokenize;
|
|
||||||
#[cfg(feature = "update-control")]
|
#[cfg(feature = "update-control")]
|
||||||
pub mod update_control;
|
pub mod update_control;
|
||||||
#[cfg(feature = "version-cmp")]
|
#[cfg(feature = "version-cmp")]
|
||||||
|
|
|
@ -14,8 +14,15 @@
|
||||||
mod spec;
|
mod spec;
|
||||||
|
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use std::io::{stdout, Write};
|
use std::{
|
||||||
|
error::Error,
|
||||||
|
fmt::Display,
|
||||||
|
io::{stdout, Write},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::error::UError;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub enum FormatError {
|
pub enum FormatError {
|
||||||
SpecError,
|
SpecError,
|
||||||
IoError(std::io::Error),
|
IoError(std::io::Error),
|
||||||
|
@ -23,6 +30,21 @@ pub enum FormatError {
|
||||||
InvalidArgument(FormatArgument),
|
InvalidArgument(FormatArgument),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Error for FormatError {}
|
||||||
|
impl UError for FormatError {}
|
||||||
|
|
||||||
|
impl Display for FormatError {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
// TODO: Be more precise about these
|
||||||
|
match self {
|
||||||
|
FormatError::SpecError => write!(f, "invalid spec"),
|
||||||
|
FormatError::IoError(_) => write!(f, "io error"),
|
||||||
|
FormatError::NoMoreArguments => write!(f, "no more arguments"),
|
||||||
|
FormatError::InvalidArgument(_) => write!(f, "invalid argument"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A single item to format
|
/// A single item to format
|
||||||
enum FormatItem {
|
enum FormatItem {
|
||||||
/// A format specifier
|
/// A format specifier
|
||||||
|
@ -35,16 +57,23 @@ enum FormatItem {
|
||||||
Char(u8),
|
Char(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
pub enum FormatArgument {
|
pub enum FormatArgument {
|
||||||
Char(char),
|
Char(char),
|
||||||
String(String),
|
String(String),
|
||||||
UnsignedInt(u64),
|
UnsignedInt(u64),
|
||||||
SignedInt(i64),
|
SignedInt(i64),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
|
// Special argument that gets coerced into the other variants
|
||||||
|
Unparsed(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FormatItem {
|
impl FormatItem {
|
||||||
fn write<'a>(&self, mut writer: impl Write, args: &mut impl Iterator<Item = FormatArgument>) -> Result<(), FormatError> {
|
fn write<'a>(
|
||||||
|
&self,
|
||||||
|
mut writer: impl Write,
|
||||||
|
args: &mut impl Iterator<Item = &'a FormatArgument>,
|
||||||
|
) -> Result<(), FormatError> {
|
||||||
match self {
|
match self {
|
||||||
FormatItem::Spec(spec) => spec.write(writer, args),
|
FormatItem::Spec(spec) => spec.write(writer, args),
|
||||||
FormatItem::Text(bytes) => writer.write_all(bytes).map_err(FormatError::IoError),
|
FormatItem::Text(bytes) => writer.write_all(bytes).map_err(FormatError::IoError),
|
||||||
|
@ -110,13 +139,20 @@ fn parse_iter(fmt: &[u8]) -> impl Iterator<Item = Result<FormatItem, FormatError
|
||||||
/// printf("hello %s", &["world".to_string()]).unwrap();
|
/// printf("hello %s", &["world".to_string()]).unwrap();
|
||||||
/// // prints "hello world"
|
/// // prints "hello world"
|
||||||
/// ```
|
/// ```
|
||||||
pub fn printf(format_string: &[u8], arguments: impl IntoIterator<Item = FormatArgument>) -> Result<(), FormatError> {
|
pub fn printf<'a>(
|
||||||
|
format_string: impl AsRef<[u8]>,
|
||||||
|
arguments: impl IntoIterator<Item = &'a FormatArgument>,
|
||||||
|
) -> Result<(), FormatError> {
|
||||||
printf_writer(stdout(), format_string, arguments)
|
printf_writer(stdout(), format_string, arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn printf_writer(mut writer: impl Write, format_string: &[u8], args: impl IntoIterator<Item = FormatArgument>) -> Result<(), FormatError> {
|
fn printf_writer<'a>(
|
||||||
|
mut writer: impl Write,
|
||||||
|
format_string: impl AsRef<[u8]>,
|
||||||
|
args: impl IntoIterator<Item = &'a FormatArgument>,
|
||||||
|
) -> Result<(), FormatError> {
|
||||||
let mut args = args.into_iter();
|
let mut args = args.into_iter();
|
||||||
for item in parse_iter(format_string) {
|
for item in parse_iter(format_string.as_ref()) {
|
||||||
item?.write(&mut writer, &mut args)?;
|
item?.write(&mut writer, &mut args)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -137,7 +173,10 @@ fn printf_writer(mut writer: impl Write, format_string: &[u8], args: impl IntoIt
|
||||||
/// let s = sprintf("hello %s", &["world".to_string()]).unwrap();
|
/// let s = sprintf("hello %s", &["world".to_string()]).unwrap();
|
||||||
/// assert_eq!(s, "hello world".to_string());
|
/// assert_eq!(s, "hello world".to_string());
|
||||||
/// ```
|
/// ```
|
||||||
pub fn sprintf(format_string: &[u8], arguments: impl IntoIterator<Item = FormatArgument>) -> Result<Vec<u8>, FormatError> {
|
pub fn sprintf<'a>(
|
||||||
|
format_string: impl AsRef<[u8]>,
|
||||||
|
arguments: impl IntoIterator<Item = &'a FormatArgument>,
|
||||||
|
) -> Result<Vec<u8>, FormatError> {
|
||||||
let mut writer = Vec::new();
|
let mut writer = Vec::new();
|
||||||
printf_writer(&mut writer, format_string, arguments)?;
|
printf_writer(&mut writer, format_string, arguments)?;
|
||||||
Ok(writer)
|
Ok(writer)
|
||||||
|
|
|
@ -257,7 +257,7 @@ impl Spec {
|
||||||
pub fn write<'a>(
|
pub fn write<'a>(
|
||||||
&self,
|
&self,
|
||||||
mut writer: impl Write,
|
mut writer: impl Write,
|
||||||
mut args: impl Iterator<Item = FormatArgument>,
|
mut args: impl Iterator<Item = &'a FormatArgument>,
|
||||||
) -> Result<(), FormatError> {
|
) -> Result<(), FormatError> {
|
||||||
match self {
|
match self {
|
||||||
&Spec::Char { width, align_left } => {
|
&Spec::Char { width, align_left } => {
|
||||||
|
@ -265,7 +265,7 @@ impl Spec {
|
||||||
let arg = next_arg(&mut args)?;
|
let arg = next_arg(&mut args)?;
|
||||||
match arg {
|
match arg {
|
||||||
FormatArgument::Char(c) => write_padded(writer, c, width, false, align_left),
|
FormatArgument::Char(c) => write_padded(writer, c, width, false, align_left),
|
||||||
_ => Err(FormatError::InvalidArgument(arg)),
|
_ => Err(FormatError::InvalidArgument(arg.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Spec::String { width, align_left } => {
|
&Spec::String { width, align_left } => {
|
||||||
|
@ -273,7 +273,7 @@ impl Spec {
|
||||||
let arg = next_arg(&mut args)?;
|
let arg = next_arg(&mut args)?;
|
||||||
match arg {
|
match arg {
|
||||||
FormatArgument::String(s) => write_padded(writer, s, width, false, align_left),
|
FormatArgument::String(s) => write_padded(writer, s, width, false, align_left),
|
||||||
_ => Err(FormatError::InvalidArgument(arg)),
|
_ => Err(FormatError::InvalidArgument(arg.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Spec::SignedInt {
|
&Spec::SignedInt {
|
||||||
|
@ -285,10 +285,10 @@ impl Spec {
|
||||||
|
|
||||||
let arg = next_arg(&mut args)?;
|
let arg = next_arg(&mut args)?;
|
||||||
let FormatArgument::SignedInt(i) = arg else {
|
let FormatArgument::SignedInt(i) = arg else {
|
||||||
return Err(FormatError::InvalidArgument(arg));
|
return Err(FormatError::InvalidArgument(arg.clone()));
|
||||||
};
|
};
|
||||||
|
|
||||||
if i >= 0 {
|
if *i >= 0 {
|
||||||
match positive_sign {
|
match positive_sign {
|
||||||
PositiveSign::None => Ok(()),
|
PositiveSign::None => Ok(()),
|
||||||
PositiveSign::Plus => write!(writer, "+"),
|
PositiveSign::Plus => write!(writer, "+"),
|
||||||
|
@ -313,7 +313,7 @@ impl Spec {
|
||||||
|
|
||||||
let arg = next_arg(args)?;
|
let arg = next_arg(args)?;
|
||||||
let FormatArgument::SignedInt(i) = arg else {
|
let FormatArgument::SignedInt(i) = arg else {
|
||||||
return Err(FormatError::InvalidArgument(arg));
|
return Err(FormatError::InvalidArgument(arg.clone()));
|
||||||
};
|
};
|
||||||
|
|
||||||
let s = match variant {
|
let s = match variant {
|
||||||
|
@ -355,7 +355,7 @@ impl Spec {
|
||||||
|
|
||||||
let arg = next_arg(args)?;
|
let arg = next_arg(args)?;
|
||||||
let FormatArgument::Float(f) = arg else {
|
let FormatArgument::Float(f) = arg else {
|
||||||
return Err(FormatError::InvalidArgument(arg));
|
return Err(FormatError::InvalidArgument(arg.clone()));
|
||||||
};
|
};
|
||||||
|
|
||||||
if f.is_sign_positive() {
|
if f.is_sign_positive() {
|
||||||
|
@ -369,16 +369,16 @@ impl Spec {
|
||||||
|
|
||||||
let s = match variant {
|
let s = match variant {
|
||||||
FloatVariant::Decimal => {
|
FloatVariant::Decimal => {
|
||||||
format_float_decimal(f, precision, case, force_decimal)
|
format_float_decimal(*f, precision, case, force_decimal)
|
||||||
}
|
}
|
||||||
FloatVariant::Scientific => {
|
FloatVariant::Scientific => {
|
||||||
format_float_scientific(f, precision, case, force_decimal)
|
format_float_scientific(*f, precision, case, force_decimal)
|
||||||
}
|
}
|
||||||
FloatVariant::Shortest => {
|
FloatVariant::Shortest => {
|
||||||
format_float_shortest(f, precision, case, force_decimal)
|
format_float_shortest(*f, precision, case, force_decimal)
|
||||||
}
|
}
|
||||||
FloatVariant::Hexadecimal => {
|
FloatVariant::Hexadecimal => {
|
||||||
format_float_hexadecimal(f, precision, case, force_decimal)
|
format_float_hexadecimal(*f, precision, case, force_decimal)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -490,7 +490,7 @@ fn format_float_hexadecimal(
|
||||||
let mut s = match (precision, force_decimal) {
|
let mut s = match (precision, force_decimal) {
|
||||||
(0, ForceDecimal::No) => format!("0x{first_digit}p{exponent:+x}"),
|
(0, ForceDecimal::No) => format!("0x{first_digit}p{exponent:+x}"),
|
||||||
(0, ForceDecimal::Yes) => format!("0x{first_digit}.p{exponent:+x}"),
|
(0, ForceDecimal::Yes) => format!("0x{first_digit}.p{exponent:+x}"),
|
||||||
_ => format!("0x{first_digit}.{mantissa:0>13x}p{exponent:+x}")
|
_ => format!("0x{first_digit}.{mantissa:0>13x}p{exponent:+x}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if case == Case::Uppercase {
|
if case == Case::Uppercase {
|
||||||
|
@ -500,29 +500,29 @@ fn format_float_hexadecimal(
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_asterisk(
|
fn resolve_asterisk<'a>(
|
||||||
option: Option<CanAsterisk<usize>>,
|
option: Option<CanAsterisk<usize>>,
|
||||||
args: impl Iterator<Item = FormatArgument>,
|
args: impl Iterator<Item = &'a FormatArgument>,
|
||||||
) -> Result<Option<usize>, FormatError> {
|
) -> Result<Option<usize>, FormatError> {
|
||||||
Ok(match option {
|
Ok(match option {
|
||||||
None => None,
|
None => None,
|
||||||
Some(CanAsterisk::Asterisk) => {
|
Some(CanAsterisk::Asterisk) => {
|
||||||
let arg = next_arg(args)?;
|
let arg = next_arg(args)?;
|
||||||
match arg {
|
match arg {
|
||||||
FormatArgument::UnsignedInt(u) => match usize::try_from(u) {
|
FormatArgument::UnsignedInt(u) => match usize::try_from(*u) {
|
||||||
Ok(u) => Some(u),
|
Ok(u) => Some(u),
|
||||||
Err(_) => return Err(FormatError::InvalidArgument(arg)),
|
Err(_) => return Err(FormatError::InvalidArgument(arg.clone())),
|
||||||
},
|
},
|
||||||
_ => return Err(FormatError::InvalidArgument(arg)),
|
_ => return Err(FormatError::InvalidArgument(arg.clone())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(CanAsterisk::Fixed(w)) => Some(w),
|
Some(CanAsterisk::Fixed(w)) => Some(w),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn next_arg(
|
fn next_arg<'a>(
|
||||||
mut arguments: impl Iterator<Item = FormatArgument>,
|
mut arguments: impl Iterator<Item = &'a FormatArgument>,
|
||||||
) -> Result<FormatArgument, FormatError> {
|
) -> Result<&'a FormatArgument, FormatError> {
|
||||||
arguments.next().ok_or(FormatError::NoMoreArguments)
|
arguments.next().ok_or(FormatError::NoMoreArguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -37,16 +37,14 @@ pub use crate::parser::shortcut_value_parser;
|
||||||
pub use crate::features::backup_control;
|
pub use crate::features::backup_control;
|
||||||
#[cfg(feature = "encoding")]
|
#[cfg(feature = "encoding")]
|
||||||
pub use crate::features::encoding;
|
pub use crate::features::encoding;
|
||||||
|
#[cfg(feature = "format")]
|
||||||
|
pub use crate::features::format;
|
||||||
#[cfg(feature = "fs")]
|
#[cfg(feature = "fs")]
|
||||||
pub use crate::features::fs;
|
pub use crate::features::fs;
|
||||||
#[cfg(feature = "fsext")]
|
#[cfg(feature = "fsext")]
|
||||||
pub use crate::features::fsext;
|
pub use crate::features::fsext;
|
||||||
#[cfg(feature = "lines")]
|
#[cfg(feature = "lines")]
|
||||||
pub use crate::features::lines;
|
pub use crate::features::lines;
|
||||||
#[cfg(feature = "format")]
|
|
||||||
pub use crate::features::format;
|
|
||||||
#[cfg(feature = "memo")]
|
|
||||||
pub use crate::features::memo;
|
|
||||||
#[cfg(feature = "quoting-style")]
|
#[cfg(feature = "quoting-style")]
|
||||||
pub use crate::features::quoting_style;
|
pub use crate::features::quoting_style;
|
||||||
#[cfg(feature = "ranges")]
|
#[cfg(feature = "ranges")]
|
||||||
|
|
Loading…
Reference in a new issue