Obsolete option --no-sig-create-check.
[gnupg.git] / util / simple-gettext.c
index b5ee446..9225737 100644 (file)
@@ -1,11 +1,12 @@
 /* simple-gettext.c  - a simplified version of gettext.
- * Copyright (C) 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
+ * Copyright (C) 1995, 1996, 1997, 1999,
+ *               2005 Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
  * GnuPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
  * (at your option) any later version.
  *
  * GnuPG is distributed in the hope that it will be useful,
@@ -14,8 +15,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
  */
 
 /* This is a simplified version of gettext written by Ulrich Drepper.
@@ -27,8 +27,8 @@
 
 #include <config.h>
 #ifdef USE_SIMPLE_GETTEXT
-#if !defined (__MINGW32__) && !defined (__CYGWIN32__)
-#error This file can only be used with MingW32 or Cygwin32
+#if !defined (_WIN32) && !defined (__CYGWIN32__)
+#error This file can only be used under Windows or Cygwin32
 #endif
 
 #include <stdio.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <windows.h>
 #include "types.h"
 #include "util.h"
 
+#include "windows.h" /* For GetModuleFileName.  */
 
 /* The magic number of the GNU message catalog format. */
 #define MAGIC        0x950412de
@@ -79,13 +79,22 @@ struct string_desc
 };
 
 
+struct overflow_space_s
+{
+  struct overflow_space_s *next;
+  u32 idx;
+  char d[1];
+};
 
 struct loaded_domain
 {
   char *data;
   int must_swap;
   u32 nstrings;
-/*    char *mapped; */
+  char *mapped;  /* 0 = not yet mapped, 1 = mapped,
+                    2 = mapped to
+                    overflow space */
+  struct overflow_space_s *overflow_space;
   struct string_desc *orig_tab;
   struct string_desc *trans_tab;
   u32 hash_size;
@@ -210,198 +219,216 @@ load_domain( const char *filename )
        return NULL;
     }
 
-    /* allocate an array to keep track of code page mappings */
-/*      domain->mapped = calloc( 1, domain->nstrings ); */
-/*      if( !domain->mapped ) { */
-/*     free( data ); */
-/*     free( domain ); */
-/*     return NULL; */
-/*      } */
+    /* Allocate an array to keep track of code page mappings. */
+    domain->mapped = calloc( 1, domain->nstrings );
+    if( !domain->mapped ) {
+        free( data );
+        free( domain );
+        return NULL;
+    }
 
     return domain;
 }
 
 
-/****************
- * Set the file used for translations. Pass a NULL to disable
- * translation.  A new filename may be set at anytime.
- * WARNING: After changing the filename you shoudl not access any data
- *         retrieved by gettext().
+/* Set the file used for translations.  Pass a NULL to disable
+   translation.  A new filename may be set at anytime.  WARNING: After
+   changing the filename you should not access any data retrieved by
+   gettext().
+
+   If REGKEY is not NULL, the function tries to selected the language
+   the registry key "Lang" below that key.  If in addition the
+   environment variable LANGUAGE has been set, that value will
+   override a value set by the registry key.
  */
 int
