int config_set_value(Config *config, const char *section_name, const char *bss_name, const char *key, const char *new_value) { ConfigSection *sec = find_section(config, section_name); if (!sec) return -1; if (sec->is_bss_section) { // 处理 BSS 节 BssModule *bss = find_bss(sec, bss_name); if (!bss) return -1; printf("🔧 开始设置 key: %s = %s 在 bss: %s\n", key, new_value, bss_name); for (ConfigLine *line = bss->lines; line; line = line->next) { printf("遍历行: %s\n", line->line); char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) != 2) { printf("❌ 解析失败: %s\n", line->line); continue; } printf("解析到 key: %s\n", k); if (strcmp(k, "bss") == 0) { printf("跳过 bss=xxx 行\n"); continue; } if (strcmp(k, key) == 0) { // 修改已有行的 value size_t new_len = strlen(k) + strlen(new_value) + 2; char *new_line_str = realloc(line->line, new_len); if (!new_line_str) return -1; line->line = new_line_str; snprintf(line->line, new_len, "%s=%s", k, new_value); return 0; } } } else { // 处理普通节(General 或 Interface) printf("🔧 开始设置 key: %s = %s 在普通节: %s\n", key, new_value, section_name); for (ConfigLine *line = sec->lines; line; line = line->next) { printf("遍历行: %s\n", line->line); char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) != 2) { printf("❌ 解析失败: %s\n", line->line); continue; } printf("解析到 key: %s\n", k); if (strcmp(k, key) == 0) { // 修改已有行的 value size_t new_len = strlen(k) + strlen(new_value) + 2; char *new_line_str = realloc(line->line, new_len); if (!new_line_str) return -1; line->line = new_line_str; snprintf(line->line, new_len, "%s=%s", k, new_value); return 0; } } } return -1; // key 不存在 } 这里报错line->line = new_line_str;必须是可修改的左值,同时我不想修改结构体

时间: 2025-09-07 11:51:32 AIGC 浏览: 4
你遇到的错误是: ``` error: expression must be a modifiable lvalue ``` 出现在这一行: ```c line->line = new_line_str; ``` --- ## ❌ 错误原因 你使用了 `realloc` 来重新分配内存: ```c char *new_line_str = realloc(line->line, new_len); ``` 然后试图将新地址赋给 `line->line`: ```c line->line = new_line_str; ``` 但是你的结构体定义是: ```c typedef struct ConfigLine { char line[256]; // 固定大小的数组 struct ConfigLine *next; } ConfigLine; ``` `line->line` 是一个 **固定大小的字符数组(char[256])**,**不是指针**,所以你 **不能将它重新赋值为另一个地址**。 --- ## ✅ 你想要的:**不修改结构体的前提下安全地修改 `line->line` 的内容** ### ✅ 替代方案:使用 `strncpy` + `snprintf` 由于你不能使用 `realloc`,也不能赋值 `line->line = ...`,你需要: - 使用 `snprintf` 构造新字符串; - 使用 `strncpy` 将其复制进 `line->line`; - 确保字符串结尾有 `\0`。 --- ## ✅ 修改后的函数(不修改结构体) ```c int config_set_value(Config *config, const char *section_name, const char *bss_name, const char *key, const char *new_value) { ConfigSection *sec = find_section(config, section_name); if (!sec) return -1; if (sec->is_bss_section) { // 处理 BSS 节 BssModule *bss = find_bss(sec, bss_name); if (!bss) return -1; printf("🔧 开始设置 key: %s = %s 在 bss: %s\n", key, new_value, bss_name); for (ConfigLine *line = bss->lines; line; line = line->next) { printf("遍历行: %s\n", line->line); char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) != 2) { printf("❌ 解析失败: %s\n", line->line); continue; } printf("解析到 key: %s\n", k); if (strcmp(k, "bss") == 0) { printf("跳过 bss=xxx 行\n"); continue; } if (strcmp(k, key) == 0) { // 构造新行 char new_line[256]; snprintf(new_line, sizeof(new_line), "%s=%s", k, new_value); // 使用 strncpy 安全地复制 strncpy(line->line, new_line, sizeof(line->line) - 1); line->line[sizeof(line->line) - 1] = '\0'; // 确保结尾 return 0; } } } else { // 处理普通节(General 或 Interface) printf("🔧 开始设置 key: %s = %s 在普通节: %s\n", key, new_value, section_name); for (ConfigLine *line = sec->lines; line; line = line->next) { printf("遍历行: %s\n", line->line); char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) != 2) { printf("❌ 解析失败: %s\n", line->line); continue; } printf("解析到 key: %s\n", k); if (strcmp(k, key) == 0) { char new_line[256]; snprintf(new_line, sizeof(new_line), "%s=%s", k, new_value); strncpy(line->line, new_line, sizeof(line->line) - 1); line->line[sizeof(line->line) - 1] = '\0'; return 0; } } } return -1; // key 不存在 } ``` --- ## ✅ 关键修改点 | 原代码 | 修改后 | |--------|--------| | `char *new_line_str = realloc(...)` | 删除 `realloc` | | `line->line = new_line_str;` | 删除赋值 | | `snprintf(line->line, new_len, ...)` | 使用 `snprintf` 构造临时字符串 | | `strncpy(line->line, new_line, ...)` | 使用 `strncpy` 安全复制进固定数组 | --- ## ⚠️ 注意事项 | 项目 | 说明 | |------|------| | 是否修改结构体 | ❌ 不修改 | | 是否支持任意长度字符串 | ❌ 最多 255 字符 | | 是否会截断 | ✅ 如果新字符串太长会被截断 | | 是否需要动态内存管理 | ❌ 不需要 `malloc` / `realloc` | | 是否安全 | ✅ 使用 `strncpy` + `\0` 保护 | --- ## ✅ 示例 假设原字符串是: ``` ifname=wl0.1 ``` 调用: ```c config_set_value(config, "BSS configurations", "radio0", "ifname", "wl0.3"); ``` 结果会变成: ``` ifname=wl0.3 ``` 只要长度不超过 255 字符即可。 --- ### ❓相关问题:
阅读全文

相关推荐

#ifndef HAPDCONF_PARSER_H #define HAPDCONF_PARSER_H #include <stdio.h> // 宏定义替换硬编码数字 #define HAPDCONFIG_LINE_MAX 1024 // 每行最大长度 #define HAPDCONFIG_BSS_NAME_LEN 64 // BSS 模块名最大长度 #define HAPDCONFIG_SECTION_NAME_LEN 128 // 节名最大长度 typedef struct HapdConfigLine { char line[HAPDCONFIG_LINE_MAX]; // 使用宏定义 struct HapdConfigLine *next; } HapdConfigLine; typedef struct HapdBssModule { char name[HAPDCONFIG_BSS_NAME_LEN]; // 使用宏定义 HapdConfigLine *lines; struct HapdBssModule *next; } HapdBssModule; typedef struct HapdConfigSection { char name[HAPDCONFIG_SECTION_NAME_LEN]; // 使用宏定义 int is_bss_section; // 1 if it's a BSS section union { HapdConfigLine *lines; HapdBssModule *bss_list; }; struct HapdConfigSection *next; } HapdConfigSection; typedef struct { HapdConfigSection *sections; } HapdConfig; // 函数声明:使用 hapdconfig_ 前缀 HapdConfig * hapdconfig_load(const char *filename); int hapdconfig_save(HapdConfig *config, const char *filename); void hapdconfig_free(HapdConfig *config); int hapdconfig_get_value(HapdConfig *config, const char *section, const char *bss, const char *key, char *value, size_t size); int hapdconfig_set_value(HapdConfig *config, const char *section, const char *bss, const char *key, const char *value); int hapdconfig_clear_value(HapdConfig *config, const char *section, const char *bss, const char *key); int hapdconfig_add_value(HapdConfig *config, const char *section, const char *bss, const char *key, const char *new_value); void hapdconfig_print_bss_lines(HapdConfig *config, const char *bss_name); #endif // HAPDCONF_PARSER_H 还有这个文件

#ifndef CONFIG_PARSER_H #define CONFIG_PARSER_H #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> // 配置行节点 typedef struct ConfigLine { char line[512]; struct ConfigLine *next; } ConfigLine; // 配置段节点 typedef struct ConfigSection { char name[64]; // 段名,如 "network" char key[128]; // 键,如 "my_ssid" ConfigLine *lines; // 该段下的所有行 struct ConfigSection *next; } ConfigSection; // 配置对象 typedef struct { ConfigSection *sections; } Config; // 创建配置对象 Config *config_new(); // 释放配置对象 void config_free(Config *config); // 从 hostapd.conf 读取配置(扁平格式,支持多个 bss=) int config_read(Config *config, const char *filename); // 写入 hostapd.conf 格式配置 int config_write(Config *config, const char *filename); // 从 wpa_supplicant.conf 读取配置(network={...} 格式) int config_read_wpa(Config *config, const char *filename); // 写入 wpa_supplicant.conf 格式配置 int config_write_wpa(Config *config, const char *filename); // 获取指定段的值 int config_get_value(Config *config, const char *section, const char *key, const char *name, char *value, size_t size); // 设置指定段的值 int config_set_value(Config *config, const char *section, const char *key, const char *name, const char *value); // 添加新段 int config_add_section(Config *config, const char *section, const char *key); // 删除段 int config_remove_section(Config *config, const char *section, const char *key); // 删除键 int config_remove_key(Config *config, const char *section, const char *key, const char *name); #endif // CONFIG_PARSER_H 这是当前代码,依据修改根据你提供的 gdb 调用栈信息,程序崩溃在 strcmp() 调用中,而调用栈显示: #1 0x00005555555559de in find_section (config=0x55555555a2a0, section=0x55555555705c "General", key=0x0) at config_parser.c:58 说明你在 find_section() 函数中调用了 strcmp(),并且传入了 key = NULL。 🔍 问题定位 从调用栈来看: 在 main.c 第 26 行调用了 config_set_value(...); 该函数又调用了 find_section(config, "General", NULL); find_section() 内部使用了 strcmp(sec->name, key); 因为 key == NULL,导致 strcmp() 崩溃。 🛠 修复方案 ✅ 1. 修复 find_section() 中的 key == NULL 判断逻辑 假设你的 find_section() 函数如下(简化版): ❌ 问题:key == NULL 时调用 strcmp(sec->name, key) 导致段错误 ✅ 修复后的 find_section() 函数 ✅ 同时修复 config_set_value() 中的逻辑(如果适用) ✅ 修复总结 问题 修复方式 find_section() 中 key == NULL 导致 strcmp() 崩溃 加入 key == NULL 判断 config_set_value() 未检查 key 是否为 NULL 增加 NULL 检查 ConfigSection 字段未初始化为 NULL 确保 config_section_new() 初始化 name 和 type config_new() 未初始化 sections 设置为 NULL

#include "config_parser.h" #include <ctype.h> #include <string.h> #include <stdlib.h> #include <stdio.h> // 释放 ConfigLine 链表 static void free_lines(ConfigLine *head) { while (head) { ConfigLine *tmp = head; head = head->next; free(tmp); } } // 释放 BssModule 链表 static void free_bss(BssModule *head) { while (head) { BssModule *tmp = head; head = head->next; free_lines(tmp->lines); free(tmp); } } // 释放整个 Config 结构 void config_free(Config *config) { if (!config) return; ConfigSection *sec = config->sections; while (sec) { ConfigSection *tmp = sec; sec = sec->next; if (tmp->is_bss_section) { free_bss(tmp->bss_list); } else { free_lines(tmp->lines); } free(tmp); } free(config); } // 创建新的 Config 结构 Config *config_new() { Config *config = (Config *)malloc(sizeof(Config)); if (!config) return NULL; config->sections = NULL; return config; } /** * 打印指定配置节中的 bss_list 链表内容 * * @param sec 配置节指针 */ static void print_bss_list(ConfigSection *sec) { if (!sec || !sec->is_bss_section) { printf("❌ 无效的配置节或不是 BSS 类型的节\n"); return; } BssModule *bss = sec->bss_list; if (!bss) { printf("📄 节 [%s] 中没有 bss 模块\n", sec->name); return; } printf("📄 节 [%s] 中的 bss_list 内容:\n", sec->name); int index = 0; while (bss) { printf(" %d. %s\n", index++, bss->name); bss = bss->next; } } // 查找指定名称的 section static ConfigSection *find_section(Config *config, const char *section_name) { for (ConfigSection *sec = config->sections; sec; sec = sec->next) { if (strcmp(sec->name, section_name) == 0) return sec; } return NULL; } // 查找指定名称的 bss static BssModule *find_bss(ConfigSection *section, const char *bss_name) { if (!section->is_bss_section) { printf("❌ find_bss: section 不是 BSS 节\n"); return NULL; } printf("🔍 开始查找 bss: '%s'\n", bss_name); for (BssModule *bss = section->bss_list; bss; bss = bss->next) { printf(" 比较: '%s' vs '%s' => %d\n", bss->name, bss_name, strcmp(bss->name, bss_name)); // 打印十六进制,用于定位隐藏字符 printf(" bss->name hex: "); for (int i = 0; i < strlen(bss->name) && i < 32; i++) { printf("%02X ", (unsigned char)bss->name[i]); } printf("\n"); printf(" bss_name hex : "); for (int i = 0; i < strlen(bss_name) && i < 32; i++) { printf("%02X ", (unsigned char)bss_name[i]); } printf("\n"); if (strcmp(bss->name, bss_name) == 0) { printf("✅ 找到匹配的 bss: %s\n", bss_name); return bss; } } printf("find_bss: ❌ 未找到 bss: %s\n", bss_name); return NULL; } // 加载配置文件 Config *config_load(const char *filename) { FILE *fp = fopen(filename, "r"); if (!fp) return NULL; Config *config = config_new(); if (!config) { fclose(fp); return NULL; } ConfigSection *current_section = NULL; BssModule *current_bss = NULL; char line[MAX_LINE]; while (fgets(line, sizeof(line), fp)) { char *trimmed = line; while (isspace(*trimmed)) trimmed++; // 跳过空行和非 section 注释行 if (trimmed[0] == '\0' || trimmed[0] == '\n') continue; if (trimmed[0] == '#' && strncmp(trimmed, "##", 2) != 0) continue; // 处理节头 if (strncmp(trimmed, "##", 2) == 0) { char *section_name_start = trimmed + 2; while (isspace(*section_name_start)) section_name_start++; char section_name[64] = {0}; int i = 0; while (*section_name_start && *section_name_start != '\n' && i < 63) { section_name[i++] = *section_name_start++; } // 先查找是否已有该节 ConfigSection *existing = find_section(config, section_name); if (existing) { // 如果已存在,就切换 current_section 到它 current_section = existing; current_bss = NULL; printf("✅ 节 [%s] 已存在,切换使用\n", section_name); continue; } // 如果不存在,创建新节 ConfigSection *new_sec = (ConfigSection *)malloc(sizeof(ConfigSection)); if (!new_sec) continue; strncpy(new_sec->name, section_name, sizeof(new_sec->name) - 1); new_sec->name[sizeof(new_sec->name) - 1] = '\0'; new_sec->is_bss_section = (strcmp(section_name, "BSS configurations") == 0); new_sec->lines = NULL; new_sec->next = NULL; // 插入到 sections 尾部 if (config->sections == NULL) { config->sections = new_sec; } else { ConfigSection *tmp = config->sections; while (tmp->next) tmp = tmp->next; tmp->next = new_sec; } current_section = new_sec; current_bss = NULL; printf("🆕 新建节 [%s]\n", section_name); } else if (strchr(trimmed, '=')) { if (!current_section) continue; char key[128], val[128]; if (sscanf(trimmed, "%127[^=]=%127[^\n]", key, val) != 2) continue; ConfigLine *new_line = (ConfigLine *)malloc(sizeof(ConfigLine)); if (!new_line) continue; strncpy(new_line->line, line, sizeof(new_line->line) - 1); new_line->line[sizeof(new_line->line) - 1] = '\0'; new_line->next = NULL; if (current_section->is_bss_section) { if (strcmp(key, "bss") == 0) { // 提取并清理 bss 名称 char *val_start = val; while (isspace(*val_start)) val_start++; size_t val_len = strlen(val_start); while (val_len > 0 && isspace((unsigned char)val_start[val_len - 1])) { val_start[--val_len] = '\0'; } if (val_len == 0) { printf("⚠️ bss 值为空,跳过\n"); free(new_line); continue; } BssModule *new_bss = (BssModule *)malloc(sizeof(BssModule)); if (!new_bss) { free(new_line); continue; } strncpy(new_bss->name, val_start, sizeof(new_bss->name) - 1); new_bss->name[sizeof(new_bss->name) - 1] = '\0'; printf("解析到 bss: '%s'\n", new_bss->name); new_bss->lines = new_line; new_bss->next = NULL; // 插入到 bss_list 尾部 if (current_section->bss_list == NULL) { current_section->bss_list = new_bss; } else { BssModule *tmp = current_section->bss_list; while (tmp->next) tmp = tmp->next; tmp->next = new_bss; } current_bss = new_bss; } else { if (current_bss) { // 插入到 bss->lines 尾部 new_line->next = NULL; if (current_bss->lines == NULL) { current_bss->lines = new_line; } else { ConfigLine *tmp = current_bss->lines; while (tmp->next) tmp = tmp->next; tmp->next = new_line; } } else { free(new_line); } } } else { // 非 BSS section 的普通行插入到 lines 尾部 new_line->next = NULL; if (current_section->lines == NULL) { current_section->lines = new_line; } else { ConfigLine *tmp = current_section->lines; while (tmp->next) tmp = tmp->next; tmp->next = new_line; } } } } // ✅ 打印所有 ConfigSection 名字,确认顺序 ConfigSection *sec = config->sections; printf("📄 所有配置节:\n"); while (sec) { printf(" - %s\n", sec->name); sec = sec->next; } // ✅ 打印第一个 BSS configurations 的 bss_list sec = find_section(config, "BSS configurations"); if (sec) { printf("【调试】加载完成后的 bss_list 内容:\n"); print_bss_list(sec); } fclose(fp); return config; } // 保存配置文件 int config_save(Config *config, const char *filename) { FILE *fp = fopen(filename, "w"); if (!fp) return -1; for (ConfigSection *sec = config->sections; sec; sec = sec->next) { if (sec->is_bss_section) { // 对于 BSS 类型的节,每个 bss 单独写入标题和内容 for (BssModule *bss = sec->bss_list; bss; bss = bss->next) { // 写入标题 fprintf(fp, "## %s\n", sec->name); // 写入该 bss 的所有配置行 for (ConfigLine *line = bss->lines; line; line = line->next) { fprintf(fp, "%s", line->line); // 假设 line->line 已包含换行符 } } } else { // 普通节写入一次标题和所有行 fprintf(fp, "## %s\n", sec->name); for (ConfigLine *line = sec->lines; line; line = line->next) { fprintf(fp, "%s", line->line); } } } fclose(fp); return 0; } // 获取 value int config_get_value(Config *config, const char *section_name, const char *bss_name, const char *key, char *value, size_t val_size) { ConfigSection *sec = find_section(config, section_name); if (!sec || !sec->is_bss_section) return -1; BssModule *bss = find_bss(sec, bss_name); if (!bss) return -1; printf("🔍 开始查找 key: %s 在 bss: %s\n", key, bss_name); for (ConfigLine *line = bss->lines; line; line = line->next) { printf("遍历行: %s\n", line->line); char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) != 2) { printf("❌ 解析失败: %s\n", line->line); continue; } printf("解析到 key: %s\n", k); if (strcmp(k, "bss") == 0) { printf("跳过 bss=xxx 行\n"); continue; } if (strcmp(k, key) == 0) { strncpy(value, v, val_size - 1); value[val_size - 1] = '\0'; return 0; } } return -1; } // 设置 value int config_set_value(Config *config, const char *section_name, const char *bss_name, const char *key, const char *new_value) { ConfigSection *sec = find_section(config, section_name); if (!sec || !sec->is_bss_section) return -1; BssModule *bss = find_bss(sec, bss_name); if (!bss) return -1; printf("🔧 开始设置 key: %s = %s 在 bss: %s\n", key, new_value, bss_name); for (ConfigLine *line = bss->lines; line; line = line->next) { printf("遍历行: %s\n", line->line); char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) != 2) { printf("❌ 解析失败: %s\n", line->line); continue; } printf("解析到 key: %s\n", k); if (strcmp(k, "bss") == 0) { printf("跳过 bss=xxx 行\n"); continue; } if (strcmp(k, key) == 0) { snprintf(line->line, sizeof(line->line), "%s=%s\n", k, new_value); return 0; } } // 如果找不到 key,可以添加新行 ConfigLine *new_line = (ConfigLine *)malloc(sizeof(ConfigLine)); if (!new_line) return -1; snprintf(new_line->line, sizeof(new_line->line), "%s=%s\n", key, new_value); new_line->next = bss->lines; bss->lines = new_line; return 0; } // 清空 value int config_clear_value(Config *config, const char *section, const char *bss, const char *key) { return config_set_value(config, section, bss, key, ""); } // 追加 value int config_add_value(Config *config, const char *section, const char *bss, const char *key, const char *new_value) { ConfigSection *sec = find_section(config, section); if (!sec) return -1; if (bss && sec->is_bss_section) { BssModule *bss_mod = find_bss(sec, bss); if (!bss_mod) return -1; for (ConfigLine *line = bss_mod->lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { char new_line[256]; if (strlen(v) == 0) { snprintf(new_line, sizeof(new_line), "%s=%s\n", key, new_value); } else { snprintf(new_line, sizeof(new_line), "%s=%s %s\n", key, v, new_value); } strncpy(line->line, new_line, sizeof(line->line) - 1); line->line[sizeof(line->line) - 1] = '\0'; return 0; } } } else { for (ConfigLine *line = sec->lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { char new_line[256]; if (strlen(v) == 0) { snprintf(new_line, sizeof(new_line), "%s=%s\n", key, new_value); } else { snprintf(new_line, sizeof(new_line), "%s=%s %s\n", key, v, new_value); } strncpy(line->line, new_line, sizeof(line->line) - 1); line->line[sizeof(line->line) - 1] = '\0'; return 0; } } } return -1; } void print_bss_lines(Config *config, const char *bss_name) { ConfigSection *sec = find_section(config, "BSS configurations"); if (!sec || !sec->is_bss_section) { printf("printf_bss_lines:❌ 找不到 BSS configurations 节\n"); return; } BssModule *bss = find_bss(sec, bss_name); if (!bss) { printf("printf_bss_lines: ❌ 找不到 bss: %s\n", bss_name); return; } printf("📄 %s 的配置行如下:\n", bss_name); for (ConfigLine *line = bss->lines; line; line = line->next) { printf(" %s\n", line->line); } } 目前我的四个函数int config_get_value(Config *config, const char *section, const char *bss, const char *key, char *value, size_t size); int config_set_value(Config *config, const char *section, const char *bss, const char *key, const char *value); int config_clear_value(Config *config, const char *section, const char *bss, const char *key); int config_add_value(Config *config, const char *section, const char *bss, const char *key, const char *new_value); 并不支持我修改除BSS节之外的节,帮我修改

#include "wpaconf_parser.h" // 创建一个新的配置 WpaConfig* wpa_config_new() { WpaConfig *config = (WpaConfig *)calloc(1, sizeof(WpaConfig)); return config; } // 释放整个配置 void wpa_config_free(WpaConfig *config) { // 释放全局配置项 while (config->global_lines) { ConfigLine *tmp = config->global_lines; config->global_lines = config->global_lines->next; free(tmp); } // 释放 network 块 while (config->networks) { WpaNetwork *tmp = config->networks; // 释放 network 的配置项 while (tmp->lines) { ConfigLine *line_tmp = tmp->lines; tmp->lines = tmp->lines->next; free(line_tmp); } config->networks = config->networks->next; free(tmp); } free(config); } // 获取或创建一个 network WpaNetwork* wpa_config_get_network(WpaConfig *config, const char *ssid) { for (WpaNetwork *network = config->networks; network; network = network->next) { if (strcmp(network->ssid, ssid) == 0) return network; } return NULL; } // 添加一个 network int wpa_config_add_network(WpaConfig *config, const char *ssid) { if (wpa_config_get_network(config, ssid) != NULL) return -1; WpaNetwork *network = (WpaNetwork *)calloc(1, sizeof(WpaNetwork)); if (!network) return -1; strncpy(network->ssid, ssid, sizeof(network->ssid) - 1); network->next = config->networks; config->networks = network; return 0; } // 定义通用操作函数类型 typedef int (ConfigOpFunc)(ConfigLine **lines, const char *key, const char *value); // 通用操作函数 int foreach_config_section(WpaConfig *config, const char *ssid, ConfigOpFunc *func, const char *key, const char *value) { if (ssid == NULL || ssid[0] == '\0') { return func(&config->global_lines, key, value); } for (WpaNetwork *network = config->networks; network; network = network->next) { if (strcmp(network->ssid, ssid) == 0) { return func(&network->lines, key, value); } } return -1; } // 实现通用操作 // get int config_get(ConfigLine **lines, const char *key, const char *value_str) { for (ConfigLine *line = *lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { strncpy((char *)value_str, v, strlen(v) + 1); return 0; } } return -1; } int wpa_config_get_value(WpaConfig *config, const char *ssid, const char *key, char *value, size_t val_size) { int ret = foreach_config_section(config, ssid, config_get, key, value); if (ret == 0) { value[val_size - 1] = '\0'; } return ret; } // set int config_set(ConfigLine **lines, const char *key, const char *new_value) { for (ConfigLine *line = *lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { snprintf(line->line, sizeof(line->line), "%s=%s\n", k, new_value); return 0; } } // 如果没找到 key,添加新行 ConfigLine *new_line = (ConfigLine *)malloc(sizeof(ConfigLine)); if (!new_line) return -1; snprintf(new_line->line, sizeof(new_line->line), "%s=%s\n", key, new_value); new_line->next = *lines; *lines = new_line; return 0; } int wpa_config_set_value(WpaConfig *config, const char *ssid, const char *key, const char *new_value) { return foreach_config_section(config, ssid, config_set, key, new_value); } // add int config_add(ConfigLine **lines, const char *key, const char *value) { ConfigLine *new_line = (ConfigLine *)malloc(sizeof(ConfigLine)); if (!new_line) return -1; snprintf(new_line->line, sizeof(new_line->line), "%s=%s\n", key, value); new_line->next = *lines; *lines = new_line; return 0; } int wpa_config_add_value(WpaConfig *config, const char *ssid, const char *key, const char *value) { return foreach_config_section(config, ssid, config_add, key, value); } // clear int config_clear(ConfigLine **lines, const char *key, const char *unused) { (void)unused; ConfigLine **line_ptr = lines; while (*line_ptr) { char k[128], v[128]; if (sscanf((*line_ptr)->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { ConfigLine *to_remove = *line_ptr; *line_ptr = (*line_ptr)->next; free(to_remove); return 0; } line_ptr = &(*line_ptr)->next; } return -1; } int wpa_config_clear_value(WpaConfig *config, const char *ssid, const char *key) { return foreach_config_section(config, ssid, config_clear, key, NULL); } // 保存配置到文件 int wpa_config_save(WpaConfig *config, const char *filename) { FILE *fp = fopen(filename, "w"); if (!fp) return -1; // 写入全局配置 for (ConfigLine *line = config->global_lines; line; line = line->next) { fprintf(fp, "%s", line->line); } // 写入每个 network 块 for (WpaNetwork *network = config->networks; network; network = network->next) { fprintf(fp, "\nnetwork={\n"); for (ConfigLine *line = network->lines; line; line = line->next) { fprintf(fp, "\t%s", line->line); } fprintf(fp, "}\n"); } fclose(fp); return 0; } 修改之后给出完整文件#include "hapdconf_parser.h" #include "wpaconf_parser.h" #include <stdio.h> #define BUF_SIZE 256 int main() { Config *hapdconfig = config_load("wl0.1_hapd.conf"); if (!hapdconfig) { printf("加载配置失败\n"); return -1; } // 打印 wl0.2 的所有配置行 print_bss_lines(hapdconfig, "wl0.2"); // char value[BUF_SIZE]; // if (config_get_value(config, "General configurations", NULL, "driver", value, BUF_SIZE) == 0) { // printf("✅ config_get_value(\"driver\") = %s\n", value); // } else { // printf("❌ config_get_value(\"driver\") 失败\n"); // } // // 2. 修改 key1 的值为 "new_value1" // if (config_set_value(config, "General configurations", NULL, "driver", "new_value1") == 0) { // printf("✅ config_set_value(\"driver\", \"new_value1\") 成功\n"); // } else { // printf("❌ config_set_value(\"driver\", \"new_value1\") 失败\n"); // } // // 4. 追加 "append_value" 到 key1 // if (config_add_value(config, "General configurations", NULL, "driver", "append_value") == 0) { // printf("✅ config_add_value(\"driver\", \"append_value\") 成功\n"); // } else { // printf("❌ config_add_value(\"driver\", \"append_value\") 失败\n"); // } // // 5. 清空 driver 的值为 // if (config_clear_value(config, "General configurations", NULL, "driver") == 0) { // printf("✅ config_clear_value(\"driver\") 成功\n"); // } else { // printf("❌ config_clear_value(\"driver\") 失败\n"); // } // int set_ret = config_set_value(config, "BSS configurations", "wl0.2", "bridge", "br-wan"); // if (set_ret == 0) { // printf("✅ 已修改 wl0.2 的 bridge 为 br-wan\n"); // } else { // printf("❌ 修改失败,未找到 wl0.2\n"); // } // config_save(config, "wl0.1_hapd_new.conf"); // config_free(config); WpaConfig *config = wpa_config_new(); // === 设置全局配置项 === wpa_config_set_value(config, NULL, "update_config", "1"); wpa_config_set_value(config, NULL, "ctrl_interface", "/var/run/wl0_wpa_supplicant"); wpa_config_set_value(config, NULL, "ctrl_interface_group", "0"); wpa_config_set_value(config, NULL, "device_name", "RE235BE"); wpa_config_set_value(config, NULL, "manufacturer", "TP-Link"); wpa_config_set_value(config, NULL, "model_name", "RE235BE"); wpa_config_set_value(config, NULL, "model_number", "2.0"); wpa_config_set_value(config, NULL, "serial_number", "1234"); wpa_config_set_value(config, NULL, "os_version", "134217728"); wpa_config_set_value(config, NULL, "device_type", "6-0050F204-1"); wpa_config_set_value(config, NULL, "config_methods", "display push_button virtual_push_button physical_push_button virtual_display"); wpa_config_set_value(config, NULL, "wps_cred_processing", "2"); wpa_config_set_value(config, NULL, "pmf", "0"); wpa_config_set_value(config, NULL, "dpp_config_processing", "2"); wpa_config_set_value(config, NULL, "dpp_mud_url", "https://example.com/mud"); wpa_config_set_value(config, NULL, "sae_groups", "19 20 21"); wpa_config_set_value(config, NULL, "sae_pwe", "2"); wpa_config_set_value(config, NULL, "spp_amsdu", "0"); wpa_config_set_value(config, NULL, "tp_mesh_enable", "1"); wpa_config_set_value(config, NULL, "auto_reconnect_disabled", "1"); // === 添加 network 块 === wpa_config_add_network(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm"); // 设置 network 配置项 wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "disabled", "0"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "ssid", "\"mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm\""); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "urnm_mfpr", "0"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "key_mgmt", "WPA-PSK"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "proto", "WPA RSN"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "pairwise", "TKIP CCMP"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "group", "TKIP CCMP"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "psk", "\"4mdgr4T7nhTgspGKydjJ18nHR3BuSF\""); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "ieee80211w", "0"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "wep_tx_keyidx", "0"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "scan_ssid", "1"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "multi_ap_backhaul_sta", "1"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "dpp_connector", ""); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "bssid", ""); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "ocv", "0"); wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "freq_list", ""); // === 修改某些配置项(可选)=== wpa_config_set_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "scan_ssid", "0"); wpa_config_set_value(config, NULL, "auto_reconnect_disabled", "0"); // === 删除某些配置项(可选)=== wpa_config_clear_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "dpp_connector"); // === 添加一个新配置项(可选)=== wpa_config_add_value(config, "mkiJ8Jz4uE3zYU3v0PDSlqV29lePUm", "priority", "3"); // === 保存配置到文件 === wpa_config_save(config, "wpa_supplicant.conf"); // === 释放资源 === wpa_config_free(config); printf("配置已写入文件: wpa_supplicant.conf\n"); return 0; }

#include “config_parser.h” #include <ctype.h> #include <string.h> #include <stdlib.h> #include <stdio.h> // 释放 ConfigLine 链表 static void free_lines(ConfigLine *head) { while (head) { ConfigLine *tmp = head; head = head->next; free(tmp); } } // 释放 BssModule 链表 static void free_bss(BssModule *head) { while (head) { BssModule *tmp = head; head = head->next; free_lines(tmp->lines); free(tmp); } } // 释放整个 Config 结构 void config_free(Config *config) { if (!config) return; ConfigSection *sec = config->sections; while (sec) { ConfigSection *tmp = sec; sec = sec->next; if (tmp->is_bss_section) { free_bss(tmp->bss_list); } else { free_lines(tmp->lines); } free(tmp); } free(config); } // 创建新的 Config 结构 Config *config_new() { Config *config = (Config *)malloc(sizeof(Config)); if (!config) return NULL; config->sections = NULL; return config; } /** 打印指定配置节中的 bss_list 链表内容 @param sec 配置节指针 */ static void print_bss_list(ConfigSection *sec) { if (!sec || !sec->is_bss_section) { printf(“❌ 无效的配置节或不是 BSS 类型的节\n”); return; } BssModule *bss = sec->bss_list; if (!bss) { printf(“📄 节 [%s] 中没有 bss 模块\n”, sec->name); return; } printf(“📄 节 [%s] 中的 bss_list 内容:\n”, sec->name); int index = 0; while (bss) { printf(" %d. %s\n", index++, bss->name); bss = bss->next; } } // 查找指定名称的 section static ConfigSection *find_section(Config *config, const char *section_name) { for (ConfigSection *sec = config->sections; sec; sec = sec->next) { if (strcmp(sec->name, section_name) == 0) return sec; } return NULL; } // 查找指定名称的 bss static BssModule *find_bss(ConfigSection *section, const char *bss_name) { if (!section->is_bss_section) { printf(“❌ find_bss: section 不是 BSS 节\n”); return NULL; } printf("🔍 开始查找 bss: '%s'\n", bss_name); for (BssModule *bss = section->bss_list; bss; bss = bss->next) { printf(" 比较: '%s' vs '%s' => %d\n", bss->name, bss_name, strcmp(bss->name, bss_name)); // 打印十六进制,用于定位隐藏字符 printf(" bss->name hex: "); for (int i = 0; i < strlen(bss->name) && i < 32; i++) { printf("%02X ", (unsigned char)bss->name[i]); } printf("\n"); printf(" bss_name hex : "); for (int i = 0; i < strlen(bss_name) && i < 32; i++) { printf("%02X ", (unsigned char)bss_name[i]); } printf("\n"); if (strcmp(bss->name, bss_name) == 0) { printf("✅ 找到匹配的 bss: %s\n", bss_name); return bss; } } printf("find_bss: ❌ 未找到 bss: %s\n", bss_name); return NULL; } // 加载配置文件 Config *config_load(const char *filename) { FILE *fp = fopen(filename, “r”); if (!fp) return NULL; Config *config = config_new(); if (!config) { fclose(fp); return NULL; } ConfigSection *current_section = NULL; BssModule *current_bss = NULL; char line[MAX_LINE]; while (fgets(line, sizeof(line), fp)) { char *trimmed = line; while (isspace(*trimmed)) trimmed++; // 跳过空行和非 section 注释行 if (trimmed[0] == '\0' || trimmed[0] == '\n') continue; if (trimmed[0] == '#' && strncmp(trimmed, "##", 2) != 0) continue; if (strncmp(trimmed, "##", 2) == 0) { char *section_name_start = trimmed + 2; while (isspace(*section_name_start)) section_name_start++; char section_name[64] = {0}; int i = 0; while (*section_name_start && *section_name_start != '\n' && i < 63) { section_name[i++] = *section_name_start++; } ConfigSection *new_sec = (ConfigSection *)malloc(sizeof(ConfigSection)); if (!new_sec) continue; strncpy(new_sec->name, section_name, sizeof(new_sec->name) - 1); new_sec->is_bss_section = (strcmp(section_name, "BSS configurations") == 0); new_sec->next = NULL; // 插入到 config->sections 尾部 if (config->sections == NULL) { config->sections = new_sec; } else { ConfigSection *tmp = config->sections; while (tmp->next) tmp = tmp->next; tmp->next = new_sec; } current_section = new_sec; current_bss = NULL; } else if (strchr(trimmed, '=')) { if (!current_section) continue; char key[128], val[128]; if (sscanf(trimmed, "%127[^=]=%127[^\n]", key, val) != 2) continue; ConfigLine *new_line = (ConfigLine *)malloc(sizeof(ConfigLine)); if (!new_line) continue; strncpy(new_line->line, line, sizeof(new_line->line) - 1); new_line->line[sizeof(new_line->line) - 1] = '\0'; new_line->next = NULL; if (current_section->is_bss_section) { if (strcmp(key, "bss") == 0) { // 提取并清理 bss 名称 char *val_start = val; while (isspace(*val_start)) val_start++; size_t val_len = strlen(val_start); while (val_len > 0 && isspace((unsigned char)val_start[val_len - 1])) { val_start[--val_len] = '\0'; } if (val_len == 0) { printf("⚠️ bss 值为空,跳过\n"); free(new_line); continue; } BssModule *new_bss = (BssModule *)malloc(sizeof(BssModule)); if (!new_bss) { free(new_line); continue; } strncpy(new_bss->name, val_start, sizeof(new_bss->name) - 1); new_bss->name[sizeof(new_bss->name) - 1] = '\0'; printf("解析到 bss: '%s'\n", new_bss->name); new_bss->lines = new_line; new_bss->next = NULL; // 插入到 bss_list 尾部 if (current_section->bss_list == NULL) { current_section->bss_list = new_bss; } else { BssModule *tmp = current_section->bss_list; while (tmp->next) tmp = tmp->next; tmp->next = new_bss; } current_bss = new_bss; } else { if (current_bss) { // 插入到 bss->lines 尾部 new_line->next = NULL; if (current_bss->lines == NULL) { current_bss->lines = new_line; } else { ConfigLine *tmp = current_bss->lines; while (tmp->next) tmp = tmp->next; tmp->next = new_line; } } else { free(new_line); } } } else { // 非 BSS section 的普通行插入到 lines 尾部 new_line->next = NULL; if (current_section->lines == NULL) { current_section->lines = new_line; } else { ConfigLine *tmp = current_section->lines; while (tmp->next) tmp = tmp->next; tmp->next = new_line; } } } } // ✅ 打印所有 ConfigSection 名字,确认顺序 ConfigSection *sec = config->sections; printf("📄 所有配置节:\n"); while (sec) { printf(" - %s\n", sec->name); sec = sec->next; } // ✅ 打印第一个 BSS configurations 的 bss_list sec = find_section(config, "BSS configurations"); if (sec) { printf("【调试】加载完成后的 bss_list 内容:\n"); print_bss_list(sec); } fclose(fp); return config; } // 保存配置文件 int config_save(Config *config, const char *filename) { FILE *fp = fopen(filename, “w”); if (!fp) return -1; for (ConfigSection *sec = config->sections; sec; sec = sec->next) { fprintf(fp, "## %s\n", sec->name); if (sec->is_bss_section) { for (BssModule *bss = sec->bss_list; bss; bss = bss->next) { ConfigLine *first_line = bss->lines; if (first_line) { fprintf(fp, "%s", first_line->line); for (ConfigLine *line = first_line->next; line; line = line->next) { fprintf(fp, "%s", line->line); } } fprintf(fp, "\n"); } } else { for (ConfigLine *line = sec->lines; line; line = line->next) { fprintf(fp, "%s", line->line); } fprintf(fp, "\n"); } } fclose(fp); return 0; } // 获取 value int config_get_value(Config *config, const char *section_name, const char *bss_name, const char *key, char *value, size_t val_size) { ConfigSection *sec = find_section(config, section_name); if (!sec || !sec->is_bss_section) return -1; BssModule *bss = find_bss(sec, bss_name); if (!bss) return -1; printf("🔍 开始查找 key: %s 在 bss: %s\n", key, bss_name); for (ConfigLine *line = bss->lines; line; line = line->next) { printf("遍历行: %s\n", line->line); char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) != 2) { printf("❌ 解析失败: %s\n", line->line); continue; } printf("解析到 key: %s\n", k); if (strcmp(k, "bss") == 0) { printf("跳过 bss=xxx 行\n"); continue; } if (strcmp(k, key) == 0) { strncpy(value, v, val_size - 1); value[val_size - 1] = '\0'; return 0; } } return -1; } // 设置 value int config_set_value(Config *config, const char *section_name, const char *bss_name, const char *key, const char *new_value) { ConfigSection *sec = find_section(config, section_name); if (!sec || !sec->is_bss_section) return -1; BssModule *bss = find_bss(sec, bss_name); if (!bss) return -1; printf("🔧 开始设置 key: %s = %s 在 bss: %s\n", key, new_value, bss_name); for (ConfigLine *line = bss->lines; line; line = line->next) { printf("遍历行: %s\n", line->line); char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) != 2) { printf("❌ 解析失败: %s\n", line->line); continue; } printf("解析到 key: %s\n", k); if (strcmp(k, "bss") == 0) { printf("跳过 bss=xxx 行\n"); continue; } if (strcmp(k, key) == 0) { snprintf(line->line, sizeof(line->line), "%s=%s\n", k, new_value); return 0; } } // 如果找不到 key,可以添加新行 ConfigLine *new_line = (ConfigLine *)malloc(sizeof(ConfigLine)); if (!new_line) return -1; snprintf(new_line->line, sizeof(new_line->line), "%s=%s\n", key, new_value); new_line->next = bss->lines; bss->lines = new_line; return 0; } // 清空 value int config_clear_value(Config *config, const char *section, const char *bss, const char *key) { return config_set_value(config, section, bss, key, “”); } // 追加 value int config_add_value(Config *config, const char *section, const char *bss, const char *key, const char *new_value) { ConfigSection *sec = find_section(config, section); if (!sec) return -1; if (bss && sec->is_bss_section) { BssModule *bss_mod = find_bss(sec, bss); if (!bss_mod) return -1; for (ConfigLine *line = bss_mod->lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { char new_line[256]; if (strlen(v) == 0) { snprintf(new_line, sizeof(new_line), "%s=%s\n", key, new_value); } else { snprintf(new_line, sizeof(new_line), "%s=%s %s\n", key, v, new_value); } strncpy(line->line, new_line, sizeof(line->line) - 1); line->line[sizeof(line->line) - 1] = '\0'; return 0; } } } else { for (ConfigLine *line = sec->lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { char new_line[256]; if (strlen(v) == 0) { snprintf(new_line, sizeof(new_line), "%s=%s\n", key, new_value); } else { snprintf(new_line, sizeof(new_line), "%s=%s %s\n", key, v, new_value); } strncpy(line->line, new_line, sizeof(line->line) - 1); line->line[sizeof(line->line) - 1] = '\0'; return 0; } } } return -1; } void print_bss_lines(Config *config, const char *bss_name) { ConfigSection *sec = find_section(config, “BSS configurations”); if (!sec || !sec->is_bss_section) { printf(“printf_bss_lines:❌ 找不到 BSS configurations 节\n”); return; } BssModule *bss = find_bss(sec, bss_name); if (!bss) { printf("printf_bss_lines: ❌ 找不到 bss: %s\n", bss_name); return; } printf("📄 %s 的配置行如下:\n", bss_name); for (ConfigLine *line = bss->lines; line; line = line->next) { printf(" %s\n", line->line); } } #include “config_parser.h” #include <stdio.h> int main() { Config *config = config_load(“wl0.1_hapd.conf”); if (!config) { printf(“加载配置失败\n”); return -1; } // 打印 wl0.2 的所有配置行 print_bss_lines(config, "wl0.2"); char value[128]; int ret = config_get_value(config, "BSS configurations", "wl0.2", "bridge", value, sizeof(value)); if (ret == 0) { printf("wl0.2 的 bridge: %s\n", value); } else { printf("⚠️ 未找到 wl0.2 或其 bridge 字段\n"); } int set_ret = config_set_value(config, "BSS configurations", "wl0.2", "bridge", "br-wan"); if (set_ret == 0) { printf("✅ 已修改 wl0.2 的 bridge 为 br-wan\n"); } else { printf("❌ 修改失败,未找到 wl0.2\n"); } config_save(config, "wl0.1_hapd.conf.new"); config_free(config); return 0; } #ifndef CONFIG_PARSER_H #define CONFIG_PARSER_H #include <stdio.h> #define MAX_LINE 1024 typedef struct ConfigLine { char line[MAX_LINE]; struct ConfigLine *next; } ConfigLine; typedef struct BssModule { char name[64]; ConfigLine *lines; struct BssModule *next; } BssModule; typedef struct ConfigSection { char name[128]; int is_bss_section; // 1 if it’s a BSS section union { ConfigLine *lines; BssModule *bss_list; }; struct ConfigSection *next; } ConfigSection; typedef struct { ConfigSection *sections; } Config; Config *config_load(const char *filename); int config_save(Config *config, const char *filename); void config_free(Config *config); int config_get_value(Config *config, const char *section, const char *bss, const char *key, char *value, size_t size); int config_set_value(Config *config, const char *section, const char *bss, const char *key, const char *value); int config_clear_value(Config *config, const char *section, const char *bss, const char *key); int config_add_value(Config *config, const char *section, const char *bss, const char *key, const char *new_value); void print_bss_lines(Config *config, const char *bss_name) ; #endif // CONFIG_PARSER_H运行结果如下zhilong@server:~/桌面/test/test20250821$ ./main 解析到 bss: ‘wl0.3’ 解析到 bss: ‘wl0.2’ 解析到 bss: ‘wl0.7’ 解析到 bss: ‘wl0.8’ 📄 所有配置节: General configurations Interface configurations BSS configurations BSS configurations BSS configurations BSS configurations 【调试】加载完成后的 bss_list 内容: 📄 节 [BSS configurations] 中的 bss_list 内容: wl0.3 🔍 开始查找 bss: ‘wl0.2’ 比较: ‘wl0.3’ vs ‘wl0.2’ => 1 bss->name hex: 77 6C 30 2E 33 bss_name hex : 77 6C 30 2E 32 find_bss: ❌ 未找到 bss: wl0.2 printf_bss_lines: ❌ 找不到 bss: wl0.2 🔍 开始查找 bss: ‘wl0.2’ 比较: ‘wl0.3’ vs ‘wl0.2’ => 1 bss->name hex: 77 6C 30 2E 33 bss_name hex : 77 6C 30 2E 32 find_bss: ❌ 未找到 bss: wl0.2 ⚠️ 未找到 wl0.2 或其 bridge 字段 🔍 开始查找 bss: ‘wl0.2’ 比较: ‘wl0.3’ vs ‘wl0.2’ => 1 bss->name hex: 77 6C 30 2E 33 bss_name hex : 77 6C 30 2E 32 find_bss: ❌ 未找到 bss: wl0.2 ❌ 修改失败,未找到 wl0.2是什么地方出问题了,前提我同意多节创造是可以的,可以依据bss的值区分,我在意的是链表是否创建成功,结构是否有问题,为什么遍历不出来

#include "config_parser.h" #include <ctype.h> #include <string.h> #include <stdlib.h> #include <stdio.h> // 释放 ConfigLine 链表 static void free_lines(ConfigLine *head) { while (head) { ConfigLine *tmp = head; head = head->next; free(tmp); } } // 释放 BssModule 链表 static void free_bss(BssModule *head) { while (head) { BssModule *tmp = head; free_lines(tmp->lines); head = head->next; free(tmp); } } // 释放整个 Config 结构 void config_free(Config *config) { if (!config) return; ConfigSection *sec = config->sections; while (sec) { ConfigSection *tmp = sec; sec = sec->next; if (tmp->is_bss_section) { free_bss(tmp->bss_list); } else { free_lines(tmp->lines); } free(tmp); } free(config); } // 创建新的 Config 结构 Config *config_new() { Config *config = (Config *)malloc(sizeof(Config)); if (!config) return NULL; config->sections = NULL; return config; } // 查找指定名称的 section static ConfigSection *find_section(Config *config, const char *section_name) { for (ConfigSection *sec = config->sections; sec; sec = sec->next) { if (strcmp(sec->name, section_name) == 0) return sec; } return NULL; } // 查找指定名称的 bss static BssModule *find_bss(ConfigSection *section, const char *bss_name) { if (!section->is_bss_section) return NULL; for (BssModule *bss = section->bss_list; bss; bss = bss->next) { if (strcmp(bss->name, bss_name) == 0) return bss; } return NULL; } // 加载配置文件 Config *config_load(const char *filename) { FILE *fp = fopen(filename, "r"); if (!fp) return NULL; Config *config = config_new(); if (!config) { fclose(fp); return NULL; } ConfigSection *current_section = NULL; BssModule *current_bss = NULL; char line[MAX_LINE]; while (fgets(line, sizeof(line), fp)) { char *trimmed = line; while (isspace(*trimmed)) trimmed++; if (strncmp(trimmed, "##", 2) == 0) { char *section_name_start = trimmed + 2; while (isspace(*section_name_start)) section_name_start++; char section_name[64] = {0}; int i = 0; while (*section_name_start && *section_name_start != '\n' && i < 63) { section_name[i++] = *section_name_start++; } ConfigSection *new_sec = (ConfigSection *)malloc(sizeof(ConfigSection)); if (!new_sec) continue; strncpy(new_sec->name, section_name, sizeof(new_sec->name) - 1); new_sec->is_bss_section = (strcmp(section_name, "BSS configurations") == 0); new_sec->next = config->sections; config->sections = new_sec; if (new_sec->is_bss_section) { new_sec->bss_list = NULL; } else { new_sec->lines = NULL; } current_section = new_sec; current_bss = NULL; } else if (strchr(trimmed, '=')) { if (!current_section) continue; char key[128], val[128]; if (sscanf(trimmed, "%127[^=]=%127[^\n]", key, val) != 2) continue; ConfigLine *new_line = (ConfigLine *)malloc(sizeof(ConfigLine)); if (!new_line) continue; strncpy(new_line->line, line, sizeof(new_line->line) - 1); new_line->line[sizeof(new_line->line) - 1] = '\0'; new_line->next = NULL; if (current_section->is_bss_section) { if (strcmp(key, "bss") == 0) { BssModule *new_bss = (BssModule *)malloc(sizeof(BssModule)); if (!new_bss) { free(new_line); continue; } strncpy(new_bss->name, val, sizeof(new_bss->name) - 1); new_bss->lines = new_line; new_bss->next = current_section->bss_list; current_section->bss_list = new_bss; current_bss = new_bss; } else { if (current_bss) { new_line->next = current_bss->lines; current_bss->lines = new_line; } else { free(new_line); } } } else { new_line->next = current_section->lines; current_section->lines = new_line; } } } fclose(fp); return config; } // 保存配置文件 int config_save(Config *config, const char *filename) { FILE *fp = fopen(filename, "w"); if (!fp) return -1; for (ConfigSection *sec = config->sections; sec; sec = sec->next) { fprintf(fp, "## %s\n", sec->name); if (sec->is_bss_section) { for (BssModule *bss = sec->bss_list; bss; bss = bss->next) { ConfigLine *first_line = bss->lines; if (first_line) { fprintf(fp, "%s", first_line->line); for (ConfigLine *line = first_line->next; line; line = line->next) { fprintf(fp, "%s", line->line); } } fprintf(fp, "\n"); } } else { for (ConfigLine *line = sec->lines; line; line = line->next) { fprintf(fp, "%s", line->line); } fprintf(fp, "\n"); } } fclose(fp); return 0; } // 获取 value int config_get_value(Config *config, const char *section, const char *bss, const char *key, char *value, size_t size) { ConfigSection *sec = find_section(config, section); if (!sec) return -1; if (bss && sec->is_bss_section) { BssModule *bss_mod = find_bss(sec, bss); if (!bss_mod) return -1; for (ConfigLine *line = bss_mod->lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { strncpy(value, v, size - 1); value[size - 1] = '\0'; return 0; } } } else { for (ConfigLine *line = sec->lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { strncpy(value, v, size - 1); value[size - 1] = '\0'; return 0; } } } return -1; } // 设置 value int config_set_value(Config *config, const char *section, const char *bss, const char *key, const char *value) { ConfigSection *sec = find_section(config, section); if (!sec) return -1; if (bss && sec->is_bss_section) { BssModule *bss_mod = find_bss(sec, bss); if (!bss_mod) return -1; for (ConfigLine *line = bss_mod->lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { snprintf(line->line, sizeof(line->line), "%s=%s\n", key, value); return 0; } } } else { for (ConfigLine *line = sec->lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { snprintf(line->line, sizeof(line->line), "%s=%s\n", key, value); return 0; } } } return -1; } // 清空 value int config_clear_value(Config *config, const char *section, const char *bss, const char *key) { return config_set_value(config, section, bss, key, ""); } // 追加 value int config_add_value(Config *config, const char *section, const char *bss, const char *key, const char *new_value) { ConfigSection *sec = find_section(config, section); if (!sec) return -1; if (bss && sec->is_bss_section) { BssModule *bss_mod = find_bss(sec, bss); if (!bss_mod) return -1; for (ConfigLine *line = bss_mod->lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { char new_line[256]; if (strlen(v) == 0) { snprintf(new_line, sizeof(new_line), "%s=%s\n", key, new_value); } else { snprintf(new_line, sizeof(new_line), "%s=%s %s\n", key, v, new_value); } strncpy(line->line, new_line, sizeof(line->line) - 1); line->line[sizeof(line->line) - 1] = '\0'; return 0; } } } else { for (ConfigLine *line = sec->lines; line; line = line->next) { char k[128], v[128]; if (sscanf(line->line, "%127[^=]=%127[^\n]", k, v) == 2 && strcmp(k, key) == 0) { char new_line[256]; if (strlen(v) == 0) { snprintf(new_line, sizeof(new_line), "%s=%s\n", key, new_value); } else { snprintf(new_line, sizeof(new_line), "%s=%s %s\n", key, v, new_value); } strncpy(line->line, new_line, sizeof(line->line) - 1); line->line[sizeof(line->line) - 1] = '\0'; return 0; } } } return -1; } 给出修改后的.c文件

最新推荐

recommend-type

智能体平台dify-1.13版本的sql表结构

https://github.com/langgenius 提供的docker版本,开源提供的sql有一些缺失,项目无法运行。 从docker拉出来的结构,已验证,1.13版本可部署运行。
recommend-type

【scratch3.0少儿编程-游戏原型-动画-项目源码】河道清理船巡线改编.zip

资源说明: 1:本资料仅用作交流学习参考,请切勿用于商业用途。 2:一套精品实用scratch3.0少儿编程游戏、动画源码资源,无论是入门练手还是项目复用都超实用,省去重复开发时间,让开发少走弯路! 更多精品资源请访问 https://blog.csdn.net/ashyyyy/article/details/146464041
recommend-type

具备建图导航人脸及异常行为检测功能的 ROS 安防机器人

打开下面链接,直接免费下载资源: https://renmaiwang.cn/s/i0hbr ROS 安防机器人系统,能够为用户提供包括建图导航、人脸识别以及异常行为检测在内的多项核心功能。
recommend-type

微信小程序基础实验项目_大学课程实践作业_微信开发者工具_前端开发_JavaScript_WXML_WXSS_小程序框架_组件应用_API调用_云开发_数据绑定_事件处理_页面路由.zip

微信小程序基础实验项目_大学课程实践作业_微信开发者工具_前端开发_JavaScript_WXML_WXSS_小程序框架_组件应用_API调用_云开发_数据绑定_事件处理_页面路由.zip
recommend-type

采用普通摄像头结合 dlib 与 opencv 实现人脸 68 点检测及识别

打开下面链接,直接免费下载资源: https://renmaiwang.cn/s/wverw 在对人的正面脸部展开识别工作的过程中,所运用的设备为常规类型的摄像头,同时,在技术应用层面,借助 dlib 工具来对人脸的 68 个特征点实施检测操作,并且利用 opencv 中的 FaceRecognizer 模块分别开展人脸模型的训练工作与后续的人脸识别工作。
recommend-type

Docker环境下的弹性APM服务器搭建指南

根据提供的文件信息,我们可以梳理出以下几个关键知识点: 1. Docker技术概念: Docker是一个开源的应用容器引擎,允许开发者打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何支持Docker的平台上。容器是完全使用沙箱机制,相互之间不会有任何接口(类似iOS的app)。 2. Docker的使用优势: 使用Docker部署应用可以带来多方面的优势,如提高开发效率、简化部署流程、易于迁移和扩展、强化安全性和隔离性等。容器化应用可以在不同的环境中保持一致的运行状态,减少了"在我的机器上可以运行"这类问题。 3. Compose工具: Docker Compose是一个用来定义和运行多容器Docker应用程序的工具。通过Compose,用户可以使用YAML文件来配置应用程序服务,并通过一个命令,完成容器的创建和启动。Docker Compose使得复杂配置的多容器应用的部署和管理工作变得简单。 4. APM(应用性能管理)服务器: APM服务器是用来监控和管理软件应用性能的工具。它通常包括实时性能监控、问题诊断、性能瓶颈定位、用户体验报告等功能。通过提供深入的应用性能洞察,APM能够帮助开发者和运维人员优化和提升应用性能。 5. 弹性APM服务器: 在标题中提到的“弹性”可能是指APM服务器能够根据应用的性能需求自动调整资源分配。这种弹性服务器可以动态地根据负载情况增加或减少资源,以保证应用性能的稳定,并在必要时节省资源。 6. Docker和Compose在APM服务器部署中的作用: Docker和Compose共同作用于APM服务器的部署,意味着开发者可能通过定义一个Docker Compose文件来指定APM服务器的所有依赖和服务。利用容器化的方式,可以保证APM服务器在开发、测试和生产环境中的部署和运行一致性。 7. “docker-apm-master”文件结构: 文件名称列表中提及的“docker-apm-master”很可能是包含Dockerfile、docker-compose.yml等文件的目录名称,这个目录用于管理和构建弹性APM服务器的Docker镜像和服务。在该目录下,可能包含了用于构建APM服务器镜像的脚本、配置文件,以及用于部署和管理APM服务器的Docker Compose配置。 8. 开发和运维实践: 一个“由Docker和Compose支持的弹性apm服务器”项目体现了现代软件开发和运维的实践,即使用容器化和自动化工具来提升开发效率、简化运维工作以及优化应用部署。在微服务架构和云计算日益普及的今天,这类实践变得越来越普遍。 综合以上知识点,我们可以理解“docker-apm:由Docker和Compose支持的弹性apm服务器”是一个运用现代开发运维技术实践,提供应用性能管理解决方案的项目。它结合了Docker容器化技术和Docker Compose自动化管理工具,以实现一个可扩展、弹性的APM服务器,帮助开发者和运维团队高效地监控和优化应用性能。
recommend-type

游戏开发与部署全流程指南

# 游戏开发与部署全流程指南 ## 1. 开发整体游戏结构 ### 1.1 场景添加与游戏启动 要确保场景能被加载,需将其添加到构建设置中。若不添加,Unity 就无法知晓可用的场景。在之前的测试中,若只是重新加载当前场景,无需进行此操作;但现在若要切换关卡,就必须添加。添加完成后,可从启动场景点击“播放”来启动游戏,此时游戏管理器对象会在两个场景中共享。 不过需注意,由于管理器是在启动场景中加载的,所以必须始终从该场景启动游戏。若觉得每次手动打开启动场景麻烦,可使用此编辑器脚本,它能在点击“播放”时自动切换到指定场景:[https://github.com/jhocking/from-u
recommend-type

初级运维面试题

<think> 首先,用户的问题是:“我想查找初级运维面试题”,这是在查询初级运维岗位的面试题。系统指令要求我参考提供的引用内容,这些引用来自之前的消息。 回顾引用内容: - 引用[1]:是关于运维面试题的文章,提到“2024年9月最新运维高频面试题汇总(1)”,但它是个标题,没有具体题目内容。它宣传了一个群组。 - 引用[2]:是“云计算运维工程师面试题(二)”,列出了11个具体问题,涉及云计算、弹性伸缩、高可用性、安全等。这些不是专门针对初级的,但可能涵盖。 - 引用[3]:是“初级运维工程师面试题”,描述了一个场景:查杀病毒的过程,提到了一个可疑进程。这不是直接的面试题列表,而是
recommend-type

构建Ikiwiki的Docker容器:简易部署与使用

### 知识点概述 #### 标题:“docker-ikiwiki:Ikiwiki的Docker容器” - Docker:一种开源的容器化平台,用于自动化部署、扩展和管理应用程序。 - Ikiwiki:一个使用git作为后端的wiki引擎,其特色在于使用Markdown或Textile等标记语言编辑页面。 - 容器化部署:利用Docker技术进行软件的打包、分发和运行,以容器形式提供一致的运行环境。 #### 描述:“Ikiwiki Docker容器” - Docker映像与使用:介绍了如何通过命令行工具拉取并运行一个Ikiwiki的Docker镜像。 - 拉取Docker镜像:使用命令`docker pull ankitrgadiya/ikiwiki`从Docker Hub中获取预配置好的Ikiwiki容器镜像。 - 使用方式:提供了两种使用该Docker镜像的示例,一种是与域名绑定进行SSL支持的配置,另一种是作为独立运行且不支持SSL的配置。 - 独立映像的局限性:明确指出独立映像不支持SSL,因此推荐与Nginx-Proxy结合使用以获得更好的网络服务。 #### 标签:“docker ikiwiki Shell” - 标签汇总:这些标签提示了该文档内容涉及的技术范畴,即Docker容器技术、Ikiwiki应用以及Shell命令行操作。 - Docker标签:强调了Docker在自动化部署Ikiwiki中的应用。 - Ikiwiki标签:指出了本文内容与Ikiwiki的使用和配置相关。 - Shell标签:表明操作过程涉及到Linux Shell命令的执行。 #### 压缩包子文件的文件名称列表:“docker-ikiwiki-master” - 压缩包内容:该列表暗示了压缩包内包含的文件是以"docker-ikiwiki-master"为名称的主目录或项目文件。 - 文件结构:可能包含了Dockerfile、配置脚本、说明文档等文件,用于构建和运行Ikiwiki Docker容器。 ### 详细知识点 #### Docker容器技术 - Docker基础:Docker是一个开源的应用容器引擎,允许开发者打包他们的应用以及应用的依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口(类似 iPhone 的 app)。 - 镜像与容器:在Docker中,镜像(Image)是一个可执行包,包含了运行应用程序所需的所有内容,例如代码、运行时、库、环境变量和配置文件。容器(Container)是从镜像创建的应用运行实例,可以进行启动、停止、删除等操作。每个容器都是相互隔离的,保证应用安全运行。 #### Ikiwiki的配置与部署 - Ikiwiki简介:Ikiwiki是一个用git作为后端的wiki引擎,它允许通过文本文件来编辑网页,支持Markdown、Textile等标记语言,使得内容的编写更加直观和方便。 - 部署要求:部署Ikiwiki通常需要一个web服务器和一些配置来处理HTTP请求。而通过Docker,用户可以快速部署一个预配置好的Ikiwiki环境。 - 配置方式:Docker运行命令中涉及到了多个参数的使用,如`--name`用于给容器命名,`-v`用于指定挂载卷,`-e`用于设置环境变量,`-p`用于端口映射,`-d`用于让容器在后台运行。 #### Docker命令行操作 - docker pull:从Docker Hub或用户指定的仓库拉取指定的镜像。 - docker run:创建一个新的容器并运行一个命令。这里提供了两种运行Ikiwiki的方式,一种是用于生产环境的,与域名绑定并支持SSL;另一种是用于开发或测试环境的,直接在80端口运行。 #### 网络代理和SSL支持 - SSL支持:SSL(Secure Sockets Layer)是一种安全协议,用于保障Web服务器和浏览器之间的通信安全。当容器配置为不支持SSL时,通常意味着不直接处理HTTPS请求。 - Nginx-Proxy:一个Docker镜像,用于运行一个Nginx服务器,充当SSL终止层,将SSL终止在Nginx代理中,然后将非加密的HTTP请求转发到后端的容器。这样可以利用Nginx强大的网络功能来处理HTTPS、HTTP/2等,增强系统的安全性和效率。 ### 总结 在介绍如何部署Ikiwiki wiki引擎到Docker容器的过程中,涉及到了Docker的基本概念、容器的创建和配置、Ikiwiki的运行机制以及Shell命令行的实用操作。文档也提到了在使用不支持SSL的独立容器时,推荐配合Nginx-Proxy来增强安全性和扩展性。这些知识点对于管理和维护Docker容器化的应用具有很高的实用价值。
recommend-type

Unity开发实用指南:快捷键、外部工具与模型创建

### Unity开发实用指南:快捷键、外部工具与模型创建 #### 1. Unity场景导航与键盘快捷键 在使用Unity进行开发时,一个三键鼠标会带来更好的操作体验,虽然Unity也支持单键或双键鼠标,但三键鼠标能让操作更加便捷,在Mac系统上同样适用。 除了使用鼠标进行导航操作外,键盘也能实现一些视图控制功能。当按住鼠标右键时,可以使用键盘上的W、A、S、D键像在第一人称游戏中一样移动视角。在进行其他操作时按住Shift键可以加快移动速度。 而在选择对象后按下F键,场景视图会自动平移和缩放以聚焦该对象。如果在场景导航中迷失方向,可以在层级面板中选择一个对象,将鼠标移到场景视图上(此