c语言解释conf配置文件库

c语言中并没有提供解释conf文件的库,因此要自己实现,实际上也不是什么难的事情,下面就是我自己写的一个小代码,测试了下基本能使用,如发现bug及时更新,需要新添加功能自己扩展。

文件【list.h】,代码中使用到的链表实现。

#ifndef __LIST_H__
#define __LIST_H__

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

//tail queue
#define TAILQ_HEAD(name, type) \
    struct name                \
    {                          \
        struct type *tqh_first;    \
        struct type **tqh_last;    \
    }                          \

#define TAILQ_ENTRY(type)      \
    struct                     \
    {                          \
        struct type *tqe_next;     \
        struct type **tqe_prev;    \
    }                          \

/*
 * tail queue access methods
 */
#define	TAILQ_FIRST(head)		((head)->tqh_first)
#define	TAILQ_END(head)			NULL
#define	TAILQ_NEXT(elm, field)		((elm)->field.tqe_next)
#define TAILQ_LAST(head, headname)					\
        (*(((struct headname *)((head)->tqh_last ))->tqh_last))
/* XXX */
#define TAILQ_PREV(elm, headname, field)				\
        (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define	TAILQ_EMPTY(head)						\
        (TAILQ_FIRST(head) == TAILQ_END(head))

#define TAILQ_FOREACH(var, head, field)					\
        for((var) = TAILQ_FIRST(head);					\
            (var) != TAILQ_END(head);					\
            (var) = TAILQ_NEXT(var, field))

#define TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
        for((var) = TAILQ_LAST(head, headname);				\
            (var) != TAILQ_END(head);					\
            (var) = TAILQ_PREV(var, headname, field))

#define TAILQ_INIT(head)            do{ \
    (head)->tqh_first = NULL;           \
    (head)->tqh_last = &(head)->tqh_first; \
}while(0) \

#define TAILQ_INSERT_HEAD(head, elm, field) do {			\
        if (((elm)->field.tqe_next = (head)->tqh_first) != NULL)	\
                (head)->tqh_first->field.tqe_prev =			\
                    &(elm)->field.tqe_next;				\
        else								\
                (head)->tqh_last = &(elm)->field.tqe_next;		\
        (head)->tqh_first = (elm);					\
        (elm)->field.tqe_prev = &(head)->tqh_first;			\
} while (0)

#define TAILQ_INSERT_TAIL(head, elm, field) do {			\
        (elm)->field.tqe_next = NULL;				\
        (elm)->field.tqe_prev = (head)->tqh_last;			\
        *(head)->tqh_last = (elm);					\
        (head)->tqh_last = &(elm)->field.tqe_next;			\
} while (0)

#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
        if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\
                (elm)->field.tqe_next->field.tqe_prev =			\
                    &(elm)->field.tqe_next;				\
        else								\
                (head)->tqh_last = &(elm)->field.tqe_next;		\
        (listelm)->field.tqe_next = (elm);				\
        (elm)->field.tqe_prev = &(listelm)->field.tqe_next;		\
} while (0)

#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
        (elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
        (elm)->field.tqe_next = (listelm);				\
        *(listelm)->field.tqe_prev = (elm);				\
        (listelm)->field.tqe_prev = &(elm)->field.tqe_next;		\
} while (0)

#define TAILQ_REMOVE(head, elm, field) do {				\
        if (((elm)->field.tqe_next) != NULL)				\
                (elm)->field.tqe_next->field.tqe_prev =			\
                    (elm)->field.tqe_prev;				\
        else								\
                (head)->tqh_last = (elm)->field.tqe_prev;		\
        *(elm)->field.tqe_prev = (elm)->field.tqe_next;			\
} while (0)

