Commit 642959ea authored by Antoine Cellerier's avatar Antoine Cellerier

Add lua console handling code for windows.

This fixes the lua command line interface under windows. Adding all
those special cases in the host abstraction layer doesn't seem optimal
but at least it works. I'll probably try cleaning it up later.
parent d13f0eaa
...@@ -37,4 +37,8 @@ SOURCES_lua = \ ...@@ -37,4 +37,8 @@ SOURCES_lua = \
libs/xml.c \ libs/xml.c \
$(NULL) $(NULL)
if HAVE_WIN32
SOURCES_lua += libs/win.c
endif
libvlc_LTLIBRARIES += liblua_plugin.la libvlc_LTLIBRARIES += liblua_plugin.la
...@@ -839,6 +839,9 @@ static lua_State* GetLuaState( extensions_manager_t *p_mgr, ...@@ -839,6 +839,9 @@ static lua_State* GetLuaState( extensions_manager_t *p_mgr,
luaopen_vlm( L ); luaopen_vlm( L );
luaopen_volume( L ); luaopen_volume( L );
luaopen_xml( L ); luaopen_xml( L );
#ifdef WIN32
luaopen_win( L );
#endif
/* Register extension specific functions */ /* Register extension specific functions */
lua_getglobal( L, "vlc" ); lua_getglobal( L, "vlc" );
......
...@@ -254,6 +254,9 @@ static int Start_LuaIntf( vlc_object_t *p_this, const char *name ) ...@@ -254,6 +254,9 @@ static int Start_LuaIntf( vlc_object_t *p_this, const char *name )
luaopen_gettext( L ); luaopen_gettext( L );
luaopen_xml( L ); luaopen_xml( L );
luaopen_equalizer( L ); luaopen_equalizer( L );
#ifdef WIN32
luaopen_win( L );
#endif
/* clean up */ /* clean up */
lua_pop( L, 1 ); lua_pop( L, 1 );
......
...@@ -46,5 +46,8 @@ void luaopen_gettext( lua_State * ); ...@@ -46,5 +46,8 @@ void luaopen_gettext( lua_State * );
void luaopen_input_item( lua_State *L, input_item_t *item ); void luaopen_input_item( lua_State *L, input_item_t *item );
void luaopen_xml( lua_State *L ); void luaopen_xml( lua_State *L );
void luaopen_equalizer( lua_State *L ); void luaopen_equalizer( lua_State *L );
#ifdef WIN32
void luaopen_win( lua_State *L );
#endif
#endif #endif
...@@ -215,10 +215,11 @@ static int vlclua_net_poll( lua_State *L ) ...@@ -215,10 +215,11 @@ static int vlclua_net_poll( lua_State *L )
lua_pop( L, 1 ); lua_pop( L, 1 );
i++; i++;
} }
int i_timeout = luaL_optint( L, 2, -1 );
int i_ret; int i_ret;
do do
i_ret = poll( p_fds, i_fds, -1 ); i_ret = poll( p_fds, i_fds, i_timeout );
while( i_ret == -1 ); while( i_ret == -1 );
for( i = 0; i < i_fds; i++ ) for( i = 0; i < i_fds; i++ )
......
/*****************************************************************************
* win.c: Windows specific functions
*****************************************************************************
* Copyright (C) 2007-2012 the VideoLAN team
* $Id$
*
* Authors: Antoine Cellerier <dionoea at videolan tod org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include "../vlc.h"
#include "../libs.h"
/* Based on modules/control/rc.c and include/vlc_interface.h */
static HANDLE GetConsole( lua_State *L )
{
/* Get the file descriptor of the console input */
HANDLE hConsoleIn = GetStdHandle(STD_INPUT_HANDLE);
if( hConsoleIn == INVALID_HANDLE_VALUE )
luaL_error( L, "couldn't find user input handle" );
return hConsoleIn;
}
#define MAX_LINE_LENGTH 1024
static bool ReadWin32( HANDLE *hConsoleIn, char *p_buffer, int *pi_size )
{
INPUT_RECORD input_record;
DWORD i_dw;
while( /*vlc_object_alive( p_intf ) &&*/ *pi_size < MAX_LINE_LENGTH &&
ReadConsoleInput( hConsoleIn, &input_record, 1, &i_dw ) )
{
if( input_record.EventType != KEY_EVENT ||
!input_record.Event.KeyEvent.bKeyDown ||
input_record.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT ||
input_record.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL||
input_record.Event.KeyEvent.wVirtualKeyCode == VK_MENU ||
input_record.Event.KeyEvent.wVirtualKeyCode == VK_CAPITAL )
{
/* nothing interesting */
continue;
}
p_buffer[ *pi_size ] = input_record.Event.KeyEvent.uChar.AsciiChar;
/* Echo out the command */
putc( p_buffer[ *pi_size ], stdout );
/* Handle special keys */
if( p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
{
if ( p_buffer[ *pi_size ] == '\r' )
p_buffer[ *pi_size ] = '\n';
(*pi_size)++; /* We want the \n to be in the output string */
putc( '\n', stdout );
break;
}
switch( p_buffer[ *pi_size ] )
{
case '\b':
if( *pi_size )
{
*pi_size -= 2;
putc( ' ', stdout );
putc( '\b', stdout );
}
break;
//case '\r':
// (*pi_size) --;
// break;
}
(*pi_size)++;
}
if( *pi_size == MAX_LINE_LENGTH )
// p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
{
p_buffer[ *pi_size ] = 0;
return true;
}
return false;
}
static int vlclua_console_init( lua_State *L )
{
(void)L;
//if ( !AllocConsole() )
// luaL_error( L, "failed to allocate windows console" );
AllocConsole();
freopen( "CONOUT$", "w", stdout );
freopen( "CONOUT$", "w", stderr );
freopen( "CONIN$", "r", stdin );
fprintf(stdout, "Tadam!\n");
fflush(stdout);
return 0;
}
static int vlclua_console_wait( lua_State *L )
{
int i_timeout = luaL_optint( L, 1, 0 );
DWORD status = WaitForSingleObject( GetConsole( L ), i_timeout );
lua_pushboolean( L, status == WAIT_OBJECT_0 );
return 1;
}
static int vlclua_console_read( lua_State *L )
{
char psz_buffer[MAX_LINE_LENGTH+1];
int i_size = 0;
ReadWin32( GetConsole( L ), psz_buffer, &i_size );
lua_pushlstring( L, psz_buffer, i_size );
return 1;
}
/*****************************************************************************
*
*****************************************************************************/
static const luaL_Reg vlclua_win_reg[] = {
{ "console_init", vlclua_console_init },
{ "console_wait", vlclua_console_wait },
{ "console_read", vlclua_console_read },
{ NULL, NULL }
};
void luaopen_win( lua_State *L )
{
lua_newtable( L );
luaL_register( L, NULL, vlclua_win_reg );
lua_setfield( L, -2, "win" );
}
...@@ -191,7 +191,7 @@ net.connect_tcp( host, port ): open a connection to the given host:port (TCP). ...@@ -191,7 +191,7 @@ net.connect_tcp( host, port ): open a connection to the given host:port (TCP).
net.close( fd ): Close file descriptor. net.close( fd ): Close file descriptor.
net.send( fd, string, [length] ): Send data on fd. net.send( fd, string, [length] ): Send data on fd.
net.recv( fd, [max length] ): Receive data from fd. net.recv( fd, [max length] ): Receive data from fd.
net.poll( { fd = events } ): Implement poll function. net.poll( { fd = events }, [timeout in ms] ): Implement poll function.
Returns the numbers of file descriptors with a non 0 revent. The function Returns the numbers of file descriptors with a non 0 revent. The function
modifies the input table to { fd = revents }. See "man poll". modifies the input table to { fd = revents }. See "man poll".
net.POLLIN/POLLPRI/POLLOUT/POLLRDHUP/POLLERR/POLLHUP/POLLNVAL: poll event flags net.POLLIN/POLLPRI/POLLOUT/POLLRDHUP/POLLERR/POLLHUP/POLLNVAL: poll event flags
...@@ -443,6 +443,15 @@ volume.set( level ): Set volume to an absolute level between 0 and 1024. ...@@ -443,6 +443,15 @@ volume.set( level ): Set volume to an absolute level between 0 and 1024.
volume.up( [n] ): Increment volume by n steps of 32. n defaults to 1. volume.up( [n] ): Increment volume by n steps of 32. n defaults to 1.
volume.down( [n] ): Decrement volume by n steps of 32. n defaults to 1. volume.down( [n] ): Decrement volume by n steps of 32. n defaults to 1.
Win
---
This module is only available on Windows builds
win.console_init(): Initialize the windows console.
win.console_wait([timeout]): Wait for input on the console for timeout ms.
Returns true if console input is available.
win.console_read(): Read input from the windows console. Note that polling and
reading from stdin does not work under windows.
XML XML
--- ---
xml = vlc.xml(): Create an xml object. xml = vlc.xml(): Create an xml object.
......
--[==========================================================================[ --[==========================================================================[
host.lua: VLC Lua interface command line host module host.lua: VLC Lua interface command line host module
--[==========================================================================[ --[==========================================================================[
Copyright (C) 2007 the VideoLAN team Copyright (C) 2007-2012 the VideoLAN team
$Id$ $Id$
Authors: Antoine Cellerier <dionoea at videolan dot org> Authors: Antoine Cellerier <dionoea at videolan dot org>
...@@ -114,6 +114,21 @@ function host() ...@@ -114,6 +114,21 @@ function host()
end end
end end
local function write_console( client, data )
-- FIXME: this method shouldn't be needed. vlc.net.write should just work
io.write(data or client.buffer)
return string.len(data or client.buffer)
end
local function read_console( client, len )
-- Read stdin from a windows console (beware: select/poll doesn't work!)
if vlc.win.console_wait(0) then
return vlc.win.console_read()
else
return 0
end
end
local function del_client( client ) local function del_client( client )
if client.type == client_type.stdio then if client.type == client_type.stdio then
client:send( "Cannot delete stdin/stdout client.\n" ) client:send( "Cannot delete stdin/stdout client.\n" )
...@@ -155,11 +170,18 @@ function host() ...@@ -155,11 +170,18 @@ function host()
w = send w = send
r = recv r = recv
else if t == client_type.stdio or t == client_type.fifo then else if t == client_type.stdio or t == client_type.fifo then
w = write if vlc.win and t == client_type.stdio then
r = read vlc.win.console_init()
w = write_console
r = read_console
else
w = write
r = read
end
else else
error("Unknown client type", t ) error("Unknown client type", t )
end end end end
local client = { -- data local client = { -- data
rfd = fd, rfd = fd,
wfd = wfd or fd, wfd = wfd or fd,
...@@ -249,7 +271,14 @@ function host() ...@@ -249,7 +271,14 @@ function host()
end end
end end
local ret = vlc.net.poll( pollfds ) local timeout = -1
if vlc.win and listeners.stdio then
timeout = 50
end
local ret = 0
if not vlc.win or listeners.tcp then
ret = vlc.net.poll( pollfds, timeout )
end
local wclients = {} local wclients = {}
local rclients = {} local rclients = {}
if ret > 0 then if ret > 0 then
...@@ -259,9 +288,9 @@ function host() ...@@ -259,9 +288,9 @@ function host()
or is_flag_set(pollfds[client:fd()], vlc.net.POLLNVAL) then or is_flag_set(pollfds[client:fd()], vlc.net.POLLNVAL) then
del_client(client) del_client(client)
elseif is_flag_set(pollfds[client:fd()], vlc.net.POLLOUT) then elseif is_flag_set(pollfds[client:fd()], vlc.net.POLLOUT) then
table.insert(wclients,client) table.insert(wclients, client)
elseif is_flag_set(pollfds[client:fd()], vlc.net.POLLIN) then elseif is_flag_set(pollfds[client:fd()], vlc.net.POLLIN) then
table.insert(rclients,client) table.insert(rclients, client)
end end
end end
if listeners.tcp then if listeners.tcp then
...@@ -277,14 +306,26 @@ function host() ...@@ -277,14 +306,26 @@ function host()
end end
end end
if vlc.win and listeners.stdio then
for _, client in pairs(clients) do
if client.type == client_type.stdio then
if client.status == status.read or client.status == status.password then
if vlc.win.console_wait(50) then
table.insert(rclients, client)
end
else
table.insert(wclients, client)
end
end
end
end
return wclients, rclients return wclients, rclients
end end
-- FIXME: this is never called, client sockets are leaked
local function destructor( h ) local function destructor( h )
print "destructor"
for _,client in pairs(clients) do for _,client in pairs(clients) do
--client:send("Shutting down.") client:send("Shutting down.")
if client.type == client_type.net if client.type == client_type.net
or client.type == client_type.telnet then or client.type == client_type.telnet then
if client.wfd ~= client.rfd then if client.wfd ~= client.rfd then
...@@ -302,7 +343,8 @@ function host() ...@@ -302,7 +343,8 @@ function host()
end end
-- the instance -- the instance
local h = { -- data local h = setmetatable(
{ -- data
status_callbacks = status_callbacks, status_callbacks = status_callbacks,
-- methods -- methods
listen = _listen, listen = _listen,
...@@ -310,7 +352,10 @@ function host() ...@@ -310,7 +352,10 @@ function host()
listen_stdio = _listen_stdio, listen_stdio = _listen_stdio,
accept_and_select = _accept_and_select, accept_and_select = _accept_and_select,
broadcast = _broadcast, broadcast = _broadcast,
} },
{ -- metatable
__gc = destructor,
__metatable = "",
})
return h return h
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment