diff options
| author | Tim Angus <tim@ngus.net> | 2007-09-05 22:05:32 +0000 | 
|---|---|---|
| committer | Tim Angus <tim@ngus.net> | 2007-09-05 22:05:32 +0000 | 
| commit | c99975c73ae2941751d86d3b8466454c5ad122c0 (patch) | |
| tree | b5bb65655fbdbc22201426046092939bcf696abe /src/sys | |
| parent | 27ad2c0e19891f7f2454c9eedf76878dc1942ba6 (diff) | |
* Merge of ioq3-r1163
  + SDL everywhere
  + New R_LoadImage
  + net_ip.c
  + Window icon
  + GUI based dedicated server support
  + Compile time linked OpenGL
* Remove ui_menuFiles cvar
Diffstat (limited to 'src/sys')
| -rw-r--r-- | src/sys/sys_loadlib.h | 36 | ||||
| -rw-r--r-- | src/sys/sys_local.h | 40 | ||||
| -rw-r--r-- | src/sys/sys_main.c | 646 | ||||
| -rw-r--r-- | src/sys/sys_unix.c | 450 | ||||
| -rw-r--r-- | src/sys/sys_win32.c | 510 | ||||
| -rw-r--r-- | src/sys/tty_console.c | 440 | ||||
| -rw-r--r-- | src/sys/win_resource.h | 44 | ||||
| -rw-r--r-- | src/sys/win_resource.rc | 75 | 
8 files changed, 2241 insertions, 0 deletions
diff --git a/src/sys/sys_loadlib.h b/src/sys/sys_loadlib.h new file mode 100644 index 00000000..29b21c7d --- /dev/null +++ b/src/sys/sys_loadlib.h @@ -0,0 +1,36 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +=========================================================================== +*/ + +#ifdef DEDICATED +#	include <dlfcn.h> +#	define Sys_LoadLibrary(f) dlopen(f,RTLD_NOW) +#	define Sys_UnloadLibrary(h) dlclose(h) +#	define Sys_LoadFunction(h,fn) dlsym(h,fn) +#	define Sys_LibraryError() dlerror() +#else +#	include "SDL.h" +#	include "SDL_loadso.h" +#	define Sys_LoadLibrary(f) SDL_LoadObject(f) +#	define Sys_UnloadLibrary(h) SDL_UnloadObject(h) +#	define Sys_LoadFunction(h,fn) SDL_LoadFunction(h,fn) +#	define Sys_LibraryError() SDL_GetError() +#endif diff --git a/src/sys/sys_local.h b/src/sys/sys_local.h new file mode 100644 index 00000000..2ccac5cf --- /dev/null +++ b/src/sys/sys_local.h @@ -0,0 +1,40 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +=========================================================================== +*/ + +#include "../qcommon/q_shared.h" +#include "../qcommon/qcommon.h" + +// Input subsystem +void IN_Init (void); +void IN_Frame (void); +void IN_Shutdown (void); + +// TTY console +void TTY_Hide( void ); +void TTY_Show( void ); +void TTY_Shutdown( void ); +void TTY_Init( void ); +char *TTY_ConsoleInput(void); + +#ifdef MACOS_X +char *Sys_StripAppBundle( char *pwd ); +#endif diff --git a/src/sys/sys_main.c b/src/sys/sys_main.c new file mode 100644 index 00000000..df743733 --- /dev/null +++ b/src/sys/sys_main.c @@ -0,0 +1,646 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +=========================================================================== +*/ +#include <unistd.h> +#include <signal.h> +#include <stdlib.h> +#include <limits.h> +#include <sys/time.h> +#include <sys/types.h> +#include <unistd.h> +#include <stdarg.h> +#include <stdio.h> +#include <sys/stat.h> +#include <string.h> +#include <ctype.h> +#include <errno.h> + +#ifndef DEDICATED +#include "SDL.h" +#endif + +#include "sys_local.h" +#include "sys_loadlib.h" + +#include "../qcommon/q_shared.h" +#include "../qcommon/qcommon.h" + +static char binaryPath[ MAX_OSPATH ] = { 0 }; +static char installPath[ MAX_OSPATH ] = { 0 }; + +/* +================= +Sys_SetBinaryPath +================= +*/ +void Sys_SetBinaryPath(const char *path) +{ +	Q_strncpyz(binaryPath, path, sizeof(binaryPath)); +} + +/* +================= +Sys_BinaryPath +================= +*/ +char *Sys_BinaryPath(void) +{ +	return binaryPath; +} + +/* +================= +Sys_SetDefaultInstallPath +================= +*/ +void Sys_SetDefaultInstallPath(const char *path) +{ +	Q_strncpyz(installPath, path, sizeof(installPath)); +} + +/* +================= +Sys_DefaultInstallPath +================= +*/ +char *Sys_DefaultInstallPath(void) +{ +	if (*installPath) +		return installPath; +	else +		return Sys_Cwd(); +} + +/* +================= +Sys_In_Restart_f + +Restart the input subsystem +================= +*/ +void Sys_In_Restart_f( void ) +{ +	IN_Shutdown(); +	IN_Init(); +} + +/* +================= +Sys_ConsoleInputInit + +Start the console input subsystem +================= +*/ +void Sys_ConsoleInputInit( void ) +{ +#ifdef DEDICATED +	TTY_Init( ); +#endif +} + +/* +================= +Sys_ConsoleInputShutdown + +Shutdown the console input subsystem +================= +*/ +void Sys_ConsoleInputShutdown( void ) +{ +#ifdef DEDICATED +	TTY_Shutdown( ); +#endif +} + +/* +================= +Sys_ConsoleInput + +Handle new console input +================= +*/ +char *Sys_ConsoleInput(void) +{ +#ifdef DEDICATED +	return TTY_ConsoleInput( ); +#endif + +	return NULL; +} + +/* +================= +Sys_Exit + +Single exit point (regular exit or in case of error) +================= +*/ +void Sys_Exit( int ex ) +{ +	Sys_ConsoleInputShutdown(); + +#ifndef DEDICATED +	SDL_Quit( ); +#endif + +#ifdef NDEBUG +	// _exit is called instead of exit since there are rumours of +	// GL libraries installing atexit calls that we don't want to call +	// FIXME: get some testing done with plain exit +	_exit(ex); +#else +	// Cause a backtrace on error exits +	assert( ex == 0 ); +	exit(ex); +#endif +} + +/* +================= +Sys_Quit +================= +*/ +void Sys_Quit (void) +{ +	CL_Shutdown (); +	Sys_Exit(0); +} + +/* +================= +Sys_GetProcessorFeatures +================= +*/ +cpuFeatures_t Sys_GetProcessorFeatures( void ) +{ +	cpuFeatures_t features = 0; + +#ifndef DEDICATED +	if( SDL_HasRDTSC( ) )    features |= CF_RDTSC; +	if( SDL_HasMMX( ) )      features |= CF_MMX; +	if( SDL_HasMMXExt( ) )   features |= CF_MMX_EXT; +	if( SDL_Has3DNow( ) )    features |= CF_3DNOW; +	if( SDL_Has3DNowExt( ) ) features |= CF_3DNOW_EXT; +	if( SDL_HasSSE( ) )      features |= CF_SSE; +	if( SDL_HasSSE2( ) )     features |= CF_SSE2; +	if( SDL_HasAltiVec( ) )  features |= CF_ALTIVEC; +#endif + +	return features; +} + +/* +================= +Sys_Init +================= +*/ +void Sys_Init(void) +{ +	Cmd_AddCommand( "in_restart", Sys_In_Restart_f ); +	Cvar_Set( "arch", OS_STRING " " ARCH_STRING ); +	Cvar_Set( "username", Sys_GetCurrentUser( ) ); +} + +static struct Q3ToAnsiColorTable_s +{ +	char Q3color; +	char *ANSIcolor; +} TTY_colorTable[ ] = +{ +	{ COLOR_BLACK,    "30" }, +	{ COLOR_RED,      "31" }, +	{ COLOR_GREEN,    "32" }, +	{ COLOR_YELLOW,   "33" }, +	{ COLOR_BLUE,     "34" }, +	{ COLOR_CYAN,     "36" }, +	{ COLOR_MAGENTA,  "35" }, +	{ COLOR_WHITE,    "0" } +}; + +static int TTY_colorTableSize = +	sizeof( TTY_colorTable ) / sizeof( TTY_colorTable[ 0 ] ); + +/* +================= +Sys_ANSIColorify + +Transform Q3 colour codes to ANSI escape sequences +================= +*/ +static void Sys_ANSIColorify( const char *msg, char *buffer, int bufferSize ) +{ +	int   msgLength, pos; +	int   i, j; +	char  *escapeCode; +	char  tempBuffer[ 7 ]; + +	if( !msg || !buffer ) +		return; + +	msgLength = strlen( msg ); +	pos = 0; +	i = 0; +	buffer[ 0 ] = '\0'; + +	while( i < msgLength ) +	{ +		if( msg[ i ] == '\n' ) +		{ +			Com_sprintf( tempBuffer, 7, "%c[0m\n", 0x1B ); +			strncat( buffer, tempBuffer, bufferSize ); +			i++; +		} +		else if( msg[ i ] == Q_COLOR_ESCAPE ) +		{ +			i++; + +			if( i < msgLength ) +			{ +				escapeCode = NULL; +				for( j = 0; j < TTY_colorTableSize; j++ ) +				{ +					if( msg[ i ] == TTY_colorTable[ j ].Q3color ) +					{ +						escapeCode = TTY_colorTable[ j ].ANSIcolor; +						break; +					} +				} + +				if( escapeCode ) +				{ +					Com_sprintf( tempBuffer, 7, "%c[%sm", 0x1B, escapeCode ); +					strncat( buffer, tempBuffer, bufferSize ); +				} + +				i++; +			} +		} +		else +		{ +			Com_sprintf( tempBuffer, 7, "%c", msg[ i++ ] ); +			strncat( buffer, tempBuffer, bufferSize ); +		} +	} +} + +/* +================= +Sys_Print +================= +*/ +void Sys_Print( const char *msg ) +{ +#ifdef DEDICATED +	TTY_Hide(); +#endif + +	if( com_ansiColor && com_ansiColor->integer ) +	{ +		char ansiColorString[ MAXPRINTMSG ]; +		Sys_ANSIColorify( msg, ansiColorString, MAXPRINTMSG ); +		fputs( ansiColorString, stderr ); +	} +	else +		fputs(msg, stderr); + +#ifdef DEDICATED +	TTY_Show(); +#endif +} + +/* +================= +Sys_Error +================= +*/ +void Sys_Error( const char *error, ... ) +{ +	va_list argptr; +	char    string[1024]; + +#ifdef DEDICATED +	TTY_Hide(); +#endif + +	CL_Shutdown (); + +	va_start (argptr,error); +	Q_vsnprintf (string, sizeof(string), error, argptr); +	va_end (argptr); +	fprintf(stderr, "Sys_Error: %s\n", string); + +	Sys_Exit( 1 ); +} + +/* +================= +Sys_Warn +================= +*/ +void Sys_Warn( char *warning, ... ) +{ +	va_list argptr; +	char    string[1024]; + +	va_start (argptr,warning); +	Q_vsnprintf (string, sizeof(string), warning, argptr); +	va_end (argptr); + +#ifdef DEDICATED +	TTY_Hide(); +#endif + +	fprintf(stderr, "Warning: %s", string); + +#ifdef DEDICATED +	TTY_Show(); +#endif +} + +/* +============ +Sys_FileTime + +returns -1 if not present +============ +*/ +int Sys_FileTime( char *path ) +{ +	struct stat buf; + +	if (stat (path,&buf) == -1) +		return -1; + +	return buf.st_mtime; +} + +/* +================= +Sys_UnloadDll +================= +*/ +void Sys_UnloadDll( void *dllHandle ) +{ +	if( !dllHandle ) +	{ +		Com_Printf("Sys_UnloadDll(NULL)\n"); +		return; +	} + +	Sys_UnloadLibrary(dllHandle); +} + +/* +================= +Sys_TryLibraryLoad +================= +*/ +static void* Sys_TryLibraryLoad(const char* base, const char* gamedir, const char* fname, char* fqpath ) +{ +	void* libHandle; +	char* fn; + +	*fqpath = 0; + +	fn = FS_BuildOSPath( base, gamedir, fname ); +	Com_Printf( "Sys_LoadDll(%s)... \n", fn ); + +	libHandle = Sys_LoadLibrary(fn); + +	if(!libHandle) { +		Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", fn, Sys_LibraryError() ); +		return NULL; +	} + +	Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn ); +	Q_strncpyz ( fqpath , fn , MAX_QPATH ) ; + +	return libHandle; +} + +/* +================= +Sys_LoadDll + +Used to load a development dll instead of a virtual machine +#1 look down current path +#2 look in fs_homepath +#3 look in fs_basepath +================= +*/ +void *Sys_LoadDll( const char *name, char *fqpath , +	intptr_t (**entryPoint)(int, ...), +	intptr_t (*systemcalls)(intptr_t, ...) ) +{ +	void  *libHandle; +	void  (*dllEntry)( intptr_t (*syscallptr)(intptr_t, ...) ); +	char  curpath[MAX_OSPATH]; +	char  fname[MAX_OSPATH]; +	char  *basepath; +	char  *homepath; +	char  *pwdpath; +	char  *gamedir; + +	assert( name ); + +	getcwd(curpath, sizeof(curpath)); +	snprintf (fname, sizeof(fname), "%s" ARCH_STRING DLL_EXT, name); + +	// TODO: use fs_searchpaths from files.c +	pwdpath = Sys_Cwd(); +	basepath = Cvar_VariableString( "fs_basepath" ); +	homepath = Cvar_VariableString( "fs_homepath" ); +	gamedir = Cvar_VariableString( "fs_game" ); + +	libHandle = Sys_TryLibraryLoad(pwdpath, gamedir, fname, fqpath); + +	if(!libHandle && homepath) +		libHandle = Sys_TryLibraryLoad(homepath, gamedir, fname, fqpath); + +	if(!libHandle && basepath) +		libHandle = Sys_TryLibraryLoad(basepath, gamedir, fname, fqpath); + +	if(!libHandle) { +		Com_Printf ( "Sys_LoadDll(%s) failed to load library\n", name ); +		return NULL; +	} + +	dllEntry = Sys_LoadFunction( libHandle, "dllEntry" ); +	*entryPoint = Sys_LoadFunction( libHandle, "vmMain" ); + +	if ( !*entryPoint || !dllEntry ) +	{ +		Com_Printf ( "Sys_LoadDll(%s) failed to find vmMain function:\n\"%s\" !\n", name, Sys_LibraryError( ) ); +		Sys_UnloadLibrary(libHandle); + +		return NULL; +	} + +	Com_Printf ( "Sys_LoadDll(%s) found vmMain function at %p\n", name, *entryPoint ); +	dllEntry( systemcalls ); + +	return libHandle; +} + +/* +================= +Sys_Idle +================= +*/ +static void Sys_Idle( void ) +{ +#ifndef DEDICATED +	int appState = SDL_GetAppState( ); +	int sleep = 0; + +	// If we have no input focus at all, sleep a bit +	if( !( appState & ( SDL_APPMOUSEFOCUS | SDL_APPINPUTFOCUS ) ) ) +	{ +		Cvar_SetValue( "com_unfocused", 1 ); +		sleep += 16; +	} +	else +		Cvar_SetValue( "com_unfocused", 0 ); + +	// If we're minimised, sleep a bit more +	if( !( appState & SDL_APPACTIVE ) ) +	{ +		Cvar_SetValue( "com_minimized", 1 ); +		sleep += 32; +	} +	else +		Cvar_SetValue( "com_minimized", 0 ); + +	if( !com_dedicated->integer && sleep ) +		SDL_Delay( sleep ); +#else +	// Dedicated server idles via NET_Sleep +#endif +} + +/* +================= +Sys_ParseArgs +================= +*/ +void Sys_ParseArgs( int argc, char **argv ) +{ +	if( argc == 2 ) +	{ +		if( !strcmp( argv[1], "--version" ) || +				!strcmp( argv[1], "-v" ) ) +		{ +			const char* date = __DATE__; +#ifdef DEDICATED +			fprintf( stdout, Q3_VERSION " dedicated server (%s)\n", date ); +#else +			fprintf( stdout, Q3_VERSION " client (%s)\n", date ); +#endif +			Sys_Exit(0); +		} +	} +} + +#ifndef DEFAULT_BASEDIR +#	ifdef MACOS_X +#		define DEFAULT_BASEDIR Sys_StripAppBundle(Sys_BinaryPath()) +#	else +#		define DEFAULT_BASEDIR Sys_BinaryPath() +#	endif +#endif + +/* +================= +Sys_SigHandler +================= +*/ +static void Sys_SigHandler( int signal ) +{ +	static qboolean signalcaught = qfalse; + +	if( signalcaught ) +	{ +		fprintf( stderr, "DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n", +			signal ); +	} +	else +	{ +		signalcaught = qtrue; +		fprintf( stderr, "Received signal %d, exiting...\n", signal ); +#ifndef DEDICATED +		CL_Shutdown(); +#endif +		SV_Shutdown( "Signal caught" ); +	} + +	Sys_Exit( 0 ); // Exit with 0 to avoid recursive signals +} + +/* +================= +main +================= +*/ +int main( int argc, char **argv ) +{ +	int   i; +	char  commandLine[ MAX_STRING_CHARS ] = { 0 }; + +	Sys_ParseArgs( argc, argv ); +	Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) ); +	Sys_SetDefaultInstallPath( DEFAULT_BASEDIR ); + +	// Concatenate the command line for passing to Com_Init +	for( i = 1; i < argc; i++ ) +	{ +		Q_strcat( commandLine, sizeof( commandLine ), argv[ i ] ); +		Q_strcat( commandLine, sizeof( commandLine ), " " ); +	} + +	Com_Init( commandLine ); +	NET_Init(); + +	Sys_ConsoleInputInit(); + +#ifndef _WIN32 +	// Windows doesn't have these signals +	signal( SIGHUP, Sys_SigHandler ); +	signal( SIGQUIT, Sys_SigHandler ); +	signal( SIGTRAP, Sys_SigHandler ); +	signal( SIGIOT, Sys_SigHandler ); +	signal( SIGBUS, Sys_SigHandler ); +#endif + +	signal( SIGILL, Sys_SigHandler ); +	signal( SIGFPE, Sys_SigHandler ); +	signal( SIGSEGV, Sys_SigHandler ); +	signal( SIGTERM, Sys_SigHandler ); + +	while( 1 ) +	{ +		Sys_Idle( ); +		IN_Frame( ); +		Com_Frame( ); +	} + +	return 0; +} + diff --git a/src/sys/sys_unix.c b/src/sys/sys_unix.c new file mode 100644 index 00000000..8a8240bd --- /dev/null +++ b/src/sys/sys_unix.c @@ -0,0 +1,450 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +=========================================================================== +*/ +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdio.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <pwd.h> +#include <libgen.h> + +#include "../qcommon/q_shared.h" +#include "../qcommon/qcommon.h" + +// Used to determine where to store user-specific files +static char homePath[ MAX_OSPATH ] = { 0 }; + +/* +================== +Sys_DefaultHomePath +================== +*/ +char *Sys_DefaultHomePath(void) +{ +	char *p; + +	if( !*homePath ) +	{ +		if( ( p = getenv( "HOME" ) ) != NULL ) +		{ +			Q_strncpyz( homePath, p, sizeof( homePath ) ); +#ifdef MACOS_X +			Q_strcat( homePath, sizeof( homePath ), "/Library/Application Support/Quake3" ); +#else +			Q_strcat( homePath, sizeof( homePath ), "/.q3a" ); +#endif +			if( mkdir( homePath, 0777 ) ) +			{ +				if( errno != EEXIST ) +				{ +					Sys_Error( "Unable to create directory \"%s\", error is %s(%d)\n", +							homePath, strerror( errno ), errno ); +				} +			} +		} +	} + +	return homePath; +} + +/* +================ +Sys_Milliseconds +================ +*/ +/* base time in seconds, that's our origin +   timeval:tv_sec is an int: +   assuming this wraps every 0x7fffffff - ~68 years since the Epoch (1970) - we're safe till 2038 +   using unsigned long data type to work right with Sys_XTimeToSysTime */ +unsigned long sys_timeBase = 0; +/* current time in ms, using sys_timeBase as origin +   NOTE: sys_timeBase*1000 + curtime -> ms since the Epoch +     0x7fffffff ms - ~24 days +   although timeval:tv_usec is an int, I'm not sure wether it is actually used as an unsigned int +     (which would affect the wrap period) */ +int curtime; +int Sys_Milliseconds (void) +{ +	struct timeval tp; + +	gettimeofday(&tp, NULL); + +	if (!sys_timeBase) +	{ +		sys_timeBase = tp.tv_sec; +		return tp.tv_usec/1000; +	} + +	curtime = (tp.tv_sec - sys_timeBase)*1000 + tp.tv_usec/1000; + +	return curtime; +} + +#if !id386 +/* +================== +fastftol +================== +*/ +long fastftol( float f ) +{ +	return (long)f; +} + +/* +================== +Sys_SnapVector +================== +*/ +void Sys_SnapVector( float *v ) +{ +	v[0] = rint(v[0]); +	v[1] = rint(v[1]); +	v[2] = rint(v[2]); +} +#endif + + +/* +================== +Sys_RandomBytes +================== +*/ +qboolean Sys_RandomBytes( byte *string, int len ) +{ +	FILE *fp; + +	fp = fopen( "/dev/urandom", "r" ); +	if( !fp ) +		return qfalse; + +	if( !fread( string, sizeof( byte ), len, fp ) ) +	{ +		fclose( fp ); +		return qfalse; +	} + +	fclose( fp ); +	return qtrue; +} + +/* +================== +Sys_GetCurrentUser +================== +*/ +char *Sys_GetCurrentUser( void ) +{ +	struct passwd *p; + +	if ( (p = getpwuid( getuid() )) == NULL ) { +		return "player"; +	} +	return p->pw_name; +} + +/* +================== +Sys_GetClipboardData +================== +*/ +char *Sys_GetClipboardData(void) +{ +	return NULL; +} + +#define MEM_THRESHOLD 96*1024*1024 + +/* +================== +Sys_LowPhysicalMemory + +TODO +================== +*/ +qboolean Sys_LowPhysicalMemory( void ) +{ +	return qfalse; +} + +/* +================== +Sys_Basename +================== +*/ +const char *Sys_Basename( char *path ) +{ +	return basename( path ); +} + +/* +================== +Sys_Dirname +================== +*/ +const char *Sys_Dirname( char *path ) +{ +	return dirname( path ); +} + +/* +================== +Sys_Mkdir +================== +*/ +void Sys_Mkdir( const char *path ) +{ +	mkdir( path, 0777 ); +} + +/* +================== +Sys_Cwd +================== +*/ +char *Sys_Cwd( void ) +{ +	static char cwd[MAX_OSPATH]; + +	getcwd( cwd, sizeof( cwd ) - 1 ); +	cwd[MAX_OSPATH-1] = 0; + +	return cwd; +} + +/* +============================================================== + +DIRECTORY SCANNING + +============================================================== +*/ + +#define MAX_FOUND_FILES 0x1000 + +/* +================== +Sys_ListFilteredFiles +================== +*/ +void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles ) +{ +	char          search[MAX_OSPATH], newsubdirs[MAX_OSPATH]; +	char          filename[MAX_OSPATH]; +	DIR           *fdir; +	struct dirent *d; +	struct stat   st; + +	if ( *numfiles >= MAX_FOUND_FILES - 1 ) { +		return; +	} + +	if (strlen(subdirs)) { +		Com_sprintf( search, sizeof(search), "%s/%s", basedir, subdirs ); +	} +	else { +		Com_sprintf( search, sizeof(search), "%s", basedir ); +	} + +	if ((fdir = opendir(search)) == NULL) { +		return; +	} + +	while ((d = readdir(fdir)) != NULL) { +		Com_sprintf(filename, sizeof(filename), "%s/%s", search, d->d_name); +		if (stat(filename, &st) == -1) +			continue; + +		if (st.st_mode & S_IFDIR) { +			if (Q_stricmp(d->d_name, ".") && Q_stricmp(d->d_name, "..")) { +				if (strlen(subdirs)) { +					Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s/%s", subdirs, d->d_name); +				} +				else { +					Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", d->d_name); +				} +				Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles ); +			} +		} +		if ( *numfiles >= MAX_FOUND_FILES - 1 ) { +			break; +		} +		Com_sprintf( filename, sizeof(filename), "%s/%s", subdirs, d->d_name ); +		if (!Com_FilterPath( filter, filename, qfalse )) +			continue; +		list[ *numfiles ] = CopyString( filename ); +		(*numfiles)++; +	} + +	closedir(fdir); +} + +/* +================== +Sys_ListFiles +================== +*/ +char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) +{ +	struct dirent *d; +	DIR           *fdir; +	qboolean      dironly = wantsubs; +	char          search[MAX_OSPATH]; +	int           nfiles; +	char          **listCopy; +	char          *list[MAX_FOUND_FILES]; +	int           i; +	struct stat   st; + +	int           extLen; + +	if (filter) { + +		nfiles = 0; +		Sys_ListFilteredFiles( directory, "", filter, list, &nfiles ); + +		list[ nfiles ] = NULL; +		*numfiles = nfiles; + +		if (!nfiles) +			return NULL; + +		listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) ); +		for ( i = 0 ; i < nfiles ; i++ ) { +			listCopy[i] = list[i]; +		} +		listCopy[i] = NULL; + +		return listCopy; +	} + +	if ( !extension) +		extension = ""; + +	if ( extension[0] == '/' && extension[1] == 0 ) { +		extension = ""; +		dironly = qtrue; +	} + +	extLen = strlen( extension ); +	 +	// search +	nfiles = 0; + +	if ((fdir = opendir(directory)) == NULL) { +		*numfiles = 0; +		return NULL; +	} + +	while ((d = readdir(fdir)) != NULL) { +		Com_sprintf(search, sizeof(search), "%s/%s", directory, d->d_name); +		if (stat(search, &st) == -1) +			continue; +		if ((dironly && !(st.st_mode & S_IFDIR)) || +			(!dironly && (st.st_mode & S_IFDIR))) +			continue; + +		if (*extension) { +			if ( strlen( d->d_name ) < strlen( extension ) || +				Q_stricmp( +					d->d_name + strlen( d->d_name ) - strlen( extension ), +					extension ) ) { +				continue; // didn't match +			} +		} + +		if ( nfiles == MAX_FOUND_FILES - 1 ) +			break; +		list[ nfiles ] = CopyString( d->d_name ); +		nfiles++; +	} + +	list[ nfiles ] = NULL; + +	closedir(fdir); + +	// return a copy of the list +	*numfiles = nfiles; + +	if ( !nfiles ) { +		return NULL; +	} + +	listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) ); +	for ( i = 0 ; i < nfiles ; i++ ) { +		listCopy[i] = list[i]; +	} +	listCopy[i] = NULL; + +	return listCopy; +} + +/* +================== +Sys_FreeFileList +================== +*/ +void Sys_FreeFileList( char **list ) +{ +	int i; + +	if ( !list ) { +		return; +	} + +	for ( i = 0 ; list[i] ; i++ ) { +		Z_Free( list[i] ); +	} + +	Z_Free( list ); +} + +#ifdef MACOS_X +/* +================= +Sys_StripAppBundle + +Discovers if passed dir is suffixed with the directory structure of a Mac OS X +.app bundle. If it is, the .app directory structure is stripped off the end and +the result is returned. If not, dir is returned untouched. +================= +*/ +char *Sys_StripAppBundle( char *dir ) +{ +	static char cwd[MAX_OSPATH]; + +	Q_strncpyz(cwd, dir, sizeof(cwd)); +	if(strcmp(Sys_Basename(cwd), "MacOS")) +		return dir; +	Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd)); +	if(strcmp(Sys_Basename(cwd), "Contents")) +		return dir; +	Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd)); +	if(!strstr(Sys_Basename(cwd), ".app")) +		return dir; +	Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd)); +	return cwd; +} +#endif // MACOS_X diff --git a/src/sys/sys_win32.c b/src/sys/sys_win32.c new file mode 100644 index 00000000..1ab3130b --- /dev/null +++ b/src/sys/sys_win32.c @@ -0,0 +1,510 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +=========================================================================== +*/ + +#include "../qcommon/q_shared.h" +#include "../qcommon/qcommon.h" +#include "sys_local.h" + +#include <windows.h> +#include <lmerr.h> +#include <lmcons.h> +#include <lmwksta.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <direct.h> +#include <io.h> +#include <conio.h> +#include <wincrypt.h> +#include <shlobj.h> + +// Used to determine where to store user-specific files +static char homePath[ MAX_OSPATH ] = { 0 }; + +/* +================ +Sys_DefaultHomePath +================ +*/ +char *Sys_DefaultHomePath( void ) +{ +	TCHAR szPath[MAX_PATH]; +	FARPROC qSHGetFolderPath; +	HMODULE shfolder = LoadLibrary("shfolder.dll"); +	 +	if( !*homePath ) +	{ +		if(shfolder == NULL) +		{ +			Com_Printf("Unable to load SHFolder.dll\n"); +			return NULL; +		} + +		qSHGetFolderPath = GetProcAddress(shfolder, "SHGetFolderPathA"); +		if(qSHGetFolderPath == NULL) +		{ +			Com_Printf("Unable to find SHGetFolderPath in SHFolder.dll\n"); +			FreeLibrary(shfolder); +			return NULL; +		} + +		if( !SUCCEEDED( qSHGetFolderPath( NULL, CSIDL_APPDATA, +						NULL, 0, szPath ) ) ) +		{ +			Com_Printf("Unable to detect CSIDL_APPDATA\n"); +			FreeLibrary(shfolder); +			return NULL; +		} +		Q_strncpyz( homePath, szPath, sizeof( homePath ) ); +		Q_strcat( homePath, sizeof( homePath ), "\\Quake3" ); +		FreeLibrary(shfolder); +		if( !CreateDirectory( homePath, NULL ) ) +		{ +			if( GetLastError() != ERROR_ALREADY_EXISTS ) +			{ +				Com_Printf("Unable to create directory \"%s\"\n", homePath ); +				return NULL; +			} +		} +	} + +	return homePath; +} + +/* +================ +Sys_Milliseconds +================ +*/ +int sys_timeBase; +int Sys_Milliseconds (void) +{ +	int             sys_curtime; +	static qboolean initialized = qfalse; + +	if (!initialized) { +		sys_timeBase = timeGetTime(); +		initialized = qtrue; +	} +	sys_curtime = timeGetTime() - sys_timeBase; + +	return sys_curtime; +} + +#ifndef __GNUC__ //see snapvectora.s +/* +================ +Sys_SnapVector +================ +*/ +void Sys_SnapVector( float *v ) +{ +	int i; +	float f; + +	f = *v; +	__asm	fld		f; +	__asm	fistp	i; +	*v = i; +	v++; +	f = *v; +	__asm	fld		f; +	__asm	fistp	i; +	*v = i; +	v++; +	f = *v; +	__asm	fld		f; +	__asm	fistp	i; +	*v = i; +} +#endif + +/* +================ +Sys_RandomBytes +================ +*/ +qboolean Sys_RandomBytes( byte *string, int len ) +{ +	HCRYPTPROV  prov; + +	if( !CryptAcquireContext( &prov, NULL, NULL, +		PROV_RSA_FULL, CRYPT_VERIFYCONTEXT ) )  { + +		return qfalse; +	} + +	if( !CryptGenRandom( prov, len, (BYTE *)string ) )  { +		CryptReleaseContext( prov, 0 ); +		return qfalse; +	} +	CryptReleaseContext( prov, 0 ); +	return qtrue; +} + +/* +================ +Sys_GetCurrentUser +================ +*/ +char *Sys_GetCurrentUser( void ) +{ +	static char s_userName[1024]; +	unsigned long size = sizeof( s_userName ); + +	if( !GetUserName( s_userName, &size ) ) +		strcpy( s_userName, "player" ); + +	if( !s_userName[0] ) +	{ +		strcpy( s_userName, "player" ); +	} + +	return s_userName; +} + +/* +================ +Sys_GetClipboardData +================ +*/ +char *Sys_GetClipboardData( void ) +{ +	char *data = NULL; +	char *cliptext; + +	if ( OpenClipboard( NULL ) != 0 ) { +		HANDLE hClipboardData; + +		if ( ( hClipboardData = GetClipboardData( CF_TEXT ) ) != 0 ) { +			if ( ( cliptext = GlobalLock( hClipboardData ) ) != 0 ) { +				data = Z_Malloc( GlobalSize( hClipboardData ) + 1 ); +				Q_strncpyz( data, cliptext, GlobalSize( hClipboardData ) ); +				GlobalUnlock( hClipboardData ); +				 +				strtok( data, "\n\r\b" ); +			} +		} +		CloseClipboard(); +	} +	return data; +} + +#define MEM_THRESHOLD 96*1024*1024 + +/* +================== +Sys_LowPhysicalMemory +================== +*/ +qboolean Sys_LowPhysicalMemory( void ) +{ +	MEMORYSTATUS stat; +	GlobalMemoryStatus (&stat); +	return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse; +} + +/* +============== +Sys_Basename +============== +*/ +const char *Sys_Basename( char *path ) +{ +	static char base[ MAX_OSPATH ] = { 0 }; +	int length; + +	length = strlen( path ) - 1; + +	// Skip trailing slashes +	while( length > 0 && path[ length ] == '\\' ) +		length--; + +	while( length > 0 && path[ length - 1 ] != '\\' ) +		length--; + +	Q_strncpyz( base, &path[ length ], sizeof( base ) ); + +	length = strlen( base ) - 1; + +	// Strip trailing slashes +	while( length > 0 && base[ length ] == '\\' ) +    base[ length-- ] = '\0'; + +	return base; +} + +/* +============== +Sys_Dirname +============== +*/ +const char *Sys_Dirname( char *path ) +{ +	static char dir[ MAX_OSPATH ] = { 0 }; +	int length; + +	Q_strncpyz( dir, path, sizeof( dir ) ); +	length = strlen( dir ) - 1; + +	while( length > 0 && dir[ length ] != '\\' ) +		length--; + +	dir[ length ] = '\0'; + +	return dir; +} + +/* +============== +Sys_Mkdir +============== +*/ +void Sys_Mkdir( const char *path ) +{ +	_mkdir (path); +} + +/* +============== +Sys_Cwd +============== +*/ +char *Sys_Cwd( void ) { +	static char cwd[MAX_OSPATH]; + +	_getcwd( cwd, sizeof( cwd ) - 1 ); +	cwd[MAX_OSPATH-1] = 0; + +	return cwd; +} + +/* +============================================================== + +DIRECTORY SCANNING + +============================================================== +*/ + +#define MAX_FOUND_FILES 0x1000 + +/* +============== +Sys_ListFilteredFiles +============== +*/ +void Sys_ListFilteredFiles( const char *basedir, char *subdirs, char *filter, char **list, int *numfiles ) +{ +	char		search[MAX_OSPATH], newsubdirs[MAX_OSPATH]; +	char		filename[MAX_OSPATH]; +	int			findhandle; +	struct _finddata_t findinfo; + +	if ( *numfiles >= MAX_FOUND_FILES - 1 ) { +		return; +	} + +	if (strlen(subdirs)) { +		Com_sprintf( search, sizeof(search), "%s\\%s\\*", basedir, subdirs ); +	} +	else { +		Com_sprintf( search, sizeof(search), "%s\\*", basedir ); +	} + +	findhandle = _findfirst (search, &findinfo); +	if (findhandle == -1) { +		return; +	} + +	do { +		if (findinfo.attrib & _A_SUBDIR) { +			if (Q_stricmp(findinfo.name, ".") && Q_stricmp(findinfo.name, "..")) { +				if (strlen(subdirs)) { +					Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s\\%s", subdirs, findinfo.name); +				} +				else { +					Com_sprintf( newsubdirs, sizeof(newsubdirs), "%s", findinfo.name); +				} +				Sys_ListFilteredFiles( basedir, newsubdirs, filter, list, numfiles ); +			} +		} +		if ( *numfiles >= MAX_FOUND_FILES - 1 ) { +			break; +		} +		Com_sprintf( filename, sizeof(filename), "%s\\%s", subdirs, findinfo.name ); +		if (!Com_FilterPath( filter, filename, qfalse )) +			continue; +		list[ *numfiles ] = CopyString( filename ); +		(*numfiles)++; +	} while ( _findnext (findhandle, &findinfo) != -1 ); + +	_findclose (findhandle); +} + +/* +============== +strgtr +============== +*/ +static qboolean strgtr(const char *s0, const char *s1) +{ +	int l0, l1, i; + +	l0 = strlen(s0); +	l1 = strlen(s1); + +	if (l1<l0) { +		l0 = l1; +	} + +	for(i=0;i<l0;i++) { +		if (s1[i] > s0[i]) { +			return qtrue; +		} +		if (s1[i] < s0[i]) { +			return qfalse; +		} +	} +	return qfalse; +} + +/* +============== +Sys_ListFiles +============== +*/ +char **Sys_ListFiles( const char *directory, const char *extension, char *filter, int *numfiles, qboolean wantsubs ) +{ +	char		search[MAX_OSPATH]; +	int			nfiles; +	char		**listCopy; +	char		*list[MAX_FOUND_FILES]; +	struct _finddata_t findinfo; +	int			findhandle; +	int			flag; +	int			i; + +	if (filter) { + +		nfiles = 0; +		Sys_ListFilteredFiles( directory, "", filter, list, &nfiles ); + +		list[ nfiles ] = 0; +		*numfiles = nfiles; + +		if (!nfiles) +			return NULL; + +		listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) ); +		for ( i = 0 ; i < nfiles ; i++ ) { +			listCopy[i] = list[i]; +		} +		listCopy[i] = NULL; + +		return listCopy; +	} + +	if ( !extension) { +		extension = ""; +	} + +	// passing a slash as extension will find directories +	if ( extension[0] == '/' && extension[1] == 0 ) { +		extension = ""; +		flag = 0; +	} else { +		flag = _A_SUBDIR; +	} + +	Com_sprintf( search, sizeof(search), "%s\\*%s", directory, extension ); + +	// search +	nfiles = 0; + +	findhandle = _findfirst (search, &findinfo); +	if (findhandle == -1) { +		*numfiles = 0; +		return NULL; +	} + +	do { +		if ( (!wantsubs && flag ^ ( findinfo.attrib & _A_SUBDIR )) || (wantsubs && findinfo.attrib & _A_SUBDIR) ) { +			if ( nfiles == MAX_FOUND_FILES - 1 ) { +				break; +			} +			list[ nfiles ] = CopyString( findinfo.name ); +			nfiles++; +		} +	} while ( _findnext (findhandle, &findinfo) != -1 ); + +	list[ nfiles ] = 0; + +	_findclose (findhandle); + +	// return a copy of the list +	*numfiles = nfiles; + +	if ( !nfiles ) { +		return NULL; +	} + +	listCopy = Z_Malloc( ( nfiles + 1 ) * sizeof( *listCopy ) ); +	for ( i = 0 ; i < nfiles ; i++ ) { +		listCopy[i] = list[i]; +	} +	listCopy[i] = NULL; + +	do { +		flag = 0; +		for(i=1; i<nfiles; i++) { +			if (strgtr(listCopy[i-1], listCopy[i])) { +				char *temp = listCopy[i]; +				listCopy[i] = listCopy[i-1]; +				listCopy[i-1] = temp; +				flag = 1; +			} +		} +	} while(flag); + +	return listCopy; +} + +/* +============== +Sys_FreeFileList +============== +*/ +void Sys_FreeFileList( char **list ) +{ +	int i; + +	if ( !list ) { +		return; +	} + +	for ( i = 0 ; list[i] ; i++ ) { +		Z_Free( list[i] ); +	} + +	Z_Free( list ); +} diff --git a/src/sys/tty_console.c b/src/sys/tty_console.c new file mode 100644 index 00000000..34a09d10 --- /dev/null +++ b/src/sys/tty_console.c @@ -0,0 +1,440 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +=========================================================================== +*/ + +#include "../qcommon/q_shared.h" +#include "../qcommon/qcommon.h" + +#include <unistd.h> +#include <signal.h> +#include <termios.h> +#include <fcntl.h> + +/* +============================================================= +tty console routines + +NOTE: if the user is editing a line when something gets printed to the early +console then it won't look good so we provide TTY_Hide and TTY_Show to be +called before and after a stdout or stderr output +============================================================= +*/ + +// general flag to tell about tty console mode +static qboolean ttycon_on = qfalse; +static int ttycon_hide = 0; + +// some key codes that the terminal may be using, initialised on start up +static int TTY_erase; +static int TTY_eof; + +static struct termios TTY_tc; + +static field_t TTY_con; + +// This is somewhat of aduplicate of the graphical console history +// but it's safer more modular to have our own here +#define TTY_HISTORY 32 +static field_t ttyEditLines[ TTY_HISTORY ]; +static int hist_current = -1, hist_count = 0; + +/* +================== +TTY_FlushIn + +Flush stdin, I suspect some terminals are sending a LOT of shit +FIXME relevant? +================== +*/ +static void TTY_FlushIn( void ) +{ +	char key; +	while (read(0, &key, 1)!=-1); +} + +/* +================== +TTY_Back + +Output a backspace + +NOTE: it seems on some terminals just sending '\b' is not enough so instead we +send "\b \b" +(FIXME there may be a way to find out if '\b' alone would work though) +================== +*/ +static void TTY_Back( void ) +{ +	char key; +	key = '\b'; +	write(1, &key, 1); +	key = ' '; +	write(1, &key, 1); +	key = '\b'; +	write(1, &key, 1); +} + +/* +================== +TTY_Hide + +Clear the display of the line currently edited +bring cursor back to beginning of line +================== +*/ +void TTY_Hide( void ) +{ +	if( ttycon_on ) +	{ +		int i; +		if (ttycon_hide) +		{ +			ttycon_hide++; +			return; +		} +		if (TTY_con.cursor>0) +		{ +			for (i=0; i<TTY_con.cursor; i++) +			{ +				TTY_Back(); +			} +		} +		TTY_Back(); // Delete "]" +		ttycon_hide++; +	} +} + +/* +================== +TTY_Show + +Show the current line +FIXME need to position the cursor if needed? +================== +*/ +void TTY_Show( void ) +{ +	if( ttycon_on ) +	{ +		int i; + +		assert(ttycon_hide>0); +		ttycon_hide--; +		if (ttycon_hide == 0) +		{ +			write( 1, "]", 1 ); +			if (TTY_con.cursor) +			{ +				for (i=0; i<TTY_con.cursor; i++) +				{ +					write(1, TTY_con.buffer+i, 1); +				} +			} +		} +	} +} + +/* +================== +TTY_Shutdown + +Never exit without calling this, or your terminal will be left in a pretty bad state +================== +*/ +void TTY_Shutdown( void ) +{ +	if (ttycon_on) +	{ +		TTY_Back(); // Delete "]" +		tcsetattr (0, TCSADRAIN, &TTY_tc); + +		// Restore blocking to stdin reads +		fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) & ~O_NDELAY ); +	} +} + +/* +================== +Hist_Add +================== +*/ +void Hist_Add(field_t *field) +{ +	int i; +	assert(hist_count <= TTY_HISTORY); +	assert(hist_count >= 0); +	assert(hist_current >= -1); +	assert(hist_current <= hist_count); +	// make some room +	for (i=TTY_HISTORY-1; i>0; i--) +	{ +		ttyEditLines[i] = ttyEditLines[i-1]; +	} +	ttyEditLines[0] = *field; +	if (hist_count<TTY_HISTORY) +	{ +		hist_count++; +	} +	hist_current = -1; // re-init +} + +/* +================== +Hist_Prev +================== +*/ +field_t *Hist_Prev( void ) +{ +	int hist_prev; +	assert(hist_count <= TTY_HISTORY); +	assert(hist_count >= 0); +	assert(hist_current >= -1); +	assert(hist_current <= hist_count); +	hist_prev = hist_current + 1; +	if (hist_prev >= hist_count) +	{ +		return NULL; +	} +	hist_current++; +	return &(ttyEditLines[hist_current]); +} + +/* +================== +Hist_Next +================== +*/ +field_t *Hist_Next( void ) +{ +	assert(hist_count <= TTY_HISTORY); +	assert(hist_count >= 0); +	assert(hist_current >= -1); +	assert(hist_current <= hist_count); +	if (hist_current >= 0) +	{ +		hist_current--; +	} +	if (hist_current == -1) +	{ +		return NULL; +	} +	return &(ttyEditLines[hist_current]); +} + +/* +================== +TTY_Init + +Initialize the console input (tty mode if possible) +================== +*/ +void TTY_Init( void ) +{ +	struct termios tc; + +	// If the process is backgrounded (running non interactively) +	// then SIGTTIN or SIGTOU is emitted, if not caught, turns into a SIGSTP +	signal(SIGTTIN, SIG_IGN); +	signal(SIGTTOU, SIG_IGN); + +	// Make stdin reads non-blocking +	fcntl( 0, F_SETFL, fcntl( 0, F_GETFL, 0 ) | O_NDELAY ); + +	if (isatty(STDIN_FILENO)!=1) +	{ +		Com_Printf( "stdin is not a tty, tty console mode disabled\n"); +		ttycon_on = qfalse; +		return; +	} + +	Field_Clear(&TTY_con); +	tcgetattr (0, &TTY_tc); +	TTY_erase = TTY_tc.c_cc[VERASE]; +	TTY_eof = TTY_tc.c_cc[VEOF]; +	tc = TTY_tc; + +	/* +	ECHO: don't echo input characters +	ICANON: enable canonical mode.  This  enables  the  special +	characters  EOF,  EOL,  EOL2, ERASE, KILL, REPRINT, +	STATUS, and WERASE, and buffers by lines. +	ISIG: when any of the characters  INTR,  QUIT,  SUSP,  or +	DSUSP are received, generate the corresponding sig +	nal +	*/ +	tc.c_lflag &= ~(ECHO | ICANON); + +	/* +	ISTRIP strip off bit 8 +	INPCK enable input parity checking +	*/ +	tc.c_iflag &= ~(ISTRIP | INPCK); +	tc.c_cc[VMIN] = 1; +	tc.c_cc[VTIME] = 0; +	tcsetattr (0, TCSADRAIN, &tc); +	ttycon_on = qtrue; +} + +/* +================== +TTY_ConsoleInput +================== +*/ +char *TTY_ConsoleInput( void ) +{ +	// we use this when sending back commands +	static char text[256]; +	int avail; +	char key; +	field_t *history; + +	if( ttycon_on ) +	{ +		avail = read(0, &key, 1); +		if (avail != -1) +		{ +			// we have something +			// backspace? +			// NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere +			if ((key == TTY_erase) || (key == 127) || (key == 8)) +			{ +				if (TTY_con.cursor > 0) +				{ +					TTY_con.cursor--; +					TTY_con.buffer[TTY_con.cursor] = '\0'; +					TTY_Back(); +				} +				return NULL; +			} +			// check if this is a control char +			if ((key) && (key) < ' ') +			{ +				if (key == '\n') +				{ +					// push it in history +					Hist_Add(&TTY_con); +					strcpy(text, TTY_con.buffer); +					Field_Clear(&TTY_con); +					key = '\n'; +					write(1, &key, 1); +					write( 1, "]", 1 ); +					return text; +				} +				if (key == '\t') +				{ +					TTY_Hide(); +					Field_AutoComplete( &TTY_con ); +					TTY_Show(); +					return NULL; +				} +				avail = read(0, &key, 1); +				if (avail != -1) +				{ +					// VT 100 keys +					if (key == '[' || key == 'O') +					{ +						avail = read(0, &key, 1); +						if (avail != -1) +						{ +							switch (key) +							{ +								case 'A': +									history = Hist_Prev(); +									if (history) +									{ +										TTY_Hide(); +										TTY_con = *history; +										TTY_Show(); +									} +									TTY_FlushIn(); +									return NULL; +									break; +								case 'B': +									history = Hist_Next(); +									TTY_Hide(); +									if (history) +									{ +										TTY_con = *history; +									} else +									{ +										Field_Clear(&TTY_con); +									} +									TTY_Show(); +									TTY_FlushIn(); +									return NULL; +									break; +								case 'C': +									return NULL; +								case 'D': +									return NULL; +							} +						} +					} +				} +				Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase); +				TTY_FlushIn(); +				return NULL; +			} +			// push regular character +			TTY_con.buffer[TTY_con.cursor] = key; +			TTY_con.cursor++; +			// print the current line (this is differential) +			write(1, &key, 1); +		} + +		return NULL; +	} +	else +	{ +		int     len; +		fd_set  fdset; +		struct timeval timeout; +		static qboolean stdin_active; + +		if (!com_dedicated || !com_dedicated->value) +			return NULL; + +		if (!stdin_active) +			return NULL; + +		FD_ZERO(&fdset); +		FD_SET(0, &fdset); // stdin +		timeout.tv_sec = 0; +		timeout.tv_usec = 0; +		if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset)) +		{ +			return NULL; +		} + +		len = read (0, text, sizeof(text)); +		if (len == 0) +		{ // eof! +			stdin_active = qfalse; +			return NULL; +		} + +		if (len < 1) +			return NULL; +		text[len-1] = 0;    // rip off the /n and terminate + +		return text; +	} +} diff --git a/src/sys/win_resource.h b/src/sys/win_resource.h new file mode 100644 index 00000000..93c517ea --- /dev/null +++ b/src/sys/win_resource.h @@ -0,0 +1,44 @@ +/* +=========================================================================== +Copyright (C) 1999-2005 Id Software, Inc. + +This file is part of Quake III Arena source code. + +Quake III Arena source code 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. + +Quake III Arena source code 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 Quake III Arena source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA +=========================================================================== +*/ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by winquake.rc +// +#define IDS_STRING1                     1 +#define IDI_ICON1                       1 +#define IDB_BITMAP1                     1 +#define IDB_BITMAP2                     128 +#define IDC_CURSOR1                     129 +#define IDC_CURSOR2                     130 +#define IDC_CURSOR3                     131 + +// Next default values for new objects +//  +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NO_MFC                     1 +#define _APS_NEXT_RESOURCE_VALUE        132 +#define _APS_NEXT_COMMAND_VALUE         40001 +#define _APS_NEXT_CONTROL_VALUE         1005 +#define _APS_NEXT_SYMED_VALUE           101 +#endif +#endif diff --git a/src/sys/win_resource.rc b/src/sys/win_resource.rc new file mode 100644 index 00000000..4b50adc2 --- /dev/null +++ b/src/sys/win_resource.rc @@ -0,0 +1,75 @@ +//Microsoft Developer Studio generated resource script. +// +#include "win_resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#ifndef __MINGW32__ +#include "winres.h" +#else +#include <winresrc.h> +#endif + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE  +BEGIN +    "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE  +BEGIN +    "#include ""winres.h""\r\n" +    "\0" +END + +3 TEXTINCLUDE DISCARDABLE  +BEGIN +    "\0" +END + +#endif    // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1               ICON    DISCARDABLE     "misc/tremulous.ico" + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE  +BEGIN +    IDS_STRING1             "Tremulous" +END + +#endif    // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + +  | 