#define TAILQ_REPLACE(head, elm, elm2, field) do {			\
        if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL)	\
                (elm2)->field.tqe_next->field.tqe_prev =		\
                    &(elm2)->field.tqe_next;				\
        else								\
                (head)->tqh_last = &(elm2)->field.tqe_next;		\
        (elm2)->field.tqe_prev = (elm)->field.tqe_prev;			\
        *(elm2)->field.tqe_prev = (elm2);				\
} while (0)

#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

#endif
文件【config.h】,解析库的头文件:

#ifndef __CONFIG_H__
#define __CONFIG_H__

#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif

#include "list.h"

struct ct_config_comment
{
		TAILQ_ENTRY(ct_config_comment) next;
                char comment[0];
};

typedef struct ct_config_comment ct_ST_config_comment; 

struct ct_config_variable
{
		TAILQ_ENTRY(ct_config_variable) next;
		char *name;
		char *value;
		//int line;
                TAILQ_HEAD(ct_config_comment_list, ct_config_comment) prevline_comment_list,sameline_comment_list;
                //TAILQ_HEAD(ct_config_comment_list, ct_config_comment) sameline_comment_list;
		int blanklines;
                char buf[0];
};

typedef struct ct_config_variable ct_ST_config_variable;

struct ct_config_section
{
		TAILQ_ENTRY(ct_config_section) next;
		char *name;
		TAILQ_HEAD(ct_config_variable_list, ct_config_variable) variable_list;
                //TAILQ_HEAD(ct_config_comment_list, ct_config_comment) prevline_comment_list, sameline_comment_list;
                //TAILQ_HEAD(ct_config_comment_list, ct_config_comment) sameline_comment_list;
		int blanklines;
                char buf[0];
};

typedef struct ct_config_section ct_ST_config_section; 

struct ct_config
{
		char *filename;
		TAILQ_HEAD(ct_config_section_list, ct_config_section) section_list;
                char buf[0];
};

typedef struct ct_config ct_ST_config;

//function for config
/*
ct_ST_config_comment *ct_config_comment_new(const char *comment);
int ct_config_comment_destory(ct_ST_config_comment *p);
int ct_config_comment_modify(ct_ST_config *config, const char *section_name, const char *variable_name, const char *comment);
*/

ct_ST_config_variable *ct_config_variable_new(const char *name, const char *value);
void ct_config_variable_destory(ct_ST_config_variable *var);
int ct_config_variable_append(ct_ST_config_section *section, ct_ST_config_variable *var);
int ct_config_variable_delete(ct_ST_config_section *section, const char *name);
int ct_config_variable_update(ct_ST_config_section *section, const char *name, const char *match, const char *new_value);
ct_ST_config_variable *ct_config_variable_find(ct_ST_config_section *section, const char *name);
void ct_config_variable_display(ct_ST_config_variable *var);

ct_ST_config_section *ct_config_section_new(const char *name);
void ct_config_section_destory(ct_ST_config_section *section);
int ct_config_section_append(ct_ST_config *cfg, ct_ST_config_section *section);
int ct_config_section_delete(ct_ST_config *cfg, const char *name);
int ct_config_section_update(ct_ST_config *cfg, const char *match, const char *new_name);
ct_ST_config *ct_config_section_find(ct_ST_config *cfg, const char *match);
void ct_config_section_display(ct_ST_config_section *section);

//ct_ST_config *ct_config_new();
ct_ST_config *ct_config_new(const char *filename);
void ct_config_destory(ct_ST_config *cfg);
int ct_config_load(const char *filename, ct_ST_config **cfg);
int ct_config_save(ct_ST_config *cfg, const char *new_filename);
void ct_config_display(ct_ST_config *cfg);

#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

#endif
文件【config.c】,解析库的函数实现,包含了一个main函数:

#include "config.h"
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>

