10b57cec5SDimitry Andric /*
20b57cec5SDimitry Andric * kmp_i18n.cpp
30b57cec5SDimitry Andric */
40b57cec5SDimitry Andric
50b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
80b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
90b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "kmp_i18n.h"
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric #include "kmp.h"
160b57cec5SDimitry Andric #include "kmp_debug.h"
170b57cec5SDimitry Andric #include "kmp_io.h" // __kmp_printf.
180b57cec5SDimitry Andric #include "kmp_lock.h"
190b57cec5SDimitry Andric #include "kmp_os.h"
200b57cec5SDimitry Andric
210b57cec5SDimitry Andric #include <errno.h>
220b57cec5SDimitry Andric #include <locale.h>
230b57cec5SDimitry Andric #include <stdarg.h>
240b57cec5SDimitry Andric #include <stdio.h>
250b57cec5SDimitry Andric #include <string.h>
260b57cec5SDimitry Andric
270b57cec5SDimitry Andric #include "kmp_environment.h"
280b57cec5SDimitry Andric #include "kmp_i18n_default.inc"
290b57cec5SDimitry Andric #include "kmp_str.h"
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric #undef KMP_I18N_OK
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric #define get_section(id) ((id) >> 16)
340b57cec5SDimitry Andric #define get_number(id) ((id)&0xFFFF)
350b57cec5SDimitry Andric
360b57cec5SDimitry Andric kmp_msg_t __kmp_msg_null = {kmp_mt_dummy, 0, NULL, 0};
370b57cec5SDimitry Andric static char const *no_message_available = "(No message available)";
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric static void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message,
400b57cec5SDimitry Andric va_list ap);
410b57cec5SDimitry Andric
420b57cec5SDimitry Andric enum kmp_i18n_cat_status {
430b57cec5SDimitry Andric KMP_I18N_CLOSED, // Not yet opened or closed.
440b57cec5SDimitry Andric KMP_I18N_OPENED, // Opened successfully, ready to use.
450b57cec5SDimitry Andric KMP_I18N_ABSENT // Opening failed, message catalog should not be used.
460b57cec5SDimitry Andric }; // enum kmp_i18n_cat_status
470b57cec5SDimitry Andric typedef enum kmp_i18n_cat_status kmp_i18n_cat_status_t;
480b57cec5SDimitry Andric static volatile kmp_i18n_cat_status_t status = KMP_I18N_CLOSED;
490b57cec5SDimitry Andric
500b57cec5SDimitry Andric /* Message catalog is opened at first usage, so we have to synchronize opening
510b57cec5SDimitry Andric to avoid race and multiple openings.
520b57cec5SDimitry Andric
530b57cec5SDimitry Andric Closing does not require synchronization, because catalog is closed very late
540b57cec5SDimitry Andric at library shutting down, when no other threads are alive. */
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric static void __kmp_i18n_do_catopen();
570b57cec5SDimitry Andric static kmp_bootstrap_lock_t lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(lock);
580b57cec5SDimitry Andric // `lock' variable may be placed into __kmp_i18n_catopen function because it is
590b57cec5SDimitry Andric // used only by that function. But we afraid a (buggy) compiler may treat it
600b57cec5SDimitry Andric // wrongly. So we put it outside of function just in case.
610b57cec5SDimitry Andric
__kmp_i18n_catopen()620b57cec5SDimitry Andric void __kmp_i18n_catopen() {
630b57cec5SDimitry Andric if (status == KMP_I18N_CLOSED) {
640b57cec5SDimitry Andric __kmp_acquire_bootstrap_lock(&lock);
650b57cec5SDimitry Andric if (status == KMP_I18N_CLOSED) {
660b57cec5SDimitry Andric __kmp_i18n_do_catopen();
670b57cec5SDimitry Andric }
680b57cec5SDimitry Andric __kmp_release_bootstrap_lock(&lock);
690b57cec5SDimitry Andric }
700b57cec5SDimitry Andric } // func __kmp_i18n_catopen
710b57cec5SDimitry Andric
720b57cec5SDimitry Andric /* Linux* OS and OS X* part */
730b57cec5SDimitry Andric #if KMP_OS_UNIX
740b57cec5SDimitry Andric #define KMP_I18N_OK
750b57cec5SDimitry Andric
760b57cec5SDimitry Andric #include <nl_types.h>
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric #define KMP_I18N_NULLCAT ((nl_catd)(-1))
790b57cec5SDimitry Andric static nl_catd cat = KMP_I18N_NULLCAT; // !!! Shall it be volatile?
800b57cec5SDimitry Andric static char const *name =
810b57cec5SDimitry Andric (KMP_VERSION_MAJOR == 4 ? "libguide.cat" : "libomp.cat");
820b57cec5SDimitry Andric
830b57cec5SDimitry Andric /* Useful links:
840b57cec5SDimitry Andric http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html#tag_08_02
850b57cec5SDimitry Andric http://www.opengroup.org/onlinepubs/000095399/functions/catopen.html
860b57cec5SDimitry Andric http://www.opengroup.org/onlinepubs/000095399/functions/setlocale.html
870b57cec5SDimitry Andric */
880b57cec5SDimitry Andric
__kmp_i18n_do_catopen()890b57cec5SDimitry Andric void __kmp_i18n_do_catopen() {
900b57cec5SDimitry Andric int english = 0;
910b57cec5SDimitry Andric char *lang = __kmp_env_get("LANG");
920b57cec5SDimitry Andric // TODO: What about LC_ALL or LC_MESSAGES?
930b57cec5SDimitry Andric
940b57cec5SDimitry Andric KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);
950b57cec5SDimitry Andric KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);
960b57cec5SDimitry Andric
970b57cec5SDimitry Andric english = lang == NULL || // In all these cases English language is used.
980b57cec5SDimitry Andric strcmp(lang, "") == 0 || strcmp(lang, " ") == 0 ||
990b57cec5SDimitry Andric // Workaround for Fortran RTL bug DPD200137873 "Fortran runtime
1000b57cec5SDimitry Andric // resets LANG env var to space if it is not set".
1010b57cec5SDimitry Andric strcmp(lang, "C") == 0 || strcmp(lang, "POSIX") == 0;
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric if (!english) { // English language is not yet detected, let us continue.
1040b57cec5SDimitry Andric // Format of LANG is: [language[_territory][.codeset][@modifier]]
1050b57cec5SDimitry Andric // Strip all parts except language.
1060b57cec5SDimitry Andric char *tail = NULL;
1070b57cec5SDimitry Andric __kmp_str_split(lang, '@', &lang, &tail);
1080b57cec5SDimitry Andric __kmp_str_split(lang, '.', &lang, &tail);
1090b57cec5SDimitry Andric __kmp_str_split(lang, '_', &lang, &tail);
1100b57cec5SDimitry Andric english = (strcmp(lang, "en") == 0);
1110b57cec5SDimitry Andric }
1120b57cec5SDimitry Andric
1130b57cec5SDimitry Andric KMP_INTERNAL_FREE(lang);
1140b57cec5SDimitry Andric
1150b57cec5SDimitry Andric // Do not try to open English catalog because internal messages are
1160b57cec5SDimitry Andric // exact copy of messages in English catalog.
1170b57cec5SDimitry Andric if (english) {
1180b57cec5SDimitry Andric status = KMP_I18N_ABSENT; // mark catalog as absent so it will not
1190b57cec5SDimitry Andric // be re-opened.
1200b57cec5SDimitry Andric return;
1210b57cec5SDimitry Andric }
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric cat = catopen(name, 0);
1240b57cec5SDimitry Andric // TODO: Why do we pass 0 in flags?
1250b57cec5SDimitry Andric status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric if (status == KMP_I18N_ABSENT) {
1280b57cec5SDimitry Andric if (__kmp_generate_warnings > kmp_warnings_low) {
1290b57cec5SDimitry Andric // AC: only issue warning in case explicitly asked to
1300b57cec5SDimitry Andric int error = errno; // Save errno immediately.
1310b57cec5SDimitry Andric char *nlspath = __kmp_env_get("NLSPATH");
1320b57cec5SDimitry Andric char *lang = __kmp_env_get("LANG");
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric // Infinite recursion will not occur -- status is KMP_I18N_ABSENT now, so
1350b57cec5SDimitry Andric // __kmp_i18n_catgets() will not try to open catalog, but will return
1360b57cec5SDimitry Andric // default message.
1370b57cec5SDimitry Andric kmp_msg_t err_code = KMP_ERR(error);
1380b57cec5SDimitry Andric __kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, name), err_code,
1390b57cec5SDimitry Andric KMP_HNT(CheckEnvVar, "NLSPATH", nlspath),
1400b57cec5SDimitry Andric KMP_HNT(CheckEnvVar, "LANG", lang), __kmp_msg_null);
1410b57cec5SDimitry Andric if (__kmp_generate_warnings == kmp_warnings_off) {
1420b57cec5SDimitry Andric __kmp_str_free(&err_code.str);
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric KMP_INFORM(WillUseDefaultMessages);
1460b57cec5SDimitry Andric KMP_INTERNAL_FREE(nlspath);
1470b57cec5SDimitry Andric KMP_INTERNAL_FREE(lang);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric } else { // status == KMP_I18N_OPENED
1500b57cec5SDimitry Andric int section = get_section(kmp_i18n_prp_Version);
1510b57cec5SDimitry Andric int number = get_number(kmp_i18n_prp_Version);
1520b57cec5SDimitry Andric char const *expected = __kmp_i18n_default_table.sect[section].str[number];
1530b57cec5SDimitry Andric // Expected version of the catalog.
1540b57cec5SDimitry Andric kmp_str_buf_t version; // Actual version of the catalog.
1550b57cec5SDimitry Andric __kmp_str_buf_init(&version);
1560b57cec5SDimitry Andric __kmp_str_buf_print(&version, "%s", catgets(cat, section, number, NULL));
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric // String returned by catgets is invalid after closing catalog, so copy it.
1590b57cec5SDimitry Andric if (strcmp(version.str, expected) != 0) {
1600b57cec5SDimitry Andric __kmp_i18n_catclose(); // Close bad catalog.
1610b57cec5SDimitry Andric status = KMP_I18N_ABSENT; // And mark it as absent.
1620b57cec5SDimitry Andric if (__kmp_generate_warnings > kmp_warnings_low) {
1630b57cec5SDimitry Andric // AC: only issue warning in case explicitly asked to
1640b57cec5SDimitry Andric // And now print a warning using default messages.
1650b57cec5SDimitry Andric char const *name = "NLSPATH";
1660b57cec5SDimitry Andric char const *nlspath = __kmp_env_get(name);
1670b57cec5SDimitry Andric __kmp_msg(kmp_ms_warning,
1680b57cec5SDimitry Andric KMP_MSG(WrongMessageCatalog, name, version.str, expected),
1690b57cec5SDimitry Andric KMP_HNT(CheckEnvVar, name, nlspath), __kmp_msg_null);
1700b57cec5SDimitry Andric KMP_INFORM(WillUseDefaultMessages);
1710b57cec5SDimitry Andric KMP_INTERNAL_FREE(CCAST(char *, nlspath));
1720b57cec5SDimitry Andric } // __kmp_generate_warnings
1730b57cec5SDimitry Andric }
1740b57cec5SDimitry Andric __kmp_str_buf_free(&version);
1750b57cec5SDimitry Andric }
1760b57cec5SDimitry Andric } // func __kmp_i18n_do_catopen
1770b57cec5SDimitry Andric
__kmp_i18n_catclose()1780b57cec5SDimitry Andric void __kmp_i18n_catclose() {
1790b57cec5SDimitry Andric if (status == KMP_I18N_OPENED) {
1800b57cec5SDimitry Andric KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
1810b57cec5SDimitry Andric catclose(cat);
1820b57cec5SDimitry Andric cat = KMP_I18N_NULLCAT;
1830b57cec5SDimitry Andric }
1840b57cec5SDimitry Andric status = KMP_I18N_CLOSED;
1850b57cec5SDimitry Andric } // func __kmp_i18n_catclose
1860b57cec5SDimitry Andric
__kmp_i18n_catgets(kmp_i18n_id_t id)1870b57cec5SDimitry Andric char const *__kmp_i18n_catgets(kmp_i18n_id_t id) {
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric int section = get_section(id);
1900b57cec5SDimitry Andric int number = get_number(id);
1910b57cec5SDimitry Andric char const *message = NULL;
1920b57cec5SDimitry Andric
1930b57cec5SDimitry Andric if (1 <= section && section <= __kmp_i18n_default_table.size) {
1940b57cec5SDimitry Andric if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {
1950b57cec5SDimitry Andric if (status == KMP_I18N_CLOSED) {
1960b57cec5SDimitry Andric __kmp_i18n_catopen();
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric if (status == KMP_I18N_OPENED) {
1990b57cec5SDimitry Andric message = catgets(cat, section, number,
2000b57cec5SDimitry Andric __kmp_i18n_default_table.sect[section].str[number]);
2010b57cec5SDimitry Andric }
2020b57cec5SDimitry Andric if (message == NULL) {
2030b57cec5SDimitry Andric message = __kmp_i18n_default_table.sect[section].str[number];
2040b57cec5SDimitry Andric }
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric if (message == NULL) {
2080b57cec5SDimitry Andric message = no_message_available;
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric return message;
2110b57cec5SDimitry Andric
2120b57cec5SDimitry Andric } // func __kmp_i18n_catgets
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric #endif // KMP_OS_UNIX
2150b57cec5SDimitry Andric
2160b57cec5SDimitry Andric /* Windows* OS part. */
2170b57cec5SDimitry Andric
2180b57cec5SDimitry Andric #if KMP_OS_WINDOWS
2190b57cec5SDimitry Andric #define KMP_I18N_OK
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric #include "kmp_environment.h"
2220b57cec5SDimitry Andric #include <windows.h>
2230b57cec5SDimitry Andric
2240b57cec5SDimitry Andric #define KMP_I18N_NULLCAT NULL
2250b57cec5SDimitry Andric static HMODULE cat = KMP_I18N_NULLCAT; // !!! Shall it be volatile?
2260b57cec5SDimitry Andric static char const *name =
2270b57cec5SDimitry Andric (KMP_VERSION_MAJOR == 4 ? "libguide40ui.dll" : "libompui.dll");
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric static kmp_i18n_table_t table = {0, NULL};
2300b57cec5SDimitry Andric // Messages formatted by FormatMessage() should be freed, but catgets()
2310b57cec5SDimitry Andric // interface assumes user will not free messages. So we cache all the retrieved
2320b57cec5SDimitry Andric // messages in the table, which are freed at catclose().
2330b57cec5SDimitry Andric static UINT const default_code_page = CP_OEMCP;
2340b57cec5SDimitry Andric static UINT code_page = default_code_page;
2350b57cec5SDimitry Andric
2360b57cec5SDimitry Andric static char const *___catgets(kmp_i18n_id_t id);
2370b57cec5SDimitry Andric static UINT get_code_page();
2380b57cec5SDimitry Andric static void kmp_i18n_table_free(kmp_i18n_table_t *table);
2390b57cec5SDimitry Andric
get_code_page()2400b57cec5SDimitry Andric static UINT get_code_page() {
2410b57cec5SDimitry Andric
2420b57cec5SDimitry Andric UINT cp = default_code_page;
2430b57cec5SDimitry Andric char const *value = __kmp_env_get("KMP_CODEPAGE");
2440b57cec5SDimitry Andric if (value != NULL) {
2450b57cec5SDimitry Andric if (_stricmp(value, "ANSI") == 0) {
2460b57cec5SDimitry Andric cp = CP_ACP;
2470b57cec5SDimitry Andric } else if (_stricmp(value, "OEM") == 0) {
2480b57cec5SDimitry Andric cp = CP_OEMCP;
2490b57cec5SDimitry Andric } else if (_stricmp(value, "UTF-8") == 0 || _stricmp(value, "UTF8") == 0) {
2500b57cec5SDimitry Andric cp = CP_UTF8;
2510b57cec5SDimitry Andric } else if (_stricmp(value, "UTF-7") == 0 || _stricmp(value, "UTF7") == 0) {
2520b57cec5SDimitry Andric cp = CP_UTF7;
2530b57cec5SDimitry Andric } else {
2540b57cec5SDimitry Andric // !!! TODO: Issue a warning?
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric }
2570b57cec5SDimitry Andric KMP_INTERNAL_FREE((void *)value);
2580b57cec5SDimitry Andric return cp;
2590b57cec5SDimitry Andric
2600b57cec5SDimitry Andric } // func get_code_page
2610b57cec5SDimitry Andric
kmp_i18n_table_free(kmp_i18n_table_t * table)2620b57cec5SDimitry Andric static void kmp_i18n_table_free(kmp_i18n_table_t *table) {
2630b57cec5SDimitry Andric int s;
2640b57cec5SDimitry Andric int m;
2650b57cec5SDimitry Andric for (s = 0; s < table->size; ++s) {
2660b57cec5SDimitry Andric for (m = 0; m < table->sect[s].size; ++m) {
2670b57cec5SDimitry Andric // Free message.
2680b57cec5SDimitry Andric KMP_INTERNAL_FREE((void *)table->sect[s].str[m]);
2690b57cec5SDimitry Andric table->sect[s].str[m] = NULL;
2700b57cec5SDimitry Andric }
2710b57cec5SDimitry Andric table->sect[s].size = 0;
2720b57cec5SDimitry Andric // Free section itself.
2730b57cec5SDimitry Andric KMP_INTERNAL_FREE((void *)table->sect[s].str);
2740b57cec5SDimitry Andric table->sect[s].str = NULL;
2750b57cec5SDimitry Andric }
2760b57cec5SDimitry Andric table->size = 0;
2770b57cec5SDimitry Andric KMP_INTERNAL_FREE((void *)table->sect);
2780b57cec5SDimitry Andric table->sect = NULL;
2790b57cec5SDimitry Andric } // kmp_i18n_table_free
2800b57cec5SDimitry Andric
__kmp_i18n_do_catopen()2810b57cec5SDimitry Andric void __kmp_i18n_do_catopen() {
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric LCID locale_id = GetThreadLocale();
2840b57cec5SDimitry Andric WORD lang_id = LANGIDFROMLCID(locale_id);
2850b57cec5SDimitry Andric WORD primary_lang_id = PRIMARYLANGID(lang_id);
2860b57cec5SDimitry Andric kmp_str_buf_t path;
2870b57cec5SDimitry Andric
2880b57cec5SDimitry Andric KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);
2890b57cec5SDimitry Andric KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);
2900b57cec5SDimitry Andric
2910b57cec5SDimitry Andric __kmp_str_buf_init(&path);
2920b57cec5SDimitry Andric
2930b57cec5SDimitry Andric // Do not try to open English catalog because internal messages are exact copy
2940b57cec5SDimitry Andric // of messages in English catalog.
2950b57cec5SDimitry Andric if (primary_lang_id == LANG_ENGLISH) {
2960b57cec5SDimitry Andric status = KMP_I18N_ABSENT; // mark catalog as absent so it will not
2970b57cec5SDimitry Andric // be re-opened.
2980b57cec5SDimitry Andric goto end;
2990b57cec5SDimitry Andric }
3000b57cec5SDimitry Andric
3010b57cec5SDimitry Andric // Construct resource DLL name.
3020b57cec5SDimitry Andric /* Simple LoadLibrary( name ) is not suitable due to security issue (see
3030b57cec5SDimitry Andric http://www.microsoft.com/technet/security/advisory/2269637.mspx). We have
3040b57cec5SDimitry Andric to specify full path to the message catalog. */
3050b57cec5SDimitry Andric {
3060b57cec5SDimitry Andric // Get handle of our DLL first.
3070b57cec5SDimitry Andric HMODULE handle;
3080b57cec5SDimitry Andric BOOL brc = GetModuleHandleEx(
3090b57cec5SDimitry Andric GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
3100b57cec5SDimitry Andric GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
3110b57cec5SDimitry Andric reinterpret_cast<LPCSTR>(&__kmp_i18n_do_catopen), &handle);
3120b57cec5SDimitry Andric if (!brc) { // Error occurred.
3130b57cec5SDimitry Andric status = KMP_I18N_ABSENT; // mark catalog as absent so it will not be
3140b57cec5SDimitry Andric // re-opened.
3150b57cec5SDimitry Andric goto end;
3160b57cec5SDimitry Andric // TODO: Enable multiple messages (KMP_MSG) to be passed to __kmp_msg; and
3170b57cec5SDimitry Andric // print a proper warning.
3180b57cec5SDimitry Andric }
3190b57cec5SDimitry Andric
3200b57cec5SDimitry Andric // Now get path to the our DLL.
3210b57cec5SDimitry Andric for (;;) {
3220b57cec5SDimitry Andric DWORD drc = GetModuleFileName(handle, path.str, path.size);
3230b57cec5SDimitry Andric if (drc == 0) { // Error occurred.
3240b57cec5SDimitry Andric status = KMP_I18N_ABSENT;
3250b57cec5SDimitry Andric goto end;
3260b57cec5SDimitry Andric }
3270b57cec5SDimitry Andric if (drc < path.size) {
3280b57cec5SDimitry Andric path.used = drc;
3290b57cec5SDimitry Andric break;
3300b57cec5SDimitry Andric }
3310b57cec5SDimitry Andric __kmp_str_buf_reserve(&path, path.size * 2);
3320b57cec5SDimitry Andric }
3330b57cec5SDimitry Andric
3340b57cec5SDimitry Andric // Now construct the name of message catalog.
3350b57cec5SDimitry Andric kmp_str_fname fname;
3360b57cec5SDimitry Andric __kmp_str_fname_init(&fname, path.str);
3370b57cec5SDimitry Andric __kmp_str_buf_clear(&path);
3380b57cec5SDimitry Andric __kmp_str_buf_print(&path, "%s%lu/%s", fname.dir,
3390b57cec5SDimitry Andric (unsigned long)(locale_id), name);
3400b57cec5SDimitry Andric __kmp_str_fname_free(&fname);
3410b57cec5SDimitry Andric }
3420b57cec5SDimitry Andric
3430b57cec5SDimitry Andric // For security reasons, use LoadLibraryEx() and load message catalog as a
3440b57cec5SDimitry Andric // data file.
3450b57cec5SDimitry Andric cat = LoadLibraryEx(path.str, NULL, LOAD_LIBRARY_AS_DATAFILE);
3460b57cec5SDimitry Andric status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);
3470b57cec5SDimitry Andric
3480b57cec5SDimitry Andric if (status == KMP_I18N_ABSENT) {
3490b57cec5SDimitry Andric if (__kmp_generate_warnings > kmp_warnings_low) {
3500b57cec5SDimitry Andric // AC: only issue warning in case explicitly asked to
3510b57cec5SDimitry Andric DWORD error = GetLastError();
3520b57cec5SDimitry Andric // Infinite recursion will not occur -- status is KMP_I18N_ABSENT now, so
3530b57cec5SDimitry Andric // __kmp_i18n_catgets() will not try to open catalog but will return
3540b57cec5SDimitry Andric // default message.
3550b57cec5SDimitry Andric /* If message catalog for another architecture found (e.g. OpenMP RTL for
3560b57cec5SDimitry Andric IA-32 architecture opens libompui.dll for Intel(R) 64) Windows* OS
3570b57cec5SDimitry Andric returns error 193 (ERROR_BAD_EXE_FORMAT). However, FormatMessage fails
3580b57cec5SDimitry Andric to return a message for this error, so user will see:
3590b57cec5SDimitry Andric
3600b57cec5SDimitry Andric OMP: Warning #2: Cannot open message catalog "1041\libompui.dll":
3610b57cec5SDimitry Andric OMP: System error #193: (No system error message available)
3620b57cec5SDimitry Andric OMP: Info #3: Default messages will be used.
3630b57cec5SDimitry Andric
3640b57cec5SDimitry Andric Issue hint in this case so cause of trouble is more understandable. */
3650b57cec5SDimitry Andric kmp_msg_t err_code = KMP_SYSERRCODE(error);
3660b57cec5SDimitry Andric __kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, path.str),
367*fe6060f1SDimitry Andric err_code,
368*fe6060f1SDimitry Andric (error == ERROR_BAD_EXE_FORMAT
3690b57cec5SDimitry Andric ? KMP_HNT(BadExeFormat, path.str, KMP_ARCH_STR)
3700b57cec5SDimitry Andric : __kmp_msg_null),
3710b57cec5SDimitry Andric __kmp_msg_null);
3720b57cec5SDimitry Andric if (__kmp_generate_warnings == kmp_warnings_off) {
3730b57cec5SDimitry Andric __kmp_str_free(&err_code.str);
3740b57cec5SDimitry Andric }
3750b57cec5SDimitry Andric KMP_INFORM(WillUseDefaultMessages);
3760b57cec5SDimitry Andric }
3770b57cec5SDimitry Andric } else { // status == KMP_I18N_OPENED
3780b57cec5SDimitry Andric
3790b57cec5SDimitry Andric int section = get_section(kmp_i18n_prp_Version);
3800b57cec5SDimitry Andric int number = get_number(kmp_i18n_prp_Version);
3810b57cec5SDimitry Andric char const *expected = __kmp_i18n_default_table.sect[section].str[number];
3820b57cec5SDimitry Andric kmp_str_buf_t version; // Actual version of the catalog.
3830b57cec5SDimitry Andric __kmp_str_buf_init(&version);
3840b57cec5SDimitry Andric __kmp_str_buf_print(&version, "%s", ___catgets(kmp_i18n_prp_Version));
3850b57cec5SDimitry Andric // String returned by catgets is invalid after closing catalog, so copy it.
3860b57cec5SDimitry Andric if (strcmp(version.str, expected) != 0) {
3870b57cec5SDimitry Andric // Close bad catalog.
3880b57cec5SDimitry Andric __kmp_i18n_catclose();
3890b57cec5SDimitry Andric status = KMP_I18N_ABSENT; // And mark it as absent.
3900b57cec5SDimitry Andric if (__kmp_generate_warnings > kmp_warnings_low) {
3910b57cec5SDimitry Andric // And now print a warning using default messages.
3920b57cec5SDimitry Andric __kmp_msg(kmp_ms_warning,
3930b57cec5SDimitry Andric KMP_MSG(WrongMessageCatalog, path.str, version.str, expected),
3940b57cec5SDimitry Andric __kmp_msg_null);
3950b57cec5SDimitry Andric KMP_INFORM(WillUseDefaultMessages);
3960b57cec5SDimitry Andric } // __kmp_generate_warnings
3970b57cec5SDimitry Andric }
3980b57cec5SDimitry Andric __kmp_str_buf_free(&version);
3990b57cec5SDimitry Andric }
4000b57cec5SDimitry Andric code_page = get_code_page();
4010b57cec5SDimitry Andric
4020b57cec5SDimitry Andric end:
4030b57cec5SDimitry Andric __kmp_str_buf_free(&path);
4040b57cec5SDimitry Andric return;
4050b57cec5SDimitry Andric } // func __kmp_i18n_do_catopen
4060b57cec5SDimitry Andric
__kmp_i18n_catclose()4070b57cec5SDimitry Andric void __kmp_i18n_catclose() {
4080b57cec5SDimitry Andric if (status == KMP_I18N_OPENED) {
4090b57cec5SDimitry Andric KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
4100b57cec5SDimitry Andric kmp_i18n_table_free(&table);
4110b57cec5SDimitry Andric FreeLibrary(cat);
4120b57cec5SDimitry Andric cat = KMP_I18N_NULLCAT;
4130b57cec5SDimitry Andric }
4140b57cec5SDimitry Andric code_page = default_code_page;
4150b57cec5SDimitry Andric status = KMP_I18N_CLOSED;
4160b57cec5SDimitry Andric } // func __kmp_i18n_catclose
4170b57cec5SDimitry Andric
4180b57cec5SDimitry Andric /* We use FormatMessage() to get strings from catalog, get system error
4190b57cec5SDimitry Andric messages, etc. FormatMessage() tends to return Windows* OS-style
4200b57cec5SDimitry Andric end-of-lines, "\r\n". When string is printed, printf() also replaces all the
4210b57cec5SDimitry Andric occurrences of "\n" with "\r\n" (again!), so sequences like "\r\r\r\n"
4220b57cec5SDimitry Andric appear in output. It is not too good.
4230b57cec5SDimitry Andric
4240b57cec5SDimitry Andric Additional mess comes from message catalog: Our catalog source en_US.mc file
4250b57cec5SDimitry Andric (generated by message-converter.pl) contains only "\n" characters, but
4260b57cec5SDimitry Andric en_US_msg_1033.bin file (produced by mc.exe) may contain "\r\n" or just "\n".
4270b57cec5SDimitry Andric This mess goes from en_US_msg_1033.bin file to message catalog,
4280b57cec5SDimitry Andric libompui.dll. For example, message
4290b57cec5SDimitry Andric
4300b57cec5SDimitry Andric Error
4310b57cec5SDimitry Andric
4320b57cec5SDimitry Andric (there is "\n" at the end) is compiled by mc.exe to "Error\r\n", while
4330b57cec5SDimitry Andric
4340b57cec5SDimitry Andric OMP: Error %1!d!: %2!s!\n
4350b57cec5SDimitry Andric
4360b57cec5SDimitry Andric (there is "\n" at the end as well) is compiled to "OMP: Error %1!d!:
4370b57cec5SDimitry Andric %2!s!\r\n\n".
4380b57cec5SDimitry Andric
4390b57cec5SDimitry Andric Thus, stripping all "\r" normalizes string and returns it to canonical form,
4400b57cec5SDimitry Andric so printf() will produce correct end-of-line sequences.
4410b57cec5SDimitry Andric
4420b57cec5SDimitry Andric ___strip_crs() serves for this purpose: it removes all the occurrences of
4430b57cec5SDimitry Andric "\r" in-place and returns new length of string. */
___strip_crs(char * str)4440b57cec5SDimitry Andric static int ___strip_crs(char *str) {
4450b57cec5SDimitry Andric int in = 0; // Input character index.
4460b57cec5SDimitry Andric int out = 0; // Output character index.
4470b57cec5SDimitry Andric for (;;) {
4480b57cec5SDimitry Andric if (str[in] != '\r') {
4490b57cec5SDimitry Andric str[out] = str[in];
4500b57cec5SDimitry Andric ++out;
4510b57cec5SDimitry Andric }
4520b57cec5SDimitry Andric if (str[in] == 0) {
4530b57cec5SDimitry Andric break;
4540b57cec5SDimitry Andric }
4550b57cec5SDimitry Andric ++in;
4560b57cec5SDimitry Andric }
4570b57cec5SDimitry Andric return out - 1;
4580b57cec5SDimitry Andric } // func __strip_crs
4590b57cec5SDimitry Andric
___catgets(kmp_i18n_id_t id)4600b57cec5SDimitry Andric static char const *___catgets(kmp_i18n_id_t id) {
4610b57cec5SDimitry Andric
4620b57cec5SDimitry Andric char *result = NULL;
4630b57cec5SDimitry Andric PVOID addr = NULL;
4640b57cec5SDimitry Andric wchar_t *wmsg = NULL;
4650b57cec5SDimitry Andric DWORD wlen = 0;
4660b57cec5SDimitry Andric char *msg = NULL;
4670b57cec5SDimitry Andric int len = 0;
4680b57cec5SDimitry Andric int rc;
4690b57cec5SDimitry Andric
4700b57cec5SDimitry Andric KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
4710b57cec5SDimitry Andric wlen = // wlen does *not* include terminating null.
4720b57cec5SDimitry Andric FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
4730b57cec5SDimitry Andric FORMAT_MESSAGE_FROM_HMODULE |
4740b57cec5SDimitry Andric FORMAT_MESSAGE_IGNORE_INSERTS,
4750b57cec5SDimitry Andric cat, id,
4760b57cec5SDimitry Andric 0, // LangId
4770b57cec5SDimitry Andric (LPWSTR)&addr,
4780b57cec5SDimitry Andric 0, // Size in elements, not in bytes.
4790b57cec5SDimitry Andric NULL);
4800b57cec5SDimitry Andric if (wlen <= 0) {
4810b57cec5SDimitry Andric goto end;
4820b57cec5SDimitry Andric }
4830b57cec5SDimitry Andric wmsg = (wchar_t *)addr; // Warning: wmsg may be not nul-terminated!
4840b57cec5SDimitry Andric
4850b57cec5SDimitry Andric // Calculate length of multibyte message.
4860b57cec5SDimitry Andric // Since wlen does not include terminating null, len does not include it also.
4870b57cec5SDimitry Andric len = WideCharToMultiByte(code_page,
4880b57cec5SDimitry Andric 0, // Flags.
4890b57cec5SDimitry Andric wmsg, wlen, // Wide buffer and size.
4900b57cec5SDimitry Andric NULL, 0, // Buffer and size.
4910b57cec5SDimitry Andric NULL, NULL // Default char and used default char.
4920b57cec5SDimitry Andric );
4930b57cec5SDimitry Andric if (len <= 0) {
4940b57cec5SDimitry Andric goto end;
4950b57cec5SDimitry Andric }
4960b57cec5SDimitry Andric
4970b57cec5SDimitry Andric // Allocate memory.
4980b57cec5SDimitry Andric msg = (char *)KMP_INTERNAL_MALLOC(len + 1);
4990b57cec5SDimitry Andric
5000b57cec5SDimitry Andric // Convert wide message to multibyte one.
5010b57cec5SDimitry Andric rc = WideCharToMultiByte(code_page,
5020b57cec5SDimitry Andric 0, // Flags.
5030b57cec5SDimitry Andric wmsg, wlen, // Wide buffer and size.
5040b57cec5SDimitry Andric msg, len, // Buffer and size.
5050b57cec5SDimitry Andric NULL, NULL // Default char and used default char.
5060b57cec5SDimitry Andric );
5070b57cec5SDimitry Andric if (rc <= 0 || rc > len) {
5080b57cec5SDimitry Andric goto end;
5090b57cec5SDimitry Andric }
5100b57cec5SDimitry Andric KMP_DEBUG_ASSERT(rc == len);
5110b57cec5SDimitry Andric len = rc;
5120b57cec5SDimitry Andric msg[len] = 0; // Put terminating null to the end.
5130b57cec5SDimitry Andric
5140b57cec5SDimitry Andric // Stripping all "\r" before stripping last end-of-line simplifies the task.
5150b57cec5SDimitry Andric len = ___strip_crs(msg);
5160b57cec5SDimitry Andric
5170b57cec5SDimitry Andric // Every message in catalog is terminated with "\n". Strip it.
5180b57cec5SDimitry Andric if (len >= 1 && msg[len - 1] == '\n') {
5190b57cec5SDimitry Andric --len;
5200b57cec5SDimitry Andric msg[len] = 0;
5210b57cec5SDimitry Andric }
5220b57cec5SDimitry Andric
5230b57cec5SDimitry Andric // Everything looks ok.
5240b57cec5SDimitry Andric result = msg;
5250b57cec5SDimitry Andric msg = NULL;
5260b57cec5SDimitry Andric
5270b57cec5SDimitry Andric end:
5280b57cec5SDimitry Andric
5290b57cec5SDimitry Andric if (msg != NULL) {
5300b57cec5SDimitry Andric KMP_INTERNAL_FREE(msg);
5310b57cec5SDimitry Andric }
5320b57cec5SDimitry Andric if (wmsg != NULL) {
5330b57cec5SDimitry Andric LocalFree(wmsg);
5340b57cec5SDimitry Andric }
5350b57cec5SDimitry Andric
5360b57cec5SDimitry Andric return result;
5370b57cec5SDimitry Andric
5380b57cec5SDimitry Andric } // ___catgets
5390b57cec5SDimitry Andric
__kmp_i18n_catgets(kmp_i18n_id_t id)5400b57cec5SDimitry Andric char const *__kmp_i18n_catgets(kmp_i18n_id_t id) {
5410b57cec5SDimitry Andric
5420b57cec5SDimitry Andric int section = get_section(id);
5430b57cec5SDimitry Andric int number = get_number(id);
5440b57cec5SDimitry Andric char const *message = NULL;
5450b57cec5SDimitry Andric
5460b57cec5SDimitry Andric if (1 <= section && section <= __kmp_i18n_default_table.size) {
5470b57cec5SDimitry Andric if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {
5480b57cec5SDimitry Andric if (status == KMP_I18N_CLOSED) {
5490b57cec5SDimitry Andric __kmp_i18n_catopen();
5500b57cec5SDimitry Andric }
5510b57cec5SDimitry Andric if (cat != KMP_I18N_NULLCAT) {
5520b57cec5SDimitry Andric if (table.size == 0) {
5530b57cec5SDimitry Andric table.sect = (kmp_i18n_section_t *)KMP_INTERNAL_CALLOC(
5540b57cec5SDimitry Andric (__kmp_i18n_default_table.size + 2), sizeof(kmp_i18n_section_t));
5550b57cec5SDimitry Andric table.size = __kmp_i18n_default_table.size;
5560b57cec5SDimitry Andric }
5570b57cec5SDimitry Andric if (table.sect[section].size == 0) {
5580b57cec5SDimitry Andric table.sect[section].str = (const char **)KMP_INTERNAL_CALLOC(
5590b57cec5SDimitry Andric __kmp_i18n_default_table.sect[section].size + 2,
5600b57cec5SDimitry Andric sizeof(char const *));
5610b57cec5SDimitry Andric table.sect[section].size =
5620b57cec5SDimitry Andric __kmp_i18n_default_table.sect[section].size;
5630b57cec5SDimitry Andric }
5640b57cec5SDimitry Andric if (table.sect[section].str[number] == NULL) {
5650b57cec5SDimitry Andric table.sect[section].str[number] = ___catgets(id);
5660b57cec5SDimitry Andric }
5670b57cec5SDimitry Andric message = table.sect[section].str[number];
5680b57cec5SDimitry Andric }
5690b57cec5SDimitry Andric if (message == NULL) {
5700b57cec5SDimitry Andric // Catalog is not opened or message is not found, return default
5710b57cec5SDimitry Andric // message.
5720b57cec5SDimitry Andric message = __kmp_i18n_default_table.sect[section].str[number];
5730b57cec5SDimitry Andric }
5740b57cec5SDimitry Andric }
5750b57cec5SDimitry Andric }
5760b57cec5SDimitry Andric if (message == NULL) {
5770b57cec5SDimitry Andric message = no_message_available;
5780b57cec5SDimitry Andric }
5790b57cec5SDimitry Andric return message;
5800b57cec5SDimitry Andric
5810b57cec5SDimitry Andric } // func __kmp_i18n_catgets
5820b57cec5SDimitry Andric
5830b57cec5SDimitry Andric #endif // KMP_OS_WINDOWS
5840b57cec5SDimitry Andric
5850b57cec5SDimitry Andric // -----------------------------------------------------------------------------
5860b57cec5SDimitry Andric
5870b57cec5SDimitry Andric #ifndef KMP_I18N_OK
5880b57cec5SDimitry Andric #error I18n support is not implemented for this OS.
5890b57cec5SDimitry Andric #endif // KMP_I18N_OK
5900b57cec5SDimitry Andric
5910b57cec5SDimitry Andric // -----------------------------------------------------------------------------
5920b57cec5SDimitry Andric
__kmp_i18n_dump_catalog(kmp_str_buf_t * buffer)5930b57cec5SDimitry Andric void __kmp_i18n_dump_catalog(kmp_str_buf_t *buffer) {
5940b57cec5SDimitry Andric
5950b57cec5SDimitry Andric struct kmp_i18n_id_range_t {
5960b57cec5SDimitry Andric kmp_i18n_id_t first;
5970b57cec5SDimitry Andric kmp_i18n_id_t last;
5980b57cec5SDimitry Andric }; // struct kmp_i18n_id_range_t
5990b57cec5SDimitry Andric
6000b57cec5SDimitry Andric static struct kmp_i18n_id_range_t ranges[] = {
6010b57cec5SDimitry Andric {kmp_i18n_prp_first, kmp_i18n_prp_last},
6020b57cec5SDimitry Andric {kmp_i18n_str_first, kmp_i18n_str_last},
6030b57cec5SDimitry Andric {kmp_i18n_fmt_first, kmp_i18n_fmt_last},
6040b57cec5SDimitry Andric {kmp_i18n_msg_first, kmp_i18n_msg_last},
6050b57cec5SDimitry Andric {kmp_i18n_hnt_first, kmp_i18n_hnt_last}}; // ranges
6060b57cec5SDimitry Andric
6070b57cec5SDimitry Andric int num_of_ranges = sizeof(ranges) / sizeof(struct kmp_i18n_id_range_t);
6080b57cec5SDimitry Andric int range;
6090b57cec5SDimitry Andric kmp_i18n_id_t id;
6100b57cec5SDimitry Andric
6110b57cec5SDimitry Andric for (range = 0; range < num_of_ranges; ++range) {
6120b57cec5SDimitry Andric __kmp_str_buf_print(buffer, "*** Set #%d ***\n", range + 1);
6130b57cec5SDimitry Andric for (id = (kmp_i18n_id_t)(ranges[range].first + 1); id < ranges[range].last;
6140b57cec5SDimitry Andric id = (kmp_i18n_id_t)(id + 1)) {
6150b57cec5SDimitry Andric __kmp_str_buf_print(buffer, "%d: <<%s>>\n", id, __kmp_i18n_catgets(id));
6160b57cec5SDimitry Andric }
6170b57cec5SDimitry Andric }
6180b57cec5SDimitry Andric
6190b57cec5SDimitry Andric __kmp_printf("%s", buffer->str);
6200b57cec5SDimitry Andric
6210b57cec5SDimitry Andric } // __kmp_i18n_dump_catalog
6220b57cec5SDimitry Andric
6230b57cec5SDimitry Andric // -----------------------------------------------------------------------------
__kmp_msg_format(unsigned id_arg,...)6240b57cec5SDimitry Andric kmp_msg_t __kmp_msg_format(unsigned id_arg, ...) {
6250b57cec5SDimitry Andric
6260b57cec5SDimitry Andric kmp_msg_t msg;
6270b57cec5SDimitry Andric va_list args;
6280b57cec5SDimitry Andric kmp_str_buf_t buffer;
6290b57cec5SDimitry Andric __kmp_str_buf_init(&buffer);
6300b57cec5SDimitry Andric
6310b57cec5SDimitry Andric va_start(args, id_arg);
6320b57cec5SDimitry Andric
6330b57cec5SDimitry Andric // We use unsigned for the ID argument and explicitly cast it here to the
6340b57cec5SDimitry Andric // right enumerator because variadic functions are not compatible with
6350b57cec5SDimitry Andric // default promotions.
6360b57cec5SDimitry Andric kmp_i18n_id_t id = (kmp_i18n_id_t)id_arg;
6370b57cec5SDimitry Andric
6380b57cec5SDimitry Andric #if KMP_OS_UNIX
6390b57cec5SDimitry Andric // On Linux* OS and OS X*, printf() family functions process parameter
6400b57cec5SDimitry Andric // numbers, for example: "%2$s %1$s".
6410b57cec5SDimitry Andric __kmp_str_buf_vprint(&buffer, __kmp_i18n_catgets(id), args);
6420b57cec5SDimitry Andric #elif KMP_OS_WINDOWS
6435ffd83dbSDimitry Andric // On Windows, printf() family functions does not recognize GNU style
6440b57cec5SDimitry Andric // parameter numbers, so we have to use FormatMessage() instead. It recognizes
6450b57cec5SDimitry Andric // parameter numbers, e. g.: "%2!s! "%1!s!".
6460b57cec5SDimitry Andric {
6470b57cec5SDimitry Andric LPTSTR str = NULL;
6480b57cec5SDimitry Andric int len;
6490b57cec5SDimitry Andric FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
6500b57cec5SDimitry Andric __kmp_i18n_catgets(id), 0, 0, (LPTSTR)(&str), 0, &args);
6510b57cec5SDimitry Andric len = ___strip_crs(str);
6520b57cec5SDimitry Andric __kmp_str_buf_cat(&buffer, str, len);
6530b57cec5SDimitry Andric LocalFree(str);
6540b57cec5SDimitry Andric }
6550b57cec5SDimitry Andric #else
6560b57cec5SDimitry Andric #error
6570b57cec5SDimitry Andric #endif
6580b57cec5SDimitry Andric va_end(args);
6590b57cec5SDimitry Andric __kmp_str_buf_detach(&buffer);
6600b57cec5SDimitry Andric
6610b57cec5SDimitry Andric msg.type = (kmp_msg_type_t)(id >> 16);
6620b57cec5SDimitry Andric msg.num = id & 0xFFFF;
6630b57cec5SDimitry Andric msg.str = buffer.str;
6640b57cec5SDimitry Andric msg.len = buffer.used;
6650b57cec5SDimitry Andric
6660b57cec5SDimitry Andric return msg;
6670b57cec5SDimitry Andric
6680b57cec5SDimitry Andric } // __kmp_msg_format
6690b57cec5SDimitry Andric
6700b57cec5SDimitry Andric // -----------------------------------------------------------------------------
sys_error(int err)6710b57cec5SDimitry Andric static char *sys_error(int err) {
6720b57cec5SDimitry Andric
6730b57cec5SDimitry Andric char *message = NULL;
6740b57cec5SDimitry Andric
6750b57cec5SDimitry Andric #if KMP_OS_WINDOWS
6760b57cec5SDimitry Andric
6770b57cec5SDimitry Andric LPVOID buffer = NULL;
6780b57cec5SDimitry Andric int len;
6790b57cec5SDimitry Andric DWORD rc;
6800b57cec5SDimitry Andric rc = FormatMessage(
6810b57cec5SDimitry Andric FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
6820b57cec5SDimitry Andric MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.
6830b57cec5SDimitry Andric (LPTSTR)&buffer, 0, NULL);
6840b57cec5SDimitry Andric if (rc > 0) {
6850b57cec5SDimitry Andric // Message formatted. Copy it (so we can free it later with normal free().
6860b57cec5SDimitry Andric message = __kmp_str_format("%s", (char *)buffer);
6870b57cec5SDimitry Andric len = ___strip_crs(message); // Delete carriage returns if any.
6880b57cec5SDimitry Andric // Strip trailing newlines.
6890b57cec5SDimitry Andric while (len > 0 && message[len - 1] == '\n') {
6900b57cec5SDimitry Andric --len;
6910b57cec5SDimitry Andric }
6920b57cec5SDimitry Andric message[len] = 0;
6930b57cec5SDimitry Andric } else {
6940b57cec5SDimitry Andric // FormatMessage() failed to format system error message. GetLastError()
6950b57cec5SDimitry Andric // would give us error code, which we would convert to message... this it
6960b57cec5SDimitry Andric // dangerous recursion, which cannot clarify original error, so we will not
6970b57cec5SDimitry Andric // even start it.
6980b57cec5SDimitry Andric }
6990b57cec5SDimitry Andric if (buffer != NULL) {
7000b57cec5SDimitry Andric LocalFree(buffer);
7010b57cec5SDimitry Andric }
7020b57cec5SDimitry Andric
7030b57cec5SDimitry Andric #else // Non-Windows* OS: Linux* OS or OS X*
7040b57cec5SDimitry Andric
7050b57cec5SDimitry Andric /* There are 2 incompatible versions of strerror_r:
7060b57cec5SDimitry Andric
7070b57cec5SDimitry Andric char * strerror_r( int, char *, size_t ); // GNU version
7080b57cec5SDimitry Andric int strerror_r( int, char *, size_t ); // XSI version
7090b57cec5SDimitry Andric */
7100b57cec5SDimitry Andric
7110b57cec5SDimitry Andric #if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || \
7120b57cec5SDimitry Andric (defined(__BIONIC__) && defined(_GNU_SOURCE) && \
7130b57cec5SDimitry Andric __ANDROID_API__ >= __ANDROID_API_M__)
7140b57cec5SDimitry Andric // GNU version of strerror_r.
7150b57cec5SDimitry Andric
7160b57cec5SDimitry Andric char buffer[2048];
7170b57cec5SDimitry Andric char *const err_msg = strerror_r(err, buffer, sizeof(buffer));
7180b57cec5SDimitry Andric // Do not eliminate this assignment to temporary variable, otherwise compiler
7190b57cec5SDimitry Andric // would not issue warning if strerror_r() returns `int' instead of expected
7200b57cec5SDimitry Andric // `char *'.
7210b57cec5SDimitry Andric message = __kmp_str_format("%s", err_msg);
7220b57cec5SDimitry Andric
7230b57cec5SDimitry Andric #else // OS X*, FreeBSD* etc.
7240b57cec5SDimitry Andric // XSI version of strerror_r.
7250b57cec5SDimitry Andric int size = 2048;
7260b57cec5SDimitry Andric char *buffer = (char *)KMP_INTERNAL_MALLOC(size);
7270b57cec5SDimitry Andric int rc;
7280b57cec5SDimitry Andric if (buffer == NULL) {
7290b57cec5SDimitry Andric KMP_FATAL(MemoryAllocFailed);
7300b57cec5SDimitry Andric }
7310b57cec5SDimitry Andric rc = strerror_r(err, buffer, size);
7320b57cec5SDimitry Andric if (rc == -1) {
7330b57cec5SDimitry Andric rc = errno; // XSI version sets errno.
7340b57cec5SDimitry Andric }
7350b57cec5SDimitry Andric while (rc == ERANGE) { // ERANGE means the buffer is too small.
7360b57cec5SDimitry Andric KMP_INTERNAL_FREE(buffer);
7370b57cec5SDimitry Andric size *= 2;
7380b57cec5SDimitry Andric buffer = (char *)KMP_INTERNAL_MALLOC(size);
7390b57cec5SDimitry Andric if (buffer == NULL) {
7400b57cec5SDimitry Andric KMP_FATAL(MemoryAllocFailed);
7410b57cec5SDimitry Andric }
7420b57cec5SDimitry Andric rc = strerror_r(err, buffer, size);
7430b57cec5SDimitry Andric if (rc == -1) {
7440b57cec5SDimitry Andric rc = errno; // XSI version sets errno.
7450b57cec5SDimitry Andric }
7460b57cec5SDimitry Andric }
7470b57cec5SDimitry Andric if (rc == 0) {
7480b57cec5SDimitry Andric message = buffer;
7490b57cec5SDimitry Andric } else { // Buffer is unused. Free it.
7500b57cec5SDimitry Andric KMP_INTERNAL_FREE(buffer);
7510b57cec5SDimitry Andric }
7520b57cec5SDimitry Andric
7530b57cec5SDimitry Andric #endif
7540b57cec5SDimitry Andric
7550b57cec5SDimitry Andric #endif /* KMP_OS_WINDOWS */
7560b57cec5SDimitry Andric
7570b57cec5SDimitry Andric if (message == NULL) {
7580b57cec5SDimitry Andric // TODO: I18n this message.
7590b57cec5SDimitry Andric message = __kmp_str_format("%s", "(No system error message available)");
7600b57cec5SDimitry Andric }
7610b57cec5SDimitry Andric return message;
7620b57cec5SDimitry Andric } // sys_error
7630b57cec5SDimitry Andric
7640b57cec5SDimitry Andric // -----------------------------------------------------------------------------
__kmp_msg_error_code(int code)7650b57cec5SDimitry Andric kmp_msg_t __kmp_msg_error_code(int code) {
7660b57cec5SDimitry Andric
7670b57cec5SDimitry Andric kmp_msg_t msg;
7680b57cec5SDimitry Andric msg.type = kmp_mt_syserr;
7690b57cec5SDimitry Andric msg.num = code;
7700b57cec5SDimitry Andric msg.str = sys_error(code);
7710b57cec5SDimitry Andric msg.len = KMP_STRLEN(msg.str);
7720b57cec5SDimitry Andric return msg;
7730b57cec5SDimitry Andric
7740b57cec5SDimitry Andric } // __kmp_msg_error_code
7750b57cec5SDimitry Andric
7760b57cec5SDimitry Andric // -----------------------------------------------------------------------------
__kmp_msg_error_mesg(char const * mesg)7770b57cec5SDimitry Andric kmp_msg_t __kmp_msg_error_mesg(char const *mesg) {
7780b57cec5SDimitry Andric
7790b57cec5SDimitry Andric kmp_msg_t msg;
7800b57cec5SDimitry Andric msg.type = kmp_mt_syserr;
7810b57cec5SDimitry Andric msg.num = 0;
7820b57cec5SDimitry Andric msg.str = __kmp_str_format("%s", mesg);
7830b57cec5SDimitry Andric msg.len = KMP_STRLEN(msg.str);
7840b57cec5SDimitry Andric return msg;
7850b57cec5SDimitry Andric
7860b57cec5SDimitry Andric } // __kmp_msg_error_mesg
7870b57cec5SDimitry Andric
7880b57cec5SDimitry Andric // -----------------------------------------------------------------------------
__kmp_msg(kmp_msg_severity_t severity,kmp_msg_t message,va_list args)7890b57cec5SDimitry Andric void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, va_list args) {
7900b57cec5SDimitry Andric kmp_i18n_id_t format; // format identifier
7910b57cec5SDimitry Andric kmp_msg_t fmsg; // formatted message
7920b57cec5SDimitry Andric kmp_str_buf_t buffer;
7930b57cec5SDimitry Andric
7940b57cec5SDimitry Andric if (severity != kmp_ms_fatal && __kmp_generate_warnings == kmp_warnings_off)
7950b57cec5SDimitry Andric return; // no reason to form a string in order to not print it
7960b57cec5SDimitry Andric
7970b57cec5SDimitry Andric __kmp_str_buf_init(&buffer);
7980b57cec5SDimitry Andric
7990b57cec5SDimitry Andric // Format the primary message.
8000b57cec5SDimitry Andric switch (severity) {
8010b57cec5SDimitry Andric case kmp_ms_inform: {
8020b57cec5SDimitry Andric format = kmp_i18n_fmt_Info;
8030b57cec5SDimitry Andric } break;
8040b57cec5SDimitry Andric case kmp_ms_warning: {
8050b57cec5SDimitry Andric format = kmp_i18n_fmt_Warning;
8060b57cec5SDimitry Andric } break;
8070b57cec5SDimitry Andric case kmp_ms_fatal: {
8080b57cec5SDimitry Andric format = kmp_i18n_fmt_Fatal;
8090b57cec5SDimitry Andric } break;
810*fe6060f1SDimitry Andric default: {
811*fe6060f1SDimitry Andric KMP_DEBUG_ASSERT(0);
812*fe6060f1SDimitry Andric }
8130b57cec5SDimitry Andric }
8140b57cec5SDimitry Andric fmsg = __kmp_msg_format(format, message.num, message.str);
8150b57cec5SDimitry Andric __kmp_str_free(&message.str);
8160b57cec5SDimitry Andric __kmp_str_buf_cat(&buffer, fmsg.str, fmsg.len);
8170b57cec5SDimitry Andric __kmp_str_free(&fmsg.str);
8180b57cec5SDimitry Andric
8190b57cec5SDimitry Andric // Format other messages.
8200b57cec5SDimitry Andric for (;;) {
8210b57cec5SDimitry Andric message = va_arg(args, kmp_msg_t);
8220b57cec5SDimitry Andric if (message.type == kmp_mt_dummy && message.str == NULL) {
8230b57cec5SDimitry Andric break;
8240b57cec5SDimitry Andric }
8250b57cec5SDimitry Andric switch (message.type) {
8260b57cec5SDimitry Andric case kmp_mt_hint: {
8270b57cec5SDimitry Andric format = kmp_i18n_fmt_Hint;
8280b57cec5SDimitry Andric // we cannot skip %1$ and only use %2$ to print the message without the
8290b57cec5SDimitry Andric // number
8300b57cec5SDimitry Andric fmsg = __kmp_msg_format(format, message.str);
8310b57cec5SDimitry Andric } break;
8320b57cec5SDimitry Andric case kmp_mt_syserr: {
8330b57cec5SDimitry Andric format = kmp_i18n_fmt_SysErr;
8340b57cec5SDimitry Andric fmsg = __kmp_msg_format(format, message.num, message.str);
8350b57cec5SDimitry Andric } break;
836*fe6060f1SDimitry Andric default: {
837*fe6060f1SDimitry Andric KMP_DEBUG_ASSERT(0);
838*fe6060f1SDimitry Andric }
8390b57cec5SDimitry Andric }
8400b57cec5SDimitry Andric __kmp_str_free(&message.str);
8410b57cec5SDimitry Andric __kmp_str_buf_cat(&buffer, fmsg.str, fmsg.len);
8420b57cec5SDimitry Andric __kmp_str_free(&fmsg.str);
8430b57cec5SDimitry Andric }
8440b57cec5SDimitry Andric
8450b57cec5SDimitry Andric // Print formatted messages.
8460b57cec5SDimitry Andric // This lock prevents multiple fatal errors on the same problem.
8470b57cec5SDimitry Andric // __kmp_acquire_bootstrap_lock( & lock ); // GEH - This lock causing tests
8480b57cec5SDimitry Andric // to hang on OS X*.
8490b57cec5SDimitry Andric __kmp_printf("%s", buffer.str);
8500b57cec5SDimitry Andric __kmp_str_buf_free(&buffer);
8510b57cec5SDimitry Andric
8520b57cec5SDimitry Andric // __kmp_release_bootstrap_lock( & lock ); // GEH - this lock causing tests
8530b57cec5SDimitry Andric // to hang on OS X*.
8540b57cec5SDimitry Andric
8550b57cec5SDimitry Andric } // __kmp_msg
8560b57cec5SDimitry Andric
__kmp_msg(kmp_msg_severity_t severity,kmp_msg_t message,...)8570b57cec5SDimitry Andric void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, ...) {
8580b57cec5SDimitry Andric va_list args;
8590b57cec5SDimitry Andric va_start(args, message);
8600b57cec5SDimitry Andric __kmp_msg(severity, message, args);
8610b57cec5SDimitry Andric va_end(args);
8620b57cec5SDimitry Andric }
8630b57cec5SDimitry Andric
__kmp_fatal(kmp_msg_t message,...)8640b57cec5SDimitry Andric void __kmp_fatal(kmp_msg_t message, ...) {
8650b57cec5SDimitry Andric va_list args;
8660b57cec5SDimitry Andric va_start(args, message);
8670b57cec5SDimitry Andric __kmp_msg(kmp_ms_fatal, message, args);
8680b57cec5SDimitry Andric va_end(args);
8690b57cec5SDimitry Andric #if KMP_OS_WINDOWS
8700b57cec5SDimitry Andric // Delay to give message a chance to appear before reaping
8710b57cec5SDimitry Andric __kmp_thread_sleep(500);
8720b57cec5SDimitry Andric #endif
8730b57cec5SDimitry Andric __kmp_abort_process();
8740b57cec5SDimitry Andric } // __kmp_fatal
8750b57cec5SDimitry Andric
8760b57cec5SDimitry Andric // end of file //
877