bpp-core3  3.0.0
AttributesTools.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: The Bio++ Development Group
2 //
3 // SPDX-License-Identifier: CECILL-2.1
4 
5 // From the STL:
6 #include <cstdlib>
7 #include <string>
8 #include <iostream>
9 #include <fstream>
10 #include <algorithm>
11 
12 
13 using namespace std;
14 
15 #include "AttributesTools.h"
16 #include "../App/ApplicationTools.h"
17 #include "../Text/TextTools.h"
18 #include "../Io/FileTools.h"
19 
20 using namespace bpp;
21 
22 std::vector<std::string> AttributesTools::vParam_;
23 
24 /******************************************************************************/
25 
26 std::vector<std::string> AttributesTools::getVector(int argc, char* argv[])
27 {
28  size_t n = static_cast<size_t>(argc);
29  vector<string> result(n);
30  for (size_t i = 1; i < n; ++i)
31  {
32  result[i] = string(argv[i]);
33  }
34  // Ignore first argc which is the program name!
35  return result;
36 }
37 
38 /******************************************************************************/
39 
40 std::map<std::string, std::string> AttributesTools::getAttributesMap(
41  const std::vector<std::string>& argv,
42  const std::string& delimiter)
43 {
44  map<string, string> am;
45  getAttributesMap(argv, am, delimiter);
46  return am;
47 }
48 
49 /******************************************************************************/
50 
51 void AttributesTools::getAttributesMap(
52  const std::vector<std::string>& argv,
53  std::map<std::string, std::string>& am,
54  const std::string& delimiter)
55 {
56  vector<string> argv2(argv.size());
57  // First make a few cleaning:
58  for (size_t i = 0; i < argv.size(); ++i)
59  {
60  // Make a few corrections first:
61  string arg = removeComments(argv[i], "#", "\n"); // remove shell comments.
62  arg = removeComments(arg, "//", "\n"); // remove C simple comments.
63  arg = removeComments(arg, "/*", "*/"); // remove C multiple comments.
65  argv2[i] = arg;
66  }
67  // Now parse arguments:
68  for (size_t i = 0; i < argv.size(); i++)
69  {
70  string arg = argv2[i];
71  if (arg == "")
72  continue; // Skipping void line.
73  while (arg[arg.size() - 1] == '\\')
74  {
75  // Splitted line
76  i++;
77  arg = arg.substr(0, arg.length() - 1) + argv2[i];
78  }
79  // Parsing:
80  string::size_type limit = arg.find(delimiter, 0);
81  if (limit == string::npos)
82  {
83  // Invalid parameter
84  (*ApplicationTools::warning << "WARNING!!! Parameter '" << arg << "' has been ignored.").endLine();
85  }
86  else
87  {
88  string name = string(arg.begin(), arg.begin() + static_cast<ptrdiff_t>(limit));
89  string value = string(arg.begin() + static_cast<ptrdiff_t>(limit + delimiter.size()), arg.end());
90  am[name] = value;
91  }
92  }
93 }
94 
95 /******************************************************************************/
96 
97 void AttributesTools::getAttributesMapFromFile(
98  const std::string& file,
99  std::map<std::string, std::string>& params,
100  const std::string& delimiter)
101 {
102  cout << "Parsing file " << file << " for options." << endl;
103  ifstream input(file.c_str(), ios::in);
104  vector<string> lines = FileTools::putStreamIntoVectorOfStrings(input);
105  getAttributesMap(lines, params, delimiter);
106 }
107 
108 /******************************************************************************/
109 
110 std::map<std::string, std::string> AttributesTools::getAttributesMapFromFile(
111  const std::string& file,
112  const std::string& delimiter)
113 {
114  map<string, string> params;
115  getAttributesMapFromFile(file, params, delimiter);
116  return params;
117 }
118 
119 /******************************************************************************/
120 
121 void AttributesTools::actualizeAttributesMap(
122  std::map<std::string, std::string>& attMap,
123  const std::map<std::string, std::string>& atts,
124  bool replace)
125 {
126  for (const auto& i : atts)
127  {
128  if (replace || attMap.find(i.first) == attMap.end())
129  attMap[i.first] = i.second;
130  }
131 }
132 
133 /******************************************************************************/
134 
135 void AttributesTools::resolveVariables(
136  std::map<std::string, std::string>& am,
137  char varCode,
138  char varBeg,
139  char varEnd)
140 {
141  // Now resolve any variable:
142  for (map<string, string>::iterator it = am.begin(); it != am.end(); it++)
143  {
144  string value = it->second;
145  string::size_type index1 = value.find(TextTools::toString(varCode) + TextTools::toString(varBeg));
146  while (index1 != string::npos)
147  {
148  string::size_type index2 = value.find(TextTools::toString(varEnd), index1);
149  if (index2 != string::npos)
150  {
151  string varName = value.substr(index1 + 2, index2 - index1 - 2);
152  map<string, string>::iterator varIt = am.find(varName);
153  string varValue = "";
154  if (varIt == am.end())
155  {
156  if (ApplicationTools::error)
157  (*ApplicationTools::error << "Variable '" << varName << "' is undefined and was ignored.").endLine();
158  index1 = string::npos;
159  }
160  else
161  {
162  if (varIt->second == value)
163  {
164  if (ApplicationTools::error)
165  (*ApplicationTools::error << "Variable '" << varName << "' definition is cyclic and was ignored.").endLine();
166  index1 = string::npos;
167  }
168  else
169  {
170  varValue = varIt->second;
171  string newValue = value.substr(0, index1) + varValue + value.substr(index2 + 1);
172  it->second = newValue;
173  value = it->second;
174  index1 = value.find(TextTools::toString(varCode) + TextTools::toString(varBeg));
175  }
176  }
177  // Modify original field:
178  }
179  else
180  throw Exception("Syntax error, variable name is not closed.");
181  }
182  }
183 }
184 
185 /******************************************************************************/
186 
187 std::string AttributesTools::removeComments(
188  const std::string& s,
189  const std::string& begin,
190  const std::string& end)
191 {
192  string r = s;
193  string::size_type last = 0;
194  do
195  {
196  auto first = r.find(begin, last);
197  if (first == string::npos)
198  return r; // No shell comment.
199  // else:
200  last = r.find(end, first);
201  if (last == string::npos)
202  {
203  r.erase(r.begin() + static_cast<ptrdiff_t>(first), r.end());
204  }
205  else
206  {
207  r.erase(r.begin() + static_cast<ptrdiff_t>(first), r.begin() + static_cast<ptrdiff_t>(last));
208  }
209  }
210  while (last != string::npos);
211  return r;
212 }
213 
214 /******************************************************************************/
215 
216 std::map<std::string, std::string> AttributesTools::parseOptions(int args, char** argv)
217 {
218  // Get the parameters from command line:
219  map<string, string> cmdParams = AttributesTools::getAttributesMap(
220  AttributesTools::getVector(args, argv), "=");
221 
222  resolveVariables(cmdParams);
223 
224  // Look for specified files with parameters:
225  // With priority to the deeper
226 
227  map<string, string> params;
228 
229  if (cmdParams.find("param") != cmdParams.end())
230  {
231  StringTokenizer st(cmdParams["param"],",");
232  cmdParams.erase("param");
233  vector<string> vfile;
234 
235  while (st.hasMoreToken())
236  vfile.push_back(st.nextToken());
237 
238  size_t i = 0;
239  while (i != vfile.size())
240  {
241  const auto& file = vfile[i];
242  auto ii = static_cast<vector<string>::difference_type>(i);
243  if (std::find(vfile.begin(), vfile.begin() + ii, file) != vfile.begin() + ii)
244  {
245  cout << file << " already seen. Skipping." << endl;
246  i++;
247  continue;
248  }
249 
250  if (!FileTools::fileExists(file))
251  throw Exception("AttributesTools::parseOptions(). Parameter file not found.: " + file);
252 
253  params = getAttributesMapFromFile(file, "=");
254  actualizeAttributesMap(cmdParams, params, false);
255 
256  resolveVariables(cmdParams);
257 
258  // Actualize list of param files
259  if (cmdParams.find("param") != cmdParams.end())
260  {
261  StringTokenizer st2(cmdParams["param"],",");
262  cmdParams.erase("param");
263 
264  while (st2.hasMoreToken())
265  vfile.push_back(st2.nextToken());
266  }
267 
268  i ++;
269  }
270  }
271 
272  return cmdParams;
273 }
274 
275 /******************************************************************************/
A tokenizer for strings.
const std::string & nextToken()
Get the next available token. If no token is availbale, throw an Exception.
bool hasMoreToken() const
Tell if some tokens are still available.
STL namespace.
std::string removeWhiteSpaces(const std::string &s)
Remove all white spaces characters in a string.
Definition: TextTools.cpp:57
Exception base class. Overload exception constructor (to control the exceptions mechanism). Destructor is already virtual (from std::exception)
Definition: Exceptions.h:20
std::string toString(T t)
General template method to convert to a string.
Definition: TextTools.h:115