【智能路由器】系列文章连接
http://blog.csdn.net/u012819339/article/category/5803489
上篇博客讲解了命令行下uci的使用方法,本篇博客arvik将简单剖析uci部分源码,带领大家使用c语言调用uci的API来读取配置文件。
实战背景
倘若我们自己写了一个应用程序,也想用uci来集中化管理配置该应用的配置文件,怎么办呢?
看了arvik的上一篇博客后相信新手能很快的使用uci对某个配置文件进行配置,只是如何让我们的应用程序读取配置文件内容呢,本篇arvik将解答这个问题。
简单的基本关系
图解
这里画一个图让大家大致了解配置文件的内容和uci的几个基本结构之间的对应关系。(例举文件为uhttpd的配置文件)
几个结构体
struct uci_package: 包结构体。它对应一个配置文件内容
struct uci_package
{
struct uci_element e;
struct uci_list sections;
struct uci_context *ctx;
bool has_delta;
char *path;
/* private: */
struct uci_backend *backend;
void *priv;
int n_section;
struct uci_list delta;
struct uci_list saved_delta;
};
struct uci_section:节结构体,它对应配置文件中的节
struct uci_section
{
struct uci_element e;
struct uci_list options;
struct uci_package *package;
bool anonymous;
char *type;
};
struct uci_option:选项结构体,它对应配置文件里节中的option或者list
struct uci_option
{
struct uci_element e;
struct uci_section *section;
enum uci_option_type type;
union {
struct uci_list list;
char *string;
} v;
};
struct uci_ptr:元素位置指针结构,用来查询并保存对应位置元素
struct uci_ptr
{
enum uci_type target;
enum {
UCI_LOOKUP_DONE = (1 << 0),
UCI_LOOKUP_COMPLETE = (1 << 1),
UCI_LOOKUP_EXTENDED = (1 << 2),
} flags;
struct uci_package *p;
struct uci_section *s;
struct uci_option *o;
struct uci_element *last;
const char *package;
const char *section;
const char *option;
const char *value;
};
struct uci_context: uci上下文结构,贯穿查询、更改配置文件全过程。
struct uci_context
{
/* 配置文件包列表 */
struct uci_list root;
/* 解析上下文,只用于错误处理 */
struct uci_parse_context *pctx;
/* 后端导入导出 */
struct uci_backend *backend;
struct uci_list backends;
/* uci 运行标识 */
enum uci_flags flags;
char *confdir;
char *savedir;
/* search path for delta files */
struct uci_list delta_path;
/* 私有数据 */
int err;
const char *func;
jmp_buf trap;
bool internal, nested;
char *buf;
int bufsz;
};
几个基本API函数
uci_alloc_context:动态申请一个uci上下文结构
struct uci_context *uci_alloc_context(void);
uci_free_contex:释放由uci_alloc_context申请的uci上下文结构且包括它的所有数据
void uci_free_context(struct uci_context *ctx);
uci_lookup_ptr:由给定的元组查找元素
/**
* uci_lookup_ptr: 分离一个uci元组字符串且查找对应元素树
* @ctx: uci context结构体指针
* @ptr: 存放元素查询结果的结构体指针
* @str: 待查找的uci元组字符串
* @extended: 允许扩展语法查询
*
*如果extended被设为ture,则uci_lookup_ptr支持下列扩展语法:
*
*例子:
* network.@interface[0].ifname ('ifname' option of the first interface section)
* network.@interface[-1] (last interface section)
* Note: 有必要的话uci_lookup_ptr将会自动加载配置文件包
* @str 不能是一个const类型指针,它在使用的过程中将会被更改且用于将字符串填写到@ptr中,因此
* 它只要@ptr还在使用,它就必须是可用的
*
* 这个函数在指定包元组的的字符串未被找到时返回UCI_ERR_NOTFOUND,否则返回UCI_OK
*
* 记住在查找其他部分失败的情况,如果它们同样被指定,包括section和option,同样会返回UCI_OK,
* 但是ptr->flags * UCI_LOOKUP_COMPLETE标志位不会被置位
*/
int uci_lookup_ptr(struct uci_context *ctx, struct uci_ptr *ptr, char *str, bool extended);
只需由以上3个API就可以对一个uci标准配置文件进行简单的读取了。
代码实战
下面就写一个实例代码试试吧
/***********************************
author:arvik
email:1216601195@qq.com
csdn:http://blog.csdn.net/u012819339
************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "uci.h"
int main()
{
struct uci_context *c;
struct uci_ptr p;
char *a = strdup("arvik_testconfig.main.home");
c = uci_alloc_context();
if(UCI_OK != uci_lookup_ptr(c, &p, a, true))
{
uci_perror(c, "no found!\n");
return -1;
}
printf("%s\n", p.o->v.string);
uci_free_context(c);
free(a);
return(0);
}
效果:
root@OpenWrt:/# arvik_uci_test
/www
运行截图:
【智能路由器】系列文章连接
http://blog.csdn.net/u012819339/article/category/5803489