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}