xref: /netbsd-src/external/gpl2/gettext/dist/gettext-runtime/intl/finddomain.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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