Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Source / cmGeneratedFileStream.cxx
blob36767eb88c04b5ffd5556e92753fed4564bd438f
1 /*=========================================================================
3 Program: CMake - Cross-Platform Makefile Generator
4 Module: $RCSfile: cmGeneratedFileStream.cxx,v $
5 Language: C++
6 Date: $Date: 2007/11/16 12:01:58 $
7 Version: $Revision: 1.19 $
9 Copyright (c) 2002 Kitware, Inc., Insight Consortium. All rights reserved.
10 See Copyright.txt or http://www.cmake.org/HTML/Copyright.html for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmGeneratedFileStream.h"
19 #include "cmSystemTools.h"
21 // Includes needed for implementation of RenameFile. This is not in
22 // system tools because it is not implemented robustly enough to move
23 // files across directories.
24 #ifdef _WIN32
25 # include <windows.h>
26 # include <sys/stat.h>
27 #endif
29 #if defined(CMAKE_BUILD_WITH_CMAKE)
30 # include <cm_zlib.h>
31 #endif
33 //----------------------------------------------------------------------------
34 cmGeneratedFileStream::cmGeneratedFileStream():
35 cmGeneratedFileStreamBase(), Stream()
39 //----------------------------------------------------------------------------
40 cmGeneratedFileStream::cmGeneratedFileStream(const char* name, bool quiet):
41 cmGeneratedFileStreamBase(name),
42 Stream(TempName.c_str())
44 // Check if the file opened.
45 if(!*this && !quiet)
47 cmSystemTools::Error("Cannot open file for write: ",
48 this->TempName.c_str());
49 cmSystemTools::ReportLastSystemError("");
53 //----------------------------------------------------------------------------
54 cmGeneratedFileStream::~cmGeneratedFileStream()
56 // This is the first destructor called. Check the status of the
57 // stream and give the information to the private base. Next the
58 // stream will be destroyed which will close the temporary file.
59 // Finally the base destructor will be called to replace the
60 // destination file.
61 this->Okay = (*this)?true:false;
64 //----------------------------------------------------------------------------
65 cmGeneratedFileStream&
66 cmGeneratedFileStream::Open(const char* name, bool quiet, bool binaryFlag)
68 // Store the file name and construct the temporary file name.
69 this->cmGeneratedFileStreamBase::Open(name);
71 // Open the temporary output file.
72 if ( binaryFlag )
74 this->Stream::open(this->TempName.c_str(),
75 std::ios::out | std::ios::binary);
77 else
79 this->Stream::open(this->TempName.c_str(), std::ios::out);
82 // Check if the file opened.
83 if(!*this && !quiet)
85 cmSystemTools::Error("Cannot open file for write: ",
86 this->TempName.c_str());
87 cmSystemTools::ReportLastSystemError("");
89 return *this;
92 //----------------------------------------------------------------------------
93 bool
94 cmGeneratedFileStream::Close()
96 // Save whether the temporary output file is valid before closing.
97 this->Okay = (*this)?true:false;
99 // Close the temporary output file.
100 this->Stream::close();
102 // Remove the temporary file (possibly by renaming to the real file).
103 return this->cmGeneratedFileStreamBase::Close();
106 //----------------------------------------------------------------------------
107 void cmGeneratedFileStream::SetCopyIfDifferent(bool copy_if_different)
109 this->CopyIfDifferent = copy_if_different;
112 //----------------------------------------------------------------------------
113 void cmGeneratedFileStream::SetCompression(bool compression)
115 this->Compress = compression;
118 //----------------------------------------------------------------------------
119 void cmGeneratedFileStream::SetCompressionExtraExtension(bool ext)
121 this->CompressExtraExtension = ext;
124 //----------------------------------------------------------------------------
125 cmGeneratedFileStreamBase::cmGeneratedFileStreamBase():
126 Name(),
127 TempName(),
128 CopyIfDifferent(false),
129 Okay(false),
130 Compress(false),
131 CompressExtraExtension(true)
135 //----------------------------------------------------------------------------
136 cmGeneratedFileStreamBase::cmGeneratedFileStreamBase(const char* name):
137 Name(),
138 TempName(),
139 CopyIfDifferent(false),
140 Okay(false),
141 Compress(false),
142 CompressExtraExtension(true)
144 this->Open(name);
147 //----------------------------------------------------------------------------
148 cmGeneratedFileStreamBase::~cmGeneratedFileStreamBase()
150 this->Close();
153 //----------------------------------------------------------------------------
154 void cmGeneratedFileStreamBase::Open(const char* name)
156 // Save the original name of the file.
157 this->Name = name;
159 // Create the name of the temporary file.
160 this->TempName = name;
161 this->TempName += ".tmp";
163 // Make sure the temporary file that will be used is not present.
164 cmSystemTools::RemoveFile(this->TempName.c_str());
166 std::string dir = cmSystemTools::GetFilenamePath(this->TempName);
167 cmSystemTools::MakeDirectory(dir.c_str());
170 //----------------------------------------------------------------------------
171 bool cmGeneratedFileStreamBase::Close()
173 bool replaced = false;
175 std::string resname = this->Name;
176 if ( this->Compress && this->CompressExtraExtension )
178 resname += ".gz";
181 // Only consider replacing the destination file if no error
182 // occurred.
183 if(!this->Name.empty() &&
184 this->Okay &&
185 (!this->CopyIfDifferent ||
186 cmSystemTools::FilesDiffer(this->TempName.c_str(), resname.c_str())))
188 // The destination is to be replaced. Rename the temporary to the
189 // destination atomically.
190 if ( this->Compress )
192 std::string gzname = this->TempName + ".temp.gz";
193 if ( this->CompressFile(this->TempName.c_str(), gzname.c_str()) )
195 this->RenameFile(gzname.c_str(), resname.c_str());
197 cmSystemTools::RemoveFile(gzname.c_str());
199 else
201 this->RenameFile(this->TempName.c_str(), resname.c_str());
204 replaced = true;
207 // Else, the destination was not replaced.
209 // Always delete the temporary file. We never want it to stay around.
210 cmSystemTools::RemoveFile(this->TempName.c_str());
212 return replaced;
215 //----------------------------------------------------------------------------
216 #ifdef CMAKE_BUILD_WITH_CMAKE
217 int cmGeneratedFileStreamBase::CompressFile(const char* oldname,
218 const char* newname)
220 gzFile gf = gzopen(newname, "w");
221 if ( !gf )
223 return 0;
225 FILE* ifs = fopen(oldname, "r");
226 if ( !ifs )
228 return 0;
230 size_t res;
231 const size_t BUFFER_SIZE = 1024;
232 char buffer[BUFFER_SIZE];
233 while ( (res = fread(buffer, 1, BUFFER_SIZE, ifs)) > 0 )
235 if ( !gzwrite(gf, buffer, static_cast<int>(res)) )
237 fclose(ifs);
238 gzclose(gf);
239 return 0;
242 fclose(ifs);
243 gzclose(gf);
244 return 1;
246 #else
247 int cmGeneratedFileStreamBase::CompressFile(const char*, const char*)
249 return 0;
251 #endif
253 //----------------------------------------------------------------------------
254 int cmGeneratedFileStreamBase::RenameFile(const char* oldname,
255 const char* newname)
257 #ifdef _WIN32
258 /* On Windows the move functions will not replace existing files.
259 Check if the destination exists. */
260 struct stat newFile;
261 if(stat(newname, &newFile) == 0)
263 /* The destination exists. We have to replace it carefully. The
264 MoveFileEx function does what we need but is not available on
265 Win9x. */
266 OSVERSIONINFO osv;
267 DWORD attrs;
269 /* Make sure the destination is not read only. */
270 attrs = GetFileAttributes(newname);
271 if(attrs & FILE_ATTRIBUTE_READONLY)
273 SetFileAttributes(newname, attrs & ~FILE_ATTRIBUTE_READONLY);
276 /* Check the windows version number. */
277 osv.dwOSVersionInfoSize = sizeof(osv);
278 GetVersionEx(&osv);
279 if(osv.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
281 /* This is Win9x. There is no MoveFileEx implementation. We
282 cannot quite rename the file atomically. Just delete the
283 destination and then move the file. */
284 DeleteFile(newname);
285 return MoveFile(oldname, newname);
287 else
289 /* This is not Win9x. Use the MoveFileEx implementation. */
290 return MoveFileEx(oldname, newname, MOVEFILE_REPLACE_EXISTING);
293 else
295 /* The destination does not exist. Just move the file. */
296 return MoveFile(oldname, newname);
298 #else
299 /* On UNIX we have an OS-provided call to do this atomically. */
300 return rename(oldname, newname) == 0;
301 #endif
304 //----------------------------------------------------------------------------
305 void cmGeneratedFileStream::SetName(const char* fname)
307 if ( !fname )
309 this->Name = "";
310 return;
312 this->Name = fname;