1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 11:37:44 +00:00

join: add support for full outer joins

This commit is contained in:
Justin Tracey 2021-08-12 23:32:29 -04:00
parent 01be7b356f
commit 1bb0237281
6 changed files with 65 additions and 12 deletions

View file

@ -19,7 +19,6 @@ static NAME: &str = "join";
#[derive(Copy, Clone, PartialEq)] #[derive(Copy, Clone, PartialEq)]
enum FileNum { enum FileNum {
None,
File1, File1,
File2, File2,
} }
@ -41,7 +40,8 @@ enum CheckOrder {
struct Settings { struct Settings {
key1: usize, key1: usize,
key2: usize, key2: usize,
print_unpaired: FileNum, print_unpaired1: bool,
print_unpaired2: bool,
print_joined: bool, print_joined: bool,
ignore_case: bool, ignore_case: bool,
separator: Sep, separator: Sep,
@ -57,7 +57,8 @@ impl Default for Settings {
Settings { Settings {
key1: 0, key1: 0,
key2: 0, key2: 0,
print_unpaired: FileNum::None, print_unpaired1: false,
print_unpaired2: false,
print_joined: true, print_joined: true,
ignore_case: false, ignore_case: false,
separator: Sep::Whitespaces, separator: Sep::Whitespaces,
@ -243,7 +244,7 @@ impl<'a> State<'a> {
name: &'a str, name: &'a str,
stdin: &'a Stdin, stdin: &'a Stdin,
key: usize, key: usize,
print_unpaired: FileNum, print_unpaired: bool,
) -> State<'a> { ) -> State<'a> {
let f = if name == "-" { let f = if name == "-" {
Box::new(stdin.lock()) as Box<dyn BufRead> Box::new(stdin.lock()) as Box<dyn BufRead>
@ -258,7 +259,7 @@ impl<'a> State<'a> {
key, key,
file_name: name, file_name: name,
file_num, file_num,
print_unpaired: print_unpaired == file_num, print_unpaired,
lines: f.lines(), lines: f.lines(),
seq: Vec::new(), seq: Vec::new(),
max_fields: None, max_fields: None,
@ -450,11 +451,19 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let mut settings: Settings = Default::default(); let mut settings: Settings = Default::default();
if let Some(value) = matches.value_of("v") { let v_values = matches.values_of("v");
settings.print_unpaired = parse_file_number(value); if v_values.is_some() {
settings.print_joined = false; settings.print_joined = false;
} else if let Some(value) = matches.value_of("a") { }
settings.print_unpaired = parse_file_number(value);
let unpaired = v_values
.unwrap_or_default()
.chain(matches.values_of("a").unwrap_or_default());
for file_num in unpaired {
match parse_file_number(file_num) {
FileNum::File1 => settings.print_unpaired1 = true,
FileNum::File2 => settings.print_unpaired2 = true,
}
} }
settings.ignore_case = matches.is_present("i"); settings.ignore_case = matches.is_present("i");
@ -520,7 +529,8 @@ When FILE1 or FILE2 (not both) is -, read standard input.",
.arg( .arg(
Arg::with_name("a") Arg::with_name("a")
.short("a") .short("a")
.takes_value(true) .multiple(true)
.number_of_values(1)
.possible_values(&["1", "2"]) .possible_values(&["1", "2"])
.value_name("FILENUM") .value_name("FILENUM")
.help( .help(
@ -531,6 +541,9 @@ FILENUM is 1 or 2, corresponding to FILE1 or FILE2",
.arg( .arg(
Arg::with_name("v") Arg::with_name("v")
.short("v") .short("v")
.multiple(true)
.number_of_values(1)
.possible_values(&["1", "2"])
.value_name("FILENUM") .value_name("FILENUM")
.help("like -a FILENUM, but suppress joined output lines"), .help("like -a FILENUM, but suppress joined output lines"),
) )
@ -617,7 +630,7 @@ fn exec(file1: &str, file2: &str, settings: &Settings) -> i32 {
file1, file1,
&stdin, &stdin,
settings.key1, settings.key1,
settings.print_unpaired, settings.print_unpaired1,
); );
let mut state2 = State::new( let mut state2 = State::new(
@ -625,7 +638,7 @@ fn exec(file1: &str, file2: &str, settings: &Settings) -> i32 {
file2, file2,
&stdin, &stdin,
settings.key2, settings.key2,
settings.print_unpaired, settings.print_unpaired2,
); );
let input = Input::new( let input = Input::new(

View file

@ -94,6 +94,18 @@ fn unpaired_lines() {
.arg("2") .arg("2")
.succeeds() .succeeds()
.stdout_only_fixture("unpaired_lines.expected"); .stdout_only_fixture("unpaired_lines.expected");
new_ucmd!()
.arg("fields_3.txt")
.arg("fields_2.txt")
.arg("-1")
.arg("2")
.arg("-a")
.arg("1")
.arg("-a")
.arg("2")
.succeeds()
.stdout_only_fixture("unpaired_lines_outer.expected");
} }
#[test] #[test]
@ -107,6 +119,18 @@ fn suppress_joined() {
.arg("2") .arg("2")
.succeeds() .succeeds()
.stdout_only_fixture("suppress_joined.expected"); .stdout_only_fixture("suppress_joined.expected");
new_ucmd!()
.arg("fields_3.txt")
.arg("fields_2.txt")
.arg("-1")
.arg("2")
.arg("-a")
.arg("1")
.arg("-v")
.arg("2")
.succeeds()
.stdout_only_fixture("suppress_joined_outer.expected");
} }
#[test] #[test]

View file

@ -4,3 +4,4 @@ c 4 h
f 5 i f 5 i
g 6 j g 6 j
h 7 k h 7 k
i 99 l

View file

@ -0,0 +1,4 @@
1 a
8 h
9 i
99 i l

View file

@ -4,3 +4,4 @@
i 5 f i 5 f
j 6 g j 6 g
k 7 h k 7 h
l 99 i

View file

@ -0,0 +1,10 @@
1 a
2 a f b
3 b g c
4 c h d
5 f i e
6 g j f
7 h k g
8 h
9 i
99 i l