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