/* * Copyright (C) 2008 Tor Lillqvist * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; see the file COPYING.LIB.txt. If * not, write to the Free Software Foundation, Inc., 51 Franklin * Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifdef _WIN32 # include # include #else # include # if !STUB_ONLY # include # endif typedef void* HMODULE; #endif #include #include "libintl.h" int _nl_msg_cat_cntr; /* So that configury thinks it is GNU * gettext */ static char * (*p_gettext) (const char *msgid); static char * (*p_dgettext) (const char *domainname, const char *msgid); static char * (*p_dcgettext) (const char *domainname, const char *msgid, int category); static char * (*p_ngettext) (const char *msgid1, const char *msgid2, unsigned long int n); static char * (*p_dngettext) (const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n); static char * (*p_dcngettext) (const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n, int category); static char * (*p_textdomain) (const char *domainname); static char * (*p_bindtextdomain) (const char *domainname, const char *dirname); static char * (*p_bind_textdomain_codeset) (const char *domainname, const char *codeset); static int use_intl_dll (HMODULE dll) { #if !STUB_ONLY # ifdef _WIN32 # define LOOKUP(fn) p_##fn = (void *) GetProcAddress (dll, #fn); if (p_##fn == NULL) return 0 # else # define LOOKUP(fn) p_##fn = (void *) dlsym (dll, #fn); if (p_##fn == NULL) return 0 # endif /* _WIN32 */ LOOKUP (gettext); LOOKUP (dgettext); LOOKUP (dcgettext); LOOKUP (ngettext); LOOKUP (dngettext); LOOKUP (dcngettext); LOOKUP (textdomain); LOOKUP (bindtextdomain); LOOKUP (bind_textdomain_codeset); #undef LOOKUP #endif /* !STUB_ONLY */ return 1; } static char *current_domain = NULL; #define DUMMY(fn, parlist, retval) \ static char * \ dummy_##fn parlist \ { \ return (char *) (retval); \ } DUMMY (gettext, (const char *msgid), msgid) DUMMY (dgettext, (const char *domainname, const char *msgid), msgid) DUMMY (dcgettext, (const char *domainname, const char *msgid, int category), msgid) DUMMY (ngettext, (const char *msgid1, const char *msgid2, unsigned long int n), n == 1 ? msgid1 : msgid2) DUMMY (dngettext, (const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n), n == 1 ? msgid1 : msgid2) DUMMY (dcngettext, (const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n, int category), n == 1 ? msgid1 : msgid2) /* GLib requires that textdomain(NULL) returns "messages" * if textdomain() hasn't been called earlier. */ DUMMY (textdomain, (const char *domainname), (domainname ? (free(current_domain), current_domain = _strdup(domainname)) : (current_domain ? current_domain : (current_domain = _strdup ("messages"))))) /* bindtextdomain() should return the current dirname for the domain, * after possibly changing it. I don't think software usually checks * the return value, though, so just return a dummy string now. This * is the dummy implementation after all, so it hardly matters? */ DUMMY (bindtextdomain, (const char *domainname, const char *dirname), "/dummy") /* bind_textdomain_codeset() should return the corrent codeset for the * domain after possibly changing it. Again, this is the dummy * implementation, so just return the codeset argument. */ DUMMY (bind_textdomain_codeset, (const char *domainname, const char *codeset), codeset) #undef DUMMY static void use_dummy (void) { #define USE_DUMMY(fn) p_##fn = dummy_##fn USE_DUMMY (gettext); USE_DUMMY (dgettext); USE_DUMMY (dcgettext); USE_DUMMY (ngettext); USE_DUMMY (dngettext); USE_DUMMY (dcngettext); USE_DUMMY (textdomain); USE_DUMMY (bindtextdomain); USE_DUMMY (bind_textdomain_codeset); #undef USE_DUMMY } #ifdef _WIN32 /* To reduce DLL hijacking risk we look for the libintl DLL in * explicit full paths. We look in two places: The the directory of * the application's exe file, then the directory of the DLL this code * is in. (Those two might be the same, of course, but we don't bother * testing that.) */ static HMODULE try_load_from_directory_of_module (HMODULE module, const char *dll_name) { wchar_t buf[MAX_PATH*2]; wchar_t *slash; int n; n = GetModuleFileNameW (module, buf, MAX_PATH); if (n == 0 || n == MAX_PATH) return NULL; slash = wcsrchr (buf, L'\\'); if (slash) *slash = L'\0'; wcscat (buf, L"\\"); MultiByteToWideChar (CP_ACP, 0, dll_name, -1, buf + wcslen (buf), MAX_PATH); return LoadLibraryW (buf); } static HMODULE try_load (const char *dll_name) { HMODULE retval = NULL; HMODULE this_module = NULL; typedef BOOL (WINAPI *GetModuleHandleExA_t) (DWORD, LPVOID, HMODULE *); GetModuleHandleExA_t GetModuleHandleExA_p; retval = try_load_from_directory_of_module (GetModuleHandle (NULL), dll_name); if (retval) return retval; GetModuleHandleExA_p = (GetModuleHandleExA_t) GetProcAddress (GetModuleHandle ("kernel32.dll"), "GetModuleHandleExA"); if (GetModuleHandleExA_p == NULL || !(*GetModuleHandleExA_p) (GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, &try_load, &this_module)) { /* If GetModuleHandleExA() fails, or if it isn't present, use * heuristics that the module handle equals the allocation base * address for the module's code region. */ MEMORY_BASIC_INFORMATION mbi; if (VirtualQuery (&try_load, &mbi, sizeof (mbi))) this_module = (HMODULE) mbi.AllocationBase; } if (this_module) retval = try_load_from_directory_of_module (this_module, dll_name); return retval; } #endif static void setup (void) { static int beenhere = 0; if (!beenhere) { #if !STUB_ONLY #if defined(_WIN64) /* On 64-bit Windows we have let libtool choose the default name * for the DLL, as we don't need the intl.dll name for backward * compatibility */ HMODULE intl_dll = try_load ("libintl-8.dll"); # elif defined( _WIN32) /* On 32-bit Windows try both the traditional name intl.dll, * and libintl-8.dll. */ HMODULE intl_dll = try_load ("intl.dll"); if (intl_dll == NULL) intl_dll = try_load ("libintl-8.dll"); # elif defined(__APPLE__) && defined(__MACH__) HMODULE intl_dll = dlopen ("libintl.dylib", RTLD_LAZY); # else HMODULE intl_dll = dlopen ("libintl.so", RTLD_LAZY); # endif #else /* !STUB_ONLY */ HMODULE intl_dll = NULL; #endif /* STUB_ONLY */ if (intl_dll != NULL && use_intl_dll (intl_dll)) ; else use_dummy (); beenhere = 1; } } #define IMPLEMENT(fn, parlist, parlist2) \ char * \ fn parlist \ { \ setup (); \ return p_##fn parlist2; \ } IMPLEMENT (gettext, (const char *msgid), (msgid)) IMPLEMENT (dgettext, (const char *domainname, const char *msgid), (domainname, msgid)) IMPLEMENT (dcgettext, (const char *domainname, const char *msgid, int category), (domainname, msgid, category)) IMPLEMENT (ngettext, (const char *msgid1, const char *msgid2, unsigned long int n), (msgid1, msgid2, n)) IMPLEMENT (dngettext, (const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n), (domainname, msgid1, msgid2, n)) IMPLEMENT (dcngettext, (const char *domainname, const char *msgid1, const char *msgid2, unsigned long int n, int category), (domainname, msgid1, msgid2, n, category)) IMPLEMENT (textdomain, (const char *domainname), (domainname)) IMPLEMENT (bindtextdomain, (const char *domainname, const char *dirname), (domainname, dirname)) IMPLEMENT (bind_textdomain_codeset, (const char *domainname, const char *codeset), (domainname, codeset)) #undef IMPLEMENT