mirror of
https://github.com/libretro/RetroArch
synced 2025-01-30 21:32:45 +00:00
(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 <string.h>
|
||||
|
||||
#include "libretrodb.h"
|
||||
|
||||
#include "rmsgpack_dom.h"
|
||||
#include <compat/fnmatch.h>
|
||||
#include <compat/strl.h>
|
||||
|
||||
#include "libretrodb.h"
|
||||
#include "query.h"
|
||||
#include "rmsgpack_dom.h"
|
||||
|
||||
#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};
|
||||
|
||||
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
|
||||
{
|
||||
const char *data;
|
||||
@ -66,13 +28,11 @@ struct buffer
|
||||
off_t offset;
|
||||
};
|
||||
|
||||
/* Forward declarations */
|
||||
struct argument;
|
||||
|
||||
/* Errors */
|
||||
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;
|
||||
}
|
||||
|
||||
@ -88,7 +48,7 @@ static void raise_expected_number(off_t where, const char **error)
|
||||
*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,
|
||||
#ifdef _WIN32
|
||||
@ -100,7 +60,7 @@ static void raise_expected_string(off_t where, const char **error)
|
||||
*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,
|
||||
#ifdef _WIN32
|
||||
@ -115,12 +75,12 @@ static void raise_unexpected_eof(off_t where, 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;
|
||||
}
|
||||
|
||||
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,
|
||||
#ifdef _WIN32
|
||||
@ -134,7 +94,7 @@ static void raise_unknown_function(off_t where, const char *name,
|
||||
if (len < (MAX_ERROR_LEN - n - 3))
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if (arg->type != AT_FUNCTION)
|
||||
{
|
||||
rmsgpack_dom_value_free(&arg->arg.value);
|
||||
rmsgpack_dom_value_free(&arg->a.value);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < arg->arg.invocation.argc; i++)
|
||||
argument_free(&arg->arg.invocation.argv[i]);
|
||||
for (i = 0; i < arg->a.invocation.argc; 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,
|
||||
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)
|
||||
{
|
||||
struct rmsgpack_dom_value res;
|
||||
memset(&res, 0, sizeof(res));
|
||||
|
||||
res.type = RDT_BOOL;
|
||||
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,
|
||||
unsigned argc, const struct argument *argv)
|
||||
unsigned argc, const struct argument * argv)
|
||||
{
|
||||
struct rmsgpack_dom_value res;
|
||||
struct argument arg;
|
||||
struct rmsgpack_dom_value res;
|
||||
memset(&res, 0, sizeof(res));
|
||||
|
||||
res.type = RDT_BOOL;
|
||||
|
||||
@ -215,22 +220,23 @@ static struct rmsgpack_dom_value equals(struct rmsgpack_dom_value input,
|
||||
res.val.bool_ = 0;
|
||||
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.arg.value.val.uint_ = arg.arg.value.val.int_;
|
||||
arg.a.value.type = RDT_UINT;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
struct rmsgpack_dom_value res;
|
||||
memset(&res, 0, sizeof(res));
|
||||
|
||||
res.type = RDT_BOOL;
|
||||
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]);
|
||||
else
|
||||
{
|
||||
res = is_true(argv[i].arg.invocation.func(input,
|
||||
argv[i].arg.invocation.argc,
|
||||
argv[i].arg.invocation.argv
|
||||
res = is_true(argv[i].a.invocation.func(input,
|
||||
argv[i].a.invocation.argc,
|
||||
argv[i].a.invocation.argv
|
||||
), 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,
|
||||
unsigned argc, const struct argument *argv)
|
||||
unsigned argc, const struct argument * argv)
|
||||
{
|
||||
struct rmsgpack_dom_value res;
|
||||
unsigned i = 0;
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
|
||||
res.type = RDT_BOOL;
|
||||
res.val.bool_ = 0;
|
||||
|
||||
@ -269,16 +277,16 @@ static struct rmsgpack_dom_value between(struct rmsgpack_dom_value input,
|
||||
return res;
|
||||
if (argv[0].type != AT_VALUE || argv[1].type != AT_VALUE)
|
||||
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;
|
||||
|
||||
switch (input.type)
|
||||
{
|
||||
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;
|
||||
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;
|
||||
default:
|
||||
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,
|
||||
unsigned argc, const struct argument *argv)
|
||||
unsigned argc, const struct argument * argv)
|
||||
{
|
||||
struct rmsgpack_dom_value res;
|
||||
unsigned i;
|
||||
struct rmsgpack_dom_value res;
|
||||
memset(&res, 0, sizeof(res));
|
||||
|
||||
res.type = RDT_BOOL;
|
||||
res.val.bool_ = 0;
|
||||
@ -303,9 +312,9 @@ static struct rmsgpack_dom_value operator_and(struct rmsgpack_dom_value input,
|
||||
else
|
||||
{
|
||||
res = is_true(
|
||||
argv[i].arg.invocation.func(input,
|
||||
argv[i].arg.invocation.argc,
|
||||
argv[i].arg.invocation.argv
|
||||
argv[i].a.invocation.func(input,
|
||||
argv[i].a.invocation.argc,
|
||||
argv[i].a.invocation.argv
|
||||
),
|
||||
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,
|
||||
unsigned argc, const struct argument *argv)
|
||||
unsigned argc, const struct argument * argv)
|
||||
{
|
||||
struct rmsgpack_dom_value res;
|
||||
unsigned i = 0;
|
||||
memset(&res, 0, sizeof(res));
|
||||
|
||||
res.type = RDT_BOOL;
|
||||
res.val.bool_ = 0;
|
||||
@ -329,12 +339,12 @@ static struct rmsgpack_dom_value q_glob(struct rmsgpack_dom_value input,
|
||||
|
||||
if (argc != 1)
|
||||
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;
|
||||
if (input.type != RDT_STRING)
|
||||
return res;
|
||||
res.val.bool_ = rl_fnmatch(
|
||||
argv[0].arg.value.val.string.buff,
|
||||
argv[0].a.value.val.string.buff,
|
||||
input.val.string.buff,
|
||||
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 i;
|
||||
struct rmsgpack_dom_value res;
|
||||
struct argument arg;
|
||||
struct rmsgpack_dom_value res;
|
||||
struct rmsgpack_dom_value nil_value;
|
||||
struct rmsgpack_dom_value *value = NULL;
|
||||
memset(&res, 0, sizeof(res));
|
||||
|
||||
nil_value.type = RDT_NULL;
|
||||
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)
|
||||
{
|
||||
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 */
|
||||
value = &nil_value;
|
||||
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);
|
||||
else
|
||||
{
|
||||
res = is_true(arg.arg.invocation.func(
|
||||
res = is_true(arg.a.invocation.func(
|
||||
*value,
|
||||
arg.arg.invocation.argc,
|
||||
arg.arg.invocation.argv
|
||||
arg.a.invocation.argc,
|
||||
arg.a.invocation.argv
|
||||
), 0, NULL);
|
||||
value = NULL;
|
||||
}
|
||||
if (!res.val.bool_)
|
||||
break;
|
||||
}
|
||||
|
||||
clean:
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -404,14 +415,14 @@ struct registered_func registered_functions[100] = {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
else if (buff.data[buff.offset] != c)
|
||||
raise_unexpected_char(
|
||||
@ -421,15 +432,15 @@ static struct buffer expect_char(struct buffer 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);
|
||||
if (buff.offset < buff.len)
|
||||
if ((unsigned)buff.offset < buff.len)
|
||||
raise_expected_eof(buff.offset, buff.data[buff.offset], error);
|
||||
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;
|
||||
|
||||
@ -442,7 +453,7 @@ static int peek(struct buffer buff, const char *data)
|
||||
|
||||
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)
|
||||
@ -456,8 +467,8 @@ static void peek_char(struct buffer buff, char *c, const char **error)
|
||||
*c = buff.data[buff.offset];
|
||||
}
|
||||
|
||||
static struct buffer get_char(struct buffer buff, char *c,
|
||||
const char **error)
|
||||
static struct buffer get_char(struct buffer buff, char * c,
|
||||
const char ** error)
|
||||
{
|
||||
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,
|
||||
struct rmsgpack_dom_value *value, const char **error)
|
||||
{
|
||||
const char *str_start;
|
||||
const char * str_start = NULL;
|
||||
char terminator = '\0';
|
||||
char c = '\0';
|
||||
int is_binstr = 0;
|
||||
|
||||
(void)c;
|
||||
|
||||
@ -483,6 +495,12 @@ static struct buffer parse_string(struct buffer buff,
|
||||
if (*error)
|
||||
return buff;
|
||||
|
||||
if (terminator == 'b')
|
||||
{
|
||||
is_binstr = 1;
|
||||
buff = get_char(buff, &terminator, error);
|
||||
}
|
||||
|
||||
if (terminator != '"' && terminator != '\'')
|
||||
{
|
||||
buff.offset--;
|
||||
@ -501,18 +519,44 @@ static struct buffer parse_string(struct buffer buff,
|
||||
|
||||
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.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)
|
||||
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
|
||||
memcpy(
|
||||
value->val.string.buff,
|
||||
str_start,
|
||||
value->val.string.len
|
||||
);
|
||||
hi = (hic - 'A') + 10;
|
||||
|
||||
if (loc <= '9')
|
||||
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;
|
||||
}
|
||||
@ -532,7 +576,7 @@ static struct buffer parse_integer(struct buffer buff,
|
||||
raise_expected_number(buff.offset, error);
|
||||
else
|
||||
{
|
||||
while (isdigit(buff.data[buff.offset]))
|
||||
while (isdigit((int)buff.data[buff.offset]))
|
||||
buff.offset++;
|
||||
}
|
||||
return buff;
|
||||
@ -560,9 +604,9 @@ static struct buffer parse_value(struct buffer buff,
|
||||
value->type = RDT_BOOL;
|
||||
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);
|
||||
else if (isdigit(buff.data[buff.offset]))
|
||||
else if (isdigit((int)buff.data[buff.offset]))
|
||||
buff = parse_integer(buff, value, error);
|
||||
return buff;
|
||||
}
|
||||
@ -583,7 +627,9 @@ static struct buffer get_ident(struct buffer buff,
|
||||
*len = 0;
|
||||
peek_char(buff, &c, error);
|
||||
|
||||
if (*error || !isalpha(c))
|
||||
if (*error)
|
||||
goto clean;
|
||||
if (!isalpha((int)c))
|
||||
return buff;
|
||||
|
||||
buff.offset++;
|
||||
@ -592,36 +638,37 @@ static struct buffer get_ident(struct buffer buff,
|
||||
|
||||
while (!*error)
|
||||
{
|
||||
if (!(isalpha(c) || isdigit(c) || c == '_'))
|
||||
if (!(isalpha((int)c) || isdigit((int)c) || c == '_'))
|
||||
break;
|
||||
buff.offset++;
|
||||
*len = *len + 1;
|
||||
peek_char(buff, &c, error);
|
||||
}
|
||||
|
||||
clean:
|
||||
return buff;
|
||||
}
|
||||
|
||||
static struct buffer parse_method_call(struct buffer buff,
|
||||
struct invocation *invocation, const char **error)
|
||||
{
|
||||
const char *func_name;
|
||||
size_t func_name_len;
|
||||
unsigned i;
|
||||
struct argument args[QUERY_MAX_ARGS];
|
||||
struct argument args[MAX_ARGS];
|
||||
unsigned argi = 0;
|
||||
const char *func_name = NULL;
|
||||
struct registered_func *rf = registered_functions;
|
||||
|
||||
invocation->func = NULL;
|
||||
|
||||
buff = get_ident(buff, &func_name, &func_name_len, error);
|
||||
if (*error)
|
||||
goto error;
|
||||
goto clean;
|
||||
|
||||
buff = chomp(buff);
|
||||
buff = expect_char(buff, '(', error);
|
||||
if (*error)
|
||||
goto error;
|
||||
goto clean;
|
||||
|
||||
while (rf->name)
|
||||
{
|
||||
@ -637,22 +684,22 @@ static struct buffer parse_method_call(struct buffer buff,
|
||||
{
|
||||
raise_unknown_function(buff.offset, func_name,
|
||||
func_name_len, error);
|
||||
goto error;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
buff = chomp(buff);
|
||||
while (!peek(buff, ")"))
|
||||
{
|
||||
if (argi >= QUERY_MAX_ARGS)
|
||||
if (argi >= MAX_ARGS)
|
||||
{
|
||||
raise_too_many_arguments(error);
|
||||
goto error;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
buff = parse_argument(buff, &args[argi], error);
|
||||
|
||||
if (*error)
|
||||
goto error;
|
||||
goto clean;
|
||||
|
||||
argi++;
|
||||
buff = chomp(buff);
|
||||
@ -668,83 +715,81 @@ static struct buffer parse_method_call(struct buffer buff,
|
||||
buff = expect_char(buff, ')', error);
|
||||
|
||||
if (*error)
|
||||
goto error;
|
||||
goto clean;
|
||||
|
||||
invocation->argc = argi;
|
||||
invocation->argv = (struct argument*)
|
||||
malloc(sizeof(struct argument) *argi);
|
||||
malloc(sizeof(struct argument) * argi);
|
||||
|
||||
if (!invocation->argv)
|
||||
{
|
||||
raise_enomem(error);
|
||||
goto error;
|
||||
goto clean;
|
||||
}
|
||||
memcpy(invocation->argv, args,
|
||||
sizeof(struct argument) *argi);
|
||||
sizeof(struct argument) * argi);
|
||||
|
||||
return buff;
|
||||
|
||||
error:
|
||||
goto success;
|
||||
clean:
|
||||
for (i = 0; i < argi; i++)
|
||||
argument_free(&args[i]);
|
||||
success:
|
||||
return buff;
|
||||
}
|
||||
|
||||
static struct buffer parse_table(struct buffer buff,
|
||||
struct invocation *invocation, const char **error)
|
||||
{
|
||||
struct argument args[QUERY_MAX_ARGS];
|
||||
unsigned i;
|
||||
const char *ident_name;
|
||||
size_t ident_len;
|
||||
struct argument args[MAX_ARGS];
|
||||
const char *ident_name = NULL;
|
||||
unsigned argi = 0;
|
||||
|
||||
memset(args, 0, sizeof(struct argument) * QUERY_MAX_ARGS);
|
||||
|
||||
buff = chomp(buff);
|
||||
buff = expect_char(buff, '{', error);
|
||||
|
||||
if (*error)
|
||||
goto error;
|
||||
goto clean;
|
||||
|
||||
buff = chomp(buff);
|
||||
|
||||
while (!peek(buff, "}"))
|
||||
{
|
||||
if (argi >= QUERY_MAX_ARGS)
|
||||
if (argi >= MAX_ARGS)
|
||||
{
|
||||
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);
|
||||
|
||||
if (!*error)
|
||||
{
|
||||
args[argi].arg.value.type = RDT_STRING;
|
||||
args[argi].arg.value.val.string.len = ident_len;
|
||||
args[argi].arg.value.val.string.buff = (char*)calloc(
|
||||
args[argi].a.value.type = RDT_STRING;
|
||||
args[argi].a.value.val.string.len = ident_len;
|
||||
args[argi].a.value.val.string.buff = (char*)calloc(
|
||||
ident_len + 1,
|
||||
sizeof(char)
|
||||
);
|
||||
|
||||
if (!args[argi].arg.value.val.string.buff)
|
||||
goto error;
|
||||
if (!args[argi].a.value.val.string.buff)
|
||||
goto clean;
|
||||
|
||||
strncpy(
|
||||
args[argi].arg.value.val.string.buff,
|
||||
args[argi].a.value.val.string.buff,
|
||||
ident_name,
|
||||
ident_len
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
buff = parse_string(buff, &args[argi].arg.value, error);
|
||||
buff = parse_string(buff, &args[argi].a.value, error);
|
||||
|
||||
if (*error)
|
||||
goto error;
|
||||
goto clean;
|
||||
|
||||
args[argi].type = AT_VALUE;
|
||||
buff = chomp(buff);
|
||||
@ -752,20 +797,20 @@ static struct buffer parse_table(struct buffer buff,
|
||||
buff = expect_char(buff, ':', error);
|
||||
|
||||
if (*error)
|
||||
goto error;
|
||||
goto clean;
|
||||
|
||||
buff = chomp(buff);
|
||||
|
||||
if (argi >= QUERY_MAX_ARGS)
|
||||
if (argi >= MAX_ARGS)
|
||||
{
|
||||
raise_too_many_arguments(error);
|
||||
goto error;
|
||||
goto clean;
|
||||
}
|
||||
|
||||
buff = parse_argument(buff, &args[argi], error);
|
||||
|
||||
if (*error)
|
||||
goto error;
|
||||
goto clean;
|
||||
argi++;
|
||||
buff = chomp(buff);
|
||||
buff = expect_char(buff, ',', error);
|
||||
@ -781,7 +826,7 @@ static struct buffer parse_table(struct buffer buff,
|
||||
buff = expect_char(buff, '}', error);
|
||||
|
||||
if (*error)
|
||||
goto error;
|
||||
goto clean;
|
||||
|
||||
invocation->func = all_map;
|
||||
invocation->argc = argi;
|
||||
@ -791,16 +836,16 @@ static struct buffer parse_table(struct buffer buff,
|
||||
if (!invocation->argv)
|
||||
{
|
||||
raise_enomem(error);
|
||||
goto error;
|
||||
goto clean;
|
||||
}
|
||||
memcpy(invocation->argv, args,
|
||||
sizeof(struct argument) *argi);
|
||||
sizeof(struct argument) * argi);
|
||||
|
||||
return buff;
|
||||
|
||||
error:
|
||||
goto success;
|
||||
clean:
|
||||
for (i = 0; i < argi; i++)
|
||||
argument_free(&args[i]);
|
||||
success:
|
||||
return buff;
|
||||
}
|
||||
|
||||
@ -810,32 +855,31 @@ static struct buffer parse_argument(struct buffer buff,
|
||||
buff = chomp(buff);
|
||||
|
||||
if (
|
||||
isalpha(buff.data[buff.offset])
|
||||
isalpha((int)buff.data[buff.offset])
|
||||
&& !(
|
||||
peek(buff, "nil")
|
||||
|| peek(buff, "true")
|
||||
|| peek(buff, "false")
|
||||
|| peek(buff, "b\"") || peek(buff, "b'") /* bin string prefix*/
|
||||
)
|
||||
)
|
||||
{
|
||||
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, "{"))
|
||||
{
|
||||
arg->type = AT_FUNCTION;
|
||||
buff = parse_table(buff, &arg->arg.invocation, error);
|
||||
buff = parse_table(buff, &arg->a.invocation, error);
|
||||
}
|
||||
else
|
||||
{
|
||||
arg->type = AT_VALUE;
|
||||
buff = parse_value(buff, &arg->arg.value, error);
|
||||
buff = parse_value(buff, &arg->a.value, error);
|
||||
}
|
||||
return buff;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void libretrodb_query_free(void *q)
|
||||
{
|
||||
unsigned i;
|
||||
@ -848,9 +892,9 @@ void libretrodb_query_free(void *q)
|
||||
for (i = 0; i < real_q->root.argc; i++)
|
||||
argument_free(&real_q->root.argv[i]);
|
||||
|
||||
|
||||
free(real_q->root.argv);
|
||||
real_q->root.argv = NULL;
|
||||
real_q->root.argc = 0;
|
||||
free(real_q);
|
||||
}
|
||||
|
||||
@ -858,11 +902,10 @@ void *libretrodb_query_compile(libretrodb_t *db,
|
||||
const char *query, size_t buff_len, const char **error)
|
||||
{
|
||||
struct buffer buff;
|
||||
struct query *q = (struct query*)calloc(1,
|
||||
sizeof(*q));
|
||||
struct query *q = (struct query*)calloc(1, sizeof(*q));
|
||||
|
||||
if (!q)
|
||||
goto error;
|
||||
goto clean;
|
||||
|
||||
q->ref_count = 1;
|
||||
buff.data = query;
|
||||
@ -876,26 +919,25 @@ void *libretrodb_query_compile(libretrodb_t *db,
|
||||
{
|
||||
buff = parse_table(buff, &q->root, 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 = expect_eof(buff, error);
|
||||
if (*error)
|
||||
goto error;
|
||||
goto clean;
|
||||
|
||||
if (!q->root.func)
|
||||
{
|
||||
raise_unexpected_eof(buff.offset, error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return q;
|
||||
|
||||
error:
|
||||
goto success;
|
||||
clean:
|
||||
if (q)
|
||||
libretrodb_query_free(q);
|
||||
success:
|
||||
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);
|
||||
return (res.type == RDT_BOOL && res.val.bool_);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user