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