mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 03:27:44 +00:00
pr: add -m and -o option
pr: Add -o option
This commit is contained in:
parent
dd07aed4d1
commit
5956894d00
7 changed files with 1151 additions and 94 deletions
443
src/pr/pr.rs
443
src/pr/pr.rs
|
@ -15,12 +15,12 @@ extern crate chrono;
|
|||
extern crate getopts;
|
||||
extern crate uucore;
|
||||
|
||||
use std::io::{BufRead, BufReader, stdin, stdout, stderr, Error, Read, Write, Stdout, Lines};
|
||||
use std::io::{BufRead, BufReader, stdin, stdout, stderr, Error, Read, Write, Stdout, Lines, Stdin};
|
||||
use std::vec::Vec;
|
||||
use chrono::offset::Local;
|
||||
use chrono::DateTime;
|
||||
use getopts::{Matches, Options};
|
||||
use std::fs::{metadata, File};
|
||||
use std::fs::{metadata, File, Metadata};
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::FileTypeExt;
|
||||
use quick_error::ResultExt;
|
||||
|
@ -29,6 +29,7 @@ use getopts::{HasArg, Occur};
|
|||
use std::num::ParseIntError;
|
||||
use itertools::{Itertools, GroupBy};
|
||||
use std::iter::{Enumerate, Map, TakeWhile, SkipWhile};
|
||||
use itertools::structs::KMergeBy;
|
||||
|
||||
static NAME: &str = "pr";
|
||||
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
@ -51,6 +52,8 @@ static COLUMN_WIDTH_OPTION: &str = "w";
|
|||
static ACROSS_OPTION: &str = "a";
|
||||
static COLUMN_OPTION: &str = "column";
|
||||
static COLUMN_SEPARATOR_OPTION: &str = "s";
|
||||
static MERGE_FILES_PRINT: &str = "m";
|
||||
static OFFSET_SPACES_OPTION: &str = "o";
|
||||
static FILE_STDIN: &str = "-";
|
||||
static READ_BUFFER_SIZE: usize = 1024 * 64;
|
||||
static DEFAULT_COLUMN_WIDTH: usize = 72;
|
||||
|
@ -71,6 +74,22 @@ struct OutputOptions {
|
|||
content_lines_per_page: usize,
|
||||
page_separator_char: String,
|
||||
column_mode_options: Option<ColumnModeOptions>,
|
||||
merge_files_print: Option<usize>,
|
||||
offset_spaces: usize
|
||||
}
|
||||
|
||||
struct FileLine {
|
||||
file_id: usize,
|
||||
line_number: usize,
|
||||
page_number: usize,
|
||||
key: usize,
|
||||
line_content: Result<String, Error>,
|
||||
}
|
||||
|
||||
impl AsRef<FileLine> for FileLine {
|
||||
fn as_ref(&self) -> &FileLine {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
struct ColumnModeOptions {
|
||||
|
@ -283,6 +302,27 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
Occur::Optional,
|
||||
);
|
||||
|
||||
opts.opt(
|
||||
MERGE_FILES_PRINT,
|
||||
"merge",
|
||||
"Merge files. Standard output shall be formatted so the pr utility writes one line from each file specified by a
|
||||
file operand, side by side into text columns of equal fixed widths, in terms of the number of column positions.
|
||||
Implementations shall support merging of at least nine file operands.",
|
||||
"",
|
||||
HasArg::No,
|
||||
Occur::Optional,
|
||||
);
|
||||
|
||||
opts.opt(
|
||||
OFFSET_SPACES_OPTION,
|
||||
"indent",
|
||||
"Each line of output shall be preceded by offset <space>s. If the -o option is not specified, the default offset
|
||||
shall be zero. The space taken is in addition to the output line width (see the -w option below).",
|
||||
"offset",
|
||||
HasArg::Yes,
|
||||
Occur::Optional,
|
||||
);
|
||||
|
||||
opts.optflag("", "help", "display this help and exit");
|
||||
opts.optflag("V", "version", "output version information and exit");
|
||||
|
||||
|
@ -297,21 +337,20 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
}
|
||||
|
||||
let mut files: Vec<String> = matches.free.clone();
|
||||
if files.is_empty() {
|
||||
// -n value is optional if -n <path> is given the opts gets confused
|
||||
if matches.opt_present(NUMBERING_MODE_OPTION) {
|
||||
let maybe_file = matches.opt_str(NUMBERING_MODE_OPTION).unwrap();
|
||||
let is_afile = is_a_file(&maybe_file);
|
||||
if !is_afile {
|
||||
print_error(&matches, PrError::NotExists(maybe_file));
|
||||
return 1;
|
||||
} else {
|
||||
files.push(maybe_file);
|
||||
}
|
||||
} else {
|
||||
//For stdin
|
||||
files.push(FILE_STDIN.to_owned());
|
||||
// -n value is optional if -n <path> is given the opts gets confused
|
||||
// if -n is used just before file path it might be captured as value of -n
|
||||
if matches.opt_str(NUMBERING_MODE_OPTION).is_some() {
|
||||
let maybe_a_file_path: String = matches.opt_str(NUMBERING_MODE_OPTION).unwrap();
|
||||
let is_file: bool = is_a_file(&maybe_a_file_path);
|
||||
if !is_file && files.is_empty() {
|
||||
print_error(&matches, PrError::NotExists(maybe_a_file_path));
|
||||
return 1;
|
||||
} else if is_file {
|
||||
files.insert(0, maybe_a_file_path);
|
||||
}
|
||||
} else if files.is_empty() {
|
||||
//For stdin
|
||||
files.insert(0, FILE_STDIN.to_owned());
|
||||
}
|
||||
|
||||
|
||||
|
@ -319,14 +358,25 @@ pub fn uumain(args: Vec<String>) -> i32 {
|
|||
return print_usage(&mut opts, &matches);
|
||||
}
|
||||
|
||||
for f in files {
|
||||
let result_options = build_options(&matches, &f);
|
||||
let file_groups: Vec<Vec<String>> = if matches.opt_present(MERGE_FILES_PRINT) {
|
||||
vec![files]
|
||||
} else {
|
||||
files.into_iter().map(|i| vec![i]).collect()
|
||||
};
|
||||
|
||||
for file_group in file_groups {
|
||||
let result_options: Result<OutputOptions, PrError> = build_options(&matches, &file_group);
|
||||
if result_options.is_err() {
|
||||
print_error(&matches, result_options.err().unwrap());
|
||||
return 1;
|
||||
}
|
||||
let options = &result_options.unwrap();
|
||||
let status: i32 = match pr(&f, options) {
|
||||
let options: &OutputOptions = &result_options.unwrap();
|
||||
let cmd_result: Result<i32, PrError> = if file_group.len() == 1 {
|
||||
pr(&file_group.get(0).unwrap(), options)
|
||||
} else {
|
||||
mpr(&file_group, options)
|
||||
};
|
||||
let status: i32 = match cmd_result {
|
||||
Err(error) => {
|
||||
print_error(&matches, error);
|
||||
1
|
||||
|
@ -385,22 +435,44 @@ fn print_usage(opts: &mut Options, matches: &Matches) -> i32 {
|
|||
return 0;
|
||||
}
|
||||
|
||||
fn build_options(matches: &Matches, path: &String) -> Result<OutputOptions, PrError> {
|
||||
let header: String = matches.opt_str(STRING_HEADER_OPTION).unwrap_or(if path == FILE_STDIN {
|
||||
fn build_options(matches: &Matches, paths: &Vec<String>) -> Result<OutputOptions, PrError> {
|
||||
let is_merge_mode: bool = matches.opt_present(MERGE_FILES_PRINT);
|
||||
|
||||
if is_merge_mode && matches.opt_present(COLUMN_OPTION) {
|
||||
let err_msg: String = "cannot specify number of columns when printing in parallel".to_string();
|
||||
return Err(PrError::EncounteredErrors(err_msg));
|
||||
}
|
||||
|
||||
if is_merge_mode && matches.opt_present(ACROSS_OPTION) {
|
||||
let err_msg: String = "cannot specify both printing across and printing in parallel".to_string();
|
||||
return Err(PrError::EncounteredErrors(err_msg));
|
||||
}
|
||||
|
||||
let merge_files_print: Option<usize> = if matches.opt_present(MERGE_FILES_PRINT) {
|
||||
Some(paths.len())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let header: String = matches.opt_str(STRING_HEADER_OPTION).unwrap_or(if is_merge_mode {
|
||||
"".to_string()
|
||||
} else {
|
||||
path.to_string()
|
||||
if paths[0].to_string() == FILE_STDIN {
|
||||
"".to_string()
|
||||
} else {
|
||||
paths[0].to_string()
|
||||
}
|
||||
});
|
||||
|
||||
let default_first_number = NumberingMode::default().first_number;
|
||||
let first_number = matches.opt_str(FIRST_LINE_NUMBER_OPTION).map(|n| {
|
||||
let default_first_number: usize = NumberingMode::default().first_number;
|
||||
let first_number: usize = matches.opt_str(FIRST_LINE_NUMBER_OPTION).map(|n| {
|
||||
n.parse::<usize>().unwrap_or(default_first_number)
|
||||
}).unwrap_or(default_first_number);
|
||||
|
||||
let numbering_options: Option<NumberingMode> = matches.opt_str(NUMBERING_MODE_OPTION).map(|i| {
|
||||
let parse_result = i.parse::<usize>();
|
||||
let parse_result: Result<usize, ParseIntError> = i.parse::<usize>();
|
||||
|
||||
let separator = if parse_result.is_err() {
|
||||
let separator: String = if parse_result.is_err() {
|
||||
if is_a_file(&i) {
|
||||
NumberingMode::default().separator
|
||||
} else {
|
||||
|
@ -410,7 +482,7 @@ fn build_options(matches: &Matches, path: &String) -> Result<OutputOptions, PrEr
|
|||
NumberingMode::default().separator
|
||||
};
|
||||
|
||||
let width = if parse_result.is_err() {
|
||||
let width: usize = if parse_result.is_err() {
|
||||
if is_a_file(&i) {
|
||||
NumberingMode::default().width
|
||||
} else {
|
||||
|
@ -432,7 +504,7 @@ fn build_options(matches: &Matches, path: &String) -> Result<OutputOptions, PrEr
|
|||
return None;
|
||||
});
|
||||
|
||||
let double_space = matches.opt_present(DOUBLE_SPACE_OPTION);
|
||||
let double_space: bool = matches.opt_present(DOUBLE_SPACE_OPTION);
|
||||
|
||||
let content_line_separator: String = if double_space {
|
||||
"\n\n".to_string()
|
||||
|
@ -442,21 +514,21 @@ fn build_options(matches: &Matches, path: &String) -> Result<OutputOptions, PrEr
|
|||
|
||||
let line_separator: String = "\n".to_string();
|
||||
|
||||
let last_modified_time = if path.eq(FILE_STDIN) {
|
||||
let last_modified_time: String = if is_merge_mode || paths[0].eq(FILE_STDIN) {
|
||||
current_time()
|
||||
} else {
|
||||
file_last_modified_time(path)
|
||||
file_last_modified_time(paths.get(0).unwrap())
|
||||
};
|
||||
|
||||
let invalid_pages_map = |i: Result<usize, ParseIntError>| {
|
||||
let unparsed_value = matches.opt_str(PAGE_RANGE_OPTION).unwrap();
|
||||
let unparsed_value: String = matches.opt_str(PAGE_RANGE_OPTION).unwrap();
|
||||
match i {
|
||||
Ok(val) => Ok(val),
|
||||
Err(_e) => Err(PrError::EncounteredErrors(format!("invalid --pages argument '{}'", unparsed_value)))
|
||||
}
|
||||
};
|
||||
|
||||
let start_page = match matches.opt_str(PAGE_RANGE_OPTION).map(|i| {
|
||||
let start_page: Option<usize> = match matches.opt_str(PAGE_RANGE_OPTION).map(|i| {
|
||||
let x: Vec<&str> = i.split(":").collect();
|
||||
x[0].parse::<usize>()
|
||||
}).map(invalid_pages_map)
|
||||
|
@ -465,9 +537,9 @@ fn build_options(matches: &Matches, path: &String) -> Result<OutputOptions, PrEr
|
|||
_ => None
|
||||
};
|
||||
|
||||
let end_page = match matches.opt_str(PAGE_RANGE_OPTION)
|
||||
.filter(|i| i.contains(":"))
|
||||
.map(|i| {
|
||||
let end_page: Option<usize> = match matches.opt_str(PAGE_RANGE_OPTION)
|
||||
.filter(|i: &String| i.contains(":"))
|
||||
.map(|i: String| {
|
||||
let x: Vec<&str> = i.split(":").collect();
|
||||
x[1].parse::<usize>()
|
||||
})
|
||||
|
@ -481,38 +553,38 @@ fn build_options(matches: &Matches, path: &String) -> Result<OutputOptions, PrEr
|
|||
return Err(PrError::EncounteredErrors(format!("invalid --pages argument '{}:{}'", start_page.unwrap(), end_page.unwrap())));
|
||||
}
|
||||
|
||||
let page_length = match matches.opt_str(PAGE_LENGTH_OPTION).map(|i| {
|
||||
let page_length: usize = match matches.opt_str(PAGE_LENGTH_OPTION).map(|i| {
|
||||
i.parse::<usize>()
|
||||
}) {
|
||||
Some(res) => res?,
|
||||
_ => LINES_PER_PAGE
|
||||
};
|
||||
let page_length_le_ht = page_length < (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE);
|
||||
let page_length_le_ht: bool = page_length < (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE);
|
||||
|
||||
let display_header_and_trailer = !(page_length_le_ht) && !matches.opt_present(NO_HEADER_TRAILER_OPTION);
|
||||
let display_header_and_trailer: bool = !(page_length_le_ht) && !matches.opt_present(NO_HEADER_TRAILER_OPTION);
|
||||
|
||||
let content_lines_per_page = if page_length_le_ht {
|
||||
let content_lines_per_page: usize = if page_length_le_ht {
|
||||
page_length
|
||||
} else {
|
||||
page_length - (HEADER_LINES_PER_PAGE + TRAILER_LINES_PER_PAGE)
|
||||
};
|
||||
|
||||
let page_separator_char = matches.opt_str(FORM_FEED_OPTION).map(|_i| {
|
||||
let page_separator_char: String = matches.opt_str(FORM_FEED_OPTION).map(|_i| {
|
||||
'\u{000A}'.to_string()
|
||||
}).unwrap_or("\n".to_string());
|
||||
|
||||
let column_width = match matches.opt_str(COLUMN_WIDTH_OPTION).map(|i| i.parse::<usize>()) {
|
||||
let column_width: Option<usize> = match matches.opt_str(COLUMN_WIDTH_OPTION).map(|i| i.parse::<usize>()) {
|
||||
Some(res) => Some(res?),
|
||||
_ => None
|
||||
};
|
||||
|
||||
let across_mode = matches.opt_present(ACROSS_OPTION);
|
||||
let across_mode: bool = matches.opt_present(ACROSS_OPTION);
|
||||
|
||||
let column_separator = matches.opt_str(COLUMN_SEPARATOR_OPTION)
|
||||
let column_separator: String = matches.opt_str(COLUMN_SEPARATOR_OPTION)
|
||||
.unwrap_or(DEFAULT_COLUMN_SEPARATOR.to_string());
|
||||
|
||||
|
||||
let column_mode_options = match matches.opt_str(COLUMN_OPTION).map(|i| {
|
||||
let column_mode_options: Option<ColumnModeOptions> = match matches.opt_str(COLUMN_OPTION).map(|i| {
|
||||
i.parse::<usize>()
|
||||
}) {
|
||||
Some(res) => {
|
||||
|
@ -529,6 +601,14 @@ fn build_options(matches: &Matches, path: &String) -> Result<OutputOptions, PrEr
|
|||
_ => None
|
||||
};
|
||||
|
||||
let offset_spaces: usize = matches.opt_str(OFFSET_SPACES_OPTION)
|
||||
.map(|i| {
|
||||
match i.parse::<usize>() {
|
||||
Ok(val)=> Ok(val),
|
||||
Err(e)=> Err(PrError::EncounteredErrors("".to_string()))
|
||||
}
|
||||
}).unwrap_or(Ok(0))?;
|
||||
|
||||
Ok(OutputOptions {
|
||||
number: numbering_options,
|
||||
header,
|
||||
|
@ -543,16 +623,18 @@ fn build_options(matches: &Matches, path: &String) -> Result<OutputOptions, PrEr
|
|||
content_lines_per_page,
|
||||
page_separator_char,
|
||||
column_mode_options,
|
||||
merge_files_print,
|
||||
offset_spaces,
|
||||
})
|
||||
}
|
||||
|
||||
fn open(path: &str) -> Result<Box<Read>, PrError> {
|
||||
if path == FILE_STDIN {
|
||||
let stdin = stdin();
|
||||
let stdin: Stdin = stdin();
|
||||
return Ok(Box::new(stdin) as Box<Read>);
|
||||
}
|
||||
|
||||
metadata(path).map(|i| {
|
||||
metadata(path).map(|i: Metadata| {
|
||||
let path_string = path.to_string();
|
||||
match i.file_type() {
|
||||
#[cfg(unix)]
|
||||
|
@ -582,50 +664,217 @@ fn open(path: &str) -> Result<Box<Read>, PrError> {
|
|||
}).unwrap_or(Err(PrError::NotExists(path.to_string())))
|
||||
}
|
||||
|
||||
fn pr(path: &str, options: &OutputOptions) -> Result<i32, PrError> {
|
||||
fn pr(path: &String, options: &OutputOptions) -> Result<i32, PrError> {
|
||||
let start_page: &usize = options.start_page.as_ref().unwrap_or(&1);
|
||||
let start_line_number: usize = get_start_line_number(options);
|
||||
let last_page: Option<&usize> = options.end_page.as_ref();
|
||||
let lines_needed_per_page: usize = lines_to_read_for_page(options);
|
||||
let start_line_number: usize = get_start_line_number(options);
|
||||
|
||||
let pages: GroupBy<usize, Map<TakeWhile<SkipWhile<Enumerate<Lines<BufReader<Box<Read>>>>, _>, _>, _>, _> =
|
||||
BufReader::with_capacity(READ_BUFFER_SIZE, open(path)?)
|
||||
let file_line_groups: GroupBy<usize, Map<TakeWhile<SkipWhile<Map<Enumerate<Lines<BufReader<Box<Read>>>>, _>, _>, _>, _>, _> =
|
||||
BufReader::with_capacity(READ_BUFFER_SIZE, open(path).unwrap())
|
||||
.lines()
|
||||
.enumerate()
|
||||
.skip_while(|line_index: &(usize, Result<String, Error>)| {
|
||||
// Skip the initial lines if not in page range
|
||||
let start_line_index_of_start_page = (*start_page - 1) * lines_needed_per_page;
|
||||
line_index.0 < (start_line_index_of_start_page)
|
||||
.map(move |i: (usize, Result<String, Error>)| {
|
||||
FileLine {
|
||||
file_id: 0,
|
||||
line_number: i.0,
|
||||
line_content: i.1,
|
||||
page_number: 0,
|
||||
key: 0,
|
||||
}
|
||||
})
|
||||
.take_while(|i: &(usize, Result<String, Error>)| {
|
||||
.skip_while(move |file_line: &FileLine| {
|
||||
// Skip the initial lines if not in page range
|
||||
let start_line_index_of_start_page = (start_page - 1) * lines_needed_per_page;
|
||||
file_line.line_number < (start_line_index_of_start_page)
|
||||
})
|
||||
.take_while(move |file_line: &FileLine| {
|
||||
// Only read the file until provided last page reached
|
||||
last_page
|
||||
.map(|lp| i.0 < ((*lp) * lines_needed_per_page))
|
||||
.map(|lp| file_line.line_number < ((*lp) * lines_needed_per_page))
|
||||
.unwrap_or(true)
|
||||
})
|
||||
.map(|i: (usize, Result<String, Error>)| (i.0 + start_line_number, i.1)) // get display line number with line content
|
||||
.group_by(|i: &(usize, Result<String, Error>)| {
|
||||
((i.0 - start_line_number + 1) as f64 / lines_needed_per_page as f64).ceil() as usize
|
||||
}); // group them by page number
|
||||
.map(move |file_line: FileLine| {
|
||||
let page_number = ((file_line.line_number + 1) as f64 / lines_needed_per_page as f64).ceil() as usize;
|
||||
FileLine {
|
||||
line_number: file_line.line_number + start_line_number,
|
||||
page_number,
|
||||
key: page_number,
|
||||
..file_line
|
||||
}
|
||||
}) // get display line number with line content
|
||||
.group_by(|file_line: &FileLine| {
|
||||
file_line.page_number
|
||||
});
|
||||
|
||||
|
||||
for (page_number, content_with_line_number) in pages.into_iter() {
|
||||
let mut lines: Vec<(usize, String)> = Vec::new();
|
||||
for line_number_and_line in content_with_line_number {
|
||||
let line_number: usize = line_number_and_line.0;
|
||||
let line: Result<String, Error> = line_number_and_line.1;
|
||||
let x = line?;
|
||||
lines.push((line_number, x));
|
||||
for (page_number, file_line_group) in file_line_groups.into_iter() {
|
||||
let mut lines: Vec<FileLine> = Vec::new();
|
||||
for file_line in file_line_group {
|
||||
if file_line.line_content.is_err() {
|
||||
return Err(PrError::from(file_line.line_content.unwrap_err()));
|
||||
}
|
||||
lines.push(file_line);
|
||||
}
|
||||
let print_status: Result<usize, Error> = print_page(&lines, options, &page_number);
|
||||
if print_status.is_err() {
|
||||
return Err(PrError::from(print_status.unwrap_err()));
|
||||
}
|
||||
|
||||
print_page(&lines, options, &page_number);
|
||||
}
|
||||
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
fn print_page(lines: &Vec<(usize, String)>, options: &OutputOptions, page: &usize) -> Result<usize, Error> {
|
||||
fn mpr(paths: &Vec<String>, options: &OutputOptions) -> Result<i32, PrError> {
|
||||
let nfiles = paths.len();
|
||||
|
||||
let lines_needed_per_page: usize = lines_to_read_for_page(options);
|
||||
let lines_needed_per_page_f64: f64 = lines_needed_per_page as f64;
|
||||
let start_page: &usize = options.start_page.as_ref().unwrap_or(&1);
|
||||
let last_page: Option<&usize> = options.end_page.as_ref();
|
||||
|
||||
let file_line_groups: GroupBy<usize, KMergeBy<Map<TakeWhile<SkipWhile<Map<Enumerate<Lines<BufReader<Box<Read>>>>, _>, _>, _>, _>, _>, _> = paths
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|indexed_path: (usize, &String)| {
|
||||
let start_line_number: usize = get_start_line_number(options);
|
||||
BufReader::with_capacity(READ_BUFFER_SIZE, open(indexed_path.1).unwrap())
|
||||
.lines()
|
||||
.enumerate()
|
||||
.map(move |i: (usize, Result<String, Error>)| {
|
||||
FileLine {
|
||||
file_id: indexed_path.0,
|
||||
line_number: i.0,
|
||||
line_content: i.1,
|
||||
page_number: 0,
|
||||
key: 0,
|
||||
}
|
||||
})
|
||||
.skip_while(move |file_line: &FileLine| {
|
||||
// Skip the initial lines if not in page range
|
||||
let start_line_index_of_start_page = (start_page - 1) * lines_needed_per_page;
|
||||
file_line.line_number < (start_line_index_of_start_page)
|
||||
})
|
||||
.take_while(move |file_line: &FileLine| {
|
||||
// Only read the file until provided last page reached
|
||||
|
||||
last_page
|
||||
.map(|lp| file_line.line_number < ((*lp) * lines_needed_per_page))
|
||||
.unwrap_or(true)
|
||||
})
|
||||
.map(move |file_line: FileLine| {
|
||||
let page_number = ((file_line.line_number + 2 - start_line_number) as f64 / (lines_needed_per_page_f64)).ceil() as usize;
|
||||
FileLine {
|
||||
line_number: file_line.line_number + start_line_number,
|
||||
page_number,
|
||||
key: page_number * nfiles + file_line.file_id,
|
||||
..file_line
|
||||
}
|
||||
}) // get display line number with line content
|
||||
})
|
||||
.kmerge_by(|a: &FileLine, b: &FileLine| {
|
||||
if a.key == b.key {
|
||||
a.line_number < b.line_number
|
||||
} else {
|
||||
a.key < b.key
|
||||
}
|
||||
})
|
||||
.group_by(|file_line: &FileLine| {
|
||||
file_line.key
|
||||
});
|
||||
|
||||
let mut lines: Vec<FileLine> = Vec::new();
|
||||
let start_page: &usize = options.start_page.as_ref().unwrap_or(&1);
|
||||
let mut page_counter: usize = *start_page;
|
||||
for (_key, file_line_group) in file_line_groups.into_iter() {
|
||||
for file_line in file_line_group {
|
||||
if file_line.line_content.is_err() {
|
||||
return Err(PrError::from(file_line.line_content.unwrap_err()));
|
||||
}
|
||||
let new_page_number = file_line.page_number;
|
||||
if page_counter != new_page_number {
|
||||
fill_missing_files(&mut lines, lines_needed_per_page, &nfiles, page_counter);
|
||||
let print_status: Result<usize, Error> = print_page(&lines, options, &page_counter);
|
||||
if print_status.is_err() {
|
||||
return Err(PrError::from(print_status.unwrap_err()));
|
||||
}
|
||||
lines = Vec::new();
|
||||
}
|
||||
lines.push(file_line);
|
||||
page_counter = new_page_number;
|
||||
}
|
||||
}
|
||||
|
||||
fill_missing_files(&mut lines, lines_needed_per_page, &nfiles, page_counter);
|
||||
let print_status: Result<usize, Error> = print_page(&lines, options, &page_counter);
|
||||
if print_status.is_err() {
|
||||
return Err(PrError::from(print_status.unwrap_err()));
|
||||
}
|
||||
|
||||
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
fn fill_missing_files(lines: &mut Vec<FileLine>, lines_per_file: usize, nfiles: &usize, page_number: usize) {
|
||||
let init_line_number = (page_number - 1) * lines_per_file + 1;
|
||||
let final_line_number = page_number * lines_per_file;
|
||||
let mut file_id_counter: usize = 0;
|
||||
let mut line_number_counter: usize = init_line_number;
|
||||
let mut lines_processed: usize = 0;
|
||||
let mut file_id_missing: bool = false;
|
||||
for mut i in 0..lines_per_file * nfiles {
|
||||
let file_id = lines.get(i).map(|i: &FileLine| i.file_id).unwrap_or(file_id_counter);
|
||||
let line_number = lines.get(i).map(|i: &FileLine| i.line_number).unwrap_or(1);
|
||||
if lines_processed == lines_per_file {
|
||||
line_number_counter = init_line_number;
|
||||
file_id_counter += 1;
|
||||
lines_processed = 0;
|
||||
file_id_missing = false;
|
||||
}
|
||||
|
||||
if file_id_counter >= *nfiles {
|
||||
file_id_counter = 0;
|
||||
file_id_missing = false;
|
||||
}
|
||||
|
||||
if file_id != file_id_counter {
|
||||
file_id_missing = true;
|
||||
}
|
||||
|
||||
if file_id_missing {
|
||||
// Insert missing file_ids
|
||||
lines.insert(i, FileLine {
|
||||
file_id: file_id_counter,
|
||||
line_number: line_number_counter,
|
||||
line_content: Ok("".to_string()),
|
||||
page_number,
|
||||
key: 0,
|
||||
});
|
||||
line_number_counter += 1;
|
||||
} else {
|
||||
// Insert missing lines for a file_id
|
||||
if line_number < line_number_counter {
|
||||
line_number_counter += 1;
|
||||
lines.insert(i, FileLine {
|
||||
file_id,
|
||||
line_number: line_number_counter,
|
||||
line_content: Ok("".to_string()),
|
||||
page_number,
|
||||
key: 0,
|
||||
});
|
||||
} else {
|
||||
line_number_counter = line_number;
|
||||
if line_number_counter == final_line_number {
|
||||
line_number_counter = init_line_number;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lines_processed += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn print_page(lines: &Vec<FileLine>, options: &OutputOptions, page: &usize) -> Result<usize, Error> {
|
||||
let page_separator = options.page_separator_char.as_bytes();
|
||||
let header: Vec<String> = header_content(options, page);
|
||||
let trailer_content: Vec<String> = trailer_content(options);
|
||||
|
@ -653,7 +902,7 @@ fn print_page(lines: &Vec<(usize, String)>, options: &OutputOptions, page: &usiz
|
|||
Ok(lines_written)
|
||||
}
|
||||
|
||||
fn write_columns(lines: &Vec<(usize, String)>, options: &OutputOptions, out: &mut Stdout) -> Result<usize, Error> {
|
||||
fn write_columns(lines: &Vec<FileLine>, options: &OutputOptions, out: &mut Stdout) -> Result<usize, Error> {
|
||||
let line_separator = options.content_line_separator.as_bytes();
|
||||
let content_lines_per_page = if options.double_space {
|
||||
options.content_lines_per_page / 2
|
||||
|
@ -671,26 +920,35 @@ fn write_columns(lines: &Vec<(usize, String)>, options: &OutputOptions, out: &mu
|
|||
.unwrap_or(NumberingMode::default().separator);
|
||||
|
||||
let blank_line = "".to_string();
|
||||
let columns = get_columns(options);
|
||||
|
||||
let columns = options.merge_files_print.unwrap_or(get_columns(options));
|
||||
let def_sep = DEFAULT_COLUMN_SEPARATOR.to_string();
|
||||
let col_sep: &String = options
|
||||
.column_mode_options.as_ref()
|
||||
.map(|i| &i.column_separator)
|
||||
.unwrap_or(&blank_line);
|
||||
.unwrap_or(options
|
||||
.merge_files_print
|
||||
.map(|_k| &def_sep)
|
||||
.unwrap_or(&blank_line)
|
||||
);
|
||||
|
||||
let col_width: Option<usize> = options
|
||||
.column_mode_options.as_ref()
|
||||
.map(|i| i.width)
|
||||
.unwrap_or(None);
|
||||
.unwrap_or(options
|
||||
.merge_files_print
|
||||
.map(|_k| Some(DEFAULT_COLUMN_WIDTH))
|
||||
.unwrap_or(None)
|
||||
);
|
||||
|
||||
let across_mode = options
|
||||
.column_mode_options.as_ref()
|
||||
.map(|i| i.across_mode)
|
||||
.unwrap_or(false);
|
||||
|
||||
let offset_spaces: &usize = &options.offset_spaces;
|
||||
|
||||
let mut lines_printed = 0;
|
||||
let is_number_mode = options.number.is_some();
|
||||
|
||||
let fetch_indexes: Vec<Vec<usize>> = if across_mode {
|
||||
(0..content_lines_per_page)
|
||||
.map(|a|
|
||||
|
@ -707,19 +965,20 @@ fn write_columns(lines: &Vec<(usize, String)>, options: &OutputOptions, out: &mu
|
|||
).collect()
|
||||
};
|
||||
|
||||
let spaces = " ".repeat(*offset_spaces);
|
||||
|
||||
for fetch_index in fetch_indexes {
|
||||
let indexes = fetch_index.len();
|
||||
for i in 0..indexes {
|
||||
let index = fetch_index[i];
|
||||
let index: usize = fetch_index[i];
|
||||
if lines.get(index).is_none() {
|
||||
break;
|
||||
}
|
||||
let read_line: &String = &lines.get(index).unwrap().1;
|
||||
let next_line_number: usize = lines.get(index).unwrap().0;
|
||||
let trimmed_line = get_line_for_printing(
|
||||
next_line_number, &width,
|
||||
&number_separator, columns, col_width,
|
||||
read_line, is_number_mode);
|
||||
let file_line: &FileLine = lines.get(index).unwrap();
|
||||
let trimmed_line: String = format!("{}{}", spaces, get_line_for_printing(
|
||||
file_line, &width, &number_separator, columns, col_width,
|
||||
is_number_mode, &options.merge_files_print, &i,
|
||||
));
|
||||
out.write(trimmed_line.as_bytes())?;
|
||||
if (i + 1) != indexes {
|
||||
out.write(col_sep.as_bytes())?;
|
||||
|
@ -731,16 +990,20 @@ fn write_columns(lines: &Vec<(usize, String)>, options: &OutputOptions, out: &mu
|
|||
Ok(lines_printed)
|
||||
}
|
||||
|
||||
fn get_line_for_printing(line_number: usize, width: &usize,
|
||||
fn get_line_for_printing(file_line: &FileLine, width: &usize,
|
||||
separator: &String, columns: usize,
|
||||
col_width: Option<usize>,
|
||||
read_line: &String, is_number_mode: bool) -> String {
|
||||
let fmtd_line_number: String = if is_number_mode {
|
||||
get_fmtd_line_number(&width, line_number, &separator)
|
||||
is_number_mode: bool, merge_files_print: &Option<usize>,
|
||||
index: &usize,
|
||||
) -> String {
|
||||
let should_show_line_number_merge_file = merge_files_print.is_none() || index == &usize::min_value();
|
||||
let should_show_line_number = is_number_mode && should_show_line_number_merge_file;
|
||||
let fmtd_line_number: String = if should_show_line_number {
|
||||
get_fmtd_line_number(&width, file_line.line_number, &separator)
|
||||
} else {
|
||||
"".to_string()
|
||||
};
|
||||
let mut complete_line = format!("{}{}", fmtd_line_number, read_line);
|
||||
let mut complete_line = format!("{}{}", fmtd_line_number, file_line.line_content.as_ref().unwrap());
|
||||
|
||||
let tab_count: usize = complete_line
|
||||
.chars()
|
||||
|
|
198
tests/fixtures/pr/column_spaces_across.log.expected
vendored
Normal file
198
tests/fixtures/pr/column_spaces_across.log.expected
vendored
Normal file
|
@ -0,0 +1,198 @@
|
|||
|
||||
|
||||
{last_modified_time} column.log Page 3
|
||||
|
||||
|
||||
337 337 338 338 339 339
|
||||
340 340 341 341 342 342
|
||||
343 343 344 344 345 345
|
||||
346 346 347 347 348 348
|
||||
349 349 350 350 351 351
|
||||
352 352 353 353 354 354
|
||||
355 355 356 356 357 357
|
||||
358 358 359 359 360 360
|
||||
361 361 362 362 363 363
|
||||
364 364 365 365 366 366
|
||||
367 367 368 368 369 369
|
||||
370 370 371 371 372 372
|
||||
373 373 374 374 375 375
|
||||
376 376 377 377 378 378
|
||||
379 379 380 380 381 381
|
||||
382 382 383 383 384 384
|
||||
385 385 386 386 387 387
|
||||
388 388 389 389 390 390
|
||||
391 391 392 392 393 393
|
||||
394 394 395 395 396 396
|
||||
397 397 398 398 399 399
|
||||
400 400 401 401 402 402
|
||||
403 403 404 404 405 405
|
||||
406 406 407 407 408 408
|
||||
409 409 410 410 411 411
|
||||
412 412 413 413 414 414
|
||||
415 415 416 416 417 417
|
||||
418 418 419 419 420 420
|
||||
421 421 422 422 423 423
|
||||
424 424 425 425 426 426
|
||||
427 427 428 428 429 429
|
||||
430 430 431 431 432 432
|
||||
433 433 434 434 435 435
|
||||
436 436 437 437 438 438
|
||||
439 439 440 440 441 441
|
||||
442 442 443 443 444 444
|
||||
445 445 446 446 447 447
|
||||
448 448 449 449 450 450
|
||||
451 451 452 452 453 453
|
||||
454 454 455 455 456 456
|
||||
457 457 458 458 459 459
|
||||
460 460 461 461 462 462
|
||||
463 463 464 464 465 465
|
||||
466 466 467 467 468 468
|
||||
469 469 470 470 471 471
|
||||
472 472 473 473 474 474
|
||||
475 475 476 476 477 477
|
||||
478 478 479 479 480 480
|
||||
481 481 482 482 483 483
|
||||
484 484 485 485 486 486
|
||||
487 487 488 488 489 489
|
||||
490 490 491 491 492 492
|
||||
493 493 494 494 495 495
|
||||
496 496 497 497 498 498
|
||||
499 499 500 500 501 501
|
||||
502 502 503 503 504 504
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{last_modified_time} column.log Page 4
|
||||
|
||||
|
||||
505 505 506 506 507 507
|
||||
508 508 509 509 510 510
|
||||
511 511 512 512 513 513
|
||||
514 514 515 515 516 516
|
||||
517 517 518 518 519 519
|
||||
520 520 521 521 522 522
|
||||
523 523 524 524 525 525
|
||||
526 526 527 527 528 528
|
||||
529 529 530 530 531 531
|
||||
532 532 533 533 534 534
|
||||
535 535 536 536 537 537
|
||||
538 538 539 539 540 540
|
||||
541 541 542 542 543 543
|
||||
544 544 545 545 546 546
|
||||
547 547 548 548 549 549
|
||||
550 550 551 551 552 552
|
||||
553 553 554 554 555 555
|
||||
556 556 557 557 558 558
|
||||
559 559 560 560 561 561
|
||||
562 562 563 563 564 564
|
||||
565 565 566 566 567 567
|
||||
568 568 569 569 570 570
|
||||
571 571 572 572 573 573
|
||||
574 574 575 575 576 576
|
||||
577 577 578 578 579 579
|
||||
580 580 581 581 582 582
|
||||
583 583 584 584 585 585
|
||||
586 586 587 587 588 588
|
||||
589 589 590 590 591 591
|
||||
592 592 593 593 594 594
|
||||
595 595 596 596 597 597
|
||||
598 598 599 599 600 600
|
||||
601 601 602 602 603 603
|
||||
604 604 605 605 606 606
|
||||
607 607 608 608 609 609
|
||||
610 610 611 611 612 612
|
||||
613 613 614 614 615 615
|
||||
616 616 617 617 618 618
|
||||
619 619 620 620 621 621
|
||||
622 622 623 623 624 624
|
||||
625 625 626 626 627 627
|
||||
628 628 629 629 630 630
|
||||
631 631 632 632 633 633
|
||||
634 634 635 635 636 636
|
||||
637 637 638 638 639 639
|
||||
640 640 641 641 642 642
|
||||
643 643 644 644 645 645
|
||||
646 646 647 647 648 648
|
||||
649 649 650 650 651 651
|
||||
652 652 653 653 654 654
|
||||
655 655 656 656 657 657
|
||||
658 658 659 659 660 660
|
||||
661 661 662 662 663 663
|
||||
664 664 665 665 666 666
|
||||
667 667 668 668 669 669
|
||||
670 670 671 671 672 672
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{last_modified_time} column.log Page 5
|
||||
|
||||
|
||||
673 673 674 674 675 675
|
||||
676 676 677 677 678 678
|
||||
679 679 680 680 681 681
|
||||
682 682 683 683 684 684
|
||||
685 685 686 686 687 687
|
||||
688 688 689 689 690 690
|
||||
691 691 692 692 693 693
|
||||
694 694 695 695 696 696
|
||||
697 697 698 698 699 699
|
||||
700 700 701 701 702 702
|
||||
703 703 704 704 705 705
|
||||
706 706 707 707 708 708
|
||||
709 709 710 710 711 711
|
||||
712 712 713 713 714 714
|
||||
715 715 716 716 717 717
|
||||
718 718 719 719 720 720
|
||||
721 721 722 722 723 723
|
||||
724 724 725 725 726 726
|
||||
727 727 728 728 729 729
|
||||
730 730 731 731 732 732
|
||||
733 733 734 734 735 735
|
||||
736 736 737 737 738 738
|
||||
739 739 740 740 741 741
|
||||
742 742 743 743 744 744
|
||||
745 745 746 746 747 747
|
||||
748 748 749 749 750 750
|
||||
751 751 752 752 753 753
|
||||
754 754 755 755 756 756
|
||||
757 757 758 758 759 759
|
||||
760 760 761 761 762 762
|
||||
763 763 764 764 765 765
|
||||
766 766 767 767 768 768
|
||||
769 769 770 770 771 771
|
||||
772 772 773 773 774 774
|
||||
775 775 776 776 777 777
|
||||
778 778 779 779 780 780
|
||||
781 781 782 782 783 783
|
||||
784 784 785 785 786 786
|
||||
787 787 788 788 789 789
|
||||
790 790 791 791 792 792
|
||||
793 793 794 794 795 795
|
||||
796 796 797 797 798 798
|
||||
799 799 800 800 801 801
|
||||
802 802 803 803 804 804
|
||||
805 805 806 806 807 807
|
||||
808 808 809 809 810 810
|
||||
811 811 812 812 813 813
|
||||
814 814 815 815 816 816
|
||||
817 817 818 818 819 819
|
||||
820 820 821 821 822 822
|
||||
823 823 824 824 825 825
|
||||
826 826 827 827 828 828
|
||||
829 829 830 830 831 831
|
||||
832 832 833 833 834 834
|
||||
835 835 836 836 837 837
|
||||
838 838 839 839 840 840
|
||||
|
||||
|
||||
|
||||
|
||||
|
11
tests/fixtures/pr/hosts.log
vendored
Normal file
11
tests/fixtures/pr/hosts.log
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
##
|
||||
# Host Database
|
||||
#
|
||||
# localhost is used to configure the loopback interface
|
||||
# when the system is booting. Do not change this entry.
|
||||
##
|
||||
127.0.0.1 localhost
|
||||
127.0.0.1 Techopss-MacBook-Pro.local
|
||||
127.0.0.1 tilakpr
|
||||
255.255.255.255 broadcasthost
|
||||
::1 localhost
|
132
tests/fixtures/pr/mpr.log.expected
vendored
Normal file
132
tests/fixtures/pr/mpr.log.expected
vendored
Normal file
|
@ -0,0 +1,132 @@
|
|||
|
||||
|
||||
{last_modified_time} Page 1
|
||||
|
||||
|
||||
1 1 ##
|
||||
2 2 # Host Database
|
||||
3 3 #
|
||||
4 4 # localhost is used to configure th
|
||||
5 5 # when the system is booting. Do n
|
||||
6 6 ##
|
||||
7 7 127.0.0.1 localhost
|
||||
8 8 127.0.0.1 Techopss-MacBook-Pro.loca
|
||||
9 9 127.0.0.1 tilakpr
|
||||
10 10 255.255.255.255 broadcasthost
|
||||
11 11 ::1 localhost
|
||||
12 12
|
||||
13 13
|
||||
14 14
|
||||
15 15
|
||||
16 16
|
||||
17 17
|
||||
18 18
|
||||
19 19
|
||||
20 20
|
||||
21 21
|
||||
22 22
|
||||
23 23
|
||||
24 24
|
||||
25 25
|
||||
26 26
|
||||
27 27
|
||||
28 28
|
||||
29 29
|
||||
30 30
|
||||
31 31
|
||||
32 32
|
||||
33 33
|
||||
34 34
|
||||
35 35
|
||||
36 36
|
||||
37 37
|
||||
38 38
|
||||
39 39
|
||||
40 40
|
||||
41 41
|
||||
42 42
|
||||
43 43
|
||||
44 44
|
||||
45 45
|
||||
46 46
|
||||
47 47
|
||||
48 48
|
||||
49 49
|
||||
50 50
|
||||
51 51
|
||||
52 52
|
||||
53 53
|
||||
54 54
|
||||
55 55
|
||||
56 56
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{last_modified_time} Page 2
|
||||
|
||||
|
||||
57 57
|
||||
58 58
|
||||
59 59
|
||||
60 60
|
||||
61 61
|
||||
62 62
|
||||
63 63
|
||||
64 64
|
||||
65 65
|
||||
66 66
|
||||
67 67
|
||||
68 68
|
||||
69 69
|
||||
70 70
|
||||
71 71
|
||||
72 72
|
||||
73 73
|
||||
74 74
|
||||
75 75
|
||||
76 76
|
||||
77 77
|
||||
78 78
|
||||
79 79
|
||||
80 80
|
||||
81 81
|
||||
82 82
|
||||
83 83
|
||||
84 84
|
||||
85 85
|
||||
86 86
|
||||
87 87
|
||||
88 88
|
||||
89 89
|
||||
90 90
|
||||
91 91
|
||||
92 92
|
||||
93 93
|
||||
94 94
|
||||
95 95
|
||||
96 96
|
||||
97 97
|
||||
98 98
|
||||
99 99
|
||||
100 100
|
||||
101 101
|
||||
102 102
|
||||
103 103
|
||||
104 104
|
||||
105 105
|
||||
106 106
|
||||
107 107
|
||||
108 108
|
||||
109 109
|
||||
110 110
|
||||
111 111
|
||||
112 112
|
||||
|
||||
|
||||
|
||||
|
||||
|
198
tests/fixtures/pr/mpr1.log.expected
vendored
Normal file
198
tests/fixtures/pr/mpr1.log.expected
vendored
Normal file
|
@ -0,0 +1,198 @@
|
|||
|
||||
|
||||
{last_modified_time} Page 2
|
||||
|
||||
|
||||
57 57
|
||||
58 58
|
||||
59 59
|
||||
60 60
|
||||
61 61
|
||||
62 62
|
||||
63 63
|
||||
64 64
|
||||
65 65
|
||||
66 66
|
||||
67 67
|
||||
68 68
|
||||
69 69
|
||||
70 70
|
||||
71 71
|
||||
72 72
|
||||
73 73
|
||||
74 74
|
||||
75 75
|
||||
76 76
|
||||
77 77
|
||||
78 78
|
||||
79 79
|
||||
80 80
|
||||
81 81
|
||||
82 82
|
||||
83 83
|
||||
84 84
|
||||
85 85
|
||||
86 86
|
||||
87 87
|
||||
88 88
|
||||
89 89
|
||||
90 90
|
||||
91 91
|
||||
92 92
|
||||
93 93
|
||||
94 94
|
||||
95 95
|
||||
96 96
|
||||
97 97
|
||||
98 98
|
||||
99 99
|
||||
100 100
|
||||
101 101
|
||||
102 102
|
||||
103 103
|
||||
104 104
|
||||
105 105
|
||||
106 106
|
||||
107 107
|
||||
108 108
|
||||
109 109
|
||||
110 110
|
||||
111 111
|
||||
112 112
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{last_modified_time} Page 3
|
||||
|
||||
|
||||
113 113
|
||||
114 114
|
||||
115 115
|
||||
116 116
|
||||
117 117
|
||||
118 118
|
||||
119 119
|
||||
120 120
|
||||
121 121
|
||||
122 122
|
||||
123 123
|
||||
124 124
|
||||
125 125
|
||||
126 126
|
||||
127 127
|
||||
128 128
|
||||
129 129
|
||||
130 130
|
||||
131 131
|
||||
132 132
|
||||
133 133
|
||||
134 134
|
||||
135 135
|
||||
136 136
|
||||
137 137
|
||||
138 138
|
||||
139 139
|
||||
140 140
|
||||
141 141
|
||||
142 142
|
||||
143 143
|
||||
144 144
|
||||
145 145
|
||||
146 146
|
||||
147 147
|
||||
148 148
|
||||
149 149
|
||||
150 150
|
||||
151 151
|
||||
152 152
|
||||
153 153
|
||||
154 154
|
||||
155 155
|
||||
156 156
|
||||
157 157
|
||||
158 158
|
||||
159 159
|
||||
160 160
|
||||
161 161
|
||||
162 162
|
||||
163 163
|
||||
164 164
|
||||
165 165
|
||||
166 166
|
||||
167 167
|
||||
168 168
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{last_modified_time} Page 4
|
||||
|
||||
|
||||
169 169
|
||||
170 170
|
||||
171 171
|
||||
172 172
|
||||
173 173
|
||||
174 174
|
||||
175 175
|
||||
176 176
|
||||
177 177
|
||||
178 178
|
||||
179 179
|
||||
180 180
|
||||
181 181
|
||||
182 182
|
||||
183 183
|
||||
184 184
|
||||
185 185
|
||||
186 186
|
||||
187 187
|
||||
188 188
|
||||
189 189
|
||||
190 190
|
||||
191 191
|
||||
192 192
|
||||
193 193
|
||||
194 194
|
||||
195 195
|
||||
196 196
|
||||
197 197
|
||||
198 198
|
||||
199 199
|
||||
200 200
|
||||
201 201
|
||||
202 202
|
||||
203 203
|
||||
204 204
|
||||
205 205
|
||||
206 206
|
||||
207 207
|
||||
208 208
|
||||
209 209
|
||||
210 210
|
||||
211 211
|
||||
212 212
|
||||
213 213
|
||||
214 214
|
||||
215 215
|
||||
216 216
|
||||
217 217
|
||||
218 218
|
||||
219 219
|
||||
220 220
|
||||
221 221
|
||||
222 222
|
||||
223 223
|
||||
224 224
|
||||
|
||||
|
||||
|
||||
|
||||
|
200
tests/fixtures/pr/mpr2.log.expected
vendored
Normal file
200
tests/fixtures/pr/mpr2.log.expected
vendored
Normal file
|
@ -0,0 +1,200 @@
|
|||
|
||||
|
||||
{last_modified_time} Page 1
|
||||
|
||||
|
||||
1 1 ## 1
|
||||
2 2 # Host Database 2
|
||||
3 3 # 3
|
||||
4 4 # localhost is used to 4
|
||||
5 5 # when the system is bo 5
|
||||
6 6 ## 6
|
||||
7 7 127.0.0.1 localhost 7
|
||||
8 8 127.0.0.1 Techopss-MacB 8
|
||||
9 9 127.0.0.1 tilakpr 9
|
||||
10 10 255.255.255.255 broadca 10
|
||||
11 11 ::1 localho 11
|
||||
12 12 12
|
||||
13 13 13
|
||||
14 14 14
|
||||
15 15 15
|
||||
16 16 16
|
||||
17 17 17
|
||||
18 18 18
|
||||
19 19 19
|
||||
20 20 20
|
||||
21 21 21
|
||||
22 22 22
|
||||
23 23 23
|
||||
24 24 24
|
||||
25 25 25
|
||||
26 26 26
|
||||
27 27 27
|
||||
28 28 28
|
||||
29 29 29
|
||||
30 30 30
|
||||
31 31 31
|
||||
32 32 32
|
||||
33 33 33
|
||||
34 34 34
|
||||
35 35 35
|
||||
36 36 36
|
||||
37 37 37
|
||||
38 38 38
|
||||
39 39 39
|
||||
40 40 40
|
||||
41 41 41
|
||||
42 42 42
|
||||
43 43 43
|
||||
44 44 44
|
||||
45 45 45
|
||||
46 46 46
|
||||
47 47 47
|
||||
48 48 48
|
||||
49 49 49
|
||||
50 50 50
|
||||
51 51 51
|
||||
52 52 52
|
||||
53 53 53
|
||||
54 54 54
|
||||
55 55 55
|
||||
56 56 56
|
||||
57 57 57
|
||||
58 58 58
|
||||
59 59 59
|
||||
60 60 60
|
||||
61 61 61
|
||||
62 62 62
|
||||
63 63 63
|
||||
64 64 64
|
||||
65 65 65
|
||||
66 66 66
|
||||
67 67 67
|
||||
68 68 68
|
||||
69 69 69
|
||||
70 70 70
|
||||
71 71 71
|
||||
72 72 72
|
||||
73 73 73
|
||||
74 74 74
|
||||
75 75 75
|
||||
76 76 76
|
||||
77 77 77
|
||||
78 78 78
|
||||
79 79 79
|
||||
80 80 80
|
||||
81 81 81
|
||||
82 82 82
|
||||
83 83 83
|
||||
84 84 84
|
||||
85 85 85
|
||||
86 86 86
|
||||
87 87 87
|
||||
88 88 88
|
||||
89 89 89
|
||||
90 90 90
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
{last_modified_time} Page 2
|
||||
|
||||
|
||||
91 91 91
|
||||
92 92 92
|
||||
93 93 93
|
||||
94 94 94
|
||||
95 95 95
|
||||
96 96 96
|
||||
97 97 97
|
||||
98 98 98
|
||||
99 99 99
|
||||
100 100 100
|
||||
101 101 101
|
||||
102 102 102
|
||||
103 103 103
|
||||
104 104 104
|
||||
105 105 105
|
||||
106 106 106
|
||||
107 107 107
|
||||
108 108 108
|
||||
109 109 109
|
||||
110 110 110
|
||||
111 111 111
|
||||
112 112 112
|
||||
113 113 113
|
||||
114 114 114
|
||||
115 115 115
|
||||
116 116 116
|
||||
117 117 117
|
||||
118 118 118
|
||||
119 119 119
|
||||
120 120 120
|
||||
121 121 121
|
||||
122 122 122
|
||||
123 123 123
|
||||
124 124 124
|
||||
125 125 125
|
||||
126 126 126
|
||||
127 127 127
|
||||
128 128 128
|
||||
129 129 129
|
||||
130 130 130
|
||||
131 131 131
|
||||
132 132 132
|
||||
133 133 133
|
||||
134 134 134
|
||||
135 135 135
|
||||
136 136 136
|
||||
137 137 137
|
||||
138 138 138
|
||||
139 139 139
|
||||
140 140 140
|
||||
141 141 141
|
||||
142 142 142
|
||||
143 143 143
|
||||
144 144 144
|
||||
145 145 145
|
||||
146 146 146
|
||||
147 147 147
|
||||
148 148 148
|
||||
149 149 149
|
||||
150 150 150
|
||||
151 151 151
|
||||
152 152 152
|
||||
153 153 153
|
||||
154 154 154
|
||||
155 155 155
|
||||
156 156 156
|
||||
157 157 157
|
||||
158 158 158
|
||||
159 159 159
|
||||
160 160 160
|
||||
161 161 161
|
||||
162 162 162
|
||||
163 163 163
|
||||
164 164 164
|
||||
165 165 165
|
||||
166 166 166
|
||||
167 167 167
|
||||
168 168 168
|
||||
169 169 169
|
||||
170 170 170
|
||||
171 171 171
|
||||
172 172 172
|
||||
173 173 173
|
||||
174 174 174
|
||||
175 175 175
|
||||
176 176 176
|
||||
177 177 177
|
||||
178 178 178
|
||||
179 179 179
|
||||
180 180 180
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -282,7 +282,6 @@ fn test_with_suppress_error_option() {
|
|||
|
||||
#[test]
|
||||
fn test_with_stdin() {
|
||||
let test_file_path = "stdin.log";
|
||||
let expected_file_path = "stdin.log.expected";
|
||||
let mut scenario = new_ucmd!();
|
||||
scenario
|
||||
|
@ -306,7 +305,6 @@ fn test_with_column() {
|
|||
.stdout_is_templated_fixture(expected_test_file_path, vec![
|
||||
(&"{last_modified_time}".to_string(), &value),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -321,7 +319,6 @@ fn test_with_column_across_option() {
|
|||
.stdout_is_templated_fixture(expected_test_file_path, vec![
|
||||
(&"{last_modified_time}".to_string(), &value),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -336,6 +333,64 @@ fn test_with_column_across_option_and_column_separator() {
|
|||
.stdout_is_templated_fixture(expected_test_file_path, vec![
|
||||
(&"{last_modified_time}".to_string(), &value),
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_mpr() {
|
||||
let test_file_path = "column.log";
|
||||
let test_file_path1 = "hosts.log";
|
||||
let expected_test_file_path = "mpr.log.expected";
|
||||
let expected_test_file_path1 = "mpr1.log.expected";
|
||||
let expected_test_file_path2 = "mpr2.log.expected";
|
||||
new_ucmd!()
|
||||
.args(&["--pages=1:2", "-m", "-n", test_file_path, test_file_path1])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(expected_test_file_path, vec![
|
||||
(&"{last_modified_time}".to_string(), &now_time()),
|
||||
]);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["--pages=2:4", "-m", "-n", test_file_path, test_file_path1])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(expected_test_file_path1, vec![
|
||||
(&"{last_modified_time}".to_string(), &now_time()),
|
||||
]);
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["--pages=1:2", "-l", "100", "-n", "-m", test_file_path, test_file_path1, test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(expected_test_file_path2, vec![
|
||||
(&"{last_modified_time}".to_string(), &now_time()),
|
||||
]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_with_mpr_and_column_options() {
|
||||
let test_file_path = "column.log";
|
||||
new_ucmd!()
|
||||
.args(&["--column=2", "-m", "-n", test_file_path])
|
||||
.fails()
|
||||
.stderr_is("pr: cannot specify number of columns when printing in parallel")
|
||||
.stdout_is("");
|
||||
|
||||
new_ucmd!()
|
||||
.args(&["-a", "-m", "-n", test_file_path])
|
||||
.fails()
|
||||
.stderr_is("pr: cannot specify both printing across and printing in parallel")
|
||||
.stdout_is("");
|
||||
}
|
||||
|
||||
|
||||
#[test]
|
||||
fn test_with_offset_space_option() {
|
||||
let test_file_path = "column.log";
|
||||
let expected_test_file_path = "column_spaces_across.log.expected";
|
||||
let mut scenario = new_ucmd!();
|
||||
let value = file_last_modified_time(&scenario, test_file_path);
|
||||
scenario
|
||||
.args(&["-o", "5", "--pages=3:5", "--column=3", "-a", "-n", test_file_path])
|
||||
.succeeds()
|
||||
.stdout_is_templated_fixture(expected_test_file_path, vec![
|
||||
(&"{last_modified_time}".to_string(), &value),
|
||||
]);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue