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 () void Arguments::categorize ()
{ {
bool terminated = false; bool terminated = false;
@ -184,10 +184,8 @@ void Arguments::categorize ()
else if (arg->first.substr (0, 3) == "rc.") else if (arg->first.substr (0, 3) == "rc.")
arg->second = "override"; arg->second = "override";
// +tag // [+-]tag
// -tag else if (is_tag (arg->first))
else if (arg->first[0] == '+' ||
arg->first[0] == '-')
arg->second = "tag"; arg->second = "tag";
// /pattern/ // /pattern/
@ -203,13 +201,19 @@ void Arguments::categorize ()
else if (is_attr (arg->first)) else if (is_attr (arg->first))
arg->second = "attribute"; arg->second = "attribute";
// TODO Sequence // <id>[-<id>][,...]
// TODO UUID else if (is_id (arg->first))
arg->second = "id";
// /<from>/<to>/[g] // /<from>/<to>/[g]
else if (is_subst (arg->first)) else if (is_subst (arg->first))
arg->second = "substitution"; 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 == "") else if (arg->second == "")
arg->second = "word"; arg->second = "word";
} }
@ -499,6 +503,74 @@ bool Arguments::is_pattern (const std::string& input)
return false; 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; 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: // A sequence can be:
// //
@ -692,89 +754,103 @@ bool Arguments::valid_modifier (const std::string& modifier)
// //
// The sequence is "1,2". // The sequence is "1,2".
// //
/* bool Arguments::extract_id (const std::string& input, std::vector <int>& sequence)
void Arguments::extract_sequence (std::vector <int>& sequence)
{ {
Nibbler n (input);
sequence.clear (); sequence.clear ();
std::vector <int> kill;
bool terminated = false; int id;
for (unsigned int i = 0; i < this->size (); ++i) 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); sequence.push_back (id);
something = true;
} if (n.skip ('-'))
else if (range.size () == 2)
{ {
if (! digitsOnly (range[0]) || if (!n.getUnsignedInt (id))
! digitsOnly (range[1])) throw std::string ("Unrecognized ID after hyphen.");
throw std::string ("Invalid ID in range.");
int low = (int)strtol (range[0].c_str (), NULL, 10); sequence.push_back (id);
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;
} }
// 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 else
break; throw std::string ("Malformed ID");
} }
} }
else
throw std::string ("Malformed ID");
return n.depleted ();
}
// Once a sequence has been found, any non-numeric arguments effectively ////////////////////////////////////////////////////////////////////////////////
// terminate sequence processing. bool Arguments::extract_uuid (
else if (sequence.size ()) const std::string& input,
terminated = true; 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;
} }
if (something) ////////////////////////////////////////////////////////////////////////////////
kill.push_back (i); 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;
} }
// Now remove args in the kill list. return false;
for (unsigned int k = 0; k < kill.size (); ++k) }
this->erase (this->begin () + kill[k]);
////////////////////////////////////////////////////////////////////////////////
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) 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["pattern"] = Color ("cyan on gray3");
color_map["attribute"] = Color ("bold red on gray3"); color_map["attribute"] = Color ("bold red on gray3");
color_map["attmod"] = 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["uuid"] = Color ("yellow on gray3");
color_map["substitution"] = Color ("bold cyan on gray3"); color_map["substitution"] = Color ("bold cyan on gray3");
color_map["none"] = Color ("white on gray3"); color_map["none"] = Color ("white on gray3");
@ -801,7 +877,7 @@ void Arguments::dump (const std::string& label)
ViewText view; ViewText view;
view.width (context.getWidth ()); view.width (context.getWidth ());
view.leftMargin (4); view.leftMargin (2);
for (unsigned int i = 0; i < this->size (); ++i) for (unsigned int i = 0; i < this->size (); ++i)
view.add (Column::factory ("string", "")); view.add (Column::factory ("string", ""));

View file

@ -63,23 +63,24 @@ public:
bool is_attmod (const std::string&); bool is_attmod (const std::string&);
bool is_subst (const std::string&); bool is_subst (const std::string&);
bool is_pattern (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_attr (const std::string&, std::string&, std::string&);
bool extract_attmod (const std::string&, std::string&, 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_subst (const std::string&, std::string&, std::string&, bool&);
bool extract_pattern (const std::string&, std::string&); 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&); 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&); void dump (const std::string&);
}; };

View file

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

View file

@ -33,7 +33,7 @@ Context context;
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int main (int argc, char** argv) int main (int argc, char** argv)
{ {
UnitTest t (168); UnitTest t (171);
try try
{ {
@ -273,12 +273,17 @@ int main (int argc, char** argv)
// bool getUUID (std::string&); // bool getUUID (std::string&);
t.diag ("Nibbler::getUUID"); 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.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.skip (','), "comma -> skipped");
t.ok (n.getUUID (s), "uuid 2 -> found"); 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"); t.ok (n.depleted (), "depleted");
// bool getUntilEOL (std::string&); // bool getUntilEOL (std::string&);