Blame intl/finddomain.c

Packit 6c4009
/* Handle list of needed message catalogs
Packit 6c4009
   Copyright (C) 1995-2018 Free Software Foundation, Inc.
Packit 6c4009
   Written by Ulrich Drepper <drepper@gnu.org>, 1995.
Packit 6c4009
Packit 6c4009
   This program is free software: you can redistribute it and/or modify
Packit 6c4009
   it under the terms of the GNU Lesser General Public License as published by
Packit 6c4009
   the Free Software Foundation; either version 2.1 of the License, or
Packit 6c4009
   (at your option) any later version.
Packit 6c4009
Packit 6c4009
   This program is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6c4009
   GNU Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public License
Packit 6c4009
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifdef HAVE_CONFIG_H
Packit 6c4009
# include <config.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <sys/types.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
#if defined HAVE_UNISTD_H || defined _LIBC
Packit 6c4009
# include <unistd.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include "gettextP.h"
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
# include <libintl.h>
Packit 6c4009
#else
Packit 6c4009
# include "libgnuintl.h"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Handle multi-threaded applications.  */
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
# include <libc-lock.h>
Packit 6c4009
# define gl_rwlock_define_initialized __libc_rwlock_define_initialized
Packit 6c4009
# define gl_rwlock_rdlock __libc_rwlock_rdlock
Packit 6c4009
# define gl_rwlock_wrlock __libc_rwlock_wrlock
Packit 6c4009
# define gl_rwlock_unlock __libc_rwlock_unlock
Packit 6c4009
#else
Packit 6c4009
# include "lock.h"
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* @@ end of prolog @@ */
Packit 6c4009
/* List of already loaded domains.  */
Packit 6c4009
static struct loaded_l10nfile *_nl_loaded_domains;
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Return a data structure describing the message catalog described by
Packit 6c4009
   the DOMAINNAME and CATEGORY parameters with respect to the currently
Packit 6c4009
   established bindings.  */
Packit 6c4009
struct loaded_l10nfile *
Packit 6c4009
_nl_find_domain (const char *dirname, char *locale,
Packit 6c4009
		 const char *domainname, struct binding *domainbinding)
Packit 6c4009
{
Packit 6c4009
  struct loaded_l10nfile *retval;
Packit 6c4009
  const char *language;
Packit 6c4009
  const char *modifier;
Packit 6c4009
  const char *territory;
Packit 6c4009
  const char *codeset;
Packit 6c4009
  const char *normalized_codeset;
Packit 6c4009
  const char *alias_value;
Packit 6c4009
  int mask;
Packit 6c4009
Packit 6c4009
  /* LOCALE can consist of up to four recognized parts for the XPG syntax:
Packit 6c4009
Packit 6c4009
		language[_territory][.codeset][@modifier]
Packit 6c4009
Packit 6c4009
     Beside the first part all of them are allowed to be missing.  If
Packit 6c4009
     the full specified locale is not found, the less specific one are
Packit 6c4009
     looked for.  The various parts will be stripped off according to
Packit 6c4009
     the following order:
Packit 6c4009
		(1) codeset
Packit 6c4009
		(2) normalized codeset
Packit 6c4009
		(3) territory
Packit 6c4009
		(4) modifier
Packit 6c4009
   */
Packit 6c4009
Packit 6c4009
  /* We need to protect modifying the _NL_LOADED_DOMAINS data.  */
Packit 6c4009
  gl_rwlock_define_initialized (static, lock);
Packit 6c4009
  gl_rwlock_rdlock (lock);
Packit 6c4009
Packit 6c4009
  /* If we have already tested for this locale entry there has to
Packit 6c4009
     be one data set in the list of loaded domains.  */
Packit 6c4009
  retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
Packit 6c4009
			       strlen (dirname) + 1, 0, locale, NULL, NULL,
Packit 6c4009
			       NULL, NULL, domainname, 0);
Packit 6c4009
Packit 6c4009
  gl_rwlock_unlock (lock);
Packit 6c4009
Packit 6c4009
  if (retval != NULL)
