在实际项目中,经常会把软件的某些选项写入配置文件。 Windows 平台上的 INI 文件格式简单易用,本篇文章利用《C语言面向对象编程(五):单链表实现》中实现的单链表,设计了一个“类” ini_parser 来读写 INI 格式的配置文件。
struct ini_parser 可以解析 INI 格式的字符串、文件,也可以将内存中的符合 INI 格式的数据写入文件,能够支持 Windows 、 Linux 、 Android 等多平台。目前暂不支持选项分组功能。
功能相对简单,直接看源码吧。
下面是头文件:
-
struct single_list; -
struct ini_parser { -
struct single_list * keyvalues; -
int (*parse_file)(struct ini_parser *, const char * file); -
int (*parse_string)(struct ini_parser *, const char *text); -
char * (*value)(struct ini_parser *, const char * key); -
void (*set_value)(struct ini_parser *, const char * key, const char * value); -
void (*remove)(struct ini_parser *, const char *key); -
int (*save_to_file)(struct ini_parser *, const char * file); -
void (*deletor)(struct ini_parser *ini); -
}; -
struct ini_parser * new_ini_parser();
struct init_parser 的声明符合我们在本系列文章中提到的面向对象框架,需要说明的是,一旦 deletor 方法被调用, ini_parser 的实例将不再允许访问。
下面是源文件:
-
#include "ini_parser.h" -
#include <stdio.h> -
#include <string.h> -
struct tag_value_pair{ -
struct slist_node node; -
char * szTag; -
char * szValue; -
}; -
typedef struct tag_value_pair tag_value; -
static void _tag_value_free(struct slist_node *node) -
{ -
if(node) delete_tag_value_pair(node); -
} -
static int _tag_value_hittest(struct slist_node * node, void *key) -
{ -
return strcmp((char*)tag, ((struct tag_value_pair*)node)->szTag); -
} -
static struct single_list * new_tag_value_list() -
{ -
return new_single_list(_tag_value_free, _tag_value_hittest); -
} -
static struct tag_value_pair *new_tag_value_pair() -
{ -
struct tag_value_pair * pair = (struct tag_value_pair *)malloc(sizeof(struct tag_value_pair)); -
pair->node.next = 0; -
pair->szTag = 0; -
pair->szValue = 0; -
return pair; -
} -
static struct tag_value_pair * make_tag_value_pair(char * tag, char * value) -
{ -
struct tag_value_pair *pair = 0; -
if(!tag || !value)return 0; -
pair = (struct tag_value_pair*)malloc(sizeof(struct tag_value_pair)); -
pair->szTag = strdup(tag); -
pair->szValue = strdup(value); -
pair->node.next = 0; -
return pair; -
} -
static struct tag_value_pair * parse_line(char *line, int len) -
{ -
struct tag_value_pair * pair = 0; -
int count = 0; -
char * p = line; -
char * end = 0;m -
char * start = line; -
if(!p) return 0; -
while(*p == ' ') ++p; -
/*blank line*/ -
if(p - line == len || -
*p == '\r' || -
*p == '\n' || -
*p == '\0') return 0; -
/*do not support group*/ -
if(*p == '[') return 0; -
/*comments*/ -
if(*p == '#') return 0; -
/* extract key */ -
start = p; -
end = line + len; -
while(*p != '=' && p!= end) ++p; -
if(p == end) -
{ -
/* none '=' , invalid line */ -
return 0; -
} -
end = p - 1; -
while(*end == ' ') --end; /* skip blank at the end */ -
count = end - start + 1; -
pair = new_tag_value_pair(); -
pair->szTag = malloc(count + 1); -
strncpy(pair->szTag, start, count); -
pair->szTag[count] = 0; -
/* extract value */ -
++p; -
end = line + len; /* next pos of the last char */ -
while( *p == ' ' && p != end) ++p; -
if(p == end) -
{ -
delete_tag_value_pair(pair); -
return 0; -
} -
start = p; -
--end; /* to the last char */ -
if(*end == '\n') { *end = 0; --end; } -
if(*end == '\r') { *end = 0; --end; } -
count = end - start + 1; -
if(count > 0) -
{ -
pair->szValue = malloc(count + 1); -
strncpy(pair->szValue, start, count); -
pair->szValue[count] = 0; -
} -
/* release empty key-value pair */ -
if(!pair->szValue) -
{ -
delete_tag_value_pair(pair); -
return 0; -
} -
return pair; -
} -
static int _parse_file(struct ini_parser * ini, const char *file){ -
FILE * fp = fopen(file, "r"); -
if(fp) -
{ -
struct tag_value_pair * pair = 0; -
char buf[1024] = {0}; -
while(fgets(buf, 1024, fp)) -
{ -
pair = parse_line(buf, strlen(buf)); -
if(pair) -
{ -
ini->keyvalues->add(ini->keyvalues, pair); -
} -
} -
fclose(fp); -
return ini->keyvalues->size; -
} -
return -1; -
} -
static int _parse_text(struct ini_parser * ini, const char * text){ -
char *p = text; -
char * start = 0; -
struct tag_value_pair * pair = 0; -
if(!text) return -1; -
while(1) -
{ -
start = p; -
while(*p != '\n' && *p != '\0' )++p; -
if(*p == '\0') break; -
pair = parse_line(start, p - start); -
if(pair) ini->keyvalues->add(ini->keyvalues, pair); -
++p; -
} -
return ini->keyvalues->size; -
} -
static char * _value(struct ini_parser * ini, const char * key){ -
struct tag_value_pair * pair = NODE_T(ini->keyvalues->find_by_key(ini->keyvalues, key), struct tag_value_pair); -
if(pair) return pair->szValue; -
return 0; -
} -
static void _set_value(struct ini_parser * ini, const char * key, const char *value){ -
struct tag_value_pair * pair = NODE_T(ini->keyvalues->find_by_key(ini->keyvalues, key), struct tag_value_pair); -
if(pair) -
{ -
if(pair->szValue) free(pair->szValue); -
pair->szValue = strdup(value); -
} -
else -
{ -
ini->keyvalues->add(ini->keyvalues, make_tag_value_pair(key, value)); -
} -
} -
static void _remove(struct ini_parser * ini, const char * key){ -
struct tag_value_pair * pair = NODE_T(ini->keyvalues->find_by_key(ini->keyvalues, key), struct tag_value_pair); -
if(pair)ini->keyvalues->remove(ini->keyvalues, pair); -
} -
static void write_keyvalue(struct tag_value_pair * pair, FILE *fp) -
{ -
fputs(pair->szTag, fp); -
fputc('=', fp); -
fputs(pair->szValue, fp); -
fputc('\n', fp); -
} -
static int _save_to_file(struct ini_parser * ini, const char * file){ -
if(ini->keyvalues->size > 0) -
{ -
FILE * fp = fopen(file, "w"); -
if(fp) -
{ -
struct tag_value_pair * pair = NODE_T(ini->keyvalues->head,struct tag_value_pair); -
while(pair != 0) -
{ -
write_keyvalue(pair, fp); -
pair = NODE_T(pair->node.next, struct tag_value_pair); -
} -
fclose(fp); -
return 0; -
} -
} -
return -1; -
} -
static void _delete_ini_parser(struct ini_parser *ini){ -
if(ini) -
{ -
ini->keyvalues->deletor(ini->keyvalues); -
free(ini); -
} -
} -
struct ini_parser * new_ini_parser(){ -
struct ini_parser * ini = (struct ini_parser*)malloc(sizeof(struct ini_parser)); -
ini->keyvalues = new_tag_value_list(); -
ini->parse_file = _parse_file; -
ini->parse_string = _parse_text; -
ini->value = _value; -
ini->set_value = _set_value; -
ini->remove = _remove; -
ini->save_to_file = _save_to_file; -
ini->deletor = _delete_ini_parser; -
return ini; -
}
下面是简单的测试代码:
-
static char * g_szIniString = "#abc\nfirst=2\nsecond\nname=charli zhang \n"; -
static void ini_parser_test_string() -
{ -
struct ini_parser * ini = new_ini_parser(); -
int size = ini->parse_string(ini, g_szIniString); -
assert( size > 0); -
assert( ini->value(ini, "second") == 0 ); -
assert( ini->value(ini, "abc") == 0); -
assert( ini->value(ini, "name") != NULL ); -
assert( ini->value(ini, "first") != NULL); -
printf("ini string: %s\n", g_szIniString); -
printf("key-value pairs count = %d\n", size); -
printf("key \'name\'', value = %s\n", ini->value(ini, "name")); -
printf("key \'first\'', value = %s\n", ini->value(ini, "first")); -
ini->set_value(ini, "baidu", "hahaha"); -
ini->save_to_file(ini, "write.conf"); -
ini->remove(ini, "first"); -
ini->save_to_file(ini, "write2.conf"); -
ini->deletor(ini); -
} -
static void ini_parser_test_file() -
{ -
struct ini_parser * ini = new_ini_parser(); -
int size = ini->parse_file(ini, "test.conf"); -
assert( size > 0); -
assert( ini->value(ini, "second") == 0 ); -
assert( ini->value(ini, "abc") == 0); -
assert( ini->value(ini, "name") != NULL ); -
assert( ini->value(ini, "first") != NULL); -
printf("ini string: %s\n", g_szIniString); -
printf("key-value pairs count = %d\n", size); -
printf("key \'name\'', value = %s\n", ini->value(ini, "name")); -
printf("key \'first\'', value = %s\n", ini->value(ini, "first")); -
printf("key \'baidu\'', value = %s\n", ini->value(ini, "baidu")); -
ini->deletor(ini); -
} -
void ini_parser_test() -
{ -
ini_parser_test_string(); -
ini_parser_test_file(); -
}
struct ini_parser 已经运用在实际的项目中,目前为止没发现什么问题。
1015

被折叠的 条评论
为什么被折叠?



