From 19aa78a922bad6c168b1659ed23906d2b9505276 Mon Sep 17 00:00:00 2001 From: Paul Beckingham Date: Sat, 4 Jun 2011 17:02:19 -0400 Subject: [PATCH] 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. --- src/Arguments.cpp | 258 +++++++++++++++++++++++++++++---------------- src/Arguments.h | 19 ++-- src/Nibbler.cpp | 81 +++++++------- test/nibbler.t.cpp | 21 ++-- 4 files changed, 230 insertions(+), 149 deletions(-) diff --git a/src/Arguments.cpp b/src/Arguments.cpp index b01e18b63..02cc07432 100644 --- a/src/Arguments.cpp +++ b/src/Arguments.cpp @@ -57,7 +57,7 @@ static const char* modifierNames[] = "noword" }; -#define NUM_MODIFIER_NAMES (sizeof (modifierNames) / sizeof (modifierNames[0])) +#define NUM_MODIFIER_NAMES (sizeof (modifierNames) / sizeof (modifierNames[0])) //////////////////////////////////////////////////////////////////////////////// Arguments::Arguments () @@ -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 + // [-][,...] + else if (is_id (arg->first)) + arg->second = "id"; // ///[g] else if (is_subst (arg->first)) arg->second = "substitution"; + // [,...] + 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; } +//////////////////////////////////////////////////////////////////////////////// +// [-][,[-]] +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 (); +} + +//////////////////////////////////////////////////////////////////////////////// +// [,...] +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 (); +} + +//////////////////////////////////////////////////////////////////////////////// +// [+-] +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 & sequence) +bool Arguments::extract_id (const std::string& input, std::vector & sequence) { + Nibbler n (input); sequence.clear (); - std::vector kill; - bool terminated = false; - for (unsigned int i = 0; i < this->size (); ++i) + int id; + if (n.getUnsignedInt (id)) { - if (!terminated) - { - bool something = false; + sequence.push_back (id); - // The '--' argument shuts off all parsing - everything is an argument. - if ((*this)[i] == "--") + if (n.skip ('-')) + { + if (!n.getUnsignedInt (id)) + throw std::string ("Unrecognized ID after hyphen."); + + sequence.push_back (id); + } + + while (n.skip (',')) + { + if (n.getUnsignedInt (id)) { - terminated = true; + sequence.push_back (id); + + if (n.skip ('-')) + { + if (!n.getUnsignedInt (id)) + throw std::string ("Unrecognized ID after hyphen."); + + sequence.push_back (id); + } } else - { - if (isdigit ((*this)[i][0])) - { - std::vector ranges; - split (ranges, (*this)[i], ','); - - std::vector ::iterator it; - for (it = ranges.begin (); it != ranges.end (); ++it) - { - std::vector 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."); - - // 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. - 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); + throw std::string ("Malformed ID"); } } + else + throw std::string ("Malformed ID"); - // 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 & 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", "")); diff --git a/src/Arguments.h b/src/Arguments.h index ac662df8b..037ba740e 100644 --- a/src/Arguments.h +++ b/src/Arguments.h @@ -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 &); + bool extract_uuid (const std::string&, std::vector &); + bool extract_tag (const std::string&, char&, std::string&); + +/* + void extract_words (); +*/ bool valid_modifier (const std::string&); -/* - void extract_sequence (std::vector &); - void extract_uuids (std::vector &); - void extract_attrs (); - void extract_words (); - void extract_tags (); - void extract_pattern (); - void extract_subst (); -*/ void dump (const std::string&); }; diff --git a/src/Nibbler.cpp b/src/Nibbler.cpp index 9772c869c..d30ceea8d 100644 --- a/src/Nibbler.cpp +++ b/src/Nibbler.cpp @@ -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; } } diff --git a/test/nibbler.t.cpp b/test/nibbler.t.cpp index cd55f1110..b59457bf6 100644 --- a/test/nibbler.t.cpp +++ b/test/nibbler.t.cpp @@ -33,7 +33,7 @@ Context context; //////////////////////////////////////////////////////////////////////////////// int main (int argc, char** argv) { - UnitTest t (168); + UnitTest t (171); try { @@ -273,13 +273,18 @@ 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"); - t.ok (n.getUUID (s), "uuid 1 found"); - t.is (s, "00000000-0000-0000-0000-000000-000000", "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.ok (n.depleted (), "depleted"); + n = Nibbler ("a0b1c2d3-e4f5-A6B7-C8D9-E0F1a2b3c4d5"); + t.ok (n.getUUID (s), "uuid 1 found"); + 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-E0F1a2b3c4d5", "uuid 2 -> correct"); + t.ok (n.depleted (), "depleted"); // bool getUntilEOL (std::string&); t.diag ("Nibbler::getUntilEOL");