📄 iconvconfig.c
字号:
/* Generate fastloading iconv module configuration files. Copyright (C) 2000, 2001, 2002 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Ulrich Drepper <drepper@redhat.com>, 2000. 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 <argp.h>#include <assert.h>#include <error.h>#include <errno.h>#include <fcntl.h>#include <libintl.h>#include <locale.h>#include <mcheck.h>#include <search.h>#include <stdint.h>#include <stdio.h>#include <stdio_ext.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/cdefs.h>#include <sys/uio.h>#include "iconvconfig.h"/* Get libc version number. */#include "../version.h"#define PACKAGE _libc_intl_domainname/* The hashing function we use. */#include "../intl/hash-string.h"/* Types used. */struct module{ char *fromname; struct Strent *fromname_strent; char *filename; struct Strent *filename_strent; const char *directory; struct Strent *directory_strent; struct module *next; int cost; struct Strent *toname_strent; char toname[0];};struct alias{ char *fromname; struct Strent *froment; struct module *module; struct Strent *toent; char toname[0];};struct name{ const char *name; struct Strent *strent; int module_idx; uint32_t hashval;};struct name_info{ const char *canonical_name; struct Strent *canonical_strent; struct module *from_internal; struct module *to_internal; struct other_conv_list { int dest_idx; struct other_conv { gidx_t module_idx; struct module *module; struct other_conv *next; } other_conv; struct other_conv_list *next; } *other_conv_list;};/* Name and version of program. */static void print_version (FILE *stream, struct argp_state *state);void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;/* Short description of program. */static const char doc[] = N_("\Create fastloading iconv module configuration file.");/* Strings for arguments in help texts. */static const char args_doc[] = N_("[DIR...]");/* Function to print some extra text in the help message. */static char *more_help (int key, const char *text, void *input);/* Data structure to communicate with argp functions. */static struct argp argp ={ NULL, NULL, args_doc, doc, NULL, more_help};/* The function doing the actual work. */static int handle_dir (const char *dir);/* Add all known builtin conversions and aliases. */static void add_builtins (void);/* Create list of all aliases without circular aliases. */static void get_aliases (void);/* Create list of all modules. */static void get_modules (void);/* Get list of all the names and thereby indexing them. */static void generate_name_list (void);/* Collect information about all the names. */static void generate_name_info (void);/* Write the output file. */static int write_output (void);/* Search tree of the modules we know. */static void *modules;/* Search tree of the aliases we know. */static void *aliases;/* Search tree for name to index mapping. */static void *names;/* Number of names we know about. */static int nnames;/* List of all aliases. */static struct alias **alias_list;static size_t nalias_list;static size_t nalias_list_max;/* List of all modules. */static struct module **module_list;static size_t nmodule_list;static size_t nmodule_list_max;/* Names and information about them. */static struct name_info *name_info;static size_t nname_info;/* Number of translations not from or to INTERNAL. */static size_t nextra_modules;/* Names and aliases for the builtin transformations. */static struct{ const char *from; const char *to;} builtin_alias[] = {#define BUILTIN_ALIAS(alias, real) \ { .from = alias, .to = real },#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, MinF, MaxF, \ MinT, MaxT)#include <gconv_builtin.h> };#undef BUILTIN_ALIAS#undef BUILTIN_TRANSFORMATION#define nbuiltin_alias (sizeof (builtin_alias) / sizeof (builtin_alias[0]))static struct{ const char *from; const char *to; const char *module; int cost;} builtin_trans[] = {#define BUILTIN_ALIAS(alias, real)#define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, MinF, MaxF, \ MinT, MaxT) \ { .from = From, .to = To, .module = Name, .cost = Cost },#include <gconv_builtin.h> };#define nbuiltin_trans (sizeof (builtin_trans) / sizeof (builtin_trans[0]))/* Filename extension for the modules. */#ifndef MODULE_EXT# define MODULE_EXT ".so"#endifstatic const char gconv_module_ext[] = MODULE_EXT;extern void *xmalloc (size_t n) __attribute_malloc__;extern void *xcalloc (size_t n, size_t m) __attribute_malloc__;extern void *xrealloc (void *p, size_t n);/* C string table handling. */struct Strtab;struct Strent;/* Create new C string table object in memory. */extern struct Strtab *strtabinit (void);/* Free resources allocated for C string table ST. */extern void strtabfree (struct Strtab *st);/* Add string STR (length LEN is != 0) to C string table ST. */extern struct Strent *strtabadd (struct Strtab *st, const char *str, size_t len);/* Finalize string table ST and store size in *SIZE and return a pointer. */extern void *strtabfinalize (struct Strtab *st, size_t *size);/* Get offset in string table for string associated with SE. */extern size_t strtaboffset (struct Strent *se);/* String table we construct. */static struct Strtab *strtab;intmain (int argc, char *argv[]){ int remaining; int status = 0; char *path; char *tp; const char *old = GCONV_PATH; size_t len = strlen (old) + 1; char *new = alloca(len); /* Enable memory use testing. */ /* mcheck_pedantic (NULL); */ mtrace (); /* Set locale via LC_ALL. */ setlocale (LC_ALL, ""); /* Set the text message domain. */ textdomain (_libc_intl_domainname); /* Parse and process arguments. */ argp_parse (&argp, argc, argv, 0, &remaining, NULL); /* Initialize the string table. */ strtab = strtabinit (); /* Handle all directories mentioned. */ while (remaining < argc) status |= handle_dir (argv[remaining++]); /* In any case also handle the standard directory. */ path = memcpy (new, old, len); tp = strtok (path, ":"); while (tp != NULL) { status |= handle_dir (tp); tp = strtok (NULL, ":"); } /* Add the builtin transformations and aliases without overwriting anything. */ add_builtins (); /* Store aliases in an array. */ get_aliases (); /* Get list of all modules. */ get_modules (); /* Generate list of all the names we know to handle in some way. */ generate_name_list (); /* Now we know all the names we will handle, collect information about them. */ generate_name_info (); /* Write the output file, but only if we haven't seen any error. */ if (status == 0) status = write_output (); else error (1, 0, _("no output file produced because warning were issued")); return status;}static char *more_help (int key, const char *text, void *input){ switch (key) { case ARGP_KEY_HELP_EXTRA: /* We print some extra information. */ return strdup (gettext ("\Report bugs using the `glibcbug' script to <bugs@gnu.org>.\n")); default: break; } return (char *) text;}/* Print the version information. */static voidprint_version (FILE *stream, struct argp_state *state){ fprintf (stream, "iconvconfig (GNU %s) %s\n", PACKAGE, VERSION); fprintf (stream, gettext ("\Copyright (C) %s Free Software Foundation, Inc.\n\This is free software; see the source for copying conditions. There is NO\n\warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\"), "2002"); fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");}static intalias_compare (const void *p1, const void *p2){ const struct alias *a1 = (const struct alias *) p1; const struct alias *a2 = (const struct alias *) p2; return strcmp (a1->fromname, a2->fromname);}static voidnew_alias (const char *fromname, size_t fromlen, const char *toname, size_t tolen){ struct alias *newp; void **inserted; newp = (struct alias *) xmalloc (sizeof (struct alias) + fromlen + tolen); newp->fromname = memcpy (newp->toname, toname, tolen); newp->fromname += tolen; memcpy (newp->fromname, fromname, fromlen); newp->module = NULL; inserted = (void **) tsearch (newp, &aliases, alias_compare); if (inserted == NULL) error (EXIT_FAILURE, errno, gettext ("while inserting in search tree")); if (*inserted != newp) /* Something went wrong, free this entry. */ free (newp); else { newp->froment = strtabadd (strtab, newp->fromname, fromlen); newp->toent = strtabadd (strtab, newp->toname, tolen); }}/* Add new alias. */static voidadd_alias (char *rp){ /* We now expect two more string. The strings are normalized (converted to UPPER case) and strored in the alias database. */ char *from; char *to; char *wp; while (isspace (*rp)) ++rp; from = wp = rp; while (*rp != '\0' && !isspace (*rp)) *wp++ = toupper (*rp++); if (*rp == '\0') /* 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) /* No `to' string, ignore the line. */ return; *wp++ = '\0'; assert (strlen (from) + 1 == to - from); assert (strlen (to) + 1 == wp - to); new_alias (from, to - from, to, wp - to);}static voidappend_alias (const void *nodep, VISIT value, int level){ if (value != leaf && value != postorder) return; if (nalias_list_max == nalias_list) { nalias_list_max += 50; alias_list = (struct alias **) xrealloc (alias_list, (nalias_list_max * sizeof (struct alias *))); } alias_list[nalias_list++] = *(struct alias **) nodep;}static voidget_aliases (void){ twalk (aliases, append_alias);}static intmodule_compare (const void *p1, const void *p2){ const struct module *m1 = (const struct module *) p1; const struct module *m2 = (const struct module *) p2; int result; result = strcmp (m1->fromname, m2->fromname); if (result == 0) result = strcmp (m1->toname, m2->toname); return result;}/* Create new module record. */static voidnew_module (const char *fromname, size_t fromlen, const char *toname, size_t tolen, const char *directory, const char *filename, size_t filelen, int cost, size_t need_ext){ struct module *new_module; size_t dirlen = strlen (directory) + 1; char *tmp; void **inserted; new_module = (struct module *) xmalloc (sizeof (struct module) + fromlen + tolen + filelen + need_ext); new_module->fromname = memcpy (new_module->toname, toname, tolen); new_module->fromname += tolen; new_module->filename = memcpy (new_module->fromname, fromname, fromlen); new_module->filename += fromlen; new_module->cost = cost; new_module->next = NULL; tmp = memcpy (new_module->filename, filename, filelen); tmp += filelen; if (need_ext) { memcpy (tmp - 1, gconv_module_ext, need_ext + 1); filelen += need_ext; } new_module->directory = directory; /* Now insert the new module data structure in our search tree. */ inserted = (void **) tsearch (new_module, &modules, module_compare); if (inserted == NULL) error (EXIT_FAILURE, errno, "while inserting in search tree"); if (*inserted != new_module) free (new_module); else { new_module->fromname_strent = strtabadd (strtab, new_module->fromname, fromlen); new_module->toname_strent = strtabadd (strtab, new_module->toname, tolen); new_module->filename_strent = strtabadd (strtab, new_module->filename, filelen); new_module->directory_strent = strtabadd (strtab, directory, dirlen); }}/* Add new module. */static voidinternal_functionadd_module (char *rp, const char *directory){ /* We expect now 1. `from' name 2. `to' name 3. filename of the module 4. an optional cost value */ char *from; char *to; char *module; char *wp; int need_ext; int cost; while (isspace (*rp)) ++rp; from = rp; while (*rp != '\0' && !isspace (*rp)) { *rp = toupper (*rp); ++rp; } if (*rp == '\0') return; *rp++ = '\0'; to = wp = rp; while (isspace (*rp)) ++rp; while (*rp != '\0' && !isspace (*rp)) *wp++ = toupper (*rp++); if (*rp == '\0') 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 = 1; } else { /* There might be a cost value. */ char *endp; *wp++ = '\0'; cost = strtol (rp, &endp, 10); if (rp == endp || cost < 1) /* No useful information. */ cost = 1; } if (module[0] == '\0') /* No module name given. */ return; /* See whether we must add the ending. */ need_ext = 0; if (wp - module < sizeof (gconv_module_ext) || memcmp (wp - sizeof (gconv_module_ext), gconv_module_ext, sizeof (gconv_module_ext)) != 0) /* We must add the module extension. */ need_ext = sizeof (gconv_module_ext) - 1; assert (strlen (from) + 1 == to - from); assert (strlen (to) + 1 == module - to); assert (strlen (module) + 1 == wp - module);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -