介绍说明

最近自己基于 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. 开箱即用 yyg-cli(脚手架工具):快速创建 vue3 组件库和vue3 全家桶项目

    1 yyg-cli 是什么 yyg-cli 是优雅哥开发的快速创建 vue3 项目的脚手架.在 npm 上发布了两个月,11月1日进行了大升级,发布 1.1.0 版本:支持创建 vue3 全家桶项目和 ...

  2. jmeter执行报错:java.lang.UnsupportedClassVersionError解决办法

    做个记录. 问题记录: jmeter版本:5.4.1 本地Java版本:1.8.0_151 执行jmeter,报错: 2022-10-14 12:06:27,372 ERROR o.a.j.JMete ...

  3. 基于SqlSugar的开发框架循序渐进介绍(21)-- 在工作流列表页面中增加一些转义信息的输出,在后端进行内容转换

    有时候,为了给前端页面输出内容,有时候我们需要准备和数据库不一样的实体信息,因为数据库可能记录的是一些引用的ID或者特殊字符,那么我们为了避免前端单独的进行转义处理,我们可以在后端进行统一的格式化后再 ...

  4. shell文件报错syntax error near unexpected token '$'\r''

    本来跑的好好得一个文件,在windows下修改了,然后移植到linux就报错了. 找了一圈以下是解决方案: 这种情况发生的原因是因为你所处理的文件换行符是dos格式的"\r\n" ...

  5. [排序算法] 冒泡排序 (C++)

    冒泡排序解释: 冒泡排序 BubbleSort 是一种最基础的交换排序.顾名思义,数组中的每一个元素就好像泡泡一样,根据自己的大小不同一点点的向一侧移动. 冒泡排序原理: 每一趟只能确定将一个数归位. ...

  6. table 动态隐藏tr行

    table: <table style="width:100%" class="table01" cellspacing="1" ce ...

  7. Linux系统下安装tomcat步骤

    安装参考教程:https://www.cnblogs.com/li150dan/p/12535067.html 说明:jdk自动安装后路径是/usr/lib/jvm 在"vim /etc/p ...

  8. 《MySQL必知必会》知识汇总二

    六.用通配符进行过滤 本章介绍什么是通配符.如何使用通配符以及怎样使用LIKE操作符进行通配搜索 LIKE操作符 百分号(%)通配符 select prod_id,prod_name from pro ...

  9. 【Shell案例】【awk和循环、NR、格式打印、全局变量、$0、通配符】12、打印每一行出现的数字个数

    写一个 bash脚本以统计一个文本文件 nowcoder.txt中每一行出现的1,2,3,4,5数字个数并且要计算一下整个文档中一共出现了几个1,2,3,4,5数字数字总数. 示例: 假设 nowco ...

  10. 【Java EE】Day03 DQL、约束、数据库设计、范式、备份和还原

    〇.总结 1.DQL 聚合函数有空值需要使用ifnull函数 where不能使用聚合函数 分页开始索引的计算,及mysql和oracle的方言 2.约束 删除唯一约束DROP INDEX 列名; 3. ...