variables.c
上传用户:kjfoods
上传日期:2020-07-06
资源大小:29949k
文件大小:18k
源码类别:

midi

开发平台:

Unix_Linux

  1. /*****************************************************************************
  2.  * variables.c: Generic lua<->vlc variables interface
  3.  *****************************************************************************
  4.  * Copyright (C) 2007-2008 the VideoLAN team
  5.  * $Id: 16833bc6c405ead000018a01504bfbd1e4b5d739 $
  6.  *
  7.  * Authors: Antoine Cellerier <dionoea at videolan tod org>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #ifndef  _GNU_SOURCE
  27. #   define  _GNU_SOURCE
  28. #endif
  29. #ifdef HAVE_CONFIG_H
  30. # include "config.h"
  31. #endif
  32. #include <vlc_common.h>
  33. #include <lua.h>        /* Low level lua C API */
  34. #include <lauxlib.h>    /* Higher level C API */
  35. #include <lualib.h>     /* Lua libs */
  36. #include "../vlc.h"
  37. #include "../libs.h"
  38. #include "variables.h"
  39. #include "objects.h"
  40. /*****************************************************************************
  41.  * Variables handling
  42.  *****************************************************************************/
  43. int vlclua_pushvalue( lua_State *L, int i_type, vlc_value_t val )
  44. {
  45.     switch( i_type &= 0xf0 )
  46.     {
  47.         case VLC_VAR_VOID:
  48.             vlclua_error( L );
  49.             break;
  50.         case VLC_VAR_BOOL:
  51.             lua_pushboolean( L, val.b_bool );
  52.             break;
  53.         case VLC_VAR_INTEGER:
  54.             lua_pushinteger( L, val.i_int );
  55.             break;
  56.         case VLC_VAR_STRING:
  57.             lua_pushstring( L, val.psz_string );
  58.             break;
  59.         case VLC_VAR_FLOAT:
  60.             lua_pushnumber( L, val.f_float );
  61.             break;
  62.         case VLC_VAR_TIME:
  63.             /* FIXME? (we're losing some precision, but does it really matter?) */
  64.             lua_pushnumber( L, ((double)val.i_time)/1000000. );
  65.             break;
  66.         case VLC_VAR_ADDRESS:
  67.             vlclua_error( L );
  68.             break;
  69.         case VLC_VAR_MUTEX:
  70.             vlclua_error( L );
  71.             break;
  72.         case VLC_VAR_LIST:
  73.             {
  74.                 int i_count = val.p_list->i_count;
  75.                 int i;
  76.                 lua_createtable( L, i_count, 0 );
  77.                 for( i = 0; i < i_count; i++ )
  78.                 {
  79.                     lua_pushinteger( L, i+1 );
  80.                     if( !vlclua_pushvalue( L, val.p_list->pi_types[i],
  81.                                            val.p_list->p_values[i] ) )
  82.                         lua_pushnil( L );
  83.                     lua_settable( L, -3 );
  84.                 }
  85.             }
  86.             break;
  87.         default:
  88.             vlclua_error( L );
  89.     }
  90.     return 1;
  91. }
  92. static int vlclua_tovalue( lua_State *L, int i_type, vlc_value_t *val )
  93. {
  94.     switch( i_type & 0xf0 )
  95.     {
  96.         case VLC_VAR_VOID:
  97.             break;
  98.         case VLC_VAR_BOOL:
  99.             val->b_bool = luaL_checkboolean( L, -1 );
  100.             break;
  101.         case VLC_VAR_INTEGER:
  102.             val->i_int = luaL_checkint( L, -1 );
  103.             break;
  104.         case VLC_VAR_STRING:
  105.             val->psz_string = (char*)luaL_checkstring( L, -1 ); /* XXX: Beware, this only stays valid as long as (L,-1) stays in the stack */
  106.             break;
  107.         case VLC_VAR_FLOAT:
  108.             val->f_float = luaL_checknumber( L, -1 );
  109.             break;
  110.         case VLC_VAR_TIME:
  111.             {
  112.                 double f = luaL_checknumber( L, -1 );
  113.                 val->i_time = (int64_t)(f*1000000.);
  114.             }
  115.             break;
  116.         case VLC_VAR_ADDRESS:
  117.             vlclua_error( L );
  118.             break;
  119.         case VLC_VAR_MUTEX:
  120.             vlclua_error( L );
  121.             break;
  122.         case VLC_VAR_LIST:
  123.             vlclua_error( L );
  124.             break;
  125.         default:
  126.             vlclua_error( L );
  127.     }
  128.     return 1;
  129. }
  130. static int vlclua_var_get( lua_State *L )
  131. {
  132.     int i_type;
  133.     vlc_value_t val;
  134.     vlc_object_t **pp_obj = luaL_checkudata( L, 1, "vlc_object" );
  135.     const char *psz_var = luaL_checkstring( L, 2 );
  136.     i_type = var_Type( *pp_obj, psz_var );
  137.     if( var_Get( *pp_obj, psz_var, &val ) != VLC_SUCCESS )
  138.         return 0;
  139.     lua_pop( L, 2 );
  140.     return vlclua_pushvalue( L, i_type, val );
  141. }
  142. static int vlclua_var_set( lua_State *L )
  143. {
  144.     int i_type;
  145.     vlc_value_t val;
  146.     vlc_object_t **pp_obj = luaL_checkudata( L, 1, "vlc_object" );
  147.     const char *psz_var = luaL_checkstring( L, 2 );
  148.     int i_ret;
  149.     i_type = var_Type( *pp_obj, psz_var );
  150.     vlclua_tovalue( L, i_type, &val );
  151.     i_ret = var_Set( *pp_obj, psz_var, val );
  152.     lua_pop( L, 3 );
  153.     return vlclua_push_ret( L, i_ret );
  154. }
  155. static int vlclua_var_create( lua_State *L )
  156. {
  157.     vlc_object_t **pp_obj = luaL_checkudata( L, 1, "vlc_object" );
  158.     const char *psz_var = luaL_checkstring( L, 2 );
  159.     int i_type;
  160.     switch( lua_type( L, 3 ) )
  161.     {
  162.         case LUA_TNUMBER:
  163.             i_type = VLC_VAR_FLOAT;
  164.             break;
  165.         case LUA_TBOOLEAN:
  166.             i_type = VLC_VAR_BOOL;
  167.             break;
  168.         case LUA_TSTRING:
  169.             i_type = VLC_VAR_STRING;
  170.             break;
  171.         default:
  172.             return 0;
  173.     }
  174.     int i_ret = var_Create( *pp_obj, psz_var, i_type );
  175.     if( i_ret != VLC_SUCCESS )
  176.         return vlclua_push_ret( L, i_ret );
  177.     vlc_value_t val;
  178.     vlclua_tovalue( L, i_type, &val );
  179.     return vlclua_push_ret( L, var_Set( *pp_obj, psz_var, val ) );
  180. }
  181. static int vlclua_var_get_list( lua_State *L )
  182. {
  183.     vlc_value_t val;
  184.     vlc_value_t text;
  185.     vlc_object_t **pp_obj = luaL_checkudata( L, 1, "vlc_object" );
  186.     const char *psz_var = luaL_checkstring( L, 2 );
  187.     int i_ret = var_Change( *pp_obj, psz_var, VLC_VAR_GETLIST, &val, &text );
  188.     if( i_ret < 0 ) return vlclua_push_ret( L, i_ret );
  189.     vlclua_pushvalue( L, VLC_VAR_LIST, val );
  190.     vlclua_pushvalue( L, VLC_VAR_LIST, text );
  191.     var_Change( *pp_obj, psz_var, VLC_VAR_FREELIST, &val, &text );
  192.     return 2;
  193. }
  194. static int vlclua_command( lua_State *L )
  195. {
  196.     vlc_object_t * p_this = vlclua_get_this( L );
  197.     const char *psz_name;
  198.     const char *psz_cmd;
  199.     const char *psz_arg;
  200.     char *psz_msg;
  201.     int ret;
  202.     psz_name = luaL_checkstring( L, 1 );
  203.     psz_cmd = luaL_checkstring( L, 2 );
  204.     psz_arg = luaL_checkstring( L, 3 );
  205.     lua_pop( L, 3 );
  206.     ret = var_Command( p_this, psz_name, psz_cmd, psz_arg, &psz_msg );
  207.     if( psz_msg )
  208.     {
  209.         lua_pushstring( L, psz_msg );
  210.         free( psz_msg );
  211.     }
  212.     else
  213.     {
  214.         lua_pushstring( L, "" );
  215.     }
  216.     return vlclua_push_ret( L, ret ) + 1;
  217. }
  218. static int vlclua_libvlc_command( lua_State *L )
  219. {
  220.     vlc_object_t * p_this = vlclua_get_this( L );
  221.     const char *psz_cmd;
  222.     vlc_value_t val_arg;
  223.     psz_cmd = luaL_checkstring( L, 1 );
  224.     val_arg.psz_string = strdup( luaL_optstring( L, 2, "" ) );
  225.     lua_pop( L, 2 );
  226.     int i_type = var_Type( p_this->p_libvlc, psz_cmd );
  227.     if( ! i_type & VLC_VAR_ISCOMMAND )
  228.     {
  229.         free( val_arg.psz_string );
  230.         return luaL_error( L, "libvlc's "%s" is not a command",
  231.                            psz_cmd );
  232.     }
  233.     return vlclua_push_ret( L,
  234.                             var_Set( p_this->p_libvlc, psz_cmd, val_arg ) );
  235. }
  236. int __vlclua_var_toggle_or_set( lua_State *L, vlc_object_t *p_obj,
  237.                                 const char *psz_name )
  238. {
  239.     bool b_bool;
  240.     if( lua_gettop( L ) > 1 ) return vlclua_error( L );
  241.     if( lua_gettop( L ) == 0 )
  242.         b_bool = !var_GetBool( p_obj, psz_name );
  243.     else /* lua_gettop( L ) == 1 */
  244.     {
  245.         b_bool = luaL_checkboolean( L, -1 )?true:false;
  246.         lua_pop( L, 1 );
  247.     }
  248.     if( b_bool != var_GetBool( p_obj, psz_name ) )
  249.         var_SetBool( p_obj, psz_name, b_bool );
  250.     lua_pushboolean( L, b_bool );
  251.     return 1;
  252. }
  253. static inline const void *luaL_checklightuserdata( lua_State *L, int narg )
  254. {
  255.     luaL_checktype( L, narg, LUA_TLIGHTUSERDATA ); /* can raise an error */
  256.     return lua_topointer( L, narg );
  257. }
  258. typedef struct
  259. {
  260.     int i_index;
  261.     int i_type;
  262.     lua_State *L;
  263. }   vlclua_callback_t;
  264. static int vlclua_callback( vlc_object_t *p_this, char const *psz_var,
  265.                             vlc_value_t oldval, vlc_value_t newval,
  266.                             void *p_data )
  267. {
  268.     vlclua_callback_t *p_callback = (vlclua_callback_t*)p_data;
  269.     lua_State *L = p_callback->L;
  270.     /* <empty stack> */
  271.     lua_getglobal( L, "vlc" );
  272.     /* vlc */
  273.     lua_getfield( L, -1, "callbacks" );
  274.     /* vlc callbacks */
  275.     lua_remove( L, -2 );
  276.     /* callbacks */
  277.     lua_pushinteger( L, p_callback->i_index );
  278.     /* callbacks index */
  279.     lua_gettable( L, -2 );
  280.     /* callbacks callbacks[index] */
  281.     lua_remove( L, -2 );
  282.     /* callbacks[index] */
  283.     lua_getfield( L, -1, "callback" );
  284.     /* callbacks[index] callback */
  285.     lua_pushstring( L, psz_var );
  286.     /* callbacks[index] callback var */
  287.     vlclua_pushvalue( L, p_callback->i_type, oldval );
  288.     /* callbacks[index] callback var oldval */
  289.     vlclua_pushvalue( L, p_callback->i_type, newval );
  290.     /* callbacks[index] callback var oldval newval */
  291.     lua_getfield( L, -5, "data" );
  292.     /* callbacks[index] callback var oldval newval data */
  293.     lua_remove( L, -6 );
  294.     /* callback var oldval newval data */
  295.     if( lua_pcall( L, 4, 0, 0 ) )
  296.     {
  297.         /* errormessage */
  298.         const char *psz_err = lua_tostring( L, -1 );
  299.         msg_Err( p_this, "Error while runing lua interface callback: %s",
  300.                  psz_err );
  301.         /* empty the stack (should only contain the error message) */
  302.         lua_settop( L, 0 );
  303.         return VLC_EGENERIC;
  304.     }
  305.     /* empty the stack (should already be empty) */
  306.     lua_settop( L, 0 );
  307.     return VLC_SUCCESS;
  308. }
  309. static int vlclua_add_callback( lua_State *L )
  310. {
  311.     vlclua_callback_t *p_callback;
  312.     static int i_index = 0;
  313.     vlc_object_t **pp_obj = luaL_checkudata( L, 1, "vlc_object" );
  314.     const char *psz_var = luaL_checkstring( L, 2 );
  315.     lua_settop( L, 4 ); /* makes sure that optional data arg is set */
  316.     if( !lua_isfunction( L, 3 ) )
  317.         return vlclua_error( L );
  318.     i_index++;
  319.     p_callback = (vlclua_callback_t*)malloc( sizeof( vlclua_callback_t ) );
  320.     if( !p_callback )
  321.         return vlclua_error( L );
  322.     /* obj var func data */
  323.     lua_getglobal( L, "vlc" );
  324.     /* obj var func data vlc */
  325.     lua_getfield( L, -1, "callbacks" );
  326.     if( lua_isnil( L, -1 ) )
  327.     {
  328.         lua_pop( L, 1 );
  329.         lua_newtable( L );
  330.         lua_setfield( L, -2, "callbacks" );
  331.         lua_getfield( L, -1, "callbacks" );
  332.     }
  333.     /* obj var func data vlc callbacks */
  334.     lua_remove( L, -2 );
  335.     /* obj var func data callbacks */
  336.     lua_pushinteger( L, i_index );
  337.     /* obj var func data callbacks index */
  338.     lua_insert( L, -4 );
  339.     /* obj var index func data callbacks */
  340.     lua_insert( L, -4 );
  341.     /* obj var callbacks index func data */
  342.     lua_createtable( L, 0, 0 );
  343.     /* obj var callbacks index func data cbtable */
  344.     lua_insert( L, -2 );
  345.     /* obj var callbacks index func cbtable data */
  346.     lua_setfield( L, -2, "data" );
  347.     /* obj var callbacks index func cbtable */
  348.     lua_insert( L, -2 );
  349.     /* obj var callbacks index cbtable func */
  350.     lua_setfield( L, -2, "callback" );
  351.     /* obj var callbacks index cbtable */
  352.     lua_pushlightuserdata( L, *pp_obj ); /* will be needed in vlclua_del_callback */
  353.     /* obj var callbacks index cbtable p_obj */
  354.     lua_setfield( L, -2, "private1" );
  355.     /* obj var callbacks index cbtable */
  356.     lua_pushvalue( L, 2 ); /* will be needed in vlclua_del_callback */
  357.     /* obj var callbacks index cbtable var */
  358.     lua_setfield( L, -2, "private2" );
  359.     /* obj var callbacks index cbtable */
  360.     lua_pushlightuserdata( L, p_callback ); /* will be needed in vlclua_del_callback */
  361.     /* obj var callbacks index cbtable p_callback */
  362.     lua_setfield( L, -2, "private3" );
  363.     /* obj var callbacks index cbtable */
  364.     lua_settable( L, -3 );
  365.     /* obj var callbacks */
  366.     lua_pop( L, 3 );
  367.     /* <empty stack> */
  368.     /* Do not move this before the lua specific code (it somehow changes
  369.      * the function in the stack to nil) */
  370.     p_callback->i_index = i_index;
  371.     p_callback->i_type = var_Type( *pp_obj, psz_var );
  372.     p_callback->L = lua_newthread( L ); /* Do we have to keep a reference to this thread somewhere to prevent garbage collection? */
  373.     var_AddCallback( *pp_obj, psz_var, vlclua_callback, p_callback );
  374.     return 0;
  375. }
  376. static int vlclua_del_callback( lua_State *L )
  377. {
  378.     vlclua_callback_t *p_callback;
  379.     bool b_found = false;
  380.     vlc_object_t **pp_obj = luaL_checkudata( L, 1, "vlc_object" );
  381.     const char *psz_var = luaL_checkstring( L, 2 );
  382.     lua_settop( L, 4 ); /* makes sure that optional data arg is set */
  383.     if( !lua_isfunction( L, 3 ) )
  384.         return vlclua_error( L );
  385.     /* obj var func data */
  386.     lua_getglobal( L, "vlc" );
  387.     /* obj var func data vlc */
  388.     lua_getfield( L, -1, "callbacks" );
  389.     if( lua_isnil( L, -1 ) )
  390.         return luaL_error( L, "Couldn't find matching callback." );
  391.     /* obj var func data vlc callbacks */
  392.     lua_remove( L, -2 );
  393.     /* obj var func data callbacks */
  394.     lua_pushnil( L );
  395.     /* obj var func data callbacks index */
  396.     while( lua_next( L, -2 ) )
  397.     {
  398.         /* obj var func data callbacks index value */
  399.         if( lua_isnumber( L, -2 ) )
  400.         {
  401.             lua_getfield( L, -1, "private2" );
  402.             /* obj var func data callbacks index value private2 */
  403.             if( lua_equal( L, 2, -1 ) ) /* var name is equal */
  404.             {
  405.                 lua_pop( L, 1 );
  406.                 /* obj var func data callbacks index value */
  407.                 lua_getfield( L, -1, "callback" );
  408.                 /* obj var func data callbacks index value callback */
  409.                 if( lua_equal( L, 3, -1 ) ) /* callback function is equal */
  410.                 {
  411.                     lua_pop( L, 1 );
  412.                     /* obj var func data callbacks index value */
  413.                     lua_getfield( L, -1, "data" ); /* callback data is equal */
  414.                     /* obj var func data callbacks index value data */
  415.                     if( lua_equal( L, 4, -1 ) )
  416.                     {
  417.                         vlc_object_t *p_obj2;
  418.                         lua_pop( L, 1 );
  419.                         /* obj var func data callbacks index value */
  420.                         lua_getfield( L, -1, "private1" );
  421.                         /* obj var func data callbacks index value private1 */
  422.                         p_obj2 = (vlc_object_t*)luaL_checklightuserdata( L, -1 );
  423.                         if( p_obj2 == *pp_obj ) /* object is equal */
  424.                         {
  425.                             lua_pop( L, 1 );
  426.                             /* obj var func data callbacks index value */
  427.                             lua_getfield( L, -1, "private3" );
  428.                             /* obj var func data callbacks index value private3 */
  429.                             p_callback = (vlclua_callback_t*)luaL_checklightuserdata( L, -1 );
  430.                             lua_pop( L, 2 );
  431.                             /* obj var func data callbacks index */
  432.                             b_found = true;
  433.                             break;
  434.                         }
  435.                         else
  436.                         {
  437.                             /* obj var func data callbacks index value private1 */
  438.                             lua_pop( L, 1 );
  439.                             /* obj var func data callbacks index value */
  440.                         }
  441.                     }
  442.                     else
  443.                     {
  444.                         /* obj var func data callbacks index value data */
  445.                         lua_pop( L, 1 );
  446.                         /* obj var func data callbacks index value */
  447.                     }
  448.                 }
  449.                 else
  450.                 {
  451.                     /* obj var func data callbacks index value callback */
  452.                     lua_pop( L, 1 );
  453.                     /* obj var func data callbacks index value */
  454.                 }
  455.             }
  456.             else
  457.             {
  458.                 /* obj var func data callbacks index value private2 */
  459.                 lua_pop( L, 1 );
  460.                 /* obj var func data callbacks index value */
  461.             }
  462.         }
  463.         /* obj var func data callbacks index value */
  464.         lua_pop( L, 1 );
  465.         /* obj var func data callbacks index */
  466.     }
  467.     if( b_found == false )
  468.         /* obj var func data callbacks */
  469.         return luaL_error( L, "Couldn't find matching callback." );
  470.     /* else */
  471.         /* obj var func data callbacks index*/
  472.     var_DelCallback( *pp_obj, psz_var, vlclua_callback, p_callback );
  473.     free( p_callback );
  474.     /* obj var func data callbacks index */
  475.     lua_pushnil( L );
  476.     /* obj var func data callbacks index nil */
  477.     lua_settable( L, -3 ); /* delete the callback table entry */
  478.     /* obj var func data callbacks */
  479.     lua_pop( L, 5 );
  480.     /* <empty stack> */
  481.     return 0;
  482. }
  483. /*****************************************************************************
  484.  *
  485.  *****************************************************************************/
  486. static const luaL_Reg vlclua_var_reg[] = {
  487.     { "get", vlclua_var_get },
  488.     { "get_list", vlclua_var_get_list },
  489.     { "set", vlclua_var_set },
  490.     { "create", vlclua_var_create },
  491.     { "add_callback", vlclua_add_callback },
  492.     { "del_callback", vlclua_del_callback },
  493.     { "command", vlclua_command },
  494.     { "libvlc_command", vlclua_libvlc_command },
  495.     { NULL, NULL }
  496. };
  497. void luaopen_variables( lua_State *L )
  498. {
  499.     lua_newtable( L );
  500.     luaL_register( L, NULL, vlclua_var_reg );
  501.     lua_setfield( L, -2, "var" );
  502. }