纯C语言INI文件解析

分享到:
  在一个跨平台( Android 、Windows、Linux )项目中配置文件用 INI 格式,自己写了个解析库,纯C语言的,简单好用。

    可以解析 INI 格式的字符串、解析文件、保存到文件。

    下面是头文件:

#ifndef INI_PARSER_H
#define INI_PARSER_H
#ifdef __cplusplus
extern "C" {
#endif
struct tag_value_list;
struct ini_parser {
struct tag_value_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);
};
struct ini_parser * new_ini_parser();
void delete_ini_parser(struct ini_parser *);
#ifdef __cplusplus
}
#endif
#endif // INI_PARSER_H
下面是源文件:
#include "ini_parser.h"
#include <stdio.h>
#include <string.h>
#include "tag_value.h"
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;
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 = ini->keyvalues->find_by_tag(ini->keyvalues, key);
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 = ini->keyvalues->find_by_tag(ini->keyvalues, key);
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 = ini->keyvalues->find_by_tag(ini->keyvalues, key);
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 = ini->keyvalues->head;
while(pair != ini->keyvalues->tail)
{
write_keyvalue(pair, fp);
pair = pair->next;
}
if(pair)write_keyvalue(pair, fp);
fclose(fp);
return 0;
}
}
return -1;
}
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;
return ini;
}
void delete_ini_parser(struct ini_parser *ini){
if(ini)
{
delete_tag_value_list(ini->keyvalues);
free(ini);
}
}
    测试代码:
#include "util/ini_parser.h"
#include "ini_test.h"
#include <stdio.h>
#include <assert.h>
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");
delete_ini_parser(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"));
delete_ini_parser(ini);
}
void ini_parser_test()
{
ini_parser_test_string();
ini_parser_test_file();
}
    测试了解析字符串、文件、增、删、写文件,都没什么大问题。

来自:http://blog.csdn.net/foruok/article/details/17715969

昵    称:
验证码:

相关文档:

  • 4个函数实现的C编译器:C4
    4个函数实现的c编译器,大约500行。基本上已经比较完备了,可以自己编译自己。...
  • GCC的图形化前端 wxgcc
    wxgcc 的全称是:wxpython gcc compiling toolkit ,它是一个在Linux环境下使用的,基于 wxpython 的GCC 编译器图形前端软件,可以用来快速的编译验...
  • 一致性hash的C++实现
    一致性哈希是分布式计算领域被广泛应用的一个算法。在许多分布式系统包括 Amazon Dynamo, memcached, Riak 等中都有使用。...
  • OpenDDS:数据分布式服务(DDS)的C++实现
    OpenDDS 是一个开源的 C++ 实现的 对象管理组织 OMG 的 数据分布式服务 (DDS) 。...
  • 优化的内存访问 TCMalloc
    TCMalloc (google-perftools) 是用于优化C++写的多线程应用,比glibc 2.3的malloc快。这个模块可以用来让MySQL在高并发下内存占用更加稳定。...
  • java嵌入c,c++程序指南
    本文为在 32 位 Windows 平台上实现 Java 本地方法提供了实用的 示例、步骤和准则。本文中的示例使用 Sun Microsystems 公司创建的 Java Developmen...
  • C序列化或反序列化库:tpl
    tpl是一个开源的小项目,其主要是提供一个可以序列化或反序列化C语言数据的一个API函数库。tpl号称是最有效率的也是最快的,它可以...
  • zip文件C语言解析包 ZZIPlib
    ZZIPlib 是一个轻量级的用来从ZIP文件抽读取文件的C语言包,同时也可以用来将多个文件压缩成zip格式,采用的是 zlib 库开发。...
  • C语言开发工具 PythoidC
    PythoidC是中国人研发的最方便的C语言开发工具,实现了易如Python快如C的最高境界:...
  • 标准C++类库 STDCXX
    Apache的C++ 标准库项目(代号stdcxx ,发音为“standard C++ library” ,而不是STDCXX )是一个集算法,容器,迭代器等等功能的C++类库。...
  • C++国际化 UTF-8 CPP
    一个处理UTF-8编码字符串的简单、小巧、跨平台的泛型库。...
  • 高性能的 URL 路由C语言开发包:R3
    R3是一个URL路由分发开发库,拥有较高的性能。采用C语言实现。可将你的路由规则编译成前缀树。 在启动时利用构造前缀树,你可以高...
  • C++截图-二维码识别工具:BusyBoy.QReader
    实现截图和二维码识别的小工具 按下ctrl+alt+z截图 按下ctrl+alt+x识别二维码...
  • 五个好的C语言编程实践
    前几天,我看到一个关于编程语言的调查,我发现到目前为止,C 编程语言在全球开发者中仍然稳居前三。如此多的代码使用C来编写,我...
  • C/C++ 依赖管理器:biicode
    biicode 是一个支持多平台的 C/C++ 依赖管理器。可集成到 Visual Studio 和 Eclipse CDT 中。该工具目前是免费的,即将开源。...
  • 50条大牛C++编程开发学习建议
    每个从事C++开发的朋友相信都能给后来者一些建议,但是真正为此进行大致总结的很少。本文就给出了网上流传的对C++编程开发学习的50...
  • 异步DNS解析C语言库 c-ares
    c-ares 是一个用来异步的执行 DNS 请求和名字解析的 C 库。...
  • C++系统调用库 CSCall++
    CSCall++ 是对常用的一些系统调用进行封装的 C++ 库,主要包括:线程、文件、FIFOs、串行IO、socket通讯和目录处理等。...
  • C/C++集成开发环境 Dev C++
    Dev-C++是一个Windows下的C和C++程序的集成开发环境。它使用MingW32/GCC编 译器,遵循C/C++标准。...
  • Trie树的C++实现
    Trie,又称单词查找树、前缀树,是一种哈希树的变种。应用于字符串的统计与排序,经常被搜索引擎系统用于文本词频统计。...