(linenum→info "unix/slp.c:2238")

glibc/2.7/intl/l10nflist.c

    1: /* Copyright (C) 1995-2002, 2004, 2005 Free Software Foundation, Inc.
    2:    This file is part of the GNU C Library.
    3:    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
    4: 
    5:    The GNU C Library is free software; you can redistribute it and/or
    6:    modify it under the terms of the GNU Lesser General Public
    7:    License as published by the Free Software Foundation; either
    8:    version 2.1 of the License, or (at your option) any later version.
    9: 
   10:    The GNU C Library is distributed in the hope that it will be useful,
   11:    but WITHOUT ANY WARRANTY; without even the implied warranty of
   12:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   13:    Lesser General Public License for more details.
   14: 
   15:    You should have received a copy of the GNU Lesser General Public
   16:    License along with the GNU C Library; if not, write to the Free
   17:    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
   18:    02111-1307 USA.  */
   19: 
   20: /* Tell glibc's <string.h> to provide a prototype for stpcpy().
   21:    This must come before <config.h> because <config.h> may include
   22:    <features.h>, and once <features.h> has been included, it's too late.  */
   23: #ifndef _GNU_SOURCE
   24: # define _GNU_SOURCE    1
   25: #endif
   26: 
   27: #ifdef HAVE_CONFIG_H
   28: # include <config.h>
   29: #endif
   30: 
   31: #include <string.h>
   32: 
   33: #if defined _LIBC || defined HAVE_ARGZ_H
   34: # include <argz.h>
   35: #endif
   36: #include <ctype.h>
   37: #include <sys/types.h>
   38: #include <stdlib.h>
   39: 
   40: #include "loadinfo.h"
   41: 
   42: /* On some strange systems still no definition of NULL is found.  Sigh!  */
   43: #ifndef NULL
   44: # if defined __STDC__ && __STDC__
   45: #  define NULL ((void *) 0)
   46: # else
   47: #  define NULL 0
   48: # endif
   49: #endif
   50: 
   51: /* @@ end of prolog @@ */
   52: 
   53: #ifdef _LIBC
   54: /* Rename the non ANSI C functions.  This is required by the standard
   55:    because some ANSI C functions will require linking with this object
   56:    file and the name space must not be polluted.  */
   57: # ifndef stpcpy
   58: #  define stpcpy(dest, src) __stpcpy(dest, src)
   59: # endif
   60: #else
   61: # ifndef HAVE_STPCPY
   62: static char *stpcpy PARAMS ((char *dest, const char *src));
   63: # endif
   64: #endif
   65: 
   66: /* Define function which are usually not available.  */
   67: 
   68: #if !defined _LIBC && !defined HAVE___ARGZ_COUNT
   69: /* Returns the number of strings in ARGZ.  */
   70: static size_t argz_count__ PARAMS ((const char *argz, size_t len));
   71: 
   72: static size_t
   73: argz_count__ (argz, len)
   74:      const char *argz;
   75:      size_t len;
   76: {
   77:   size_t count = 0;
   78:   while (len > 0)
   79:     {
   80:       size_t part_len = strlen (argz);
   81:       argz += part_len + 1;
   82:       len -= part_len + 1;
   83:       count++;
   84:     }
   85:   return count;
   86: }
   87: # undef __argz_count
   88: # define __argz_count(argz, len) argz_count__ (argz, len)
   89: #else
   90: # ifdef _LIBC
   91: #  define __argz_count(argz, len) INTUSE(__argz_count) (argz, len)
   92: # endif
   93: #endif  /* !_LIBC && !HAVE___ARGZ_COUNT */
   94: 
   95: #if !defined _LIBC && !defined HAVE___ARGZ_STRINGIFY
   96: /* Make '\0' separated arg vector ARGZ printable by converting all the '\0's
   97:    except the last into the character SEP.  */
   98: static void argz_stringify__ PARAMS ((char *argz, size_t len, int sep));
   99: 
  100: static void
  101: argz_stringify__ (argz, len, sep)
  102:      char *argz;
  103:      size_t len;
  104:      int sep;
  105: {
  106:   while (len > 0)
  107:     {
  108:       size_t part_len = strlen (argz);
  109:       argz += part_len;
  110:       len -= part_len + 1;
  111:       if (len > 0)
  112:         *argz++ = sep;
  113:     }
  114: }
  115: # undef __argz_stringify
  116: # define __argz_stringify(argz, len, sep) argz_stringify__ (argz, len, sep)
  117: #else
  118: # ifdef _LIBC
  119: #  define __argz_stringify(argz, len, sep) \
  120:   INTUSE(__argz_stringify) (argz, len, sep)
  121: # endif
  122: #endif  /* !_LIBC && !HAVE___ARGZ_STRINGIFY */
  123: 
  124: #if !defined _LIBC && !defined HAVE___ARGZ_NEXT
  125: static char *argz_next__ PARAMS ((char *argz, size_t argz_len,
  126:                                   const char *entry));
  127: 
  128: static char *
  129: argz_next__ (argz, argz_len, entry)
  130:      char *argz;
  131:      size_t argz_len;
  132:      const char *entry;
  133: {
  134:   if (entry)
  135:     {
  136:       if (entry < argz + argz_len)
  137:         entry = strchr (entry, '\0') + 1;
  138: 
  139:       return entry >= argz + argz_len ? NULL : (char *) entry;
  140:     }
  141:   else
  142:     if (argz_len > 0)
  143:       return argz;
  144:     else
  145:       return 0;
  146: }
  147: # undef __argz_next
  148: # define __argz_next(argz, len, entry) argz_next__ (argz, len, entry)
  149: #endif  /* !_LIBC && !HAVE___ARGZ_NEXT */
  150: 
  151: 
  152: /* Return number of bits set in X.  */
  153: static int pop PARAMS ((int x));
  154: 
  155: static inline int
  156: pop (x)
  157:      int x;
  158: {
  159:   /* We assume that no more than 16 bits are used.  */
  160:   x = ((x & ~0x5555) >> 1) + (x & 0x5555);
  161:   x = ((x & ~0x3333) >> 2) + (x & 0x3333);
  162:   x = ((x >> 4) + x) & 0x0f0f;
  163:   x = ((x >> 8) + x) & 0xff;
  164: 
  165:   return x;
  166: }
  167: 
  168: ^L
  169: struct loaded_l10nfile *
  170: _nl_make_l10nflist (l10nfile_list, dirlist, dirlist_len, mask, language,
  171:                     territory, codeset, normalized_codeset, modifier,
  172:                     filename, do_allocate)
  173:      struct loaded_l10nfile **l10nfile_list;
  174:      const char *dirlist;
  175:      size_t dirlist_len;
  176:      int mask;
  177:      const char *language;
  178:      const char *territory;
  179:      const char *codeset;
  180:      const char *normalized_codeset;
  181:      const char *modifier;
  182:      const char *filename;
  183:      int do_allocate;
  184: {
  185:   char *abs_filename;
  186:   struct loaded_l10nfile *last = NULL;
  187:   struct loaded_l10nfile *retval;
  188:   char *cp;
  189:   size_t entries;
  190:   int cnt;
  191: 
  192:   /* Allocate room for the full file name.  */
  193:   abs_filename = (char *) malloc (dirlist_len
  194:                                   + strlen (language)
  195:                                   + ((mask & XPG_TERRITORY) != 0
  196:                                      ? strlen (territory) + 1 : 0)
  197:                                   + ((mask & XPG_CODESET) != 0
  198:                                      ? strlen (codeset) + 1 : 0)
  199:                                   + ((mask & XPG_NORM_CODESET) != 0
  200:                                      ? strlen (normalized_codeset) + 1 : 0)
  201:                                   + ((mask & XPG_MODIFIER) != 0
  202:                                      ? strlen (modifier) + 1 : 0)
  203:                                   + 1 + strlen (filename) + 1);
  204: 
  205:   if (abs_filename == NULL)
  206:     return NULL;
  207: 
  208:   retval = NULL;
  209:   last = NULL;
  210: 
  211:   /* Construct file name.  */
  212:   memcpy (abs_filename, dirlist, dirlist_len);
  213:   __argz_stringify (abs_filename, dirlist_len, ':');
  214:   cp = abs_filename + (dirlist_len - 1);
  215:   *cp++ = '/';
  216:   cp = stpcpy (cp, language);
  217: 
  218:   if ((mask & XPG_TERRITORY) != 0)
  219:     {
  220:       *cp++ = '_';
  221:       cp = stpcpy (cp, territory);
  222:     }
  223:   if ((mask & XPG_CODESET) != 0)
  224:     {
  225:       *cp++ = '.';
  226:       cp = stpcpy (cp, codeset);
  227:     }
  228:   if ((mask & XPG_NORM_CODESET) != 0)
  229:     {
  230:       *cp++ = '.';
  231:       cp = stpcpy (cp, normalized_codeset);
  232:     }
  233:   if ((mask & XPG_MODIFIER) != 0)
  234:     {
  235:       *cp++ = '@';
  236:       cp = stpcpy (cp, modifier);
  237:     }
  238: 
  239:   *cp++ = '/';
  240:   stpcpy (cp, filename);
  241: 
  242:   /* Look in list of already loaded domains whether it is already
  243:      available.  */
  244:   last = NULL;
  245:   for (retval = *l10nfile_list; retval != NULL; retval = retval->next)
  246:     if (retval->filename != NULL)
  247:       {
  248:         int compare = strcmp (retval->filename, abs_filename);
  249:         if (compare == 0)
  250:           /* We found it!  */
  251:           break;
  252:         if (compare < 0)
  253:           {
  254:             /* It's not in the list.  */
  255:             retval = NULL;
  256:             break;
  257:           }
  258: 
  259:         last = retval;
  260:       }
  261: 
  262:   if (retval != NULL || do_allocate == 0)
  263:     {
  264:       free (abs_filename);
  265:       return retval;
  266:     }
  267: 
  268:   retval = (struct loaded_l10nfile *)
  269:     malloc (sizeof (*retval) + (__argz_count (dirlist, dirlist_len)
  270:                                 * (1 << pop (mask))
  271:                                 * sizeof (struct loaded_l10nfile *)));
  272:   if (retval == NULL)
  273:     {
  274:       free (abs_filename);
  275:       return NULL;
  276:     }
  277: 
  278:   retval->filename = abs_filename;
  279:   /* If more than one directory is in the list this is a pseudo-entry
  280:      which just references others.  We do not try to load data for it,
  281:      ever.  */
  282:   retval->decided = (__argz_count (dirlist, dirlist_len) != 1
  283:                      || ((mask & XPG_CODESET) != 0
  284:                          && (mask & XPG_NORM_CODESET) != 0));
  285:   retval->data = NULL;
  286: 
  287:   if (last == NULL)
  288:     {
  289:       retval->next = *l10nfile_list;
  290:       *l10nfile_list = retval;
  291:     }
  292:   else
  293:     {
  294:       retval->next = last->next;
  295:       last->next = retval;
  296:     }
  297: 
  298:   entries = 0;
  299:   /* If the DIRLIST is a real list the RETVAL entry corresponds not to
  300:      a real file.  So we have to use the DIRLIST separation mechanism
  301:      of the inner loop.  */
  302:   cnt = __argz_count (dirlist, dirlist_len) == 1 ? mask - 1 : mask;
  303:   for (; cnt >= 0; --cnt)
  304:     if ((cnt & ~mask) == 0)
  305:       {
  306:         /* Iterate over all elements of the DIRLIST.  */
  307:         char *dir = NULL;
  308: 
  309:         while ((dir = __argz_next ((char *) dirlist, dirlist_len, dir))
  310:                != NULL)
  311:           retval->successor[entries++]
  312:             = _nl_make_l10nflist (l10nfile_list, dir, strlen (dir) + 1, cnt,
  313:                                   language, territory, codeset,
  314:                                   normalized_codeset, modifier, filename, 1);
  315:       }
  316:   retval->successor[entries] = NULL;
  317: 
  318:   return retval;
  319: }
  320: ^L
  321: /* Normalize codeset name.  There is no standard for the codeset
  322:    names.  Normalization allows the user to use any of the common
  323:    names.  The return value is dynamically allocated and has to be
  324:    freed by the caller.  */
  325: const char *
  326: _nl_normalize_codeset (codeset, name_len)
  327:      const char *codeset;
  328:      size_t name_len;
  329: {
  330:   int len = 0;
  331:   int only_digit = 1;
  332:   char *retval;
  333:   char *wp;
  334:   size_t cnt;
  335: 
  336:   for (cnt = 0; cnt < name_len; ++cnt)
  337:     if (isalnum ((unsigned char) codeset[cnt]))
  338:       {
  339:         ++len;
  340: 
  341:         if (isalpha ((unsigned char) codeset[cnt]))
  342:           only_digit = 0;
  343:       }
  344: 
  345:   retval = (char *) malloc ((only_digit ? 3 : 0) + len + 1);
  346: 
  347:   if (retval != NULL)
  348:     {
  349:       if (only_digit)
  350:         wp = stpcpy (retval, "iso");
  351:       else
  352:         wp = retval;
  353: 
  354:       for (cnt = 0; cnt < name_len; ++cnt)
  355:         if (isalpha ((unsigned char) codeset[cnt]))
  356:           *wp++ = tolower ((unsigned char) codeset[cnt]);
  357:         else if (isdigit ((unsigned char) codeset[cnt]))
  358:           *wp++ = codeset[cnt];
  359: 
  360:       *wp = '\0';
  361:     }
  362: 
  363:   return (const char *) retval;
  364: }
  365: 
  366: 
  367: /* @@ begin of epilog @@ */
  368: 
  369: /* We don't want libintl.a to depend on any other library.  So we
  370:    avoid the non-standard function stpcpy.  In GNU C Library this
  371:    function is available, though.  Also allow the symbol HAVE_STPCPY
  372:    to be defined.  */
  373: #if !_LIBC && !HAVE_STPCPY
  374: static char *
  375: stpcpy (dest, src)
  376:      char *dest;
  377:      const char *src;
  378: {
  379:   while ((*dest++ = *src++) != '\0')
  380:     /* Do nothing. */ ;
  381:   return dest - 1;
  382: }
  383: #endif
Syntax (Markdown)