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
+3 -3
View File
@@ -7,12 +7,12 @@ use std::env;
pub static EXIT_OK: i32 = 0;
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() {
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();
}
// by default stdout only flushes
+15 -14
View File
@@ -1,4 +1,4 @@
//! Memo runner of printf
//! Memo runner of printf
//! Takes a format string and arguments
//! 1. tokenizes format string into tokens, consuming
//! any subst. arguments along the way.
@@ -17,18 +17,15 @@ pub struct Memo {
tokens: Vec<Box<Token>>,
}
fn warn_excess_args(first_arg : &str) {
fn warn_excess_args(first_arg: &str) {
cli::err_msg(&format!("warning: ignoring excess arguments, starting with '{}'",
first_arg));
first_arg));
}
impl Memo {
pub fn new(
pf_string: &String,
pf_args_it: &mut Peekable<Iter<String>>
) -> Memo {
pub fn new(pf_string: &String, pf_args_it: &mut Peekable<Iter<String>>) -> Memo {
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 has_sub = false;
loop {
@@ -40,24 +37,28 @@ impl Memo {
tmp_token = Sub::from_it(&mut it, pf_args_it);
match tmp_token {
Some(x) => {
if ! has_sub { has_sub = true; }
if !has_sub {
has_sub = true;
}
pm.tokens.push(x);
},
}
None => {}
}
if let Some(x) = it.next() {
it.put_back(x);
} else { break; }
} else {
break;
}
}
if ! has_sub {
let mut drain= false;
if !has_sub {
let mut drain = false;
if let Some(first_arg) = pf_args_it.peek() {
warn_excess_args(first_arg);
drain = true;
}
if drain {
loop {
//drain remaining args;
// drain remaining args;
if pf_args_it.next().is_none() {
break;
}
-1
View File
@@ -1,4 +1,3 @@
mod cli;
mod memo;
mod tokenize;
+19 -21
View File
@@ -11,23 +11,22 @@ pub enum FieldType {
Charf,
}
/*
#[allow(non_camel_case_types)]
pub enum FChar {
d,
e,
E,
i,
f,
F,
g,
G,
u,
x,
X,
o
}
*/
// #[allow(non_camel_case_types)]
// pub enum FChar {
// d,
// e,
// E,
// i,
// f,
// F,
// g,
// G,
// u,
// x,
// X,
// o
// }
//
// a Sub Tokens' fields are stored
// as a single object so they can be more simply
@@ -36,8 +35,7 @@ pub enum FChar {
pub struct FormatField<'a> {
pub min_width: Option<isize>,
pub second_field: Option<u32>,
pub field_char: & 'a char,
pub field_type: & 'a FieldType,
pub orig : & 'a String
pub field_char: &'a char,
pub field_type: &'a FieldType,
pub orig: &'a String,
}
+19 -25
View File
@@ -13,7 +13,7 @@ pub struct FormatPrimitive {
pub prefix: Option<String>,
pub pre_decimal: Option<String>,
pub post_decimal: Option<String>,
pub suffix: Option<String>
pub suffix: Option<String>,
}
impl Default for FormatPrimitive {
@@ -22,52 +22,46 @@ impl Default for FormatPrimitive {
prefix: None,
pre_decimal: None,
post_decimal: None,
suffix: None
}
suffix: None,
}
}
}
#[derive(Clone)]
#[derive(PartialEq)]
pub enum Base {
Ten=10,
Hex=16,
Octal=8,
Ten = 10,
Hex = 16,
Octal = 8,
}
// information from the beginning of a numeric argument
// the precedes the beginning of a numeric value
pub struct InPrefix {
pub radix_in : Base,
pub sign : i8,
pub offset : usize
pub radix_in: Base,
pub sign: i8,
pub offset: usize,
}
pub trait Formatter {
// return a FormatPrimitive for
// return a FormatPrimitive for
// particular field char(s), given the argument
// string and prefix information (sign, radix)
fn get_primitive(
&self,
field: &FormatField,
inprefix: &InPrefix,
str_in: &str
) -> Option<FormatPrimitive>;
fn get_primitive(&self,
field: &FormatField,
inprefix: &InPrefix,
str_in: &str)
-> Option<FormatPrimitive>;
// return a string from a formatprimitive,
// given information about the field
fn primitive_to_str(
&self,
prim: &FormatPrimitive,
field: FormatField) -> String;
fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String;
}
pub fn get_it_at(offset: usize,
str_in: &str) -> PutBackN<Chars> {
pub fn get_it_at(offset: usize, str_in: &str) -> PutBackN<Chars> {
PutBackN::new(str_in[offset..].chars())
}
// TODO: put this somewhere better
pub fn warn_incomplete_conv(pf_arg: &str) {
//important: keep println here not print
cli::err_msg(&format!("{}: value not completely converted",
pf_arg))
// important: keep println here not print
cli::err_msg(&format!("{}: value not completely converted", pf_arg))
}
@@ -1,25 +1,21 @@
pub fn arrnum_int_mult(
arr_num : &Vec<u8>,
basenum : u8,
base_ten_int_fact : u8
) -> Vec<u8> {
let mut carry : u16 = 0;
let mut rem : u16;
let mut new_amount : u16;
let fact : u16 = base_ten_int_fact as u16;
let base : u16 = basenum as u16;
let mut ret_rev : Vec<u8> = Vec::new();
pub fn arrnum_int_mult(arr_num: &Vec<u8>, basenum: u8, base_ten_int_fact: u8) -> Vec<u8> {
let mut carry: u16 = 0;
let mut rem: u16;
let mut new_amount: u16;
let fact: u16 = base_ten_int_fact as u16;
let base: u16 = basenum as u16;
let mut ret_rev: Vec<u8> = Vec::new();
let mut it = arr_num.iter().rev();
loop {
let i = it.next();
match i {
Some(u) => {
new_amount = ((u.clone() as u16)*fact) + carry;
new_amount = ((u.clone() as u16) * fact) + carry;
rem = new_amount % base;
carry = (new_amount - rem) / base;
ret_rev.push(rem as u8)
},
}
None => {
while carry != 0 {
rem = carry % base;
@@ -30,33 +26,31 @@ pub fn arrnum_int_mult(
}
}
}
let ret : Vec<u8> =
ret_rev.iter().rev().map(|x| x.clone()).collect();
let ret: Vec<u8> = ret_rev.iter().rev().map(|x| x.clone()).collect();
ret
}
pub struct Remainder<'a> {
pub struct Remainder<'a> {
pub position: usize,
pub replace: Vec<u8>,
pub arr_num: &'a Vec<u8>
pub arr_num: &'a Vec<u8>,
}
pub struct DivOut<'a> {
pub quotient: u8,
pub remainder: Remainder<'a>
pub remainder: Remainder<'a>,
}
pub fn arrnum_int_div_step<'a>(
rem_in: Remainder<'a>,
radix_in: u8,
base_ten_int_divisor: u8,
after_decimal: bool
) -> DivOut<'a> {
pub fn arrnum_int_div_step<'a>(rem_in: Remainder<'a>,
radix_in: u8,
base_ten_int_divisor: u8,
after_decimal: bool)
-> DivOut<'a> {
let mut rem_out = Remainder {
position: rem_in.position,
replace: Vec::new(),
arr_num: rem_in.arr_num
arr_num: rem_in.arr_num,
};
let mut bufferval: u16 = 0;
@@ -65,17 +59,15 @@ pub fn arrnum_int_div_step<'a>(
let mut traversed = 0;
let mut quotient = 0;
let refd_vals = &rem_in.arr_num[rem_in.position+rem_in.replace.len()..];
let refd_vals = &rem_in.arr_num[rem_in.position + rem_in.replace.len()..];
let mut it_replace = rem_in.replace.iter();
let mut it_f = refd_vals.iter();
loop {
let u = match it_replace.next() {
Some(u_rep) => { u_rep.clone() as u16 }
Some(u_rep) => u_rep.clone() as u16,
None => {
match it_f.next() {
Some(u_orig) => {
u_orig.clone() as u16
}
Some(u_orig) => u_orig.clone() as u16,
None => {
if !after_decimal {
break;
@@ -89,104 +81,98 @@ pub fn arrnum_int_div_step<'a>(
bufferval += u;
if bufferval > divisor {
while bufferval >= divisor {
quotient+=1;
quotient += 1;
bufferval -= divisor;
}
rem_out.replace = if bufferval == 0 {
Vec::new()
} else {
let remainder_as_arrnum = unsigned_to_arrnum(bufferval);
let remainder_as_base_arrnum = base_conv_vec(
&remainder_as_arrnum,
10,
radix_in
);
let remainder_as_base_arrnum = base_conv_vec(&remainder_as_arrnum, 10, radix_in);
remainder_as_base_arrnum
};
rem_out.position += 1+(traversed - rem_out.replace.len());
rem_out.position += 1 + (traversed - rem_out.replace.len());
break;
} else {
bufferval *= base;
bufferval *= base;
}
}
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()
DivOut {
quotient: quotient,
remainder: rem_out,
}
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 rem : u16;
let mut new_amount : u16;
let base : u16 = basenum as u16;
let mut ret_rev : Vec<u8> = Vec::new();
// 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();
// 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 rem: u16;
let mut new_amount: u16;
let base: u16 = basenum as u16;
let mut ret_rev: Vec<u8> = Vec::new();
let mut it = arrnum.iter().rev();
loop {
let i = it.next();
@@ -196,7 +182,7 @@ pub fn arrnum_int_add(
rem = new_amount % base;
carry = (new_amount - rem) / base;
ret_rev.push(rem as u8)
},
}
None => {
while carry != 0 {
rem = carry % base;
@@ -207,35 +193,23 @@ pub fn arrnum_int_add(
}
}
}
let ret : Vec<u8> =
ret_rev.iter().rev().map(|x| x.clone()).collect();
let ret: Vec<u8> = ret_rev.iter().rev().map(|x| x.clone()).collect();
ret
}
pub fn base_conv_vec(
src : &Vec<u8>,
radix_src : u8,
radix_dest : u8
) -> Vec<u8> {
let mut result : Vec<u8> = Vec::new();
pub fn base_conv_vec(src: &Vec<u8>, radix_src: u8, radix_dest: u8) -> Vec<u8> {
let mut result: Vec<u8> = Vec::new();
result.push(0);
for i in src {
result = arrnum_int_mult(&result,
radix_dest, radix_src);
result = arrnum_int_add(
&result,
radix_dest,
i.clone()
);
result = arrnum_int_mult(&result, radix_dest, radix_src);
result = arrnum_int_add(&result, radix_dest, i.clone());
}
result
}
pub fn unsigned_to_arrnum(
src : u16
) -> Vec<u8> {
let mut result : Vec<u8> = Vec::new();
let mut src_tmp : u16 = src.clone();
pub fn unsigned_to_arrnum(src: u16) -> Vec<u8> {
let mut result: Vec<u8> = Vec::new();
let mut src_tmp: u16 = src.clone();
while src_tmp > 0 {
result.push((src_tmp % 10) as u8);
src_tmp /= 10;
@@ -245,50 +219,44 @@ pub fn unsigned_to_arrnum(
}
//temporary needs-improvement-function
// temporary needs-improvement-function
#[allow(unused_variables)]
pub fn base_conv_float(
src : &Vec<u8>,
radix_src : u8,
radix_dest : u8
) -> f64 {
//it would require a lot of addl code
pub fn base_conv_float(src: &Vec<u8>, radix_src: u8, radix_dest: u8) -> f64 {
// it would require a lot of addl code
// to implement this for arbitrary string input.
//until then, the below operates as an outline
// until then, the below operates as an outline
// of how it would work.
let mut result : Vec<u8> = Vec::new();
let mut result: Vec<u8> = Vec::new();
result.push(0);
let mut factor : f64 = 1.;
let radix_src_float : f64 = radix_src as f64;
let mut factor: f64 = 1.;
let radix_src_float: f64 = radix_src as f64;
let mut i = 0;
let mut r :f64 = 0 as f64;
let mut r: f64 = 0 as f64;
for u in src {
if i > 15 { break; }
i+=1;
if i > 15 {
break;
}
i += 1;
factor /= radix_src_float;
r += factor * (u.clone() as f64)
}
r
}
pub fn str_to_arrnum(
src: &str,
radix_def_src : &RadixDef
) -> Vec<u8> {
let mut intermed_in : Vec<u8> = Vec::new();
pub fn str_to_arrnum(src: &str, radix_def_src: &RadixDef) -> Vec<u8> {
let mut intermed_in: Vec<u8> = Vec::new();
for c in src.chars() {
match radix_def_src.from_char::<>(c) {
Some(u) => { intermed_in.push(u); }
match radix_def_src.from_char(c) {
Some(u) => {
intermed_in.push(u);
}
None => {} //todo err msg on incorrect
}
}
intermed_in
}
pub fn arrnum_to_str(
src: &Vec<u8>,
radix_def_dest : &RadixDef
) -> String {
pub fn arrnum_to_str(src: &Vec<u8>, radix_def_dest: &RadixDef) -> String {
let mut str_out = String::new();
for u in src.iter() {
match radix_def_dest.from_u8(u.clone()) {
@@ -302,64 +270,61 @@ pub fn arrnum_to_str(
}
#[allow(unused_variables)]
pub fn base_conv_str(
src: &str,
radix_def_src : &RadixDef,
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_dest.get_max(),
);
pub fn base_conv_str(src: &str, radix_def_src: &RadixDef, 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_dest.get_max());
arrnum_to_str(&intermed_out, radix_def_dest)
}
pub trait RadixDef {
fn get_max (&self) -> u8;
fn from_char (&self, x:char) -> Option<u8>;
fn from_u8 (&self, x:u8) -> Option<char>;
fn get_max(&self) -> u8;
fn from_char(&self, x: char) -> Option<u8>;
fn from_u8(&self, x: u8) -> Option<char>;
}
pub struct RadixTen;
const ZERO_ASC : u8 = '0' as u8;
const UPPER_A_ASC : u8 = 'A' as u8;
const LOWER_A_ASC : u8 = 'a' as u8;
const ZERO_ASC: u8 = '0' as u8;
const UPPER_A_ASC: u8 = 'A' as u8;
const LOWER_A_ASC: u8 = 'a' as u8;
impl RadixDef for RadixTen {
fn get_max(&self) -> u8 { 10 }
fn from_char (&self, c:char) -> Option<u8> {
fn get_max(&self) -> u8 {
10
}
fn from_char(&self, c: char) -> Option<u8> {
match c {
'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 {
0...9 => Some((ZERO_ASC + u) as char),
_ => None
}
_ => None,
}
}
}
pub struct RadixHex;
impl RadixDef for RadixHex {
fn get_max(&self) -> u8 { 16 }
fn from_char (&self, c:char) -> Option<u8> {
fn get_max(&self) -> u8 {
16
}
fn from_char(&self, c: char) -> Option<u8> {
match c {
'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 - LOWER_A_ASC),
_ => None
'A'...'F' => Some(c as u8 + 10 - UPPER_A_ASC),
'a'...'f' => Some(c as u8 + 10 - LOWER_A_ASC),
_ => None,
}
}
fn from_u8 (&self, u:u8) -> Option<char> {
fn from_u8(&self, u: u8) -> Option<char> {
match u {
0...9 => Some((ZERO_ASC + u) as char),
10...15 => Some((UPPER_A_ASC + (u-10)) as char),
_ => None
}
10...15 => Some((UPPER_A_ASC + (u - 10)) as char),
_ => None,
}
}
}
@@ -4,61 +4,52 @@ use super::*;
#[test]
fn test_arrnum_int_mult() {
//(in base 10) 12 * 4 = 48
let factor : Vec<u8> = vec!(1, 2);
// (in base 10) 12 * 4 = 48
let factor: Vec<u8> = vec![1, 2];
let base_num = 10;
let base_ten_int_fact : u8 = 4;
let should_output : Vec<u8> = vec![4, 8];
let product = arrnum_int_mult(&factor,
base_num, base_ten_int_fact);
let base_ten_int_fact: u8 = 4;
let should_output: Vec<u8> = vec![4, 8];
let product = arrnum_int_mult(&factor, base_num, base_ten_int_fact);
assert!(product == should_output);
}
#[test]
fn test_arrnum_int_non_base_10() {
//(in base 3)
// (in base 3)
// 5 * 4 = 20
let factor : Vec<u8> = vec![1, 2];
let factor: Vec<u8> = vec![1, 2];
let base_num = 3;
let base_ten_int_fact : u8 = 4;
let should_output : Vec<u8> = vec![2,0,2];
let product = arrnum_int_mult(&factor,
base_num, base_ten_int_fact);
let base_ten_int_fact: u8 = 4;
let should_output: Vec<u8> = vec![2, 0, 2];
let product = arrnum_int_mult(&factor, base_num, base_ten_int_fact);
assert!(product == should_output);
}
#[test]
fn test_arrnum_int_div_shortcircuit() {
//(
let arrnum : Vec<u8> = vec![5,5,5,5,0];
// (
let arrnum: Vec<u8> = vec![5, 5, 5, 5, 0];
let base_num = 10;
let base_ten_int_divisor : u8 = 41;
let base_ten_int_divisor: u8 = 41;
let remainder_passed_in = Remainder {
position : 1,
replace : vec![1,3],
arr_num : &arrnum
position: 1,
replace: vec![1, 3],
arr_num: &arrnum,
};
//the "replace" should mean the number being divided
// the "replace" should mean the number being divided
// is 1350, the first time you can get 41 to go into
// 1350, its at 135, where you can get a quotient of
// 3 and a remainder of 12;
let quotient_should_be : u8 = 3;
let remainder_position_should_be : usize = 3;
let quotient_should_be: u8 = 3;
let remainder_position_should_be: usize = 3;
let remainder_replace_should_be = vec![1, 2];
let result = arrnum_int_div_step(remainder_passed_in,
base_num,
base_ten_int_divisor,
false
);
let result = arrnum_int_div_step(remainder_passed_in, base_num, base_ten_int_divisor, false);
assert!(quotient_should_be == result.quotient);
assert!(remainder_position_should_be ==
result.remainder.position);
assert!(remainder_replace_should_be ==
result.remainder.replace);
}
assert!(remainder_position_should_be == result.remainder.position);
assert!(remainder_replace_should_be == result.remainder.replace);
}
@@ -1,14 +1,13 @@
//! formatter for %a %F C99 Hex-floating-point subs
use super::super::format_field::FormatField;
use super::super::formatter::{InPrefix,FormatPrimitive,Formatter};
use super::float_common::{FloatAnalysis,
primitive_to_str_common};
use super::super::formatter::{InPrefix, FormatPrimitive, Formatter};
use super::float_common::{FloatAnalysis, primitive_to_str_common};
use super::base_conv;
use super::base_conv::{RadixDef};
use super::base_conv::RadixDef;
pub struct CninetyNineHexFloatf {
as_num : f64
as_num: f64,
}
impl CninetyNineHexFloatf {
pub fn new() -> CninetyNineHexFloatf {
@@ -17,86 +16,77 @@ impl CninetyNineHexFloatf {
}
impl Formatter for CninetyNineHexFloatf {
fn get_primitive(
&self,
field : &FormatField,
inprefix : &InPrefix,
str_in : &str
) -> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6)+1;
let analysis = FloatAnalysis::analyze(
&str_in,
inprefix,
Some(second_field as usize),
None,
true);
let f = get_primitive_hex(
inprefix,
&str_in[inprefix.offset..],
&analysis,
second_field as usize,
*field.field_char == 'A');
fn get_primitive(&self,
field: &FormatField,
inprefix: &InPrefix,
str_in: &str)
-> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6) + 1;
let analysis = FloatAnalysis::analyze(&str_in,
inprefix,
Some(second_field as usize),
None,
true);
let f = get_primitive_hex(inprefix,
&str_in[inprefix.offset..],
&analysis,
second_field as usize,
*field.field_char == 'A');
Some(f)
}
fn primitive_to_str(
&self,
prim: &FormatPrimitive,
field: FormatField) -> String {
primitive_to_str_common(
prim,
&field
)
fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
primitive_to_str_common(prim, &field)
}
}
//c99 hex has unique requirements of all floating point subs in pretty much every part of building a primitive, from prefix and suffix to need for base conversion (in all other cases if you don't have decimal you must have decimal, here it's the other way around)
// c99 hex has unique requirements of all floating point subs in pretty much every part of building a primitive, from prefix and suffix to need for base conversion (in all other cases if you don't have decimal you must have decimal, here it's the other way around)
// 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_assignments)]
fn get_primitive_hex(
inprefix : &InPrefix,
str_in : &str,
analysis : &FloatAnalysis,
last_dec_place : usize,
capitalized : bool
) -> FormatPrimitive {
let mut f : FormatPrimitive = Default::default();
f.prefix = Some(String::from(
if inprefix.sign == -1 { "-0x" } else { "0x" }));
fn get_primitive_hex(inprefix: &InPrefix,
str_in: &str,
analysis: &FloatAnalysis,
last_dec_place: usize,
capitalized: bool)
-> FormatPrimitive {
let mut f: FormatPrimitive = Default::default();
f.prefix = Some(String::from(if inprefix.sign == -1 {
"-0x"
} else {
"0x"
}));
// assign the digits before and after the decimal points
// to separate slices. If no digits after decimal point,
// assign 0
let (mut first_segment_raw, second_segment_raw) =
match analysis.decimal_pos {
Some(pos) => {
(&str_in[..pos], &str_in[pos+1..])
},
None => { (&str_in[..], "0") }
};
let (mut first_segment_raw, second_segment_raw) = match analysis.decimal_pos {
Some(pos) => (&str_in[..pos], &str_in[pos + 1..]),
None => (&str_in[..], "0"),
};
if first_segment_raw.len() == 0 {
first_segment_raw = "0";
}
// convert to string, hexifying if input is in dec.
/*let (first_segment, second_segment) =
match inprefix.radix_in {
Base::Ten => {
(to_hex(first_segment_raw, true),
to_hex(second_segment_raw, false))
}
_ => {
(String::from(first_segment_raw),
String::from(second_segment_raw))
}
};
f.pre_decimal = Some(first_segment);
f.post_decimal = Some(second_segment);
*/
//TODO actual conversion, make sure to get back mantissa.
// let (first_segment, second_segment) =
// match inprefix.radix_in {
// Base::Ten => {
// (to_hex(first_segment_raw, true),
// to_hex(second_segment_raw, false))
// }
// _ => {
// (String::from(first_segment_raw),
// String::from(second_segment_raw))
// }
// };
//
//
// f.pre_decimal = Some(first_segment);
// f.post_decimal = Some(second_segment);
//
// TODO actual conversion, make sure to get back mantissa.
// for hex to hex, it's really just a matter of moving the
// decimal point and calculating the mantissa by its initial
// position and its moves, with every position counting for
@@ -109,10 +99,14 @@ fn get_primitive_hex(
// the hex float name may be a bit misleading in terms of how to go about the
// conversion. The best way to do it is to just convert the floatnum
// directly to base 2 and then at the end translate back to hex.
let mantissa=0;
let mantissa = 0;
f.suffix = Some({
let ind = if capitalized { "P" } else { "p" };
if mantissa >=0 {
let ind = if capitalized {
"P"
} else {
"p"
};
if mantissa >= 0 {
format!("{}+{}", ind, mantissa)
} else {
format!("{}{}", ind, mantissa)
@@ -121,25 +115,19 @@ fn get_primitive_hex(
f
}
fn to_hex(
src: &str,
before_decimal: bool
) -> String {
let rten = base_conv::RadixTen;
fn to_hex(src: &str, before_decimal: bool) -> String {
let rten = base_conv::RadixTen;
let rhex = base_conv::RadixHex;
if before_decimal {
base_conv::base_conv_str(src, &rten, &rhex)
} else {
let as_arrnum_ten =base_conv::str_to_arrnum(src, &rten);
let s = format!("{}", base_conv::base_conv_float(
&as_arrnum_ten,
rten.get_max(),
rhex.get_max()
));
let as_arrnum_ten = base_conv::str_to_arrnum(src, &rten);
let s = format!("{}",
base_conv::base_conv_float(&as_arrnum_ten, rten.get_max(), rhex.get_max()));
if s.len() > 2 {
String::from(&s[2..])
} else {
//zero
// zero
s
}
}
@@ -1,23 +1,27 @@
//! formatter for %g %G decimal subs
use super::super::format_field::FormatField;
use super::super::formatter::{InPrefix,FormatPrimitive,Formatter};
use super::float_common::{FloatAnalysis,
get_primitive_dec,
primitive_to_str_common};
use super::super::formatter::{InPrefix, FormatPrimitive, Formatter};
use super::float_common::{FloatAnalysis, get_primitive_dec, primitive_to_str_common};
fn get_len_fprim(
fprim : &FormatPrimitive
) -> usize {
fn get_len_fprim(fprim: &FormatPrimitive) -> usize {
let mut len = 0;
if let Some(ref s) = fprim.prefix { 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(); }
if let Some(ref s) = fprim.prefix {
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
}
pub struct Decf {
as_num : f64
as_num: f64,
}
impl Decf {
pub fn new() -> Decf {
@@ -25,62 +29,55 @@ impl Decf {
}
}
impl Formatter for Decf {
fn get_primitive(
&self,
field : &FormatField,
inprefix : &InPrefix,
str_in : &str
) -> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6)+1;
//default to scif interp. so as to not truncate input vals
//(that would be displayed in scif) based on relation to decimal place
let analysis = FloatAnalysis::analyze(
str_in,
inprefix,
Some(second_field as usize+1),
None,
false);
let mut f_sci = get_primitive_dec(
inprefix,
&str_in[inprefix.offset..],
&analysis,
second_field as usize,
Some(*field.field_char == 'G'));
//strip trailing zeroes
fn get_primitive(&self,
field: &FormatField,
inprefix: &InPrefix,
str_in: &str)
-> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6) + 1;
// default to scif interp. so as to not truncate input vals
// (that would be displayed in scif) based on relation to decimal place
let analysis = FloatAnalysis::analyze(str_in,
inprefix,
Some(second_field as usize + 1),
None,
false);
let mut f_sci = get_primitive_dec(inprefix,
&str_in[inprefix.offset..],
&analysis,
second_field as usize,
Some(*field.field_char == 'G'));
// strip trailing zeroes
match f_sci.post_decimal.clone() {
Some(ref post_dec) => {
let mut i = post_dec.len();
{
let mut it = post_dec.chars();
while let Some(c) = it.next_back() {
if c != '0' { break; }
i-=1;
if c != '0' {
break;
}
i -= 1;
}
}
if i != post_dec.len() {
f_sci.post_decimal =
Some(String::from(&post_dec[0..i]));
f_sci.post_decimal = Some(String::from(&post_dec[0..i]));
}
}
None => {}
}
let f_fl = get_primitive_dec(
inprefix,
&str_in[inprefix.offset..],
&analysis,
second_field as usize,
None);
let f_fl = get_primitive_dec(inprefix,
&str_in[inprefix.offset..],
&analysis,
second_field as usize,
None);
Some(if get_len_fprim(&f_fl) >= get_len_fprim(&f_sci) {
f_sci
} else { f_fl })
} else {
f_fl
})
}
fn primitive_to_str(
&self,
prim: &FormatPrimitive,
field: FormatField) -> String {
primitive_to_str_common(
prim,
&field
)
fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
primitive_to_str_common(prim, &field)
}
}
File diff suppressed because it is too large Load Diff
@@ -1,12 +1,10 @@
//! formatter for %f %F common-notation floating-point subs
use super::super::format_field::FormatField;
use super::super::formatter::{InPrefix,FormatPrimitive,Formatter};
use super::float_common::{FloatAnalysis,
get_primitive_dec,
primitive_to_str_common};
use super::super::formatter::{InPrefix, FormatPrimitive, Formatter};
use super::float_common::{FloatAnalysis, get_primitive_dec, primitive_to_str_common};
pub struct Floatf {
as_num : f64
as_num: f64,
}
impl Floatf {
pub fn new() -> Floatf {
@@ -14,35 +12,25 @@ impl Floatf {
}
}
impl Formatter for Floatf {
fn get_primitive(
&self,
field : &FormatField,
inprefix : &InPrefix,
str_in : &str
) -> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6)+1;
let analysis = FloatAnalysis::analyze(
&str_in,
inprefix,
None,
Some(second_field as usize),
false);
let f = get_primitive_dec(
inprefix,
&str_in[inprefix.offset..],
&analysis,
second_field as usize,
None);
fn get_primitive(&self,
field: &FormatField,
inprefix: &InPrefix,
str_in: &str)
-> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6) + 1;
let analysis = FloatAnalysis::analyze(&str_in,
inprefix,
None,
Some(second_field as usize),
false);
let f = get_primitive_dec(inprefix,
&str_in[inprefix.offset..],
&analysis,
second_field as usize,
None);
Some(f)
}
fn primitive_to_str(
&self,
prim: &FormatPrimitive,
field: FormatField) -> String {
primitive_to_str_common(
prim,
&field
)
fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
primitive_to_str_common(prim, &field)
}
}
+118 -132
View File
@@ -4,23 +4,24 @@
use std::u64;
use std::i64;
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 {
a : u32
a: u32,
}
// see the Intf::analyze() function below
struct IntAnalysis {
check_past_max : bool,
past_max : bool,
check_past_max: bool,
past_max: bool,
is_zero: bool,
len_digits: u8
len_digits: u8,
}
impl Intf {
pub fn new() -> Intf {
Intf { a:0 }
Intf { a: 0 }
}
// take a ref to argument string, and basic information
// about prefix (offset, radix, sign), and analyze string
@@ -34,78 +35,79 @@ impl Intf {
// is_zero: true if number is zero, false otherwise
// len_digits: length of digits used to create the int
// important, for example, if we run into a non-valid character
fn analyze(
str_in: &str,
signed_out: bool,
inprefix: &InPrefix
) -> IntAnalysis {
fn analyze(str_in: &str, signed_out: bool, inprefix: &InPrefix) -> IntAnalysis {
// the maximum number of digits we could conceivably
// have before the decimal point without exceeding the
// max
let mut str_it = get_it_at(inprefix.offset, str_in);
let max_sd_in =
if signed_out {
match inprefix.radix_in {
Base::Ten => 19,
Base::Octal => 21,
Base::Hex => 16
}
} else {
match inprefix.radix_in {
Base::Ten => 20,
Base::Octal => 22,
Base::Hex => 16
}
};
let max_sd_in = if signed_out {
match inprefix.radix_in {
Base::Ten => 19,
Base::Octal => 21,
Base::Hex => 16,
}
} else {
match inprefix.radix_in {
Base::Ten => 20,
Base::Octal => 22,
Base::Hex => 16,
}
};
let mut ret = IntAnalysis {
check_past_max: false,
past_max: false,
is_zero: false,
len_digits : 0
len_digits: 0,
};
// todo turn this to a while let now that we know
// no special behavior on EOI break
loop {
let c_opt = str_it.next();
if let Some(c) = c_opt { match c {
'0'...'9' | 'a'...'f' | 'A'...'F' => {
if ret.len_digits == 0 && c == '0' {
ret.is_zero = true;
} else if ret.is_zero {
ret.is_zero = false;
}
ret.len_digits += 1;
if ret.len_digits == max_sd_in {
if let Some(next_ch) = str_it.next() {
match next_ch {
'0'...'9' => {
ret.past_max = true;
if let Some(c) = c_opt {
match c {
'0'...'9' | 'a'...'f' | 'A'...'F' => {
if ret.len_digits == 0 && c == '0' {
ret.is_zero = true;
} else if ret.is_zero {
ret.is_zero = false;
}
ret.len_digits += 1;
if ret.len_digits == max_sd_in {
if let Some(next_ch) = str_it.next() {
match next_ch {
'0'...'9' => {
ret.past_max = true;
}
_ => {
// force conversion
// to check if its above max.
// todo: spin out convert
// into fn, call it here to try
// read val, on Ok()
// save val for reuse later
// that way on same-base in and out
// we don't needlessly convert int
// to str, we can just copy it over.
ret.check_past_max = true;
str_it.put_back(next_ch);
}
}
_ => {
// force conversion
// to check if its above max.
// todo: spin out convert
// into fn, call it here to try
// read val, on Ok()
// save val for reuse later
// that way on same-base in and out
// we don't needlessly convert int
// to str, we can just copy it over.
ret.check_past_max = true;
str_it.put_back(next_ch);
if ret.past_max {
break;
}
} else {
ret.check_past_max = true;
}
if ret.past_max { break; }
} else { ret.check_past_max = true; }
}
}
_ => {
warn_incomplete_conv(str_in);
break;
}
}
_ => {
warn_incomplete_conv(str_in);
break;
}
} } else {
//breaks on EOL
} else {
// breaks on EOL
break;
}
}
@@ -113,22 +115,21 @@ impl Intf {
}
// get a FormatPrimitive of the maximum value for the field char
// and given sign
fn get_max(
fchar : char,
sign : i8
) -> FormatPrimitive {
let mut fmt_prim : FormatPrimitive = Default::default();
fn get_max(fchar: char, sign: i8) -> FormatPrimitive {
let mut fmt_prim: FormatPrimitive = Default::default();
fmt_prim.pre_decimal = Some(String::from(match fchar {
'd' | 'i' => match sign {
1 => "9223372036854775807",
_ => {
fmt_prim.prefix = Some(String::from("-"));
"9223372036854775808"
'd' | 'i' => {
match sign {
1 => "9223372036854775807",
_ => {
fmt_prim.prefix = Some(String::from("-"));
"9223372036854775808"
}
}
},
}
'x' | 'X' => "ffffffffffffffff",
'o' => "1777777777777777777777",
'u' | _ => "18446744073709551615"
'u' | _ => "18446744073709551615",
}));
fmt_prim
}
@@ -147,102 +148,90 @@ impl Intf {
// - if the string falls outside bounds:
// for i64 output, the int minimum or int max (depending on sign)
// for u64 output, the u64 max in the output radix
fn conv_from_segment(
segment : &str,
radix_in : Base,
fchar : char,
sign : i8,
) ->
FormatPrimitive
{
fn conv_from_segment(segment: &str, radix_in: Base, fchar: char, sign: i8) -> FormatPrimitive {
match fchar {
'i' | 'd' => {
match i64::from_str_radix(segment, radix_in as u32) {
Ok(i) => {
let mut fmt_prim : FormatPrimitive =
Default::default();
let mut fmt_prim: FormatPrimitive = Default::default();
if sign == -1 {
fmt_prim.prefix = Some(String::from("-"));
}
fmt_prim.pre_decimal =
Some(format!("{}", i));
fmt_prim.pre_decimal = Some(format!("{}", i));
fmt_prim
}
Err(_) => Intf::get_max(fchar, sign)
Err(_) => Intf::get_max(fchar, sign),
}
},
}
_ => {
match u64::from_str_radix(segment, radix_in as u32) {
Ok(u) => {
let mut fmt_prim : FormatPrimitive =
Default::default();
let u_f =
if sign == -1 { u64::MAX - (u -1)
} else { u };
let mut fmt_prim: FormatPrimitive = Default::default();
let u_f = if sign == -1 {
u64::MAX - (u - 1)
} else {
u
};
fmt_prim.pre_decimal = Some(match fchar {
'X' => format!("{:X}", u_f),
'x' => format!("{:x}", u_f),
'o' => format!("{:o}", u_f),
_ => format!("{}", u_f)
_ => format!("{}", u_f),
});
fmt_prim
}
Err(_) => Intf::get_max(fchar, sign)
Err(_) => Intf::get_max(fchar, sign),
}
}
}
}
}
impl Formatter for Intf {
fn get_primitive(
&self,
field : &FormatField,
inprefix : &InPrefix,
str_in : &str
) -> Option<FormatPrimitive> {
fn get_primitive(&self,
field: &FormatField,
inprefix: &InPrefix,
str_in: &str)
-> Option<FormatPrimitive> {
let begin = inprefix.offset;
//get information about the string. see Intf::Analyze
// get information about the string. see Intf::Analyze
// def above.
let convert_hints = Intf::analyze(str_in,
*field.field_char == 'i' || *field.field_char == 'd',
inprefix);
//We always will have a formatprimitive to return
// We always will have a formatprimitive to return
Some(if convert_hints.len_digits == 0 || convert_hints.is_zero {
//if non-digit or end is reached before a non-zero digit
let mut fmt_prim : FormatPrimitive = Default::default();
fmt_prim.pre_decimal=Some(String::from("0"));
// if non-digit or end is reached before a non-zero digit
let mut fmt_prim: FormatPrimitive = Default::default();
fmt_prim.pre_decimal = Some(String::from("0"));
fmt_prim
} else if ! convert_hints.past_max {
//if the number is or may be below the bounds limit
} else if !convert_hints.past_max {
// if the number is or may be below the bounds limit
let radix_out = match *field.field_char {
'd' | 'i' | 'u' => Base::Ten,
'x' | 'X' => Base::Hex,
'o' | _ => Base::Octal
'o' | _ => Base::Octal,
};
let radix_mismatch = ! radix_out.eq(&inprefix.radix_in);
let decr_from_max :bool = inprefix.sign == -1 &&
*field.field_char !='i';
let radix_mismatch = !radix_out.eq(&inprefix.radix_in);
let decr_from_max: bool = inprefix.sign == -1 && *field.field_char != 'i';
let end = begin + convert_hints.len_digits as usize;
// convert to int if any one of these is true:
// - number of digits in int indicates it may be past max
// - we're subtracting from the max
// - we're converting the base
if convert_hints.check_past_max
|| decr_from_max || radix_mismatch {
//radix of in and out is the same.
if convert_hints.check_past_max || decr_from_max || radix_mismatch {
// radix of in and out is the same.
let segment = String::from(&str_in[begin..end]);
let m = Intf::conv_from_segment(
&segment,
inprefix.radix_in.clone(),
*field.field_char,
inprefix.sign);
let m = Intf::conv_from_segment(&segment,
inprefix.radix_in.clone(),
*field.field_char,
inprefix.sign);
m
} else {
//otherwise just do a straight string copy.
let mut fmt_prim : FormatPrimitive = Default::default();
// otherwise just do a straight string copy.
let mut fmt_prim: FormatPrimitive = Default::default();
// this is here and not earlier because
// zero doesn't get a sign, and conv_from_segment
@@ -251,28 +240,24 @@ impl Formatter for Intf {
fmt_prim.prefix = Some(String::from("-"));
}
fmt_prim.pre_decimal = Some(String::from
(&str_in[begin..end]));
fmt_prim.pre_decimal = Some(String::from(&str_in[begin..end]));
fmt_prim
}
}
} else {
Intf::get_max(*field.field_char, inprefix.sign)
})
}
fn primitive_to_str(
&self,
prim: &FormatPrimitive,
field: FormatField) -> String {
let mut finalstr : String = String::new();
fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
let mut finalstr: String = String::new();
match prim.prefix {
Some(ref prefix) => {
finalstr.push_str(&prefix);
},
}
None => {}
}
//integral second fields is zero-padded minimum-width
//which gets handled before general minimum-width
// integral second fields is zero-padded minimum-width
// which gets handled before general minimum-width
match prim.pre_decimal {
Some(ref pre_decimal) => {
match field.second_field {
@@ -286,10 +271,11 @@ impl Formatter for Intf {
}
None => {}
}
finalstr.push_str(&pre_decimal);
finalstr.push_str(&pre_decimal);
}
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
@@ -1,12 +1,10 @@
//! formatter for %e %E scientific notation subs
use super::super::format_field::FormatField;
use super::super::formatter::{InPrefix,FormatPrimitive,Formatter};
use super::float_common::{FloatAnalysis,
get_primitive_dec,
primitive_to_str_common};
use super::super::formatter::{InPrefix, FormatPrimitive, Formatter};
use super::float_common::{FloatAnalysis, get_primitive_dec, primitive_to_str_common};
pub struct Scif {
as_num : f64
as_num: f64,
}
impl Scif {
pub fn new() -> Scif {
@@ -14,34 +12,25 @@ impl Scif {
}
}
impl Formatter for Scif {
fn get_primitive(
&self,
field : &FormatField,
inprefix : &InPrefix,
str_in : &str
) -> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6)+1;
let analysis = FloatAnalysis::analyze(
str_in,
inprefix,
Some(second_field as usize+1),
None,
false);
let f = get_primitive_dec(
inprefix,
&str_in[inprefix.offset..],
&analysis,
second_field as usize,
Some(*field.field_char == 'E'));
fn get_primitive(&self,
field: &FormatField,
inprefix: &InPrefix,
str_in: &str)
-> Option<FormatPrimitive> {
let second_field = field.second_field.unwrap_or(6) + 1;
let analysis = FloatAnalysis::analyze(str_in,
inprefix,
Some(second_field as usize + 1),
None,
false);
let f = get_primitive_dec(inprefix,
&str_in[inprefix.offset..],
&analysis,
second_field as usize,
Some(*field.field_char == 'E'));
Some(f)
}
fn primitive_to_str(
&self,
prim: &FormatPrimitive,
field: FormatField) -> String {
primitive_to_str_common(
prim,
&field
)
fn primitive_to_str(&self, prim: &FormatPrimitive, field: FormatField) -> String {
primitive_to_str_common(prim, &field)
}
}
+79 -66
View File
@@ -12,7 +12,7 @@ use super::formatters::scif::Scif;
use super::formatters::decf::Decf;
pub fn warn_expected_numeric(pf_arg: &String) {
//important: keep println here not print
// important: keep println here not print
cli::err_msg(&format!("{}: expected a numeric value", pf_arg));
}
@@ -24,8 +24,10 @@ fn warn_char_constant_ign(remaining_bytes: Vec<u8>) {
Err(e) => {
match e {
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,11 +37,9 @@ fn warn_char_constant_ign(remaining_bytes: Vec<u8>) {
// this function looks at the first few
// 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)
fn get_provided(
str_in_opt : Option<&String>
) -> Option<u8> {
const C_S_QUOTE: u8=39;
const C_D_QUOTE: u8=34;
fn get_provided(str_in_opt: Option<&String>) -> Option<u8> {
const C_S_QUOTE: u8 = 39;
const C_D_QUOTE: u8 = 34;
match str_in_opt {
Some(str_in) => {
let mut byte_it = str_in.bytes();
@@ -48,31 +48,34 @@ fn get_provided(
C_S_QUOTE | C_D_QUOTE => {
return Some(match byte_it.next() {
Some(second_byte) => {
let mut ignored : Vec<u8> = Vec::new();
while let Some(cont)=byte_it.next() {
let mut ignored: Vec<u8> = Vec::new();
while let Some(cont) = byte_it.next() {
ignored.push(cont);
}
if ignored.len() > 0 {
warn_char_constant_ign(ignored);
}
second_byte as u8
},
//no byte after quote
}
// no byte after quote
None => {
let so_far =
(qchar as u8 as char).to_string();
let so_far = (qchar as u8 as char).to_string();
warn_expected_numeric(&so_far);
0 as u8
}
});
},
//first byte is not quote
_ => { return None; }
//no first byte
}
// first byte is not quote
_ => {
return None;
}
// no first byte
}
} else { Some(0 as u8) }
} else {
Some(0 as u8)
}
}
None =>{ Some(0) }
None => Some(0),
}
}
@@ -81,27 +84,39 @@ fn get_provided(
// a base,
// and an offset for index after all
// initial spacing, sign, base prefix, and leading zeroes
fn get_inprefix(
str_in : &String,
field_type : &FieldType
) -> InPrefix {
fn get_inprefix(str_in: &String, field_type: &FieldType) -> InPrefix {
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();
//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)
loop {
match topchar
{
Some(' ')=>{ret.offset+=1; topchar=str_it.next();},
_=>{ break; }
}
match topchar {
Some(' ') => {
ret.offset += 1;
topchar = str_it.next();
}
_ => {
break;
}
}
}
//parse sign
// parse sign
match topchar {
Some('+')=>{ ret.offset+=1; topchar=str_it.next(); }
Some('-')=>{ ret.sign = -1; ret.offset+=1; topchar=str_it.next(); }
_=>{}
Some('+') => {
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
// the index of the first non-zero
@@ -128,20 +143,20 @@ fn get_inprefix(
ret.offset += 2;
ret.radix_in = Base::Hex;
do_clean_lead_zeroes = true;
},
}
e @ '0'...'9' => {
ret.offset+=1;
ret.offset += 1;
match *field_type {
FieldType::Intf => {
FieldType::Intf => {
ret.radix_in = Base::Octal;
},
}
_ => {}
}
if e == '0' {
do_clean_lead_zeroes = true;
}
}
_=>{}
_ => {}
}
if do_clean_lead_zeroes {
let mut first = true;
@@ -159,22 +174,26 @@ fn get_inprefix(
// current offset is not the final offset.
match ch_zero {
'0' => {
if !(is_hex && first) { ret.offset+=1; }
},
//if decimal, keep last zero if one exists
//(it's possible for last zero to
if !(is_hex && first) {
ret.offset += 1;
}
}
// if decimal, keep last zero if one exists
// (it's possible for last zero to
// not exist at this branch if we're in hex input)
'.' => {
break
},
//other digit, etc.
'.' => break,
// other digit, etc.
_ => {
if !(is_hex && first) { ret.offset+=1; }
break
if !(is_hex && first) {
ret.offset += 1;
}
break;
}
}
if first { first = false; }
if first {
first = false;
}
}
}
}
@@ -185,12 +204,9 @@ fn get_inprefix(
// this is the function a Sub's print will delegate to
// if it is a numeric field, passing the field details
// and an iterator to the argument
pub fn num_format(
field: &FormatField,
in_str_opt: Option<&String>
) -> Option<String> {
pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option<String> {
let fchar = field.field_char.clone();
// num format mainly operates by further delegating to one of
@@ -198,13 +214,15 @@ pub fn num_format(
// see formatter.rs for more details
// to do switch to static dispatch
let fmtr : Box<Formatter> = match *field.field_type {
let fmtr: Box<Formatter> = match *field.field_type {
FieldType::Intf => Box::new(Intf::new()),
FieldType::Floatf => Box::new(Floatf::new()),
FieldType::CninetyNineHexFloatf => Box::new(CninetyNineHexFloatf::new()),
FieldType::Scif => Box::new(Scif::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=
// if we can get an assumed value from looking at the first
@@ -258,13 +276,8 @@ pub fn num_format(
};
// if we have a formatPrimitive, print its results
// according to the field-char appropriate Formatter
if let Some(prim) = prim_opt {
Some(
fmtr.primitive_to_str(
&prim,
field.clone()
)
)
if let Some(prim) = prim_opt {
Some(fmtr.primitive_to_str(&prim, field.clone()))
} else {
None
}
+161 -163
View File
File diff suppressed because it is too large Load Diff
+1 -3
View File
@@ -26,7 +26,5 @@ pub trait Token {
// a number of arguments equal to the number of argument-using tokens
pub trait Tokenizer {
fn from_it(it: &mut PutBackN<Chars>,
args: &mut Peekable<Iter<String>>)
-> Option<Box<Token>>;
fn from_it(it: &mut PutBackN<Chars>, args: &mut Peekable<Iter<String>>) -> Option<Box<Token>>;
}
+63 -78
View File
@@ -17,23 +17,18 @@ impl UnescapedText {
fn new() -> UnescapedText {
UnescapedText(Vec::new())
}
//take an iterator to the format string
//consume between min and max chars
//and return it as a base-X number
fn base_to_u32(
min_chars: u8,
max_chars: u8,
base : u32,
it: &mut PutBackN<Chars>
) -> u32 {
let mut retval : u32 = 0;
let mut found=0;
// take an iterator to the format string
// consume between min and max chars
// and return it as a base-X number
fn base_to_u32(min_chars: u8, max_chars: u8, base: u32, it: &mut PutBackN<Chars>) -> u32 {
let mut retval: u32 = 0;
let mut found = 0;
while found < max_chars {
//if end of input break
// if end of input break
let nc = it.next();
match nc {
Some(digit) => {
//if end of hexchars break
// if end of hexchars break
match digit.to_digit(base) {
Some(d) => {
found += 1;
@@ -42,17 +37,17 @@ impl UnescapedText {
}
None => {
it.put_back(digit);
break
break;
}
}
},
}
None => {
break;
}
}
}
if found < min_chars {
//only ever expected for hex
// only ever expected for hex
println!("missing hexadecimal number in escape"); //todo stderr
exit(cli::EXIT_ERR);
}
@@ -65,36 +60,29 @@ impl UnescapedText {
// dropped-in as a replacement.
fn validate_iec(val: u32, eight_word: bool) {
let mut preface = 'u';
let mut leading_zeros= 4;
let mut leading_zeros = 4;
if eight_word {
preface='U';
leading_zeros=8;
preface = 'U';
leading_zeros = 8;
}
let err_msg = format!("invalid universal character name {0}{1:02$x}",
preface,
val,
leading_zeros);
if (val < 159 && (val != 36 && val != 64 && val != 96)) || (val > 55296 && val < 57343) {
println!("{}", err_msg);//todo stderr
exit(cli::EXIT_ERR);
}
let err_msg=format!("invalid universal character name {0}{1:02$x}",
preface,
val,
leading_zeros);
if (val < 159 && (val != 36 &&
val != 64 &&
val != 96)) ||
(val > 55296 && val < 57343) {
println!("{}", err_msg);//todo stderr
exit(cli::EXIT_ERR);
}
}
// pass an iterator that succeeds an '/',
// and process the remaining character
// adding the unescaped bytes
// to the passed byte_vec
// in subs_mode change octal behavior
fn handle_escaped(
byte_vec: &mut Vec<u8>,
it: &mut PutBackN<Chars>,
subs_mode: bool
) {
fn handle_escaped(byte_vec: &mut Vec<u8>, it: &mut PutBackN<Chars>, subs_mode: bool) {
let ch = match it.next() {
Some(x) => x,
None => '\\'
None => '\\',
};
match ch {
'0'...'9' | 'x' => {
@@ -103,9 +91,10 @@ impl UnescapedText {
let mut base = 16;
let ignore = false;
match ch {
'x'=>{ },
'x' => {}
e @ '0'...'9' => {
max_len=3; base =8;
max_len = 3;
base = 8;
// in practice, gnu coreutils printf
// interprets octals without a
// leading zero in %b
@@ -114,31 +103,29 @@ impl UnescapedText {
// if we ever want to match gnu coreutil
// printf's docs instead of its behavior
// we'd set this to true.
//if subs_mode && e != '0'
// { ignore = true; }
if ! subs_mode || e != '0'
{ it.put_back(ch); }
// if subs_mode && e != '0'
// { ignore = true; }
if !subs_mode || e != '0' {
it.put_back(ch);
}
}
_ =>{}
_ => {}
}
if ! ignore {
let val = (UnescapedText::base_to_u32(min_len,
max_len,
base,
it) % 256) as u8;
if !ignore {
let val = (UnescapedText::base_to_u32(min_len, max_len, base, it) % 256) as u8;
byte_vec.push(val);
let bvec = [val];
cli::flush_bytes(&bvec);
} else {
byte_vec.push(ch as u8);
}
},
}
e @ _ => {
//only for hex and octal
//is byte encoding specified.
//otherwise, why not leave the door open
//for other encodings unless it turns out
//a bottleneck.
// only for hex and octal
// is byte encoding specified.
// otherwise, why not leave the door open
// for other encodings unless it turns out
// a bottleneck.
let mut s = String::new();
let ch = match e {
'\\' => '\\',
@@ -146,31 +133,30 @@ impl UnescapedText {
'n' => '\n',
'r' => '\r',
't' => '\t',
//bell
// bell
'a' => '\x07',
//backspace
// backspace
'b' => '\x08',
//vertical tab
// vertical tab
'v' => '\x0B',
//form feed
// form feed
'f' => '\x0C',
//escape character
// escape character
'e' => '\x1B',
'c' => { exit(cli::EXIT_OK) },
'c' => exit(cli::EXIT_OK),
'u' | 'U' => {
let len = match e {
'u' => 4,
'U' | _ => 8
'U' | _ => 8,
};
let val = UnescapedText::base_to_u32(len,
len,
16,
it);
let val = UnescapedText::base_to_u32(len, len, 16, it);
UnescapedText::validate_iec(val, false);
if let Some(c) = from_u32(val) {
c
} else { '-' }
},
} else {
'-'
}
}
_ => {
s.push('\\');
ch
@@ -188,15 +174,16 @@ impl UnescapedText {
// and return a wrapper around a Vec<u8> of unescaped bytes
// break on encounter of sub symbol ('%[^%]') unless called
// through %b subst.
pub fn from_it_core(it: &mut PutBackN<Chars>,
subs_mode: bool) -> Option<Box<token::Token>> {
pub fn from_it_core(it: &mut PutBackN<Chars>, subs_mode: bool) -> Option<Box<token::Token>> {
let mut addchar = false;
let mut new_text = UnescapedText::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() {
if ! addchar { addchar = true; }
if !addchar {
addchar = true;
}
match ch as char {
x if x != '\\' && x != '%' => {
// lazy branch eval
@@ -216,10 +203,8 @@ impl UnescapedText {
if tmp_str.len() > 0 {
new_vec.extend(tmp_str.bytes());
tmp_str = String::new();
}
UnescapedText::handle_escaped(new_vec,
it,
subs_mode)
}
UnescapedText::handle_escaped(new_vec, it, subs_mode)
}
x if x == '%' && !subs_mode => {
if let Some(follow) = it.next() {
@@ -229,11 +214,11 @@ impl UnescapedText {
} else {
it.put_back(follow);
it.put_back(ch);
break
break;
}
} else {
it.put_back(ch);
break
break;
}
}
_ => {
@@ -248,7 +233,7 @@ impl UnescapedText {
}
match addchar {
true => Some(Box::new(new_text)),
false => None
false => None,
}
}
}
+242 -197
View File
@@ -8,228 +8,273 @@ static UTIL_NAME: &'static str = "printf";
fn expect_stdout(input: Vec<&str>, expected: &str) {
let (_, mut ucmd) = testing(UTIL_NAME);
let results = ucmd.args(&input).run();
//assert_empty_stderr!(result);
//assert!(result.success);
assert_eq!(expected,results.stdout);
// assert_empty_stderr!(result);
// assert!(result.success);
assert_eq!(expected, results.stdout);
}
#[test]
fn basic_literal() { 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");
fn basic_literal() {
expect_stdout(vec!["hello world"], "hello world");
}
#[test]
fn sub_any_asterisk_second_param() { expect_stdout(
vec!("%.*i", "3", "11", "4", "12"), "0110012");
fn escaped_tab() {
expect_stdout(vec!["hello\\t world"], "hello\t world");
}
#[test]
fn sub_any_asterisk_both_params() { expect_stdout(
vec!("%*.*i", "4", "3", "11", "5", "4", "12"), " 011 0012");
fn escaped_newline() {
expect_stdout(vec!["hello\\n world"], "hello\n world");
}
#[test]
fn sub_any_asterisk_octal_arg() { expect_stdout(
vec!("%.*i", "011", "12345678"), "012345678");
fn escaped_slash() {
expect_stdout(vec!["hello\\\\ world"], "hello\\ world");
}
#[test]
fn sub_any_asterisk_hex_arg() { expect_stdout(
vec!("%.*i", "0xA", "123456789"), "0123456789");
fn escaped_hex() {
expect_stdout(vec!["\\x41"], "A");
}
#[test]
fn sub_any_specifiers_no_params() { expect_stdout(
vec!("%ztlhLji", "3"), "3");
fn escaped_octal() {
expect_stdout(vec!["\\101"], "A");
}
#[test]
fn sub_any_specifiers_after_first_param() { expect_stdout(
vec!("%0ztlhLji", "3"), "3");
fn escaped_unicode_fourdigit() {
expect_stdout(vec!["\\u0125"], "ĥ");
}
#[test]
fn sub_any_specifiers_after_period() { expect_stdout(
vec!("%0.ztlhLji", "3"), "3");
fn escaped_unicode_eightdigit() {
expect_stdout(vec!["\\U00000125"], "ĥ");
}
#[test]
fn sub_any_specifiers_after_second_param() { expect_stdout(
vec!("%0.0ztlhLji", "3"), "3");
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]
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");
}