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