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