Path: blob/main/contrib/llvm-project/openmp/runtime/src/kmp_i18n.cpp
35258 views
/*1* kmp_i18n.cpp2*/34//===----------------------------------------------------------------------===//5//6// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.7// See https://llvm.org/LICENSE.txt for license information.8// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception9//10//===----------------------------------------------------------------------===//1112#include "kmp_i18n.h"1314#include "kmp.h"15#include "kmp_debug.h"16#include "kmp_io.h" // __kmp_printf.17#include "kmp_lock.h"18#include "kmp_os.h"1920#include <errno.h>21#include <locale.h>22#include <stdarg.h>23#include <stdio.h>24#include <string.h>2526#include "kmp_environment.h"27#include "kmp_i18n_default.inc"28#include "kmp_str.h"2930#undef KMP_I18N_OK3132#define get_section(id) ((id) >> 16)33#define get_number(id) ((id)&0xFFFF)3435kmp_msg_t __kmp_msg_null = {kmp_mt_dummy, 0, NULL, 0};36static char const *no_message_available = "(No message available)";3738static void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message,39va_list ap);4041enum kmp_i18n_cat_status {42KMP_I18N_CLOSED, // Not yet opened or closed.43KMP_I18N_OPENED, // Opened successfully, ready to use.44KMP_I18N_ABSENT // Opening failed, message catalog should not be used.45}; // enum kmp_i18n_cat_status46typedef enum kmp_i18n_cat_status kmp_i18n_cat_status_t;47static volatile kmp_i18n_cat_status_t status = KMP_I18N_CLOSED;4849/* Message catalog is opened at first usage, so we have to synchronize opening50to avoid race and multiple openings.5152Closing does not require synchronization, because catalog is closed very late53at library shutting down, when no other threads are alive. */5455static void __kmp_i18n_do_catopen();56static kmp_bootstrap_lock_t lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(lock);57// `lock' variable may be placed into __kmp_i18n_catopen function because it is58// used only by that function. But we afraid a (buggy) compiler may treat it59// wrongly. So we put it outside of function just in case.6061void __kmp_i18n_catopen() {62if (status == KMP_I18N_CLOSED) {63__kmp_acquire_bootstrap_lock(&lock);64if (status == KMP_I18N_CLOSED) {65__kmp_i18n_do_catopen();66}67__kmp_release_bootstrap_lock(&lock);68}69} // func __kmp_i18n_catopen7071/* Linux* OS and OS X* part */72#if KMP_OS_UNIX73#define KMP_I18N_OK7475#include <nl_types.h>7677#define KMP_I18N_NULLCAT ((nl_catd)(-1))78static nl_catd cat = KMP_I18N_NULLCAT; // !!! Shall it be volatile?79static char const *name =80(KMP_VERSION_MAJOR == 4 ? "libguide.cat" : "libomp.cat");8182/* Useful links:83http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html#tag_08_0284http://www.opengroup.org/onlinepubs/000095399/functions/catopen.html85http://www.opengroup.org/onlinepubs/000095399/functions/setlocale.html86*/8788void __kmp_i18n_do_catopen() {89int english = 0;90char *lang = __kmp_env_get("LANG");91// TODO: What about LC_ALL or LC_MESSAGES?9293KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);94KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);9596english = lang == NULL || // In all these cases English language is used.97strcmp(lang, "") == 0 || strcmp(lang, " ") == 0 ||98// Workaround for Fortran RTL bug DPD200137873 "Fortran runtime99// resets LANG env var to space if it is not set".100strcmp(lang, "C") == 0 || strcmp(lang, "POSIX") == 0;101102if (!english) { // English language is not yet detected, let us continue.103// Format of LANG is: [language[_territory][.codeset][@modifier]]104// Strip all parts except language.105char *tail = NULL;106__kmp_str_split(lang, '@', &lang, &tail);107__kmp_str_split(lang, '.', &lang, &tail);108__kmp_str_split(lang, '_', &lang, &tail);109english = (strcmp(lang, "en") == 0);110}111112KMP_INTERNAL_FREE(lang);113114// Do not try to open English catalog because internal messages are115// exact copy of messages in English catalog.116if (english) {117status = KMP_I18N_ABSENT; // mark catalog as absent so it will not118// be re-opened.119return;120}121122cat = catopen(name, 0);123// TODO: Why do we pass 0 in flags?124status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);125126if (status == KMP_I18N_ABSENT) {127if (__kmp_generate_warnings > kmp_warnings_low) {128// AC: only issue warning in case explicitly asked to129int error = errno; // Save errno immediately.130char *nlspath = __kmp_env_get("NLSPATH");131char *lang = __kmp_env_get("LANG");132133// Infinite recursion will not occur -- status is KMP_I18N_ABSENT now, so134// __kmp_i18n_catgets() will not try to open catalog, but will return135// default message.136kmp_msg_t err_code = KMP_ERR(error);137__kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, name), err_code,138KMP_HNT(CheckEnvVar, "NLSPATH", nlspath),139KMP_HNT(CheckEnvVar, "LANG", lang), __kmp_msg_null);140if (__kmp_generate_warnings == kmp_warnings_off) {141__kmp_str_free(&err_code.str);142}143144KMP_INFORM(WillUseDefaultMessages);145KMP_INTERNAL_FREE(nlspath);146KMP_INTERNAL_FREE(lang);147}148} else { // status == KMP_I18N_OPENED149int section = get_section(kmp_i18n_prp_Version);150int number = get_number(kmp_i18n_prp_Version);151char const *expected = __kmp_i18n_default_table.sect[section].str[number];152// Expected version of the catalog.153kmp_str_buf_t version; // Actual version of the catalog.154__kmp_str_buf_init(&version);155__kmp_str_buf_print(&version, "%s", catgets(cat, section, number, NULL));156157// String returned by catgets is invalid after closing catalog, so copy it.158if (strcmp(version.str, expected) != 0) {159__kmp_i18n_catclose(); // Close bad catalog.160status = KMP_I18N_ABSENT; // And mark it as absent.161if (__kmp_generate_warnings > kmp_warnings_low) {162// AC: only issue warning in case explicitly asked to163// And now print a warning using default messages.164char const *name = "NLSPATH";165char const *nlspath = __kmp_env_get(name);166__kmp_msg(kmp_ms_warning,167KMP_MSG(WrongMessageCatalog, name, version.str, expected),168KMP_HNT(CheckEnvVar, name, nlspath), __kmp_msg_null);169KMP_INFORM(WillUseDefaultMessages);170KMP_INTERNAL_FREE(CCAST(char *, nlspath));171} // __kmp_generate_warnings172}173__kmp_str_buf_free(&version);174}175} // func __kmp_i18n_do_catopen176177void __kmp_i18n_catclose() {178if (status == KMP_I18N_OPENED) {179KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);180catclose(cat);181cat = KMP_I18N_NULLCAT;182}183status = KMP_I18N_CLOSED;184} // func __kmp_i18n_catclose185186char const *__kmp_i18n_catgets(kmp_i18n_id_t id) {187188int section = get_section(id);189int number = get_number(id);190char const *message = NULL;191192if (1 <= section && section <= __kmp_i18n_default_table.size) {193if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {194if (status == KMP_I18N_CLOSED) {195__kmp_i18n_catopen();196}197if (status == KMP_I18N_OPENED) {198message = catgets(cat, section, number,199__kmp_i18n_default_table.sect[section].str[number]);200}201if (message == NULL) {202message = __kmp_i18n_default_table.sect[section].str[number];203}204}205}206if (message == NULL) {207message = no_message_available;208}209return message;210211} // func __kmp_i18n_catgets212213#endif // KMP_OS_UNIX214215/* Windows* OS part. */216217#if KMP_OS_WINDOWS218#define KMP_I18N_OK219220#include "kmp_environment.h"221#include <windows.h>222223#define KMP_I18N_NULLCAT NULL224static HMODULE cat = KMP_I18N_NULLCAT; // !!! Shall it be volatile?225static char const *name =226(KMP_VERSION_MAJOR == 4 ? "libguide40ui.dll" : "libompui.dll");227228static kmp_i18n_table_t table = {0, NULL};229// Messages formatted by FormatMessage() should be freed, but catgets()230// interface assumes user will not free messages. So we cache all the retrieved231// messages in the table, which are freed at catclose().232static UINT const default_code_page = CP_OEMCP;233static UINT code_page = default_code_page;234235static char const *___catgets(kmp_i18n_id_t id);236static UINT get_code_page();237static void kmp_i18n_table_free(kmp_i18n_table_t *table);238239static UINT get_code_page() {240241UINT cp = default_code_page;242char const *value = __kmp_env_get("KMP_CODEPAGE");243if (value != NULL) {244if (_stricmp(value, "ANSI") == 0) {245cp = CP_ACP;246} else if (_stricmp(value, "OEM") == 0) {247cp = CP_OEMCP;248} else if (_stricmp(value, "UTF-8") == 0 || _stricmp(value, "UTF8") == 0) {249cp = CP_UTF8;250} else if (_stricmp(value, "UTF-7") == 0 || _stricmp(value, "UTF7") == 0) {251cp = CP_UTF7;252} else {253// !!! TODO: Issue a warning?254}255}256KMP_INTERNAL_FREE((void *)value);257return cp;258259} // func get_code_page260261static void kmp_i18n_table_free(kmp_i18n_table_t *table) {262int s;263int m;264for (s = 0; s < table->size; ++s) {265for (m = 0; m < table->sect[s].size; ++m) {266// Free message.267KMP_INTERNAL_FREE((void *)table->sect[s].str[m]);268table->sect[s].str[m] = NULL;269}270table->sect[s].size = 0;271// Free section itself.272KMP_INTERNAL_FREE((void *)table->sect[s].str);273table->sect[s].str = NULL;274}275table->size = 0;276KMP_INTERNAL_FREE((void *)table->sect);277table->sect = NULL;278} // kmp_i18n_table_free279280void __kmp_i18n_do_catopen() {281282LCID locale_id = GetThreadLocale();283WORD lang_id = LANGIDFROMLCID(locale_id);284WORD primary_lang_id = PRIMARYLANGID(lang_id);285kmp_str_buf_t path;286287KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);288KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);289290__kmp_str_buf_init(&path);291292// Do not try to open English catalog because internal messages are exact copy293// of messages in English catalog.294if (primary_lang_id == LANG_ENGLISH) {295status = KMP_I18N_ABSENT; // mark catalog as absent so it will not296// be re-opened.297goto end;298}299300// Construct resource DLL name.301/* Simple LoadLibrary( name ) is not suitable due to security issue (see302http://www.microsoft.com/technet/security/advisory/2269637.mspx). We have303to specify full path to the message catalog. */304{305// Get handle of our DLL first.306HMODULE handle;307BOOL brc = GetModuleHandleEx(308GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |309GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,310reinterpret_cast<LPCSTR>(&__kmp_i18n_do_catopen), &handle);311if (!brc) { // Error occurred.312status = KMP_I18N_ABSENT; // mark catalog as absent so it will not be313// re-opened.314goto end;315// TODO: Enable multiple messages (KMP_MSG) to be passed to __kmp_msg; and316// print a proper warning.317}318319// Now get path to the our DLL.320for (;;) {321DWORD drc = GetModuleFileName(handle, path.str, path.size);322if (drc == 0) { // Error occurred.323status = KMP_I18N_ABSENT;324goto end;325}326if (drc < path.size) {327path.used = drc;328break;329}330__kmp_str_buf_reserve(&path, path.size * 2);331}332333// Now construct the name of message catalog.334kmp_str_fname fname;335__kmp_str_fname_init(&fname, path.str);336__kmp_str_buf_clear(&path);337__kmp_str_buf_print(&path, "%s%lu/%s", fname.dir,338(unsigned long)(locale_id), name);339__kmp_str_fname_free(&fname);340}341342// For security reasons, use LoadLibraryEx() and load message catalog as a343// data file.344cat = LoadLibraryEx(path.str, NULL, LOAD_LIBRARY_AS_DATAFILE);345status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);346347if (status == KMP_I18N_ABSENT) {348if (__kmp_generate_warnings > kmp_warnings_low) {349// AC: only issue warning in case explicitly asked to350DWORD error = GetLastError();351// Infinite recursion will not occur -- status is KMP_I18N_ABSENT now, so352// __kmp_i18n_catgets() will not try to open catalog but will return353// default message.354/* If message catalog for another architecture found (e.g. OpenMP RTL for355IA-32 architecture opens libompui.dll for Intel(R) 64) Windows* OS356returns error 193 (ERROR_BAD_EXE_FORMAT). However, FormatMessage fails357to return a message for this error, so user will see:358359OMP: Warning #2: Cannot open message catalog "1041\libompui.dll":360OMP: System error #193: (No system error message available)361OMP: Info #3: Default messages will be used.362363Issue hint in this case so cause of trouble is more understandable. */364kmp_msg_t err_code = KMP_SYSERRCODE(error);365__kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, path.str),366err_code,367(error == ERROR_BAD_EXE_FORMAT368? KMP_HNT(BadExeFormat, path.str, KMP_ARCH_STR)369: __kmp_msg_null),370__kmp_msg_null);371if (__kmp_generate_warnings == kmp_warnings_off) {372__kmp_str_free(&err_code.str);373}374KMP_INFORM(WillUseDefaultMessages);375}376} else { // status == KMP_I18N_OPENED377378int section = get_section(kmp_i18n_prp_Version);379int number = get_number(kmp_i18n_prp_Version);380char const *expected = __kmp_i18n_default_table.sect[section].str[number];381kmp_str_buf_t version; // Actual version of the catalog.382__kmp_str_buf_init(&version);383__kmp_str_buf_print(&version, "%s", ___catgets(kmp_i18n_prp_Version));384// String returned by catgets is invalid after closing catalog, so copy it.385if (strcmp(version.str, expected) != 0) {386// Close bad catalog.387__kmp_i18n_catclose();388status = KMP_I18N_ABSENT; // And mark it as absent.389if (__kmp_generate_warnings > kmp_warnings_low) {390// And now print a warning using default messages.391__kmp_msg(kmp_ms_warning,392KMP_MSG(WrongMessageCatalog, path.str, version.str, expected),393__kmp_msg_null);394KMP_INFORM(WillUseDefaultMessages);395} // __kmp_generate_warnings396}397__kmp_str_buf_free(&version);398}399code_page = get_code_page();400401end:402__kmp_str_buf_free(&path);403return;404} // func __kmp_i18n_do_catopen405406void __kmp_i18n_catclose() {407if (status == KMP_I18N_OPENED) {408KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);409kmp_i18n_table_free(&table);410FreeLibrary(cat);411cat = KMP_I18N_NULLCAT;412}413code_page = default_code_page;414status = KMP_I18N_CLOSED;415} // func __kmp_i18n_catclose416417/* We use FormatMessage() to get strings from catalog, get system error418messages, etc. FormatMessage() tends to return Windows* OS-style419end-of-lines, "\r\n". When string is printed, printf() also replaces all the420occurrences of "\n" with "\r\n" (again!), so sequences like "\r\r\r\n"421appear in output. It is not too good.422423Additional mess comes from message catalog: Our catalog source en_US.mc file424(generated by message-converter.pl) contains only "\n" characters, but425en_US_msg_1033.bin file (produced by mc.exe) may contain "\r\n" or just "\n".426This mess goes from en_US_msg_1033.bin file to message catalog,427libompui.dll. For example, message428429Error430431(there is "\n" at the end) is compiled by mc.exe to "Error\r\n", while432433OMP: Error %1!d!: %2!s!\n434435(there is "\n" at the end as well) is compiled to "OMP: Error %1!d!:436%2!s!\r\n\n".437438Thus, stripping all "\r" normalizes string and returns it to canonical form,439so printf() will produce correct end-of-line sequences.440441___strip_crs() serves for this purpose: it removes all the occurrences of442"\r" in-place and returns new length of string. */443static int ___strip_crs(char *str) {444int in = 0; // Input character index.445int out = 0; // Output character index.446for (;;) {447if (str[in] != '\r') {448str[out] = str[in];449++out;450}451if (str[in] == 0) {452break;453}454++in;455}456return out - 1;457} // func __strip_crs458459static char const *___catgets(kmp_i18n_id_t id) {460461char *result = NULL;462PVOID addr = NULL;463wchar_t *wmsg = NULL;464DWORD wlen = 0;465char *msg = NULL;466int len = 0;467int rc;468469KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);470wlen = // wlen does *not* include terminating null.471FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |472FORMAT_MESSAGE_FROM_HMODULE |473FORMAT_MESSAGE_IGNORE_INSERTS,474cat, id,4750, // LangId476(LPWSTR)&addr,4770, // Size in elements, not in bytes.478NULL);479if (wlen <= 0) {480goto end;481}482wmsg = (wchar_t *)addr; // Warning: wmsg may be not nul-terminated!483484// Calculate length of multibyte message.485// Since wlen does not include terminating null, len does not include it also.486len = WideCharToMultiByte(code_page,4870, // Flags.488wmsg, wlen, // Wide buffer and size.489NULL, 0, // Buffer and size.490NULL, NULL // Default char and used default char.491);492if (len <= 0) {493goto end;494}495496// Allocate memory.497msg = (char *)KMP_INTERNAL_MALLOC(len + 1);498499// Convert wide message to multibyte one.500rc = WideCharToMultiByte(code_page,5010, // Flags.502wmsg, wlen, // Wide buffer and size.503msg, len, // Buffer and size.504NULL, NULL // Default char and used default char.505);506if (rc <= 0 || rc > len) {507goto end;508}509KMP_DEBUG_ASSERT(rc == len);510len = rc;511msg[len] = 0; // Put terminating null to the end.512513// Stripping all "\r" before stripping last end-of-line simplifies the task.514len = ___strip_crs(msg);515516// Every message in catalog is terminated with "\n". Strip it.517if (len >= 1 && msg[len - 1] == '\n') {518--len;519msg[len] = 0;520}521522// Everything looks ok.523result = msg;524msg = NULL;525526end:527528if (msg != NULL) {529KMP_INTERNAL_FREE(msg);530}531if (wmsg != NULL) {532LocalFree(wmsg);533}534535return result;536537} // ___catgets538539char const *__kmp_i18n_catgets(kmp_i18n_id_t id) {540541int section = get_section(id);542int number = get_number(id);543char const *message = NULL;544545if (1 <= section && section <= __kmp_i18n_default_table.size) {546if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {547if (status == KMP_I18N_CLOSED) {548__kmp_i18n_catopen();549}550if (cat != KMP_I18N_NULLCAT) {551if (table.size == 0) {552table.sect = (kmp_i18n_section_t *)KMP_INTERNAL_CALLOC(553(__kmp_i18n_default_table.size + 2), sizeof(kmp_i18n_section_t));554table.size = __kmp_i18n_default_table.size;555}556if (table.sect[section].size == 0) {557table.sect[section].str = (const char **)KMP_INTERNAL_CALLOC(558__kmp_i18n_default_table.sect[section].size + 2,559sizeof(char const *));560table.sect[section].size =561__kmp_i18n_default_table.sect[section].size;562}563if (table.sect[section].str[number] == NULL) {564table.sect[section].str[number] = ___catgets(id);565}566message = table.sect[section].str[number];567}568if (message == NULL) {569// Catalog is not opened or message is not found, return default570// message.571message = __kmp_i18n_default_table.sect[section].str[number];572}573}574}575if (message == NULL) {576message = no_message_available;577}578return message;579580} // func __kmp_i18n_catgets581582#endif // KMP_OS_WINDOWS583584// -----------------------------------------------------------------------------585586#ifndef KMP_I18N_OK587#error I18n support is not implemented for this OS.588#endif // KMP_I18N_OK589590// -----------------------------------------------------------------------------591592void __kmp_i18n_dump_catalog(kmp_str_buf_t *buffer) {593594struct kmp_i18n_id_range_t {595kmp_i18n_id_t first;596kmp_i18n_id_t last;597}; // struct kmp_i18n_id_range_t598599static struct kmp_i18n_id_range_t ranges[] = {600{kmp_i18n_prp_first, kmp_i18n_prp_last},601{kmp_i18n_str_first, kmp_i18n_str_last},602{kmp_i18n_fmt_first, kmp_i18n_fmt_last},603{kmp_i18n_msg_first, kmp_i18n_msg_last},604{kmp_i18n_hnt_first, kmp_i18n_hnt_last}}; // ranges605606int num_of_ranges = sizeof(ranges) / sizeof(struct kmp_i18n_id_range_t);607int range;608kmp_i18n_id_t id;609610for (range = 0; range < num_of_ranges; ++range) {611__kmp_str_buf_print(buffer, "*** Set #%d ***\n", range + 1);612for (id = (kmp_i18n_id_t)(ranges[range].first + 1); id < ranges[range].last;613id = (kmp_i18n_id_t)(id + 1)) {614__kmp_str_buf_print(buffer, "%d: <<%s>>\n", id, __kmp_i18n_catgets(id));615}616}617618__kmp_printf("%s", buffer->str);619620} // __kmp_i18n_dump_catalog621622// -----------------------------------------------------------------------------623kmp_msg_t __kmp_msg_format(unsigned id_arg, ...) {624625kmp_msg_t msg;626va_list args;627kmp_str_buf_t buffer;628__kmp_str_buf_init(&buffer);629630va_start(args, id_arg);631632// We use unsigned for the ID argument and explicitly cast it here to the633// right enumerator because variadic functions are not compatible with634// default promotions.635kmp_i18n_id_t id = (kmp_i18n_id_t)id_arg;636637#if KMP_OS_UNIX638// On Linux* OS and OS X*, printf() family functions process parameter639// numbers, for example: "%2$s %1$s".640__kmp_str_buf_vprint(&buffer, __kmp_i18n_catgets(id), args);641#elif KMP_OS_WINDOWS642// On Windows, printf() family functions does not recognize GNU style643// parameter numbers, so we have to use FormatMessage() instead. It recognizes644// parameter numbers, e. g.: "%2!s! "%1!s!".645{646LPTSTR str = NULL;647int len;648FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,649__kmp_i18n_catgets(id), 0, 0, (LPTSTR)(&str), 0, &args);650len = ___strip_crs(str);651__kmp_str_buf_cat(&buffer, str, len);652LocalFree(str);653}654#else655#error656#endif657va_end(args);658__kmp_str_buf_detach(&buffer);659660msg.type = (kmp_msg_type_t)(id >> 16);661msg.num = id & 0xFFFF;662msg.str = buffer.str;663msg.len = buffer.used;664665return msg;666667} // __kmp_msg_format668669// -----------------------------------------------------------------------------670static char *sys_error(int err) {671672char *message = NULL;673674#if KMP_OS_WINDOWS675676LPVOID buffer = NULL;677int len;678DWORD rc;679rc = FormatMessage(680FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,681MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.682(LPTSTR)&buffer, 0, NULL);683if (rc > 0) {684// Message formatted. Copy it (so we can free it later with normal free().685message = __kmp_str_format("%s", (char *)buffer);686len = ___strip_crs(message); // Delete carriage returns if any.687// Strip trailing newlines.688while (len > 0 && message[len - 1] == '\n') {689--len;690}691message[len] = 0;692} else {693// FormatMessage() failed to format system error message. GetLastError()694// would give us error code, which we would convert to message... this it695// dangerous recursion, which cannot clarify original error, so we will not696// even start it.697}698if (buffer != NULL) {699LocalFree(buffer);700}701702#else // Non-Windows* OS: Linux* OS or OS X*703704/* There are 2 incompatible versions of strerror_r:705706char * strerror_r( int, char *, size_t ); // GNU version707int strerror_r( int, char *, size_t ); // XSI version708*/709710#if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || \711(defined(__BIONIC__) && defined(_GNU_SOURCE) && \712__ANDROID_API__ >= __ANDROID_API_M__)713// GNU version of strerror_r.714715char buffer[2048];716char *const err_msg = strerror_r(err, buffer, sizeof(buffer));717// Do not eliminate this assignment to temporary variable, otherwise compiler718// would not issue warning if strerror_r() returns `int' instead of expected719// `char *'.720message = __kmp_str_format("%s", err_msg);721722#else // OS X*, FreeBSD* etc.723// XSI version of strerror_r.724int size = 2048;725char *buffer = (char *)KMP_INTERNAL_MALLOC(size);726int rc;727if (buffer == NULL) {728KMP_FATAL(MemoryAllocFailed);729}730rc = strerror_r(err, buffer, size);731if (rc == -1) {732rc = errno; // XSI version sets errno.733}734while (rc == ERANGE) { // ERANGE means the buffer is too small.735KMP_INTERNAL_FREE(buffer);736size *= 2;737buffer = (char *)KMP_INTERNAL_MALLOC(size);738if (buffer == NULL) {739KMP_FATAL(MemoryAllocFailed);740}741rc = strerror_r(err, buffer, size);742if (rc == -1) {743rc = errno; // XSI version sets errno.744}745}746if (rc == 0) {747message = buffer;748} else { // Buffer is unused. Free it.749KMP_INTERNAL_FREE(buffer);750}751752#endif753754#endif /* KMP_OS_WINDOWS */755756if (message == NULL) {757// TODO: I18n this message.758message = __kmp_str_format("%s", "(No system error message available)");759}760return message;761} // sys_error762763// -----------------------------------------------------------------------------764kmp_msg_t __kmp_msg_error_code(int code) {765766kmp_msg_t msg;767msg.type = kmp_mt_syserr;768msg.num = code;769msg.str = sys_error(code);770msg.len = KMP_STRLEN(msg.str);771return msg;772773} // __kmp_msg_error_code774775// -----------------------------------------------------------------------------776kmp_msg_t __kmp_msg_error_mesg(char const *mesg) {777778kmp_msg_t msg;779msg.type = kmp_mt_syserr;780msg.num = 0;781msg.str = __kmp_str_format("%s", mesg);782msg.len = KMP_STRLEN(msg.str);783return msg;784785} // __kmp_msg_error_mesg786787// -----------------------------------------------------------------------------788void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, va_list args) {789kmp_i18n_id_t format; // format identifier790kmp_msg_t fmsg; // formatted message791kmp_str_buf_t buffer;792793if (severity != kmp_ms_fatal && __kmp_generate_warnings == kmp_warnings_off)794return; // no reason to form a string in order to not print it795796__kmp_str_buf_init(&buffer);797798// Format the primary message.799switch (severity) {800case kmp_ms_inform: {801format = kmp_i18n_fmt_Info;802} break;803case kmp_ms_warning: {804format = kmp_i18n_fmt_Warning;805} break;806case kmp_ms_fatal: {807format = kmp_i18n_fmt_Fatal;808} break;809default: {810KMP_DEBUG_ASSERT(0);811}812}813fmsg = __kmp_msg_format(format, message.num, message.str);814__kmp_str_free(&message.str);815__kmp_str_buf_cat(&buffer, fmsg.str, fmsg.len);816__kmp_str_free(&fmsg.str);817818// Format other messages.819for (;;) {820message = va_arg(args, kmp_msg_t);821if (message.type == kmp_mt_dummy && message.str == NULL) {822break;823}824switch (message.type) {825case kmp_mt_hint: {826format = kmp_i18n_fmt_Hint;827// we cannot skip %1$ and only use %2$ to print the message without the828// number829fmsg = __kmp_msg_format(format, message.str);830} break;831case kmp_mt_syserr: {832format = kmp_i18n_fmt_SysErr;833fmsg = __kmp_msg_format(format, message.num, message.str);834} break;835default: {836KMP_DEBUG_ASSERT(0);837}838}839__kmp_str_free(&message.str);840__kmp_str_buf_cat(&buffer, fmsg.str, fmsg.len);841__kmp_str_free(&fmsg.str);842}843844// Print formatted messages.845// This lock prevents multiple fatal errors on the same problem.846// __kmp_acquire_bootstrap_lock( & lock ); // GEH - This lock causing tests847// to hang on OS X*.848__kmp_printf("%s", buffer.str);849__kmp_str_buf_free(&buffer);850851// __kmp_release_bootstrap_lock( & lock ); // GEH - this lock causing tests852// to hang on OS X*.853854} // __kmp_msg855856void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, ...) {857va_list args;858va_start(args, message);859__kmp_msg(severity, message, args);860va_end(args);861}862863void __kmp_fatal(kmp_msg_t message, ...) {864va_list args;865va_start(args, message);866__kmp_msg(kmp_ms_fatal, message, args);867va_end(args);868#if KMP_OS_WINDOWS869// Delay to give message a chance to appear before reaping870__kmp_thread_sleep(500);871#endif872__kmp_abort_process();873} // __kmp_fatal874875// end of file //876877878