diff --git a/src/Att.cpp b/src/Att.cpp index 29847ebf2..da68453ce 100644 --- a/src/Att.cpp +++ b/src/Att.cpp @@ -196,6 +196,12 @@ bool Att::evalMod (Att& other) return false; } +//////////////////////////////////////////////////////////////////////////////// +bool Att::match (const Att& other) +{ + return false; +} + //////////////////////////////////////////////////////////////////////////////// // name : " value " std::string Att::composeF4 () const diff --git a/src/Att.h b/src/Att.h index a1cbcf7f1..f66c066ba 100644 --- a/src/Att.h +++ b/src/Att.h @@ -44,6 +44,7 @@ public: bool parse (Nibbler&); bool validMod (const std::string&); bool evalMod (Att&); + bool match (const Att&); std::string composeF4 () const; void addMod (const std::string&); diff --git a/src/T2.cpp b/src/T2.cpp index 25d77441e..15451e704 100644 --- a/src/T2.cpp +++ b/src/T2.cpp @@ -60,7 +60,8 @@ T2& T2::operator= (const T2& other) throw std::string ("unimplemented T2::operator="); if (this != &other) { - mId = other.mId; + sequence = other.sequence; + subst = other.subst; } return *this; @@ -73,8 +74,177 @@ T2::~T2 () //////////////////////////////////////////////////////////////////////////////// // Support FF2, FF3. -void T2::legacyParse (const std::string& input) +void T2::legacyParse (const std::string& line) { + switch (determineVersion (line)) + { + // File format version 1, from 2006.11.27 - 2007.12.31 + case 1: + throw std::string ("Task no longer supports file format 1, originally used " + "between 27 November 2006 and 31 December 2007."); + break; + + // File format version 2, from 2008.1.1 - 2009.3.23 + case 2: +/* + { + if (line.length () > 46) // ^.{36} . \[\] \[\] \n + { + mUUID = line.substr (0, 36); + + mStatus = line[37] == '+' ? completed + : line[37] == 'X' ? deleted + : line[37] == 'r' ? recurring + : pending; + + size_t openTagBracket = line.find ("["); + size_t closeTagBracket = line.find ("]", openTagBracket); + if (openTagBracket != std::string::npos && + closeTagBracket != std::string::npos) + { + size_t openAttrBracket = line.find ("[", closeTagBracket); + size_t closeAttrBracket = line.find ("]", openAttrBracket); + if (openAttrBracket != std::string::npos && + closeAttrBracket != std::string::npos) + { + std::string tags = line.substr ( + openTagBracket + 1, closeTagBracket - openTagBracket - 1); + std::vector rawTags; + split (mTags, tags, ' '); + + std::string attributes = line.substr ( + openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1); + std::vector pairs; + split (pairs, attributes, ' '); + for (size_t i = 0; i < pairs.size (); ++i) + { + std::vector pair; + split (pair, pairs[i], ':'); + if (pair.size () == 2) + mAttributes[pair[0]] = pair[1]; + } + + mDescription = line.substr (closeAttrBracket + 2, std::string::npos); + } + else + throw std::string ("Missing attribute brackets"); + } + else + throw std::string ("Missing tag brackets"); + } + else + throw std::string ("Line too short"); + + mAnnotations.clear (); + } +*/ + break; + + // File format version 3, from 2009.3.23 + case 3: +/* + { + if (line.length () > 49) // ^.{36} . \[\] \[\] \[\] \n + { + mUUID = line.substr (0, 36); + + mStatus = line[37] == '+' ? completed + : line[37] == 'X' ? deleted + : line[37] == 'r' ? recurring + : pending; + + size_t openTagBracket = line.find ("["); + size_t closeTagBracket = line.find ("]", openTagBracket); + if (openTagBracket != std::string::npos && + closeTagBracket != std::string::npos) + { + size_t openAttrBracket = line.find ("[", closeTagBracket); + size_t closeAttrBracket = line.find ("]", openAttrBracket); + if (openAttrBracket != std::string::npos && + closeAttrBracket != std::string::npos) + { + size_t openAnnoBracket = line.find ("[", closeAttrBracket); + size_t closeAnnoBracket = line.find ("]", openAnnoBracket); + if (openAnnoBracket != std::string::npos && + closeAnnoBracket != std::string::npos) + { + std::string tags = line.substr ( + openTagBracket + 1, closeTagBracket - openTagBracket - 1); + std::vector rawTags; + split (mTags, tags, ' '); + + std::string attributes = line.substr ( + openAttrBracket + 1, closeAttrBracket - openAttrBracket - 1); + std::vector pairs; + split (pairs, attributes, ' '); + + for (size_t i = 0; i < pairs.size (); ++i) + { + std::vector pair; + split (pair, pairs[i], ':'); + if (pair.size () == 2) + mAttributes[pair[0]] = pair[1]; + } + + // Extract and split the annotations, which are of the form: + // 1234:"..." 5678:"..." + std::string annotations = line.substr ( + openAnnoBracket + 1, closeAnnoBracket - openAnnoBracket - 1); + pairs.clear (); + + std::string::size_type start = 0; + std::string::size_type end = 0; + do + { + end = annotations.find ('"', start); + if (end != std::string::npos) + { + end = annotations.find ('"', end + 1); + + if (start != std::string::npos && + end != std::string::npos) + { + pairs.push_back (annotations.substr (start, end - start + 1)); + start = end + 2; + } + } + } + while (start != std::string::npos && + end != std::string::npos); + + for (size_t i = 0; i < pairs.size (); ++i) + { + std::string pair = pairs[i]; + std::string::size_type colon = pair.find (":"); + if (colon != std::string::npos) + { + std::string name = pair.substr (0, colon); + std::string value = pair.substr (colon + 2, pair.length () - colon - 3); + mAnnotations[::atoi (name.c_str ())] = value; + } + } + + mDescription = line.substr (closeAnnoBracket + 2, std::string::npos); + } + else + throw std::string ("Missing annotation brackets."); + } + else + throw std::string ("Missing attribute brackets."); + } + else + throw std::string ("Missing tag brackets."); + } + else + throw std::string ("Line too short."); + } +*/ + break; + + default: + throw std::string ("Unrecognized task file format."); + break; + } } //////////////////////////////////////////////////////////////////////////////// @@ -130,3 +300,74 @@ bool T2::validate () const } //////////////////////////////////////////////////////////////////////////////// +int T2::determineVersion (const std::string& line) +{ + // Version 2 looks like: + // + // uuid status [tags] [attributes] description\n + // + // Where uuid looks like: + // + // 27755d92-c5e9-4c21-bd8e-c3dd9e6d3cf7 + // + // Scan for the hyphens in the uuid, the following space, and a valid status + // character. + if (line[8] == '-' && + line[13] == '-' && + line[18] == '-' && + line[23] == '-' && + line[36] == ' ' && + (line[37] == '-' || line[37] == '+' || line[37] == 'X' || line[37] == 'r')) + { + // Version 3 looks like: + // + // uuid status [tags] [attributes] [annotations] description\n + // + // Scan for the number of [] pairs. + std::string::size_type tagAtts = line.find ("] [", 0); + std::string::size_type attsAnno = line.find ("] [", tagAtts + 1); + std::string::size_type annoDesc = line.find ("] ", attsAnno + 1); + if (tagAtts != std::string::npos && + attsAnno != std::string::npos && + annoDesc != std::string::npos) + return 3; + else + return 2; + } + + // Version 1 looks like: + // + // [tags] [attributes] description\n + // X [tags] [attributes] description\n + // + // Scan for the first character being either the bracket or X. + else if ((line[0] == '[' && line[line.length () - 1] != ']') || + line.find ("X [") == 0) + return 1; + + // Version 4 looks like: + // + // [name:"value" ...] + // + // Scan for [, ] and :". + if (line[0] == '[' && + line[line.length () - 1] == ']' && + line.find (":\"") != std::string::npos) + return 4; + + // Version 5? + // + // Fortunately, with the hindsight that will come with version 5, the + // identifying characteristics of 1, 2, 3 and 4 may be modified such that if 5 + // has a UUID followed by a status, then there is still a way to differentiate + // between 2, 3, 4 and 5. + // + // The danger is that a version 3 binary reads and misinterprets a version 4 + // file. This is why it is a good idea to rely on an explicit version + // declaration rather than chance positioning. + + // Zero means 'no idea'. + return 0; +} + +//////////////////////////////////////////////////////////////////////////////// diff --git a/src/T2.h b/src/T2.h index 3def633b1..296afa272 100644 --- a/src/T2.h +++ b/src/T2.h @@ -51,19 +51,16 @@ public: Subst subst; // Series of helper functions. - int getId () const { return mId; } - void setId (int id) { mId = id; sequence.push_back (id); } + int id () const { return sequence.size () ? sequence[0] : 0; } + void id (int anotherId) { sequence.push_back (anotherId); } /* - std::vector getAllIds () const { return mSequence; } - void addId (int id) { if (mId == 0) mId = id; mSequence.push_back (id); } - status getStatus () const { return mStatus; } void setStatus (status s) { mStatus = s; } bool hasTag (const std::string&) const; - void getRemoveTags (std::vector&); // SPECIAL - void addRemoveTag (const std::string&); // SPECIAL + void getRemoveTags (std::vector&); // SPECIAL + void addRemoveTag (const std::string&); // SPECIAL int getTagCount () const; void getTags (std::vector&) const; void addTag (const std::string&); @@ -79,15 +76,9 @@ public: bool validate () const; private: -/* int determineVersion (const std::string&); -*/ private: -/* - status mStatus; -*/ - int mId; /* std::vector mTags; std::vector mRemoveTags;