Skip to content

Commit c81e9d0

Browse files
mattsu2020sylvestre
authored andcommitted
fix: improve error handling for format modifier width parsing
- Changed FormatError::FieldWidthTooLarge to store width as String instead of usize - Updated error message generation to use FluentArgs for proper localization - Fixed width parsing to return FormatError instead of panicking on parse failure - Updated error message formatting to use get_message_with_args for consistency - Fixed test assertions to compare width as String instead of usize
1 parent 12b30cb commit c81e9d0

2 files changed

Lines changed: 34 additions & 18 deletions

File tree

src/uu/date/src/format_modifiers.rs

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -33,35 +33,37 @@
3333
//! - `%^B`: Month name in uppercase (JUNE)
3434
//! - `%+4C`: Century with sign, padded to 4 characters (+019)
3535
36+
use fluent::FluentArgs;
3637
use jiff::Zoned;
3738
use jiff::fmt::strtime::{BrokenDownTime, Config, PosixCustom};
3839
use regex::Regex;
3940
use std::fmt;
4041
use std::sync::OnceLock;
41-
use uucore::translate;
42+
use uucore::locale::get_message_with_args;
4243

4344
/// Error type for format modifier operations
4445
#[derive(Debug)]
4546
pub enum FormatError {
4647
/// Error from the underlying jiff library
4748
JiffError(jiff::Error),
4849
/// Field width calculation overflowed or required allocation failed
49-
FieldWidthTooLarge { width: usize, specifier: String },
50+
FieldWidthTooLarge { width: String, specifier: String },
5051
}
5152

5253
impl fmt::Display for FormatError {
5354
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5455
match self {
5556
Self::JiffError(e) => write!(f, "{e}"),
56-
Self::FieldWidthTooLarge { width, specifier } => write!(
57-
f,
58-
"{}",
59-
translate!(
60-
"date-error-format-modifier-width-too-large",
61-
"width" => width,
62-
"specifier" => specifier
57+
Self::FieldWidthTooLarge { width, specifier } => {
58+
let mut args = FluentArgs::new();
59+
args.set("width", width.clone());
60+
args.set("specifier", specifier.clone());
61+
write!(
62+
f,
63+
"{}",
64+
get_message_with_args("date-error-format-modifier-width-too-large", args)
6365
)
64-
),
66+
}
6567
}
6668
}
6769
}
@@ -153,7 +155,16 @@ fn format_with_modifiers(
153155
// Check if this specifier has modifiers
154156
if !flags.is_empty() || !width_str.is_empty() {
155157
// Apply modifiers to the formatted value
156-
let width: usize = width_str.parse().unwrap_or(0);
158+
let width = if width_str.is_empty() {
159+
0
160+
} else {
161+
width_str
162+
.parse()
163+
.map_err(|_| FormatError::FieldWidthTooLarge {
164+
width: width_str.to_string(),
165+
specifier: spec.to_string(),
166+
})?
167+
};
157168
let explicit_width = !width_str.is_empty();
158169
let modified = apply_modifiers(&formatted, flags, width, spec, explicit_width)?;
159170
result.push_str(&modified);
@@ -397,15 +408,15 @@ fn apply_modifiers(
397408
let rest = &result[1..];
398409
let target_len = result.len().checked_add(padding).ok_or_else(|| {
399410
FormatError::FieldWidthTooLarge {
400-
width,
411+
width: width.to_string(),
401412
specifier: specifier.to_string(),
402413
}
403414
})?;
404415
let mut padded = String::new();
405416
padded
406417
.try_reserve(target_len)
407418
.map_err(|_| FormatError::FieldWidthTooLarge {
408-
width,
419+
width: width.to_string(),
409420
specifier: specifier.to_string(),
410421
})?;
411422
padded.push(sign);
@@ -416,15 +427,15 @@ fn apply_modifiers(
416427
// Default: pad on the left (e.g., " -22" or " 1999")
417428
let target_len = result.len().checked_add(padding).ok_or_else(|| {
418429
FormatError::FieldWidthTooLarge {
419-
width,
430+
width: width.to_string(),
420431
specifier: specifier.to_string(),
421432
}
422433
})?;
423434
let mut padded = String::new();
424435
padded
425436
.try_reserve(target_len)
426437
.map_err(|_| FormatError::FieldWidthTooLarge {
427-
width,
438+
width: width.to_string(),
428439
specifier: specifier.to_string(),
429440
})?;
430441
padded.extend(std::iter::repeat_n(pad_char, padding));
@@ -789,7 +800,7 @@ mod tests {
789800
assert!(matches!(
790801
err,
791802
FormatError::FieldWidthTooLarge { width, specifier }
792-
if width == usize::MAX && specifier == "c"
803+
if width == usize::MAX.to_string() && specifier == "c"
793804
));
794805
}
795806
}

tests/by-util/test_date.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2511,8 +2511,13 @@ fn test_date_format_modifier_edge_cases() {
25112511
fn test_date_format_modifier_huge_width_fails_without_abort() {
25122512
// GNU date also exits with failure for extremely large width.
25132513
// Assert exit code only to avoid coupling to implementation-specific error text.
2514-
let format = format!("+%{}c", usize::MAX);
2515-
new_ucmd!().arg(&format).fails().code_is(1);
2514+
let formats = [
2515+
format!("+%{}c", usize::MAX),
2516+
"+%184467440737095516160c".into(),
2517+
];
2518+
for format in formats {
2519+
new_ucmd!().arg(&format).fails().code_is(1);
2520+
}
25162521
}
25172522

25182523
// Tests for --debug flag

0 commit comments

Comments
 (0)