(libretro-db/query.c) Update this - should fix crash
This commit is contained in:
parent
3960897e74
commit
031190ed14
|
@ -8,57 +8,19 @@
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "libretrodb.h"
|
|
||||||
|
|
||||||
#include "rmsgpack_dom.h"
|
|
||||||
#include <compat/fnmatch.h>
|
#include <compat/fnmatch.h>
|
||||||
#include <compat/strl.h>
|
#include <compat/strl.h>
|
||||||
|
|
||||||
|
#include "libretrodb.h"
|
||||||
|
#include "query.h"
|
||||||
|
#include "rmsgpack_dom.h"
|
||||||
|
|
||||||
#define MAX_ERROR_LEN 256
|
#define MAX_ERROR_LEN 256
|
||||||
#define QUERY_MAX_ARGS 50
|
#undef MAX_ARGS
|
||||||
|
#define MAX_ARGS 50
|
||||||
|
|
||||||
static char tmp_error_buff [MAX_ERROR_LEN] = {0};
|
static char tmp_error_buff [MAX_ERROR_LEN] = {0};
|
||||||
|
|
||||||
enum argument_type
|
|
||||||
{
|
|
||||||
AT_FUNCTION,
|
|
||||||
AT_VALUE
|
|
||||||
};
|
|
||||||
|
|
||||||
struct argument;
|
|
||||||
|
|
||||||
typedef struct rmsgpack_dom_value (*rarch_query_func)(struct rmsgpack_dom_value input,
|
|
||||||
unsigned argc, const struct argument *argv);
|
|
||||||
|
|
||||||
struct invocation
|
|
||||||
{
|
|
||||||
rarch_query_func func;
|
|
||||||
unsigned argc;
|
|
||||||
struct argument *argv;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct argument
|
|
||||||
{
|
|
||||||
enum argument_type type;
|
|
||||||
union
|
|
||||||
{
|
|
||||||
struct rmsgpack_dom_value value;
|
|
||||||
struct invocation invocation;
|
|
||||||
} arg;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct query
|
|
||||||
{
|
|
||||||
unsigned ref_count;
|
|
||||||
struct invocation root;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct registered_func
|
|
||||||
{
|
|
||||||
const char *name;
|
|
||||||
rarch_query_func func;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct buffer
|
struct buffer
|
||||||
{
|
{
|
||||||
const char *data;
|
const char *data;
|
||||||
|
@ -66,13 +28,11 @@ struct buffer
|
||||||
off_t offset;
|
off_t offset;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Forward declarations */
|
|
||||||
struct argument;
|
|
||||||
|
|
||||||
/* Errors */
|
/* Errors */
|
||||||
static void raise_too_many_arguments(const char **error)
|
static void raise_too_many_arguments(const char **error)
|
||||||
{
|
{
|
||||||
strlcpy(tmp_error_buff, "Too many arguments in function call.", MAX_ERROR_LEN);
|
strlcpy(tmp_error_buff,
|
||||||
|
"Too many arguments in function call.", sizeof(tmp_error_buff));
|
||||||
*error = tmp_error_buff;
|
*error = tmp_error_buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +48,7 @@ static void raise_expected_number(off_t where, const char **error)
|
||||||
*error = tmp_error_buff;
|
*error = tmp_error_buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raise_expected_string(off_t where, const char **error)
|
static void raise_expected_string(off_t where, const char ** error)
|
||||||
{
|
{
|
||||||
snprintf(tmp_error_buff, MAX_ERROR_LEN,
|
snprintf(tmp_error_buff, MAX_ERROR_LEN,
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -100,7 +60,7 @@ static void raise_expected_string(off_t where, const char **error)
|
||||||
*error = tmp_error_buff;
|
*error = tmp_error_buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raise_unexpected_eof(off_t where, const char **error)
|
static void raise_unexpected_eof(off_t where, const char ** error)
|
||||||
{
|
{
|
||||||
snprintf(tmp_error_buff, MAX_ERROR_LEN,
|
snprintf(tmp_error_buff, MAX_ERROR_LEN,
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -115,12 +75,12 @@ static void raise_unexpected_eof(off_t where, const char **error)
|
||||||
|
|
||||||
static void raise_enomem(const char **error)
|
static void raise_enomem(const char **error)
|
||||||
{
|
{
|
||||||
strlcpy(tmp_error_buff, "Out of memory", MAX_ERROR_LEN);
|
strlcpy(tmp_error_buff, "Out of memory", sizeof(tmp_error_buff));
|
||||||
*error = tmp_error_buff;
|
*error = tmp_error_buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void raise_unknown_function(off_t where, const char *name,
|
static void raise_unknown_function(off_t where, const char *name,
|
||||||
size_t len, const char **error)
|
ssize_t len, const char **error)
|
||||||
{
|
{
|
||||||
int n = snprintf(tmp_error_buff, MAX_ERROR_LEN,
|
int n = snprintf(tmp_error_buff, MAX_ERROR_LEN,
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -134,7 +94,7 @@ static void raise_unknown_function(off_t where, const char *name,
|
||||||
if (len < (MAX_ERROR_LEN - n - 3))
|
if (len < (MAX_ERROR_LEN - n - 3))
|
||||||
strncpy(tmp_error_buff + n, name, len);
|
strncpy(tmp_error_buff + n, name, len);
|
||||||
|
|
||||||
strlcpy(tmp_error_buff + n + len, "'", sizeof(tmp_error_buff));
|
strcpy(tmp_error_buff + n + len, "'");
|
||||||
*error = tmp_error_buff;
|
*error = tmp_error_buff;
|
||||||
}
|
}
|
||||||
static void raise_expected_eof(off_t where, char found, const char **error)
|
static void raise_expected_eof(off_t where, char found, const char **error)
|
||||||
|
@ -164,20 +124,63 @@ static void raise_unexpected_char(off_t where, char expected, char found,
|
||||||
*error = tmp_error_buff;
|
*error = tmp_error_buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum argument_type
|
||||||
|
{
|
||||||
|
AT_FUNCTION,
|
||||||
|
AT_VALUE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct argument;
|
||||||
|
|
||||||
|
typedef struct rmsgpack_dom_value (*rarch_query_func)(
|
||||||
|
struct rmsgpack_dom_value input,
|
||||||
|
unsigned argc,
|
||||||
|
const struct argument *argv
|
||||||
|
);
|
||||||
|
|
||||||
|
struct invocation
|
||||||
|
{
|
||||||
|
rarch_query_func func;
|
||||||
|
unsigned argc;
|
||||||
|
struct argument *argv;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct argument
|
||||||
|
{
|
||||||
|
enum argument_type type;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct rmsgpack_dom_value value;
|
||||||
|
struct invocation invocation;
|
||||||
|
} a;
|
||||||
|
};
|
||||||
|
|
||||||
static void argument_free(struct argument *arg)
|
static void argument_free(struct argument *arg)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
if (arg->type != AT_FUNCTION)
|
if (arg->type != AT_FUNCTION)
|
||||||
{
|
{
|
||||||
rmsgpack_dom_value_free(&arg->arg.value);
|
rmsgpack_dom_value_free(&arg->a.value);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < arg->arg.invocation.argc; i++)
|
for (i = 0; i < arg->a.invocation.argc; i++)
|
||||||
argument_free(&arg->arg.invocation.argv[i]);
|
argument_free(&arg->a.invocation.argv[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct query
|
||||||
|
{
|
||||||
|
unsigned ref_count;
|
||||||
|
struct invocation root;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct registered_func
|
||||||
|
{
|
||||||
|
const char *name;
|
||||||
|
rarch_query_func func;
|
||||||
|
};
|
||||||
|
|
||||||
static struct buffer parse_argument(struct buffer buff, struct argument *arg,
|
static struct buffer parse_argument(struct buffer buff, struct argument *arg,
|
||||||
const char **error);
|
const char **error);
|
||||||
|
|
||||||
|
@ -185,6 +188,7 @@ static struct rmsgpack_dom_value is_true(struct rmsgpack_dom_value input,
|
||||||
unsigned argc, const struct argument *argv)
|
unsigned argc, const struct argument *argv)
|
||||||
{
|
{
|
||||||
struct rmsgpack_dom_value res;
|
struct rmsgpack_dom_value res;
|
||||||
|
memset(&res, 0, sizeof(res));
|
||||||
|
|
||||||
res.type = RDT_BOOL;
|
res.type = RDT_BOOL;
|
||||||
res.val.bool_ = 0;
|
res.val.bool_ = 0;
|
||||||
|
@ -198,10 +202,11 @@ static struct rmsgpack_dom_value is_true(struct rmsgpack_dom_value input,
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rmsgpack_dom_value equals(struct rmsgpack_dom_value input,
|
static struct rmsgpack_dom_value equals(struct rmsgpack_dom_value input,
|
||||||
unsigned argc, const struct argument *argv)
|
unsigned argc, const struct argument * argv)
|
||||||
{
|
{
|
||||||
struct rmsgpack_dom_value res;
|
|
||||||
struct argument arg;
|
struct argument arg;
|
||||||
|
struct rmsgpack_dom_value res;
|
||||||
|
memset(&res, 0, sizeof(res));
|
||||||
|
|
||||||
res.type = RDT_BOOL;
|
res.type = RDT_BOOL;
|
||||||
|
|
||||||
|
@ -215,22 +220,23 @@ static struct rmsgpack_dom_value equals(struct rmsgpack_dom_value input,
|
||||||
res.val.bool_ = 0;
|
res.val.bool_ = 0;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (input.type == RDT_UINT && arg.arg.value.type == RDT_INT)
|
if (input.type == RDT_UINT && arg.a.value.type == RDT_INT)
|
||||||
{
|
{
|
||||||
arg.arg.value.type = RDT_UINT;
|
arg.a.value.type = RDT_UINT;
|
||||||
arg.arg.value.val.uint_ = arg.arg.value.val.int_;
|
arg.a.value.val.uint_ = arg.a.value.val.int_;
|
||||||
}
|
}
|
||||||
res.val.bool_ = (rmsgpack_dom_value_cmp(&input, &arg.arg.value) == 0);
|
res.val.bool_ = (rmsgpack_dom_value_cmp(&input, &arg.a.value) == 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rmsgpack_dom_value operator_or(struct rmsgpack_dom_value input,
|
static struct rmsgpack_dom_value operator_or(struct rmsgpack_dom_value input,
|
||||||
unsigned argc, const struct argument *argv)
|
unsigned argc, const struct argument * argv)
|
||||||
{
|
{
|
||||||
struct rmsgpack_dom_value res;
|
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
struct rmsgpack_dom_value res;
|
||||||
|
memset(&res, 0, sizeof(res));
|
||||||
|
|
||||||
res.type = RDT_BOOL;
|
res.type = RDT_BOOL;
|
||||||
res.val.bool_ = 0;
|
res.val.bool_ = 0;
|
||||||
|
@ -241,9 +247,9 @@ static struct rmsgpack_dom_value operator_or(struct rmsgpack_dom_value input,
|
||||||
res = equals(input, 1, &argv[i]);
|
res = equals(input, 1, &argv[i]);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res = is_true(argv[i].arg.invocation.func(input,
|
res = is_true(argv[i].a.invocation.func(input,
|
||||||
argv[i].arg.invocation.argc,
|
argv[i].a.invocation.argc,
|
||||||
argv[i].arg.invocation.argv
|
argv[i].a.invocation.argv
|
||||||
), 0, NULL);
|
), 0, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -255,11 +261,13 @@ static struct rmsgpack_dom_value operator_or(struct rmsgpack_dom_value input,
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rmsgpack_dom_value between(struct rmsgpack_dom_value input,
|
static struct rmsgpack_dom_value between(struct rmsgpack_dom_value input,
|
||||||
unsigned argc, const struct argument *argv)
|
unsigned argc, const struct argument * argv)
|
||||||
{
|
{
|
||||||
struct rmsgpack_dom_value res;
|
struct rmsgpack_dom_value res;
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
|
|
||||||
|
memset(&res, 0, sizeof(res));
|
||||||
|
|
||||||
res.type = RDT_BOOL;
|
res.type = RDT_BOOL;
|
||||||
res.val.bool_ = 0;
|
res.val.bool_ = 0;
|
||||||
|
|
||||||
|
@ -269,16 +277,16 @@ static struct rmsgpack_dom_value between(struct rmsgpack_dom_value input,
|
||||||
return res;
|
return res;
|
||||||
if (argv[0].type != AT_VALUE || argv[1].type != AT_VALUE)
|
if (argv[0].type != AT_VALUE || argv[1].type != AT_VALUE)
|
||||||
return res;
|
return res;
|
||||||
if (argv[0].arg.value.type != RDT_INT || argv[1].arg.value.type != RDT_INT)
|
if (argv[0].a.value.type != RDT_INT || argv[1].a.value.type != RDT_INT)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
switch (input.type)
|
switch (input.type)
|
||||||
{
|
{
|
||||||
case RDT_INT:
|
case RDT_INT:
|
||||||
res.val.bool_ = (input.val.int_ >= argv[0].arg.value.val.int_) && (input.val.int_ <= argv[1].arg.value.val.int_);
|
res.val.bool_ = ((input.val.int_ >= argv[0].a.value.val.int_) && (input.val.int_ <= argv[1].a.value.val.int_));
|
||||||
break;
|
break;
|
||||||
case RDT_UINT:
|
case RDT_UINT:
|
||||||
res.val.bool_ = (input.val.int_ >= argv[0].arg.value.val.uint_) && (input.val.int_ <= argv[1].arg.value.val.int_);
|
res.val.bool_ = (((unsigned)input.val.int_ >= argv[0].a.value.val.uint_) && (input.val.int_ <= argv[1].a.value.val.int_));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return res;
|
return res;
|
||||||
|
@ -288,10 +296,11 @@ static struct rmsgpack_dom_value between(struct rmsgpack_dom_value input,
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rmsgpack_dom_value operator_and(struct rmsgpack_dom_value input,
|
static struct rmsgpack_dom_value operator_and(struct rmsgpack_dom_value input,
|
||||||
unsigned argc, const struct argument *argv)
|
unsigned argc, const struct argument * argv)
|
||||||
{
|
{
|
||||||
struct rmsgpack_dom_value res;
|
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
struct rmsgpack_dom_value res;
|
||||||
|
memset(&res, 0, sizeof(res));
|
||||||
|
|
||||||
res.type = RDT_BOOL;
|
res.type = RDT_BOOL;
|
||||||
res.val.bool_ = 0;
|
res.val.bool_ = 0;
|
||||||
|
@ -303,9 +312,9 @@ static struct rmsgpack_dom_value operator_and(struct rmsgpack_dom_value input,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res = is_true(
|
res = is_true(
|
||||||
argv[i].arg.invocation.func(input,
|
argv[i].a.invocation.func(input,
|
||||||
argv[i].arg.invocation.argc,
|
argv[i].a.invocation.argc,
|
||||||
argv[i].arg.invocation.argv
|
argv[i].a.invocation.argv
|
||||||
),
|
),
|
||||||
0, NULL);
|
0, NULL);
|
||||||
}
|
}
|
||||||
|
@ -317,10 +326,11 @@ static struct rmsgpack_dom_value operator_and(struct rmsgpack_dom_value input,
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct rmsgpack_dom_value q_glob(struct rmsgpack_dom_value input,
|
static struct rmsgpack_dom_value q_glob(struct rmsgpack_dom_value input,
|
||||||
unsigned argc, const struct argument *argv)
|
unsigned argc, const struct argument * argv)
|
||||||
{
|
{
|
||||||
struct rmsgpack_dom_value res;
|
struct rmsgpack_dom_value res;
|
||||||
unsigned i = 0;
|
unsigned i = 0;
|
||||||
|
memset(&res, 0, sizeof(res));
|
||||||
|
|
||||||
res.type = RDT_BOOL;
|
res.type = RDT_BOOL;
|
||||||
res.val.bool_ = 0;
|
res.val.bool_ = 0;
|
||||||
|
@ -329,12 +339,12 @@ static struct rmsgpack_dom_value q_glob(struct rmsgpack_dom_value input,
|
||||||
|
|
||||||
if (argc != 1)
|
if (argc != 1)
|
||||||
return res;
|
return res;
|
||||||
if (argv[0].type != AT_VALUE || argv[0].arg.value.type != RDT_STRING)
|
if (argv[0].type != AT_VALUE || argv[0].a.value.type != RDT_STRING)
|
||||||
return res;
|
return res;
|
||||||
if (input.type != RDT_STRING)
|
if (input.type != RDT_STRING)
|
||||||
return res;
|
return res;
|
||||||
res.val.bool_ = rl_fnmatch(
|
res.val.bool_ = rl_fnmatch(
|
||||||
argv[0].arg.value.val.string.buff,
|
argv[0].a.value.val.string.buff,
|
||||||
input.val.string.buff,
|
input.val.string.buff,
|
||||||
0
|
0
|
||||||
) == 0;
|
) == 0;
|
||||||
|
@ -345,10 +355,11 @@ static struct rmsgpack_dom_value all_map(struct rmsgpack_dom_value input,
|
||||||
unsigned argc, const struct argument *argv)
|
unsigned argc, const struct argument *argv)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct rmsgpack_dom_value res;
|
|
||||||
struct argument arg;
|
struct argument arg;
|
||||||
|
struct rmsgpack_dom_value res;
|
||||||
struct rmsgpack_dom_value nil_value;
|
struct rmsgpack_dom_value nil_value;
|
||||||
struct rmsgpack_dom_value *value = NULL;
|
struct rmsgpack_dom_value *value = NULL;
|
||||||
|
memset(&res, 0, sizeof(res));
|
||||||
|
|
||||||
nil_value.type = RDT_NULL;
|
nil_value.type = RDT_NULL;
|
||||||
res.type = RDT_BOOL;
|
res.type = RDT_BOOL;
|
||||||
|
@ -369,9 +380,9 @@ static struct rmsgpack_dom_value all_map(struct rmsgpack_dom_value input,
|
||||||
if (arg.type != AT_VALUE)
|
if (arg.type != AT_VALUE)
|
||||||
{
|
{
|
||||||
res.val.bool_ = 0;
|
res.val.bool_ = 0;
|
||||||
return res;
|
goto clean;
|
||||||
}
|
}
|
||||||
value = rmsgpack_dom_value_map_value(&input, &arg.arg.value);
|
value = rmsgpack_dom_value_map_value(&input, &arg.a.value);
|
||||||
if (!value) /* All missing fields are nil */
|
if (!value) /* All missing fields are nil */
|
||||||
value = &nil_value;
|
value = &nil_value;
|
||||||
arg = argv[i + 1];
|
arg = argv[i + 1];
|
||||||
|
@ -379,17 +390,17 @@ static struct rmsgpack_dom_value all_map(struct rmsgpack_dom_value input,
|
||||||
res = equals(*value, 1, &arg);
|
res = equals(*value, 1, &arg);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
res = is_true(arg.arg.invocation.func(
|
res = is_true(arg.a.invocation.func(
|
||||||
*value,
|
*value,
|
||||||
arg.arg.invocation.argc,
|
arg.a.invocation.argc,
|
||||||
arg.arg.invocation.argv
|
arg.a.invocation.argv
|
||||||
), 0, NULL);
|
), 0, NULL);
|
||||||
value = NULL;
|
value = NULL;
|
||||||
}
|
}
|
||||||
if (!res.val.bool_)
|
if (!res.val.bool_)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
clean:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,14 +415,14 @@ struct registered_func registered_functions[100] = {
|
||||||
|
|
||||||
static struct buffer chomp(struct buffer buff)
|
static struct buffer chomp(struct buffer buff)
|
||||||
{
|
{
|
||||||
for (; buff.offset < buff.len && isspace(buff.data[buff.offset]); buff.offset++);
|
for (; (unsigned)buff.offset < buff.len && isspace((int)buff.data[buff.offset]); buff.offset++);
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct buffer expect_char(struct buffer buff,
|
static struct buffer expect_char(struct buffer buff,
|
||||||
char c, const char **error)
|
char c, const char ** error)
|
||||||
{
|
{
|
||||||
if (buff.offset >= buff.len)
|
if ((unsigned)buff.offset >= buff.len)
|
||||||
raise_unexpected_eof(buff.offset, error);
|
raise_unexpected_eof(buff.offset, error);
|
||||||
else if (buff.data[buff.offset] != c)
|
else if (buff.data[buff.offset] != c)
|
||||||
raise_unexpected_char(
|
raise_unexpected_char(
|
||||||
|
@ -421,15 +432,15 @@ static struct buffer expect_char(struct buffer buff,
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct buffer expect_eof(struct buffer buff, const char **error)
|
static struct buffer expect_eof(struct buffer buff, const char ** error)
|
||||||
{
|
{
|
||||||
buff = chomp(buff);
|
buff = chomp(buff);
|
||||||
if (buff.offset < buff.len)
|
if ((unsigned)buff.offset < buff.len)
|
||||||
raise_expected_eof(buff.offset, buff.data[buff.offset], error);
|
raise_expected_eof(buff.offset, buff.data[buff.offset], error);
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int peek(struct buffer buff, const char *data)
|
static int peek(struct buffer buff, const char * data)
|
||||||
{
|
{
|
||||||
size_t remain = buff.len - buff.offset;
|
size_t remain = buff.len - buff.offset;
|
||||||
|
|
||||||
|
@ -442,7 +453,7 @@ static int peek(struct buffer buff, const char *data)
|
||||||
|
|
||||||
static int is_eot(struct buffer buff)
|
static int is_eot(struct buffer buff)
|
||||||
{
|
{
|
||||||
return (buff.offset >= buff.len);
|
return ((unsigned)buff.offset >= buff.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void peek_char(struct buffer buff, char *c, const char **error)
|
static void peek_char(struct buffer buff, char *c, const char **error)
|
||||||
|
@ -456,8 +467,8 @@ static void peek_char(struct buffer buff, char *c, const char **error)
|
||||||
*c = buff.data[buff.offset];
|
*c = buff.data[buff.offset];
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct buffer get_char(struct buffer buff, char *c,
|
static struct buffer get_char(struct buffer buff, char * c,
|
||||||
const char **error)
|
const char ** error)
|
||||||
{
|
{
|
||||||
if (is_eot(buff))
|
if (is_eot(buff))
|
||||||
{
|
{
|
||||||
|
@ -472,9 +483,10 @@ static struct buffer get_char(struct buffer buff, char *c,
|
||||||
static struct buffer parse_string(struct buffer buff,
|
static struct buffer parse_string(struct buffer buff,
|
||||||
struct rmsgpack_dom_value *value, const char **error)
|
struct rmsgpack_dom_value *value, const char **error)
|
||||||
{
|
{
|
||||||
const char *str_start;
|
const char * str_start = NULL;
|
||||||
char terminator = '\0';
|
char terminator = '\0';
|
||||||
char c = '\0';
|
char c = '\0';
|
||||||
|
int is_binstr = 0;
|
||||||
|
|
||||||
(void)c;
|
(void)c;
|
||||||
|
|
||||||
|
@ -483,6 +495,12 @@ static struct buffer parse_string(struct buffer buff,
|
||||||
if (*error)
|
if (*error)
|
||||||
return buff;
|
return buff;
|
||||||
|
|
||||||
|
if (terminator == 'b')
|
||||||
|
{
|
||||||
|
is_binstr = 1;
|
||||||
|
buff = get_char(buff, &terminator, error);
|
||||||
|
}
|
||||||
|
|
||||||
if (terminator != '"' && terminator != '\'')
|
if (terminator != '"' && terminator != '\'')
|
||||||
{
|
{
|
||||||
buff.offset--;
|
buff.offset--;
|
||||||
|
@ -501,18 +519,44 @@ static struct buffer parse_string(struct buffer buff,
|
||||||
|
|
||||||
if (!*error)
|
if (!*error)
|
||||||
{
|
{
|
||||||
value->type = RDT_STRING;
|
size_t count;
|
||||||
|
value->type = is_binstr ? RDT_BINARY : RDT_STRING;
|
||||||
value->val.string.len = (buff.data + buff.offset) - str_start - 1;
|
value->val.string.len = (buff.data + buff.offset) - str_start - 1;
|
||||||
value->val.string.buff = (char*)calloc(value->val.string.len + 1, sizeof(char));
|
|
||||||
|
count = is_binstr ? (value->val.string.len + 1) / 2 : (value->val.string.len + 1);
|
||||||
|
value->val.string.buff = (char*)calloc(count, sizeof(char));
|
||||||
|
|
||||||
if (!value->val.string.buff)
|
if (!value->val.string.buff)
|
||||||
raise_enomem(error);
|
raise_enomem(error);
|
||||||
|
else if (is_binstr)
|
||||||
|
{
|
||||||
|
unsigned i;
|
||||||
|
const char *tok = str_start;
|
||||||
|
unsigned j = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < value->val.string.len; i += 2)
|
||||||
|
{
|
||||||
|
uint8_t hi, lo;
|
||||||
|
char hic = tok[i];
|
||||||
|
char loc = tok[i + 1];
|
||||||
|
|
||||||
|
if (hic <= '9')
|
||||||
|
hi = hic - '0';
|
||||||
else
|
else
|
||||||
memcpy(
|
hi = (hic - 'A') + 10;
|
||||||
value->val.string.buff,
|
|
||||||
str_start,
|
if (loc <= '9')
|
||||||
value->val.string.len
|
lo = loc - '0';
|
||||||
);
|
else
|
||||||
|
lo = (loc - 'A') + 10;
|
||||||
|
|
||||||
|
value->val.string.buff[j++] = hi * 16 + lo;
|
||||||
|
}
|
||||||
|
|
||||||
|
value->val.string.len = j;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
memcpy(value->val.string.buff, str_start, value->val.string.len);
|
||||||
}
|
}
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
@ -532,7 +576,7 @@ static struct buffer parse_integer(struct buffer buff,
|
||||||
raise_expected_number(buff.offset, error);
|
raise_expected_number(buff.offset, error);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (isdigit(buff.data[buff.offset]))
|
while (isdigit((int)buff.data[buff.offset]))
|
||||||
buff.offset++;
|
buff.offset++;
|
||||||
}
|
}
|
||||||
return buff;
|
return buff;
|
||||||
|
@ -560,9 +604,9 @@ static struct buffer parse_value(struct buffer buff,
|
||||||
value->type = RDT_BOOL;
|
value->type = RDT_BOOL;
|
||||||
value->val.bool_ = 0;
|
value->val.bool_ = 0;
|
||||||
}
|
}
|
||||||
else if (peek(buff, "\"") || peek(buff, "'"))
|
else if (peek(buff, "b") || peek(buff, "\"") || peek(buff, "'"))
|
||||||
buff = parse_string(buff, value, error);
|
buff = parse_string(buff, value, error);
|
||||||
else if (isdigit(buff.data[buff.offset]))
|
else if (isdigit((int)buff.data[buff.offset]))
|
||||||
buff = parse_integer(buff, value, error);
|
buff = parse_integer(buff, value, error);
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
@ -583,7 +627,9 @@ static struct buffer get_ident(struct buffer buff,
|
||||||
*len = 0;
|
*len = 0;
|
||||||
peek_char(buff, &c, error);
|
peek_char(buff, &c, error);
|
||||||
|
|
||||||
if (*error || !isalpha(c))
|
if (*error)
|
||||||
|
goto clean;
|
||||||
|
if (!isalpha((int)c))
|
||||||
return buff;
|
return buff;
|
||||||
|
|
||||||
buff.offset++;
|
buff.offset++;
|
||||||
|
@ -592,36 +638,37 @@ static struct buffer get_ident(struct buffer buff,
|
||||||
|
|
||||||
while (!*error)
|
while (!*error)
|
||||||
{
|
{
|
||||||
if (!(isalpha(c) || isdigit(c) || c == '_'))
|
if (!(isalpha((int)c) || isdigit((int)c) || c == '_'))
|
||||||
break;
|
break;
|
||||||
buff.offset++;
|
buff.offset++;
|
||||||
*len = *len + 1;
|
*len = *len + 1;
|
||||||
peek_char(buff, &c, error);
|
peek_char(buff, &c, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
clean:
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct buffer parse_method_call(struct buffer buff,
|
static struct buffer parse_method_call(struct buffer buff,
|
||||||
struct invocation *invocation, const char **error)
|
struct invocation *invocation, const char **error)
|
||||||
{
|
{
|
||||||
const char *func_name;
|
|
||||||
size_t func_name_len;
|
size_t func_name_len;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
struct argument args[QUERY_MAX_ARGS];
|
struct argument args[MAX_ARGS];
|
||||||
unsigned argi = 0;
|
unsigned argi = 0;
|
||||||
|
const char *func_name = NULL;
|
||||||
struct registered_func *rf = registered_functions;
|
struct registered_func *rf = registered_functions;
|
||||||
|
|
||||||
invocation->func = NULL;
|
invocation->func = NULL;
|
||||||
|
|
||||||
buff = get_ident(buff, &func_name, &func_name_len, error);
|
buff = get_ident(buff, &func_name, &func_name_len, error);
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
buff = chomp(buff);
|
buff = chomp(buff);
|
||||||
buff = expect_char(buff, '(', error);
|
buff = expect_char(buff, '(', error);
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
while (rf->name)
|
while (rf->name)
|
||||||
{
|
{
|
||||||
|
@ -637,22 +684,22 @@ static struct buffer parse_method_call(struct buffer buff,
|
||||||
{
|
{
|
||||||
raise_unknown_function(buff.offset, func_name,
|
raise_unknown_function(buff.offset, func_name,
|
||||||
func_name_len, error);
|
func_name_len, error);
|
||||||
goto error;
|
goto clean;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff = chomp(buff);
|
buff = chomp(buff);
|
||||||
while (!peek(buff, ")"))
|
while (!peek(buff, ")"))
|
||||||
{
|
{
|
||||||
if (argi >= QUERY_MAX_ARGS)
|
if (argi >= MAX_ARGS)
|
||||||
{
|
{
|
||||||
raise_too_many_arguments(error);
|
raise_too_many_arguments(error);
|
||||||
goto error;
|
goto clean;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff = parse_argument(buff, &args[argi], error);
|
buff = parse_argument(buff, &args[argi], error);
|
||||||
|
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
argi++;
|
argi++;
|
||||||
buff = chomp(buff);
|
buff = chomp(buff);
|
||||||
|
@ -668,83 +715,81 @@ static struct buffer parse_method_call(struct buffer buff,
|
||||||
buff = expect_char(buff, ')', error);
|
buff = expect_char(buff, ')', error);
|
||||||
|
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
invocation->argc = argi;
|
invocation->argc = argi;
|
||||||
invocation->argv = (struct argument*)
|
invocation->argv = (struct argument*)
|
||||||
malloc(sizeof(struct argument) *argi);
|
malloc(sizeof(struct argument) * argi);
|
||||||
|
|
||||||
if (!invocation->argv)
|
if (!invocation->argv)
|
||||||
{
|
{
|
||||||
raise_enomem(error);
|
raise_enomem(error);
|
||||||
goto error;
|
goto clean;
|
||||||
}
|
}
|
||||||
memcpy(invocation->argv, args,
|
memcpy(invocation->argv, args,
|
||||||
sizeof(struct argument) *argi);
|
sizeof(struct argument) * argi);
|
||||||
|
|
||||||
return buff;
|
goto success;
|
||||||
|
clean:
|
||||||
error:
|
|
||||||
for (i = 0; i < argi; i++)
|
for (i = 0; i < argi; i++)
|
||||||
argument_free(&args[i]);
|
argument_free(&args[i]);
|
||||||
|
success:
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct buffer parse_table(struct buffer buff,
|
static struct buffer parse_table(struct buffer buff,
|
||||||
struct invocation *invocation, const char **error)
|
struct invocation *invocation, const char **error)
|
||||||
{
|
{
|
||||||
struct argument args[QUERY_MAX_ARGS];
|
|
||||||
unsigned i;
|
unsigned i;
|
||||||
const char *ident_name;
|
|
||||||
size_t ident_len;
|
size_t ident_len;
|
||||||
|
struct argument args[MAX_ARGS];
|
||||||
|
const char *ident_name = NULL;
|
||||||
unsigned argi = 0;
|
unsigned argi = 0;
|
||||||
|
|
||||||
memset(args, 0, sizeof(struct argument) * QUERY_MAX_ARGS);
|
|
||||||
|
|
||||||
buff = chomp(buff);
|
buff = chomp(buff);
|
||||||
buff = expect_char(buff, '{', error);
|
buff = expect_char(buff, '{', error);
|
||||||
|
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
buff = chomp(buff);
|
buff = chomp(buff);
|
||||||
|
|
||||||
while (!peek(buff, "}"))
|
while (!peek(buff, "}"))
|
||||||
{
|
{
|
||||||
if (argi >= QUERY_MAX_ARGS)
|
if (argi >= MAX_ARGS)
|
||||||
{
|
{
|
||||||
raise_too_many_arguments(error);
|
raise_too_many_arguments(error);
|
||||||
goto error;
|
goto clean;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isalpha(buff.data[buff.offset]))
|
if (isalpha((int)buff.data[buff.offset]))
|
||||||
{
|
{
|
||||||
buff = get_ident(buff, &ident_name, &ident_len, error);
|
buff = get_ident(buff, &ident_name, &ident_len, error);
|
||||||
|
|
||||||
if (!*error)
|
if (!*error)
|
||||||
{
|
{
|
||||||
args[argi].arg.value.type = RDT_STRING;
|
args[argi].a.value.type = RDT_STRING;
|
||||||
args[argi].arg.value.val.string.len = ident_len;
|
args[argi].a.value.val.string.len = ident_len;
|
||||||
args[argi].arg.value.val.string.buff = (char*)calloc(
|
args[argi].a.value.val.string.buff = (char*)calloc(
|
||||||
ident_len + 1,
|
ident_len + 1,
|
||||||
sizeof(char)
|
sizeof(char)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!args[argi].arg.value.val.string.buff)
|
if (!args[argi].a.value.val.string.buff)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
strncpy(
|
strncpy(
|
||||||
args[argi].arg.value.val.string.buff,
|
args[argi].a.value.val.string.buff,
|
||||||
ident_name,
|
ident_name,
|
||||||
ident_len
|
ident_len
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
buff = parse_string(buff, &args[argi].arg.value, error);
|
buff = parse_string(buff, &args[argi].a.value, error);
|
||||||
|
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
args[argi].type = AT_VALUE;
|
args[argi].type = AT_VALUE;
|
||||||
buff = chomp(buff);
|
buff = chomp(buff);
|
||||||
|
@ -752,20 +797,20 @@ static struct buffer parse_table(struct buffer buff,
|
||||||
buff = expect_char(buff, ':', error);
|
buff = expect_char(buff, ':', error);
|
||||||
|
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
buff = chomp(buff);
|
buff = chomp(buff);
|
||||||
|
|
||||||
if (argi >= QUERY_MAX_ARGS)
|
if (argi >= MAX_ARGS)
|
||||||
{
|
{
|
||||||
raise_too_many_arguments(error);
|
raise_too_many_arguments(error);
|
||||||
goto error;
|
goto clean;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff = parse_argument(buff, &args[argi], error);
|
buff = parse_argument(buff, &args[argi], error);
|
||||||
|
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
argi++;
|
argi++;
|
||||||
buff = chomp(buff);
|
buff = chomp(buff);
|
||||||
buff = expect_char(buff, ',', error);
|
buff = expect_char(buff, ',', error);
|
||||||
|
@ -781,7 +826,7 @@ static struct buffer parse_table(struct buffer buff,
|
||||||
buff = expect_char(buff, '}', error);
|
buff = expect_char(buff, '}', error);
|
||||||
|
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
invocation->func = all_map;
|
invocation->func = all_map;
|
||||||
invocation->argc = argi;
|
invocation->argc = argi;
|
||||||
|
@ -791,16 +836,16 @@ static struct buffer parse_table(struct buffer buff,
|
||||||
if (!invocation->argv)
|
if (!invocation->argv)
|
||||||
{
|
{
|
||||||
raise_enomem(error);
|
raise_enomem(error);
|
||||||
goto error;
|
goto clean;
|
||||||
}
|
}
|
||||||
memcpy(invocation->argv, args,
|
memcpy(invocation->argv, args,
|
||||||
sizeof(struct argument) *argi);
|
sizeof(struct argument) * argi);
|
||||||
|
|
||||||
return buff;
|
goto success;
|
||||||
|
clean:
|
||||||
error:
|
|
||||||
for (i = 0; i < argi; i++)
|
for (i = 0; i < argi; i++)
|
||||||
argument_free(&args[i]);
|
argument_free(&args[i]);
|
||||||
|
success:
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -810,32 +855,31 @@ static struct buffer parse_argument(struct buffer buff,
|
||||||
buff = chomp(buff);
|
buff = chomp(buff);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isalpha(buff.data[buff.offset])
|
isalpha((int)buff.data[buff.offset])
|
||||||
&& !(
|
&& !(
|
||||||
peek(buff, "nil")
|
peek(buff, "nil")
|
||||||
|| peek(buff, "true")
|
|| peek(buff, "true")
|
||||||
|| peek(buff, "false")
|
|| peek(buff, "false")
|
||||||
|
|| peek(buff, "b\"") || peek(buff, "b'") /* bin string prefix*/
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
arg->type = AT_FUNCTION;
|
arg->type = AT_FUNCTION;
|
||||||
buff = parse_method_call(buff, &arg->arg.invocation, error);
|
buff = parse_method_call(buff, &arg->a.invocation, error);
|
||||||
}
|
}
|
||||||
else if (peek(buff, "{"))
|
else if (peek(buff, "{"))
|
||||||
{
|
{
|
||||||
arg->type = AT_FUNCTION;
|
arg->type = AT_FUNCTION;
|
||||||
buff = parse_table(buff, &arg->arg.invocation, error);
|
buff = parse_table(buff, &arg->a.invocation, error);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
arg->type = AT_VALUE;
|
arg->type = AT_VALUE;
|
||||||
buff = parse_value(buff, &arg->arg.value, error);
|
buff = parse_value(buff, &arg->a.value, error);
|
||||||
}
|
}
|
||||||
return buff;
|
return buff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void libretrodb_query_free(void *q)
|
void libretrodb_query_free(void *q)
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
@ -848,9 +892,9 @@ void libretrodb_query_free(void *q)
|
||||||
for (i = 0; i < real_q->root.argc; i++)
|
for (i = 0; i < real_q->root.argc; i++)
|
||||||
argument_free(&real_q->root.argv[i]);
|
argument_free(&real_q->root.argv[i]);
|
||||||
|
|
||||||
|
|
||||||
free(real_q->root.argv);
|
free(real_q->root.argv);
|
||||||
real_q->root.argv = NULL;
|
real_q->root.argv = NULL;
|
||||||
|
real_q->root.argc = 0;
|
||||||
free(real_q);
|
free(real_q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,11 +902,10 @@ void *libretrodb_query_compile(libretrodb_t *db,
|
||||||
const char *query, size_t buff_len, const char **error)
|
const char *query, size_t buff_len, const char **error)
|
||||||
{
|
{
|
||||||
struct buffer buff;
|
struct buffer buff;
|
||||||
struct query *q = (struct query*)calloc(1,
|
struct query *q = (struct query*)calloc(1, sizeof(*q));
|
||||||
sizeof(*q));
|
|
||||||
|
|
||||||
if (!q)
|
if (!q)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
q->ref_count = 1;
|
q->ref_count = 1;
|
||||||
buff.data = query;
|
buff.data = query;
|
||||||
|
@ -876,26 +919,25 @@ void *libretrodb_query_compile(libretrodb_t *db,
|
||||||
{
|
{
|
||||||
buff = parse_table(buff, &q->root, error);
|
buff = parse_table(buff, &q->root, error);
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
}
|
}
|
||||||
else if (isalpha(buff.data[buff.offset]))
|
else if (isalpha((int)buff.data[buff.offset]))
|
||||||
buff = parse_method_call(buff, &q->root, error);
|
buff = parse_method_call(buff, &q->root, error);
|
||||||
|
|
||||||
buff = expect_eof(buff, error);
|
buff = expect_eof(buff, error);
|
||||||
if (*error)
|
if (*error)
|
||||||
goto error;
|
goto clean;
|
||||||
|
|
||||||
if (!q->root.func)
|
if (!q->root.func)
|
||||||
{
|
{
|
||||||
raise_unexpected_eof(buff.offset, error);
|
raise_unexpected_eof(buff.offset, error);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
goto success;
|
||||||
return q;
|
clean:
|
||||||
|
|
||||||
error:
|
|
||||||
if (q)
|
if (q)
|
||||||
libretrodb_query_free(q);
|
libretrodb_query_free(q);
|
||||||
|
success:
|
||||||
return q;
|
return q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -913,3 +955,4 @@ int libretrodb_query_filter(libretrodb_query_t *q,
|
||||||
struct rmsgpack_dom_value res = inv.func(*v, inv.argc, inv.argv);
|
struct rmsgpack_dom_value res = inv.func(*v, inv.argc, inv.argv);
|
||||||
return (res.type == RDT_BOOL && res.val.bool_);
|
return (res.type == RDT_BOOL && res.val.bool_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue