home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / id-utils-3.2-src.tgz / tar.out / fsf / id-utils / intl / l10nflist.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  10KB  |  403 lines

  1. /* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3. Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
  4.  
  5. The GNU C Library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Library General Public License as
  7. published by the Free Software Foundation; either version 2 of the
  8. License, or (at your option) any later version.
  9.  
  10. The GNU C Library is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13. Library General Public License for more details.
  14.  
  15. You should have received a copy of the GNU Library General Public
  16. License along with the GNU C Library; see the file COPYING.LIB.  If
  17. not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  18. Boston, MA 02111-1307, USA.  */
  19.  
  20. #ifdef HAVE_CONFIG_H
  21. # include <config.h>
  22. #endif
  23.  
  24. #if defined _LIBC || defined HAVE_ARGZ_H
  25. # include <argz.h>
  26. #endif
  27. #include <ctype.h>
  28.  
  29. #if defined STDC_HEADERS || defined _LIBC
  30. # include <stdlib.h>
  31. #endif
  32.  
  33. #if defined HAVE_STRING_H || defined _LIBC
  34. # ifndef _GNU_SOURCE
  35. #  define _GNU_SOURCE    1
  36. # endif
  37. # include <string.h>
  38. #else
  39. # include <strings.h>
  40. #endif
  41. #if !HAVE_STRCHR && !defined _LIBC
  42. # ifndef strchr
  43. #  define strchr index
  44. # endif
  45. #endif
  46.  
  47. #include "loadinfo.h"
  48.  
  49. /* On some strange systems still no definition of NULL is found.  Sigh!  */
  50. #ifndef NULL
  51. # if defined __STDC__ && __STDC__
  52. #  define NULL ((void *) 0)
  53. # else
  54. #  define NULL 0
  55. # endif
  56. #endif
  57.  
  58. /* @@ end of prolog @@ */
  59.  
  60. #ifdef _LIBC
  61. /* Rename the non ANSI C functions.  This is required by the standard
  62.    because some ANSI C functions will require linking with this object
  63.    file and the name space must not be polluted.  */
  64. # define stpcpy(dest, src) __stpcpy(dest, src)
  65. #else
  66. # ifndef HAVE_STPCPY
  67. static char *stpcpy PARAMS ((char *dest, const char *src));
  68. # endif
  69. #endif
  70.  
  71. /* Define function which are usually not available.  */
  72.  
  73. #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
  74. /* Returns the number of strings in ARGZ.  */
  75. static size_t argz_count__ PARAMS ((const char *argz, size_t len));
  76.  
  77. static size_t
  78. argz_count__ (argz, len)
  79.      const char *argz;
  80.      size_t len;
  81. {
  82.   size_t count = 0;
  83.   while (len > 0)
  84.     {
  85.       size_t part_len = strlen (argz);
  86.       argz += part_len + 1;
  87.       len -= part_len + 1;
  88.       count++;
  89.     }
  90.   return count;
  91. }
  92. # undef __argz_count
  93. # define __argz_count(argz, len) argz_count__ (argz, len)
  94. #endif    /* !_LIBC && !HAVE___ARGZ_COUNT */
  95.  
  96. #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
  97. /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
  98.    except the last into the character SEP.  */
  99. static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
  100.  
  101. static void
  102. argz_stringify__ (argz, len, sep)
  103.      char *argz;
  104.      size_t len;
  105.      int sep;
  106. {
  107.   while (len > 0)
  108.     {
  109.       size_t part_len = strlen (argz);
  110.       argz += part_len;
  111.       len -= part_len + 1;
  112.       if (len > 0)
  113.     *argz++ = sep;
  114.     }
  115. }
  116. # undef __argz_stringify
  117. # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
  118. #endif    /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
  119.  
  120. #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
  121. static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
  122.                   const char *entry));
  123.  
  124. static char *
  125. argz_next__ (argz, argz_len, entry)
  126.      char *argz;
  127.      size_t argz_len;
  128.      const char *entry;
  129. {
  130.   if (entry)
  131.     {
  132.       if (entry < argz + argz_len)
  133.         entry = strchr (entry, '\0') + 1;
  134.  
  135.       return entry >= argz + argz_len ? NULL : (char *) entry;
  136.     }
  137.   else
  138.     if (argz_len > 0)
  139.       return argz;
  140.     else
  141.       return 0;
  142. }
  143. # undef __argz_next
  144. # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
  145. #endif    /* !_LIBC && !HAVE___ARGZ_NEXT */
  146.  
  147.  
  148. /* Return number of bits set in X.  */
  149. static int pop PARAMS ((int x));
  150.  
  151. static inline int
  152. pop (x)
  153.      int x;
  154. {
  155.   /* We assume that no more than 16 bits are used.  */
  156.   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
  157.   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
  158.   x = ((x >> 4) + x) & 0x0f0f;
  159.   x = ((x >> 8) + x) & 0xff;
  160.  
  161.   return x;
  162. }
  163.  
  164.  
  165. struct loaded_l10nfile *
  166. _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
  167.             territory, codeset, normalized_codeset, modifier, special,
  168.             sponsor, revision, filename, do_allocate)
  169.      struct loaded_l10nfile **l10nfile_list;
  170.      const char *dirlist;
  171.      size_t dirlist_len;
  172.      int mask;
  173.      const char *language;
  174.      const char *territory;
  175.      const char *codeset;
  176.      const char *normalized_codeset;
  177.      const char *modifier;
  178.      const char *special;
  179.      const char *sponsor;
  180.      const char *revision;
  181.      const char *filename;
  182.      int do_allocate;
  183. {
  184.   char *abs_filename;
  185.   struct loaded_l10nfile *last = NULL;
  186.   struct loaded_l10nfile *retval;
  187.   char *cp;
  188.   size_t entries;
  189.   int cnt;
  190.  
  191.   /* Allocate room for the full file name.  */
  192.   abs_filename = (char *) malloc (dirlist_len
  193.                   + strlen (language)
  194.                   + ((mask & TERRITORY) != 0
  195.                      ? strlen (territory) + 1 : 0)
  196.                   + ((mask & XPG_CODESET) != 0
  197.                      ? strlen (codeset) + 1 : 0)
  198.                   + ((mask & XPG_NORM_CODESET) != 0
  199.                      ? strlen (normalized_codeset) + 1 : 0)
  200.                   + (((mask & XPG_MODIFIER) != 0
  201.                       || (mask & CEN_AUDIENCE) != 0) ?
  202.                      strlen (modifier) + 1 : 0)
  203.                   + ((mask & CEN_SPECIAL) != 0
  204.                      ? strlen (special) + 1 : 0)
  205.                   + ((mask & CEN_SPONSOR) != 0
  206.                      ? strlen (sponsor) + 1 : 0)
  207.                   + ((mask & CEN_REVISION) != 0
  208.                      ? strlen (revision) + 1 : 0)
  209.                   + 1 + strlen (filename) + 1);
  210.  
  211.   if (abs_filename == NULL)
  212.     return NULL;
  213.  
  214.   retval = NULL;
  215.   last = NULL;
  216.  
  217.   /* Construct file name.  */
  218.   memcpy (abs_filename, dirlist, dirlist_len);
  219.   __argz_stringify (abs_filename, dirlist_len, ':');
  220.   cp = abs_filename + (dirlist_len - 1);
  221.   *cp++ = '/';
  222.   cp = stpcpy (cp, language);
  223.  
  224.   if ((mask & TERRITORY) != 0)
  225.     {
  226.       *cp++ = '_';
  227.       cp = stpcpy (cp, territory);
  228.     }
  229.   if ((mask & XPG_CODESET) != 0)
  230.     {
  231.       *cp++ = '.';
  232.       cp = stpcpy (cp, codeset);
  233.     }
  234.   if ((mask & XPG_NORM_CODESET) != 0)
  235.     {
  236.       *cp++ = '.';
  237.       cp = stpcpy (cp, normalized_codeset);
  238.     }
  239.   if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
  240.     {
  241.       /* This component can be part of both syntaces but has different
  242.      leading characters.  For CEN we use `+', else `@'.  */
  243.       *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
  244.       cp = stpcpy (cp, modifier);
  245.     }
  246.   if ((mask & CEN_SPECIAL) != 0)
  247.     {
  248.       *cp++ = '+';
  249.       cp = stpcpy (cp, special);
  250.     }
  251.   if ((mask & CEN_SPONSOR) != 0)
  252.     {
  253.       *cp++ = ',';
  254.       cp = stpcpy (cp, sponsor);
  255.     }
  256.   if ((mask & CEN_REVISION) != 0)
  257.     {
  258.       *cp++ = '_';
  259.       cp = stpcpy (cp, revision);
  260.     }
  261.  
  262.   *cp++ = '/';
  263.   stpcpy (cp, filename);
  264.  
  265.   /* Look in list of already loaded domains whether it is already
  266.      available.  */
  267.   last = NULL;
  268.   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
  269.     if (retval->filename != NULL)
  270.       {
  271.     int compare = strcmp (retval->filename, abs_filename);
  272.     if (compare == 0)
  273.       /* We found it!  */
  274.       break;
  275.     if (compare < 0)
  276.       {
  277.         /* It's not in the list.  */
  278.         retval = NULL;
  279.         break;
  280.       }
  281.  
  282.     last = retval;
  283.       }
  284.  
  285.   if (retval != NULL || do_allocate == 0)
  286.     {
  287.       free (abs_filename);
  288.       return retval;
  289.     }
  290.  
  291.   retval = (struct loaded_l10nfile *)
  292.     malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
  293.                 * (1 << pop (mask))
  294.                 * sizeof (struct loaded_l10nfile *)));
  295.   if (retval == NULL)
  296.     return NULL;
  297.  
  298.   retval->filename = abs_filename;
  299.   retval->decided = (__argz_count (dirlist, dirlist_len) != 1
  300.              || ((mask & XPG_CODESET) != 0
  301.              && (mask & XPG_NORM_CODESET) != 0));
  302.   retval->data = NULL;
  303.  
  304.   if (last == NULL)
  305.     {
  306.       retval->next = *l10nfile_list;
  307.       *l10nfile_list = retval;
  308.     }
  309.   else
  310.     {
  311.       retval->next = last->next;
  312.       last->next = retval;
  313.     }
  314.  
  315.   entries = 0;
  316.   /* If the DIRLIST is a real list the RETVAL entry correcponds not to
  317.      a real file.  So we have to use the DIRLIST separation machanism
  318.      of the inner loop.  */
  319.   cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
  320.   for (; cnt >= 0; --cnt)
  321.     if ((cnt & ~mask) == 0
  322.     && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
  323.     && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
  324.       {
  325.     /* Iterate over all elements of the DIRLIST.  */
  326.     char *dir = NULL;
  327.  
  328.     while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
  329.            != NULL)
  330.       retval->successor[entries++]
  331.         = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
  332.                   language, territory, codeset,
  333.                   normalized_codeset, modifier, special,
  334.                   sponsor, revision, filename, 1);
  335.       }
  336.   retval->successor[entries] = NULL;
  337.  
  338.   return retval;
  339. }
  340.  
  341. /* Normalize codeset name.  There is no standard for the codeset
  342.    names.  Normalization allows the user to use any of the common
  343.    names.  */
  344. const char *
  345. _nl_normalize_codeset (codeset, name_len)
  346.      const char *codeset;
  347.      size_t name_len;
  348. {
  349.   int len = 0;
  350.   int only_digit = 1;
  351.   char *retval;
  352.   char *wp;
  353.   size_t cnt;
  354.  
  355.   for (cnt = 0; cnt < name_len; ++cnt)
  356.     if (isalnum (codeset[cnt]))
  357.       {
  358.     ++len;
  359.  
  360.     if (isalpha (codeset[cnt]))
  361.       only_digit = 0;
  362.       }
  363.  
  364.   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
  365.  
  366.   if (retval != NULL)
  367.     {
  368.       if (only_digit)
  369.     wp = stpcpy (retval, "ISO");
  370.       else
  371.     wp = retval;
  372.  
  373.       for (cnt = 0; cnt < name_len; ++cnt)
  374.     if (isalpha (codeset[cnt]))
  375.       *wp++ = tolower (codeset[cnt]);
  376.     else if (isdigit (codeset[cnt]))
  377.       *wp++ = codeset[cnt];
  378.  
  379.       *wp = '\0';
  380.     }
  381.  
  382.   return (const char *) retval;
  383. }
  384.  
  385.  
  386. /* @@ begin of epilog @@ */
  387.  
  388. /* We don't want libintl.a to depend on any other library.  So we
  389.    avoid the non-standard function stpcpy.  In GNU C Library this
  390.    function is available, though.  Also allow the symbol HAVE_STPCPY
  391.    to be defined.  */
  392. #if !_LIBC && !HAVE_STPCPY
  393. static char *
  394. stpcpy (dest, src)
  395.      char *dest;
  396.      const char *src;
  397. {
  398.   while ((*dest++ = *src++) != '\0')
  399.     /* Do nothing. */ ;
  400.   return dest - 1;
  401. }
  402. #endif
  403.