Skip to content

Commit b439534

Browse files
cerdelensylvestre
andauthored
date: Fix Error message missing '+' for format string after valid d flag (#10982)
* date: Fix Errors message missing '+' for format string after valid d flag * Update src/uu/date/locales/fr-FR.ftl Co-authored-by: Sylvestre Ledru <[email protected]> --------- Co-authored-by: Sylvestre Ledru <[email protected]>
1 parent ed06c14 commit b439534

File tree

4 files changed

+50
-22
lines changed

4 files changed

+50
-22
lines changed

src/uu/date/locales/en-US.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,6 @@ date-error-setting-date-not-supported-redox = setting the date is not supported
106106
date-error-cannot-set-date = cannot set date
107107
date-error-extra-operand = extra operand '{$operand}'
108108
date-error-write = write error: {$error}
109+
date-error-format-missing-plus = the argument {$arg} lacks a leading '+';
110+
when using an option to specify date(s), any non-option
111+
argument must be a format string beginning with '+'

src/uu/date/locales/fr-FR.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,6 @@ date-error-setting-date-not-supported-redox = la définition de la date n'est pa
101101
date-error-cannot-set-date = impossible de définir la date
102102
date-error-extra-operand = opérande supplémentaire '{$operand}'
103103
date-error-write = erreur d'écriture: {$error}
104+
date-error-format-missing-plus = l'argument {$arg} ne commence pas par un signe '+';
105+
lorsqu'une option est utilisée pour spécifier une ou plusieurs dates, tout argument autre
106+
qu'une option doit être une chaîne de format commençant par un signe '+'.

src/uu/date/src/date.rs

Lines changed: 32 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,27 @@ fn parse_military_timezone_with_offset(s: &str) -> Option<(i32, DayDelta)> {
285285
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
286286
let matches = uucore::clap_localization::handle_clap_result(uu_app(), args)?;
287287

288+
let date_source = if let Some(date_os) = matches.get_one::<std::ffi::OsString>(OPT_DATE) {
289+
// Convert OsString to String, handling invalid UTF-8 with GNU-compatible error
290+
let date = date_os.to_str().ok_or_else(|| {
291+
let bytes = date_os.as_encoded_bytes();
292+
let escaped_str = escape_invalid_bytes(bytes);
293+
USimpleError::new(1, format!("invalid date '{escaped_str}'"))
294+
})?;
295+
DateSource::Human(date.into())
296+
} else if let Some(file) = matches.get_one::<String>(OPT_FILE) {
297+
match file.as_ref() {
298+
"-" => DateSource::Stdin,
299+
_ => DateSource::File(file.into()),
300+
}
301+
} else if let Some(file) = matches.get_one::<String>(OPT_REFERENCE) {
302+
DateSource::FileMtime(file.into())
303+
} else if matches.get_flag(OPT_RESOLUTION) {
304+
DateSource::Resolution
305+
} else {
306+
DateSource::Now
307+
};
308+
288309
// Check for extra operands (multiple positional arguments)
289310
if let Some(formats) = matches.get_many::<String>(OPT_FORMAT) {
290311
let format_args: Vec<&String> = formats.collect();
@@ -298,9 +319,19 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
298319

299320
let format = if let Some(form) = matches.get_one::<String>(OPT_FORMAT) {
300321
if !form.starts_with('+') {
322+
// if an optional Format String was found but the user has not provided an input date
323+
// GNU prints an invalid date Error
324+
if !matches!(date_source, DateSource::Human(_)) {
325+
return Err(USimpleError::new(
326+
1,
327+
translate!("date-error-invalid-date", "date" => form),
328+
));
329+
}
330+
// If the user did provide an input date with the --date flag and the Format String is
331+
// not starting with '+' GNU prints the missing '+' error message
301332
return Err(USimpleError::new(
302333
1,
303-
translate!("date-error-invalid-date", "date" => form),
334+
translate!("date-error-format-missing-plus", "arg" => form),
304335
));
305336
}
306337
let form = form[1..].to_string();
@@ -333,27 +364,6 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
333364
Zoned::now()
334365
};
335366

336-
let date_source = if let Some(date_os) = matches.get_one::<std::ffi::OsString>(OPT_DATE) {
337-
// Convert OsString to String, handling invalid UTF-8 with GNU-compatible error
338-
let date = date_os.to_str().ok_or_else(|| {
339-
let bytes = date_os.as_encoded_bytes();
340-
let escaped_str = escape_invalid_bytes(bytes);
341-
USimpleError::new(1, format!("invalid date '{escaped_str}'"))
342-
})?;
343-
DateSource::Human(date.into())
344-
} else if let Some(file) = matches.get_one::<String>(OPT_FILE) {
345-
match file.as_ref() {
346-
"-" => DateSource::Stdin,
347-
_ => DateSource::File(file.into()),
348-
}
349-
} else if let Some(file) = matches.get_one::<String>(OPT_REFERENCE) {
350-
DateSource::FileMtime(file.into())
351-
} else if matches.get_flag(OPT_RESOLUTION) {
352-
DateSource::Resolution
353-
} else {
354-
DateSource::Now
355-
};
356-
357367
let set_to = match matches
358368
.get_one::<String>(OPT_SET)
359369
.map(|s| parse_date(s, &now, DebugOptions::new(debug_mode, true)))

tests/by-util/test_date.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,18 @@ fn test_extra_operands() {
3535
.stderr_contains("extra operand 'extra'");
3636
}
3737

38+
#[test]
39+
fn test_bad_format_option_missing_leading_plus_after_d_flag() {
40+
let bad_arguments = vec!["q", "a", "test", "%Y-%m-%d"];
41+
42+
for bad_argument in bad_arguments {
43+
new_ucmd!()
44+
.args(&["--date", "1996-01-31", bad_argument])
45+
.fails_with_code(1)
46+
.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 '+'"), );
47+
}
48+
}
49+
3850
#[test]
3951
fn test_invalid_long_option() {
4052
new_ucmd!()

0 commit comments

Comments
 (0)