1 | #include <vector> |
2 | #include <iostream> |
3 | #include <fstream> |
4 | #include <stack> |
5 | #include <stdio.h> |
6 | |
7 | #include "port.h" |
8 | #include "bml.h" |
9 | |
10 | bml_node::bml_node() |
11 | { |
12 | type = CHILD; |
13 | depth = -1; |
14 | } |
15 | |
16 | static inline int islf(char c) |
17 | { |
18 | return (c == '\r' || c == '\n'); |
19 | } |
20 | |
21 | static inline int isblank(char c) |
22 | { |
23 | return (c == ' ' || c == '\t'); |
24 | } |
25 | |
26 | static inline int isblankorlf(char c) |
27 | { |
28 | return (islf(c) || isblank(c)); |
29 | } |
30 | |
31 | static inline int isalnum(char c) |
32 | { |
33 | return ((c >= 'a' && c <= 'z') || |
34 | (c >= 'A' && c <= 'Z') || |
35 | (c >= '0' && c <= '9')); |
36 | } |
37 | |
38 | static inline int bml_valid(char c) |
39 | { |
40 | return (isalnum(c) || c == '-'); |
41 | } |
42 | |
43 | static std::string trim(std::string str) |
44 | { |
45 | int start; |
46 | int end; |
47 | for (start = 0; str[start] && start != (int)str.length() && isblank(str[start]); start++) {} |
48 | if (start >= (int)str.length()) |
49 | return std::string("" ); |
50 | for (end = str.length() - 1; isblankorlf(str[end]); end--) {} |
51 | return str.substr(start, end - start + 1); |
52 | } |
53 | |
54 | static std::string (std::string str) |
55 | { |
56 | int end = str.length(); |
57 | size_t = str.find("//" ); |
58 | if (comment != std::string::npos) |
59 | end = comment; |
60 | |
61 | for (int i = end - 1; i >= 0; i--) |
62 | { |
63 | if (!isblankorlf(str[i])) |
64 | { |
65 | end = i + 1; |
66 | break; |
67 | } |
68 | } |
69 | |
70 | return str.substr(0, end); |
71 | } |
72 | |
73 | static inline int bml_read_depth(std::string &data) |
74 | { |
75 | size_t depth; |
76 | for (depth = 0; isblank(data[depth]) && depth < data.length(); depth++) {} |
77 | return depth == data.length() ? -1 : depth; |
78 | } |
79 | |
80 | static void bml_parse_depth(bml_node &node, std::string &line) |
81 | { |
82 | unsigned int depth = bml_read_depth(line); |
83 | line.erase(0, depth); |
84 | node.depth = depth; |
85 | } |
86 | |
87 | static void bml_parse_name(bml_node &node, std::string &line) |
88 | { |
89 | int len; |
90 | |
91 | for (len = 0; bml_valid(line[len]); len++) {}; |
92 | |
93 | node.name = trim(line.substr(0, len)); |
94 | line.erase(0, len); |
95 | } |
96 | |
97 | static void bml_parse_data(bml_node &node, std::string &line) |
98 | { |
99 | int len; |
100 | |
101 | if (line[0] == '=' && line[1] == '\"') |
102 | { |
103 | len = 2; |
104 | while (line[len] && line[len] != '\"' && !islf(line[len])) |
105 | len++; |
106 | if (line[len] != '\"') |
107 | return; |
108 | |
109 | node.data = line.substr(2, len - 2); |
110 | line.erase(0, len + 1); |
111 | } |
112 | else if (line[0] == '=') |
113 | { |
114 | len = 1; |
115 | while (line[len] && !islf(line[len]) && line[len] != '"' && line[len] != ' ') |
116 | len++; |
117 | if (line[len] == '\"') |
118 | return; |
119 | node.data = line.substr(1, len - 1); |
120 | line.erase(0, len); |
121 | } |
122 | else if (line[0] == ':') |
123 | { |
124 | len = 1; |
125 | while (line[len] && !islf(line[len])) |
126 | len++; |
127 | node.data = trim(line.substr(1, len - 1)); |
128 | line.erase(0, len); |
129 | } |
130 | |
131 | return; |
132 | } |
133 | |
134 | static std::string bml_read_line(std::ifstream &fd) |
135 | { |
136 | std::string line; |
137 | |
138 | while (fd) |
139 | { |
140 | std::getline(fd, line); |
141 | line = trimcomments(line); |
142 | if (!line.empty()) |
143 | { |
144 | return line; |
145 | } |
146 | } |
147 | |
148 | return std::string("" ); |
149 | } |
150 | |
151 | static void bml_parse_attr(bml_node &node, std::string &line) |
152 | { |
153 | int len; |
154 | |
155 | while (line.length() > 0) |
156 | { |
157 | if (!isblank(line[0])) |
158 | return; |
159 | |
160 | while (isblank(line[0])) |
161 | line.erase(0, 1); |
162 | |
163 | bml_node n; |
164 | len = 0; |
165 | while (bml_valid(line[len])) |
166 | len++; |
167 | if (len == 0) |
168 | return; |
169 | n.name = trim(line.substr(0, len)); |
170 | line.erase(0, len); |
171 | bml_parse_data(n, line); |
172 | n.depth = node.depth + 1; |
173 | n.type = bml_node::ATTRIBUTE; |
174 | node.child.push_back(n); |
175 | } |
176 | } |
177 | |
178 | static int contains_space(const char *str) |
179 | { |
180 | for (int i = 0; str[i]; i++) |
181 | { |
182 | if (isblank(str[i])) |
183 | return 1; |
184 | } |
185 | |
186 | return 0; |
187 | } |
188 | |
189 | static void bml_print_node(bml_node &node, int depth) |
190 | { |
191 | int i; |
192 | |
193 | for (i = 0; i < depth * 2; i++) |
194 | { |
195 | printf(" " ); |
196 | } |
197 | |
198 | if (!node.name.empty()) |
199 | printf("%s" , node.name.c_str()); |
200 | |
201 | if (!node.data.empty()) |
202 | { |
203 | if (contains_space(node.data.c_str())) |
204 | printf("=\"%s\"" , node.data.c_str()); |
205 | else |
206 | printf(": %s" , node.data.c_str()); |
207 | } |
208 | for (i = 0; i < (int)node.child.size() && node.child[i].type == bml_node::ATTRIBUTE; i++) |
209 | { |
210 | if (!node.child[i].name.empty()) |
211 | { |
212 | printf(" %s" , node.child[i].name.c_str()); |
213 | if (!node.child[i].data.empty()) |
214 | { |
215 | if (contains_space(node.child[i].data.c_str())) |
216 | printf("=\"%s\"" , node.child[i].data.c_str()); |
217 | else |
218 | printf("=%s" , node.child[i].data.c_str()); |
219 | } |
220 | } |
221 | } |
222 | |
223 | if (depth >= 0) |
224 | printf("\n" ); |
225 | |
226 | for (; i < (int)node.child.size(); i++) |
227 | { |
228 | bml_print_node(node.child[i], depth + 1); |
229 | } |
230 | |
231 | if (depth == 0) |
232 | printf("\n" ); |
233 | } |
234 | |
235 | void bml_node::print() |
236 | { |
237 | bml_print_node(*this, -1); |
238 | } |
239 | |
240 | void bml_node::parse(std::ifstream &fd) |
241 | { |
242 | std::stack<bml_node *> nodestack; |
243 | nodestack.push(this); |
244 | |
245 | while (fd) |
246 | { |
247 | bml_node newnode; |
248 | std::string line = bml_read_line(fd); |
249 | if (line.empty()) |
250 | return; |
251 | |
252 | int line_depth = bml_read_depth(line); |
253 | while (line_depth <= nodestack.top()->depth && nodestack.size() > 1) |
254 | nodestack.pop(); |
255 | |
256 | bml_parse_depth(newnode, line); |
257 | bml_parse_name(newnode, line); |
258 | bml_parse_data(newnode, line); |
259 | bml_parse_attr(newnode, line); |
260 | |
261 | nodestack.top()->child.push_back(newnode); |
262 | nodestack.push(&nodestack.top()->child.back()); |
263 | } |
264 | |
265 | return; |
266 | } |
267 | |
268 | bml_node *bml_node::find_subnode(std::string name) |
269 | { |
270 | unsigned int i; |
271 | |
272 | for (i = 0; i < child.size(); i++) |
273 | { |
274 | if (name.compare(child[i].name) == 0) |
275 | return &child[i]; |
276 | } |
277 | |
278 | return NULL; |
279 | } |
280 | |
281 | bool bml_node::parse_file(std::string filename) |
282 | { |
283 | std::ifstream file(filename.c_str(), std::ios_base::binary); |
284 | |
285 | if (!file) |
286 | return false; |
287 | |
288 | parse(file); |
289 | |
290 | return true; |
291 | } |
292 | |