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