1use crate::sys::*;
14use std::{
15 ffi::{CStr, c_int},
16 mem::zeroed,
17 os::raw::c_char,
18 ptr::null_mut,
19 str,
20};
21
22pub fn ini_get<T: FromIniValue>(name: &str) -> T {
34 T::from_ini_value(name)
35}
36
37#[repr(u32)]
39#[derive(Copy, Clone)]
40pub enum Policy {
41 All = PHP_INI_ALL,
43 User = PHP_INI_USER,
46 Perdir = PHP_INI_PERDIR,
48 System = PHP_INI_SYSTEM,
50}
51
52pub trait IntoIniValue {
54 fn into_ini_value(self) -> String;
56}
57
58impl IntoIniValue for bool {
59 #[inline]
60 fn into_ini_value(self) -> String {
61 if self { "1".to_owned() } else { "0".to_owned() }
62 }
63}
64
65impl IntoIniValue for i64 {
66 #[inline]
67 fn into_ini_value(self) -> String {
68 self.to_string()
69 }
70}
71
72impl IntoIniValue for f64 {
73 #[inline]
74 fn into_ini_value(self) -> String {
75 self.to_string()
76 }
77}
78
79impl IntoIniValue for String {
80 #[inline]
81 fn into_ini_value(self) -> String {
82 self
83 }
84}
85
86pub trait FromIniValue {
91 fn from_ini_value(name: &str) -> Self;
93}
94
95impl FromIniValue for bool {
96 #[allow(clippy::useless_conversion)]
97 fn from_ini_value(name: &str) -> Self {
98 let s = <Option<&CStr>>::from_ini_value(name);
99 [Some(c"1"), Some(c"true"), Some(c"on"), Some(c"On")].contains(&s)
100 }
101}
102
103impl FromIniValue for i64 {
104 #[allow(clippy::useless_conversion)]
105 fn from_ini_value(name: &str) -> Self {
106 unsafe {
107 let name_ptr = name.as_ptr() as *mut u8 as *mut c_char;
108 zend_ini_long(name_ptr, name.len().try_into().unwrap(), 0)
109 }
110 }
111}
112
113impl FromIniValue for f64 {
114 #[allow(clippy::useless_conversion)]
115 fn from_ini_value(name: &str) -> Self {
116 unsafe {
117 let name_ptr = name.as_ptr() as *mut u8 as *mut c_char;
118 zend_ini_double(name_ptr, name.len().try_into().unwrap(), 0)
119 }
120 }
121}
122
123impl FromIniValue for Option<&CStr> {
124 #[allow(clippy::useless_conversion)]
125 fn from_ini_value(name: &str) -> Self {
126 unsafe {
127 let name_ptr = name.as_ptr() as *mut u8 as *mut c_char;
128 let ptr = zend_ini_string_ex(name_ptr, name.len().try_into().unwrap(), 0, null_mut());
129 (!ptr.is_null()).then(|| CStr::from_ptr(ptr))
130 }
131 }
132}
133
134pub(crate) struct IniEntity {
135 name: String,
136 default_value: String,
137 policy: Policy,
138}
139
140impl IniEntity {
141 pub(crate) fn new<T: IntoIniValue>(
142 name: impl Into<String>, default_value: T, policy: Policy,
143 ) -> Self {
144 Self {
145 name: name.into(),
146 default_value: default_value.into_ini_value(),
147 policy,
148 }
149 }
150
151 #[inline]
152 pub(crate) fn entry(&self) -> zend_ini_entry_def {
153 create_ini_entry_ex(&self.name, &self.default_value, self.policy as u32)
154 }
155}
156
157fn create_ini_entry_ex(name: &str, default_value: &str, modifiable: u32) -> zend_ini_entry_def {
158 #[cfg(any(
159 phper_major_version = "8",
160 all(
161 phper_major_version = "7",
162 any(phper_minor_version = "4", phper_minor_version = "3")
163 )
164 ))]
165 let (modifiable, name_length) = (modifiable as std::os::raw::c_uchar, name.len() as u16);
166
167 #[cfg(all(
168 phper_major_version = "7",
169 any(
170 phper_minor_version = "2",
171 phper_minor_version = "1",
172 phper_minor_version = "0",
173 )
174 ))]
175 let (modifiable, name_length) = (modifiable as std::os::raw::c_int, name.len() as u32);
176
177 zend_ini_entry_def {
178 name: name.as_ptr().cast(),
179 on_modify: None,
180 mh_arg1: null_mut(),
181 mh_arg2: null_mut(),
182 mh_arg3: null_mut(),
183 value: default_value.as_ptr().cast(),
184 displayer: None,
185 modifiable,
186 name_length,
187 value_length: default_value.len() as u32,
188 }
189}
190
191unsafe fn entries(ini_entries: &[IniEntity]) -> *const zend_ini_entry_def {
192 unsafe {
193 let mut entries = Vec::with_capacity(ini_entries.len() + 1);
194
195 ini_entries.iter().for_each(|entity| {
196 entries.push(entity.entry());
198 });
199
200 entries.push(zeroed::<zend_ini_entry_def>());
201
202 Box::into_raw(entries.into_boxed_slice()).cast()
203 }
204}
205
206pub(crate) fn register(ini_entries: &[IniEntity], module_number: c_int) {
207 unsafe {
208 zend_register_ini_entries(entries(ini_entries), module_number);
209 }
210}
211
212pub(crate) fn unregister(module_number: c_int) {
213 unsafe {
214 zend_unregister_ini_entries(module_number);
215 }
216}