mirror of
https://github.com/uutils/coreutils
synced 2024-12-15 07:42:48 +00:00
Merge pull request #1293 from JJJollyjim/master
numfmt: support neither or both of --to and --from
This commit is contained in:
commit
5008b4db2e
2 changed files with 54 additions and 30 deletions
|
@ -34,17 +34,13 @@ const IEC_BASES: [f64; 10] = [
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, String>;
|
type Result<T> = std::result::Result<T, String>;
|
||||||
|
|
||||||
enum TransformDirection {
|
|
||||||
From,
|
|
||||||
To,
|
|
||||||
}
|
|
||||||
|
|
||||||
type WithI = bool;
|
type WithI = bool;
|
||||||
|
|
||||||
enum Unit {
|
enum Unit {
|
||||||
Auto,
|
Auto,
|
||||||
Si,
|
Si,
|
||||||
Iec(WithI),
|
Iec(WithI),
|
||||||
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RawSuffix {
|
enum RawSuffix {
|
||||||
|
@ -119,12 +115,17 @@ fn parse_unit(s: String) -> Result<Unit> {
|
||||||
"si" => Ok(Unit::Si),
|
"si" => Ok(Unit::Si),
|
||||||
"iec" => Ok(Unit::Iec(false)),
|
"iec" => Ok(Unit::Iec(false)),
|
||||||
"iec-i" => Ok(Unit::Iec(true)),
|
"iec-i" => Ok(Unit::Iec(true)),
|
||||||
|
"none" => Ok(Unit::None),
|
||||||
_ => Err("Unsupported unit is specified".to_owned()),
|
_ => Err("Unsupported unit is specified".to_owned()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TransformOptions {
|
struct TransformOptions {
|
||||||
direction: TransformDirection,
|
from: Transform,
|
||||||
|
to: Transform,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Transform {
|
||||||
unit: Unit,
|
unit: Unit,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,9 +166,9 @@ fn remove_suffix(i: f64, s: Option<Suffix>, u: &Unit) -> Result<f64> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_from(s: String, unit: &Unit) -> Result<String> {
|
fn transform_from(s: String, opts: &Transform) -> Result<f64> {
|
||||||
let (i, suffix) = parse_suffix(s)?;
|
let (i, suffix) = parse_suffix(s)?;
|
||||||
remove_suffix(i, suffix, unit).map(|n| n.round().to_string())
|
remove_suffix(i, suffix, &opts.unit).map(|n| n.round())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consider_suffix(i: f64, u: &Unit) -> Result<(f64, Option<Suffix>)> {
|
fn consider_suffix(i: f64, u: &Unit) -> Result<(f64, Option<Suffix>)> {
|
||||||
|
@ -198,12 +199,12 @@ fn consider_suffix(i: f64, u: &Unit) -> Result<(f64, Option<Suffix>)> {
|
||||||
_ => Err("Number is too big and unsupported".to_owned()),
|
_ => Err("Number is too big and unsupported".to_owned()),
|
||||||
},
|
},
|
||||||
Unit::Auto => Err("Unit 'auto' isn't supported with --to options".to_owned()),
|
Unit::Auto => Err("Unit 'auto' isn't supported with --to options".to_owned()),
|
||||||
|
Unit::None => Ok((i, None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn transform_to(s: String, unit: &Unit) -> Result<String> {
|
fn transform_to(s: f64, opts: &Transform) -> Result<String> {
|
||||||
let i = s.parse::<f64>().map_err(|err| err.to_string())?;
|
let (i2, s) = consider_suffix(s, &opts.unit)?;
|
||||||
let (i2, s) = consider_suffix(i, unit)?;
|
|
||||||
Ok(match s {
|
Ok(match s {
|
||||||
None => format!("{}", i2),
|
None => format!("{}", i2),
|
||||||
Some(s) => format!("{:.1}{}", i2, DisplayableSuffix(s)),
|
Some(s) => format!("{:.1}{}", i2, DisplayableSuffix(s)),
|
||||||
|
@ -211,10 +212,10 @@ fn transform_to(s: String, unit: &Unit) -> Result<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn format_string(source: String, options: &NumfmtOptions) -> Result<String> {
|
fn format_string(source: String, options: &NumfmtOptions) -> Result<String> {
|
||||||
let number = match options.transform.direction {
|
let number = transform_to(
|
||||||
TransformDirection::From => transform_from(source, &options.transform.unit)?,
|
transform_from(source, &options.transform.from)?,
|
||||||
TransformDirection::To => transform_to(source, &options.transform.unit)?,
|
&options.transform.to,
|
||||||
};
|
)?;
|
||||||
|
|
||||||
Ok(match options.padding {
|
Ok(match options.padding {
|
||||||
p if p == 0 => number,
|
p if p == 0 => number,
|
||||||
|
@ -224,21 +225,19 @@ fn format_string(source: String, options: &NumfmtOptions) -> Result<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_options(args: &Matches) -> Result<NumfmtOptions> {
|
fn parse_options(args: &Matches) -> Result<NumfmtOptions> {
|
||||||
let transform = if args.opt_present("from") {
|
let transform = TransformOptions {
|
||||||
TransformOptions {
|
from: Transform {
|
||||||
direction: TransformDirection::From,
|
unit: args
|
||||||
unit: parse_unit(
|
.opt_str("from")
|
||||||
args.opt_str("from")
|
.map(parse_unit)
|
||||||
.ok_or("'--from' should have argument")?,
|
.unwrap_or(Ok(Unit::None))?,
|
||||||
)?,
|
},
|
||||||
}
|
to: Transform {
|
||||||
} else if args.opt_present("to") {
|
unit: args
|
||||||
TransformOptions {
|
.opt_str("to")
|
||||||
direction: TransformDirection::To,
|
.map(parse_unit)
|
||||||
unit: parse_unit(args.opt_str("to").ok_or("'--to' should have argument")?)?,
|
.unwrap_or(Ok(Unit::None))?,
|
||||||
}
|
},
|
||||||
} else {
|
|
||||||
return Err("Either '--from' or '--to' should be specified".to_owned());
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let padding = match args.opt_str("padding") {
|
let padding = match args.opt_str("padding") {
|
||||||
|
|
|
@ -120,3 +120,28 @@ fn test_negative() {
|
||||||
.run()
|
.run()
|
||||||
.stdout_is("-1.0Ki\n-1.1Mi\n-102.4Mi");
|
.stdout_is("-1.0Ki\n-1.1Mi\n-102.4Mi");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_no_op() {
|
||||||
|
new_ucmd!()
|
||||||
|
.pipe_in("1024\n1234567")
|
||||||
|
.run()
|
||||||
|
.stdout_is("1024\n1234567");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_normalize() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["--from=si", "--to=si"])
|
||||||
|
.pipe_in("10000000K\n0.001K")
|
||||||
|
.run()
|
||||||
|
.stdout_is("10.0G\n1");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_si_to_iec() {
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&["--from=si", "--to=iec", "15334263563K"])
|
||||||
|
.run()
|
||||||
|
.stdout_is("13.9T");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue