1 /* LIBGIMP - The GIMP Library
2 * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
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/>.
29 #include "libgimpbase/gimpbase.h"
31 #include "gimpconfig-error.h"
32 #include "gimpconfig-path.h"
34 #include "libgimp/libgimp-intl.h"
38 * SECTION: gimpconfig-path
39 * @title: GimpConfig-path
40 * @short_description: File path utilities for libgimpconfig.
42 * File path utilities for libgimpconfig.
47 * gimp_config_path_get_type:
49 * Reveals the object type
51 * Returns: the #GType for a GimpConfigPath string property
56 gimp_config_path_get_type (void)
58 static GType path_type
= 0;
62 const GTypeInfo type_info
= { 0, };
64 path_type
= g_type_register_static (G_TYPE_STRING
, "GimpConfigPath",
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);
90 * gimp_param_config_path_get_type:
92 * Reveals the object type
94 * Returns: the #GType for a directory path object
99 gimp_param_config_path_get_type (void)
101 static GType spec_type
= 0;
105 const GTypeInfo type_info
=
107 sizeof (GParamSpecClass
),
109 (GClassInitFunc
) gimp_param_config_path_class_init
,
111 sizeof (GimpParamSpecConfigPath
),
115 spec_type
= g_type_register_static (G_TYPE_PARAM_STRING
,
116 "GimpParamConfigPath",
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
147 gimp_param_spec_config_path (const gchar
*name
,
150 GimpConfigPathType type
,
151 const gchar
*default_value
,
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
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
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
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
,
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
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
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
,
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
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
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
313 gimp_config_path_expand (const gchar
*path
,
317 g_return_val_if_fail (path
!= NULL
, NULL
);
318 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
323 gchar
*expanded
= gimp_config_path_expand_only (path
, error
);
328 retval
= g_filename_from_utf8 (expanded
, -1, NULL
, NULL
, error
);
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.
358 gimp_config_path_expand_to_files (const gchar
*path
,
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
);
373 files
= gimp_path_parse (expanded
, 256, FALSE
, NULL
);
377 for (list
= files
; list
; list
= g_list_next (list
))
379 gchar
*dir
= list
->data
;
381 list
->data
= g_file_new_for_path (dir
);
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
409 gimp_config_path_unexpand (const gchar
*path
,
413 g_return_val_if_fail (path
!= NULL
, NULL
);
414 g_return_val_if_fail (error
== NULL
|| *error
== NULL
, NULL
);
419 gchar
*utf8
= g_filename_to_utf8 (path
, -1, NULL
, NULL
, error
);
424 retval
= gimp_config_path_unexpand_only (utf8
);
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.
449 gimp_file_new_for_config_path (const gchar
*path
,
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
);
462 file
= g_file_new_for_path (expanded
);
470 * gimp_file_get_config_path:
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.
485 gimp_file_get_config_path (GFile
*file
,
488 gchar
*unexpanded
= NULL
;
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
);
498 unexpanded
= gimp_config_path_unexpand (path
, TRUE
, error
);
503 g_set_error_literal (error
, 0, 0,
504 _("File has no path representation"));
511 /* private functions */
513 #define SUBSTS_ALLOC 4
516 gimp_config_path_expand_only (const gchar
*path
,
524 gchar
*filename
= NULL
;
525 gchar
*expanded
= NULL
;
526 gchar
**substs
= NULL
;
531 home
= g_get_home_dir ();
533 home
= gimp_filename_to_utf8 (home
);
539 if (*p
== '~' && home
)
541 length
+= strlen (home
);
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)
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 ();
571 s
= g_getenv (token
);
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 */
586 g_set_error (error
, GIMP_CONFIG_ERROR
, GIMP_CONFIG_ERROR_PARSE
,
587 _("Cannot expand ${%s}"), token
);
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]);
604 length
+= g_utf8_skip
[(const guchar
) *p
];
605 p
= g_utf8_next_char (p
);
610 return g_strdup (path
);
612 expanded
= g_new (gchar
, length
+ 1);
619 if (*p
== '~' && home
)
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)
653 for (i
= 0; i
< n_substs
; i
++)
654 g_free (substs
[2*i
]);
662 static inline gchar
*
663 gimp_config_path_extract_token (const gchar
**str
)
668 if (strncmp (*str
, "${", 2))
673 while (*p
&& (*p
!= '}'))
674 p
= g_utf8_next_char (p
);
679 token
= g_strndup (*str
+ 2, g_utf8_pointer_to_offset (*str
+ 2, p
));
681 *str
= p
+ 1; /* after the closing bracket */
687 gimp_config_path_unexpand_only (const gchar
*path
)
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 () }
707 files
= gimp_path_parse (path
, 256, FALSE
, NULL
);
709 for (list
= files
; list
; list
= g_list_next (list
))
711 gchar
*dir
= list
->data
;
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
),
730 unexpanded
= gimp_path_to_str (files
);
732 gimp_path_free (files
);