Skip to main content

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