1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

Merge branch 'master' of https://github.com/uutils/coreutils into ln/dst-symlink

This commit is contained in:
Michael Debertol 2021-06-10 21:48:43 +02:00
commit 32f5e8baf8
18 changed files with 213 additions and 303 deletions

11
Cargo.lock generated
View file

@ -6,16 +6,6 @@ version = "0.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3"
[[package]]
name = "advapi32-sys"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e06588080cb19d0acb6739808aafa5f26bfb2ca015b2b6370028b44cf7cb8a9a"
dependencies = [
"winapi 0.2.8",
"winapi-build",
]
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "0.7.18" version = "0.7.18"
@ -2754,7 +2744,6 @@ dependencies = [
name = "uu_whoami" name = "uu_whoami"
version = "0.0.6" version = "0.0.6"
dependencies = [ dependencies = [
"advapi32-sys",
"clap", "clap",
"uucore", "uucore",
"uucore_procs", "uucore_procs",

View file

@ -28,6 +28,7 @@ mod options {
pub const GROUP: &str = "group"; pub const GROUP: &str = "group";
pub const GROUPS: &str = "groups"; pub const GROUPS: &str = "groups";
pub const USERSPEC: &str = "userspec"; pub const USERSPEC: &str = "userspec";
pub const COMMAND: &str = "command";
} }
pub fn uumain(args: impl uucore::Args) -> i32 { pub fn uumain(args: impl uucore::Args) -> i32 {
@ -39,7 +40,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.version(crate_version!()) .version(crate_version!())
.about(ABOUT) .about(ABOUT)
.usage(SYNTAX) .usage(SYNTAX)
.arg(Arg::with_name(options::NEWROOT).hidden(true).required(true)) .arg(
Arg::with_name(options::NEWROOT)
.hidden(true)
.required(true)
.index(1),
)
.arg( .arg(
Arg::with_name(options::USER) Arg::with_name(options::USER)
.short("u") .short("u")
@ -71,6 +77,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
) )
.value_name("USER:GROUP"), .value_name("USER:GROUP"),
) )
.arg(
Arg::with_name(options::COMMAND)
.hidden(true)
.multiple(true)
.index(2),
)
.get_matches_from(args); .get_matches_from(args);
let default_shell: &'static str = "/bin/sh"; let default_shell: &'static str = "/bin/sh";
@ -94,7 +106,14 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
); );
} }
let command: Vec<&str> = match matches.args.len() { let commands = match matches.values_of(options::COMMAND) {
Some(v) => v.collect(),
None => vec![],
};
// TODO: refactor the args and command matching
// See: https://github.com/uutils/coreutils/pull/2365#discussion_r647849967
let command: Vec<&str> = match commands.len() {
1 => { 1 => {
let shell: &str = match user_shell { let shell: &str = match user_shell {
Err(_) => default_shell, Err(_) => default_shell,
@ -102,14 +121,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
}; };
vec![shell, default_option] vec![shell, default_option]
} }
_ => { _ => commands,
let mut vector: Vec<&str> = Vec::new();
for (&k, v) in matches.args.iter() {
vector.push(k);
vector.push(v.vals[0].to_str().unwrap());
}
vector
}
}; };
set_context(newroot, &matches); set_context(newroot, &matches);

View file

@ -19,6 +19,8 @@ clap = "2.33"
chrono = "0.4" chrono = "0.4"
uucore = { version=">=0.0.8", package="uucore", path="../../uucore" } uucore = { version=">=0.0.8", package="uucore", path="../../uucore" }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[target.'cfg(target_os = "windows")'.dependencies]
winapi = { version="0.3", features=[] } winapi = { version="0.3", features=[] }
[[bin]] [[bin]]

View file

