summary refs log tree commit diff stats
path: root/libotr/libgpg-error-1.42/src/gpg-error.c
diff options
context:
space:
mode:
Diffstat (limited to 'libotr/libgpg-error-1.42/src/gpg-error.c')
-rw-r--r--libotr/libgpg-error-1.42/src/gpg-error.c767
1 files changed, 767 insertions, 0 deletions
diff --git a/libotr/libgpg-error-1.42/src/gpg-error.c b/libotr/libgpg-error-1.42/src/gpg-error.c
new file mode 100644
index 0000000..4e8bd8b
--- /dev/null
+++ b/libotr/libgpg-error-1.42/src/gpg-error.c
@@ -0,0 +1,767 @@
+/* gpg-error.c - Determining gpg-error error codes.
+   Copyright (C) 2004, 2016 g10 Code GmbH
+
+   This file is part of libgpg-error.
+
+   libgpg-error is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public License
+   as published by the Free Software Foundation; either version 2.1 of
+   the License, or (at your option) any later version.
+
+   libgpg-error is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with libgpg-error; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+#ifdef ENABLE_NLS
+#ifdef HAVE_W32_SYSTEM
+# include "gettext.h"
+#else
+# include <libintl.h>
+#endif
+# define _(a) gettext (a)
+# ifdef gettext_noop
+#  define N_(a) gettext_noop (a)
+# else
+#  define N_(a) (a)
+# endif
+#else
+# define _(a) (a)
+# define N_(a) (a)
+#endif
+
+#include <gpg-error.h>
+
+
+#if HAVE_W32_SYSTEM
+/* The implementation follows below.  */
+static char *get_locale_dir (void);
+static void drop_locale_dir (char *locale_dir);
+#else
+#define get_locale_dir() LOCALEDIR
+#define drop_locale_dir(dir)
+#endif
+
+static void
+i18n_init (void)
+{
+#ifdef ENABLE_NLS
+  char *locale_dir;
+
+#ifdef HAVE_LC_MESSAGES
+  setlocale (LC_TIME, "");
+  setlocale (LC_MESSAGES, "");
+#else
+# ifndef HAVE_W32_SYSTEM
+  setlocale (LC_ALL, "" );
+# endif
+#endif
+
+  /* Note that for this program we would only need the textdomain call
+     because libgpg-error already initializes itself to its locale dir
+     (via gpg_err_init or a constructor).  However this is only done
+     for the static standard locale and thus if the above setlocale
+     calls select a different locale the bindtext below will do
+     something else.  */
+
+  locale_dir = get_locale_dir ();
+  if (locale_dir)
+    {
+      bindtextdomain (PACKAGE, locale_dir);
+      drop_locale_dir (locale_dir);
+    }
+  textdomain (PACKAGE);
+#endif
+}
+
+
+#ifdef HAVE_W32_SYSTEM
+
+#include <windows.h>
+
+
+static char *
+get_locale_dir (void)
+{
+  static wchar_t moddir[MAX_PATH+5];
+  char *result, *p;
+  int nbytes;
+
+  if (!GetModuleFileNameW (NULL, moddir, MAX_PATH))
+    *moddir = 0;
+
+#define SLDIR "\\share\\locale"
+  if (*moddir)
+    {
+      nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1, NULL, 0, NULL, NULL);
+      if (nbytes < 0)
+        return NULL;
+
+      result = malloc (nbytes + strlen (SLDIR) + 1);
+      if (result)
+        {
+          nbytes = WideCharToMultiByte (CP_UTF8, 0, moddir, -1,
+                                        result, nbytes, NULL, NULL);
+          if (nbytes < 0)
+            {
+              free (result);
+              result = NULL;
+            }
+          else
+            {
+              p = strrchr (result, '\\');
+              if (p)
+                *p = 0;
+              /* If we are installed below "bin" strip that part and
+                 use the top directory instead.  */
+              p = strrchr (result, '\\');
+              if (p && !strcmp (p+1, "bin"))
+                *p = 0;
+              /* Append the static part.  */
+              strcat (result, SLDIR);
+            }
+        }
+    }
+  else /* Use the old default value.  */
+    {
+      result = malloc (10 + strlen (SLDIR) + 1);
+      if (result)
+        {
+          strcpy (result, "c:\\gnupg");
+          strcat (result, SLDIR);
+        }
+    }
+#undef SLDIR
+  return result;
+}
+
+
+static void
+drop_locale_dir (char *locale_dir)
+{
+  free (locale_dir);
+}
+
+#endif	/* HAVE_W32_SYSTEM */
+
+
+const char *gpg_strerror_sym (gpg_error_t err);
+const char *gpg_strsource_sym (gpg_error_t err);
+
+
+/* Parse string STR assuming it is either a single number N or in the
+ * form K.N to denote an error source code K and and error code N.
+ * Returns false on error (e.g. invalid number) or true for valid
+ * codes; if true is returned a full error code is stored at ERR.  */
+static int
+get_err_from_number (char *str, gpg_error_t *err)
+{
+  unsigned long nr;
+  char *tail;
+
+  gpg_err_set_errno (0);
+  nr = strtoul (str, &tail, 0);
+  if (errno)
+    return 0;
+
+  if (nr > UINT_MAX)
+    return 0;
+
+  if (*tail)
+    {
+      unsigned long cnr = strtoul (tail + 1, &tail, 0);
+      if (errno || *tail)
+	return 0;
+
+      if (nr >= GPG_ERR_SOURCE_DIM || cnr >= GPG_ERR_CODE_DIM)
+	return 0;
+
+      nr = gpg_err_make (nr, cnr);
+    }
+
+  *err = (unsigned int) nr;
+  return 1;
+}
+
+
+/* Helper function to parse a symbol either with a "GPG_ERR_SOURCE_"
+ * or "GPG_ERR_" prefix.  If the symbol is not available false is
+ * return; else the symbols value is ORed into the value at ERR
+ * (shifted for a GPG_ERR_SOURCE_) and true returned.  HAVE_SOURCE and
+ * HAVE_CODE are expected to be addresses where a 0 is stored; a 1 is
+ * stored at the respective address to mark whether a code or source
+ * value was found.  If one of those state variables already point to
+ * a true value the function will return 0 and not change the value at
+ * ERR.  */
+static int
+get_err_from_symbol_one (char *str, gpg_error_t *err,
+			 int *have_source, int *have_code)
+{
+  static const char src_prefix[] = "GPG_ERR_SOURCE_";
+  static const char code_prefix[] = "GPG_ERR_";
+
+  if (!strncasecmp (src_prefix, str, sizeof (src_prefix) - 1))
+    {
+      gpg_err_source_t src;
+
+      if (*have_source)
+	return 0;
+      *have_source = 1;
+      str += sizeof (src_prefix) - 1;
+
+      for (src = 0; src < GPG_ERR_SOURCE_DIM; src++)
+	{
+	  const char *src_sym;
+
+	  src_sym = gpg_strsource_sym (src << GPG_ERR_SOURCE_SHIFT);
+	  if (src_sym && !strcasecmp (str, src_sym + sizeof (src_prefix) - 1))
+	    {
+	      *err |= src << GPG_ERR_SOURCE_SHIFT;
+	      return 1;
+	    }
+	}
+    }
+  else if (!strncasecmp (code_prefix, str, sizeof (code_prefix) - 1))
+    {
+      gpg_err_code_t code;
+
+      if (*have_code)
+	return 0;
+      *have_code = 1;
+      str += sizeof (code_prefix) - 1;
+
+      for (code = 0; code < GPG_ERR_CODE_DIM; code++)
+	{
+	  const char *code_sym = gpg_strerror_sym (code);
+	  if (code_sym
+	      && !strcasecmp (str, code_sym + sizeof (code_prefix) - 1))
+	    {
+	      *err |= code;
+	      return 1;
+	    }
+	}
+    }
+  return 0;
+}
+
+
+/* Parse string STR assuming it is either a single symbol C or in the
+ * form S.C to denote an error source symbold S and and error code
+ * symbold C.  Returns false on error (e.g. invalid number) or true
+ * for valid codes; if true is returned a full error code is stored at
+ * ERR.  */
+static int
+get_err_from_symbol (char *str, gpg_error_t *err)
+{
+  char *str2 = str;
+  int have_source = 0;
+  int have_code = 0;
+  int ret;
+  char *saved_pos = NULL;
+  char saved_char;
+
+  *err = 0;
+  while (*str2 && ((*str2 >= 'A' && *str2 <= 'Z')
+		   || (*str2 >= '0' && *str2 <= '9')
+		   || *str2 == '_'))
+    str2++;
+  if (*str2)
+    {
+      saved_pos = str2;
+      saved_char = *str2;
+      *str2 = '\0';
+      str2++;
+    }
+  else
+    str2 = NULL;
+
+  ret = get_err_from_symbol_one (str, err, &have_source, &have_code);
+  if (ret && str2)
+    ret = get_err_from_symbol_one (str2, err, &have_source, &have_code);
+
+  if (saved_pos)
+    *saved_pos = saved_char;
+  return ret;
+}
+
+
+/* Parse string STR assuming it partial code symbol and store its
+ * value at ERR and return true.  */
+static int
+get_err_from_codesymbol (char *str, gpg_error_t *err)
+{
+  static const char code_prefix[] = "GPG_ERR_";
+  gpg_err_code_t code;
+
+  *err = 0;
+
+  /* Skip an optional prefix.  */
+  if (!strncasecmp (code_prefix, str, sizeof (code_prefix) - 1))
+    str += sizeof (code_prefix) - 1;
+
+  for (code = 0; code < GPG_ERR_CODE_DIM; code++)
+    {
+      const char *code_sym = gpg_strerror_sym (code);
+      if (code_sym
+          && !strcasecmp (str, code_sym + sizeof (code_prefix) - 1))
+        {
+          *err |= code;
+          return 1;
+        }
+    }
+  return 0;
+}
+
+
+/* Helper function to parse a string which maps back to a source or
+ * code value.  If no source or code for the symbold is available
+ * false is return; else the source or code value is ORed into the
+ * value at ERR (shifted for a GPG_ERR_SOURCE_) and true returned.
+ * The match is first tried on source values and then on code values.
+ * HAVE_SOURCE and HAVE_CODE are expected to be addresses where a 0 is
+ * stored; a 1 is stored at the respective address to mark whether a
+ * code or source value was found.  If one of those state variables
+ * already point to a true value the function will return 0 and not
+ * change the value at ERR.  */
+static int
+get_err_from_str_one (char *str, gpg_error_t *err,
+		      int *have_source, int *have_code)
+{
+  gpg_err_source_t src;
+  gpg_err_code_t code;
+
+  for (src = 0; src < GPG_ERR_SOURCE_DIM; src++)
+    {
+      const char *src_str = gpg_strsource (src << GPG_ERR_SOURCE_SHIFT);
+      if (src_str && !strcasecmp (str, src_str))
+	{
+	  if (*have_source)
+	    return 0;
+
+	  *have_source = 1;
+	  *err |= src << GPG_ERR_SOURCE_SHIFT;
+	  return 1;
+	}
+    }
+
+  for (code = 0; code < GPG_ERR_CODE_DIM; code++)
+    {
+      const char *code_str = gpg_strerror (code);
+      if (code_str && !strcasecmp (str, code_str))
+	{
+	  if (*have_code)
+	    return 0;
+
+	  *have_code = 1;
+	  *err |= code;
+	  return 1;
+	}
+    }
+
+  return 0;
+}
+
+
+/* Parse string STR assuming it is either a single desription string C
+ * or in the form S.C to denote an error source descrition S and and
+ * error code description C.  Returns false on error (e.g. invalid
+ * symbol) or true for valid codes; if true is returned a full error
+ * code is stored at ERR.  */
+static int
+get_err_from_str (char *str, gpg_error_t *err)
+{
+  char *str2 = str;
+  int have_source = 0;
+  int have_code = 0;
+  int ret;
+  char *saved_pos = NULL;
+  char saved_char = 0; /* (avoid warning) */
+
+  *err = 0;
+  /* First match on the entire string to handle the case that it is
+   * code description with spaces.  */
+  ret = get_err_from_str_one (str, err, &have_source, &have_code);
+  if (ret)
+    return ret;
+
+  /* Then figure out whether the first string is a simple word.  */
+  while (*str2 && ((*str2 >= 'A' && *str2 <= 'Z')
+		   || (*str2 >= 'a' && *str2 <= 'z')
+		   || (*str2 >= '0' && *str2 <= '9')
+		   || *str2 == '_'))
+    str2++;
+  if (*str2)
+    {
+      saved_pos = str2;
+      saved_char = *str2;
+      *((char *) str2) = '\0';
+      str2++;
+      while (*str2 && !((*str2 >= 'A' && *str2 <= 'Z')
+			|| (*str2 >= 'a' && *str2 <= 'z')
+			|| (*str2 >= '0' && *str2 <= '9')
+			|| *str2 == '_'))
+	str2++;
+    }
+  else
+    str2 = NULL;
+
+  ret = get_err_from_str_one (str, err, &have_source, &have_code);
+  if (ret && str2)
+    ret = get_err_from_str_one (str2, err, &have_source, &have_code);
+
+  if (saved_pos)
+    *saved_pos = saved_char;
+  return ret;
+}
+
+
+static void
+print_desc (const char *symbol)
+{
+  static int initialized;
+  static FILE *fp;
+  char line[512];
+  char *p;
+  int indesc = 0;
+  int blanklines = 0;
+  int last_was_keyword = 0;
+
+  if (!symbol)
+    return;
+
+  if (!initialized)
+    {
+      initialized = 1;
+      fp = fopen (PKGDATADIR "/errorref.txt", "r");
+    }
+  if (!fp)
+    return;
+  rewind (fp);
+  while (fgets (line, sizeof line, fp))
+    {
+      if (*line == '#')
+        continue;
+      if (*line && line[strlen(line)-1] == '\n')
+        line[strlen(line)-1] = 0;
+
+      if (!strncmp (line, "GPG_ERR_", 8))
+        {
+          if (indesc == 1 && last_was_keyword)
+            continue; /* Skip keywords immediately following a matched
+                       * keyword.  */
+          last_was_keyword = 1;
+
+          indesc = 0;
+          p = strchr (line, ' ');
+          if (!p)
+            continue;
+          *p = 0;
+          if (!strcmp (line, symbol))
+            {
+              indesc = 1;
+              continue; /* Skip this line.  */
+            }
+        }
+      else
+        last_was_keyword = 0;
+      if (!indesc)
+        continue;
+      if (indesc == 1 && !*line)
+        continue; /* Skip leading empty lines in a description.  */
+      if (indesc == 1)
+        putchar ('\n'); /* One leading empty line.  */
+      indesc = 2;
+      if (!*line)
+        {
+          blanklines++;
+          continue;
+        }
+      for (; blanklines; blanklines--)
+        putchar ('\n');
+      printf ("%s\n", line);
+    }
+  putchar ('\n'); /* One trailing blank line.  */
+}
+
+
+
+
+
+static const char *
+my_strusage (int level)
+{
+  const char *p;
+
+  switch (level)
+    {
+    case  9: p = "LGPL-2.1-or-later"; break;
+
+    case 11: p = "gpg-error"; break;
+    case 12: p = PACKAGE_NAME; break;
+    case 13: p = PACKAGE_VERSION; break;
+    case 14: p = "Copyright (C) 2019 g10 Code GmbH"; break;
+    case 19: p = _("Please report bugs to <https://bugs.gnupg.org>.\n"); break;
+
+    case 1:
+    case 40:
+      p = ("Usage: gpg-error [options] error-numbers");
+      break;
+    case 41:
+      p = ("Map error numbers to strings and vice versa.\n");
+      break;
+
+    case 42:
+      p = "1"; /* Flag: print 40 as part of 41. */
+      break;
+
+    default: p = NULL; break;
+    }
+  return p;
+}
+
+
+
+int
+main (int argc, char *argv[])
+{
+  enum { CMD_DEFAULT     = 0,
+         CMD_LIB_VERSION = 501,
+         CMD_LIST,
+         CMD_DEFINES,
+         CMD_LOCALE,
+         OPT_DESC
+  };
+  static gpgrt_opt_t opts[] = {
+    ARGPARSE_c (CMD_LIB_VERSION, "lib-version",
+                "Print library version"),
+    ARGPARSE_c (CMD_LIST, "list",
+                "Print all error codes"),
+    ARGPARSE_c (CMD_DEFINES, "defines",
+                "Print all error codes as #define lines"),
+#if HAVE_W32_SYSTEM
+    ARGPARSE_c (CMD_LOCALE, "locale",
+                "Return the locale used for gettext"),
+#else
+    ARGPARSE_c (CMD_LOCALE, "locale",
+                "@"),
+#endif
+    ARGPARSE_s_n (OPT_DESC, "desc",
+                  "Print with error description"),
+    ARGPARSE_end()
+  };
+  gpgrt_argparse_t pargs = { &argc, &argv };
+
+  int i;
+  int libversion = 0;
+  int listmode = 0;
+  int localemode = 0;
+  int desc = 0;
+  const char *s, *s2;
+  const char *source_sym;
+  const char *error_sym;
+  gpg_error_t err;
+
+  gpgrt_init ();
+  i18n_init ();
+  gpgrt_set_strusage (my_strusage);
+  gpgrt_log_set_prefix (gpgrt_strusage (11), GPGRT_LOG_WITH_PREFIX);
+
+
+  while (gpgrt_argparse (NULL, &pargs, opts))
+    {
+      switch (pargs.r_opt)
+        {
+        case CMD_LIB_VERSION: libversion = 1; break;
+        case CMD_LIST:       listmode = 1; break;
+        case CMD_DEFINES:    listmode = 2; break;
+        case CMD_LOCALE:     localemode = 1; break;
+        case OPT_DESC:       desc = 1; break;
+        default: pargs.err = ARGPARSE_PRINT_WARNING; break;
+        }
+    }
+  gpgrt_argparse (NULL, &pargs, NULL);  /* Free internal memory.  */
+
+  if (libversion)
+    {
+      if (argc)
+        gpgrt_usage (1);
+    }
+  else if (localemode)
+    {
+      if (argc > 1)
+        gpgrt_usage (1);
+    }
+  else if ((argc && listmode) || (!argc && !listmode))
+    gpgrt_usage (1);
+
+
+  if (libversion)
+    {
+      argc--; argv++;
+      printf ("Version from header: %s (0x%06x)\n",
+              GPG_ERROR_VERSION, GPG_ERROR_VERSION_NUMBER);
+      printf ("Version from binary: %s\n", gpg_error_check_version (NULL));
+      s = gpg_error_check_version ("\x01\x01");
+      while (*s && *s == '\n')
+        s++;
+      fputs ("Copyright blurb ...: ", stdout);
+      for (; *s; s++)
+        {
+          if (*s == '\n')
+            {
+              for (s2=s+1; *s2 == '\n'; s2++)
+                ;
+              if (!*s2)
+                break;  /* Cut off trailing LFs.  */
+              fputs ("\n                     ", stdout);
+            }
+          else
+            putc (*s, stdout);
+        }
+      putc ('\n', stdout);
+    }
+  else if (localemode)
+    {
+#if HAVE_W32_SYSTEM
+      if (argc)
+        {
+          /* Warning: What we do here is not allowed because
+           * gpgrt_w32_override_locale needs to be called as early as
+           * possible.  However for this very purpose it is okay.  */
+          if (**argv >= '0' && **argv <= '9')
+            gpgrt_w32_override_locale (NULL, strtoul (*argv, NULL, 0));
+          else
+            gpgrt_w32_override_locale (*argv, 0);
+        }
+
+      printf ("%s\n", gettext_localename ());
+#else
+      log_info ("this command is only useful on Windows\n");
+#endif
+    }
+  else if (listmode == 1)
+    {
+      for (i=0; i <  GPG_ERR_SOURCE_DIM; i++)
+        {
+          /* We use error code 1 because gpg_err_make requires a
+             non-zero error code. */
+          err = gpg_err_make (i, 1);
+          err -= 1;
+	  source_sym = gpg_strsource_sym (err);
+          if (source_sym)
+            {
+              printf ("%u = (%u, -) = (%s, -) = (%s, -)\n",
+                      err, gpg_err_source (err),
+                      source_sym, gpg_strsource (err));
+              if (desc)
+                print_desc (source_sym);
+            }
+        }
+      for (i=0; i <  GPG_ERR_CODE_DIM; i++)
+        {
+          err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i);
+	  error_sym = gpg_strerror_sym (err);
+          if (error_sym)
+            {
+              printf ("%u = (-, %u) = (-, %s) = (-, %s)\n",
+                      err, gpg_err_code (err),
+                      error_sym, gpg_strerror (err));
+              if (desc)
+                print_desc (error_sym);
+            }
+        }
+    }
+  else if (listmode == 2)
+    {
+      int n, nmax;
+
+      for (i=0, nmax=0; i <  GPG_ERR_SOURCE_DIM; i++)
+        {
+          err = gpg_err_make (i, 1);
+	  source_sym = gpg_strsource_sym (err);
+          if (source_sym)
+            {
+              n = strlen (source_sym);
+              if (n > nmax)
+                nmax = n;
+            }
+        }
+      for (i=0; i <  GPG_ERR_SOURCE_DIM; i++)
+        {
+          err = gpg_err_make (i, 1);
+	  source_sym = gpg_strsource_sym (err);
+          if (source_sym)
+            printf ("#define %-*s %3u\n", nmax,source_sym,gpg_err_source (err));
+        }
+
+
+      for (i=0, nmax = 0; i <  GPG_ERR_CODE_DIM; i++)
+        {
+          err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i);
+	  error_sym = gpg_strerror_sym (err);
+          if (error_sym)
+            {
+              n = strlen (error_sym);
+              if (n > nmax)
+                nmax = n;
+            }
+        }
+      for (i=0; i <  GPG_ERR_CODE_DIM; i++)
+        {
+          err = gpg_err_make (GPG_ERR_SOURCE_UNKNOWN, i);
+	  error_sym = gpg_strerror_sym (err);
+          if (error_sym)
+            printf ("#define %-*s %5u\n", nmax, error_sym, gpg_err_code (err));
+        }
+    }
+  else /* Standard mode.  */
+    {
+      for (i=0; i < argc; i++)
+        {
+          /* First check the arg is a number N or K.N,
+           * then check the arg for CODESYM or SOURCESYM.CODESYM,
+           * then check the arg for CODESYM or CODESYM w/o GPG_ERR_ prefix,
+           * then check the arg for code description
+           *                     or symbol dot code description.
+           */
+          if (get_err_from_number (argv[i], &err)
+              || get_err_from_symbol (argv[i], &err)
+              || get_err_from_codesymbol (argv[i], &err)
+              || get_err_from_str (argv[i], &err))
+            {
+              source_sym = gpg_strsource_sym (err);
+              error_sym = gpg_strerror_sym (err);
+
+              printf ("%u = (%u, %u) = (%s, %s) = (%s, %s)\n",
+                      err, gpg_err_source (err), gpg_err_code (err),
+                      source_sym ? source_sym : "-", error_sym ? error_sym:"-",
+                      gpg_strsource (err), gpg_strerror (err));
+              if (desc)
+                print_desc (error_sym);
+            }
+          else
+            log_error (_("warning: could not recognize %s\n"), argv[i]);
+        }
+    }
+
+  exit (0);
+}