【开源】libinimini:适用于单片机的极简 ini 解析库
介绍说明
最近自己基于 XR872 在做一个小作品练习练习,具备可以配置的功能,选择了使用 ini 作为配置文件。我调研了网上常见的 ini 解析库,几乎都涉及到了 fopen()/fgets().. 以及 malloc()。
说明这些开源库都仅适用于支持完整 C语言标准库的系统,并不适用于 RTOS 或裸跑的单片机。因为前者虽是 C 语言的标准文件操作函数,但在单片机中基本上使用的都是简化版的 fatfs 接口,要想引入单片机使用,意味着需要对该接口库进行修改。后者更是涉及到内存管理,ram 的占用会随着 ini 配置文件的内容而变化,意味着 ram 的使用不可控,极易受外部因素影响,这对 ram 资源极为稀有的单片机来说,是不可接受的。
本着学习的态度,就自己设计了一个非常简单的 ini 配置文件解析库(libinimini),具有以下几种特点:
1. 内存空间占用可控,libinimini 只使用用户指定的一段内存空间进行解析和返回结果。
2. 不关心数据的来源,libinimini 会通过回调用户的接口来获取每一行文本,不关心文本来自于文件还是其它通信接口。
3. 使用方便简单易上手,用户只需要实现以行为单位的文本数据的回调接口,之后只需要等待 libinimini 解析结果即可。
注意:接口本身会将键值作为字符串传递出来,如果需要转换为数字,调用类似 atoi() 的函数转换即可。
源码仓库位置:
https://github.com/lovemengx/libinimini
https://gitee.com/lovemengx/libinimini
示例代码
sys_config.ini(部分内容)

单片机版本(xr872@FreeRtos)
/**
******************************************************************************
* @文件 main.c
* @版本 V1.0.0
* @日期
* @概要 用于举例说明 libinimini 如何在单片机中应用
* @作者 lmx
******************************************************************************
* @注意
******************************************************************************
*/
#include <stdio.h>
#include <string.h>
#include "fs/fatfs/ff.h"
#include "kernel/os/os.h"
#include "../src/libinimini.h"
#include "common/framework/fs_ctrl.h"
#include "common/framework/platform_init.h"
// 由 libinimini 回调,用于将解析的结果返回
// 返回值: LIB_INIMINI_STOP:停止解析 LIB_INIMINI_KEEP:继续解析
static int inimini_result_cb(libinimini_data_t* data, void* context)
{
printf("section:%-20s keyname:%-30s strval:%-30s\n", data->section, data->keyname, data->strval);
if (strcmp(data->section, "compass_para") == 0 && strcmp(data->keyname, "compass_int") == 0) {
printf("-------------------------------------------------\n");
printf("[%s]\n", data->section);
printf("%s = %s\n", data->keyname, data->strval);
printf("-------------------------------------------------\n");
return LIB_INIMINI_STOP;
}
return LIB_INIMINI_KEEP;
}
// 由 libinimini 回调,用于获取每一行的原始文本数据
// 返回值: 0: 已无数据可以提供 >0: 字符串数据的长度
static unsigned int inimini_getline_cb(char* buf, unsigned int size, void* context)
{
FIL* fp = (FIL*)context;
if (f_gets(buf, size, fp) == NULL) {
return LIB_INIMINI_STOP;
}
return (unsigned int)strlen(buf);
}
int main(void)
{
FIL file;
static char cache[512] = { 0 };
libinimini_parameter_t para;
platform_init();
if(fs_ctrl_mount(FS_MNT_DEV_TYPE_SDCARD, 0) != FS_MNT_STATUS_MOUNT_OK){
printf("fs mount failed\n");
while(1) OS_Sleep(1);
}
if(f_open(&file, "sys_config.ini", FA_READ | FA_OPEN_EXISTING) != FR_OK){
printf("open file failed\n");
while(1) OS_Sleep(1);
}
memset(¶, 0x00, sizeof(libinimini_parameter_t));
para.contex = &file;
para.result = inimini_result_cb;
para.ops.getline_cb = inimini_getline_cb;
libinimini_foreach(¶, cache, sizeof(cache));
f_close(&file);
printf("libinimini_foreach done...\n");
while(1) OS_Sleep(1);
return 0;
}

