mirror of
https://github.com/GothenburgBitFactory/taskwarrior.git
synced 2025-07-07 20:06:36 +02:00
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:
parent
354d66a5ac
commit
19aa78a922
4 changed files with 230 additions and 149 deletions
|
@ -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", ""));
|
||||||
|
|
||||||
|
|
|
@ -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&);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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&);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue