Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals  

l10nflist.c

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

Generated on Sun Feb 16 23:39:49 2003 for FreeLCD by doxygen1.2.18