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  // drain::Logger mout(__FILE__, __FUNCTION__);
130  // Default implementation discards \c key.
131  return formatValue(value, format, ostr);
132  }
133 
135  virtual inline
136  bool formatVariable(const std::string & key, const T & value, const std::string & format, std::string & str) const final {
137  std::stringstream sstr;
138  const bool result = formatVariable(key, value, format, sstr);
139  str = sstr.str();
140  return result;
141  }
142 
143 
145 
148  static
149  bool formatValue(const T & value, const std::string & format, std::ostream & ostr) {
150 
151  drain::Logger mout(__FILE__, __FUNCTION__);
152 
153  const char firstChar = format.at(0);
154  const char lastChar = format.at(format.size()-1);
155 
156  if (firstChar == ':'){
157 
158  mout.attention<LOG_DEBUG>("substring extraction: ", format);
159 
160  std::string s;
161  drain::Convert2<T>::convert(value, s);
162  //drain::StringTools::import(variable, s);
163 
164  std::vector<size_t> v;
165  drain::StringTools::split(format, v, ':');
166  size_t pos = 0;
167  size_t count = s.size();
168 
169  switch (v.size()) {
170  case 3:
171  count = v[2];
172  // no break
173  case 2:
174  pos = v[1];
175  if (pos >= s.size()){
176  mout.warn("index ", pos, " greater than size (", s.size(), ") of string value '", s, "' of '", value, "'");
177  return true;
178  }
179  count = std::min(count, s.size()-pos);
180  ostr << s.substr(v[1], count);
181  break;
182  default:
183  mout.warn("unsupported formatting '", format, "' for variable '", value, "'");
184  mout.advice("use :startpos or :startpos:count for substring extraction");
185  }
186  return true;
187 
188  }
189  else if (firstChar == '%'){
190 
191  mout.attention<LOG_DEBUG>("string formatting: ", format);
192 
193  //else if (format.find('%') != std::string::npos){
194  //drain::MapTools::get(variables, key, s);
195 
196  const size_t BUFFER_SIZE = 256;
197  char buffer[BUFFER_SIZE];
198  buffer[0] = '\0';
199  size_t n = 0;
200 
201  switch (lastChar){
202  case 's':
203  {
204  std::string s;
205  drain::Convert2<T>::convert(value, s);
206  // drain::StringTools::import(variable, s);
207  n = std::sprintf(buffer, format.c_str(), s.c_str());
208  }
209  break;
210  case 'c':
211  {
212  std::string s;
213  drain::Convert2<T>::convert(value, s);
214  //drain::StringTools::import(variable, s);
215  n = std::sprintf(buffer, format.c_str(), s.at(0)); // ?
216  }
217  break;
218  case 'p':
219  mout.unimplemented("pointer type: ", format);
220  break;
221  case 'f':
222  case 'F':
223  case 'e':
224  case 'E':
225  case 'a':
226  case 'A':
227  case 'g':
228  case 'G':
229  {
230  double d = NAN; //nand()
231  drain::Convert2<T>::convert(value, d);
232  // drain::StringTools::import(variable, d);
233  //drain::MapTools::get(variables, key, d);
234  // ostr << d << "=>"; // debugging
235  n = std::sprintf(buffer, format.c_str(), d);
236  }
237  break;
238  case 'd':
239  case 'i':
240  case 'o':
241  case 'u':
242  case 'x':
243  case 'X':
244  {
245  int i = 0;
246  drain::Convert::convert(value, i);
247  // drain::convertAny(variable, i);
248  // drain::StringTools::import(variable, i);
249  // drain::MapTools::get(variables, key, i);
250  // ostr << i << "=>"; // debugging
251  n = std::sprintf(buffer, format.c_str(), i);
252  }
253  break;
254  default:
255  mout.warn("formatting '", format, "' requested for '", value, "' : unsupported type key: '", lastChar, "'");
256  return false; // could be also true, if seen as handled this way?
257  }
258 
259  ostr << buffer;
260  if (n > BUFFER_SIZE){
261  mout.fail("formatting with '", format, "' exceeded buffer size (", BUFFER_SIZE, ')');
262  }
263 
264  // mout.warn("time formatting '", format, "' requested for '", k, "' not ending with 'time' or 'date'!");
265  }
266 
267  return true;
268  }
269 
270 
271 
272 };
273 
274 /*
275 inline
276 std::ostream & operator<<(std::ostream & ostr, const StringMapper & strmap){
277  return strmap.toStream(ostr);
278 }
279 */
280 
281 
282 } // NAMESPACE
283 
284 #endif /* STRINGMAPPER_H_ */
285 
286 // 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:310
Logger & attention(const TT &... args)
Possible error, but execution can continue. Special type of Logger::warn().
Definition: Log.h:474
Logger & fail(const TT &... args)
Possible error, but execution can continue. Special type of Logger::warn().
Definition: Log.h:451
Logger & unimplemented(const TT &... args)
Feature to be done. Special type of Logger::note().
Definition: Log.h:509
Logger & warn(const TT &... args)
Possible error, but execution can continue.
Definition: Log.h:428
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:318
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:149
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
virtual bool formatVariable(const std::string &key, const T &value, const std::string &format, std::string &str) const final
Checks if variables have ODIM names (keys), and apply special formatting (currently with time stamps)
Definition: VariableFormatter.h:136
Definition: DataSelector.cpp:1277