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}