init: add Parser::AddSingleLineParser()

Add the ability to override the current section being parsed and
instead parse a line by itself if a given line starts with a specific
prefix.

Test: Boot bullhead
Change-Id: Idbbf2682b78996b41d05f3db655c8937a8c6ccda
diff --git a/init/init_parser.cpp b/init/init_parser.cpp
index 5c7af79..c8ef8d9 100644
--- a/init/init_parser.cpp
+++ b/init/init_parser.cpp
@@ -20,6 +20,7 @@
 
 #include <android-base/logging.h>
 #include <android-base/stringprintf.h>
+#include <android-base/strings.h>
 
 #include "parser.h"
 #include "util.h"
@@ -37,6 +38,10 @@
     section_parsers_[name] = std::move(parser);
 }
 
+void Parser::AddSingleLineParser(const std::string& prefix, LineCallback callback) {
+    line_callbacks_.emplace_back(prefix, callback);
+}
+
 void Parser::ParseData(const std::string& filename, const std::string& data) {
     //TODO: Use a parser with const input and remove this copy
     std::vector<char> data_copy(data.begin(), data.end());
@@ -63,6 +68,20 @@
             if (args.empty()) {
                 break;
             }
+            // If we have a line matching a prefix we recognize, call its callback and unset any
+            // current section parsers.  This is meant for /sys/ and /dev/ line entries for uevent.
+            for (const auto& [prefix, callback] : line_callbacks_) {
+                if (android::base::StartsWith(args[0], prefix.c_str())) {
+                    if (section_parser) section_parser->EndSection();
+
+                    std::string ret_err;
+                    if (!callback(std::move(args), &ret_err)) {
+                        parse_error(&state, "%s\n", ret_err.c_str());
+                    }
+                    section_parser = nullptr;
+                    break;
+                }
+            }
             if (section_parsers_.count(args[0])) {
                 if (section_parser) {
                     section_parser->EndSection();