佐须之男的博客

技术需要沉淀,成长需要痛苦,成功需要坚持,敬仰需要奉献

重新封装OpenWRT下的LibUCI库-降低使用难度

    2013年时,做过一段时间的OpenWRT开发,感觉最头疼的还是UCI的配置框架部分。相对于JSON和XML来说,UCI的使用便利性和交互上面上是欠缺的。因为UCI是一套私有的配置协议,缺乏社区的支持,所以在语言的绑定(binding)上是比较匮乏的。在项目中,你只能采用官方的两种语言,C和LUA。由于时间有限,当年项目为了加快进度方便组员调用LibUCI,所以我重新封装了库。

    由于当年那个项目一直没有起来,所以就没有做PHP这块的语言绑定。下面是代码:


// uci-helper.h

#define get(args...) uci_easyget(ctx,p,args) 
#define sget(args...) uci_sectionget(ctx,p,args) 
#define safe_get(args...) uci_easysafeget(ctx,p,args)
#define set(args...) uci_easyset(ctx,&ptr,args)
#define del(args...) uci_easydel(ctx,&ptr,args)
#define list(args...) uci_easylist(ctx,&ptr,args)
#define get_int(args...) atoi(uci_easyget(ctx,p,args))
#define del_section(args...) uci_easydelsection(args)
/* 常用的变量 */
#define prep_uci()     struct uci_context *ctx; ctx =uci_alloc_context(); struct uci_ptr ptr; struct uci_package *p=NULL 
 
extern char *uci_easyget(struct uci_context *ctx,struct uci_package *p,char* package_name,char* section_name,char* option_name);
extern char *uci_sectionget(struct uci_context *ctx,struct uci_package *p,char* package_name,char* section_name);
extern char *uci_easysafeget(struct uci_context *ctx,struct uci_package *p,char* package_name,char* section_name,char* option_name);
extern int uci_easyset(struct uci_context *ctx, struct uci_ptr *ptr,const char *format,...);
extern int uci_easyadd(struct uci_context *ctx, struct uci_ptr *ptr,const char *format,...);
extern int uci_easyxdel(char *package_name,const char *section_name,const char *format,...);
extern int uci_easydel(struct uci_context *ctx, struct uci_ptr *ptr,const char *format,...);
extern int uci_easydelsection(char *package_name,char *section_name);
            
extern char* dynamic_strcat(int num_strs, ...);
extern char* dynamic_replace(char* template_str, char* old, char* new);
extern int get_uci_option(struct uci_context* ctx, struct uci_element** e, struct uci_package *p, char* package_name, char* section_name, char* option_name);
extern char* get_option_value_string(struct uci_option* uopt);


// uci-helper.c

#include "uci.h"
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
char *uci_easyget(struct uci_context *ctx,struct uci_package *p, char* package_name,char* section_name,char* option_name);
char *uci_sectionget(struct uci_context *ctx,struct uci_package *p, char* package_name,char* section_name);
char *uci_easysafeget(struct uci_context *ctx,struct uci_package *p, char* package_name,char* section_name,char* option_name);
int uci_easyset(struct uci_context *ctx, struct uci_ptr *ptr,const char *format,...);
int uci_easylist(struct uci_context *ctx, struct uci_ptr *ptr,const char *format,...);
int uci_easyxdel(char *package_name,const char *section_name,const char *format,...);
int uci_easydel(struct uci_context *ctx, struct uci_ptr *ptr,const char *format,...);
int uci_easydelsection(char *package_name,char *section_name);
char* dynamic_strcat(int num_strs, ...);
char* dynamic_replace(char* template_str, char* old, char* new);
int get_uci_option(struct uci_context* ctx, struct uci_element** e, struct uci_package *p, char* package_name, char* section_name, char* option_name);
char* get_option_value_string(struct uci_option* uopt);
    /* 为了兼容get_uci_option 的申明 */
inline char *uci_easyget(struct uci_context *ctx,struct uci_package *p,char* package_name,char* section_name,char* option_name)
{
    static char option_value[2048];
    char *string;
    int ret;
    struct uci_element *e=NULL;
        
    memset(option_value,0,sizeof(option_value));
            
    if ((ret=get_uci_option(ctx,&e,p,package_name,section_name,option_name))==UCI_OK)
        {
                string=get_option_value_string(uci_to_option(e));
        strcpy(option_value,string);    
                free(string);
        }
    return ( ret==UCI_OK ? option_value :NULL );
}
inline char *uci_sectionget(struct uci_context *ctx,struct uci_package *p,char* package_name,char* section_name)
{
        static char type_value[2048];
        char *string;
        int ret;
        char *type=NULL;
        memset(type_value,0,sizeof(type_value));
        if ((ret=get_uci_section(ctx,&type,p,package_name,section_name))==UCI_OK)
        {
                strcpy(type_value,type);
        }
        return ( ret==UCI_OK ? type_value :NULL );
}
    /* 返回空字符 */    
