Back to index

glibc  2.9
l10nflist.c
Go to the documentation of this file.
00001 /* Copyright (C) 1995-2002, 2004, 2005 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 /* Tell glibc's <string.h> to provide a prototype for stpcpy().
00021    This must come before <config.h> because <config.h> may include
00022    <features.h>, and once <features.h> has been included, it's too late.  */
00023 #ifndef _GNU_SOURCE
00024 # define _GNU_SOURCE 1
00025 #endif
00026 
00027 #ifdef HAVE_CONFIG_H
00028 # include <config.h>
00029 #endif
00030 
00031 #include <string.h>
00032 
00033 #if defined _LIBC || defined HAVE_ARGZ_H
00034 # include <argz.h>
00035 #endif
00036 #include <ctype.h>
00037 #include <sys/types.h>
00038 #include <stdlib.h>
00039 
00040 #include "loadinfo.h"
00041 
00042 /* On some strange systems still no definition of NULL is found.  Sigh!  */
00043 #ifndef NULL
00044 # if defined __STDC__ && __STDC__
00045 #  define NULL ((void *) 0)
00046 # else
00047 #  define NULL 0
00048 # endif
00049 #endif
00050 
00051 /* @@ end of prolog @@ */
00052 
00053 #ifdef _LIBC
00054 /* Rename the non ANSI C functions.  This is required by the standard
00055    because some ANSI C functions will require linking with this object
00056    file and the name space must not be polluted.  */
00057 # ifndef stpcpy
00058 #  define stpcpy(dest, src) __stpcpy(dest, src)
00059 # endif
00060 #else
00061 # ifndef HAVE_STPCPY
00062 static char *stpcpy PARAMS ((char *dest, const char *src));
00063 # endif
00064 #endif
00065 
00066 /* Define function which are usually not available.  */
00067 
00068 #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
00069 /* Returns the number of strings in ARGZ.  */
00070 static size_t argz_count__ PARAMS ((const char *argz, size_t len));
00071 
00072 static size_t
00073 argz_count__ (argz, len)
00074      const char *argz;
00075      size_t len;
00076 {
00077   size_t count = 0;
00078   while (len > 0)
00079     {
00080       size_t part_len = strlen (argz);
00081       argz += part_len + 1;
00082       len -= part_len + 1;
00083       count++;
00084     }
00085   return count;
00086 }
00087 # undef __argz_count
00088 # define __argz_count(argz, len) argz_count__ (argz, len)
00089 #else
00090 # ifdef _LIBC
00091 #  define __argz_count(argz, len) INTUSE(__argz_count) (argz, len)
00092 # endif
00093 #endif /* !_LIBC && !HAVE___ARGZ_COUNT */
00094 
00095 #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
00096 /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
00097    except the last into the character SEP.  */
00098 static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
00099 
00100 static void
00101 argz_stringify__ (argz, len, sep)
00102      char *argz;
00103      size_t len;
00104      int sep;
00105 {
00106   while (len > 0)
00107     {
00108       size_t part_len = strlen (argz);
00109       argz += part_len;
00110       len -= part_len + 1;
00111       if (len > 0)
00112        *argz++ = sep;
00113     }
00114 }
00115 # undef __argz_stringify
00116 # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
00117 #else
00118 # ifdef _LIBC
00119 #  define __argz_stringify(argz, len, sep) \
00120   INTUSE(__argz_stringify) (argz, len, sep)
00121 # endif
00122 #endif /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
00123 
00124 #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
00125 static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
00126                               const char *entry));
00127 
00128 static char *
00129 argz_next__ (argz, argz_len, entry)
00130      char *argz;
00131      size_t argz_len;
00132      const char *entry;
00133 {
00134   if (entry)
00135     {
00136       if (entry < argz + argz_len)
00137         entry = strchr (entry, '\0') + 1;
00138 
00139       return entry >= argz + argz_len ? NULL : (char *) entry;
00140     }
00141   else
00142     if (argz_len > 0)
00143       return argz;
00144     else
00145       return 0;
00146 }
00147 # undef __argz_next
00148 # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
00149 #endif /* !_LIBC && !HAVE___ARGZ_NEXT */
00150 
00151 
00152 /* Return number of bits set in X.  */
00153 static int pop PARAMS ((int x));
00154 
00155 static inline int
00156 pop (x)
00157      int x;
00158 {
00159   /* We assume that no more than 16 bits are used.  */
00160   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
00161   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
00162   x = ((x >> 4) + x) & 0x0f0f;
00163   x = ((x >> 8) + x) & 0xff;
00164 
00165   return x;
00166 }
00167 
00168 
00169 struct loaded_l10nfile *
00170 _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
00171                   territory, codeset, normalized_codeset, modifier,
00172                   filename, do_allocate)
00173      struct loaded_l10nfile **l10nfile_list;
00174      const char *dirlist;
00175      size_t dirlist_len;
00176      int mask;
00177      const char *language;
00178      const char *territory;
00179      const char *codeset;
00180      const char *normalized_codeset;
00181      const char *modifier;
00182      const char *filename;
00183      int do_allocate;
00184 {
00185   char *abs_filename;
00186   struct loaded_l10nfile *last = NULL;
00187   struct loaded_l10nfile *retval;
00188   char *cp;
00189   size_t entries;
00190   int cnt;
00191 
00192   /* Allocate room for the full file name.  */
00193   abs_filename = (char *) malloc (dirlist_len
00194                               + strlen (language)
00195                               + ((mask & XPG_TERRITORY) != 0
00196                                  ? strlen (territory) + 1 : 0)
00197                               + ((mask & XPG_CODESET) != 0
00198                                  ? strlen (codeset) + 1 : 0)
00199                               + ((mask & XPG_NORM_CODESET) != 0
00200                                  ? strlen (normalized_codeset) + 1 : 0)
00201                               + ((mask & XPG_MODIFIER) != 0
00202                                  ? strlen (modifier) + 1 : 0)
00203                               + 1 + strlen (filename) + 1);
00204 
00205   if (abs_filename == NULL)
00206     return NULL;
00207 
00208   retval = NULL;
00209   last = NULL;
00210 
00211   /* Construct file name.  */
00212   memcpy (abs_filename, dirlist, dirlist_len);
00213   __argz_stringify (abs_filename, dirlist_len, ':');
00214   cp = abs_filename + (dirlist_len - 1);
00215   *cp++ = '/';
00216   cp = stpcpy (cp, language);
00217 
00218   if ((mask & XPG_TERRITORY) != 0)
00219     {
00220       *cp++ = '_';
00221       cp = stpcpy (cp, territory);
00222     }
00223   if ((mask & XPG_CODESET) != 0)
00224     {
00225       *cp++ = '.';
00226       cp = stpcpy (cp, codeset);
00227     }
00228   if ((mask & XPG_NORM_CODESET) != 0)
00229     {
00230       *cp++ = '.';
00231       cp = stpcpy (cp, normalized_codeset);
00232     }
00233   if ((mask & XPG_MODIFIER) != 0)
00234     {
00235       *cp++ = '@';
00236       cp = stpcpy (cp, modifier);
00237     }
00238 
00239   *cp++ = '/';
00240   stpcpy (cp, filename);
00241 
00242   /* Look in list of already loaded domains whether it is already
00243      available.  */
00244   last = NULL;
00245   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
00246     if (retval->filename != NULL)
00247       {
00248        int compare = strcmp (retval->filename, abs_filename);
00249        if (compare == 0)
00250          /* We found it!  */
00251          break;
00252        if (compare < 0)
00253          {
00254            /* It's not in the list.  */
00255            retval = NULL;
00256            break;
00257          }
00258 
00259        last = retval;
00260       }
00261 
00262   if (retval != NULL || do_allocate == 0)
00263     {
00264       free (abs_filename);
00265       return retval;
00266     }
00267 
00268   retval = (struct loaded_l10nfile *)
00269     malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
00270                             * (1 << pop (mask))
00271                             * sizeof (struct loaded_l10nfile *)));
00272   if (retval == NULL)
00273     {
00274       free (abs_filename);
00275       return NULL;
00276     }
00277 
00278   retval->filename = abs_filename;
00279   /* If more than one directory is in the list this is a pseudo-entry
00280      which just references others.  We do not try to load data for it,
00281      ever.  */
00282   retval->decided = (__argz_count (dirlist, dirlist_len) != 1
00283                    || ((mask & XPG_CODESET) != 0
00284                       && (mask & XPG_NORM_CODESET) != 0));
00285   retval->data = NULL;
00286 
00287   if (last == NULL)
00288     {
00289       retval->next = *l10nfile_list;
00290       *l10nfile_list = retval;
00291     }
00292   else
00293     {
00294       retval->next = last->next;
00295       last->next = retval;
00296     }
00297 
00298   entries = 0;
00299   /* If the DIRLIST is a real list the RETVAL entry corresponds not to
00300      a real file.  So we have to use the DIRLIST separation mechanism
00301      of the inner loop.  */
00302   cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
00303   for (; cnt >= 0; --cnt)
00304     if ((cnt & ~mask) == 0)
00305       {
00306        /* Iterate over all elements of the DIRLIST.  */
00307        char *dir = NULL;
00308 
00309        while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
00310               != NULL)
00311          retval->successor[entries++]
00312            = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
00313                               language, territory, codeset,
00314                               normalized_codeset, modifier, filename, 1);
00315       }
00316   retval->successor[entries] = NULL;
00317 
00318   return retval;
00319 }
00320 
00321 /* Normalize codeset name.  There is no standard for the codeset
00322    names.  Normalization allows the user to use any of the common
00323    names.  The return value is dynamically allocated and has to be
00324    freed by the caller.  */
00325 const char *
00326 _nl_normalize_codeset (codeset, name_len)
00327      const char *codeset;
00328      size_t name_len;
00329 {
00330   int len = 0;
00331   int only_digit = 1;
00332   char *retval;
00333   char *wp;
00334   size_t cnt;
00335 
00336   for (cnt = 0; cnt < name_len; ++cnt)
00337     if (isalnum ((unsigned char) codeset[cnt]))
00338       {
00339        ++len;
00340 
00341        if (isalpha ((unsigned char) codeset[cnt]))
00342          only_digit = 0;
00343       }
00344 
00345   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
00346 
00347   if (retval != NULL)
00348     {
00349       if (only_digit)
00350        wp = stpcpy (retval, "iso");
00351       else
00352        wp = retval;
00353 
00354       for (cnt = 0; cnt < name_len; ++cnt)
00355        if (isalpha ((unsigned char) codeset[cnt]))
00356          *wp++ = tolower ((unsigned char) codeset[cnt]);
00357        else if (isdigit ((unsigned char) codeset[cnt]))
00358          *wp++ = codeset[cnt];
00359 
00360       *wp = '\0';
00361     }
00362 
00363   return (const char *) retval;
00364 }
00365 
00366 
00367 /* @@ begin of epilog @@ */
00368 
00369 /* We don't want libintl.a to depend on any other library.  So we
00370    avoid the non-standard function stpcpy.  In GNU C Library this
00371    function is available, though.  Also allow the symbol HAVE_STPCPY
00372    to be defined.  */
00373 #if !_LIBC && !HAVE_STPCPY
00374 static char *
00375 stpcpy (dest, src)
00376      char *dest;
00377      const char *src;
00378 {
00379   while ((*dest++ = *src++) != '\0')
00380     /* Do nothing. */ ;
00381   return dest - 1;
00382 }
00383 #endif