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