1  /* Duplicate handle for selection of locales.
       2     Copyright (C) 1997-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <locale.h>
      20  #include <libc-lock.h>
      21  #include <stdlib.h>
      22  #include <string.h>
      23  
      24  #include <localeinfo.h>
      25  
      26  
      27  /* Lock for protecting global data.  */
      28  __libc_rwlock_define (extern , __libc_setlocale_lock attribute_hidden)
      29  
      30  
      31  locale_t
      32  __duplocale (locale_t dataset)
      33  {
      34    /* This static object is returned for newlocale (LC_ALL_MASK, "C").  */
      35    if (dataset == _nl_C_locobj_ptr)
      36      return dataset;
      37  
      38    /* Handle a special value.  */
      39    if (dataset == LC_GLOBAL_LOCALE)
      40      dataset = &_nl_global_locale;
      41  
      42    locale_t result;
      43    int cnt;
      44    size_t names_len = 0;
      45  
      46    /* Calculate the total space we need to store all the names.  */
      47    for (cnt = 0; cnt < __LC_LAST; ++cnt)
      48      if (cnt != LC_ALL && dataset->__names[cnt] != _nl_C_name)
      49        names_len += strlen (dataset->__names[cnt]) + 1;
      50  
      51    /* Get memory.  */
      52    result = malloc (sizeof (struct __locale_struct) + names_len);
      53  
      54    if (result != NULL)
      55      {
      56        char *namep = (char *) (result + 1);
      57  
      58        /* We modify global data (the usage counts).  */
      59        __libc_rwlock_wrlock (__libc_setlocale_lock);
      60  
      61        for (cnt = 0; cnt < __LC_LAST; ++cnt)
      62  	if (cnt != LC_ALL)
      63  	  {
      64  	    result->__locales[cnt] = dataset->__locales[cnt];
      65  	    if (result->__locales[cnt]->usage_count < MAX_USAGE_COUNT)
      66  	      ++result->__locales[cnt]->usage_count;
      67  
      68  	    if (dataset->__names[cnt] == _nl_C_name)
      69  	      result->__names[cnt] = _nl_C_name;
      70  	    else
      71  	      {
      72  		result->__names[cnt] = namep;
      73  		namep = __stpcpy (namep, dataset->__names[cnt]) + 1;
      74  	      }
      75  	  }
      76  
      77        /* Update the special members.  */
      78        result->__ctype_b = dataset->__ctype_b;
      79        result->__ctype_tolower = dataset->__ctype_tolower;
      80        result->__ctype_toupper = dataset->__ctype_toupper;
      81  
      82        /* It's done.  */
      83        __libc_rwlock_unlock (__libc_setlocale_lock);
      84      }
      85  
      86    return result;
      87  }
      88  weak_alias (__duplocale, duplocale)