#pragma once #include #include #include #include "file_ext.h" #define CONFIG_PATH "/.config/taro" enum { CONFIG_CREATED = 0, CONFIG_LOADED, CONFIG_ERRORED }; struct config { str config_dir; str config_path; bool newly_created; str asset_dir; array(str) wallpaper_dirs; bool valid; bool errored; }; AL_IGNORE_WARNING("-Wunused-function") static void close_config(struct config *conf) { al_str_free(&conf->config_dir); al_str_free(&conf->config_path); al_str_free(&conf->asset_dir); str *dir; al_array_foreach_ptr(conf->wallpaper_dirs, i, dir) { al_str_free(dir); } al_array_free(conf->wallpaper_dirs); } static void maybe_replace_home_in_path(str *dest, const char *envhome, const char *path) { if (path[0] == '~') { al_str_from(dest, envhome); path++; al_str_cat(dest, &al_str_cr(path)); } else if (al_str_cmp(&al_str_cr(path), &al_str_c("$HOME"), 0, 5) == 0) { al_str_from(dest, envhome); path += 5; al_str_cat(dest, &al_str_cr(path)); } else { al_str_from(dest, path); } } static void parse_config_json(struct config *conf, char *envhome, json_t *root) { conf->valid = true; json_t *directories = json_object_get(root, "directories"); if (!directories) { conf->valid = false; goto out; } json_t *assets = json_object_get(directories, "assets"); if (!assets || !json_is_string(assets) || al_strlen(json_string_value(assets)) == 0) { log_error("asset directory not set or invalid"); conf->valid = false; goto out; } json_t *wallpapers = json_object_get(directories, "wallpapers"); if (!wallpapers) { conf->valid = false; goto out; } size_t index; json_t *value; json_array_foreach(wallpapers, index, value) { if (!json_is_string(value) || al_strlen(json_string_value(value)) == 0) { log_error("invalid wallpaper directory (index: %zu)", index); continue; } str path; maybe_replace_home_in_path(&path, envhome, json_string_value(value)); if (!nn_dir_exists(&path)) { log_warn("directory does not exist %.*s", al_str_x(&path)); al_str_free(&path); continue; } al_array_push(conf->wallpaper_dirs, path); } if (conf->wallpaper_dirs.count == 0) { log_error("no valid wallpaper directories"); conf->valid = false; goto out; } maybe_replace_home_in_path(&conf->asset_dir, envhome, json_string_value(assets)); out: json_decref(root); } static u8 open_config(struct config *conf, bool create) { al_memset(conf, 0, sizeof(struct config)); al_array_init(conf->wallpaper_dirs); conf->errored = false; char *envhome = getenv("HOME"); if (!envhome) goto err; al_str_from(&conf->config_dir, envhome); al_str_cat(&conf->config_dir, &al_str_c(CONFIG_PATH)); if (!nn_dir_exists(&conf->config_dir)) { if (!create || !nn_dir_create(&conf->config_dir)) { goto err; } else { conf->newly_created = true; } } al_str_clone(&conf->config_path, &conf->config_dir); al_str_cat(&conf->config_path, &al_str_c("/config.json")); if (!nn_file_exists(&conf->config_path)) { if (nn_file_create(&conf->config_path)) { json_t *blank = json_object(); json_t *directories = json_object(); json_object_set_new(directories, "assets", json_string_nocheck("")); json_object_set_new(directories, "wallpapers", json_array()); json_object_set_new(blank, "directories", directories); nn_dump_json_and_decref(&conf->config_path, blank); } } json_t *root = nn_file_open_as_json(&conf->config_path); if (!root) goto err; if (!conf->newly_created) { parse_config_json(conf, envhome, root); } else { conf->valid = false; } return conf->newly_created ? CONFIG_CREATED : CONFIG_LOADED; err: conf->errored = true; close_config(conf); return CONFIG_ERRORED; } AL_IGNORE_WARNING_END