Back to index

tetex-bin  3.0
l10nflist.c
Go to the documentation of this file.
00001 /* Copyright (C) 1995-1999, 2000-2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
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 (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
00088 argz_count__ (const char *argz, size_t len)
00089 {
00090   size_t count = 0;
00091   while (len > 0)
00092     {
00093       size_t part_len = strlen (argz);
00094       argz += part_len + 1;
00095       len -= part_len + 1;
00096       count++;
00097     }
00098   return count;
00099 }
00100 # undef __argz_count
00101 # define __argz_count(argz, len) argz_count__ (argz, len)
00102 #else
00103 # ifdef _LIBC
00104 #  define __argz_count(argz, len) INTUSE(__argz_count) (argz, len)
00105 # endif
00106 #endif /* !_LIBC && !HAVE___ARGZ_COUNT */
00107 
00108 #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
00109 /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
00110    except the last into the character SEP.  */
00111 static void
00112 argz_stringify__ (char *argz, size_t len, int sep)
00113 {
00114   while (len > 0)
00115     {
00116       size_t part_len = strlen (argz);
00117       argz += part_len;
00118       len -= part_len + 1;
00119       if (len > 0)
00120        *argz++ = sep;
00121     }
00122 }
00123 # undef __argz_stringify
00124 # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
00125 #else
00126 # ifdef _LIBC
00127 #  define __argz_stringify(argz, len, sep) \
00128   INTUSE(__argz_stringify) (argz, len, sep)
00129 # endif
00130 #endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
00131 
00132 #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
00133 static char *
00134 argz_next__ (char *argz, size_t argz_len, const char *entry)
00135 {
00136   if (entry)
00137     {
00138       if (entry < argz + argz_len)
00139         entry = strchr (entry, '\0') + 1;
00140 
00141       return entry >= argz + argz_len ? NULL : (char *) entry;
00142     }
00143   else
00144     if (argz_len > 0)
00145       return argz;
00146     else
00147       return 0;
00148 }
00149 # undef __argz_next
00150 # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
00151 #endif /* !_LIBC && !HAVE___ARGZ_NEXT */
00152 
00153 
00154 /* Return number of bits set in X.  */
00155 static inline int
00156 pop (int x)
00157 {
00158   /* We assume that no more than 16 bits are used.  */
00159   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
00160   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
00161   x = ((x >> 4) + x) & 0x0f0f;
00162   x = ((x >> 8) + x) & 0xff;
00163 
00164   return x;
00165 }
00166 
00167 
00168 struct loaded_l10nfile *
00169 _nl_make_l10nflist (struct loaded_l10nfile **l10nfile_list,
00170                   const char *dirlist, size_t dirlist_len,
00171                   int mask, const char *language, const char *territory,
00172                   const char *codeset, const char *normalized_codeset,
00173                   const char *modifier, const char *special,
00174                   const char *sponsor, const char *revision,
00175                   const char *filename, int do_allocate)
00176 {
00177   char *abs_filename;
00178   struct loaded_l10nfile **lastp;
00179   struct loaded_l10nfile *retval;
00180   char *cp;
00181   size_t dirlist_count;
00182   size_t entries;
00183   int cnt;
00184 
00185   /* If LANGUAGE contains an absolute directory specification, we ignore
00186      DIRLIST.  */
00187   if (IS_ABSOLUTE_PATH (language))
00188     dirlist_len = 0;
00189 
00190   /* Allocate room for the full file name.  */
00191   abs_filename = (char *) malloc (dirlist_len
00192                               + strlen (language)
00193                               + ((mask & TERRITORY) != 0
00194                                  ? strlen (territory) + 1 : 0)
00195                               + ((mask & XPG_CODESET) != 0
00196                                  ? strlen (codeset) + 1 : 0)
00197                               + ((mask & XPG_NORM_CODESET) != 0
00198                                  ? strlen (normalized_codeset) + 1 : 0)
00199                               + (((mask & XPG_MODIFIER) != 0
00200                                   || (mask & CEN_AUDIENCE) != 0)
00201                                  ? strlen (modifier) + 1 : 0)
00202                               + ((mask & CEN_SPECIAL) != 0
00203                                  ? strlen (special) + 1 : 0)
00204                               + (((mask & CEN_SPONSOR) != 0
00205                                   || (mask & CEN_REVISION) != 0)
00206                                  ? (1 + ((mask & CEN_SPONSOR) != 0
00207                                         ? strlen (sponsor) : 0)
00208                                    + ((mask & CEN_REVISION) != 0
00209                                       ? strlen (revision) + 1 : 0)) : 0)
00210                               + 1 + strlen (filename) + 1);
00211 
00212   if (abs_filename == NULL)
00213     return NULL;
00214 
00215   /* Construct file name.  */
00216   cp = abs_filename;
00217   if (dirlist_len > 0)
00218     {
00219       memcpy (cp, dirlist, dirlist_len);
00220       __argz_stringify (cp, dirlist_len, PATH_SEPARATOR);
00221       cp += dirlist_len;
00222       cp[-1] = '/';
00223     }
00224 
00225   cp = stpcpy (cp, language);
00226 
00227   if ((mask & TERRITORY) != 0)
00228     {
00229       *cp++ = '_';
00230       cp = stpcpy (cp, territory);
00231     }
00232   if ((mask & XPG_CODESET) != 0)
00233     {
00234       *cp++ = '.';
00235       cp = stpcpy (cp, codeset);
00236     }
00237   if ((mask & XPG_NORM_CODESET) != 0)
00238     {
00239       *cp++ = '.';
00240       cp = stpcpy (cp, normalized_codeset);
00241     }
00242   if ((mask & (XPG_MODIFIER | CEN_AUDIENCE)) != 0)
00243     {
00244       /* This component can be part of both syntaces but has different
00245         leading characters.  For CEN we use `+', else `@'.  */
00246       *cp++ = (mask & CEN_AUDIENCE) != 0 ? '+' : '@';
00247       cp = stpcpy (cp, modifier);
00248     }
00249   if ((mask & CEN_SPECIAL) != 0)
00250     {
00251       *cp++ = '+';
00252       cp = stpcpy (cp, special);
00253     }
00254   if ((mask & (CEN_SPONSOR | CEN_REVISION)) != 0)
00255     {
00256       *cp++ = ',';
00257       if ((mask & CEN_SPONSOR) != 0)
00258        cp = stpcpy (cp, sponsor);
00259       if ((mask & CEN_REVISION) != 0)
00260        {
00261          *cp++ = '_';
00262          cp = stpcpy (cp, revision);
00263        }
00264     }
00265 
00266   *cp++ = '/';
00267   stpcpy (cp, filename);
00268 
00269   /* Look in list of already loaded domains whether it is already
00270      available.  */
00271   lastp = l10nfile_list;
00272   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
00273     if (retval->filename != NULL)
00274       {
00275        int compare = strcmp (retval->filename, abs_filename);
00276        if (compare == 0)
00277          /* We found it!  */
00278          break;
00279        if (compare < 0)
00280          {
00281            /* It's not in the list.  */
00282            retval = NULL;
00283            break;
00284          }
00285 
00286        lastp = &retval->next;
00287       }
00288 
00289   if (retval != NULL || do_allocate == 0)
00290     {
00291       free (abs_filename);
00292       return retval;
00293     }
00294 
00295   dirlist_count = (dirlist_len > 0 ? __argz_count (dirlist, dirlist_len) : 1);
00296 
00297   /* Allocate a new loaded_l10nfile.  */
00298   retval =
00299     (struct loaded_l10nfile *)
00300     malloc (sizeof (*retval)
00301            + (((dirlist_count << pop (mask)) + (dirlist_count > 1 ? 1 : 0))
00302               * sizeof (struct loaded_l10nfile *)));
00303   if (retval == NULL)
00304     return NULL;
00305 
00306   retval->filename = abs_filename;
00307 
00308   /* We set retval->data to NULL here; it is filled in later.
00309      Setting retval->decided to 1 here means that retval does not
00310      correspond to a real file (dirlist_count > 1) or is not worth
00311      looking up (if an unnormalized codeset was specified).  */
00312   retval->decided = (dirlist_count > 1
00313                    || ((mask & XPG_CODESET) != 0
00314                       && (mask & XPG_NORM_CODESET) != 0));
00315   retval->data = NULL;
00316 
00317   retval->next = *lastp;
00318   *lastp = retval;
00319 
00320   entries = 0;
00321   /* Recurse to fill the inheritance list of RETVAL.
00322      If the DIRLIST is a real list (i.e. DIRLIST_COUNT > 1), the RETVAL
00323      entry does not correspond to a real file; retval->filename contains
00324      colons.  In this case we loop across all elements of DIRLIST and
00325      across all bit patterns dominated by MASK.
00326      If the DIRLIST is a single directory or entirely redundant (i.e.
00327      DIRLIST_COUNT == 1), we loop across all bit patterns dominated by
00328      MASK, excluding MASK itself.
00329      In either case, we loop down from MASK to 0.  This has the effect
00330      that the extra bits in the locale name are dropped in this order:
00331      first the modifier, then the territory, then the codeset, then the
00332      normalized_codeset.  */
00333   for (cnt = dirlist_count > 1 ? mask : mask - 1; cnt >= 0; --cnt)
00334     if ((cnt & ~mask) == 0
00335        && ((cnt & CEN_SPECIFIC) == 0 || (cnt & XPG_SPECIFIC) == 0)
00336        && ((cnt & XPG_CODESET) == 0 || (cnt & XPG_NORM_CODESET) == 0))
00337       {
00338        if (dirlist_count > 1)
00339          {
00340            /* Iterate over all elements of the DIRLIST.  */
00341            char *dir = NULL;
00342 
00343            while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
00344                  != NULL)
00345              retval->successor[entries++]
00346               = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1,
00347                                   cnt, language, territory, codeset,
00348                                   normalized_codeset, modifier, special,
00349                                   sponsor, revision, filename, 1);
00350          }
00351        else
00352          retval->successor[entries++]
00353            = _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len,
00354                               cnt, language, territory, codeset,
00355                               normalized_codeset, modifier, special,
00356                               sponsor, revision, filename, 1);
00357       }
00358   retval->successor[entries] = NULL;
00359 
00360   return retval;
00361 }
00362 
00363 /* Normalize codeset name.  There is no standard for the codeset
00364    names.  Normalization allows the user to use any of the common
00365    names.  The return value is dynamically allocated and has to be
00366    freed by the caller.  */
00367 const char *
00368 _nl_normalize_codeset (const char *codeset, size_t name_len)
00369 {
00370   int len = 0;
00371   int only_digit = 1;
00372   char *retval;
00373   char *wp;
00374   size_t cnt;
00375 
00376   for (cnt = 0; cnt < name_len; ++cnt)
00377     if (isalnum ((unsigned char) codeset[cnt]))
00378       {
00379        ++len;
00380 
00381        if (isalpha ((unsigned char) codeset[cnt]))
00382          only_digit = 0;
00383       }
00384 
00385   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
00386 
00387   if (retval != NULL)
00388     {
00389       if (only_digit)
00390        wp = stpcpy (retval, "iso");
00391       else
00392        wp = retval;
00393 
00394       for (cnt = 0; cnt < name_len; ++cnt)
00395        if (isalpha ((unsigned char) codeset[cnt]))
00396          *wp++ = tolower ((unsigned char) codeset[cnt]);
00397        else if (isdigit ((unsigned char) codeset[cnt]))
00398          *wp++ = codeset[cnt];
00399 
00400       *wp = '\0';
00401     }
00402 
00403   return (const char *) retval;
00404 }
00405 
00406 
00407 /* @@ begin of epilog @@ */
00408 
00409 /* We don't want libintl.a to depend on any other library.  So we
00410    avoid the non-standard function stpcpy.  In GNU C Library this
00411    function is available, though.  Also allow the symbol HAVE_STPCPY
00412    to be defined.  */
00413 #if !_LIBC && !HAVE_STPCPY
00414 static char *
00415 stpcpy (char *dest, const char *src)
00416 {
00417   while ((*dest++ = *src++) != '\0')
00418     /* Do nothing. */ ;
00419   return dest - 1;
00420 }
00421 #endif