1 /*
2 * kmp_i18n.cpp
3 */
4
5 //===----------------------------------------------------------------------===//
6 //
7 // The LLVM Compiler Infrastructure
8 //
9 // This file is dual licensed under the MIT and the University of Illinois Open
10 // Source Licenses. See LICENSE.txt for details.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "kmp_i18n.h"
15
16 #include "kmp.h"
17 #include "kmp_debug.h"
18 #include "kmp_io.h" // __kmp_printf.
19 #include "kmp_lock.h"
20 #include "kmp_os.h"
21
22 #include <errno.h>
23 #include <locale.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <string.h>
27
28 #include "kmp_environment.h"
29 #include "kmp_i18n_default.inc"
30 #include "kmp_str.h"
31
32 #undef KMP_I18N_OK
33
34 #define get_section(id) ((id) >> 16)
35 #define get_number(id) ((id)&0xFFFF)
36
37 kmp_msg_t __kmp_msg_null = {kmp_mt_dummy, 0, NULL, 0};
38 static char const *no_message_available = "(No message available)";
39
40 static void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message,
41 va_list ap);
42
43 enum kmp_i18n_cat_status {
44 KMP_I18N_CLOSED, // Not yet opened or closed.
45 KMP_I18N_OPENED, // Opened successfully, ready to use.
46 KMP_I18N_ABSENT // Opening failed, message catalog should not be used.
47 }; // enum kmp_i18n_cat_status
48 typedef enum kmp_i18n_cat_status kmp_i18n_cat_status_t;
49 static volatile kmp_i18n_cat_status_t status = KMP_I18N_CLOSED;
50
51 /* Message catalog is opened at first usage, so we have to synchronize opening
52 to avoid race and multiple openings.
53
54 Closing does not require synchronization, because catalog is closed very late
55 at library shutting down, when no other threads are alive. */
56
57 static void __kmp_i18n_do_catopen();
58 static kmp_bootstrap_lock_t lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(lock);
59 // `lock' variable may be placed into __kmp_i18n_catopen function because it is
60 // used only by that function. But we afraid a (buggy) compiler may treat it
61 // wrongly. So we put it outside of function just in case.
62
__kmp_i18n_catopen()63 void __kmp_i18n_catopen() {
64 if (status == KMP_I18N_CLOSED) {
65 __kmp_acquire_bootstrap_lock(&lock);
66 if (status == KMP_I18N_CLOSED) {
67 __kmp_i18n_do_catopen();
68 }
69 __kmp_release_bootstrap_lock(&lock);
70 }
71 } // func __kmp_i18n_catopen
72
73 /* Linux* OS and OS X* part */
74 #if KMP_OS_UNIX
75 #define KMP_I18N_OK
76
77 #include <nl_types.h>
78
79 #define KMP_I18N_NULLCAT ((nl_catd)(-1))
80 static nl_catd cat = KMP_I18N_NULLCAT; // !!! Shall it be volatile?
81 static char const *name =
82 (KMP_VERSION_MAJOR == 4 ? "libguide.cat" : "libomp.cat");
83
84 /* Useful links:
85 http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap08.html#tag_08_02
86 http://www.opengroup.org/onlinepubs/000095399/functions/catopen.html
87 http://www.opengroup.org/onlinepubs/000095399/functions/setlocale.html
88 */
89
__kmp_i18n_do_catopen()90 void __kmp_i18n_do_catopen() {
91 int english = 0;
92 char *lang = __kmp_env_get("LANG");
93 // TODO: What about LC_ALL or LC_MESSAGES?
94
95 KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);
96 KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);
97
98 english = lang == NULL || // In all these cases English language is used.
99 strcmp(lang, "") == 0 || strcmp(lang, " ") == 0 ||
100 // Workaround for Fortran RTL bug DPD200137873 "Fortran runtime
101 // resets LANG env var to space if it is not set".
102 strcmp(lang, "C") == 0 || strcmp(lang, "POSIX") == 0;
103
104 if (!english) { // English language is not yet detected, let us continue.
105 // Format of LANG is: [language[_territory][.codeset][@modifier]]
106 // Strip all parts except language.
107 char *tail = NULL;
108 __kmp_str_split(lang, '@', &lang, &tail);
109 __kmp_str_split(lang, '.', &lang, &tail);
110 __kmp_str_split(lang, '_', &lang, &tail);
111 english = (strcmp(lang, "en") == 0);
112 }
113
114 KMP_INTERNAL_FREE(lang);
115
116 // Do not try to open English catalog because internal messages are
117 // exact copy of messages in English catalog.
118 if (english) {
119 status = KMP_I18N_ABSENT; // mark catalog as absent so it will not
120 // be re-opened.
121 return;
122 }
123
124 cat = catopen(name, 0);
125 // TODO: Why do we pass 0 in flags?
126 status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);
127
128 if (status == KMP_I18N_ABSENT) {
129 if (__kmp_generate_warnings > kmp_warnings_low) {
130 // AC: only issue warning in case explicitly asked to
131 int error = errno; // Save errno immediately.
132 char *nlspath = __kmp_env_get("NLSPATH");
133 char *lang = __kmp_env_get("LANG");
134
135 // Infinite recursion will not occur -- status is KMP_I18N_ABSENT now, so
136 // __kmp_i18n_catgets() will not try to open catalog, but will return
137 // default message.
138 kmp_msg_t err_code = KMP_ERR(error);
139 __kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, name), err_code,
140 KMP_HNT(CheckEnvVar, "NLSPATH", nlspath),
141 KMP_HNT(CheckEnvVar, "LANG", lang), __kmp_msg_null);
142 if (__kmp_generate_warnings == kmp_warnings_off) {
143 __kmp_str_free(&err_code.str);
144 }
145
146 KMP_INFORM(WillUseDefaultMessages);
147 KMP_INTERNAL_FREE(nlspath);
148 KMP_INTERNAL_FREE(lang);
149 }
150 } else { // status == KMP_I18N_OPENED
151 int section = get_section(kmp_i18n_prp_Version);
152 int number = get_number(kmp_i18n_prp_Version);
153 char const *expected = __kmp_i18n_default_table.sect[section].str[number];
154 // Expected version of the catalog.
155 kmp_str_buf_t version; // Actual version of the catalog.
156 __kmp_str_buf_init(&version);
157 __kmp_str_buf_print(&version, "%s", catgets(cat, section, number, NULL));
158
159 // String returned by catgets is invalid after closing catalog, so copy it.
160 if (strcmp(version.str, expected) != 0) {
161 __kmp_i18n_catclose(); // Close bad catalog.
162 status = KMP_I18N_ABSENT; // And mark it as absent.
163 if (__kmp_generate_warnings > kmp_warnings_low) {
164 // AC: only issue warning in case explicitly asked to
165 // And now print a warning using default messages.
166 char const *name = "NLSPATH";
167 char const *nlspath = __kmp_env_get(name);
168 __kmp_msg(kmp_ms_warning,
169 KMP_MSG(WrongMessageCatalog, name, version.str, expected),
170 KMP_HNT(CheckEnvVar, name, nlspath), __kmp_msg_null);
171 KMP_INFORM(WillUseDefaultMessages);
172 KMP_INTERNAL_FREE(CCAST(char *, nlspath));
173 } // __kmp_generate_warnings
174 }
175 __kmp_str_buf_free(&version);
176 }
177 } // func __kmp_i18n_do_catopen
178
__kmp_i18n_catclose()179 void __kmp_i18n_catclose() {
180 if (status == KMP_I18N_OPENED) {
181 KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
182 catclose(cat);
183 cat = KMP_I18N_NULLCAT;
184 }
185 status = KMP_I18N_CLOSED;
186 } // func __kmp_i18n_catclose
187
__kmp_i18n_catgets(kmp_i18n_id_t id)188 char const *__kmp_i18n_catgets(kmp_i18n_id_t id) {
189
190 int section = get_section(id);
191 int number = get_number(id);
192 char const *message = NULL;
193
194 if (1 <= section && section <= __kmp_i18n_default_table.size) {
195 if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {
196 if (status == KMP_I18N_CLOSED) {
197 __kmp_i18n_catopen();
198 }
199 if (status == KMP_I18N_OPENED) {
200 message = catgets(cat, section, number,
201 __kmp_i18n_default_table.sect[section].str[number]);
202 }
203 if (message == NULL) {
204 message = __kmp_i18n_default_table.sect[section].str[number];
205 }
206 }
207 }
208 if (message == NULL) {
209 message = no_message_available;
210 }
211 return message;
212
213 } // func __kmp_i18n_catgets
214
215 #endif // KMP_OS_UNIX
216
217 /* Windows* OS part. */
218
219 #if KMP_OS_WINDOWS
220 #define KMP_I18N_OK
221
222 #include "kmp_environment.h"
223 #include <windows.h>
224
225 #define KMP_I18N_NULLCAT NULL
226 static HMODULE cat = KMP_I18N_NULLCAT; // !!! Shall it be volatile?
227 static char const *name =
228 (KMP_VERSION_MAJOR == 4 ? "libguide40ui.dll" : "libompui.dll");
229
230 static kmp_i18n_table_t table = {0, NULL};
231 // Messages formatted by FormatMessage() should be freed, but catgets()
232 // interface assumes user will not free messages. So we cache all the retrieved
233 // messages in the table, which are freed at catclose().
234 static UINT const default_code_page = CP_OEMCP;
235 static UINT code_page = default_code_page;
236
237 static char const *___catgets(kmp_i18n_id_t id);
238 static UINT get_code_page();
239 static void kmp_i18n_table_free(kmp_i18n_table_t *table);
240
get_code_page()241 static UINT get_code_page() {
242
243 UINT cp = default_code_page;
244 char const *value = __kmp_env_get("KMP_CODEPAGE");
245 if (value != NULL) {
246 if (_stricmp(value, "ANSI") == 0) {
247 cp = CP_ACP;
248 } else if (_stricmp(value, "OEM") == 0) {
249 cp = CP_OEMCP;
250 } else if (_stricmp(value, "UTF-8") == 0 || _stricmp(value, "UTF8") == 0) {
251 cp = CP_UTF8;
252 } else if (_stricmp(value, "UTF-7") == 0 || _stricmp(value, "UTF7") == 0) {
253 cp = CP_UTF7;
254 } else {
255 // !!! TODO: Issue a warning?
256 }
257 }
258 KMP_INTERNAL_FREE((void *)value);
259 return cp;
260
261 } // func get_code_page
262
kmp_i18n_table_free(kmp_i18n_table_t * table)263 static void kmp_i18n_table_free(kmp_i18n_table_t *table) {
264 int s;
265 int m;
266 for (s = 0; s < table->size; ++s) {
267 for (m = 0; m < table->sect[s].size; ++m) {
268 // Free message.
269 KMP_INTERNAL_FREE((void *)table->sect[s].str[m]);
270 table->sect[s].str[m] = NULL;
271 }
272 table->sect[s].size = 0;
273 // Free section itself.
274 KMP_INTERNAL_FREE((void *)table->sect[s].str);
275 table->sect[s].str = NULL;
276 }
277 table->size = 0;
278 KMP_INTERNAL_FREE((void *)table->sect);
279 table->sect = NULL;
280 } // kmp_i18n_table_free
281
__kmp_i18n_do_catopen()282 void __kmp_i18n_do_catopen() {
283
284 LCID locale_id = GetThreadLocale();
285 WORD lang_id = LANGIDFROMLCID(locale_id);
286 WORD primary_lang_id = PRIMARYLANGID(lang_id);
287 kmp_str_buf_t path;
288
289 KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);
290 KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);
291
292 __kmp_str_buf_init(&path);
293
294 // Do not try to open English catalog because internal messages are exact copy
295 // of messages in English catalog.
296 if (primary_lang_id == LANG_ENGLISH) {
297 status = KMP_I18N_ABSENT; // mark catalog as absent so it will not
298 // be re-opened.
299 goto end;
300 }
301
302 // Construct resource DLL name.
303 /* Simple LoadLibrary( name ) is not suitable due to security issue (see
304 http://www.microsoft.com/technet/security/advisory/2269637.mspx). We have
305 to specify full path to the message catalog. */
306 {
307 // Get handle of our DLL first.
308 HMODULE handle;
309 BOOL brc = GetModuleHandleEx(
310 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
311 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
312 reinterpret_cast<LPCSTR>(&__kmp_i18n_do_catopen), &handle);
313 if (!brc) { // Error occurred.
314 status = KMP_I18N_ABSENT; // mark catalog as absent so it will not be
315 // re-opened.
316 goto end;
317 // TODO: Enable multiple messages (KMP_MSG) to be passed to __kmp_msg; and
318 // print a proper warning.
319 }
320
321 // Now get path to the our DLL.
322 for (;;) {
323 DWORD drc = GetModuleFileName(handle, path.str, path.size);
324 if (drc == 0) { // Error occurred.
325 status = KMP_I18N_ABSENT;
326 goto end;
327 }
328 if (drc < path.size) {
329 path.used = drc;
330 break;
331 }
332 __kmp_str_buf_reserve(&path, path.size * 2);
333 }
334
335 // Now construct the name of message catalog.
336 kmp_str_fname fname;
337 __kmp_str_fname_init(&fname, path.str);
338 __kmp_str_buf_clear(&path);
339 __kmp_str_buf_print(&path, "%s%lu/%s", fname.dir,
340 (unsigned long)(locale_id), name);
341 __kmp_str_fname_free(&fname);
342 }
343
344 // For security reasons, use LoadLibraryEx() and load message catalog as a
345 // data file.
346 cat = LoadLibraryEx(path.str, NULL, LOAD_LIBRARY_AS_DATAFILE);
347 status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);
348
349 if (status == KMP_I18N_ABSENT) {
350 if (__kmp_generate_warnings > kmp_warnings_low) {
351 // AC: only issue warning in case explicitly asked to
352 DWORD error = GetLastError();
353 // Infinite recursion will not occur -- status is KMP_I18N_ABSENT now, so
354 // __kmp_i18n_catgets() will not try to open catalog but will return
355 // default message.
356 /* If message catalog for another architecture found (e.g. OpenMP RTL for
357 IA-32 architecture opens libompui.dll for Intel(R) 64) Windows* OS
358 returns error 193 (ERROR_BAD_EXE_FORMAT). However, FormatMessage fails
359 to return a message for this error, so user will see:
360
361 OMP: Warning #2: Cannot open message catalog "1041\libompui.dll":
362 OMP: System error #193: (No system error message available)
363 OMP: Info #3: Default messages will be used.
364
365 Issue hint in this case so cause of trouble is more understandable. */
366 kmp_msg_t err_code = KMP_SYSERRCODE(error);
367 __kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, path.str),
368 err_code, (error == ERROR_BAD_EXE_FORMAT
369 ? KMP_HNT(BadExeFormat, path.str, KMP_ARCH_STR)
370 : __kmp_msg_null),
371 __kmp_msg_null);
372 if (__kmp_generate_warnings == kmp_warnings_off) {
373 __kmp_str_free(&err_code.str);
374 }
375 KMP_INFORM(WillUseDefaultMessages);
376 }
377 } else { // status == KMP_I18N_OPENED
378
379 int section = get_section(kmp_i18n_prp_Version);
380 int number = get_number(kmp_i18n_prp_Version);
381 char const *expected = __kmp_i18n_default_table.sect[section].str[number];
382 kmp_str_buf_t version; // Actual version of the catalog.
383 __kmp_str_buf_init(&version);
384 __kmp_str_buf_print(&version, "%s", ___catgets(kmp_i18n_prp_Version));
385 // String returned by catgets is invalid after closing catalog, so copy it.
386 if (strcmp(version.str, expected) != 0) {
387 // Close bad catalog.
388 __kmp_i18n_catclose();
389 status = KMP_I18N_ABSENT; // And mark it as absent.
390 if (__kmp_generate_warnings > kmp_warnings_low) {
391 // And now print a warning using default messages.
392 __kmp_msg(kmp_ms_warning,
393 KMP_MSG(WrongMessageCatalog, path.str, version.str, expected),
394 __kmp_msg_null);
395 KMP_INFORM(WillUseDefaultMessages);
396 } // __kmp_generate_warnings
397 }
398 __kmp_str_buf_free(&version);
399 }
400 code_page = get_code_page();
401
402 end:
403 __kmp_str_buf_free(&path);
404 return;
405 } // func __kmp_i18n_do_catopen
406
__kmp_i18n_catclose()407 void __kmp_i18n_catclose() {
408 if (status == KMP_I18N_OPENED) {
409 KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
410 kmp_i18n_table_free(&table);
411 FreeLibrary(cat);
412 cat = KMP_I18N_NULLCAT;
413 }
414 code_page = default_code_page;
415 status = KMP_I18N_CLOSED;
416 } // func __kmp_i18n_catclose
417
418 /* We use FormatMessage() to get strings from catalog, get system error
419 messages, etc. FormatMessage() tends to return Windows* OS-style
420 end-of-lines, "\r\n". When string is printed, printf() also replaces all the
421 occurrences of "\n" with "\r\n" (again!), so sequences like "\r\r\r\n"
422 appear in output. It is not too good.
423
424 Additional mess comes from message catalog: Our catalog source en_US.mc file
425 (generated by message-converter.pl) contains only "\n" characters, but
426 en_US_msg_1033.bin file (produced by mc.exe) may contain "\r\n" or just "\n".
427 This mess goes from en_US_msg_1033.bin file to message catalog,
428 libompui.dll. For example, message
429
430 Error
431
432 (there is "\n" at the end) is compiled by mc.exe to "Error\r\n", while
433
434 OMP: Error %1!d!: %2!s!\n
435
436 (there is "\n" at the end as well) is compiled to "OMP: Error %1!d!:
437 %2!s!\r\n\n".
438
439 Thus, stripping all "\r" normalizes string and returns it to canonical form,
440 so printf() will produce correct end-of-line sequences.
441
442 ___strip_crs() serves for this purpose: it removes all the occurrences of
443 "\r" in-place and returns new length of string. */
___strip_crs(char * str)444 static int ___strip_crs(char *str) {
445 int in = 0; // Input character index.
446 int out = 0; // Output character index.
447 for (;;) {
448 if (str[in] != '\r') {
449 str[out] = str[in];
450 ++out;
451 }
452 if (str[in] == 0) {
453 break;
454 }
455 ++in;
456 }
457 return out - 1;
458 } // func __strip_crs
459
___catgets(kmp_i18n_id_t id)460 static char const *___catgets(kmp_i18n_id_t id) {
461
462 char *result = NULL;
463 PVOID addr = NULL;
464 wchar_t *wmsg = NULL;
465 DWORD wlen = 0;
466 char *msg = NULL;
467 int len = 0;
468 int rc;
469
470 KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
471 wlen = // wlen does *not* include terminating null.
472 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
473 FORMAT_MESSAGE_FROM_HMODULE |
474 FORMAT_MESSAGE_IGNORE_INSERTS,
475 cat, id,
476 0, // LangId
477 (LPWSTR)&addr,
478 0, // Size in elements, not in bytes.
479 NULL);
480 if (wlen <= 0) {
481 goto end;
482 }
483 wmsg = (wchar_t *)addr; // Warning: wmsg may be not nul-terminated!
484
485 // Calculate length of multibyte message.
486 // Since wlen does not include terminating null, len does not include it also.
487 len = WideCharToMultiByte(code_page,
488 0, // Flags.
489 wmsg, wlen, // Wide buffer and size.
490 NULL, 0, // Buffer and size.
491 NULL, NULL // Default char and used default char.
492 );
493 if (len <= 0) {
494 goto end;
495 }
496
497 // Allocate memory.
498 msg = (char *)KMP_INTERNAL_MALLOC(len + 1);
499
500 // Convert wide message to multibyte one.
501 rc = WideCharToMultiByte(code_page,
502 0, // Flags.
503 wmsg, wlen, // Wide buffer and size.
504 msg, len, // Buffer and size.
505 NULL, NULL // Default char and used default char.
506 );
507 if (rc <= 0 || rc > len) {
508 goto end;
509 }
510 KMP_DEBUG_ASSERT(rc == len);
511 len = rc;
512 msg[len] = 0; // Put terminating null to the end.
513
514 // Stripping all "\r" before stripping last end-of-line simplifies the task.
515 len = ___strip_crs(msg);
516
517 // Every message in catalog is terminated with "\n". Strip it.
518 if (len >= 1 && msg[len - 1] == '\n') {
519 --len;
520 msg[len] = 0;
521 }
522
523 // Everything looks ok.
524 result = msg;
525 msg = NULL;
526
527 end:
528
529 if (msg != NULL) {
530 KMP_INTERNAL_FREE(msg);
531 }
532 if (wmsg != NULL) {
533 LocalFree(wmsg);
534 }
535
536 return result;
537
538 } // ___catgets
539
__kmp_i18n_catgets(kmp_i18n_id_t id)540 char const *__kmp_i18n_catgets(kmp_i18n_id_t id) {
541
542 int section = get_section(id);
543 int number = get_number(id);
544 char const *message = NULL;
545
546 if (1 <= section && section <= __kmp_i18n_default_table.size) {
547 if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {
548 if (status == KMP_I18N_CLOSED) {
549 __kmp_i18n_catopen();
550 }
551 if (cat != KMP_I18N_NULLCAT) {
552 if (table.size == 0) {
553 table.sect = (kmp_i18n_section_t *)KMP_INTERNAL_CALLOC(
554 (__kmp_i18n_default_table.size + 2), sizeof(kmp_i18n_section_t));
555 table.size = __kmp_i18n_default_table.size;
556 }
557 if (table.sect[section].size == 0) {
558 table.sect[section].str = (const char **)KMP_INTERNAL_CALLOC(
559 __kmp_i18n_default_table.sect[section].size + 2,
560 sizeof(char const *));
561 table.sect[section].size =
562 __kmp_i18n_default_table.sect[section].size;
563 }
564 if (table.sect[section].str[number] == NULL) {
565 table.sect[section].str[number] = ___catgets(id);
566 }
567 message = table.sect[section].str[number];
568 }
569 if (message == NULL) {
570 // Catalog is not opened or message is not found, return default
571 // message.
572 message = __kmp_i18n_default_table.sect[section].str[number];
573 }
574 }
575 }
576 if (message == NULL) {
577 message = no_message_available;
578 }
579 return message;
580
581 } // func __kmp_i18n_catgets
582
583 #endif // KMP_OS_WINDOWS
584
585 // -----------------------------------------------------------------------------
586
587 #ifndef KMP_I18N_OK
588 #error I18n support is not implemented for this OS.
589 #endif // KMP_I18N_OK
590
591 // -----------------------------------------------------------------------------
592
__kmp_i18n_dump_catalog(kmp_str_buf_t * buffer)593 void __kmp_i18n_dump_catalog(kmp_str_buf_t *buffer) {
594
595 struct kmp_i18n_id_range_t {
596 kmp_i18n_id_t first;
597 kmp_i18n_id_t last;
598 }; // struct kmp_i18n_id_range_t
599
600 static struct kmp_i18n_id_range_t ranges[] = {
601 {kmp_i18n_prp_first, kmp_i18n_prp_last},
602 {kmp_i18n_str_first, kmp_i18n_str_last},
603 {kmp_i18n_fmt_first, kmp_i18n_fmt_last},
604 {kmp_i18n_msg_first, kmp_i18n_msg_last},
605 {kmp_i18n_hnt_first, kmp_i18n_hnt_last}}; // ranges
606
607 int num_of_ranges = sizeof(ranges) / sizeof(struct kmp_i18n_id_range_t);
608 int range;
609 kmp_i18n_id_t id;
610
611 for (range = 0; range < num_of_ranges; ++range) {
612 __kmp_str_buf_print(buffer, "*** Set #%d ***\n", range + 1);
613 for (id = (kmp_i18n_id_t)(ranges[range].first + 1); id < ranges[range].last;
614 id = (kmp_i18n_id_t)(id + 1)) {
615 __kmp_str_buf_print(buffer, "%d: <<%s>>\n", id, __kmp_i18n_catgets(id));
616 }
617 }
618
619 __kmp_printf("%s", buffer->str);
620
621 } // __kmp_i18n_dump_catalog
622
623 // -----------------------------------------------------------------------------
__kmp_msg_format(unsigned id_arg,...)624 kmp_msg_t __kmp_msg_format(unsigned id_arg, ...) {
625
626 kmp_msg_t msg;
627 va_list args;
628 kmp_str_buf_t buffer;
629 __kmp_str_buf_init(&buffer);
630
631 va_start(args, id_arg);
632
633 // We use unsigned for the ID argument and explicitly cast it here to the
634 // right enumerator because variadic functions are not compatible with
635 // default promotions.
636 kmp_i18n_id_t id = (kmp_i18n_id_t)id_arg;
637
638 #if KMP_OS_UNIX
639 // On Linux* OS and OS X*, printf() family functions process parameter
640 // numbers, for example: "%2$s %1$s".
641 __kmp_str_buf_vprint(&buffer, __kmp_i18n_catgets(id), args);
642 #elif KMP_OS_WINDOWS
643 // On Winodws, printf() family functions does not recognize GNU style
644 // parameter numbers, so we have to use FormatMessage() instead. It recognizes
645 // parameter numbers, e. g.: "%2!s! "%1!s!".
646 {
647 LPTSTR str = NULL;
648 int len;
649 FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
650 __kmp_i18n_catgets(id), 0, 0, (LPTSTR)(&str), 0, &args);
651 len = ___strip_crs(str);
652 __kmp_str_buf_cat(&buffer, str, len);
653 LocalFree(str);
654 }
655 #else
656 #error
657 #endif
658 va_end(args);
659 __kmp_str_buf_detach(&buffer);
660
661 msg.type = (kmp_msg_type_t)(id >> 16);
662 msg.num = id & 0xFFFF;
663 msg.str = buffer.str;
664 msg.len = buffer.used;
665
666 return msg;
667
668 } // __kmp_msg_format
669
670 // -----------------------------------------------------------------------------
sys_error(int err)671 static char *sys_error(int err) {
672
673 char *message = NULL;
674
675 #if KMP_OS_WINDOWS
676
677 LPVOID buffer = NULL;
678 int len;
679 DWORD rc;
680 rc = FormatMessage(
681 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
682 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language.
683 (LPTSTR)&buffer, 0, NULL);
684 if (rc > 0) {
685 // Message formatted. Copy it (so we can free it later with normal free().
686 message = __kmp_str_format("%s", (char *)buffer);
687 len = ___strip_crs(message); // Delete carriage returns if any.
688 // Strip trailing newlines.
689 while (len > 0 && message[len - 1] == '\n') {
690 --len;
691 }
692 message[len] = 0;
693 } else {
694 // FormatMessage() failed to format system error message. GetLastError()
695 // would give us error code, which we would convert to message... this it
696 // dangerous recursion, which cannot clarify original error, so we will not
697 // even start it.
698 }
699 if (buffer != NULL) {
700 LocalFree(buffer);
701 }
702
703 #else // Non-Windows* OS: Linux* OS or OS X*
704
705 /* There are 2 incompatible versions of strerror_r:
706
707 char * strerror_r( int, char *, size_t ); // GNU version
708 int strerror_r( int, char *, size_t ); // XSI version
709 */
710
711 #if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || \
712 (defined(__BIONIC__) && defined(_GNU_SOURCE) && \
713 __ANDROID_API__ >= __ANDROID_API_M__)
714 // GNU version of strerror_r.
715
716 char buffer[2048];
717 char *const err_msg = strerror_r(err, buffer, sizeof(buffer));
718 // Do not eliminate this assignment to temporary variable, otherwise compiler
719 // would not issue warning if strerror_r() returns `int' instead of expected
720 // `char *'.
721 message = __kmp_str_format("%s", err_msg);
722
723 #else // OS X*, FreeBSD* etc.
724 // XSI version of strerror_r.
725 int size = 2048;
726 char *buffer = (char *)KMP_INTERNAL_MALLOC(size);
727 int rc;
728 if (buffer == NULL) {
729 KMP_FATAL(MemoryAllocFailed);
730 }
731 rc = strerror_r(err, buffer, size);
732 if (rc == -1) {
733 rc = errno; // XSI version sets errno.
734 }
735 while (rc == ERANGE) { // ERANGE means the buffer is too small.
736 KMP_INTERNAL_FREE(buffer);
737 size *= 2;
738 buffer = (char *)KMP_INTERNAL_MALLOC(size);
739 if (buffer == NULL) {
740 KMP_FATAL(MemoryAllocFailed);
741 }
742 rc = strerror_r(err, buffer, size);
743 if (rc == -1) {
744 rc = errno; // XSI version sets errno.
745 }
746 }
747 if (rc == 0) {
748 message = buffer;
749 } else { // Buffer is unused. Free it.
750 KMP_INTERNAL_FREE(buffer);
751 }
752
753 #endif
754
755 #endif /* KMP_OS_WINDOWS */
756
757 if (message == NULL) {
758 // TODO: I18n this message.
759 message = __kmp_str_format("%s", "(No system error message available)");
760 }
761 return message;
762 } // sys_error
763
764 // -----------------------------------------------------------------------------
__kmp_msg_error_code(int code)765 kmp_msg_t __kmp_msg_error_code(int code) {
766
767 kmp_msg_t msg;
768 msg.type = kmp_mt_syserr;
769 msg.num = code;
770 msg.str = sys_error(code);
771 msg.len = KMP_STRLEN(msg.str);
772 return msg;
773
774 } // __kmp_msg_error_code
775
776 // -----------------------------------------------------------------------------
__kmp_msg_error_mesg(char const * mesg)777 kmp_msg_t __kmp_msg_error_mesg(char const *mesg) {
778
779 kmp_msg_t msg;
780 msg.type = kmp_mt_syserr;
781 msg.num = 0;
782 msg.str = __kmp_str_format("%s", mesg);
783 msg.len = KMP_STRLEN(msg.str);
784 return msg;
785
786 } // __kmp_msg_error_mesg
787
788 // -----------------------------------------------------------------------------
__kmp_msg(kmp_msg_severity_t severity,kmp_msg_t message,va_list args)789 void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, va_list args) {
790 kmp_i18n_id_t format; // format identifier
791 kmp_msg_t fmsg; // formatted message
792 kmp_str_buf_t buffer;
793
794 if (severity != kmp_ms_fatal && __kmp_generate_warnings == kmp_warnings_off)
795 return; // no reason to form a string in order to not print it
796
797 __kmp_str_buf_init(&buffer);
798
799 // Format the primary message.
800 switch (severity) {
801 case kmp_ms_inform: {
802 format = kmp_i18n_fmt_Info;
803 } break;
804 case kmp_ms_warning: {
805 format = kmp_i18n_fmt_Warning;
806 } break;
807 case kmp_ms_fatal: {
808 format = kmp_i18n_fmt_Fatal;
809 } break;
810 default: { KMP_DEBUG_ASSERT(0); }
811 }
812 fmsg = __kmp_msg_format(format, message.num, message.str);
813 __kmp_str_free(&message.str);
814 __kmp_str_buf_cat(&buffer, fmsg.str, fmsg.len);
815 __kmp_str_free(&fmsg.str);
816
817 // Format other messages.
818 for (;;) {
819 message = va_arg(args, kmp_msg_t);
820 if (message.type == kmp_mt_dummy && message.str == NULL) {
821 break;
822 }
823 switch (message.type) {
824 case kmp_mt_hint: {
825 format = kmp_i18n_fmt_Hint;
826 // we cannot skip %1$ and only use %2$ to print the message without the
827 // number
828 fmsg = __kmp_msg_format(format, message.str);
829 } break;
830 case kmp_mt_syserr: {
831 format = kmp_i18n_fmt_SysErr;
832 fmsg = __kmp_msg_format(format, message.num, message.str);
833 } break;
834 default: { KMP_DEBUG_ASSERT(0); }
835 }
836 __kmp_str_free(&message.str);
837 __kmp_str_buf_cat(&buffer, fmsg.str, fmsg.len);
838 __kmp_str_free(&fmsg.str);
839 }
840
841 // Print formatted messages.
842 // This lock prevents multiple fatal errors on the same problem.
843 // __kmp_acquire_bootstrap_lock( & lock ); // GEH - This lock causing tests
844 // to hang on OS X*.
845 __kmp_printf("%s", buffer.str);
846 __kmp_str_buf_free(&buffer);
847
848 // __kmp_release_bootstrap_lock( & lock ); // GEH - this lock causing tests
849 // to hang on OS X*.
850
851 } // __kmp_msg
852
__kmp_msg(kmp_msg_severity_t severity,kmp_msg_t message,...)853 void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, ...) {
854 va_list args;
855 va_start(args, message);
856 __kmp_msg(severity, message, args);
857 va_end(args);
858 }
859
__kmp_fatal(kmp_msg_t message,...)860 void __kmp_fatal(kmp_msg_t message, ...) {
861 va_list args;
862 va_start(args, message);
863 __kmp_msg(kmp_ms_fatal, message, args);
864 va_end(args);
865 #if KMP_OS_WINDOWS
866 // Delay to give message a chance to appear before reaping
867 __kmp_thread_sleep(500);
868 #endif
869 __kmp_abort_process();
870 } // __kmp_fatal
871
872 // end of file //
873