(root)/
glibc-2.38/
intl/
finddomain.c
       1  /* Handle list of needed message catalogs
       2     Copyright (C) 1995-2023 Free Software Foundation, Inc.
       3     Written by Ulrich Drepper <drepper@gnu.org>, 1995.
       4  
       5     This program is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU Lesser General Public License as published by
       7     the Free Software Foundation; either version 2.1 of the License, or
       8     (at your option) any later version.
       9  
      10     This program 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
      13     GNU Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  #ifdef HAVE_CONFIG_H
      19  # include <config.h>
      20  #endif
      21  
      22  #include <stdio.h>
      23  #include <sys/types.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  
      27  #if defined HAVE_UNISTD_H || defined _LIBC
      28  # include <unistd.h>
      29  #endif
      30  
      31  #include "gettextP.h"
      32  #ifdef _LIBC
      33  # include <libintl.h>
      34  #else
      35  # include "libgnuintl.h"
      36  #endif
      37  
      38  /* Handle multi-threaded applications.  */
      39  #ifdef _LIBC
      40  # include <libc-lock.h>
      41  # define gl_rwlock_define_initialized __libc_rwlock_define_initialized
      42  # define gl_rwlock_rdlock __libc_rwlock_rdlock
      43  # define gl_rwlock_wrlock __libc_rwlock_wrlock
      44  # define gl_rwlock_unlock __libc_rwlock_unlock
      45  #else
      46  # include "lock.h"
      47  #endif
      48  
      49  /* @@ end of prolog @@ */
      50  /* List of already loaded domains.  */
      51  static struct loaded_l10nfile *_nl_loaded_domains;
      52  
      53  
      54  /* Return a data structure describing the message catalog described by
      55     the DOMAINNAME and CATEGORY parameters with respect to the currently
      56     established bindings.  */
      57  struct loaded_l10nfile *
      58  _nl_find_domain (const char *dirname, char *locale,
      59  		 const char *domainname, struct binding *domainbinding)
      60  {
      61    struct loaded_l10nfile *retval;
      62    const char *language;
      63    const char *modifier;
      64    const char *territory;
      65    const char *codeset;
      66    const char *normalized_codeset;
      67    const char *alias_value;
      68    int mask;
      69  
      70    /* LOCALE can consist of up to four recognized parts for the XPG syntax:
      71  
      72  		language[_territory][.codeset][@modifier]
      73  
      74       Beside the first part all of them are allowed to be missing.  If
      75       the full specified locale is not found, the less specific one are
      76       looked for.  The various parts will be stripped off according to
      77       the following order:
      78  		(1) codeset
      79  		(2) normalized codeset
      80  		(3) territory
      81  		(4) modifier
      82     */
      83  
      84    /* We need to protect modifying the _NL_LOADED_DOMAINS data.  */
      85    gl_rwlock_define_initialized (static, lock);
      86    gl_rwlock_rdlock (lock);
      87  
      88    /* If we have already tested for this locale entry there has to
      89       be one data set in the list of loaded domains.  */
      90    retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
      91  			       strlen (dirname) + 1, 0, locale, NULL, NULL,
      92  			       NULL, NULL, domainname, 0);
      93  
      94    gl_rwlock_unlock (lock);
      95  
      96    if (retval != NULL)
      97      {
      98        /* We know something about this locale.  */
      99        int cnt;
     100  
     101        if (retval->decided <= 0)
     102  	_nl_load_domain (retval, domainbinding);
     103  
     104        if (retval->data != NULL)
     105  	return retval;
     106  
     107        for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
     108  	{
     109  	  if (retval->successor[cnt]->decided <= 0)
     110  	    _nl_load_domain (retval->successor[cnt], domainbinding);
     111  
     112  	  if (retval->successor[cnt]->data != NULL)
     113  	    break;
     114  	}
     115  
     116        return retval;
     117        /* NOTREACHED */
     118      }
     119  
     120    /* See whether the locale value is an alias.  If yes its value
     121       *overwrites* the alias name.  No test for the original value is
     122       done.  */
     123    alias_value = _nl_expand_alias (locale);
     124    if (alias_value != NULL)
     125      {
     126        size_t len = strlen (alias_value) + 1;
     127        locale = (char *) malloc (len);
     128        if (locale == NULL)
     129  	return NULL;
     130  
     131        memcpy (locale, alias_value, len);
     132      }
     133  
     134    /* Now we determine the single parts of the locale name.  First
     135       look for the language.  Termination symbols are `_', '.', and `@'.  */
     136    mask = _nl_explode_name (locale, &language, &modifier, &territory,
     137  			   &codeset, &normalized_codeset);
     138    if (mask == -1)
     139      /* This means we are out of core.  */
     140      return NULL;
     141  
     142    /* We need to protect modifying the _NL_LOADED_DOMAINS data.  */
     143    gl_rwlock_wrlock (lock);
     144  
     145    /* Create all possible locale entries which might be interested in
     146       generalization.  */
     147    retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
     148  			       strlen (dirname) + 1, mask, language, territory,
     149  			       codeset, normalized_codeset, modifier,
     150  			       domainname, 1);
     151  
     152    gl_rwlock_unlock (lock);
     153  
     154    if (retval == NULL)
     155      /* This means we are out of core.  */
     156      goto out;
     157  
     158    if (retval->decided <= 0)
     159      _nl_load_domain (retval, domainbinding);
     160    if (retval->data == NULL)
     161      {
     162        int cnt;
     163        for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
     164  	{
     165  	  if (retval->successor[cnt]->decided <= 0)
     166  	    _nl_load_domain (retval->successor[cnt], domainbinding);
     167  	  if (retval->successor[cnt]->data != NULL)
     168  	    break;
     169  	}
     170      }
     171  
     172    /* The room for an alias was dynamically allocated.  Free it now.  */
     173    if (alias_value != NULL)
     174      free (locale);
     175  
     176  out:
     177    /* The space for normalized_codeset is dynamically allocated.  Free it.  */
     178    if (mask & XPG_NORM_CODESET)
     179      free ((void *) normalized_codeset);
     180  
     181    return retval;
     182  }
     183  
     184  
     185  #ifdef _LIBC
     186  /* This is called from iconv/gconv_db.c's free_mem, as locales must
     187     be freed before freeing gconv steps arrays.  */
     188  void
     189  _nl_finddomain_subfreeres (void)
     190  {
     191    struct loaded_l10nfile *runp = _nl_loaded_domains;
     192  
     193    while (runp != NULL)
     194      {
     195        struct loaded_l10nfile *here = runp;
     196        if (runp->data != NULL)
     197  	_nl_unload_domain ((struct loaded_domain *) runp->data);
     198        runp = runp->next;
     199        free ((char *) here->filename);
     200        free (here);
     201      }
     202  }
     203  #endif