inih(INI Not Invented Here)是一个用 C 语言编写的简单的 .INI 文件解析器。它只有几页代码,并且被设计得小而简单,因此它非常适合嵌入式系统。它还或多或少地与 Python 的 ConfigParser 风格的 .INI 文件兼容,包括 RFC 822 风格的多行语法和name: value
条目。
要使用它,只需给ini_parse()
一个 INI 文件,它就会为解析的每个name=value
对调用回调,为您提供部分、名称和值的字符串。它以这种方式完成(“SAX 风格”),因为它在低内存嵌入式系统上运行良好,而且还因为它适合 KISS 实现。
您还可以调用ini_parse_file()
来直接从FILE*
对象进行解析, ini_parse_string()
来解析字符串中的数据,或者调用ini_parse_stream()
来使用自定义 I/O 的自定义 fgets 样式读取器函数进行解析。
下载版本、浏览源代码或阅读有关如何通过 X-Macros 以 DRY 风格使用 inih 的信息。
您可以使用预处理器定义来控制 inih 的各个方面:
-DINI_ALLOW_MULTILINE=0
。-DINI_ALLOW_BOM=0
。;
特点。要禁用,请添加-DINI_ALLOW_INLINE_COMMENTS=0
。您还可以使用INI_INLINE_COMMENT_PREFIXES
指定哪些字符开始内联注释。;
和#
在行首开始注释。您可以通过更改INI_START_COMMENT_PREFIXES
来覆盖此设置。=
:
:)视为错误。要允许没有值的名称,请添加-DINI_ALLOW_NO_VALUE=1
,inih 将调用您的处理函数,并将值设置为 NULL。-DINI_STOP_ON_FIRST_ERROR=1
。ini_handler
回调不接收行号作为参数。如果需要,请添加-DINI_HANDLER_LINENO=1
。name=value
对上调用处理程序。要检测新部分(例如,INI 文件具有多个同名部分),请添加-DINI_CALL_HANDLER_ON_NEW_SECTION=1
。然后,每次遇到新节时都会调用处理函数, section
设置为新节名称,但name
和value
设置为 NULL。malloc
在堆上分配,请指定-DINI_USE_STACK=0
。-DINI_MAX_LINE=1000
内容。请注意, INI_MAX_LINE
必须比最长行多 3(由于r
、 n
和 NUL)。INI_INITIAL_ALLOC
指定使用堆时的初始malloc大小。默认为 200 字节。-DINI_USE_STACK=0
) 时,inih 分配INI_INITIAL_ALLOC
字节的固定大小缓冲区。要允许其增长到INI_MAX_LINE
字节(如果需要则加倍),请设置-DINI_ALLOW_REALLOC=1
。malloc
、 free
和realloc
函数;要使用自定义分配器,请指定-DINI_CUSTOM_ALLOCATOR=1
(和-DINI_USE_STACK=0
)。您必须定义并链接名为ini_malloc
、 ini_free
和(如果设置了INI_ALLOW_REALLOC
) ini_realloc
的函数,它们必须具有与stdlib.h
内存分配函数相同的签名。 #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../ini.h"
typedef struct
{
int version ;
const char * name ;
const char * email ;
} configuration ;
static int handler ( void * user , const char * section , const char * name ,
const char * value )
{
configuration * pconfig = ( configuration * ) user ;
#define MATCH ( s , n ) strcmp(section, s) == 0 && strcmp(name, n) == 0
if ( MATCH ( "protocol" , "version" )) {
pconfig -> version = atoi ( value );
} else if ( MATCH ( "user" , "name" )) {
pconfig -> name = strdup ( value );
} else if ( MATCH ( "user" , "email" )) {
pconfig -> email = strdup ( value );
} else {
return 0 ; /* unknown section/name, error */
}
return 1 ;
}
int main ( int argc , char * argv [])
{
configuration config ;
if ( ini_parse ( "test.ini" , handler , & config ) < 0 ) {
printf ( "Can't load 'test.ini'n" );
return 1 ;
}
printf ( "Config loaded from 'test.ini': version=%d, name=%s, email=%sn" ,
config . version , config . name , config . email );
return 0 ;
}
如果您喜欢 C++ 和 STL,还有一个易于使用的 INIReader 类,它将值存储在map
中并允许您Get()
它们:
# include < iostream >
# include " INIReader.h "
int main ()
{
INIReader reader ( " ../examples/test.ini " );
if (reader. ParseError () < 0 ) {
std::cout << " Can't load 'test.ini' n " ;
return 1 ;
}
std::cout << " Config loaded from 'test.ini': version= "
<< reader. GetInteger ( " protocol " , " version " , - 1 ) << " , name= "
<< reader. Get ( " user " , " name " , " UNKNOWN " ) << " , email= "
<< reader. Get ( " user " , " email " , " UNKNOWN " ) << " , pi= "
<< reader. GetReal ( " user " , " pi " , - 1 ) << " , active= "
<< reader. GetBoolean ( " user " , " active " , true ) << " n " ;
return 0 ;
}
这个简单的 C++ API 工作得很好,但还不是很成熟。我目前不打算在 C++ API 上进行更多工作,因此如果您想要更多功能(例如GetSections()
和GetFields()
函数),请参阅这些分支:
inih 和 Python 的 ConfigParser 标准库模块之间的一些区别:
_wfopen()
打开文件,然后调用ini_parse_file()
解析它; inih 不包括wchar_t
或 Unicode 处理。 meson.build
文件不需要使用或编译 inih,它的主要目的是用于发行版。-Ddefault_library=static
构建静态库。-Ddistro_install=false
库、标头和 pkg-config 文件将不会被安装。-Dwith_INIReader=false
可以禁用构建 C++ 库。distro_install
设置为true
,这些将不起作用。inih
和INIReader
。inih_dep
和INIReader_dep
依赖变量。您可能需要为子项目设置default_library=static
和distro_install=false
。 WrapDB 上提供了官方的 Wrap。version : '<version_as_int>',
位于project()
函数中的license
标记之后,以及version : meson.project_version(),
位于两个library()
函数中的soversion
标记之后。 只需将以下条目添加到.tipi/deps
中(将r56
替换为最新版本标记),即可在 tipi.build 项目中轻松使用inih
:
{
"benhoyt/inih" : { "@" : " r56 " }
}
项目中所需的包含路径是:
#include <ini.h>
您可以使用 vcpkg 依赖管理器构建和安装 inih:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install inih
vcpkg 中的 inih 端口由 Microsoft 团队成员和社区贡献者保持最新。如果版本已过时,请在 vcpkg 存储库上创建问题或拉取请求。