-set_gettext_file( const char *filename )
+set_gettext_file ( const char *filename, const char *regkey )
 {
-    struct loaded_domain *domain = NULL;
+  struct loaded_domain *domain = NULL;
 
-    if( filename && *filename ) {
-       if( filename[0] == '/'
-          #ifdef HAVE_DRIVE_LETTERS
-           || ( isalpha(filename[0])
-                && filename[1] == ':'
-                && (filename[2] == '/' || filename[2] == '\\') )
-          #endif
-          ) {
-           /* absolute path - use it as is */
-           domain = load_domain( filename );
+  if ( filename && *filename )
+    {
+      if ( filename[0] == '/'
+#ifdef HAVE_DRIVE_LETTERS
+           || ( isalpha(filename[0])
+                && filename[1] == ':'
+                && (filename[2] == '/' || filename[2] == '\\') )
+#endif
+          )
+        {
+          /* absolute path - use it as is */
+          domain = load_domain( filename );
        }
-       else { /* relative path - append ".mo" and get dir from the environment */
-           char *buf = NULL;
-           char *dir;
-            char *p;
-
-           dir = read_w32_registry_string( NULL,
-                                           "Control Panel\\Mingw32\\NLS",
-                                           "MODir" );
-           if( dir && (buf=malloc(strlen(dir)+strlen(filename)+1+3+1)) ) {
-               strcpy(stpcpy(stpcpy(stpcpy( buf, dir),"\\"), filename),".mo");
-                /* Better make sure that we don't mix forward and
-                   backward slashes.  It seems that some Windoze
-                   versions don't accept this. */
-                for (p=buf; *p; p++)
-                  {
-                    if (*p == '/')
-                      *p = '\\';
-                  }
-               domain = load_domain( buf );
-               free(buf);
-           }
-           free(dir);
+      else if (regkey)  /* Standard.  */
+        {
+          char *instdir, *langid, *fname;
+          char *p;
+          int envvar_mode = 0;
+          
+        again:
+          if (!envvar_mode && (p = getenv ("LANGUAGE")) && *p)
+            {
+              envvar_mode = 1;
+              langid = malloc (strlen (p)+1);
+              if (!langid)
+                return -1;
+              strcpy (langid, p);
+              /* We only make use of the first language given.  Strip
+                 the rest.  */
+              p = strchr (langid, ':');
+              if (p)
+                *p = 0;
+              
+              /* In the $LANGUAGE case we do not use the registered
+                 installation directory but the one where the gpg
+                 binary has been found.  */
+              instdir = malloc (MAX_PATH+5);
+              if ( !instdir || !GetModuleFileName (NULL, instdir, MAX_PATH) )
+                {
+                  free (langid);
+                  free (instdir);
+                  return -1; /* Error getting the process' file name.  */
+                }
+              p = strrchr (instdir, DIRSEP_C);
+              if (!p)
+                {
+                  free (langid);
+                  free (instdir);
+                  return -1; /* Invalid file name returned.  */
+                }
+              *p = 0;
+            }
+          else
+            {
+              instdir = read_w32_registry_string ("HKEY_LOCAL_MACHINE",
+                                                  regkey,
+                                                  "Install Directory");
+              if (!instdir)
+                return -1;
+              langid = read_w32_registry_string (NULL, /* HKCU then HKLM */
+                                                 regkey,
+                                                 "Lang");
+              if (!langid)
+                {
+                  free (instdir);
+                  return -1;
+                }
+            }
+          
+          /* Strip stuff after a dot in case the user tried to enter
+             the entire locale syntacs as usual for POSIX.  */
+          p = strchr (langid, '.');
+          if (p)
+            *p = 0;
+          
+          /* Build the key: "<instdir>/<domain>.nls/<langid>.mo" We
+             use a directory below the installation directory with the
+             domain included in case the software has been insalled
+             with other software altogether at the same place.  */
+          fname = malloc (strlen (instdir) + 1 + strlen (filename) + 5
+                          + strlen (langid) + 3 + 1);
+          if (!fname)
+            {
+              free (instdir);
+              free (langid);
+              return -1;
+            }
+          strcpy (stpcpy (stpcpy (stpcpy (stpcpy ( stpcpy (fname,
+                  instdir),"\\"), filename), ".nls\\"), langid), ".mo");
+          free (instdir);
+          free (langid);
+
+          /* Better make sure that we don't mix forward and backward
+             slashes.  It seems that some Windoze versions don't
+             accept this. */
+          for (p=fname; *p; p++) 
+            {
+              if (*p == '/')
+                *p = '\\';
+            }
+          domain = load_domain (fname);
+          free(fname);
+
+          if (!domain && envvar_mode == 1)
+            {
+              /* In case it failed, we try again using the registry
+                 method. */
+              envvar_mode++;
+              goto again;
+            }
        }
-       if( !domain )
-           return -1;
+      
+
+      if (!domain)
+        return -1;
     }
 
-    if( the_domain ) {
-       free( the_domain->data );
-/*     free( the_domain->mapped ); */
-       free( the_domain );
-       the_domain = NULL;
+  if ( the_domain )
+    {
+      struct overflow_space_s *os, *os2;
+
+      free ( the_domain->data );
+      free ( the_domain->mapped );
+      for (os=the_domain->overflow_space; os; os = os2)
+        {
+          os2 = os->next;
+          free (os);
+        }
+      free ( the_domain );
+      the_domain = NULL;
     }
-    the_domain = domain;
-    return NULL;
+  the_domain = domain;
+  return 0;
 }
 
 
 static const char*
 get_string( struct loaded_domain *domain, u32 idx )
 {
-    char *p = domain->data + SWAPIT(domain->must_swap,
-                                   domain->trans_tab[idx].offset);
-#if 0 /* Mapping is not used any more.  Instead we convert the files when
-         Creating the binary distribution. */
-    if( !domain->mapped[idx] ) {
-       byte *pp;
-
-       domain->mapped[idx] = 1;
-       /* we assume Latin1 -> CP 850 for now */
-       for( pp=p; *pp; pp++ ) {
-           if( (*pp & 0x80) ) {
-               switch( *pp ) {
-                 /* ISO-8859-1 to IBM-CP-850 */
-                 case 0xa0: *pp = '\xff' ; break;  /* nobreakspace */
-                 case 0xa1: *pp = '\xad' ; break;  /* exclamdown */
-                 case 0xa2: *pp = '\xbd' ; break;  /* cent */
-                 case 0xa3: *pp = '\x9c' ; break;  /* sterling */
-                 case 0xa4: *pp = '\xcf' ; break;  /* currency */
-                 case 0xa5: *pp = '\xbe' ; break;  /* yen */
-                 case 0xa6: *pp = '\xdd' ; break;  /* brokenbar */
-                 case 0xa7: *pp = '\xf5' ; break;  /* section */
-                 case 0xa8: *pp = '\xf9' ; break;  /* diaeresis */
-                 case 0xa9: *pp = '\xb8' ; break;  /* copyright */
-                 case 0xaa: *pp = '\xa6' ; break;  /* ordfeminine */
-                 case 0xab: *pp = '\xae' ; break;  /* guillemotleft */
-                 case 0xac: *pp = '\xaa' ; break;  /* notsign */
-                 case 0xad: *pp = '\xf0' ; break;  /* hyphen */
-                 case 0xae: *pp = '\xa9' ; break;  /* registered */
-                 case 0xaf: *pp = '\xee' ; break;  /* macron */
-                 case 0xb0: *pp = '\xf8' ; break;  /* degree */
-                 case 0xb1: *pp = '\xf1' ; break;  /* plusminus */
-                 case 0xb2: *pp = '\xfd' ; break;  /* twosuperior */
-                 case 0xb3: *pp = '\xfc' ; break;  /* threesuperior */
-                 case 0xb4: *pp = '\xef' ; break;  /* acute */
-                 case 0xb5: *pp = '\xe6' ; break;  /* mu */
-                 case 0xb6: *pp = '\xf4' ; break;  /* paragraph */
-                 case 0xb7: *pp = '\xfa' ; break;  /* periodcentered */
-                 case 0xb8: *pp = '\xf7' ; break;  /* cedilla */
-                 case 0xb9: *pp = '\xfb' ; break;  /* onesuperior */
-                 case 0xba: *pp = '\xa7' ; break;  /* masculine */
-                 case 0xbb: *pp = '\xaf' ; break;  /* guillemotright */
-                 case 0xbc: *pp = '\xac' ; break;  /* onequarter */
-                 case 0xbd: *pp = '\xab' ; break;  /* onehalf */
-                 case 0xbe: *pp = '\xf3' ; break;  /* threequarters */
-                 case 0xbf: *pp = '\xa8' ; break;  /* questiondown */
-                 case 0xc0: *pp = '\xb7' ; break;  /* Agrave */
-                 case 0xc1: *pp = '\xb5' ; break;  /* Aacute */
-                 case 0xc2: *pp = '\xb6' ; break;  /* Acircumflex */
-                 case 0xc3: *pp = '\xc7' ; break;  /* Atilde */
-                 case 0xc4: *pp = '\x8e' ; break;  /* Adiaeresis */
-                 case 0xc5: *pp = '\x8f' ; break;  /* Aring */
-                 case 0xc6: *pp = '\x92' ; break;  /* AE */
-                 case 0xc7: *pp = '\x80' ; break;  /* Ccedilla */
-                 case 0xc8: *pp = '\xd4' ; break;  /* Egrave */
-                 case 0xc9: *pp = '\x90' ; break;  /* Eacute */
-                 case 0xca: *pp = '\xd2' ; break;  /* Ecircumflex */
-                 case 0xcb: *pp = '\xd3' ; break;  /* Ediaeresis */
-                 case 0xcc: *pp = '\xde' ; break;  /* Igrave */
-                 case 0xcd: *pp = '\xd6' ; break;  /* Iacute */
-                 case 0xce: *pp = '\xd7' ; break;  /* Icircumflex */
-                 case 0xcf: *pp = '\xd8' ; break;  /* Idiaeresis */
-                 case 0xd0: *pp = '\xd1' ; break;  /* Eth */
-                 case 0xd1: *pp = '\xa5' ; break;  /* Ntilde */
-                 case 0xd2: *pp = '\xe3' ; break;  /* Ograve */
-                 case 0xd3: *pp = '\xe0' ; break;  /* Oacute */
-                 case 0xd4: *pp = '\xe2' ; break;  /* Ocircumflex */
-                 case 0xd5: *pp = '\xe5' ; break;  /* Otilde */
-                 case 0xd6: *pp = '\x99' ; break;  /* Odiaeresis */
-                 case 0xd7: *pp = '\x9e' ; break;  /* multiply */
-                 case 0xd8: *pp = '\x9d' ; break;  /* Ooblique */
-                 case 0xd9: *pp = '\xeb' ; break;  /* Ugrave */
-                 case 0xda: *pp = '\xe9' ; break;  /* Uacute */
-                 case 0xdb: *pp = '\xea' ; break;  /* Ucircumflex */
-                 case 0xdc: *pp = '\x9a' ; break;  /* Udiaeresis */
-                 case 0xdd: *pp = '\xed' ; break;  /* Yacute */
-                 case 0xde: *pp = '\xe8' ; break;  /* Thorn */
-                 case 0xdf: *pp = '\xe1' ; break;  /* ssharp */
-                 case 0xe0: *pp = '\x85' ; break;  /* agrave */
-                 case 0xe1: *pp = '\xa0' ; break;  /* aacute */
-                 case 0xe2: *pp = '\x83' ; break;  /* acircumflex */
-                 case 0xe3: *pp = '\xc6' ; break;  /* atilde */
-                 case 0xe4: *pp = '\x84' ; break;  /* adiaeresis */
-                 case 0xe5: *pp = '\x86' ; break;  /* aring */
-                 case 0xe6: *pp = '\x91' ; break;  /* ae */
-                 case 0xe7: *pp = '\x87' ; break;  /* ccedilla */
-                 case 0xe8: *pp = '\x8a' ; break;  /* egrave */
-                 case 0xe9: *pp = '\x82' ; break;  /* eacute */
-                 case 0xea: *pp = '\x88' ; break;  /* ecircumflex */
-                 case 0xeb: *pp = '\x89' ; break;  /* ediaeresis */
-                 case 0xec: *pp = '\x8d' ; break;  /* igrave */
-                 case 0xed: *pp = '\xa1' ; break;  /* iacute */
-                 case 0xee: *pp = '\x8c' ; break;  /* icircumflex */
-                 case 0xef: *pp = '\x8b' ; break;  /* idiaeresis */
-                 case 0xf0: *pp = '\xd0' ; break;  /* eth */
-                 case 0xf1: *pp = '\xa4' ; break;  /* ntilde */
-                 case 0xf2: *pp = '\x95' ; break;  /* ograve */
-                 case 0xf3: *pp = '\xa2' ; break;  /* oacute */
-                 case 0xf4: *pp = '\x93' ; break;  /* ocircumflex */
-                 case 0xf5: *pp = '\xe4' ; break;  /* otilde */
-                 case 0xf6: *pp = '\x94' ; break;  /* odiaeresis */
-                 case 0xf7: *pp = '\xf6' ; break;  /* division */
-                 case 0xf8: *pp = '\x9b' ; break;  /* oslash */
-                 case 0xf9: *pp = '\x97' ; break;  /* ugrave */
-                 case 0xfa: *pp = '\xa3' ; break;  /* uacute */
-                 case 0xfb: *pp = '\x96' ; break;  /* ucircumflex */
-                 case 0xfc: *pp = '\x81' ; break;  /* udiaeresis */
-                 case 0xfd: *pp = '\xec' ; break;  /* yacute */
-                 case 0xfe: *pp = '\xe7' ; break;  /* thorn */
-                 case 0xff: *pp = '\x98' ; break;  /* ydiaeresis */
-                 default  :  break;
-               }
-           }
-       }
+  struct overflow_space_s *os;
+  char *p;
 
+  p = domain->data + SWAPIT(domain->must_swap, domain->trans_tab[idx].offset);
+  if (!domain->mapped[idx]) 
+    {
+      size_t plen, buflen;
+      char *buf;
+
+      domain->mapped[idx] = 1;
+
+      plen = strlen (p);
+      buf = utf8_to_native (p, plen, -1);
+      buflen = strlen (buf);
+      if (buflen <= plen)
+        strcpy (p, buf);
+      else
+        {
+          /* There is not enough space for the translation - store it
+             in the overflow_space else and mark that in the mapped
+             array.  Because we expect that this won't happen too
+             often, we use a simple linked list.  */
+          os = malloc (sizeof *os + buflen);
+          if (os)
+            {
+              os->idx = idx;
+              strcpy (os->d, buf);
+              os->next = domain->overflow_space;
+              domain->overflow_space = os;
+              p = os->d;
+            }
+          else
+            p = "ERROR in GETTEXT MALLOC";
+        }
+      xfree (buf);
+    }
+  else if (domain->mapped[idx] == 2) 
+    { /* We need to get the string from the overflow_space. */
+      for (os=domain->overflow_space; os; os = os->next)
+        if (os->idx == idx)
+          return (const char*)os->d;
+      p = "ERROR in GETTEXT\n";
     }
-#endif /* unused code */
-    return (const char*)p;
+  return (const char*)p;
 }
 
 
@@ -487,7 +514,7 @@ gettext( const char *msgid )
        log_info("InputCP=%u  OutputCP=%u\n", cp1, cp2 );
 
        if( !SetConsoleOutputCP( 1252 ) )
-          log_info("SetConsoleOutputCP failed: %d\n", (int)GetLastError() );
+            log_info("SetConsoleOutputCP failed: %s\n", w32_strerror (0));
 
        cp1 = GetConsoleCP();
        cp2 = GetConsoleOutputCP();