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

Merge pull request #961 from nathanross/coreopts-further-refinement

Coreopts further refinement
This commit is contained in:
Jian Zeng 2016-08-12 12:00:20 +08:00 committed by GitHub
commit 9b82387960
7 changed files with 189 additions and 191 deletions

View file

@ -18,6 +18,10 @@ use std::ffi::CStr;
use std::mem::uninitialized;
use uucore::c_types::utsname;
static SYNTAX: &'static str = "";
static SUMMARY: &'static str = "Determine architecture name for current machine.";
static LONG_HELP: &'static str = "";
struct Arch {
arch_name: String
}
@ -38,19 +42,8 @@ unsafe fn get_machine_arch() -> Arch {
}
}
static NAME: &'static str = "arch";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = uucore::coreopts::CoreOptions::new(NAME);
let usage = opts.usage("Determine architecture name for current machine.");
opts.help(format!("
{0} {1}
{0}
{2}
", NAME, VERSION, usage)).parse(args);
new_coreopts!(SYNTAX, SUMMARY, LONG_HELP).parse(args);
let machine_arch = unsafe { get_machine_arch() };
let mut output = String::new();

View file

@ -25,8 +25,87 @@ mod buffer;
mod ranges;
mod searcher;
static NAME: &'static str = "cut";
static VERSION: &'static str = env!("CARGO_PKG_VERSION");
static SYNTAX: &'static str = "[-d] [-s] [-z] [--output-delimiter] ((-f|-b|-c) {{sequence}}) {{sourcefile}}+";
static SUMMARY: &'static str = "Prints specified byte or field columns from each line of stdin or the input files";
static LONG_HELP: &'static str = "
Each call must specify a mode (what to use for columns),
a sequence (which columns to print), and provide a data source
Specifying a mode
Use --bytes (-b) or --characters (-c) to specify byte mode
Use --fields (-f) to specify field mode, where each line is broken into
fields identified by a delimiter character. For example for a typical CSV
you could use this in combination with setting comma as the delimiter
Specifying a sequence
A sequence is a group of 1 or more numbers or inclusive ranges separated
by a commas.
cut -f 2,5-7 some_file.txt
will display the 2nd, 5th, 6th, and 7th field for each source line
Ranges can extend to the end of the row by excluding the the second number
cut -f 3- some_file.txt
will display the 3rd field and all fields after for each source line
The first number of a range can be excluded, and this is effectively the
same as using 1 as the first number: it causes the range to begin at the
first column. Ranges can also display a single column
cut -f 1,3-5 some_file.txt
will display the 1st, 3rd, 4th, and 5th field for each source line
The --complement option, when used, inverts the effect of the sequence
cut --complement -f 4-6 some_file.txt
will display the every field but the 4th, 5th, and 6th
Specifying a data source
If no sourcefile arguments are specified, stdin is used as the source of
lines to print
If sourcefile arguments are specified, stdin is ignored and all files are
read in consecutively if a sourcefile is not successfully read, a warning
will print to stderr, and the eventual status code will be 1, but cut
will continue to read through proceeding sourcefiles
To print columns from both STDIN and a file argument, use - (dash) as a
sourcefile argument to represent stdin.
Field Mode options
The fields in each line are identified by a delimiter (separator)
Set the delimiter
Set the delimiter which separates fields in the file using the
--delimiter (-d) option. Setting the delimiter is optional.
If not set, a default delimiter of Tab will be used.
Optionally Filter based on delimiter
If the --only-delimited (-s) flag is provided, only lines which
contain the delimiter will be printed
Replace the delimiter
If the --output-delimiter option is provided, the argument used for
it will replace the delimiter character in each line printed. This is
useful for transforming tabular data - e.g. to convert a CSV to a
TSV (tab-separated file)
Line endings
When the --zero-terminated (-z) option is used, cut sees \\0 (null) as the
'line ending' character (both for the purposes of reading lines and
separating printed lines) instead of \\n (newline). This is useful for
tabular data where some of the cells may contain newlines
echo 'ab\\0cd' | cut -z -c 1
will result in 'a\\0c\\0'
";
struct Options {
out_delim: Option<String>,
@ -408,8 +487,7 @@ fn cut_files(mut filenames: Vec<String>, mode: Mode) -> i32 {
}
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = uucore::coreopts::CoreOptions::new(NAME);
let mut opts = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP);
opts.optopt("b", "bytes", "filter byte columns from the input source", "sequence");
opts.optopt("c", "characters", "alias for character mode", "sequence");
opts.optopt("d", "delimiter", "specify the delimiter character that separates fields in the input source. Defaults to Tab.", "delimiter");
@ -419,95 +497,6 @@ pub fn uumain(args: Vec<String>) -> i32 {
opts.optflag("s", "only-delimited", "in field mode, only print lines which contain the delimiter");
opts.optflag("z", "zero-terminated", "instead of filtering columns based on line, filter columns based on \\0 (NULL character)");
opts.optopt("", "output-delimiter", "in field mode, replace the delimiter in output lines with this option's argument", "new delimiter");
let usage = opts.usage("Prints specified byte or field columns from each line of stdin or the input files");
opts.help(format!("
{0} {1}
{0} [-d] [-s] [-z] [--output-delimiter] ((-f|-b|-c) {{sequence}}) {{sourcefile}}+
{2}
Reference
Each call must specify a mode (what to use for columns),
a sequence (which columns to print), and provide a data source
Specifying a mode
Use --bytes (-b) or --characters (-c) to specify byte mode
Use --fields (-f) to specify field mode, where each line is broken into
fields identified by a delimiter character. For example for a typical CSV
you could use this in combination with setting comma as the delimiter
Specifying a sequence
A sequence is a group of 1 or more numbers or inclusive ranges separated
by a commas.
cut -f 2,5-7 some_file.txt
will display the 2nd, 5th, 6th, and 7th field for each source line
Ranges can extend to the end of the row by excluding the the second number
cut -f 3- some_file.txt
will display the 3rd field and all fields after for each source line
The first number of a range can be excluded, and this is effectively the
same as using 1 as the first number: it causes the range to begin at the
first column. Ranges can also display a single column
cut -f 1,3-5 some_file.txt
will display the 1st, 3rd, 4th, and 5th field for each source line
The --complement option, when used, inverts the effect of the sequence
cut --complement -f 4-6 some_file.txt
will display the every field but the 4th, 5th, and 6th
Specifying a data source
If no sourcefile arguments are specified, stdin is used as the source of
lines to print
If sourcefile arguments are specified, stdin is ignored and all files are
read in consecutively if a sourcefile is not successfully read, a warning
will print to stderr, and the eventual status code will be 1, but cut
will continue to read through proceeding sourcefiles
To print columns from both STDIN and a file argument, use - (dash) as a
sourcefile argument to represent stdin.
Field Mode options
The fields in each line are identified by a delimiter (separator)
Set the delimiter
Set the delimiter which separates fields in the file using the
--delimiter (-d) option. Setting the delimiter is optional.
If not set, a default delimiter of Tab will be used.
Optionally Filter based on delimiter
If the --only-delimited (-s) flag is provided, only lines which
contain the delimiter will be printed
Replace the delimiter
If the --output-delimiter option is provided, the argument used for
it will replace the delimiter character in each line printed. This is
useful for transforming tabular data - e.g. to convert a CSV to a
TSV (tab-separated file)
Line endings
When the --zero-terminated (-z) option is used, cut sees \\0 (null) as the
'line ending' character (both for the purposes of reading lines and
separating printed lines) instead of \\n (newline). This is useful for
tabular data where some of the cells may contain newlines
echo 'ab\\0cd' | cut -z -c 1
will result in 'a\\0c\\0'
", NAME, VERSION, usage));
let matches = opts.parse(args);
let complement = matches.opt_present("complement");

View file

@ -14,7 +14,6 @@
extern crate uucore;
use uucore::c_types::getpwnam;
use uucore::utmpx::{self, time, Utmpx};
use uucore::coreopts;
use uucore::libc::{uid_t, gid_t, c_char, S_IWGRP};
use std::io::prelude::*;
@ -29,12 +28,28 @@ use std::ffi::{CStr, CString};
use std::path::PathBuf;
static NAME: &'static str = "pinky";
static SYNTAX: &'static str = "[OPTION]... [USER]...";
static SUMMARY: &'static str = "A lightweight 'finger' program; print user information.";
const BUFSIZE: usize = 1024;
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = coreopts::CoreOptions::new(NAME);
let long_help = &format!("
-l produce long format output for the specified USERs
-b omit the user's home directory and shell in long format
-h omit the user's project file in long format
-p omit the user's plan file in long format
-s do short format output, this is the default
-f omit the line of column headings in short format
-w omit the user's full name in short format
-i omit the user's full name and remote host in short format
-q omit the user's full name, remote host and idle time
in short format
--help display this help and exit
--version output version information and exit
The utmp file will be {}", utmpx::DEFAULT_FILE);
let mut opts = new_coreopts!(SYNTAX, SUMMARY, &long_help);
opts.optflag("l",
"l",
"produce long format output for the specified USERs");
@ -55,27 +70,6 @@ pub fn uumain(args: Vec<String>) -> i32 {
opts.optflag("", "help", "display this help and exit");
opts.optflag("", "version", "output version information and exit");
opts.help(format!(
"Usage: {} [OPTION]... [USER]...
-l produce long format output for the specified USERs
-b omit the user's home directory and shell in long format
-h omit the user's project file in long format
-p omit the user's plan file in long format
-s do short format output, this is the default
-f omit the line of column headings in short format
-w omit the user's full name in short format
-i omit the user's full name and remote host in short format
-q omit the user's full name, remote host and idle time
in short format
--help display this help and exit
--version output version information and exit
A lightweight 'finger' program; print user information.
The utmp file will be {}",
NAME,
utmpx::DEFAULT_FILE));
let matches = opts.parse(args);
// If true, display the hours:minutes since each user has touched

View file

@ -1,36 +1,39 @@
extern crate getopts;
use std::io::Write;
pub struct CoreOptions {
pub options : getopts::Options,
pkgname: &'static str,
longhelp : Option<String>
pub struct HelpText<'a> {
pub name : &'a str,
pub version : &'a str,
pub syntax : &'a str,
pub summary : &'a str,
pub long_help : &'a str,
pub display_usage : bool
}
impl<'a> CoreOptions {
pub fn new(name: &'static str) -> Self {
pub struct CoreOptions<'a> {
options : getopts::Options,
help_text : HelpText<'a>
}
impl<'a> CoreOptions<'a> {
pub fn new(help_text: HelpText<'a>) -> Self {
let mut ret = CoreOptions {
options : getopts::Options::new(),
pkgname: name,
longhelp: None
help_text : help_text
};
ret.options
.optflag("", "help", "print usage information")
.optflag("", "version", "print name and version number");
ret
}
pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions {
pub fn optopt(&mut self, short_name: &str, long_name: &str, desc: &str, hint: &str) -> &mut CoreOptions<'a> {
self.options.optopt(short_name, long_name, desc, hint);
self
}
pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str) -> &mut CoreOptions {
pub fn optflag(&mut self, short_name: &str, long_name: &str, desc: &str) -> &mut CoreOptions<'a> {
self.options.optflag(short_name, long_name, desc);
self
}
pub fn help<T: Into<String>>(&mut self, longhelp : T) -> &mut CoreOptions {
self.longhelp = Some(longhelp.into());
self
}
pub fn usage(&self, summary : &str) -> String {
self.options.usage(summary)
}
@ -38,20 +41,50 @@ impl<'a> CoreOptions {
let matches = match self.options.parse(&args[1..]) {
Ok(m) => { Some(m) },
Err(f) => {
eprintln!("{}: {}", self.pkgname, f);
eprintln!("Try '{} --help' for more information.", self.pkgname);
exit!(1)
crash!(1, "{}", f);
}
}.unwrap();
if matches.opt_present("help") {
exit!(match self.longhelp {
Some(ref lhelp) => { println!("{}", lhelp); 0}
None => 1
});
if matches.opt_present("help") {
let usage_str = if self.help_text.display_usage {
format!("\n {}\n\n Reference\n",
self.options.usage(self.help_text.summary)
).replace("Options:", " Options:")
} else { String::new() };
print!("
{0} {1}
{0} {2}
{3}{4}
", self.help_text.name, self.help_text.version, self.help_text.syntax, usage_str, self.help_text.long_help);
exit!(0);
} else if matches.opt_present("version") {
println!("{} {}", self.pkgname, env!("CARGO_PKG_VERSION"));
println!("{} {}", self.help_text.name, self.help_text.version);
exit!(0);
}
matches
}
}
#[macro_export]
macro_rules! new_coreopts {
($syntax: expr, $summary: expr, $long_help: expr) => (
uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
name: executable!(),
version: env!("CARGO_PKG_VERSION"),
syntax: $syntax,
summary: $summary,
long_help: $long_help,
display_usage: true
})
);
($syntax: expr, $summary: expr, $long_help: expr, $display_usage: expr) => (
uucore::coreopts::CoreOptions::new(uucore::coreopts::HelpText {
name: executable!(),
version: env!("CARGO_PKG_VERSION"),
syntax: $syntax,
summary: $summary,
long_help: $long_help,
display_usage: $display_usage
})
);
}

View file

@ -3,6 +3,7 @@ pub extern crate libc;
#[macro_use]
mod macros;
#[macro_use]
pub mod coreopts;
#[cfg(feature = "fs")]

View file

@ -264,15 +264,6 @@ macro_rules! snippet_list_join_or {
);
}
//-- message templates : help and version
#[macro_export]
macro_rules! msg_version {
() => (
format!("{} {}", executable!(), env!("CARGO_PKG_VERSION"))
)
}
//-- message templates : invalid input
#[macro_export]

View file

@ -12,7 +12,6 @@
#[macro_use]
extern crate uucore;
use uucore::utmpx::{self, time, Utmpx};
use uucore::coreopts;
use uucore::libc::{STDIN_FILENO, time_t, ttyname, S_IWGRP};
use std::borrow::Cow;
@ -21,11 +20,35 @@ use std::ffi::CStr;
use std::path::PathBuf;
use std::os::unix::fs::MetadataExt;
static NAME: &'static str = "who";
static SYNTAX: &'static str = "[OPTION]... [ FILE | ARG1 ARG2 ]";
static SUMMARY: &'static str = "Print information about users who are currently logged in.";
static LONG_HELP: &'static str = "
-a, --all same as -b -d --login -p -r -t -T -u
-b, --boot time of last system boot
-d, --dead print dead processes
-H, --heading print line of column headings
-l, --login print system login processes
--lookup attempt to canonicalize hostnames via DNS
-m only hostname and user associated with stdin
-p, --process print active processes spawned by init
-q, --count all login names and number of users logged on
-r, --runlevel print current runlevel
-s, --short print only name, line, and time (default)
-t, --time print last system clock change
-T, -w, --mesg add user's message status as +, - or ?
-u, --users list users logged in
--message same as -T
--writable same as -T
--help display this help and exit
--version output version information and exit
If FILE is not specified, use /var/run/utmp. /var/log/wtmp as FILE is common.
If ARG1 ARG2 given, -m presumed: 'am i' or 'mom likes' are usual.
";
pub fn uumain(args: Vec<String>) -> i32 {
let mut opts = coreopts::CoreOptions::new(NAME);
let mut opts = new_coreopts!(SYNTAX, SUMMARY, LONG_HELP);
opts.optflag("a", "all", "same as -b -d --login -p -r -t -T -u");
opts.optflag("b", "boot", "time of last system boot");
opts.optflag("d", "dead", "print dead processes");
@ -49,32 +72,6 @@ pub fn uumain(args: Vec<String>) -> i32 {
opts.optflag("", "help", "display this help and exit");
opts.optflag("", "version", "output version information and exit");
opts.help(format!("Usage: {} [OPTION]... [ FILE | ARG1 ARG2 ]
Print information about users who are currently logged in.
-a, --all same as -b -d --login -p -r -t -T -u
-b, --boot time of last system boot
-d, --dead print dead processes
-H, --heading print line of column headings
-l, --login print system login processes
--lookup attempt to canonicalize hostnames via DNS
-m only hostname and user associated with stdin
-p, --process print active processes spawned by init
-q, --count all login names and number of users logged on
-r, --runlevel print current runlevel
-s, --short print only name, line, and time (default)
-t, --time print last system clock change
-T, -w, --mesg add user's message status as +, - or ?
-u, --users list users logged in
--message same as -T
--writable same as -T
--help display this help and exit
--version output version information and exit
If FILE is not specified, use /var/run/utmp. /var/log/wtmp as FILE is common.
If ARG1 ARG2 given, -m presumed: 'am i' or 'mom likes' are usual.",
NAME));
let matches = opts.parse(args);
// If true, attempt to canonicalize hostnames via a DNS lookup.