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

glibc/2.7/intl/dcigettext.c

    1: /* Implementation of the internal dcigettext function.
    2:    Copyright (C) 1995-2005, 2006, 2007 Free Software Foundation, Inc.
    3:    This file is part of the GNU C Library.
    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 mempcpy().
   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 <sys/types.h>
   32: 
   33: #ifdef __GNUC__
   34: # define alloca __builtin_alloca
   35: # define HAVE_ALLOCA 1
   36: #else
   37: # if defined HAVE_ALLOCA_H || defined _LIBC
   38: #  include <alloca.h>
   39: # else
   40: #  ifdef _AIX
   41:  #pragma alloca
   42: #  else
   43: #   ifndef alloca
   44: char *alloca ();
   45: #   endif
   46: #  endif
   47: # endif
   48: #endif
   49: 
   50: #include <errno.h>
   51: #ifndef errno
   52: extern int errno;
   53: #endif
   54: #ifndef __set_errno
   55: # define __set_errno(val) errno = (val)
   56: #endif
   57: 
   58: #include <stddef.h>
   59: #include <stdlib.h>
   60: #include <string.h>
   61: 
   62: #if defined HAVE_UNISTD_H || defined _LIBC
   63: # include <unistd.h>
   64: #endif
   65: 
   66: #include <locale.h>
   67: 
   68: #if defined HAVE_SYS_PARAM_H || defined _LIBC
   69: # include <sys/param.h>
   70: #endif
   71: 
   72: #include "gettextP.h"
   73: #include "plural-exp.h"
   74: #ifdef _LIBC
   75: # include <libintl.h>
   76: #else
   77: # include "libgnuintl.h"
   78: #endif
   79: #include "hash-string.h"
   80: 
   81: /* Thread safetyness.  */
   82: #ifdef _LIBC
   83: # include <bits/libc-lock.h>
   84: #else
   85: /* Provide dummy implementation if this is outside glibc.  */
   86: # define __libc_lock_define_initialized(CLASS, NAME)
   87: # define __libc_lock_lock(NAME)
   88: # define __libc_lock_unlock(NAME)
   89: # define __libc_rwlock_define_initialized(CLASS, NAME)
   90: # define __libc_rwlock_rdlock(NAME)
   91: # define __libc_rwlock_unlock(NAME)
   92: #endif
   93: 
   94: /* Alignment of types.  */
   95: #if defined __GNUC__ && __GNUC__ >= 2
   96: # define alignof(TYPE) __alignof__ (TYPE)
   97: #else
   98: # define alignof(TYPE) \
   99:     ((int) &((struct { char dummy1; TYPE dummy2; } *) 0)->dummy2)
  100: #endif
  101: 
  102: /* The internal variables in the standalone libintl.a must have different
  103:    names than the internal variables in GNU libc, otherwise programs
  104:    using libintl.a cannot be linked statically.  */
  105: #if !defined _LIBC
  106: # define _nl_default_default_domain libintl_nl_default_default_domain
  107: # define _nl_current_default_domain libintl_nl_current_default_domain
  108: # define _nl_default_dirname libintl_nl_default_dirname
  109: # define _nl_domain_bindings libintl_nl_domain_bindings
  110: #endif
  111: 
  112: /* Some compilers, like SunOS4 cc, don't have offsetof in <stddef.h>.  */
  113: #ifndef offsetof
  114: # define offsetof(type,ident) ((size_t)&(((type*)0)->ident))
  115: #endif
  116: 
  117: /* @@ end of prolog @@ */
  118: 
  119: #ifdef _LIBC
  120: /* Rename the non ANSI C functions.  This is required by the standard
  121:    because some ANSI C functions will require linking with this object
  122:    file and the name space must not be polluted.  */
  123: # define getcwd __getcwd
  124: # ifndef stpcpy
  125: #  define stpcpy __stpcpy
  126: # endif
  127: # define tfind __tfind
  128: #else
  129: # if !defined HAVE_GETCWD
  130: char *getwd ();
  131: #  define getcwd(buf, max) getwd (buf)
  132: # else
  133: char *getcwd ();
  134: # endif
  135: # ifndef HAVE_STPCPY
  136: static char *stpcpy PARAMS ((char *dest, const char *src));
  137: # endif
  138: # ifndef HAVE_MEMPCPY
  139: static void *mempcpy PARAMS ((void *dest, const void *src, size_t n));
  140: # endif
  141: #endif
  142: 
  143: /* Amount to increase buffer size by in each try.  */
  144: #define PATH_INCR 32
  145: 
  146: /* The following is from pathmax.h.  */
  147: /* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define
  148:    PATH_MAX but might cause redefinition warnings when sys/param.h is
  149:    later included (as on MORE/BSD 4.3).  */
  150: #if defined _POSIX_VERSION || (defined HAVE_LIMITS_H && !defined __GNUC__)
  151: # include <limits.h>
  152: #endif
  153: 
  154: #ifndef _POSIX_PATH_MAX
  155: # define _POSIX_PATH_MAX 255
  156: #endif
  157: 
  158: #if !defined PATH_MAX && defined _PC_PATH_MAX
  159: # define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX))
  160: #endif
  161: 
  162: /* Don't include sys/param.h if it already has been.  */
  163: #if defined HAVE_SYS_PARAM_H && !defined PATH_MAX && !defined MAXPATHLEN
  164: # include <sys/param.h>
  165: #endif
  166: 
  167: #if !defined PATH_MAX && defined MAXPATHLEN
  168: # define PATH_MAX MAXPATHLEN
  169: #endif
  170: 
  171: #ifndef PATH_MAX
  172: # define PATH_MAX _POSIX_PATH_MAX
  173: #endif
  174: 
  175: /* Whether to support different locales in different threads.  */
  176: #if defined _LIBC || HAVE_NL_LOCALE_NAME
  177: # define HAVE_PER_THREAD_LOCALE
  178: #endif
  179: 
  180: /* This is the type used for the search tree where known translations
  181:    are stored.  */
  182: struct known_translation_t
  183: {
  184:   /* Domain in which to search.  */
  185:   const char *domainname;
  186: 
  187:   /* The category.  */
  188:   int category;
  189: 
  190: #ifdef HAVE_PER_THREAD_LOCALE
  191:   /* Name of the relevant locale category, or "" for the global locale.  */
  192:   const char *localename;
  193: #endif
  194: 
  195:   /* State of the catalog counter at the point the string was found.  */
  196:   int counter;
  197: 
  198:   /* Catalog where the string was found.  */
  199:   struct loaded_l10nfile *domain;
  200: 
  201:   /* And finally the translation.  */
  202:   const char *translation;
  203:   size_t translation_length;
  204: 
  205:   /* Pointer to the string in question.  */
  206:   char msgid[ZERO];
  207: };
  208: 
  209: /* Root of the search tree with known translations.  We can use this
  210:    only if the system provides the `tsearch' function family.  */
  211: #if defined HAVE_TSEARCH || defined _LIBC
  212: # include <search.h>
  213: 
  214: static void *root;
  215: 
  216: # ifdef _LIBC
  217: #  define tsearch __tsearch
  218: # endif
  219: 
  220: /* Function to compare two entries in the table of known translations.  */
  221: static int transcmp PARAMS ((const void *p1, const void *p2));
  222: static int
  223: transcmp (p1, p2)
  224:      const void *p1;
  225:      const void *p2;
  226: {
  227:   const struct known_translation_t *s1;
  228:   const struct known_translation_t *s2;
  229:   int result;
  230: 
  231:   s1 = (const struct known_translation_t *) p1;
  232:   s2 = (const struct known_translation_t *) p2;
  233: 
  234:   result = strcmp (s1->msgid, s2->msgid);
  235:   if (result == 0)
  236:     {
  237:       result = strcmp (s1->domainname, s2->domainname);
  238:       if (result == 0)
  239:         {
  240: #ifdef HAVE_PER_THREAD_LOCALE
  241:           result = strcmp (s1->localename, s2->localename);
  242:           if (result == 0)
  243: #endif
  244:             /* We compare the category last (though this is the cheapest
  245:                operation) since it is hopefully always the same (namely
  246:                LC_MESSAGES).  */
  247:             result = s1->category - s2->category;
  248:         }
  249:     }
  250: 
  251:   return result;
  252: }
  253: #endif
  254: 
  255: /* Name of the default domain used for gettext(3) prior any call to
  256:    textdomain(3).  The default value for this is "messages".  */
  257: const char _nl_default_default_domain[] attribute_hidden = "messages";
  258: 
  259: /* Value used as the default domain for gettext(3).  */
  260: const char *_nl_current_default_domain attribute_hidden
  261:      = _nl_default_default_domain;
  262: 
  263: /* Contains the default location of the message catalogs.  */
  264: 
  265: #ifdef _LIBC
  266: extern const char _nl_default_dirname[];
  267: libc_hidden_proto (_nl_default_dirname)
  268: #endif
  269: const char _nl_default_dirname[] = LOCALEDIR;
  270: #ifdef _LIBC
  271: libc_hidden_data_def (_nl_default_dirname)
  272: #endif
  273: 
  274: /* List with bindings of specific domains created by bindtextdomain()
  275:    calls.  */
  276: struct binding *_nl_domain_bindings;
  277: 
  278: /* Prototypes for local functions.  */
  279: static char *plural_lookup PARAMS ((struct loaded_l10nfile *domain,
  280:                                     unsigned long int n,
  281:                                     const char *translation,
  282:                                     size_t translation_len))
  283:      internal_function;
  284: static const char *guess_category_value PARAMS ((int category,
  285:                                                  const char *categoryname))
  286:      internal_function;
  287: #ifdef _LIBC
  288: # include "../locale/localeinfo.h"
  289: # define category_to_name(category) \
  290:   _nl_category_names.str + _nl_category_name_idxs[category]
  291: #else
  292: static const char *category_to_name PARAMS ((int category)) internal_function;
  293: #endif
  294: 
  295: 
  296: /* For those loosing systems which don't have `alloca' we have to add
  297:    some additional code emulating it.  */
  298: #ifdef HAVE_ALLOCA
  299: /* Nothing has to be done.  */
  300: # define freea(p) /* nothing */
  301: # define ADD_BLOCK(list, address) /* nothing */
  302: # define FREE_BLOCKS(list) /* nothing */
  303: #else
  304: struct block_list
  305: {
  306:   void *address;
  307:   struct block_list *next;
  308: };
  309: # define ADD_BLOCK(list, addr)                                                \
  310:   do {                                                                        \
  311:     struct block_list *newp = (struct block_list *) malloc (sizeof (*newp));  \
  312:     /* If we cannot get a free block we cannot add the new element to         \
  313:        the list.  */                                                          \
  314:     if (newp != NULL) {                                                       \
  315:       newp->address = (addr);                                                 \
  316:       newp->next = (list);                                                    \
  317:       (list) = newp;                                                          \
  318:     }                                                                         \
  319:   } while (0)
  320: # define FREE_BLOCKS(list)                                                    \
  321:   do {                                                                        \
  322:     while (list != NULL) {                                                    \
  323:       struct block_list *old = list;                                          \
  324:       list = list->next;                                                      \
  325:       free (old->address);                                                    \
  326:       free (old);                                                             \
  327:     }                                                                         \
  328:   } while (0)
  329: # undef alloca
  330: # define alloca(size) (malloc (size))
  331: # define freea(p) free (p)
  332: #endif  /* have alloca */
  333: 
  334: 
  335: #ifdef _LIBC
  336: /* List of blocks allocated for translations.  */
  337: typedef struct transmem_list
  338: {
  339:   struct transmem_list *next;
  340:   char data[ZERO];
  341: } transmem_block_t;
  342: static struct transmem_list *transmem_list;
  343: #else
  344: typedef unsigned char transmem_block_t;
  345: #endif
  346: #if defined _LIBC || HAVE_ICONV
  347: static const char *get_output_charset PARAMS ((struct binding *domainbinding))
  348:      internal_function;
  349: #endif
  350: 
  351: 
  352: /* Names for the libintl functions are a problem.  They must not clash
  353:    with existing names and they should follow ANSI C.  But this source
  354:    code is also used in GNU C Library where the names have a __
  355:    prefix.  So we have to make a difference here.  */
  356: #ifdef _LIBC
  357: # define DCIGETTEXT __dcigettext
  358: #else
  359: # define DCIGETTEXT libintl_dcigettext
  360: #endif
  361: 
  362: /* Lock variable to protect the global data in the gettext implementation.  */
  363: #ifdef _LIBC
  364: __libc_rwlock_define_initialized (, _nl_state_lock attribute_hidden)
  365: #endif
  366: 
  367: /* Checking whether the binaries runs SUID must be done and glibc provides
  368:    easier methods therefore we make a difference here.  */
  369: #ifdef _LIBC
  370: # define ENABLE_SECURE __libc_enable_secure
  371: # define DETERMINE_SECURE
  372: #else
  373: # ifndef HAVE_GETUID
  374: #  define getuid() 0
  375: # endif
  376: # ifndef HAVE_GETGID
  377: #  define getgid() 0
  378: # endif
  379: # ifndef HAVE_GETEUID
  380: #  define geteuid() getuid()
  381: # endif
  382: # ifndef HAVE_GETEGID
  383: #  define getegid() getgid()
  384: # endif
  385: static int enable_secure;
  386: # define ENABLE_SECURE (enable_secure == 1)
  387: # define DETERMINE_SECURE \
  388:   if (enable_secure == 0)                                                     \
  389:     {                                                                         \
  390:       if (getuid () != geteuid () || getgid () != getegid ())                 \
  391:         enable_secure = 1;                                                   \
  392:       else                                                                    \
  393:         enable_secure = -1;                                                  \
  394:     }
  395: #endif
  396: 
  397: /* Get the function to evaluate the plural expression.  */
  398: #include "plural-eval.c"
  399: 
  400: /* Look up MSGID in the DOMAINNAME message catalog for the current
  401:    CATEGORY locale and, if PLURAL is nonzero, search over string
  402:    depending on the plural form determined by N.  */
  403: char *
  404: DCIGETTEXT (domainname, msgid1, msgid2, plural, n, category)
  405:      const char *domainname;
  406:      const char *msgid1;
  407:      const char *msgid2;
  408:      int plural;
  409:      unsigned long int n;
  410:      int category;
  411: {
  412: #ifndef HAVE_ALLOCA
  413:   struct block_list *block_list = NULL;
  414: #endif
  415:   struct loaded_l10nfile *domain;
  416:   struct binding *binding;
  417:   const char *categoryname;
  418:   const char *categoryvalue;
  419:   char *dirname, *xdomainname;
  420:   char *single_locale;
  421:   char *retval;
  422:   size_t retlen;
  423:   int saved_errno;
  424: #if defined HAVE_TSEARCH || defined _LIBC
  425:   struct known_translation_t *search;
  426:   struct known_translation_t **foundp = NULL;
  427:   size_t msgid_len;
  428: # ifdef HAVE_PER_THREAD_LOCALE
  429:   const char *localename;
  430: # endif
  431: #endif
  432:   size_t domainname_len;
  433: 
  434:   /* If no real MSGID is given return NULL.  */
  435:   if (msgid1 == NULL)
  436:     return NULL;
  437: 
  438: #ifdef _LIBC
  439:   if (category < 0 || category >= __LC_LAST || category == LC_ALL)
  440:     /* Bogus.  */
  441:     return (plural == 0
  442:             ? (char *) msgid1
  443:             /* Use the Germanic plural rule.  */
  444:             : n == 1 ? (char *) msgid1 : (char *) msgid2);
  445: #endif
  446: 
  447:   __libc_rwlock_rdlock (_nl_state_lock);
  448: 
  449:   /* If DOMAINNAME is NULL, we are interested in the default domain.  If
  450:      CATEGORY is not LC_MESSAGES this might not make much sense but the
  451:      definition left this undefined.  */
  452:   if (domainname == NULL)
  453:     domainname = _nl_current_default_domain;
  454: 
  455: #if defined HAVE_TSEARCH || defined _LIBC
  456:   msgid_len = strlen (msgid1) + 1;
  457: 
  458:   /* Try to find the translation among those which we found at
  459:      some time.  */
  460:   search = (struct known_translation_t *)
  461:            alloca (offsetof (struct known_translation_t, msgid) + msgid_len);
  462:   memcpy (search->msgid, msgid1, msgid_len);
  463:   search->domainname = domainname;
  464:   search->category = category;
  465: # ifdef HAVE_PER_THREAD_LOCALE
  466: #  ifdef _LIBC
  467:   localename = __current_locale_name (category);
  468: #  endif
  469:   search->localename = localename;
  470: # endif
  471: 
  472:   /* Since tfind/tsearch manage a balanced tree, concurrent tfind and
  473:      tsearch calls can be fatal.  */
  474:   __libc_rwlock_define_initialized (static, tree_lock);
  475:   __libc_rwlock_rdlock (tree_lock);
  476: 
  477:   foundp = (struct known_translation_t **) tfind (search, &root, transcmp);
  478: 
  479:   __libc_rwlock_unlock (tree_lock);
  480: 
  481:   freea (search);
  482:   if (foundp != NULL && (*foundp)->counter == _nl_msg_cat_cntr)
  483:     {
  484:       /* Now deal with plural.  */
  485:       if (plural)
  486:         retval = plural_lookup ((*foundp)->domain, n, (*foundp)->translation,
  487:                                 (*foundp)->translation_length);
  488:       else
  489:         retval = (char *) (*foundp)->translation;
  490: 
  491:       __libc_rwlock_unlock (_nl_state_lock);
  492:       return retval;
  493:     }
  494: #endif
  495: 
  496:   /* Preserve the `errno' value.  */
  497:   saved_errno = errno;
  498: 
  499:   /* See whether this is a SUID binary or not.  */
  500:   DETERMINE_SECURE;
  501: 
  502:   /* First find matching binding.  */
  503:   for (binding = _nl_domain_bindings; binding != NULL; binding = binding->next)
  504:     {
  505:       int compare = strcmp (domainname, binding->domainname);
  506:       if (compare == 0)
  507:         /* We found it!  */
  508:         break;
  509:       if (compare < 0)
  510:         {
  511:           /* It is not in the list.  */
  512:           binding = NULL;
  513:           break;
  514:         }
  515:     }
  516: 
  517:   if (binding == NULL)
  518:     dirname = (char *) _nl_default_dirname;
  519:   else if (binding->dirname[0] == '/')
  520:     dirname = binding->dirname;
  521:   else
  522:     {
  523:       /* We have a relative path.  Make it absolute now.  */
  524:       size_t dirname_len = strlen (binding->dirname) + 1;
  525:       size_t path_max;
  526:       char *ret;
  527: 
  528:       path_max = (unsigned int) PATH_MAX;
  529:       path_max += 2;            /* The getcwd docs say to do this.  */
  530: 
  531:       for (;;)
  532:         {
  533:           dirname = (char *) alloca (path_max + dirname_len);
  534:           ADD_BLOCK (block_list, dirname);
  535: 
  536:           __set_errno (0);
  5