Argument Parsing

- Fixed bug in Nibbler::getUUID.
- Implemented Arguments::is_id.
- Implemented Arguments::is_uuid.
- Implemented Arguments::is_tag.
- Implemented Arguments::extract_id.
- Implemented Arguments::extract_uuid.
- Implemented Arguments::extract_tag.
- Implemented Arguments::valid_modifier.
- Implemented nibbler.t.cpp unit tests.
This commit is contained in:
Paul Beckingham 2011-06-04 17:02:19 -04:00
parent 354d66a5ac
commit 19aa78a922
4 changed files with 230 additions and 149 deletions

View file

@ -121,7 +121,7 @@ void Arguments::append_stdin ()
}
////////////////////////////////////////////////////////////////////////////////
// Scan all the arguments, and assign a category.
// Scan all the arguments, and assign a category for each one.
void Arguments::categorize ()
{
bool terminated = false;
@ -184,10 +184,8 @@ void Arguments::categorize ()
else if (arg->first.substr (0, 3) == "rc.")
arg->second = "override";
// +tag
// -tag
else if (arg->first[0] == '+' ||
arg->first[0] == '-')
// [+-]tag
else if (is_tag (arg->first))
arg->second = "tag";
// /pattern/
@ -203,13 +201,19 @@ void Arguments::categorize ()
else if (is_attr (arg->first))
arg->second = "attribute";
// TODO Sequence
// TODO UUID
// <id>[-<id>][,...]
else if (is_id (arg->first))
arg->second = "id";
// /<from>/<to>/[g]
else if (is_subst (arg->first))
arg->second = "substitution";
// <uuid>[,...]
else if (is_uuid (arg->first))
arg->second = "uuid";
// If the type is not known, it is treated as a generic word.
else if (arg->second == "")
arg->second = "word";
}
@ -499,6 +503,74 @@ bool Arguments::is_pattern (const std::string& input)
return false;
}
////////////////////////////////////////////////////////////////////////////////
// <id>[-<id>][,<id>[-<id>]]
bool Arguments::is_id (const std::string& input)
{
Nibbler n (input);
int id;
if (n.getUnsignedInt (id))
{
if (n.skip ('-'))
{
if (!n.getUnsignedInt (id))
return false;
}
while (n.skip (','))
{
if (n.getUnsignedInt (id))
{
if (n.skip ('-'))
{
if (!n.getUnsignedInt (id))
return false;
}
}
else
return false;
}
}
else
return false;
return n.depleted ();
}
////////////////////////////////////////////////////////////////////////////////
// <uuid>[,...]
bool Arguments::is_uuid (const std::string& input)
{
Nibbler n (input);
std::string uuid;
if (n.getUUID (uuid))
{
while (n.skip (','))
{
if (!n.getUUID (uuid))
return false;
}
}
else
return false;
return n.depleted ();
}
////////////////////////////////////////////////////////////////////////////////
// [+-]<tag>
bool Arguments::is_tag (const std::string& input)
{
if (input.length () > 1 &&
(input[0] == '+' ||
input[0] == '-'))
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
// ______________
// | |
@ -659,16 +731,6 @@ bool Arguments::extract_pattern (const std::string& input, std::string& pattern)
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Arguments::valid_modifier (const std::string& modifier)
{
for (unsigned int i = 0; i < NUM_MODIFIER_NAMES; ++i)
if (modifierNames[i] == modifier)
return true;
return false;
}
////////////////////////////////////////////////////////////////////////////////
// A sequence can be:
//
@ -692,89 +754,103 @@ bool Arguments::valid_modifier (const std::string& modifier)
//
// The sequence is "1,2".
//
/*
void Arguments::extract_sequence (std::vector <int>& sequence)
bool Arguments::extract_id (const std::string& input, std::vector <int>& sequence)
{
Nibbler n (input);
sequence.clear ();
std::vector <int> kill;
bool terminated = false;
for (unsigned int i = 0; i < this->size (); ++i)
int id;
if (n.getUnsignedInt (id))
{
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 (n.skip ('-'))
{
if (! digitsOnly (range[0]) ||
! digitsOnly (range[1]))
throw std::string ("Invalid ID in range.");
if (!n.getUnsignedInt (id))
throw std::string ("Unrecognized ID after hyphen.");
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.");
// TODO Is this meaningful?
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;
sequence.push_back (id);
}
// Not a properly formed sequence, therefore probably text.
while (n.skip (','))
{
if (n.getUnsignedInt (id))
{
sequence.push_back (id);
if (n.skip ('-'))
{
if (!n.getUnsignedInt (id))
throw std::string ("Unrecognized ID after hyphen.");
sequence.push_back (id);
}
}
else
break;
throw std::string ("Malformed ID");
}
}
else
throw std::string ("Malformed ID");
// 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 (unsigned int k = 0; k < kill.size (); ++k)
this->erase (this->begin () + kill[k]);
return n.depleted ();
}
////////////////////////////////////////////////////////////////////////////////
bool Arguments::extract_uuid (
const std::string& input,
std::vector <std::string>& sequence)
{
Nibbler n (input);
sequence.clear ();
std::string uuid;
if (n.getUUID (uuid))
{
sequence.push_back (uuid);
while (n.skip (','))
{
if (!n.getUUID (uuid))
throw std::string ("Unrecognized UUID after comma.");
sequence.push_back (uuid);
}
}
else
throw std::string ("Malformed UUID");
if (!n.depleted ())
throw std::string ("Unrecognized character(s) at end of pattern.");
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Arguments::extract_tag (
const std::string& input,
char& type,
std::string& tag)
{
if (input.length () > 1)
{
type = input[0];
tag = input.substr (1);
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////////////////
bool Arguments::valid_modifier (const std::string& modifier)
{
for (unsigned int i = 0; i < NUM_MODIFIER_NAMES; ++i)
if (modifierNames[i] == modifier)
return true;
return false;
}
*/
////////////////////////////////////////////////////////////////////////////////
void Arguments::dump (const std::string& label)
@ -789,7 +865,7 @@ void Arguments::dump (const std::string& label)
color_map["pattern"] = Color ("cyan on gray3");
color_map["attribute"] = Color ("bold red on gray3");
color_map["attmod"] = Color ("bold red on gray3");
color_map["sequence"] = Color ("yellow on gray3");
color_map["id"] = Color ("yellow on gray3");
color_map["uuid"] = Color ("yellow on gray3");
color_map["substitution"] = Color ("bold cyan on gray3");
color_map["none"] = Color ("white on gray3");
@ -801,7 +877,7 @@ void Arguments::dump (const std::string& label)
ViewText view;
view.width (context.getWidth ());
view.leftMargin (4);
view.leftMargin (2);
for (unsigned int i = 0; i < this->size (); ++i)
view.add (Column::factory ("string", ""));

View file

@ -63,23 +63,24 @@ public:
bool is_attmod (const std::string&);
bool is_subst (const std::string&);
bool is_pattern (const std::string&);
bool is_id (const std::string&);
bool is_uuid (const std::string&);
bool is_tag (const std::string&);
bool extract_attr (const std::string&, std::string&, std::string&);
bool extract_attmod (const std::string&, std::string&, std::string&, std::string&, std::string&);
bool extract_subst (const std::string&, std::string&, std::string&, bool&);
bool extract_pattern (const std::string&, std::string&);
bool extract_id (const std::string&, std::vector <int>&);
bool extract_uuid (const std::string&, std::vector <std::string>&);
bool extract_tag (const std::string&, char&, std::string&);
/*
void extract_words ();
*/
bool valid_modifier (const std::string&);
/*
void extract_sequence (std::vector <int>&);
void extract_uuids (std::vector <std::string>&);
void extract_attrs ();
void extract_words ();
void extract_tags ();
void extract_pattern ();
void extract_subst ();
*/
void dump (const std::string&);
};