inline char *uci_easysafeget(struct uci_context *ctx,struct uci_package *p,char* package_name,char* section_name,char* option_name)
{
    static char option_value[2048];
    char *string;
    int ret;
    struct uci_element *e=NULL;
        
    memset(option_value,0,sizeof(option_value));
            
    if ((ret=get_uci_option(ctx,&e,p,package_name,section_name,option_name))==UCI_OK)
        {
                string=get_option_value_string(uci_to_option(e));
        strcpy(option_value,string);    
                free(string);
        }
    return ( ( ret==UCI_OK && option_value!=NULL) ? option_value :"" );
}
inline int uci_easyset(struct uci_context *ctx, struct uci_ptr *ptr,const char *format,...)
{
    int ret;
    char str[2048];
    
    va_list args;
    
    va_start(args, format);
        vsnprintf(str, sizeof(str), format, args);
        va_end(args);
    
    if (uci_lookup_ptr(ctx, ptr, str,true) == UCI_OK)
    {
        ret=uci_set(ctx, ptr);
    }
    
    return ret;
}
inline int uci_easylist(struct uci_context *ctx, struct uci_ptr *ptr,const char *format,...)
{
    int ret;
    char str[2048];
    
    va_list args;
    
    va_start(args, format);
        vsnprintf(str, sizeof(str), format, args);
        va_end(args);
    
    if (uci_lookup_ptr(ctx, ptr, str,true) == UCI_OK)
    {
        ret=uci_add_list(ctx, ptr);
    }
             
    return ret;
}
 
