(linenum→info "unix/slp.c:2238")

glibc/2.7/iconv/iconvconfig.c

    1: /* Generate fastloading iconv module configuration files.
    2:    Copyright (C) 2000-2004, 2005, 2006, 2007 Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    4:    Contributed by Ulrich Drepper <drepper@redhat.com>, 2000.
    5: 
    6:    This program is free software; you can redistribute it and/or modify
    7:    it under the terms of the GNU General Public License as published
    8:    by the Free Software Foundation; version 2 of the License, or
    9:    (at your option) any later version.
   10: 
   11:    This program is distributed in the hope that it will be useful,
   12:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   13:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14:    GNU General Public License for more details.
   15: 
   16:    You should have received a copy of the GNU General Public License
   17:    along with this program; if not, write to the Free Software Foundation,
   18:    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
   19: 
   20: #include <argp.h>
   21: #include <assert.h>
   22: #include <error.h>
   23: #include <errno.h>
   24: #include <fcntl.h>
   25: #include <libintl.h>
   26: #include <locale.h>
   27: #include <mcheck.h>
   28: #include <search.h>
   29: #include <stdint.h>
   30: #include <stdbool.h>
   31: #include <stdio.h>
   32: #include <stdio_ext.h>
   33: #include <stdlib.h>
   34: #include <string.h>
   35: #include <unistd.h>
   36: #include <sys/cdefs.h>
   37: #include <sys/uio.h>
   38: 
   39: #include "iconvconfig.h"
   40: 
   41: /* Get libc version number.  */
   42: #include "../version.h"
   43: 
   44: #define PACKAGE _libc_intl_domainname
   45: 
   46: 
   47: /* The hashing function we use.  */
   48: #include "../intl/hash-string.h"
   49: 
   50: 
   51: /* Types used.  */
   52: struct module
   53: {
   54:   char *fromname;
   55:   struct Strent *fromname_strent;
   56:   char *filename;
   57:   struct Strent *filename_strent;
   58:   const char *directory;
   59:   struct Strent *directory_strent;
   60:   struct module *next;
   61:   int cost;
   62:   struct Strent *toname_strent;
   63:   char toname[0];
   64: };
   65: 
   66: struct alias
   67: {
   68:   char *fromname;
   69:   struct Strent *froment;
   70:   struct module *module;
   71:   struct Strent *toent;
   72:   char toname[0];
   73: };
   74: 
   75: struct name
   76: {
   77:   const char *name;
   78:   struct Strent *strent;
   79:   int module_idx;
   80:   uint32_t hashval;
   81: };
   82: 
   83: struct name_info
   84: {
   85:   const char *canonical_name;
   86:   struct Strent *canonical_strent;
   87: 
   88:   struct module *from_internal;
   89:   struct module *to_internal;
   90: 
   91:   struct other_conv_list
   92:   {
   93:     int dest_idx;
   94:     struct other_conv
   95:     {
   96:       gidx_t module_idx;
   97:       struct module *module;
   98:       struct other_conv *next;
   99:     } other_conv;
  100:     struct other_conv_list *next;
  101:   } *other_conv_list;
  102: };
  103: 
  104: 
  105: /* Name and version of program.  */
  106: static void print_version (FILE *stream, struct argp_state *state);
  107: void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
  108: 
  109: /* Short description of program.  */
  110: static const char doc[] = N_("\
  111: Create fastloading iconv module configuration file.");
  112: 
  113: /* Strings for arguments in help texts.  */
  114: static const char args_doc[] = N_("[DIR...]");
  115: 
  116: /* Prototype for option handler.  */
  117: static error_t parse_opt (int key, char *arg, struct argp_state *state);
  118: 
  119: /* Function to print some extra text in the help message.  */
  120: static char *more_help (int key, const char *text, void *input);
  121: 
  122: /* Definitions of arguments for argp functions.  */
  123: #define OPT_PREFIX 300
  124: #define OPT_NOSTDLIB 301
  125: static const struct argp_option options[] =
  126: {
  127:   { "prefix", OPT_PREFIX, "PATH", 0, N_("Prefix used for all file accesses") },
  128:   { "output", 'o', "FILE", 0, N_("\
  129: Put output in FILE instead of installed location\
  130:  (--prefix does not apply to FILE)") },
  131:   { "nostdlib", OPT_NOSTDLIB, NULL, 0,
  132:     N_("Do not search standard directories, only those on the command line") },
  133:   { NULL, 0, NULL, 0, NULL }
  134: };
  135: 
  136: /* Data structure to communicate with argp functions.  */
  137: static struct argp argp =
  138: {
  139:   options, parse_opt, args_doc, doc, NULL, more_help
  140: };
  141: 
  142: 
  143: /* The function doing the actual work.  */
  144: static int handle_dir (const char *dir);
  145: 
  146: /* Add all known builtin conversions and aliases.  */
  147: static void add_builtins (void);
  148: 
  149: /* Create list of all aliases without circular aliases.  */
  150: static void get_aliases (void);
  151: 
  152: /* Create list of all modules.  */
  153: static void get_modules (void);
  154: 
  155: /* Get list of all the names and thereby indexing them.  */
  156: static void generate_name_list (void);
  157: 
  158: /* Collect information about all the names.  */
  159: static void generate_name_info (void);
  160: 
  161: /* Write the output file.  */
  162: static int write_output (void);
  163: 
  164: 
  165: /* Prefix to be used for all file accesses.  */
  166: static const char *prefix = "";
  167: /* Its length.  */
  168: static size_t prefix_len;
  169: 
  170: /* Directory to place output file in.  */
  171: static const char *output_file;
  172: /* Its length.  */
  173: static size_t output_file_len;
  174: 
  175: /* If true, omit the GCONV_PATH directories and require some arguments.  */
  176: static bool nostdlib;
  177: 
  178: /* Search tree of the modules we know.  */
  179: static void *modules;
  180: 
  181: /* Search tree of the aliases we know.  */
  182: static void *aliases;
  183: 
  184: /* Search tree for name to index mapping.  */
  185: static void *names;
  186: 
  187: /* Number of names we know about.  */
  188: static int nnames;
  189: 
  190: /* List of all aliases.  */
  191: static struct alias **alias_list;
  192: static size_t nalias_list;
  193: static size_t nalias_list_max;
  194: 
  195: /* List of all modules.  */
  196: static struct module **module_list;
  197: static size_t nmodule_list;
  198: static size_t nmodule_list_max;
  199: 
  200: /* Names and information about them.  */
  201: static struct name_info *name_info;
  202: static size_t nname_info;
  203: 
  204: /* Number of translations not from or to INTERNAL.  */
  205: static size_t nextra_modules;
  206: 
  207: 
  208: /* Names and aliases for the builtin transformations.  */
  209: static struct
  210: {
  211:   const char *from;
  212:   const char *to;
  213: } builtin_alias[] =
  214:   {
  215: #define BUILTIN_ALIAS(alias, real) \
  216:     { .from = alias, .to = real },
  217: #define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
  218:                                MinF, MaxF, MinT, MaxT)
  219: #include <gconv_builtin.h>
  220:   };
  221: #undef BUILTIN_ALIAS
  222: #undef BUILTIN_TRANSFORMATION
  223: #define nbuiltin_alias (sizeof (builtin_alias) / sizeof (builtin_alias[0]))
  224: 
  225: static struct
  226: {
  227:   const char *from;
  228:   const char *to;
  229:   const char *module;
  230:   int cost;
  231: } builtin_trans[] =
  232:   {
  233: #define BUILTIN_ALIAS(alias, real)
  234: #define BUILTIN_TRANSFORMATION(From, To, Cost, Name, Fct, BtowcFct, \
  235:                                MinF, MaxF, MinT, MaxT) \
  236:     { .from = From, .to = To, .module = Name, .cost = Cost },
  237: #include <gconv_builtin.h>
  238:   };
  239: #undef BUILTIN_ALIAS
  240: #undef BUILTIN_TRANSFORMATION
  241: #define nbuiltin_trans (sizeof (builtin_trans) / sizeof (builtin_trans[0]))
  242: 
  243: 
  244: /* Filename extension for the modules.  */
  245: #ifndef MODULE_EXT
  246: # define MODULE_EXT ".so"
  247: #endif
  248: static const char gconv_module_ext[] = MODULE_EXT;
  249: 
  250: 
  251: extern void *xmalloc (size_t n) __attribute_malloc__;
  252: extern void *xcalloc (size_t n, size_t m) __attribute_malloc__;
  253: extern void *xrealloc (void *p, size_t n);
  254: 
  255: 
  256: /* C string table handling.  */
  257: struct Strtab;
  258: struct Strent;
  259: 
  260: /* Create new C string table object in memory.  */
  261: extern struct Strtab *strtabinit (void);
  262: 
  263: /* Free resources allocated for C string table ST.  */
  264: extern void strtabfree (struct Strtab *st);
  265: 
  266: /* Add string STR (length LEN is != 0) to C string table ST.  */
  267: extern struct Strent *strtabadd (struct Strtab *st, const char *str,
  268:                                  size_t len);
  269: 
  270: /* Finalize string table ST and store size in *SIZE and return a pointer.  */
  271: extern void *strtabfinalize (struct Strtab *st, size_t *size);
  272: 
  273: /* Get offset in string table for string associated with SE.  */
  274: extern size_t strtaboffset (struct Strent *se);
  275: 
  276: /* String table we construct.  */
  277: static struct Strtab *strtab;
  278: 
  279: 
  280: 
  281: int
  282: main (int argc, char *argv[])
  283: {
  284:   int remaining;
  285:   int status = 0;
  286: 
  287:   /* Enable memory use testing.  */
  288:   /* mcheck_pedantic (NULL); */
  289:   mtrace ();
  290: 
  291:   /* Set locale via LC_ALL.  */
  292:   setlocale (LC_ALL, "");
  293: 
  294:   /* Set the text message domain.  */
  295:   textdomain (_libc_intl_domainname);
  296: 
  297:   /* Parse and process arguments.  */
  298:   argp_parse (&argp, argc, argv, 0, &remaining, NULL);
  299: 
  300:   if (nostdlib && remaining == argc)
  301:     error (2, 0, _("Directory arguments required when using --nostdlib"));
  302: 
  303:   /* Initialize the string table.  */
  304:   strtab = strtabinit ();
  305: 
  306:   /* Handle all directories mentioned.  */
  307:   while (remaining < argc)
  308:     status |= handle_dir (argv[remaining++]);
  309: 
  310:   if (! nostdlib)
  311:     {
  312:       /* In any case also handle the standard directory.  */
  313:       char *path = strdupa (GCONV_PATH), *tp = strsep (&path, ":");
  314:       while (tp != NULL)
  315:         {
  316:           status |= handle_dir (tp);
  317: 
  318:           tp = strsep (&path, ":");
  319:         }
  320:     }
  321: 
  322:   /* Add the builtin transformations and aliases without overwriting
  323:      anything.  */
  324:   add_builtins ();
  325: 
  326:   /* Store aliases in an array.  */
  327:   get_aliases ();
  328: 
  329:   /* Get list of all modules.  */
  330:   get_modules ();
  331: 
  332:   /* Generate list of all the names we know to handle in some way.  */
  333:   generate_name_list ();
  334: 
  335:   /* Now we know all the names we will handle, collect information
  336:      about them.  */
  337:   generate_name_info ();
  338: 
  339:   /* Write the output file, but only if we haven't seen any error.  */
  340:   if (status == 0)
  341:     status = write_output ();
  342:   else
  343:     error (1, 0, _("no output file produced because warnings were issued"));
  344: 
  345:   return status;
  346: }
  347: 
  348: 
  349: /* Handle program arguments.  */
  350: static error_t
  351: parse_opt (int key, char *arg, struct argp_state *state)
  352: {
  353:   switch (key)
  354:     {
  355:     case OPT_PREFIX:
  356:       prefix = arg;
  357:       prefix_len = strlen (prefix);
  358:       break;
  359:     case 'o':
  360:       output_file = arg;
  361:       output_file_len = strlen (output_file);
  362:       break;
  363:     case OPT_NOSTDLIB:
  364:       nostdlib = true;
  365:       break;
  366:     default:
  367:       return ARGP_ERR_UNKNOWN;
  368:     }
  369:   return 0;
  370: }
  371: 
  372: 
  373: static char *
  374: more_help (int key, const char *text, void *input)
  375: {
  376:   switch (key)
  377:     {
  378:     case ARGP_KEY_HELP_EXTRA:
  379:       /* We print some extra information.  */
  380:       return strdup (gettext ("\
  381: For bug reporting instructions, please see:\n\
  382: <http://www.gnu.org/software/libc/bugs.html>.\n"));
  383:     default:
  384:       break;
  385:     }
  386:   return (char *) text;
  387: }
  388: 
  389: 
  390: /* Print the version information.  */
  391: static void
  392: print_version (FILE *stream, struct argp_state *state)
  393: {
  394:   fprintf (stream, "iconvconfig (GNU %s) %s\n", PACKAGE, VERSION);
  395:   fprintf (stream, gettext ("\
  396: Copyright (C) %s Free Software Foundation, Inc.\n\
  397: This is free software; see the source for copying conditions.  There is NO\n\
  398: warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
  399: "), "2007");
  400:   fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
  401: }
  402: 
  403: 
  404: static int
  405: alias_compare (const void *p1, const void *p2)
  406: {
  407:   const struct alias *a1 = (const struct alias *) p1;
  408:   const struct alias *a2 = (const struct alias *) p2;
  409: 
  410:   return strcmp (a1->fromname, a2->fromname);
  411: }
  412: 
  413: 
  414: static void
  415: new_alias (const char *fromname, size_t fromlen, const char *toname,
  416:            size_t tolen)
  417: {
  418:   struct alias *newp;
  419:   void **inserted;
  420: 
  421:   newp = (struct alias *) xmalloc (sizeof (struct alias) + fromlen + tolen);
  422: 
  423:   newp->fromname = mempcpy (newp->toname, toname, tolen);
  424:   memcpy (newp->fromname, fromname, fromlen);
  425:   newp->module = NULL;
  426: 
  427:   inserted = (void **) tsearch (newp, &aliases, alias_compare);
  428:   if (inserted == NULL)
  429:     error (EXIT_FAILURE, errno, gettext ("while inserting in search tree"));
  430:   if (*inserted != newp)
  431:     /* Something went wrong, free this entry.  */
  432:     free (newp);
  433:   else
  434:     {
  435:       newp->froment = strtabadd (strtab, newp->fromname, fromlen);
  436:       newp->toent = strtabadd (strtab, newp->toname, tolen);
  437:     }
  438: }
  439: 
  440: 
  441: /* Add new alias.  */
  442: static void
  443: add_alias (char *rp)
  444: {
  445:   /* We now expect two more string.  The strings are normalized
  446:      (converted to UPPER case) and strored in the alias database.  */
  447:   char *from;
  448:   char *to;
  449:   char *wp;
  450: 
  451:   while (isspace (*rp))
  452:     ++rp;
  453:   from = wp = rp;
  454:   while (*rp != '\0' && !isspace (*rp))
  455:     *wp++ = toupper (*rp++);
  456:   if (*rp == '\0')
  457:     /* There is no `to' string on the line.  Ignore it.  */
  458:     return;
  459:   *wp++ = '\0';
  460:   to = ++rp;
  461:   while (isspace (*rp))
  462:     ++rp;
  463:   while (*rp != '\0' && !isspace (*rp))
  464:     *wp++ = toupper (*rp++);
  465:   if (to == wp)
  466:     /* No `to' string, ignore the line.  */
  467:     return;
  468:   *wp++ = '\0';
  469: 
  470:   assert (strlen (from) + 1 == (size_t) (to - from));
  471:   assert (strlen (to) + 1 == (size_t) (wp - to));
  472: 
  473:   new_alias (from, to - from, to, wp - to);
  474: }
  475: 
  476: 
  477: static void
  478: append_alias (const void *nodep, VISIT value, int level)
  479: {
  480:   if (value != leaf && value != postorder)
  481:     return;
  482: 
  483:   if (nalias_list_max == nalias_list)
  484:     {
  485:       nalias_list_max += 50;
  486:       alias_list = (struct alias **) xrealloc (alias_list,
  487:                                                (nalias_list_max
  488:                                                 * sizeof (struct alias *)));
  489:     }
  490: 
  491:   alias_list[nalias_list++] = *(struct alias **) nodep;
  492: }
  493: 
  494: 
  495: static void
  496: get_aliases (void)
  497: {
  498:   twalk (aliases, append_alias);
  499: }
  500: 
  501: 
  502: static int
  503: module_compare (const void *p1, const void *p2)
  504: {
  505:   const struct module *m1 = (const struct module *) p1;
  506:   const struct module *m2 = (const struct module *) p2;
  507:   int result;
  508: 
  509:   result = strcmp (m1->fromname, m2->fromname);
  510:   if (result == 0)
  511:     result = strcmp (m1->toname, m2->toname);
  512: 
  513:   return result;
  514: }
  515: 
  516: 
  517: /* Create new module record.  */
  518: static void
  519: new_module (const char *fromname, size_t fromlen, const char *toname,
  520:             size_t tolen, const char *directory,
  521:             const char *filename, size_t filelen, int cost, size_t need_ext)
  522: {
  523:   struct module *new_module;
  524:   size_t dirlen = strlen (directory) + 1;
  525:   char *tmp;
  526:   void **inserted;
  527: 
  528:   new_module = (struct module *) xmalloc (sizeof (struct module)
  529:                                           + fromlen + tolen + filelen
  530:                                           + need_ext);
  531: 
  532:   new_module->fromname = mempcpy (new_module->toname, toname, tolen);
  533: 
  534:   new_module->filename = mempcpy (new_module->fromname, fromname, fromlen);
  535: 
  536:   new_module->cost = cost;
  537:   new_module->next = NULL;
  538: 
  539:   tmp = mempcpy (new_module->filename, filename, filelen);
  540:   if (need_ext)
  541:     {
  542:       memcpy (tmp - 1, gconv_module_ext, need_ext + 1);
  543:       filelen += need_ext;
  544:     }
  545:   new_module->directory = directory;
  546: 
  547:   /* Now insert the new module data structure in our search tree.  */
  548:   inserted = (void **) tsearch (new_module, &modules, module_compare);
  549:   if (inserted == NULL)
  550:     error (EXIT_FAILURE, errno, "while inserting in search tree");
  551:   if (*inserted != new_module)
  552:     free (new_module);
  553:   else
  554:     {
  555:       new_module->fromname_strent = strtabadd (strtab, new_module->fromname,
  556:                                                fromlen);
  557:       new_module->toname_strent = strtabadd (strtab, new_module->toname,
  558:                                              tolen);
  559:       new_module->filename_strent = strtabadd (strtab, new_module->filename,
  560:                                                filelen);
  561:       new_module->directory_strent = strtabadd (strtab, directory, dirlen);
  562:     }
  563: }
  564: 
  565: 
  566: /* Add new module.  */
  567: static void
  568: internal_function
  569: add_module (char *rp, const char *directory)
  570: {
  571:   /* We expect now
  572:      1. `from' name
  573:      2. `to' name
  574:      3. filename of the module
  575:      4. an optional cost value
  576:   */
  577:   char *from;
  578:   char *to;
  579:   char *module;
  580:   char *wp;
  581:   int need_ext;
  582:   int cost;
  583: