1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-27 02:57:44 +00:00

od: several small changes after review

* update status in README.md
* enable busybox tests
  Adding `CONFIG_DESKTOP` and `CONFIG_LONG_OPTS` to busybox config.
  These flags also enable other tests, but those utilities are not
  included in `TEST_PROGS`. (eg. awk)
* fix whitespace and small issues
* fix Eq imp for FormatWriter on nightly + beta
* fix indention in multifilereader.rs
* fix intermittent errors in tests
This commit is contained in:
Wim Hueskes 2016-11-09 20:26:55 +01:00
parent 99f70ba648
commit 2550e0f3c7
16 changed files with 180 additions and 247 deletions

View file

@ -1,2 +1,4 @@
CONFIG_FEATURE_FANCY_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y
CONFIG_UNICODE_SUPPORT=y CONFIG_UNICODE_SUPPORT=y
CONFIG_DESKTOP=y
CONFIG_LONG_OPTS=y

View file

@ -201,7 +201,7 @@ To do
* [x] nohup * [x] nohup
* [x] nproc * [x] nproc
* [ ] numfmt * [ ] numfmt
* [ ] od (in progress, needs lots of work) * [ ] od (almost complete, `--strings` and 128-bit datatypes are missing)
* [x] paste * [x] paste
* [x] pathchk * [x] pathchk
* [x] pinky * [x] pinky

View file

