35 #define snprintf _snprintf
38 extern char** environ;
44 #if defined(__APPLE__)
45 #include <crt_externs.h>
46 char **environ = NULL;
81 if (c==
'\n')
return C_EOL;
82 if (isspace(c))
return C_SPACE;
83 if ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z'))
return C_ALPHA;
84 if (isdigit(c))
return C_NUMERIC;
85 if (c ==
'-' || c ==
'_')
return C_DASH;
86 if (c ==
'=')
return C_EQ;
87 if (c ==
'"')
return C_QUOTE;
88 if (c ==
'[')
return C_SQUARE_OPEN;
89 if (c ==
']')
return C_SQUARE_CLOSE;
90 if (c ==
'#')
return C_HASH;
91 if (c ==
'\\')
return C_ESCAPE;
98 Config* Config::m_instance =
nullptr;
100 Config* Config::inst()
102 if (m_instance ==
nullptr)
103 m_instance =
new Config;
108 Config::Config(
const Config & conf)
110 m_conf = conf.m_conf;
111 m_par_lookup = conf.m_par_lookup;
116 if (m_instance ==
this)
117 m_instance =
nullptr;
120 std::ostream & operator <<(std::ostream & out, Config & conf)
122 if (!conf.writeToStream(out, USER)) {
123 conf.sige.emit(
"\nVarconf Error: error while trying to write "
124 "configuration data to output stream.\n");
130 std::istream & operator >>(std::istream & in, Config & conf)
133 conf.parseStream(in, USER);
135 catch (
const ParseError& p) {
137 std::string p_str = p;
138 snprintf(buf, 1024,
"\nVarconf Error: parser exception throw while "
139 "parsing input stream.\n%s", p_str.c_str());
146 bool operator ==(
const Config & one,
const Config & two)
148 return one.m_conf == two.m_conf && one.m_par_lookup == two.m_par_lookup;
151 void Config::clean(std::string & str)
155 for (
char & i : str) {
158 if (c != C_NUMERIC && c != C_ALPHA && c != C_DASH) {
161 i = (char) tolower(i);
166 bool Config::erase(
const std::string & section,
const std::string & key)
170 m_conf.erase(section);
172 }
else if (find(section, key)) {
173 m_conf[section].erase(key);
181 bool Config::find(
const std::string & section,
const std::string & key)
const
183 auto I = m_conf.find(section);
184 if (I != m_conf.end()) {
188 const sec_map & sectionRef = I->second;
189 auto J = sectionRef.find(key);
190 if (J != sectionRef.end()) {
198 bool Config::findSection(
const std::string & section)
const
200 return find(section);
203 bool Config::findItem(
const std::string & section,
const std::string & key)
const
205 return find(section, key);
208 int Config::getCmdline(
int argc,
char** argv, Scope scope)
212 for (
int i = 1; i < argc; i++) {
213 if (argv[i][0] !=
'-' ) {
217 std::string section, name, value, arg;
218 bool fnd_sec =
false, fnd_nam =
false;
220 if (argv[i][1] ==
'-' && argv[i][2] !=
'\0') {
224 for (
size_t j = 2; j < arg.size(); j++) {
225 if (arg[j] ==
':' && arg[j+1] !=
'\0' && !fnd_sec && !fnd_nam) {
226 section = arg.substr(mark, (j - mark));
230 else if (arg[j] ==
'=' && (j - mark) > 1) {
231 name = arg.substr(mark, (j - mark));
233 value = arg.substr((j + 1), (arg.size() - (j + 1)));
238 if (!fnd_nam && arg.size() != mark) {
239 name = arg.substr(mark, (arg.size() - mark));
242 }
else if (argv[i][1] !=
'-' && argv[i][1] !=
'\0') {
244 auto I = m_par_lookup.find(argv[i][1]);
246 if (I != m_par_lookup.end()) {
247 name = ((*I).second).first;
248 bool needs_value = ((*I).second).second;
250 if (needs_value && (i+1) < argc && argv[i+1][0] != 0
251 && argv[i+1][0] !=
'-') {
256 snprintf(buf, 1024,
"\nVarconf Warning: short argument \"%s\""
257 " given on command-line expects a value"
258 " but none was given.\n", argv[i]);
264 snprintf(buf, 1024,
"\nVarconf Warning: short argument \"%s\""
265 " given on command-line does not exist in"
266 " the lookup table.\n", argv[i]);
272 setItem(section, name, value, scope);
279 void Config::getEnv(
const std::string & prefix, Scope scope)
281 std::string name, value, section, env;
284 #if defined(__APPLE__)
286 environ = *_NSGetEnviron();
289 for (
size_t i = 0; environ[i] !=
nullptr; i++) {
292 if (env.substr(0, prefix.size()) == prefix) {
293 eq_pos = env.find(
'=');
295 if (eq_pos != std::string::npos) {
296 name = env.substr(prefix.size(), (eq_pos - prefix.size()));
297 value = env.substr((eq_pos + 1), (env.size() - (eq_pos + 1)));
300 name = env.substr(prefix.size(), (env.size() - prefix.size()));
304 setItem(section, name, value, scope);
309 const sec_map & Config::getSection(
const std::string & section)
313 return m_conf[section];
316 Variable Config::getItem(
const std::string & section,
const std::string & key)
const
318 auto I = m_conf.find(section);
319 if (I != m_conf.end()) {
320 auto J = I->second.find(key);
321 if (J != I->second.end()) {
328 const conf_map& Config::getSections()
const
334 void Config::parseStream(std::istream & in, Scope scope)
337 bool escaped =
false;
338 size_t line = 1, col = 0;
339 std::string name, value, section;
340 state_t state = S_EXPECT_NAME;
364 throw ParseError(
"item name", (
int) line, (
int) col);
375 state = S_EXPECT_EOL;
378 throw ParseError(
"']'", (
int) line, (
int) col);
389 state = S_EXPECT_VALUE;
395 throw ParseError(
"'='", (
int) line, (
int) col);
401 state = S_EXPECT_NAME;
412 state = S_EXPECT_VALUE;
415 throw ParseError(
"'='", (
int) line, (
int) col);
428 state = S_QUOTED_VALUE;
432 state = S_EXPECT_NAME;
433 setItem(section, name, value, scope);
438 throw ParseError(
"value", (
int) line, (
int) col);
444 throw ParseError(
"value", (
int) line, (
int) col);
446 state = S_EXPECT_EOL;
447 setItem(section, name, value, scope);
450 state = S_EXPECT_NAME;
451 setItem(section, name, value, scope);
455 setItem(section, name, value, scope);
469 state = S_EXPECT_EOL;
470 setItem(section, name, value, scope);
487 state = S_EXPECT_NAME;
492 throw ParseError(
"end of line", (
int) line, (
int) col);
505 if (state == S_QUOTED_VALUE) {
506 throw ParseError(
"\"", (
int) line, (
int) col);
509 if (state == S_VALUE) {
510 setItem(section, name, value, scope);
511 }
else if (state == S_EXPECT_VALUE) {
512 setItem(section, name,
"", scope);
516 bool Config::readFromFile(
const std::string & filename, Scope scope)
518 std::ifstream fin(filename.c_str());
522 snprintf(buf, 1024,
"\nVarconf Error: could not open configuration file"
523 " \"%s\" for input.\n", filename.c_str());
530 parseStream(fin, scope);
532 catch (
const ParseError& p) {
534 std::string p_str = p;
535 snprintf(buf, 1024,
"\nVarconf Error: parsing exception thrown while "
536 "parsing \"%s\".\n%s", filename.c_str(), p_str.c_str());
544 void Config::setItem(
const std::string & section,
545 const std::string & key,
546 const Variable & item,
551 snprintf(buf, 1024,
"\nVarconf Warning: blank key under section \"%s\""
552 " sent to setItem() method.\n", section.c_str());
556 std::string sec_clean = section;
557 std::string key_clean = key;
562 item->setScope(scope);
563 std::map<std::string, Variable> & section_map = m_conf[sec_clean];
564 std::map<std::string, Variable>::const_iterator I = section_map.find(key_clean);
565 if (I == section_map.end() || I->second != item) {
566 section_map[key_clean] = item;
570 sigv.emit(sec_clean, key_clean);
571 sigsv.emit(sec_clean, key_clean, *
this);
575 void Config::setParameterLookup(
char s_name,
const std::string & l_name,
bool value)
577 m_par_lookup[s_name] = std::pair<std::string, bool>(l_name, value);
580 bool Config::writeToFile(
const std::string & filename, Scope scope_mask)
const
582 std::ofstream fout(filename.c_str());
586 snprintf(buf, 1024,
"\nVarconf Error: could not open configuration file"
587 " \"%s\" for output.\n", filename.c_str());
593 return writeToStream(fout, scope_mask);
596 bool Config::writeToStream(std::ostream & out, Scope scope_mask)
const
598 conf_map::const_iterator I;
599 sec_map::const_iterator J;
601 for (I = m_conf.begin(); I != m_conf.end(); I++) {
602 out << std::endl <<
"[" << (*I).first <<
"]\n\n";
604 for (J = (*I).second.begin(); J != (*I).second.end(); J++) {
605 if (J->second->scope() & scope_mask) {
606 out << (*J).first <<
" = \"" << (*J).second <<
"\"\n";