mirror of
https://github.com/php-win-ext/php-lua.git
synced 2026-03-24 09:02:13 +01:00
Use proper internal object storage rather than private props. Favor NULL clone_obj handler over empty private __clone method. Favor free_obj handler over __destruct() method.
885 lines
22 KiB
C
Executable File
885 lines
22 KiB
C
Executable File
/*
|
|
+----------------------------------------------------------------------+
|
|
| Lua |
|
|
+----------------------------------------------------------------------+
|
|
| This source file is subject to version 3.01 of the PHP license, |
|
|
| that is bundled with this package in the file LICENSE, and is |
|
|
| available through the world-wide-web at the following url: |
|
|
| http://www.php.net/license/3_01.txt |
|
|
| If you did not receive a copy of the PHP license and are unable to |
|
|
| obtain it through the world-wide-web, please send a note to |
|
|
| license@php.net so we can mail you a copy immediately. |
|
|
+----------------------------------------------------------------------+
|
|
| Author : Johannes Schlueter <johannes@php.net> |
|
|
| Xinchen Hui <laruence@php.net> |
|
|
| Marcelo Araujo <msaraujo@php.net> |
|
|
| Helmut Januschka <helmut@januschka.com> |
|
|
+----------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "php.h"
|
|
#include "php_ini.h"
|
|
#include "ext/standard/info.h"
|
|
#include "Zend/zend_exceptions.h"
|
|
#include "php_lua.h"
|
|
#include "lua_closure.h"
|
|
|
|
zend_class_entry *lua_ce;
|
|
zend_class_entry *lua_exception_ce;
|
|
static zend_object_handlers lua_object_handlers;
|
|
|
|
/** {{{ ARG_INFO
|
|
*
|
|
*/
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_lua_call, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, method)
|
|
ZEND_ARG_INFO(0, args)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_lua_assign, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, name)
|
|
ZEND_ARG_INFO(0, value)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_lua_register, 0, 0, 2)
|
|
ZEND_ARG_INFO(0, name)
|
|
ZEND_ARG_INFO(0, function)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_lua_include, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, file)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_lua_eval, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, statements)
|
|
ZEND_END_ARG_INFO()
|
|
|
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_lua_free, 0, 0, 1)
|
|
ZEND_ARG_INFO(0, closure)
|
|
ZEND_END_ARG_INFO()
|
|
/* }}} */
|
|
|
|
/* {{{ lua_module_entry
|
|
*/
|
|
zend_module_entry lua_module_entry = {
|
|
#if ZEND_MODULE_API_NO >= 20010901
|
|
STANDARD_MODULE_HEADER,
|
|
#endif
|
|
"lua",
|
|
NULL,
|
|
PHP_MINIT(lua),
|
|
PHP_MSHUTDOWN(lua),
|
|
NULL,
|
|
NULL,
|
|
PHP_MINFO(lua),
|
|
#if ZEND_MODULE_API_NO >= 20010901
|
|
PHP_LUA_VERSION,
|
|
#endif
|
|
STANDARD_MODULE_PROPERTIES
|
|
};
|
|
/* }}} */
|
|
|
|
#ifdef COMPILE_DL_LUA
|
|
ZEND_GET_MODULE(lua)
|
|
#endif
|
|
|
|
/** {{{ static void php_lua_stack_dump(lua_State* L)
|
|
* just for debug
|
|
*/
|
|
static void php_lua_stack_dump(lua_State* L) {
|
|
int i = 1;
|
|
int n = lua_gettop(L);
|
|
printf("The Length of stack is %d\n", n);
|
|
for (; i <= n; ++i) {
|
|
int t = lua_type(L, i);
|
|
printf("%s:", lua_typename(L, t));
|
|
switch(t) {
|
|
case LUA_TNUMBER:
|
|
printf("%f", lua_tonumber(L, i));
|
|
break;
|
|
case LUA_TSTRING:
|
|
printf("%s", lua_tostring(L, i));
|
|
break;
|
|
case LUA_TTABLE:
|
|
break;
|
|
case LUA_TFUNCTION:
|
|
break;
|
|
case LUA_TNIL:
|
|
printf("NULL");
|
|
break;
|
|
case LUA_TBOOLEAN:
|
|
printf("%s", lua_toboolean(L, i) ? "TRUE" : "FALSE");
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ static int php_lua_atpanic(lua_State *L)
|
|
*/
|
|
static int php_lua_atpanic(lua_State *L) {
|
|
php_error_docref(NULL, E_ERROR, "lua panic (%s)", lua_tostring(L, 1));
|
|
lua_pop(L, 1);
|
|
zend_bailout();
|
|
return 0;
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ static int php_lua_print(lua_State *L)
|
|
*/
|
|
static int php_lua_print(lua_State *L) {
|
|
zval rv;
|
|
int i = 0;
|
|
int nargs = lua_gettop(L);
|
|
|
|
for (i = 1; i <= nargs; ++i) {
|
|
php_lua_get_zval_from_lua(L, i, NULL, &rv);
|
|
zend_print_zval_r(&rv, 1);
|
|
zval_ptr_dtor(&rv);
|
|
}
|
|
return 0;
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ static void * php_lua_alloc_function(void *ud, void *ptr, size_t osize, size_t nsize)
|
|
* the memory-allocation function used by Lua states.
|
|
*/
|
|
static void * php_lua_alloc_function(void *ud, void *ptr, size_t osize, size_t nsize) {
|
|
(void) osize;
|
|
(void) nsize;
|
|
|
|
if (nsize) {
|
|
if (ptr) {
|
|
return erealloc(ptr, nsize);
|
|
}
|
|
return emalloc(nsize);
|
|
} else {
|
|
if (ptr) {
|
|
efree(ptr);
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
/* }}} */
|
|
|
|
static void php_lua_dtor_object(zend_object *object) /* {{{ */ {
|
|
php_lua_object *lua_obj = php_lua_obj_from_obj(object);
|
|
|
|
zend_object_std_dtor(&(lua_obj->obj));
|
|
}
|
|
/* }}} */
|
|
|
|
static void php_lua_free_object(zend_object *object) /* {{{ */ {
|
|
php_lua_object *lua_obj = php_lua_obj_from_obj(object);
|
|
|
|
if (lua_obj->L) {
|
|
lua_close(lua_obj->L);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ static zend_object_value php_lua_create_object(zend_class_entry *ce)
|
|
*/
|
|
zend_object *php_lua_create_object(zend_class_entry *ce)
|
|
{
|
|
php_lua_object* intern;
|
|
lua_State *L;
|
|
|
|
L = luaL_newstate();
|
|
|
|
lua_atpanic(L, php_lua_atpanic);
|
|
|
|
intern = emalloc(sizeof(php_lua_object) + sizeof(zval) * (ce->default_properties_count - 1));
|
|
|
|
if (!intern) {
|
|
php_error_docref(NULL, E_ERROR, "alloc memory for lua object failed");
|
|
}
|
|
|
|
intern->L = L;
|
|
|
|
zend_object_std_init(&intern->obj, ce);
|
|
object_properties_init(&intern->obj, ce);
|
|
|
|
intern->obj.handlers = &lua_object_handlers;
|
|
|
|
return &intern->obj;
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ static zval * php_lua_read_property(zval *object, zval *member, int type)
|
|
*/
|
|
zval *php_lua_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv){
|
|
lua_State *L = NULL;
|
|
zval *tmp_member = NULL;
|
|
|
|
if (type != BP_VAR_R) {
|
|
ZVAL_NULL(rv);
|
|
return rv;
|
|
}
|
|
|
|
if (Z_TYPE_P(member) != IS_STRING) {
|
|
*tmp_member = *member;
|
|
zval_copy_ctor(tmp_member);
|
|
convert_to_string(tmp_member);
|
|
member = tmp_member;
|
|
}
|
|
|
|
L = (Z_LUAVAL_P(object))->L;
|
|
#if (LUA_VERSION_NUM < 502)
|
|
lua_getfield(L, LUA_GLOBALSINDEX, Z_STRVAL_P(member));
|
|
#else
|
|
lua_getglobal(L, Z_STRVAL_P(member));
|
|
#endif
|
|
php_lua_get_zval_from_lua(L, -1, object, rv);
|
|
lua_pop(L, 1);
|
|
return rv;
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ static void php_lua_write_property(zval *object, zval *member, zval *value)
|
|
*/
|
|
static void php_lua_write_property(zval *object, zval *member, zval *value, void ** key) {
|
|
lua_State *L = NULL;
|
|
zval *tmp_member = NULL;
|
|
|
|
if (Z_TYPE_P(member) != IS_STRING) {
|
|
*tmp_member = *member;
|
|
zval_copy_ctor(tmp_member);
|
|
convert_to_string(tmp_member);
|
|
member = tmp_member;
|
|
}
|
|
|
|
L = (Z_LUAVAL_P(object))->L;
|
|
|
|
#if (LUA_VERSION_NUM < 502)
|
|
php_lua_send_zval_to_lua(L, member);
|
|
php_lua_send_zval_to_lua(L, value);
|
|
|
|
lua_settable(L, LUA_GLOBALSINDEX);
|
|
#else
|
|
php_lua_send_zval_to_lua(L, value);
|
|
lua_setglobal(L, Z_STRVAL_P(member));
|
|
#endif
|
|
|
|
if (tmp_member) {
|
|
zval_ptr_dtor(tmp_member);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ static int php_lua_call_callback(lua_State *L)
|
|
*/
|
|
static int php_lua_call_callback(lua_State *L) {
|
|
int order = 0;
|
|
zval retval;
|
|
zval *func = NULL;
|
|
zval *callbacks = NULL;
|
|
|
|
order = lua_tonumber(L, lua_upvalueindex(1));
|
|
|
|
callbacks = zend_read_static_property(lua_ce, ZEND_STRL("_callbacks"), 1);
|
|
|
|
if (ZVAL_IS_NULL(callbacks)) {
|
|
return 0;
|
|
}
|
|
|
|
func = zend_hash_index_find(Z_ARRVAL_P(callbacks), order);
|
|
|
|
if (!zend_is_callable(func, 0, NULL)) {
|
|
return 0;
|
|
} else {
|
|
zval *params;
|
|
int i = 0;
|
|
int arg_num = lua_gettop(L);
|
|
|
|
params = safe_emalloc(sizeof(zval), arg_num, 0);
|
|
for (i = 0; i < arg_num; i++) {
|
|
php_lua_get_zval_from_lua(L, -(arg_num - i), NULL, ¶ms[i]);
|
|
}
|
|
|
|
call_user_function(EG(function_table), NULL, func, &retval, arg_num, params);
|
|
php_lua_send_zval_to_lua(L, &retval);
|
|
|
|
for (i = 0; i<arg_num; i++) {
|
|
zval_ptr_dtor(¶ms[i]);
|
|
|
|
}
|
|
efree(params);
|
|
zval_ptr_dtor(&retval);
|
|
return 1;
|
|
}
|
|
|
|
}
|
|
/* }}} */
|
|
|
|
zval *php_lua_get_zval_from_lua(lua_State *L, int index, zval *lua_obj, zval *rv) /* {{{ */ {
|
|
switch (lua_type(L, index)) {
|
|
case LUA_TNIL:
|
|
ZVAL_NULL(rv);
|
|
break;
|
|
case LUA_TBOOLEAN:
|
|
ZVAL_BOOL(rv, lua_toboolean(L, index));
|
|
break;
|
|
case LUA_TNUMBER:
|
|
ZVAL_DOUBLE(rv, lua_tonumber(L, index));
|
|
break;
|
|
case LUA_TSTRING:
|
|
{
|
|
char *val = NULL;
|
|
size_t len = 0;
|
|
|
|
val = (char *)lua_tolstring(L, index, &len);
|
|
ZVAL_STRINGL(rv, val, len);
|
|
}
|
|
break;
|
|
case LUA_TTABLE:
|
|
array_init(rv);
|
|
lua_pushnil(L); /* first key */
|
|
while (lua_next(L, index-1) != 0) {
|
|
zval key, val;
|
|
|
|
/* uses 'key' (at index -2) and 'value' (at index -1) */
|
|
if (!php_lua_get_zval_from_lua(L, -2, lua_obj, &key)) {
|
|
break;
|
|
}
|
|
if (!php_lua_get_zval_from_lua(L, -1, lua_obj, &val)) {
|
|
zval_ptr_dtor(&key);
|
|
/* there is a warning already in php_lua_get_zval_from_lua */
|
|
break;
|
|
}
|
|
|
|
switch (Z_TYPE(key)) {
|
|
case IS_DOUBLE:
|
|
case IS_LONG:
|
|
add_index_zval(rv, Z_DVAL(key), &val);
|
|
break;
|
|
case IS_STRING:
|
|
add_assoc_zval(rv, Z_STRVAL(key), &val);
|
|
zval_ptr_dtor(&key);
|
|
break;
|
|
case IS_ARRAY:
|
|
case IS_OBJECT:
|
|
default:
|
|
break;
|
|
}
|
|
lua_pop(L, 1);
|
|
}
|
|
break;
|
|
case LUA_TFUNCTION:
|
|
{
|
|
long ref_id = 0;
|
|
if (!lua_obj) {
|
|
php_error_docref(NULL, E_WARNING, "corrupted Lua object");
|
|
break;
|
|
}
|
|
|
|
lua_pushvalue(L, index);
|
|
ref_id = luaL_ref(L, LUA_REGISTRYINDEX);
|
|
|
|
if (!php_lua_closure_instance(rv, ref_id, lua_obj)) {
|
|
php_error_docref(NULL, E_WARNING, "failed to initialize closure object");
|
|
ZVAL_NULL(rv);
|
|
return NULL;
|
|
}
|
|
}
|
|
break;
|
|
case LUA_TUSERDATA:
|
|
case LUA_TTHREAD:
|
|
case LUA_TLIGHTUSERDATA:
|
|
default:
|
|
php_error_docref(NULL, E_WARNING, "unsupported type '%s' for php",
|
|
lua_typename(L, lua_type(L, index)));
|
|
ZVAL_NULL(rv);
|
|
return NULL;
|
|
}
|
|
return rv;
|
|
}
|
|
/* }}} */
|
|
|
|
int php_lua_send_zval_to_lua(lua_State *L, zval *val) /* {{{ */ {
|
|
|
|
try_again:
|
|
switch (Z_TYPE_P(val)) {
|
|
case IS_TRUE:
|
|
lua_pushboolean(L, 1);
|
|
break;
|
|
case IS_FALSE:
|
|
lua_pushboolean(L, 0);
|
|
break;
|
|
case IS_UNDEF:
|
|
case IS_NULL:
|
|
lua_pushnil(L);
|
|
break;
|
|
case IS_DOUBLE:
|
|
lua_pushnumber(L, Z_DVAL_P(val));
|
|
break;
|
|
case IS_LONG:
|
|
lua_pushnumber(L, Z_LVAL_P(val));
|
|
break;
|
|
case IS_STRING:
|
|
lua_pushlstring(L, Z_STRVAL_P(val), Z_STRLEN_P(val));
|
|
break;
|
|
case IS_OBJECT:
|
|
case IS_ARRAY:
|
|
{
|
|
if (zend_is_callable(val, 0, NULL)) {
|
|
zval *callbacks;
|
|
|
|
callbacks = zend_read_static_property(lua_ce, ZEND_STRL("_callbacks"), 1);
|
|
|
|
if (ZVAL_IS_NULL(callbacks)) {
|
|
array_init(callbacks);
|
|
}
|
|
|
|
lua_pushnumber(L, zend_hash_num_elements(Z_ARRVAL_P(callbacks)));
|
|
lua_pushcclosure(L, php_lua_call_callback, 1);
|
|
|
|
zval_add_ref(val);
|
|
add_next_index_zval(callbacks, val);
|
|
} else {
|
|
zval *v;
|
|
ulong longkey;
|
|
zend_string *key;
|
|
zval zkey;
|
|
|
|
HashTable *ht = HASH_OF(val);
|
|
if (ZEND_HASH_APPLY_PROTECTION(ht)) {
|
|
ZEND_HASH_INC_APPLY_COUNT(ht);
|
|
if (ZEND_HASH_GET_APPLY_COUNT(ht) > 1) {
|
|
php_error_docref(NULL, E_ERROR, "recursion found");
|
|
ZEND_HASH_DEC_APPLY_COUNT(ht);
|
|
break;
|
|
}
|
|
}
|
|
|
|
lua_newtable(L);
|
|
|
|
ZEND_HASH_FOREACH_KEY_VAL_IND(ht, longkey, key, v) {
|
|
if (key) {
|
|
ZVAL_STR(&zkey, key);
|
|
} else {
|
|
ZVAL_LONG(&zkey, longkey);
|
|
}
|
|
php_lua_send_zval_to_lua(L, &zkey);
|
|
php_lua_send_zval_to_lua(L, v);
|
|
lua_settable(L, -3);
|
|
} ZEND_HASH_FOREACH_END();
|
|
|
|
if (ZEND_HASH_APPLY_PROTECTION(ht)) {
|
|
ZEND_HASH_DEC_APPLY_COUNT(ht);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case IS_REFERENCE:
|
|
ZVAL_DEREF(val);
|
|
goto try_again;
|
|
break;
|
|
case IS_INDIRECT:
|
|
val = Z_INDIRECT_P(val);
|
|
goto try_again;
|
|
break;
|
|
default:
|
|
php_error_docref(NULL, E_ERROR, "unsupported type `%s' for lua", zend_zval_type_name(val));
|
|
lua_pushnil(L);
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/* }}} */
|
|
|
|
/*** {{{ static int php_lua_arg_apply_func(void *data, void *L)
|
|
*/
|
|
static int php_lua_arg_apply_func(void *data, void *L) {
|
|
php_lua_send_zval_to_lua((lua_State*)L, (zval*)data);
|
|
return ZEND_HASH_APPLY_KEEP;
|
|
} /* }}} */
|
|
|
|
static zval *php_lua_call_lua_function(zval *lua_obj, zval *func, zval *args, int use_self, zval *retval) /* {{{ */ {
|
|
int bp = 0;
|
|
int sp = 0;
|
|
int arg_num = 0;
|
|
zval rv;
|
|
lua_State *L;
|
|
|
|
L = (Z_LUAVAL_P(lua_obj))->L;
|
|
|
|
if (IS_ARRAY == Z_TYPE_P(func)) {
|
|
zval *t, *f;
|
|
if ((t = zend_hash_index_find(Z_ARRVAL_P(func), 0)) == NULL || Z_TYPE_P(t) != IS_STRING
|
|
|| (f = zend_hash_index_find(Z_ARRVAL_P(func), 1)) == NULL || Z_TYPE_P(f) != IS_STRING) {
|
|
/* as johannes suggesting use exceptioni to distinguish the error from a lua function return false
|
|
php_error_docref(NULL, E_WARNING,
|
|
"invalid lua function, argument must be an array which contain two elements: array('table', 'method')");
|
|
*/
|
|
zend_throw_exception_ex(lua_exception_ce, 0,
|
|
"invalid lua function, argument must be an array which contain two elements: array('table', 'method')");
|
|
return NULL;
|
|
}
|
|
#if (LUA_VERSION_NUM < 502)
|
|
lua_getfield(L, LUA_GLOBALSINDEX, Z_STRVAL_P(t));
|
|
#else
|
|
lua_getglobal(L, Z_STRVAL_P(t));
|
|
#endif
|
|
if (LUA_TTABLE != lua_type(L, lua_gettop(L))) {
|
|
lua_pop(L, -1);
|
|
zend_throw_exception_ex(lua_exception_ce, 0, "invalid lua table '%s'", Z_STRVAL_P(t));
|
|
return NULL;
|
|
}
|
|
bp = lua_gettop(L);
|
|
lua_getfield(L, -1, Z_STRVAL_P(f));
|
|
if (LUA_TFUNCTION != lua_type(L, lua_gettop(L))) {
|
|
lua_pop(L, -2);
|
|
zend_throw_exception_ex(lua_exception_ce, 0, "invalid lua table function '%s'.%s", Z_STRVAL_P(t), Z_STRVAL_P(f));
|
|
return NULL;
|
|
}
|
|
} else if (IS_STRING == Z_TYPE_P(func)) {
|
|
bp = lua_gettop(L);
|
|
#if (LUA_VERSION_NUM < 502)
|
|
lua_getfield(L, LUA_GLOBALSINDEX, Z_STRVAL_P(func));
|
|
#else
|
|
lua_getglobal(L, Z_STRVAL_P(func));
|
|
#endif
|
|
if (LUA_TFUNCTION != lua_type(L, lua_gettop(L))) {
|
|
lua_pop(L, -1);
|
|
zend_throw_exception_ex(lua_exception_ce, 0, "invalid lua function '%s'", Z_STRVAL_P(func));
|
|
return NULL;
|
|
}
|
|
} else if (IS_OBJECT == Z_TYPE_P(func)
|
|
&& instanceof_function(Z_OBJCE_P(func), php_lua_get_closure_ce())) {
|
|
lua_closure_object *closure_obj = php_lua_closure_object_from_zend_object(Z_OBJ_P(func));
|
|
bp = lua_gettop(L);
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, closure_obj->closure);
|
|
if (LUA_TFUNCTION != lua_type(L, lua_gettop(L))) {
|
|
lua_pop(L, -1);
|
|
zend_throw_exception_ex(lua_exception_ce, 0, "call to lua closure failed");
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (use_self) {
|
|
lua_pushvalue(L, -2);
|
|
lua_remove(L, -2);
|
|
arg_num++;
|
|
}
|
|
|
|
if (args) {
|
|
arg_num += zend_hash_num_elements(Z_ARRVAL_P(args));
|
|
zend_hash_apply_with_argument(Z_ARRVAL_P(args), (apply_func_arg_t)php_lua_arg_apply_func, (void *)L);
|
|
}
|
|
|
|
if (lua_pcall(L, arg_num, LUA_MULTRET, 0) != LUA_OK) {
|
|
php_error_docref(NULL, E_WARNING,
|
|
"call to lua function %s failed", lua_tostring(L, -1));
|
|
lua_pop(L, lua_gettop(L) - bp);
|
|
return NULL;
|
|
}
|
|
|
|
sp = lua_gettop(L) - bp;
|
|
|
|
if (!sp) {
|
|
ZVAL_NULL(retval);
|
|
} else if (sp == 1) {
|
|
php_lua_get_zval_from_lua(L, -1, lua_obj, retval);
|
|
} else {
|
|
zval rv;
|
|
int i = 0;
|
|
array_init(retval);
|
|
for (i = -sp; i < 0; i++) {
|
|
php_lua_get_zval_from_lua(L, i, lua_obj, &rv);
|
|
add_next_index_zval(retval, &rv);
|
|
}
|
|
}
|
|
|
|
lua_pop(L, sp);
|
|
|
|
if (IS_ARRAY == Z_TYPE_P(func)) {
|
|
lua_pop(L, -1);
|
|
}
|
|
|
|
return retval;
|
|
} /* }}} */
|
|
|
|
/** {{{ proto Lua::eval(string $lua_chunk)
|
|
* eval a lua chunk
|
|
*/
|
|
PHP_METHOD(lua, eval) {
|
|
lua_State *L;
|
|
char *statements;
|
|
long bp, len;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &statements, &len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
L = (Z_LUAVAL_P(getThis()))->L;
|
|
|
|
bp = lua_gettop(L);
|
|
if ((ret = luaL_loadbuffer(L, statements, len, "line")) != LUA_OK || (ret = lua_pcall(L, 0, LUA_MULTRET, 0) != LUA_OK)) {
|
|
zend_throw_exception_ex(lua_exception_ce, ret, "%s", lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
RETURN_FALSE;
|
|
} else {
|
|
int ret_count;
|
|
|
|
ret_count = lua_gettop(L) - bp;
|
|
if (ret_count > 1) {
|
|
zval rv;
|
|
int i = 0;
|
|
array_init(return_value);
|
|
for (i = -ret_count; i<0; i++) {
|
|
php_lua_get_zval_from_lua(L, i, getThis(), &rv);
|
|
add_next_index_zval(return_value, &rv);
|
|
}
|
|
} else if (ret_count) {
|
|
php_lua_get_zval_from_lua(L, -1, getThis(), return_value);
|
|
}
|
|
lua_pop(L, ret_count);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ proto Lua::include(string $file)
|
|
* run a lua script file
|
|
*/
|
|
PHP_METHOD(lua, include) {
|
|
lua_State *L;
|
|
char *file;
|
|
size_t bp, len;
|
|
int ret;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &file, &len) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (php_check_open_basedir(file)) {
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
L = (Z_LUAVAL_P(getThis()))->L;
|
|
|
|
bp = lua_gettop(L);
|
|
if ((ret = luaL_loadfile(L, file)) != LUA_OK || (ret = lua_pcall(L, 0, LUA_MULTRET, 0) != LUA_OK)) {
|
|
zend_throw_exception_ex(lua_exception_ce, ret, "%s", lua_tostring(L, -1));
|
|
lua_pop(L, 1);
|
|
RETURN_FALSE;
|
|
} else {
|
|
int ret_count;
|
|
|
|
ret_count = lua_gettop(L) - bp;
|
|
if (ret_count > 1) {
|
|
zval rv;
|
|
int i = 0;
|
|
array_init(return_value);
|
|
for (i = -ret_count; i<0; i++) {
|
|
php_lua_get_zval_from_lua(L, i, getThis(), &rv);
|
|
add_next_index_zval(return_value, &rv);
|
|
}
|
|
} else if (ret_count) {
|
|
php_lua_get_zval_from_lua(L, -1, getThis(), return_value);
|
|
}
|
|
lua_pop(L, ret_count);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ proto Lua::call(mixed $function, array $args, bool $use_self)
|
|
*/
|
|
PHP_METHOD(lua, call) {
|
|
long u_self = 0;
|
|
zval *func;
|
|
zval *args = NULL;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "z|al", &func, &args, &u_self) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
if (!(php_lua_call_lua_function(getThis(), func, args, u_self, return_value))) {
|
|
RETURN_FALSE;
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ proto Lua::assign(string $name, mix $value)
|
|
*/
|
|
PHP_METHOD(lua, assign) {
|
|
zval *name;
|
|
zval *value;
|
|
lua_State *L;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "zz", &name, &value) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
L = (Z_LUAVAL_P(getThis()))->L;
|
|
|
|
php_lua_send_zval_to_lua(L, value);
|
|
#if (LUA_VERSION_NUM < 502)
|
|
lua_setfield(L, LUA_GLOBALSINDEX, Z_STRVAL_P(name));
|
|
#else
|
|
lua_setglobal(L, Z_STRVAL_P(name));
|
|
#endif
|
|
|
|
RETURN_ZVAL(getThis(), 1, 0);
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ proto Lua::registerCallback(string $name, mix $value)
|
|
*/
|
|
PHP_METHOD(lua, registerCallback) {
|
|
char *name;
|
|
size_t len;
|
|
zval *func;
|
|
lua_State *L;
|
|
zval* callbacks;
|
|
|
|
if (zend_parse_parameters(ZEND_NUM_ARGS(),"sz", &name, &len, &func) == FAILURE) {
|
|
return;
|
|
}
|
|
|
|
L = (Z_LUAVAL_P(getThis()))->L;
|
|
|
|
callbacks = zend_read_static_property(lua_ce, ZEND_STRL("_callbacks"), 1);
|
|
|
|
if (ZVAL_IS_NULL(callbacks)) {
|
|
array_init(callbacks);
|
|
}
|
|
|
|
if (zend_is_callable(func, 0, NULL)) {
|
|
lua_pushnumber(L, zend_hash_num_elements(Z_ARRVAL_P(callbacks)));
|
|
lua_pushcclosure(L, php_lua_call_callback, 1);
|
|
lua_setglobal(L, name);
|
|
} else {
|
|
zend_throw_exception_ex(lua_exception_ce, 0, "invalid php callback");
|
|
RETURN_FALSE;
|
|
}
|
|
|
|
zval_add_ref(func);
|
|
add_next_index_zval(callbacks, func);
|
|
|
|
RETURN_ZVAL(getThis(), 1, 0);
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ proto Lua::getVersion()
|
|
*/
|
|
PHP_METHOD(lua, getVersion) {
|
|
RETURN_STRING(LUA_RELEASE);
|
|
}
|
|
/* }}} */
|
|
|
|
/** {{{ proto Lua::__construct()
|
|
*/
|
|
PHP_METHOD(lua, __construct) {
|
|
lua_State * L = (Z_LUAVAL_P(getThis()))->L;
|
|
|
|
luaL_openlibs(L);
|
|
lua_register(L, "print", php_lua_print);
|
|
if (ZEND_NUM_ARGS()) {
|
|
PHP_MN(lua_include)(INTERNAL_FUNCTION_PARAM_PASSTHRU);
|
|
}
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ lua_class_methods[]
|
|
*
|
|
*/
|
|
zend_function_entry lua_class_methods[] = {
|
|
PHP_ME(lua, __construct, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_CTOR)
|
|
PHP_ME(lua, eval, arginfo_lua_eval, ZEND_ACC_PUBLIC)
|
|
PHP_ME(lua, include, arginfo_lua_include, ZEND_ACC_PUBLIC)
|
|
PHP_ME(lua, call, arginfo_lua_call, ZEND_ACC_PUBLIC)
|
|
PHP_ME(lua, assign, arginfo_lua_assign, ZEND_ACC_PUBLIC)
|
|
PHP_ME(lua, getVersion, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_ALLOW_STATIC)
|
|
PHP_ME(lua, registerCallback, arginfo_lua_register, ZEND_ACC_PUBLIC)
|
|
PHP_MALIAS(lua, __call, call, arginfo_lua_call, ZEND_ACC_PUBLIC)
|
|
{NULL, NULL, NULL}
|
|
};
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_MINIT_FUNCTION
|
|
*/
|
|
PHP_MINIT_FUNCTION(lua) {
|
|
zend_class_entry ce;
|
|
|
|
INIT_CLASS_ENTRY(ce, "Lua", lua_class_methods);
|
|
|
|
REGISTER_LONG_CONSTANT("LUA_OK", LUA_OK, CONST_PERSISTENT | CONST_CS);
|
|
REGISTER_LONG_CONSTANT("LUA_YIELD", LUA_YIELD, CONST_PERSISTENT | CONST_CS);
|
|
REGISTER_LONG_CONSTANT("LUA_ERRRUN", LUA_ERRRUN, CONST_PERSISTENT | CONST_CS);
|
|
REGISTER_LONG_CONSTANT("LUA_ERRSYNTAX", LUA_ERRSYNTAX, CONST_PERSISTENT | CONST_CS);
|
|
REGISTER_LONG_CONSTANT("LUA_ERRMEM", LUA_ERRMEM, CONST_PERSISTENT | CONST_CS);
|
|
#ifdef LUA_ERRGCMM
|
|
REGISTER_LONG_CONSTANT("LUA_ERRGCMM", LUA_ERRGCMM, CONST_PERSISTENT | CONST_CS);
|
|
#endif
|
|
REGISTER_LONG_CONSTANT("LUA_ERRERR", LUA_ERRERR, CONST_PERSISTENT | CONST_CS);
|
|
REGISTER_LONG_CONSTANT("LUA_ERRFILE", LUA_ERRFILE, CONST_PERSISTENT | CONST_CS);
|
|
|
|
|
|
lua_ce = zend_register_internal_class(&ce);
|
|
|
|
lua_ce->create_object = php_lua_create_object;
|
|
memcpy(&lua_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
|
|
lua_object_handlers.offset = XtOffsetOf(php_lua_object, obj);
|
|
lua_object_handlers.dtor_obj = php_lua_dtor_object;
|
|
lua_object_handlers.free_obj = php_lua_free_object;
|
|
lua_object_handlers.clone_obj = NULL;
|
|
lua_object_handlers.write_property = php_lua_write_property;
|
|
lua_object_handlers.read_property = php_lua_read_property;
|
|
|
|
lua_ce->ce_flags |= ZEND_ACC_FINAL;
|
|
|
|
zend_declare_property_null(lua_ce, ZEND_STRL("_callbacks"), ZEND_ACC_STATIC|ZEND_ACC_PRIVATE);
|
|
zend_declare_class_constant_string(lua_ce, ZEND_STRL("LUA_VERSION"), LUA_RELEASE);
|
|
|
|
php_lua_closure_register();
|
|
|
|
INIT_CLASS_ENTRY(ce, "LuaException", NULL);
|
|
|
|
lua_exception_ce = zend_register_internal_class_ex(&ce, zend_exception_get_default());
|
|
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_MSHUTDOWN_FUNCTION
|
|
*/
|
|
PHP_MSHUTDOWN_FUNCTION(lua)
|
|
{
|
|
return SUCCESS;
|
|
}
|
|
/* }}} */
|
|
|
|
/* {{{ PHP_MINFO_FUNCTION
|
|
*/
|
|
PHP_MINFO_FUNCTION(lua)
|
|
{
|
|
php_info_print_table_start();
|
|
php_info_print_table_header(2, "lua support", "enabled");
|
|
php_info_print_table_row(2, "lua extension version", PHP_LUA_VERSION);
|
|
php_info_print_table_row(2, "lua release", LUA_RELEASE);
|
|
php_info_print_table_row(2, "lua copyright", LUA_COPYRIGHT);
|
|
php_info_print_table_row(2, "lua authors", LUA_AUTHORS);
|
|
php_info_print_table_end();
|
|
}
|
|
/* }}} */
|
|
|
|
/*
|
|
* Local variables:
|
|
* tab-width: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
* vim600: noet sw=4 ts=4 fdm=marker
|
|
* vim<600: noet sw=4 ts=4
|
|
*/
|