概述
ini文件的基本格式如下:
1: [Section1]
2: Name1=Value1
3: Name2=Value2
4:
5: [Section2]
6: Name1=Value1
7: Name2=Value2
ini文件由section组成,每个section内可以定义若干个属性,以及他们的值。
ini文件算是一种比较简单的信息管理方式了,内容简单,格式简单,使用起来也简单。而且内容全部是ASCII,直观。
在很多场合都可能会用到ini文件,比如,希望我们写的程序可以让用户做一些细微的配置的时候,或者,希望程序可以具备保存设置的能力的时候。
下面给出一个用双向链表来操作ini的代码实现方式。
我用了三个结构体来描述一个ini文件:
1: typedef struct ini_item_t {
2: struct ini_item_t *prev;
3: struct ini_item_t *next;
4: char *name;
5: char *value;
6: } INIITEM, *LPINIITEM;
7:
8: typedef struct ini_section_t {
9: struct ini_section_t *prev;
10: struct ini_section_t *next;
11: char *name;
12: int itemCount;
13: struct ini_item_t *first_item;
14: struct ini_item_t *last_item;
15: } INISECTION, *LPINISECTION;
16:
17: typedef struct ini_file_t {
18: char *name;
19: int sectionCount;
20: struct ini_section_t *first_section;
21: struct ini_section_t *last_section;
22: int flag;
23: char mode[8];
24: } INIFILE, *LPINIFILE;
INIFILE用来描述一个ini文件,它内部的first_section和last_section用来表示一个链表,这个链表的成员节点即为INISECTION,它描述了当前这个ini文件里包含了哪些section区段;
INISECTION用来描述ini文件内的一个section,它本身是一个链表的节点,它内部的first_item和last_item用来表示另外一个链表,这个链表描述的就是当前这个section里包含了哪些条目;
INIITEM是最基础的结构体定义,它描述了一个item的信息。
一个INIFILE代表了一个ini文件,这个INIFILE内可能有若干个section,这些section形成了一个链表;
初始化INIFILE的过程如下:
1: static LPINIFILE ini_createIniStruct(const char *name)
2: {
3: LPINIFILE iniFile = (LPINIFILE)malloc(sizeof(INIFILE));
4: iniFile->name = (char *)malloc(strlen(name) + 1);
5: strcpy(iniFile->name, name);
6: iniFile->first_section = NULL;
7: iniFile->last_section = NULL;
8: iniFile->sectionCount = 0;
9: iniFile->flag = 0;
10: return iniFile;
11: }
12:
13: static void ini_destryIniStruct(LPINIFILE iniFile)
14: {
15: LPINISECTION sec = iniFile->first_section;
16: free(iniFile->name);
17: while(sec)
18: {
19: LPINISECTION tmp = sec->next;
20: ini_delSection(iniFile, sec);
21: sec = tmp;
22: }
23: free(iniFile);
24: }
在初始化一个INIFILE结构体的过程中,主要是为INIFILE结构体内的数据分配空间,并将INIFILE里的INISECTION链表设置为空;
在某个section内,可能包含了若干个item,这些item在当前section内也形成了一个链表;
初始化一个INISECTION的过程如下:
1: static LPINISECTION ini_addSection(LPINIFILE iniFile, const char *name)
2: {
3: LPINISECTION sec = (LPINISECTION)malloc(sizeof(INISECTION));
4: sec->name = (char *)malloc(strlen(name) + 1);
5: strcpy(sec->name, name);
6: sec->first_item = NULL;
7: sec->last_item = NULL;
8: sec->itemCount = 0;
9: add_node((void**)&(iniFile->first_section), (void**)&(iniFile->last_section), sec);
10: return sec;
11: }
12:
13: static void ini_delSection(LPINIFILE iniFile, LPINISECTION sec)
14: {
15: LPINIITEM item = sec->first_item;
16: free(sec->name);
17: while(item)
18: {
19: LPINIITEM tmp = item->next;
20: ini_delItem(sec, item);
21: item = tmp;
22: }
23: del_node((void**)&(iniFile->first_section), (void**)&(iniFile->last_section), sec);
24: free(sec);
25: }
当需要向INIFILE添加一个section时,一方面需要创建出来INISECTION,并添加到INIFILE的链表内,另一方面,要初始化INISECTION内的INIITEM链表。
最后是item的操作:
1: static LPINIITEM ini_addItem(LPINISECTION iniSection, const char *name, const char *value)
2: {
3: LPINIITEM item = (LPINIITEM)malloc(sizeof(INIITEM));
4: item->name = (char *)malloc(strlen(name) + 1);
5: strcpy(item->name, name);
6: item->value = (char *)malloc(strlen(value) + 1);
7: strcpy(item->value, value);
8: add_node((void**)&(iniSection->first_item), (void**)&(iniSection->last_item), item);
9: iniSection->itemCount++;
10: return item;
11: }
12:
13: static void ini_delItem(LPINISECTION iniSection, LPINIITEM item)
14: {
15: free(item->name);
16: free(item->value);
17: del_node((void**)&(iniSection->first_item), (void**)&(iniSection->last_item), item);
18: free(item);
19: iniSection->itemCount--;
20: }
以上有关链表的操作,都调用了《一个通用的双向链表管理程序》一文中介绍的通用双向链表管理程序。因为有了这个程序的存在,才使得对ini文件进行操作时,对于INISECTION链表和INIITEM链表可以使用相同的操作方法,调用相同的函数。
有了描述ini文件的数据结构之后,剩下的就是如何将ini文件解析成相应的数据结构了:
1: INIFILEHANDLE ini_open(const char *iniFile, const char *mode)
2: {
3: char lineBuf[1024];
4: LPINIFILE file;
5: LPINISECTION curSection = NULL;
6: FILE *fp;
7: fp = fopen(iniFile, mode);
8: if(fp == NULL)
9: return NULL;
10: file = ini_createIniStruct(iniFile);
11: strcpy(file->mode, mode);
12: while(fgets(lineBuf, 1023, fp))
13: {
14: char *p = strtrim(lineBuf);
15: int len = strlen(p);
16: if(strlen(p) <= 0)
17: continue;
18: else if(p[0] == '#')
19: continue;
20: else if((p[0] == '[') && (p[len - 1] == ']'))
21: {
22: p[len - 1] = '