#include "config.h" #include #include #include #include // strcasecmp #include #include static xmlNodePtr find_child(xmlNodePtr parent, const char *name) { if (!parent || !name) return NULL; for (xmlNodePtr n = parent->children; n; n = n->next) { if (n->type == XML_ELEMENT_NODE && xmlStrcmp(n->name, BAD_CAST name) == 0) { return n; } } return NULL; } static void set_default_config(AppConfig *cfg) { memset(cfg, 0, sizeof(*cfg)); strncpy(cfg->ip, "127.0.0.1", sizeof(cfg->ip) - 1); cfg->ip[sizeof(cfg->ip) - 1] = '\0'; strncpy(cfg->master_ip, "127.0.0.1", sizeof(cfg->master_ip) - 1); cfg->master_ip[sizeof(cfg->master_ip) - 1] = '\0'; cfg->port = 8888; cfg->log_level = LOG_LEVEL_INFO; cfg->mode = MODE_MASTER; cfg->master_port = 8888; cfg->persistence = PERSIST_NONE; cfg->allocator = ALLOC_JEMALLOC; } /* ---- 字符串转枚举 ---- */ static void parse_log_level(const char *s, LogLevel *out) { if (!s || !out) return; if (!strcasecmp(s, "DEBUG")) *out = LOG_LEVEL_DEBUG; else if (!strcasecmp(s, "INFO")) *out = LOG_LEVEL_INFO; else if (!strcasecmp(s, "ERROR")) *out = LOG_LEVEL_ERROR; /* 不认识就保持默认 */ } static void parse_server_mode(const char *s, ServerMode *out) { if (!s || !out) return; if (!strcasecmp(s, "master")) *out = MODE_MASTER; else if (!strcasecmp(s, "slave")) *out = MODE_SLAVE; } static void parse_persistence(const char *s, PersistenceType *out) { if (!s || !out) return; if (!strcasecmp(s, "incremental")) *out = PERSIST_INCREMENTAL; else if (!strcasecmp(s, "none")) *out = PERSIST_NONE; } static void parse_allocator(const char *s, AllocatorType *out) { if (!s || !out) return; if (!strcasecmp(s, "jemalloc")) *out = ALLOC_JEMALLOC; else if (!strcasecmp(s, "malloc")) *out = ALLOC_MALLOC; else *out = ALLOC_OTHER; } /* ---- 对外的枚举转字符串工具 ---- */ const char *log_level_to_string(LogLevel lvl) { switch (lvl) { case LOG_LEVEL_DEBUG: return "DEBUG"; case LOG_LEVEL_INFO: return "INFO"; case LOG_LEVEL_ERROR: return "ERROR"; default: return "UNKNOWN"; } } const char *server_mode_to_string(ServerMode mode) { switch (mode) { case MODE_MASTER: return "master"; case MODE_SLAVE: return "slave"; default: return "unknown"; } } const char *persistence_to_string(PersistenceType p) { switch (p) { case PERSIST_INCREMENTAL: return "incremental"; case PERSIST_NONE: return "none"; default: return "unknown"; } } const char *allocator_to_string(AllocatorType a) { switch (a) { case ALLOC_JEMALLOC: return "jemalloc"; case ALLOC_MALLOC: return "malloc"; case ALLOC_OTHER: return "other"; default: return "unknown"; } } /* ---- 主函数:从 XML 加载配置 ---- */ int config_load(const char *filename, AppConfig *out_cfg) { if (!filename || !out_cfg) return -1; set_default_config(out_cfg); xmlDocPtr doc = xmlReadFile(filename, "UTF-8", XML_PARSE_NOBLANKS); if (!doc) { fprintf(stderr, "config_load: failed to read file %s\n", filename); return -1; } xmlNodePtr root = xmlDocGetRootElement(doc); if (!root || xmlStrcmp(root->name, BAD_CAST "config") != 0) { fprintf(stderr, "config_load: root element is not \n"); xmlFreeDoc(doc); return -1; } /* server 部分 */ xmlNodePtr server = find_child(root, "server"); if (server) { /* ip */ xmlNodePtr ip_node = find_child(server, "ip"); if (ip_node) { xmlChar *txt = xmlNodeGetContent(ip_node); if (txt) { strncpy(out_cfg->ip, (char *)txt, sizeof(out_cfg->ip) - 1); out_cfg->ip[sizeof(out_cfg->ip) - 1] = '\0'; xmlFree(txt); } } /* port */ xmlNodePtr port_node = find_child(server, "port"); if (port_node) { xmlChar *txt = xmlNodeGetContent(port_node); if (txt) { out_cfg->port = atoi((char *)txt); xmlFree(txt); } } /* mode: master / slave */ xmlNodePtr mode_node = find_child(server, "mode"); if (mode_node) { xmlChar *txt = xmlNodeGetContent(mode_node); if (txt) { parse_server_mode((char *)txt, &out_cfg->mode); xmlFree(txt); } } /* master (always read if present) */ xmlNodePtr master = find_child(server, "master"); if (master) { xmlNodePtr mip_node = find_child(master, "ip"); if (mip_node) { xmlChar *txt = xmlNodeGetContent(mip_node); if (txt) { strncpy(out_cfg->master_ip, (char *)txt, sizeof(out_cfg->master_ip) - 1); out_cfg->master_ip[sizeof(out_cfg->master_ip) - 1] = '\0'; xmlFree(txt); } } xmlNodePtr mport_node = find_child(master, "port"); if (mport_node) { xmlChar *txt = xmlNodeGetContent(port_node); if (txt) { out_cfg->master_port = atoi((char *)txt); xmlFree(txt); } } } } /* log 部分 */ xmlNodePtr log = find_child(root, "log"); if (log) { xmlNodePtr lvl_node = find_child(log, "level"); if (lvl_node) { xmlChar *txt = xmlNodeGetContent(lvl_node); if (txt) { parse_log_level((char *)txt, &out_cfg->log_level); xmlFree(txt); } } } /* persistence 部分 */ xmlNodePtr pers = find_child(root, "persistence"); if (pers) { xmlNodePtr type_node = find_child(pers, "type"); if (type_node) { xmlChar *txt = xmlNodeGetContent(type_node); if (txt) { parse_persistence((char *)txt, &out_cfg->persistence); xmlFree(txt); } } } /* memory 部分 */ xmlNodePtr mem = find_child(root, "memory"); if (mem) { xmlNodePtr alloc_node = find_child(mem, "allocator"); if (alloc_node) { xmlChar *txt = xmlNodeGetContent(alloc_node); if (txt) { parse_allocator((char *)txt, &out_cfg->allocator); xmlFree(txt); } } } xmlFreeDoc(doc); /* xmlCleanupParser() 建议在程序退出时 main 里统一调用 */ return 0; }