{
const gchar *p, *key = NULL, *end, *cls;
va_list ap;
- gboolean required = FALSE, failed = FALSE;
+ gboolean required = FALSE, failed = FALSE, is_table;
gchar classbuf[128];
enum {
read_key = 0,
read_semicolon
} state = read_key;
gsize keylen = 0, *valuelen, clslen;
+ gint idx;
+
+ g_assert (extraction_pattern != NULL);
if (pos < 0) {
/* Get absolute pos */
pos = lua_gettop (L) + pos + 1;
}
- g_assert (extraction_pattern != NULL);
- g_assert (lua_type (L, pos) == LUA_TTABLE);
+ if (lua_type (L, pos) == LUA_TTABLE) {
+ is_table = TRUE;
+ }
+ else {
+ is_table = FALSE;
+ idx = pos;
+ }
p = extraction_pattern;
end = p + strlen (extraction_pattern);
break;
case read_arg:
g_assert (keylen != 0);
- lua_pushlstring (L, key, keylen);
- lua_gettable (L, pos);
+
+ if (is_table) {
+ lua_pushlstring (L, key, keylen);
+ lua_gettable (L, pos);
+ idx = -1;
+ }
switch (g_ascii_toupper (*p)) {
case 'S':
- if (lua_type (L, -1) == LUA_TSTRING) {
- *(va_arg (ap, const gchar **)) = lua_tostring (L, -1);
+ if (lua_type (L, idx) == LUA_TSTRING) {
+ *(va_arg (ap, const gchar **)) = lua_tostring (L, idx);
}
- else if (lua_type (L, -1) == LUA_TNIL) {
+ else if (lua_type (L, idx) == LUA_TNIL) {
failed = TRUE;
*(va_arg (ap, const gchar **)) = NULL;
}
return FALSE;
}
- lua_pop (L, 1);
+
+ if (is_table) {
+ lua_pop (L, 1);
+ }
break;
case 'I':
- if (lua_type (L, -1) == LUA_TNUMBER) {
- *(va_arg (ap, gint64 *)) = lua_tonumber (L, -1);
+ if (lua_type (L, idx) == LUA_TNUMBER) {
+ *(va_arg (ap, gint64 *)) = lua_tonumber (L, idx);
}
- else if (lua_type (L, -1) == LUA_TNIL) {
+ else if (lua_type (L, idx) == LUA_TNIL) {
failed = TRUE;
*(va_arg (ap, gint64 *)) = 0;
}
" %.*s: '%s', '%s' is expected",
(gint) keylen,
key,
- lua_typename (L, lua_type (L, -1)),
+ lua_typename (L, lua_type (L, idx)),
"int64");
va_end (ap);
return FALSE;
}
- lua_pop (L, 1);
+ if (is_table) {
+ lua_pop (L, 1);
+ }
break;
case 'F':
- if (lua_type (L, -1) == LUA_TFUNCTION) {
+ if (lua_type (L, idx) == LUA_TFUNCTION) {
+ if (!is_table) {
+ lua_pushvalue (L, idx);
+ }
+
*(va_arg (ap, gint *)) = luaL_ref (L, LUA_REGISTRYINDEX);
}
- else if (lua_type (L, -1) == LUA_TNIL) {
+ else if (lua_type (L, idx) == LUA_TNIL) {
failed = TRUE;
*(va_arg (ap, gint *)) = -1;
- lua_pop (L, 1);
+ if (is_table) {
+ lua_pop (L, 1);
+ }
}
else {
g_set_error (err,
" %.*s: '%s', '%s' is expected",
(gint) keylen,
key,
- lua_typename (L, lua_type (L, -1)),
+ lua_typename (L, lua_type (L, idx)),
"function");
va_end (ap);
- lua_pop (L, 1);
+ if (is_table) {
+ lua_pop (L, 1);
+ }
return FALSE;
}
break;
case 'B':
- if (lua_type (L, -1) == LUA_TBOOLEAN) {
+ if (lua_type (L, idx) == LUA_TBOOLEAN) {
*(va_arg (ap, gboolean *)) = lua_toboolean (L, -1);
}
- else if (lua_type (L, -1) == LUA_TNIL) {
+ else if (lua_type (L, idx) == LUA_TNIL) {
failed = TRUE;
*(va_arg (ap, gboolean *)) = 0;
}
" %.*s: '%s', '%s' is expected",
(gint) keylen,
key,
- lua_typename (L, lua_type (L, -1)),
+ lua_typename (L, lua_type (L, idx)),
"bool");
va_end (ap);
return FALSE;
}
- lua_pop (L, 1);
+
+ if (is_table) {
+ lua_pop (L, 1);
+ }
break;
case 'N':
- if (lua_type (L, -1) == LUA_TNUMBER) {
- *(va_arg (ap, gdouble *)) = lua_tonumber (L, -1);
+ if (lua_type (L, idx) == LUA_TNUMBER) {
+ *(va_arg (ap, gdouble *)) = lua_tonumber (L, idx);
}
- else if (lua_type (L, -1) == LUA_TNIL) {
+ else if (lua_type (L, idx) == LUA_TNIL) {
failed = TRUE;
*(va_arg (ap, gdouble *)) = 0;
}
" %.*s: '%s', '%s' is expected",
(gint) keylen,
key,
- lua_typename (L, lua_type (L, -1)),
+ lua_typename (L, lua_type (L, idx)),
"double");
va_end (ap);
return FALSE;
}
- lua_pop (L, 1);
+
+ if (is_table) {
+ lua_pop (L, 1);
+ }
break;
case 'V':
valuelen = va_arg (ap, gsize *);
- if (lua_type (L, -1) == LUA_TSTRING) {
- *(va_arg (ap, const gchar **)) = lua_tolstring (L, -1,
+
+ if (lua_type (L, idx) == LUA_TSTRING) {
+ *(va_arg (ap, const gchar **)) = lua_tolstring (L, idx,
valuelen);
}
- else if (lua_type (L, -1) == LUA_TNIL) {
+ else if (lua_type (L, idx) == LUA_TNIL) {
failed = TRUE;
*(va_arg (ap, const char **)) = NULL;
*valuelen = 0;
" %.*s: '%s', '%s' is expected",
(gint) keylen,
key,
- lua_typename (L, lua_type (L, -1)),
+ lua_typename (L, lua_type (L, idx)),
"string");
va_end (ap);
return FALSE;
}
- lua_pop (L, 1);
+
+ if (is_table) {
+ lua_pop (L, 1);
+ }
break;
case 'U':
- if (lua_type (L, -1) == LUA_TNIL) {
+ if (lua_type (L, idx) == LUA_TNIL) {
failed = TRUE;
}
- else if (lua_type (L, -1) != LUA_TUSERDATA) {
+ else if (lua_type (L, idx) != LUA_TUSERDATA) {
g_set_error (err,
lua_error_quark (),
1,
return FALSE;
}
+ if (!is_table) {
+ idx ++;
+ }
+
/* Reset read params */
state = read_semicolon;
failed = FALSE;
state = read_class;
}
else {
- lua_pop (L, 1);
+ if (is_table) {
+ lua_pop (L, 1);
+ }
+
g_set_error (err, lua_error_quark (), 2, "missing classname for "
"%.*s", (gint)keylen, key);
va_end (ap);
if (*p == '}') {
clslen = p - cls;
if (clslen == 0) {
- lua_pop (L, 1);
+ if (is_table) {
+ lua_pop (L, 1);
+ }
+
g_set_error (err,
lua_error_quark (),
2,
rspamd_snprintf (classbuf, sizeof (classbuf), "rspamd{%*s}",
(gint) clslen, cls);
- if (!failed && rspamd_lua_check_class (L, -1, classbuf)) {
- *(va_arg (ap, void **)) = *(void **)lua_touserdata (L, -1);
+ /*
+ * Need to go to the previous index as we have increased it in
+ * the previous state
+ */
+ if (!is_table) {
+ idx --;
+ }
+
+ /*
+ * We skip class check here for speed in non-table mode
+ */
+ if (!failed && (!is_table ||
+ rspamd_lua_check_class (L, idx, classbuf))) {
+ *(va_arg (ap, void **)) = *(void **)lua_touserdata (L, idx);
}
else {
if (!failed) {
(gint) keylen,
key,
classbuf,
- lua_tostring (L, -1));
+ lua_tostring (L, idx));
va_end (ap);
return FALSE;
}
}
- lua_pop (L, 1);
+ if (!is_table) {
+ lua_pop (L, 1);
+ }
+ else {
+ idx ++;
+ }
if (failed && required) {
g_set_error (err,