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