xref: /netbsd-src/external/gpl2/texinfo/dist/intl/bindtextdom.c (revision 29619d2afe564e54d657b83e5a3ae89584f83720)
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