介绍说明

最近自己基于 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(&para, 0x00, sizeof(libinimini_parameter_t));
para.contex = &file;
para.result = inimini_result_cb;
para.ops.getline_cb = inimini_getline_cb;
libinimini_foreach(&para, 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(&para, 0x00, sizeof(libinimini_parameter_t));
para.contex = fp;
para.result = inimini_result_cb;
para.ops.getline_cb = inimini_getline_cb;
int cnt = libinimini_foreach(&para, inimini_cache, sizeof(inimini_cache));
fclose(fp); printf("libinimini_foreach done...\n");
return 0;
}

【开源】libinimini:适用于单片机的极简 ini 解析库的更多相关文章

  1. .NET开源项目 QuarkDoc 一款自带极简主义属性的文档管理系统

    有些话说在前头 因为公司产品业务重构且功能拆分组件化,往后会有很多的接口文档需要留存,所以急需一款文档管理系统.当时选型要求3点: 1.不能是云平台上的Saas服务,整个系统都要在自己公司部署维护(数 ...

  2. itest(爱测试) 开源一站式敏捷测试管理平台&极简项目管理,重大升级(接口测试)6.0.0 发布

    itest 简介 itest 开源敏捷测试管理,testOps 践行者,极简的任务管理,测试管理,缺陷管理,测试环境管理,接口测试5合1,又有丰富的统计分析.可按测试包分配测试用例执行,也可建测试迭代 ...

  3. 极简实用的Asp.NetCore模块化框架新增CMS模块

    简介 关于这个框架的背景,在前面我已经交代过了.不清楚的可以查看这个链接 极简实用的Asp.NetCore模块化框架决定免费开源了 在最近一段时间内,对这个框架新增了以下功能: 1.新增了CMS模块, ...

  4. ServiceFabric极简文档-0. ServiceFabric简介

    前言: 最近ServiceFabric开源了,大家热情都比较高,官方文档大而全,但快速入手不容易找到头绪.发几篇极简的文档,跟大家分享一下,顺便为Ray的ServiceFabric部署做一下铺垫.因为 ...

  5. .NET Core实战项目之CMS 第八章 设计篇-内容管理极简设计全过程

    写在前面 上一篇文章中我带着大家进行了权限部分的极简设计,也仅仅是一个基本的权限设计.不过你完全可以基于这套权限系统设计你的更复杂的权限系统,当然更复杂的权限系统要根据你的业务来进行,因为任何脱离实际 ...

  6. [深度学习工具]·极简安装Dlib人脸识别库

    [深度学习工具]·极简安装Dlib人脸识别库 Dlib介绍 Dlib是一个现代化的C ++工具箱,其中包含用于在C ++中创建复杂软件以解决实际问题的机器学习算法和工具.它广泛应用于工业界和学术界,包 ...

  7. 树莓派(Raspberry Pi)使用Shell编写的极简Service

    树莓派(Raspberry Pi)运行的系统是基于Debian的,不仅可以运行Shell,还支持systemd和docker,可以编写一个简单的服务,让其在启动时运行,执行一些自动化的操作.这里在Ra ...

  8. 首发:极简的Centos主机监控方法,分分钟即可使用【转】

    需求天天有,今年事更多.硬盘测试刚刚完成,就又来了性能监控的需求.一般我们生产就用zabbix了,用起来还行,就是蛮多脚本要写.开发和测试都是分散的,经常还要重装系统,用zabbix就算了,开发和测试 ...

  9. Asky极简教程:零基础1小时学编程,已更新前8节

    Asky极简架构 开源Asky极简架构.超轻量级.高并发.水平扩展.微服务架构 <Asky极简教程:零基础1小时学编程>开源教程 零基础入门,从零开始全程演示,如何开发一个大型互联网系统, ...

  10. [开发技巧]·Python极简实现滑动平均滤波(基于Numpy.convolve)

    [开发技巧]·Python极简实现滑动平均滤波(基于Numpy.convolve) ​ 1.滑动平均概念 滑动平均滤波法(又称递推平均滤波法),时把连续取N个采样值看成一个队列 ,队列的长度固定为N ...

随机推荐

  1. MvvmLight框架的基本使用

    关于MvvmLight框架的介绍可以看这篇,说的很详细,在此记录下来以作复习,通过一个简单的例子说明MvvmLight的基本使用 https://www.cnblogs.com/3xiaolonglo ...

  2. Node.js的学习(二)node.js 模块化

    一.Node.js模块化 1.模块化概要 早期的javascript版本没有块级作用域.没有类.没有包.也没有模块,这样会带来一些问题,如复用.依赖.冲突.代码组织混乱等,随着前端的膨胀,模块化显得非 ...

  3. 这次,听人大教授讲讲分布式数据库的多级一致性|TDSQL 关键技术突破

    近年来,凭借高可扩展.高可用等技术特性,分布式数据库正在成为金融行业数字化转型的重要支撑.分布式数据库如何在不同的金融级应用场景下,在确保数据一致性的前提下,同时保障系统的高性能和高可扩展性,是分布式 ...

  4. Java判断质数/素数的三种方法

    介绍 质数:在大于1的整数中,如果只包含1和本身这两个约数,就被称为质数(素数) 解法 解法一:暴力枚举 枚举从2 ~ N的每一个数 实际上不用枚举到N,只需要枚举到√N就行 注意: 不要使用sqrt ...

  5. 核磁共振成像学习笔记——从FID信号到K空间

    在理想磁场环境下(没有不存在场不均匀性),对于一个没有梯度场的方块. 此时,RF pulse的两路正交信号(相位差为90°)对此方块进行激发,然后收取信号,我们可以得到由此方块产生的FID信号. 设此 ...

  6. [排序算法] 简单选择排序 (C++)

    简单选择排序原理 简单选择排序 SelectSort 是一种十分直观地排序方法.其原理是每次从未排序的元素中找到当前最小的元素,放在当前未排序序列的首位.一直重复操作直至最后未排序的元素个数为 0,即 ...

  7. (GCC) gcc编译选项 -Wl, -start-group,whole-archive,-Wl, Bstatic

    1. start-group 编译选项 假设程序x依赖三个静态库:libX1.a.libX2.a和libX3.a,而libX2.a又依赖libX1.a,libX3.a依赖libX2.a和libX1.a ...

  8. Easy-Classification-验证码识别

    1.背景 Easy-Classification是一个应用于分类任务的深度学习框架,它集成了众多成熟的分类神经网络模型,可帮助使用者简单快速的构建分类训练任务.   案例源代码 Easy-Classi ...

  9. 教你用JavaScript实现随机点名

    案例介绍 欢迎来到我的小院,我是霍大侠,恭喜你今天又要进步一点点了!我们来用JavaScript相关知识,做一个随机点名的案例.你可以通过点击开始按钮控制上方名字的闪动,点击停止按钮可以随机选定一个名 ...

  10. Windows 10 读取bitlocker加密的硬盘出现参数错误怎么解决?

    我为了数据安全,用windows专业版的bitlocker加密了一个固态硬盘SSD做的移动硬盘(u盘同理),在家里电脑(windows10 家庭版)打开的时候出现了参数错误 即使密码输入正确还是这个错 ...