Windows/Linux 版本
#include <stdio.h>
#include <string.h>
#include "libinimini.h"
// 由 libinimini 回调,用于将解析的结果返回
// 返回值: LIB_INIMINI_STOP:停止解析 LIB_INIMINI_KEEP:继续解析
static int inimini_result_cb(libinimini_data_t* data, void* context)
{
printf("section:%-20s keyname:%-30s strval:%-30s\n", data->section, data->keyname, data->strval);
if (strcmp(data->section, "compass_para") == 0 && strcmp(data->keyname, "compass_int") == 0) {
printf("-------------------------------------------------\n");
printf("[%s]\n", data->section);
printf("%s = %s\n", data->keyname, data->strval);
printf("-------------------------------------------------\n");
return LIB_INIMINI_STOP;
}
return LIB_INIMINI_KEEP;
}
// 由 libinimini 回调,用于获取每一行的原始文本数据
// 返回值: 0: 已无数据可以提供 >0: 字符串数据的长度
static unsigned int inimini_getline_cb(char* buf, unsigned int size, void* contex)
{
FILE* fp = (FILE*)contex;
if (fgets(buf, size, fp) == NULL) {
return LIB_INIMINI_STOP;
}
return strlen(buf);
}
int main(void)
{
char inimini_cache[1024] = { 0 };
libinimini_parameter_t para;
FILE* fp = fopen("F:/sys_config.ini", "r");
if (NULL == fp) {
printf("open file failed\n");
return 0;
}
memset(¶, 0x00, sizeof(libinimini_parameter_t));
para.contex = fp;
para.result = inimini_result_cb;
para.ops.getline_cb = inimini_getline_cb;
int cnt = libinimini_foreach(¶, inimini_cache, sizeof(inimini_cache));
fclose(fp);
printf("libinimini_foreach done...\n");
return 0;
}

