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")]
73pub fn mkstemp<P: AsRef<std::path::Path>>(tmpl: P) -> i32 {
74 unsafe {
75 ffi::g_mkstemp(tmpl.as_ref().to_glib_none().0)
78 }
79}
80
81#[doc(alias = "g_mkstemp_full")]
107pub fn mkstemp_full(tmpl: impl AsRef<std::path::Path>, flags: i32, mode: i32) -> i32 {
108 unsafe {
109 ffi::g_mkstemp_full(tmpl.as_ref().to_glib_none().0, flags, mode)
112 }
113}
114
115#[doc(alias = "g_mkdtemp")]
139pub fn mkdtemp(tmpl: impl AsRef<std::path::Path>) -> Option<std::path::PathBuf> {
140 unsafe {
141 let tmpl = tmpl.as_ref().to_glib_full();
144 let res = ffi::g_mkdtemp(tmpl);
145 if res.is_null() {
146 ffi::g_free(tmpl as ffi::gpointer);
147 None
148 } else {
149 from_glib_full(res)
150 }
151 }
152}
153
154#[doc(alias = "g_mkdtemp_full")]
180pub fn mkdtemp_full(tmpl: impl AsRef<std::path::Path>, mode: i32) -> Option<std::path::PathBuf> {
181 unsafe {
182 let tmpl = tmpl.as_ref().to_glib_full();
185 let res = ffi::g_mkdtemp_full(tmpl, mode);
186 if res.is_null() {
187 ffi::g_free(tmpl as ffi::gpointer);
188 None
189 } else {
190 from_glib_full(res)
191 }
192 }
193}
194
195#[doc(alias = "g_file_get_contents")]
196pub fn file_get_contents(
197 filename: impl AsRef<std::path::Path>,
198) -> Result<crate::Slice<u8>, crate::Error> {
199 unsafe {
200 let mut contents = ptr::null_mut();
201 let mut length = mem::MaybeUninit::uninit();
202 let mut error = ptr::null_mut();
203 let _ = ffi::g_file_get_contents(
204 filename.as_ref().to_glib_none().0,
205 &mut contents,
206 length.as_mut_ptr(),
207 &mut error,
208 );
209 if error.is_null() {
210 Ok(crate::Slice::from_glib_full_num(
211 contents,
212 length.assume_init() as _,
213 ))
214 } else {
215 Err(from_glib_full(error))
216 }
217 }
218}
219
220pub fn is_canonical_pspec_name(name: &str) -> bool {
221 name.as_bytes().iter().enumerate().all(|(i, c)| {
222 i != 0 && (*c >= b'0' && *c <= b'9' || *c == b'-')
223 || (*c >= b'A' && *c <= b'Z')
224 || (*c >= b'a' && *c <= b'z')
225 })
226}
227
228#[doc(alias = "g_uri_escape_string")]
229pub fn uri_escape_string(
230 unescaped: impl IntoGStr,
231 reserved_chars_allowed: Option<impl IntoGStr>,
232 allow_utf8: bool,
233) -> crate::GString {
234 unescaped.run_with_gstr(|unescaped| {
235 reserved_chars_allowed.run_with_gstr(|reserved_chars_allowed| unsafe {
236 from_glib_full(ffi::g_uri_escape_string(
237 unescaped.to_glib_none().0,
238 reserved_chars_allowed.to_glib_none().0,
239 allow_utf8.into_glib(),
240 ))
241 })
242 })
243}
244
245#[doc(alias = "g_uri_unescape_string")]
246pub fn uri_unescape_string(
247 escaped_string: impl IntoGStr,
248 illegal_characters: Option<impl IntoGStr>,
249) -> Option<crate::GString> {
250 escaped_string.run_with_gstr(|escaped_string| {
251 illegal_characters.run_with_gstr(|illegal_characters| unsafe {
252 from_glib_full(ffi::g_uri_unescape_string(
253 escaped_string.to_glib_none().0,
254 illegal_characters.to_glib_none().0,
255 ))
256 })
257 })
258}
259
260#[doc(alias = "g_uri_parse_scheme")]
261pub fn uri_parse_scheme(uri: impl IntoGStr) -> Option<crate::GString> {
262 uri.run_with_gstr(|uri| unsafe {
263 from_glib_full(ffi::g_uri_parse_scheme(uri.to_glib_none().0))
264 })
265}
266
267#[doc(alias = "g_uri_unescape_segment")]
268pub fn uri_unescape_segment(
269 escaped_string: Option<impl IntoGStr>,
270 escaped_string_end: Option<impl IntoGStr>,
271 illegal_characters: Option<impl IntoGStr>,
272) -> Option<crate::GString> {
273 escaped_string.run_with_gstr(|escaped_string| {
274 escaped_string_end.run_with_gstr(|escaped_string_end| {
275 illegal_characters.run_with_gstr(|illegal_characters| unsafe {
276 from_glib_full(ffi::g_uri_unescape_segment(
277 escaped_string.to_glib_none().0,
278 escaped_string_end.to_glib_none().0,
279 illegal_characters.to_glib_none().0,
280 ))
281 })
282 })
283 })
284}
285
286#[cfg(test)]
287mod tests {
288 use std::{env, sync::Mutex, sync::OnceLock};
289
290 fn lock() -> &'static Mutex<()> {
292 static LOCK: OnceLock<Mutex<()>> = OnceLock::new();
293 LOCK.get_or_init(|| Mutex::new(()))
294 }
295
296 const VAR_NAME: &str = "function_environment_test";
297
298 fn check_getenv(val: &str) {
299 let _data = lock().lock().unwrap();
300
301 env::set_var(VAR_NAME, val);
302 assert_eq!(env::var_os(VAR_NAME), Some(val.into()));
303 assert_eq!(crate::getenv(VAR_NAME), Some(val.into()));
304
305 let environ = crate::environ();
306 assert_eq!(crate::environ_getenv(&environ, VAR_NAME), Some(val.into()));
307 }
308
309 fn check_setenv(val: &str) {
310 let _data = lock().lock().unwrap();
311
312 crate::setenv(VAR_NAME, val, true).unwrap();
313 assert_eq!(env::var_os(VAR_NAME), Some(val.into()));
314 }
315
316 #[test]
317 fn getenv() {
318 check_getenv("Test");
319 check_getenv("Тест"); }
321
322 #[test]
323 fn setenv() {
324 check_setenv("Test");
325 check_setenv("Тест"); }
327
328 #[test]
329 fn test_filename_from_uri() {
330 use std::path::PathBuf;
331
332 use crate::GString;
333 let uri: GString = "file:///foo/bar.txt".into();
334 if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) {
335 assert_eq!(filename, PathBuf::from(r"/foo/bar.txt"));
336 assert_eq!(hostname, None);
337 } else {
338 unreachable!();
339 }
340
341 let uri: GString = "file://host/foo/bar.txt".into();
342 if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) {
343 assert_eq!(filename, PathBuf::from(r"/foo/bar.txt"));
344 assert_eq!(hostname, Some(GString::from("host")));
345 } else {
346 unreachable!();
347 }
348 }
349
350 #[test]
351 fn test_uri_parsing() {
352 use crate::GString;
353 assert_eq!(
354 crate::uri_parse_scheme("foo://bar"),
355 Some(GString::from("foo"))
356 );
357 assert_eq!(crate::uri_parse_scheme("foo"), None);
358
359 let escaped = crate::uri_escape_string("&foo", crate::NONE_STR, true);
360 assert_eq!(escaped, GString::from("%26foo"));
361
362 let unescaped = crate::uri_unescape_string(escaped.as_str(), crate::GStr::NONE);
363 assert_eq!(unescaped, Some(GString::from("&foo")));
364
365 assert_eq!(
366 crate::uri_unescape_segment(Some("/foo"), crate::NONE_STR, crate::NONE_STR),
367 Some(GString::from("/foo"))
368 );
369 assert_eq!(
370 crate::uri_unescape_segment(Some("/foo%"), crate::NONE_STR, crate::NONE_STR),
371 None
372 );
373 }
374}