112 lines
3.3 KiB
C++
112 lines
3.3 KiB
C++
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <sys/stat.h>
|
|
#include <string>
|
|
#include <nlohmann/json.hpp>
|
|
|
|
#include "log.h"
|
|
#include "misc.h"
|
|
#include "config.h"
|
|
|
|
static FILE* fopen_or_raise(const char* path, const char* mode, bool ignore_enoent) {
|
|
FILE* file = fopen(path, mode);
|
|
if (!file && !(ignore_enoent && errno == ENOENT)) {
|
|
throw_system_error(std::string("fopen(") + quote(path) + ')');
|
|
}
|
|
return file;
|
|
}
|
|
|
|
static void fclose_and_log(FILE* file) {
|
|
if (!fclose(file)) {
|
|
return;
|
|
}
|
|
log(std::string("Failed to close a file: fclose(): ") + strerror(errno));
|
|
}
|
|
|
|
|
|
std::string get_config_folder() {
|
|
const char* path;
|
|
|
|
path = getenv("XDG_CONFIG_HOME");
|
|
if (path) {
|
|
return std::string(path) + "/logmeow";
|
|
}
|
|
path = getenv("HOME");
|
|
if (path) {
|
|
return std::string(path) + "/.config/logmeow";
|
|
}
|
|
|
|
throw std::runtime_error("cannot find suitable config folder, please set XDG_CONFIG_HOME or HOME");
|
|
}
|
|
|
|
std::string get_config_file_path() {
|
|
return get_config_folder() + "/config.json";
|
|
}
|
|
|
|
// tries to create a directory with an empty string if it's just "/" but who cares
|
|
void create_config_folders_if_necessary() {
|
|
std::string full_path = get_config_folder();
|
|
std::string path;
|
|
size_t pos = 0;
|
|
|
|
while (pos != std::string::npos) {
|
|
pos = full_path.find('/', pos);
|
|
if (pos != std::string::npos) {
|
|
pos++;
|
|
}
|
|
path = full_path.substr(0, pos);
|
|
if (!mkdir(path.c_str(), 0600)) {
|
|
continue;
|
|
}
|
|
if (errno == EEXIST) {
|
|
continue;
|
|
}
|
|
throw_system_error(std::string("mkdir(") + quote(path) + ')');
|
|
}
|
|
}
|
|
|
|
|
|
void from_json(const nlohmann::json& j, Config& config) {
|
|
j.at("logcat_command").get_to(config.logcat_command);
|
|
j.at("normal_font_size").get_to(config.normal_font_size);
|
|
j.at("monospace_font_size").get_to(config.monospace_font_size);
|
|
j.at("filters").get_to(config.filters);
|
|
j.at("exclusions").get_to(config.exclusions);
|
|
}
|
|
|
|
Config load_config() {
|
|
std::string config_file_path = get_config_file_path();
|
|
std::unique_ptr<FILE, decltype(&fclose_and_log)> config_file(fopen_or_raise(config_file_path.c_str(), "r", true), fclose_and_log);
|
|
|
|
if (!config_file) {
|
|
return Config();
|
|
}
|
|
|
|
return nlohmann::json::parse(config_file.get()).get<Config>();
|
|
}
|
|
|
|
|
|
void to_json(nlohmann::json& j, const Config& config) {
|
|
j["logcat_command"] = config.logcat_command;
|
|
j["normal_font_size"] = config.normal_font_size;
|
|
j["monospace_font_size"] = config.monospace_font_size;
|
|
j["filters"] = config.filters;
|
|
j["exclusions"] = config.exclusions;
|
|
}
|
|
|
|
void write_config(const Config& config) {
|
|
std::string config_file_path = get_config_file_path();
|
|
std::string tmp_config_file_path = config_file_path + ".tmp";
|
|
|
|
std::unique_ptr<FILE, decltype(&fclose_and_log)> config_file(fopen_or_raise(tmp_config_file_path.c_str(), "w", false), fclose_and_log);
|
|
nlohmann::json json_config = config;
|
|
std::string str_config = json_config.dump();
|
|
fwrite(str_config.data(), sizeof(char), str_config.size(), config_file.get());
|
|
config_file.reset();
|
|
|
|
if (!rename(tmp_config_file_path.c_str(), config_file_path.c_str())) {
|
|
return;
|
|
}
|
|
throw_system_error(std::string("rename(") + quote(tmp_config_file_path) + ", " + quote(config_file_path) + ')');
|
|
}
|