Skip to content

Commit

Permalink
Add validation/fixes for time formatting strings (#5)
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker authored Jul 4, 2023
1 parent 1160795 commit eccd659
Show file tree
Hide file tree
Showing 3 changed files with 79 additions and 3 deletions.
77 changes: 76 additions & 1 deletion generate-api/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
pub mod generator;
pub mod parser;

use crate::parser::{Object, Value};
use anyhow::{bail, Result};
use cargo_metadata::MetadataCommand;
use sha2::{Digest, Sha256};
Expand Down Expand Up @@ -32,7 +33,8 @@ fn main() -> Result<()> {
let path = entry.path();
if let Ok(input) = std::fs::read_to_string(&path) {
eprintln!("{}", path.display());
let objects = parser::parse(&input)?;
let mut objects = parser::parse(&input)?;
validate_and_fix(&mut objects);
locales.insert(lang.to_string(), objects);
}
}
Expand Down Expand Up @@ -66,3 +68,76 @@ fn main() -> Result<()> {

Ok(())
}

fn validate_and_fix(objects: &mut Vec<Object>) {
validate_and_fix_t_fmt_ampm(objects);
validate_and_fix_d_t_fmt(objects);
}

/// Add a `T_FMT_AMPM` item if it is missing (happens for 3 locales).
///
/// If the locale has non-empty values for `AM_PM` we assume the correct string to be the same as
/// for POSIX: `%l:%M:%S %p`.
/// If the locale has empty values for `AM_PM` we set `T_FMT_AMPM` to an empty value, similar to
/// other locales that don't have a 12-hour clock format.
fn validate_and_fix_t_fmt_ampm(objects: &mut Vec<Object>) {
for object in objects.iter_mut() {
if object.name != "LC_TIME" {
continue;
}
let mut found_t_fmt_ampm = false;
let mut am_pm_empty = false;
for (key, value) in object.values.iter() {
match (key.as_str(), value.as_slice()) {
("t_fmt_ampm" | "copy" | "insert", _) => found_t_fmt_ampm = true,
("am_pm", &[Value::String(ref am), Value::String(ref pm)]) => {
am_pm_empty = am.is_empty() && pm.is_empty()
}
_ => {}
}
}
if !found_t_fmt_ampm {
let value = match am_pm_empty {
true => vec![Value::String(String::new())],
false => vec![Value::String("%l:%M:%S %p".to_string())],
};
object.values.push(("t_fmt_ampm".to_string(), value));
}
}
}

/// In some locales `D_T_FMT` refers to other items:
/// to `D_FMT` with `%x`, `T_FMT` with `%X`, and/or `T_FMT_AMPM` with `%r`.
/// Inlining these strings simplifies the implementation of the strftime parser in chrono.
fn validate_and_fix_d_t_fmt(objects: &mut Vec<Object>) {
for object in objects.iter_mut() {
if object.name != "LC_TIME" {
continue;
}
let mut d_fmt = String::new();
let mut t_fmt = String::new();
let mut t_fmt_ampm = String::new();
for (key, value) in object.values.iter() {
match (key.as_str(), value.as_slice()) {
("d_fmt", &[Value::String(ref value)]) => d_fmt = value.clone(),
("t_fmt", &[Value::String(ref value)]) => t_fmt = value.clone(),
("t_fmt_ampm", &[Value::String(ref value)]) => t_fmt_ampm = value.clone(),
_ => {}
}
}
for (key, ref mut value) in object.values.iter_mut() {
match (key.as_str(), value) {
("d_t_fmt", vec) => {
if let Value::String(ref val) = vec[0] {
let d_t_fmt = val
.replace("%x", &d_fmt)
.replace("%X", &t_fmt)
.replace("%r", &t_fmt_ampm);
vec[0] = Value::String(d_t_fmt);
}
}
_ => {}
}
}
}
}
1 change: 1 addition & 0 deletions generate-api/src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ fn parse_str<'a, E: ParseError<&'a str>>(
map_parser(
alt((
take_while1(|c| c != escape_char && c != '"'),
map(preceded(char(escape_char), char('\n')), |_| ""),
preceded(char(escape_char), take(1_usize)),
)),
unescape_unicode,
Expand Down
4 changes: 2 additions & 2 deletions src/lib.rs
Git LFS file not shown

0 comments on commit eccd659

Please sign in to comment.