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