girepository: Use an array to iterate over and return the search paths

We used to store the search paths into a GSList but this is not
efficient for various reasons, so replace this with an array so that we
can replace return just a GStrv in the public API.
This commit is contained in:
Marco Trevisan (Treviño) 2023-12-20 06:29:40 +01:00
parent a8588b803e
commit 2c00c7c924
4 changed files with 99 additions and 79 deletions

View File

@ -58,7 +58,7 @@
*/ */
static GIRepository *default_repository = NULL; static GIRepository *default_repository = NULL;
static GSList *typelib_search_path = NULL; static GPtrArray *typelib_search_path = NULL;
typedef struct { typedef struct {
guint n_interfaces; guint n_interfaces;
@ -198,32 +198,24 @@ init_globals (void)
*/ */
type_lib_path_env = g_getenv ("GI_TYPELIB_PATH"); type_lib_path_env = g_getenv ("GI_TYPELIB_PATH");
typelib_search_path = NULL;
if (type_lib_path_env) if (type_lib_path_env)
{ {
gchar **custom_dirs; gchar **custom_dirs;
gchar **d;
custom_dirs = g_strsplit (type_lib_path_env, G_SEARCHPATH_SEPARATOR_S, 0); custom_dirs = g_strsplit (type_lib_path_env, G_SEARCHPATH_SEPARATOR_S, 0);
typelib_search_path =
d = custom_dirs; g_ptr_array_new_take_null_terminated ((gpointer) g_steal_pointer (&custom_dirs), g_free);
while (*d) }
{ else
typelib_search_path = g_slist_prepend (typelib_search_path, *d); {
d++; typelib_search_path = g_ptr_array_new_null_terminated (1, g_free, TRUE);
}
/* ownership of the array content was passed to the list */
g_free (custom_dirs);
} }
libdir = GOBJECT_INTROSPECTION_LIBDIR; libdir = GOBJECT_INTROSPECTION_LIBDIR;
typelib_dir = g_build_filename (libdir, "girepository-1.0", NULL); typelib_dir = g_build_filename (libdir, "girepository-1.0", NULL);
typelib_search_path = g_slist_prepend (typelib_search_path, typelib_dir); g_ptr_array_add (typelib_search_path, g_steal_pointer (&typelib_dir));
typelib_search_path = g_slist_reverse (typelib_search_path);
} }
g_once_init_leave (&initialized, 1); g_once_init_leave (&initialized, 1);
@ -244,11 +236,12 @@ void
gi_repository_prepend_search_path (const char *directory) gi_repository_prepend_search_path (const char *directory)
{ {
init_globals (); init_globals ();
typelib_search_path = g_slist_prepend (typelib_search_path, g_strdup (directory)); g_ptr_array_insert (typelib_search_path, 0, g_strdup (directory));
} }
/** /**
* gi_repository_get_search_path: * gi_repository_get_search_path:
* @n_paths_out: (optional) (out): The number of search paths returned.
* *
* Returns the current search path [class@GIRepository.Repository] will use when * Returns the current search path [class@GIRepository.Repository] will use when
* loading typelib files. * loading typelib files.
@ -256,14 +249,27 @@ gi_repository_prepend_search_path (const char *directory)
* The list is internal to [class@GIRepository.Repository] and should not be * The list is internal to [class@GIRepository.Repository] and should not be
* freed, nor should its string elements. * freed, nor should its string elements.
* *
* Returns: (element-type filename) (transfer none): list of search paths, most * Returns: (element-type filename) (transfer none) (array length=n_paths_out): list of search paths, most
* important first * important first
* Since: 2.80 * Since: 2.80
*/ */
GSList * const char * const *
gi_repository_get_search_path (void) gi_repository_get_search_path (size_t *n_paths_out)
{ {
return typelib_search_path; if G_UNLIKELY (!typelib_search_path || !typelib_search_path->pdata)
{
static const char * const empty_search_path[] = {NULL};
if (n_paths_out)
*n_paths_out = 0;
return empty_search_path;
}
if (n_paths_out)
*n_paths_out = typelib_search_path->len;
return (const char * const *) typelib_search_path->pdata;
} }
static char * static char *
@ -1310,21 +1316,21 @@ gi_repository_get_typelib_path (GIRepository *repository,
/* This simple search function looks for a specified namespace-version; /* This simple search function looks for a specified namespace-version;
it's faster than the full directory listing required for latest version. */ it's faster than the full directory listing required for latest version. */
static GMappedFile * static GMappedFile *
find_namespace_version (const gchar *namespace, find_namespace_version (const char *namespace,
const gchar *version, const char *version,
GSList *search_path, const char * const *search_paths,
gchar **path_ret) size_t n_search_paths,
char **path_ret)
{ {
GSList *ldir;
GError *error = NULL; GError *error = NULL;
GMappedFile *mfile = NULL; GMappedFile *mfile = NULL;
char *fname; char *fname;
fname = g_strdup_printf ("%s-%s.typelib", namespace, version); fname = g_strdup_printf ("%s-%s.typelib", namespace, version);
for (ldir = search_path; ldir; ldir = ldir->next) for (size_t i = 0; i < n_search_paths; ++i)
{ {
char *path = g_build_filename (ldir->data, fname, NULL); char *path = g_build_filename (search_paths[i], fname, NULL);
mfile = g_mapped_file_new (path, FALSE, &error); mfile = g_mapped_file_new (path, FALSE, &error);
if (error) if (error)
@ -1434,14 +1440,14 @@ free_candidate (struct NamespaceVersionCandidadate *candidate)
} }
static GSList * static GSList *
enumerate_namespace_versions (const gchar *namespace, enumerate_namespace_versions (const char *namespace,
GSList *search_path) const char * const *search_paths,
size_t n_search_paths)
{ {
GSList *candidates = NULL; GSList *candidates = NULL;
GHashTable *found_versions = g_hash_table_new (g_str_hash, g_str_equal); GHashTable *found_versions = g_hash_table_new (g_str_hash, g_str_equal);
char *namespace_dash; char *namespace_dash;
char *namespace_typelib; char *namespace_typelib;
GSList *ldir;
GError *error = NULL; GError *error = NULL;
int index; int index;
@ -1449,13 +1455,13 @@ enumerate_namespace_versions (const gchar *namespace,
namespace_typelib = g_strdup_printf ("%s.typelib", namespace); namespace_typelib = g_strdup_printf ("%s.typelib", namespace);
index = 0; index = 0;
for (ldir = search_path; ldir; ldir = ldir->next) for (size_t i = 0; i < n_search_paths; ++i)
{ {
GDir *dir; GDir *dir;
const char *dirname; const char *dirname;
const char *entry; const char *entry;
dirname = (const char*)ldir->data; dirname = search_paths[i];
dir = g_dir_open (dirname, 0, NULL); dir = g_dir_open (dirname, 0, NULL);
if (dir == NULL) if (dir == NULL)
continue; continue;
@ -1521,10 +1527,11 @@ enumerate_namespace_versions (const gchar *namespace,
} }
static GMappedFile * static GMappedFile *
find_namespace_latest (const gchar *namespace, find_namespace_latest (const char *namespace,
GSList *search_path, const char * const *search_paths,
gchar **version_ret, size_t n_search_paths,
gchar **path_ret) char **version_ret,
char **path_ret)
{ {
GSList *candidates; GSList *candidates;
GMappedFile *result = NULL; GMappedFile *result = NULL;
@ -1532,7 +1539,7 @@ find_namespace_latest (const gchar *namespace,
*version_ret = NULL; *version_ret = NULL;
*path_ret = NULL; *path_ret = NULL;
candidates = enumerate_namespace_versions (namespace, search_path); candidates = enumerate_namespace_versions (namespace, search_paths, n_search_paths);
if (candidates != NULL) if (candidates != NULL)
{ {
@ -1577,7 +1584,9 @@ gi_repository_enumerate_versions (GIRepository *repository,
char **ret; char **ret;
init_globals (); init_globals ();
candidates = enumerate_namespace_versions (namespace_, typelib_search_path); candidates = enumerate_namespace_versions (namespace_,
(const char * const *) typelib_search_path->pdata,
typelib_search_path->len);
if (!candidates) if (!candidates)
{ {
@ -1614,12 +1623,13 @@ gi_repository_enumerate_versions (GIRepository *repository,
} }
static GITypelib * static GITypelib *
require_internal (GIRepository *repository, require_internal (GIRepository *repository,
const gchar *namespace, const char *namespace,
const gchar *version, const char *version,
GIRepositoryLoadFlags flags, GIRepositoryLoadFlags flags,
GSList *search_path, const char * const *search_paths,
GError **error) size_t n_search_paths,
GError **error)
{ {
GMappedFile *mfile; GMappedFile *mfile;
GITypelib *ret = NULL; GITypelib *ret = NULL;
@ -1652,14 +1662,14 @@ require_internal (GIRepository *repository,
if (version != NULL) if (version != NULL)
{ {
mfile = find_namespace_version (namespace, version, mfile = find_namespace_version (namespace, version, search_paths,
search_path, &path); n_search_paths, &path);
tmp_version = g_strdup (version); tmp_version = g_strdup (version);
} }
else else
{ {
mfile = find_namespace_latest (namespace, search_path, mfile = find_namespace_latest (namespace, search_paths, n_search_paths,
&tmp_version, &path); &tmp_version, &path);
} }
if (mfile == NULL) if (mfile == NULL)
@ -1759,7 +1769,8 @@ gi_repository_require (GIRepository *repository,
init_globals (); init_globals ();
typelib = require_internal (repository, namespace, version, flags, typelib = require_internal (repository, namespace, version, flags,
typelib_search_path, error); (const char * const *) typelib_search_path->pdata,
typelib_search_path->len, error);
return typelib; return typelib;
} }
@ -1794,10 +1805,10 @@ gi_repository_require_private (GIRepository *repository,
GIRepositoryLoadFlags flags, GIRepositoryLoadFlags flags,
GError **error) GError **error)
{ {
GSList search_path = { (gpointer) typelib_dir, NULL }; const char * const search_path[] = { typelib_dir, NULL };
return require_internal (repository, namespace, version, flags, return require_internal (repository, namespace, version, flags,
&search_path, error); search_path, 1, error);
} }
static gboolean static gboolean

View File

@ -109,7 +109,7 @@ GI_AVAILABLE_IN_ALL
void gi_repository_prepend_library_path (const char *directory); void gi_repository_prepend_library_path (const char *directory);
GI_AVAILABLE_IN_ALL GI_AVAILABLE_IN_ALL
GSList * gi_repository_get_search_path (void); const char * const * gi_repository_get_search_path (size_t *n_paths_out);
GI_AVAILABLE_IN_ALL GI_AVAILABLE_IN_ALL
const char * gi_repository_load_typelib (GIRepository *repository, const char * gi_repository_load_typelib (GIRepository *repository,

View File

@ -26,32 +26,39 @@
static void static void
test_repository_search_paths_unset (void) test_repository_search_paths_unset (void)
{ {
GSList *search_paths; const char * const *search_paths;
size_t n_search_paths;
search_paths = gi_repository_get_search_path (); search_paths = gi_repository_get_search_path (&n_search_paths);
g_assert_null (search_paths); g_assert_nonnull (search_paths);
g_assert_cmpstrv (search_paths, ((char *[]){NULL}));
g_assert_cmpuint (n_search_paths, ==, 0);
search_paths = gi_repository_get_search_path (NULL);
g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 0);
} }
static void static void
test_repository_search_paths_default (void) test_repository_search_paths_default (void)
{ {
GSList *search_paths; const char * const *search_paths;
size_t n_search_paths;
search_paths = gi_repository_get_search_path (); search_paths = gi_repository_get_search_path (&n_search_paths);
g_assert_null (search_paths); g_assert_nonnull (search_paths);
/* Init default paths */ /* Init default paths */
g_assert_nonnull (gi_repository_get_default ()); g_assert_nonnull (gi_repository_get_default ());
search_paths = gi_repository_get_search_path (); search_paths = gi_repository_get_search_path (&n_search_paths);
g_assert_nonnull (search_paths); g_assert_nonnull (search_paths);
g_assert_cmpuint (g_slist_length (search_paths), ==, 2); g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 2);
g_assert_cmpstr (g_slist_nth_data (search_paths, 0), ==, g_get_tmp_dir ()); g_assert_cmpstr (search_paths[0], ==, g_get_tmp_dir ());
#ifndef G_PLATFORM_WIN32 #ifndef G_PLATFORM_WIN32
char *expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL); char *expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL);
g_assert_cmpstr (g_slist_nth_data (search_paths, 1), ==, expected_path); g_assert_cmpstr (search_paths[1], ==, expected_path);
g_clear_pointer (&expected_path, g_free); g_clear_pointer (&expected_path, g_free);
#endif #endif
} }
@ -59,34 +66,35 @@ test_repository_search_paths_default (void)
static void static void
test_repository_search_paths_prepend (void) test_repository_search_paths_prepend (void)
{ {
GSList *search_paths; const char * const *search_paths;
size_t n_search_paths;
gi_repository_prepend_search_path (g_test_get_dir (G_TEST_BUILT)); gi_repository_prepend_search_path (g_test_get_dir (G_TEST_BUILT));
search_paths = gi_repository_get_search_path (); search_paths = gi_repository_get_search_path (&n_search_paths);
g_assert_nonnull (search_paths); g_assert_nonnull (search_paths);
g_assert_cmpuint (g_slist_length (search_paths), ==, 3); g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 3);
g_assert_cmpstr (g_slist_nth_data (search_paths, 0), ==, g_test_get_dir (G_TEST_BUILT)); g_assert_cmpstr (search_paths[0], ==, g_test_get_dir (G_TEST_BUILT));
g_assert_cmpstr (g_slist_nth_data (search_paths, 1), ==, g_get_tmp_dir ()); g_assert_cmpstr (search_paths[1], ==, g_get_tmp_dir ());
#ifndef G_PLATFORM_WIN32 #ifndef G_PLATFORM_WIN32
char *expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL); char *expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL);
g_assert_cmpstr (g_slist_nth_data (search_paths, 2), ==, expected_path); g_assert_cmpstr (search_paths[2], ==, expected_path);
g_clear_pointer (&expected_path, g_free); g_clear_pointer (&expected_path, g_free);
#endif #endif
gi_repository_prepend_search_path (g_test_get_dir (G_TEST_DIST)); gi_repository_prepend_search_path (g_test_get_dir (G_TEST_DIST));
search_paths = gi_repository_get_search_path (); search_paths = gi_repository_get_search_path (&n_search_paths);
g_assert_nonnull (search_paths); g_assert_nonnull (search_paths);
g_assert_cmpuint (g_slist_length (search_paths), ==, 4); g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 4);
g_assert_cmpstr (g_slist_nth_data (search_paths, 0), ==, g_test_get_dir (G_TEST_DIST)); g_assert_cmpstr (search_paths[0], ==, g_test_get_dir (G_TEST_DIST));
g_assert_cmpstr (g_slist_nth_data (search_paths, 1), ==, g_test_get_dir (G_TEST_BUILT)); g_assert_cmpstr (search_paths[1], ==, g_test_get_dir (G_TEST_BUILT));
g_assert_cmpstr (g_slist_nth_data (search_paths, 2), ==, g_get_tmp_dir ()); g_assert_cmpstr (search_paths[2], ==, g_get_tmp_dir ());
#ifndef G_PLATFORM_WIN32 #ifndef G_PLATFORM_WIN32
expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL); expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL);
g_assert_cmpstr (g_slist_nth_data (search_paths, 3), ==, expected_path); g_assert_cmpstr (search_paths[3], ==, expected_path);
g_clear_pointer (&expected_path, g_free); g_clear_pointer (&expected_path, g_free);
#endif #endif
} }

View File

@ -27,7 +27,7 @@ test_repository_basic (void)
{ {
GIRepository *repository; GIRepository *repository;
char *gobject_typelib_dir = NULL; char *gobject_typelib_dir = NULL;
GSList *search_path; const char * const * search_paths;
GITypelib *typelib = NULL; GITypelib *typelib = NULL;
char **namespaces = NULL; char **namespaces = NULL;
const char *expected_namespaces[] = { "GLib", NULL }; const char *expected_namespaces[] = { "GLib", NULL };
@ -55,9 +55,10 @@ test_repository_basic (void)
g_assert_cmpstrv (versions, ((char *[]){"2.0", NULL})); g_assert_cmpstrv (versions, ((char *[]){"2.0", NULL}));
g_clear_pointer (&versions, g_strfreev); g_clear_pointer (&versions, g_strfreev);
search_path = gi_repository_get_search_path (); search_paths = gi_repository_get_search_path (NULL);
g_assert_nonnull (search_path); g_assert_nonnull (search_paths);
g_assert_cmpstr (search_path->data, ==, gobject_typelib_dir); g_assert_cmpuint (g_strv_length ((char **) search_paths), >, 0);
g_assert_cmpstr (search_paths[0], ==, gobject_typelib_dir);
typelib = gi_repository_require (repository, "GLib", "2.0", 0, &local_error); typelib = gi_repository_require (repository, "GLib", "2.0", 0, &local_error);
g_assert_no_error (local_error); g_assert_no_error (local_error);