mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Merge pull request #2397 from miDeb/sort/args
sort: refactor command line arguments
This commit is contained in:
commit
dfe0314d8d
2 changed files with 206 additions and 156 deletions
|
@ -46,8 +46,8 @@ use unicode_width::UnicodeWidthStr;
|
||||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
|
||||||
static NAME: &str = "sort";
|
const NAME: &str = "sort";
|
||||||
static ABOUT: &str = "Display sorted concatenation of all FILE(s).";
|
const ABOUT: &str = "Display sorted concatenation of all FILE(s).";
|
||||||
|
|
||||||
const LONG_HELP_KEYS: &str = "The key format is FIELD[.CHAR][OPTIONS][,FIELD[.CHAR]][OPTIONS].
|
const LONG_HELP_KEYS: &str = "The key format is FIELD[.CHAR][OPTIONS][,FIELD[.CHAR]][OPTIONS].
|
||||||
|
|
||||||
|
@ -59,49 +59,59 @@ If CHAR is set 0, it means the end of the field. CHAR defaults to 1 for the star
|
||||||
|
|
||||||
Valid options are: MbdfhnRrV. They override the global options for this key.";
|
Valid options are: MbdfhnRrV. They override the global options for this key.";
|
||||||
|
|
||||||
static OPT_HUMAN_NUMERIC_SORT: &str = "human-numeric-sort";
|
mod options {
|
||||||
static OPT_MONTH_SORT: &str = "month-sort";
|
pub mod modes {
|
||||||
static OPT_NUMERIC_SORT: &str = "numeric-sort";
|
pub const SORT: &str = "sort";
|
||||||
static OPT_GENERAL_NUMERIC_SORT: &str = "general-numeric-sort";
|
|
||||||
static OPT_VERSION_SORT: &str = "version-sort";
|
|
||||||
|
|
||||||
static OPT_SORT: &str = "sort";
|
pub const HUMAN_NUMERIC: &str = "human-numeric-sort";
|
||||||
|
pub const MONTH: &str = "month-sort";
|
||||||
|
pub const NUMERIC: &str = "numeric-sort";
|
||||||
|
pub const GENERAL_NUMERIC: &str = "general-numeric-sort";
|
||||||
|
pub const VERSION: &str = "version-sort";
|
||||||
|
pub const RANDOM: &str = "random-sort";
|
||||||
|
|
||||||
static ALL_SORT_MODES: &[&str] = &[
|
pub const ALL_SORT_MODES: [&str; 6] = [
|
||||||
OPT_GENERAL_NUMERIC_SORT,
|
GENERAL_NUMERIC,
|
||||||
OPT_HUMAN_NUMERIC_SORT,
|
HUMAN_NUMERIC,
|
||||||
OPT_MONTH_SORT,
|
MONTH,
|
||||||
OPT_NUMERIC_SORT,
|
NUMERIC,
|
||||||
OPT_VERSION_SORT,
|
VERSION,
|
||||||
OPT_RANDOM,
|
RANDOM,
|
||||||
];
|
];
|
||||||
|
}
|
||||||
|
|
||||||
static OPT_DICTIONARY_ORDER: &str = "dictionary-order";
|
pub mod check {
|
||||||
static OPT_MERGE: &str = "merge";
|
pub const CHECK: &str = "check";
|
||||||
static OPT_CHECK: &str = "check";
|
pub const CHECK_SILENT: &str = "check-silent";
|
||||||
static OPT_CHECK_SILENT: &str = "check-silent";
|
pub const SILENT: &str = "silent";
|
||||||
static OPT_DEBUG: &str = "debug";
|
pub const QUIET: &str = "quiet";
|
||||||
static OPT_IGNORE_CASE: &str = "ignore-case";
|
pub const DIAGNOSE_FIRST: &str = "diagnose-first";
|
||||||
static OPT_IGNORE_BLANKS: &str = "ignore-blanks";
|
}
|
||||||
static OPT_IGNORE_NONPRINTING: &str = "ignore-nonprinting";
|
|
||||||
static OPT_OUTPUT: &str = "output";
|
|
||||||
static OPT_REVERSE: &str = "reverse";
|
|
||||||
static OPT_STABLE: &str = "stable";
|
|
||||||
static OPT_UNIQUE: &str = "unique";
|
|
||||||
static OPT_KEY: &str = "key";
|
|
||||||
static OPT_SEPARATOR: &str = "field-separator";
|
|
||||||
static OPT_RANDOM: &str = "random-sort";
|
|
||||||
static OPT_ZERO_TERMINATED: &str = "zero-terminated";
|
|
||||||
static OPT_PARALLEL: &str = "parallel";
|
|
||||||
static OPT_FILES0_FROM: &str = "files0-from";
|
|
||||||
static OPT_BUF_SIZE: &str = "buffer-size";
|
|
||||||
static OPT_TMP_DIR: &str = "temporary-directory";
|
|
||||||
static OPT_COMPRESS_PROG: &str = "compress-program";
|
|
||||||
static OPT_BATCH_SIZE: &str = "batch-size";
|
|
||||||
|
|
||||||
static ARG_FILES: &str = "files";
|
pub const DICTIONARY_ORDER: &str = "dictionary-order";
|
||||||
|
pub const MERGE: &str = "merge";
|
||||||
|
pub const DEBUG: &str = "debug";
|
||||||
|
pub const IGNORE_CASE: &str = "ignore-case";
|
||||||
|
pub const IGNORE_LEADING_BLANKS: &str = "ignore-leading-blanks";
|
||||||
|
pub const IGNORE_NONPRINTING: &str = "ignore-nonprinting";
|
||||||
|
pub const OUTPUT: &str = "output";
|
||||||
|
pub const REVERSE: &str = "reverse";
|
||||||
|
pub const STABLE: &str = "stable";
|
||||||
|
pub const UNIQUE: &str = "unique";
|
||||||
|
pub const KEY: &str = "key";
|
||||||
|
pub const SEPARATOR: &str = "field-separator";
|
||||||
|
pub const ZERO_TERMINATED: &str = "zero-terminated";
|
||||||
|
pub const PARALLEL: &str = "parallel";
|
||||||
|
pub const FILES0_FROM: &str = "files0-from";
|
||||||
|
pub const BUF_SIZE: &str = "buffer-size";
|
||||||
|
pub const TMP_DIR: &str = "temporary-directory";
|
||||||
|
pub const COMPRESS_PROG: &str = "compress-program";
|
||||||
|
pub const BATCH_SIZE: &str = "batch-size";
|
||||||
|
|
||||||
static DECIMAL_PT: char = '.';
|
pub const FILES: &str = "files";
|
||||||
|
}
|
||||||
|
|
||||||
|
const DECIMAL_PT: char = '.';
|
||||||
|
|
||||||
const NEGATIVE: char = '-';
|
const NEGATIVE: char = '-';
|
||||||
const POSITIVE: char = '+';
|
const POSITIVE: char = '+';
|
||||||
|
@ -109,7 +119,7 @@ const POSITIVE: char = '+';
|
||||||
// Choosing a higher buffer size does not result in performance improvements
|
// Choosing a higher buffer size does not result in performance improvements
|
||||||
// (at least not on my machine). TODO: In the future, we should also take the amount of
|
// (at least not on my machine). TODO: In the future, we should also take the amount of
|
||||||
// available memory into consideration, instead of relying on this constant only.
|
// available memory into consideration, instead of relying on this constant only.
|
||||||
static DEFAULT_BUF_SIZE: usize = 1_000_000_000; // 1 GB
|
const DEFAULT_BUF_SIZE: usize = 1_000_000_000; // 1 GB
|
||||||
|
|
||||||
#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Copy, Debug)]
|
#[derive(Eq, Ord, PartialEq, PartialOrd, Clone, Copy, Debug)]
|
||||||
enum SortMode {
|
enum SortMode {
|
||||||
|
@ -140,7 +150,7 @@ impl SortMode {
|
||||||
pub struct GlobalSettings {
|
pub struct GlobalSettings {
|
||||||
mode: SortMode,
|
mode: SortMode,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
ignore_blanks: bool,
|
ignore_leading_blanks: bool,
|
||||||
ignore_case: bool,
|
ignore_case: bool,
|
||||||
dictionary_order: bool,
|
dictionary_order: bool,
|
||||||
ignore_non_printing: bool,
|
ignore_non_printing: bool,
|
||||||
|
@ -207,7 +217,7 @@ impl Default for GlobalSettings {
|
||||||
GlobalSettings {
|
GlobalSettings {
|
||||||
mode: SortMode::Default,
|
mode: SortMode::Default,
|
||||||
debug: false,
|
debug: false,
|
||||||
ignore_blanks: false,
|
ignore_leading_blanks: false,
|
||||||
ignore_case: false,
|
ignore_case: false,
|
||||||
dictionary_order: false,
|
dictionary_order: false,
|
||||||
ignore_non_printing: false,
|
ignore_non_printing: false,
|
||||||
|
@ -298,7 +308,7 @@ impl From<&GlobalSettings> for KeySettings {
|
||||||
fn from(settings: &GlobalSettings) -> Self {
|
fn from(settings: &GlobalSettings) -> Self {
|
||||||
Self {
|
Self {
|
||||||
mode: settings.mode,
|
mode: settings.mode,
|
||||||
ignore_blanks: settings.ignore_blanks,
|
ignore_blanks: settings.ignore_leading_blanks,
|
||||||
ignore_case: settings.ignore_case,
|
ignore_case: settings.ignore_case,
|
||||||
ignore_non_printing: settings.ignore_non_printing,
|
ignore_non_printing: settings.ignore_non_printing,
|
||||||
reverse: settings.reverse,
|
reverse: settings.reverse,
|
||||||
|
@ -505,7 +515,7 @@ impl<'a> Line<'a> {
|
||||||
&& !settings.stable
|
&& !settings.stable
|
||||||
&& !settings.unique
|
&& !settings.unique
|
||||||
&& (settings.dictionary_order
|
&& (settings.dictionary_order
|
||||||
|| settings.ignore_blanks
|
|| settings.ignore_leading_blanks
|
||||||
|| settings.ignore_case
|
|| settings.ignore_case
|
||||||
|| settings.ignore_non_printing
|
|| settings.ignore_non_printing
|
||||||
|| settings.mode != SortMode::Default
|
|| settings.mode != SortMode::Default
|
||||||
|
@ -669,9 +679,11 @@ impl FieldSelector {
|
||||||
// This would be ideal for a try block, I think. In the meantime this closure allows
|
// This would be ideal for a try block, I think. In the meantime this closure allows
|
||||||
// to use the `?` operator here.
|
// to use the `?` operator here.
|
||||||
Self::new(
|
Self::new(
|
||||||
KeyPosition::new(from, 1, global_settings.ignore_blanks)?,
|
KeyPosition::new(from, 1, global_settings.ignore_leading_blanks)?,
|
||||||
to.map(|(to, _)| KeyPosition::new(to, 0, global_settings.ignore_blanks))
|
to.map(|(to, _)| {
|
||||||
.transpose()?,
|
KeyPosition::new(to, 0, global_settings.ignore_leading_blanks)
|
||||||
|
})
|
||||||
|
.transpose()?,
|
||||||
KeySettings::from(global_settings),
|
KeySettings::from(global_settings),
|
||||||
)
|
)
|
||||||
})()
|
})()
|
||||||
|
@ -887,9 +899,10 @@ With no FILE, or when FILE is -, read standard input.",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates an `Arg` that conflicts with all other sort modes.
|
||||||
fn make_sort_mode_arg<'a, 'b>(mode: &'a str, short: &'b str, help: &'b str) -> Arg<'a, 'b> {
|
fn make_sort_mode_arg<'a, 'b>(mode: &'a str, short: &'b str, help: &'b str) -> Arg<'a, 'b> {
|
||||||
let mut arg = Arg::with_name(mode).short(short).long(mode).help(help);
|
let mut arg = Arg::with_name(mode).short(short).long(mode).help(help);
|
||||||
for possible_mode in ALL_SORT_MODES {
|
for possible_mode in &options::modes::ALL_SORT_MODES {
|
||||||
if *possible_mode != mode {
|
if *possible_mode != mode {
|
||||||
arg = arg.conflicts_with(possible_mode);
|
arg = arg.conflicts_with(possible_mode);
|
||||||
}
|
}
|
||||||
|
@ -909,8 +922,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
.about(ABOUT)
|
.about(ABOUT)
|
||||||
.usage(&usage[..])
|
.usage(&usage[..])
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_SORT)
|
Arg::with_name(options::modes::SORT)
|
||||||
.long(OPT_SORT)
|
.long(options::modes::SORT)
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.possible_values(
|
.possible_values(
|
||||||
&[
|
&[
|
||||||
|
@ -922,199 +935,221 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
"random",
|
"random",
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
.conflicts_with_all(ALL_SORT_MODES)
|
.conflicts_with_all(&options::modes::ALL_SORT_MODES)
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
make_sort_mode_arg(
|
make_sort_mode_arg(
|
||||||
OPT_HUMAN_NUMERIC_SORT,
|
options::modes::HUMAN_NUMERIC,
|
||||||
"h",
|
"h",
|
||||||
"compare according to human readable sizes, eg 1M > 100k"
|
"compare according to human readable sizes, eg 1M > 100k"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
make_sort_mode_arg(
|
make_sort_mode_arg(
|
||||||
OPT_MONTH_SORT,
|
options::modes::MONTH,
|
||||||
"M",
|
"M",
|
||||||
"compare according to month name abbreviation"
|
"compare according to month name abbreviation"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
make_sort_mode_arg(
|
make_sort_mode_arg(
|
||||||
OPT_NUMERIC_SORT,
|
options::modes::NUMERIC,
|
||||||
"n",
|
"n",
|
||||||
"compare according to string numerical value"
|
"compare according to string numerical value"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
make_sort_mode_arg(
|
make_sort_mode_arg(
|
||||||
OPT_GENERAL_NUMERIC_SORT,
|
options::modes::GENERAL_NUMERIC,
|
||||||
"g",
|
"g",
|
||||||
"compare according to string general numerical value"
|
"compare according to string general numerical value"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
make_sort_mode_arg(
|
make_sort_mode_arg(
|
||||||
OPT_VERSION_SORT,
|
options::modes::VERSION,
|
||||||
"V",
|
"V",
|
||||||
"Sort by SemVer version number, eg 1.12.2 > 1.1.2",
|
"Sort by SemVer version number, eg 1.12.2 > 1.1.2",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
make_sort_mode_arg(
|
make_sort_mode_arg(
|
||||||
OPT_RANDOM,
|
options::modes::RANDOM,
|
||||||
"R",
|
"R",
|
||||||
"shuffle in random order",
|
"shuffle in random order",
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_DICTIONARY_ORDER)
|
Arg::with_name(options::DICTIONARY_ORDER)
|
||||||
.short("d")
|
.short("d")
|
||||||
.long(OPT_DICTIONARY_ORDER)
|
.long(options::DICTIONARY_ORDER)
|
||||||
.help("consider only blanks and alphanumeric characters")
|
.help("consider only blanks and alphanumeric characters")
|
||||||
.conflicts_with_all(&[OPT_NUMERIC_SORT, OPT_GENERAL_NUMERIC_SORT, OPT_HUMAN_NUMERIC_SORT, OPT_MONTH_SORT]),
|
.conflicts_with_all(
|
||||||
|
&[
|
||||||
|
options::modes::NUMERIC,
|
||||||
|
options::modes::GENERAL_NUMERIC,
|
||||||
|
options::modes::HUMAN_NUMERIC,
|
||||||
|
options::modes::MONTH,
|
||||||
|
]
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_MERGE)
|
Arg::with_name(options::MERGE)
|
||||||
.short("m")
|
.short("m")
|
||||||
.long(OPT_MERGE)
|
.long(options::MERGE)
|
||||||
.help("merge already sorted files; do not sort"),
|
.help("merge already sorted files; do not sort"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_CHECK)
|
Arg::with_name(options::check::CHECK)
|
||||||
.short("c")
|
.short("c")
|
||||||
.long(OPT_CHECK)
|
.long(options::check::CHECK)
|
||||||
|
.takes_value(true)
|
||||||
|
.require_equals(true)
|
||||||
|
.min_values(0)
|
||||||
|
.possible_values(&[
|
||||||
|
options::check::SILENT,
|
||||||
|
options::check::QUIET,
|
||||||
|
options::check::DIAGNOSE_FIRST,
|
||||||
|
])
|
||||||
.help("check for sorted input; do not sort"),
|
.help("check for sorted input; do not sort"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_CHECK_SILENT)
|
Arg::with_name(options::check::CHECK_SILENT)
|
||||||
.short("C")
|
.short("C")
|
||||||
.long(OPT_CHECK_SILENT)
|
.long(options::check::CHECK_SILENT)
|
||||||
.help("exit successfully if the given file is already sorted, and exit with status 1 otherwise."),
|
.help("exit successfully if the given file is already sorted, and exit with status 1 otherwise."),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_IGNORE_CASE)
|
Arg::with_name(options::IGNORE_CASE)
|
||||||
.short("f")
|
.short("f")
|
||||||
.long(OPT_IGNORE_CASE)
|
.long(options::IGNORE_CASE)
|
||||||
.help("fold lower case to upper case characters"),
|
.help("fold lower case to upper case characters"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_IGNORE_NONPRINTING)
|
Arg::with_name(options::IGNORE_NONPRINTING)
|
||||||
.short("i")
|
.short("i")
|
||||||
.long(OPT_IGNORE_NONPRINTING)
|
.long(options::IGNORE_NONPRINTING)
|
||||||
.help("ignore nonprinting characters")
|
.help("ignore nonprinting characters")
|
||||||
.conflicts_with_all(&[OPT_NUMERIC_SORT, OPT_GENERAL_NUMERIC_SORT, OPT_HUMAN_NUMERIC_SORT, OPT_MONTH_SORT]),
|
.conflicts_with_all(
|
||||||
|
&[
|
||||||
|
options::modes::NUMERIC,
|
||||||
|
options::modes::GENERAL_NUMERIC,
|
||||||
|
options::modes::HUMAN_NUMERIC,
|
||||||
|
options::modes::MONTH
|
||||||
|
]
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_IGNORE_BLANKS)
|
Arg::with_name(options::IGNORE_LEADING_BLANKS)
|
||||||
.short("b")
|
.short("b")
|
||||||
.long(OPT_IGNORE_BLANKS)
|
.long(options::IGNORE_LEADING_BLANKS)
|
||||||
.help("ignore leading blanks when finding sort keys in each line"),
|
.help("ignore leading blanks when finding sort keys in each line"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_OUTPUT)
|
Arg::with_name(options::OUTPUT)
|
||||||
.short("o")
|
.short("o")
|
||||||
.long(OPT_OUTPUT)
|
.long(options::OUTPUT)
|
||||||
.help("write output to FILENAME instead of stdout")
|
.help("write output to FILENAME instead of stdout")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("FILENAME"),
|
.value_name("FILENAME"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_REVERSE)
|
Arg::with_name(options::REVERSE)
|
||||||
.short("r")
|
.short("r")
|
||||||
.long(OPT_REVERSE)
|
.long(options::REVERSE)
|
||||||
.help("reverse the output"),
|
.help("reverse the output"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_STABLE)
|
Arg::with_name(options::STABLE)
|
||||||
.short("s")
|
.short("s")
|
||||||
.long(OPT_STABLE)
|
.long(options::STABLE)
|
||||||
.help("stabilize sort by disabling last-resort comparison"),
|
.help("stabilize sort by disabling last-resort comparison"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_UNIQUE)
|
Arg::with_name(options::UNIQUE)
|
||||||
.short("u")
|
.short("u")
|
||||||
.long(OPT_UNIQUE)
|
.long(options::UNIQUE)
|
||||||
.help("output only the first of an equal run"),
|
.help("output only the first of an equal run"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_KEY)
|
Arg::with_name(options::KEY)
|
||||||
.short("k")
|
.short("k")
|
||||||
.long(OPT_KEY)
|
.long(options::KEY)
|
||||||
.help("sort by a key")
|
.help("sort by a key")
|
||||||
.long_help(LONG_HELP_KEYS)
|
.long_help(LONG_HELP_KEYS)
|
||||||
.multiple(true)
|
.multiple(true)
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_SEPARATOR)
|
Arg::with_name(options::SEPARATOR)
|
||||||
.short("t")
|
.short("t")
|
||||||
.long(OPT_SEPARATOR)
|
.long(options::SEPARATOR)
|
||||||
.help("custom separator for -k")
|
.help("custom separator for -k")
|
||||||
.takes_value(true))
|
.takes_value(true))
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_ZERO_TERMINATED)
|
Arg::with_name(options::ZERO_TERMINATED)
|
||||||
.short("z")
|
.short("z")
|
||||||
.long(OPT_ZERO_TERMINATED)
|
.long(options::ZERO_TERMINATED)
|
||||||
.help("line delimiter is NUL, not newline"),
|
.help("line delimiter is NUL, not newline"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_PARALLEL)
|
Arg::with_name(options::PARALLEL)
|
||||||
.long(OPT_PARALLEL)
|
.long(options::PARALLEL)
|
||||||
.help("change the number of threads running concurrently to NUM_THREADS")
|
.help("change the number of threads running concurrently to NUM_THREADS")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("NUM_THREADS"),
|
.value_name("NUM_THREADS"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_BUF_SIZE)
|
Arg::with_name(options::BUF_SIZE)
|
||||||
.short("S")
|
.short("S")
|
||||||
.long(OPT_BUF_SIZE)
|
.long(options::BUF_SIZE)
|
||||||
.help("sets the maximum SIZE of each segment in number of sorted items")
|
.help("sets the maximum SIZE of each segment in number of sorted items")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("SIZE"),
|
.value_name("SIZE"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_TMP_DIR)
|
Arg::with_name(options::TMP_DIR)
|
||||||
.short("T")
|
.short("T")
|
||||||
.long(OPT_TMP_DIR)
|
.long(options::TMP_DIR)
|
||||||
.help("use DIR for temporaries, not $TMPDIR or /tmp")
|
.help("use DIR for temporaries, not $TMPDIR or /tmp")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("DIR"),
|
.value_name("DIR"),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_COMPRESS_PROG)
|
Arg::with_name(options::COMPRESS_PROG)
|
||||||
.long(OPT_COMPRESS_PROG)
|
.long(options::COMPRESS_PROG)
|
||||||
.help("compress temporary files with PROG, decompress with PROG -d")
|
.help("compress temporary files with PROG, decompress with PROG -d")
|
||||||
.long_help("PROG has to take input from stdin and output to stdout")
|
.long_help("PROG has to take input from stdin and output to stdout")
|
||||||
.value_name("PROG")
|
.value_name("PROG")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_BATCH_SIZE)
|
Arg::with_name(options::BATCH_SIZE)
|
||||||
.long(OPT_BATCH_SIZE)
|
.long(options::BATCH_SIZE)
|
||||||
.help("Merge at most N_MERGE inputs at once.")
|
.help("Merge at most N_MERGE inputs at once.")
|
||||||
.value_name("N_MERGE")
|
.value_name("N_MERGE")
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_FILES0_FROM)
|
Arg::with_name(options::FILES0_FROM)
|
||||||
.long(OPT_FILES0_FROM)
|
.long(options::FILES0_FROM)
|
||||||
.help("read input from the files specified by NUL-terminated NUL_FILES")
|
.help("read input from the files specified by NUL-terminated NUL_FILES")
|
||||||
.takes_value(true)
|
.takes_value(true)
|
||||||
.value_name("NUL_FILES")
|
.value_name("NUL_FILES")
|
||||||
.multiple(true),
|
.multiple(true),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::with_name(OPT_DEBUG)
|
Arg::with_name(options::DEBUG)
|
||||||
.long(OPT_DEBUG)
|
.long(options::DEBUG)
|
||||||
.help("underline the parts of the line that are actually used for sorting"),
|
.help("underline the parts of the line that are actually used for sorting"),
|
||||||
)
|
)
|
||||||
.arg(Arg::with_name(ARG_FILES).multiple(true).takes_value(true))
|
.arg(Arg::with_name(options::FILES).multiple(true).takes_value(true))
|
||||||
.get_matches_from(args);
|
.get_matches_from(args);
|
||||||
|
|
||||||
settings.debug = matches.is_present(OPT_DEBUG);
|
settings.debug = matches.is_present(options::DEBUG);
|
||||||
|
|
||||||
// check whether user specified a zero terminated list of files for input, otherwise read files from args
|
// check whether user specified a zero terminated list of files for input, otherwise read files from args
|
||||||
let mut files: Vec<String> = if matches.is_present(OPT_FILES0_FROM) {
|
let mut files: Vec<String> = if matches.is_present(options::FILES0_FROM) {
|
||||||
let files0_from: Vec<String> = matches
|
let files0_from: Vec<String> = matches
|
||||||
.values_of(OPT_FILES0_FROM)
|
.values_of(options::FILES0_FROM)
|
||||||
.map(|v| v.map(ToString::to_string).collect())
|
.map(|v| v.map(ToString::to_string).collect())
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
@ -1133,82 +1168,93 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
files
|
files
|
||||||
} else {
|
} else {
|
||||||
matches
|
matches
|
||||||
.values_of(ARG_FILES)
|
.values_of(options::FILES)
|
||||||
.map(|v| v.map(ToString::to_string).collect())
|
.map(|v| v.map(ToString::to_string).collect())
|
||||||
.unwrap_or_default()
|
.unwrap_or_default()
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.mode = if matches.is_present(OPT_HUMAN_NUMERIC_SORT)
|
settings.mode = if matches.is_present(options::modes::HUMAN_NUMERIC)
|
||||||
|| matches.value_of(OPT_SORT) == Some("human-numeric")
|
|| matches.value_of(options::modes::SORT) == Some("human-numeric")
|
||||||
{
|
{
|
||||||
SortMode::HumanNumeric
|
SortMode::HumanNumeric
|
||||||
} else if matches.is_present(OPT_MONTH_SORT) || matches.value_of(OPT_SORT) == Some("month") {
|
} else if matches.is_present(options::modes::MONTH)
|
||||||
|
|| matches.value_of(options::modes::SORT) == Some("month")
|
||||||
|
{
|
||||||
SortMode::Month
|
SortMode::Month
|
||||||
} else if matches.is_present(OPT_GENERAL_NUMERIC_SORT)
|
} else if matches.is_present(options::modes::GENERAL_NUMERIC)
|
||||||
|| matches.value_of(OPT_SORT) == Some("general-numeric")
|
|| matches.value_of(options::modes::SORT) == Some("general-numeric")
|
||||||
{
|
{
|
||||||
SortMode::GeneralNumeric
|
SortMode::GeneralNumeric
|
||||||
} else if matches.is_present(OPT_NUMERIC_SORT) || matches.value_of(OPT_SORT) == Some("numeric")
|
} else if matches.is_present(options::modes::NUMERIC)
|
||||||
|
|| matches.value_of(options::modes::SORT) == Some("numeric")
|
||||||
{
|
{
|
||||||
SortMode::Numeric
|
SortMode::Numeric
|
||||||
} else if matches.is_present(OPT_VERSION_SORT) || matches.value_of(OPT_SORT) == Some("version")
|
} else if matches.is_present(options::modes::VERSION)
|
||||||
|
|| matches.value_of(options::modes::SORT) == Some("version")
|
||||||
{
|
{
|
||||||
SortMode::Version
|
SortMode::Version
|
||||||
} else if matches.is_present(OPT_RANDOM) || matches.value_of(OPT_SORT) == Some("random") {
|
} else if matches.is_present(options::modes::RANDOM)
|
||||||
|
|| matches.value_of(options::modes::SORT) == Some("random")
|
||||||
|
{
|
||||||
settings.salt = get_rand_string();
|
settings.salt = get_rand_string();
|
||||||
SortMode::Random
|
SortMode::Random
|
||||||
} else {
|
} else {
|
||||||
SortMode::Default
|
SortMode::Default
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.dictionary_order = matches.is_present(OPT_DICTIONARY_ORDER);
|
settings.dictionary_order = matches.is_present(options::DICTIONARY_ORDER);
|
||||||
settings.ignore_non_printing = matches.is_present(OPT_IGNORE_NONPRINTING);
|
settings.ignore_non_printing = matches.is_present(options::IGNORE_NONPRINTING);
|
||||||
if matches.is_present(OPT_PARALLEL) {
|
if matches.is_present(options::PARALLEL) {
|
||||||
// "0" is default - threads = num of cores
|
// "0" is default - threads = num of cores
|
||||||
settings.threads = matches
|
settings.threads = matches
|
||||||
.value_of(OPT_PARALLEL)
|
.value_of(options::PARALLEL)
|
||||||
.map(String::from)
|
.map(String::from)
|
||||||
.unwrap_or_else(|| "0".to_string());
|
.unwrap_or_else(|| "0".to_string());
|
||||||
env::set_var("RAYON_NUM_THREADS", &settings.threads);
|
env::set_var("RAYON_NUM_THREADS", &settings.threads);
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.buffer_size = matches
|
settings.buffer_size = matches
|
||||||
.value_of(OPT_BUF_SIZE)
|
.value_of(options::BUF_SIZE)
|
||||||
.map_or(DEFAULT_BUF_SIZE, |s| {
|
.map_or(DEFAULT_BUF_SIZE, |s| {
|
||||||
GlobalSettings::parse_byte_count(s)
|
GlobalSettings::parse_byte_count(s)
|
||||||
.unwrap_or_else(|e| crash!(2, "{}", format_error_message(e, s, OPT_BUF_SIZE)))
|
.unwrap_or_else(|e| crash!(2, "{}", format_error_message(e, s, options::BUF_SIZE)))
|
||||||
});
|
});
|
||||||
|
|
||||||
settings.tmp_dir = matches
|
settings.tmp_dir = matches
|
||||||
.value_of(OPT_TMP_DIR)
|
.value_of(options::TMP_DIR)
|
||||||
.map(PathBuf::from)
|
.map(PathBuf::from)
|
||||||
.unwrap_or_else(env::temp_dir);
|
.unwrap_or_else(env::temp_dir);
|
||||||
|
|
||||||
settings.compress_prog = matches.value_of(OPT_COMPRESS_PROG).map(String::from);
|
settings.compress_prog = matches.value_of(options::COMPRESS_PROG).map(String::from);
|
||||||
|
|
||||||
if let Some(n_merge) = matches.value_of(OPT_BATCH_SIZE) {
|
if let Some(n_merge) = matches.value_of(options::BATCH_SIZE) {
|
||||||
settings.merge_batch_size = n_merge
|
settings.merge_batch_size = n_merge
|
||||||
.parse()
|
.parse()
|
||||||
.unwrap_or_else(|_| crash!(2, "invalid --batch-size argument '{}'", n_merge));
|
.unwrap_or_else(|_| crash!(2, "invalid --batch-size argument '{}'", n_merge));
|
||||||
}
|
}
|
||||||
|
|
||||||
settings.zero_terminated = matches.is_present(OPT_ZERO_TERMINATED);
|
settings.zero_terminated = matches.is_present(options::ZERO_TERMINATED);
|
||||||
settings.merge = matches.is_present(OPT_MERGE);
|
settings.merge = matches.is_present(options::MERGE);
|
||||||
|
|
||||||
settings.check = matches.is_present(OPT_CHECK);
|
settings.check = matches.is_present(options::check::CHECK);
|
||||||
if matches.is_present(OPT_CHECK_SILENT) {
|
if matches.is_present(options::check::CHECK_SILENT)
|
||||||
settings.check_silent = matches.is_present(OPT_CHECK_SILENT);
|
|| matches!(
|
||||||
|
matches.value_of(options::check::CHECK),
|
||||||
|
Some(options::check::SILENT) | Some(options::check::QUIET)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
settings.check_silent = true;
|
||||||
settings.check = true;
|
settings.check = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
settings.ignore_case = matches.is_present(OPT_IGNORE_CASE);
|
settings.ignore_case = matches.is_present(options::IGNORE_CASE);
|
||||||
|
|
||||||
settings.ignore_blanks = matches.is_present(OPT_IGNORE_BLANKS);
|
settings.ignore_leading_blanks = matches.is_present(options::IGNORE_LEADING_BLANKS);
|
||||||
|
|
||||||
settings.output_file = matches.value_of(OPT_OUTPUT).map(String::from);
|
settings.output_file = matches.value_of(options::OUTPUT).map(String::from);
|
||||||
settings.reverse = matches.is_present(OPT_REVERSE);
|
settings.reverse = matches.is_present(options::REVERSE);
|
||||||
settings.stable = matches.is_present(OPT_STABLE);
|
settings.stable = matches.is_present(options::STABLE);
|
||||||
settings.unique = matches.is_present(OPT_UNIQUE);
|
settings.unique = matches.is_present(options::UNIQUE);
|
||||||
|
|
||||||
if files.is_empty() {
|
if files.is_empty() {
|
||||||
/* if no file, default to stdin */
|
/* if no file, default to stdin */
|
||||||
|
@ -1217,7 +1263,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
crash!(1, "extra operand `{}' not allowed with -c", files[1])
|
crash!(1, "extra operand `{}' not allowed with -c", files[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(arg) = matches.args.get(OPT_SEPARATOR) {
|
if let Some(arg) = matches.args.get(options::SEPARATOR) {
|
||||||
let separator = arg.vals[0].to_string_lossy();
|
let separator = arg.vals[0].to_string_lossy();
|
||||||
let separator = separator;
|
let separator = separator;
|
||||||
if separator.len() != 1 {
|
if separator.len() != 1 {
|
||||||
|
@ -1226,15 +1272,15 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||||
settings.separator = Some(separator.chars().next().unwrap())
|
settings.separator = Some(separator.chars().next().unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
if matches.is_present(OPT_KEY) {
|
if let Some(values) = matches.values_of(options::KEY) {
|
||||||
for key in &matches.args[OPT_KEY].vals {
|
for value in values {
|
||||||
settings
|
settings
|
||||||
.selectors
|
.selectors
|
||||||
.push(FieldSelector::parse(&key.to_string_lossy(), &settings));
|
.push(FieldSelector::parse(value, &settings));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !matches.is_present(OPT_KEY) {
|
if !matches.is_present(options::KEY) {
|
||||||
// add a default selector matching the whole line
|
// add a default selector matching the whole line
|
||||||
let key_settings = KeySettings::from(&settings);
|
let key_settings = KeySettings::from(&settings);
|
||||||
settings.selectors.push(
|
settings.selectors.push(
|
||||||
|
|
|
@ -762,26 +762,30 @@ fn test_pipe() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check() {
|
fn test_check() {
|
||||||
new_ucmd!()
|
for diagnose_arg in &["-c", "--check", "--check=diagnose-first"] {
|
||||||
.arg("-c")
|
new_ucmd!()
|
||||||
.arg("check_fail.txt")
|
.arg(diagnose_arg)
|
||||||
.fails()
|
.arg("check_fail.txt")
|
||||||
.stdout_is("sort: check_fail.txt:6: disorder: 5\n");
|
.fails()
|
||||||
|
.stdout_is("sort: check_fail.txt:6: disorder: 5\n");
|
||||||
|
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
.arg("-c")
|
.arg(diagnose_arg)
|
||||||
.arg("multiple_files.expected")
|
.arg("multiple_files.expected")
|
||||||
.succeeds()
|
.succeeds()
|
||||||
.stdout_is("");
|
.stdout_is("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_check_silent() {
|
fn test_check_silent() {
|
||||||
new_ucmd!()
|
for silent_arg in &["-C", "--check=silent", "--check=quiet"] {
|
||||||
.arg("-C")
|
new_ucmd!()
|
||||||
.arg("check_fail.txt")
|
.arg(silent_arg)
|
||||||
.fails()
|
.arg("check_fail.txt")
|
||||||
.stdout_is("");
|
.fails()
|
||||||
|
.stdout_is("");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -835,7 +839,7 @@ fn test_nonexistent_file() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_blanks() {
|
fn test_blanks() {
|
||||||
test_helper("blanks", &["-b", "--ignore-blanks"]);
|
test_helper("blanks", &["-b", "--ignore-leading-blanks"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue