mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
od: Accept multiple files names as input
This commit is contained in:
parent
1fbda9663d
commit
e6cf167d1d
1 changed files with 119 additions and 49 deletions
96
src/od/od.rs
96
src/od/od.rs
|
@ -14,7 +14,9 @@ extern crate getopts;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::Path;
|
use std::io::BufReader;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::io;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
enum Radix { Decimal, Hexadecimal, Octal, Binary }
|
enum Radix { Decimal, Hexadecimal, Octal, Binary }
|
||||||
|
@ -51,30 +53,96 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
Err(f) => { panic!("Invalid -A/--address-radix\n{}", f) }
|
Err(f) => { panic!("Invalid -A/--address-radix\n{}", f) }
|
||||||
};
|
};
|
||||||
|
|
||||||
let fname = match args.last() {
|
// Gather up file names - args wich don't start with '-'
|
||||||
Some(n) => n,
|
let fnames = args[1..]
|
||||||
None => { panic!("Need fname for now") ; }
|
.iter()
|
||||||
|
.filter(|w| !w.starts_with('-'))
|
||||||
|
.map(|x| x.clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
// With no filenames, od would use stdin as input, which is currently not supported.
|
||||||
|
if fnames.len() == 0 {
|
||||||
|
panic!("Need fname for now") ;
|
||||||
};
|
};
|
||||||
|
odfunc(&input_offset_base, fnames)
|
||||||
odfunc(&input_offset_base, &fname);
|
|
||||||
|
|
||||||
0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const LINEBYTES:usize = 16;
|
const LINEBYTES:usize = 16;
|
||||||
const WORDBYTES:usize = 2;
|
const WORDBYTES:usize = 2;
|
||||||
|
|
||||||
fn odfunc(input_offset_base: &Radix, fname: &str) {
|
fn odfunc(input_offset_base: &Radix, fnames: Vec<String>) -> i32 {
|
||||||
let mut f = match File::open(Path::new(fname)) {
|
|
||||||
Ok(f) => f,
|
let mut status = 0;
|
||||||
Err(e) => panic!("file error: {}", e)
|
let mut ni = fnames.iter();
|
||||||
|
{
|
||||||
|
// Open and return the next file to process as a BufReader
|
||||||
|
// Returns None when no more files.
|
||||||
|
let mut next_file = || -> Option<BufReader<File>> {
|
||||||
|
// loop retries with subsequent files if err - normally 'loops' once
|
||||||
|
loop {
|
||||||
|
let fname = match ni.next() {
|
||||||
|
None => return None,
|
||||||
|
Some(s) => s,
|
||||||
|
};
|
||||||
|
match File::open(fname) {
|
||||||
|
Ok(f) => return Some(BufReader::new(f)),
|
||||||
|
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);
|
||||||
|
if status == 0 {status = 1}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut curr_file: BufReader<File> = match next_file() {
|
||||||
|
Some(f) => f,
|
||||||
|
None => {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut exhausted = false; // There is no more input, gone to the end of the last file.
|
||||||
|
|
||||||
|
// 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>
|
||||||
|
let mut f_read = |buf: &mut [u8]| -> io::Result<usize> {
|
||||||
|
if exhausted {
|
||||||
|
Ok(0)
|
||||||
|
} else {
|
||||||
|
let mut xfrd = 0;
|
||||||
|
while xfrd < buf.len() {
|
||||||
|
xfrd += match curr_file.read(&mut buf[xfrd..]) {
|
||||||
|
Ok(n) => n,
|
||||||
|
Err(e) => panic!("file error: {}", e),
|
||||||
|
};
|
||||||
|
if xfrd == buf.len() {
|
||||||
|
// transferred all that was asked for.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
curr_file = match next_file() {
|
||||||
|
Some(f) => f,
|
||||||
|
None => {
|
||||||
|
exhausted = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
Ok(xfrd)
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut addr = 0;
|
let mut addr = 0;
|
||||||
let bytes = &mut [b'\x00'; LINEBYTES];
|
let bytes = &mut [b'\x00'; LINEBYTES];
|
||||||
loop { // print each line
|
loop { // print each line
|
||||||
print_with_radix(input_offset_base, addr); // print offset
|
print_with_radix(input_offset_base, addr); // print offset
|
||||||
match f.read(bytes) {
|
match f_read(bytes) {
|
||||||
Ok(0) => {
|
Ok(0) => {
|
||||||
print!("\n");
|
print!("\n");
|
||||||
break;
|
break;
|
||||||
|
@ -106,6 +174,8 @@ fn odfunc(input_offset_base: &Radix, fname: &str) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
|
status
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_radix(radix_str: Option<String>) -> Result<Radix, &'static str> {
|
fn parse_radix(radix_str: Option<String>) -> Result<Radix, &'static str> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue