From f45169d37c1452695f4e1b90906ab51573abd839 Mon Sep 17 00:00:00 2001 From: Wim Hueskes Date: Sat, 23 Jul 2016 19:15:47 +0200 Subject: [PATCH] od: refactor: split into modules --- src/od/multifilereader.rs | 98 ++++++++++ src/od/od.rs | 367 +------------------------------------- src/od/prn_char.rs | 64 +++++++ src/od/prn_float.rs | 159 +++++++++++++++++ src/od/prn_int.rs | 39 ++++ 5 files changed, 369 insertions(+), 358 deletions(-) create mode 100644 src/od/multifilereader.rs create mode 100644 src/od/prn_char.rs create mode 100644 src/od/prn_float.rs create mode 100644 src/od/prn_int.rs diff --git a/src/od/multifilereader.rs b/src/od/multifilereader.rs new file mode 100644 index 000000000..2e3d2d909 --- /dev/null +++ b/src/od/multifilereader.rs @@ -0,0 +1,98 @@ +use std; +use std::io; +use std::io::BufReader; +use std::fs::File; +use std::io::Write; + +#[derive(Debug)] +pub enum InputSource<'a> { + FileName(&'a str ), + Stdin +} + +// MultifileReader - concatenate all our input, file or stdin. +pub struct MultifileReader<'a> { + ni: std::slice::Iter<'a, InputSource<'a>>, + curr_file: Option>, + pub any_err: bool, +} + +impl<'b> MultifileReader<'b> { + pub fn new<'a>(fnames: &'a [InputSource]) -> MultifileReader<'a> { + let mut mf = MultifileReader { + ni: fnames.iter(), + curr_file: None, // normally this means done; call next_file() + any_err: false, + }; + mf.next_file(); + return mf; + } + + fn next_file(&mut self) { + // loop retries with subsequent files if err - normally 'loops' once + loop { + match self.ni.next() { + None => { + self.curr_file = None; + return; + } + Some(input) => { + match *input { + InputSource::Stdin => { + self.curr_file = Some(Box::new(BufReader::new(std::io::stdin()))); + return; + } + InputSource::FileName(fname) => { + match File::open(fname) { + Ok(f) => { + self.curr_file = Some(Box::new(BufReader::new(f))); + return; + } + Err(e) => { + // If any file can't be opened, + // print an error at the time that the file is needed, + // then move on the the next file. + // This matches the behavior of the original `od` + let _ = + writeln!(&mut std::io::stderr(), "od: '{}': {}", fname, e); + self.any_err = true + } + } + } + } + } + } + } + } + + // Fill buf with bytes read from the list of files + // Returns Ok() + // Handles io errors itself, thus always returns OK + // Fills the provided buffer completely, unless it has run out of input. + // If any call returns short (< buf.len()), all subsequent calls will return Ok<0> + pub fn f_read(&mut self, buf: &mut [u8]) -> io::Result { + let mut xfrd = 0; + // while buffer we are filling is not full.. May go thru several files. + 'fillloop: while xfrd < buf.len() { + match self.curr_file { + None => break, + Some(ref mut curr_file) => { + loop { + // stdin may return on 'return' (enter), even though the buffer isn't full. + xfrd += match curr_file.read(&mut buf[xfrd..]) { + Ok(0) => break, + Ok(n) => n, + Err(e) => panic!("file error: {}", e), + }; + if xfrd == buf.len() { + // transferred all that was asked for. + break 'fillloop; + } + } + } + } + self.next_file(); + } + Ok(xfrd) + } +} diff --git a/src/od/od.rs b/src/od/od.rs index 99e9f6726..f658f8b83 100644 --- a/src/od/od.rs +++ b/src/od/od.rs @@ -13,16 +13,18 @@ extern crate getopts; extern crate unindent; extern crate byteorder; -use std::fs::File; -use std::io::Read; -use std::io::BufReader; -use std::io::Write; -use std::io; -use std::num::FpCategory; -use std::f32; +mod multifilereader; +mod prn_int; +mod prn_char; +mod prn_float; + use std::f64; use unindent::*; use byteorder::*; +use multifilereader::*; +use prn_int::*; +use prn_char::*; +use prn_float::*; //This is available in some versions of std, but not all that we target. macro_rules! hashmap { @@ -39,12 +41,6 @@ static VERSION: &'static str = env!("CARGO_PKG_VERSION"); #[derive(Debug)] enum Radix { Decimal, Hexadecimal, Octal, Binary } -#[derive(Debug)] -enum InputSource<'a> { - FileName(&'a str ), - Stdin -} - pub fn uumain(args: Vec) -> i32 { let mut opts = getopts::Options::new(); @@ -349,92 +345,6 @@ fn print_with_radix(r: &Radix, x: usize) { } } -// MultifileReader - concatenate all our input, file or stdin. -struct MultifileReader<'a> { - ni: std::slice::Iter<'a, InputSource<'a>>, - curr_file: Option>, - any_err: bool, -} -impl<'b> MultifileReader<'b> { - fn new<'a>(fnames: &'a [InputSource]) -> MultifileReader<'a> { - let mut mf = MultifileReader { - ni: fnames.iter(), - curr_file: None, // normally this means done; call next_file() - any_err: false, - }; - mf.next_file(); - return mf; - } - - fn next_file(&mut self) { - // loop retries with subsequent files if err - normally 'loops' once - loop { - match self.ni.next() { - None => { - self.curr_file = None; - return; - } - Some(input) => { - match *input { - InputSource::Stdin => { - self.curr_file = Some(Box::new(BufReader::new(std::io::stdin()))); - return; - } - InputSource::FileName(fname) => { - match File::open(fname) { - Ok(f) => { - self.curr_file = Some(Box::new(BufReader::new(f))); - return; - } - Err(e) => { - // If any file can't be opened, - // print an error at the time that the file is needed, - // then move on the the next file. - // This matches the behavior of the original `od` - let _ = - writeln!(&mut std::io::stderr(), "od: '{}': {}", fname, e); - self.any_err = true - } - } - } - } - } - } - } - } - - // Fill buf with bytes read from the list of files - // Returns Ok() - // Handles io errors itself, thus always returns OK - // Fills the provided buffer completely, unless it has run out of input. - // If any call returns short (< buf.len()), all subsequent calls will return Ok<0> - fn f_read(&mut self, buf: &mut [u8]) -> io::Result { - let mut xfrd = 0; - // while buffer we are filling is not full.. May go thru several files. - 'fillloop: while xfrd < buf.len() { - match self.curr_file { - None => break, - Some(ref mut curr_file) => { - loop { - // stdin may return on 'return' (enter), even though the buffer isn't full. - xfrd += match curr_file.read(&mut buf[xfrd..]) { - Ok(0) => break, - Ok(n) => n, - Err(e) => panic!("file error: {}", e), - }; - if xfrd == buf.len() { - // transferred all that was asked for. - break 'fillloop; - } - } - } - } - self.next_file(); - } - Ok(xfrd) - } -} - #[derive(Clone, Copy)] enum FormatWriter { IntWriter(fn(u64, usize)), @@ -446,262 +356,3 @@ struct OdFormat { writer: FormatWriter, offmarg: usize, } - -// TODO: use some sort of byte iterator, instead of passing bytes in u64 -fn print_item_oct(p: u64, itembytes: usize) { - let itemwidth = 3 * itembytes; - let itemspace = 4 * itembytes - itemwidth; - - print!("{:>itemspace$}{:0width$o}", - "", - p, - width = itemwidth, - itemspace = itemspace); -} - -fn print_item_hex(p: u64, itembytes: usize) { - let itemwidth = 2 * itembytes; - let itemspace = 4 * itembytes - itemwidth; - - print!("{:>itemspace$}{:0width$x}", - "", - p, - width = itemwidth, - itemspace = itemspace); -} - - -fn sign_extend(item: u64, itembytes: usize) -> i64{ - let shift = 64 - itembytes * 8; - (item << shift) as i64 >> shift -} - - -fn print_item_dec_s(p: u64, itembytes: usize) { - // sign extend - let s = sign_extend(p,itembytes); - print!("{:totalwidth$}", s, totalwidth = 4 * itembytes); -} -fn print_item_dec_u(p: u64, itembytes: usize) { - print!("{:totalwidth$}", p, totalwidth = 4 * itembytes); -} - -// TODO: multi-byte chars -// Quoth the man page: Multi-byte characters are displayed in the area corresponding to the first byte of the character. The remaining bytes are shown as `**'. - -static A_CHRS : [&'static str; 160] = -["nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", - "bs", "ht", "nl", "vt", "ff", "cr", "so", "si", - "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", - "can", "em", "sub", "esc", "fs", "gs", "rs", "us", - "sp", "!", "\"", "#", "$", "%", "&", "'", - "(", ")", "*", "+", ",", "-", ".", "/", - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", ":", ";", "<", "=", ">", "?", - "@", "A", "B", "C", "D", "E", "F", "G", - "H", "I", "J", "K", "L", "M", "N", "O", - "P", "Q", "R", "S", "T", "U", "V", "W", - "X", "Y", "Z", "[", "\\", "]", "^", "_", - "`", "a", "b", "c", "d", "e", "f", "g", - "h", "i", "j", "k", "l", "m", "n", "o", - "p", "q", "r", "s", "t", "u", "v", "w", - "x", "y", "z", "{", "|", "}", "~", "del", - "80", "81", "82", "83", "84", "85", "86", "87", - "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", - "90", "91", "92", "93", "94", "95", "96", "97", - "98", "99", "9a", "9b", "9c", "9d", "9e", "9f"]; - -fn print_item_a(p: u64, _: usize) { - // itembytes == 1 - let b = (p & 0xff) as u8; - print!("{:>4}", A_CHRS.get(b as usize).unwrap_or(&"?") // XXX od dose not actually do this, it just prints the byte - ); -} - - -static C_CHRS : [&'static str; 127] = [ -"\\0", "001", "002", "003", "004", "005", "006", "\\a", -"\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "016", "017", -"020", "021", "022", "023", "024", "025", "026", "027", -"030", "031", "032", "033", "034", "035", "036", "037", - " ", "!", "\"", "#", "$", "%", "&", "'", - "(", ")", "*", "+", ",", "-", ".", "/", - "0", "1", "2", "3", "4", "5", "6", "7", - "8", "9", ":", ";", "<", "=", ">", "?", - "@", "A", "B", "C", "D", "E", "F", "G", - "H", "I", "J", "K", "L", "M", "N", "O", - "P", "Q", "R", "S", "T", "U", "V", "W", - "X", "Y", "Z", "[", "\\", "]", "^", "_", - "`", "a", "b", "c", "d", "e", "f", "g", - "h", "i", "j", "k", "l", "m", "n", "o", - "p", "q", "r", "s", "t", "u", "v", "w", - "x", "y", "z", "{", "|", "}", "~" ]; - - -fn print_item_c(p: u64, _: usize) { - // itembytes == 1 - let b = (p & 0xff) as usize; - - if b < C_CHRS.len() { - match C_CHRS.get(b as usize) { - Some(s) => print!("{:>4}", s), - None => print!("{:>4}", b), - } - } -} - -fn print_item_flo32(f: f64) { - print!(" {}", format_flo32(f as f32)) -} - -fn print_item_flo64(f: f64) { - print!(" {}", format_flo64(f)) -} - -// formats float with 8 significant digits, eg 12345678 or -1.2345678e+12 -// always retuns a string of 14 characters -fn format_flo32(f: f32) -> String { - let width: usize = 14; - let precision: usize = 8; - - if f.classify() == FpCategory::Subnormal { - // subnormal numbers will be normal as f64, so will print with a wrong precision - format!("{:width$e}", f, width = width) // subnormal numbers - } - else { - format_float(f as f64, width, precision) - } -} - -fn format_flo64(f: f64) -> String { - format_float(f, 24, 17) -} - -fn format_float(f: f64, width: usize, precision: usize) -> String { - - if !f.is_normal() { - if f == -0.0 && f.is_sign_negative() { return format!("{:>width$}", "-0", width = width) } - if f == 0.0 || !f.is_finite() { return format!("{:width$}", f, width = width) } - return format!("{:width$e}", f, width = width) // subnormal numbers - } - - let mut l = f.abs().log10().floor() as i32; - - let r = 10f64.powi(l); - if (f > 0.0 && r > f) || (f < 0.0 && -r < f) { - // fix precision error - l = l - 1; - } - - if l >= 0 && l <= (precision as i32 - 1) { - format!("{:width$.dec$}", f, - width = width, - dec = (precision-1) - l as usize) - } - else if l == -1 { - format!("{:width$.dec$}", f, - width = width, - dec = precision) - } - else { - format!("{:width$.dec$e}", f, - width = width, - dec = precision - 1) - } -} - -#[test] -fn test_format_flo32() { - assert_eq!(format_flo32(1.0), " 1.0000000"); - assert_eq!(format_flo32(9.9999990), " 9.9999990"); - assert_eq!(format_flo32(10.0), " 10.000000"); - assert_eq!(format_flo32(99.999977), " 99.999977"); - assert_eq!(format_flo32(99.999992), " 99.999992"); - assert_eq!(format_flo32(100.0), " 100.00000"); - assert_eq!(format_flo32(999.99994), " 999.99994"); - assert_eq!(format_flo32(1000.0), " 1000.0000"); - assert_eq!(format_flo32(9999.9990), " 9999.9990"); - assert_eq!(format_flo32(10000.0), " 10000.000"); - assert_eq!(format_flo32(99999.992), " 99999.992"); - assert_eq!(format_flo32(100000.0), " 100000.00"); - assert_eq!(format_flo32(999999.94), " 999999.94"); - assert_eq!(format_flo32(1000000.0), " 1000000.0"); - assert_eq!(format_flo32(9999999.0), " 9999999.0"); - assert_eq!(format_flo32(10000000.0), " 10000000"); - assert_eq!(format_flo32(99999992.0), " 99999992"); - assert_eq!(format_flo32(100000000.0), " 1.0000000e8"); - assert_eq!(format_flo32(9.9999994e8), " 9.9999994e8"); - assert_eq!(format_flo32(1.0e9), " 1.0000000e9"); - assert_eq!(format_flo32(9.9999990e9), " 9.9999990e9"); - assert_eq!(format_flo32(1.0e10), " 1.0000000e10"); - - assert_eq!(format_flo32(0.1), " 0.10000000"); - assert_eq!(format_flo32(0.99999994), " 0.99999994"); - assert_eq!(format_flo32(0.010000001), " 1.0000001e-2"); - assert_eq!(format_flo32(0.099999994), " 9.9999994e-2"); - assert_eq!(format_flo32(0.001), " 1.0000000e-3"); - assert_eq!(format_flo32(0.0099999998), " 9.9999998e-3"); - - assert_eq!(format_flo32(-1.0), " -1.0000000"); - assert_eq!(format_flo32(-9.9999990), " -9.9999990"); - assert_eq!(format_flo32(-10.0), " -10.000000"); - assert_eq!(format_flo32(-99.999977), " -99.999977"); - assert_eq!(format_flo32(-99.999992), " -99.999992"); - assert_eq!(format_flo32(-100.0), " -100.00000"); - assert_eq!(format_flo32(-999.99994), " -999.99994"); - assert_eq!(format_flo32(-1000.0), " -1000.0000"); - assert_eq!(format_flo32(-9999.9990), " -9999.9990"); - assert_eq!(format_flo32(-10000.0), " -10000.000"); - assert_eq!(format_flo32(-99999.992), " -99999.992"); - assert_eq!(format_flo32(-100000.0), " -100000.00"); - assert_eq!(format_flo32(-999999.94), " -999999.94"); - assert_eq!(format_flo32(-1000000.0), " -1000000.0"); - assert_eq!(format_flo32(-9999999.0), " -9999999.0"); - assert_eq!(format_flo32(-10000000.0), " -10000000"); - assert_eq!(format_flo32(-99999992.0), " -99999992"); - assert_eq!(format_flo32(-100000000.0), " -1.0000000e8"); - assert_eq!(format_flo32(-9.9999994e8), " -9.9999994e8"); - assert_eq!(format_flo32(-1.0e9), " -1.0000000e9"); - assert_eq!(format_flo32(-9.9999990e9), " -9.9999990e9"); - assert_eq!(format_flo32(-1.0e10), " -1.0000000e10"); - - assert_eq!(format_flo32(-0.1), " -0.10000000"); - assert_eq!(format_flo32(-0.99999994), " -0.99999994"); - assert_eq!(format_flo32(-0.010000001), " -1.0000001e-2"); - assert_eq!(format_flo32(-0.099999994), " -9.9999994e-2"); - assert_eq!(format_flo32(-0.001), " -1.0000000e-3"); - assert_eq!(format_flo32(-0.0099999998), " -9.9999998e-3"); - - assert_eq!(format_flo32(3.4028233e38), " 3.4028233e38"); - assert_eq!(format_flo32(-3.4028233e38), " -3.4028233e38"); - assert_eq!(format_flo32(-1.1663108e-38),"-1.1663108e-38"); - assert_eq!(format_flo32(-4.7019771e-38),"-4.7019771e-38"); - assert_eq!(format_flo32(1e-45), " 1e-45"); - - assert_eq!(format_flo32(-3.402823466e+38), " -3.4028235e38"); - assert_eq!(format_flo32(f32::NAN), " NaN"); - assert_eq!(format_flo32(f32::INFINITY), " inf"); - assert_eq!(format_flo32(f32::NEG_INFINITY), " -inf"); - assert_eq!(format_flo32(-0.0), " -0"); - assert_eq!(format_flo32(0.0), " 0"); -} - -#[test] -fn test_format_flo64() { - assert_eq!(format_flo64(1.0), " 1.0000000000000000"); - assert_eq!(format_flo64(10.0), " 10.000000000000000"); - assert_eq!(format_flo64(1000000000000000.0), " 1000000000000000.0"); - assert_eq!(format_flo64(10000000000000000.0), " 10000000000000000"); - assert_eq!(format_flo64(100000000000000000.0), " 1.0000000000000000e17"); - - assert_eq!(format_flo64(-0.1), " -0.10000000000000001"); - assert_eq!(format_flo64(-0.01), " -1.0000000000000000e-2"); - - assert_eq!(format_flo64(-2.2250738585072014e-308),"-2.2250738585072014e-308"); - assert_eq!(format_flo64(4e-320), " 4e-320"); - assert_eq!(format_flo64(f64::NAN), " NaN"); - assert_eq!(format_flo64(f64::INFINITY), " inf"); - assert_eq!(format_flo64(f64::NEG_INFINITY), " -inf"); - assert_eq!(format_flo64(-0.0), " -0"); - assert_eq!(format_flo64(0.0), " 0"); -} diff --git a/src/od/prn_char.rs b/src/od/prn_char.rs new file mode 100644 index 000000000..8791d51d5 --- /dev/null +++ b/src/od/prn_char.rs @@ -0,0 +1,64 @@ + +// TODO: multi-byte chars +// Quoth the man page: Multi-byte characters are displayed in the area corresponding to the first byte of the character. The remaining bytes are shown as `**'. + +static A_CHRS : [&'static str; 160] = +["nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", + "bs", "ht", "nl", "vt", "ff", "cr", "so", "si", + "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", + "can", "em", "sub", "esc", "fs", "gs", "rs", "us", + "sp", "!", "\"", "#", "$", "%", "&", "'", + "(", ")", "*", "+", ",", "-", ".", "/", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", ":", ";", "<", "=", ">", "?", + "@", "A", "B", "C", "D", "E", "F", "G", + "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", + "X", "Y", "Z", "[", "\\", "]", "^", "_", + "`", "a", "b", "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", "m", "n", "o", + "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "{", "|", "}", "~", "del", + "80", "81", "82", "83", "84", "85", "86", "87", + "88", "89", "8a", "8b", "8c", "8d", "8e", "8f", + "90", "91", "92", "93", "94", "95", "96", "97", + "98", "99", "9a", "9b", "9c", "9d", "9e", "9f"]; + +pub fn print_item_a(p: u64, _: usize) { + // itembytes == 1 + let b = (p & 0xff) as u8; + print!("{:>4}", A_CHRS.get(b as usize).unwrap_or(&"?") // XXX od dose not actually do this, it just prints the byte + ); +} + + +static C_CHRS : [&'static str; 127] = [ +"\\0", "001", "002", "003", "004", "005", "006", "\\a", +"\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "016", "017", +"020", "021", "022", "023", "024", "025", "026", "027", +"030", "031", "032", "033", "034", "035", "036", "037", + " ", "!", "\"", "#", "$", "%", "&", "'", + "(", ")", "*", "+", ",", "-", ".", "/", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", ":", ";", "<", "=", ">", "?", + "@", "A", "B", "C", "D", "E", "F", "G", + "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", + "X", "Y", "Z", "[", "\\", "]", "^", "_", + "`", "a", "b", "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", "m", "n", "o", + "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "{", "|", "}", "~" ]; + + +pub fn print_item_c(p: u64, _: usize) { + // itembytes == 1 + let b = (p & 0xff) as usize; + + if b < C_CHRS.len() { + match C_CHRS.get(b as usize) { + Some(s) => print!("{:>4}", s), + None => print!("{:>4}", b), + } + } +} diff --git a/src/od/prn_float.rs b/src/od/prn_float.rs new file mode 100644 index 000000000..76118e73c --- /dev/null +++ b/src/od/prn_float.rs @@ -0,0 +1,159 @@ +use std::num::FpCategory; +use std::f32; +use std::f64; + +pub fn print_item_flo32(f: f64) { + print!(" {}", format_flo32(f as f32)) +} + +pub fn print_item_flo64(f: f64) { + print!(" {}", format_flo64(f)) +} + +// formats float with 8 significant digits, eg 12345678 or -1.2345678e+12 +// always retuns a string of 14 characters +fn format_flo32(f: f32) -> String { + let width: usize = 14; + let precision: usize = 8; + + if f.classify() == FpCategory::Subnormal { + // subnormal numbers will be normal as f64, so will print with a wrong precision + format!("{:width$e}", f, width = width) // subnormal numbers + } + else { + format_float(f as f64, width, precision) + } +} + +fn format_flo64(f: f64) -> String { + format_float(f, 24, 17) +} + +fn format_float(f: f64, width: usize, precision: usize) -> String { + + if !f.is_normal() { + if f == -0.0 && f.is_sign_negative() { return format!("{:>width$}", "-0", width = width) } + if f == 0.0 || !f.is_finite() { return format!("{:width$}", f, width = width) } + return format!("{:width$e}", f, width = width) // subnormal numbers + } + + let mut l = f.abs().log10().floor() as i32; + + let r = 10f64.powi(l); + if (f > 0.0 && r > f) || (f < 0.0 && -r < f) { + // fix precision error + l = l - 1; + } + + if l >= 0 && l <= (precision as i32 - 1) { + format!("{:width$.dec$}", f, + width = width, + dec = (precision-1) - l as usize) + } + else if l == -1 { + format!("{:width$.dec$}", f, + width = width, + dec = precision) + } + else { + format!("{:width$.dec$e}", f, + width = width, + dec = precision - 1) + } +} + +#[test] +fn test_format_flo32() { + assert_eq!(format_flo32(1.0), " 1.0000000"); + assert_eq!(format_flo32(9.9999990), " 9.9999990"); + assert_eq!(format_flo32(10.0), " 10.000000"); + assert_eq!(format_flo32(99.999977), " 99.999977"); + assert_eq!(format_flo32(99.999992), " 99.999992"); + assert_eq!(format_flo32(100.0), " 100.00000"); + assert_eq!(format_flo32(999.99994), " 999.99994"); + assert_eq!(format_flo32(1000.0), " 1000.0000"); + assert_eq!(format_flo32(9999.9990), " 9999.9990"); + assert_eq!(format_flo32(10000.0), " 10000.000"); + assert_eq!(format_flo32(99999.992), " 99999.992"); + assert_eq!(format_flo32(100000.0), " 100000.00"); + assert_eq!(format_flo32(999999.94), " 999999.94"); + assert_eq!(format_flo32(1000000.0), " 1000000.0"); + assert_eq!(format_flo32(9999999.0), " 9999999.0"); + assert_eq!(format_flo32(10000000.0), " 10000000"); + assert_eq!(format_flo32(99999992.0), " 99999992"); + assert_eq!(format_flo32(100000000.0), " 1.0000000e8"); + assert_eq!(format_flo32(9.9999994e8), " 9.9999994e8"); + assert_eq!(format_flo32(1.0e9), " 1.0000000e9"); + assert_eq!(format_flo32(9.9999990e9), " 9.9999990e9"); + assert_eq!(format_flo32(1.0e10), " 1.0000000e10"); + + assert_eq!(format_flo32(0.1), " 0.10000000"); + assert_eq!(format_flo32(0.99999994), " 0.99999994"); + assert_eq!(format_flo32(0.010000001), " 1.0000001e-2"); + assert_eq!(format_flo32(0.099999994), " 9.9999994e-2"); + assert_eq!(format_flo32(0.001), " 1.0000000e-3"); + assert_eq!(format_flo32(0.0099999998), " 9.9999998e-3"); + + assert_eq!(format_flo32(-1.0), " -1.0000000"); + assert_eq!(format_flo32(-9.9999990), " -9.9999990"); + assert_eq!(format_flo32(-10.0), " -10.000000"); + assert_eq!(format_flo32(-99.999977), " -99.999977"); + assert_eq!(format_flo32(-99.999992), " -99.999992"); + assert_eq!(format_flo32(-100.0), " -100.00000"); + assert_eq!(format_flo32(-999.99994), " -999.99994"); + assert_eq!(format_flo32(-1000.0), " -1000.0000"); + assert_eq!(format_flo32(-9999.9990), " -9999.9990"); + assert_eq!(format_flo32(-10000.0), " -10000.000"); + assert_eq!(format_flo32(-99999.992), " -99999.992"); + assert_eq!(format_flo32(-100000.0), " -100000.00"); + assert_eq!(format_flo32(-999999.94), " -999999.94"); + assert_eq!(format_flo32(-1000000.0), " -1000000.0"); + assert_eq!(format_flo32(-9999999.0), " -9999999.0"); + assert_eq!(format_flo32(-10000000.0), " -10000000"); + assert_eq!(format_flo32(-99999992.0), " -99999992"); + assert_eq!(format_flo32(-100000000.0), " -1.0000000e8"); + assert_eq!(format_flo32(-9.9999994e8), " -9.9999994e8"); + assert_eq!(format_flo32(-1.0e9), " -1.0000000e9"); + assert_eq!(format_flo32(-9.9999990e9), " -9.9999990e9"); + assert_eq!(format_flo32(-1.0e10), " -1.0000000e10"); + + assert_eq!(format_flo32(-0.1), " -0.10000000"); + assert_eq!(format_flo32(-0.99999994), " -0.99999994"); + assert_eq!(format_flo32(-0.010000001), " -1.0000001e-2"); + assert_eq!(format_flo32(-0.099999994), " -9.9999994e-2"); + assert_eq!(format_flo32(-0.001), " -1.0000000e-3"); + assert_eq!(format_flo32(-0.0099999998), " -9.9999998e-3"); + + assert_eq!(format_flo32(3.4028233e38), " 3.4028233e38"); + assert_eq!(format_flo32(-3.4028233e38), " -3.4028233e38"); + assert_eq!(format_flo32(-1.1663108e-38),"-1.1663108e-38"); + assert_eq!(format_flo32(-4.7019771e-38),"-4.7019771e-38"); + assert_eq!(format_flo32(1e-45), " 1e-45"); + + assert_eq!(format_flo32(-3.402823466e+38), " -3.4028235e38"); + assert_eq!(format_flo32(f32::NAN), " NaN"); + assert_eq!(format_flo32(f32::INFINITY), " inf"); + assert_eq!(format_flo32(f32::NEG_INFINITY), " -inf"); + assert_eq!(format_flo32(-0.0), " -0"); + assert_eq!(format_flo32(0.0), " 0"); +} + +#[test] +fn test_format_flo64() { + assert_eq!(format_flo64(1.0), " 1.0000000000000000"); + assert_eq!(format_flo64(10.0), " 10.000000000000000"); + assert_eq!(format_flo64(1000000000000000.0), " 1000000000000000.0"); + assert_eq!(format_flo64(10000000000000000.0), " 10000000000000000"); + assert_eq!(format_flo64(100000000000000000.0), " 1.0000000000000000e17"); + + assert_eq!(format_flo64(-0.1), " -0.10000000000000001"); + assert_eq!(format_flo64(-0.01), " -1.0000000000000000e-2"); + + assert_eq!(format_flo64(-2.2250738585072014e-308),"-2.2250738585072014e-308"); + assert_eq!(format_flo64(4e-320), " 4e-320"); + assert_eq!(format_flo64(f64::NAN), " NaN"); + assert_eq!(format_flo64(f64::INFINITY), " inf"); + assert_eq!(format_flo64(f64::NEG_INFINITY), " -inf"); + assert_eq!(format_flo64(-0.0), " -0"); + assert_eq!(format_flo64(0.0), " 0"); +} diff --git a/src/od/prn_int.rs b/src/od/prn_int.rs new file mode 100644 index 000000000..47959168f --- /dev/null +++ b/src/od/prn_int.rs @@ -0,0 +1,39 @@ +// TODO: use some sort of byte iterator, instead of passing bytes in u64 +pub fn print_item_oct(p: u64, itembytes: usize) { + let itemwidth = 3 * itembytes; + let itemspace = 4 * itembytes - itemwidth; + + print!("{:>itemspace$}{:0width$o}", + "", + p, + width = itemwidth, + itemspace = itemspace); +} + +pub fn print_item_hex(p: u64, itembytes: usize) { + let itemwidth = 2 * itembytes; + let itemspace = 4 * itembytes - itemwidth; + + print!("{:>itemspace$}{:0width$x}", + "", + p, + width = itemwidth, + itemspace = itemspace); +} + + +fn sign_extend(item: u64, itembytes: usize) -> i64{ + let shift = 64 - itembytes * 8; + (item << shift) as i64 >> shift +} + + +pub fn print_item_dec_s(p: u64, itembytes: usize) { + // sign extend + let s = sign_extend(p,itembytes); + print!("{:totalwidth$}", s, totalwidth = 4 * itembytes); +} + +pub fn print_item_dec_u(p: u64, itembytes: usize) { + print!("{:totalwidth$}", p, totalwidth = 4 * itembytes); +}