diff --git a/include/common.hpp b/include/common.hpp index f97c2d91..757f35e4 100644 --- a/include/common.hpp +++ b/include/common.hpp @@ -13,6 +13,7 @@ // Include some of the C++ stdlib for convenience #include +#include namespace rack { @@ -136,4 +137,10 @@ DeferWrapper deferWrapper(F f) { #define DEFER(code) auto CONCAT(_defer_, __COUNTER__) = rack::deferWrapper([&]() code) +/** Reports a string to the user */ +struct UserException : std::runtime_error { + UserException(const std::string &msg) : std::runtime_error(msg) {} +}; + + } // namespace rack diff --git a/src/main.cpp b/src/main.cpp index ecc9c4d2..95322123 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -82,7 +82,6 @@ int main(int argc, char *argv[]) { patchPath = argv[optind]; } - // Initialize environment asset::init(); logger::init(); @@ -106,6 +105,19 @@ int main(int argc, char *argv[]) { INFO("System directory: %s", asset::systemDir.c_str()); INFO("User directory: %s", asset::userDir.c_str()); + // Load settings + try { + settings::load(asset::user("settings.json")); + } + catch (UserException &e) { + std::string msg = e.what(); + msg += "\n\nReset settings to default?"; + if (!osdialog_message(OSDIALOG_WARNING, OSDIALOG_OK_CANCEL, msg.c_str())) { + exit(1); + } + } + + // Check existence of the system res/ directory std::string resDir = asset::system("res"); if (!system::isDirectory(resDir)) { std::string message = string::f("Rack's resource directory \"%s\" does not exist. Make sure Rack is correctly installed and launched.", resDir.c_str()); @@ -128,7 +140,6 @@ int main(int argc, char *argv[]) { // Initialize app INFO("Initializing app"); - settings::load(asset::user("settings.json")); appInit(); const char *openedFilename = glfwGetOpenedFilename(); diff --git a/src/settings.cpp b/src/settings.cpp index 533ca927..a722a284 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -230,34 +230,36 @@ void fromJson(json_t *rootJ) { void save(const std::string &path) { INFO("Saving settings %s", path.c_str()); json_t *rootJ = toJson(); - if (rootJ) { - FILE *file = std::fopen(path.c_str(), "w"); - if (!file) - return; - - json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); - json_decref(rootJ); - std::fclose(file); - } + if (!rootJ) + return; + + FILE *file = fopen(path.c_str(), "w"); + if (!file) + return; + DEFER({ + fclose(file); + }); + + json_dumpf(rootJ, file, JSON_INDENT(2) | JSON_REAL_PRECISION(9)); + json_decref(rootJ); } void load(const std::string &path) { INFO("Loading settings %s", path.c_str()); - FILE *file = std::fopen(path.c_str(), "r"); + FILE *file = fopen(path.c_str(), "r"); if (!file) - return; + throw UserException(string::f("Could not load settings file %s", path.c_str())); + DEFER({ + fclose(file); + }); json_error_t error; json_t *rootJ = json_loadf(file, 0, &error); - if (rootJ) { - fromJson(rootJ); - json_decref(rootJ); - } - else { - WARN("JSON parsing error at %s %d:%d %s", error.source, error.line, error.column, error.text); - } + if (!rootJ) + throw UserException(string::f("Settings file has invalid JSON at %d:%d %s", error.line, error.column, error.text)); - std::fclose(file); + fromJson(rootJ); + json_decref(rootJ); }