From 3da5375bc096cf172d0d91fa47f6fc0597ca0862 Mon Sep 17 00:00:00 2001 From: Serial <69764315+Serial-ATA@users.noreply.github.com> Date: Sun, 29 Dec 2024 17:32:29 -0500 Subject: [PATCH] wip --- Cargo.toml | 1 + platform/Cargo.toml | 1 + platform/src/arch/mod.rs | 24 +- platform/src/arch/x86/features.rs | 1 + platform/src/arch/x86/ordering.rs | 28 +- platform/src/family/mod.rs | 28 +- platform/src/family/properties.rs | 197 ++++---- platform/src/family/unix/linux/properties.rs | 459 ++++++++++--------- platform/src/family/unix/macos/properties.rs | 12 +- platform/src/family/unix/mod.rs | 20 +- platform/src/family/unix/properties.rs | 10 +- platform/src/family/windows/properties.rs | 35 +- platform/src/lib.rs | 1 - platform/src/macros.rs | 40 -- 14 files changed, 417 insertions(+), 440 deletions(-) delete mode 100644 platform/src/macros.rs diff --git a/Cargo.toml b/Cargo.toml index 34827a8..547f9af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ symbols = { path = "symbols" } byteorder = "1.5.0" byte-slice-cast = "1.2.2" cesu8 = "1.1.0" +cfg-if = "1.0.0" const_format = "0.2.33" libc = "0.2" libloading = "0.8.5" diff --git a/platform/Cargo.toml b/platform/Cargo.toml index cad783d..acd6df4 100644 --- a/platform/Cargo.toml +++ b/platform/Cargo.toml @@ -6,6 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +cfg-if.workspace = true libc.workspace = true [target.'cfg(target_family = "windows")'.dependencies] diff --git a/platform/src/arch/mod.rs b/platform/src/arch/mod.rs index dbfd024..2e2f30a 100644 --- a/platform/src/arch/mod.rs +++ b/platform/src/arch/mod.rs @@ -1,17 +1,11 @@ -use crate::macros::match_cfg_meta; - -match_cfg_meta! { - match cfg(target_arch) { - "x86" => { - mod x86; - pub use x86::*; - }, - "x86_64" => { - mod x86; - pub use x86::*; - }, - _ => { - compile_error!("target architecture is not supported!"); - } +cfg_if::cfg_if! { + if #[cfg(target_arch = "x86")] { + mod x86; + pub use x86::*; + } else if #[cfg(target_arch = "x86_64")] { + mod x86; + pub use x86::*; + } else { + compile_error!("target architecture is not supported!"); } } diff --git a/platform/src/arch/x86/features.rs b/platform/src/arch/x86/features.rs index e69de29..8b13789 100644 --- a/platform/src/arch/x86/features.rs +++ b/platform/src/arch/x86/features.rs @@ -0,0 +1 @@ + diff --git a/platform/src/arch/x86/ordering.rs b/platform/src/arch/x86/ordering.rs index 799d2f8..3d63704 100644 --- a/platform/src/arch/x86/ordering.rs +++ b/platform/src/arch/x86/ordering.rs @@ -1,5 +1,3 @@ -#![cfg_attr(rustfmt, rustfmt_skip)] - #[inline(always)] unsafe fn compiler_barrier() { // Create a compiler barrier to prevent instruction reordering @@ -7,22 +5,34 @@ unsafe fn compiler_barrier() { } #[inline(always)] -pub fn loadload() { unsafe { compiler_barrier() } } +pub fn loadload() { + unsafe { compiler_barrier() } +} #[inline(always)] -pub fn storestore() { unsafe { compiler_barrier() } } +pub fn storestore() { + unsafe { compiler_barrier() } +} #[inline(always)] -pub fn loadstore() { unsafe { compiler_barrier() } } +pub fn loadstore() { + unsafe { compiler_barrier() } +} #[inline(always)] -pub fn storeload() { fence() } +pub fn storeload() { + fence() +} #[inline(always)] -pub fn acquire() { unsafe { compiler_barrier() } } +pub fn acquire() { + unsafe { compiler_barrier() } +} #[inline(always)] -pub fn release() { unsafe { compiler_barrier() } } +pub fn release() { + unsafe { compiler_barrier() } +} #[cfg(target_arch = "x86")] #[inline(always)] @@ -48,7 +58,7 @@ pub fn fence() { options(nomem, preserves_flags, att_syntax) ) } - + unsafe { compiler_barrier() } } diff --git a/platform/src/family/mod.rs b/platform/src/family/mod.rs index b383903..8c7702e 100644 --- a/platform/src/family/mod.rs +++ b/platform/src/family/mod.rs @@ -3,24 +3,18 @@ pub use signals::*; pub mod properties; -use crate::macros::match_cfg_meta; - // `target_family` specific exports -match_cfg_meta! { - match cfg(target_family) { - "unix" => { - mod unix; - pub use unix::*; - pub use unix::signals::*; - }, - "windows" => { - mod windows; - pub use windows::*; - pub use windows::signals::*; - }, - _ => { - compile_error!("target family is not supported!"); - } +cfg_if::cfg_if! { + if #[cfg(unix)] { + mod unix; + pub use unix::*; + pub use unix::signals::*; + } else if #[cfg(windows)] { + mod windows; + pub use windows::*; + pub use windows::signals::*; + } else { + compile_error!("target family is not supported!"); } } diff --git a/platform/src/family/properties.rs b/platform/src/family/properties.rs index f687388..1448fd2 100644 --- a/platform/src/family/properties.rs +++ b/platform/src/family/properties.rs @@ -1,128 +1,131 @@ -#![cfg_attr(rustfmt, rustfmt_skip)] +use std::fmt::{Display, Formatter}; // Properties shared between all `target_family`s -pub const CPU_ENDIAN: &str = if cfg!(target_endian = "big") { "big" } else { "little" }; +pub const CPU_ENDIAN: &str = if cfg!(target_endian = "big") { + "big" +} else { + "little" +}; // TODO: Document // TODO: Probably make all fields `Option`, to avoid setting empty values at runtime #[allow(non_snake_case)] pub struct PropertySet { - pub display_country: String, - pub display_language: String, - pub display_script: String, - pub display_variant: String, - pub file_encoding: String, - pub file_separator: String, - pub format_country: String, - pub format_language: String, - pub format_script: String, - pub format_variant: String, - pub ftp_nonProxyHosts: Option, - pub ftp_proxyHost: Option, - pub ftp_proxyPort: Option, - pub http_nonProxyHosts: Option, - pub http_proxyHost: Option, - pub http_proxyPort: Option, - pub https_proxyHost: Option, - pub https_proxyPort: Option, - pub java_io_tmpdir: String, - pub line_separator: String, - pub os_arch: String, - pub os_name: String, - pub os_version: String, - pub path_separator: String, - pub socksNonProxyHosts: Option, - pub socksProxyHost: Option, - pub socksProxyPort: Option, - pub stderr_encoding: Option, - pub stdout_encoding: Option, - pub sun_arch_abi: Option, - pub sun_arch_data_model: String, - pub sun_cpu_endian: String, - pub sun_cpu_isalist: Option, - pub sun_io_unicode_encoding: String, - pub sun_jnu_encoding: String, - pub sun_os_patch_level: String, - pub user_dir: String, - pub user_home: String, - pub user_name: String, + pub display_country: String, + pub display_language: String, + pub display_script: String, + pub display_variant: String, + pub file_encoding: String, + pub file_separator: String, + pub format_country: String, + pub format_language: String, + pub format_script: String, + pub format_variant: String, + pub ftp_nonProxyHosts: Option, + pub ftp_proxyHost: Option, + pub ftp_proxyPort: Option, + pub http_nonProxyHosts: Option, + pub http_proxyHost: Option, + pub http_proxyPort: Option, + pub https_proxyHost: Option, + pub https_proxyPort: Option, + pub java_io_tmpdir: String, + pub line_separator: String, + pub os_arch: String, + pub os_name: String, + pub os_version: String, + pub path_separator: String, + pub socksNonProxyHosts: Option, + pub socksProxyHost: Option, + pub socksProxyPort: Option, + pub stderr_encoding: Option, + pub stdout_encoding: Option, + pub sun_arch_abi: Option, + pub sun_arch_data_model: String, + pub sun_cpu_endian: String, + pub sun_cpu_isalist: Option, + pub sun_io_unicode_encoding: String, + pub sun_jnu_encoding: String, + pub sun_os_patch_level: String, + pub user_dir: String, + pub user_home: String, + pub user_name: String, } impl PropertySet { - pub fn fill(&mut self) -> Result<(), Error> { - fill_properties_impl(self) - } + pub fn fill(&mut self) -> Result<(), Error> { + fill_properties_impl(self) + } } impl Default for PropertySet { - fn default() -> Self { - PropertySet { - // Set the constant properties, exported below - file_separator: FILE_SEPARATOR.into(), - line_separator: LINE_SEPARATOR.into(), - os_arch: OS_ARCH.into(), - path_separator: PATH_SEPARATOR.into(), - sun_cpu_endian: CPU_ENDIAN.into(), - sun_io_unicode_encoding: UNICODE_ENCODING.into(), + fn default() -> Self { + PropertySet { + // Set the constant properties, exported below + file_separator: FILE_SEPARATOR.into(), + line_separator: LINE_SEPARATOR.into(), + os_arch: OS_ARCH.into(), + path_separator: PATH_SEPARATOR.into(), + sun_cpu_endian: CPU_ENDIAN.into(), + sun_io_unicode_encoding: UNICODE_ENCODING.into(), - // Others will need to be filled by their platform-specific implementations - display_country: String::new(), - display_language: String::new(), - display_script: String::new(), - display_variant: String::new(), - file_encoding: String::new(), - format_country: String::new(), - format_language: String::new(), - format_script: String::new(), - format_variant: String::new(), - ftp_nonProxyHosts: None, - ftp_proxyHost: None, - ftp_proxyPort: None, - http_nonProxyHosts: None, - http_proxyHost: None, - http_proxyPort: None, - https_proxyHost: None, - https_proxyPort: None, - java_io_tmpdir: String::new(), - os_name: String::new(), - os_version: String::new(), - socksNonProxyHosts: None, - socksProxyHost: None, - socksProxyPort: None, - stderr_encoding: None, - stdout_encoding: None, - sun_arch_abi: None, - sun_arch_data_model: String::new(), - sun_cpu_isalist: None, - sun_jnu_encoding: String::new(), - sun_os_patch_level: String::new(), - user_dir: String::new(), - user_home: String::new(), - user_name: String::new(), - } - } + // Others will need to be filled by their platform-specific implementations + display_country: String::new(), + display_language: String::new(), + display_script: String::new(), + display_variant: String::new(), + file_encoding: String::new(), + format_country: String::new(), + format_language: String::new(), + format_script: String::new(), + format_variant: String::new(), + ftp_nonProxyHosts: None, + ftp_proxyHost: None, + ftp_proxyPort: None, + http_nonProxyHosts: None, + http_proxyHost: None, + http_proxyPort: None, + https_proxyHost: None, + https_proxyPort: None, + java_io_tmpdir: String::new(), + os_name: String::new(), + os_version: String::new(), + socksNonProxyHosts: None, + socksProxyHost: None, + socksProxyPort: None, + stderr_encoding: None, + stdout_encoding: None, + sun_arch_abi: None, + sun_arch_data_model: String::new(), + sun_cpu_isalist: None, + sun_jnu_encoding: String::new(), + sun_os_patch_level: String::new(), + user_dir: String::new(), + user_home: String::new(), + user_name: String::new(), + } + } } #[derive(Debug)] pub enum Error { - WorkingDir, + WorkingDir, } impl Display for Error { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - Error::WorkingDir => f.write_str("Could not determine currenting working directory") - } - } + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Error::WorkingDir => f.write_str("Could not determine currenting working directory"), + } + } } impl core::error::Error for Error {} // Export family specific properties -use std::fmt::{Display, Formatter}; #[cfg(target_family = "unix")] pub use super::unix::properties::*; #[cfg(target_family = "windows")] -pub use super::windows::properties::*; \ No newline at end of file +pub use super::windows::properties::*; diff --git a/platform/src/family/unix/linux/properties.rs b/platform/src/family/unix/linux/properties.rs index 8323a5c..259705c 100644 --- a/platform/src/family/unix/linux/properties.rs +++ b/platform/src/family/unix/linux/properties.rs @@ -1,11 +1,9 @@ -#![cfg_attr(rustfmt, rustfmt_skip)] - use crate::properties::{Error, PropertySet}; use core::ffi::CStr; -use std::io::BufRead; use core::mem::MaybeUninit; use core::ptr::{self, NonNull}; +use std::io::BufRead; // @Native private static final int _display_country_NDX = 0; // @Native private static final int _display_language_NDX = 1 + _display_country_NDX; @@ -32,221 +30,246 @@ const JAVA_IO_TMPDIR: &str = "/var/tmp"; // @Native private static final int _user_name_NDX = 1 + _user_home_NDX; pub fn fill_properties_impl(props: &mut PropertySet) -> Result<(), Error> { - props.java_io_tmpdir = JAVA_IO_TMPDIR.into(); - - // OS props - { - let mut utsname = unsafe { MaybeUninit::::zeroed().assume_init() }; - unsafe { - libc::uname(&raw mut utsname); - } - - let sysname_raw = unsafe { - CStr::from_ptr(utsname.sysname.as_ptr()) - }; - props.os_name = sysname_raw.to_str().expect("TODO: Other string encodings").to_owned(); - - let release_raw = unsafe { - CStr::from_ptr(utsname.release.as_ptr()) - }; - props.os_version = release_raw.to_str().expect("TODO: Other string encodings").to_owned(); - } - - // Locale props - { - unsafe { libc::setlocale(libc::LC_ALL, c"".as_ptr()) }; - init_locale( - libc::LC_CTYPE, - Some(&mut props.format_language), - Some(&mut props.format_script), - Some(&mut props.format_country), - Some(&mut props.format_variant), - Some(&mut props.file_encoding) - ); - init_locale( - libc::LC_MESSAGES, - Some(&mut props.display_language), - Some(&mut props.display_script), - Some(&mut props.display_country), - Some(&mut props.display_variant), - None - ); - - props.sun_jnu_encoding = props.file_encoding.clone(); - } - - // User props - { - let uid = unsafe { libc::getuid() }; - let passwd = unsafe { libc::getpwuid(uid) }; - - let user_name; - let user_home; - if passwd.is_null() { - user_name = String::from("?"); - user_home = None; - } else { - let user_name_raw = unsafe { - CStr::from_ptr((*passwd).pw_name) - }; - user_name = user_name_raw.to_str().expect("TODO: Other string encodings").to_owned(); - - let user_home_raw = unsafe { - CStr::from_ptr((*passwd).pw_dir) - }; - - if user_home_raw.to_bytes().len() < 3 { - user_home = None; - } else { - user_home = Some(user_home_raw.to_str().expect("TODO: Other string encodings").to_owned()); - } - } - - let user_home = match user_home { - Some(user_home) => user_home, - None => { - match std::env::var("HOME") { - Ok(env_home) if env_home.len() > 2 => { - env_home - } - _ => String::from("?") - } - } - }; - } - - // Current directory - { - let Ok(dir) = std::env::current_dir() else { - return Err(Error::WorkingDir) - }; - - props.user_dir = dir.to_str().expect("TODO: Other path encodings").to_owned(); - } - - Ok(()) + props.java_io_tmpdir = JAVA_IO_TMPDIR.into(); + + // OS props + { + let mut utsname = unsafe { MaybeUninit::::zeroed().assume_init() }; + unsafe { + libc::uname(&raw mut utsname); + } + + let sysname_raw = unsafe { CStr::from_ptr(utsname.sysname.as_ptr()) }; + props.os_name = sysname_raw + .to_str() + .expect("TODO: Other string encodings") + .to_owned(); + + let release_raw = unsafe { CStr::from_ptr(utsname.release.as_ptr()) }; + props.os_version = release_raw + .to_str() + .expect("TODO: Other string encodings") + .to_owned(); + } + + // Locale props + { + unsafe { libc::setlocale(libc::LC_ALL, c"".as_ptr()) }; + init_locale( + libc::LC_CTYPE, + Some(&mut props.format_language), + Some(&mut props.format_script), + Some(&mut props.format_country), + Some(&mut props.format_variant), + Some(&mut props.file_encoding), + ); + init_locale( + libc::LC_MESSAGES, + Some(&mut props.display_language), + Some(&mut props.display_script), + Some(&mut props.display_country), + Some(&mut props.display_variant), + None, + ); + + props.sun_jnu_encoding = props.file_encoding.clone(); + } + + // User props + { + let uid = unsafe { libc::getuid() }; + let passwd = unsafe { libc::getpwuid(uid) }; + + let user_name; + let user_home; + if passwd.is_null() { + user_name = String::from("?"); + user_home = None; + } else { + let user_name_raw = unsafe { CStr::from_ptr((*passwd).pw_name) }; + user_name = user_name_raw + .to_str() + .expect("TODO: Other string encodings") + .to_owned(); + + let user_home_raw = unsafe { CStr::from_ptr((*passwd).pw_dir) }; + + if user_home_raw.to_bytes().len() < 3 { + user_home = None; + } else { + user_home = Some( + user_home_raw + .to_str() + .expect("TODO: Other string encodings") + .to_owned(), + ); + } + } + + let user_home = match user_home { + Some(user_home) => user_home, + None => match std::env::var("HOME") { + Ok(env_home) if env_home.len() > 2 => env_home, + _ => String::from("?"), + }, + }; + } + + // Current directory + { + let Ok(dir) = std::env::current_dir() else { + return Err(Error::WorkingDir); + }; + + props.user_dir = dir.to_str().expect("TODO: Other path encodings").to_owned(); + } + + Ok(()) } -fn init_locale(category: i32, language_field: Option<&mut String>, script_field: Option<&mut String>, country_field: Option<&mut String>, variant_field: Option<&mut String>, encoding_field: Option<&mut String>) { - // Parses the locale in the form: `language_country.encoding@variant` - // - // `language_country`: Required - // `encoding`: Optional, preceded by . - // `variant`: Optional, preceded by @ - fn split_locale(locale: &CStr) -> (&[u8], &[u8], Option<&[u8]>, Option<&[u8]>) { - let bytes = locale.to_bytes(); - - let mut has_encoding_or_variant = false; - let mut language_country_end_pos = bytes.len(); - - // Encoding - let mut encoding = None; - let variant_position = bytes.iter().position(|b| *b == b'@'); - if let Some(pos) = bytes.iter().position(|b| *b == b'.') { - language_country_end_pos = pos; - - has_encoding_or_variant = true; - let end = variant_position.unwrap_or(bytes.len()); - encoding = Some(&bytes[pos..end]); - } - - // Variant - let mut variant = None; - if let Some(pos) = variant_position { - if encoding.is_none() { - language_country_end_pos = pos; - } - - has_encoding_or_variant = true; - variant = Some(&bytes[pos..]); - } - - let mut language_country = bytes[..language_country_end_pos].split(|b| *b == b'_'); - - let language = language_country.next().expect("TODO: Nice error"); - let country = language_country.next().expect("TODO: Nice error"); - - (language, country, encoding, variant) - } - - let locale_raw = unsafe { libc::setlocale(category, ptr::null()) }; - - let locale; - if locale_raw.is_null() { - locale = c"en_US"; - } else { - locale = unsafe { CStr::from_ptr(locale_raw) }; - } - - let (mut language, mut country, mut encoding, mut variant) = split_locale(locale); - - if encoding.is_none() && variant.is_none() { - if let Some((_, new_locale)) = super::locale::locale_aliases().find(|(k, _)| *k == locale) { - (language, country, encoding, variant) = split_locale(new_locale); - } - } - - // Normalize the language name - if let Some(language_field) = language_field { - // In case we can't find anything... - *language_field = String::from("en"); - - if let Some((_, language)) = super::locale::language_names().find(|(k, _)| k.to_bytes() == language) { - let language = language.to_str().expect("normalized table entries should never be invalid"); - *language_field = String::from(language); - } - } - - // Normalize the country name - if let Some(country_field) = country_field { - if let Some((_, country)) = super::locale::country_names().find(|(k, _)| k.to_bytes() == country) { - let country = country.to_str().expect("normalized table entries should never be invalid"); - *country_field = String::from(country); - } - } - - // Normalize the script and variant name. - // Note that we only use variants listed in the mapping array; others are ignored. - if let Some(variant) = variant { - if let Some(script_field) = script_field { - if let Some((_, script)) = super::locale::script_names().find(|(k, _)| k.to_bytes() == variant) { - let script = script.to_str().expect("normalized table entries should never be invalid"); - *script_field = String::from(script); - } - } - - if let Some(variant_field) = variant_field { - if let Some((_, variant)) = crate::locale::base_variant_names().find(|(k, _)| k.to_bytes() == variant) { - let variant = variant.to_str().expect("normalized table entries should never be invalid"); - *variant_field = String::from(variant); - } - } - } - - // Normalize the encoding name. Note that we IGNORE the string 'encoding' extracted from the - // locale name above. Instead, we use the more reliable method of calling `nl_langinfo(CODESET)`. - // This function returns an empty string if no encoding is set for the given - // locale (e.g., the C or POSIX locales); we use the default ISO 8859-1 converter for such locales. - if let Some(encoding) = encoding { - if let Some(encoding_field) = encoding_field { - let ret_encoding; - match encoding { - b"ISO8859-15" => ret_encoding = "ISO8859-15", - // Remap the encoding string to a different value for japanese locales on linux so that - // customized converters are used instead of the default converter for "EUC-JP" - b"EUC-JP" => ret_encoding = "EUC-JP-LINUX", - _ => { - let lang = unsafe { libc::nl_langinfo(libc::CODESET) }; - if lang.is_null() { - ret_encoding = "ISO8859-1"; - } else { - let cstr = unsafe { CStr::from_ptr(lang) }; - ret_encoding = cstr.to_str().expect("TODO: Nice error"); - } - } - } - - *encoding_field = String::from(ret_encoding); - } - } +fn init_locale( + category: i32, + language_field: Option<&mut String>, + script_field: Option<&mut String>, + country_field: Option<&mut String>, + variant_field: Option<&mut String>, + encoding_field: Option<&mut String>, +) { + // Parses the locale in the form: `language_country.encoding@variant` + // + // `language_country`: Required + // `encoding`: Optional, preceded by . + // `variant`: Optional, preceded by @ + fn split_locale(locale: &CStr) -> (&[u8], &[u8], Option<&[u8]>, Option<&[u8]>) { + let bytes = locale.to_bytes(); + + let mut has_encoding_or_variant = false; + let mut language_country_end_pos = bytes.len(); + + // Encoding + let mut encoding = None; + let variant_position = bytes.iter().position(|b| *b == b'@'); + if let Some(pos) = bytes.iter().position(|b| *b == b'.') { + language_country_end_pos = pos; + + has_encoding_or_variant = true; + let end = variant_position.unwrap_or(bytes.len()); + encoding = Some(&bytes[pos..end]); + } + + // Variant + let mut variant = None; + if let Some(pos) = variant_position { + if encoding.is_none() { + language_country_end_pos = pos; + } + + has_encoding_or_variant = true; + variant = Some(&bytes[pos..]); + } + + let mut language_country = bytes[..language_country_end_pos].split(|b| *b == b'_'); + + let language = language_country.next().expect("TODO: Nice error"); + let country = language_country.next().expect("TODO: Nice error"); + + (language, country, encoding, variant) + } + + let locale_raw = unsafe { libc::setlocale(category, ptr::null()) }; + + let locale; + if locale_raw.is_null() { + locale = c"en_US"; + } else { + locale = unsafe { CStr::from_ptr(locale_raw) }; + } + + let (mut language, mut country, mut encoding, mut variant) = split_locale(locale); + + if encoding.is_none() && variant.is_none() { + if let Some((_, new_locale)) = super::locale::locale_aliases().find(|(k, _)| *k == locale) { + (language, country, encoding, variant) = split_locale(new_locale); + } + } + + // Normalize the language name + if let Some(language_field) = language_field { + // In case we can't find anything... + *language_field = String::from("en"); + + if let Some((_, language)) = + super::locale::language_names().find(|(k, _)| k.to_bytes() == language) + { + let language = language + .to_str() + .expect("normalized table entries should never be invalid"); + *language_field = String::from(language); + } + } + + // Normalize the country name + if let Some(country_field) = country_field { + if let Some((_, country)) = + super::locale::country_names().find(|(k, _)| k.to_bytes() == country) + { + let country = country + .to_str() + .expect("normalized table entries should never be invalid"); + *country_field = String::from(country); + } + } + + // Normalize the script and variant name. + // Note that we only use variants listed in the mapping array; others are ignored. + if let Some(variant) = variant { + if let Some(script_field) = script_field { + if let Some((_, script)) = + super::locale::script_names().find(|(k, _)| k.to_bytes() == variant) + { + let script = script + .to_str() + .expect("normalized table entries should never be invalid"); + *script_field = String::from(script); + } + } + + if let Some(variant_field) = variant_field { + if let Some((_, variant)) = + crate::locale::base_variant_names().find(|(k, _)| k.to_bytes() == variant) + { + let variant = variant + .to_str() + .expect("normalized table entries should never be invalid"); + *variant_field = String::from(variant); + } + } + } + + // Normalize the encoding name. Note that we IGNORE the string 'encoding' extracted from the + // locale name above. Instead, we use the more reliable method of calling `nl_langinfo(CODESET)`. + // This function returns an empty string if no encoding is set for the given + // locale (e.g., the C or POSIX locales); we use the default ISO 8859-1 converter for such locales. + if let Some(encoding) = encoding { + if let Some(encoding_field) = encoding_field { + let ret_encoding; + match encoding { + b"ISO8859-15" => ret_encoding = "ISO8859-15", + // Remap the encoding string to a different value for japanese locales on linux so that + // customized converters are used instead of the default converter for "EUC-JP" + b"EUC-JP" => ret_encoding = "EUC-JP-LINUX", + _ => { + let lang = unsafe { libc::nl_langinfo(libc::CODESET) }; + if lang.is_null() { + ret_encoding = "ISO8859-1"; + } else { + let cstr = unsafe { CStr::from_ptr(lang) }; + ret_encoding = cstr.to_str().expect("TODO: Nice error"); + } + }, + } + + *encoding_field = String::from(ret_encoding); + } + } } diff --git a/platform/src/family/unix/macos/properties.rs b/platform/src/family/unix/macos/properties.rs index 11b8ba6..6d28e93 100644 --- a/platform/src/family/unix/macos/properties.rs +++ b/platform/src/family/unix/macos/properties.rs @@ -1,5 +1,3 @@ -#![cfg_attr(rustfmt, rustfmt_skip)] - // TODO use std::ptr::NonNull; @@ -38,8 +36,10 @@ pub const SUN_JNU_ENCODING: &str = "UTF-8"; // @Native private static final int _user_home_NDX = 1 + _user_dir_NDX; // @Native private static final int _user_name_NDX = 1 + _user_home_NDX; -pub fn fill_properties_impl(props: &mut crate::properties::PropertySet) -> Result<(), crate::properties::Error> { - props.os_name = OS_NAME; - props.sun_jnu_encoding = SUN_JNU_ENCODING; - unimplemented!("macOS property set"); +pub fn fill_properties_impl( + props: &mut crate::properties::PropertySet, +) -> Result<(), crate::properties::Error> { + props.os_name = OS_NAME; + props.sun_jnu_encoding = SUN_JNU_ENCODING; + unimplemented!("macOS property set"); } diff --git a/platform/src/family/unix/mod.rs b/platform/src/family/unix/mod.rs index a049123..dc637df 100644 --- a/platform/src/family/unix/mod.rs +++ b/platform/src/family/unix/mod.rs @@ -1,18 +1,12 @@ -use crate::macros::match_cfg_meta; - // OS specific modules -match_cfg_meta! { - match cfg(target_os) { - "linux" => { - mod linux; - }, - "macos" => { - mod macos; - }, - _ => { - compile_error!("target OS is not supported!"); - } +cfg_if::cfg_if! { + if #[cfg(target_os = "linux")] { + mod linux; + } else if #[cfg(target_os = "macos")] { + mod macos; + } else { + compile_error!("target OS is not supported!"); } } diff --git a/platform/src/family/unix/properties.rs b/platform/src/family/unix/properties.rs index ffa727c..444a37e 100644 --- a/platform/src/family/unix/properties.rs +++ b/platform/src/family/unix/properties.rs @@ -1,16 +1,18 @@ -#![cfg_attr(rustfmt, rustfmt_skip)] - // Properties shared between all `target_family = "unix"` pub const FILE_SEPARATOR: &str = "/"; pub const LINE_SEPARATOR: &str = "\n"; pub const OS_ARCH: &str = std::env::consts::ARCH; pub const PATH_SEPARATOR: &str = ":"; -pub const UNICODE_ENCODING: &str = if cfg!(target_endian = "big") { "UnicodeBig" } else { "UnicodeLittle" }; +pub const UNICODE_ENCODING: &str = if cfg!(target_endian = "big") { + "UnicodeBig" +} else { + "UnicodeLittle" +}; // Export OS specific properties #[cfg(target_os = "linux")] pub use super::linux::properties::*; #[cfg(target_os = "macos")] -pub use super::macos::properties::*; \ No newline at end of file +pub use super::macos::properties::*; diff --git a/platform/src/family/windows/properties.rs b/platform/src/family/windows/properties.rs index 3e76abe..c066fdd 100644 --- a/platform/src/family/windows/properties.rs +++ b/platform/src/family/windows/properties.rs @@ -1,7 +1,5 @@ -#![cfg_attr(rustfmt, rustfmt_skip)] - -use std::ptr::NonNull; use crate::macros::match_cfg_meta; +use std::ptr::NonNull; // TODO @@ -18,21 +16,16 @@ pub const FILE_SEPARATOR: &str = "\\"; // @Native private static final int _java_io_tmpdir_NDX = 1 + _https_proxyPort_NDX; pub const LINE_SEPARATOR: &str = "\r\n"; // https://github.com/openjdk/jdk/blob/19373b2ff0cd795afa262c17dcb3388fd6a5be59/src/java.base/windows/native/libjava/java_props_md.c#L580-L588 -match_cfg_meta! { - match cfg(target_arch) { - "x86_64" => { - pub const OS_ARCH: &str = "amd64"; - }, - "x86" => { - pub const OS_ARCH: &str = "x86"; - }, - "aarch64" => { - pub const OS_ARCH: &str = "aarch64"; - }, - _ => { - pub const OS_ARCH: &str = "unknown"; - } - } +cfg_if::cfg_if! { + if #[(target_arch = "x86_64")] { + pub const OS_ARCH: &str = "amd64"; + } else if #[cfg(target_arch = "x86")] { + pub const OS_ARCH: &str = "x86"; + } else if #[cfg(target_arch = "aarch64")] { + pub const OS_ARCH: &str = "aarch64"; + } else { + pub const OS_ARCH: &str = "unknown"; + } } // @Native private static final int _os_name_NDX = 1 + _os_arch_NDX; // @Native private static final int _os_version_NDX = 1 + _os_name_NDX; @@ -49,6 +42,8 @@ pub const UNICODE_ENCODING: &str = "UnicodeLittle"; // @Native private static final int _user_home_NDX = 1 + _user_dir_NDX; // @Native private static final int _user_name_NDX = 1 + _user_home_NDX; -pub fn fill_properties_impl(props: &mut crate::properties::PropertySet) -> Result<(), crate::properties::Error> { - unimplemented!("Windows property set"); +pub fn fill_properties_impl( + props: &mut crate::properties::PropertySet, +) -> Result<(), crate::properties::Error> { + unimplemented!("Windows property set"); } diff --git a/platform/src/lib.rs b/platform/src/lib.rs index c47764d..15d440a 100644 --- a/platform/src/lib.rs +++ b/platform/src/lib.rs @@ -2,7 +2,6 @@ pub mod arch; mod family; -mod macros; // Exports diff --git a/platform/src/macros.rs b/platform/src/macros.rs deleted file mode 100644 index b8bb771..0000000 --- a/platform/src/macros.rs +++ /dev/null @@ -1,40 +0,0 @@ -macro_rules! conditional { - ( - #[$meta:meta] - - $( - $item:item - )+ - ) => { - $( - #[$meta] - $item - )+ - } -} - -macro_rules! match_cfg_meta { - ( - match cfg($ident:ident) { - $($pat:literal => { $($val:item)* }),+ $(,)? - $(_ => { $($fallback:item)* })? - } - ) => { - $( - $( - #[cfg($ident = $pat)] - $val - )* - )+ - - match_cfg_meta!(@FALLBACK $ident; $($pat)+; $($($fallback)*)?); - }; - (@FALLBACK $ident:ident; $($pat:literal)+; $($fallback:item)*) => { - #[cfg(not(any($($ident = $pat),+)))] - $($fallback)* - }; - (@FALLBACK $ident:ident; $($pat:literal)+;) => {} -} - -#[allow(unused_imports)] -pub(crate) use {conditional, match_cfg_meta};