summaryrefslogtreecommitdiffstats
path: root/Source/cmGeneratedFileStream.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'Source/cmGeneratedFileStream.cxx')
-rw-r--r--Source/cmGeneratedFileStream.cxx223
1 files changed, 223 insertions, 0 deletions
diff --git a/Source/cmGeneratedFileStream.cxx b/Source/cmGeneratedFileStream.cxx
new file mode 100644
index 0000000..c35a1bc
--- /dev/null
+++ b/Source/cmGeneratedFileStream.cxx
@@ -0,0 +1,223 @@
+/*============================================================================
+ CMake - Cross Platform Makefile Generator
+ Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#include "cmGeneratedFileStream.h"
+
+#include "cmSystemTools.h"
+
+#if defined(CMAKE_BUILD_WITH_CMAKE)
+#include <cm_zlib.h>
+#endif
+
+cmGeneratedFileStream::cmGeneratedFileStream()
+ : cmGeneratedFileStreamBase()
+ , Stream()
+{
+}
+
+cmGeneratedFileStream::cmGeneratedFileStream(const char* name, bool quiet)
+ : cmGeneratedFileStreamBase(name)
+ , Stream(TempName.c_str())
+{
+ // Check if the file opened.
+ if (!*this && !quiet) {
+ cmSystemTools::Error("Cannot open file for write: ",
+ this->TempName.c_str());
+ cmSystemTools::ReportLastSystemError("");
+ }
+}
+
+cmGeneratedFileStream::~cmGeneratedFileStream()
+{
+ // This is the first destructor called. Check the status of the
+ // stream and give the information to the private base. Next the
+ // stream will be destroyed which will close the temporary file.
+ // Finally the base destructor will be called to replace the
+ // destination file.
+ this->Okay = !this->fail();
+}
+
+cmGeneratedFileStream& cmGeneratedFileStream::Open(const char* name,
+ bool quiet, bool binaryFlag)
+{
+ // Store the file name and construct the temporary file name.
+ this->cmGeneratedFileStreamBase::Open(name);
+
+ // Open the temporary output file.
+ if (binaryFlag) {
+ this->Stream::open(this->TempName.c_str(),
+ std::ios::out | std::ios::binary);
+ } else {
+ this->Stream::open(this->TempName.c_str());
+ }
+
+ // Check if the file opened.
+ if (!*this && !quiet) {
+ cmSystemTools::Error("Cannot open file for write: ",
+ this->TempName.c_str());
+ cmSystemTools::ReportLastSystemError("");
+ }
+ return *this;
+}
+
+bool cmGeneratedFileStream::Close()
+{
+ // Save whether the temporary output file is valid before closing.
+ this->Okay = !this->fail();
+
+ // Close the temporary output file.
+ this->Stream::close();
+
+ // Remove the temporary file (possibly by renaming to the real file).
+ return this->cmGeneratedFileStreamBase::Close();
+}
+
+void cmGeneratedFileStream::SetCopyIfDifferent(bool copy_if_different)
+{
+ this->CopyIfDifferent = copy_if_different;
+}
+
+void cmGeneratedFileStream::SetCompression(bool compression)
+{
+ this->Compress = compression;
+}
+
+void cmGeneratedFileStream::SetCompressionExtraExtension(bool ext)
+{
+ this->CompressExtraExtension = ext;
+}
+
+cmGeneratedFileStreamBase::cmGeneratedFileStreamBase()
+ : Name()
+ , TempName()
+ , CopyIfDifferent(false)
+ , Okay(false)
+ , Compress(false)
+ , CompressExtraExtension(true)
+{
+}
+
+cmGeneratedFileStreamBase::cmGeneratedFileStreamBase(const char* name)
+ : Name()
+ , TempName()
+ , CopyIfDifferent(false)
+ , Okay(false)
+ , Compress(false)
+ , CompressExtraExtension(true)
+{
+ this->Open(name);
+}
+
+cmGeneratedFileStreamBase::~cmGeneratedFileStreamBase()
+{
+ this->Close();
+}
+
+void cmGeneratedFileStreamBase::Open(const char* name)
+{
+ // Save the original name of the file.
+ this->Name = name;
+
+ // Create the name of the temporary file.
+ this->TempName = name;
+#if defined(__VMS)
+ this->TempName += "_tmp";
+#else
+ this->TempName += ".tmp";
+#endif
+
+ // Make sure the temporary file that will be used is not present.
+ cmSystemTools::RemoveFile(this->TempName);
+
+ std::string dir = cmSystemTools::GetFilenamePath(this->TempName);
+ cmSystemTools::MakeDirectory(dir.c_str());
+}
+
+bool cmGeneratedFileStreamBase::Close()
+{
+ bool replaced = false;
+
+ std::string resname = this->Name;
+ if (this->Compress && this->CompressExtraExtension) {
+ resname += ".gz";
+ }
+
+ // Only consider replacing the destination file if no error
+ // occurred.
+ if (!this->Name.empty() && this->Okay &&
+ (!this->CopyIfDifferent ||
+ cmSystemTools::FilesDiffer(this->TempName, resname))) {
+ // The destination is to be replaced. Rename the temporary to the
+ // destination atomically.
+ if (this->Compress) {
+ std::string gzname = this->TempName + ".temp.gz";
+ if (this->CompressFile(this->TempName.c_str(), gzname.c_str())) {
+ this->RenameFile(gzname.c_str(), resname.c_str());
+ }
+ cmSystemTools::RemoveFile(gzname);
+ } else {
+ this->RenameFile(this->TempName.c_str(), resname.c_str());
+ }
+
+ replaced = true;
+ }
+
+ // Else, the destination was not replaced.
+ //
+ // Always delete the temporary file. We never want it to stay around.
+ cmSystemTools::RemoveFile(this->TempName);
+
+ return replaced;
+}
+
+#ifdef CMAKE_BUILD_WITH_CMAKE
+int cmGeneratedFileStreamBase::CompressFile(const char* oldname,
+ const char* newname)
+{
+ gzFile gf = gzopen(newname, "w");
+ if (!gf) {
+ return 0;
+ }
+ FILE* ifs = cmsys::SystemTools::Fopen(oldname, "r");
+ if (!ifs) {
+ return 0;
+ }
+ size_t res;
+ const size_t BUFFER_SIZE = 1024;
+ char buffer[BUFFER_SIZE];
+ while ((res = fread(buffer, 1, BUFFER_SIZE, ifs)) > 0) {
+ if (!gzwrite(gf, buffer, static_cast<int>(res))) {
+ fclose(ifs);
+ gzclose(gf);
+ return 0;
+ }
+ }
+ fclose(ifs);
+ gzclose(gf);
+ return 1;
+}
+#else
+int cmGeneratedFileStreamBase::CompressFile(const char*, const char*)
+{
+ return 0;
+}
+#endif
+
+int cmGeneratedFileStreamBase::RenameFile(const char* oldname,
+ const char* newname)
+{
+ return cmSystemTools::RenameFile(oldname, newname);
+}
+
+void cmGeneratedFileStream::SetName(const std::string& fname)
+{
+ this->Name = fname;
+}