Add simple wrapper for `libc::settext()` to query system locale

finchie
Jun 27, 2024, 6:30 AM
WBI5HFOBBUMDSGKY2RX3YA6N7YDCJEP23JNEJ7PG5VZXHLYIRJRQC

Dependencies

  • [2] HCGVXOF7 Add language negotiation using `fluent-langneg`
  • [3] YNEOCYMG Create `locale-select` crate
  • [4] T6JEWQJ7 Implement converting `PosixLocale` to `icu_locid::Locale`
  • [5] LIH6JCXY Implement POSIX locale category lookup
  • [*] UKFEFT6L Create basic `Output` proc-macro
  • [*] SHNZZSZG Create `cli_macros` shim crate

Change contents

  • edit in Cargo.lock at line 21
    [8.1208]
    [8.1208]
    "locale_select",
  • edit in Cargo.lock at line 206
    [8.3670]
    [8.3670]
    [[package]]
    name = "libc"
    version = "0.2.153"
    source = "registry+https://github.com/rust-lang/crates.io-index"
    checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
  • edit in Cargo.lock at line 225
    [3.5729]
    [3.5729]
    "libc",
  • edit in locale_select/Cargo.toml at line 5
    [3.5518]
    [3.5518]
    [lints]
    workspace = true
  • replacement in locale_select/Cargo.toml at line 12
    [3.5554][3.5554:5555](),[3.5555][3.5555:5580]()
    [lints]
    workspace = true
    [3.5554]
    libc = "0.2.153"
  • replacement in locale_select/src/unix.rs at line 3
    [3.234][2.0:52]()
    use icu_locid::subtags::{self, Language, Variants};
    [3.234]
    [3.276]
    use icu_locid::subtags::{self, Variants};
  • replacement in locale_select/src/unix.rs at line 206
    [2.185][2.185:208]()
    .get_locales()
    [2.185]
    [2.208]
    .get_locales_custom()
  • replacement in locale_select/src/lib.rs at line 4
    [2.604][3.0:11](),[3.5398][3.0:11]()
    mod fetch;
    [2.604]
    [3.5399]
    pub mod fetch;
  • edit in locale_select/src/lib.rs at line 7
    [2.606]
    [2.606]
    // TODO: this can probably be enums, not strings
  • replacement in locale_select/src/lib.rs at line 11
    [2.700][2.700:731]()
    ) -> Vec<LanguageIdentifier> {
    [2.700]
    [2.731]
    ) -> LanguageIdentifier {
  • replacement in locale_select/src/lib.rs at line 13
    [2.799][2.799:877]()
    let requested = unix::get_locales(fetch::unix::LocaleCategory::Messages);
    [2.799]
    [2.877]
    let requested = unix::get_locales(fetch::unix::LocaleCategory::LC_MESSAGES);
  • replacement in locale_select/src/lib.rs at line 21
    [2.1045][2.1045:1162]()
    // TODO: this is wasteful but avoids dealing with lifetimes for now
    supported.into_iter().cloned().collect()
    [2.1045]
    [2.1162]
    // TODO: properly handle this case
    if let [single_locale] = supported[..] {
    // TODO: this is wasteful but avoids dealing with lifetimes for now
    single_locale.to_owned()
    } else {
    todo!("Multiple locales returned, which is not yet handled. Got: {supported:#?}");
    }
  • edit in locale_select/src/fetch/unix.rs at line 2
    [3.78]
    [3.78]
    use std::ffi::CStr;
    const NUL_BYTE: &[u8] = b"\0";
    macro_rules! repr_lc {
    ($($variant:ident),+) => {
    #[derive(Clone, Copy, Debug)]
    #[allow(non_camel_case_types)] // Required for parity with C enum
    pub enum LocaleCategory {
    $($variant,)*
    }
    impl TryFrom<i32> for LocaleCategory {
    type Error = ();
  • replacement in locale_select/src/fetch/unix.rs at line 17
    [3.79][2.1165:1191](),[2.1191][3.106:269](),[3.106][3.106:269]()
    pub enum LocaleCategory {
    CType,
    Collate,
    Messages,
    Monetary,
    Numeric,
    Time,
    Address,
    Identification,
    Measurement,
    Name,
    Paper,
    Telephone,
    }
    [3.79]
    [3.269]
    fn try_from(value: i32) -> Result<Self, Self::Error> {
    match value {
    $(libc::$variant => Ok(Self::$variant),)*
    _ => Err(())
    }
    }
    }
    impl Into<i32> for LocaleCategory {
    fn into(self) -> i32 {
    match self {
    $(Self::$variant => libc::$variant,)*
    }
    }
    }
  • replacement in locale_select/src/fetch/unix.rs at line 34
    [3.270][2.1192:1214](),[2.1214][3.297:875](),[3.297][3.297:875]()
    impl LocaleCategory {
    fn as_str(&self) -> &str {
    match self {
    Self::CType => "LC_CTYPE",
    Self::Collate => "LC_COLLATE",
    Self::Messages => "LC_MESSAGES",
    Self::Monetary => "LC_MONETARY",
    Self::Numeric => "LC_NUMERIC",
    Self::Time => "LC_TIME",
    Self::Address => "LC_ADDRESS",
    Self::Identification => "LC_IDENTIFICATION",
    Self::Measurement => "LC_MEASUREMENT",
    Self::Name => "LC_NAME",
    Self::Paper => "LC_PAPER",
    Self::Telephone => "LC_TELEPHONE",
    [3.270]
    [3.875]
    impl LocaleCategory {
    fn as_str(&self) -> &str {
    match self {
    $(Self::$variant => stringify!($variant),)*
    }
    }
  • edit in locale_select/src/fetch/unix.rs at line 42
    [3.891]
    [3.893]
    }
    repr_lc! {
    LC_ALL,
    LC_CTYPE,
    LC_COLLATE,
    LC_MESSAGES,
    LC_MONETARY,
    LC_NUMERIC,
    LC_TIME,
    LC_ADDRESS,
    LC_IDENTIFICATION,
    LC_MEASUREMENT,
    LC_NAME,
    LC_PAPER,
    LC_TELEPHONE
    }
  • edit in locale_select/src/fetch/unix.rs at line 60
    [3.894]
    [3.921]
    // TODO: handle and document safety invariants
    fn get_locale_libc(category: i32) -> String {
    let empty_cstr = CStr::from_bytes_with_nul(NUL_BYTE).unwrap();
    let locale_string_pointer = unsafe { libc::setlocale(category, empty_cstr.as_ptr()) };
    let locale_c_str = unsafe { CStr::from_ptr(locale_string_pointer) };
    locale_c_str.to_str().unwrap().to_string()
    }
    impl LocaleCategory {
  • replacement in locale_select/src/fetch/unix.rs at line 78
    [3.1247][2.1215:1262]()
    pub fn get_locales(&self) -> Vec<String> {
    [3.1247]
    [2.1262]
    pub fn get_locales_custom(&self) -> Vec<String> {
  • edit in locale_select/src/fetch/unix.rs at line 94
    [2.1577]
    [3.1603]
    }
    pub fn get_locales_libc(self) -> Vec<String> {
    let global_locale = get_locale_libc(libc::LC_ALL);
    let locale_for_category = get_locale_libc(self.into());
    vec![global_locale, locale_for_category]