Panda3D
withOutputFile.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file withOutputFile.cxx
10  * @author drose
11  * @date 2001-04-11
12  */
13 
14 #include "withOutputFile.h"
15 #include "executionEnvironment.h"
16 #include "zStream.h"
17 
18 #include "pnotify.h"
19 
20 /**
21  *
22  */
23 WithOutputFile::
24 WithOutputFile(bool allow_last_param, bool allow_stdout,
25  bool binary_output) {
26  _allow_last_param = allow_last_param;
27  _allow_stdout = allow_stdout;
28  _binary_output = binary_output;
29  _got_output_filename = false;
30  _output_ptr = nullptr;
31  _owns_output_ptr = false;
32 }
33 
34 /**
35  *
36  */
37 WithOutputFile::
38 ~WithOutputFile() {
39  if (_owns_output_ptr) {
40  delete _output_ptr;
41  _owns_output_ptr = false;
42  }
43 }
44 
45 /**
46  * Returns an output stream that corresponds to the user's intended egg file
47  * output--either stdout, or the named output file.
48  */
49 std::ostream &WithOutputFile::
51  if (_output_ptr == nullptr) {
52  if (!_got_output_filename) {
53  // No filename given; use standard output.
54  if (!_allow_stdout) {
55  nout << "No output filename specified.\n";
56  exit(1);
57  }
58  _output_ptr = &std::cout;
59  _owns_output_ptr = false;
60 
61  } else {
62  // Attempt to open the named file.
63  unlink(_output_filename.c_str());
64  _output_filename.make_dir();
65 
66  bool pz_file = false;
67 #ifdef HAVE_ZLIB
68  if (_output_filename.get_extension() == "pz") {
69  // The filename ends in .pz, which means to automatically compress the
70  // file that we write.
71  pz_file = true;
72  }
73 #endif // HAVE_ZLIB
74 
75  if (_binary_output || pz_file) {
76  _output_filename.set_binary();
77  } else {
78  _output_filename.set_text();
79  }
80 
81  _output_stream.clear();
82  if (!_output_filename.open_write(_output_stream)) {
83  nout << "Unable to write to " << _output_filename << "\n";
84  exit(1);
85  }
86  nout << "Writing " << _output_filename << "\n";
87  _output_ptr = &_output_stream;
88  _owns_output_ptr = false;
89 
90 #ifdef HAVE_ZLIB
91  if (pz_file) {
92  _output_ptr = new OCompressStream(_output_ptr, _owns_output_ptr);
93  _owns_output_ptr = true;
94  }
95 #endif // HAVE_ZLIB
96  }
97  }
98  return *_output_ptr;
99 }
100 
101 /**
102  * Closes the output stream previously opened by get_output(). A subsequent
103  * call to get_output() will open a new stream.
104  */
105 void WithOutputFile::
107  if (_owns_output_ptr) {
108  delete _output_ptr;
109  _owns_output_ptr = false;
110  }
111  _output_ptr = nullptr;
112  _output_stream.close();
113 }
114 
115 
116 
117 /**
118  * Returns true if the user specified an output filename, false otherwise
119  * (e.g. the output file is implicitly stdout).
120  */
121 bool WithOutputFile::
123  return _got_output_filename;
124 }
125 
126 /**
127  * If has_output_filename() returns true, this is the filename that the user
128  * specified. Otherwise, it returns the empty string.
129  */
132  if (_got_output_filename) {
133  return _output_filename;
134  }
135  return Filename();
136 }
137 
138 /**
139  * Checks if the last filename on the argument list is a file with the
140  * expected extension (if _allow_last_param was set true), and removes it from
141  * the argument list if it is. Returns true if the arguments are good, false
142  * if something is invalid.
143  *
144  * minimum_args is the number of arguments we know must be input parameters
145  * and therefore cannot be interpreted as output filenames.
146  */
147 bool WithOutputFile::
148 check_last_arg(ProgramBase::Args &args, int minimum_args) {
149  if (_allow_last_param && !_got_output_filename &&
150  (int)args.size() > minimum_args) {
151  Filename filename = Filename::from_os_specific(args.back());
152 
153  if (!_preferred_extension.empty() &&
154  ("." + filename.get_extension()) != _preferred_extension) {
155  // This argument must not be an output filename.
156  if (!_allow_stdout) {
157  nout << "Output filename " << filename
158  << " does not end in " << _preferred_extension
159  << ". If this is really what you intended, "
160  "use the -o output_file syntax.\n";
161  return false;
162  }
163 
164  } else {
165  // This argument appears to be an output filename.
166  _got_output_filename = true;
167  _output_filename = filename;
168  args.pop_back();
169 
170  if (!verify_output_file_safe()) {
171  return false;
172  }
173  }
174  }
175 
176  return true;
177 }
178 
179 /**
180  * This is called when the output file is given as the last parameter on the
181  * command line. Since this is a fairly dangerous way to specify the output
182  * file (it's easy to accidentally overwrite an input file this way), the
183  * convention is to disallow this syntax if the output file already exists.
184  *
185  * This function will test if the output file exists, and issue a warning
186  * message if it does, returning false. If all is well, it will return true.
187  */
188 bool WithOutputFile::
189 verify_output_file_safe() const {
190  nassertr(_got_output_filename, false);
191 
192  if (_output_filename.exists()) {
193  nout << "The output filename " << _output_filename << " already exists. "
194  "If you wish to overwrite it, you must use the -o option to specify "
195  "the output filename, instead of simply specifying it as the last "
196  "parameter.\n";
197  return false;
198  }
199  return true;
200 }
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
Definition: filename.cxx:1899
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:414
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:424
void close_output()
Closes the output stream previously opened by get_output().
Filename get_output_filename() const
If has_output_filename() returns true, this is the filename that the user specified.
bool has_output_filename() const
Returns true if the user specified an output filename, false otherwise (e.g.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
std::string get_extension() const
Returns the file extension.
Definition: filename.I:400
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool make_dir() const
Creates all the directories in the path to the file specified in the filename, except for the basenam...
Definition: filename.cxx:2484
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & get_output()
Returns an output stream that corresponds to the user's intended egg file output–either stdout,...
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
Definition: filename.cxx:1267
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
Definition: filename.cxx:328