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

Update message quoting and filename printing

This commit is contained in:
Jan Verbeek 2021-09-03 16:10:39 +02:00
parent 60df3c6b7c
commit 259f18fcab
91 changed files with 777 additions and 550 deletions

View file

@ -9,6 +9,8 @@ bytewise
canonicalization canonicalization
canonicalize canonicalize
canonicalizing canonicalizing
codepoint
codepoints
colorizable colorizable
colorize colorize
coprime coprime

View file

@ -10,10 +10,12 @@ use clap::Arg;
use clap::Shell; use clap::Shell;
use std::cmp; use std::cmp;
use std::collections::hash_map::HashMap; use std::collections::hash_map::HashMap;
use std::ffi::OsStr;
use std::ffi::OsString; use std::ffi::OsString;
use std::io::{self, Write}; use std::io::{self, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::process; use std::process;
use uucore::display::Quotable;
const VERSION: &str = env!("CARGO_PKG_VERSION"); const VERSION: &str = env!("CARGO_PKG_VERSION");
@ -76,13 +78,21 @@ fn main() {
// 0th argument equals util name? // 0th argument equals util name?
if let Some(util_os) = util_name { if let Some(util_os) = util_name {
let util = util_os.as_os_str().to_string_lossy(); fn not_found(util: &OsStr) -> ! {
println!("{}: function/utility not found", util.maybe_quote());
process::exit(1);
}
let util = match util_os.to_str() {
Some(util) => util,
None => not_found(&util_os),
};
if util == "completion" { if util == "completion" {
gen_completions(args, utils); gen_completions(args, utils);
} }
match utils.get(&util[..]) { match utils.get(util) {
Some(&(uumain, _)) => { Some(&(uumain, _)) => {
process::exit(uumain((vec![util_os].into_iter()).chain(args))); process::exit(uumain((vec![util_os].into_iter()).chain(args)));
} }
@ -90,9 +100,12 @@ fn main() {
if util == "--help" || util == "-h" { if util == "--help" || util == "-h" {
// see if they want help on a specific util // see if they want help on a specific util
if let Some(util_os) = args.next() { if let Some(util_os) = args.next() {
let util = util_os.as_os_str().to_string_lossy(); let util = match util_os.to_str() {
Some(util) => util,
None => not_found(&util_os),
};
match utils.get(&util[..]) { match utils.get(util) {
Some(&(uumain, _)) => { Some(&(uumain, _)) => {
let code = uumain( let code = uumain(
(vec![util_os, OsString::from("--help")].into_iter()) (vec![util_os, OsString::from("--help")].into_iter())
@ -101,17 +114,13 @@ fn main() {
io::stdout().flush().expect("could not flush stdout"); io::stdout().flush().expect("could not flush stdout");
process::exit(code); process::exit(code);
} }
None => { None => not_found(&util_os),
println!("{}: function/utility not found", util);
process::exit(1);
}
} }
} }
usage(&utils, binary_as_util); usage(&utils, binary_as_util);
process::exit(0); process::exit(0);
} else { } else {
println!("{}: function/utility not found", util); not_found(&util_os);
process::exit(1);
} }
} }
} }

View file

@ -9,6 +9,7 @@
use std::io::{stdout, Read, Write}; use std::io::{stdout, Read, Write};
use uucore::display::Quotable;
use uucore::encoding::{wrap_print, Data, Format}; use uucore::encoding::{wrap_print, Data, Format};
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
@ -40,8 +41,9 @@ impl Config {
let name = values.next().unwrap(); let name = values.next().unwrap();
if let Some(extra_op) = values.next() { if let Some(extra_op) = values.next() {
return Err(format!( return Err(format!(
"extra operand '{}'\nTry '{} --help' for more information.", "extra operand {}\nTry '{} --help' for more information.",
extra_op, app_name extra_op.quote(),
app_name
)); ));
} }
@ -49,7 +51,7 @@ impl Config {
None None
} else { } else {
if !Path::exists(Path::new(name)) { if !Path::exists(Path::new(name)) {
return Err(format!("{}: No such file or directory", name)); return Err(format!("{}: No such file or directory", name.maybe_quote()));
} }
Some(name.to_owned()) Some(name.to_owned())
} }
@ -61,7 +63,7 @@ impl Config {
.value_of(options::WRAP) .value_of(options::WRAP)
.map(|num| { .map(|num| {
num.parse::<usize>() num.parse::<usize>()
.map_err(|_| format!("invalid wrap size: '{}'", num)) .map_err(|_| format!("invalid wrap size: {}", num.quote()))
}) })
.transpose()?; .transpose()?;

View file

@ -20,6 +20,7 @@ use clap::{crate_version, App, Arg};
use std::fs::{metadata, File}; use std::fs::{metadata, File};
use std::io::{self, Read, Write}; use std::io::{self, Read, Write};
use thiserror::Error; use thiserror::Error;
use uucore::display::Quotable;
use uucore::error::UResult; use uucore::error::UResult;
#[cfg(unix)] #[cfg(unix)]
@ -386,7 +387,7 @@ fn cat_files(files: Vec<String>, options: &OutputOptions) -> UResult<()> {
for path in &files { for path in &files {
if let Err(err) = cat_path(path, options, &mut state, &out_info) { if let Err(err) = cat_path(path, options, &mut state, &out_info) {
error_messages.push(format!("{}: {}", path, err)); error_messages.push(format!("{}: {}", path.maybe_quote(), err));
} }
} }
if state.skipped_carriage_return { if state.skipped_carriage_return {

View file

@ -2,7 +2,7 @@
#![allow(clippy::upper_case_acronyms)] #![allow(clippy::upper_case_acronyms)]
use uucore::{show_error, show_usage_error, show_warning}; use uucore::{display::Quotable, show_error, show_usage_error, show_warning};
use clap::{App, Arg}; use clap::{App, Arg};
use selinux::{OpaqueSecurityContext, SecurityContext}; use selinux::{OpaqueSecurityContext, SecurityContext};
@ -111,13 +111,13 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
Ok(context) => context, Ok(context) => context,
Err(_r) => { Err(_r) => {
show_error!("Invalid security context '{}'.", context.to_string_lossy()); show_error!("Invalid security context {}.", context.quote());
return libc::EXIT_FAILURE; return libc::EXIT_FAILURE;
} }
}; };
if SecurityContext::from_c_str(&c_context, false).check() == Some(false) { if SecurityContext::from_c_str(&c_context, false).check() == Some(false) {
show_error!("Invalid security context '{}'.", context.to_string_lossy()); show_error!("Invalid security context {}.", context.quote());
return libc::EXIT_FAILURE; return libc::EXIT_FAILURE;
} }
@ -564,7 +564,7 @@ fn process_file(
println!( println!(
"{}: Changing security context of: {}", "{}: Changing security context of: {}",
uucore::util_name(), uucore::util_name(),
file_full_name.to_string_lossy() file_full_name.quote()
); );
} }
@ -699,9 +699,9 @@ fn root_dev_ino_warn(dir_name: &Path) {
); );
} else { } else {
show_warning!( show_warning!(
"It is dangerous to operate recursively on '{}' (same as '/'). \ "It is dangerous to operate recursively on {} (same as '/'). \
Use --{} to override this failsafe.", Use --{} to override this failsafe.",
dir_name.to_string_lossy(), dir_name.quote(),
options::preserve_root::NO_PRESERVE_ROOT, options::preserve_root::NO_PRESERVE_ROOT,
); );
} }
@ -726,8 +726,8 @@ fn emit_cycle_warning(file_name: &Path) {
"Circular directory structure.\n\ "Circular directory structure.\n\
This almost certainly means that you have a corrupted file system.\n\ This almost certainly means that you have a corrupted file system.\n\
NOTIFY YOUR SYSTEM MANAGER.\n\ NOTIFY YOUR SYSTEM MANAGER.\n\
The following directory is part of the cycle '{}'.", The following directory is part of the cycle {}.",
file_name.display() file_name.quote()
) )
} }

View file

@ -2,6 +2,8 @@ use std::ffi::OsString;
use std::fmt::Write; use std::fmt::Write;
use std::io; use std::io;
use uucore::display::Quotable;
pub(crate) type Result<T> = std::result::Result<T, Error>; pub(crate) type Result<T> = std::result::Result<T, Error>;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
@ -30,7 +32,7 @@ pub(crate) enum Error {
source: io::Error, source: io::Error,
}, },
#[error("{operation} failed on '{}'", .operand1.to_string_lossy())] #[error("{operation} failed on {}", .operand1.quote())]
Io1 { Io1 {
operation: &'static str, operation: &'static str,
operand1: OsString, operand1: OsString,

View file

@ -9,6 +9,7 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::display::Quotable;
pub use uucore::entries; pub use uucore::entries;
use uucore::error::{FromIo, UResult, USimpleError}; use uucore::error::{FromIo, UResult, USimpleError};
use uucore::perms::{chown_base, options, IfFrom}; use uucore::perms::{chown_base, options, IfFrom};
@ -32,7 +33,7 @@ fn parse_gid_and_uid(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>,
let dest_gid = if let Some(file) = matches.value_of(options::REFERENCE) { let dest_gid = if let Some(file) = matches.value_of(options::REFERENCE) {
fs::metadata(&file) fs::metadata(&file)
.map(|meta| Some(meta.gid())) .map(|meta| Some(meta.gid()))
.map_err_context(|| format!("failed to get attributes of '{}'", file))? .map_err_context(|| format!("failed to get attributes of {}", file.quote()))?
} else { } else {
let group = matches.value_of(options::ARG_GROUP).unwrap_or_default(); let group = matches.value_of(options::ARG_GROUP).unwrap_or_default();
if group.is_empty() { if group.is_empty() {
@ -40,7 +41,12 @@ fn parse_gid_and_uid(matches: &ArgMatches) -> UResult<(Option<u32>, Option<u32>,
} else { } else {
match entries::grp2gid(group) { match entries::grp2gid(group) {
Ok(g) => Some(g), Ok(g) => Some(g),
_ => return Err(USimpleError::new(1, format!("invalid group: '{}'", group))), _ => {
return Err(USimpleError::new(
1,
format!("invalid group: {}", group.quote()),
))
}
} }
} }
}; };

View file

@ -14,6 +14,7 @@ use clap::{crate_version, App, Arg};
use std::fs; use std::fs;
use std::os::unix::fs::{MetadataExt, PermissionsExt}; use std::os::unix::fs::{MetadataExt, PermissionsExt};
use std::path::Path; use std::path::Path;
use uucore::display::Quotable;
use uucore::fs::display_permissions_unix; use uucore::fs::display_permissions_unix;
use uucore::libc::mode_t; use uucore::libc::mode_t;
#[cfg(not(windows))] #[cfg(not(windows))]
@ -75,7 +76,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.value_of(options::REFERENCE) .value_of(options::REFERENCE)
.and_then(|fref| match fs::metadata(fref) { .and_then(|fref| match fs::metadata(fref) {
Ok(meta) => Some(meta.mode()), Ok(meta) => Some(meta.mode()),
Err(err) => crash!(1, "cannot stat attributes of '{}': {}", fref, err), Err(err) => crash!(1, "cannot stat attributes of {}: {}", fref.quote(), err),
}); });
let modes = matches.value_of(options::MODE).unwrap(); // should always be Some because required let modes = matches.value_of(options::MODE).unwrap(); // should always be Some because required
let cmode = if mode_had_minus_prefix { let cmode = if mode_had_minus_prefix {
@ -223,21 +224,24 @@ impl Chmoder {
if !file.exists() { if !file.exists() {
if is_symlink(file) { if is_symlink(file) {
println!( println!(
"failed to change mode of '{}' from 0000 (---------) to 0000 (---------)", "failed to change mode of {} from 0000 (---------) to 0000 (---------)",
filename filename.quote()
); );
if !self.quiet { if !self.quiet {
show_error!("cannot operate on dangling symlink '{}'", filename); show_error!("cannot operate on dangling symlink {}", filename.quote());
} }
} else if !self.quiet { } else if !self.quiet {
show_error!("cannot access '{}': No such file or directory", filename); show_error!(
"cannot access {}: No such file or directory",
filename.quote()
);
} }
return Err(1); return Err(1);
} }
if self.recursive && self.preserve_root && filename == "/" { if self.recursive && self.preserve_root && filename == "/" {
show_error!( show_error!(
"it is dangerous to operate recursively on '{}'\nuse --no-preserve-root to override this failsafe", "it is dangerous to operate recursively on {}\nuse --no-preserve-root to override this failsafe",
filename filename.quote()
); );
return Err(1); return Err(1);
} }
@ -270,15 +274,17 @@ impl Chmoder {
if is_symlink(file) { if is_symlink(file) {
if self.verbose { if self.verbose {
println!( println!(
"neither symbolic link '{}' nor referent has been changed", "neither symbolic link {} nor referent has been changed",
file.display() file.quote()
); );
} }
return Ok(()); return Ok(());
} else if err.kind() == std::io::ErrorKind::PermissionDenied { } else if err.kind() == std::io::ErrorKind::PermissionDenied {
show_error!("'{}': Permission denied", file.display()); // These two filenames would normally be conditionally
// quoted, but GNU's tests expect them to always be quoted
show_error!("{}: Permission denied", file.quote());
} else { } else {
show_error!("'{}': {}", file.display(), err); show_error!("{}: {}", file.quote(), err);
} }
return Err(1); return Err(1);
} }
@ -325,7 +331,7 @@ impl Chmoder {
if (new_mode & !naively_expected_new_mode) != 0 { if (new_mode & !naively_expected_new_mode) != 0 {
show_error!( show_error!(
"{}: new permissions are {}, not {}", "{}: new permissions are {}, not {}",
file.display(), file.maybe_quote(),
display_permissions_unix(new_mode as mode_t, false), display_permissions_unix(new_mode as mode_t, false),
display_permissions_unix(naively_expected_new_mode as mode_t, false) display_permissions_unix(naively_expected_new_mode as mode_t, false)
); );
@ -342,8 +348,8 @@ impl Chmoder {
if fperm == mode { if fperm == mode {
if self.verbose && !self.changes { if self.verbose && !self.changes {
println!( println!(
"mode of '{}' retained as {:04o} ({})", "mode of {} retained as {:04o} ({})",
file.display(), file.quote(),
fperm, fperm,
display_permissions_unix(fperm as mode_t, false), display_permissions_unix(fperm as mode_t, false),
); );
@ -355,8 +361,8 @@ impl Chmoder {
} }
if self.verbose { if self.verbose {
println!( println!(
"failed to change mode of file '{}' from {:04o} ({}) to {:04o} ({})", "failed to change mode of file {} from {:04o} ({}) to {:04o} ({})",
file.display(), file.quote(),
fperm, fperm,
display_permissions_unix(fperm as mode_t, false), display_permissions_unix(fperm as mode_t, false),
mode, mode,
@ -367,8 +373,8 @@ impl Chmoder {
} else { } else {
if self.verbose || self.changes { if self.verbose || self.changes {
println!( println!(
"mode of '{}' changed from {:04o} ({}) to {:04o} ({})", "mode of {} changed from {:04o} ({}) to {:04o} ({})",
file.display(), file.quote(),
fperm, fperm,
display_permissions_unix(fperm as mode_t, false), display_permissions_unix(fperm as mode_t, false),
mode, mode,

View file

@ -9,6 +9,7 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::display::Quotable;
pub use uucore::entries::{self, Group, Locate, Passwd}; pub use uucore::entries::{self, Group, Locate, Passwd};
use uucore::perms::{chown_base, options, IfFrom}; use uucore::perms::{chown_base, options, IfFrom};
@ -44,7 +45,7 @@ fn parse_gid_uid_and_filter(matches: &ArgMatches) -> UResult<(Option<u32>, Optio
let dest_gid: Option<u32>; let dest_gid: Option<u32>;
if let Some(file) = matches.value_of(options::REFERENCE) { if let Some(file) = matches.value_of(options::REFERENCE) {
let meta = fs::metadata(&file) let meta = fs::metadata(&file)
.map_err_context(|| format!("failed to get attributes of '{}'", file))?; .map_err_context(|| format!("failed to get attributes of {}", file.quote()))?;
dest_gid = Some(meta.gid()); dest_gid = Some(meta.gid());
dest_uid = Some(meta.uid()); dest_uid = Some(meta.uid());
} else { } else {
@ -173,7 +174,7 @@ fn parse_spec(spec: &str) -> UResult<(Option<u32>, Option<u32>)> {
let uid = if usr_only || usr_grp { let uid = if usr_only || usr_grp {
Some( Some(
Passwd::locate(args[0]) Passwd::locate(args[0])
.map_err(|_| USimpleError::new(1, format!("invalid user: '{}'", spec)))? .map_err(|_| USimpleError::new(1, format!("invalid user: {}", spec.quote())))?
.uid(), .uid(),
) )
} else { } else {
@ -182,7 +183,7 @@ fn parse_spec(spec: &str) -> UResult<(Option<u32>, Option<u32>)> {
let gid = if grp_only || usr_grp { let gid = if grp_only || usr_grp {
Some( Some(
Group::locate(args[1]) Group::locate(args[1])
.map_err(|_| USimpleError::new(1, format!("invalid group: '{}'", spec)))? .map_err(|_| USimpleError::new(1, format!("invalid group: {}", spec.quote())))?
.gid(), .gid(),
) )
} else { } else {

View file

@ -15,6 +15,7 @@ use std::ffi::CString;
use std::io::Error; use std::io::Error;
use std::path::Path; use std::path::Path;
use std::process::Command; use std::process::Command;
use uucore::display::Quotable;
use uucore::libc::{self, chroot, setgid, setgroups, setuid}; use uucore::libc::{self, chroot, setgid, setgroups, setuid};
use uucore::{entries, InvalidEncodingHandling}; use uucore::{entries, InvalidEncodingHandling};
@ -53,8 +54,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
if !newroot.is_dir() { if !newroot.is_dir() {
crash!( crash!(
1, 1,
"cannot change root directory to `{}`: no such directory", "cannot change root directory to {}: no such directory",
newroot.display() newroot.quote()
); );
} }
@ -170,7 +171,6 @@ fn set_context(root: &Path, options: &clap::ArgMatches) {
} }
fn enter_chroot(root: &Path) { fn enter_chroot(root: &Path) {
let root_str = root.display();
std::env::set_current_dir(root).unwrap(); std::env::set_current_dir(root).unwrap();
let err = unsafe { let err = unsafe {
chroot(CString::new(".").unwrap().as_bytes_with_nul().as_ptr() as *const libc::c_char) chroot(CString::new(".").unwrap().as_bytes_with_nul().as_ptr() as *const libc::c_char)
@ -179,7 +179,7 @@ fn enter_chroot(root: &Path) {
crash!( crash!(
1, 1,
"cannot chroot to {}: {}", "cannot chroot to {}: {}",
root_str, root.quote(),
Error::last_os_error() Error::last_os_error()
) )
}; };
@ -189,7 +189,7 @@ fn set_main_group(group: &str) {
if !group.is_empty() { if !group.is_empty() {
let group_id = match entries::grp2gid(group) { let group_id = match entries::grp2gid(group) {
Ok(g) => g, Ok(g) => g,
_ => crash!(1, "no such group: {}", group), _ => crash!(1, "no such group: {}", group.maybe_quote()),
}; };
let err = unsafe { setgid(group_id) }; let err = unsafe { setgid(group_id) };
if err != 0 { if err != 0 {
@ -234,7 +234,12 @@ fn set_user(user: &str) {
let user_id = entries::usr2uid(user).unwrap(); let user_id = entries::usr2uid(user).unwrap();
let err = unsafe { setuid(user_id as libc::uid_t) }; let err = unsafe { setuid(user_id as libc::uid_t) };
if err != 0 { if err != 0 {
crash!(1, "cannot set user to {}: {}", user, Error::last_os_error()) crash!(
1,
"cannot set user to {}: {}",
user.maybe_quote(),
Error::last_os_error()
)
} }
} }
} }

View file

@ -14,6 +14,7 @@ use clap::{crate_version, App, Arg};
use std::fs::File; use std::fs::File;
use std::io::{self, stdin, BufReader, Read}; use std::io::{self, stdin, BufReader, Read};
use std::path::Path; use std::path::Path;
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
// NOTE: CRC_TABLE_LEN *must* be <= 256 as we cast 0..CRC_TABLE_LEN to u8 // NOTE: CRC_TABLE_LEN *must* be <= 256 as we cast 0..CRC_TABLE_LEN to u8
@ -191,7 +192,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
match cksum("-") { match cksum("-") {
Ok((crc, size)) => println!("{} {}", crc, size), Ok((crc, size)) => println!("{} {}", crc, size),
Err(err) => { Err(err) => {
show_error!("{}", err); show_error!("-: {}", err);
return 2; return 2;
} }
} }
@ -203,7 +204,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
match cksum(fname.as_ref()) { match cksum(fname.as_ref()) {
Ok((crc, size)) => println!("{} {} {}", crc, size, fname), Ok((crc, size)) => println!("{} {} {}", crc, size, fname),
Err(err) => { Err(err) => {
show_error!("'{}' {}", fname, err); show_error!("{}: {}", fname.maybe_quote(), err);
exit_code = 2; exit_code = 2;
} }
} }

View file

@ -18,6 +18,7 @@ extern crate quick_error;
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::display::Quotable;
#[cfg(windows)] #[cfg(windows)]
use winapi::um::fileapi::CreateFileW; use winapi::um::fileapi::CreateFileW;
#[cfg(windows)] #[cfg(windows)]
@ -541,8 +542,8 @@ impl FromStr for Attribute {
"xattr" => Attribute::Xattr, "xattr" => Attribute::Xattr,
_ => { _ => {
return Err(Error::InvalidArgument(format!( return Err(Error::InvalidArgument(format!(
"invalid attribute '{}'", "invalid attribute {}",
value value.quote()
))); )));
} }
}) })
@ -659,8 +660,8 @@ impl Options {
"never" => ReflinkMode::Never, "never" => ReflinkMode::Never,
value => { value => {
return Err(Error::InvalidArgument(format!( return Err(Error::InvalidArgument(format!(
"invalid argument '{}' for \'reflink\'", "invalid argument {} for \'reflink\'",
value value.quote()
))); )));
} }
} }
@ -832,7 +833,7 @@ fn copy(sources: &[Source], target: &TargetSlice, options: &Options) -> CopyResu
let mut seen_sources = HashSet::with_capacity(sources.len()); let mut seen_sources = HashSet::with_capacity(sources.len());
for source in sources { for source in sources {
if seen_sources.contains(source) { if seen_sources.contains(source) {
show_warning!("source '{}' specified more than once", source.display()); show_warning!("source {} specified more than once", source.quote());
} else { } else {
let mut found_hard_link = false; let mut found_hard_link = false;
if preserve_hard_links { if preserve_hard_links {
@ -873,8 +874,8 @@ fn construct_dest_path(
) -> CopyResult<PathBuf> { ) -> CopyResult<PathBuf> {
if options.no_target_dir && target.is_dir() { if options.no_target_dir && target.is_dir() {
return Err(format!( return Err(format!(
"cannot overwrite directory '{}' with non-directory", "cannot overwrite directory {} with non-directory",
target.display() target.quote()
) )
.into()); .into());
} }
@ -941,7 +942,7 @@ fn adjust_canonicalization(p: &Path) -> Cow<Path> {
/// will not cause a short-circuit. /// will not cause a short-circuit.
fn copy_directory(root: &Path, target: &TargetSlice, options: &Options) -> CopyResult<()> { fn copy_directory(root: &Path, target: &TargetSlice, options: &Options) -> CopyResult<()> {
if !options.recursive { if !options.recursive {
return Err(format!("omitting directory '{}'", root.display()).into()); return Err(format!("omitting directory {}", root.quote()).into());
} }
// if no-dereference is enabled and this is a symlink, copy it as a file // if no-dereference is enabled and this is a symlink, copy it as a file
@ -1041,12 +1042,12 @@ impl OverwriteMode {
match *self { match *self {
OverwriteMode::NoClobber => Err(Error::NotAllFilesCopied), OverwriteMode::NoClobber => Err(Error::NotAllFilesCopied),
OverwriteMode::Interactive(_) => { OverwriteMode::Interactive(_) => {
if prompt_yes!("{}: overwrite {}? ", uucore::util_name(), path.display()) { if prompt_yes!("{}: overwrite {}? ", uucore::util_name(), path.quote()) {
Ok(()) Ok(())
} else { } else {
Err(Error::Skipped(format!( Err(Error::Skipped(format!(
"Not overwriting {} at user request", "Not overwriting {} at user request",
path.display() path.quote()
))) )))
} }
} }
@ -1056,7 +1057,7 @@ impl OverwriteMode {
} }
fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResult<()> { fn copy_attribute(source: &Path, dest: &Path, attribute: &Attribute) -> CopyResult<()> {
let context = &*format!("'{}' -> '{}'", source.display().to_string(), dest.display()); let context = &*format!("{} -> {}", source.quote(), dest.quote());
let source_metadata = fs::symlink_metadata(source).context(context)?; let source_metadata = fs::symlink_metadata(source).context(context)?;
match *attribute { match *attribute {
Attribute::Mode => { Attribute::Mode => {
@ -1152,7 +1153,7 @@ fn symlink_file(source: &Path, dest: &Path, context: &str) -> CopyResult<()> {
} }
fn context_for(src: &Path, dest: &Path) -> String { fn context_for(src: &Path, dest: &Path) -> String {
format!("'{}' -> '{}'", src.display(), dest.display()) format!("{} -> {}", src.quote(), dest.quote())
} }
/// Implements a simple backup copy for the destination file. /// Implements a simple backup copy for the destination file.
@ -1332,8 +1333,8 @@ fn copy_link(source: &Path, dest: &Path) -> CopyResult<()> {
Some(name) => dest.join(name).into(), Some(name) => dest.join(name).into(),
None => crash!( None => crash!(
EXIT_ERR, EXIT_ERR,
"cannot stat '{}': No such file or directory", "cannot stat {}: No such file or directory",
source.display() source.quote()
), ),
} }
} else { } else {
@ -1454,11 +1455,11 @@ fn copy_on_write_macos(
pub fn verify_target_type(target: &Path, target_type: &TargetType) -> CopyResult<()> { pub fn verify_target_type(target: &Path, target_type: &TargetType) -> CopyResult<()> {
match (target_type, target.is_dir()) { match (target_type, target.is_dir()) {
(&TargetType::Directory, false) => { (&TargetType::Directory, false) => {
Err(format!("target: '{}' is not a directory", target.display()).into()) Err(format!("target: {} is not a directory", target.quote()).into())
} }
(&TargetType::File, true) => Err(format!( (&TargetType::File, true) => Err(format!(
"cannot overwrite directory '{}' with non-directory", "cannot overwrite directory {} with non-directory",
target.display() target.quote()
) )
.into()), .into()),
_ => Ok(()), _ => Ok(()),

View file

@ -10,6 +10,7 @@ use std::{
fs::{remove_file, File}, fs::{remove_file, File},
io::{BufRead, BufWriter, Write}, io::{BufRead, BufWriter, Write},
}; };
use uucore::display::Quotable;
mod csplit_error; mod csplit_error;
mod patterns; mod patterns;
@ -734,7 +735,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let file = crash_if_err!(1, File::open(file_name)); let file = crash_if_err!(1, File::open(file_name));
let file_metadata = crash_if_err!(1, file.metadata()); let file_metadata = crash_if_err!(1, file.metadata());
if !file_metadata.is_file() { if !file_metadata.is_file() {
crash!(1, "'{}' is not a regular file", file_name); crash!(1, "{} is not a regular file", file_name.quote());
} }
crash_if_err!(1, csplit(&options, patterns, BufReader::new(file))); crash_if_err!(1, csplit(&options, patterns, BufReader::new(file)));
}; };

View file

@ -1,26 +1,28 @@
use std::io; use std::io;
use thiserror::Error; use thiserror::Error;
use uucore::display::Quotable;
/// Errors thrown by the csplit command /// Errors thrown by the csplit command
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum CsplitError { pub enum CsplitError {
#[error("IO error: {}", _0)] #[error("IO error: {}", _0)]
IoError(io::Error), IoError(io::Error),
#[error("'{}': line number out of range", _0)] #[error("{}: line number out of range", ._0.quote())]
LineOutOfRange(String), LineOutOfRange(String),
#[error("'{}': line number out of range on repetition {}", _0, _1)] #[error("{}: line number out of range on repetition {}", ._0.quote(), _1)]
LineOutOfRangeOnRepetition(String, usize), LineOutOfRangeOnRepetition(String, usize),
#[error("'{}': match not found", _0)] #[error("{}: match not found", ._0.quote())]
MatchNotFound(String), MatchNotFound(String),
#[error("'{}': match not found on repetition {}", _0, _1)] #[error("{}: match not found on repetition {}", ._0.quote(), _1)]
MatchNotFoundOnRepetition(String, usize), MatchNotFoundOnRepetition(String, usize),
#[error("line number must be greater than zero")] #[error("line number must be greater than zero")]
LineNumberIsZero, LineNumberIsZero,
#[error("line number '{}' is smaller than preceding line number, {}", _0, _1)] #[error("line number '{}' is smaller than preceding line number, {}", _0, _1)]
LineNumberSmallerThanPrevious(usize, usize), LineNumberSmallerThanPrevious(usize, usize),
#[error("invalid pattern: {}", _0)] #[error("{}: invalid pattern", ._0.quote())]
InvalidPattern(String), InvalidPattern(String),
#[error("invalid number: '{}'", _0)] #[error("invalid number: {}", ._0.quote())]
InvalidNumber(String), InvalidNumber(String),
#[error("incorrect conversion specification in suffix")] #[error("incorrect conversion specification in suffix")]
SuffixFormatIncorrect, SuffixFormatIncorrect,

View file

@ -15,6 +15,7 @@ use clap::{crate_version, App, Arg};
use std::fs::File; use std::fs::File;
use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write}; use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write};
use std::path::Path; use std::path::Path;
use uucore::display::Quotable;
use self::searcher::Searcher; use self::searcher::Searcher;
use uucore::ranges::Range; use uucore::ranges::Range;
@ -351,19 +352,19 @@ fn cut_files(mut filenames: Vec<String>, mode: Mode) -> i32 {
let path = Path::new(&filename[..]); let path = Path::new(&filename[..]);
if path.is_dir() { if path.is_dir() {
show_error!("{}: Is a directory", filename); show_error!("{}: Is a directory", filename.maybe_quote());
continue; continue;
} }
if path.metadata().is_err() { if path.metadata().is_err() {
show_error!("{}: No such file or directory", filename); show_error!("{}: No such file or directory", filename.maybe_quote());
continue; continue;
} }
let file = match File::open(&path) { let file = match File::open(&path) {
Ok(f) => f, Ok(f) => f,
Err(e) => { Err(e) => {
show_error!("opening '{}': {}", &filename[..], e); show_error!("opening {}: {}", filename.quote(), e);
continue; continue;
} }
}; };

View file

@ -17,6 +17,7 @@ use libc::{clock_settime, timespec, CLOCK_REALTIME};
use std::fs::File; use std::fs::File;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::path::PathBuf; use std::path::PathBuf;
use uucore::display::Quotable;
#[cfg(windows)] #[cfg(windows)]
use winapi::{ use winapi::{
shared::minwindef::WORD, shared::minwindef::WORD,
@ -145,7 +146,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let format = if let Some(form) = matches.value_of(OPT_FORMAT) { let format = if let Some(form) = matches.value_of(OPT_FORMAT) {
if !form.starts_with('+') { if !form.starts_with('+') {
eprintln!("date: invalid date '{}'", form); eprintln!("date: invalid date {}", form.quote());
return 1; return 1;
} }
let form = form[1..].to_string(); let form = form[1..].to_string();
@ -174,7 +175,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let set_to = match matches.value_of(OPT_SET).map(parse_date) { let set_to = match matches.value_of(OPT_SET).map(parse_date) {
None => None, None => None,
Some(Err((input, _err))) => { Some(Err((input, _err))) => {
eprintln!("date: invalid date '{}'", input); eprintln!("date: invalid date {}", input.quote());
return 1; return 1;
} }
Some(Ok(date)) => Some(date), Some(Ok(date)) => Some(date),
@ -240,7 +241,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
println!("{}", formatted); println!("{}", formatted);
} }
Err((input, _err)) => { Err((input, _err)) => {
println!("date: invalid date '{}'", input); println!("date: invalid date {}", input.quote());
} }
} }
} }

View file

@ -17,6 +17,7 @@ use std::fs::File;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use uucore::display::Quotable;
mod options { mod options {
pub const BOURNE_SHELL: &str = "bourne-shell"; pub const BOURNE_SHELL: &str = "bourne-shell";
@ -94,9 +95,9 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
if matches.is_present(options::PRINT_DATABASE) { if matches.is_present(options::PRINT_DATABASE) {
if !files.is_empty() { if !files.is_empty() {
show_usage_error!( show_usage_error!(
"extra operand '{}'\nfile operands cannot be combined with \ "extra operand {}\nfile operands cannot be combined with \
--print-database (-p)", --print-database (-p)",
files[0] files[0].quote()
); );
return 1; return 1;
} }
@ -126,7 +127,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
result = parse(INTERNAL_DB.lines(), out_format, "") result = parse(INTERNAL_DB.lines(), out_format, "")
} else { } else {
if files.len() > 1 { if files.len() > 1 {
show_usage_error!("extra operand '{}'", files[1]); show_usage_error!("extra operand {}", files[1].quote());
return 1; return 1;
} }
match File::open(files[0]) { match File::open(files[0]) {
@ -135,7 +136,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
result = parse(fin.lines().filter_map(Result::ok), out_format, files[0]) result = parse(fin.lines().filter_map(Result::ok), out_format, files[0])
} }
Err(e) => { Err(e) => {
show_error!("{}: {}", files[0], e); show_error!("{}: {}", files[0].maybe_quote(), e);
return 1; return 1;
} }
} }
@ -314,7 +315,8 @@ where
if val.is_empty() { if val.is_empty() {
return Err(format!( return Err(format!(
"{}:{}: invalid line; missing second token", "{}:{}: invalid line; missing second token",
fp, num fp.maybe_quote(),
num
)); ));
} }
let lower = key.to_lowercase(); let lower = key.to_lowercase();
@ -341,7 +343,12 @@ where
} else if let Some(s) = table.get(lower.as_str()) { } else if let Some(s) = table.get(lower.as_str()) {
result.push_str(format!("{}={}:", s, val).as_str()); result.push_str(format!("{}={}:", s, val).as_str());
} else { } else {
return Err(format!("{}:{}: unrecognized keyword {}", fp, num, key)); return Err(format!(
"{}:{}: unrecognized keyword {}",
fp.maybe_quote(),
num,
key
));
} }
} }
} }

View file

@ -10,6 +10,7 @@ extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use std::path::Path; use std::path::Path;
use uucore::display::print_verbatim;
use uucore::error::{UResult, UUsageError}; use uucore::error::{UResult, UUsageError};
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
@ -65,7 +66,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
if d.components().next() == None { if d.components().next() == None {
print!(".") print!(".")
} else { } else {
print!("{}", d.to_string_lossy()); print_verbatim(d).unwrap();
} }
} }
None => { None => {

View file

@ -32,6 +32,7 @@ use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
use std::time::{Duration, UNIX_EPOCH}; use std::time::{Duration, UNIX_EPOCH};
use std::{error::Error, fmt::Display}; use std::{error::Error, fmt::Display};
use uucore::display::{print_verbatim, Quotable};
use uucore::error::{UError, UResult}; use uucore::error::{UError, UResult};
use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::parse_size::{parse_size, ParseSizeError};
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
@ -293,9 +294,9 @@ fn du(
Err(e) => { Err(e) => {
safe_writeln!( safe_writeln!(
stderr(), stderr(),
"{}: cannot read directory '{}': {}", "{}: cannot read directory {}: {}",
options.util_name, options.util_name,
my_stat.path.display(), my_stat.path.quote(),
e e
); );
return Box::new(iter::once(my_stat)); return Box::new(iter::once(my_stat));
@ -334,11 +335,11 @@ fn du(
} }
Err(error) => match error.kind() { Err(error) => match error.kind() {
ErrorKind::PermissionDenied => { ErrorKind::PermissionDenied => {
let description = format!("cannot access '{}'", entry.path().display()); let description = format!("cannot access {}", entry.path().quote());
let error_message = "Permission denied"; let error_message = "Permission denied";
show_error_custom_description!(description, "{}", error_message) show_error_custom_description!(description, "{}", error_message)
} }
_ => show_error!("cannot access '{}': {}", entry.path().display(), error), _ => show_error!("cannot access {}: {}", entry.path().quote(), error),
}, },
}, },
Err(error) => show_error!("{}", error), Err(error) => show_error!("{}", error),
@ -411,26 +412,30 @@ enum DuError {
impl Display for DuError { impl Display for DuError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
DuError::InvalidMaxDepthArg(s) => write!(f, "invalid maximum depth '{}'", s), DuError::InvalidMaxDepthArg(s) => write!(f, "invalid maximum depth {}", s.quote()),
DuError::SummarizeDepthConflict(s) => { DuError::SummarizeDepthConflict(s) => {
write!(f, "summarizing conflicts with --max-depth={}", s) write!(
f,
"summarizing conflicts with --max-depth={}",
s.maybe_quote()
)
} }
DuError::InvalidTimeStyleArg(s) => write!( DuError::InvalidTimeStyleArg(s) => write!(
f, f,
"invalid argument '{}' for 'time style' "invalid argument {} for 'time style'
Valid arguments are: Valid arguments are:
- 'full-iso' - 'full-iso'
- 'long-iso' - 'long-iso'
- 'iso' - 'iso'
Try '{} --help' for more information.", Try '{} --help' for more information.",
s, s.quote(),
uucore::execution_phrase() uucore::execution_phrase()
), ),
DuError::InvalidTimeArg(s) => write!( DuError::InvalidTimeArg(s) => write!(
f, f,
"Invalid argument '{}' for --time. "Invalid argument {} for --time.
'birth' and 'creation' arguments are not supported on this platform.", 'birth' and 'creation' arguments are not supported on this platform.",
s s.quote()
), ),
} }
} }
@ -566,21 +571,14 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
}; };
if !summarize || index == len - 1 { if !summarize || index == len - 1 {
let time_str = tm.format(time_format_str).to_string(); let time_str = tm.format(time_format_str).to_string();
print!( print!("{}\t{}\t", convert_size(size), time_str);
"{}\t{}\t{}{}", print_verbatim(stat.path).unwrap();
convert_size(size), print!("{}", line_separator);
time_str,
stat.path.display(),
line_separator
);
} }
} else if !summarize || index == len - 1 { } else if !summarize || index == len - 1 {
print!( print!("{}\t", convert_size(size));
"{}\t{}{}", print_verbatim(stat.path).unwrap();
convert_size(size), print!("{}", line_separator);
stat.path.display(),
line_separator
);
} }
if options.total && index == (len - 1) { if options.total && index == (len - 1) {
// The last element will be the total size of the the path under // The last element will be the total size of the the path under
@ -590,7 +588,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} }
} }
Err(_) => { Err(_) => {
show_error!("{}: {}", path_string, "No such file or directory"); show_error!(
"{}: {}",
path_string.maybe_quote(),
"No such file or directory"
);
} }
} }
} }
@ -837,8 +839,8 @@ fn format_error_message(error: ParseSizeError, s: &str, option: &str) -> String
// GNU's du echos affected flag, -B or --block-size (-t or --threshold), depending user's selection // GNU's du echos affected flag, -B or --block-size (-t or --threshold), depending user's selection
// GNU's du does distinguish between "invalid (suffix in) argument" // GNU's du does distinguish between "invalid (suffix in) argument"
match error { match error {
ParseSizeError::ParseFailure(_) => format!("invalid --{} argument '{}'", option, s), ParseSizeError::ParseFailure(_) => format!("invalid --{} argument {}", option, s.quote()),
ParseSizeError::SizeTooBig(_) => format!("--{} argument '{}' too large", option, s), ParseSizeError::SizeTooBig(_) => format!("--{} argument {} too large", option, s.quote()),
} }
} }

10
src/uu/env/src/env.rs vendored
View file

@ -65,8 +65,14 @@ fn parse_name_value_opt<'a>(opts: &mut Options<'a>, opt: &'a str) -> Result<bool
fn parse_program_opt<'a>(opts: &mut Options<'a>, opt: &'a str) -> Result<(), i32> { fn parse_program_opt<'a>(opts: &mut Options<'a>, opt: &'a str) -> Result<(), i32> {
if opts.null { if opts.null {
eprintln!("{}: cannot specify --null (-0) with command", crate_name!()); eprintln!(
eprintln!("Type \"{} --help\" for detailed information", crate_name!()); "{}: cannot specify --null (-0) with command",
uucore::util_name()
);
eprintln!(
"Type \"{} --help\" for detailed information",
uucore::execution_phrase()
);
Err(1) Err(1)
} else { } else {
opts.program.push(opt); opts.program.push(opt);

View file

@ -17,6 +17,7 @@ use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write}; use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use std::str::from_utf8; use std::str::from_utf8;
use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthChar;
use uucore::display::Quotable;
static ABOUT: &str = "Convert tabs in each FILE to spaces, writing to standard output. static ABOUT: &str = "Convert tabs in each FILE to spaces, writing to standard output.
With no FILE, or when FILE is -, read standard input."; With no FILE, or when FILE is -, read standard input.";
@ -216,7 +217,7 @@ fn open(path: String) -> BufReader<Box<dyn Read + 'static>> {
} else { } else {
file_buf = match File::open(&path[..]) { file_buf = match File::open(&path[..]) {
Ok(a) => a, Ok(a) => a,
Err(e) => crash!(1, "{}: {}\n", &path[..], e), Err(e) => crash!(1, "{}: {}\n", path.maybe_quote(), e),
}; };
BufReader::new(Box::new(file_buf) as Box<dyn Read>) BufReader::new(Box::new(file_buf) as Box<dyn Read>)
} }

View file

@ -16,6 +16,7 @@ use std::io::{self, stdin, stdout, BufRead, Write};
mod factor; mod factor;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
pub use factor::*; pub use factor::*;
use uucore::display::Quotable;
mod miller_rabin; mod miller_rabin;
pub mod numeric; pub mod numeric;
@ -52,7 +53,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
if let Some(values) = matches.values_of(options::NUMBER) { if let Some(values) = matches.values_of(options::NUMBER) {
for number in values { for number in values {
if let Err(e) = print_factors_str(number, &mut w, &mut factors_buffer) { if let Err(e) = print_factors_str(number, &mut w, &mut factors_buffer) {
show_warning!("{}: {}", number, e); show_warning!("{}: {}", number.maybe_quote(), e);
} }
} }
} else { } else {
@ -61,7 +62,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
for line in stdin.lock().lines() { for line in stdin.lock().lines() {
for number in line.unwrap().split_whitespace() { for number in line.unwrap().split_whitespace() {
if let Err(e) = print_factors_str(number, &mut w, &mut factors_buffer) { if let Err(e) = print_factors_str(number, &mut w, &mut factors_buffer) {
show_warning!("{}: {}", number, e); show_warning!("{}: {}", number.maybe_quote(), e);
} }
} }
} }

View file

@ -15,6 +15,7 @@ use std::cmp;
use std::fs::File; use std::fs::File;
use std::io::{stdin, stdout, Write}; use std::io::{stdin, stdout, Write};
use std::io::{BufReader, BufWriter, Read}; use std::io::{BufReader, BufWriter, Read};
use uucore::display::Quotable;
use self::linebreak::break_lines; use self::linebreak::break_lines;
use self::parasplit::ParagraphStream; use self::parasplit::ParagraphStream;
@ -187,7 +188,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
_ => match File::open(i) { _ => match File::open(i) {
Ok(f) => BufReader::new(Box::new(f) as Box<dyn Read + 'static>), Ok(f) => BufReader::new(Box::new(f) as Box<dyn Read + 'static>),
Err(e) => { Err(e) => {
show_warning!("{}: {}", i, e); show_warning!("{}: {}", i.maybe_quote(), e);
continue; continue;
} }
}, },

View file

@ -17,7 +17,10 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::entries::{get_groups_gnu, gid2grp, Locate, Passwd}; use uucore::{
display::Quotable,
entries::{get_groups_gnu, gid2grp, Locate, Passwd},
};
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
@ -77,7 +80,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.join(" ") .join(" ")
); );
} else { } else {
show_error!("'{}': no such user", user); show_error!("{}: no such user", user.quote());
exit_code = 1; exit_code = 1;
} }
} }

View file

@ -34,6 +34,7 @@ use std::io::{self, stdin, BufRead, BufReader, Read};
use std::iter; use std::iter;
use std::num::ParseIntError; use std::num::ParseIntError;
use std::path::Path; use std::path::Path;
use uucore::display::Quotable;
const NAME: &str = "hashsum"; const NAME: &str = "hashsum";
@ -525,7 +526,7 @@ where
if options.warn { if options.warn {
show_warning!( show_warning!(
"{}: {}: improperly formatted {} checksum line", "{}: {}: improperly formatted {} checksum line",
filename.display(), filename.maybe_quote(),
i + 1, i + 1,
options.algoname options.algoname
); );
@ -546,6 +547,10 @@ where
) )
) )
.to_ascii_lowercase(); .to_ascii_lowercase();
// FIXME: (How) should these be quoted?
// They seem like they would be processed programmatically, and
// our ordinary quoting might interfere, but newlines should be
// sanitized probably
if sum == real_sum { if sum == real_sum {
if !options.quiet { if !options.quiet {
println!("{}: OK", ck_filename); println!("{}: OK", ck_filename);

View file

@ -9,6 +9,7 @@ use clap::{crate_version, App, Arg};
use std::convert::TryFrom; use std::convert::TryFrom;
use std::ffi::OsString; use std::ffi::OsString;
use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write};
use uucore::display::Quotable;
use uucore::{crash, show_error_custom_description}; use uucore::{crash, show_error_custom_description};
const EXIT_FAILURE: i32 = 1; const EXIT_FAILURE: i32 = 1;
@ -127,10 +128,10 @@ fn arg_iterate<'a>(
match parse::parse_obsolete(s) { match parse::parse_obsolete(s) {
Some(Ok(iter)) => Ok(Box::new(vec![first].into_iter().chain(iter).chain(args))), Some(Ok(iter)) => Ok(Box::new(vec![first].into_iter().chain(iter).chain(args))),
Some(Err(e)) => match e { Some(Err(e)) => match e {
parse::ParseError::Syntax => Err(format!("bad argument format: '{}'", s)), parse::ParseError::Syntax => Err(format!("bad argument format: {}", s.quote())),
parse::ParseError::Overflow => Err(format!( parse::ParseError::Overflow => Err(format!(
"invalid argument: '{}' Value too large for defined datatype", "invalid argument: {} Value too large for defined datatype",
s s.quote()
)), )),
}, },
None => Ok(Box::new(vec![first, second].into_iter().chain(args))), None => Ok(Box::new(vec![first, second].into_iter().chain(args))),
@ -418,7 +419,7 @@ fn uu_head(options: &HeadOptions) -> Result<(), u32> {
let mut file = match std::fs::File::open(name) { let mut file = match std::fs::File::open(name) {
Ok(f) => f, Ok(f) => f,
Err(err) => { Err(err) => {
let prefix = format!("cannot open '{}' for reading", name); let prefix = format!("cannot open {} for reading", name.quote());
match err.kind() { match err.kind() {
ErrorKind::NotFound => { ErrorKind::NotFound => {
show_error_custom_description!(prefix, "No such file or directory"); show_error_custom_description!(prefix, "No such file or directory");

View file

@ -41,6 +41,7 @@ extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use std::ffi::CStr; use std::ffi::CStr;
use uucore::display::Quotable;
use uucore::entries::{self, Group, Locate, Passwd}; use uucore::entries::{self, Group, Locate, Passwd};
use uucore::error::UResult; use uucore::error::UResult;
use uucore::error::{set_exit_code, USimpleError}; use uucore::error::{set_exit_code, USimpleError};
@ -230,7 +231,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
match Passwd::locate(users[i].as_str()) { match Passwd::locate(users[i].as_str()) {
Ok(p) => Some(p), Ok(p) => Some(p),
Err(_) => { Err(_) => {
show_error!("'{}': no such user", users[i]); show_error!("{}: no such user", users[i].quote());
set_exit_code(1); set_exit_code(1);
if i + 1 >= users.len() { if i + 1 >= users.len() {
break; break;

View file

@ -16,6 +16,7 @@ use clap::{crate_version, App, Arg, ArgMatches};
use file_diff::diff; use file_diff::diff;
use filetime::{set_file_times, FileTime}; use filetime::{set_file_times, FileTime};
use uucore::backup_control::{self, BackupMode}; use uucore::backup_control::{self, BackupMode};
use uucore::display::Quotable;
use uucore::entries::{grp2gid, usr2uid}; use uucore::entries::{grp2gid, usr2uid};
use uucore::error::{FromIo, UError, UIoError, UResult}; use uucore::error::{FromIo, UError, UIoError, UResult};
use uucore::mode::get_umask; use uucore::mode::get_umask;
@ -95,40 +96,30 @@ impl Display for InstallError {
) )
} }
IE::CreateDirFailed(dir, e) => { IE::CreateDirFailed(dir, e) => {
Display::fmt(&uio_error!(e, "failed to create {}", dir.display()), f) Display::fmt(&uio_error!(e, "failed to create {}", dir.quote()), f)
} }
IE::ChmodFailed(file) => write!(f, "failed to chmod {}", file.display()), IE::ChmodFailed(file) => write!(f, "failed to chmod {}", file.quote()),
IE::InvalidTarget(target) => write!( IE::InvalidTarget(target) => write!(
f, f,
"invalid target {}: No such file or directory", "invalid target {}: No such file or directory",
target.display() target.quote()
), ),
IE::TargetDirIsntDir(target) => { IE::TargetDirIsntDir(target) => {
write!(f, "target '{}' is not a directory", target.display()) write!(f, "target {} is not a directory", target.quote())
} }
IE::BackupFailed(from, to, e) => Display::fmt( IE::BackupFailed(from, to, e) => Display::fmt(
&uio_error!( &uio_error!(e, "cannot backup {} to {}", from.quote(), to.quote()),
e,
"cannot backup '{}' to '{}'",
from.display(),
to.display()
),
f, f,
), ),
IE::InstallFailed(from, to, e) => Display::fmt( IE::InstallFailed(from, to, e) => Display::fmt(
&uio_error!( &uio_error!(e, "cannot install {} to {}", from.quote(), to.quote()),
e,
"cannot install '{}' to '{}'",
from.display(),
to.display()
),
f, f,
), ),
IE::StripProgramFailed(msg) => write!(f, "strip program failed: {}", msg), IE::StripProgramFailed(msg) => write!(f, "strip program failed: {}", msg),
IE::MetadataFailed(e) => Display::fmt(&uio_error!(e, ""), f), IE::MetadataFailed(e) => Display::fmt(&uio_error!(e, ""), f),
IE::NoSuchUser(user) => write!(f, "no such user: {}", user), IE::NoSuchUser(user) => write!(f, "no such user: {}", user.maybe_quote()),
IE::NoSuchGroup(group) => write!(f, "no such group: {}", group), IE::NoSuchGroup(group) => write!(f, "no such group: {}", group.maybe_quote()),
IE::OmittingDirectory(dir) => write!(f, "omitting directory '{}'", dir.display()), IE::OmittingDirectory(dir) => write!(f, "omitting directory {}", dir.quote()),
} }
} }
} }
@ -416,14 +407,14 @@ fn directory(paths: Vec<String>, b: Behavior) -> UResult<()> {
// the default mode. Hence it is safe to use fs::create_dir_all // the default mode. Hence it is safe to use fs::create_dir_all
// and then only modify the target's dir mode. // and then only modify the target's dir mode.
if let Err(e) = if let Err(e) =
fs::create_dir_all(path).map_err_context(|| format!("{}", path.display())) fs::create_dir_all(path).map_err_context(|| path.maybe_quote().to_string())
{ {
show!(e); show!(e);
continue; continue;
} }
if b.verbose { if b.verbose {
println!("creating directory '{}'", path.display()); println!("creating directory {}", path.quote());
} }
} }
@ -445,7 +436,7 @@ fn directory(paths: Vec<String>, b: Behavior) -> UResult<()> {
fn is_new_file_path(path: &Path) -> bool { fn is_new_file_path(path: &Path) -> bool {
!path.exists() !path.exists()
&& (path.parent().map(Path::is_dir).unwrap_or(true) && (path.parent().map(Path::is_dir).unwrap_or(true)
|| path.parent().unwrap().to_string_lossy().is_empty()) // In case of a simple file || path.parent().unwrap().as_os_str().is_empty()) // In case of a simple file
} }
/// Perform an install, given a list of paths and behavior. /// Perform an install, given a list of paths and behavior.
@ -502,7 +493,7 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
if !sourcepath.exists() { if !sourcepath.exists() {
let err = UIoError::new( let err = UIoError::new(
std::io::ErrorKind::NotFound, std::io::ErrorKind::NotFound,
format!("cannot stat '{}'", sourcepath.display()), format!("cannot stat {}", sourcepath.quote()),
); );
show!(err); show!(err);
continue; continue;
@ -566,7 +557,7 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
} }
} }
if from.to_string_lossy() == "/dev/null" { if from.as_os_str() == "/dev/null" {
/* workaround a limitation of fs::copy /* workaround a limitation of fs::copy
* https://github.com/rust-lang/rust/issues/79390 * https://github.com/rust-lang/rust/issues/79390
*/ */
@ -674,9 +665,9 @@ fn copy(from: &Path, to: &Path, b: &Behavior) -> UResult<()> {
} }
if b.verbose { if b.verbose {
print!("'{}' -> '{}'", from.display(), to.display()); print!("{} -> {}", from.quote(), to.quote());
match backup_path { match backup_path {
Some(path) => println!(" (backup: '{}')", path.display()), Some(path) => println!(" (backup: {})", path.quote()),
None => println!(), None => println!(),
} }
} }

View file

@ -22,8 +22,9 @@ pub fn parse(mode_string: &str, considering_dir: bool, umask: u32) -> Result<u32
#[cfg(any(unix, target_os = "redox"))] #[cfg(any(unix, target_os = "redox"))]
pub fn chmod(path: &Path, mode: u32) -> Result<(), ()> { pub fn chmod(path: &Path, mode: u32) -> Result<(), ()> {
use std::os::unix::fs::PermissionsExt; use std::os::unix::fs::PermissionsExt;
use uucore::display::Quotable;
fs::set_permissions(path, fs::Permissions::from_mode(mode)).map_err(|err| { fs::set_permissions(path, fs::Permissions::from_mode(mode)).map_err(|err| {
show_error!("{}: chmod failed with error {}", path.display(), err); show_error!("{}: chmod failed with error {}", path.maybe_quote(), err);
}) })
} }

View file

@ -14,6 +14,7 @@ use clap::{crate_version, App, Arg};
use std::cmp::Ordering; use std::cmp::Ordering;
use std::fs::File; use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Lines, Stdin}; use std::io::{stdin, BufRead, BufReader, Lines, Stdin};
use uucore::display::Quotable;
static NAME: &str = "join"; static NAME: &str = "join";
@ -181,18 +182,18 @@ impl Spec {
return Spec::Key; return Spec::Key;
} }
crash!(1, "invalid field specifier: '{}'", format); crash!(1, "invalid field specifier: {}", format.quote());
} }
Some('1') => FileNum::File1, Some('1') => FileNum::File1,
Some('2') => FileNum::File2, Some('2') => FileNum::File2,
_ => crash!(1, "invalid file number in field spec: '{}'", format), _ => crash!(1, "invalid file number in field spec: {}", format.quote()),
}; };
if let Some('.') = chars.next() { if let Some('.') = chars.next() {
return Spec::Field(file_num, parse_field_number(chars.as_str())); return Spec::Field(file_num, parse_field_number(chars.as_str()));
} }
crash!(1, "invalid field specifier: '{}'", format); crash!(1, "invalid field specifier: {}", format.quote());
} }
} }
@ -245,7 +246,7 @@ impl<'a> State<'a> {
} else { } else {
match File::open(name) { match File::open(name) {
Ok(file) => Box::new(BufReader::new(file)) as Box<dyn BufRead>, Ok(file) => Box::new(BufReader::new(file)) as Box<dyn BufRead>,
Err(err) => crash!(1, "{}: {}", name, err), Err(err) => crash!(1, "{}: {}", name.maybe_quote(), err),
} }
}; };
@ -393,7 +394,11 @@ impl<'a> State<'a> {
let diff = input.compare(self.get_current_key(), line.get_field(self.key)); let diff = input.compare(self.get_current_key(), line.get_field(self.key));
if diff == Ordering::Greater { if diff == Ordering::Greater {
eprintln!("{}:{}: is not sorted", self.file_name, self.line_num); eprintln!(
"{}:{}: is not sorted",
self.file_name.maybe_quote(),
self.line_num
);
// This is fatal if the check is enabled. // This is fatal if the check is enabled.
if input.check_order == CheckOrder::Enabled { if input.check_order == CheckOrder::Enabled {
@ -727,7 +732,7 @@ fn get_field_number(keys: Option<usize>, key: Option<usize>) -> usize {
fn parse_field_number(value: &str) -> usize { fn parse_field_number(value: &str) -> usize {
match value.parse::<usize>() { match value.parse::<usize>() {
Ok(result) if result > 0 => result - 1, Ok(result) if result > 0 => result - 1,
_ => crash!(1, "invalid field number: '{}'", value), _ => crash!(1, "invalid field number: {}", value.quote()),
} }
} }
@ -735,7 +740,7 @@ fn parse_file_number(value: &str) -> FileNum {
match value { match value {
"1" => FileNum::File1, "1" => FileNum::File1,
"2" => FileNum::File2, "2" => FileNum::File2,
value => crash!(1, "invalid file number: '{}'", value), value => crash!(1, "invalid file number: {}", value.quote()),
} }
} }

View file

@ -13,6 +13,7 @@ extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use libc::{c_int, pid_t}; use libc::{c_int, pid_t};
use std::io::Error; use std::io::Error;
use uucore::display::Quotable;
use uucore::error::{UResult, USimpleError}; use uucore::error::{UResult, USimpleError};
use uucore::signals::ALL_SIGNALS; use uucore::signals::ALL_SIGNALS;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
@ -154,7 +155,7 @@ fn print_signal(signal_name_or_value: &str) -> UResult<()> {
} }
Err(USimpleError::new( Err(USimpleError::new(
1, 1,
format!("unknown signal name {}", signal_name_or_value), format!("unknown signal name {}", signal_name_or_value.quote()),
)) ))
} }
@ -190,7 +191,7 @@ fn kill(signalname: &str, pids: &[String]) -> UResult<()> {
None => { None => {
return Err(USimpleError::new( return Err(USimpleError::new(
1, 1,
format!("unknown signal name {}", signalname), format!("unknown signal name {}", signalname.quote()),
)); ));
} }
}; };
@ -204,7 +205,7 @@ fn kill(signalname: &str, pids: &[String]) -> UResult<()> {
Err(e) => { Err(e) => {
return Err(USimpleError::new( return Err(USimpleError::new(
1, 1,
format!("failed to parse argument {}: {}", pid, e), format!("failed to parse argument {}: {}", pid.quote(), e),
)); ));
} }
}; };

View file

@ -11,11 +11,12 @@
extern crate uucore; extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use uucore::display::Quotable;
use uucore::error::{UError, UResult}; use uucore::error::{UError, UResult};
use std::borrow::Cow; use std::borrow::Cow;
use std::error::Error; use std::error::Error;
use std::ffi::OsStr; use std::ffi::{OsStr, OsString};
use std::fmt::Display; use std::fmt::Display;
use std::fs; use std::fs;
@ -49,26 +50,26 @@ pub enum OverwriteMode {
#[derive(Debug)] #[derive(Debug)]
enum LnError { enum LnError {
TargetIsDirectory(String), TargetIsDirectory(PathBuf),
SomeLinksFailed, SomeLinksFailed,
FailedToLink(String), FailedToLink(String),
MissingDestination(String), MissingDestination(PathBuf),
ExtraOperand(String), ExtraOperand(OsString),
} }
impl Display for LnError { impl Display for LnError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
Self::TargetIsDirectory(s) => write!(f, "target '{}' is not a directory", s), Self::TargetIsDirectory(s) => write!(f, "target {} is not a directory", s.quote()),
Self::FailedToLink(s) => write!(f, "failed to link '{}'", s), Self::FailedToLink(e) => write!(f, "failed to link: {}", e),
Self::SomeLinksFailed => write!(f, "some links failed to create"), Self::SomeLinksFailed => write!(f, "some links failed to create"),
Self::MissingDestination(s) => { Self::MissingDestination(s) => {
write!(f, "missing destination file operand after '{}'", s) write!(f, "missing destination file operand after {}", s.quote())
} }
Self::ExtraOperand(s) => write!( Self::ExtraOperand(s) => write!(
f, f,
"extra operand '{}'\nTry '{} --help' for more information.", "extra operand {}\nTry '{} --help' for more information.",
s, s.quote(),
uucore::execution_phrase() uucore::execution_phrase()
), ),
} }
@ -279,10 +280,10 @@ fn exec(files: &[PathBuf], settings: &Settings) -> UResult<()> {
// 1st form. Now there should be only two operands, but if -T is // 1st form. Now there should be only two operands, but if -T is
// specified we may have a wrong number of operands. // specified we may have a wrong number of operands.
if files.len() == 1 { if files.len() == 1 {
return Err(LnError::MissingDestination(files[0].to_string_lossy().into()).into()); return Err(LnError::MissingDestination(files[0].clone()).into());
} }
if files.len() > 2 { if files.len() > 2 {
return Err(LnError::ExtraOperand(files[2].display().to_string()).into()); return Err(LnError::ExtraOperand(files[2].clone().into()).into());
} }
assert!(!files.is_empty()); assert!(!files.is_empty());
@ -294,7 +295,7 @@ fn exec(files: &[PathBuf], settings: &Settings) -> UResult<()> {
fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings) -> UResult<()> { fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings) -> UResult<()> {
if !target_dir.is_dir() { if !target_dir.is_dir() {
return Err(LnError::TargetIsDirectory(target_dir.display().to_string()).into()); return Err(LnError::TargetIsDirectory(target_dir.to_owned()).into());
} }
let mut all_successful = true; let mut all_successful = true;
@ -306,7 +307,7 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings)
if is_symlink(target_dir) { if is_symlink(target_dir) {
if target_dir.is_file() { if target_dir.is_file() {
if let Err(e) = fs::remove_file(target_dir) { if let Err(e) = fs::remove_file(target_dir) {
show_error!("Could not update {}: {}", target_dir.display(), e) show_error!("Could not update {}: {}", target_dir.quote(), e)
}; };
} }
if target_dir.is_dir() { if target_dir.is_dir() {
@ -314,7 +315,7 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings)
// considered as a dir // considered as a dir
// See test_ln::test_symlink_no_deref_dir // See test_ln::test_symlink_no_deref_dir
if let Err(e) = fs::remove_dir(target_dir) { if let Err(e) = fs::remove_dir(target_dir) {
show_error!("Could not update {}: {}", target_dir.display(), e) show_error!("Could not update {}: {}", target_dir.quote(), e)
}; };
} }
} }
@ -332,10 +333,7 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings)
} }
} }
None => { None => {
show_error!( show_error!("cannot stat {}: No such file or directory", srcpath.quote());
"cannot stat '{}': No such file or directory",
srcpath.display()
);
all_successful = false; all_successful = false;
continue; continue;
} }
@ -344,9 +342,9 @@ fn link_files_in_dir(files: &[PathBuf], target_dir: &Path, settings: &Settings)
if let Err(e) = link(srcpath, &targetpath, settings) { if let Err(e) = link(srcpath, &targetpath, settings) {
show_error!( show_error!(
"cannot link '{}' to '{}': {}", "cannot link {} to {}: {}",
targetpath.display(), targetpath.quote(),
srcpath.display(), srcpath.quote(),
e e
); );
all_successful = false; all_successful = false;
@ -399,7 +397,7 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> Result<()> {
match settings.overwrite { match settings.overwrite {
OverwriteMode::NoClobber => {} OverwriteMode::NoClobber => {}
OverwriteMode::Interactive => { OverwriteMode::Interactive => {
print!("{}: overwrite '{}'? ", uucore::util_name(), dst.display()); print!("{}: overwrite {}? ", uucore::util_name(), dst.quote());
if !read_yes() { if !read_yes() {
return Ok(()); return Ok(());
} }
@ -426,9 +424,9 @@ fn link(src: &Path, dst: &Path, settings: &Settings) -> Result<()> {
} }
if settings.verbose { if settings.verbose {
print!("'{}' -> '{}'", dst.display(), &source.display()); print!("{} -> {}", dst.quote(), source.quote());
match backup_path { match backup_path {
Some(path) => println!(" (backup: '{}')", path.display()), Some(path) => println!(" (backup: {})", path.quote()),
None => println!(), None => println!(),
} }
} }

View file

@ -40,7 +40,10 @@ use std::{
time::Duration, time::Duration,
}; };
use term_grid::{Cell, Direction, Filling, Grid, GridOptions}; use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
use uucore::error::{set_exit_code, FromIo, UError, UResult}; use uucore::{
display::Quotable,
error::{set_exit_code, FromIo, UError, UResult},
};
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
#[cfg(unix)] #[cfg(unix)]
@ -150,8 +153,8 @@ impl Error for LsError {}
impl Display for LsError { impl Display for LsError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self { match self {
LsError::InvalidLineWidth(s) => write!(f, "invalid line width: '{}'", s), LsError::InvalidLineWidth(s) => write!(f, "invalid line width: {}", s.quote()),
LsError::NoMetadata(p) => write!(f, "could not open file: '{}'", p.display()), LsError::NoMetadata(p) => write!(f, "could not open file: {}", p.quote()),
} }
} }
} }
@ -410,18 +413,18 @@ impl Config {
}, },
None => match termsize::get() { None => match termsize::get() {
Some(size) => size.cols, Some(size) => size.cols,
None => match std::env::var("COLUMNS") { None => match std::env::var_os("COLUMNS") {
Ok(columns) => match columns.parse() { Some(columns) => match columns.to_str().and_then(|s| s.parse().ok()) {
Ok(columns) => columns, Some(columns) => columns,
Err(_) => { None => {
show_error!( show_error!(
"ignoring invalid width in environment variable COLUMNS: '{}'", "ignoring invalid width in environment variable COLUMNS: {}",
columns columns.quote()
); );
DEFAULT_TERM_WIDTH DEFAULT_TERM_WIDTH
} }
}, },
Err(_) => DEFAULT_TERM_WIDTH, None => DEFAULT_TERM_WIDTH,
}, },
}, },
}; };
@ -538,7 +541,7 @@ impl Config {
Ok(p) => { Ok(p) => {
ignore_patterns.add(p); ignore_patterns.add(p);
} }
Err(_) => show_warning!("Invalid pattern for ignore: '{}'", pattern), Err(_) => show_warning!("Invalid pattern for ignore: {}", pattern.quote()),
} }
} }
@ -548,7 +551,7 @@ impl Config {
Ok(p) => { Ok(p) => {
ignore_patterns.add(p); ignore_patterns.add(p);
} }
Err(_) => show_warning!("Invalid pattern for hide: '{}'", pattern), Err(_) => show_warning!("Invalid pattern for hide: {}", pattern.quote()),
} }
} }
} }
@ -1255,7 +1258,7 @@ fn list(locs: Vec<&Path>, config: Config) -> UResult<()> {
if path_data.md().is_none() { if path_data.md().is_none() {
show!(std::io::ErrorKind::NotFound show!(std::io::ErrorKind::NotFound
.map_err_context(|| format!("cannot access '{}'", path_data.p_buf.display()))); .map_err_context(|| format!("cannot access {}", path_data.p_buf.quote())));
// We found an error, no need to continue the execution // We found an error, no need to continue the execution
continue; continue;
} }

View file

@ -12,6 +12,7 @@ use clap::OsValues;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError}; use uucore::error::{FromIo, UResult, USimpleError};
static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist"; static ABOUT: &str = "Create the given DIRECTORY(ies) if they do not exist";
@ -43,7 +44,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// Not tested on Windows // Not tested on Windows
let mode: u16 = match matches.value_of(options::MODE) { let mode: u16 = match matches.value_of(options::MODE) {
Some(m) => u16::from_str_radix(m, 8) Some(m) => u16::from_str_radix(m, 8)
.map_err(|_| USimpleError::new(1, format!("invalid mode '{}'", m)))?, .map_err(|_| USimpleError::new(1, format!("invalid mode {}", m.quote())))?,
None => 0o755_u16, None => 0o755_u16,
}; };
@ -100,13 +101,13 @@ fn mkdir(path: &Path, recursive: bool, mode: u16, verbose: bool) -> UResult<()>
fs::create_dir fs::create_dir
}; };
create_dir(path).map_err_context(|| format!("cannot create directory '{}'", path.display()))?; create_dir(path).map_err_context(|| format!("cannot create directory {}", path.quote()))?;
if verbose { if verbose {
println!( println!(
"{}: created directory '{}'", "{}: created directory {}",
uucore::util_name(), uucore::util_name(),
path.display() path.quote()
); );
} }
@ -121,7 +122,7 @@ fn chmod(path: &Path, mode: u16) -> UResult<()> {
let mode = Permissions::from_mode(u32::from(mode)); let mode = Permissions::from_mode(u32::from(mode));
set_permissions(path, mode) set_permissions(path, mode)
.map_err_context(|| format!("cannot set permissions '{}'", path.display())) .map_err_context(|| format!("cannot set permissions {}", path.quote()))
} }
#[cfg(windows)] #[cfg(windows)]

View file

@ -11,7 +11,7 @@ extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use libc::mkfifo; use libc::mkfifo;
use std::ffi::CString; use std::ffi::CString;
use uucore::InvalidEncodingHandling; use uucore::{display::Quotable, InvalidEncodingHandling};
static NAME: &str = "mkfifo"; static NAME: &str = "mkfifo";
static USAGE: &str = "mkfifo [OPTION]... NAME..."; static USAGE: &str = "mkfifo [OPTION]... NAME...";
@ -61,7 +61,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
mkfifo(name.as_ptr(), mode as libc::mode_t) mkfifo(name.as_ptr(), mode as libc::mode_t)
}; };
if err == -1 { if err == -1 {
show_error!("cannot create fifo '{}': File exists", f); show_error!("cannot create fifo {}: File exists", f.quote());
exit_code = 1; exit_code = 1;
} }
} }

View file

@ -16,6 +16,7 @@ use clap::{crate_version, App, Arg, ArgMatches};
use libc::{dev_t, mode_t}; use libc::{dev_t, mode_t};
use libc::{S_IFBLK, S_IFCHR, S_IFIFO, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR}; use libc::{S_IFBLK, S_IFCHR, S_IFIFO, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR};
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
static ABOUT: &str = "Create the special file NAME of the given TYPE."; static ABOUT: &str = "Create the special file NAME of the given TYPE.";
@ -219,7 +220,7 @@ fn valid_type(tpe: String) -> Result<(), String> {
if vec!['b', 'c', 'u', 'p'].contains(&first_char) { if vec!['b', 'c', 'u', 'p'].contains(&first_char) {
Ok(()) Ok(())
} else { } else {
Err(format!("invalid device type '{}'", tpe)) Err(format!("invalid device type {}", tpe.quote()))
} }
}) })
} }