ct_ST_config_variable *ct_config_variable_new(const char *name, const char *value)
{
    ct_ST_config_variable *var = (ct_ST_config_variable *)malloc(sizeof(ct_ST_config_variable) + strlen(name) + strlen(value) + 2);
    if (var == NULL)
        return NULL;
    memset((char *)var, 0, sizeof(ct_ST_config_variable));
    TAILQ_INIT(&var->prevline_comment_list);
    TAILQ_INIT(&var->sameline_comment_list);
    var->name = var->buf;
    var->value = var->buf + strlen(name) + 1;
    if (name != NULL)
        strcpy(var->name, name);
    if (value != NULL)
        strcpy(var->value, value);

    return var;
}

void ct_config_variable_destory(ct_ST_config_variable *var)
{
    if (var == NULL)
        return;
    ct_ST_config_comment *comment;
    TAILQ_FOREACH(comment, &var->prevline_comment_list, next)
    {
        if (comment != NULL)
        {
            free(comment->comment);
            free(comment);
        }
    }

    TAILQ_FOREACH(comment, &var->sameline_comment_list, next)
    {
        if (comment != NULL)
        {
            free(comment->comment);
            free(comment);
        }
    }

    free(var);
}

int ct_config_variable_append(ct_ST_config_section *section, ct_ST_config_variable *var)
{
    if (section == NULL || var == NULL)
        return -1;
    //printf("enter ct_config_section_append, %d, %d, %d\n", \
    //       §ion->variable_list, section->variable_list.tqh_last, var);
    TAILQ_INSERT_TAIL(§ion->variable_list, var, next);
    return 0;
}

ct_ST_config_variable *ct_config_variable_find(ct_ST_config_section *section, const char *name)
{
    if (section == NULL || name == NULL)
        return NULL;
    ct_ST_config_variable *var;
    TAILQ_FOREACH(var, §ion->variable_list, next)
    {
        if (strcmp(var->name, name) == 0)
            return var;
    }
    return NULL;
}

int ct_config_variable_delete(ct_ST_config_section *section, const char *name)
{
    if (section == NULL || name == NULL)
        return -1;

    ct_ST_config_variable *var;
    var = ct_config_variable_find(section, name);
    if (var != NULL)
    {
        TAILQ_REMOVE(§ion->variable_list, var, next);
        ct_config_variable_destory(var);
        return 1;
    }
    else
        return 0;

}

void ct_config_variable_display(ct_ST_config_variable *var)
{
    if (var == NULL)
        return NULL;
    printf("        {%s} = {%s} \n", var->name, var->value);
}

ct_ST_config_section *ct_config_section_new(const char *name)
{
    int len = strlen(name);
    ct_ST_config_section *section = malloc(sizeof(ct_ST_config_section) + len + 1);
    section->name = section->buf;
    TAILQ_INIT(§ion->variable_list);
    strcpy(section->name, name);

    return section;
}

void ct_config_section_destory(ct_ST_config_section *section)
{
    if (section == NULL)
        return;
    ct_ST_config_variable *var;
    TAILQ_FOREACH(var, §ion->variable_list, next)
    {
        ct_config_variable_destory(var);
    }
}

int ct_config_section_append(ct_ST_config *cfg, ct_ST_config_section *section)
{
    if (cfg == NULL || section == NULL)
        return -1;
    //printf("enter ct_config_section_append, %d, %d, %d\n", &(cfg->section_list.tqh_first), cfg->section_list.tqh_last, section);
    TAILQ_INSERT_TAIL(&cfg->section_list, section, next);
    return 0;
}

ct_ST_config *ct_config_section_find(ct_ST_config *cfg, const char *match)
{

    if (cfg == NULL || match == NULL)
        return NULL;
    ct_ST_config_section *section;
    TAILQ_FOREACH(section, &cfg->section_list, next)
    {
        if (strcmp(section->name, match) == 0)
            return section;
    }

    return NULL;
}

int ct_config_section_delete(ct_ST_config *cfg, const char *name)
{
    if (cfg == NULL || name == NULL)
        return -1;
    ct_ST_config_section *section;
    section = ct_config_section_find(cfg, name);
    if (section == NULL)
        return 0;
    else
    {
        TAILQ_REMOVE(&cfg->section_list, section, next);
        ct_config_section_destory(section);
        return 0;
    }
}

