2013-12-19 17:10:14 +00:00
# include "types.h"
# include "cfg/cfg.h"
# if HOST_OS==OS_LINUX
# include <poll.h>
# include <termios.h>
//#include <curses.h>
# include <fcntl.h>
# include <semaphore.h>
# include <stdarg.h>
# include <signal.h>
# include <sys/param.h>
# include <sys/mman.h>
# include <sys/time.h>
# include "hw/sh4/dyna/blockmanager.h"
# include <unistd.h>
2015-07-29 04:22:59 +00:00
# if defined(TARGET_EMSCRIPTEN)
2015-08-17 21:46:28 +00:00
# include <emscripten.h>
2015-07-29 04:22:59 +00:00
# endif
2013-12-19 17:10:14 +00:00
2016-03-02 05:48:34 +00:00
# if defined(SUPPORT_DISPMANX)
# include "linux-dist/dispmanx.h"
# endif
2015-08-11 23:57:29 +00:00
# if defined(SUPPORT_X11)
2015-08-17 21:46:28 +00:00
# include "linux-dist/x11.h"
2013-12-19 17:10:14 +00:00
# endif
2015-08-29 18:23:16 +00:00
# if defined(USE_SDL)
# include "sdl/sdl.h"
# endif
2015-08-15 03:07:37 +00:00
# if defined(USES_HOMEDIR)
2015-08-17 21:46:28 +00:00
# include <sys/stat.h>
2013-12-19 17:10:14 +00:00
# endif
2015-08-15 01:23:11 +00:00
# if defined(USE_EVDEV)
2015-08-17 21:46:28 +00:00
# include "linux-dist/evdev.h"
2018-08-13 11:00:24 +00:00
# include "hw/maple/maple_devs.h"
2015-08-15 01:23:11 +00:00
# endif
2018-08-24 21:13:41 +00:00
# include "hw/maple/maple_cfg.h"
2015-08-12 01:03:01 +00:00
# if defined(USE_JOYSTICK)
2015-08-17 21:46:28 +00:00
# include "linux-dist/joystick.h"
2015-08-12 01:03:01 +00:00
# endif
2013-12-20 15:24:38 +00:00
# ifdef TARGET_PANDORA
2015-08-17 21:46:28 +00:00
# include <signal.h>
# include <execinfo.h>
2015-08-21 00:52:49 +00:00
# include <sys/soundcard.h>
2013-12-20 15:24:38 +00:00
# endif
2015-08-11 23:57:29 +00:00
2015-08-24 22:54:23 +00:00
# if FEAT_HAS_NIXPROF
# include "profiler/profiler.h"
# endif
2013-12-19 17:10:14 +00:00
2015-08-11 23:57:29 +00:00
int msgboxf ( const wchar * text , unsigned int type , . . . )
2013-12-19 17:10:14 +00:00
{
2015-08-17 21:46:28 +00:00
va_list args ;
2013-12-19 17:10:14 +00:00
2015-08-17 21:46:28 +00:00
wchar temp [ 2048 ] ;
va_start ( args , type ) ;
vsprintf ( temp , text , args ) ;
va_end ( args ) ;
2013-12-19 17:10:14 +00:00
2015-08-17 21:46:28 +00:00
//printf(NULL,temp,VER_SHORTNAME,type | MB_TASKMODAL);
puts ( temp ) ;
return MBX_OK ;
2013-12-19 17:10:14 +00:00
}
2015-08-15 03:50:08 +00:00
void * x11_win = 0 ;
void * x11_disp = 0 ;
void * libPvr_GetRenderTarget ( )
{
2015-08-17 21:46:28 +00:00
return x11_win ;
2015-08-15 03:50:08 +00:00
}
void * libPvr_GetRenderSurface ( )
{
2015-08-17 21:46:28 +00:00
return x11_disp ;
2015-08-15 03:50:08 +00:00
}
2015-08-12 10:16:23 +00:00
u16 kcode [ 4 ] = { 0xFFFF , 0xFFFF , 0xFFFF , 0xFFFF } ;
u8 rt [ 4 ] = { 0 , 0 , 0 , 0 } ;
u8 lt [ 4 ] = { 0 , 0 , 0 , 0 } ;
2013-12-19 17:10:14 +00:00
u32 vks [ 4 ] ;
2015-08-12 10:29:41 +00:00
s8 joyx [ 4 ] , joyy [ 4 ] ;
2013-12-19 17:10:14 +00:00
void emit_WriteCodeCache ( ) ;
2015-08-12 01:40:09 +00:00
# if defined(USE_EVDEV)
2015-08-17 21:46:28 +00:00
/* evdev input */
2015-08-19 08:20:52 +00:00
static EvdevController evdev_controllers [ 4 ] = {
2015-08-17 21:46:28 +00:00
{ - 1 , NULL } ,
{ - 1 , NULL } ,
{ - 1 , NULL } ,
{ - 1 , NULL }
} ;
2015-08-12 01:40:09 +00:00
# endif
2013-12-19 17:10:14 +00:00
2015-08-12 01:40:09 +00:00
# if defined(USE_JOYSTICK)
2015-08-17 21:46:28 +00:00
/* legacy joystick input */
static int joystick_fd = - 1 ; // Joystick file descriptor
2015-08-12 01:40:09 +00:00
# endif
2018-08-20 14:35:48 +00:00
MapleDeviceType GetMapleDeviceType ( int value , int port )
2018-08-16 08:20:42 +00:00
{
switch ( value )
{
2018-08-20 14:35:48 +00:00
case 0 :
# if defined(_DEBUG) || defined(DEBUG)
printf ( " Maple Device: None \n " ) ;
# endif
return MDT_None ;
2018-08-16 08:20:42 +00:00
case 1 :
# if defined(_DEBUG) || defined(DEBUG)
printf ( " Maple Device: VMU \n " ) ;
# endif
return MDT_SegaVMU ;
case 2 :
# if defined(_DEBUG) || defined(DEBUG)
printf ( " Maple Device: Microphone \n " ) ;
# endif
return MDT_Microphone ;
case 3 :
# if defined(_DEBUG) || defined(DEBUG)
printf ( " Maple Device: PuruPuruPack \n " ) ;
# endif
return MDT_PurupuruPack ;
default :
2018-08-20 14:35:48 +00:00
MapleDeviceType result = MDT_None ;
string result_type = " None " ;
2018-08-16 08:20:42 +00:00
2018-08-27 08:01:08 +00:00
// Controller in port 0 (player1) defaults to VMU for Maple device, all other to None
if ( port = = 0 )
2018-08-20 14:35:48 +00:00
{
result_type = " VMU " ;
result = MDT_SegaVMU ;
}
2018-08-20 20:15:18 +00:00
printf ( " Unsupported configuration (%d) for Maple Device, using %s \n " , value , result_type . c_str ( ) ) ;
2018-08-20 14:35:48 +00:00
return result ;
}
2018-08-16 08:20:42 +00:00
}
2018-08-20 11:36:34 +00:00
void os_SetupInput ( )
2015-08-12 01:40:09 +00:00
{
2015-08-17 21:46:28 +00:00
# if defined(USE_EVDEV)
int evdev_device_id [ 4 ] = { - 1 , - 1 , - 1 , - 1 } ;
2015-08-21 12:32:04 +00:00
size_t size_needed ;
2015-08-18 18:57:18 +00:00
int port , i ;
2015-08-17 21:46:28 +00:00
char * evdev_device ;
2015-08-21 00:52:49 +00:00
2015-08-17 21:46:28 +00:00
for ( port = 0 ; port < 4 ; port + + )
{
2015-08-21 12:32:04 +00:00
size_needed = snprintf ( NULL , 0 , EVDEV_DEVICE_CONFIG_KEY , port + 1 ) + 1 ;
char * evdev_config_key = ( char * ) malloc ( size_needed ) ;
sprintf ( evdev_config_key , EVDEV_DEVICE_CONFIG_KEY , port + 1 ) ;
2015-08-17 21:46:28 +00:00
evdev_device_id [ port ] = cfgLoadInt ( " input " , evdev_config_key , EVDEV_DEFAULT_DEVICE_ID ( port + 1 ) ) ;
2015-08-18 18:57:18 +00:00
free ( evdev_config_key ) ;
2015-08-21 00:52:49 +00:00
2015-08-17 21:46:28 +00:00
// Check if the same device is already in use on another port
if ( evdev_device_id [ port ] < 0 )
{
printf ( " evdev: Controller %d disabled by config. \n " , port + 1 ) ;
}
else
{
2015-08-18 18:57:18 +00:00
size_needed = snprintf ( NULL , 0 , EVDEV_DEVICE_STRING , evdev_device_id [ port ] ) + 1 ;
evdev_device = ( char * ) malloc ( size_needed ) ;
2015-08-17 21:46:28 +00:00
sprintf ( evdev_device , EVDEV_DEVICE_STRING , evdev_device_id [ port ] ) ;
2015-08-18 18:57:18 +00:00
size_needed = snprintf ( NULL , 0 , EVDEV_MAPPING_CONFIG_KEY , port + 1 ) + 1 ;
evdev_config_key = ( char * ) malloc ( size_needed ) ;
sprintf ( evdev_config_key , EVDEV_MAPPING_CONFIG_KEY , port + 1 ) ;
2017-12-09 14:51:57 +00:00
string tmp ;
const char * mapping = ( cfgExists ( " input " , evdev_config_key ) = = 2 ? ( tmp = cfgLoadStr ( " input " , evdev_config_key , " " ) ) . c_str ( ) : NULL ) ;
2015-08-18 18:57:18 +00:00
free ( evdev_config_key ) ;
2015-08-19 08:20:52 +00:00
input_evdev_init ( & evdev_controllers [ port ] , evdev_device , mapping ) ;
2015-08-18 19:50:19 +00:00
2015-08-17 21:46:28 +00:00
free ( evdev_device ) ;
2018-08-11 07:56:13 +00:00
for ( i = 0 ; i < port ; i + + )
{
if ( evdev_device_id [ port ] = = evdev_device_id [ i ] )
{
// Multiple controllers with the same device, check for multiple button assignments
if ( input_evdev_button_duplicate_button ( evdev_controllers [ i ] . mapping , evdev_controllers [ port ] . mapping ) )
{
2018-08-25 08:55:52 +00:00
printf ( " WARNING: One or more button(s) of this device is also used in the configuration of input device %d (mapping: %s) \n " , i , evdev_controllers [ i ] . mapping - > name . c_str ( ) ) ;
2018-08-11 07:56:13 +00:00
}
}
}
2018-08-13 11:00:24 +00:00
2018-08-20 14:35:48 +00:00
mcfg_CreateController ( port , GetMapleDeviceType ( evdev_controllers [ port ] . mapping - > Maple_Device1 , port ) , GetMapleDeviceType ( evdev_controllers [ port ] . mapping - > Maple_Device2 , port ) ) ;
2015-08-17 21:46:28 +00:00
}
}
# endif
# if defined(USE_JOYSTICK)
int joystick_device_id = cfgLoadInt ( " input " , " joystick_device_id " , JOYSTICK_DEFAULT_DEVICE_ID ) ;
if ( joystick_device_id < 0 ) {
2015-08-25 23:34:49 +00:00
puts ( " Legacy Joystick input disabled by config. \n " ) ;
2015-08-17 21:46:28 +00:00
}
else
{
int joystick_device_length = snprintf ( NULL , 0 , JOYSTICK_DEVICE_STRING , joystick_device_id ) ;
char * joystick_device = ( char * ) malloc ( joystick_device_length + 1 ) ;
sprintf ( joystick_device , JOYSTICK_DEVICE_STRING , joystick_device_id ) ;
joystick_fd = input_joystick_init ( joystick_device ) ;
free ( joystick_device ) ;
}
# endif
# if defined(SUPPORT_X11)
input_x11_init ( ) ;
# endif
2015-08-29 18:23:16 +00:00
# if defined(USE_SDL)
input_sdl_init ( ) ;
# endif
2013-12-19 17:10:14 +00:00
}
void UpdateInputState ( u32 port )
{
2015-08-17 21:46:28 +00:00
# if defined(TARGET_EMSCRIPTEN)
return ;
# endif
2015-08-11 16:08:06 +00:00
2015-08-17 21:46:28 +00:00
# if defined(USE_JOYSTICK)
input_joystick_handle ( joystick_fd , port ) ;
# endif
2015-08-12 01:40:09 +00:00
2015-08-17 21:46:28 +00:00
# if defined(USE_EVDEV)
2015-08-19 08:20:52 +00:00
input_evdev_handle ( & evdev_controllers [ port ] , port ) ;
2015-08-17 21:46:28 +00:00
# endif
2015-08-29 18:23:16 +00:00
# if defined(USE_SDL)
input_sdl_handle ( port ) ;
# endif
2013-12-19 17:10:14 +00:00
}
2015-12-08 00:27:19 +00:00
void UpdateVibration ( u32 port , u32 value )
{
2015-12-14 00:09:03 +00:00
# if defined(USE_EVDEV)
u8 POW_POS = ( value > > 8 ) & 0x3 ;
u8 POW_NEG = ( value > > 12 ) & 0x3 ;
u8 FREQ = ( value > > 16 ) & 0xFF ;
double pow = ( POW_POS + POW_NEG ) / 7.0 ;
double pow_l = pow * ( 0x3B - FREQ ) / 17.0 ;
2016-09-13 11:46:05 +00:00
double pow_r = pow * ( FREQ - 0x07 ) / 15.0 ;
2015-12-14 00:09:03 +00:00
if ( pow_l > 1.0 ) pow_l = 1.0 ;
if ( pow_r > 1.0 ) pow_r = 1.0 ;
u16 pow_strong = ( u16 ) ( 65535 * pow_l ) ;
u16 pow_weak = ( u16 ) ( 65535 * pow_r ) ;
input_evdev_rumble ( & evdev_controllers [ port ] , pow_strong , pow_weak ) ;
# endif
2015-12-08 00:27:19 +00:00
}
2013-12-19 17:10:14 +00:00
void os_DoEvents ( )
{
2015-08-17 21:46:28 +00:00
# if defined(SUPPORT_X11)
input_x11_handle ( ) ;
2018-07-23 17:47:24 +00:00
event_x11_handle ( ) ;
2015-08-17 21:46:28 +00:00
# endif
2013-12-19 17:10:14 +00:00
}
void os_SetWindowText ( const char * text )
{
2015-08-17 21:46:28 +00:00
printf ( " %s \n " , text ) ;
# if defined(SUPPORT_X11)
x11_window_set_text ( text ) ;
# endif
2015-08-29 18:23:16 +00:00
# if defined(USE_SDL)
sdl_window_set_text ( text ) ;
# endif
2013-12-19 17:10:14 +00:00
}
void os_CreateWindow ( )
{
2016-03-02 05:48:34 +00:00
# if defined(SUPPORT_DISPMANX)
dispmanx_window_create ( ) ;
# endif
2015-08-17 21:46:28 +00:00
# if defined(SUPPORT_X11)
x11_window_create ( ) ;
# endif
2015-08-29 18:23:16 +00:00
# if defined(USE_SDL)
sdl_window_create ( ) ;
# endif
2013-12-19 17:10:14 +00:00
}
2015-08-11 23:57:29 +00:00
void common_linux_setup ( ) ;
int dc_init ( int argc , wchar * argv [ ] ) ;
void dc_run ( ) ;
2018-07-23 17:47:24 +00:00
void dc_term ( ) ;
2013-12-19 17:10:14 +00:00
2015-08-11 23:57:29 +00:00
# ifdef TARGET_PANDORA
2015-08-17 21:46:28 +00:00
void gl_term ( ) ;
void clean_exit ( int sig_num )
{
void * array [ 10 ] ;
size_t size ;
if ( joystick_fd > = 0 ) { close ( joystick_fd ) ; }
for ( int port = 0 ; port < 4 ; port + + )
{
2015-08-19 08:20:52 +00:00
if ( evdev_controllers [ port ] - > fd > = 0 )
2015-08-17 21:46:28 +00:00
{
2015-08-19 08:20:52 +00:00
close ( evdev_controllers [ port ] - > fd ) ;
2015-08-17 21:46:28 +00:00
}
}
// Close EGL context ???
if ( sig_num ! = 0 )
{
gl_term ( ) ;
}
x11_window_destroy ( ) :
// finish cleaning
if ( sig_num ! = 0 )
{
write ( 2 , " \n Signal received \n " , sizeof ( " \n Signal received \n " ) ) ;
size = backtrace ( array , 10 ) ;
backtrace_symbols_fd ( array , size , STDERR_FILENO ) ;
exit ( 1 ) ;
}
}
2013-12-20 15:24:38 +00:00
# endif
2015-08-22 19:49:12 +00:00
string find_user_config_dir ( )
2015-08-22 16:47:17 +00:00
{
# ifdef USES_HOMEDIR
struct stat info ;
string home = " " ;
if ( getenv ( " HOME " ) ! = NULL )
{
// Support for the legacy config dir at "$HOME/.reicast"
string legacy_home = ( string ) getenv ( " HOME " ) + " /.reicast " ;
if ( ( stat ( legacy_home . c_str ( ) , & info ) = = 0 ) & & ( info . st_mode & S_IFDIR ) )
{
// "$HOME/.reicast" already exists, let's use it!
return legacy_home ;
}
/* If $XDG_CONFIG_HOME is not set, we're supposed to use "$HOME/.config" instead.
* Consult the XDG Base Directory Specification for details :
* http : //standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
*/
home = ( string ) getenv ( " HOME " ) + " /.config/reicast " ;
}
if ( getenv ( " XDG_CONFIG_HOME " ) ! = NULL )
{
// If XDG_CONFIG_HOME is set explicitly, we'll use that instead of $HOME/.config
home = ( string ) getenv ( " XDG_CONFIG_HOME " ) + " /reicast " ;
}
2015-08-22 19:49:12 +00:00
2015-08-22 16:47:17 +00:00
if ( ! home . empty ( ) )
{
if ( ( stat ( home . c_str ( ) , & info ) ! = 0 ) | | ! ( info . st_mode & S_IFDIR ) )
{
// If the directory doesn't exist yet, create it!
mkdir ( home . c_str ( ) , 0755 ) ;
}
return home ;
}
# endif
2015-08-22 19:49:12 +00:00
// Unable to detect config dir, use the current folder
return " . " ;
}
string find_user_data_dir ( )
{
# ifdef USES_HOMEDIR
struct stat info ;
string data = " " ;
if ( getenv ( " HOME " ) ! = NULL )
{
// Support for the legacy config dir at "$HOME/.reicast"
string legacy_data = ( string ) getenv ( " HOME " ) + " /.reicast " ;
if ( ( stat ( legacy_data . c_str ( ) , & info ) = = 0 ) & & ( info . st_mode & S_IFDIR ) )
{
// "$HOME/.reicast" already exists, let's use it!
return legacy_data ;
}
/* If $XDG_DATA_HOME is not set, we're supposed to use "$HOME/.local/share" instead.
* Consult the XDG Base Directory Specification for details :
* http : //standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#variables
*/
data = ( string ) getenv ( " HOME " ) + " /.local/share/reicast " ;
}
if ( getenv ( " XDG_DATA_HOME " ) ! = NULL )
{
// If XDG_DATA_HOME is set explicitly, we'll use that instead of $HOME/.config
data = ( string ) getenv ( " XDG_DATA_HOME " ) + " /reicast " ;
}
2018-08-13 11:00:24 +00:00
2015-08-22 19:49:12 +00:00
if ( ! data . empty ( ) )
{
if ( ( stat ( data . c_str ( ) , & info ) ! = 0 ) | | ! ( info . st_mode & S_IFDIR ) )
{
// If the directory doesn't exist yet, create it!
mkdir ( data . c_str ( ) , 0755 ) ;
}
return data ;
}
# endif
2015-08-22 16:47:17 +00:00
// Unable to detect config dir, use the current folder
return " . " ;
}
2015-08-22 19:49:12 +00:00
std : : vector < string > find_system_config_dirs ( )
{
std : : vector < string > dirs ;
2016-01-30 09:21:17 +00:00
if ( getenv ( " XDG_CONFIG_DIRS " ) ! = NULL )
2015-08-22 19:49:12 +00:00
{
string s = ( string ) getenv ( " XDG_CONFIG_DIRS " ) ;
string : : size_type pos = 0 ;
string : : size_type n = s . find ( " : " , pos ) ;
while ( n ! = std : : string : : npos )
{
dirs . push_back ( s . substr ( pos , n - pos ) + " /reicast " ) ;
pos = n + 1 ;
n = s . find ( " : " , pos ) ;
}
// Separator not found
dirs . push_back ( s . substr ( pos ) + " /reicast " ) ;
}
else
{
2015-08-23 00:13:19 +00:00
dirs . push_back ( " /etc/reicast " ) ; // This isn't part of the XDG spec, but much more common than /etc/xdg/
2015-08-22 19:49:12 +00:00
dirs . push_back ( " /etc/xdg/reicast " ) ;
}
return dirs ;
}
std : : vector < string > find_system_data_dirs ( )
{
std : : vector < string > dirs ;
if ( getenv ( " XDG_DATA_DIRS " ) ! = NULL )
{
string s = ( string ) getenv ( " XDG_DATA_DIRS " ) ;
string : : size_type pos = 0 ;
string : : size_type n = s . find ( " : " , pos ) ;
while ( n ! = std : : string : : npos )
{
dirs . push_back ( s . substr ( pos , n - pos ) + " /reicast " ) ;
pos = n + 1 ;
n = s . find ( " : " , pos ) ;
}
// Separator not found
dirs . push_back ( s . substr ( pos ) + " /reicast " ) ;
}
else
{
dirs . push_back ( " /usr/local/share/reicast " ) ;
dirs . push_back ( " /usr/share/reicast " ) ;
}
return dirs ;
}
2013-12-19 17:10:14 +00:00
int main ( int argc , wchar * argv [ ] )
{
2015-08-17 21:46:28 +00:00
# ifdef TARGET_PANDORA
signal ( SIGSEGV , clean_exit ) ;
signal ( SIGKILL , clean_exit ) ;
# endif
2015-08-22 19:49:12 +00:00
/* Set directories */
set_user_config_dir ( find_user_config_dir ( ) ) ;
set_user_data_dir ( find_user_data_dir ( ) ) ;
std : : vector < string > dirs ;
dirs = find_system_config_dirs ( ) ;
for ( unsigned int i = 0 ; i < dirs . size ( ) ; i + + )
{
add_system_data_dir ( dirs [ i ] ) ;
}
dirs = find_system_data_dirs ( ) ;
for ( unsigned int i = 0 ; i < dirs . size ( ) ; i + + )
{
add_system_data_dir ( dirs [ i ] ) ;
}
2015-08-28 23:28:51 +00:00
printf ( " Config dir is: %s \n " , get_writable_config_path ( " / " ) . c_str ( ) ) ;
printf ( " Data dir is: %s \n " , get_writable_data_path ( " / " ) . c_str ( ) ) ;
2015-08-17 21:46:28 +00:00
2015-08-29 18:23:16 +00:00
# if defined(USE_SDL)
if ( SDL_Init ( 0 ) ! = 0 )
{
die ( " SDL: Initialization failed! " ) ;
}
# endif
2015-08-17 21:46:28 +00:00
common_linux_setup ( ) ;
settings . profile . run_counts = 0 ;
dc_init ( argc , argv ) ;
# if !defined(TARGET_EMSCRIPTEN)
2015-08-24 22:54:23 +00:00
# if FEAT_HAS_NIXPROF
install_prof_handler ( 0 ) ;
# endif
2015-08-17 21:46:28 +00:00
dc_run ( ) ;
# else
emscripten_set_main_loop ( & dc_run , 100 , false ) ;
# endif
# ifdef TARGET_PANDORA
clean_exit ( 0 ) ;
# endif
2018-07-23 17:47:24 +00:00
dc_term ( ) ;
# if defined(USE_EVDEV)
for ( int port = 0 ; port < 4 ; port + + )
{
if ( evdev_controllers [ port ] . fd > = 0 )
{
close ( evdev_controllers [ port ] . fd ) ;
}
}
# endif
# if defined(SUPPORT_X11)
x11_window_destroy ( ) ;
# endif
2015-08-17 21:46:28 +00:00
return 0 ;
2015-08-11 23:57:29 +00:00
}
2015-04-14 14:58:41 +00:00
# endif
2014-03-20 15:13:53 +00:00
int get_mic_data ( u8 * buffer ) { return 0 ; }
int push_vmu_screen ( u8 * buffer ) { return 0 ; }
2014-12-30 11:20:51 +00:00
void os_DebugBreak ( )
{
2015-08-17 21:46:28 +00:00
# if !defined(TARGET_EMSCRIPTEN)
raise ( SIGTRAP ) ;
# else
printf ( " DEBUGBREAK! \n " ) ;
exit ( - 1 ) ;
# endif
2014-12-30 11:20:51 +00:00
}
2015-08-18 18:57:18 +00:00
2015-08-19 05:04:36 +00:00