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:
parent
104f8eb509
commit
f45169d37c
5 changed files with 369 additions and 358 deletions
98
src/od/multifilereader.rs
Normal file
98
src/od/multifilereader.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
367
src/od/od.rs
367
src/od/od.rs
|
@ -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
64
src/od/prn_char.rs
Normal 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
159
src/od/prn_float.rs
Normal 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
39
src/od/prn_int.rs
Normal 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);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue