📄 gconv_conf.c
字号:
/* Handle configuration data. Copyright (C) 1997,98,99,2000,2001 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */#include <assert.h>#include <ctype.h>#include <errno.h>#include <limits.h>#include <locale.h>#include <search.h>#include <stddef.h>#include <stdio.h>#include <stdio_ext.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/param.h>#include <dirent.h>#include <gconv_int.h>/* This is the default path where we look for module lists. */static const char default_gconv_path[] = GCONV_PATH;/* The path elements, as determined by the __gconv_get_path function. All path elements end in a slash. */struct path_elem *__gconv_path_elem;/* Maximum length of a single path element in __gconv_path_elem. */size_t __gconv_max_path_elem_len;/* We use the following struct if we couldn't allocate memory. */static const struct path_elem empty_path_elem;/* Name of the file containing the module information in the directories along the path. */static const char gconv_conf_filename[] = "gconv-modules";/* Filename extension for the modules. */#ifndef MODULE_EXT# define MODULE_EXT ".so"#endifstatic const char gconv_module_ext[] = MODULE_EXT;/* We have a few builtin transformations. */static struct gconv_module builtin_modules[] ={#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, MinF, MaxF, \ MinT, MaxT) \ { \ from_string: From, \ to_string: To, \ cost_hi: Cost, \ cost_lo: INT_MAX, \ module_name: Name \ },#define BUILTIN_ALIAS(From, To)#include "gconv_builtin.h"};#undef BUILTIN_TRANSFORMATION#undef BUILTIN_ALIASstatic const char *builtin_aliases[] ={#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, MinF, MaxF, \ MinT, MaxT)#define BUILTIN_ALIAS(From, To) From " " To,#include "gconv_builtin.h"};#ifdef USE_IN_LIBIO# include <libio/libioP.h># define __getdelim(line, len, c, fp) _IO_getdelim (line, len, c, fp)#endif/* Value of the GCONV_PATH environment variable. */const char *__gconv_path_envvar;/* Test whether there is already a matching module known. */static intinternal_functiondetect_conflict (const char *alias){ struct gconv_module *node = __gconv_modules_db; while (node != NULL) { int cmpres = strcmp (alias, node->from_string); if (cmpres == 0) /* We have a conflict. */ return 1; else if (cmpres < 0) node = node->left; else node = node->right; } return node != NULL;}/* Add new alias. */static inline voidadd_alias (char *rp, void *modules){ /* We now expect two more string. The strings are normalized (converted to UPPER case) and strored in the alias database. */ struct gconv_alias *new_alias; char *from, *to, *wp; char old_locale[20], *old_locale_p; /* Set locale to default C locale. */ old_locale_p = setlocale(LC_ALL, "C"); strncpy(old_locale, old_locale_p, 20); while (isspace (*rp)) ++rp; from = wp = rp; while (*rp != '\0' && !isspace (*rp)) *wp++ = toupper (*rp++); if (*rp == '\0') { setlocale(LC_ALL, old_locale); /* There is no `to' string on the line. Ignore it. */ return; } *wp++ = '\0'; to = ++rp; while (isspace (*rp)) ++rp; while (*rp != '\0' && !isspace (*rp)) *wp++ = toupper (*rp++); if (to == wp) { setlocale(LC_ALL, old_locale); /* No `to' string, ignore the line. */ return; } *wp++ = '\0'; /* Test whether this alias conflicts with any available module. */ if (detect_conflict (from)) { setlocale(LC_ALL, old_locale); /* It does conflict, don't add the alias. */ return; } new_alias = (struct gconv_alias *) malloc (sizeof (struct gconv_alias) + (wp - from)); if (new_alias != NULL) { void **inserted; new_alias->fromname = memcpy ((char *) new_alias + sizeof (struct gconv_alias), from, wp - from); new_alias->toname = new_alias->fromname + (to - from); inserted = (void **) tsearch (new_alias, &__gconv_alias_db, __gconv_alias_compare); if (inserted == NULL || *inserted != new_alias) /* Something went wrong, free this entry. */ free (new_alias); } setlocale(LC_ALL, old_locale);}/* Insert a data structure for a new module in the search tree. */static inline voidinternal_functioninsert_module (struct gconv_module *newp, int tobefreed){ struct gconv_module **rootp = &__gconv_modules_db; while (*rootp != NULL) { struct gconv_module *root = *rootp; int cmpres; cmpres = strcmp (newp->from_string, root->from_string); if (cmpres == 0) { /* Both strings are identical. Insert the string at the end of the `same' list if it is not already there. */ while (strcmp (newp->from_string, root->from_string) != 0 || strcmp (newp->to_string, root->to_string) != 0) { rootp = &root->same; root = *rootp; if (root == NULL) break; } if (root != NULL) { /* This is a no new conversion. But maybe the cost is better. */ if (newp->cost_hi < root->cost_hi || (newp->cost_hi == root->cost_hi && newp->cost_lo < root->cost_lo)) { newp->left = root->left; newp->right = root->right; newp->same = root->same; *rootp = newp; free (root); } else if (tobefreed) free (newp); return; } break; } else if (cmpres < 0) rootp = &root->left; else rootp = &root->right; } /* Plug in the new node here. */ *rootp = newp;}/* Add new module. */static voidinternal_functionadd_module (char *rp, const char *directory, size_t dir_len, void **modules, size_t *nmodules, int modcounter){ /* We expect now 1. `from' name 2. `to' name 3. filename of the module 4. an optional cost value */ struct gconv_alias fake_alias; struct gconv_module *new_module; char *from, *to, *module, *wp; int need_ext; int cost_hi; char old_locale[20], *old_locale_p; char *old; size_t len; char *new; /* Set locale to default C locale. */ old_locale_p = setlocale(LC_ALL, "C"); strncpy(old_locale, old_locale_p, 20); while (isspace (*rp)) ++rp; from = rp; while (*rp != '\0' && !isspace (*rp)) { *rp = toupper (*rp); ++rp; } if (*rp == '\0') { setlocale(LC_ALL, old_locale); return; } *rp++ = '\0'; to = wp = rp; while (isspace (*rp)) { setlocale(LC_ALL, old_locale); ++rp; } while (*rp != '\0' && !isspace (*rp)) *wp++ = toupper (*rp++); if (*rp == '\0') { setlocale(LC_ALL, old_locale); return; } *wp++ = '\0'; do ++rp; while (isspace (*rp)); module = wp; while (*rp != '\0' && !isspace (*rp)) *wp++ = *rp++; if (*rp == '\0') { /* There is no cost, use one by default. */ *wp++ = '\0'; cost_hi = 1; } else { /* There might be a cost value. */ char *endp; *wp++ = '\0'; cost_hi = strtol (rp, &endp, 10); if (rp == endp || cost_hi < 1) /* No useful information. */ cost_hi = 1; } if (module[0] == '\0') { setlocale(LC_ALL, old_locale); /* No module name given. */ return; } if (module[0] == '/') dir_len = 0; /* See whether we must add the ending. */ need_ext = 0; if (wp - module < (ptrdiff_t) sizeof (gconv_module_ext) || memcmp (wp - sizeof (gconv_module_ext), gconv_module_ext, sizeof (gconv_module_ext)) != 0) /* We must add the module extension. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -