mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
cat: move cat to clap (#1910)
This commit is contained in:
parent
035f811dd0
commit
83f8140aaf
2 changed files with 109 additions and 34 deletions
|
@ -15,6 +15,7 @@ edition = "2018"
|
|||
path = "src/cat.rs"
|
||||
|
||||
[dependencies]
|
||||
clap = "2.33"
|
||||
quick-error = "1.2.3"
|
||||
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["fs"] }
|
||||
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
|
||||
|
|
|
@ -17,6 +17,7 @@ extern crate unix_socket;
|
|||
extern crate uucore;
|
||||
|
||||
// last synced with: cat (GNU coreutils) 8.13
|
||||
use clap::{App, Arg};
|
||||
use quick_error::ResultExt;
|
||||
use std::fs::{metadata, File};
|
||||
use std::io::{self, stderr, stdin, stdout, BufWriter, Read, Write};
|
||||
|
@ -30,10 +31,11 @@ use std::os::unix::fs::FileTypeExt;
|
|||
#[cfg(unix)]
|
||||
use unix_socket::UnixStream;
|
||||
|
||||
static NAME: &str = "cat";
|
||||
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
static SYNTAX: &str = "[OPTION]... [FILE]...";
|
||||
static SUMMARY: &str = "Concatenate FILE(s), or standard input, to standard output
|
||||
With no FILE, or when FILE is -, read standard input.";
|
||||
static LONG_HELP: &str = "";
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum NumberingMode {
|
||||
|
@ -124,50 +126,122 @@ enum InputType {
|
|||
|
||||
type CatResult<T> = Result<T, CatError>;
|
||||
|
||||
mod options {
|
||||
pub static FILE: &str = "file";
|
||||
pub static SHOW_ALL: &str = "show-all";
|
||||
pub static NUMBER_NONBLANK: &str = "number-nonblank";
|
||||
pub static SHOW_NONPRINTING_ENDS: &str = "e";
|
||||
pub static SHOW_ENDS: &str = "show-ends";
|
||||
pub static NUMBER: &str = "number";
|
||||
pub static SQUEEZE_BLANK: &str = "squeeze-blank";
|
||||
pub static SHOW_NONPRINTING_TABS: &str = "t";
|
||||
pub static SHOW_TABS: &str = "show-tabs";
|
||||
pub static SHOW_NONPRINTING: &str = "show-nonprinting";
|
||||
}
|
||||
|
||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||
let args = args.collect_str();
|
||||
|
||||
let matches = app!(SYNTAX, SUMMARY, LONG_HELP)
|
||||
.optflag("A", "show-all", "equivalent to -vET")
|
||||
.optflag(
|
||||
"b",
|
||||
"number-nonblank",
|
||||
"number nonempty output lines, overrides -n",
|
||||
let matches = App::new(executable!())
|
||||
.name(NAME)
|
||||
.version(VERSION)
|
||||
.usage(SYNTAX)
|
||||
.about(SUMMARY)
|
||||
.arg(Arg::with_name(options::FILE).hidden(true).multiple(true))
|
||||
.arg(
|
||||
Arg::with_name(options::SHOW_ALL)
|
||||
.short("A")
|
||||
.long(options::SHOW_ALL)
|
||||
.help("equivalent to -vET"),
|
||||
)
|
||||
.optflag("e", "", "equivalent to -vE")
|
||||
.optflag("E", "show-ends", "display $ at end of each line")
|
||||
.optflag("n", "number", "number all output lines")
|
||||
.optflag("s", "squeeze-blank", "suppress repeated empty output lines")
|
||||
.optflag("t", "", "equivalent to -vT")
|
||||
.optflag("T", "show-tabs", "display TAB characters as ^I")
|
||||
.optflag(
|
||||
"v",
|
||||
"show-nonprinting",
|
||||
"use ^ and M- notation, except for LF (\\n) and TAB (\\t)",
|
||||
.arg(
|
||||
Arg::with_name(options::NUMBER_NONBLANK)
|
||||
.short("b")
|
||||
.long(options::NUMBER_NONBLANK)
|
||||
.help("number nonempty output lines, overrides -n")
|
||||
.overrides_with(options::NUMBER),
|
||||
)
|
||||
.parse(args);
|
||||
.arg(
|
||||
Arg::with_name(options::SHOW_NONPRINTING_ENDS)
|
||||
.short("e")
|
||||
.help("equivalent to -vE"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::SHOW_ENDS)
|
||||
.short("E")
|
||||
.long(options::SHOW_ENDS)
|
||||
.help("display $ at end of each line"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::NUMBER)
|
||||
.short("n")
|
||||
.long(options::NUMBER)
|
||||
.help("number all output lines"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::SQUEEZE_BLANK)
|
||||
.short("s")
|
||||
.long(options::SQUEEZE_BLANK)
|
||||
.help("suppress repeated empty output lines"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::SHOW_NONPRINTING_TABS)
|
||||
.short("t")
|
||||
.long(options::SHOW_NONPRINTING_TABS)
|
||||
.help("equivalent to -vT"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::SHOW_TABS)
|
||||
.short("T")
|
||||
.long(options::SHOW_TABS)
|
||||
.help("display TAB characters at ^I"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::SHOW_NONPRINTING)
|
||||
.short("v")
|
||||
.long(options::SHOW_NONPRINTING)
|
||||
.help("use ^ and M- notation, except for LF (\\n) and TAB (\\t)"),
|
||||
)
|
||||
.get_matches_from(args);
|
||||
|
||||
let number_mode = if matches.opt_present("b") {
|
||||
let number_mode = if matches.is_present(options::NUMBER_NONBLANK) {
|
||||
NumberingMode::NonEmpty
|
||||
} else if matches.opt_present("n") {
|
||||
} else if matches.is_present(options::NUMBER) {
|
||||
NumberingMode::All
|
||||
} else {
|
||||
NumberingMode::None
|
||||
};
|
||||
|
||||
let show_nonprint = matches.opts_present(&[
|
||||
"A".to_owned(),
|
||||
"e".to_owned(),
|
||||
"t".to_owned(),
|
||||
"v".to_owned(),
|
||||
]);
|
||||
let show_ends = matches.opts_present(&["E".to_owned(), "A".to_owned(), "e".to_owned()]);
|
||||
let show_tabs = matches.opts_present(&["A".to_owned(), "T".to_owned(), "t".to_owned()]);
|
||||
let squeeze_blank = matches.opt_present("s");
|
||||
let mut files = matches.free;
|
||||
if files.is_empty() {
|
||||
files.push("-".to_owned());
|
||||
}
|
||||
let show_nonprint = vec![
|
||||
options::SHOW_ALL.to_owned(),
|
||||
options::SHOW_NONPRINTING_ENDS.to_owned(),
|
||||
options::SHOW_NONPRINTING_TABS.to_owned(),
|
||||
options::SHOW_NONPRINTING.to_owned(),
|
||||
]
|
||||
.iter()
|
||||
.any(|v| matches.is_present(v));
|
||||
|
||||
let show_ends = vec![
|
||||
options::SHOW_ENDS.to_owned(),
|
||||
options::SHOW_ALL.to_owned(),
|
||||
options::SHOW_NONPRINTING_ENDS.to_owned(),
|
||||
]
|
||||
.iter()
|
||||
.any(|v| matches.is_present(v));
|
||||
|
||||
let show_tabs = vec![
|
||||
options::SHOW_ALL.to_owned(),
|
||||
options::SHOW_TABS.to_owned(),
|
||||
options::SHOW_NONPRINTING_TABS.to_owned(),
|
||||
]
|
||||
.iter()
|
||||
.any(|v| matches.is_present(v));
|
||||
|
||||
let squeeze_blank = matches.is_present(options::SQUEEZE_BLANK);
|
||||
let files: Vec<String> = match matches.values_of(options::FILE) {
|
||||
Some(v) => v.clone().map(|v| v.to_owned()).collect(),
|
||||
None => vec!["-".to_owned()],
|
||||
};
|
||||
|
||||
let can_write_fast = !(show_tabs
|
||||
|| show_nonprint
|
||||
|
@ -361,7 +435,7 @@ fn write_file_lines(file: &str, options: &OutputOptions, state: &mut OutputState
|
|||
}
|
||||
writer.write_all(options.end_of_line.as_bytes())?;
|
||||
if handle.is_interactive {
|
||||
writer.flush().context(&file[..])?;
|
||||
writer.flush().context(file)?;
|
||||
}
|
||||
}
|
||||
state.at_line_start = true;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue