]> git.ipfire.org Git - thirdparty/glibc.git/blame - intl/finddomain.c
locale: Handle loading a missing locale twice (Bug 14247)
[thirdparty/glibc.git] / intl / finddomain.c
CommitLineData
8f2ece69 1/* Handle list of needed message catalogs
dff8da6b 2 Copyright (C) 1995-2024 Free Software Foundation, Inc.
f84ad0b1 3 Written by Ulrich Drepper <drepper@gnu.org>, 1995.
92f3773b 4
6d248857
WN
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
0393dfd6 9
6d248857 10 This program is distributed in the hope that it will be useful,
e4cf5070 11 but WITHOUT ANY WARRANTY; without even the implied warranty of
6d248857
WN
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
24906b43 14
6d248857 15 You should have received a copy of the GNU Lesser General Public License
5a82c748 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */
24906b43
RM
17
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
24906b43
RM
22#include <stdio.h>
23#include <sys/types.h>
0555fcce
UD
24#include <stdlib.h>
25#include <string.h>
24906b43
RM
26
27#if defined HAVE_UNISTD_H || defined _LIBC
28# include <unistd.h>
29#endif
30
24906b43
RM
31#include "gettextP.h"
32#ifdef _LIBC
33# include <libintl.h>
34#else
4a4d50f3 35# include "libgnuintl.h"
24906b43
RM
36#endif
37
6d248857
WN
38/* Handle multi-threaded applications. */
39#ifdef _LIBC
ec999b8e 40# include <libc-lock.h>
6d248857
WN
41# define gl_rwlock_define_initialized __libc_rwlock_define_initialized
42# define gl_rwlock_rdlock __libc_rwlock_rdlock
43# define gl_rwlock_wrlock __libc_rwlock_wrlock
44# define gl_rwlock_unlock __libc_rwlock_unlock
45#else
46# include "lock.h"
47#endif
48
24906b43 49/* @@ end of prolog @@ */
24906b43 50/* List of already loaded domains. */
7a12c6bb 51static struct loaded_l10nfile *_nl_loaded_domains;
857fa1b8 52
24906b43
RM
53
54/* Return a data structure describing the message catalog described by
55 the DOMAINNAME and CATEGORY parameters with respect to the currently
56 established bindings. */
7a12c6bb 57struct loaded_l10nfile *
6d248857
WN
58_nl_find_domain (const char *dirname, char *locale,
59 const char *domainname, struct binding *domainbinding)
24906b43 60{
7a12c6bb 61 struct loaded_l10nfile *retval;
24906b43 62 const char *language;
7a12c6bb
RM
63 const char *modifier;
64 const char *territory;
65 const char *codeset;
66 const char *normalized_codeset;
7a12c6bb 67 const char *alias_value;
24906b43
RM
68 int mask;
69
7a12c6bb 70 /* LOCALE can consist of up to four recognized parts for the XPG syntax:
24906b43 71
6d248857 72 language[_territory][.codeset][@modifier]
24906b43 73
f41c8091
UD
74 Beside the first part all of them are allowed to be missing. If
75 the full specified locale is not found, the less specific one are
76 looked for. The various parts will be stripped off according to
24906b43 77 the following order:
e155c801
UD
78 (1) codeset
79 (2) normalized codeset
80 (3) territory
81 (4) modifier
24906b43
RM
82 */
83
f6b90f42 84 /* We need to protect modifying the _NL_LOADED_DOMAINS data. */
6d248857
WN
85 gl_rwlock_define_initialized (static, lock);
86 gl_rwlock_rdlock (lock);
f6b90f42 87
24906b43
RM
88 /* If we have already tested for this locale entry there has to
89 be one data set in the list of loaded domains. */
7a12c6bb
RM
90 retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
91 strlen (dirname) + 1, 0, locale, NULL, NULL,
e155c801 92 NULL, NULL, domainname, 0);
6d248857
WN
93
94 gl_rwlock_unlock (lock);
f6b90f42 95
24906b43
RM
96 if (retval != NULL)
97 {
98 /* We know something about this locale. */
99 int cnt;
100
ce7265c7 101 if (retval->decided <= 0)
c44a663d 102 _nl_load_domain (retval, domainbinding);
24906b43
RM
103
104 if (retval->data != NULL)
105 return retval;
106
75914335 107 for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
24906b43 108 {
ce7265c7 109 if (retval->successor[cnt]->decided <= 0)
c44a663d 110 _nl_load_domain (retval->successor[cnt], domainbinding);
24906b43
RM
111
112 if (retval->successor[cnt]->data != NULL)
113 break;
114 }
f6b90f42 115
0292b0dd 116 return retval;
24906b43
RM
117 /* NOTREACHED */
118 }
119
120 /* See whether the locale value is an alias. If yes its value
121 *overwrites* the alias name. No test for the original value is
122 done. */
123 alias_value = _nl_expand_alias (locale);
124 if (alias_value != NULL)
6d248857 125 {
6d248857
WN
126 size_t len = strlen (alias_value) + 1;
127 locale = (char *) malloc (len);
128 if (locale == NULL)
129 return NULL;
130
131 memcpy (locale, alias_value, len);
6d248857 132 }
24906b43
RM
133
134 /* Now we determine the single parts of the locale name. First
6d248857 135 look for the language. Termination symbols are `_', '.', and `@'. */
7a12c6bb 136 mask = _nl_explode_name (locale, &language, &modifier, &territory,
e155c801 137 &codeset, &normalized_codeset);
1c298d08
UD
138 if (mask == -1)
139 /* This means we are out of core. */
140 return NULL;
24906b43 141
f6b90f42 142 /* We need to protect modifying the _NL_LOADED_DOMAINS data. */
6d248857 143 gl_rwlock_wrlock (lock);
f6b90f42 144
24906b43 145 /* Create all possible locale entries which might be interested in
6d52618b 146 generalization. */
7a12c6bb
RM
147 retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
148 strlen (dirname) + 1, mask, language, territory,
e155c801
UD
149 codeset, normalized_codeset, modifier,
150 domainname, 1);
6d248857
WN
151
152 gl_rwlock_unlock (lock);
f6b90f42 153
24906b43
RM
154 if (retval == NULL)
155 /* This means we are out of core. */
ce31a3b1 156 goto out;
24906b43 157
ce7265c7 158 if (retval->decided <= 0)
c44a663d 159 _nl_load_domain (retval, domainbinding);
24906b43
RM
160 if (retval->data == NULL)
161 {
162 int cnt;
163 for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
164 {
ce7265c7 165 if (retval->successor[cnt]->decided <= 0)
c44a663d 166 _nl_load_domain (retval->successor[cnt], domainbinding);
24906b43
RM
167 if (retval->successor[cnt]->data != NULL)
168 break;
24906b43 169 }
24906b43
RM
170 }
171
6d248857
WN
172 /* The room for an alias was dynamically allocated. Free it now. */
173 if (alias_value != NULL)
174 free (locale);
175
ce31a3b1 176out:
a1648746
UD
177 /* The space for normalized_codeset is dynamically allocated. Free it. */
178 if (mask & XPG_NORM_CODESET)
a7123f0e 179 free ((void *) normalized_codeset);
a1648746 180
24906b43
RM
181 return retval;
182}
a5a0310d
UD
183
184
185#ifdef _LIBC
9e365fe7
UD
186/* This is called from iconv/gconv_db.c's free_mem, as locales must
187 be freed before freeing gconv steps arrays. */
88677348 188void
60d2f8f3 189_nl_finddomain_subfreeres (void)
a5a0310d
UD
190{
191 struct loaded_l10nfile *runp = _nl_loaded_domains;
192
193 while (runp != NULL)
194 {
195 struct loaded_l10nfile *here = runp;
196 if (runp->data != NULL)
197 _nl_unload_domain ((struct loaded_domain *) runp->data);
198 runp = runp->next;
f84ad0b1 199 free ((char *) here->filename);
a5a0310d
UD
200 free (here);
201 }
202}
a5a0310d 203#endif