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