Back to index

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