#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "gpgrt-int.h"
#include "gettext.h"
#include "init.h"
#ifdef HAVE_W32CE_SYSTEM
# include "mkw32errmap.map.c"
# ifndef TLS_OUT_OF_INDEXES
# define TLS_OUT_OF_INDEXES 0xFFFFFFFF
# endif
# ifndef __MINGW32CE__
#
# define abort() do { TerminateProcess (GetCurrentProcess(), 8); } while (0)
# endif
#endif
#if HAVE_W32_SYSTEM
#include <windows.h>
static int tls_index = TLS_OUT_OF_INDEXES;
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 *(*custom_realloc)(void *a, size_t n);
static void
real_init (void)
{
#ifdef ENABLE_NLS
char *locale_dir;
locale_dir = get_locale_dir ();
if (locale_dir)
{
bindtextdomain (PACKAGE, locale_dir);
drop_locale_dir (locale_dir);
}
#endif
_gpgrt_estream_init ();
}
gpg_error_t
_gpg_err_init (void)
{
#ifdef HAVE_W32_SYSTEM
# ifdef DLL_EXPORT
# else
if (tls_index == TLS_OUT_OF_INDEXES)
{
tls_index = TlsAlloc ();
if (tls_index == TLS_OUT_OF_INDEXES)
{
abort ();
}
_gpg_w32__init_gettext_module ();
real_init ();
}
# endif
#else
real_init ();
#endif
return 0;
}
void
_gpg_err_deinit (int mode)
{
#if defined (HAVE_W32_SYSTEM) && !defined(DLL_EXPORT)
struct tls_space_s *tls;
tls = TlsGetValue (tls_index);
if (tls)
{
TlsSetValue (tls_index, NULL);
LocalFree (tls);
}
if (mode == 0)
{
TlsFree (tls_index);
tls_index = TLS_OUT_OF_INDEXES;
}
#else
(void)mode;
#endif
}
void
_gpgrt_set_alloc_func (void *(*f)(void *a, size_t n))
{
custom_realloc = f;
}
void *
_gpgrt_realloc (void *a, size_t n)
{
if (custom_realloc)
return custom_realloc (a, n);
if (!n)
{
free (a);
return NULL;
}
if (!a)
return malloc (n);
return realloc (a, n);
}
void *
_gpgrt_malloc (size_t n)
{
if (!n)
n++;
return _gpgrt_realloc (NULL, n);
}
void
_gpgrt_free (void *a)
{
_gpgrt_realloc (a, 0);
}
void
_gpg_err_set_errno (int err)
{
#ifdef HAVE_W32CE_SYSTEM
SetLastError (err);
#else
errno = err;
#endif
}
static FILE *trace_fp;
static int trace_save_errno;
static int trace_with_errno;
static const char *trace_arg_module;
static const char *trace_arg_file;
static int trace_arg_line;
static int trace_missing_lf;
static int trace_prefix_done;
void
_gpgrt_internal_trace_begin (const char *module, const char *file, int line,
int with_errno)
{
int save_errno = errno;
if (!trace_fp)
{
FILE *fp;
const char *s = getenv ("GPGRT_TRACE_FILE");
if (!s || !(fp = fopen (s, "wb")))
fp = stderr;
trace_fp = fp;
}
#ifdef HAVE_FLOCKFILE
flockfile (trace_fp);
#endif
trace_save_errno = save_errno;
trace_with_errno = with_errno;
trace_arg_module = module;
trace_arg_file = file;
trace_arg_line = line;
trace_missing_lf = 0;
trace_prefix_done = 0;
}
static void
print_internal_trace_prefix (void)
{
if (!trace_prefix_done)
{
trace_prefix_done = 1;
fprintf (trace_fp, "%s:%s:%d: ",
trace_arg_module,
trace_arg_file, trace_arg_line);
}
}
static void
do_internal_trace (const char *format, va_list arg_ptr)
{
print_internal_trace_prefix ();
vfprintf (trace_fp, format, arg_ptr);
if (trace_with_errno)
fprintf (trace_fp, " errno=%s", strerror (trace_save_errno));
if (*format && format[strlen(format)-1] != '\n')
fputc ('\n', trace_fp);
}
void
_gpgrt_internal_trace_printf (const char *format, ...)
{
va_list arg_ptr;
print_internal_trace_prefix ();
va_start (arg_ptr, format) ;
vfprintf (trace_fp, format, arg_ptr);
va_end (arg_ptr);
trace_missing_lf = (*format && format[strlen(format)-1] != '\n');
}
void
_gpgrt_internal_trace (const char *format, ...)
{
va_list arg_ptr;
va_start (arg_ptr, format) ;
do_internal_trace (format, arg_ptr);
va_end (arg_ptr);
}
void
_gpgrt_internal_trace_end (void)
{
int save_errno = trace_save_errno;
if (trace_missing_lf)
fputc ('\n', trace_fp);
#ifdef HAVE_FLOCKFILE
funlockfile (trace_fp);
#endif
errno = save_errno;
}
#ifdef HAVE_W32_SYSTEM
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;
p = strrchr (result, '\\');
if (p && !strcmp (p+1, "bin"))
*p = 0;
strcat (result, SLDIR);
}
}
}
else
{
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);
}
struct tls_space_s *
get_tls (void)
{
struct tls_space_s *tls;
tls = TlsGetValue (tls_index);
if (!tls)
{
tls = LocalAlloc (LPTR, sizeof *tls);
if (!tls)
{
abort ();
}
tls->gt_use_utf8 = 0;
TlsSetValue (tls_index, tls);
}
return tls;
}
#ifdef HAVE_W32CE_SYSTEM
int
_gpg_w32ce_get_errno (void)
{
return map_w32codes ( GetLastError () );
}
#endif
#ifdef HAVE_W32CE_SYSTEM
char *
_gpg_w32ce_strerror (int err)
{
struct tls_space_s *tls = get_tls ();
wchar_t tmpbuf[STRBUFFER_SIZE];
int n;
if (err == -1)
err = _gpg_w32ce_get_errno ();
if (FormatMessageW (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
tmpbuf, STRBUFFER_SIZE -1,
NULL))
{
n = WideCharToMultiByte (CP_UTF8, 0, tmpbuf, -1,
tls->strerror_buffer,
sizeof tls->strerror_buffer -1,
NULL, NULL);
}
else
n = -1;
if (n < 0)
snprintf (tls->strerror_buffer, sizeof tls->strerror_buffer -1,
"[w32err=%d]", err);
return tls->strerror_buffer;
}
#endif
#ifdef DLL_EXPORT
int WINAPI
DllMain (HINSTANCE hinst, DWORD reason, LPVOID reserved)
{
struct tls_space_s *tls;
(void)reserved;
(void)hinst;
switch (reason)
{
case DLL_PROCESS_ATTACH:
tls_index = TlsAlloc ();
if (tls_index == TLS_OUT_OF_INDEXES)
return FALSE;
#ifndef _GPG_ERR_HAVE_CONSTRUCTOR
_gpg_w32__init_gettext_module ();
#endif
case DLL_THREAD_ATTACH:
tls = LocalAlloc (LPTR, sizeof *tls);
if (!tls)
return FALSE;
tls->gt_use_utf8 = 0;
TlsSetValue (tls_index, tls);
if (reason == DLL_PROCESS_ATTACH)
{
real_init ();
}
break;
case DLL_THREAD_DETACH:
tls = TlsGetValue (tls_index);
if (tls)
LocalFree (tls);
break;
case DLL_PROCESS_DETACH:
tls = TlsGetValue (tls_index);
if (tls)
LocalFree (tls);
TlsFree (tls_index);
break;
default:
break;
}
return TRUE;
}
#endif
#endif