37 extern char** environ;
43 #if defined(__APPLE__) 44 #include <crt_externs.h> 45 char **environ = NULL;
80 if (c==
'\n')
return C_EOL;
81 if (isspace(c))
return C_SPACE;
82 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z'))
return C_ALPHA;
83 if (isdigit(c))
return C_NUMERIC;
84 if (c ==
'-' || c ==
'_')
return C_DASH;
85 if (c ==
'=')
return C_EQ;
86 if (c ==
'"')
return C_QUOTE;
87 if (c ==
'[')
return C_SQUARE_OPEN;
88 if (c ==
']')
return C_SQUARE_CLOSE;
89 if (c ==
'#')
return C_HASH;
90 if (c ==
'\\')
return C_ESCAPE;
97 Config* Config::m_instance =
nullptr;
99 Config* Config::inst()
101 if (m_instance ==
nullptr)
102 m_instance =
new Config;
107 Config::Config(
const Config & conf)
109 m_conf = conf.m_conf;
110 m_par_lookup = conf.m_par_lookup;
115 if (m_instance ==
this)
116 m_instance =
nullptr;
119 std::ostream & operator <<(std::ostream & out, Config & conf)
121 if (!conf.writeToStream(out, USER)) {
122 conf.sige.emit(
"\nVarconf Error: error while trying to write " 123 "configuration data to output stream.\n");
129 std::istream & operator >>(std::istream & in, Config & conf)
132 conf.parseStream(in, USER);
134 catch (
const ParseError& p) {
135 std::stringstream ss;
136 ss <<
"Varconf Error: parser exception throw while parsing input stream.\n" << p.what();
137 conf.sige.emit(ss.str().c_str());
143 bool operator ==(
const Config & one,
const Config & two)
145 return one.m_conf == two.m_conf && one.m_par_lookup == two.m_par_lookup;
148 void Config::clean(std::string & str)
152 for (
char & i : str) {
155 if (c != C_NUMERIC && c != C_ALPHA && c != C_DASH) {
158 i = (char) tolower(i);
163 bool Config::erase(
const std::string & section,
const std::string & key)
167 m_conf.erase(section);
169 }
else if (find(section, key)) {
170 m_conf[section].erase(key);
178 bool Config::find(
const std::string & section,
const std::string & key)
const 180 auto I = m_conf.find(section);
181 if (I != m_conf.end()) {
185 const sec_map & sectionRef = I->second;
186 auto J = sectionRef.find(key);
187 if (J != sectionRef.end()) {
195 bool Config::findSection(
const std::string & section)
const 197 return find(section);
200 bool Config::findItem(
const std::string & section,
const std::string & key)
const 202 return find(section, key);
205 int Config::getCmdline(
int argc,
char** argv, Scope scope)
209 for (
int i = 1; i < argc; i++) {
210 if (argv[i][0] !=
'-' ) {
214 std::string section, name, value, arg;
215 bool fnd_sec =
false, fnd_nam =
false;
217 if (argv[i][1] ==
'-' && argv[i][2] !=
'\0') {
221 for (
size_t j = 2; j < arg.size(); j++) {
222 if (arg[j] ==
':' && arg[j+1] !=
'\0' && !fnd_sec && !fnd_nam) {
223 section = arg.substr(mark, (j - mark));
227 else if (arg[j] ==
'=' && (j - mark) > 1) {
228 name = arg.substr(mark, (j - mark));
230 value = arg.substr((j + 1), (arg.size() - (j + 1)));
235 if (!fnd_nam && arg.size() != mark) {
236 name = arg.substr(mark, (arg.size() - mark));
239 }
else if (argv[i][1] !=
'-' && argv[i][1] !=
'\0') {
241 auto I = m_par_lookup.find(argv[i][1]);
243 if (I != m_par_lookup.end()) {
244 name = ((*I).second).first;
245 bool needs_value = ((*I).second).second;
248 if ((i+1) < argc && argv[i+1][0] != 0 && argv[i+1][0] !=
'-') {
252 std::stringstream ss;
253 ss <<
"Varconf Warning: short argument \""<< argv[i] <<
"\"" 254 " given on command-line expects a value" 255 " but none was given.";
256 sige.emit(ss.str().c_str());
261 std::stringstream ss;
262 ss <<
"Varconf Warning: short argument \""<<argv[i]<<
"\"" 263 " given on command-line does not exist in" 264 " the lookup table.";
265 sige.emit(ss.str().c_str());
270 setItem(section, name, value, scope);
277 void Config::getEnv(
const std::string & prefix, Scope scope)
279 std::string name, value, section, env;
282 #if defined(__APPLE__) 284 environ = *_NSGetEnviron();
287 for (
size_t i = 0; environ[i] !=
nullptr; i++) {
290 if (env.substr(0, prefix.size()) == prefix) {
291 eq_pos = env.find(
'=');
293 if (eq_pos != std::string::npos) {
294 name = env.substr(prefix.size(), (eq_pos - prefix.size()));
295 value = env.substr((eq_pos + 1), (env.size() - (eq_pos + 1)));
298 name = env.substr(prefix.size(), (env.size() - prefix.size()));
302 setItem(section, name, value, scope);
307 const sec_map & Config::getSection(
const std::string & section)
311 return m_conf[section];
314 Variable Config::getItem(
const std::string & section,
const std::string & key)
const 316 auto I = m_conf.find(section);
317 if (I != m_conf.end()) {
318 auto J = I->second.find(key);
319 if (J != I->second.end()) {
326 const conf_map& Config::getSections()
const 332 void Config::parseStream(std::istream & in, Scope scope)
335 bool escaped =
false;
336 size_t line = 1, col = 0;
337 std::string name, value, section;
338 state_t state = S_EXPECT_NAME;
362 throw ParseError(
"item name", (
int) line, (
int) col);
373 state = S_EXPECT_EOL;
376 throw ParseError(
"']'", (
int) line, (
int) col);
387 state = S_EXPECT_VALUE;
393 throw ParseError(
"'='", (
int) line, (
int) col);
399 state = S_EXPECT_NAME;
410 state = S_EXPECT_VALUE;
413 throw ParseError(
"'='", (
int) line, (
int) col);
426 state = S_QUOTED_VALUE;
430 state = S_EXPECT_NAME;
431 setItem(section, name, value, scope);
436 throw ParseError(
"value", (
int) line, (
int) col);
442 throw ParseError(
"value", (
int) line, (
int) col);
444 state = S_EXPECT_EOL;
445 setItem(section, name, value, scope);
448 state = S_EXPECT_NAME;
449 setItem(section, name, value, scope);
453 setItem(section, name, value, scope);
467 state = S_EXPECT_EOL;
468 setItem(section, name, value, scope);
485 state = S_EXPECT_NAME;
490 throw ParseError(
"end of line", (
int) line, (
int) col);
503 if (state == S_QUOTED_VALUE) {
504 throw ParseError(
"\"", (
int) line, (
int) col);
507 if (state == S_VALUE) {
508 setItem(section, name, value, scope);
509 }
else if (state == S_EXPECT_VALUE) {
510 setItem(section, name,
"", scope);
514 bool Config::readFromFile(
const std::string & filename, Scope scope)
516 std::ifstream fin(filename.c_str());
519 std::stringstream ss;
520 ss <<
"Varconf Error: could not open configuration file" 521 " \""<<filename<<
"\" for input.";
522 sige.emit(ss.str().c_str());
528 parseStream(fin, scope);
530 catch (
const ParseError& p) {
531 std::stringstream ss;
532 ss <<
"Varconf Error: parsing exception thrown while " 533 "parsing \""<<filename<<
"\".\n"<< p.what();
534 sige.emit(ss.str().c_str());
541 void Config::setItem(
const std::string & section,
542 const std::string & key,
543 const Variable & item,
547 std::stringstream ss;
548 ss <<
"Varconf Warning: blank key under section \""<<section<<
"\"" 549 " sent to setItem() method.";
550 sige.emit(ss.str().c_str());
553 std::string sec_clean = section;
554 std::string key_clean = key;
559 item->setScope(scope);
560 std::map<std::string, Variable> & section_map = m_conf[sec_clean];
561 std::map<std::string, Variable>::const_iterator I = section_map.find(key_clean);
562 if (I == section_map.end() || I->second != item) {
563 section_map[key_clean] = item;
567 sigv.emit(sec_clean, key_clean);
568 sigsv.emit(sec_clean, key_clean, *
this);
572 void Config::setParameterLookup(
char s_name,
const std::string & l_name,
bool value)
574 m_par_lookup[s_name] = std::pair<std::string, bool>(l_name, value);
577 bool Config::writeToFile(
const std::string & filename, Scope scope_mask)
const 579 std::ofstream fout(filename.c_str());
582 std::stringstream ss;
583 ss <<
"Varconf Error: could not open configuration file" 584 " \""<< filename <<
"\" for output.";
585 sige.emit(ss.str().c_str());
590 return writeToStream(fout, scope_mask);
593 bool Config::writeToStream(std::ostream & out, Scope scope_mask)
const 595 conf_map::const_iterator I;
596 sec_map::const_iterator J;
598 for (I = m_conf.begin(); I != m_conf.end(); I++) {
599 out << std::endl <<
"[" << (*I).first <<
"]\n\n";
601 for (J = (*I).second.begin(); J != (*I).second.end(); J++) {
602 if (J->second->scope() & scope_mask) {
603 out << (*J).first <<
" = \"" << (*J).second <<
"\"\n";