1*bb16d227Schristos /* Implementation of the bindtextdomain(3) function
2*bb16d227Schristos Copyright (C) 1995-1998, 2000, 2001, 2002 Free Software Foundation, Inc.
3*bb16d227Schristos
4*bb16d227Schristos This program is free software; you can redistribute it and/or modify it
5*bb16d227Schristos under the terms of the GNU Library General Public License as published
6*bb16d227Schristos by the Free Software Foundation; either version 2, or (at your option)
7*bb16d227Schristos any later version.
8*bb16d227Schristos
9*bb16d227Schristos This program is distributed in the hope that it will be useful,
10*bb16d227Schristos but WITHOUT ANY WARRANTY; without even the implied warranty of
11*bb16d227Schristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12*bb16d227Schristos Library General Public License for more details.
13*bb16d227Schristos
14*bb16d227Schristos You should have received a copy of the GNU Library General Public
15*bb16d227Schristos License along with this program; if not, write to the Free Software
16*bb16d227Schristos Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
17*bb16d227Schristos USA. */
18*bb16d227Schristos
19*bb16d227Schristos #ifdef HAVE_CONFIG_H
20*bb16d227Schristos # include <config.h>
21*bb16d227Schristos #endif
22*bb16d227Schristos
23*bb16d227Schristos #include <stddef.h>
24*bb16d227Schristos #include <stdlib.h>
25*bb16d227Schristos #include <string.h>
26*bb16d227Schristos
27*bb16d227Schristos #ifdef _LIBC
28*bb16d227Schristos # include <libintl.h>
29*bb16d227Schristos #else
30*bb16d227Schristos # include "libgnuintl.h"
31*bb16d227Schristos #endif
32*bb16d227Schristos #include "gettextP.h"
33*bb16d227Schristos
34*bb16d227Schristos #ifdef _LIBC
35*bb16d227Schristos /* We have to handle multi-threaded applications. */
36*bb16d227Schristos # include <bits/libc-lock.h>
37*bb16d227Schristos #else
38*bb16d227Schristos /* Provide dummy implementation if this is outside glibc. */
39*bb16d227Schristos # define __libc_rwlock_define(CLASS, NAME)
40*bb16d227Schristos # define __libc_rwlock_wrlock(NAME)
41*bb16d227Schristos # define __libc_rwlock_unlock(NAME)
42*bb16d227Schristos #endif
43*bb16d227Schristos
44*bb16d227Schristos /* The internal variables in the standalone libintl.a must have different
45*bb16d227Schristos names than the internal variables in GNU libc, otherwise programs
46*bb16d227Schristos using libintl.a cannot be linked statically. */
47*bb16d227Schristos #if !defined _LIBC
48*bb16d227Schristos # define _nl_default_dirname libintl_nl_default_dirname
49*bb16d227Schristos # define _nl_domain_bindings libintl_nl_domain_bindings
50*bb16d227Schristos #endif
51*bb16d227Schristos
52*bb16d227Schristos /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>. */
53*bb16d227Schristos #ifndef offsetof
54*bb16d227Schristos # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
55*bb16d227Schristos #endif
56*bb16d227Schristos
57*bb16d227Schristos /* @@ end of prolog @@ */
58*bb16d227Schristos
59*bb16d227Schristos /* Contains the default location of the message catalogs. */
60*bb16d227Schristos extern const char _nl_default_dirname[];
61*bb16d227Schristos #ifdef _LIBC
62*bb16d227Schristos extern const char _nl_default_dirname_internal[] attribute_hidden;
63*bb16d227Schristos #else
64*bb16d227Schristos # define INTUSE(name) name
65*bb16d227Schristos #endif
66*bb16d227Schristos
67*bb16d227Schristos /* List with bindings of specific domains. */
68*bb16d227Schristos extern struct binding *_nl_domain_bindings;
69*bb16d227Schristos
70*bb16d227Schristos /* Lock variable to protect the global data in the gettext implementation. */
71*bb16d227Schristos __libc_rwlock_define (extern, _nl_state_lock attribute_hidden)
72*bb16d227Schristos
73*bb16d227Schristos
74*bb16d227Schristos /* Names for the libintl functions are a problem. They must not clash
75*bb16d227Schristos with existing names and they should follow ANSI C. But this source
76*bb16d227Schristos code is also used in GNU C Library where the names have a __
77*bb16d227Schristos prefix. So we have to make a difference here. */
78*bb16d227Schristos #ifdef _LIBC
79*bb16d227Schristos # define BINDTEXTDOMAIN __bindtextdomain
80*bb16d227Schristos # define BIND_TEXTDOMAIN_CODESET __bind_textdomain_codeset
81*bb16d227Schristos # ifndef strdup
82*bb16d227Schristos # define strdup(str) __strdup (str)
83*bb16d227Schristos # endif
84*bb16d227Schristos #else
85*bb16d227Schristos # define BINDTEXTDOMAIN libintl_bindtextdomain
86*bb16d227Schristos # define BIND_TEXTDOMAIN_CODESET libintl_bind_textdomain_codeset
87*bb16d227Schristos #endif
88*bb16d227Schristos
89*bb16d227Schristos /* Prototypes for local functions. */
90*bb16d227Schristos static void set_binding_values PARAMS ((const char *domainname,
91*bb16d227Schristos const char **dirnamep,
92*bb16d227Schristos const char **codesetp));
93*bb16d227Schristos
94*bb16d227Schristos /* Specifies the directory name *DIRNAMEP and the output codeset *CODESETP
95*bb16d227Schristos to be used for the DOMAINNAME message catalog.
96*bb16d227Schristos If *DIRNAMEP or *CODESETP is NULL, the corresponding attribute is not
97*bb16d227Schristos modified, only the current value is returned.
98*bb16d227Schristos If DIRNAMEP or CODESETP is NULL, the corresponding attribute is neither
99*bb16d227Schristos modified nor returned. */
100*bb16d227Schristos static void
set_binding_values(domainname,dirnamep,codesetp)101*bb16d227Schristos set_binding_values (domainname, dirnamep, codesetp)
102*bb16d227Schristos const char *domainname;
103*bb16d227Schristos const char **dirnamep;
104*bb16d227Schristos const char **codesetp;
105*bb16d227Schristos {
106*bb16d227Schristos struct binding *binding;
107*bb16d227Schristos int modified;
108*bb16d227Schristos
109*bb16d227Schristos /* Some sanity checks. */
110*bb16d227Schristos if (domainname == NULL || domainname[0] == '\0')
111*bb16d227Schristos {
112*bb16d227Schristos if (dirnamep)
113*bb16d227Schristos *dirnamep = NULL;
114*bb16d227Schristos if (codesetp)
115*bb16d227Schristos *codesetp = NULL;
116*bb16d227Schristos return;
117*bb16d227Schristos }
118*bb16d227Schristos
119*bb16d227Schristos __libc_rwlock_wrlock (_nl_state_lock);
120*bb16d227Schristos
121*bb16d227Schristos modified = 0;
122*bb16d227Schristos
123*bb16d227Schristos for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
124*bb16d227Schristos {
125*bb16d227Schristos int compare = strcmp (domainname, binding->domainname);
126*bb16d227Schristos if (compare == 0)
127*bb16d227Schristos /* We found it! */
128*bb16d227Schristos break;
129*bb16d227Schristos if (compare < 0)
130*bb16d227Schristos {
131*bb16d227Schristos /* It is not in the list. */
132*bb16d227Schristos binding = NULL;
133*bb16d227Schristos break;
134*bb16d227Schristos }
135*bb16d227Schristos }
136*bb16d227Schristos
137*bb16d227Schristos if (binding != NULL)
138*bb16d227Schristos {
139*bb16d227Schristos if (dirnamep)
140*bb16d227Schristos {
141*bb16d227Schristos const char *dirname = *dirnamep;
142*bb16d227Schristos
143*bb16d227Schristos if (dirname == NULL)
144*bb16d227Schristos /* The current binding has be to returned. */
145*bb16d227Schristos *dirnamep = binding->dirname;
146*bb16d227Schristos else
147*bb16d227Schristos {
148*bb16d227Schristos /* The domain is already bound. If the new value and the old
149*bb16d227Schristos one are equal we simply do nothing. Otherwise replace the
150*bb16d227Schristos old binding. */
151*bb16d227Schristos char *result = binding->dirname;
152*bb16d227Schristos if (strcmp (dirname, result) != 0)
153*bb16d227Schristos {
154*bb16d227Schristos if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
155*bb16d227Schristos result = (char *) INTUSE(_nl_default_dirname);
156*bb16d227Schristos else
157*bb16d227Schristos {
158*bb16d227Schristos #if defined _LIBC || defined HAVE_STRDUP
159*bb16d227Schristos result = strdup (dirname);
160*bb16d227Schristos #else
161*bb16d227Schristos size_t len = strlen (dirname) + 1;
162*bb16d227Schristos result = (char *) malloc (len);
163*bb16d227Schristos if (__builtin_expect (result != NULL, 1))
164*bb16d227Schristos memcpy (result, dirname, len);
165*bb16d227Schristos #endif
166*bb16d227Schristos }
167*bb16d227Schristos
168*bb16d227Schristos if (__builtin_expect (result != NULL, 1))
169*bb16d227Schristos {
170*bb16d227Schristos if (binding->dirname != INTUSE(_nl_default_dirname))
171*bb16d227Schristos free (binding->dirname);
172*bb16d227Schristos
173*bb16d227Schristos binding->dirname = result;
174*bb16d227Schristos modified = 1;
175*bb16d227Schristos }
176*bb16d227Schristos }
177*bb16d227Schristos *dirnamep = result;
178*bb16d227Schristos }
179*bb16d227Schristos }
180*bb16d227Schristos
181*bb16d227Schristos if (codesetp)
182*bb16d227Schristos {
183*bb16d227Schristos const char *codeset = *codesetp;
184*bb16d227Schristos
185*bb16d227Schristos if (codeset == NULL)
186*bb16d227Schristos /* The current binding has be to returned. */
187*bb16d227Schristos *codesetp = binding->codeset;
188*bb16d227Schristos else
189*bb16d227Schristos {
190*bb16d227Schristos /* The domain is already bound. If the new value and the old
191*bb16d227Schristos one are equal we simply do nothing. Otherwise replace the
192*bb16d227Schristos old binding. */
193*bb16d227Schristos char *result = binding->codeset;
194*bb16d227Schristos if (result == NULL || strcmp (codeset, result) != 0)
195*bb16d227Schristos {
196*bb16d227Schristos #if defined _LIBC || defined HAVE_STRDUP
197*bb16d227Schristos result = strdup (codeset);
198*bb16d227Schristos #else
199*bb16d227Schristos size_t len = strlen (codeset) + 1;
200*bb16d227Schristos result = (char *) malloc (len);
201*bb16d227Schristos if (__builtin_expect (result != NULL, 1))
202*bb16d227Schristos memcpy (result, codeset, len);
203*bb16d227Schristos #endif
204*bb16d227Schristos
205*bb16d227Schristos if (__builtin_expect (result != NULL, 1))
206*bb16d227Schristos {
207*bb16d227Schristos if (binding->codeset != NULL)
208*bb16d227Schristos free (binding->codeset);
209*bb16d227Schristos
210*bb16d227Schristos binding->codeset = result;
211*bb16d227Schristos binding->codeset_cntr++;
212*bb16d227Schristos modified = 1;
213*bb16d227Schristos }
214*bb16d227Schristos }
215*bb16d227Schristos *codesetp = result;
216*bb16d227Schristos }
217*bb16d227Schristos }
218*bb16d227Schristos }
219*bb16d227Schristos else if ((dirnamep == NULL || *dirnamep == NULL)
220*bb16d227Schristos && (codesetp == NULL || *codesetp == NULL))
221*bb16d227Schristos {
222*bb16d227Schristos /* Simply return the default values. */
223*bb16d227Schristos if (dirnamep)
224*bb16d227Schristos *dirnamep = INTUSE(_nl_default_dirname);
225*bb16d227Schristos if (codesetp)
226*bb16d227Schristos *codesetp = NULL;
227*bb16d227Schristos }
228*bb16d227Schristos else
229*bb16d227Schristos {
230*bb16d227Schristos /* We have to create a new binding. */
231*bb16d227Schristos size_t len = strlen (domainname) + 1;
232*bb16d227Schristos struct binding *new_binding =
233*bb16d227Schristos (struct binding *) malloc (offsetof (struct binding, domainname) + len);
234*bb16d227Schristos
235*bb16d227Schristos if (__builtin_expect (new_binding == NULL, 0))
236*bb16d227Schristos goto failed;
237*bb16d227Schristos
238*bb16d227Schristos memcpy (new_binding->domainname, domainname, len);
239*bb16d227Schristos
240*bb16d227Schristos if (dirnamep)
241*bb16d227Schristos {
242*bb16d227Schristos const char *dirname = *dirnamep;
243*bb16d227Schristos
244*bb16d227Schristos if (dirname == NULL)
245*bb16d227Schristos /* The default value. */
246*bb16d227Schristos dirname = INTUSE(_nl_default_dirname);
247*bb16d227Schristos else
248*bb16d227Schristos {
249*bb16d227Schristos if (strcmp (dirname, INTUSE(_nl_default_dirname)) == 0)
250*bb16d227Schristos dirname = INTUSE(_nl_default_dirname);
251*bb16d227Schristos else
252*bb16d227Schristos {
253*bb16d227Schristos char *result;
254*bb16d227Schristos #if defined _LIBC || defined HAVE_STRDUP
255*bb16d227Schristos result = strdup (dirname);
256*bb16d227Schristos if (__builtin_expect (result == NULL, 0))
257*bb16d227Schristos goto failed_dirname;
258*bb16d227Schristos #else
259*bb16d227Schristos size_t len = strlen (dirname) + 1;
260*bb16d227Schristos result = (char *) malloc (len);
261*bb16d227Schristos if (__builtin_expect (result == NULL, 0))
262*bb16d227Schristos goto failed_dirname;
263*bb16d227Schristos memcpy (result, dirname, len);
264*bb16d227Schristos #endif
265*bb16d227Schristos dirname = result;
266*bb16d227Schristos }
267*bb16d227Schristos }
268*bb16d227Schristos *dirnamep = dirname;
269*bb16d227Schristos new_binding->dirname = (char *) dirname;
270*bb16d227Schristos }
271*bb16d227Schristos else
272*bb16d227Schristos /* The default value. */
273*bb16d227Schristos new_binding->dirname = (char *) INTUSE(_nl_default_dirname);
274*bb16d227Schristos
275*bb16d227Schristos new_binding->codeset_cntr = 0;
276*bb16d227Schristos
277*bb16d227Schristos if (codesetp)
278*bb16d227Schristos {
279*bb16d227Schristos const char *codeset = *codesetp;
280*bb16d227Schristos
281*bb16d227Schristos if (codeset != NULL)
282*bb16d227Schristos {
283*bb16d227Schristos char *result;
284*bb16d227Schristos
285*bb16d227Schristos #if defined _LIBC || defined HAVE_STRDUP
286*bb16d227Schristos result = strdup (codeset);
287*bb16d227Schristos if (__builtin_expect (result == NULL, 0))
288*bb16d227Schristos goto failed_codeset;
289*bb16d227Schristos #else
290*bb16d227Schristos size_t len = strlen (codeset) + 1;
291*bb16d227Schristos result = (char *) malloc (len);
292*bb16d227Schristos if (__builtin_expect (result == NULL, 0))
293*bb16d227Schristos goto failed_codeset;
294*bb16d227Schristos memcpy (result, codeset, len);
295*bb16d227Schristos #endif
296*bb16d227Schristos codeset = result;
297*bb16d227Schristos new_binding->codeset_cntr++;
298*bb16d227Schristos }
299*bb16d227Schristos *codesetp = codeset;
300*bb16d227Schristos new_binding->codeset = (char *) codeset;
301*bb16d227Schristos }
302*bb16d227Schristos else
303*bb16d227Schristos new_binding->codeset = NULL;
304*bb16d227Schristos
305*bb16d227Schristos /* Now enqueue it. */
306*bb16d227Schristos if (_nl_domain_bindings == NULL
307*bb16d227Schristos || strcmp (domainname, _nl_domain_bindings->domainname) < 0)
308*bb16d227Schristos {
309*bb16d227Schristos new_binding->next = _nl_domain_bindings;
310*bb16d227Schristos _nl_domain_bindings = new_binding;
311*bb16d227Schristos }
312*bb16d227Schristos else
313*bb16d227Schristos {
314*bb16d227Schristos binding = _nl_domain_bindings;
315*bb16d227Schristos while (binding->next != NULL
316*bb16d227Schristos && strcmp (domainname, binding->next->domainname) > 0)
317*bb16d227Schristos binding = binding->next;
318*bb16d227Schristos
319*bb16d227Schristos new_binding->next = binding->next;
320*bb16d227Schristos binding->next = new_binding;
321*bb16d227Schristos }
322*bb16d227Schristos
323*bb16d227Schristos modified = 1;
324*bb16d227Schristos
325*bb16d227Schristos /* Here we deal with memory allocation failures. */
326*bb16d227Schristos if (0)
327*bb16d227Schristos {
328*bb16d227Schristos failed_codeset:
329*bb16d227Schristos if (new_binding->dirname != INTUSE(_nl_default_dirname))
330*bb16d227Schristos free (new_binding->dirname);
331*bb16d227Schristos failed_dirname:
332*bb16d227Schristos free (new_binding);
333*bb16d227Schristos failed:
334*bb16d227Schristos if (dirnamep)
335*bb16d227Schristos *dirnamep = NULL;
336*bb16d227Schristos if (codesetp)
337*bb16d227Schristos *codesetp = NULL;
338*bb16d227Schristos }
339*bb16d227Schristos }
340*bb16d227Schristos
341*bb16d227Schristos /* If we modified any binding, we flush the caches. */
342*bb16d227Schristos if (modified)
343*bb16d227Schristos ++_nl_msg_cat_cntr;
344*bb16d227Schristos
345*bb16d227Schristos __libc_rwlock_unlock (_nl_state_lock);
346*bb16d227Schristos }
347*bb16d227Schristos
348*bb16d227Schristos /* Specify that the DOMAINNAME message catalog will be found
349*bb16d227Schristos in DIRNAME rather than in the system locale data base. */
350*bb16d227Schristos char *
BINDTEXTDOMAIN(domainname,dirname)351*bb16d227Schristos BINDTEXTDOMAIN (domainname, dirname)
352*bb16d227Schristos const char *domainname;
353*bb16d227Schristos const char *dirname;
354*bb16d227Schristos {
355*bb16d227Schristos set_binding_values (domainname, &dirname, NULL);
356*bb16d227Schristos return (char *) dirname;
357*bb16d227Schristos }
358*bb16d227Schristos
359*bb16d227Schristos /* Specify the character encoding in which the messages from the
360*bb16d227Schristos DOMAINNAME message catalog will be returned. */
361*bb16d227Schristos char *
BIND_TEXTDOMAIN_CODESET(domainname,codeset)362*bb16d227Schristos BIND_TEXTDOMAIN_CODESET (domainname, codeset)
363*bb16d227Schristos const char *domainname;
364*bb16d227Schristos const char *codeset;
365*bb16d227Schristos {
366*bb16d227Schristos set_binding_values (domainname, NULL, &codeset);
367*bb16d227Schristos return (char *) codeset;
368*bb16d227Schristos }
369*bb16d227Schristos
370*bb16d227Schristos #ifdef _LIBC
371*bb16d227Schristos /* Aliases for function names in GNU C Library. */
372*bb16d227Schristos weak_alias (__bindtextdomain, bindtextdomain);
373*bb16d227Schristos weak_alias (__bind_textdomain_codeset, bind_textdomain_codeset);
374*bb16d227Schristos #endif
375