/** * Copyright (c) 2016 rxi * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #include #include #include #include #include #include "ini.h" // 去除字符串首尾的空白字符 char* trim(char* str) { char *end; // 去除首部空白 while(isspace((unsigned char)*str)) str++; if(*str == 0) return str; // 去除尾部空白 end = str + strlen(str) - 1; while(end > str && isspace((unsigned char)*end)) end--; end[1] = '\0'; return str; } // 初始化INI文件结构 INI_File* ini_init() { INI_File *ini = malloc(sizeof(INI_File)); if (!ini) return NULL; ini->section_capacity = 10; ini->section_count = 0; ini->sections = malloc(sizeof(INI_Section) * ini->section_capacity); return ini; } // 释放INI文件结构 void ini_free(INI_File *ini) { if (!ini) return; for (int i = 0; i < ini->section_count; i++) { free(ini->sections[i].entries); } free(ini->sections); free(ini); } // 解析INI文件 int ini_parse(INI_File *ini, const char *filename) { FILE *file = fopen(filename, "r"); if (!file) { return -1; // 文件打开失败 } char line[MAX_LINE_LENGTH]; char current_section[MAX_SECTION_LENGTH] = ""; int line_num = 0; while (fgets(line, sizeof(line), file)) { line_num++; char *trimmed_line = trim(line); // 跳过空行和注释 if (strlen(trimmed_line) == 0 || trimmed_line[0] == ';' || trimmed_line[0] == '#') { continue; } // 处理节(section) if (trimmed_line[0] == '[' && trimmed_line[strlen(trimmed_line)-1] == ']') { strncpy(current_section, trimmed_line + 1, strlen(trimmed_line) - 2); current_section[strlen(trimmed_line) - 2] = '\0'; trim(current_section); continue; } // 处理键值对 char *equal_pos = strchr(trimmed_line, '='); if (equal_pos) { *equal_pos = '\0'; char *key = trim(trimmed_line); char *value = trim(equal_pos + 1); // 如果key或value为空,跳过 if (strlen(key) == 0 || strlen(value) == 0) { continue; } // 添加到INI结构 ini_set_value(ini, current_section, key, value); } } fclose(file); return 0; } // 设置键值对 int ini_set_value(INI_File *ini, const char *section, const char *key, const char *value) { // 查找或创建section INI_Section *current_section = NULL; for (int i = 0; i < ini->section_count; i++) { if (strcmp(ini->sections[i].section, section) == 0) { current_section = &ini->sections[i]; break; } } // 如果section不存在,创建新的 if (!current_section) { if (ini->section_count >= ini->section_capacity) { ini->section_capacity *= 2; ini->sections = realloc(ini->sections, sizeof(INI_Section) * ini->section_capacity); } current_section = &ini->sections[ini->section_count]; strncpy(current_section->section, section, MAX_SECTION_LENGTH - 1); current_section->section[MAX_SECTION_LENGTH - 1] = '\0'; current_section->entry_capacity = 10; current_section->entry_count = 0; current_section->entries = malloc(sizeof(INI_Entry) * current_section->entry_capacity); ini->section_count++; } // 查找是否已存在该key for (int i = 0; i < current_section->entry_count; i++) { if (strcmp(current_section->entries[i].key, key) == 0) { // 更新已存在的值 strncpy(current_section->entries[i].value, value, MAX_VALUE_LENGTH - 1); current_section->entries[i].value[MAX_VALUE_LENGTH - 1] = '\0'; return 0; } } // 添加新的键值对 if (current_section->entry_count >= current_section->entry_capacity) { current_section->entry_capacity *= 2; current_section->entries = realloc(current_section->entries, sizeof(INI_Entry) * current_section->entry_capacity); } INI_Entry *entry = ¤t_section->entries[current_section->entry_count]; strncpy(entry->key, key, MAX_KEY_LENGTH - 1); entry->key[MAX_KEY_LENGTH - 1] = '\0'; strncpy(entry->value, value, MAX_VALUE_LENGTH - 1); entry->value[MAX_VALUE_LENGTH - 1] = '\0'; current_section->entry_count++; return 0; } // 保存INI文件到磁盘 int ini_save(INI_File *ini, const char *filename) { FILE *file = fopen(filename, "w"); if (!file) { return -1; // 文件打开失败 } // 首先处理空section(全局设置) for (int i = 0; i < ini->section_count; i++) { if (strlen(ini->sections[i].section) == 0) { for (int j = 0; j < ini->sections[i].entry_count; j++) { fprintf(file, "%s = %s\n", ini->sections[i].entries[j].key, ini->sections[i].entries[j].value); } if (ini->sections[i].entry_count > 0) { fprintf(file, "\n"); // 在节之间添加空行 } break; } } // 处理其他section for (int i = 0; i < ini->section_count; i++) { if (strlen(ini->sections[i].section) > 0) { // 写入section头 fprintf(file, "[%s]\n", ini->sections[i].section); // 写入该section的所有键值对 for (int j = 0; j < ini->sections[i].entry_count; j++) { fprintf(file, "%s = %s\n", ini->sections[i].entries[j].key, ini->sections[i].entries[j].value); } fprintf(file, "\n"); // 在节之间添加空行 } } fclose(file); return 0; } // 删除指定的键 int ini_delete_key(INI_File *ini, const char *section, const char *key) { for (int i = 0; i < ini->section_count; i++) { if (strcmp(ini->sections[i].section, section) == 0) { for (int j = 0; j < ini->sections[i].entry_count; j++) { if (strcmp(ini->sections[i].entries[j].key, key) == 0) { // 将后面的元素前移 for (int k = j; k < ini->sections[i].entry_count - 1; k++) { memcpy(&ini->sections[i].entries[k], &ini->sections[i].entries[k + 1], sizeof(INI_Entry)); } ini->sections[i].entry_count--; return 0; // 成功删除 } } break; } } return -1; // 未找到 } // 获取键值 char* ini_get_value(INI_File *ini, const char *section, const char *key,char *def) { for (int i = 0; i < ini->section_count; i++) { if (strcmp(ini->sections[i].section, section) == 0) { for (int j = 0; j < ini->sections[i].entry_count; j++) { if (strcmp(ini->sections[i].entries[j].key, key) == 0) { return ini->sections[i].entries[j].value; } } break; } } return def; // 未找到 } // 获取整数值 int ini_get_int(INI_File *ini, const char *section, const char *key, int default_value) { const char *value = ini_get_value(ini, section, key,"0"); if (!value) return default_value; return atoi(value); } // 获取浮点数值 double ini_get_double(INI_File *ini, const char *section, const char *key, double default_value) { const char *value = ini_get_value(ini, section, key,"0"); if (!value) return default_value; return atof(value); } // 获取布尔值 int ini_get_bool(INI_File *ini, const char *section, const char *key, int default_value) { const char *value = ini_get_value(ini, section, key,"0"); if (!value) return default_value; if (strcasecmp(value, "true") == 0 || strcasecmp(value, "yes") == 0 || strcasecmp(value, "1") == 0 || strcasecmp(value, "on") == 0) { return 1; } if (strcasecmp(value, "false") == 0 || strcasecmp(value, "no") == 0 || strcasecmp(value, "0") == 0 || strcasecmp(value, "off") == 0) { return 0; } return default_value; }