@ -229,10 +229,9 @@ fn unit_string_to_number(s: &str) -> Option<u64> {
let mut offset = 0; let mut offset = 0;
let mut s_chars = s.chars().rev(); let mut s_chars = s.chars().rev();
let (mut ch, multiple) = match s_chars.next() { let (mut ch, multiple) = match s_chars.next()? {
Some('B') | Some('b') => ('B', 1000u64), 'B' | 'b' => ('B', 1000u64),
Some(ch) => (ch, 1024u64), ch => (ch, 1024u64),
None => return None,
}; };
if ch == 'B' { if ch == 'B' {
ch = s_chars.next()?; ch = s_chars.next()?;

View file

@ -77,17 +77,19 @@ fn get_long_usage() -> String {
static ABOUT: &str = "change file owner and group"; static ABOUT: &str = "change file owner and group";
static OPT_B: &str = "b"; mod options {
static OPT_BACKUP: &str = "backup"; pub const B: &str = "b";
static OPT_FORCE: &str = "force"; pub const BACKUP: &str = "backup";
static OPT_INTERACTIVE: &str = "interactive"; pub const FORCE: &str = "force";
static OPT_NO_DEREFERENCE: &str = "no-dereference"; pub const INTERACTIVE: &str = "interactive";
static OPT_SYMBOLIC: &str = "symbolic"; pub const NO_DEREFERENCE: &str = "no-dereference";
static OPT_SUFFIX: &str = "suffix"; pub const SYMBOLIC: &str = "symbolic";
static OPT_TARGET_DIRECTORY: &str = "target-directory"; pub const SUFFIX: &str = "suffix";
static OPT_NO_TARGET_DIRECTORY: &str = "no-target-directory"; pub const TARGET_DIRECTORY: &str = "target-directory";
static OPT_RELATIVE: &str = "relative"; pub const NO_TARGET_DIRECTORY: &str = "no-target-directory";
static OPT_VERBOSE: &str = "verbose"; pub const RELATIVE: &str = "relative";
pub const VERBOSE: &str = "verbose";
}
static ARG_FILES: &str = "files"; static ARG_FILES: &str = "files";
@ -100,47 +102,42 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.about(ABOUT) .about(ABOUT)
.usage(&usage[..]) .usage(&usage[..])
.after_help(&long_usage[..]) .after_help(&long_usage[..])
.arg(Arg::with_name(OPT_B).short(OPT_B).help( .arg(Arg::with_name(options::B).short(options::B).help(
"make a backup of each file that would otherwise be overwritten or \ "make a backup of each file that would otherwise be overwritten or \
removed", removed",
)) ))
.arg( .arg(
Arg::with_name(OPT_BACKUP) Arg::with_name(options::BACKUP)
.long(OPT_BACKUP) .long(options::BACKUP)
.help( .help(
"make a backup of each file that would otherwise be overwritten \ "make a backup of each file that would otherwise be overwritten \
or removed", or removed",
) )
.takes_value(true) .takes_value(true)
.possible_value("simple") .possible_values(&[
.possible_value("never") "simple", "never", "numbered", "t", "existing", "nil", "none", "off",
.possible_value("numbered") ])
.possible_value("t")
.possible_value("existing")
.possible_value("nil")
.possible_value("none")
.possible_value("off")
.value_name("METHOD"), .value_name("METHOD"),
) )
// TODO: opts.arg( // TODO: opts.arg(
// Arg::with_name(("d", "directory", "allow users with appropriate privileges to attempt \ // Arg::with_name(("d", "directory", "allow users with appropriate privileges to attempt \
// to make hard links to directories"); // to make hard links to directories");
.arg( .arg(
Arg::with_name(OPT_FORCE) Arg::with_name(options::FORCE)
.short("f") .short("f")
.long(OPT_FORCE) .long(options::FORCE)
.help("remove existing destination files"), .help("remove existing destination files"),
) )
.arg( .arg(
Arg::with_name(OPT_INTERACTIVE) Arg::with_name(options::INTERACTIVE)
.short("i") .short("i")
.long(OPT_INTERACTIVE) .long(options::INTERACTIVE)
.help("prompt whether to remove existing destination files"), .help("prompt whether to remove existing destination files"),
) )
.arg( .arg(
Arg::with_name(OPT_NO_DEREFERENCE) Arg::with_name(options::NO_DEREFERENCE)
.short("n") .short("n")
.long(OPT_NO_DEREFERENCE) .long(options::NO_DEREFERENCE)
.help( .help(
"treat LINK_NAME as a normal file if it is a \ "treat LINK_NAME as a normal file if it is a \
symbolic link to a directory", symbolic link to a directory",
@ -152,44 +149,46 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
// TODO: opts.arg( // TODO: opts.arg(
// Arg::with_name(("P", "physical", "make hard links directly to symbolic links"); // Arg::with_name(("P", "physical", "make hard links directly to symbolic links");
.arg( .arg(
Arg::with_name(OPT_SYMBOLIC) Arg::with_name(options::SYMBOLIC)
.short("s") .short("s")
.long("symbolic") .long("symbolic")
.help("make symbolic links instead of hard links"), .help("make symbolic links instead of hard links")
// override added for https://github.com/uutils/coreutils/issues/2359
.overrides_with(options::SYMBOLIC),
) )
.arg( .arg(
Arg::with_name(OPT_SUFFIX) Arg::with_name(options::SUFFIX)
.short("S") .short("S")
.long(OPT_SUFFIX) .long(options::SUFFIX)
.help("override the usual backup suffix") .help("override the usual backup suffix")
.value_name("SUFFIX") .value_name("SUFFIX")
.takes_value(true), .takes_value(true),
) )
.arg( .arg(
Arg::with_name(OPT_TARGET_DIRECTORY) Arg::with_name(options::TARGET_DIRECTORY)
.short("t") .short("t")
.long(OPT_TARGET_DIRECTORY) .long(options::TARGET_DIRECTORY)
.help("specify the DIRECTORY in which to create the links") .help("specify the DIRECTORY in which to create the links")
.value_name("DIRECTORY") .value_name("DIRECTORY")
.conflicts_with(OPT_NO_TARGET_DIRECTORY), .conflicts_with(options::NO_TARGET_DIRECTORY),
) )
.arg( .arg(
Arg::with_name(OPT_NO_TARGET_DIRECTORY) Arg::with_name(options::NO_TARGET_DIRECTORY)
.short("T") .short("T")
.long(OPT_NO_TARGET_DIRECTORY) .long(options::NO_TARGET_DIRECTORY)
.help("treat LINK_NAME as a normal file always"), .help("treat LINK_NAME as a normal file always"),
) )
.arg( .arg(
Arg::with_name(OPT_RELATIVE) Arg::with_name(options::RELATIVE)
.short("r") .short("r")
.long(OPT_RELATIVE) .long(options::RELATIVE)
.help("create symbolic links relative to link location") .help("create symbolic links relative to link location")
.requires(OPT_SYMBOLIC), .requires(options::SYMBOLIC),
) )
.arg( .arg(
Arg::with_name(OPT_VERBOSE) Arg::with_name(options::VERBOSE)
.short("v") .short("v")
.long(OPT_VERBOSE) .long(options::VERBOSE)
.help("print name of each linked file"), .help("print name of each linked file"),
) )
.arg( .arg(
@ -209,18 +208,18 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.map(PathBuf::from) .map(PathBuf::from)
.collect(); .collect();
let overwrite_mode = if matches.is_present(OPT_FORCE) { let overwrite_mode = if matches.is_present(options::FORCE) {
OverwriteMode::Force OverwriteMode::Force
} else if matches.is_present(OPT_INTERACTIVE) { } else if matches.is_present(options::INTERACTIVE) {
OverwriteMode::Interactive OverwriteMode::Interactive
} else { } else {
OverwriteMode::NoClobber OverwriteMode::NoClobber
}; };
let backup_mode = if matches.is_present(OPT_B) { let backup_mode = if matches.is_present(options::B) {
BackupMode::ExistingBackup BackupMode::ExistingBackup
} else if matches.is_present(OPT_BACKUP) { } else if matches.is_present(options::BACKUP) {
match matches.value_of(OPT_BACKUP) { match matches.value_of(options::BACKUP) {
None => BackupMode::ExistingBackup, None => BackupMode::ExistingBackup,
Some(mode) => match mode { Some(mode) => match mode {
"simple" | "never" => BackupMode::SimpleBackup, "simple" | "never" => BackupMode::SimpleBackup,
@ -234,8 +233,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
BackupMode::NoBackup BackupMode::NoBackup
}; };
let backup_suffix = if matches.is_present(OPT_SUFFIX) { let backup_suffix = if matches.is_present(options::SUFFIX) {
matches.value_of(OPT_SUFFIX).unwrap() matches.value_of(options::SUFFIX).unwrap()
} else { } else {
"~" "~"
}; };
@ -244,12 +243,14 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
overwrite: overwrite_mode, overwrite: overwrite_mode,
backup: backup_mode, backup: backup_mode,
suffix: backup_suffix.to_string(), suffix: backup_suffix.to_string(),
symbolic: matches.is_present(OPT_SYMBOLIC), symbolic: matches.is_present(options::SYMBOLIC),
relative: matches.is_present(OPT_RELATIVE), relative: matches.is_present(options::RELATIVE),
target_dir: matches.value_of(OPT_TARGET_DIRECTORY).map(String::from), target_dir: matches
no_target_dir: matches.is_present(OPT_NO_TARGET_DIRECTORY), .value_of(options::TARGET_DIRECTORY)
no_dereference: matches.is_present(OPT_NO_DEREFERENCE), .map(String::from),
verbose: matches.is_present(OPT_VERBOSE), no_target_dir: matches.is_present(options::NO_TARGET_DIRECTORY),
no_dereference: matches.is_present(options::NO_DEREFERENCE),
verbose: matches.is_present(options::VERBOSE),
}; };
exec(&paths[..], &settings) exec(&paths[..], &settings)

View file

@ -247,7 +247,7 @@ fn nl<T: Read>(reader: &mut BufReader<T>, settings: &Settings) {
let mut line_filter: fn(&str, &regex::Regex) -> bool = pass_regex; let mut line_filter: fn(&str, &regex::Regex) -> bool = pass_regex;
for mut l in reader.lines().map(|r| r.unwrap()) { for mut l in reader.lines().map(|r| r.unwrap()) {
// Sanitize the string. We want to print the newline ourselves. // Sanitize the string. We want to print the newline ourselves.
if !l.is_empty() && l.chars().rev().next().unwrap() == '\n' { if l.chars().last() == Some('\n') {
l.pop(); l.pop();
} }
// Next we iterate through the individual chars to see if this // Next we iterate through the individual chars to see if this

View file

@ -297,30 +297,25 @@ fn parse_type_string(params: &str) -> Result<Vec<ParsedFormatterItemInfo>, Strin
ch = chars.next(); ch = chars.next();
} }
if !decimal_size.is_empty() { if !decimal_size.is_empty() {
byte_size = match decimal_size.parse() { byte_size = decimal_size.parse().map_err(|_| {
Err(_) => { format!(
return Err(format!( "invalid number '{}' in format specification '{}'",
"invalid number '{}' in format specification '{}'", decimal_size, params
decimal_size, params )
)) })?;
}
Ok(n) => n,
}
} }
} }
if is_format_dump_char(ch, &mut show_ascii_dump) { if is_format_dump_char(ch, &mut show_ascii_dump) {
ch = chars.next(); ch = chars.next();
} }
match od_format_type(type_char, byte_size) { let ft = od_format_type(type_char, byte_size).ok_or_else(|| {
Some(ft) => formats.push(ParsedFormatterItemInfo::new(ft, show_ascii_dump)), format!(
None => { "invalid size '{}' in format specification '{}'",
return Err(format!( byte_size, params
"invalid size '{}' in format specification '{}'", )
byte_size, params })?;
)) formats.push(ParsedFormatterItemInfo::new(ft, show_ascii_dump));
}
}
} }
Ok(formats) Ok(formats)
@ -331,16 +326,13 @@ pub fn parse_format_flags_str(
args_str: &Vec<&'static str>, args_str: &Vec<&'static str>,
) -> Result<Vec<FormatterItemInfo>, String> { ) -> Result<Vec<FormatterItemInfo>, String> {
let args: Vec<String> = args_str.iter().map(|s| s.to_string()).collect(); let args: Vec<String> = args_str.iter().map(|s| s.to_string()).collect();
match parse_format_flags(&args) { parse_format_flags(&args).map(|v| {
Err(e) => Err(e), // tests using this function assume add_ascii_dump is not set
Ok(v) => { v.into_iter()
// tests using this function assume add_ascii_dump is not set .inspect(|f| assert!(!f.add_ascii_dump))
Ok(v.into_iter() .map(|f| f.formatter_item_info)
.inspect(|f| assert!(!f.add_ascii_dump)) .collect()
.map(|f| f.formatter_item_info) })
.collect())
}
}
} }
#[test] #[test]

View file

@ -241,13 +241,14 @@ fn no_leading_hyphen(path_segment: &str) -> bool {
// check whether a path segment contains only valid (read: portable) characters // check whether a path segment contains only valid (read: portable) characters
fn check_portable_chars(path_segment: &str) -> bool { fn check_portable_chars(path_segment: &str) -> bool {
let valid_str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-".to_string(); const VALID_CHARS: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-";
for ch in path_segment.chars() { for (i, ch) in path_segment.as_bytes().iter().enumerate() {
if !valid_str.contains(ch) { if !VALID_CHARS.contains(ch) {
let invalid = path_segment[i..].chars().next().unwrap();
writeln!( writeln!(
&mut std::io::stderr(), &mut std::io::stderr(),
"nonportable character '{}' in file name component '{}'", "nonportable character '{}' in file name component '{}'",
ch, invalid,
path_segment path_segment
); );
return false; return false;

View file

@ -401,18 +401,18 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
for file_group in file_groups { for file_group in file_groups {
let result_options = build_options(&matches, &file_group, args.join(" ")); let result_options = build_options(&matches, &file_group, args.join(" "));
let options = match result_options {
Ok(options) => options,
Err(err) => {
print_error(&matches, err);
return 1;
}
};
if result_options.is_err() { let cmd_result = if let Ok(group) = file_group.iter().exactly_one() {
print_error(&matches, result_options.err().unwrap()); pr(group, &options)
return 1;
}
let options = &result_options.unwrap();
let cmd_result = if file_group.len() == 1 {
pr(file_group.get(0).unwrap(), options)
} else { } else {
mpr(&file_group, options) mpr(&file_group, &options)
}; };
let status = match cmd_result { let status = match cmd_result {
@ -442,11 +442,12 @@ fn recreate_arguments(args: &[String]) -> Vec<String> {
let mut arguments = args.to_owned(); let mut arguments = args.to_owned();
let num_option = args.iter().find_position(|x| n_regex.is_match(x.trim())); let num_option = args.iter().find_position(|x| n_regex.is_match(x.trim()));
if let Some((pos, _value)) = num_option { if let Some((pos, _value)) = num_option {
let num_val_opt = args.get(pos + 1); if let Some(num_val_opt) = args.get(pos + 1) {
if num_val_opt.is_some() && !num_regex.is_match(num_val_opt.unwrap()) { if !num_regex.is_match(num_val_opt) {
let could_be_file = arguments.remove(pos + 1); let could_be_file = arguments.remove(pos + 1);
arguments.insert(pos + 1, format!("{}", NumberingMode::default().width)); arguments.insert(pos + 1, format!("{}", NumberingMode::default().width));
arguments.insert(pos + 2, could_be_file); arguments.insert(pos + 2, could_be_file);
}
} }
} }
@ -666,12 +667,14 @@ fn build_options(
None => end_page_in_plus_option, None => end_page_in_plus_option,
}; };
if end_page.is_some() && start_page > end_page.unwrap() { if let Some(end_page) = end_page {
return Err(PrError::EncounteredErrors(format!( if start_page > end_page {
"invalid --pages argument '{}:{}'", return Err(PrError::EncounteredErrors(format!(
start_page, "invalid --pages argument '{}:{}'",
end_page.unwrap() start_page,
))); end_page
)));
}
} }
let default_lines_per_page = if form_feed_used { let default_lines_per_page = if form_feed_used {
@ -947,7 +950,7 @@ fn read_stream_and_create_pages(
let current_page = x + 1; let current_page = x + 1;
current_page >= start_page current_page >= start_page
&& (last_page.is_none() || current_page <= last_page.unwrap()) && last_page.map_or(true, |last_page| current_page <= last_page)
}), }),
) )
} }
@ -1030,8 +1033,7 @@ fn print_page(lines: &[FileLine], options: &OutputOptions, page: usize) -> Resul
let lines_written = write_columns(lines, options, out)?; let lines_written = write_columns(lines, options, out)?;
for index in 0..trailer_content.len() { for (index, x) in trailer_content.iter().enumerate() {
let x = trailer_content.get(index).unwrap();
out.write_all(x.as_bytes())?; out.write_all(x.as_bytes())?;
if index + 1 != trailer_content.len() { if index + 1 != trailer_content.len() {
out.write_all(line_separator)?; out.write_all(line_separator)?;
@ -1074,8 +1076,7 @@ fn write_columns(
let mut offset = 0; let mut offset = 0;
for col in 0..columns { for col in 0..columns {
let mut inserted = 0; let mut inserted = 0;
for i in offset..lines.len() { for line in &lines[offset..] {
let line = lines.get(i).unwrap();
if line.file_id != col { if line.file_id != col {
break; break;
} }

View file

@ -55,18 +55,9 @@ impl Formatter for Decf {
); );
// strip trailing zeroes // strip trailing zeroes
if let Some(ref post_dec) = f_sci.post_decimal { if let Some(ref post_dec) = f_sci.post_decimal {
let mut i = post_dec.len(); let trimmed = post_dec.trim_end_matches('0');
{ if trimmed.len() != post_dec.len() {
let mut it = post_dec.chars(); f_sci.post_decimal = Some(trimmed.to_owned());
while let Some(c) = it.next_back() {
if c != '0' {
break;
}
i -= 1;
}
}
if i != post_dec.len() {
f_sci.post_decimal = Some(String::from(&post_dec[0..i]));
} }
} }
let f_fl = get_primitive_dec( let f_fl = get_primitive_dec(

View file

@ -247,8 +247,12 @@ pub fn get_primitive_dec(
first_segment.len() as isize - 1, first_segment.len() as isize - 1,
) )
} else { } else {
match first_segment.chars().next() { match first_segment
Some('0') => { .chars()
.next()
.expect("float_common: no chars in first segment.")
{
'0' => {
let it = second_segment.chars().enumerate(); let it = second_segment.chars().enumerate();
let mut m: isize = 0; let mut m: isize = 0;
let mut pre = String::from("0"); let mut pre = String::from("0");
@ -266,10 +270,7 @@ pub fn get_primitive_dec(
} }
(pre, post, m) (pre, post, m)
} }
Some(_) => (first_segment, second_segment, 0), _ => (first_segment, second_segment, 0),
None => {
panic!("float_common: no chars in first segment.");
}
} }
} }
} else { } else {

View file

@ -24,7 +24,7 @@ extern crate uucore;
static NAME: &str = "shred"; static NAME: &str = "shred";
const BLOCK_SIZE: usize = 512; const BLOCK_SIZE: usize = 512;
const NAME_CHARSET: &str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_."; const NAME_CHARSET: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.";
// Patterns as shown in the GNU coreutils shred implementation // Patterns as shown in the GNU coreutils shred implementation
const PATTERNS: [&[u8]; 22] = [ const PATTERNS: [&[u8]; 22] = [
@ -89,7 +89,7 @@ impl Iterator for FilenameGenerator {
// Make the return value, then increment // Make the return value, then increment
let mut ret = String::new(); let mut ret = String::new();
for i in name_charset_indices.iter() { for i in name_charset_indices.iter() {
let c: char = NAME_CHARSET.chars().nth(*i).unwrap(); let c = char::from(NAME_CHARSET[*i]);
ret.push(c); ret.push(c);
} }
@ -163,16 +163,14 @@ impl<'a> BytesGenerator<'a> {
return None; return None;
} }
let this_block_size = { let this_block_size = if !self.exact {
if !self.exact { self.block_size
} else {
let bytes_left = self.total_bytes - self.bytes_generated.get();
if bytes_left >= self.block_size as u64 {
self.block_size self.block_size
} else { } else {
let bytes_left = self.total_bytes - self.bytes_generated.get(); (bytes_left % self.block_size as u64) as usize
if bytes_left >= self.block_size as u64 {
self.block_size
} else {
(bytes_left % self.block_size as u64) as usize
}
} }
}; };
@ -184,12 +182,10 @@ impl<'a> BytesGenerator<'a> {
rng.fill(bytes); rng.fill(bytes);
} }
PassType::Pattern(pattern) => { PassType::Pattern(pattern) => {
let skip = { let skip = if self.bytes_generated.get() == 0 {
if self.bytes_generated.get() == 0 { 0
0 } else {
} else { (pattern.len() as u64 % self.bytes_generated.get()) as usize
(pattern.len() as u64 % self.bytes_generated.get()) as usize
}
}; };
// Copy the pattern in chunks rather than simply one byte at a time // Copy the pattern in chunks rather than simply one byte at a time

View file

@ -174,7 +174,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
match matches.value_of(options::LINES) { match matches.value_of(options::LINES) {
Some(n) => { Some(n) => {
let mut slice: &str = n; let mut slice: &str = n;
if slice.chars().next().unwrap_or('_') == '+' { if slice.as_bytes().first() == Some(&b'+') {
settings.beginning = true; settings.beginning = true;
slice = &slice[1..]; slice = &slice[1..];
} }
@ -189,7 +189,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
None => { None => {
if let Some(n) = matches.value_of(options::BYTES) { if let Some(n) = matches.value_of(options::BYTES) {
let mut slice: &str = n; let mut slice: &str = n;
if slice.chars().next().unwrap_or('_') == '+' { if slice.as_bytes().first() == Some(&b'+') {
settings.beginning = true; settings.beginning = true;
slice = &slice[1..]; slice = &slice[1..];
} }
@ -305,41 +305,35 @@ impl ParseSizeErr {
pub type ParseSizeResult = Result<u64, ParseSizeErr>; pub type ParseSizeResult = Result<u64, ParseSizeErr>;
pub fn parse_size(mut size_slice: &str) -> Result<u64, ParseSizeErr> { pub fn parse_size(mut size_slice: &str) -> Result<u64, ParseSizeErr> {
let mut base = if size_slice.chars().last().unwrap_or('_') == 'B' { let mut base = if size_slice.as_bytes().last() == Some(&b'B') {
size_slice = &size_slice[..size_slice.len() - 1]; size_slice = &size_slice[..size_slice.len() - 1];
1000u64 1000u64
} else { } else {
1024u64 1024u64
}; };
let exponent = if !size_slice.is_empty() { let exponent = match size_slice.as_bytes().last() {
let mut has_suffix = true; Some(unit) => match unit {
let exp = match size_slice.chars().last().unwrap_or('_') { b'K' | b'k' => 1u64,
'K' | 'k' => 1u64, b'M' => 2u64,
'M' => 2u64, b'G' => 3u64,
'G' => 3u64, b'T' => 4u64,
'T' => 4u64, b'P' => 5u64,
'P' => 5u64, b'E' => 6u64,
'E' => 6u64, b'Z' | b'Y' => {
'Z' | 'Y' => {
return Err(ParseSizeErr::size_too_big(size_slice)); return Err(ParseSizeErr::size_too_big(size_slice));
} }
'b' => { b'b' => {
base = 512u64; base = 512u64;
1u64 1u64
} }
_ => { _ => 0u64,
has_suffix = false; },
0u64 None => 0u64,
}
};
if has_suffix {
size_slice = &size_slice[..size_slice.len() - 1];
}
exp
} else {
0u64
}; };
if exponent != 0 {
size_slice = &size_slice[..size_slice.len() - 1];
}
let mut multiplier = 1u64; let mut multiplier = 1u64;
for _ in 0u64..exponent { for _ in 0u64..exponent {

View file

@ -22,14 +22,15 @@ use std::ops::RangeInclusive;
/// character; octal escape sequences consume 1 to 3 octal digits. /// character; octal escape sequences consume 1 to 3 octal digits.
#[inline] #[inline]
fn parse_sequence(s: &str) -> (char, usize) { fn parse_sequence(s: &str) -> (char, usize) {
let c = s.chars().next().expect("invalid escape: empty string"); let mut s = s.chars();
let c = s.next().expect("invalid escape: empty string");
if ('0'..='7').contains(&c) { if ('0'..='7').contains(&c) {
let mut v = c.to_digit(8).unwrap(); let mut v = c.to_digit(8).unwrap();
let mut consumed = 1; let mut consumed = 1;
let bits_per_digit = 3; let bits_per_digit = 3;
for c in s.chars().skip(1).take(2) { for c in s.take(2) {
match c.to_digit(8) { match c.to_digit(8) {
Some(c) => { Some(c) => {
v = (v << bits_per_digit) | c; v = (v << bits_per_digit) | c;

View file

@ -363,10 +363,7 @@ fn parse_size(size: &str) -> Result<u64, ()> {
// Get the numeric part of the size argument. For example, if the // Get the numeric part of the size argument. For example, if the
// argument is "123K", then the numeric part is "123". // argument is "123K", then the numeric part is "123".
let numeric_string: String = size.chars().take_while(|c| c.is_digit(10)).collect(); let numeric_string: String = size.chars().take_while(|c| c.is_digit(10)).collect();
let number: u64 = match numeric_string.parse() { let number: u64 = numeric_string.parse().map_err(|_| ())?;
Ok(n) => n,
Err(_) => return Err(()),
};
// Get the alphabetic units part of the size argument and compute // Get the alphabetic units part of the size argument and compute
// the factor it represents. For example, if the argument is "123K", // the factor it represents. For example, if the argument is "123K",

View file

@ -179,124 +179,58 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
// Ignored for 'who am i'. // Ignored for 'who am i'.
let short_list = matches.is_present(options::COUNT); let short_list = matches.is_present(options::COUNT);
// If true, display only name, line, and time fields. let all = matches.is_present(options::ALL);
let mut short_output = false;
// If true, display the hours:minutes since each user has touched
// the keyboard, or "." if within the last minute, or "old" if
// not within the last day.
let mut include_idle = false;
// If true, display a line at the top describing each field. // If true, display a line at the top describing each field.
let include_heading = matches.is_present(options::HEADING); let include_heading = matches.is_present(options::HEADING);
// If true, display a '+' for each user if mesg y, a '-' if mesg n, // If true, display a '+' for each user if mesg y, a '-' if mesg n,
// or a '?' if their tty cannot be statted. // or a '?' if their tty cannot be statted.
let include_mesg = matches.is_present(options::ALL) let include_mesg = all || matches.is_present(options::MESG) || matches.is_present("w");
|| matches.is_present(options::MESG)
|| matches.is_present("w");
// If true, display process termination & exit status.
let mut include_exit = false;
// If true, display the last boot time. // If true, display the last boot time.
let mut need_boottime = false; let need_boottime = all || matches.is_present(options::BOOT);
// If true, display dead processes. // If true, display dead processes.
let mut need_deadprocs = false; let need_deadprocs = all || matches.is_present(options::DEAD);
// If true, display processes waiting for user login. // If true, display processes waiting for user login.
let mut need_login = false; let need_login = all || matches.is_present(options::LOGIN);
// If true, display processes started by init. // If true, display processes started by init.
let mut need_initspawn = false; let need_initspawn = all || matches.is_present(options::PROCESS);
// If true, display the last clock change. // If true, display the last clock change.
let mut need_clockchange = false; let need_clockchange = all || matches.is_present(options::TIME);
// If true, display the current runlevel. // If true, display the current runlevel.
let mut need_runlevel = false; let need_runlevel = all || matches.is_present(options::RUNLEVEL);
let use_defaults = !(all
|| need_boottime
|| need_deadprocs
|| need_login
|| need_initspawn
|| need_runlevel
|| need_clockchange
|| matches.is_present(options::USERS));
// If true, display user processes. // If true, display user processes.
let mut need_users = false; let need_users = all || matches.is_present(options::USERS) || use_defaults;
// If true, display the hours:minutes since each user has touched
// the keyboard, or "." if within the last minute, or "old" if
// not within the last day.
let include_idle = need_deadprocs || need_login || need_runlevel || need_users;
// If true, display process termination & exit status.
let include_exit = need_deadprocs;
// If true, display only name, line, and time fields.
let short_output = !include_exit && use_defaults;
// If true, display info only for the controlling tty. // If true, display info only for the controlling tty.
let mut my_line_only = false; let my_line_only = matches.is_present(options::ONLY_HOSTNAME_USER) || files.len() == 2;
let mut assumptions = true;
#[allow(clippy::useless_let_if_seq)]
{
if matches.is_present(options::ALL) {
need_boottime = true;
need_deadprocs = true;
need_login = true;
need_initspawn = true;
need_runlevel = true;
need_clockchange = true;
need_users = true;
include_idle = true;
include_exit = true;
assumptions = false;
}
if matches.is_present(options::BOOT) {
need_boottime = true;
assumptions = false;
}
if matches.is_present(options::DEAD) {
need_deadprocs = true;
include_idle = true;
include_exit = true;
assumptions = false;
}
if matches.is_present(options::LOGIN) {
need_login = true;
include_idle = true;
assumptions = false;
}
if matches.is_present(options::ONLY_HOSTNAME_USER) || files.len() == 2 {
my_line_only = true;
}
if matches.is_present(options::PROCESS) {
need_initspawn = true;
assumptions = false;
}
if matches.is_present(options::RUNLEVEL) {
need_runlevel = true;
include_idle = true;
assumptions = false;
}
if matches.is_present(options::SHORT) {
short_output = true;
}
if matches.is_present(options::TIME) {
need_clockchange = true;
assumptions = false;
}
if matches.is_present(options::USERS) {
need_users = true;
include_idle = true;
assumptions = false;
}
if assumptions {
need_users = true;
short_output = true;
}
if include_exit {
short_output = false;
}
}
let mut who = Who { let mut who = Who {
do_lookup, do_lookup,

View file

@ -20,7 +20,6 @@ uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features=["
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
[target.'cfg(target_os = "windows")'.dependencies] [target.'cfg(target_os = "windows")'.dependencies]
advapi32-sys = "0.2.0"
winapi = { version = "0.3", features = ["lmcons"] } winapi = { version = "0.3", features = ["lmcons"] }
[[bin]] [[bin]]

View file

@ -11,7 +11,7 @@ extern crate winapi;
use self::winapi::shared::lmcons; use self::winapi::shared::lmcons;
use self::winapi::shared::minwindef; use self::winapi::shared::minwindef;
use self::winapi::um::winnt; use self::winapi::um::{winbase, winnt};
use std::io::{Error, Result}; use std::io::{Error, Result};
use std::mem; use std::mem;
use uucore::wide::FromWide; use uucore::wide::FromWide;
@ -20,7 +20,7 @@ pub unsafe fn get_username() -> Result<String> {
#[allow(deprecated)] #[allow(deprecated)]
let mut buffer: [winnt::WCHAR; lmcons::UNLEN as usize + 1] = mem::uninitialized(); let mut buffer: [winnt::WCHAR; lmcons::UNLEN as usize + 1] = mem::uninitialized();
let mut len = buffer.len() as minwindef::DWORD; let mut len = buffer.len() as minwindef::DWORD;
if advapi32::GetUserNameW(buffer.as_mut_ptr(), &mut len) == 0 { if winbase::GetUserNameW(buffer.as_mut_ptr(), &mut len) == 0 {
return Err(Error::last_os_error()); return Err(Error::last_os_error());
} }
let username = String::from_wide(&buffer[..len as usize - 1]); let username = String::from_wide(&buffer[..len as usize - 1]);