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 Sys_DefaultAppPath
123 =================
124 */
Sys_DefaultAppPath(void)125 char *Sys_DefaultAppPath(void)
126 {
127 	return Sys_BinaryPath();
128 }
129 
130 /*
131 =================
132 Sys_In_Restart_f
133 
134 Restart the input subsystem
135 =================
136 */
Sys_In_Restart_f(void)137 void Sys_In_Restart_f( void )
138 {
139 	IN_Restart( );
140 }
141 
142 /*
143 =================
144 Sys_ConsoleInput
145 
146 Handle new console input
147 =================
148 */
Sys_ConsoleInput(void)149 char *Sys_ConsoleInput(void)
150 {
151 	return CON_Input( );
152 }
153 
154 #ifdef DEDICATED
155 #	define PID_FILENAME PRODUCT_NAME "_server.pid"
156 #else
157 #	define PID_FILENAME PRODUCT_NAME ".pid"
158 #endif
159 
160 /*
161 =================
162 Sys_PIDFileName
163 =================
164 */
Sys_PIDFileName(void)165 static char *Sys_PIDFileName( void )
166 {
167 	return va( "%s/%s", Sys_TempPath( ), PID_FILENAME );
168 }
169 
170 /*
171 =================
172 Sys_WritePIDFile
173 
174 Return qtrue if there is an existing stale PID file
175 =================
176 */
Sys_WritePIDFile(void)177 qboolean Sys_WritePIDFile( void )
178 {
179 	char      *pidFile = Sys_PIDFileName( );
180 	FILE      *f;
181 	qboolean  stale = qfalse;
182 
183 	// First, check if the pid file is already there
184 	if( ( f = fopen( pidFile, "r" ) ) != NULL )
185 	{
186 		char  pidBuffer[ 64 ] = { 0 };
187 		int   pid;
188 
189 		pid = fread( pidBuffer, sizeof( char ), sizeof( pidBuffer ) - 1, f );
190 		fclose( f );
191 
192 		if(pid > 0)
193 		{
194 			pid = atoi( pidBuffer );
195 			if( !Sys_PIDIsRunning( pid ) )
196 				stale = qtrue;
197 		}
198 		else
199 			stale = qtrue;
200 	}
201 
202 	if( ( f = fopen( pidFile, "w" ) ) != NULL )
203 	{
204 		fprintf( f, "%d", Sys_PID( ) );
205 		fclose( f );
206 	}
207 	else
208 		Com_Printf( S_COLOR_YELLOW "Couldn't write %s.\n", pidFile );
209 
210 	return stale;
211 }
212 
213 /*
214 =================
215 Sys_Exit
216 
217 Single exit point (regular exit or in case of error)
218 =================
219 */
Sys_Exit(int exitCode)220 static void Sys_Exit( int exitCode )
221 {
222 	CON_Shutdown( );
223 
224 #ifndef DEDICATED
225 	SDL_Quit( );
226 #endif
227 
228 	if( exitCode < 2 )
229 	{
230 		// Normal exit
231 		remove( Sys_PIDFileName( ) );
232 	}
233 
234 	exit( exitCode );
235 }
236 
237 /*
238 =================
239 Sys_Quit
240 =================
241 */
Sys_Quit(void)242 void Sys_Quit( void )
243 {
244 	Sys_Exit( 0 );
245 }
246 
247 /*
248 =================
249 Sys_GetProcessorFeatures
250 =================
251 */
Sys_GetProcessorFeatures(void)252 cpuFeatures_t Sys_GetProcessorFeatures( void )
253 {
254 	cpuFeatures_t features = 0;
255 
256 #ifndef DEDICATED
257 	if( SDL_HasRDTSC( ) )    features |= CF_RDTSC;
258 	if( SDL_HasMMX( ) )      features |= CF_MMX;
259 	if( SDL_HasMMXExt( ) )   features |= CF_MMX_EXT;
260 	if( SDL_Has3DNow( ) )    features |= CF_3DNOW;
261 	if( SDL_Has3DNowExt( ) ) features |= CF_3DNOW_EXT;
262 	if( SDL_HasSSE( ) )      features |= CF_SSE;
263 	if( SDL_HasSSE2( ) )     features |= CF_SSE2;
264 	if( SDL_HasAltiVec( ) )  features |= CF_ALTIVEC;
265 #endif
266 
267 	return features;
268 }
269 
270 /*
271 =================
272 Sys_Init
273 =================
274 */
Sys_Init(void)275 void Sys_Init(void)
276 {
277 	Cmd_AddCommand( "in_restart", Sys_In_Restart_f );
278 	Cvar_Set( "arch", OS_STRING " " ARCH_STRING );
279 	Cvar_Set( "username", Sys_GetCurrentUser( ) );
280 }
281 
282 /*
283 =================
284 Sys_AnsiColorPrint
285 
286 Transform Q3 colour codes to ANSI escape sequences
287 =================
288 */
Sys_AnsiColorPrint(const char * msg)289 void Sys_AnsiColorPrint( const char *msg )
290 {
291 	static char buffer[ MAXPRINTMSG ];
292 	int         length = 0;
293 	static int  q3ToAnsi[ 8 ] =
294 	{
295 		30, // COLOR_BLACK
296 		31, // COLOR_RED
297 		32, // COLOR_GREEN
298 		33, // COLOR_YELLOW
299 		34, // COLOR_BLUE
300 		36, // COLOR_CYAN
301 		35, // COLOR_MAGENTA
302 		0   // COLOR_WHITE
303 	};
304 
305 	while( *msg )
306 	{
307 		if( Q_IsColorString( msg ) || *msg == '\n' )
308 		{
309 			// First empty the buffer
310 			if( length > 0 )
311 			{
312 				buffer[ length ] = '\0';
313 				fputs( buffer, stderr );
314 				length = 0;
315 			}
316 
317 			if( *msg == '\n' )
318 			{
319 				// Issue a reset and then the newline
320 				fputs( "\033[0m\n", stderr );
321 				msg++;
322 			}
323 			else
324 			{
325 				// Print the color code
326 				Com_sprintf( buffer, sizeof( buffer ), "\033[%dm",
327 						q3ToAnsi[ ColorIndex( *( msg + 1 ) ) ] );
328 				fputs( buffer, stderr );
329 				msg += 2;
330 			}
331 		}
332 		else
333 		{
334 			if( length >= MAXPRINTMSG - 1 )
335 				break;
336 
337 			buffer[ length ] = *msg;
338 			length++;
339 			msg++;
340 		}
341 	}
342 
343 	// Empty anything still left in the buffer
344 	if( length > 0 )
345 	{
346 		buffer[ length ] = '\0';
347 		fputs( buffer, stderr );
348 	}
349 }
350 
351 /*
352 =================
353 Sys_Print
354 =================
355 */
Sys_Print(const char * msg)356 void Sys_Print( const char *msg )
357 {
358 	CON_LogWrite( msg );
359 	CON_Print( msg );
360 }
361 
362 /*
363 =================
364 Sys_Error
365 =================
366 */
Sys_Error(const char * error,...)367 void Sys_Error( const char *error, ... )
368 {
369 	va_list argptr;
370 	char    string[1024];
371 
372 	va_start (argptr,error);
373 	Q_vsnprintf (string, sizeof(string), error, argptr);
374 	va_end (argptr);
375 
376 	CL_Shutdown( string );
377 	Sys_ErrorDialog( string );
378 
379 	Sys_Exit( 3 );
380 }
381 
382 /*
383 =================
384 Sys_Warn
385 =================
386 */
Sys_Warn(char * warning,...)387 void Sys_Warn( char *warning, ... )
388 {
389 	va_list argptr;
390 	char    string[1024];
391 
392 	va_start (argptr,warning);
393 	Q_vsnprintf (string, sizeof(string), warning, argptr);
394 	va_end (argptr);
395 
396 	CON_Print( va( "Warning: %s", string ) );
397 }
398 
399 /*
400 ============
401 Sys_FileTime
402 
403 returns -1 if not present
404 ============
405 */
Sys_FileTime(char * path)406 int Sys_FileTime( char *path )
407 {
408 	struct stat buf;
409 
410 	if (stat (path,&buf) == -1)
411 		return -1;
412 
413 	return buf.st_mtime;
414 }
415 
416 /*
417 =================
418 Sys_UnloadDll
419 =================
420 */
Sys_UnloadDll(void * dllHandle)421 void Sys_UnloadDll( void *dllHandle )
422 {
423 	if( !dllHandle )
424 	{
425 		Com_Printf("Sys_UnloadDll(NULL)\n");
426 		return;
427 	}
428 
429 	Sys_UnloadLibrary(dllHandle);
430 }
431 
432 /*
433 =================
434 Sys_LoadDll
435 
436 Used to load a development dll instead of a virtual machine
437 #1 look in fs_homepath
438 #2 look in fs_basepath
439 =================
440 */
Sys_LoadDll(const char * name,intptr_t (** entryPoint)(int,...),intptr_t (* systemcalls)(intptr_t,...))441 void *Sys_LoadDll( const char *name,
442 	intptr_t (**entryPoint)(int, ...),
443 	intptr_t (*systemcalls)(intptr_t, ...) )
444 {
445 	void  *libHandle;
446 	void  (*dllEntry)( intptr_t (*syscallptr)(intptr_t, ...) );
447 	char  fname[MAX_OSPATH];
448 	char  *netpath;
449 
450 	assert( name );
451 
452 	Com_sprintf(fname, sizeof(fname), "%s" ARCH_STRING DLL_EXT, name);
453 
454 	netpath = FS_FindDll(fname);
455 
456 	if(!netpath) {
457 		Com_Printf( "Sys_LoadDll(%s) could not find it\n", fname );
458 		return NULL;
459 	}
460 
461 	Com_Printf( "Loading DLL file: %s\n", netpath);
462 	libHandle = Sys_LoadLibrary(netpath);
463 
464 	if(!libHandle) {
465 		Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", netpath, Sys_LibraryError() );
466 		return NULL;
467 	}
468 
469 	dllEntry = Sys_LoadFunction( libHandle, "dllEntry" );
470 	*entryPoint = Sys_LoadFunction( libHandle, "vmMain" );
471 
472 	if ( !*entryPoint || !dllEntry )
473 	{
474 		Com_Printf ( "Sys_LoadDll(%s) failed to find vmMain function:\n\"%s\" !\n", name, Sys_LibraryError( ) );
475 		Sys_UnloadLibrary(libHandle);
476 
477 		return NULL;
478 	}
479 
480 	Com_Printf ( "Sys_LoadDll(%s) found vmMain function at %p\n", name, *entryPoint );
481 	dllEntry( systemcalls );
482 
483 	return libHandle;
484 }
485 
486 /*
487 =================
488 Sys_ParseArgs
489 =================
490 */
Sys_ParseArgs(int argc,char ** argv)491 void Sys_ParseArgs( int argc, char **argv )
492 {
493 	if( argc == 2 )
494 	{
495 		if( !strcmp( argv[1], "--version" ) ||
496 				!strcmp( argv[1], "-v" ) )
497 		{
498 			const char* date = __DATE__;
499 #ifdef DEDICATED
500 			fprintf( stdout, Q3_VERSION " dedicated server (%s)\n", date );
501 #else
502 			fprintf( stdout, Q3_VERSION " client (%s)\n", date );
503 #endif
504 			Sys_Exit( 0 );
505 		}
506 	}
507 }
508 
509 #ifndef DEFAULT_BASEDIR
510 #	ifdef MACOS_X
511 #		define DEFAULT_BASEDIR Sys_StripAppBundle(Sys_BinaryPath())
512 #	else
513 #		define DEFAULT_BASEDIR Sys_BinaryPath()
514 #	endif
515 #endif
516 
517 #ifndef DEFAULT_LIBDIR
518 #	ifdef MACOS_X
519 #		define DEFAULT_LIBDIR Sys_StripAppBundle(Sys_BinaryPath())
520 #	else
521 #		define DEFAULT_LIBDIR Sys_BinaryPath()
522 #	endif
523 #endif
524 
525 /*
526 =================
527 Sys_SigHandler
528 =================
529 */
Sys_SigHandler(int signal)530 void Sys_SigHandler( int signal )
531 {
532 	static qboolean signalcaught = qfalse;
533 
534 	if( signalcaught )
535 	{
536 		fprintf( stderr, "DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n",
537 			signal );
538 	}
539 	else
540 	{
541 		signalcaught = qtrue;
542 #ifndef DEDICATED
543 		CL_Shutdown( va( "Received signal %d", signal ) );
544 #endif
545 		SV_Shutdown( va( "Received signal %d", signal ) );
546 	}
547 
548 	if( signal == SIGTERM || signal == SIGINT )
549 		Sys_Exit( 1 );
550 	else
551 		Sys_Exit( 2 );
552 }
553 
554 /*
555 =================
556 main
557 =================
558 */
main(int argc,char ** argv)559 int main( int argc, char **argv )
560 {
561 	int   i;
562 	char  commandLine[ MAX_STRING_CHARS ] = { 0 };
563 
564 #ifndef DEDICATED
565 	// SDL version check
566 
567 	// Compile time
568 #	if !SDL_VERSION_ATLEAST(MINSDL_MAJOR,MINSDL_MINOR,MINSDL_PATCH)
569 #		error A more recent version of SDL is required
570 #	endif
571 
572 	// Run time
573 	const SDL_version *ver = SDL_Linked_Version( );
574 
575 #define MINSDL_VERSION \
576 	XSTRING(MINSDL_MAJOR) "." \
577 	XSTRING(MINSDL_MINOR) "." \
578 	XSTRING(MINSDL_PATCH)
579 
580 	if( SDL_VERSIONNUM( ver->major, ver->minor, ver->patch ) <
581 			SDL_VERSIONNUM( MINSDL_MAJOR, MINSDL_MINOR, MINSDL_PATCH ) )
582 	{
583 		Sys_Dialog( DT_ERROR, va( "SDL version " MINSDL_VERSION " or greater is required, "
584 			"but only version %d.%d.%d was found. You may be able to obtain a more recent copy "
585 			"from http://www.libsdl.org/.", ver->major, ver->minor, ver->patch ), "SDL Library Too Old" );
586 
587 		Sys_Exit( 1 );
588 	}
589 #endif
590 
591 	Sys_PlatformInit( );
592 
593 	// Set the initial time base
594 	Sys_Milliseconds( );
595 
596 	Sys_ParseArgs( argc, argv );
597 	Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) );
598 	Sys_SetDefaultInstallPath( DEFAULT_BASEDIR );
599 	Sys_SetDefaultLibPath( DEFAULT_LIBDIR );
600 
601 	// Concatenate the command line for passing to Com_Init
602 	for( i = 1; i < argc; i++ )
603 	{
604 		const qboolean containsSpaces = strchr(argv[i], ' ') != NULL;
605 		if (containsSpaces)
606 			Q_strcat( commandLine, sizeof( commandLine ), "\"" );
607 
608 		Q_strcat( commandLine, sizeof( commandLine ), argv[ i ] );
609 
610 		if (containsSpaces)
611 			Q_strcat( commandLine, sizeof( commandLine ), "\"" );
612 
613 		Q_strcat( commandLine, sizeof( commandLine ), " " );
614 	}
615 
616 	Com_Init( commandLine );
617 	NET_Init( );
618 
619 	CON_Init( );
620 
621 	signal( SIGILL, Sys_SigHandler );
622 	signal( SIGFPE, Sys_SigHandler );
623 	signal( SIGSEGV, Sys_SigHandler );
624 	signal( SIGTERM, Sys_SigHandler );
625 	signal( SIGINT, Sys_SigHandler );
626 
627 	while( 1 )
628 	{
629 		IN_Frame( );
630 		Com_Frame( );
631 	}
632 
633 	return 0;
634 }
635 
636