/***************************************************************************** * Variables handling *****************************************************************************/ static int vlclua_pushvalue( lua_State *L, int i_type, vlc_value_t val, bool b_error_void ) { switch( i_type & VLC_VAR_CLASS ) { case VLC_VAR_VOID: if( b_error_void ) vlclua_error( L ); else lua_pushnil( L ); break; case VLC_VAR_BOOL: lua_pushboolean( L, val.b_bool ); break; case VLC_VAR_INTEGER: lua_pushinteger( L, val.i_int ); break; case VLC_VAR_STRING: lua_pushstring( L, val.psz_string ); break; case VLC_VAR_FLOAT: lua_pushnumber( L, val.f_float ); break; case VLC_VAR_ADDRESS: vlclua_error( L ); break; default: vlclua_error( L ); } return 1; }
/***************************************************************************** * Variables handling *****************************************************************************/ static int vlclua_pushvalue( lua_State *L, int i_type, vlc_value_t val, bool b_error_void ) { switch( i_type & VLC_VAR_CLASS ) { case VLC_VAR_VOID: if( b_error_void ) vlclua_error( L ); else lua_pushnil( L ); break; case VLC_VAR_BOOL: lua_pushboolean( L, val.b_bool ); break; case VLC_VAR_INTEGER: lua_pushinteger( L, val.i_int ); break; case VLC_VAR_STRING: lua_pushstring( L, val.psz_string ); break; case VLC_VAR_FLOAT: lua_pushnumber( L, val.f_float ); break; case VLC_VAR_TIME: /* FIXME? (we're losing some precision, but does it really matter?) */ lua_pushnumber( L, ((double)val.i_time)/1000000. ); break; case VLC_VAR_ADDRESS: vlclua_error( L ); break; default: vlclua_error( L ); } return 1; }
static int vlclua_tovalue( lua_State *L, int i_type, vlc_value_t *val ) { switch( i_type & VLC_VAR_CLASS ) { case VLC_VAR_VOID: break; case VLC_VAR_BOOL: val->b_bool = luaL_checkboolean( L, -1 ); break; case VLC_VAR_INTEGER: val->i_int = (int)luaL_checkinteger( L, -1 ); break; case VLC_VAR_STRING: val->psz_string = (char*)luaL_checkstring( L, -1 ); /* XXX: Beware, this only stays valid as long as (L,-1) stays in the stack */ break; case VLC_VAR_FLOAT: val->f_float = luaL_checknumber( L, -1 ); break; case VLC_VAR_ADDRESS: vlclua_error( L ); break; default: vlclua_error( L ); } return 1; }
static int vlclua_from_charset( lua_State *L ) { if( lua_gettop( L ) < 2 ) return vlclua_error( L ); size_t i_in_bytes; const char *psz_input = luaL_checklstring( L, 2, &i_in_bytes ); if( i_in_bytes == 0 ) return vlclua_error( L ); const char *psz_charset = luaL_checkstring( L, 1 ); char *psz_output = FromCharset( psz_charset, psz_input, i_in_bytes ); lua_pushstring( L, psz_output ? psz_output : "" ); free( psz_output ); return 1; }
/***************************************************************************** * Variables handling *****************************************************************************/ int vlclua_pushvalue( lua_State *L, int i_type, vlc_value_t val ) { switch( i_type &= VLC_VAR_CLASS ) { case VLC_VAR_VOID: vlclua_error( L ); break; case VLC_VAR_BOOL: lua_pushboolean( L, val.b_bool ); break; case VLC_VAR_INTEGER: lua_pushinteger( L, val.i_int ); break; case VLC_VAR_STRING: lua_pushstring( L, val.psz_string ); break; case VLC_VAR_FLOAT: lua_pushnumber( L, val.f_float ); break; case VLC_VAR_TIME: /* FIXME? (we're losing some precision, but does it really matter?) */ lua_pushnumber( L, ((double)val.i_time)/1000000. ); break; case VLC_VAR_ADDRESS: vlclua_error( L ); break; case VLC_VAR_MUTEX: vlclua_error( L ); break; case VLC_VAR_LIST: { int i_count = val.p_list->i_count; int i; lua_createtable( L, i_count, 0 ); for( i = 0; i < i_count; i++ ) { lua_pushinteger( L, i+1 ); if( !vlclua_pushvalue( L, val.p_list->pi_types[i], val.p_list->p_values[i] ) ) lua_pushnil( L ); lua_settable( L, -3 ); } } break; default: vlclua_error( L ); } return 1; }
static int vlclua_config_set( lua_State *L ) { vlc_object_t *p_this = vlclua_get_this( L ); const char *psz_name = luaL_checkstring( L, 1 ); switch( config_GetType( p_this, psz_name ) ) { case VLC_VAR_STRING: config_PutPsz( p_this, psz_name, luaL_checkstring( L, 2 ) ); break; case VLC_VAR_INTEGER: config_PutInt( p_this, psz_name, luaL_checkinteger( L, 2 ) ); break; case VLC_VAR_BOOL: config_PutInt( p_this, psz_name, luaL_checkboolean( L, 2 ) ); break; case VLC_VAR_FLOAT: config_PutFloat( p_this, psz_name, luaL_checknumber( L, 2 ) ); break; default: return vlclua_error( L ); } return 0; }
/***************************************************************************** * Config handling *****************************************************************************/ static int vlclua_config_get( lua_State *L ) { vlc_object_t * p_this = vlclua_get_this( L ); const char *psz_name = luaL_checkstring( L, 1 ); switch( config_GetType( p_this, psz_name ) ) { case VLC_VAR_STRING: { char *psz = config_GetPsz( p_this, psz_name ); lua_pushstring( L, psz ); free( psz ); break; } case VLC_VAR_INTEGER: lua_pushinteger( L, config_GetInt( p_this, psz_name ) ); break; case VLC_VAR_BOOL: lua_pushboolean( L, config_GetInt( p_this, psz_name ) ); break; case VLC_VAR_FLOAT: lua_pushnumber( L, config_GetFloat( p_this, psz_name ) ); break; default: return vlclua_error( L ); } return 1; }
int vlclua_var_toggle_or_set( lua_State *L, vlc_object_t *p_obj, const char *psz_name ) { bool b_bool; if( lua_gettop( L ) > 1 ) return vlclua_error( L ); if( lua_gettop( L ) == 0 ) { b_bool = var_ToggleBool( p_obj, psz_name ); goto end; } /* lua_gettop( L ) == 1 */ const char *s = luaL_checkstring( L, -1 ); lua_pop( L, 1 ); if( s && !strcmp(s, "on") ) b_bool = true; else if( s && !strcmp(s, "off") ) b_bool = false; else { b_bool = var_GetBool( p_obj, psz_name ); goto end; } if( b_bool != var_GetBool( p_obj, psz_name ) ) var_SetBool( p_obj, psz_name, b_bool ); end: lua_pushboolean( L, b_bool ); return 1; }
static int vlclua_tovalue( lua_State *L, int i_type, vlc_value_t *val ) { switch( i_type & VLC_VAR_CLASS ) { case VLC_VAR_VOID: break; case VLC_VAR_BOOL: val->b_bool = luaL_checkboolean( L, -1 ); break; case VLC_VAR_INTEGER: /* Lua may only support 32-bit integers. If so, we need to * get the value as a float instead so we can even know if * there would be an overflow. */ // TODO: check using LUA_MININTEGER and LUA_MAXINTEGER macros // if and when we require lua >= 5.3 if( sizeof( lua_Integer ) < sizeof( val->i_int ) ) { lua_Number f = luaL_checknumber( L, -1 ); // Calling vlc.var.set() on integer object variables with // an out-of-range float value is not handled. val->i_int = (int64_t)llround( f ); if( INT32_MIN < val->i_int && val->i_int < INT32_MAX ) val->i_int = luaL_checkinteger( L, -1 ); } else val->i_int = luaL_checkinteger( L, -1 ); break; case VLC_VAR_STRING: val->psz_string = (char*)luaL_checkstring( L, -1 ); /* XXX: Beware, this only stays valid as long as (L,-1) stays in the stack */ break; case VLC_VAR_FLOAT: val->f_float = luaL_checknumber( L, -1 ); break; case VLC_VAR_ADDRESS: vlclua_error( L ); break; default: vlclua_error( L ); } return 1; }
/***************************************************************************** * Vout control *****************************************************************************/ static int vlclua_fullscreen( lua_State *L ) { vout_thread_t *p_vout; int i_ret; input_thread_t * p_input = vlclua_get_input_internal( L ); if( !p_input ) return vlclua_error( L ); p_vout = input_GetVout( p_input ); if( !p_vout ) { vlc_object_release( p_input ); return vlclua_error( L ); } i_ret = vlclua_var_toggle_or_set( L, p_vout, "fullscreen" ); vlc_object_release( p_vout ); vlc_object_release( p_input ); return i_ret; }
/***************************************************************************** * Variables handling *****************************************************************************/ static int vlclua_pushvalue( lua_State *L, int i_type, vlc_value_t val ) { switch( i_type & VLC_VAR_CLASS ) { case VLC_VAR_BOOL: lua_pushboolean( L, val.b_bool ); break; case VLC_VAR_INTEGER: /* Lua may only support 32-bit integers. If so, and the * value requires a higher range, push it as a float. We * lose some precision, but object variables are not a * recommended API for lua scripts: functionality requiring * high precision should be provided with a dedicated lua * binding instead of object variables. */ // TODO: check using LUA_MININTEGER and LUA_MAXINTEGER macros // if and when we require lua >= 5.3 if( sizeof( lua_Integer ) < sizeof( val.i_int ) && ( val.i_int < INT32_MIN || INT32_MAX < val.i_int ) ) lua_pushnumber( L, (lua_Number)val.i_int ); else lua_pushinteger( L, val.i_int ); break; case VLC_VAR_STRING: lua_pushstring( L, val.psz_string ); break; case VLC_VAR_FLOAT: lua_pushnumber( L, val.f_float ); break; case VLC_VAR_ADDRESS: vlclua_error( L ); break; case VLC_VAR_VOID: default: vlclua_error( L ); } return 1; }
static int vlclua_tovalue( lua_State *L, int i_type, vlc_value_t *val ) { switch( i_type & 0xf0 ) { case VLC_VAR_VOID: break; case VLC_VAR_BOOL: val->b_bool = luaL_checkboolean( L, -1 ); break; case VLC_VAR_INTEGER: val->i_int = luaL_checkint( L, -1 ); break; case VLC_VAR_STRING: val->psz_string = (char*)luaL_checkstring( L, -1 ); /* XXX: Beware, this only stays valid as long as (L,-1) stays in the stack */ break; case VLC_VAR_FLOAT: val->f_float = luaL_checknumber( L, -1 ); break; case VLC_VAR_TIME: { double f = luaL_checknumber( L, -1 ); val->i_time = (int64_t)(f*1000000.); } break; case VLC_VAR_ADDRESS: vlclua_error( L ); break; case VLC_VAR_MUTEX: vlclua_error( L ); break; case VLC_VAR_LIST: vlclua_error( L ); break; default: vlclua_error( L ); } return 1; }
static int vlclua_stream_add_filter( lua_State *L ) { vlc_object_t *p_this = vlclua_get_this( L ); /* Make sure that we have 1 argument (+ 1 object) */ lua_settop( L, 2 ); stream_t **pp_stream = (stream_t **)luaL_checkudata( L, 1, "stream" ); if( !*pp_stream ) return vlclua_error( L ); const char *psz_filter = NULL; if( lua_isstring( L, 2 ) ) psz_filter = lua_tostring( L, 2 ); if( !psz_filter || !*psz_filter ) { msg_Dbg( p_this, "adding all automatic stream filters" ); while( true ) { /* Add next automatic stream */ stream_t *p_filtered = vlc_stream_FilterNew( *pp_stream, NULL ); if( !p_filtered ) break; else { msg_Dbg( p_this, "inserted an automatic stream filter" ); *pp_stream = p_filtered; } } luaL_getmetatable( L, "stream" ); lua_setmetatable( L, 1 ); } else { /* Add a named filter */ stream_t *p_filter = vlc_stream_FilterNew( *pp_stream, psz_filter ); if( !p_filter ) msg_Dbg( p_this, "Unable to open requested stream filter '%s'", psz_filter ); else { *pp_stream = p_filter; luaL_getmetatable( L, "stream" ); lua_setmetatable( L, 1 ); } } return 1; }
static int vlclua_stream_read( lua_State *L ) { int i_read; stream_t **pp_stream = (stream_t **)luaL_checkudata( L, 1, "stream" ); int n = luaL_checkint( L, 2 ); uint8_t *p_read = malloc( n ); if( !p_read ) return vlclua_error( L ); i_read = vlc_stream_Read( *pp_stream, p_read, n ); if( i_read > 0 ) lua_pushlstring( L, (const char *)p_read, i_read ); else lua_pushnil( L ); free( p_read ); return 1; }
int __vlclua_var_toggle_or_set( lua_State *L, vlc_object_t *p_obj, const char *psz_name ) { bool b_bool; if( lua_gettop( L ) > 1 ) return vlclua_error( L ); if( lua_gettop( L ) == 0 ) b_bool = var_ToggleBool( p_obj, psz_name ); else /* lua_gettop( L ) == 1 */ { b_bool = luaL_checkboolean( L, -1 ); lua_pop( L, 1 ); if( b_bool != var_GetBool( p_obj, psz_name ) ) var_SetBool( p_obj, psz_name, b_bool ); } lua_pushboolean( L, b_bool ); return 1; }
static int vlclua_add_callback( lua_State *L ) { vlclua_callback_t *p_callback; static int i_index = 0; vlc_object_t **pp_obj = luaL_checkudata( L, 1, "vlc_object" ); const char *psz_var = luaL_checkstring( L, 2 ); lua_settop( L, 4 ); /* makes sure that optional data arg is set */ if( !lua_isfunction( L, 3 ) ) return vlclua_error( L ); if( !pp_obj || !*pp_obj ) return vlclua_error( L ); /* Check variable type, in order to avoid PANIC */ switch( var_Type( *pp_obj, psz_var ) ) { case VLC_VAR_BOOL: case VLC_VAR_INTEGER: case VLC_VAR_STRING: case VLC_VAR_FLOAT: case VLC_VAR_TIME: break; case VLC_VAR_ADDRESS: case VLC_VAR_VOID: case VLC_VAR_MUTEX: case VLC_VAR_LIST: default: return vlclua_error( L ); } i_index++; p_callback = (vlclua_callback_t*)malloc( sizeof( vlclua_callback_t ) ); if( !p_callback ) return vlclua_error( L ); /* obj var func data */ lua_getglobal( L, "vlc" ); /* obj var func data vlc */ lua_getfield( L, -1, "callbacks" ); if( lua_isnil( L, -1 ) ) { lua_pop( L, 1 ); lua_newtable( L ); lua_setfield( L, -2, "callbacks" ); lua_getfield( L, -1, "callbacks" ); } /* obj var func data vlc callbacks */ lua_remove( L, -2 ); /* obj var func data callbacks */ lua_pushinteger( L, i_index ); /* obj var func data callbacks index */ lua_insert( L, -4 ); /* obj var index func data callbacks */ lua_insert( L, -4 ); /* obj var callbacks index func data */ lua_createtable( L, 0, 0 ); /* obj var callbacks index func data cbtable */ lua_insert( L, -2 ); /* obj var callbacks index func cbtable data */ lua_setfield( L, -2, "data" ); /* obj var callbacks index func cbtable */ lua_insert( L, -2 ); /* obj var callbacks index cbtable func */ lua_setfield( L, -2, "callback" ); /* obj var callbacks index cbtable */ lua_pushlightuserdata( L, *pp_obj ); /* will be needed in vlclua_del_callback */ /* obj var callbacks index cbtable p_obj */ lua_setfield( L, -2, "private1" ); /* obj var callbacks index cbtable */ lua_pushvalue( L, 2 ); /* will be needed in vlclua_del_callback */ /* obj var callbacks index cbtable var */ lua_setfield( L, -2, "private2" ); /* obj var callbacks index cbtable */ lua_pushlightuserdata( L, p_callback ); /* will be needed in vlclua_del_callback */ /* obj var callbacks index cbtable p_callback */ lua_setfield( L, -2, "private3" ); /* obj var callbacks index cbtable */ lua_settable( L, -3 ); /* obj var callbacks */ lua_pop( L, 3 ); /* <empty stack> */ /* Do not move this before the lua specific code (it somehow changes * the function in the stack to nil) */ p_callback->i_index = i_index; p_callback->i_type = var_Type( *pp_obj, psz_var ); p_callback->L = lua_newthread( L ); /* Do we have to keep a reference to this thread somewhere to prevent garbage collection? */ var_AddCallback( *pp_obj, psz_var, vlclua_callback, p_callback ); return 0; }
static int vlclua_del_callback( lua_State *L ) { vlclua_callback_t *p_callback; bool b_found = false; vlc_object_t **pp_obj = luaL_checkudata( L, 1, "vlc_object" ); const char *psz_var = luaL_checkstring( L, 2 ); lua_settop( L, 4 ); /* makes sure that optional data arg is set */ if( !lua_isfunction( L, 3 ) ) return vlclua_error( L ); /* obj var func data */ lua_getglobal( L, "vlc" ); /* obj var func data vlc */ lua_getfield( L, -1, "callbacks" ); if( lua_isnil( L, -1 ) ) return luaL_error( L, "Couldn't find matching callback." ); /* obj var func data vlc callbacks */ lua_remove( L, -2 ); /* obj var func data callbacks */ lua_pushnil( L ); /* obj var func data callbacks index */ while( lua_next( L, -2 ) ) { /* obj var func data callbacks index value */ if( lua_isnumber( L, -2 ) ) { lua_getfield( L, -1, "private2" ); /* obj var func data callbacks index value private2 */ if( lua_equal( L, 2, -1 ) ) /* var name is equal */ { lua_pop( L, 1 ); /* obj var func data callbacks index value */ lua_getfield( L, -1, "callback" ); /* obj var func data callbacks index value callback */ if( lua_equal( L, 3, -1 ) ) /* callback function is equal */ { lua_pop( L, 1 ); /* obj var func data callbacks index value */ lua_getfield( L, -1, "data" ); /* callback data is equal */ /* obj var func data callbacks index value data */ if( lua_equal( L, 4, -1 ) ) { vlc_object_t *p_obj2; lua_pop( L, 1 ); /* obj var func data callbacks index value */ lua_getfield( L, -1, "private1" ); /* obj var func data callbacks index value private1 */ p_obj2 = (vlc_object_t*)luaL_checklightuserdata( L, -1 ); if( p_obj2 == *pp_obj ) /* object is equal */ { lua_pop( L, 1 ); /* obj var func data callbacks index value */ lua_getfield( L, -1, "private3" ); /* obj var func data callbacks index value private3 */ p_callback = (vlclua_callback_t*)luaL_checklightuserdata( L, -1 ); lua_pop( L, 2 ); /* obj var func data callbacks index */ b_found = true; break; } else { /* obj var func data callbacks index value private1 */ lua_pop( L, 1 ); /* obj var func data callbacks index value */ } } else { /* obj var func data callbacks index value data */ lua_pop( L, 1 ); /* obj var func data callbacks index value */ } } else { /* obj var func data callbacks index value callback */ lua_pop( L, 1 ); /* obj var func data callbacks index value */ } } else { /* obj var func data callbacks index value private2 */ lua_pop( L, 1 ); /* obj var func data callbacks index value */ } } /* obj var func data callbacks index value */ lua_pop( L, 1 ); /* obj var func data callbacks index */ } if( b_found == false ) /* obj var func data callbacks */ return luaL_error( L, "Couldn't find matching callback." ); /* else */ /* obj var func data callbacks index*/ var_DelCallback( *pp_obj, psz_var, vlclua_callback, p_callback ); free( p_callback ); /* obj var func data callbacks index */ lua_pushnil( L ); /* obj var func data callbacks index nil */ lua_settable( L, -3 ); /* delete the callback table entry */ /* obj var func data callbacks */ lua_pop( L, 5 ); /* <empty stack> */ return 0; }