mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 12:07:46 +00:00
quoting_style: use and return OsString
s
This exposes the non-UTF-8 functionality to callers. Support in `argument`, `spec`, and `wc` are implemented, as their usage is simple. A wrapper only returning valid unicode is used in `ls`, since proper handling of OsStrings there is more involved (outputs that escape non-unicode work now though).
This commit is contained in:
parent
2331600f4c
commit
43229ae104
5 changed files with 76 additions and 35 deletions
|
@ -21,7 +21,7 @@ use std::os::windows::fs::MetadataExt;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::Reverse,
|
cmp::Reverse,
|
||||||
error::Error,
|
error::Error,
|
||||||
ffi::OsString,
|
ffi::{OsStr, OsString},
|
||||||
fmt::{Display, Write as FmtWrite},
|
fmt::{Display, Write as FmtWrite},
|
||||||
fs::{self, DirEntry, FileType, Metadata, ReadDir},
|
fs::{self, DirEntry, FileType, Metadata, ReadDir},
|
||||||
io::{stdout, BufWriter, ErrorKind, Stdout, Write},
|
io::{stdout, BufWriter, ErrorKind, Stdout, Write},
|
||||||
|
@ -55,7 +55,7 @@ use uucore::libc::{dev_t, major, minor};
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR};
|
use uucore::libc::{S_IXGRP, S_IXOTH, S_IXUSR};
|
||||||
use uucore::line_ending::LineEnding;
|
use uucore::line_ending::LineEnding;
|
||||||
use uucore::quoting_style::{escape_dir_name, escape_name, QuotingStyle};
|
use uucore::quoting_style::{self, QuotingStyle};
|
||||||
use uucore::{
|
use uucore::{
|
||||||
display::Quotable,
|
display::Quotable,
|
||||||
error::{set_exit_code, UError, UResult},
|
error::{set_exit_code, UError, UResult},
|
||||||
|
@ -2048,7 +2048,11 @@ impl PathData {
|
||||||
/// file11
|
/// file11
|
||||||
/// ```
|
/// ```
|
||||||
fn show_dir_name(path_data: &PathData, out: &mut BufWriter<Stdout>, config: &Config) {
|
fn show_dir_name(path_data: &PathData, out: &mut BufWriter<Stdout>, config: &Config) {
|
||||||
let escaped_name = escape_dir_name(path_data.p_buf.as_os_str(), &config.quoting_style);
|
// FIXME: replace this with appropriate behavior for literal unprintable bytes
|
||||||
|
let escaped_name =
|
||||||
|
quoting_style::escape_dir_name(path_data.p_buf.as_os_str(), &config.quoting_style)
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string();
|
||||||
|
|
||||||
let name = if config.hyperlink && !config.dired {
|
let name = if config.hyperlink && !config.dired {
|
||||||
create_hyperlink(&escaped_name, path_data)
|
create_hyperlink(&escaped_name, path_data)
|
||||||
|
@ -3002,7 +3006,6 @@ use std::sync::Mutex;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use uucore::entries;
|
use uucore::entries;
|
||||||
use uucore::fs::FileInformation;
|
use uucore::fs::FileInformation;
|
||||||
use uucore::quoting_style;
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn cached_uid2usr(uid: u32) -> String {
|
fn cached_uid2usr(uid: u32) -> String {
|
||||||
|
@ -3542,3 +3545,10 @@ fn calculate_padding_collection(
|
||||||
|
|
||||||
padding_collections
|
padding_collections
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: replace this with appropriate behavior for literal unprintable bytes
|
||||||
|
fn escape_name(name: &OsStr, style: &QuotingStyle) -> String {
|
||||||
|
quoting_style::escape_name(name, style)
|
||||||
|
.to_string_lossy()
|
||||||
|
.to_string()
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ mod word_count;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::{Borrow, Cow},
|
borrow::{Borrow, Cow},
|
||||||
cmp::max,
|
cmp::max,
|
||||||
ffi::OsString,
|
ffi::{OsStr, OsString},
|
||||||
fs::{self, File},
|
fs::{self, File},
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
iter,
|
iter,
|
||||||
|
@ -28,7 +28,7 @@ use utf8::{BufReadDecoder, BufReadDecoderError};
|
||||||
use uucore::{
|
use uucore::{
|
||||||
error::{FromIo, UError, UResult},
|
error::{FromIo, UError, UResult},
|
||||||
format_usage, help_about, help_usage,
|
format_usage, help_about, help_usage,
|
||||||
quoting_style::{escape_name, QuotingStyle},
|
quoting_style::{self, QuotingStyle},
|
||||||
shortcut_value_parser::ShortcutValueParser,
|
shortcut_value_parser::ShortcutValueParser,
|
||||||
show,
|
show,
|
||||||
};
|
};
|
||||||
|
@ -259,7 +259,7 @@ impl<'a> Input<'a> {
|
||||||
match self {
|
match self {
|
||||||
Self::Path(path) => Some(match path.to_str() {
|
Self::Path(path) => Some(match path.to_str() {
|
||||||
Some(s) if !s.contains('\n') => Cow::Borrowed(s),
|
Some(s) if !s.contains('\n') => Cow::Borrowed(s),
|
||||||
_ => Cow::Owned(escape_name(path.as_os_str(), QS_ESCAPE)),
|
_ => Cow::Owned(escape_name_wrapper(path.as_os_str())),
|
||||||
}),
|
}),
|
||||||
Self::Stdin(StdinKind::Explicit) => Some(Cow::Borrowed(STDIN_REPR)),
|
Self::Stdin(StdinKind::Explicit) => Some(Cow::Borrowed(STDIN_REPR)),
|
||||||
Self::Stdin(StdinKind::Implicit) => None,
|
Self::Stdin(StdinKind::Implicit) => None,
|
||||||
|
@ -269,7 +269,7 @@ impl<'a> Input<'a> {
|
||||||
/// Converts input into the form that appears in errors.
|
/// Converts input into the form that appears in errors.
|
||||||
fn path_display(&self) -> String {
|
fn path_display(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
Self::Path(path) => escape_name(path.as_os_str(), QS_ESCAPE),
|
Self::Path(path) => escape_name_wrapper(path.as_os_str()),
|
||||||
Self::Stdin(_) => String::from("standard input"),
|
Self::Stdin(_) => String::from("standard input"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -361,7 +361,7 @@ impl WcError {
|
||||||
Some((input, idx)) => {
|
Some((input, idx)) => {
|
||||||
let path = match input {
|
let path = match input {
|
||||||
Input::Stdin(_) => STDIN_REPR.into(),
|
Input::Stdin(_) => STDIN_REPR.into(),
|
||||||
Input::Path(path) => escape_name(path.as_os_str(), QS_ESCAPE).into(),
|
Input::Path(path) => escape_name_wrapper(path.as_os_str()).into(),
|
||||||
};
|
};
|
||||||
Self::ZeroLengthFileNameCtx { path, idx }
|
Self::ZeroLengthFileNameCtx { path, idx }
|
||||||
}
|
}
|
||||||
|
@ -761,7 +761,9 @@ fn files0_iter_file<'a>(path: &Path) -> UResult<impl Iterator<Item = InputIterIt
|
||||||
Err(e) => Err(e.map_err_context(|| {
|
Err(e) => Err(e.map_err_context(|| {
|
||||||
format!(
|
format!(
|
||||||
"cannot open {} for reading",
|
"cannot open {} for reading",
|
||||||
escape_name(path.as_os_str(), QS_QUOTE_ESCAPE)
|
quoting_style::escape_name(path.as_os_str(), QS_QUOTE_ESCAPE)
|
||||||
|
.into_string()
|
||||||
|
.expect("All escaped names with the escaping option return valid strings.")
|
||||||
)
|
)
|
||||||
})),
|
})),
|
||||||
}
|
}
|
||||||
|
@ -793,9 +795,9 @@ fn files0_iter<'a>(
|
||||||
Ok(Input::Path(PathBuf::from(s).into()))
|
Ok(Input::Path(PathBuf::from(s).into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => Err(e.map_err_context(|| {
|
Err(e) => Err(e
|
||||||
format!("{}: read error", escape_name(&err_path, QS_ESCAPE))
|
.map_err_context(|| format!("{}: read error", escape_name_wrapper(&err_path)))
|
||||||
}) as Box<dyn UError>),
|
as Box<dyn UError>),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
// Loop until there is an error; yield that error and then nothing else.
|
// Loop until there is an error; yield that error and then nothing else.
|
||||||
|
@ -808,6 +810,12 @@ fn files0_iter<'a>(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn escape_name_wrapper(name: &OsStr) -> String {
|
||||||
|
quoting_style::escape_name(name, QS_ESCAPE)
|
||||||
|
.into_string()
|
||||||
|
.expect("All escaped names with the escaping option return valid strings.")
|
||||||
|
}
|
||||||
|
|
||||||
fn wc(inputs: &Inputs, settings: &Settings) -> UResult<()> {
|
fn wc(inputs: &Inputs, settings: &Settings) -> UResult<()> {
|
||||||
let mut total_word_count = WordCount::default();
|
let mut total_word_count = WordCount::default();
|
||||||
let mut num_inputs: usize = 0;
|
let mut num_inputs: usize = 0;
|
||||||
|
|
|
@ -112,7 +112,8 @@ fn extract_value<T: Default>(p: Result<T, ParseError<'_, T>>, input: &str) -> T
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
ParseError::PartialMatch(v, rest) => {
|
ParseError::PartialMatch(v, rest) => {
|
||||||
if input.starts_with('\'') {
|
let bytes = input.as_encoded_bytes();
|
||||||
|
if !bytes.is_empty() && bytes[0] == b'\'' {
|
||||||
show_warning!(
|
show_warning!(
|
||||||
"{}: character(s) following character constant have been ignored",
|
"{}: character(s) following character constant have been ignored",
|
||||||
&rest,
|
&rest,
|
||||||
|
|
|
@ -353,20 +353,20 @@ impl Spec {
|
||||||
writer.write_all(&parsed).map_err(FormatError::IoError)
|
writer.write_all(&parsed).map_err(FormatError::IoError)
|
||||||
}
|
}
|
||||||
Self::QuotedString => {
|
Self::QuotedString => {
|
||||||
let s = args.get_str();
|
let s = escape_name(
|
||||||
writer
|
args.get_str().as_ref(),
|
||||||
.write_all(
|
&QuotingStyle::Shell {
|
||||||
escape_name(
|
escape: true,
|
||||||
s.as_ref(),
|
always_quote: false,
|
||||||
&QuotingStyle::Shell {
|
show_control: false,
|
||||||
escape: true,
|
},
|
||||||
always_quote: false,
|
);
|
||||||
show_control: false,
|
#[cfg(unix)]
|
||||||
},
|
let bytes = std::os::unix::ffi::OsStringExt::into_vec(s);
|
||||||
)
|
#[cfg(not(unix))]
|
||||||
.as_bytes(),
|
let bytes = s.to_string_lossy().as_bytes().to_owned();
|
||||||
)
|
|
||||||
.map_err(FormatError::IoError)
|
writer.write_all(&bytes).map_err(FormatError::IoError)
|
||||||
}
|
}
|
||||||
Self::SignedInt {
|
Self::SignedInt {
|
||||||
width,
|
width,
|
||||||
|
|
|
@ -6,8 +6,10 @@
|
||||||
//! Set of functions for escaping names according to different quoting styles.
|
//! Set of functions for escaping names according to different quoting styles.
|
||||||
|
|
||||||
use std::char::from_digit;
|
use std::char::from_digit;
|
||||||
use std::ffi::OsStr;
|
use std::ffi::{OsStr, OsString};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::ffi::{OsStrExt, OsStringExt};
|
||||||
|
|
||||||
// These are characters with special meaning in the shell (e.g. bash).
|
// These are characters with special meaning in the shell (e.g. bash).
|
||||||
// The first const contains characters that only have a special meaning when they appear at the beginning of a name.
|
// The first const contains characters that only have a special meaning when they appear at the beginning of a name.
|
||||||
|
@ -459,17 +461,37 @@ fn escape_name_inner(name: &[u8], style: &QuotingStyle, dirname: bool) -> Vec<u8
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Escape a filename with respect to the given style.
|
/// Escape a filename with respect to the given style.
|
||||||
pub fn escape_name(name: &OsStr, style: &QuotingStyle) -> String {
|
pub fn escape_name(name: &OsStr, style: &QuotingStyle) -> OsString {
|
||||||
let name = name.to_string_lossy();
|
#[cfg(unix)]
|
||||||
String::from_utf8_lossy(&escape_name_inner(name.as_bytes(), style, false)).to_string()
|
{
|
||||||
|
let name = name.as_bytes();
|
||||||
|
OsStringExt::from_vec(escape_name_inner(name, style, false))
|
||||||
|
}
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
{
|
||||||
|
let name = name.to_string_lossy();
|
||||||
|
String::from_utf8_lossy(&escape_name_inner(name.as_bytes(), style, false))
|
||||||
|
.to_string()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Escape a directory name with respect to the given style.
|
/// Escape a directory name with respect to the given style.
|
||||||
/// This is mainly meant to be used for ls' directory name printing and is not
|
/// This is mainly meant to be used for ls' directory name printing and is not
|
||||||
/// likely to be used elsewhere.
|
/// likely to be used elsewhere.
|
||||||
pub fn escape_dir_name(dir_name: &OsStr, style: &QuotingStyle) -> String {
|
pub fn escape_dir_name(dir_name: &OsStr, style: &QuotingStyle) -> OsString {
|
||||||
let dir_name = dir_name.to_string_lossy();
|
#[cfg(unix)]
|
||||||
String::from_utf8_lossy(&escape_name_inner(dir_name.as_bytes(), style, true)).to_string()
|
{
|
||||||
|
let name = dir_name.as_bytes();
|
||||||
|
OsStringExt::from_vec(escape_name_inner(name, style, true))
|
||||||
|
}
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
{
|
||||||
|
let name = dir_name.to_string_lossy();
|
||||||
|
String::from_utf8_lossy(&escape_name_inner(name.as_bytes(), style, true))
|
||||||
|
.to_string()
|
||||||
|
.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for QuotingStyle {
|
impl fmt::Display for QuotingStyle {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue