kmp_i18n.cpp 28 KB

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