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_UNICODE_SUPPORT=y
CONFIG_DESKTOP=y
CONFIG_LONG_OPTS=y

View file

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

View file

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

View file

@ -26,12 +26,11 @@ pub struct InputDecoder<'a, I> where I: 'a {
}
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.
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);
unsafe { bytes.set_len(normal_length+peek_length); } // fast but uninitialized
let mut bytes: Vec<u8> = Vec::with_capacity(normal_length + peek_length);
unsafe { bytes.set_len(normal_length + peek_length); } // fast but uninitialized
InputDecoder {
input: input,
@ -45,7 +44,7 @@ impl<'a, I> InputDecoder<'a, I> {
}
impl<'a, I> InputDecoder<'a, I> where I : PeekRead {
impl<'a, I> InputDecoder<'a, I> where I: PeekRead {
/// calls `peek_read` on the internal stream to (re)fill the buffer. Returns a
/// MemoryDecoder providing access to the result or returns an i/o error.
pub fn peek_read(&mut self) -> io::Result<MemoryDecoder> {
@ -66,7 +65,7 @@ impl<'a, I> InputDecoder<'a, I> where I : PeekRead {
}
}
impl<'a, I> HasError for InputDecoder<'a, I> where I : HasError {
impl<'a, I> HasError for InputDecoder<'a, I> where I: HasError {
/// calls has_error on the internal stream.
fn has_error(&self) -> bool {
self.input.has_error()
@ -112,7 +111,7 @@ impl<'a> MemoryDecoder<'a> {
/// Returns a slice to the internal buffer including the peek data starting at `start`.
pub fn get_full_buffer(&self, start: usize) -> &[u8] {
&self.data[start..self.used_normal_length+self.used_peek_length]
&self.data[start..self.used_normal_length + self.used_peek_length]
}
/// Returns a u8/u16/u32/u64 from the internal buffer at position `start`.
@ -147,8 +146,8 @@ mod tests {
#[test]
fn smoke_test() {
let data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0xff, 0xff];
let mut input=PeekReader::new(Cursor::new(&data));
let mut sut=InputDecoder::new(&mut input, 8, 2, ByteOrder::Little);
let mut input = PeekReader::new(Cursor::new(&data));
let mut sut = InputDecoder::new(&mut input, 8, 2, ByteOrder::Little);
match sut.peek_read() {
Ok(mut mem) => {
@ -165,7 +164,7 @@ mod tests {
let mut copy: Vec<u8> = Vec::new();
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);
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> {
if self.repeat_count == 0 {
return Ok(0)
}
else {
} else {
if self.repeat_count > 0 {
self.repeat_count -= 1;
}

View file

@ -6,7 +6,7 @@ use std::io::Write;
use std::vec::Vec;
pub enum InputSource<'a> {
FileName(&'a str ),
FileName(&'a str),
Stdin,
#[allow(dead_code)]
Stream(Box<io::Read>),
@ -31,7 +31,7 @@ impl<'b> MultifileReader<'b> {
any_err: false,
};
mf.next_file();
return mf;
mf
}
fn next_file(&mut self) {
@ -39,18 +39,18 @@ impl<'b> MultifileReader<'b> {
loop {
if self.ni.len() == 0 {
self.curr_file = None;
return;
break;
}
match self.ni.remove(0) {
InputSource::Stdin => {
self.curr_file = Some(Box::new(BufReader::new(std::io::stdin())));
return;
break;
}
InputSource::FileName(fname) => {
match File::open(fname) {
Ok(f) => {
self.curr_file = Some(Box::new(BufReader::new(f)));
return;
break;
}
Err(e) => {
// If any file can't be opened,
@ -66,7 +66,7 @@ impl<'b> MultifileReader<'b> {
}
InputSource::Stream(s) => {
self.curr_file = Some(s);
return;
break;
}
}
}
@ -74,7 +74,6 @@ impl<'b> MultifileReader<'b> {
}
impl<'b> io::Read for MultifileReader<'b> {
// Fill buf with bytes read from the list of files
// Returns Ok(<number of bytes read>)
// 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!(v, [0x42, 0x43, 0x44, 0x64, 0x41]); // last two bytes are not overwritten
}
}

View file

@ -147,8 +147,8 @@ fn create_getopts_options() -> getopts::Options {
struct OdOptions {
byte_order: ByteOrder,
skip_bytes : usize,
read_bytes : Option<usize>,
skip_bytes: usize,
read_bytes: Option<usize>,
label: Option<usize>,
input_strings: Vec<String>,
formats: Vec<ParsedFormatterItemInfo>,
@ -187,7 +187,7 @@ impl OdOptions {
Ok(CommandLineInputs::FileAndOffset((f, s, l))) => {
skip_bytes = s;
label = l;
vec!{f}
vec![f]
},
Err(e) => {
return Err(format!("Invalid inputs: {}", e));
@ -311,7 +311,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
/// Loops through the input line by line, calling print_bytes to take care of the output.
fn odfunc<I>(input_offset: &mut InputOffset, input_decoder: &mut InputDecoder<I>,
output_info: &OutputInfo) -> i32
where I : PeekRead+HasError {
where I: PeekRead + HasError {
let mut duplicate_line = false;
let mut previous_bytes: Vec<u8> = Vec::new();
let line_bytes = output_info.byte_size_line;
@ -321,7 +321,7 @@ fn odfunc<I>(input_offset: &mut InputOffset, input_decoder: &mut InputDecoder<I>
match input_decoder.peek_read() {
Ok(mut memory_decoder) => {
let length=memory_decoder.length();
let length = memory_decoder.length();
if length == 0 {
input_offset.print_final_offset();
@ -346,8 +346,7 @@ fn odfunc<I>(input_offset: &mut InputOffset, input_decoder: &mut InputDecoder<I>
duplicate_line = true;
println!("*");
}
}
else {
} else {
duplicate_line = false;
if length == line_bytes {
// save a copy of the input unless it is the last line
@ -409,15 +408,14 @@ fn print_bytes(prefix: &str, input_decoder: &MemoryDecoder, output_info: &Output
output_text.push_str(&format!("{:>width$} {}",
"",
format_ascii_dump(input_decoder.get_buffer(0)),
width=missing_spacing));
width = missing_spacing));
}
if first {
print!("{}", prefix); // print offset
// if printing in multiple formats offset is printed only once
first = false;
}
else {
} else {
// this takes the space of the file offset on subsequent
// lines of multi-format rasters.
print!("{:>width$}", "", width=prefix.chars().count());
@ -426,13 +424,13 @@ fn print_bytes(prefix: &str, input_decoder: &MemoryDecoder, output_info: &Output
}
}
/// returns a reader implementing `PeekRead+Read+HasError` providing the combined input
/// returns a reader implementing `PeekRead + Read + HasError` providing the combined input
///
/// `skip_bytes` is the number of bytes skipped from the input
/// `read_bytes` is an optinal limit to the number of bytes to read
fn open_input_peek_reader<'a>(input_strings: &'a Vec<String>, skip_bytes: usize,
read_bytes: Option<usize>) -> PeekReader<PartialReader<MultifileReader<'a>>> {
// should return "impl PeekRead+Read+HasError" when supported in (stable) rust
// should return "impl PeekRead + Read + HasError" when supported in (stable) rust
let inputs = input_strings
.iter()
.map(|w| match w as &str {

View file

@ -49,7 +49,6 @@ impl OutputInfo {
/// Creates a new `OutputInfo` based on the parameters
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 print_width_block = formats
.iter()
@ -129,7 +128,6 @@ impl OutputInfo {
/// Increase MAX_BYTES_PER_UNIT to allow larger types.
fn calculate_alignment(sf: &TypeSizeInfo, byte_size_block: usize,
print_width_block: usize) -> [usize; MAX_BYTES_PER_UNIT] {
if byte_size_block > MAX_BYTES_PER_UNIT {
panic!("{}-bits types are unsupported. Current max={}-bits.",
8 * byte_size_block,
@ -181,7 +179,6 @@ impl TypeSizeInfo for TypeInfo {
#[test]
fn test_calculate_alignment() {
// For this example `byte_size_block` is 8 and 'print_width_block' is 23:
// 1777777777777777777777 1777777777777777777777
// 4294967295 4294967295 4294967295 4294967295
@ -214,31 +211,31 @@ fn test_calculate_alignment() {
// 9 tests where 8 .. 16 spaces are spread across 8 positions
assert_eq!([1, 1, 1, 1, 1, 1, 1, 1],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16+8));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16 + 8));
assert_eq!([2, 1, 1, 1, 1, 1, 1, 1],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16+9));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16 + 9));
assert_eq!([2, 1, 1, 1, 2, 1, 1, 1],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16+10));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16 + 10));
assert_eq!([3, 1, 1, 1, 2, 1, 1, 1],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16+11));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16 + 11));
assert_eq!([2, 1, 2, 1, 2, 1, 2, 1],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16+12));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16 + 12));
assert_eq!([3, 1, 2, 1, 2, 1, 2, 1],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16+13));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16 + 13));
assert_eq!([3, 1, 2, 1, 3, 1, 2, 1],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16+14));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16 + 14));
assert_eq!([4, 1, 2, 1, 3, 1, 2, 1],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16+15));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16 + 15));
assert_eq!([2, 2, 2, 2, 2, 2, 2, 2],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16+16));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16 + 16));
// 4 tests where 15 spaces are spread across 8, 4, 2 or 1 position(s)
assert_eq!([4, 1, 2, 1, 3, 1, 2, 1],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16+15));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:1, print_width:2}, 8, 16 + 15));
assert_eq!([5, 0, 3, 0, 4, 0, 3, 0],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:2, print_width:4}, 8, 16+15));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:2, print_width:4}, 8, 16 + 15));
assert_eq!([8, 0, 0, 0, 7, 0, 0, 0],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:4, print_width:8}, 8, 16+15));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:4, print_width:8}, 8, 16 + 15));
assert_eq!([15, 0, 0, 0, 0, 0, 0, 0],
OutputInfo::calculate_alignment(&TypeInfo{byte_size:8, print_width:16}, 8, 16+15));
OutputInfo::calculate_alignment(&TypeInfo{byte_size:8, print_width:16}, 8, 16 + 15));
}

