/* Copyright (c) 2021 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "dlua-script-private.h" /* * Adjust the index by the specified delta. * * In a couple of places we need to adjust the passed in index to reflect * additional items pushed onto the stack. We cannot blindly adjust the * index because the index could be one of three things and only one of them * is supposed to be ajusted: * * 1. negative number: index relative to top of stack, adjust * 2. positive number: absolute index, don't adjust * 3. special registry index: don't adjust */ static inline int adj(int idx, int delta) { if ((idx == LUA_REGISTRYINDEX) || (idx > 0)) return idx; else return idx - delta; } /* * Pushes onto the stack the value t[k], where t is the value at the given * index and k is the value at the top of the stack. Unlike lua_gettable(), * this function checks the type of the retreived value against the passed * in type. [-1,+0..1,e] * * Return value: * -1 = incompatible type * 0 = nil or none * 1 = found */ static int dlua_table_get(lua_State *L, int idx, int type) { /* can only work with tables */ if (!lua_istable(L, idx)) return -1; lua_gettable(L, idx); /* check if the field was there */ if (lua_isnoneornil(L, -1)) { lua_pop(L, 1); return 0; } /* check that the field is the expected type */ if (lua_type(L, -1) != type) { lua_pop(L, 1); return -1; } return 1; } /* Get by string name [-0,+1,e] */ int dlua_table_get_by_str(lua_State *L, int idx, int type, const char *field) { /* push the key */ lua_pushstring(L, field); return dlua_table_get(L, adj(idx, 1), type); } /* Get by int name [-0,+1,e] */ int dlua_table_get_by_int(lua_State *L, int idx, int type, lua_Integer field) { /* push the key */ lua_pushinteger(L, field); return dlua_table_get(L, adj(idx, 1), type); } /* Get by thread [-0,+1,e] */ int dlua_table_get_by_thread(lua_State *L, int idx, int type) { /* push the key */ lua_pushthread(L); return dlua_table_get(L, adj(idx, 1), type); } /* generate a set of functions to access fields of an integral data type */ #define GET_INTTYPE(fxn, ctype, minval, maxval, unsigned_check) \ int fxn##_by_str(lua_State *L, int idx, const char *field, \ ctype *value_r) \ { \ lua_Integer tmp; \ int ret; \ \ ret = dlua_table_get_luainteger_by_str(L, idx, field, &tmp); \ if (ret < 1) \ return ret; \ \ if (unsigned_check) { \ if ((tmp < 0) || (((uintmax_t) tmp) > (maxval))) \ return -1; \ } else { \ if ((tmp < (minval)) || (tmp > (intmax_t) (maxval))) \ return -1; \ } \ \ *value_r = (ctype) tmp; \ \ return 1; \ } \ int fxn##_by_int(lua_State *L, int idx, lua_Integer field, \ ctype *value_r) \ { \ lua_Integer tmp; \ int ret; \ \ ret = dlua_table_get_luainteger_by_int(L, idx, field, &tmp); \ if (ret < 1) \ return ret; \ \ if (unsigned_check) { \ if ((tmp < 0) || (((uintmax_t) tmp) > (maxval))) \ return -1; \ } else { \ if ((tmp < (minval)) || (tmp > (intmax_t) (maxval))) \ return -1; \ } \ \ *value_r = (ctype) tmp; \ \ return 1; \ } \ int fxn##_by_thread(lua_State *L, int idx, ctype *value_r) \ { \ lua_Integer tmp; \ int ret; \ \ ret = dlua_table_get_luainteger_by_thread(L, idx, &tmp); \ if (ret < 1) \ return ret; \ \ if (unsigned_check) { \ if ((tmp < 0) || (((uintmax_t) tmp) > (maxval))) \ return -1; \ } else { \ if ((tmp < (minval)) || (tmp > (intmax_t) (maxval))) \ return -1; \ } \ \ *value_r = (ctype) tmp; \ \ return 1; \ } /* generate a set of functions to access fields of a binary data type */ #define GET_DATAPTR(fxn) \ int fxn##_by_str(lua_State *L, int idx, const char *field, \ const unsigned char **value_r, size_t *len_r) \ { \ int ret; \ \ ret = dlua_table_get_by_str(L, idx, LUA_TSTRING, field); \ if (ret < 1) \ return ret; \ \ *value_r = (const unsigned char *) lua_tolstring(L, -1, len_r); \ lua_pop(L, 1); \ \ return 1; \ } \ int fxn##_by_int(lua_State *L, int idx, lua_Integer field, \ const unsigned char **value_r, size_t *len_r) \ { \ int ret; \ \ ret = dlua_table_get_by_int(L, idx, LUA_TSTRING, field); \ if (ret < 1) \ return ret; \ \ *value_r = (const unsigned char *) lua_tolstring(L, -1, len_r); \ lua_pop(L, 1); \ \ return 1; \ } \ int fxn##_by_thread(lua_State *L, int idx, \ const unsigned char **value_r, size_t *len_r) \ { \ int ret; \ \ ret = dlua_table_get_by_thread(L, idx, LUA_TSTRING); \ if (ret < 1) \ return ret; \ \ *value_r = (const unsigned char *) lua_tolstring(L, -1, len_r); \ lua_pop(L, 1); \ \ return 1; \ } /* generate a set of functions to access fields of a generic-ish type */ #define GET_GENERIC(fxn, ctype, ltype, cvt) \ int fxn##_by_str(lua_State *L, int idx, const char *field, ctype *value_r)\ { \ int ret; \ \ ret = dlua_table_get_by_str(L, idx, (ltype), field); \ if (ret < 1) \ return ret; \ \ *value_r = cvt(L, -1); \ lua_pop(L, 1); \ \ return 1; \ } \ int fxn##_by_int(lua_State *L, int idx, lua_Integer field, ctype *value_r)\ { \ int ret; \ \ ret = dlua_table_get_by_int(L, idx, (ltype), field); \ if (ret < 1) \ return ret; \ \ *value_r = cvt(L, -1); \ lua_pop(L, 1); \ \ return 1; \ } \ int fxn##_by_thread(lua_State *L, int idx, ctype *value_r) \ { \ int ret; \ \ ret = dlua_table_get_by_thread(L, idx, (ltype)); \ if (ret < 1) \ return ret; \ \ *value_r = cvt(L, -1); \ lua_pop(L, 1); \ \ return 1; \ } GET_INTTYPE(dlua_table_get_int, int, INT_MIN, INT_MAX, FALSE); GET_INTTYPE(dlua_table_get_intmax, intmax_t, INTMAX_MIN, INTMAX_MAX, FALSE); GET_INTTYPE(dlua_table_get_uint, unsigned int, 0, UINT_MAX, TRUE); GET_INTTYPE(dlua_table_get_uintmax, uintmax_t, 0, UINTMAX_MAX, TRUE); /* we need to use lua_tointegerx which takes an extra argument */ int dlua_table_get_luainteger_by_str(lua_State *L, int idx, const char *field, lua_Integer *value_r) { int isnum; int ret; ret = dlua_table_get_by_str(L, idx, LUA_TNUMBER, field); if (ret < 1) return ret; *value_r = lua_tointegerx(L, -1, &isnum); lua_pop(L, 1); return (isnum == 1) ? 1 : -1; } /* we need to use lua_tointegerx which takes an extra argument */ int dlua_table_get_luainteger_by_int(lua_State *L, int idx, lua_Integer field, lua_Integer *value_r) { int isnum; int ret; ret = dlua_table_get_by_int(L, idx, LUA_TNUMBER, field); if (ret < 1) return ret; *value_r = lua_tointegerx(L, -1, &isnum); lua_pop(L, 1); return (isnum == 1) ? 1 : -1; } /* we need to use lua_tointegerx which takes an extra argument */ int dlua_table_get_luainteger_by_thread(lua_State *L, int idx, lua_Integer *value_r) { int isnum; int ret; ret = dlua_table_get_by_thread(L, idx, LUA_TNUMBER); if (ret < 1) return ret; *value_r = lua_tointegerx(L, -1, &isnum); lua_pop(L, 1); return (isnum == 1) ? 1 : -1; } GET_GENERIC(dlua_table_get_number, lua_Number, LUA_TNUMBER, lua_tonumber); GET_GENERIC(dlua_table_get_bool, bool, LUA_TBOOLEAN, lua_toboolean); GET_GENERIC(dlua_table_get_string, const char *, LUA_TSTRING, lua_tostring); GET_DATAPTR(dlua_table_get_data);