/* Provide access to the collection of available transformation modules.
Copyright (C) 1997-2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <assert.h>
#include <limits.h>
#include <search.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <libc-lock.h>
#include <locale/localeinfo.h>
#include <dlfcn.h>
#include <gconv_int.h>
#include <pointer_guard.h>
/* Simple data structure for alias mapping. We have two names, `from'
and `to'. */
void *__gconv_alias_db;
/* Array with available modules. */
struct gconv_module *__gconv_modules_db;
/* We modify global data. */
__libc_lock_define_initialized (, __gconv_lock)
/* Provide access to module database. */
struct gconv_module *
__gconv_get_modules_db (void)
{
return __gconv_modules_db;
}
void *
__gconv_get_alias_db (void)
{
return __gconv_alias_db;
}
/* Function for searching alias. */
int
__gconv_alias_compare (const void *p1, const void *p2)
{
const struct gconv_alias *s1 = (const struct gconv_alias *) p1;
const struct gconv_alias *s2 = (const struct gconv_alias *) p2;
return strcmp (s1->fromname, s2->fromname);
}
/* To search for a derivation we create a list of intermediate steps.
Each element contains a pointer to the element which precedes it
in the derivation order. */
struct derivation_step
{
const char *result_set;
size_t result_set_len;
int cost_lo;
int cost_hi;
struct gconv_module *code;
struct derivation_step *last;
struct derivation_step *next;
};
#define NEW_STEP(result, hi, lo, module, last_mod) \
({ struct derivation_step *newp = alloca (sizeof (struct derivation_step)); \
newp->result_set = result; \
newp->result_set_len = strlen (result); \
newp->cost_hi = hi; \
newp->cost_lo = lo; \
newp->code = module; \
newp->last = last_mod; \
newp->next = NULL; \
newp; })
/* If a specific transformation is used more than once we should not need
to start looking for it again. Instead cache each successful result. */
struct known_derivation
{
const char *from;
const char *to;
struct __gconv_step *steps;