mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Merge pull request #946 from ChrisNikkel/feature/zero_terminated
uniq: add -z option to allow for zero terminated input and output
This commit is contained in:
commit
1880c46acd
4 changed files with 26 additions and 4 deletions
|
@ -34,6 +34,7 @@ struct Uniq {
|
||||||
slice_start: Option<usize>,
|
slice_start: Option<usize>,
|
||||||
slice_stop: Option<usize>,
|
slice_stop: Option<usize>,
|
||||||
ignore_case: bool,
|
ignore_case: bool,
|
||||||
|
zero_terminated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Uniq {
|
impl Uniq {
|
||||||
|
@ -41,9 +42,10 @@ impl Uniq {
|
||||||
let mut lines: Vec<String> = vec!();
|
let mut lines: Vec<String> = vec!();
|
||||||
let mut first_line_printed = false;
|
let mut first_line_printed = false;
|
||||||
let delimiters = &self.delimiters[..];
|
let delimiters = &self.delimiters[..];
|
||||||
|
let line_terminator = self.get_line_terminator();
|
||||||
|
|
||||||
for io_line in reader.lines() {
|
for io_line in reader.split(line_terminator) {
|
||||||
let line = crash_if_err!(1, io_line);
|
let line = String::from_utf8(crash_if_err!(1, io_line)).unwrap();
|
||||||
if !lines.is_empty() && self.cmp_key(&lines[0]) != self.cmp_key(&line) {
|
if !lines.is_empty() && self.cmp_key(&lines[0]) != self.cmp_key(&line) {
|
||||||
let print_delimiter = delimiters == "prepend" || (delimiters == "separate" && first_line_printed);
|
let print_delimiter = delimiters == "prepend" || (delimiters == "separate" && first_line_printed);
|
||||||
first_line_printed |= self.print_lines(writer, &lines, print_delimiter);
|
first_line_printed |= self.print_lines(writer, &lines, print_delimiter);
|
||||||
|
@ -80,6 +82,14 @@ impl Uniq {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_line_terminator(&self) -> u8 {
|
||||||
|
if self.zero_terminated {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
'\n' as u8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn cmp_key(&self, line: &str) -> String {
|
fn cmp_key(&self, line: &str) -> String {
|
||||||
let fields_to_check = &self.skip_fields(line);
|
let fields_to_check = &self.skip_fields(line);
|
||||||
let len = fields_to_check.len();
|
let len = fields_to_check.len();
|
||||||
|
@ -116,8 +126,10 @@ impl Uniq {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_line<W: Write>(&self, writer: &mut BufWriter<W>, line: &str, count: usize, print_delimiter: bool) {
|
fn print_line<W: Write>(&self, writer: &mut BufWriter<W>, line: &str, count: usize, print_delimiter: bool) {
|
||||||
|
let line_terminator = self.get_line_terminator();
|
||||||
|
|
||||||
if print_delimiter {
|
if print_delimiter {
|
||||||
crash_if_err!(1, writer.write_all(&['\n' as u8]));
|
crash_if_err!(1, writer.write_all(&[line_terminator]));
|
||||||
}
|
}
|
||||||
|
|
||||||
crash_if_err!(1, if self.show_counts {
|
crash_if_err!(1, if self.show_counts {
|
||||||
|
@ -125,7 +137,7 @@ impl Uniq {
|
||||||
} else {
|
} else {
|
||||||
writer.write_all(line.as_bytes())
|
writer.write_all(line.as_bytes())
|
||||||
});
|
});
|
||||||
crash_if_err!(1, writer.write_all("\n".as_bytes()));
|
crash_if_err!(1, writer.write_all(&[line_terminator]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,6 +165,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
opts.optopt("w", "check-chars", "compare no more than N characters in lines", "N");
|
opts.optopt("w", "check-chars", "compare no more than N characters in lines", "N");
|
||||||
opts.optflag("i", "ignore-case", "ignore differences in case when comparing");
|
opts.optflag("i", "ignore-case", "ignore differences in case when comparing");
|
||||||
opts.optflag("u", "unique", "only print unique lines");
|
opts.optflag("u", "unique", "only print unique lines");
|
||||||
|
opts.optflag("z", "zero-terminated", "end lines with 0 byte, not newline");
|
||||||
opts.optflag("h", "help", "display this help and exit");
|
opts.optflag("h", "help", "display this help and exit");
|
||||||
opts.optflag("V", "version", "output version information and exit");
|
opts.optflag("V", "version", "output version information and exit");
|
||||||
|
|
||||||
|
@ -202,6 +215,7 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
||||||
slice_start: opt_parsed("skip-chars", &matches),
|
slice_start: opt_parsed("skip-chars", &matches),
|
||||||
slice_stop: opt_parsed("check-chars", &matches),
|
slice_stop: opt_parsed("check-chars", &matches),
|
||||||
ignore_case: matches.opt_present("ignore-case"),
|
ignore_case: matches.opt_present("ignore-case"),
|
||||||
|
zero_terminated: matches.opt_present("zero-terminated"),
|
||||||
};
|
};
|
||||||
uniq.print_uniq(&mut open_input_file(in_file_name),
|
uniq.print_uniq(&mut open_input_file(in_file_name),
|
||||||
&mut open_output_file(out_file_name));
|
&mut open_output_file(out_file_name));
|
||||||
|
|
BIN
tests/fixtures/uniq/sorted-zero-terminated.expected
vendored
Normal file
BIN
tests/fixtures/uniq/sorted-zero-terminated.expected
vendored
Normal file
Binary file not shown.
BIN
tests/fixtures/uniq/sorted-zero-terminated.txt
vendored
Normal file
BIN
tests/fixtures/uniq/sorted-zero-terminated.txt
vendored
Normal file
Binary file not shown.
|
@ -8,6 +8,7 @@ fn new_ucmd() -> UCommand {
|
||||||
static INPUT: &'static str = "sorted.txt";
|
static INPUT: &'static str = "sorted.txt";
|
||||||
static SKIP_CHARS: &'static str = "skip-chars.txt";
|
static SKIP_CHARS: &'static str = "skip-chars.txt";
|
||||||
static SKIP_FIELDS: &'static str = "skip-fields.txt";
|
static SKIP_FIELDS: &'static str = "skip-fields.txt";
|
||||||
|
static SORTED_ZERO_TERMINATED: &'static str = "sorted-zero-terminated.txt";
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_stdin_default() {
|
fn test_stdin_default() {
|
||||||
|
@ -92,3 +93,10 @@ fn test_stdin_repeated_only() {
|
||||||
.args(&["-d"]).pipe_in_fixture(INPUT)
|
.args(&["-d"]).pipe_in_fixture(INPUT)
|
||||||
.run().stdout_is_fixture("sorted-repeated-only.expected");
|
.run().stdout_is_fixture("sorted-repeated-only.expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_stdin_zero_terminated() {
|
||||||
|
new_ucmd()
|
||||||
|
.args(&["-z"]).pipe_in_fixture(SORTED_ZERO_TERMINATED)
|
||||||
|
.run().stdout_is_fixture("sorted-zero-terminated.expected");
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue