Complete definition for CompatibilityMatrix

* Add KernelConfigTypedValue to CompatibilityMatrix
  to support KV pair in kernel information. config items
  in /proc/config.gz are more than just a string; they have
  the format:
    CONFIG_FOO=y
    CONFIG_BAR=""
    CONFIG_BAZ=0x99
  etc. Compatibility matrix needs to match the value part
  as well.

* Added minlts to each kernel entry. This allows
  KernelInfo::checkCompatibility to check if the current
  LTS version can support the framework.

Test: libvintf_test

Change-Id: I859829dee8fdee0d856c33c1f5836d8c9c94099a
diff --git a/parse_string.cpp b/parse_string.cpp
index d0e655b..abeeb06 100644
--- a/parse_string.cpp
+++ b/parse_string.cpp
@@ -103,8 +103,93 @@
     return parseEnum(s, tr, gTransportStrings);
 }
 
-std::ostream &operator<<(std::ostream &os, Transport il) {
-    return os << gTransportStrings.at(static_cast<size_t>(il));
+std::ostream &operator<<(std::ostream &os, Transport tr) {
+    return os << gTransportStrings.at(static_cast<size_t>(tr));
+}
+
+bool parse(const std::string &s, KernelConfigType *kc) {
+    return parseEnum(s, kc, gKernelConfigTypeStrings);
+}
+
+std::ostream &operator<<(std::ostream &os, KernelConfigType kc) {
+    return os << gKernelConfigTypeStrings.at(static_cast<size_t>(kc));
+}
+
+bool parse(const std::string &s, Tristate *kc) {
+    return parseEnum(s, kc, gTristateStrings);
+}
+
+std::ostream &operator<<(std::ostream &os, Tristate kc) {
+    return os << gTristateStrings.at(static_cast<size_t>(kc));
+}
+
+std::ostream &operator<<(std::ostream &os, const KernelConfigTypedValue &kctv) {
+    switch (kctv.mType) {
+        case KernelConfigType::STRING:
+            return os << kctv.mStringValue;
+        case KernelConfigType::INTEGER:
+            return os << to_string(kctv.mIntegerValue);
+        case KernelConfigType::RANGE:
+            return os << to_string(kctv.mRangeValue.first) << "-"
+                      << to_string(kctv.mRangeValue.second);
+        case KernelConfigType::TRISTATE:
+            return os << to_string(kctv.mTristateValue);
+    }
+}
+
+// Notice that strtoull is used even though KernelConfigIntValue is signed int64_t,
+// because strtoull can accept negative values as well.
+// Notice that according to man strtoul, strtoull can actually accept
+// -2^64 + 1 to 2^64 - 1, with the 65th bit truncated.
+// ParseInt / ParseUint are not used because they do not handle signed hex very well.
+template <typename T>
+bool parseKernelConfigIntHelper(const std::string &s, T *i) {
+    char *end;
+    errno = 0;
+    unsigned long long int ulli = strtoull(s.c_str(), &end, 0 /* base */);
+    // It is implementation defined that what value will be returned by strtoull
+    // in the error case, so we are checking errno directly here.
+    if (errno == 0 && s.c_str() != end && *end == '\0') {
+        *i = static_cast<T>(ulli);
+        return true;
+    }
+    return false;
+}
+
+bool parseKernelConfigInt(const std::string &s, int64_t *i) {
+    return parseKernelConfigIntHelper(s, i);
+}
+
+bool parseKernelConfigInt(const std::string &s, uint64_t *i) {
+    return parseKernelConfigIntHelper(s, i);
+}
+
+bool parseRange(const std::string &s, KernelConfigRangeValue *range) {
+    auto pos = s.find('-');
+    if (pos == std::string::npos) {
+        return false;
+    }
+    return parseKernelConfigInt(s.substr(0, pos),  &range->first)
+        && parseKernelConfigInt(s.substr(pos + 1), &range->second);
+}
+
+bool parse(const std::string &s, KernelConfigKey *key) {
+    *key = s;
+    return true;
+}
+
+bool parseKernelConfigValue(const std::string &s, KernelConfigTypedValue *kctv) {
+    switch (kctv->mType) {
+        case KernelConfigType::STRING:
+            kctv->mStringValue = s;
+            return true;
+        case KernelConfigType::INTEGER:
+            return parseKernelConfigInt(s, &kctv->mIntegerValue);
+        case KernelConfigType::RANGE:
+            return parseRange(s, &kctv->mRangeValue);
+        case KernelConfigType::TRISTATE:
+            return parse(s, &kctv->mTristateValue);
+    }
 }
 
 bool parse(const std::string &s, Version *ver) {
@@ -155,6 +240,29 @@
     return os << vr.minVer() << "-" << vr.maxMinor;
 }
 
+bool parse(const std::string &s, KernelVersion *kernelVersion) {
+    std::vector<std::string> v = SplitString(s, '.');
+    if (v.size() != 3) {
+        return false;
+    }
+    size_t version, major, minor;
+    if (!ParseUint(v[0], &version)) {
+        return false;
+    }
+    if (!ParseUint(v[1], &major)) {
+        return false;
+    }
+    if (!ParseUint(v[2], &minor)) {
+        return false;
+    }
+    *kernelVersion = KernelVersion(version, major, minor);
+    return true;
+}
+
+std::ostream &operator<<(std::ostream &os, const KernelVersion &ver) {
+    return os << ver.version << "." << ver.majorRev << "." << ver.minorRev;
+}
+
 bool parse(const std::string &s, ManifestHal *hal) {
     std::vector<std::string> v = SplitString(s, '/');
     if (v.size() != 5) {
@@ -212,14 +320,6 @@
               << (req.optional ? kOptional : kRequired);
 }
 
-bool parse(const std::string &s, KernelConfig *kc) {
-    if (s.find(kConfigPrefix) != 0) {
-        return false;
-    }
-    *kc = s;
-    return true;
-}
-
 std::string dump(const VendorManifest &vm) {
     std::ostringstream oss;
     bool first = true;