1177 lines
25 KiB
C++
1177 lines
25 KiB
C++
|
/*
|
||
|
* AnyOption 1.3
|
||
|
*
|
||
|
* kishan at hackorama dot com www.hackorama.com JULY 2001
|
||
|
*
|
||
|
* + Acts as a common facade class for reading
|
||
|
* commandline options as well as options from
|
||
|
* an optionfile with delimited type value pairs
|
||
|
*
|
||
|
* + Handles the POSIX style single character options ( -w )
|
||
|
* as well as the newer GNU long options ( --width )
|
||
|
*
|
||
|
* + The option file assumes the traditional format of
|
||
|
* first character based comment lines and type value
|
||
|
* pairs with a delimiter , and flags which are not pairs
|
||
|
*
|
||
|
* # this is a coment
|
||
|
* # next line is an option value pair
|
||
|
* width : 100
|
||
|
* # next line is a flag
|
||
|
* noimages
|
||
|
*
|
||
|
* + Supports printing out Help and Usage
|
||
|
*
|
||
|
* + Why not just use getopt() ?
|
||
|
*
|
||
|
* getopt() Its a POSIX standard not part of ANSI-C.
|
||
|
* So it may not be available on platforms like Windows.
|
||
|
*
|
||
|
* + Why it is so long ?
|
||
|
*
|
||
|
* The actual code which does command line parsing
|
||
|
* and option file parsing are done in few methods.
|
||
|
* Most of the extra code are for providing a flexible
|
||
|
* common public interface to both a resourcefile and
|
||
|
* and command line supporting POSIX style and
|
||
|
* GNU long option as well as mixing of both.
|
||
|
*
|
||
|
* + Please see "anyoption.h" for public method descriptions
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/* Updated Auguest 2004
|
||
|
* Fix from Michael D Peters (mpeters at sandia.gov)
|
||
|
* to remove static local variables, allowing multiple instantiations
|
||
|
* of the reader (for using multiple configuration files). There is
|
||
|
* an error in the destructor when using multiple instances, so you
|
||
|
* cannot delete your objects (it will crash), but not calling the
|
||
|
* destructor only introduces a small memory leak, so I
|
||
|
* have not bothered tracking it down.
|
||
|
*
|
||
|
* Also updated to use modern C++ style headers, rather than
|
||
|
* depricated iostream.h (it was causing my compiler problems)
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Updated September 2006
|
||
|
* Fix from Boyan Asenov for a bug in mixing up option indexes
|
||
|
* leading to exception when mixing different options types
|
||
|
*/
|
||
|
|
||
|
#include "anyoption.h"
|
||
|
|
||
|
#include <string.h>
|
||
|
|
||
|
AnyOption::AnyOption()
|
||
|
{
|
||
|
init();
|
||
|
}
|
||
|
|
||
|
AnyOption::AnyOption(int maxopt)
|
||
|
{
|
||
|
init( maxopt , maxopt );
|
||
|
}
|
||
|
|
||
|
AnyOption::AnyOption(int maxopt, int maxcharopt)
|
||
|
{
|
||
|
init( maxopt , maxcharopt );
|
||
|
}
|
||
|
|
||
|
AnyOption::~AnyOption()
|
||
|
{
|
||
|
if( mem_allocated )
|
||
|
cleanup();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::init()
|
||
|
{
|
||
|
init( DEFAULT_MAXOPTS , DEFAULT_MAXOPTS );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::init(int maxopt, int maxcharopt )
|
||
|
{
|
||
|
|
||
|
max_options = maxopt;
|
||
|
max_char_options = maxcharopt;
|
||
|
max_usage_lines = DEFAULT_MAXUSAGE;
|
||
|
usage_lines = 0 ;
|
||
|
argc = 0;
|
||
|
argv = NULL;
|
||
|
posix_style = true;
|
||
|
verbose = false;
|
||
|
filename = NULL;
|
||
|
appname = NULL;
|
||
|
option_counter = 0;
|
||
|
optchar_counter = 0;
|
||
|
new_argv = NULL;
|
||
|
new_argc = 0 ;
|
||
|
max_legal_args = 0 ;
|
||
|
command_set = false;
|
||
|
file_set = false;
|
||
|
values = NULL;
|
||
|
g_value_counter = 0;
|
||
|
mem_allocated = false;
|
||
|
command_set = false;
|
||
|
file_set = false;
|
||
|
opt_prefix_char = '-';
|
||
|
file_delimiter_char = ':';
|
||
|
file_comment_char = '#';
|
||
|
equalsign = '=';
|
||
|
comment = '#' ;
|
||
|
delimiter = ':' ;
|
||
|
endofline = '\n';
|
||
|
whitespace = ' ' ;
|
||
|
nullterminate = '\0';
|
||
|
set = false;
|
||
|
once = true;
|
||
|
hasoptions = false;
|
||
|
autousage = false;
|
||
|
|
||
|
strcpy( long_opt_prefix , "--" );
|
||
|
|
||
|
if( alloc() == false ){
|
||
|
cout << endl << "OPTIONS ERROR : Failed allocating memory" ;
|
||
|
cout << endl ;
|
||
|
cout << "Exiting." << endl ;
|
||
|
exit (0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::alloc()
|
||
|
{
|
||
|
int i = 0 ;
|
||
|
int size = 0 ;
|
||
|
|
||
|
if( mem_allocated )
|
||
|
return true;
|
||
|
|
||
|
size = (max_options+1) * sizeof(const char*);
|
||
|
options = (const char**)malloc( size );
|
||
|
optiontype = (int*) malloc( (max_options+1)*sizeof(int) );
|
||
|
optionindex = (int*) malloc( (max_options+1)*sizeof(int) );
|
||
|
if( options == NULL || optiontype == NULL || optionindex == NULL )
|
||
|
return false;
|
||
|
else
|
||
|
mem_allocated = true;
|
||
|
for( i = 0 ; i < max_options ; i++ ){
|
||
|
options[i] = NULL;
|
||
|
optiontype[i] = 0 ;
|
||
|
optionindex[i] = -1 ;
|
||
|
}
|
||
|
optionchars = (char*) malloc( (max_char_options+1)*sizeof(char) );
|
||
|
optchartype = (int*) malloc( (max_char_options+1)*sizeof(int) );
|
||
|
optcharindex = (int*) malloc( (max_char_options+1)*sizeof(int) );
|
||
|
if( optionchars == NULL ||
|
||
|
optchartype == NULL ||
|
||
|
optcharindex == NULL )
|
||
|
{
|
||
|
mem_allocated = false;
|
||
|
return false;
|
||
|
}
|
||
|
for( i = 0 ; i < max_char_options ; i++ ){
|
||
|
optionchars[i] = '0';
|
||
|
optchartype[i] = 0 ;
|
||
|
optcharindex[i] = -1 ;
|
||
|
}
|
||
|
|
||
|
size = (max_usage_lines+1) * sizeof(const char*) ;
|
||
|
usage = (const char**) malloc( size );
|
||
|
|
||
|
if( usage == NULL ){
|
||
|
mem_allocated = false;
|
||
|
return false;
|
||
|
}
|
||
|
for( i = 0 ; i < max_usage_lines ; i++ )
|
||
|
usage[i] = NULL;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::doubleOptStorage()
|
||
|
{
|
||
|
options = (const char**)realloc( options,
|
||
|
((2*max_options)+1) * sizeof( const char*) );
|
||
|
optiontype = (int*) realloc( optiontype ,
|
||
|
((2 * max_options)+1)* sizeof(int) );
|
||
|
optionindex = (int*) realloc( optionindex,
|
||
|
((2 * max_options)+1) * sizeof(int) );
|
||
|
if( options == NULL || optiontype == NULL || optionindex == NULL )
|
||
|
return false;
|
||
|
/* init new storage */
|
||
|
for( int i = max_options ; i < 2*max_options ; i++ ){
|
||
|
options[i] = NULL;
|
||
|
optiontype[i] = 0 ;
|
||
|
optionindex[i] = -1 ;
|
||
|
}
|
||
|
max_options = 2 * max_options ;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::doubleCharStorage()
|
||
|
{
|
||
|
optionchars = (char*) realloc( optionchars,
|
||
|
((2*max_char_options)+1)*sizeof(char) );
|
||
|
optchartype = (int*) realloc( optchartype,
|
||
|
((2*max_char_options)+1)*sizeof(int) );
|
||
|
optcharindex = (int*) realloc( optcharindex,
|
||
|
((2*max_char_options)+1)*sizeof(int) );
|
||
|
if( optionchars == NULL ||
|
||
|
optchartype == NULL ||
|
||
|
optcharindex == NULL )
|
||
|
return false;
|
||
|
/* init new storage */
|
||
|
for( int i = max_char_options ; i < 2*max_char_options ; i++ ){
|
||
|
optionchars[i] = '0';
|
||
|
optchartype[i] = 0 ;
|
||
|
optcharindex[i] = -1 ;
|
||
|
}
|
||
|
max_char_options = 2 * max_char_options;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::doubleUsageStorage()
|
||
|
{
|
||
|
usage = (const char**)realloc( usage,
|
||
|
((2*max_usage_lines)+1) * sizeof( const char*) );
|
||
|
if ( usage == NULL )
|
||
|
return false;
|
||
|
for( int i = max_usage_lines ; i < 2*max_usage_lines ; i++ )
|
||
|
usage[i] = NULL;
|
||
|
max_usage_lines = 2 * max_usage_lines ;
|
||
|
return true;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
AnyOption::cleanup()
|
||
|
{
|
||
|
free (options);
|
||
|
free (optiontype);
|
||
|
free (optionindex);
|
||
|
free (optionchars);
|
||
|
free (optchartype);
|
||
|
free (optcharindex);
|
||
|
free (usage);
|
||
|
if( values != NULL )
|
||
|
free (values);
|
||
|
if( new_argv != NULL )
|
||
|
free (new_argv);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setCommandPrefixChar( char _prefix )
|
||
|
{
|
||
|
opt_prefix_char = _prefix;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setCommandLongPrefix( char *_prefix )
|
||
|
{
|
||
|
if( strlen( _prefix ) > MAX_LONG_PREFIX_LENGTH ){
|
||
|
*( _prefix + MAX_LONG_PREFIX_LENGTH ) = '\0';
|
||
|
}
|
||
|
|
||
|
strcpy (long_opt_prefix, _prefix);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setFileCommentChar( char _comment )
|
||
|
{
|
||
|
file_delimiter_char = _comment;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
AnyOption::setFileDelimiterChar( char _delimiter )
|
||
|
{
|
||
|
file_comment_char = _delimiter ;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::CommandSet()
|
||
|
{
|
||
|
return( command_set );
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::FileSet()
|
||
|
{
|
||
|
return( file_set );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::noPOSIX()
|
||
|
{
|
||
|
posix_style = false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::POSIX()
|
||
|
{
|
||
|
return posix_style;
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
AnyOption::setVerbose()
|
||
|
{
|
||
|
verbose = true ;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::printVerbose()
|
||
|
{
|
||
|
if( verbose )
|
||
|
cout << endl ;
|
||
|
}
|
||
|
void
|
||
|
AnyOption::printVerbose( const char *msg )
|
||
|
{
|
||
|
if( verbose )
|
||
|
cout << msg ;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::printVerbose( char *msg )
|
||
|
{
|
||
|
if( verbose )
|
||
|
cout << msg ;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::printVerbose( char ch )
|
||
|
{
|
||
|
if( verbose )
|
||
|
cout << ch ;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::hasOptions()
|
||
|
{
|
||
|
return hasoptions;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::autoUsagePrint(bool _autousage)
|
||
|
{
|
||
|
autousage = _autousage;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::useCommandArgs( int _argc, char **_argv )
|
||
|
{
|
||
|
argc = _argc;
|
||
|
argv = _argv;
|
||
|
command_set = true;
|
||
|
appname = argv[0];
|
||
|
if(argc > 1) hasoptions = true;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::useFiileName( const char *_filename )
|
||
|
{
|
||
|
filename = _filename;
|
||
|
file_set = true;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* set methods for options
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
AnyOption::setCommandOption( const char *opt )
|
||
|
{
|
||
|
addOption( opt , COMMAND_OPT );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setCommandOption( char opt )
|
||
|
{
|
||
|
addOption( opt , COMMAND_OPT );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setCommandOption( const char *opt , char optchar )
|
||
|
{
|
||
|
addOption( opt , COMMAND_OPT );
|
||
|
addOption( optchar , COMMAND_OPT );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setCommandFlag( const char *opt )
|
||
|
{
|
||
|
addOption( opt , COMMAND_FLAG );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setCommandFlag( char opt )
|
||
|
{
|
||
|
addOption( opt , COMMAND_FLAG );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setCommandFlag( const char *opt , char optchar )
|
||
|
{
|
||
|
addOption( opt , COMMAND_FLAG );
|
||
|
addOption( optchar , COMMAND_FLAG );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setFileOption( const char *opt )
|
||
|
{
|
||
|
addOption( opt , FILE_OPT );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setFileOption( char opt )
|
||
|
{
|
||
|
addOption( opt , FILE_OPT );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setFileOption( const char *opt , char optchar )
|
||
|
{
|
||
|
addOption( opt , FILE_OPT );
|
||
|
addOption( optchar, FILE_OPT );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setFileFlag( const char *opt )
|
||
|
{
|
||
|
addOption( opt , FILE_FLAG );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setFileFlag( char opt )
|
||
|
{
|
||
|
addOption( opt , FILE_FLAG );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setFileFlag( const char *opt , char optchar )
|
||
|
{
|
||
|
addOption( opt , FILE_FLAG );
|
||
|
addOption( optchar , FILE_FLAG );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setOption( const char *opt )
|
||
|
{
|
||
|
addOption( opt , COMMON_OPT );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setOption( char opt )
|
||
|
{
|
||
|
addOption( opt , COMMON_OPT );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setOption( const char *opt , char optchar )
|
||
|
{
|
||
|
addOption( opt , COMMON_OPT );
|
||
|
addOption( optchar , COMMON_OPT );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setFlag( const char *opt )
|
||
|
{
|
||
|
addOption( opt , COMMON_FLAG );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setFlag( const char opt )
|
||
|
{
|
||
|
addOption( opt , COMMON_FLAG );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::setFlag( const char *opt , char optchar )
|
||
|
{
|
||
|
addOption( opt , COMMON_FLAG );
|
||
|
addOption( optchar , COMMON_FLAG );
|
||
|
g_value_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::addOption( const char *opt, int type )
|
||
|
{
|
||
|
if( option_counter >= max_options ){
|
||
|
if( doubleOptStorage() == false ){
|
||
|
addOptionError( opt );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
options[ option_counter ] = opt ;
|
||
|
optiontype[ option_counter ] = type ;
|
||
|
optionindex[ option_counter ] = g_value_counter;
|
||
|
option_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::addOption( char opt, int type )
|
||
|
{
|
||
|
if( !POSIX() ){
|
||
|
printVerbose("Ignoring the option character \"");
|
||
|
printVerbose( opt );
|
||
|
printVerbose( "\" ( POSIX options are turned off )" );
|
||
|
printVerbose();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
if( optchar_counter >= max_char_options ){
|
||
|
if( doubleCharStorage() == false ){
|
||
|
addOptionError( opt );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
optionchars[ optchar_counter ] = opt ;
|
||
|
optchartype[ optchar_counter ] = type ;
|
||
|
optcharindex[ optchar_counter ] = g_value_counter;
|
||
|
optchar_counter++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::addOptionError( const char *opt )
|
||
|
{
|
||
|
cout << endl ;
|
||
|
cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
|
||
|
cout << "While adding the option : \""<< opt << "\"" << endl;
|
||
|
cout << "Exiting." << endl ;
|
||
|
cout << endl ;
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::addOptionError( char opt )
|
||
|
{
|
||
|
cout << endl ;
|
||
|
cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
|
||
|
cout << "While adding the option: \""<< opt << "\"" << endl;
|
||
|
cout << "Exiting." << endl ;
|
||
|
cout << endl ;
|
||
|
exit(0);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::processOptions()
|
||
|
{
|
||
|
if( ! valueStoreOK() )
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::processCommandArgs(int max_args)
|
||
|
{
|
||
|
max_legal_args = max_args;
|
||
|
processCommandArgs();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::processCommandArgs( int _argc, char **_argv, int max_args )
|
||
|
{
|
||
|
max_legal_args = max_args;
|
||
|
processCommandArgs( _argc, _argv );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::processCommandArgs( int _argc, char **_argv )
|
||
|
{
|
||
|
useCommandArgs( _argc, _argv );
|
||
|
processCommandArgs();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::processCommandArgs()
|
||
|
{
|
||
|
if( ! ( valueStoreOK() && CommandSet() ) )
|
||
|
return;
|
||
|
|
||
|
if( max_legal_args == 0 )
|
||
|
max_legal_args = argc;
|
||
|
new_argv = (int*) malloc( (max_legal_args+1) * sizeof(int) );
|
||
|
for( int i = 1 ; i < argc ; i++ ){/* ignore first argv */
|
||
|
if( argv[i][0] == long_opt_prefix[0] &&
|
||
|
argv[i][1] == long_opt_prefix[1] ) { /* long GNU option */
|
||
|
int match_at = parseGNU( argv[i]+2 ); /* skip -- */
|
||
|
if( match_at >= 0 && i < argc-1 ) /* found match */
|
||
|
setValue( options[match_at] , argv[++i] );
|
||
|
}else if( argv[i][0] == opt_prefix_char ) { /* POSIX char */
|
||
|
if( POSIX() ){
|
||
|
char ch = parsePOSIX( argv[i]+1 );/* skip - */
|
||
|
if( ch != '0' && i < argc-1 ) /* matching char */
|
||
|
setValue( ch , argv[++i] );
|
||
|
} else { /* treat it as GNU option with a - */
|
||
|
int match_at = parseGNU( argv[i]+1 ); /* skip - */
|
||
|
if( match_at >= 0 && i < argc-1 ) /* found match */
|
||
|
setValue( options[match_at] , argv[++i] );
|
||
|
}
|
||
|
}else { /* not option but an argument keep index */
|
||
|
if( new_argc < max_legal_args ){
|
||
|
new_argv[ new_argc ] = i ;
|
||
|
new_argc++;
|
||
|
}else{ /* ignore extra arguments */
|
||
|
printVerbose( "Ignoring extra argument: " );
|
||
|
printVerbose( argv[i] );
|
||
|
printVerbose( );
|
||
|
printAutoUsage();
|
||
|
}
|
||
|
printVerbose( "Unknown command argument option : " );
|
||
|
printVerbose( argv[i] );
|
||
|
printVerbose( );
|
||
|
printAutoUsage();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
char
|
||
|
AnyOption::parsePOSIX( char* arg )
|
||
|
{
|
||
|
|
||
|
for( unsigned int i = 0 ; i < strlen(arg) ; i++ ){
|
||
|
char ch = arg[i] ;
|
||
|
if( matchChar(ch) ) { /* keep matching flags till an option */
|
||
|
/*if last char argv[++i] is the value */
|
||
|
if( i == strlen(arg)-1 ){
|
||
|
return ch;
|
||
|
}else{/* else the rest of arg is the value */
|
||
|
i++; /* skip any '=' and ' ' */
|
||
|
while( arg[i] == whitespace
|
||
|
|| arg[i] == equalsign )
|
||
|
i++;
|
||
|
setValue( ch , arg+i );
|
||
|
return '0';
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
printVerbose( "Unknown command argument option : " );
|
||
|
printVerbose( arg );
|
||
|
printVerbose( );
|
||
|
printAutoUsage();
|
||
|
return '0';
|
||
|
}
|
||
|
|
||
|
int
|
||
|
AnyOption::parseGNU( char *arg )
|
||
|
{
|
||
|
int split_at = 0;
|
||
|
/* if has a '=' sign get value */
|
||
|
for( unsigned int i = 0 ; i < strlen(arg) ; i++ ){
|
||
|
if(arg[i] == equalsign ){
|
||
|
split_at = i ; /* store index */
|
||
|
i = strlen(arg); /* get out of loop */
|
||
|
}
|
||
|
}
|
||
|
if( split_at > 0 ){ /* it is an option value pair */
|
||
|
char* tmp = (char*) malloc( (split_at+1)*sizeof(char) );
|
||
|
for( int i = 0 ; i < split_at ; i++ )
|
||
|
tmp[i] = arg[i];
|
||
|
tmp[split_at] = '\0';
|
||
|
|
||
|
if ( matchOpt( tmp ) >= 0 ){
|
||
|
setValue( options[matchOpt(tmp)] , arg+split_at+1 );
|
||
|
free (tmp);
|
||
|
}else{
|
||
|
printVerbose( "Unknown command argument option : " );
|
||
|
printVerbose( arg );
|
||
|
printVerbose( );
|
||
|
printAutoUsage();
|
||
|
free (tmp);
|
||
|
return -1;
|
||
|
}
|
||
|
}else{ /* regular options with no '=' sign */
|
||
|
return matchOpt(arg);
|
||
|
}
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
AnyOption::matchOpt( char *opt )
|
||
|
{
|
||
|
for( int i = 0 ; i < option_counter ; i++ ){
|
||
|
if( strcmp( options[i], opt ) == 0 ){
|
||
|
if( optiontype[i] == COMMON_OPT ||
|
||
|
optiontype[i] == COMMAND_OPT )
|
||
|
{ /* found option return index */
|
||
|
return i;
|
||
|
}else if( optiontype[i] == COMMON_FLAG ||
|
||
|
optiontype[i] == COMMAND_FLAG )
|
||
|
{ /* found flag, set it */
|
||
|
setFlagOn( opt );
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
printVerbose( "Unknown command argument option : " );
|
||
|
printVerbose( opt ) ;
|
||
|
printVerbose( );
|
||
|
printAutoUsage();
|
||
|
return -1;
|
||
|
}
|
||
|
bool
|
||
|
AnyOption::matchChar( char c )
|
||
|
{
|
||
|
for( int i = 0 ; i < optchar_counter ; i++ ){
|
||
|
if( optionchars[i] == c ) { /* found match */
|
||
|
if(optchartype[i] == COMMON_OPT ||
|
||
|
optchartype[i] == COMMAND_OPT )
|
||
|
{ /* an option store and stop scanning */
|
||
|
return true;
|
||
|
}else if( optchartype[i] == COMMON_FLAG ||
|
||
|
optchartype[i] == COMMAND_FLAG ) { /* a flag store and keep scanning */
|
||
|
setFlagOn( c );
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
printVerbose( "Unknown command argument option : " );
|
||
|
printVerbose( c ) ;
|
||
|
printVerbose( );
|
||
|
printAutoUsage();
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::valueStoreOK( )
|
||
|
{
|
||
|
int size= 0;
|
||
|
if( !set ){
|
||
|
if( g_value_counter > 0 ){
|
||
|
size = g_value_counter * sizeof(char*);
|
||
|
values = (char**)malloc( size );
|
||
|
for( int i = 0 ; i < g_value_counter ; i++)
|
||
|
values[i] = NULL;
|
||
|
set = true;
|
||
|
}
|
||
|
}
|
||
|
return set;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* public get methods
|
||
|
*/
|
||
|
char*
|
||
|
AnyOption::getValue( const char *option )
|
||
|
{
|
||
|
if( !valueStoreOK() )
|
||
|
return NULL;
|
||
|
|
||
|
for( int i = 0 ; i < option_counter ; i++ ){
|
||
|
if( strcmp( options[i], option ) == 0 )
|
||
|
return values[ optionindex[i] ];
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::getFlag( const char *option )
|
||
|
{
|
||
|
if( !valueStoreOK() )
|
||
|
return false;
|
||
|
for( int i = 0 ; i < option_counter ; i++ ){
|
||
|
if( strcmp( options[i], option ) == 0 )
|
||
|
return findFlag( values[ optionindex[i] ] );
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
char*
|
||
|
AnyOption::getValue( char option )
|
||
|
{
|
||
|
if( !valueStoreOK() )
|
||
|
return NULL;
|
||
|
for( int i = 0 ; i < optchar_counter ; i++ ){
|
||
|
if( optionchars[i] == option )
|
||
|
return values[ optcharindex[i] ];
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::getFlag( char option )
|
||
|
{
|
||
|
if( !valueStoreOK() )
|
||
|
return false;
|
||
|
for( int i = 0 ; i < optchar_counter ; i++ ){
|
||
|
if( optionchars[i] == option )
|
||
|
return findFlag( values[ optcharindex[i] ] ) ;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::findFlag( char* val )
|
||
|
{
|
||
|
if( val == NULL )
|
||
|
return false;
|
||
|
|
||
|
if( strcmp( TRUE_FLAG , val ) == 0 )
|
||
|
return true;
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* private set methods
|
||
|
*/
|
||
|
bool
|
||
|
AnyOption::setValue( const char *option , char *value )
|
||
|
{
|
||
|
if( !valueStoreOK() )
|
||
|
return false;
|
||
|
for( int i = 0 ; i < option_counter ; i++ ){
|
||
|
if( strcmp( options[i], option ) == 0 ){
|
||
|
values[ optionindex[i] ] = (char*) malloc((strlen(value)+1)*sizeof(char));
|
||
|
strcpy( values[ optionindex[i] ], value );
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::setFlagOn( const char *option )
|
||
|
{
|
||
|
if( !valueStoreOK() )
|
||
|
return false;
|
||
|
for( int i = 0 ; i < option_counter ; i++ ){
|
||
|
if( strcmp( options[i], option ) == 0 ){
|
||
|
values[ optionindex[i] ] = (char*) malloc((strlen(TRUE_FLAG)+1)*sizeof(char));
|
||
|
strcpy( values[ optionindex[i] ] , TRUE_FLAG );
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::setValue( char option , char *value )
|
||
|
{
|
||
|
if( !valueStoreOK() )
|
||
|
return false;
|
||
|
for( int i = 0 ; i < optchar_counter ; i++ ){
|
||
|
if( optionchars[i] == option ){
|
||
|
values[ optcharindex[i] ] = (char*) malloc((strlen(value)+1)*sizeof(char));
|
||
|
strcpy( values[ optcharindex[i] ], value );
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::setFlagOn( char option )
|
||
|
{
|
||
|
if( !valueStoreOK() )
|
||
|
return false;
|
||
|
for( int i = 0 ; i < optchar_counter ; i++ ){
|
||
|
if( optionchars[i] == option ){
|
||
|
values[ optcharindex[i] ] = (char*) malloc((strlen(TRUE_FLAG)+1)*sizeof(char));
|
||
|
strcpy( values[ optcharindex[i] ] , TRUE_FLAG );
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
AnyOption::getArgc( )
|
||
|
{
|
||
|
return new_argc;
|
||
|
}
|
||
|
|
||
|
char*
|
||
|
AnyOption::getArgv( int index )
|
||
|
{
|
||
|
if( index < new_argc ){
|
||
|
return ( argv[ new_argv[ index ] ] );
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/* dotfile sub routines */
|
||
|
|
||
|
bool
|
||
|
AnyOption::processFile()
|
||
|
{
|
||
|
if( ! (valueStoreOK() && FileSet()) )
|
||
|
return false;
|
||
|
return ( consumeFile(readFile()) );
|
||
|
}
|
||
|
|
||
|
bool
|
||
|
AnyOption::processFile( const char *filename )
|
||
|
{
|
||
|
useFiileName(filename );
|
||
|
return ( processFile() );
|
||
|
}
|
||
|
|
||
|
char*
|
||
|
AnyOption::readFile()
|
||
|
{
|
||
|
return ( readFile(filename) );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* read the file contents to a character buffer
|
||
|
*/
|
||
|
|
||
|
char*
|
||
|
AnyOption::readFile( const char* fname )
|
||
|
{
|
||
|
int length;
|
||
|
char *buffer;
|
||
|
ifstream is;
|
||
|
is.open ( fname , ifstream::in );
|
||
|
if( ! is.good() ){
|
||
|
is.close();
|
||
|
return NULL;
|
||
|
}
|
||
|
is.seekg (0, ios::end);
|
||
|
length = is.tellg();
|
||
|
is.seekg (0, ios::beg);
|
||
|
buffer = (char*) malloc(length*sizeof(char));
|
||
|
is.read (buffer,length);
|
||
|
is.close();
|
||
|
return buffer;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* scans a char* buffer for lines that does not
|
||
|
* start with the specified comment character.
|
||
|
*/
|
||
|
bool
|
||
|
AnyOption::consumeFile( char *buffer )
|
||
|
{
|
||
|
|
||
|
if( buffer == NULL )
|
||
|
return false;
|
||
|
|
||
|
char *cursor = buffer;/* preserve the ptr */
|
||
|
char *pline = NULL ;
|
||
|
int linelength = 0;
|
||
|
bool newline = true;
|
||
|
for( unsigned int i = 0 ; i < strlen( buffer ) ; i++ ){
|
||
|
if( *cursor == endofline ) { /* end of line */
|
||
|
if( pline != NULL ) /* valid line */
|
||
|
processLine( pline, linelength );
|
||
|
pline = NULL;
|
||
|
newline = true;
|
||
|
}else if( newline ){ /* start of line */
|
||
|
newline = false;
|
||
|
if( (*cursor != comment ) ){ /* not a comment */
|
||
|
pline = cursor ;
|
||
|
linelength = 0 ;
|
||
|
}
|
||
|
}
|
||
|
cursor++; /* keep moving */
|
||
|
linelength++;
|
||
|
}
|
||
|
free (buffer);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* find a valid type value pair separated by a delimiter
|
||
|
* character and pass it to valuePairs()
|
||
|
* any line which is not valid will be considered a value
|
||
|
* and will get passed on to justValue()
|
||
|
*
|
||
|
* assuming delimiter is ':' the behaviour will be,
|
||
|
*
|
||
|
* width:10 - valid pair valuePairs( width, 10 );
|
||
|
* width : 10 - valid pair valuepairs( width, 10 );
|
||
|
*
|
||
|
* :::: - not valid
|
||
|
* width - not valid
|
||
|
* :10 - not valid
|
||
|
* width: - not valid
|
||
|
* :: - not valid
|
||
|
* : - not valid
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
void
|
||
|
AnyOption::processLine( char *theline, int length )
|
||
|
{
|
||
|
bool found = false;
|
||
|
char *pline = (char*) malloc( (length+1)*sizeof(char) );
|
||
|
for( int i = 0 ; i < length ; i ++ )
|
||
|
pline[i]= *(theline++);
|
||
|
pline[length] = nullterminate;
|
||
|
char *cursor = pline ; /* preserve the ptr */
|
||
|
if( *cursor == delimiter || *(cursor+length-1) == delimiter ){
|
||
|
justValue( pline );/* line with start/end delimiter */
|
||
|
}else{
|
||
|
for( int i = 1 ; i < length-1 && !found ; i++){/* delimiter */
|
||
|
if( *cursor == delimiter ){
|
||
|
*(cursor-1) = nullterminate; /* two strings */
|
||
|
found = true;
|
||
|
valuePairs( pline , cursor+1 );
|
||
|
}
|
||
|
cursor++;
|
||
|
}
|
||
|
cursor++;
|
||
|
if( !found ) /* not a pair */
|
||
|
justValue( pline );
|
||
|
}
|
||
|
free (pline);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* removes trailing and preceeding whitespaces from a string
|
||
|
*/
|
||
|
char*
|
||
|
AnyOption::chomp( char *str )
|
||
|
{
|
||
|
while( *str == whitespace )
|
||
|
str++;
|
||
|
char *end = str+strlen(str)-1;
|
||
|
while( *end == whitespace )
|
||
|
end--;
|
||
|
*(end+1) = nullterminate;
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::valuePairs( char *type, char *value )
|
||
|
{
|
||
|
if ( strlen(chomp(type)) == 1 ){ /* this is a char option */
|
||
|
for( int i = 0 ; i < optchar_counter ; i++ ){
|
||
|
if( optionchars[i] == type[0] ){ /* match */
|
||
|
if( optchartype[i] == COMMON_OPT ||
|
||
|
optchartype[i] == FILE_OPT )
|
||
|
{
|
||
|
setValue( type[0] , chomp(value) );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/* if no char options matched */
|
||
|
for( int i = 0 ; i < option_counter ; i++ ){
|
||
|
if( strcmp( options[i], type ) == 0 ){ /* match */
|
||
|
if( optiontype[i] == COMMON_OPT ||
|
||
|
optiontype[i] == FILE_OPT )
|
||
|
{
|
||
|
setValue( type , chomp(value) );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
printVerbose( "Unknown option in resourcefile : " );
|
||
|
printVerbose( type );
|
||
|
printVerbose( );
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::justValue( char *type )
|
||
|
{
|
||
|
|
||
|
if ( strlen(chomp(type)) == 1 ){ /* this is a char option */
|
||
|
for( int i = 0 ; i < optchar_counter ; i++ ){
|
||
|
if( optionchars[i] == type[0] ){ /* match */
|
||
|
if( optchartype[i] == COMMON_FLAG ||
|
||
|
optchartype[i] == FILE_FLAG )
|
||
|
{
|
||
|
setFlagOn( type[0] );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/* if no char options matched */
|
||
|
for( int i = 0 ; i < option_counter ; i++ ){
|
||
|
if( strcmp( options[i], type ) == 0 ){ /* match */
|
||
|
if( optiontype[i] == COMMON_FLAG ||
|
||
|
optiontype[i] == FILE_FLAG )
|
||
|
{
|
||
|
setFlagOn( type );
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
printVerbose( "Unknown option in resourcefile : " );
|
||
|
printVerbose( type );
|
||
|
printVerbose( );
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* usage and help
|
||
|
*/
|
||
|
|
||
|
|
||
|
void
|
||
|
AnyOption::printAutoUsage()
|
||
|
{
|
||
|
if( autousage ) printUsage();
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::printUsage()
|
||
|
{
|
||
|
|
||
|
if( once ) {
|
||
|
once = false ;
|
||
|
cout << endl ;
|
||
|
for( int i = 0 ; i < usage_lines ; i++ )
|
||
|
cout << usage[i] << endl ;
|
||
|
cout << endl ;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
AnyOption::addUsage( const char *line )
|
||
|
{
|
||
|
if( usage_lines >= max_usage_lines ){
|
||
|
if( doubleUsageStorage() == false ){
|
||
|
addUsageError( line );
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
usage[ usage_lines ] = line ;
|
||
|
usage_lines++;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
AnyOption::addUsageError( const char *line )
|
||
|
{
|
||
|
cout << endl ;
|
||
|
cout << "OPTIONS ERROR : Failed allocating extra memory " << endl ;
|
||
|
cout << "While adding the usage/help : \""<< line << "\"" << endl;
|
||
|
cout << "Exiting." << endl ;
|
||
|
cout << endl ;
|
||
|
exit(0);
|
||
|
|
||
|
}
|