Async 1.8.0
AsyncConfig.h
Go to the documentation of this file.
1
38#ifndef ASYNC_CONFIG_INCLUDED
39#define ASYNC_CONFIG_INCLUDED
40
41
42/****************************************************************************
43 *
44 * System Includes
45 *
46 ****************************************************************************/
47
48#include <stdio.h>
49#include <sigc++/sigc++.h>
50
51#include <string>
52#include <map>
53#include <list>
54#include <memory>
55#include <sstream>
56#include <locale>
57#include <vector>
58#include <cassert>
59
60
61/****************************************************************************
62 *
63 * Project Includes
64 *
65 ****************************************************************************/
66
67
68
69/****************************************************************************
70 *
71 * Local Includes
72 *
73 ****************************************************************************/
74
75
76
77/****************************************************************************
78 *
79 * Forward declarations
80 *
81 ****************************************************************************/
82
83
84
85/****************************************************************************
86 *
87 * Namespace
88 *
89 ****************************************************************************/
90
91namespace Async
92{
93
94
95/****************************************************************************
96 *
97 * Forward declarations of classes inside of the declared namespace
98 *
99 ****************************************************************************/
100
101
102
103/****************************************************************************
104 *
105 * Defines & typedefs
106 *
107 ****************************************************************************/
108
109
110
111/****************************************************************************
112 *
113 * Exported Global Variables
114 *
115 ****************************************************************************/
116
117
118
119/****************************************************************************
120 *
121 * Class definitions
122 *
123 ****************************************************************************/
124
139{
140 public:
144 Config(void) {}
145
149 ~Config(void);
150
160 bool open(const std::string& name);
161
174 const std::string &getValue(const std::string& section,
175 const std::string& tag) const;
176
189 bool getValue(const std::string& section, const std::string& tag,
190 std::string& value, bool missing_ok = false) const;
191
212 template <typename Rsp>
213 bool getValue(const std::string& section, const std::string& tag,
214 Rsp &rsp, bool missing_ok = false) const
215 {
216 std::string str_val;
217 if (!getValue(section, tag, str_val))
218 {
219 return missing_ok;
220 }
221 std::stringstream ssval(str_val);
222 Rsp tmp;
223 ssval >> tmp;
224 if(!ssval.eof())
225 {
226 ssval >> std::ws;
227 }
228 if (ssval.fail() || !ssval.eof())
229 {
230 return false;
231 }
232 rsp = tmp;
233 return true;
234 } /* Config::getValue */
235
256 template <template <typename, typename> class Container,
257 typename Value>
258 bool getValue(const std::string& section, const std::string& tag,
259 Container<Value, std::allocator<Value> > &c,
260 bool missing_ok = false) const
261 {
262 std::string str_val;
263 if (!getValue(section, tag, str_val))
264 {
265 return missing_ok;
266 }
267 if (str_val.empty())
268 {
269 c.clear();
270 return true;
271 }
272 std::stringstream ssval(str_val);
273 ssval.imbue(std::locale(ssval.getloc(), new csv_whitespace));
274 while (!ssval.eof())
275 {
276 Value tmp;
277 ssval >> tmp;
278 if(!ssval.eof())
279 {
280 ssval >> std::ws;
281 }
282 if (ssval.fail())
283 {
284 return false;
285 }
286 c.push_back(tmp);
287 }
288 return true;
289 } /* Config::getValue */
290
312 template <template <typename, typename, typename> class Container,
313 typename Key>
314 bool getValue(const std::string& section, const std::string& tag,
315 Container<Key, std::less<Key>, std::allocator<Key> > &c,
316 bool missing_ok = false) const
317 {
318 std::string str_val;
319 if (!getValue(section, tag, str_val))
320 {
321 return missing_ok;
322 }
323 if (str_val.empty())
324 {
325 c.clear();
326 return true;
327 }
328 std::stringstream ssval(str_val);
329 ssval.imbue(std::locale(ssval.getloc(), new csv_whitespace));
330 while (!ssval.eof())
331 {
332 Key tmp;
333 ssval >> tmp;
334 if(!ssval.eof())
335 {
336 ssval >> std::ws;
337 }
338 if (ssval.fail())
339 {
340 return false;
341 }
342 c.insert(tmp);
343 }
344 return true;
345 } /* Config::getValue */
346
368 template <template <typename, typename, typename, typename> class Container,
369 class Key, class T, class Compare=std::less<Key>,
370 class Allocator=std::allocator<std::pair<const Key, T>>>
371 bool getValue(const std::string& section, const std::string& tag,
372 Container<Key, T, Compare, Allocator>& c,
373 char sep = ':', bool missing_ok = false) const
374 {
375 std::string str_val;
376 if (!getValue(section, tag, str_val))
377 {
378 return missing_ok;
379 }
380 if (str_val.empty())
381 {
382 c.clear();
383 return true;
384 }
385 std::stringstream ssval(str_val);
386 ssval.imbue(std::locale(ssval.getloc(), new csv_whitespace));
387 while (!ssval.eof())
388 {
389 std::string entry;
390 ssval >> entry;
391 std::string::size_type seppos = entry.find(sep);
392 if (seppos == std::string::npos)
393 {
394 return false;
395 }
396 std::string keystr(entry.substr(0, seppos));
397 std::string valuestr(entry.substr(seppos+1));
398 Key key;
399 T value;
400 if (!setValueFromString(key, keystr) ||
401 !setValueFromString(value, valuestr))
402 {
403 return false;
404 }
405 if(!ssval.eof())
406 {
407 ssval >> std::ws;
408 }
409 if (ssval.fail())
410 {
411 return false;
412 }
413 c.insert(std::pair<Key, T>(key, value));
414 }
415 return true;
416 } /* Config::getValue */
417
439 template <typename Rsp>
440 bool getValue(const std::string& section, const std::string& tag,
441 const Rsp& min, const Rsp& max, Rsp &rsp,
442 bool missing_ok = false) const
443 {
444 std::string str_val;
445 if (!getValue(section, tag, str_val))
446 {
447 return missing_ok;
448 }
449 std::stringstream ssval(str_val);
450 Rsp tmp;
451 ssval >> tmp;
452 if(!ssval.eof())
453 {
454 ssval >> std::ws;
455 }
456 if (ssval.fail() || !ssval.eof() || (tmp < min) || (tmp > max))
457 {
458 return false;
459 }
460 rsp = tmp;
461 return true;
462 } /* Config::getValue */
463
480 template <typename F=std::function<void(const char*)>>
481 void subscribeValue(const std::string& section, const std::string& tag,
482 const char* def, F func)
483 {
484 subscribeValue(section, tag, std::string(def),
485 [=](const std::string& str_val) -> void
486 {
487 func(str_val.c_str());
488 });
489 } /* subscribeValue */
490
507 template <typename Rsp, typename F=std::function<void(const Rsp&)>>
508 void subscribeValue(const std::string& section, const std::string& tag,
509 const Rsp& def, F func)
510 {
511 Value& v = getValueP(section, tag, def);
512 v.subs.push_back(
513 [=](const std::string& str_val) -> void
514 {
515 std::stringstream ssval(str_val);
516 ssval.imbue(std::locale(ssval.getloc(), new empty_ctype));
517 Rsp tmp;
518 ssval >> tmp;
519 func(tmp);
520 });
521 v.subs.back()(v.val);
522 } /* subscribeValue */
523
540 template <template <typename, typename> class Container,
541 typename Rsp, typename F=std::function<void(const Rsp&)>>
542 void subscribeValue(const std::string& section, const std::string& tag,
543 const Container<Rsp, std::allocator<Rsp>>& def, F func)
544 {
545 Value& v = getValueP(section, tag, def);
546 v.subs.push_back(
547 [=](const std::string& str_val) -> void
548 {
549 std::stringstream ssval(str_val);
550 ssval.imbue(std::locale(ssval.getloc(), new csv_whitespace));
551 Container<Rsp, std::allocator<Rsp>> c;
552 while (!ssval.eof())
553 {
554 Rsp tmp;
555 ssval >> tmp;
556 if(!ssval.eof())
557 {
558 ssval >> std::ws;
559 }
560 if (ssval.fail())
561 {
562 return;
563 }
564 c.push_back(tmp);
565 }
566 func(std::move(c));
567 });
568 v.subs.back()(v.val);
569 } /* Config::subscribeValue */
570
575 std::list<std::string> listSections(void);
576
583 std::list<std::string> listSection(const std::string& section);
584
601 void setValue(const std::string& section, const std::string& tag,
602 const std::string& value);
603
621 template <typename Rsp>
622 void setValue(const std::string& section, const std::string& tag,
623 const Rsp& value)
624 {
625 std::ostringstream ss;
626 ss << value;
627 setValue(section, tag, ss.str());
628 }
629
649 template <template <typename, typename> class Container,
650 typename Rsp>
651 void setValue(const std::string& section, const std::string& tag,
652 const Container<Rsp, std::allocator<Rsp>>& c)
653 {
654 std::ostringstream ss;
655 bool first_val = true;
656 for (const auto& val : c)
657 {
658 if (!first_val)
659 {
660 ss << ",";
661 }
662 first_val = false;
663 ss << val;
664 }
665 setValue(section, tag, ss.str());
666 } /* setValue */
667
677 sigc::signal<void, const std::string&, const std::string&> valueUpdated;
678
679 private:
680 using Subscriber = std::function<void(const std::string&)>;
681 struct Value
682 {
683 std::string val;
684 std::vector<Subscriber> subs;
685 };
686 typedef std::map<std::string, Value> Values;
687 typedef std::map<std::string, Values> Sections;
688
689 // Really wanted to use classic_table() but it returns nullptr on Alpine
690 static const std::ctype<char>::mask* empty_table()
691 {
692 static const auto table_size = std::ctype<char>::table_size;
693 static std::ctype<char>::mask v[table_size];
694 std::fill(&v[0], &v[table_size], 0);
695 return &v[0];
696 }
697
698 struct empty_ctype : std::ctype<char>
699 {
700 static const mask* make_table(void) { return empty_table(); }
701 empty_ctype(std::size_t refs=0) : ctype(make_table(), false, refs) {}
702 };
703
704 struct csv_whitespace : std::ctype<char>
705 {
706 static const mask* make_table()
707 {
708 auto tbl = empty_table();
709 static std::vector<mask> v(tbl, tbl + table_size);
710 v[' '] |= space;
711 v[','] |= space;
712 return &v[0];
713 }
714 csv_whitespace(std::size_t refs=0) : ctype(make_table(), false, refs) {}
715 };
716
717 Sections sections;
718
719 bool parseCfgFile(FILE *file);
720 char *trimSpaces(char *line);
721 char *parseSection(char *line);
722 char *parseDelimitedString(char *str, char begin_tok, char end_tok);
723 bool parseValueLine(char *line, std::string& tag, std::string& value);
724 char *parseValue(char *value);
725 char *translateEscapedChars(char *val);
726
727 template <class T>
728 bool setValueFromString(T& val, const std::string &str) const
729 {
730 std::istringstream ss(str);
731 ss >> std::noskipws >> val;
732 if(!ss.eof())
733 {
734 ss >> std::ws;
735 }
736 return !ss.fail() && ss.eof();
737 }
738
739 template <typename T>
740 Value& getValueP(const std::string& section, const std::string& tag,
741 const T& def)
742 {
743 Values::iterator val_it = sections[section].find(tag);
744 if (val_it == sections[section].end())
745 {
746 setValue(section, tag, def);
747 }
748
749 return sections[section][tag];
750 } /* getValueP */
751
752}; /* class Config */
753
754
755} /* namespace */
756
757#endif /* ASYNC_CONFIG_INCLUDED */
758
759
760
761/*
762 * This file has not been truncated
763 */
764
A class for reading INI-formatted configuration files.
bool getValue(const std::string &section, const std::string &tag, const Rsp &min, const Rsp &max, Rsp &rsp, bool missing_ok=false) const
Get a range checked variable value.
Config(void)
Default constuctor.
std::list< std::string > listSection(const std::string &section)
Return the name of all the tags in the given section.
void setValue(const std::string &section, const std::string &tag, const Container< Rsp, std::allocator< Rsp > > &c)
Set the value of a configuration variable (sequence container)
void subscribeValue(const std::string &section, const std::string &tag, const Rsp &def, F func)
Subscribe to the given configuration variable.
bool getValue(const std::string &section, const std::string &tag, Container< Key, std::less< Key >, std::allocator< Key > > &c, bool missing_ok=false) const
Get the value of the given config variable into keyed container.
bool getValue(const std::string &section, const std::string &tag, Rsp &rsp, bool missing_ok=false) const
Get the value of the given configuration variable.
void subscribeValue(const std::string &section, const std::string &tag, const Container< Rsp, std::allocator< Rsp > > &def, F func)
Subscribe to the given configuration variable (sequence)
bool getValue(const std::string &section, const std::string &tag, Container< Key, T, Compare, Allocator > &c, char sep=':', bool missing_ok=false) const
Get value of given config variable into associative container.
bool open(const std::string &name)
Open the given config file.
bool getValue(const std::string &section, const std::string &tag, Container< Value, std::allocator< Value > > &c, bool missing_ok=false) const
Get the value of the given config variable into container.
~Config(void)
Destructor.
const std::string & getValue(const std::string &section, const std::string &tag) const
Return the string value of the given configuration variable.
void setValue(const std::string &section, const std::string &tag, const Rsp &value)
Set the value of a configuration variable (generic type)
bool getValue(const std::string &section, const std::string &tag, std::string &value, bool missing_ok=false) const
Get the string value of the given configuration variable.
std::list< std::string > listSections(void)
Return the name of all configuration sections.
void setValue(const std::string &section, const std::string &tag, const std::string &value)
Set the value of a configuration variable.
void subscribeValue(const std::string &section, const std::string &tag, const char *def, F func)
Subscribe to the given configuration variable (char*)
sigc::signal< void, const std::string &, const std::string & > valueUpdated
A signal that is emitted when a config value is updated.
Namespace for the asynchronous programming classes.