userdata_t *u = (userdata_t *)data - 1;
mrp_lua_class_member_t *m;
mrp_lua_value_t *vptr;
+ void **itemsp;
+ size_t *nitemp;
m = u->def->members + member;
vptr = data + m->offs;
case MRP_LUA_ANY:
vptr->any = LUA_NOREF;
goto ok;
+ case MRP_LUA_STRING_ARRAY:
+ case MRP_LUA_BOOLEAN_ARRAY:
+ case MRP_LUA_INTEGER_ARRAY:
+ case MRP_LUA_DOUBLE_ARRAY:
+ itemsp = data + m->offs;
+ nitemp = data + m->size;
+ *itemsp = NULL;
+ *nitemp = 0;
+ goto ok;
default:
goto error;
}
vptr->any = v->any;
goto ok;
+ case MRP_LUA_STRING_ARRAY:
+ case MRP_LUA_BOOLEAN_ARRAY:
+ case MRP_LUA_INTEGER_ARRAY:
+ case MRP_LUA_DOUBLE_ARRAY:
+ itemsp = data + m->offs;
+ nitemp = data + m->size;
+ mrp_lua_object_free_array(itemsp, nitemp, m->type);
+ *itemsp = *v->array.items;
+ *nitemp = *v->array.nitem;
+ goto ok;
+
default:
goto error;
}
case MRP_LUA_ANY:
v->any = vptr->any;
goto ok;
+
+ case MRP_LUA_STRING_ARRAY:
+ case MRP_LUA_BOOLEAN_ARRAY:
+ case MRP_LUA_INTEGER_ARRAY:
+ case MRP_LUA_DOUBLE_ARRAY:
+ v->array = vptr->array;
+ goto ok;
+
+ default:
+ goto error;
}
ok:
if ((m->name = mrp_strdup(members[i].name)) == NULL)
goto fail;
+ *m = members[i];
+ if (m->setter == NULL)
+ m->setter = default_setter;
+ if (m->getter == NULL)
+ m->getter = default_getter;
+ m->flags |= (flags & MRP_LUA_CLASS_READONLY);
+
+#if 0
m->type = members[i].type;
m->offs = members[i].offs;
m->setter = members[i].setter ? members[i].setter : default_setter;
m->getter = members[i].getter ? members[i].getter : default_getter;
m->flags = members[i].flags | (flags & MRP_LUA_CLASS_READONLY);
+#endif
def->nmember++;
}
mrp_debug("initializing %s.%s of Lua object %p(%p)", u->def->class_name,
m->name, data, u);
m->setter(data, NULL, i, NULL);
-
}
u->initializing = false;
}
}
-static int seterr(char *err, size_t esize, const char *format, ...)
+static int seterr(lua_State *L, char *e, size_t size, const char *format, ...)
{
va_list ap;
+ char msg[256];
- if (err != NULL) {
- va_start(ap, format);
- vsnprintf(err, esize, format, ap);
- va_end(ap);
+ va_start(ap, format);
+ vsnprintf(e ? e : msg, e ? size : sizeof(msg), format, ap);
+ va_end(ap);
+
+ if (!e && L) {
+ lua_pushstring(L, msg);
+ lua_error(L);
}
return -1;
if (u->exttbl == LUA_NOREF) {
if (err)
- return seterr(err, esize, "trying to set user-defined field %s "
+ return seterr(L, err, esize, "trying to set user-defined field %s "
"for non-extensible object %s", name,
u->def->class_name);
else
}
+static inline int array_lua_type(int type)
+{
+ switch (type) {
+ case MRP_LUA_STRING_ARRAY: return LUA_TSTRING;
+ case MRP_LUA_BOOLEAN_ARRAY: return LUA_TBOOLEAN;
+ case MRP_LUA_INTEGER_ARRAY: return LUA_TNUMBER;
+ case MRP_LUA_DOUBLE_ARRAY: return LUA_TNUMBER;
+ default: return LUA_TNONE;
+ }
+}
+
+
+static inline int array_murphy_type(int type)
+{
+ switch (type) {
+ case LUA_TSTRING: return MRP_LUA_STRING_ARRAY;
+ case LUA_TBOOLEAN: return MRP_LUA_BOOLEAN_ARRAY;
+ case LUA_TNUMBER: return MRP_LUA_INTEGER_ARRAY;
+ default: return MRP_LUA_NONE;
+ }
+}
+
+
+static inline int array_item_size(int type)
+{
+ switch (type) {
+ case MRP_LUA_STRING_ARRAY: return sizeof(char *);
+ case MRP_LUA_BOOLEAN_ARRAY: return sizeof(bool);
+ case MRP_LUA_INTEGER_ARRAY: return sizeof(int32_t);
+ case MRP_LUA_DOUBLE_ARRAY: return sizeof(double);
+ default: return 0;
+ }
+}
+
+
+static inline const char *array_type_name(int type)
+{
+ switch (type) {
+ case MRP_LUA_STRING_ARRAY: return "string";
+ case MRP_LUA_BOOLEAN_ARRAY: return "boolean";
+ case MRP_LUA_INTEGER_ARRAY: return "integer";
+ case MRP_LUA_DOUBLE_ARRAY: return "double";
+ case MRP_LUA_ANY: return "any";
+ default: return "<invalid array type>";
+ }
+}
+
+
+int mrp_lua_object_collect_array(lua_State *L, int tidx, void **itemsp,
+ size_t *nitemp, int expected, int copy,
+ char *e, size_t esize)
+{
+ const char *name, *str;
+ int ktype, vtype, ltype, i;
+ size_t max, idx, isize;
+ void *items;
+
+ max = *nitemp;
+ tidx = mrp_lua_absidx(L, tidx);
+ items = NULL;
+
+ if (expected != MRP_LUA_ANY) {
+ ltype = array_lua_type(expected);
+ isize = array_item_size(expected);
+
+ if (ltype == LUA_TNONE || !isize)
+ goto type_error;
+ }
+
+ lua_pushnil(L);
+ MRP_LUA_FOREACH_ALL(L, i, tidx, ktype, name, idx) {
+ vtype = lua_type(L, -1);
+
+ mrp_debug("collecting <%s>:<%s> element for %s array",
+ lua_typename(L, ktype), lua_typename(L, vtype),
+ array_type_name(expected));
+
+ if (ktype != LUA_TNUMBER)
+ goto not_pure;
+
+ if (expected == MRP_LUA_ANY) {
+ expected = array_murphy_type(vtype);
+
+ if (!expected)
+ goto type_error;
+
+ ltype = array_lua_type(expected);
+ isize = array_item_size(expected);
+ }
+ else
+ if (vtype != ltype &&
+ !(expected && MRP_LUA_STRING_ARRAY && vtype == LUA_TNIL))
+ goto type_error;
+
+ if (max != (size_t)-1 && i >= (int)max)
+ goto overflow;
+
+ if (mrp_realloc(items, (i + 1) * isize) == NULL)
+ goto nomem;
+
+ switch (expected) {
+ case MRP_LUA_STRING_ARRAY:
+ str = (vtype != LUA_TNIL ? lua_tostring(L, -1) : NULL);
+ if (copy) {
+ ((char **)items)[i] = str ? mrp_strdup(str) : NULL;
+ if (!((char **)items)[i] && str)
+ goto nomem;
+ }
+ else
+ ((char **)items)[i] = (char *)str;
+ break;
+ case MRP_LUA_BOOLEAN_ARRAY:
+ ((bool *)items)[i] = lua_toboolean(L, -1);
+ break;
+ case MRP_LUA_INTEGER_ARRAY:
+ ((int32_t *)items)[i] = lua_tointeger(L, -1);
+ break;
+ case MRP_LUA_DOUBLE_ARRAY:
+ ((double *)items)[i] = lua_tonumber(L, -1);
+ break;
+ default:
+ goto type_error;
+ }
+ }
+
+ *itemsp = items;
+ *nitemp = i;
+
+ return 0;
+
+
+#define CLEANUP() do { \
+ mrp_lua_object_free_array(itemsp, nitemp, expected); \
+ } while (0)
+
+ type_error:
+ CLEANUP(); return seterr(L, e, esize, "array or element of wrong type");
+ not_pure:
+ CLEANUP(); return seterr(L, e, esize, "not a pure array");
+ nomem:
+ CLEANUP(); return seterr(L, e, esize, "could not allocate array");
+ overflow:
+ CLEANUP(); return seterr(L, e, esize, "array too large");
+#undef CLEANUP
+}
+
+
+void mrp_lua_object_free_array(void **itemsp, size_t *nitemp, int type)
+{
+ size_t nitem = *nitemp;
+ char **saptr;
+ size_t i;
+
+ switch (type) {
+ case MRP_LUA_STRING_ARRAY:
+ saptr = *itemsp;
+ for (i = 0; i < nitem; i++)
+ mrp_free(saptr[i]);
+ case MRP_LUA_BOOLEAN_ARRAY:
+ case MRP_LUA_INTEGER_ARRAY:
+ case MRP_LUA_DOUBLE_ARRAY:
+ mrp_free(*itemsp);
+ *itemsp = NULL;
+ *nitemp = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+
+int mrp_lua_object_push_array(lua_State *L, int type, void *items, size_t nitem)
+{
+ int i;
+
+ lua_createtable(L, nitem, 0);
+
+ for (i = 0; i < (int)nitem; i++) {
+ switch (type) {
+ case MRP_LUA_STRING_ARRAY:
+ lua_pushstring(L, ((char **)items)[i]);
+ break;
+ case MRP_LUA_BOOLEAN_ARRAY:
+ lua_pushboolean(L, ((bool *)items)[i]);
+ break;
+ case MRP_LUA_INTEGER_ARRAY:
+ lua_pushinteger(L, ((int32_t *)items)[i]);
+ break;
+ case MRP_LUA_DOUBLE_ARRAY:
+ lua_pushnumber(L, ((double *)items)[i]);
+ break;
+ default:
+ lua_pop(L, 1);
+ return -1;
+ }
+
+ lua_rawseti(L, -2, i + 1);
+ }
+
+ return 1;
+}
+
+
int mrp_lua_set_member(void *data, lua_State *L, char *err, size_t esize)
{
userdata_t *u = (userdata_t *)data - 1;
int midx = class_member(u, L, -2);
mrp_lua_class_member_t *m;
mrp_lua_value_t v;
- int vtype;
+ int vtype, etype;
+ void *items;
+ size_t nitem;
if (midx < 0)
goto notfound;
m->name, data, u);
if (m->flags & MRP_LUA_CLASS_READONLY && !u->initializing)
- return seterr(err, esize, "%s.%s of Lua object is readonly",
+ return seterr(L, err, esize, "%s.%s of Lua object is readonly",
u->def->class_name, m->name);
switch (m->type) {
case MRP_LUA_STRING:
if (vtype != LUA_TSTRING && vtype != LUA_TNIL)
- return seterr(err, esize, "%s.%s expects string or nil, got %s",
+ return seterr(L, err, esize, "%s.%s expects string or nil, got %s",
u->def->class_name, m->name,
lua_typename(L, vtype), m->name);
case MRP_LUA_INTEGER:
if (vtype != LUA_TNUMBER)
- return seterr(err, esize, "%s.%s expects number, got %s",
+ return seterr(L, err, esize, "%s.%s expects number, got %s",
u->def->class_name, m->name, lua_typename(L, vtype));
v.s32 = lua_tointeger(L, -1);
case MRP_LUA_DOUBLE:
if (vtype != LUA_TNUMBER)
- return seterr(err, esize, "%s.%s expects number, got %s",
+ return seterr(L, err, esize, "%s.%s expects number, got %s",
u->def->class_name, m->name, lua_typename(L, vtype));
v.dbl = lua_tonumber(L, -1);
case MRP_LUA_LFUNC:
if (vtype != LUA_TFUNCTION && vtype != LUA_TNIL)
- return seterr(err, esize, "%s.%s expects function, got %s",
+ return seterr(L, err, esize, "%s.%s expects function, got %s",
u->def->class_name, m->name, lua_typename(L, vtype));
v.lfn = mrp_lua_object_ref_value(data, L, -1);
goto error;
case MRP_LUA_CFUNC:
- seterr(err, esize, "CFUNC is not implemented");
+ seterr(L, err, esize, "CFUNC is not implemented");
goto error;
case MRP_LUA_ANY:
else
goto error;
+ case MRP_LUA_STRING_ARRAY:
+ case MRP_LUA_BOOLEAN_ARRAY:
+ case MRP_LUA_INTEGER_ARRAY:
+ case MRP_LUA_DOUBLE_ARRAY:
+ items = NULL;
+ nitem = (size_t)-1;
+ etype = m->type;
+ if (mrp_lua_object_collect_array(L, -1, &items, &nitem, etype, true,
+ err, esize) < 0)
+ return -1;
+ else {
+ v.array.items = data + m->offs;
+ v.array.nitem = data + m->size;
+ *v.array.items = items;
+ *v.array.nitem = nitem;
+ }
+ goto ok;
+
default:
- seterr(err, esize, "type %d not implemented");
+ seterr(L, err, esize, "type %d not implemented");
break;
}
int midx = class_member(u, L, -1);
mrp_lua_class_member_t *m;
mrp_lua_value_t v;
+ void **items;
+ size_t *nitem;
if (midx < 0)
goto notfound;
goto ok;
case MRP_LUA_CFUNC:
- seterr(err, esize, "CFUNC is not implemented");
+ seterr(L, err, esize, "CFUNC is not implemented");
goto error;
case MRP_LUA_ANY:
mrp_lua_object_deref_value(data, L, v.any, true);
goto ok;
+
+ case MRP_LUA_STRING_ARRAY:
+ case MRP_LUA_BOOLEAN_ARRAY:
+ case MRP_LUA_INTEGER_ARRAY:
+ case MRP_LUA_DOUBLE_ARRAY:
+ items = data + m->offs;
+ nitem = data + m->size;
+ if (mrp_lua_object_push_array(L, m->type, *items, *nitem) > 0)
+ goto ok;
+ else {
+ seterr(L, err, esize, "failed to push array");
+ goto error;
+ }
+
+ case MRP_LUA_NONE:
+ seterr(L, err, esize, "invalid type");
+ goto error;
}
ok:
goto error;
}
else {
- seterr(err, esize, "trying toinitialize unknown member %s.%s",
+ seterr(L, err, esize,
+ "trying toinitialize unknown member %s.%s",
u->def->class_name, n);
lua_pop(L, 2 + 1);
goto error;
\
lua_pop(_L, 1))
+
+/** _i=loopcount, _t=table idx, _type=key type, _n=field, _l=len or idx */
+#define MRP_LUA_FOREACH_ALL(_L, _i, _t, _type, _n, _l) \
+ for (lua_pushnil(_L), _i = 0; \
+ \
+ (lua_next(_L, _t) && \
+ (((_type = lua_type(_L, -2)) == LUA_TSTRING ? \
+ (_n = lua_tolstring(_L, -2, &_l)) : (_n = NULL)) || \
+ ((_type == LUA_TNIL ? \
+ !(_n = NULL, _l = 0) : \
+ (_type == LUA_TNUMBER ? \
+ (_n = NULL, _l = lua_tointeger(_L, -2)) : \
+ !(_n = NULL, _l = 0)) || \
+ _type != LUA_TSTRING)))); \
+ \
+ lua_pop(_L, 1), _i++)
+
+
enum mrp_lua_event_type_e {
MRP_LUA_OBJECT_DESTRUCTION = 1,
};
+static inline int mrp_lua_absidx(lua_State *L, int idx) {
+ return ((idx < 0) ? lua_gettop(L) + idx + 1 : idx);
+}
+
/*
* pre-declared class members
*/
*/
typedef enum {
+ MRP_LUA_NONE = 0,
MRP_LUA_STRING = 1, /* string member */
MRP_LUA_BOOLEAN, /* boolean member */
MRP_LUA_INTEGER, /* integer member */
MRP_LUA_DOUBLE, /* double member */
MRP_LUA_LFUNC, /* Lua function member */
MRP_LUA_CFUNC, /* C-function member */
+ MRP_LUA_STRING_ARRAY, /* string array member */
+ MRP_LUA_BOOLEAN_ARRAY, /* boolean array member */
+ MRP_LUA_INTEGER_ARRAY, /* integer array member */
+ MRP_LUA_DOUBLE_ARRAY, /* double array member */
MRP_LUA_ANY /* member of any type */
} mrp_lua_type_t;
double dbl; /* double value */
int lfn; /* Lua function (ref) value */
void *cfn; /* C function (bridge) value */
+ struct { /* array value */
+ void **items; /* array items */
+ size_t *nitem; /* number of items */
+ } array;
int any; /* Lua reference */
};
char *name; /* member name */
mrp_lua_type_t type; /* memebr type */
size_t offs; /* offset within type buffer */
+ size_t size; /* offset to size within type buffer */
mrp_lua_setter_t setter; /* setter if any */
mrp_lua_getter_t getter; /* getter if any */
int flags; /* member flags */
* MRP_LUA_CLASS_NOTIFY. MRP_LUA_CLASS_NOFLAGS is available
* to denote no specific flag set.
*/
-#define MRP_LUA_CLASS_MEMBER(_type, _name, _offs, _set, _get, _flags) \
+#define MRP_LUA_CLASS_MEMBER(_type, _name, _offs, _size, _set, _get, _flags) \
{ \
.name = _name, \
.type = _type, \
.offs = _offs, \
+ .size = _size, \
.setter = _set, \
.getter = _get, \
.flags = _flags, \
*/
/** Declare an automatic string member. */
-#define MRP_LUA_CLASS_STRING(_name, _offs, _set, _get, _flags) \
- MRP_LUA_CLASS_MEMBER(MRP_LUA_STRING, _name, _offs, _set, _get, _flags)
+#define MRP_LUA_CLASS_STRING(_name, _offs, _set, _get, _flags) \
+ MRP_LUA_CLASS_MEMBER(MRP_LUA_STRING, _name, _offs, 0, _set, _get, _flags)
/** Declare an automatic (signed 32-bit) integer member. */
-#define MRP_LUA_CLASS_INTEGER(_name, _offs, _set, _get, _flags) \
- MRP_LUA_CLASS_MEMBER(MRP_LUA_INTEGER, _name, _offs, _set, _get, _flags)
+#define MRP_LUA_CLASS_INTEGER(_name, _offs, _set, _get, _flags) \
+ MRP_LUA_CLASS_MEMBER(MRP_LUA_INTEGER, _name, _offs, 0, _set, _get, _flags)
/** Declare an automatic double-precision floating point member. */
-#define MRP_LUA_CLASS_DOUBLE(_name, _offs, _set, _get, _flags) \
- MRP_LUA_CLASS_MEMBER(MRP_LUA_DOUBLE, _name, _offs, _set, _get, _flags),
+#define MRP_LUA_CLASS_DOUBLE(_name, _offs, _set, _get, _flags) \
+ MRP_LUA_CLASS_MEMBER(MRP_LUA_DOUBLE, _name, _offs, 0, _set, _get, _flags),
/** Declare an automatic boolean member. */
-#define MRP_LUA_CLASS_BOOLEAN(_name, _offs, _set, _get, _flags) \
- MRP_LUA_CLASS_MEMBER(MRP_LUA_BOOLEAN, _name, _offs, _set, _get, _flags)
+#define MRP_LUA_CLASS_BOOLEAN(_name, _offs, _set, _get, _flags) \
+ MRP_LUA_CLASS_MEMBER(MRP_LUA_BOOLEAN, _name, _offs, 0, _set, _get, _flags)
/** Declare an automatic Lua function member. */
-#define MRP_LUA_CLASS_LFUNC(_name, _offs, _set, _get, _flags) \
- MRP_LUA_CLASS_MEMBER(MRP_LUA_LFUNC, _name, _offs, _set, _get, _flags)
+#define MRP_LUA_CLASS_LFUNC(_name, _offs, _set, _get, _flags) \
+ MRP_LUA_CLASS_MEMBER(MRP_LUA_LFUNC, _name, _offs, 0, _set, _get, _flags)
/** Declare an automatic C function member. */
-#define MRP_LUA_CLASS_CFUNC(_name, _offs, _set, _get, _flags) \
- MRP_LUA_CLASS_MEMBER(MRP_LUA_CFUNC, _name, _offs, _set, _get, _flags)
+#define MRP_LUA_CLASS_CFUNC(_name, _offs, _set, _get, _flags) \
+ MRP_LUA_CLASS_MEMBER(MRP_LUA_CFUNC, _name, _offs, 0, _set, _get, _flags)
/** Declare an automatic member with a value of any acceptable type. */
#define MRP_LUA_CLASS_ANY(_name, _offs, _set, _get, _flags) \
- MRP_LUA_CLASS_MEMBER(MRP_LUA_ANY, _name, _offs, _set, _get, _flags)
+ MRP_LUA_CLASS_MEMBER(MRP_LUA_ANY, _name, _offs, 0, _set, _get, _flags)
+
+/** Declare an automatic array and size member of the given type. */
+#define MRP_LUA_CLASS_ARRAY(_name, _type, _poffs, _noffs, _set, _get, _flags) \
+ MRP_LUA_CLASS_MEMBER(MRP_LUA_##_type##_ARRAY, _name, \
+ _poffs, _noffs, _set, _get, _flags)
typedef struct mrp_lua_classdef_s mrp_lua_classdef_t;
typedef void (*mrp_lua_class_notify_t)(void *data, lua_State *L, int member);
+
struct mrp_lua_classdef_s {
const char *class_name;
const char *class_id;
int mrp_lua_init_members(void *data, lua_State *L, int idx,
char *err, size_t esize);
+int mrp_lua_object_collect_array(lua_State *L, int tidx, void **itemsp,
+ size_t *nitemp, int expected, int copy,
+ char *e, size_t esize);
+void mrp_lua_object_free_array(void **itemsp, size_t *nitemp, int type);
#endif /* __MURPHY_LUA_OBJECT_H__ */