Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 38 additions & 4 deletions src/uu/join/src/join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ enum FileNum {
File2,
}

#[repr(u8)]
#[derive(Copy, Clone)]
enum LineEnding {
Nul = 0,
Newline = b'\n',
}

#[derive(Copy, Clone)]
enum Sep {
Char(u8),
Expand All @@ -46,6 +53,7 @@ struct Settings {
print_unpaired2: bool,
print_joined: bool,
ignore_case: bool,
line_ending: LineEnding,
separator: Sep,
autoformat: bool,
format: Vec<Spec>,
Expand All @@ -63,6 +71,7 @@ impl Default for Settings {
print_unpaired2: false,
print_joined: true,
ignore_case: false,
line_ending: LineEnding::Newline,
separator: Sep::Whitespaces,
autoformat: false,
format: vec![],
Expand All @@ -75,14 +84,21 @@ impl Default for Settings {

/// Output representation.
struct Repr<'a> {
line_ending: LineEnding,
separator: u8,
format: &'a [Spec],
empty: &'a [u8],
}

impl<'a> Repr<'a> {
fn new(separator: u8, format: &'a [Spec], empty: &'a [u8]) -> Repr<'a> {
fn new(
line_ending: LineEnding,
separator: u8,
format: &'a [Spec],
empty: &'a [u8],
) -> Repr<'a> {
Repr {
line_ending,
separator,
format,
empty,
Expand Down Expand Up @@ -133,6 +149,10 @@ impl<'a> Repr<'a> {
}
Ok(())
}

fn print_line_ending(&self) -> Result<(), std::io::Error> {
stdout().write_all(&[self.line_ending as u8])
}
}

/// Input processing parameters.
Expand Down Expand Up @@ -260,6 +280,7 @@ impl<'a> State<'a> {
name: &'a str,
stdin: &'a Stdin,
key: usize,
line_ending: LineEnding,
print_unpaired: bool,
) -> State<'a> {
let f = if name == "-" {
Expand All @@ -276,7 +297,7 @@ impl<'a> State<'a> {
file_name: name,
file_num,
print_unpaired,
lines: f.split(b'\n'),
lines: f.split(line_ending as u8),
seq: Vec::new(),
line_num: 0,
has_failed: false,
Expand Down Expand Up @@ -351,7 +372,7 @@ impl<'a> State<'a> {
repr.print_fields(line2, other.key)?;
}

stdout().write_all(&[b'\n'])?;
repr.print_line_ending()?;
}
}

Expand Down Expand Up @@ -461,7 +482,7 @@ impl<'a> State<'a> {
repr.print_fields(line, self.key)?;
}

stdout().write_all(&[b'\n'])
repr.print_line_ending()
}

fn print_first_line(&self, repr: &Repr) -> Result<(), std::io::Error> {
Expand Down Expand Up @@ -540,6 +561,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
settings.headers = true;
}

if matches.is_present("z") {
settings.line_ending = LineEnding::Nul;
}

let file1 = matches.value_of("file1").unwrap();
let file2 = matches.value_of("file2").unwrap();

Expand Down Expand Up @@ -646,6 +671,12 @@ FILENUM is 1 or 2, corresponding to FILE1 or FILE2",
"treat the first line in each file as field headers, \
print them without trying to pair them",
))
.arg(
Arg::with_name("z")
.short("z")
.long("zero-terminated")
.help("line delimiter is NUL, not newline"),
)
.arg(
Arg::with_name("file1")
.required(true)
Expand All @@ -668,6 +699,7 @@ fn exec(file1: &str, file2: &str, settings: Settings) -> Result<(), std::io::Err
file1,
&stdin,
settings.key1,
settings.line_ending,
settings.print_unpaired1,
);

Expand All @@ -676,6 +708,7 @@ fn exec(file1: &str, file2: &str, settings: Settings) -> Result<(), std::io::Err
file2,
&stdin,
settings.key2,
settings.line_ending,
settings.print_unpaired2,
);

Expand Down Expand Up @@ -705,6 +738,7 @@ fn exec(file1: &str, file2: &str, settings: Settings) -> Result<(), std::io::Err
};

let repr = Repr::new(
settings.line_ending,
match settings.separator {
Sep::Char(sep) => sep,
_ => b' ',
Expand Down
10 changes: 10 additions & 0 deletions tests/by-util/test_join.rs
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,13 @@ fn non_unicode() {
.succeeds()
.stdout_only_fixture("non-unicode.expected");
}

#[test]
fn null_line_endings() {
new_ucmd!()
.arg("-z")
.arg("non-unicode_1.bin")
.arg("non-unicode_2.bin")
.succeeds()
.stdout_only_fixture("z.expected");
}
Binary file added tests/fixtures/join/z.expected
Binary file not shown.