Back to index

glibc  2.9
newlocale.c
Go to the documentation of this file.
00001 /* Return a reference to locale information record.
00002    Copyright (C) 1996, 1997, 1999, 2000-2002, 2004, 2005, 2006, 2008
00003    Free Software Foundation, Inc.
00004    This file is part of the GNU C Library.
00005    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
00006 
00007    The GNU C Library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Lesser General Public
00009    License as published by the Free Software Foundation; either
00010    version 2.1 of the License, or (at your option) any later version.
00011 
00012    The GNU C Library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Lesser General Public License for more details.
00016 
00017    You should have received a copy of the GNU Lesser General Public
00018    License along with the GNU C Library; if not, write to the Free
00019    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00020    02111-1307 USA.  */
00021 
00022 #include <argz.h>
00023 #include <bits/libc-lock.h>
00024 #include <errno.h>
00025 #include <locale.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 
00029 #include "localeinfo.h"
00030 
00031 
00032 /* Lock for protecting global data.  */
00033 __libc_rwlock_define (extern , __libc_setlocale_lock attribute_hidden)
00034 
00035 
00036 /* Use this when we come along an error.  */
00037 #define ERROR_RETURN                                                 \
00038   do {                                                               \
00039     __set_errno (EINVAL);                                            \
00040     return NULL;                                                     \
00041   } while (0)
00042 
00043 
00044 __locale_t
00045 __newlocale (int category_mask, const char *locale, __locale_t base)
00046 {
00047   /* Intermediate memory for result.  */
00048   const char *newnames[__LC_LAST];
00049   struct __locale_struct result;
00050   __locale_t result_ptr;
00051   char *locale_path;
00052   size_t locale_path_len;
00053   const char *locpath_var;
00054   int cnt;
00055   size_t names_len;
00056 
00057   /* We treat LC_ALL in the same way as if all bits were set.  */
00058   if (category_mask == 1 << LC_ALL)
00059     category_mask = (1 << __LC_LAST) - 1 - (1 << LC_ALL);
00060 
00061   /* Sanity check for CATEGORY argument.  */
00062   if ((category_mask & ~((1 << __LC_LAST) - 1 - (1 << LC_ALL))) != 0)
00063     ERROR_RETURN;
00064 
00065   /* `newlocale' does not support asking for the locale name. */
00066   if (locale == NULL)
00067     ERROR_RETURN;
00068 
00069   if (base == _nl_C_locobj_ptr)
00070     /* We're to modify BASE, returned for a previous call with "C".
00071        We can't really modify the read-only structure, so instead
00072        start over by copying it.  */
00073     base = NULL;
00074 
00075   if ((base == NULL || category_mask == (1 << __LC_LAST) - 1 - (1 << LC_ALL))
00076       && (category_mask == 0 || !strcmp (locale, "C")))
00077     /* Asking for the "C" locale needn't allocate a new object.  */
00078     return _nl_C_locobj_ptr;
00079 
00080   /* Allocate memory for the result.  */
00081   if (base != NULL)
00082     result = *base;
00083   else
00084     /* Fill with pointers to C locale data.  */
00085     result = _nl_C_locobj;
00086 
00087   /* If no category is to be set we return BASE if available or a
00088      dataset using the C locale data.  */
00089   if (category_mask == 0)
00090     {
00091       result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
00092       if (result_ptr == NULL)
00093        return NULL;
00094       *result_ptr = result;
00095 
00096       goto update;
00097     }
00098 
00099   /* We perhaps really have to load some data.  So we determine the
00100      path in which to look for the data now.  The environment variable
00101      `LOCPATH' must only be used when the binary has no SUID or SGID
00102      bit set.  If using the default path, we tell _nl_find_locale
00103      by passing null and it can check the canonical locale archive.  */
00104   locale_path = NULL;
00105   locale_path_len = 0;
00106 
00107   locpath_var = getenv ("LOCPATH");
00108   if (locpath_var != NULL && locpath_var[0] != '\0')
00109     {
00110       if (__argz_create_sep (locpath_var, ':',
00111                           &locale_path, &locale_path_len) != 0)
00112        return NULL;
00113 
00114       if (__argz_add_sep (&locale_path, &locale_path_len,
00115                        _nl_default_locale_path, ':') != 0)
00116        return NULL;
00117     }
00118 
00119   /* Get the names for the locales we are interested in.  We either
00120      allow a composite name or a single name.  */
00121   for (cnt = 0; cnt < __LC_LAST; ++cnt)
00122     if (cnt != LC_ALL)
00123       newnames[cnt] = locale;
00124   if (strchr (locale, ';') != NULL)
00125     {
00126       /* This is a composite name.  Make a copy and split it up.  */
00127       char *np = strdupa (locale);
00128       char *cp;
00129       int specified_mask = 0;
00130 
00131       while ((cp = strchr (np, '=')) != NULL)
00132        {
00133          for (cnt = 0; cnt < __LC_LAST; ++cnt)
00134            if (cnt != LC_ALL
00135               && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
00136               && memcmp (np, (_nl_category_names.str
00137                             + _nl_category_name_idxs[cnt]), cp - np) == 0)
00138              break;
00139 
00140          if (cnt == __LC_LAST)
00141            /* Bogus category name.  */
00142            ERROR_RETURN;
00143 
00144          /* Found the category this clause sets.  */
00145          specified_mask |= 1 << cnt;
00146          newnames[cnt] = ++cp;
00147          cp = strchr (cp, ';');
00148          if (cp != NULL)
00149            {
00150              /* Examine the next clause.  */
00151              *cp = '\0';
00152              np = cp + 1;
00153            }
00154          else
00155            /* This was the last clause.  We are done.  */
00156            break;
00157        }
00158 
00159       if (category_mask &~ specified_mask)
00160        /* The composite name did not specify all categories we need.  */
00161        ERROR_RETURN;
00162     }
00163 
00164   /* Protect global data.  */
00165   __libc_rwlock_wrlock (__libc_setlocale_lock);
00166 
00167   /* Now process all categories we are interested in.  */
00168   names_len = 0;
00169   for (cnt = 0; cnt < __LC_LAST; ++cnt)
00170     {
00171       if ((category_mask & 1 << cnt) != 0)
00172        {
00173          result.__locales[cnt] = _nl_find_locale (locale_path,
00174                                              locale_path_len,
00175                                              cnt, &newnames[cnt]);
00176          if (result.__locales[cnt] == NULL)
00177            {
00178            free_cnt_data_and_exit:
00179              while (cnt-- > 0)
00180               if (((category_mask & 1 << cnt) != 0)
00181                   && result.__locales[cnt]->usage_count != UNDELETABLE)
00182                 /* We can remove the data.  */
00183                 _nl_remove_locale (cnt, result.__locales[cnt]);
00184 
00185               /* Critical section left.  */
00186               __libc_rwlock_unlock (__libc_setlocale_lock);
00187              return NULL;
00188            }
00189 
00190          if (newnames[cnt] != _nl_C_name)
00191            names_len += strlen (newnames[cnt]) + 1;
00192        }
00193       else if (cnt != LC_ALL && result.__names[cnt] != _nl_C_name)
00194        /* Tally up the unchanged names from BASE as well.  */
00195        names_len += strlen (result.__names[cnt]) + 1;
00196     }
00197 
00198   /* We successfully loaded all required data.  Allocate a new structure.
00199      We can't just reuse the BASE pointer, because the name strings are
00200      changing and we need the old name string area intact so we can copy
00201      out of it into the new one without overlap problems should some
00202      category's name be getting longer.  */
00203   result_ptr = malloc (sizeof (struct __locale_struct) + names_len);
00204   if (result_ptr == NULL)
00205     {
00206       cnt = __LC_LAST;
00207       goto free_cnt_data_and_exit;
00208     }
00209 
00210   if (base == NULL)
00211     {
00212       /* Fill in this new structure from scratch.  */
00213 
00214       char *namep = (char *) (result_ptr + 1);
00215 
00216       /* Install copied new names in the new structure's __names array.
00217         If resolved to "C", that is already in RESULT.__names to start.  */
00218       for (cnt = 0; cnt < __LC_LAST; ++cnt)
00219        if ((category_mask & 1 << cnt) != 0 && newnames[cnt] != _nl_C_name)
00220          {
00221            result.__names[cnt] = namep;
00222            namep = __stpcpy (namep, newnames[cnt]) + 1;
00223          }
00224 
00225       *result_ptr = result;
00226     }
00227   else
00228     {
00229       /* We modify the base structure.  */
00230 
00231       char *namep = (char *) (result_ptr + 1);
00232 
00233       for (cnt = 0; cnt < __LC_LAST; ++cnt)
00234        if ((category_mask & 1 << cnt) != 0)
00235          {
00236            if (base->__locales[cnt]->usage_count != UNDELETABLE)
00237              /* We can remove the old data.  */
00238              _nl_remove_locale (cnt, base->__locales[cnt]);
00239            result_ptr->__locales[cnt] = result.__locales[cnt];
00240 
00241            if (newnames[cnt] == _nl_C_name)
00242              result_ptr->__names[cnt] = _nl_C_name;
00243            else
00244              {
00245               result_ptr->__names[cnt] = namep;
00246               namep = __stpcpy (namep, newnames[cnt]) + 1;
00247              }
00248          }
00249        else if (cnt != LC_ALL)
00250          {
00251            /* The RESULT members point into the old BASE structure.  */
00252            result_ptr->__locales[cnt] = result.__locales[cnt];
00253            if (result.__names[cnt] == _nl_C_name)
00254              result_ptr->__names[cnt] = _nl_C_name;
00255            else
00256              {
00257               result_ptr->__names[cnt] = namep;
00258               namep = __stpcpy (namep, result.__names[cnt]) + 1;
00259              }
00260          }
00261 
00262       free (base);
00263     }
00264 
00265   /* Critical section left.  */
00266   __libc_rwlock_unlock (__libc_setlocale_lock);
00267 
00268   /* Update the special members.  */
00269  update:
00270   {
00271     union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values;
00272     result_ptr->__ctype_b = (const unsigned short int *)
00273       ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)].string + 128;
00274     result_ptr->__ctype_tolower = (const int *)
00275       ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER)].string + 128;
00276     result_ptr->__ctype_toupper = (const int *)
00277       ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER)].string + 128;
00278   }
00279 
00280   return result_ptr;
00281 }
00282 weak_alias (__newlocale, newlocale)