glib/
key_file.rs

1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::{mem, path, ptr};
4
5use crate::{ffi, translate::*, Error, GString, GStringPtr, KeyFile, KeyFileFlags, PtrSlice};
6
7impl KeyFile {
8    /// Writes the contents of @self to @filename using
9    /// [`file_set_contents()`][crate::file_set_contents()].
10    ///
11    /// If you need stricter guarantees about durability of
12    /// the written file than are provided by [`file_set_contents()`][crate::file_set_contents()], use
13    /// [`file_set_contents_full()`][crate::file_set_contents_full()] with the return value of
14    /// [`to_data()`][Self::to_data()].
15    ///
16    /// This function can fail for any of the reasons that
17    /// [`file_set_contents()`][crate::file_set_contents()] may fail.
18    /// ## `filename`
19    /// the name of the file to write to
20    ///
21    /// # Returns
22    ///
23    /// true if successful, false otherwise
24    #[doc(alias = "g_key_file_save_to_file")]
25    pub fn save_to_file<T: AsRef<std::path::Path>>(&self, filename: T) -> Result<(), Error> {
26        unsafe {
27            let mut error = ptr::null_mut();
28            let _ = ffi::g_key_file_save_to_file(
29                self.to_glib_none().0,
30                filename.as_ref().to_glib_none().0,
31                &mut error,
32            );
33            if error.is_null() {
34                Ok(())
35            } else {
36                Err(from_glib_full(error))
37            }
38        }
39    }
40
41    /// Looks for a key file named @file in the paths returned from
42    /// [`user_data_dir()`][crate::user_data_dir()] and [`system_data_dirs()`][crate::system_data_dirs()].
43    ///
44    /// The search algorithm from [`load_from_dirs()`][Self::load_from_dirs()] is used. If
45    /// @file is found, it’s loaded into @self and its full path is returned in
46    /// @full_path.
47    ///
48    /// If the file could not be loaded then either a [`FileError`][crate::FileError] or
49    /// [`KeyFileError`][crate::KeyFileError] is returned.
50    /// ## `file`
51    /// a relative path to a filename to open and parse
52    /// ## `flags`
53    /// flags from [`KeyFileFlags`][crate::KeyFileFlags]
54    ///
55    /// # Returns
56    ///
57    /// true if a key file could be loaded, false otherwise
58    ///
59    /// ## `full_path`
60    /// return location for a string
61    ///    containing the full path of the file, or `NULL` to ignore
62    #[doc(alias = "g_key_file_load_from_data_dirs")]
63    pub fn load_from_data_dirs<T: AsRef<std::path::Path>>(
64        &self,
65        file: T,
66        flags: KeyFileFlags,
67    ) -> Result<path::PathBuf, Error> {
68        unsafe {
69            let mut error = ptr::null_mut();
70            let mut full_path: *mut libc::c_char = ptr::null_mut();
71            let _ = ffi::g_key_file_load_from_data_dirs(
72                self.to_glib_none().0,
73                file.as_ref().to_glib_none().0,
74                &mut full_path,
75                flags.into_glib(),
76                &mut error,
77            );
78            if error.is_null() {
79                let path: GString = from_glib_full(full_path);
80                Ok(path::PathBuf::from(&path))
81            } else {
82                Err(from_glib_full(error))
83            }
84        }
85    }
86
87    /// Looks for a key file named @file in the paths specified in @search_dirs,
88    /// loads the file into @self and returns the file’s full path in @full_path.
89    ///
90    /// @search_dirs are checked in the order listed in the array, with the highest
91    /// priority directory listed first. Within each directory, @file is looked for.
92    /// If it’s not found, `-` characters in @file are progressively replaced with
93    /// directory separators to search subdirectories of the search directory. If the
94    /// file has not been found after all `-` characters have been replaced, the next
95    /// search directory in @search_dirs is checked.
96    ///
97    /// If the file could not be found in any of the @search_dirs,
98    /// [error@GLib.KeyFileError.NOT_FOUND] is returned. If
99    /// the file is found but the OS returns an error when opening or reading the
100    /// file, a [`FileError`][crate::FileError] is returned. If there is a problem parsing the
101    /// file, a [`KeyFileError`][crate::KeyFileError] is returned.
102    /// ## `file`
103    /// a relative path to a filename to open and parse
104    /// ## `search_dirs`
105    /// `NULL`-terminated
106    ///    array of directories to search
107    /// ## `flags`
108    /// flags from [`KeyFileFlags`][crate::KeyFileFlags]
109    ///
110    /// # Returns
111    ///
112    /// true if a key file could be loaded, false otherwise
113    ///
114    /// ## `full_path`
115    /// return location for a string
116    ///    containing the full path of the file, or `NULL` to ignore
117    #[doc(alias = "g_key_file_load_from_dirs")]
118    pub fn load_from_dirs<T: AsRef<std::path::Path>, U: AsRef<std::path::Path>>(
119        &self,
120        file: T,
121        search_dirs: &[U],
122        flags: KeyFileFlags,
123    ) -> Result<path::PathBuf, Error> {
124        unsafe {
125            let search_dirs: Vec<&std::path::Path> =
126                search_dirs.iter().map(AsRef::as_ref).collect();
127            let mut error = ptr::null_mut();
128            let mut full_path: *mut libc::c_char = ptr::null_mut();
129            let _ = ffi::g_key_file_load_from_dirs(
130                self.to_glib_none().0,
131                file.as_ref().to_glib_none().0,
132                search_dirs.to_glib_none().0,
133                &mut full_path,
134                flags.into_glib(),
135                &mut error,
136            );
137            if error.is_null() {
138                let path: GString = from_glib_full(full_path);
139                Ok(path::PathBuf::from(&path))
140            } else {
141                Err(from_glib_full(error))
142            }
143        }
144    }
145
146    /// Outputs @self as a string.
147    ///
148    /// Note that this function never reports an error.
149    ///
150    /// # Returns
151    ///
152    /// a newly allocated string holding the contents of the key file
153    ///
154    /// ## `length`
155    /// return location for the length of the
156    ///   returned string, or `NULL` to ignore
157    #[doc(alias = "g_key_file_to_data")]
158    pub fn to_data(&self) -> GString {
159        unsafe {
160            let ret =
161                ffi::g_key_file_to_data(self.to_glib_none().0, ptr::null_mut(), ptr::null_mut());
162            from_glib_full(ret)
163        }
164    }
165
166    /// Returns all groups in the key file loaded with @self.
167    ///
168    /// The array of returned groups will be `NULL`-terminated, so
169    /// @length may optionally be `NULL`.
170    ///
171    /// # Returns
172    ///
173    /// a newly-allocated
174    ///    `NULL`-terminated array of strings. Use `strfreev()` to free it.
175    ///
176    /// ## `length`
177    /// return location for the number of returned groups,
178    ///    or `NULL` to ignore
179    #[doc(alias = "g_key_file_get_groups")]
180    #[doc(alias = "get_groups")]
181    pub fn groups(&self) -> PtrSlice<GStringPtr> {
182        unsafe {
183            let mut length = mem::MaybeUninit::uninit();
184            let ret = ffi::g_key_file_get_groups(self.to_glib_none().0, length.as_mut_ptr());
185            FromGlibContainer::from_glib_full_num(ret, length.assume_init() as _)
186        }
187    }
188
189    /// Returns all keys for the group name @group_name.
190    ///
191    /// The array of returned keys will be `NULL`-terminated, so @length may
192    /// optionally be `NULL`. If the @group_name cannot be found,
193    /// [error@GLib.KeyFileError.GROUP_NOT_FOUND] is returned.
194    /// ## `group_name`
195    /// a group name
196    ///
197    /// # Returns
198    ///
199    /// a newly-allocated
200    ///    `NULL`-terminated array of strings. Use `strfreev()` to free it.
201    ///
202    /// ## `length`
203    /// return location for the number of keys returned,
204    ///    or `NULL` to ignore
205    #[doc(alias = "g_key_file_get_keys")]
206    #[doc(alias = "get_keys")]
207    pub fn keys(&self, group_name: &str) -> Result<PtrSlice<GStringPtr>, crate::Error> {
208        unsafe {
209            let mut length = mem::MaybeUninit::uninit();
210            let mut error = ptr::null_mut();
211            let ret = ffi::g_key_file_get_keys(
212                self.to_glib_none().0,
213                group_name.to_glib_none().0,
214                length.as_mut_ptr(),
215                &mut error,
216            );
217            if error.is_null() {
218                Ok(FromGlibContainer::from_glib_full_num(
219                    ret,
220                    length.assume_init() as _,
221                ))
222            } else {
223                Err(from_glib_full(error))
224            }
225        }
226    }
227
228    /// Returns the value associated with @key under @group_name as a
229    /// boolean.
230    ///
231    /// If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
232    /// returned. Likewise, if the value associated with @key cannot be interpreted
233    /// as a boolean then [error@GLib.KeyFileError.INVALID_VALUE] is returned.
234    /// ## `group_name`
235    /// a group name
236    /// ## `key`
237    /// a key
238    ///
239    /// # Returns
240    ///
241    /// the value associated with the key as a boolean,
242    ///    or false if the key was not found or could not be parsed.
243    #[doc(alias = "g_key_file_get_boolean")]
244    #[doc(alias = "get_boolean")]
245    pub fn boolean(&self, group_name: &str, key: &str) -> Result<bool, Error> {
246        unsafe {
247            let mut error = ptr::null_mut();
248            let ret = ffi::g_key_file_get_boolean(
249                self.to_glib_none().0,
250                group_name.to_glib_none().0,
251                key.to_glib_none().0,
252                &mut error,
253            );
254            if error.is_null() {
255                Ok(from_glib(ret))
256            } else {
257                Err(from_glib_full(error))
258            }
259        }
260    }
261
262    /// Looks whether the key file has the key @key in the group
263    /// @group_name.
264    ///
265    /// Note that this function does not follow the rules for [`Error`][crate::Error]
266    /// strictly;
267    /// the return value both carries meaning and signals an error.  To use
268    /// this function, you must pass a [`Error`][crate::Error] pointer in @error, and
269    /// check whether it is not `NULL` to see if an error occurred.
270    ///
271    /// Language bindings should use [`value()`][Self::value()] to test whether
272    /// a key exists.
273    /// ## `group_name`
274    /// a group name
275    /// ## `key`
276    /// a key name
277    ///
278    /// # Returns
279    ///
280    /// true if @key is a part of @group_name, false otherwise
281    #[doc(alias = "g_key_file_has_key")]
282    pub fn has_key(&self, group_name: &str, key: &str) -> Result<bool, Error> {
283        unsafe {
284            let mut error = ptr::null_mut();
285            let ret = ffi::g_key_file_has_key(
286                self.to_glib_none().0,
287                group_name.to_glib_none().0,
288                key.to_glib_none().0,
289                &mut error,
290            );
291            if error.is_null() {
292                Ok(from_glib(ret))
293            } else {
294                Err(from_glib_full(error))
295            }
296        }
297    }
298
299    /// Returns the values associated with @key under @group_name as
300    /// booleans.
301    ///
302    /// If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
303    /// returned. Likewise, if the values associated with @key cannot be interpreted
304    /// as booleans then [error@GLib.KeyFileError.INVALID_VALUE] is returned.
305    /// ## `group_name`
306    /// a group name
307    /// ## `key`
308    /// a key
309    ///
310    /// # Returns
311    ///
312    ///
313    ///    the values associated with the key as a list of booleans, or `NULL` if the
314    ///    key was not found or could not be parsed. The returned list of booleans
315    ///    should be freed with `free()` when no longer needed.
316    #[doc(alias = "g_key_file_get_boolean_list")]
317    #[doc(alias = "get_boolean_list")]
318    pub fn boolean_list(&self, group_name: &str, key: &str) -> Result<Vec<bool>, Error> {
319        unsafe {
320            let mut length = mem::MaybeUninit::uninit();
321            let mut error = ptr::null_mut();
322            let ret = ffi::g_key_file_get_boolean_list(
323                self.to_glib_none().0,
324                group_name.to_glib_none().0,
325                key.to_glib_none().0,
326                length.as_mut_ptr(),
327                &mut error,
328            );
329            if !error.is_null() {
330                return Err(from_glib_full(error));
331            }
332            Ok(FromGlibContainer::from_glib_container_num(
333                ret,
334                length.assume_init() as _,
335            ))
336        }
337    }
338
339    /// Returns the string value associated with @key under @group_name.
340    ///
341    /// Unlike [`value()`][Self::value()], this function handles escape
342    /// sequences like `\s`.
343    ///
344    /// If the key cannot be found, [error@GLib.KeyFileError.KEY_NOT_FOUND] is
345    /// returned. If the @group_name cannot be found,
346    /// [error@GLib.KeyFileError.GROUP_NOT_FOUND] is returned.
347    /// ## `group_name`
348    /// a group name
349    /// ## `key`
350    /// a key
351    ///
352    /// # Returns
353    ///
354    /// a newly allocated string or `NULL` if the specified
355    ///   key cannot be found.
356    #[doc(alias = "g_key_file_get_string")]
357    #[doc(alias = "get_string")]
358    pub fn string(&self, group_name: &str, key: &str) -> Result<GString, Error> {
359        unsafe {
360            let mut error = ptr::null_mut();
361            let ret = ffi::g_key_file_get_string(
362                self.to_glib_none().0,
363                group_name.to_glib_none().0,
364                key.to_glib_none().0,
365                &mut error,
366            );
367            if error.is_null() {
368                Ok(from_glib_full(ret))
369            } else {
370                ffi::g_free(ret as *mut _);
371                Err(from_glib_full(error))
372            }
373        }
374    }
375
376    /// Returns the values associated with @key under @group_name.
377    ///
378    /// If the key cannot be found, [error@GLib.KeyFileError.KEY_NOT_FOUND] is
379    /// returned. If the @group_name cannot be found,
380    /// [error@GLib.KeyFileError.GROUP_NOT_FOUND] is returned.
381    /// ## `group_name`
382    /// a group name
383    /// ## `key`
384    /// a key
385    ///
386    /// # Returns
387    ///
388    ///
389    ///  a `NULL`-terminated string array or `NULL` if the specified
390    ///  key cannot be found. The array should be freed with `strfreev()`.
391    #[doc(alias = "g_key_file_get_string_list")]
392    #[doc(alias = "get_string_list")]
393    pub fn string_list(&self, group_name: &str, key: &str) -> Result<PtrSlice<GStringPtr>, Error> {
394        unsafe {
395            let mut length = mem::MaybeUninit::uninit();
396            let mut error = ptr::null_mut();
397            let ret = ffi::g_key_file_get_string_list(
398                self.to_glib_none().0,
399                group_name.to_glib_none().0,
400                key.to_glib_none().0,
401                length.as_mut_ptr(),
402                &mut error,
403            );
404            if error.is_null() {
405                Ok(FromGlibContainer::from_glib_full_num(
406                    ret,
407                    length.assume_init() as _,
408                ))
409            } else {
410                ffi::g_strfreev(ret);
411                Err(from_glib_full(error))
412            }
413        }
414    }
415
416    /// Returns the value associated with @key under @group_name
417    /// translated in the given @locale if available.
418    ///
419    /// If @locale is `C` then the untranslated value is returned (since GLib 2.84).
420    ///
421    /// If @locale is `NULL` then the current locale is assumed.
422    ///
423    /// If @locale is to be non-`NULL`, or if the current locale will change over
424    /// the lifetime of the [`KeyFile`][crate::KeyFile], it must be loaded with
425    /// [flags@GLib.KeyFileFlags.KEEP_TRANSLATIONS] in order to load strings for all
426    /// locales.
427    ///
428    /// If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
429    /// returned. If the value associated
430    /// with @key cannot be interpreted or no suitable translation can
431    /// be found then the untranslated value is returned.
432    /// ## `group_name`
433    /// a group name
434    /// ## `key`
435    /// a key
436    /// ## `locale`
437    /// a locale identifier or `NULL` to use the current locale
438    ///
439    /// # Returns
440    ///
441    /// a newly allocated string or `NULL` if the specified
442    ///   key cannot be found.
443    #[doc(alias = "g_key_file_get_locale_string")]
444    #[doc(alias = "get_locale_string")]
445    pub fn locale_string(
446        &self,
447        group_name: &str,
448        key: &str,
449        locale: Option<&str>,
450    ) -> Result<GString, Error> {
451        unsafe {
452            let mut error = ptr::null_mut();
453            let ret = ffi::g_key_file_get_locale_string(
454                self.to_glib_none().0,
455                group_name.to_glib_none().0,
456                key.to_glib_none().0,
457                locale.to_glib_none().0,
458                &mut error,
459            );
460            if error.is_null() {
461                Ok(from_glib_full(ret))
462            } else {
463                ffi::g_free(ret as *mut _);
464                Err(from_glib_full(error))
465            }
466        }
467    }
468
469    /// Returns the values associated with @key under @group_name
470    /// translated in the given @locale if available.
471    ///
472    /// If @locale is `C` then the untranslated value is returned (since GLib 2.84).
473    ///
474    /// If @locale is `NULL` then the current locale is assumed.
475    ///
476    /// If @locale is to be non-`NULL`, or if the current locale will change over
477    /// the lifetime of the [`KeyFile`][crate::KeyFile], it must be loaded with
478    /// [flags@GLib.KeyFileFlags.KEEP_TRANSLATIONS] in order to load strings for all
479    /// locales.
480    ///
481    /// If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
482    /// returned. If the values associated
483    /// with @key cannot be interpreted or no suitable translations
484    /// can be found then the untranslated values are returned. The
485    /// returned array is `NULL`-terminated, so @length may optionally
486    /// be `NULL`.
487    /// ## `group_name`
488    /// a group name
489    /// ## `key`
490    /// a key
491    /// ## `locale`
492    /// a locale identifier or `NULL` to use the current locale
493    ///
494    /// # Returns
495    ///
496    ///
497    ///    a newly allocated `NULL`-terminated string array or `NULL` if the key
498    ///    isn’t found. The string array should be freed with `strfreev()`.
499    #[doc(alias = "g_key_file_get_locale_string_list")]
500    #[doc(alias = "get_locale_string_list")]
501    pub fn locale_string_list(
502        &self,
503        group_name: &str,
504        key: &str,
505        locale: Option<&str>,
506    ) -> Result<PtrSlice<GStringPtr>, Error> {
507        unsafe {
508            let mut length = mem::MaybeUninit::uninit();
509            let mut error = ptr::null_mut();
510            let ret = ffi::g_key_file_get_locale_string_list(
511                self.to_glib_none().0,
512                group_name.to_glib_none().0,
513                key.to_glib_none().0,
514                locale.to_glib_none().0,
515                length.as_mut_ptr(),
516                &mut error,
517            );
518            if error.is_null() {
519                Ok(FromGlibContainer::from_glib_full_num(
520                    ret,
521                    length.assume_init() as _,
522                ))
523            } else {
524                ffi::g_strfreev(ret);
525                Err(from_glib_full(error))
526            }
527        }
528    }
529}