1 /**
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "verification/util/parser/parser.h"
17
18 #include "config_parse.h"
19
20 #include "runtime/include/mem/panda_string.h"
21
22 #include <cctype>
23 #include <vector>
24
25 namespace ark::verifier::config {
26
27 using ark::parser::Action;
28 using ark::parser::Parser;
29 using ark::verifier::config::Section;
30
31 namespace {
32
33 struct Context {
34 Section current;
35 std::vector<Section> sections;
36 };
37
38 } // namespace
39
40 using P = ark::parser::Parser<Context, const char, const char *>;
41
IsComment(const PandaString & s)42 static bool IsComment(const PandaString &s)
43 {
44 for (char const c : s) {
45 if (c == '#') {
46 return true;
47 }
48 if (isspace(c) != 0) {
49 return false;
50 }
51 }
52 return false;
53 }
54
HandleLine(Action a,Context & c,PandaString && s)55 static bool HandleLine(Action a, Context &c, PandaString &&s)
56 {
57 if (a == Action::PARSED) {
58 if (!IsComment(s)) {
59 c.current.items.push_back(std::move(s));
60 }
61 }
62 return true;
63 }
64
HandleSection(Action a,Context & c)65 static bool HandleSection(Action a, Context &c)
66 {
67 if (a == Action::START) {
68 c.sections.push_back(c.current);
69 c.current.sections.clear();
70 }
71 if (a == Action::CANCEL) {
72 c.current = c.sections.back();
73 c.sections.pop_back();
74 }
75 if (a == Action::PARSED) {
76 c.sections.back().sections.push_back(c.current);
77 c.current = c.sections.back();
78 c.sections.pop_back();
79 }
80 return true;
81 }
82
ParseConfig(const char * str,Section & cfg)83 bool ParseConfig(const char *str, Section &cfg)
84 {
85 using ark::parser::Charset;
86 using P1 = P::P;
87 using P2 = P1::P;
88 using P3 = P2::P;
89 using P4 = P3::P;
90 using P5 = P4::P;
91 using P6 = P5::P;
92
93 static const auto CM = P::P::SkipComment("#");
94 static const auto WS = ~CM >> P::OfCharset(" \t\r\n");
95 static const auto NL = ~CM >> P1::OfCharset("\r\n");
96 static const auto SP = P2::OfCharset(" \t");
97 static const auto NAME_HANDLER = [](auto a, Context &c, auto from, auto to) {
98 if (a == Action::PARSED) {
99 c.current.name = PandaString {from, to};
100 }
101 return true;
102 };
103 static const auto NAME = P3::OfCharset("abcdefghijklmnopqrstuvwxyz_") |= NAME_HANDLER;
104
105 static const auto LCURL = P4::OfString("{");
106 static const auto RCURL = P5::OfString("}");
107
108 static const auto LINE_HANDLER = [](auto a, Context &c, auto from, auto to) {
109 return HandleLine(a, c, PandaString {from, to});
110 };
111
112 static const auto LINE = P6::OfCharset(!Charset {"\r\n"}) |= LINE_HANDLER;
113
114 static const auto SECTION_END = ~SP >> RCURL >> ~SP >> NL;
115 static const auto SECTION_START = ~SP >> NAME >> ~SP >> LCURL >> ~SP >> NL;
116 static const auto ITEM = (!SECTION_END) & (~SP >> LINE >> NL);
117
118 // CC-OFFNXT(G.NAM.03) false positive
119 static const auto SECTION_HANDLER = [](auto a, Context &c) { return HandleSection(a, c); };
120
121 static P::P sectionRec;
122
123 static const auto SECTION = ~WS >> SECTION_START >> ~WS >> *sectionRec >> *ITEM >> SECTION_END >> ~WS |=
124 SECTION_HANDLER; // NOLINT
125
126 sectionRec = SECTION;
127
128 Context context;
129
130 context.current.name = "config";
131
132 if (SECTION(context, str, &str[std::strlen(str)])) { // NOLINT
133 cfg = context.current;
134 return true;
135 }
136
137 return false;
138 }
139
140 } // namespace ark::verifier::config
141