Packit 6c4009
    {
Packit 6c4009
      /* We know something about this locale.  */
Packit 6c4009
      int cnt;
Packit 6c4009
Packit 6c4009
      if (retval->decided <= 0)
Packit 6c4009
	_nl_load_domain (retval, domainbinding);
Packit 6c4009
Packit 6c4009
      if (retval->data != NULL)
Packit 6c4009
	return retval;
Packit 6c4009
Packit 6c4009
      for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
Packit 6c4009
	{
Packit 6c4009
	  if (retval->successor[cnt]->decided <= 0)
Packit 6c4009
	    _nl_load_domain (retval->successor[cnt], domainbinding);
Packit 6c4009
Packit 6c4009
	  if (retval->successor[cnt]->data != NULL)
Packit 6c4009
	    break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      return retval;
Packit 6c4009
      /* NOTREACHED */
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* See whether the locale value is an alias.  If yes its value
Packit 6c4009
     *overwrites* the alias name.  No test for the original value is
Packit 6c4009
     done.  */
Packit 6c4009
  alias_value = _nl_expand_alias (locale);
Packit 6c4009
  if (alias_value != NULL)
Packit 6c4009
    {
Packit 6c4009
      size_t len = strlen (alias_value) + 1;
Packit 6c4009
      locale = (char *) malloc (len);
Packit 6c4009
      if (locale == NULL)
Packit 6c4009
	return NULL;
Packit 6c4009
Packit 6c4009
      memcpy (locale, alias_value, len);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Now we determine the single parts of the locale name.  First
Packit 6c4009
     look for the language.  Termination symbols are `_', '.', and `@'.  */
Packit 6c4009
  mask = _nl_explode_name (locale, &language, &modifier, &territory,
Packit 6c4009
			   &codeset, &normalized_codeset);
Packit 6c4009
  if (mask == -1)
Packit 6c4009
    /* This means we are out of core.  */
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  /* We need to protect modifying the _NL_LOADED_DOMAINS data.  */
Packit 6c4009
  gl_rwlock_wrlock (lock);
Packit 6c4009
Packit 6c4009
  /* Create all possible locale entries which might be interested in
Packit 6c4009
     generalization.  */
Packit 6c4009
  retval = _nl_make_l10nflist (&_nl_loaded_domains, dirname,
Packit 6c4009
			       strlen (dirname) + 1, mask, language, territory,
Packit 6c4009
			       codeset, normalized_codeset, modifier,
Packit 6c4009
			       domainname, 1);
Packit 6c4009
Packit 6c4009
  gl_rwlock_unlock (lock);
Packit 6c4009
Packit 6c4009
  if (retval == NULL)
Packit 6c4009
    /* This means we are out of core.  */
Packit 6c4009
    goto out;
Packit 6c4009
Packit 6c4009
  if (retval->decided <= 0)
Packit 6c4009
    _nl_load_domain (retval, domainbinding);
Packit 6c4009
  if (retval->data == NULL)
Packit 6c4009
    {
Packit 6c4009
      int cnt;
Packit 6c4009
      for (cnt = 0; retval->successor[cnt] != NULL; ++cnt)
Packit 6c4009
	{
Packit 6c4009
	  if (retval->successor[cnt]->decided <= 0)
Packit 6c4009
	    _nl_load_domain (retval->successor[cnt], domainbinding);
Packit 6c4009
	  if (retval->successor[cnt]->data != NULL)
Packit 6c4009
	    break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* The room for an alias was dynamically allocated.  Free it now.  */
Packit 6c4009
  if (alias_value != NULL)
Packit 6c4009
    free (locale);
Packit 6c4009
Packit 6c4009
out:
Packit 6c4009
  /* The space for normalized_codeset is dynamically allocated.  Free it.  */
Packit 6c4009
  if (mask & XPG_NORM_CODESET)
Packit 6c4009
    free ((void *) normalized_codeset);
Packit 6c4009
Packit 6c4009
  return retval;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
#ifdef _LIBC
Packit 6c4009
/* This is called from iconv/gconv_db.c's free_mem, as locales must
Packit 6c4009
   be freed before freeing gconv steps arrays.  */
Packit 6c4009
void __libc_freeres_fn_section
Packit 6c4009
_nl_finddomain_subfreeres (void)
Packit 6c4009
{
Packit 6c4009
  struct loaded_l10nfile *runp = _nl_loaded_domains;
Packit 6c4009
Packit 6c4009
  while (runp != NULL)
Packit 6c4009
    {
Packit 6c4009
      struct loaded_l10nfile *here = runp;
Packit 6c4009
      if (runp->data != NULL)
Packit 6c4009
	_nl_unload_domain ((struct loaded_domain *) runp->data);
Packit 6c4009
      runp = runp->next;
Packit 6c4009
      free ((char *) here->filename);
Packit 6c4009
      free (here);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
#endif