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