aboutsummaryrefslogtreecommitdiff
path: root/iconv/gconv_conf.c
diff options
context:
space:
mode:
Diffstat (limited to 'iconv/gconv_conf.c')
-rw-r--r--iconv/gconv_conf.c208
1 files changed, 109 insertions, 99 deletions
diff --git a/iconv/gconv_conf.c b/iconv/gconv_conf.c
index ce9f10f3af..78010491e6 100644
--- a/iconv/gconv_conf.c
+++ b/iconv/gconv_conf.c
@@ -426,119 +426,115 @@ read_conf_file (const char *filename, const char *directory, size_t dir_len,
}
-/* Determine the directories we are looking for data in. */
+/* Determine the directories we are looking for data in. This function should
+ only be called from __gconv_read_conf. */
static void
__gconv_get_path (void)
{
struct path_elem *result;
- __libc_lock_define_initialized (static, lock);
- __libc_lock_lock (lock);
-
- /* Make sure there wasn't a second thread doing it already. */
- result = (struct path_elem *) __gconv_path_elem;
- if (result == NULL)
+ /* This function is only ever called when __gconv_path_elem is NULL. */
+ result = __gconv_path_elem;
+ assert (result == NULL);
+
+ /* Determine the complete path first. */
+ char *gconv_path;
+ size_t gconv_path_len;
+ char *elem;
+ char *oldp;
+ char *cp;
+ int nelems;
+ char *cwd;
+ size_t cwdlen;
+
+ if (__gconv_path_envvar == NULL)
{
- /* Determine the complete path first. */
- char *gconv_path;
- size_t gconv_path_len;
- char *elem;
- char *oldp;
- char *cp;
- int nelems;
- char *cwd;
- size_t cwdlen;
-
- if (__gconv_path_envvar == NULL)
- {
- /* No user-defined path. Make a modifiable copy of the
- default path. */
- gconv_path = strdupa (default_gconv_path);
- gconv_path_len = sizeof (default_gconv_path);
- cwd = NULL;
- cwdlen = 0;
- }
- else
- {
- /* Append the default path to the user-defined path. */
- size_t user_len = strlen (__gconv_path_envvar);
-
- gconv_path_len = user_len + 1 + sizeof (default_gconv_path);
- gconv_path = alloca (gconv_path_len);
- __mempcpy (__mempcpy (__mempcpy (gconv_path, __gconv_path_envvar,
- user_len),
- ":", 1),
- default_gconv_path, sizeof (default_gconv_path));
- cwd = __getcwd (NULL, 0);
- cwdlen = __glibc_unlikely (cwd == NULL) ? 0 : strlen (cwd);
- }
- assert (default_gconv_path[0] == '/');
-
- /* In a first pass we calculate the number of elements. */
- oldp = NULL;
- cp = strchr (gconv_path, ':');
- nelems = 1;
- while (cp != NULL)
- {
- if (cp != oldp + 1)
- ++nelems;
- oldp = cp;
- cp = strchr (cp + 1, ':');
- }
-
- /* Allocate the memory for the result. */
- result = (struct path_elem *) malloc ((nelems + 1)
- * sizeof (struct path_elem)
- + gconv_path_len + nelems
- + (nelems - 1) * (cwdlen + 1));
- if (result != NULL)
- {
- char *strspace = (char *) &result[nelems + 1];
- int n = 0;
-
- /* Separate the individual parts. */
- __gconv_max_path_elem_len = 0;
- elem = __strtok_r (gconv_path, ":", &gconv_path);
- assert (elem != NULL);
- do
- {
- result[n].name = strspace;
- if (elem[0] != '/')
- {
- assert (cwd != NULL);
- strspace = __mempcpy (strspace, cwd, cwdlen);
- *strspace++ = '/';
- }
- strspace = __stpcpy (strspace, elem);
- if (strspace[-1] != '/')
- *strspace++ = '/';
-
- result[n].len = strspace - result[n].name;
- if (result[n].len > __gconv_max_path_elem_len)
- __gconv_max_path_elem_len = result[n].len;
-
- *strspace++ = '\0';
- ++n;
- }
- while ((elem = __strtok_r (NULL, ":", &gconv_path)) != NULL);
-
- result[n].name = NULL;
- result[n].len = 0;
- }
+ /* No user-defined path. Make a modifiable copy of the
+ default path. */
+ gconv_path = strdupa (default_gconv_path);
+ gconv_path_len = sizeof (default_gconv_path);
+ cwd = NULL;
+ cwdlen = 0;
+ }
+ else
+ {
+ /* Append the default path to the user-defined path. */
+ size_t user_len = strlen (__gconv_path_envvar);
+
+ gconv_path_len = user_len + 1 + sizeof (default_gconv_path);
+ gconv_path = alloca (gconv_path_len);
+ __mempcpy (__mempcpy (__mempcpy (gconv_path, __gconv_path_envvar,
+ user_len),
+ ":", 1),
+ default_gconv_path, sizeof (default_gconv_path));
+ cwd = __getcwd (NULL, 0);
+ cwdlen = __glibc_unlikely (cwd == NULL) ? 0 : strlen (cwd);
+ }
+ assert (default_gconv_path[0] == '/');
- __gconv_path_elem = result ?: (struct path_elem *) &empty_path_elem;
+ /* In a first pass we calculate the number of elements. */
+ oldp = NULL;
+ cp = strchr (gconv_path, ':');
+ nelems = 1;
+ while (cp != NULL)
+ {
+ if (cp != oldp + 1)
+ ++nelems;
+ oldp = cp;
+ cp = strchr (cp + 1, ':');
+ }
- free (cwd);
+ /* Allocate the memory for the result. */
+ result = malloc ((nelems + 1)
+ * sizeof (struct path_elem)
+ + gconv_path_len + nelems
+ + (nelems - 1) * (cwdlen + 1));
+ if (result != NULL)
+ {
+ char *strspace = (char *) &result[nelems + 1];
+ int n = 0;
+
+ /* Separate the individual parts. */
+ __gconv_max_path_elem_len = 0;
+ elem = __strtok_r (gconv_path, ":", &gconv_path);
+ assert (elem != NULL);
+ do
+ {
+ result[n].name = strspace;
+ if (elem[0] != '/')
+ {
+ assert (cwd != NULL);
+ strspace = __mempcpy (strspace, cwd, cwdlen);
+ *strspace++ = '/';
+ }
+ strspace = __stpcpy (strspace, elem);
+ if (strspace[-1] != '/')
+ *strspace++ = '/';
+
+ result[n].len = strspace - result[n].name;
+ if (result[n].len > __gconv_max_path_elem_len)
+ __gconv_max_path_elem_len = result[n].len;
+
+ *strspace++ = '\0';
+ ++n;
+ }
+ while ((elem = __strtok_r (NULL, ":", &gconv_path)) != NULL);
+
+ result[n].name = NULL;
+ result[n].len = 0;
}
- __libc_lock_unlock (lock);
+ __gconv_path_elem = result ?: (struct path_elem *) &empty_path_elem;
+
+ free (cwd);
}
/* Read all configuration files found in the user-specified and the default
- path. */
-void
-attribute_hidden
+ path. This function should only be called once during the program's
+ lifetime. It disregards locking and synchronization because its only
+ caller, __gconv_load_conf, handles this. */
+static void
__gconv_read_conf (void)
{
void *modules = NULL;
@@ -609,6 +605,20 @@ __gconv_read_conf (void)
}
+/* This "once" variable is used to do a one-time load of the configuration. */
+__libc_once_define (static, once);
+
+
+/* Read all configuration files found in the user-specified and the default
+ path, but do it only "once" using __gconv_read_conf to do the actual
+ work. This is the function that must be called when reading iconv
+ configuration. */
+void
+__gconv_load_conf (void)
+{
+ __libc_once (once, __gconv_read_conf);
+}
+
/* Free all resources if necessary. */
libc_freeres_fn (free_mem)