Line data Source code
1 : /**
2 : * @file
3 : *
4 : * @brief Tests for the Backend parser class
5 : *
6 : * @copyright BSD License (see LICENSE.md or https://www.libelektra.org)
7 : *
8 : */
9 :
10 : #include <backendparser.hpp>
11 :
12 : #include <functional>
13 :
14 : #include <string>
15 :
16 : #include <keyset.hpp>
17 :
18 : #include <toolexcept.hpp>
19 :
20 :
21 : namespace kdb
22 : {
23 :
24 : namespace tools
25 : {
26 :
27 :
28 : /**
29 : * @brief Parse a string containing information to create a KeySet
30 : *
31 : * @param pluginArguments comma (,) to separate key=value, contains no whitespaces
32 : *
33 : * @return newly created keyset with the information found in the string
34 : */
35 1755 : KeySet parsePluginArguments (std::string const & pluginArguments, std::string const & basepath)
36 : {
37 1755 : KeySet ks;
38 3510 : std::istringstream sstream (pluginArguments);
39 :
40 3510 : std::string keyName;
41 1755 : std::string value;
42 :
43 : // read until the next '=', this will be the keyname
44 4125 : while (std::getline (sstream, keyName, '='))
45 : {
46 : // read until a ',' or the end of line
47 : // if nothing is read because the '=' is the last character
48 : // in the config string, consider the value empty
49 410 : if (!std::getline (sstream, value, ',')) value = "";
50 :
51 1025 : ks.append (Key (basepath + "/" + keyName, KEY_VALUE, value.c_str (), KEY_END));
52 : }
53 1755 : return ks;
54 : }
55 :
56 4 : PluginSpecVector parseArguments (std::initializer_list<std::string> cmdline)
57 : {
58 4 : return parseArguments (cmdline.begin (), cmdline.end ());
59 : }
60 :
61 :
62 : /**
63 : * @brief Parse a complete commandline
64 : *
65 : * @param cmdline contains space separated plugins with optional plugin configurations
66 : *
67 : * @note currently whitespaces are not allowed within pluginname or config, use
68 : * iterator interface parseArguments() if you need it.
69 : *
70 : * @see parseArguments()
71 : * @return a parsed PluginSpecVector
72 : */
73 876 : PluginSpecVector parseArguments (std::string const & cmdline)
74 : {
75 1752 : std::vector<std::string> args;
76 1752 : std::istringstream sstream (cmdline);
77 876 : std::string argument;
78 2804 : while (std::getline (sstream, argument, ' '))
79 : {
80 526 : args.push_back (argument);
81 : }
82 2581 : return parseArguments (args.begin (), args.end ());
83 : }
84 :
85 :
86 : namespace detail
87 : {
88 :
89 : /**
90 : * @brief Process a single argument and add it to PluginSpecVector
91 : *
92 : * @internal
93 : *
94 : * @param [in,out] arguments current list of processed arguments
95 : * @param [in,out] counter current counter, to be modified when argument is added
96 : * @param argument the argument to parse and add
97 : */
98 807 : void processArgument (PluginSpecVector & arguments, size_t & counter, std::string argument)
99 : {
100 : // ignore empty or useless arguments (whitespace , only)
101 807 : if (argument.empty ()) return;
102 2868 : if (std::all_of (argument.begin (), argument.end (), [](char c) { return std::isspace (c) || c == ','; })) return;
103 :
104 693 : if (argument.find ('=') == std::string::npos)
105 : {
106 : // we have a plugin
107 2797 : PluginSpec ps (argument);
108 553 : if (argument.find ('#') == std::string::npos)
109 : {
110 409 : ps.setRefNumber (counter++);
111 409 : arguments.push_back (ps);
112 : }
113 : else
114 : {
115 144 : arguments.push_back (ps);
116 : }
117 : }
118 : else
119 : {
120 : // we have a plugin's configuration
121 146 : if (arguments.empty ()) throw ParseException ("config for plugin (" + argument + ") without previous plugin name");
122 750 : arguments.back ().appendConfig (parsePluginArguments (argument));
123 : }
124 : }
125 :
126 : /**
127 : * @brief Fix refnames after parsing
128 : *
129 : * @internal
130 : *
131 : * @param arguments to fix
132 : */
133 1109 : void fixArguments (PluginSpecVector & arguments)
134 : {
135 : // fix refnames of single occurrences for backwards compatibility and cleaner names
136 4863 : for (auto & a : arguments)
137 : {
138 1836 : size_t nr = std::count_if (arguments.begin (), arguments.end (),
139 3546 : [&a](PluginSpec const & spec) { return spec.getName () == a.getName (); });
140 459 : if (nr == 1 && a.isRefNumber ())
141 : {
142 690 : a.setRefName (a.getName ());
143 : }
144 :
145 : size_t identical =
146 2295 : std::count_if (arguments.begin (), arguments.end (), std::bind (PluginSpecRefName (), a, std::placeholders::_1));
147 459 : if (identical > 1)
148 : {
149 96 : throw ParseException ("identical reference names found for plugin: " + a.getFullName ());
150 : }
151 : }
152 :
153 : // now fix counter to be minimal
154 1077 : size_t counter = 0;
155 4721 : for (auto & a : arguments)
156 : {
157 413 : if (a.isRefNumber ())
158 : {
159 14 : a.setRefNumber (counter++);
160 : }
161 : }
162 1077 : }
163 : } // namespace detail
164 : } // namespace tools
165 : } // namespace kdb
|