Back to index

cell-binutils  2.17cvs20070401
l10nflist.c
Go to the documentation of this file.
00001 /* Copyright (C) 1995-1999, 2000, 2001, 2002 Free Software Foundation, Inc.
00002    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
00003 
00004    This program is free software; you can redistribute it and/or modify it
00005    under the terms of the GNU Library General Public License as published
00006    by the Free Software Foundation; either version 2, or (at your option)
00007    any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public
00015    License along with this program; if not, write to the Free Software
00016    Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301,
00017    USA.  */
00018 
00019 /* Tell glibc's <string.h> to provide a prototype for stpcpy().
00020    This must come before <config.h> because <config.h> may include
00021    <features.h>, and once <features.h> has been included, it's too late.  */
00022 #ifndef _GNU_SOURCE
00023 # define _GNU_SOURCE 1
00024 #endif
00025 
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029 
00030 #include <string.h>
00031 
00032 #if defined _LIBC || defined HAVE_ARGZ_H
00033 # include <argz.h>
00034 #endif
00035 #include <ctype.h>
00036 #include <sys/types.h>
00037 #include <stdlib.h>
00038 
00039 #include "loadinfo.h"
00040 
00041 /* On some strange systems still no definition of NULL is found.  Sigh!  */
00042 #ifndef NULL
00043 # if defined __STDC__ && __STDC__
00044 #  define NULL ((void *) 0)
00045 # else
00046 #  define NULL 0
00047 # endif
00048 #endif
00049 
00050 /* @@ end of prolog @@ */
00051 
00052 #ifdef _LIBC
00053 /* Rename the non ANSI C functions.  This is required by the standard
00054    because some ANSI C functions will require linking with this object
00055    file and the name space must not be polluted.  */
00056 # ifndef stpcpy
00057 #  define stpcpy(dest, src) __stpcpy(dest, src)
00058 # endif
00059 #else
00060 # ifndef HAVE_STPCPY
00061 static char *stpcpy PARAMS ((char *dest, const char *src));
00062 # endif
00063 #endif
00064 
00065 /* Pathname support.
00066    ISSLASH(C)           tests whether C is a directory separator character.
00067    IS_ABSOLUTE_PATH(P)  tests whether P is an absolute path.  If it is not,
00068                         it may be concatenated to a directory pathname.
00069  */
00070 #if defined _WIN32 || defined __WIN32__ || defined __EMX__ || defined __DJGPP__
00071   /* Win32, OS/2, DOS */
00072 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
00073 # define HAS_DEVICE(P) \
00074     ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) \
00075      && (P)[1] == ':')
00076 # define IS_ABSOLUTE_PATH(P) (ISSLASH ((P)[0]) || HAS_DEVICE (P))
00077 #else
00078   /* Unix */
00079 # define ISSLASH(C) ((C) == '/')
00080 # define IS_ABSOLUTE_PATH(P) ISSLASH ((P)[0])
00081 #endif
00082 
00083 /* Define function which are usually not available.  */
00084 
00085 #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
00086 /* Returns the number of strings in ARGZ.  */
00087 static size_t argz_count__ PARAMS ((const char *argz, size_t len));
00088 
00089 static size_t
00090 argz_count__ (argz, len)
00091      const char *argz;
00092      size_t len;
00093 {
00094   size_t count = 0;
00095   while (len > 0)
00096     {
00097       size_t part_len = strlen (argz);
00098       argz += part_len + 1;
00099       len -= part_len + 1;
00100       count++;
00101     }
00102   return count;
00103 }
00104 # undef __argz_count
00105 # define __argz_count(argz, len) argz_count__ (argz, len)
00106 #else
00107 # ifdef _LIBC
00108 #  define __argz_count(argz, len) INTUSE(__argz_count) (argz, len)
00109 # endif
00110 #endif /* !_LIBC && !HAVE___ARGZ_COUNT */
00111 
00112 #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
00113 /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
00114    except the last into the character SEP.  */
00115 static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
00116 
00117 static void
00118 argz_stringify__ (argz, len, sep)
00119      char *argz;
00120      size_t len;
00121      int sep;
00122 {
00123   while (len > 0)
00124     {
00125       size_t part_len = strlen (argz);
00126       argz += part_len;
00127       len -= part_len + 1;
00128       if (len > 0)
00129        *argz++ = sep;
00130     }
00131 }
00132 # undef __argz_stringify
00133 # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
00134 #else
00135 # ifdef _LIBC
00136 #  define __argz_stringify(argz, len, sep) \
00137   INTUSE(__argz_stringify) (argz, len, sep)
00138 # endif
00139 #endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
00140 
00141 #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
00142 static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
00143                               const char *entry));
00144 
00145 static char *
00146 argz_next__ (argz, argz_len, entry)
00147      char *argz;
00148      size_t argz_len;
00149      const char *entry;
00150 {
00151   if (entry)
00152     {
00153       if (entry < argz + argz_len)
00154         entry = strchr (entry, '\0') + 1;
00155 
00156       return entry >= argz + argz_len ? NULL : (char *) entry;
00157     }
00158   else
00159     if (argz_len > 0)
00160       return argz;
00161     else
00162       return 0;
00163 }
00164 # undef __argz_next
00165 # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
00166 #endif /* !_LIBC && !HAVE___ARGZ_NEXT */
00167 
00168 
00169 /* Return number of bits set in X.  */
00170 static int pop PARAMS ((int x));
00171 
00172 static inline int
00173 pop (x)
00174      int x;
00175 {
00176   /* We assume that no more than 16 bits are used.  */
00177   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
00178   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
00179   x = ((x >> 4) + x) & 0x0f0f;
00180   x = ((x >> 8) + x) & 0xff;
00181 
00182   return x;
00183 }
00184 
00185 
00186 struct loaded_l10nfile *
00187 _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
00188                   territory, codeset, normalized_codeset, modifier, special,
00189                   sponsor, revision, filename, do_allocate)
00190      struct loaded_l10nfile **l10nfile_list;
00191      const char *dirlist;
00192      size_t dirlist_len;
00193      int mask;
00194      const char *language;
00195      const char *territory;
00196      const char *codeset;
00197      const char *normalized_codeset;
00198      const char *modifier;
00199      const char *special;
00200      const char *sponsor;
00201      const char *revision;
00202      const char *filename;
00203      int do_allocate;
00204 {
00205   char *abs_filename;
00206   struct loaded_l10nfile **lastp;
00207   struct loaded_l10nfile *retval;
00208   char *cp;
00209   size_t dirlist_count;
00210   size_t entries;
00211   int cnt;
00212 
00213   /* If LANGUAGE contains an absolute directory specification, we ignore
00214      DIRLIST.  */
00215   if (IS_ABSOLUTE_PATH (language))
00216     dirlist_len = 0;
00217 
00218   /* Allocate room for the full file name.  */
00219   abs_filename = (char *) malloc (dirlist_len
00220                               + strlen (language)
00221                               + ((mask & TERRITORY) != 0
00222                                  ? strlen (territory) + 1 : 0)
00223                               + ((mask & XPG_CODESET) != 0
00224                                  ? strlen (codeset) + 1 : 0)
00225                               + ((mask & XPG_NORM_CODESET) != 0
00226                                  ? strlen (normalized_codeset) + 1 : 0)
00227                               + (((mask & XPG_MODIFIER) != 0
00228                                   || (mask & CEN_AUDIENCE) != 0)
00229                                  ? strlen (modifier) + 1 : 0)
00230                               + ((mask & CEN_SPECIAL) != 0
00231                                  ? strlen (special) + 1 : 0)
00232                               + (((mask & CEN_SPONSOR) != 0
00233                                   || (mask & CEN_REVISION) != 0)
00234                                  ? (1 + ((mask & CEN_SPONSOR) != 0
00235                                         ? strlen (sponsor) : 0)
00236                                    + ((mask & CEN_REVISION) != 0
00237                                       ? strlen (revision) + 1 : 0)) : 0)
00238                               + 1 + strlen (filename) + 1);
00239 
00240   if (abs_filename == NULL)
00241     return NULL;
00242 
00243   /* Construct file name.  */
00244   cp = abs_filename;
00245   if (dirlist_len > 0)
00246     {
00247       memcpy (cp, dirlist, dirlist_len);
00248       __argz_stringify (cp, dirlist_len, PATH_SEPARATOR);
00249       cp += dirlist_len;
00250       cp[-1] = '/';
00251     }
00252 
00253   cp = stpcpy (cp, language);
00254 
00255   if ((mask & TERRITORY) != 0)
00256     {
00257       *cp++ = '_';
00258       cp = stpcpy (cp, territory);
00259     }
00260   if ((mask & XPG_CODESET) != 0)
00261     {
00262       *cp++ = '.';
00263       cp = stpcpy (cp, codeset);
00264     }
00265   if ((mask & XPG_NORM_CODESET) != 0)
00266     {
00267       *cp++ = '.';
00268       cp = stpcpy (cp, normalized_codeset);
00269     }
00270   if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
00271     {
00272       /* This component can be part of both syntaces but has different
00273         leading characters.  For CEN we use `+', else `@'.  */
00274       *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
00275       cp = stpcpy (cp, modifier);
00276     }
00277   if ((mask & CEN_SPECIAL) != 0)
00278     {
00279       *cp++ = '+';
00280       cp = stpcpy (cp, special);
00281     }
00282   if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
00283     {
00284       *cp++ = ',';
00285       if ((mask & CEN_SPONSOR) != 0)
00286        cp = stpcpy (cp, sponsor);
00287       if ((mask & CEN_REVISION) != 0)
00288        {
00289          *cp++ = '_';
00290          cp = stpcpy (cp, revision);
00291        }
00292     }
00293 
00294   *cp++ = '/';
00295   stpcpy (cp, filename);
00296 
00297   /* Look in list of already loaded domains whether it is already
00298      available.  */
00299   lastp = l10nfile_list;
00300   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
00301     if (retval->filename != NULL)
00302       {
00303        int compare = strcmp (retval->filename, abs_filename);
00304        if (compare == 0)
00305          /* We found it!  */
00306          break;
00307        if (compare < 0)
00308          {
00309            /* It's not in the list.  */
00310            retval = NULL;
00311            break;
00312          }
00313 
00314        lastp = &retval->next;
00315       }
00316 
00317   if (retval != NULL || do_allocate == 0)
00318     {
00319       free (abs_filename);
00320       return retval;
00321     }
00322 
00323   dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1);
00324 
00325   /* Allocate a new loaded_l10nfile.  */
00326   retval =
00327     (struct loaded_l10nfile *)
00328     malloc (sizeof (*retval)
00329            + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0))
00330               * sizeof (struct loaded_l10nfile *)));
00331   if (retval == NULL)
00332     return NULL;
00333 
00334   retval->filename = abs_filename;
00335 
00336   /* We set retval->data to NULL here; it is filled in later.
00337      Setting retval->decided to 1 here means that retval does not
00338      correspond to a real file (dirlist_count > 1) or is not worth
00339      looking up (if an unnormalized codeset was specified).  */
00340   retval->decided = (dirlist_count > 1
00341                    || ((mask & XPG_CODESET) != 0
00342                       && (mask & XPG_NORM_CODESET) != 0));
00343   retval->data = NULL;
00344 
00345   retval->next = *lastp;
00346   *lastp = retval;
00347 
00348   entries = 0;
00349   /* Recurse to fill the inheritance list of RETVAL.
00350      If the DIRLIST is a real list (i.e. DIRLIST_COUNT > 1), the RETVAL
00351      entry does not correspond to a real file; retval->filename contains
00352      colons.  In this case we loop across all elements of DIRLIST and
00353      across all bit patterns dominated by MASK.
00354      If the DIRLIST is a single directory or entirely redundant (i.e.
00355      DIRLIST_COUNT == 1), we loop across all bit patterns dominated by
00356      MASK, excluding MASK itself.
00357      In either case, we loop down from MASK to 0.  This has the effect
00358      that the extra bits in the locale name are dropped in this order:
00359      first the modifier, then the territory, then the codeset, then the
00360      normalized_codeset.  */
00361   for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt)
00362     if ((cnt & ~mask) == 0
00363        && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
00364        && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
00365       {
00366        if (dirlist_count > 1)
00367          {
00368            /* Iterate over all elements of the DIRLIST.  */
00369            char *dir = NULL;
00370 
00371            while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
00372                  != NULL)
00373              retval->successor[entries++]
00374               = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1,
00375                                   cnt, language, territory, codeset,
00376                                   normalized_codeset, modifier, special,
00377                                   sponsor, revision, filename, 1);
00378          }
00379        else
00380          retval->successor[entries++]
00381            = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len,
00382                               cnt, language, territory, codeset,
00383                               normalized_codeset, modifier, special,
00384                               sponsor, revision, filename, 1);
00385       }
00386   retval->successor[entries] = NULL;
00387 
00388   return retval;
00389 }
00390 
00391 /* Normalize codeset name.  There is no standard for the codeset
00392    names.  Normalization allows the user to use any of the common
00393    names.  The return value is dynamically allocated and has to be
00394    freed by the caller.  */
00395 const char *
00396 _nl_normalize_codeset (codeset, name_len)
00397      const char *codeset;
00398      size_t name_len;
00399 {
00400   int len = 0;
00401   int only_digit = 1;
00402   char *retval;
00403   char *wp;
00404   size_t cnt;
00405 
00406   for (cnt = 0; cnt < name_len; ++cnt)
00407     if (isalnum ((unsigned char) codeset[cnt]))
00408       {
00409        ++len;
00410 
00411        if (isalpha ((unsigned char) codeset[cnt]))
00412          only_digit = 0;
00413       }
00414 
00415   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
00416 
00417   if (retval != NULL)
00418     {
00419       if (only_digit)
00420        wp = stpcpy (retval, "iso");
00421       else
00422        wp = retval;
00423 
00424       for (cnt = 0; cnt < name_len; ++cnt)
00425        if (isalpha ((unsigned char) codeset[cnt]))
00426          *wp++ = tolower ((unsigned char) codeset[cnt]);
00427        else if (isdigit ((unsigned char) codeset[cnt]))
00428          *wp++ = codeset[cnt];
00429 
00430       *wp = '\0';
00431     }
00432 
00433   return (const char *) retval;
00434 }
00435 
00436 
00437 /* @@ begin of epilog @@ */
00438 
00439 /* We don't want libintl.a to depend on any other library.  So we
00440    avoid the non-standard function stpcpy.  In GNU C Library this
00441    function is available, though.  Also allow the symbol HAVE_STPCPY
00442    to be defined.  */
00443 #if !_LIBC && !HAVE_STPCPY
00444 static char *
00445 stpcpy (dest, src)
00446      char *dest;
00447      const char *src;
00448 {
00449   while ((*dest++ = *src++) != '\0')
00450     /* Do nothing. */ ;
00451   return dest - 1;
00452 }
00453 #endif