inline int uci_easydel(struct uci_context *ctx, struct uci_ptr *ptr,const char *format,...)
{
    int ret;
    char str[2048];
    
    va_list args;
    
    va_start(args, format);
        vsnprintf(str, sizeof(str), format, args);
        va_end(args);
    
    if ((ret=uci_lookup_ptr(ctx, ptr, str,true)) == UCI_OK)
    {
        uci_delete(ctx, ptr);
    }
    
    return ret;
}
inline int uci_easyxdel(char *package_name,const char *section_name,const char *format,...)
{
    int ret;
    char str[2048];
    va_list args;
        va_start(args, format);
    /* strstr  查找字符代替循环的查找 */
        vsnprintf(str, sizeof(str),format, args);
        va_end(args);
    
    
    struct uci_ptr ptr;
    /* section element */
    struct uci_element *es=NULL;
    /* option element */
    struct uci_element *eo=NULL;
    struct uci_package *p=NULL;
    
    struct uci_context *del_ctx;
    del_ctx =uci_alloc_context();
    struct uci_context *ctx;
    ctx =uci_alloc_context();
    if (uci_load(ctx,package_name,&p)!=UCI_OK)
        {
                fprintf(stderr,"No %s package!\n",package_name);
        }
    
    /* 遍历 整个package中的section元素*/
    uci_foreach_element(&p->sections, es)
    {
        struct uci_section *section = uci_to_section(es);
        if (strcmp(section->e.name,section_name)==0)
        {
    
            /* 遍历 section中的option元素*/
            uci_foreach_element(&section->options,eo)
            {
                struct uci_option *o=uci_to_option(eo);
                if (strstr(str,o->e.name)!=NULL) continue;
                char *var_set = dynamic_strcat(5, package_name,".",section_name,".",o->e.name);
                if (uci_lookup_ptr(del_ctx, &ptr, var_set, true) == UCI_OK)
                {
                    ret=uci_delete(del_ctx, &ptr);
                }
                free(var_set);
            }
        }
    }
    
    if (uci_lookup_ptr(del_ctx, &ptr,package_name, true) == UCI_OK)
    {
        uci_commit(del_ctx, &ptr.p,false);
    }
    /* reload package */
    uci_free_context(del_ctx);
    uci_free_context(ctx);
    return ret;
    
}
inline int uci_easydelsection(char *package_name,char *section_name)
{
    struct uci_context *ctx;
    ctx =uci_alloc_context();
    struct uci_context *del_ctx;
    del_ctx=uci_alloc_context();
    
    struct uci_ptr ptr;
    struct uci_package *p=NULL;
    struct uci_element *e=NULL;
    char *var_set=NULL;
    
    if (uci_load(ctx,package_name,&p)!=UCI_OK) 
    {
        fprintf(stderr,"No %s package\n",package_name);    
    }
        
    uci_foreach_element(&p->sections,e) 
    {
        struct uci_section *section = uci_to_section(e);
        if (strncmp(section->e.name,section_name,strlen(section_name))==0) 
        {
            /* 删除主节点*/
            var_set = dynamic_strcat(3, package_name,".",section->e.name);
            if (uci_lookup_ptr(del_ctx, &ptr, var_set, true) == UCI_OK)
            {
                uci_delete(del_ctx, &ptr);
            }
            free(var_set);
        }
    }
    
    if (uci_lookup_ptr(del_ctx, &ptr, package_name, true) == UCI_OK)
        {
                uci_commit(del_ctx, &ptr.p, false);
        }
    
        uci_free_context(del_ctx);
    /*      why ?    */     
    uci_free_context(ctx);
    return 1;    
}
char* dynamic_strcat(int num_strs, ...)
{
        va_list strs;
        int new_length = 0;
        int i;
        int next_start;
        char* new_str;
        va_start(strs, num_strs);
        for(i=0; i < num_strs; i++)
        {
                char* next_arg = va_arg(strs, char*);
                if(next_arg != NULL)
                {
                        new_length = new_length + strlen(next_arg);
                }
        }
        va_end(strs);
        new_str = malloc((1+new_length)*sizeof(char));
        va_start(strs, num_strs);
        next_start = 0;
        for(i=0; i < num_strs; i++)
        {
                char* next_arg = va_arg(strs, char*);
                if(next_arg != NULL)
                {
                        int next_length = strlen(next_arg);
                        memcpy(new_str+next_start,next_arg, next_length);
                        next_start = next_start+next_length;
                }
        }
        new_str[next_start] = '\0';
        return new_str;
}
char* dynamic_replace(char* template_str, char* old, char* new)
{
        char *ret;
        int i, count = 0;
        int newlen = strlen(new);
        int oldlen = strlen(old);
        char* dyn_template = strdup(template_str);
        char* s = dyn_template;
        for (i = 0; s[i] != '\0'; i++)
        {
                if (strstr(&s[i], old) == &s[i])
                {
                        count++;
                        i += oldlen - 1;
                }
        }
        ret = malloc(i + 1 + count * (newlen - oldlen));
        i = 0;
        while (*s)
        {
                if (strstr(s, old) == s)
                {
                        strcpy(&ret[i], new);
                        i += newlen;
                        s += oldlen;
                }
                else
                {
                        ret[i++] = *s++;
                }
        }
        ret[i] = '\0';
        free(dyn_template);
        return ret;
}
int get_uci_option(struct uci_context* ctx, struct uci_element** e, struct uci_package *p, char* package_name, char* section_name, char* option_name)
{
        struct uci_ptr ptr;
    char* lookup_str = dynamic_strcat(5, package_name, ".", section_name, ".", option_name);
        int ret_value = uci_lookup_ptr(ctx, &ptr,lookup_str, 1);
        if(ret_value == UCI_OK)
        {
                if( !(ptr.flags & UCI_LOOKUP_COMPLETE))
                {
                        ret_value = UCI_ERR_NOTFOUND;
                }
                else
                {
                        *e = (struct uci_element*)ptr.o;
                }
        }
    free(lookup_str);
        return ret_value;
}
int get_uci_section(struct uci_context* ctx, char** type, struct uci_package *p, char* package_name, char* section_name)
{
        struct uci_ptr ptr;
        char* lookup_str = dynamic_strcat(3, package_name, ".", section_name);
        int ret_value = uci_lookup_ptr(ctx, &ptr,lookup_str, 1);
        if(ret_value == UCI_OK)
        {
                if( !(ptr.flags & UCI_LOOKUP_COMPLETE))
                {
                        ret_value = UCI_ERR_NOTFOUND;
                }
                else
                {
                        *type=ptr.s->type;
                }
        }
        free(lookup_str);
        return ret_value;
}
char* get_option_value_string(struct uci_option* uopt)
{
        char* opt_str = NULL;
        if(uopt->type == UCI_TYPE_STRING)
        {
                opt_str = strdup(uopt->v.string);
        }
        if(uopt->type == UCI_TYPE_LIST)
        {
                struct uci_element* e;
                uci_foreach_element(&uopt->v.list, e)
                {
                        if(opt_str == NULL)
                        {
                                opt_str = strdup(e->name);
                        }
                        else
                        {
                                char* tmp;
                                tmp = dynamic_strcat(3, opt_str, " ", e->name);
                                free(opt_str);
                                opt_str = tmp;
                        }
                }
        }
        
    return opt_str;
}


PS:大家有OpenWRT或者路由器定制项目,可以直接联系佐须之男。

版权所有: http://forgotfun.org/2016/02/%E9%87%8D%E6%96%B0%E5%B0%81%E8%A3%85OpenWRT%E4%B8%8B%E7%9A%84LibUCI%E5%BA%93-%E9%99%8D%E4%BD%8E%E4%BD%BF%E7%94%A8%E9%9A%BE%E5%BA%A6.html 作者: 佐须之男 未经允许请勿转载

© 2016 佐须之男版权所有 | 联系方式 forgotfun@qq.com | 业务合作 181-1435-4589 (陆工)