2004-09-07 18:10:08 +00:00
/*
Copyright ( C ) 1996 - 1997 Id Software , Inc .
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
2005-11-03 23:42:00 +00:00
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
2004-09-07 18:10:08 +00:00
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 . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
2013-05-07 21:07:14 +00:00
# ifdef __i386__
# define _GNU_SOURCE //we need this in order to fix up broken backtraces. make sure its defined only where needed so we still some posixy conformance test on one plat.
# endif
2006-03-17 22:44:17 +00:00
# include <signal.h>
2004-09-07 18:10:08 +00:00
# include <sys/types.h>
2006-05-02 00:56:30 +00:00
# include <dlfcn.h>
2013-03-31 04:36:21 +00:00
# include "quakedef.h"
2004-09-07 18:10:08 +00:00
2006-03-17 22:44:17 +00:00
2004-09-07 18:10:08 +00:00
# undef malloc
# ifdef NeXT
# include <libc.h>
# endif
# include <sys/stat.h>
2005-12-21 03:07:33 +00:00
# include <termios.h>
2004-09-07 18:10:08 +00:00
# include <unistd.h>
# include <sys/time.h>
# include <errno.h>
# include <fcntl.h>
2010-01-11 18:15:42 +00:00
# include <dirent.h>
2011-07-06 01:01:13 +00:00
# include <time.h>
2004-09-07 18:10:08 +00:00
2007-12-30 20:12:50 +00:00
# ifdef MULTITHREAD
# include <pthread.h>
# endif
2006-05-06 02:53:36 +00:00
// callbacks
void Sys_Linebuffer_Callback ( struct cvar_s * var , char * oldvalue ) ;
2010-07-11 12:33:58 +00:00
cvar_t sys_nostdout = CVAR ( " sys_nostdout " , " 0 " ) ;
cvar_t sys_extrasleep = CVAR ( " sys_extrasleep " , " 0 " ) ;
2013-05-13 13:43:18 +00:00
cvar_t sys_colorconsole = CVAR ( " sys_colorconsole " , " 1 " ) ;
2010-07-11 12:33:58 +00:00
cvar_t sys_linebuffer = CVARC ( " sys_linebuffer " , " 1 " , Sys_Linebuffer_Callback ) ;
2004-09-07 18:10:08 +00:00
qboolean stdin_ready ;
2005-12-21 03:07:33 +00:00
struct termios orig , changes ;
2004-09-07 18:10:08 +00:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
REQUIRED SYS FUNCTIONS
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
/*
= = = = = = = = = = = =
Sys_FileTime
returns - 1 if not present
= = = = = = = = = = = =
*/
int Sys_FileTime ( char * path )
{
struct stat buf ;
2005-11-03 23:42:00 +00:00
2004-09-07 18:10:08 +00:00
if ( stat ( path , & buf ) = = - 1 )
return - 1 ;
2005-11-03 23:42:00 +00:00
2004-09-07 18:10:08 +00:00
return buf . st_mtime ;
}
/*
= = = = = = = = = = = =
Sys_mkdir
= = = = = = = = = = = =
*/
void Sys_mkdir ( char * path )
{
if ( mkdir ( path , 0777 ) ! = - 1 )
return ;
2007-03-11 12:27:17 +00:00
// if (errno != EEXIST)
// Sys_Error ("mkdir %s: %s",path, strerror(errno));
2004-09-07 18:10:08 +00:00
}
qboolean Sys_remove ( char * path )
{
return system ( va ( " rm \" %s \" " , path ) ) ;
}
2012-04-24 07:59:11 +00:00
qboolean Sys_Rename ( char * oldfname , char * newfname )
{
return ! rename ( oldfname , newfname ) ;
}
2005-12-05 16:47:29 +00:00
int Sys_DebugLog ( char * file , char * fmt , . . . )
2004-09-07 18:10:08 +00:00
{
va_list argptr ;
char data [ 1024 ] ;
int fd ;
2011-05-15 13:23:13 +00:00
size_t result ;
2005-11-03 23:42:00 +00:00
2004-09-07 18:10:08 +00:00
va_start ( argptr , fmt ) ;
2012-07-15 02:44:54 +00:00
vsnprintf ( data , sizeof ( data ) - 1 , fmt , argptr ) ;
2004-09-07 18:10:08 +00:00
va_end ( argptr ) ;
if ( strlen ( data ) > = sizeof ( data ) - 1 )
Sys_Error ( " Sys_DebugLog was stomped \n " ) ;
fd = open ( file , O_WRONLY | O_CREAT | O_APPEND , 0666 ) ;
2005-12-05 16:47:29 +00:00
if ( fd )
{
2011-05-15 13:23:13 +00:00
result = write ( fd , data , strlen ( data ) ) ; // do something with the result
2011-05-30 04:32:04 +00:00
if ( result ! = strlen ( data ) )
2011-06-01 13:21:54 +00:00
Con_Printf ( " Sys_DebugLog() write: Filename: %s, expected %lu, result was %lu (%s) \n " , file , ( unsigned long ) strlen ( data ) , ( unsigned long ) result , strerror ( errno ) ) ;
2011-05-30 04:32:04 +00:00
2005-12-05 16:47:29 +00:00
close ( fd ) ;
return 0 ;
}
return 1 ;
2004-09-07 18:10:08 +00:00
}
2007-10-02 15:17:22 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_Milliseconds
= = = = = = = = = = = = = = = =
*/
unsigned int Sys_Milliseconds ( void )
{
struct timeval tp ;
struct timezone tzp ;
2007-12-03 11:38:58 +00:00
static int secbase ;
2007-10-02 15:17:22 +00:00
gettimeofday ( & tp , & tzp ) ;
if ( ! secbase )
{
secbase = tp . tv_sec ;
return tp . tv_usec / 1000 ;
}
return ( tp . tv_sec - secbase ) * 1000 + tp . tv_usec / 1000 ;
}
2004-09-07 18:10:08 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_DoubleTime
= = = = = = = = = = = = = = = =
*/
double Sys_DoubleTime ( void )
{
struct timeval tp ;
struct timezone tzp ;
static int secbase ;
gettimeofday ( & tp , & tzp ) ;
2005-11-03 23:42:00 +00:00
2004-09-07 18:10:08 +00:00
if ( ! secbase )
{
secbase = tp . tv_sec ;
return tp . tv_usec / 1000000.0 ;
}
2005-11-03 23:42:00 +00:00
2004-09-07 18:10:08 +00:00
return ( tp . tv_sec - secbase ) + tp . tv_usec / 1000000.0 ;
}
/*
= = = = = = = = = = = = = = = =
Sys_Error
= = = = = = = = = = = = = = = =
*/
void Sys_Error ( const char * error , . . . )
{
va_list argptr ;
char string [ 1024 ] ;
2005-11-03 23:42:00 +00:00
2004-09-07 18:10:08 +00:00
va_start ( argptr , error ) ;
2012-07-15 02:44:54 +00:00
vsnprintf ( string , sizeof ( string ) - 1 , error , argptr ) ;
2004-09-07 18:10:08 +00:00
va_end ( argptr ) ;
printf ( " Fatal error: %s \n " , string ) ;
2005-11-03 23:42:00 +00:00
2005-12-21 03:07:33 +00:00
tcsetattr ( STDIN_FILENO , TCSADRAIN , & orig ) ;
2004-09-07 18:10:08 +00:00
* ( int * ) - 3 = 0 ;
exit ( 1 ) ;
}
2006-01-01 09:01:15 +00:00
int ansiremap [ 8 ] = { 0 , 4 , 2 , 6 , 1 , 5 , 3 , 7 } ;
2005-12-21 03:07:33 +00:00
void ApplyColour ( unsigned int chr )
{
2006-01-01 09:01:15 +00:00
static int oldchar = CON_WHITEMASK ;
int bg , fg ;
chr & = CON_FLAGSMASK ;
2005-12-21 03:07:33 +00:00
if ( oldchar = = chr )
return ;
oldchar = chr ;
2006-01-01 09:01:15 +00:00
printf ( " \ e[0; " ) ; // reset
if ( chr & CON_BLINKTEXT )
printf ( " 5; " ) ; // set blink
2006-04-06 08:21:17 +00:00
bg = ( chr & CON_BGMASK ) > > CON_BGSHIFT ;
fg = ( chr & CON_FGMASK ) > > CON_FGSHIFT ;
2011-05-15 13:23:13 +00:00
2006-01-01 09:01:15 +00:00
// don't handle intensive bit for background
// as terminals differ too much in displaying \e[1;7;3?m
bg & = 0x7 ;
if ( chr & CON_NONCLEARBG )
{
if ( fg & 0x8 ) // intensive bit set for foreground
{
printf ( " 1; " ) ; // set bold/intensity ansi flag
fg & = 0x7 ; // strip intensive bit
}
// set foreground and background colors
printf ( " 3%i;4%im " , ansiremap [ fg ] , ansiremap [ bg ] ) ;
}
else
2005-12-21 03:07:33 +00:00
{
2006-01-01 09:01:15 +00:00
switch ( fg )
{
//to get around wierd defaults (like a white background) we have these special hacks for colours 0 and 7
case COLOR_BLACK :
printf ( " 7m " ) ; // set inverse
break ;
case COLOR_GREY :
printf ( " 1;30m " ) ; // treat as dark grey
break ;
case COLOR_WHITE :
2006-01-29 00:47:54 +00:00
printf ( " m " ) ; // set nothing else
2006-01-01 09:01:15 +00:00
break ;
default :
if ( fg & 0x8 ) // intensive bit set for foreground
{
printf ( " 1; " ) ; // set bold/intensity ansi flag
fg & = 0x7 ; // strip intensive bit
}
2006-04-06 08:21:17 +00:00
printf ( " 3%im " , ansiremap [ fg ] ) ; // set foreground
2006-01-01 09:01:15 +00:00
break ;
}
2005-12-21 03:07:33 +00:00
}
}
# define putch(c) putc(c, stdout);
void Sys_PrintColouredChar ( unsigned int chr )
{
ApplyColour ( chr ) ;
2006-04-06 08:33:47 +00:00
chr = chr & CON_CHARMASK ;
2006-03-11 04:57:22 +00:00
if ( ( chr > 128 | | chr < 32 ) & & chr ! = 10 & & chr ! = 13 & & chr ! = 9 )
printf ( " [%02x] " , chr ) ;
else
chr & = ~ 0x80 ;
2006-04-06 08:33:47 +00:00
putch ( chr ) ;
2005-12-21 03:07:33 +00:00
}
/*
= = = = = = = = = = = = = = = =
Sys_Printf
= = = = = = = = = = = = = = = =
*/
# define MAXPRINTMSG 4096
char coninput_text [ 256 ] ;
int coninput_len ;
void Sys_Printf ( char * fmt , . . . )
{
2011-05-15 13:23:13 +00:00
va_list argptr ;
2005-12-21 03:07:33 +00:00
if ( sys_nostdout . value )
return ;
if ( 1 )
{
char msg [ MAXPRINTMSG ] ;
unsigned char * t ;
va_start ( argptr , fmt ) ;
vsnprintf ( msg , sizeof ( msg ) - 1 , fmt , argptr ) ;
va_end ( argptr ) ;
2013-05-13 13:43:18 +00:00
//if we're not linebuffered, kill the currently displayed input line, add the new text, and add more output.
2005-12-21 03:07:33 +00:00
if ( ! sys_linebuffer . value )
{
int i ;
2011-05-15 13:23:13 +00:00
2005-12-21 03:07:33 +00:00
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
putch ( ' \b ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' ' ) ;
putch ( ' ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
putch ( ' \b ' ) ;
}
2013-05-13 13:43:18 +00:00
if ( sys_colorconsole . value )
2005-12-21 03:07:33 +00:00
{
2013-05-13 13:43:18 +00:00
wchar_t w ;
conchar_t * e , * c ;
conchar_t ctext [ MAXPRINTMSG ] ;
e = COM_ParseFunString ( CON_WHITEMASK , msg , ctext , sizeof ( ctext ) , false ) ;
for ( c = ctext ; c < e ; c + + )
2005-12-21 03:07:33 +00:00
{
2013-05-13 13:43:18 +00:00
if ( * c & CON_HIDDEN )
continue ;
ApplyColour ( * c ) ;
w = * c & 0x0ffff ;
if ( w > = 0xe000 & & w < 0xe100 )
2005-12-21 03:07:33 +00:00
{
2013-05-13 13:43:18 +00:00
/*not all quake chars are ascii compatible, so map those control chars to safe ones so we don't mess up anyone's xterm*/
if ( ( w & 0x7f ) > 0x20 )
putc ( w & 0x7f , stdout ) ;
else if ( w & 0x80 )
2006-01-11 07:23:31 +00:00
{
2013-05-13 13:43:18 +00:00
static char tab [ 32 ] = " ---#@.@@@@ # >.. " " []0123456789.--- " ;
putc ( tab [ w & 31 ] , stdout ) ;
2006-01-11 07:23:31 +00:00
}
2013-05-13 13:43:18 +00:00
else
2005-12-21 03:07:33 +00:00
{
2013-05-13 13:43:18 +00:00
static char tab [ 32 ] = " .####.#### # >.. " " []0123456789.--- " ;
putc ( tab [ w & 31 ] , stdout ) ;
2005-12-21 03:07:33 +00:00
}
2013-05-13 13:43:18 +00:00
}
else
{
/*putwc doesn't like me. force it in utf8*/
if ( w > = 0x80 )
2005-12-21 03:07:33 +00:00
{
2013-05-13 13:43:18 +00:00
if ( w > 0x800 )
2005-12-21 03:07:33 +00:00
{
2013-05-13 13:43:18 +00:00
putc ( 0xe0 | ( ( w > > 12 ) & 0x0f ) , stdout ) ;
putc ( 0x80 | ( ( w > > 6 ) & 0x3f ) , stdout ) ;
2005-12-21 03:07:33 +00:00
}
2013-05-13 13:43:18 +00:00
else
putc ( 0xc0 | ( ( w > > 6 ) & 0x1f ) , stdout ) ;
putc ( 0x80 | ( w & 0x3f ) , stdout ) ;
2005-12-21 03:07:33 +00:00
}
else
2013-05-13 13:43:18 +00:00
putc ( w , stdout ) ;
2005-12-21 03:07:33 +00:00
}
}
}
else
{
2013-05-13 13:43:18 +00:00
for ( t = ( unsigned char * ) msg ; * t ; t + + )
2005-12-21 03:07:33 +00:00
{
2013-05-13 13:43:18 +00:00
if ( * t > = 146 & & * t < 156 )
* t = * t - 146 + ' 0 ' ;
if ( * t > = 0x12 & & * t < = 0x1b )
* t = * t - 0x12 + ' 0 ' ;
if ( * t = = 143 )
* t = ' . ' ;
if ( * t = = 157 | | * t = = 158 | | * t = = 159 )
* t = ' - ' ;
if ( * t > = 128 )
* t - = 128 ;
if ( * t = = 16 )
* t = ' [ ' ;
if ( * t = = 17 )
* t = ' ] ' ;
if ( * t = = 0x1c )
* t = 249 ;
2005-12-21 03:07:33 +00:00
* t & = 0x7f ;
if ( ( * t > 128 | | * t < 32 ) & & * t ! = 10 & & * t ! = 13 & & * t ! = 9 )
printf ( " [%02x] " , * t ) ;
else
putc ( * t , stdout ) ;
}
}
2013-05-13 13:43:18 +00:00
//and put the input line back
2005-12-21 03:07:33 +00:00
if ( ! sys_linebuffer . value )
{
if ( coninput_len )
printf ( " ]%s " , coninput_text ) ;
else
putch ( ' ] ' ) ;
}
}
else
{
va_start ( argptr , fmt ) ;
vprintf ( fmt , argptr ) ;
va_end ( argptr ) ;
}
fflush ( stdout ) ;
}
#if 0
2004-09-07 18:10:08 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_Printf
= = = = = = = = = = = = = = = =
*/
void Sys_Printf ( char * fmt , . . . )
{
va_list argptr ;
static char text [ 2048 ] ;
unsigned char * p ;
va_start ( argptr , fmt ) ;
2012-07-15 02:44:54 +00:00
vsnprintf ( text , sizeof ( text ) - 1 , fmt , argptr ) ;
2004-09-07 18:10:08 +00:00
va_end ( argptr ) ;
if ( strlen ( text ) > sizeof ( text ) )
Sys_Error ( " memory overwrite in Sys_Printf " ) ;
2013-05-13 13:43:18 +00:00
if ( sys_nostdout . value )
return ;
2004-09-07 18:10:08 +00:00
for ( p = ( unsigned char * ) text ; * p ; p + + ) {
* p & = 0x7f ;
if ( ( * p > 128 | | * p < 32 ) & & * p ! = 10 & & * p ! = 13 & & * p ! = 9 )
printf ( " [%02x] " , * p ) ;
else
putc ( * p , stdout ) ;
}
fflush ( stdout ) ;
}
2005-12-21 03:07:33 +00:00
# endif
2004-09-07 18:10:08 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_Quit
= = = = = = = = = = = = = = = =
*/
void Sys_Quit ( void )
{
2005-12-21 03:07:33 +00:00
tcsetattr ( STDIN_FILENO , TCSADRAIN , & orig ) ;
2004-09-07 18:10:08 +00:00
exit ( 0 ) ; // appkit isn't running
}
static int do_stdin = 1 ;
2005-12-21 03:07:33 +00:00
# if 1
char * Sys_LineInputChar ( char * line )
{
2014-02-07 08:38:40 +00:00
char c ;
2005-12-21 03:07:33 +00:00
while ( * line )
{
2014-02-07 08:38:40 +00:00
c = * line + + ;
if ( c = = ' \r ' | | c = = ' \n ' )
2005-12-21 03:07:33 +00:00
{
coninput_text [ coninput_len ] = 0 ;
2014-02-07 08:38:40 +00:00
putch ( ' \n ' ) ;
putch ( ' ] ' ) ;
coninput_len = 0 ;
fflush ( stdout ) ;
return coninput_text ;
2005-12-21 03:07:33 +00:00
}
2014-02-07 08:38:40 +00:00
if ( c = = 8 )
2005-12-21 03:07:33 +00:00
{
2014-02-07 08:38:40 +00:00
if ( coninput_len )
{
putch ( c ) ;
putch ( ' ' ) ;
putch ( c ) ;
coninput_len - - ;
coninput_text [ coninput_len ] = 0 ;
}
continue ;
}
if ( c = = ' \t ' )
{
int i ;
char * s = Cmd_CompleteCommand ( coninput_text , true , true , 0 , NULL ) ;
if ( s )
{
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' ' ) ;
for ( i = 0 ; i < coninput_len ; i + + )
putch ( ' \b ' ) ;
strcpy ( coninput_text , s ) ;
coninput_len = strlen ( coninput_text ) ;
printf ( " %s " , coninput_text ) ;
}
continue ;
2005-12-21 03:07:33 +00:00
}
2014-02-07 08:38:40 +00:00
putch ( c ) ;
coninput_text [ coninput_len ] = c ;
coninput_len + + ;
coninput_text [ coninput_len ] = 0 ;
if ( coninput_len = = sizeof ( coninput_text ) )
coninput_len = 0 ;
2005-12-21 03:07:33 +00:00
}
fflush ( stdout ) ;
2014-02-07 08:38:40 +00:00
return NULL ;
2005-12-21 03:07:33 +00:00
}
# endif
2004-09-07 18:10:08 +00:00
/*
= = = = = = = = = = = = = = = =
Sys_ConsoleInput
Checks for a complete line of text typed in at the console , then forwards
it to the host command processor
= = = = = = = = = = = = = = = =
*/
2006-05-06 02:53:36 +00:00
void Sys_Linebuffer_Callback ( struct cvar_s * var , char * oldvalue )
{
changes = orig ;
if ( var - > value )
{
changes . c_lflag | = ( ICANON | ECHO ) ;
}
else
{
changes . c_lflag & = ~ ( ICANON | ECHO ) ;
changes . c_cc [ VTIME ] = 0 ;
changes . c_cc [ VMIN ] = 1 ;
}
tcsetattr ( STDIN_FILENO , TCSADRAIN , & changes ) ;
}
2004-09-07 18:10:08 +00:00
char * Sys_ConsoleInput ( void )
{
2006-03-04 20:43:48 +00:00
static char text [ 256 ] ;
2005-12-21 03:07:33 +00:00
int len ;
2004-09-07 18:10:08 +00:00
if ( ! stdin_ready | | ! do_stdin )
return NULL ; // the select didn't say it was ready
stdin_ready = false ;
2005-12-21 03:07:33 +00:00
if ( sys_linebuffer . value = = 0 )
{
text [ 0 ] = getc ( stdin ) ;
text [ 1 ] = 0 ;
len = 1 ;
return Sys_LineInputChar ( text ) ;
}
else
{
len = read ( 0 , text , sizeof ( text ) - 1 ) ;
2014-02-07 08:38:40 +00:00
if ( len = = 0 )
{
2005-12-21 03:07:33 +00:00
// end of file
do_stdin = 0 ;
return NULL ;
}
if ( len < 1 )
return NULL ;
text [ len - 1 ] = 0 ; // rip off the /n and terminate
return text ;
2004-09-07 18:10:08 +00:00
}
}
/*
= = = = = = = = = = = = =
Sys_Init
Quake calls this so the system can register variables before host_hunklevel
is marked
= = = = = = = = = = = = =
*/
void Sys_Init ( void )
{
Cvar_Register ( & sys_nostdout , " System configuration " ) ;
Cvar_Register ( & sys_extrasleep , " System configuration " ) ;
2005-12-21 03:07:33 +00:00
Cvar_Register ( & sys_colorconsole , " System configuration " ) ;
Cvar_Register ( & sys_linebuffer , " System configuration " ) ;
2004-09-07 18:10:08 +00:00
}
2011-04-30 17:21:10 +00:00
void Sys_Shutdown ( void )
{
}
2011-06-18 17:04:47 +00:00
# ifdef __linux__ /*should probably be GNUC but whatever*/
2011-06-06 01:41:33 +00:00
# include <execinfo.h>
2013-05-04 04:01:47 +00:00
# ifdef __i386__
# include <ucontext.h>
# endif
static void Friendly_Crash_Handler ( int sig , siginfo_t * info , void * vcontext )
2011-06-06 01:41:33 +00:00
{
int fd ;
void * array [ 10 ] ;
size_t size ;
2013-05-04 04:01:47 +00:00
int firstframe = 0 ;
char signame [ 32 ] ;
switch ( sig )
{
case SIGILL : strcpy ( signame , " SIGILL " ) ; break ;
case SIGFPE : strcpy ( signame , " SIGFPE " ) ; break ;
case SIGBUS : strcpy ( signame , " SIGBUS " ) ; break ;
case SIGSEGV : Q_snprintfz ( signame , sizeof ( signame ) , " SIGSEGV (%p) " , info - > si_addr ) ; break ;
default : Q_snprintfz ( signame , sizeof ( signame ) , " %i " , sig ) ; break ;
}
2011-06-06 01:41:33 +00:00
// get void*'s for all entries on the stack
size = backtrace ( array , 10 ) ;
2013-05-04 04:01:47 +00:00
# if defined(__i386__)
2013-05-07 19:41:17 +00:00
//x86 signals don't leave the stack in a clean state, so replace the signal handler with the real crash address, and hide this function
2013-05-07 21:07:14 +00:00
ucontext_t * uc = vcontext ;
array [ 1 ] = uc - > uc_mcontext . gregs [ REG_EIP ] ;
2013-05-04 04:01:47 +00:00
firstframe = 1 ;
# elif defined(__amd64__)
2013-05-07 19:41:17 +00:00
//amd64 is sane enough, but this function and the libc signal handler are on the stack, and should be ignored.
2013-05-04 04:01:47 +00:00
firstframe = 2 ;
# endif
2011-06-06 01:41:33 +00:00
// print out all the frames to stderr
2013-05-04 04:01:47 +00:00
fprintf ( stderr , " Error: signal %s: \n " , signame ) ;
backtrace_symbols_fd ( array + firstframe , size - firstframe , 2 ) ;
2011-06-06 01:41:33 +00:00
fd = open ( " crash.log " , O_WRONLY | O_CREAT | O_APPEND , S_IRUSR | S_IWUSR | S_IRGRP ) ;
if ( fd ! = - 1 )
{
2013-05-03 04:28:08 +00:00
time_t rawtime ;
struct tm * timeinfo ;
2013-05-04 04:01:47 +00:00
char buffer [ 80 ] ;
2013-05-03 04:28:08 +00:00
time ( & rawtime ) ;
timeinfo = localtime ( & rawtime ) ;
strftime ( buffer , sizeof ( buffer ) , " Time: %Y-%m-%d %H:%M:%S \n " , timeinfo ) ;
write ( fd , buffer , strlen ( buffer ) ) ;
2013-05-04 04:01:47 +00:00
Q_snprintfz ( buffer , sizeof ( buffer ) , " Binary: " __DATE__ " " __TIME__ " \n " ) ;
2013-05-03 04:28:08 +00:00
write ( fd , buffer , strlen ( buffer ) ) ;
2013-05-04 04:01:47 +00:00
Q_snprintfz ( buffer , sizeof ( buffer ) , " Ver: %i.%02i%s \n " , FTE_VER_MAJOR , FTE_VER_MINOR ,
2013-05-03 04:28:08 +00:00
# ifdef OFFICIAL_RELEASE
" (official) " ) ;
# else
" " ) ;
# endif
write ( fd , buffer , strlen ( buffer ) ) ;
# ifdef SVNREVISION
if ( strcmp ( STRINGIFY ( SVNREVISION ) , " - " ) )
{
2013-05-04 04:01:47 +00:00
Q_snprintfz ( buffer , sizeof ( buffer ) , " Revision: %s \n " , STRINGIFY ( SVNREVISION ) ) ;
2013-05-03 04:28:08 +00:00
write ( fd , buffer , strlen ( buffer ) ) ;
}
# endif
2013-05-04 04:01:47 +00:00
backtrace_symbols_fd ( array + firstframe , size - firstframe , fd ) ;
2011-06-06 01:41:33 +00:00
write ( fd , " \n " , 1 ) ;
close ( fd ) ;
}
exit ( 1 ) ;
}
2011-06-18 17:04:47 +00:00
# endif
2011-06-06 01:41:33 +00:00
2004-09-07 18:10:08 +00:00
/*
= = = = = = = = = = = = =
main
= = = = = = = = = = = = =
*/
int main ( int argc , char * argv [ ] )
{
2014-07-02 03:20:40 +00:00
float maxsleep ;
2004-09-07 18:10:08 +00:00
quakeparms_t parms ;
// fd_set fdset;
// extern int net_socket;
int j ;
2006-03-17 22:44:17 +00:00
signal ( SIGPIPE , SIG_IGN ) ;
2005-12-21 03:07:33 +00:00
tcgetattr ( STDIN_FILENO , & orig ) ;
changes = orig ;
2004-09-07 18:10:08 +00:00
memset ( & parms , 0 , sizeof ( parms ) ) ;
2011-05-19 13:34:07 +00:00
COM_InitArgv ( argc , ( const char * * ) argv ) ;
2004-09-07 18:10:08 +00:00
parms . argc = com_argc ;
parms . argv = com_argv ;
2011-06-18 17:04:47 +00:00
# ifdef __linux__
2013-05-03 04:28:08 +00:00
if ( ! COM_CheckParm ( " -nodumpstack " ) )
2011-06-06 01:41:33 +00:00
{
2013-05-04 04:01:47 +00:00
struct sigaction act ;
memset ( & act , 0 , sizeof ( act ) ) ;
act . sa_sigaction = Friendly_Crash_Handler ;
act . sa_flags = SA_SIGINFO | SA_RESTART ;
sigaction ( SIGILL , & act , NULL ) ;
sigaction ( SIGFPE , & act , NULL ) ;
sigaction ( SIGSEGV , & act , NULL ) ;
sigaction ( SIGBUS , & act , NULL ) ;
2011-06-06 01:41:33 +00:00
}
2011-06-18 17:04:47 +00:00
# endif
2006-03-17 22:44:17 +00:00
2013-11-21 23:02:28 +00:00
parms . basedir = " ./ " ;
2015-05-03 19:57:46 +00:00
TL_InitLanguages ( parms . basedir ) ;
2004-09-07 18:10:08 +00:00
SV_Init ( & parms ) ;
// run one frame immediately for first heartbeat
2014-07-02 03:20:40 +00:00
maxsleep = SV_Frame ( ) ;
2004-09-07 18:10:08 +00:00
//
// main loop
//
while ( 1 )
{
2005-03-10 03:55:18 +00:00
if ( do_stdin )
2011-06-05 23:53:33 +00:00
stdin_ready = NET_Sleep ( maxsleep , true ) ;
2005-03-10 03:55:18 +00:00
else
2005-11-03 23:42:00 +00:00
{
2011-06-05 23:53:33 +00:00
NET_Sleep ( maxsleep , false ) ;
2005-03-10 03:55:18 +00:00
stdin_ready = false ;
}
2004-09-07 18:10:08 +00:00
2014-07-02 03:20:40 +00:00
maxsleep = SV_Frame ( ) ;
2005-11-03 23:42:00 +00:00
2004-09-07 18:10:08 +00:00
// extrasleep is just a way to generate a fucked up connection on purpose
if ( sys_extrasleep . value )
usleep ( sys_extrasleep . value ) ;
2005-11-03 23:42:00 +00:00
}
2004-09-07 18:10:08 +00:00
return 0 ;
}
2015-02-02 08:01:53 +00:00
int Sys_EnumerateFiles ( const char * gpath , const char * match , int ( * func ) ( const char * , qofs_t , time_t mtime , void * , searchpathfuncs_t * ) , void * parm , searchpathfuncs_t * spath )
2004-09-07 18:10:08 +00:00
{
2010-01-11 18:15:42 +00:00
DIR * dir ;
2004-09-07 18:10:08 +00:00
char apath [ MAX_OSPATH ] ;
char file [ MAX_OSPATH ] ;
char truepath [ MAX_OSPATH ] ;
char * s ;
struct dirent * ent ;
2010-01-11 18:15:42 +00:00
struct stat st ;
2004-09-07 18:10:08 +00:00
//printf("path = %s\n", gpath);
//printf("match = %s\n", match);
if ( ! gpath )
gpath = " " ;
* apath = ' \0 ' ;
Q_strncpyz ( apath , match , sizeof ( apath ) ) ;
for ( s = apath + strlen ( apath ) - 1 ; s > = apath ; s - - )
{
if ( * s = = ' / ' )
{
s [ 1 ] = ' \0 ' ;
match + = s - apath + 1 ;
break ;
}
}
if ( s < apath ) //didn't find a '/'
* apath = ' \0 ' ;
2006-05-19 19:15:52 +00:00
Q_snprintfz ( truepath , sizeof ( truepath ) , " %s/%s " , gpath , apath ) ;
2004-09-07 18:10:08 +00:00
//printf("truepath = %s\n", truepath);
//printf("gamepath = %s\n", gpath);
//printf("apppath = %s\n", apath);
//printf("match = %s\n", match);
dir = opendir ( truepath ) ;
if ( ! dir )
{
2011-12-05 15:23:40 +00:00
Con_DPrintf ( " Failed to open dir %s \n " , truepath ) ;
2004-09-07 18:10:08 +00:00
return true ;
}
do
{
ent = readdir ( dir ) ;
if ( ! ent )
break ;
if ( * ent - > d_name ! = ' . ' )
2010-01-11 18:15:42 +00:00
{
2004-09-07 18:10:08 +00:00
if ( wildcmp ( match , ent - > d_name ) )
{
2010-01-11 18:15:42 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s/%s " , truepath , ent - > d_name ) ;
2004-09-07 18:10:08 +00:00
2010-01-11 18:15:42 +00:00
if ( stat ( file , & st ) = = 0 )
2004-09-07 18:10:08 +00:00
{
2010-01-11 18:15:42 +00:00
Q_snprintfz ( file , sizeof ( file ) , " %s%s%s " , apath , ent - > d_name , S_ISDIR ( st . st_mode ) ? " / " : " " ) ;
2004-09-07 18:10:08 +00:00
2015-02-02 08:01:53 +00:00
if ( ! func ( file , st . st_size , st . st_mtime , parm , spath ) )
2010-01-11 18:15:42 +00:00
{
closedir ( dir ) ;
return false ;
}
2004-09-07 18:10:08 +00:00
}
2010-01-11 18:15:42 +00:00
else
printf ( " Stat failed for \" %s \" \n " , file ) ;
2004-09-07 18:10:08 +00:00
}
2010-01-11 18:15:42 +00:00
}
2004-09-07 18:10:08 +00:00
} while ( 1 ) ;
closedir ( dir ) ;
return true ;
}
2009-03-07 05:05:54 +00:00
void Sys_CloseLibrary ( dllhandle_t * lib )
{
dlclose ( ( void * ) lib ) ;
}
2009-11-04 21:16:50 +00:00
dllhandle_t * Sys_LoadLibrary ( const char * name , dllfunction_t * funcs )
2009-03-07 05:05:54 +00:00
{
int i ;
2015-01-07 13:48:24 +00:00
dllhandle_t * lib ;
2009-03-07 05:05:54 +00:00
lib = dlopen ( name , RTLD_LAZY ) ;
if ( ! lib )
return NULL ;
2011-05-30 21:48:32 +00:00
if ( funcs )
2009-03-07 05:05:54 +00:00
{
2011-05-30 21:48:32 +00:00
for ( i = 0 ; funcs [ i ] . name ; i + + )
{
* funcs [ i ] . funcptr = dlsym ( lib , funcs [ i ] . name ) ;
if ( ! * funcs [ i ] . funcptr )
break ;
}
if ( funcs [ i ] . name )
{
Sys_CloseLibrary ( ( dllhandle_t * ) lib ) ;
lib = NULL ;
}
2009-03-07 05:05:54 +00:00
}
return ( dllhandle_t * ) lib ;
}
2011-05-30 21:48:32 +00:00
void * Sys_GetAddressForName ( dllhandle_t * module , const char * exportname )
{
if ( ! module )
return NULL ;
return dlsym ( module , exportname ) ;
}
2009-03-07 05:05:54 +00:00
2004-09-07 18:10:08 +00:00
void Sys_ServerActivity ( void )
{
}
2007-12-30 00:09:34 +00:00
# ifdef MULTITHREAD
/* Thread creation calls */
typedef void * ( * pfunction_t ) ( void * ) ;
2012-11-29 13:37:48 +00:00
void * Sys_CreateThread ( char * name , int ( * func ) ( void * ) , void * args , int priority , int stacksize )
2007-12-30 00:09:34 +00:00
{
2007-12-30 20:05:49 +00:00
pthread_t * thread ;
2007-12-30 00:09:34 +00:00
pthread_attr_t attr ;
2011-05-15 13:23:13 +00:00
2007-12-30 20:05:49 +00:00
thread = ( pthread_t * ) malloc ( sizeof ( pthread_t ) ) ;
if ( ! thread )
return NULL ;
2011-05-15 13:23:13 +00:00
2007-12-30 00:09:34 +00:00
pthread_attr_init ( & attr ) ;
2007-12-30 20:05:49 +00:00
pthread_attr_setdetachstate ( & attr , PTHREAD_CREATE_JOINABLE ) ;
2007-12-30 00:09:34 +00:00
if ( stacksize < PTHREAD_STACK_MIN )
stacksize = PTHREAD_STACK_MIN ;
pthread_attr_setstacksize ( & attr , stacksize ) ;
2007-12-30 20:05:49 +00:00
if ( pthread_create ( thread , & attr , ( pfunction_t ) func , args ) )
{
free ( thread ) ;
thread = NULL ;
}
pthread_attr_destroy ( & attr ) ;
return ( void * ) thread ;
}
2007-12-30 00:09:34 +00:00
2007-12-30 20:05:49 +00:00
void Sys_WaitOnThread ( void * thread )
{
2011-05-15 13:23:13 +00:00
pthread_join ( ( pthread_t * ) thread , NULL ) ;
2007-12-30 20:05:49 +00:00
free ( thread ) ;
2007-12-30 00:09:34 +00:00
}
/* Mutex calls */
2008-06-01 05:42:23 +00:00
void * Sys_CreateMutex ( void )
2007-12-30 00:09:34 +00:00
{
pthread_mutex_t * mutex = ( pthread_mutex_t * ) malloc ( sizeof ( pthread_mutex_t ) ) ;
2011-05-15 13:23:13 +00:00
2007-12-30 00:09:34 +00:00
if ( mutex & & ! pthread_mutex_init ( mutex , NULL ) )
return mutex ;
return NULL ;
}
qboolean Sys_TryLockMutex ( void * mutex )
{
return ! pthread_mutex_trylock ( mutex ) ;
}
qboolean Sys_LockMutex ( void * mutex )
{
return ! pthread_mutex_lock ( mutex ) ;
}
qboolean Sys_UnlockMutex ( void * mutex )
{
return ! pthread_mutex_unlock ( mutex ) ;
}
void Sys_DestroyMutex ( void * mutex )
{
pthread_mutex_destroy ( mutex ) ;
free ( mutex ) ;
}
2008-06-01 05:42:23 +00:00
/* Conditional wait calls */
typedef struct condvar_s
{
2014-10-05 20:04:11 +00:00
//FIXME: these should not be pointers.
2008-06-01 05:42:23 +00:00
pthread_mutex_t * mutex ;
pthread_cond_t * cond ;
} condvar_t ;
void * Sys_CreateConditional ( void )
{
condvar_t * condv ;
pthread_mutex_t * mutex ;
pthread_cond_t * cond ;
2011-05-15 13:23:13 +00:00
2008-06-01 05:42:23 +00:00
condv = ( condvar_t * ) malloc ( sizeof ( condvar_t ) ) ;
if ( ! condv )
return NULL ;
2011-05-15 13:23:13 +00:00
2008-06-01 05:42:23 +00:00
mutex = ( pthread_mutex_t * ) malloc ( sizeof ( pthread_mutex_t ) ) ;
if ( ! mutex )
return NULL ;
2011-05-15 13:23:13 +00:00
2008-06-01 05:42:23 +00:00
cond = ( pthread_cond_t * ) malloc ( sizeof ( pthread_cond_t ) ) ;
if ( ! cond )
return NULL ;
2011-05-15 13:23:13 +00:00
2008-06-01 05:42:23 +00:00
if ( ! pthread_mutex_init ( mutex , NULL ) )
{
if ( ! pthread_cond_init ( cond , NULL ) )
{
condv - > cond = cond ;
condv - > mutex = mutex ;
2011-05-15 13:23:13 +00:00
2008-06-01 05:42:23 +00:00
return ( void * ) condv ;
}
else
pthread_mutex_destroy ( mutex ) ;
}
2011-05-15 13:23:13 +00:00
2008-06-01 05:42:23 +00:00
free ( cond ) ;
free ( mutex ) ;
free ( condv ) ;
2011-05-15 13:23:13 +00:00
return NULL ;
2008-06-01 05:42:23 +00:00
}
qboolean Sys_LockConditional ( void * condv )
{
return ! pthread_mutex_lock ( ( ( condvar_t * ) condv ) - > mutex ) ;
}
qboolean Sys_UnlockConditional ( void * condv )
{
return ! pthread_mutex_unlock ( ( ( condvar_t * ) condv ) - > mutex ) ;
}
qboolean Sys_ConditionWait ( void * condv )
{
return ! pthread_cond_wait ( ( ( condvar_t * ) condv ) - > cond , ( ( condvar_t * ) condv ) - > mutex ) ;
}
qboolean Sys_ConditionSignal ( void * condv )
{
return ! pthread_cond_signal ( ( ( condvar_t * ) condv ) - > cond ) ;
}
qboolean Sys_ConditionBroadcast ( void * condv )
{
return ! pthread_cond_broadcast ( ( ( condvar_t * ) condv ) - > cond ) ;
}
void Sys_DestroyConditional ( void * condv )
{
condvar_t * cv = ( condvar_t * ) condv ;
2011-05-15 13:23:13 +00:00
2008-06-01 05:42:23 +00:00
pthread_cond_destroy ( cv - > cond ) ;
pthread_mutex_destroy ( cv - > mutex ) ;
free ( cv - > cond ) ;
free ( cv - > mutex ) ;
free ( cv ) ;
}
2011-07-06 01:01:13 +00:00
# endif
2011-07-03 16:24:53 +00:00
2011-07-06 01:01:13 +00:00
void Sys_Sleep ( double seconds )
2011-07-03 16:24:53 +00:00
{
2011-07-06 01:01:13 +00:00
struct timespec ts ;
2007-12-30 00:09:34 +00:00
2011-07-06 01:01:13 +00:00
ts . tv_sec = ( time_t ) seconds ;
seconds - = ts . tv_sec ;
ts . tv_nsec = seconds * 1000000000.0 ;
nanosleep ( & ts , NULL ) ;
}
2011-07-31 11:18:49 +00:00
qboolean Sys_RandomBytes ( qbyte * string , int len )
{
qboolean res ;
int fd = open ( " /dev/urandom " , 0 ) ;
res = ( read ( fd , string , len ) = = len ) ;
close ( fd ) ;
return res ;
}