Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmGeneratedFileStream.h
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#pragma once
4
5
#include "cmConfigure.h" // IWYU pragma: keep
6
7
#include <string>
8
9
#include <cm/string_view>
10
11
#include "cmsys/FStream.hxx"
12
13
#include "cm_codecvt_Encoding.hxx"
14
15
// This is the first base class of cmGeneratedFileStream.  It will be
16
// created before and destroyed after the ofstream portion and can
17
// therefore be used to manage the temporary file.
18
class cmGeneratedFileStreamBase
19
{
20
protected:
21
  // This constructor does not prepare the temporary file.  The open
22
  // method must be used.
23
  cmGeneratedFileStreamBase();
24
25
  // This constructor prepares the temporary output file.
26
  cmGeneratedFileStreamBase(std::string const& name);
27
28
  // The destructor renames the temporary output file to the real name.
29
  ~cmGeneratedFileStreamBase();
30
31
  // Internal methods to handle the temporary file.  Open is always
32
  // called before the real stream is opened.  Close is always called
33
  // after the real stream is closed and Okay is set to whether the
34
  // real stream was still valid for writing when it was closed.
35
  void Open(std::string const& name);
36
  bool Close();
37
38
  // Internal file replacement implementation.
39
  int RenameFile(std::string const& oldname, std::string const& newname);
40
41
  // Internal file compression implementation.
42
  int CompressFile(std::string const& oldname, std::string const& newname);
43
44
  // The name of the final destination file for the output.
45
  std::string Name;
46
47
  // The extension of the temporary file.
48
  std::string TempExt;
49
50
  // The name of the temporary file.
51
  std::string TempName;
52
53
  // Whether to do a copy-if-different.
54
  bool CopyIfDifferent = false;
55
56
  // Whether the real file stream was valid when it was closed.
57
  bool Okay = false;
58
59
  // Whether the destination file is compressed
60
  bool Compress = false;
61
62
  // Whether the destination file is compressed
63
  bool CompressExtraExtension = true;
64
};
65
66
/** \class cmGeneratedFileStream
67
 * \brief Output stream for generated files.
68
 *
69
 * File generation should be atomic so that if CMake is killed then a
70
 * generated file is either the original version or the complete new
71
 * version.  This stream is used to make sure file generation is
72
 * atomic.  Optionally the output file is only replaced if its
73
 * contents have changed to prevent the file modification time from
74
 * being updated.
75
 */
76
class cmGeneratedFileStream
77
  : private cmGeneratedFileStreamBase
78
  , public cmsys::ofstream
79
{
80
public:
81
  using Stream = cmsys::ofstream;
82
  using Encoding = codecvt_Encoding;
83
84
  /**
85
   * This constructor prepares a default stream.  The open method must
86
   * be used before writing to the stream.
87
   */
88
  cmGeneratedFileStream(codecvt_Encoding encoding = codecvt_Encoding::None);
89
90
  /**
91
   * This constructor takes the name of the file to be generated.  It
92
   * automatically generates a name for the temporary file.  If the
93
   * file cannot be opened an error message is produced unless the
94
   * second argument is set to true.
95
   */
96
  cmGeneratedFileStream(std::string const& name, bool quiet = false,
97
                        codecvt_Encoding encoding = codecvt_Encoding::None);
98
99
  /**
100
   * The destructor checks the stream status to be sure the temporary
101
   * file was successfully written before allowing the original to be
102
   * replaced.
103
   */
104
  ~cmGeneratedFileStream() override;
105
106
  cmGeneratedFileStream(cmGeneratedFileStream const&) = delete;
107
108
  /**
109
   * Open an output file by name.  This should be used only with a
110
   * non-open stream.  It automatically generates a name for the
111
   * temporary file.  If the file cannot be opened an error message is
112
   * produced unless the second argument is set to true.
113
   */
114
  cmGeneratedFileStream& Open(std::string const& name, bool quiet = false,
115
                              bool binaryFlag = false);
116
117
  /**
118
   * Close the output file.  This should be used only with an open
119
   * stream.  The temporary file is atomically renamed to the
120
   * destination file if the stream is still valid when this method
121
   * is called.
122
   */
123
  bool Close();
124
125
  /**
126
   * Set whether copy-if-different is done.
127
   */
128
  void SetCopyIfDifferent(bool copy_if_different);
129
130
  /**
131
   * Set whether compression is done.
132
   */
133
  void SetCompression(bool compression);
134
135
  /**
136
   * Set whether compression has extra extension
137
   */
138
  void SetCompressionExtraExtension(bool ext);
139
140
  /**
141
   * Set name of the file that will hold the actual output. This method allows
142
   * the output file to be changed during the use of cmGeneratedFileStream.
143
   */
144
  void SetName(std::string const& fname);
145
146
  /**
147
   * Set set a custom temporary file extension used with 'Open'.
148
   * This does not work if the file was opened by the constructor.
149
   */
150
  void SetTempExt(std::string const& ext);
151
152
  /**
153
   * Get the name of the temporary file.
154
   */
155
0
  std::string const& GetTempName() const { return this->TempName; }
156
157
  /**
158
   * Write a specific string using an alternate encoding.
159
   * Afterward, the original encoding is restored.
160
   */
161
  void WriteAltEncoding(std::string const& data, codecvt_Encoding encoding);
162
163
  /**
164
   * Atomically replace the named file with the given content in binary
165
   * mode, unless the file already has exactly this content.  Unlike
166
   * copy-if-different, this compares the content with the file directly
167
   * instead of writing a temporary file and reading it back, which is
168
   * expensive with real-time virus scanners.  Return false if the file
169
   * had to be written but could not be.  If written is given, it is set
170
   * to whether the file was written.
171
   */
172
  static bool WriteIfDifferent(std::string const& name,
173
                               cm::string_view content, bool quiet = false,
174
                               bool* written = nullptr);
175
};