xref: /freebsd/contrib/llvm-project/llvm/lib/Support/AutoConvert.cpp (revision 770cf0a5f02dc8983a89c6568d741fbc25baa999)
1 //===- AutoConvert.cpp - Auto conversion between ASCII/EBCDIC -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file contains functions used for auto conversion between
10 // ASCII/EBCDIC codepages specific to z/OS.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifdef __MVS__
15 
16 #include "llvm/Support/AutoConvert.h"
17 #include <cassert>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 
22 using namespace llvm;
23 
24 static int savedStdHandleAutoConversionMode[3] = {-1, -1, -1};
25 
26 int disablezOSAutoConversion(int FD) {
27   static const struct f_cnvrt Convert = {
28       SETCVTOFF, // cvtcmd
29       0,         // pccsid
30       0,         // fccsid
31   };
32 
33   return fcntl(FD, F_CONTROL_CVT, &Convert);
34 }
35 
36 int restorezOSStdHandleAutoConversion(int FD) {
37   assert(FD == STDIN_FILENO || FD == STDOUT_FILENO || FD == STDERR_FILENO);
38   if (savedStdHandleAutoConversionMode[FD] == -1)
39     return 0;
40   struct f_cnvrt Cvt = {
41       savedStdHandleAutoConversionMode[FD], // cvtcmd
42       0,                                    // pccsid
43       0,                                    // fccsid
44   };
45   return (fcntl(FD, F_CONTROL_CVT, &Cvt));
46 }
47 
48 int enablezOSAutoConversion(int FD) {
49   struct f_cnvrt Query = {
50       QUERYCVT, // cvtcmd
51       0,        // pccsid
52       0,        // fccsid
53   };
54 
55   if (fcntl(FD, F_CONTROL_CVT, &Query) == -1)
56     return -1;
57 
58   // We don't need conversion for UTF-8 tagged files.
59   // TODO: Remove the assumption of ISO8859-1 = UTF-8 here when we fully resolve
60   // problems related to UTF-8 tagged source files.
61   // When the pccsid is not ISO8859-1, autoconversion is still needed.
62   if (Query.pccsid == CCSID_ISO8859_1 &&
63       (Query.fccsid == CCSID_UTF_8 || Query.fccsid == CCSID_ISO8859_1))
64     return 0;
65 
66   // Save the state of std handles before we make changes to it.
67   if ((FD == STDIN_FILENO || FD == STDOUT_FILENO || FD == STDERR_FILENO) &&
68       savedStdHandleAutoConversionMode[FD] == -1)
69     savedStdHandleAutoConversionMode[FD] = Query.cvtcmd;
70 
71   if (FD == STDOUT_FILENO || FD == STDERR_FILENO)
72     Query.cvtcmd = SETCVTON;
73   else
74     Query.cvtcmd = SETCVTALL;
75 
76   Query.pccsid =
77       (FD == STDIN_FILENO || FD == STDOUT_FILENO || FD == STDERR_FILENO)
78           ? 0
79           : CCSID_UTF_8;
80   // Assume untagged files to be IBM-1047 encoded.
81   Query.fccsid = (Query.fccsid == FT_UNTAGGED) ? CCSID_IBM_1047 : Query.fccsid;
82   return fcntl(FD, F_CONTROL_CVT, &Query);
83 }
84 
85 std::error_code llvm::setzOSFileTag(int FD, int CCSID, bool Text) {
86   assert((!Text || (CCSID != FT_UNTAGGED && CCSID != FT_BINARY)) &&
87          "FT_UNTAGGED and FT_BINARY are not allowed for text files");
88   struct file_tag Tag;
89   Tag.ft_ccsid = CCSID;
90   Tag.ft_txtflag = Text;
91   Tag.ft_deferred = 0;
92   Tag.ft_rsvflags = 0;
93 
94   if (fcntl(FD, F_SETTAG, &Tag) == -1)
95     return errnoAsErrorCode();
96   return std::error_code();
97 }
98 
99 ErrorOr<__ccsid_t> llvm::getzOSFileTag(const char *FileName, const int FD) {
100   // If we have a file descriptor, use it to find out file tagging. Otherwise we
101   // need to use stat() with the file path.
102   if (FD != -1) {
103     struct f_cnvrt Query = {
104         QUERYCVT, // cvtcmd
105         0,        // pccsid
106         0,        // fccsid
107     };
108     if (fcntl(FD, F_CONTROL_CVT, &Query) == -1)
109       return std::error_code(errno, std::generic_category());
110     return Query.fccsid;
111   }
112   struct stat Attr;
113   if (stat(FileName, &Attr) == -1)
114     return std::error_code(errno, std::generic_category());
115   return Attr.st_tag.ft_ccsid;
116 }
117 
118 ErrorOr<bool> llvm::needzOSConversion(const char *FileName, const int FD) {
119   ErrorOr<__ccsid_t> Ccsid = getzOSFileTag(FileName, FD);
120   if (std::error_code EC = Ccsid.getError())
121     return EC;
122   // We don't need conversion for UTF-8 tagged files or binary files.
123   // TODO: Remove the assumption of ISO8859-1 = UTF-8 here when we fully resolve
124   // problems related to UTF-8 tagged source files.
125   switch (*Ccsid) {
126   case CCSID_UTF_8:
127   case CCSID_ISO8859_1:
128   case FT_BINARY:
129     return false;
130   default:
131     return true;
132   }
133 }
134 
135 #endif //__MVS__
136