1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

od: refactor: split into modules

This commit is contained in:
Wim Hueskes 2016-07-23 19:15:47 +02:00
parent 104f8eb509
commit f45169d37c
5 changed files with 369 additions and 358 deletions

98
src/od/multifilereader.rs Normal file
View file

@ -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<Box<io::Read>>,
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(<number of bytes read>)
// 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<usize> {
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)
}
}

View file

@ -13,16 +13,18 @@ extern crate getopts;
extern crate unindent; extern crate unindent;
extern crate byteorder; extern crate byteorder;
use std::fs::File; mod multifilereader;
use std::io::Read; mod prn_int;
use std::io::BufReader; mod prn_char;
use std::io::Write; mod prn_float;
use std::io;
use std::num::FpCategory;
use std::f32;
use std::f64; use std::f64;
use unindent::*; use unindent::*;
use byteorder::*; 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. //This is available in some versions of std, but not all that we target.
macro_rules! hashmap { macro_rules! hashmap {
@ -39,12 +41,6 @@ static VERSION: &'static str = env!("CARGO_PKG_VERSION");
#[derive(Debug)] #[derive(Debug)]
enum Radix { Decimal, Hexadecimal, Octal, Binary } enum Radix { Decimal, Hexadecimal, Octal, Binary }
#[derive(Debug)]
enum InputSource<'a> {
FileName(&'a str ),
Stdin
}
pub fn uumain(args: Vec<String>) -> i32 { pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = getopts::Options::new(); 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<Box<io::Read>>,
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(<number of bytes read>)
// 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<usize> {
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)] #[derive(Clone, Copy)]
enum FormatWriter { enum FormatWriter {
IntWriter(fn(u64, usize)), IntWriter(fn(u64, usize)),
@ -446,262 +356,3 @@ struct OdFormat {
writer: FormatWriter, writer: FormatWriter,
offmarg: usize, 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");
}

64
src/od/prn_char.rs Normal file
View file

@ -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),
}
}
}

159
src/od/prn_float.rs Normal file
View file

@ -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");
}

39
src/od/prn_int.rs Normal file
View file

@ -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);
}