diff --git a/inc/ini/ini.h b/inc/ini/ini.h index c95bf7788f2c483b4f61e8ce21844c05e473394c..43a6afdff5dfd0239ca46b333c55ddb5f08a0afb 100644 --- a/inc/ini/ini.h +++ b/inc/ini/ini.h @@ -131,7 +131,7 @@ int ini_parse_string(const char *string, ini_handler handler, void *user); name and value NULL). Default is to only call the handler on each name=value pair. */ #ifndef INI_CALL_HANDLER_ON_NEW_SECTION -#define INI_CALL_HANDLER_ON_NEW_SECTION 1 +#define INI_CALL_HANDLER_ON_NEW_SECTION 0 #endif /* Nonzero to allow a name without a value (no '=' or ':' on the line) and diff --git a/inc/ini/ini.hpp b/inc/ini/ini.hpp deleted file mode 100644 index 763d65a176b9b5a94e136e729301600ec4c9b388..0000000000000000000000000000000000000000 --- a/inc/ini/ini.hpp +++ /dev/null @@ -1,74 +0,0 @@ -// Read an INI file into easy-to-access name/value pairs. - -// SPDX-License-Identifier: BSD-3-Clause - -// Copyright (C) 2009-2020, Ben Hoyt - -// inih and INIReader are released under the New BSD license (see LICENSE.txt). -// Go to the project home page for more info: -// -// https://github.com/benhoyt/inih - -#ifndef __INIREADER_H__ -#define __INIREADER_H__ - -#include <map> -#include <string> - -// Read an INI file into easy-to-access name/value pairs. (Note that I've gone -// for simplicity here rather than speed, but it should be pretty decent.) -class INIReader -{ -public: - // Construct INIReader and parse given filename. See ini.h for more info - // about the parsing. - explicit INIReader(const std::string &filename); - - // Construct INIReader and parse given buffer. See ini.h for more info - // about the parsing. - explicit INIReader(const char *buffer, size_t buffer_size); - - // Return the result of ini_parse(), i.e., 0 on success, line number of - // first error on parse error, or -1 on file open error. - int ParseError() const; - - // Get a string value from INI file, returning default_value if not found. - std::string Get(const std::string §ion, const std::string &name, - const std::string &default_value) const; - - // Get a string value from INI file, returning default_value if not found, - // empty, or contains only whitespace. - std::string GetString(const std::string §ion, const std::string &name, - const std::string &default_value) const; - - // Get an integer (long) value from INI file, returning default_value if - // not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2"). - long GetInteger(const std::string §ion, const std::string &name, long default_value) const; - - // Get a real (floating point double) value from INI file, returning - // default_value if not found or not a valid floating point value - // according to strtod(). - double GetReal(const std::string §ion, const std::string &name, double default_value) const; - - // Get a boolean value from INI file, returning default_value if not found or if - // not a valid true/false value. Valid true values are "true", "yes", "on", "1", - // and valid false values are "false", "no", "off", "0" (not case sensitive). - bool GetBoolean(const std::string §ion, const std::string &name, bool default_value) const; - - // Return true if the given section exists (section must contain at least - // one name=value pair). - bool HasSection(const std::string §ion) const; - - // Return true if a value exists with the given section and field names. - bool HasValue(const std::string §ion, const std::string &name) const; - -private: - int m_error; - std::map<std::string, std::string> m_values; - - static std::string MakeKey(const std::string §ion, const std::string &name); - static int ValueHandler(void *user, const char *section, const char *name, - const char *value); -}; - -#endif // __INIREADER_H__ diff --git a/inc/lektor/config.h b/inc/lektor/config.h index c517b0358036642fb9fb2e6c2c1eb8598e3de089..56c28206b8a2dd70264469a4908fd9005dc42146 100644 --- a/inc/lektor/config.h +++ b/inc/lektor/config.h @@ -1,7 +1,7 @@ #pragma once #include <stddef.h> - +#include <sqlite3.h> static const char *const lkt_default_config_file = "; Lektor's configuration file\n" @@ -52,48 +52,22 @@ static const char *const lkt_default_config_file = "specific_opt1 = 1\n" "specific_opt2 = a string\n"; -typedef void *lkt_config_t; - /* It is just an alias to the consecutive use of config_detect_file and config_new function, with the return an '&&' between the two returns of the two other functions. */ -int config_open(lkt_config_t *conf); +int config_open(sqlite3 *db); /* Get the path to the config file that may be red, taking into account the priority between existing files. The returned path is a path to an existing file. If no file is found, returns a non zero value. Returns 1 otherwise. */ -int config_detect_file(char **conf, size_t conf_len); - -/* Simply free a configuration. */ -void config_free(lkt_config_t *conf); +int config_detect_file(char *conf, size_t conf_len); /* Create and read the configuration in the conf file and write it into lkt_conf. The type is opaque because it's a C++ class. Return 0 if the read operation was a success, a non zero value otherwise. */ -int config_new(const char *conf, lkt_config_t *lkt_conf); +int config_new(sqlite3 *db, const char *conf); /* Load a module by its name. Also initialize the mod pointer. No check on data type is done, it is up to the user to check if the structure passed as a `void*` is the right structure. */ -int load_module_by_name(lkt_config_t conf, const char *name, void *mod); - -/* Get the value of a parameter in the configuration. The value is stored as a - string in the ret pointer. This string will be null-terminated. If the result - is longer than the size of ret (as specified by the max_len) the result will - be truncated to max_len characters including the null termination byte. */ -int config_get(lkt_config_t conf, const char *section, const char *opt, - char *const ret, const size_t max_len); - -/* Get the value of a parameter in the configuration as an integer. If there was - an error return a non zero value. If the value was retrieved without any error - return 0. */ -int config_get_int(lkt_config_t conf, const char *section, const char *opt, int *ret); - -/* Get the value of a parameter. The `char*` will be allocated BY THIS FUNCTION, - do not malloc or calloc the `char *ret` pointer before. - Returns 0 is everything was successfull, a non zero value otherwise. */ -int config_get_alloc(lkt_config_t conf, const char *section, const char *opt, char **ret); - -/* Get the value of a parameter as a boolean. - Returns 0 is everything was successfull, a non zero value otherwise. */ -int config_get_bool(lkt_config_t conf, const char *section, const char *opt, int *ret); +int load_module_by_name(sqlite3 *db, const char *name, void *mod); diff --git a/inc/lektor/database.h b/inc/lektor/database.h index a65a28a94a3ce7c483ba2a9b192ff8fe707491b7..303d8499032baad782b4f1355b3539902ac480c8 100644 --- a/inc/lektor/database.h +++ b/inc/lektor/database.h @@ -32,7 +32,8 @@ struct lkt_queue_state { }; /* Open correctly a database for lektor. */ -bool database_open(sqlite3 **db, const char *dbpath); +bool database_new(sqlite3 **db); +bool database_open(sqlite3 *db, const char *dbpath); /* Get information on the queue and currently playing kara. */ bool database_queue_state(sqlite3 *db, struct lkt_queue_state *res); @@ -98,8 +99,12 @@ bool database_queue_next(sqlite3 *db, char filepath[PATH_MAX]); bool database_queue_prev(sqlite3 *db, char filepath[PATH_MAX]); /* Set a value in the config table */ -bool database_config(sqlite3 *db, const char *option, int value); -bool database_config_default(sqlite3 *db); +bool database_config_set(sqlite3 *db, const char *section, const char *key, const char *value); +bool database_config_get_text(sqlite3 *db, const char *section, const char *key, char *value, size_t len); +bool database_config_get_int(sqlite3 *db, const char *section, const char *key, int *value); +bool database_config_exists(sqlite3 *db, const char *section, const char *key); +bool database_config_queue(sqlite3 *db, const char *option, int value); +bool database_config_queue_default(sqlite3 *db); /* Get a value from the config table */ bool database_get_config(sqlite3 *db, const char *option, int *value); diff --git a/inc/lektor/net.h b/inc/lektor/net.h index c1ce1b2031b62544440422b06de4b6a47790d3b4..c4f3d86d77c1d9393dc3b1903e955226b2dfd29f 100644 --- a/inc/lektor/net.h +++ b/inc/lektor/net.h @@ -76,4 +76,4 @@ long long int *lkt_client_get_mask(struct lkt_state *srv, size_t c); bool lkt_client_auth(struct lkt_state *srv, size_t c, bool set_auth); /* The server's listen function. */ -int lkt_listen(lkt_config_t conf); +int lkt_listen(void); diff --git a/meson.build b/meson.build index 5a881e22ab03d0a8cc817d85fe770aa70ff49c1b..bf5f440b7dd10c788043d30b27eef1327e540446 100644 --- a/meson.build +++ b/meson.build @@ -13,12 +13,9 @@ project( 'lektor' ] ) -add_languages('cpp', required : true, native : false) add_project_arguments('-march=native', language : 'c') -add_project_arguments('-march=native', language : 'cpp') cc = meson.get_compiler('c') -cxx = meson.get_compiler('cpp') libdl = cc.find_library('dl') dep_x11 = dependency('x11', required : false) dep_mpv = dependency('mpv', required : false) @@ -40,11 +37,10 @@ core_sources = [ 'src/mkv/bufferfd.c' , 'src/net/command.c' , 'src/net/listen.c' , 'src/net/message.c' - , 'src/config.cpp' + , 'src/config.c' , 'src/utils.c' , 'src/uri.c' , 'src/ini/ini.c' - , 'src/ini/ini.cpp' , 'src/repo/curl.c' , 'src/repo/async.c' , 'src/thread.c' diff --git a/src/commands.c b/src/commands.c index b0db806537bf457c157122d91a7502f7404e98a2..32565f6f04cce2add02f670400e3232a90ab97ff 100644 --- a/src/commands.c +++ b/src/commands.c @@ -725,19 +725,19 @@ command_set_playback_option(struct lkt_state *srv, size_t c, switch (opt) { case lkt_playback_option_random: - ret = database_config(srv->db, "random", val); + ret = database_config_queue(srv->db, "random", val); break; case lkt_playback_option_single: - ret = database_config(srv->db, "single", val); + ret = database_config_queue(srv->db, "single", val); break; case lkt_playback_option_consume: - ret = database_config(srv->db, "consume", val); + ret = database_config_queue(srv->db, "consume", val); break; case lkt_playback_option_repeat: - ret = database_config(srv->db, "repeat", val); + ret = database_config_queue(srv->db, "repeat", val); break; case lkt_playback_option_volume: - ret = database_config(srv->db, "volume", val); + ret = database_config_queue(srv->db, "volume", val); fprintf(stderr, " . command_set_playback_option: set volume to %ld\n", val); ret &= win->set_volume(win, val); srv->mpd_idle_events |= MPD_IDLE_MIXER; diff --git a/src/config.c b/src/config.c new file mode 100644 index 0000000000000000000000000000000000000000..5df978b5ab42d01a0f44ab72695963bc9c7e404d --- /dev/null +++ b/src/config.c @@ -0,0 +1,210 @@ +#define _POSIX_C_SOURCE 200809L + +#include <lektor/config.h> +#include <lektor/database.h> +#include <ini/ini.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <dlfcn.h> +#include <stdio.h> +#include <pwd.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <limits.h> + +static inline int +load_so(const char *const mod_path, const char *const mod_init, void *mod) +{ + /* An init function takes two arguments: the module pointer and a void* + which is the handler for the .so file. It the role of the module to + store the handle pointer. + Uppon successfull completion, the function shall return 0, and return + a non zero value if something bad happened. */ + int (*module_set_function)(void *const, void *const); + char *error; + void *handle = dlopen(mod_path, RTLD_NOW); + + if (NULL == handle) { + fprintf(stderr, " ! load_so: libdl error in dlopen: %s\n", dlerror()); + return 1; + } + + dlerror(); + *(void **) (&module_set_function) = dlsym(handle, mod_init); + + if ((error = dlerror()) != NULL) { + fprintf(stderr, " ! load_so: libdl error in dlsym: %s\n", error); + return 1; + } + + return ! module_set_function(mod, handle); +} + +inline int +load_module_by_name(sqlite3 *db, const char *name, void *mod) +{ + char mod_path[PATH_MAX], mod_load[INI_MAX_LINE]; + + if (!database_config_get_text(db, name, "path", mod_path, PATH_MAX) || + !database_config_get_text(db, name, "load_function", mod_load, INI_MAX_LINE)) { + fprintf(stderr, " ! load_module_by_name: Module named %s is incomplete or is not " + "defined in config file", name); + return 1; + } + + return load_so(mod_path, mod_load, mod); +} + +inline static int +validate_conf(sqlite3 *db) +{ +#define CHK_OPTION(section, name) \ + if (!database_config_exists(db, section, name)) { \ + fprintf(stderr, " ! validate_conf: Missing option " name " in section " section "\n"); \ + return 1; \ + } + + CHK_OPTION("externals", "mkvpropedit"); + CHK_OPTION("externals", "sqlite3"); + + CHK_OPTION("server", "host"); + CHK_OPTION("server", "port"); + CHK_OPTION("server", "max_clients"); + + CHK_OPTION("player", "module"); + CHK_OPTION("player", "autoclear"); + CHK_OPTION("player", "def_random"); + CHK_OPTION("player", "def_consume"); + CHK_OPTION("player", "def_single"); + CHK_OPTION("player", "def_repeat"); + + CHK_OPTION("database", "kara_dir"); + CHK_OPTION("database", "db_path"); + + return 0; +} + +static int +#if INI_HANDLER_LINENO +handler(void *user, const char *section, const char *name, const char *value, int lineno) +{ + (void) lineno; +#else +handler(void *user, const char *section, const char *name, const char *value) +{ +#endif + if (!section || !name || !value) { + fprintf(stderr, " . handler: I can't complete the database with incomplete lines\n"); + return 1; + } + + if (!database_config_set(user, section, name, value)) { + fprintf(stderr, " . handler: Failed to update the database\n"); + return 0; + } + + return 1; +} + +int +config_detect_file(char *conf, size_t conf_len) +{ + bool is_malloc = false; + struct passwd *pw = getpwuid(getuid()); + char *home; + + if (conf == NULL) + return 1; + + memset(conf, 0, conf_len * sizeof(char)); + + /* Try the current working dir config file. */ + if (getcwd(conf, conf_len - 1) != NULL) { + strncat(conf, "/lektor.ini", conf_len - 1); + fprintf(stderr, " . config_detect_file: trying %s\n", conf); + if (!access(conf, R_OK)) + goto found; + } + + /* Try the config file from the config directory. */ + home = getenv("XDG_CONFIG_HOME"); + if (!home || (strlen(home) >= conf_len)) + home = getenv("HOME"); + if (!home || (strlen(home) >= conf_len)) + home = pw->pw_dir; + if (!home || (strlen(home) >= conf_len)) + goto no_config_directory; + memcpy(conf, home, (strlen(home) + 1) * sizeof(char)); + strncat(conf, "/.config/lektor/lektor.ini", conf_len - 1); + fprintf(stderr, " . config_detect_file: trying %s\n", conf); + if (!access(conf, R_OK | F_OK)) + goto found; + +no_config_directory: + /* Try the '/opt/lektor' file. */ + memcpy(conf, "/opt/lektor/lektor.ini", sizeof("/opt/lektor/lektor.ini")); + fprintf(stderr, " . config_detect_file: trying %s\n", conf); + if (!access(conf, R_OK)) + goto found; + + /* Try the '/usr/local/etc/lektor.ini' file. */ + memcpy(conf, "/usr/local/etc/lektor.ini", sizeof("/opt/lektor/lektor.ini")); + fprintf(stderr, " . config_detect_file: trying %s\n", conf); + if (!access(conf, R_OK)) + goto found; + + /* Try the '/etc/lektor.ini' file. */ + memcpy(conf, "/etc/lektor.ini", sizeof("/etc/lektor.ini")); + fprintf(stderr, " . config_detect_file: trying %s\n", conf); + if (!access(conf, R_OK)) + goto found; + + /* Error */ + fprintf(stderr, "config_detect_file: an error occured with file %s: %s", + conf, strerror(errno)); + if (is_malloc) + free(conf); + return 1; +found: + fprintf(stderr, " . config_detect_file: using file %s\n", conf); + return 0; +} + +int +config_new(sqlite3 *db, const char *conf) +{ + if (ini_parse(conf, handler, db)) { + fprintf(stderr, " . config_new: Failed to parse file %s\n", conf); + return 1; + } + + if (validate_conf(db)) { + fprintf(stderr, " . config_new: Configuration file %s is incomplete\n", conf); + return 1; + } + + return 0; +} + +int +config_open(sqlite3 *db) +{ + char conf_file[PATH_MAX]; + int ret = 1; + + if (config_detect_file(conf_file, PATH_MAX)) { + fprintf(stderr, " ! config_open: error while searching for a config file\n"); + goto error; + } + + if (config_new(db, conf_file)) { + fprintf(stderr, " ! config_open: failed to read configuration file\n"); + goto error; + } + + ret = 0; +error: + return ret; +} diff --git a/src/config.cpp b/src/config.cpp deleted file mode 100644 index e5dfb425216d6b66ffd9ccd916102a1684c1a358..0000000000000000000000000000000000000000 --- a/src/config.cpp +++ /dev/null @@ -1,393 +0,0 @@ -#define _POSIX_C_SOURCE 200809L - -/* Perform includes. */ - -extern "C" -{ -#include <lektor/config.h> -#include <dlfcn.h> -#include <stdio.h> -#include <pwd.h> -#include <unistd.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <errno.h> -#include <stdlib.h> -#include <limits.h> -} - -#include <ini/ini.hpp> -#include <string> -#include <cstring> - -/* Function to load a .so as a lektor's module. */ -extern "C" inline int -load_so(const char *const mod_path, const char *const mod_init, void *mod) -{ - /* An init function takes two arguments: the module pointer and a void* - which is the handler for the .so file. It the role of the module to - store the handle pointer. - Uppon successfull completion, the function shall return 0, and return - a non zero value if something bad happened. */ - int (*module_set_function)(void *const, void *const); - char *error; - void *handle = dlopen(mod_path, RTLD_NOW); - - if (NULL == handle) { - fprintf(stderr, " ! load_so: libdl error in dlopen: %s\n", dlerror()); - return 1; - } - - dlerror(); - *(void **) (&module_set_function) = dlsym(handle, mod_init); - - if ((error = dlerror()) != NULL) { - fprintf(stderr, " ! load_so: libdl error in dlsym: %s\n", error); - return 1; - } - - return ! module_set_function(mod, handle); -} - -/* Real functions here, C++ functions. */ - -inline static void -__config_free(lkt_config_t *conf) -{ - delete reinterpret_cast<INIReader *>(*conf); - *conf = nullptr; -} - -inline static int -validate_conf(const INIReader *const ini) -{ - /* Check for mendatory sections. */ -#define CHK_SECTION(name) \ - if (!ini->HasSection(name)) \ - { \ - fprintf(stderr, " ! validate_conf: missing section %s\n", name); \ - return 1; \ - } - - CHK_SECTION("externals"); - CHK_SECTION("server"); - CHK_SECTION("player"); - CHK_SECTION("database"); - - /* Check for mendatory options. */ - -#define CHK_OPTION(section, name) \ - if (!ini->HasValue(section, name)) \ - { \ - fprintf(stderr, " ! validate_conf: missing option %s in section %s\n", name, section); \ - return 1; \ - } - - CHK_OPTION("externals", "mkvpropedit"); - CHK_OPTION("externals", "sqlite3"); - - CHK_OPTION("server", "host"); - CHK_OPTION("server", "port"); - CHK_OPTION("server", "max_clients"); - - CHK_OPTION("player", "module"); - CHK_OPTION("player", "autoclear"); - CHK_OPTION("player", "def_random"); - CHK_OPTION("player", "def_consume"); - CHK_OPTION("player", "def_single"); - CHK_OPTION("player", "def_repeat"); - - CHK_OPTION("database", "kara_dir"); - CHK_OPTION("database", "db_path"); - - /* Everything is OK. */ - - return 0; -} - -inline static int -__config_new(const char *conf, lkt_config_t *lkt_conf) -{ - INIReader *ini = nullptr; - int status; - - try { - ini = new INIReader(std::string(conf)); - *lkt_conf = ini; - } catch (...) { - return 1; - } - - /* Is parsing OK? */ - - status = ini->ParseError(); - - if (status == -1) { - fprintf(stderr, " ! config_new: could not read file %s\n", conf); - return 1; - } - - if (status > 0) { - fprintf(stderr, " ! config_new: error on line %d in file %s\n", status, conf); - return 1; - } - - /* We need some basic options to be happy here. */ - - if (validate_conf(ini)) { - fprintf(stderr, " ! config_new: some basic options are missing in file %s\n", conf); - return 2; - } - - /* Now everything is OK. */ - - return 0; -} - -inline static int -__load_module_by_name(lkt_config_t const conf, const char *name, void *mod) -{ - INIReader *ini = reinterpret_cast<INIReader *>(conf); - - if (!ini->HasSection(name)) { - fprintf(stderr, " ! load_module_by_name: No module named %s in the conf file\n", name); - return 1; - } - - std::string mod_path = ini->GetString(name, "path", ""); - std::string mod_load = ini->GetString(name, "load_function", ""); - - if (mod_path.empty() || mod_load.empty()) { - fprintf(stderr, " ! load_module_by_name: " - "options 'path' and 'load_function' may be absent or empty " - "in the section %s\n", name); - return 2; - } - - return load_so(mod_path.c_str(), mod_load.c_str(), mod); -} - -static int -__config_get(lkt_config_t conf, const char *section, const char *opt, - char *const ret, const size_t max_len) -{ - INIReader *ini = reinterpret_cast<INIReader *>(conf); - - if (!ini->HasValue(section, opt)) - return 1; - - std::string value = ini->GetString(section, opt, ""); - - if (value.empty()) - return 2; - - size_t max_idx = std::min(value.size() + 1, max_len); - ret[max_idx] = 0; - memcpy(ret, value.c_str(), (max_idx - 1) * sizeof(char)); - - return 0; -} - -static int -__config_get(lkt_config_t conf, const char *section, const char *opt, - int *const ret) -{ - INIReader *ini = reinterpret_cast<INIReader *>(conf); - - if (!ini->HasValue(section, opt)) - return 1; - - std::string value = ini->GetString(section, opt, ""); - - if (value.empty()) - return 2; - - try { - *ret = std::stoi(value, /* start index */ 0, /* autotedect the base */ 0); - } catch (...) { - return 3; - } - - return 0; -} - -static int -__config_get(lkt_config_t conf, const char *section, const char *opt, - bool *const ret) -{ - INIReader *ini = reinterpret_cast<INIReader *>(conf); - - if (!ini->HasValue(section, opt)) - return 1; - - *ret = ini->GetBoolean(section, opt, false); - return 0; -} - -static int -__config_get(lkt_config_t conf, const char *section, const char *opt, char **ret) -{ - INIReader *ini = reinterpret_cast<INIReader *>(conf); - - if (!ini->HasValue(section, opt)) - return 1; - - std::string value = ini->GetString(section, opt, ""); - - if (value.empty()) - return 2; - - size_t max_idx = value.size(); - - /* Yes, use calloc here. */ - *ret = reinterpret_cast<char *>(calloc(max_idx + 1, sizeof(char))); - (*ret)[max_idx] = 0; - memcpy(*ret, value.c_str(), max_idx * sizeof(char)); - - return 0; -} - -/* Bindings to C functions. */ - -extern "C" -{ - void - config_free(lkt_config_t *conf) - { - __config_free(conf); - } - - int - config_new(const char *conf, lkt_config_t *lkt_conf) - { - return __config_new(conf, lkt_conf); - } - - int - load_module_by_name(lkt_config_t conf, const char *name, void *mod) - { - return __load_module_by_name(conf, name, mod); - } - - int - config_get(lkt_config_t conf, const char *section, const char *opt, - char *const ret, const size_t max_len) - { - return __config_get(conf, section, opt, ret, max_len); - } - - int - config_get_int(lkt_config_t conf, const char *section, const char *opt, int *ret) - { - return __config_get(conf, section, opt, ret); - } - - int - config_get_alloc(lkt_config_t conf, const char *section, const char *opt, char **ret) - { - return __config_get(conf, section, opt, ret); - } - - int - config_get_bool(lkt_config_t conf, const char *section, const char *opt, int *ret) - { - bool ret__ = false; - int status = __config_get(conf, section, opt, &ret__); - *ret = ret__; - return status; - } - - int - config_detect_file(char **conf, size_t conf_len) - { - bool is_malloc = false; - struct passwd *pw = getpwuid(getuid()); - char *home; - - if (conf == NULL) - return 1; - - if (*conf == NULL) { - *conf = (char *) calloc(conf_len, sizeof(char)); - - if (!*conf) - return ENOMEM; - } - - memset(*conf, 0, conf_len * sizeof(char)); - - /* Try the current working dir config file. */ - if (getcwd(*conf, conf_len - 1) != NULL) { - strncat(*conf, "/lektor.ini", conf_len - 1); - fprintf(stderr, " . config_detect_file: trying %s\n", *conf); - if (!access(*conf, R_OK)) - goto found; - } - - /* Try the config file from the config directory. */ - home = getenv("XDG_CONFIG_HOME"); - if (!home || (strlen(home) >= conf_len)) - home = getenv("HOME"); - if (!home || (strlen(home) >= conf_len)) - home = pw->pw_dir; - if (!home || (strlen(home) >= conf_len)) - goto no_config_directory; - memcpy(*conf, home, (strlen(home) + 1) * sizeof(char)); - strncat(*conf, "/.config/lektor/lektor.ini", conf_len - 1); - fprintf(stderr, " . config_detect_file: trying %s\n", *conf); - if (!access(*conf, R_OK | F_OK)) - goto found; - -no_config_directory: - /* Try the '/opt/lektor' file. */ - memcpy(*conf, "/opt/lektor/lektor.ini", sizeof("/opt/lektor/lektor.ini")); - fprintf(stderr, " . config_detect_file: trying %s\n", *conf); - if (!access(*conf, R_OK)) - goto found; - - /* Try the '/usr/local/etc/lektor.ini' file. */ - memcpy(*conf, "/usr/local/etc/lektor.ini", sizeof("/opt/lektor/lektor.ini")); - fprintf(stderr, " . config_detect_file: trying %s\n", *conf); - if (!access(*conf, R_OK)) - goto found; - - /* Try the '/etc/lektor.ini' file. */ - memcpy(*conf, "/etc/lektor.ini", sizeof("/etc/lektor.ini")); - fprintf(stderr, " . config_detect_file: trying %s\n", *conf); - if (!access(*conf, R_OK)) - goto found; - - /* Error */ - fprintf(stderr, "config_detect_file: an error occured with file %s: %s", - *conf, strerror(errno)); - if (is_malloc) - free(*conf); - return 1; -found: - fprintf(stderr, " . config_detect_file: using file %s\n", *conf); - return 0; - } - - int - config_open(lkt_config_t *conf) - { - char *conf_file = NULL; - int ret = 1; - - if (config_detect_file(&conf_file, PATH_MAX)) { - fprintf(stderr, " ! config_open: error while searching for a config file\n"); - goto error; - } - - if (config_new(conf_file, conf)) { - fprintf(stderr, " ! config_open: failed to read configuration file\n"); - goto error; - } - - ret = 0; -error: - if (conf_file) - free(conf_file); - return ret; - } -} diff --git a/src/database/config.c b/src/database/config.c index 2970a44f60212a311ed3d0d43b3c8c36daa0e0ea..cf4b2eefa9a6e4642639883fe0f435560e01f806 100644 --- a/src/database/config.c +++ b/src/database/config.c @@ -1,11 +1,171 @@ +#define _POSIX_C_SOURCE 200809L + #include <lektor/database.h> -#include <linux/limits.h> +#include <limits.h> #include <stdio.h> #include <string.h> bool -database_config(sqlite3 *db, const char *option, int value) +database_config_set(sqlite3 *db, const char *section, const char *key, const char *value) +{ + static const char *SQL_STMT = + "INSERT OR REPLACE INTO" + " config (section, key, value)" + " VALUES (?, ?, ?);\n"; + sqlite3_stmt *stmt = 0; + bool ret = false; + int code; + + if (sqlite3_prepare_v2(db, SQL_STMT, -1, &stmt, 0) != SQLITE_OK) { + fprintf(stderr, " ! database_config_set: Failed to prepare statement: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + if (sqlite3_bind_text(stmt, 1, section, -1, 0) != SQLITE_OK || + sqlite3_bind_text(stmt, 2, key, -1, 0) != SQLITE_OK || + sqlite3_bind_text(stmt, 3, value, -1, 0) != SQLITE_OK) { + fprintf(stderr, " ! database_config_set: Failed to bind: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + code = sqlite3_step(stmt); + + if (code != SQLITE_OK && code != SQLITE_DONE) { + fprintf(stderr, " ! database_config_set: Failed to insert or replace: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} + +bool +database_config_get_text(sqlite3 *db, const char *section, const char *key, char *value, size_t len) +{ + static const char *SQL_STMT = + "SELECT value" + " FROM config" + " WHERE section = ? AND key = ?;\n"; + sqlite3_stmt *stmt = 0; + bool ret = false; + int code; + char *row; + + if (sqlite3_prepare_v2(db, SQL_STMT, -1, &stmt, 0) != SQLITE_OK) { + fprintf(stderr, " ! database_config_get_text: Failed to prepare statement: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + if (sqlite3_bind_text(stmt, 1, section, -1, 0) != SQLITE_OK || + sqlite3_bind_text(stmt, 2, key, -1, 0) != SQLITE_OK) { + fprintf(stderr, " ! database_config_get_text: Failed to bind: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + code = sqlite3_step(stmt); + + if (code != SQLITE_ROW) { + fprintf(stderr, " ! database_config_get_text: Failed to insert or replace: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + row = (char *) sqlite3_column_text(stmt, 0); + strncpy(value, row, len); + value[len - 1] = 0; + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} + +bool +database_config_exists(sqlite3 *db, const char *section, const char *key) +{ + static const char *SQL_STMT = + "SELECT value" + " FROM config" + " WHERE section = ? AND key = ?;\n"; + sqlite3_stmt *stmt = 0; + bool ret = false; + int code; + + if (sqlite3_prepare_v2(db, SQL_STMT, -1, &stmt, 0) != SQLITE_OK) { + fprintf(stderr, " ! database_config_exists: Failed to prepare statement: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + if (sqlite3_bind_text(stmt, 1, section, -1, 0) != SQLITE_OK || + sqlite3_bind_text(stmt, 2, key, -1, 0) != SQLITE_OK) { + fprintf(stderr, " ! database_config_exists: Failed to bind: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + code = sqlite3_step(stmt); + + if (code != SQLITE_ROW) { + fprintf(stderr, " ! database_config_exists: No rows: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} + +bool +database_config_get_int(sqlite3 *db, const char *section, const char *key, int *value) +{ + static const char *SQL_STMT = + "SELECT CAST(value AS INTEGER)" + " FROM config" + " WHERE section = ? AND key = ?;\n"; + sqlite3_stmt *stmt = 0; + bool ret = false; + int code; + + if (sqlite3_prepare_v2(db, SQL_STMT, -1, &stmt, 0) != SQLITE_OK) { + fprintf(stderr, " ! database_config_get_int: Failed to prepare statement: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + if (sqlite3_bind_text(stmt, 1, section, -1, 0) != SQLITE_OK || + sqlite3_bind_text(stmt, 2, key, -1, 0) != SQLITE_OK) { + fprintf(stderr, " ! database_config_get_int: Failed to bind: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + code = sqlite3_step(stmt); + + if (code != SQLITE_ROW) { + fprintf(stderr, " ! database_config_get_int: Failed to insert or replace: %s\n", + sqlite3_errmsg(db)); + goto error; + } + + *value = sqlite3_column_int(stmt, 1); + ret = true; +error: + sqlite3_finalize(stmt); + return ret; +} + +bool +database_config_queue(sqlite3 *db, const char *option, int value) { static const char *SQL_STMT_TMP = "UPDATE queue_state SET %s = ? WHERE id = 42;"; char SQL_STMT[PATH_MAX]; @@ -41,7 +201,7 @@ error: } bool -database_config_default(sqlite3 *db) +database_config_queue_default(sqlite3 *db) { static const char *SQL_DEFAULT = "UPDATE queue_state SET" diff --git a/src/database/open.c b/src/database/open.c index cdc78a1298e64af7d07f918818f460596a327dc3..b493bf2612155e06d2ec03e0222e73a92068c1b4 100644 --- a/src/database/open.c +++ b/src/database/open.c @@ -17,18 +17,24 @@ This schema is used to initialize the in-memory database. */ static const char *const SQL_MEM_SCHEM = "CREATE TABLE IF NOT EXISTS queue_state" - " ( id INTEGER PRIMARY KEY DEFAULT 42 CHECK(id = 42)" - " , volume INTEGER NOT NULL DEFAULT 100 CHECK(0 <= volume AND volume <= 100)" - " , paused INTEGER NOT NULL DEFAULT 1" - " , random INTEGER NOT NULL DEFAULT 0" - " , repeat INTEGER NOT NULL DEFAULT 0" - " , single INTEGER NOT NULL DEFAULT 0" - " , consume INTEGER NOT NULL DEFAULT 0" - " , current INTEGER CHECK(current > 0)" - " , duration INTEGER CHECK(duration >= 0)" - " , elapsed INTEGER CHECK(elapsed >= 0)" + " ( id INTEGER PRIMARY KEY DEFAULT 42 CHECK(id = 42)" + " , volume INTEGER NOT NULL DEFAULT 100 CHECK(0 <= volume AND volume <= 100)" + " , paused INTEGER NOT NULL DEFAULT 1" + " , random INTEGER NOT NULL DEFAULT 0" + " , repeat INTEGER NOT NULL DEFAULT 0" + " , single INTEGER NOT NULL DEFAULT 0" + " , consume INTEGER NOT NULL DEFAULT 0" + " , current INTEGER CHECK(current > 0)" + " , duration INTEGER CHECK(duration >= 0)" + " , elapsed INTEGER CHECK(elapsed >= 0)" " );\n" - "INSERT INTO queue_state (id) VALUES (42);\n"; + "INSERT INTO queue_state (id) VALUES (42);\n" + "CREATE TABLE IF NOT EXISTS config" + " ( section TEXT NOT NULL" + " , key TEXT NOT NULL" + " , value TEXT" + " , PRIMARY KEY (section, key)" + " ) WITHOUT ROWID;\n"; #define INVALID_CHARS_DBPATH ":?!'\"" #define HEAP_LIMIT_SOFT 100 * 1024 * 1024 @@ -42,25 +48,20 @@ is_sql_str_invalid(const char *str) } bool -database_open(sqlite3 **db, const char *dbpath) +database_new(sqlite3 **db) { - if (is_sql_str_invalid(dbpath)) { - fprintf(stderr, " ! database_open: The database path %s is invalid\n", dbpath); - return false; - } - if (SQLITE_OK != sqlite3_enable_shared_cache(1)) { - fprintf(stderr, " ! database_open: Failed to enable shared cache\n"); + fprintf(stderr, " ! database_new: Failed to enable shared cache\n"); return false; } if (sqlite3_soft_heap_limit64(HEAP_LIMIT_SOFT) < 0) { - fprintf(stderr, " ! database_open: Failed to set soft heap limit to %u\n", HEAP_LIMIT_SOFT); + fprintf(stderr, " ! database_new: Failed to set soft heap limit to %u\n", HEAP_LIMIT_SOFT); return false; } if (sqlite3_hard_heap_limit64(HEAP_LIMIT_HARD) < 0) { - fprintf(stderr, " ! database_open: Failed to set soft heap limit to %u\n", HEAP_LIMIT_HARD); + fprintf(stderr, " ! database_new: Failed to set soft heap limit to %u\n", HEAP_LIMIT_HARD); return false; } @@ -80,14 +81,28 @@ database_open(sqlite3 **db, const char *dbpath) goto err_not_init; } + return true; +err_not_init: + *db = NULL; + return false; +} + +bool +database_open(sqlite3 *db, const char *dbpath) +{ + if (is_sql_str_invalid(dbpath)) { + fprintf(stderr, " ! database_open: The database path %s is invalid\n", dbpath); + return false; + } + static const char SQL_ATTACH_TEMPLATE[] = "ATTACH '%s' AS disk;"; size_t len = strlen(dbpath) + (sizeof(SQL_ATTACH_TEMPLATE) / sizeof(char)); char *SQL_ATTACH = (char *) calloc(len, sizeof(char)); snprintf(SQL_ATTACH, len - 1, SQL_ATTACH_TEMPLATE, dbpath); - if (SQLITE_OK != sqlite3_exec(*db, SQL_ATTACH, 0, 0, 0)) { + if (SQLITE_OK != sqlite3_exec(db, SQL_ATTACH, 0, 0, 0)) { fprintf(stderr, " ! database_open: Failed to attach disk database %s: %s\n", - dbpath, sqlite3_errmsg(*db)); + dbpath, sqlite3_errmsg(db)); goto err_no_attach; } @@ -95,8 +110,5 @@ database_open(sqlite3 **db, const char *dbpath) err_no_attach: free(SQL_ATTACH); - sqlite3_close(*db); -err_not_init: - *db = NULL; return false; } diff --git a/src/ini/ini.c b/src/ini/ini.c index 0b66f597079eca28da2b5b99d14628f11b778874..3a480689220d1811f80543b85f071c987f406ece 100644 --- a/src/ini/ini.c +++ b/src/ini/ini.c @@ -236,10 +236,14 @@ ini_parse(const char *filename, ini_handler handler, void *user) int error; file = fopen(filename, "r"); - if (!file) + if (!file) { + fprintf(stderr, " ! ini_parse: Failed to open file %s\n", filename); return -1; + } error = ini_parse_file(file, handler, user); fclose(file); + if (error) + fprintf(stderr, " ! ini_parse: Got an error, code is %d\n", error); return error; } diff --git a/src/ini/ini.cpp b/src/ini/ini.cpp deleted file mode 100644 index 529fa810dabef6aca23e097bc7ecb9d288a061eb..0000000000000000000000000000000000000000 --- a/src/ini/ini.cpp +++ /dev/null @@ -1,122 +0,0 @@ -// Read an INI file into easy-to-access name/value pairs. - -// SPDX-License-Identifier: BSD-3-Clause - -// Copyright (C) 2009-2020, Ben Hoyt - -// inih and INIReader are released under the New BSD license (see LICENSE.txt). -// Go to the project home page for more info: -// -// https://github.com/benhoyt/inih - -#include <algorithm> -#include <cctype> -#include <cstdlib> -#include <ini/ini.h> -#include <ini/ini.hpp> - -using std::string; - -INIReader::INIReader(const string &filename) -{ - m_error = ini_parse(filename.c_str(), ValueHandler, this); -} - -INIReader::INIReader(const char *buffer, size_t buffer_size) -{ - string content(buffer, buffer_size); - m_error = ini_parse_string(content.c_str(), ValueHandler, this); -} - -int -INIReader::ParseError() const -{ - return m_error; -} - -string -INIReader::Get(const string §ion, const string &name, const string &default_value) const -{ - string key = MakeKey(section, name); - return m_values.count(key) ? m_values.find(key)->second : default_value; -} - -string -INIReader::GetString(const string §ion, const string &name, const string &default_value) const -{ - const string str = Get(section, name, ""); - return str.empty() ? default_value : str; -} - -long -INIReader::GetInteger(const string §ion, const string &name, long default_value) const -{ - string valstr = Get(section, name, ""); - const char *value = valstr.c_str(); - char *end; - long n = strtol(value, &end, 0); - return end > value ? n : default_value; -} - -double -INIReader::GetReal(const string §ion, const string &name, double default_value) const -{ - string valstr = Get(section, name, ""); - const char *value = valstr.c_str(); - char *end; - double n = strtod(value, &end); - return end > value ? n : default_value; -} - -bool -INIReader::GetBoolean(const string §ion, const string &name, bool default_value) const -{ - string valstr = Get(section, name, ""); - std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower); // Case-insensitive - if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1") - return true; - else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0") - return false; - else - return default_value; -} - -bool -INIReader::HasSection(const string §ion) const -{ - const string key = MakeKey(section, ""); - std::map<string, string>::const_iterator pos = m_values.lower_bound(key); - if (pos == m_values.end()) - return false; - // Does the key at the lower_bound pos start with "section"? - return pos->first.compare(0, key.length(), key) == 0; -} - -bool -INIReader::HasValue(const string §ion, const string &name) const -{ - string key = MakeKey(section, name); - return m_values.count(key); -} - -string -INIReader::MakeKey(const string §ion, const string &name) -{ - string key = section + "=" + name; - std::transform(key.begin(), key.end(), key.begin(), ::tolower); // Case-insensitive - return key; -} - -int -INIReader::ValueHandler(void *user, const char *section, const char *name, - const char *value) -{ - if (!name) // Happens when INI_CALL_HANDLER_ON_NEW_SECTION enabled - return 1; - INIReader *reader = static_cast<INIReader *>(user); - string key = MakeKey(section, name); - if (reader->m_values[key].size() > 0) - reader->m_values[key] += "\n"; - reader->m_values[key] += value ? value : ""; - return 1; -} diff --git a/src/main/lktadm.c b/src/main/lktadm.c index caddcd63ba54e44c2d16302969110b1bfa4a3f7a..59681e77053fb04a661732e2b3ad409314e76199 100644 --- a/src/main/lktadm.c +++ b/src/main/lktadm.c @@ -31,8 +31,7 @@ main(int argc, char *argv[]) int i, num; sqlite3 *db; bool ret = true; - lkt_config_t conf; - char kara_dir[PATH_MAX], *db_path, *mkvpropedit, buf[100]; + char kara_dir[PATH_MAX], *db_path, mkvpropedit[PATH_MAX], buf[100]; struct kara_metadata data; struct lkt_repo repo; @@ -41,13 +40,18 @@ main(int argc, char *argv[]) /* Read the config file. */ - if (config_open(&conf)) { + if (!database_new(&db)) { + fprintf(stderr, " ! Failed to initialize memory database\n"); + return 1; + } + + if (config_open(db)) { fprintf(stderr, " ! could not load configuration\n"); return 1; } /* In any case, we won't free the mkvpropedit, this is not a daemon. */ - if (config_get_alloc(conf, "externals", "mkvpropedit", &mkvpropedit)) { + if (!database_config_get_text(db, "externals", "mkvpropedit", mkvpropedit, PATH_MAX)) { fprintf(stderr, " ! could not get the 'mkvpropedit property from the externals section\n'"); return 1; } @@ -55,7 +59,7 @@ main(int argc, char *argv[]) /* Arguments handle. */ if (strcmp(argv[1], "--init") == 0) { - if (config_get(conf, "database", "kara_dir", kara_dir, PATH_MAX)) { + if (!database_config_get_text(db, "database", "kara_dir", kara_dir, PATH_MAX)) { fprintf(stderr, " ! failed to get the kara directory\n"); return 10; } @@ -66,17 +70,21 @@ main(int argc, char *argv[]) else if (strcmp(argv[1], "--populate-all") == 0) { db_path = (char *) calloc(PATH_MAX, sizeof(char)); - if (config_get(conf, "database", "db_path", db_path, PATH_MAX)) { + if (!database_config_get_text(db, "database", "db_path", db_path, PATH_MAX)) { fprintf(stderr, " ! Failed to get database path\n"); goto end_populate; } - if (config_get(conf, "database", "kara_dir", kara_dir, PATH_MAX)) { + if (!database_config_get_text(db, "database", "kara_dir", kara_dir, PATH_MAX)) { fprintf(stderr, " ! Failed to get kara directory\n"); goto end_populate; } - sqlite3_open(db_path, &db); + if (!database_open(db, db_path)) { + fprintf(stderr, " ! lkt_listen: Failed to open database\n"); + return 1; + } + database_update(db, kara_dir); sqlite3_close(db); diff --git a/src/main/server.c b/src/main/server.c index 991153762a832d1146fced9f68c3742510691c96..ba4eea5e717579761bc9d1d318948ee9afb2365d 100644 --- a/src/main/server.c +++ b/src/main/server.c @@ -37,8 +37,6 @@ main(int argc, char *argv[]) { /* Variable initialisation */ struct passwd *pw = getpwuid(getuid()); - char *conf_file = NULL; - lkt_config_t conf; /* Argument handleing */ if (argc <= 1) @@ -59,15 +57,5 @@ normal_launch: fprintf(stderr, " * Lektor launched by user %s (shell: %s, home: %s)\n", pw->pw_name, pw->pw_shell, pw->pw_dir); - if (config_detect_file(&conf_file, PATH_MAX)) { - fprintf(stderr, " ! error while searching for a config file\n"); - return 1; - } - - if (config_new(conf_file, &conf)) { - fprintf(stderr, " ! failed to read configuration file\n"); - return 1; - } - - return lkt_listen(conf); + return lkt_listen(); } diff --git a/src/module/module_x11.c b/src/module/module_x11.c index 39c584ed593e5ca18fcc11d1c298c3505e83a501..25bcb20f0497b89d65b5bb01ca6dbb237da3ceff 100644 --- a/src/module/module_x11.c +++ b/src/module/module_x11.c @@ -272,18 +272,18 @@ lmpv_handle(struct lkt_win *win, sqlite3 *db, long long int *mpd_idle_events) if (!strcmp(prop->name, "ao-volume") && prop->format == MPV_FORMAT_INT64) { ao_volume = *(int *) prop->data; - database_config(db, "volume", ao_volume); + database_config_queue(db, "volume", ao_volume); } // File duration // if (!strcmp(prop->name, "duration") && prop->format == MPV_FORMAT_INT64) { win_x11->mpv_duration = *(int *) prop->data; - database_config(db, "duration", *(int *) prop->data); + database_config_queue(db, "duration", *(int *) prop->data); } if (!strcmp(prop->name, "time-pos") && prop->format == MPV_FORMAT_INT64) { win_x11->mpv_time_pos = *(int *) prop->data; - database_config(db, "elapsed", *(int *) prop->data); + database_config_queue(db, "elapsed", *(int *) prop->data); } // Pause state // if (!strcmp(prop->name, "pause") diff --git a/src/net/listen.c b/src/net/listen.c index 7c7dc5d59b4c8ee7c00e75d3542b188b8854d2a3..8818ad900ad37e50552ff365d20f1bd37141cb0f 100644 --- a/src/net/listen.c +++ b/src/net/listen.c @@ -4,6 +4,7 @@ #include <lektor/database.h> #include <lektor/repo.h> #include <lektor/net.h> +#include <ini/ini.h> #include <sqlite3.h> @@ -705,45 +706,69 @@ get_out: } int -lkt_listen(lkt_config_t conf) +lkt_listen(void) { struct lkt_state srv; struct lkt_repo repo; int autoclear; + char *db_path = (char *) calloc(PATH_MAX, sizeof(char)); + char *kara_dir = (char *) calloc(PATH_MAX, sizeof(char)); + char *host = (char *) calloc(HOST_NAME_MAX, sizeof(char)); + char port[7]; /* Maximal port number is 65535, +2 for '\n' and '\0' */ + char player_mod[INI_MAX_LINE]; + char conf_file[PATH_MAX]; memset(&srv, 0, sizeof(struct lkt_state)); - if (config_get_bool(conf, "player", "autoclear", &autoclear)) { - fprintf(stderr, " ! Failed to get queue autoclear property\n"); + /* Initialize the system. */ + + if (!database_new(&srv.db)) { + fprintf(stderr, " ! lkt_listen: Failed to initialize memory database\n"); return 1; } - char *db_path = (char *) calloc(PATH_MAX, sizeof(char)); - char *kara_dir = (char *) calloc(PATH_MAX, sizeof(char)); - char *host = (char *) calloc(HOST_NAME_MAX, sizeof(char)); - char port[5]; /* Maximal port number is 65535. */ - char *player_mod; + if (config_detect_file(conf_file, PATH_MAX)) { + fprintf(stderr, " ! lkt_listen: error while searching for a config file\n"); + return 1; + } + + if (config_new(srv.db, conf_file)) { + fprintf(stderr, " ! lkt_listen: failed to read configuration file %s\n", conf_file); + return 1; + } - if (config_get(conf, "database", "db_path", db_path, PATH_MAX)) { + if (!database_open(srv.db, db_path)) { + fprintf(stderr, " ! lkt_listen: Failed to open database\n"); + return 1; + } + + /* Read the configuration. */ + + if (!database_config_get_int(srv.db, "player", "autoclear", &autoclear)) { + fprintf(stderr, " ! Failed to get queue autoclear property\n"); + return 1; + } + + if (!database_config_get_text(srv.db, "database", "db_path", db_path, PATH_MAX)) { fprintf(stderr, " ! lkt_listen: Failed to get database path\n"); goto end_free_strings; } - if (config_get(conf, "database", "kara_dir", kara_dir, PATH_MAX)) { + if (!database_config_get_text(srv.db, "database", "kara_dir", kara_dir, PATH_MAX)) { fprintf(stderr, " ! lkt_listen: Failed to get kara directory\n"); goto end_free_strings; } - if (config_get(conf, "server", "host", host, HOST_NAME_MAX)) { + if (!database_config_get_text(srv.db, "server", "host", host, HOST_NAME_MAX)) { fprintf(stderr, " ! lkt_listen: Failed to get the host\n"); goto end_free_strings; } - if (config_get(conf, "server", "port", port, 5)) { + if (!database_config_get_text(srv.db, "server", "port", port, 5)) { fprintf(stderr, " ! lkt_listen: Failed to get the port\n"); goto end_free_strings; } - if (config_get_alloc(conf, "player", "module", &player_mod)) { + if (!database_config_get_text(srv.db, "player", "module", player_mod, INI_MAX_LINE)) { fprintf(stderr, " ! lkt_listen: Failed to get the module for the player\n"); goto end_free_strings; } @@ -751,14 +776,9 @@ lkt_listen(lkt_config_t conf) if (kara_dir[strlen(kara_dir) - 1] != '/') strncat(kara_dir, "/", PATH_MAX - 1); - if (!database_open(&srv.db, db_path)) { - fprintf(stderr, " ! lkt_listen: Failed to open database\n"); - goto end_free_strings; - } - srv.kara_prefix = kara_dir; - database_config_default(srv.db); + database_config_queue_default(srv.db); srv.fds_max = 16; srv.fds = malloc(srv.fds_max * sizeof(struct pollfd)); @@ -774,7 +794,7 @@ lkt_listen(lkt_config_t conf) if (autoclear) database_queue_clear(srv.db); - if (!load_module_by_name(conf, player_mod, &srv.win)) + if (!load_module_by_name(srv.db, player_mod, &srv.win)) return -2; if (!srv.win.new(&srv.win))