├── images ├── sys_config.png ├── sample_xr872.png └── sample_windows_linux.png ├── LICENSE ├── sample ├── sample_windows_linux.c └── sample_mcu_xr872.c ├── src ├── libinimini.h └── libinimini.c └── README.md /images/sys_config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovemengx/libinimini/HEAD/images/sys_config.png -------------------------------------------------------------------------------- /images/sample_xr872.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovemengx/libinimini/HEAD/images/sample_xr872.png -------------------------------------------------------------------------------- /images/sample_windows_linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lovemengx/libinimini/HEAD/images/sample_windows_linux.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 lovemengx 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sample/sample_windows_linux.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @文件 main.c 4 | * @版本 V1.0.0 5 | * @日期 6 | * @概要 用于举例说明 libinimini 如何在 Windows/Linux 中应用 7 | * @作者 lmx 8 | ****************************************************************************** 9 | * @注意 10 | ****************************************************************************** 11 | */ 12 | #include 13 | #include 14 | #include "../src/libinimini.h" 15 | 16 | // 由 libinimini 回调,用于将解析的结果返回 17 | // 返回值: LIB_INIMINI_STOP:停止解析 LIB_INIMINI_KEEP:继续解析 18 | static int inimini_result_cb(libinimini_data_t* data, void* context) 19 | { 20 | printf("section:%-20s keyname:%-30s strval:%-30s\n", data->section, data->keyname, data->strval); 21 | if (strcmp(data->section, "compass_para") == 0 && strcmp(data->keyname, "compass_int") == 0) { 22 | printf("-------------------------------------------------\n"); 23 | printf("[%s]\n", data->section); 24 | printf("%s = %s\n", data->keyname, data->strval); 25 | printf("-------------------------------------------------\n"); 26 | return LIB_INIMINI_STOP; 27 | } 28 | return LIB_INIMINI_KEEP; 29 | } 30 | 31 | // 由 libinimini 回调,用于获取每一行的原始文本数据 32 | // 返回值: 0: 已无数据可以提供 >0: 字符串数据的长度 33 | static unsigned int inimini_getline_cb(char* buf, unsigned int size, void* contex) 34 | { 35 | FILE* fp = (FILE*)contex; 36 | if (fgets(buf, size, fp) == NULL) { 37 | return LIB_INIMINI_STOP; 38 | } 39 | return strlen(buf); 40 | } 41 | 42 | int main(void) 43 | { 44 | char inimini_cache[1024] = { 0 }; 45 | libinimini_parameter_t para; 46 | 47 | FILE* fp = fopen("F:/sys_config.ini", "r"); 48 | if (NULL == fp) { 49 | printf("open file failed\n"); 50 | return 0; 51 | } 52 | 53 | memset(¶, 0x00, sizeof(libinimini_parameter_t)); 54 | para.contex = fp; 55 | para.result = inimini_result_cb; 56 | para.ops.getline_cb = inimini_getline_cb; 57 | int cnt = libinimini_foreach(¶, inimini_cache, sizeof(inimini_cache)); 58 | fclose(fp); 59 | 60 | printf("libinimini_foreach done...\n"); 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /sample/sample_mcu_xr872.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @文件 main.c 4 | * @版本 V1.0.0 5 | * @日期 6 | * @概要 用于举例说明 libinimini 如何在单片机中应用 7 | * @作者 lmx 8 | ****************************************************************************** 9 | * @注意 10 | ****************************************************************************** 11 | */ 12 | #include 13 | #include 14 | #include "fs/fatfs/ff.h" 15 | #include "kernel/os/os.h" 16 | #include "../src/libinimini.h" 17 | #include "common/framework/fs_ctrl.h" 18 | #include "common/framework/platform_init.h" 19 | 20 | // 由 libinimini 回调,用于将解析的结果返回 21 | // 返回值: LIB_INIMINI_STOP:停止解析 LIB_INIMINI_KEEP:继续解析 22 | static int inimini_result_cb(libinimini_data_t* data, void* context) 23 | { 24 | printf("section:%-20s keyname:%-30s strval:%-30s\n", data->section, data->keyname, data->strval); 25 | if (strcmp(data->section, "compass_para") == 0 && strcmp(data->keyname, "compass_int") == 0) { 26 | printf("-------------------------------------------------\n"); 27 | printf("[%s]\n", data->section); 28 | printf("%s = %s\n", data->keyname, data->strval); 29 | printf("-------------------------------------------------\n"); 30 | return LIB_INIMINI_STOP; 31 | } 32 | return LIB_INIMINI_KEEP; 33 | } 34 | 35 | // 由 libinimini 回调,用于获取每一行的原始文本数据 36 | // 返回值: 0: 已无数据可以提供 >0: 字符串数据的长度 37 | static unsigned int inimini_getline_cb(char* buf, unsigned int size, void* context) 38 | { 39 | FIL* fp = (FIL*)context; 40 | if (f_gets(buf, size, fp) == NULL) { 41 | return LIB_INIMINI_STOP; 42 | } 43 | return (unsigned int)strlen(buf); 44 | } 45 | 46 | int main(void) 47 | { 48 | FIL file; 49 | static char cache[512] = { 0 }; 50 | libinimini_parameter_t para; 51 | 52 | platform_init(); 53 | 54 | if(fs_ctrl_mount(FS_MNT_DEV_TYPE_SDCARD, 0) != FS_MNT_STATUS_MOUNT_OK){ 55 | printf("fs mount failed\n"); 56 | while(1) OS_Sleep(1); 57 | } 58 | 59 | if(f_open(&file, "sys_config.ini", FA_READ | FA_OPEN_EXISTING) != FR_OK){ 60 | printf("open file failed\n"); 61 | while(1) OS_Sleep(1); 62 | } 63 | 64 | memset(¶, 0x00, sizeof(libinimini_parameter_t)); 65 | para.contex = &file; 66 | para.result = inimini_result_cb; 67 | para.ops.getline_cb = inimini_getline_cb; 68 | libinimini_foreach(¶, cache, sizeof(cache)); 69 | f_close(&file); 70 | 71 | printf("libinimini_foreach done...\n"); 72 | while(1) OS_Sleep(1); 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /src/libinimini.h: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @文件 libinimini.h 4 | * @版本 V1.0.2 5 | * @日期 2022-02-28 6 | * @概要 7 | * 1. 适用于在跑 RTOS 或裸跑的单片机平台上读取 ini 配置文件。 8 | * 2. 因单片机 RAM 稀有性,接口不会动态申请, 所需的内存由外部提供。 9 | * 3. 因单片机的文件系统差异和数据来源丰富, 接口实现不局限于文件。 10 | * @作者 lmx QQ:1007566569 EMAIL:lovemengx@foxmail.com 11 | ****************************************************************************** 12 | * @注意 13 | ****************************************************************************** 14 | */ 15 | #ifndef __LIB_INI_MINI_H__ 16 | #define __LIB_INI_MINI_H__ 17 | 18 | #define LIB_INIMINI_KEEP 1 // 继续解析 19 | #define LIB_INIMINI_STOP 0 // 终止解析 20 | 21 | // 缓冲区回调 22 | typedef struct { 23 | /***************************************************************************** 24 | * 函数: getline_cb 25 | * 功能: 由用户实现, 用于接口库获取 ini 配置文件的每一行字符串的函数 26 | * 参数: buf:由接口库传入的缓冲区, 用于存储一行字符串 size:缓冲区大小 27 | * contex:用户的上下文指针, 由初始化时用户传入 28 | * 返回: 0:已无数据可以提供,接口库会停止解析 >0:字符串数据的长度 29 | ******************************************************************************/ 30 | unsigned int (*getline_cb)(char* buf, unsigned int size, void* contex); 31 | }libinimini_buffer_ops; 32 | 33 | // ini 配置的某一项字段内容 34 | typedef struct { 35 | const char* section; // ini 字段字符串 36 | const char* keyname; // ini 键名字符串 37 | const char* strval; // ini 键值字符串 38 | }libinimini_data_t; 39 | 40 | /***************************************************************************** 41 | * 函数: libinimini_result_fun 42 | * 功能: 接口库解析到完整的配置信息后会通过此回调返回数据 43 | * 参数: data:接口库解析成功的配置信息 44 | * contex:用户的上下文指针, 由初始化时用户传入 45 | * 返回: LIB_INIMINI_KEEP:允许接口库继续解析下一个配置 46 | * LIB_INIMINI_STOP:终止接口库继续解析配置 47 | ******************************************************************************/ 48 | typedef int (*libinimini_result_fun)(libinimini_data_t* data, void* contex); 49 | 50 | // 接口参数配置 51 | typedef struct { 52 | libinimini_buffer_ops ops; // 获取数据的回调 53 | libinimini_result_fun result; // 数据结果的回调 54 | void* contex; // 用户上下文指针 55 | }libinimini_parameter_t; 56 | 57 | /******************************************************************** 58 | * 函数: libinimini_foreach 59 | * 功能: 遍历整个 ini 配置文件, 并通过回调获取数据和输出内容 60 | * 参数: para: 参数配置 61 | * cache:用于处理数据和返回内容的缓冲区 62 | * size: 缓冲区大小, 必须大于字段名称+键值内容长度 63 | * 返回: 已遍历成功的 ini 配置数量 64 | *********************************************************************/ 65 | int libinimini_foreach(libinimini_parameter_t* para, char* cache, unsigned int size); 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## libinimini 2 | 3 | 最近自己基于 XR872 做一个小作品练习练习,具备可以配置的功能,选择了使用 ini 作为配置文件。我调研了网上常见的 ini 解析库,几乎都涉及到了 fopen()/fgets().. 以及 malloc()。 4 | 5 | 说明这些开源库都仅适用于 linux 系统,并不适用于 RTOS 或裸跑的单片机。因为前者虽是 C 语言的标准文件操作函数,但在单片机中基本上使用的都是简化版的 fatfs 接口,要想引入单片机使用,意味着需要对该接口库进行修改。后者更是涉及到内存管理,ram 的占用会随着 ini 配置文件的内容而变化,意味着 ram 的使用不可控,极易受外部因素影响,这对 ram 资源极为稀有的单片机来说,是不可接受的。 6 | 7 | 本着学习的态度,就设计了一个非常简单的 ini 配置文件解析库(libinimini),具有以下几种特点: 8 | 9 | * 内存空间占用可控,libinimini 只使用用户指定的一段内存空间进行解析和返回结果。 10 | * 不关心数据的来源,libinimini 通过回调用户的接口获取每一行文本,不关心文本来自文件还是其它通信接口。 11 | * 使用方便简单易上手,用户只需实现以行为单位的文本数据回调接口,之后只需等待 libinimini 解析结果即可。 12 | 13 | 注意:接口本身会将键值作为字符串传递出来,如果需要转换为数字,调用 atoi() 的函数转换即可。 14 | 15 | ## 接口介绍 16 | 17 | ```C 18 | // 缓冲区回调 19 | typedef struct { 20 | /***************************************************************************** 21 | * 函数: getline_cb 22 | * 功能: 由用户实现, 用于接口库获取 ini 配置文件的每一行字符串的函数 23 | * 参数: buf:由接口库传入的缓冲区, 用于存储一行字符串 size:缓冲区大小 24 | * contex:用户的上下文指针, 由初始化时用户传入 25 | * 返回: 0:已无数据可以提供,接口库会停止解析 >0:字符串数据的长度 26 | ******************************************************************************/ 27 | unsigned int (*getline_cb)(char* buf, unsigned int size, void* contex); 28 | }libinimini_buffer_ops; 29 | 30 | // ini 配置的某一项字段内容 31 | typedef struct { 32 | const char* section; // ini 字段字符串 33 | const char* keyname; // ini 键名字符串 34 | const char* strval; // ini 键值字符串 35 | }libinimini_data_t; 36 | 37 | /***************************************************************************** 38 | * 函数: libinimini_result_fun 39 | * 功能: 接口库解析到完整的配置信息后会通过此回调返回数据 40 | * 参数: data:接口库解析成功的配置信息 41 | * contex:用户的上下文指针, 由初始化时用户传入 42 | * 返回: LIB_INIMINI_KEEP:允许接口库继续解析下一个配置 43 | * LIB_INIMINI_STOP:终止接口库继续解析配置 44 | ******************************************************************************/ 45 | typedef int (*libinimini_result_fun)(libinimini_data_t* data, void* contex); 46 | 47 | // 接口参数配置 48 | typedef struct { 49 | libinimini_buffer_ops ops; // 获取数据的回调 50 | libinimini_result_fun result; // 数据结果的回调 51 | void* contex; // 用户上下文指针 52 | }libinimini_parameter_t; 53 | 54 | /******************************************************************** 55 | * 函数: libinimini_foreach 56 | * 功能: 遍历整个 ini 配置文件, 并通过回调获取数据和输出内容 57 | * 参数: para: 参数配置 58 | * cache:用于处理数据和返回内容的缓冲区 59 | * size: 缓冲区大小, 必须大于字段名称+键值内容长度 60 | * 返回: 已遍历成功的 ini 配置数量 61 | *********************************************************************/ 62 | int libinimini_foreach(libinimini_parameter_t* para, char* cache, unsigned int size); 63 | ``` 64 | 65 | ## sys_config.ini (示例配置文件) 66 | 67 | ![](/images/sys_config.png "sys config") 68 | 69 | 70 | ## Sample (FreeRTOS@xr872) 71 | 72 | ```C 73 | /** 74 | ****************************************************************************** 75 | * @文件 main.c 76 | * @版本 V1.0.0 77 | * @日期 78 | * @概要 用于举例说明 libinimini 如何在单片机中应用 79 | * @作者 lmx 80 | ****************************************************************************** 81 | * @注意 82 | ****************************************************************************** 83 | */ 84 | #include 85 | #include 86 | #include "fs/fatfs/ff.h" 87 | #include "kernel/os/os.h" 88 | #include "../src/libinimini.h" 89 | #include "common/framework/fs_ctrl.h" 90 | #include "common/framework/platform_init.h" 91 | 92 | // 由 libinimini 回调,用于将解析的结果返回 93 | // 返回值: LIB_INIMINI_STOP:停止解析 LIB_INIMINI_KEEP:继续解析 94 | static int inimini_result_cb(libinimini_data_t* data, void* context) 95 | { 96 | printf("section:%-20s keyname:%-30s strval:%-30s\n", data->section, data->keyname, data->strval); 97 | if (strcmp(data->section, "compass_para") == 0 && strcmp(data->keyname, "compass_int") == 0) { 98 | printf("-------------------------------------------------\n"); 99 | printf("[%s]\n", data->section); 100 | printf("%s = %s\n", data->keyname, data->strval); 101 | printf("-------------------------------------------------\n"); 102 | return LIB_INIMINI_STOP; 103 | } 104 | return LIB_INIMINI_KEEP; 105 | } 106 | 107 | // 由 libinimini 回调,用于获取每一行的原始文本数据 108 | // 返回值: 0: 已无数据可以提供 >0: 字符串数据的长度 109 | static unsigned int inimini_getline_cb(char* buf, unsigned int size, void* context) 110 | { 111 | FIL* fp = (FIL*)context; 112 | if (f_gets(buf, size, fp) == NULL) { 113 | return LIB_INIMINI_STOP; 114 | } 115 | return (unsigned int)strlen(buf); 116 | } 117 | 118 | int main(void) 119 | { 120 | FIL file; 121 | static char cache[512] = { 0 }; 122 | libinimini_parameter_t para; 123 | 124 | platform_init(); 125 | 126 | if(fs_ctrl_mount(FS_MNT_DEV_TYPE_SDCARD, 0) != FS_MNT_STATUS_MOUNT_OK){ 127 | printf("fs mount failed\n"); 128 | while(1) OS_Sleep(1); 129 | } 130 | 131 | if(f_open(&file, "sys_config.ini", FA_READ | FA_OPEN_EXISTING) != FR_OK){ 132 | printf("open file failed\n"); 133 | while(1) OS_Sleep(1); 134 | } 135 | 136 | memset(¶, 0x00, sizeof(libinimini_parameter_t)); 137 | para.contex = &file; 138 | para.result = inimini_result_cb; 139 | para.ops.getline_cb = inimini_getline_cb; 140 | libinimini_foreach(¶, cache, sizeof(cache)); 141 | f_close(&file); 142 | 143 | printf("libinimini_foreach done...\n"); 144 | while(1) OS_Sleep(1); 145 | return 0; 146 | } 147 | ``` 148 | ![](/images/sample_xr872.png "xr872 example") 149 | 150 | ## Sample(Windows/Linux) 151 | 152 | ```C 153 | /** 154 | ****************************************************************************** 155 | * @文件 main.c 156 | * @版本 V1.0.0 157 | * @日期 158 | * @概要 用于举例说明 libinimini 如何在 Windows/Linux 中应用 159 | * @作者 lmx 160 | ****************************************************************************** 161 | * @注意 162 | ****************************************************************************** 163 | */ 164 | #include 165 | #include 166 | #include "../src/libinimini.h" 167 | 168 | // 由 libinimini 回调,用于将解析的结果返回 169 | // 返回值: LIB_INIMINI_STOP:停止解析 LIB_INIMINI_KEEP:继续解析 170 | static int inimini_result_cb(libinimini_data_t* data, void* context) 171 | { 172 | printf("section:%-20s keyname:%-30s strval:%-30s\n", data->section, data->keyname, data->strval); 173 | if (strcmp(data->section, "compass_para") == 0 && strcmp(data->keyname, "compass_int") == 0) { 174 | printf("-------------------------------------------------\n"); 175 | printf("[%s]\n", data->section); 176 | printf("%s = %s\n", data->keyname, data->strval); 177 | printf("-------------------------------------------------\n"); 178 | return LIB_INIMINI_STOP; 179 | } 180 | return LIB_INIMINI_KEEP; 181 | } 182 | 183 | // 由 libinimini 回调,用于获取每一行的原始文本数据 184 | // 返回值: 0: 已无数据可以提供 >0: 字符串数据的长度 185 | static unsigned int inimini_getline_cb(char* buf, unsigned int size, void* contex) 186 | { 187 | FILE* fp = (FILE*)contex; 188 | if (fgets(buf, size, fp) == NULL) { 189 | return LIB_INIMINI_STOP; 190 | } 191 | return strlen(buf); 192 | } 193 | 194 | int main(void) 195 | { 196 | char inimini_cache[1024] = { 0 }; 197 | libinimini_parameter_t para; 198 | 199 | FILE* fp = fopen("F:/sys_config.ini", "r"); 200 | if (NULL == fp) { 201 | printf("open file failed\n"); 202 | return 0; 203 | } 204 | 205 | memset(¶, 0x00, sizeof(libinimini_parameter_t)); 206 | para.contex = fp; 207 | para.result = inimini_result_cb; 208 | para.ops.getline_cb = inimini_getline_cb; 209 | int cnt = libinimini_foreach(¶, inimini_cache, sizeof(inimini_cache)); 210 | fclose(fp); 211 | 212 | printf("libinimini_foreach done...\n"); 213 | return 0; 214 | } 215 | 216 | ``` 217 | ![](/images/sample_windows_linux.png "windows linux example") -------------------------------------------------------------------------------- /src/libinimini.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @文件 libinimini.c 4 | * @版本 V1.0.2 5 | * @日期 2022-02-28 6 | * @概要 7 | * 1. 适用于在跑 RTOS 或裸跑的单片机平台上读取 ini 配置文件。 8 | * 2. 因单片机 RAM 稀有性,接口不会动态申请, 所需的内存由外部提供。 9 | * 3. 因单片机的文件系统差异和数据来源丰富, 接口实现不局限于文件。 10 | * @作者 lmx QQ:1007566569 EMAIL:lovemengx@foxmail.com 11 | ****************************************************************************** 12 | * @注意 13 | ****************************************************************************** 14 | */ 15 | #include 16 | #include "libinimini.h" 17 | 18 | /******************************************************************** 19 | * 函数: libinimini_is_comment 20 | * 功能: 判断字符串是否为注解 21 | * 参数: buf:字符串 len:字符串长度 22 | * 返回: 0:不是 ini 的注释文本 1:为 ini 的注释文本 23 | *********************************************************************/ 24 | static inline unsigned int libinimini_is_comment(char* buf, unsigned int len) 25 | { 26 | return ';' == buf[0] ? 1 : 0; 27 | } 28 | 29 | /******************************************************************** 30 | * 函数: libinimini_is_section 31 | * 功能: 判断字符串是否为字段类型 32 | * 参数: buf:字符串 len:字符串长度 33 | * 返回: 0:不是 ini 的字段文本 1:为 ini 的字段文本 34 | *********************************************************************/ 35 | static inline unsigned int libinimini_is_section(char* buf, unsigned int len) 36 | { 37 | return '[' == buf[0] ? 1 : 0; 38 | } 39 | 40 | /******************************************************************** 41 | * 函数: libinimini_is_section 42 | * 功能: 移除字符串的前后空格或制表符号 43 | * 参数: buf:字符串 len:字符串长度 44 | * 返回: 处理后的字符串长度 45 | *********************************************************************/ 46 | static inline unsigned int libinimini_remove_frontback_space(char* buf, unsigned int len) 47 | { 48 | char* p = buf; 49 | unsigned int cnt = 0; 50 | 51 | while (' ' == *p || '\t' == *p){ 52 | cnt++, p++; 53 | } 54 | 55 | if ((len = len - cnt) > 0) { 56 | if (cnt) { 57 | memcpy(buf, buf + cnt, len); 58 | } 59 | p = buf + (len - 1); 60 | while (' ' == *p || '\t' == *p){ 61 | len--, p--; 62 | } 63 | } 64 | buf[len] = '\0'; 65 | 66 | return len; 67 | } 68 | 69 | /******************************************************************** 70 | * 函数: libinimini_terminator_stringt 71 | * 功能: 寻找指定字符并在该处截断字符串 72 | * 参数: buf:字符串 len:字符串长度 73 | * 返回: 0:未找到 >0:已找到并截断后的字符串长度 74 | *********************************************************************/ 75 | static inline unsigned int libinimini_terminator_stringt(char ech, char* buf, unsigned int len) 76 | { 77 | char* k1 = NULL; 78 | if ((k1 = strchr(buf, ech)) != NULL) { 79 | *k1 = '\0'; 80 | return (unsigned int)(k1 - buf); 81 | } 82 | return 0; 83 | } 84 | 85 | /******************************************************************** 86 | * 函数: libinimini_terminator_linefeed 87 | * 功能: 截取换行符之前的字符串 88 | * 参数: buf:字符串 len:字符串长度 89 | * 返回: 处理后的字符串长度 90 | *********************************************************************/ 91 | static inline unsigned int libinimini_terminator_linefeed(char* buf, unsigned int len) 92 | { 93 | if((len = libinimini_terminator_stringt('\n', buf, len)) > 0){ 94 | if('\r' == buf[len-1]){ 95 | buf[len-1] = '\0'; 96 | len = len - 1; 97 | } 98 | } 99 | 100 | return len; 101 | } 102 | 103 | /******************************************************************** 104 | * 函数: libinimini_extract_string 105 | * 功能: 提取在 sch 字符和 ech 字符之间的字符串 106 | * 参数: sch:起始字符 ech:结束字符 buf:字符串 len:字符串长度 107 | * 返回: 0:未找到 >0:提取成功后的字符串长度 108 | *********************************************************************/ 109 | static inline unsigned int libinimini_extract_string(char sch, char ech, char* buf, unsigned int len) 110 | { 111 | char* k1 = NULL; 112 | char* k2 = NULL; 113 | 114 | if ((k1 = strchr(buf, sch)) == NULL || (k2 = strchr(k1 + 1, ech)) == NULL) { 115 | return 0; 116 | } 117 | 118 | if ((len = (unsigned int)(k2 - k1 - 1)) > 0) { 119 | memcpy(buf, k1 + 1, len); 120 | } 121 | buf[len] = '\0'; 122 | return len; 123 | } 124 | 125 | /******************************************************************** 126 | * 函数: libinimini_find_strval 127 | * 功能: 提取键的值 128 | * 参数: buf:字符串 len:字符串长度 129 | * 返回: 提取成功后的字符串长度 130 | *********************************************************************/ 131 | static inline unsigned int libinimini_find_strval(char* buf, unsigned int len) 132 | { 133 | len = libinimini_remove_frontback_space(buf, len); 134 | if (len && '\"' == buf[0] && '\"' == buf[len - 1]) { 135 | len = libinimini_extract_string('\"', '\"', buf, len); 136 | len = libinimini_remove_frontback_space(buf, len); 137 | } 138 | return len; 139 | } 140 | 141 | /******************************************************************** 142 | * 函数: libinimini_find_keyname 143 | * 功能: 提取键名 144 | * 参数: buf:字符串 len:字符串长度 valpos:返回键值的起始位置 145 | * 返回: 0:未找到键名 >0: 提取成功后的字符串长度以及键值的起始位置 146 | *********************************************************************/ 147 | static inline unsigned int libinimini_find_keyname(char* buf, unsigned int len, unsigned int* valpos) 148 | { 149 | if ((len = libinimini_terminator_stringt('=', buf, len)) <= 0) { 150 | return 0; 151 | } 152 | 153 | *valpos = len; 154 | len = libinimini_remove_frontback_space(buf, len); 155 | return len; 156 | } 157 | 158 | /******************************************************************** 159 | * 函数: libinimini_find_section 160 | * 功能: 提取字段 161 | * 参数: buf:字符串 len:字符串长度 162 | * 返回: 0:未找到字段 >0:提取成功后的字符串长度 163 | *********************************************************************/ 164 | static inline unsigned int libinimini_find_section(char* buf, unsigned int len) 165 | { 166 | if ((len = libinimini_extract_string('[', ']', buf, len)) <= 0) { 167 | return 0; 168 | } 169 | len = libinimini_remove_frontback_space(buf, len); 170 | return len; 171 | } 172 | 173 | /******************************************************************** 174 | * 函数: libinimini_pre_process 175 | * 功能: 对原始字符串的预处理,如移除换行符和空格、检查释放为注释 176 | * 参数: buf:字符串 len:字符串长度 177 | * 返回: 0:预处理失败或是注释文本 >0:返回处理后的字符串长度 178 | *********************************************************************/ 179 | static inline unsigned int libinimini_pre_process(char* buf, unsigned int len) 180 | { 181 | if ((len = libinimini_terminator_linefeed(buf, len)) == 0) { 182 | return 0; 183 | } 184 | 185 | if ((len = libinimini_remove_frontback_space(buf, len)) == 0) { 186 | return 0; 187 | } 188 | 189 | if (libinimini_is_comment(buf, len) > 0) { 190 | return 0; 191 | } 192 | 193 | return len; 194 | } 195 | 196 | /******************************************************************** 197 | * 函数: libinimini_foreach 198 | * 功能: 遍历整个 ini 配置文件, 并通过回调获取数据和输出内容 199 | * 参数: para: 参数配置 200 | * cache:用于处理数据和返回内容的缓冲区 201 | * size: 缓冲区大小, 必须大于字段名称+键值内容长度 202 | * 返回: 已遍历成功的 ini 配置数量 203 | *********************************************************************/ 204 | int libinimini_foreach(libinimini_parameter_t* para, char* cache, unsigned int size) 205 | { 206 | char* buf = cache; 207 | libinimini_data_t data; 208 | unsigned int buflen = size, valpos = 0, len = 0, datacnt = 0; 209 | 210 | memset(&data, 0x00, sizeof(libinimini_data_t)); 211 | while ((len = para->ops.getline_cb(buf, buflen, para->contex)) > 0) 212 | { 213 | // 对数据进行预处理 214 | if ((len = libinimini_pre_process(buf, len)) <= 0) { 215 | continue; 216 | } 217 | 218 | // 判断是否为段落 219 | if (libinimini_is_section(buf, len) > 0) { 220 | if ((len = libinimini_find_section(buf, len)) > 0) { 221 | if (data.section != NULL) { 222 | memcpy(cache, buf, len); 223 | cache[len] = '\0'; 224 | buf = cache; 225 | buflen = size; 226 | } 227 | data.section = buf; 228 | buf = buf + len + 1; 229 | buflen = buflen - len - 1; 230 | } 231 | continue; 232 | } 233 | 234 | // 尝试提取键值对 235 | if (data.section && libinimini_find_keyname(buf, len, &valpos) > 0) { 236 | if ((len = libinimini_find_strval(buf + valpos + 1, len - valpos - 1)) > 0) { 237 | datacnt++; 238 | data.keyname = buf; 239 | data.strval = buf + valpos + 1; 240 | if (para->result(&data, para->contex) != LIB_INIMINI_KEEP) { 241 | break; 242 | } 243 | } 244 | } 245 | } 246 | 247 | return datacnt; 248 | } 249 | --------------------------------------------------------------------------------