1 //===-- MIUtilFileStd.cpp ---------------------------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 // Third party headers
11 #include <assert.h>
12 #include <cerrno>
13 #include <stdio.h>
14 #include <string.h>
15
16 // In-house headers:
17 #include "MICmnResources.h"
18 #include "MIUtilFileStd.h"
19 #include "lldb/Host/FileSystem.h"
20
21 #include "llvm/Support/ConvertUTF.h"
22
23 //++
24 //------------------------------------------------------------------------------------
25 // Details: CMIUtilFileStd constructor.
26 // Type: Method.
27 // Args: None.
28 // Return: None.
29 // Throws: None.
30 //--
CMIUtilFileStd()31 CMIUtilFileStd::CMIUtilFileStd()
32 : m_fileNamePath(CMIUtilString()), m_pFileHandle(nullptr)
33 #if defined(_MSC_VER)
34 ,
35 m_constCharNewLine("\r\n")
36 #else
37 ,
38 m_constCharNewLine("\n")
39 #endif // #if defined( _MSC_VER )
40 ,
41 m_bFileError(false) {
42 }
43
44 //++
45 //------------------------------------------------------------------------------------
46 // Details: CMIUtilFileStd destructor.
47 // Type: Method.
48 // Args: None.
49 // Return: None.
50 // Throws: None.
51 //--
~CMIUtilFileStd()52 CMIUtilFileStd::~CMIUtilFileStd() { Close(); }
53
54 //++
55 //------------------------------------------------------------------------------------
56 // Details: Open file for writing. On the first call to this function after
57 // *this object
58 // is created the file is either created or replace, from then on open
59 // only opens
60 // an existing file.
61 // Type: Method.
62 // Args: vFileNamePath - (R) File name path.
63 // vwrbNewCreated - (W) True - file recreated, false - file appended
64 // too.
65 // Return: MIstatus::success - Functional succeeded.
66 // MIstatus::failure - Functional failed.
67 // Throws: None.
68 //--
CreateWrite(const CMIUtilString & vFileNamePath,bool & vwrbNewCreated)69 bool CMIUtilFileStd::CreateWrite(const CMIUtilString &vFileNamePath,
70 bool &vwrbNewCreated) {
71 // Reset
72 m_bFileError = false;
73 vwrbNewCreated = false;
74
75 if (vFileNamePath.empty()) {
76 m_bFileError = true;
77 SetErrorDescription(MIRSRC(IDS_UTIL_FILE_ERR_INVALID_PATHNAME));
78 return MIstatus::failure;
79 }
80
81 // File is already open so exit
82 if (m_pFileHandle != nullptr)
83 return MIstatus::success;
84
85 #if !defined(_MSC_VER)
86 // Open with 'write' and 'binary' mode
87 m_pFileHandle = ::fopen(vFileNamePath.c_str(), "wb");
88 #else
89 // Open a file with exclusive write and shared read permissions
90 std::wstring path;
91 if (llvm::ConvertUTF8toWide(vFileNamePath.c_str(), path))
92 m_pFileHandle = ::_wfsopen(path.c_str(), L"wb", _SH_DENYWR);
93 else {
94 errno = EINVAL;
95 m_pFileHandle = nullptr;
96 }
97 #endif // !defined( _MSC_VER )
98
99 if (m_pFileHandle == nullptr) {
100 m_bFileError = true;
101 SetErrorDescriptionn(MIRSRC(IDS_UTIL_FILE_ERR_OPENING_FILE),
102 strerror(errno), vFileNamePath.c_str());
103 return MIstatus::failure;
104 }
105
106 vwrbNewCreated = true;
107 m_fileNamePath = vFileNamePath;
108
109 return MIstatus::success;
110 }
111
112 //++
113 //------------------------------------------------------------------------------------
114 // Details: Write data to existing opened file.
115 // Type: Method.
116 // Args: vData - (R) Text data.
117 // Return: MIstatus::success - Functional succeeded.
118 // MIstatus::failure - Functional failed.
119 // Throws: None.
120 //--
Write(const CMIUtilString & vData)121 bool CMIUtilFileStd::Write(const CMIUtilString &vData) {
122 if (vData.size() == 0)
123 return MIstatus::success;
124
125 if (m_bFileError)
126 return MIstatus::failure;
127
128 if (m_pFileHandle == nullptr) {
129 m_bFileError = true;
130 SetErrorDescriptionn(MIRSRC(IDE_UTIL_FILE_ERR_WRITING_NOTOPEN),
131 m_fileNamePath.c_str());
132 return MIstatus::failure;
133 }
134
135 // Get the string size
136 MIuint size = vData.size();
137 if (::fwrite(vData.c_str(), 1, size, m_pFileHandle) == size) {
138 // Flush the data to the file
139 ::fflush(m_pFileHandle);
140 return MIstatus::success;
141 }
142
143 // Not all of the data has been transferred
144 m_bFileError = true;
145 SetErrorDescriptionn(MIRSRC(IDE_UTIL_FILE_ERR_WRITING_FILE),
146 m_fileNamePath.c_str());
147 return MIstatus::failure;
148 }
149
150 //++
151 //------------------------------------------------------------------------------------
152 // Details: Write data to existing opened file.
153 // Type: Method.
154 // Args: vData - (R) Text data.
155 // vCharCnt - (R) Text data length.
156 // Return: MIstatus::success - Functional succeeded.
157 // MIstatus::failure - Functional failed.
158 // Throws: None.
159 //--
Write(const char * vpData,const MIuint vCharCnt)160 bool CMIUtilFileStd::Write(const char *vpData, const MIuint vCharCnt) {
161 if (vCharCnt == 0)
162 return MIstatus::success;
163
164 if (m_bFileError)
165 return MIstatus::failure;
166
167 if (m_pFileHandle == nullptr) {
168 m_bFileError = true;
169 SetErrorDescriptionn(MIRSRC(IDE_UTIL_FILE_ERR_WRITING_NOTOPEN),
170 m_fileNamePath.c_str());
171 return MIstatus::failure;
172 }
173
174 if (::fwrite(vpData, 1, vCharCnt, m_pFileHandle) == vCharCnt) {
175 // Flush the data to the file
176 ::fflush(m_pFileHandle);
177 return MIstatus::success;
178 }
179
180 // Not all of the data has been transferred
181 m_bFileError = true;
182 SetErrorDescriptionn(MIRSRC(IDE_UTIL_FILE_ERR_WRITING_FILE),
183 m_fileNamePath.c_str());
184 return MIstatus::failure;
185 }
186
187 //++
188 //------------------------------------------------------------------------------------
189 // Details: Close existing opened file. Note Close() must must an open!
190 // Type: Method.
191 // Args: None.
192 // Return: None.
193 // Throws: None.
194 //--
Close()195 void CMIUtilFileStd::Close() {
196 if (m_pFileHandle == nullptr)
197 return;
198
199 ::fclose(m_pFileHandle);
200 m_pFileHandle = nullptr;
201 // m_bFileError = false; Do not reset as want to remain until next attempt at
202 // open or create
203 }
204
205 //++
206 //------------------------------------------------------------------------------------
207 // Details: Retrieve state of whether the file is ok.
208 // Type: Method.
209 // Args: None.
210 // Return: True - file ok.
211 // False - file has a problem.
212 // Throws: None.
213 //--
IsOk() const214 bool CMIUtilFileStd::IsOk() const { return !m_bFileError; }
215
216 //++
217 //------------------------------------------------------------------------------------
218 // Details: Status on a file existing already.
219 // Type: Method.
220 // Args: vFileNamePath.
221 // Return: True - Exists.
222 // False - Not found.
223 // Throws: None.
224 //--
IsFileExist(const CMIUtilString & vFileNamePath) const225 bool CMIUtilFileStd::IsFileExist(const CMIUtilString &vFileNamePath) const {
226 if (vFileNamePath.empty())
227 return false;
228
229 FILE *pTmp = nullptr;
230 pTmp = ::fopen(vFileNamePath.c_str(), "wb");
231 if (pTmp != nullptr) {
232 ::fclose(pTmp);
233 return true;
234 }
235
236 return false;
237 }
238
239 //++
240 //------------------------------------------------------------------------------------
241 // Details: Retrieve the file current carriage line return characters used.
242 // Type: Method.
243 // Args: None.
244 // Return: CMIUtilString & - Text.
245 // Throws: None.
246 //--
GetLineReturn() const247 const CMIUtilString &CMIUtilFileStd::GetLineReturn() const {
248 return m_constCharNewLine;
249 }
250
251 //++
252 //------------------------------------------------------------------------------------
253 // Details: Given a file name directory path, strip off the filename and return
254 // the path.
255 // It look for either backslash or forward slash.
256 // Type: Method.
257 // Args: vDirectoryPath - (R) Text directory path.
258 // Return: CMIUtilString - Directory path.
259 // Throws: None.
260 //--
261 CMIUtilString
StripOffFileName(const CMIUtilString & vDirectoryPath)262 CMIUtilFileStd::StripOffFileName(const CMIUtilString &vDirectoryPath) {
263 const size_t nPos = vDirectoryPath.rfind('\\');
264 size_t nPos2 = vDirectoryPath.rfind('/');
265 if ((nPos == std::string::npos) && (nPos2 == std::string::npos))
266 return vDirectoryPath;
267
268 if (nPos > nPos2)
269 nPos2 = nPos;
270
271 const CMIUtilString strPath(vDirectoryPath.substr(0, nPos2).c_str());
272 return strPath;
273 }
274
275 //++
276 //------------------------------------------------------------------------------------
277 // Details: Return either backslash or forward slash appropriate to the OS this
278 // application
279 // is running on.
280 // Type: Static method.
281 // Args: None.
282 // Return: char - '/' or '\' character.
283 // Throws: None.
284 //--
GetSlash()285 char CMIUtilFileStd::GetSlash() {
286 #if !defined(_MSC_VER)
287 return '/';
288 #else
289 return '\\';
290 #endif // !defined( _MSC_VER )
291 }
292