1 /*
2 ===========================================================================
3 Copyright (C) 2005 - 2015, ioquake3 contributors
4 Copyright (C) 2013 - 2015, OpenJK contributors
5
6 This file is part of the OpenJK source code.
7
8 OpenJK is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License version 2 as
10 published by the Free Software Foundation.
11
12 This program is distributed in the hope that it will be useful,
13 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 this program; if not, see <http://www.gnu.org/licenses/>.
19 ===========================================================================
20 */
21
22 #include <csignal>
23 #include <cstdlib>
24 #include <cstdarg>
25 #include <cstdio>
26 #include <sys/stat.h>
27 #define __STDC_FORMAT_MACROS
28 #include <inttypes.h>
29 #include "qcommon/qcommon.h"
30 #include "sys_local.h"
31 #include "sys_loadlib.h"
32 #include "sys_public.h"
33 #include "con_local.h"
34
35 static char binaryPath[ MAX_OSPATH ] = { 0 };
36 static char installPath[ MAX_OSPATH ] = { 0 };
37
38 cvar_t *com_minimized;
39 cvar_t *com_unfocused;
40 cvar_t *com_maxfps;
41 cvar_t *com_maxfpsMinimized;
42 cvar_t *com_maxfpsUnfocused;
43
44 /*
45 =================
46 Sys_SetBinaryPath
47 =================
48 */
Sys_SetBinaryPath(const char * path)49 void Sys_SetBinaryPath(const char *path)
50 {
51 Q_strncpyz(binaryPath, path, sizeof(binaryPath));
52 }
53
54 /*
55 =================
56 Sys_BinaryPath
57 =================
58 */
Sys_BinaryPath(void)59 char *Sys_BinaryPath(void)
60 {
61 return binaryPath;
62 }
63
64 /*
65 =================
66 Sys_SetDefaultInstallPath
67 =================
68 */
Sys_SetDefaultInstallPath(const char * path)69 void Sys_SetDefaultInstallPath(const char *path)
70 {
71 Q_strncpyz(installPath, path, sizeof(installPath));
72 }
73
74 /*
75 =================
76 Sys_DefaultInstallPath
77 =================
78 */
Sys_DefaultInstallPath(void)79 char *Sys_DefaultInstallPath(void)
80 {
81 if (*installPath)
82 return installPath;
83 else
84 return Sys_Cwd();
85 }
86
87 /*
88 =================
89 Sys_DefaultAppPath
90 =================
91 */
Sys_DefaultAppPath(void)92 char *Sys_DefaultAppPath(void)
93 {
94 return Sys_BinaryPath();
95 }
96
97 /*
98 ==================
99 Sys_GetClipboardData
100 ==================
101 */
Sys_GetClipboardData(void)102 char *Sys_GetClipboardData( void ) {
103 #ifdef DEDICATED
104 return NULL;
105 #else
106 if ( !SDL_HasClipboardText() )
107 return NULL;
108
109 char *cbText = SDL_GetClipboardText();
110 size_t len = strlen( cbText ) + 1;
111
112 char *buf = (char *)Z_Malloc( len, TAG_CLIPBOARD );
113 Q_strncpyz( buf, cbText, len );
114
115 SDL_free( cbText );
116 return buf;
117 #endif
118 }
119
120 /*
121 =================
122 Sys_ConsoleInput
123
124 Handle new console input
125 =================
126 */
Sys_ConsoleInput(void)127 char *Sys_ConsoleInput(void)
128 {
129 return CON_Input( );
130 }
131
Sys_Print(const char * msg)132 void Sys_Print( const char *msg ) {
133 // TTimo - prefix for text that shows up in console but not in notify
134 // backported from RTCW
135 if ( !Q_strncmp( msg, "[skipnotify]", 12 ) ) {
136 msg += 12;
137 }
138 if ( msg[0] == '*' ) {
139 msg += 1;
140 }
141 ConsoleLogAppend( msg );
142 CON_Print( msg );
143 }
144
145 /*
146 ================
147 Sys_Init
148
149 Called after the common systems (cvars, files, etc)
150 are initialized
151 ================
152 */
Sys_Init(void)153 void Sys_Init( void ) {
154 Cmd_AddCommand ("in_restart", IN_Restart);
155 Cvar_Get( "arch", OS_STRING " " ARCH_STRING, CVAR_ROM );
156 Cvar_Get( "username", Sys_GetCurrentUser(), CVAR_ROM );
157
158 com_unfocused = Cvar_Get( "com_unfocused", "0", CVAR_ROM );
159 com_minimized = Cvar_Get( "com_minimized", "0", CVAR_ROM );
160 #ifdef _JK2EXE
161 com_maxfps = Cvar_Get ("com_maxfps", "125", CVAR_ARCHIVE );
162 #else
163 com_maxfps = Cvar_Get( "com_maxfps", "125", CVAR_ARCHIVE, "Maximum frames per second" );
164 #endif
165 com_maxfpsUnfocused = Cvar_Get( "com_maxfpsUnfocused", "0", CVAR_ARCHIVE_ND );
166 com_maxfpsMinimized = Cvar_Get( "com_maxfpsMinimized", "50", CVAR_ARCHIVE_ND );
167 }
168
Sys_Exit(int ex)169 static void NORETURN Sys_Exit( int ex ) {
170 IN_Shutdown();
171 #ifndef DEDICATED
172 SDL_Quit();
173 #endif
174
175 NET_Shutdown();
176
177 Sys_PlatformExit();
178
179 Com_ShutdownHunkMemory();
180 Com_ShutdownZoneMemory();
181
182 CON_Shutdown();
183
184 exit( ex );
185 }
186
187 #if !defined(DEDICATED)
Sys_ErrorDialog(const char * error)188 static void Sys_ErrorDialog( const char *error )
189 {
190 time_t rawtime;
191 char timeStr[32] = {}; // should really only reach ~19 chars
192 char crashLogPath[MAX_OSPATH];
193
194 time( &rawtime );
195 strftime( timeStr, sizeof( timeStr ), "%Y-%m-%d_%H-%M-%S", localtime( &rawtime ) ); // or gmtime
196 Com_sprintf( crashLogPath, sizeof( crashLogPath ),
197 "%s%ccrashlog-%s.txt",
198 Sys_DefaultHomePath(), PATH_SEP, timeStr );
199
200 Sys_Mkdir( Sys_DefaultHomePath() );
201
202 FILE *fp = fopen( crashLogPath, "w" );
203 if ( fp )
204 {
205 ConsoleLogWriteOut( fp );
206 fclose( fp );
207
208 const char *errorMessage = va( "%s\n\nThe crash log was written to %s", error, crashLogPath );
209 if ( SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "Error", errorMessage, NULL ) < 0 )
210 {
211 fprintf( stderr, "%s", errorMessage );
212 }
213 }
214 else
215 {
216 // Getting pretty desperate now
217 ConsoleLogWriteOut( stderr );
218 fflush( stderr );
219
220 const char *errorMessage = va( "%s\nCould not write the crash log file, but we printed it to stderr.\n"
221 "Try running the game using a command line interface.", error );
222 if ( SDL_ShowSimpleMessageBox( SDL_MESSAGEBOX_ERROR, "Error", errorMessage, NULL ) < 0 )
223 {
224 // We really have hit rock bottom here :(
225 fprintf( stderr, "%s", errorMessage );
226 }
227 }
228 }
229 #endif
230
Sys_Error(const char * error,...)231 void NORETURN QDECL Sys_Error( const char *error, ... )
232 {
233 va_list argptr;
234 char string[1024];
235
236 va_start (argptr,error);
237 Q_vsnprintf (string, sizeof(string), error, argptr);
238 va_end (argptr);
239
240 Sys_Print( string );
241
242 // Only print Sys_ErrorDialog for client binary. The dedicated
243 // server binary is meant to be a command line program so you would
244 // expect to see the error printed.
245 #if !defined(DEDICATED)
246 Sys_ErrorDialog( string );
247 #endif
248
249 Sys_Exit( 3 );
250 }
251
Sys_Quit(void)252 void NORETURN Sys_Quit (void) {
253 Sys_Exit(0);
254 }
255
256 /*
257 ============
258 Sys_FileTime
259
260 returns -1 if not present
261 ============
262 */
Sys_FileTime(const char * path)263 time_t Sys_FileTime( const char *path )
264 {
265 struct stat buf;
266
267 if ( stat( path, &buf ) == -1 )
268 return -1;
269
270 return buf.st_mtime;
271 }
272
273 /*
274 =================
275 Sys_UnloadDll
276 =================
277 */
Sys_UnloadDll(void * dllHandle)278 void Sys_UnloadDll( void *dllHandle )
279 {
280 if( !dllHandle )
281 {
282 Com_Printf("Sys_UnloadDll(NULL)\n");
283 return;
284 }
285
286 Sys_UnloadLibrary(dllHandle);
287 }
288
289 /*
290 =================
291 Sys_LoadDll
292
293 First try to load library name from system library path,
294 from executable path, then fs_basepath.
295 =================
296 */
Sys_LoadDll(const char * name,qboolean useSystemLib)297 void *Sys_LoadDll( const char *name, qboolean useSystemLib )
298 {
299 void *dllhandle = NULL;
300
301 // Don't load any DLLs that end with the pk3 extension
302 if ( COM_CompareExtension( name, ".pk3" ) )
303 {
304 Com_Printf( S_COLOR_YELLOW "WARNING: Rejecting DLL named \"%s\"", name );
305 return NULL;
306 }
307
308 if ( useSystemLib )
309 {
310 Com_Printf( "Trying to load \"%s\"...\n", name );
311
312 dllhandle = Sys_LoadLibrary( name );
313 if ( dllhandle )
314 return dllhandle;
315
316 Com_Printf( "%s(%s) failed: \"%s\"\n", __FUNCTION__, name, Sys_LibraryError() );
317 }
318
319 const char *binarypath = Sys_BinaryPath();
320 const char *basepath = Cvar_VariableString( "fs_basepath" );
321
322 if ( !*binarypath )
323 binarypath = ".";
324
325 const char *searchPaths[] = {
326 binarypath,
327 basepath,
328 };
329 const size_t numPaths = ARRAY_LEN( searchPaths );
330
331 for ( size_t i = 0; i < numPaths; i++ )
332 {
333 const char *libDir = searchPaths[i];
334 if ( !libDir[0] )
335 continue;
336
337 Com_Printf( "Trying to load \"%s\" from \"%s\"...\n", name, libDir );
338 char *fn = va( "%s%c%s", libDir, PATH_SEP, name );
339 dllhandle = Sys_LoadLibrary( fn );
340 if ( dllhandle )
341 return dllhandle;
342
343 Com_Printf( "%s(%s) failed: \"%s\"\n", __FUNCTION__, fn, Sys_LibraryError() );
344 }
345 return NULL;
346 }
347
348 #if defined(MACOS_X) && !defined(_JK2EXE)
Sys_LoadMachOBundle(const char * name)349 void *Sys_LoadMachOBundle( const char *name )
350 {
351 if ( !FS_LoadMachOBundle(name) )
352 return NULL;
353
354 char *homepath = Cvar_VariableString( "fs_homepath" );
355 char *gamedir = Cvar_VariableString( "fs_game" );
356 char dllName[MAX_QPATH];
357
358 Com_sprintf( dllName, sizeof(dllName), "%s_pk3" DLL_EXT, name );
359
360 //load the unzipped library
361 char *fn = FS_BuildOSPath( homepath, gamedir, dllName );
362
363 void *libHandle = Sys_LoadLibrary( fn );
364
365 if ( libHandle != NULL ) {
366 Com_Printf( "Loaded pk3 bundle %s.\n", name );
367 }
368
369 return libHandle;
370 }
371 #endif
372
373 enum SearchPathFlag
374 {
375 SEARCH_PATH_MOD = 1 << 0,
376 SEARCH_PATH_BASE = 1 << 1,
377 SEARCH_PATH_OPENJK = 1 << 2,
378 SEARCH_PATH_ROOT = 1 << 3
379 };
380
Sys_LoadDllFromPaths(const char * filename,const char * gamedir,const char ** searchPaths,size_t numPaths,uint32_t searchFlags,const char * callerName)381 static void *Sys_LoadDllFromPaths( const char *filename, const char *gamedir, const char **searchPaths,
382 size_t numPaths, uint32_t searchFlags, const char *callerName )
383 {
384 char *fn;
385 void *libHandle;
386
387 if ( searchFlags & SEARCH_PATH_MOD )
388 {
389 for ( size_t i = 0; i < numPaths; i++ )
390 {
391 const char *libDir = searchPaths[i];
392 if ( !libDir[0] )
393 continue;
394
395 fn = FS_BuildOSPath( libDir, gamedir, filename );
396 libHandle = Sys_LoadLibrary( fn );
397 if ( libHandle )
398 return libHandle;
399
400 Com_Printf( "%s(%s) failed: \"%s\"\n", callerName, fn, Sys_LibraryError() );
401 }
402 }
403
404 if ( searchFlags & SEARCH_PATH_BASE )
405 {
406 for ( size_t i = 0; i < numPaths; i++ )
407 {
408 const char *libDir = searchPaths[i];
409 if ( !libDir[0] )
410 continue;
411
412 fn = FS_BuildOSPath( libDir, BASEGAME, filename );
413 libHandle = Sys_LoadLibrary( fn );
414 if ( libHandle )
415 return libHandle;
416
417 Com_Printf( "%s(%s) failed: \"%s\"\n", callerName, fn, Sys_LibraryError() );
418 }
419 }
420
421 if ( searchFlags & SEARCH_PATH_OPENJK )
422 {
423 for ( size_t i = 0; i < numPaths; i++ )
424 {
425 const char *libDir = searchPaths[i];
426 if ( !libDir[0] )
427 continue;
428
429 fn = FS_BuildOSPath( libDir, OPENJKGAME, filename );
430 libHandle = Sys_LoadLibrary( fn );
431 if ( libHandle )
432 return libHandle;
433
434 Com_Printf( "%s(%s) failed: \"%s\"\n", callerName, fn, Sys_LibraryError() );
435 }
436 }
437
438 if ( searchFlags & SEARCH_PATH_ROOT )
439 {
440 for ( size_t i = 0; i < numPaths; i++ )
441 {
442 const char *libDir = searchPaths[i];
443 if ( !libDir[0] )
444 continue;
445
446 fn = va( "%s%c%s", libDir, PATH_SEP, filename );
447 libHandle = Sys_LoadLibrary( fn );
448 if ( libHandle )
449 return libHandle;
450
451 Com_Printf( "%s(%s) failed: \"%s\"\n", callerName, fn, Sys_LibraryError() );
452 }
453 }
454
455 return NULL;
456 }
457
FreeUnpackDLLResult(UnpackDLLResult * result)458 static void FreeUnpackDLLResult(UnpackDLLResult *result)
459 {
460 if ( result->tempDLLPath )
461 Z_Free((void *)result->tempDLLPath);
462 }
463
Sys_LoadLegacyGameDll(const char * name,VMMainProc ** vmMain,SystemCallProc * systemcalls)464 void *Sys_LoadLegacyGameDll( const char *name, VMMainProc **vmMain, SystemCallProc *systemcalls )
465 {
466 void *libHandle = NULL;
467 char filename[MAX_OSPATH];
468
469 Com_sprintf (filename, sizeof(filename), "%s" ARCH_STRING DLL_EXT, name);
470
471 #if defined(_DEBUG)
472 libHandle = Sys_LoadLibrary( filename );
473 if ( !libHandle )
474 #endif
475 {
476 UnpackDLLResult unpackResult = Sys_UnpackDLL(filename);
477 if ( !unpackResult.succeeded )
478 {
479 if ( Sys_DLLNeedsUnpacking() )
480 {
481 FreeUnpackDLLResult(&unpackResult);
482 Com_DPrintf( "Sys_LoadLegacyGameDll: Failed to unpack %s from PK3.\n", filename );
483 return NULL;
484 }
485 }
486 else
487 {
488 libHandle = Sys_LoadLibrary(unpackResult.tempDLLPath);
489 }
490
491 FreeUnpackDLLResult(&unpackResult);
492
493 if ( !libHandle )
494 {
495 #if defined(MACOS_X) && !defined(_JK2EXE)
496 //First, look for the old-style mac .bundle that's inside a pk3
497 //It's actually zipped, and the zipfile has the same name as 'name'
498 libHandle = Sys_LoadMachOBundle( name );
499 #endif
500
501 if (!libHandle) {
502 char *basepath = Cvar_VariableString( "fs_basepath" );
503 char *homepath = Cvar_VariableString( "fs_homepath" );
504 char *cdpath = Cvar_VariableString( "fs_cdpath" );
505 char *gamedir = Cvar_VariableString( "fs_game" );
506 #ifdef MACOS_X
507 char *apppath = Cvar_VariableString( "fs_apppath" );
508 #endif
509
510 const char *searchPaths[] = {
511 homepath,
512 #ifdef MACOS_X
513 apppath,
514 #endif
515 basepath,
516 cdpath,
517 };
518 size_t numPaths = ARRAY_LEN( searchPaths );
519
520 libHandle = Sys_LoadDllFromPaths( filename, gamedir, searchPaths, numPaths, SEARCH_PATH_BASE | SEARCH_PATH_MOD, __FUNCTION__ );
521 if ( !libHandle )
522 return NULL;
523 }
524 }
525 }
526
527 typedef void QDECL DllEntryProc( SystemCallProc *syscallptr );
528
529 DllEntryProc *dllEntry = (DllEntryProc *)Sys_LoadFunction( libHandle, "dllEntry" );
530 *vmMain = (VMMainProc *)Sys_LoadFunction( libHandle, "vmMain" );
531
532 if ( !*vmMain || !dllEntry ) {
533 Com_DPrintf ( "Sys_LoadLegacyGameDll(%s) failed to find vmMain function:\n...%s!\n", name, Sys_LibraryError() );
534 Sys_UnloadLibrary( libHandle );
535 return NULL;
536 }
537
538 Com_DPrintf ( "Sys_LoadLegacyGameDll(%s) found vmMain function at 0x%" PRIxPTR "\n", name, *vmMain );
539 dllEntry( systemcalls );
540
541 return libHandle;
542 }
543
Sys_LoadSPGameDll(const char * name,GetGameAPIProc ** GetGameAPI)544 void *Sys_LoadSPGameDll( const char *name, GetGameAPIProc **GetGameAPI )
545 {
546 void *libHandle = NULL;
547 char filename[MAX_OSPATH];
548
549 assert( GetGameAPI );
550
551 Com_sprintf (filename, sizeof(filename), "%s" ARCH_STRING DLL_EXT, name);
552
553 #if defined(MACOS_X) && !defined(_JK2EXE)
554 //First, look for the old-style mac .bundle that's inside a pk3
555 //It's actually zipped, and the zipfile has the same name as 'name'
556 libHandle = Sys_LoadMachOBundle( filename );
557 #endif
558
559 if (!libHandle) {
560 char *basepath = Cvar_VariableString( "fs_basepath" );
561 char *homepath = Cvar_VariableString( "fs_homepath" );
562 char *cdpath = Cvar_VariableString( "fs_cdpath" );
563 char *gamedir = Cvar_VariableString( "fs_game" );
564 #ifdef MACOS_X
565 char *apppath = Cvar_VariableString( "fs_apppath" );
566 #endif
567
568 const char *searchPaths[] = {
569 homepath,
570 #ifdef MACOS_X
571 apppath,
572 #endif
573 basepath,
574 cdpath,
575 };
576 size_t numPaths = ARRAY_LEN( searchPaths );
577
578 libHandle = Sys_LoadDllFromPaths( filename, gamedir, searchPaths, numPaths,
579 SEARCH_PATH_BASE | SEARCH_PATH_MOD | SEARCH_PATH_OPENJK | SEARCH_PATH_ROOT,
580 __FUNCTION__ );
581 if ( !libHandle )
582 return NULL;
583 }
584
585 *GetGameAPI = (GetGameAPIProc *)Sys_LoadFunction( libHandle, "GetGameAPI" );
586 if ( !*GetGameAPI ) {
587 Com_DPrintf ( "%s(%s) failed to find GetGameAPI function:\n...%s!\n", __FUNCTION__, name, Sys_LibraryError() );
588 Sys_UnloadLibrary( libHandle );
589 return NULL;
590 }
591
592 return libHandle;
593 }
594
Sys_LoadGameDll(const char * name,GetModuleAPIProc ** moduleAPI)595 void *Sys_LoadGameDll( const char *name, GetModuleAPIProc **moduleAPI )
596 {
597 void *libHandle = NULL;
598 char filename[MAX_OSPATH];
599
600 Com_sprintf (filename, sizeof(filename), "%s" ARCH_STRING DLL_EXT, name);
601
602 #if defined(_DEBUG)
603 libHandle = Sys_LoadLibrary( filename );
604 if ( !libHandle )
605 #endif
606 {
607 UnpackDLLResult unpackResult = Sys_UnpackDLL(filename);
608 if ( !unpackResult.succeeded )
609 {
610 if ( Sys_DLLNeedsUnpacking() )
611 {
612 FreeUnpackDLLResult(&unpackResult);
613 Com_DPrintf( "Sys_LoadLegacyGameDll: Failed to unpack %s from PK3.\n", filename );
614 return NULL;
615 }
616 }
617 else
618 {
619 libHandle = Sys_LoadLibrary(unpackResult.tempDLLPath);
620 }
621
622 FreeUnpackDLLResult(&unpackResult);
623
624 if ( !libHandle )
625 {
626 #if defined(MACOS_X) && !defined(_JK2EXE)
627 //First, look for the old-style mac .bundle that's inside a pk3
628 //It's actually zipped, and the zipfile has the same name as 'name'
629 libHandle = Sys_LoadMachOBundle( name );
630 #endif
631
632 if (!libHandle) {
633 char *basepath = Cvar_VariableString( "fs_basepath" );
634 char *homepath = Cvar_VariableString( "fs_homepath" );
635 char *cdpath = Cvar_VariableString( "fs_cdpath" );
636 char *gamedir = Cvar_VariableString( "fs_game" );
637 #ifdef MACOS_X
638 char *apppath = Cvar_VariableString( "fs_apppath" );
639 #endif
640
641 const char *searchPaths[] = {
642 homepath,
643 #ifdef MACOS_X
644 apppath,
645 #endif
646 basepath,
647 cdpath,
648 };
649 size_t numPaths = ARRAY_LEN( searchPaths );
650
651 libHandle = Sys_LoadDllFromPaths( filename, gamedir, searchPaths, numPaths, SEARCH_PATH_BASE | SEARCH_PATH_MOD, __FUNCTION__ );
652 if ( !libHandle )
653 return NULL;
654 }
655 }
656 }
657
658 *moduleAPI = (GetModuleAPIProc *)Sys_LoadFunction( libHandle, "GetModuleAPI" );
659 if ( !*moduleAPI ) {
660 Com_DPrintf ( "Sys_LoadGameDll(%s) failed to find GetModuleAPI function:\n...%s!\n", name, Sys_LibraryError() );
661 Sys_UnloadLibrary( libHandle );
662 return NULL;
663 }
664
665 return libHandle;
666 }
667
668 /*
669 =================
670 Sys_SigHandler
671 =================
672 */
Sys_SigHandler(int signal)673 void Sys_SigHandler( int signal )
674 {
675 static qboolean signalcaught = qfalse;
676
677 if( signalcaught )
678 {
679 fprintf( stderr, "DOUBLE SIGNAL FAULT: Received signal %d, exiting...\n",
680 signal );
681 }
682 else
683 {
684 signalcaught = qtrue;
685 //VM_Forced_Unload_Start();
686 #ifndef DEDICATED
687 CL_Shutdown();
688 //CL_Shutdown(va("Received signal %d", signal), qtrue, qtrue);
689 #endif
690 SV_Shutdown(va("Received signal %d", signal) );
691 //VM_Forced_Unload_Done();
692 }
693
694 if( signal == SIGTERM || signal == SIGINT )
695 Sys_Exit( 1 );
696 else
697 Sys_Exit( 2 );
698 }
699
700 #ifdef MACOS_X
701 /*
702 =================
703 Sys_StripAppBundle
704
705 Discovers if passed dir is suffixed with the directory structure of a Mac OS X
706 .app bundle. If it is, the .app directory structure is stripped off the end and
707 the result is returned. If not, dir is returned untouched.
708 =================
709 */
Sys_StripAppBundle(char * dir)710 char *Sys_StripAppBundle( char *dir )
711 {
712 static char cwd[MAX_OSPATH];
713
714 Q_strncpyz(cwd, dir, sizeof(cwd));
715 if(strcmp(Sys_Basename(cwd), "MacOS"))
716 return dir;
717 Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
718 if(strcmp(Sys_Basename(cwd), "Contents"))
719 return dir;
720 Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
721 if(!strstr(Sys_Basename(cwd), ".app"))
722 return dir;
723 Q_strncpyz(cwd, Sys_Dirname(cwd), sizeof(cwd));
724 return cwd;
725 }
726 #endif
727
728 #ifndef DEFAULT_BASEDIR
729 # ifdef MACOS_X
730 # define DEFAULT_BASEDIR Sys_StripAppBundle(Sys_BinaryPath())
731 # else
732 # define DEFAULT_BASEDIR Sys_BinaryPath()
733 # endif
734 #endif
735
main(int argc,char * argv[])736 int main ( int argc, char* argv[] )
737 {
738 int i;
739 char commandLine[ MAX_STRING_CHARS ] = { 0 };
740
741 Sys_PlatformInit();
742 CON_Init();
743
744 // get the initial time base
745 Sys_Milliseconds();
746
747 #ifdef MACOS_X
748 // This is passed if we are launched by double-clicking
749 if ( argc >= 2 && Q_strncmp ( argv[1], "-psn", 4 ) == 0 )
750 argc = 1;
751 #endif
752
753 Sys_SetBinaryPath( Sys_Dirname( argv[ 0 ] ) );
754 Sys_SetDefaultInstallPath( DEFAULT_BASEDIR );
755
756 // Concatenate the command line for passing to Com_Init
757 for( i = 1; i < argc; i++ )
758 {
759 const bool containsSpaces = (strchr(argv[i], ' ') != NULL);
760 if (containsSpaces)
761 Q_strcat( commandLine, sizeof( commandLine ), "\"" );
762
763 Q_strcat( commandLine, sizeof( commandLine ), argv[ i ] );
764
765 if (containsSpaces)
766 Q_strcat( commandLine, sizeof( commandLine ), "\"" );
767
768 Q_strcat( commandLine, sizeof( commandLine ), " " );
769 }
770
771 Com_Init (commandLine);
772
773 #ifndef DEDICATED
774 SDL_version compiled;
775 SDL_version linked;
776
777 SDL_VERSION( &compiled );
778 SDL_GetVersion( &linked );
779
780 Com_Printf( "SDL Version Compiled: %d.%d.%d\n", compiled.major, compiled.minor, compiled.patch );
781 Com_Printf( "SDL Version Linked: %d.%d.%d\n", linked.major, linked.minor, linked.patch );
782 #endif
783
784 NET_Init();
785
786 // main game loop
787 while (1)
788 {
789 if ( com_busyWait->integer )
790 {
791 bool shouldSleep = false;
792
793 #if !defined(_JK2EXE)
794 if ( com_dedicated->integer )
795 {
796 shouldSleep = true;
797 }
798 #endif
799
800 if ( com_minimized->integer )
801 {
802 shouldSleep = true;
803 }
804
805 if ( shouldSleep )
806 {
807 Sys_Sleep( 5 );
808 }
809 }
810
811 // run the game
812 Com_Frame();
813 }
814
815 // never gets here
816 return 0;
817 }
818