#include #include #include #include #include #include #include "config.h" #include "intl.h" #include "log.h" #define option_count() sizeof(config.options) / sizeof(config.options[0]) config_t config = { .options = { {.key = "threads", .type = TYPE_INTEGER, .def.integer = 10}, {.key = "addr", .type = TYPE_STRING, .def.string = "0.0.0.0:5858"}, {.key = "dir", .type = TYPE_STRING, .def.string = NULL}, {.key = "log", .type = TYPE_STRING, .def.string = NULL}, }, .pools = NULL, }; pool_config_t *config_pool_add(char *name) { pool_config_t *pool = malloc(sizeof(pool_config_t)); bzero(pool, sizeof(pool_config_t)); pool->name = strdup(name); pool->next = config.pools; config.pools = pool; return pool; } bool config_pool_contains(char *name) { pool_config_t *cur = config.pools; while (NULL != cur) { if (eq(cur->name, name)) return true; cur = cur->next; } return false; } void config_option_set(config_option_t *op, char *value) { switch (op->type) { case TYPE_STRING: free(op->val.string); op->val.string = strdup(value); break; case TYPE_INTEGER: op->val.integer = atoi(value); break; } } void config_option_free(config_option_t *op) { switch (op->type) { case TYPE_STRING: free(op->val.string); break; case TYPE_INTEGER: op->val.integer = 0; break; } } bool config_set(char *key, char *value) { for (int i = 0; i < option_count(); i++) { if (eq(config.options[i].key, key)) { config_option_set(&config.options[i], value); return true; } } return false; } void config_options_clear() { for (int i = 0; i < option_count(); i++) { config_option_t *cur = &config.options[i]; switch (cur->type) { case TYPE_STRING: cur->val.string = NULL; break; case TYPE_INTEGER: cur->val.integer = -1; break; } } } int config_load_handler(void *data, const char *_section, const char *_key, const char *_value) { char *section = (char *)_section, *key = (char *)_key, *value = (char *)_value; if (eq("", section)) { if (!config_set(key, value)) goto unknown; return 1; } if (!config_pool_contains(section)) config_pool_add(section); if (eq(key, "host")) { free(config.pools->host); config.pools->host = strdup(value); } else goto unknown; return 1; unknown: log_error("Unknown configuration option: %s/%s", section, key); return 0; } bool config_load(char *file) { config_options_clear(); if (!exists(file) || !can_read(file)) { log_error("Failed to access the configuration file: %s", file); return false; } if (ini_parse(file, config_load_handler, NULL) < 0) { log_error("Failed to parse the configuration"); return false; } pool_config_t *pool = config.pools; while (NULL != pool) { if (NULL == pool->host) { log_error("Hostname not specified for the pool: %s", pool->name); return false; } pool = pool->next; } log_info("Loaded the configuration"); return true; } void config_free() { for (int i = 0; i < option_count(); i++) config_option_free(&config.options[i]); pool_config_t *cur = config.pools, *old = NULL; while (NULL != cur) { old = cur; cur = cur->next; free(old->host); free(old->name); free(old); } } char *config_get_string(char *key) { for (int i = 0; i < option_count(); i++) { if (!eq(config.options[i].key, key) || config.options[i].type != TYPE_STRING) continue; if (NULL == config.options[i].val.string) return config.options[i].def.string; return config.options[i].val.string; } return NULL; } int config_get_integer(char *key) { for (int i = 0; i < option_count(); i++) { if (!eq(config.options[i].key, key) || config.options[i].type != TYPE_INTEGER) continue; if (config.options[i].val.integer < 0) return config.options[i].def.integer; return config.options[i].val.integer; } return -1; }