*** empty log message ***

This commit is contained in:
David Rose 2001-04-12 03:52:59 +00:00
parent 9815d0fb23
commit e2393582ba
21 changed files with 587 additions and 279 deletions

View File

@ -22,7 +22,9 @@ EggConverter(const string &format_name,
bool allow_last_param,
bool allow_stdout) :
EggFilter(allow_last_param, allow_stdout),
_format_name(format_name),
_preferred_extension(preferred_extension)
_format_name(format_name)
{
// Indicate the extension name we expect the user to supply for
// output files.
_preferred_extension = preferred_extension;
}

View File

@ -25,7 +25,6 @@ public:
protected:
string _format_name;
string _preferred_extension;
};
#endif

View File

@ -42,7 +42,7 @@ EggFilter(bool allow_last_param, bool allow_stdout) :
////////////////////////////////////////////////////////////////////
bool EggFilter::
handle_args(ProgramBase::Args &args) {
if (!check_last_arg(args)) {
if (!check_last_arg(args, 0)) {
return false;
}

View File

@ -81,23 +81,8 @@ EggToSomething(const string &format_name,
////////////////////////////////////////////////////////////////////
bool EggToSomething::
handle_args(ProgramBase::Args &args) {
if (_allow_last_param && !_got_output_filename && args.size() > 1) {
_got_output_filename = true;
_output_filename = args.back();
args.pop_back();
if (!_preferred_extension.empty() &&
("." + _output_filename.get_extension()) != _preferred_extension) {
nout << "Output filename " << _output_filename
<< " does not end in " << _preferred_extension
<< ". If this is really what you intended, "
"use the -o output_file syntax.\n";
return false;
}
if (!verify_output_file_safe()) {
return false;
}
if (!check_last_arg(args, 1)) {
return false;
}
return EggConverter::handle_args(args);

View File

@ -28,9 +28,12 @@
// inappropriate when writing binary file formats).
////////////////////////////////////////////////////////////////////
EggWriter::
EggWriter(bool allow_last_param, bool allow_stdout) {
_allow_last_param = allow_last_param;
_allow_stdout = allow_stdout;
EggWriter(bool allow_last_param, bool allow_stdout) :
WithOutputFile(allow_last_param, allow_stdout, false)
{
// Indicate the extension name we expect the user to supply for
// output files.
_preferred_extension = ".egg";
clear_runlines();
if (_allow_last_param) {
@ -77,8 +80,6 @@ EggWriter(bool allow_last_param, bool allow_stdout) {
"one of 'y-up', 'z-up', 'y-up-left', or 'z-up-left'. The default is "
"y-up.");
_output_ptr = (ostream *)NULL;
_normals_mode = NM_preserve;
_normals_threshold = 0.0;
@ -178,68 +179,6 @@ as_writer() {
return this;
}
////////////////////////////////////////////////////////////////////
// Function: EggWriter::get_output
// Access: Public
// Description: Returns an output stream that corresponds to the
// user's intended egg file output--either stdout, or
// the named output file. Normally, you should not need
// to call this directly, as write_egg_file() will write
// the egg file to the resulting stream. Call this only
// if you cannot use write_egg_file() to write out the
// egg file for some reason.
////////////////////////////////////////////////////////////////////
ostream &EggWriter::
get_output() {
if (_output_ptr == (ostream *)NULL) {
if (!_got_output_filename) {
// No filename given; use standard output.
assert(_allow_stdout);
_output_ptr = &cout;
} else {
// Attempt to open the named file.
unlink(_output_filename.c_str());
_output_filename.make_dir();
_output_filename.set_text();
if (!_output_filename.open_write(_output_stream)) {
nout << "Unable to write to " << _output_filename << "\n";
exit(1);
}
nout << "Writing " << _output_filename << "\n";
_output_ptr = &_output_stream;
}
}
return *_output_ptr;
}
////////////////////////////////////////////////////////////////////
// Function: EggWriter::has_output_filename
// Access: Public
// Description: Returns true if the user specified an output
// filename, false otherwise (e.g. the output file is
// implicitly stdout).
////////////////////////////////////////////////////////////////////
bool EggWriter::
has_output_filename() const {
return _got_output_filename;
}
////////////////////////////////////////////////////////////////////
// Function: EggWriter::get_output_filename
// Access: Public
// Description: If has_output_filename() returns true, this is the
// filename that the user specified. Otherwise, it
// returns the empty string.
////////////////////////////////////////////////////////////////////
Filename EggWriter::
get_output_filename() const {
if (_got_output_filename) {
return _output_filename;
}
return Filename();
}
////////////////////////////////////////////////////////////////////
// Function: EggWriter::post_process_egg_file
// Access: Public, Virtual
@ -316,7 +255,7 @@ write_egg_file() {
////////////////////////////////////////////////////////////////////
bool EggWriter::
handle_args(ProgramBase::Args &args) {
if (!check_last_arg(args)) {
if (!check_last_arg(args, 0)) {
return false;
}
@ -330,33 +269,6 @@ handle_args(ProgramBase::Args &args) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: EggWriter::check_last_arg
// Access: Protected
// Description: Checks if the last filename on the argument list is
// an egg file (if _allow_last_param was set true), and
// removes it from the argument list if it is. Returns
// true if the arguments are good, false if something is
// invalid.
////////////////////////////////////////////////////////////////////
bool EggWriter::
check_last_arg(ProgramBase::Args &args) {
if (_allow_last_param && !_got_output_filename && !args.empty()) {
Filename filename = args.back();
if (filename.get_extension() == "egg") {
_got_output_filename = true;
_output_filename = filename;
args.pop_back();
if (!verify_output_file_safe()) {
return false;
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: EggWriter::post_command_line
// Access: Protected, Virtual
@ -585,31 +497,3 @@ dispatch_translate(const string &opt, const string &arg, void *var) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: EggWriter::verify_output_file_safe
// Access: Protected
// Description: This is called when the output file is given as the
// last parameter on the command line. Since this is a
// fairly dangerous way to specify the output file (it's
// easy to accidentally overwrite an input file this
// way), the convention is to disallow this syntax if
// the output file already exists.
//
// This function will test if the output file exists,
// and issue a warning message if it does, returning
// false. If all is well, it will return true.
////////////////////////////////////////////////////////////////////
bool EggWriter::
verify_output_file_safe() const {
nassertr(_got_output_filename, false);
if (_output_filename.exists()) {
nout << "The output filename " << _output_filename << " already exists. "
"If you wish to overwrite it, you must use the -o option to specify "
"the output filename, instead of simply specifying it as the last "
"parameter.\n";
return false;
}
return true;
}

View File

@ -10,6 +10,8 @@
#include "eggBase.h"
#include <withOutputFile.h>
#include <filename.h>
#include <luse.h>
@ -18,7 +20,7 @@
// Description : This is the base class for a program that generates
// an egg file output, but doesn't read any for input.
////////////////////////////////////////////////////////////////////
class EggWriter : virtual public EggBase {
class EggWriter : virtual public EggBase, public WithOutputFile {
public:
EggWriter(bool allow_last_param = false, bool allow_stdout = true);
@ -27,16 +29,11 @@ public:
virtual EggWriter *as_writer();
ostream &get_output();
bool has_output_filename() const;
Filename get_output_filename() const;
virtual void post_process_egg_file();
void write_egg_file();
protected:
virtual bool handle_args(Args &args);
bool check_last_arg(Args &args);
virtual bool post_command_line();
static bool dispatch_normals(ProgramBase *self, const string &opt, const string &arg, void *mode);
@ -49,14 +46,7 @@ protected:
bool ns_dispatch_rotate_axis(const string &opt, const string &arg, void *var);
static bool dispatch_translate(const string &opt, const string &arg, void *var);
bool verify_output_file_safe() const;
protected:
bool _allow_last_param;
bool _allow_stdout;
bool _got_output_filename;
Filename _output_filename;
enum NormalsMode {
NM_strip,
NM_polygon,

View File

@ -61,7 +61,7 @@ EggTextureCards() : EggWriter(true, true) {
////////////////////////////////////////////////////////////////////
bool EggTextureCards::
handle_args(ProgramBase::Args &args) {
if (!check_last_arg(args)) {
if (!check_last_arg(args, 0)) {
return false;
}

View File

@ -54,17 +54,3 @@
fltVertex.h fltVertexList.h
#end ss_lib_target
#begin test_bin_target
#define TARGET test_flt
#define LOCAL_LIBS \
flt
#define OTHER_LIBS \
express:c pandaexpress:m \
dtoolutil:c dconfig:c dtoolconfig:m dtool:m pystub
#define SOURCES \
test_flt.cxx
#end test_bin_target

View File

@ -231,11 +231,14 @@ build_record(FltRecordWriter &writer) const {
return false;
}
datagram.add_be_int16(_texture_mapping_index);
datagram.pad_bytes(2);
datagram.add_be_uint32(_color_index);
datagram.add_be_uint32(_alt_color_index);
datagram.pad_bytes(2 + 2);
if (_header->get_flt_version() >= 15.2) {
// New with 15.2
datagram.add_be_int16(_texture_mapping_index);
datagram.pad_bytes(2);
datagram.add_be_uint32(_color_index);
datagram.add_be_uint32(_alt_color_index);
datagram.pad_bytes(2 + 2);
}
return true;
}

View File

@ -10,6 +10,7 @@
#include "config_flt.h"
#include <assert.h>
#include <math.h>
TypeHandle FltHeader::_type_handle;
@ -55,6 +56,8 @@ FltHeader() : FltBeadID(this) {
_next_light_id = 1;
_next_road_id = 1;
_next_cat_id = 1;
// New with 15.2
_earth_model = EM_wgs84;
// New with 15.6
@ -228,6 +231,21 @@ get_flt_version() const {
}
}
////////////////////////////////////////////////////////////////////
// Function: FltHeader::set_flt_version
// Access: Public
// Description: Changes the version number of the flt file that will
// be reported in the header.
////////////////////////////////////////////////////////////////////
void FltHeader::
set_flt_version(double version) {
if (version < 14.2) {
_format_revision_level = (int)floor(version + 0.5);
} else {
_format_revision_level = (int)floor(version * 100.0 + 0.5);
}
}
////////////////////////////////////////////////////////////////////
// Function: FltHeader::min_flt_version
// Access: Public, Static
@ -1289,24 +1307,28 @@ build_record(FltRecordWriter &writer) const {
datagram.pad_bytes(2);
datagram.add_be_int16(_next_road_id);
datagram.add_be_int16(_next_cat_id);
datagram.pad_bytes(2 + 2 + 2 + 2);
datagram.add_be_int32(_earth_model);
datagram.pad_bytes(4);
if (get_flt_version() >= 15.2) {
// New with 15.2
datagram.pad_bytes(2 + 2 + 2 + 2);
datagram.add_be_int32(_earth_model);
if (get_flt_version() >= 15.6) {
// New with 15.6
datagram.add_be_int16(_next_adaptive_id);
datagram.add_be_int16(_next_curve_id);
datagram.pad_bytes(4);
datagram.pad_bytes(4);
if (get_flt_version() >= 15.7) {
// New with 15.7
datagram.add_be_float64(_delta_z);
datagram.add_be_float64(_radius);
datagram.add_be_int16(_next_mesh_id);
datagram.pad_bytes(2);
if (get_flt_version() >= 15.6) {
// New with 15.6
datagram.add_be_int16(_next_adaptive_id);
datagram.add_be_int16(_next_curve_id);
datagram.pad_bytes(4);
if (get_flt_version() >= 15.7) {
// New with 15.7
datagram.add_be_float64(_delta_z);
datagram.add_be_float64(_radius);
datagram.add_be_int16(_next_mesh_id);
datagram.pad_bytes(2);
datagram.pad_bytes(4);
}
}
}
@ -1660,10 +1682,44 @@ FltError FltHeader::
write_material_palette(FltRecordWriter &writer) const {
FltError result;
Materials::const_iterator mi;
for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
FltMaterial *material = (*mi).second;
material->build_record(writer);
if (get_flt_version() >= 15.2) {
// Write a version 15 material palette.
Materials::const_iterator mi;
for (mi = _materials.begin(); mi != _materials.end(); ++mi) {
FltMaterial *material = (*mi).second;
material->build_record(writer);
result = writer.advance();
if (result != FE_ok) {
return result;
}
}
} else {
// Write a version 14 material palette.
if (_materials.empty()) {
// No palette is OK.
return FE_ok;
}
writer.set_opcode(FO_14_material_palette);
Datagram &datagram = writer.update_datagram();
PT(FltMaterial) dummy_material = new FltMaterial(_header);
Materials::const_iterator mi = _materials.lower_bound(0);
int index;
static const int expected_material_entries = 64;
for (index = 0; index < expected_material_entries; index++) {
if (mi == _materials.end() || index < (*mi).first) {
dummy_material->build_14_record(datagram);
} else {
nassertr(index == (*mi).first, FE_internal);
FltMaterial *material = (*mi).second;
material->build_14_record(datagram);
++mi;
}
}
result = writer.advance();
if (result != FE_ok) {
return result;

View File

@ -128,6 +128,7 @@ public:
public:
double get_flt_version() const;
void set_flt_version(double version);
static double min_flt_version();
static double max_flt_version();
bool check_version() const;

View File

@ -137,3 +137,34 @@ extract_14_record(int index, DatagramIterator &di) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: FltMaterial::build_14_record
// Access: Public
// Description: Fills up the current record on the FltRecordWriter
// with data for this record, formatted as a part of a
// v14 material palette. Returns true on success, false
// if there is some error.
////////////////////////////////////////////////////////////////////
bool FltMaterial::
build_14_record(Datagram &datagram) {
datagram.add_be_float32(_ambient[0]);
datagram.add_be_float32(_ambient[1]);
datagram.add_be_float32(_ambient[2]);
datagram.add_be_float32(_diffuse[0]);
datagram.add_be_float32(_diffuse[1]);
datagram.add_be_float32(_diffuse[2]);
datagram.add_be_float32(_specular[0]);
datagram.add_be_float32(_specular[1]);
datagram.add_be_float32(_specular[2]);
datagram.add_be_float32(_emissive[0]);
datagram.add_be_float32(_emissive[1]);
datagram.add_be_float32(_emissive[2]);
datagram.add_be_float32(_shininess);
datagram.add_be_float32(_alpha);
datagram.add_be_uint32(_flags);
datagram.add_fixed_string(_material_name, 12);
datagram.pad_bytes(4 * 28);
return true;
}

View File

@ -42,6 +42,7 @@ protected:
public:
bool extract_14_record(int index, DatagramIterator &di);
bool build_14_record(Datagram &datagram);
public:
virtual TypeHandle get_type() const {

View File

@ -59,21 +59,43 @@ get_opcode() const {
////////////////////////////////////////////////////////////////////
int FltVertex::
get_record_length() const {
switch (get_opcode()) {
case FO_vertex_c:
return 40;
if (_header->get_flt_version() < 15.2) {
// Version 14.2
switch (get_opcode()) {
case FO_vertex_c:
return 36;
case FO_vertex_cn:
return 48;
case FO_vertex_cnu:
return 56;
case FO_vertex_cu:
return 44;
default:
nassertr(false, 0);
}
case FO_vertex_cn:
return 56;
case FO_vertex_cnu:
return 64;
case FO_vertex_cu:
return 48;
default:
nassertr(false, 0);
} else {
// Version 15.2 and higher
switch (get_opcode()) {
case FO_vertex_c:
return 40;
case FO_vertex_cn:
return 56;
case FO_vertex_cnu:
return 64;
case FO_vertex_cu:
return 48;
default:
nassertr(false, 0);
}
}
return 0;
@ -222,12 +244,15 @@ build_record(FltRecordWriter &writer) const {
return false;
}
datagram.add_be_uint32(_color_index);
if (_header->get_flt_version() >= 15.2) {
// New with 15.2
datagram.add_be_uint32(_color_index);
if (_has_normal) {
// If we added a normal, our double-word alignment is off; now we
// have a few extra bytes to add.
datagram.pad_bytes(4);
if (_has_normal) {
// If we added a normal, our double-word alignment is off; now we
// have a few extra bytes to add.
datagram.pad_bytes(4);
}
}
nassertr((int)datagram.get_length() == get_record_length() - 4, true);

View File

@ -1,63 +0,0 @@
// Filename: test_flt.cxx
// Created by: drose (24Aug00)
//
////////////////////////////////////////////////////////////////////
#include "fltHeader.h"
#include <getopt.h>
void
usage() {
cerr << "Usage: test_flt [opts] filename.flt\n";
}
int
main(int argc, char *argv[]) {
static const char * const opts = "t:";
extern char *optarg;
extern int optind;
DSearchPath texture_path;
int flag = getopt(argc, argv, opts);
while (flag != EOF) {
switch (flag) {
case 't':
// t: Texture search path.
texture_path.append_directory(optarg);
break;
default:
usage();
exit(1);
}
flag = getopt(argc, argv, opts);
}
argc -= (optind - 1);
argv += (optind - 1);
if (argc != 2) {
usage();
exit(1);
}
Filename filename = argv[1];
PT(FltHeader) header = new FltHeader;
header->set_texture_path(texture_path);
FltError result = header->read_flt(filename);
cerr << "Read result is " << result << "\n"
<< "Version is " << header->get_flt_version() << "\n";
header->check_version();
if (result == FE_ok) {
//header->write(cerr);
result = header->write_flt("t.flt");
cerr << "Write result is " << result << "\n\n";
}
return (0);
}

View File

@ -11,3 +11,17 @@
fltCopy.cxx fltCopy.h
#end bin_target
#begin bin_target
#define TARGET flt-trans
#define LOCAL_LIBS \
progbase flt
#define OTHER_LIBS \
linmath:c panda:m \
express:c pandaexpress:m \
dtoolutil:c dconfig:c dtoolconfig:m dtool:m pystub
#define SOURCES \
fltTrans.cxx fltTrans.h
#end bin_target

View File

@ -0,0 +1,130 @@
// Filename: fltTrans.cxx
// Created by: drose (11Apr01)
//
////////////////////////////////////////////////////////////////////
#include "fltTrans.h"
#include <fltHeader.h>
////////////////////////////////////////////////////////////////////
// Function: FltTrans::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
FltTrans::
FltTrans() :
WithOutputFile(true, false, true)
{
// Indicate the extension name we expect the user to supply for
// output files.
_preferred_extension = ".flt";
set_program_description
("This program reads a MultiGen OpenFlight (.flt) file and writes an "
"essentially equivalent .flt file, to the file specified with -o (or "
"as the second parameter). Some simple operations may be performed.");
clear_runlines();
add_runline("[opts] input.flt output.flt");
add_runline("[opts] -o output.flt input.flt");
add_option
("tp", "path", 0,
"Add the indicated colon-delimited paths to the path that is searched "
"for textures referenced by the flt file. This "
"option may also be repeated to add multiple paths.",
&FltTrans::dispatch_search_path, NULL, &_texture_path);
add_option
("v", "version", 0,
"Upgrade (or downgrade) the flt file to the indicated version. This "
"may not be completely correct for all version-to-version combinations.",
&FltTrans::dispatch_double, &_got_new_version, &_new_version);
add_option
("o", "filename", 0,
"Specify the filename to which the resulting .flt file will be written. "
"If this option is omitted, the last parameter name is taken to be the "
"name of the output file.",
&FltTrans::dispatch_filename, &_got_output_filename, &_output_filename);
}
////////////////////////////////////////////////////////////////////
// Function: FltTrans::run
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void FltTrans::
run() {
if (_got_new_version) {
if (_new_version < FltHeader::min_flt_version() ||
_new_version > FltHeader::max_flt_version()) {
nout << "Cannot write flt files of version " << _new_version
<< ". This program only understands how to write flt files between version "
<< FltHeader::min_flt_version() << " and "
<< FltHeader::max_flt_version() << ".\n";
exit(1);
}
}
PT(FltHeader) header = new FltHeader;
header->set_texture_path(_texture_path);
nout << "Reading " << _input_filename << "\n";
FltError result = header->read_flt(_input_filename);
if (result != FE_ok) {
nout << "Unable to read: " << result << "\n";
exit(1);
} else {
if (header->check_version()) {
nout << "Version is " << header->get_flt_version() << "\n";
}
if (_got_new_version) {
header->set_flt_version(_new_version);
}
result = header->write_flt(get_output());
if (result != FE_ok) {
nout << "Unable to write: " << result << "\n";
} else {
nout << "Successfully written.\n";
}
}
}
////////////////////////////////////////////////////////////////////
// Function: FltTrans::handle_args
// Access: Protected, Virtual
// Description:
////////////////////////////////////////////////////////////////////
bool FltTrans::
handle_args(ProgramBase::Args &args) {
if (!check_last_arg(args, 1)) {
return false;
}
if (args.empty()) {
nout << "You must specify the .flt file to read on the command line.\n";
return false;
} else if (args.size() != 1) {
nout << "You must specify only one .flt file to read on the command line.\n";
return false;
}
_input_filename = args[0];
return true;
}
int main(int argc, char *argv[]) {
FltTrans prog;
prog.parse_command_line(argc, argv);
prog.run();
return 0;
}

View File

@ -0,0 +1,38 @@
// Filename: fltTrans.h
// Created by: drose (11Apr01)
//
////////////////////////////////////////////////////////////////////
#ifndef FLTTRANS_H
#define FLTTRANS_H
#include <pandatoolbase.h>
#include <programBase.h>
#include <withOutputFile.h>
#include <dSearchPath.h>
////////////////////////////////////////////////////////////////////
// Class : FltTrans
// Description : A program to read a flt file and write an equivalent
// flt file, possibly performing some minor operations
// along the way.
////////////////////////////////////////////////////////////////////
class FltTrans : public ProgramBase, public WithOutputFile {
public:
FltTrans();
void run();
protected:
virtual bool handle_args(Args &args);
Filename _input_filename;
DSearchPath _texture_path;
bool _got_new_version;
double _new_version;
};
#endif

View File

@ -6,12 +6,16 @@
linmath:c putil:c express:c panda:m pystub dtool
#define SOURCES \
programBase.I programBase.cxx programBase.h wordWrapStream.cxx \
programBase.I programBase.cxx programBase.h \
withOutputFile.cxx withOutputFile.h \
wordWrapStream.cxx \
wordWrapStream.h wordWrapStreamBuf.I wordWrapStreamBuf.cxx \
wordWrapStreamBuf.h
#define INSTALL_HEADERS \
programBase.I programBase.h wordWrapStream.h wordWrapStreamBuf.I \
programBase.I programBase.h \
withOutputFile.h \
wordWrapStream.h wordWrapStreamBuf.I \
wordWrapStreamBuf.h
#end ss_lib_target

View File

@ -0,0 +1,169 @@
// Filename: withOutputFile.cxx
// Created by: drose (11Apr01)
//
////////////////////////////////////////////////////////////////////
#include "withOutputFile.h"
#include <notify.h>
////////////////////////////////////////////////////////////////////
// Function: WithOutputFile::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
WithOutputFile::
WithOutputFile(bool allow_last_param, bool allow_stdout,
bool binary_output) {
_allow_last_param = allow_last_param;
_allow_stdout = allow_stdout;
_binary_output = binary_output;
_got_output_filename = false;
_output_ptr = (ostream *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: WithOutputFile::Destructor
// Access: Public, Virtual
// Description:
////////////////////////////////////////////////////////////////////
WithOutputFile::
~WithOutputFile() {
}
////////////////////////////////////////////////////////////////////
// Function: WithOutputFile::get_output
// Access: Public
// Description: Returns an output stream that corresponds to the
// user's intended egg file output--either stdout, or
// the named output file.
////////////////////////////////////////////////////////////////////
ostream &WithOutputFile::
get_output() {
if (_output_ptr == (ostream *)NULL) {
if (!_got_output_filename) {
// No filename given; use standard output.
nassertr(_allow_stdout, _output_stream);
_output_ptr = &cout;
} else {
// Attempt to open the named file.
unlink(_output_filename.c_str());
_output_filename.make_dir();
if (_binary_output) {
_output_filename.set_binary();
} else {
_output_filename.set_text();
}
if (!_output_filename.open_write(_output_stream)) {
nout << "Unable to write to " << _output_filename << "\n";
exit(1);
}
nout << "Writing " << _output_filename << "\n";
_output_ptr = &_output_stream;
}
}
return *_output_ptr;
}
////////////////////////////////////////////////////////////////////
// Function: WithOutputFile::has_output_filename
// Access: Public
// Description: Returns true if the user specified an output
// filename, false otherwise (e.g. the output file is
// implicitly stdout).
////////////////////////////////////////////////////////////////////
bool WithOutputFile::
has_output_filename() const {
return _got_output_filename;
}
////////////////////////////////////////////////////////////////////
// Function: WithOutputFile::get_output_filename
// Access: Public
// Description: If has_output_filename() returns true, this is the
// filename that the user specified. Otherwise, it
// returns the empty string.
////////////////////////////////////////////////////////////////////
Filename WithOutputFile::
get_output_filename() const {
if (_got_output_filename) {
return _output_filename;
}
return Filename();
}
////////////////////////////////////////////////////////////////////
// Function: WithOutputFile::check_last_arg
// Access: Protected
// Description: Checks if the last filename on the argument list is
// a file with the expected extension (if
// _allow_last_param was set true), and removes it from
// the argument list if it is. Returns true if the
// arguments are good, false if something is invalid.
//
// minimum_args is the number of arguments we know must
// be input parameters and therefore cannot be
// interpreted as output filenames.
////////////////////////////////////////////////////////////////////
bool WithOutputFile::
check_last_arg(ProgramBase::Args &args, int minimum_args) {
if (_allow_last_param && !_got_output_filename &&
(int)args.size() > minimum_args) {
Filename filename = args.back();
if (!_preferred_extension.empty() &&
("." + filename.get_extension()) != _preferred_extension) {
// This argument must not be an output filename.
if (!_allow_stdout) {
nout << "Output filename " << filename
<< " does not end in " << _preferred_extension
<< ". If this is really what you intended, "
"use the -o output_file syntax.\n";
return false;
}
} else {
// This argument appears to be an output filename.
_got_output_filename = true;
_output_filename = filename;
args.pop_back();
if (!verify_output_file_safe()) {
return false;
}
}
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: WithOutputFile::verify_output_file_safe
// Access: Protected
// Description: This is called when the output file is given as the
// last parameter on the command line. Since this is a
// fairly dangerous way to specify the output file (it's
// easy to accidentally overwrite an input file this
// way), the convention is to disallow this syntax if
// the output file already exists.
//
// This function will test if the output file exists,
// and issue a warning message if it does, returning
// false. If all is well, it will return true.
////////////////////////////////////////////////////////////////////
bool WithOutputFile::
verify_output_file_safe() const {
nassertr(_got_output_filename, false);
if (_output_filename.exists()) {
nout << "The output filename " << _output_filename << " already exists. "
"If you wish to overwrite it, you must use the -o option to specify "
"the output filename, instead of simply specifying it as the last "
"parameter.\n";
return false;
}
return true;
}

View File

@ -0,0 +1,53 @@
// Filename: outputFile.h
// Created by: drose (11Apr01)
//
////////////////////////////////////////////////////////////////////
#ifndef WITHOUTPUTFILE_H
#define WITHOUTPUTFILE_H
#include <pandatoolbase.h>
#include "programBase.h"
#include <filename.h>
////////////////////////////////////////////////////////////////////
// Class : WithOutputFile
// Description : This is the bare functionality (intended to be
// inherited from along with ProgramBase or some
// derivative) for a program that might generate an
// output file.
//
// This provides the has_output_filename() and
// get_output_filename() methods.
////////////////////////////////////////////////////////////////////
class WithOutputFile {
public:
WithOutputFile(bool allow_last_param, bool allow_stdout,
bool binary_output);
virtual ~WithOutputFile();
ostream &get_output();
bool has_output_filename() const;
Filename get_output_filename() const;
protected:
bool check_last_arg(ProgramBase::Args &args, int minimum_args);
bool verify_output_file_safe() const;
protected:
bool _allow_last_param;
bool _allow_stdout;
bool _binary_output;
string _preferred_extension;
bool _got_output_filename;
Filename _output_filename;
private:
ofstream _output_stream;
ostream *_output_ptr;
};
#endif