246 lines
5.1 KiB
Markdown
246 lines
5.1 KiB
Markdown
<p align="center">
|
||
<img width="200" src="./assets/icon.png">
|
||
</p>
|
||
|
||
<h1 align="center">
|
||
Pine INI Reader
|
||
</h1>
|
||
|
||
<p align="center">
|
||
A simple INI file reading tool implemented in C89 aimed at teaching
|
||
</p>
|
||
|
||
## INI 格式
|
||
|
||
本解析器实现了 ini 格式的三种 pattern :`COMMENT `注释、`SECTION`段落和`PARAMETER`参数
|
||
|
||
### Comment 注释
|
||
|
||
注释以`;`开头
|
||
|
||
```ini
|
||
; This is a comment
|
||
```
|
||
|
||
### Section
|
||
|
||
段落以`[`与`]`包围
|
||
|
||
```ini
|
||
[Section Name]
|
||
```
|
||
|
||
### Parameter
|
||
|
||
参数以`=`分割`key`键与`value`值
|
||
|
||
```ini
|
||
KEY=VALUE
|
||
```
|
||
|
||
### 等效 JSON
|
||
|
||
```ini
|
||
; 下列的 parameter 没有写明 section,
|
||
; 本库的处理方法是:自动创建一个名为 _default 的 section
|
||
targetFps=10
|
||
[mount]
|
||
root=card0
|
||
[file]
|
||
ext=k3v
|
||
```
|
||
|
||
上面的 ini 与下面的 json 等效
|
||
|
||
```json
|
||
{
|
||
"_default": {
|
||
"targetFps": "10"
|
||
},
|
||
"mount": {
|
||
"root": "card0"
|
||
},
|
||
"file": {
|
||
"ext": "k3v"
|
||
}
|
||
}
|
||
```
|
||
|
||
|
||
|
||
## 使用范例
|
||
|
||
```c
|
||
PineIniError errorRet;
|
||
PineIniFile* iniResult;
|
||
int i, j;
|
||
|
||
/* 解析 INI 文本 */
|
||
iniResult = PineIni_Parse(iniText, &errorRet);
|
||
|
||
/* 返回NULL,从errorRet中读取错误信息 */
|
||
if (iniResult == NULL) {
|
||
printf("!!! ERROR !!!\n");
|
||
printf("errorMessage: %s\n", PINE_INI_ERRMSG[errorRet.errorCode]);
|
||
printf("errorCode: %d\n", errorRet.errorCode);
|
||
printf("lineNumber: %d\n", errorRet.lineNumber);
|
||
printf("line: \"%s\"\n", errorRet.lineContent);
|
||
return;
|
||
}
|
||
|
||
/* 打印 INI 结果中的 Section 数量 */
|
||
printf("Total sections = %d\n", iniResult->numSection);
|
||
|
||
/* 打印 INI 结果中的 Section*/
|
||
for (i = 0; i < iniResult->numSection; ++i) {
|
||
|
||
PineIniSection* section = iniResult->sections[i];
|
||
|
||
/* 打印 Section 的 Parameter 数量 */
|
||
printf("<%s> %d Parameters\n", section->name, section->numParam);
|
||
|
||
/* 打印 Section 的所有 Parameter */
|
||
for (j = 0; j < section->numParam; ++j) {
|
||
PineIniParameter* param = section->params[j];
|
||
printf(" %s: %s\n", param->key, param->value);
|
||
}
|
||
}
|
||
|
||
/* 释放 INI 资源 */
|
||
PineIni_Destory(iniResult);
|
||
```
|
||
|
||
### 输入测试文件
|
||
```ini
|
||
hello=1
|
||
; General setting
|
||
[General]
|
||
sLanguage=ENGLISH
|
||
uGridsToLoad=7
|
||
uExterior Cell Buffer=64
|
||
iPreloadSizeLimit=262144000
|
||
|
||
[Display]
|
||
fShadowLODMaxStartFade=1000.0
|
||
fSpecularLODMaxStartFade=2000.0
|
||
fLightLODMaxStartFade=3500.0
|
||
iShadowMapResolutionPrimary=4096
|
||
bAllowScreenshot=1
|
||
fDefaultWorldFOV=80
|
||
fDefault1stPersonFOV=80.0000
|
||
|
||
[Audio]
|
||
fMusicDuckingSeconds=6.0
|
||
fMusicUnDuckingSeconds=8.0
|
||
fMenuModeFadeOutTime=3.0
|
||
fMenuModeFadeInTime=1.0
|
||
|
||
; 覆盖上面 General 的 sLanguage
|
||
[General]
|
||
sLanguage = "CHINESE"
|
||
```
|
||
|
||
### 输出结果
|
||
|
||
```text
|
||
Total sections = 4
|
||
<_default> 1 Parameters
|
||
hello: 1
|
||
<General> 4 Parameters
|
||
sLanguage: CHINESE
|
||
uGridsToLoad: 7
|
||
uExterior Cell Buffer: 64
|
||
iPreloadSizeLimit: 262144000
|
||
<Display> 7 Parameters
|
||
fShadowLODMaxStartFade: 1000.0
|
||
fSpecularLODMaxStartFade: 2000.0
|
||
fLightLODMaxStartFade: 3500.0
|
||
iShadowMapResolutionPrimary: 4096
|
||
bAllowScreenshot: 1
|
||
fDefaultWorldFOV: 80
|
||
fDefault1stPersonFOV: 80.0000
|
||
<Audio> 4 Parameters
|
||
fMusicDuckingSeconds: 6.0
|
||
fMusicUnDuckingSeconds: 8.0
|
||
fMenuModeFadeOutTime: 3.0
|
||
fMenuModeFadeInTime: 1.0
|
||
```
|
||
|
||
|
||
|
||
## 测试
|
||
|
||
```c
|
||
/*
|
||
* Trim 测试
|
||
* 删除字符串左右的空格
|
||
* 空格定义:' ' 空格 | '\t' 制表符 | '\r' 回车符 | '\n' 换行符
|
||
*/
|
||
PutsTitle("Test: StringTrim");
|
||
test_PineIni_StringTrim();
|
||
|
||
/*
|
||
* RemoveQuotes 测试
|
||
* Trim并且删除字符串左右的引号
|
||
* 空格定义:" | '
|
||
*/
|
||
PutsTitle("Test: StringRemoveQuotes");
|
||
test_PineIni_StringRemoveQuotes();
|
||
|
||
/*
|
||
* INI 测试1:无法识别的模式
|
||
* 某行的内容不是 COMMENT / SECTION / PARAMETER 其中之一
|
||
*/
|
||
PutsTitle("Test: Ini Illegal Pattern");
|
||
test_Ini_IllegalPattern();
|
||
|
||
/*
|
||
* INI 测试2:PARAMETER模式中KEY未指定
|
||
* 例:`=notValidLine`
|
||
*/
|
||
PutsTitle("Test: Ini Empty Key");
|
||
test_Ini_EmptyKey();
|
||
|
||
/*
|
||
* INI 测试3:Section数量过多
|
||
* 文件中的section过多,超过了
|
||
* 宏 PINE_INI_MAX_NUM_SECTIONS 定义的最大数量
|
||
*/
|
||
PutsTitle("Test: Ini Section Exceed");
|
||
test_Ini_SectionExceed();
|
||
|
||
/*
|
||
* INI 测试4:Parameter数量过多
|
||
* 某section的parameter过多,超过了
|
||
* 宏 PINE_INI_MAX_NUM_PARAMETERS 定义的最大数量
|
||
*/
|
||
PutsTitle("Test: Ini Param Exceed");
|
||
test_Ini_Param_Exceed();
|
||
|
||
/*
|
||
* INI 测试5:无错误
|
||
* 成功后打印所有的 section 和里面 parameter
|
||
*/
|
||
PutsTitle("Test: Ini Success");
|
||
test_Ini_Success();
|
||
|
||
/*
|
||
* INI 测试6:从INI文件获取值
|
||
* 测试7种情况
|
||
* 1. 从 ini 文件通过 section.key 获取值,section、key都存在
|
||
* 2. 从 ini 文件通过 section.key 获取值,key不存在,使用默认值
|
||
* 3. 从 ini 文件通过 section.key 获取值,section不存在,使用默认值
|
||
* 4. 从 section 通过 key 获取值,key存在
|
||
* 5. 从 section 通过 key 获取值,key不存在,使用默认值
|
||
* 6. 从 ini 文件通过 section.key 获取整数,section、key都存在
|
||
* 7. 从 ini 文件通过 section.key 获取整数,key不存在,使用默认值
|
||
*/
|
||
PutsTitle("Test: Get value from INI");
|
||
test_Ini_Get_Value();
|
||
|
||
PutsTitle("Test completed!");
|
||
```
|
||
|
||
|
||
|