@ -1,6 +1,6 @@
use std::fmt; use std::fmt;
#[derive(Copy, Eq)] #[derive(Copy)]
pub enum FormatWriter { pub enum FormatWriter {
IntWriter(fn(u64) -> String), IntWriter(fn(u64) -> String),
FloatWriter(fn(f64) -> String), FloatWriter(fn(f64) -> String),
@ -27,6 +27,8 @@ impl PartialEq for FormatWriter {
} }
} }
impl Eq for FormatWriter {}
impl fmt::Debug for FormatWriter { impl fmt::Debug for FormatWriter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {

View file

@ -29,7 +29,6 @@ impl<'a, I> InputDecoder<'a, I> {
/// Creates a new `InputDecoder` with an allocated buffer of `normal_length` + `peek_length` bytes. /// Creates a new `InputDecoder` with an allocated buffer of `normal_length` + `peek_length` bytes.
/// `byte_order` determines how to read multibyte formats from the buffer. /// `byte_order` determines how to read multibyte formats from the buffer.
pub fn new(input: &mut I, normal_length: usize, peek_length: usize, byte_order: ByteOrder) -> InputDecoder<I> { pub fn new(input: &mut I, normal_length: usize, peek_length: usize, byte_order: ByteOrder) -> InputDecoder<I> {
let mut bytes: Vec<u8> = Vec::with_capacity(normal_length + peek_length); let mut bytes: Vec<u8> = Vec::with_capacity(normal_length + peek_length);
unsafe { bytes.set_len(normal_length + peek_length); } // fast but uninitialized unsafe { bytes.set_len(normal_length + peek_length); } // fast but uninitialized
@ -165,7 +164,7 @@ mod tests {
let mut copy: Vec<u8> = Vec::new(); let mut copy: Vec<u8> = Vec::new();
mem.clone_buffer(&mut copy); mem.clone_buffer(&mut copy);
assert_eq!(vec!{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0}, copy); assert_eq!(vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0], copy);
mem.zero_out_buffer(7, 8); mem.zero_out_buffer(7, 8);
assert_eq!(&[0, 0, 0xff, 0xff], mem.get_full_buffer(6)); assert_eq!(&[0, 0, 0xff, 0xff], mem.get_full_buffer(6));

View file

@ -62,8 +62,7 @@ impl FailingMockStream {
fn error(&mut self) -> Result<usize> { fn error(&mut self) -> Result<usize> {
if self.repeat_count == 0 { if self.repeat_count == 0 {
return Ok(0) return Ok(0)
} } else {
else {
if self.repeat_count > 0 { if self.repeat_count > 0 {
self.repeat_count -= 1; self.repeat_count -= 1;
} }

View file

@ -31,7 +31,7 @@ impl<'b> MultifileReader<'b> {
any_err: false, any_err: false,
}; };
mf.next_file(); mf.next_file();
return mf; mf
} }
fn next_file(&mut self) { fn next_file(&mut self) {
@ -39,18 +39,18 @@ impl<'b> MultifileReader<'b> {
loop { loop {
if self.ni.len() == 0 { if self.ni.len() == 0 {
self.curr_file = None; self.curr_file = None;
return; break;
} }
match self.ni.remove(0) { match self.ni.remove(0) {
InputSource::Stdin => { InputSource::Stdin => {
self.curr_file = Some(Box::new(BufReader::new(std::io::stdin()))); self.curr_file = Some(Box::new(BufReader::new(std::io::stdin())));
return; break;
} }
InputSource::FileName(fname) => { InputSource::FileName(fname) => {
match File::open(fname) { match File::open(fname) {
Ok(f) => { Ok(f) => {
self.curr_file = Some(Box::new(BufReader::new(f))); self.curr_file = Some(Box::new(BufReader::new(f)));
return; break;
} }
Err(e) => { Err(e) => {
// If any file can't be opened, // If any file can't be opened,
@ -66,7 +66,7 @@ impl<'b> MultifileReader<'b> {
} }
InputSource::Stream(s) => { InputSource::Stream(s) => {
self.curr_file = Some(s); self.curr_file = Some(s);
return; break;
} }
} }
} }
@ -74,7 +74,6 @@ impl<'b> MultifileReader<'b> {
} }
impl<'b> io::Read for MultifileReader<'b> { impl<'b> io::Read for MultifileReader<'b> {
// Fill buf with bytes read from the list of files // Fill buf with bytes read from the list of files
// Returns Ok(<number of bytes read>) // Returns Ok(<number of bytes read>)
// Handles io errors itself, thus always returns OK // Handles io errors itself, thus always returns OK
@ -192,5 +191,4 @@ mod tests {
assert_eq!(sut.read(v.as_mut()).unwrap(), 3); assert_eq!(sut.read(v.as_mut()).unwrap(), 3);
assert_eq!(v, [0x42, 0x43, 0x44, 0x64, 0x41]); // last two bytes are not overwritten assert_eq!(v, [0x42, 0x43, 0x44, 0x64, 0x41]); // last two bytes are not overwritten
} }
} }

View file

@ -187,7 +187,7 @@ impl OdOptions {
Ok(CommandLineInputs::FileAndOffset((f, s, l))) => { Ok(CommandLineInputs::FileAndOffset((f, s, l))) => {
skip_bytes = s; skip_bytes = s;
label = l; label = l;
vec!{f} vec![f]
}, },
Err(e) => { Err(e) => {
return Err(format!("Invalid inputs: {}", e)); return Err(format!("Invalid inputs: {}", e));
@ -346,8 +346,7 @@ fn odfunc<I>(input_offset: &mut InputOffset, input_decoder: &mut InputDecoder<I>
duplicate_line = true; duplicate_line = true;
println!("*"); println!("*");
} }
} } else {
else {
duplicate_line = false; duplicate_line = false;
if length == line_bytes { if length == line_bytes {
// save a copy of the input unless it is the last line // save a copy of the input unless it is the last line
@ -416,8 +415,7 @@ fn print_bytes(prefix: &str, input_decoder: &MemoryDecoder, output_info: &Output
print!("{}", prefix); // print offset print!("{}", prefix); // print offset
// if printing in multiple formats offset is printed only once // if printing in multiple formats offset is printed only once
first = false; first = false;
} } else {
else {
// this takes the space of the file offset on subsequent // this takes the space of the file offset on subsequent
// lines of multi-format rasters. // lines of multi-format rasters.
print!("{:>width$}", "", width=prefix.chars().count()); print!("{:>width$}", "", width=prefix.chars().count());

View file

@ -49,7 +49,6 @@ impl OutputInfo {
/// Creates a new `OutputInfo` based on the parameters /// Creates a new `OutputInfo` based on the parameters
pub fn new(line_bytes: usize, formats: &[ParsedFormatterItemInfo], output_duplicates: bool) -> OutputInfo { pub fn new(line_bytes: usize, formats: &[ParsedFormatterItemInfo], output_duplicates: bool) -> OutputInfo {
let byte_size_block = formats.iter().fold(1, |max, next| cmp::max(max, next.formatter_item_info.byte_size)); let byte_size_block = formats.iter().fold(1, |max, next| cmp::max(max, next.formatter_item_info.byte_size));
let print_width_block = formats let print_width_block = formats
.iter() .iter()
@ -129,7 +128,6 @@ impl OutputInfo {
/// Increase MAX_BYTES_PER_UNIT to allow larger types. /// Increase MAX_BYTES_PER_UNIT to allow larger types.
fn calculate_alignment(sf: &TypeSizeInfo, byte_size_block: usize, fn calculate_alignment(sf: &TypeSizeInfo, byte_size_block: usize,
print_width_block: usize) -> [usize; MAX_BYTES_PER_UNIT] { print_width_block: usize) -> [usize; MAX_BYTES_PER_UNIT] {
if byte_size_block > MAX_BYTES_PER_UNIT { if byte_size_block > MAX_BYTES_PER_UNIT {
panic!("{}-bits types are unsupported. Current max={}-bits.", panic!("{}-bits types are unsupported. Current max={}-bits.",
8 * byte_size_block, 8 * byte_size_block,
@ -181,7 +179,6 @@ impl TypeSizeInfo for TypeInfo {
#[test] #[test]
fn test_calculate_alignment() { fn test_calculate_alignment() {
// For this example `byte_size_block` is 8 and 'print_width_block' is 23: // For this example `byte_size_block` is 8 and 'print_width_block' is 23:
// 1777777777777777777777 1777777777777777777777 // 1777777777777777777777 1777777777777777777777
// 4294967295 4294967295 4294967295 4294967295 // 4294967295 4294967295 4294967295 4294967295

View file

@ -115,8 +115,7 @@ pub fn parse_format_flags(args: &Vec<String>) -> Result<Vec<ParsedFormatterItemI
Err(e) => return Err(e), Err(e) => return Err(e),
} }
expect_type_string = false; expect_type_string = false;
} } else if arg.starts_with("--") {
else if arg.starts_with("--") {
if arg.len() == 2 { if arg.len() == 2 {
break; break;
} }
@ -130,29 +129,23 @@ pub fn parse_format_flags(args: &Vec<String>) -> Result<Vec<ParsedFormatterItemI
if arg == "--format" { if arg == "--format" {
expect_type_string = true; expect_type_string = true;
} }
} } else if arg.starts_with("-") {
else if arg.starts_with("-") {
let mut flags = arg.chars().skip(1); let mut flags = arg.chars().skip(1);
let mut format_spec = String::new(); let mut format_spec = String::new();
while let Some(c) = flags.next() { while let Some(c) = flags.next() {
if expect_type_string { if expect_type_string {
format_spec.push(c); format_spec.push(c);
} } else if od_argument_with_option(c) {
else if od_argument_with_option(c) {
break; break;
} } else if c == 't' {
else if c=='t' {
expect_type_string = true; expect_type_string = true;
} } else {
else { // not every option is a format
match od_argument_traditional_format(c) { if let Some(r) = od_argument_traditional_format(c) {
None => {} // not every option is a format
Some(r) => {
formats.push(ParsedFormatterItemInfo::new(r, false)) formats.push(ParsedFormatterItemInfo::new(r, false))
} }
} }
} }
}
if !format_spec.is_empty() { if !format_spec.is_empty() {
match parse_type_string(&format_spec) { match parse_type_string(&format_spec) {
Ok(v) => formats.extend(v.into_iter()), Ok(v) => formats.extend(v.into_iter()),
@ -217,7 +210,6 @@ fn format_type_category(t: FormatType) -> FormatTypeCategory {
} }
fn is_format_size_char(ch: Option<char>, format_type: FormatTypeCategory, byte_size: &mut u8) -> bool { fn is_format_size_char(ch: Option<char>, format_type: FormatTypeCategory, byte_size: &mut u8) -> bool {
match (format_type, ch) { match (format_type, ch) {
(FormatTypeCategory::Integer, Some('C')) => { (FormatTypeCategory::Integer, Some('C')) => {
*byte_size = 1; *byte_size = 1;
@ -294,8 +286,7 @@ fn parse_type_string(params: &String) -> Result<Vec<ParsedFormatterItemInfo>, St
let mut show_ascii_dump = false; let mut show_ascii_dump = false;
if is_format_size_char(ch, type_cat, &mut byte_size) { if is_format_size_char(ch, type_cat, &mut byte_size) {
ch = chars.next(); ch = chars.next();
} } else {
else {
let mut decimal_size = String::new(); let mut decimal_size = String::new();
while is_format_size_decimal(ch, type_cat, &mut decimal_size) { while is_format_size_decimal(ch, type_cat, &mut decimal_size) {
ch = chars.next(); ch = chars.next();

View file

@ -40,7 +40,6 @@ pub enum CommandLineInputs {
/// '-' is used as filename if stdin is meant. This is also returned if /// '-' is used as filename if stdin is meant. This is also returned if
/// there is no input, as stdin is the default input. /// there is no input, as stdin is the default input.
pub fn parse_inputs(matches: &CommandLineOpts) -> Result<CommandLineInputs, String> { pub fn parse_inputs(matches: &CommandLineOpts) -> Result<CommandLineInputs, String> {
let mut input_strings: Vec<String> = matches.inputs(); let mut input_strings: Vec<String> = matches.inputs();
if matches.opts_present(&["traditional"]) { if matches.opts_present(&["traditional"]) {
@ -84,7 +83,7 @@ pub fn parse_inputs(matches: &CommandLineOpts) -> Result<CommandLineInputs, Stri
pub fn parse_inputs_traditional(input_strings: Vec<String>) -> Result<CommandLineInputs, String> { pub fn parse_inputs_traditional(input_strings: Vec<String>) -> Result<CommandLineInputs, String> {
match input_strings.len() { match input_strings.len() {
0 => { 0 => {
Ok(CommandLineInputs::FileNames(vec!{"-".to_string()})) Ok(CommandLineInputs::FileNames(vec!["-".to_string()]))
} }
1 => { 1 => {
let offset0 = parse_offset_operand(&input_strings[0]); let offset0 = parse_offset_operand(&input_strings[0]);
@ -131,8 +130,7 @@ pub fn parse_offset_operand(s: &String) -> Result<usize, &'static str> {
if s[start..len].starts_with("0x") || s[start..len].starts_with("0X") { if s[start..len].starts_with("0x") || s[start..len].starts_with("0X") {
start += 2; start += 2;
radix = 16; radix = 16;
} } else {
else {
if s[start..len].ends_with("b") { if s[start..len].ends_with("b") {
len -= 1; len -= 1;
multiply = 512; multiply = 512;
@ -189,31 +187,30 @@ mod tests {
#[test] #[test]
fn test_parse_inputs_normal() { fn test_parse_inputs_normal() {
assert_eq!(CommandLineInputs::FileNames(vec!["-".to_string()]),
assert_eq!(CommandLineInputs::FileNames(vec!{"-".to_string()}),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{}, vec![],
vec!{})).unwrap()); vec![])).unwrap());
assert_eq!(CommandLineInputs::FileNames(vec!{"-".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["-".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"-"}, vec!["-"],
vec!{})).unwrap()); vec![])).unwrap());
assert_eq!(CommandLineInputs::FileNames(vec!{"file1".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["file1".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"file1"}, vec!["file1"],
vec!{})).unwrap()); vec![])).unwrap());
assert_eq!(CommandLineInputs::FileNames(vec!{"file1".to_string(), "file2".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["file1".to_string(), "file2".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"file1", "file2"}, vec!["file1", "file2"],
vec!{})).unwrap()); vec![])).unwrap());
assert_eq!(CommandLineInputs::FileNames(vec!{"-".to_string(), "file1".to_string(), "file2".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["-".to_string(), "file1".to_string(), "file2".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"-", "file1", "file2"}, vec!["-", "file1", "file2"],
vec!{})).unwrap()); vec![])).unwrap());
} }
#[test] #[test]
@ -221,113 +218,112 @@ mod tests {
// offset is found without filename, so stdin will be used. // offset is found without filename, so stdin will be used.
assert_eq!(CommandLineInputs::FileAndOffset(("-".to_string(), 8, None)), assert_eq!(CommandLineInputs::FileAndOffset(("-".to_string(), 8, None)),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"+10"}, vec!["+10"],
vec!{})).unwrap()); vec![])).unwrap());
// offset must start with "+" if no input is specified. // offset must start with "+" if no input is specified.
assert_eq!(CommandLineInputs::FileNames(vec!{"10".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["10".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"10"}, vec!["10"],
vec!{""})).unwrap()); vec![""])).unwrap());
// offset is not valid, so it is considered a filename. // offset is not valid, so it is considered a filename.
assert_eq!(CommandLineInputs::FileNames(vec!{"+10a".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["+10a".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"+10a"}, vec!["+10a"],
vec!{""})).unwrap()); vec![""])).unwrap());
// if -j is included in the commandline, there cannot be an offset. // if -j is included in the commandline, there cannot be an offset.
assert_eq!(CommandLineInputs::FileNames(vec!{"+10".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["+10".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"+10"}, vec!["+10"],
vec!{"j"})).unwrap()); vec!["j"])).unwrap());
// if -v is included in the commandline, there cannot be an offset. // if -v is included in the commandline, there cannot be an offset.
assert_eq!(CommandLineInputs::FileNames(vec!{"+10".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["+10".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"+10"}, vec!["+10"],
vec!{"o", "v"})).unwrap()); vec!["o", "v"])).unwrap());
assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)), assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"file1", "+10"}, vec!["file1", "+10"],
vec!{})).unwrap()); vec![])).unwrap());
// offset does not need to start with "+" if a filename is included. // offset does not need to start with "+" if a filename is included.
assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)), assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"file1", "10"}, vec!["file1", "10"],
vec!{})).unwrap()); vec![])).unwrap());
assert_eq!(CommandLineInputs::FileNames(vec!{"file1".to_string(), "+10a".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["file1".to_string(), "+10a".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"file1", "+10a"}, vec!["file1", "+10a"],
vec!{""})).unwrap()); vec![""])).unwrap());
assert_eq!(CommandLineInputs::FileNames(vec!{"file1".to_string(), "+10".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["file1".to_string(), "+10".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"file1", "+10"}, vec!["file1", "+10"],
vec!{"j"})).unwrap()); vec!["j"])).unwrap());
// offset must be last on the commandline // offset must be last on the commandline
assert_eq!(CommandLineInputs::FileNames(vec!{"+10".to_string(), "file1".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["+10".to_string(), "file1".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"+10", "file1"}, vec!["+10", "file1"],
vec!{""})).unwrap()); vec![""])).unwrap());
} }
#[test] #[test]
fn test_parse_inputs_traditional() { fn test_parse_inputs_traditional() {
// it should not return FileAndOffset to signal no offset was entered on the commandline. // it should not return FileAndOffset to signal no offset was entered on the commandline.
assert_eq!(CommandLineInputs::FileNames(vec!{"-".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["-".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{}, vec![],
vec!{"traditional"})).unwrap()); vec!["traditional"])).unwrap());
assert_eq!(CommandLineInputs::FileNames(vec!{"file1".to_string()}), assert_eq!(CommandLineInputs::FileNames(vec!["file1".to_string()]),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"file1"}, vec!["file1"],
vec!{"traditional"})).unwrap()); vec!["traditional"])).unwrap());
// offset does not need to start with a + // offset does not need to start with a +
assert_eq!(CommandLineInputs::FileAndOffset(("-".to_string(), 8, None)), assert_eq!(CommandLineInputs::FileAndOffset(("-".to_string(), 8, None)),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"10"}, vec!["10"],
vec!{"traditional"})).unwrap()); vec!["traditional"])).unwrap());
// valid offset and valid label // valid offset and valid label
assert_eq!(CommandLineInputs::FileAndOffset(("-".to_string(), 8, Some(8))), assert_eq!(CommandLineInputs::FileAndOffset(("-".to_string(), 8, Some(8))),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"10", "10"}, vec!["10", "10"],
vec!{"traditional"})).unwrap()); vec!["traditional"])).unwrap());
assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)), assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"file1", "10"}, vec!["file1", "10"],
vec!{"traditional"})).unwrap()); vec!["traditional"])).unwrap());
// only one file is allowed, it must be the first // only one file is allowed, it must be the first
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"10", "file1"}, vec!["10", "file1"],
vec!{"traditional"})).unwrap_err(); vec!["traditional"])).unwrap_err();
assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, Some(8))), assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, Some(8))),
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"file1", "10", "10"}, vec!["file1", "10", "10"],
vec!{"traditional"})).unwrap()); vec!["traditional"])).unwrap());
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"10", "file1", "10"}, vec!["10", "file1", "10"],
vec!{"traditional"})).unwrap_err(); vec!["traditional"])).unwrap_err();
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"10", "10", "file1"}, vec!["10", "10", "file1"],
vec!{"traditional"})).unwrap_err(); vec!["traditional"])).unwrap_err();
parse_inputs(&MockOptions::new( parse_inputs(&MockOptions::new(
vec!{"10", "10", "10", "10"}, vec!["10", "10", "10", "10"],
vec!{"traditional"})).unwrap_err(); vec!["traditional"])).unwrap_err();
} }
fn parse_offset_operand_str(s: &str) -> Result<usize, &'static str> { fn parse_offset_operand_str(s: &str) -> Result<usize, &'static str> {
@ -363,5 +359,4 @@ mod tests {
assert_eq!(5120, parse_offset_operand_str("+10.b").unwrap()); // b suffix = *512 assert_eq!(5120, parse_offset_operand_str("+10.b").unwrap()); // b suffix = *512
assert_eq!(267, parse_offset_operand_str("0x10b").unwrap()); // hex assert_eq!(267, parse_offset_operand_str("0x10b").unwrap()); // hex
} }
} }