View file

@ -115,8 +115,7 @@ pub fn parse_format_flags(args: &Vec<String>) -> Result<Vec<ParsedFormatterItemI
Err(e) => return Err(e),
}
expect_type_string = false;
}
else if arg.starts_with("--") {
} else if arg.starts_with("--") {
if arg.len() == 2 {
break;
}
@ -130,29 +129,23 @@ pub fn parse_format_flags(args: &Vec<String>) -> Result<Vec<ParsedFormatterItemI
if arg == "--format" {
expect_type_string = true;
}
}
else if arg.starts_with("-") {
} else if arg.starts_with("-") {
let mut flags = arg.chars().skip(1);
let mut format_spec = String::new();
while let Some(c) = flags.next() {
if expect_type_string {
format_spec.push(c);
}
else if od_argument_with_option(c) {
} else if od_argument_with_option(c) {
break;
}
else if c=='t' {
} else if c == 't' {
expect_type_string = true;
}
else {
match od_argument_traditional_format(c) {
None => {} // not every option is a format
Some(r) => {
} else {
// not every option is a format
if let Some(r) = od_argument_traditional_format(c) {
formats.push(ParsedFormatterItemInfo::new(r, false))
}
}
}
}
if !format_spec.is_empty() {
match parse_type_string(&format_spec) {
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 {
match (format_type, ch) {
(FormatTypeCategory::Integer, Some('C')) => {
*byte_size = 1;
@ -274,7 +266,7 @@ fn is_format_dump_char(ch: Option<char>, show_ascii_dump: &mut bool) -> bool {
fn parse_type_string(params: &String) -> Result<Vec<ParsedFormatterItemInfo>, String> {
let mut formats = Vec::new();
let mut chars=params.chars();
let mut chars = params.chars();
let mut ch = chars.next();
while ch.is_some() {
@ -294,14 +286,13 @@ fn parse_type_string(params: &String) -> Result<Vec<ParsedFormatterItemInfo>, St
let mut show_ascii_dump = false;
if is_format_size_char(ch, type_cat, &mut byte_size) {
ch = chars.next();
}
else {
} else {
let mut decimal_size = String::new();
while is_format_size_decimal(ch, type_cat, &mut decimal_size) {
ch = chars.next();
}
if !decimal_size.is_empty() {
byte_size=match decimal_size.parse() {
byte_size = match decimal_size.parse() {
Err(_) => return Err(format!("invalid number '{}' in format specification '{}'", decimal_size, params)),
Ok(n) => n,
}

View file

@ -40,7 +40,6 @@ pub enum CommandLineInputs {
/// '-' is used as filename if stdin is meant. This is also returned if
/// there is no input, as stdin is the default input.
pub fn parse_inputs(matches: &CommandLineOpts) -> Result<CommandLineInputs, String> {
let mut input_strings: Vec<String> = matches.inputs();
if matches.opts_present(&["traditional"]) {
@ -53,7 +52,7 @@ pub fn parse_inputs(matches: &CommandLineOpts) -> Result<CommandLineInputs, Stri
// if any of the options -A, -j, -N, -t, -v or -w are present there is no offset
if !matches.opts_present(&["A", "j", "N", "t", "v", "w"]) {
// test if the last input can be parsed as an offset.
let offset=parse_offset_operand(&input_strings[input_strings.len()-1]);
let offset = parse_offset_operand(&input_strings[input_strings.len()-1]);
match offset {
Ok(n) => {
// if there is just 1 input (stdin), an offset must start with '+'
@ -80,22 +79,22 @@ pub fn parse_inputs(matches: &CommandLineOpts) -> Result<CommandLineInputs, Stri
/// interprets inputs when --traditional is on the commandline
///
/// normally returns CommandLineInputs::FileAndOffset, but if no offset is found,
/// it returns CommandLineInputs::FileNames (also to differentiate from the offset==0)
/// it returns CommandLineInputs::FileNames (also to differentiate from the offset == 0)
pub fn parse_inputs_traditional(input_strings: Vec<String>) -> Result<CommandLineInputs, String> {
match input_strings.len() {
0 => {
Ok(CommandLineInputs::FileNames(vec!{"-".to_string()}))
Ok(CommandLineInputs::FileNames(vec!["-".to_string()]))
}
1 => {
let offset0=parse_offset_operand(&input_strings[0]);
let offset0 = parse_offset_operand(&input_strings[0]);
Ok(match offset0 {
Ok(n) => CommandLineInputs::FileAndOffset(("-".to_string(), n, None)),
_ => CommandLineInputs::FileNames(input_strings),
})
}
2 => {
let offset0=parse_offset_operand(&input_strings[0]);
let offset1=parse_offset_operand(&input_strings[1]);
let offset0 = parse_offset_operand(&input_strings[0]);
let offset1 = parse_offset_operand(&input_strings[1]);
match (offset0, offset1) {
(Ok(n), Ok(m)) => Ok(CommandLineInputs::FileAndOffset(("-".to_string(), n, Some(m)))),
(_, Ok(m)) => Ok(CommandLineInputs::FileAndOffset((input_strings[0].clone(), m, None))),
@ -103,8 +102,8 @@ pub fn parse_inputs_traditional(input_strings: Vec<String>) -> Result<CommandLin
}
}
3 => {
let offset=parse_offset_operand(&input_strings[1]);
let label=parse_offset_operand(&input_strings[2]);
let offset = parse_offset_operand(&input_strings[1]);
let label = parse_offset_operand(&input_strings[2]);
match (offset, label) {
(Ok(n), Ok(m)) => Ok(CommandLineInputs::FileAndOffset((input_strings[0].clone(), n, Some(m)))),
(Err(_), _) => Err(format!("invalid offset: {}", input_strings[1])),
@ -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") {
start += 2;
radix = 16;
}
else {
} else {
if s[start..len].ends_with("b") {
len -= 1;
multiply = 512;
@ -178,7 +176,7 @@ mod tests {
fn opts_present(&self, opts: &[&str]) -> bool {
for expected in opts.iter() {
for actual in self.option_names.iter() {
if *expected==*actual {
if *expected == *actual {
return true;
}
}
@ -189,31 +187,30 @@ mod tests {
#[test]
fn test_parse_inputs_normal() {
assert_eq!(CommandLineInputs::FileNames(vec!{"-".to_string()}),
assert_eq!(CommandLineInputs::FileNames(vec!["-".to_string()]),
parse_inputs(&MockOptions::new(
vec!{},
vec!{})).unwrap());
vec![],
vec![])).unwrap());
assert_eq!(CommandLineInputs::FileNames(vec!{"-".to_string()}),
assert_eq!(CommandLineInputs::FileNames(vec!["-".to_string()]),
parse_inputs(&MockOptions::new(
vec!{"-"},
vec!{})).unwrap());
vec!["-"],
vec![])).unwrap());
assert_eq!(CommandLineInputs::FileNames(vec!{"file1".to_string()}),
assert_eq!(CommandLineInputs::FileNames(vec!["file1".to_string()]),
parse_inputs(&MockOptions::new(
vec!{"file1"},
vec!{})).unwrap());
vec!["file1"],
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(
vec!{"file1", "file2"},
vec!{})).unwrap());
vec!["file1", "file2"],
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(
vec!{"-", "file1", "file2"},
vec!{})).unwrap());
vec!["-", "file1", "file2"],
vec![])).unwrap());
}
#[test]
@ -221,113 +218,112 @@ mod tests {
// offset is found without filename, so stdin will be used.
assert_eq!(CommandLineInputs::FileAndOffset(("-".to_string(), 8, None)),
parse_inputs(&MockOptions::new(
vec!{"+10"},
vec!{})).unwrap());
vec!["+10"],
vec![])).unwrap());
// 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(
vec!{"10"},
vec!{""})).unwrap());
vec!["10"],
vec![""])).unwrap());
// 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(
vec!{"+10a"},
vec!{""})).unwrap());
vec!["+10a"],
vec![""])).unwrap());
// 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(
vec!{"+10"},
vec!{"j"})).unwrap());
vec!["+10"],
vec!["j"])).unwrap());
// 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(
vec!{"+10"},
vec!{"o", "v"})).unwrap());
vec!["+10"],
vec!["o", "v"])).unwrap());
assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)),
parse_inputs(&MockOptions::new(
vec!{"file1", "+10"},
vec!{})).unwrap());
vec!["file1", "+10"],
vec![])).unwrap());
// offset does not need to start with "+" if a filename is included.
assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)),
parse_inputs(&MockOptions::new(
vec!{"file1", "10"},
vec!{})).unwrap());
vec!["file1", "10"],
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(
vec!{"file1", "+10a"},
vec!{""})).unwrap());
vec!["file1", "+10a"],
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(
vec!{"file1", "+10"},
vec!{"j"})).unwrap());
vec!["file1", "+10"],
vec!["j"])).unwrap());
// 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(
vec!{"+10", "file1"},
vec!{""})).unwrap());
vec!["+10", "file1"],
vec![""])).unwrap());
}
#[test]
fn test_parse_inputs_traditional() {
// 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(
vec!{},
vec!{"traditional"})).unwrap());
vec![],
vec!["traditional"])).unwrap());
assert_eq!(CommandLineInputs::FileNames(vec!{"file1".to_string()}),
assert_eq!(CommandLineInputs::FileNames(vec!["file1".to_string()]),
parse_inputs(&MockOptions::new(
vec!{"file1"},
vec!{"traditional"})).unwrap());
vec!["file1"],
vec!["traditional"])).unwrap());
// offset does not need to start with a +
assert_eq!(CommandLineInputs::FileAndOffset(("-".to_string(), 8, None)),
parse_inputs(&MockOptions::new(
vec!{"10"},
vec!{"traditional"})).unwrap());
vec!["10"],
vec!["traditional"])).unwrap());
// valid offset and valid label
assert_eq!(CommandLineInputs::FileAndOffset(("-".to_string(), 8, Some(8))),
parse_inputs(&MockOptions::new(
vec!{"10", "10"},
vec!{"traditional"})).unwrap());
vec!["10", "10"],
vec!["traditional"])).unwrap());
assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, None)),
parse_inputs(&MockOptions::new(
vec!{"file1", "10"},
vec!{"traditional"})).unwrap());
vec!["file1", "10"],
vec!["traditional"])).unwrap());
// only one file is allowed, it must be the first
parse_inputs(&MockOptions::new(
vec!{"10", "file1"},
vec!{"traditional"})).unwrap_err();
vec!["10", "file1"],
vec!["traditional"])).unwrap_err();
assert_eq!(CommandLineInputs::FileAndOffset(("file1".to_string(), 8, Some(8))),
parse_inputs(&MockOptions::new(
vec!{"file1", "10", "10"},
vec!{"traditional"})).unwrap());
vec!["file1", "10", "10"],
vec!["traditional"])).unwrap());
parse_inputs(&MockOptions::new(
vec!{"10", "file1", "10"},
vec!{"traditional"})).unwrap_err();
vec!["10", "file1", "10"],
vec!["traditional"])).unwrap_err();
parse_inputs(&MockOptions::new(
vec!{"10", "10", "file1"},
vec!{"traditional"})).unwrap_err();
vec!["10", "10", "file1"],
vec!["traditional"])).unwrap_err();
parse_inputs(&MockOptions::new(
vec!{"10", "10", "10", "10"},
vec!{"traditional"})).unwrap_err();
vec!["10", "10", "10", "10"],
vec!["traditional"])).unwrap_err();
}
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!(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") {
start = 2;
radix = 16;
}
else if s.starts_with("0") {
} else if s.starts_with("0") {
radix = 8;
}
@ -24,40 +23,40 @@ pub fn parse_number_of_bytes(s: &String) -> Result<usize, &'static str> {
len -= 1;
}
Some('m') | Some('M') => {
multiply = 1024*1024;
multiply = 1024 * 1024;
len -= 1;
}
Some('G') => {
multiply = 1024*1024*1024;
multiply = 1024 * 1024 * 1024;
len -= 1;
}
#[cfg(target_pointer_width = "64")]
Some('T') => {
multiply = 1024*1024*1024*1024;
multiply = 1024 * 1024 * 1024 * 1024;
len -= 1;
}
#[cfg(target_pointer_width = "64")]
Some('P') => {
multiply = 1024*1024*1024*1024*1024;
multiply = 1024 * 1024 * 1024 * 1024 * 1024;
len -= 1;
}
#[cfg(target_pointer_width = "64")]
Some('E') => {
multiply = 1024*1024*1024*1024*1024*1024;
multiply = 1024 * 1024 * 1024 * 1024 * 1024 * 1024;
len -= 1;
}
Some('B') if radix != 16 => {
len -= 2;
multiply = match ends_with.next() {
Some('k') | Some('K') => 1000,
Some('m') | Some('M') => 1000*1000,
Some('G') => 1000*1000*1000,
Some('m') | Some('M') => 1000 * 1000,
Some('G') => 1000 * 1000 * 1000,
#[cfg(target_pointer_width = "64")]
Some('T') => 1000*1000*1000*1000,
Some('T') => 1000 * 1000 * 1000 * 1000,
#[cfg(target_pointer_width = "64")]
Some('P') => 1000*1000*1000*1000*1000,
Some('P') => 1000 * 1000 * 1000 * 1000 * 1000,
#[cfg(target_pointer_width = "64")]
Some('E') => 1000*1000*1000*1000*1000*1000,
Some('E') => 1000 * 1000 * 1000 * 1000 * 1000 * 1000,
_ => return Err("parse failed"),
}
},
@ -81,11 +80,11 @@ fn test_parse_number_of_bytes() {
assert_eq!(0, parse_number_of_bytes_str("0").unwrap());
assert_eq!(5, parse_number_of_bytes_str("5").unwrap());
assert_eq!(999, parse_number_of_bytes_str("999").unwrap());
assert_eq!(2*512, parse_number_of_bytes_str("2b").unwrap());
assert_eq!(2*1024, parse_number_of_bytes_str("2k").unwrap());
assert_eq!(4*1024, parse_number_of_bytes_str("4K").unwrap());
assert_eq!(2*1048576, parse_number_of_bytes_str("2m").unwrap());
assert_eq!(4*1048576, parse_number_of_bytes_str("4M").unwrap());
assert_eq!(2 * 512, parse_number_of_bytes_str("2b").unwrap());
assert_eq!(2 * 1024, parse_number_of_bytes_str("2k").unwrap());
assert_eq!(4 * 1024, parse_number_of_bytes_str("4K").unwrap());
assert_eq!(2 * 1048576, parse_number_of_bytes_str("2m").unwrap());
assert_eq!(4 * 1048576, parse_number_of_bytes_str("4M").unwrap());
assert_eq!(1073741824, parse_number_of_bytes_str("1G").unwrap());
assert_eq!(2000, parse_number_of_bytes_str("2kB").unwrap());
assert_eq!(4000, parse_number_of_bytes_str("4KB").unwrap());
@ -95,16 +94,16 @@ fn test_parse_number_of_bytes() {
// octal input
assert_eq!(8, parse_number_of_bytes_str("010").unwrap());
assert_eq!(8*512, parse_number_of_bytes_str("010b").unwrap());
assert_eq!(8*1024, parse_number_of_bytes_str("010k").unwrap());
assert_eq!(8*1048576, parse_number_of_bytes_str("010m").unwrap());
assert_eq!(8 * 512, parse_number_of_bytes_str("010b").unwrap());
assert_eq!(8 * 1024, parse_number_of_bytes_str("010k").unwrap());
assert_eq!(8 * 1048576, parse_number_of_bytes_str("010m").unwrap());
// hex input
assert_eq!(15, parse_number_of_bytes_str("0xf").unwrap());
assert_eq!(15, parse_number_of_bytes_str("0XF").unwrap());
assert_eq!(27, parse_number_of_bytes_str("0x1b").unwrap());
assert_eq!(16*1024, parse_number_of_bytes_str("0x10k").unwrap());
assert_eq!(16*1048576, parse_number_of_bytes_str("0x10m").unwrap());
assert_eq!(16 * 1024, parse_number_of_bytes_str("0x10k").unwrap());
assert_eq!(16 * 1048576, parse_number_of_bytes_str("0x10m").unwrap());
// invalid input
parse_number_of_bytes_str("").unwrap_err();

View file

@ -5,7 +5,7 @@ use multifilereader::HasError;
/// When a large number of bytes must be skipped, it will be read into a
/// dynamically allocated buffer. The buffer will be limited to this size.
const MAX_SKIP_BUFFER: usize = 64*1024;
const MAX_SKIP_BUFFER: usize = 64 * 1024;
/// Wrapper for `std::io::Read` which can skip bytes at the beginning
/// of the input, and it can limit the returned bytes to a particular

View file

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

View file

@ -14,7 +14,7 @@ pub static FORMAT_ITEM_C: FormatterItemInfo = FormatterItemInfo {
};
static A_CHRS : [&'static str; 128] =
static A_CHRS: [&'static str; 128] =
["nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel",
"bs", "ht", "nl", "vt", "ff", "cr", "so", "si",
"dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb",
@ -40,7 +40,7 @@ fn format_item_a(p: u64) -> String {
}
static C_CHRS : [&'static str; 128] = [
static C_CHRS: [&'static str; 128] = [
"\\0", "001", "002", "003", "004", "005", "006", "\\a",
"\\b", "\\t", "\\n", "\\v", "\\f", "\\r", "016", "017",
"020", "021", "022", "023", "024", "025", "026", "027",
@ -68,33 +68,28 @@ fn format_item_c(bytes: &[u8]) -> String {
Some(s) => format!("{:>4}", s),
None => format!("{:>4}", b),
}
}
else if (b & 0xc0) == 0x80 {
} else if (b & 0xc0) == 0x80 {
// second or subsequent octet of an utf-8 sequence
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
match from_utf8(&bytes[0..2]) {
Ok(s) => { format!("{:>4}", s) },
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
match from_utf8(&bytes[0..3]) {
Ok(s) => { format!("{:>4}", s) },
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
match from_utf8(&bytes[0..4]) {
Ok(s) => { format!("{:>4}", s) },
Err(_) => { format!(" {:03o}", b) },
}
}
else {
} else {
// invalid utf-8
format!(" {:03o}", b)
}
@ -107,8 +102,7 @@ pub fn format_ascii_dump(bytes: &[u8]) -> String {
for c in bytes.iter() {
if *c >= 0x20 && *c <= 0x7e {
result.push_str(C_CHRS[*c as usize]);
}
else {
} else {
result.push('.');
}
}

View file

@ -47,8 +47,7 @@ fn format_flo32(f: f32) -> String {
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 {
} else {
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 {
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) }
@ -77,13 +75,11 @@ fn format_float(f: f64, width: usize, precision: usize) -> String {
format!("{:width$.dec$}", f,
width = width,
dec = (precision-1) - l as usize)
}
else if l == -1 {
} else if l == -1 {
format!("{:width$.dec$}", f,
width = width,
dec = precision)
}
else {
} else {
format!("{:width$.dec$e}", f,
width = width,
dec = precision - 1)

View file

@ -89,20 +89,17 @@ fn test_no_file() {
// Test that od reads from stdin instead of a file
#[test]
fn test_from_stdin() {
let input = "abcdefghijklmnopqrstuvwxyz\n";
let result = new_ucmd!().arg("--endian=little").run_piped_stdin(input.as_bytes());
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, unindent(ALPHA_OUT));
}
// Test that od reads from stdin and also from files
#[test]
fn test_from_mixed() {
let temp = env::temp_dir();
let tmpdir = Path::new(&temp);
let file1 = tmpdir.join("test-1");
@ -122,12 +119,10 @@ fn test_from_mixed() {
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, unindent(ALPHA_OUT));
}
#[test]
fn test_multiple_formats() {
let input = "abcdefghijklmnopqrstuvwxyz\n";
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
0000033
"));
}
#[test]
fn test_dec() {
let input = [
0u8, 0u8,
1u8, 0u8,
@ -163,13 +156,11 @@ fn test_dec() {
assert_empty_stderr!(result);
assert!(result.success);
assert_eq!(result.stdout, expected_output);
}
#[test]
fn test_hex16(){
let input : [u8; 9] = [
let input: [u8; 9] = [
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xff];
let expected_output = unindent("
0000000 2301 6745 ab89 efcd 00ff
@ -184,8 +175,7 @@ fn test_hex16(){
#[test]
fn test_hex32(){
let input : [u8; 9] = [
let input: [u8; 9] = [
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, 0xff];
let expected_output = unindent("
0000000 67452301 efcdab89 000000ff
@ -200,8 +190,7 @@ fn test_hex32(){
#[test]
fn test_f16(){
let input : [u8; 14] = [
let input: [u8; 14] = [
0x00, 0x3c, // 0x3C00 1.0
0x00, 0x00, // 0x0000 0.0
0x00, 0x80, // 0x8000 -0.0
@ -223,8 +212,7 @@ fn test_f16(){
#[test]
fn test_f32(){
let input : [u8; 28] = [
let input: [u8; 28] = [
0x52, 0x06, 0x9e, 0xbf, // 0xbf9e0652 -1.2345679
0x4e, 0x61, 0x3c, 0x4b, // 0x4b3c614e 12345678
0x0f, 0x9b, 0x94, 0xfe, // 0xfe949b0f -9.876543E37
@ -246,8 +234,7 @@ fn test_f32(){
#[test]
fn test_f64(){
let input : [u8; 40] = [
let input: [u8; 40] = [
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, 0x10, 0x80, // 0x8010000000000000 -2.2250738585072014e-308
@ -268,7 +255,6 @@ fn test_f64(){
#[test]
fn test_multibyte() {
let result = new_ucmd!().arg("-c").arg("-w12").run_piped_stdin("Universität Tübingen \u{1B000}".as_bytes());
assert_empty_stderr!(result);
@ -283,8 +269,7 @@ fn test_multibyte() {
#[test]
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("
0000000 000000 000000
0000004 000000 000000
@ -300,8 +285,7 @@ fn test_width(){
#[test]
fn test_invalid_width(){
let input : [u8; 4] = [0x00, 0x00, 0x00, 0x00];
let input: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
let expected_output = unindent("
0000000 000000
0000002 000000
@ -317,8 +301,7 @@ fn test_invalid_width(){
#[test]
fn test_zero_width(){
let input : [u8; 4] = [0x00, 0x00, 0x00, 0x00];
let input: [u8; 4] = [0x00, 0x00, 0x00, 0x00];
let expected_output = unindent("
0000000 000000
0000002 000000
@ -334,8 +317,7 @@ fn test_zero_width(){
#[test]
fn test_width_without_value(){
let input : [u8; 40] = [0 ; 40];
let input: [u8; 40] = [0 ; 40];
let expected_output = unindent("
0000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000 000000
0000040 000000 000000 000000 000000
@ -351,7 +333,6 @@ fn test_width_without_value(){
#[test]
fn test_suppress_duplicates(){
let input: [u8; 41] = [
0, 0, 0, 0,
0, 0, 0, 0,
@ -387,8 +368,7 @@ fn test_suppress_duplicates(){
#[test]
fn test_big_endian() {
let input : [u8; 8] = [
let input: [u8; 8] = [
0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];// 0xc000000000000000 -2
let expected_output = unindent("
@ -409,8 +389,7 @@ fn test_big_endian() {
#[test]
#[allow(non_snake_case)]
fn test_alignment_Xxa() {
let input : [u8; 8] = [
let input: [u8; 8] = [
0x0A, 0x0D, 0x65, 0x66, 0x67, 0x00, 0x9e, 0x9f];
let expected_output = unindent("
@ -431,8 +410,7 @@ fn test_alignment_Xxa() {
#[test]
#[allow(non_snake_case)]
fn test_alignment_Fx() {
let input : [u8; 8] = [
let input: [u8; 8] = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0];// 0xc000000000000000 -2
let expected_output = unindent("
@ -451,7 +429,6 @@ fn test_alignment_Fx() {
#[test]
fn test_maxuint(){
let input = [0xFFu8 ; 8];
let expected_output = unindent("
0000000 1777777777777777777777
@ -474,7 +451,6 @@ fn test_maxuint(){
#[test]
fn test_hex_offset(){
let input = [0u8 ; 0x1F];
let expected_output = unindent("
000000 00000000 00000000 00000000 00000000
@ -493,7 +469,6 @@ fn test_hex_offset(){
#[test]
fn test_dec_offset(){
let input = [0u8 ; 19];
let expected_output = unindent("
0000000 00000000 00000000 00000000 00000000
@ -512,7 +487,6 @@ fn test_dec_offset(){
#[test]
fn test_no_offset(){
let input = [0u8 ; 31];
const LINE: &'static str = " 00000000 00000000 00000000 00000000\n";
let expected_output = [LINE, LINE, LINE, LINE].join("");
@ -526,17 +500,13 @@ fn test_no_offset(){
#[test]
fn test_invalid_offset(){
let input = [0u8 ; 4];
let result = new_ucmd!().arg("-Ab").run_piped_stdin(&input[..]);
let result = new_ucmd!().arg("-Ab").run();
assert!(!result.success);
}
#[test]
fn test_skip_bytes(){
let input = "abcdefghijklmnopq";
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]
fn test_skip_bytes_error(){
let input = "12345";
let result = new_ucmd!().arg("--skip-bytes=10").run_piped_stdin(input.as_bytes());
@ -559,7 +528,6 @@ fn test_skip_bytes_error(){
#[test]
fn test_read_bytes(){
let input = "abcdefghijklmnopqrstuvwxyz\n12345678";
let result = new_ucmd!().arg("--endian=little").arg("--read-bytes=27").run_piped_stdin(input.as_bytes());
@ -570,8 +538,7 @@ fn test_read_bytes(){
#[test]
fn test_ascii_dump(){
let input : [u8; 22] = [
let input: [u8; 22] = [
0x00, 0x01, 0x0a, 0x0d, 0x10, 0x1f, 0x20, 0x61, 0x62, 0x63, 0x7d,
0x7e, 0x7f, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff];
let result = new_ucmd!().arg("-tx1zacz").run_piped_stdin(&input[..]);
@ -607,7 +574,6 @@ fn test_filename_parsing(){
#[test]
fn test_stdin_offset(){
let input = "abcdefghijklmnopq";
let result = new_ucmd!().arg("-c").arg("+5").run_piped_stdin(input.as_bytes());
@ -621,7 +587,6 @@ fn test_stdin_offset(){
#[test]
fn test_file_offset(){
let result = new_ucmd!().arg("-c").arg("--").arg("-f").arg("10").run();
assert_empty_stderr!(result);
@ -678,8 +643,7 @@ fn test_traditional_with_skip_bytes_non_override(){
#[test]
fn test_traditional_error(){
// 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_piped_stdin(input.as_bytes());
let result = new_ucmd!().arg("--traditional").arg("0").arg("0").arg("0").arg("0").run();
assert!(!result.success);
}