use std::env;
use std::vec::Vec;
use super::format_field::{FieldType, FormatField};
use super::formatter::{Base, FormatPrimitive, Formatter, InPrefix};
use super::formatters::cninetyninehexfloatf::CninetyNineHexFloatf;
use super::formatters::decf::Decf;
use super::formatters::floatf::Floatf;
use super::formatters::intf::Intf;
use super::formatters::scif::Scif;
use crate::cli;
pub fn warn_expected_numeric(pf_arg: &str) {
cli::err_msg(&format!("{}: expected a numeric value", pf_arg));
}
fn warn_char_constant_ign(remaining_bytes: Vec<u8>) {
match env::var("POSIXLY_CORRECT") {
Ok(_) => {}
Err(e) => {
if let env::VarError::NotPresent = e {
cli::err_msg(&format!(
"warning: {:?}: character(s) following character \
constant have been ignored",
&*remaining_bytes
));
}
}
}
}
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();
if let Some(qchar) = byte_it.next() {
match qchar {
C_S_QUOTE | C_D_QUOTE => {
Some(match byte_it.next() {
Some(second_byte) => {
let mut ignored: Vec<u8> = Vec::new();
for cont in byte_it {
ignored.push(cont);
}
if !ignored.is_empty() {
warn_char_constant_ign(ignored);
}
second_byte as u8
}
None => {
let so_far = (qchar as u8 as char).to_string();
warn_expected_numeric(&so_far);
0_u8
}
})
}
_ => None, }
} else {
Some(0_u8)
}
}
None => Some(0),
}
}
fn get_inprefix(str_in: &str, 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 topchar = str_it.next();
while let Some(' ') = topchar {
ret.offset += 1;
topchar = str_it.next();
}
match topchar {
Some('+') => {
ret.offset += 1;
topchar = str_it.next();
}
Some('-') => {
ret.sign = -1;
ret.offset += 1;
topchar = str_it.next();
}
_ => {}
}
let mut is_hex = false;
if Some('0') == topchar {
if let Some(base) = str_it.next() {
let mut do_clean_lead_zeroes = false;
match base {
'x' | 'X' => {
is_hex = true;
ret.offset += 2;
ret.radix_in = Base::Hex;
do_clean_lead_zeroes = true;
}
e @ '0'..='9' => {
ret.offset += 1;
if let FieldType::Intf = *field_type {
ret.radix_in = Base::Octal;
}
if e == '0' {
do_clean_lead_zeroes = true;
}
}
_ => {}
}
if do_clean_lead_zeroes {
let mut first = true;
for ch_zero in str_it {
match ch_zero {
'0' => {
if !(is_hex && first) {
ret.offset += 1;
}
}
'.' => break,
_ => {
if !(is_hex && first) {
ret.offset += 1;
}
break;
}
}
if first {
first = false;
}
}
}
}
}
ret
}
pub fn num_format(field: &FormatField, in_str_opt: Option<&String>) -> Option<String> {
let fchar = field.field_char;
let fmtr: Box<dyn 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");
}
};
let prim_opt=
if let Some(provided_num) = get_provided(in_str_opt) {
let mut tmp : FormatPrimitive = Default::default();
match fchar {
'u' | 'i' | 'd' => {
tmp.pre_decimal = Some(
format!("{}", provided_num));
},
'x' | 'X' => {
tmp.pre_decimal = Some(
format!("{:x}", provided_num));
},
'o' => {
tmp.pre_decimal = Some(
format!("{:o}", provided_num));
},
'e' | 'E' | 'g' | 'G' => {
let as_str = format!("{}", provided_num);
let inprefix = get_inprefix(
&as_str,
&field.field_type
);
tmp=fmtr.get_primitive(field, &inprefix, &as_str)
.expect("err during default provided num");
},
_ => {
tmp.pre_decimal = Some(
format!("{}", provided_num));
tmp.post_decimal = Some(String::from("0"));
}
}
Some(tmp)
} else {
let in_str = in_str_opt.expect(
"please send the devs this message:
\n get_provided is failing to ret as Some(0) on no str ");
let inprefix = get_inprefix(
in_str,
&field.field_type
);
fmtr.get_primitive(field, &inprefix, in_str)
};
if let Some(prim) = prim_opt {
Some(fmtr.primitive_to_str(&prim, field.clone()))
} else {
None
}
}