/////////////////////////////////////////////////////////////////////////// Attempt an FF4 parse. Note that FF1, FF2, FF3, and JSON are no longer supported. start --> [ --> Att --> ] --> end ^ | +-------+
| 65 | // +-------+ |
| 66 | // |
| 67 | std::map<std::string, std::string> TF2::load_task(const std::string& input) { |
| 68 | std::map<std::string, std::string> data; |
| 69 | |
| 70 | // File format version 4, from 2009-5-16 - now, v1.7.1+ |
| 71 | // This is the parse format tried first, because it is most used. |
| 72 | data.clear(); |
| 73 | |
| 74 | if (input[0] == '[') { |
| 75 | // Not using Pig to parse here (which would be idiomatic), because we |
| 76 | // don't need to differentiate betwen utf-8 and normal characters. |
| 77 | // Pig's scanning the string can be expensive. |
| 78 | auto ending_bracket = input.find_last_of(']'); |
| 79 | if (ending_bracket != std::string::npos) { |
| 80 | std::string line = input.substr(1, ending_bracket); |
| 81 | |
| 82 | if (line.length() == 0) throw std::string("Empty record in input."); |
| 83 | |
| 84 | Pig attLine(line); |
| 85 | std::string name; |
| 86 | std::string value; |
| 87 | while (!attLine.eos()) { |
| 88 | if (attLine.getUntilAscii(':', name) && attLine.skip(':') && |
| 89 | attLine.getQuoted('"', value)) { |
| 90 | #ifdef PRODUCT_TASKWARRIOR |
| 91 | legacyAttributeMap(name); |
| 92 | #endif |
| 93 | |
| 94 | data[name] = decode(json::decode(value)); |
| 95 | } |
| 96 | |
| 97 | attLine.skip(' '); |
| 98 | } |
| 99 | |
| 100 | std::string remainder; |
| 101 | attLine.getRemainder(remainder); |
| 102 | if (remainder.length()) throw std::string("Unrecognized characters at end of line."); |
| 103 | } |
| 104 | } else { |
| 105 | throw std::string("Record not recognized as format 4."); |
| 106 | } |
| 107 | |
| 108 | // for compatibility, include all tags in `tags` as `tag_..` attributes |
| 109 | if (data.find("tags") != data.end()) { |
| 110 | for (auto& tag : split(data["tags"], ',')) { |
| 111 | data[Task::tag2Attr(tag)] = "x"; |
| 112 | } |
| 113 | } |
| 114 | |
| 115 | // same for `depends` / `dep_..` |
| 116 | if (data.find("depends") != data.end()) { |
| 117 | for (auto& dep : split(data["depends"], ',')) { |
| 118 | data[Task::dep2Attr(dep)] = "x"; |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | return data; |
| 123 | } |
| 124 |
nothing calls this directly
no test coverage detected