16 #include "kmp_debug.h"
27 #include "kmp_environment.h"
28 #include "kmp_i18n_default.inc"
33 #define get_section(id) ((id) >> 16)
34 #define get_number(id) ((id)&0xFFFF)
36 kmp_msg_t __kmp_msg_null = {kmp_mt_dummy, 0, NULL, 0};
37 static char const *no_message_available =
"(No message available)";
39 static void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message,
42 enum kmp_i18n_cat_status {
47 typedef enum kmp_i18n_cat_status kmp_i18n_cat_status_t;
48 static volatile kmp_i18n_cat_status_t status = KMP_I18N_CLOSED;
56 static void __kmp_i18n_do_catopen();
57 static kmp_bootstrap_lock_t lock = KMP_BOOTSTRAP_LOCK_INITIALIZER(lock);
62 void __kmp_i18n_catopen() {
63 if (status == KMP_I18N_CLOSED) {
64 __kmp_acquire_bootstrap_lock(&lock);
65 if (status == KMP_I18N_CLOSED) {
66 __kmp_i18n_do_catopen();
68 __kmp_release_bootstrap_lock(&lock);
78 #define KMP_I18N_NULLCAT ((nl_catd)(-1))
79 static nl_catd cat = KMP_I18N_NULLCAT;
80 static char const *name =
81 (KMP_VERSION_MAJOR == 4 ?
"libguide.cat" :
"libomp.cat");
89 void __kmp_i18n_do_catopen() {
91 char *lang = __kmp_env_get(
"LANG");
94 KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);
95 KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);
97 english = lang == NULL ||
98 strcmp(lang,
"") == 0 || strcmp(lang,
" ") == 0 ||
101 strcmp(lang,
"C") == 0 || strcmp(lang,
"POSIX") == 0;
107 __kmp_str_split(lang,
'@', &lang, &tail);
108 __kmp_str_split(lang,
'.', &lang, &tail);
109 __kmp_str_split(lang,
'_', &lang, &tail);
110 english = (strcmp(lang,
"en") == 0);
113 KMP_INTERNAL_FREE(lang);
118 status = KMP_I18N_ABSENT;
123 cat = catopen(name, 0);
125 status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);
127 if (status == KMP_I18N_ABSENT) {
128 if (__kmp_generate_warnings > kmp_warnings_low) {
131 char *nlspath = __kmp_env_get(
"NLSPATH");
132 char *lang = __kmp_env_get(
"LANG");
137 kmp_msg_t err_code = KMP_ERR(error);
138 __kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, name), err_code,
139 KMP_HNT(CheckEnvVar,
"NLSPATH", nlspath),
140 KMP_HNT(CheckEnvVar,
"LANG", lang), __kmp_msg_null);
141 if (__kmp_generate_warnings == kmp_warnings_off) {
142 __kmp_str_free(&err_code.str);
145 KMP_INFORM(WillUseDefaultMessages);
146 KMP_INTERNAL_FREE(nlspath);
147 KMP_INTERNAL_FREE(lang);
150 int section = get_section(kmp_i18n_prp_Version);
151 int number = get_number(kmp_i18n_prp_Version);
152 char const *expected = __kmp_i18n_default_table.sect[section].str[number];
154 kmp_str_buf_t version;
155 __kmp_str_buf_init(&version);
156 __kmp_str_buf_print(&version,
"%s", catgets(cat, section, number, NULL));
159 if (strcmp(version.str, expected) != 0) {
160 __kmp_i18n_catclose();
161 status = KMP_I18N_ABSENT;
162 if (__kmp_generate_warnings > kmp_warnings_low) {
165 char const *name =
"NLSPATH";
166 char const *nlspath = __kmp_env_get(name);
167 __kmp_msg(kmp_ms_warning,
168 KMP_MSG(WrongMessageCatalog, name, version.str, expected),
169 KMP_HNT(CheckEnvVar, name, nlspath), __kmp_msg_null);
170 KMP_INFORM(WillUseDefaultMessages);
171 KMP_INTERNAL_FREE(CCAST(
char *, nlspath));
174 __kmp_str_buf_free(&version);
178 void __kmp_i18n_catclose() {
179 if (status == KMP_I18N_OPENED) {
180 KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
182 cat = KMP_I18N_NULLCAT;
184 status = KMP_I18N_CLOSED;
187 char const *__kmp_i18n_catgets(kmp_i18n_id_t
id) {
189 int section = get_section(
id);
190 int number = get_number(
id);
191 char const *message = NULL;
193 if (1 <= section && section <= __kmp_i18n_default_table.size) {
194 if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {
195 if (status == KMP_I18N_CLOSED) {
196 __kmp_i18n_catopen();
198 if (status == KMP_I18N_OPENED) {
199 message = catgets(cat, section, number,
200 __kmp_i18n_default_table.sect[section].str[number]);
202 if (message == NULL) {
203 message = __kmp_i18n_default_table.sect[section].str[number];
207 if (message == NULL) {
208 message = no_message_available;
214 #endif // KMP_OS_UNIX
221 #include "kmp_environment.h"
224 #define KMP_I18N_NULLCAT NULL
225 static HMODULE cat = KMP_I18N_NULLCAT;
226 static char const *name =
227 (KMP_VERSION_MAJOR == 4 ?
"libguide40ui.dll" :
"libompui.dll");
229 static kmp_i18n_table_t table = {0, NULL};
233 static UINT
const default_code_page = CP_OEMCP;
234 static UINT code_page = default_code_page;
236 static char const *___catgets(kmp_i18n_id_t
id);
237 static UINT get_code_page();
238 static void kmp_i18n_table_free(kmp_i18n_table_t *table);
240 static UINT get_code_page() {
242 UINT cp = default_code_page;
243 char const *value = __kmp_env_get(
"KMP_CODEPAGE");
245 if (_stricmp(value,
"ANSI") == 0) {
247 }
else if (_stricmp(value,
"OEM") == 0) {
249 }
else if (_stricmp(value,
"UTF-8") == 0 || _stricmp(value,
"UTF8") == 0) {
251 }
else if (_stricmp(value,
"UTF-7") == 0 || _stricmp(value,
"UTF7") == 0) {
257 KMP_INTERNAL_FREE((
void *)value);
262 static void kmp_i18n_table_free(kmp_i18n_table_t *table) {
265 for (s = 0; s < table->size; ++s) {
266 for (m = 0; m < table->sect[s].size; ++m) {
268 KMP_INTERNAL_FREE((
void *)table->sect[s].str[m]);
269 table->sect[s].str[m] = NULL;
271 table->sect[s].size = 0;
273 KMP_INTERNAL_FREE((
void *)table->sect[s].str);
274 table->sect[s].str = NULL;
277 KMP_INTERNAL_FREE((
void *)table->sect);
281 void __kmp_i18n_do_catopen() {
283 LCID locale_id = GetThreadLocale();
284 WORD lang_id = LANGIDFROMLCID(locale_id);
285 WORD primary_lang_id = PRIMARYLANGID(lang_id);
288 KMP_DEBUG_ASSERT(status == KMP_I18N_CLOSED);
289 KMP_DEBUG_ASSERT(cat == KMP_I18N_NULLCAT);
291 __kmp_str_buf_init(&path);
295 if (primary_lang_id == LANG_ENGLISH) {
296 status = KMP_I18N_ABSENT;
308 BOOL brc = GetModuleHandleEx(
309 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
310 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
311 reinterpret_cast<LPCSTR
>(&__kmp_i18n_do_catopen), &handle);
313 status = KMP_I18N_ABSENT;
322 DWORD drc = GetModuleFileName(handle, path.str, path.size);
324 status = KMP_I18N_ABSENT;
327 if (drc < path.size) {
331 __kmp_str_buf_reserve(&path, path.size * 2);
336 __kmp_str_fname_init(&fname, path.str);
337 __kmp_str_buf_clear(&path);
338 __kmp_str_buf_print(&path,
"%s%lu/%s", fname.dir,
339 (
unsigned long)(locale_id), name);
340 __kmp_str_fname_free(&fname);
345 cat = LoadLibraryEx(path.str, NULL, LOAD_LIBRARY_AS_DATAFILE);
346 status = (cat == KMP_I18N_NULLCAT ? KMP_I18N_ABSENT : KMP_I18N_OPENED);
348 if (status == KMP_I18N_ABSENT) {
349 if (__kmp_generate_warnings > kmp_warnings_low) {
351 DWORD error = GetLastError();
365 kmp_msg_t err_code = KMP_SYSERRCODE(error);
366 __kmp_msg(kmp_ms_warning, KMP_MSG(CantOpenMessageCatalog, path.str),
367 err_code, (error == ERROR_BAD_EXE_FORMAT
368 ? KMP_HNT(BadExeFormat, path.str, KMP_ARCH_STR)
371 if (__kmp_generate_warnings == kmp_warnings_off) {
372 __kmp_str_free(&err_code.str);
374 KMP_INFORM(WillUseDefaultMessages);
378 int section = get_section(kmp_i18n_prp_Version);
379 int number = get_number(kmp_i18n_prp_Version);
380 char const *expected = __kmp_i18n_default_table.sect[section].str[number];
381 kmp_str_buf_t version;
382 __kmp_str_buf_init(&version);
383 __kmp_str_buf_print(&version,
"%s", ___catgets(kmp_i18n_prp_Version));
385 if (strcmp(version.str, expected) != 0) {
387 __kmp_i18n_catclose();
388 status = KMP_I18N_ABSENT;
389 if (__kmp_generate_warnings > kmp_warnings_low) {
391 __kmp_msg(kmp_ms_warning,
392 KMP_MSG(WrongMessageCatalog, path.str, version.str, expected),
394 KMP_INFORM(WillUseDefaultMessages);
397 __kmp_str_buf_free(&version);
399 code_page = get_code_page();
402 __kmp_str_buf_free(&path);
406 void __kmp_i18n_catclose() {
407 if (status == KMP_I18N_OPENED) {
408 KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
409 kmp_i18n_table_free(&table);
411 cat = KMP_I18N_NULLCAT;
413 code_page = default_code_page;
414 status = KMP_I18N_CLOSED;
443 static int ___strip_crs(
char *str) {
447 if (str[in] !=
'\r') {
459 static char const *___catgets(kmp_i18n_id_t
id) {
463 wchar_t *wmsg = NULL;
469 KMP_DEBUG_ASSERT(cat != KMP_I18N_NULLCAT);
471 FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
472 FORMAT_MESSAGE_FROM_HMODULE |
473 FORMAT_MESSAGE_IGNORE_INSERTS,
482 wmsg = (
wchar_t *)addr;
486 len = WideCharToMultiByte(code_page,
497 msg = (
char *)KMP_INTERNAL_MALLOC(len + 1);
500 rc = WideCharToMultiByte(code_page,
506 if (rc <= 0 || rc > len) {
509 KMP_DEBUG_ASSERT(rc == len);
514 len = ___strip_crs(msg);
517 if (len >= 1 && msg[len - 1] ==
'\n') {
529 KMP_INTERNAL_FREE(msg);
539 char const *__kmp_i18n_catgets(kmp_i18n_id_t
id) {
541 int section = get_section(
id);
542 int number = get_number(
id);
543 char const *message = NULL;
545 if (1 <= section && section <= __kmp_i18n_default_table.size) {
546 if (1 <= number && number <= __kmp_i18n_default_table.sect[section].size) {
547 if (status == KMP_I18N_CLOSED) {
548 __kmp_i18n_catopen();
550 if (cat != KMP_I18N_NULLCAT) {
551 if (table.size == 0) {
552 table.sect = (kmp_i18n_section_t *)KMP_INTERNAL_CALLOC(
553 (__kmp_i18n_default_table.size + 2),
sizeof(kmp_i18n_section_t));
554 table.size = __kmp_i18n_default_table.size;
556 if (table.sect[section].size == 0) {
557 table.sect[section].str = (
const char **)KMP_INTERNAL_CALLOC(
558 __kmp_i18n_default_table.sect[section].size + 2,
559 sizeof(
char const *));
560 table.sect[section].size =
561 __kmp_i18n_default_table.sect[section].size;
563 if (table.sect[section].str[number] == NULL) {
564 table.sect[section].str[number] = ___catgets(
id);
566 message = table.sect[section].str[number];
568 if (message == NULL) {
571 message = __kmp_i18n_default_table.sect[section].str[number];
575 if (message == NULL) {
576 message = no_message_available;
582 #endif // KMP_OS_WINDOWS
587 #error I18n support is not implemented for this OS.
588 #endif // KMP_I18N_OK
592 void __kmp_i18n_dump_catalog(kmp_str_buf_t *buffer) {
594 struct kmp_i18n_id_range_t {
599 static struct kmp_i18n_id_range_t ranges[] = {
600 {kmp_i18n_prp_first, kmp_i18n_prp_last},
601 {kmp_i18n_str_first, kmp_i18n_str_last},
602 {kmp_i18n_fmt_first, kmp_i18n_fmt_last},
603 {kmp_i18n_msg_first, kmp_i18n_msg_last},
604 {kmp_i18n_hnt_first, kmp_i18n_hnt_last}};
606 int num_of_ranges =
sizeof(ranges) /
sizeof(
struct kmp_i18n_id_range_t);
610 for (range = 0; range < num_of_ranges; ++range) {
611 __kmp_str_buf_print(buffer,
"*** Set #%d ***\n", range + 1);
612 for (
id = (kmp_i18n_id_t)(ranges[range].first + 1);
id < ranges[range].last;
613 id = (kmp_i18n_id_t)(
id + 1)) {
614 __kmp_str_buf_print(buffer,
"%d: <<%s>>\n",
id, __kmp_i18n_catgets(
id));
618 __kmp_printf(
"%s", buffer->str);
623 kmp_msg_t __kmp_msg_format(
unsigned id_arg, ...) {
627 kmp_str_buf_t buffer;
628 __kmp_str_buf_init(&buffer);
630 va_start(args, id_arg);
635 kmp_i18n_id_t
id = (kmp_i18n_id_t)id_arg;
640 __kmp_str_buf_vprint(&buffer, __kmp_i18n_catgets(
id), args);
648 FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER,
649 __kmp_i18n_catgets(
id), 0, 0, (LPTSTR)(&str), 0, &args);
650 len = ___strip_crs(str);
651 __kmp_str_buf_cat(&buffer, str, len);
658 __kmp_str_buf_detach(&buffer);
660 msg.type = (kmp_msg_type_t)(
id >> 16);
661 msg.num =
id & 0xFFFF;
662 msg.str = buffer.str;
663 msg.len = buffer.used;
670 static char *sys_error(
int err) {
672 char *message = NULL;
676 LPVOID buffer = NULL;
680 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
681 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
682 (LPTSTR)&buffer, 0, NULL);
685 message = __kmp_str_format(
"%s", (
char *)buffer);
686 len = ___strip_crs(message);
688 while (len > 0 && message[len - 1] ==
'\n') {
698 if (buffer != NULL) {
702 #else // Non-Windows* OS: Linux* OS or OS X*
710 #if (defined(__GLIBC__) && defined(_GNU_SOURCE)) || \
711 (defined(__BIONIC__) && defined(_GNU_SOURCE) && \
712 __ANDROID_API__ >= __ANDROID_API_M__)
716 char *
const err_msg = strerror_r(err, buffer,
sizeof(buffer));
720 message = __kmp_str_format(
"%s", err_msg);
722 #else // OS X*, FreeBSD* etc.
725 char *buffer = (
char *)KMP_INTERNAL_MALLOC(size);
727 if (buffer == NULL) {
728 KMP_FATAL(MemoryAllocFailed);
730 rc = strerror_r(err, buffer, size);
734 while (rc == ERANGE) {
735 KMP_INTERNAL_FREE(buffer);
737 buffer = (
char *)KMP_INTERNAL_MALLOC(size);
738 if (buffer == NULL) {
739 KMP_FATAL(MemoryAllocFailed);
741 rc = strerror_r(err, buffer, size);
749 KMP_INTERNAL_FREE(buffer);
756 if (message == NULL) {
758 message = __kmp_str_format(
"%s",
"(No system error message available)");
764 kmp_msg_t __kmp_msg_error_code(
int code) {
767 msg.type = kmp_mt_syserr;
769 msg.str = sys_error(code);
770 msg.len = KMP_STRLEN(msg.str);
776 kmp_msg_t __kmp_msg_error_mesg(
char const *mesg) {
779 msg.type = kmp_mt_syserr;
781 msg.str = __kmp_str_format(
"%s", mesg);
782 msg.len = KMP_STRLEN(msg.str);
788 void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, va_list args) {
789 kmp_i18n_id_t format;
791 kmp_str_buf_t buffer;
793 if (severity != kmp_ms_fatal && __kmp_generate_warnings == kmp_warnings_off)
796 __kmp_str_buf_init(&buffer);
800 case kmp_ms_inform: {
801 format = kmp_i18n_fmt_Info;
803 case kmp_ms_warning: {
804 format = kmp_i18n_fmt_Warning;
807 format = kmp_i18n_fmt_Fatal;
809 default: { KMP_DEBUG_ASSERT(0); }
811 fmsg = __kmp_msg_format(format, message.num, message.str);
812 __kmp_str_free(&message.str);
813 __kmp_str_buf_cat(&buffer, fmsg.str, fmsg.len);
814 __kmp_str_free(&fmsg.str);
818 message = va_arg(args, kmp_msg_t);
819 if (message.type == kmp_mt_dummy && message.str == NULL) {
822 switch (message.type) {
824 format = kmp_i18n_fmt_Hint;
827 fmsg = __kmp_msg_format(format, message.str);
829 case kmp_mt_syserr: {
830 format = kmp_i18n_fmt_SysErr;
831 fmsg = __kmp_msg_format(format, message.num, message.str);
833 default: { KMP_DEBUG_ASSERT(0); }
835 __kmp_str_free(&message.str);
836 __kmp_str_buf_cat(&buffer, fmsg.str, fmsg.len);
837 __kmp_str_free(&fmsg.str);
844 __kmp_printf(
"%s", buffer.str);
845 __kmp_str_buf_free(&buffer);
852 void __kmp_msg(kmp_msg_severity_t severity, kmp_msg_t message, ...) {
854 va_start(args, message);
855 __kmp_msg(severity, message, args);
859 void __kmp_fatal(kmp_msg_t message, ...) {
861 va_start(args, message);
862 __kmp_msg(kmp_ms_fatal, message, args);
866 __kmp_thread_sleep(500);
868 __kmp_abort_process();