app: s/sprintf/g_snprintf/ in xcf_save_image()
[gimp.git] / libgimpconfig / gimpconfig-path.c
blob3eaff5049fef26562dad86820c5bcdda618412e7
1 /* LIBGIMP - The GIMP Library
2 * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
4 * gimpconfig-path.c
5 * Copyright (C) 2001 Sven Neumann <sven@gimp.org>
7 * This library is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 3 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <https://www.gnu.org/licenses/>.
22 #include "config.h"
24 #include <stdio.h>
25 #include <string.h>
27 #include <gio/gio.h>
29 #include "libgimpbase/gimpbase.h"
31 #include "gimpconfig-error.h"
32 #include "gimpconfig-path.h"
34 #include "libgimp/libgimp-intl.h"
37 /**
38 * SECTION: gimpconfig-path
39 * @title: GimpConfig-path
40 * @short_description: File path utilities for libgimpconfig.
42 * File path utilities for libgimpconfig.
43 **/
46 /**
47 * gimp_config_path_get_type:
49 * Reveals the object type
51 * Returns: the #GType for a GimpConfigPath string property
53 * Since: 2.4
54 **/
55 GType
56 gimp_config_path_get_type (void)
58 static GType path_type = 0;
60 if (! path_type)
62 const GTypeInfo type_info = { 0, };
64 path_type = g_type_register_static (G_TYPE_STRING, "GimpConfigPath",
65 &type_info, 0);
68 return path_type;
73 * GIMP_TYPE_PARAM_CONFIG_PATH
76 #define GIMP_PARAM_SPEC_CONFIG_PATH(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_CONFIG_PATH, GimpParamSpecConfigPath))
78 typedef struct _GimpParamSpecConfigPath GimpParamSpecConfigPath;
80 struct _GimpParamSpecConfigPath
82 GParamSpecString parent_instance;
84 GimpConfigPathType type;
87 static void gimp_param_config_path_class_init (GParamSpecClass *class);
89 /**
90 * gimp_param_config_path_get_type:
92 * Reveals the object type
94 * Returns: the #GType for a directory path object
96 * Since: 2.4
97 **/
98 GType
99 gimp_param_config_path_get_type (void)
101 static GType spec_type = 0;
103 if (! spec_type)
105 const GTypeInfo type_info =
107 sizeof (GParamSpecClass),
108 NULL, NULL,
109 (GClassInitFunc) gimp_param_config_path_class_init,
110 NULL, NULL,
111 sizeof (GimpParamSpecConfigPath),
112 0, NULL, NULL
115 spec_type = g_type_register_static (G_TYPE_PARAM_STRING,
116 "GimpParamConfigPath",
117 &type_info, 0);
120 return spec_type;
123 static void
124 gimp_param_config_path_class_init (GParamSpecClass *class)
126 class->value_type = GIMP_TYPE_CONFIG_PATH;
130 * gimp_param_spec_config_path:
131 * @name: Canonical name of the param
132 * @nick: Nickname of the param
133 * @blurb: Brief description of param.
134 * @type: a #GimpConfigPathType value.
135 * @default_value: Value to use if none is assigned.
136 * @flags: a combination of #GParamFlags
138 * Creates a param spec to hold a filename, dir name,
139 * or list of file or dir names.
140 * See g_param_spec_internal() for more information.
142 * Returns: a newly allocated #GParamSpec instance
144 * Since: 2.4
146 GParamSpec *
147 gimp_param_spec_config_path (const gchar *name,
148 const gchar *nick,
149 const gchar *blurb,
150 GimpConfigPathType type,
151 const gchar *default_value,
152 GParamFlags flags)
154 GParamSpecString *pspec;
156 pspec = g_param_spec_internal (GIMP_TYPE_PARAM_CONFIG_PATH,
157 name, nick, blurb, flags);
159 pspec->default_value = g_strdup (default_value);
161 GIMP_PARAM_SPEC_CONFIG_PATH (pspec)->type = type;
163 return G_PARAM_SPEC (pspec);
167 * gimp_param_spec_config_path_type:
168 * @pspec: A #GParamSpec for a path param
170 * Tells whether the path param encodes a filename,
171 * dir name, or list of file or dir names.
173 * Returns: a #GimpConfigPathType value
175 * Since: 2.4
177 GimpConfigPathType
178 gimp_param_spec_config_path_type (GParamSpec *pspec)
180 g_return_val_if_fail (GIMP_IS_PARAM_SPEC_CONFIG_PATH (pspec), 0);
182 return GIMP_PARAM_SPEC_CONFIG_PATH (pspec)->type;
187 * GimpConfig path utilities
190 static gchar * gimp_config_path_expand_only (const gchar *path,
191 GError **error) G_GNUC_MALLOC;
192 static inline gchar * gimp_config_path_extract_token (const gchar **str);
193 static gchar * gimp_config_path_unexpand_only (const gchar *path) G_GNUC_MALLOC;
197 * gimp_config_build_data_path:
198 * @name: directory name (in UTF-8 encoding)
200 * Creates a search path as it is used in the gimprc file. The path
201 * returned by gimp_config_build_data_path() includes a directory
202 * below the user's gimp directory and one in the system-wide data
203 * directory.
205 * Note that you cannot use this path directly with gimp_path_parse().
206 * As it is in the gimprc notation, you first need to expand and
207 * recode it using gimp_config_path_expand().
209 * Returns: a newly allocated string
211 * Since: 2.4
213 gchar *
214 gimp_config_build_data_path (const gchar *name)
216 return g_strconcat ("${gimp_dir}", G_DIR_SEPARATOR_S, name,
217 G_SEARCHPATH_SEPARATOR_S,
218 "${gimp_data_dir}", G_DIR_SEPARATOR_S, name,
219 NULL);
223 * gimp_config_build_plug_in_path:
224 * @name: directory name (in UTF-8 encoding)
226 * Creates a search path as it is used in the gimprc file. The path
227 * returned by gimp_config_build_plug_in_path() includes a directory
228 * below the user's gimp directory and one in the system-wide plug-in
229 * directory.
231 * Note that you cannot use this path directly with gimp_path_parse().
232 * As it is in the gimprc notation, you first need to expand and
233 * recode it using gimp_config_path_expand().
235 * Returns: a newly allocated string
237 * Since: 2.4
239 gchar *
240 gimp_config_build_plug_in_path (const gchar *name)
242 return g_strconcat ("${gimp_dir}", G_DIR_SEPARATOR_S, name,
243 G_SEARCHPATH_SEPARATOR_S,
244 "${gimp_plug_in_dir}", G_DIR_SEPARATOR_S, name,
245 NULL);
249 * gimp_config_build_writable_path:
250 * @name: directory name (in UTF-8 encoding)
252 * Creates a search path as it is used in the gimprc file. The path
253 * returned by gimp_config_build_writable_path() is just the writable
254 * parts of the search path constructed by gimp_config_build_data_path().
256 * Note that you cannot use this path directly with gimp_path_parse().
257 * As it is in the gimprc notation, you first need to expand and
258 * recode it using gimp_config_path_expand().
260 * Returns: a newly allocated string
262 * Since: 2.4
264 gchar *
265 gimp_config_build_writable_path (const gchar *name)
267 return g_strconcat ("${gimp_dir}", G_DIR_SEPARATOR_S, name, NULL);
271 * gimp_config_build_system_path:
272 * @name: directory name (in UTF-8 encoding)
274 * Creates a search path as it is used in the gimprc file. The path
275 * returned by gimp_config_build_system_path() is just the read-only
276 * parts of the search path constructed by gimp_config_build_plug_in_path().
278 * Note that you cannot use this path directly with gimp_path_parse().
279 * As it is in the gimprc notation, you first need to expand and
280 * recode it using gimp_config_path_expand().
282 * Returns: a newly allocated string
284 * Since: 2.10.6
286 gchar *
287 gimp_config_build_system_path (const gchar *name)
289 return g_strconcat ("${gimp_plug_in_dir}", G_DIR_SEPARATOR_S, name, NULL);
293 * gimp_config_path_expand:
294 * @path: a NUL-terminated string in UTF-8 encoding
295 * @recode: whether to convert to the filesystem's encoding
296 * @error: return location for errors
298 * Paths as stored in gimprc and other config files have to be treated
299 * special. The string may contain special identifiers such as for
300 * example ${gimp_dir} that have to be substituted before use. Also
301 * the user's filesystem may be in a different encoding than UTF-8
302 * (which is what is used for the gimprc). This function does the
303 * variable substitution for you and can also attempt to convert to
304 * the filesystem encoding.
306 * To reverse the expansion, use gimp_config_path_unexpand().
308 * Return value: a newly allocated NUL-terminated string
310 * Since: 2.4
312 gchar *
313 gimp_config_path_expand (const gchar *path,
314 gboolean recode,
315 GError **error)
317 g_return_val_if_fail (path != NULL, NULL);
318 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
320 if (recode)
322 gchar *retval;
323 gchar *expanded = gimp_config_path_expand_only (path, error);
325 if (! expanded)
326 return NULL;
328 retval = g_filename_from_utf8 (expanded, -1, NULL, NULL, error);
330 g_free (expanded);
332 return retval;
335 return gimp_config_path_expand_only (path, error);
339 * gimp_config_path_expand_to_files:
340 * @path: a NUL-terminated string in UTF-8 encoding
341 * @error: return location for errors
343 * Paths as stored in the gimprc have to be treated special. The
344 * string may contain special identifiers such as for example
345 * ${gimp_dir} that have to be substituted before use. Also the user's
346 * filesystem may be in a different encoding than UTF-8 (which is what
347 * is used for the gimprc).
349 * This function runs @path through gimp_config_path_expand() and
350 * gimp_path_parse(), then turns the filenames returned by
351 * gimp_path_parse() into GFile using g_file_new_for_path().
353 * Return value: a #GList of newly allocated #GFile objects.
355 * Since: 2.10
357 GList *
358 gimp_config_path_expand_to_files (const gchar *path,
359 GError **error)
361 GList *files;
362 GList *list;
363 gchar *expanded;
365 g_return_val_if_fail (path != NULL, NULL);
366 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
368 expanded = gimp_config_path_expand (path, TRUE, error);
370 if (! expanded)
371 return NULL;
373 files = gimp_path_parse (expanded, 256, FALSE, NULL);
375 g_free (expanded);
377 for (list = files; list; list = g_list_next (list))
379 gchar *dir = list->data;
381 list->data = g_file_new_for_path (dir);
382 g_free (dir);
385 return files;
389 * gimp_config_path_unexpand:
390 * @path: a NUL-terminated string
391 * @recode: whether @path is in filesystem encoding or UTF-8
392 * @error: return location for errors
394 * The inverse operation of gimp_config_path_expand()
396 * This function takes a @path and tries to substitute the first
397 * elements by well-known special identifiers such as for example
398 * ${gimp_dir}. The unexpanded path can then be stored in gimprc and
399 * other config files.
401 * If @recode is %TRUE then @path is in local filesystem encoding,
402 * if @recode is %FALSE then @path is assumed to be UTF-8.
404 * Return value: a newly allocated NUL-terminated UTF-8 string
406 * Since: 2.10
408 gchar *
409 gimp_config_path_unexpand (const gchar *path,
410 gboolean recode,
411 GError **error)
413 g_return_val_if_fail (path != NULL, NULL);
414 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
416 if (recode)
418 gchar *retval;
419 gchar *utf8 = g_filename_to_utf8 (path, -1, NULL, NULL, error);
421 if (! utf8)
422 return NULL;
424 retval = gimp_config_path_unexpand_only (utf8);
426 g_free (utf8);
428 return retval;
431 return gimp_config_path_unexpand_only (path);
435 * gimp_file_new_for_config_path:
436 * @path: a NUL-terminated string in UTF-8 encoding
437 * @error: return location for errors
439 * Expands @path using gimp_config_path_expand() and returns a #GFile
440 * for the expanded path.
442 * To reverse the expansion, use gimp_file_get_config_path().
444 * Return value: a newly allocated #GFile, or %NULL if the expansion failed.
446 * Since: 2.10
448 GFile *
449 gimp_file_new_for_config_path (const gchar *path,
450 GError **error)
452 GFile *file = NULL;
453 gchar *expanded;
455 g_return_val_if_fail (path != NULL, NULL);
456 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
458 expanded = gimp_config_path_expand (path, TRUE, error);
460 if (expanded)
462 file = g_file_new_for_path (expanded);
463 g_free (expanded);
466 return file;
470 * gimp_file_get_config_path:
471 * @file: a #GFile
472 * @error: return location for errors
474 * Unexpands @file's path using gimp_config_path_unexpand() and
475 * returns the unexpanded path.
477 * The inverse operation of gimp_file_new_for_config_path().
479 * Return value: a newly allocated NUL-terminated UTF-8 string, or %NULL if
480 * unexpanding failed.
482 * Since: 2.10
484 gchar *
485 gimp_file_get_config_path (GFile *file,
486 GError **error)
488 gchar *unexpanded = NULL;
489 gchar *path;
491 g_return_val_if_fail (G_IS_FILE (file), NULL);
492 g_return_val_if_fail (error == NULL || *error == NULL, NULL);
494 path = g_file_get_path (file);
496 if (path)
498 unexpanded = gimp_config_path_unexpand (path, TRUE, error);
499 g_free (path);
501 else
503 g_set_error_literal (error, 0, 0,
504 _("File has no path representation"));
507 return unexpanded;
511 /* private functions */
513 #define SUBSTS_ALLOC 4
515 static gchar *
516 gimp_config_path_expand_only (const gchar *path,
517 GError **error)
519 const gchar *home;
520 const gchar *p;
521 const gchar *s;
522 gchar *n;
523 gchar *token;
524 gchar *filename = NULL;
525 gchar *expanded = NULL;
526 gchar **substs = NULL;
527 guint n_substs = 0;
528 gint length = 0;
529 gint i;
531 home = g_get_home_dir ();
532 if (home)
533 home = gimp_filename_to_utf8 (home);
535 p = path;
537 while (*p)
539 if (*p == '~' && home)
541 length += strlen (home);
542 p += 1;
544 else if ((token = gimp_config_path_extract_token (&p)) != NULL)
546 for (i = 0; i < n_substs; i++)
547 if (strcmp (substs[2*i], token) == 0)
548 break;
550 if (i < n_substs)
552 s = substs[2*i+1];
554 else
556 s = NULL;
558 if (strcmp (token, "gimp_dir") == 0)
559 s = gimp_directory ();
560 else if (strcmp (token, "gimp_data_dir") == 0)
561 s = gimp_data_directory ();
562 else if (strcmp (token, "gimp_plug_in_dir") == 0 ||
563 strcmp (token, "gimp_plugin_dir") == 0)
564 s = gimp_plug_in_directory ();
565 else if (strcmp (token, "gimp_sysconf_dir") == 0)
566 s = gimp_sysconf_directory ();
567 else if (strcmp (token, "gimp_installation_dir") == 0)
568 s = gimp_installation_directory ();
570 if (!s)
571 s = g_getenv (token);
573 #ifdef G_OS_WIN32
574 /* The default user gimprc on Windows references
575 * ${TEMP}, but not all Windows installations have that
576 * environment variable, even if it should be kinda
577 * standard. So special-case it.
579 if (!s && strcmp (token, "TEMP") == 0)
580 s = g_get_tmp_dir ();
581 #endif /* G_OS_WIN32 */
584 if (!s)
586 g_set_error (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE,
587 _("Cannot expand ${%s}"), token);
588 g_free (token);
589 goto cleanup;
592 if (n_substs % SUBSTS_ALLOC == 0)
593 substs = g_renew (gchar *, substs, 2 * (n_substs + SUBSTS_ALLOC));
595 substs[2*n_substs] = token;
596 substs[2*n_substs + 1] = (gchar *) gimp_filename_to_utf8 (s);
598 length += strlen (substs[2*n_substs + 1]);
600 n_substs++;
602 else
604 length += g_utf8_skip[(const guchar) *p];
605 p = g_utf8_next_char (p);
609 if (n_substs == 0)
610 return g_strdup (path);
612 expanded = g_new (gchar, length + 1);
614 p = path;
615 n = expanded;
617 while (*p)
619 if (*p == '~' && home)
621 *n = '\0';
622 strcat (n, home);
623 n += strlen (home);
624 p += 1;
626 else if ((token = gimp_config_path_extract_token (&p)) != NULL)
628 for (i = 0; i < n_substs; i++)
630 if (strcmp (substs[2*i], token) == 0)
632 s = substs[2*i+1];
634 *n = '\0';
635 strcat (n, s);
636 n += strlen (s);
638 break;
642 g_free (token);
644 else
646 *n++ = *p++;
650 *n = '\0';
652 cleanup:
653 for (i = 0; i < n_substs; i++)
654 g_free (substs[2*i]);
656 g_free (substs);
657 g_free (filename);
659 return expanded;
662 static inline gchar *
663 gimp_config_path_extract_token (const gchar **str)
665 const gchar *p;
666 gchar *token;
668 if (strncmp (*str, "${", 2))
669 return NULL;
671 p = *str + 2;
673 while (*p && (*p != '}'))
674 p = g_utf8_next_char (p);
676 if (! *p)
677 return NULL;
679 token = g_strndup (*str + 2, g_utf8_pointer_to_offset (*str + 2, p));
681 *str = p + 1; /* after the closing bracket */
683 return token;
686 static gchar *
687 gimp_config_path_unexpand_only (const gchar *path)
689 const struct
691 const gchar *id;
692 const gchar *prefix;
694 identifiers[] =
696 { "${gimp_plug_in_dir}", gimp_plug_in_directory () },
697 { "${gimp_data_dir}", gimp_data_directory () },
698 { "${gimp_sysconf_dir}", gimp_sysconf_directory () },
699 { "${gimp_installation_dir}", gimp_installation_directory () },
700 { "${gimp_dir}", gimp_directory () }
703 GList *files;
704 GList *list;
705 gchar *unexpanded;
707 files = gimp_path_parse (path, 256, FALSE, NULL);
709 for (list = files; list; list = g_list_next (list))
711 gchar *dir = list->data;
712 gint i;
714 for (i = 0; i < G_N_ELEMENTS (identifiers); i++)
716 if (g_str_has_prefix (dir, identifiers[i].prefix))
718 gchar *tmp = g_strconcat (identifiers[i].id,
719 dir + strlen (identifiers[i].prefix),
720 NULL);
722 g_free (dir);
723 list->data = tmp;
725 break;
730 unexpanded = gimp_path_to_str (files);
732 gimp_path_free (files);
734 return unexpanded;