goptions
Loading...
Searching...
No Matches
goption.cc
Go to the documentation of this file.
1#include "goption.h"
3#include "gutilities.h"
4
5// gemc
6#include "gutsConventions.h"
7
8#include <iostream>
9#include <algorithm>
10#include <functional>
11
12using std::cerr;
13using std::endl;
14using std::cout;
15using std::left;
16using std::string;
17using std::vector;
18
27void GOption::set_scalar_value(const string& v) {
28 if (v.empty()) return;
29 string value_to_set = gutilities::replaceCharInStringWithChars(v, ",", "");
30 auto key = value.begin()->first.as<string>();
31 value[key] = value_to_set;
32}
33
42void GOption::set_value(const YAML::Node& v) {
43 if (isCumulative) {
44 for (const auto& element : v) {
45 if (!does_the_option_set_all_necessary_values(element)) {
46 cerr << FATALERRORL << "Trying to set " << YELLOWHHL << name << RSTHHR
47 << " but missing mandatory values." << endl;
48 cerr << " Use the option: " << YELLOWHHL << " help " << name
49 << " " << RSTHHR << " for details." << endl << endl;
51 }
52 }
53 value[name] = v;
54 auto default_value_node = defaultValue.begin()->second;
55 for (const auto& map_element_in_default_value : default_value_node) {
56 for (auto default_value_iterator = map_element_in_default_value.begin();
57 default_value_iterator != map_element_in_default_value.end(); ++default_value_iterator) {
58 auto default_key = default_value_iterator->first.as<string>();
59 auto default_value = default_value_iterator->second;
60 for (auto map_element_in_value : value[name]) {
61 bool key_found = false;
62 for (auto value_iterator = map_element_in_value.begin();
63 value_iterator != map_element_in_value.end(); ++value_iterator) {
64 auto value_key = value_iterator->first.as<string>();
65 if (default_key == value_key) {
66 key_found = true;
67 break;
68 }
69 }
70 if (!key_found) { map_element_in_value[default_key] = default_value; }
71 }
72 }
73 }
74 }
75 else {
76 for (const auto& map_element_in_desired_value : v) {
77 for (auto desired_value_iterator = map_element_in_desired_value.begin();
78 desired_value_iterator != map_element_in_desired_value.end(); ++desired_value_iterator) {
79 for (auto existing_map : value[name]) {
80 for (auto existing_map_iterator = existing_map.begin();
81 existing_map_iterator != existing_map.end(); ++existing_map_iterator) {
82 auto first_key = existing_map_iterator->first.as<string>();
83 auto second_key = desired_value_iterator->first.as<string>();
84 if (first_key == second_key) {
85 existing_map[existing_map_iterator->first] = desired_value_iterator->second;
86 }
87 }
88 }
89 }
90 }
91 }
92}
93
100bool GOption::does_the_option_set_all_necessary_values(const YAML::Node& v) {
101 vector<string> this_keys;
102 if (v.Type() == YAML::NodeType::Map) { for (const auto& it : v) { this_keys.push_back(it.first.as<string>()); } }
103 for (const auto& key : mandatory_keys) {
104 if (find(this_keys.begin(), this_keys.end(), key) == this_keys.end()) { return false; }
105 }
106 return true;
107}
108
116void GOption::saveOption(std::ofstream* yamlConf) const
117{
118 std::vector<std::string> missing; // paths of null values
119
120 // --------------------------------------------------------------------
121 // recursive lambda: returns a *new* node with nulls → "not provided"
122 // --------------------------------------------------------------------
123 std::function<YAML::Node(YAML::Node, std::string)> clean =
124 [&](YAML::Node n, const std::string& path) -> YAML::Node
125 {
126 if (n.IsNull()) {
127 missing.push_back(path.empty() ? name : path);
128 return YAML::Node("not provided"); // null replaced
129 }
130
131 if (n.IsMap()) {
132 YAML::Node res(YAML::NodeType::Map);
133 for (auto it : n) {
134 const std::string key = it.first.as<std::string>();
135 res[it.first] = clean(it.second,
136 path.empty() ? key : path + "." + key);
137 }
138 return res;
139 }
140
141 if (n.IsSequence()) {
142 YAML::Node res(YAML::NodeType::Sequence);
143 for (std::size_t i = 0; i < n.size(); ++i)
144 res.push_back(clean(n[i],
145 path + "[" + std::to_string(i) + "]"));
146 return res;
147 }
148
149 return n; // scalar, already OK
150 };
151
152 YAML::Node out = clean(value, ""); // fully cleaned copy
153
154 // --------------------------------------------------------------------
155 // write one comment line per missing entry
156 // --------------------------------------------------------------------
157 for (const auto& p : missing)
158 *yamlConf << "# " << p << " not provided\n";
159
160 // write the YAML itself (block style)
161 out.SetStyle(YAML::EmitterStyle::Block);
162 *yamlConf << out << '\n';
163}
164
165
166
167
176void GOption::printHelp(bool detailed) const {
177 if (name == GVERSION_STRING) return;
178 long int fill_width = string(HELPFILLSPACE).size() + 1;
179 cout.fill('.');
180 string helpString = "-" + name + RST;
181 bool is_sequence = defaultValue.begin()->second.IsSequence();
182 helpString += is_sequence ? "=<sequence>" : "=<value>";
183 helpString += " ";
184 cout << KGRN << " " << left;
185 cout.width(fill_width);
186 if (detailed) {
187 cout << helpString << ": " << description << endl << endl;
188 cout << detailedHelp() << endl;
189 }
190 else { cout << helpString << ": " << description << endl; }
191}
192
201string GOption::detailedHelp() const {
202 string newHelp;
203 YAML::Node yvalues = defaultValue.begin()->second;
204 if (yvalues.IsSequence()) {
205 newHelp += "\n";
206 for (unsigned i = 0; i < yvalues.size(); i++) {
207 YAML::Node this_node = yvalues[i];
208 for (auto it = this_node.begin(); it != this_node.end(); ++it) {
209 cout << TGREENPOINTITEM << " " << KGRN << it->first.as<string>() << RST
210 << ": " << gvar_descs[i] << ". Default value: " << it->second.as<string>() << endl;
211 }
212 }
213 }
214 newHelp += "\n";
215 vector<string> help_lines = gutilities::getStringVectorFromStringWithDelimiter(help, "\n");
216 for (const auto& line : help_lines) { newHelp += GTAB + line + "\n"; }
217 return newHelp;
218}
219
229void GOption::set_sub_option_value(const string& subkey, const string& subvalue) {
230 YAML::Node option_node = value.begin()->second;
231 if (option_node.IsSequence()) {
232 bool updated = false;
233 for (auto it = option_node.begin(); it != option_node.end(); ++it) {
234 if ((*it).IsMap() && (*it)[subkey]) {
235 (*it)[subkey] = YAML::Load(subvalue);
236 updated = true;
237 }
238 }
239 if (!updated) {
240 cerr << "Sub-option key '" << subkey << "' not found in option '" << name << "'." << endl;
241 exit(EC__NOOPTIONFOUND);
242 }
243 }
244 else if (option_node.IsMap()) {
245 if (option_node[subkey]) { option_node[subkey] = YAML::Load(subvalue); }
246 else {
247 cerr << "Sub-option key '" << subkey << "' not found in option '" << name << "'." << endl;
248 exit(EC__NOOPTIONFOUND);
249 }
250 }
251 else {
252 cerr << "Option '" << name << "' is not structured to accept sub–options." << endl;
253 exit(EC__NOOPTIONFOUND);
254 }
255}
void set_sub_option_value(const std::string &subkey, const std::string &subvalue)
Sets the value of a sub–option using dot–notation.
Definition goption.cc:229
#define EC__NOOPTIONFOUND
#define HELPFILLSPACE
#define GVERSION_STRING
#define EC__MANDATORY_NOT_FILLED