View file

@ -8,8 +8,7 @@ pub fn parse_number_of_bytes(s: &String) -> Result<usize, &'static str> {
if s.starts_with("0x") || s.starts_with("0X") { if s.starts_with("0x") || s.starts_with("0X") {
start = 2; start = 2;
radix = 16; radix = 16;
} } else if s.starts_with("0") {
else if s.starts_with("0") {
radix = 8; radix = 8;
} }

View file

@ -91,8 +91,7 @@ impl<R: Read> PeekRead for PeekReader<R> {
let unused = out.len() - bytes_in_buffer; let unused = out.len() - bytes_in_buffer;
if peek_size <= unused { if peek_size <= unused {
Ok((bytes_in_buffer, 0)) Ok((bytes_in_buffer, 0))
} } else {
else {
let actual_peek_size = peek_size - unused; let actual_peek_size = peek_size - unused;
let real_size = bytes_in_buffer - actual_peek_size; let real_size = bytes_in_buffer - actual_peek_size;
self.write_to_tempbuffer(&out[real_size..bytes_in_buffer]); self.write_to_tempbuffer(&out[real_size..bytes_in_buffer]);

View file

@ -68,33 +68,28 @@ fn format_item_c(bytes: &[u8]) -> String {
Some(s) => format!("{:>4}", s), Some(s) => format!("{:>4}", s),
None => format!("{:>4}", b), None => format!("{:>4}", b),
} }
} } else if (b & 0xc0) == 0x80 {
else if (b & 0xc0) == 0x80 {
// second or subsequent octet of an utf-8 sequence // second or subsequent octet of an utf-8 sequence
String::from(" **") String::from(" **")
} } else if ((b & 0xe0) == 0xc0) && (bytes.len() >= 2) {
else if ((b & 0xe0) == 0xc0) && (bytes.len() >= 2) {
// start of a 2 octet utf-8 sequence // start of a 2 octet utf-8 sequence
match from_utf8(&bytes[0..2]) { match from_utf8(&bytes[0..2]) {
Ok(s) => { format!("{:>4}", s) }, Ok(s) => { format!("{:>4}", s) },
Err(_) => { format!(" {:03o}", b) }, Err(_) => { format!(" {:03o}", b) },
} }
} } else if ((b & 0xf0) == 0xe0) && (bytes.len() >= 3) {
else if ((b & 0xf0) == 0xe0) && (bytes.len() >= 3) {
// start of a 3 octet utf-8 sequence // start of a 3 octet utf-8 sequence
match from_utf8(&bytes[0..3]) { match from_utf8(&bytes[0..3]) {
Ok(s) => { format!("{:>4}", s) }, Ok(s) => { format!("{:>4}", s) },
Err(_) => { format!(" {:03o}", b) }, Err(_) => { format!(" {:03o}", b) },
} }
} } else if ((b & 0xf8) == 0xf0) && (bytes.len() >= 4) {
else if ((b & 0xf8) == 0xf0) && (bytes.len() >= 4) {
// start of a 4 octet utf-8 sequence // start of a 4 octet utf-8 sequence
match from_utf8(&bytes[0..4]) { match from_utf8(&bytes[0..4]) {
Ok(s) => { format!("{:>4}", s) }, Ok(s) => { format!("{:>4}", s) },
Err(_) => { format!(" {:03o}", b) }, Err(_) => { format!(" {:03o}", b) },
} }
} } else {
else {
// invalid utf-8 // invalid utf-8
format!(" {:03o}", b) format!(" {:03o}", b)
} }
@ -107,8 +102,7 @@ pub fn format_ascii_dump(bytes: &[u8]) -> String {
for c in bytes.iter() { for c in bytes.iter() {
if *c >= 0x20 && *c <= 0x7e { if *c >= 0x20 && *c <= 0x7e {
result.push_str(C_CHRS[*c as usize]); result.push_str(C_CHRS[*c as usize]);
} } else {
else {
result.push('.'); result.push('.');
} }
} }

View file

@ -47,8 +47,7 @@ fn format_flo32(f: f32) -> String {
if f.classify() == FpCategory::Subnormal { if f.classify() == FpCategory::Subnormal {
// subnormal numbers will be normal as f64, so will print with a wrong precision // subnormal numbers will be normal as f64, so will print with a wrong precision
format!("{:width$e}", f, width = width) // subnormal numbers format!("{:width$e}", f, width = width) // subnormal numbers
} } else {
else {
format_float(f as f64, width, precision) format_float(f as f64, width, precision)
} }
} }
@ -58,7 +57,6 @@ fn format_flo64(f: f64) -> String {
} }
fn format_float(f: f64, width: usize, precision: usize) -> String { fn format_float(f: f64, width: usize, precision: usize) -> String {
if !f.is_normal() { if !f.is_normal() {
if f == -0.0 && f.is_sign_negative() { return format!("{:>width$}", "-0", width = width) } 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) } if f == 0.0 || !f.is_finite() { return format!("{:width$}", f, width = width) }
@ -77,13 +75,11 @@ fn format_float(f: f64, width: usize, precision: usize) -> String {
format!("{:width$.dec$}", f, format!("{:width$.dec$}", f,
width = width, width = width,
dec = (precision-1) - l as usize) dec = (precision-1) - l as usize)
} } else if l == -1 {
else if l == -1 {
format!("{:width$.dec$}", f, format!("{:width$.dec$}", f,
width = width, width = width,
dec = precision) dec = precision)
} } else {
else {
format!("{:width$.dec$e}", f, format!("{:width$.dec$e}", f,
width = width, width = width,
dec = precision - 1) dec = precision - 1)

View file

@ -89,20 +89,17 @@ fn test_no_file() {
// Test that od reads from stdin instead of a file // Test that od reads from stdin instead of a file
#[test] #[test]
fn test_from_stdin() { fn test_from_stdin() {
let input = "abcdefghijklmnopqrstuvwxyz\n"; let input = "abcdefghijklmnopqrstuvwxyz\n";
let result = new_ucmd!().arg("--endian=little").run_piped_stdin(input.as_bytes()); let result = new_ucmd!().arg("--endian=little").run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result); assert_empty_stderr!(result);
assert!(result.success); assert!(result.success);
assert_eq!(result.stdout, unindent(ALPHA_OUT)); assert_eq!(result.stdout, unindent(ALPHA_OUT));
} }
// Test that od reads from stdin and also from files // Test that od reads from stdin and also from files
#[test] #[test]
fn test_from_mixed() { fn test_from_mixed() {
let temp = env::temp_dir(); let temp = env::temp_dir();
let tmpdir = Path::new(&temp); let tmpdir = Path::new(&temp);
let file1 = tmpdir.join("test-1"); let file1 = tmpdir.join("test-1");
@ -122,12 +119,10 @@ fn test_from_mixed() {
assert_empty_stderr!(result); assert_empty_stderr!(result);
assert!(result.success); assert!(result.success);
assert_eq!(result.stdout, unindent(ALPHA_OUT)); assert_eq!(result.stdout, unindent(ALPHA_OUT));
} }
#[test] #[test]
fn test_multiple_formats() { fn test_multiple_formats() {
let input = "abcdefghijklmnopqrstuvwxyz\n"; let input = "abcdefghijklmnopqrstuvwxyz\n";
let result = new_ucmd!().arg("-c").arg("-b").run_piped_stdin(input.as_bytes()); let result = new_ucmd!().arg("-c").arg("-b").run_piped_stdin(input.as_bytes());
@ -140,12 +135,10 @@ fn test_multiple_formats() {
161 162 163 164 165 166 167 170 171 172 012 161 162 163 164 165 166 167 170 171 172 012
0000033 0000033
")); "));
} }
#[test] #[test]
fn test_dec() { fn test_dec() {
let input = [ let input = [
0u8, 0u8, 0u8, 0u8,
1u8, 0u8, 1u8, 0u8,
@ -163,12 +156,10 @@ fn test_dec() {
assert_empty_stderr!(result); assert_empty_stderr!(result);
assert!(result.success); assert!(result.success);
assert_eq!(result.stdout, expected_output); assert_eq!(result.stdout, expected_output);
} }
#[test] #[test]
fn test_hex16(){ fn test_hex16(){
let input: [u8; 9] = [ let input: [u8; 9] = [
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xff]; 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xff];
let expected_output = unindent(" let expected_output = unindent("
@ -184,7 +175,6 @@ fn test_hex16(){
#[test] #[test]
fn test_hex32(){ fn test_hex32(){
let input: [u8; 9] = [ let input: [u8; 9] = [
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xff]; 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xff];
let expected_output = unindent(" let expected_output = unindent("
@ -200,7 +190,6 @@ fn test_hex32(){
#[test] #[test]
fn test_f16(){ fn test_f16(){
let input: [u8; 14] = [ let input: [u8; 14] = [
0x00, 0x3c, // 0x3C00 1.0 0x00, 0x3c, // 0x3C00 1.0
0x00, 0x00, // 0x0000 0.0 0x00, 0x00, // 0x0000 0.0
@ -223,7 +212,6 @@ fn test_f16(){
#[test] #[test]
fn test_f32(){ fn test_f32(){
let input: [u8; 28] = [ let input: [u8; 28] = [
0x52, 0x06, 0x9e, 0xbf, // 0xbf9e0652 -1.2345679 0x52, 0x06, 0x9e, 0xbf, // 0xbf9e0652 -1.2345679
0x4e, 0x61, 0x3c, 0x4b, // 0x4b3c614e 12345678 0x4e, 0x61, 0x3c, 0x4b, // 0x4b3c614e 12345678
@ -246,7 +234,6 @@ fn test_f32(){
#[test] #[test]
fn test_f64(){ fn test_f64(){
let input: [u8; 40] = [ let input: [u8; 40] = [
0x27, 0x6b, 0x0a, 0x2f, 0x2a, 0xee, 0x45, 0x43, // 0x4345EE2A2F0A6B27 12345678912345678 0x27, 0x6b, 0x0a, 0x2f, 0x2a, 0xee, 0x45, 0x43, // 0x4345EE2A2F0A6B27 12345678912345678
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0000000000000000 0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 0x0000000000000000 0
@ -268,7 +255,6 @@ fn test_f64(){
#[test] #[test]
fn test_multibyte() { fn test_multibyte() {
let result = new_ucmd!().arg("-c").arg("-w12").run_piped_stdin("Universität Tübingen \u{1B000}".as_bytes()); let result = new_ucmd!().arg("-c").arg("-w12").run_piped_stdin("Universität Tübingen \u{1B000}".as_bytes());
assert_empty_stderr!(result); assert_empty_stderr!(result);
@ -283,7 +269,6 @@ fn test_multibyte() {
#[test] #[test]
fn test_width(){ fn test_width(){
let input: [u8; 8] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]; let input: [u8; 8] = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
let expected_output = unindent(" let expected_output = unindent("
0000000 000000 000000 0000000 000000 000000
@ -300,7 +285,6 @@ fn test_width(){
#[test] #[test]
fn test_invalid_width(){ fn test_invalid_width(){
let input: [u8; 4] = [0x00, 0x00, 0x00, 0x00]; let input: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
let expected_output = unindent(" let expected_output = unindent("
0000000 000000 0000000 000000
@ -317,7 +301,6 @@ fn test_invalid_width(){
#[test] #[test]
fn test_zero_width(){ fn test_zero_width(){
let input: [u8; 4] = [0x00, 0x00, 0x00, 0x00]; let input: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
let expected_output = unindent(" let expected_output = unindent("
0000000 000000 0000000 000000
@ -334,7 +317,6 @@ fn test_zero_width(){
#[test] #[test]
fn test_width_without_value(){ fn test_width_without_value(){
let input: [u8; 40] = [0 ; 40]; let input: [u8; 40] = [0 ; 40];
let expected_output = unindent(" let expected_output = unindent("
0000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 0000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000
@ -351,7 +333,6 @@ fn test_width_without_value(){
#[test] #[test]
fn test_suppress_duplicates(){ fn test_suppress_duplicates(){
let input: [u8; 41] = [ let input: [u8; 41] = [
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@ -387,7 +368,6 @@ fn test_suppress_duplicates(){
#[test] #[test]
fn test_big_endian() { fn test_big_endian() {
let input: [u8; 8] = [ let input: [u8; 8] = [
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];// 0xc000000000000000 -2 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];// 0xc000000000000000 -2
@ -409,7 +389,6 @@ fn test_big_endian() {
#[test] #[test]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn test_alignment_Xxa() { fn test_alignment_Xxa() {
let input: [u8; 8] = [ let input: [u8; 8] = [
0x0A, 0x0D, 0x65, 0x66, 0x67, 0x00, 0x9e, 0x9f]; 0x0A, 0x0D, 0x65, 0x66, 0x67, 0x00, 0x9e, 0x9f];
@ -431,7 +410,6 @@ fn test_alignment_Xxa() {
#[test] #[test]
#[allow(non_snake_case)] #[allow(non_snake_case)]
fn test_alignment_Fx() { fn test_alignment_Fx() {
let input: [u8; 8] = [ let input: [u8; 8] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0];// 0xc000000000000000 -2 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0];// 0xc000000000000000 -2
@ -451,7 +429,6 @@ fn test_alignment_Fx() {
#[test] #[test]
fn test_maxuint(){ fn test_maxuint(){
let input = [0xFFu8 ; 8]; let input = [0xFFu8 ; 8];
let expected_output = unindent(" let expected_output = unindent("
0000000 1777777777777777777777 0000000 1777777777777777777777
@ -474,7 +451,6 @@ fn test_maxuint(){
#[test] #[test]
fn test_hex_offset(){ fn test_hex_offset(){
let input = [0u8 ; 0x1F]; let input = [0u8 ; 0x1F];
let expected_output = unindent(" let expected_output = unindent("
000000 00000000 00000000 00000000 00000000 000000 00000000 00000000 00000000 00000000
@ -493,7 +469,6 @@ fn test_hex_offset(){
#[test] #[test]
fn test_dec_offset(){ fn test_dec_offset(){
let input = [0u8 ; 19]; let input = [0u8 ; 19];
let expected_output = unindent(" let expected_output = unindent("
0000000 00000000 00000000 00000000 00000000 0000000 00000000 00000000 00000000 00000000
@ -512,7 +487,6 @@ fn test_dec_offset(){
#[test] #[test]
fn test_no_offset(){ fn test_no_offset(){
let input = [0u8 ; 31]; let input = [0u8 ; 31];
const LINE: &'static str = " 00000000 00000000 00000000 00000000\n"; const LINE: &'static str = " 00000000 00000000 00000000 00000000\n";
let expected_output = [LINE, LINE, LINE, LINE].join(""); let expected_output = [LINE, LINE, LINE, LINE].join("");
@ -526,17 +500,13 @@ fn test_no_offset(){
#[test] #[test]
fn test_invalid_offset(){ fn test_invalid_offset(){
let result = new_ucmd!().arg("-Ab").run();
let input = [0u8 ; 4];
let result = new_ucmd!().arg("-Ab").run_piped_stdin(&input[..]);
assert!(!result.success); assert!(!result.success);
} }
#[test] #[test]
fn test_skip_bytes(){ fn test_skip_bytes(){
let input = "abcdefghijklmnopq"; let input = "abcdefghijklmnopq";
let result = new_ucmd!().arg("-c").arg("--skip-bytes=5").run_piped_stdin(input.as_bytes()); let result = new_ucmd!().arg("-c").arg("--skip-bytes=5").run_piped_stdin(input.as_bytes());
@ -550,7 +520,6 @@ fn test_skip_bytes(){
#[test] #[test]
fn test_skip_bytes_error(){ fn test_skip_bytes_error(){
let input = "12345"; let input = "12345";
let result = new_ucmd!().arg("--skip-bytes=10").run_piped_stdin(input.as_bytes()); let result = new_ucmd!().arg("--skip-bytes=10").run_piped_stdin(input.as_bytes());
@ -559,7 +528,6 @@ fn test_skip_bytes_error(){
#[test] #[test]
fn test_read_bytes(){ fn test_read_bytes(){
let input = "abcdefghijklmnopqrstuvwxyz\n12345678"; let input = "abcdefghijklmnopqrstuvwxyz\n12345678";
let result = new_ucmd!().arg("--endian=little").arg("--read-bytes=27").run_piped_stdin(input.as_bytes()); let result = new_ucmd!().arg("--endian=little").arg("--read-bytes=27").run_piped_stdin(input.as_bytes());
@ -570,7 +538,6 @@ fn test_read_bytes(){
#[test] #[test]
fn test_ascii_dump(){ fn test_ascii_dump(){
let input: [u8; 22] = [ let input: [u8; 22] = [
0x00, 0x01, 0x0a, 0x0d, 0x10, 0x1f, 0x20, 0x61, 0x62, 0x63, 0x7d, 0x00, 0x01, 0x0a, 0x0d, 0x10, 0x1f, 0x20, 0x61, 0x62, 0x63, 0x7d,
0x7e, 0x7f, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff]; 0x7e, 0x7f, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff];
@ -607,7 +574,6 @@ fn test_filename_parsing(){
#[test] #[test]
fn test_stdin_offset(){ fn test_stdin_offset(){
let input = "abcdefghijklmnopq"; let input = "abcdefghijklmnopq";
let result = new_ucmd!().arg("-c").arg("+5").run_piped_stdin(input.as_bytes()); let result = new_ucmd!().arg("-c").arg("+5").run_piped_stdin(input.as_bytes());
@ -621,7 +587,6 @@ fn test_stdin_offset(){
#[test] #[test]
fn test_file_offset(){ fn test_file_offset(){
let result = new_ucmd!().arg("-c").arg("--").arg("-f").arg("10").run(); let result = new_ucmd!().arg("-c").arg("--").arg("-f").arg("10").run();
assert_empty_stderr!(result); assert_empty_stderr!(result);
@ -678,8 +643,7 @@ fn test_traditional_with_skip_bytes_non_override(){
#[test] #[test]
fn test_traditional_error(){ fn test_traditional_error(){
// file "0" exists - don't fail on that, but --traditional only accepts a single input // file "0" exists - don't fail on that, but --traditional only accepts a single input
let input = "abcdefghijklmnopq"; let result = new_ucmd!().arg("--traditional").arg("0").arg("0").arg("0").arg("0").run();
let result = new_ucmd!().arg("--traditional").arg("0").arg("0").arg("0").arg("0").run_piped_stdin(input.as_bytes());
assert!(!result.success); assert!(!result.success);
} }