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