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