Add KernelConfigParser
KernelConfigParser is a helper class to parse text like follows:
# CONFIG_FOO is not set
CONFIG_BAR=y
CONFIG_BAZ=1
It is used in parsing android-base.cfg and /proc/config.gz.
Test: libvintf_test
Test: device boots
Bug: 38324908
Change-Id: Ic2044a9e8580538fb5bdac0df278b2a65c5b6341
diff --git a/KernelConfigParser.cpp b/KernelConfigParser.cpp
new file mode 100644
index 0000000..e657a33
--- /dev/null
+++ b/KernelConfigParser.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "KernelConfigParser.h"
+
+#include <regex>
+
+namespace android {
+namespace vintf {
+
+KernelConfigParser::KernelConfigParser(bool processComments) : mProcessComments(processComments) {}
+
+status_t KernelConfigParser::finish() {
+ return process("\n", 1 /* sizeof "\n" */);
+}
+
+const std::stringstream& KernelConfigParser::error() const {
+ return mError;
+}
+
+std::map<std::string, std::string>& KernelConfigParser::configs() {
+ return mConfigs;
+}
+
+const std::map<std::string, std::string>& KernelConfigParser::configs() const {
+ return mConfigs;
+}
+
+status_t KernelConfigParser::processRemaining() {
+ static std::regex sCommentPattern("^# (CONFIG[\\w_]+) is not set$");
+
+ if (mRemaining.empty()) {
+ return OK;
+ }
+
+ if (mRemaining[0] == '#') {
+ if (!mProcessComments) {
+ return OK;
+ }
+ std::smatch sm;
+ if (!std::regex_match(mRemaining, sm, sCommentPattern)) {
+ return OK; // ignore this comment;
+ }
+ if (!mConfigs.emplace(sm[1], "n").second) {
+ mError << "Key " << sm[1] << " is set but commented as not set"
+ << "\n";
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+ }
+
+ size_t equalPos = mRemaining.find('=');
+ if (equalPos == std::string::npos) {
+ mError << "Unrecognized line in configs: " << mRemaining << "\n";
+ return UNKNOWN_ERROR;
+ }
+ std::string key = mRemaining.substr(0, equalPos);
+ std::string value = mRemaining.substr(equalPos + 1);
+ if (!mConfigs.emplace(std::move(key), std::move(value)).second) {
+ mError << "Duplicated key in configs: " << mRemaining.substr(0, equalPos) << "\n";
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
+status_t KernelConfigParser::process(const char* buf, size_t len) {
+ const char* begin = buf;
+ const char* end = buf;
+ const char* stop = buf + len;
+ status_t err = OK;
+ while (end < stop) {
+ if (*end == '\n') {
+ mRemaining.insert(mRemaining.size(), begin, end - begin);
+ status_t newErr = processRemaining();
+ if (newErr != OK && err == OK) {
+ err = newErr;
+ // but continue to get more
+ }
+ mRemaining.clear();
+ begin = end + 1;
+ }
+ end++;
+ }
+ mRemaining.insert(mRemaining.size(), begin, end - begin);
+ return err;
+}
+
+} // namespace vintf
+} // namespace android