Skip to content

Commit 5305310

Browse files
committed
locale.rs: move more code outside of the unsafe block
1 parent 16f7350 commit 5305310

File tree

1 file changed

+56
-45
lines changed

1 file changed

+56
-45
lines changed

src/uu/date/src/locale.rs

Lines changed: 56 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -34,70 +34,81 @@ cfg_langinfo! {
3434
/// Cached result of locale time format detection
3535
static TIME_FORMAT_CACHE: OnceLock<bool> = OnceLock::new();
3636

37-
/// Internal function that performs the actual locale detection
38-
fn detect_12_hour_format() -> bool {
37+
/// Safe wrapper around libc setlocale
38+
fn set_time_locale() {
3939
unsafe {
40-
// Set locale from environment variables (empty string = use LC_TIME/LANG env vars)
41-
libc::setlocale(libc::LC_TIME, c"".as_ptr());
40+
nix::libc::setlocale(nix::libc::LC_TIME, c"".as_ptr());
41+
}
42+
}
4243

43-
// Get the date/time format string from locale
44-
let d_t_fmt_ptr = libc::nl_langinfo(libc::D_T_FMT);
45-
if d_t_fmt_ptr.is_null() {
46-
return false;
44+
/// Safe wrapper around libc nl_langinfo that returns Option<String>
45+
fn get_locale_info(item: nix::libc::nl_item) -> Option<String> {
46+
unsafe {
47+
let ptr = nix::libc::nl_langinfo(item);
48+
if ptr.is_null() {
49+
None
50+
} else {
51+
CStr::from_ptr(ptr).to_str().ok().map(String::from)
52+
}
4753
}
54+
}
4855

49-
let Ok(format) = CStr::from_ptr(d_t_fmt_ptr).to_str() else {
50-
return false;
51-
};
56+
/// Internal function that performs the actual locale detection
57+
fn detect_12_hour_format() -> bool {
58+
// Helper function to check for 12-hour format indicators
59+
fn has_12_hour_indicators(format_str: &str) -> bool {
60+
format_str.contains("%I") || format_str.contains("%l") || format_str.contains("%r")
61+
}
5262

53-
// Check for 12-hour indicators first (higher priority)
54-
// %I = hour (01-12), %l = hour (1-12) space-padded, %r = 12-hour time with AM/PM
55-
if format.contains("%I") || format.contains("%l") || format.contains("%r") {
56-
return true;
63+
// Helper function to check for 24-hour format indicators
64+
fn has_24_hour_indicators(format_str: &str) -> bool {
65+
format_str.contains("%H")
66+
|| format_str.contains("%k")
67+
|| format_str.contains("%R")
68+
|| format_str.contains("%T")
5769
}
5870

59-
// If we find 24-hour indicators, it's definitely not 12-hour
60-
// %H = hour (00-23), %k = hour (0-23) space-padded, %R = %H:%M, %T = %H:%M:%S
61-
if format.contains("%H")
62-
|| format.contains("%k")
63-
|| format.contains("%R")
64-
|| format.contains("%T")
65-
{
66-
return false;
71+
// Set locale from environment variables (empty string = use LC_TIME/LANG env vars)
72+
set_time_locale();
73+
74+
// Get locale format strings using safe wrappers
75+
let d_t_fmt = get_locale_info(nix::libc::D_T_FMT);
76+
let t_fmt_opt = get_locale_info(nix::libc::T_FMT);
77+
let t_fmt_ampm_opt = get_locale_info(nix::libc::T_FMT_AMPM);
78+
79+
// Check D_T_FMT first
80+
if let Some(ref format) = d_t_fmt {
81+
// Check for 12-hour indicators first (higher priority)
82+
if has_12_hour_indicators(format) {
83+
return true;
84+
}
85+
86+
// If we find 24-hour indicators, it's definitely not 12-hour
87+
if has_24_hour_indicators(format) {
88+
return false;
89+
}
6790
}
6891

6992
// Also check the time-only format as a fallback
70-
let t_fmt_ptr = libc::nl_langinfo(libc::T_FMT);
71-
let mut time_fmt_opt = None;
72-
if !t_fmt_ptr.is_null() {
73-
if let Ok(time_format) = CStr::from_ptr(t_fmt_ptr).to_str() {
74-
time_fmt_opt = Some(time_format);
75-
if time_format.contains("%I")
76-
|| time_format.contains("%l")
77-
|| time_format.contains("%r")
78-
{
79-
return true;
80-
}
93+
if let Some(ref time_format) = t_fmt_opt {
94+
if has_12_hour_indicators(time_format) {
95+
return true;
8196
}
8297
}
8398

8499
// Check if there's a specific 12-hour format defined
85-
let t_fmt_ampm_ptr = libc::nl_langinfo(libc::T_FMT_AMPM);
86-
if !t_fmt_ampm_ptr.is_null() {
87-
if let Ok(ampm_format) = CStr::from_ptr(t_fmt_ampm_ptr).to_str() {
88-
// If T_FMT_AMPM is non-empty and different from T_FMT, locale supports 12-hour
89-
if !ampm_format.is_empty() {
90-
if let Some(time_format) = time_fmt_opt {
91-
if ampm_format != time_format {
92-
return true;
93-
}
94-
} else {
100+
if let Some(ref ampm_format) = t_fmt_ampm_opt {
101+
// If T_FMT_AMPM is non-empty and different from T_FMT, locale supports 12-hour
102+
if !ampm_format.is_empty() {
103+
if let Some(ref time_format) = t_fmt_opt {
104+
if ampm_format != time_format {
95105
return true;
96106
}
107+
} else {
108+
return true;
97109
}
98110
}
99111
}
100-
}
101112

102113
// Default to 24-hour format if we can't determine
103114
false

0 commit comments

Comments
 (0)