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(§ion->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或者路由器定制项目,可以直接联系佐须之男。