goptions
goption.cc
Go to the documentation of this file.
1 #include "goption.h"
2 #include "goptionsConventions.h"
3 #include "gutilities.h"
4 
5 // gemc
6 #include "gutsConventions.h"
7 
8 #include <iostream>
9 #include <algorithm>
10 #include <functional>
11 
12 using std::cerr;
13 using std::endl;
14 using std::cout;
15 using std::left;
16 using std::string;
17 using std::vector;
18 
27 void 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 
42 void 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 
100 bool 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 
116 void 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 
176 void 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 
201 string 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 
229 void 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