Skip to content
Snippets Groups Projects
ipaaca-config.cc 6.10 KiB
/*
 * This file is part of IPAACA, the
 *  "Incremental Processing Architecture
 *   for Artificial Conversational Agents".
 *
 * Copyright (c) 2009-2019 Social Cognitive Systems Group
 *                         (formerly the Sociable Agents Group)
 *                         CITEC, Bielefeld University
 *
 * http://opensource.cit-ec.de/projects/ipaaca/
 * http://purl.org/net/ipaaca
 *
 * This file may be licensed under the terms of of the
 * GNU Lesser General Public License Version 3 (the ``LGPL''),
 * or (at your option) any later version.
 *
 * Software distributed under the License is distributed
 * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
 * express or implied. See the LGPL for the specific language
 * governing rights and limitations.
 *
 * You should have received a copy of the LGPL along with this
 * program. If not, go to http://www.gnu.org/licenses/lgpl.html
 * or write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * The development of this software was supported by the
 * Excellence Cluster EXC 277 Cognitive Interaction Technology.
 * The Excellence Cluster EXC 277 is a grant of the Deutsche
 * Forschungsgemeinschaft (DFG) in the context of the German
 * Excellence Initiative.
 */

/**
 * \file   ipaaca-config.cc
 *
 * \brief Source file for IPAACA configuration handling
 *
 * \author Ramin Yaghoubzadeh Torky (ryaghoubzadeh@uni-bielefeld.de)
 * \date   January, 2019
 */

#include <ipaaca/ipaaca.h>

extern char **environ;

namespace ipaaca {

template<>
int Config::get_with_default_internal<int>(const std::string& key, int const& default_value, bool warn)
{
    auto it = _data.find(key);
    if (it==_data.end()) {
        config_key_not_found(key, default_value, warn);
        return default_value;
    }
    std::size_t processed;
    int res = std::stoi(it->second, &processed);
    if (processed != it->second.size()) {
        config_conversion_failed(key, default_value);
        return default_value;
    }
    return res;
}
template<>
std::string Config::get_with_default_internal<std::string>(const std::string& key, std::string const& default_value, bool warn)
{
    auto it = _data.find(key);
    if (it==_data.end()) {
        config_key_not_found(key, default_value, warn);
        return default_value;
    }
    return it->second;
}

Config::ptr get_global_config(bool auto_parse_on_demand){
    static bool first = true;
    static Config::ptr global_config = std::make_shared<Config>();
    if (first) {
        first = false;
        IPAACA_DEBUG("This is IPAACA-C++ version " << IPAACA_PROTOCOL_VERSION_MAJOR << "." << IPAACA_PROTOCOL_VERSION_MINOR << " (release " << IPAACA_CPP_RELEASE_NUMBER << " with nominal release date " << IPAACA_CPP_RELEASE_DATE << ") - library compiled on " << __DATE__)
        if (auto_parse_on_demand) {
            IPAACA_DEBUG("Populating global configuration from default sources")
            global_config->populate_from_global_sources();
        }
    }
    return global_config;
}
void Config::populate_from_global_sources()
{
    _messages_delivered.clear(); // message variable warnings
    populate_from_any_conf_files();
    populate_from_environment();
}
bool Config::get_key_and_value(const std::string& s, std::string& key, std::string& value)
{
    bool good = true;
    size_t pos = 0;
    for (pos=0; pos<s.size(); ++pos) {
        auto c = s[pos]; //std::tolower(s[pos]);
        if (c=='=') {
            value = ipaaca::str_trim(s.substr(pos+1));
            break;
        } else if (c=='_') {
            key += '.';
        } else if (c=='.') {
            key += '.';
        } else if ((c>='a')&&(c<='z')) {
            key += c;
        } else if ((c>='A')&&(c<='Z')) {
            key += (c+32);
        } else {
            good = false;
            break;
        }
    }
    if (!good) {
        IPAACA_ERROR("Malformed configuration ignored: " << s.substr(0, pos+1))
    }
    return good;
}
void Config::populate_from_environment()
{
    int i = 1;
    char* envline = *environ;
    while (envline) {
        if(strncmp(envline, "IPAACA_", 7) == 0) {
            if (strlen(envline) > 1023) {
                IPAACA_ERROR("Ignoring overly long environment entry starting with IPAACA_")
            } else {
                std::string s(envline);
                s = s.substr(7);
                std::string key("");
                std::string value("");
                bool good = get_key_and_value(s, key, value);
                if (good) {
                    IPAACA_INFO("Configuration set from environment: " << key << "=\"" << value << "\"");
                    _data[key] = value;
                }
            }
        }
        envline = *(environ+i);
        i++;
    }
}
void Config::populate_from_any_conf_files()
{
    std::fstream f1;
    f1.open("ipaaca.conf", std::fstream::in);
    bool had_file = false;
    if (f1.is_open()) {
        IPAACA_DEBUG("Including configuration from ./ipaaca.conf")
        populate_from_conf_file(f1);
        f1.close();
        had_file = true;
    } else {
        std::fstream f2;
		char* homedir = std::getenv("HOME"); // TODO: windows
		if (homedir) {
			std::string conf_in_home(homedir);
			conf_in_home += "/.config/ipaaca.conf";
			f2.open(conf_in_home, std::fstream::in);
			if (f2.is_open()) {
				IPAACA_DEBUG("Including configuration from ~/.config/ipaaca.conf")
					populate_from_conf_file(f2);
				f2.close();
				had_file = true;
			}
		}
    }
    if (!had_file) {
        IPAACA_INFO("Could not load ipaaca.conf either here or in ~/.config")
    }
}
void Config::populate_from_conf_file(std::fstream& fs)
{
    std::string line;
    while (std::getline(fs, line)) {
        //std::cout << "--->  " << line << std::endl;
        line = ipaaca::str_trim(line);
        std::string key("");
        std::string value("");
        if ((line.length() > 0) && (line[0] != '#') && (line[0] != '[')) {
            bool good = get_key_and_value(line, key, value);
            if (good) {
                IPAACA_INFO("Configuration set from conf file: " << key << "=\"" << value << "\"");
                _data[key] = value;
            }
        }
    }
}

} // of namespace ipaaca