Skip to content

Commit ab380c2

Browse files
authored
[SystemZ][z/OS] Complete EBCDIC I/O support (#75212)
This patch completes the support for EBCDIC I/O support on z/OS using the autoconversion functions.
1 parent fd8fa31 commit ab380c2

File tree

9 files changed

+170
-17
lines changed

9 files changed

+170
-17
lines changed

clang/tools/c-arcmt-test/c-arcmt-test.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
/* c-arcmt-test.c */
22

33
#include "clang-c/Index.h"
4-
#include <stdlib.h>
4+
#include "llvm/Support/AutoConvert.h"
55
#include <stdio.h>
6+
#include <stdlib.h>
67
#include <string.h>
78
#if defined(_WIN32)
89
#include <io.h>
@@ -107,6 +108,14 @@ static void flush_atexit(void) {
107108
}
108109

109110
int main(int argc, const char **argv) {
111+
#ifdef __MVS__
112+
if (enableAutoConversion(fileno(stdout)) == -1)
113+
fprintf(stderr, "Setting conversion on stdout failed\n");
114+
115+
if (enableAutoConversion(fileno(stderr)) == -1)
116+
fprintf(stderr, "Setting conversion on stderr failed\n");
117+
#endif
118+
110119
thread_info client_data;
111120

112121
atexit(flush_atexit);

clang/tools/c-index-test/c-index-test.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "clang-c/Documentation.h"
99
#include "clang-c/Index.h"
1010
#include "clang/Config/config.h"
11+
#include "llvm/Support/AutoConvert.h"
1112
#include <assert.h>
1213
#include <ctype.h>
1314
#include <stdio.h>
@@ -5150,6 +5151,14 @@ static void flush_atexit(void) {
51505151
int main(int argc, const char **argv) {
51515152
thread_info client_data;
51525153

5154+
#ifdef __MVS__
5155+
if (enableAutoConversion(fileno(stdout)) == -1)
5156+
fprintf(stderr, "Setting conversion on stdout failed\n");
5157+
5158+
if (enableAutoConversion(fileno(stderr)) == -1)
5159+
fprintf(stderr, "Setting conversion on stderr failed\n");
5160+
#endif
5161+
51535162
atexit(flush_atexit);
51545163

51555164
#ifdef CLANG_HAVE_LIBXML

llvm/include/llvm/Support/AutoConvert.h

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,27 @@
1515
#define LLVM_SUPPORT_AUTOCONVERT_H
1616

1717
#ifdef __MVS__
18-
#define CCSID_IBM_1047 1047
19-
#define CCSID_UTF_8 1208
18+
#include <_Ccsid.h>
19+
#ifdef __cplusplus
2020
#include <system_error>
21+
#endif // __cplusplus
2122

23+
#define CCSID_IBM_1047 1047
24+
#define CCSID_UTF_8 1208
25+
#define CCSID_ISO8859_1 819
26+
27+
#ifdef __cplusplus
28+
extern "C" {
29+
#endif // __cplusplus
30+
int enableAutoConversion(int FD);
31+
int disableAutoConversion(int FD);
32+
int restoreStdHandleAutoConversion(int FD);
33+
int overrideAutoConversion(int FD, char *Filetag);
34+
#ifdef __cplusplus
35+
}
36+
#endif // __cplusplus
37+
38+
#ifdef __cplusplus
2239
namespace llvm {
2340

2441
/// \brief Disable the z/OS enhanced ASCII auto-conversion for the file
@@ -30,10 +47,14 @@ std::error_code disableAutoConversion(int FD);
3047
/// codepage.
3148
std::error_code enableAutoConversion(int FD);
3249

50+
/// Restore the z/OS enhanced ASCII auto-conversion for the std handle.
51+
std::error_code restoreStdHandleAutoConversion(int FD);
52+
3353
/// \brief Set the tag information for a file descriptor.
3454
std::error_code setFileTag(int FD, int CCSID, bool Text);
3555

3656
} // namespace llvm
57+
#endif // __cplusplus
3758

3859
#endif // __MVS__
3960

llvm/lib/Support/AutoConvert.cpp

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,39 +14,90 @@
1414
#ifdef __MVS__
1515

1616
#include "llvm/Support/AutoConvert.h"
17+
#include <cassert>
1718
#include <fcntl.h>
1819
#include <sys/stat.h>
20+
#include <unistd.h>
1921

20-
std::error_code llvm::disableAutoConversion(int FD) {
22+
static int savedStdHandleAutoConversionMode[3] = {-1, -1, -1};
23+
24+
int disableAutoConversion(int FD) {
2125
static const struct f_cnvrt Convert = {
22-
SETCVTOFF, // cvtcmd
23-
0, // pccsid
24-
(short)FT_BINARY, // fccsid
26+
SETCVTOFF, // cvtcmd
27+
0, // pccsid
28+
0, // fccsid
2529
};
26-
if (fcntl(FD, F_CONTROL_CVT, &Convert) == -1)
27-
return std::error_code(errno, std::generic_category());
28-
return std::error_code();
30+
31+
return fcntl(FD, F_CONTROL_CVT, &Convert);
2932
}
3033

31-
std::error_code llvm::enableAutoConversion(int FD) {
34+
int restoreStdHandleAutoConversion(int FD) {
35+
assert(FD == STDIN_FILENO || FD == STDOUT_FILENO || FD == STDERR_FILENO);
36+
if (savedStdHandleAutoConversionMode[FD] == -1)
37+
return 0;
38+
struct f_cnvrt Cvt = {
39+
savedStdHandleAutoConversionMode[FD], // cvtcmd
40+
0, // pccsid
41+
0, // fccsid
42+
};
43+
return (fcntl(FD, F_CONTROL_CVT, &Cvt));
44+
}
45+
46+
int enableAutoConversion(int FD) {
3247
struct f_cnvrt Query = {
3348
QUERYCVT, // cvtcmd
3449
0, // pccsid
3550
0, // fccsid
3651
};
3752

3853
if (fcntl(FD, F_CONTROL_CVT, &Query) == -1)
39-
return std::error_code(errno, std::generic_category());
54+
return -1;
55+
56+
// We don't need conversion for UTF-8 tagged files.
57+
// TODO: Remove the assumption of ISO8859-1 = UTF-8 here when we fully resolve
58+
// problems related to UTF-8 tagged source files.
59+
// When the pccsid is not ISO8859-1, autoconversion is still needed.
60+
if (Query.pccsid == CCSID_ISO8859_1 &&
61+
(Query.fccsid == CCSID_UTF_8 || Query.fccsid == CCSID_ISO8859_1))
62+
return 0;
63+
64+
// Save the state of std handles before we make changes to it.
65+
if ((FD == STDIN_FILENO || FD == STDOUT_FILENO || FD == STDERR_FILENO) &&
66+
savedStdHandleAutoConversionMode[FD] == -1)
67+
savedStdHandleAutoConversionMode[FD] = Query.cvtcmd;
68+
69+
if (FD == STDOUT_FILENO || FD == STDERR_FILENO)
70+
Query.cvtcmd = SETCVTON;
71+
else
72+
Query.cvtcmd = SETCVTALL;
4073

41-
Query.cvtcmd = SETCVTALL;
4274
Query.pccsid =
4375
(FD == STDIN_FILENO || FD == STDOUT_FILENO || FD == STDERR_FILENO)
4476
? 0
4577
: CCSID_UTF_8;
4678
// Assume untagged files to be IBM-1047 encoded.
4779
Query.fccsid = (Query.fccsid == FT_UNTAGGED) ? CCSID_IBM_1047 : Query.fccsid;
48-
if (fcntl(FD, F_CONTROL_CVT, &Query) == -1)
80+
return fcntl(FD, F_CONTROL_CVT, &Query);
81+
}
82+
83+
std::error_code llvm::disableAutoConversion(int FD) {
84+
if (::disableAutoConversion(FD) == -1)
85+
return std::error_code(errno, std::generic_category());
86+
87+
return std::error_code();
88+
}
89+
90+
std::error_code llvm::enableAutoConversion(int FD) {
91+
if (::enableAutoConversion(FD) == -1)
4992
return std::error_code(errno, std::generic_category());
93+
94+
return std::error_code();
95+
}
96+
97+
std::error_code llvm::restoreStdHandleAutoConversion(int FD) {
98+
if (::restoreStdHandleAutoConversion(FD) == -1)
99+
return std::error_code(errno, std::generic_category());
100+
50101
return std::error_code();
51102
}
52103

llvm/lib/Support/InitLLVM.cpp

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,40 @@
88

99
#include "llvm/Support/InitLLVM.h"
1010
#include "llvm/ADT/StringRef.h"
11+
#include "llvm/Support/AutoConvert.h"
12+
#include "llvm/Support/Error.h"
1113
#include "llvm/Support/ErrorHandling.h"
1214
#include "llvm/Support/ManagedStatic.h"
1315
#include "llvm/Support/PrettyStackTrace.h"
1416
#include "llvm/Support/Signals.h"
1517
#include "llvm/Support/SwapByteOrder.h"
1618

1719
#ifdef _WIN32
18-
#include "llvm/Support/Error.h"
1920
#include "llvm/Support/Windows/WindowsSupport.h"
2021
#endif
2122

23+
#ifdef __MVS__
24+
#include <unistd.h>
25+
26+
void CleanupStdHandles(void *Cookie) {
27+
llvm::raw_ostream *Outs = &llvm::outs(), *Errs = &llvm::errs();
28+
Outs->flush();
29+
Errs->flush();
30+
llvm::restoreStdHandleAutoConversion(STDIN_FILENO);
31+
llvm::restoreStdHandleAutoConversion(STDOUT_FILENO);
32+
llvm::restoreStdHandleAutoConversion(STDERR_FILENO);
33+
}
34+
#endif
35+
2236
using namespace llvm;
2337
using namespace llvm::sys;
2438

2539
InitLLVM::InitLLVM(int &Argc, const char **&Argv,
2640
bool InstallPipeSignalExitHandler) {
41+
#ifdef __MVS__
42+
// Bring stdin/stdout/stderr into a known state.
43+
sys::AddSignalHandler(CleanupStdHandles, nullptr);
44+
#endif
2745
if (InstallPipeSignalExitHandler)
2846
// The pipe signal handler must be installed before any other handlers are
2947
// registered. This is because the Unix \ref RegisterHandlers function does
@@ -37,6 +55,20 @@ InitLLVM::InitLLVM(int &Argc, const char **&Argv,
3755
sys::PrintStackTraceOnErrorSignal(Argv[0]);
3856
install_out_of_memory_new_handler();
3957

58+
#ifdef __MVS__
59+
60+
// We use UTF-8 as the internal character encoding. On z/OS, all external
61+
// output is encoded in EBCDIC. In order to be able to read all
62+
// error messages, we turn conversion to EBCDIC on for stderr fd.
63+
std::string Banner = std::string(Argv[0]) + ": ";
64+
ExitOnError ExitOnErr(Banner);
65+
66+
// If turning on conversion for stderr fails then the error message
67+
// may be garbled. There is no solution to this problem.
68+
ExitOnErr(errorCodeToError(llvm::enableAutoConversion(STDERR_FILENO)));
69+
ExitOnErr(errorCodeToError(llvm::enableAutoConversion(STDOUT_FILENO)));
70+
#endif
71+
4072
#ifdef _WIN32
4173
// We use UTF-8 as the internal character encoding. On Windows,
4274
// arguments passed to main() may not be encoded in UTF-8. In order
@@ -61,4 +93,9 @@ InitLLVM::InitLLVM(int &Argc, const char **&Argv,
6193
#endif
6294
}
6395

64-
InitLLVM::~InitLLVM() { llvm_shutdown(); }
96+
InitLLVM::~InitLLVM() {
97+
#ifdef __MVS__
98+
CleanupStdHandles(nullptr);
99+
#endif
100+
llvm_shutdown();
101+
}

llvm/lib/Support/Unix/Program.inc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "Unix.h"
2121
#include "llvm/ADT/StringExtras.h"
2222
#include "llvm/Config/config.h"
23+
#include "llvm/Support/AutoConvert.h"
2324
#include "llvm/Support/Compiler.h"
2425
#include "llvm/Support/Errc.h"
2526
#include "llvm/Support/FileSystem.h"
@@ -521,8 +522,12 @@ std::error_code llvm::sys::ChangeStdoutMode(fs::OpenFlags Flags) {
521522
}
522523

523524
std::error_code llvm::sys::ChangeStdinToBinary() {
525+
#ifdef __MVS__
526+
return disableAutoConversion(STDIN_FILENO);
527+
#else
524528
// Do nothing, as Unix doesn't differentiate between text and binary.
525529
return std::error_code();
530+
#endif
526531
}
527532

528533
std::error_code llvm::sys::ChangeStdoutToBinary() {

llvm/lib/Support/raw_ostream.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "llvm/Support/raw_ostream.h"
1414
#include "llvm/ADT/StringExtras.h"
1515
#include "llvm/Config/config.h"
16+
#include "llvm/Support/AutoConvert.h"
1617
#include "llvm/Support/Compiler.h"
1718
#include "llvm/Support/Duration.h"
1819
#include "llvm/Support/ErrorHandling.h"
@@ -895,13 +896,21 @@ void raw_fd_ostream::anchor() {}
895896
raw_fd_ostream &llvm::outs() {
896897
// Set buffer settings to model stdout behavior.
897898
std::error_code EC;
899+
#ifdef __MVS__
900+
EC = enableAutoConversion(STDOUT_FILENO);
901+
assert(!EC);
902+
#endif
898903
static raw_fd_ostream S("-", EC, sys::fs::OF_None);
899904
assert(!EC);
900905
return S;
901906
}
902907

903908
raw_fd_ostream &llvm::errs() {
904909
// Set standard error to be unbuffered and tied to outs() by default.
910+
#ifdef __MVS__
911+
std::error_code EC = enableAutoConversion(STDOUT_FILENO);
912+
assert(!EC);
913+
#endif
905914
static raw_fd_ostream S(STDERR_FILENO, false, true);
906915
return S;
907916
}

llvm/utils/count/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
set(LLVM_LINK_COMPONENTS
2+
support
3+
)
4+
15
add_llvm_utility(count
26
count.c
37
)

llvm/utils/count/count.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,18 @@
66
*
77
\*===----------------------------------------------------------------------===*/
88

9-
#include <stdlib.h>
9+
#include "llvm/Support/AutoConvert.h"
1010
#include <stdio.h>
11+
#include <stdlib.h>
1112

1213
int main(int argc, char **argv) {
14+
#ifdef __MVS__
15+
if (enableAutoConversion(fileno(stdin)) == -1)
16+
fprintf(stderr, "Setting conversion on stdin failed\n");
17+
18+
if (enableAutoConversion(fileno(stderr)) == -1)
19+
fprintf(stdout, "Setting conversion on stderr failed\n");
20+
#endif
1321
size_t Count, NumLines, NumRead;
1422
char Buffer[4096], *End;
1523

0 commit comments

Comments
 (0)