libconfig - Configuration File Library

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

找了好几种相关的类库,发觉还是 hyperrealm libconfig 最强大最好用,相关细节可参考 官方手册

源中的版本是 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 = &(config_t){};
    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,不知道是不是版本的问题。


原文地址:http://www.rainsts.net/article.asp?id=960

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值