View file

@ -12,6 +12,7 @@
extern crate uucore; extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use uucore::display::{println_verbatim, Quotable};
use uucore::error::{FromIo, UError, UResult}; use uucore::error::{FromIo, UError, UResult};
use std::env; use std::env;
@ -57,16 +58,20 @@ impl Display for MkTempError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use MkTempError::*; use MkTempError::*;
match self { match self {
PersistError(p) => write!(f, "could not persist file '{}'", p.display()), PersistError(p) => write!(f, "could not persist file {}", p.quote()),
MustEndInX(s) => write!(f, "with --suffix, template '{}' must end in X", s), MustEndInX(s) => write!(f, "with --suffix, template {} must end in X", s.quote()),
TooFewXs(s) => write!(f, "too few X's in template '{}'", s), TooFewXs(s) => write!(f, "too few X's in template {}", s.quote()),
ContainsDirSeparator(s) => { ContainsDirSeparator(s) => {
write!(f, "invalid suffix '{}', contains directory separator", s) write!(
f,
"invalid suffix {}, contains directory separator",
s.quote()
)
} }
InvalidTemplate(s) => write!( InvalidTemplate(s) => write!(
f, f,
"invalid template, '{}'; with --tmpdir, it may not be absolute", "invalid template, {}; with --tmpdir, it may not be absolute",
s s.quote()
), ),
} }
} }
@ -244,8 +249,7 @@ pub fn dry_exec(mut tmpdir: PathBuf, prefix: &str, rand: usize, suffix: &str) ->
} }
} }
tmpdir.push(buf); tmpdir.push(buf);
println!("{}", tmpdir.display()); println_verbatim(tmpdir).map_err_context(|| "failed to print directory name".to_owned())
Ok(())
} }
fn exec(dir: PathBuf, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<()> { fn exec(dir: PathBuf, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<()> {
@ -274,6 +278,5 @@ fn exec(dir: PathBuf, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -
.map_err(|e| MkTempError::PersistError(e.file.path().to_path_buf()))? .map_err(|e| MkTempError::PersistError(e.file.path().to_path_buf()))?
.1 .1
}; };
println!("{}", path.display()); println_verbatim(path).map_err_context(|| "failed to print directory name".to_owned())
Ok(())
} }

View file

@ -30,6 +30,7 @@ use crossterm::{
use unicode_segmentation::UnicodeSegmentation; use unicode_segmentation::UnicodeSegmentation;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use uucore::display::Quotable;
const BELL: &str = "\x07"; const BELL: &str = "\x07";
@ -64,12 +65,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let file = Path::new(file); let file = Path::new(file);
if file.is_dir() { if file.is_dir() {
terminal::disable_raw_mode().unwrap(); terminal::disable_raw_mode().unwrap();
show_usage_error!("'{}' is a directory.", file.display()); show_usage_error!("{} is a directory.", file.quote());
return 1; return 1;
} }
if !file.exists() { if !file.exists() {
terminal::disable_raw_mode().unwrap(); terminal::disable_raw_mode().unwrap();
show_error!("cannot open {}: No such file or directory", file.display()); show_error!("cannot open {}: No such file or directory", file.quote());
return 1; return 1;
} }
if length > 1 { if length > 1 {

View file

@ -21,6 +21,7 @@ use std::os::unix;
use std::os::windows; use std::os::windows;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use uucore::backup_control::{self, BackupMode}; use uucore::backup_control::{self, BackupMode};
use uucore::display::Quotable;
use fs_extra::dir::{move_dir, CopyOptions as DirCopyOptions}; use fs_extra::dir::{move_dir, CopyOptions as DirCopyOptions};
@ -223,10 +224,7 @@ fn exec(files: &[PathBuf], b: Behavior) -> i32 {
// `Ok()` results unless the source does not exist, or the user // `Ok()` results unless the source does not exist, or the user
// lacks permission to access metadata. // lacks permission to access metadata.
if source.symlink_metadata().is_err() { if source.symlink_metadata().is_err() {
show_error!( show_error!("cannot stat {}: No such file or directory", source.quote());
"cannot stat '{}': No such file or directory",
source.display()
);
return 1; return 1;
} }
@ -234,8 +232,8 @@ fn exec(files: &[PathBuf], b: Behavior) -> i32 {
if b.no_target_dir { if b.no_target_dir {
if !source.is_dir() { if !source.is_dir() {
show_error!( show_error!(
"cannot overwrite directory '{}' with non-directory", "cannot overwrite directory {} with non-directory",
target.display() target.quote()
); );
return 1; return 1;
} }
@ -243,9 +241,9 @@ fn exec(files: &[PathBuf], b: Behavior) -> i32 {
return match rename(source, target, &b) { return match rename(source, target, &b) {
Err(e) => { Err(e) => {
show_error!( show_error!(
"cannot move '{}' to '{}': {}", "cannot move {} to {}: {}",
source.display(), source.quote(),
target.display(), target.quote(),
e.to_string() e.to_string()
); );
1 1
@ -257,9 +255,9 @@ fn exec(files: &[PathBuf], b: Behavior) -> i32 {
return move_files_into_dir(&[source.clone()], target, &b); return move_files_into_dir(&[source.clone()], target, &b);
} else if target.exists() && source.is_dir() { } else if target.exists() && source.is_dir() {
show_error!( show_error!(
"cannot overwrite non-directory '{}' with directory '{}'", "cannot overwrite non-directory {} with directory {}",
target.display(), target.quote(),
source.display() source.quote()
); );
return 1; return 1;
} }
@ -272,9 +270,9 @@ fn exec(files: &[PathBuf], b: Behavior) -> i32 {
_ => { _ => {
if b.no_target_dir { if b.no_target_dir {
show_error!( show_error!(
"mv: extra operand '{}'\n\ "mv: extra operand {}\n\
Try '{} --help' for more information.", Try '{} --help' for more information.",
files[2].display(), files[2].quote(),
uucore::execution_phrase() uucore::execution_phrase()
); );
return 1; return 1;
@ -288,7 +286,7 @@ fn exec(files: &[PathBuf], b: Behavior) -> i32 {
fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> i32 { fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> i32 {
if !target_dir.is_dir() { if !target_dir.is_dir() {
show_error!("target '{}' is not a directory", target_dir.display()); show_error!("target {} is not a directory", target_dir.quote());
return 1; return 1;
} }
@ -298,8 +296,8 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> i3
Some(name) => target_dir.join(name), Some(name) => target_dir.join(name),
None => { None => {
show_error!( show_error!(
"cannot stat '{}': No such file or directory", "cannot stat {}: No such file or directory",
sourcepath.display() sourcepath.quote()
); );
all_successful = false; all_successful = false;
@ -309,9 +307,9 @@ fn move_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> i3
if let Err(e) = rename(sourcepath, &targetpath, b) { if let Err(e) = rename(sourcepath, &targetpath, b) {
show_error!( show_error!(
"cannot move '{}' to '{}': {}", "cannot move {} to {}: {}",
sourcepath.display(), sourcepath.quote(),
targetpath.display(), targetpath.quote(),
e.to_string() e.to_string()
); );
all_successful = false; all_successful = false;
@ -332,7 +330,7 @@ fn rename(from: &Path, to: &Path, b: &Behavior) -> io::Result<()> {
match b.overwrite { match b.overwrite {
OverwriteMode::NoClobber => return Ok(()), OverwriteMode::NoClobber => return Ok(()),
OverwriteMode::Interactive => { OverwriteMode::Interactive => {
println!("{}: overwrite '{}'? ", uucore::util_name(), to.display()); println!("{}: overwrite {}? ", uucore::util_name(), to.quote());
if !read_yes() { if !read_yes() {
return Ok(()); return Ok(());
} }
@ -365,9 +363,9 @@ fn rename(from: &Path, to: &Path, b: &Behavior) -> io::Result<()> {
rename_with_fallback(from, to)?; rename_with_fallback(from, to)?;
if b.verbose { if b.verbose {
print!("'{}' -> '{}'", from.display(), to.display()); print!("{} -> {}", from.quote(), to.quote());
match backup_path { match backup_path {
Some(path) => println!(" (backup: '{}')", path.display()), Some(path) => println!(" (backup: {})", path.quote()),
None => println!(), None => println!(),
} }
} }

View file

@ -19,6 +19,7 @@ use std::fs::{File, OpenOptions};
use std::io::Error; use std::io::Error;
use std::os::unix::prelude::*; use std::os::unix::prelude::*;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
static ABOUT: &str = "Run COMMAND ignoring hangup signals."; static ABOUT: &str = "Run COMMAND ignoring hangup signals.";
@ -122,13 +123,16 @@ fn find_stdout() -> File {
.open(Path::new(NOHUP_OUT)) .open(Path::new(NOHUP_OUT))
{ {
Ok(t) => { Ok(t) => {
show_error!("ignoring input and appending output to '{}'", NOHUP_OUT); show_error!(
"ignoring input and appending output to {}",
NOHUP_OUT.quote()
);
t t
} }
Err(e1) => { Err(e1) => {
let home = match env::var("HOME") { let home = match env::var("HOME") {
Err(_) => { Err(_) => {
show_error!("failed to open '{}': {}", NOHUP_OUT, e1); show_error!("failed to open {}: {}", NOHUP_OUT.quote(), e1);
exit!(internal_failure_code) exit!(internal_failure_code)
} }
Ok(h) => h, Ok(h) => h,
@ -143,12 +147,15 @@ fn find_stdout() -> File {
.open(&homeout) .open(&homeout)
{ {
Ok(t) => { Ok(t) => {
show_error!("ignoring input and appending output to '{}'", homeout_str); show_error!(
"ignoring input and appending output to {}",
homeout_str.quote()
);
t t
} }
Err(e2) => { Err(e2) => {
show_error!("failed to open '{}': {}", NOHUP_OUT, e1); show_error!("failed to open {}: {}", NOHUP_OUT.quote(), e1);
show_error!("failed to open '{}': {}", homeout_str, e2); show_error!("failed to open {}: {}", homeout_str.quote(), e2);
exit!(internal_failure_code) exit!(internal_failure_code)
} }
} }

View file

@ -1,3 +1,5 @@
use uucore::display::Quotable;
use crate::options::{NumfmtOptions, RoundMethod}; use crate::options::{NumfmtOptions, RoundMethod};
use crate::units::{DisplayableSuffix, RawSuffix, Result, Suffix, Unit, IEC_BASES, SI_BASES}; use crate::units::{DisplayableSuffix, RawSuffix, Result, Suffix, Unit, IEC_BASES, SI_BASES};
@ -78,7 +80,7 @@ fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
Some('Z') => Some((RawSuffix::Z, with_i)), Some('Z') => Some((RawSuffix::Z, with_i)),
Some('Y') => Some((RawSuffix::Y, with_i)), Some('Y') => Some((RawSuffix::Y, with_i)),
Some('0'..='9') => None, Some('0'..='9') => None,
_ => return Err(format!("invalid suffix in input: '{}'", s)), _ => return Err(format!("invalid suffix in input: {}", s.quote())),
}; };
let suffix_len = match suffix { let suffix_len = match suffix {
@ -89,7 +91,7 @@ fn parse_suffix(s: &str) -> Result<(f64, Option<Suffix>)> {
let number = s[..s.len() - suffix_len] let number = s[..s.len() - suffix_len]
.parse::<f64>() .parse::<f64>()
.map_err(|_| format!("invalid number: '{}'", s))?; .map_err(|_| format!("invalid number: {}", s.quote()))?;
Ok((number, suffix)) Ok((number, suffix))
} }

View file

@ -15,6 +15,7 @@ use crate::options::*;
use crate::units::{Result, Unit}; use crate::units::{Result, Unit};
use clap::{crate_version, App, AppSettings, Arg, ArgMatches}; use clap::{crate_version, App, AppSettings, Arg, ArgMatches};
use std::io::{BufRead, Write}; use std::io::{BufRead, Write};
use uucore::display::Quotable;
use uucore::ranges::Range; use uucore::ranges::Range;
pub mod format; pub mod format;
@ -113,7 +114,7 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
0 => Err(value), 0 => Err(value),
_ => Ok(n), _ => Ok(n),
}) })
.map_err(|value| format!("invalid header value '{}'", value)) .map_err(|value| format!("invalid header value {}", value.quote()))
} }
}?; }?;

View file

@ -5,6 +5,8 @@ use std::io;
use std::io::BufReader; use std::io::BufReader;
use std::vec::Vec; use std::vec::Vec;
use uucore::display::Quotable;
pub enum InputSource<'a> { pub enum InputSource<'a> {
FileName(&'a str), FileName(&'a str),
Stdin, Stdin,
@ -57,7 +59,7 @@ impl<'b> MultifileReader<'b> {
// print an error at the time that the file is needed, // print an error at the time that the file is needed,
// then move on the the next file. // then move on the the next file.
// This matches the behavior of the original `od` // This matches the behavior of the original `od`
eprintln!("{}: '{}': {}", uucore::util_name(), fname, e); eprintln!("{}: {}: {}", uucore::util_name(), fname.maybe_quote(), e);
self.any_err = true self.any_err = true
} }
} }

View file

@ -43,6 +43,7 @@ use crate::partialreader::*;
use crate::peekreader::*; use crate::peekreader::*;
use crate::prn_char::format_ascii_dump; use crate::prn_char::format_ascii_dump;
use clap::{self, crate_version, AppSettings, Arg, ArgMatches}; use clap::{self, crate_version, AppSettings, Arg, ArgMatches};
use uucore::display::Quotable;
use uucore::parse_size::ParseSizeError; use uucore::parse_size::ParseSizeError;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
@ -635,7 +636,7 @@ fn format_error_message(error: ParseSizeError, s: &str, option: &str) -> String
// GNU's od echos affected flag, -N or --read-bytes (-j or --skip-bytes, etc.), depending user's selection // GNU's od echos affected flag, -N or --read-bytes (-j or --skip-bytes, etc.), depending user's selection
// GNU's od does distinguish between "invalid (suffix in) argument" // GNU's od does distinguish between "invalid (suffix in) argument"
match error { match error {
ParseSizeError::ParseFailure(_) => format!("invalid --{} argument '{}'", option, s), ParseSizeError::ParseFailure(_) => format!("invalid --{} argument {}", option, s.quote()),
ParseSizeError::SizeTooBig(_) => format!("--{} argument '{}' too large", option, s), ParseSizeError::SizeTooBig(_) => format!("--{} argument {} too large", option, s.quote()),
} }
} }

View file

@ -1,5 +1,7 @@
// spell-checker:ignore formatteriteminfo docopt fvox fvoxw vals acdx // spell-checker:ignore formatteriteminfo docopt fvox fvoxw vals acdx
use uucore::display::Quotable;
use crate::formatteriteminfo::FormatterItemInfo; use crate::formatteriteminfo::FormatterItemInfo;
use crate::prn_char::*; use crate::prn_char::*;
use crate::prn_float::*; use crate::prn_float::*;
@ -272,8 +274,9 @@ fn parse_type_string(params: &str) -> Result<Vec<ParsedFormatterItemInfo>, Strin
while let Some(type_char) = ch { while let Some(type_char) = ch {
let type_char = format_type(type_char).ok_or_else(|| { let type_char = format_type(type_char).ok_or_else(|| {
format!( format!(
"unexpected char '{}' in format specification '{}'", "unexpected char '{}' in format specification {}",
type_char, params type_char,
params.quote()
) )
})?; })?;
@ -293,8 +296,9 @@ fn parse_type_string(params: &str) -> Result<Vec<ParsedFormatterItemInfo>, Strin
if !decimal_size.is_empty() { if !decimal_size.is_empty() {
byte_size = decimal_size.parse().map_err(|_| { byte_size = decimal_size.parse().map_err(|_| {
format!( format!(
"invalid number '{}' in format specification '{}'", "invalid number {} in format specification {}",
decimal_size, params decimal_size.quote(),
params.quote()
) )
})?; })?;
} }
@ -305,8 +309,9 @@ fn parse_type_string(params: &str) -> Result<Vec<ParsedFormatterItemInfo>, Strin
let ft = od_format_type(type_char, byte_size).ok_or_else(|| { let ft = od_format_type(type_char, byte_size).ok_or_else(|| {
format!( format!(
"invalid size '{}' in format specification '{}'", "invalid size '{}' in format specification {}",
byte_size, params byte_size,
params.quote()
) )
})?; })?;
formats.push(ParsedFormatterItemInfo::new(ft, show_ascii_dump)); formats.push(ParsedFormatterItemInfo::new(ft, show_ascii_dump));

View file

@ -15,6 +15,7 @@ extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use std::fs; use std::fs;
use std::io::{ErrorKind, Write}; use std::io::{ErrorKind, Write};
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
// operating mode // operating mode
@ -153,10 +154,10 @@ fn check_basic(path: &[String]) -> bool {
if component_len > POSIX_NAME_MAX { if component_len > POSIX_NAME_MAX {
writeln!( writeln!(
&mut std::io::stderr(), &mut std::io::stderr(),
"limit {} exceeded by length {} of file name component '{}'", "limit {} exceeded by length {} of file name component {}",
POSIX_NAME_MAX, POSIX_NAME_MAX,
component_len, component_len,
p p.quote()
); );
return false; return false;
} }
@ -175,8 +176,8 @@ fn check_extra(path: &[String]) -> bool {
if p.starts_with('-') { if p.starts_with('-') {
writeln!( writeln!(
&mut std::io::stderr(), &mut std::io::stderr(),
"leading hyphen in file name component '{}'", "leading hyphen in file name component {}",
p p.quote()
); );
return false; return false;
} }
@ -197,10 +198,10 @@ fn check_default(path: &[String]) -> bool {
if total_len > libc::PATH_MAX as usize { if total_len > libc::PATH_MAX as usize {
writeln!( writeln!(
&mut std::io::stderr(), &mut std::io::stderr(),
"limit {} exceeded by length {} of file name '{}'", "limit {} exceeded by length {} of file name {}",
libc::PATH_MAX, libc::PATH_MAX,
total_len, total_len,
joined_path joined_path.quote()
); );
return false; return false;
} }
@ -210,10 +211,10 @@ fn check_default(path: &[String]) -> bool {
if component_len > libc::FILENAME_MAX as usize { if component_len > libc::FILENAME_MAX as usize {
writeln!( writeln!(
&mut std::io::stderr(), &mut std::io::stderr(),
"limit {} exceeded by length {} of file name component '{}'", "limit {} exceeded by length {} of file name component {}",
libc::FILENAME_MAX, libc::FILENAME_MAX,
component_len, component_len,
p p.quote()
); );
return false; return false;
} }
@ -246,9 +247,9 @@ fn check_portable_chars(path_segment: &str) -> bool {
let invalid = path_segment[i..].chars().next().unwrap(); 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 {}",
invalid, invalid,
path_segment path_segment.quote()
); );
return false; return false;
} }

View file

@ -24,6 +24,8 @@ use std::io::{stdin, stdout, BufRead, BufReader, Lines, Read, Stdout, Write};
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::fs::FileTypeExt; use std::os::unix::fs::FileTypeExt;
use uucore::display::Quotable;
type IOError = std::io::Error; type IOError = std::io::Error;
const NAME: &str = "pr"; const NAME: &str = "pr";
@ -517,7 +519,7 @@ fn parse_usize(matches: &Matches, opt: &str) -> Option<Result<usize, PrError>> {
let i = value_to_parse.0; let i = value_to_parse.0;
let option = value_to_parse.1; let option = value_to_parse.1;
i.parse().map_err(|_e| { i.parse().map_err(|_e| {
PrError::EncounteredErrors(format!("invalid {} argument '{}'", option, i)) PrError::EncounteredErrors(format!("invalid {} argument {}", option, i.quote()))
}) })
}; };
matches matches
@ -619,7 +621,7 @@ fn build_options(
let unparsed_num = i.get(1).unwrap().as_str().trim(); let unparsed_num = i.get(1).unwrap().as_str().trim();
let x: Vec<_> = unparsed_num.split(':').collect(); let x: Vec<_> = unparsed_num.split(':').collect();
x[0].to_string().parse::<usize>().map_err(|_e| { x[0].to_string().parse::<usize>().map_err(|_e| {
PrError::EncounteredErrors(format!("invalid {} argument '{}'", "+", unparsed_num)) PrError::EncounteredErrors(format!("invalid {} argument {}", "+", unparsed_num.quote()))
}) })
}) { }) {
Some(res) => res?, Some(res) => res?,
@ -633,7 +635,11 @@ fn build_options(
.map(|unparsed_num| { .map(|unparsed_num| {
let x: Vec<_> = unparsed_num.split(':').collect(); let x: Vec<_> = unparsed_num.split(':').collect();
x[1].to_string().parse::<usize>().map_err(|_e| { x[1].to_string().parse::<usize>().map_err(|_e| {
PrError::EncounteredErrors(format!("invalid {} argument '{}'", "+", unparsed_num)) PrError::EncounteredErrors(format!(
"invalid {} argument {}",
"+",
unparsed_num.quote()
))
}) })
}) { }) {
Some(res) => Some(res?), Some(res) => Some(res?),
@ -643,7 +649,10 @@ fn build_options(
let invalid_pages_map = |i: String| { let invalid_pages_map = |i: String| {
let unparsed_value = matches.opt_str(options::PAGE_RANGE_OPTION).unwrap(); let unparsed_value = matches.opt_str(options::PAGE_RANGE_OPTION).unwrap();
i.parse::<usize>().map_err(|_e| { i.parse::<usize>().map_err(|_e| {
PrError::EncounteredErrors(format!("invalid --pages argument '{}'", unparsed_value)) PrError::EncounteredErrors(format!(
"invalid --pages argument {}",
unparsed_value.quote()
))
}) })
}; };
@ -741,7 +750,7 @@ fn build_options(
let start_column_option = match re_col.captures(&free_args).map(|i| { let start_column_option = match re_col.captures(&free_args).map(|i| {
let unparsed_num = i.get(1).unwrap().as_str().trim(); let unparsed_num = i.get(1).unwrap().as_str().trim();
unparsed_num.parse::<usize>().map_err(|_e| { unparsed_num.parse::<usize>().map_err(|_e| {
PrError::EncounteredErrors(format!("invalid {} argument '{}'", "-", unparsed_num)) PrError::EncounteredErrors(format!("invalid {} argument {}", "-", unparsed_num.quote()))
}) })
}) { }) {
Some(res) => Some(res?), Some(res) => Some(res?),

View file

@ -2,20 +2,11 @@
// spell-checker:ignore (ToDO) bslice // spell-checker:ignore (ToDO) bslice
use std::env; use std::io::{stdout, Write};
use std::io::{stderr, stdout, Write};
pub const EXIT_OK: i32 = 0; pub const EXIT_OK: i32 = 0;
pub const EXIT_ERR: i32 = 1; pub const EXIT_ERR: i32 = 1;
pub fn err_msg(msg: &str) {
let exe_path = match env::current_exe() {
Ok(p) => p.to_string_lossy().into_owned(),
_ => String::from(""),
};
writeln!(&mut stderr(), "{}: {}", exe_path, msg).unwrap();
}
// by default stdout only flushes // by default stdout only flushes
// to console when a newline is passed. // to console when a newline is passed.
pub fn flush_char(c: char) { pub fn flush_char(c: char) {

View file

@ -8,8 +8,9 @@
use itertools::put_back_n; use itertools::put_back_n;
use std::iter::Peekable; use std::iter::Peekable;
use std::slice::Iter; use std::slice::Iter;
use uucore::display::Quotable;
use uucore::show_error;
use crate::cli;
use crate::tokenize::sub::Sub; use crate::tokenize::sub::Sub;
use crate::tokenize::token::{Token, Tokenizer}; use crate::tokenize::token::{Token, Tokenizer};
use crate::tokenize::unescaped_text::UnescapedText; use crate::tokenize::unescaped_text::UnescapedText;
@ -19,10 +20,10 @@ pub struct Memo {
} }
fn warn_excess_args(first_arg: &str) { fn warn_excess_args(first_arg: &str) {
cli::err_msg(&format!( show_error!(
"warning: ignoring excess arguments, starting with '{}'", "warning: ignoring excess arguments, starting with {}",
first_arg first_arg.quote()
)); );
} }
impl Memo { impl Memo {

View file

@ -3,11 +3,10 @@
use itertools::{put_back_n, PutBackN}; use itertools::{put_back_n, PutBackN};
use std::str::Chars; use std::str::Chars;
use uucore::{display::Quotable, show_error};
use super::format_field::FormatField; use super::format_field::FormatField;
use crate::cli;
// contains the rough ingredients to final // contains the rough ingredients to final
// output for a number, organized together // output for a number, organized together
// to allow for easy generalization of output manipulation // to allow for easy generalization of output manipulation
@ -66,5 +65,5 @@ pub fn get_it_at(offset: usize, str_in: &str) -> PutBackN<Chars> {
// TODO: put this somewhere better // TODO: put this somewhere better
pub fn warn_incomplete_conv(pf_arg: &str) { pub fn warn_incomplete_conv(pf_arg: &str) {
// important: keep println here not print // important: keep println here not print
cli::err_msg(&format!("{}: value not completely converted", pf_arg)) show_error!("{}: value not completely converted", pf_arg.maybe_quote());
} }

View file

@ -7,6 +7,9 @@
use std::env; use std::env;
use std::vec::Vec; use std::vec::Vec;
use uucore::display::Quotable;
use uucore::show_error;
use super::format_field::{FieldType, FormatField}; use super::format_field::{FieldType, FormatField};
use super::formatter::{Base, FormatPrimitive, Formatter, InitialPrefix}; use super::formatter::{Base, FormatPrimitive, Formatter, InitialPrefix};
use super::formatters::cninetyninehexfloatf::CninetyNineHexFloatf; use super::formatters::cninetyninehexfloatf::CninetyNineHexFloatf;
@ -15,11 +18,9 @@ use super::formatters::floatf::Floatf;
use super::formatters::intf::Intf; use super::formatters::intf::Intf;
use super::formatters::scif::Scif; use super::formatters::scif::Scif;
use crate::cli;
pub fn warn_expected_numeric(pf_arg: &str) { pub fn warn_expected_numeric(pf_arg: &str) {
// important: keep println here not print // important: keep println here not print
cli::err_msg(&format!("{}: expected a numeric value", pf_arg)); show_error!("{}: expected a numeric value", pf_arg.maybe_quote());
} }
// when character constant arguments have excess characters // when character constant arguments have excess characters
@ -29,11 +30,11 @@ fn warn_char_constant_ign(remaining_bytes: Vec<u8>) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
if let env::VarError::NotPresent = e { if let env::VarError::NotPresent = e {
cli::err_msg(&format!( show_error!(
"warning: {:?}: character(s) following character \ "warning: {:?}: character(s) following character \
constant have been ignored", constant have been ignored",
&*remaining_bytes &*remaining_bytes
)); );
} }
} }
} }

View file

@ -10,6 +10,7 @@ use std::iter::Peekable;
use std::process::exit; use std::process::exit;
use std::slice::Iter; use std::slice::Iter;
use std::str::Chars; use std::str::Chars;
use uucore::show_error;
// use std::collections::HashSet; // use std::collections::HashSet;
use super::num_format::format_field::{FieldType, FormatField}; use super::num_format::format_field::{FieldType, FormatField};
@ -19,7 +20,7 @@ use super::unescaped_text::UnescapedText;
use crate::cli; use crate::cli;
fn err_conv(sofar: &str) { fn err_conv(sofar: &str) {
cli::err_msg(&format!("%{}: invalid conversion specification", sofar)); show_error!("%{}: invalid conversion specification", sofar);
exit(cli::EXIT_ERR); exit(cli::EXIT_ERR);
} }

View file

@ -17,6 +17,7 @@ use std::collections::{BTreeSet, HashMap, HashSet};
use std::default::Default; use std::default::Default;
use std::fs::File; use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write}; use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Write};
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
static NAME: &str = "ptx"; static NAME: &str = "ptx";
@ -292,7 +293,11 @@ fn create_word_set(config: &Config, filter: &WordFilter, file_map: &FileMap) ->
fn get_reference(config: &Config, word_ref: &WordRef, line: &str, context_reg: &Regex) -> String { fn get_reference(config: &Config, word_ref: &WordRef, line: &str, context_reg: &Regex) -> String {
if config.auto_ref { if config.auto_ref {
format!("{}:{}", word_ref.filename, word_ref.local_line_nr + 1) format!(
"{}:{}",
word_ref.filename.maybe_quote(),
word_ref.local_line_nr + 1
)
} else if config.input_ref { } else if config.input_ref {
let (beg, end) = match context_reg.find(line) { let (beg, end) = match context_reg.find(line) {
Some(x) => (x.start(), x.end()), Some(x) => (x.start(), x.end()),

View file

@ -14,6 +14,7 @@ use clap::{crate_version, App, Arg};
use std::fs; use std::fs;
use std::io::{stdout, Write}; use std::io::{stdout, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use uucore::display::Quotable;
use uucore::fs::{canonicalize, MissingHandling, ResolveMode}; use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
const ABOUT: &str = "Print value of a symbolic link or canonical file name."; const ABOUT: &str = "Print value of a symbolic link or canonical file name.";
@ -71,10 +72,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
} }
if no_newline && files.len() > 1 && !silent { if no_newline && files.len() > 1 && !silent {
eprintln!( show_error!("ignoring --no-newline with multiple arguments");
"{}: ignoring --no-newline with multiple arguments",
uucore::util_name()
);
no_newline = false; no_newline = false;
} }
@ -85,12 +83,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
Ok(path) => show(&path, no_newline, use_zero), Ok(path) => show(&path, no_newline, use_zero),
Err(err) => { Err(err) => {
if verbose { if verbose {
eprintln!( show_error!("{}: errno {}", f.maybe_quote(), err.raw_os_error().unwrap());
"{}: {}: errno {}",
uucore::util_name(),
f,
err.raw_os_error().unwrap()
);
} }
return 1; return 1;
} }
@ -100,12 +93,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
Ok(path) => show(&path, no_newline, use_zero), Ok(path) => show(&path, no_newline, use_zero),
Err(err) => { Err(err) => {
if verbose { if verbose {
eprintln!( show_error!("{}: errno {}", f.maybe_quote(), err.raw_os_error().unwrap());
"{}: {}: errno {:?}",
uucore::util_name(),
f,
err.raw_os_error().unwrap()
);
} }
return 1; return 1;
} }

View file

@ -11,8 +11,14 @@
extern crate uucore; extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use std::path::{Path, PathBuf}; use std::{
use uucore::fs::{canonicalize, MissingHandling, ResolveMode}; io::{stdout, Write},
path::{Path, PathBuf},
};
use uucore::{
display::{print_verbatim, Quotable},
fs::{canonicalize, MissingHandling, ResolveMode},
};
static ABOUT: &str = "print the resolved path"; static ABOUT: &str = "print the resolved path";
@ -58,7 +64,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
for path in &paths { for path in &paths {
if let Err(e) = resolve_path(path, strip, zero, logical, can_mode) { if let Err(e) = resolve_path(path, strip, zero, logical, can_mode) {
if !quiet { if !quiet {
show_error!("{}: {}", e, path.display()); show_error!("{}: {}", path.maybe_quote(), e);
} }
retcode = 1 retcode = 1
}; };
@ -154,8 +160,9 @@ fn resolve_path(
ResolveMode::Physical ResolveMode::Physical
}; };
let abs = canonicalize(p, can_mode, resolve)?; let abs = canonicalize(p, can_mode, resolve)?;
let line_ending = if zero { '\0' } else { '\n' }; let line_ending = if zero { b'\0' } else { b'\n' };
print!("{}{}", abs.display(), line_ending); print_verbatim(&abs)?;
stdout().write_all(&[line_ending])?;
Ok(()) Ok(())
} }

View file

@ -10,6 +10,7 @@
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use std::env; use std::env;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use uucore::display::println_verbatim;
use uucore::fs::{canonicalize, MissingHandling, ResolveMode}; use uucore::fs::{canonicalize, MissingHandling, ResolveMode};
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
@ -48,7 +49,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
if !absto.as_path().starts_with(absbase.as_path()) if !absto.as_path().starts_with(absbase.as_path())
|| !absfrom.as_path().starts_with(absbase.as_path()) || !absfrom.as_path().starts_with(absbase.as_path())
{ {
println!("{}", absto.display()); println_verbatim(absto).unwrap();
return 0; return 0;
} }
} }
@ -74,7 +75,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
.map(|x| result.push(x.as_os_str())) .map(|x| result.push(x.as_os_str()))
.last(); .last();
println!("{}", result.display()); println_verbatim(result).unwrap();
0 0
} }

View file

@ -17,6 +17,7 @@ use std::fs;
use std::io::{stderr, stdin, BufRead, Write}; use std::io::{stderr, stdin, BufRead, Write};
use std::ops::BitOr; use std::ops::BitOr;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use uucore::display::Quotable;
use walkdir::{DirEntry, WalkDir}; use walkdir::{DirEntry, WalkDir};
#[derive(Eq, PartialEq, Clone, Copy)] #[derive(Eq, PartialEq, Clone, Copy)]
@ -236,7 +237,10 @@ fn remove(files: Vec<String>, options: Options) -> bool {
// (e.g., permission), even rm -f should fail with // (e.g., permission), even rm -f should fail with
// outputting the error, but there's no easy eay. // outputting the error, but there's no easy eay.
if !options.force { if !options.force {
show_error!("cannot remove '{}': No such file or directory", filename); show_error!(
"cannot remove {}: No such file or directory",
filename.quote()
);
true true
} else { } else {
false false
@ -263,13 +267,9 @@ fn handle_dir(path: &Path, options: &Options) -> bool {
// GNU compatibility (rm/fail-eacces.sh) // GNU compatibility (rm/fail-eacces.sh)
// here, GNU doesn't use some kind of remove_dir_all // here, GNU doesn't use some kind of remove_dir_all
// It will show directory+file // It will show directory+file
show_error!( show_error!("cannot remove {}: {}", path.quote(), "Permission denied");
"cannot remove '{}': {}",
path.display(),
"Permission denied"
);
} else { } else {
show_error!("cannot remove '{}': {}", path.display(), e); show_error!("cannot remove {}: {}", path.quote(), e);
} }
} }
} else { } else {
@ -287,7 +287,7 @@ fn handle_dir(path: &Path, options: &Options) -> bool {
} }
Err(e) => { Err(e) => {
had_err = true; had_err = true;
show_error!("recursing in '{}': {}", path.display(), e); show_error!("recursing in {}: {}", path.quote(), e);
} }
} }
} }
@ -299,12 +299,12 @@ fn handle_dir(path: &Path, options: &Options) -> bool {
} else if options.dir && (!is_root || !options.preserve_root) { } else if options.dir && (!is_root || !options.preserve_root) {
had_err = remove_dir(path, options).bitor(had_err); had_err = remove_dir(path, options).bitor(had_err);
} else if options.recursive { } else if options.recursive {
show_error!("could not remove directory '{}'", path.display()); show_error!("could not remove directory {}", path.quote());
had_err = true; had_err = true;
} else { } else {
show_error!( show_error!(
"cannot remove '{}': Is a directory", // GNU's rm error message does not include help "cannot remove {}: Is a directory", // GNU's rm error message does not include help
path.display() path.quote()
); );
had_err = true; had_err = true;
} }
@ -325,36 +325,36 @@ fn remove_dir(path: &Path, options: &Options) -> bool {
match fs::remove_dir(path) { match fs::remove_dir(path) {
Ok(_) => { Ok(_) => {
if options.verbose { if options.verbose {
println!("removed directory '{}'", normalize(path).display()); println!("removed directory {}", normalize(path).quote());
} }
} }
Err(e) => { Err(e) => {
if e.kind() == std::io::ErrorKind::PermissionDenied { if e.kind() == std::io::ErrorKind::PermissionDenied {
// GNU compatibility (rm/fail-eacces.sh) // GNU compatibility (rm/fail-eacces.sh)
show_error!( show_error!(
"cannot remove '{}': {}", "cannot remove {}: {}",
path.display(), path.quote(),
"Permission denied" "Permission denied"
); );
} else { } else {
show_error!("cannot remove '{}': {}", path.display(), e); show_error!("cannot remove {}: {}", path.quote(), e);
} }
return true; return true;
} }
} }
} else { } else {
// directory can be read but is not empty // directory can be read but is not empty
show_error!("cannot remove '{}': Directory not empty", path.display()); show_error!("cannot remove {}: Directory not empty", path.quote());
return true; return true;
} }
} else { } else {
// called to remove a symlink_dir (windows) without "-r"/"-R" or "-d" // called to remove a symlink_dir (windows) without "-r"/"-R" or "-d"
show_error!("cannot remove '{}': Is a directory", path.display()); show_error!("cannot remove {}: Is a directory", path.quote());
return true; return true;
} }
} else { } else {
// GNU's rm shows this message if directory is empty but not readable // GNU's rm shows this message if directory is empty but not readable
show_error!("cannot remove '{}': Directory not empty", path.display()); show_error!("cannot remove {}: Directory not empty", path.quote());
return true; return true;
} }
} }
@ -372,19 +372,15 @@ fn remove_file(path: &Path, options: &Options) -> bool {
match fs::remove_file(path) { match fs::remove_file(path) {
Ok(_) => { Ok(_) => {
if options.verbose { if options.verbose {
println!("removed '{}'", normalize(path).display()); println!("removed {}", normalize(path).quote());
} }
} }
Err(e) => { Err(e) => {
if e.kind() == std::io::ErrorKind::PermissionDenied { if e.kind() == std::io::ErrorKind::PermissionDenied {
// GNU compatibility (rm/fail-eacces.sh) // GNU compatibility (rm/fail-eacces.sh)
show_error!( show_error!("cannot remove {}: {}", path.quote(), "Permission denied");
"cannot remove '{}': {}",
path.display(),
"Permission denied"
);
} else { } else {
show_error!("cannot remove '{}': {}", path.display(), e); show_error!("cannot remove {}: {}", path.quote(), e);
} }
return true; return true;
} }
@ -396,9 +392,9 @@ fn remove_file(path: &Path, options: &Options) -> bool {
fn prompt_file(path: &Path, is_dir: bool) -> bool { fn prompt_file(path: &Path, is_dir: bool) -> bool {
if is_dir { if is_dir {
prompt(&(format!("rm: remove directory '{}'? ", path.display()))) prompt(&(format!("rm: remove directory {}? ", path.quote())))
} else { } else {
prompt(&(format!("rm: remove file '{}'? ", path.display()))) prompt(&(format!("rm: remove file {}? ", path.quote())))
} }
} }

View file

@ -3,6 +3,8 @@ use std::fmt::Write;
use std::io; use std::io;
use std::str::Utf8Error; use std::str::Utf8Error;
use uucore::display::Quotable;
pub(crate) type Result<T> = std::result::Result<T, Error>; pub(crate) type Result<T> = std::result::Result<T, Error>;
#[derive(thiserror::Error, Debug)] #[derive(thiserror::Error, Debug)]
@ -31,7 +33,7 @@ pub(crate) enum Error {
source: io::Error, source: io::Error,
}, },
#[error("{operation} failed on '{}'", .operand1.to_string_lossy())] #[error("{operation} failed on {}", .operand1.quote())]
Io1 { Io1 {
operation: &'static str, operation: &'static str,
operand1: OsString, operand1: OsString,

View file

@ -14,6 +14,7 @@ use num_traits::{Num, ToPrimitive};
use std::cmp; use std::cmp;
use std::io::{stdout, Write}; use std::io::{stdout, Write};
use std::str::FromStr; use std::str::FromStr;
use uucore::display::Quotable;
static ABOUT: &str = "Display numbers from FIRST to LAST, in steps of INCREMENT."; static ABOUT: &str = "Display numbers from FIRST to LAST, in steps of INCREMENT.";
static OPT_SEPARATOR: &str = "separator"; static OPT_SEPARATOR: &str = "separator";
@ -115,14 +116,14 @@ impl FromStr for Number {
} }
Err(_) => match s.parse::<f64>() { Err(_) => match s.parse::<f64>() {
Ok(value) if value.is_nan() => Err(format!( Ok(value) if value.is_nan() => Err(format!(
"invalid 'not-a-number' argument: '{}'\nTry '{} --help' for more information.", "invalid 'not-a-number' argument: {}\nTry '{} --help' for more information.",
s, s.quote(),
uucore::execution_phrase(), uucore::execution_phrase(),
)), )),
Ok(value) => Ok(Number::F64(value)), Ok(value) => Ok(Number::F64(value)),
Err(_) => Err(format!( Err(_) => Err(format!(
"invalid floating point argument: '{}'\nTry '{} --help' for more information.", "invalid floating point argument: {}\nTry '{} --help' for more information.",
s, s.quote(),
uucore::execution_phrase(), uucore::execution_phrase(),
)), )),
}, },

View file

@ -18,12 +18,12 @@ use std::io;
use std::io::prelude::*; use std::io::prelude::*;
use std::io::SeekFrom; use std::io::SeekFrom;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use uucore::InvalidEncodingHandling; use uucore::display::Quotable;
use uucore::{util_name, InvalidEncodingHandling};
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
static NAME: &str = "shred";
const BLOCK_SIZE: usize = 512; const BLOCK_SIZE: usize = 512;
const NAME_CHARSET: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_."; const NAME_CHARSET: &[u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_.";
@ -281,7 +281,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
if !matches.is_present(options::FILE) { if !matches.is_present(options::FILE) {
show_error!("Missing an argument"); show_error!("Missing an argument");
show_error!("For help, try '{} --help'", NAME); show_error!("For help, try '{} --help'", uucore::execution_phrase());
return 0; return 0;
} }
@ -289,7 +289,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
Some(s) => match s.parse::<usize>() { Some(s) => match s.parse::<usize>() {
Ok(u) => u, Ok(u) => u,
Err(_) => { Err(_) => {
errs.push(format!("invalid number of passes: '{}'", s)); errs.push(format!("invalid number of passes: {}", s.quote()));
0 0
} }
}, },
@ -414,7 +414,11 @@ fn get_size(size_str_opt: Option<String>) -> Option<u64> {
let coefficient = match size_str.parse::<u64>() { let coefficient = match size_str.parse::<u64>() {
Ok(u) => u, Ok(u) => u,
Err(_) => { Err(_) => {
println!("{}: {}: Invalid file size", NAME, size_str_opt.unwrap()); println!(
"{}: {}: Invalid file size",
util_name(),
size_str_opt.unwrap().maybe_quote()
);
exit!(1); exit!(1);
} }
}; };
@ -452,11 +456,11 @@ fn wipe_file(
// Get these potential errors out of the way first // Get these potential errors out of the way first
let path: &Path = Path::new(path_str); let path: &Path = Path::new(path_str);
if !path.exists() { if !path.exists() {
show_error!("{}: No such file or directory", path.display()); show_error!("{}: No such file or directory", path.maybe_quote());
return; return;
} }
if !path.is_file() { if !path.is_file() {
show_error!("{}: Not a file", path.display()); show_error!("{}: Not a file", path.maybe_quote());
return; return;
} }
@ -520,7 +524,7 @@ fn wipe_file(
let mut file: File = match OpenOptions::new().write(true).truncate(false).open(path) { let mut file: File = match OpenOptions::new().write(true).truncate(false).open(path) {
Ok(f) => f, Ok(f) => f,
Err(e) => { Err(e) => {
show_error!("{}: failed to open for writing: {}", path.display(), e); show_error!("{}: failed to open for writing: {}", path.maybe_quote(), e);
return; return;
} }
}; };
@ -535,8 +539,8 @@ fn wipe_file(
if total_passes.to_string().len() == 1 { if total_passes.to_string().len() == 1 {
println!( println!(
"{}: {}: pass {}/{} ({})... ", "{}: {}: pass {}/{} ({})... ",
NAME, util_name(),
path.display(), path.maybe_quote(),
i + 1, i + 1,
total_passes, total_passes,
pass_name pass_name
@ -544,8 +548,8 @@ fn wipe_file(
} else { } else {
println!( println!(
"{}: {}: pass {:2.0}/{:2.0} ({})... ", "{}: {}: pass {:2.0}/{:2.0} ({})... ",
NAME, util_name(),
path.display(), path.maybe_quote(),
i + 1, i + 1,
total_passes, total_passes,
pass_name pass_name
@ -556,7 +560,7 @@ fn wipe_file(
match do_pass(&mut file, path, &mut generator, *pass_type, size) { match do_pass(&mut file, path, &mut generator, *pass_type, size) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
show_error!("{}: File write pass failed: {}", path.display(), e); show_error!("{}: File write pass failed: {}", path.maybe_quote(), e);
} }
} }
// Ignore failed writes; just keep trying // Ignore failed writes; just keep trying
@ -567,7 +571,7 @@ fn wipe_file(
match do_remove(path, path_str, verbose) { match do_remove(path, path_str, verbose) {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
show_error!("{}: failed to remove file: {}", path.display(), e); show_error!("{}: failed to remove file: {}", path.maybe_quote(), e);
} }
} }
} }
@ -622,9 +626,9 @@ fn wipe_name(orig_path: &Path, verbose: bool) -> Option<PathBuf> {
if verbose { if verbose {
println!( println!(
"{}: {}: renamed to {}", "{}: {}: renamed to {}",
NAME, util_name(),
last_path.display(), last_path.maybe_quote(),
new_path.display() new_path.quote()
); );
} }
@ -641,9 +645,9 @@ fn wipe_name(orig_path: &Path, verbose: bool) -> Option<PathBuf> {
Err(e) => { Err(e) => {
println!( println!(
"{}: {}: Couldn't rename to {}: {}", "{}: {}: Couldn't rename to {}: {}",
NAME, util_name(),
last_path.display(), last_path.maybe_quote(),
new_path.display(), new_path.quote(),
e e
); );
return None; return None;
@ -657,7 +661,7 @@ fn wipe_name(orig_path: &Path, verbose: bool) -> Option<PathBuf> {
fn do_remove(path: &Path, orig_filename: &str, verbose: bool) -> Result<(), io::Error> { fn do_remove(path: &Path, orig_filename: &str, verbose: bool) -> Result<(), io::Error> {
if verbose { if verbose {
println!("{}: {}: removing", NAME, orig_filename); println!("{}: {}: removing", util_name(), orig_filename.maybe_quote());
} }
let renamed_path: Option<PathBuf> = wipe_name(path, verbose); let renamed_path: Option<PathBuf> = wipe_name(path, verbose);
@ -666,7 +670,7 @@ fn do_remove(path: &Path, orig_filename: &str, verbose: bool) -> Result<(), io::
} }
if verbose { if verbose {
println!("{}: {}: removed", NAME, orig_filename); println!("{}: {}: removed", util_name(), orig_filename.maybe_quote());
} }
Ok(()) Ok(())

View file

@ -14,6 +14,7 @@ use clap::{crate_version, App, Arg};
use rand::Rng; use rand::Rng;
use std::fs::File; use std::fs::File;
use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write}; use std::io::{stdin, stdout, BufReader, BufWriter, Read, Write};
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
enum Mode { enum Mode {
@ -76,7 +77,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
Some(count) => match count.parse::<usize>() { Some(count) => match count.parse::<usize>() {
Ok(val) => val, Ok(val) => val,
Err(_) => { Err(_) => {
show_error!("invalid line count: '{}'", count); show_error!("invalid line count: {}", count.quote());
return 1; return 1;
} }
}, },
@ -185,13 +186,13 @@ fn read_input_file(filename: &str) -> Vec<u8> {
} else { } else {
match File::open(filename) { match File::open(filename) {
Ok(f) => Box::new(f) as Box<dyn Read>, Ok(f) => Box::new(f) as Box<dyn Read>,
Err(e) => crash!(1, "failed to open '{}': {}", filename, e), Err(e) => crash!(1, "failed to open {}: {}", filename.quote(), e),
} }
}); });
let mut data = Vec::new(); let mut data = Vec::new();
if let Err(e) = file.read_to_end(&mut data) { if let Err(e) = file.read_to_end(&mut data) {
crash!(1, "failed reading '{}': {}", filename, e) crash!(1, "failed reading {}: {}", filename.quote(), e)
}; };
data data
@ -235,7 +236,7 @@ fn shuf_bytes(input: &mut Vec<&[u8]>, opts: Options) {
None => Box::new(stdout()) as Box<dyn Write>, None => Box::new(stdout()) as Box<dyn Write>,
Some(s) => match File::create(&s[..]) { Some(s) => match File::create(&s[..]) {
Ok(f) => Box::new(f) as Box<dyn Write>, Ok(f) => Box::new(f) as Box<dyn Write>,
Err(e) => crash!(1, "failed to open '{}' for writing: {}", &s[..], e), Err(e) => crash!(1, "failed to open {} for writing: {}", s.quote(), e),
}, },
}); });
@ -243,7 +244,7 @@ fn shuf_bytes(input: &mut Vec<&[u8]>, opts: Options) {
Some(r) => WrappedRng::RngFile(rand::rngs::adapter::ReadRng::new( Some(r) => WrappedRng::RngFile(rand::rngs::adapter::ReadRng::new(
match File::open(&r[..]) { match File::open(&r[..]) {
Ok(f) => f, Ok(f) => f,
Err(e) => crash!(1, "failed to open random source '{}': {}", &r[..], e), Err(e) => crash!(1, "failed to open random source {}: {}", r.quote(), e),
}, },
)), )),
None => WrappedRng::RngDefault(rand::thread_rng()), None => WrappedRng::RngDefault(rand::thread_rng()),
@ -288,14 +289,14 @@ fn shuf_bytes(input: &mut Vec<&[u8]>, opts: Options) {
fn parse_range(input_range: &str) -> Result<(usize, usize), String> { fn parse_range(input_range: &str) -> Result<(usize, usize), String> {
let split: Vec<&str> = input_range.split('-').collect(); let split: Vec<&str> = input_range.split('-').collect();
if split.len() != 2 { if split.len() != 2 {
Err(format!("invalid input range: '{}'", input_range)) Err(format!("invalid input range: {}", input_range.quote()))
} else { } else {
let begin = split[0] let begin = split[0]
.parse::<usize>() .parse::<usize>()
.map_err(|_| format!("invalid input range: '{}'", split[0]))?; .map_err(|_| format!("invalid input range: {}", split[0].quote()))?;
let end = split[1] let end = split[1]
.parse::<usize>() .parse::<usize>()
.map_err(|_| format!("invalid input range: '{}'", split[1]))?; .map_err(|_| format!("invalid input range: {}", split[1].quote()))?;
Ok((begin, end + 1)) Ok((begin, end + 1))
} }
} }

View file

@ -45,6 +45,7 @@ use std::path::Path;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::Utf8Error; use std::str::Utf8Error;
use unicode_width::UnicodeWidthStr; use unicode_width::UnicodeWidthStr;
use uucore::display::Quotable;
use uucore::error::{set_exit_code, strip_errno, UError, UResult, USimpleError, UUsageError}; use uucore::error::{set_exit_code, strip_errno, UError, UResult, USimpleError, UUsageError};
use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::parse_size::{parse_size, ParseSizeError};
use uucore::version_cmp::version_cmp; use uucore::version_cmp::version_cmp;
@ -139,7 +140,7 @@ enum SortError {
error: std::io::Error, error: std::io::Error,
}, },
ReadFailed { ReadFailed {
path: String, path: PathBuf,
error: std::io::Error, error: std::io::Error,
}, },
ParseKeyError { ParseKeyError {
@ -189,7 +190,7 @@ impl Display for SortError {
write!( write!(
f, f,
"{}:{}: disorder: {}", "{}:{}: disorder: {}",
file.to_string_lossy(), file.maybe_quote(),
line_number, line_number,
line line
) )
@ -198,13 +199,23 @@ impl Display for SortError {
} }
} }
SortError::OpenFailed { path, error } => { SortError::OpenFailed { path, error } => {
write!(f, "open failed: {}: {}", path, strip_errno(error)) write!(
f,
"open failed: {}: {}",
path.maybe_quote(),
strip_errno(error)
)
} }
SortError::ParseKeyError { key, msg } => { SortError::ParseKeyError { key, msg } => {
write!(f, "failed to parse key `{}`: {}", key, msg) write!(f, "failed to parse key {}: {}", key.quote(), msg)
} }
SortError::ReadFailed { path, error } => { SortError::ReadFailed { path, error } => {
write!(f, "cannot read: {}: {}", path, strip_errno(error)) write!(
f,
"cannot read: {}: {}",
path.maybe_quote(),
strip_errno(error)
)
} }
SortError::OpenTmpFileFailed { error } => { SortError::OpenTmpFileFailed { error } => {
write!(f, "failed to open temporary file: {}", strip_errno(error)) write!(f, "failed to open temporary file: {}", strip_errno(error))
@ -213,7 +224,7 @@ impl Display for SortError {
write!(f, "couldn't execute compress program: errno {}", code) write!(f, "couldn't execute compress program: errno {}", code)
} }
SortError::CompressProgTerminatedAbnormally { prog } => { SortError::CompressProgTerminatedAbnormally { prog } => {
write!(f, "'{}' terminated abnormally", prog) write!(f, "{} terminated abnormally", prog.quote())
} }
SortError::TmpDirCreationFailed => write!(f, "could not create temporary directory"), SortError::TmpDirCreationFailed => write!(f, "could not create temporary directory"),
SortError::Uft8Error { error } => write!(f, "{}", error), SortError::Uft8Error { error } => write!(f, "{}", error),
@ -1179,7 +1190,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
if let Some(n_merge) = matches.value_of(options::BATCH_SIZE) { if let Some(n_merge) = matches.value_of(options::BATCH_SIZE) {
settings.merge_batch_size = n_merge.parse().map_err(|_| { settings.merge_batch_size = n_merge.parse().map_err(|_| {
UUsageError::new(2, format!("invalid --batch-size argument '{}'", n_merge)) UUsageError::new(
2,
format!("invalid --batch-size argument {}", n_merge.quote()),
)
})?; })?;
} }
@ -1211,23 +1225,30 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} else if settings.check && files.len() != 1 { } else if settings.check && files.len() != 1 {
return Err(UUsageError::new( return Err(UUsageError::new(
2, 2,
format!( format!("extra operand {} not allowed with -c", files[1].quote()),
"extra operand `{}' not allowed with -c",
files[1].to_string_lossy()
),
)); ));
} }
if let Some(arg) = matches.args.get(options::SEPARATOR) { if let Some(arg) = matches.args.get(options::SEPARATOR) {
let separator = arg.vals[0].to_string_lossy(); let mut separator = arg.vals[0].to_str().ok_or_else(|| {
let mut separator = separator.as_ref(); UUsageError::new(
2,
format!("separator is not valid unicode: {}", arg.vals[0].quote()),
)
})?;
if separator == "\\0" { if separator == "\\0" {
separator = "\0"; separator = "\0";
} }
// This rejects non-ASCII codepoints, but perhaps we don't have to.
// On the other hand GNU accepts any single byte, valid unicode or not.
// (Supporting multi-byte chars would require changes in tokenize_with_separator().)
if separator.len() != 1 { if separator.len() != 1 {
return Err(UUsageError::new( return Err(UUsageError::new(
2, 2,
"separator must be exactly one character long", format!(
"separator must be exactly one character long: {}",
separator.quote()
),
)); ));
} }
settings.separator = Some(separator.chars().next().unwrap()) settings.separator = Some(separator.chars().next().unwrap())
@ -1816,7 +1837,7 @@ fn open(path: impl AsRef<OsStr>) -> UResult<Box<dyn Read + Send>> {
match File::open(path) { match File::open(path) {
Ok(f) => Ok(Box::new(f) as Box<dyn Read + Send>), Ok(f) => Ok(Box::new(f) as Box<dyn Read + Send>),
Err(error) => Err(SortError::ReadFailed { Err(error) => Err(SortError::ReadFailed {
path: path.to_string_lossy().to_string(), path: path.to_owned(),
error, error,
} }
.into()), .into()),
@ -1828,8 +1849,8 @@ fn format_error_message(error: ParseSizeError, s: &str, option: &str) -> String
// GNU's sort echos affected flag, -S or --buffer-size, depending user's selection // GNU's sort echos affected flag, -S or --buffer-size, depending user's selection
// GNU's sort does distinguish between "invalid (suffix in) argument" // GNU's sort does distinguish between "invalid (suffix in) argument"
match error { match error {
ParseSizeError::ParseFailure(_) => format!("invalid --{} argument '{}'", option, s), ParseSizeError::ParseFailure(_) => format!("invalid --{} argument {}", option, s.quote()),
ParseSizeError::SizeTooBig(_) => format!("--{} argument '{}' too large", option, s), ParseSizeError::SizeTooBig(_) => format!("--{} argument {} too large", option, s.quote()),
} }
} }

View file

@ -19,6 +19,7 @@ use std::fs::File;
use std::io::{stdin, BufRead, BufReader, BufWriter, Read, Write}; use std::io::{stdin, BufRead, BufReader, BufWriter, Read, Write};
use std::path::Path; use std::path::Path;
use std::{char, fs::remove_file}; use std::{char, fs::remove_file};
use uucore::display::Quotable;
use uucore::parse_size::parse_size; use uucore::parse_size::parse_size;
static OPT_BYTES: &str = "bytes"; static OPT_BYTES: &str = "bytes";
@ -238,7 +239,11 @@ impl LineSplitter {
fn new(settings: &Settings) -> LineSplitter { fn new(settings: &Settings) -> LineSplitter {
LineSplitter { LineSplitter {
lines_per_split: settings.strategy_param.parse().unwrap_or_else(|_| { lines_per_split: settings.strategy_param.parse().unwrap_or_else(|_| {
crash!(1, "invalid number of lines: '{}'", settings.strategy_param) crash!(
1,
"invalid number of lines: {}",
settings.strategy_param.quote()
)
}), }),
} }
} }
@ -373,8 +378,8 @@ fn split(settings: &Settings) -> i32 {
let r = File::open(Path::new(&settings.input)).unwrap_or_else(|_| { let r = File::open(Path::new(&settings.input)).unwrap_or_else(|_| {
crash!( crash!(
1, 1,
"cannot open '{}' for reading: No such file or directory", "cannot open {} for reading: No such file or directory",
settings.input settings.input.quote()
) )
}); });
Box::new(r) as Box<dyn Read> Box::new(r) as Box<dyn Read>
@ -383,7 +388,7 @@ fn split(settings: &Settings) -> i32 {
let mut splitter: Box<dyn Splitter> = match settings.strategy.as_str() { let mut splitter: Box<dyn Splitter> = match settings.strategy.as_str() {
s if s == OPT_LINES => Box::new(LineSplitter::new(settings)), s if s == OPT_LINES => Box::new(LineSplitter::new(settings)),
s if (s == OPT_BYTES || s == OPT_LINE_BYTES) => Box::new(ByteSplitter::new(settings)), s if (s == OPT_BYTES || s == OPT_LINE_BYTES) => Box::new(ByteSplitter::new(settings)),
a => crash!(1, "strategy {} not supported", a), a => crash!(1, "strategy {} not supported", a.quote()),
}; };
let mut fileno = 0; let mut fileno = 0;

View file

@ -7,6 +7,7 @@
#[macro_use] #[macro_use]
extern crate uucore; extern crate uucore;
use uucore::display::Quotable;
use uucore::entries; use uucore::entries;
use uucore::fs::display_permissions; use uucore::fs::display_permissions;
use uucore::fsext::{ use uucore::fsext::{
@ -24,7 +25,7 @@ use std::{cmp, fs, iter};
macro_rules! check_bound { macro_rules! check_bound {
($str: ident, $bound:expr, $beg: expr, $end: expr) => { ($str: ident, $bound:expr, $beg: expr, $end: expr) => {
if $end >= $bound { if $end >= $bound {
return Err(format!("'{}': invalid directive", &$str[$beg..$end])); return Err(format!("{}: invalid directive", $str[$beg..$end].quote()));
} }
}; };
} }
@ -652,11 +653,7 @@ impl Stater {
return 1; return 1;
} }
}; };
arg = format!( arg = format!("{} -> {}", file.quote(), dst.quote());
"`{}' -> `{}'",
file,
dst.to_string_lossy()
);
} else { } else {
arg = file.to_string(); arg = file.to_string();
} }
@ -750,7 +747,7 @@ impl Stater {
} }
} }
Err(e) => { Err(e) => {
show_error!("cannot stat '{}': {}", file, e); show_error!("cannot stat {}: {}", file.quote(), e);
return 1; return 1;
} }
} }
@ -843,7 +840,11 @@ impl Stater {
} }
} }
Err(e) => { Err(e) => {
show_error!("cannot read file system information for '{}': {}", file, e); show_error!(
"cannot read file system information for {}: {}",
file.quote(),
e
);
return 1; return 1;
} }
} }

View file

@ -14,6 +14,7 @@ use clap::{crate_version, App, Arg};
use std::fs::File; use std::fs::File;
use std::io::{stdin, Read, Result}; use std::io::{stdin, Read, Result};
use std::path::Path; use std::path::Path;
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
static NAME: &str = "sum"; static NAME: &str = "sum";
@ -118,7 +119,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let reader = match open(file) { let reader = match open(file) {
Ok(f) => f, Ok(f) => f,
Err(error) => { Err(error) => {
show_error!("'{}' {}", file, error); show_error!("{}: {}", file.maybe_quote(), error);
exit_code = 2; exit_code = 2;
continue; continue;
} }

View file

@ -14,6 +14,7 @@ extern crate uucore;
use clap::{crate_version, App, Arg}; use clap::{crate_version, App, Arg};
use std::path::Path; use std::path::Path;
use uucore::display::Quotable;
static EXIT_ERR: i32 = 1; static EXIT_ERR: i32 = 1;
@ -175,7 +176,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
for f in &files { for f in &files {
if !Path::new(&f).exists() { if !Path::new(&f).exists() {
crash!(EXIT_ERR, "cannot stat '{}': No such file or directory", f); crash!(
EXIT_ERR,
"cannot stat {}: No such file or directory",
f.quote()
);
} }
} }

View file

@ -14,6 +14,7 @@ use clap::{crate_version, App, Arg};
use memchr::memmem; use memchr::memmem;
use std::io::{stdin, stdout, BufReader, Read, Write}; use std::io::{stdin, stdout, BufReader, Read, Write};
use std::{fs::File, path::Path}; use std::{fs::File, path::Path};
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
static NAME: &str = "tac"; static NAME: &str = "tac";
@ -141,11 +142,11 @@ fn tac(filenames: Vec<String>, before: bool, _: bool, separator: &str) -> i32 {
let path = Path::new(filename); let path = Path::new(filename);
if path.is_dir() || path.metadata().is_err() { if path.is_dir() || path.metadata().is_err() {
if path.is_dir() { if path.is_dir() {
show_error!("{}: read error: Invalid argument", filename); show_error!("{}: read error: Invalid argument", filename.maybe_quote());
} else { } else {
show_error!( show_error!(
"failed to open '{}' for reading: No such file or directory", "failed to open {} for reading: No such file or directory",
filename filename.quote()
); );
} }
exit_code = 1; exit_code = 1;
@ -154,7 +155,7 @@ fn tac(filenames: Vec<String>, before: bool, _: bool, separator: &str) -> i32 {
match File::open(path) { match File::open(path) {
Ok(f) => Box::new(f) as Box<dyn Read>, Ok(f) => Box::new(f) as Box<dyn Read>,
Err(e) => { Err(e) => {
show_error!("failed to open '{}' for reading: {}", filename, e); show_error!("failed to open {} for reading: {}", filename.quote(), e);
exit_code = 1; exit_code = 1;
continue; continue;
} }
@ -163,7 +164,7 @@ fn tac(filenames: Vec<String>, before: bool, _: bool, separator: &str) -> i32 {
let mut data = Vec::new(); let mut data = Vec::new();
if let Err(e) = file.read_to_end(&mut data) { if let Err(e) = file.read_to_end(&mut data) {
show_error!("failed to read '{}': {}", filename, e); show_error!("failed to read {}: {}", filename.quote(), e);
exit_code = 1; exit_code = 1;
continue; continue;
}; };

View file

@ -12,7 +12,8 @@ use clap::{crate_version, App, Arg};
use retain_mut::RetainMut; use retain_mut::RetainMut;
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write}; use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
use std::path::{Path, PathBuf}; use std::path::PathBuf;
use uucore::display::Quotable;
#[cfg(unix)] #[cfg(unix)]
use uucore::libc; use uucore::libc;
@ -167,7 +168,7 @@ impl Write for MultiWriter {
let result = writer.write_all(buf); let result = writer.write_all(buf);
match result { match result {
Err(f) => { Err(f) => {
show_error!("{}: {}", writer.name, f.to_string()); show_error!("{}: {}", writer.name.maybe_quote(), f);
false false
} }
_ => true, _ => true,
@ -181,7 +182,7 @@ impl Write for MultiWriter {
let result = writer.flush(); let result = writer.flush();
match result { match result {
Err(f) => { Err(f) => {
show_error!("{}: {}", writer.name, f.to_string()); show_error!("{}: {}", writer.name.maybe_quote(), f);
false false
} }
_ => true, _ => true,
@ -214,7 +215,7 @@ impl Read for NamedReader {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> { fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
match self.inner.read(buf) { match self.inner.read(buf) {
Err(f) => { Err(f) => {
show_error!("{}: {}", Path::new("stdin").display(), f.to_string()); show_error!("stdin: {}", f);
Err(f) Err(f)
} }
okay => okay, okay => okay,

View file

@ -10,6 +10,8 @@
use std::ffi::OsString; use std::ffi::OsString;
use std::iter::Peekable; use std::iter::Peekable;
use uucore::display::Quotable;
/// Represents one of the binary comparison operators for strings, integers, or files /// Represents one of the binary comparison operators for strings, integers, or files
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub enum Operator { pub enum Operator {
@ -43,19 +45,22 @@ impl Symbol {
/// Returns Symbol::None in place of None /// Returns Symbol::None in place of None
fn new(token: Option<OsString>) -> Symbol { fn new(token: Option<OsString>) -> Symbol {
match token { match token {
Some(s) => match s.to_string_lossy().as_ref() { Some(s) => match s.to_str() {
"(" => Symbol::LParen, Some(t) => match t {
"!" => Symbol::Bang, "(" => Symbol::LParen,
"-a" | "-o" => Symbol::BoolOp(s), "!" => Symbol::Bang,
"=" | "==" | "!=" => Symbol::Op(Operator::String(s)), "-a" | "-o" => Symbol::BoolOp(s),
"-eq" | "-ge" | "-gt" | "-le" | "-lt" | "-ne" => Symbol::Op(Operator::Int(s)), "=" | "==" | "!=" => Symbol::Op(Operator::String(s)),
"-ef" | "-nt" | "-ot" => Symbol::Op(Operator::File(s)), "-eq" | "-ge" | "-gt" | "-le" | "-lt" | "-ne" => Symbol::Op(Operator::Int(s)),
"-n" | "-z" => Symbol::UnaryOp(UnaryOperator::StrlenOp(s)), "-ef" | "-nt" | "-ot" => Symbol::Op(Operator::File(s)),
"-b" | "-c" | "-d" | "-e" | "-f" | "-g" | "-G" | "-h" | "-k" | "-L" | "-O" "-n" | "-z" => Symbol::UnaryOp(UnaryOperator::StrlenOp(s)),
| "-p" | "-r" | "-s" | "-S" | "-t" | "-u" | "-w" | "-x" => { "-b" | "-c" | "-d" | "-e" | "-f" | "-g" | "-G" | "-h" | "-k" | "-L" | "-O"
Symbol::UnaryOp(UnaryOperator::FiletestOp(s)) | "-p" | "-r" | "-s" | "-S" | "-t" | "-u" | "-w" | "-x" => {
} Symbol::UnaryOp(UnaryOperator::FiletestOp(s))
_ => Symbol::Literal(s), }
_ => Symbol::Literal(s),
},
None => Symbol::Literal(s),
}, },
None => Symbol::None, None => Symbol::None,
} }
@ -391,7 +396,7 @@ impl Parser {
self.expr(); self.expr();
match self.tokens.next() { match self.tokens.next() {
Some(token) => Err(format!("extra argument '{}'", token.to_string_lossy())), Some(token) => Err(format!("extra argument {}", token.quote())),
None => Ok(()), None => Ok(()),
} }
} }

View file

@ -13,7 +13,7 @@ mod parser;
use clap::{crate_version, App, AppSettings}; use clap::{crate_version, App, AppSettings};
use parser::{parse, Operator, Symbol, UnaryOperator}; use parser::{parse, Operator, Symbol, UnaryOperator};
use std::ffi::{OsStr, OsString}; use std::ffi::{OsStr, OsString};
use std::path::Path; use uucore::{display::Quotable, show_error};
const USAGE: &str = "test EXPRESSION const USAGE: &str = "test EXPRESSION
or: test or: test
@ -93,10 +93,7 @@ pub fn uu_app() -> App<'static, 'static> {
pub fn uumain(mut args: impl uucore::Args) -> i32 { pub fn uumain(mut args: impl uucore::Args) -> i32 {
let program = args.next().unwrap_or_else(|| OsString::from("test")); let program = args.next().unwrap_or_else(|| OsString::from("test"));
let binary_name = Path::new(&program) let binary_name = uucore::util_name();
.file_name()
.unwrap_or_else(|| OsStr::new("test"))
.to_string_lossy();
let mut args: Vec<_> = args.collect(); let mut args: Vec<_> = args.collect();
if binary_name.ends_with('[') { if binary_name.ends_with('[') {
@ -116,8 +113,8 @@ pub fn uumain(mut args: impl uucore::Args) -> i32 {
} }
// If invoked via name '[', matching ']' must be in the last arg // If invoked via name '[', matching ']' must be in the last arg
let last = args.pop(); let last = args.pop();
if last != Some(OsString::from("]")) { if last.as_deref() != Some(OsStr::new("]")) {
eprintln!("[: missing ']'"); show_error!("missing ']'");
return 2; return 2;
} }
} }
@ -133,7 +130,7 @@ pub fn uumain(mut args: impl uucore::Args) -> i32 {
} }
} }
Err(e) => { Err(e) => {
eprintln!("test: {}", e); show_error!("{}", e);
2 2
} }
} }
@ -190,11 +187,11 @@ fn eval(stack: &mut Vec<Symbol>) -> Result<bool, String> {
}) })
} }
Some(Symbol::UnaryOp(UnaryOperator::FiletestOp(op))) => { Some(Symbol::UnaryOp(UnaryOperator::FiletestOp(op))) => {
let op = op.to_string_lossy(); let op = op.to_str().unwrap();
let f = pop_literal!(); let f = pop_literal!();
Ok(match op.as_ref() { Ok(match op {
"-b" => path(&f, PathCondition::BlockSpecial), "-b" => path(&f, PathCondition::BlockSpecial),
"-c" => path(&f, PathCondition::CharacterSpecial), "-c" => path(&f, PathCondition::CharacterSpecial),
"-d" => path(&f, PathCondition::Directory), "-d" => path(&f, PathCondition::Directory),
@ -231,31 +228,33 @@ fn eval(stack: &mut Vec<Symbol>) -> Result<bool, String> {
} }
fn integers(a: &OsStr, b: &OsStr, op: &OsStr) -> Result<bool, String> { fn integers(a: &OsStr, b: &OsStr, op: &OsStr) -> Result<bool, String> {
let format_err = |value| format!("invalid integer '{}'", value); let format_err = |value: &OsStr| format!("invalid integer {}", value.quote());
let a = a.to_string_lossy(); let a: i64 = a
let a: i64 = a.parse().map_err(|_| format_err(a))?; .to_str()
.and_then(|s| s.parse().ok())
.ok_or_else(|| format_err(a))?;
let b = b.to_string_lossy(); let b: i64 = b
let b: i64 = b.parse().map_err(|_| format_err(b))?; .to_str()
.and_then(|s| s.parse().ok())
.ok_or_else(|| format_err(b))?;
let operator = op.to_string_lossy(); Ok(match op.to_str() {
Ok(match operator.as_ref() { Some("-eq") => a == b,
"-eq" => a == b, Some("-ne") => a != b,
"-ne" => a != b, Some("-gt") => a > b,
"-gt" => a > b, Some("-ge") => a >= b,
"-ge" => a >= b, Some("-lt") => a < b,
"-lt" => a < b, Some("-le") => a <= b,
"-le" => a <= b, _ => return Err(format!("unknown operator {}", op.quote())),
_ => return Err(format!("unknown operator '{}'", operator)),
}) })
} }
fn isatty(fd: &OsStr) -> Result<bool, String> { fn isatty(fd: &OsStr) -> Result<bool, String> {
let fd = fd.to_string_lossy(); fd.to_str()
.and_then(|s| s.parse().ok())
fd.parse() .ok_or_else(|| format!("invalid integer {}", fd.quote()))
.map_err(|_| format!("invalid integer '{}'", fd))
.map(|i| { .map(|i| {
#[cfg(not(target_os = "redox"))] #[cfg(not(target_os = "redox"))]
unsafe { unsafe {

View file

@ -16,6 +16,7 @@ use clap::{crate_version, App, AppSettings, Arg};
use std::io::ErrorKind; use std::io::ErrorKind;
use std::process::{Command, Stdio}; use std::process::{Command, Stdio};
use std::time::Duration; use std::time::Duration;
use uucore::display::Quotable;
use uucore::process::ChildExt; use uucore::process::ChildExt;
use uucore::signals::{signal_by_name_or_value, signal_name_by_value}; use uucore::signals::{signal_by_name_or_value, signal_name_by_value};
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
@ -61,7 +62,7 @@ impl Config {
let signal_result = signal_by_name_or_value(signal_); let signal_result = signal_by_name_or_value(signal_);
match signal_result { match signal_result {
None => { None => {
unreachable!("invalid signal '{}'", signal_); unreachable!("invalid signal {}", signal_.quote());
} }
Some(signal_value) => signal_value, Some(signal_value) => signal_value,
} }
@ -216,9 +217,9 @@ fn timeout(
Ok(None) => { Ok(None) => {
if verbose { if verbose {
show_error!( show_error!(
"sending signal {} to command '{}'", "sending signal {} to command {}",
signal_name_by_value(signal).unwrap(), signal_name_by_value(signal).unwrap(),
cmd[0] cmd[0].quote()
); );
} }
crash_if_err!(ERR_EXIT_STATUS, process.send_signal(signal)); crash_if_err!(ERR_EXIT_STATUS, process.send_signal(signal));
@ -233,7 +234,7 @@ fn timeout(
} }
Ok(None) => { Ok(None) => {
if verbose { if verbose {
show_error!("sending signal KILL to command '{}'", cmd[0]); show_error!("sending signal KILL to command {}", cmd[0].quote());
} }
crash_if_err!( crash_if_err!(
ERR_EXIT_STATUS, ERR_EXIT_STATUS,

View file

@ -17,6 +17,7 @@ use clap::{crate_version, App, Arg, ArgGroup};
use filetime::*; use filetime::*;
use std::fs::{self, File}; use std::fs::{self, File};
use std::path::Path; use std::path::Path;
use uucore::display::Quotable;
use uucore::error::{FromIo, UError, UResult, USimpleError}; use uucore::error::{FromIo, UError, UResult, USimpleError};
static ABOUT: &str = "Update the access and modification times of each FILE to the current time."; static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
@ -82,7 +83,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} }
if let Err(e) = File::create(path) { if let Err(e) = File::create(path) {
show!(e.map_err_context(|| format!("cannot touch '{}'", path.display()))); show!(e.map_err_context(|| format!("cannot touch {}", path.quote())));
continue; continue;
}; };
@ -122,7 +123,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} else { } else {
filetime::set_file_times(path, atime, mtime) filetime::set_file_times(path, atime, mtime)
} }
.map_err_context(|| format!("setting times of '{}'", path.display()))?; .map_err_context(|| format!("setting times of {}", path.quote()))?;
} }
Ok(()) Ok(())
@ -209,7 +210,7 @@ fn stat(path: &Path, follow: bool) -> UResult<(FileTime, FileTime)> {
} else { } else {
fs::metadata(path) fs::metadata(path)
} }
.map_err_context(|| format!("failed to get attributes of '{}'", path.display()))?; .map_err_context(|| format!("failed to get attributes of {}", path.quote()))?;
Ok(( Ok((
FileTime::from_last_access_time(&metadata), FileTime::from_last_access_time(&metadata),
@ -249,11 +250,16 @@ fn parse_timestamp(s: &str) -> UResult<FileTime> {
10 => ("%y%m%d%H%M", s.to_owned()), 10 => ("%y%m%d%H%M", s.to_owned()),
11 => ("%Y%m%d%H%M.%S", format!("{}{}", now.tm_year + 1900, s)), 11 => ("%Y%m%d%H%M.%S", format!("{}{}", now.tm_year + 1900, s)),
8 => ("%Y%m%d%H%M", format!("{}{}", now.tm_year + 1900, s)), 8 => ("%Y%m%d%H%M", format!("{}{}", now.tm_year + 1900, s)),
_ => return Err(USimpleError::new(1, format!("invalid date format '{}'", s))), _ => {
return Err(USimpleError::new(
1,
format!("invalid date format {}", s.quote()),
))
}
}; };
let tm = time::strptime(&ts, format) let tm = time::strptime(&ts, format)
.map_err(|_| USimpleError::new(1, format!("invalid date format '{}'", s)))?; .map_err(|_| USimpleError::new(1, format!("invalid date format {}", s.quote())))?;
let mut local = to_local(tm); let mut local = to_local(tm);
local.tm_isdst = -1; local.tm_isdst = -1;
@ -269,7 +275,10 @@ fn parse_timestamp(s: &str) -> UResult<FileTime> {
}; };
let tm2 = time::at(ts); let tm2 = time::at(ts);
if tm.tm_hour != tm2.tm_hour { if tm.tm_hour != tm2.tm_hour {
return Err(USimpleError::new(1, format!("invalid date format '{}'", s))); return Err(USimpleError::new(
1,
format!("invalid date format {}", s.quote()),
));
} }
Ok(ft) Ok(ft)

View file

@ -21,7 +21,7 @@ use fnv::FnvHashMap;
use std::io::{stdin, stdout, BufRead, BufWriter, Write}; use std::io::{stdin, stdout, BufRead, BufWriter, Write};
use crate::expand::ExpandSet; use crate::expand::ExpandSet;
use uucore::InvalidEncodingHandling; use uucore::{display::Quotable, InvalidEncodingHandling};
static ABOUT: &str = "translate or delete characters"; static ABOUT: &str = "translate or delete characters";
@ -271,8 +271,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
if !(delete_flag || squeeze_flag) && sets.len() < 2 { if !(delete_flag || squeeze_flag) && sets.len() < 2 {
show_error!( show_error!(
"missing operand after '{}'\nTry '{} --help' for more information.", "missing operand after {}\nTry '{} --help' for more information.",
sets[0], sets[0].quote(),
uucore::execution_phrase() uucore::execution_phrase()
); );
return 1; return 1;

View file

@ -15,6 +15,7 @@ use std::convert::TryFrom;
use std::fs::{metadata, OpenOptions}; use std::fs::{metadata, OpenOptions};
use std::io::ErrorKind; use std::io::ErrorKind;
use std::path::Path; use std::path::Path;
use uucore::display::Quotable;
use uucore::parse_size::{parse_size, ParseSizeError}; use uucore::parse_size::{parse_size, ParseSizeError};
#[derive(Debug, Eq, PartialEq)] #[derive(Debug, Eq, PartialEq)]
@ -120,8 +121,8 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let reference = matches.value_of(options::REFERENCE).map(String::from); let reference = matches.value_of(options::REFERENCE).map(String::from);
crash!( crash!(
1, 1,
"cannot stat '{}': No such file or directory", "cannot stat {}: No such file or directory",
reference.unwrap_or_else(|| "".to_string()) reference.as_deref().unwrap_or("").quote()
); // TODO: fix '--no-create' see test_reference and test_truncate_bytes_size ); // TODO: fix '--no-create' see test_reference and test_truncate_bytes_size
} }
_ => crash!(1, "{}", e.to_string()), _ => crash!(1, "{}", e.to_string()),

View file

@ -14,6 +14,7 @@ use std::collections::{HashMap, HashSet};
use std::fs::File; use std::fs::File;
use std::io::{stdin, BufRead, BufReader, Read}; use std::io::{stdin, BufRead, BufReader, Read};
use std::path::Path; use std::path::Path;
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
static SUMMARY: &str = "Topological sort the strings in FILE. static SUMMARY: &str = "Topological sort the strings in FILE.
@ -45,7 +46,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
file_buf = match File::open(Path::new(&input)) { file_buf = match File::open(Path::new(&input)) {
Ok(a) => a, Ok(a) => a,
_ => { _ => {
show_error!("{}: No such file or directory", input); show_error!("{}: No such file or directory", input.maybe_quote());
return 1; return 1;
} }
}; };
@ -68,7 +69,11 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
for ab in tokens.chunks(2) { for ab in tokens.chunks(2) {
match ab.len() { match ab.len() {
2 => g.add_edge(&ab[0], &ab[1]), 2 => g.add_edge(&ab[0], &ab[1]),
_ => crash!(1, "{}: input contains an odd number of tokens", input), _ => crash!(
1,
"{}: input contains an odd number of tokens",
input.maybe_quote()
),
} }
} }
} }

View file

@ -16,6 +16,7 @@ use std::fs::File;
use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Stdout, Write}; use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Stdout, Write};
use std::str::from_utf8; use std::str::from_utf8;
use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthChar;
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
static NAME: &str = "unexpand"; static NAME: &str = "unexpand";
@ -141,9 +142,9 @@ fn open(path: String) -> BufReader<Box<dyn Read + 'static>> {
if path == "-" { if path == "-" {
BufReader::new(Box::new(stdin()) as Box<dyn Read>) BufReader::new(Box::new(stdin()) as Box<dyn Read>)
} else { } else {
file_buf = match File::open(&path[..]) { file_buf = match File::open(&path) {
Ok(a) => a, Ok(a) => a,
Err(e) => crash!(1, "{}: {}", &path[..], e), Err(e) => crash!(1, "{}: {}", path.maybe_quote(), e),
}; };
BufReader::new(Box::new(file_buf) as Box<dyn Read>) BufReader::new(Box::new(file_buf) as Box<dyn Read>)
} }

View file

@ -14,6 +14,7 @@ use std::io::{stdin, stdout, BufRead, BufReader, BufWriter, Read, Result, Write}
use std::path::Path; use std::path::Path;
use std::str::FromStr; use std::str::FromStr;
use strum_macros::{AsRefStr, EnumString}; use strum_macros::{AsRefStr, EnumString};
use uucore::display::Quotable;
static ABOUT: &str = "Report or omit repeated lines."; static ABOUT: &str = "Report or omit repeated lines.";
pub mod options { pub mod options {
@ -217,7 +218,14 @@ fn get_line_string(io_line: Result<Vec<u8>>) -> String {
fn opt_parsed<T: FromStr>(opt_name: &str, matches: &ArgMatches) -> Option<T> { fn opt_parsed<T: FromStr>(opt_name: &str, matches: &ArgMatches) -> Option<T> {
matches.value_of(opt_name).map(|arg_str| { matches.value_of(opt_name).map(|arg_str| {
let opt_val: Option<T> = arg_str.parse().ok(); let opt_val: Option<T> = arg_str.parse().ok();
opt_val.unwrap_or_else(|| crash!(1, "Invalid argument for {}: {}", opt_name, arg_str)) opt_val.unwrap_or_else(|| {
crash!(
1,
"Invalid argument for {}: {}",
opt_name,
arg_str.maybe_quote()
)
})
}) })
} }

View file

@ -17,6 +17,7 @@ use libc::{lstat, stat, unlink};
use libc::{S_IFLNK, S_IFMT, S_IFREG}; use libc::{S_IFLNK, S_IFMT, S_IFREG};
use std::ffi::CString; use std::ffi::CString;
use std::io::{Error, ErrorKind}; use std::io::{Error, ErrorKind};
use uucore::display::Quotable;
use uucore::InvalidEncodingHandling; use uucore::InvalidEncodingHandling;
static ABOUT: &str = "Unlink the file at [FILE]."; static ABOUT: &str = "Unlink the file at [FILE].";
@ -63,7 +64,12 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
let result = unsafe { lstat(c_string.as_ptr(), &mut buf as *mut stat) }; let result = unsafe { lstat(c_string.as_ptr(), &mut buf as *mut stat) };
if result < 0 { if result < 0 {
crash!(1, "Cannot stat '{}': {}", paths[0], Error::last_os_error()); crash!(
1,
"Cannot stat {}: {}",
paths[0].quote(),
Error::last_os_error()
);
} }
buf.st_mode & S_IFMT buf.st_mode & S_IFMT

View file

@ -5,6 +5,7 @@
//! Common functions to manage permissions //! Common functions to manage permissions
use crate::display::Quotable;
use crate::error::strip_errno; use crate::error::strip_errno;
use crate::error::UResult; use crate::error::UResult;
use crate::error::USimpleError; use crate::error::USimpleError;
@ -80,29 +81,29 @@ pub fn wrap_chown<P: AsRef<Path>>(
VerbosityLevel::Silent => (), VerbosityLevel::Silent => (),
level => { level => {
out = format!( out = format!(
"changing {} of '{}': {}", "changing {} of {}: {}",
if verbosity.groups_only { if verbosity.groups_only {
"group" "group"
} else { } else {
"ownership" "ownership"
}, },
path.display(), path.quote(),
e e
); );
if level == VerbosityLevel::Verbose { if level == VerbosityLevel::Verbose {
out = if verbosity.groups_only { out = if verbosity.groups_only {
format!( format!(
"{}\nfailed to change group of '{}' from {} to {}", "{}\nfailed to change group of {} from {} to {}",
out, out,
path.display(), path.quote(),
entries::gid2grp(meta.gid()).unwrap(), entries::gid2grp(meta.gid()).unwrap(),
entries::gid2grp(dest_gid).unwrap() entries::gid2grp(dest_gid).unwrap()
) )
} else { } else {
format!( format!(
"{}\nfailed to change ownership of '{}' from {}:{} to {}:{}", "{}\nfailed to change ownership of {} from {}:{} to {}:{}",
out, out,
path.display(), path.quote(),
entries::uid2usr(meta.uid()).unwrap(), entries::uid2usr(meta.uid()).unwrap(),
entries::gid2grp(meta.gid()).unwrap(), entries::gid2grp(meta.gid()).unwrap(),
entries::uid2usr(dest_uid).unwrap(), entries::uid2usr(dest_uid).unwrap(),
@ -120,15 +121,15 @@ pub fn wrap_chown<P: AsRef<Path>>(
VerbosityLevel::Changes | VerbosityLevel::Verbose => { VerbosityLevel::Changes | VerbosityLevel::Verbose => {
out = if verbosity.groups_only { out = if verbosity.groups_only {
format!( format!(
"changed group of '{}' from {} to {}", "changed group of {} from {} to {}",
path.display(), path.quote(),
entries::gid2grp(meta.gid()).unwrap(), entries::gid2grp(meta.gid()).unwrap(),
entries::gid2grp(dest_gid).unwrap() entries::gid2grp(dest_gid).unwrap()
) )
} else { } else {
format!( format!(
"changed ownership of '{}' from {}:{} to {}:{}", "changed ownership of {} from {}:{} to {}:{}",
path.display(), path.quote(),
entries::uid2usr(meta.uid()).unwrap(), entries::uid2usr(meta.uid()).unwrap(),
entries::gid2grp(meta.gid()).unwrap(), entries::gid2grp(meta.gid()).unwrap(),
entries::uid2usr(dest_uid).unwrap(), entries::uid2usr(dest_uid).unwrap(),
@ -141,14 +142,14 @@ pub fn wrap_chown<P: AsRef<Path>>(
} else if verbosity.level == VerbosityLevel::Verbose { } else if verbosity.level == VerbosityLevel::Verbose {
out = if verbosity.groups_only { out = if verbosity.groups_only {
format!( format!(
"group of '{}' retained as {}", "group of {} retained as {}",
path.display(), path.quote(),
entries::gid2grp(dest_gid).unwrap_or_default() entries::gid2grp(dest_gid).unwrap_or_default()
) )
} else { } else {
format!( format!(
"ownership of '{}' retained as {}:{}", "ownership of {} retained as {}:{}",
path.display(), path.quote(),
entries::uid2usr(dest_uid).unwrap(), entries::uid2usr(dest_uid).unwrap(),
entries::gid2grp(dest_gid).unwrap() entries::gid2grp(dest_gid).unwrap()
) )
@ -358,9 +359,9 @@ impl ChownExecutor {
match self.verbosity.level { match self.verbosity.level {
VerbosityLevel::Silent => (), VerbosityLevel::Silent => (),
_ => show_error!( _ => show_error!(
"cannot {} '{}': {}", "cannot {} {}: {}",
if follow { "dereference" } else { "access" }, if follow { "dereference" } else { "access" },
path.display(), path.quote(),
strip_errno(&e) strip_errno(&e)
), ),
} }

View file

@ -72,6 +72,8 @@ use std::sync::atomic::Ordering;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use crate::display::Quotable;
pub fn get_utility_is_second_arg() -> bool { pub fn get_utility_is_second_arg() -> bool {
crate::macros::UTILITY_IS_SECOND_ARG.load(Ordering::SeqCst) crate::macros::UTILITY_IS_SECOND_ARG.load(Ordering::SeqCst)
} }
@ -171,14 +173,15 @@ pub trait Args: Iterator<Item = OsString> + Sized {
Ok(string) => Ok(string), Ok(string) => Ok(string),
Err(s_ret) => { Err(s_ret) => {
full_conversion = false; full_conversion = false;
let lossy_conversion = s_ret.to_string_lossy();
eprintln!( eprintln!(
"Input with broken encoding occurred! (s = '{}') ", "Input with broken encoding occurred! (s = {}) ",
&lossy_conversion s_ret.quote()
); );
match handling { match handling {
InvalidEncodingHandling::Ignore => Err(String::new()), InvalidEncodingHandling::Ignore => Err(String::new()),
InvalidEncodingHandling::ConvertLossy => Err(lossy_conversion.to_string()), InvalidEncodingHandling::ConvertLossy => {
Err(s_ret.to_string_lossy().into_owned())
}
InvalidEncodingHandling::Panic => { InvalidEncodingHandling::Panic => {
panic!("Broken encoding found but caller cannot handle it") panic!("Broken encoding found but caller cannot handle it")
} }

View file

@ -78,7 +78,10 @@
// spell-checker:ignore backupopt // spell-checker:ignore backupopt
use crate::error::{UError, UResult}; use crate::{
display::Quotable,
error::{UError, UResult},
};
use clap::ArgMatches; use clap::ArgMatches;
use std::{ use std::{
env, env,
@ -167,18 +170,22 @@ impl Display for BackupError {
match self { match self {
BE::InvalidArgument(arg, origin) => write!( BE::InvalidArgument(arg, origin) => write!(
f, f,
"invalid argument '{}' for '{}'\n{}", "invalid argument {} for '{}'\n{}",
arg, origin, VALID_ARGS_HELP arg.quote(),
origin,
VALID_ARGS_HELP
), ),
BE::AmbiguousArgument(arg, origin) => write!( BE::AmbiguousArgument(arg, origin) => write!(
f, f,
"ambiguous argument '{}' for '{}'\n{}", "ambiguous argument {} for '{}'\n{}",
arg, origin, VALID_ARGS_HELP arg.quote(),
origin,
VALID_ARGS_HELP
), ),
BE::BackupImpossible() => write!(f, "cannot create backup"), BE::BackupImpossible() => write!(f, "cannot create backup"),
// Placeholder for later // Placeholder for later
// BE::BackupFailed(from, to, e) => Display::fmt( // BE::BackupFailed(from, to, e) => Display::fmt(
// &uio_error!(e, "failed to backup '{}' to '{}'", from.display(), to.display()), // &uio_error!(e, "failed to backup {} to {}", from.quote(), to.quote()),
// f // f
// ), // ),
} }

View file

@ -87,13 +87,16 @@ macro_rules! impl_as_ref {
}; };
} }
impl_as_ref!(str);
impl_as_ref!(&'_ str); impl_as_ref!(&'_ str);
impl_as_ref!(String); impl_as_ref!(String);
impl_as_ref!(std::path::Path);
impl_as_ref!(&'_ std::path::Path); impl_as_ref!(&'_ std::path::Path);
impl_as_ref!(std::path::PathBuf); impl_as_ref!(std::path::PathBuf);
impl_as_ref!(std::path::Component<'_>); impl_as_ref!(std::path::Component<'_>);
impl_as_ref!(std::path::Components<'_>); impl_as_ref!(std::path::Components<'_>);
impl_as_ref!(std::path::Iter<'_>); impl_as_ref!(std::path::Iter<'_>);
impl_as_ref!(std::ffi::OsStr);
impl_as_ref!(&'_ std::ffi::OsStr); impl_as_ref!(&'_ std::ffi::OsStr);
impl_as_ref!(std::ffi::OsString); impl_as_ref!(std::ffi::OsString);
@ -106,6 +109,13 @@ impl Quotable for Cow<'_, str> {
} }
} }
impl Quotable for Cow<'_, std::path::Path> {
fn quote(&self) -> Quoted<'_> {
let text: &std::path::Path = self.as_ref();
Quoted::new(text.as_ref())
}
}
/// A wrapper around [`OsStr`] for printing paths with quoting and escaping applied. /// A wrapper around [`OsStr`] for printing paths with quoting and escaping applied.
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub struct Quoted<'a> { pub struct Quoted<'a> {
@ -407,6 +417,19 @@ pub fn println_verbatim<S: AsRef<OsStr>>(text: S) -> io::Result<()> {
Ok(()) Ok(())
} }
/// Like `println_verbatim`, without the trailing newline.
pub fn print_verbatim<S: AsRef<OsStr>>(text: S) -> io::Result<()> {
let mut stdout = io::stdout();
#[cfg(any(unix, target_os = "wasi"))]
{
stdout.write_all(text.as_ref().as_bytes())
}
#[cfg(not(any(unix, target_os = "wasi")))]
{
write!(stdout, "{}", std::path::Path::new(text.as_ref()).display())
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

View file

@ -99,7 +99,10 @@ pub type UResult<T> = Result<T, Box<dyn UError>>;
/// An example of a custom error from `ls`: /// An example of a custom error from `ls`:
/// ///
/// ``` /// ```
/// use uucore::error::{UError, UResult}; /// use uucore::{
/// display::Quotable,
/// error::{UError, UResult}
/// };
/// use std::{ /// use std::{
/// error::Error, /// error::Error,
/// fmt::{Display, Debug}, /// fmt::{Display, Debug},
@ -126,8 +129,8 @@ pub type UResult<T> = Result<T, Box<dyn UError>>;
/// impl Display for LsError { /// impl Display for LsError {
/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
/// match self { /// match self {
/// LsError::InvalidLineWidth(s) => write!(f, "invalid line width: '{}'", s), /// LsError::InvalidLineWidth(s) => write!(f, "invalid line width: {}", s.quote()),
/// LsError::NoMetadata(p) => write!(f, "could not open file: '{}'", p.display()), /// LsError::NoMetadata(p) => write!(f, "could not open file: {}", p.quote()),
/// } /// }
/// } /// }
/// } /// }
@ -158,7 +161,10 @@ pub trait UError: Error + Send {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use uucore::error::{UError}; /// use uucore::{
/// display::Quotable,
/// error::UError
/// };
/// use std::{ /// use std::{
/// error::Error, /// error::Error,
/// fmt::{Display, Debug}, /// fmt::{Display, Debug},
@ -189,8 +195,8 @@ pub trait UError: Error + Send {
/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
/// use MyError as ME; /// use MyError as ME;
/// match self { /// match self {
/// ME::Foo(s) => write!(f, "Unknown Foo: '{}'", s), /// ME::Foo(s) => write!(f, "Unknown Foo: {}", s.quote()),
/// ME::Bar(p) => write!(f, "Couldn't find Bar: '{}'", p.display()), /// ME::Bar(p) => write!(f, "Couldn't find Bar: {}", p.quote()),
/// ME::Bing() => write!(f, "Exterminate!"), /// ME::Bing() => write!(f, "Exterminate!"),
/// } /// }
/// } /// }
@ -209,7 +215,10 @@ pub trait UError: Error + Send {
/// # Example /// # Example
/// ///
/// ``` /// ```
/// use uucore::error::{UError}; /// use uucore::{
/// display::Quotable,
/// error::UError
/// };
/// use std::{ /// use std::{
/// error::Error, /// error::Error,
/// fmt::{Display, Debug}, /// fmt::{Display, Debug},
@ -240,8 +249,8 @@ pub trait UError: Error + Send {
/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
/// use MyError as ME; /// use MyError as ME;
/// match self { /// match self {
/// ME::Foo(s) => write!(f, "Unknown Foo: '{}'", s), /// ME::Foo(s) => write!(f, "Unknown Foo: {}", s.quote()),
/// ME::Bar(p) => write!(f, "Couldn't find Bar: '{}'", p.display()), /// ME::Bar(p) => write!(f, "Couldn't find Bar: {}", p.quote()),
/// ME::Bing() => write!(f, "Exterminate!"), /// ME::Bing() => write!(f, "Exterminate!"),
/// } /// }
/// } /// }
@ -342,7 +351,10 @@ impl UError for UUsageError {
/// There are two ways to construct this type: with [`UIoError::new`] or by calling the /// There are two ways to construct this type: with [`UIoError::new`] or by calling the
/// [`FromIo::map_err_context`] method on a [`std::io::Result`] or [`std::io::Error`]. /// [`FromIo::map_err_context`] method on a [`std::io::Result`] or [`std::io::Error`].
/// ``` /// ```
/// use uucore::error::{FromIo, UResult, UIoError, UError}; /// use uucore::{
/// display::Quotable,
/// error::{FromIo, UResult, UIoError, UError}
/// };
/// use std::fs::File; /// use std::fs::File;
/// use std::path::Path; /// use std::path::Path;
/// let path = Path::new("test.txt"); /// let path = Path::new("test.txt");
@ -350,12 +362,12 @@ impl UError for UUsageError {
/// // Manual construction /// // Manual construction
/// let e: Box<dyn UError> = UIoError::new( /// let e: Box<dyn UError> = UIoError::new(
/// std::io::ErrorKind::NotFound, /// std::io::ErrorKind::NotFound,
/// format!("cannot access '{}'", path.display()) /// format!("cannot access {}", path.quote())
/// ); /// );
/// let res: UResult<()> = Err(e.into()); /// let res: UResult<()> = Err(e.into());
/// ///
/// // Converting from an `std::io::Error`. /// // Converting from an `std::io::Error`.
/// let res: UResult<File> = File::open(path).map_err_context(|| format!("cannot access '{}'", path.display())); /// let res: UResult<File> = File::open(path).map_err_context(|| format!("cannot access {}", path.quote()));
/// ``` /// ```
#[derive(Debug)] #[derive(Debug)]
pub struct UIoError { pub struct UIoError {

View file

@ -9,6 +9,8 @@
use std::str::FromStr; use std::str::FromStr;
use crate::display::Quotable;
#[derive(PartialEq, Eq, PartialOrd, Ord, Debug)] #[derive(PartialEq, Eq, PartialOrd, Ord, Debug)]
pub struct Range { pub struct Range {
pub low: usize, pub low: usize,
@ -86,7 +88,7 @@ impl Range {
for item in list.split(',') { for item in list.split(',') {
let range_item = FromStr::from_str(item) let range_item = FromStr::from_str(item)
.map_err(|e| format!("range '{}' was invalid: {}", item, e))?; .map_err(|e| format!("range {} was invalid: {}", item.quote(), e))?;
ranges.push(range_item); ranges.push(range_item);
} }

View file

@ -9,6 +9,8 @@ use std::convert::TryFrom;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
use crate::display::Quotable;
/// Parse a size string into a number of bytes. /// Parse a size string into a number of bytes.
/// ///
/// A size string comprises an integer and an optional unit. The unit /// A size string comprises an integer and an optional unit. The unit
@ -107,6 +109,9 @@ impl fmt::Display for ParseSizeError {
} }
} }
// FIXME: It's more idiomatic to move the formatting into the Display impl,
// but there's a lot of downstream code that constructs these errors manually
// that would be affected
impl ParseSizeError { impl ParseSizeError {
fn parse_failure(s: &str) -> ParseSizeError { fn parse_failure(s: &str) -> ParseSizeError {
// stderr on linux (GNU coreutils 8.32) (LC_ALL=C) // stderr on linux (GNU coreutils 8.32) (LC_ALL=C)
@ -140,7 +145,7 @@ impl ParseSizeError {
// --width // --width
// --strings // --strings
// etc. // etc.
ParseSizeError::ParseFailure(format!("'{}'", s)) ParseSizeError::ParseFailure(format!("{}", s.quote()))
} }
fn size_too_big(s: &str) -> ParseSizeError { fn size_too_big(s: &str) -> ParseSizeError {
@ -160,7 +165,10 @@ impl ParseSizeError {
// stderr on macos (brew - GNU coreutils 8.32) also differs for the same version, e.g.: // stderr on macos (brew - GNU coreutils 8.32) also differs for the same version, e.g.:
// ghead: invalid number of bytes: '1Y': Value too large to be stored in data type // ghead: invalid number of bytes: '1Y': Value too large to be stored in data type
// gtail: invalid number of bytes: '1Y': Value too large to be stored in data type // gtail: invalid number of bytes: '1Y': Value too large to be stored in data type
ParseSizeError::SizeTooBig(format!("'{}': Value too large for defined data type", s)) ParseSizeError::SizeTooBig(format!(
"{}: Value too large for defined data type",
s.quote()
))
} }
} }
@ -262,7 +270,7 @@ mod tests {
for &test_string in &test_strings { for &test_string in &test_strings {
assert_eq!( assert_eq!(
parse_size(test_string).unwrap_err(), parse_size(test_string).unwrap_err(),
ParseSizeError::ParseFailure(format!("'{}'", test_string)) ParseSizeError::ParseFailure(format!("{}", test_string.quote()))
); );
} }
} }

View file

@ -9,6 +9,8 @@
use std::time::Duration; use std::time::Duration;
use crate::display::Quotable;
pub fn from_str(string: &str) -> Result<Duration, String> { pub fn from_str(string: &str) -> Result<Duration, String> {
let len = string.len(); let len = string.len();
if len == 0 { if len == 0 {
@ -25,13 +27,13 @@ pub fn from_str(string: &str) -> Result<Duration, String> {
if string == "inf" || string == "infinity" { if string == "inf" || string == "infinity" {
("inf", 1) ("inf", 1)
} else { } else {
return Err(format!("invalid time interval '{}'", string)); return Err(format!("invalid time interval {}", string.quote()));
} }
} }
}; };
let num = numstr let num = numstr
.parse::<f64>() .parse::<f64>()
.map_err(|e| format!("invalid time interval '{}': {}", string, e))?; .map_err(|e| format!("invalid time interval {}: {}", string.quote(), e))?;
const NANOS_PER_SEC: u32 = 1_000_000_000; const NANOS_PER_SEC: u32 = 1_000_000_000;
let whole_secs = num.trunc(); let whole_secs = num.trunc();

View file

@ -23,7 +23,7 @@ fn test_enter_chroot_fails() {
assert!(result assert!(result
.stderr_str() .stderr_str()
.starts_with("chroot: cannot chroot to jail: Operation not permitted (os error 1)")); .starts_with("chroot: cannot chroot to 'jail': Operation not permitted (os error 1)"));
} }
#[test] #[test]
@ -34,7 +34,7 @@ fn test_no_such_directory() {
ucmd.arg("a") ucmd.arg("a")
.fails() .fails()
.stderr_is("chroot: cannot change root directory to `a`: no such directory"); .stderr_is("chroot: cannot change root directory to 'a': no such directory");
} }
#[test] #[test]

View file

@ -68,7 +68,7 @@ fn test_invalid_file() {
.arg(folder_name) .arg(folder_name)
.fails() .fails()
.no_stdout() .no_stdout()
.stderr_contains("cksum: 'asdf' No such file or directory"); .stderr_contains("cksum: asdf: No such file or directory");
// Then check when the file is of an invalid type // Then check when the file is of an invalid type
at.mkdir(folder_name); at.mkdir(folder_name);
@ -76,7 +76,7 @@ fn test_invalid_file() {
.arg(folder_name) .arg(folder_name)
.fails() .fails()
.no_stdout() .no_stdout()
.stderr_contains("cksum: 'asdf' Is a directory"); .stderr_contains("cksum: asdf: Is a directory");
} }
// Make sure crc is correct for files larger than 32 bytes // Make sure crc is correct for files larger than 32 bytes

View file

@ -531,7 +531,7 @@ fn test_keys_invalid_field() {
new_ucmd!() new_ucmd!()
.args(&["-k", "1."]) .args(&["-k", "1."])
.fails() .fails()
.stderr_only("sort: failed to parse key `1.`: failed to parse character index ``: cannot parse integer from empty string"); .stderr_only("sort: failed to parse key '1.': failed to parse character index ``: cannot parse integer from empty string");
} }
#[test] #[test]
@ -539,7 +539,7 @@ fn test_keys_invalid_field_option() {
new_ucmd!() new_ucmd!()
.args(&["-k", "1.1x"]) .args(&["-k", "1.1x"])
.fails() .fails()
.stderr_only("sort: failed to parse key `1.1x`: invalid option: `x`"); .stderr_only("sort: failed to parse key '1.1x': invalid option: `x`");
} }
#[test] #[test]
@ -547,7 +547,7 @@ fn test_keys_invalid_field_zero() {
new_ucmd!() new_ucmd!()
.args(&["-k", "0.1"]) .args(&["-k", "0.1"])
.fails() .fails()
.stderr_only("sort: failed to parse key `0.1`: field index can not be 0"); .stderr_only("sort: failed to parse key '0.1': field index can not be 0");
} }
#[test] #[test]
@ -555,7 +555,7 @@ fn test_keys_invalid_char_zero() {
new_ucmd!() new_ucmd!()
.args(&["-k", "1.0"]) .args(&["-k", "1.0"])
.fails() .fails()
.stderr_only("sort: failed to parse key `1.0`: invalid character index 0 for the start position of a field"); .stderr_only("sort: failed to parse key '1.0': invalid character index 0 for the start position of a field");
} }
#[test] #[test]

View file

@ -59,7 +59,7 @@ fn test_invalid_file() {
at.mkdir("a"); at.mkdir("a");
ucmd.arg("a").fails().stderr_is("sum: 'a' Is a directory"); ucmd.arg("a").fails().stderr_is("sum: a: Is a directory");
} }
#[test] #[test]
@ -68,5 +68,5 @@ fn test_invalid_metadata() {
ucmd.arg("b") ucmd.arg("b")
.fails() .fails()
.stderr_is("sum: 'b' No such file or directory"); .stderr_is("sum: b: No such file or directory");
} }

View file

@ -320,7 +320,7 @@ fn test_invalid_utf8_integer_compare() {
cmd.run() cmd.run()
.status_code(2) .status_code(2)
.stderr_is("test: invalid integer 'fo<66>o'"); .stderr_is("test: invalid integer $'fo\\x80o'");
let mut cmd = new_ucmd!(); let mut cmd = new_ucmd!();
cmd.raw.arg(arg); cmd.raw.arg(arg);
@ -328,7 +328,7 @@ fn test_invalid_utf8_integer_compare() {
cmd.run() cmd.run()
.status_code(2) .status_code(2)
.stderr_is("test: invalid integer 'fo<66>o'"); .stderr_is("test: invalid integer $'fo\\x80o'");
} }
#[test] #[test]