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