VariableFormatter.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25 */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31 
32 #ifndef VARIABLE_FORMATTER_H_
33 #define VARIABLE_FORMATTER_H_
34 
35 #include <drain/Log.h>
36 #include <map>
37 #include <list>
38 #include <iterator>
39 #include <sstream>
40 
41 #include <drain/Convert.h>
42 #include <drain/RegExp.h>
43 #include <drain/String.h>
44 // #include <drain/VariableAssign.h>
45 #include <drain/SmartMapTools.h>
46 //#include "Variable.h"
47 
48 #include "IosFormat.h"
49 //#include "MapTools.h"
50 
51 //#include "Sprinter.h"
52 #include "Time.h"
53 
54 namespace drain {
55 
56 
58 
70 template <class T=std::string>
72 
73 public:
74 
75  inline virtual
76  ~VariableFormatter(){};
77 
78  IosFormat iosFormat;
79 
80  typedef std::map<std::string,T> map_t;
81 
83 
87  virtual
88  bool handle(const std::string & key, const map_t & variables, std::ostream & ostr) const {
89 
90  drain::Logger mout(__FILE__, __FUNCTION__);
91 
92  std::string k,format;
93  drain::StringTools::split2(key, k, format, '|');
94  // mout.attention("split '", key, "' to ", k, " + ", format);
95 
96  const typename std::map<std::string,T>::const_iterator it = variables.find(k);
97  if (it == variables.end()) {
98  // Don't format.
99  return false;
100  }
101 
102 
103  if (format.empty()){
104  iosFormat.copyTo(ostr);
105  //vostr.width(width);
106  //vstd::cerr << __FILE__ << " assign -> " << stringlet << std::endl;
107  //vstd::cerr << __FILE__ << " assign <---- " << mit->second << std::endl;
108  ostr << it->second;
109  return true;
110  }
111  else {
112  // mout.attention("delegating '", k, "' to formatVariable: ", format);
113  //return formatVariable(k, variables, format, ostr);
114  return formatVariable(k, it->second, format, ostr);
115  }
116 
117  }
118 
119 
121 
126  // NOTE: must return false, if not found. Then, further processors may handle the variable tag (remove, change, leave it).
127  virtual
128  bool formatVariable(const std::string & key, const T & value, const std::string & format, std::ostream & ostr) const {
129 
130  drain::Logger mout(__FILE__, __FUNCTION__);
131 
132  // Default implementation discards \c key.
133  return formatValue(value, format, ostr);
134 
135  /*
136  typename std::map<std::string,T>::const_iterator it = variables.find(key);
137 
138  if (it != variables.end()){
139  return formatValue(it->second, format, ostr);
140  }
141  else {
142  return false;
143  }
144  */
145 
146  }
147 
149 
152  static
153  bool formatValue(const T & value, const std::string & format, std::ostream & ostr) {
154 
155  drain::Logger mout(__FILE__, __FUNCTION__);
156 
157  const char firstChar = format.at(0);
158  const char lastChar = format.at(format.size()-1);
159 
160  if (firstChar == ':'){
161 
162  mout.attention<LOG_DEBUG>("substring extraction: ", format);
163 
164  std::string s;
165  drain::Convert2<T>::convert(value, s);
166  //drain::StringTools::import(variable, s);
167 
168  std::vector<size_t> v;
169  drain::StringTools::split(format, v, ':');
170  size_t pos = 0;
171  size_t count = s.size();
172 
173  switch (v.size()) {
174  case 3:
175  count = v[2];
176  // no break
177  case 2:
178  pos = v[1];
179  if (pos >= s.size()){
180  mout.warn("index ", pos, " greater than size (", s.size(), ") of string value '", s, "' of '", value, "'");
181  return true;
182  }
183  count = std::min(count, s.size()-pos);
184  ostr << s.substr(v[1], count);
185  break;
186  default:
187  mout.warn("unsupported formatting '", format, "' for variable '", value, "'");
188  mout.advice("use :startpos or :startpos:count for substring extraction");
189  }
190  return true;
191 
192  }
193  else if (firstChar == '%'){
194 
195  mout.attention<LOG_DEBUG>("string formatting: ", format);
196 
197  //else if (format.find('%') != std::string::npos){
198  //drain::MapTools::get(variables, key, s);
199 
200  const size_t BUFFER_SIZE = 256;
201  char buffer[BUFFER_SIZE];
202  buffer[0] = '\0';
203  size_t n = 0;
204 
205  switch (lastChar){
206  case 's':
207  {
208  std::string s;
209  drain::Convert2<T>::convert(value, s);
210  // drain::StringTools::import(variable, s);
211  n = std::sprintf(buffer, format.c_str(), s.c_str());
212  }
213  break;
214  case 'c':
215  {
216  std::string s;
217  drain::Convert2<T>::convert(value, s);
218  //drain::StringTools::import(variable, s);
219  n = std::sprintf(buffer, format.c_str(), s.at(0)); // ?
220  }
221  break;
222  case 'p':
223  mout.unimplemented("pointer type: ", format);
224  break;
225  case 'f':
226  case 'F':
227  case 'e':
228  case 'E':
229  case 'a':
230  case 'A':
231  case 'g':
232  case 'G':
233  {
234  double d = NAN; //nand()
235  drain::Convert2<T>::convert(value, d);
236  // drain::StringTools::import(variable, d);
237  //drain::MapTools::get(variables, key, d);
238  // ostr << d << "=>"; // debugging
239  n = std::sprintf(buffer, format.c_str(), d);
240  }
241  break;
242  case 'd':
243  case 'i':
244  case 'o':
245  case 'u':
246  case 'x':
247  case 'X':
248  {
249  int i = 0;
250  drain::Convert::convert(value, i);
251  // drain::convertAny(variable, i);
252  // drain::StringTools::import(variable, i);
253  // drain::MapTools::get(variables, key, i);
254  // ostr << i << "=>"; // debugging
255  n = std::sprintf(buffer, format.c_str(), i);
256  }
257  break;
258  default:
259  mout.warn("formatting '", format, "' requested for '", value, "' : unsupported type key: '", lastChar, "'");
260  return false; // could be also true, if seen as handled this way?
261  }
262 
263  ostr << buffer;
264  if (n > BUFFER_SIZE){
265  mout.fail("formatting with '", format, "' exceeded buffer size (", BUFFER_SIZE, ')');
266  }
267 
268  // mout.warn("time formatting '", format, "' requested for '", k, "' not ending with 'time' or 'date'!");
269  }
270 
271  return true;
272  }
273 
274 
275 
276 };
277 
278 /*
279 inline
280 std::ostream & operator<<(std::ostream & ostr, const StringMapper & strmap){
281  return strmap.toStream(ostr);
282 }
283 */
284 
285 
286 } // NAMESPACE
287 
288 #endif /* STRINGMAPPER_H_ */
289 
290 // Drain
static void convert(const T &src, T &dst)
Trivial case: source and destination are of same class.
Definition: Convert.h:94
static void convert(const T &src, T &dst)
Trivial case: source and destination are of same class.
Definition: Convert.h:58
Stores precision, fillChar and fieldWidth applied by STD streams.
Definition: IosFormat.h:45
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:308
Logger & attention(const TT &... args)
Possible error, but execution can continue. Special type of Logger::warn().
Definition: Log.h:472
Logger & fail(const TT &... args)
Possible error, but execution can continue. Special type of Logger::warn().
Definition: Log.h:449
Logger & unimplemented(const TT &... args)
Feature to be done. Special type of Logger::note().
Definition: Log.h:507
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition: Log.h:426
static bool split2(const std::string &s, T1 &first, T2 &second, const C &separators, const std::string &trimChars=" \t\n")
Splits and trims a given std::string to a std Sequence.
static void split(const std::string &s, T &sequence, const C &separators, const std::string &trimChars=" \t\n")
Splits and trims a given std::string to a std Sequence.
Definition: String.h:309
Formats variables to output stream.
Definition: VariableFormatter.h:71
static bool formatValue(const T &value, const std::string &format, std::ostream &ostr)
Given a value, print it formatted to stream.
Definition: VariableFormatter.h:153
virtual bool formatVariable(const std::string &key, const T &value, const std::string &format, std::ostream &ostr) const
Given a key, retrieve an associated value from the map and print the value formatted into a stream.
Definition: VariableFormatter.h:128
virtual bool handle(const std::string &key, const map_t &variables, std::ostream &ostr) const
Searches given key in a map, and if found, processes (formats) the value to ostream....
Definition: VariableFormatter.h:88
Definition: DataSelector.cpp:1277