Chinaunix首页 | 论坛 | 博客
  • 博客访问: 828471
  • 博文数量: 330
  • 博客积分: 9641
  • 博客等级: 中将
  • 技术积分: 3181
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-19 14:41
文章分类

全部博文(330)

文章存档

2012年(17)

2011年(135)

2010年(85)

2009年(57)

2008年(36)

我的朋友

分类: C/C++

2010-12-10 13:21:59

配置文件很重要,INI 太弱,XML 太繁复,Linux *.conf 很酷。

找了好几种相关的类库,发觉还是  最强大最好用,相关细节可参考 。

源中的版本是 1.3.2-1,也可以去官方文章下载最新版本。

$ sudo apt-get install libconfig8 libconfig8-dev


完全类脚本化的配置语法,支持注释、包含、简单配置、数组、列表以及非常像类的组。

test.conf

# Example application configuration file

title = "Test Application"; // scalar value
version = 1; // int, int64, float, bool, string

app: // group
{
    user:
    {
        name = "Q.yuhen";
        code = "xxx-xxx-xxx";
        tags = ["t1", "t2", "t3"]; // array
        data = ( "Hello", 1234 ); // list
    };
};


1. Path

直接用多级路径读取目标值,这是最简单的做法。注意区分参数中 path 和 name 的区别,后者无法使用路径。

int config_lookup_int (const config_t * config, const char * path, int * value)
int config_lookup_int64 (const config_t * config, const char * path, long long * value)
int config_lookup_float (const config_t * config, const char * path, double * value)
int config_lookup_bool (const config_t * config, const char * path, int * value)
int config_lookup_string (const config_t * config, const char * path, const char ** value)


我们试试看。

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <libconfig.h>

void scalar(config_t* conf)
{
    char* title;
    config_lookup_string(conf, "title", &title);
    printf("title = %s;n", title);

    int version;
    config_lookup_int(conf, "version", &version);
    printf("version = %d;n", version);

    char* user_name;
    config_lookup_string(conf, "app.user.name", &user_name);
    printf("app.user.name = %s;n", user_name);

    char* tag;
    config_lookup_string(conf, "app.user.tags.[2]", &tag);
    printf("app.user.tags[2] = %s;n", tag);

    int data;
    config_lookup_int(conf, "app.user.data.[1]", &data);
    printf("app.user.data.[1] = %d;n", data);
}

int main(int argc, char* argv[])
{
    config_t* conf = 
NULL;
    config_init(conf);
    config_read_file(conf, "test.conf");

    scalar(conf);
 
    config_destroy(conf);
    return EXIT_SUCCESS;
}


输出:

title = Test Application;
version = 1;
app.user.name = Q.yuhen;
app.user.tags[2] = t3;
app.user.data.[1] = 1234;


2. Config_Setting

所有的 Group 和其 Member 都是 Config_Setting,我们可以用 config_lookup() 找出目标后,然后使用 Name 读取。

config_setting_t * config_lookup (const config_t * config, const char * path)

int config_setting_lookup_int (const config_setting_t * setting, const char * name, int * value)
int config_setting_lookup_int64 (const config_setting_t * setting, const char * name, long long * value)
int config_setting_lookup_float (const config_setting_t * setting, const char * name, double * value)
int config_setting_lookup_bool (const config_setting_t * setting, const char * name, int * value)
int config_setting_lookup_string (const config_setting_t * setting, const char * name, const char ** value)


注意 config_setting_lookup_xxx() 只能使用 Member Name,而不是 Path。

void group(config_t* conf)
{
    config_setting_t* user = config_lookup(conf, "app.user");

    char* code;
    config_setting_lookup_string(user, "code", &code);
    printf("user.code = %s;n", code);
}


利用相关的函数,我们还可以遍历 Array/List 的所有 Element。

void group(config_t* conf)
{
    config_setting_t* user = config_lookup(conf, "app.user");

    config_setting_t* tags = config_setting_get_member(user, "tags");
    int count = config_setting_length(tags);

    int i;
    for (i = 0; i < count; i++)
    {
        printf("user.tags[%d] = %s;n", i, config_setting_get_string_elem(tags, i));
    }
}


输出:

