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