• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
491 typedef struct _GKeyFileGroup GKeyFileGroup;
492 
493 /**
494  * GKeyFile:
495  *
496  * The GKeyFile struct contains only private data
497  * and should not be accessed directly.
498  */
499 struct _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 
519 typedef struct _GKeyFileKeyValuePair GKeyFileKeyValuePair;
520 
521 struct _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 
535 struct _GKeyFileKeyValuePair
536 {
537   gchar *key;  /* NULL for comments */
538   gchar *value;
539 };
540 
541 static gint                  find_file_in_data_dirs            (const gchar            *file,
542 								const gchar           **data_dirs,
543 								gchar                 **output_file,
544 								GError                **error);
545 static gboolean              g_key_file_load_from_fd           (GKeyFile               *key_file,
546 								gint                    fd,
547 								GKeyFileFlags           flags,
548 								GError                **error);
549 static GList                *g_key_file_lookup_group_node      (GKeyFile               *key_file,
550 			                                        const gchar            *group_name);
551 static GKeyFileGroup        *g_key_file_lookup_group           (GKeyFile               *key_file,
552 								const gchar            *group_name);
553 
554 static GList                *g_key_file_lookup_key_value_pair_node  (GKeyFile       *key_file,
555 			                                             GKeyFileGroup  *group,
556                                                                      const gchar    *key);
557 static GKeyFileKeyValuePair *g_key_file_lookup_key_value_pair       (GKeyFile       *key_file,
558                                                                      GKeyFileGroup  *group,
559                                                                      const gchar    *key);
560 
561 static void                  g_key_file_remove_group_node          (GKeyFile      *key_file,
562 							  	    GList         *group_node);
563 static void                  g_key_file_remove_key_value_pair_node (GKeyFile      *key_file,
564                                                                     GKeyFileGroup *group,
565                                                                     GList         *pair_node);
566 
567 static void                  g_key_file_add_key_value_pair     (GKeyFile               *key_file,
568                                                                 GKeyFileGroup          *group,
569                                                                 GKeyFileKeyValuePair   *pair);
570 static void                  g_key_file_add_key                (GKeyFile               *key_file,
571 								GKeyFileGroup          *group,
572 								const gchar            *key,
573 								const gchar            *value);
574 static void                  g_key_file_add_group              (GKeyFile               *key_file,
575 								const gchar            *group_name);
576 static gboolean              g_key_file_is_group_name          (const gchar *name);
577 static gboolean              g_key_file_is_key_name            (const gchar *name);
578 static void                  g_key_file_key_value_pair_free    (GKeyFileKeyValuePair   *pair);
579 static gboolean              g_key_file_line_is_comment        (const gchar            *line);
580 static gboolean              g_key_file_line_is_group          (const gchar            *line);
581 static gboolean              g_key_file_line_is_key_value_pair (const gchar            *line);
582 static gchar                *g_key_file_parse_value_as_string  (GKeyFile               *key_file,
583 								const gchar            *value,
584 								GSList                **separators,
585 								GError                **error);
586 static gchar                *g_key_file_parse_string_as_value  (GKeyFile               *key_file,
587 								const gchar            *string,
588 								gboolean                escape_separator);
589 static gint                  g_key_file_parse_value_as_integer (GKeyFile               *key_file,
590 								const gchar            *value,
591 								GError                **error);
592 static gchar                *g_key_file_parse_integer_as_value (GKeyFile               *key_file,
593 								gint                    value);
594 static gdouble               g_key_file_parse_value_as_double  (GKeyFile               *key_file,
595                                                                 const gchar            *value,
596                                                                 GError                **error);
597 static gboolean              g_key_file_parse_value_as_boolean (GKeyFile               *key_file,
598 								const gchar            *value,
599 								GError                **error);
600 static gchar                *g_key_file_parse_boolean_as_value (GKeyFile               *key_file,
601 								gboolean                value);
602 static gchar                *g_key_file_parse_value_as_comment (GKeyFile               *key_file,
603                                                                 const gchar            *value,
604                                                                 gboolean                is_final_line);
605 static gchar                *g_key_file_parse_comment_as_value (GKeyFile               *key_file,
606                                                                 const gchar            *comment);
607 static void                  g_key_file_parse_key_value_pair   (GKeyFile               *key_file,
608 								const gchar            *line,
609 								gsize                   length,
610 								GError                **error);
611 static void                  g_key_file_parse_comment          (GKeyFile               *key_file,
612 								const gchar            *line,
613 								gsize                   length,
614 								GError                **error);
615 static void                  g_key_file_parse_group            (GKeyFile               *key_file,
616 								const gchar            *line,
617 								gsize                   length,
618 								GError                **error);
619 static gchar                *key_get_locale                    (const gchar            *key);
620 static void                  g_key_file_parse_data             (GKeyFile               *key_file,
621 								const gchar            *data,
622 								gsize                   length,
623 								GError                **error);
624 static void                  g_key_file_flush_parse_buffer     (GKeyFile               *key_file,
625 								GError                **error);
626 
627 G_DEFINE_QUARK (g-key-file-error-quark, g_key_file_error)
628 
629 static void
g_key_file_init(GKeyFile * key_file)630 g_key_file_init (GKeyFile *key_file)
631 {
632   key_file->current_group = g_slice_new0 (GKeyFileGroup);
633   key_file->groups = g_list_prepend (NULL, 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 
641 static void
g_key_file_clear(GKeyFile * key_file)642 g_key_file_clear (GKeyFile *key_file)
643 {
644   GList *tmp, *group_node;
645 
646   if (key_file->locales)
647     {
648       g_strfreev (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 (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 (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  **/
689 GKeyFile *
g_key_file_new(void)690 g_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  */
712 void
g_key_file_set_list_separator(GKeyFile * key_file,gchar separator)713 g_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  */
727 static gint
find_file_in_data_dirs(const gchar * file,const gchar ** dirs,gchar ** output_file,GError ** error)728 find_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 ("");
751       while (candidate_file != NULL && fd == -1)
752         {
753           gchar *p;
754 
755           path = g_build_filename (data_dir, sub_dir,
756                                    candidate_file, NULL);
757 
758           fd = g_open (path, O_RDONLY, 0);
759 
760           if (fd == -1)
761             {
762               g_free (path);
763               path = NULL;
764             }
765 
766           candidate_file = strchr (candidate_file, '-');
767 
768           if (candidate_file == NULL)
769             break;
770 
771           candidate_file++;
772 
773           g_free (sub_dir);
774           sub_dir = g_strndup (file, 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 (sub_dir);
783       data_dirs++;
784     }
785 
786   if (fd == -1)
787     {
788       g_set_error_literal (error, G_KEY_FILE_ERROR,
789                            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 (path);
796 
797   g_free (path);
798 
799   return fd;
800 }
801 
802 static gboolean
g_key_file_load_from_fd(GKeyFile * key_file,gint fd,GKeyFileFlags flags,GError ** error)803 g_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, &stat_buf) < 0)
815     {
816       int errsv = errno;
817       g_set_error_literal (error, G_FILE_ERROR,
818                            g_file_error_from_errno (errsv),
819                            g_strerror (errsv));
820       return FALSE;
821     }
822 
823   if (!S_ISREG (stat_buf.st_mode))
824     {
825       g_set_error_literal (error, G_KEY_FILE_ERROR,
826                            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, read_buf, 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 (error, G_FILE_ERROR,
853                                g_file_error_from_errno (errsv),
854                                g_strerror (errsv));
855           return FALSE;
856         }
857 
858       g_key_file_parse_data (key_file,
859 			     read_buf, bytes_read,
860 			     &key_file_error);
861     }
862   while (!key_file_error);
863 
864   if (key_file_error)
865     {
866       g_propagate_error (error, key_file_error);
867       return FALSE;
868     }
869 
870   g_key_file_flush_parse_buffer (key_file, &key_file_error);
871 
872   if (key_file_error)
873     {
874       g_propagate_error (error, 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  **/
901 gboolean
g_key_file_load_from_file(GKeyFile * key_file,const gchar * file,GKeyFileFlags flags,GError ** error)902 g_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, O_RDONLY, 0);
915   errsv = errno;
916 
917   if (fd == -1)
918     {
919       g_set_error_literal (error, G_FILE_ERROR,
920                            g_file_error_from_errno (errsv),
921                            g_strerror (errsv));
922       return FALSE;
923     }
924 
925   g_key_file_load_from_fd (key_file, fd, flags, &key_file_error);
926   close (fd);
927 
928   if (key_file_error)
929     {
930       g_propagate_error (error, 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  **/
952 gboolean
g_key_file_load_from_data(GKeyFile * key_file,const gchar * data,gsize length,GKeyFileFlags flags,GError ** error)953 g_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 (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, &key_file_error);
975 
976   if (key_file_error)
977     {
978       g_propagate_error (error, key_file_error);
979       return FALSE;
980     }
981 
982   g_key_file_flush_parse_buffer (key_file, &key_file_error);
983 
984   if (key_file_error)
985     {
986       g_propagate_error (error, 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  **/
1007 gboolean
g_key_file_load_from_bytes(GKeyFile * key_file,GBytes * bytes,GKeyFileFlags flags,GError ** error)1008 g_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);
1020   return g_key_file_load_from_data (key_file, (const gchar *) data, 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  **/
1047 gboolean
g_key_file_load_from_dirs(GKeyFile * key_file,const gchar * file,const gchar ** search_dirs,gchar ** full_path,GKeyFileFlags flags,GError ** error)1048 g_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 (output_path);
1071       output_path = NULL;
1072 
1073       fd = find_file_in_data_dirs (file, data_dirs, &output_path,
1074                                    &key_file_error);
1075 
1076       if (fd == -1)
1077         {
1078           if (key_file_error)
1079             g_propagate_error (error, key_file_error);
1080  	  break;
1081         }
1082 
1083       found_file = g_key_file_load_from_fd (key_file, fd, flags,
1084 	                                    &key_file_error);
1085       close (fd);
1086 
1087       if (key_file_error)
1088         {
1089 	  g_propagate_error (error, key_file_error);
1090 	  break;
1091         }
1092     }
1093 
1094   if (found_file && full_path)
1095     *full_path = output_path;
1096   else
1097     g_free (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  **/
1120 gboolean
g_key_file_load_from_data_dirs(GKeyFile * key_file,const gchar * file,gchar ** full_path,GKeyFileFlags flags,GError ** error)1121 g_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 (user_data_dir);
1142 
1143   j = 0;
1144   while (system_data_dirs[j] != NULL)
1145     all_data_dirs[i++] = g_strdup (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                                           (const gchar **)all_data_dirs,
1151                                           full_path,
1152                                           flags,
1153                                           error);
1154 
1155   g_strfreev (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  **/
1170 GKeyFile *
g_key_file_ref(GKeyFile * key_file)1171 g_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  **/
1190 void
g_key_file_free(GKeyFile * key_file)1191 g_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  **/
1212 void
g_key_file_unref(GKeyFile * key_file)1213 g_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  */
1227 static gboolean
g_key_file_locale_is_interesting(GKeyFile * key_file,const gchar * locale)1228 g_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 ((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 (key_file->locales[i], locale) == 0)
1245 	return TRUE;
1246     }
1247 
1248   return FALSE;
1249 }
1250 
1251 static void
g_key_file_parse_line(GKeyFile * key_file,const gchar * line,gsize length,GError ** error)1252 g_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_start))
1268     g_key_file_parse_comment (key_file, line, length, &parse_error);
1269   else if (g_key_file_line_is_group (line_start))
1270     g_key_file_parse_group (key_file, line_start,
1271 			    length - (line_start - line),
1272 			    &parse_error);
1273   else if (g_key_file_line_is_key_value_pair (line_start))
1274     g_key_file_parse_key_value_pair (key_file, line_start,
1275 				     length - (line_start - line),
1276 				     &parse_error);
1277   else
1278     {
1279       gchar *line_utf8 = g_utf8_make_valid (line, length);
1280       g_set_error (error, G_KEY_FILE_ERROR,
1281                    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 (line_utf8);
1286 
1287       return;
1288     }
1289 
1290   if (parse_error)
1291     g_propagate_error (error, parse_error);
1292 }
1293 
1294 static void
g_key_file_parse_comment(GKeyFile * key_file,const gchar * line,gsize length,GError ** error)1295 g_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 (line, length);
1310 
1311   key_file->current_group->key_value_pairs =
1312     g_list_prepend (key_file->current_group->key_value_pairs, pair);
1313 }
1314 
1315 static void
g_key_file_parse_group(GKeyFile * key_file,const gchar * line,gsize length,GError ** error)1316 g_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 (group_name_start,
1333                           group_name_end - group_name_start);
1334 
1335   if (!g_key_file_is_group_name (group_name))
1336     {
1337       g_set_error (error, G_KEY_FILE_ERROR,
1338 		   G_KEY_FILE_ERROR_PARSE,
1339 		   _("Invalid group name: %s"), group_name);
1340       g_free (group_name);
1341       return;
1342     }
1343 
1344   g_key_file_add_group (key_file, group_name);
1345   g_free (group_name);
1346 }
1347 
1348 static void
g_key_file_parse_key_value_pair(GKeyFile * key_file,const gchar * line,gsize length,GError ** error)1349 g_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 (error, G_KEY_FILE_ERROR,
1360                            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 (line, '=');
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 (line, key_len - 1);
1382 
1383   if (!g_key_file_is_key_name (key))
1384     {
1385       g_set_error (error, G_KEY_FILE_ERROR,
1386                    G_KEY_FILE_ERROR_PARSE,
1387                    _("Invalid key name: %s"), key);
1388       g_free (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 (value_start, 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 (key_file->start_group->name,
1406                  key_file->current_group->name) == 0
1407       && strcmp (key, "Encoding") == 0)
1408     {
1409       if (g_ascii_strcasecmp (value, "UTF-8") != 0)
1410         {
1411 	  gchar *value_utf8 = g_utf8_make_valid (value, value_len);
1412           g_set_error (error, G_KEY_FILE_ERROR,
1413                        G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
1414                        _("Key file contains unsupported "
1415 			 "encoding “%s”"), value_utf8);
1416 	  g_free (value_utf8);
1417 
1418           g_free (key);
1419           g_free (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, key_file->current_group, pair);
1437     }
1438   else
1439     {
1440       g_free (key);
1441       g_free (value);
1442     }
1443 
1444   g_free (locale);
1445 }
1446 
1447 static gchar *
key_get_locale(const gchar * key)1448 key_get_locale (const gchar *key)
1449 {
1450   gchar *locale;
1451 
1452   locale = g_strrstr (key, "[");
1453 
1454   if (locale && strlen (locale) <= 2)
1455     locale = NULL;
1456 
1457   if (locale)
1458     locale = g_strndup (locale + 1, strlen (locale) - 2);
1459 
1460   return locale;
1461 }
1462 
1463 static void
g_key_file_parse_data(GKeyFile * key_file,const gchar * data,gsize length,GError ** error)1464 g_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 (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 (key_file->parse_buffer,
1489 			    key_file->parse_buffer->len - 1,
1490 			    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, &parse_error);
1498           else
1499             g_key_file_parse_comment (key_file, "", 1, &parse_error);
1500 
1501           if (parse_error)
1502             {
1503               g_propagate_error (error, 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 (start_of_line, '\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 (key_file->parse_buffer, start_of_line, line_length);
1523           i += line_length;
1524         }
1525     }
1526 }
1527 
1528 static void
g_key_file_flush_parse_buffer(GKeyFile * key_file,GError ** error)1529 g_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, key_file->parse_buffer->str,
1544 			     key_file->parse_buffer->len,
1545 			     &file_error);
1546       g_string_erase (key_file->parse_buffer, 0, -1);
1547 
1548       if (file_error)
1549         {
1550           g_propagate_error (error, 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  **/
1573 gchar *
g_key_file_to_data(GKeyFile * key_file,gsize * length,GError ** error)1574 g_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 (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 (data_string, "%s\n", group->comment->value);
1600 
1601       if (group->name != NULL)
1602         g_string_append_printf (data_string, "[%s]\n", group->name);
1603 
1604       for (key_file_node = g_list_last (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 (data_string, "%s=%s\n", pair->key, pair->value);
1614           else
1615             g_string_append_printf (data_string, "%s\n", pair->value);
1616         }
1617     }
1618 
1619   if (length)
1620     *length = data_string->len;
1621 
1622   return g_string_free (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  **/
1643 gchar **
g_key_file_get_keys(GKeyFile * key_file,const gchar * group_name,gsize * length,GError ** error)1644 g_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 (error, G_KEY_FILE_ERROR,
1662                    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 (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  **/
1713 gchar *
g_key_file_get_start_group(GKeyFile * key_file)1714 g_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 (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  **/
1737 gchar **
g_key_file_get_groups(GKeyFile * key_file,gsize * length)1738 g_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 (key_file->groups);
1748 
1749   g_return_val_if_fail (num_groups > 0, NULL);
1750 
1751   group_node = g_list_last (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 (group->name);
1775     }
1776   groups[i] = NULL;
1777 
1778   if (length)
1779     *length = i;
1780 
1781   return groups;
1782 }
1783 
1784 static void
set_not_found_key_error(const char * group_name,const char * key,GError ** error)1785 set_not_found_key_error (const char *group_name,
1786                          const char *key,
1787                          GError    **error)
1788 {
1789   g_set_error (error, G_KEY_FILE_ERROR,
1790                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  **/
1816 gchar *
g_key_file_get_value(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)1817 g_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 (error, G_KEY_FILE_ERROR,
1835                    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 (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  **/
1867 void
g_key_file_set_value(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * value)1868 g_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 (pair->value);
1899           pair->value = g_strdup (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  **/
1925 gchar *
g_key_file_get_string(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)1926 g_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, &key_file_error);
1941 
1942   if (key_file_error)
1943     {
1944       g_propagate_error (error, key_file_error);
1945       return NULL;
1946     }
1947 
1948   if (!g_utf8_validate (value, -1, NULL))
1949     {
1950       gchar *value_utf8 = g_utf8_make_valid (value, -1);
1951       g_set_error (error, G_KEY_FILE_ERROR,
1952                    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 (value_utf8);
1956       g_free (value);
1957 
1958       return NULL;
1959     }
1960 
1961   string_value = g_key_file_parse_value_as_string (key_file, value, NULL,
1962 						   &key_file_error);
1963   g_free (value);
1964 
1965   if (key_file_error)
1966     {
1967       if (g_error_matches (key_file_error,
1968                            G_KEY_FILE_ERROR,
1969                            G_KEY_FILE_ERROR_INVALID_VALUE))
1970         {
1971           g_set_error (error, G_KEY_FILE_ERROR,
1972                        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 (key_file_error);
1977         }
1978       else
1979         g_propagate_error (error, 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  **/
2000 void
g_key_file_set_string(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * string)2001 g_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 (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  **/
2037 gchar **
g_key_file_get_string_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gsize * length,GError ** error)2038 g_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, &key_file_error);
2057 
2058   if (key_file_error)
2059     {
2060       g_propagate_error (error, key_file_error);
2061       return NULL;
2062     }
2063 
2064   if (!g_utf8_validate (value, -1, NULL))
2065     {
2066       gchar *value_utf8 = g_utf8_make_valid (value, -1);
2067       g_set_error (error, G_KEY_FILE_ERROR,
2068                    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 (value_utf8);
2072       g_free (value);
2073 
2074       return NULL;
2075     }
2076 
2077   string_value = g_key_file_parse_value_as_string (key_file, value, &pieces, &key_file_error);
2078   g_free (value);
2079   g_free (string_value);
2080 
2081   if (key_file_error)
2082     {
2083       if (g_error_matches (key_file_error,
2084                            G_KEY_FILE_ERROR,
2085                            G_KEY_FILE_ERROR_INVALID_VALUE))
2086         {
2087           g_set_error (error, G_KEY_FILE_ERROR,
2088                        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 (key_file_error);
2093         }
2094       else
2095         g_propagate_error (error, key_file_error);
2096 
2097       g_slist_free_full (pieces, g_free);
2098       return NULL;
2099     }
2100 
2101   len = g_slist_length (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 (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  **/
2129 void
g_key_file_set_string_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * const list[],gsize length)2130 g_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 (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, list[i], TRUE);
2148       g_string_append (value_list, value);
2149       g_string_append_c (value_list, key_file->list_separator);
2150 
2151       g_free (value);
2152     }
2153 
2154   g_key_file_set_value (key_file, group_name, key, value_list->str);
2155   g_string_free (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  **/
2171 void
g_key_file_set_locale_string(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * locale,const gchar * string)2172 g_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 ("%s[%s]", key, locale);
2187   g_key_file_set_value (key_file, group_name, full_key, value);
2188   g_free (full_key);
2189   g_free (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  **/
2218 gchar *
g_key_file_get_locale_string(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * locale,GError ** error)2219 g_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 ("%s[%s]", key, languages[i]);
2253 
2254       translated_value = g_key_file_get_string (key_file,
2255 						group_name,
2256 						candidate_key, NULL);
2257       g_free (candidate_key);
2258 
2259       if (translated_value)
2260 	break;
2261 
2262       g_free (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 						&key_file_error);
2272 
2273       if (!translated_value)
2274         g_propagate_error (error, key_file_error);
2275     }
2276 
2277   if (free_languages)
2278     g_strfreev (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  */
2305 gchar *
g_key_file_get_locale_for_key(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * locale)2306 g_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 ("%s[%s]", key, languages[i]);
2333       translated_value = g_key_file_get_string (key_file, group_name, candidate_key, NULL);
2334       g_free (translated_value);
2335       g_free (candidate_key);
2336 
2337       if (translated_value != NULL)
2338         break;
2339    }
2340 
2341   result = g_strdup (languages[i]);
2342 
2343   g_strfreev (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  **/
2378 gchar **
g_key_file_get_locale_string_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * locale,gsize * length,GError ** error)2379 g_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 					&key_file_error);
2400 
2401   if (key_file_error)
2402     g_propagate_error (error, key_file_error);
2403 
2404   if (!value)
2405     {
2406       if (length)
2407         *length = 0;
2408       return NULL;
2409     }
2410 
2411   len = strlen (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 (value, list_separator, 0);
2418 
2419   g_free (value);
2420 
2421   if (length)
2422     *length = g_strv_length (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  **/
2442 void
g_key_file_set_locale_string_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * locale,const gchar * const list[],gsize length)2443 g_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 (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, list[i], TRUE);
2465       g_string_append (value_list, value);
2466       g_string_append_c (value_list, key_file->list_separator);
2467 
2468       g_free (value);
2469     }
2470 
2471   full_key = g_strdup_printf ("%s[%s]", key, locale);
2472   g_key_file_set_value (key_file, group_name, full_key, value_list->str);
2473   g_free (full_key);
2474   g_string_free (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  **/
2497 gboolean
g_key_file_get_boolean(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)2498 g_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, &key_file_error);
2512 
2513   if (!value)
2514     {
2515       g_propagate_error (error, key_file_error);
2516       return FALSE;
2517     }
2518 
2519   bool_value = g_key_file_parse_value_as_boolean (key_file, value,
2520 						  &key_file_error);
2521   g_free (value);
2522 
2523   if (key_file_error)
2524     {
2525       if (g_error_matches (key_file_error,
2526                            G_KEY_FILE_ERROR,
2527                            G_KEY_FILE_ERROR_INVALID_VALUE))
2528         {
2529           g_set_error (error, G_KEY_FILE_ERROR,
2530                        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 (key_file_error);
2535         }
2536       else
2537         g_propagate_error (error, 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  **/
2555 void
g_key_file_set_boolean(GKeyFile * key_file,const gchar * group_name,const gchar * key,gboolean value)2556 g_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, result);
2567   g_free (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  **/
2593 gboolean *
g_key_file_get_boolean_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gsize * length,GError ** error)2594 g_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 				       &num_bools, &key_file_error);
2616 
2617   if (key_file_error)
2618     g_propagate_error (error, 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 							  values[i],
2629 							  &key_file_error);
2630 
2631       if (key_file_error)
2632         {
2633           g_propagate_error (error, key_file_error);
2634           g_strfreev (values);
2635           g_free (bool_values);
2636 
2637           return NULL;
2638         }
2639     }
2640   g_strfreev (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  **/
2662 void
g_key_file_set_boolean_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gboolean list[],gsize length)2663 g_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 (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, list[i]);
2681 
2682       g_string_append (value_list, value);
2683       g_string_append_c (value_list, key_file->list_separator);
2684 
2685       g_free (value);
2686     }
2687 
2688   g_key_file_set_value (key_file, group_name, key, value_list->str);
2689   g_string_free (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  **/
2713 gint
g_key_file_get_integer(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)2714 g_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, &key_file_error);
2730 
2731   if (key_file_error)
2732     {
2733       g_propagate_error (error, key_file_error);
2734       return 0;
2735     }
2736 
2737   int_value = g_key_file_parse_value_as_integer (key_file, value,
2738 						 &key_file_error);
2739   g_free (value);
2740 
2741   if (key_file_error)
2742     {
2743       if (g_error_matches (key_file_error,
2744                            G_KEY_FILE_ERROR,
2745                            G_KEY_FILE_ERROR_INVALID_VALUE))
2746         {
2747           g_set_error (error, G_KEY_FILE_ERROR,
2748                        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 (key_file_error);
2753         }
2754       else
2755         g_propagate_error (error, 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  **/
2773 void
g_key_file_set_integer(GKeyFile * key_file,const gchar * group_name,const gchar * key,gint value)2774 g_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, result);
2785   g_free (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  */
2804 gint64
g_key_file_get_int64(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)2805 g_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 (s, &end, 10);
2823 
2824   if (*s == '\0' || *end != '\0')
2825     {
2826       g_set_error (error, G_KEY_FILE_ERROR, 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 (s);
2831       return 0;
2832     }
2833 
2834   g_free (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  **/
2850 void
g_key_file_set_int64(GKeyFile * key_file,const gchar * group_name,const gchar * key,gint64 value)2851 g_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 ("%" G_GINT64_FORMAT, value);
2861   g_key_file_set_value (key_file, group_name, key, result);
2862   g_free (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  */
2881 guint64
g_key_file_get_uint64(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)2882 g_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 (s, &end, 10);
2900 
2901   if (*s == '\0' || *end != '\0')
2902     {
2903       g_set_error (error, G_KEY_FILE_ERROR, 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 (s);
2908       return 0;
2909     }
2910 
2911   g_free (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  **/
2927 void
g_key_file_set_uint64(GKeyFile * key_file,const gchar * group_name,const gchar * key,guint64 value)2928 g_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 ("%" G_GUINT64_FORMAT, value);
2938   g_key_file_set_value (key_file, group_name, key, result);
2939   g_free (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  **/
2966 gint *
g_key_file_get_integer_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gsize * length,GError ** error)2967 g_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 				       &num_ints, &key_file_error);
2987 
2988   if (key_file_error)
2989     g_propagate_error (error, 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 							 values[i],
3000 							 &key_file_error);
3001 
3002       if (key_file_error)
3003         {
3004           g_propagate_error (error, key_file_error);
3005           g_strfreev (values);
3006           g_free (int_values);
3007 
3008           return NULL;
3009         }
3010     }
3011   g_strfreev (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  **/
3032 void
g_key_file_set_integer_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gint list[],gsize length)3033 g_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 (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, list[i]);
3051 
3052       g_string_append (values, value);
3053       g_string_append_c (values, key_file->list_separator);
3054 
3055       g_free (value);
3056     }
3057 
3058   g_key_file_set_value (key_file, group_name, key, values->str);
3059   g_string_free (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  **/
3082 gdouble
g_key_file_get_double(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)3083 g_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, &key_file_error);
3099 
3100   if (key_file_error)
3101     {
3102       g_propagate_error (error, key_file_error);
3103       return 0;
3104     }
3105 
3106   double_value = g_key_file_parse_value_as_double (key_file, value,
3107                                                   &key_file_error);
3108   g_free (value);
3109 
3110   if (key_file_error)
3111     {
3112       if (g_error_matches (key_file_error,
3113                            G_KEY_FILE_ERROR,
3114                            G_KEY_FILE_ERROR_INVALID_VALUE))
3115         {
3116           g_set_error (error, G_KEY_FILE_ERROR,
3117                        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 (key_file_error);
3122         }
3123       else
3124         g_propagate_error (error, 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  **/
3142 void
g_key_file_set_double(GKeyFile * key_file,const gchar * group_name,const gchar * key,gdouble value)3143 g_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 (result, sizeof (result), value);
3153   g_key_file_set_value (key_file, group_name, key, 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  **/
3179 gdouble *
g_key_file_get_double_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gsize * length,GError ** error)3180 g_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                                        &num_doubles, &key_file_error);
3200 
3201   if (key_file_error)
3202     g_propagate_error (error, 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 							   values[i],
3213 							   &key_file_error);
3214 
3215       if (key_file_error)
3216         {
3217           g_propagate_error (error, key_file_error);
3218           g_strfreev (values);
3219           g_free (double_values);
3220 
3221           return NULL;
3222         }
3223     }
3224   g_strfreev (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  **/
3245 void
g_key_file_set_double_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gdouble list[],gsize length)3246 g_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 (length * 16);
3259   for (i = 0; i < length; i++)
3260     {
3261       gchar result[G_ASCII_DTOSTR_BUF_SIZE];
3262 
3263       g_ascii_dtostr( result, sizeof (result), list[i] );
3264 
3265       g_string_append (values, result);
3266       g_string_append_c (values, key_file->list_separator);
3267     }
3268 
3269   g_key_file_set_value (key_file, group_name, key, values->str);
3270   g_string_free (values, TRUE);
3271 }
3272 
3273 static gboolean
g_key_file_set_key_comment(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * comment,GError ** error)3274 g_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 (error, G_KEY_FILE_ERROR,
3288                    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, 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                                              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 (key_node, pair, 1);
3333   (void) key_node;
3334 
3335   return TRUE;
3336 }
3337 
3338 static gboolean
g_key_file_set_group_comment(GKeyFile * key_file,const gchar * group_name,const gchar * comment,GError ** error)3339 g_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 (error, G_KEY_FILE_ERROR,
3352                    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 (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 
3379 static gboolean
g_key_file_set_top_comment(GKeyFile * key_file,const gchar * comment,GError ** error)3380 g_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 (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 (group->key_value_pairs, (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 (group->key_value_pairs, 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  **/
3436 gboolean
g_key_file_set_comment(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * comment,GError ** error)3437 g_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 
3464 static gchar *
g_key_file_get_key_comment(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)3465 g_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 (error, G_KEY_FILE_ERROR,
3482                    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, 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 (512);
3529 
3530       comment = g_key_file_parse_value_as_comment (key_file, pair->value,
3531                                                    (tmp->prev == key_node));
3532       g_string_append (string, comment);
3533       g_free (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 
3549 static gchar *
get_group_comment(GKeyFile * key_file,GKeyFileGroup * group,GError ** error)3550 get_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 (512);
3587 
3588       comment = g_key_file_parse_value_as_comment (key_file, pair->value,
3589                                                    (tmp->prev == NULL));
3590       g_string_append (string, comment);
3591       g_free (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 
3602 static gchar *
g_key_file_get_group_comment(GKeyFile * key_file,const gchar * group_name,GError ** error)3603 g_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 (error, G_KEY_FILE_ERROR,
3614                    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 (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 
3630 static gchar *
g_key_file_get_top_comment(GKeyFile * key_file,GError ** error)3631 g_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 (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  **/
3668 gchar *
g_key_file_get_comment(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)3669 g_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 
3701 gboolean
g_key_file_remove_comment(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)3702 g_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  **/
3728 gboolean
g_key_file_has_group(GKeyFile * key_file,const gchar * group_name)3729 g_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  */
3741 static gboolean
g_key_file_has_key_full(GKeyFile * key_file,const gchar * group_name,const gchar * key,gboolean * has_key,GError ** error)3742 g_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 (error, G_KEY_FILE_ERROR,
3760                    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  **/
3796 gboolean
g_key_file_has_key(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)3797 g_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, &temp_error))
3806     {
3807       return has_key;
3808     }
3809   else
3810     {
3811       g_propagate_error (error, temp_error);
3812       return FALSE;
3813     }
3814 }
3815 
3816 static void
g_key_file_add_group(GKeyFile * key_file,const gchar * group_name)3817 g_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 (group_name);
3834   group->lookup_map = g_hash_table_new (g_str_hash, g_str_equal);
3835   key_file->groups = g_list_prepend (key_file->groups, 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 (g_str_hash, g_str_equal);
3843 
3844   g_hash_table_insert (key_file->group_hash, (gpointer)group->name, group);
3845 }
3846 
3847 static void
g_key_file_key_value_pair_free(GKeyFileKeyValuePair * pair)3848 g_key_file_key_value_pair_free (GKeyFileKeyValuePair *pair)
3849 {
3850   if (pair != NULL)
3851     {
3852       g_free (pair->key);
3853       g_free (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  */
3867 static void
g_key_file_remove_key_value_pair_node(GKeyFile * key_file,GKeyFileGroup * group,GList * pair_node)3868 g_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 (group->key_value_pairs, 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 (pair_node);
3884 }
3885 
3886 static void
g_key_file_remove_group_node(GKeyFile * key_file,GList * group_node)3887 g_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 (key_file->group_hash, 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 (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 (key_file->groups, 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 (group->comment);
3953       group->comment = NULL;
3954     }
3955 
3956   if (group->lookup_map)
3957     {
3958       g_hash_table_destroy (group->lookup_map);
3959       group->lookup_map = NULL;
3960     }
3961 
3962   g_free ((gchar *) group->name);
3963   g_slice_free (GKeyFileGroup, group);
3964   g_list_free_1 (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  **/
3980 gboolean
g_key_file_remove_group(GKeyFile * key_file,const gchar * group_name,GError ** error)3981 g_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 (error, G_KEY_FILE_ERROR,
3995 		   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 
4006 static void
g_key_file_add_key_value_pair(GKeyFile * key_file,GKeyFileGroup * group,GKeyFileKeyValuePair * pair)4007 g_key_file_add_key_value_pair (GKeyFile             *key_file,
4008                                GKeyFileGroup        *group,
4009                                GKeyFileKeyValuePair *pair)
4010 {
4011   g_hash_table_replace (group->lookup_map, pair->key, pair);
4012   group->key_value_pairs = g_list_prepend (group->key_value_pairs, pair);
4013 }
4014 
4015 static void
g_key_file_add_key(GKeyFile * key_file,GKeyFileGroup * group,const gchar * key,const gchar * value)4016 g_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 (key);
4025   pair->value = g_strdup (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  **/
4043 gboolean
g_key_file_remove_key(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)4044 g_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 (error, G_KEY_FILE_ERROR,
4062                    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, key, error);
4073       return FALSE;
4074     }
4075 
4076   group->key_value_pairs = g_list_remove (group->key_value_pairs, pair);
4077   g_hash_table_remove (group->lookup_map, pair->key);
4078   g_key_file_key_value_pair_free (pair);
4079 
4080   return TRUE;
4081 }
4082 
4083 static GList *
g_key_file_lookup_group_node(GKeyFile * key_file,const gchar * group_name)4084 g_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 (group->name, group_name) == 0)
4095         break;
4096     }
4097 
4098   return tmp;
4099 }
4100 
4101 static GKeyFileGroup *
g_key_file_lookup_group(GKeyFile * key_file,const gchar * group_name)4102 g_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 (key_file->group_hash, group_name);
4109 }
4110 
4111 static GList *
g_key_file_lookup_key_value_pair_node(GKeyFile * key_file,GKeyFileGroup * group,const gchar * key)4112 g_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 (pair->key, key) == 0)
4127         break;
4128     }
4129 
4130   return key_node;
4131 }
4132 
4133 static GKeyFileKeyValuePair *
g_key_file_lookup_key_value_pair(GKeyFile * key_file,GKeyFileGroup * group,const gchar * key)4134 g_key_file_lookup_key_value_pair (GKeyFile      *key_file,
4135 				  GKeyFileGroup *group,
4136 				  const gchar   *key)
4137 {
4138   return (GKeyFileKeyValuePair *) g_hash_table_lookup (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  */
4145 static gboolean
g_key_file_line_is_comment(const gchar * line)4146 g_key_file_line_is_comment (const gchar *line)
4147 {
4148   return (*line == '#' || *line == '\0' || *line == '\n');
4149 }
4150 
4151 static gboolean
g_key_file_is_group_name(const gchar * name)4152 g_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 (q, NULL);
4162 
4163   if (*q != '\0' || q == p)
4164     return FALSE;
4165 
4166   return TRUE;
4167 }
4168 
4169 static gboolean
g_key_file_is_key_name(const gchar * name)4170 g_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 (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 (g_utf8_get_char_validated (q, -1)) || *q == '-' || *q == '_' || *q == '.' || *q == '@'))
4200         q = g_utf8_find_next_char (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  */
4217 static gboolean
g_key_file_line_is_group(const gchar * line)4218 g_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 
4245 static gboolean
g_key_file_line_is_key_value_pair(const gchar * line)4246 g_key_file_line_is_key_value_pair (const gchar *line)
4247 {
4248   gchar *p;
4249 
4250   p = (gchar *) g_utf8_strchr (line, -1, '=');
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 
4263 static gchar *
g_key_file_parse_value_as_string(GKeyFile * key_file,const gchar * value,GSList ** pieces,GError ** error)4264 g_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 (error, G_KEY_FILE_ERROR,
4305                                    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 (error, G_KEY_FILE_ERROR,
4327 				   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 (*pieces, g_strndup (q0, 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 (*pieces, g_strndup (q0, q - q0));
4357     *pieces = g_slist_reverse (*pieces);
4358   }
4359 
4360   return string_value;
4361 }
4362 
4363 static gchar *
g_key_file_parse_string_as_value(GKeyFile * key_file,const gchar * string,gboolean escape_separator)4364 g_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 (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 (q, 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 (q, 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 (q, escaped_character);
4417           q += 2;
4418           break;
4419         case '\r':
4420           escaped_character[1] = 'r';
4421           strcpy (q, escaped_character);
4422           q += 2;
4423           break;
4424         case '\\':
4425           escaped_character[1] = '\\';
4426           strcpy (q, 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 (q, 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 
4453 static gint
g_key_file_parse_value_as_integer(GKeyFile * key_file,const gchar * value,GError ** error)4454 g_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 (value, &eof_int, 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 (value, -1);
4470       g_set_error (error, G_KEY_FILE_ERROR,
4471 		   G_KEY_FILE_ERROR_INVALID_VALUE,
4472 		   _("Value “%s” cannot be interpreted "
4473 		     "as a number."), value_utf8);
4474       g_free (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 (value, -1);
4483       g_set_error (error,
4484 		   G_KEY_FILE_ERROR,
4485 		   G_KEY_FILE_ERROR_INVALID_VALUE,
4486 		   _("Integer value “%s” out of range"),
4487 		   value_utf8);
4488       g_free (value_utf8);
4489 
4490       return 0;
4491     }
4492 
4493   return int_value;
4494 }
4495 
4496 static gchar *
g_key_file_parse_integer_as_value(GKeyFile * key_file,gint value)4497 g_key_file_parse_integer_as_value (GKeyFile *key_file,
4498 				   gint      value)
4499 
4500 {
4501   return g_strdup_printf ("%d", value);
4502 }
4503 
4504 static gdouble
g_key_file_parse_value_as_double(GKeyFile * key_file,const gchar * value,GError ** error)4505 g_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 (value, &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 (value, -1);
4517       g_set_error (error, G_KEY_FILE_ERROR,
4518 		   G_KEY_FILE_ERROR_INVALID_VALUE,
4519 		   _("Value “%s” cannot be interpreted "
4520 		     "as a float number."),
4521 		   value_utf8);
4522       g_free (value_utf8);
4523 
4524       double_value = 0;
4525     }
4526 
4527   return double_value;
4528 }
4529 
4530 static gint
strcmp_sized(const gchar * s1,size_t len1,const gchar * s2)4531 strcmp_sized (const gchar *s1, size_t len1, const gchar *s2)
4532 {
4533   size_t len2 = strlen (s2);
4534   return strncmp (s1, s2, MAX (len1, len2));
4535 }
4536 
4537 static gboolean
g_key_file_parse_value_as_boolean(GKeyFile * key_file,const gchar * value,GError ** error)4538 g_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 (value, length, "true") == 0 || strcmp_sized (value, length, "1") == 0)
4551     return TRUE;
4552   else if (strcmp_sized (value, length, "false") == 0 || strcmp_sized (value, length, "0") == 0)
4553     return FALSE;
4554 
4555   value_utf8 = g_utf8_make_valid (value, -1);
4556   g_set_error (error, G_KEY_FILE_ERROR,
4557                G_KEY_FILE_ERROR_INVALID_VALUE,
4558                _("Value “%s” cannot be interpreted "
4559 		 "as a boolean."), value_utf8);
4560   g_free (value_utf8);
4561 
4562   return FALSE;
4563 }
4564 
4565 static gchar *
g_key_file_parse_boolean_as_value(GKeyFile * key_file,gboolean value)4566 g_key_file_parse_boolean_as_value (GKeyFile *key_file,
4567 				   gboolean  value)
4568 {
4569   if (value)
4570     return g_strdup ("true");
4571   else
4572     return g_strdup ("false");
4573 }
4574 
4575 static gchar *
g_key_file_parse_value_as_comment(GKeyFile * key_file,const gchar * value,gboolean is_final_line)4576 g_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 (512);
4585 
4586   lines = g_strsplit (value, "\n", 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, line);
4598     }
4599   g_strfreev (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 
4609 static gchar *
g_key_file_parse_comment_as_value(GKeyFile * key_file,const gchar * comment)4610 g_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 (512);
4618 
4619   lines = g_strsplit (comment, "\n", 0);
4620 
4621   for (i = 0; lines[i] != NULL; i++)
4622     g_string_append_printf (string, "#%s%s", lines[i],
4623                             lines[i + 1] == NULL? "" : "\n");
4624   g_strfreev (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  */
4647 gboolean
g_key_file_save_to_file(GKeyFile * key_file,const gchar * filename,GError ** error)4648 g_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, NULL);
4661   g_assert (contents != NULL);
4662 
4663   success = g_file_set_contents (filename, contents, length, error);
4664   g_free (contents);
4665 
4666   return success;
4667 }
4668