bpp-core3  3.0.0
KeyvalTools.cpp
Go to the documentation of this file.
1 //
2 // File: KeyvalTools.cpp
3 // Authors:
4 // Julien Dutheil
5 // Created: 2009-05-11 13:16:00+02:00
6 //
7 
8 /*
9  Copyright or © or Copr. Bio++ Development Team, (2009)
10 
11  This software is a computer program whose purpose is to provide classes
12  for numerical calculus.
13 
14  This software is governed by the CeCILL license under French law and
15  abiding by the rules of distribution of free software. You can use,
16  modify and/ or redistribute the software under the terms of the CeCILL
17  license as circulated by CEA, CNRS and INRIA at the following URL
18  "http://www.cecill.info".
19 
20  As a counterpart to the access to the source code and rights to copy,
21  modify and redistribute granted by the license, users are provided only
22  with a limited warranty and the software's author, the holder of the
23  economic rights, and the successive licensors have only limited
24  liability.
25 
26  In this respect, the user's attention is drawn to the risks associated
27  with loading, using, modifying and/or developing or reproducing the
28  software by the user in light of its specific status of free software,
29  that may mean that it is complicated to manipulate, and that also
30  therefore means that it is reserved for developers and experienced
31  professionals having in-depth computer knowledge. Users are therefore
32  encouraged to load and test the software's suitability as regards their
33  requirements in conditions enabling the security of their systems and/or
34  data to be ensured and, more generally, to use and operate it in the
35  same conditions as regards security.
36 
37  The fact that you are presently reading this means that you have had
38  knowledge of the CeCILL license and that you accept its terms.
39 */
40 
41 
42 #include "KeyvalTools.h"
43 #include "NestedStringTokenizer.h"
44 
45 // From the STL:
46 #include <memory>
47 
48 using namespace bpp;
49 using namespace std;
50 
51 void KeyvalTools::singleKeyval(const std::string& desc, std::string& key, std::string& val, const std::string& split)
52 {
53  string::size_type i = desc.find(split);
54  if (i == string::npos)
55  throw KeyvalException("Bad syntax! keyval should be of the form 'key" + split + "=value', found '" + desc + "'.");
56  key = desc.substr(0, i);
57  val = desc.substr(i + 1);
58 }
59 
60 void KeyvalTools::multipleKeyvals(const std::string& desc, std::map<std::string, std::string>& keyvals, const std::string& split, bool nested)
61 {
62  unique_ptr<StringTokenizer> st;
63  if (nested)
64  st.reset(new NestedStringTokenizer(desc, "(", ")", split));
65  else
66  st.reset(new StringTokenizer(desc, split));
67  string key, val;
68  vector<string> tokens;
69  // Check tokens:
70  string token;
71  while (st->hasMoreToken())
72  {
73  token = st->nextToken();
74  if (token == "=")
75  {
76  // We need to merge the next token with the last one:
77  if (tokens.size() == 0)
78  throw KeyvalException("Invalid syntax, found '=' without argument name.");
79  if (!st->hasMoreToken())
80  throw KeyvalException("Invalid syntax, found '=' without argument value.");
81  string nextToken = st->nextToken();
82  if (nextToken == "=")
83  throw KeyvalException("Invalid syntax, found a double '='.");
84  tokens[tokens.size() - 1] += "=" + nextToken;
85  }
86  else
87  {
88  tokens.push_back(token);
89  }
90  }
91  for (vector<string>::iterator it = tokens.begin(); it != tokens.end(); it++)
92  {
93  singleKeyval(*it, key, val);
96  keyvals[key] = val;
97  }
98 }
99 
100 std::string KeyvalTools::changeKeyvals(const std::string& desc, const std::map<std::string, std::string>& newkeyvals, const std::string& split, bool nested)
101 {
102  string::size_type begin = desc.find_first_of("(");
103  string::size_type end = desc.find_last_of(")");
104 
105  if (begin == string::npos && end == string::npos)
106  {
107  // Empty procedure:
108  return desc;
109  }
110  if (begin == string::npos && end != string::npos)
111  throw KeyvalException("Bad keyval procedure, missing opening parenthesis.");
112  if (begin == string::npos && end != string::npos)
113  throw KeyvalException("Bad keyval procedure, missing closing parenthesis.");
114 
115  if (!TextTools::isEmpty(desc.substr(end + 1)))
116  throw KeyvalException("Bad keyval procedure, extra characters after closing parenthesis: " + desc.substr(end + 1));
117  // Get the procedure name (without leading spaces):
118 
119  string newDesc = TextTools::removeFirstWhiteSpaces(desc.substr(0, begin)) + "(";
120 
121  string desckv = desc.substr(begin + 1, end - begin - 1);
122 
123  unique_ptr<StringTokenizer> st;
124  if (nested)
125  st.reset(new NestedStringTokenizer(desckv, "(", ")", split));
126  else
127  st.reset(new StringTokenizer(desckv, split));
128  string key, val;
129  vector<string> tokens;
130  // Check tokens:
131  string token;
132 
133  while (st->hasMoreToken())
134  {
135  token = st->nextToken();
136  if (token == "=")
137  {
138  // We need to merge the next token with the last one:
139  if (tokens.size() == 0)
140  throw KeyvalException("Invalid syntax, found '=' without argument name.");
141  if (!st->hasMoreToken())
142  throw KeyvalException("Invalid syntax, found '=' without argument value.");
143  string nextToken = st->nextToken();
144  if (nextToken == "=")
145  throw KeyvalException("Invalid syntax, found a double '='.");
146  tokens[tokens.size() - 1] += "=" + nextToken;
147  }
148  else
149  {
150  tokens.push_back(token);
151  }
152  }
153 
154  for (vector<string>::iterator it = tokens.begin(); it != tokens.end(); it++)
155  {
156  singleKeyval(*it, key, val);
158  if (it != tokens.begin())
159  newDesc += split;
160 
161  map<string, string>::const_iterator iter = newkeyvals.find(key);
162 
163  if (iter != newkeyvals.end())
164  newDesc += key + "=" + iter->second;
165  else
166  newDesc += *it;
167  }
168 
169  newDesc += ")";
170 
171  return newDesc;
172 }
173 
174 void KeyvalTools::parseProcedure(const std::string& desc, std::string& name, std::map<std::string, std::string>& args)
175 {
176  string::size_type begin = desc.find_first_of("(");
177  string::size_type end = desc.find_last_of(")");
178 
179  if (begin == string::npos && end == string::npos)
180  {
181  // Empty procedure:
182  name = desc;
183  return;
184  }
185  if (begin == string::npos && end != string::npos)
186  throw KeyvalException("Bad keyval procedure, missing opening parenthesis.");
187  if (begin == string::npos && end != string::npos)
188  throw KeyvalException("Bad keyval procedure, missing closing parenthesis.");
189 
190  if (!TextTools::isEmpty(desc.substr(end + 1)))
191  throw KeyvalException("Bad keyval procedure, extra characters after closing parenthesis: " + desc.substr(end + 1));
192  // Get the procedure name (without leading spaces):
193  name = TextTools::removeFirstWhiteSpaces(desc.substr(0, begin));
194  multipleKeyvals(desc.substr(begin + 1, end - begin - 1), args);
195 }
Exception thrown by the Keyval parser.
Definition: KeyvalTools.h:59
static void parseProcedure(const std::string &desc, std::string &name, std::map< std::string, std::string > &args)
Parse (not recursively) a procedure string.
static std::string changeKeyvals(const std::string &desc, const std::map< std::string, std::string > &newkeyvals, const std::string &split=",", bool nested=true)
Change several keys to new corresponding values (General purpose function).
static void multipleKeyvals(const std::string &desc, std::map< std::string, std::string > &keyvals, const std::string &split=",", bool nested=true)
Split a string into several keys and corresponding values (General purpose function).
Definition: KeyvalTools.cpp:60
static void singleKeyval(const std::string &desc, std::string &key, std::string &val, const std::string &split="=")
Split a string into a key and a value (General purpose function).
Definition: KeyvalTools.cpp:51
An improved tokenizer for strings.
A tokenizer for strings.
std::string removeSurroundingWhiteSpaces(const std::string &s)
Remove all white spaces characters at the beginning and the end of a string.
Definition: TextTools.cpp:128
bool isEmpty(const std::string &s)
Tell if a string is empty. A string is considered to be 'empty' if it is only made of white spaces.
Definition: TextTools.cpp:58
std::vector< std::string > split(const std::string &s, std::size_t n)
Definition: TextTools.cpp:301
std::string removeFirstWhiteSpaces(const std::string &s)
Remove all white spaces characters at the beginning of a string.
Definition: TextTools.cpp:107