summaryrefslogtreecommitdiff
path: root/src/config/config.cpp
blob: 2f64b9ece7ccdc64972bbb446927529b917076b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <config/config.hpp>
#include <utils/tolower.hpp>
#include <utils/split.hpp>

#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <vector>

using namespace std::string_literals;

extern char** environ;

std::string Config::filename{};
std::map<std::string, std::string> Config::values{};
std::vector<t_config_changed_callback> Config::callbacks{};

std::string Config::get(const std::string& option, const std::string& def)
{
  auto it = Config::values.find(option);

  if (it == Config::values.end())
    return def;
  return it->second;
}

bool Config::get_bool(const std::string& option, const bool def)
{
  auto res = Config::get(option, "");
  if (res.empty())
    return def;
  return res == "true";
}

int Config::get_int(const std::string& option, const int& def)
{
  std::string res = Config::get(option, "");
  if (!res.empty())
    return std::atoi(res.c_str());
  else
    return def;
}

bool Config::is_in_list(const std::string& option, const std::string& value)
{
  std::string res = Config::get(option, "");
  if (res.empty())
    return false;
  std::vector<std::string> list = utils::split(res, ':');
  return std::find(list.cbegin(), list.cend(), value) != list.cend();
}

void Config::set(const std::string& option, const std::string& value, bool save)
{
  Config::values[option] = value;
  if (save)
    {
      Config::save_to_file();
      Config::trigger_configuration_change();
    }
}

void Config::connect(const t_config_changed_callback& callback)
{
    Config::callbacks.push_back(callback);
}

void Config::clear()
{
  Config::values.clear();
}

/**
 * Private methods
 */
void Config::trigger_configuration_change()
{
  std::vector<t_config_changed_callback>::iterator it;
  for (it = Config::callbacks.begin(); it < Config::callbacks.end(); ++it)
      (*it)();
}

bool Config::read_conf(const std::string& name)
{
  if (!name.empty())
    Config::filename = name;

  std::ifstream file(Config::filename.data());
  if (!file.is_open())
    {
      std::cerr << "Error while opening file " << filename << " for reading: " << strerror(errno) << std::endl;
      return false;
    }

  Config::clear();

  auto parse_line = [](const std::string& line, const bool env)
  {
    static const auto env_option_prefix = "BIBOUMI_"s;

    if (line == "" || line[0] == '#')
      return;
    size_t pos = line.find('=');
    if (pos == std::string::npos)
      return;
    std::string option = line.substr(0, pos);
    std::string value = line.substr(pos+1);
    if (env)
      {
        auto a = option.substr(0, env_option_prefix.size());
        if (a == env_option_prefix)
          option = utils::tolower(option.substr(env_option_prefix.size()));
        else
          return;
      }
    Config::values[option] = value;
  };

  std::string line;
  while (file.good())
    {
      std::getline(file, line);
      parse_line(line, false);
    }

  char** env_line = environ;
  while (*env_line)
    {
      parse_line(*env_line, true);
      env_line++;
    }
  return true;
}

void Config::save_to_file()
{
  std::ofstream file(Config::filename.data());
  if (file.fail())
    {
      std::cerr << "Could not save config file." << std::endl;
      return ;
    }
  for (const auto& it: Config::values)
    file << it.first << "=" << it.second << '\n';
}