Change ProgramOptions functions to classes and create a new parser from string arrays

This commit is contained in:
jfmcarreira committed 2015-03-24 17:50:23 +00:00
1 parent 53d5ae4139
commit fb36f82bc1
7 files changed
+247 -311

No files matched your search

+206 -275
View File
@@ -53,8 +53,8 @@ namespace plaYUVer
Options::Options( const std::string& name )
{
opt_name = name;
allow_unknow = false;
m_cOptionGroupName = name;
m_bAllowUnkonw = true;
}
Options::~Options()
@@ -152,6 +152,207 @@ static void setOptions( Options::OptionsList& opt_list, const string& value )
}
}
Bool Options::storePair( Bool allow_long, Bool allow_short, const string& name, const string& value )
{
bool found = false;
Options::OptionMap::iterator opt_it;
if( allow_long )
{
opt_it = opt_long_map.find( name );
if( opt_it != opt_long_map.end() )
{
found = true;
}
}
/* check for the short list */
if( allow_short && !( found && allow_long ) )
{
opt_it = opt_short_map.find( name );
if( opt_it != opt_short_map.end() )
{
found = true;
}
}
if( !found )
{
if( !m_bAllowUnkonw )
{
/* not found */
cerr << "Unknown option: `"
<< name
<< "' (value:`"
<< value
<< "')"
<< endl;
}
return false;
}
setOptions( ( *opt_it ).second, value );
return true;
}
Bool Options::storePair( const string& name, const string& value )
{
return storePair( true, true, name, value );
}
/**
* returns number of extra arguments consumed
*/
UInt Options::parseLONG( unsigned argc, const char* argv[] )
{
/* gnu style long options can take the forms:
* --option=arg
* --option arg
*/
string arg( argv[0] );
size_t arg_opt_start = arg.find_first_not_of( '-' );
size_t arg_opt_sep = arg.find_first_of( '=' );
string option = arg.substr( arg_opt_start, arg_opt_sep - arg_opt_start );
unsigned extra_argc_consumed = 0;
if( arg_opt_sep == string::npos )
{
/* no argument found => argument in argv[1] (maybe) */
/* xxx, need to handle case where option isn't required */
#if 0
/* commented out, to return to true GNU style processing
* where longopts have to include an =, otherwise they are
* booleans */
if (argc == 1)
return 0; /* run out of argv for argument */
extra_argc_consumed = 1;
#endif
if( !storePair( true, false, option, "1" ) )
{
return 0;
}
}
else
{
/* argument occurs after option_sep */
string val = arg.substr( arg_opt_sep + 1 );
storePair( true, false, option, val );
}
return extra_argc_consumed;
}
/**
* returns number of extra arguments consumed
*/
UInt Options::parseLONG( string arg )
{
/* gnu style long options can take the forms:
* --option=arg
* --option arg
*/
size_t arg_opt_start = arg.find_first_not_of( '-' );
size_t arg_opt_sep = arg.find_first_of( '=' );
string option = arg.substr( arg_opt_start, arg_opt_sep - arg_opt_start );
unsigned extra_argc_consumed = 0;
if( arg_opt_sep == string::npos )
{
/* no argument found => argument in argv[1] (maybe) */
/* xxx, need to handle case where option isn't required */
if( !storePair( true, false, option, "1" ) )
{
return 0;
}
}
else
{
/* argument occurs after option_sep */
string val = arg.substr( arg_opt_sep + 1 );
storePair( true, false, option, val );
}
return extra_argc_consumed;
}
unsigned Options::parseSHORT( unsigned argc, const char* argv[] )
{
/* short options can take the forms:
* --option arg
* -option arg
*/
string arg( argv[0] );
size_t arg_opt_start = arg.find_first_not_of( '-' );
string option = arg.substr( arg_opt_start );
/* lookup option */
/* argument in argv[1] */
/* xxx, need to handle case where option isn't required */
if( argc == 1 )
{
cerr << "Not processing option without argument `"
<< option
<< "'"
<< endl;
return 0; /* run out of argv for argument */
}
storePair( false, true, option, string( argv[1] ) );
return 1;
}
list<const char*> Options::scanArgv( unsigned argc, const char* argv[] )
{
/* a list for anything that didn't get handled as an option */
list<const char*> non_option_arguments;
for( unsigned i = 1; i < argc; i++ )
{
if( argv[i][0] != '-' )
{
non_option_arguments.push_back( argv[i] );
continue;
}
if( argv[i][1] == 0 )
{
/* a lone single dash is an argument (usually signifying stdin) */
non_option_arguments.push_back( argv[i] );
continue;
}
if( argv[i][1] != '-' )
{
/* handle short (single dash) options */
#if 0
i += parsePOSIX(opts, argc - i, &argv[i]);
#else
i += parseSHORT( argc - i, &argv[i] );
#endif
continue;
}
if( argv[i][2] == 0 )
{
/* a lone double dash ends option processing */
while( ++i < argc )
non_option_arguments.push_back( argv[i] );
break;
}
/* handle long (double dash) options */
i += parseLONG( argc - i, &argv[i] );
}
return non_option_arguments;
}
Void Options::scanArgs( std::vector<std::string> args_array)
{
for( unsigned i = 0; i < args_array.size(); i++ )
{
i += parseLONG( args_array[0] );
}
return;
}
static const char spaces[41] = " ";
/* format help text for a single option:
@@ -187,12 +388,12 @@ static void doHelpOpt( ostream& out, const Options::Option& entry, unsigned pad_
}
/* format the help text */
void doHelp( ostream& out, Options& opts, unsigned columns )
Void Options::doHelp( ostream& out, unsigned columns )
{
const unsigned pad_short = 3;
/* first pass: work out the longest option name */
unsigned max_width = 0;
for( Options::OptionsList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++ )
for( Options::OptionsList::iterator it = opt_list.begin(); it != opt_list.end(); it++ )
{
ostringstream line( ios_base::out );
doHelpOpt( line, **it, pad_short );
@@ -207,7 +408,7 @@ void doHelp( ostream& out, Options& opts, unsigned columns )
* - if the option text is longer than opt_width, place the help
* text at opt_width on the next line.
*/
for( Options::OptionsList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++ )
for( Options::OptionsList::iterator it = opt_list.begin(); it != opt_list.end(); it++ )
{
ostringstream line( ios_base::out );
line << " ";
@@ -285,275 +486,5 @@ void doHelp( ostream& out, Options& opts, unsigned columns )
}
}
bool storePair( Options& opts, bool allow_long, bool allow_short, const string& name, const string& value )
{
bool found = false;
Options::OptionMap::iterator opt_it;
if( allow_long )
{
opt_it = opts.opt_long_map.find( name );
if( opt_it != opts.opt_long_map.end() )
{
found = true;
}
}
/* check for the short list */
if( allow_short && !( found && allow_long ) )
{
opt_it = opts.opt_short_map.find( name );
if( opt_it != opts.opt_short_map.end() )
{
found = true;
}
}
if( !found )
{
// if( !opts.allow_unknow )
// {
// /* not found */
// cerr << "Unknown option: `"
// << name
// << "' (value:`"
// << value
// << "')"
// << endl;
// }
return false;
}
setOptions( ( *opt_it ).second, value );
return true;
}
bool storePair( Options& opts, const string& name, const string& value )
{
return storePair( opts, true, true, name, value );
}
/**
* returns number of extra arguments consumed
*/
unsigned parseGNU( Options& opts, unsigned argc, const char* argv[] )
{
/* gnu style long options can take the forms:
* --option=arg
* --option arg
*/
string arg( argv[0] );
size_t arg_opt_start = arg.find_first_not_of( '-' );
size_t arg_opt_sep = arg.find_first_of( '=' );
string option = arg.substr( arg_opt_start, arg_opt_sep - arg_opt_start );
unsigned extra_argc_consumed = 0;
if( arg_opt_sep == string::npos )
{
/* no argument found => argument in argv[1] (maybe) */
/* xxx, need to handle case where option isn't required */
#if 0
/* commented out, to return to true GNU style processing
* where longopts have to include an =, otherwise they are
* booleans */
if (argc == 1)
return 0; /* run out of argv for argument */
extra_argc_consumed = 1;
#endif
if( !storePair( opts, true, false, option, "1" ) )
{
return 0;
}
}
else
{
/* argument occurs after option_sep */
string val = arg.substr( arg_opt_sep + 1 );
storePair( opts, true, false, option, val );
}
return extra_argc_consumed;
}
unsigned parseSHORT( Options& opts, unsigned argc, const char* argv[] )
{
/* short options can take the forms:
* --option arg
* -option arg
*/
string arg( argv[0] );
size_t arg_opt_start = arg.find_first_not_of( '-' );
string option = arg.substr( arg_opt_start );
/* lookup option */
/* argument in argv[1] */
/* xxx, need to handle case where option isn't required */
if( argc == 1 )
{
cerr << "Not processing option without argument `"
<< option
<< "'"
<< endl;
return 0; /* run out of argv for argument */
}
storePair( opts, false, true, option, string( argv[1] ) );
return 1;
}
list<const char*> scanArgv( Options& opts, unsigned argc, const char* argv[] )
{
/* a list for anything that didn't get handled as an option */
list<const char*> non_option_arguments;
for( unsigned i = 1; i < argc; i++ )
{
if( argv[i][0] != '-' )
{
non_option_arguments.push_back( argv[i] );
continue;
}
if( argv[i][1] == 0 )
{
/* a lone single dash is an argument (usually signifying stdin) */
non_option_arguments.push_back( argv[i] );
continue;
}
if( argv[i][1] != '-' )
{
/* handle short (single dash) options */
#if 0
i += parsePOSIX(opts, argc - i, &argv[i]);
#else
i += parseSHORT( opts, argc - i, &argv[i] );
#endif
continue;
}
if( argv[i][2] == 0 )
{
/* a lone double dash ends option processing */
while( ++i < argc )
non_option_arguments.push_back( argv[i] );
break;
}
/* handle long (double dash) options */
i += parseGNU( opts, argc - i, &argv[i] );
}
return non_option_arguments;
}
void scanLine( Options& opts, string& line )
{
/* strip any leading whitespace */
size_t start = line.find_first_not_of( " \t\n\r" );
if( start == string::npos )
{
/* blank line */
return;
}
if( line[start] == '#' )
{
/* comment line */
return;
}
/* look for first whitespace or ':' after the option end */
size_t option_end = line.find_first_of( ": \t\n\r", start );
string option = line.substr( start, option_end - start );
/* look for ':', eat up any whitespace first */
start = line.find_first_not_of( " \t\n\r", option_end );
if( start == string::npos )
{
/* error: badly formatted line */
return;
}
if( line[start] != ':' )
{
/* error: badly formatted line */
return;
}
/* look for start of value string -- eat up any leading whitespace */
start = line.find_first_not_of( " \t\n\r", ++start );
if( start == string::npos )
{
/* error: badly formatted line */
return;
}
/* extract the value part, which may contain embedded spaces
* by searching for a word at a time, until we hit a comment or end of line */
size_t value_end = start;
do
{
if( line[value_end] == '#' )
{
/* rest of line is a comment */
value_end--;
break;
}
value_end = line.find_first_of( " \t\n\r", value_end );
/* consume any white space, incase there is another word.
* any trailing whitespace will be removed shortly */
value_end = line.find_first_not_of( " \t\n\r", value_end );
}
while( value_end != string::npos );
/* strip any trailing space from value*/
value_end = line.find_last_not_of( " \t\n\r", value_end );
string value;
if( value_end >= start )
{
value = line.substr( start, value_end + 1 - start );
}
else
{
/* error: no value */
return;
}
/* store the value in option */
storePair( opts, true, false, option, value );
}
void scanFile( Options& opts, istream& in )
{
do
{
string line;
getline( in, line );
scanLine( opts, line );
}
while( !!in );
}
/* for all options in opts, set their storage to their specified
* default value */
void setDefaults( Options& opts )
{
// for( Options::OptionsList::iterator it = opts.opt_list.begin(); it != opts.opt_list.end(); it++ )
// {
// ( *it )->opt->setDefault();
// }
}
void parseConfigFile( Options& opts, const string& filename )
{
ifstream cfgstream( filename.c_str(), ifstream::in );
if( !cfgstream )
{
cerr << "Failed to open config file: `"
<< filename
<< "'"
<< endl;
exit( EXIT_FAILURE );
}
scanFile( opts, cfgstream );
}
} // NAMESPACE