blob: 44cbf07eecfa06af0b24b5865e7e7a8af4f47c27 [file] [log] [blame]
Yifan Hong587ca002017-07-05 16:02:03 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "KernelConfigParser.h"
18
19#include <regex>
20
Yifan Hongc1889722017-07-07 16:19:52 -070021#define KEY "(CONFIG[\\w_]+)"
22#define COMMENT "(?:#.*)"
23
24static const std::regex sKeyValuePattern("^\\s*" KEY "\\s*=\\s*([^#]+)" COMMENT "?$");
25static const std::regex sNotSetPattern("^\\s*#\\s*" KEY " is not set\\s*$");
26static const std::regex sCommentPattern("^\\s*" COMMENT "$");
27
Yifan Hong587ca002017-07-05 16:02:03 -070028namespace android {
29namespace vintf {
30
31KernelConfigParser::KernelConfigParser(bool processComments) : mProcessComments(processComments) {}
32
33status_t KernelConfigParser::finish() {
34 return process("\n", 1 /* sizeof "\n" */);
35}
36
Yifan Hongae53a0e2017-07-07 15:19:06 -070037std::stringbuf* KernelConfigParser::error() const {
38 return mError.rdbuf();
Yifan Hong587ca002017-07-05 16:02:03 -070039}
40
41std::map<std::string, std::string>& KernelConfigParser::configs() {
42 return mConfigs;
43}
44
45const std::map<std::string, std::string>& KernelConfigParser::configs() const {
46 return mConfigs;
47}
48
Yifan Hongc1889722017-07-07 16:19:52 -070049// trim spaces between value and #, value and end of line
50std::string trimTrailingSpaces(const std::string& s) {
51 auto r = s.rbegin();
52 for (; r != s.rend() && std::isspace(*r); ++r)
53 ;
54 return std::string{s.begin(), r.base()};
55}
56
Yifan Hong587ca002017-07-05 16:02:03 -070057status_t KernelConfigParser::processRemaining() {
Yifan Hong587ca002017-07-05 16:02:03 -070058
59 if (mRemaining.empty()) {
60 return OK;
61 }
62
Yifan Hongc1889722017-07-07 16:19:52 -070063 std::smatch match;
64 if (std::regex_match(mRemaining, match, sKeyValuePattern)) {
65 if (mConfigs.emplace(match[1], trimTrailingSpaces(match[2])).second) {
Yifan Hong587ca002017-07-05 16:02:03 -070066 return OK;
67 }
Yifan Hongc1889722017-07-07 16:19:52 -070068 mError << "Duplicated key in configs: " << match[1] << "\n";
69 return UNKNOWN_ERROR;
70 }
Yifan Hong587ca002017-07-05 16:02:03 -070071
Yifan Hongc1889722017-07-07 16:19:52 -070072 if (mProcessComments && std::regex_match(mRemaining, match, sNotSetPattern)) {
73 if (mConfigs.emplace(match[1], "n").second) {
74 return OK;
75 }
76 mError << "Key " << match[1] << " is set but commented as not set"
77 << "\n";
78 return UNKNOWN_ERROR;
79 }
80
81 if (std::regex_match(mRemaining, match, sCommentPattern)) {
Yifan Hong587ca002017-07-05 16:02:03 -070082 return OK;
83 }
84
Yifan Hongc1889722017-07-07 16:19:52 -070085 mError << "Unrecognized line in configs: " << mRemaining << "\n";
86 return UNKNOWN_ERROR;
Yifan Hong587ca002017-07-05 16:02:03 -070087}
88
89status_t KernelConfigParser::process(const char* buf, size_t len) {
90 const char* begin = buf;
91 const char* end = buf;
92 const char* stop = buf + len;
93 status_t err = OK;
94 while (end < stop) {
95 if (*end == '\n') {
96 mRemaining.insert(mRemaining.size(), begin, end - begin);
97 status_t newErr = processRemaining();
98 if (newErr != OK && err == OK) {
99 err = newErr;
100 // but continue to get more
101 }
102 mRemaining.clear();
103 begin = end + 1;
104 }
105 end++;
106 }
107 mRemaining.insert(mRemaining.size(), begin, end - begin);
108 return err;
109}
110
111} // namespace vintf
112} // namespace android