View file

@ -452,49 +452,48 @@ bool Nibbler::getUUID (std::string& result)
std::string::size_type i = mCursor;
if (i < mLength &&
mLength - i >= 37)
mLength - i >= 36)
{
// 8-4-4-4-6-6
if (isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
mInput[i++] == '-' &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
mInput[i++] == '-' &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
mInput[i++] == '-' &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
mInput[i++] == '-' &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
mInput[i++] == '-' &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]) &&
isxdigit (mInput[i++]))
// 88888888-4444-4444-4444-cccccccccccc
if (isxdigit (mInput[i + 0]) &&
isxdigit (mInput[i + 1]) &&
isxdigit (mInput[i + 2]) &&
isxdigit (mInput[i + 3]) &&
isxdigit (mInput[i + 4]) &&
isxdigit (mInput[i + 5]) &&
isxdigit (mInput[i + 6]) &&
isxdigit (mInput[i + 7]) &&
mInput[i + 8] == '-' &&
isxdigit (mInput[i + 9]) &&
isxdigit (mInput[i + 10]) &&
isxdigit (mInput[i + 11]) &&
isxdigit (mInput[i + 12]) &&
mInput[i + 13] == '-' &&
isxdigit (mInput[i + 14]) &&
isxdigit (mInput[i + 15]) &&
isxdigit (mInput[i + 16]) &&
isxdigit (mInput[i + 17]) &&
mInput[i + 18] == '-' &&
isxdigit (mInput[i + 19]) &&
isxdigit (mInput[i + 20]) &&
isxdigit (mInput[i + 21]) &&
isxdigit (mInput[i + 22]) &&
mInput[i + 23] == '-' &&
isxdigit (mInput[i + 24]) &&
isxdigit (mInput[i + 25]) &&
isxdigit (mInput[i + 26]) &&
isxdigit (mInput[i + 27]) &&
isxdigit (mInput[i + 28]) &&
isxdigit (mInput[i + 29]) &&
isxdigit (mInput[i + 30]) &&
isxdigit (mInput[i + 31]) &&
isxdigit (mInput[i + 32]) &&
isxdigit (mInput[i + 33]) &&
isxdigit (mInput[i + 34]) &&
isxdigit (mInput[i + 35]))
{
result = mInput.substr (mCursor, 37);
mCursor = i;
result = mInput.substr (mCursor, 36);
mCursor = i + 36;
return true;
}
}

View file

@ -33,7 +33,7 @@ Context context;
////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv)
{
UnitTest t (168);
UnitTest t (171);
try
{
@ -273,12 +273,17 @@ int main (int argc, char** argv)
// bool getUUID (std::string&);
t.diag ("Nibbler::getUUID");
n = Nibbler ("00000000-0000-0000-0000-000000-000000,a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2-b3c4d5");
n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5");
t.ok (n.getUUID (s), "uuid 1 found");
t.is (s, "00000000-0000-0000-0000-000000-000000", "uuid 1 -> correct");
t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5", "uuid 1 -> correct");
t.ok (n.depleted (), "depleted");
n = Nibbler ("00000000-0000-0000-0000-000000000000,a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5");
t.ok (n.getUUID (s), "uuid 1 found");
t.is (s, "00000000-0000-0000-0000-000000000000", "uuid 1 -> correct");
t.ok (n.skip (','), "comma -> skipped");
t.ok (n.getUUID (s), "uuid 2 -> found");
t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2-b3c4d5", "uuid 2 -> correct");
t.is (s, "a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5", "uuid 2 -> correct");
t.ok (n.depleted (), "depleted");
// bool getUntilEOL (std::string&);