packaging: Initial packaging
[platform/upstream/cmake.git] / Source / cmGeneratedFileStream.cxx
1 /*============================================================================
2   CMake - Cross Platform Makefile Generator
3   Copyright 2000-2009 Kitware, Inc., Insight Software Consortium
4
5   Distributed under the OSI-approved BSD License (the "License");
6   see accompanying file Copyright.txt for details.
7
8   This software is distributed WITHOUT ANY WARRANTY; without even the
9   implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10   See the License for more information.
11 ============================================================================*/
12 #include "cmGeneratedFileStream.h"
13
14 #include "cmSystemTools.h"
15
16 #if defined(CMAKE_BUILD_WITH_CMAKE)
17 # include <cm_zlib.h>
18 #endif
19
20 //----------------------------------------------------------------------------
21 cmGeneratedFileStream::cmGeneratedFileStream():
22   cmGeneratedFileStreamBase(), Stream()
23 {
24 }
25
26 //----------------------------------------------------------------------------
27 cmGeneratedFileStream::cmGeneratedFileStream(const char* name, bool quiet):
28   cmGeneratedFileStreamBase(name),
29   Stream(TempName.c_str())
30 {
31   // Check if the file opened.
32   if(!*this && !quiet)
33     {
34     cmSystemTools::Error("Cannot open file for write: ",
35                          this->TempName.c_str());
36     cmSystemTools::ReportLastSystemError("");
37     }
38 }
39
40 //----------------------------------------------------------------------------
41 cmGeneratedFileStream::~cmGeneratedFileStream()
42 {
43   // This is the first destructor called.  Check the status of the
44   // stream and give the information to the private base.  Next the
45   // stream will be destroyed which will close the temporary file.
46   // Finally the base destructor will be called to replace the
47   // destination file.
48   this->Okay = (*this)?true:false;
49 }
50
51 //----------------------------------------------------------------------------
52 cmGeneratedFileStream&
53 cmGeneratedFileStream::Open(const char* name, bool quiet, bool binaryFlag)
54 {
55   // Store the file name and construct the temporary file name.
56   this->cmGeneratedFileStreamBase::Open(name);
57
58   // Open the temporary output file.
59   if ( binaryFlag )
60     {
61     this->Stream::open(this->TempName.c_str(),
62                        std::ios::out | std::ios::binary);
63     }
64   else
65     {
66     this->Stream::open(this->TempName.c_str(), std::ios::out);
67     }
68
69   // Check if the file opened.
70   if(!*this && !quiet)
71     {
72     cmSystemTools::Error("Cannot open file for write: ",
73                          this->TempName.c_str());
74     cmSystemTools::ReportLastSystemError("");
75     }
76   return *this;
77 }
78
79 //----------------------------------------------------------------------------
80 bool
81 cmGeneratedFileStream::Close()
82 {
83   // Save whether the temporary output file is valid before closing.
84   this->Okay = (*this)?true:false;
85
86   // Close the temporary output file.
87   this->Stream::close();
88
89   // Remove the temporary file (possibly by renaming to the real file).
90   return this->cmGeneratedFileStreamBase::Close();
91 }
92
93 //----------------------------------------------------------------------------
94 void cmGeneratedFileStream::SetCopyIfDifferent(bool copy_if_different)
95 {
96   this->CopyIfDifferent = copy_if_different;
97 }
98
99 //----------------------------------------------------------------------------
100 void cmGeneratedFileStream::SetCompression(bool compression)
101 {
102   this->Compress = compression;
103 }
104
105 //----------------------------------------------------------------------------
106 void cmGeneratedFileStream::SetCompressionExtraExtension(bool ext)
107 {
108   this->CompressExtraExtension = ext;
109 }
110
111 //----------------------------------------------------------------------------
112 cmGeneratedFileStreamBase::cmGeneratedFileStreamBase():
113   Name(),
114   TempName(),
115   CopyIfDifferent(false),
116   Okay(false),
117   Compress(false),
118   CompressExtraExtension(true)
119 {
120 }
121
122 //----------------------------------------------------------------------------
123 cmGeneratedFileStreamBase::cmGeneratedFileStreamBase(const char* name):
124   Name(),
125   TempName(),
126   CopyIfDifferent(false),
127   Okay(false),
128   Compress(false),
129   CompressExtraExtension(true)
130 {
131   this->Open(name);
132 }
133
134 //----------------------------------------------------------------------------
135 cmGeneratedFileStreamBase::~cmGeneratedFileStreamBase()
136 {
137   this->Close();
138 }
139
140 //----------------------------------------------------------------------------
141 void cmGeneratedFileStreamBase::Open(const char* name)
142 {
143   // Save the original name of the file.
144   this->Name = name;
145
146   // Create the name of the temporary file.
147   this->TempName = name;
148 #if defined(__VMS)
149   this->TempName += "_tmp";
150 #else
151   this->TempName += ".tmp";
152 #endif
153
154   // Make sure the temporary file that will be used is not present.
155   cmSystemTools::RemoveFile(this->TempName.c_str());
156
157   std::string dir = cmSystemTools::GetFilenamePath(this->TempName);
158   cmSystemTools::MakeDirectory(dir.c_str());
159 }
160
161 //----------------------------------------------------------------------------
162 bool cmGeneratedFileStreamBase::Close()
163 {
164   bool replaced = false;
165
166   std::string resname = this->Name;
167   if ( this->Compress && this->CompressExtraExtension )
168     {
169     resname += ".gz";
170     }
171
172   // Only consider replacing the destination file if no error
173   // occurred.
174   if(!this->Name.empty() &&
175     this->Okay &&
176     (!this->CopyIfDifferent ||
177      cmSystemTools::FilesDiffer(this->TempName.c_str(), resname.c_str())))
178     {
179     // The destination is to be replaced.  Rename the temporary to the
180     // destination atomically.
181     if ( this->Compress )
182       {
183       std::string gzname = this->TempName + ".temp.gz";
184       if ( this->CompressFile(this->TempName.c_str(), gzname.c_str()) )
185         {
186         this->RenameFile(gzname.c_str(), resname.c_str());
187         }
188       cmSystemTools::RemoveFile(gzname.c_str());
189       }
190     else
191       {
192       this->RenameFile(this->TempName.c_str(), resname.c_str());
193       }
194
195     replaced = true;
196     }
197
198   // Else, the destination was not replaced.
199   //
200   // Always delete the temporary file. We never want it to stay around.
201   cmSystemTools::RemoveFile(this->TempName.c_str());
202
203   return replaced;
204 }
205
206 //----------------------------------------------------------------------------
207 #ifdef CMAKE_BUILD_WITH_CMAKE
208 int cmGeneratedFileStreamBase::CompressFile(const char* oldname,
209                                             const char* newname)
210 {
211   gzFile gf = gzopen(newname, "w");
212   if ( !gf )
213     {
214     return 0;
215     }
216   FILE* ifs = fopen(oldname, "r");
217   if ( !ifs )
218     {
219     return 0;
220     }
221   size_t res;
222   const size_t BUFFER_SIZE = 1024;
223   char buffer[BUFFER_SIZE];
224   while ( (res = fread(buffer, 1, BUFFER_SIZE, ifs)) > 0 )
225     {
226     if ( !gzwrite(gf, buffer, static_cast<int>(res)) )
227       {
228       fclose(ifs);
229       gzclose(gf);
230       return 0;
231       }
232     }
233   fclose(ifs);
234   gzclose(gf);
235   return 1;
236 }
237 #else
238 int cmGeneratedFileStreamBase::CompressFile(const char*, const char*)
239 {
240   return 0;
241 }
242 #endif
243
244 //----------------------------------------------------------------------------
245 int cmGeneratedFileStreamBase::RenameFile(const char* oldname,
246                                           const char* newname)
247 {
248   return cmSystemTools::RenameFile(oldname, newname);
249 }
250
251 //----------------------------------------------------------------------------
252 void cmGeneratedFileStream::SetName(const char* fname)
253 {
254   if ( !fname )
255     {
256     this->Name = "";
257     return;
258     }
259   this->Name = fname;
260 }