(libretro-db/query.c) Update this - should fix crash

This commit is contained in:
twinaphex 2015-09-21 16:23:08 +02:00
parent 3960897e74
commit 031190ed14
1 changed files with 247 additions and 204 deletions

View File

@ -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_);
} }