summaryrefslogtreecommitdiffstats
path: root/src/lib-lua/dlua-compat.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-lua/dlua-compat.c')
-rw-r--r--src/lib-lua/dlua-compat.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/lib-lua/dlua-compat.c b/src/lib-lua/dlua-compat.c
new file mode 100644
index 0000000..c676186
--- /dev/null
+++ b/src/lib-lua/dlua-compat.c
@@ -0,0 +1,157 @@
+/* Copyright (c) 2017-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "strnum.h"
+#include "dlua-script-private.h"
+
+#if LUA_VERSION_NUM == 502
+# error "Lua 5.2 is not supported. Use Lua 5.1 or 5.3 instead."
+#endif
+
+#ifndef HAVE_LUAL_SETFUNCS
+void luaL_setfuncs(lua_State *L, const luaL_Reg *l, int nup)
+{
+ luaL_checkstack(L, nup + 1, "too many upvalues");
+ for (; l->name != NULL; l++) {
+ int i;
+ lua_pushstring(L, l->name);
+ for (i = 0; i < nup; i++)
+ lua_pushvalue(L, -(nup + 1));
+ lua_pushcclosure(L, l->func, nup);
+ lua_settable(L, -(nup + 3));
+ }
+ lua_pop(L, nup);
+}
+#endif
+
+#ifndef HAVE_LUAL_SETMETATABLE
+void luaL_setmetatable(lua_State *L, const char *tname)
+{
+ luaL_checkstack(L, 1, "not enough stack slots");
+ luaL_getmetatable(L, tname);
+ lua_setmetatable(L, -2);
+}
+#endif
+
+#ifndef HAVE_LUA_ISINTEGER
+# if LUA_VERSION_NUM >= 503
+# error "Lua 5.3+ should have lua_isinteger()"
+# endif
+/*
+ * Lua 5.3 added lua_isinteger() which tells us whether or not the input is
+ * an integer. In Lua 5.1 and 5.2, we have to emulate it.
+ */
+#undef lua_isinteger
+int lua_isinteger(lua_State *L, int idx)
+{
+ int isnum;
+
+ if (lua_type(L, idx) != LUA_TNUMBER)
+ return 0;
+
+ (void) lua_tointegerx(L, idx, &isnum);
+
+ return isnum;
+}
+#endif
+
+#ifndef HAVE_LUA_SETI
+void lua_seti(lua_State *L, int index, lua_Integer n)
+{
+ /* stack: value (top) */
+ lua_pushinteger(L, n);
+ /* stack: value, n (top) */
+ lua_insert(L, -2);
+ /* stack: n, value (top) */
+
+ /* adjust relative stack position */
+ if (index < 0)
+ index--;
+
+ lua_settable(L, index);
+}
+#endif
+
+#ifndef HAVE_LUA_TOINTEGERX
+# if LUA_VERSION_NUM >= 502
+# error "Lua 5.2+ should have lua_tointegerx()"
+# endif
+/*
+ * Lua 5.2 added lua_tointegerx() which tells us whether or not the
+ * input was an integer. In Lua 5.1, we have to emulate it to the best of
+ * our ability.
+ */
+lua_Integer lua_tointegerx(lua_State *L, int idx, int *isnum_r)
+{
+ lua_Integer integer;
+ lua_Number number;
+ const char *str;
+
+ /*
+ * Unfortunately, Lua 5.1 doesn't provide MIN/MAX value macros for
+ * the lua_Integer type, so we hardcode the assumption that it is
+ * the same size as ptrdiff_t. This matches what Lua does by
+ * default.
+ *
+ * If this compile-time assertion fails, don't forget to change the
+ * PTRDIFF_{MIN,MAX} usage below as well.
+ */
+ (void) COMPILE_ERROR_IF_TRUE(sizeof(lua_Integer) != sizeof(ptrdiff_t));
+
+ switch (lua_type(L, idx)) {
+ case LUA_TSTRING:
+ /* convert using str_to_long() */
+ str = lua_tostring(L, idx);
+
+ if (strncasecmp(str, "0x", 2) == 0) {
+ /* hex */
+ uintmax_t tmp;
+
+ /* skip over leading 0x */
+ str += 2;
+
+ if (str_to_uintmax_hex(str, &tmp) < 0)
+ break;
+
+ *isnum_r = (tmp <= PTRDIFF_MAX) ? 1 : 0;
+ return tmp;
+ } else {
+ /* try decimal */
+ intmax_t tmp;
+
+ if (str_to_intmax(str, &tmp) < 0)
+ break;
+
+ *isnum_r = ((tmp >= PTRDIFF_MIN) && (tmp <= PTRDIFF_MAX)) ? 1 : 0;
+ return tmp;
+ }
+
+ break;
+ case LUA_TNUMBER:
+ /* use lua helper macro */
+ number = lua_tonumber(L, idx);
+
+ /* Lua 5.1-only macro from luaconf.h */
+ lua_number2integer(integer, number);
+
+ *isnum_r = (((lua_Number) integer) == number) ? 1 : 0;
+
+ return integer;
+ default:
+ break;
+ }
+
+ /* not an integer */
+ *isnum_r = 0;
+ return 0;
+}
+#endif
+
+#if LUA_VERSION_NUM > 501 && LUA_VERSION_NUM < 504
+# undef lua_resume
+int lua_resume_compat(lua_State *L, lua_State *from, int nargs, int *nresults)
+{
+ *nresults = 1;
+ return lua_resume(L, from, nargs);
+}
+#endif