LCOV - code coverage report
Current view: top level - common - i18n.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 25 67 37.3 %
Date: 2016-09-12 13:01:59 Functions: 4 5 80.0 %

          Line data    Source code
       1             : /* i18n.c - gettext initialization
       2             :  * Copyright (C) 2007, 2010 Free Software Foundation, Inc.
       3             :  * Copyright (C) 2015 g10 Code GmbH
       4             :  *
       5             :  * This file is free software; you can redistribute it and/or modify
       6             :  * it under the terms of either
       7             :  *
       8             :  *   - the GNU Lesser General Public License as published by the Free
       9             :  *     Software Foundation; either version 3 of the License, or (at
      10             :  *     your option) any later version.
      11             :  *
      12             :  * or
      13             :  *
      14             :  *   - the GNU General Public License as published by the Free
      15             :  *     Software Foundation; either version 2 of the License, or (at
      16             :  *     your option) any later version.
      17             :  *
      18             :  * or both in parallel, as here.
      19             :  *
      20             :  * This file is distributed in the hope that it will be useful,
      21             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      22             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      23             :  * GNU General Public License for more details.
      24             :  *
      25             :  * You should have received a copy of the GNU General Public License
      26             :  * along with this program; if not, see <http://www.gnu.org/licenses/>.
      27             :  */
      28             : 
      29             : #include <config.h>
      30             : #ifdef HAVE_LOCALE_H
      31             : #include <locale.h>
      32             : #endif
      33             : #ifdef HAVE_LANGINFO_CODESET
      34             : #include <langinfo.h>
      35             : #endif
      36             : 
      37             : #include "util.h"
      38             : #include "i18n.h"
      39             : 
      40             : 
      41             : #undef USE_MSGCACHE
      42             : #if defined(HAVE_SETLOCALE) && defined(LC_MESSAGES) \
      43             :    && !defined(USE_SIMPLE_GETTEXT) && defined(ENABLE_NLS)
      44             : # define USE_MSGCACHE 1
      45             : #endif
      46             : 
      47             : 
      48             : #ifdef USE_MSGCACHE
      49             : /* An object to store pointers to static strings and their static
      50             :    translations.  A linked list is not optimal but given that we only
      51             :    have a few dozen messages it should be acceptable. */
      52             : struct msg_cache_s
      53             : {
      54             :   struct msg_cache_s *next;
      55             :   const char *key;
      56             :   const char *value;
      57             : };
      58             : 
      59             : /* A object to store an lc_messages string and a link to the cache
      60             :    object.  */
      61             : struct msg_cache_heads_s
      62             : {
      63             :   struct msg_cache_heads_s *next;
      64             :   struct msg_cache_s *cache;
      65             :   char lc_messages[1];
      66             : };
      67             : 
      68             : /* Out static cache of translated messages.  We need this because
      69             :    there is no gettext API to return a translation depending on the
      70             :    locale.  Switching the locale for each access to a translatable
      71             :    string seems to be too expensive.  Note that this is used only for
      72             :    strings in gpg-agent which are passed to Pinentry.  All other
      73             :    strings are using the regular gettext interface.  Note that we can
      74             :    never release this memory because consumers take the result as
      75             :    static strings.  */
      76             : static struct msg_cache_heads_s *msgcache;
      77             : 
      78             : #endif /*USE_MSGCACHE*/
      79             : 
      80             : 
      81             : void
      82        2339 : i18n_init (void)
      83             : {
      84             : #ifdef USE_SIMPLE_GETTEXT
      85             :   bindtextdomain (PACKAGE_GT, gnupg_localedir ());
      86             :   textdomain (PACKAGE_GT);
      87             : #else
      88             : # ifdef ENABLE_NLS
      89        2339 :   setlocale (LC_ALL, "" );
      90        2339 :   bindtextdomain (PACKAGE_GT, LOCALEDIR);
      91        2339 :   textdomain (PACKAGE_GT);
      92             : # endif
      93             : #endif
      94        2339 : }
      95             : 
      96             : 
      97             : /* The Assuan agent protocol requires us to transmit utf-8 strings
      98             :    thus we need a way to temporary switch gettext from native to
      99             :    utf8.  */
     100             : char *
     101         433 : i18n_switchto_utf8 (void)
     102             : {
     103             : #ifdef USE_SIMPLE_GETTEXT
     104             :   /* Return an arbitrary pointer as true value.  */
     105             :   return gettext_use_utf8 (1) ? (char*)(-1) : NULL;
     106             : #elif defined(ENABLE_NLS)
     107         433 :   char *orig_codeset = bind_textdomain_codeset (PACKAGE_GT, NULL);
     108             : # ifdef HAVE_LANGINFO_CODESET
     109         433 :   if (!orig_codeset)
     110         406 :     orig_codeset = nl_langinfo (CODESET);
     111             : # endif
     112         433 :   if (orig_codeset)
     113             :     { /* We only switch when we are able to restore the codeset later.
     114             :          Note that bind_textdomain_codeset does only return on memory
     115             :          errors but not if a codeset is not available.  Thus we don't
     116             :          bother printing a diagnostic here. */
     117         433 :       orig_codeset = xstrdup (orig_codeset);
     118         433 :       if (!bind_textdomain_codeset (PACKAGE_GT, "utf-8"))
     119             :         {
     120           0 :           xfree (orig_codeset);
     121           0 :           orig_codeset = NULL;
     122             :         }
     123             :     }
     124         433 :   return orig_codeset;
     125             : #else
     126             :   return NULL;
     127             : #endif
     128             : }
     129             : 
     130             : /* Switch back to the saved codeset.  */
     131             : void
     132         433 : i18n_switchback (char *saved_codeset)
     133             : {
     134             : #ifdef USE_SIMPLE_GETTEXT
     135             :   gettext_use_utf8 (!!saved_codeset);
     136             : #elif defined(ENABLE_NLS)
     137         433 :   if (saved_codeset)
     138             :     {
     139         433 :       bind_textdomain_codeset (PACKAGE_GT, saved_codeset);
     140         433 :       xfree (saved_codeset);
     141             :     }
     142             : #else
     143             :   (void)saved_codeset;
     144             : #endif
     145         433 : }
     146             : 
     147             : 
     148             : /* Gettext variant which temporary switches to utf-8 for string. */
     149             : const char *
     150           0 : i18n_utf8 (const char *string)
     151             : {
     152           0 :   char *saved = i18n_switchto_utf8 ();
     153           0 :   const char *result = _(string);
     154           0 :   i18n_switchback (saved);
     155           0 :   return result;
     156             : }
     157             : 
     158             : 
     159             : /* A variant of gettext which allows the programmer to specify the
     160             :    locale to use for translating the message.  The function assumes
     161             :    that utf-8 is used for the encoding.  */
     162             : const char *
     163         107 : i18n_localegettext (const char *lc_messages, const char *string)
     164             : {
     165             : #if USE_MSGCACHE
     166         107 :   const char *result = NULL;
     167         107 :   char *saved = NULL;
     168             :   struct msg_cache_heads_s *mh;
     169             :   struct msg_cache_s *mc;
     170             : 
     171         107 :   if (!lc_messages)
     172         107 :     goto leave;
     173             : 
     174             :   /* Lookup in the cache.  */
     175           0 :   for (mh = msgcache; mh; mh = mh->next)
     176           0 :     if (!strcmp (mh->lc_messages, lc_messages))
     177           0 :       break;
     178           0 :   if (mh)
     179             :     {
     180             :       /* A cache entry for this local exists - find the string.
     181             :          Because the system is designed for static strings it is
     182             :          sufficient to compare the pointers.  */
     183           0 :       for (mc = mh->cache; mc; mc = mc->next)
     184           0 :         if (mc->key == string)
     185             :           {
     186             :             /* Cache hit.  */
     187           0 :             result = mc->value;
     188           0 :             goto leave;
     189             :           }
     190             :     }
     191             : 
     192             :   /* Cached miss.  Change the locale, translate, reset locale.  */
     193           0 :   saved = setlocale (LC_MESSAGES, NULL);
     194           0 :   if (!saved)
     195           0 :     goto leave;
     196           0 :   saved = xtrystrdup (saved);
     197           0 :   if (!saved)
     198           0 :     goto leave;
     199           0 :   if (!setlocale (LC_MESSAGES, lc_messages))
     200           0 :     goto leave;
     201             : 
     202           0 :   bindtextdomain (PACKAGE_GT, LOCALEDIR);
     203           0 :   result = gettext (string);
     204           0 :   setlocale (LC_MESSAGES, saved);
     205           0 :   bindtextdomain (PACKAGE_GT, LOCALEDIR);
     206             : 
     207             :   /* Cache the result.  */
     208           0 :   if (!mh)
     209             :     {
     210             :       /* First use of this locale - create an entry.  */
     211           0 :       mh = xtrymalloc (sizeof *mh + strlen (lc_messages));
     212           0 :       if (!mh)
     213           0 :         goto leave;
     214           0 :       strcpy (mh->lc_messages, lc_messages);
     215           0 :       mh->cache = NULL;
     216           0 :       mh->next = msgcache;
     217           0 :       msgcache = mh;
     218             :     }
     219           0 :   mc = xtrymalloc (sizeof *mc);
     220           0 :   if (!mc)
     221           0 :     goto leave;
     222           0 :   mc->key = string;
     223           0 :   mc->value = result;
     224           0 :   mc->next = mh->cache;
     225           0 :   mh->cache = mc;
     226             : 
     227             :  leave:
     228         107 :   xfree (saved);
     229         107 :   return result? result : _(string);
     230             : 
     231             : #else /*!USE_MSGCACHE*/
     232             : 
     233             :   (void)lc_messages;
     234             :   return _(string);
     235             : 
     236             : #endif /*!USE_MSGCACHE*/
     237             : }

Generated by: LCOV version 1.11