1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{
4 ffi::{OsStr, OsString},
5 mem, ptr,
6};
7
8use crate::{translate::*, GString, IntoGStr, IntoOptionalGStr};
9
10// rustdoc-stripper-ignore-next
11/// Same as [`get_prgname()`].
12///
13/// [`get_prgname()`]: fn.get_prgname.html
14#[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(ptr:ffi::g_get_prgname()) }
25}
26
27// rustdoc-stripper-ignore-next
28/// Same as [`set_prgname()`].
29///
30/// [`set_prgname()`]: fn.set_prgname.html
31#[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: Option<&GStr>| 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(ptr:ffi::g_environ_getenv(
46 envp:envp.to_glib_none().0,
47 variable: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 // NOTE: This modifies the string in place, which is fine here because
56 // to_glib_none() will create a temporary, NUL-terminated copy of the string.
57 ffi::g_mkstemp(tmpl: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 // NOTE: This modifies the string in place, which is fine here because
65 // to_glib_none() will create a temporary, NUL-terminated copy of the string.
66 ffi::g_mkstemp_full(tmpl: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 // NOTE: This modifies the string in place and returns it but does not free it
74 // if it returns NULL.
75 let tmpl: *mut i8 = tmpl.as_ref().to_glib_full();
76 let res: *mut i8 = ffi::g_mkdtemp(tmpl);
77 if res.is_null() {
78 ffi::g_free(mem:tmpl as ffi::gpointer);
79 None
80 } else {
81 from_glib_full(ptr: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 // NOTE: This modifies the string in place and returns it but does not free it
90 // if it returns NULL.
91 let tmpl: *mut i8 = tmpl.as_ref().to_glib_full();
92 let res: *mut i8 = ffi::g_mkdtemp_full(tmpl, mode);
93 if res.is_null() {
94 ffi::g_free(mem:tmpl as ffi::gpointer);
95 None
96 } else {
97 from_glib_full(ptr: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: *mut u8 = ptr::null_mut();
108 let mut length: MaybeUninit = mem::MaybeUninit::uninit();
109 let mut error: *mut GError = ptr::null_mut();
110 let _ = ffi::g_file_get_contents(
111 filename:filename.as_ref().to_glib_none().0,
112 &mut contents,
113 length:length.as_mut_ptr(),
114 &mut error,
115 );
116 if error.is_null() {
117 Ok(crate::Slice::from_glib_full_num(
118 ptr:contents,
119 len:length.assume_init() as _,
120 ))
121 } else {
122 Err(from_glib_full(ptr:error))
123 }
124 }
125}
126
127pub fn is_canonical_pspec_name(name: &str) -> bool {
128 name.as_bytes().iter().enumerate().all(|(i: usize, c: &u8)| {
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: &GStr| {
142 reserved_chars_allowed.run_with_gstr(|reserved_chars_allowed: Option<&GStr>| unsafe {
143 from_glib_full(ptr:ffi::g_uri_escape_string(
144 unescaped:unescaped.to_glib_none().0,
145 reserved_chars_allowed:reserved_chars_allowed.to_glib_none().0,
146 allow_utf8: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: &GStr| {
158 illegal_characters.run_with_gstr(|illegal_characters: Option<&GStr>| unsafe {
159 from_glib_full(ptr:ffi::g_uri_unescape_string(
160 escaped_string:escaped_string.to_glib_none().0,
161 illegal_characters: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: &GStr| unsafe {
170 from_glib_full(ptr:ffi::g_uri_parse_scheme(uri: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: Option<&GStr>| {
181 escaped_string_end.run_with_gstr(|escaped_string_end: Option<&GStr>| {
182 illegal_characters.run_with_gstr(|illegal_characters: Option<&GStr>| unsafe {
183 from_glib_full(ptr:ffi::g_uri_unescape_segment(
184 escaped_string:escaped_string.to_glib_none().0,
185 escaped_string_end:escaped_string_end.to_glib_none().0,
186 illegal_characters:illegal_characters.to_glib_none().0,
187 ))
188 })
189 })
190 })
191}
192
193#[cfg(test)]
194mod tests {
195 use std::{env, sync::Mutex};
196
197 //Mutex to prevent run environment tests parallel
198 static LOCK: once_cell::sync::Lazy<Mutex<()>> = once_cell::sync::Lazy::new(|| Mutex::new(()));
199
200 const VAR_NAME: &str = "function_environment_test";
201
202 fn check_getenv(val: &str) {
203 let _data = LOCK.lock().unwrap();
204
205 env::set_var(VAR_NAME, val);
206 assert_eq!(env::var_os(VAR_NAME), Some(val.into()));
207 assert_eq!(crate::getenv(VAR_NAME), Some(val.into()));
208
209 let environ = crate::environ();
210 assert_eq!(crate::environ_getenv(&environ, VAR_NAME), Some(val.into()));
211 }
212
213 fn check_setenv(val: &str) {
214 let _data = LOCK.lock().unwrap();
215
216 crate::setenv(VAR_NAME, val, true).unwrap();
217 assert_eq!(env::var_os(VAR_NAME), Some(val.into()));
218 }
219
220 #[test]
221 fn getenv() {
222 check_getenv("Test");
223 check_getenv("Тест"); // "Test" in Russian
224 }
225
226 #[test]
227 fn setenv() {
228 check_setenv("Test");
229 check_setenv("Тест"); // "Test" in Russian
230 }
231
232 #[test]
233 fn test_filename_from_uri() {
234 use std::path::PathBuf;
235
236 use crate::GString;
237 let uri: GString = "file:///foo/bar.txt".into();
238 if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) {
239 assert_eq!(filename, PathBuf::from(r"/foo/bar.txt"));
240 assert_eq!(hostname, None);
241 } else {
242 unreachable!();
243 }
244
245 let uri: GString = "file://host/foo/bar.txt".into();
246 if let Ok((filename, hostname)) = crate::filename_from_uri(&uri) {
247 assert_eq!(filename, PathBuf::from(r"/foo/bar.txt"));
248 assert_eq!(hostname, Some(GString::from("host")));
249 } else {
250 unreachable!();
251 }
252 }
253
254 #[test]
255 fn test_uri_parsing() {
256 use crate::GString;
257 assert_eq!(
258 crate::uri_parse_scheme("foo://bar"),
259 Some(GString::from("foo"))
260 );
261 assert_eq!(crate::uri_parse_scheme("foo"), None);
262
263 let escaped = crate::uri_escape_string("&foo", crate::NONE_STR, true);
264 assert_eq!(escaped, GString::from("%26foo"));
265
266 let unescaped = crate::uri_unescape_string(escaped.as_str(), crate::GStr::NONE);
267 assert_eq!(unescaped, Some(GString::from("&foo")));
268
269 assert_eq!(
270 crate::uri_unescape_segment(Some("/foo"), crate::NONE_STR, crate::NONE_STR),
271 Some(GString::from("/foo"))
272 );
273 assert_eq!(
274 crate::uri_unescape_segment(Some("/foo%"), crate::NONE_STR, crate::NONE_STR),
275 None
276 );
277 }
278}
279