1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 19:17:43 +00:00

printf: rustfmt pass

This commit is contained in:
Nathan Ross 2016-02-15 00:47:02 -05:00
parent 9242ba1db6
commit 5f88dfe12b
18 changed files with 1266 additions and 1345 deletions

View file

@ -10,7 +10,7 @@ pub static EXIT_ERR: i32 = 1;
pub fn err_msg(msg: &str) { pub fn err_msg(msg: &str) {
let exe_path = match env::current_exe() { let exe_path = match env::current_exe() {
Ok(p) => p.to_string_lossy().into_owned(), Ok(p) => p.to_string_lossy().into_owned(),
_ => String::from("") _ => String::from(""),
}; };
writeln!(&mut stderr(), "{}: {}", exe_path, msg).unwrap(); writeln!(&mut stderr(), "{}: {}", exe_path, msg).unwrap();
} }

View file

@ -23,10 +23,7 @@ fn warn_excess_args(first_arg : &str) {
} }
impl Memo { impl Memo {
pub fn new( pub fn new(pf_string: &String, pf_args_it: &mut Peekable<Iter<String>>) -> Memo {
pf_string: &String,
pf_args_it: &mut Peekable<Iter<String>>
) -> Memo {
let mut pm = Memo { tokens: Vec::new() }; let mut pm = Memo { tokens: Vec::new() };
let mut tmp_token: Option<Box<Token>>; let mut tmp_token: Option<Box<Token>>;
let mut it = PutBackN::new(pf_string.chars()); let mut it = PutBackN::new(pf_string.chars());
@ -40,14 +37,18 @@ impl Memo {
tmp_token = Sub::from_it(&mut it, pf_args_it); tmp_token = Sub::from_it(&mut it, pf_args_it);
match tmp_token { match tmp_token {
Some(x) => { Some(x) => {
if ! has_sub { has_sub = true; } if !has_sub {
has_sub = true;
}
pm.tokens.push(x); pm.tokens.push(x);
}, }
None => {} None => {}
} }
if let Some(x) = it.next() { if let Some(x) = it.next() {
it.put_back(x); it.put_back(x);
} else { break; } } else {
break;
}
} }
if !has_sub { if !has_sub {
let mut drain = false; let mut drain = false;

View file

@ -1,4 +1,3 @@
mod cli; mod cli;
mod memo; mod memo;
mod tokenize; mod tokenize;

View file

@ -11,23 +11,22 @@ pub enum FieldType {
Charf, Charf,
} }
/* // #[allow(non_camel_case_types)]
#[allow(non_camel_case_types)] // pub enum FChar {
pub enum FChar { // d,
d, // e,
e, // E,
E, // i,
i, // f,
f, // F,
F, // g,
g, // G,
G, // u,
u, // x,
x, // X,
X, // o
o // }
} //
*/
// a Sub Tokens' fields are stored // a Sub Tokens' fields are stored
// as a single object so they can be more simply // as a single object so they can be more simply
@ -38,6 +37,5 @@ pub struct FormatField<'a> {
pub second_field: Option<u32>, pub second_field: Option<u32>,
pub field_char: &'a char, pub field_char: &'a char,
pub field_type: &'a FieldType, pub field_type: &'a FieldType,
pub orig : & 'a String pub orig: &'a String,
} }

View file

@ -13,7 +13,7 @@ pub struct FormatPrimitive {
pub prefix: Option<String>, pub prefix: Option<String>,
pub pre_decimal: Option<String>, pub pre_decimal: Option<String>,
pub post_decimal: Option<String>, pub post_decimal: Option<String>,
pub suffix: Option<String> pub suffix: Option<String>,
} }
impl Default for FormatPrimitive { impl Default for FormatPrimitive {
@ -22,7 +22,7 @@ impl Default for FormatPrimitive {
prefix: None, prefix: None,
pre_decimal: None, pre_decimal: None,
post_decimal: None, post_decimal: None,
suffix: None suffix: None,
} }
} }
} }
@ -40,34 +40,28 @@ pub enum Base {
pub struct InPrefix { pub struct InPrefix {
pub radix_in: Base, pub radix_in: Base,
pub sign: i8, pub sign: i8,
pub offset : usize pub offset: usize,
} }
pub trait Formatter { pub trait Formatter {
// return a FormatPrimitive for // return a FormatPrimitive for
// particular field char(s), given the argument // particular field char(s), given the argument
// string and prefix information (sign, radix) // string and prefix information (sign, radix)
fn get_primitive( fn get_primitive(&self,
&self,
field: &FormatField, field: &FormatField,
inprefix: &InPrefix, inprefix: &InPrefix,
str_in: &str str_in: &str)
) -> Option<FormatPrimitive>; -> Option<FormatPrimitive>;
// return a string from a formatprimitive, // return a string from a formatprimitive,
// given information about the field // given information about the field
fn primitive_to_str( fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String;
&self,
prim: &FormatPrimitive,
field: FormatField) -> String;
} }
pub fn get_it_at(offset: usize, pub fn get_it_at(offset: usize, str_in: &str) -> PutBackN<Chars> {
str_in: &str) -> PutBackN<Chars> {
PutBackN::new(str_in[offset..].chars()) PutBackN::new(str_in[offset..].chars())
} }
// TODO: put this somewhere better // TODO: put this somewhere better
pub fn warn_incomplete_conv(pf_arg: &str) { pub fn warn_incomplete_conv(pf_arg: &str) {
// important: keep println here not print // important: keep println here not print
cli::err_msg(&format!("{}: value not completely converted", cli::err_msg(&format!("{}: value not completely converted", pf_arg))
pf_arg))
} }

View file

@ -1,8 +1,4 @@
pub fn arrnum_int_mult( pub fn arrnum_int_mult(arr_num: &Vec<u8>, basenum: u8, base_ten_int_fact: u8) -> Vec<u8> {
arr_num : &Vec<u8>,
basenum : u8,
base_ten_int_fact : u8
) -> Vec<u8> {
let mut carry: u16 = 0; let mut carry: u16 = 0;
let mut rem: u16; let mut rem: u16;
let mut new_amount: u16; let mut new_amount: u16;
@ -19,7 +15,7 @@ pub fn arrnum_int_mult(
rem = new_amount % base; rem = new_amount % base;
carry = (new_amount - rem) / base; carry = (new_amount - rem) / base;
ret_rev.push(rem as u8) ret_rev.push(rem as u8)
}, }
None => { None => {
while carry != 0 { while carry != 0 {
rem = carry % base; rem = carry % base;
@ -30,33 +26,31 @@ pub fn arrnum_int_mult(
} }
} }
} }
let ret : Vec<u8> = let ret: Vec<u8> = ret_rev.iter().rev().map(|x| x.clone()).collect();
ret_rev.iter().rev().map(|x| x.clone()).collect();
ret ret
} }
pub struct Remainder<'a> { pub struct Remainder<'a> {
pub position: usize, pub position: usize,
pub replace: Vec<u8>, pub replace: Vec<u8>,
pub arr_num: &'a Vec<u8> pub arr_num: &'a Vec<u8>,
} }
pub struct DivOut<'a> { pub struct DivOut<'a> {
pub quotient: u8, pub quotient: u8,
pub remainder: Remainder<'a> pub remainder: Remainder<'a>,
} }
pub fn arrnum_int_div_step<'a>( pub fn arrnum_int_div_step<'a>(rem_in: Remainder<'a>,
rem_in: Remainder<'a>,
radix_in: u8, radix_in: u8,
base_ten_int_divisor: u8, base_ten_int_divisor: u8,
after_decimal: bool after_decimal: bool)
) -> DivOut<'a> { -> DivOut<'a> {
let mut rem_out = Remainder { let mut rem_out = Remainder {
position: rem_in.position, position: rem_in.position,
replace: Vec::new(), replace: Vec::new(),
arr_num: rem_in.arr_num arr_num: rem_in.arr_num,
}; };
let mut bufferval: u16 = 0; let mut bufferval: u16 = 0;
@ -70,12 +64,10 @@ pub fn arrnum_int_div_step<'a>(
let mut it_f = refd_vals.iter(); let mut it_f = refd_vals.iter();
loop { loop {
let u = match it_replace.next() { let u = match it_replace.next() {
Some(u_rep) => { u_rep.clone() as u16 } Some(u_rep) => u_rep.clone() as u16,
None => { None => {
match it_f.next() { match it_f.next() {
Some(u_orig) => { Some(u_orig) => u_orig.clone() as u16,
u_orig.clone() as u16
}
None => { None => {
if !after_decimal { if !after_decimal {
break; break;
@ -96,11 +88,7 @@ pub fn arrnum_int_div_step<'a>(
Vec::new() Vec::new()
} else { } else {
let remainder_as_arrnum = unsigned_to_arrnum(bufferval); let remainder_as_arrnum = unsigned_to_arrnum(bufferval);
let remainder_as_base_arrnum = base_conv_vec( let remainder_as_base_arrnum = base_conv_vec(&remainder_as_arrnum, 10, radix_in);
&remainder_as_arrnum,
10,
radix_in
);
remainder_as_base_arrnum remainder_as_base_arrnum
}; };
rem_out.position += 1 + (traversed - rem_out.replace.len()); rem_out.position += 1 + (traversed - rem_out.replace.len());
@ -109,78 +97,76 @@ pub fn arrnum_int_div_step<'a>(
bufferval *= base; bufferval *= base;
} }
} }
DivOut { quotient: quotient, remainder: rem_out } DivOut {
} quotient: quotient,
/* remainder: rem_out,
pub struct ArrFloat {
pub leading_zeros: u8,
pub values: Vec<u8>,
pub basenum: u8
}
pub struct ArrFloatDivOut {
pub quotient: u8,
pub remainder: ArrFloat
}
pub fn arrfloat_int_div(
arrfloat_in : &ArrFloat,
base_ten_int_divisor : u8,
precision : u16
) -> DivOut {
let mut remainder = ArrFloat {
basenum: arrfloat_in.basenum,
leading_zeros: arrfloat_in.leading_zeroes,
values: Vec<u8>::new()
}
let mut quotient = 0;
let mut bufferval : u16 = 0;
let base : u16 = arrfloat_in.basenum as u16;
let divisor : u16 = base_ten_int_divisor as u16;
let mut it_f = arrfloat_in.values.iter();
let mut position = 0 + arrfloat_in.leading_zeroes as u16;
let mut at_end = false;
while position< precision {
let next_digit = match it_f.next() {
Some(c) => {}
None => { 0 }
}
match u_cur {
Some(u) => {
bufferval += u.clone() as u16;
if bufferval > divisor {
while bufferval >= divisor {
quotient+=1;
bufferval -= divisor;
}
if bufferval == 0 {
rem_out.position +=1;
} else {
rem_out.replace = Some(bufferval as u8);
}
break;
} else {
bufferval *= base;
}
},
None => {
break;
} }
} }
u_cur = it_f.next().clone(); // pub struct ArrFloat {
rem_out.position+=1; // pub leading_zeros: u8,
} // pub values: Vec<u8>,
ArrFloatDivOut { quotient: quotient, remainder: remainder } // pub basenum: u8
} // }
*/ //
pub fn arrnum_int_add( // pub struct ArrFloatDivOut {
arrnum : &Vec<u8>, // pub quotient: u8,
basenum : u8, // pub remainder: ArrFloat
base_ten_int_term : u8 // }
) -> Vec<u8> { //
// pub fn arrfloat_int_div(
// arrfloat_in : &ArrFloat,
// base_ten_int_divisor : u8,
// precision : u16
// ) -> DivOut {
//
// let mut remainder = ArrFloat {
// basenum: arrfloat_in.basenum,
// leading_zeros: arrfloat_in.leading_zeroes,
// values: Vec<u8>::new()
// }
// let mut quotient = 0;
//
// let mut bufferval : u16 = 0;
// let base : u16 = arrfloat_in.basenum as u16;
// let divisor : u16 = base_ten_int_divisor as u16;
//
// let mut it_f = arrfloat_in.values.iter();
// let mut position = 0 + arrfloat_in.leading_zeroes as u16;
// let mut at_end = false;
// while position< precision {
// let next_digit = match it_f.next() {
// Some(c) => {}
// None => { 0 }
// }
// match u_cur {
// Some(u) => {
// bufferval += u.clone() as u16;
// if bufferval > divisor {
// while bufferval >= divisor {
// quotient+=1;
// bufferval -= divisor;
// }
// if bufferval == 0 {
// rem_out.position +=1;
// } else {
// rem_out.replace = Some(bufferval as u8);
// }
// break;
// } else {
// bufferval *= base;
// }
// },
// None => {
// break;
// }
// }
// u_cur = it_f.next().clone();
// rem_out.position+=1;
// }
// ArrFloatDivOut { quotient: quotient, remainder: remainder }
// }
//
pub fn arrnum_int_add(arrnum: &Vec<u8>, basenum: u8, base_ten_int_term: u8) -> Vec<u8> {
let mut carry: u16 = base_ten_int_term as u16; let mut carry: u16 = base_ten_int_term as u16;
let mut rem: u16; let mut rem: u16;
let mut new_amount: u16; let mut new_amount: u16;
@ -196,7 +182,7 @@ pub fn arrnum_int_add(
rem = new_amount % base; rem = new_amount % base;
carry = (new_amount - rem) / base; carry = (new_amount - rem) / base;
ret_rev.push(rem as u8) ret_rev.push(rem as u8)
}, }
None => { None => {
while carry != 0 { while carry != 0 {
rem = carry % base; rem = carry % base;
@ -207,33 +193,21 @@ pub fn arrnum_int_add(
} }
} }
} }
let ret : Vec<u8> = let ret: Vec<u8> = ret_rev.iter().rev().map(|x| x.clone()).collect();
ret_rev.iter().rev().map(|x| x.clone()).collect();
ret ret
} }
pub fn base_conv_vec( pub fn base_conv_vec(src: &Vec<u8>, radix_src: u8, radix_dest: u8) -> Vec<u8> {
src : &Vec<u8>,
radix_src : u8,
radix_dest : u8
) -> Vec<u8> {
let mut result: Vec<u8> = Vec::new(); let mut result: Vec<u8> = Vec::new();
result.push(0); result.push(0);
for i in src { for i in src {
result = arrnum_int_mult(&result, result = arrnum_int_mult(&result, radix_dest, radix_src);
radix_dest, radix_src); result = arrnum_int_add(&result, radix_dest, i.clone());
result = arrnum_int_add(
&result,
radix_dest,
i.clone()
);
} }
result result
} }
pub fn unsigned_to_arrnum( pub fn unsigned_to_arrnum(src: u16) -> Vec<u8> {
src : u16
) -> Vec<u8> {
let mut result: Vec<u8> = Vec::new(); let mut result: Vec<u8> = Vec::new();
let mut src_tmp: u16 = src.clone(); let mut src_tmp: u16 = src.clone();
while src_tmp > 0 { while src_tmp > 0 {
@ -247,11 +221,7 @@ pub fn unsigned_to_arrnum(
// temporary needs-improvement-function // temporary needs-improvement-function
#[allow(unused_variables)] #[allow(unused_variables)]
pub fn base_conv_float( pub fn base_conv_float(src: &Vec<u8>, radix_src: u8, radix_dest: u8) -> f64 {
src : &Vec<u8>,
radix_src : u8,
radix_dest : u8
) -> f64 {
// it would require a lot of addl code // it would require a lot of addl code
// to implement this for arbitrary string input. // to implement this for arbitrary string input.
// until then, the below operates as an outline // until then, the below operates as an outline
@ -263,7 +233,9 @@ pub fn base_conv_float(
let mut i = 0; let mut i = 0;
let mut r: f64 = 0 as f64; let mut r: f64 = 0 as f64;
for u in src { for u in src {
if i > 15 { break; } if i > 15 {
break;
}
i += 1; i += 1;
factor /= radix_src_float; factor /= radix_src_float;
r += factor * (u.clone() as f64) r += factor * (u.clone() as f64)
@ -271,24 +243,20 @@ pub fn base_conv_float(
r r
} }
pub fn str_to_arrnum( pub fn str_to_arrnum(src: &str, radix_def_src: &RadixDef) -> Vec<u8> {
src: &str,
radix_def_src : &RadixDef
) -> Vec<u8> {
let mut intermed_in: Vec<u8> = Vec::new(); let mut intermed_in: Vec<u8> = Vec::new();
for c in src.chars() { for c in src.chars() {
match radix_def_src.from_char::<>(c) { match radix_def_src.from_char(c) {
Some(u) => { intermed_in.push(u); } Some(u) => {
intermed_in.push(u);
}
None => {} //todo err msg on incorrect None => {} //todo err msg on incorrect
} }
} }
intermed_in intermed_in
} }
pub fn arrnum_to_str( pub fn arrnum_to_str(src: &Vec<u8>, radix_def_dest: &RadixDef) -> String {
src: &Vec<u8>,
radix_def_dest : &RadixDef
) -> String {
let mut str_out = String::new(); let mut str_out = String::new();
for u in src.iter() { for u in src.iter() {
match radix_def_dest.from_u8(u.clone()) { match radix_def_dest.from_u8(u.clone()) {
@ -302,18 +270,11 @@ pub fn arrnum_to_str(
} }
#[allow(unused_variables)] #[allow(unused_variables)]
pub fn base_conv_str( pub fn base_conv_str(src: &str, radix_def_src: &RadixDef, radix_def_dest: &RadixDef) -> String {
src: &str, let intermed_in: Vec<u8> = str_to_arrnum(src, radix_def_src);
radix_def_src : &RadixDef, let intermed_out = base_conv_vec(&intermed_in,
radix_def_dest : &RadixDef
) -> String {
let intermed_in : Vec<u8> =
str_to_arrnum(src, radix_def_src);
let intermed_out = base_conv_vec(
&intermed_in,
radix_def_src.get_max(), radix_def_src.get_max(),
radix_def_dest.get_max(), radix_def_dest.get_max());
);
arrnum_to_str(&intermed_out, radix_def_dest) arrnum_to_str(&intermed_out, radix_def_dest)
} }
@ -329,36 +290,40 @@ const UPPER_A_ASC : u8 = 'A' as u8;
const LOWER_A_ASC: u8 = 'a' as u8; const LOWER_A_ASC: u8 = 'a' as u8;
impl RadixDef for RadixTen { impl RadixDef for RadixTen {
fn get_max(&self) -> u8 { 10 } fn get_max(&self) -> u8 {
10
}
fn from_char(&self, c: char) -> Option<u8> { fn from_char(&self, c: char) -> Option<u8> {
match c { match c {
'0'...'9' => Some(c as u8 - ZERO_ASC), '0'...'9' => Some(c as u8 - ZERO_ASC),
_ => None _ => None,
} }
} }
fn from_u8(&self, u: u8) -> Option<char> { fn from_u8(&self, u: u8) -> Option<char> {
match u { match u {
0...9 => Some((ZERO_ASC + u) as char), 0...9 => Some((ZERO_ASC + u) as char),
_ => None _ => None,
} }
} }
} }
pub struct RadixHex; pub struct RadixHex;
impl RadixDef for RadixHex { impl RadixDef for RadixHex {
fn get_max(&self) -> u8 { 16 } fn get_max(&self) -> u8 {
16
}
fn from_char(&self, c: char) -> Option<u8> { fn from_char(&self, c: char) -> Option<u8> {
match c { match c {
'0'...'9' => Some(c as u8 - ZERO_ASC), '0'...'9' => Some(c as u8 - ZERO_ASC),
'A'...'F' => Some(c as u8 + 10 - UPPER_A_ASC), 'A'...'F' => Some(c as u8 + 10 - UPPER_A_ASC),
'a'...'f' => Some(c as u8 + 10 - LOWER_A_ASC), 'a'...'f' => Some(c as u8 + 10 - LOWER_A_ASC),
_ => None _ => None,
} }
} }
fn from_u8(&self, u: u8) -> Option<char> { fn from_u8(&self, u: u8) -> Option<char> {
match u { match u {
0...9 => Some((ZERO_ASC + u) as char), 0...9 => Some((ZERO_ASC + u) as char),
10...15 => Some((UPPER_A_ASC + (u - 10)) as char), 10...15 => Some((UPPER_A_ASC + (u - 10)) as char),
_ => None _ => None,
} }
} }
} }

View file

@ -5,13 +5,12 @@ use super::*;
#[test] #[test]
fn test_arrnum_int_mult() { fn test_arrnum_int_mult() {
// (in base 10) 12 * 4 = 48 // (in base 10) 12 * 4 = 48
let factor : Vec<u8> = vec!(1, 2); let factor: Vec<u8> = vec![1, 2];
let base_num = 10; let base_num = 10;
let base_ten_int_fact: u8 = 4; let base_ten_int_fact: u8 = 4;
let should_output: Vec<u8> = vec![4, 8]; let should_output: Vec<u8> = vec![4, 8];
let product = arrnum_int_mult(&factor, let product = arrnum_int_mult(&factor, base_num, base_ten_int_fact);
base_num, base_ten_int_fact);
assert!(product == should_output); assert!(product == should_output);
} }
@ -24,8 +23,7 @@ fn test_arrnum_int_non_base_10() {
let base_ten_int_fact: u8 = 4; let base_ten_int_fact: u8 = 4;
let should_output: Vec<u8> = vec![2, 0, 2]; let should_output: Vec<u8> = vec![2, 0, 2];
let product = arrnum_int_mult(&factor, let product = arrnum_int_mult(&factor, base_num, base_ten_int_fact);
base_num, base_ten_int_fact);
assert!(product == should_output); assert!(product == should_output);
} }
@ -38,7 +36,7 @@ fn test_arrnum_int_div_shortcircuit() {
let remainder_passed_in = Remainder { let remainder_passed_in = Remainder {
position: 1, position: 1,
replace: vec![1, 3], replace: vec![1, 3],
arr_num : &arrnum arr_num: &arrnum,
}; };
// the "replace" should mean the number being divided // the "replace" should mean the number being divided
@ -50,15 +48,8 @@ fn test_arrnum_int_div_shortcircuit() {
let remainder_position_should_be: usize = 3; let remainder_position_should_be: usize = 3;
let remainder_replace_should_be = vec![1, 2]; let remainder_replace_should_be = vec![1, 2];
let result = arrnum_int_div_step(remainder_passed_in, let result = arrnum_int_div_step(remainder_passed_in, base_num, base_ten_int_divisor, false);
base_num,
base_ten_int_divisor,
false
);
assert!(quotient_should_be == result.quotient); assert!(quotient_should_be == result.quotient);
assert!(remainder_position_should_be == assert!(remainder_position_should_be == result.remainder.position);
result.remainder.position); assert!(remainder_replace_should_be == result.remainder.replace);
assert!(remainder_replace_should_be ==
result.remainder.replace);
} }

View file

@ -1,14 +1,13 @@
//! formatter for %a %F C99 Hex-floating-point subs //! formatter for %a %F C99 Hex-floating-point subs
use super::super::format_field::FormatField; use super::super::format_field::FormatField;
use super::super::formatter::{InPrefix, FormatPrimitive, Formatter}; use super::super::formatter::{InPrefix, FormatPrimitive, Formatter};
use super::float_common::{FloatAnalysis, use super::float_common::{FloatAnalysis, primitive_to_str_common};
primitive_to_str_common};
use super::base_conv; use super::base_conv;
use super::base_conv::{RadixDef}; use super::base_conv::RadixDef;
pub struct CninetyNineHexFloatf { pub struct CninetyNineHexFloatf {
as_num : f64 as_num: f64,
} }
impl CninetyNineHexFloatf { impl CninetyNineHexFloatf {
pub fn new() -> CninetyNineHexFloatf { pub fn new() -> CninetyNineHexFloatf {
@ -17,35 +16,26 @@ impl CninetyNineHexFloatf {
} }
impl Formatter for CninetyNineHexFloatf { impl Formatter for CninetyNineHexFloatf {
fn get_primitive( fn get_primitive(&self,
&self,
field: &FormatField, field: &FormatField,
inprefix: &InPrefix, inprefix: &InPrefix,
str_in : &str str_in: &str)
) -> Option<FormatPrimitive> { -> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6) + 1; let second_field = field.second_field.unwrap_or(6) + 1;
let analysis = FloatAnalysis::analyze( let analysis = FloatAnalysis::analyze(&str_in,
&str_in,
inprefix, inprefix,
Some(second_field as usize), Some(second_field as usize),
None, None,
true); true);
let f = get_primitive_hex( let f = get_primitive_hex(inprefix,
inprefix,
&str_in[inprefix.offset..], &str_in[inprefix.offset..],
&analysis, &analysis,
second_field as usize, second_field as usize,
*field.field_char == 'A'); *field.field_char == 'A');
Some(f) Some(f)
} }
fn primitive_to_str( fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
&self, primitive_to_str_common(prim, &field)
prim: &FormatPrimitive,
field: FormatField) -> String {
primitive_to_str_common(
prim,
&field
)
} }
} }
@ -54,48 +44,48 @@ impl Formatter for CninetyNineHexFloatf {
// on the todo list is to have a trait for get_primitive that is implemented by each float formatter and can override a default. when that happens we can take the parts of get_primitive_dec specific to dec and spin them out to their own functions that can be overriden. // on the todo list is to have a trait for get_primitive that is implemented by each float formatter and can override a default. when that happens we can take the parts of get_primitive_dec specific to dec and spin them out to their own functions that can be overriden.
#[allow(unused_variables)] #[allow(unused_variables)]
#[allow(unused_assignments)] #[allow(unused_assignments)]
fn get_primitive_hex( fn get_primitive_hex(inprefix: &InPrefix,
inprefix : &InPrefix,
str_in: &str, str_in: &str,
analysis: &FloatAnalysis, analysis: &FloatAnalysis,
last_dec_place: usize, last_dec_place: usize,
capitalized : bool capitalized: bool)
) -> FormatPrimitive { -> FormatPrimitive {
let mut f: FormatPrimitive = Default::default(); let mut f: FormatPrimitive = Default::default();
f.prefix = Some(String::from( f.prefix = Some(String::from(if inprefix.sign == -1 {
if inprefix.sign == -1 { "-0x" } else { "0x" })); "-0x"
} else {
"0x"
}));
// assign the digits before and after the decimal points // assign the digits before and after the decimal points
// to separate slices. If no digits after decimal point, // to separate slices. If no digits after decimal point,
// assign 0 // assign 0
let (mut first_segment_raw, second_segment_raw) = let (mut first_segment_raw, second_segment_raw) = match analysis.decimal_pos {
match analysis.decimal_pos { Some(pos) => (&str_in[..pos], &str_in[pos + 1..]),
Some(pos) => { None => (&str_in[..], "0"),
(&str_in[..pos], &str_in[pos+1..])
},
None => { (&str_in[..], "0") }
}; };
if first_segment_raw.len() == 0 { if first_segment_raw.len() == 0 {
first_segment_raw = "0"; first_segment_raw = "0";
} }
// convert to string, hexifying if input is in dec. // convert to string, hexifying if input is in dec.
/*let (first_segment, second_segment) = // let (first_segment, second_segment) =
match inprefix.radix_in { // match inprefix.radix_in {
Base::Ten => { // Base::Ten => {
(to_hex(first_segment_raw, true), // (to_hex(first_segment_raw, true),
to_hex(second_segment_raw, false)) // to_hex(second_segment_raw, false))
} // }
_ => { // _ => {
(String::from(first_segment_raw), // (String::from(first_segment_raw),
String::from(second_segment_raw)) // String::from(second_segment_raw))
} // }
}; // };
//
//
// f.pre_decimal = Some(first_segment);
// f.post_decimal = Some(second_segment);
//
f.pre_decimal = Some(first_segment);
f.post_decimal = Some(second_segment);
*/
// TODO actual conversion, make sure to get back mantissa. // TODO actual conversion, make sure to get back mantissa.
// for hex to hex, it's really just a matter of moving the // for hex to hex, it's really just a matter of moving the
// decimal point and calculating the mantissa by its initial // decimal point and calculating the mantissa by its initial
@ -111,7 +101,11 @@ fn get_primitive_hex(
// directly to base 2 and then at the end translate back to hex. // directly to base 2 and then at the end translate back to hex.
let mantissa = 0; let mantissa = 0;
f.suffix = Some({ f.suffix = Some({
let ind = if capitalized { "P" } else { "p" }; let ind = if capitalized {
"P"
} else {
"p"
};
if mantissa >= 0 { if mantissa >= 0 {
format!("{}+{}", ind, mantissa) format!("{}+{}", ind, mantissa)
} else { } else {
@ -121,21 +115,15 @@ fn get_primitive_hex(
f f
} }
fn to_hex( fn to_hex(src: &str, before_decimal: bool) -> String {
src: &str,
before_decimal: bool
) -> String {
let rten = base_conv::RadixTen; let rten = base_conv::RadixTen;
let rhex = base_conv::RadixHex; let rhex = base_conv::RadixHex;
if before_decimal { if before_decimal {
base_conv::base_conv_str(src, &rten, &rhex) base_conv::base_conv_str(src, &rten, &rhex)
} else { } else {
let as_arrnum_ten = base_conv::str_to_arrnum(src, &rten); let as_arrnum_ten = base_conv::str_to_arrnum(src, &rten);
let s = format!("{}", base_conv::base_conv_float( let s = format!("{}",
&as_arrnum_ten, base_conv::base_conv_float(&as_arrnum_ten, rten.get_max(), rhex.get_max()));
rten.get_max(),
rhex.get_max()
));
if s.len() > 2 { if s.len() > 2 {
String::from(&s[2..]) String::from(&s[2..])
} else { } else {

View file

@ -1,23 +1,27 @@
//! formatter for %g %G decimal subs //! formatter for %g %G decimal subs
use super::super::format_field::FormatField; use super::super::format_field::FormatField;
use super::super::formatter::{InPrefix, FormatPrimitive, Formatter}; use super::super::formatter::{InPrefix, FormatPrimitive, Formatter};
use super::float_common::{FloatAnalysis, use super::float_common::{FloatAnalysis, get_primitive_dec, primitive_to_str_common};
get_primitive_dec,
primitive_to_str_common};
fn get_len_fprim( fn get_len_fprim(fprim: &FormatPrimitive) -> usize {
fprim : &FormatPrimitive
) -> usize {
let mut len = 0; let mut len = 0;
if let Some(ref s) = fprim.prefix { len += s.len(); } if let Some(ref s) = fprim.prefix {
if let Some(ref s) = fprim.pre_decimal { len += s.len(); } len += s.len();
if let Some(ref s) = fprim.post_decimal { len += s.len(); } }
if let Some(ref s) = fprim.suffix { len += s.len(); } if let Some(ref s) = fprim.pre_decimal {
len += s.len();
}
if let Some(ref s) = fprim.post_decimal {
len += s.len();
}
if let Some(ref s) = fprim.suffix {
len += s.len();
}
len len
} }
pub struct Decf { pub struct Decf {
as_num : f64 as_num: f64,
} }
impl Decf { impl Decf {
pub fn new() -> Decf { pub fn new() -> Decf {
@ -25,23 +29,20 @@ impl Decf {
} }
} }
impl Formatter for Decf { impl Formatter for Decf {
fn get_primitive( fn get_primitive(&self,
&self,
field: &FormatField, field: &FormatField,
inprefix: &InPrefix, inprefix: &InPrefix,
str_in : &str str_in: &str)
) -> Option<FormatPrimitive> { -> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6) + 1; let second_field = field.second_field.unwrap_or(6) + 1;
// default to scif interp. so as to not truncate input vals // default to scif interp. so as to not truncate input vals
// (that would be displayed in scif) based on relation to decimal place // (that would be displayed in scif) based on relation to decimal place
let analysis = FloatAnalysis::analyze( let analysis = FloatAnalysis::analyze(str_in,
str_in,
inprefix, inprefix,
Some(second_field as usize + 1), Some(second_field as usize + 1),
None, None,
false); false);
let mut f_sci = get_primitive_dec( let mut f_sci = get_primitive_dec(inprefix,
inprefix,
&str_in[inprefix.offset..], &str_in[inprefix.offset..],
&analysis, &analysis,
second_field as usize, second_field as usize,
@ -53,34 +54,30 @@ impl Formatter for Decf {
{ {
let mut it = post_dec.chars(); let mut it = post_dec.chars();
while let Some(c) = it.next_back() { while let Some(c) = it.next_back() {
if c != '0' { break; } if c != '0' {
break;
}
i -= 1; i -= 1;
} }
} }
if i != post_dec.len() { if i != post_dec.len() {
f_sci.post_decimal = f_sci.post_decimal = Some(String::from(&post_dec[0..i]));
Some(String::from(&post_dec[0..i]));
} }
} }
None => {} None => {}
} }
let f_fl = get_primitive_dec( let f_fl = get_primitive_dec(inprefix,
inprefix,
&str_in[inprefix.offset..], &str_in[inprefix.offset..],
&analysis, &analysis,
second_field as usize, second_field as usize,
None); None);
Some(if get_len_fprim(&f_fl) >= get_len_fprim(&f_sci) { Some(if get_len_fprim(&f_fl) >= get_len_fprim(&f_sci) {
f_sci f_sci
} else { f_fl }) } else {
f_fl
})
} }
fn primitive_to_str( fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
&self, primitive_to_str_common(prim, &field)
prim: &FormatPrimitive,
field: FormatField) -> String {
primitive_to_str_common(
prim,
&field
)
} }
} }

View file

@ -1,7 +1,7 @@
use super::super::format_field::{FormatField}; use super::super::format_field::FormatField;
use super::super::formatter::{InPrefix, Base, FormatPrimitive, warn_incomplete_conv, get_it_at}; use super::super::formatter::{InPrefix, Base, FormatPrimitive, warn_incomplete_conv, get_it_at};
use super::base_conv; use super::base_conv;
use super::base_conv::{RadixDef}; use super::base_conv::RadixDef;
// if the memory, copy, and comparison cost of chars // if the memory, copy, and comparison cost of chars
// becomes an issue, we can always operate in vec<u8> here // becomes an issue, we can always operate in vec<u8> here
@ -11,15 +11,14 @@ pub struct FloatAnalysis {
pub len_important: usize, pub len_important: usize,
// none means no decimal point. // none means no decimal point.
pub decimal_pos: Option<usize>, pub decimal_pos: Option<usize>,
pub follow: Option<char> pub follow: Option<char>,
} }
fn has_enough_digits( fn has_enough_digits(hex_input: bool,
hex_input: bool,
hex_output: bool, hex_output: bool,
string_position: usize, string_position: usize,
starting_position: usize, starting_position: usize,
limit: usize, limit: usize)
) -> bool { -> bool {
// -1s are for rounding // -1s are for rounding
if hex_output { if hex_output {
if hex_input { if hex_input {
@ -38,13 +37,12 @@ fn has_enough_digits(
} }
impl FloatAnalysis { impl FloatAnalysis {
pub fn analyze( pub fn analyze(str_in: &str,
str_in: &str,
inprefix: &InPrefix, inprefix: &InPrefix,
max_sd_opt: Option<usize>, max_sd_opt: Option<usize>,
max_after_dec_opt: Option<usize>, max_after_dec_opt: Option<usize>,
hex_output: bool hex_output: bool)
) -> FloatAnalysis { -> FloatAnalysis {
// this fn assumes // this fn assumes
// the input string // the input string
// has no leading spaces or 0s // has no leading spaces or 0s
@ -52,27 +50,32 @@ impl FloatAnalysis {
let mut ret = FloatAnalysis { let mut ret = FloatAnalysis {
len_important: 0, len_important: 0,
decimal_pos: None, decimal_pos: None,
follow: None follow: None,
}; };
let hex_input = match inprefix.radix_in { let hex_input = match inprefix.radix_in {
Base::Hex => { true } Base::Hex => true,
Base::Ten => { false } Base::Ten => false,
Base::Octal => { panic!("this should never happen: floats should never receive octal input"); } Base::Octal => {
panic!("this should never happen: floats should never receive octal input");
}
}; };
let mut i = 0; let mut i = 0;
let mut pos_before_first_nonzero_after_decimal: Option<usize> = None; let mut pos_before_first_nonzero_after_decimal: Option<usize> = None;
while let Some(c) = str_it.next() { match c{ while let Some(c) = str_it.next() {
match c {
e @ '0'...'9' | e @ 'A'...'F' | e @ 'a'...'f' => { e @ '0'...'9' | e @ 'A'...'F' | e @ 'a'...'f' => {
if !hex_input { if !hex_input {
match e { match e {
'0'...'9' => {}, '0'...'9' => {}
_ => { _ => {
warn_incomplete_conv(str_in); warn_incomplete_conv(str_in);
break; break;
} }
} }
} }
if ret.decimal_pos.is_some() && pos_before_first_nonzero_after_decimal.is_none() && e != '0' { if ret.decimal_pos.is_some() &&
pos_before_first_nonzero_after_decimal.is_none() &&
e != '0' {
pos_before_first_nonzero_after_decimal = Some(i - 1); pos_before_first_nonzero_after_decimal = Some(i - 1);
} }
if let Some(max_sd) = max_sd_opt { if let Some(max_sd) = max_sd_opt {
@ -99,7 +102,7 @@ impl FloatAnalysis {
} }
} }
} }
}, }
'.' => { '.' => {
if ret.decimal_pos.is_none() { if ret.decimal_pos.is_none() {
ret.decimal_pos = Some(i); ret.decimal_pos = Some(i);
@ -112,27 +115,23 @@ impl FloatAnalysis {
warn_incomplete_conv(str_in); warn_incomplete_conv(str_in);
break; break;
} }
}; i+=1; } };
i += 1;
}
ret.len_important = i; ret.len_important = i;
ret ret
} }
} }
fn de_hex( fn de_hex(src: &str, before_decimal: bool) -> String {
src: &str,
before_decimal: bool
) -> String {
let rten = base_conv::RadixTen; let rten = base_conv::RadixTen;
let rhex = base_conv::RadixHex; let rhex = base_conv::RadixHex;
if before_decimal { if before_decimal {
base_conv::base_conv_str(src, &rhex, &rten) base_conv::base_conv_str(src, &rhex, &rten)
} else { } else {
let as_arrnum_hex = base_conv::str_to_arrnum(src, &rhex); let as_arrnum_hex = base_conv::str_to_arrnum(src, &rhex);
let s = format!("{}", base_conv::base_conv_float( let s = format!("{}",
&as_arrnum_hex, base_conv::base_conv_float(&as_arrnum_hex, rhex.get_max(), rten.get_max()));
rhex.get_max(),
rten.get_max()
));
if s.len() > 2 { if s.len() > 2 {
String::from(&s[2..]) String::from(&s[2..])
} else { } else {
@ -147,10 +146,7 @@ fn de_hex(
// bumps the last digit up one, // bumps the last digit up one,
// and if the digit was nine // and if the digit was nine
// propagate to the next, etc. // propagate to the next, etc.
fn _round_str_from( fn _round_str_from(in_str: &str, position: usize) -> (String, bool) {
in_str : &str,
position : usize
) -> (String, bool) {
let mut it = in_str[0..position].chars(); let mut it = in_str[0..position].chars();
let mut rev = String::new(); let mut rev = String::new();
@ -159,10 +155,11 @@ fn _round_str_from(
while let Some(c) = it.next_back() { while let Some(c) = it.next_back() {
i -= 1; i -= 1;
match c { match c {
'9' => { rev.push('0'); } '9' => {
rev.push('0');
}
e @ _ => { e @ _ => {
rev.push( rev.push(((e as u8) + 1) as char);
((e as u8)+1) as char);
finished_in_dec = true; finished_in_dec = true;
break; break;
} }
@ -175,45 +172,42 @@ fn _round_str_from(
(fwd, finished_in_dec) (fwd, finished_in_dec)
} }
fn round_terminal_digit( fn round_terminal_digit(before_dec: String,
before_dec: String,
after_dec: String, after_dec: String,
position: usize position: usize)
) -> (String, String) { -> (String, String) {
if position < after_dec.len() { if position < after_dec.len() {
let digit_at_pos: char; let digit_at_pos: char;
{ {
digit_at_pos = (&after_dec[position..position + 1]) digit_at_pos = (&after_dec[position..position + 1])
.chars().next().expect(""); .chars()
.next()
.expect("");
} }
match digit_at_pos { match digit_at_pos {
'5'...'9' => { '5'...'9' => {
let (new_after_dec, finished_in_dec) = let (new_after_dec, finished_in_dec) = _round_str_from(&after_dec, position);
_round_str_from(&after_dec, position);
if finished_in_dec { if finished_in_dec {
return (before_dec, new_after_dec) return (before_dec, new_after_dec);
} else { } else {
let (new_before_dec, _) = let (new_before_dec, _) = _round_str_from(&before_dec, before_dec.len());
_round_str_from(&before_dec, return (new_before_dec, new_after_dec);
before_dec.len());
return (new_before_dec, new_after_dec)
} }
// TODO // TODO
}, }
_ => {} _ => {}
} }
} }
(before_dec, after_dec) (before_dec, after_dec)
} }
pub fn get_primitive_dec( pub fn get_primitive_dec(inprefix: &InPrefix,
inprefix : &InPrefix,
str_in: &str, str_in: &str,
analysis: &FloatAnalysis, analysis: &FloatAnalysis,
last_dec_place: usize, last_dec_place: usize,
sci_mode : Option<bool> sci_mode: Option<bool>)
) -> FormatPrimitive { -> FormatPrimitive {
let mut f: FormatPrimitive = Default::default(); let mut f: FormatPrimitive = Default::default();
// add negative sign section // add negative sign section
@ -224,19 +218,15 @@ pub fn get_primitive_dec(
// assign the digits before and after the decimal points // assign the digits before and after the decimal points
// to separate slices. If no digits after decimal point, // to separate slices. If no digits after decimal point,
// assign 0 // assign 0
let (mut first_segment_raw, second_segment_raw) = let (mut first_segment_raw, second_segment_raw) = match analysis.decimal_pos {
match analysis.decimal_pos { Some(pos) => (&str_in[..pos], &str_in[pos + 1..]),
Some(pos) => { None => (&str_in[..], "0"),
(&str_in[..pos], &str_in[pos+1..])
},
None => { (&str_in[..], "0") }
}; };
if first_segment_raw.len() == 0 { if first_segment_raw.len() == 0 {
first_segment_raw = "0"; first_segment_raw = "0";
} }
// convert to string, de_hexifying if input is in hex. // convert to string, de_hexifying if input is in hex.
let (first_segment, second_segment) = let (first_segment, second_segment) = match inprefix.radix_in {
match inprefix.radix_in {
Base::Hex => { Base::Hex => {
(de_hex(first_segment_raw, true), (de_hex(first_segment_raw, true),
de_hex(second_segment_raw, false)) de_hex(second_segment_raw, false))
@ -246,8 +236,7 @@ pub fn get_primitive_dec(
String::from(second_segment_raw)) String::from(second_segment_raw))
} }
}; };
let (pre_dec_unrounded, post_dec_unrounded, mantissa) = let (pre_dec_unrounded, post_dec_unrounded, mantissa) = if sci_mode.is_some() {
if sci_mode.is_some() {
if first_segment.len() > 1 { if first_segment.len() > 1 {
let mut post_dec = String::from(&first_segment[1..]); let mut post_dec = String::from(&first_segment[1..]);
post_dec.push_str(&second_segment); post_dec.push_str(&second_segment);
@ -261,25 +250,22 @@ pub fn get_primitive_dec(
let mut m: isize = 0; let mut m: isize = 0;
let mut pre = String::from("0"); let mut pre = String::from("0");
let mut post = String::from("0"); let mut post = String::from("0");
while let Some((i,c)) = it.next() { match c { while let Some((i, c)) = it.next() {
match c {
'0' => {} '0' => {}
_ => { _ => {
m = ((i as isize) + 1) * -1; m = ((i as isize) + 1) * -1;
pre = String::from( pre = String::from(&second_segment[i..i + 1]);
&second_segment[i..i+1]); post = String::from(&second_segment[i + 1..]);
post = String::from(
&second_segment[i+1..]);
break; break;
} }
} } }
}
(pre, post, m) (pre, post, m)
}, }
Some(_) => { Some(_) => (first_segment, second_segment, 0),
(first_segment, second_segment, 0)
},
None => { None => {
panic!( panic!("float_common: no chars in first segment.");
"float_common: no chars in first segment.");
} }
} }
} }
@ -287,15 +273,18 @@ pub fn get_primitive_dec(
(first_segment, second_segment, 0) (first_segment, second_segment, 0)
}; };
let (pre_dec_draft, post_dec_draft) = let (pre_dec_draft, post_dec_draft) = round_terminal_digit(pre_dec_unrounded,
round_terminal_digit(pre_dec_unrounded,
post_dec_unrounded, post_dec_unrounded,
last_dec_place - 1); last_dec_place - 1);
f.pre_decimal = Some(pre_dec_draft); f.pre_decimal = Some(pre_dec_draft);
f.post_decimal = Some(post_dec_draft); f.post_decimal = Some(post_dec_draft);
if let Some(capitalized) = sci_mode { if let Some(capitalized) = sci_mode {
let si_ind = if capitalized { 'E' } else { 'e' }; let si_ind = if capitalized {
'E'
} else {
'e'
};
f.suffix = Some(if mantissa >= 0 { f.suffix = Some(if mantissa >= 0 {
format!("{}+{:02}", si_ind, mantissa) format!("{}+{:02}", si_ind, mantissa)
} else { } else {
@ -308,15 +297,12 @@ pub fn get_primitive_dec(
f f
} }
pub fn primitive_to_str_common( pub fn primitive_to_str_common(prim: &FormatPrimitive, field: &FormatField) -> String {
prim: &FormatPrimitive,
field: &FormatField
) -> String {
let mut final_str = String::new(); let mut final_str = String::new();
match prim.prefix { match prim.prefix {
Some(ref prefix) => { Some(ref prefix) => {
final_str.push_str(&prefix); final_str.push_str(&prefix);
}, }
None => {} None => {}
} }
match prim.pre_decimal { match prim.pre_decimal {
@ -324,7 +310,8 @@ pub fn primitive_to_str_common(
final_str.push_str(&pre_decimal); final_str.push_str(&pre_decimal);
} }
None => { None => {
panic!("error, format primitives provided to int, will, incidentally under correct behavior, always have a pre_dec value."); panic!("error, format primitives provided to int, will, incidentally under correct \
behavior, always have a pre_dec value.");
} }
} }
let decimal_places = field.second_field.unwrap_or(6); let decimal_places = field.second_field.unwrap_or(6);
@ -338,8 +325,7 @@ pub fn primitive_to_str_common(
// println!("dec {}, len avail {}", decimal_places, len_avail); // println!("dec {}, len avail {}", decimal_places, len_avail);
final_str.push_str(post_decimal); final_str.push_str(post_decimal);
if *field.field_char != 'g' && if *field.field_char != 'g' && *field.field_char != 'G' {
*field.field_char != 'G' {
let diff = decimal_places - len_avail; let diff = decimal_places - len_avail;
for _ in 0..diff { for _ in 0..diff {
final_str.push('0'); final_str.push('0');
@ -347,19 +333,19 @@ pub fn primitive_to_str_common(
} }
} else { } else {
// println!("printing to only {}", decimal_places); // println!("printing to only {}", decimal_places);
final_str.push_str( final_str.push_str(&post_decimal[0..decimal_places as usize]);
&post_decimal[0..decimal_places as usize]);
} }
} }
} }
None => { None => {
panic!("error, format primitives provided to int, will, incidentally under correct behavior, always have a pre_dec value."); panic!("error, format primitives provided to int, will, incidentally under correct \
behavior, always have a pre_dec value.");
} }
} }
match prim.suffix { match prim.suffix {
Some(ref suffix) => { Some(ref suffix) => {
final_str.push_str(suffix); final_str.push_str(suffix);
}, }
None => {} None => {}
} }

View file

@ -1,12 +1,10 @@
//! formatter for %f %F common-notation floating-point subs //! formatter for %f %F common-notation floating-point subs
use super::super::format_field::FormatField; use super::super::format_field::FormatField;
use super::super::formatter::{InPrefix, FormatPrimitive, Formatter}; use super::super::formatter::{InPrefix, FormatPrimitive, Formatter};
use super::float_common::{FloatAnalysis, use super::float_common::{FloatAnalysis, get_primitive_dec, primitive_to_str_common};
get_primitive_dec,
primitive_to_str_common};
pub struct Floatf { pub struct Floatf {
as_num : f64 as_num: f64,
} }
impl Floatf { impl Floatf {
pub fn new() -> Floatf { pub fn new() -> Floatf {
@ -14,35 +12,25 @@ impl Floatf {
} }
} }
impl Formatter for Floatf { impl Formatter for Floatf {
fn get_primitive( fn get_primitive(&self,
&self,
field: &FormatField, field: &FormatField,
inprefix: &InPrefix, inprefix: &InPrefix,
str_in : &str str_in: &str)
) -> Option<FormatPrimitive> { -> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6) + 1; let second_field = field.second_field.unwrap_or(6) + 1;
let analysis = FloatAnalysis::analyze( let analysis = FloatAnalysis::analyze(&str_in,
&str_in,
inprefix, inprefix,
None, None,
Some(second_field as usize), Some(second_field as usize),
false); false);
let f = get_primitive_dec( let f = get_primitive_dec(inprefix,
inprefix,
&str_in[inprefix.offset..], &str_in[inprefix.offset..],
&analysis, &analysis,
second_field as usize, second_field as usize,
None); None);
Some(f) Some(f)
} }
fn primitive_to_str( fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
&self, primitive_to_str_common(prim, &field)
prim: &FormatPrimitive,
field: FormatField) -> String {
primitive_to_str_common(
prim,
&field
)
} }
} }

View file

@ -4,10 +4,11 @@
use std::u64; use std::u64;
use std::i64; use std::i64;
use super::super::format_field::FormatField; use super::super::format_field::FormatField;
use super::super::formatter::{InPrefix,FormatPrimitive,Base,Formatter,warn_incomplete_conv,get_it_at}; use super::super::formatter::{InPrefix, FormatPrimitive, Base, Formatter, warn_incomplete_conv,
get_it_at};
pub struct Intf { pub struct Intf {
a : u32 a: u32,
} }
// see the Intf::analyze() function below // see the Intf::analyze() function below
@ -15,7 +16,7 @@ struct IntAnalysis {
check_past_max: bool, check_past_max: bool,
past_max: bool, past_max: bool,
is_zero: bool, is_zero: bool,
len_digits: u8 len_digits: u8,
} }
impl Intf { impl Intf {
@ -34,41 +35,37 @@ impl Intf {
// is_zero: true if number is zero, false otherwise // is_zero: true if number is zero, false otherwise
// len_digits: length of digits used to create the int // len_digits: length of digits used to create the int
// important, for example, if we run into a non-valid character // important, for example, if we run into a non-valid character
fn analyze( fn analyze(str_in: &str, signed_out: bool, inprefix: &InPrefix) -> IntAnalysis {
str_in: &str,
signed_out: bool,
inprefix: &InPrefix
) -> IntAnalysis {
// the maximum number of digits we could conceivably // the maximum number of digits we could conceivably
// have before the decimal point without exceeding the // have before the decimal point without exceeding the
// max // max
let mut str_it = get_it_at(inprefix.offset, str_in); let mut str_it = get_it_at(inprefix.offset, str_in);
let max_sd_in = let max_sd_in = if signed_out {
if signed_out {
match inprefix.radix_in { match inprefix.radix_in {
Base::Ten => 19, Base::Ten => 19,
Base::Octal => 21, Base::Octal => 21,
Base::Hex => 16 Base::Hex => 16,
} }
} else { } else {
match inprefix.radix_in { match inprefix.radix_in {
Base::Ten => 20, Base::Ten => 20,
Base::Octal => 22, Base::Octal => 22,
Base::Hex => 16 Base::Hex => 16,
} }
}; };
let mut ret = IntAnalysis { let mut ret = IntAnalysis {
check_past_max: false, check_past_max: false,
past_max: false, past_max: false,
is_zero: false, is_zero: false,
len_digits : 0 len_digits: 0,
}; };
// todo turn this to a while let now that we know // todo turn this to a while let now that we know
// no special behavior on EOI break // no special behavior on EOI break
loop { loop {
let c_opt = str_it.next(); let c_opt = str_it.next();
if let Some(c) = c_opt { match c { if let Some(c) = c_opt {
match c {
'0'...'9' | 'a'...'f' | 'A'...'F' => { '0'...'9' | 'a'...'f' | 'A'...'F' => {
if ret.len_digits == 0 && c == '0' { if ret.len_digits == 0 && c == '0' {
ret.is_zero = true; ret.is_zero = true;
@ -96,15 +93,20 @@ impl Intf {
str_it.put_back(next_ch); str_it.put_back(next_ch);
} }
} }
if ret.past_max { break; } if ret.past_max {
} else { ret.check_past_max = true; } break;
}
} else {
ret.check_past_max = true;
}
} }
} }
_ => { _ => {
warn_incomplete_conv(str_in); warn_incomplete_conv(str_in);
break; break;
} }
} } else { }
} else {
// breaks on EOL // breaks on EOL
break; break;
} }
@ -113,22 +115,21 @@ impl Intf {
} }
// get a FormatPrimitive of the maximum value for the field char // get a FormatPrimitive of the maximum value for the field char
// and given sign // and given sign
fn get_max( fn get_max(fchar: char, sign: i8) -> FormatPrimitive {
fchar : char,
sign : i8
) -> FormatPrimitive {
let mut fmt_prim: FormatPrimitive = Default::default(); let mut fmt_prim: FormatPrimitive = Default::default();
fmt_prim.pre_decimal = Some(String::from(match fchar { fmt_prim.pre_decimal = Some(String::from(match fchar {
'd' | 'i' => match sign { 'd' | 'i' => {
match sign {
1 => "9223372036854775807", 1 => "9223372036854775807",
_ => { _ => {
fmt_prim.prefix = Some(String::from("-")); fmt_prim.prefix = Some(String::from("-"));
"9223372036854775808" "9223372036854775808"
} }
}, }
}
'x' | 'X' => "ffffffffffffffff", 'x' | 'X' => "ffffffffffffffff",
'o' => "1777777777777777777777", 'o' => "1777777777777777777777",
'u' | _ => "18446744073709551615" 'u' | _ => "18446744073709551615",
})); }));
fmt_prim fmt_prim
} }
@ -147,59 +148,50 @@ impl Intf {
// - if the string falls outside bounds: // - if the string falls outside bounds:
// for i64 output, the int minimum or int max (depending on sign) // for i64 output, the int minimum or int max (depending on sign)
// for u64 output, the u64 max in the output radix // for u64 output, the u64 max in the output radix
fn conv_from_segment( fn conv_from_segment(segment: &str, radix_in: Base, fchar: char, sign: i8) -> FormatPrimitive {
segment : &str,
radix_in : Base,
fchar : char,
sign : i8,
) ->
FormatPrimitive
{
match fchar { match fchar {
'i' | 'd' => { 'i' | 'd' => {
match i64::from_str_radix(segment, radix_in as u32) { match i64::from_str_radix(segment, radix_in as u32) {
Ok(i) => { Ok(i) => {
let mut fmt_prim : FormatPrimitive = let mut fmt_prim: FormatPrimitive = Default::default();
Default::default();
if sign == -1 { if sign == -1 {
fmt_prim.prefix = Some(String::from("-")); fmt_prim.prefix = Some(String::from("-"));
} }
fmt_prim.pre_decimal = fmt_prim.pre_decimal = Some(format!("{}", i));
Some(format!("{}", i));
fmt_prim fmt_prim
} }
Err(_) => Intf::get_max(fchar, sign) Err(_) => Intf::get_max(fchar, sign),
}
} }
},
_ => { _ => {
match u64::from_str_radix(segment, radix_in as u32) { match u64::from_str_radix(segment, radix_in as u32) {
Ok(u) => { Ok(u) => {
let mut fmt_prim : FormatPrimitive = let mut fmt_prim: FormatPrimitive = Default::default();
Default::default(); let u_f = if sign == -1 {
let u_f = u64::MAX - (u - 1)
if sign == -1 { u64::MAX - (u -1) } else {
} else { u }; u
};
fmt_prim.pre_decimal = Some(match fchar { fmt_prim.pre_decimal = Some(match fchar {
'X' => format!("{:X}", u_f), 'X' => format!("{:X}", u_f),
'x' => format!("{:x}", u_f), 'x' => format!("{:x}", u_f),
'o' => format!("{:o}", u_f), 'o' => format!("{:o}", u_f),
_ => format!("{}", u_f) _ => format!("{}", u_f),
}); });
fmt_prim fmt_prim
} }
Err(_) => Intf::get_max(fchar, sign) Err(_) => Intf::get_max(fchar, sign),
} }
} }
} }
} }
} }
impl Formatter for Intf { impl Formatter for Intf {
fn get_primitive( fn get_primitive(&self,
&self,
field: &FormatField, field: &FormatField,
inprefix: &InPrefix, inprefix: &InPrefix,
str_in : &str str_in: &str)
) -> Option<FormatPrimitive> { -> Option<FormatPrimitive> {
let begin = inprefix.offset; let begin = inprefix.offset;
@ -219,23 +211,20 @@ impl Formatter for Intf {
let radix_out = match *field.field_char { let radix_out = match *field.field_char {
'd' | 'i' | 'u' => Base::Ten, 'd' | 'i' | 'u' => Base::Ten,
'x' | 'X' => Base::Hex, 'x' | 'X' => Base::Hex,
'o' | _ => Base::Octal 'o' | _ => Base::Octal,
}; };
let radix_mismatch = !radix_out.eq(&inprefix.radix_in); let radix_mismatch = !radix_out.eq(&inprefix.radix_in);
let decr_from_max :bool = inprefix.sign == -1 && let decr_from_max: bool = inprefix.sign == -1 && *field.field_char != 'i';
*field.field_char !='i';
let end = begin + convert_hints.len_digits as usize; let end = begin + convert_hints.len_digits as usize;
// convert to int if any one of these is true: // convert to int if any one of these is true:
// - number of digits in int indicates it may be past max // - number of digits in int indicates it may be past max
// - we're subtracting from the max // - we're subtracting from the max
// - we're converting the base // - we're converting the base
if convert_hints.check_past_max if convert_hints.check_past_max || decr_from_max || radix_mismatch {
|| decr_from_max || radix_mismatch {
// radix of in and out is the same. // radix of in and out is the same.
let segment = String::from(&str_in[begin..end]); let segment = String::from(&str_in[begin..end]);
let m = Intf::conv_from_segment( let m = Intf::conv_from_segment(&segment,
&segment,
inprefix.radix_in.clone(), inprefix.radix_in.clone(),
*field.field_char, *field.field_char,
inprefix.sign); inprefix.sign);
@ -251,8 +240,7 @@ impl Formatter for Intf {
fmt_prim.prefix = Some(String::from("-")); fmt_prim.prefix = Some(String::from("-"));
} }
fmt_prim.pre_decimal = Some(String::from fmt_prim.pre_decimal = Some(String::from(&str_in[begin..end]));
(&str_in[begin..end]));
fmt_prim fmt_prim
} }
} else { } else {
@ -260,15 +248,12 @@ impl Formatter for Intf {
}) })
} }
fn primitive_to_str( fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
&self,
prim: &FormatPrimitive,
field: FormatField) -> String {
let mut finalstr: String = String::new(); let mut finalstr: String = String::new();
match prim.prefix { match prim.prefix {
Some(ref prefix) => { Some(ref prefix) => {
finalstr.push_str(&prefix); finalstr.push_str(&prefix);
}, }
None => {} None => {}
} }
// integral second fields is zero-padded minimum-width // integral second fields is zero-padded minimum-width
@ -289,7 +274,8 @@ impl Formatter for Intf {
finalstr.push_str(&pre_decimal); finalstr.push_str(&pre_decimal);
} }
None => { None => {
panic!("error, format primitives provided to int, will, incidentally under correct behavior, always have a pre_dec value."); panic!("error, format primitives provided to int, will, incidentally under \
correct behavior, always have a pre_dec value.");
} }
} }
finalstr finalstr

View file

@ -1,12 +1,10 @@
//! formatter for %e %E scientific notation subs //! formatter for %e %E scientific notation subs
use super::super::format_field::FormatField; use super::super::format_field::FormatField;
use super::super::formatter::{InPrefix, FormatPrimitive, Formatter}; use super::super::formatter::{InPrefix, FormatPrimitive, Formatter};
use super::float_common::{FloatAnalysis, use super::float_common::{FloatAnalysis, get_primitive_dec, primitive_to_str_common};
get_primitive_dec,
primitive_to_str_common};
pub struct Scif { pub struct Scif {
as_num : f64 as_num: f64,
} }
impl Scif { impl Scif {
pub fn new() -> Scif { pub fn new() -> Scif {
@ -14,34 +12,25 @@ impl Scif {
} }
} }
impl Formatter for Scif { impl Formatter for Scif {
fn get_primitive( fn get_primitive(&self,
&self,
field: &FormatField, field: &FormatField,
inprefix: &InPrefix, inprefix: &InPrefix,
str_in : &str str_in: &str)
) -> Option<FormatPrimitive> { -> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6) + 1; let second_field = field.second_field.unwrap_or(6) + 1;
let analysis = FloatAnalysis::analyze( let analysis = FloatAnalysis::analyze(str_in,
str_in,
inprefix, inprefix,
Some(second_field as usize + 1), Some(second_field as usize + 1),
None, None,
false); false);
let f = get_primitive_dec( let f = get_primitive_dec(inprefix,
inprefix,
&str_in[inprefix.offset..], &str_in[inprefix.offset..],
&analysis, &analysis,
second_field as usize, second_field as usize,
Some(*field.field_char == 'E')); Some(*field.field_char == 'E'));
Some(f) Some(f)
} }
fn primitive_to_str( fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
&self, primitive_to_str_common(prim, &field)
prim: &FormatPrimitive,
field: FormatField) -> String {
primitive_to_str_common(
prim,
&field
)
} }
} }

View file

@ -24,8 +24,10 @@ fn warn_char_constant_ign(remaining_bytes: Vec<u8>) {
Err(e) => { Err(e) => {
match e { match e {
env::VarError::NotPresent => { env::VarError::NotPresent => {
cli::err_msg(&format!("warning: {:?}: character(s) following character constant have been ignored", &*remaining_bytes)); cli::err_msg(&format!("warning: {:?}: character(s) following character \
}, constant have been ignored",
&*remaining_bytes));
}
_ => {} _ => {}
} }
} }
@ -35,9 +37,7 @@ fn warn_char_constant_ign(remaining_bytes: Vec<u8>) {
// this function looks at the first few // this function looks at the first few
// characters of an argument and returns a value if we can learn // characters of an argument and returns a value if we can learn
// a value from that (e.g. no argument? return 0, char constant? ret value) // a value from that (e.g. no argument? return 0, char constant? ret value)
fn get_provided( fn get_provided(str_in_opt: Option<&String>) -> Option<u8> {
str_in_opt : Option<&String>
) -> Option<u8> {
const C_S_QUOTE: u8 = 39; const C_S_QUOTE: u8 = 39;
const C_D_QUOTE: u8 = 34; const C_D_QUOTE: u8 = 34;
match str_in_opt { match str_in_opt {
@ -56,23 +56,26 @@ fn get_provided(
warn_char_constant_ign(ignored); warn_char_constant_ign(ignored);
} }
second_byte as u8 second_byte as u8
}, }
// no byte after quote // no byte after quote
None => { None => {
let so_far = let so_far = (qchar as u8 as char).to_string();
(qchar as u8 as char).to_string();
warn_expected_numeric(&so_far); warn_expected_numeric(&so_far);
0 as u8 0 as u8
} }
}); });
}, }
// first byte is not quote // first byte is not quote
_ => { return None; } _ => {
return None;
}
// no first byte // no first byte
} }
} else { Some(0 as u8) } } else {
Some(0 as u8)
} }
None =>{ Some(0) } }
None => Some(0),
} }
} }
@ -81,26 +84,38 @@ fn get_provided(
// a base, // a base,
// and an offset for index after all // and an offset for index after all
// initial spacing, sign, base prefix, and leading zeroes // initial spacing, sign, base prefix, and leading zeroes
fn get_inprefix( fn get_inprefix(str_in: &String, field_type: &FieldType) -> InPrefix {
str_in : &String,
field_type : &FieldType
) -> InPrefix {
let mut str_it = str_in.chars(); let mut str_it = str_in.chars();
let mut ret = InPrefix { radix_in: Base::Ten, sign: 1, offset: 0 }; let mut ret = InPrefix {
radix_in: Base::Ten,
sign: 1,
offset: 0,
};
let mut topchar = str_it.next().clone(); let mut topchar = str_it.next().clone();
// skip spaces and ensure topchar is the first non-space char // skip spaces and ensure topchar is the first non-space char
// (or None if none exists) // (or None if none exists)
loop { loop {
match topchar match topchar {
{ Some(' ') => {
Some(' ')=>{ret.offset+=1; topchar=str_it.next();}, ret.offset += 1;
_=>{ break; } topchar = str_it.next();
}
_ => {
break;
}
} }
} }
// parse sign // parse sign
match topchar { match topchar {
Some('+')=>{ ret.offset+=1; topchar=str_it.next(); } Some('+') => {
Some('-')=>{ ret.sign = -1; ret.offset+=1; topchar=str_it.next(); } ret.offset += 1;
topchar = str_it.next();
}
Some('-') => {
ret.sign = -1;
ret.offset += 1;
topchar = str_it.next();
}
_ => {} _ => {}
} }
// we want to exit with offset being // we want to exit with offset being
@ -128,13 +143,13 @@ fn get_inprefix(
ret.offset += 2; ret.offset += 2;
ret.radix_in = Base::Hex; ret.radix_in = Base::Hex;
do_clean_lead_zeroes = true; do_clean_lead_zeroes = true;
}, }
e @ '0'...'9' => { e @ '0'...'9' => {
ret.offset += 1; ret.offset += 1;
match *field_type { match *field_type {
FieldType::Intf => { FieldType::Intf => {
ret.radix_in = Base::Octal; ret.radix_in = Base::Octal;
}, }
_ => {} _ => {}
} }
if e == '0' { if e == '0' {
@ -159,21 +174,25 @@ fn get_inprefix(
// current offset is not the final offset. // current offset is not the final offset.
match ch_zero { match ch_zero {
'0' => { '0' => {
if !(is_hex && first) { ret.offset+=1; } if !(is_hex && first) {
}, ret.offset += 1;
}
}
// if decimal, keep last zero if one exists // if decimal, keep last zero if one exists
// (it's possible for last zero to // (it's possible for last zero to
// not exist at this branch if we're in hex input) // not exist at this branch if we're in hex input)
'.' => { '.' => break,
break
},
// other digit, etc. // other digit, etc.
_ => { _ => {
if !(is_hex && first) { ret.offset+=1; } if !(is_hex && first) {
break ret.offset += 1;
}
break;
} }
} }
if first { first = false; } if first {
first = false;
}
} }
} }
@ -185,10 +204,7 @@ fn get_inprefix(
// this is the function a Sub's print will delegate to // this is the function a Sub's print will delegate to
// if it is a numeric field, passing the field details // if it is a numeric field, passing the field details
// and an iterator to the argument // and an iterator to the argument
pub fn num_format( pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option<String> {
field: &FormatField,
in_str_opt: Option<&String>
) -> Option<String> {
let fchar = field.field_char.clone(); let fchar = field.field_char.clone();
@ -204,7 +220,9 @@ pub fn num_format(
FieldType::CninetyNineHexFloatf => Box::new(CninetyNineHexFloatf::new()), FieldType::CninetyNineHexFloatf => Box::new(CninetyNineHexFloatf::new()),
FieldType::Scif => Box::new(Scif::new()), FieldType::Scif => Box::new(Scif::new()),
FieldType::Decf => Box::new(Decf::new()), FieldType::Decf => Box::new(Decf::new()),
_ => { panic!("asked to do num format with non-num fieldtype"); } _ => {
panic!("asked to do num format with non-num fieldtype");
}
}; };
let prim_opt= let prim_opt=
// if we can get an assumed value from looking at the first // if we can get an assumed value from looking at the first
@ -259,12 +277,7 @@ pub fn num_format(
// if we have a formatPrimitive, print its results // if we have a formatPrimitive, print its results
// according to the field-char appropriate Formatter // according to the field-char appropriate Formatter
if let Some(prim) = prim_opt { if let Some(prim) = prim_opt {
Some( Some(fmtr.primitive_to_str(&prim, field.clone()))
fmtr.primitive_to_str(
&prim,
field.clone()
)
)
} else { } else {
None None
} }

View file

@ -34,17 +34,17 @@ fn convert_asterisk_arg_int(asterisk_arg : &String) -> isize {
second_field: Some(0), second_field: Some(0),
orig: asterisk_arg, orig: asterisk_arg,
field_type: &field_type, field_type: &field_type,
field_char: &field_char field_char: &field_char,
}; };
num_format::num_format( num_format::num_format(&field_info, Some(asterisk_arg))
&field_info, .unwrap()
Some(asterisk_arg) .parse::<isize>()
).unwrap().parse::<isize>().unwrap() .unwrap()
} }
pub enum CanAsterisk<T> { pub enum CanAsterisk<T> {
Fixed(T), Fixed(T),
Asterisk Asterisk,
} }
// Sub is a tokenizer which creates tokens // Sub is a tokenizer which creates tokens
@ -54,13 +54,14 @@ pub struct Sub {
second_field: CanAsterisk<Option<u32>>, second_field: CanAsterisk<Option<u32>>,
field_char: char, field_char: char,
field_type: FieldType, field_type: FieldType,
orig: String orig: String,
} }
impl Sub { impl Sub {
pub fn new(min_width: CanAsterisk<Option<isize>>, pub fn new(min_width: CanAsterisk<Option<isize>>,
second_field: CanAsterisk<Option<u32>>, second_field: CanAsterisk<Option<u32>>,
field_char: char, field_char: char,
orig: String) -> Sub { orig: String)
-> Sub {
// for more dry printing, field characters are grouped // for more dry printing, field characters are grouped
// in initialization of token. // in initialization of token.
let field_type = match field_char { let field_type = match field_char {
@ -82,10 +83,9 @@ impl Sub {
second_field: second_field, second_field: second_field,
field_char: field_char, field_char: field_char,
field_type: field_type, field_type: field_type,
orig: orig orig: orig,
} }
} }
} }
struct SubParser { struct SubParser {
@ -96,7 +96,7 @@ struct SubParser {
second_field_is_asterisk: bool, second_field_is_asterisk: bool,
specifiers_found: bool, specifiers_found: bool,
field_char: Option<char>, field_char: Option<char>,
text_so_far : String text_so_far: String,
} }
impl SubParser { impl SubParser {
@ -109,7 +109,7 @@ impl SubParser {
second_field_is_asterisk: false, second_field_is_asterisk: false,
specifiers_found: false, specifiers_found: false,
field_char: None, field_char: None,
text_so_far : String::new() text_so_far: String::new(),
} }
} }
fn from_it(it: &mut PutBackN<Chars>, fn from_it(it: &mut PutBackN<Chars>,
@ -127,9 +127,7 @@ impl SubParser {
fn build_token(parser: SubParser) -> Box<token::Token> { fn build_token(parser: SubParser) -> Box<token::Token> {
// not a self method so as to allow move of subparser vals. // not a self method so as to allow move of subparser vals.
// return new Sub struct as token // return new Sub struct as token
let t: Box<token::Token> = Box::new( let t: Box<token::Token> = Box::new(Sub::new(if parser.min_width_is_asterisk {
Sub::new(
if parser.min_width_is_asterisk {
CanAsterisk::Asterisk CanAsterisk::Asterisk
} else { } else {
CanAsterisk::Fixed(parser.min_width_tmp.map(|x| x.parse::<isize>().unwrap())) CanAsterisk::Fixed(parser.min_width_tmp.map(|x| x.parse::<isize>().unwrap()))
@ -140,14 +138,10 @@ impl SubParser {
CanAsterisk::Fixed(parser.second_field_tmp.map(|x| x.parse::<u32>().unwrap())) CanAsterisk::Fixed(parser.second_field_tmp.map(|x| x.parse::<u32>().unwrap()))
}, },
parser.field_char.unwrap(), parser.field_char.unwrap(),
parser.text_so_far parser.text_so_far));
)
);
t t
} }
fn sub_vals_retrieved(&mut self, fn sub_vals_retrieved(&mut self, it: &mut PutBackN<Chars>) -> bool {
it: &mut PutBackN<Chars>)
-> bool {
if !SubParser::successfully_eat_prefix(it, &mut self.text_so_far) { if !SubParser::successfully_eat_prefix(it, &mut self.text_so_far) {
return false; return false;
@ -158,10 +152,22 @@ impl SubParser {
// though, as we want to mimic the original behavior of printing // though, as we want to mimic the original behavior of printing
// the field as interpreted up until the error in the field. // the field as interpreted up until the error in the field.
let mut legal_fields=vec![ let mut legal_fields = vec![// 'a', 'A', //c99 hex float implementation not yet complete
//'a', 'A', //c99 hex float implementation not yet complete 'b',
'b', 'c', 'd', 'e', 'E', 'f', 'c',
'F', 'g', 'G', 'i', 'o','s', 'u', 'x', 'X']; 'd',
'e',
'E',
'f',
'F',
'g',
'G',
'i',
'o',
's',
'u',
'x',
'X'];
let mut specifiers = vec!['h', 'j', 'l', 'L', 't', 'z']; let mut specifiers = vec!['h', 'j', 'l', 'L', 't', 'z'];
legal_fields.sort(); legal_fields.sort();
specifiers.sort(); specifiers.sort();
@ -173,8 +179,7 @@ impl SubParser {
match ch as char { match ch as char {
'-' | '*' | '0'...'9' => { '-' | '*' | '0'...'9' => {
if !self.past_decimal { if !self.past_decimal {
if self.min_width_is_asterisk if self.min_width_is_asterisk || self.specifiers_found {
|| self.specifiers_found {
err_conv(&self.text_so_far); err_conv(&self.text_so_far);
} }
if self.min_width_tmp.is_none() { if self.min_width_tmp.is_none() {
@ -190,14 +195,14 @@ impl SubParser {
} }
x.push(ch); x.push(ch);
} }
None => { panic!("should be unreachable"); } None => {
panic!("should be unreachable");
}
} }
} else { } else {
// second field should never have a // second field should never have a
// negative value // negative value
if self.second_field_is_asterisk if self.second_field_is_asterisk || ch == '-' || self.specifiers_found {
|| ch == '-'
|| self.specifiers_found {
err_conv(&self.text_so_far); err_conv(&self.text_so_far);
} }
if self.second_field_tmp.is_none() { if self.second_field_tmp.is_none() {
@ -213,21 +218,23 @@ impl SubParser {
} }
x.push(ch); x.push(ch);
} }
None => { panic!("should be unreachable"); } None => {
panic!("should be unreachable");
}
}
} }
} }
},
'.' => { '.' => {
if !self.past_decimal { if !self.past_decimal {
self.past_decimal = true; self.past_decimal = true;
} else { } else {
err_conv(&self.text_so_far); err_conv(&self.text_so_far);
} }
}, }
x if legal_fields.binary_search(&x).is_ok() => { x if legal_fields.binary_search(&x).is_ok() => {
self.field_char = Some(ch); self.field_char = Some(ch);
self.text_so_far.push(ch); self.text_so_far.push(ch);
break break;
} }
x if specifiers.binary_search(&x).is_ok() => { x if specifiers.binary_search(&x).is_ok() => {
if !self.past_decimal { if !self.past_decimal {
@ -242,8 +249,9 @@ impl SubParser {
} }
} }
} }
if ! self.field_char.is_some() if !self.field_char.is_some() {
{ err_conv(&self.text_so_far); } err_conv(&self.text_so_far);
}
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"));
@ -262,15 +270,13 @@ impl SubParser {
true true
} }
fn successfully_eat_prefix(it: &mut PutBackN<Chars>, fn successfully_eat_prefix(it: &mut PutBackN<Chars>, text_so_far: &mut String) -> bool {
text_so_far : &mut String ) -> 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
let preface = it.next(); let preface = it.next();
let n_ch = it.next(); let n_ch = it.next();
if preface == Some('%') && if preface == Some('%') && n_ch != Some('%') {
n_ch != Some('%') {
match n_ch { match n_ch {
Some(x) => { Some(x) => {
it.put_back(x); it.put_back(x);
@ -292,8 +298,7 @@ impl SubParser {
// 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
if (field_char == 's' && if (field_char == 's' && self.min_width_tmp == Some(String::from("0"))) ||
self.min_width_tmp == Some(String::from("0"))) ||
(field_char == 'c' && (field_char == 'c' &&
(self.min_width_tmp == Some(String::from("0")) || self.past_decimal)) || (self.min_width_tmp == Some(String::from("0")) || self.past_decimal)) ||
(field_char == 'b' && (field_char == 'b' &&
@ -322,7 +327,7 @@ impl token::Token for Sub {
match pf_args_it.next() { match pf_args_it.next() {
// temporary, use intf.rs instead // temporary, use intf.rs instead
Some(x) => Some(convert_asterisk_arg_int(x)), Some(x) => Some(convert_asterisk_arg_int(x)),
None => Some(0) None => Some(0),
} }
} }
}, },
@ -338,8 +343,8 @@ impl token::Token for Sub {
} else { } else {
Some(result as u32) Some(result as u32)
} }
}, }
None => Some(0) None => Some(0),
} }
} }
}, },
@ -361,32 +366,24 @@ impl token::Token for Sub {
match *field.field_char { match *field.field_char {
's' => { 's' => {
Some(match field.second_field { Some(match field.second_field {
Some(max) =>{ Some(max) => String::from(&arg_string[..max as usize]),
String::from( None => arg_string.clone(),
&arg_string[..max as usize])
}
None => {
arg_string.clone()
}
}) })
} }
'b' => { 'b' => {
let mut a_it=PutBackN::new( let mut a_it = PutBackN::new(arg_string.chars());
arg_string.chars()); UnescapedText::from_it_core(&mut a_it, true);
UnescapedText::from_it_core(
&mut a_it, true);
None None
} }
// for 'c': get iter of string vals, // for 'c': get iter of string vals,
// get opt<char> of first val // get opt<char> of first val
// and map it to opt<String> // and map it to opt<String>
'c' | _ => arg_string.chars().next().map( 'c' | _ => arg_string.chars().next().map(|x| x.to_string()),
|x| x.to_string()) }
}
None => None,
} }
},
None => None
} }
},
_ => { _ => {
// non string/char fields are delegated to num_format // non string/char fields are delegated to num_format
num_format::num_format(&field, pf_arg) num_format::num_format(&field, pf_arg)
@ -395,7 +392,8 @@ impl token::Token for Sub {
match pre_min_width_opt { match pre_min_width_opt {
// if have a string, print it, ensuring minimum width is met. // if have a string, print it, ensuring minimum width is met.
Some(pre_min_width) => { Some(pre_min_width) => {
print!("{}", match field.min_width { print!("{}",
match field.min_width {
Some(min_width) => { Some(min_width) => {
let diff: isize = min_width.abs() as isize - let diff: isize = min_width.abs() as isize -
pre_min_width.len() as isize; pre_min_width.len() as isize;
@ -418,7 +416,7 @@ impl token::Token for Sub {
pre_min_width pre_min_width
} }
} }
None => { pre_min_width } None => pre_min_width,
}); });
} }
None => {} None => {}

View file

@ -26,7 +26,5 @@ pub trait Token {
// a number of arguments equal to the number of argument-using tokens // a number of arguments equal to the number of argument-using tokens
pub trait Tokenizer { pub trait Tokenizer {
fn from_it(it: &mut PutBackN<Chars>, fn from_it(it: &mut PutBackN<Chars>, args: &mut Peekable<Iter<String>>) -> Option<Box<Token>>;
args: &mut Peekable<Iter<String>>)
-> Option<Box<Token>>;
} }

View file

@ -20,12 +20,7 @@ impl UnescapedText {
// take an iterator to the format string // take an iterator to the format string
// consume between min and max chars // consume between min and max chars
// and return it as a base-X number // and return it as a base-X number
fn base_to_u32( fn base_to_u32(min_chars: u8, max_chars: u8, base: u32, it: &mut PutBackN<Chars>) -> u32 {
min_chars: u8,
max_chars: u8,
base : u32,
it: &mut PutBackN<Chars>
) -> u32 {
let mut retval: u32 = 0; let mut retval: u32 = 0;
let mut found = 0; let mut found = 0;
while found < max_chars { while found < max_chars {
@ -42,10 +37,10 @@ impl UnescapedText {
} }
None => { None => {
it.put_back(digit); it.put_back(digit);
break break;
}
} }
} }
},
None => { None => {
break; break;
} }
@ -74,10 +69,7 @@ impl UnescapedText {
preface, preface,
val, val,
leading_zeros); leading_zeros);
if (val < 159 && (val != 36 && if (val < 159 && (val != 36 && val != 64 && val != 96)) || (val > 55296 && val < 57343) {
val != 64 &&
val != 96)) ||
(val > 55296 && val < 57343) {
println!("{}", err_msg);//todo stderr println!("{}", err_msg);//todo stderr
exit(cli::EXIT_ERR); exit(cli::EXIT_ERR);
} }
@ -87,14 +79,10 @@ impl UnescapedText {
// adding the unescaped bytes // adding the unescaped bytes
// to the passed byte_vec // to the passed byte_vec
// in subs_mode change octal behavior // in subs_mode change octal behavior
fn handle_escaped( fn handle_escaped(byte_vec: &mut Vec<u8>, it: &mut PutBackN<Chars>, subs_mode: bool) {
byte_vec: &mut Vec<u8>,
it: &mut PutBackN<Chars>,
subs_mode: bool
) {
let ch = match it.next() { let ch = match it.next() {
Some(x) => x, Some(x) => x,
None => '\\' None => '\\',
}; };
match ch { match ch {
'0'...'9' | 'x' => { '0'...'9' | 'x' => {
@ -103,9 +91,10 @@ impl UnescapedText {
let mut base = 16; let mut base = 16;
let ignore = false; let ignore = false;
match ch { match ch {
'x'=>{ }, 'x' => {}
e @ '0'...'9' => { e @ '0'...'9' => {
max_len=3; base =8; max_len = 3;
base = 8;
// in practice, gnu coreutils printf // in practice, gnu coreutils printf
// interprets octals without a // interprets octals without a
// leading zero in %b // leading zero in %b
@ -116,23 +105,21 @@ impl UnescapedText {
// we'd set this to true. // we'd set this to true.
// if subs_mode && e != '0' // if subs_mode && e != '0'
// { ignore = true; } // { ignore = true; }
if ! subs_mode || e != '0' if !subs_mode || e != '0' {
{ it.put_back(ch); } it.put_back(ch);
}
} }
_ => {} _ => {}
} }
if !ignore { if !ignore {
let val = (UnescapedText::base_to_u32(min_len, let val = (UnescapedText::base_to_u32(min_len, max_len, base, it) % 256) as u8;
max_len,
base,
it) % 256) as u8;
byte_vec.push(val); byte_vec.push(val);
let bvec = [val]; let bvec = [val];
cli::flush_bytes(&bvec); cli::flush_bytes(&bvec);
} else { } else {
byte_vec.push(ch as u8); byte_vec.push(ch as u8);
} }
}, }
e @ _ => { e @ _ => {
// only for hex and octal // only for hex and octal
// is byte encoding specified. // is byte encoding specified.
@ -156,21 +143,20 @@ impl UnescapedText {
'f' => '\x0C', 'f' => '\x0C',
// escape character // escape character
'e' => '\x1B', 'e' => '\x1B',
'c' => { exit(cli::EXIT_OK) }, 'c' => exit(cli::EXIT_OK),
'u' | 'U' => { 'u' | 'U' => {
let len = match e { let len = match e {
'u' => 4, 'u' => 4,
'U' | _ => 8 'U' | _ => 8,
}; };
let val = UnescapedText::base_to_u32(len, let val = UnescapedText::base_to_u32(len, len, 16, it);
len,
16,
it);
UnescapedText::validate_iec(val, false); UnescapedText::validate_iec(val, false);
if let Some(c) = from_u32(val) { if let Some(c) = from_u32(val) {
c c
} else { '-' } } else {
}, '-'
}
}
_ => { _ => {
s.push('\\'); s.push('\\');
ch ch
@ -188,15 +174,16 @@ impl UnescapedText {
// and return a wrapper around a Vec<u8> of unescaped bytes // and return a wrapper around a Vec<u8> of unescaped bytes
// break on encounter of sub symbol ('%[^%]') unless called // break on encounter of sub symbol ('%[^%]') unless called
// through %b subst. // through %b subst.
pub fn from_it_core(it: &mut PutBackN<Chars>, pub fn from_it_core(it: &mut PutBackN<Chars>, subs_mode: bool) -> Option<Box<token::Token>> {
subs_mode: bool) -> Option<Box<token::Token>> {
let mut addchar = false; let mut addchar = false;
let mut new_text = UnescapedText::new(); let mut new_text = UnescapedText::new();
let mut tmp_str = String::new(); let mut tmp_str = String::new();
{ {
let mut new_vec: &mut Vec<u8> = &mut (new_text.0); let mut new_vec: &mut Vec<u8> = &mut (new_text.0);
while let Some(ch) = it.next() { while let Some(ch) = it.next() {
if ! addchar { addchar = true; } if !addchar {
addchar = true;
}
match ch as char { match ch as char {
x if x != '\\' && x != '%' => { x if x != '\\' && x != '%' => {
// lazy branch eval // lazy branch eval
@ -217,9 +204,7 @@ impl UnescapedText {
new_vec.extend(tmp_str.bytes()); new_vec.extend(tmp_str.bytes());
tmp_str = String::new(); tmp_str = String::new();
} }
UnescapedText::handle_escaped(new_vec, UnescapedText::handle_escaped(new_vec, it, subs_mode)
it,
subs_mode)
} }
x if x == '%' && !subs_mode => { x if x == '%' && !subs_mode => {
if let Some(follow) = it.next() { if let Some(follow) = it.next() {
@ -229,11 +214,11 @@ impl UnescapedText {
} else { } else {
it.put_back(follow); it.put_back(follow);
it.put_back(ch); it.put_back(ch);
break break;
} }
} else { } else {
it.put_back(ch); it.put_back(ch);
break break;
} }
} }
_ => { _ => {
@ -248,7 +233,7 @@ impl UnescapedText {
} }
match addchar { match addchar {
true => Some(Box::new(new_text)), true => Some(Box::new(new_text)),
false => None false => None,
} }
} }
} }

View file

@ -14,222 +14,267 @@ fn expect_stdout(input: Vec<&str>, expected: &str) {
} }
#[test] #[test]
fn basic_literal() { expect_stdout( fn basic_literal() {
vec!("hello world"), "hello world"); } expect_stdout(vec!["hello world"], "hello world");
#[test]
fn escaped_tab() { expect_stdout(
vec!("hello\\t world"), "hello\t world"); }
#[test]
fn escaped_newline() { expect_stdout(
vec!("hello\\n world"), "hello\n world"); }
#[test]
fn escaped_slash() { expect_stdout(
vec!("hello\\\\ world"), "hello\\ world"); }
#[test]
fn escaped_hex() { expect_stdout(
vec!("\\x41"), "A"); }
#[test]
fn escaped_octal() { expect_stdout(
vec!("\\101"), "A"); }
#[test]
fn escaped_unicode_fourdigit() { expect_stdout(
vec!("\\u0125"), "ĥ"); }
#[test]
fn escaped_unicode_eightdigit() { expect_stdout(
vec!("\\U00000125"), "ĥ"); }
#[test]
fn escaped_percent_sign() { expect_stdout(
vec!("hello%% world"), "hello% world"); }
#[test]
fn escaped_unrecognized() { expect_stdout(
vec!("c\\d"), "c\\d"); }
#[test]
fn sub_string() { expect_stdout(
vec!("hello %s", "world"), "hello world"); }
#[test]
fn sub_multifield() { expect_stdout(
vec!("%s %s", "hello", "world"), "hello world"); }
#[test]
fn sub_repeat_formatstr() { expect_stdout(
vec!("%s.", "hello", "world"), "hello.world."); }
#[test]
fn sub_string_ignore_escapes() { expect_stdout(
vec!("hello %s", "\\tworld"), "hello \\tworld"); }
#[test]
fn sub_bstring_handle_escapes() { expect_stdout(
vec!("hello %b", "\\tworld"), "hello \tworld"); }
#[test]
fn sub_bstring_ignore_subs() { expect_stdout(
vec!("hello %b", "world %% %i"), "hello world %% %i"); }
#[test]
fn sub_char() { expect_stdout(
vec!("the letter %c", "A"), "the letter A"); }
#[test]
fn sub_num_int() { expect_stdout(
vec!("twenty is %i", "20"), "twenty is 20"); }
#[test]
fn sub_num_int_minwidth() { expect_stdout(
vec!("twenty is %1i", "20"), "twenty is 20"); }
#[test]
fn sub_num_int_neg() { expect_stdout(
vec!("neg. twenty is %i", "-20"), "neg. twenty is -20"); }
#[test]
fn sub_num_int_oct_in() { expect_stdout(
vec!("twenty is %i", "024"), "twenty is 20"); }
#[test]
fn sub_num_int_oct_in_neg() { expect_stdout(
vec!("neg. twenty is %i", "-024"), "neg. twenty is -20"); }
#[test]
fn sub_num_int_hex_in() { expect_stdout(
vec!("twenty is %i", "0x14"), "twenty is 20"); }
#[test]
fn sub_num_int_hex_in_neg() { expect_stdout(
vec!("neg. twenty is %i", "-0x14"), "neg. twenty is -20"); }
#[test]
fn sub_num_int_charconst_in() { expect_stdout(
vec!("ninetyseven is %i", "'a"), "ninetyseven is 97"); }
#[test]
fn sub_num_uint() { expect_stdout(
vec!("twenty is %u", "20"), "twenty is 20"); }
#[test]
fn sub_num_octal() { expect_stdout(
vec!("twenty in octal is %o", "20"), "twenty in octal is 24"); }
#[test]
fn sub_num_hex_lower() { expect_stdout(
vec!("thirty in hex is %x", "30"), "thirty in hex is 1e"); }
#[test]
fn sub_num_hex_upper() { expect_stdout(
vec!("thirty in hex is %X", "30"), "thirty in hex is 1E"); }
#[test]
fn sub_num_float() { expect_stdout(
vec!("twenty is %f", "20"), "twenty is 20.000000"); }
#[test]
fn sub_num_float_round() { expect_stdout(
vec!("two is %f", "1.9999995"), "two is 2.000000"); }
#[test]
fn sub_num_sci_lower() { expect_stdout(
vec!("twenty is %e", "20"), "twenty is 2.000000e+01"); }
#[test]
fn sub_num_sci_upper() { expect_stdout(
vec!("twenty is %E", "20"), "twenty is 2.000000E+01"); }
#[test]
fn sub_num_sci_trunc() { expect_stdout(
vec!("pi is ~ %e", "3.1415926535"), "pi is ~ 3.141593e+00"); }
#[test]
fn sub_num_dec_trunc() { expect_stdout(
vec!("pi is ~ %g", "3.1415926535"), "pi is ~ 3.141593"); }
#[test]
fn sub_minwidth() { expect_stdout(
vec!("hello %7s", "world"), "hello world"); }
#[test]
fn sub_minwidth_negative() { expect_stdout(
vec!("hello %-7s", "world"), "hello world "); }
#[test]
fn sub_str_max_chars_input() { expect_stdout(
vec!("hello %7.2s", "world"), "hello wo"); }
#[test]
fn sub_int_decimal() { expect_stdout(
vec!("%0.i", "11"), "11"); }
#[test]
fn sub_int_leading_zeroes() { expect_stdout(
vec!("%.4i", "11"), "0011"); }
#[test]
fn sub_int_leading_zeroes_prio() { expect_stdout(
vec!("%5.4i", "11"), " 0011"); }
#[test]
fn sub_float_dec_places() { expect_stdout(
vec!("pi is ~ %.11f", "3.1415926535"), "pi is ~ 3.14159265350"); }
#[test]
fn sub_float_hex_in() { expect_stdout(
vec!("%f", "0xF1.1F"), "241.121094"); }
#[test]
fn sub_float_no_octal_in() { expect_stdout(
vec!("%f", "077"), "77.000000"); }
#[test]
fn sub_any_asterisk_firstparam() { expect_stdout(
vec!("%*i", "3", "11", "4", "12"), " 11 12");
} }
#[test] #[test]
fn sub_any_asterisk_second_param() { expect_stdout( fn escaped_tab() {
vec!("%.*i", "3", "11", "4", "12"), "0110012"); expect_stdout(vec!["hello\\t world"], "hello\t world");
} }
#[test] #[test]
fn sub_any_asterisk_both_params() { expect_stdout( fn escaped_newline() {
vec!("%*.*i", "4", "3", "11", "5", "4", "12"), " 011 0012"); expect_stdout(vec!["hello\\n world"], "hello\n world");
} }
#[test] #[test]
fn sub_any_asterisk_octal_arg() { expect_stdout( fn escaped_slash() {
vec!("%.*i", "011", "12345678"), "012345678"); expect_stdout(vec!["hello\\\\ world"], "hello\\ world");
} }
#[test] #[test]
fn sub_any_asterisk_hex_arg() { expect_stdout( fn escaped_hex() {
vec!("%.*i", "0xA", "123456789"), "0123456789"); expect_stdout(vec!["\\x41"], "A");
} }
#[test] #[test]
fn sub_any_specifiers_no_params() { expect_stdout( fn escaped_octal() {
vec!("%ztlhLji", "3"), "3"); expect_stdout(vec!["\\101"], "A");
} }
#[test] #[test]
fn sub_any_specifiers_after_first_param() { expect_stdout( fn escaped_unicode_fourdigit() {
vec!("%0ztlhLji", "3"), "3"); expect_stdout(vec!["\\u0125"], "ĥ");
} }
#[test] #[test]
fn sub_any_specifiers_after_period() { expect_stdout( fn escaped_unicode_eightdigit() {
vec!("%0.ztlhLji", "3"), "3"); expect_stdout(vec!["\\U00000125"], "ĥ");
} }
#[test] #[test]
fn sub_any_specifiers_after_second_param() { expect_stdout( fn escaped_percent_sign() {
vec!("%0.0ztlhLji", "3"), "3"); expect_stdout(vec!["hello%% world"], "hello% world");
}
#[test]
fn escaped_unrecognized() {
expect_stdout(vec!["c\\d"], "c\\d");
}
#[test]
fn sub_string() {
expect_stdout(vec!["hello %s", "world"], "hello world");
}
#[test]
fn sub_multifield() {
expect_stdout(vec!["%s %s", "hello", "world"], "hello world");
}
#[test]
fn sub_repeat_formatstr() {
expect_stdout(vec!["%s.", "hello", "world"], "hello.world.");
}
#[test]
fn sub_string_ignore_escapes() {
expect_stdout(vec!["hello %s", "\\tworld"], "hello \\tworld");
}
#[test]
fn sub_bstring_handle_escapes() {
expect_stdout(vec!["hello %b", "\\tworld"], "hello \tworld");
}
#[test]
fn sub_bstring_ignore_subs() {
expect_stdout(vec!["hello %b", "world %% %i"], "hello world %% %i");
}
#[test]
fn sub_char() {
expect_stdout(vec!["the letter %c", "A"], "the letter A");
}
#[test]
fn sub_num_int() {
expect_stdout(vec!["twenty is %i", "20"], "twenty is 20");
}
#[test]
fn sub_num_int_minwidth() {
expect_stdout(vec!["twenty is %1i", "20"], "twenty is 20");
}
#[test]
fn sub_num_int_neg() {
expect_stdout(vec!["neg. twenty is %i", "-20"], "neg. twenty is -20");
}
#[test]
fn sub_num_int_oct_in() {
expect_stdout(vec!["twenty is %i", "024"], "twenty is 20");
}
#[test]
fn sub_num_int_oct_in_neg() {
expect_stdout(vec!["neg. twenty is %i", "-024"], "neg. twenty is -20");
}
#[test]
fn sub_num_int_hex_in() {
expect_stdout(vec!["twenty is %i", "0x14"], "twenty is 20");
}
#[test]
fn sub_num_int_hex_in_neg() {
expect_stdout(vec!["neg. twenty is %i", "-0x14"], "neg. twenty is -20");
}
#[test]
fn sub_num_int_charconst_in() {
expect_stdout(vec!["ninetyseven is %i", "'a"], "ninetyseven is 97");
}
#[test]
fn sub_num_uint() {
expect_stdout(vec!["twenty is %u", "20"], "twenty is 20");
}
#[test]
fn sub_num_octal() {
expect_stdout(vec!["twenty in octal is %o", "20"], "twenty in octal is 24");
}
#[test]
fn sub_num_hex_lower() {
expect_stdout(vec!["thirty in hex is %x", "30"], "thirty in hex is 1e");
}
#[test]
fn sub_num_hex_upper() {
expect_stdout(vec!["thirty in hex is %X", "30"], "thirty in hex is 1E");
}
#[test]
fn sub_num_float() {
expect_stdout(vec!["twenty is %f", "20"], "twenty is 20.000000");
}
#[test]
fn sub_num_float_round() {
expect_stdout(vec!["two is %f", "1.9999995"], "two is 2.000000");
}
#[test]
fn sub_num_sci_lower() {
expect_stdout(vec!["twenty is %e", "20"], "twenty is 2.000000e+01");
}
#[test]
fn sub_num_sci_upper() {
expect_stdout(vec!["twenty is %E", "20"], "twenty is 2.000000E+01");
}
#[test]
fn sub_num_sci_trunc() {
expect_stdout(vec!["pi is ~ %e", "3.1415926535"], "pi is ~ 3.141593e+00");
}
#[test]
fn sub_num_dec_trunc() {
expect_stdout(vec!["pi is ~ %g", "3.1415926535"], "pi is ~ 3.141593");
}
#[test]
fn sub_minwidth() {
expect_stdout(vec!["hello %7s", "world"], "hello world");
}
#[test]
fn sub_minwidth_negative() {
expect_stdout(vec!["hello %-7s", "world"], "hello world ");
}
#[test]
fn sub_str_max_chars_input() {
expect_stdout(vec!["hello %7.2s", "world"], "hello wo");
}
#[test]
fn sub_int_decimal() {
expect_stdout(vec!["%0.i", "11"], "11");
}
#[test]
fn sub_int_leading_zeroes() {
expect_stdout(vec!["%.4i", "11"], "0011");
}
#[test]
fn sub_int_leading_zeroes_prio() {
expect_stdout(vec!["%5.4i", "11"], " 0011");
}
#[test]
fn sub_float_dec_places() {
expect_stdout(vec!["pi is ~ %.11f", "3.1415926535"],
"pi is ~ 3.14159265350");
}
#[test]
fn sub_float_hex_in() {
expect_stdout(vec!["%f", "0xF1.1F"], "241.121094");
}
#[test]
fn sub_float_no_octal_in() {
expect_stdout(vec!["%f", "077"], "77.000000");
}
#[test]
fn sub_any_asterisk_firstparam() {
expect_stdout(vec!["%*i", "3", "11", "4", "12"], " 11 12");
}
#[test]
fn sub_any_asterisk_second_param() {
expect_stdout(vec!["%.*i", "3", "11", "4", "12"], "0110012");
}
#[test]
fn sub_any_asterisk_both_params() {
expect_stdout(vec!["%*.*i", "4", "3", "11", "5", "4", "12"], " 011 0012");
}
#[test]
fn sub_any_asterisk_octal_arg() {
expect_stdout(vec!["%.*i", "011", "12345678"], "012345678");
}
#[test]
fn sub_any_asterisk_hex_arg() {
expect_stdout(vec!["%.*i", "0xA", "123456789"], "0123456789");
}
#[test]
fn sub_any_specifiers_no_params() {
expect_stdout(vec!["%ztlhLji", "3"], "3");
}
#[test]
fn sub_any_specifiers_after_first_param() {
expect_stdout(vec!["%0ztlhLji", "3"], "3");
}
#[test]
fn sub_any_specifiers_after_period() {
expect_stdout(vec!["%0.ztlhLji", "3"], "3");
}
#[test]
fn sub_any_specifiers_after_second_param() {
expect_stdout(vec!["%0.0ztlhLji", "3"], "3");
} }