Coverage Report

Created: 2026-02-09 06:05

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