add json_script, a minimalistic JSON based script interpreter
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
This commit is contained in:
parent
af2f52a37b
commit
38ea521911
3 changed files with 737 additions and 1 deletions
|
@ -43,7 +43,10 @@ IF(EXISTS ${json})
|
|||
ADD_EXECUTABLE(jshn jshn.c)
|
||||
TARGET_LINK_LIBRARIES(jshn ${json})
|
||||
|
||||
INSTALL(TARGETS blobmsg_json jshn
|
||||
ADD_LIBRARY(json_script SHARED json_script.c)
|
||||
TARGET_LINK_LIBRARIES(json_script ubox)
|
||||
|
||||
INSTALL(TARGETS blobmsg_json jshn json_script
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
|
622
json_script.c
Normal file
622
json_script.c
Normal file
|
@ -0,0 +1,622 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/stat.h>
|
||||
#include <regex.h>
|
||||
|
||||
#include <libubox/avl-cmp.h>
|
||||
|
||||
#include "json_script.h"
|
||||
|
||||
struct json_call {
|
||||
struct json_script_ctx *ctx;
|
||||
struct blob_attr *vars;
|
||||
unsigned int seq;
|
||||
};
|
||||
|
||||
struct json_handler {
|
||||
const char *name;
|
||||
int (*cb)(struct json_call *call, struct blob_attr *cur);
|
||||
};
|
||||
|
||||
static int json_process_expr(struct json_call *call, struct blob_attr *cur);
|
||||
static int json_process_cmd(struct json_call *call, struct blob_attr *cur);
|
||||
|
||||
struct json_script_file *
|
||||
json_script_file_from_blobmsg(const char *name, void *data, int len)
|
||||
{
|
||||
struct json_script_file *f;
|
||||
char *new_name;
|
||||
int name_len = 0;
|
||||
|
||||
if (name)
|
||||
name_len = strlen(name) + 1;
|
||||
|
||||
f = calloc_a(sizeof(*f) + len, &new_name, name_len);
|
||||
memcpy(f->data, data, len);
|
||||
if (name)
|
||||
f->avl.key = strcpy(new_name, name);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static struct json_script_file *
|
||||
json_script_get_file(struct json_script_ctx *ctx, const char *filename)
|
||||
{
|
||||
struct json_script_file *f;
|
||||
|
||||
f = avl_find_element(&ctx->files, filename, f, avl);
|
||||
if (f)
|
||||
return f;
|
||||
|
||||
f = ctx->handle_file(ctx, filename);
|
||||
if (!f)
|
||||
return NULL;
|
||||
|
||||
avl_insert(&ctx->files, &f->avl);
|
||||
return f;
|
||||
}
|
||||
|
||||
static void __json_script_run(struct json_call *call, struct json_script_file *file,
|
||||
struct blob_attr *context)
|
||||
{
|
||||
struct json_script_ctx *ctx = call->ctx;
|
||||
|
||||
if (file->seq == call->seq) {
|
||||
if (context)
|
||||
ctx->handle_error(ctx, "Recursive include", context);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
file->seq = call->seq;
|
||||
while (file) {
|
||||
json_process_cmd(call, file->data);
|
||||
file = file->next;
|
||||
}
|
||||
}
|
||||
|
||||
const char *json_script_find_var(struct json_script_ctx *ctx, struct blob_attr *vars,
|
||||
const char *name)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
int rem;
|
||||
|
||||
blobmsg_for_each_attr(cur, vars, rem) {
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING)
|
||||
continue;
|
||||
|
||||
if (strcmp(blobmsg_name(cur), name) != 0)
|
||||
continue;
|
||||
|
||||
return blobmsg_data(cur);
|
||||
}
|
||||
|
||||
return ctx->handle_var(ctx, name, vars);
|
||||
}
|
||||
|
||||
static const char *
|
||||
msg_find_var(struct json_call *call, const char *name)
|
||||
{
|
||||
return json_script_find_var(call->ctx, call->vars, name);
|
||||
}
|
||||
|
||||
static void
|
||||
json_get_tuple(struct blob_attr *cur, struct blob_attr **tb, int t1, int t2)
|
||||
{
|
||||
static struct blobmsg_policy expr_tuple[3] = {
|
||||
{ .type = BLOBMSG_TYPE_STRING },
|
||||
{},
|
||||
{},
|
||||
};
|
||||
|
||||
expr_tuple[1].type = t1;
|
||||
expr_tuple[2].type = t2;
|
||||
blobmsg_parse_array(expr_tuple, 3, tb, blobmsg_data(cur), blobmsg_data_len(cur));
|
||||
}
|
||||
|
||||
static int handle_if(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
struct blob_attr *tb[4];
|
||||
int ret;
|
||||
|
||||
static const struct blobmsg_policy if_tuple[4] = {
|
||||
{ .type = BLOBMSG_TYPE_STRING },
|
||||
{ .type = BLOBMSG_TYPE_ARRAY },
|
||||
{ .type = BLOBMSG_TYPE_ARRAY },
|
||||
{ .type = BLOBMSG_TYPE_ARRAY },
|
||||
};
|
||||
|
||||
blobmsg_parse_array(if_tuple, 4, tb, blobmsg_data(expr), blobmsg_data_len(expr));
|
||||
|
||||
if (!tb[1] || !tb[2])
|
||||
return 0;
|
||||
|
||||
ret = json_process_expr(call, tb[1]);
|
||||
if (ret < 0)
|
||||
return 0;
|
||||
|
||||
if (ret)
|
||||
return json_process_cmd(call, tb[2]);
|
||||
|
||||
if (!tb[3])
|
||||
return 0;
|
||||
|
||||
return json_process_cmd(call, tb[3]);
|
||||
}
|
||||
|
||||
static int handle_case(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
struct blob_attr *tb[3], *cur;
|
||||
const char *var;
|
||||
int rem;
|
||||
|
||||
json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, BLOBMSG_TYPE_TABLE);
|
||||
if (!tb[1] || !tb[2])
|
||||
return 0;
|
||||
|
||||
var = msg_find_var(call, blobmsg_data(tb[1]));
|
||||
if (!var)
|
||||
return 0;
|
||||
|
||||
blobmsg_for_each_attr(cur, tb[2], rem) {
|
||||
if (!strcmp(var, blobmsg_name(cur)))
|
||||
return json_process_cmd(call, cur);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int handle_return(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
return -2;
|
||||
}
|
||||
|
||||
static int handle_include(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
struct blob_attr *tb[3];
|
||||
struct json_script_file *f;
|
||||
|
||||
json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
|
||||
if (!tb[1])
|
||||
return 0;
|
||||
|
||||
f = json_script_get_file(call->ctx, blobmsg_data(tb[1]));
|
||||
if (!f)
|
||||
return 0;
|
||||
|
||||
__json_script_run(call, f, expr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct json_handler cmd[] = {
|
||||
{ "if", handle_if },
|
||||
{ "case", handle_case },
|
||||
{ "return", handle_return },
|
||||
{ "include", handle_include },
|
||||
};
|
||||
|
||||
static int eq_regex_cmp(const char *str, const char *pattern, bool regex)
|
||||
{
|
||||
regex_t reg;
|
||||
int ret;
|
||||
|
||||
if (!regex)
|
||||
return !strcmp(str, pattern);
|
||||
|
||||
if (regcomp(®, pattern, REG_EXTENDED | REG_NOSUB))
|
||||
return 0;
|
||||
|
||||
ret = !regexec(®, str, 0, NULL, 0);
|
||||
regfree(®);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int expr_eq_regex(struct json_call *call, struct blob_attr *expr, bool regex)
|
||||
{
|
||||
struct json_script_ctx *ctx = call->ctx;
|
||||
struct blob_attr *tb[3], *cur;
|
||||
const char *var;
|
||||
int rem;
|
||||
|
||||
json_get_tuple(expr, tb, BLOBMSG_TYPE_STRING, 0);
|
||||
if (!tb[1] || !tb[2])
|
||||
return -1;
|
||||
|
||||
var = msg_find_var(call, blobmsg_data(tb[1]));
|
||||
if (!var)
|
||||
return 0;
|
||||
|
||||
switch(blobmsg_type(tb[2])) {
|
||||
case BLOBMSG_TYPE_STRING:
|
||||
return eq_regex_cmp(var, blobmsg_data(tb[2]), regex);
|
||||
case BLOBMSG_TYPE_ARRAY:
|
||||
blobmsg_for_each_attr(cur, tb[2], rem) {
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
|
||||
ctx->handle_error(ctx, "Unexpected element type", cur);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (eq_regex_cmp(var, blobmsg_data(cur), regex))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
ctx->handle_error(ctx, "Unexpected element type", tb[2]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int handle_expr_eq(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
return expr_eq_regex(call, expr, false);
|
||||
}
|
||||
|
||||
static int handle_expr_regex(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
return expr_eq_regex(call, expr, true);
|
||||
}
|
||||
|
||||
static int handle_expr_has(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
struct json_script_ctx *ctx = call->ctx;
|
||||
struct blob_attr *tb[3], *cur;
|
||||
int rem;
|
||||
|
||||
json_get_tuple(expr, tb, 0, 0);
|
||||
if (!tb[1])
|
||||
return -1;
|
||||
|
||||
switch(blobmsg_type(tb[1])) {
|
||||
case BLOBMSG_TYPE_STRING:
|
||||
return !!msg_find_var(call, blobmsg_data(tb[1]));
|
||||
case BLOBMSG_TYPE_ARRAY:
|
||||
blobmsg_for_each_attr(cur, tb[1], rem) {
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
|
||||
ctx->handle_error(ctx, "Unexpected element type", cur);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg_find_var(call, blobmsg_data(cur)))
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
ctx->handle_error(ctx, "Unexpected element type", tb[1]);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int expr_and_or(struct json_call *call, struct blob_attr *expr, bool and)
|
||||
{
|
||||
struct blob_attr *cur;
|
||||
int ret, rem;
|
||||
int i = 0;
|
||||
|
||||
blobmsg_for_each_attr(cur, expr, rem) {
|
||||
if (i++ < 1)
|
||||
continue;
|
||||
|
||||
ret = json_process_expr(call, cur);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (ret != and)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return and;
|
||||
}
|
||||
|
||||
static int handle_expr_and(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
return expr_and_or(call, expr, 1);
|
||||
}
|
||||
|
||||
static int handle_expr_or(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
return expr_and_or(call, expr, 0);
|
||||
}
|
||||
|
||||
static int handle_expr_not(struct json_call *call, struct blob_attr *expr)
|
||||
{
|
||||
struct blob_attr *tb[3];
|
||||
|
||||
json_get_tuple(expr, tb, BLOBMSG_TYPE_ARRAY, 0);
|
||||
if (!tb[1])
|
||||
return -1;
|
||||
|
||||
return json_process_expr(call, tb[1]);
|
||||
}
|
||||
|
||||
static const struct json_handler expr[] = {
|
||||
{ "eq", handle_expr_eq },
|
||||
{ "regex", handle_expr_regex },
|
||||
{ "has", handle_expr_has },
|
||||
{ "and", handle_expr_and },
|
||||
{ "or", handle_expr_or },
|
||||
{ "not", handle_expr_not },
|
||||
};
|
||||
|
||||
static int
|
||||
__json_process_type(struct json_call *call, struct blob_attr *cur,
|
||||
const struct json_handler *h, int n, bool *found)
|
||||
{
|
||||
const char *name = blobmsg_data(blobmsg_data(cur));
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (strcmp(name, h[i].name) != 0)
|
||||
continue;
|
||||
|
||||
*found = true;
|
||||
return h[i].cb(call, cur);
|
||||
}
|
||||
|
||||
*found = false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int json_process_expr(struct json_call *call, struct blob_attr *cur)
|
||||
{
|
||||
struct json_script_ctx *ctx = call->ctx;
|
||||
bool found;
|
||||
int ret;
|
||||
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY ||
|
||||
blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) {
|
||||
ctx->handle_error(ctx, "Unexpected element type", cur);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = __json_process_type(call, cur, expr, ARRAY_SIZE(expr), &found);
|
||||
if (!found)
|
||||
ctx->handle_error(ctx, "Unknown expression type", cur);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int cmd_add_string(struct json_call *call, const char *pattern)
|
||||
{
|
||||
struct json_script_ctx *ctx = call->ctx;
|
||||
char *dest, *next, *str;
|
||||
int len = 0;
|
||||
bool var = false;
|
||||
char c = '%';
|
||||
|
||||
dest = blobmsg_alloc_string_buffer(&ctx->buf, NULL, 1);
|
||||
next = alloca(strlen(pattern) + 1);
|
||||
strcpy(next, pattern);
|
||||
|
||||
for (str = next; str; str = next) {
|
||||
const char *cur;
|
||||
char *end;
|
||||
int cur_len = 0;
|
||||
bool cur_var = var;
|
||||
|
||||
end = strchr(str, '%');
|
||||
if (end) {
|
||||
*end = 0;
|
||||
next = end + 1;
|
||||
var = !var;
|
||||
} else {
|
||||
end = str + strlen(str);
|
||||
next = NULL;
|
||||
}
|
||||
|
||||
if (cur_var) {
|
||||
if (next > str) {
|
||||
cur = msg_find_var(call, str);
|
||||
if (!cur)
|
||||
continue;
|
||||
|
||||
cur_len = strlen(cur);
|
||||
} else {
|
||||
cur = &c;
|
||||
cur_len = 1;
|
||||
}
|
||||
} else {
|
||||
if (str == end)
|
||||
continue;
|
||||
|
||||
cur = str;
|
||||
cur_len = end - str;
|
||||
}
|
||||
|
||||
dest = blobmsg_realloc_string_buffer(&ctx->buf, cur_len + 1);
|
||||
memcpy(dest + len, cur, cur_len);
|
||||
len += cur_len;
|
||||
}
|
||||
|
||||
if (var)
|
||||
return -1;
|
||||
|
||||
dest[len] = 0;
|
||||
blobmsg_add_string_buffer(&ctx->buf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmd_process_strings(struct json_call *call, struct blob_attr *attr)
|
||||
{
|
||||
struct json_script_ctx *ctx = call->ctx;
|
||||
struct blob_attr *cur;
|
||||
int args = -1;
|
||||
int rem, ret;
|
||||
void *c;
|
||||
|
||||
blob_buf_init(&ctx->buf, 0);
|
||||
c = blobmsg_open_array(&ctx->buf, NULL);
|
||||
blobmsg_for_each_attr(cur, attr, rem) {
|
||||
if (args++ < 0)
|
||||
continue;
|
||||
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_STRING) {
|
||||
ctx->handle_error(ctx, "Invalid argument in command", attr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = cmd_add_string(call, blobmsg_data(cur));
|
||||
if (ret) {
|
||||
ctx->handle_error(ctx, "Unterminated variable reference in string", attr);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
blobmsg_close_array(&ctx->buf, c);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __json_process_cmd(struct json_call *call, struct blob_attr *cur)
|
||||
{
|
||||
struct json_script_ctx *ctx = call->ctx;
|
||||
const char *name;
|
||||
bool found;
|
||||
int ret;
|
||||
|
||||
if (blobmsg_type(cur) != BLOBMSG_TYPE_ARRAY ||
|
||||
blobmsg_type(blobmsg_data(cur)) != BLOBMSG_TYPE_STRING) {
|
||||
ctx->handle_error(ctx, "Unexpected element type", cur);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = __json_process_type(call, cur, cmd, ARRAY_SIZE(cmd), &found);
|
||||
if (found)
|
||||
return ret;
|
||||
|
||||
name = blobmsg_data(blobmsg_data(cur));
|
||||
ret = cmd_process_strings(call, cur);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ctx->handle_command(ctx, name, blob_data(ctx->buf.head), call->vars);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int json_process_cmd(struct json_call *call, struct blob_attr *block)
|
||||
{
|
||||
struct json_script_ctx *ctx = call->ctx;
|
||||
struct blob_attr *cur;
|
||||
int rem;
|
||||
int ret;
|
||||
int i = 0;
|
||||
|
||||
if (blobmsg_type(block) != BLOBMSG_TYPE_ARRAY) {
|
||||
ctx->handle_error(ctx, "Unexpected element type", block);
|
||||
return -1;
|
||||
}
|
||||
|
||||
blobmsg_for_each_attr(cur, block, rem) {
|
||||
switch(blobmsg_type(cur)) {
|
||||
case BLOBMSG_TYPE_STRING:
|
||||
if (!i)
|
||||
return __json_process_cmd(call, block);
|
||||
default:
|
||||
ret = json_process_cmd(call, cur);
|
||||
if (ret < -1)
|
||||
return ret;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void json_script_run(struct json_script_ctx *ctx, const char *name,
|
||||
struct blob_attr *vars)
|
||||
{
|
||||
struct json_script_file *file;
|
||||
static unsigned int _seq = 0;
|
||||
struct json_call call = {
|
||||
.ctx = ctx,
|
||||
.vars = vars,
|
||||
.seq = ++_seq,
|
||||
};
|
||||
|
||||
/* overflow */
|
||||
if (!call.seq)
|
||||
call.seq = ++_seq;
|
||||
|
||||
file = json_script_get_file(ctx, name);
|
||||
if (!file)
|
||||
return;
|
||||
|
||||
__json_script_run(&call, file, NULL);
|
||||
}
|
||||
|
||||
static void __json_script_file_free(struct json_script_ctx *ctx, struct json_script_file *f)
|
||||
{
|
||||
struct json_script_file *next;
|
||||
|
||||
for (next = f->next; f; f = next, next = f->next)
|
||||
free(f);
|
||||
}
|
||||
|
||||
void
|
||||
json_script_free(struct json_script_ctx *ctx)
|
||||
{
|
||||
struct json_script_file *f, *next;
|
||||
|
||||
avl_remove_all_elements(&ctx->files, f, avl, next)
|
||||
__json_script_file_free(ctx, f);
|
||||
|
||||
blob_buf_free(&ctx->buf);
|
||||
}
|
||||
|
||||
static void
|
||||
__default_handle_error(struct json_script_ctx *ctx, const char *msg,
|
||||
struct blob_attr *context)
|
||||
{
|
||||
}
|
||||
|
||||
static const char *
|
||||
__default_handle_var(struct json_script_ctx *ctx, const char *name,
|
||||
struct blob_attr *vars)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
__default_handle_expr(struct json_script_ctx *ctx, const char *name,
|
||||
struct blob_attr *expr, struct blob_attr *vars)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
static struct json_script_file *
|
||||
__default_handle_file(struct json_script_ctx *ctx, const char *name)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void json_script_init(struct json_script_ctx *ctx)
|
||||
{
|
||||
avl_init(&ctx->files, avl_strcmp, false, NULL);
|
||||
|
||||
if (!ctx->handle_error)
|
||||
ctx->handle_error = __default_handle_error;
|
||||
|
||||
if (!ctx->handle_var)
|
||||
ctx->handle_var = __default_handle_var;
|
||||
|
||||
if (!ctx->handle_expr)
|
||||
ctx->handle_expr = __default_handle_expr;
|
||||
|
||||
if (!ctx->handle_file)
|
||||
ctx->handle_file = __default_handle_file;
|
||||
}
|
111
json_script.h
Normal file
111
json_script.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef __JSON_SCRIPT_H
|
||||
#define __JSON_SCRIPT_H
|
||||
|
||||
#include <libubox/avl.h>
|
||||
#include <libubox/blob.h>
|
||||
#include <libubox/blobmsg.h>
|
||||
#include <libubox/utils.h>
|
||||
|
||||
struct json_script_file;
|
||||
|
||||
struct json_script_ctx {
|
||||
struct avl_tree files;
|
||||
struct blob_buf buf;
|
||||
|
||||
uint32_t run_seq;
|
||||
|
||||
/*
|
||||
* handle_command: handle a command that was not recognized by the
|
||||
* json_script core (required)
|
||||
*
|
||||
* @cmd: blobmsg container of the processed command
|
||||
* @vars: blobmsg container of current run variables
|
||||
*/
|
||||
void (*handle_command)(struct json_script_ctx *ctx, const char *name,
|
||||
struct blob_attr *cmd, struct blob_attr *vars);
|
||||
|
||||
/*
|
||||
* handle_expr: handle an expression that was not recognized by the
|
||||
* json_script core (optional)
|
||||
*
|
||||
* @expr: blobmsg container of the processed expression
|
||||
* @vars: blobmsg container of current runtime variables
|
||||
*/
|
||||
int (*handle_expr)(struct json_script_ctx *ctx, const char *name,
|
||||
struct blob_attr *expr, struct blob_attr *vars);
|
||||
|
||||
/*
|
||||
* handle_var - look up a variable that's not part of the runtime
|
||||
* variable set (optional)
|
||||
*/
|
||||
const char *(*handle_var)(struct json_script_ctx *ctx, const char *name,
|
||||
struct blob_attr *vars);
|
||||
|
||||
/*
|
||||
* handle_file - load a file by filename (optional)
|
||||
*
|
||||
* in case of wildcards, it can return a chain of json_script files
|
||||
* linked via the ::next pointer. Only the first json_script file is
|
||||
* added to the tree.
|
||||
*/
|
||||
struct json_script_file *(*handle_file)(struct json_script_ctx *ctx,
|
||||
const char *name);
|
||||
|
||||
/*
|
||||
* handle_error - handle a processing error in a command or expression
|
||||
* (optional)
|
||||
*
|
||||
* @msg: error message
|
||||
* @context: source file context of the error (blobmsg container)
|
||||
*/
|
||||
void (*handle_error)(struct json_script_ctx *ctx, const char *msg,
|
||||
struct blob_attr *context);
|
||||
};
|
||||
|
||||
struct json_script_file {
|
||||
struct avl_node avl;
|
||||
struct json_script_file *next;
|
||||
|
||||
unsigned int seq;
|
||||
struct blob_attr data[];
|
||||
};
|
||||
|
||||
void json_script_init(struct json_script_ctx *ctx);
|
||||
void json_script_free(struct json_script_ctx *ctx);
|
||||
|
||||
/*
|
||||
* json_script_run - run a json script with a set of runtime variables
|
||||
*
|
||||
* @filename: initial filename to run
|
||||
* @vars: blobmsg container of the current runtime variables
|
||||
*/
|
||||
void json_script_run(struct json_script_ctx *ctx, const char *filename,
|
||||
struct blob_attr *vars);
|
||||
|
||||
struct json_script_file *
|
||||
json_script_file_from_blobmsg(const char *name, void *data, int len);
|
||||
|
||||
/*
|
||||
* json_script_find_var - helper function to find a runtime variable from
|
||||
* the list passed by json_script user.
|
||||
* It is intended to be used by the .handle_var callback
|
||||
*/
|
||||
const char *json_script_find_var(struct json_script_ctx *ctx, struct blob_attr *vars,
|
||||
const char *name);
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue