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