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