(linenum→info "unix/slp.c:2238")

glibc/2.7/locale/newlocale.c

    1: /* Return a reference to locale information record.
    2:    Copyright (C) 1996, 1997, 1999, 2000-2002, 2004, 2005, 2006
    3:    Free Software Foundation, Inc.
    4:    This file is part of the GNU C Library.
    5:    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
    6: 
    7:    The GNU C Library is free software; you can redistribute it and/or
    8:    modify it under the terms of the GNU Lesser General Public
    9:    License as published by the Free Software Foundation; either
   10:    version 2.1 of the License, or (at your option) any later version.
   11: 
   12:    The GNU C Library is distributed in the hope that it will be useful,
   13:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   15:    Lesser General Public License for more details.
   16: 
   17:    You should have received a copy of the GNU Lesser General Public
   18:    License along with the GNU C Library; if not, write to the Free
   19:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   20:    02111-1307 USA.  */
   21: 
   22: #include <argz.h>
   23: #include <bits/libc-lock.h>
   24: #include <errno.h>
   25: #include <locale.h>
   26: #include <stdlib.h>
   27: #include <string.h>
   28: 
   29: #include "localeinfo.h"
   30: 
   31: 
   32: /* Lock for protecting global data.  */
   33: __libc_lock_define (extern , __libc_setlocale_lock attribute_hidden)
   34: 
   35: 
   36: /* Use this when we come along an error.  */
   37: #define ERROR_RETURN                                                          \
   38:   do {                                                                        \
   39:     __set_errno (EINVAL);                                                     \
   40:     return NULL;                                                              \
   41:   } while (0)
   42: 
   43: 
   44: __locale_t
   45: __newlocale (int category_mask, const char *locale, __locale_t base)
   46: {
   47:   /* Intermediate memory for result.  */
   48:   const char *newnames[__LC_LAST];
   49:   struct __locale_struct result;
   50:   __locale_t result_ptr;
   51:   char *locale_path;
   52:   size_t locale_path_len;
   53:   const char *locpath_var;
   54:   int cnt;
   55:   size_t names_len;
   56: 
   57:   /* We treat LC_ALL in the same way as if all bits were set.  */
   58:   if (category_mask == 1 << LC_ALL)
   59:     category_mask = (1 << __LC_LAST) - 1 - (1 << LC_ALL);
   60: 
   61:   /* Sanity check for CATEGORY argument.  */
   62:   if ((category_mask & ~((1 << __LC_LAST) - 1 - (1 << LC_ALL))) != 0)
   63:     ERROR_RETURN;
   64: 
   65:   /* `newlocale' does not support asking for the locale name. */
   66:   if (locale == NULL)
   67:     ERROR_RETURN;
   68: 
   69:   if (base == _nl_C_locobj_ptr)
   70:     /* We're to modify BASE, returned for a previous call with "C".
   71:        We can't really modify the read-only structure, so instead
   72:        start over by copying it.  */
   73:     base = NULL;
   74: 
   75:   if ((base == NULL || category_mask == (1 << __LC_LAST) - 1 - (1 << LC_ALL))
   76:       && (category_mask == 0 || !strcmp (locale, "C")))
   77:     /* Asking for the "C" locale needn't allocate a new object.  */
   78:     return _nl_C_locobj_ptr;
   79: 
   80:   /* Allocate memory for the result.  */
   81:   if (base != NULL)
   82:     result = *base;
   83:   else
   84:     /* Fill with pointers to C locale data.  */
   85:     result = _nl_C_locobj;
   86: 
   87:   /* If no category is to be set we return BASE if available or a
   88:      dataset using the C locale data.  */
   89:   if (category_mask == 0)
   90:     {
   91:       result_ptr = (__locale_t) malloc (sizeof (struct __locale_struct));
   92:       if (result_ptr == NULL)
   93:         return NULL;
   94:       *result_ptr = result;
   95: 
   96:       goto update;
   97:     }
   98: 
   99:   /* We perhaps really have to load some data.  So we determine the
  100:      path in which to look for the data now.  The environment variable
  101:      `LOCPATH' must only be used when the binary has no SUID or SGID
  102:      bit set.  If using the default path, we tell _nl_find_locale
  103:      by passing null and it can check the canonical locale archive.  */
  104:   locale_path = NULL;
  105:   locale_path_len = 0;
  106: 
  107:   locpath_var = getenv ("LOCPATH");
  108:   if (locpath_var != NULL && locpath_var[0] != '\0')
  109:     {
  110:       if (__argz_create_sep (locpath_var, ':',
  111:                              &locale_path, &locale_path_len) != 0)
  112:         return NULL;
  113: 
  114:       if (__argz_add_sep (&locale_path, &locale_path_len,
  115:                           _nl_default_locale_path, ':') != 0)
  116:         return NULL;
  117:     }
  118: 
  119:   /* Get the names for the locales we are interested in.  We either
  120:      allow a composite name or a single name.  */
  121:   for (cnt = 0; cnt < __LC_LAST; ++cnt)
  122:     if (cnt != LC_ALL)
  123:       newnames[cnt] = locale;
  124:   if (strchr (locale, ';') != NULL)
  125:     {
  126:       /* This is a composite name.  Make a copy and split it up.  */
  127:       char *np = strdupa (locale);
  128:       char *cp;
  129:       int specified_mask = 0;
  130: 
  131:       while ((cp = strchr (np, '=')) != NULL)
  132:         {
  133:           for (cnt = 0; cnt < __LC_LAST; ++cnt)
  134:             if (cnt != LC_ALL
  135:                 && (size_t) (cp - np) == _nl_category_name_sizes[cnt]
  136:                 && memcmp (np, (_nl_category_names.str
  137:                                 + _nl_category_name_idxs[cnt]), cp - np) == 0)
  138:               break;
  139: 
  140:           if (cnt == __LC_LAST)
  141:             /* Bogus category name.  */
  142:             ERROR_RETURN;
  143: 
  144:           /* Found the category this clause sets.  */
  145:           specified_mask |= 1 << cnt;
  146:           newnames[cnt] = ++cp;
  147:           cp = strchr (cp, ';');
  148:           if (cp != NULL)
  149:             {
  150:               /* Examine the next clause.  */
  151:               *cp = '\0';
  152:               np = cp + 1;
  153:             }
  154:           else
  155:             /* This was the last clause.  We are done.  */
  156:             break;
  157:         }
  158: 
  159:       if (category_mask &~ specified_mask)
  160:         /* The composite name did not specify all categories we need.  */
  161:         ERROR_RETURN;
  162:     }
  163: 
  164:   /* Protect global data.  */
  165:   __libc_lock_lock (__libc_setlocale_lock);
  166: 
  167:   /* Now process all categories we are interested in.  */
  168:   names_len = 0;
  169:   for (cnt = 0; cnt < __LC_LAST; ++cnt)
  170:     {
  171:       if ((category_mask & 1 << cnt) != 0)
  172:         {
  173:           result.__locales[cnt] = _nl_find_locale (locale_path,
  174:                                                    locale_path_len,
  175:                                                    cnt, &newnames[cnt]);
  176:           if (result.__locales[cnt] == NULL)
  177:             {
  178:             free_cnt_data_and_exit:
  179:               while (cnt-- > 0)
  180:                 if (((category_mask & 1 << cnt) != 0)
  181:                     && result.__locales[cnt]->usage_count != UNDELETABLE)
  182:                   /* We can remove the data.  */
  183:                   _nl_remove_locale (cnt, result.__locales[cnt]);
  184: 
  185:               /* Critical section left.  */
  186:               __libc_lock_unlock (__libc_setlocale_lock);
  187:               return NULL;
  188:             }
  189: 
  190:           if (newnames[cnt] != _nl_C_name)
  191:             names_len += strlen (newnames[cnt]) + 1;
  192:         }
  193:       else if (cnt != LC_ALL && result.__names[cnt] != _nl_C_name)
  194:         /* Tally up the unchanged names from BASE as well.  */
  195:         names_len += strlen (result.__names[cnt]) + 1;
  196:     }
  197: 
  198:   /* We successfully loaded all required data.  Allocate a new structure.
  199:      We can't just reuse the BASE pointer, because the name strings are
  200:      changing and we need the old name string area intact so we can copy
  201:      out of it into the new one without overlap problems should some
  202:      category's name be getting longer.  */
  203:   result_ptr = malloc (sizeof (struct __locale_struct) + names_len);
  204:   if (result_ptr == NULL)
  205:     {
  206:       cnt = __LC_LAST;
  207:       goto free_cnt_data_and_exit;
  208:     }
  209: 
  210:   if (base == NULL)
  211:     {
  212:       /* Fill in this new structure from scratch.  */
  213: 
  214:       char *namep = (char *) (result_ptr + 1);
  215: 
  216:       /* Install copied new names in the new structure's __names array.
  217:          If resolved to "C", that is already in RESULT.__names to start.  */
  218:       for (cnt = 0; cnt < __LC_LAST; ++cnt)
  219:         if ((category_mask & 1 << cnt) != 0 && newnames[cnt] != _nl_C_name)
  220:           {
  221:             result.__names[cnt] = namep;
  222:             namep = __stpcpy (namep, newnames[cnt]) + 1;
  223:           }
  224: 
  225:       *result_ptr = result;
  226:     }
  227:   else
  228:     {
  229:       /* We modify the base structure.  */
  230: 
  231:       char *namep = (char *) (result_ptr + 1);
  232: 
  233:       for (cnt = 0; cnt < __LC_LAST; ++cnt)
  234:         if ((category_mask & 1 << cnt) != 0)
  235:           {
  236:             if (base->__locales[cnt]->usage_count != UNDELETABLE)
  237:               /* We can remove the old data.  */
  238:               _nl_remove_locale (cnt, base->__locales[cnt]);
  239:             result_ptr->__locales[cnt] = result.__locales[cnt];
  240: 
  241:             if (newnames[cnt] == _nl_C_name)
  242:               result_ptr->__names[cnt] = _nl_C_name;
  243:             else
  244:               {
  245:                 result_ptr->__names[cnt] = namep;
  246:                 namep = __stpcpy (namep, newnames[cnt]) + 1;
  247:               }
  248:           }
  249:         else if (cnt != LC_ALL)
  250:           {
  251:             /* The RESULT members point into the old BASE structure.  */
  252:             result_ptr->__locales[cnt] = result.__locales[cnt];
  253:             if (result.__names[cnt] == _nl_C_name)
  254:               result_ptr->__names[cnt] = _nl_C_name;
  255:             else
  256:               {
  257:                 result_ptr->__names[cnt] = namep;
  258:                 namep = __stpcpy (namep, result.__names[cnt]) + 1;
  259:               }
  260:           }
  261: 
  262:       free (base);
  263:     }
  264: 
  265:   /* Critical section left.  */
  266:   __libc_lock_unlock (__libc_setlocale_lock);
  267: 
  268:   /* Update the special members.  */
  269:  update:
  270:   {
  271:     union locale_data_value *ctypes = result_ptr->__locales[LC_CTYPE]->values;
  272:     result_ptr->__ctype_b = (const unsigned short int *)
  273:       ctypes[_NL_ITEM_INDEX (_NL_CTYPE_CLASS)].string + 128;
  274:     result_ptr->__ctype_tolower = (const int *)
  275:       ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOLOWER)].string + 128;
  276:     result_ptr->__ctype_toupper = (const int *)
  277:       ctypes[_NL_ITEM_INDEX (_NL_CTYPE_TOUPPER)].string + 128;
  278:   }
  279: 
  280:   return result_ptr;
  281: }
  282: weak_alias (__newlocale, newlocale)
Syntax (Markdown)