1/* gkeyfile.c - key file parser
2 *
3 * Copyright 2004 Red Hat, Inc.
4 * Copyright 2009-2010 Collabora Ltd.
5 * Copyright 2009 Nokia Corporation
6 *
7 * Written by Ray Strode <rstrode@redhat.com>
8 * Matthias Clasen <mclasen@redhat.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this library; if not, see <http://www.gnu.org/licenses/>.
22 */
23
24#include "config.h"
25
26#include "gkeyfile.h"
27#include "gutils.h"
28
29#include <errno.h>
30#include <fcntl.h>
31#include <locale.h>
32#include <string.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#ifdef G_OS_UNIX
38#include <unistd.h>
39#endif
40#ifdef G_OS_WIN32
41#include <io.h>
42
43#undef fstat
44#define fstat(a,b) _fstati64(a,b)
45#undef stat
46#define stat _stati64
47
48#ifndef S_ISREG
49#define S_ISREG(mode) ((mode)&_S_IFREG)
50#endif
51
52#endif /* G_OS_WIN23 */
53
54#include "gconvert.h"
55#include "gdataset.h"
56#include "gerror.h"
57#include "gfileutils.h"
58#include "ghash.h"
59#include "glibintl.h"
60#include "glist.h"
61#include "gslist.h"
62#include "gmem.h"
63#include "gmessages.h"
64#include "gstdio.h"
65#include "gstring.h"
66#include "gstrfuncs.h"
67#include "gutils.h"
68
69
70/**
71 * SECTION:keyfile
72 * @title: Key-value file parser
73 * @short_description: parses .ini-like config files
74 *
75 * #GKeyFile lets you parse, edit or create files containing groups of
76 * key-value pairs, which we call "key files" for lack of a better name.
77 * Several freedesktop.org specifications use key files now, e.g the
78 * [Desktop Entry Specification](http://freedesktop.org/Standards/desktop-entry-spec)
79 * and the
80 * [Icon Theme Specification](http://freedesktop.org/Standards/icon-theme-spec).
81 *
82 * The syntax of key files is described in detail in the
83 * [Desktop Entry Specification](http://freedesktop.org/Standards/desktop-entry-spec),
84 * here is a quick summary: Key files
85 * consists of groups of key-value pairs, interspersed with comments.
86 *
87 * |[
88 * # this is just an example
89 * # there can be comments before the first group
90 *
91 * [First Group]
92 *
93 * Name=Key File Example\tthis value shows\nescaping
94 *
95 * # localized strings are stored in multiple key-value pairs
96 * Welcome=Hello
97 * Welcome[de]=Hallo
98 * Welcome[fr_FR]=Bonjour
99 * Welcome[it]=Ciao
100 * Welcome[be@latin]=Hello
101 *
102 * [Another Group]
103 *
104 * Numbers=2;20;-200;0
105 *
106 * Booleans=true;false;true;true
107 * ]|
108 *
109 * Lines beginning with a '#' and blank lines are considered comments.
110 *
111 * Groups are started by a header line containing the group name enclosed
112 * in '[' and ']', and ended implicitly by the start of the next group or
113 * the end of the file. Each key-value pair must be contained in a group.
114 *
115 * Key-value pairs generally have the form `key=value`, with the
116 * exception of localized strings, which have the form
117 * `key[locale]=value`, with a locale identifier of the
118 * form `lang_COUNTRY@MODIFIER` where `COUNTRY` and `MODIFIER`
119 * are optional.
120 * Space before and after the '=' character are ignored. Newline, tab,
121 * carriage return and backslash characters in value are escaped as \n,
122 * \t, \r, and \\\\, respectively. To preserve leading spaces in values,
123 * these can also be escaped as \s.
124 *
125 * Key files can store strings (possibly with localized variants), integers,
126 * booleans and lists of these. Lists are separated by a separator character,
127 * typically ';' or ','. To use the list separator character in a value in
128 * a list, it has to be escaped by prefixing it with a backslash.
129 *
130 * This syntax is obviously inspired by the .ini files commonly met
131 * on Windows, but there are some important differences:
132 *
133 * - .ini files use the ';' character to begin comments,
134 * key files use the '#' character.
135 *
136 * - Key files do not allow for ungrouped keys meaning only
137 * comments can precede the first group.
138 *
139 * - Key files are always encoded in UTF-8.
140 *
141 * - Key and Group names are case-sensitive. For example, a group called
142 * [GROUP] is a different from [group].
143 *
144 * - .ini files don't have a strongly typed boolean entry type,
145 * they only have GetProfileInt(). In key files, only
146 * true and false (in lower case) are allowed.
147 *
148 * Note that in contrast to the
149 * [Desktop Entry Specification](http://freedesktop.org/Standards/desktop-entry-spec),
150 * groups in key files may contain the same
151 * key multiple times; the last entry wins. Key files may also contain
152 * multiple groups with the same name; they are merged together.
153 * Another difference is that keys and group names in key files are not
154 * restricted to ASCII characters.
155 *
156 * Here is an example of loading a key file and reading a value:
157 * |[<!-- language="C" -->
158 * g_autoptr(GError) error = NULL;
159 * g_autoptr(GKeyFile) key_file = g_key_file_new ();
160 *
161 * if (!g_key_file_load_from_file (key_file, "key-file.ini", flags, &error))
162 * {
163 * if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
164 * g_warning ("Error loading key file: %s", error->message);
165 * return;
166 * }
167 *
168 * g_autofree gchar *val = g_key_file_get_string (key_file, "Group Name", "SomeKey", &error);
169 * if (val == NULL &&
170 * !g_error_matches (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_KEY_NOT_FOUND))
171 * {
172 * g_warning ("Error finding key in key file: %s", error->message);
173 * return;
174 * }
175 * else if (val == NULL)
176 * {
177 * // Fall back to a default value.
178 * val = g_strdup ("default-value");
179 * }
180 * ]|
181 *
182 * Here is an example of creating and saving a key file:
183 * |[<!-- language="C" -->
184 * g_autoptr(GKeyFile) key_file = g_key_file_new ();
185 * const gchar *val = …;
186 * g_autoptr(GError) error = NULL;
187 *
188 * g_key_file_set_string (key_file, "Group Name", "SomeKey", val);
189 *
190 * // Save as a file.
191 * if (!g_key_file_save_to_file (key_file, "key-file.ini", &error))
192 * {
193 * g_warning ("Error saving key file: %s", error->message);
194 * return;
195 * }
196 *
197 * // Or store to a GBytes for use elsewhere.
198 * gsize data_len;
199 * g_autofree guint8 *data = (guint8 *) g_key_file_to_data (key_file, &data_len, &error);
200 * if (data == NULL)
201 * {
202 * g_warning ("Error saving key file: %s", error->message);
203 * return;
204 * }
205 * g_autoptr(GBytes) bytes = g_bytes_new_take (g_steal_pointer (&data), data_len);
206 * ]|
207 */
208
209/**
210 * G_KEY_FILE_ERROR:
211 *
212 * Error domain for key file parsing. Errors in this domain will
213 * be from the #GKeyFileError enumeration.
214 *
215 * See #GError for information on error domains.
216 */
217
218/**
219 * GKeyFileError:
220 * @G_KEY_FILE_ERROR_UNKNOWN_ENCODING: the text being parsed was in
221 * an unknown encoding
222 * @G_KEY_FILE_ERROR_PARSE: document was ill-formed
223 * @G_KEY_FILE_ERROR_NOT_FOUND: the file was not found
224 * @G_KEY_FILE_ERROR_KEY_NOT_FOUND: a requested key was not found
225 * @G_KEY_FILE_ERROR_GROUP_NOT_FOUND: a requested group was not found
226 * @G_KEY_FILE_ERROR_INVALID_VALUE: a value could not be parsed
227 *
228 * Error codes returned by key file parsing.
229 */
230
231/**
232 * GKeyFileFlags:
233 * @G_KEY_FILE_NONE: No flags, default behaviour
234 * @G_KEY_FILE_KEEP_COMMENTS: Use this flag if you plan to write the
235 * (possibly modified) contents of the key file back to a file;
236 * otherwise all comments will be lost when the key file is
237 * written back.
238 * @G_KEY_FILE_KEEP_TRANSLATIONS: Use this flag if you plan to write the
239 * (possibly modified) contents of the key file back to a file;
240 * otherwise only the translations for the current language will be
241 * written back.
242 *
243 * Flags which influence the parsing.
244 */
245
246/**
247 * G_KEY_FILE_DESKTOP_GROUP:
248 *
249 * The name of the main group of a desktop entry file, as defined in the
250 * [Desktop Entry Specification](http://freedesktop.org/Standards/desktop-entry-spec).
251 * Consult the specification for more
252 * details about the meanings of the keys below.
253 *
254 * Since: 2.14
255 */
256
257/**
258 * G_KEY_FILE_DESKTOP_KEY_TYPE:
259 *
260 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a string
261 * giving the type of the desktop entry. Usually
262 * #G_KEY_FILE_DESKTOP_TYPE_APPLICATION,
263 * #G_KEY_FILE_DESKTOP_TYPE_LINK, or
264 * #G_KEY_FILE_DESKTOP_TYPE_DIRECTORY.
265 *
266 * Since: 2.14
267 */
268
269/**
270 * G_KEY_FILE_DESKTOP_KEY_VERSION:
271 *
272 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a string
273 * giving the version of the Desktop Entry Specification used for
274 * the desktop entry file.
275 *
276 * Since: 2.14
277 */
278
279/**
280 * G_KEY_FILE_DESKTOP_KEY_NAME:
281 *
282 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a localized
283 * string giving the specific name of the desktop entry.
284 *
285 * Since: 2.14
286 */
287
288/**
289 * G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME:
290 *
291 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a localized
292 * string giving the generic name of the desktop entry.
293 *
294 * Since: 2.14
295 */
296
297/**
298 * G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY:
299 *
300 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a boolean
301 * stating whether the desktop entry should be shown in menus.
302 *
303 * Since: 2.14
304 */
305
306/**
307 * G_KEY_FILE_DESKTOP_KEY_COMMENT:
308 *
309 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a localized
310 * string giving the tooltip for the desktop entry.
311 *
312 * Since: 2.14
313 */
314
315/**
316 * G_KEY_FILE_DESKTOP_KEY_ICON:
317 *
318 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a localized
319 * string giving the name of the icon to be displayed for the desktop
320 * entry.
321 *
322 * Since: 2.14
323 */
324
325/**
326 * G_KEY_FILE_DESKTOP_KEY_HIDDEN:
327 *
328 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a boolean
329 * stating whether the desktop entry has been deleted by the user.
330 *
331 * Since: 2.14
332 */
333
334/**
335 * G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN:
336 *
337 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a list of
338 * strings identifying the environments that should display the
339 * desktop entry.
340 *
341 * Since: 2.14
342 */
343
344/**
345 * G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN:
346 *
347 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a list of
348 * strings identifying the environments that should not display the
349 * desktop entry.
350 *
351 * Since: 2.14
352 */
353
354/**
355 * G_KEY_FILE_DESKTOP_KEY_TRY_EXEC:
356 *
357 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a string
358 * giving the file name of a binary on disk used to determine if the
359 * program is actually installed. It is only valid for desktop entries
360 * with the `Application` type.
361 *
362 * Since: 2.14
363 */
364
365/**
366 * G_KEY_FILE_DESKTOP_KEY_EXEC:
367 *
368 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a string
369 * giving the command line to execute. It is only valid for desktop
370 * entries with the `Application` type.
371 *
372 * Since: 2.14
373 */
374
375 /**
376 * G_KEY_FILE_DESKTOP_KEY_PATH:
377 *
378 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a string
379 * containing the working directory to run the program in. It is only
380 * valid for desktop entries with the `Application` type.
381 *
382 * Since: 2.14
383 */
384
385/**
386 * G_KEY_FILE_DESKTOP_KEY_TERMINAL:
387 *
388 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a boolean
389 * stating whether the program should be run in a terminal window.
390 * It is only valid for desktop entries with the
391 * `Application` type.
392 *
393 * Since: 2.14
394 */
395
396/**
397 * G_KEY_FILE_DESKTOP_KEY_MIME_TYPE:
398 *
399 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a list
400 * of strings giving the MIME types supported by this desktop entry.
401 *
402 * Since: 2.14
403 */
404
405/**
406 * G_KEY_FILE_DESKTOP_KEY_CATEGORIES:
407 *
408 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a list
409 * of strings giving the categories in which the desktop entry
410 * should be shown in a menu.
411 *
412 * Since: 2.14
413 */
414
415/**
416 * G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY:
417 *
418 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a boolean
419 * stating whether the application supports the
420 * [Startup Notification Protocol Specification](http://www.freedesktop.org/Standards/startup-notification-spec).
421 *
422 * Since: 2.14
423 */
424
425/**
426 * G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS:
427 *
428 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is string
429 * identifying the WM class or name hint of a window that the application
430 * will create, which can be used to emulate Startup Notification with
431 * older applications.
432 *
433 * Since: 2.14
434 */
435
436/**
437 * G_KEY_FILE_DESKTOP_KEY_URL:
438 *
439 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a string
440 * giving the URL to access. It is only valid for desktop entries
441 * with the `Link` type.
442 *
443 * Since: 2.14
444 */
445
446/**
447 * G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE:
448 *
449 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a boolean set to true
450 * if the application is D-Bus activatable.
451 *
452 * Since: 2.38
453 */
454
455/**
456 * G_KEY_FILE_DESKTOP_KEY_ACTIONS:
457 *
458 * A key under #G_KEY_FILE_DESKTOP_GROUP, whose value is a string list
459 * giving the available application actions.
460 *
461 * Since: 2.38
462 */
463
464/**
465 * G_KEY_FILE_DESKTOP_TYPE_APPLICATION:
466 *
467 * The value of the #G_KEY_FILE_DESKTOP_KEY_TYPE, key for desktop
468 * entries representing applications.
469 *
470 * Since: 2.14
471 */
472
473/**
474 * G_KEY_FILE_DESKTOP_TYPE_LINK:
475 *
476 * The value of the #G_KEY_FILE_DESKTOP_KEY_TYPE, key for desktop
477 * entries representing links to documents.
478 *
479 * Since: 2.14
480 */
481
482/**
483 * G_KEY_FILE_DESKTOP_TYPE_DIRECTORY:
484 *
485 * The value of the #G_KEY_FILE_DESKTOP_KEY_TYPE, key for desktop
486 * entries representing directories.
487 *
488 * Since: 2.14
489 */
490
491typedef struct _GKeyFileGroup GKeyFileGroup;
492
493/**
494 * GKeyFile:
495 *
496 * The GKeyFile struct contains only private data
497 * and should not be accessed directly.
498 */
499struct _GKeyFile
500{
501 GList *groups;
502 GHashTable *group_hash;
503
504 GKeyFileGroup *start_group;
505 GKeyFileGroup *current_group;
506
507 GString *parse_buffer; /* Holds up to one line of not-yet-parsed data */
508
509 gchar list_separator;
510
511 GKeyFileFlags flags;
512
513 gboolean checked_locales;
514 gchar **locales;
515
516 gint ref_count; /* (atomic) */
517};
518
519typedef struct _GKeyFileKeyValuePair GKeyFileKeyValuePair;
520
521struct _GKeyFileGroup
522{
523 const gchar *name; /* NULL for above first group (which will be comments) */
524
525 GKeyFileKeyValuePair *comment; /* Special comment that is stuck to the top of a group */
526
527 GList *key_value_pairs;
528
529 /* Used in parallel with key_value_pairs for
530 * increased lookup performance
531 */
532 GHashTable *lookup_map;
533};
534
535struct _GKeyFileKeyValuePair
536{
537 gchar *key; /* NULL for comments */
538 gchar *value;
539};
540
541static gint find_file_in_data_dirs (const gchar *file,
542 const gchar **data_dirs,
543 gchar **output_file,
544 GError **error);
545static gboolean g_key_file_load_from_fd (GKeyFile *key_file,
546 gint fd,
547 GKeyFileFlags flags,
548 GError **error);
549static GList *g_key_file_lookup_group_node (GKeyFile *key_file,
550 const gchar *group_name);
551static GKeyFileGroup *g_key_file_lookup_group (GKeyFile *key_file,
552 const gchar *group_name);
553
554static GList *g_key_file_lookup_key_value_pair_node (GKeyFile *key_file,
555 GKeyFileGroup *group,
556 const gchar *key);
557static GKeyFileKeyValuePair *g_key_file_lookup_key_value_pair (GKeyFile *key_file,
558 GKeyFileGroup *group,
559 const gchar *key);
560
561static void g_key_file_remove_group_node (GKeyFile *key_file,
562 GList *group_node);
563static void g_key_file_remove_key_value_pair_node (GKeyFile *key_file,
564 GKeyFileGroup *group,
565 GList *pair_node);
566
567static void g_key_file_add_key_value_pair (GKeyFile *key_file,
568 GKeyFileGroup *group,
569 GKeyFileKeyValuePair *pair);
570static void g_key_file_add_key (GKeyFile *key_file,
571 GKeyFileGroup *group,
572 const gchar *key,
573 const gchar *value);
574static void g_key_file_add_group (GKeyFile *key_file,
575 const gchar *group_name);
576static gboolean g_key_file_is_group_name (const gchar *name);
577static gboolean g_key_file_is_key_name (const gchar *name);
578static void g_key_file_key_value_pair_free (GKeyFileKeyValuePair *pair);
579static gboolean g_key_file_line_is_comment (const gchar *line);
580static gboolean g_key_file_line_is_group (const gchar *line);
581static gboolean g_key_file_line_is_key_value_pair (const gchar *line);
582static gchar *g_key_file_parse_value_as_string (GKeyFile *key_file,
583 const gchar *value,
584 GSList **separators,
585 GError **error);
586static gchar *g_key_file_parse_string_as_value (GKeyFile *key_file,
587 const gchar *string,
588 gboolean escape_separator);
589static gint g_key_file_parse_value_as_integer (GKeyFile *key_file,
590 const gchar *value,
591 GError **error);
592static gchar *g_key_file_parse_integer_as_value (GKeyFile *key_file,
593 gint value);
594static gdouble g_key_file_parse_value_as_double (GKeyFile *key_file,
595 const gchar *value,
596 GError **error);
597static gboolean g_key_file_parse_value_as_boolean (GKeyFile *key_file,
598 const gchar *value,
599 GError **error);
600static gchar *g_key_file_parse_boolean_as_value (GKeyFile *key_file,
601 gboolean value);
602static gchar *g_key_file_parse_value_as_comment (GKeyFile *key_file,
603 const gchar *value,
604 gboolean is_final_line);
605static gchar *g_key_file_parse_comment_as_value (GKeyFile *key_file,
606 const gchar *comment);
607static void g_key_file_parse_key_value_pair (GKeyFile *key_file,
608 const gchar *line,
609 gsize length,
610 GError **error);
611static void g_key_file_parse_comment (GKeyFile *key_file,
612 const gchar *line,
613 gsize length,
614 GError **error);
615static void g_key_file_parse_group (GKeyFile *key_file,
616 const gchar *line,
617 gsize length,
618 GError **error);
619static gchar *key_get_locale (const gchar *key);
620static void g_key_file_parse_data (GKeyFile *key_file,
621 const gchar *data,
622 gsize length,
623 GError **error);
624static void g_key_file_flush_parse_buffer (GKeyFile *key_file,
625 GError **error);
626
627G_DEFINE_QUARK (g-key-file-error-quark, g_key_file_error)
628
629static void
630g_key_file_init (GKeyFile *key_file)
631{
632 key_file->current_group = g_slice_new0 (GKeyFileGroup);
633 key_file->groups = g_list_prepend (NULL, data: key_file->current_group);
634 key_file->group_hash = NULL;
635 key_file->start_group = NULL;
636 key_file->parse_buffer = NULL;
637 key_file->list_separator = ';';
638 key_file->flags = 0;
639}
640
641static void
642g_key_file_clear (GKeyFile *key_file)
643{
644 GList *tmp, *group_node;
645
646 if (key_file->locales)
647 {
648 g_strfreev (str_array: key_file->locales);
649 key_file->locales = NULL;
650 }
651 key_file->checked_locales = FALSE;
652
653 if (key_file->parse_buffer)
654 {
655 g_string_free (string: key_file->parse_buffer, TRUE);
656 key_file->parse_buffer = NULL;
657 }
658
659 tmp = key_file->groups;
660 while (tmp != NULL)
661 {
662 group_node = tmp;
663 tmp = tmp->next;
664 g_key_file_remove_group_node (key_file, group_node);
665 }
666
667 if (key_file->group_hash != NULL)
668 {
669 g_hash_table_destroy (hash_table: key_file->group_hash);
670 key_file->group_hash = NULL;
671 }
672
673 g_warn_if_fail (key_file->groups == NULL);
674}
675
676
677/**
678 * g_key_file_new:
679 *
680 * Creates a new empty #GKeyFile object. Use
681 * g_key_file_load_from_file(), g_key_file_load_from_data(),
682 * g_key_file_load_from_dirs() or g_key_file_load_from_data_dirs() to
683 * read an existing key file.
684 *
685 * Returns: (transfer full): an empty #GKeyFile.
686 *
687 * Since: 2.6
688 **/
689GKeyFile *
690g_key_file_new (void)
691{
692 GKeyFile *key_file;
693
694 key_file = g_slice_new0 (GKeyFile);
695 key_file->ref_count = 1;
696 g_key_file_init (key_file);
697
698 return key_file;
699}
700
701/**
702 * g_key_file_set_list_separator:
703 * @key_file: a #GKeyFile
704 * @separator: the separator
705 *
706 * Sets the character which is used to separate
707 * values in lists. Typically ';' or ',' are used
708 * as separators. The default list separator is ';'.
709 *
710 * Since: 2.6
711 */
712void
713g_key_file_set_list_separator (GKeyFile *key_file,
714 gchar separator)
715{
716 g_return_if_fail (key_file != NULL);
717
718 key_file->list_separator = separator;
719}
720
721
722/* Iterates through all the directories in *dirs trying to
723 * open file. When it successfully locates and opens a file it
724 * returns the file descriptor to the open file. It also
725 * outputs the absolute path of the file in output_file.
726 */
727static gint
728find_file_in_data_dirs (const gchar *file,
729 const gchar **dirs,
730 gchar **output_file,
731 GError **error)
732{
733 const gchar **data_dirs, *data_dir;
734 gchar *path;
735 gint fd;
736
737 path = NULL;
738 fd = -1;
739
740 if (dirs == NULL)
741 return fd;
742
743 data_dirs = dirs;
744
745 while (data_dirs && (data_dir = *data_dirs) && fd == -1)
746 {
747 gchar *candidate_file, *sub_dir;
748
749 candidate_file = (gchar *) file;
750 sub_dir = g_strdup (str: "");
751 while (candidate_file != NULL && fd == -1)
752 {
753 gchar *p;
754
755 path = g_build_filename (first_element: data_dir, sub_dir,
756 candidate_file, NULL);
757
758 fd = g_open (file: path, O_RDONLY, 0);
759
760 if (fd == -1)
761 {
762 g_free (mem: path);
763 path = NULL;
764 }
765
766 candidate_file = strchr (s: candidate_file, c: '-');
767
768 if (candidate_file == NULL)
769 break;
770
771 candidate_file++;
772
773 g_free (mem: sub_dir);
774 sub_dir = g_strndup (str: file, n: candidate_file - file - 1);
775
776 for (p = sub_dir; *p != '\0'; p++)
777 {
778 if (*p == '-')
779 *p = G_DIR_SEPARATOR;
780 }
781 }
782 g_free (mem: sub_dir);
783 data_dirs++;
784 }
785
786 if (fd == -1)
787 {
788 g_set_error_literal (err: error, G_KEY_FILE_ERROR,
789 code: G_KEY_FILE_ERROR_NOT_FOUND,
790 _("Valid key file could not be "
791 "found in search dirs"));
792 }
793
794 if (output_file != NULL && fd != -1)
795 *output_file = g_strdup (str: path);
796
797 g_free (mem: path);
798
799 return fd;
800}
801
802static gboolean
803g_key_file_load_from_fd (GKeyFile *key_file,
804 gint fd,
805 GKeyFileFlags flags,
806 GError **error)
807{
808 GError *key_file_error = NULL;
809 gssize bytes_read;
810 struct stat stat_buf;
811 gchar read_buf[4096];
812 gchar list_separator;
813
814 if (fstat (fd: fd, buf: &stat_buf) < 0)
815 {
816 int errsv = errno;
817 g_set_error_literal (err: error, G_FILE_ERROR,
818 code: g_file_error_from_errno (err_no: errsv),
819 message: g_strerror (errnum: errsv));
820 return FALSE;
821 }
822
823 if (!S_ISREG (stat_buf.st_mode))
824 {
825 g_set_error_literal (err: error, G_KEY_FILE_ERROR,
826 code: G_KEY_FILE_ERROR_PARSE,
827 _("Not a regular file"));
828 return FALSE;
829 }
830
831 list_separator = key_file->list_separator;
832 g_key_file_clear (key_file);
833 g_key_file_init (key_file);
834 key_file->list_separator = list_separator;
835 key_file->flags = flags;
836
837 do
838 {
839 int errsv;
840
841 bytes_read = read (fd: fd, buf: read_buf, nbytes: 4096);
842 errsv = errno;
843
844 if (bytes_read == 0) /* End of File */
845 break;
846
847 if (bytes_read < 0)
848 {
849 if (errsv == EINTR || errsv == EAGAIN)
850 continue;
851
852 g_set_error_literal (err: error, G_FILE_ERROR,
853 code: g_file_error_from_errno (err_no: errsv),
854 message: g_strerror (errnum: errsv));
855 return FALSE;
856 }
857
858 g_key_file_parse_data (key_file,
859 data: read_buf, length: bytes_read,
860 error: &key_file_error);
861 }
862 while (!key_file_error);
863
864 if (key_file_error)
865 {
866 g_propagate_error (dest: error, src: key_file_error);
867 return FALSE;
868 }
869
870 g_key_file_flush_parse_buffer (key_file, error: &key_file_error);
871
872 if (key_file_error)
873 {
874 g_propagate_error (dest: error, src: key_file_error);
875 return FALSE;
876 }
877
878 return TRUE;
879}
880
881/**
882 * g_key_file_load_from_file:
883 * @key_file: an empty #GKeyFile struct
884 * @file: (type filename): the path of a filename to load, in the GLib filename encoding
885 * @flags: flags from #GKeyFileFlags
886 * @error: return location for a #GError, or %NULL
887 *
888 * Loads a key file into an empty #GKeyFile structure.
889 *
890 * If the OS returns an error when opening or reading the file, a
891 * %G_FILE_ERROR is returned. If there is a problem parsing the file, a
892 * %G_KEY_FILE_ERROR is returned.
893 *
894 * This function will never return a %G_KEY_FILE_ERROR_NOT_FOUND error. If the
895 * @file is not found, %G_FILE_ERROR_NOENT is returned.
896 *
897 * Returns: %TRUE if a key file could be loaded, %FALSE otherwise
898 *
899 * Since: 2.6
900 **/
901gboolean
902g_key_file_load_from_file (GKeyFile *key_file,
903 const gchar *file,
904 GKeyFileFlags flags,
905 GError **error)
906{
907 GError *key_file_error = NULL;
908 gint fd;
909 int errsv;
910
911 g_return_val_if_fail (key_file != NULL, FALSE);
912 g_return_val_if_fail (file != NULL, FALSE);
913
914 fd = g_open (file: file, O_RDONLY, 0);
915 errsv = errno;
916
917 if (fd == -1)
918 {
919 g_set_error_literal (err: error, G_FILE_ERROR,
920 code: g_file_error_from_errno (err_no: errsv),
921 message: g_strerror (errnum: errsv));
922 return FALSE;
923 }
924
925 g_key_file_load_from_fd (key_file, fd, flags, error: &key_file_error);
926 close (fd: fd);
927
928 if (key_file_error)
929 {
930 g_propagate_error (dest: error, src: key_file_error);
931 return FALSE;
932 }
933
934 return TRUE;
935}
936
937/**
938 * g_key_file_load_from_data:
939 * @key_file: an empty #GKeyFile struct
940 * @data: key file loaded in memory
941 * @length: the length of @data in bytes (or (gsize)-1 if data is nul-terminated)
942 * @flags: flags from #GKeyFileFlags
943 * @error: return location for a #GError, or %NULL
944 *
945 * Loads a key file from memory into an empty #GKeyFile structure.
946 * If the object cannot be created then %error is set to a #GKeyFileError.
947 *
948 * Returns: %TRUE if a key file could be loaded, %FALSE otherwise
949 *
950 * Since: 2.6
951 **/
952gboolean
953g_key_file_load_from_data (GKeyFile *key_file,
954 const gchar *data,
955 gsize length,
956 GKeyFileFlags flags,
957 GError **error)
958{
959 GError *key_file_error = NULL;
960 gchar list_separator;
961
962 g_return_val_if_fail (key_file != NULL, FALSE);
963 g_return_val_if_fail (data != NULL || length == 0, FALSE);
964
965 if (length == (gsize)-1)
966 length = strlen (s: data);
967
968 list_separator = key_file->list_separator;
969 g_key_file_clear (key_file);
970 g_key_file_init (key_file);
971 key_file->list_separator = list_separator;
972 key_file->flags = flags;
973
974 g_key_file_parse_data (key_file, data, length, error: &key_file_error);
975
976 if (key_file_error)
977 {
978 g_propagate_error (dest: error, src: key_file_error);
979 return FALSE;
980 }
981
982 g_key_file_flush_parse_buffer (key_file, error: &key_file_error);
983
984 if (key_file_error)
985 {
986 g_propagate_error (dest: error, src: key_file_error);
987 return FALSE;
988 }
989
990 return TRUE;
991}
992
993/**
994 * g_key_file_load_from_bytes:
995 * @key_file: an empty #GKeyFile struct
996 * @bytes: a #GBytes
997 * @flags: flags from #GKeyFileFlags
998 * @error: return location for a #GError, or %NULL
999 *
1000 * Loads a key file from the data in @bytes into an empty #GKeyFile structure.
1001 * If the object cannot be created then %error is set to a #GKeyFileError.
1002 *
1003 * Returns: %TRUE if a key file could be loaded, %FALSE otherwise
1004 *
1005 * Since: 2.50
1006 **/
1007gboolean
1008g_key_file_load_from_bytes (GKeyFile *key_file,
1009 GBytes *bytes,
1010 GKeyFileFlags flags,
1011 GError **error)
1012{
1013 const guchar *data;
1014 gsize size;
1015
1016 g_return_val_if_fail (key_file != NULL, FALSE);
1017 g_return_val_if_fail (bytes != NULL, FALSE);
1018
1019 data = g_bytes_get_data (bytes, size: &size);
1020 return g_key_file_load_from_data (key_file, data: (const gchar *) data, length: size, flags, error);
1021}
1022
1023/**
1024 * g_key_file_load_from_dirs:
1025 * @key_file: an empty #GKeyFile struct
1026 * @file: (type filename): a relative path to a filename to open and parse
1027 * @search_dirs: (array zero-terminated=1) (element-type filename): %NULL-terminated array of directories to search
1028 * @full_path: (out) (type filename) (optional): return location for a string containing the full path
1029 * of the file, or %NULL
1030 * @flags: flags from #GKeyFileFlags
1031 * @error: return location for a #GError, or %NULL
1032 *
1033 * This function looks for a key file named @file in the paths
1034 * specified in @search_dirs, loads the file into @key_file and
1035 * returns the file's full path in @full_path.
1036 *
1037 * If the file could not be found in any of the @search_dirs,
1038 * %G_KEY_FILE_ERROR_NOT_FOUND is returned. If
1039 * the file is found but the OS returns an error when opening or reading the
1040 * file, a %G_FILE_ERROR is returned. If there is a problem parsing the file, a
1041 * %G_KEY_FILE_ERROR is returned.
1042 *
1043 * Returns: %TRUE if a key file could be loaded, %FALSE otherwise
1044 *
1045 * Since: 2.14
1046 **/
1047gboolean
1048g_key_file_load_from_dirs (GKeyFile *key_file,
1049 const gchar *file,
1050 const gchar **search_dirs,
1051 gchar **full_path,
1052 GKeyFileFlags flags,
1053 GError **error)
1054{
1055 GError *key_file_error = NULL;
1056 const gchar **data_dirs;
1057 gchar *output_path;
1058 gint fd;
1059 gboolean found_file;
1060
1061 g_return_val_if_fail (key_file != NULL, FALSE);
1062 g_return_val_if_fail (!g_path_is_absolute (file), FALSE);
1063 g_return_val_if_fail (search_dirs != NULL, FALSE);
1064
1065 found_file = FALSE;
1066 data_dirs = search_dirs;
1067 output_path = NULL;
1068 while (*data_dirs != NULL && !found_file)
1069 {
1070 g_free (mem: output_path);
1071 output_path = NULL;
1072
1073 fd = find_file_in_data_dirs (file, dirs: data_dirs, output_file: &output_path,
1074 error: &key_file_error);
1075
1076 if (fd == -1)
1077 {
1078 if (key_file_error)
1079 g_propagate_error (dest: error, src: key_file_error);
1080 break;
1081 }
1082
1083 found_file = g_key_file_load_from_fd (key_file, fd, flags,
1084 error: &key_file_error);
1085 close (fd: fd);
1086
1087 if (key_file_error)
1088 {
1089 g_propagate_error (dest: error, src: key_file_error);
1090 break;
1091 }
1092 }
1093
1094 if (found_file && full_path)
1095 *full_path = output_path;
1096 else
1097 g_free (mem: output_path);
1098
1099 return found_file;
1100}
1101
1102/**
1103 * g_key_file_load_from_data_dirs:
1104 * @key_file: an empty #GKeyFile struct
1105 * @file: (type filename): a relative path to a filename to open and parse
1106 * @full_path: (out) (type filename) (optional): return location for a string containing the full path
1107 * of the file, or %NULL
1108 * @flags: flags from #GKeyFileFlags
1109 * @error: return location for a #GError, or %NULL
1110 *
1111 * This function looks for a key file named @file in the paths
1112 * returned from g_get_user_data_dir() and g_get_system_data_dirs(),
1113 * loads the file into @key_file and returns the file's full path in
1114 * @full_path. If the file could not be loaded then an %error is
1115 * set to either a #GFileError or #GKeyFileError.
1116 *
1117 * Returns: %TRUE if a key file could be loaded, %FALSE otherwise
1118 * Since: 2.6
1119 **/
1120gboolean
1121g_key_file_load_from_data_dirs (GKeyFile *key_file,
1122 const gchar *file,
1123 gchar **full_path,
1124 GKeyFileFlags flags,
1125 GError **error)
1126{
1127 gchar **all_data_dirs;
1128 const gchar * user_data_dir;
1129 const gchar * const * system_data_dirs;
1130 gsize i, j;
1131 gboolean found_file;
1132
1133 g_return_val_if_fail (key_file != NULL, FALSE);
1134 g_return_val_if_fail (!g_path_is_absolute (file), FALSE);
1135
1136 user_data_dir = g_get_user_data_dir ();
1137 system_data_dirs = g_get_system_data_dirs ();
1138 all_data_dirs = g_new (gchar *, g_strv_length ((gchar **)system_data_dirs) + 2);
1139
1140 i = 0;
1141 all_data_dirs[i++] = g_strdup (str: user_data_dir);
1142
1143 j = 0;
1144 while (system_data_dirs[j] != NULL)
1145 all_data_dirs[i++] = g_strdup (str: system_data_dirs[j++]);
1146 all_data_dirs[i] = NULL;
1147
1148 found_file = g_key_file_load_from_dirs (key_file,
1149 file,
1150 search_dirs: (const gchar **)all_data_dirs,
1151 full_path,
1152 flags,
1153 error);
1154
1155 g_strfreev (str_array: all_data_dirs);
1156
1157 return found_file;
1158}
1159
1160/**
1161 * g_key_file_ref: (skip)
1162 * @key_file: a #GKeyFile
1163 *
1164 * Increases the reference count of @key_file.
1165 *
1166 * Returns: the same @key_file.
1167 *
1168 * Since: 2.32
1169 **/
1170GKeyFile *
1171g_key_file_ref (GKeyFile *key_file)
1172{
1173 g_return_val_if_fail (key_file != NULL, NULL);
1174
1175 g_atomic_int_inc (&key_file->ref_count);
1176
1177 return key_file;
1178}
1179
1180/**
1181 * g_key_file_free: (skip)
1182 * @key_file: a #GKeyFile
1183 *
1184 * Clears all keys and groups from @key_file, and decreases the
1185 * reference count by 1. If the reference count reaches zero,
1186 * frees the key file and all its allocated memory.
1187 *
1188 * Since: 2.6
1189 **/
1190void
1191g_key_file_free (GKeyFile *key_file)
1192{
1193 g_return_if_fail (key_file != NULL);
1194
1195 g_key_file_clear (key_file);
1196
1197 if (g_atomic_int_dec_and_test (&key_file->ref_count))
1198 g_slice_free (GKeyFile, key_file);
1199 else
1200 g_key_file_init (key_file);
1201}
1202
1203/**
1204 * g_key_file_unref:
1205 * @key_file: a #GKeyFile
1206 *
1207 * Decreases the reference count of @key_file by 1. If the reference count
1208 * reaches zero, frees the key file and all its allocated memory.
1209 *
1210 * Since: 2.32
1211 **/
1212void
1213g_key_file_unref (GKeyFile *key_file)
1214{
1215 g_return_if_fail (key_file != NULL);
1216
1217 if (g_atomic_int_dec_and_test (&key_file->ref_count))
1218 {
1219 g_key_file_clear (key_file);
1220 g_slice_free (GKeyFile, key_file);
1221 }
1222}
1223
1224/* If G_KEY_FILE_KEEP_TRANSLATIONS is not set, only returns
1225 * true for locales that match those in g_get_language_names().
1226 */
1227static gboolean
1228g_key_file_locale_is_interesting (GKeyFile *key_file,
1229 const gchar *locale)
1230{
1231 gsize i;
1232
1233 if (key_file->flags & G_KEY_FILE_KEEP_TRANSLATIONS)
1234 return TRUE;
1235
1236 if (!key_file->checked_locales)
1237 {
1238 key_file->locales = g_strdupv (str_array: (gchar **)g_get_language_names ());
1239 key_file->checked_locales = TRUE;
1240 }
1241
1242 for (i = 0; key_file->locales[i] != NULL; i++)
1243 {
1244 if (g_ascii_strcasecmp (s1: key_file->locales[i], s2: locale) == 0)
1245 return TRUE;
1246 }
1247
1248 return FALSE;
1249}
1250
1251static void
1252g_key_file_parse_line (GKeyFile *key_file,
1253 const gchar *line,
1254 gsize length,
1255 GError **error)
1256{
1257 GError *parse_error = NULL;
1258 gchar *line_start;
1259
1260 g_return_if_fail (key_file != NULL);
1261 g_return_if_fail (line != NULL);
1262
1263 line_start = (gchar *) line;
1264 while (g_ascii_isspace (*line_start))
1265 line_start++;
1266
1267 if (g_key_file_line_is_comment (line: line_start))
1268 g_key_file_parse_comment (key_file, line, length, error: &parse_error);
1269 else if (g_key_file_line_is_group (line: line_start))
1270 g_key_file_parse_group (key_file, line: line_start,
1271 length: length - (line_start - line),
1272 error: &parse_error);
1273 else if (g_key_file_line_is_key_value_pair (line: line_start))
1274 g_key_file_parse_key_value_pair (key_file, line: line_start,
1275 length: length - (line_start - line),
1276 error: &parse_error);
1277 else
1278 {
1279 gchar *line_utf8 = g_utf8_make_valid (str: line, len: length);
1280 g_set_error (err: error, G_KEY_FILE_ERROR,
1281 code: G_KEY_FILE_ERROR_PARSE,
1282 _("Key file contains line “%s” which is not "
1283 "a key-value pair, group, or comment"),
1284 line_utf8);
1285 g_free (mem: line_utf8);
1286
1287 return;
1288 }
1289
1290 if (parse_error)
1291 g_propagate_error (dest: error, src: parse_error);
1292}
1293
1294static void
1295g_key_file_parse_comment (GKeyFile *key_file,
1296 const gchar *line,
1297 gsize length,
1298 GError **error)
1299{
1300 GKeyFileKeyValuePair *pair;
1301
1302 if (!(key_file->flags & G_KEY_FILE_KEEP_COMMENTS))
1303 return;
1304
1305 g_warn_if_fail (key_file->current_group != NULL);
1306
1307 pair = g_slice_new (GKeyFileKeyValuePair);
1308 pair->key = NULL;
1309 pair->value = g_strndup (str: line, n: length);
1310
1311 key_file->current_group->key_value_pairs =
1312 g_list_prepend (list: key_file->current_group->key_value_pairs, data: pair);
1313}
1314
1315static void
1316g_key_file_parse_group (GKeyFile *key_file,
1317 const gchar *line,
1318 gsize length,
1319 GError **error)
1320{
1321 gchar *group_name;
1322 const gchar *group_name_start, *group_name_end;
1323
1324 /* advance past opening '['
1325 */
1326 group_name_start = line + 1;
1327 group_name_end = line + length - 1;
1328
1329 while (*group_name_end != ']')
1330 group_name_end--;
1331
1332 group_name = g_strndup (str: group_name_start,
1333 n: group_name_end - group_name_start);
1334
1335 if (!g_key_file_is_group_name (name: group_name))
1336 {
1337 g_set_error (err: error, G_KEY_FILE_ERROR,
1338 code: G_KEY_FILE_ERROR_PARSE,
1339 _("Invalid group name: %s"), group_name);
1340 g_free (mem: group_name);
1341 return;
1342 }
1343
1344 g_key_file_add_group (key_file, group_name);
1345 g_free (mem: group_name);
1346}
1347
1348static void
1349g_key_file_parse_key_value_pair (GKeyFile *key_file,
1350 const gchar *line,
1351 gsize length,
1352 GError **error)
1353{
1354 gchar *key, *value, *key_end, *value_start, *locale;
1355 gsize key_len, value_len;
1356
1357 if (key_file->current_group == NULL || key_file->current_group->name == NULL)
1358 {
1359 g_set_error_literal (err: error, G_KEY_FILE_ERROR,
1360 code: G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
1361 _("Key file does not start with a group"));
1362 return;
1363 }
1364
1365 key_end = value_start = strchr (s: line, c: '=');
1366
1367 g_warn_if_fail (key_end != NULL);
1368
1369 key_end--;
1370 value_start++;
1371
1372 /* Pull the key name from the line (chomping trailing whitespace)
1373 */
1374 while (g_ascii_isspace (*key_end))
1375 key_end--;
1376
1377 key_len = key_end - line + 2;
1378
1379 g_warn_if_fail (key_len <= length);
1380
1381 key = g_strndup (str: line, n: key_len - 1);
1382
1383 if (!g_key_file_is_key_name (name: key))
1384 {
1385 g_set_error (err: error, G_KEY_FILE_ERROR,
1386 code: G_KEY_FILE_ERROR_PARSE,
1387 _("Invalid key name: %s"), key);
1388 g_free (mem: key);
1389 return;
1390 }
1391
1392 /* Pull the value from the line (chugging leading whitespace)
1393 */
1394 while (g_ascii_isspace (*value_start))
1395 value_start++;
1396
1397 value_len = line + length - value_start + 1;
1398
1399 value = g_strndup (str: value_start, n: value_len);
1400
1401 g_warn_if_fail (key_file->start_group != NULL);
1402
1403 if (key_file->current_group
1404 && key_file->current_group->name
1405 && strcmp (s1: key_file->start_group->name,
1406 s2: key_file->current_group->name) == 0
1407 && strcmp (s1: key, s2: "Encoding") == 0)
1408 {
1409 if (g_ascii_strcasecmp (s1: value, s2: "UTF-8") != 0)
1410 {
1411 gchar *value_utf8 = g_utf8_make_valid (str: value, len: value_len);
1412 g_set_error (err: error, G_KEY_FILE_ERROR,
1413 code: G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
1414 _("Key file contains unsupported "
1415 "encoding “%s”"), value_utf8);
1416 g_free (mem: value_utf8);
1417
1418 g_free (mem: key);
1419 g_free (mem: value);
1420 return;
1421 }
1422 }
1423
1424 /* Is this key a translation? If so, is it one that we care about?
1425 */
1426 locale = key_get_locale (key);
1427
1428 if (locale == NULL || g_key_file_locale_is_interesting (key_file, locale))
1429 {
1430 GKeyFileKeyValuePair *pair;
1431
1432 pair = g_slice_new (GKeyFileKeyValuePair);
1433 pair->key = key;
1434 pair->value = value;
1435
1436 g_key_file_add_key_value_pair (key_file, group: key_file->current_group, pair);
1437 }
1438 else
1439 {
1440 g_free (mem: key);
1441 g_free (mem: value);
1442 }
1443
1444 g_free (mem: locale);
1445}
1446
1447static gchar *
1448key_get_locale (const gchar *key)
1449{
1450 gchar *locale;
1451
1452 locale = g_strrstr (haystack: key, needle: "[");
1453
1454 if (locale && strlen (s: locale) <= 2)
1455 locale = NULL;
1456
1457 if (locale)
1458 locale = g_strndup (str: locale + 1, n: strlen (s: locale) - 2);
1459
1460 return locale;
1461}
1462
1463static void
1464g_key_file_parse_data (GKeyFile *key_file,
1465 const gchar *data,
1466 gsize length,
1467 GError **error)
1468{
1469 GError *parse_error;
1470 gsize i;
1471
1472 g_return_if_fail (key_file != NULL);
1473 g_return_if_fail (data != NULL || length == 0);
1474
1475 parse_error = NULL;
1476
1477 if (!key_file->parse_buffer)
1478 key_file->parse_buffer = g_string_sized_new (dfl_size: 128);
1479
1480 i = 0;
1481 while (i < length)
1482 {
1483 if (data[i] == '\n')
1484 {
1485 if (key_file->parse_buffer->len > 0
1486 && (key_file->parse_buffer->str[key_file->parse_buffer->len - 1]
1487 == '\r'))
1488 g_string_erase (string: key_file->parse_buffer,
1489 pos: key_file->parse_buffer->len - 1,
1490 len: 1);
1491
1492 /* When a newline is encountered flush the parse buffer so that the
1493 * line can be parsed. Note that completely blank lines won't show
1494 * up in the parse buffer, so they get parsed directly.
1495 */
1496 if (key_file->parse_buffer->len > 0)
1497 g_key_file_flush_parse_buffer (key_file, error: &parse_error);
1498 else
1499 g_key_file_parse_comment (key_file, line: "", length: 1, error: &parse_error);
1500
1501 if (parse_error)
1502 {
1503 g_propagate_error (dest: error, src: parse_error);
1504 return;
1505 }
1506 i++;
1507 }
1508 else
1509 {
1510 const gchar *start_of_line;
1511 const gchar *end_of_line;
1512 gsize line_length;
1513
1514 start_of_line = data + i;
1515 end_of_line = memchr (s: start_of_line, c: '\n', n: length - i);
1516
1517 if (end_of_line == NULL)
1518 end_of_line = data + length;
1519
1520 line_length = end_of_line - start_of_line;
1521
1522 g_string_append_len (string: key_file->parse_buffer, val: start_of_line, len: line_length);
1523 i += line_length;
1524 }
1525 }
1526}
1527
1528static void
1529g_key_file_flush_parse_buffer (GKeyFile *key_file,
1530 GError **error)
1531{
1532 GError *file_error = NULL;
1533
1534 g_return_if_fail (key_file != NULL);
1535
1536 if (!key_file->parse_buffer)
1537 return;
1538
1539 file_error = NULL;
1540
1541 if (key_file->parse_buffer->len > 0)
1542 {
1543 g_key_file_parse_line (key_file, line: key_file->parse_buffer->str,
1544 length: key_file->parse_buffer->len,
1545 error: &file_error);
1546 g_string_erase (string: key_file->parse_buffer, pos: 0, len: -1);
1547
1548 if (file_error)
1549 {
1550 g_propagate_error (dest: error, src: file_error);
1551 return;
1552 }
1553 }
1554}
1555
1556/**
1557 * g_key_file_to_data:
1558 * @key_file: a #GKeyFile
1559 * @length: (out) (optional): return location for the length of the
1560 * returned string, or %NULL
1561 * @error: return location for a #GError, or %NULL
1562 *
1563 * This function outputs @key_file as a string.
1564 *
1565 * Note that this function never reports an error,
1566 * so it is safe to pass %NULL as @error.
1567 *
1568 * Returns: a newly allocated string holding
1569 * the contents of the #GKeyFile
1570 *
1571 * Since: 2.6
1572 **/
1573gchar *
1574g_key_file_to_data (GKeyFile *key_file,
1575 gsize *length,
1576 GError **error)
1577{
1578 GString *data_string;
1579 GList *group_node, *key_file_node;
1580
1581 g_return_val_if_fail (key_file != NULL, NULL);
1582
1583 data_string = g_string_new (NULL);
1584
1585 for (group_node = g_list_last (list: key_file->groups);
1586 group_node != NULL;
1587 group_node = group_node->prev)
1588 {
1589 GKeyFileGroup *group;
1590
1591 group = (GKeyFileGroup *) group_node->data;
1592
1593 /* separate groups by at least an empty line */
1594 if (data_string->len >= 2 &&
1595 data_string->str[data_string->len - 2] != '\n')
1596 g_string_append_c (data_string, '\n');
1597
1598 if (group->comment != NULL)
1599 g_string_append_printf (string: data_string, format: "%s\n", group->comment->value);
1600
1601 if (group->name != NULL)
1602 g_string_append_printf (string: data_string, format: "[%s]\n", group->name);
1603
1604 for (key_file_node = g_list_last (list: group->key_value_pairs);
1605 key_file_node != NULL;
1606 key_file_node = key_file_node->prev)
1607 {
1608 GKeyFileKeyValuePair *pair;
1609
1610 pair = (GKeyFileKeyValuePair *) key_file_node->data;
1611
1612 if (pair->key != NULL)
1613 g_string_append_printf (string: data_string, format: "%s=%s\n", pair->key, pair->value);
1614 else
1615 g_string_append_printf (string: data_string, format: "%s\n", pair->value);
1616 }
1617 }
1618
1619 if (length)
1620 *length = data_string->len;
1621
1622 return g_string_free (string: data_string, FALSE);
1623}
1624
1625/**
1626 * g_key_file_get_keys:
1627 * @key_file: a #GKeyFile
1628 * @group_name: a group name
1629 * @length: (out) (optional): return location for the number of keys returned, or %NULL
1630 * @error: return location for a #GError, or %NULL
1631 *
1632 * Returns all keys for the group name @group_name. The array of
1633 * returned keys will be %NULL-terminated, so @length may
1634 * optionally be %NULL. In the event that the @group_name cannot
1635 * be found, %NULL is returned and @error is set to
1636 * #G_KEY_FILE_ERROR_GROUP_NOT_FOUND.
1637 *
1638 * Returns: (array zero-terminated=1) (transfer full): a newly-allocated %NULL-terminated array of strings.
1639 * Use g_strfreev() to free it.
1640 *
1641 * Since: 2.6
1642 **/
1643gchar **
1644g_key_file_get_keys (GKeyFile *key_file,
1645 const gchar *group_name,
1646 gsize *length,
1647 GError **error)
1648{
1649 GKeyFileGroup *group;
1650 GList *tmp;
1651 gchar **keys;
1652 gsize i, num_keys;
1653
1654 g_return_val_if_fail (key_file != NULL, NULL);
1655 g_return_val_if_fail (group_name != NULL, NULL);
1656
1657 group = g_key_file_lookup_group (key_file, group_name);
1658
1659 if (!group)
1660 {
1661 g_set_error (err: error, G_KEY_FILE_ERROR,
1662 code: G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
1663 _("Key file does not have group “%s”"),
1664 group_name);
1665 return NULL;
1666 }
1667
1668 num_keys = 0;
1669 for (tmp = group->key_value_pairs; tmp; tmp = tmp->next)
1670 {
1671 GKeyFileKeyValuePair *pair;
1672
1673 pair = (GKeyFileKeyValuePair *) tmp->data;
1674
1675 if (pair->key)
1676 num_keys++;
1677 }
1678
1679 keys = g_new (gchar *, num_keys + 1);
1680
1681 i = num_keys - 1;
1682 for (tmp = group->key_value_pairs; tmp; tmp = tmp->next)
1683 {
1684 GKeyFileKeyValuePair *pair;
1685
1686 pair = (GKeyFileKeyValuePair *) tmp->data;
1687
1688 if (pair->key)
1689 {
1690 keys[i] = g_strdup (str: pair->key);
1691 i--;
1692 }
1693 }
1694
1695 keys[num_keys] = NULL;
1696
1697 if (length)
1698 *length = num_keys;
1699
1700 return keys;
1701}
1702
1703/**
1704 * g_key_file_get_start_group:
1705 * @key_file: a #GKeyFile
1706 *
1707 * Returns the name of the start group of the file.
1708 *
1709 * Returns: (nullable): The start group of the key file.
1710 *
1711 * Since: 2.6
1712 **/
1713gchar *
1714g_key_file_get_start_group (GKeyFile *key_file)
1715{
1716 g_return_val_if_fail (key_file != NULL, NULL);
1717
1718 if (key_file->start_group)
1719 return g_strdup (str: key_file->start_group->name);
1720
1721 return NULL;
1722}
1723
1724/**
1725 * g_key_file_get_groups:
1726 * @key_file: a #GKeyFile
1727 * @length: (out) (optional): return location for the number of returned groups, or %NULL
1728 *
1729 * Returns all groups in the key file loaded with @key_file.
1730 * The array of returned groups will be %NULL-terminated, so
1731 * @length may optionally be %NULL.
1732 *
1733 * Returns: (array zero-terminated=1) (transfer full): a newly-allocated %NULL-terminated array of strings.
1734 * Use g_strfreev() to free it.
1735 * Since: 2.6
1736 **/
1737gchar **
1738g_key_file_get_groups (GKeyFile *key_file,
1739 gsize *length)
1740{
1741 GList *group_node;
1742 gchar **groups;
1743 gsize i, num_groups;
1744
1745 g_return_val_if_fail (key_file != NULL, NULL);
1746
1747 num_groups = g_list_length (list: key_file->groups);
1748
1749 g_return_val_if_fail (num_groups > 0, NULL);
1750
1751 group_node = g_list_last (list: key_file->groups);
1752
1753 g_return_val_if_fail (((GKeyFileGroup *) group_node->data)->name == NULL, NULL);
1754
1755 /* Only need num_groups instead of num_groups + 1
1756 * because the first group of the file (last in the
1757 * list) is always the comment group at the top,
1758 * which we skip
1759 */
1760 groups = g_new (gchar *, num_groups);
1761
1762
1763 i = 0;
1764 for (group_node = group_node->prev;
1765 group_node != NULL;
1766 group_node = group_node->prev)
1767 {
1768 GKeyFileGroup *group;
1769
1770 group = (GKeyFileGroup *) group_node->data;
1771
1772 g_warn_if_fail (group->name != NULL);
1773
1774 groups[i++] = g_strdup (str: group->name);
1775 }
1776 groups[i] = NULL;
1777
1778 if (length)
1779 *length = i;
1780
1781 return groups;
1782}
1783
1784static void
1785set_not_found_key_error (const char *group_name,
1786 const char *key,
1787 GError **error)
1788{
1789 g_set_error (err: error, G_KEY_FILE_ERROR,
1790 code: G_KEY_FILE_ERROR_KEY_NOT_FOUND,
1791 _("Key file does not have key “%s” in group “%s”"),
1792 key, group_name);
1793}
1794
1795/**
1796 * g_key_file_get_value:
1797 * @key_file: a #GKeyFile
1798 * @group_name: a group name
1799 * @key: a key
1800 * @error: return location for a #GError, or %NULL
1801 *
1802 * Returns the raw value associated with @key under @group_name.
1803 * Use g_key_file_get_string() to retrieve an unescaped UTF-8 string.
1804 *
1805 * In the event the key cannot be found, %NULL is returned and
1806 * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. In the
1807 * event that the @group_name cannot be found, %NULL is returned
1808 * and @error is set to #G_KEY_FILE_ERROR_GROUP_NOT_FOUND.
1809 *
1810 *
1811 * Returns: a newly allocated string or %NULL if the specified
1812 * key cannot be found.
1813 *
1814 * Since: 2.6
1815 **/
1816gchar *
1817g_key_file_get_value (GKeyFile *key_file,
1818 const gchar *group_name,
1819 const gchar *key,
1820 GError **error)
1821{
1822 GKeyFileGroup *group;
1823 GKeyFileKeyValuePair *pair;
1824 gchar *value = NULL;
1825
1826 g_return_val_if_fail (key_file != NULL, NULL);
1827 g_return_val_if_fail (group_name != NULL, NULL);
1828 g_return_val_if_fail (key != NULL, NULL);
1829
1830 group = g_key_file_lookup_group (key_file, group_name);
1831
1832 if (!group)
1833 {
1834 g_set_error (err: error, G_KEY_FILE_ERROR,
1835 code: G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
1836 _("Key file does not have group “%s”"),
1837 group_name);
1838 return NULL;
1839 }
1840
1841 pair = g_key_file_lookup_key_value_pair (key_file, group, key);
1842
1843 if (pair)
1844 value = g_strdup (str: pair->value);
1845 else
1846 set_not_found_key_error (group_name, key, error);
1847
1848 return value;
1849}
1850
1851/**
1852 * g_key_file_set_value:
1853 * @key_file: a #GKeyFile
1854 * @group_name: a group name
1855 * @key: a key
1856 * @value: a string
1857 *
1858 * Associates a new value with @key under @group_name.
1859 *
1860 * If @key cannot be found then it is created. If @group_name cannot
1861 * be found then it is created. To set an UTF-8 string which may contain
1862 * characters that need escaping (such as newlines or spaces), use
1863 * g_key_file_set_string().
1864 *
1865 * Since: 2.6
1866 **/
1867void
1868g_key_file_set_value (GKeyFile *key_file,
1869 const gchar *group_name,
1870 const gchar *key,
1871 const gchar *value)
1872{
1873 GKeyFileGroup *group;
1874 GKeyFileKeyValuePair *pair;
1875
1876 g_return_if_fail (key_file != NULL);
1877 g_return_if_fail (g_key_file_is_group_name (group_name));
1878 g_return_if_fail (g_key_file_is_key_name (key));
1879 g_return_if_fail (value != NULL);
1880
1881 group = g_key_file_lookup_group (key_file, group_name);
1882
1883 if (!group)
1884 {
1885 g_key_file_add_group (key_file, group_name);
1886 group = (GKeyFileGroup *) key_file->groups->data;
1887
1888 g_key_file_add_key (key_file, group, key, value);
1889 }
1890 else
1891 {
1892 pair = g_key_file_lookup_key_value_pair (key_file, group, key);
1893
1894 if (!pair)
1895 g_key_file_add_key (key_file, group, key, value);
1896 else
1897 {
1898 g_free (mem: pair->value);
1899 pair->value = g_strdup (str: value);
1900 }
1901 }
1902}
1903
1904/**
1905 * g_key_file_get_string:
1906 * @key_file: a #GKeyFile
1907 * @group_name: a group name
1908 * @key: a key
1909 * @error: return location for a #GError, or %NULL
1910 *
1911 * Returns the string value associated with @key under @group_name.
1912 * Unlike g_key_file_get_value(), this function handles escape sequences
1913 * like \s.
1914 *
1915 * In the event the key cannot be found, %NULL is returned and
1916 * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. In the
1917 * event that the @group_name cannot be found, %NULL is returned
1918 * and @error is set to #G_KEY_FILE_ERROR_GROUP_NOT_FOUND.
1919 *
1920 * Returns: a newly allocated string or %NULL if the specified
1921 * key cannot be found.
1922 *
1923 * Since: 2.6
1924 **/
1925gchar *
1926g_key_file_get_string (GKeyFile *key_file,
1927 const gchar *group_name,
1928 const gchar *key,
1929 GError **error)
1930{
1931 gchar *value, *string_value;
1932 GError *key_file_error;
1933
1934 g_return_val_if_fail (key_file != NULL, NULL);
1935 g_return_val_if_fail (group_name != NULL, NULL);
1936 g_return_val_if_fail (key != NULL, NULL);
1937
1938 key_file_error = NULL;
1939
1940 value = g_key_file_get_value (key_file, group_name, key, error: &key_file_error);
1941
1942 if (key_file_error)
1943 {
1944 g_propagate_error (dest: error, src: key_file_error);
1945 return NULL;
1946 }
1947
1948 if (!g_utf8_validate (str: value, max_len: -1, NULL))
1949 {
1950 gchar *value_utf8 = g_utf8_make_valid (str: value, len: -1);
1951 g_set_error (err: error, G_KEY_FILE_ERROR,
1952 code: G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
1953 _("Key file contains key “%s” with value “%s” "
1954 "which is not UTF-8"), key, value_utf8);
1955 g_free (mem: value_utf8);
1956 g_free (mem: value);
1957
1958 return NULL;
1959 }
1960
1961 string_value = g_key_file_parse_value_as_string (key_file, value, NULL,
1962 error: &key_file_error);
1963 g_free (mem: value);
1964
1965 if (key_file_error)
1966 {
1967 if (g_error_matches (error: key_file_error,
1968 G_KEY_FILE_ERROR,
1969 code: G_KEY_FILE_ERROR_INVALID_VALUE))
1970 {
1971 g_set_error (err: error, G_KEY_FILE_ERROR,
1972 code: G_KEY_FILE_ERROR_INVALID_VALUE,
1973 _("Key file contains key “%s” "
1974 "which has a value that cannot be interpreted."),
1975 key);
1976 g_error_free (error: key_file_error);
1977 }
1978 else
1979 g_propagate_error (dest: error, src: key_file_error);
1980 }
1981
1982 return string_value;
1983}
1984
1985/**
1986 * g_key_file_set_string:
1987 * @key_file: a #GKeyFile
1988 * @group_name: a group name
1989 * @key: a key
1990 * @string: a string
1991 *
1992 * Associates a new string value with @key under @group_name.
1993 * If @key cannot be found then it is created.
1994 * If @group_name cannot be found then it is created.
1995 * Unlike g_key_file_set_value(), this function handles characters
1996 * that need escaping, such as newlines.
1997 *
1998 * Since: 2.6
1999 **/
2000void
2001g_key_file_set_string (GKeyFile *key_file,
2002 const gchar *group_name,
2003 const gchar *key,
2004 const gchar *string)
2005{
2006 gchar *value;
2007
2008 g_return_if_fail (key_file != NULL);
2009 g_return_if_fail (string != NULL);
2010
2011 value = g_key_file_parse_string_as_value (key_file, string, FALSE);
2012 g_key_file_set_value (key_file, group_name, key, value);
2013 g_free (mem: value);
2014}
2015
2016/**
2017 * g_key_file_get_string_list:
2018 * @key_file: a #GKeyFile
2019 * @group_name: a group name
2020 * @key: a key
2021 * @length: (out) (optional): return location for the number of returned strings, or %NULL
2022 * @error: return location for a #GError, or %NULL
2023 *
2024 * Returns the values associated with @key under @group_name.
2025 *
2026 * In the event the key cannot be found, %NULL is returned and
2027 * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. In the
2028 * event that the @group_name cannot be found, %NULL is returned
2029 * and @error is set to #G_KEY_FILE_ERROR_GROUP_NOT_FOUND.
2030 *
2031 * Returns: (array zero-terminated=1 length=length) (element-type utf8) (transfer full):
2032 * a %NULL-terminated string array or %NULL if the specified
2033 * key cannot be found. The array should be freed with g_strfreev().
2034 *
2035 * Since: 2.6
2036 **/
2037gchar **
2038g_key_file_get_string_list (GKeyFile *key_file,
2039 const gchar *group_name,
2040 const gchar *key,
2041 gsize *length,
2042 GError **error)
2043{
2044 GError *key_file_error = NULL;
2045 gchar *value, *string_value, **values;
2046 gint i, len;
2047 GSList *p, *pieces = NULL;
2048
2049 g_return_val_if_fail (key_file != NULL, NULL);
2050 g_return_val_if_fail (group_name != NULL, NULL);
2051 g_return_val_if_fail (key != NULL, NULL);
2052
2053 if (length)
2054 *length = 0;
2055
2056 value = g_key_file_get_value (key_file, group_name, key, error: &key_file_error);
2057
2058 if (key_file_error)
2059 {
2060 g_propagate_error (dest: error, src: key_file_error);
2061 return NULL;
2062 }
2063
2064 if (!g_utf8_validate (str: value, max_len: -1, NULL))
2065 {
2066 gchar *value_utf8 = g_utf8_make_valid (str: value, len: -1);
2067 g_set_error (err: error, G_KEY_FILE_ERROR,
2068 code: G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
2069 _("Key file contains key “%s” with value “%s” "
2070 "which is not UTF-8"), key, value_utf8);
2071 g_free (mem: value_utf8);
2072 g_free (mem: value);
2073
2074 return NULL;
2075 }
2076
2077 string_value = g_key_file_parse_value_as_string (key_file, value, separators: &pieces, error: &key_file_error);
2078 g_free (mem: value);
2079 g_free (mem: string_value);
2080
2081 if (key_file_error)
2082 {
2083 if (g_error_matches (error: key_file_error,
2084 G_KEY_FILE_ERROR,
2085 code: G_KEY_FILE_ERROR_INVALID_VALUE))
2086 {
2087 g_set_error (err: error, G_KEY_FILE_ERROR,
2088 code: G_KEY_FILE_ERROR_INVALID_VALUE,
2089 _("Key file contains key “%s” "
2090 "which has a value that cannot be interpreted."),
2091 key);
2092 g_error_free (error: key_file_error);
2093 }
2094 else
2095 g_propagate_error (dest: error, src: key_file_error);
2096
2097 g_slist_free_full (list: pieces, free_func: g_free);
2098 return NULL;
2099 }
2100
2101 len = g_slist_length (list: pieces);
2102 values = g_new (gchar *, len + 1);
2103 for (p = pieces, i = 0; p; p = p->next)
2104 values[i++] = p->data;
2105 values[len] = NULL;
2106
2107 g_slist_free (list: pieces);
2108
2109 if (length)
2110 *length = len;
2111
2112 return values;
2113}
2114
2115/**
2116 * g_key_file_set_string_list:
2117 * @key_file: a #GKeyFile
2118 * @group_name: a group name
2119 * @key: a key
2120 * @list: (array zero-terminated=1 length=length) (element-type utf8): an array of string values
2121 * @length: number of string values in @list
2122 *
2123 * Associates a list of string values for @key under @group_name.
2124 * If @key cannot be found then it is created.
2125 * If @group_name cannot be found then it is created.
2126 *
2127 * Since: 2.6
2128 **/
2129void
2130g_key_file_set_string_list (GKeyFile *key_file,
2131 const gchar *group_name,
2132 const gchar *key,
2133 const gchar * const list[],
2134 gsize length)
2135{
2136 GString *value_list;
2137 gsize i;
2138
2139 g_return_if_fail (key_file != NULL);
2140 g_return_if_fail (list != NULL || length == 0);
2141
2142 value_list = g_string_sized_new (dfl_size: length * 128);
2143 for (i = 0; i < length && list[i] != NULL; i++)
2144 {
2145 gchar *value;
2146
2147 value = g_key_file_parse_string_as_value (key_file, string: list[i], TRUE);
2148 g_string_append (string: value_list, val: value);
2149 g_string_append_c (value_list, key_file->list_separator);
2150
2151 g_free (mem: value);
2152 }
2153
2154 g_key_file_set_value (key_file, group_name, key, value: value_list->str);
2155 g_string_free (string: value_list, TRUE);
2156}
2157
2158/**
2159 * g_key_file_set_locale_string:
2160 * @key_file: a #GKeyFile
2161 * @group_name: a group name
2162 * @key: a key
2163 * @locale: a locale identifier
2164 * @string: a string
2165 *
2166 * Associates a string value for @key and @locale under @group_name.
2167 * If the translation for @key cannot be found then it is created.
2168 *
2169 * Since: 2.6
2170 **/
2171void
2172g_key_file_set_locale_string (GKeyFile *key_file,
2173 const gchar *group_name,
2174 const gchar *key,
2175 const gchar *locale,
2176 const gchar *string)
2177{
2178 gchar *full_key, *value;
2179
2180 g_return_if_fail (key_file != NULL);
2181 g_return_if_fail (key != NULL);
2182 g_return_if_fail (locale != NULL);
2183 g_return_if_fail (string != NULL);
2184
2185 value = g_key_file_parse_string_as_value (key_file, string, FALSE);
2186 full_key = g_strdup_printf (format: "%s[%s]", key, locale);
2187 g_key_file_set_value (key_file, group_name, key: full_key, value);
2188 g_free (mem: full_key);
2189 g_free (mem: value);
2190}
2191
2192/**
2193 * g_key_file_get_locale_string:
2194 * @key_file: a #GKeyFile
2195 * @group_name: a group name
2196 * @key: a key
2197 * @locale: (nullable): a locale identifier or %NULL
2198 * @error: return location for a #GError, or %NULL
2199 *
2200 * Returns the value associated with @key under @group_name
2201 * translated in the given @locale if available. If @locale is
2202 * %NULL then the current locale is assumed.
2203 *
2204 * If @locale is to be non-%NULL, or if the current locale will change over
2205 * the lifetime of the #GKeyFile, it must be loaded with
2206 * %G_KEY_FILE_KEEP_TRANSLATIONS in order to load strings for all locales.
2207 *
2208 * If @key cannot be found then %NULL is returned and @error is set
2209 * to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. If the value associated
2210 * with @key cannot be interpreted or no suitable translation can
2211 * be found then the untranslated value is returned.
2212 *
2213 * Returns: a newly allocated string or %NULL if the specified
2214 * key cannot be found.
2215 *
2216 * Since: 2.6
2217 **/
2218gchar *
2219g_key_file_get_locale_string (GKeyFile *key_file,
2220 const gchar *group_name,
2221 const gchar *key,
2222 const gchar *locale,
2223 GError **error)
2224{
2225 gchar *candidate_key, *translated_value;
2226 GError *key_file_error;
2227 gchar **languages;
2228 gboolean free_languages = FALSE;
2229 gint i;
2230
2231 g_return_val_if_fail (key_file != NULL, NULL);
2232 g_return_val_if_fail (group_name != NULL, NULL);
2233 g_return_val_if_fail (key != NULL, NULL);
2234
2235 candidate_key = NULL;
2236 translated_value = NULL;
2237 key_file_error = NULL;
2238
2239 if (locale)
2240 {
2241 languages = g_get_locale_variants (locale);
2242 free_languages = TRUE;
2243 }
2244 else
2245 {
2246 languages = (gchar **) g_get_language_names ();
2247 free_languages = FALSE;
2248 }
2249
2250 for (i = 0; languages[i]; i++)
2251 {
2252 candidate_key = g_strdup_printf (format: "%s[%s]", key, languages[i]);
2253
2254 translated_value = g_key_file_get_string (key_file,
2255 group_name,
2256 key: candidate_key, NULL);
2257 g_free (mem: candidate_key);
2258
2259 if (translated_value)
2260 break;
2261
2262 g_free (mem: translated_value);
2263 translated_value = NULL;
2264 }
2265
2266 /* Fallback to untranslated key
2267 */
2268 if (!translated_value)
2269 {
2270 translated_value = g_key_file_get_string (key_file, group_name, key,
2271 error: &key_file_error);
2272
2273 if (!translated_value)
2274 g_propagate_error (dest: error, src: key_file_error);
2275 }
2276
2277 if (free_languages)
2278 g_strfreev (str_array: languages);
2279
2280 return translated_value;
2281}
2282
2283/**
2284 * g_key_file_get_locale_for_key:
2285 * @key_file: a #GKeyFile
2286 * @group_name: a group name
2287 * @key: a key
2288 * @locale: (nullable): a locale identifier or %NULL
2289 *
2290 * Returns the actual locale which the result of
2291 * g_key_file_get_locale_string() or g_key_file_get_locale_string_list()
2292 * came from.
2293 *
2294 * If calling g_key_file_get_locale_string() or
2295 * g_key_file_get_locale_string_list() with exactly the same @key_file,
2296 * @group_name, @key and @locale, the result of those functions will
2297 * have originally been tagged with the locale that is the result of
2298 * this function.
2299 *
2300 * Returns: (nullable): the locale from the file, or %NULL if the key was not
2301 * found or the entry in the file was was untranslated
2302 *
2303 * Since: 2.56
2304 */
2305gchar *
2306g_key_file_get_locale_for_key (GKeyFile *key_file,
2307 const gchar *group_name,
2308 const gchar *key,
2309 const gchar *locale)
2310{
2311 gchar **languages_allocated = NULL;
2312 const gchar * const *languages;
2313 gchar *result = NULL;
2314 gsize i;
2315
2316 g_return_val_if_fail (key_file != NULL, NULL);
2317 g_return_val_if_fail (group_name != NULL, NULL);
2318 g_return_val_if_fail (key != NULL, NULL);
2319
2320 if (locale != NULL)
2321 {
2322 languages_allocated = g_get_locale_variants (locale);
2323 languages = (const gchar * const *) languages_allocated;
2324 }
2325 else
2326 languages = g_get_language_names ();
2327
2328 for (i = 0; languages[i] != NULL; i++)
2329 {
2330 gchar *candidate_key, *translated_value;
2331
2332 candidate_key = g_strdup_printf (format: "%s[%s]", key, languages[i]);
2333 translated_value = g_key_file_get_string (key_file, group_name, key: candidate_key, NULL);
2334 g_free (mem: translated_value);
2335 g_free (mem: candidate_key);
2336
2337 if (translated_value != NULL)
2338 break;
2339 }
2340
2341 result = g_strdup (str: languages[i]);
2342
2343 g_strfreev (str_array: languages_allocated);
2344
2345 return result;
2346}
2347
2348/**
2349 * g_key_file_get_locale_string_list:
2350 * @key_file: a #GKeyFile
2351 * @group_name: a group name
2352 * @key: a key
2353 * @locale: (nullable): a locale identifier or %NULL
2354 * @length: (out) (optional): return location for the number of returned strings or %NULL
2355 * @error: return location for a #GError or %NULL
2356 *
2357 * Returns the values associated with @key under @group_name
2358 * translated in the given @locale if available. If @locale is
2359 * %NULL then the current locale is assumed.
2360 *
2361 * If @locale is to be non-%NULL, or if the current locale will change over
2362 * the lifetime of the #GKeyFile, it must be loaded with
2363 * %G_KEY_FILE_KEEP_TRANSLATIONS in order to load strings for all locales.
2364 *
2365 * If @key cannot be found then %NULL is returned and @error is set
2366 * to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. If the values associated
2367 * with @key cannot be interpreted or no suitable translations
2368 * can be found then the untranslated values are returned. The
2369 * returned array is %NULL-terminated, so @length may optionally
2370 * be %NULL.
2371 *
2372 * Returns: (array zero-terminated=1 length=length) (element-type utf8) (transfer full): a newly allocated %NULL-terminated string array
2373 * or %NULL if the key isn't found. The string array should be freed
2374 * with g_strfreev().
2375 *
2376 * Since: 2.6
2377 **/
2378gchar **
2379g_key_file_get_locale_string_list (GKeyFile *key_file,
2380 const gchar *group_name,
2381 const gchar *key,
2382 const gchar *locale,
2383 gsize *length,
2384 GError **error)
2385{
2386 GError *key_file_error;
2387 gchar **values, *value;
2388 char list_separator[2];
2389 gsize len;
2390
2391 g_return_val_if_fail (key_file != NULL, NULL);
2392 g_return_val_if_fail (group_name != NULL, NULL);
2393 g_return_val_if_fail (key != NULL, NULL);
2394
2395 key_file_error = NULL;
2396
2397 value = g_key_file_get_locale_string (key_file, group_name,
2398 key, locale,
2399 error: &key_file_error);
2400
2401 if (key_file_error)
2402 g_propagate_error (dest: error, src: key_file_error);
2403
2404 if (!value)
2405 {
2406 if (length)
2407 *length = 0;
2408 return NULL;
2409 }
2410
2411 len = strlen (s: value);
2412 if (value[len - 1] == key_file->list_separator)
2413 value[len - 1] = '\0';
2414
2415 list_separator[0] = key_file->list_separator;
2416 list_separator[1] = '\0';
2417 values = g_strsplit (string: value, delimiter: list_separator, max_tokens: 0);
2418
2419 g_free (mem: value);
2420
2421 if (length)
2422 *length = g_strv_length (str_array: values);
2423
2424 return values;
2425}
2426
2427/**
2428 * g_key_file_set_locale_string_list:
2429 * @key_file: a #GKeyFile
2430 * @group_name: a group name
2431 * @key: a key
2432 * @locale: a locale identifier
2433 * @list: (array zero-terminated=1 length=length): a %NULL-terminated array of locale string values
2434 * @length: the length of @list
2435 *
2436 * Associates a list of string values for @key and @locale under
2437 * @group_name. If the translation for @key cannot be found then
2438 * it is created.
2439 *
2440 * Since: 2.6
2441 **/
2442void
2443g_key_file_set_locale_string_list (GKeyFile *key_file,
2444 const gchar *group_name,
2445 const gchar *key,
2446 const gchar *locale,
2447 const gchar * const list[],
2448 gsize length)
2449{
2450 GString *value_list;
2451 gchar *full_key;
2452 gsize i;
2453
2454 g_return_if_fail (key_file != NULL);
2455 g_return_if_fail (key != NULL);
2456 g_return_if_fail (locale != NULL);
2457 g_return_if_fail (length != 0);
2458
2459 value_list = g_string_sized_new (dfl_size: length * 128);
2460 for (i = 0; i < length && list[i] != NULL; i++)
2461 {
2462 gchar *value;
2463
2464 value = g_key_file_parse_string_as_value (key_file, string: list[i], TRUE);
2465 g_string_append (string: value_list, val: value);
2466 g_string_append_c (value_list, key_file->list_separator);
2467
2468 g_free (mem: value);
2469 }
2470
2471 full_key = g_strdup_printf (format: "%s[%s]", key, locale);
2472 g_key_file_set_value (key_file, group_name, key: full_key, value: value_list->str);
2473 g_free (mem: full_key);
2474 g_string_free (string: value_list, TRUE);
2475}
2476
2477/**
2478 * g_key_file_get_boolean:
2479 * @key_file: a #GKeyFile
2480 * @group_name: a group name
2481 * @key: a key
2482 * @error: return location for a #GError
2483 *
2484 * Returns the value associated with @key under @group_name as a
2485 * boolean.
2486 *
2487 * If @key cannot be found then %FALSE is returned and @error is set
2488 * to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if the value
2489 * associated with @key cannot be interpreted as a boolean then %FALSE
2490 * is returned and @error is set to #G_KEY_FILE_ERROR_INVALID_VALUE.
2491 *
2492 * Returns: the value associated with the key as a boolean,
2493 * or %FALSE if the key was not found or could not be parsed.
2494 *
2495 * Since: 2.6
2496 **/
2497gboolean
2498g_key_file_get_boolean (GKeyFile *key_file,
2499 const gchar *group_name,
2500 const gchar *key,
2501 GError **error)
2502{
2503 GError *key_file_error = NULL;
2504 gchar *value;
2505 gboolean bool_value;
2506
2507 g_return_val_if_fail (key_file != NULL, FALSE);
2508 g_return_val_if_fail (group_name != NULL, FALSE);
2509 g_return_val_if_fail (key != NULL, FALSE);
2510
2511 value = g_key_file_get_value (key_file, group_name, key, error: &key_file_error);
2512
2513 if (!value)
2514 {
2515 g_propagate_error (dest: error, src: key_file_error);
2516 return FALSE;
2517 }
2518
2519 bool_value = g_key_file_parse_value_as_boolean (key_file, value,
2520 error: &key_file_error);
2521 g_free (mem: value);
2522
2523 if (key_file_error)
2524 {
2525 if (g_error_matches (error: key_file_error,
2526 G_KEY_FILE_ERROR,
2527 code: G_KEY_FILE_ERROR_INVALID_VALUE))
2528 {
2529 g_set_error (err: error, G_KEY_FILE_ERROR,
2530 code: G_KEY_FILE_ERROR_INVALID_VALUE,
2531 _("Key file contains key “%s” "
2532 "which has a value that cannot be interpreted."),
2533 key);
2534 g_error_free (error: key_file_error);
2535 }
2536 else
2537 g_propagate_error (dest: error, src: key_file_error);
2538 }
2539
2540 return bool_value;
2541}
2542
2543/**
2544 * g_key_file_set_boolean:
2545 * @key_file: a #GKeyFile
2546 * @group_name: a group name
2547 * @key: a key
2548 * @value: %TRUE or %FALSE
2549 *
2550 * Associates a new boolean value with @key under @group_name.
2551 * If @key cannot be found then it is created.
2552 *
2553 * Since: 2.6
2554 **/
2555void
2556g_key_file_set_boolean (GKeyFile *key_file,
2557 const gchar *group_name,
2558 const gchar *key,
2559 gboolean value)
2560{
2561 gchar *result;
2562
2563 g_return_if_fail (key_file != NULL);
2564
2565 result = g_key_file_parse_boolean_as_value (key_file, value);
2566 g_key_file_set_value (key_file, group_name, key, value: result);
2567 g_free (mem: result);
2568}
2569
2570/**
2571 * g_key_file_get_boolean_list:
2572 * @key_file: a #GKeyFile
2573 * @group_name: a group name
2574 * @key: a key
2575 * @length: (out): the number of booleans returned
2576 * @error: return location for a #GError
2577 *
2578 * Returns the values associated with @key under @group_name as
2579 * booleans.
2580 *
2581 * If @key cannot be found then %NULL is returned and @error is set to
2582 * #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if the values associated
2583 * with @key cannot be interpreted as booleans then %NULL is returned
2584 * and @error is set to #G_KEY_FILE_ERROR_INVALID_VALUE.
2585 *
2586 * Returns: (array length=length) (element-type gboolean) (transfer container):
2587 * the values associated with the key as a list of booleans, or %NULL if the
2588 * key was not found or could not be parsed. The returned list of booleans
2589 * should be freed with g_free() when no longer needed.
2590 *
2591 * Since: 2.6
2592 **/
2593gboolean *
2594g_key_file_get_boolean_list (GKeyFile *key_file,
2595 const gchar *group_name,
2596 const gchar *key,
2597 gsize *length,
2598 GError **error)
2599{
2600 GError *key_file_error;
2601 gchar **values;
2602 gboolean *bool_values;
2603 gsize i, num_bools;
2604
2605 g_return_val_if_fail (key_file != NULL, NULL);
2606 g_return_val_if_fail (group_name != NULL, NULL);
2607 g_return_val_if_fail (key != NULL, NULL);
2608
2609 if (length)
2610 *length = 0;
2611
2612 key_file_error = NULL;
2613
2614 values = g_key_file_get_string_list (key_file, group_name, key,
2615 length: &num_bools, error: &key_file_error);
2616
2617 if (key_file_error)
2618 g_propagate_error (dest: error, src: key_file_error);
2619
2620 if (!values)
2621 return NULL;
2622
2623 bool_values = g_new (gboolean, num_bools);
2624
2625 for (i = 0; i < num_bools; i++)
2626 {
2627 bool_values[i] = g_key_file_parse_value_as_boolean (key_file,
2628 value: values[i],
2629 error: &key_file_error);
2630
2631 if (key_file_error)
2632 {
2633 g_propagate_error (dest: error, src: key_file_error);
2634 g_strfreev (str_array: values);
2635 g_free (mem: bool_values);
2636
2637 return NULL;
2638 }
2639 }
2640 g_strfreev (str_array: values);
2641
2642 if (length)
2643 *length = num_bools;
2644
2645 return bool_values;
2646}
2647
2648/**
2649 * g_key_file_set_boolean_list:
2650 * @key_file: a #GKeyFile
2651 * @group_name: a group name
2652 * @key: a key
2653 * @list: (array length=length): an array of boolean values
2654 * @length: length of @list
2655 *
2656 * Associates a list of boolean values with @key under @group_name.
2657 * If @key cannot be found then it is created.
2658 * If @group_name is %NULL, the start_group is used.
2659 *
2660 * Since: 2.6
2661 **/
2662void
2663g_key_file_set_boolean_list (GKeyFile *key_file,
2664 const gchar *group_name,
2665 const gchar *key,
2666 gboolean list[],
2667 gsize length)
2668{
2669 GString *value_list;
2670 gsize i;
2671
2672 g_return_if_fail (key_file != NULL);
2673 g_return_if_fail (list != NULL);
2674
2675 value_list = g_string_sized_new (dfl_size: length * 8);
2676 for (i = 0; i < length; i++)
2677 {
2678 gchar *value;
2679
2680 value = g_key_file_parse_boolean_as_value (key_file, value: list[i]);
2681
2682 g_string_append (string: value_list, val: value);
2683 g_string_append_c (value_list, key_file->list_separator);
2684
2685 g_free (mem: value);
2686 }
2687
2688 g_key_file_set_value (key_file, group_name, key, value: value_list->str);
2689 g_string_free (string: value_list, TRUE);
2690}
2691
2692/**
2693 * g_key_file_get_integer:
2694 * @key_file: a #GKeyFile
2695 * @group_name: a group name
2696 * @key: a key
2697 * @error: return location for a #GError
2698 *
2699 * Returns the value associated with @key under @group_name as an
2700 * integer.
2701 *
2702 * If @key cannot be found then 0 is returned and @error is set to
2703 * #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if the value associated
2704 * with @key cannot be interpreted as an integer, or is out of range
2705 * for a #gint, then 0 is returned
2706 * and @error is set to #G_KEY_FILE_ERROR_INVALID_VALUE.
2707 *
2708 * Returns: the value associated with the key as an integer, or
2709 * 0 if the key was not found or could not be parsed.
2710 *
2711 * Since: 2.6
2712 **/
2713gint
2714g_key_file_get_integer (GKeyFile *key_file,
2715 const gchar *group_name,
2716 const gchar *key,
2717 GError **error)
2718{
2719 GError *key_file_error;
2720 gchar *value;
2721 gint int_value;
2722
2723 g_return_val_if_fail (key_file != NULL, -1);
2724 g_return_val_if_fail (group_name != NULL, -1);
2725 g_return_val_if_fail (key != NULL, -1);
2726
2727 key_file_error = NULL;
2728
2729 value = g_key_file_get_value (key_file, group_name, key, error: &key_file_error);
2730
2731 if (key_file_error)
2732 {
2733 g_propagate_error (dest: error, src: key_file_error);
2734 return 0;
2735 }
2736
2737 int_value = g_key_file_parse_value_as_integer (key_file, value,
2738 error: &key_file_error);
2739 g_free (mem: value);
2740
2741 if (key_file_error)
2742 {
2743 if (g_error_matches (error: key_file_error,
2744 G_KEY_FILE_ERROR,
2745 code: G_KEY_FILE_ERROR_INVALID_VALUE))
2746 {
2747 g_set_error (err: error, G_KEY_FILE_ERROR,
2748 code: G_KEY_FILE_ERROR_INVALID_VALUE,
2749 _("Key file contains key “%s” in group “%s” "
2750 "which has a value that cannot be interpreted."),
2751 key, group_name);
2752 g_error_free (error: key_file_error);
2753 }
2754 else
2755 g_propagate_error (dest: error, src: key_file_error);
2756 }
2757
2758 return int_value;
2759}
2760
2761/**
2762 * g_key_file_set_integer:
2763 * @key_file: a #GKeyFile
2764 * @group_name: a group name
2765 * @key: a key
2766 * @value: an integer value
2767 *
2768 * Associates a new integer value with @key under @group_name.
2769 * If @key cannot be found then it is created.
2770 *
2771 * Since: 2.6
2772 **/
2773void
2774g_key_file_set_integer (GKeyFile *key_file,
2775 const gchar *group_name,
2776 const gchar *key,
2777 gint value)
2778{
2779 gchar *result;
2780
2781 g_return_if_fail (key_file != NULL);
2782
2783 result = g_key_file_parse_integer_as_value (key_file, value);
2784 g_key_file_set_value (key_file, group_name, key, value: result);
2785 g_free (mem: result);
2786}
2787
2788/**
2789 * g_key_file_get_int64:
2790 * @key_file: a non-%NULL #GKeyFile
2791 * @group_name: a non-%NULL group name
2792 * @key: a non-%NULL key
2793 * @error: return location for a #GError
2794 *
2795 * Returns the value associated with @key under @group_name as a signed
2796 * 64-bit integer. This is similar to g_key_file_get_integer() but can return
2797 * 64-bit results without truncation.
2798 *
2799 * Returns: the value associated with the key as a signed 64-bit integer, or
2800 * 0 if the key was not found or could not be parsed.
2801 *
2802 * Since: 2.26
2803 */
2804gint64
2805g_key_file_get_int64 (GKeyFile *key_file,
2806 const gchar *group_name,
2807 const gchar *key,
2808 GError **error)
2809{
2810 gchar *s, *end;
2811 gint64 v;
2812
2813 g_return_val_if_fail (key_file != NULL, -1);
2814 g_return_val_if_fail (group_name != NULL, -1);
2815 g_return_val_if_fail (key != NULL, -1);
2816
2817 s = g_key_file_get_value (key_file, group_name, key, error);
2818
2819 if (s == NULL)
2820 return 0;
2821
2822 v = g_ascii_strtoll (nptr: s, endptr: &end, base: 10);
2823
2824 if (*s == '\0' || *end != '\0')
2825 {
2826 g_set_error (err: error, G_KEY_FILE_ERROR, code: G_KEY_FILE_ERROR_INVALID_VALUE,
2827 _("Key “%s” in group “%s” has value “%s” "
2828 "where %s was expected"),
2829 key, group_name, s, "int64");
2830 g_free (mem: s);
2831 return 0;
2832 }
2833
2834 g_free (mem: s);
2835 return v;
2836}
2837
2838/**
2839 * g_key_file_set_int64:
2840 * @key_file: a #GKeyFile
2841 * @group_name: a group name
2842 * @key: a key
2843 * @value: an integer value
2844 *
2845 * Associates a new integer value with @key under @group_name.
2846 * If @key cannot be found then it is created.
2847 *
2848 * Since: 2.26
2849 **/
2850void
2851g_key_file_set_int64 (GKeyFile *key_file,
2852 const gchar *group_name,
2853 const gchar *key,
2854 gint64 value)
2855{
2856 gchar *result;
2857
2858 g_return_if_fail (key_file != NULL);
2859
2860 result = g_strdup_printf (format: "%" G_GINT64_FORMAT, value);
2861 g_key_file_set_value (key_file, group_name, key, value: result);
2862 g_free (mem: result);
2863}
2864
2865/**
2866 * g_key_file_get_uint64:
2867 * @key_file: a non-%NULL #GKeyFile
2868 * @group_name: a non-%NULL group name
2869 * @key: a non-%NULL key
2870 * @error: return location for a #GError
2871 *
2872 * Returns the value associated with @key under @group_name as an unsigned
2873 * 64-bit integer. This is similar to g_key_file_get_integer() but can return
2874 * large positive results without truncation.
2875 *
2876 * Returns: the value associated with the key as an unsigned 64-bit integer,
2877 * or 0 if the key was not found or could not be parsed.
2878 *
2879 * Since: 2.26
2880 */
2881guint64
2882g_key_file_get_uint64 (GKeyFile *key_file,
2883 const gchar *group_name,
2884 const gchar *key,
2885 GError **error)
2886{
2887 gchar *s, *end;
2888 guint64 v;
2889
2890 g_return_val_if_fail (key_file != NULL, -1);
2891 g_return_val_if_fail (group_name != NULL, -1);
2892 g_return_val_if_fail (key != NULL, -1);
2893
2894 s = g_key_file_get_value (key_file, group_name, key, error);
2895
2896 if (s == NULL)
2897 return 0;
2898
2899 v = g_ascii_strtoull (nptr: s, endptr: &end, base: 10);
2900
2901 if (*s == '\0' || *end != '\0')
2902 {
2903 g_set_error (err: error, G_KEY_FILE_ERROR, code: G_KEY_FILE_ERROR_INVALID_VALUE,
2904 _("Key “%s” in group “%s” has value “%s” "
2905 "where %s was expected"),
2906 key, group_name, s, "uint64");
2907 g_free (mem: s);
2908 return 0;
2909 }
2910
2911 g_free (mem: s);
2912 return v;
2913}
2914
2915/**
2916 * g_key_file_set_uint64:
2917 * @key_file: a #GKeyFile
2918 * @group_name: a group name
2919 * @key: a key
2920 * @value: an integer value
2921 *
2922 * Associates a new integer value with @key under @group_name.
2923 * If @key cannot be found then it is created.
2924 *
2925 * Since: 2.26
2926 **/
2927void
2928g_key_file_set_uint64 (GKeyFile *key_file,
2929 const gchar *group_name,
2930 const gchar *key,
2931 guint64 value)
2932{
2933 gchar *result;
2934
2935 g_return_if_fail (key_file != NULL);
2936
2937 result = g_strdup_printf (format: "%" G_GUINT64_FORMAT, value);
2938 g_key_file_set_value (key_file, group_name, key, value: result);
2939 g_free (mem: result);
2940}
2941
2942/**
2943 * g_key_file_get_integer_list:
2944 * @key_file: a #GKeyFile
2945 * @group_name: a group name
2946 * @key: a key
2947 * @length: (out): the number of integers returned
2948 * @error: return location for a #GError
2949 *
2950 * Returns the values associated with @key under @group_name as
2951 * integers.
2952 *
2953 * If @key cannot be found then %NULL is returned and @error is set to
2954 * #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if the values associated
2955 * with @key cannot be interpreted as integers, or are out of range for
2956 * #gint, then %NULL is returned
2957 * and @error is set to #G_KEY_FILE_ERROR_INVALID_VALUE.
2958 *
2959 * Returns: (array length=length) (element-type gint) (transfer container):
2960 * the values associated with the key as a list of integers, or %NULL if
2961 * the key was not found or could not be parsed. The returned list of
2962 * integers should be freed with g_free() when no longer needed.
2963 *
2964 * Since: 2.6
2965 **/
2966gint *
2967g_key_file_get_integer_list (GKeyFile *key_file,
2968 const gchar *group_name,
2969 const gchar *key,
2970 gsize *length,
2971 GError **error)
2972{
2973 GError *key_file_error = NULL;
2974 gchar **values;
2975 gint *int_values;
2976 gsize i, num_ints;
2977
2978 g_return_val_if_fail (key_file != NULL, NULL);
2979 g_return_val_if_fail (group_name != NULL, NULL);
2980 g_return_val_if_fail (key != NULL, NULL);
2981
2982 if (length)
2983 *length = 0;
2984
2985 values = g_key_file_get_string_list (key_file, group_name, key,
2986 length: &num_ints, error: &key_file_error);
2987
2988 if (key_file_error)
2989 g_propagate_error (dest: error, src: key_file_error);
2990
2991 if (!values)
2992 return NULL;
2993
2994 int_values = g_new (gint, num_ints);
2995
2996 for (i = 0; i < num_ints; i++)
2997 {
2998 int_values[i] = g_key_file_parse_value_as_integer (key_file,
2999 value: values[i],
3000 error: &key_file_error);
3001
3002 if (key_file_error)
3003 {
3004 g_propagate_error (dest: error, src: key_file_error);
3005 g_strfreev (str_array: values);
3006 g_free (mem: int_values);
3007
3008 return NULL;
3009 }
3010 }
3011 g_strfreev (str_array: values);
3012
3013 if (length)
3014 *length = num_ints;
3015
3016 return int_values;
3017}
3018
3019/**
3020 * g_key_file_set_integer_list:
3021 * @key_file: a #GKeyFile
3022 * @group_name: a group name
3023 * @key: a key
3024 * @list: (array length=length): an array of integer values
3025 * @length: number of integer values in @list
3026 *
3027 * Associates a list of integer values with @key under @group_name.
3028 * If @key cannot be found then it is created.
3029 *
3030 * Since: 2.6
3031 **/
3032void
3033g_key_file_set_integer_list (GKeyFile *key_file,
3034 const gchar *group_name,
3035 const gchar *key,
3036 gint list[],
3037 gsize length)
3038{
3039 GString *values;
3040 gsize i;
3041
3042 g_return_if_fail (key_file != NULL);
3043 g_return_if_fail (list != NULL);
3044
3045 values = g_string_sized_new (dfl_size: length * 16);
3046 for (i = 0; i < length; i++)
3047 {
3048 gchar *value;
3049
3050 value = g_key_file_parse_integer_as_value (key_file, value: list[i]);
3051
3052 g_string_append (string: values, val: value);
3053 g_string_append_c (values, key_file->list_separator);
3054
3055 g_free (mem: value);
3056 }
3057
3058 g_key_file_set_value (key_file, group_name, key, value: values->str);
3059 g_string_free (string: values, TRUE);
3060}
3061
3062/**
3063 * g_key_file_get_double:
3064 * @key_file: a #GKeyFile
3065 * @group_name: a group name
3066 * @key: a key
3067 * @error: return location for a #GError
3068 *
3069 * Returns the value associated with @key under @group_name as a
3070 * double. If @group_name is %NULL, the start_group is used.
3071 *
3072 * If @key cannot be found then 0.0 is returned and @error is set to
3073 * #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if the value associated
3074 * with @key cannot be interpreted as a double then 0.0 is returned
3075 * and @error is set to #G_KEY_FILE_ERROR_INVALID_VALUE.
3076 *
3077 * Returns: the value associated with the key as a double, or
3078 * 0.0 if the key was not found or could not be parsed.
3079 *
3080 * Since: 2.12
3081 **/
3082gdouble
3083g_key_file_get_double (GKeyFile *key_file,
3084 const gchar *group_name,
3085 const gchar *key,
3086 GError **error)
3087{
3088 GError *key_file_error;
3089 gchar *value;
3090 gdouble double_value;
3091
3092 g_return_val_if_fail (key_file != NULL, -1);
3093 g_return_val_if_fail (group_name != NULL, -1);
3094 g_return_val_if_fail (key != NULL, -1);
3095
3096 key_file_error = NULL;
3097
3098 value = g_key_file_get_value (key_file, group_name, key, error: &key_file_error);
3099
3100 if (key_file_error)
3101 {
3102 g_propagate_error (dest: error, src: key_file_error);
3103 return 0;
3104 }
3105
3106 double_value = g_key_file_parse_value_as_double (key_file, value,
3107 error: &key_file_error);
3108 g_free (mem: value);
3109
3110 if (key_file_error)
3111 {
3112 if (g_error_matches (error: key_file_error,
3113 G_KEY_FILE_ERROR,
3114 code: G_KEY_FILE_ERROR_INVALID_VALUE))
3115 {
3116 g_set_error (err: error, G_KEY_FILE_ERROR,
3117 code: G_KEY_FILE_ERROR_INVALID_VALUE,
3118 _("Key file contains key “%s” in group “%s” "
3119 "which has a value that cannot be interpreted."),
3120 key, group_name);
3121 g_error_free (error: key_file_error);
3122 }
3123 else
3124 g_propagate_error (dest: error, src: key_file_error);
3125 }
3126
3127 return double_value;
3128}
3129
3130/**
3131 * g_key_file_set_double:
3132 * @key_file: a #GKeyFile
3133 * @group_name: a group name
3134 * @key: a key
3135 * @value: a double value
3136 *
3137 * Associates a new double value with @key under @group_name.
3138 * If @key cannot be found then it is created.
3139 *
3140 * Since: 2.12
3141 **/
3142void
3143g_key_file_set_double (GKeyFile *key_file,
3144 const gchar *group_name,
3145 const gchar *key,
3146 gdouble value)
3147{
3148 gchar result[G_ASCII_DTOSTR_BUF_SIZE];
3149
3150 g_return_if_fail (key_file != NULL);
3151
3152 g_ascii_dtostr (buffer: result, buf_len: sizeof (result), d: value);
3153 g_key_file_set_value (key_file, group_name, key, value: result);
3154}
3155
3156/**
3157 * g_key_file_get_double_list:
3158 * @key_file: a #GKeyFile
3159 * @group_name: a group name
3160 * @key: a key
3161 * @length: (out): the number of doubles returned
3162 * @error: return location for a #GError
3163 *
3164 * Returns the values associated with @key under @group_name as
3165 * doubles.
3166 *
3167 * If @key cannot be found then %NULL is returned and @error is set to
3168 * #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if the values associated
3169 * with @key cannot be interpreted as doubles then %NULL is returned
3170 * and @error is set to #G_KEY_FILE_ERROR_INVALID_VALUE.
3171 *
3172 * Returns: (array length=length) (element-type gdouble) (transfer container):
3173 * the values associated with the key as a list of doubles, or %NULL if the
3174 * key was not found or could not be parsed. The returned list of doubles
3175 * should be freed with g_free() when no longer needed.
3176 *
3177 * Since: 2.12
3178 **/
3179gdouble *
3180g_key_file_get_double_list (GKeyFile *key_file,
3181 const gchar *group_name,
3182 const gchar *key,
3183 gsize *length,
3184 GError **error)
3185{
3186 GError *key_file_error = NULL;
3187 gchar **values;
3188 gdouble *double_values;
3189 gsize i, num_doubles;
3190
3191 g_return_val_if_fail (key_file != NULL, NULL);
3192 g_return_val_if_fail (group_name != NULL, NULL);
3193 g_return_val_if_fail (key != NULL, NULL);
3194
3195 if (length)
3196 *length = 0;
3197
3198 values = g_key_file_get_string_list (key_file, group_name, key,
3199 length: &num_doubles, error: &key_file_error);
3200
3201 if (key_file_error)
3202 g_propagate_error (dest: error, src: key_file_error);
3203
3204 if (!values)
3205 return NULL;
3206
3207 double_values = g_new (gdouble, num_doubles);
3208
3209 for (i = 0; i < num_doubles; i++)
3210 {
3211 double_values[i] = g_key_file_parse_value_as_double (key_file,
3212 value: values[i],
3213 error: &key_file_error);
3214
3215 if (key_file_error)
3216 {
3217 g_propagate_error (dest: error, src: key_file_error);
3218 g_strfreev (str_array: values);
3219 g_free (mem: double_values);
3220
3221 return NULL;
3222 }
3223 }
3224 g_strfreev (str_array: values);
3225
3226 if (length)
3227 *length = num_doubles;
3228
3229 return double_values;
3230}
3231
3232/**
3233 * g_key_file_set_double_list:
3234 * @key_file: a #GKeyFile
3235 * @group_name: a group name
3236 * @key: a key
3237 * @list: (array length=length): an array of double values
3238 * @length: number of double values in @list
3239 *
3240 * Associates a list of double values with @key under
3241 * @group_name. If @key cannot be found then it is created.
3242 *
3243 * Since: 2.12
3244 **/
3245void
3246g_key_file_set_double_list (GKeyFile *key_file,
3247 const gchar *group_name,
3248 const gchar *key,
3249 gdouble list[],
3250 gsize length)
3251{
3252 GString *values;
3253 gsize i;
3254
3255 g_return_if_fail (key_file != NULL);
3256 g_return_if_fail (list != NULL);
3257
3258 values = g_string_sized_new (dfl_size: length * 16);
3259 for (i = 0; i < length; i++)
3260 {
3261 gchar result[G_ASCII_DTOSTR_BUF_SIZE];
3262
3263 g_ascii_dtostr( buffer: result, buf_len: sizeof (result), d: list[i] );
3264
3265 g_string_append (string: values, val: result);
3266 g_string_append_c (values, key_file->list_separator);
3267 }
3268
3269 g_key_file_set_value (key_file, group_name, key, value: values->str);
3270 g_string_free (string: values, TRUE);
3271}
3272
3273static gboolean
3274g_key_file_set_key_comment (GKeyFile *key_file,
3275 const gchar *group_name,
3276 const gchar *key,
3277 const gchar *comment,
3278 GError **error)
3279{
3280 GKeyFileGroup *group;
3281 GKeyFileKeyValuePair *pair;
3282 GList *key_node, *comment_node, *tmp;
3283
3284 group = g_key_file_lookup_group (key_file, group_name);
3285 if (!group)
3286 {
3287 g_set_error (err: error, G_KEY_FILE_ERROR,
3288 code: G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3289 _("Key file does not have group “%s”"),
3290 group_name ? group_name : "(null)");
3291
3292 return FALSE;
3293 }
3294
3295 /* First find the key the comments are supposed to be
3296 * associated with
3297 */
3298 key_node = g_key_file_lookup_key_value_pair_node (key_file, group, key);
3299
3300 if (key_node == NULL)
3301 {
3302 set_not_found_key_error (group_name: group->name, key, error);
3303 return FALSE;
3304 }
3305
3306 /* Then find all the comments already associated with the
3307 * key and free them
3308 */
3309 tmp = key_node->next;
3310 while (tmp != NULL)
3311 {
3312 pair = (GKeyFileKeyValuePair *) tmp->data;
3313
3314 if (pair->key != NULL)
3315 break;
3316
3317 comment_node = tmp;
3318 tmp = tmp->next;
3319 g_key_file_remove_key_value_pair_node (key_file, group,
3320 pair_node: comment_node);
3321 }
3322
3323 if (comment == NULL)
3324 return TRUE;
3325
3326 /* Now we can add our new comment
3327 */
3328 pair = g_slice_new (GKeyFileKeyValuePair);
3329 pair->key = NULL;
3330 pair->value = g_key_file_parse_comment_as_value (key_file, comment);
3331
3332 key_node = g_list_insert (list: key_node, data: pair, position: 1);
3333 (void) key_node;
3334
3335 return TRUE;
3336}
3337
3338static gboolean
3339g_key_file_set_group_comment (GKeyFile *key_file,
3340 const gchar *group_name,
3341 const gchar *comment,
3342 GError **error)
3343{
3344 GKeyFileGroup *group;
3345
3346 g_return_val_if_fail (g_key_file_is_group_name (group_name), FALSE);
3347
3348 group = g_key_file_lookup_group (key_file, group_name);
3349 if (!group)
3350 {
3351 g_set_error (err: error, G_KEY_FILE_ERROR,
3352 code: G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3353 _("Key file does not have group “%s”"),
3354 group_name ? group_name : "(null)");
3355
3356 return FALSE;
3357 }
3358
3359 /* First remove any existing comment
3360 */
3361 if (group->comment)
3362 {
3363 g_key_file_key_value_pair_free (pair: group->comment);
3364 group->comment = NULL;
3365 }
3366
3367 if (comment == NULL)
3368 return TRUE;
3369
3370 /* Now we can add our new comment
3371 */
3372 group->comment = g_slice_new (GKeyFileKeyValuePair);
3373 group->comment->key = NULL;
3374 group->comment->value = g_key_file_parse_comment_as_value (key_file, comment);
3375
3376 return TRUE;
3377}
3378
3379static gboolean
3380g_key_file_set_top_comment (GKeyFile *key_file,
3381 const gchar *comment,
3382 GError **error)
3383{
3384 GList *group_node;
3385 GKeyFileGroup *group;
3386 GKeyFileKeyValuePair *pair;
3387
3388 /* The last group in the list should be the top (comments only)
3389 * group in the file
3390 */
3391 g_warn_if_fail (key_file->groups != NULL);
3392 group_node = g_list_last (list: key_file->groups);
3393 group = (GKeyFileGroup *) group_node->data;
3394 g_warn_if_fail (group->name == NULL);
3395
3396 /* Note all keys must be comments at the top of
3397 * the file, so we can just free it all.
3398 */
3399 g_list_free_full (list: group->key_value_pairs, free_func: (GDestroyNotify) g_key_file_key_value_pair_free);
3400 group->key_value_pairs = NULL;
3401
3402 if (comment == NULL)
3403 return TRUE;
3404
3405 pair = g_slice_new (GKeyFileKeyValuePair);
3406 pair->key = NULL;
3407 pair->value = g_key_file_parse_comment_as_value (key_file, comment);
3408
3409 group->key_value_pairs =
3410 g_list_prepend (list: group->key_value_pairs, data: pair);
3411
3412 return TRUE;
3413}
3414
3415/**
3416 * g_key_file_set_comment:
3417 * @key_file: a #GKeyFile
3418 * @group_name: (nullable): a group name, or %NULL
3419 * @key: (nullable): a key
3420 * @comment: a comment
3421 * @error: return location for a #GError
3422 *
3423 * Places a comment above @key from @group_name.
3424 *
3425 * If @key is %NULL then @comment will be written above @group_name.
3426 * If both @key and @group_name are %NULL, then @comment will be
3427 * written above the first group in the file.
3428 *
3429 * Note that this function prepends a '#' comment marker to
3430 * each line of @comment.
3431 *
3432 * Returns: %TRUE if the comment was written, %FALSE otherwise
3433 *
3434 * Since: 2.6
3435 **/
3436gboolean
3437g_key_file_set_comment (GKeyFile *key_file,
3438 const gchar *group_name,
3439 const gchar *key,
3440 const gchar *comment,
3441 GError **error)
3442{
3443 g_return_val_if_fail (key_file != NULL, FALSE);
3444
3445 if (group_name != NULL && key != NULL)
3446 {
3447 if (!g_key_file_set_key_comment (key_file, group_name, key, comment, error))
3448 return FALSE;
3449 }
3450 else if (group_name != NULL)
3451 {
3452 if (!g_key_file_set_group_comment (key_file, group_name, comment, error))
3453 return FALSE;
3454 }
3455 else
3456 {
3457 if (!g_key_file_set_top_comment (key_file, comment, error))
3458 return FALSE;
3459 }
3460
3461 return TRUE;
3462}
3463
3464static gchar *
3465g_key_file_get_key_comment (GKeyFile *key_file,
3466 const gchar *group_name,
3467 const gchar *key,
3468 GError **error)
3469{
3470 GKeyFileGroup *group;
3471 GKeyFileKeyValuePair *pair;
3472 GList *key_node, *tmp;
3473 GString *string;
3474 gchar *comment;
3475
3476 g_return_val_if_fail (g_key_file_is_group_name (group_name), NULL);
3477
3478 group = g_key_file_lookup_group (key_file, group_name);
3479 if (!group)
3480 {
3481 g_set_error (err: error, G_KEY_FILE_ERROR,
3482 code: G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3483 _("Key file does not have group “%s”"),
3484 group_name ? group_name : "(null)");
3485
3486 return NULL;
3487 }
3488
3489 /* First find the key the comments are supposed to be
3490 * associated with
3491 */
3492 key_node = g_key_file_lookup_key_value_pair_node (key_file, group, key);
3493
3494 if (key_node == NULL)
3495 {
3496 set_not_found_key_error (group_name: group->name, key, error);
3497 return NULL;
3498 }
3499
3500 string = NULL;
3501
3502 /* Then find all the comments already associated with the
3503 * key and concatenate them.
3504 */
3505 tmp = key_node->next;
3506 if (!key_node->next)
3507 return NULL;
3508
3509 pair = (GKeyFileKeyValuePair *) tmp->data;
3510 if (pair->key != NULL)
3511 return NULL;
3512
3513 while (tmp->next)
3514 {
3515 pair = (GKeyFileKeyValuePair *) tmp->next->data;
3516
3517 if (pair->key != NULL)
3518 break;
3519
3520 tmp = tmp->next;
3521 }
3522
3523 while (tmp != key_node)
3524 {
3525 pair = (GKeyFileKeyValuePair *) tmp->data;
3526
3527 if (string == NULL)
3528 string = g_string_sized_new (dfl_size: 512);
3529
3530 comment = g_key_file_parse_value_as_comment (key_file, value: pair->value,
3531 is_final_line: (tmp->prev == key_node));
3532 g_string_append (string, val: comment);
3533 g_free (mem: comment);
3534
3535 tmp = tmp->prev;
3536 }
3537
3538 if (string != NULL)
3539 {
3540 comment = string->str;
3541 g_string_free (string, FALSE);
3542 }
3543 else
3544 comment = NULL;
3545
3546 return comment;
3547}
3548
3549static gchar *
3550get_group_comment (GKeyFile *key_file,
3551 GKeyFileGroup *group,
3552 GError **error)
3553{
3554 GString *string;
3555 GList *tmp;
3556 gchar *comment;
3557
3558 string = NULL;
3559
3560 tmp = group->key_value_pairs;
3561 while (tmp)
3562 {
3563 GKeyFileKeyValuePair *pair;
3564
3565 pair = (GKeyFileKeyValuePair *) tmp->data;
3566
3567 if (pair->key != NULL)
3568 {
3569 tmp = tmp->prev;
3570 break;
3571 }
3572
3573 if (tmp->next == NULL)
3574 break;
3575
3576 tmp = tmp->next;
3577 }
3578
3579 while (tmp != NULL)
3580 {
3581 GKeyFileKeyValuePair *pair;
3582
3583 pair = (GKeyFileKeyValuePair *) tmp->data;
3584
3585 if (string == NULL)
3586 string = g_string_sized_new (dfl_size: 512);
3587
3588 comment = g_key_file_parse_value_as_comment (key_file, value: pair->value,
3589 is_final_line: (tmp->prev == NULL));
3590 g_string_append (string, val: comment);
3591 g_free (mem: comment);
3592
3593 tmp = tmp->prev;
3594 }
3595
3596 if (string != NULL)
3597 return g_string_free (string, FALSE);
3598
3599 return NULL;
3600}
3601
3602static gchar *
3603g_key_file_get_group_comment (GKeyFile *key_file,
3604 const gchar *group_name,
3605 GError **error)
3606{
3607 GList *group_node;
3608 GKeyFileGroup *group;
3609
3610 group = g_key_file_lookup_group (key_file, group_name);
3611 if (!group)
3612 {
3613 g_set_error (err: error, G_KEY_FILE_ERROR,
3614 code: G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3615 _("Key file does not have group “%s”"),
3616 group_name ? group_name : "(null)");
3617
3618 return NULL;
3619 }
3620
3621 if (group->comment)
3622 return g_strdup (str: group->comment->value);
3623
3624 group_node = g_key_file_lookup_group_node (key_file, group_name);
3625 group_node = group_node->next;
3626 group = (GKeyFileGroup *)group_node->data;
3627 return get_group_comment (key_file, group, error);
3628}
3629
3630static gchar *
3631g_key_file_get_top_comment (GKeyFile *key_file,
3632 GError **error)
3633{
3634 GList *group_node;
3635 GKeyFileGroup *group;
3636
3637 /* The last group in the list should be the top (comments only)
3638 * group in the file
3639 */
3640 g_warn_if_fail (key_file->groups != NULL);
3641 group_node = g_list_last (list: key_file->groups);
3642 group = (GKeyFileGroup *) group_node->data;
3643 g_warn_if_fail (group->name == NULL);
3644
3645 return get_group_comment (key_file, group, error);
3646}
3647
3648/**
3649 * g_key_file_get_comment:
3650 * @key_file: a #GKeyFile
3651 * @group_name: (nullable): a group name, or %NULL
3652 * @key: (nullable): a key
3653 * @error: return location for a #GError
3654 *
3655 * Retrieves a comment above @key from @group_name.
3656 * If @key is %NULL then @comment will be read from above
3657 * @group_name. If both @key and @group_name are %NULL, then
3658 * @comment will be read from above the first group in the file.
3659 *
3660 * Note that the returned string does not include the '#' comment markers,
3661 * but does include any whitespace after them (on each line). It includes
3662 * the line breaks between lines, but does not include the final line break.
3663 *
3664 * Returns: a comment that should be freed with g_free()
3665 *
3666 * Since: 2.6
3667 **/
3668gchar *
3669g_key_file_get_comment (GKeyFile *key_file,
3670 const gchar *group_name,
3671 const gchar *key,
3672 GError **error)
3673{
3674 g_return_val_if_fail (key_file != NULL, NULL);
3675
3676 if (group_name != NULL && key != NULL)
3677 return g_key_file_get_key_comment (key_file, group_name, key, error);
3678 else if (group_name != NULL)
3679 return g_key_file_get_group_comment (key_file, group_name, error);
3680 else
3681 return g_key_file_get_top_comment (key_file, error);
3682}
3683
3684/**
3685 * g_key_file_remove_comment:
3686 * @key_file: a #GKeyFile
3687 * @group_name: (nullable): a group name, or %NULL
3688 * @key: (nullable): a key
3689 * @error: return location for a #GError
3690 *
3691 * Removes a comment above @key from @group_name.
3692 * If @key is %NULL then @comment will be removed above @group_name.
3693 * If both @key and @group_name are %NULL, then @comment will
3694 * be removed above the first group in the file.
3695 *
3696 * Returns: %TRUE if the comment was removed, %FALSE otherwise
3697 *
3698 * Since: 2.6
3699 **/
3700
3701gboolean
3702g_key_file_remove_comment (GKeyFile *key_file,
3703 const gchar *group_name,
3704 const gchar *key,
3705 GError **error)
3706{
3707 g_return_val_if_fail (key_file != NULL, FALSE);
3708
3709 if (group_name != NULL && key != NULL)
3710 return g_key_file_set_key_comment (key_file, group_name, key, NULL, error);
3711 else if (group_name != NULL)
3712 return g_key_file_set_group_comment (key_file, group_name, NULL, error);
3713 else
3714 return g_key_file_set_top_comment (key_file, NULL, error);
3715}
3716
3717/**
3718 * g_key_file_has_group:
3719 * @key_file: a #GKeyFile
3720 * @group_name: a group name
3721 *
3722 * Looks whether the key file has the group @group_name.
3723 *
3724 * Returns: %TRUE if @group_name is a part of @key_file, %FALSE
3725 * otherwise.
3726 * Since: 2.6
3727 **/
3728gboolean
3729g_key_file_has_group (GKeyFile *key_file,
3730 const gchar *group_name)
3731{
3732 g_return_val_if_fail (key_file != NULL, FALSE);
3733 g_return_val_if_fail (group_name != NULL, FALSE);
3734
3735 return g_key_file_lookup_group (key_file, group_name) != NULL;
3736}
3737
3738/* This code remains from a historical attempt to add a new public API
3739 * which respects the GError rules.
3740 */
3741static gboolean
3742g_key_file_has_key_full (GKeyFile *key_file,
3743 const gchar *group_name,
3744 const gchar *key,
3745 gboolean *has_key,
3746 GError **error)
3747{
3748 GKeyFileKeyValuePair *pair;
3749 GKeyFileGroup *group;
3750
3751 g_return_val_if_fail (key_file != NULL, FALSE);
3752 g_return_val_if_fail (group_name != NULL, FALSE);
3753 g_return_val_if_fail (key != NULL, FALSE);
3754
3755 group = g_key_file_lookup_group (key_file, group_name);
3756
3757 if (!group)
3758 {
3759 g_set_error (err: error, G_KEY_FILE_ERROR,
3760 code: G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3761 _("Key file does not have group “%s”"),
3762 group_name);
3763
3764 return FALSE;
3765 }
3766
3767 pair = g_key_file_lookup_key_value_pair (key_file, group, key);
3768
3769 if (has_key)
3770 *has_key = pair != NULL;
3771 return TRUE;
3772}
3773
3774/**
3775 * g_key_file_has_key: (skip)
3776 * @key_file: a #GKeyFile
3777 * @group_name: a group name
3778 * @key: a key name
3779 * @error: return location for a #GError
3780 *
3781 * Looks whether the key file has the key @key in the group
3782 * @group_name.
3783 *
3784 * Note that this function does not follow the rules for #GError strictly;
3785 * the return value both carries meaning and signals an error. To use
3786 * this function, you must pass a #GError pointer in @error, and check
3787 * whether it is not %NULL to see if an error occurred.
3788 *
3789 * Language bindings should use g_key_file_get_value() to test whether
3790 * or not a key exists.
3791 *
3792 * Returns: %TRUE if @key is a part of @group_name, %FALSE otherwise
3793 *
3794 * Since: 2.6
3795 **/
3796gboolean
3797g_key_file_has_key (GKeyFile *key_file,
3798 const gchar *group_name,
3799 const gchar *key,
3800 GError **error)
3801{
3802 GError *temp_error = NULL;
3803 gboolean has_key;
3804
3805 if (g_key_file_has_key_full (key_file, group_name, key, has_key: &has_key, error: &temp_error))
3806 {
3807 return has_key;
3808 }
3809 else
3810 {
3811 g_propagate_error (dest: error, src: temp_error);
3812 return FALSE;
3813 }
3814}
3815
3816static void
3817g_key_file_add_group (GKeyFile *key_file,
3818 const gchar *group_name)
3819{
3820 GKeyFileGroup *group;
3821
3822 g_return_if_fail (key_file != NULL);
3823 g_return_if_fail (g_key_file_is_group_name (group_name));
3824
3825 group = g_key_file_lookup_group (key_file, group_name);
3826 if (group != NULL)
3827 {
3828 key_file->current_group = group;
3829 return;
3830 }
3831
3832 group = g_slice_new0 (GKeyFileGroup);
3833 group->name = g_strdup (str: group_name);
3834 group->lookup_map = g_hash_table_new (hash_func: g_str_hash, key_equal_func: g_str_equal);
3835 key_file->groups = g_list_prepend (list: key_file->groups, data: group);
3836 key_file->current_group = group;
3837
3838 if (key_file->start_group == NULL)
3839 key_file->start_group = group;
3840
3841 if (!key_file->group_hash)
3842 key_file->group_hash = g_hash_table_new (hash_func: g_str_hash, key_equal_func: g_str_equal);
3843
3844 g_hash_table_insert (hash_table: key_file->group_hash, key: (gpointer)group->name, value: group);
3845}
3846
3847static void
3848g_key_file_key_value_pair_free (GKeyFileKeyValuePair *pair)
3849{
3850 if (pair != NULL)
3851 {
3852 g_free (mem: pair->key);
3853 g_free (mem: pair->value);
3854 g_slice_free (GKeyFileKeyValuePair, pair);
3855 }
3856}
3857
3858/* Be careful not to call this function on a node with data in the
3859 * lookup map without removing it from the lookup map, first.
3860 *
3861 * Some current cases where this warning is not a concern are
3862 * when:
3863 * - the node being removed is a comment node
3864 * - the entire lookup map is getting destroyed soon after
3865 * anyway.
3866 */
3867static void
3868g_key_file_remove_key_value_pair_node (GKeyFile *key_file,
3869 GKeyFileGroup *group,
3870 GList *pair_node)
3871{
3872
3873 GKeyFileKeyValuePair *pair;
3874
3875 pair = (GKeyFileKeyValuePair *) pair_node->data;
3876
3877 group->key_value_pairs = g_list_remove_link (list: group->key_value_pairs, llink: pair_node);
3878
3879 g_warn_if_fail (pair->value != NULL);
3880
3881 g_key_file_key_value_pair_free (pair);
3882
3883 g_list_free_1 (list: pair_node);
3884}
3885
3886static void
3887g_key_file_remove_group_node (GKeyFile *key_file,
3888 GList *group_node)
3889{
3890 GKeyFileGroup *group;
3891 GList *tmp;
3892
3893 group = (GKeyFileGroup *) group_node->data;
3894
3895 if (group->name)
3896 {
3897 g_assert (key_file->group_hash);
3898 g_hash_table_remove (hash_table: key_file->group_hash, key: group->name);
3899 }
3900
3901 /* If the current group gets deleted make the current group the last
3902 * added group.
3903 */
3904 if (key_file->current_group == group)
3905 {
3906 /* groups should always contain at least the top comment group,
3907 * unless g_key_file_clear has been called
3908 */
3909 if (key_file->groups)
3910 key_file->current_group = (GKeyFileGroup *) key_file->groups->data;
3911 else
3912 key_file->current_group = NULL;
3913 }
3914
3915 /* If the start group gets deleted make the start group the first
3916 * added group.
3917 */
3918 if (key_file->start_group == group)
3919 {
3920 tmp = g_list_last (list: key_file->groups);
3921 while (tmp != NULL)
3922 {
3923 if (tmp != group_node &&
3924 ((GKeyFileGroup *) tmp->data)->name != NULL)
3925 break;
3926
3927 tmp = tmp->prev;
3928 }
3929
3930 if (tmp)
3931 key_file->start_group = (GKeyFileGroup *) tmp->data;
3932 else
3933 key_file->start_group = NULL;
3934 }
3935
3936 key_file->groups = g_list_remove_link (list: key_file->groups, llink: group_node);
3937
3938 tmp = group->key_value_pairs;
3939 while (tmp != NULL)
3940 {
3941 GList *pair_node;
3942
3943 pair_node = tmp;
3944 tmp = tmp->next;
3945 g_key_file_remove_key_value_pair_node (key_file, group, pair_node);
3946 }
3947
3948 g_warn_if_fail (group->key_value_pairs == NULL);
3949
3950 if (group->comment)
3951 {
3952 g_key_file_key_value_pair_free (pair: group->comment);
3953 group->comment = NULL;
3954 }
3955
3956 if (group->lookup_map)
3957 {
3958 g_hash_table_destroy (hash_table: group->lookup_map);
3959 group->lookup_map = NULL;
3960 }
3961
3962 g_free (mem: (gchar *) group->name);
3963 g_slice_free (GKeyFileGroup, group);
3964 g_list_free_1 (list: group_node);
3965}
3966
3967/**
3968 * g_key_file_remove_group:
3969 * @key_file: a #GKeyFile
3970 * @group_name: a group name
3971 * @error: return location for a #GError or %NULL
3972 *
3973 * Removes the specified group, @group_name,
3974 * from the key file.
3975 *
3976 * Returns: %TRUE if the group was removed, %FALSE otherwise
3977 *
3978 * Since: 2.6
3979 **/
3980gboolean
3981g_key_file_remove_group (GKeyFile *key_file,
3982 const gchar *group_name,
3983 GError **error)
3984{
3985 GList *group_node;
3986
3987 g_return_val_if_fail (key_file != NULL, FALSE);
3988 g_return_val_if_fail (group_name != NULL, FALSE);
3989
3990 group_node = g_key_file_lookup_group_node (key_file, group_name);
3991
3992 if (!group_node)
3993 {
3994 g_set_error (err: error, G_KEY_FILE_ERROR,
3995 code: G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3996 _("Key file does not have group “%s”"),
3997 group_name);
3998 return FALSE;
3999 }
4000
4001 g_key_file_remove_group_node (key_file, group_node);
4002
4003 return TRUE;
4004}
4005
4006static void
4007g_key_file_add_key_value_pair (GKeyFile *key_file,
4008 GKeyFileGroup *group,
4009 GKeyFileKeyValuePair *pair)
4010{
4011 g_hash_table_replace (hash_table: group->lookup_map, key: pair->key, value: pair);
4012 group->key_value_pairs = g_list_prepend (list: group->key_value_pairs, data: pair);
4013}
4014
4015static void
4016g_key_file_add_key (GKeyFile *key_file,
4017 GKeyFileGroup *group,
4018 const gchar *key,
4019 const gchar *value)
4020{
4021 GKeyFileKeyValuePair *pair;
4022
4023 pair = g_slice_new (GKeyFileKeyValuePair);
4024 pair->key = g_strdup (str: key);
4025 pair->value = g_strdup (str: value);
4026
4027 g_key_file_add_key_value_pair (key_file, group, pair);
4028}
4029
4030/**
4031 * g_key_file_remove_key:
4032 * @key_file: a #GKeyFile
4033 * @group_name: a group name
4034 * @key: a key name to remove
4035 * @error: return location for a #GError or %NULL
4036 *
4037 * Removes @key in @group_name from the key file.
4038 *
4039 * Returns: %TRUE if the key was removed, %FALSE otherwise
4040 *
4041 * Since: 2.6
4042 **/
4043gboolean
4044g_key_file_remove_key (GKeyFile *key_file,
4045 const gchar *group_name,
4046 const gchar *key,
4047 GError **error)
4048{
4049 GKeyFileGroup *group;
4050 GKeyFileKeyValuePair *pair;
4051
4052 g_return_val_if_fail (key_file != NULL, FALSE);
4053 g_return_val_if_fail (group_name != NULL, FALSE);
4054 g_return_val_if_fail (key != NULL, FALSE);
4055
4056 pair = NULL;
4057
4058 group = g_key_file_lookup_group (key_file, group_name);
4059 if (!group)
4060 {
4061 g_set_error (err: error, G_KEY_FILE_ERROR,
4062 code: G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
4063 _("Key file does not have group “%s”"),
4064 group_name);
4065 return FALSE;
4066 }
4067
4068 pair = g_key_file_lookup_key_value_pair (key_file, group, key);
4069
4070 if (!pair)
4071 {
4072 set_not_found_key_error (group_name: group->name, key, error);
4073 return FALSE;
4074 }
4075
4076 group->key_value_pairs = g_list_remove (list: group->key_value_pairs, data: pair);
4077 g_hash_table_remove (hash_table: group->lookup_map, key: pair->key);
4078 g_key_file_key_value_pair_free (pair);
4079
4080 return TRUE;
4081}
4082
4083static GList *
4084g_key_file_lookup_group_node (GKeyFile *key_file,
4085 const gchar *group_name)
4086{
4087 GKeyFileGroup *group;
4088 GList *tmp;
4089
4090 for (tmp = key_file->groups; tmp != NULL; tmp = tmp->next)
4091 {
4092 group = (GKeyFileGroup *) tmp->data;
4093
4094 if (group && group->name && strcmp (s1: group->name, s2: group_name) == 0)
4095 break;
4096 }
4097
4098 return tmp;
4099}
4100
4101static GKeyFileGroup *
4102g_key_file_lookup_group (GKeyFile *key_file,
4103 const gchar *group_name)
4104{
4105 if (!key_file->group_hash)
4106 return NULL;
4107
4108 return (GKeyFileGroup *)g_hash_table_lookup (hash_table: key_file->group_hash, key: group_name);
4109}
4110
4111static GList *
4112g_key_file_lookup_key_value_pair_node (GKeyFile *key_file,
4113 GKeyFileGroup *group,
4114 const gchar *key)
4115{
4116 GList *key_node;
4117
4118 for (key_node = group->key_value_pairs;
4119 key_node != NULL;
4120 key_node = key_node->next)
4121 {
4122 GKeyFileKeyValuePair *pair;
4123
4124 pair = (GKeyFileKeyValuePair *) key_node->data;
4125
4126 if (pair->key && strcmp (s1: pair->key, s2: key) == 0)
4127 break;
4128 }
4129
4130 return key_node;
4131}
4132
4133static GKeyFileKeyValuePair *
4134g_key_file_lookup_key_value_pair (GKeyFile *key_file,
4135 GKeyFileGroup *group,
4136 const gchar *key)
4137{
4138 return (GKeyFileKeyValuePair *) g_hash_table_lookup (hash_table: group->lookup_map, key);
4139}
4140
4141/* Lines starting with # or consisting entirely of whitespace are merely
4142 * recorded, not parsed. This function assumes all leading whitespace
4143 * has been stripped.
4144 */
4145static gboolean
4146g_key_file_line_is_comment (const gchar *line)
4147{
4148 return (*line == '#' || *line == '\0' || *line == '\n');
4149}
4150
4151static gboolean
4152g_key_file_is_group_name (const gchar *name)
4153{
4154 gchar *p, *q;
4155
4156 if (name == NULL)
4157 return FALSE;
4158
4159 p = q = (gchar *) name;
4160 while (*q && *q != ']' && *q != '[' && !g_ascii_iscntrl (*q))
4161 q = g_utf8_find_next_char (p: q, NULL);
4162
4163 if (*q != '\0' || q == p)
4164 return FALSE;
4165
4166 return TRUE;
4167}
4168
4169static gboolean
4170g_key_file_is_key_name (const gchar *name)
4171{
4172 gchar *p, *q;
4173
4174 if (name == NULL)
4175 return FALSE;
4176
4177 p = q = (gchar *) name;
4178 /* We accept a little more than the desktop entry spec says,
4179 * since gnome-vfs uses mime-types as keys in its cache.
4180 */
4181 while (*q && *q != '=' && *q != '[' && *q != ']')
4182 q = g_utf8_find_next_char (p: q, NULL);
4183
4184 /* No empty keys, please */
4185 if (q == p)
4186 return FALSE;
4187
4188 /* We accept spaces in the middle of keys to not break
4189 * existing apps, but we don't tolerate initial or final
4190 * spaces, which would lead to silent corruption when
4191 * rereading the file.
4192 */
4193 if (*p == ' ' || q[-1] == ' ')
4194 return FALSE;
4195
4196 if (*q == '[')
4197 {
4198 q++;
4199 while (*q && (g_unichar_isalnum (c: g_utf8_get_char_validated (p: q, max_len: -1)) || *q == '-' || *q == '_' || *q == '.' || *q == '@'))
4200 q = g_utf8_find_next_char (p: q, NULL);
4201
4202 if (*q != ']')
4203 return FALSE;
4204
4205 q++;
4206 }
4207
4208 if (*q != '\0')
4209 return FALSE;
4210
4211 return TRUE;
4212}
4213
4214/* A group in a key file is made up of a starting '[' followed by one
4215 * or more letters making up the group name followed by ']'.
4216 */
4217static gboolean
4218g_key_file_line_is_group (const gchar *line)
4219{
4220 gchar *p;
4221
4222 p = (gchar *) line;
4223 if (*p != '[')
4224 return FALSE;
4225
4226 p++;
4227
4228 while (*p && *p != ']')
4229 p = g_utf8_find_next_char (p, NULL);
4230
4231 if (*p != ']')
4232 return FALSE;
4233
4234 /* silently accept whitespace after the ] */
4235 p = g_utf8_find_next_char (p, NULL);
4236 while (*p == ' ' || *p == '\t')
4237 p = g_utf8_find_next_char (p, NULL);
4238
4239 if (*p)
4240 return FALSE;
4241
4242 return TRUE;
4243}
4244
4245static gboolean
4246g_key_file_line_is_key_value_pair (const gchar *line)
4247{
4248 gchar *p;
4249
4250 p = (gchar *) g_utf8_strchr (p: line, len: -1, c: '=');
4251
4252 if (!p)
4253 return FALSE;
4254
4255 /* Key must be non-empty
4256 */
4257 if (*p == line[0])
4258 return FALSE;
4259
4260 return TRUE;
4261}
4262
4263static gchar *
4264g_key_file_parse_value_as_string (GKeyFile *key_file,
4265 const gchar *value,
4266 GSList **pieces,
4267 GError **error)
4268{
4269 gchar *string_value, *p, *q0, *q;
4270
4271 string_value = g_new (gchar, strlen (value) + 1);
4272
4273 p = (gchar *) value;
4274 q0 = q = string_value;
4275 while (*p)
4276 {
4277 if (*p == '\\')
4278 {
4279 p++;
4280
4281 switch (*p)
4282 {
4283 case 's':
4284 *q = ' ';
4285 break;
4286
4287 case 'n':
4288 *q = '\n';
4289 break;
4290
4291 case 't':
4292 *q = '\t';
4293 break;
4294
4295 case 'r':
4296 *q = '\r';
4297 break;
4298
4299 case '\\':
4300 *q = '\\';
4301 break;
4302
4303 case '\0':
4304 g_set_error_literal (err: error, G_KEY_FILE_ERROR,
4305 code: G_KEY_FILE_ERROR_INVALID_VALUE,
4306 _("Key file contains escape character "
4307 "at end of line"));
4308 break;
4309
4310 default:
4311 if (pieces && *p == key_file->list_separator)
4312 *q = key_file->list_separator;
4313 else
4314 {
4315 *q++ = '\\';
4316 *q = *p;
4317
4318 if (*error == NULL)
4319 {
4320 gchar sequence[3];
4321
4322 sequence[0] = '\\';
4323 sequence[1] = *p;
4324 sequence[2] = '\0';
4325
4326 g_set_error (err: error, G_KEY_FILE_ERROR,
4327 code: G_KEY_FILE_ERROR_INVALID_VALUE,
4328 _("Key file contains invalid escape "
4329 "sequence “%s”"), sequence);
4330 }
4331 }
4332 break;
4333 }
4334 }
4335 else
4336 {
4337 *q = *p;
4338 if (pieces && (*p == key_file->list_separator))
4339 {
4340 *pieces = g_slist_prepend (list: *pieces, data: g_strndup (str: q0, n: q - q0));
4341 q0 = q + 1;
4342 }
4343 }
4344
4345 if (*p == '\0')
4346 break;
4347
4348 q++;
4349 p++;
4350 }
4351
4352 *q = '\0';
4353 if (pieces)
4354 {
4355 if (q0 < q)
4356 *pieces = g_slist_prepend (list: *pieces, data: g_strndup (str: q0, n: q - q0));
4357 *pieces = g_slist_reverse (list: *pieces);
4358 }
4359
4360 return string_value;
4361}
4362
4363static gchar *
4364g_key_file_parse_string_as_value (GKeyFile *key_file,
4365 const gchar *string,
4366 gboolean escape_separator)
4367{
4368 gchar *value, *p, *q;
4369 gsize length;
4370 gboolean parsing_leading_space;
4371
4372 length = strlen (s: string) + 1;
4373
4374 /* Worst case would be that every character needs to be escaped.
4375 * In other words every character turns to two characters
4376 */
4377 value = g_new (gchar, 2 * length);
4378
4379 p = (gchar *) string;
4380 q = value;
4381 parsing_leading_space = TRUE;
4382 while (p < (string + length - 1))
4383 {
4384 gchar escaped_character[3] = { '\\', 0, 0 };
4385
4386 switch (*p)
4387 {
4388 case ' ':
4389 if (parsing_leading_space)
4390 {
4391 escaped_character[1] = 's';
4392 strcpy (dest: q, src: escaped_character);
4393 q += 2;
4394 }
4395 else
4396 {
4397 *q = *p;
4398 q++;
4399 }
4400 break;
4401 case '\t':
4402 if (parsing_leading_space)
4403 {
4404 escaped_character[1] = 't';
4405 strcpy (dest: q, src: escaped_character);
4406 q += 2;
4407 }
4408 else
4409 {
4410 *q = *p;
4411 q++;
4412 }
4413 break;
4414 case '\n':
4415 escaped_character[1] = 'n';
4416 strcpy (dest: q, src: escaped_character);
4417 q += 2;
4418 break;
4419 case '\r':
4420 escaped_character[1] = 'r';
4421 strcpy (dest: q, src: escaped_character);
4422 q += 2;
4423 break;
4424 case '\\':
4425 escaped_character[1] = '\\';
4426 strcpy (dest: q, src: escaped_character);
4427 q += 2;
4428 parsing_leading_space = FALSE;
4429 break;
4430 default:
4431 if (escape_separator && *p == key_file->list_separator)
4432 {
4433 escaped_character[1] = key_file->list_separator;
4434 strcpy (dest: q, src: escaped_character);
4435 q += 2;
4436 parsing_leading_space = TRUE;
4437 }
4438 else
4439 {
4440 *q = *p;
4441 q++;
4442 parsing_leading_space = FALSE;
4443 }
4444 break;
4445 }
4446 p++;
4447 }
4448 *q = '\0';
4449
4450 return value;
4451}
4452
4453static gint
4454g_key_file_parse_value_as_integer (GKeyFile *key_file,
4455 const gchar *value,
4456 GError **error)
4457{
4458 gchar *eof_int;
4459 glong long_value;
4460 gint int_value;
4461 int errsv;
4462
4463 errno = 0;
4464 long_value = strtol (nptr: value, endptr: &eof_int, base: 10);
4465 errsv = errno;
4466
4467 if (*value == '\0' || (*eof_int != '\0' && !g_ascii_isspace(*eof_int)))
4468 {
4469 gchar *value_utf8 = g_utf8_make_valid (str: value, len: -1);
4470 g_set_error (err: error, G_KEY_FILE_ERROR,
4471 code: G_KEY_FILE_ERROR_INVALID_VALUE,
4472 _("Value “%s” cannot be interpreted "
4473 "as a number."), value_utf8);
4474 g_free (mem: value_utf8);
4475
4476 return 0;
4477 }
4478
4479 int_value = long_value;
4480 if (int_value != long_value || errsv == ERANGE)
4481 {
4482 gchar *value_utf8 = g_utf8_make_valid (str: value, len: -1);
4483 g_set_error (err: error,
4484 G_KEY_FILE_ERROR,
4485 code: G_KEY_FILE_ERROR_INVALID_VALUE,
4486 _("Integer value “%s” out of range"),
4487 value_utf8);
4488 g_free (mem: value_utf8);
4489
4490 return 0;
4491 }
4492
4493 return int_value;
4494}
4495
4496static gchar *
4497g_key_file_parse_integer_as_value (GKeyFile *key_file,
4498 gint value)
4499
4500{
4501 return g_strdup_printf (format: "%d", value);
4502}
4503
4504static gdouble
4505g_key_file_parse_value_as_double (GKeyFile *key_file,
4506 const gchar *value,
4507 GError **error)
4508{
4509 gchar *end_of_valid_d;
4510 gdouble double_value = 0;
4511
4512 double_value = g_ascii_strtod (nptr: value, endptr: &end_of_valid_d);
4513
4514 if (*end_of_valid_d != '\0' || end_of_valid_d == value)
4515 {
4516 gchar *value_utf8 = g_utf8_make_valid (str: value, len: -1);
4517 g_set_error (err: error, G_KEY_FILE_ERROR,
4518 code: G_KEY_FILE_ERROR_INVALID_VALUE,
4519 _("Value “%s” cannot be interpreted "
4520 "as a float number."),
4521 value_utf8);
4522 g_free (mem: value_utf8);
4523
4524 double_value = 0;
4525 }
4526
4527 return double_value;
4528}
4529
4530static gint
4531strcmp_sized (const gchar *s1, size_t len1, const gchar *s2)
4532{
4533 size_t len2 = strlen (s: s2);
4534 return strncmp (s1: s1, s2: s2, MAX (len1, len2));
4535}
4536
4537static gboolean
4538g_key_file_parse_value_as_boolean (GKeyFile *key_file,
4539 const gchar *value,
4540 GError **error)
4541{
4542 gchar *value_utf8;
4543 gint i, length = 0;
4544
4545 /* Count the number of non-whitespace characters */
4546 for (i = 0; value[i]; i++)
4547 if (!g_ascii_isspace (value[i]))
4548 length = i + 1;
4549
4550 if (strcmp_sized (s1: value, len1: length, s2: "true") == 0 || strcmp_sized (s1: value, len1: length, s2: "1") == 0)
4551 return TRUE;
4552 else if (strcmp_sized (s1: value, len1: length, s2: "false") == 0 || strcmp_sized (s1: value, len1: length, s2: "0") == 0)
4553 return FALSE;
4554
4555 value_utf8 = g_utf8_make_valid (str: value, len: -1);
4556 g_set_error (err: error, G_KEY_FILE_ERROR,
4557 code: G_KEY_FILE_ERROR_INVALID_VALUE,
4558 _("Value “%s” cannot be interpreted "
4559 "as a boolean."), value_utf8);
4560 g_free (mem: value_utf8);
4561
4562 return FALSE;
4563}
4564
4565static gchar *
4566g_key_file_parse_boolean_as_value (GKeyFile *key_file,
4567 gboolean value)
4568{
4569 if (value)
4570 return g_strdup (str: "true");
4571 else
4572 return g_strdup (str: "false");
4573}
4574
4575static gchar *
4576g_key_file_parse_value_as_comment (GKeyFile *key_file,
4577 const gchar *value,
4578 gboolean is_final_line)
4579{
4580 GString *string;
4581 gchar **lines;
4582 gsize i;
4583
4584 string = g_string_sized_new (dfl_size: 512);
4585
4586 lines = g_strsplit (string: value, delimiter: "\n", max_tokens: 0);
4587
4588 for (i = 0; lines[i] != NULL; i++)
4589 {
4590 const gchar *line = lines[i];
4591
4592 if (i != 0)
4593 g_string_append_c (string, '\n');
4594
4595 if (line[0] == '#')
4596 line++;
4597 g_string_append (string, val: line);
4598 }
4599 g_strfreev (str_array: lines);
4600
4601 /* This function gets called once per line of a comment, but we don’t want
4602 * to add a trailing newline. */
4603 if (!is_final_line)
4604 g_string_append_c (string, '\n');
4605
4606 return g_string_free (string, FALSE);
4607}
4608
4609static gchar *
4610g_key_file_parse_comment_as_value (GKeyFile *key_file,
4611 const gchar *comment)
4612{
4613 GString *string;
4614 gchar **lines;
4615 gsize i;
4616
4617 string = g_string_sized_new (dfl_size: 512);
4618
4619 lines = g_strsplit (string: comment, delimiter: "\n", max_tokens: 0);
4620
4621 for (i = 0; lines[i] != NULL; i++)
4622 g_string_append_printf (string, format: "#%s%s", lines[i],
4623 lines[i + 1] == NULL? "" : "\n");
4624 g_strfreev (str_array: lines);
4625
4626 return g_string_free (string, FALSE);
4627}
4628
4629/**
4630 * g_key_file_save_to_file:
4631 * @key_file: a #GKeyFile
4632 * @filename: the name of the file to write to
4633 * @error: a pointer to a %NULL #GError, or %NULL
4634 *
4635 * Writes the contents of @key_file to @filename using
4636 * g_file_set_contents(). If you need stricter guarantees about durability of
4637 * the written file than are provided by g_file_set_contents(), use
4638 * g_file_set_contents_full() with the return value of g_key_file_to_data().
4639 *
4640 * This function can fail for any of the reasons that
4641 * g_file_set_contents() may fail.
4642 *
4643 * Returns: %TRUE if successful, else %FALSE with @error set
4644 *
4645 * Since: 2.40
4646 */
4647gboolean
4648g_key_file_save_to_file (GKeyFile *key_file,
4649 const gchar *filename,
4650 GError **error)
4651{
4652 gchar *contents;
4653 gboolean success;
4654 gsize length;
4655
4656 g_return_val_if_fail (key_file != NULL, FALSE);
4657 g_return_val_if_fail (filename != NULL, FALSE);
4658 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
4659
4660 contents = g_key_file_to_data (key_file, length: &length, NULL);
4661 g_assert (contents != NULL);
4662
4663 success = g_file_set_contents (filename, contents, length, error);
4664 g_free (mem: contents);
4665
4666 return success;
4667}
4668

source code of gtk/subprojects/glib/glib/gkeyfile.c