Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/uu/stat/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ stat-after-help = Valid format sequences for files (without `--file-system`):
## Error messages

stat-error-invalid-quoting-style = Invalid quoting style: {$style}
stat-warning-invalid-env-quoting-style = ignoring invalid value of environment variable QUOTING_STYLE: '{$style}'
stat-error-missing-operand = missing operand
Try 'stat --help' for more information.
stat-error-invalid-directive = {$directive}: invalid directive
Expand Down
1 change: 1 addition & 0 deletions src/uu/stat/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ stat-word-birth = Créé
## Messages d'erreur

stat-error-invalid-quoting-style = Style de guillemets invalide : {$style}
stat-warning-invalid-env-quoting-style = valeur invalide de la variable d'environnement QUOTING_STYLE ignorée : '{$style}'
stat-error-missing-operand = opérande manquant
Essayez 'stat --help' pour plus d'informations.
stat-error-invalid-directive = {$directive} : directive invalide
Expand Down
24 changes: 20 additions & 4 deletions src/uu/stat/src/stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,16 +451,32 @@ fn quote_file_name(file_name: &str, quoting_style: &QuotingStyle) -> String {
}
}

fn warn_invalid_quoting_style(style: &str) {
use std::sync::atomic::{AtomicBool, Ordering};
static WARNED: AtomicBool = AtomicBool::new(false);
if !WARNED.swap(true, Ordering::Relaxed) {
show_error!(
"{}",
translate!("stat-warning-invalid-env-quoting-style", "style" => style.to_string())
);
}
}

fn get_quoted_file_name(
display_name: &str,
file: &OsString,
file_type: FileType,
from_user: bool,
) -> Result<String, i32> {
let quoting_style = env::var("QUOTING_STYLE")
.ok()
.and_then(|style| style.parse().ok())
.unwrap_or_default();
let quoting_style = match env::var("QUOTING_STYLE") {
Ok(style) => style.parse().unwrap_or_else(|_| {
// Match GNU coreutils 9.11: warn (once) when QUOTING_STYLE is set
// to a value we don't understand, then fall back to the default.
warn_invalid_quoting_style(&style);
QuotingStyle::default()
}),
Err(_) => QuotingStyle::default(),
};

if file_type.is_symlink() {
let quoted_display_name = quote_file_name(display_name, &quoting_style);
Expand Down
48 changes: 48 additions & 0 deletions tests/by-util/test_stat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.

// spell-checker:ignore crème brûlée

use uutests::at_and_ucmd;
use uutests::new_ucmd;
use uutests::unwrap_or_return;
Expand Down Expand Up @@ -447,6 +449,52 @@ fn test_quoting_style_locale() {
.stdout_only("\'\"\'\n");
}

#[test]
fn test_quoting_style_invalid_env() {
let ts = TestScenario::new(util_name!());
let at = &ts.fixtures;
at.touch("baguette");
at.touch("Croissant");
at.touch("Escargot");

let needle = "ignoring invalid value of environment variable QUOTING_STYLE";

// A bogus value triggers exactly one warning across multiple files and the
// output falls back to the default (shell-escape) style.
let res = ts
.ucmd()
.env("QUOTING_STYLE", "fromage")
.args(&["-c", "nom=[%N]", "baguette", "Croissant", "Escargot"])
.succeeds();
res.stdout_is("nom=['baguette']\nnom=['Croissant']\nnom=['Escargot']\n");
assert_eq!(res.stderr_str().matches(needle).count(), 1);
Comment on lines +469 to +470
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would check stdout and stderr in the same way you do below.


// An empty value is also invalid and must be reported with empty quotes.
ts.ucmd()
.env("QUOTING_STYLE", "")
.args(&["-c", "%N", "baguette"])
.succeeds()
.stdout_is("'baguette'\n")
.stderr_is("stat: ignoring invalid value of environment variable QUOTING_STYLE: ''\n");

// %%%N: a literal '%' followed by the quoted name, fallback style applies.
ts.ucmd()
.env("QUOTING_STYLE", "soufflé")
.args(&["-c", "%%%N", "baguette"])
.succeeds()
.stdout_is("%'baguette'\n")
.stderr_is(
"stat: ignoring invalid value of environment variable QUOTING_STYLE: 'soufflé'\n",
);

// When the format never consults %N, QUOTING_STYLE must not be parsed at all.
ts.ucmd()
.env("QUOTING_STYLE", "crème-brûlée")
.args(&["-c", "taille=%s genre:%F brut=%n", "baguette"])
.succeeds()
.no_stderr();
}

#[test]
fn test_printf_octal_1() {
let ts = TestScenario::new(util_name!());
Expand Down
Loading