Skip to content

Commit d7ed3c6

Browse files
authored
ptx: handle duplicate input files (#9823)
1 parent 87c332c commit d7ed3c6

File tree

3 files changed

+25
-7
lines changed

3 files changed

+25
-7
lines changed

src/uu/ptx/src/ptx.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
use std::cmp;
99
use std::cmp::PartialEq;
10-
use std::collections::{BTreeSet, HashMap, HashSet};
10+
use std::collections::{BTreeSet, HashSet};
1111
use std::ffi::{OsStr, OsString};
1212
use std::fmt::Write as FmtWrite;
1313
use std::fs::File;
@@ -279,10 +279,10 @@ struct FileContent {
279279
offset: usize,
280280
}
281281

282-
type FileMap = HashMap<OsString, FileContent>;
282+
type FileMap = Vec<(OsString, FileContent)>;
283283

284284
fn read_input(input_files: &[OsString], config: &Config) -> std::io::Result<FileMap> {
285-
let mut file_map: FileMap = HashMap::new();
285+
let mut file_map: FileMap = FileMap::new();
286286
let mut offset: usize = 0;
287287

288288
let sentence_splitter = config
@@ -304,14 +304,14 @@ fn read_input(input_files: &[OsString], config: &Config) -> std::io::Result<File
304304
// Since we will be jumping around the line a lot, we dump the content into a Vec<char>, which can be indexed in constant time.
305305
let chars_lines: Vec<Vec<char>> = lines.iter().map(|x| x.chars().collect()).collect();
306306
let size = lines.len();
307-
file_map.insert(
307+
file_map.push((
308308
filename.clone(),
309309
FileContent {
310310
lines,
311311
chars_lines,
312312
offset,
313313
},
314-
);
314+
));
315315
offset += size;
316316
}
317317
Ok(file_map)
@@ -793,8 +793,17 @@ fn write_traditional_output(
793793
}
794794

795795
for word_ref in words {
796-
let file_map_value: &FileContent = file_map
797-
.get(&word_ref.filename)
796+
// Since `ptx` accepts duplicate file arguments (e.g., `ptx file file`),
797+
// simply looking up by filename is ambiguous.
798+
// We use the `global_line_nr` (which is unique across the entire input stream)
799+
// to identify which file covers this line.
800+
let (_, file_map_value) = file_map
801+
.iter()
802+
.find(|(name, content)| {
803+
name == &word_ref.filename
804+
&& word_ref.global_line_nr >= content.offset
805+
&& word_ref.global_line_nr < content.offset + content.lines.len()
806+
})
798807
.expect("Missing file in file map");
799808
let FileContent {
800809
ref lines,

tests/by-util/test_ptx.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,14 @@ fn test_unicode_truncation_alignment() {
339339
.stdout_only(" / bar\n föö/\n");
340340
}
341341

342+
#[test]
343+
fn test_duplicate_input_files() {
344+
new_ucmd!()
345+
.args(&["one_word", "one_word"])
346+
.succeeds()
347+
.stdout_is(" rust\n rust\n");
348+
}
349+
342350
#[test]
343351
fn test_narrow_width_with_long_reference_no_panic() {
344352
new_ucmd!()

tests/fixtures/ptx/one_word

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
rust

0 commit comments

Comments
 (0)