diff options
author | Amaury Pouly <amaury.pouly@gmail.com> | 2017-01-26 15:26:10 +0100 |
---|---|---|
committer | Amaury Pouly <amaury.pouly@gmail.com> | 2017-02-04 17:18:13 +0100 |
commit | 6f0f1193e549245f3b4ac77c8875a40652286d1e (patch) | |
tree | b262e7942ca690c31946ee1dff880261e6b0d56a | |
parent | c156c5f5e57ee0ae5fc1dbba92550f80f9eaf4a8 (diff) | |
download | rockbox-6f0f1193e549245f3b4ac77c8875a40652286d1e.tar.gz rockbox-6f0f1193e549245f3b4ac77c8875a40652286d1e.zip |
regtools: add new tool list/find/describe registers
Change-Id: I2d93d24bd421e1a2ea6d27b8f7cfd17311e6d458
-rw-r--r-- | utils/regtools/Makefile | 2 | ||||
-rw-r--r-- | utils/regtools/regtool.cpp | 630 |
2 files changed, 631 insertions, 1 deletions
diff --git a/utils/regtools/Makefile b/utils/regtools/Makefile index fed5d8c8e5..647a5b42ef 100644 --- a/utils/regtools/Makefile +++ b/utils/regtools/Makefile | |||
@@ -4,7 +4,7 @@ CXX?=g++ | |||
4 | LD?=g++ | 4 | LD?=g++ |
5 | INCLUDE=-Iinclude/ | 5 | INCLUDE=-Iinclude/ |
6 | CFLAGS=-g -std=c99 -Wall $(DEFINES) $(INCLUDE) | 6 | CFLAGS=-g -std=c99 -Wall $(DEFINES) $(INCLUDE) |
7 | CXXFLAGS=-g -Wall $(DEFINES) $(INCLUDE) | 7 | CXXFLAGS=-g -std=c++11 -Wall $(DEFINES) $(INCLUDE) |
8 | LDFLAGS=-Llib -lsocdesc `xml2-config --libs` | 8 | LDFLAGS=-Llib -lsocdesc `xml2-config --libs` |
9 | SRC=$(wildcard *.c) | 9 | SRC=$(wildcard *.c) |
10 | SRCXX=$(wildcard *.cpp) | 10 | SRCXX=$(wildcard *.cpp) |
diff --git a/utils/regtools/regtool.cpp b/utils/regtools/regtool.cpp new file mode 100644 index 0000000000..2f7f04b956 --- /dev/null +++ b/utils/regtools/regtool.cpp | |||
@@ -0,0 +1,630 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2016 by Amaury Pouly | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | #include "soc_desc.hpp" | ||
22 | #include "soc_desc_v1.hpp" | ||
23 | #include <cstdio> | ||
24 | #include <cstdlib> | ||
25 | #include <map> | ||
26 | #include <set> | ||
27 | #include <cstring> | ||
28 | #include <fstream> | ||
29 | #include <sstream> | ||
30 | #include <cstring> | ||
31 | #include <dirent.h> | ||
32 | #include <getopt.h> | ||
33 | #include <regex> | ||
34 | |||
35 | using namespace soc_desc; | ||
36 | int g_verbose = 0; | ||
37 | bool g_inline = false; | ||
38 | bool g_print_zero = false; | ||
39 | bool g_regex_mode = false; | ||
40 | std::regex_constants::syntax_option_type g_regex_flags; | ||
41 | |||
42 | std::regex_constants::syntax_option_type parse_regex_mode(const std::string& mode) | ||
43 | { | ||
44 | std::regex_constants::syntax_option_type flags; | ||
45 | size_t index = 0; | ||
46 | while(index < mode.size()) | ||
47 | { | ||
48 | size_t end = mode.find(',', index); | ||
49 | if(end == std::string::npos) | ||
50 | end = mode.size(); | ||
51 | std::string opt = mode.substr(index, end - index); | ||
52 | if(opt == "icase") | ||
53 | flags |= std::regex_constants::icase; | ||
54 | else if(opt == "ECMAScript") | ||
55 | flags |= std::regex_constants::ECMAScript; | ||
56 | else if(opt == "basic") | ||
57 | flags |= std::regex_constants::basic; | ||
58 | else if(opt == "extended") | ||
59 | flags |= std::regex_constants::extended; | ||
60 | else if(opt == "awk") | ||
61 | flags |= std::regex_constants::awk; | ||
62 | else if(opt == "grep") | ||
63 | flags |= std::regex_constants::grep; | ||
64 | else if(opt == "egrep") | ||
65 | flags |= std::regex_constants::egrep; | ||
66 | else | ||
67 | { | ||
68 | fprintf(stderr, "Invalid regex option '%s'\n", opt.c_str()); | ||
69 | exit(1); | ||
70 | } | ||
71 | index = end + 1; | ||
72 | } | ||
73 | return flags; | ||
74 | } | ||
75 | |||
76 | void print_path(node_ref_t node, bool nl = true) | ||
77 | { | ||
78 | printf("%s", node.soc().get()->name.c_str()); | ||
79 | std::vector< std::string > path = node.path(); | ||
80 | for(size_t i = 0; i < path.size(); i++) | ||
81 | printf(".%s", path[i].c_str()); | ||
82 | if(nl) | ||
83 | printf("\n"); | ||
84 | } | ||
85 | |||
86 | template<typename T> | ||
87 | std::string to_str(const T& t) | ||
88 | { | ||
89 | std::ostringstream oss; | ||
90 | oss << t; | ||
91 | return oss.str(); | ||
92 | } | ||
93 | |||
94 | std::string get_path(node_inst_t inst) | ||
95 | { | ||
96 | if(!inst.is_root()) | ||
97 | { | ||
98 | std::string path = get_path(inst.parent()) + "." + inst.name(); | ||
99 | if(inst.is_indexed()) | ||
100 | path += "[" + to_str(inst.index()) + "]"; | ||
101 | return path; | ||
102 | } | ||
103 | else | ||
104 | return inst.soc().get()->name; | ||
105 | } | ||
106 | |||
107 | void print_inst(node_inst_t inst, bool addr = true, bool nl = true) | ||
108 | { | ||
109 | if(!inst.is_root()) | ||
110 | { | ||
111 | print_inst(inst.parent(), false); | ||
112 | printf(".%s", inst.name().c_str()); | ||
113 | if(inst.is_indexed()) | ||
114 | printf("[%u]", (unsigned)inst.index()); | ||
115 | } | ||
116 | else | ||
117 | printf("%s", inst.soc().get()->name.c_str()); | ||
118 | if(addr) | ||
119 | { | ||
120 | printf(" @ %#x", inst.addr()); | ||
121 | if(nl) | ||
122 | printf("\n"); | ||
123 | } | ||
124 | } | ||
125 | |||
126 | void find_insts(std::vector< node_inst_t >& list, node_inst_t inst, soc_addr_t addr) | ||
127 | { | ||
128 | if(inst.addr() == addr) | ||
129 | { | ||
130 | /* only keep matches that are registers */ | ||
131 | if(inst.node().reg().valid()) | ||
132 | list.push_back(inst); | ||
133 | } | ||
134 | std::vector< node_inst_t > children = inst.children(); | ||
135 | for(size_t i = 0; i < children.size(); i++) | ||
136 | find_insts(list, children[i], addr); | ||
137 | } | ||
138 | |||
139 | void find_insts(std::vector< node_inst_t >& insts, | ||
140 | std::vector< soc_t >& soc_list, soc_addr_t addr) | ||
141 | { | ||
142 | for(size_t i = 0; i < soc_list.size(); i++) | ||
143 | find_insts(insts, soc_ref_t(&soc_list[i]).root_inst(), addr); | ||
144 | } | ||
145 | |||
146 | const size_t NO_INDEX = (size_t)-1; | ||
147 | /* index is set to NO_INDEX if there is no index */ | ||
148 | bool parse_name(std::string& name, std::string& component, size_t& index) | ||
149 | { | ||
150 | size_t i = 0; | ||
151 | /* name must be of the form [a-zA-Z0-9_]+ */ | ||
152 | while(i < name.size() && (isalnum(name[i]) || name[i] == '_')) | ||
153 | i++; | ||
154 | if(i == 0) | ||
155 | return false; | ||
156 | component = name.substr(0, i); | ||
157 | /* must stop at the end, or on '.' or on '[' */ | ||
158 | if(name.size() == i) | ||
159 | { | ||
160 | index = NO_INDEX; | ||
161 | name = name.substr(i); | ||
162 | return true; | ||
163 | } | ||
164 | else if(name[i] == '.') | ||
165 | { | ||
166 | index = NO_INDEX; | ||
167 | name = name.substr(i + 1); | ||
168 | return true; | ||
169 | } | ||
170 | else if(name[i] == '[') | ||
171 | { | ||
172 | /* parse index */ | ||
173 | char *end; | ||
174 | index = strtoul(name.c_str() + i + 1, &end, 0); | ||
175 | /* must stop on ']'. Also strtoul is happy with an empty string, check for this */ | ||
176 | if(*end != ']' || end == name.c_str() + i + 1) | ||
177 | return false; | ||
178 | i = end + 1 - name.c_str(); | ||
179 | /* check if we have a '.' after that, or the end */ | ||
180 | if(i < name.size() && name[i] != '.') | ||
181 | return false; | ||
182 | name = name.substr(i + 1); | ||
183 | return true; | ||
184 | } | ||
185 | else | ||
186 | return false; | ||
187 | } | ||
188 | |||
189 | int find_insts(std::vector< node_inst_t >& matches, node_inst_t inst, std::regex& regex) | ||
190 | { | ||
191 | /* only keep matches that are registers */ | ||
192 | if(inst.node().reg().valid()) | ||
193 | { | ||
194 | std::string path = get_path(inst); | ||
195 | if(regex_match(path, regex)) | ||
196 | matches.push_back(inst); | ||
197 | } | ||
198 | std::vector< node_inst_t > children = inst.children(); | ||
199 | for(size_t i = 0; i < children.size(); i++) | ||
200 | find_insts(matches, children[i], regex); | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | int find_insts_regex(std::vector< node_inst_t >& matches, std::vector< soc_t >& soc_list, std::string str) | ||
205 | { | ||
206 | auto flags = g_regex_flags | std::regex_constants::optimize; /* we will match a lot */ | ||
207 | /* any error during construction or mayching will throw exception, and print | ||
208 | * an error message so don't catch them */ | ||
209 | std::regex regex(str, flags); | ||
210 | for(size_t i = 0; i < soc_list.size(); i++) | ||
211 | if(find_insts(matches, soc_ref_t(&soc_list[i]).root_inst(), regex) != 0) | ||
212 | return 1; | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | int find_insts(std::vector< node_inst_t >& matches, node_inst_t inst, std::string name) | ||
217 | { | ||
218 | if(name.empty()) | ||
219 | { | ||
220 | if(inst.node().reg().valid()) | ||
221 | matches.push_back(inst); | ||
222 | return 0; | ||
223 | } | ||
224 | std::string component; | ||
225 | size_t index; | ||
226 | bool ok = parse_name(name, component, index); | ||
227 | if(!ok) | ||
228 | { | ||
229 | fprintf(stderr, "invalid name '%s'\n", name.c_str()); | ||
230 | return 1; | ||
231 | } | ||
232 | if(index == NO_INDEX) | ||
233 | inst = inst.child(component); | ||
234 | else | ||
235 | inst = inst.child(component, index); | ||
236 | if(inst.valid()) | ||
237 | return find_insts(matches, inst, name); | ||
238 | else | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | int find_insts(std::vector< node_inst_t >& matches, soc_t& soc, std::string name) | ||
243 | { | ||
244 | return find_insts(matches, soc_ref_t(&soc).root_inst(), name); | ||
245 | } | ||
246 | |||
247 | int find_insts(std::vector< node_inst_t >& matches, std::vector< soc_t >& soc_list, | ||
248 | std::string name) | ||
249 | { | ||
250 | /* regex mode is special */ | ||
251 | if(g_regex_mode) | ||
252 | return find_insts_regex(matches, soc_list, name); | ||
253 | /* if name is an integer, parse it */ | ||
254 | char *end; | ||
255 | unsigned long addr = strtoul(name.c_str(), &end, 0); | ||
256 | if(*end == 0) | ||
257 | { | ||
258 | find_insts(matches, soc_list, addr); | ||
259 | return 0; | ||
260 | } | ||
261 | /* else assume it's a name */ | ||
262 | std::string name_copy = name; | ||
263 | std::string component; | ||
264 | size_t index; | ||
265 | bool ok = parse_name(name_copy, component, index); | ||
266 | if(!ok) | ||
267 | { | ||
268 | fprintf(stderr, "invalid name '%s'\n", name.c_str()); | ||
269 | return 1; | ||
270 | } | ||
271 | /* a soc cannot be indexed */ | ||
272 | for(size_t i = 0; i < soc_list.size(); i++) | ||
273 | { | ||
274 | int ret; | ||
275 | if(index == NO_INDEX && soc_list[i].name == component) | ||
276 | ret = find_insts(matches, soc_list[i], name_copy); | ||
277 | else | ||
278 | ret = find_insts(matches, soc_list[i], name); | ||
279 | if(ret != 0) | ||
280 | return ret; | ||
281 | } | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | void do_describe(node_inst_t inst, soc_word_t *decode_val) | ||
286 | { | ||
287 | if(decode_val) | ||
288 | printf(" = %#lx", (unsigned long)*decode_val); | ||
289 | if(g_inline) | ||
290 | printf(" {"); | ||
291 | else | ||
292 | printf("\n"); | ||
293 | std::vector< field_ref_t > fields = inst.node().reg().fields(); | ||
294 | bool first = true; | ||
295 | soc_word_t mask = 0; /* mask of all decoded bits */ | ||
296 | /* special index fields.size() means "undecoded bits" */ | ||
297 | for(size_t i = 0; i <= fields.size(); i++) | ||
298 | { | ||
299 | unsigned long val = 0; | ||
300 | bool dont_print = false; | ||
301 | field_t f; | ||
302 | if(i == fields.size()) | ||
303 | { | ||
304 | /* create fake field */ | ||
305 | f.name = "undecoded bits"; | ||
306 | f.pos = 0; | ||
307 | f.width = inst.node().reg().get()->width; | ||
308 | val = decode_val ? *decode_val & ~mask : 0; | ||
309 | /* only print if decoding and something was left */ | ||
310 | dont_print = (val == 0); | ||
311 | } | ||
312 | else | ||
313 | { | ||
314 | f = *fields[i].get(); | ||
315 | val = decode_val ? f.extract(*decode_val) : 0; | ||
316 | /* don't print zero fields unless asked */ | ||
317 | dont_print = decode_val && !g_print_zero && val == 0; | ||
318 | } | ||
319 | if(dont_print) | ||
320 | continue; | ||
321 | if(g_inline) | ||
322 | printf("%s", first ? " " : ", "); | ||
323 | else | ||
324 | printf(" "); | ||
325 | printf("%s", f.name.c_str()); | ||
326 | first = false; | ||
327 | if(f.width == 1) | ||
328 | printf("[%zu]", f.pos); | ||
329 | else | ||
330 | printf("[%zu:%zu]", f.pos + f.width - 1, f.pos); | ||
331 | /* decode if needed */ | ||
332 | if(decode_val) | ||
333 | { | ||
334 | /* track what we decoded */ | ||
335 | mask |= ~f.bitmask(); | ||
336 | printf(" = %#lx", val); | ||
337 | } | ||
338 | /* newline if need */ | ||
339 | if(!g_inline) | ||
340 | printf("\n"); | ||
341 | } | ||
342 | if(g_inline) | ||
343 | printf(" }\n"); | ||
344 | } | ||
345 | |||
346 | int do_find(std::vector< soc_t >& soc_list, int argc, char **argv, bool describe, | ||
347 | soc_word_t *decode_val = nullptr) | ||
348 | { | ||
349 | if(argc != 1) | ||
350 | { | ||
351 | fprintf(stderr, "action 'find' takes on argument: the name or address of a register\n"); | ||
352 | return 1; | ||
353 | } | ||
354 | std::vector< node_inst_t > matches; | ||
355 | int ret = find_insts(matches, soc_list, argv[0]); | ||
356 | if(ret != 0) | ||
357 | return 0; | ||
358 | /* print matches */ | ||
359 | if(matches.size() > 0) | ||
360 | { | ||
361 | for(size_t i = 0; i < matches.size(); i++) | ||
362 | { | ||
363 | print_inst(matches[i], true, !describe); | ||
364 | if(describe) | ||
365 | do_describe(matches[i], decode_val); | ||
366 | } | ||
367 | return 0; | ||
368 | } | ||
369 | else | ||
370 | { | ||
371 | fprintf(stderr, "No matches\n"); | ||
372 | return 1; | ||
373 | } | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | int do_decode(std::vector< soc_t >& soc_list, int argc, char **argv) | ||
378 | { | ||
379 | if(argc != 2) | ||
380 | { | ||
381 | fprintf(stderr, "action 'decode' takes two arguments: the register and the value\n"); | ||
382 | return 1; | ||
383 | } | ||
384 | char *end; | ||
385 | soc_word_t val = strtoul(argv[1], &end, 0); | ||
386 | if(*end) | ||
387 | { | ||
388 | fprintf(stderr, "invalid value '%s'\n", argv[1]); | ||
389 | return 1; | ||
390 | } | ||
391 | return do_find(soc_list, argc - 1, argv, true, &val); | ||
392 | } | ||
393 | |||
394 | void print_context(const error_context_t& ctx) | ||
395 | { | ||
396 | for(size_t j = 0; j < ctx.count(); j++) | ||
397 | { | ||
398 | err_t e = ctx.get(j); | ||
399 | switch(e.level()) | ||
400 | { | ||
401 | case err_t::INFO: printf("[INFO]"); break; | ||
402 | case err_t::WARNING: printf("[WARN]"); break; | ||
403 | case err_t::FATAL: printf("[FATAL]"); break; | ||
404 | default: printf("[UNK]"); break; | ||
405 | } | ||
406 | if(e.location().size() != 0) | ||
407 | printf(" %s:", e.location().c_str()); | ||
408 | printf(" %s\n", e.message().c_str()); | ||
409 | } | ||
410 | } | ||
411 | |||
412 | int usage() | ||
413 | { | ||
414 | printf("usage: regtool [options] <action> [args]\n"); | ||
415 | printf("options:\n"); | ||
416 | printf(" -h Display this help\n"); | ||
417 | printf(" -f <regfile> Load a register file\n"); | ||
418 | printf(" -d <regdir> Specify a directory where to look for register files\n"); | ||
419 | printf(" -v Increase verbosity level\n"); | ||
420 | printf(" -s <soc list> Limit search to a one or more socs (comma separated)\n"); | ||
421 | printf(" -i Describe/decode in one line\n"); | ||
422 | printf(" -z Print fields even when the value is zero\n"); | ||
423 | printf(" -r <mode> Enable regex mode\n"); | ||
424 | printf("\n"); | ||
425 | printf("actions:\n"); | ||
426 | printf(" find <addr> Find all registers that match this address\n"); | ||
427 | printf(" find <name> Find the registers that match this name\n"); | ||
428 | printf(" describe <reg> Describe a register (either found by address or name)\n"); | ||
429 | printf(" decode <reg> <val> Decode a register value\n"); | ||
430 | printf("By default, regtool will look for register files in desc/, but if\n"); | ||
431 | printf("any file or directory is specified, regtool will ignore the default directory\n"); | ||
432 | printf("Adresses can be in decimal or hexadecimal (using 0x prefix).\n"); | ||
433 | printf("Names can be fully qualified with a soc name or left ambiguous.\n"); | ||
434 | printf(" <reg> ::= <soc>.<regpath> | <regpath>\n"); | ||
435 | printf(" <regpath> ::= (<regcomp>.)*<regcomp>\n"); | ||
436 | printf(" <regcomp> ::= <name> | <name>[<index>]\n"); | ||
437 | printf("In regex mode, all commands expect a regular expression that is matched\n"); | ||
438 | printf("against the full path (<soc>.<regpath>) of every register. The regex must\n"); | ||
439 | printf("follow the C++11 standard and accepts the following, comma-separated options:\n"); | ||
440 | printf(" icase Case insensitive match\n"); | ||
441 | printf(" ECMAScript Use ECMAScript grammar\n"); | ||
442 | printf(" basic Use basic POSIX grammar\n"); | ||
443 | printf(" extended Use extended basic grammar\n"); | ||
444 | printf(" awk Use awk grammar\n"); | ||
445 | printf(" grep Use grep grammar\n"); | ||
446 | printf(" egrep Use egrep grammar\n"); | ||
447 | printf("Examples:\n"); | ||
448 | printf(" regtool -d desc/ -s stmp3700,imx233 find 0x8001c310\n"); | ||
449 | printf(" regtool find DIGCTL.CHIPID\n"); | ||
450 | printf(" regtool describe imx233.DIGCTL.CHIPID\n"); | ||
451 | printf(" regtool -f desc/regs-stmp3780.xml decode 0x8001c310 0x37800001\n"); | ||
452 | printf(" regtool -r awk find 'imx233\\.LCDIF\\..*'\n"); | ||
453 | return 1; | ||
454 | } | ||
455 | |||
456 | std::string my_dirname(const std::string& filename) | ||
457 | { | ||
458 | size_t idx = filename.find_last_of("/\\"); | ||
459 | if(idx == std::string::npos) | ||
460 | return filename; | ||
461 | else | ||
462 | return filename.substr(0, idx); | ||
463 | } | ||
464 | |||
465 | /* warn controls whether we warn about error at lowest verbosity: we warn | ||
466 | * for files explicitely loaded but not the one listed in directories */ | ||
467 | bool load_file(std::vector< soc_t >& soc_list, const std::string& file, bool user_load) | ||
468 | { | ||
469 | if(g_verbose >= 2) | ||
470 | fprintf(stderr, "Loading file '%s'...\n", file.c_str()); | ||
471 | error_context_t ctx; | ||
472 | soc_t s; | ||
473 | bool ret = parse_xml(file.c_str(), s, ctx); | ||
474 | if(g_verbose >= 1 || user_load) | ||
475 | { | ||
476 | if(ctx.count() != 0) | ||
477 | fprintf(stderr, "In file %s:\n", file.c_str()); | ||
478 | print_context(ctx); | ||
479 | } | ||
480 | if(!ret) | ||
481 | { | ||
482 | if(g_verbose >= 1 || user_load) | ||
483 | fprintf(stderr, "Cannot parse file '%s'\n", file.c_str()); | ||
484 | return !user_load; /* error only if user loaded */ | ||
485 | } | ||
486 | soc_list.push_back(s); | ||
487 | return true; | ||
488 | } | ||
489 | |||
490 | bool load_dir(std::vector< soc_t >& soc_list, const std::string& dirname, bool user_load) | ||
491 | { | ||
492 | if(g_verbose >= 2) | ||
493 | fprintf(stderr, "Loading directory '%s'...\n", dirname.c_str()); | ||
494 | DIR *dir = opendir(dirname.c_str()); | ||
495 | if(dir == NULL) | ||
496 | { | ||
497 | if(g_verbose >= 1 || user_load) | ||
498 | fprintf(stderr, "Warning: cannot open directory '%s'\n", dirname.c_str()); | ||
499 | return !user_load; /* error only if user loaded */ | ||
500 | } | ||
501 | struct dirent *ent; | ||
502 | while((ent = readdir(dir))) | ||
503 | { | ||
504 | std::string name(ent->d_name); | ||
505 | /* only list *.xml */ | ||
506 | if(name.size() < 4 || name.substr(name.size() - 4) != ".xml") | ||
507 | continue; | ||
508 | if(!load_file(soc_list, dirname + "/" + name, false)) | ||
509 | { | ||
510 | closedir(dir); | ||
511 | return false; | ||
512 | } | ||
513 | } | ||
514 | closedir(dir); | ||
515 | return true; | ||
516 | } | ||
517 | |||
518 | void add_socs_to_list(std::set< std::string >& soc_list, const std::string& list) | ||
519 | { | ||
520 | size_t idx = 0; | ||
521 | while(idx < list.size()) | ||
522 | { | ||
523 | size_t next = list.find(',', idx); | ||
524 | if(next == std::string::npos) | ||
525 | next = list.size(); | ||
526 | soc_list.insert(list.substr(idx, next - idx)); | ||
527 | idx = next + 1; | ||
528 | } | ||
529 | } | ||
530 | |||
531 | int main(int argc, char **argv) | ||
532 | { | ||
533 | std::vector< std::string > g_soc_dir; | ||
534 | std::vector< std::string > g_soc_files; | ||
535 | std::vector< soc_t > g_soc_list; | ||
536 | std::set< std::string> g_allowed_soc; | ||
537 | |||
538 | if(argc <= 1) | ||
539 | return usage(); | ||
540 | while(1) | ||
541 | { | ||
542 | static struct option long_options[] = | ||
543 | { | ||
544 | {"help", no_argument, 0, 'h'}, | ||
545 | {0, 0, 0, 0} | ||
546 | }; | ||
547 | |||
548 | int c = getopt_long(argc, argv, "hf:d:vs:izr:", long_options, NULL); | ||
549 | if(c == -1) | ||
550 | break; | ||
551 | switch(c) | ||
552 | { | ||
553 | case -1: | ||
554 | break; | ||
555 | case 'h': | ||
556 | return usage(); | ||
557 | case 's': | ||
558 | add_socs_to_list(g_allowed_soc, optarg); | ||
559 | break; | ||
560 | case 'd': | ||
561 | g_soc_dir.push_back(std::string(optarg)); | ||
562 | break; | ||
563 | case 'f': | ||
564 | g_soc_files.push_back(std::string(optarg)); | ||
565 | break; | ||
566 | case 'v': | ||
567 | g_verbose++; | ||
568 | break; | ||
569 | case 'i': | ||
570 | g_inline = true; | ||
571 | break; | ||
572 | case 'z': | ||
573 | g_print_zero = true; | ||
574 | break; | ||
575 | case 'r': | ||
576 | g_regex_mode = true; | ||
577 | g_regex_flags = parse_regex_mode(optarg); | ||
578 | break; | ||
579 | default: | ||
580 | abort(); | ||
581 | } | ||
582 | } | ||
583 | if(argc == optind) | ||
584 | { | ||
585 | fprintf(stderr, "You need at least one action\n"); | ||
586 | return 2; | ||
587 | } | ||
588 | /* if no file or directory, add default */ | ||
589 | if(g_soc_files.empty() && g_soc_dir.empty()) | ||
590 | load_dir(g_soc_list, my_dirname(argv[0]) + "/desc", false); | ||
591 | /* load directories */ | ||
592 | for(size_t i = 0; i < g_soc_dir.size(); i++) | ||
593 | load_dir(g_soc_list, g_soc_dir[i], true); | ||
594 | /* load files */ | ||
595 | for(size_t i = 0; i < g_soc_files.size(); i++) | ||
596 | load_file(g_soc_list, g_soc_files[i], true); | ||
597 | /* filter soc list */ | ||
598 | if(g_allowed_soc.size() > 0) | ||
599 | { | ||
600 | for(size_t i = 0; i < g_soc_list.size(); i++) | ||
601 | { | ||
602 | if(g_allowed_soc.find(g_soc_list[i].name) == g_allowed_soc.end()) | ||
603 | { | ||
604 | std::swap(g_soc_list[i], g_soc_list.back()); | ||
605 | g_soc_list.pop_back(); | ||
606 | i--; | ||
607 | } | ||
608 | } | ||
609 | } | ||
610 | /* print */ | ||
611 | if(g_verbose >= 1) | ||
612 | { | ||
613 | fprintf(stderr, "Available socs after filtering:"); | ||
614 | for(size_t i = 0; i < g_soc_list.size(); i++) | ||
615 | fprintf(stderr, " %s", g_soc_list[i].name.c_str()); | ||
616 | fprintf(stderr, "\n"); | ||
617 | } | ||
618 | |||
619 | std::string action = argv[optind]; | ||
620 | argc -= optind + 1; | ||
621 | argv += optind + 1; | ||
622 | if(action == "find") | ||
623 | return do_find(g_soc_list, argc, argv, false); | ||
624 | if(action == "describe") | ||
625 | return do_find(g_soc_list, argc, argv, true); | ||
626 | if(action == "decode") | ||
627 | return do_decode(g_soc_list, argc, argv); | ||
628 | fprintf(stderr, "unknown action '%s'\n", action.c_str()); | ||
629 | return 1; | ||
630 | } | ||