gaffitter-0.6.0/ 0000755 0001750 0001750 00000000000 11051403130 013332 5 ustar douglas douglas gaffitter-0.6.0/INSTALL 0000644 0001750 0001750 00000001563 11036735627 014416 0 ustar douglas douglas $Id: INSTALL 193 2008-07-14 20:48:23Z daaugusto $
------------------------------------------
Genetic Algorithm File Fitter -- gaffitter
------------------------------------------
http://gaffitter.sourceforge.net/ (home page)
http://sourceforge.net/projects/gaffitter/ (project page)
2005-2008 - Douglas A. Augusto (daaugusto@gmail.com)
Released under the GNU General Public License (GPL) version 3 (or
later)
http://www.gnu.org/licenses/gpl.txt
== Installation Instructions ==
1) Prerequisites
- POSIX-compatible Operating System (required by DiskUsage class to get
the size of a file or directory)
- C++ compiler (recommended: GCC)
2) Compilation
cd gaffitter-X.Y.Z
make
3) Installation (may need administrator privileges):
make install DESTDIR=/usr/local
(will install gaffitter in /usr/local/bin/; change DESTDIR as
necessary)
gaffitter-0.6.0/src/ 0000755 0001750 0001750 00000000000 11051403130 014121 5 ustar douglas douglas gaffitter-0.6.0/src/gaffitter.cc 0000644 0001750 0001750 00000005072 11050707040 016415 0 ustar douglas douglas // ---------------------------------------------------------------------
// $Id: gaffitter.cc 230 2008-08-14 01:45:04Z daaugusto $
//
// gaffitter.cc (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with gaffitter; if not, see .
//
// ---------------------------------------------------------------------
#include "Optimizer.h"
#include "optimizers/GeneticAlgorithm.h"
#include "optimizers/BestFit.h"
#include "optimizers/Split.h"
#include "Params.h"
#include "Input.h"
#include "util/Exception.h"
#include "util/CmdLineException.h"
//----------------------------------------------------------------------
int main( int argc, char** argv )
{
try {
// read the options
Params parameters( argc, argv );
// just ShowUsage()?
if( !parameters.Initialize() ) return 0;
// read the filenames
Input input( parameters );
Optimizer* gaffitter = 0;
try {
// create the GA optimizer
if( parameters.m_approximate )
gaffitter = new BestFit( input );
else if( parameters.m_split )
gaffitter = new Split( input );
else
gaffitter = new GeneticAlgorithm( input );
// evolve
gaffitter->Evolve();
// print the results
gaffitter->Output();
}
catch( ... ) {
delete gaffitter;
throw;
}
delete gaffitter;
}
catch( const CmdLine::E_Exception& e ) {
std::cerr << e;
return 1;
}
catch( const E_Exception& e )
{
std::cerr << e;
return 2;
}
catch( const std::exception& e )
{
std::cerr << '\n' << "> Error: " << e.what() << std::endl;
return 3;
}
catch( ... ) {
std::cerr << '\n' << "> Error: " << "An unknown error occurred."
<< std::endl;
return 4;
}
return 0; // ok, no errors
}
gaffitter-0.6.0/src/DiskUsage.cc 0000644 0001750 0001750 00000012101 11022703255 016313 0 ustar douglas douglas // ---------------------------------------------------------------------
// $Id: DiskUsage.cc 156 2008-06-08 07:13:49Z daaugusto $
//
// DiskUsage.cc (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with gaffitter; if not, see .
//
// ---------------------------------------------------------------------
/**
* This macro determines which file system interface shall be used, one
* replacing the other. `_FILE_OFFSET_BITS' allows the 64 bit interface
* to replace the old interface.
*
* If `_FILE_OFFSET_BITS' is undefined, or if it is defined to the value
* `32', nothing changes. The 32 bit interface is used and types like
* `off_t' have a size of 32 bits on 32 bit systems.
*
* On 32bit systems 'stat -> stat64' and 'lstat -> lstat64'
* transparently.
*/
#define _FILE_OFFSET_BITS 64
#include "DiskUsage.h"
#include "util/Exception.h"
#include
#include
#include
#include
#include
using namespace std;
//----------------------------------------------------------------------
unsigned DiskUsage::m_block_size;
//----------------------------------------------------------------------
Params::UBigInt
DiskUsage::GetSize(const char* filename)
{
struct stat st;
if (lstat(filename, &st) != 0)
{
cerr << "> Could not read: " << filename << endl;
return 0;
}
if (S_ISDIR(st.st_mode))
{
char saved_path[m_max_path_name], tmp_path[m_max_path_name];
// saves current path before chdir to 'filename' directory
if (getcwd(saved_path, m_max_path_name-1) == NULL)
{
cerr << "> Path name too long; maximum " << m_max_path_name-1
<< " chars." << endl;
return 0;
}
if (chdir(filename) != 0)
{
cerr << "> Could not chdir to: " << filename << endl;
return 0;
}
if (getcwd(tmp_path, m_max_path_name-1) == NULL)
{
cerr << "> Path name too long; maximum " << m_max_path_name-1
<< " chars." << endl;
return 0;
}
if (lstat(tmp_path, &st) != 0)
{
cerr << "> Could not read dir: " << tmp_path << endl;
return 0;
}
Params::UBigInt total =
AllocationSize(static_cast(st.st_size))
+ DepthFirstTraversal(tmp_path);
// return to the original path (important!)
chdir(saved_path);
return total;
}
else // ISREG, ISLNK, ISFIFO, ISBLK, ...
return AllocationSize(static_cast(st.st_size));
}
//----------------------------------------------------------------------
Params::UBigInt
DiskUsage::AllocationSize(Params::UBigInt size)
{
Params::UBigInt remainder = size % m_block_size;
/* Test whether the filesize is smaller than the allocation block.
Also, 0-sized files occupy space equal to the allocation block size. */
if (remainder || size==0)
return size += m_block_size - remainder;
// the filesize matches perfectly the allocation block
return size;
}
//----------------------------------------------------------------------
Params::UBigInt
DiskUsage::DepthFirstTraversal(const char* currdir)
{
if (chdir(currdir) != 0)
{
cerr << "> Could not chdir to: " << currdir << endl;
return 0;
}
Params::UBigInt sum = 0;
// open the directory
DIR *dir = opendir(".");
if (dir == NULL)
{
cerr << "> Could not open dir: " << currdir << endl;
chdir("..");
return 0;
}
struct dirent *de;
while ((de = readdir(dir)))
{
struct stat st;
if (lstat(de->d_name, &st) != 0)
{
cerr << "> Could not read: " << de->d_name << endl;
continue;
}
if (S_ISDIR(st.st_mode)) // is a directory (= recursive)
{
string tmp_str = de->d_name;
if ((tmp_str != ".") && (tmp_str != ".."))
{
string filename = string(currdir) + "/" + tmp_str;
sum += AllocationSize(static_cast(st.st_size))
+ DepthFirstTraversal(filename.c_str());
}
}
else // ISREG, ISLNK, ISFIFO, ISBLK, ...
sum += AllocationSize(static_cast(st.st_size));
}
closedir(dir);
chdir("..");
return sum;
}
//----------------------------------------------------------------------
gaffitter-0.6.0/src/Params.h 0000644 0001750 0001750 00000016717 11050677726 015560 0 ustar douglas douglas // ---------------------------------------------------------------------
// $Id: Params.h 229 2008-08-14 00:44:06Z daaugusto $
//
// Params.h (created on Tue Aug 23 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with gaffitter; if not, see .
//
// ---------------------------------------------------------------------
#ifndef params_hh
#define params_hh
#include
#include
#include
#include
#include
//----------------------------------------------------------------------
/**
* @class Params
*
* @brief This class gets and processes parameters (general and GA-related)
* specified by the user.
*/
class Params {
public:
/**
* @typedef Size_t
*
* @brief For file/item sizes and Score/Evaluate functions.
*
* - double can hold usually a max integer of 2^53 = 8192TiB
* - long double can hold usually a max integer of 2^64 = 16777216TiB :)
* - long int = 2^32 = 4GiB :(
* - long long int = 2^64 = 16777216TiB :), but isn't ANSI C++ :(
*/
typedef double Size_t;
typedef long double BigFloat; /**< big float datatype. */
typedef long long BigInt; /**< big signed int. */
typedef unsigned long long UBigInt; /**< big unsigned int. Must have
at least off_t (from stat.h) bits. */
public:
/**
* @brief Params' constructor.
*/
Params(int& argc, char** argv): m_argc(argc), m_argv(argv),
m_no_metric(false) {}
/**
* Print gaffitter version and exit
*/
void ShowVersion() const;
/**
* Show a brief help text and exit.
*/
void ShowUsage(const char*) const;
/**
* Set gaffitter options from user args.
*/
bool Initialize();
/**
* Print filesizes using Bytes, KiB, MiB or GiB units ("human"
* readable form); KB, MB or GB if '--si' option is set. Also, if
* Gaffitter is using direct input without units then PrettySize will
* just print the raw size (no suffixes).
*
* If --show-bytes is set then PrettySize prints output sizes in
* bytes too (except for direct input without a metric).
*/
std::string PrettySize(Size_t) const;
public:
int& m_argc;
char** m_argv;
/** A list of pointers to characters ("list of strings"). This list
* holds the arguments that could not be identified from the
* command-line (argv). Its values are probably files or item names.
*/
std::list m_cmdline_items;
public:
// General options.
Size_t m_target; /**< target in bytes (or just a number if "no metric"). */
Size_t m_min_size, m_max_size; /**< min and max size for the input
files/items. */
unsigned m_max_bins; /**< max number of desired bins (volumes). After the
process finishes, the m_max_bins better filled
bins are printed. */
int m_block_size; /**< the smallest amount of bytes a file can occupy. */
bool m_verbose; /**< switch to verbose mode. */
bool m_pipe; /**< accept input from pipe. */
bool m_hide_items; /**< don't print the selected items. */
bool m_hide_summary; /**< don't print footer summary. */
bool m_show_size; /**< print file size.*/
bool m_show_bytes; /**< also print size in bytes. */
bool m_direct_input; /**< accept "by hand" input (files not required). */
bool m_no_metric; /**< direct input does not require a metric (KB, MB...). */
// Sorting options
bool m_sort_by_size; /**< sort output by size instead of by name. */
bool m_sort_reverse; /**< reverse order while sorting. */
bool m_no_case; /**< ignore case distinctions when sorting. */
bool m_null_data; /**< assumes NULL (\\0) as the delimiter of input files */
char m_bins_separator; /**< char to separate the bins (default = newline) */
char m_enclose_chr; /**< char to enclose the filenames (default = none) */
bool m_enclose; /**< don't print anything if "--ew" was not used */
char m_delimit_chr; /**< char to delimit lines (default = newline) */
// Genetic Algorithm options.
unsigned m_ga_pop_size; /**< Population size */
int m_ga_num_gens; /**< Number of generations */
long m_ga_seed; /**< GA seed */
int m_ga_sel_pressure; /**< Selection pressure */
float m_ga_cross_prob; /**< Crossover probability */
float m_ga_mut_prob; /**< Mutation probability */
bool m_theoretical; /**< stop if the theoretical minimum number
of bins is reached */
unsigned m_bins_theo; /**< holds the theoretical minimum number of bins (can be
entered by the user). It differs from m_max_bins in the
sense that if m_bins_theo is reached, then the process
stops immediately and does not try to optimize (fill
better) the bins. */
// Search options
bool m_approximate; /**< Local approximation using Best First search
(non-optimal but very fast). */
bool m_split; /**< Split "Search" (very fast, but just
split sequentially the input according to target.*/
#if 0
bool m_brute_force; /**< Try all combinations, may be very slow. Not
recommended when |input| > 10. Use carefully! */
#endif
private:
/** XiB ou XB (if SI), where X is K, M or G. */
char m_unit_symbol;
/** power equal 1000 if --si is set; 1024 otherwise. */
float m_unit_power;
// constants
double KB(double power) const { return power; }
double KB() const { return KB(m_unit_power); }
double MB(double power) const { return power*power; }
double MB() const { return MB(m_unit_power); }
/* 1024^3 = 2^30, but 'float' usually supports only 2^24 integer
* numbers without loss (mantissa). However 'double' supports 2^53. */
double GB(double power) const { return power*power*power; }
double GB() const { return GB(m_unit_power); }
double TB(double power) const { return power*power*power*power; }
double TB() const { return TB(m_unit_power); }
public:
/**
* Converts a given string to \ref Size_t, checking for errors.
*/
static bool StringToDouble(Size_t& d, const std::string& s)
{
std::istringstream iss(s); return !(iss >> std::dec >> d).fail();
}
/** Get the correct size for target, min and max values. This
* function already applies the correct factor.
*/
bool GetSize( const std::string&, Size_t& ) const;
double DI_Factor() const { return m_di_factor; }
private:
double m_di_factor; /**< Factor to convert in bytes a size in KB, MB or GB.
(for direct input). */
};
//----------------------------------------------------------------------
#endif
gaffitter-0.6.0/src/util/ 0000755 0001750 0001750 00000000000 11051403130 015076 5 ustar douglas douglas gaffitter-0.6.0/src/util/Random.h 0000644 0001750 0001750 00000005353 11022703255 016506 0 ustar douglas douglas // ---------------------------------------------------------------------
// $Id: Random.h 156 2008-06-08 07:13:49Z daaugusto $
//
// Random.h (created on Tue Nov 08 01:08:35 BRT 2005)
//
// Genetic Algorithm File Fitter (gaffitter)
//
// Copyright (C) 2005-2008 Douglas A. Augusto
//
// This file is part of gaffitter.
//
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// gaffitter is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with gaffitter; if not, see .
//
// ---------------------------------------------------------------------
#ifndef random_hh
#define random_hh
#include
#include
#include
// ---------------------------------------------------------------------
/**
* Simple random number generator (based on standard rand() function).
*/
class Random {
public:
/** Sets the random seed. (0 = "random") */
static unsigned long Seed(unsigned long seed = 0L)
{
srand(seed = (seed == 0L) ? time(NULL) : seed);
return seed;
}
/** Uniform random [0:RAND_MAX] */
static unsigned long Int() { return rand(); }
/** Uniform random (integer) [a:b] */
static long Int(long a, long b)
{
return a + static_cast( Int()*(b-a+1.0) / (RAND_MAX+1.0) );
}
/** Uniform random (real) [a:b] */
static double Real(double a=0.0, double b=1.0)
{
return a + Int()*(b-a) / RAND_MAX;
}
/* Non Uniform Random Numbers
*
* 'weight = 1': uniform distribution between 'a' and 'b' [a,b]
* 'weight > 1': non uniform distribution towards 'a'
* 'weight < 1': non uniform distribution towards 'b'
*/
/** Non-uniform. Integer version [a,b) */
static long NonUniformInt(double weight, long a, long b)
{
return static_cast(pow(Real(0.0, 1.0), weight) * (b-a) + a);
}
/** Non-uniform. Float version */
static double NonUniformReal(double weight, double a=0.0, double b=1.0)
{
return pow(Real(0.0, 1.0), weight) * (b-a) + a;
}
/** Probability ("flip coin"): [0% = 0.0 and 100% = 1.0] */
static bool Probability(double p)
{
if (p <= 0.0) return false;
if (p >= 1.0) return true;
return (Real(0.0,1.0) < p) ? true : false;
}
};
// --------------------------------------------------------------------
#endif
gaffitter-0.6.0/src/util/CmdLineParser.cc 0000644 0001750 0001750 00000032220 11046010756 020110 0 ustar douglas douglas // ------------------------------------------------------------------------
// $Id: CmdLineParser.cc 226 2008-08-05 08:40:14Z daaugusto $
//
// CmdLineParser.cc (created on Tue Aug 8 11:01:58 BRT 2006)
//
// Command-line Parser
//
// Copyright (C) 2006-2008 Douglas Adriano Augusto (daaugusto)
//
// Command-line Parser is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// Command-line Parser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with Command-line Parser; if not, see .
//
// ------------------------------------------------------------------------
#include
#include
#include // for va_list, va_star, and va_end
#include "CmdLineParser.h"
using namespace CmdLine;
// ---------------------------------------------------------------------------
Option&
OptionsINT::Add( const std::string& name, const std::string& alias, INT def,
INT min, INT max )
{
if( max < min ) throw E_MaxMin( min, max, "Option " + name + ": " );
// calls the base Add function
return OptionsType::Add( name, alias, def, min, max ).
Flags( m_parser.m_flags );
}
// ---------------------------------------------------------------------------
Option&
OptionsFLOAT::Add( const std::string& name, const std::string& alias,
FLOAT def, FLOAT min, FLOAT max )
{
if( max < min ) throw E_MaxMin( min, max, "Option " + name + ": " );
// calls the base Add function
return OptionsType::Add( name, alias, def, min, max ).
Flags( m_parser.m_flags );
}
// ---------------------------------------------------------------------------
Option&
OptionsCHAR::Add( const std::string& name, const std::string& alias, char def,
const char* range, bool include_null_char )
{
m_ranges[name] = std::pair(range, include_null_char);
// calls the base Add function
return OptionsType::Add( name, alias, def ).Flags( m_parser.m_flags );
}
// ---------------------------------------------------------------------------
Option&
OptionsSTRING::Add( const std::string& name, const std::string& alias,
std::string def, const char* first, ... )
{
std::list range;
if( first ) // check if a list of strings was provided
{
const char* str;
va_list vl;
str = first;
va_start( vl, first );
do
{
range.push_back( std::string( str ) );
str = va_arg( vl, const char* );
} while( str != NULL ); // don't work with Zero (0), use NULL
va_end(vl);
}
if( !range.empty() ) m_ranges[name] = range;
// calls the base Add function
return OptionsType::Add( name, alias, def ).
Flags( m_parser.m_flags );
}
// ---------------------------------------------------------------------------
bool
OptionsINT::Match( int& i, char** argv, int argc )
{
// try to find
Option* p = Find( argv[i] );
if( p ) // found in the database of options OptionsType.m_opts
{
// try to convert the option arg to 'int'
if( i + 1 < argc )
{
std::istringstream s( argv[i + 1] ); INT tmp;
if( !(s >> std::dec >> tmp).fail() ) // ok, successful conversion
{
/* This is a special case. Although the provided value could
* be converted to an integer type, if the value is real
* (float) and there is a FLOAT option with the same name,
* then we ignore it and the function returns false, i.e.,
* "that option was not found in the database of options". */
if( std::string( argv[i + 1] ).find( '.' ) != std::string::npos &&
m_parser.Float.Find( argv[i] ) )
return false;
/* If argv[i] is duplicate, check if we may continue. If not, dis-
* card its argument (++i) and return true (found, but ignored).*/
if( !CheckDuplicate( p, argv[i] ) ) { ++i; return true; }
p->m_found = true; /* an useful/complete option (it has correct value)
found in the command-line. */
if( tmp >= p->m_min && tmp <= p->m_max )
p->m_value = tmp;
else {
if( p->IsSet( OUT_OF_RANGE ) )
throw E_OutOfRange( tmp, p->m_min, p->m_max, argv[i] );
if( !p->IsSet( SILENT ) )
std::cerr << "> [Ignoring] Option '" << argv[i] <<
"': value out of range." << std::endl;
}
// if used then "eat the argument"
++i;
// ok, there was used tmp or the default value
return true;
}
}
/* Option found in command-line, but was a compatible value found
* either? */
if( !p->m_found && p->IsSet( NO_VALUE ) ) throw E_NoValue( argv[i] );
}
return false;
}
// ---------------------------------------------------------------------
bool
OptionsFLOAT::Match( int& i, char** argv, int argc )
{
// try to find
Option* p = Find( argv[i] );
if( p ) // found in the database of options OptionsType.m_opts
{
// try to convert the option arg to 'FLOAT'
if( i + 1 < argc )
{
std::istringstream s( argv[i + 1] ); FLOAT tmp;
if( !(s >> std::dec >> tmp).fail() ) // ok, successful conversion
{
/* If argv[i] is duplicate, check if we may continue. If not, dis-
* card its argument (++i) and return true (found, but ignored).*/
if( !CheckDuplicate( p, argv[i] ) ) { ++i; return true; }
p->m_found = true;
// Check the range
if( tmp >= p->m_min && tmp <= p->m_max )
p->m_value = tmp;
else {
if( p->IsSet( OUT_OF_RANGE ) )
throw E_OutOfRange( tmp, p->m_min, p->m_max, argv[i] );
if( !p->IsSet( SILENT ) )
std::cerr << "> [Ignoring] Option '" << argv[i] <<
"': value out of range." << std::endl;
}
// if used then "eat the argument"
++i;
return true;
}
}
/* Option found in command-line, but was a compatible value found
* either? */
if( !p->m_found && p->IsSet( NO_VALUE ) ) throw E_NoValue( argv[i] );
}
return false;
}
// ---------------------------------------------------------------------
bool
OptionsBOOL::Match( int& i, char** argv, int argc )
{
/* A minus sign ("-") after the option name disable the previous one,
i.e.: -d- disables -d if -d was already declared. */
std::string tmp( argv[i] ); bool disable = false;
if( tmp.size() > 1 && tmp[tmp.size() - 1] == '-' )
{
disable = true; tmp.erase(tmp.end() - 1);
}
Option* p = Find( tmp );
if( p ) // found!
{
/* If argv[i] is duplicate, check if we may continue. If not,
* return true (found, but ignored).*/
if( !CheckDuplicate( p, argv[i] ) ) return true;
p->m_found = true;
p->m_value = disable ? false : true;
return true;
}
return false;
}
// ---------------------------------------------------------------------
bool
OptionsCHAR::Match( int& i, char** argv, int argc )
{
Option* p = Find( argv[i] );
if( p ) { // found!
if( i + 1 < argc )
{
/* If argv[i] is duplicate, check if we may continue. If not, dis-
* card its argument (++i) and return true (found, but ignored).*/
if( !CheckDuplicate( p, argv[i] ) ) { ++i; return true; }
char default_value = p->m_value;
// accept only if has one character or two (if the first is
// a backslash)
if( argv[i + 1][0] == '\0' || argv[i+1][1] == '\0')
{
p->m_value = argv[i+1][0];
p->m_found = true;
}
else if( argv[i + 1][0] == '\\' && argv[i + 1][2] == '\0' )
{
switch( argv[i + 1][1] ) {
case '0' : p->m_value = '\0'; break;
case 'a' : p->m_value = '\a'; break;
case 'b' : p->m_value = '\b'; break;
case 'f' : p->m_value = '\f'; break;
case 'n' : p->m_value = '\n'; break;
case 'r' : p->m_value = '\r'; break;
case 't' : p->m_value = '\t'; break;
case 'v' : p->m_value = '\v'; break;
case '\\': p->m_value = '\\'; break;
default : p->m_value = argv[i+1][1]; break;
}
p->m_found = true;
}
if( p->m_found )
{
std::map >
::iterator it = m_ranges.find( argv[i] );
/*
* it->second: pair
* it->second.first: const char* [ range of valid chars ]
* it->second.second: bool [ if \0 is also a valid char ]
*/
// A valid set of values was provided?
if( it != m_ranges.end() && it->second.first )
{
bool in_range = false;
for( int j = 0; (it->second.first)[j] != '\0'; ++j )
{
if( p->m_value == (it->second.first)[j] )
{
in_range = true;
break;
}
}
// Include the null char as a valid one?
if( it->second.second ) in_range |= p->m_value == '\0';
if( !in_range ) // p->m_value not in it
{
if( p->IsSet( OUT_OF_RANGE ) )
throw E_OutOfRange( argv[i + 1], it->second.first, argv[i] );
if( !p->IsSet( SILENT ) )
std::cerr << "> [Ignoring] Option '" << argv[i] <<
"': value out of range." << std::endl;
// restore the default value
p->m_value = default_value;
}
}
++i; // if used then "eat the argument"
return true;
}
}
/* Option found in command-line, but was a compatible value found
* either? */
if( p->IsSet( NO_VALUE ) ) throw E_NoValue( argv[i] );
}
return false;
}
// ---------------------------------------------------------------------
bool
OptionsSTRING::Match( int& i, char** argv, int argc )
{
// try to find
Option* p = Find( argv[i] );
if( p ) // found!
{
if( i + 1 < argc )
{
/* If argv[i] is duplicate, check if we may continue. If not, dis-
* card its argument (++i) and return true (found, but ignored).*/
if( !CheckDuplicate( p, argv[i] ) ) { ++i; return true; }
p->m_found = true;
// check if a range was given for the option argv[i]
std::map >
::iterator it = m_ranges.find( argv[i] );
// verify if a range has specified and if argv[i + 1] is in range
if( it != m_ranges.end() &&
find( it->second.begin(), it->second.end(),
std::string( argv[i + 1] ) ) == it->second.end() )
{
if( p->IsSet( OUT_OF_RANGE ) )
throw E_OutOfRange( argv[i + 1], it->second,
argv[i] );
if( !p->IsSet( SILENT ) )
std::cerr << "> [Ignoring] Option '" << argv[i] <<
"': value out of range." << std::endl;
}
else p->m_value = std::string( argv[i + 1] );
// if used then "eat the argument"
++i;
return true;
}
/* Option found in command-line, but was a value found either? */
if( !p->m_found && p->IsSet( NO_VALUE ) ) throw E_NoValue( argv[i] );
}
return false;
}
// ---------------------------------------------------------------------
int
Parser::Process()
{
int matched = 0;
for( int i = 1; i < m_argc; ++i )
{
if( !strcmp( m_argv[i], "--" ) ) break; // "--" stops the option processing
if( m_argv[i][0] == '-' && ( Int.Match( i, m_argv, m_argc ) ||
Float.Match( i, m_argv, m_argc ) || Bool.Match( i, m_argv, m_argc ) ||
Char.Match( i, m_argv, m_argc ) || String.Match( i, m_argv, m_argc )) )
{
++matched;
}
}
return matched;
}
// ---------------------------------------------------------------------
gaffitter-0.6.0/src/util/CmdLineParser.h 0000644 0001750 0001750 00000070173 11051344267 017766 0 ustar douglas douglas // ---------------------------------------------------------------------------
// $Id: CmdLineParser.h 232 2008-08-15 18:19:35Z daaugusto $
//
// CmdLineParser.h (created on Tue Aug 8 11:01:58 BRT 2006)
//
// Command-line Parser
//
// Copyright (C) 2006-2008 Douglas Adriano Augusto (daaugusto)
//
// Command-line Parser is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as published
// by the Free Software Foundation; either version 3 of the License, or (at
// your option) any later version.
//
// Command-line Parser is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
// Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with Command-line Parser; if not, see .
//
// ------------------------------------------------------------------------
#ifndef cmd_line_parser_h
#define cmd_line_parser_h
/** @file CmdLineParser.h
*
* Reads and extracts options/args from the command-line (via argv/argc).
*
Example:
@code
int main( int argc, char** argv )
{
CmdLine::Parser Opts( argc, argv );
// declaring a boolean option with an alias (optional)
Opts.Bool.Add( "-h", "--help" );
// an integer option (without alias) with default, min and max values
Opts.Int.Add( "-n","",5, 0, 10 );
// a float (float/double/long double) option
Opts.Float.Add( "--float", "--float-option" ,1.0, -10.0, 10.0 );
// a char option that specifies a set of valid characters
Opts.Char.Add( "--letter", "", "A", "abcABC" );
// a string option
Opts.String.Add( "-s", "--string-option", "default string" );
// another string option, but it specifies a range of values
Opts.String.Add( "--rgb-color", "", "red", "red", "green" ,"blue", NULL );
// ...
// it will contain the unrecognized options/arguments
vector remains;
// processing the command-line
Opts.Process( remains );
// getting the results!
if (Opts.Bool.Get("-h")) cout << "-h is set" << endl;
if (!Opts.Int.Found("-n"))
cout << "-n not declared, using default." << endl;
int integer = Opts.Int.Get("-n");
cout << "Value for '-n': " << integer << " As short int: "
<< Opts.Int.Get("-n") << endl;
cout << "Value for '-s': " << Opts.String.Get("-s") << endl;
// ...
cout << "\nUnrecognized arguments:" << endl;
list::const_iterator ci = remains.begin();
while (ci != remains.end()) cout << *ci++ << endl;
}
@endcode
For the code above, for example:
@verbatim
$ ./a.out -h --string-option "abc" item1 item2
-h is set
-n not declared, using default.
Value for '-n': 5
Value for '-s': abc
Unrecognized arguments:
item1
item2
@endverbatim
Other features:
@li A command-line with '--' makes the remaining parameters "unrecognized"
a priori, i.e., stops the searching/processing for options.
@li Using an option with a minus sign after the name cancels the previous
declaration (if any). For instance, '-x-' (or '--blahblah-') turns off
the previous declaration of '-x' (or '--blahblah').
@li If an option is declared two or more times, the last is used.
@li 'Char' options allow special characters such as '\\0', '\\n', etc.
*/
/**
* @page page1 Command-line Parser: General Documentation
There are four steps for a complete parsing of the command-line
arguments:
-# Initialization (@ref sec1)
-# Options inclusion (@ref sec2)
-# The parsing itself (@ref sec3)
-# Getting the values of the options (@ref sec4)
@section sec1 Initialization
In the initialization phase it is given to parser two variables: (1)
an integer indicating the @e number of strings (tokens) provided; (2)
the char** argv, containing a null-terminated list of
strings (the command-line itself). There are two ways to call the
@ref CmdLine::Parser constructor:
@code
CmdLine::Parser Opts( argc, argv );
@endcode
that creates the parser object Opts over the command-line argv.
Also, one could pass some flags:
@code
CmdLine::Parser Opts( m_argc, m_argv, CmdLine::SILENT |
CmdLine::OUT_OF_RANGE | CmdLine::NO_VALUE );
@endcode
The possible flags are:
- @b NONE just an alias to zero (0). To be used as Flags( CmdLine::NONE )
in order to clear the current flags.
- @b SILENT if set don't print warning messages to cerr (stderr).
- @b OUT_OF_RANGE throw a fatal exception (@ref CmdLine::E_OutOfRange)
when a value is out of a certain range provided by the user. If not
set, then the @b default value (provided by the user) is used when
a argument value is out of range.
- @b NO_VALUE throw a fatal exception (@ref CmdLine::E_NoValue) when no
value is found for an option that requires argument. If not set, that
option will be @b ignored and considered not found (Found() will return
false).
- @b DUPLICATE throw an error when an option is declared twice (or more)
times in command-line.
- @b FIRSTONLY pick up the first declaration only (discards all duplicates).
@section sec2 Declaring the Options
An user may specify five types of option: @b boolean (Bool), @b integer (Int),
@b float (Float), @b char (Char), and @b string (String) options.
The basic declaration format is: Object..Add( "--option-name" ).
For instance:
@code
Opts.Bool.Add( "-h" );
@endcode
will declare a boolean option labeled @c "-h". You can also create an alias
for an option:
@code
Opts.Bool.Add( "-h", "--help" );
@endcode
so the following two command-lines are equivalent:
@verbatim
program -h
program --help
@endverbatim
For the @e integer and @e float options it is possible to provide a default
value and a range of accepted values (min and max). For example:
@code
Opts.Int.Add( "-age", "", 18, 10, 65 );
Opts.Float.Add( "-f", "--float", 3.14, -1.0, numeric_limits::max() );
@endcode
will declare an option labeled @c -age with no alias, default value @c 18,
minimum value @c 10 and maximum allowed value @c 65. Analogically, a float
option @c -f/--float is declared with a maximum value defined as the maximum
value supported by a primitive float type.
The @b Char and @b String options go further allowing the specification,
respectively, of a set of valid characters or strings. For instance, the
code:
@code
Opts.Char.Add( "-c", "", 'a', "abcXYZ\n" );
@endcode
declares an option '-c' with default value 'a' and allows one of 'a', 'b',
'c', 'X', 'Y', 'Z', and '\\n' chars. If the user gives a value not in this
valid set, the default value 'a' is used or an exception out of range is
thrown (if @c OUT_OF_RANGE is set).
The String type uses a slightly different mode:
@code
Opts.String.Add( "-s", "", "low", "low", "high", NULL );
@endcode
In the above declaration, the valid values for -s are "low" and "high";
the default is "low".
@attention Since that version of the Add function allows variable
number of arguments, the keyword @b NULL is required in order to
close the list of valid strings. An unexpected error will be caused
if you forget that.
Also, one can specify custom flags to each option. E.g.:
@code
// Adding flags (use the operator | to add more than one at a time):
Opts.Int.Add( "-i", "--int" ).Set( CmdLine::NO_VALUE );
// Unsetting flags:
Opts.Int.Add( "-i", "--int" ).UnSet( CmdLine::NO_VALUE );
// Reseting default flags and adding specific ones:
Opts.Int.Add( "-i", "--int" ).Flags( CmdLine::SILENT | CmdLine::NO_VALUE );
// Reseting all default flags:
Opts.Int.Add( "-i", "--int" ).Flags( CmdLine::NONE );
@endcode
@section sec3 Parsing
The parsing is done by the @ref Parser::Process() function. It searches the
command-line, store the values of the arguments of each declared option and
finally returns the number of found (matched) options.
If the user wants to access the unrecognized options--like filenames--, it
is possible to pass a STL container as argument of Process(), e.g.:
@code
vector residue;
Opts.Process( residue ); // will fill residue with the unrecognized tokens
@endcode
One could also @c char* and const char* instead of @c
string. Moreover, Process( T& ), being a template function, will
accept any container provided that it implements @c clear() and @c
push_back() member functions.
@section sec4 Getting the Values
Finally, the processed values of the arguments of the options can be
accessed by the Get() function. Also, finding out whether an
option was found or not may be useful; this can be achieved by the function
Found( "option label" ). Consider the examples below:
@code
if( Opts.Bool.Get( "-h" ) ) { ShowHelp(); return; }
// If not provided by the user, it returns the default value
int age = Opts.Int.Get( "-age" );
// Alternative mode
int age;
bool found = Opts.Int.Get( "-age", age );
if( found )
cout << "The age is: " << age;
else
cout << "-age option not provided."
// Still, if the user just needs to know whether an option was
// provided on the command-line:
if( Opts.Int.Found( "-age" ) ) cout << "Age not specified."
@endcode
*/
#include
#include
#include
#include
#include