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