1 /*
2 ===========================================================================
3 Copyright (C) 1999-2005 Id Software, Inc.
4 
5 This file is part of Quake III Arena source code.
6 
7 Quake III Arena source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
11 
12 Quake III Arena source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Quake III Arena source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 ===========================================================================
21 */
22 
23 #include <signal.h>
24 #include <stdlib.h>
25 #include <limits.h>
26 #include <sys/types.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <sys/stat.h>
30 #include <string.h>
31 #include <ctype.h>
32 #include <errno.h>
33 
34 #ifndef DEDICATED
35 #ifdef USE_LOCAL_HEADERS
36 #	include "SDL.h"
37 #	include "SDL_cpuinfo.h"
38 #else
39 #	include <SDL.h>
40 #	include <SDL_cpuinfo.h>
41 #endif
42 #endif
43 
44 #include "sys_local.h"
45 #include "sys_loadlib.h"
46 
47 #include "../qcommon/q_shared.h"
48 #include "../qcommon/qcommon.h"
49 
50 static char binaryPath[ MAX_OSPATH ] = { 0 };
51 static char installPath[ MAX_OSPATH ] = { 0 };
52 static char libPath[ MAX_OSPATH ] = { 0 };
53 
54 /*
55 =================
56 Sys_SetBinaryPath
57 =================
58 */
Sys_SetBinaryPath(const char * path)59 void Sys_SetBinaryPath(const char *path)
60 {
61 	Q_strncpyz(binaryPath, path, sizeof(binaryPath));
62 }
63 
64 /*
65 =================
66 Sys_BinaryPath
67 =================
68 */
Sys_BinaryPath(void)69 char *Sys_BinaryPath(void)
70 {
71 	return binaryPath;
72 }
73 
74 /*
75 =================
76 Sys_SetDefaultInstallPath
77 =================
78 */
Sys_SetDefaultInstallPath(const char * path)79 void Sys_SetDefaultInstallPath(const char *path)
80 {
81 	Q_strncpyz(installPath, path, sizeof(installPath));
82 }
83 
84 /*
85 =================
86 Sys_DefaultInstallPath
87 =================
88 */
Sys_DefaultInstallPath(void)89 char *Sys_DefaultInstallPath(void)
90 {
91 	if (*installPath)
92 		return installPath;
93 	else
94 		return Sys_Cwd();
95 }
96 
97 /*
98 =================
99 Sys_SetDefaultLibPath
100 =================
101 */
Sys_SetDefaultLibPath(const char * path)102 void Sys_SetDefaultLibPath(const char *path)
103 {
104 	Q_strncpyz(libPath, path, sizeof(libPath));
105 }
106 
107 /*
108 =================
109 Sys_DefaultLibPath
110 =================
111 */
Sys_DefaultLibPath(void)112 char *Sys_DefaultLibPath(void)
113 {
114 	if (*libPath)
115 		return libPath;
116 	else
117 		return Sys_Cwd();
118 }
119 
120 
121 /*
122 =================
123 Sys_DefaultAppPath
124 =================
125 */
Sys_DefaultAppPath(void)126 char *Sys_DefaultAppPath(void)
127 {
128 	return Sys_BinaryPath();
129 }
130 
131 /*
132 =================
133 Sys_In_Restart_f
134 
135 Restart the input subsystem
136 =================
137 */
Sys_In_Restart_f(void)138 void Sys_In_Restart_f( void )
139 {
140 	IN_Restart( );
141 }
142 
143 /*
144 =================
145 Sys_ConsoleInput
146 
147 Handle new console input
148 =================
149 */
Sys_ConsoleInput(void)150 char *Sys_ConsoleInput(void)
151 {
152 	return CON_Input( );
153 }
154 
155 /*
156 =================
157 Sys_Exit
158 
159 Single exit point (regular exit or in case of error)
160 =================
161 */
Sys_Exit(int ex)162 void Sys_Exit( int ex )
163 {
164 	CON_Shutdown( );
165 
166 #ifndef DEDICATED
167 	SDL_Quit( );
168 #endif
169 
170 #ifdef NDEBUG
171 	exit( ex );
172 #else
173 	// Cause a backtrace on error exits
174 	assert( ex == 0 );
175 	exit( ex );
176 #endif
177 }
178 
179 /*
180 =================
181 Sys_Quit
182 =================
183 */
Sys_Quit(void)184 void Sys_Quit( void )
185 {
186 	CL_Shutdown( );
187 	Sys_Exit( 0 );
188 }
189 
190 /*
191 =================
192 Sys_GetProcessorFeatures
193 =================
194 */
Sys_GetProcessorFeatures(void)195 cpuFeatures_t Sys_GetProcessorFeatures( void )
196 {
197 	cpuFeatures_t features = 0;
198 
199 #ifndef DEDICATED
200 	if( SDL_HasRDTSC( ) )    features |= CF_RDTSC;
201 	if( SDL_HasMMX( ) )      features |= CF_MMX;
202 	if( SDL_HasMMXExt( ) )   features |= CF_MMX_EXT;
203 	if( SDL_Has3DNow( ) )    features |= CF_3DNOW;
204 	if( SDL_Has3DNowExt( ) ) features |= CF_3DNOW_EXT;
205 	if( SDL_HasSSE( ) )      features |= CF_SSE;
206 	if( SDL_HasSSE2( ) )     features |= CF_SSE2;
207 	if( SDL_HasAltiVec( ) )  features |= CF_ALTIVEC;
208 #endif
209 
210 	return features;
211 }
212 
213 /*
214 =================
215 Sys_Init
216 =================
217 */
Sys_Init(void)218 void Sys_Init(void)
219 {
220 	Cmd_AddCommand( "in_restart", Sys_In_Restart_f );
221 	Cvar_Set( "arch", OS_STRING " " ARCH_STRING );
222 	Cvar_Set( "username", Sys_GetCurrentUser( ) );
223 }
224 
225 /*
226 =================
227 Sys_AnsiColorPrint
228 
229 Transform Q3 colour codes to ANSI escape sequences
230 =================
231 */
Sys_AnsiColorPrint(const char * msg)232 void Sys_AnsiColorPrint( const char *msg )
233 {
234 	static char buffer[ MAXPRINTMSG ];
235 	int         length = 0;
236 	static int  q3ToAnsi[ 8 ] =
237 	{
238 		30, // COLOR_BLACK
239 		31, // COLOR_RED
240 		32, // COLOR_GREEN
241 		33, // COLOR_YELLOW
242 		34, // COLOR_BLUE
243 		36, // COLOR_CYAN
244 		35, // COLOR_MAGENTA
245 		0   // COLOR_WHITE
246 	};
247 
248 	while( *msg )
249 	{
250 		if( Q_IsColorString( msg ) || *msg == '\n' )
251 		{
252 			// First empty the buffer
253 			if( length > 0 )
254 			{
255 				buffer[ length ] = '\0';
256 				fputs( buffer, stderr );
257 				length = 0;
258 			}
259 
260 			if( *msg == '\n' )
261 			{
262 				// Issue a reset and then the newline
263 				fputs( "\033[0m\n", stderr );
264 				msg++;
265 			}
266 			else
267 			{
268 				// Print the color code
269 				Com_sprintf( buffer, sizeof( buffer ), "\033[%dm",
270 						q3ToAnsi[ ColorIndex( *( msg + 1 ) ) ] );
271 				fputs( buffer, stderr );
272 				msg += 2;
273 			}
274 		}
275 		else
276 		{
277 			if( length >= MAXPRINTMSG - 1 )
278 				break;
279 
280 			buffer[ length ] = *msg;
281 			length++;
282 			msg++;
283 		}
284 	}
285 
286 	// Empty anything still left in the buffer
287 	if( length > 0 )
288 	{
289 		buffer[ length ] = '\0';
290 		fputs( buffer, stderr );
291 	}
292 }
293 
294 /*
295 =================
296 Sys_Print
297 =================
298 */
Sys_Print(const char * msg)299 void Sys_Print( const char *msg )
300 {
301 	CON_LogWrite( msg );
302 	CON_Print( msg );
303 }
304 
305 /*
306 =================
307 Sys_Error
308 =================
309 */
Sys_Error(const char * error,...)310 void Sys_Error( const char *error, ... )
311 {
312 	va_list argptr;
313 	char    string[1024];
314 
315 	CL_Shutdown ();
316 
317 	va_start (argptr,error);
318 	Q_vsnprintf (string, sizeof(string), error, argptr);
319 	va_end (argptr);
320 
321 	Sys_ErrorDialog( string );
322 
323 	Sys_Exit( 1 );
324 }
325 
326 /*
327 =================
328 Sys_Warn
329 =================
330 */
Sys_Warn(char * warning,...)331 void Sys_Warn( char *warning, ... )
332 {
333 	va_list argptr;
334 	char    string[1024];
335 
336 	va_start (argptr,warning);
337 	Q_vsnprintf (string, sizeof(string), warning, argptr);
338 	va_end (argptr);
339 
340 	CON_Print( va( "Warning: %s", string ) );
341 }
342 
343 /*
344 ============
345 Sys_FileTime
346 
347 returns -1 if not present
348 ============
349 */
Sys_FileTime(char * path)350 int Sys_FileTime( char *path )
351 {
352 	struct stat buf;
353 
354 	if (stat (path,&buf) == -1)
355 		return -1;
356 
357 	return buf.st_mtime;
358 }
359 
360 /*
361 =================
362 Sys_UnloadDll
363 =================
364 */
Sys_UnloadDll(void * dllHandle)365 void Sys_UnloadDll( void *dllHandle )
366 {
367 	if( !dllHandle )
368 	{
369 		Com_Printf("Sys_UnloadDll(NULL)\n");
370 		return;
371 	}
372 
373 	Sys_UnloadLibrary(dllHandle);
374 }
375 
376 /*
377 =================
378 Sys_TryLibraryLoad
379 =================
380 */
Sys_TryLibraryLoad(const char * base,const char * gamedir,const char * fname,char * fqpath)381 static void* Sys_TryLibraryLoad(const char* base, const char* gamedir, const char* fname, char* fqpath )
382 {
383 	void* libHandle;
384 	char* fn;
385 
386 	*fqpath = 0;
387 
388 	fn = FS_BuildOSPath( base, gamedir, fname );
389 	Com_Printf( "Sys_LoadDll(%s)... \n", fn );
390 
391 	libHandle = Sys_LoadLibrary(fn);
392 
393 	if(!libHandle) {
394 		Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", fn, Sys_LibraryError() );
395 		return NULL;
396 	}
397 
398 	Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn );
399 	Q_strncpyz ( fqpath , fn , MAX_QPATH ) ;
400 
401 	return libHandle;
402 }
403 
404 /*
405 =================
406 Sys_LoadDll
407 
408 Used to load a development dll instead of a virtual machine
409 #1 look down current path
410 #2 look in fs_homepath
411 #3 look in fs_basepath
412 #4 look in fs_libpath
413 =================
414 */
Sys_LoadDll(const char * name,char * fqpath,intptr_t (** entryPoint)(int,...),intptr_t (* systemcalls)(intptr_t,...))415 void *Sys_LoadDll( const char *name, char *fqpath ,
416 	intptr_t (**entryPoint)(int, ...),
417 	intptr_t (*systemcalls)(intptr_t, ...) )
418 {
419 	void  *libHandle;
420 	void  (*dllEntry)( intptr_t (*syscallptr)(intptr_t, ...) );
421 	char  fname[MAX_OSPATH];
422 	char  *basepath;
423 	char  *libpath;
424 	char  *homepath;
425 	char  *pwdpath;
426 	char  *gamedir;
427 
428 	assert( name );
429 
430 	Q_snprintf (fname, sizeof(fname), "%s" ARCH_STRING DLL_EXT, name);
431 
432 	// TODO: use fs_searchpaths from files.c
433 	pwdpath = Sys_Cwd();
434 	basepath = Cvar_VariableString( "fs_basepath" );
435 	libpath = Cvar_VariableString( "fs_libpath" );
436 	homepath = Cvar_VariableString( "fs_homepath" );
437 	gamedir = Cvar_VariableString( "fs_game" );
438 
439 	libHandle = Sys_TryLibraryLoad(pwdpath, gamedir, fname, fqpath);
440 
441 	if(!libHandle && homepath)
442 		libHandle = Sys_TryLibraryLoad(homepath, gamedir, fname, fqpath);
443 
444 	if(!libHandle && libpath)
445 		libHandle = Sys_TryLibraryLoad(libpath, gamedir, fname, fqpath);
446 
447 	if(!libHandle && basepath)
448 		libHandle = Sys_TryLibraryLoad(basepath, gamedir, fname, fqpath);
449 
450 	if(!libHandle) {
451 		Com_Printf ( "Sys_LoadDll(%s) failed to load library\n", name );
452 		return NULL;
453 	}
454 
455 	dllEntry = Sys_LoadFunction( libHandle, "dllEntry" );
456 	*entryPoint = Sys_LoadFunction( libHandle, "vmMain" );
457 
458 	if ( !*entryPoint || !dllEntry )
459 	{
460 		Com_Printf ( "Sys_LoadDll(%s) failed to find vmMain function:\n\"%s\" !\n", name, Sys_LibraryError( ) );
461 		Sys_UnloadLibrary(libHandle);
462 
463 		return NULL;
464 	}
465 
466 	Com_Printf ( "Sys_LoadDll(%s) found vmMain function at %p\n", name, *entryPoint );
467 	dllEntry( systemcalls );
468 
469 	return libHandle;
470 }
471 
472 /*
473 =================
474 Sys_ParseArgs
475 =================
476 */
Sys_ParseArgs(int argc,char ** argv)477 void Sys_ParseArgs( int argc, char **argv )
478 {
479 	if( argc == 2 )
480 	{
481 		if( !strcmp( argv[1], "--version" ) ||
482 				!strcmp( argv[1], "-v" ) )
483 		{
484 			const char* date = __DATE__;
485 #ifdef DEDICATED
486 			fprintf( stdout, Q3_VERSION " dedicated server (%s)\n", date );
487 #else
488 			fprintf( stdout, Q3_VERSION " client (%s)\n", date );
489 #endif
490 			Sys_Exit(0);
491 		}
492 	}
493 }
494 
495 #ifndef DEFAULT_BASEDIR
496 #	ifdef MACOS_X
497 #		define DEFAULT_BASEDIR Sys_StripAppBundle(Sys_BinaryPath())
498 #	else
499 #		define DEFAULT_BASEDIR Sys_BinaryPath()
500 #	endif
501 #endif
502 
503 #ifndef DEFAULT_LIBDIR
504 #	define DEFAULT_LIBDIR DEFAULT_BASEDIR
505 #endif
506 
507 /*
508 =================
509 Sys_SigHandler
510 =================
511 */
Sys_SigHandler(int signal)512 void Sys_SigHandler( int signal )
513 {
514 	static qboolean signalcaught = qfalse;
515 
516 	if( signalcaught )
517 	{
518 		fprintf( stderr, "DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n",
519 			signal );
520 	}
521 	else
522 	{
523 		signalcaught = qtrue;
524 		fprintf( stderr, "Received signal %d, exiting...\n", signal );
525 #ifndef DEDICATED
526 		CL_Shutdown();
527 #endif
528 		SV_Shutdown( "Signal caught" );
529 	}
530 
531 	Sys_Exit( 0 ); // Exit with 0 to avoid recursive signals
532 }
533 
534 /*
535 =================
536 main
537 =================
538 */
main(int argc,char ** argv)539 int main( int argc, char **argv )
540 {
541 	int   i;
542 	char  commandLine[ MAX_STRING_CHARS ] = { 0 };
543 
544 #ifndef DEDICATED
545 	// SDL version check
546 
547 	// Compile time
548 #	if !SDL_VERSION_ATLEAST(MINSDL_MAJOR,MINSDL_MINOR,MINSDL_PATCH)
549 #		error A more recent version of SDL is required
550 #	endif
551 
552 	// Run time
553 	const SDL_version *ver = SDL_Linked_Version( );
554 
555 #define STRING(s) #s
556 #define XSTRING(s) STRING(s)
557 #define MINSDL_VERSION \
558 	XSTRING(MINSDL_MAJOR) "." \
559 	XSTRING(MINSDL_MINOR) "." \
560 	XSTRING(MINSDL_PATCH)
561 
562 	if( SDL_VERSIONNUM( ver->major, ver->minor, ver->patch ) <
563 			SDL_VERSIONNUM( MINSDL_MAJOR, MINSDL_MINOR, MINSDL_PATCH ) )
564 	{
565 		Sys_Print( "SDL version " MINSDL_VERSION " or greater required\n" );
566 		Sys_Exit( 1 );
567 	}
568 #endif
569 
570 	Sys_PlatformInit( );
571 
572 	// Set the initial time base
573 	Sys_Milliseconds( );
574 
575 	Sys_ParseArgs( argc, argv );
576 	Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) );
577 	Sys_SetDefaultInstallPath( DEFAULT_BASEDIR );
578 	Sys_SetDefaultLibPath( DEFAULT_LIBDIR );
579 
580 	// Concatenate the command line for passing to Com_Init
581 	for( i = 1; i < argc; i++ )
582 	{
583 		Q_strcat( commandLine, sizeof( commandLine ), argv[ i ] );
584 		Q_strcat( commandLine, sizeof( commandLine ), " " );
585 	}
586 
587 	Com_Init( commandLine );
588 	NET_Init( );
589 
590 	CON_Init( );
591 
592 	signal( SIGILL, Sys_SigHandler );
593 	signal( SIGFPE, Sys_SigHandler );
594 	signal( SIGSEGV, Sys_SigHandler );
595 	signal( SIGTERM, Sys_SigHandler );
596 
597 	while( 1 )
598 	{
599 #ifndef DEDICATED
600 		int appState = SDL_GetAppState( );
601 
602 		Cvar_SetValue( "com_unfocused",	!( appState & SDL_APPINPUTFOCUS ) );
603 		Cvar_SetValue( "com_minimized", !( appState & SDL_APPACTIVE ) );
604 #endif
605 
606 		IN_Frame( );
607 		Com_Frame( );
608 	}
609 
610 	return 0;
611 }
612 
613