#ifndef INI_FILES_H_
#define INI_FILES_H_
#ifdef __cplusplus
extern "C" {
#endif
#define max_sec_len 20
#define max_key_len 20
#define max_val_len 64
#define max_section_counts 100
struct ini_file;
typedef struct ini_file* ini_file_handle;
/**
* 函数: load_ini_file
* 创建一个ini文件句柄
* 参数:
* const char * const f_name ini文件全名,包括文件路径
* 返回值:
* NULL 创建ini文件句柄失败
* 非NULL 创建ini文件句柄成功
* 版本号:1.0
*/
ini_file_handle load_ini_file(const char*const f_name);
/**
* 函数: get_value
* 获取对应的section,key值
* 参数:
* ini_file_handle h ini文件句柄
* const char * const s_name section名称
* const char * const k_name key名称
*
* 返回值:
* NULL 没有找到对应的section,key值
* 非NULL 指向对应的section,key值
* 版本号:1.0
*/
const char*const get_value(ini_file_handle h, const char*const s_name,const char*const k_name);
/**
* 函数: get_section
* 根据key,以及key对应的值返回包含第一个这个值得section名称
* 参数:
* ini_file_handle h ini文件句柄
* const char * const k_name key名称
* const char * const k_val key对应的值
*
* 返回值:
* NULL 没有找到包含key=value的section
* 非NULL 指向第一个包含key=value的section名称
* 版本号:1.0
*
*/const char*const get_section(ini_file_handle h,const char*const k_name,const char*const k_val);
/**
* 函数: find_section
* 查找该ini文件中是否包含一个特定的section
* 参数:
* ini_file_handle h ini文件句柄
* const char * const s_name section名称
* 返回值:
* NULL 在该ini文件中没有找到指定的section
* 非NULL 指向ini文件中的section名称
* 版本号:1.0
*
*/const char*const find_section(ini_file_handle h,const char*const s_name);
/**
* 函数: unload_ini_file
*
* 参数:
* ini_file_handle h
* 返回值:
* void
* 版本号:1.0
*
*/void unload_ini_file(ini_file_handle h);
#ifdef __cplusplus
}
#endif
#endif /* INI_FILES_H_ */
#include <ini_files.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#ifndef _countof
#define _countof(x) sizeof(x)/sizeof(x[0])
#endif
#define hints printf
#define max_line_count ((max_key_len + max_val_len) * 2)
#define common_checked(exp,ret) do{\
if(exp)\
{\
hints("%s(%d)"#exp":error = %s(%d)\n",__FUNCTION__,__LINE__,strerror(errno),errno);\
ret;\
}\
}while(0)
struct key_values{
char k_name[max_key_len];
char v_valu[max_val_len];
};
struct section{
struct key_values kv_sets[max_section_counts];
int key_counts;
char s_name[max_sec_len];
};
struct ini_file {
struct section sections[max_section_counts];
int sec_counts;
};
static int parse_ini_section(const char*const line,struct section*const sec){
int ret = sscanf(line,"[%[^]]",sec->s_name);
if(1 != ret){
hints("parse section name failed = %s\n",line);
return 0;
}
sec->key_counts = -1;
return 1;
}
static int parse_ini_keyval(const char*const line,struct section*const sec){
int j = ++(sec->key_counts);
char*const k_name = sec->kv_sets[j].k_name;
char*const k_valu = sec->kv_sets[j].v_valu;
int ret = sscanf(line,"%[^=]=%s",k_name,k_valu);
if (2 != ret){
hints("parse key=value pare failed %s\n",line);
return 0;
}
return 1;
}
static const char*const filter_ini_line(char*const line){
char* commnet_pos = NULL;
if (NULL == line){
return line;
}
commnet_pos = strchr(line,';');
if(NULL == commnet_pos){
return line;
}
*commnet_pos = '\0';
return (0 == strlen(line)) ? NULL : line;
}
static int parse_ini_context(FILE* f,struct section f_context[max_section_counts]){
int i = 0;
for (i = -1; !feof(f) && i < max_section_counts -1;) {
char buffer[max_line_count] = {0};
char*const line = fgets(buffer,sizeof(buffer),f);
if (NULL == filter_ini_line(line)){
continue;
}
if(NULL != strchr(line,'[') && NULL != strchr(line,']')){
if(!parse_ini_section(line,&f_context[++i])){
break;
}
continue;
}
if(NULL != strchr(line,'=')){
if(!parse_ini_keyval(line,&f_context[i])){
break;
}
continue;
}
hints("read error line %s\n",line);
}
return i;
}
static int load_ini_context(const char*const file_name, struct ini_file*const f_context) {
FILE* file_handle = fopen(file_name, "r");
common_checked(NULL == file_handle,return -1);
memset(f_context,0,sizeof(struct ini_file));
f_context->sec_counts = parse_ini_context(file_handle,f_context->sections);
fclose(file_handle);
return f_context->sec_counts;
}
ini_file_handle load_ini_file(const char*const f_name) {
struct ini_file* ret = NULL;
common_checked(NULL == f_name,return NULL);
ret = (struct ini_file*)malloc(sizeof(struct ini_file));
common_checked(NULL == ret , return NULL);
if (load_ini_context(f_name,ret) <= 0){
free(ret);
return NULL;
}
return ret;
}
const char*const get_value(ini_file_handle h, const char*const s_name,const char*const k_name){
int i = 0, j = 0;
common_checked(NULL == s_name || NULL == k_name,return NULL);
for (i = 0; i <= h->sec_counts; ++i) {
if(0 == strcmp(s_name,h->sections[i].s_name)){
break;
}
}
if(i > h->sec_counts){
hints("get section [%s] failed\n",s_name);
return NULL;
}
for (j = 0; j <= h->sections[i].key_counts; ++j) {
const struct key_values*const kv = &h->sections[i].kv_sets[j];
if(0 == strcmp(k_name,kv->k_name)){
return kv->v_valu;
}
}
hints("get [%s] %s value failed\n",s_name,k_name);
return NULL;
}
const char*const get_section(ini_file_handle h,const char*const k_name,const char*const k_val){
int i = 0, j = 0;
common_checked(NULL == k_name || NULL == k_val,return NULL);
for (i = 0; i <= h->sec_counts; ++i) {
for (j = 0; j <= h->sections[i].key_counts; ++j) {
const char*const name = h->sections[i].kv_sets[j].k_name;
const char*const valu = h->sections[i].kv_sets[j].v_valu;
if( 0 == strcmp(k_name,name) && 0 == strcmp(k_val,valu)){
return h->sections[i].s_name;
}
}
}
hints("get section failed by %s=%s\n",k_name,k_val);
return NULL;
}
const char*const find_section(ini_file_handle h,const char*const s_name){
int i = 0;
common_checked(NULL == s_name,return NULL);
for (i = 0; i <= h->sec_counts; ++i) {
if(strcmp(h->sections[i].s_name,s_name) == 0){
return h->sections[i].s_name;
}
}
hints("find section failed %s\n",s_name);
return NULL;
}
void unload_ini_file(ini_file_handle h){
free(h);
}
#ifdef ini_file_test
#include <assert.h>
static void show_context(ini_file_handle h){
int i= 0, j = 0;
common_checked(NULL == h,return);
for (i = 0; i <= h->sec_counts; ++i) {
hints("[%s]\n",h->sections[i].s_name);
for (j = 0; j <= h->sections[i].key_counts; ++j) {
const struct key_values*const kv = &h->sections[i].kv_sets[j];
hints("%s=%s\n",kv->k_name,kv->v_valu);
}
}
}
static void check_context(ini_file_handle h){
int i = 0, j = 0;
for (i = 0; i <= h->sec_counts; ++i){
assert(NULL != find_section(h,h->sections[i].s_name));
for (j = 0; j <= h->sections[i].key_counts;++j){
assert(NULL != get_value(h,h->sections[i].s_name,h->sections[i].kv_sets[j].k_name));
assert(NULL != get_section(h,h->sections[i].kv_sets[j].k_name,h->sections[i].kv_sets[j].v_valu));
}
}
assert(NULL == get_section(h,"aa","bb"));
assert(NULL == get_value(h,"aabb","bbaa"));
assert(NULL == find_section(h,"acd"));
}
int main(int argc,char* argv[]){
if(2 == argc){
ini_file_handle fh = load_ini_file(argv[1]);
common_checked(NULL == fh , return -1);
show_context(fh);
check_context(fh);
unload_ini_file(fh);
return 0;
}
printf("usage : %s file_name\n",argv[0]);
return -1;
}
#endif