Command Line Parsing

- Implemented Arguments::extract_command to locate the command
  keyword in an argument list.
- Implemented Arguments::extract_sequence to locate and remove an ID
  sequence from an argument list.
- Added unit test for extract_sequence.
- Stubbed all Argument::extract_<object> methods.
- Simplified code in (soon to be obsolete) Sequence.cpp.
This commit is contained in:
Paul Beckingham
2011-05-28 12:09:25 -04:00
parent 8f85b0e194
commit 306f10b420
9 changed files with 291 additions and 46 deletions

View File

@@ -30,6 +30,7 @@
#include <Context.h>
#include <Nibbler.h>
#include <text.h>
#include <util.h>
#include <Arguments.h>
extern Context context;
@@ -45,22 +46,11 @@ Arguments::~Arguments ()
}
////////////////////////////////////////////////////////////////////////////////
void Arguments::capture (int argc, char** argv)
void Arguments::capture (int argc, const char** argv)
{
for (int i = 0; i < argc; ++i)
{
/*
if (i == 0)
{
std::string::size_type cal = context.program.find ("/cal");
if (context.program == "cal" ||
(cal != std::string::npos && context.program.length () == cal + 4))
this->push_back ("calendar");
}
else
*/
if (i > 0)
this->push_back (argv[i]);
}
}
////////////////////////////////////////////////////////////////////////////////
@@ -241,3 +231,159 @@ std::string Arguments::combine ()
}
////////////////////////////////////////////////////////////////////////////////
// Given a vector of command keywords, scan all arguments and locate the first
// argument that matches a keyword.
bool Arguments::extract_command (
const std::vector <std::string>& keywords,
std::string& command)
{
std::vector <std::string>::iterator arg;
for (arg = this->begin (); arg != this->end (); ++arg)
{
std::vector <std::string> matches;
if (autoComplete (*arg, keywords, matches) == 1)
{
if (*arg != matches[0])
context.debug ("Arguments::extract_command keyword '" + *arg + "' --> '" + matches[0] + "'");
else
context.debug ("Arguments::extract_command keyword '" + *arg + "'");
command = matches[0];
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
// A sequence can be:
//
// a single ID: 1
// a list of IDs: 1,3,5
// a list of IDs: 1 3 5
// a range: 5-10
// or a combination: 1,3,5-10 12
//
// If a sequence is followed by a non-number, then subsequent numbers are not
// interpreted as IDs. For example:
//
// 1 2 three 4
//
// The sequence is "1 2".
//
// The first number found in the command line is assumed to be a sequence. If
// there are two sequences, only the first is recognized, for example:
//
// 1,2 three 4,5
//
// The sequence is "1,2".
//
void Arguments::extract_sequence (std::vector <int>& sequence)
{
sequence.clear ();
std::vector <int> kill;
bool terminated = false;
for (int i = 0; i < this->size (); ++i)
{
if (!terminated)
{
bool something = false;
// The '--' argument shuts off all parsing - everything is an argument.
if ((*this)[i] == "--")
{
terminated = true;
}
else
{
if (isdigit ((*this)[i][0]))
{
std::vector <std::string> ranges;
split (ranges, (*this)[i], ',');
std::vector <std::string>::iterator it;
for (it = ranges.begin (); it != ranges.end (); ++it)
{
std::vector <std::string> range;
split (range, *it, '-');
if (range.size () == 1)
{
if (! digitsOnly (range[0]))
throw std::string ("Invalid ID in sequence.");
int id = (int)strtol (range[0].c_str (), NULL, 10);
sequence.push_back (id);
something = true;
}
else if (range.size () == 2)
{
if (! digitsOnly (range[0]) ||
! digitsOnly (range[1]))
throw std::string ("Invalid ID in range.");
int low = (int)strtol (range[0].c_str (), NULL, 10);
int high = (int)strtol (range[1].c_str (), NULL, 10);
if (low > high)
throw std::string ("Inverted sequence range high-low.");
if (high - low >= ARGUMENTS_SEQUENCE_MAX_RANGE)
throw std::string ("ID Range too large.");
for (int r = low; r <= high; ++r)
sequence.push_back (r);
something = true;
}
// Not a properly formed sequence, therefore probably text.
else
break;
}
}
// Once a sequence has been found, any non-numeric arguments effectively
// terminate sequence processing.
else if (sequence.size ())
terminated = true;
}
if (something)
kill.push_back (i);
}
}
// Now remove args in the kill list.
for (int k = 0; k < kill.size (); ++k)
this->erase (this->begin () + kill[k]);
}
////////////////////////////////////////////////////////////////////////////////
// TODO
void Arguments::extract_uuids (std::vector <std::string>& uuids)
{
uuids.clear ();
}
////////////////////////////////////////////////////////////////////////////////
// TODO
void Arguments::extract_filter ()
{
}
////////////////////////////////////////////////////////////////////////////////
// TODO
void Arguments::extract_modifications ()
{
}
////////////////////////////////////////////////////////////////////////////////
// TODO
void Arguments::extract_text ()
{
}
////////////////////////////////////////////////////////////////////////////////