blob: fa868ae0bf02b43849ac8abcfa42c34100a1a560 [file] [log] [blame]
/* gpg-error.c - Determining gpg-error error codes.
Copyright (C) 2004 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);
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;
}
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;
}
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;
}
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;
}
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;
*err = 0;
ret = get_err_from_str_one (str, err, &have_source, &have_code);
if (ret)
return ret;
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;
}
int
main (int argc, char *argv[])
{
int i = 1;
int listmode = 0;
const char *source_sym;
const char *error_sym;
gpg_error_t err;
#ifndef GPG_ERR_INITIALIZED
gpg_err_init ();
#endif
i18n_init ();
if (argc == 1)
{
fprintf (stderr, _("Usage: %s GPG-ERROR [...]\n"),
strrchr (argv[0],'/')? (strrchr (argv[0], '/')+1): argv[0]);
exit (1);
}
else if (argc == 2 && !strcmp (argv[1], "--version"))
{
fputs ("gpg-error (" PACKAGE_NAME ") " PACKAGE_VERSION "\n", stdout);
exit (0);
}
else if (argc == 2 && !strcmp (argv[1], "--list"))
{
listmode = 1;
}
if (listmode)
{
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));
}
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));
}
i = argc; /* Don't run the usual stuff. */
}
while (i < argc)
{
if (get_err_from_number (argv[i], &err)
|| get_err_from_symbol (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));
}
else
fprintf (stderr, _("%s: warning: could not recognize %s\n"),
argv[0], argv[i]);
i++;
}
exit (0);
}