1use std::{
4 ffi::{OsStr, OsString},
5 mem, ptr,
6};
7
8use crate::{ffi, translate::*, GString};
9
10#[doc(alias = "get_program_name")]
15#[inline]
16pub fn program_name() -> Option<GString> {
17 prgname()
18}
19
20#[doc(alias = "g_get_prgname")]
21#[doc(alias = "get_prgname")]
22#[inline]
23pub fn prgname() -> Option<GString> {
24 unsafe { from_glib_none(ffi::g_get_prgname()) }
25}
26
27#[inline]
32pub fn set_program_name(name: Option<impl IntoGStr>) {
33 set_prgname(name)
34}
35
36#[doc(alias = "g_set_prgname")]
37#[inline]
38pub fn set_prgname(name: Option<impl IntoGStr>) {
39 name.run_with_gstr(|name| unsafe { ffi::g_set_prgname(name.to_glib_none().0) })
40}
41
42#[doc(alias = "g_environ_getenv")]
43pub fn environ_getenv<K: AsRef<OsStr>>(envp: &[OsString], variable: K) -> Option<OsString> {
44 unsafe {
45 from_glib_none(ffi::g_environ_getenv(
46 envp.to_glib_none().0,
47 variable.as_ref().to_glib_none().0,
48 ))
49 }
50}
51
52#[doc(alias = "g_mkstemp")]
53pub fn mkstemp<P: AsRef<std::path::Path>>(tmpl: P) -> i32 {
54 unsafe {
55 ffi::g_mkstemp(tmpl.as_ref().to_glib_none().0)
58 }
59}
60
61#[doc(alias = "g_mkstemp_full")]
62pub fn mkstemp_full(tmpl: impl AsRef<std::path::Path>, flags: i32, mode: i32) -> i32 {
63 unsafe {
64 ffi::g_mkstemp_full(tmpl.as_ref().to_glib_none().0, flags, mode)
67 }
68}
69
70#[doc(alias = "g_mkdtemp")]
71pub fn mkdtemp(tmpl: impl AsRef<std::path::Path>) -> Option<std::path::PathBuf> {
72 unsafe {
73 let tmpl = tmpl.as_ref().to_glib_full();
76 let res = ffi::g_mkdtemp(tmpl);
77 if res.is_null() {
78 ffi::g_free(tmpl as ffi::gpointer);
79 None
80 } else {
81 from_glib_full(res)
82 }
83 }
84}
85
86#[doc(alias = "g_mkdtemp_full")]
87pub fn mkdtemp_full(tmpl: impl AsRef<std::path::Path>, mode: i32) -> Option<std::path::PathBuf> {
88 unsafe {
89 let tmpl = tmpl.as_ref().to_glib_full();
92 let res = ffi::g_mkdtemp_full(tmpl, mode);
93 if res.is_null() {
94 ffi::g_free(tmpl as ffi::gpointer);
95 None
96 } else {
97 from_glib_full(res)
98 }
99 }
100}
101
102#[doc(alias = "g_file_get_contents")]
103pub fn file_get_contents(
104 filename: impl AsRef<std::path::Path>,
105) -> Result<crate::Slice<u8>, crate::Error> {
106 unsafe {
107 let mut contents = ptr::null_mut();
108 let mut length = mem::MaybeUninit::uninit();
109 let mut error = ptr::null_mut();
110 let _ = ffi::g_file_get_contents(
111 filename.as_ref().to_glib_none().0,
112 &mut contents,
113 length.as_mut_ptr(),
114 &mut error,
115 );
116 if error.is_null() {
117 Ok(crate::Slice::from_glib_full_num(
118 contents,
119 length.assume_init() as _,
120 ))
121 } else {
122 Err(from_glib_full(error))
123 }
124 }
125}
126
127pub fn is_canonical_pspec_name(name: &str) -> bool {
128 name.as_bytes().iter().enumerate().all(|(i, c)| {
129 i != 0 && (*c >= b'0' && *c <= b'9' || *c == b'-')
130 || (*c >= b'A' && *c <= b'Z')
131 || (*c >= b'a' && *c <= b'z')
132 })
133}
134
135#[doc(alias = "g_uri_escape_string")]
136pub fn uri_escape_string(
137 unescaped: impl IntoGStr,
138 reserved_chars_allowed: Option<impl IntoGStr>,
139 allow_utf8: bool,
140) -> crate::GString {
141 unescaped.run_with_gstr(|unescaped| {
142 reserved_chars_allowed.run_with_gstr(|reserved_chars_allowed| unsafe {
143 from_glib_full(ffi::g_uri_escape_string(
144 unescaped.to_glib_none().0,
145 reserved_chars_allowed.to_glib_none().0,
146 allow_utf8.into_glib(),
147 ))
148 })
149 })
150}
151
152#[doc(alias = "g_uri_unescape_string")]
153pub fn uri_unescape_string(
154 escaped_string: impl IntoGStr,
155 illegal_characters: Option<impl IntoGStr>,
156) -> Option<crate::GString> {
157 escaped_string.run_with_gstr(|escaped_string| {
158 illegal_characters.run_with_gstr(|illegal_characters| unsafe {
159 from_glib_full(ffi::g_uri_unescape_string(
160 escaped_string.to_glib_none().0,
161 illegal_characters.to_glib_none().0,
162 ))
163 })
164 })
165}
166
167#[doc(alias = "g_uri_parse_scheme")]
168pub fn uri_parse_scheme(uri: impl IntoGStr) -> Option<crate::GString> {
169 uri.run_with_gstr(|uri| unsafe {
170 from_glib_full(ffi::g_uri_parse_scheme(uri.to_glib_none().0))
171 })
172}
173
174#[doc(alias = "g_uri_unescape_segment")]
175pub fn uri_unescape_segment(
176 escaped_string: Option<impl IntoGStr>,
177 escaped_string_end: Option<impl IntoGStr>,
178 illegal_characters: Option<impl IntoGStr>,
179) -> Option<crate::GString> {
180 escaped_string.run_with_gstr(|escaped_string| {
181 escaped_string_end.run_with_gstr(|escaped_string_end| {
182 illegal_characters.run_with_gstr(|illegal_characters| unsafe {
183 from_glib_full(ffi::g_uri_unescape_segment(
184 escaped_string.to_glib_none().0,
185 escaped_string_end.to_glib_none().0,
186 illegal_characters.to_glib_none().0,
187 ))
188 })
189 })
190 })
191}
192
193#[cfg(test)]
194mod tests {
195 use std::{env, sync::Mutex, sync::OnceLock};
196
197 fn lock() -> &'static Mutex<()> {
199 static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
200 LOCK.get_or_init(|| Mutex::new(()))
201 }
202
203 const VAR_NAME: &str = "function_environment_test";
204
205 fn check_getenv(val: &str) {
206 let _data = lock().lock().unwrap();
207
208 env::set_var(VAR_NAME, val);
209 assert_eq!(env::var_os(VAR_NAME), Some(val.into()));
210 assert_eq!(crate::getenv(VAR_NAME), Some(val.into()));
211
212 let environ = crate::environ();
213 assert_eq!(crate::environ_getenv(&environ, VAR_NAME), Some(val.into()));
214 }
215
216 fn check_setenv(val: &str) {
217 let _data = lock().lock().unwrap();
218
219 crate::setenv(VAR_NAME, val, true).unwrap();
220 assert_eq!(env::var_os(VAR_NAME), Some(val.into()));
221 }
222
223 #[test]
224 fn getenv() {
225 check_getenv("Test");
226 check_getenv("Тест"); }
228
229 #[test]
230 fn setenv() {
231 check_setenv("Test");
232 check_setenv("Тест"); }
234
235 #[test]
236 fn test_filename_from_uri() {
237 use std::path::PathBuf;
238
239 use crate::GString;
240 let uri: GString = "file:///foo/bar.txt".into();
241 if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) {
242 assert_eq!(filename, PathBuf::from(r"/foo/bar.txt"));
243 assert_eq!(hostname, None);
244 } else {
245 unreachable!();
246 }
247
248 let uri: GString = "file://host/foo/bar.txt".into();
249 if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) {
250 assert_eq!(filename, PathBuf::from(r"/foo/bar.txt"));
251 assert_eq!(hostname, Some(GString::from("host")));
252 } else {
253 unreachable!();
254 }
255 }
256
257 #[test]
258 fn test_uri_parsing() {
259 use crate::GString;
260 assert_eq!(
261 crate::uri_parse_scheme("foo://bar"),
262 Some(GString::from("foo"))
263 );
264 assert_eq!(crate::uri_parse_scheme("foo"), None);
265
266 let escaped = crate::uri_escape_string("&foo", crate::NONE_STR, true);
267 assert_eq!(escaped, GString::from("%26foo"));
268
269 let unescaped = crate::uri_unescape_string(escaped.as_str(), crate::GStr::NONE);
270 assert_eq!(unescaped, Some(GString::from("&foo")));
271
272 assert_eq!(
273 crate::uri_unescape_segment(Some("/foo"), crate::NONE_STR, crate::NONE_STR),
274 Some(GString::from("/foo"))
275 );
276 assert_eq!(
277 crate::uri_unescape_segment(Some("/foo%"), crate::NONE_STR, crate::NONE_STR),
278 None
279 );
280 }
281}