#include "kmp_i18n.h"
#include "kmp.h"
#include "kmp_debug.h"
#include "kmp_io.h"
#include "kmp_lock.h"
#include "kmp_os.h"
#include <errno.h>
#include <locale.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "kmp_environment.h"
#include "kmp_i18n_default.inc"
#include "kmp_str.h"
#undef KMP_I18N_OK
#define get_section(id) …
#define get_number(id) …
kmp_msg_t __kmp_msg_null = …;
static char const *no_message_available = …;
static void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message,
va_list ap);
enum kmp_i18n_cat_status { … };
kmp_i18n_cat_status_t;
static volatile kmp_i18n_cat_status_t status = …;
static void __kmp_i18n_do_catopen();
static kmp_bootstrap_lock_t lock = …;
void __kmp_i18n_catopen() { … }
#if KMP_OS_UNIX
#define KMP_I18N_OK
#include <nl_types.h>
#define KMP_I18N_NULLCAT …
static nl_catd cat = …;
static char const *name = …;
void __kmp_i18n_do_catopen() { … }
void __kmp_i18n_catclose() { … }
char const *__kmp_i18n_catgets(kmp_i18n_id_t id) { … }
#endif
#if KMP_OS_WINDOWS
#define KMP_I18N_OK
#include "kmp_environment.h"
#include <windows.h>
#define KMP_I18N_NULLCAT …
static HMODULE cat = KMP_I18N_NULLCAT;
static char const *name =
(KMP_VERSION_MAJOR == 4 ? "libguide40ui.dll" : "libompui.dll");
static kmp_i18n_table_t table = {0, NULL};
static UINT const default_code_page = CP_OEMCP;
static UINT code_page = default_code_page;
static char const *___catgets(kmp_i18n_id_t id);
static UINT get_code_page();
static void kmp_i18n_table_free(kmp_i18n_table_t *table);
static UINT get_code_page() {
UINT cp = default_code_page;
char const *value = __kmp_env_get("KMP_CODEPAGE");
if (value != NULL) {
if (_stricmp(value, "ANSI") == 0) {
cp = CP_ACP;
} else if (_stricmp(value, "OEM") == 0) {
cp = CP_OEMCP;
} else if (_stricmp(value, "UTF-8") == 0 || _stricmp(value, "UTF8") == 0) {
cp = CP_UTF8;
} else if (_stricmp(value, "UTF-7") == 0 || _stricmp(value, "UTF7") == 0) {
cp = CP_UTF7;
} else {
}
}
KMP_INTERNAL_FREE((void *)value);
return cp;
}
static void kmp_i18n_table_free(kmp_i18n_table_t *table) {
int s;
int m;
for (s = 0; s < table->size; ++s) {
for (m = 0; m < table->sect[s].size; ++m) {
KMP_INTERNAL_FREE((void *)table->sect[s].str[m]);
table->sect[s].str[m] = NULL;
}
table->sect[s].size = 0;
KMP_INTERNAL_FREE((void *)table->sect[s].str);
table->sect[s].str = NULL;
}
table->size = 0;
KMP_INTERNAL_FREE((void *)table->sect);
table->sect = NULL;
}
void __kmp_i18n_do_catopen() {
LCID locale_id = GetThreadLocale();
WORD lang_id = LANGIDFROMLCID(locale_id);
WORD primary_lang_id = PRIMARYLANGID(lang_id);
kmp_str_buf_t path;
KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);
KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);
__kmp_str_buf_init(&path);
if (primary_lang_id == LANG_ENGLISH) {
status = KMP_I18N_ABSENT;
goto end;
}
{
HMODULE handle;
BOOL brc = GetModuleHandleEx(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
reinterpret_cast<LPCSTR>(&__kmp_i18n_do_catopen), &handle);
if (!brc) {
status = KMP_I18N_ABSENT;
goto end;
}
for (;;) {
DWORD drc = GetModuleFileName(handle, path.str, path.size);
if (drc == 0) {
status = KMP_I18N_ABSENT;
goto end;
}
if (drc < path.size) {
path.used = drc;
break;
}
__kmp_str_buf_reserve(&path, path.size * 2);
}
kmp_str_fname fname;
__kmp_str_fname_init(&fname, path.str);
__kmp_str_buf_clear(&path);
__kmp_str_buf_print(&path, "%s%lu/%s", fname.dir,
(unsigned long)(locale_id), name);
__kmp_str_fname_free(&fname);
}
cat = LoadLibraryEx(path.str, NULL, LOAD_LIBRARY_AS_DATAFILE);
status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);
if (status == KMP_I18N_ABSENT) {
if (__kmp_generate_warnings > kmp_warnings_low) {
DWORD error = GetLastError();
kmp_msg_t err_code = KMP_SYSERRCODE(error);
__kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, path.str),
err_code,
(error == ERROR_BAD_EXE_FORMAT
? KMP_HNT(BadExeFormat, path.str, KMP_ARCH_STR)
: __kmp_msg_null),
__kmp_msg_null);
if (__kmp_generate_warnings == kmp_warnings_off) {
__kmp_str_free(&err_code.str);
}
KMP_INFORM(WillUseDefaultMessages);
}
} else {
int section = get_section(kmp_i18n_prp_Version);
int number = get_number(kmp_i18n_prp_Version);
char const *expected = __kmp_i18n_default_table.sect[section].str[number];
kmp_str_buf_t version;
__kmp_str_buf_init(&version);
__kmp_str_buf_print(&version, "%s", ___catgets(kmp_i18n_prp_Version));
if (strcmp(version.str, expected) != 0) {
__kmp_i18n_catclose();
status = KMP_I18N_ABSENT;
if (__kmp_generate_warnings > kmp_warnings_low) {
__kmp_msg(kmp_ms_warning,
KMP_MSG(WrongMessageCatalog, path.str, version.str, expected),
__kmp_msg_null);
KMP_INFORM(WillUseDefaultMessages);
}
}
__kmp_str_buf_free(&version);
}
code_page = get_code_page();
end:
__kmp_str_buf_free(&path);
return;
}
void __kmp_i18n_catclose() {
if (status == KMP_I18N_OPENED) {
KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
kmp_i18n_table_free(&table);
FreeLibrary(cat);
cat = KMP_I18N_NULLCAT;
}
code_page = default_code_page;
status = KMP_I18N_CLOSED;
}
static int ___strip_crs(char *str) {
int in = 0;
int out = 0;
for (;;) {
if (str[in] != '\r') {
str[out] = str[in];
++out;
}
if (str[in] == 0) {
break;
}
++in;
}
return out - 1;
}
static char const *___catgets(kmp_i18n_id_t id) {
char *result = NULL;
PVOID addr = NULL;
wchar_t *wmsg = NULL;
DWORD wlen = 0;
char *msg = NULL;
int len = 0;
int rc;
KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
wlen =
FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_IGNORE_INSERTS,
cat, id,
0,
(LPWSTR)&addr,
0,
NULL);
if (wlen <= 0) {
goto end;
}
wmsg = (wchar_t *)addr;
len = WideCharToMultiByte(code_page,
0,
wmsg, wlen,
NULL, 0,
NULL, NULL
);
if (len <= 0) {
goto end;
}
msg = (char *)KMP_INTERNAL_MALLOC(len + 1);
rc = WideCharToMultiByte(code_page,
0,
wmsg, wlen,
msg, len,
NULL, NULL
);
if (rc <= 0 || rc > len) {
goto end;
}
KMP_DEBUG_ASSERT(rc == len);
len = rc;
msg[len] = 0;
len = ___strip_crs(msg);
if (len >= 1 && msg[len - 1] == '\n') {
--len;
msg[len] = 0;
}
result = msg;
msg = NULL;
end:
if (msg != NULL) {
KMP_INTERNAL_FREE(msg);
}
if (wmsg != NULL) {
LocalFree(wmsg);
}
return result;
}
char const *__kmp_i18n_catgets(kmp_i18n_id_t id) {
int section = get_section(id);
int number = get_number(id);
char const *message = NULL;
if (1 <= section && section <= __kmp_i18n_default_table.size) {
if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {
if (status == KMP_I18N_CLOSED) {
__kmp_i18n_catopen();
}
if (cat != KMP_I18N_NULLCAT) {
if (table.size == 0) {
table.sect = (kmp_i18n_section_t *)KMP_INTERNAL_CALLOC(
(__kmp_i18n_default_table.size + 2), sizeof(kmp_i18n_section_t));
table.size = __kmp_i18n_default_table.size;
}
if (table.sect[section].size == 0) {
table.sect[section].str = (const char **)KMP_INTERNAL_CALLOC(
__kmp_i18n_default_table.sect[section].size + 2,
sizeof(char const *));
table.sect[section].size =
__kmp_i18n_default_table.sect[section].size;
}
if (table.sect[section].str[number] == NULL) {
table.sect[section].str[number] = ___catgets(id);
}
message = table.sect[section].str[number];
}
if (message == NULL) {
message = __kmp_i18n_default_table.sect[section].str[number];
}
}
}
if (message == NULL) {
message = no_message_available;
}
return message;
}
#endif
#ifndef KMP_I18N_OK
#error I18n support is not implemented for this OS.
#endif
void __kmp_i18n_dump_catalog(kmp_str_buf_t *buffer) { … }
kmp_msg_t __kmp_msg_format(unsigned id_arg, ...) { … }
static char *sys_error(int err) { … }
kmp_msg_t __kmp_msg_error_code(int code) { … }
kmp_msg_t __kmp_msg_error_mesg(char const *mesg) { … }
void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, va_list args) { … }
void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, ...) { … }
void __kmp_fatal(kmp_msg_t message, ...) { … }