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 : 10726 : G_DEFINE_QUARK (g-key-file-error-quark, g_key_file_error)
637 : :
638 : : static void
639 : 4274 : g_key_file_init (GKeyFile *key_file)
640 : : {
641 : 4274 : key_file->current_group = g_new0 (GKeyFileGroup, 1);
642 : 4274 : key_file->groups = g_list_prepend (NULL, key_file->current_group);
643 : 4274 : key_file->group_hash = NULL;
644 : 4274 : key_file->start_group = NULL;
645 : 4274 : key_file->parse_buffer = NULL;
646 : 4274 : key_file->list_separator = ';';
647 : 4274 : key_file->flags = 0;
648 : 4274 : }
649 : :
650 : : static void
651 : 4274 : g_key_file_clear (GKeyFile *key_file)
652 : : {
653 : : GList *tmp, *group_node;
654 : :
655 : 4274 : if (key_file->locales)
656 : : {
657 : 724 : g_strfreev (key_file->locales);
658 : 724 : key_file->locales = NULL;
659 : : }
660 : 4274 : key_file->checked_locales = FALSE;
661 : :
662 : 4274 : if (key_file->parse_buffer)
663 : : {
664 : 1449 : g_string_free (key_file->parse_buffer, TRUE);
665 : 1449 : key_file->parse_buffer = NULL;
666 : : }
667 : :
668 : 4274 : tmp = key_file->groups;
669 : 10404 : while (tmp != NULL)
670 : : {
671 : 6130 : group_node = tmp;
672 : 6130 : tmp = tmp->next;
673 : 6130 : g_key_file_remove_group_node (key_file, group_node);
674 : : }
675 : :
676 : 4274 : if (key_file->group_hash != NULL)
677 : : {
678 : 1492 : g_hash_table_destroy (key_file->group_hash);
679 : 1492 : key_file->group_hash = NULL;
680 : : }
681 : :
682 : 4274 : g_warn_if_fail (key_file->groups == NULL);
683 : 4274 : }
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 : 2807 : g_key_file_new (void)
702 : : {
703 : : GKeyFile *key_file;
704 : :
705 : 2807 : key_file = g_new0 (GKeyFile, 1);
706 : 2807 : key_file->ref_count = 1;
707 : 2807 : g_key_file_init (key_file);
708 : :
709 : 2807 : 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 : 1387 : g_key_file_load_from_fd (GKeyFile *key_file,
817 : : gint fd,
818 : : GKeyFileFlags flags,
819 : : GError **error)
820 : : {
821 : 1387 : 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 : 1387 : 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 : 1387 : 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 : 1387 : list_separator = key_file->list_separator;
845 : 1387 : g_key_file_clear (key_file);
846 : 1387 : g_key_file_init (key_file);
847 : 1387 : key_file->list_separator = list_separator;
848 : 1387 : key_file->flags = flags;
849 : :
850 : : do
851 : : {
852 : : int errsv;
853 : :
854 : 3134 : bytes_read = read (fd, read_buf, 4096);
855 : 3134 : errsv = errno;
856 : :
857 : 3134 : if (bytes_read == 0) /* End of File */
858 : 1386 : break;
859 : :
860 : 1748 : 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 : 1748 : g_key_file_parse_data (key_file,
872 : : read_buf, bytes_read,
873 : : &key_file_error);
874 : : }
875 : 1748 : while (!key_file_error);
876 : :
877 : 1387 : if (key_file_error)
878 : : {
879 : 1 : g_propagate_error (error, key_file_error);
880 : 1 : return FALSE;
881 : : }
882 : :
883 : 1386 : g_key_file_flush_parse_buffer (key_file, &key_file_error);
884 : :
885 : 1386 : if (key_file_error)
886 : : {
887 : 0 : g_propagate_error (error, key_file_error);
888 : 0 : return FALSE;
889 : : }
890 : :
891 : 1386 : 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 : 2664 : g_key_file_load_from_file (GKeyFile *key_file,
916 : : const gchar *file,
917 : : GKeyFileFlags flags,
918 : : GError **error)
919 : : {
920 : 2664 : GError *key_file_error = NULL;
921 : : gint fd;
922 : : int errsv;
923 : :
924 : 2664 : g_return_val_if_fail (key_file != NULL, FALSE);
925 : 2664 : g_return_val_if_fail (file != NULL, FALSE);
926 : :
927 : 2664 : fd = g_open (file, O_RDONLY | O_CLOEXEC, 0);
928 : 2664 : errsv = errno;
929 : :
930 : 2664 : if (fd == -1)
931 : : {
932 : 1278 : g_set_error_literal (error, G_FILE_ERROR,
933 : 1278 : g_file_error_from_errno (errsv),
934 : : g_strerror (errsv));
935 : 1278 : return FALSE;
936 : : }
937 : :
938 : 1386 : g_key_file_load_from_fd (key_file, fd, flags, &key_file_error);
939 : 1386 : close (fd);
940 : :
941 : 1386 : if (key_file_error)
942 : : {
943 : 1 : g_propagate_error (error, key_file_error);
944 : 1 : return FALSE;
945 : : }
946 : :
947 : 1385 : 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 : 78 : g_key_file_load_from_data (GKeyFile *key_file,
968 : : const gchar *data,
969 : : gsize length,
970 : : GKeyFileFlags flags,
971 : : GError **error)
972 : : {
973 : 78 : GError *key_file_error = NULL;
974 : : gchar list_separator;
975 : :
976 : 78 : g_return_val_if_fail (key_file != NULL, FALSE);
977 : 78 : g_return_val_if_fail (data != NULL || length == 0, FALSE);
978 : :
979 : 78 : if (length == (gsize)-1)
980 : 59 : length = strlen (data);
981 : :
982 : 78 : list_separator = key_file->list_separator;
983 : 78 : g_key_file_clear (key_file);
984 : 78 : g_key_file_init (key_file);
985 : 78 : key_file->list_separator = list_separator;
986 : 78 : key_file->flags = flags;
987 : :
988 : 78 : g_key_file_parse_data (key_file, data, length, &key_file_error);
989 : :
990 : 78 : if (key_file_error)
991 : : {
992 : 16 : g_propagate_error (error, key_file_error);
993 : 16 : return FALSE;
994 : : }
995 : :
996 : 62 : g_key_file_flush_parse_buffer (key_file, &key_file_error);
997 : :
998 : 62 : if (key_file_error)
999 : : {
1000 : 0 : g_propagate_error (error, key_file_error);
1001 : 0 : return FALSE;
1002 : : }
1003 : :
1004 : 62 : 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 : 2514 : g_key_file_free (GKeyFile *key_file)
1221 : : {
1222 : 2514 : g_return_if_fail (key_file != NULL);
1223 : :
1224 : 2514 : g_key_file_clear (key_file);
1225 : :
1226 : 2514 : if (g_atomic_int_dec_and_test (&key_file->ref_count))
1227 : 2512 : 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 : 1770 : g_key_file_parse_group (key_file, line_start,
1305 : 1770 : length - (line_start - line),
1306 : : &parse_error);
1307 : 57287 : else if (g_key_file_line_is_key_value_pair (line_start))
1308 : 57281 : g_key_file_parse_key_value_pair (key_file, line_start,
1309 : 57281 : 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 : 1770 : 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 : 1770 : group_name_start = line + 1;
1361 : 1770 : group_name_end = line + length - 1;
1362 : :
1363 : 1771 : while (*group_name_end != ']')
1364 : 1 : group_name_end--;
1365 : :
1366 : 1770 : group_name = g_strndup (group_name_start,
1367 : 1770 : group_name_end - group_name_start);
1368 : :
1369 : 1770 : 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 : 1767 : g_key_file_add_group (key_file, group_name, FALSE);
1379 : 1767 : g_free (group_name);
1380 : : }
1381 : :
1382 : : static void
1383 : 57281 : g_key_file_parse_key_value_pair (GKeyFile *key_file,
1384 : : const gchar *line,
1385 : : gsize length,
1386 : : GError **error)
1387 : : {
1388 : : gchar *key, *key_end, *value_start;
1389 : : const gchar *locale;
1390 : : gsize locale_len;
1391 : : gsize key_len, value_len;
1392 : :
1393 : 57281 : if (key_file->current_group == NULL || key_file->current_group->name == NULL)
1394 : : {
1395 : 1 : g_set_error_literal (error, G_KEY_FILE_ERROR,
1396 : : G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
1397 : : _("Key file does not start with a group"));
1398 : 8 : return;
1399 : : }
1400 : :
1401 : 57280 : key_end = value_start = strchr (line, '=');
1402 : :
1403 : 57280 : g_warn_if_fail (key_end != NULL);
1404 : :
1405 : 57280 : key_end--;
1406 : 57280 : value_start++;
1407 : :
1408 : : /* Pull the key name from the line (chomping trailing whitespace)
1409 : : */
1410 : 57433 : while (g_ascii_isspace (*key_end))
1411 : 153 : key_end--;
1412 : :
1413 : 57280 : key_len = key_end - line + 2;
1414 : :
1415 : 57280 : g_warn_if_fail (key_len <= length);
1416 : :
1417 : 57280 : if (!g_key_file_is_key_name (line, key_len - 1))
1418 : : {
1419 : 4 : g_set_error (error, G_KEY_FILE_ERROR,
1420 : : G_KEY_FILE_ERROR_PARSE,
1421 : 4 : _("Invalid key name: %.*s"), (int) key_len - 1, line);
1422 : 4 : return;
1423 : : }
1424 : :
1425 : 57276 : key = g_strndup (line, key_len - 1);
1426 : :
1427 : : /* Pull the value from the line (chugging leading whitespace)
1428 : : */
1429 : 57426 : while (g_ascii_isspace (*value_start))
1430 : 150 : value_start++;
1431 : :
1432 : 57276 : value_len = line + length - value_start;
1433 : :
1434 : 57276 : g_warn_if_fail (key_file->start_group != NULL);
1435 : :
1436 : : /* Checked on entry to this function */
1437 : 57276 : g_assert (key_file->current_group != NULL);
1438 : 57276 : g_assert (key_file->current_group->name != NULL);
1439 : :
1440 : 57276 : if (key_file->start_group == key_file->current_group
1441 : 56583 : && strcmp (key, "Encoding") == 0)
1442 : : {
1443 : 350 : if (value_len != strlen ("UTF-8") ||
1444 : 174 : g_ascii_strncasecmp (value_start, "UTF-8", value_len) != 0)
1445 : : {
1446 : 3 : gchar *value_utf8 = g_utf8_make_valid (value_start, value_len);
1447 : 3 : g_set_error (error, G_KEY_FILE_ERROR,
1448 : : G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
1449 : : _("Key file contains unsupported "
1450 : : "encoding “%s”"), value_utf8);
1451 : 3 : g_free (value_utf8);
1452 : :
1453 : 3 : g_free (key);
1454 : 3 : return;
1455 : : }
1456 : : }
1457 : :
1458 : : /* Is this key a translation? If so, is it one that we care about?
1459 : : */
1460 : 57273 : locale = key_get_locale (key, &locale_len);
1461 : :
1462 : 57273 : if (locale == NULL || g_key_file_locale_is_interesting (key_file, locale, locale_len))
1463 : : {
1464 : : GKeyFileKeyValuePair *pair;
1465 : :
1466 : 27308 : pair = g_new (GKeyFileKeyValuePair, 1);
1467 : 27308 : pair->key = g_steal_pointer (&key);
1468 : 27308 : pair->value = g_strndup (value_start, value_len);
1469 : :
1470 : 27308 : g_key_file_add_key_value_pair (key_file, key_file->current_group, pair,
1471 : 27308 : key_file->current_group->key_value_pairs);
1472 : : }
1473 : :
1474 : 57273 : g_free (key);
1475 : : }
1476 : :
1477 : : static const gchar *
1478 : 57273 : key_get_locale (const gchar *key,
1479 : : gsize *len_out)
1480 : : {
1481 : : const gchar *locale;
1482 : : gsize locale_len;
1483 : :
1484 : 57273 : locale = g_strrstr (key, "[");
1485 : 57273 : if (locale != NULL)
1486 : 30108 : locale_len = strlen (locale);
1487 : : else
1488 : 27165 : locale_len = 0;
1489 : :
1490 : 57273 : if (locale_len > 2)
1491 : : {
1492 : 30108 : locale++; /* skip `[` */
1493 : 30108 : locale_len -= 2; /* drop `[` and `]` */
1494 : : }
1495 : : else
1496 : : {
1497 : 27165 : locale = NULL;
1498 : 27165 : locale_len = 0;
1499 : : }
1500 : :
1501 : 57273 : *len_out = locale_len;
1502 : 57273 : return locale;
1503 : : }
1504 : :
1505 : : static void
1506 : 1826 : g_key_file_parse_data (GKeyFile *key_file,
1507 : : const gchar *data,
1508 : : gsize length,
1509 : : GError **error)
1510 : : {
1511 : : GError *parse_error;
1512 : : gsize i;
1513 : :
1514 : 1843 : g_return_if_fail (key_file != NULL);
1515 : 1826 : g_return_if_fail (data != NULL || length == 0);
1516 : :
1517 : 1826 : parse_error = NULL;
1518 : :
1519 : 1826 : if (!key_file->parse_buffer)
1520 : 1449 : key_file->parse_buffer = g_string_sized_new (128);
1521 : :
1522 : 1826 : i = 0;
1523 : 121899 : while (i < length)
1524 : : {
1525 : 120090 : if (data[i] == '\n')
1526 : : {
1527 : 60012 : if (key_file->parse_buffer->len > 0
1528 : 59654 : && (key_file->parse_buffer->str[key_file->parse_buffer->len - 1]
1529 : : == '\r'))
1530 : 97 : g_string_erase (key_file->parse_buffer,
1531 : 97 : key_file->parse_buffer->len - 1,
1532 : : 1);
1533 : :
1534 : : /* When a newline is encountered flush the parse buffer so that the
1535 : : * line can be parsed. Note that completely blank lines won't show
1536 : : * up in the parse buffer, so they get parsed directly.
1537 : : */
1538 : 60012 : if (key_file->parse_buffer->len > 0)
1539 : 59654 : g_key_file_flush_parse_buffer (key_file, &parse_error);
1540 : : else
1541 : 358 : g_key_file_parse_comment (key_file, "", 1, &parse_error);
1542 : :
1543 : 60012 : if (parse_error)
1544 : : {
1545 : 17 : g_propagate_error (error, parse_error);
1546 : 17 : return;
1547 : : }
1548 : 59995 : i++;
1549 : : }
1550 : : else
1551 : : {
1552 : : const gchar *start_of_line;
1553 : : const gchar *end_of_line;
1554 : : gsize line_length;
1555 : :
1556 : 60078 : start_of_line = data + i;
1557 : 60078 : end_of_line = memchr (start_of_line, '\n', length - i);
1558 : :
1559 : 60078 : if (end_of_line == NULL)
1560 : 452 : end_of_line = data + length;
1561 : :
1562 : 60078 : line_length = end_of_line - start_of_line;
1563 : :
1564 : 60078 : g_string_append_len (key_file->parse_buffer, start_of_line, line_length);
1565 : 60078 : i += line_length;
1566 : : }
1567 : : }
1568 : : }
1569 : :
1570 : : static void
1571 : 61102 : g_key_file_flush_parse_buffer (GKeyFile *key_file,
1572 : : GError **error)
1573 : : {
1574 : 61102 : GError *file_error = NULL;
1575 : :
1576 : 61135 : g_return_if_fail (key_file != NULL);
1577 : :
1578 : 61102 : if (!key_file->parse_buffer)
1579 : 16 : return;
1580 : :
1581 : 61086 : file_error = NULL;
1582 : :
1583 : 61086 : if (key_file->parse_buffer->len > 0)
1584 : : {
1585 : 59729 : g_key_file_parse_line (key_file, key_file->parse_buffer->str,
1586 : 59729 : key_file->parse_buffer->len,
1587 : : &file_error);
1588 : 59729 : g_string_erase (key_file->parse_buffer, 0, -1);
1589 : :
1590 : 59729 : if (file_error)
1591 : : {
1592 : 17 : g_propagate_error (error, file_error);
1593 : 17 : return;
1594 : : }
1595 : : }
1596 : : }
1597 : :
1598 : : /**
1599 : : * g_key_file_to_data:
1600 : : * @key_file: a key file
1601 : : * @length: (out) (optional): return location for the length of the
1602 : : * returned string, or `NULL` to ignore
1603 : : * @error: return location for a [struct@GLib.Error]
1604 : : *
1605 : : * Outputs @key_file as a string.
1606 : : *
1607 : : * Note that this function never reports an error.
1608 : : *
1609 : : * Returns: a newly allocated string holding the contents of the key file
1610 : : *
1611 : : * Since: 2.6
1612 : : **/
1613 : : gchar *
1614 : 175 : g_key_file_to_data (GKeyFile *key_file,
1615 : : gsize *length,
1616 : : GError **error)
1617 : : {
1618 : : GString *data_string;
1619 : : GList *group_node, *key_file_node;
1620 : :
1621 : 175 : g_return_val_if_fail (key_file != NULL, NULL);
1622 : :
1623 : 175 : data_string = g_string_new (NULL);
1624 : :
1625 : 175 : for (group_node = g_list_last (key_file->groups);
1626 : 703 : group_node != NULL;
1627 : 528 : group_node = group_node->prev)
1628 : : {
1629 : : GKeyFileGroup *group;
1630 : :
1631 : 528 : group = (GKeyFileGroup *) group_node->data;
1632 : :
1633 : 528 : if (group->name != NULL)
1634 : 353 : g_string_append_printf (data_string, "[%s]\n", group->name);
1635 : :
1636 : 528 : for (key_file_node = g_list_last (group->key_value_pairs);
1637 : 1081 : key_file_node != NULL;
1638 : 553 : key_file_node = key_file_node->prev)
1639 : : {
1640 : : GKeyFileKeyValuePair *pair;
1641 : :
1642 : 553 : pair = (GKeyFileKeyValuePair *) key_file_node->data;
1643 : :
1644 : 553 : if (pair->key != NULL)
1645 : 350 : g_string_append_printf (data_string, "%s=%s\n", pair->key, pair->value);
1646 : : else
1647 : 203 : g_string_append_printf (data_string, "%s\n", pair->value);
1648 : : }
1649 : : }
1650 : :
1651 : 175 : if (length)
1652 : 174 : *length = data_string->len;
1653 : :
1654 : 175 : return g_string_free (data_string, FALSE);
1655 : : }
1656 : :
1657 : : /**
1658 : : * g_key_file_get_keys:
1659 : : * @key_file: a key file
1660 : : * @group_name: a group name
1661 : : * @length: (out) (optional): return location for the number of keys returned,
1662 : : * or `NULL` to ignore
1663 : : * @error: return location for a [struct@GLib.Error]
1664 : : *
1665 : : * Returns all keys for the group name @group_name.
1666 : : *
1667 : : * The array of returned keys will be `NULL`-terminated, so @length may
1668 : : * optionally be `NULL`. If the @group_name cannot be found,
1669 : : * [error@GLib.KeyFileError.GROUP_NOT_FOUND] is returned.
1670 : : *
1671 : : * Returns: (array zero-terminated=1) (transfer full): a newly-allocated
1672 : : * `NULL`-terminated array of strings. Use [func@GLib.strfreev] to free it.
1673 : : *
1674 : : * Since: 2.6
1675 : : **/
1676 : : gchar **
1677 : 507 : g_key_file_get_keys (GKeyFile *key_file,
1678 : : const gchar *group_name,
1679 : : gsize *length,
1680 : : GError **error)
1681 : : {
1682 : : GKeyFileGroup *group;
1683 : : GList *tmp;
1684 : : gchar **keys;
1685 : : gsize i, num_keys;
1686 : :
1687 : 507 : g_return_val_if_fail (key_file != NULL, NULL);
1688 : 507 : g_return_val_if_fail (group_name != NULL, NULL);
1689 : :
1690 : 507 : group = g_key_file_lookup_group (key_file, group_name);
1691 : :
1692 : 507 : if (!group)
1693 : : {
1694 : 264 : g_set_error (error, G_KEY_FILE_ERROR,
1695 : : G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
1696 : : _("Key file does not have group “%s”"),
1697 : : group_name);
1698 : 264 : return NULL;
1699 : : }
1700 : :
1701 : 243 : num_keys = 0;
1702 : 14323 : for (tmp = group->key_value_pairs; tmp; tmp = tmp->next)
1703 : : {
1704 : : GKeyFileKeyValuePair *pair;
1705 : :
1706 : 14080 : pair = (GKeyFileKeyValuePair *) tmp->data;
1707 : :
1708 : 14080 : if (pair->key)
1709 : 13995 : num_keys++;
1710 : : }
1711 : :
1712 : 243 : keys = g_new (gchar *, num_keys + 1);
1713 : :
1714 : 243 : i = num_keys - 1;
1715 : 14323 : for (tmp = group->key_value_pairs; tmp; tmp = tmp->next)
1716 : : {
1717 : : GKeyFileKeyValuePair *pair;
1718 : :
1719 : 14080 : pair = (GKeyFileKeyValuePair *) tmp->data;
1720 : :
1721 : 14080 : if (pair->key)
1722 : : {
1723 : 13995 : keys[i] = g_strdup (pair->key);
1724 : 13995 : i--;
1725 : : }
1726 : : }
1727 : :
1728 : 243 : keys[num_keys] = NULL;
1729 : :
1730 : 243 : if (length)
1731 : 3 : *length = num_keys;
1732 : :
1733 : 243 : return keys;
1734 : : }
1735 : :
1736 : : /**
1737 : : * g_key_file_get_start_group:
1738 : : * @key_file: a key file
1739 : : *
1740 : : * Returns the name of the start group of the file.
1741 : : *
1742 : : * Returns: (nullable): The start group of the key file.
1743 : : *
1744 : : * Since: 2.6
1745 : : **/
1746 : : gchar *
1747 : 280 : g_key_file_get_start_group (GKeyFile *key_file)
1748 : : {
1749 : 280 : g_return_val_if_fail (key_file != NULL, NULL);
1750 : :
1751 : 280 : if (key_file->start_group)
1752 : 560 : return g_strdup (key_file->start_group->name);
1753 : :
1754 : 0 : return NULL;
1755 : : }
1756 : :
1757 : : /**
1758 : : * g_key_file_get_groups:
1759 : : * @key_file: a key file
1760 : : * @length: (out) (optional): return location for the number of returned groups,
1761 : : * or `NULL` to ignore
1762 : : *
1763 : : * Returns all groups in the key file loaded with @key_file.
1764 : : *
1765 : : * The array of returned groups will be `NULL`-terminated, so
1766 : : * @length may optionally be `NULL`.
1767 : : *
1768 : : * Returns: (array zero-terminated=1) (transfer full): a newly-allocated
1769 : : * `NULL`-terminated array of strings. Use [func@GLib.strfreev] to free it.
1770 : : * Since: 2.6
1771 : : **/
1772 : : gchar **
1773 : 10 : g_key_file_get_groups (GKeyFile *key_file,
1774 : : gsize *length)
1775 : : {
1776 : : GList *group_node;
1777 : : gchar **groups;
1778 : : gsize i, num_groups;
1779 : :
1780 : 10 : g_return_val_if_fail (key_file != NULL, NULL);
1781 : :
1782 : 10 : num_groups = g_list_length (key_file->groups);
1783 : :
1784 : 10 : g_return_val_if_fail (num_groups > 0, NULL);
1785 : :
1786 : 10 : group_node = g_list_last (key_file->groups);
1787 : :
1788 : 10 : g_return_val_if_fail (((GKeyFileGroup *) group_node->data)->name == NULL, NULL);
1789 : :
1790 : : /* Only need num_groups instead of num_groups + 1
1791 : : * because the first group of the file (last in the
1792 : : * list) is always the comment group at the top,
1793 : : * which we skip
1794 : : */
1795 : 10 : groups = g_new (gchar *, num_groups);
1796 : :
1797 : :
1798 : 10 : i = 0;
1799 : 10 : for (group_node = group_node->prev;
1800 : 25 : group_node != NULL;
1801 : 15 : group_node = group_node->prev)
1802 : : {
1803 : : GKeyFileGroup *group;
1804 : :
1805 : 15 : group = (GKeyFileGroup *) group_node->data;
1806 : :
1807 : 15 : g_warn_if_fail (group->name != NULL);
1808 : :
1809 : 30 : groups[i++] = g_strdup (group->name);
1810 : : }
1811 : 10 : groups[i] = NULL;
1812 : :
1813 : 10 : if (length)
1814 : 5 : *length = i;
1815 : :
1816 : 10 : return groups;
1817 : : }
1818 : :
1819 : : static void
1820 : 8938 : set_not_found_key_error (const char *group_name,
1821 : : const char *key,
1822 : : GError **error)
1823 : : {
1824 : 8938 : g_set_error (error, G_KEY_FILE_ERROR,
1825 : : G_KEY_FILE_ERROR_KEY_NOT_FOUND,
1826 : : _("Key file does not have key “%s” in group “%s”"),
1827 : : key, group_name);
1828 : 8938 : }
1829 : :
1830 : : /**
1831 : : * g_key_file_get_value:
1832 : : * @key_file: a key file
1833 : : * @group_name: a group name
1834 : : * @key: a key
1835 : : * @error: return location for a [struct@GLib.Error]
1836 : : *
1837 : : * Returns the raw value associated with @key under @group_name.
1838 : : *
1839 : : * Use [method@GLib.KeyFile.get_string] to retrieve an unescaped UTF-8 string.
1840 : : *
1841 : : * If the key cannot be found, [error@GLib.KeyFileError.KEY_NOT_FOUND]
1842 : : * is returned. If the @group_name cannot be found,
1843 : : * [error@GLib.KeyFileError.GROUP_NOT_FOUND] is returned.
1844 : : *
1845 : : * Returns: a newly allocated string or `NULL` if the specified
1846 : : * key cannot be found.
1847 : : *
1848 : : * Since: 2.6
1849 : : **/
1850 : : gchar *
1851 : 27533 : g_key_file_get_value (GKeyFile *key_file,
1852 : : const gchar *group_name,
1853 : : const gchar *key,
1854 : : GError **error)
1855 : : {
1856 : : GKeyFileGroup *group;
1857 : : GKeyFileKeyValuePair *pair;
1858 : 27533 : gchar *value = NULL;
1859 : :
1860 : 27533 : g_return_val_if_fail (key_file != NULL, NULL);
1861 : 27533 : g_return_val_if_fail (group_name != NULL, NULL);
1862 : 27533 : g_return_val_if_fail (key != NULL, NULL);
1863 : :
1864 : 27533 : group = g_key_file_lookup_group (key_file, group_name);
1865 : :
1866 : 27533 : if (!group)
1867 : : {
1868 : 164 : g_set_error (error, G_KEY_FILE_ERROR,
1869 : : G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
1870 : : _("Key file does not have group “%s”"),
1871 : : group_name);
1872 : 164 : return NULL;
1873 : : }
1874 : :
1875 : 27369 : pair = g_key_file_lookup_key_value_pair (key_file, group, key);
1876 : :
1877 : 27369 : if (pair)
1878 : 36954 : value = g_strdup (pair->value);
1879 : : else
1880 : 8892 : set_not_found_key_error (group_name, key, error);
1881 : :
1882 : 27369 : return value;
1883 : : }
1884 : :
1885 : : /**
1886 : : * g_key_file_set_value:
1887 : : * @key_file: a key file
1888 : : * @group_name: a group name
1889 : : * @key: a key
1890 : : * @value: a string
1891 : : *
1892 : : * Associates a new value with @key under @group_name.
1893 : : *
1894 : : * If @key cannot be found then it is created. If @group_name cannot
1895 : : * be found then it is created. To set an UTF-8 string which may contain
1896 : : * characters that need escaping (such as newlines or spaces), use
1897 : : * [method@GLib.KeyFile.set_string].
1898 : : *
1899 : : * Since: 2.6
1900 : : **/
1901 : : void
1902 : 365 : g_key_file_set_value (GKeyFile *key_file,
1903 : : const gchar *group_name,
1904 : : const gchar *key,
1905 : : const gchar *value)
1906 : : {
1907 : : GKeyFileGroup *group;
1908 : : GKeyFileKeyValuePair *pair;
1909 : :
1910 : 365 : g_return_if_fail (key_file != NULL);
1911 : 365 : g_return_if_fail (group_name != NULL && g_key_file_is_group_name (group_name));
1912 : 365 : g_return_if_fail (key != NULL && g_key_file_is_key_name (key, strlen (key)));
1913 : 365 : g_return_if_fail (value != NULL);
1914 : :
1915 : 365 : group = g_key_file_lookup_group (key_file, group_name);
1916 : :
1917 : 365 : if (!group)
1918 : : {
1919 : 94 : g_key_file_add_group (key_file, group_name, TRUE);
1920 : 94 : group = (GKeyFileGroup *) key_file->groups->data;
1921 : :
1922 : 94 : g_key_file_add_key (key_file, group, key, value);
1923 : : }
1924 : : else
1925 : : {
1926 : 271 : pair = g_key_file_lookup_key_value_pair (key_file, group, key);
1927 : :
1928 : 271 : if (!pair)
1929 : 179 : g_key_file_add_key (key_file, group, key, value);
1930 : : else
1931 : : {
1932 : 92 : g_free (pair->value);
1933 : 92 : pair->value = g_strdup (value);
1934 : : }
1935 : : }
1936 : : }
1937 : :
1938 : : /**
1939 : : * g_key_file_get_string:
1940 : : * @key_file: a key file
1941 : : * @group_name: a group name
1942 : : * @key: a key
1943 : : * @error: return location for a [struct@GLib.Error]
1944 : : *
1945 : : * Returns the string value associated with @key under @group_name.
1946 : : *
1947 : : * Unlike [method@GLib.KeyFile.get_value], this function handles escape
1948 : : * sequences like `\s`.
1949 : : *
1950 : : * If the key cannot be found, [error@GLib.KeyFileError.KEY_NOT_FOUND] is
1951 : : * returned. If the @group_name cannot be found,
1952 : : * [error@GLib.KeyFileError.GROUP_NOT_FOUND] is returned.
1953 : : *
1954 : : * Returns: a newly allocated string or `NULL` if the specified
1955 : : * key cannot be found.
1956 : : *
1957 : : * Since: 2.6
1958 : : **/
1959 : : gchar *
1960 : 8782 : g_key_file_get_string (GKeyFile *key_file,
1961 : : const gchar *group_name,
1962 : : const gchar *key,
1963 : : GError **error)
1964 : : {
1965 : : gchar *value, *string_value;
1966 : : GError *key_file_error;
1967 : :
1968 : 8782 : g_return_val_if_fail (key_file != NULL, NULL);
1969 : 8782 : g_return_val_if_fail (group_name != NULL, NULL);
1970 : 8782 : g_return_val_if_fail (key != NULL, NULL);
1971 : :
1972 : 8782 : key_file_error = NULL;
1973 : :
1974 : 8782 : value = g_key_file_get_value (key_file, group_name, key, &key_file_error);
1975 : :
1976 : 8782 : if (key_file_error)
1977 : : {
1978 : 5031 : g_propagate_error (error, key_file_error);
1979 : 5031 : return NULL;
1980 : : }
1981 : :
1982 : 3751 : if (!g_utf8_validate (value, -1, NULL))
1983 : : {
1984 : 2 : gchar *value_utf8 = g_utf8_make_valid (value, -1);
1985 : 2 : g_set_error (error, G_KEY_FILE_ERROR,
1986 : : G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
1987 : : _("Key file contains key “%s” with value “%s” "
1988 : : "which is not UTF-8"), key, value_utf8);
1989 : 2 : g_free (value_utf8);
1990 : 2 : g_free (value);
1991 : :
1992 : 2 : return NULL;
1993 : : }
1994 : :
1995 : 3749 : string_value = g_key_file_parse_value_as_string (key_file, value, NULL,
1996 : : &key_file_error);
1997 : 3749 : g_free (value);
1998 : :
1999 : 3749 : if (key_file_error)
2000 : : {
2001 : 6 : if (g_error_matches (key_file_error,
2002 : : G_KEY_FILE_ERROR,
2003 : : G_KEY_FILE_ERROR_INVALID_VALUE))
2004 : : {
2005 : 6 : g_set_error (error, G_KEY_FILE_ERROR,
2006 : : G_KEY_FILE_ERROR_INVALID_VALUE,
2007 : : _("Key file contains key “%s” "
2008 : : "which has a value that cannot be interpreted."),
2009 : : key);
2010 : 6 : g_error_free (key_file_error);
2011 : : }
2012 : : else
2013 : 0 : g_propagate_error (error, key_file_error);
2014 : : }
2015 : :
2016 : 3749 : return string_value;
2017 : : }
2018 : :
2019 : : /**
2020 : : * g_key_file_set_string:
2021 : : * @key_file: a key file
2022 : : * @group_name: a group name
2023 : : * @key: a key
2024 : : * @string: a string
2025 : : *
2026 : : * Associates a new string value with @key under @group_name.
2027 : : *
2028 : : * If @key cannot be found then it is created.
2029 : : * If @group_name cannot be found then it is created.
2030 : : * Unlike [method@GLib.KeyFile.set_value], this function handles characters
2031 : : * that need escaping, such as newlines.
2032 : : *
2033 : : * Since: 2.6
2034 : : **/
2035 : : void
2036 : 212 : g_key_file_set_string (GKeyFile *key_file,
2037 : : const gchar *group_name,
2038 : : const gchar *key,
2039 : : const gchar *string)
2040 : : {
2041 : : gchar *value;
2042 : :
2043 : 212 : g_return_if_fail (key_file != NULL);
2044 : 212 : g_return_if_fail (string != NULL);
2045 : :
2046 : 212 : value = g_key_file_parse_string_as_value (key_file, string, FALSE);
2047 : 212 : g_key_file_set_value (key_file, group_name, key, value);
2048 : 212 : g_free (value);
2049 : : }
2050 : :
2051 : : /**
2052 : : * g_key_file_get_string_list:
2053 : : * @key_file: a key file
2054 : : * @group_name: a group name
2055 : : * @key: a key
2056 : : * @length: (out) (optional): return location for the number of returned
2057 : : * strings, or `NULL` to ignore
2058 : : * @error: return location for a [struct@GLib.Error]
2059 : : *
2060 : : * Returns the values associated with @key under @group_name.
2061 : : *
2062 : : * If the key cannot be found, [error@GLib.KeyFileError.KEY_NOT_FOUND] is
2063 : : * returned. If the @group_name cannot be found,
2064 : : * [error@GLib.KeyFileError.GROUP_NOT_FOUND] is returned.
2065 : : *
2066 : : * Returns: (array zero-terminated=1 length=length) (element-type utf8) (transfer full):
2067 : : * a `NULL`-terminated string array or `NULL` if the specified
2068 : : * key cannot be found. The array should be freed with [func@GLib.strfreev].
2069 : : *
2070 : : * Since: 2.6
2071 : : **/
2072 : : gchar **
2073 : 16146 : g_key_file_get_string_list (GKeyFile *key_file,
2074 : : const gchar *group_name,
2075 : : const gchar *key,
2076 : : gsize *length,
2077 : : GError **error)
2078 : : {
2079 : 16146 : GError *key_file_error = NULL;
2080 : : gchar *value, *string_value, **values;
2081 : : gint i, len;
2082 : 16146 : GSList *p, *pieces = NULL;
2083 : :
2084 : 16146 : g_return_val_if_fail (key_file != NULL, NULL);
2085 : 16146 : g_return_val_if_fail (group_name != NULL, NULL);
2086 : 16146 : g_return_val_if_fail (key != NULL, NULL);
2087 : :
2088 : 16146 : if (length)
2089 : 256 : *length = 0;
2090 : :
2091 : 16146 : value = g_key_file_get_value (key_file, group_name, key, &key_file_error);
2092 : :
2093 : 16146 : if (key_file_error)
2094 : : {
2095 : 1802 : g_propagate_error (error, key_file_error);
2096 : 1802 : return NULL;
2097 : : }
2098 : :
2099 : 14344 : if (!g_utf8_validate (value, -1, NULL))
2100 : : {
2101 : 1 : gchar *value_utf8 = g_utf8_make_valid (value, -1);
2102 : 1 : g_set_error (error, G_KEY_FILE_ERROR,
2103 : : G_KEY_FILE_ERROR_UNKNOWN_ENCODING,
2104 : : _("Key file contains key “%s” with value “%s” "
2105 : : "which is not UTF-8"), key, value_utf8);
2106 : 1 : g_free (value_utf8);
2107 : 1 : g_free (value);
2108 : :
2109 : 1 : return NULL;
2110 : : }
2111 : :
2112 : 14343 : string_value = g_key_file_parse_value_as_string (key_file, value, &pieces, &key_file_error);
2113 : 14343 : g_free (value);
2114 : 14343 : g_free (string_value);
2115 : :
2116 : 14343 : if (key_file_error)
2117 : : {
2118 : 1 : if (g_error_matches (key_file_error,
2119 : : G_KEY_FILE_ERROR,
2120 : : G_KEY_FILE_ERROR_INVALID_VALUE))
2121 : : {
2122 : 1 : g_set_error (error, G_KEY_FILE_ERROR,
2123 : : G_KEY_FILE_ERROR_INVALID_VALUE,
2124 : : _("Key file contains key “%s” "
2125 : : "which has a value that cannot be interpreted."),
2126 : : key);
2127 : 1 : g_error_free (key_file_error);
2128 : : }
2129 : : else
2130 : 0 : g_propagate_error (error, key_file_error);
2131 : :
2132 : 1 : g_slist_free_full (pieces, g_free);
2133 : 1 : return NULL;
2134 : : }
2135 : :
2136 : 14342 : len = g_slist_length (pieces);
2137 : 14342 : values = g_new (gchar *, len + 1);
2138 : 30486 : for (p = pieces, i = 0; p; p = p->next)
2139 : 16144 : values[i++] = p->data;
2140 : 14342 : values[len] = NULL;
2141 : :
2142 : 14342 : g_slist_free (pieces);
2143 : :
2144 : 14342 : if (length)
2145 : 98 : *length = len;
2146 : :
2147 : 14342 : return values;
2148 : : }
2149 : :
2150 : : /**
2151 : : * g_key_file_set_string_list:
2152 : : * @key_file: a key file
2153 : : * @group_name: a group name
2154 : : * @key: a key
2155 : : * @list: (array zero-terminated=1 length=length) (element-type utf8): an array
2156 : : * of string values
2157 : : * @length: number of string values in @list
2158 : : *
2159 : : * Associates a list of string values for @key under @group_name.
2160 : : *
2161 : : * If @key cannot be found then it is created.
2162 : : * If @group_name cannot be found then it is created.
2163 : : *
2164 : : * Since: 2.6
2165 : : **/
2166 : : void
2167 : 91 : g_key_file_set_string_list (GKeyFile *key_file,
2168 : : const gchar *group_name,
2169 : : const gchar *key,
2170 : : const gchar * const list[],
2171 : : gsize length)
2172 : : {
2173 : : GString *value_list;
2174 : : gsize i;
2175 : :
2176 : 91 : g_return_if_fail (key_file != NULL);
2177 : 91 : g_return_if_fail (list != NULL || length == 0);
2178 : :
2179 : 91 : value_list = g_string_sized_new (length * 128);
2180 : 226 : for (i = 0; i < length && list[i] != NULL; i++)
2181 : : {
2182 : : gchar *value;
2183 : :
2184 : 135 : value = g_key_file_parse_string_as_value (key_file, list[i], TRUE);
2185 : : g_string_append (value_list, value);
2186 : 135 : g_string_append_c (value_list, key_file->list_separator);
2187 : :
2188 : 135 : g_free (value);
2189 : : }
2190 : :
2191 : 91 : g_key_file_set_value (key_file, group_name, key, value_list->str);
2192 : 91 : g_string_free (value_list, TRUE);
2193 : : }
2194 : :
2195 : : /**
2196 : : * g_key_file_set_locale_string:
2197 : : * @key_file: a key file
2198 : : * @group_name: a group name
2199 : : * @key: a key
2200 : : * @locale: a locale identifier
2201 : : * @string: a string
2202 : : *
2203 : : * Associates a string value for @key and @locale under @group_name.
2204 : : *
2205 : : * If the translation for @key cannot be found then it is created.
2206 : : *
2207 : : * If @locale is `C` then the untranslated value is set (since GLib 2.84).
2208 : : *
2209 : : * Since: 2.6
2210 : : **/
2211 : : void
2212 : 2 : g_key_file_set_locale_string (GKeyFile *key_file,
2213 : : const gchar *group_name,
2214 : : const gchar *key,
2215 : : const gchar *locale,
2216 : : const gchar *string)
2217 : : {
2218 : : gchar *full_key, *value;
2219 : :
2220 : 2 : g_return_if_fail (key_file != NULL);
2221 : 2 : g_return_if_fail (key != NULL);
2222 : 2 : g_return_if_fail (locale != NULL);
2223 : 2 : g_return_if_fail (string != NULL);
2224 : :
2225 : 2 : value = g_key_file_parse_string_as_value (key_file, string, FALSE);
2226 : 3 : full_key = g_strcmp0 (locale, "C") != 0 ? g_strdup_printf ("%s[%s]", key, locale) : g_strdup (key);
2227 : 2 : g_key_file_set_value (key_file, group_name, full_key, value);
2228 : 2 : g_free (full_key);
2229 : 2 : g_free (value);
2230 : : }
2231 : :
2232 : : /**
2233 : : * g_key_file_get_locale_string:
2234 : : * @key_file: a key file
2235 : : * @group_name: a group name
2236 : : * @key: a key
2237 : : * @locale: (nullable): a locale identifier or `NULL` to use the current locale
2238 : : * @error: return location for a [struct@GLib.Error]
2239 : : *
2240 : : * Returns the value associated with @key under @group_name
2241 : : * translated in the given @locale if available.
2242 : : *
2243 : : * If @locale is `C` then the untranslated value is returned (since GLib 2.84).
2244 : : *
2245 : : * If @locale is `NULL` then the current locale is assumed.
2246 : : *
2247 : : * If @locale is to be non-`NULL`, or if the current locale will change over
2248 : : * the lifetime of the [struct@GLib.KeyFile], it must be loaded with
2249 : : * [flags@GLib.KeyFileFlags.KEEP_TRANSLATIONS] in order to load strings for all
2250 : : * locales.
2251 : : *
2252 : : * If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
2253 : : * returned. If the value associated
2254 : : * with @key cannot be interpreted or no suitable translation can
2255 : : * be found then the untranslated value is returned.
2256 : : *
2257 : : * Returns: a newly allocated string or `NULL` if the specified
2258 : : * key cannot be found.
2259 : : *
2260 : : * Since: 2.6
2261 : : **/
2262 : : gchar *
2263 : 5637 : g_key_file_get_locale_string (GKeyFile *key_file,
2264 : : const gchar *group_name,
2265 : : const gchar *key,
2266 : : const gchar *locale,
2267 : : GError **error)
2268 : : {
2269 : : gchar *candidate_key, *translated_value;
2270 : : GError *key_file_error;
2271 : : gchar **languages;
2272 : 5637 : gboolean free_languages = FALSE;
2273 : : gint i;
2274 : :
2275 : 5637 : g_return_val_if_fail (key_file != NULL, NULL);
2276 : 5637 : g_return_val_if_fail (group_name != NULL, NULL);
2277 : 5637 : g_return_val_if_fail (key != NULL, NULL);
2278 : :
2279 : 5637 : candidate_key = NULL;
2280 : 5637 : translated_value = NULL;
2281 : 5637 : key_file_error = NULL;
2282 : :
2283 : 5637 : if (locale)
2284 : : {
2285 : 30 : languages = g_get_locale_variants (locale);
2286 : 30 : free_languages = TRUE;
2287 : : }
2288 : : else
2289 : : {
2290 : 5607 : languages = (gchar **) g_get_language_names ();
2291 : 5607 : free_languages = FALSE;
2292 : : }
2293 : :
2294 : 6901 : for (i = 0; languages[i]; i++)
2295 : : {
2296 : 6892 : if (g_strcmp0 (languages[i], "C") == 0)
2297 : 5513 : break;
2298 : :
2299 : 1379 : candidate_key = g_strdup_printf ("%s[%s]", key, languages[i]);
2300 : :
2301 : 1379 : translated_value = g_key_file_get_string (key_file,
2302 : : group_name,
2303 : : candidate_key, NULL);
2304 : 1379 : g_free (candidate_key);
2305 : :
2306 : 1379 : if (translated_value)
2307 : 115 : break;
2308 : : }
2309 : :
2310 : : /* Fallback to untranslated key
2311 : : */
2312 : 5637 : if (!translated_value)
2313 : : {
2314 : 5522 : translated_value = g_key_file_get_string (key_file, group_name, key,
2315 : : &key_file_error);
2316 : :
2317 : 5522 : if (!translated_value)
2318 : 2670 : g_propagate_error (error, key_file_error);
2319 : : }
2320 : :
2321 : 5637 : if (free_languages)
2322 : 30 : g_strfreev (languages);
2323 : :
2324 : 5637 : return translated_value;
2325 : : }
2326 : :
2327 : : /**
2328 : : * g_key_file_get_locale_for_key:
2329 : : * @key_file: a key file
2330 : : * @group_name: a group name
2331 : : * @key: a key
2332 : : * @locale: (nullable): a locale identifier or `NULL` to use the current locale
2333 : : *
2334 : : * Returns the actual locale which the result of
2335 : : * [method@GLib.KeyFile.get_locale_string] or
2336 : : * [method@GLib.KeyFile.get_locale_string_list] came from.
2337 : : *
2338 : : * If calling [method@GLib.KeyFile.get_locale_string] or
2339 : : * [method@GLib.KeyFile.get_locale_string_list] with exactly the same @key_file,
2340 : : * @group_name, @key and @locale, the result of those functions will
2341 : : * have originally been tagged with the locale that is the result of
2342 : : * this function.
2343 : : *
2344 : : * Returns: (nullable): the locale from the file, or `NULL` if the key was not
2345 : : * found or the entry in the file was was untranslated
2346 : : *
2347 : : * Since: 2.56
2348 : : */
2349 : : gchar *
2350 : 7 : g_key_file_get_locale_for_key (GKeyFile *key_file,
2351 : : const gchar *group_name,
2352 : : const gchar *key,
2353 : : const gchar *locale)
2354 : : {
2355 : 7 : gchar **languages_allocated = NULL;
2356 : : const gchar * const *languages;
2357 : 7 : gchar *result = NULL;
2358 : : gsize i;
2359 : :
2360 : 7 : g_return_val_if_fail (key_file != NULL, NULL);
2361 : 7 : g_return_val_if_fail (group_name != NULL, NULL);
2362 : 7 : g_return_val_if_fail (key != NULL, NULL);
2363 : :
2364 : 7 : if (locale != NULL)
2365 : : {
2366 : 4 : languages_allocated = g_get_locale_variants (locale);
2367 : 4 : languages = (const gchar * const *) languages_allocated;
2368 : : }
2369 : : else
2370 : 3 : languages = g_get_language_names ();
2371 : :
2372 : 11 : for (i = 0; languages[i] != NULL; i++)
2373 : : {
2374 : : gchar *candidate_key, *translated_value;
2375 : :
2376 : 10 : if (g_strcmp0 (languages[i], "C") == 0)
2377 : 3 : break;
2378 : :
2379 : 7 : candidate_key = g_strdup_printf ("%s[%s]", key, languages[i]);
2380 : 7 : translated_value = g_key_file_get_string (key_file, group_name, candidate_key, NULL);
2381 : 7 : g_free (translated_value);
2382 : 7 : g_free (candidate_key);
2383 : :
2384 : 7 : if (translated_value != NULL)
2385 : 3 : break;
2386 : : }
2387 : :
2388 : 7 : result = g_strdup (languages[i]);
2389 : :
2390 : 7 : g_strfreev (languages_allocated);
2391 : :
2392 : 7 : return result;
2393 : : }
2394 : :
2395 : : /**
2396 : : * g_key_file_get_locale_string_list:
2397 : : * @key_file: a key file
2398 : : * @group_name: a group name
2399 : : * @key: a key
2400 : : * @locale: (nullable): a locale identifier or `NULL` to use the current locale
2401 : : * @length: (out) (optional): return location for the number of returned strings
2402 : : * or `NULL` to ignore
2403 : : * @error: return location for a [struct@GLib.Error]
2404 : : *
2405 : : * Returns the values associated with @key under @group_name
2406 : : * translated in the given @locale if available.
2407 : : *
2408 : : * If @locale is `C` then the untranslated value is returned (since GLib 2.84).
2409 : : *
2410 : : * If @locale is `NULL` then the current locale is assumed.
2411 : : *
2412 : : * If @locale is to be non-`NULL`, or if the current locale will change over
2413 : : * the lifetime of the [struct@GLib.KeyFile], it must be loaded with
2414 : : * [flags@GLib.KeyFileFlags.KEEP_TRANSLATIONS] in order to load strings for all
2415 : : * locales.
2416 : : *
2417 : : * If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
2418 : : * returned. If the values associated
2419 : : * with @key cannot be interpreted or no suitable translations
2420 : : * can be found then the untranslated values are returned. The
2421 : : * returned array is `NULL`-terminated, so @length may optionally
2422 : : * be `NULL`.
2423 : : *
2424 : : * Returns: (array zero-terminated=1 length=length) (element-type utf8) (transfer full):
2425 : : * a newly allocated `NULL`-terminated string array or `NULL` if the key
2426 : : * isn’t found. The string array should be freed with [func@GLib.strfreev].
2427 : : *
2428 : : * Since: 2.6
2429 : : **/
2430 : : gchar **
2431 : 270 : g_key_file_get_locale_string_list (GKeyFile *key_file,
2432 : : const gchar *group_name,
2433 : : const gchar *key,
2434 : : const gchar *locale,
2435 : : gsize *length,
2436 : : GError **error)
2437 : : {
2438 : : GError *key_file_error;
2439 : : gchar **values, *value;
2440 : : char list_separator[2];
2441 : : gsize len;
2442 : :
2443 : 270 : g_return_val_if_fail (key_file != NULL, NULL);
2444 : 270 : g_return_val_if_fail (group_name != NULL, NULL);
2445 : 270 : g_return_val_if_fail (key != NULL, NULL);
2446 : :
2447 : 270 : key_file_error = NULL;
2448 : :
2449 : 270 : value = g_key_file_get_locale_string (key_file, group_name,
2450 : : key, locale,
2451 : : &key_file_error);
2452 : :
2453 : 270 : if (key_file_error)
2454 : 210 : g_propagate_error (error, key_file_error);
2455 : :
2456 : 270 : if (!value)
2457 : : {
2458 : 210 : if (length)
2459 : 0 : *length = 0;
2460 : 210 : return NULL;
2461 : : }
2462 : :
2463 : 60 : len = strlen (value);
2464 : 60 : if (value[len - 1] == key_file->list_separator)
2465 : 60 : value[len - 1] = '\0';
2466 : :
2467 : 60 : list_separator[0] = key_file->list_separator;
2468 : 60 : list_separator[1] = '\0';
2469 : 60 : values = g_strsplit (value, list_separator, 0);
2470 : :
2471 : 60 : g_free (value);
2472 : :
2473 : 60 : if (length)
2474 : 2 : *length = g_strv_length (values);
2475 : :
2476 : 60 : return values;
2477 : : }
2478 : :
2479 : : /**
2480 : : * g_key_file_set_locale_string_list:
2481 : : * @key_file: a key file
2482 : : * @group_name: a group name
2483 : : * @key: a key
2484 : : * @locale: a locale identifier
2485 : : * @list: (array zero-terminated=1 length=length): a `NULL`-terminated array of
2486 : : * locale string values
2487 : : * @length: the length of @list
2488 : : *
2489 : : * Associates a list of string values for @key and @locale under
2490 : : * @group_name.
2491 : : *
2492 : : * If @locale is `C` then the untranslated value is set (since GLib 2.84).
2493 : : *
2494 : : * If the translation for @key cannot be found then it is created.
2495 : : *
2496 : : * Since: 2.6
2497 : : **/
2498 : : void
2499 : 2 : g_key_file_set_locale_string_list (GKeyFile *key_file,
2500 : : const gchar *group_name,
2501 : : const gchar *key,
2502 : : const gchar *locale,
2503 : : const gchar * const list[],
2504 : : gsize length)
2505 : : {
2506 : : GString *value_list;
2507 : : gchar *full_key;
2508 : : gsize i;
2509 : :
2510 : 2 : g_return_if_fail (key_file != NULL);
2511 : 2 : g_return_if_fail (key != NULL);
2512 : 2 : g_return_if_fail (locale != NULL);
2513 : 2 : g_return_if_fail (length != 0);
2514 : :
2515 : 2 : value_list = g_string_sized_new (length * 128);
2516 : 6 : for (i = 0; i < length && list[i] != NULL; i++)
2517 : : {
2518 : : gchar *value;
2519 : :
2520 : 4 : value = g_key_file_parse_string_as_value (key_file, list[i], TRUE);
2521 : : g_string_append (value_list, value);
2522 : 4 : g_string_append_c (value_list, key_file->list_separator);
2523 : :
2524 : 4 : g_free (value);
2525 : : }
2526 : :
2527 : 2 : full_key = g_strcmp0 (locale, "C") != 0 ? g_strdup_printf ("%s[%s]", key, locale) : g_strdup (key);
2528 : 2 : g_key_file_set_value (key_file, group_name, full_key, value_list->str);
2529 : 2 : g_free (full_key);
2530 : 2 : g_string_free (value_list, TRUE);
2531 : : }
2532 : :
2533 : : /**
2534 : : * g_key_file_get_boolean:
2535 : : * @key_file: a key file
2536 : : * @group_name: a group name
2537 : : * @key: a key
2538 : : * @error: return location for a [struct@GLib.Error]
2539 : : *
2540 : : * Returns the value associated with @key under @group_name as a
2541 : : * boolean.
2542 : : *
2543 : : * If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
2544 : : * returned. Likewise, if the value associated with @key cannot be interpreted
2545 : : * as a boolean then [error@GLib.KeyFileError.INVALID_VALUE] is returned.
2546 : : *
2547 : : * Returns: the value associated with the key as a boolean,
2548 : : * or false if the key was not found or could not be parsed.
2549 : : *
2550 : : * Since: 2.6
2551 : : **/
2552 : : gboolean
2553 : 2463 : g_key_file_get_boolean (GKeyFile *key_file,
2554 : : const gchar *group_name,
2555 : : const gchar *key,
2556 : : GError **error)
2557 : : {
2558 : 2463 : GError *key_file_error = NULL;
2559 : : gchar *value;
2560 : : gboolean bool_value;
2561 : :
2562 : 2463 : g_return_val_if_fail (key_file != NULL, FALSE);
2563 : 2463 : g_return_val_if_fail (group_name != NULL, FALSE);
2564 : 2463 : g_return_val_if_fail (key != NULL, FALSE);
2565 : :
2566 : 2463 : value = g_key_file_get_value (key_file, group_name, key, &key_file_error);
2567 : :
2568 : 2463 : if (!value)
2569 : : {
2570 : 2209 : g_propagate_error (error, key_file_error);
2571 : 2209 : return FALSE;
2572 : : }
2573 : :
2574 : 254 : bool_value = g_key_file_parse_value_as_boolean (key_file, value,
2575 : : &key_file_error);
2576 : 254 : g_free (value);
2577 : :
2578 : 254 : if (key_file_error)
2579 : : {
2580 : 4 : if (g_error_matches (key_file_error,
2581 : : G_KEY_FILE_ERROR,
2582 : : G_KEY_FILE_ERROR_INVALID_VALUE))
2583 : : {
2584 : 4 : g_set_error (error, G_KEY_FILE_ERROR,
2585 : : G_KEY_FILE_ERROR_INVALID_VALUE,
2586 : : _("Key file contains key “%s” "
2587 : : "which has a value that cannot be interpreted."),
2588 : : key);
2589 : 4 : g_error_free (key_file_error);
2590 : : }
2591 : : else
2592 : 0 : g_propagate_error (error, key_file_error);
2593 : : }
2594 : :
2595 : 254 : return bool_value;
2596 : : }
2597 : :
2598 : : /**
2599 : : * g_key_file_set_boolean:
2600 : : * @key_file: a key file
2601 : : * @group_name: a group name
2602 : : * @key: a key
2603 : : * @value: true or false
2604 : : *
2605 : : * Associates a new boolean value with @key under @group_name.
2606 : : *
2607 : : * If @key cannot be found then it is created.
2608 : : *
2609 : : * Since: 2.6
2610 : : **/
2611 : : void
2612 : 37 : g_key_file_set_boolean (GKeyFile *key_file,
2613 : : const gchar *group_name,
2614 : : const gchar *key,
2615 : : gboolean value)
2616 : : {
2617 : : const gchar *result;
2618 : :
2619 : 37 : g_return_if_fail (key_file != NULL);
2620 : :
2621 : 37 : result = g_key_file_parse_boolean_as_value (key_file, value);
2622 : 37 : g_key_file_set_value (key_file, group_name, key, result);
2623 : : }
2624 : :
2625 : : /**
2626 : : * g_key_file_get_boolean_list:
2627 : : * @key_file: a key file
2628 : : * @group_name: a group name
2629 : : * @key: a key
2630 : : * @length: (out): the number of booleans returned
2631 : : * @error: return location for a [struct@GLib.Error]
2632 : : *
2633 : : * Returns the values associated with @key under @group_name as
2634 : : * booleans.
2635 : : *
2636 : : * If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
2637 : : * returned. Likewise, if the values associated with @key cannot be interpreted
2638 : : * as booleans then [error@GLib.KeyFileError.INVALID_VALUE] is returned.
2639 : : *
2640 : : * Returns: (array length=length) (element-type gboolean) (transfer container):
2641 : : * the values associated with the key as a list of booleans, or `NULL` if the
2642 : : * key was not found or could not be parsed. The returned list of booleans
2643 : : * should be freed with [func@GLib.free] when no longer needed.
2644 : : *
2645 : : * Since: 2.6
2646 : : **/
2647 : : gboolean *
2648 : 1 : g_key_file_get_boolean_list (GKeyFile *key_file,
2649 : : const gchar *group_name,
2650 : : const gchar *key,
2651 : : gsize *length,
2652 : : GError **error)
2653 : : {
2654 : : GError *key_file_error;
2655 : : gchar **values;
2656 : : gboolean *bool_values;
2657 : : gsize i, num_bools;
2658 : :
2659 : 1 : g_return_val_if_fail (key_file != NULL, NULL);
2660 : 1 : g_return_val_if_fail (group_name != NULL, NULL);
2661 : 1 : g_return_val_if_fail (key != NULL, NULL);
2662 : :
2663 : 1 : if (length)
2664 : 1 : *length = 0;
2665 : :
2666 : 1 : key_file_error = NULL;
2667 : :
2668 : 1 : values = g_key_file_get_string_list (key_file, group_name, key,
2669 : : &num_bools, &key_file_error);
2670 : :
2671 : 1 : if (key_file_error)
2672 : 0 : g_propagate_error (error, key_file_error);
2673 : :
2674 : 1 : if (!values)
2675 : 0 : return NULL;
2676 : :
2677 : 1 : bool_values = g_new (gboolean, num_bools);
2678 : :
2679 : 3 : for (i = 0; i < num_bools; i++)
2680 : : {
2681 : 4 : bool_values[i] = g_key_file_parse_value_as_boolean (key_file,
2682 : 2 : values[i],
2683 : : &key_file_error);
2684 : :
2685 : 2 : if (key_file_error)
2686 : : {
2687 : 0 : g_propagate_error (error, key_file_error);
2688 : 0 : g_strfreev (values);
2689 : 0 : g_free (bool_values);
2690 : :
2691 : 0 : return NULL;
2692 : : }
2693 : : }
2694 : 1 : g_strfreev (values);
2695 : :
2696 : 1 : if (length)
2697 : 1 : *length = num_bools;
2698 : :
2699 : 1 : return bool_values;
2700 : : }
2701 : :
2702 : : /**
2703 : : * g_key_file_set_boolean_list:
2704 : : * @key_file: a key file
2705 : : * @group_name: a group name
2706 : : * @key: a key
2707 : : * @list: (array length=length): an array of boolean values
2708 : : * @length: length of @list
2709 : : *
2710 : : * Associates a list of boolean values with @key under @group_name.
2711 : : *
2712 : : * If @key cannot be found then it is created.
2713 : : *
2714 : : * Since: 2.6
2715 : : **/
2716 : : void
2717 : 1 : g_key_file_set_boolean_list (GKeyFile *key_file,
2718 : : const gchar *group_name,
2719 : : const gchar *key,
2720 : : gboolean list[],
2721 : : gsize length)
2722 : : {
2723 : : GString *value_list;
2724 : : gsize i;
2725 : :
2726 : 1 : g_return_if_fail (key_file != NULL);
2727 : 1 : g_return_if_fail (list != NULL);
2728 : :
2729 : 1 : value_list = g_string_sized_new (length * 8);
2730 : 3 : for (i = 0; i < length; i++)
2731 : : {
2732 : : const gchar *value;
2733 : :
2734 : 2 : value = g_key_file_parse_boolean_as_value (key_file, list[i]);
2735 : :
2736 : : g_string_append (value_list, value);
2737 : 2 : g_string_append_c (value_list, key_file->list_separator);
2738 : : }
2739 : :
2740 : 1 : g_key_file_set_value (key_file, group_name, key, value_list->str);
2741 : 1 : g_string_free (value_list, TRUE);
2742 : : }
2743 : :
2744 : : /**
2745 : : * g_key_file_get_integer:
2746 : : * @key_file: a key file
2747 : : * @group_name: a group name
2748 : : * @key: a key
2749 : : * @error: return location for a [struct@GLib.Error]
2750 : : *
2751 : : * Returns the value associated with @key under @group_name as an
2752 : : * integer.
2753 : : *
2754 : : * If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
2755 : : * returned. Likewise, if the value associated with @key cannot be interpreted
2756 : : * as an integer, or is out of range for a `gint`, then
2757 : : * [error@GLib.KeyFileError.INVALID_VALUE] is returned.
2758 : : *
2759 : : * Returns: the value associated with the key as an integer, or
2760 : : * `0` if the key was not found or could not be parsed.
2761 : : *
2762 : : * Since: 2.6
2763 : : **/
2764 : : gint
2765 : 102 : g_key_file_get_integer (GKeyFile *key_file,
2766 : : const gchar *group_name,
2767 : : const gchar *key,
2768 : : GError **error)
2769 : : {
2770 : : GError *key_file_error;
2771 : : gchar *value;
2772 : : gint int_value;
2773 : :
2774 : 102 : g_return_val_if_fail (key_file != NULL, -1);
2775 : 102 : g_return_val_if_fail (group_name != NULL, -1);
2776 : 102 : g_return_val_if_fail (key != NULL, -1);
2777 : :
2778 : 102 : key_file_error = NULL;
2779 : :
2780 : 102 : value = g_key_file_get_value (key_file, group_name, key, &key_file_error);
2781 : :
2782 : 102 : if (key_file_error)
2783 : : {
2784 : 0 : g_propagate_error (error, key_file_error);
2785 : 0 : return 0;
2786 : : }
2787 : :
2788 : 102 : int_value = g_key_file_parse_value_as_integer (key_file, value,
2789 : : &key_file_error);
2790 : 102 : g_free (value);
2791 : :
2792 : 102 : if (key_file_error)
2793 : : {
2794 : 4 : if (g_error_matches (key_file_error,
2795 : : G_KEY_FILE_ERROR,
2796 : : G_KEY_FILE_ERROR_INVALID_VALUE))
2797 : : {
2798 : 4 : g_set_error (error, G_KEY_FILE_ERROR,
2799 : : G_KEY_FILE_ERROR_INVALID_VALUE,
2800 : : _("Key file contains key “%s” in group “%s” "
2801 : : "which has a value that cannot be interpreted."),
2802 : : key, group_name);
2803 : 4 : g_error_free (key_file_error);
2804 : : }
2805 : : else
2806 : 0 : g_propagate_error (error, key_file_error);
2807 : : }
2808 : :
2809 : 102 : return int_value;
2810 : : }
2811 : :
2812 : : /**
2813 : : * g_key_file_set_integer:
2814 : : * @key_file: a key file
2815 : : * @group_name: a group name
2816 : : * @key: a key
2817 : : * @value: an integer value
2818 : : *
2819 : : * Associates a new integer value with @key under @group_name.
2820 : : *
2821 : : * If @key cannot be found then it is created.
2822 : : *
2823 : : * Since: 2.6
2824 : : **/
2825 : : void
2826 : 2 : g_key_file_set_integer (GKeyFile *key_file,
2827 : : const gchar *group_name,
2828 : : const gchar *key,
2829 : : gint value)
2830 : : {
2831 : : gchar *result;
2832 : :
2833 : 2 : g_return_if_fail (key_file != NULL);
2834 : :
2835 : 2 : result = g_key_file_parse_integer_as_value (key_file, value);
2836 : 2 : g_key_file_set_value (key_file, group_name, key, result);
2837 : 2 : g_free (result);
2838 : : }
2839 : :
2840 : : /**
2841 : : * g_key_file_get_int64:
2842 : : * @key_file: a key file
2843 : : * @group_name: a group name
2844 : : * @key: a key
2845 : : * @error: return location for a [struct@GLib.Error]
2846 : : *
2847 : : * Returns the value associated with @key under @group_name as a signed
2848 : : * 64-bit integer.
2849 : : *
2850 : : * This is similar to [method@GLib.KeyFile.get_integer] but can return
2851 : : * 64-bit results without truncation.
2852 : : *
2853 : : * Returns: the value associated with the key as a signed 64-bit integer, or
2854 : : * `0` if the key was not found or could not be parsed.
2855 : : *
2856 : : * Since: 2.26
2857 : : */
2858 : : gint64
2859 : 1 : g_key_file_get_int64 (GKeyFile *key_file,
2860 : : const gchar *group_name,
2861 : : const gchar *key,
2862 : : GError **error)
2863 : : {
2864 : : gchar *s, *end;
2865 : : gint64 v;
2866 : :
2867 : 1 : g_return_val_if_fail (key_file != NULL, -1);
2868 : 1 : g_return_val_if_fail (group_name != NULL, -1);
2869 : 1 : g_return_val_if_fail (key != NULL, -1);
2870 : :
2871 : 1 : s = g_key_file_get_value (key_file, group_name, key, error);
2872 : :
2873 : 1 : if (s == NULL)
2874 : 0 : return 0;
2875 : :
2876 : 1 : v = g_ascii_strtoll (s, &end, 10);
2877 : :
2878 : 1 : if (*s == '\0' || *end != '\0')
2879 : : {
2880 : 0 : g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
2881 : : _("Key “%s” in group “%s” has value “%s” "
2882 : : "where %s was expected"),
2883 : : key, group_name, s, "int64");
2884 : 0 : g_free (s);
2885 : 0 : return 0;
2886 : : }
2887 : :
2888 : 1 : g_free (s);
2889 : 1 : return v;
2890 : : }
2891 : :
2892 : : /**
2893 : : * g_key_file_set_int64:
2894 : : * @key_file: a key file
2895 : : * @group_name: a group name
2896 : : * @key: a key
2897 : : * @value: an integer value
2898 : : *
2899 : : * Associates a new integer value with @key under @group_name.
2900 : : *
2901 : : * If @key cannot be found then it is created.
2902 : : *
2903 : : * Since: 2.26
2904 : : **/
2905 : : void
2906 : 1 : g_key_file_set_int64 (GKeyFile *key_file,
2907 : : const gchar *group_name,
2908 : : const gchar *key,
2909 : : gint64 value)
2910 : : {
2911 : : gchar *result;
2912 : :
2913 : 1 : g_return_if_fail (key_file != NULL);
2914 : :
2915 : 1 : result = g_strdup_printf ("%" G_GINT64_FORMAT, value);
2916 : 1 : g_key_file_set_value (key_file, group_name, key, result);
2917 : 1 : g_free (result);
2918 : : }
2919 : :
2920 : : /**
2921 : : * g_key_file_get_uint64:
2922 : : * @key_file: a key file
2923 : : * @group_name: a group name
2924 : : * @key: a key
2925 : : * @error: return location for a [struct@GLib.Error]
2926 : : *
2927 : : * Returns the value associated with @key under @group_name as an unsigned
2928 : : * 64-bit integer.
2929 : : *
2930 : : * This is similar to [method@GLib.KeyFile.get_integer] but can return
2931 : : * large positive results without truncation.
2932 : : *
2933 : : * Returns: the value associated with the key as an unsigned 64-bit integer,
2934 : : * or `0` if the key was not found or could not be parsed.
2935 : : *
2936 : : * Since: 2.26
2937 : : */
2938 : : guint64
2939 : 2 : g_key_file_get_uint64 (GKeyFile *key_file,
2940 : : const gchar *group_name,
2941 : : const gchar *key,
2942 : : GError **error)
2943 : : {
2944 : : gchar *s, *end;
2945 : : guint64 v;
2946 : :
2947 : 2 : g_return_val_if_fail (key_file != NULL, -1);
2948 : 2 : g_return_val_if_fail (group_name != NULL, -1);
2949 : 2 : g_return_val_if_fail (key != NULL, -1);
2950 : :
2951 : 2 : s = g_key_file_get_value (key_file, group_name, key, error);
2952 : :
2953 : 2 : if (s == NULL)
2954 : 0 : return 0;
2955 : :
2956 : 2 : v = g_ascii_strtoull (s, &end, 10);
2957 : :
2958 : 2 : if (*s == '\0' || *end != '\0')
2959 : : {
2960 : 0 : g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE,
2961 : : _("Key “%s” in group “%s” has value “%s” "
2962 : : "where %s was expected"),
2963 : : key, group_name, s, "uint64");
2964 : 0 : g_free (s);
2965 : 0 : return 0;
2966 : : }
2967 : :
2968 : 2 : g_free (s);
2969 : 2 : return v;
2970 : : }
2971 : :
2972 : : /**
2973 : : * g_key_file_set_uint64:
2974 : : * @key_file: a key file
2975 : : * @group_name: a group name
2976 : : * @key: a key
2977 : : * @value: an integer value
2978 : : *
2979 : : * Associates a new integer value with @key under @group_name.
2980 : : *
2981 : : * If @key cannot be found then it is created.
2982 : : *
2983 : : * Since: 2.26
2984 : : **/
2985 : : void
2986 : 1 : g_key_file_set_uint64 (GKeyFile *key_file,
2987 : : const gchar *group_name,
2988 : : const gchar *key,
2989 : : guint64 value)
2990 : : {
2991 : : gchar *result;
2992 : :
2993 : 1 : g_return_if_fail (key_file != NULL);
2994 : :
2995 : 1 : result = g_strdup_printf ("%" G_GUINT64_FORMAT, value);
2996 : 1 : g_key_file_set_value (key_file, group_name, key, result);
2997 : 1 : g_free (result);
2998 : : }
2999 : :
3000 : : /**
3001 : : * g_key_file_get_integer_list:
3002 : : * @key_file: a key file
3003 : : * @group_name: a group name
3004 : : * @key: a key
3005 : : * @length: (out): the number of integers returned
3006 : : * @error: return location for a [struct@GLib.Error]
3007 : : *
3008 : : * Returns the values associated with @key under @group_name as
3009 : : * integers.
3010 : : *
3011 : : * If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
3012 : : * returned. Likewise, if the values associated with @key cannot be interpreted
3013 : : * as integers, or are out of range for `gint`, then
3014 : : * [error@GLib.KeyFileError.INVALID_VALUE] is returned.
3015 : : *
3016 : : * Returns: (array length=length) (element-type gint) (transfer container):
3017 : : * the values associated with the key as a list of integers, or `NULL` if
3018 : : * the key was not found or could not be parsed. The returned list of
3019 : : * integers should be freed with [func@GLib.free] when no longer needed.
3020 : : *
3021 : : * Since: 2.6
3022 : : **/
3023 : : gint *
3024 : 3 : g_key_file_get_integer_list (GKeyFile *key_file,
3025 : : const gchar *group_name,
3026 : : const gchar *key,
3027 : : gsize *length,
3028 : : GError **error)
3029 : : {
3030 : 3 : GError *key_file_error = NULL;
3031 : : gchar **values;
3032 : : gint *int_values;
3033 : : gsize i, num_ints;
3034 : :
3035 : 3 : g_return_val_if_fail (key_file != NULL, NULL);
3036 : 3 : g_return_val_if_fail (group_name != NULL, NULL);
3037 : 3 : g_return_val_if_fail (key != NULL, NULL);
3038 : :
3039 : 3 : if (length)
3040 : 3 : *length = 0;
3041 : :
3042 : 3 : values = g_key_file_get_string_list (key_file, group_name, key,
3043 : : &num_ints, &key_file_error);
3044 : :
3045 : 3 : if (key_file_error)
3046 : 0 : g_propagate_error (error, key_file_error);
3047 : :
3048 : 3 : if (!values)
3049 : 0 : return NULL;
3050 : :
3051 : 3 : int_values = g_new (gint, num_ints);
3052 : :
3053 : 12 : for (i = 0; i < num_ints; i++)
3054 : : {
3055 : 18 : int_values[i] = g_key_file_parse_value_as_integer (key_file,
3056 : 9 : values[i],
3057 : : &key_file_error);
3058 : :
3059 : 9 : if (key_file_error)
3060 : : {
3061 : 0 : g_propagate_error (error, key_file_error);
3062 : 0 : g_strfreev (values);
3063 : 0 : g_free (int_values);
3064 : :
3065 : 0 : return NULL;
3066 : : }
3067 : : }
3068 : 3 : g_strfreev (values);
3069 : :
3070 : 3 : if (length)
3071 : 3 : *length = num_ints;
3072 : :
3073 : 3 : return int_values;
3074 : : }
3075 : :
3076 : : /**
3077 : : * g_key_file_set_integer_list:
3078 : : * @key_file: a key file
3079 : : * @group_name: a group name
3080 : : * @key: a key
3081 : : * @list: (array length=length): an array of integer values
3082 : : * @length: number of integer values in @list
3083 : : *
3084 : : * Associates a list of integer values with @key under @group_name.
3085 : : *
3086 : : * If @key cannot be found then it is created.
3087 : : *
3088 : : * Since: 2.6
3089 : : **/
3090 : : void
3091 : 2 : g_key_file_set_integer_list (GKeyFile *key_file,
3092 : : const gchar *group_name,
3093 : : const gchar *key,
3094 : : gint list[],
3095 : : gsize length)
3096 : : {
3097 : : GString *values;
3098 : : gsize i;
3099 : :
3100 : 2 : g_return_if_fail (key_file != NULL);
3101 : 2 : g_return_if_fail (list != NULL);
3102 : :
3103 : 2 : values = g_string_sized_new (length * 16);
3104 : 8 : for (i = 0; i < length; i++)
3105 : : {
3106 : : gchar *value;
3107 : :
3108 : 6 : value = g_key_file_parse_integer_as_value (key_file, list[i]);
3109 : :
3110 : : g_string_append (values, value);
3111 : 6 : g_string_append_c (values, key_file->list_separator);
3112 : :
3113 : 6 : g_free (value);
3114 : : }
3115 : :
3116 : 2 : g_key_file_set_value (key_file, group_name, key, values->str);
3117 : 2 : g_string_free (values, TRUE);
3118 : : }
3119 : :
3120 : : /**
3121 : : * g_key_file_get_double:
3122 : : * @key_file: a key file
3123 : : * @group_name: a group name
3124 : : * @key: a key
3125 : : * @error: return location for a [struct@GLib.Error]
3126 : : *
3127 : : * Returns the value associated with @key under @group_name as a double.
3128 : : *
3129 : : * If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
3130 : : * returned. Likewise, if the value associated with @key cannot be interpreted
3131 : : * as a double then [error@GLib.KeyFileError.INVALID_VALUE] is returned.
3132 : : *
3133 : : * Returns: the value associated with the key as a double, or
3134 : : * `0.0` if the key was not found or could not be parsed.
3135 : : *
3136 : : * Since: 2.12
3137 : : **/
3138 : : gdouble
3139 : 7 : g_key_file_get_double (GKeyFile *key_file,
3140 : : const gchar *group_name,
3141 : : const gchar *key,
3142 : : GError **error)
3143 : : {
3144 : : GError *key_file_error;
3145 : : gchar *value;
3146 : : gdouble double_value;
3147 : :
3148 : 7 : g_return_val_if_fail (key_file != NULL, -1);
3149 : 7 : g_return_val_if_fail (group_name != NULL, -1);
3150 : 7 : g_return_val_if_fail (key != NULL, -1);
3151 : :
3152 : 7 : key_file_error = NULL;
3153 : :
3154 : 7 : value = g_key_file_get_value (key_file, group_name, key, &key_file_error);
3155 : :
3156 : 7 : if (key_file_error)
3157 : : {
3158 : 0 : g_propagate_error (error, key_file_error);
3159 : 0 : return 0;
3160 : : }
3161 : :
3162 : 7 : double_value = g_key_file_parse_value_as_double (key_file, value,
3163 : : &key_file_error);
3164 : 7 : g_free (value);
3165 : :
3166 : 7 : if (key_file_error)
3167 : : {
3168 : 4 : if (g_error_matches (key_file_error,
3169 : : G_KEY_FILE_ERROR,
3170 : : G_KEY_FILE_ERROR_INVALID_VALUE))
3171 : : {
3172 : 4 : g_set_error (error, G_KEY_FILE_ERROR,
3173 : : G_KEY_FILE_ERROR_INVALID_VALUE,
3174 : : _("Key file contains key “%s” in group “%s” "
3175 : : "which has a value that cannot be interpreted."),
3176 : : key, group_name);
3177 : 4 : g_error_free (key_file_error);
3178 : : }
3179 : : else
3180 : 0 : g_propagate_error (error, key_file_error);
3181 : : }
3182 : :
3183 : 7 : return double_value;
3184 : : }
3185 : :
3186 : : /**
3187 : : * g_key_file_set_double:
3188 : : * @key_file: a key file
3189 : : * @group_name: a group name
3190 : : * @key: a key
3191 : : * @value: a double value
3192 : : *
3193 : : * Associates a new double value with @key under @group_name.
3194 : : *
3195 : : * If @key cannot be found then it is created.
3196 : : *
3197 : : * Since: 2.12
3198 : : **/
3199 : : void
3200 : 1 : g_key_file_set_double (GKeyFile *key_file,
3201 : : const gchar *group_name,
3202 : : const gchar *key,
3203 : : gdouble value)
3204 : : {
3205 : : gchar result[G_ASCII_DTOSTR_BUF_SIZE];
3206 : :
3207 : 1 : g_return_if_fail (key_file != NULL);
3208 : :
3209 : 1 : g_ascii_dtostr (result, sizeof (result), value);
3210 : 1 : g_key_file_set_value (key_file, group_name, key, result);
3211 : : }
3212 : :
3213 : : /**
3214 : : * g_key_file_get_double_list:
3215 : : * @key_file: a key file
3216 : : * @group_name: a group name
3217 : : * @key: a key
3218 : : * @length: (out): the number of doubles returned
3219 : : * @error: return location for a [struct@GLib.Error]
3220 : : *
3221 : : * Returns the values associated with @key under @group_name as
3222 : : * doubles.
3223 : : *
3224 : : * If @key cannot be found then [error@GLib.KeyFileError.KEY_NOT_FOUND] is
3225 : : * returned. Likewise, if the values associated with @key cannot be interpreted
3226 : : * as doubles then [error@GLib.KeyFileError.INVALID_VALUE] is returned.
3227 : : *
3228 : : * Returns: (array length=length) (element-type gdouble) (transfer container):
3229 : : * the values associated with the key as a list of doubles, or `NULL` if the
3230 : : * key was not found or could not be parsed. The returned list of doubles
3231 : : * should be freed with [func@GLib.free] when no longer needed.
3232 : : *
3233 : : * Since: 2.12
3234 : : **/
3235 : : gdouble *
3236 : 3 : g_key_file_get_double_list (GKeyFile *key_file,
3237 : : const gchar *group_name,
3238 : : const gchar *key,
3239 : : gsize *length,
3240 : : GError **error)
3241 : : {
3242 : 3 : GError *key_file_error = NULL;
3243 : : gchar **values;
3244 : : gdouble *double_values;
3245 : : gsize i, num_doubles;
3246 : :
3247 : 3 : g_return_val_if_fail (key_file != NULL, NULL);
3248 : 3 : g_return_val_if_fail (group_name != NULL, NULL);
3249 : 3 : g_return_val_if_fail (key != NULL, NULL);
3250 : :
3251 : 3 : if (length)
3252 : 3 : *length = 0;
3253 : :
3254 : 3 : values = g_key_file_get_string_list (key_file, group_name, key,
3255 : : &num_doubles, &key_file_error);
3256 : :
3257 : 3 : if (key_file_error)
3258 : 0 : g_propagate_error (error, key_file_error);
3259 : :
3260 : 3 : if (!values)
3261 : 0 : return NULL;
3262 : :
3263 : 3 : double_values = g_new (gdouble, num_doubles);
3264 : :
3265 : 10 : for (i = 0; i < num_doubles; i++)
3266 : : {
3267 : 14 : double_values[i] = g_key_file_parse_value_as_double (key_file,
3268 : 7 : values[i],
3269 : : &key_file_error);
3270 : :
3271 : 7 : if (key_file_error)
3272 : : {
3273 : 0 : g_propagate_error (error, key_file_error);
3274 : 0 : g_strfreev (values);
3275 : 0 : g_free (double_values);
3276 : :
3277 : 0 : return NULL;
3278 : : }
3279 : : }
3280 : 3 : g_strfreev (values);
3281 : :
3282 : 3 : if (length)
3283 : 3 : *length = num_doubles;
3284 : :
3285 : 3 : return double_values;
3286 : : }
3287 : :
3288 : : /**
3289 : : * g_key_file_set_double_list:
3290 : : * @key_file: a key file
3291 : : * @group_name: a group name
3292 : : * @key: a key
3293 : : * @list: (array length=length): an array of double values
3294 : : * @length: number of double values in @list
3295 : : *
3296 : : * Associates a list of double values with @key under @group_name.
3297 : : *
3298 : : * If @key cannot be found then it is created.
3299 : : *
3300 : : * Since: 2.12
3301 : : **/
3302 : : void
3303 : 2 : g_key_file_set_double_list (GKeyFile *key_file,
3304 : : const gchar *group_name,
3305 : : const gchar *key,
3306 : : gdouble list[],
3307 : : gsize length)
3308 : : {
3309 : : GString *values;
3310 : : gsize i;
3311 : :
3312 : 2 : g_return_if_fail (key_file != NULL);
3313 : 2 : g_return_if_fail (list != NULL);
3314 : :
3315 : 2 : values = g_string_sized_new (length * 16);
3316 : 6 : for (i = 0; i < length; i++)
3317 : : {
3318 : : gchar result[G_ASCII_DTOSTR_BUF_SIZE];
3319 : :
3320 : 4 : g_ascii_dtostr( result, sizeof (result), list[i] );
3321 : :
3322 : : g_string_append (values, result);
3323 : 4 : g_string_append_c (values, key_file->list_separator);
3324 : : }
3325 : :
3326 : 2 : g_key_file_set_value (key_file, group_name, key, values->str);
3327 : 2 : g_string_free (values, TRUE);
3328 : : }
3329 : :
3330 : : static gboolean
3331 : 2 : g_key_file_set_key_comment (GKeyFile *key_file,
3332 : : const gchar *group_name,
3333 : : const gchar *key,
3334 : : const gchar *comment,
3335 : : GError **error)
3336 : : {
3337 : : GKeyFileGroup *group;
3338 : : GKeyFileKeyValuePair *pair;
3339 : : GList *key_node, *comment_node, *tmp;
3340 : :
3341 : 2 : group = g_key_file_lookup_group (key_file, group_name);
3342 : 2 : if (!group)
3343 : : {
3344 : 0 : g_set_error (error, G_KEY_FILE_ERROR,
3345 : : G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3346 : : _("Key file does not have group “%s”"),
3347 : : group_name ? group_name : "(null)");
3348 : :
3349 : 0 : return FALSE;
3350 : : }
3351 : :
3352 : : /* First find the key the comments are supposed to be
3353 : : * associated with
3354 : : */
3355 : 2 : key_node = g_key_file_lookup_key_value_pair_node (key_file, group, key);
3356 : :
3357 : 2 : if (key_node == NULL)
3358 : : {
3359 : 0 : set_not_found_key_error (group->name, key, error);
3360 : 0 : return FALSE;
3361 : : }
3362 : :
3363 : : /* Then find all the comments already associated with the
3364 : : * key and free them
3365 : : */
3366 : 2 : tmp = key_node->next;
3367 : 4 : while (tmp != NULL)
3368 : : {
3369 : 4 : pair = (GKeyFileKeyValuePair *) tmp->data;
3370 : :
3371 : 4 : if (pair->key != NULL)
3372 : 2 : break;
3373 : :
3374 : 2 : comment_node = tmp;
3375 : 2 : tmp = tmp->next;
3376 : 2 : g_key_file_remove_key_value_pair_node (key_file, group,
3377 : : comment_node);
3378 : : }
3379 : :
3380 : 2 : if (comment == NULL)
3381 : 1 : return TRUE;
3382 : :
3383 : : /* Now we can add our new comment
3384 : : */
3385 : 1 : pair = g_new (GKeyFileKeyValuePair, 1);
3386 : 1 : pair->key = NULL;
3387 : 1 : pair->value = g_key_file_parse_comment_as_value (key_file, comment);
3388 : :
3389 : 1 : key_node = g_list_insert (key_node, pair, 1);
3390 : : (void) key_node;
3391 : :
3392 : 1 : return TRUE;
3393 : : }
3394 : :
3395 : : static gboolean
3396 : 3 : g_key_file_set_top_comment (GKeyFile *key_file,
3397 : : const gchar *comment,
3398 : : GError **error)
3399 : : {
3400 : : GList *group_node;
3401 : : GKeyFileGroup *group;
3402 : : GKeyFileKeyValuePair *pair;
3403 : :
3404 : : /* The last group in the list should be the top (comments only)
3405 : : * group in the file
3406 : : */
3407 : 3 : g_warn_if_fail (key_file->groups != NULL);
3408 : 3 : group_node = g_list_last (key_file->groups);
3409 : 3 : group = (GKeyFileGroup *) group_node->data;
3410 : 3 : g_warn_if_fail (group->name == NULL);
3411 : :
3412 : : /* Note all keys must be comments at the top of
3413 : : * the file, so we can just free it all.
3414 : : */
3415 : 3 : g_list_free_full (group->key_value_pairs, (GDestroyNotify) g_key_file_key_value_pair_free);
3416 : 3 : group->key_value_pairs = NULL;
3417 : :
3418 : 3 : if (comment == NULL)
3419 : 1 : return TRUE;
3420 : :
3421 : 2 : pair = g_new (GKeyFileKeyValuePair, 1);
3422 : 2 : pair->key = NULL;
3423 : 2 : pair->value = g_key_file_parse_comment_as_value (key_file, comment);
3424 : :
3425 : 2 : group->key_value_pairs =
3426 : 2 : g_list_prepend (group->key_value_pairs, pair);
3427 : :
3428 : 2 : return TRUE;
3429 : : }
3430 : :
3431 : : static gboolean
3432 : 2 : g_key_file_set_group_comment (GKeyFile *key_file,
3433 : : const gchar *group_name,
3434 : : const gchar *comment,
3435 : : GError **error)
3436 : : {
3437 : : GKeyFileGroup *group;
3438 : : GList *group_node;
3439 : : GKeyFileKeyValuePair *pair;
3440 : :
3441 : 2 : g_return_val_if_fail (group_name != NULL && g_key_file_is_group_name (group_name), FALSE);
3442 : :
3443 : 2 : group = g_key_file_lookup_group (key_file, group_name);
3444 : 2 : if (!group)
3445 : : {
3446 : 0 : g_set_error (error, G_KEY_FILE_ERROR,
3447 : : G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3448 : : _("Key file does not have group “%s”"),
3449 : : group_name);
3450 : :
3451 : 0 : return FALSE;
3452 : : }
3453 : :
3454 : 2 : if (group == key_file->start_group)
3455 : 1 : return g_key_file_set_top_comment (key_file, comment, error);
3456 : :
3457 : : /* First remove any existing comment
3458 : : */
3459 : 1 : group_node = g_key_file_lookup_group_node (key_file, group_name);
3460 : 1 : group = group_node->next->data;
3461 : 3 : for (GList *lp = group->key_value_pairs; lp != NULL; )
3462 : : {
3463 : 3 : GList *lnext = lp->next;
3464 : 3 : pair = lp->data;
3465 : 3 : if (pair->key != NULL)
3466 : 1 : break;
3467 : :
3468 : 2 : g_key_file_remove_key_value_pair_node (key_file, group, lp);
3469 : 2 : lp = lnext;
3470 : : }
3471 : :
3472 : 1 : if (comment == NULL)
3473 : 1 : return TRUE;
3474 : :
3475 : : /* Now we can add our new comment
3476 : : */
3477 : 0 : pair = g_new (GKeyFileKeyValuePair, 1);
3478 : 0 : pair->key = NULL;
3479 : 0 : pair->value = g_key_file_parse_comment_as_value (key_file, comment);
3480 : 0 : group->key_value_pairs = g_list_prepend (group->key_value_pairs, pair);
3481 : :
3482 : 0 : return TRUE;
3483 : : }
3484 : :
3485 : : /**
3486 : : * g_key_file_set_comment:
3487 : : * @key_file: a key file
3488 : : * @group_name: (nullable): a group name, or `NULL` to write a top-level comment
3489 : : * @key: (nullable): a key, or `NULL` to write a group comment
3490 : : * @comment: a comment
3491 : : * @error: return location for a [struct@GLib.Error]
3492 : : *
3493 : : * Places a comment above @key from @group_name.
3494 : : *
3495 : : * If @key is `NULL` then @comment will be written above @group_name.
3496 : : * If both @key and @group_name are `NULL`, then @comment will be
3497 : : * written above the first group in the file.
3498 : : *
3499 : : * Passing a non-existent @group_name or @key to this function returns
3500 : : * false and populates @error. (In contrast, passing a non-existent
3501 : : * `group_name` or `key` to [method@GLib.KeyFile.set_string]
3502 : : * creates the associated group name and key.)
3503 : : *
3504 : : * Note that this function prepends a `#` comment marker to
3505 : : * each line of @comment.
3506 : : *
3507 : : * Returns: true if the comment was written, false otherwise
3508 : : *
3509 : : * Since: 2.6
3510 : : **/
3511 : : gboolean
3512 : 3 : g_key_file_set_comment (GKeyFile *key_file,
3513 : : const gchar *group_name,
3514 : : const gchar *key,
3515 : : const gchar *comment,
3516 : : GError **error)
3517 : : {
3518 : 3 : g_return_val_if_fail (key_file != NULL, FALSE);
3519 : :
3520 : 3 : if (group_name != NULL && key != NULL)
3521 : : {
3522 : 1 : if (!g_key_file_set_key_comment (key_file, group_name, key, comment, error))
3523 : 0 : return FALSE;
3524 : : }
3525 : 2 : else if (group_name != NULL)
3526 : : {
3527 : 1 : if (!g_key_file_set_group_comment (key_file, group_name, comment, error))
3528 : 0 : return FALSE;
3529 : : }
3530 : : else
3531 : : {
3532 : 1 : if (!g_key_file_set_top_comment (key_file, comment, error))
3533 : 0 : return FALSE;
3534 : : }
3535 : :
3536 : 3 : return TRUE;
3537 : : }
3538 : :
3539 : : static gchar *
3540 : 4 : g_key_file_get_key_comment (GKeyFile *key_file,
3541 : : const gchar *group_name,
3542 : : const gchar *key,
3543 : : GError **error)
3544 : : {
3545 : : GKeyFileGroup *group;
3546 : : GKeyFileKeyValuePair *pair;
3547 : : GList *key_node, *tmp;
3548 : : GString *string;
3549 : : gchar *comment;
3550 : :
3551 : 4 : g_return_val_if_fail (group_name != NULL && g_key_file_is_group_name (group_name), NULL);
3552 : :
3553 : 4 : group = g_key_file_lookup_group (key_file, group_name);
3554 : 4 : if (!group)
3555 : : {
3556 : 0 : g_set_error (error, G_KEY_FILE_ERROR,
3557 : : G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3558 : : _("Key file does not have group “%s”"),
3559 : : group_name ? group_name : "(null)");
3560 : :
3561 : 0 : return NULL;
3562 : : }
3563 : :
3564 : : /* First find the key the comments are supposed to be
3565 : : * associated with
3566 : : */
3567 : 4 : key_node = g_key_file_lookup_key_value_pair_node (key_file, group, key);
3568 : :
3569 : 4 : if (key_node == NULL)
3570 : : {
3571 : 0 : set_not_found_key_error (group->name, key, error);
3572 : 0 : return NULL;
3573 : : }
3574 : :
3575 : 4 : string = NULL;
3576 : :
3577 : : /* Then find all the comments already associated with the
3578 : : * key and concatenate them.
3579 : : */
3580 : 4 : tmp = key_node->next;
3581 : 4 : if (!key_node->next)
3582 : 0 : return NULL;
3583 : :
3584 : 4 : pair = (GKeyFileKeyValuePair *) tmp->data;
3585 : 4 : if (pair->key != NULL)
3586 : 1 : return NULL;
3587 : :
3588 : 4 : while (tmp->next)
3589 : : {
3590 : 4 : pair = (GKeyFileKeyValuePair *) tmp->next->data;
3591 : :
3592 : 4 : if (pair->key != NULL)
3593 : 3 : break;
3594 : :
3595 : 1 : tmp = tmp->next;
3596 : : }
3597 : :
3598 : 7 : while (tmp != key_node)
3599 : : {
3600 : 4 : pair = (GKeyFileKeyValuePair *) tmp->data;
3601 : :
3602 : 4 : if (string == NULL)
3603 : 3 : string = g_string_sized_new (512);
3604 : :
3605 : 4 : comment = g_key_file_parse_value_as_comment (key_file, pair->value,
3606 : 4 : (tmp->prev == key_node));
3607 : 4 : g_string_append (string, comment);
3608 : 4 : g_free (comment);
3609 : :
3610 : 4 : tmp = tmp->prev;
3611 : : }
3612 : :
3613 : 3 : if (string != NULL)
3614 : 3 : comment = g_string_free_and_steal (g_steal_pointer (&string));
3615 : : else
3616 : 0 : comment = NULL;
3617 : :
3618 : 3 : return comment;
3619 : : }
3620 : :
3621 : : static gchar *
3622 : 14 : get_group_comment (GKeyFile *key_file,
3623 : : GKeyFileGroup *group,
3624 : : GError **error)
3625 : : {
3626 : : GString *string;
3627 : : GList *tmp;
3628 : : gchar *comment;
3629 : :
3630 : 14 : string = NULL;
3631 : :
3632 : 14 : tmp = group->key_value_pairs;
3633 : 27 : while (tmp)
3634 : : {
3635 : : GKeyFileKeyValuePair *pair;
3636 : :
3637 : 24 : pair = (GKeyFileKeyValuePair *) tmp->data;
3638 : :
3639 : 24 : if (pair->key != NULL)
3640 : : {
3641 : 6 : tmp = tmp->prev;
3642 : 6 : break;
3643 : : }
3644 : :
3645 : 18 : if (tmp->next == NULL)
3646 : 5 : break;
3647 : :
3648 : 13 : tmp = tmp->next;
3649 : : }
3650 : :
3651 : 32 : while (tmp != NULL)
3652 : : {
3653 : : GKeyFileKeyValuePair *pair;
3654 : :
3655 : 18 : pair = (GKeyFileKeyValuePair *) tmp->data;
3656 : :
3657 : 18 : if (string == NULL)
3658 : 9 : string = g_string_sized_new (512);
3659 : :
3660 : 18 : comment = g_key_file_parse_value_as_comment (key_file, pair->value,
3661 : 18 : (tmp->prev == NULL));
3662 : : g_string_append (string, comment);
3663 : 18 : g_free (comment);
3664 : :
3665 : 18 : tmp = tmp->prev;
3666 : : }
3667 : :
3668 : 14 : if (string != NULL)
3669 : 9 : return g_string_free (string, FALSE);
3670 : :
3671 : 5 : return NULL;
3672 : : }
3673 : :
3674 : : static gchar *
3675 : 12 : g_key_file_get_group_comment (GKeyFile *key_file,
3676 : : const gchar *group_name,
3677 : : GError **error)
3678 : : {
3679 : : GList *group_node;
3680 : : GKeyFileGroup *group;
3681 : :
3682 : 12 : group = g_key_file_lookup_group (key_file, group_name);
3683 : 12 : if (!group)
3684 : : {
3685 : 1 : g_set_error (error, G_KEY_FILE_ERROR,
3686 : : G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3687 : : _("Key file does not have group “%s”"),
3688 : : group_name ? group_name : "(null)");
3689 : :
3690 : 1 : return NULL;
3691 : : }
3692 : :
3693 : 11 : group_node = g_key_file_lookup_group_node (key_file, group_name);
3694 : 11 : group_node = group_node->next;
3695 : 11 : group = (GKeyFileGroup *)group_node->data;
3696 : 11 : return get_group_comment (key_file, group, error);
3697 : : }
3698 : :
3699 : : static gchar *
3700 : 3 : g_key_file_get_top_comment (GKeyFile *key_file,
3701 : : GError **error)
3702 : : {
3703 : : GList *group_node;
3704 : : GKeyFileGroup *group;
3705 : :
3706 : : /* The last group in the list should be the top (comments only)
3707 : : * group in the file
3708 : : */
3709 : 3 : g_warn_if_fail (key_file->groups != NULL);
3710 : 3 : group_node = g_list_last (key_file->groups);
3711 : 3 : group = (GKeyFileGroup *) group_node->data;
3712 : 3 : g_warn_if_fail (group->name == NULL);
3713 : :
3714 : 3 : return get_group_comment (key_file, group, error);
3715 : : }
3716 : :
3717 : : /**
3718 : : * g_key_file_get_comment:
3719 : : * @key_file: a key file
3720 : : * @group_name: (nullable): a group name, or `NULL` to get a top-level comment
3721 : : * @key: (nullable): a key, or `NULL` to get a group comment
3722 : : * @error: return location for a [struct@GLib.Error]
3723 : : *
3724 : : * Retrieves a comment above @key from @group_name.
3725 : : *
3726 : : * If @key is `NULL` then @comment will be read from above
3727 : : * @group_name. If both @key and @group_name are `NULL`, then
3728 : : * @comment will be read from above the first group in the file.
3729 : : *
3730 : : * Note that the returned string does not include the `#` comment markers,
3731 : : * but does include any whitespace after them (on each line). It includes
3732 : : * the line breaks between lines, but does not include the final line break.
3733 : : *
3734 : : * Returns: a comment that should be freed with [func@GLib.free]
3735 : : *
3736 : : * Since: 2.6
3737 : : **/
3738 : : gchar *
3739 : 19 : g_key_file_get_comment (GKeyFile *key_file,
3740 : : const gchar *group_name,
3741 : : const gchar *key,
3742 : : GError **error)
3743 : : {
3744 : 19 : g_return_val_if_fail (key_file != NULL, NULL);
3745 : :
3746 : 19 : if (group_name != NULL && key != NULL)
3747 : 4 : return g_key_file_get_key_comment (key_file, group_name, key, error);
3748 : 15 : else if (group_name != NULL)
3749 : 12 : return g_key_file_get_group_comment (key_file, group_name, error);
3750 : : else
3751 : 3 : return g_key_file_get_top_comment (key_file, error);
3752 : : }
3753 : :
3754 : : /**
3755 : : * g_key_file_remove_comment:
3756 : : * @key_file: a key file
3757 : : * @group_name: (nullable): a group name, or `NULL` to get a top-level comment
3758 : : * @key: (nullable): a key, or `NULL` to get a group comment
3759 : : * @error: return location for a [struct@GLib.Error]
3760 : : *
3761 : : * Removes a comment above @key from @group_name.
3762 : : *
3763 : : * If @key is `NULL` then @comment will be removed above @group_name.
3764 : : * If both @key and @group_name are `NULL`, then @comment will
3765 : : * be removed above the first group in the file.
3766 : : *
3767 : : * Returns: true if the comment was removed, false otherwise
3768 : : *
3769 : : * Since: 2.6
3770 : : **/
3771 : :
3772 : : gboolean
3773 : 3 : g_key_file_remove_comment (GKeyFile *key_file,
3774 : : const gchar *group_name,
3775 : : const gchar *key,
3776 : : GError **error)
3777 : : {
3778 : 3 : g_return_val_if_fail (key_file != NULL, FALSE);
3779 : :
3780 : 3 : if (group_name != NULL && key != NULL)
3781 : 1 : return g_key_file_set_key_comment (key_file, group_name, key, NULL, error);
3782 : 2 : else if (group_name != NULL)
3783 : 1 : return g_key_file_set_group_comment (key_file, group_name, NULL, error);
3784 : : else
3785 : 1 : return g_key_file_set_top_comment (key_file, NULL, error);
3786 : : }
3787 : :
3788 : : /**
3789 : : * g_key_file_has_group:
3790 : : * @key_file: a key file
3791 : : * @group_name: a group name
3792 : : *
3793 : : * Looks whether the key file has the group @group_name.
3794 : : *
3795 : : * Returns: true if @group_name is a part of @key_file, false otherwise.
3796 : : * Since: 2.6
3797 : : **/
3798 : : gboolean
3799 : 132 : g_key_file_has_group (GKeyFile *key_file,
3800 : : const gchar *group_name)
3801 : : {
3802 : 132 : g_return_val_if_fail (key_file != NULL, FALSE);
3803 : 132 : g_return_val_if_fail (group_name != NULL, FALSE);
3804 : :
3805 : 132 : return g_key_file_lookup_group (key_file, group_name) != NULL;
3806 : : }
3807 : :
3808 : : /* This code remains from a historical attempt to add a new public API
3809 : : * which respects the GError rules.
3810 : : */
3811 : : static gboolean
3812 : 15 : g_key_file_has_key_full (GKeyFile *key_file,
3813 : : const gchar *group_name,
3814 : : const gchar *key,
3815 : : gboolean *has_key,
3816 : : GError **error)
3817 : : {
3818 : : GKeyFileKeyValuePair *pair;
3819 : : GKeyFileGroup *group;
3820 : :
3821 : 15 : g_return_val_if_fail (key_file != NULL, FALSE);
3822 : 15 : g_return_val_if_fail (group_name != NULL, FALSE);
3823 : 15 : g_return_val_if_fail (key != NULL, FALSE);
3824 : :
3825 : 15 : group = g_key_file_lookup_group (key_file, group_name);
3826 : :
3827 : 15 : if (!group)
3828 : : {
3829 : 2 : g_set_error (error, G_KEY_FILE_ERROR,
3830 : : G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
3831 : : _("Key file does not have group “%s”"),
3832 : : group_name);
3833 : :
3834 : 2 : return FALSE;
3835 : : }
3836 : :
3837 : 13 : pair = g_key_file_lookup_key_value_pair (key_file, group, key);
3838 : :
3839 : 13 : if (has_key)
3840 : 13 : *has_key = pair != NULL;
3841 : 13 : return TRUE;
3842 : : }
3843 : :
3844 : : /**
3845 : : * g_key_file_has_key: (skip)
3846 : : * @key_file: a key file
3847 : : * @group_name: a group name
3848 : : * @key: a key name
3849 : : * @error: return location for a [struct@GLib.Error]
3850 : : *
3851 : : * Looks whether the key file has the key @key in the group
3852 : : * @group_name.
3853 : : *
3854 : : * Note that this function does not follow the rules for [struct@GLib.Error]
3855 : : * strictly;
3856 : : * the return value both carries meaning and signals an error. To use
3857 : : * this function, you must pass a [struct@GLib.Error] pointer in @error, and
3858 : : * check whether it is not `NULL` to see if an error occurred.
3859 : : *
3860 : : * Language bindings should use [method@GLib.KeyFile.get_value] to test whether
3861 : : * a key exists.
3862 : : *
3863 : : * Returns: true if @key is a part of @group_name, false otherwise
3864 : : *
3865 : : * Since: 2.6
3866 : : **/
3867 : : gboolean
3868 : 15 : g_key_file_has_key (GKeyFile *key_file,
3869 : : const gchar *group_name,
3870 : : const gchar *key,
3871 : : GError **error)
3872 : : {
3873 : 15 : GError *temp_error = NULL;
3874 : : gboolean has_key;
3875 : :
3876 : 15 : if (g_key_file_has_key_full (key_file, group_name, key, &has_key, &temp_error))
3877 : : {
3878 : 13 : return has_key;
3879 : : }
3880 : : else
3881 : : {
3882 : 2 : g_propagate_error (error, temp_error);
3883 : 2 : return FALSE;
3884 : : }
3885 : : }
3886 : :
3887 : : static void
3888 : 1861 : g_key_file_add_group (GKeyFile *key_file,
3889 : : const gchar *group_name,
3890 : : gboolean created)
3891 : : {
3892 : : GKeyFileGroup *group;
3893 : :
3894 : 1861 : g_return_if_fail (key_file != NULL);
3895 : 1861 : g_return_if_fail (group_name != NULL && g_key_file_is_group_name (group_name));
3896 : :
3897 : 1861 : group = g_key_file_lookup_group (key_file, group_name);
3898 : 1861 : if (group != NULL)
3899 : : {
3900 : 2 : key_file->current_group = group;
3901 : 2 : return;
3902 : : }
3903 : :
3904 : 1859 : group = g_new0 (GKeyFileGroup, 1);
3905 : 1859 : group->name = g_strdup (group_name);
3906 : 1859 : group->lookup_map = g_hash_table_new (g_str_hash, g_str_equal);
3907 : 1859 : key_file->groups = g_list_prepend (key_file->groups, group);
3908 : 1859 : key_file->current_group = group;
3909 : :
3910 : 1859 : if (key_file->start_group == NULL)
3911 : : {
3912 : 1492 : key_file->start_group = group;
3913 : : }
3914 : 367 : else if (!(key_file->flags & G_KEY_FILE_KEEP_COMMENTS) || created)
3915 : : {
3916 : : /* separate groups by a blank line if we don't keep comments or group is created */
3917 : 355 : GKeyFileGroup *next_group = key_file->groups->next->data;
3918 : : GKeyFileKeyValuePair *pair;
3919 : 355 : if (next_group->key_value_pairs != NULL)
3920 : 272 : pair = next_group->key_value_pairs->data;
3921 : :
3922 : 355 : if (next_group->key_value_pairs == NULL ||
3923 : 272 : (pair->key != NULL && !g_strstr_len (pair->value, -1, "\n")))
3924 : : {
3925 : 354 : GKeyFileKeyValuePair *pair = g_new (GKeyFileKeyValuePair, 1);
3926 : 354 : pair->key = NULL;
3927 : 354 : pair->value = g_strdup ("");
3928 : 354 : next_group->key_value_pairs = g_list_prepend (next_group->key_value_pairs, pair);
3929 : : }
3930 : : }
3931 : :
3932 : 1859 : if (!key_file->group_hash)
3933 : 1492 : key_file->group_hash = g_hash_table_new (g_str_hash, g_str_equal);
3934 : :
3935 : 1859 : g_hash_table_insert (key_file->group_hash, (gpointer)group->name, group);
3936 : : }
3937 : :
3938 : : static void
3939 : 27968 : g_key_file_key_value_pair_free (GKeyFileKeyValuePair *pair)
3940 : : {
3941 : 27968 : if (pair != NULL)
3942 : : {
3943 : 27968 : g_free (pair->key);
3944 : 27968 : g_free (pair->value);
3945 : 27968 : g_free_sized (pair, sizeof (GKeyFileKeyValuePair));
3946 : : }
3947 : 27968 : }
3948 : :
3949 : : /* Be careful not to call this function on a node with data in the
3950 : : * lookup map without removing it from the lookup map, first.
3951 : : *
3952 : : * Some current cases where this warning is not a concern are
3953 : : * when:
3954 : : * - the node being removed is a comment node
3955 : : * - the entire lookup map is getting destroyed soon after
3956 : : * anyway.
3957 : : */
3958 : : static void
3959 : 27888 : g_key_file_remove_key_value_pair_node (GKeyFile *key_file,
3960 : : GKeyFileGroup *group,
3961 : : GList *pair_node)
3962 : : {
3963 : :
3964 : : GKeyFileKeyValuePair *pair;
3965 : :
3966 : 27888 : pair = (GKeyFileKeyValuePair *) pair_node->data;
3967 : :
3968 : 27888 : group->key_value_pairs = g_list_remove_link (group->key_value_pairs, pair_node);
3969 : :
3970 : 27888 : g_warn_if_fail (pair->value != NULL);
3971 : :
3972 : 27888 : g_key_file_key_value_pair_free (pair);
3973 : :
3974 : 27888 : g_list_free_1 (pair_node);
3975 : 27888 : }
3976 : :
3977 : : static void
3978 : 6133 : g_key_file_remove_group_node (GKeyFile *key_file,
3979 : : GList *group_node)
3980 : : {
3981 : : GKeyFileGroup *group;
3982 : : GList *tmp;
3983 : :
3984 : 6133 : group = (GKeyFileGroup *) group_node->data;
3985 : :
3986 : 6133 : if (group->name)
3987 : : {
3988 : 1859 : g_assert (key_file->group_hash);
3989 : 1859 : g_hash_table_remove (key_file->group_hash, group->name);
3990 : : }
3991 : :
3992 : : /* If the current group gets deleted make the current group the last
3993 : : * added group.
3994 : : */
3995 : 6133 : if (key_file->current_group == group)
3996 : : {
3997 : : /* groups should always contain at least the top comment group,
3998 : : * unless g_key_file_clear has been called
3999 : : */
4000 : 4274 : if (key_file->groups)
4001 : 4274 : key_file->current_group = (GKeyFileGroup *) key_file->groups->data;
4002 : : else
4003 : 0 : key_file->current_group = NULL;
4004 : : }
4005 : :
4006 : : /* If the start group gets deleted make the start group the first
4007 : : * added group.
4008 : : */
4009 : 6133 : if (key_file->start_group == group)
4010 : : {
4011 : 1494 : tmp = g_list_last (key_file->groups);
4012 : 4482 : while (tmp != NULL)
4013 : : {
4014 : 2990 : if (tmp != group_node &&
4015 : 1496 : ((GKeyFileGroup *) tmp->data)->name != NULL)
4016 : 2 : break;
4017 : :
4018 : 2988 : tmp = tmp->prev;
4019 : : }
4020 : :
4021 : 1494 : if (tmp)
4022 : 2 : key_file->start_group = (GKeyFileGroup *) tmp->data;
4023 : : else
4024 : 1492 : key_file->start_group = NULL;
4025 : : }
4026 : :
4027 : 6133 : key_file->groups = g_list_remove_link (key_file->groups, group_node);
4028 : :
4029 : 6133 : tmp = group->key_value_pairs;
4030 : 34017 : while (tmp != NULL)
4031 : : {
4032 : : GList *pair_node;
4033 : :
4034 : 27884 : pair_node = tmp;
4035 : 27884 : tmp = tmp->next;
4036 : 27884 : g_key_file_remove_key_value_pair_node (key_file, group, pair_node);
4037 : : }
4038 : :
4039 : 6133 : g_warn_if_fail (group->key_value_pairs == NULL);
4040 : :
4041 : 6133 : if (group->lookup_map)
4042 : : {
4043 : 1859 : g_hash_table_destroy (group->lookup_map);
4044 : 1859 : group->lookup_map = NULL;
4045 : : }
4046 : :
4047 : 6133 : g_free ((gchar *) group->name);
4048 : 6133 : g_free_sized (group, sizeof (GKeyFileGroup));
4049 : 6133 : g_list_free_1 (group_node);
4050 : 6133 : }
4051 : :
4052 : : /**
4053 : : * g_key_file_remove_group:
4054 : : * @key_file: a key file
4055 : : * @group_name: a group name
4056 : : * @error: return location for a [struct@GLib.Error]
4057 : : *
4058 : : * Removes the specified group, @group_name,
4059 : : * from the key file.
4060 : : *
4061 : : * Returns: true if the group was removed, false otherwise
4062 : : *
4063 : : * Since: 2.6
4064 : : **/
4065 : : gboolean
4066 : 4 : g_key_file_remove_group (GKeyFile *key_file,
4067 : : const gchar *group_name,
4068 : : GError **error)
4069 : : {
4070 : : GList *group_node;
4071 : :
4072 : 4 : g_return_val_if_fail (key_file != NULL, FALSE);
4073 : 4 : g_return_val_if_fail (group_name != NULL, FALSE);
4074 : :
4075 : 4 : group_node = g_key_file_lookup_group_node (key_file, group_name);
4076 : :
4077 : 4 : if (!group_node)
4078 : : {
4079 : 1 : g_set_error (error, G_KEY_FILE_ERROR,
4080 : : G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
4081 : : _("Key file does not have group “%s”"),
4082 : : group_name);
4083 : 1 : return FALSE;
4084 : : }
4085 : :
4086 : 3 : g_key_file_remove_group_node (key_file, group_node);
4087 : :
4088 : 3 : return TRUE;
4089 : : }
4090 : :
4091 : : static void
4092 : 27581 : g_key_file_add_key_value_pair (GKeyFile *key_file,
4093 : : GKeyFileGroup *group,
4094 : : GKeyFileKeyValuePair *pair,
4095 : : GList *sibling)
4096 : : {
4097 : 27581 : g_hash_table_replace (group->lookup_map, pair->key, pair);
4098 : 27581 : group->key_value_pairs = g_list_insert_before (group->key_value_pairs, sibling, pair);
4099 : 27581 : }
4100 : :
4101 : : static void
4102 : 273 : g_key_file_add_key (GKeyFile *key_file,
4103 : : GKeyFileGroup *group,
4104 : : const gchar *key,
4105 : : const gchar *value)
4106 : : {
4107 : : GKeyFileKeyValuePair *pair;
4108 : : GList *lp;
4109 : :
4110 : 273 : pair = g_new (GKeyFileKeyValuePair, 1);
4111 : 273 : pair->key = g_strdup (key);
4112 : 273 : pair->value = g_strdup (value);
4113 : :
4114 : : /* skip group comment */
4115 : 273 : lp = group->key_value_pairs;
4116 : 301 : while (lp != NULL && ((GKeyFileKeyValuePair *) lp->data)->key == NULL)
4117 : 28 : lp = lp->next;
4118 : :
4119 : 273 : g_key_file_add_key_value_pair (key_file, group, pair, lp);
4120 : 273 : }
4121 : :
4122 : : /**
4123 : : * g_key_file_remove_key:
4124 : : * @key_file: a key file
4125 : : * @group_name: a group name
4126 : : * @key: a key name to remove
4127 : : * @error: return location for a [struct@GLib.Error]
4128 : : *
4129 : : * Removes @key in @group_name from the key file.
4130 : : *
4131 : : * Returns: true if the key was removed, false otherwise
4132 : : *
4133 : : * Since: 2.6
4134 : : **/
4135 : : gboolean
4136 : 218 : g_key_file_remove_key (GKeyFile *key_file,
4137 : : const gchar *group_name,
4138 : : const gchar *key,
4139 : : GError **error)
4140 : : {
4141 : : GKeyFileGroup *group;
4142 : : GKeyFileKeyValuePair *pair;
4143 : :
4144 : 218 : g_return_val_if_fail (key_file != NULL, FALSE);
4145 : 218 : g_return_val_if_fail (group_name != NULL, FALSE);
4146 : 218 : g_return_val_if_fail (key != NULL, FALSE);
4147 : :
4148 : 218 : pair = NULL;
4149 : :
4150 : 218 : group = g_key_file_lookup_group (key_file, group_name);
4151 : 218 : if (!group)
4152 : : {
4153 : 95 : g_set_error (error, G_KEY_FILE_ERROR,
4154 : : G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
4155 : : _("Key file does not have group “%s”"),
4156 : : group_name);
4157 : 95 : return FALSE;
4158 : : }
4159 : :
4160 : 123 : pair = g_key_file_lookup_key_value_pair (key_file, group, key);
4161 : :
4162 : 123 : if (!pair)
4163 : : {
4164 : 46 : set_not_found_key_error (group->name, key, error);
4165 : 46 : return FALSE;
4166 : : }
4167 : :
4168 : 77 : group->key_value_pairs = g_list_remove (group->key_value_pairs, pair);
4169 : 77 : g_hash_table_remove (group->lookup_map, pair->key);
4170 : 77 : g_key_file_key_value_pair_free (pair);
4171 : :
4172 : 77 : return TRUE;
4173 : : }
4174 : :
4175 : : static GList *
4176 : 16 : g_key_file_lookup_group_node (GKeyFile *key_file,
4177 : : const gchar *group_name)
4178 : : {
4179 : : GKeyFileGroup *group;
4180 : :
4181 : 16 : group = g_key_file_lookup_group (key_file, group_name);
4182 : 16 : if (group == NULL)
4183 : 1 : return NULL;
4184 : :
4185 : 15 : return g_list_find (key_file->groups, group);
4186 : : }
4187 : :
4188 : : static GKeyFileGroup *
4189 : 30667 : g_key_file_lookup_group (GKeyFile *key_file,
4190 : : const gchar *group_name)
4191 : : {
4192 : 30667 : if (!key_file->group_hash)
4193 : 1703 : return NULL;
4194 : :
4195 : 28964 : return (GKeyFileGroup *)g_hash_table_lookup (key_file->group_hash, group_name);
4196 : : }
4197 : :
4198 : : static GList *
4199 : 6 : g_key_file_lookup_key_value_pair_node (GKeyFile *key_file,
4200 : : GKeyFileGroup *group,
4201 : : const gchar *key)
4202 : : {
4203 : : GList *key_node;
4204 : :
4205 : 6 : for (key_node = group->key_value_pairs;
4206 : 27 : key_node != NULL;
4207 : 21 : key_node = key_node->next)
4208 : : {
4209 : : GKeyFileKeyValuePair *pair;
4210 : :
4211 : 27 : pair = (GKeyFileKeyValuePair *) key_node->data;
4212 : :
4213 : 27 : if (pair->key && strcmp (pair->key, key) == 0)
4214 : 6 : break;
4215 : : }
4216 : :
4217 : 6 : return key_node;
4218 : : }
4219 : :
4220 : : static GKeyFileKeyValuePair *
4221 : 27776 : g_key_file_lookup_key_value_pair (GKeyFile *key_file,
4222 : : GKeyFileGroup *group,
4223 : : const gchar *key)
4224 : : {
4225 : 27776 : return (GKeyFileKeyValuePair *) g_hash_table_lookup (group->lookup_map, key);
4226 : : }
4227 : :
4228 : : /* Lines starting with # or consisting entirely of whitespace are merely
4229 : : * recorded, not parsed. This function assumes all leading whitespace
4230 : : * has been stripped.
4231 : : */
4232 : : static gboolean
4233 : 59729 : g_key_file_line_is_comment (const gchar *line)
4234 : : {
4235 : 59729 : return (*line == '#' || *line == '\0' || *line == '\n');
4236 : : }
4237 : :
4238 : : static gboolean
4239 : 4002 : g_key_file_is_group_name (const gchar *name)
4240 : : {
4241 : : const gchar *p, *q;
4242 : :
4243 : 4002 : g_assert (name != NULL);
4244 : :
4245 : 4002 : p = q = name;
4246 : 61771 : while (*q && *q != ']' && *q != '[' && !g_ascii_iscntrl (*q))
4247 : 57769 : q = g_utf8_find_next_char (q, NULL);
4248 : :
4249 : 4002 : if (*q != '\0' || q == p)
4250 : 3 : return FALSE;
4251 : :
4252 : 3999 : return TRUE;
4253 : : }
4254 : :
4255 : : static gboolean
4256 : 57645 : g_key_file_is_key_name (const gchar *name,
4257 : : gsize len)
4258 : : {
4259 : : const gchar *p, *q, *end;
4260 : :
4261 : 57645 : g_assert (name != NULL);
4262 : :
4263 : 57645 : p = q = name;
4264 : 57645 : end = name + len;
4265 : :
4266 : : /* We accept a little more than the desktop entry spec says,
4267 : : * since gnome-vfs uses mime-types as keys in its cache.
4268 : : */
4269 : 772187 : while (q < end && *q && *q != '=' && *q != '[' && *q != ']')
4270 : : {
4271 : 656897 : q = g_utf8_find_next_char (q, end);
4272 : 656897 : if (q == NULL)
4273 : 27530 : q = end;
4274 : : }
4275 : :
4276 : : /* No empty keys, please */
4277 : 57645 : if (q == p)
4278 : 1 : return FALSE;
4279 : :
4280 : : /* We accept spaces in the middle of keys to not break
4281 : : * existing apps, but we don't tolerate initial or final
4282 : : * spaces, which would lead to silent corruption when
4283 : : * rereading the file.
4284 : : */
4285 : 57644 : if (*p == ' ' || q[-1] == ' ')
4286 : 1 : return FALSE;
4287 : :
4288 : 57643 : if (*q == '[')
4289 : : {
4290 : 30113 : q++;
4291 : 30113 : while (q < end &&
4292 : 133008 : *q != '\0' &&
4293 : 133007 : (g_unichar_isalnum (g_utf8_get_char_validated (q, end - q)) || *q == '-' || *q == '_' || *q == '.' || *q == '@'))
4294 : : {
4295 : 102895 : q = g_utf8_find_next_char (q, end);
4296 : 102895 : if (q == NULL)
4297 : : {
4298 : 0 : q = end;
4299 : 0 : break;
4300 : : }
4301 : : }
4302 : :
4303 : 30113 : if (*q != ']')
4304 : 2 : return FALSE;
4305 : :
4306 : 30111 : q++;
4307 : : }
4308 : :
4309 : 57641 : if (q < end)
4310 : 0 : return FALSE;
4311 : :
4312 : 57641 : return TRUE;
4313 : : }
4314 : :
4315 : : /* A group in a key file is made up of a starting '[' followed by one
4316 : : * or more letters making up the group name followed by ']'.
4317 : : */
4318 : : static gboolean
4319 : 59057 : g_key_file_line_is_group (const gchar *line)
4320 : : {
4321 : : const gchar *p;
4322 : :
4323 : 59057 : p = line;
4324 : 59057 : if (*p != '[')
4325 : 57285 : return FALSE;
4326 : :
4327 : 1772 : p++;
4328 : :
4329 : 27241 : while (*p && *p != ']')
4330 : 25469 : p = g_utf8_find_next_char (p, NULL);
4331 : :
4332 : 1772 : if (*p != ']')
4333 : 0 : return FALSE;
4334 : :
4335 : : /* silently accept whitespace after the ] */
4336 : 1772 : p = g_utf8_find_next_char (p, NULL);
4337 : 1774 : while (*p == ' ' || *p == '\t')
4338 : 2 : p = g_utf8_find_next_char (p, NULL);
4339 : :
4340 : 1772 : if (*p)
4341 : 2 : return FALSE;
4342 : :
4343 : 1770 : return TRUE;
4344 : : }
4345 : :
4346 : : static gboolean
4347 : 57287 : g_key_file_line_is_key_value_pair (const gchar *line)
4348 : : {
4349 : : const gchar *p;
4350 : :
4351 : 57287 : p = g_utf8_strchr (line, -1, '=');
4352 : :
4353 : 57287 : if (!p)
4354 : 5 : return FALSE;
4355 : :
4356 : : /* Key must be non-empty
4357 : : */
4358 : 57282 : if (*p == line[0])
4359 : 1 : return FALSE;
4360 : :
4361 : 57281 : return TRUE;
4362 : : }
4363 : :
4364 : : static gchar *
4365 : 18092 : g_key_file_parse_value_as_string (GKeyFile *key_file,
4366 : : const gchar *value,
4367 : : GSList **pieces,
4368 : : GError **error)
4369 : : {
4370 : : gchar *string_value, *q0, *q;
4371 : 18092 : GSList *tmp_pieces = NULL;
4372 : : const gchar *p;
4373 : :
4374 : 18092 : g_assert (pieces == NULL || *pieces == NULL);
4375 : :
4376 : 18092 : string_value = g_new (gchar, strlen (value) + 1);
4377 : :
4378 : 18092 : p = value;
4379 : 18092 : q0 = q = string_value;
4380 : 380063 : while (*p)
4381 : : {
4382 : 361978 : if (*p == '\\')
4383 : : {
4384 : 19 : p++;
4385 : :
4386 : 19 : switch (*p)
4387 : : {
4388 : 2 : case 's':
4389 : 2 : *q = ' ';
4390 : 2 : break;
4391 : :
4392 : 2 : case 'n':
4393 : 2 : *q = '\n';
4394 : 2 : break;
4395 : :
4396 : 2 : case 't':
4397 : 2 : *q = '\t';
4398 : 2 : break;
4399 : :
4400 : 2 : case 'r':
4401 : 2 : *q = '\r';
4402 : 2 : break;
4403 : :
4404 : 2 : case '\\':
4405 : 2 : *q = '\\';
4406 : 2 : break;
4407 : :
4408 : 3 : case '\0':
4409 : 3 : g_set_error_literal (error, G_KEY_FILE_ERROR,
4410 : : G_KEY_FILE_ERROR_INVALID_VALUE,
4411 : : _("Key file contains escape character "
4412 : : "at end of line"));
4413 : 3 : goto error;
4414 : :
4415 : 6 : default:
4416 : 6 : if (pieces && *p == key_file->list_separator)
4417 : 2 : *q = key_file->list_separator;
4418 : : else
4419 : : {
4420 : 4 : *q++ = '\\';
4421 : 4 : *q = *p;
4422 : :
4423 : 4 : if (*error == NULL)
4424 : : {
4425 : : gchar sequence[3];
4426 : :
4427 : 4 : sequence[0] = '\\';
4428 : 4 : sequence[1] = *p;
4429 : 4 : sequence[2] = '\0';
4430 : :
4431 : 4 : g_set_error (error, G_KEY_FILE_ERROR,
4432 : : G_KEY_FILE_ERROR_INVALID_VALUE,
4433 : : _("Key file contains invalid escape "
4434 : : "sequence “%s”"), sequence);
4435 : 4 : goto error;
4436 : : }
4437 : : }
4438 : 2 : break;
4439 : : }
4440 : : }
4441 : : else
4442 : : {
4443 : 361959 : *q = *p;
4444 : 361959 : if (pieces && (*p == key_file->list_separator))
4445 : : {
4446 : 15536 : tmp_pieces = g_slist_prepend (tmp_pieces, g_strndup (q0, q - q0));
4447 : 15536 : q0 = q + 1;
4448 : : }
4449 : : }
4450 : :
4451 : 361971 : if (*p == '\0')
4452 : 0 : break;
4453 : :
4454 : 361971 : q++;
4455 : 361971 : p++;
4456 : : }
4457 : :
4458 : 18085 : *q = '\0';
4459 : 18085 : if (pieces)
4460 : : {
4461 : 14342 : if (q0 < q)
4462 : 608 : tmp_pieces = g_slist_prepend (tmp_pieces, g_strndup (q0, q - q0));
4463 : 14342 : *pieces = g_slist_reverse (tmp_pieces);
4464 : : }
4465 : :
4466 : 18085 : return string_value;
4467 : :
4468 : 7 : error:
4469 : 7 : g_free (string_value);
4470 : 7 : g_slist_free_full (tmp_pieces, g_free);
4471 : :
4472 : 7 : return NULL;
4473 : : }
4474 : :
4475 : : static gchar *
4476 : 353 : g_key_file_parse_string_as_value (GKeyFile *key_file,
4477 : : const gchar *string,
4478 : : gboolean escape_separator)
4479 : : {
4480 : : gchar *value, *q;
4481 : : const gchar *p;
4482 : : gsize length;
4483 : : gboolean parsing_leading_space;
4484 : :
4485 : 353 : length = strlen (string) + 1;
4486 : :
4487 : : /* Worst case would be that every character needs to be escaped.
4488 : : * In other words every character turns to two characters
4489 : : */
4490 : 353 : value = g_new (gchar, 2 * length);
4491 : :
4492 : 353 : p = string;
4493 : 353 : q = value;
4494 : 353 : parsing_leading_space = TRUE;
4495 : 6799 : while (p < (string + length - 1))
4496 : : {
4497 : 6446 : gchar escaped_character[3] = { '\\', 0, 0 };
4498 : :
4499 : 6446 : switch (*p)
4500 : : {
4501 : 134 : case ' ':
4502 : 134 : if (parsing_leading_space)
4503 : : {
4504 : 1 : escaped_character[1] = 's';
4505 : 1 : strcpy (q, escaped_character);
4506 : 1 : q += 2;
4507 : : }
4508 : : else
4509 : : {
4510 : 133 : *q = *p;
4511 : 133 : q++;
4512 : : }
4513 : 134 : break;
4514 : 1 : case '\t':
4515 : 1 : if (parsing_leading_space)
4516 : : {
4517 : 1 : escaped_character[1] = 't';
4518 : 1 : strcpy (q, escaped_character);
4519 : 1 : q += 2;
4520 : : }
4521 : : else
4522 : : {
4523 : 0 : *q = *p;
4524 : 0 : q++;
4525 : : }
4526 : 1 : break;
4527 : 1 : case '\n':
4528 : 1 : escaped_character[1] = 'n';
4529 : 1 : strcpy (q, escaped_character);
4530 : 1 : q += 2;
4531 : 1 : break;
4532 : 1 : case '\r':
4533 : 1 : escaped_character[1] = 'r';
4534 : 1 : strcpy (q, escaped_character);
4535 : 1 : q += 2;
4536 : 1 : break;
4537 : 1 : case '\\':
4538 : 1 : escaped_character[1] = '\\';
4539 : 1 : strcpy (q, escaped_character);
4540 : 1 : q += 2;
4541 : 1 : parsing_leading_space = FALSE;
4542 : 1 : break;
4543 : 6308 : default:
4544 : 6308 : if (escape_separator && *p == key_file->list_separator)
4545 : : {
4546 : 1 : escaped_character[1] = key_file->list_separator;
4547 : 1 : strcpy (q, escaped_character);
4548 : 1 : q += 2;
4549 : 1 : parsing_leading_space = TRUE;
4550 : : }
4551 : : else
4552 : : {
4553 : 6307 : *q = *p;
4554 : 6307 : q++;
4555 : 6307 : parsing_leading_space = FALSE;
4556 : : }
4557 : 6308 : break;
4558 : : }
4559 : 6446 : p++;
4560 : : }
4561 : 353 : *q = '\0';
4562 : :
4563 : 353 : return value;
4564 : : }
4565 : :
4566 : : static gint
4567 : 111 : g_key_file_parse_value_as_integer (GKeyFile *key_file,
4568 : : const gchar *value,
4569 : : GError **error)
4570 : : {
4571 : : gchar *eof_int;
4572 : : glong long_value;
4573 : : gint int_value;
4574 : : int errsv;
4575 : :
4576 : 111 : errno = 0;
4577 : 111 : long_value = strtol (value, &eof_int, 10);
4578 : 111 : errsv = errno;
4579 : :
4580 : 111 : if (*value == '\0' || (*eof_int != '\0' && !g_ascii_isspace(*eof_int)))
4581 : : {
4582 : 4 : gchar *value_utf8 = g_utf8_make_valid (value, -1);
4583 : 4 : g_set_error (error, G_KEY_FILE_ERROR,
4584 : : G_KEY_FILE_ERROR_INVALID_VALUE,
4585 : : _("Value “%s” cannot be interpreted "
4586 : : "as a number."), value_utf8);
4587 : 4 : g_free (value_utf8);
4588 : :
4589 : 4 : return 0;
4590 : : }
4591 : :
4592 : 107 : int_value = long_value;
4593 : 107 : if (int_value != long_value || errsv == ERANGE)
4594 : : {
4595 : 0 : gchar *value_utf8 = g_utf8_make_valid (value, -1);
4596 : 0 : g_set_error (error,
4597 : : G_KEY_FILE_ERROR,
4598 : : G_KEY_FILE_ERROR_INVALID_VALUE,
4599 : : _("Integer value “%s” out of range"),
4600 : : value_utf8);
4601 : 0 : g_free (value_utf8);
4602 : :
4603 : 0 : return 0;
4604 : : }
4605 : :
4606 : 107 : return int_value;
4607 : : }
4608 : :
4609 : : static gchar *
4610 : 8 : g_key_file_parse_integer_as_value (GKeyFile *key_file,
4611 : : gint value)
4612 : :
4613 : : {
4614 : 8 : return g_strdup_printf ("%d", value);
4615 : : }
4616 : :
4617 : : static gdouble
4618 : 14 : g_key_file_parse_value_as_double (GKeyFile *key_file,
4619 : : const gchar *value,
4620 : : GError **error)
4621 : : {
4622 : : gchar *end_of_valid_d;
4623 : 14 : gdouble double_value = 0;
4624 : :
4625 : 14 : double_value = g_ascii_strtod (value, &end_of_valid_d);
4626 : :
4627 : 14 : if (*end_of_valid_d != '\0' || end_of_valid_d == value)
4628 : : {
4629 : 4 : gchar *value_utf8 = g_utf8_make_valid (value, -1);
4630 : 4 : g_set_error (error, G_KEY_FILE_ERROR,
4631 : : G_KEY_FILE_ERROR_INVALID_VALUE,
4632 : : _("Value “%s” cannot be interpreted "
4633 : : "as a float number."),
4634 : : value_utf8);
4635 : 4 : g_free (value_utf8);
4636 : :
4637 : 4 : double_value = 0;
4638 : : }
4639 : :
4640 : 14 : return double_value;
4641 : : }
4642 : :
4643 : : static gint
4644 : 438 : strcmp_sized (const gchar *s1, size_t len1, const gchar *s2)
4645 : : {
4646 : 438 : size_t len2 = strlen (s2);
4647 : 438 : return strncmp (s1, s2, MAX (len1, len2));
4648 : : }
4649 : :
4650 : : static gboolean
4651 : 256 : g_key_file_parse_value_as_boolean (GKeyFile *key_file,
4652 : : const gchar *value,
4653 : : GError **error)
4654 : : {
4655 : : gchar *value_utf8;
4656 : 256 : gint i, length = 0;
4657 : :
4658 : : /* Count the number of non-whitespace characters */
4659 : 1349 : for (i = 0; value[i]; i++)
4660 : 1093 : if (!g_ascii_isspace (value[i]))
4661 : 1092 : length = i + 1;
4662 : :
4663 : 256 : if (strcmp_sized (value, length, "true") == 0 || strcmp_sized (value, length, "1") == 0)
4664 : 168 : return TRUE;
4665 : 88 : else if (strcmp_sized (value, length, "false") == 0 || strcmp_sized (value, length, "0") == 0)
4666 : 84 : return FALSE;
4667 : :
4668 : 4 : value_utf8 = g_utf8_make_valid (value, -1);
4669 : 4 : g_set_error (error, G_KEY_FILE_ERROR,
4670 : : G_KEY_FILE_ERROR_INVALID_VALUE,
4671 : : _("Value “%s” cannot be interpreted "
4672 : : "as a boolean."), value_utf8);
4673 : 4 : g_free (value_utf8);
4674 : :
4675 : 4 : return FALSE;
4676 : : }
4677 : :
4678 : : static const gchar *
4679 : 39 : g_key_file_parse_boolean_as_value (GKeyFile *key_file,
4680 : : gboolean value)
4681 : : {
4682 : 39 : if (value)
4683 : 37 : return "true";
4684 : : else
4685 : 2 : return "false";
4686 : : }
4687 : :
4688 : : static gchar *
4689 : 22 : g_key_file_parse_value_as_comment (GKeyFile *key_file,
4690 : : const gchar *value,
4691 : : gboolean is_final_line)
4692 : : {
4693 : : GString *string;
4694 : : gchar **lines;
4695 : : gsize i;
4696 : :
4697 : 22 : string = g_string_sized_new (512);
4698 : :
4699 : 22 : lines = g_strsplit (value, "\n", 0);
4700 : :
4701 : 39 : for (i = 0; lines[i] != NULL; i++)
4702 : : {
4703 : 17 : const gchar *line = lines[i];
4704 : :
4705 : 17 : if (i != 0)
4706 : : g_string_append_c (string, '\n');
4707 : :
4708 : 17 : if (line[0] == '#')
4709 : 17 : line++;
4710 : : g_string_append (string, line);
4711 : : }
4712 : 22 : g_strfreev (lines);
4713 : :
4714 : : /* This function gets called once per line of a comment, but we don’t want
4715 : : * to add a trailing newline. */
4716 : 22 : if (!is_final_line)
4717 : : g_string_append_c (string, '\n');
4718 : :
4719 : 22 : return g_string_free (string, FALSE);
4720 : : }
4721 : :
4722 : : static gchar *
4723 : 3 : g_key_file_parse_comment_as_value (GKeyFile *key_file,
4724 : : const gchar *comment)
4725 : : {
4726 : : GString *string;
4727 : : gchar **lines;
4728 : : gsize i;
4729 : :
4730 : 3 : string = g_string_sized_new (512);
4731 : :
4732 : 3 : lines = g_strsplit (comment, "\n", 0);
4733 : :
4734 : 6 : for (i = 0; lines[i] != NULL; i++)
4735 : 3 : g_string_append_printf (string, "#%s%s", lines[i],
4736 : 3 : lines[i + 1] == NULL? "" : "\n");
4737 : 3 : g_strfreev (lines);
4738 : :
4739 : 3 : return g_string_free (string, FALSE);
4740 : : }
4741 : :
4742 : : /**
4743 : : * g_key_file_save_to_file:
4744 : : * @key_file: a key file
4745 : : * @filename: the name of the file to write to
4746 : : * @error: return location for a [struct@GLib.Error]
4747 : : *
4748 : : * Writes the contents of @key_file to @filename using
4749 : : * [func@GLib.file_set_contents].
4750 : : *
4751 : : * If you need stricter guarantees about durability of
4752 : : * the written file than are provided by [func@GLib.file_set_contents], use
4753 : : * [func@GLib.file_set_contents_full] with the return value of
4754 : : * [method@GLib.KeyFile.to_data].
4755 : : *
4756 : : * This function can fail for any of the reasons that
4757 : : * [func@GLib.file_set_contents] may fail.
4758 : : *
4759 : : * Returns: true if successful, false otherwise
4760 : : *
4761 : : * Since: 2.40
4762 : : */
4763 : : gboolean
4764 : 6 : g_key_file_save_to_file (GKeyFile *key_file,
4765 : : const gchar *filename,
4766 : : GError **error)
4767 : : {
4768 : : gchar *contents;
4769 : : gboolean success;
4770 : : gsize length;
4771 : :
4772 : 6 : g_return_val_if_fail (key_file != NULL, FALSE);
4773 : 6 : g_return_val_if_fail (filename != NULL, FALSE);
4774 : 6 : g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
4775 : :
4776 : 6 : contents = g_key_file_to_data (key_file, &length, NULL);
4777 : 6 : g_assert (contents != NULL);
4778 : :
4779 : 6 : success = g_file_set_contents (filename, contents, length, error);
4780 : 6 : g_free (contents);
4781 : :
4782 : 6 : return success;
4783 : : }
|