Get locale_charset() working.
authorBen Pfaff <blp@cs.stanford.edu>
Wed, 1 Nov 2023 14:24:32 +0000 (07:24 -0700)
committerBen Pfaff <blp@cs.stanford.edu>
Wed, 1 Nov 2023 14:24:32 +0000 (07:24 -0700)
rust/src/locale_charset.rs
rust/src/main.rs

index fdcb685f188983e0bf44726bc1c9286bcf948c07..e967c1d46de35ee4689ebb15727ae4fb72651482 100644 (file)
@@ -220,23 +220,37 @@ fn map_aliases(s: &str) -> &'static str {
 
 #[cfg(unix)]
 mod inner {
-    use std::ffi::CStr;
+    use std::{
+        ffi::{c_int, CStr, CString},
+        ptr::null,
+    };
+
+    use libc::{self, nl_langinfo, setlocale, CODESET, LC_CTYPE};
 
-    use libc::{self, nl_langinfo, CODESET};
+    unsafe fn string_from_pointer(s: *const i8) -> Option<String> {
+        if s.is_null() {
+            None
+        } else {
+            Some(CStr::from_ptr(s).to_string_lossy().into())
+        }
+    }
 
-    fn codeset() -> Option<String> {
+    fn set_locale(category: c_int, locale: Option<&str>) -> Option<String> {
         unsafe {
-            let codeset = nl_langinfo(CODESET);
-            if codeset.is_null() {
-                None
-            } else {
-                Some(CStr::from_ptr(codeset).to_string_lossy().into())
-            }
+            let locale = locale.map(|s| CString::new(s).unwrap());
+            let locale_ptr = locale.as_ref().map_or(null(), |s| s.as_ptr());
+            string_from_pointer(setlocale(category, locale_ptr))
         }
     }
 
     pub fn locale_charset() -> Option<String> {
-        codeset()
+        unsafe {
+            let saved_locale = set_locale(LC_CTYPE, None);
+            set_locale(LC_CTYPE, Some(""));
+            let codeset = string_from_pointer(nl_langinfo(CODESET));
+            set_locale(LC_CTYPE, saved_locale.as_ref().map(|x| x.as_str()));
+            codeset
+        }
     }
 }
 
@@ -283,7 +297,8 @@ mod inner {
 
 pub fn locale_charset() -> &'static str {
     lazy_static! {
-        static ref LOCALE_CHARSET: &'static str = map_aliases(&inner::locale_charset().unwrap_or(String::from("UTF-8")));
+        static ref LOCALE_CHARSET: &'static str =
+            map_aliases(&inner::locale_charset().unwrap_or(String::from("UTF-8")));
     }
     &LOCALE_CHARSET
 }
index 6024b67f2dea68c9395e1b20436d94a7fedc0ac4..8085957daad73d8b57df657ce3779855438d8b0a 100644 (file)
@@ -16,7 +16,7 @@
 
 use anyhow::Result;
 use clap::Parser;
-use pspp::raw::{Reader, Record};
+use pspp::{raw::{Reader, Record}, locale_charset::locale_charset};
 use std::fs::File;
 use std::io::BufReader;
 use std::path::{Path, PathBuf};
@@ -36,6 +36,7 @@ struct Args {
 }
 
 fn main() -> Result<()> {
+    println!("locale_charset={}", locale_charset());
     let Args { max_cases, files } = Args::parse();
 
     for file in files {