Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
3 changes: 3 additions & 0 deletions src/uu/date/locales/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,6 @@ date-error-setting-date-not-supported-redox = setting the date is not supported
date-error-cannot-set-date = cannot set date
date-error-extra-operand = extra operand '{$operand}'
date-error-write = write error: {$error}
date-error-format-missing-plus = the argument {$arg} lacks a leading '+';
when using an option to specify date(s), any non-option
argument must be a format string beginning with '+'
3 changes: 3 additions & 0 deletions src/uu/date/locales/fr-FR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,6 @@ date-error-setting-date-not-supported-redox = la définition de la date n'est pa
date-error-cannot-set-date = impossible de définir la date
date-error-extra-operand = opérande supplémentaire '{$operand}'
date-error-write = erreur d'écriture: {$error}
date-error-format-missing-plus = l'argument {$arg} ne commence pas par un '+';
lorsque vous utilisez une option pour spécifier une ou plusieurs dates, toute option non spécifiée
L'argument doit être une chaîne de format commençant par '+'
Comment thread
cerdelen marked this conversation as resolved.
Outdated
54 changes: 32 additions & 22 deletions src/uu/date/src/date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,27 @@ fn parse_military_timezone_with_offset(s: &str) -> Option<(i32, DayDelta)> {
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;

let date_source = if let Some(date_os) = matches.get_one::<std::ffi::OsString>(OPT_DATE) {
// Convert OsString to String, handling invalid UTF-8 with GNU-compatible error
let date = date_os.to_str().ok_or_else(|| {
let bytes = date_os.as_encoded_bytes();
let escaped_str = escape_invalid_bytes(bytes);
USimpleError::new(1, format!("invalid date '{escaped_str}'"))
})?;
DateSource::Human(date.into())
} else if let Some(file) = matches.get_one::<String>(OPT_FILE) {
match file.as_ref() {
"-" => DateSource::Stdin,
_ => DateSource::File(file.into()),
}
} else if let Some(file) = matches.get_one::<String>(OPT_REFERENCE) {
DateSource::FileMtime(file.into())
} else if matches.get_flag(OPT_RESOLUTION) {
DateSource::Resolution
} else {
DateSource::Now
};

// Check for extra operands (multiple positional arguments)
if let Some(formats) = matches.get_many::<String>(OPT_FORMAT) {
let format_args: Vec<&String> = formats.collect();
Expand All @@ -298,9 +319,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {

let format = if let Some(form) = matches.get_one::<String>(OPT_FORMAT) {
if !form.starts_with('+') {
// if an optional Format String was found but the user has not provided an input date
// GNU prints an invalid date Error
if !matches!(date_source, DateSource::Human(_)) {
return Err(USimpleError::new(
1,
translate!("date-error-invalid-date", "date" => form),
));
}
// If the user did provide an input date with the --date flag and the Format String is
// not starting with '+' GNU prints the missing '+' error message
return Err(USimpleError::new(
1,
translate!("date-error-invalid-date", "date" => form),
translate!("date-error-format-missing-plus", "arg" => form),
));
}
let form = form[1..].to_string();
Expand Down Expand Up @@ -333,27 +364,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
Zoned::now()
};

let date_source = if let Some(date_os) = matches.get_one::<std::ffi::OsString>(OPT_DATE) {
// Convert OsString to String, handling invalid UTF-8 with GNU-compatible error
let date = date_os.to_str().ok_or_else(|| {
let bytes = date_os.as_encoded_bytes();
let escaped_str = escape_invalid_bytes(bytes);
USimpleError::new(1, format!("invalid date '{escaped_str}'"))
})?;
DateSource::Human(date.into())
} else if let Some(file) = matches.get_one::<String>(OPT_FILE) {
match file.as_ref() {
"-" => DateSource::Stdin,
_ => DateSource::File(file.into()),
}
} else if let Some(file) = matches.get_one::<String>(OPT_REFERENCE) {
DateSource::FileMtime(file.into())
} else if matches.get_flag(OPT_RESOLUTION) {
DateSource::Resolution
} else {
DateSource::Now
};

let set_to = match matches
.get_one::<String>(OPT_SET)
.map(|s| parse_date(s, &now, DebugOptions::new(debug_mode, true)))
Expand Down
12 changes: 12 additions & 0 deletions tests/by-util/test_date.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,18 @@ fn test_extra_operands() {
.stderr_contains("extra operand 'extra'");
}

#[test]
fn test_bad_format_option_missing_leading_plus_after_d_flag() {
let bad_arguments = vec!["q", "a", "test", "%Y-%m-%d"];

for bad_argument in bad_arguments {
new_ucmd!()
.args(&["--date", "1996-01-31", bad_argument])
.fails_with_code(1)
.stderr_contains(format!("the argument {bad_argument} lacks a leading '+';\nwhen using an option to specify date(s), any non-option\nargument must be a format string beginning with '+'"), );
}
}

#[test]
fn test_invalid_long_option() {
new_ucmd!()
Expand Down
Loading