gimpconfig-path.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751
  1. /* LIBGIMP - The GIMP Library
  2. * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
  3. *
  4. * gimpconfig-path.c
  5. * Copyright (C) 2001 Sven Neumann <sven@gimp.org>
  6. *
  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.
  11. *
  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.
  16. *
  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/>.
  20. */
  21. #include "config.h"
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <gio/gio.h>
  25. #include "libgimpbase/gimpbase.h"
  26. #include "gimpconfig-error.h"
  27. #include "gimpconfig-path.h"
  28. #include "libgimp/libgimp-intl.h"
  29. /**
  30. * SECTION: gimpconfig-path
  31. * @title: GimpConfig-path
  32. * @short_description: File path utilities for libgimpconfig.
  33. *
  34. * File path utilities for libgimpconfig.
  35. **/
  36. /**
  37. * gimp_config_path_get_type:
  38. *
  39. * Reveals the object type
  40. *
  41. * Returns: the #GType for a GimpConfigPath string property
  42. *
  43. * Since: 2.4
  44. **/
  45. GType
  46. gimp_config_path_get_type (void)
  47. {
  48. static GType path_type = 0;
  49. if (! path_type)
  50. {
  51. const GTypeInfo type_info = { 0, };
  52. path_type = g_type_register_static (G_TYPE_STRING, "GimpConfigPath",
  53. &type_info, 0);
  54. }
  55. return path_type;
  56. }
  57. /*
  58. * GIMP_TYPE_PARAM_CONFIG_PATH
  59. */
  60. #define GIMP_PARAM_SPEC_CONFIG_PATH(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_CONFIG_PATH, GimpParamSpecConfigPath))
  61. typedef struct _GimpParamSpecConfigPath GimpParamSpecConfigPath;
  62. struct _GimpParamSpecConfigPath
  63. {
  64. GParamSpecString parent_instance;
  65. GimpConfigPathType type;
  66. };
  67. static void gimp_param_config_path_class_init (GParamSpecClass *class);
  68. /**
  69. * gimp_param_config_path_get_type:
  70. *
  71. * Reveals the object type
  72. *
  73. * Returns: the #GType for a directory path object
  74. *
  75. * Since: 2.4
  76. **/
  77. GType
  78. gimp_param_config_path_get_type (void)
  79. {
  80. static GType spec_type = 0;
  81. if (! spec_type)
  82. {
  83. const GTypeInfo type_info =
  84. {
  85. sizeof (GParamSpecClass),
  86. NULL, NULL,
  87. (GClassInitFunc) gimp_param_config_path_class_init,
  88. NULL, NULL,
  89. sizeof (GimpParamSpecConfigPath),
  90. 0, NULL, NULL
  91. };
  92. spec_type = g_type_register_static (G_TYPE_PARAM_STRING,
  93. "GimpParamConfigPath",
  94. &type_info, 0);
  95. }
  96. return spec_type;
  97. }
  98. static void
  99. gimp_param_config_path_class_init (GParamSpecClass *class)
  100. {
  101. class->value_type = GIMP_TYPE_CONFIG_PATH;
  102. }
  103. /**
  104. * gimp_param_spec_config_path:
  105. * @name: Canonical name of the param
  106. * @nick: Nickname of the param
  107. * @blurb: Brief description of param.
  108. * @type: a #GimpConfigPathType value.
  109. * @default_value: Value to use if none is assigned.
  110. * @flags: a combination of #GParamFlags
  111. *
  112. * Creates a param spec to hold a filename, dir name,
  113. * or list of file or dir names.
  114. * See g_param_spec_internal() for more information.
  115. *
  116. * Returns: (transfer full): a newly allocated #GParamSpec instance
  117. *
  118. * Since: 2.4
  119. **/
  120. GParamSpec *
  121. gimp_param_spec_config_path (const gchar *name,
  122. const gchar *nick,
  123. const gchar *blurb,
  124. GimpConfigPathType type,
  125. const gchar *default_value,
  126. GParamFlags flags)
  127. {
  128. GParamSpecString *pspec;
  129. pspec = g_param_spec_internal (GIMP_TYPE_PARAM_CONFIG_PATH,
  130. name, nick, blurb, flags);
  131. pspec->default_value = g_strdup (default_value);
  132. GIMP_PARAM_SPEC_CONFIG_PATH (pspec)->type = type;
  133. return G_PARAM_SPEC (pspec);
  134. }
  135. /**
  136. * gimp_param_spec_config_path_type:
  137. * @pspec: A #GParamSpec for a path param
  138. *
  139. * Tells whether the path param encodes a filename,
  140. * dir name, or list of file or dir names.
  141. *
  142. * Returns: a #GimpConfigPathType value
  143. *
  144. * Since: 2.4
  145. **/
  146. GimpConfigPathType
  147. gimp_param_spec_config_path_type (GParamSpec *pspec)
  148. {
  149. g_return_val_if_fail (GIMP_IS_PARAM_SPEC_CONFIG_PATH (pspec), 0);
  150. return GIMP_PARAM_SPEC_CONFIG_PATH (pspec)->type;
  151. }
  152. /*
  153. * GimpConfig path utilities
  154. */
  155. static gchar * gimp_config_path_expand_only (const gchar *path,
  156. GError **error) G_GNUC_MALLOC;
  157. static inline gchar * gimp_config_path_extract_token (const gchar **str);
  158. static gchar * gimp_config_path_unexpand_only (const gchar *path) G_GNUC_MALLOC;
  159. /**
  160. * gimp_config_build_data_path:
  161. * @name: directory name (in UTF-8 encoding)
  162. *
  163. * Creates a search path as it is used in the gimprc file. The path
  164. * returned by gimp_config_build_data_path() includes a directory
  165. * below the user's gimp directory and one in the system-wide data
  166. * directory.
  167. *
  168. * Note that you cannot use this path directly with gimp_path_parse().
  169. * As it is in the gimprc notation, you first need to expand and
  170. * recode it using gimp_config_path_expand().
  171. *
  172. * Returns: a newly allocated string
  173. *
  174. * Since: 2.4
  175. **/
  176. gchar *
  177. gimp_config_build_data_path (const gchar *name)
  178. {
  179. if (g_getenv ("GIMP_TESTING_ABS_TOP_SRCDIR"))
  180. /* Unit-testing mode: the source directory is where data is found. */
  181. return g_strconcat (g_getenv ("GIMP_TESTING_ABS_TOP_SRCDIR"),
  182. G_DIR_SEPARATOR_S, "data",
  183. G_DIR_SEPARATOR_S, name,
  184. NULL);
  185. else
  186. return g_strconcat ("${gimp_dir}", G_DIR_SEPARATOR_S, name,
  187. G_SEARCHPATH_SEPARATOR_S,
  188. "${gimp_data_dir}", G_DIR_SEPARATOR_S, name,
  189. NULL);
  190. }
  191. /**
  192. * gimp_config_build_plug_in_path:
  193. * @name: directory name (in UTF-8 encoding)
  194. *
  195. * Creates a search path as it is used in the gimprc file. The path
  196. * returned by gimp_config_build_plug_in_path() includes a directory
  197. * below the user's gimp directory and one in the system-wide plug-in
  198. * directory.
  199. *
  200. * Note that you cannot use this path directly with gimp_path_parse().
  201. * As it is in the gimprc notation, you first need to expand and
  202. * recode it using gimp_config_path_expand().
  203. *
  204. * Returns: a newly allocated string
  205. *
  206. * Since: 2.4
  207. **/
  208. gchar *
  209. gimp_config_build_plug_in_path (const gchar *name)
  210. {
  211. return g_strconcat ("${gimp_dir}", G_DIR_SEPARATOR_S, name,
  212. G_SEARCHPATH_SEPARATOR_S,
  213. "${gimp_plug_in_dir}", G_DIR_SEPARATOR_S, name,
  214. NULL);
  215. }
  216. /**
  217. * gimp_config_build_writable_path:
  218. * @name: directory name (in UTF-8 encoding)
  219. *
  220. * Creates a search path as it is used in the gimprc file. The path
  221. * returned by gimp_config_build_writable_path() is just the writable
  222. * parts of the search path constructed by gimp_config_build_data_path().
  223. *
  224. * Note that you cannot use this path directly with gimp_path_parse().
  225. * As it is in the gimprc notation, you first need to expand and
  226. * recode it using gimp_config_path_expand().
  227. *
  228. * Returns: a newly allocated string
  229. *
  230. * Since: 2.4
  231. **/
  232. gchar *
  233. gimp_config_build_writable_path (const gchar *name)
  234. {
  235. return g_strconcat ("${gimp_dir}", G_DIR_SEPARATOR_S, name, NULL);
  236. }
  237. /**
  238. * gimp_config_build_system_path:
  239. * @name: directory name (in UTF-8 encoding)
  240. *
  241. * Creates a search path as it is used in the gimprc file. The path
  242. * returned by gimp_config_build_system_path() is just the read-only
  243. * parts of the search path constructed by gimp_config_build_plug_in_path().
  244. *
  245. * Note that you cannot use this path directly with gimp_path_parse().
  246. * As it is in the gimprc notation, you first need to expand and
  247. * recode it using gimp_config_path_expand().
  248. *
  249. * Returns: a newly allocated string
  250. *
  251. * Since: 2.10.6
  252. **/
  253. gchar *
  254. gimp_config_build_system_path (const gchar *name)
  255. {
  256. return g_strconcat ("${gimp_plug_in_dir}", G_DIR_SEPARATOR_S, name, NULL);
  257. }
  258. /**
  259. * gimp_config_path_expand:
  260. * @path: a NUL-terminated string in UTF-8 encoding
  261. * @recode: whether to convert to the filesystem's encoding
  262. * @error: return location for errors
  263. *
  264. * Paths as stored in gimprc and other config files have to be treated
  265. * special. The string may contain special identifiers such as for
  266. * example ${gimp_dir} that have to be substituted before use. Also
  267. * the user's filesystem may be in a different encoding than UTF-8
  268. * (which is what is used for the gimprc). This function does the
  269. * variable substitution for you and can also attempt to convert to
  270. * the filesystem encoding.
  271. *
  272. * To reverse the expansion, use gimp_config_path_unexpand().
  273. *
  274. * Returns: a newly allocated NUL-terminated string
  275. *
  276. * Since: 2.4
  277. **/
  278. gchar *
  279. gimp_config_path_expand (const gchar *path,
  280. gboolean recode,
  281. GError **error)
  282. {
  283. g_return_val_if_fail (path != NULL, NULL);
  284. g_return_val_if_fail (error == NULL || *error == NULL, NULL);
  285. if (recode)
  286. {
  287. gchar *retval;
  288. gchar *expanded = gimp_config_path_expand_only (path, error);
  289. if (! expanded)
  290. return NULL;
  291. retval = g_filename_from_utf8 (expanded, -1, NULL, NULL, error);
  292. g_free (expanded);
  293. return retval;
  294. }
  295. return gimp_config_path_expand_only (path, error);
  296. }
  297. /**
  298. * gimp_config_path_expand_to_files:
  299. * @path: a NUL-terminated string in UTF-8 encoding
  300. * @error: return location for errors
  301. *
  302. * Paths as stored in the gimprc have to be treated special. The
  303. * string may contain special identifiers such as for example
  304. * ${gimp_dir} that have to be substituted before use. Also the user's
  305. * filesystem may be in a different encoding than UTF-8 (which is what
  306. * is used for the gimprc).
  307. *
  308. * This function runs @path through gimp_config_path_expand() and
  309. * gimp_path_parse(), then turns the filenames returned by
  310. * gimp_path_parse() into GFile using g_file_new_for_path().
  311. *
  312. * Returns: (element-type GFile) (transfer full):
  313. a #GList of newly allocated #GFile objects.
  314. *
  315. * Since: 2.10
  316. **/
  317. GList *
  318. gimp_config_path_expand_to_files (const gchar *path,
  319. GError **error)
  320. {
  321. GList *files;
  322. GList *list;
  323. gchar *expanded;
  324. g_return_val_if_fail (path != NULL, NULL);
  325. g_return_val_if_fail (error == NULL || *error == NULL, NULL);
  326. expanded = gimp_config_path_expand (path, TRUE, error);
  327. if (! expanded)
  328. return NULL;
  329. files = gimp_path_parse (expanded, 256, FALSE, NULL);
  330. g_free (expanded);
  331. for (list = files; list; list = g_list_next (list))
  332. {
  333. gchar *dir = list->data;
  334. list->data = g_file_new_for_path (dir);
  335. g_free (dir);
  336. }
  337. return files;
  338. }
  339. /**
  340. * gimp_config_path_unexpand:
  341. * @path: a NUL-terminated string
  342. * @recode: whether @path is in filesystem encoding or UTF-8
  343. * @error: return location for errors
  344. *
  345. * The inverse operation of gimp_config_path_expand()
  346. *
  347. * This function takes a @path and tries to substitute the first
  348. * elements by well-known special identifiers such as for example
  349. * ${gimp_dir}. The unexpanded path can then be stored in gimprc and
  350. * other config files.
  351. *
  352. * If @recode is %TRUE then @path is in local filesystem encoding,
  353. * if @recode is %FALSE then @path is assumed to be UTF-8.
  354. *
  355. * Returns: a newly allocated NUL-terminated UTF-8 string
  356. *
  357. * Since: 2.10
  358. **/
  359. gchar *
  360. gimp_config_path_unexpand (const gchar *path,
  361. gboolean recode,
  362. GError **error)
  363. {
  364. g_return_val_if_fail (path != NULL, NULL);
  365. g_return_val_if_fail (error == NULL || *error == NULL, NULL);
  366. if (recode)
  367. {
  368. gchar *retval;
  369. gchar *utf8 = g_filename_to_utf8 (path, -1, NULL, NULL, error);
  370. if (! utf8)
  371. return NULL;
  372. retval = gimp_config_path_unexpand_only (utf8);
  373. g_free (utf8);
  374. return retval;
  375. }
  376. return gimp_config_path_unexpand_only (path);
  377. }
  378. /**
  379. * gimp_file_new_for_config_path:
  380. * @path: a NUL-terminated string in UTF-8 encoding
  381. * @error: return location for errors
  382. *
  383. * Expands @path using gimp_config_path_expand() and returns a #GFile
  384. * for the expanded path.
  385. *
  386. * To reverse the expansion, use gimp_file_get_config_path().
  387. *
  388. * Returns: (nullable) (transfer full): a newly allocated #GFile,
  389. * or %NULL if the expansion failed.
  390. *
  391. * Since: 2.10
  392. **/
  393. GFile *
  394. gimp_file_new_for_config_path (const gchar *path,
  395. GError **error)
  396. {
  397. GFile *file = NULL;
  398. gchar *expanded;
  399. g_return_val_if_fail (path != NULL, NULL);
  400. g_return_val_if_fail (error == NULL || *error == NULL, NULL);
  401. expanded = gimp_config_path_expand (path, TRUE, error);
  402. if (expanded)
  403. {
  404. file = g_file_new_for_path (expanded);
  405. g_free (expanded);
  406. }
  407. return file;
  408. }
  409. /**
  410. * gimp_file_get_config_path:
  411. * @file: a #GFile
  412. * @error: return location for errors
  413. *
  414. * Unexpands @file's path using gimp_config_path_unexpand() and
  415. * returns the unexpanded path.
  416. *
  417. * The inverse operation of gimp_file_new_for_config_path().
  418. *
  419. * Returns: a newly allocated NUL-terminated UTF-8 string, or %NULL if
  420. * unexpanding failed.
  421. *
  422. * Since: 2.10
  423. **/
  424. gchar *
  425. gimp_file_get_config_path (GFile *file,
  426. GError **error)
  427. {
  428. gchar *unexpanded = NULL;
  429. gchar *path;
  430. g_return_val_if_fail (G_IS_FILE (file), NULL);
  431. g_return_val_if_fail (error == NULL || *error == NULL, NULL);
  432. path = g_file_get_path (file);
  433. if (path)
  434. {
  435. unexpanded = gimp_config_path_unexpand (path, TRUE, error);
  436. g_free (path);
  437. }
  438. else
  439. {
  440. g_set_error_literal (error, 0, 0,
  441. _("File has no path representation"));
  442. }
  443. return unexpanded;
  444. }
  445. /* private functions */
  446. #define SUBSTS_ALLOC 4
  447. static gchar *
  448. gimp_config_path_expand_only (const gchar *path,
  449. GError **error)
  450. {
  451. const gchar *home;
  452. const gchar *p;
  453. const gchar *s;
  454. gchar *n;
  455. gchar *token;
  456. gchar *filename = NULL;
  457. gchar *expanded = NULL;
  458. gchar **substs = NULL;
  459. guint n_substs = 0;
  460. gint length = 0;
  461. guint i;
  462. home = g_get_home_dir ();
  463. if (home)
  464. home = gimp_filename_to_utf8 (home);
  465. p = path;
  466. while (*p)
  467. {
  468. if (*p == '~' && home)
  469. {
  470. length += strlen (home);
  471. p += 1;
  472. }
  473. else if ((token = gimp_config_path_extract_token (&p)) != NULL)
  474. {
  475. for (i = 0; i < n_substs; i++)
  476. if (strcmp (substs[2*i], token) == 0)
  477. break;
  478. if (i < n_substs)
  479. {
  480. s = substs[2*i+1];
  481. }
  482. else
  483. {
  484. s = NULL;
  485. if (strcmp (token, "gimp_dir") == 0)
  486. s = gimp_directory ();
  487. else if (strcmp (token, "gimp_data_dir") == 0)
  488. s = gimp_data_directory ();
  489. else if (strcmp (token, "gimp_plug_in_dir") == 0 ||
  490. strcmp (token, "gimp_plugin_dir") == 0)
  491. s = gimp_plug_in_directory ();
  492. else if (strcmp (token, "gimp_sysconf_dir") == 0)
  493. s = gimp_sysconf_directory ();
  494. else if (strcmp (token, "gimp_installation_dir") == 0)
  495. s = gimp_installation_directory ();
  496. else if (strcmp (token, "gimp_cache_dir") == 0)
  497. s = gimp_cache_directory ();
  498. else if (strcmp (token, "gimp_temp_dir") == 0)
  499. s = gimp_temp_directory ();
  500. if (!s)
  501. s = g_getenv (token);
  502. #ifdef G_OS_WIN32
  503. /* The default user gimprc on Windows references
  504. * ${TEMP}, but not all Windows installations have that
  505. * environment variable, even if it should be kinda
  506. * standard. So special-case it.
  507. */
  508. if (!s && strcmp (token, "TEMP") == 0)
  509. s = g_get_tmp_dir ();
  510. #endif /* G_OS_WIN32 */
  511. }
  512. if (!s)
  513. {
  514. g_set_error (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE,
  515. _("Cannot expand ${%s}"), token);
  516. g_free (token);
  517. goto cleanup;
  518. }
  519. if (n_substs % SUBSTS_ALLOC == 0)
  520. substs = g_renew (gchar *, substs, 2 * (n_substs + SUBSTS_ALLOC));
  521. substs[2*n_substs] = token;
  522. substs[2*n_substs + 1] = (gchar *) gimp_filename_to_utf8 (s);
  523. length += strlen (substs[2*n_substs + 1]);
  524. n_substs++;
  525. }
  526. else
  527. {
  528. length += g_utf8_skip[(const guchar) *p];
  529. p = g_utf8_next_char (p);
  530. }
  531. }
  532. if (n_substs == 0)
  533. return g_strdup (path);
  534. expanded = g_new (gchar, length + 1);
  535. p = path;
  536. n = expanded;
  537. while (*p)
  538. {
  539. if (*p == '~' && home)
  540. {
  541. *n = '\0';
  542. strcat (n, home);
  543. n += strlen (home);
  544. p += 1;
  545. }
  546. else if ((token = gimp_config_path_extract_token (&p)) != NULL)
  547. {
  548. for (i = 0; i < n_substs; i++)
  549. {
  550. if (strcmp (substs[2*i], token) == 0)
  551. {
  552. s = substs[2*i+1];
  553. *n = '\0';
  554. strcat (n, s);
  555. n += strlen (s);
  556. break;
  557. }
  558. }
  559. g_free (token);
  560. }
  561. else
  562. {
  563. *n++ = *p++;
  564. }
  565. }
  566. *n = '\0';
  567. cleanup:
  568. for (i = 0; i < n_substs; i++)
  569. g_free (substs[2*i]);
  570. g_free (substs);
  571. g_free (filename);
  572. return expanded;
  573. }
  574. static inline gchar *
  575. gimp_config_path_extract_token (const gchar **str)
  576. {
  577. const gchar *p;
  578. gchar *token;
  579. if (strncmp (*str, "${", 2))
  580. return NULL;
  581. p = *str + 2;
  582. while (*p && (*p != '}'))
  583. p = g_utf8_next_char (p);
  584. if (! *p)
  585. return NULL;
  586. token = g_strndup (*str + 2, g_utf8_pointer_to_offset (*str + 2, p));
  587. *str = p + 1; /* after the closing bracket */
  588. return token;
  589. }
  590. static gchar *
  591. gimp_config_path_unexpand_only (const gchar *path)
  592. {
  593. const struct
  594. {
  595. const gchar *id;
  596. const gchar *prefix;
  597. }
  598. identifiers[] =
  599. {
  600. { "${gimp_plug_in_dir}", gimp_plug_in_directory () },
  601. { "${gimp_data_dir}", gimp_data_directory () },
  602. { "${gimp_sysconf_dir}", gimp_sysconf_directory () },
  603. { "${gimp_installation_dir}", gimp_installation_directory () },
  604. { "${gimp_cache_dir}", gimp_cache_directory () },
  605. { "${gimp_temp_dir}", gimp_temp_directory () },
  606. { "${gimp_dir}", gimp_directory () }
  607. };
  608. GList *files;
  609. GList *list;
  610. gchar *unexpanded;
  611. files = gimp_path_parse (path, 256, FALSE, NULL);
  612. for (list = files; list; list = g_list_next (list))
  613. {
  614. gchar *dir = list->data;
  615. gint i;
  616. for (i = 0; i < G_N_ELEMENTS (identifiers); i++)
  617. {
  618. if (g_str_has_prefix (dir, identifiers[i].prefix))
  619. {
  620. gchar *tmp = g_strconcat (identifiers[i].id,
  621. dir + strlen (identifiers[i].prefix),
  622. NULL);
  623. g_free (dir);
  624. list->data = tmp;
  625. break;
  626. }
  627. }
  628. }
  629. unexpanded = gimp_path_to_str (files);
  630. gimp_path_free (files);
  631. return unexpanded;
  632. }