5 //===----------------------------------------------------------------------===//
7 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
8 // See https://llvm.org/LICENSE.txt for license information.
9 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
11 //===----------------------------------------------------------------------===//
16 #include "kmp_debug.h"
17 #include "kmp_io.h" // __kmp_printf.
27 #include "kmp_environment.h"
28 #include "kmp_i18n_default.inc"
33 #define get_section(id) ((id) >> 16)
34 #define get_number(id) ((id)&0xFFFF)
36 kmp_msg_t __kmp_msg_null = {kmp_mt_dummy, 0, NULL, 0};
37 static char const *no_message_available = "(No message available)";
39 static void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message,
42 enum kmp_i18n_cat_status {
43 KMP_I18N_CLOSED, // Not yet opened or closed.
44 KMP_I18N_OPENED, // Opened successfully, ready to use.
45 KMP_I18N_ABSENT // Opening failed, message catalog should not be used.
46 }; // enum kmp_i18n_cat_status
47 typedef enum kmp_i18n_cat_status kmp_i18n_cat_status_t;
48 static volatile kmp_i18n_cat_status_t status = KMP_I18N_CLOSED;
50 /* Message catalog is opened at first usage, so we have to synchronize opening
51 to avoid race and multiple openings.
53 Closing does not require synchronization, because catalog is closed very late
54 at library shutting down, when no other threads are alive. */
56 static void __kmp_i18n_do_catopen();
57 static kmp_bootstrap_lock_t lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(lock);
58 // `lock' variable may be placed into __kmp_i18n_catopen function because it is
59 // used only by that function. But we afraid a (buggy) compiler may treat it
60 // wrongly. So we put it outside of function just in case.
62 void __kmp_i18n_catopen() {
63 if (status == KMP_I18N_CLOSED) {
64 __kmp_acquire_bootstrap_lock(&lock);
65 if (status == KMP_I18N_CLOSED) {
66 __kmp_i18n_do_catopen();
68 __kmp_release_bootstrap_lock(&lock);
70 } // func __kmp_i18n_catopen
72 /* Linux* OS and OS X* part */
78 #define KMP_I18N_NULLCAT ((nl_catd)(-1))
79 static nl_catd cat = KMP_I18N_NULLCAT; // !!! Shall it be volatile?
80 static char const *name =
81 (KMP_VERSION_MAJOR == 4 ? "libguide.cat" : "libomp.cat");
84 http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html#tag_08_02
85 http://www.opengroup.org/onlinepubs/000095399/functions/catopen.html
86 http://www.opengroup.org/onlinepubs/000095399/functions/setlocale.html
89 void __kmp_i18n_do_catopen() {
91 char *lang = __kmp_env_get("LANG");
92 // TODO: What about LC_ALL or LC_MESSAGES?
94 KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);
95 KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);
97 english = lang == NULL || // In all these cases English language is used.
98 strcmp(lang, "") == 0 || strcmp(lang, " ") == 0 ||
99 // Workaround for Fortran RTL bug DPD200137873 "Fortran runtime
100 // resets LANG env var to space if it is not set".
101 strcmp(lang, "C") == 0 || strcmp(lang, "POSIX") == 0;
103 if (!english) { // English language is not yet detected, let us continue.
104 // Format of LANG is: [language[_territory][.codeset][@modifier]]
105 // Strip all parts except language.
107 __kmp_str_split(lang, '@', &lang, &tail);
108 __kmp_str_split(lang, '.', &lang, &tail);
109 __kmp_str_split(lang, '_', &lang, &tail);
110 english = (strcmp(lang, "en") == 0);
113 KMP_INTERNAL_FREE(lang);
115 // Do not try to open English catalog because internal messages are
116 // exact copy of messages in English catalog.
118 status = KMP_I18N_ABSENT; // mark catalog as absent so it will not
123 cat = catopen(name, 0);
124 // TODO: Why do we pass 0 in flags?
125 status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);
127 if (status == KMP_I18N_ABSENT) {
128 if (__kmp_generate_warnings > kmp_warnings_low) {
129 // AC: only issue warning in case explicitly asked to
130 int error = errno; // Save errno immediately.
131 char *nlspath = __kmp_env_get("NLSPATH");
132 char *lang = __kmp_env_get("LANG");
134 // Infinite recursion will not occur -- status is KMP_I18N_ABSENT now, so
135 // __kmp_i18n_catgets() will not try to open catalog, but will return
137 kmp_msg_t err_code = KMP_ERR(error);
138 __kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, name), err_code,
139 KMP_HNT(CheckEnvVar, "NLSPATH", nlspath),
140 KMP_HNT(CheckEnvVar, "LANG", lang), __kmp_msg_null);
141 if (__kmp_generate_warnings == kmp_warnings_off) {
142 __kmp_str_free(&err_code.str);
145 KMP_INFORM(WillUseDefaultMessages);
146 KMP_INTERNAL_FREE(nlspath);
147 KMP_INTERNAL_FREE(lang);
149 } else { // status == KMP_I18N_OPENED
150 int section = get_section(kmp_i18n_prp_Version);
151 int number = get_number(kmp_i18n_prp_Version);
152 char const *expected = __kmp_i18n_default_table.sect[section].str[number];
153 // Expected version of the catalog.
154 kmp_str_buf_t version; // Actual version of the catalog.
155 __kmp_str_buf_init(&version);
156 __kmp_str_buf_print(&version, "%s", catgets(cat, section, number, NULL));
158 // String returned by catgets is invalid after closing catalog, so copy it.
159 if (strcmp(version.str, expected) != 0) {
160 __kmp_i18n_catclose(); // Close bad catalog.
161 status = KMP_I18N_ABSENT; // And mark it as absent.
162 if (__kmp_generate_warnings > kmp_warnings_low) {
163 // AC: only issue warning in case explicitly asked to
164 // And now print a warning using default messages.
165 char const *name = "NLSPATH";
166 char const *nlspath = __kmp_env_get(name);
167 __kmp_msg(kmp_ms_warning,
168 KMP_MSG(WrongMessageCatalog, name, version.str, expected),
169 KMP_HNT(CheckEnvVar, name, nlspath), __kmp_msg_null);
170 KMP_INFORM(WillUseDefaultMessages);
171 KMP_INTERNAL_FREE(CCAST(char *, nlspath));
172 } // __kmp_generate_warnings
174 __kmp_str_buf_free(&version);
176 } // func __kmp_i18n_do_catopen
178 void __kmp_i18n_catclose() {
179 if (status == KMP_I18N_OPENED) {
180 KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
182 cat = KMP_I18N_NULLCAT;
184 status = KMP_I18N_CLOSED;
185 } // func __kmp_i18n_catclose
187 char const *__kmp_i18n_catgets(kmp_i18n_id_t id) {
189 int section = get_section(id);
190 int number = get_number(id);
191 char const *message = NULL;
193 if (1 <= section && section <= __kmp_i18n_default_table.size) {
194 if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {
195 if (status == KMP_I18N_CLOSED) {
196 __kmp_i18n_catopen();
198 if (status == KMP_I18N_OPENED) {
199 message = catgets(cat, section, number,
200 __kmp_i18n_default_table.sect[section].str[number]);
202 if (message == NULL) {
203 message = __kmp_i18n_default_table.sect[section].str[number];
207 if (message == NULL) {
208 message = no_message_available;
212 } // func __kmp_i18n_catgets
214 #endif // KMP_OS_UNIX
216 /* Windows* OS part. */
221 #include "kmp_environment.h"
224 #define KMP_I18N_NULLCAT NULL
225 static HMODULE cat = KMP_I18N_NULLCAT; // !!! Shall it be volatile?
226 static char const *name =
227 (KMP_VERSION_MAJOR == 4 ? "libguide40ui.dll" : "libompui.dll");
229 static kmp_i18n_table_t table = {0, NULL};
230 // Messages formatted by FormatMessage() should be freed, but catgets()
231 // interface assumes user will not free messages. So we cache all the retrieved
232 // messages in the table, which are freed at catclose().
233 static UINT const default_code_page = CP_OEMCP;
234 static UINT code_page = default_code_page;
236 static char const *___catgets(kmp_i18n_id_t id);
237 static UINT get_code_page();
238 static void kmp_i18n_table_free(kmp_i18n_table_t *table);
240 static UINT get_code_page() {
242 UINT cp = default_code_page;
243 char const *value = __kmp_env_get("KMP_CODEPAGE");
245 if (_stricmp(value, "ANSI") == 0) {
247 } else if (_stricmp(value, "OEM") == 0) {
249 } else if (_stricmp(value, "UTF-8") == 0 || _stricmp(value, "UTF8") == 0) {
251 } else if (_stricmp(value, "UTF-7") == 0 || _stricmp(value, "UTF7") == 0) {
254 // !!! TODO: Issue a warning?
257 KMP_INTERNAL_FREE((void *)value);
260 } // func get_code_page
262 static void kmp_i18n_table_free(kmp_i18n_table_t *table) {
265 for (s = 0; s < table->size; ++s) {
266 for (m = 0; m < table->sect[s].size; ++m) {
268 KMP_INTERNAL_FREE((void *)table->sect[s].str[m]);
269 table->sect[s].str[m] = NULL;
271 table->sect[s].size = 0;
272 // Free section itself.
273 KMP_INTERNAL_FREE((void *)table->sect[s].str);
274 table->sect[s].str = NULL;
277 KMP_INTERNAL_FREE((void *)table->sect);
279 } // kmp_i18n_table_free
281 void __kmp_i18n_do_catopen() {
283 LCID locale_id = GetThreadLocale();
284 WORD lang_id = LANGIDFROMLCID(locale_id);
285 WORD primary_lang_id = PRIMARYLANGID(lang_id);
288 KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);
289 KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);
291 __kmp_str_buf_init(&path);
293 // Do not try to open English catalog because internal messages are exact copy
294 // of messages in English catalog.
295 if (primary_lang_id == LANG_ENGLISH) {
296 status = KMP_I18N_ABSENT; // mark catalog as absent so it will not
301 // Construct resource DLL name.
302 /* Simple LoadLibrary( name ) is not suitable due to security issue (see
303 http://www.microsoft.com/technet/security/advisory/2269637.mspx). We have
304 to specify full path to the message catalog. */
306 // Get handle of our DLL first.
308 BOOL brc = GetModuleHandleEx(
309 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
310 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
311 reinterpret_cast<LPCSTR>(&__kmp_i18n_do_catopen), &handle);
312 if (!brc) { // Error occurred.
313 status = KMP_I18N_ABSENT; // mark catalog as absent so it will not be
316 // TODO: Enable multiple messages (KMP_MSG) to be passed to __kmp_msg; and
317 // print a proper warning.
320 // Now get path to the our DLL.
322 DWORD drc = GetModuleFileName(handle, path.str, path.size);
323 if (drc == 0) { // Error occurred.
324 status = KMP_I18N_ABSENT;
327 if (drc < path.size) {
331 __kmp_str_buf_reserve(&path, path.size * 2);
334 // Now construct the name of message catalog.
336 __kmp_str_fname_init(&fname, path.str);
337 __kmp_str_buf_clear(&path);
338 __kmp_str_buf_print(&path, "%s%lu/%s", fname.dir,
339 (unsigned long)(locale_id), name);
340 __kmp_str_fname_free(&fname);
343 // For security reasons, use LoadLibraryEx() and load message catalog as a
345 cat = LoadLibraryEx(path.str, NULL, LOAD_LIBRARY_AS_DATAFILE);
346 status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);
348 if (status == KMP_I18N_ABSENT) {
349 if (__kmp_generate_warnings > kmp_warnings_low) {
350 // AC: only issue warning in case explicitly asked to
351 DWORD error = GetLastError();
352 // Infinite recursion will not occur -- status is KMP_I18N_ABSENT now, so
353 // __kmp_i18n_catgets() will not try to open catalog but will return
355 /* If message catalog for another architecture found (e.g. OpenMP RTL for
356 IA-32 architecture opens libompui.dll for Intel(R) 64) Windows* OS
357 returns error 193 (ERROR_BAD_EXE_FORMAT). However, FormatMessage fails
358 to return a message for this error, so user will see:
360 OMP: Warning #2: Cannot open message catalog "1041\libompui.dll":
361 OMP: System error #193: (No system error message available)
362 OMP: Info #3: Default messages will be used.
364 Issue hint in this case so cause of trouble is more understandable. */
365 kmp_msg_t err_code = KMP_SYSERRCODE(error);
366 __kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, path.str),
367 err_code, (error == ERROR_BAD_EXE_FORMAT
368 ? KMP_HNT(BadExeFormat, path.str, KMP_ARCH_STR)
371 if (__kmp_generate_warnings == kmp_warnings_off) {
372 __kmp_str_free(&err_code.str);
374 KMP_INFORM(WillUseDefaultMessages);
376 } else { // status == KMP_I18N_OPENED
378 int section = get_section(kmp_i18n_prp_Version);
379 int number = get_number(kmp_i18n_prp_Version);
380 char const *expected = __kmp_i18n_default_table.sect[section].str[number];
381 kmp_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.
385 if (strcmp(version.str, expected) != 0) {
386 // Close bad catalog.
387 __kmp_i18n_catclose();
388 status = KMP_I18N_ABSENT; // And mark it as absent.
389 if (__kmp_generate_warnings > kmp_warnings_low) {
390 // And now print a warning using default messages.
391 __kmp_msg(kmp_ms_warning,
392 KMP_MSG(WrongMessageCatalog, path.str, version.str, expected),
394 KMP_INFORM(WillUseDefaultMessages);
395 } // __kmp_generate_warnings
397 __kmp_str_buf_free(&version);
399 code_page = get_code_page();
402 __kmp_str_buf_free(&path);
404 } // func __kmp_i18n_do_catopen
406 void __kmp_i18n_catclose() {
407 if (status == KMP_I18N_OPENED) {
408 KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
409 kmp_i18n_table_free(&table);
411 cat = KMP_I18N_NULLCAT;
413 code_page = default_code_page;
414 status = KMP_I18N_CLOSED;
415 } // func __kmp_i18n_catclose
417 /* We use FormatMessage() to get strings from catalog, get system error
418 messages, etc. FormatMessage() tends to return Windows* OS-style
419 end-of-lines, "\r\n". When string is printed, printf() also replaces all the
420 occurrences of "\n" with "\r\n" (again!), so sequences like "\r\r\r\n"
421 appear in output. It is not too good.
423 Additional mess comes from message catalog: Our catalog source en_US.mc file
424 (generated by message-converter.pl) contains only "\n" characters, but
425 en_US_msg_1033.bin file (produced by mc.exe) may contain "\r\n" or just "\n".
426 This mess goes from en_US_msg_1033.bin file to message catalog,
427 libompui.dll. For example, message
431 (there is "\n" at the end) is compiled by mc.exe to "Error\r\n", while
433 OMP: Error %1!d!: %2!s!\n
435 (there is "\n" at the end as well) is compiled to "OMP: Error %1!d!:
438 Thus, stripping all "\r" normalizes string and returns it to canonical form,
439 so printf() will produce correct end-of-line sequences.
441 ___strip_crs() serves for this purpose: it removes all the occurrences of
442 "\r" in-place and returns new length of string. */
443 static int ___strip_crs(char *str) {
444 int in = 0; // Input character index.
445 int out = 0; // Output character index.
447 if (str[in] != '\r') {
457 } // func __strip_crs
459 static char const *___catgets(kmp_i18n_id_t id) {
463 wchar_t *wmsg = NULL;
469 KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
470 wlen = // wlen does *not* include terminating null.
471 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
472 FORMAT_MESSAGE_FROM_HMODULE |
473 FORMAT_MESSAGE_IGNORE_INSERTS,
477 0, // Size in elements, not in bytes.
482 wmsg = (wchar_t *)addr; // Warning: wmsg may be not nul-terminated!
484 // Calculate length of multibyte message.
485 // Since wlen does not include terminating null, len does not include it also.
486 len = WideCharToMultiByte(code_page,
488 wmsg, wlen, // Wide buffer and size.
489 NULL, 0, // Buffer and size.
490 NULL, NULL // Default char and used default char.
497 msg = (char *)KMP_INTERNAL_MALLOC(len + 1);
499 // Convert wide message to multibyte one.
500 rc = WideCharToMultiByte(code_page,
502 wmsg, wlen, // Wide buffer and size.
503 msg, len, // Buffer and size.
504 NULL, NULL // Default char and used default char.
506 if (rc <= 0 || rc > len) {
509 KMP_DEBUG_ASSERT(rc == len);
511 msg[len] = 0; // Put terminating null to the end.
513 // Stripping all "\r" before stripping last end-of-line simplifies the task.
514 len = ___strip_crs(msg);
516 // Every message in catalog is terminated with "\n". Strip it.
517 if (len >= 1 && msg[len - 1] == '\n') {
522 // Everything looks ok.
529 KMP_INTERNAL_FREE(msg);
539 char const *__kmp_i18n_catgets(kmp_i18n_id_t id) {
541 int section = get_section(id);
542 int number = get_number(id);
543 char const *message = NULL;
545 if (1 <= section && section <= __kmp_i18n_default_table.size) {
546 if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {
547 if (status == KMP_I18N_CLOSED) {
548 __kmp_i18n_catopen();
550 if (cat != KMP_I18N_NULLCAT) {
551 if (table.size == 0) {
552 table.sect = (kmp_i18n_section_t *)KMP_INTERNAL_CALLOC(
553 (__kmp_i18n_default_table.size + 2), sizeof(kmp_i18n_section_t));
554 table.size = __kmp_i18n_default_table.size;
556 if (table.sect[section].size == 0) {
557 table.sect[section].str = (const char **)KMP_INTERNAL_CALLOC(
558 __kmp_i18n_default_table.sect[section].size + 2,
559 sizeof(char const *));
560 table.sect[section].size =
561 __kmp_i18n_default_table.sect[section].size;
563 if (table.sect[section].str[number] == NULL) {
564 table.sect[section].str[number] = ___catgets(id);
566 message = table.sect[section].str[number];
568 if (message == NULL) {
569 // Catalog is not opened or message is not found, return default
571 message = __kmp_i18n_default_table.sect[section].str[number];
575 if (message == NULL) {
576 message = no_message_available;
580 } // func __kmp_i18n_catgets
582 #endif // KMP_OS_WINDOWS
584 // -----------------------------------------------------------------------------
587 #error I18n support is not implemented for this OS.
588 #endif // KMP_I18N_OK
590 // -----------------------------------------------------------------------------
592 void __kmp_i18n_dump_catalog(kmp_str_buf_t *buffer) {
594 struct kmp_i18n_id_range_t {
597 }; // struct kmp_i18n_id_range_t
599 static 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}}; // ranges
606 int num_of_ranges = sizeof(ranges) / sizeof(struct kmp_i18n_id_range_t);
610 for (range = 0; range < num_of_ranges; ++range) {
611 __kmp_str_buf_print(buffer, "*** Set #%d ***\n", range + 1);
612 for (id = (kmp_i18n_id_t)(ranges[range].first + 1); id < ranges[range].last;
613 id = (kmp_i18n_id_t)(id + 1)) {
614 __kmp_str_buf_print(buffer, "%d: <<%s>>\n", id, __kmp_i18n_catgets(id));
618 __kmp_printf("%s", buffer->str);
620 } // __kmp_i18n_dump_catalog
622 // -----------------------------------------------------------------------------
623 kmp_msg_t __kmp_msg_format(unsigned id_arg, ...) {
627 kmp_str_buf_t buffer;
628 __kmp_str_buf_init(&buffer);
630 va_start(args, id_arg);
632 // We use unsigned for the ID argument and explicitly cast it here to the
633 // right enumerator because variadic functions are not compatible with
634 // default promotions.
635 kmp_i18n_id_t id = (kmp_i18n_id_t)id_arg;
638 // On Linux* OS and OS X*, printf() family functions process parameter
639 // numbers, for example: "%2$s %1$s".
640 __kmp_str_buf_vprint(&buffer, __kmp_i18n_catgets(id), args);
642 // On Winodws, printf() family functions does not recognize GNU style
643 // parameter numbers, so we have to use FormatMessage() instead. It recognizes
644 // parameter numbers, e. g.: "%2!s! "%1!s!".
648 FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
649 __kmp_i18n_catgets(id), 0, 0, (LPTSTR)(&str), 0, &args);
650 len = ___strip_crs(str);
651 __kmp_str_buf_cat(&buffer, str, len);
658 __kmp_str_buf_detach(&buffer);
660 msg.type = (kmp_msg_type_t)(id >> 16);
661 msg.num = id & 0xFFFF;
662 msg.str = buffer.str;
663 msg.len = buffer.used;
667 } // __kmp_msg_format
669 // -----------------------------------------------------------------------------
670 static char *sys_error(int err) {
672 char *message = NULL;
676 LPVOID buffer = NULL;
680 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
681 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.
682 (LPTSTR)&buffer, 0, NULL);
684 // Message formatted. Copy it (so we can free it later with normal free().
685 message = __kmp_str_format("%s", (char *)buffer);
686 len = ___strip_crs(message); // Delete carriage returns if any.
687 // Strip trailing newlines.
688 while (len > 0 && message[len - 1] == '\n') {
693 // FormatMessage() failed to format system error message. GetLastError()
694 // would give us error code, which we would convert to message... this it
695 // dangerous recursion, which cannot clarify original error, so we will not
698 if (buffer != NULL) {
702 #else // Non-Windows* OS: Linux* OS or OS X*
704 /* There are 2 incompatible versions of strerror_r:
706 char * strerror_r( int, char *, size_t ); // GNU version
707 int strerror_r( int, char *, size_t ); // XSI version
710 #if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || \
711 (defined(__BIONIC__) && defined(_GNU_SOURCE) && \
712 __ANDROID_API__ >= __ANDROID_API_M__)
713 // GNU version of strerror_r.
716 char *const err_msg = strerror_r(err, buffer, sizeof(buffer));
717 // Do not eliminate this assignment to temporary variable, otherwise compiler
718 // would not issue warning if strerror_r() returns `int' instead of expected
720 message = __kmp_str_format("%s", err_msg);
722 #else // OS X*, FreeBSD* etc.
723 // XSI version of strerror_r.
725 char *buffer = (char *)KMP_INTERNAL_MALLOC(size);
727 if (buffer == NULL) {
728 KMP_FATAL(MemoryAllocFailed);
730 rc = strerror_r(err, buffer, size);
732 rc = errno; // XSI version sets errno.
734 while (rc == ERANGE) { // ERANGE means the buffer is too small.
735 KMP_INTERNAL_FREE(buffer);
737 buffer = (char *)KMP_INTERNAL_MALLOC(size);
738 if (buffer == NULL) {
739 KMP_FATAL(MemoryAllocFailed);
741 rc = strerror_r(err, buffer, size);
743 rc = errno; // XSI version sets errno.
748 } else { // Buffer is unused. Free it.
749 KMP_INTERNAL_FREE(buffer);
754 #endif /* KMP_OS_WINDOWS */
756 if (message == NULL) {
757 // TODO: I18n this message.
758 message = __kmp_str_format("%s", "(No system error message available)");
763 // -----------------------------------------------------------------------------
764 kmp_msg_t __kmp_msg_error_code(int code) {
767 msg.type = kmp_mt_syserr;
769 msg.str = sys_error(code);
770 msg.len = KMP_STRLEN(msg.str);
773 } // __kmp_msg_error_code
775 // -----------------------------------------------------------------------------
776 kmp_msg_t __kmp_msg_error_mesg(char const *mesg) {
779 msg.type = kmp_mt_syserr;
781 msg.str = __kmp_str_format("%s", mesg);
782 msg.len = KMP_STRLEN(msg.str);
785 } // __kmp_msg_error_mesg
787 // -----------------------------------------------------------------------------
788 void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, va_list args) {
789 kmp_i18n_id_t format; // format identifier
790 kmp_msg_t fmsg; // formatted message
791 kmp_str_buf_t buffer;
793 if (severity != kmp_ms_fatal && __kmp_generate_warnings == kmp_warnings_off)
794 return; // no reason to form a string in order to not print it
796 __kmp_str_buf_init(&buffer);
798 // Format the primary message.
800 case kmp_ms_inform: {
801 format = kmp_i18n_fmt_Info;
803 case kmp_ms_warning: {
804 format = kmp_i18n_fmt_Warning;
807 format = kmp_i18n_fmt_Fatal;
809 default: { KMP_DEBUG_ASSERT(0); }
811 fmsg = __kmp_msg_format(format, message.num, message.str);
812 __kmp_str_free(&message.str);
813 __kmp_str_buf_cat(&buffer, fmsg.str, fmsg.len);
814 __kmp_str_free(&fmsg.str);
816 // Format other messages.
818 message = va_arg(args, kmp_msg_t);
819 if (message.type == kmp_mt_dummy && message.str == NULL) {
822 switch (message.type) {
824 format = kmp_i18n_fmt_Hint;
825 // we cannot skip %1$ and only use %2$ to print the message without the
827 fmsg = __kmp_msg_format(format, message.str);
829 case kmp_mt_syserr: {
830 format = kmp_i18n_fmt_SysErr;
831 fmsg = __kmp_msg_format(format, message.num, message.str);
833 default: { KMP_DEBUG_ASSERT(0); }
835 __kmp_str_free(&message.str);
836 __kmp_str_buf_cat(&buffer, fmsg.str, fmsg.len);
837 __kmp_str_free(&fmsg.str);
840 // Print formatted messages.
841 // This lock prevents multiple fatal errors on the same problem.
842 // __kmp_acquire_bootstrap_lock( & lock ); // GEH - This lock causing tests
844 __kmp_printf("%s", buffer.str);
845 __kmp_str_buf_free(&buffer);
847 // __kmp_release_bootstrap_lock( & lock ); // GEH - this lock causing tests
852 void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, ...) {
854 va_start(args, message);
855 __kmp_msg(severity, message, args);
859 void __kmp_fatal(kmp_msg_t message, ...) {
861 va_start(args, message);
862 __kmp_msg(kmp_ms_fatal, message, args);
865 // Delay to give message a chance to appear before reaping
866 __kmp_thread_sleep(500);
868 __kmp_abort_process();