Skip to main content

glib/auto/
key_file.rs

1// This file was generated by gir (https://github.com/gtk-rs/gir)
2// from gir-files (https://github.com/gtk-rs/gir-files)
3// DO NOT EDIT
4
5use crate::{Bytes, Error, KeyFileFlags, ffi, translate::*};
6
7crate::wrapper! {
8    /// `GKeyFile` parses .ini-like config files.
9    ///
10    /// `GKeyFile` lets you parse, edit or create files containing groups of
11    /// key-value pairs, which we call ‘key files’ for lack of a better name.
12    /// Several freedesktop.org specifications use key files. For example, the
13    /// [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/)
14    /// and the [Icon Theme Specification](https://specifications.freedesktop.org/icon-theme-spec/latest/).
15    ///
16    /// The syntax of key files is described in detail in the
17    /// [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/),
18    /// here is a quick summary: Key files consists of groups of key-value pairs, interspersed
19    /// with comments.
20    ///
21    /// **⚠️ The following code is in txt ⚠️**
22    ///
23    /// ```txt
24    /// # this is just an example
25    /// # there can be comments before the first group
26    ///
27    /// [First Group]
28    ///
29    /// Name=Key File Example\tthis value shows\nescaping
30    ///
31    /// # localized strings are stored in multiple key-value pairs
32    /// Welcome=Hello
33    /// Welcome[de]=Hallo
34    /// Welcome[fr_FR]=Bonjour
35    /// Welcome[it]=Ciao
36    ///
37    /// [Another Group]
38    ///
39    /// Numbers=2;20;-200;0
40    ///
41    /// Booleans=true;false;true;true
42    /// ```
43    ///
44    /// Lines beginning with a `#` and blank lines are considered comments.
45    ///
46    /// Groups are started by a header line containing the group name enclosed
47    /// in `[` and `]`, and ended implicitly by the start of the next group or
48    /// the end of the file. Each key-value pair must be contained in a group.
49    ///
50    /// Key-value pairs generally have the form `key=value`, with the exception
51    /// of localized strings, which have the form `key[locale]=value`, with a
52    /// locale identifier of the form `lang_COUNTRY@MODIFIER` where `COUNTRY`
53    /// and `MODIFIER` are optional. As a special case, the locale `C` is associated
54    /// with the untranslated pair `key=value` (since GLib 2.84). Space before and
55    /// after the `=` character is ignored. Newline, tab, carriage return and
56    /// backslash characters in value are escaped as `\n`, `\t`, `\r`, and `\\\\`,
57    /// respectively. To preserve leading spaces in values, these can also be escaped
58    /// as `\s`.
59    ///
60    /// Key files can store strings (possibly with localized variants), integers,
61    /// booleans and lists of these. Lists are separated by a separator character,
62    /// typically `;` or `,`. To use the list separator character in a value in
63    /// a list, it has to be escaped by prefixing it with a backslash.
64    ///
65    /// This syntax is obviously inspired by the .ini files commonly met
66    /// on Windows, but there are some important differences:
67    ///
68    /// - .ini files use the `;` character to begin comments,
69    ///   key files use the `#` character.
70    ///
71    /// - Key files do not allow for ungrouped keys meaning only
72    ///   comments can precede the first group.
73    ///
74    /// - Key files are always encoded in UTF-8.
75    ///
76    /// - Key and Group names are case-sensitive. For example, a group called
77    ///   `[GROUP]` is a different from `[group]`.
78    ///
79    /// - .ini files don’t have a strongly typed boolean entry type,
80    ///    they only have `GetProfileInt()`. In key files, only
81    ///    `true` and `false` (in lower case) are allowed.
82    ///
83    /// Note that in contrast to the
84    /// [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/),
85    /// groups in key files may contain the same key multiple times; the last entry wins.
86    /// Key files may also contain multiple groups with the same name; they are merged
87    /// together. Another difference is that keys and group names in key files are not
88    /// restricted to ASCII characters.
89    ///
90    /// Here is an example of loading a key file and reading a value:
91    ///
92    /// **⚠️ The following code is in c ⚠️**
93    ///
94    /// ```c
95    /// g_autoptr(GError) error = NULL;
96    /// g_autoptr(GKeyFile) key_file = g_key_file_new ();
97    ///
98    /// if (!g_key_file_load_from_file (key_file, "key-file.ini", flags, &error))
99    ///   {
100    ///     if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
101    ///       g_warning ("Error loading key file: %s", error->message);
102    ///     return;
103    ///   }
104    ///
105    /// g_autofree gchar *val = g_key_file_get_string (key_file, "Group Name", "SomeKey", &error);
106    /// if (val == NULL &&
107    ///     !g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
108    ///   {
109    ///     g_warning ("Error finding key in key file: %s", error->message);
110    ///     return;
111    ///   }
112    /// else if (val == NULL)
113    ///   {
114    ///     // Fall back to a default value.
115    ///     val = g_strdup ("default-value");
116    ///   }
117    /// ```
118    ///
119    /// Here is an example of creating and saving a key file:
120    ///
121    /// **⚠️ The following code is in c ⚠️**
122    ///
123    /// ```c
124    /// g_autoptr(GKeyFile) key_file = g_key_file_new ();
125    /// const gchar *val = …;
126    /// g_autoptr(GError) error = NULL;
127    ///
128    /// g_key_file_set_string (key_file, "Group Name", "SomeKey", val);
129    ///
130    /// // Save as a file.
131    /// if (!g_key_file_save_to_file (key_file, "key-file.ini", &error))
132    ///   {
133    ///     g_warning ("Error saving key file: %s", error->message);
134    ///     return;
135    ///   }
136    ///
137    /// // Or store to a GBytes for use elsewhere.
138    /// gsize data_len;
139    /// g_autofree guint8 *data = (guint8 *) g_key_file_to_data (key_file, &data_len, &error);
140    /// if (data == NULL)
141    ///   {
142    ///     g_warning ("Error saving key file: %s", error->message);
143    ///     return;
144    ///   }
145    /// g_autoptr(GBytes) bytes = g_bytes_new_take (g_steal_pointer (&data), data_len);
146    /// ```
147    #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
148    pub struct KeyFile(Shared<ffi::GKeyFile>);
149
150    match fn {
151        ref => |ptr| ffi::g_key_file_ref(ptr),
152        unref => |ptr| ffi::g_key_file_unref(ptr),
153        type_ => || ffi::g_key_file_get_type(),
154    }
155}
156
157impl KeyFile {
158    /// Creates a new empty [`KeyFile`][crate::KeyFile] object.
159    ///
160    /// Use [`load_from_file()`][Self::load_from_file()],
161    /// [`load_from_data()`][Self::load_from_data()], [`load_from_dirs()`][Self::load_from_dirs()] or
162    /// [`load_from_data_dirs()`][Self::load_from_data_dirs()] to
163    /// read an existing key file.
164    ///
165    /// # Returns
166    ///
167    /// an empty [`KeyFile`][crate::KeyFile].
168    #[doc(alias = "g_key_file_new")]
169    pub fn new() -> KeyFile {
170        unsafe { from_glib_full(ffi::g_key_file_new()) }
171    }
172
173    /// Retrieves a comment above @key from @group_name.
174    ///
175    /// If @key is `NULL` then @comment will be read from above
176    /// @group_name. If both @key and @group_name are `NULL`, then
177    /// @comment will be read from above the first group in the file.
178    ///
179    /// Note that the returned string does not include the `#` comment markers,
180    /// but does include any whitespace after them (on each line). It includes
181    /// the line breaks between lines, but does not include the final line break.
182    /// ## `group_name`
183    /// a group name, or `NULL` to get a top-level comment
184    /// ## `key`
185    /// a key, or `NULL` to get a group comment
186    ///
187    /// # Returns
188    ///
189    /// a comment that should be freed with `free()`
190    #[doc(alias = "g_key_file_get_comment")]
191    #[doc(alias = "get_comment")]
192    pub fn comment(
193        &self,
194        group_name: Option<&str>,
195        key: Option<&str>,
196    ) -> Result<crate::GString, crate::Error> {
197        unsafe {
198            let mut error = std::ptr::null_mut();
199            let ret = ffi::g_key_file_get_comment(
200                self.to_glib_none().0,
201                group_name.to_glib_none().0,
202                key.to_glib_none().0,
203                &mut error,
204            );
205            if error.is_null() {
206                Ok(from_glib_full(ret))
207            } else {
208                Err(from_glib_full(error))
209            }
210        }
211    }
212
213    /// Returns the value associated with @key under @group_name as a double.
214    ///
215    /// If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
216    /// returned. Likewise, if the value associated with @key cannot be interpreted
217    /// as a double then [error@GLib.KeyFileError.INVALID_VALUE] is returned.
218    /// ## `group_name`
219    /// a group name
220    /// ## `key`
221    /// a key
222    ///
223    /// # Returns
224    ///
225    /// the value associated with the key as a double, or
226    ///     `0.0` if the key was not found or could not be parsed.
227    #[doc(alias = "g_key_file_get_double")]
228    #[doc(alias = "get_double")]
229    pub fn double(&self, group_name: &str, key: &str) -> Result<f64, crate::Error> {
230        unsafe {
231            let mut error = std::ptr::null_mut();
232            let ret = ffi::g_key_file_get_double(
233                self.to_glib_none().0,
234                group_name.to_glib_none().0,
235                key.to_glib_none().0,
236                &mut error,
237            );
238            if error.is_null() {
239                Ok(ret)
240            } else {
241                Err(from_glib_full(error))
242            }
243        }
244    }
245
246    /// Returns the values associated with @key under @group_name as
247    /// doubles.
248    ///
249    /// If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
250    /// returned. Likewise, if the values associated with @key cannot be interpreted
251    /// as doubles then [error@GLib.KeyFileError.INVALID_VALUE] is returned.
252    /// ## `group_name`
253    /// a group name
254    /// ## `key`
255    /// a key
256    ///
257    /// # Returns
258    ///
259    ///
260    ///     the values associated with the key as a list of doubles, or `NULL` if the
261    ///     key was not found or could not be parsed. The returned list of doubles
262    ///     should be freed with `free()` when no longer needed.
263    #[doc(alias = "g_key_file_get_double_list")]
264    #[doc(alias = "get_double_list")]
265    pub fn double_list(&self, group_name: &str, key: &str) -> Result<Vec<f64>, crate::Error> {
266        unsafe {
267            let mut length = std::mem::MaybeUninit::uninit();
268            let mut error = std::ptr::null_mut();
269            let ret = ffi::g_key_file_get_double_list(
270                self.to_glib_none().0,
271                group_name.to_glib_none().0,
272                key.to_glib_none().0,
273                length.as_mut_ptr(),
274                &mut error,
275            );
276            if error.is_null() {
277                Ok(FromGlibContainer::from_glib_container_num(
278                    ret,
279                    length.assume_init() as _,
280                ))
281            } else {
282                Err(from_glib_full(error))
283            }
284        }
285    }
286
287    /// Returns the value associated with @key under @group_name as a signed
288    /// 64-bit integer.
289    ///
290    /// This is similar to [`integer()`][Self::integer()] but can return
291    /// 64-bit results without truncation.
292    /// ## `group_name`
293    /// a group name
294    /// ## `key`
295    /// a key
296    ///
297    /// # Returns
298    ///
299    /// the value associated with the key as a signed 64-bit integer, or
300    ///    `0` if the key was not found or could not be parsed.
301    #[doc(alias = "g_key_file_get_int64")]
302    #[doc(alias = "get_int64")]
303    pub fn int64(&self, group_name: &str, key: &str) -> Result<i64, crate::Error> {
304        unsafe {
305            let mut error = std::ptr::null_mut();
306            let ret = ffi::g_key_file_get_int64(
307                self.to_glib_none().0,
308                group_name.to_glib_none().0,
309                key.to_glib_none().0,
310                &mut error,
311            );
312            if error.is_null() {
313                Ok(ret)
314            } else {
315                Err(from_glib_full(error))
316            }
317        }
318    }
319
320    /// Returns the value associated with @key under @group_name as an
321    /// integer.
322    ///
323    /// If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
324    /// returned. Likewise, if the value associated with @key cannot be interpreted
325    /// as an integer, or is out of range for a `gint`, then
326    /// [error@GLib.KeyFileError.INVALID_VALUE] is returned.
327    /// ## `group_name`
328    /// a group name
329    /// ## `key`
330    /// a key
331    ///
332    /// # Returns
333    ///
334    /// the value associated with the key as an integer, or
335    ///     `0` if the key was not found or could not be parsed.
336    #[doc(alias = "g_key_file_get_integer")]
337    #[doc(alias = "get_integer")]
338    pub fn integer(&self, group_name: &str, key: &str) -> Result<i32, crate::Error> {
339        unsafe {
340            let mut error = std::ptr::null_mut();
341            let ret = ffi::g_key_file_get_integer(
342                self.to_glib_none().0,
343                group_name.to_glib_none().0,
344                key.to_glib_none().0,
345                &mut error,
346            );
347            if error.is_null() {
348                Ok(ret)
349            } else {
350                Err(from_glib_full(error))
351            }
352        }
353    }
354
355    /// Returns the values associated with @key under @group_name as
356    /// integers.
357    ///
358    /// If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
359    /// returned. Likewise, if the values associated with @key cannot be interpreted
360    /// as integers, or are out of range for `gint`, then
361    /// [error@GLib.KeyFileError.INVALID_VALUE] is returned.
362    /// ## `group_name`
363    /// a group name
364    /// ## `key`
365    /// a key
366    ///
367    /// # Returns
368    ///
369    ///
370    ///     the values associated with the key as a list of integers, or `NULL` if
371    ///     the key was not found or could not be parsed. The returned list of
372    ///     integers should be freed with `free()` when no longer needed.
373    #[doc(alias = "g_key_file_get_integer_list")]
374    #[doc(alias = "get_integer_list")]
375    pub fn integer_list(&self, group_name: &str, key: &str) -> Result<Vec<i32>, crate::Error> {
376        unsafe {
377            let mut length = std::mem::MaybeUninit::uninit();
378            let mut error = std::ptr::null_mut();
379            let ret = ffi::g_key_file_get_integer_list(
380                self.to_glib_none().0,
381                group_name.to_glib_none().0,
382                key.to_glib_none().0,
383                length.as_mut_ptr(),
384                &mut error,
385            );
386            if error.is_null() {
387                Ok(FromGlibContainer::from_glib_container_num(
388                    ret,
389                    length.assume_init() as _,
390                ))
391            } else {
392                Err(from_glib_full(error))
393            }
394        }
395    }
396
397    /// Returns the actual locale which the result of
398    /// [`locale_string()`][Self::locale_string()] or
399    /// [`locale_string_list()`][Self::locale_string_list()] came from.
400    ///
401    /// If calling [`locale_string()`][Self::locale_string()] or
402    /// [`locale_string_list()`][Self::locale_string_list()] with exactly the same @self,
403    /// @group_name, @key and @locale, the result of those functions will
404    /// have originally been tagged with the locale that is the result of
405    /// this function.
406    /// ## `group_name`
407    /// a group name
408    /// ## `key`
409    /// a key
410    /// ## `locale`
411    /// a locale identifier or `NULL` to use the current locale
412    ///
413    /// # Returns
414    ///
415    /// the locale from the file, or `NULL` if the key was not
416    ///   found or the entry in the file was was untranslated
417    #[doc(alias = "g_key_file_get_locale_for_key")]
418    #[doc(alias = "get_locale_for_key")]
419    pub fn locale_for_key(
420        &self,
421        group_name: &str,
422        key: &str,
423        locale: Option<&str>,
424    ) -> Option<crate::GString> {
425        unsafe {
426            from_glib_full(ffi::g_key_file_get_locale_for_key(
427                self.to_glib_none().0,
428                group_name.to_glib_none().0,
429                key.to_glib_none().0,
430                locale.to_glib_none().0,
431            ))
432        }
433    }
434
435    /// Returns the name of the start group of the file.
436    ///
437    /// # Returns
438    ///
439    /// The start group of the key file.
440    #[doc(alias = "g_key_file_get_start_group")]
441    #[doc(alias = "get_start_group")]
442    pub fn start_group(&self) -> Option<crate::GString> {
443        unsafe { from_glib_full(ffi::g_key_file_get_start_group(self.to_glib_none().0)) }
444    }
445
446    /// Returns the value associated with @key under @group_name as an unsigned
447    /// 64-bit integer.
448    ///
449    /// This is similar to [`integer()`][Self::integer()] but can return
450    /// large positive results without truncation.
451    /// ## `group_name`
452    /// a group name
453    /// ## `key`
454    /// a key
455    ///
456    /// # Returns
457    ///
458    /// the value associated with the key as an unsigned 64-bit integer,
459    ///    or `0` if the key was not found or could not be parsed.
460    #[doc(alias = "g_key_file_get_uint64")]
461    #[doc(alias = "get_uint64")]
462    pub fn uint64(&self, group_name: &str, key: &str) -> Result<u64, crate::Error> {
463        unsafe {
464            let mut error = std::ptr::null_mut();
465            let ret = ffi::g_key_file_get_uint64(
466                self.to_glib_none().0,
467                group_name.to_glib_none().0,
468                key.to_glib_none().0,
469                &mut error,
470            );
471            if error.is_null() {
472                Ok(ret)
473            } else {
474                Err(from_glib_full(error))
475            }
476        }
477    }
478
479    /// Returns the raw value associated with @key under @group_name.
480    ///
481    /// Use [`string()`][Self::string()] to retrieve an unescaped UTF-8 string.
482    ///
483    /// If the key cannot be found, [error@GLib.KeyFileError.KEY_NOT_FOUND]
484    /// is returned.  If the @group_name cannot be found,
485    /// [error@GLib.KeyFileError.GROUP_NOT_FOUND] is returned.
486    /// ## `group_name`
487    /// a group name
488    /// ## `key`
489    /// a key
490    ///
491    /// # Returns
492    ///
493    /// a newly allocated string or `NULL` if the specified
494    ///  key cannot be found.
495    #[doc(alias = "g_key_file_get_value")]
496    #[doc(alias = "get_value")]
497    pub fn value(&self, group_name: &str, key: &str) -> Result<crate::GString, crate::Error> {
498        unsafe {
499            let mut error = std::ptr::null_mut();
500            let ret = ffi::g_key_file_get_value(
501                self.to_glib_none().0,
502                group_name.to_glib_none().0,
503                key.to_glib_none().0,
504                &mut error,
505            );
506            if error.is_null() {
507                Ok(from_glib_full(ret))
508            } else {
509                Err(from_glib_full(error))
510            }
511        }
512    }
513
514    /// Looks whether the key file has the group @group_name.
515    /// ## `group_name`
516    /// a group name
517    ///
518    /// # Returns
519    ///
520    /// true if @group_name is a part of @self, false otherwise.
521    #[doc(alias = "g_key_file_has_group")]
522    pub fn has_group(&self, group_name: &str) -> bool {
523        unsafe {
524            from_glib(ffi::g_key_file_has_group(
525                self.to_glib_none().0,
526                group_name.to_glib_none().0,
527            ))
528        }
529    }
530
531    /// Loads a key file from the data in @bytes into an empty [`KeyFile`][crate::KeyFile]
532    /// structure.
533    ///
534    /// If the object cannot be created then a [`KeyFileError`][crate::KeyFileError] is returned.
535    /// ## `bytes`
536    /// a [`Bytes`][crate::Bytes]
537    /// ## `flags`
538    /// flags from [`KeyFileFlags`][crate::KeyFileFlags]
539    ///
540    /// # Returns
541    ///
542    /// true if a key file could be loaded, false otherwise
543    #[doc(alias = "g_key_file_load_from_bytes")]
544    pub fn load_from_bytes(&self, bytes: &Bytes, flags: KeyFileFlags) -> Result<(), crate::Error> {
545        unsafe {
546            let mut error = std::ptr::null_mut();
547            let is_ok = ffi::g_key_file_load_from_bytes(
548                self.to_glib_none().0,
549                bytes.to_glib_none().0,
550                flags.into_glib(),
551                &mut error,
552            );
553            debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null());
554            if error.is_null() {
555                Ok(())
556            } else {
557                Err(from_glib_full(error))
558            }
559        }
560    }
561
562    /// Loads a key file from memory into an empty [`KeyFile`][crate::KeyFile] structure.
563    ///
564    /// If the object cannot be created then a [`KeyFileError`][crate::KeyFileError] is returned.
565    /// ## `data`
566    /// key file loaded in memory
567    /// ## `length`
568    /// the length of @data in bytes (or `(gsize)-1` if data is nul-terminated)
569    /// ## `flags`
570    /// flags from [`KeyFileFlags`][crate::KeyFileFlags]
571    ///
572    /// # Returns
573    ///
574    /// true if a key file could be loaded, false otherwise
575    #[doc(alias = "g_key_file_load_from_data")]
576    pub fn load_from_data(&self, data: &str, flags: KeyFileFlags) -> Result<(), crate::Error> {
577        let length = data.len() as _;
578        unsafe {
579            let mut error = std::ptr::null_mut();
580            let is_ok = ffi::g_key_file_load_from_data(
581                self.to_glib_none().0,
582                data.to_glib_none().0,
583                length,
584                flags.into_glib(),
585                &mut error,
586            );
587            debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null());
588            if error.is_null() {
589                Ok(())
590            } else {
591                Err(from_glib_full(error))
592            }
593        }
594    }
595
596    /// Loads a key file into an empty [`KeyFile`][crate::KeyFile] structure.
597    ///
598    /// If the OS returns an error when opening or reading the file, a
599    /// [`FileError`][crate::FileError] is returned. If there is a problem parsing the file,
600    /// a [`KeyFileError`][crate::KeyFileError] is returned.
601    ///
602    /// This function will never return a [error@GLib.KeyFileError.NOT_FOUND]
603    /// error. If the @file is not found, [error@GLib.FileError.NOENT] is returned.
604    /// ## `file`
605    /// the path of a filename to load, in the GLib filename encoding
606    /// ## `flags`
607    /// flags from [`KeyFileFlags`][crate::KeyFileFlags]
608    ///
609    /// # Returns
610    ///
611    /// true if a key file could be loaded, false otherwise
612    #[doc(alias = "g_key_file_load_from_file")]
613    pub fn load_from_file(
614        &self,
615        file: impl AsRef<std::path::Path>,
616        flags: KeyFileFlags,
617    ) -> Result<(), crate::Error> {
618        unsafe {
619            let mut error = std::ptr::null_mut();
620            let is_ok = ffi::g_key_file_load_from_file(
621                self.to_glib_none().0,
622                file.as_ref().to_glib_none().0,
623                flags.into_glib(),
624                &mut error,
625            );
626            debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null());
627            if error.is_null() {
628                Ok(())
629            } else {
630                Err(from_glib_full(error))
631            }
632        }
633    }
634
635    /// Evaluates and merges configuration key/values from multiple Unix directories into a single key file.
636    ///
637    /// This function reads and merges all available configuration files based on the rules defined by
638    /// the [UAPI Configuration Files Specification](https://github.com/uapi-group/specifications/blob/main/specs/configuration_files_specification.md) (version 1).
639    ///
640    /// This API is primarily intended for system daemons or CLI tools that need to load systemd-style
641    /// configuration files spread across vendor and customization directories. User applications
642    /// should generally use [`GSettings`](../gio/class.Settings.html) instead to manage user preferences.
643    ///
644    /// ### Directory Layout Guidance
645    /// When choosing paths for @etc_subdir and @usr_subdir, you should prefer using your build
646    /// system's standard configuration variables (such as `$sysconfdir` and `$libdir`) rather
647    /// than hard-coding absolute paths. For context, on a standard Linux layout, @etc_subdir
648    /// typically points to administrative overrides (e.g., `/etc`), @run_subdir to /run while
649    /// @usr_subdir points to the vendor defaults (e.g., `/usr/lib` or `/usr/share`). Passing `NULL`
650    /// will fall back to platform-specific defaults where appropriate.
651    ///
652    /// ### Relationship to XDG Base Directory Specification
653    /// Note that this function operates independently of the
654    /// [XDG Base Directory Specification](https://specifications.freedesktop.org/basedir/latest/)
655    /// and [`system_config_dirs()`][crate::system_config_dirs()]. While XDG directories (like `$XDG_CONFIG_DIRS`)
656    /// are intended to manage desktop session applications and user-facing environments, this
657    /// API is strictly designed for low-level system-wide components following the UAPI
658    /// specification. Mixing the two concepts should be avoided.
659    ///
660    /// Note that this function is synchronous and blocking. Because it may load an arbitrary amount
661    /// of files, it is best suited for application startup or non-interactive environments. If called
662    /// from a user-interactive UI thread, you must handle asynchronicity yourself if needed.
663    ///
664    /// If no file for parsing has been found, [error@GLib.KeyFileError.NOT_FOUND] is returned.
665    /// If files have been found but the OS returns an error when opening or reading a
666    /// file, a [`FileError`][crate::FileError] is returned. If there is a problem parsing
667    /// files, a [`KeyFileError`][crate::KeyFileError] is returned.
668    ///
669    ///
670    /// The following example parses files in following order:
671    ///
672    /// - `<SYSCONFDIR>/project/mydaemon.conf`
673    /// - `/run/project/mydaemon.conf` (if <SYSCONFDIR>/project/mydaemon.conf is not defined)
674    /// - `<LIBDIR>/project/mydaemon.conf`
675    ///   (if `<SYSCONFDIR>/project/mydaemon.conf` and `/run/project/mydaemon.conf are not defined`)
676    /// - valid drop-ins in `<SYSCONFDIR>/project/mydaemon.conf.d/`, `/run/project/mydaemon.conf.d/`, `<LIBDIR>/project/mydaemon.conf.d/`
677    ///
678    /// ```text
679    /// g_autoptr(GKeyFile) kf = g_key_file_new ();
680    /// g_autoptr(GError) local_error = NULL;
681    ///
682    /// // Using build-configured paths or defaults instead of hardcoded strings
683    /// gboolean success = g_key_file_load_unix_configurations (kf,
684    ///                                                         "my-daemon",
685    ///                                                         SYSCONFDIR,
686    ///                                                         RUNDIR,
687    ///                                                         LIBDIR,
688    ///                                                         "mydaemon",
689    ///                                                         "conf",
690    ///                                                         G_KEY_FILE_NONE,
691    ///                                                         &local_error);
692    /// if (!success)
693    ///   {
694    ///     g_warning ("Failed to load configuration: %s", local_error->message);
695    ///     return;
696    ///   }
697    ///
698    /// g_autofree char *val = g_key_file_get_string (kf, "Management", "Setting", NULL);
699    /// ```
700    /// ## `project`
701    /// name of the project used as subdirectory
702    /// ## `etc_subdir`
703    /// directory path for administrative configuration files
704    /// ## `run_subdir`
705    /// directory path for ephemeral overrides
706    /// ## `usr_subdir`
707    /// directory path for vendor-defined settings
708    /// ## `config_name`
709    /// basename of the configuration file
710    /// ## `config_suffix`
711    /// suffix of the configuration file
712    /// ## `flags`
713    /// flags from [`KeyFileFlags`][crate::KeyFileFlags]
714    ///
715    /// # Returns
716    ///
717    /// true on success, false otherwise
718    #[cfg(feature = "v2_90")]
719    #[cfg_attr(docsrs, doc(cfg(feature = "v2_90")))]
720    #[doc(alias = "g_key_file_load_unix_configurations")]
721    pub fn load_unix_configurations(
722        &self,
723        project: Option<&str>,
724        etc_subdir: Option<impl AsRef<std::path::Path>>,
725        run_subdir: Option<impl AsRef<std::path::Path>>,
726        usr_subdir: Option<impl AsRef<std::path::Path>>,
727        config_name: impl AsRef<std::path::Path>,
728        config_suffix: Option<impl AsRef<std::path::Path>>,
729        flags: KeyFileFlags,
730    ) -> Result<(), crate::Error> {
731        unsafe {
732            let mut error = std::ptr::null_mut();
733            let is_ok = ffi::g_key_file_load_unix_configurations(
734                self.to_glib_none().0,
735                project.to_glib_none().0,
736                etc_subdir.as_ref().map(|p| p.as_ref()).to_glib_none().0,
737                run_subdir.as_ref().map(|p| p.as_ref()).to_glib_none().0,
738                usr_subdir.as_ref().map(|p| p.as_ref()).to_glib_none().0,
739                config_name.as_ref().to_glib_none().0,
740                config_suffix.as_ref().map(|p| p.as_ref()).to_glib_none().0,
741                flags.into_glib(),
742                &mut error,
743            );
744            debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null());
745            if error.is_null() {
746                Ok(())
747            } else {
748                Err(from_glib_full(error))
749            }
750        }
751    }
752
753    /// Removes a comment above @key from @group_name.
754    ///
755    /// If @key is `NULL` then @comment will be removed above @group_name.
756    /// If both @key and @group_name are `NULL`, then @comment will
757    /// be removed above the first group in the file.
758    /// ## `group_name`
759    /// a group name, or `NULL` to get a top-level comment
760    /// ## `key`
761    /// a key, or `NULL` to get a group comment
762    ///
763    /// # Returns
764    ///
765    /// true if the comment was removed, false otherwise
766    #[doc(alias = "g_key_file_remove_comment")]
767    pub fn remove_comment(
768        &self,
769        group_name: Option<&str>,
770        key: Option<&str>,
771    ) -> Result<(), crate::Error> {
772        unsafe {
773            let mut error = std::ptr::null_mut();
774            let is_ok = ffi::g_key_file_remove_comment(
775                self.to_glib_none().0,
776                group_name.to_glib_none().0,
777                key.to_glib_none().0,
778                &mut error,
779            );
780            debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null());
781            if error.is_null() {
782                Ok(())
783            } else {
784                Err(from_glib_full(error))
785            }
786        }
787    }
788
789    /// Removes the specified group, @group_name,
790    /// from the key file.
791    /// ## `group_name`
792    /// a group name
793    ///
794    /// # Returns
795    ///
796    /// true if the group was removed, false otherwise
797    #[doc(alias = "g_key_file_remove_group")]
798    pub fn remove_group(&self, group_name: &str) -> Result<(), crate::Error> {
799        unsafe {
800            let mut error = std::ptr::null_mut();
801            let is_ok = ffi::g_key_file_remove_group(
802                self.to_glib_none().0,
803                group_name.to_glib_none().0,
804                &mut error,
805            );
806            debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null());
807            if error.is_null() {
808                Ok(())
809            } else {
810                Err(from_glib_full(error))
811            }
812        }
813    }
814
815    /// Removes @key in @group_name from the key file.
816    /// ## `group_name`
817    /// a group name
818    /// ## `key`
819    /// a key name to remove
820    ///
821    /// # Returns
822    ///
823    /// true if the key was removed, false otherwise
824    #[doc(alias = "g_key_file_remove_key")]
825    pub fn remove_key(&self, group_name: &str, key: &str) -> Result<(), crate::Error> {
826        unsafe {
827            let mut error = std::ptr::null_mut();
828            let is_ok = ffi::g_key_file_remove_key(
829                self.to_glib_none().0,
830                group_name.to_glib_none().0,
831                key.to_glib_none().0,
832                &mut error,
833            );
834            debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null());
835            if error.is_null() {
836                Ok(())
837            } else {
838                Err(from_glib_full(error))
839            }
840        }
841    }
842
843    /// Associates a new boolean value with @key under @group_name.
844    ///
845    /// If @key cannot be found then it is created.
846    /// ## `group_name`
847    /// a group name
848    /// ## `key`
849    /// a key
850    /// ## `value`
851    /// true or false
852    #[doc(alias = "g_key_file_set_boolean")]
853    pub fn set_boolean(&self, group_name: &str, key: &str, value: bool) {
854        unsafe {
855            ffi::g_key_file_set_boolean(
856                self.to_glib_none().0,
857                group_name.to_glib_none().0,
858                key.to_glib_none().0,
859                value.into_glib(),
860            );
861        }
862    }
863
864    //#[doc(alias = "g_key_file_set_boolean_list")]
865    //pub fn set_boolean_list(&self, group_name: &str, key: &str, list: /*Unimplemented*/&CArray TypeId { ns_id: 0, id: 1 }) {
866    //    unsafe { TODO: call ffi:g_key_file_set_boolean_list() }
867    //}
868
869    /// Places a comment above @key from @group_name.
870    ///
871    /// If @key is `NULL` then @comment will be written above @group_name.
872    /// If both @key and @group_name are `NULL`, then @comment will be
873    /// written above the first group in the file.
874    ///
875    /// Passing a non-existent @group_name or @key to this function returns
876    /// false and populates @error. (In contrast, passing a non-existent
877    /// `group_name` or `key` to [`set_string()`][Self::set_string()]
878    /// creates the associated group name and key.)
879    ///
880    /// Note that this function prepends a `#` comment marker to
881    /// each line of @comment.
882    /// ## `group_name`
883    /// a group name, or `NULL` to write a top-level comment
884    /// ## `key`
885    /// a key, or `NULL` to write a group comment
886    /// ## `comment`
887    /// a comment
888    ///
889    /// # Returns
890    ///
891    /// true if the comment was written, false otherwise
892    #[doc(alias = "g_key_file_set_comment")]
893    pub fn set_comment(
894        &self,
895        group_name: Option<&str>,
896        key: Option<&str>,
897        comment: &str,
898    ) -> Result<(), crate::Error> {
899        unsafe {
900            let mut error = std::ptr::null_mut();
901            let is_ok = ffi::g_key_file_set_comment(
902                self.to_glib_none().0,
903                group_name.to_glib_none().0,
904                key.to_glib_none().0,
905                comment.to_glib_none().0,
906                &mut error,
907            );
908            debug_assert_eq!(is_ok == crate::ffi::GFALSE, !error.is_null());
909            if error.is_null() {
910                Ok(())
911            } else {
912                Err(from_glib_full(error))
913            }
914        }
915    }
916
917    /// Associates a new double value with @key under @group_name.
918    ///
919    /// If @key cannot be found then it is created.
920    /// ## `group_name`
921    /// a group name
922    /// ## `key`
923    /// a key
924    /// ## `value`
925    /// a double value
926    #[doc(alias = "g_key_file_set_double")]
927    pub fn set_double(&self, group_name: &str, key: &str, value: f64) {
928        unsafe {
929            ffi::g_key_file_set_double(
930                self.to_glib_none().0,
931                group_name.to_glib_none().0,
932                key.to_glib_none().0,
933                value,
934            );
935        }
936    }
937
938    /// Associates a new integer value with @key under @group_name.
939    ///
940    /// If @key cannot be found then it is created.
941    /// ## `group_name`
942    /// a group name
943    /// ## `key`
944    /// a key
945    /// ## `value`
946    /// an integer value
947    #[doc(alias = "g_key_file_set_int64")]
948    pub fn set_int64(&self, group_name: &str, key: &str, value: i64) {
949        unsafe {
950            ffi::g_key_file_set_int64(
951                self.to_glib_none().0,
952                group_name.to_glib_none().0,
953                key.to_glib_none().0,
954                value,
955            );
956        }
957    }
958
959    /// Associates a new integer value with @key under @group_name.
960    ///
961    /// If @key cannot be found then it is created.
962    /// ## `group_name`
963    /// a group name
964    /// ## `key`
965    /// a key
966    /// ## `value`
967    /// an integer value
968    #[doc(alias = "g_key_file_set_integer")]
969    pub fn set_integer(&self, group_name: &str, key: &str, value: i32) {
970        unsafe {
971            ffi::g_key_file_set_integer(
972                self.to_glib_none().0,
973                group_name.to_glib_none().0,
974                key.to_glib_none().0,
975                value,
976            );
977        }
978    }
979
980    /// Sets the character which is used to separate values in lists.
981    ///
982    /// Typically `;` or `,` are used as separators. The default list separator
983    /// is `;`.
984    /// ## `separator`
985    /// the separator
986    #[doc(alias = "g_key_file_set_list_separator")]
987    pub fn set_list_separator(&self, separator: crate::Char) {
988        unsafe {
989            ffi::g_key_file_set_list_separator(self.to_glib_none().0, separator.into_glib());
990        }
991    }
992
993    /// Associates a string value for @key and @locale under @group_name.
994    ///
995    /// If the translation for @key cannot be found then it is created.
996    ///
997    /// If @locale is `C` then the untranslated value is set (since GLib 2.84).
998    /// ## `group_name`
999    /// a group name
1000    /// ## `key`
1001    /// a key
1002    /// ## `locale`
1003    /// a locale identifier
1004    /// ## `string`
1005    /// a string
1006    #[doc(alias = "g_key_file_set_locale_string")]
1007    pub fn set_locale_string(&self, group_name: &str, key: &str, locale: &str, string: &str) {
1008        unsafe {
1009            ffi::g_key_file_set_locale_string(
1010                self.to_glib_none().0,
1011                group_name.to_glib_none().0,
1012                key.to_glib_none().0,
1013                locale.to_glib_none().0,
1014                string.to_glib_none().0,
1015            );
1016        }
1017    }
1018
1019    /// Associates a new string value with @key under @group_name.
1020    ///
1021    /// If @key cannot be found then it is created.
1022    /// If @group_name cannot be found then it is created.
1023    /// Unlike [`set_value()`][Self::set_value()], this function handles characters
1024    /// that need escaping, such as newlines.
1025    /// ## `group_name`
1026    /// a group name
1027    /// ## `key`
1028    /// a key
1029    /// ## `string`
1030    /// a string
1031    #[doc(alias = "g_key_file_set_string")]
1032    pub fn set_string(&self, group_name: &str, key: &str, string: &str) {
1033        unsafe {
1034            ffi::g_key_file_set_string(
1035                self.to_glib_none().0,
1036                group_name.to_glib_none().0,
1037                key.to_glib_none().0,
1038                string.to_glib_none().0,
1039            );
1040        }
1041    }
1042
1043    /// Associates a new integer value with @key under @group_name.
1044    ///
1045    /// If @key cannot be found then it is created.
1046    /// ## `group_name`
1047    /// a group name
1048    /// ## `key`
1049    /// a key
1050    /// ## `value`
1051    /// an integer value
1052    #[doc(alias = "g_key_file_set_uint64")]
1053    pub fn set_uint64(&self, group_name: &str, key: &str, value: u64) {
1054        unsafe {
1055            ffi::g_key_file_set_uint64(
1056                self.to_glib_none().0,
1057                group_name.to_glib_none().0,
1058                key.to_glib_none().0,
1059                value,
1060            );
1061        }
1062    }
1063
1064    /// Associates a new value with @key under @group_name.
1065    ///
1066    /// If @key cannot be found then it is created. If @group_name cannot
1067    /// be found then it is created. To set an UTF-8 string which may contain
1068    /// characters that need escaping (such as newlines or spaces), use
1069    /// [`set_string()`][Self::set_string()].
1070    /// ## `group_name`
1071    /// a group name
1072    /// ## `key`
1073    /// a key
1074    /// ## `value`
1075    /// a string
1076    #[doc(alias = "g_key_file_set_value")]
1077    pub fn set_value(&self, group_name: &str, key: &str, value: &str) {
1078        unsafe {
1079            ffi::g_key_file_set_value(
1080                self.to_glib_none().0,
1081                group_name.to_glib_none().0,
1082                key.to_glib_none().0,
1083                value.to_glib_none().0,
1084            );
1085        }
1086    }
1087}
1088
1089impl Default for KeyFile {
1090    fn default() -> Self {
1091        Self::new()
1092    }
1093}