【开源】libinimini:适用于单片机的极简 ini 解析库的更多相关文章
- .NET开源项目 QuarkDoc 一款自带极简主义属性的文档管理系统
有些话说在前头 因为公司产品业务重构且功能拆分组件化,往后会有很多的接口文档需要留存,所以急需一款文档管理系统.当时选型要求3点: 1.不能是云平台上的Saas服务,整个系统都要在自己公司部署维护(数 ...
- itest(爱测试) 开源一站式敏捷测试管理平台&极简项目管理,重大升级(接口测试)6.0.0 发布
itest 简介 itest 开源敏捷测试管理,testOps 践行者,极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试5合1,又有丰富的统计分析.可按测试包分配测试用例执行,也可建测试迭代 ...
- 极简实用的Asp.NetCore模块化框架新增CMS模块
简介 关于这个框架的背景,在前面我已经交代过了.不清楚的可以查看这个链接 极简实用的Asp.NetCore模块化框架决定免费开源了 在最近一段时间内,对这个框架新增了以下功能: 1.新增了CMS模块, ...
- ServiceFabric极简文档-0. ServiceFabric简介
前言: 最近ServiceFabric开源了,大家热情都比较高,官方文档大而全,但快速入手不容易找到头绪.发几篇极简的文档,跟大家分享一下,顺便为Ray的ServiceFabric部署做一下铺垫.因为 ...
- .NET Core实战项目之CMS 第八章 设计篇-内容管理极简设计全过程
写在前面 上一篇文章中我带着大家进行了权限部分的极简设计,也仅仅是一个基本的权限设计.不过你完全可以基于这套权限系统设计你的更复杂的权限系统,当然更复杂的权限系统要根据你的业务来进行,因为任何脱离实际 ...
- [深度学习工具]·极简安装Dlib人脸识别库
[深度学习工具]·极简安装Dlib人脸识别库 Dlib介绍 Dlib是一个现代化的C ++工具箱,其中包含用于在C ++中创建复杂软件以解决实际问题的机器学习算法和工具.它广泛应用于工业界和学术界,包 ...
- 树莓派(Raspberry Pi)使用Shell编写的极简Service
树莓派(Raspberry Pi)运行的系统是基于Debian的,不仅可以运行Shell,还支持systemd和docker,可以编写一个简单的服务,让其在启动时运行,执行一些自动化的操作.这里在Ra ...
- 首发:极简的Centos主机监控方法,分分钟即可使用【转】
需求天天有,今年事更多.硬盘测试刚刚完成,就又来了性能监控的需求.一般我们生产就用zabbix了,用起来还行,就是蛮多脚本要写.开发和测试都是分散的,经常还要重装系统,用zabbix就算了,开发和测试 ...
- Asky极简教程:零基础1小时学编程,已更新前8节
Asky极简架构 开源Asky极简架构.超轻量级.高并发.水平扩展.微服务架构 <Asky极简教程:零基础1小时学编程>开源教程 零基础入门,从零开始全程演示,如何开发一个大型互联网系统, ...
- [开发技巧]·Python极简实现滑动平均滤波(基于Numpy.convolve)
[开发技巧]·Python极简实现滑动平均滤波(基于Numpy.convolve) 1.滑动平均概念 滑动平均滤波法(又称递推平均滤波法),时把连续取N个采样值看成一个队列 ,队列的长度固定为N ...
随机推荐
- VirtualBox 下 CentOS7 静态 IP 的配置 → 多次踩坑总结,蚌埠住了!
开心一刻 一个消化不良的病人向医生抱怨:我近来很不正常,吃什么拉什么,吃黄瓜拉黄瓜,吃西瓜拉西瓜,怎样才能恢复正常呢? 医生沉默片刻:那你只能吃屎了 环境准备 VirtualBox 6.1 网络连接方 ...
- 前端项目通过‘URL 重写’部署在 IIS 中,访问 WebAPI 接口
〇.前言 在前端项目开发时,我们可以通过配置代理 proxy 来访问本地或者是远程接口,但是部署后代理就失效了.如果项目部署在 IIS 上,就没法去对应到指定接口,此时就需要 IIS 中的'URL重写 ...
- 如何安装Visual Studio Community2022
如何安装Visual Studio Community2022 Visual Studio是一款强大的IDE(集成开发环境),对于初学者可以选择使用社区版,下面是Visual Studio Commu ...
- linux驱动移植
1.1 开发前准备 1.1.1 Linux 驱动(面向对象) 1).Linux 驱动框架 思想:写驱动的时候,只提供操作硬件设备的函数接口 文件存放磁盘: open ,read ,write ,clo ...
- Java内存马的学习总结
1.前置知识 Java Web三大组件 Servlet Servlet是运行在 Web 服务器或应用服务器上的程序,它是作为来自 HTTP 客户端的请求和 HTTP 服务器上的数据库或应用程序之间的中 ...
- Day30:ArrayList详解
ArrayList 1.1 集合概述 当我们要存储多个数据时,固定长度的数组存储格式已经满足不了我们的需要了,且不能满足变化的需求: Java中集合类则可以解决我们的需求 特点:提供一种存储空间可变的 ...
- 【每日一题】【双端降序队列Deque】2021年12月28日-239. 滑动窗口最大值
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧.你只可以看到在滑动窗口内的 k 个数字.滑动窗口每次只向右移动一位. 返回滑动窗口中的最大值. 来源:力扣(L ...
- feDisplacementMap滤镜实现水波纹效果,计算动态值。
参考资料 https://www.zhangxinxu.com/wordpress/2017/12/understand-svg-fedisplacementmap-filter/ 该文章已经讲的特别 ...
- EndNote设置导出参考文献格式为中文国标GBT7714
笔者使用的版本是最新的EndNote 20,其他版本大同小异. 依次打开:Tools -> Output Styles -> Open Style Manager.其他版本可能有差异,只要 ...
- 《MySQL必知必会》之快速入门存储过程
使用存储过程 本章介绍什么是存储过程,为什么使用.如何使用,并介绍如何创建和使用存储过程的基本语法 存储过程 在实际应用中,往往需要执行多个表的多条sql语句 存储过程就是为以后的使用而保存的一条或者 ...