diff --git a/inc/ini/ini.h b/inc/ini/ini.h
index 646a145e4f76feeb42bcd59cab8bed15eef23318..43a6afdff5dfd0239ca46b333c55ddb5f08a0afb 100644
--- a/inc/ini/ini.h
+++ b/inc/ini/ini.h
@@ -73,7 +73,7 @@ int ini_parse_string(const char *string, ini_handler handler, void *user);
    configparser. If allowed, ini_parse() will call the handler with the same
    name for each subsequent line parsed. */
 #ifndef INI_ALLOW_MULTILINE
-#define INI_ALLOW_MULTILINE 0
+#define INI_ALLOW_MULTILINE 1
 #endif
 
 /* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
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 &section, 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 &section, 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 &section, 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 &section, 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 &section, 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 &section) const;
-
-    // Return true if a value exists with the given section and field names.
-    bool HasValue(const std::string &section, const std::string &name) const;
-
-private:
-    int m_error;
-    std::map<std::string, std::string> m_values;
-
-    static std::string MakeKey(const std::string &section, const std::string &name);
-    static int ValueHandler(void *user, const char *section, const char *name,
-                            const char *value);
-};
-
-#endif  // __INIREADER_H__
diff --git a/meson.build b/meson.build
index eeb3376439a5f6d530a434334702ac5e6f3c993a..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)
@@ -44,7 +41,6 @@ core_sources =  [ 'src/mkv/bufferfd.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/config.c b/src/config.c
index 37498d268c01d7bfeea4644a942867aa4bd7b86c..5df978b5ab42d01a0f44ab72695963bc9c7e404d 100644
--- a/src/config.c
+++ b/src/config.c
@@ -100,12 +100,12 @@ handler(void *user, const char *section, const char *name, const char *value)
         return 1;
     }
 
-    if (database_config_set(user, section, name, value)) {
+    if (!database_config_set(user, section, name, value)) {
         fprintf(stderr, " . handler: Failed to update the database\n");
-        return 1;
+        return 0;
     }
 
-    return 0;
+    return 1;
 }
 
 int
diff --git a/src/database/config.c b/src/database/config.c
index 362ebf6bb4e936a2380c19105dc6da6a6b47a646..cf4b2eefa9a6e4642639883fe0f435560e01f806 100644
--- a/src/database/config.c
+++ b/src/database/config.c
@@ -55,6 +55,7 @@ database_config_get_text(sqlite3 *db, const char *section, const char *key, char
     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",
@@ -77,7 +78,7 @@ database_config_get_text(sqlite3 *db, const char *section, const char *key, char
         goto error;
     }
 
-    const char *row = (const char *) sqlite3_column_text(stmt, 1);
+    row = (char *) sqlite3_column_text(stmt, 0);
     strncpy(value, row, len);
     value[len - 1] = 0;
     ret = true;
@@ -90,7 +91,7 @@ bool
 database_config_exists(sqlite3 *db, const char *section, const char *key)
 {
     static const char *SQL_STMT =
-        "SELECT COUNT(value)"
+        "SELECT value"
         " FROM config"
         " WHERE section = ? AND key = ?;\n";
     sqlite3_stmt *stmt = 0;
@@ -113,12 +114,12 @@ database_config_exists(sqlite3 *db, const char *section, const char *key)
     code = sqlite3_step(stmt);
 
     if (code != SQLITE_ROW) {
-        fprintf(stderr, " ! database_config_exists: Failed to insert or replace: %s\n",
+        fprintf(stderr, " ! database_config_exists: No rows: %s\n",
                 sqlite3_errmsg(db));
         goto error;
     }
 
-    ret = (0 < sqlite3_column_int(stmt, 1));
+    ret = true;
 error:
     sqlite3_finalize(stmt);
     return ret;
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 &section, 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 &section, 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 &section, 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 &section, 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 &section, 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 &section) 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 &section, const string &name) const
-{
-    string key = MakeKey(section, name);
-    return m_values.count(key);
-}
-
-string
-INIReader::MakeKey(const string &section, 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/net/listen.c b/src/net/listen.c
index c51a2f3fb41f0a3706ee24d9d0fe28acb2489759..8818ad900ad37e50552ff365d20f1bd37141cb0f 100644
--- a/src/net/listen.c
+++ b/src/net/listen.c
@@ -727,12 +727,12 @@ lkt_listen(void)
     }
 
     if (config_detect_file(conf_file, PATH_MAX)) {
-        fprintf(stderr, " ! error while searching for a config file\n");
+        fprintf(stderr, " ! lkt_listen: error while searching for a config file\n");
         return 1;
     }
 
     if (config_new(srv.db, conf_file)) {
-        fprintf(stderr, " ! failed to read configuration file\n");
+        fprintf(stderr, " ! lkt_listen: failed to read configuration file %s\n", conf_file);
         return 1;
     }
 
@@ -743,32 +743,32 @@ lkt_listen(void)
 
     /* Read the configuration. */
 
-    if (database_config_get_int(srv.db, "player", "autoclear", &autoclear)) {
+    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)) {
+    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 (database_config_get_text(srv.db, "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 (database_config_get_text(srv.db, "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 (database_config_get_text(srv.db, "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 (database_config_get_text(srv.db, "player", "module", player_mod, INI_MAX_LINE)) {
+    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;
     }