void ct_config_section_display(ct_ST_config_section *section)
{
    if (section == NULL)
        return;
    ct_ST_config_variable *var;
    printf("     section:%s\n", section->name);
    TAILQ_FOREACH(var, §ion->variable_list, next)
    {
        ct_config_variable_display(var);
    }
}

ct_ST_config *ct_config_new(const char *filename)
{

    int len = strlen(filename);
    ct_ST_config *cfg = malloc(sizeof(ct_ST_config) + len + 1);
    TAILQ_INIT(&cfg->section_list);
    cfg->filename = cfg->buf;
    strcpy(cfg->filename, filename);
    //      printf("cfg = %d, cfg->filename = %s, &cfg->section_list = %d, &cfg->section_list.tqh_first = %d, &cfg->section_list.tqh_last = %d\n", \
    //              cfg, cfg->filename, &cfg->section_list, &cfg->section_list.tqh_first, &cfg->section_list.tqh_last);
    return cfg;
}

void ct_config_destory(ct_ST_config *cfg)
{

    if (cfg == NULL)
        return;
    ct_ST_config_section *section;
    TAILQ_FOREACH(section, &cfg->section_list, next)
    {
        ct_config_section_destory(section);
    }
}

static char *find_first_equal(char *string)
{
    if (string == NULL || !strcmp(string, ""))
        return NULL;
    char *comment = NULL, *equal = NULL;
    comment = strchr(string, '#');
    equal = strchr(string, '=');
    if (comment != NULL && comment < equal)
        equal = NULL;
    return equal;
}

static char *find_last_dash(char *string)
{
    if (string == NULL || !strcmp(string, ""))
        return NULL;
    char *comment = NULL, *prev_dash = NULL, *next_dash = NULL;
    comment = strchr(string, '#');

    while ( (next_dash = strchr(string, ']')) != NULL)
    {
        if (comment != NULL && next_dash > comment)
            break;
        else
        {
            string = next_dash + 1;
            prev_dash = next_dash;
        }
    }
    return prev_dash;
}

int clear_space(const char *str, char **new_str)
{
    if (str == NULL || !strcmp(str, ""))
        return -1;
    int len;
    const char *start = str, *end = str + strlen(str)-1;
    while (*start == ' ' || *start == '\n' || *start == '\t')start++;
    while (*end == ' ' || *end == '\n' || *end == '\t')end--;
    if (start > end)
    {
        *new_str = NULL;
        return -1;
    }
    else
    {
        len = end-start+1;
        *new_str = (char *)malloc(10+1);
        strncpy(*new_str, start, len);
        *(*new_str + len) = '\0';
        return 0;
    }
}

