Enhance monetary formatting implementation and improve comments for clarity

This commit is contained in:
Guillaume Gielly
2024-12-23 21:56:45 +01:00
parent 610909bd2b
commit f20c0552dd
2 changed files with 22 additions and 16 deletions
+16 -13
View File
@@ -1,8 +1,7 @@
/// monetary.h implementation for Redox, following the POSIX standard.
/// Following https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/monetary.h.html
///
/// We should provide a strfmon() implementation that formats a monetary value.
/// We should provide a strfmon() implementation that formats a monetary value,
/// according to the current locale (TODO).
use alloc::string::{String, ToString};
use core::{ffi::CStr, ptr, slice, str};
@@ -62,7 +61,7 @@ struct FormatFlags {
}
/// Use our own floating point implementation
/// TODO : use num-traits crate
/// TODO : maybe we can use num-traits crate
#[inline]
fn my_fabs(x: f64) -> f64 {
if x < 0.0 {
@@ -105,32 +104,36 @@ fn my_pow10(n: usize) -> f64 {
result
}
/// TODO : improve grouping implementation
/// Formats a monetary value according to the current locale.
fn apply_grouping(int_str: &str, monetary: &LocaleMonetaryInfo) -> String {
let mut grouped = String::with_capacity(int_str.len() * 2);
let mut count = 0;
let mut group_idx = 0;
let current_grouping = &monetary.mon_grouping;
let separator = monetary.mon_thousands_sep;
// The grouping array can have up to 4 elements, but the last element is always 0
for c in int_str.chars().rev() {
if count > 0 && count % monetary.mon_grouping[group_idx] == 0 {
grouped.push_str(monetary.mon_thousands_sep);
// Move to next grouping size if available
if group_idx + 1 < monetary.mon_grouping.len() {
group_idx += 1;
for c in int_str.chars() {
if count > 0 {
let current_group = current_grouping[group_idx.min(current_grouping.len() - 1)];
if current_group > 0 && count % current_group == 0 {
grouped.push_str(separator);
if group_idx + 1 < current_grouping.len() {
group_idx += 1;
}
}
}
grouped.push(c);
count += 1;
}
// Reverse the string to get the correct order
grouped.chars().rev().collect()
grouped
}
/// Safe handling of large monetary values. Returns None if the value is too large to format
fn format_value_parts(value: f64, frac_digits: usize) -> Option<(String, i64)> {
let abs_value = my_fabs(value);
if abs_value > (i64::MAX as f64) {
// Check if the value is too large to format
return None;
}
+6 -3
View File
@@ -12,9 +12,10 @@ use core::{ffi::CStr, ptr, slice, str};
an optional left precision, an optional right precision, and a conversion specifier.
The conversion specifier can be either 'i' or 'n'. The 'i' specifier formats the monetary value according to the
locale-specific rules, while the 'n' specifier formats the monetary value according to the international rules.
The function returns the number of characters written to the buffer, excluding the null terminator, or -1 if an error occurred.
TODO : better handling error : always return -1 if an error occurred
*/
pub unsafe extern "C" fn strfmon(
s: *mut i8, // char *
@@ -208,7 +209,7 @@ fn format_monetary(
// Reverse the string to get the correct order
let mut result = String::with_capacity(grouped.len() + 20);
// Add the sign
// Add the sign position
let sign_posn = if is_negative {
monetary.n_sign_posn
} else {
@@ -226,7 +227,7 @@ fn format_monetary(
""
};
// Add the sign
// Add the sign at the beginning
if sign_posn == 0 {
result.push('(');
} else if sign_posn == 1 {
@@ -273,6 +274,7 @@ fn format_monetary(
}
if !cs_precedes {
// Add the currency symbol after the value
if sep_by_space {
result.push(' ');
}
@@ -284,6 +286,7 @@ fn format_monetary(
}
if let Some(width) = flags.field_width {
// Check if the field width is specified
if result.len() < width {
let padding = " ".repeat(width - result.len());
if flags.left_justify {