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::
50 get_output() {
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  */
106 close_output() {
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  */
122 has_output_filename() const {
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  */
131 get_output_filename() const {
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 }
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:414
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
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:424
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
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
Definition: filename.cxx:1899
std::string get_extension() const
Returns the file extension.
Definition: filename.I:400
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
Definition: filename.cxx:1267
Filename get_output_filename() const
If has_output_filename() returns true, this is the filename that the user specified.
void close_output()
Closes the output stream previously opened by get_output().
bool has_output_filename() const
Returns true if the user specified an output filename, false otherwise (e.g.
std::ostream & get_output()
Returns an output stream that corresponds to the user's intended egg file output–either stdout,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.