user.tags[0] = t1;
user.tags[1] = t2;
user.tags[2] = t3;


当然,我们也可以用 config_lookup() 直接找到 app.user.tags,然后遍历。

void group(config_t* conf)
{
    config_setting_t* tags = config_lookup(conf, "app.user.tags");
    int count = config_setting_length(tags);

    int i;
    for (i = 0; i < count; i++)
    {
        printf("user.tags[%d] = %s;n", i, config_setting_get_string_elem(tags, i));
    }

    printf("-----------------------n");

    config_setting_t* code = config_lookup(conf, "app.user.code");
    printf("user.code = %s;n", config_setting_get_string(code));
}


输出:

user.tags[0] = t1;
user.tags[1] = t2;
user.tags[2] = t3;
-----------------------
user.code = xxx-xxx-xxx;


上面的例子中,我们还可以直接用 lookup() 查找简单配置 app.user.code,然后用相关方法返回值,无需再次提供 Name。

int config_setting_get_int (const config_setting_t * setting)
long long config_setting_get_int64 (const config_setting_t * setting)
double config_setting_get_float (const config_setting_t * setting)
int config_setting_get_bool (const config_setting_t * setting)
const char * config_setting_get_string (const config_setting_t * setting)


Array/List 的内容可以是 Group,我们可以用 config_setting_get_elem() 获取指定序号的元素后继续操作。

config_setting_t * config_setting_get_member (config_setting_t * setting, const char * name)
config_setting_t * config_setting_get_elem (const config_setting_t * setting, unsigned int idx)


3. Write

配置文件吗,增删改操作都要全乎。

int config_setting_set_int (config_setting_t * setting, int value)
int config_setting_set_int64 (config_setting_t * setting, long long value)
int config_setting_set_float (config_setting_t * setting, double value)
int config_setting_set_bool (config_setting_t * setting, int value)
int config_setting_set_string (config_setting_t * setting, const char * value)

config_setting_t * config_setting_set_int_elem (config_setting_t * setting, int idx, int value)
config_setting_t * config_setting_set_int64_elem (config_setting_t * setting, int idx, long long value)
config_setting_t * config_setting_set_float_elem (config_setting_t * setting, int idx, double value)
config_setting_t * config_setting_set_bool_elem (config_setting_t * setting, int idx, int value)
config_setting_t * config_setting_set_string_elem (config_setting_t * setting, int idx, const char * value)

config_setting_t * config_setting_add (config_setting_t * parent, const char * name, int type)

int config_setting_remove (config_setting_t * parent, const char * name)
int config_setting_remove_elem (config_setting_t * parent, unsigned int idx)

const char * config_setting_name (const config_setting_t * setting)


为了方便查看,我直接 "保存" 到 stdout 了。

void write(config_t* conf)
{
    config_setting_t* user = config_lookup(conf, "app.user");
    config_setting_t* name = config_setting_get_member(user, "name");
    config_setting_t* tags = config_setting_get_member(user, "tags");
    config_setting_t* data = config_setting_get_member(user, "data");

    /* ----------------- Add ------------------- */
    config_setting_t* comment = config_setting_add(user, "comment", CONFIG_TYPE_STRING);
    config_setting_set_string(comment, "test...");

        /* ----------------- Remove ---------------- */
    config_setting_remove(user, "code");
    config_setting_remove_elem(tags, 1);

        /* ----------------- Set ------------------- */
    config_setting_set_string(name, "Rainsoft");
    config_setting_set_string_elem(data, 0, "Ubuntu");

        /* ----------------- Write ----------------- */
    config_write(conf, stdout);
}


输出:

title = "Test Application";
version = 1;
app :
{
    user :
    {
        name = "Rainsoft";
        tags = [ "t1", "t3" ];
        data = ( "Ubuntu", 1234 );
        comment = "test...";
    };
};


4. Q&A

(1) 调用 config_destroy(conf) 后,其分配的字符串会被全部释放,因此得自己注意 strcpy / strdup。
(2) 官方文档中标明了 "Libconfig is not thread-safe","Libconfig is not async-safe" ……
(3) 似乎 Array/List 必须是 Group Member,不知道是不是版本的问题。
阅读(681) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~