1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  *  Copyright (C) 2006 Kouhei Sutou <kou@cozmixng.org>
4  *
5  *  This library is free software; you can redistribute it and/or
6  *  modify it under the terms of the GNU Lesser General Public
7  *  License as published by the Free Software Foundation; either
8  *  version 2 of the License, or (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public
16  *  License along with this program; if not, write to the
17  *  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  *  Boston, MA  02111-1307  USA
19  *
20  *  $Id: glib-compat-key-file.c 1080 2006-12-25 03:32:50Z kous $
21  */
22 
23 #include "glib-utils.h"
24 
25 #if !GLIB_CHECK_VERSION(2, 6, 0)
26 /* gkeyfile.c - key file parser
27  *
28  *  Copyright 2004  Red Hat, Inc.
29  *
30  * Written by Ray Strode <rstrode@redhat.com>
31  *            Matthias Clasen <mclasen@redhat.com>
32  *
33  * GLib is free software; you can redistribute it and/or modify it
34  * under the terms of the GNU Lesser General Public License as
35  * published by the Free Software Foundation; either version 2 of the
36  * License, or (at your option) any later version.
37  *
38  * GLib is distributed in the hope that it will be useful,
39  * but WITHOUT ANY WARRANTY; without even the implied warranty of
40  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41  * Lesser General Public License for more details.
42  *
43  * You should have received a copy of the GNU Lesser General Public
44  * License along with GLib; see the file COPYING.LIB.  If not,
45  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
46  *   Boston, MA 02111-1307, USA.
47  */
48 
49 #include "config.h"
50 
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <locale.h>
54 #include <string.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #ifdef HAVE_UNISTD_H
60 #include <unistd.h>
61 #endif
62 #ifdef G_OS_WIN32
63 #include <io.h>
64 
65 #ifndef S_ISREG
66 #define S_ISREG(mode) ((mode)&_S_IFREG)
67 #endif
68 
69 #endif  /* G_OS_WIN23 */
70 
71 typedef struct _GKeyFileGroup GKeyFileGroup;
72 
73 struct _GKeyFile
74 {
75   GList *groups;
76 
77   GKeyFileGroup *start_group;
78   GKeyFileGroup *current_group;
79 
80   GString *parse_buffer; /* Holds up to one line of not-yet-parsed data */
81 
82   /* Used for sizing the output buffer during serialization
83    */
84   gsize approximate_size;
85 
86   gchar list_separator;
87 
88   GKeyFileFlags flags;
89 };
90 
91 typedef struct _GKeyFileKeyValuePair GKeyFileKeyValuePair;
92 
93 struct _GKeyFileGroup
94 {
95   const gchar *name;  /* NULL for above first group (which will be comments) */
96 
97   GKeyFileKeyValuePair *comment; /* Special comment that is stuck to the top of a group */
98 
99   GList *key_value_pairs;
100 
101   /* Used in parallel with key_value_pairs for
102    * increased lookup performance
103    */
104   GHashTable *lookup_map;
105 };
106 
107 struct _GKeyFileKeyValuePair
108 {
109   gchar *key;  /* NULL for comments */
110   gchar *value;
111 };
112 
113 static gboolean              g_key_file_load_from_fd           (GKeyFile               *key_file,
114 								gint                    fd,
115 								GKeyFileFlags           flags,
116 								GError                **error);
117 static GList                *g_key_file_lookup_group_node      (GKeyFile               *key_file,
118 			                                        const gchar            *group_name);
119 static GKeyFileGroup        *g_key_file_lookup_group           (GKeyFile               *key_file,
120 								const gchar            *group_name);
121 
122 static GList                *g_key_file_lookup_key_value_pair_node  (GKeyFile       *key_file,
123 			                                             GKeyFileGroup  *group,
124                                                                      const gchar    *key);
125 static GKeyFileKeyValuePair *g_key_file_lookup_key_value_pair       (GKeyFile       *key_file,
126                                                                      GKeyFileGroup  *group,
127                                                                      const gchar    *key);
128 
129 static void                  g_key_file_remove_group_node          (GKeyFile      *key_file,
130 							  	    GList         *group_node);
131 static void                  g_key_file_remove_key_value_pair_node (GKeyFile      *key_file,
132                                                                     GKeyFileGroup *group,
133                                                                     GList         *pair_node);
134 
135 static void                  g_key_file_add_key                (GKeyFile               *key_file,
136 								GKeyFileGroup          *group,
137 								const gchar            *key,
138 								const gchar            *value);
139 static void                  g_key_file_add_group              (GKeyFile               *key_file,
140 								const gchar            *group_name);
141 static gboolean              g_key_file_is_group_name          (const gchar *name);
142 static gboolean              g_key_file_is_key_name            (const gchar *name);
143 static void                  g_key_file_key_value_pair_free    (GKeyFileKeyValuePair   *pair);
144 static gboolean              g_key_file_line_is_comment        (const gchar            *line);
145 static gboolean              g_key_file_line_is_group          (const gchar            *line);
146 static gboolean              g_key_file_line_is_key_value_pair (const gchar            *line);
147 static gchar                *g_key_file_parse_value_as_string  (GKeyFile               *key_file,
148 								const gchar            *value,
149 								GSList                **separators,
150 								GError                **error);
151 static gchar                *g_key_file_parse_string_as_value  (GKeyFile               *key_file,
152 								const gchar            *string,
153 								gboolean                escape_separator);
154 static gint                  g_key_file_parse_value_as_integer (GKeyFile               *key_file,
155 								const gchar            *value,
156 								GError                **error);
157 static gchar                *g_key_file_parse_integer_as_value (GKeyFile               *key_file,
158 								gint                    value);
159 static gdouble               g_key_file_parse_value_as_double  (GKeyFile               *key_file,
160                                                                 const gchar            *value,
161                                                                 GError                **error);
162 static gboolean              g_key_file_parse_value_as_boolean (GKeyFile               *key_file,
163 								const gchar            *value,
164 								GError                **error);
165 static gchar                *g_key_file_parse_boolean_as_value (GKeyFile               *key_file,
166 								gboolean                value);
167 static gchar                *g_key_file_parse_value_as_comment (GKeyFile               *key_file,
168                                                                 const gchar            *value);
169 static gchar                *g_key_file_parse_comment_as_value (GKeyFile               *key_file,
170                                                                 const gchar            *comment);
171 static void                  g_key_file_parse_key_value_pair   (GKeyFile               *key_file,
172 								const gchar            *line,
173 								gsize                   length,
174 								GError                **error);
175 static void                  g_key_file_parse_comment          (GKeyFile               *key_file,
176 								const gchar            *line,
177 								gsize                   length,
178 								GError                **error);
179 static void                  g_key_file_parse_group            (GKeyFile               *key_file,
180 								const gchar            *line,
181 								gsize                   length,
182 								GError                **error);
183 static gchar                *key_get_locale                    (const gchar            *key);
184 static void                  g_key_file_parse_data             (GKeyFile               *key_file,
185 								const gchar            *data,
186 								gsize                   length,
187 								GError                **error);
188 static void                  g_key_file_flush_parse_buffer     (GKeyFile               *key_file,
189 								GError                **error);
190 
191 
192 GQuark
g_key_file_error_quark(void)193 g_key_file_error_quark (void)
194 {
195   return g_quark_from_static_string ("g-key-file-error-quark");
196 }
197 
198 static void
g_key_file_init(GKeyFile * key_file)199 g_key_file_init (GKeyFile *key_file)
200 {
201   key_file->current_group = g_new0 (GKeyFileGroup, 1);
202   key_file->groups = g_list_prepend (NULL, key_file->current_group);
203   key_file->start_group = NULL;
204   key_file->parse_buffer = g_string_sized_new (128);
205   key_file->approximate_size = 0;
206   key_file->list_separator = ';';
207   key_file->flags = 0;
208 }
209 
210 static void
g_key_file_clear(GKeyFile * key_file)211 g_key_file_clear (GKeyFile *key_file)
212 {
213   GList *tmp, *group_node;
214 
215   if (key_file->parse_buffer)
216     g_string_free (key_file->parse_buffer, TRUE);
217 
218   tmp = key_file->groups;
219   while (tmp != NULL)
220     {
221       group_node = tmp;
222       tmp = tmp->next;
223       g_key_file_remove_group_node (key_file, group_node);
224     }
225 
226   g_assert (key_file->groups == NULL);
227 }
228 
229 
230 /**
231  * g_key_file_new:
232  *
233  * Creates a new empty #GKeyFile object. Use g_key_file_load_from_file(),
234  * g_key_file_load_from_data() or g_key_file_load_from_data_dirs() to
235  * read an existing key file.
236  *
237  * Return value: an empty #GKeyFile.
238  *
239  * Since: 2.6
240  **/
241 GKeyFile *
g_key_file_new(void)242 g_key_file_new (void)
243 {
244   GKeyFile *key_file;
245 
246   key_file = g_new0 (GKeyFile, 1);
247   g_key_file_init (key_file);
248 
249   return key_file;
250 }
251 
252 /**
253  * g_key_file_set_list_separator:
254  * @key_file: a #GKeyFile
255  * @separator: the separator
256  *
257  * Sets the character which is used to separate
258  * values in lists. Typically ';' or ',' are used
259  * as separators. The default list separator is ';'.
260  *
261  * Since: 2.6
262  */
263 void
g_key_file_set_list_separator(GKeyFile * key_file,gchar separator)264 g_key_file_set_list_separator (GKeyFile *key_file,
265 			       gchar     separator)
266 {
267   g_return_if_fail (key_file != NULL);
268 
269   key_file->list_separator = separator;
270 }
271 
272 
273 static gboolean
g_key_file_load_from_fd(GKeyFile * key_file,gint fd,GKeyFileFlags flags,GError ** error)274 g_key_file_load_from_fd (GKeyFile       *key_file,
275 			 gint            fd,
276 			 GKeyFileFlags   flags,
277 			 GError        **error)
278 {
279   GError *key_file_error = NULL;
280   gssize bytes_read;
281   struct stat stat_buf;
282   gchar read_buf[4096];
283 
284   if (fstat (fd, &stat_buf) < 0)
285     {
286       g_set_error (error, G_FILE_ERROR,
287                    g_file_error_from_errno (errno),
288                    "%s", g_strerror (errno));
289       return FALSE;
290     }
291 
292   if (!S_ISREG (stat_buf.st_mode))
293     {
294       g_set_error (error, G_KEY_FILE_ERROR,
295                    G_KEY_FILE_ERROR_PARSE,
296                    _("Not a regular file"));
297       return FALSE;
298     }
299 
300   if (stat_buf.st_size == 0)
301     {
302       g_set_error (error, G_KEY_FILE_ERROR,
303                    G_KEY_FILE_ERROR_PARSE,
304                    _("File is empty"));
305       return FALSE;
306     }
307 
308   if (key_file->approximate_size > 0)
309     {
310       g_key_file_clear (key_file);
311       g_key_file_init (key_file);
312     }
313   key_file->flags = flags;
314 
315   bytes_read = 0;
316   do
317     {
318       bytes_read = read (fd, read_buf, 4096);
319 
320       if (bytes_read == 0)  /* End of File */
321         break;
322 
323       if (bytes_read < 0)
324         {
325           if (errno == EINTR || errno == EAGAIN)
326             continue;
327 
328           g_set_error (error, G_FILE_ERROR,
329                        g_file_error_from_errno (errno),
330                        "%s", g_strerror (errno));
331           return FALSE;
332         }
333 
334       g_key_file_parse_data (key_file,
335 			     read_buf, bytes_read,
336 			     &key_file_error);
337     }
338   while (!key_file_error);
339 
340   if (key_file_error)
341     {
342       g_propagate_error (error, key_file_error);
343       return FALSE;
344     }
345 
346   g_key_file_flush_parse_buffer (key_file, &key_file_error);
347 
348   if (key_file_error)
349     {
350       g_propagate_error (error, key_file_error);
351       return FALSE;
352     }
353 
354   return TRUE;
355 }
356 
357 /**
358  * g_key_file_load_from_file:
359  * @key_file: an empty #GKeyFile struct
360  * @file: the path of a filename to load, in the GLib file name encoding
361  * @flags: flags from #GKeyFileFlags
362  * @error: return location for a #GError, or %NULL
363  *
364  * Loads a key file into an empty #GKeyFile structure.
365  * If the file could not be loaded then %error is set to
366  * either a #GFileError or #GKeyFileError.
367  *
368  * Return value: %TRUE if a key file could be loaded, %FALSE othewise
369  * Since: 2.6
370  **/
371 gboolean
g_key_file_load_from_file(GKeyFile * key_file,const gchar * file,GKeyFileFlags flags,GError ** error)372 g_key_file_load_from_file (GKeyFile       *key_file,
373 			   const gchar    *file,
374 			   GKeyFileFlags   flags,
375 			   GError        **error)
376 {
377   GError *key_file_error = NULL;
378   gint fd;
379 
380   g_return_val_if_fail (key_file != NULL, FALSE);
381   g_return_val_if_fail (file != NULL, FALSE);
382 
383   fd = g_open (file, O_RDONLY, 0);
384 
385   if (fd < 0)
386     {
387       g_set_error (error, G_FILE_ERROR,
388                    g_file_error_from_errno (errno),
389                    "%s", g_strerror (errno));
390       return FALSE;
391     }
392 
393   g_key_file_load_from_fd (key_file, fd, flags, &key_file_error);
394   close (fd);
395 
396   if (key_file_error)
397     {
398       g_propagate_error (error, key_file_error);
399       return FALSE;
400     }
401 
402   return TRUE;
403 }
404 
405 /**
406  * g_key_file_load_from_data:
407  * @key_file: an empty #GKeyFile struct
408  * @data: key file loaded in memory.
409  * @length: the length of @data in bytes
410  * @flags: flags from #GKeyFileFlags
411  * @error: return location for a #GError, or %NULL
412  *
413  * Loads a key file from memory into an empty #GKeyFile structure.  If
414  * the object cannot be created then %error is set to a
415  * #GKeyFileError.
416  *
417  * Return value: %TRUE if a key file could be loaded, %FALSE othewise
418  * Since: 2.6
419  **/
420 gboolean
g_key_file_load_from_data(GKeyFile * key_file,const gchar * data,gsize length,GKeyFileFlags flags,GError ** error)421 g_key_file_load_from_data (GKeyFile       *key_file,
422 			   const gchar    *data,
423 			   gsize           length,
424 			   GKeyFileFlags   flags,
425 			   GError        **error)
426 {
427   GError *key_file_error = NULL;
428 
429   g_return_val_if_fail (key_file != NULL, FALSE);
430   g_return_val_if_fail (data != NULL, FALSE);
431   g_return_val_if_fail (length != 0, FALSE);
432 
433   if (length == (gsize)-1)
434     length = strlen (data);
435 
436   if (key_file->approximate_size > 0)
437     {
438       g_key_file_clear (key_file);
439       g_key_file_init (key_file);
440     }
441   key_file->flags = flags;
442 
443   g_key_file_parse_data (key_file, data, length, &key_file_error);
444 
445   if (key_file_error)
446     {
447       g_propagate_error (error, key_file_error);
448       return FALSE;
449     }
450 
451   g_key_file_flush_parse_buffer (key_file, &key_file_error);
452 
453   if (key_file_error)
454     {
455       g_propagate_error (error, key_file_error);
456       return FALSE;
457     }
458 
459   return TRUE;
460 }
461 
462 /**
463  * g_key_file_free:
464  * @key_file: a #GKeyFile
465  *
466  * Frees a #GKeyFile.
467  *
468  * Since: 2.6
469  **/
470 void
g_key_file_free(GKeyFile * key_file)471 g_key_file_free (GKeyFile *key_file)
472 {
473   g_return_if_fail (key_file != NULL);
474 
475   g_key_file_clear (key_file);
476   g_free (key_file);
477 }
478 
479 /* If G_KEY_FILE_KEEP_TRANSLATIONS is not set, only returns
480  * true for locales that match those in g_get_language_names().
481  */
482 static gboolean
g_key_file_locale_is_interesting(GKeyFile * key_file,const gchar * locale)483 g_key_file_locale_is_interesting (GKeyFile    *key_file,
484 				  const gchar *locale)
485 {
486   if (key_file->flags & G_KEY_FILE_KEEP_TRANSLATIONS)
487     return TRUE;
488 
489   return FALSE;
490 }
491 
492 static gchar *
_g_utf8_make_valid(const gchar * name)493 _g_utf8_make_valid (const gchar *name)
494 {
495   GString *string;
496   const gchar *remainder, *invalid;
497   gint remaining_bytes, valid_bytes;
498 
499   string = NULL;
500   remainder = name;
501   remaining_bytes = strlen (name);
502 
503   while (remaining_bytes != 0)
504     {
505       if (g_utf8_validate (remainder, remaining_bytes, &invalid))
506 	break;
507       valid_bytes = invalid - remainder;
508 
509       if (string == NULL)
510 	string = g_string_sized_new (remaining_bytes);
511 
512       g_string_append_len (string, remainder, valid_bytes);
513       /* append U+FFFD REPLACEMENT CHARACTER */
514       g_string_append (string, "\357\277\275");
515 
516       remaining_bytes -= valid_bytes + 1;
517       remainder = invalid + 1;
518     }
519 
520   if (string == NULL)
521     return g_strdup (name);
522 
523   g_string_append (string, remainder);
524 
525   g_assert (g_utf8_validate (string->str, -1, NULL));
526 
527   return g_string_free (string, FALSE);
528 }
529 
530 static void
g_key_file_parse_line(GKeyFile * key_file,const gchar * line,gsize length,GError ** error)531 g_key_file_parse_line (GKeyFile     *key_file,
532 		       const gchar  *line,
533 		       gsize         length,
534 		       GError      **error)
535 {
536   GError *parse_error = NULL;
537   gchar *line_start;
538 
539   g_return_if_fail (key_file != NULL);
540   g_return_if_fail (line != NULL);
541 
542   line_start = (gchar *) line;
543   while (g_ascii_isspace (*line_start))
544     line_start++;
545 
546   if (g_key_file_line_is_comment (line_start))
547     g_key_file_parse_comment (key_file, line, length, &parse_error);
548   else if (g_key_file_line_is_group (line_start))
549     g_key_file_parse_group (key_file, line_start,
550 			    length - (line_start - line),
551 			    &parse_error);
552   else if (g_key_file_line_is_key_value_pair (line_start))
553     g_key_file_parse_key_value_pair (key_file, line_start,
554 				     length - (line_start - line),
555 				     &parse_error);
556   else
557     {
558       gchar *line_utf8 = _g_utf8_make_valid (line);
559       g_set_error (error, G_KEY_FILE_ERROR,
560                    G_KEY_FILE_ERROR_PARSE,
561                    _("Key file contains line '%s' which is not "
562                      "a key-value pair, group, or comment"),
563 		   line_utf8);
564       g_free (line_utf8);
565 
566       return;
567     }
568 
569   if (parse_error)
570     g_propagate_error (error, parse_error);
571 }
572 
573 static void
g_key_file_parse_comment(GKeyFile * key_file,const gchar * line,gsize length,GError ** error)574 g_key_file_parse_comment (GKeyFile     *key_file,
575 			  const gchar  *line,
576 			  gsize         length,
577 			  GError      **error)
578 {
579   GKeyFileKeyValuePair *pair;
580 
581   if (!(key_file->flags & G_KEY_FILE_KEEP_COMMENTS))
582     return;
583 
584   g_assert (key_file->current_group != NULL);
585 
586   pair = g_new0 (GKeyFileKeyValuePair, 1);
587 
588   pair->key = NULL;
589   pair->value = g_strndup (line, length);
590 
591   key_file->current_group->key_value_pairs =
592     g_list_prepend (key_file->current_group->key_value_pairs, pair);
593 }
594 
595 static void
g_key_file_parse_group(GKeyFile * key_file,const gchar * line,gsize length,GError ** error)596 g_key_file_parse_group (GKeyFile     *key_file,
597 			const gchar  *line,
598 			gsize         length,
599 			GError      **error)
600 {
601   gchar *group_name;
602   const gchar *group_name_start, *group_name_end;
603 
604   /* advance past opening '['
605    */
606   group_name_start = line + 1;
607   group_name_end = line + length - 1;
608 
609   while (*group_name_end != ']')
610     group_name_end--;
611 
612   group_name = g_strndup (group_name_start,
613                           group_name_end - group_name_start);
614 
615   if (!g_key_file_is_group_name (group_name))
616     {
617       g_set_error (error, G_KEY_FILE_ERROR,
618 		   G_KEY_FILE_ERROR_PARSE,
619 		   _("Invalid group name: %s"), group_name);
620       g_free (group_name);
621       return;
622     }
623 
624   g_key_file_add_group (key_file, group_name);
625   g_free (group_name);
626 }
627 
628 static void
g_key_file_parse_key_value_pair(GKeyFile * key_file,const gchar * line,gsize length,GError ** error)629 g_key_file_parse_key_value_pair (GKeyFile     *key_file,
630 				 const gchar  *line,
631 				 gsize         length,
632 				 GError      **error)
633 {
634   gchar *key, *value, *key_end, *value_start, *locale;
635   gsize key_len, value_len;
636 
637   if (key_file->current_group == NULL || key_file->current_group->name == NULL)
638     {
639       g_set_error (error, G_KEY_FILE_ERROR,
640 		   G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
641 		   _("Key file does not start with a group"));
642       return;
643     }
644 
645   key_end = value_start = strchr (line, '=');
646 
647   g_assert (key_end != NULL);
648 
649   key_end--;
650   value_start++;
651 
652   /* Pull the key name from the line (chomping trailing whitespace)
653    */
654   while (g_ascii_isspace (*key_end))
655     key_end--;
656 
657   key_len = key_end - line + 2;
658 
659   g_assert (key_len <= length);
660 
661   key = g_strndup (line, key_len - 1);
662 
663   if (!g_key_file_is_key_name (key))
664     {
665       g_set_error (error, G_KEY_FILE_ERROR,
666                    G_KEY_FILE_ERROR_PARSE,
667                    _("Invalid key name: %s"), key);
668       g_free (key);
669       return;
670     }
671 
672   /* Pull the value from the line (chugging leading whitespace)
673    */
674   while (g_ascii_isspace (*value_start))
675     value_start++;
676 
677   value_len = line + length - value_start + 1;
678 
679   value = g_strndup (value_start, value_len);
680 
681   g_assert (key_file->start_group != NULL);
682 
683   if (key_file->current_group
684       && key_file->current_group->name
685       && strcmp (key_file->start_group->name,
686                  key_file->current_group->name) == 0
687       && strcmp (key, "Encoding") == 0)
688     {
689       if (g_ascii_strcasecmp (value, "UTF-8") != 0)
690         {
691 	  gchar *value_utf8 = _g_utf8_make_valid (value);
692           g_set_error (error, G_KEY_FILE_ERROR,
693                        G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
694                        _("Key file contains unsupported "
695 			 "encoding '%s'"), value_utf8);
696 	  g_free (value_utf8);
697 
698           g_free (key);
699           g_free (value);
700           return;
701         }
702     }
703 
704   /* Is this key a translation? If so, is it one that we care about?
705    */
706   locale = key_get_locale (key);
707 
708   if (locale == NULL || g_key_file_locale_is_interesting (key_file, locale))
709     g_key_file_add_key (key_file, key_file->current_group, key, value);
710 
711   g_free (locale);
712   g_free (key);
713   g_free (value);
714 }
715 
716 static gchar *
key_get_locale(const gchar * key)717 key_get_locale (const gchar *key)
718 {
719   gchar *locale;
720 
721   locale = g_strrstr (key, "[");
722 
723   if (locale && strlen (locale) <= 2)
724     locale = NULL;
725 
726   if (locale)
727     locale = g_strndup (locale + 1, strlen (locale) - 2);
728 
729   return locale;
730 }
731 
732 static void
g_key_file_parse_data(GKeyFile * key_file,const gchar * data,gsize length,GError ** error)733 g_key_file_parse_data (GKeyFile     *key_file,
734 		       const gchar  *data,
735 		       gsize         length,
736 		       GError      **error)
737 {
738   GError *parse_error;
739   gsize i;
740 
741   g_return_if_fail (key_file != NULL);
742   g_return_if_fail (data != NULL);
743 
744   parse_error = NULL;
745 
746   for (i = 0; i < length; i++)
747     {
748       if (data[i] == '\n')
749         {
750 	  if (i > 0 && data[i - 1] == '\r')
751 	    g_string_erase (key_file->parse_buffer,
752 			    key_file->parse_buffer->len - 1,
753 			    1);
754 
755           /* When a newline is encountered flush the parse buffer so that the
756            * line can be parsed.  Note that completely blank lines won't show
757            * up in the parse buffer, so they get parsed directly.
758            */
759           if (key_file->parse_buffer->len > 0)
760             g_key_file_flush_parse_buffer (key_file, &parse_error);
761           else
762             g_key_file_parse_comment (key_file, "", 1, &parse_error);
763 
764           if (parse_error)
765             {
766               g_propagate_error (error, parse_error);
767               return;
768             }
769         }
770       else
771         g_string_append_c (key_file->parse_buffer, data[i]);
772     }
773 
774   key_file->approximate_size += length;
775 }
776 
777 static void
g_key_file_flush_parse_buffer(GKeyFile * key_file,GError ** error)778 g_key_file_flush_parse_buffer (GKeyFile  *key_file,
779 			       GError   **error)
780 {
781   GError *file_error = NULL;
782 
783   g_return_if_fail (key_file != NULL);
784 
785   file_error = NULL;
786 
787   if (key_file->parse_buffer->len > 0)
788     {
789       g_key_file_parse_line (key_file, key_file->parse_buffer->str,
790 			     key_file->parse_buffer->len,
791 			     &file_error);
792       g_string_erase (key_file->parse_buffer, 0, -1);
793 
794       if (file_error)
795         {
796           g_propagate_error (error, file_error);
797           return;
798         }
799     }
800 }
801 
802 /**
803  * g_key_file_to_data:
804  * @key_file: a #GKeyFile
805  * @length: return location for the length of the
806  *   returned string, or %NULL
807  * @error: return location for a #GError, or %NULL
808  *
809  * This function outputs @key_file as a string.
810  *
811  * Return value: a newly allocated string holding
812  *   the contents of the #GKeyFile
813  *
814  * Since: 2.6
815  **/
816 gchar *
g_key_file_to_data(GKeyFile * key_file,gsize * length,GError ** error)817 g_key_file_to_data (GKeyFile  *key_file,
818 		    gsize     *length,
819 		    GError   **error)
820 {
821   GString *data_string;
822   GList *group_node, *key_file_node;
823 
824   g_return_val_if_fail (key_file != NULL, NULL);
825 
826   data_string = g_string_sized_new (2 * key_file->approximate_size);
827 
828   for (group_node = g_list_last (key_file->groups);
829        group_node != NULL;
830        group_node = group_node->prev)
831     {
832       GKeyFileGroup *group;
833 
834       group = (GKeyFileGroup *) group_node->data;
835 
836       if (group->comment != NULL)
837         g_string_append_printf (data_string, "%s\n", group->comment->value);
838       else if (group_node->next) /* separate groups by at least an empty line */
839         g_string_append_c (data_string, '\n');
840 
841       if (group->name != NULL)
842         g_string_append_printf (data_string, "[%s]\n", group->name);
843 
844       for (key_file_node = g_list_last (group->key_value_pairs);
845            key_file_node != NULL;
846            key_file_node = key_file_node->prev)
847         {
848           GKeyFileKeyValuePair *pair;
849 
850           pair = (GKeyFileKeyValuePair *) key_file_node->data;
851 
852           if (pair->key != NULL)
853             g_string_append_printf (data_string, "%s=%s\n", pair->key, pair->value);
854           else
855             g_string_append_printf (data_string, "%s\n", pair->value);
856         }
857     }
858 
859   if (length)
860     *length = data_string->len;
861 
862   return g_string_free (data_string, FALSE);
863 }
864 
865 /**
866  * g_key_file_get_keys:
867  * @key_file: a #GKeyFile
868  * @group_name: a group name
869  * @length: return location for the number of keys returned, or %NULL
870  * @error: return location for a #GError, or %NULL
871  *
872  * Returns all keys for the group name @group_name.  The array of
873  * returned keys will be %NULL-terminated, so @length may
874  * optionally be %NULL. In the event that the @group_name cannot
875  * be found, %NULL is returned and @error is set to
876  * #G_KEY_FILE_ERROR_GROUP_NOT_FOUND.
877  *
878  * Return value: a newly-allocated %NULL-terminated array of
879  * strings. Use g_strfreev() to free it.
880  *
881  * Since: 2.6
882  **/
883 gchar **
g_key_file_get_keys(GKeyFile * key_file,const gchar * group_name,gsize * length,GError ** error)884 g_key_file_get_keys (GKeyFile     *key_file,
885 		     const gchar  *group_name,
886 		     gsize        *length,
887 		     GError      **error)
888 {
889   GKeyFileGroup *group;
890   GList *tmp;
891   gchar **keys;
892   gsize i, num_keys;
893 
894   g_return_val_if_fail (key_file != NULL, NULL);
895   g_return_val_if_fail (group_name != NULL, NULL);
896 
897   group = g_key_file_lookup_group (key_file, group_name);
898 
899   if (!group)
900     {
901       g_set_error (error, G_KEY_FILE_ERROR,
902                    G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
903                    _("Key file does not have group '%s'"),
904                    group_name ? group_name : "(null)");
905       return NULL;
906     }
907 
908   num_keys = 0;
909   for (tmp = group->key_value_pairs; tmp; tmp = tmp->next)
910     {
911       GKeyFileKeyValuePair *pair;
912 
913       pair = (GKeyFileKeyValuePair *) tmp->data;
914 
915       if (pair->key)
916 	num_keys++;
917     }
918 
919   keys = g_new0 (gchar *, num_keys + 1);
920 
921   i = num_keys - 1;
922   for (tmp = group->key_value_pairs; tmp; tmp = tmp->next)
923     {
924       GKeyFileKeyValuePair *pair;
925 
926       pair = (GKeyFileKeyValuePair *) tmp->data;
927 
928       if (pair->key)
929 	{
930 	  keys[i] = g_strdup (pair->key);
931 	  i--;
932 	}
933     }
934 
935   keys[num_keys] = NULL;
936 
937   if (length)
938     *length = num_keys;
939 
940   return keys;
941 }
942 
943 /**
944  * g_key_file_get_start_group:
945  * @key_file: a #GKeyFile
946  *
947  * Returns the name of the start group of the file.
948  *
949  * Return value: The start group of the key file.
950  *
951  * Since: 2.6
952  **/
953 gchar *
g_key_file_get_start_group(GKeyFile * key_file)954 g_key_file_get_start_group (GKeyFile *key_file)
955 {
956   g_return_val_if_fail (key_file != NULL, NULL);
957 
958   if (key_file->start_group)
959     return g_strdup (key_file->start_group->name);
960 
961   return NULL;
962 }
963 
964 /**
965  * g_key_file_get_groups:
966  * @key_file: a #GKeyFile
967  * @length: return location for the number of returned groups, or %NULL
968  *
969  * Returns all groups in the key file loaded with @key_file.  The
970  * array of returned groups will be %NULL-terminated, so @length may
971  * optionally be %NULL.
972  *
973  * Return value: a newly-allocated %NULL-terminated array of strings.
974  *   Use g_strfreev() to free it.
975  * Since: 2.6
976  **/
977 gchar **
g_key_file_get_groups(GKeyFile * key_file,gsize * length)978 g_key_file_get_groups (GKeyFile *key_file,
979 		       gsize    *length)
980 {
981   GList *group_node;
982   gchar **groups;
983   gsize i, num_groups;
984 
985   g_return_val_if_fail (key_file != NULL, NULL);
986 
987   num_groups = g_list_length (key_file->groups);
988 
989   g_assert (num_groups > 0);
990 
991   /* Only need num_groups instead of num_groups + 1
992    * because the first group of the file (last in the
993    * list) is always the comment group at the top,
994    * which we skip
995    */
996   groups = g_new0 (gchar *, num_groups);
997 
998   group_node = g_list_last (key_file->groups);
999 
1000   g_assert (((GKeyFileGroup *) group_node->data)->name == NULL);
1001 
1002   i = 0;
1003   for (group_node = group_node->prev;
1004        group_node != NULL;
1005        group_node = group_node->prev)
1006     {
1007       GKeyFileGroup *group;
1008 
1009       group = (GKeyFileGroup *) group_node->data;
1010 
1011       g_assert (group->name != NULL);
1012 
1013       groups[i++] = g_strdup (group->name);
1014     }
1015   groups[i] = NULL;
1016 
1017   if (length)
1018     *length = i;
1019 
1020   return groups;
1021 }
1022 
1023 /**
1024  * g_key_file_get_value:
1025  * @key_file: a #GKeyFile
1026  * @group_name: a group name
1027  * @key: a key
1028  * @error: return location for a #GError, or %NULL
1029  *
1030  * Returns the value associated with @key under @group_name.
1031  *
1032  * In the event the key cannot be found, %NULL is returned and
1033  * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND.  In the
1034  * event that the @group_name cannot be found, %NULL is returned
1035  * and @error is set to #G_KEY_FILE_ERROR_GROUP_NOT_FOUND.
1036  *
1037  * Return value: a newly allocated string or %NULL if the specified
1038  *  key cannot be found.
1039  *
1040  * Since: 2.6
1041  **/
1042 gchar *
g_key_file_get_value(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)1043 g_key_file_get_value (GKeyFile     *key_file,
1044 		      const gchar  *group_name,
1045 		      const gchar  *key,
1046 		      GError      **error)
1047 {
1048   GKeyFileGroup *group;
1049   GKeyFileKeyValuePair *pair;
1050   gchar *value = NULL;
1051 
1052   g_return_val_if_fail (key_file != NULL, NULL);
1053   g_return_val_if_fail (group_name != NULL, NULL);
1054   g_return_val_if_fail (key != NULL, NULL);
1055 
1056   group = g_key_file_lookup_group (key_file, group_name);
1057 
1058   if (!group)
1059     {
1060       g_set_error (error, G_KEY_FILE_ERROR,
1061                    G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
1062                    _("Key file does not have group '%s'"),
1063                    group_name ? group_name : "(null)");
1064       return NULL;
1065     }
1066 
1067   pair = g_key_file_lookup_key_value_pair (key_file, group, key);
1068 
1069   if (pair)
1070     value = g_strdup (pair->value);
1071   else
1072     g_set_error (error, G_KEY_FILE_ERROR,
1073                  G_KEY_FILE_ERROR_KEY_NOT_FOUND,
1074                  _("Key file does not have key '%s'"), key);
1075 
1076   return value;
1077 }
1078 
1079 /**
1080  * g_key_file_set_value:
1081  * @key_file: a #GKeyFile
1082  * @group_name: a group name
1083  * @key: a key
1084  * @value: a string
1085  *
1086  * Associates a new value with @key under @group_name.  If @key
1087  * cannot be found then it is created. If @group_name cannot be
1088  * found then it is created.
1089  *
1090  * Since: 2.6
1091  **/
1092 void
g_key_file_set_value(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * value)1093 g_key_file_set_value (GKeyFile    *key_file,
1094 		      const gchar *group_name,
1095 		      const gchar *key,
1096 		      const gchar *value)
1097 {
1098   GKeyFileGroup *group;
1099   GKeyFileKeyValuePair *pair;
1100 
1101   g_return_if_fail (key_file != NULL);
1102   g_return_if_fail (g_key_file_is_group_name (group_name));
1103   g_return_if_fail (g_key_file_is_key_name (key));
1104   g_return_if_fail (value != NULL);
1105 
1106   group = g_key_file_lookup_group (key_file, group_name);
1107 
1108   if (!group)
1109     {
1110       g_key_file_add_group (key_file, group_name);
1111       group = (GKeyFileGroup *) key_file->groups->data;
1112 
1113       g_key_file_add_key (key_file, group, key, value);
1114     }
1115   else
1116     {
1117       pair = g_key_file_lookup_key_value_pair (key_file, group, key);
1118 
1119       if (!pair)
1120         g_key_file_add_key (key_file, group, key, value);
1121       else
1122         {
1123           g_free (pair->value);
1124           pair->value = g_strdup (value);
1125         }
1126     }
1127 }
1128 
1129 /**
1130  * g_key_file_get_string:
1131  * @key_file: a #GKeyFile
1132  * @group_name: a group name
1133  * @key: a key
1134  * @error: return location for a #GError, or %NULL
1135  *
1136  * Returns the value associated with @key under @group_name.
1137  *
1138  * In the event the key cannot be found, %NULL is returned and
1139  * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND.  In the
1140  * event that the @group_name cannot be found, %NULL is returned
1141  * and @error is set to #G_KEY_FILE_ERROR_GROUP_NOT_FOUND.
1142  *
1143  * Return value: a newly allocated string or %NULL if the specified
1144  *   key cannot be found.
1145  *
1146  * Since: 2.6
1147  **/
1148 gchar *
g_key_file_get_string(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)1149 g_key_file_get_string (GKeyFile     *key_file,
1150 		       const gchar  *group_name,
1151 		       const gchar  *key,
1152 		       GError      **error)
1153 {
1154   gchar *value, *string_value;
1155   GError *key_file_error;
1156 
1157   g_return_val_if_fail (key_file != NULL, NULL);
1158   g_return_val_if_fail (group_name != NULL, NULL);
1159   g_return_val_if_fail (key != NULL, NULL);
1160 
1161   key_file_error = NULL;
1162 
1163   value = g_key_file_get_value (key_file, group_name, key, &key_file_error);
1164 
1165   if (key_file_error)
1166     {
1167       g_propagate_error (error, key_file_error);
1168       return NULL;
1169     }
1170 
1171   if (!g_utf8_validate (value, -1, NULL))
1172     {
1173       gchar *value_utf8 = _g_utf8_make_valid (value);
1174       g_set_error (error, G_KEY_FILE_ERROR,
1175                    G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
1176                    _("Key file contains key '%s' with value '%s' "
1177                      "which is not UTF-8"), key, value_utf8);
1178       g_free (value_utf8);
1179       g_free (value);
1180 
1181       return NULL;
1182     }
1183 
1184   string_value = g_key_file_parse_value_as_string (key_file, value, NULL,
1185 						   &key_file_error);
1186   g_free (value);
1187 
1188   if (key_file_error)
1189     {
1190       if (g_error_matches (key_file_error,
1191                            G_KEY_FILE_ERROR,
1192                            G_KEY_FILE_ERROR_INVALID_VALUE))
1193         {
1194           g_set_error (error, G_KEY_FILE_ERROR,
1195                        G_KEY_FILE_ERROR_INVALID_VALUE,
1196                        _("Key file contains key '%s' "
1197                          "which has value that cannot be interpreted."),
1198                        key);
1199           g_error_free (key_file_error);
1200         }
1201       else
1202         g_propagate_error (error, key_file_error);
1203     }
1204 
1205   return string_value;
1206 }
1207 
1208 /**
1209  * g_key_file_set_string:
1210  * @key_file: a #GKeyFile
1211  * @group_name: a group name
1212  * @key: a key
1213  * @string: a string
1214  *
1215  * Associates a new string value with @key under @group_name.  If
1216  * @key cannot be found then it is created.  If @group_name
1217  * cannot be found then it is created.
1218  *
1219  * Since: 2.6
1220  **/
1221 void
g_key_file_set_string(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * string)1222 g_key_file_set_string (GKeyFile    *key_file,
1223 		       const gchar *group_name,
1224 		       const gchar *key,
1225 		       const gchar *string)
1226 {
1227   gchar *value;
1228 
1229   g_return_if_fail (key_file != NULL);
1230   g_return_if_fail (string != NULL);
1231 
1232   value = g_key_file_parse_string_as_value (key_file, string, FALSE);
1233   g_key_file_set_value (key_file, group_name, key, value);
1234   g_free (value);
1235 }
1236 
1237 /**
1238  * g_key_file_get_string_list:
1239  * @key_file: a #GKeyFile
1240  * @group_name: a group name
1241  * @key: a key
1242  * @length: return location for the number of returned strings, or %NULL
1243  * @error: return location for a #GError, or %NULL
1244  *
1245  * Returns the values associated with @key under @group_name.
1246  *
1247  * In the event the key cannot be found, %NULL is returned and
1248  * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND.  In the
1249  * event that the @group_name cannot be found, %NULL is returned
1250  * and @error is set to #G_KEY_FILE_ERROR_GROUP_NOT_FOUND.
1251  *
1252  * Return value: a %NULL-terminated string array or %NULL if the specified
1253  *   key cannot be found. The array should be freed with g_strfreev().
1254  *
1255  * Since: 2.6
1256  **/
1257 gchar **
g_key_file_get_string_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gsize * length,GError ** error)1258 g_key_file_get_string_list (GKeyFile     *key_file,
1259 			    const gchar  *group_name,
1260 			    const gchar  *key,
1261 			    gsize        *length,
1262 			    GError      **error)
1263 {
1264   GError *key_file_error = NULL;
1265   gchar *value, *string_value, **values;
1266   gint i, len;
1267   GSList *p, *pieces = NULL;
1268 
1269   g_return_val_if_fail (key_file != NULL, NULL);
1270   g_return_val_if_fail (group_name != NULL, NULL);
1271   g_return_val_if_fail (key != NULL, NULL);
1272 
1273   value = g_key_file_get_value (key_file, group_name, key, &key_file_error);
1274 
1275   if (key_file_error)
1276     {
1277       g_propagate_error (error, key_file_error);
1278       return NULL;
1279     }
1280 
1281   if (!g_utf8_validate (value, -1, NULL))
1282     {
1283       gchar *value_utf8 = _g_utf8_make_valid (value);
1284       g_set_error (error, G_KEY_FILE_ERROR,
1285                    G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
1286                    _("Key file contains key '%s' with value '%s' "
1287                      "which is not UTF-8"), key, value_utf8);
1288       g_free (value_utf8);
1289       g_free (value);
1290 
1291       return NULL;
1292     }
1293 
1294   string_value = g_key_file_parse_value_as_string (key_file, value, &pieces, &key_file_error);
1295   g_free (value);
1296   g_free (string_value);
1297 
1298   if (key_file_error)
1299     {
1300       if (g_error_matches (key_file_error,
1301                            G_KEY_FILE_ERROR,
1302                            G_KEY_FILE_ERROR_INVALID_VALUE))
1303         {
1304           g_set_error (error, G_KEY_FILE_ERROR,
1305                        G_KEY_FILE_ERROR_INVALID_VALUE,
1306                        _("Key file contains key '%s' "
1307                          "which has value that cannot be interpreted."),
1308                        key);
1309           g_error_free (key_file_error);
1310         }
1311       else
1312         g_propagate_error (error, key_file_error);
1313     }
1314 
1315   len = g_slist_length (pieces);
1316   values = g_new0 (gchar *, len + 1);
1317   for (p = pieces, i = 0; p; p = p->next)
1318     values[i++] = p->data;
1319   values[len] = NULL;
1320 
1321   g_slist_free (pieces);
1322 
1323   if (length)
1324     *length = len;
1325 
1326   return values;
1327 }
1328 
1329 /**
1330  * g_key_file_set_string_list:
1331  * @key_file: a #GKeyFile
1332  * @group_name: a group name
1333  * @key: a key
1334  * @list: an array of locale string values
1335  * @length: number of locale string values in @list
1336  *
1337  * Associates a list of string values for @key under @group_name.
1338  * If @key cannot be found then it is created.  If @group_name
1339  * cannot be found then it is created.
1340  *
1341  * Since: 2.6
1342  **/
1343 void
g_key_file_set_string_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * const list[],gsize length)1344 g_key_file_set_string_list (GKeyFile            *key_file,
1345 			    const gchar         *group_name,
1346 			    const gchar         *key,
1347 			    const gchar * const  list[],
1348 			    gsize                length)
1349 {
1350   GString *value_list;
1351   gsize i;
1352 
1353   g_return_if_fail (key_file != NULL);
1354   g_return_if_fail (list != NULL);
1355 
1356   value_list = g_string_sized_new (length * 128);
1357   for (i = 0; i < length && list[i] != NULL; i++)
1358     {
1359       gchar *value;
1360 
1361       value = g_key_file_parse_string_as_value (key_file, list[i], TRUE);
1362       g_string_append (value_list, value);
1363       g_string_append_c (value_list, key_file->list_separator);
1364 
1365       g_free (value);
1366     }
1367 
1368   g_key_file_set_value (key_file, group_name, key, value_list->str);
1369   g_string_free (value_list, TRUE);
1370 }
1371 
1372 /**
1373  * g_key_file_set_locale_string:
1374  * @key_file: a #GKeyFile
1375  * @group_name: a group name
1376  * @key: a key
1377  * @locale: a locale
1378  * @string: a string
1379  *
1380  * Associates a string value for @key and @locale under
1381  * @group_name.  If the translation for @key cannot be found
1382  * then it is created.
1383  *
1384  * Since: 2.6
1385  **/
1386 void
g_key_file_set_locale_string(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * locale,const gchar * string)1387 g_key_file_set_locale_string (GKeyFile     *key_file,
1388 			      const gchar  *group_name,
1389 			      const gchar  *key,
1390 			      const gchar  *locale,
1391 			      const gchar  *string)
1392 {
1393   gchar *full_key, *value;
1394 
1395   g_return_if_fail (key_file != NULL);
1396   g_return_if_fail (key != NULL);
1397   g_return_if_fail (locale != NULL);
1398   g_return_if_fail (string != NULL);
1399 
1400   value = g_key_file_parse_string_as_value (key_file, string, FALSE);
1401   full_key = g_strdup_printf ("%s[%s]", key, locale);
1402   g_key_file_set_value (key_file, group_name, full_key, value);
1403   g_free (full_key);
1404   g_free (value);
1405 }
1406 
1407 extern GSList *_g_compute_locale_variants (const gchar *locale);
1408 
1409 /**
1410  * g_key_file_set_locale_string_list:
1411  * @key_file: a #GKeyFile
1412  * @group_name: a group name
1413  * @key: a key
1414  * @locale: a locale
1415  * @list: a %NULL-terminated array of locale string values
1416  * @length: the length of @list
1417  *
1418  * Associates a list of string values for @key and @locale under
1419  * @group_name.  If the translation for @key cannot be found then
1420  * it is created.
1421  *
1422  * Since: 2.6
1423  **/
1424 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)1425 g_key_file_set_locale_string_list (GKeyFile            *key_file,
1426 				   const gchar         *group_name,
1427 				   const gchar         *key,
1428 				   const gchar         *locale,
1429 				   const gchar * const  list[],
1430 				   gsize                length)
1431 {
1432   GString *value_list;
1433   gchar *full_key;
1434   gsize i;
1435 
1436   g_return_if_fail (key_file != NULL);
1437   g_return_if_fail (key != NULL);
1438   g_return_if_fail (locale != NULL);
1439   g_return_if_fail (length != 0);
1440 
1441   value_list = g_string_sized_new (length * 128);
1442   for (i = 0; i < length && list[i] != NULL; i++)
1443     {
1444       gchar *value;
1445 
1446       value = g_key_file_parse_string_as_value (key_file, list[i], TRUE);
1447 
1448       g_string_append (value_list, value);
1449       g_string_append_c (value_list, ';');
1450 
1451       g_free (value);
1452     }
1453 
1454   full_key = g_strdup_printf ("%s[%s]", key, locale);
1455   g_key_file_set_value (key_file, group_name, full_key, value_list->str);
1456   g_free (full_key);
1457   g_string_free (value_list, TRUE);
1458 }
1459 
1460 /**
1461  * g_key_file_get_boolean:
1462  * @key_file: a #GKeyFile
1463  * @group_name: a group name
1464  * @key: a key
1465  * @error: return location for a #GError
1466  *
1467  * Returns the value associated with @key under @group_name as a
1468  * boolean.
1469  *
1470  * If @key cannot be found then the return value is undefined and
1471  * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if
1472  * the value associated with @key cannot be interpreted as a boolean
1473  * then the return value is also undefined and @error is set to
1474  * #G_KEY_FILE_ERROR_INVALID_VALUE.
1475  *
1476  * Return value: the value associated with the key as a boolean
1477  * Since: 2.6
1478  **/
1479 gboolean
g_key_file_get_boolean(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)1480 g_key_file_get_boolean (GKeyFile     *key_file,
1481 			const gchar  *group_name,
1482 			const gchar  *key,
1483 			GError      **error)
1484 {
1485   GError *key_file_error = NULL;
1486   gchar *value;
1487   gboolean bool_value;
1488 
1489   g_return_val_if_fail (key_file != NULL, FALSE);
1490   g_return_val_if_fail (group_name != NULL, FALSE);
1491   g_return_val_if_fail (key != NULL, FALSE);
1492 
1493   value = g_key_file_get_value (key_file, group_name, key, &key_file_error);
1494 
1495   if (!value)
1496     {
1497       g_propagate_error (error, key_file_error);
1498       return FALSE;
1499     }
1500 
1501   bool_value = g_key_file_parse_value_as_boolean (key_file, value,
1502 						  &key_file_error);
1503   g_free (value);
1504 
1505   if (key_file_error)
1506     {
1507       if (g_error_matches (key_file_error,
1508                            G_KEY_FILE_ERROR,
1509                            G_KEY_FILE_ERROR_INVALID_VALUE))
1510         {
1511           g_set_error (error, G_KEY_FILE_ERROR,
1512                        G_KEY_FILE_ERROR_INVALID_VALUE,
1513                        _("Key file contains key '%s' "
1514                          "which has value that cannot be interpreted."),
1515                        key);
1516           g_error_free (key_file_error);
1517         }
1518       else
1519         g_propagate_error (error, key_file_error);
1520     }
1521 
1522   return bool_value;
1523 }
1524 
1525 /**
1526  * g_key_file_set_boolean:
1527  * @key_file: a #GKeyFile
1528  * @group_name: a group name
1529  * @key: a key
1530  * @value: %TRUE or %FALSE
1531  *
1532  * Associates a new boolean value with @key under @group_name.
1533  * If @key cannot be found then it is created.
1534  *
1535  * Since: 2.6
1536  **/
1537 void
g_key_file_set_boolean(GKeyFile * key_file,const gchar * group_name,const gchar * key,gboolean value)1538 g_key_file_set_boolean (GKeyFile    *key_file,
1539 			const gchar *group_name,
1540 			const gchar *key,
1541 			gboolean     value)
1542 {
1543   gchar *result;
1544 
1545   g_return_if_fail (key_file != NULL);
1546 
1547   result = g_key_file_parse_boolean_as_value (key_file, value);
1548   g_key_file_set_value (key_file, group_name, key, result);
1549   g_free (result);
1550 }
1551 
1552 /**
1553  * g_key_file_get_boolean_list:
1554  * @key_file: a #GKeyFile
1555  * @group_name: a group name
1556  * @key: a key
1557  * @length: the number of booleans returned
1558  * @error: return location for a #GError
1559  *
1560  * Returns the values associated with @key under @group_name as
1561  * booleans. If @group_name is %NULL, the start_group is used.
1562  *
1563  * If @key cannot be found then the return value is undefined and
1564  * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if
1565  * the values associated with @key cannot be interpreted as booleans
1566  * then the return value is also undefined and @error is set to
1567  * #G_KEY_FILE_ERROR_INVALID_VALUE.
1568  *
1569  * Return value: the values associated with the key as a boolean
1570  *
1571  * Since: 2.6
1572  **/
1573 gboolean *
g_key_file_get_boolean_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gsize * length,GError ** error)1574 g_key_file_get_boolean_list (GKeyFile     *key_file,
1575 			     const gchar  *group_name,
1576 			     const gchar  *key,
1577 			     gsize        *length,
1578 			     GError      **error)
1579 {
1580   GError *key_file_error;
1581   gchar **values;
1582   gboolean *bool_values;
1583   gsize i, num_bools;
1584 
1585   g_return_val_if_fail (key_file != NULL, NULL);
1586   g_return_val_if_fail (group_name != NULL, NULL);
1587   g_return_val_if_fail (key != NULL, NULL);
1588 
1589   key_file_error = NULL;
1590 
1591   values = g_key_file_get_string_list (key_file, group_name, key,
1592 				       &num_bools, &key_file_error);
1593 
1594   if (key_file_error)
1595     g_propagate_error (error, key_file_error);
1596 
1597   if (!values)
1598     return NULL;
1599 
1600   bool_values = g_new0 (gboolean, num_bools);
1601 
1602   for (i = 0; i < num_bools; i++)
1603     {
1604       bool_values[i] = g_key_file_parse_value_as_boolean (key_file,
1605 							  values[i],
1606 							  &key_file_error);
1607 
1608       if (key_file_error)
1609         {
1610           g_propagate_error (error, key_file_error);
1611           g_strfreev (values);
1612           g_free (bool_values);
1613 
1614           return NULL;
1615         }
1616     }
1617   g_strfreev (values);
1618 
1619   if (length)
1620     *length = num_bools;
1621 
1622   return bool_values;
1623 }
1624 
1625 /**
1626  * g_key_file_set_boolean_list:
1627  * @key_file: a #GKeyFile
1628  * @group_name: a group name
1629  * @key: a key
1630  * @list: an array of boolean values
1631  * @length: length of @list
1632  *
1633  * Associates a list of boolean values with @key under
1634  * @group_name.  If @key cannot be found then it is created.
1635  * If @group_name is %NULL, the start_group is used.
1636  *
1637  * Since: 2.6
1638  **/
1639 void
g_key_file_set_boolean_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gboolean list[],gsize length)1640 g_key_file_set_boolean_list (GKeyFile    *key_file,
1641 			     const gchar *group_name,
1642 			     const gchar *key,
1643 			     gboolean     list[],
1644 			     gsize        length)
1645 {
1646   GString *value_list;
1647   gsize i;
1648 
1649   g_return_if_fail (key_file != NULL);
1650   g_return_if_fail (list != NULL);
1651 
1652   value_list = g_string_sized_new (length * 8);
1653   for (i = 0; i < length; i++)
1654     {
1655       gchar *value;
1656 
1657       value = g_key_file_parse_boolean_as_value (key_file, list[i]);
1658 
1659       g_string_append (value_list, value);
1660       g_string_append_c (value_list, key_file->list_separator);
1661 
1662       g_free (value);
1663     }
1664 
1665   g_key_file_set_value (key_file, group_name, key, value_list->str);
1666   g_string_free (value_list, TRUE);
1667 }
1668 
1669 /**
1670  * g_key_file_get_integer:
1671  * @key_file: a #GKeyFile
1672  * @group_name: a group name
1673  * @key: a key
1674  * @error: return location for a #GError
1675  *
1676  * Returns the value associated with @key under @group_name as an
1677  * integer. If @group_name is %NULL, the start_group is used.
1678  *
1679  * If @key cannot be found then the return value is undefined and
1680  * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if
1681  * the value associated with @key cannot be interpreted as an integer
1682  * then the return value is also undefined and @error is set to
1683  * #G_KEY_FILE_ERROR_INVALID_VALUE.
1684  *
1685  * Return value: the value associated with the key as an integer.
1686  *
1687  * Since: 2.6
1688  **/
1689 gint
g_key_file_get_integer(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)1690 g_key_file_get_integer (GKeyFile     *key_file,
1691 			const gchar  *group_name,
1692 			const gchar  *key,
1693 			GError      **error)
1694 {
1695   GError *key_file_error;
1696   gchar *value;
1697   gint int_value;
1698 
1699   g_return_val_if_fail (key_file != NULL, -1);
1700   g_return_val_if_fail (group_name != NULL, -1);
1701   g_return_val_if_fail (key != NULL, -1);
1702 
1703   key_file_error = NULL;
1704 
1705   value = g_key_file_get_value (key_file, group_name, key, &key_file_error);
1706 
1707   if (key_file_error)
1708     {
1709       g_propagate_error (error, key_file_error);
1710       return 0;
1711     }
1712 
1713   int_value = g_key_file_parse_value_as_integer (key_file, value,
1714 						 &key_file_error);
1715   g_free (value);
1716 
1717   if (key_file_error)
1718     {
1719       if (g_error_matches (key_file_error,
1720                            G_KEY_FILE_ERROR,
1721                            G_KEY_FILE_ERROR_INVALID_VALUE))
1722         {
1723           g_set_error (error, G_KEY_FILE_ERROR,
1724                        G_KEY_FILE_ERROR_INVALID_VALUE,
1725                        _("Key file contains key '%s' in group '%s' "
1726                          "which has value that cannot be interpreted."), key,
1727                        group_name);
1728           g_error_free (key_file_error);
1729         }
1730       else
1731         g_propagate_error (error, key_file_error);
1732     }
1733 
1734   return int_value;
1735 }
1736 
1737 /**
1738  * g_key_file_set_integer:
1739  * @key_file: a #GKeyFile
1740  * @group_name: a group name
1741  * @key: a key
1742  * @value: an integer value
1743  *
1744  * Associates a new integer value with @key under @group_name.
1745  * If @key cannot be found then it is created.
1746  *
1747  * Since: 2.6
1748  **/
1749 void
g_key_file_set_integer(GKeyFile * key_file,const gchar * group_name,const gchar * key,gint value)1750 g_key_file_set_integer (GKeyFile    *key_file,
1751 			const gchar *group_name,
1752 			const gchar *key,
1753 			gint         value)
1754 {
1755   gchar *result;
1756 
1757   g_return_if_fail (key_file != NULL);
1758 
1759   result = g_key_file_parse_integer_as_value (key_file, value);
1760   g_key_file_set_value (key_file, group_name, key, result);
1761   g_free (result);
1762 }
1763 
1764 /**
1765  * g_key_file_get_integer_list:
1766  * @key_file: a #GKeyFile
1767  * @group_name: a group name
1768  * @key: a key
1769  * @length: the number of integers returned
1770  * @error: return location for a #GError
1771  *
1772  * Returns the values associated with @key under @group_name as
1773  * integers.
1774  *
1775  * If @key cannot be found then the return value is undefined and
1776  * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if
1777  * the values associated with @key cannot be interpreted as integers
1778  * then the return value is also undefined and @error is set to
1779  * #G_KEY_FILE_ERROR_INVALID_VALUE.
1780  *
1781  * Return value: the values associated with the key as a integer
1782  *
1783  * Since: 2.6
1784  **/
1785 gint *
g_key_file_get_integer_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gsize * length,GError ** error)1786 g_key_file_get_integer_list (GKeyFile     *key_file,
1787 			     const gchar  *group_name,
1788 			     const gchar  *key,
1789 			     gsize        *length,
1790 			     GError      **error)
1791 {
1792   GError *key_file_error = NULL;
1793   gchar **values;
1794   gint *int_values;
1795   gsize i, num_ints;
1796 
1797   g_return_val_if_fail (key_file != NULL, NULL);
1798   g_return_val_if_fail (group_name != NULL, NULL);
1799   g_return_val_if_fail (key != NULL, NULL);
1800 
1801   values = g_key_file_get_string_list (key_file, group_name, key,
1802 				       &num_ints, &key_file_error);
1803 
1804   if (key_file_error)
1805     g_propagate_error (error, key_file_error);
1806 
1807   if (!values)
1808     return NULL;
1809 
1810   int_values = g_new0 (gint, num_ints);
1811 
1812   for (i = 0; i < num_ints; i++)
1813     {
1814       int_values[i] = g_key_file_parse_value_as_integer (key_file,
1815 							 values[i],
1816 							 &key_file_error);
1817 
1818       if (key_file_error)
1819         {
1820           g_propagate_error (error, key_file_error);
1821           g_strfreev (values);
1822           g_free (int_values);
1823 
1824           return NULL;
1825         }
1826     }
1827   g_strfreev (values);
1828 
1829   if (length)
1830     *length = num_ints;
1831 
1832   return int_values;
1833 }
1834 
1835 /**
1836  * g_key_file_set_integer_list:
1837  * @key_file: a #GKeyFile
1838  * @group_name: a group name
1839  * @key: a key
1840  * @list: an array of integer values
1841  * @length: number of integer values in @list
1842  *
1843  * Associates a list of integer values with @key under
1844  * @group_name.  If @key cannot be found then it is created.
1845  *
1846  * Since: 2.6
1847  **/
1848 void
g_key_file_set_integer_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gint list[],gsize length)1849 g_key_file_set_integer_list (GKeyFile     *key_file,
1850 			     const gchar  *group_name,
1851 			     const gchar  *key,
1852 			     gint          list[],
1853 			     gsize         length)
1854 {
1855   GString *values;
1856   gsize i;
1857 
1858   g_return_if_fail (key_file != NULL);
1859   g_return_if_fail (list != NULL);
1860 
1861   values = g_string_sized_new (length * 16);
1862   for (i = 0; i < length; i++)
1863     {
1864       gchar *value;
1865 
1866       value = g_key_file_parse_integer_as_value (key_file, list[i]);
1867 
1868       g_string_append (values, value);
1869       g_string_append_c (values, ';');
1870 
1871       g_free (value);
1872     }
1873 
1874   g_key_file_set_value (key_file, group_name, key, values->str);
1875   g_string_free (values, TRUE);
1876 }
1877 
1878 /**
1879  * g_key_file_get_double:
1880  * @key_file: a #GKeyFile
1881  * @group_name: a group name
1882  * @key: a key
1883  * @error: return location for a #GError
1884  *
1885  * Returns the value associated with @key under @group_name as an
1886  * integer. If @group_name is %NULL, the start_group is used.
1887  *
1888  * If @key cannot be found then the return value is undefined and
1889  * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if
1890  * the value associated with @key cannot be interpreted as a double
1891  * then the return value is also undefined and @error is set to
1892  * #G_KEY_FILE_ERROR_INVALID_VALUE.
1893  *
1894  * Return value: the value associated with the key as a double.
1895  *
1896  * Since: 2.12
1897  **/
1898 gdouble
g_key_file_get_double(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)1899 g_key_file_get_double  (GKeyFile     *key_file,
1900                         const gchar  *group_name,
1901                         const gchar  *key,
1902                         GError      **error)
1903 {
1904   GError *key_file_error;
1905   gchar *value;
1906   gdouble double_value;
1907 
1908   g_return_val_if_fail (key_file != NULL, -1);
1909   g_return_val_if_fail (group_name != NULL, -1);
1910   g_return_val_if_fail (key != NULL, -1);
1911 
1912   key_file_error = NULL;
1913 
1914   value = g_key_file_get_value (key_file, group_name, key, &key_file_error);
1915 
1916   if (key_file_error)
1917     {
1918       g_propagate_error (error, key_file_error);
1919       return 0;
1920     }
1921 
1922   double_value = g_key_file_parse_value_as_double (key_file, value,
1923                                                   &key_file_error);
1924   g_free (value);
1925 
1926   if (key_file_error)
1927     {
1928       if (g_error_matches (key_file_error,
1929                            G_KEY_FILE_ERROR,
1930                            G_KEY_FILE_ERROR_INVALID_VALUE))
1931         {
1932           g_set_error (error, G_KEY_FILE_ERROR,
1933                        G_KEY_FILE_ERROR_INVALID_VALUE,
1934                        _("Key file contains key '%s' in group '%s' "
1935                          "which has value that cannot be interpreted."), key,
1936                        group_name);
1937           g_error_free (key_file_error);
1938         }
1939       else
1940         g_propagate_error (error, key_file_error);
1941     }
1942 
1943   return double_value;
1944 }
1945 
1946 /**
1947  * g_key_file_set_double:
1948  * @key_file: a #GKeyFile
1949  * @group_name: a group name
1950  * @key: a key
1951  * @value: an double value
1952  *
1953  * Associates a new double value with @key under @group_name.
1954  * If @key cannot be found then it is created. If @group_name
1955  * is %NULL, the start group is used.
1956  *
1957  * Since: 2.12
1958  **/
1959 void
g_key_file_set_double(GKeyFile * key_file,const gchar * group_name,const gchar * key,gdouble value)1960 g_key_file_set_double  (GKeyFile    *key_file,
1961                         const gchar *group_name,
1962                         const gchar *key,
1963                         gdouble      value)
1964 {
1965   gchar result[G_ASCII_DTOSTR_BUF_SIZE];
1966 
1967   g_return_if_fail (key_file != NULL);
1968 
1969   g_ascii_dtostr (result, sizeof (result), value);
1970   g_key_file_set_value (key_file, group_name, key, result);
1971 }
1972 
1973 /**
1974  * g_key_file_get_double_list:
1975  * @key_file: a #GKeyFile
1976  * @group_name: a group name
1977  * @key: a key
1978  * @length: the number of doubles returned
1979  * @error: return location for a #GError
1980  *
1981  * Returns the values associated with @key under @group_name as
1982  * doubles. If @group_name is %NULL, the start group is used.
1983  *
1984  * If @key cannot be found then the return value is undefined and
1985  * @error is set to #G_KEY_FILE_ERROR_KEY_NOT_FOUND. Likewise, if
1986  * the values associated with @key cannot be interpreted as doubles
1987  * then the return value is also undefined and @error is set to
1988  * #G_KEY_FILE_ERROR_INVALID_VALUE.
1989  *
1990  * Return value: the values associated with the key as a double
1991  *
1992  * Since: 2.12
1993  **/
1994 gdouble *
g_key_file_get_double_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gsize * length,GError ** error)1995 g_key_file_get_double_list  (GKeyFile     *key_file,
1996                              const gchar  *group_name,
1997                              const gchar  *key,
1998                              gsize        *length,
1999                              GError      **error)
2000 {
2001   GError *key_file_error = NULL;
2002   gchar **values;
2003   gdouble *double_values;
2004   gsize i, num_doubles;
2005 
2006   g_return_val_if_fail (key_file != NULL, NULL);
2007   g_return_val_if_fail (group_name != NULL, NULL);
2008   g_return_val_if_fail (key != NULL, NULL);
2009 
2010   values = g_key_file_get_string_list (key_file, group_name, key,
2011                                        &num_doubles, &key_file_error);
2012 
2013   if (key_file_error)
2014     g_propagate_error (error, key_file_error);
2015 
2016   if (!values)
2017     return NULL;
2018 
2019   double_values = g_new0 (gdouble, num_doubles);
2020 
2021   for (i = 0; i < num_doubles; i++)
2022     {
2023       double_values[i] = g_key_file_parse_value_as_double (key_file,
2024 							   values[i],
2025 							   &key_file_error);
2026 
2027       if (key_file_error)
2028         {
2029           g_propagate_error (error, key_file_error);
2030           g_strfreev (values);
2031           g_free (double_values);
2032 
2033           return NULL;
2034         }
2035     }
2036   g_strfreev (values);
2037 
2038   if (length)
2039     *length = num_doubles;
2040 
2041   return double_values;
2042 }
2043 
2044 /**
2045  * g_key_file_set_double_list:
2046  * @key_file: a #GKeyFile
2047  * @group_name: a group name
2048  * @key: a key
2049  * @list: an array of double values
2050  * @length: number of double values in @list
2051  *
2052  * Associates a list of double values with @key under
2053  * @group_name.  If @key cannot be found then it is created.
2054  * If @group_name is %NULL the start group is used.
2055  *
2056  * Since: 2.12
2057  **/
2058 void
g_key_file_set_double_list(GKeyFile * key_file,const gchar * group_name,const gchar * key,gdouble list[],gsize length)2059 g_key_file_set_double_list (GKeyFile     *key_file,
2060 			    const gchar  *group_name,
2061 			    const gchar  *key,
2062 			    gdouble       list[],
2063 			    gsize         length)
2064 {
2065   GString *values;
2066   gsize i;
2067 
2068   g_return_if_fail (key_file != NULL);
2069   g_return_if_fail (list != NULL);
2070 
2071   values = g_string_sized_new (length * 16);
2072   for (i = 0; i < length; i++)
2073     {
2074       gchar result[G_ASCII_DTOSTR_BUF_SIZE];
2075 
2076       g_ascii_dtostr( result, sizeof (result), list[i] );
2077 
2078       g_string_append (values, result);
2079       g_string_append_c (values, ';');
2080     }
2081 
2082   g_key_file_set_value (key_file, group_name, key, values->str);
2083   g_string_free (values, TRUE);
2084 }
2085 
2086 static void
g_key_file_set_key_comment(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * comment,GError ** error)2087 g_key_file_set_key_comment (GKeyFile             *key_file,
2088                             const gchar          *group_name,
2089                             const gchar          *key,
2090                             const gchar          *comment,
2091                             GError              **error)
2092 {
2093   GKeyFileGroup *group;
2094   GKeyFileKeyValuePair *pair;
2095   GList *key_node, *comment_node, *tmp;
2096 
2097   group = g_key_file_lookup_group (key_file, group_name);
2098   if (!group)
2099     {
2100       g_set_error (error, G_KEY_FILE_ERROR,
2101                    G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
2102                    _("Key file does not have group '%s'"),
2103                    group_name ? group_name : "(null)");
2104 
2105       return;
2106     }
2107 
2108   /* First find the key the comments are supposed to be
2109    * associated with
2110    */
2111   key_node = g_key_file_lookup_key_value_pair_node (key_file, group, key);
2112 
2113   if (key_node == NULL)
2114     {
2115       g_set_error (error, G_KEY_FILE_ERROR,
2116                    G_KEY_FILE_ERROR_KEY_NOT_FOUND,
2117                    _("Key file does not have key '%s' in group '%s'"),
2118                    key, group->name);
2119       return;
2120     }
2121 
2122   /* Then find all the comments already associated with the
2123    * key and free them
2124    */
2125   tmp = key_node->next;
2126   while (tmp != NULL)
2127     {
2128       GKeyFileKeyValuePair *pair;
2129 
2130       pair = (GKeyFileKeyValuePair *) tmp->data;
2131 
2132       if (pair->key != NULL)
2133         break;
2134 
2135       comment_node = tmp;
2136       tmp = tmp->next;
2137       g_key_file_remove_key_value_pair_node (key_file, group,
2138                                              comment_node);
2139     }
2140 
2141   if (comment == NULL)
2142     return;
2143 
2144   /* Now we can add our new comment
2145    */
2146   pair = g_new0 (GKeyFileKeyValuePair, 1);
2147 
2148   pair->key = NULL;
2149   pair->value = g_key_file_parse_comment_as_value (key_file, comment);
2150 
2151   key_node = g_list_insert (key_node, pair, 1);
2152 }
2153 
2154 static void
g_key_file_set_group_comment(GKeyFile * key_file,const gchar * group_name,const gchar * comment,GError ** error)2155 g_key_file_set_group_comment (GKeyFile             *key_file,
2156                               const gchar          *group_name,
2157                               const gchar          *comment,
2158                               GError              **error)
2159 {
2160   GKeyFileGroup *group;
2161 
2162   g_return_if_fail (g_key_file_is_group_name (group_name));
2163 
2164   group = g_key_file_lookup_group (key_file, group_name);
2165   if (!group)
2166     {
2167       g_set_error (error, G_KEY_FILE_ERROR,
2168                    G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
2169                    _("Key file does not have group '%s'"),
2170                    group_name ? group_name : "(null)");
2171 
2172       return;
2173     }
2174 
2175   /* First remove any existing comment
2176    */
2177   if (group->comment)
2178     {
2179       g_key_file_key_value_pair_free (group->comment);
2180       group->comment = NULL;
2181     }
2182 
2183   if (comment == NULL)
2184     return;
2185 
2186   /* Now we can add our new comment
2187    */
2188   group->comment = g_new0 (GKeyFileKeyValuePair, 1);
2189 
2190   group->comment->key = NULL;
2191   group->comment->value = g_key_file_parse_comment_as_value (key_file, comment);
2192 }
2193 
2194 static void
g_key_file_set_top_comment(GKeyFile * key_file,const gchar * comment,GError ** error)2195 g_key_file_set_top_comment (GKeyFile             *key_file,
2196                             const gchar          *comment,
2197                             GError              **error)
2198 {
2199   GList *group_node;
2200   GKeyFileGroup *group;
2201   GKeyFileKeyValuePair *pair;
2202 
2203   /* The last group in the list should be the top (comments only)
2204    * group in the file
2205    */
2206   g_assert (key_file->groups != NULL);
2207   group_node = g_list_last (key_file->groups);
2208   group = (GKeyFileGroup *) group_node->data;
2209   g_assert (group->name == NULL);
2210 
2211   /* Note all keys must be comments at the top of
2212    * the file, so we can just free it all.
2213    */
2214   if (group->key_value_pairs != NULL)
2215     {
2216       g_list_foreach (group->key_value_pairs,
2217                       (GFunc) g_key_file_key_value_pair_free,
2218                       NULL);
2219       g_list_free (group->key_value_pairs);
2220       group->key_value_pairs = NULL;
2221     }
2222 
2223   if (comment == NULL)
2224      return;
2225 
2226   pair = g_new0 (GKeyFileKeyValuePair, 1);
2227 
2228   pair->key = NULL;
2229   pair->value = g_key_file_parse_comment_as_value (key_file, comment);
2230 
2231   group->key_value_pairs =
2232     g_list_prepend (group->key_value_pairs, pair);
2233 }
2234 
2235 /**
2236  * g_key_file_set_comment:
2237  * @key_file: a #GKeyFile
2238  * @group_name: a group name, or %NULL
2239  * @key: a key
2240  * @comment: a comment
2241  * @error: return location for a #GError
2242  *
2243  * Places a comment above @key from @group_name.
2244  * @group_name. If @key is %NULL then @comment will
2245  * be written above @group_name.  If both @key
2246  * and @group_name are NULL, then @comment will
2247  * be written above the first group in the file.
2248  *
2249  * Since: 2.6
2250  **/
2251 void
g_key_file_set_comment(GKeyFile * key_file,const gchar * group_name,const gchar * key,const gchar * comment,GError ** error)2252 g_key_file_set_comment (GKeyFile             *key_file,
2253                         const gchar          *group_name,
2254                         const gchar          *key,
2255                         const gchar          *comment,
2256                         GError              **error)
2257 {
2258   g_return_if_fail (key_file != NULL);
2259 
2260   if (group_name != NULL && key != NULL)
2261     g_key_file_set_key_comment (key_file, group_name, key, comment, error);
2262   else if (group_name != NULL)
2263     g_key_file_set_group_comment (key_file, group_name, comment, error);
2264   else
2265     g_key_file_set_top_comment (key_file, comment, error);
2266 
2267   if (comment != NULL)
2268     key_file->approximate_size += strlen (comment);
2269 }
2270 
2271 static gchar *
g_key_file_get_key_comment(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)2272 g_key_file_get_key_comment (GKeyFile             *key_file,
2273                             const gchar          *group_name,
2274                             const gchar          *key,
2275                             GError              **error)
2276 {
2277   GKeyFileGroup *group;
2278   GKeyFileKeyValuePair *pair;
2279   GList *key_node, *tmp;
2280   GString *string;
2281   gchar *comment;
2282 
2283   g_return_val_if_fail (g_key_file_is_group_name (group_name), NULL);
2284 
2285   group = g_key_file_lookup_group (key_file, group_name);
2286   if (!group)
2287     {
2288       g_set_error (error, G_KEY_FILE_ERROR,
2289                    G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
2290                    _("Key file does not have group '%s'"),
2291                    group_name ? group_name : "(null)");
2292 
2293       return NULL;
2294     }
2295 
2296   /* First find the key the comments are supposed to be
2297    * associated with
2298    */
2299   key_node = g_key_file_lookup_key_value_pair_node (key_file, group, key);
2300 
2301   if (key_node == NULL)
2302     {
2303       g_set_error (error, G_KEY_FILE_ERROR,
2304                    G_KEY_FILE_ERROR_KEY_NOT_FOUND,
2305                    _("Key file does not have key '%s' in group '%s'"),
2306                    key, group->name);
2307       return NULL;
2308     }
2309 
2310   string = NULL;
2311 
2312   /* Then find all the comments already associated with the
2313    * key and concatentate them.
2314    */
2315   tmp = key_node->next;
2316   if (!key_node->next)
2317     return NULL;
2318 
2319   pair = (GKeyFileKeyValuePair *) tmp->data;
2320   if (pair->key != NULL)
2321     return NULL;
2322 
2323   while (tmp->next)
2324     {
2325       pair = (GKeyFileKeyValuePair *) tmp->next->data;
2326 
2327       if (pair->key != NULL)
2328         break;
2329 
2330       tmp = tmp->next;
2331     }
2332 
2333   while (tmp != key_node)
2334     {
2335       GKeyFileKeyValuePair *pair;
2336 
2337       pair = (GKeyFileKeyValuePair *) tmp->data;
2338 
2339       if (string == NULL)
2340 	string = g_string_sized_new (512);
2341 
2342       comment = g_key_file_parse_value_as_comment (key_file, pair->value);
2343       g_string_append (string, comment);
2344       g_free (comment);
2345 
2346       tmp = tmp->prev;
2347     }
2348 
2349   if (string != NULL)
2350     {
2351       comment = string->str;
2352       g_string_free (string, FALSE);
2353     }
2354   else
2355     comment = NULL;
2356 
2357   return comment;
2358 }
2359 
2360 static gchar *
get_group_comment(GKeyFile * key_file,GKeyFileGroup * group,GError ** error)2361 get_group_comment (GKeyFile       *key_file,
2362 		   GKeyFileGroup  *group,
2363 		   GError        **error)
2364 {
2365   GString *string;
2366   GList *tmp;
2367   gchar *comment;
2368 
2369   string = NULL;
2370 
2371   tmp = group->key_value_pairs;
2372   while (tmp)
2373     {
2374       GKeyFileKeyValuePair *pair;
2375 
2376       pair = (GKeyFileKeyValuePair *) tmp->data;
2377 
2378       if (pair->key != NULL)
2379 	{
2380 	  tmp = tmp->prev;
2381 	  break;
2382 	}
2383 
2384       if (tmp->next == NULL)
2385 	break;
2386 
2387       tmp = tmp->next;
2388     }
2389 
2390   while (tmp != NULL)
2391     {
2392       GKeyFileKeyValuePair *pair;
2393 
2394       pair = (GKeyFileKeyValuePair *) tmp->data;
2395 
2396       if (string == NULL)
2397         string = g_string_sized_new (512);
2398 
2399       comment = g_key_file_parse_value_as_comment (key_file, pair->value);
2400       g_string_append (string, comment);
2401       g_free (comment);
2402 
2403       tmp = tmp->prev;
2404     }
2405 
2406   if (string != NULL)
2407     return g_string_free (string, FALSE);
2408 
2409   return NULL;
2410 }
2411 
2412 static gchar *
g_key_file_get_group_comment(GKeyFile * key_file,const gchar * group_name,GError ** error)2413 g_key_file_get_group_comment (GKeyFile             *key_file,
2414                               const gchar          *group_name,
2415                               GError              **error)
2416 {
2417   GList *group_node;
2418   GKeyFileGroup *group;
2419 
2420   group_node = g_key_file_lookup_group_node (key_file, group_name);
2421   if (!group_node)
2422     {
2423       g_set_error (error, G_KEY_FILE_ERROR,
2424                    G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
2425                    _("Key file does not have group '%s'"),
2426                    group_name ? group_name : "(null)");
2427 
2428       return NULL;
2429     }
2430 
2431   group = (GKeyFileGroup *)group_node->data;
2432   if (group->comment)
2433     return g_strdup (group->comment->value);
2434 
2435   group_node = group_node->next;
2436   group = (GKeyFileGroup *)group_node->data;
2437   return get_group_comment (key_file, group, error);
2438 }
2439 
2440 static gchar *
g_key_file_get_top_comment(GKeyFile * key_file,GError ** error)2441 g_key_file_get_top_comment (GKeyFile             *key_file,
2442                             GError              **error)
2443 {
2444   GList *group_node;
2445   GKeyFileGroup *group;
2446 
2447   /* The last group in the list should be the top (comments only)
2448    * group in the file
2449    */
2450   g_assert (key_file->groups != NULL);
2451   group_node = g_list_last (key_file->groups);
2452   group = (GKeyFileGroup *) group_node->data;
2453   g_assert (group->name == NULL);
2454 
2455   return get_group_comment (key_file, group, error);
2456 }
2457 
2458 /**
2459  * g_key_file_get_comment:
2460  * @key_file: a #GKeyFile
2461  * @group_name: a group name, or %NULL
2462  * @key: a key
2463  * @error: return location for a #GError
2464  *
2465  * Retrieves a comment above @key from @group_name.
2466  * @group_name. If @key is %NULL then @comment will
2467  * be read from above @group_name.  If both @key
2468  * and @group_name are NULL, then @comment will
2469  * be read from above the first group in the file.
2470  *
2471  * Returns: a comment that should be freed with g_free()
2472  *
2473  * Since: 2.6
2474  **/
2475 gchar *
g_key_file_get_comment(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)2476 g_key_file_get_comment (GKeyFile             *key_file,
2477                         const gchar          *group_name,
2478                         const gchar          *key,
2479                         GError              **error)
2480 {
2481   g_return_val_if_fail (key_file != NULL, NULL);
2482 
2483   if (group_name != NULL && key != NULL)
2484     return g_key_file_get_key_comment (key_file, group_name, key, error);
2485   else if (group_name != NULL)
2486     return g_key_file_get_group_comment (key_file, group_name, error);
2487   else
2488     return g_key_file_get_top_comment (key_file, error);
2489 }
2490 
2491 /**
2492  * g_key_file_remove_comment:
2493  * @key_file: a #GKeyFile
2494  * @group_name: a group name, or %NULL
2495  * @key: a key
2496  * @error: return location for a #GError
2497  *
2498  * Removes a comment above @key from @group_name.
2499  * @group_name. If @key is %NULL then @comment will
2500  * be written above @group_name.  If both @key
2501  * and @group_name are NULL, then @comment will
2502  * be written above the first group in the file.
2503  *
2504  * Since: 2.6
2505  **/
2506 
2507 void
g_key_file_remove_comment(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)2508 g_key_file_remove_comment (GKeyFile             *key_file,
2509                            const gchar          *group_name,
2510                            const gchar          *key,
2511                            GError              **error)
2512 {
2513   g_return_if_fail (key_file != NULL);
2514 
2515   if (group_name != NULL && key != NULL)
2516     g_key_file_set_key_comment (key_file, group_name, key, NULL, error);
2517   else if (group_name != NULL)
2518     g_key_file_set_group_comment (key_file, group_name, NULL, error);
2519   else
2520     g_key_file_set_top_comment (key_file, NULL, error);
2521 }
2522 
2523 /**
2524  * g_key_file_has_group:
2525  * @key_file: a #GKeyFile
2526  * @group_name: a group name
2527  *
2528  * Looks whether the key file has the group @group_name.
2529  *
2530  * Return value: %TRUE if @group_name is a part of @key_file, %FALSE
2531  * otherwise.
2532  * Since: 2.6
2533  **/
2534 gboolean
g_key_file_has_group(GKeyFile * key_file,const gchar * group_name)2535 g_key_file_has_group (GKeyFile    *key_file,
2536 		      const gchar *group_name)
2537 {
2538   g_return_val_if_fail (key_file != NULL, FALSE);
2539   g_return_val_if_fail (group_name != NULL, FALSE);
2540 
2541   return g_key_file_lookup_group_node (key_file, group_name) != NULL;
2542 }
2543 
2544 /**
2545  * g_key_file_has_key:
2546  * @key_file: a #GKeyFile
2547  * @group_name: a group name
2548  * @key: a key name
2549  * @error: return location for a #GError
2550  *
2551  * Looks whether the key file has the key @key in the group
2552  * @group_name.
2553  *
2554  * Return value: %TRUE if @key is a part of @group_name, %FALSE
2555  * otherwise.
2556  *
2557  * Since: 2.6
2558  **/
2559 gboolean
g_key_file_has_key(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)2560 g_key_file_has_key (GKeyFile     *key_file,
2561 		    const gchar  *group_name,
2562 		    const gchar  *key,
2563 		    GError      **error)
2564 {
2565   GKeyFileKeyValuePair *pair;
2566   GKeyFileGroup *group;
2567 
2568   g_return_val_if_fail (key_file != NULL, FALSE);
2569   g_return_val_if_fail (group_name != NULL, FALSE);
2570   g_return_val_if_fail (key != NULL, FALSE);
2571 
2572   group = g_key_file_lookup_group (key_file, group_name);
2573 
2574   if (!group)
2575     {
2576       g_set_error (error, G_KEY_FILE_ERROR,
2577                    G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
2578                    _("Key file does not have group '%s'"),
2579                    group_name ? group_name : "(null)");
2580 
2581       return FALSE;
2582     }
2583 
2584   pair = g_key_file_lookup_key_value_pair (key_file, group, key);
2585 
2586   return pair != NULL;
2587 }
2588 
2589 static void
g_key_file_add_group(GKeyFile * key_file,const gchar * group_name)2590 g_key_file_add_group (GKeyFile    *key_file,
2591 		      const gchar *group_name)
2592 {
2593   GKeyFileGroup *group;
2594 
2595   g_return_if_fail (key_file != NULL);
2596   g_return_if_fail (g_key_file_is_group_name (group_name));
2597 
2598   group = g_key_file_lookup_group (key_file, group_name);
2599   if (group != NULL)
2600     {
2601       key_file->current_group = group;
2602       return;
2603     }
2604 
2605   group = g_new0 (GKeyFileGroup, 1);
2606   group->name = g_strdup (group_name);
2607   group->lookup_map = g_hash_table_new (g_str_hash, g_str_equal);
2608   key_file->groups = g_list_prepend (key_file->groups, group);
2609   key_file->approximate_size += strlen (group_name) + 3;
2610   key_file->current_group = group;
2611 
2612   if (key_file->start_group == NULL)
2613     key_file->start_group = group;
2614 }
2615 
2616 static void
g_key_file_key_value_pair_free(GKeyFileKeyValuePair * pair)2617 g_key_file_key_value_pair_free (GKeyFileKeyValuePair *pair)
2618 {
2619   if (pair != NULL)
2620     {
2621       g_free (pair->key);
2622       g_free (pair->value);
2623       g_free (pair);
2624     }
2625 }
2626 
2627 /* Be careful not to call this function on a node with data in the
2628  * lookup map without removing it from the lookup map, first.
2629  *
2630  * Some current cases where this warning is not a concern are
2631  * when:
2632  *   - the node being removed is a comment node
2633  *   - the entire lookup map is getting destroyed soon after
2634  *     anyway.
2635  */
2636 static void
g_key_file_remove_key_value_pair_node(GKeyFile * key_file,GKeyFileGroup * group,GList * pair_node)2637 g_key_file_remove_key_value_pair_node (GKeyFile      *key_file,
2638                                        GKeyFileGroup *group,
2639 			               GList         *pair_node)
2640 {
2641 
2642   GKeyFileKeyValuePair *pair;
2643 
2644   pair = (GKeyFileKeyValuePair *) pair_node->data;
2645 
2646   group->key_value_pairs = g_list_remove_link (group->key_value_pairs, pair_node);
2647 
2648   if (pair->key != NULL)
2649     key_file->approximate_size -= strlen (pair->key) + 1;
2650 
2651   g_assert (pair->value != NULL);
2652   key_file->approximate_size -= strlen (pair->value);
2653 
2654   g_key_file_key_value_pair_free (pair);
2655 
2656   g_list_free_1 (pair_node);
2657 }
2658 
2659 static void
g_key_file_remove_group_node(GKeyFile * key_file,GList * group_node)2660 g_key_file_remove_group_node (GKeyFile *key_file,
2661 			      GList    *group_node)
2662 {
2663   GKeyFileGroup *group;
2664   GList *tmp;
2665 
2666   group = (GKeyFileGroup *) group_node->data;
2667 
2668   /* If the current group gets deleted make the current group the last
2669    * added group.
2670    */
2671   if (key_file->current_group == group)
2672     {
2673       /* groups should always contain at least the top comment group,
2674        * unless g_key_file_clear has been called
2675        */
2676       if (key_file->groups)
2677         key_file->current_group = (GKeyFileGroup *) key_file->groups->data;
2678       else
2679         key_file->current_group = NULL;
2680     }
2681 
2682   /* If the start group gets deleted make the start group the first
2683    * added group.
2684    */
2685   if (key_file->start_group == group)
2686     {
2687       tmp = g_list_last (key_file->groups);
2688       while (tmp != NULL)
2689 	{
2690 	  if (tmp != group_node &&
2691 	      ((GKeyFileGroup *) tmp->data)->name != NULL)
2692 	    break;
2693 
2694 	  tmp = tmp->prev;
2695 	}
2696 
2697       if (tmp)
2698         key_file->start_group = (GKeyFileGroup *) tmp->data;
2699       else
2700         key_file->start_group = NULL;
2701     }
2702 
2703   key_file->groups = g_list_remove_link (key_file->groups, group_node);
2704 
2705   if (group->name != NULL)
2706     key_file->approximate_size -= strlen (group->name) + 3;
2707 
2708   tmp = group->key_value_pairs;
2709   while (tmp != NULL)
2710     {
2711       GList *pair_node;
2712 
2713       pair_node = tmp;
2714       tmp = tmp->next;
2715       g_key_file_remove_key_value_pair_node (key_file, group, pair_node);
2716     }
2717 
2718   g_assert (group->key_value_pairs == NULL);
2719 
2720   if (group->lookup_map)
2721     {
2722       g_hash_table_destroy (group->lookup_map);
2723       group->lookup_map = NULL;
2724     }
2725 
2726   g_free ((gchar *) group->name);
2727   g_free (group);
2728   g_list_free_1 (group_node);
2729 }
2730 
2731 /**
2732  * g_key_file_remove_group:
2733  * @key_file: a #GKeyFile
2734  * @group_name: a group name
2735  * @error: return location for a #GError or %NULL
2736  *
2737  * Removes the specified group, @group_name,
2738  * from the key file.
2739  *
2740  * Since: 2.6
2741  **/
2742 void
g_key_file_remove_group(GKeyFile * key_file,const gchar * group_name,GError ** error)2743 g_key_file_remove_group (GKeyFile     *key_file,
2744 			 const gchar  *group_name,
2745 			 GError      **error)
2746 {
2747   GList *group_node;
2748 
2749   g_return_if_fail (key_file != NULL);
2750   g_return_if_fail (group_name != NULL);
2751 
2752   group_node = g_key_file_lookup_group_node (key_file, group_name);
2753 
2754   if (!group_node)
2755     {
2756       g_set_error (error, G_KEY_FILE_ERROR,
2757 		   G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
2758 		   _("Key file does not have group '%s'"),
2759 		   group_name);
2760       return;
2761     }
2762 
2763     g_key_file_remove_group_node (key_file, group_node);
2764 }
2765 
2766 static void
g_key_file_add_key(GKeyFile * key_file,GKeyFileGroup * group,const gchar * key,const gchar * value)2767 g_key_file_add_key (GKeyFile      *key_file,
2768 		    GKeyFileGroup *group,
2769 		    const gchar   *key,
2770 		    const gchar   *value)
2771 {
2772   GKeyFileKeyValuePair *pair;
2773 
2774   pair = g_new0 (GKeyFileKeyValuePair, 1);
2775 
2776   pair->key = g_strdup (key);
2777   pair->value = g_strdup (value);
2778 
2779   g_hash_table_replace (group->lookup_map, pair->key, pair);
2780   group->key_value_pairs = g_list_prepend (group->key_value_pairs, pair);
2781   key_file->approximate_size += strlen (key) + strlen (value) + 2;
2782 }
2783 
2784 /**
2785  * g_key_file_remove_key:
2786  * @key_file: a #GKeyFile
2787  * @group_name: a group name
2788  * @key: a key name to remove
2789  * @error: return location for a #GError or %NULL
2790  *
2791  * Removes @key in @group_name from the key file.
2792  *
2793  * Since: 2.6
2794  **/
2795 void
g_key_file_remove_key(GKeyFile * key_file,const gchar * group_name,const gchar * key,GError ** error)2796 g_key_file_remove_key (GKeyFile     *key_file,
2797 		       const gchar  *group_name,
2798 		       const gchar  *key,
2799 		       GError      **error)
2800 {
2801   GKeyFileGroup *group;
2802   GKeyFileKeyValuePair *pair;
2803 
2804   g_return_if_fail (key_file != NULL);
2805   g_return_if_fail (group_name != NULL);
2806   g_return_if_fail (key != NULL);
2807 
2808   pair = NULL;
2809 
2810   group = g_key_file_lookup_group (key_file, group_name);
2811   if (!group)
2812     {
2813       g_set_error (error, G_KEY_FILE_ERROR,
2814                    G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
2815                    _("Key file does not have group '%s'"),
2816                    group_name ? group_name : "(null)");
2817       return;
2818     }
2819 
2820   pair = g_key_file_lookup_key_value_pair (key_file, group, key);
2821 
2822   if (!pair)
2823     {
2824       g_set_error (error, G_KEY_FILE_ERROR,
2825                    G_KEY_FILE_ERROR_KEY_NOT_FOUND,
2826                    _("Key file does not have key '%s' in group '%s'"),
2827 		   key, group->name);
2828       return;
2829     }
2830 
2831   key_file->approximate_size -= strlen (pair->key) + strlen (pair->value) + 2;
2832 
2833   group->key_value_pairs = g_list_remove (group->key_value_pairs, pair);
2834   g_hash_table_remove (group->lookup_map, pair->key);
2835   g_key_file_key_value_pair_free (pair);
2836 }
2837 
2838 static GList *
g_key_file_lookup_group_node(GKeyFile * key_file,const gchar * group_name)2839 g_key_file_lookup_group_node (GKeyFile    *key_file,
2840 			      const gchar *group_name)
2841 {
2842   GKeyFileGroup *group;
2843   GList *tmp;
2844 
2845   for (tmp = key_file->groups; tmp != NULL; tmp = tmp->next)
2846     {
2847       group = (GKeyFileGroup *) tmp->data;
2848 
2849       if (group && group->name && strcmp (group->name, group_name) == 0)
2850         break;
2851     }
2852 
2853   return tmp;
2854 }
2855 
2856 static GKeyFileGroup *
g_key_file_lookup_group(GKeyFile * key_file,const gchar * group_name)2857 g_key_file_lookup_group (GKeyFile    *key_file,
2858 			 const gchar *group_name)
2859 {
2860   GList *group_node;
2861 
2862   group_node = g_key_file_lookup_group_node (key_file, group_name);
2863 
2864   if (group_node != NULL)
2865     return (GKeyFileGroup *) group_node->data;
2866 
2867   return NULL;
2868 }
2869 
2870 static GList *
g_key_file_lookup_key_value_pair_node(GKeyFile * key_file,GKeyFileGroup * group,const gchar * key)2871 g_key_file_lookup_key_value_pair_node (GKeyFile       *key_file,
2872 			               GKeyFileGroup  *group,
2873                                        const gchar    *key)
2874 {
2875   GList *key_node;
2876 
2877   for (key_node = group->key_value_pairs;
2878        key_node != NULL;
2879        key_node = key_node->next)
2880     {
2881       GKeyFileKeyValuePair *pair;
2882 
2883       pair = (GKeyFileKeyValuePair *) key_node->data;
2884 
2885       if (pair->key && strcmp (pair->key, key) == 0)
2886         break;
2887     }
2888 
2889   return key_node;
2890 }
2891 
2892 static GKeyFileKeyValuePair *
g_key_file_lookup_key_value_pair(GKeyFile * key_file,GKeyFileGroup * group,const gchar * key)2893 g_key_file_lookup_key_value_pair (GKeyFile      *key_file,
2894 				  GKeyFileGroup *group,
2895 				  const gchar   *key)
2896 {
2897   return (GKeyFileKeyValuePair *) g_hash_table_lookup (group->lookup_map, key);
2898 }
2899 
2900 /* Lines starting with # or consisting entirely of whitespace are merely
2901  * recorded, not parsed. This function assumes all leading whitespace
2902  * has been stripped.
2903  */
2904 static gboolean
g_key_file_line_is_comment(const gchar * line)2905 g_key_file_line_is_comment (const gchar *line)
2906 {
2907   return (*line == '#' || *line == '\0' || *line == '\n');
2908 }
2909 
2910 static gboolean
g_key_file_is_group_name(const gchar * name)2911 g_key_file_is_group_name (const gchar *name)
2912 {
2913   gchar *p, *q;
2914 
2915   if (name == NULL)
2916     return FALSE;
2917 
2918   p = q = (gchar *) name;
2919   while (*q && *q != ']' && *q != '[' && !g_ascii_iscntrl (*q))
2920     q = g_utf8_next_char (q);
2921 
2922   if (*q != '\0' || q == p)
2923     return FALSE;
2924 
2925   return TRUE;
2926 }
2927 
2928 static gboolean
g_key_file_is_key_name(const gchar * name)2929 g_key_file_is_key_name (const gchar *name)
2930 {
2931   gchar *p, *q;
2932 
2933   if (name == NULL)
2934     return FALSE;
2935 
2936   p = q = (gchar *) name;
2937   /* We accept a little more than the desktop entry spec says,
2938    * since gnome-vfs uses mime-types as keys in its cache.
2939    */
2940   while (*q && (g_unichar_isalnum (g_utf8_get_char (q)) ||
2941                 *q == '-' || *q == '_' || *q == '/' || *q == '+' || *q == '.'))
2942     q = g_utf8_next_char (q);
2943 
2944   if (*q == '[')
2945     {
2946       q++;
2947       while (*q && (g_unichar_isalnum (g_utf8_get_char (q)) || *q == '-' || *q == '_' || *q == '.' || *q == '@'))
2948         q = g_utf8_next_char (q);
2949 
2950       if (*q != ']')
2951         return FALSE;
2952 
2953       q++;
2954     }
2955 
2956   if (*q != '\0' || q == p)
2957     return FALSE;
2958 
2959   return TRUE;
2960 }
2961 
2962 /* A group in a key file is made up of a starting '[' followed by one
2963  * or more letters making up the group name followed by ']'.
2964  */
2965 static gboolean
g_key_file_line_is_group(const gchar * line)2966 g_key_file_line_is_group (const gchar *line)
2967 {
2968   gchar *p;
2969 
2970   p = (gchar *) line;
2971   if (*p != '[')
2972     return FALSE;
2973 
2974   p++;
2975 
2976   while (*p && *p != ']')
2977     p = g_utf8_next_char (p);
2978 
2979   if (!*p)
2980     return FALSE;
2981 
2982   return TRUE;
2983 }
2984 
2985 static gboolean
g_key_file_line_is_key_value_pair(const gchar * line)2986 g_key_file_line_is_key_value_pair (const gchar *line)
2987 {
2988   gchar *p;
2989 
2990   p = (gchar *) g_utf8_strchr (line, -1, '=');
2991 
2992   if (!p)
2993     return FALSE;
2994 
2995   /* Key must be non-empty
2996    */
2997   if (*p == line[0])
2998     return FALSE;
2999 
3000   return TRUE;
3001 }
3002 
3003 static gchar *
g_key_file_parse_value_as_string(GKeyFile * key_file,const gchar * value,GSList ** pieces,GError ** error)3004 g_key_file_parse_value_as_string (GKeyFile     *key_file,
3005 				  const gchar  *value,
3006 				  GSList      **pieces,
3007 				  GError      **error)
3008 {
3009   gchar *string_value, *p, *q0, *q;
3010 
3011   string_value = g_new0 (gchar, strlen (value) + 1);
3012 
3013   p = (gchar *) value;
3014   q0 = q = string_value;
3015   while (*p)
3016     {
3017       if (*p == '\\')
3018         {
3019           p++;
3020 
3021           switch (*p)
3022             {
3023             case 's':
3024               *q = ' ';
3025               break;
3026 
3027             case 'n':
3028               *q = '\n';
3029               break;
3030 
3031             case 't':
3032               *q = '\t';
3033               break;
3034 
3035             case 'r':
3036               *q = '\r';
3037               break;
3038 
3039             case '\\':
3040               *q = '\\';
3041               break;
3042 
3043 	    case '\0':
3044 	      g_set_error (error, G_KEY_FILE_ERROR,
3045 			   G_KEY_FILE_ERROR_INVALID_VALUE,
3046 			   _("Key file contains escape character "
3047 			     "at end of line"));
3048 	      break;
3049 
3050             default:
3051 	      if (pieces && *p == key_file->list_separator)
3052 		*q = key_file->list_separator;
3053 	      else
3054 		{
3055 		  *q++ = '\\';
3056 		  *q = *p;
3057 
3058 		  if (*error == NULL)
3059 		    {
3060 		      gchar sequence[3];
3061 
3062 		      sequence[0] = '\\';
3063 		      sequence[1] = *p;
3064 		      sequence[2] = '\0';
3065 
3066 		      g_set_error (error, G_KEY_FILE_ERROR,
3067 				   G_KEY_FILE_ERROR_INVALID_VALUE,
3068 				   _("Key file contains invalid escape "
3069 				     "sequence '%s'"), sequence);
3070 		    }
3071 		}
3072               break;
3073             }
3074         }
3075       else
3076 	{
3077 	  *q = *p;
3078 	  if (pieces && (*p == key_file->list_separator))
3079 	    {
3080 	      *pieces = g_slist_prepend (*pieces, g_strndup (q0, q - q0));
3081 	      q0 = q + 1;
3082 	    }
3083 	}
3084 
3085       if (*p == '\0')
3086 	break;
3087 
3088       q++;
3089       p++;
3090     }
3091 
3092   *q = '\0';
3093   if (pieces)
3094   {
3095     if (q0 < q)
3096       *pieces = g_slist_prepend (*pieces, g_strndup (q0, q - q0));
3097     *pieces = g_slist_reverse (*pieces);
3098   }
3099 
3100   return string_value;
3101 }
3102 
3103 static gchar *
g_key_file_parse_string_as_value(GKeyFile * key_file,const gchar * string,gboolean escape_separator)3104 g_key_file_parse_string_as_value (GKeyFile    *key_file,
3105 				  const gchar *string,
3106 				  gboolean     escape_separator)
3107 {
3108   gchar *value, *p, *q;
3109   gsize length;
3110   gboolean parsing_leading_space;
3111 
3112   length = strlen (string) + 1;
3113 
3114   /* Worst case would be that every character needs to be escaped.
3115    * In other words every character turns to two characters
3116    */
3117   value = g_new0 (gchar, 2 * length);
3118 
3119   p = (gchar *) string;
3120   q = value;
3121   parsing_leading_space = TRUE;
3122   while (p < (string + length - 1))
3123     {
3124       gchar escaped_character[3] = { '\\', 0, 0 };
3125 
3126       switch (*p)
3127         {
3128         case ' ':
3129           if (parsing_leading_space)
3130             {
3131               escaped_character[1] = 's';
3132               strcpy (q, escaped_character);
3133               q += 2;
3134             }
3135           else
3136             {
3137 	      *q = *p;
3138 	      q++;
3139             }
3140           break;
3141         case '\t':
3142           if (parsing_leading_space)
3143             {
3144               escaped_character[1] = 't';
3145               strcpy (q, escaped_character);
3146               q += 2;
3147             }
3148           else
3149             {
3150 	      *q = *p;
3151 	      q++;
3152             }
3153           break;
3154         case '\n':
3155           escaped_character[1] = 'n';
3156           strcpy (q, escaped_character);
3157           q += 2;
3158           break;
3159         case '\r':
3160           escaped_character[1] = 'r';
3161           strcpy (q, escaped_character);
3162           q += 2;
3163           break;
3164         case '\\':
3165           escaped_character[1] = '\\';
3166           strcpy (q, escaped_character);
3167           q += 2;
3168           parsing_leading_space = FALSE;
3169           break;
3170         default:
3171 	  if (escape_separator && *p == key_file->list_separator)
3172 	    {
3173 	      escaped_character[1] = key_file->list_separator;
3174 	      strcpy (q, escaped_character);
3175 	      q += 2;
3176               parsing_leading_space = TRUE;
3177 	    }
3178 	  else
3179 	    {
3180 	      *q = *p;
3181 	      q++;
3182               parsing_leading_space = FALSE;
3183 	    }
3184           break;
3185         }
3186       p++;
3187     }
3188   *q = '\0';
3189 
3190   return value;
3191 }
3192 
3193 static gint
g_key_file_parse_value_as_integer(GKeyFile * key_file,const gchar * value,GError ** error)3194 g_key_file_parse_value_as_integer (GKeyFile     *key_file,
3195 				   const gchar  *value,
3196 				   GError      **error)
3197 {
3198   gchar *end_of_valid_int;
3199   glong long_value;
3200   gint int_value;
3201 
3202   errno = 0;
3203   long_value = strtol (value, &end_of_valid_int, 10);
3204 
3205   if (*value == '\0' || *end_of_valid_int != '\0')
3206     {
3207       gchar *value_utf8 = _g_utf8_make_valid (value);
3208       g_set_error (error, G_KEY_FILE_ERROR,
3209 		   G_KEY_FILE_ERROR_INVALID_VALUE,
3210 		   _("Value '%s' cannot be interpreted "
3211 		     "as a number."), value_utf8);
3212       g_free (value_utf8);
3213 
3214       return 0;
3215     }
3216 
3217   int_value = long_value;
3218   if (int_value != long_value || errno == ERANGE)
3219     {
3220       gchar *value_utf8 = _g_utf8_make_valid (value);
3221       g_set_error (error,
3222 		   G_KEY_FILE_ERROR,
3223 		   G_KEY_FILE_ERROR_INVALID_VALUE,
3224 		   _("Integer value '%s' out of range"),
3225 		   value_utf8);
3226       g_free (value_utf8);
3227 
3228       return 0;
3229     }
3230 
3231   return int_value;
3232 }
3233 
3234 static gchar *
g_key_file_parse_integer_as_value(GKeyFile * key_file,gint value)3235 g_key_file_parse_integer_as_value (GKeyFile *key_file,
3236 				   gint      value)
3237 
3238 {
3239   return g_strdup_printf ("%d", value);
3240 }
3241 
3242 static gdouble
g_key_file_parse_value_as_double(GKeyFile * key_file,const gchar * value,GError ** error)3243 g_key_file_parse_value_as_double  (GKeyFile     *key_file,
3244                                    const gchar  *value,
3245                                    GError      **error)
3246 {
3247   gchar *end_of_valid_d;
3248   gdouble double_value = 0;
3249 
3250   double_value = g_ascii_strtod (value, &end_of_valid_d);
3251 
3252   if (*end_of_valid_d != '\0' || end_of_valid_d == value)
3253     {
3254       gchar *value_utf8 = _g_utf8_make_valid (value);
3255       g_set_error (error, G_KEY_FILE_ERROR,
3256 		   G_KEY_FILE_ERROR_INVALID_VALUE,
3257 		   _("Value '%s' cannot be interpreted "
3258 		     "as a float number."),
3259 		   value_utf8);
3260       g_free (value_utf8);
3261     }
3262 
3263   return double_value;
3264 }
3265 
3266 static gboolean
g_key_file_parse_value_as_boolean(GKeyFile * key_file,const gchar * value,GError ** error)3267 g_key_file_parse_value_as_boolean (GKeyFile     *key_file,
3268 				   const gchar  *value,
3269 				   GError      **error)
3270 {
3271   gchar *value_utf8;
3272 
3273   if (value)
3274     {
3275       if (strcmp (value, "true") == 0 || strcmp (value, "1") == 0)
3276         return TRUE;
3277       else if (strcmp (value, "false") == 0 || strcmp (value, "0") == 0)
3278         return FALSE;
3279     }
3280 
3281   value_utf8 = _g_utf8_make_valid (value);
3282   g_set_error (error, G_KEY_FILE_ERROR,
3283                G_KEY_FILE_ERROR_INVALID_VALUE,
3284                _("Value '%s' cannot be interpreted "
3285 		 "as a boolean."), value_utf8);
3286   g_free (value_utf8);
3287 
3288   return FALSE;
3289 }
3290 
3291 static gchar *
g_key_file_parse_boolean_as_value(GKeyFile * key_file,gboolean value)3292 g_key_file_parse_boolean_as_value (GKeyFile *key_file,
3293 				   gboolean  value)
3294 {
3295   if (value)
3296     return g_strdup ("true");
3297   else
3298     return g_strdup ("false");
3299 }
3300 
3301 static gchar *
g_key_file_parse_value_as_comment(GKeyFile * key_file,const gchar * value)3302 g_key_file_parse_value_as_comment (GKeyFile    *key_file,
3303                                    const gchar *value)
3304 {
3305   GString *string;
3306   gchar **lines;
3307   gsize i;
3308 
3309   string = g_string_sized_new (512);
3310 
3311   lines = g_strsplit (value, "\n", 0);
3312 
3313   for (i = 0; lines[i] != NULL; i++)
3314     {
3315         if (lines[i][0] != '#')
3316            g_string_append_printf (string, "%s\n", lines[i]);
3317         else
3318            g_string_append_printf (string, "%s\n", lines[i] + 1);
3319     }
3320   g_strfreev (lines);
3321 
3322   return g_string_free (string, FALSE);
3323 }
3324 
3325 static gchar *
g_key_file_parse_comment_as_value(GKeyFile * key_file,const gchar * comment)3326 g_key_file_parse_comment_as_value (GKeyFile      *key_file,
3327                                    const gchar   *comment)
3328 {
3329   GString *string;
3330   gchar **lines;
3331   gsize i;
3332 
3333   string = g_string_sized_new (512);
3334 
3335   lines = g_strsplit (comment, "\n", 0);
3336 
3337   for (i = 0; lines[i] != NULL; i++)
3338     g_string_append_printf (string, "#%s%s", lines[i],
3339                             lines[i + 1] == NULL? "" : "\n");
3340   g_strfreev (lines);
3341 
3342   return g_string_free (string, FALSE);
3343 }
3344 #endif
3345 
3346 /*
3347 vi:ts=4:nowrap:ai:expandtab
3348 */
3349