static int prase_textline(char *start, ct_ST_config *cfg )
{
    char *p_comment = NULL, *p_equal = NULL, *p_dash = NULL, *name = NULL, *value = NULL,
    *new_name = NULL, *new_value = NULL;
    int name_len = 0, value_len = 0, ret = 0;
    ct_ST_config_variable *var;
    ct_ST_config_section *section;

    if (start == NULL || !strcmp(start, "") || cfg == NULL)
        return -1;

    if (*start == '#')
    {
        /*process comment*/
    }
    else if (*start == '[')
    {
        /* process section */
        p_comment = strchr(start, '#');
        p_dash = find_last_dash(start+1);
        if (p_dash == NULL)
        {
            //invalid section
            printf("invalid section,only left dash : %s", start);
            return -1;
        }
        name_len = p_dash -1 -start;
      //  printf("len = %d, *p_dash = %c\n", name_len, *p_dash);
        name = (char *)malloc(name_len + 1);
        strncpy(name, start+1, name_len);
        *(name + name_len) = '\0';

        clear_space(name, &new_name);
        if (new_name == NULL || !strcmp(new_name, ""))
        {
            printf("invalid section,no name : %s\n", start);
            return -1;
        }
       // printf("insert new section:%s\n", new_name);
        if ( ct_config_section_append(cfg, ct_config_section_new(new_name))  == 0)
        {
            free(name);
            free(new_name);
        }

    }
    else
    {
        /* process variable */
        p_comment = strchr(start, '#');
        p_equal = find_first_equal(start + 1);
        if (p_equal == NULL)
        {
            printf("invalid variable, no equal : %s", start);
            return -1;
        }
        name_len = p_equal-start;
        name = (char *)malloc(name_len + 1);
        if (name == NULL)
            printf("malloc failed\n");
        strncpy(name, start , name_len);
        *(name + name_len) = '\0';
        clear_space(name, &new_name);
        if (new_name == NULL || !strcmp(new_name, ""))
        {
            printf("invalid name : %s", start);
            return -1;
        }

        if (p_comment != NULL)
            value_len = p_comment-p_equal-1;
        else
            value_len = start + strlen(start)-1;
        value = (char *)malloc(value_len + 1);
        strncpy(value, p_equal + 1, value_len);
        *(value+value_len) = '\0';
        clear_space(value, &new_value);
        if (new_value == NULL || !strcmp(new_value))
        {
            printf("invalid value : %s", start);
            return -1;
        }
       // printf("insert new variable: name = %s, value = %s\n", new_name, new_value);
        section = TAILQ_LAST(&cfg->section_list, ct_config_section_list);
        var = ct_config_variable_new(new_name, new_value);

        ret = ct_config_variable_append(section, var);
        if (ret != 0)
        {
            printf("add variable in section error\n");
            return -1;
        }
    }

    return 0;
}

int ct_config_load(const char *filename, ct_ST_config **cfg)
{
    if (filename == NULL || !strcmp(filename, ""))
        return -1;

    FILE * fp;
    char * line = NULL, *ptr = NULL;
    size_t len = 0;
    size_t read;
    
    fp = fopen(filename, "r");
    if (fp == NULL)
        exit(EXIT_FAILURE);

    *cfg = ct_config_new(filename);
    while ((read = getline(&line, &len, fp)) != -1) {
      //  printf("read text: byte = %zu, len = %d, text = {%s}:\n", read, len, line);

        ptr = line;

        while (*ptr == " ") ptr++;

        if (*ptr == "\0")
            continue;

        prase_textline(ptr, *cfg);
    }

    if (line)
        free(line);

}

void ct_config_display(ct_ST_config *cfg)
{

    ct_ST_config_section *section;
    if (cfg == NULL)
        return;
    printf("----------------------------------- \n");
    printf("    display config parse result\n");
    printf("-----------------------------------\n");
    printf("parse filename : %s\n", cfg->filename);
    TAILQ_FOREACH(section, &cfg->section_list, next)
    {
        ct_config_section_display(section);
    }
}

int main()
{
    ct_ST_config *cfg = NULL;
    ct_config_load("test.conf", &cfg);
  //  ct_config_section_display(ct_config_section_find(cfg, "section9"));
  //  ct_config_variable_display(ct_config_variable_find(ct_config_section_find(cfg, "section1"), "name3"));
  //  ct_config_section_delete(cfg, "section1");
  //  ct_config_variable_delete(ct_config_section_find(cfg, "section1"), "name3");
    ct_config_display(cfg);
}
文件【test.conf】,自己随便写的测试文件,不是特别规范,很多情况可能都没考虑到:

[global]
[[left]
[right]]

#comment
name1 = 1

  name2 = 2
[section1]
name3 = 3 #comment
=2
test2]
hello
#conmm name6=6
[section2
name4 = 4
[section3]
 name5 =
 name7 = name7=1 #comment
 name8 = =name8 #comment
 name9 = =name9

编译方法:gcc config.c -o config 

运行:./config


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值