Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

unix_main.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 #include <unistd.h>
00023 #include <signal.h>
00024 #include <stdlib.h>
00025 #include <limits.h>
00026 #include <sys/time.h>
00027 #include <sys/types.h>
00028 #include <unistd.h>
00029 #include <fcntl.h>
00030 #include <stdarg.h>
00031 #include <stdio.h>
00032 #include <sys/ipc.h>
00033 #include <sys/shm.h>
00034 #include <sys/stat.h>
00035 #include <string.h>
00036 #include <ctype.h>
00037 #include <sys/wait.h>
00038 #include <sys/mman.h>
00039 #include <errno.h>
00040 #ifdef __linux__ // rb010123
00041   #include <mntent.h>
00042 #endif
00043 #include <dlfcn.h>
00044 
00045 #ifdef __linux__
00046   #include <fpu_control.h> // bk001213 - force dumps on divide by zero
00047 #endif
00048 
00049 // FIXME TTimo should we gard this? most *nix system should comply?
00050 #include <termios.h>
00051 
00052 #include "../game/q_shared.h"
00053 #include "../qcommon/qcommon.h"
00054 #include "../renderer/tr_public.h"
00055 
00056 #include "linux_local.h" // bk001204
00057 
00058 // Structure containing functions exported from refresh DLL
00059 refexport_t re;
00060 
00061 unsigned  sys_frame_time;
00062 
00063 uid_t saved_euid;
00064 qboolean stdin_active = qtrue;
00065 
00066 // =============================================================
00067 // tty console variables
00068 // =============================================================
00069 
00070 // enable/disabled tty input mode
00071 // NOTE TTimo this is used during startup, cannot be changed during run
00072 static cvar_t *ttycon = NULL;
00073 // general flag to tell about tty console mode
00074 static qboolean ttycon_on = qfalse;
00075 // when printing general stuff to stdout stderr (Sys_Printf)
00076 //   we need to disable the tty console stuff
00077 // this increments so we can recursively disable
00078 static int ttycon_hide = 0;
00079 // some key codes that the terminal may be using
00080 // TTimo NOTE: I'm not sure how relevant this is
00081 static int tty_erase;
00082 static int tty_eof;
00083 
00084 static struct termios tty_tc;
00085 
00086 static field_t tty_con;
00087 
00088 // history
00089 // NOTE TTimo this is a bit duplicate of the graphical console history
00090 //   but it's safer and faster to write our own here
00091 #define TTY_HISTORY 32
00092 static field_t ttyEditLines[TTY_HISTORY];
00093 static int hist_current = -1, hist_count = 0;
00094 
00095 // =======================================================================
00096 // General routines
00097 // =======================================================================
00098 
00099 // bk001207 
00100 #define MEM_THRESHOLD 96*1024*1024
00101 
00102 /*
00103 ==================
00104 Sys_LowPhysicalMemory()
00105 ==================
00106 */
00107 qboolean Sys_LowPhysicalMemory() {
00108   //MEMORYSTATUS stat;
00109   //GlobalMemoryStatus (&stat);
00110   //return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse;
00111   return qfalse; // bk001207 - FIXME
00112 }
00113 
00114 /*
00115 ==================
00116 Sys_FunctionCmp
00117 ==================
00118 */
00119 int Sys_FunctionCmp(void *f1, void *f2) {
00120   return qtrue;
00121 }
00122 
00123 /*
00124 ==================
00125 Sys_FunctionCheckSum
00126 ==================
00127 */
00128 int Sys_FunctionCheckSum(void *f1) {
00129   return 0;
00130 }
00131 
00132 /*
00133 ==================
00134 Sys_MonkeyShouldBeSpanked
00135 ==================
00136 */
00137 int Sys_MonkeyShouldBeSpanked( void ) {
00138   return 0;
00139 }
00140 
00141 void Sys_BeginProfiling( void ) {
00142 }
00143 
00144 /*
00145 =================
00146 Sys_In_Restart_f
00147 
00148 Restart the input subsystem
00149 =================
00150 */
00151 void Sys_In_Restart_f( void ) 
00152 {
00153   IN_Shutdown();
00154   IN_Init();
00155 }
00156 
00157 // =============================================================
00158 // tty console routines
00159 // NOTE: if the user is editing a line when something gets printed to the early console then it won't look good
00160 //   so we provide tty_Clear and tty_Show to be called before and after a stdout or stderr output
00161 // =============================================================
00162 
00163 // flush stdin, I suspect some terminals are sending a LOT of shit
00164 // FIXME TTimo relevant?
00165 void tty_FlushIn()
00166 {
00167   char key;
00168   while (read(0, &key, 1)!=-1);
00169 }
00170 
00171 // do a backspace
00172 // TTimo NOTE: it seems on some terminals just sending '\b' is not enough
00173 //   so for now, in any case we send "\b \b" .. yeah well ..
00174 //   (there may be a way to find out if '\b' alone would work though)
00175 void tty_Back()
00176 {
00177   char key;
00178   key = '\b';
00179   write(1, &key, 1);
00180   key = ' ';
00181   write(1, &key, 1);
00182   key = '\b';
00183   write(1, &key, 1);
00184 }
00185 
00186 // clear the display of the line currently edited
00187 // bring cursor back to beginning of line
00188 void tty_Hide()
00189 {
00190   int i;
00191   assert(ttycon_on);
00192   if (ttycon_hide)
00193   {
00194     ttycon_hide++;
00195     return;
00196   }
00197   if (tty_con.cursor>0)
00198   {
00199     for (i=0; i<tty_con.cursor; i++)
00200     {
00201       tty_Back();
00202     }
00203   }
00204   ttycon_hide++;
00205 }
00206 
00207 // show the current line
00208 // FIXME TTimo need to position the cursor if needed??
00209 void tty_Show()
00210 {
00211   int i;
00212   assert(ttycon_on);
00213   assert(ttycon_hide>0);
00214   ttycon_hide--;
00215   if (ttycon_hide == 0)
00216   {
00217     if (tty_con.cursor)
00218     {
00219       for (i=0; i<tty_con.cursor; i++)
00220       {
00221         write(1, tty_con.buffer+i, 1);
00222       }
00223     }
00224   }
00225 }
00226 
00227 // never exit without calling this, or your terminal will be left in a pretty bad state
00228 void Sys_ConsoleInputShutdown()
00229 {
00230   if (ttycon_on)
00231   {
00232     Com_Printf("Shutdown tty console\n");
00233     tcsetattr (0, TCSADRAIN, &tty_tc);
00234   }
00235 }
00236 
00237 void Hist_Add(field_t *field)
00238 {
00239   int i;
00240   assert(hist_count <= TTY_HISTORY);
00241   assert(hist_count >= 0);
00242   assert(hist_current >= -1);
00243   assert(hist_current <= hist_count);
00244   // make some room
00245   for (i=TTY_HISTORY-1; i>0; i--)
00246   {
00247     ttyEditLines[i] = ttyEditLines[i-1];
00248   }
00249   ttyEditLines[0] = *field;
00250   if (hist_count<TTY_HISTORY)
00251   {
00252     hist_count++;
00253   }
00254   hist_current = -1; // re-init
00255 }
00256 
00257 field_t *Hist_Prev()
00258 {
00259   int hist_prev;
00260   assert(hist_count <= TTY_HISTORY);
00261   assert(hist_count >= 0);
00262   assert(hist_current >= -1);
00263   assert(hist_current <= hist_count);
00264   hist_prev = hist_current + 1;
00265   if (hist_prev >= hist_count)
00266   {
00267     return NULL;
00268   }
00269   hist_current++;
00270   return &(ttyEditLines[hist_current]);
00271 }
00272 
00273 field_t *Hist_Next()
00274 {
00275   assert(hist_count <= TTY_HISTORY);
00276   assert(hist_count >= 0);
00277   assert(hist_current >= -1);
00278   assert(hist_current <= hist_count);
00279   if (hist_current >= 0)
00280   {
00281     hist_current--;
00282   }
00283   if (hist_current == -1)
00284   {
00285     return NULL;
00286   }
00287   return &(ttyEditLines[hist_current]);
00288 }
00289 
00290 // =============================================================
00291 // general sys routines
00292 // =============================================================
00293 
00294 #if 0
00295 // NOTE TTimo this is not used .. looks interesting though? protection against buffer overflow kind of stuff?
00296 void Sys_Printf (char *fmt, ...)
00297 {
00298   va_list   argptr;
00299   char    text[1024];
00300   unsigned char   *p;
00301 
00302   va_start (argptr,fmt);
00303   vsprintf (text,fmt,argptr);
00304   va_end (argptr);
00305 
00306   if (strlen(text) > sizeof(text))
00307     Sys_Error("memory overwrite in Sys_Printf");
00308 
00309   for (p = (unsigned char *)text; *p; p++)
00310   {
00311     *p &= 0x7f;
00312     if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9)
00313       printf("[%02x]", *p);
00314     else
00315       putc(*p, stdout);
00316   }
00317 }
00318 #endif
00319 
00320 // single exit point (regular exit or in case of signal fault)
00321 void Sys_Exit( int ex ) {
00322   Sys_ConsoleInputShutdown();
00323 
00324 #ifdef NDEBUG // regular behavior
00325 
00326   // We can't do this 
00327   //  as long as GL DLL's keep installing with atexit...
00328   //exit(ex);
00329   _exit(ex);
00330 #else
00331 
00332   // Give me a backtrace on error exits.
00333   assert( ex == 0 );
00334   exit(ex);
00335 #endif
00336 }
00337 
00338 
00339 void Sys_Quit (void) {
00340   CL_Shutdown ();
00341   fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
00342   Sys_Exit(0);
00343 }
00344 
00345 void Sys_Init(void)
00346 {
00347   Cmd_AddCommand ("in_restart", Sys_In_Restart_f);
00348 
00349 #if defined __linux__
00350 #if defined __i386__
00351   Cvar_Set( "arch", "linux i386" );
00352 #elif defined __alpha__
00353   Cvar_Set( "arch", "linux alpha" );
00354 #elif defined __sparc__
00355   Cvar_Set( "arch", "linux sparc" );
00356 #elif defined __FreeBSD__
00357 
00358 #if defined __i386__ // FreeBSD
00359   Cvar_Set( "arch", "freebsd i386" );
00360 #elif defined __alpha__
00361   Cvar_Set( "arch", "freebsd alpha" );
00362 #else
00363   Cvar_Set( "arch", "freebsd unknown" );
00364 #endif // FreeBSD
00365 
00366 #else
00367   Cvar_Set( "arch", "linux unknown" );
00368 #endif
00369 #elif defined __sun__
00370 #if defined __i386__
00371   Cvar_Set( "arch", "solaris x86" );
00372 #elif defined __sparc__
00373   Cvar_Set( "arch", "solaris sparc" );
00374 #else
00375   Cvar_Set( "arch", "solaris unknown" );
00376 #endif
00377 #elif defined __sgi__
00378 #if defined __mips__
00379   Cvar_Set( "arch", "sgi mips" );
00380 #else
00381   Cvar_Set( "arch", "sgi unknown" );
00382 #endif
00383 #else
00384   Cvar_Set( "arch", "unknown" );
00385 #endif
00386 
00387   Cvar_Set( "username", Sys_GetCurrentUser() );
00388 
00389   IN_Init();
00390 
00391 }
00392 
00393 void  Sys_Error( const char *error, ...)
00394 { 
00395   va_list     argptr;
00396   char        string[1024];
00397 
00398   // change stdin to non blocking
00399   // NOTE TTimo not sure how well that goes with tty console mode
00400   fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY);
00401 
00402   // don't bother do a show on this one heh
00403   if (ttycon_on)
00404   {
00405     tty_Hide();
00406   }
00407 
00408   CL_Shutdown ();
00409 
00410   va_start (argptr,error);
00411   vsprintf (string,error,argptr);
00412   va_end (argptr);
00413   fprintf(stderr, "Sys_Error: %s\n", string);
00414 
00415   Sys_Exit( 1 ); // bk010104 - use single exit point.
00416 } 
00417 
00418 void Sys_Warn (char *warning, ...)
00419 { 
00420   va_list     argptr;
00421   char        string[1024];
00422 
00423   va_start (argptr,warning);
00424   vsprintf (string,warning,argptr);
00425   va_end (argptr);
00426 
00427   if (ttycon_on)
00428   {
00429     tty_Hide();
00430   }
00431 
00432   fprintf(stderr, "Warning: %s", string);
00433 
00434   if (ttycon_on)
00435   {
00436     tty_Show();
00437   }
00438 } 
00439 
00440 /*
00441 ============
00442 Sys_FileTime
00443 
00444 returns -1 if not present
00445 ============
00446 */
00447 int Sys_FileTime (char *path)
00448 {
00449   struct  stat  buf;
00450 
00451   if (stat (path,&buf) == -1)
00452     return -1;
00453 
00454   return buf.st_mtime;
00455 }
00456 
00457 void floating_point_exception_handler(int whatever)
00458 {
00459   signal(SIGFPE, floating_point_exception_handler);
00460 }
00461 
00462 // initialize the console input (tty mode if wanted and possible)
00463 void Sys_ConsoleInputInit()
00464 {
00465   struct termios tc;
00466 
00467   // TTimo 
00468   // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=390
00469   // ttycon 0 or 1, if the process is backgrounded (running non interactively)
00470   // then SIGTTIN or SIGTOU is emitted, if not catched, turns into a SIGSTP
00471   signal(SIGTTIN, SIG_IGN);
00472   signal(SIGTTOU, SIG_IGN);
00473 
00474   // FIXME TTimo initialize this in Sys_Init or something?
00475   ttycon = Cvar_Get("ttycon", "1", 0);
00476   if (ttycon && ttycon->value)
00477   {
00478     if (isatty(STDIN_FILENO)!=1)
00479     {
00480       Com_Printf("stdin is not a tty, tty console mode failed\n");
00481       Cvar_Set("ttycon", "0");
00482       ttycon_on = qfalse;
00483       return;
00484     }
00485     Com_Printf("Started tty console (use +set ttycon 0 to disable)\n");
00486     Field_Clear(&tty_con);
00487     tcgetattr (0, &tty_tc);
00488     tty_erase = tty_tc.c_cc[VERASE];
00489     tty_eof = tty_tc.c_cc[VEOF];
00490     tc = tty_tc;
00491     /*
00492      ECHO: don't echo input characters
00493      ICANON: enable canonical mode.  This  enables  the  special
00494               characters  EOF,  EOL,  EOL2, ERASE, KILL, REPRINT,
00495               STATUS, and WERASE, and buffers by lines.
00496      ISIG: when any of the characters  INTR,  QUIT,  SUSP,  or
00497               DSUSP are received, generate the corresponding sig­
00498               nal
00499     */              
00500     tc.c_lflag &= ~(ECHO | ICANON);
00501     /*
00502      ISTRIP strip off bit 8
00503      INPCK enable input parity checking
00504      */
00505     tc.c_iflag &= ~(ISTRIP | INPCK);
00506     tc.c_cc[VMIN] = 1;
00507     tc.c_cc[VTIME] = 0;
00508     tcsetattr (0, TCSADRAIN, &tc);    
00509     ttycon_on = qtrue;
00510   } else
00511     ttycon_on = qfalse;
00512 }
00513 
00514 char *Sys_ConsoleInput(void)
00515 {
00516   // we use this when sending back commands
00517   static char text[256];
00518   int i;
00519   int avail;
00520   char key;
00521   field_t *history;
00522 
00523   if (ttycon && ttycon->value)
00524   {
00525     avail = read(0, &key, 1);
00526     if (avail != -1)
00527     {
00528       // we have something
00529       // backspace?
00530       // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere
00531       if ((key == tty_erase) || (key == 127) || (key == 8))
00532       {
00533         if (tty_con.cursor > 0)
00534         {
00535           tty_con.cursor--;
00536           tty_con.buffer[tty_con.cursor] = '\0';
00537           tty_Back();
00538         }
00539         return NULL;
00540       }
00541       // check if this is a control char
00542       if ((key) && (key) < ' ')
00543       {
00544         if (key == '\n')
00545         {
00546           // push it in history
00547           Hist_Add(&tty_con);
00548           strcpy(text, tty_con.buffer);
00549           Field_Clear(&tty_con);
00550           key = '\n';
00551           write(1, &key, 1);
00552           return text;
00553         }
00554         if (key == '\t')
00555         {
00556           tty_Hide();
00557           Field_CompleteCommand( &tty_con );
00558           // Field_CompleteCommand does weird things to the string, do a cleanup
00559           //   it adds a '\' at the beginning of the string
00560           //   cursor doesn't reflect actual length of the string that's sent back
00561           tty_con.cursor = strlen(tty_con.buffer);
00562           if (tty_con.cursor>0)
00563           {
00564             if (tty_con.buffer[0] == '\\')
00565             {
00566               for (i=0; i<=tty_con.cursor; i++)
00567               {
00568                 tty_con.buffer[i] = tty_con.buffer[i+1];
00569               }
00570               tty_con.cursor--;
00571             }
00572           }
00573           tty_Show();
00574           return NULL;
00575         }
00576         avail = read(0, &key, 1);
00577         if (avail != -1)
00578         {
00579           // VT 100 keys
00580           if (key == '[' || key == 'O')
00581           {
00582             avail = read(0, &key, 1);
00583             if (avail != -1)
00584             {
00585               switch (key)
00586               {
00587               case 'A':
00588                 history = Hist_Prev();
00589                 if (history)
00590                 {
00591                   tty_Hide();
00592                   tty_con = *history;
00593                   tty_Show();
00594                 }
00595                 tty_FlushIn();
00596                 return NULL;
00597                 break;
00598               case 'B':
00599                 history = Hist_Next();
00600                 tty_Hide();
00601                 if (history)
00602                 {
00603                   tty_con = *history;
00604                 } else
00605                 {
00606                   Field_Clear(&tty_con);
00607                 }
00608                 tty_Show();
00609                 tty_FlushIn();
00610                 return NULL;
00611                 break;
00612               case 'C':
00613                 return NULL;
00614               case 'D':
00615                 return NULL;
00616               }
00617             }
00618           }
00619         }
00620         Com_DPrintf("droping ISCTL sequence: %d, tty_erase: %d\n", key, tty_erase);
00621         tty_FlushIn();
00622         return NULL;
00623       }
00624       // push regular character
00625       tty_con.buffer[tty_con.cursor] = key;
00626       tty_con.cursor++;
00627       // print the current line (this is differential)
00628       write(1, &key, 1);
00629     }
00630     return NULL;
00631   } else
00632   {
00633     int     len;
00634     fd_set  fdset;
00635     struct timeval timeout;
00636 
00637     if (!com_dedicated || !com_dedicated->value)
00638       return NULL;
00639 
00640     if (!stdin_active)
00641       return NULL;
00642 
00643     FD_ZERO(&fdset);
00644     FD_SET(0, &fdset); // stdin
00645     timeout.tv_sec = 0;
00646     timeout.tv_usec = 0;
00647     if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset))
00648     {
00649       return NULL;
00650     }
00651 
00652     len = read (0, text, sizeof(text));
00653     if (len == 0)
00654     { // eof!
00655       stdin_active = qfalse;
00656       return NULL;
00657     }
00658 
00659     if (len < 1)
00660       return NULL;
00661     text[len-1] = 0;    // rip off the /n and terminate
00662 
00663     return text;
00664   }
00665 }
00666 
00667 /*****************************************************************************/
00668 
00669 /*
00670 =================
00671 Sys_UnloadDll
00672 
00673 =================
00674 */
00675 void Sys_UnloadDll( void *dllHandle ) {
00676   // bk001206 - verbose error reporting
00677   const char* err; // rb010123 - now const
00678   if ( !dllHandle )
00679   {
00680     Com_Printf("Sys_UnloadDll(NULL)\n");
00681     return;
00682   }
00683   dlclose( dllHandle );
00684   err = dlerror();
00685   if ( err != NULL )
00686     Com_Printf ( "Sys_UnloadGame failed on dlclose: \"%s\"!\n", err );
00687 }
00688 
00689 
00690 /*
00691 =================
00692 Sys_LoadDll
00693 
00694 Used to load a development dll instead of a virtual machine
00695 TTimo:
00696 changed the load procedure to match VFS logic, and allow developer use
00697 #1 look down current path
00698 #2 look in fs_homepath
00699 #3 look in fs_basepath
00700 =================
00701 */
00702 extern char   *FS_BuildOSPath( const char *base, const char *game, const char *qpath );
00703 
00704 void *Sys_LoadDll( const char *name, char *fqpath ,
00705                    int (**entryPoint)(int, ...),
00706                    int (*systemcalls)(int, ...) ) 
00707 {
00708   void *libHandle;
00709   void  (*dllEntry)( int (*syscallptr)(int, ...) );
00710   char  curpath[MAX_OSPATH];
00711   char  fname[MAX_OSPATH];
00712   char  *basepath;
00713   char  *homepath;
00714   char  *pwdpath;
00715   char  *gamedir;
00716   char  *fn;
00717   const char*  err = NULL;
00718     
00719     *fqpath = 0;
00720 
00721   // bk001206 - let's have some paranoia
00722   assert( name );
00723 
00724   getcwd(curpath, sizeof(curpath));
00725 #if defined __i386__
00726   snprintf (fname, sizeof(fname), "%si386.so", name);
00727 #elif defined __powerpc__   //rcg010207 - PPC support.
00728   snprintf (fname, sizeof(fname), "%sppc.so", name);
00729 #elif defined __axp__
00730   snprintf (fname, sizeof(fname), "%saxp.so", name);
00731 #elif defined __mips__
00732   snprintf (fname, sizeof(fname), "%smips.so", name);
00733 #else
00734 #error Unknown arch
00735 #endif
00736 
00737 // bk001129 - was RTLD_LAZY 
00738 #define Q_RTLD    RTLD_NOW
00739 
00740   pwdpath = Sys_Cwd();
00741   basepath = Cvar_VariableString( "fs_basepath" );
00742   homepath = Cvar_VariableString( "fs_homepath" );
00743   gamedir = Cvar_VariableString( "fs_game" );
00744 
00745   // pwdpath
00746   fn = FS_BuildOSPath( pwdpath, gamedir, fname );
00747   Com_Printf( "Sys_LoadDll(%s)... \n", fn );
00748   libHandle = dlopen( fn, Q_RTLD );
00749 
00750   if ( !libHandle )
00751   {
00752     Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", fn, dlerror() );
00753     // fs_homepath
00754     fn = FS_BuildOSPath( homepath, gamedir, fname );
00755     Com_Printf( "Sys_LoadDll(%s)... \n", fn );
00756     libHandle = dlopen( fn, Q_RTLD );
00757 
00758     if ( !libHandle )
00759     {
00760       Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", fn, dlerror() );
00761       // fs_basepath
00762       fn = FS_BuildOSPath( basepath, gamedir, fname );
00763       Com_Printf( "Sys_LoadDll(%s)... \n", fn );
00764       libHandle = dlopen( fn, Q_RTLD );
00765 
00766       if ( !libHandle )
00767       {
00768 #ifndef NDEBUG // bk001206 - in debug abort on failure
00769         Com_Error ( ERR_FATAL, "Sys_LoadDll(%s) failed dlopen() completely!\n", name  );
00770 #else
00771         Com_Printf ( "Sys_LoadDll(%s) failed dlopen() completely!\n", name );
00772 #endif
00773         return NULL;
00774       } else
00775         Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn );
00776     } else
00777       Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn );
00778   } else
00779     Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn ); 
00780 
00781   dllEntry = dlsym( libHandle, "dllEntry" ); 
00782   *entryPoint = dlsym( libHandle, "vmMain" );
00783   if ( !*entryPoint || !dllEntry )
00784   {
00785     err = dlerror();
00786 #ifndef NDEBUG // bk001206 - in debug abort on failure
00787     Com_Error ( ERR_FATAL, "Sys_LoadDll(%s) failed dlsym(vmMain):\n\"%s\" !\n", name, err );
00788 #else
00789     Com_Printf ( "Sys_LoadDll(%s) failed dlsym(vmMain):\n\"%s\" !\n", name, err );
00790 #endif
00791     dlclose( libHandle );
00792     err = dlerror();
00793     if ( err != NULL )
00794       Com_Printf ( "Sys_LoadDll(%s) failed dlcose:\n\"%s\"\n", name, err );
00795     return NULL;
00796   }
00797   Com_Printf ( "Sys_LoadDll(%s) found **vmMain** at  %p  \n", name, *entryPoint ); // bk001212
00798   dllEntry( systemcalls );
00799   Com_Printf ( "Sys_LoadDll(%s) succeeded!\n", name );
00800   if ( libHandle ) Q_strncpyz ( fqpath , fn , MAX_QPATH ) ;     // added 7/20/02 by T.Ray
00801   return libHandle;
00802 }
00803 
00804 /*
00805 ========================================================================
00806 
00807 BACKGROUND FILE STREAMING
00808 
00809 ========================================================================
00810 */
00811 
00812 #if 1
00813 
00814 void Sys_InitStreamThread( void ) {
00815 }
00816 
00817 void Sys_ShutdownStreamThread( void ) {
00818 }
00819 
00820 void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) {
00821 }
00822 
00823 void Sys_EndStreamedFile( fileHandle_t f ) {
00824 }
00825 
00826 int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) {
00827   return FS_Read( buffer, size * count, f );
00828 }
00829 
00830 void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
00831   FS_Seek( f, offset, origin );
00832 }
00833 
00834 #else
00835 
00836 typedef struct
00837 {
00838   fileHandle_t file;
00839   byte  *buffer;
00840   qboolean  eof;
00841   int   bufferSize;
00842   int   streamPosition; // next byte to be returned by Sys_StreamRead
00843   int   threadPosition; // next byte to be read from file
00844 } streamState_t;
00845 
00846 streamState_t stream;
00847 
00848 /*
00849 ===============
00850 Sys_StreamThread
00851 
00852 A thread will be sitting in this loop forever
00853 ================
00854 */
00855 void Sys_StreamThread( void ) 
00856 {
00857   int   buffer;
00858   int   count;
00859   int   readCount;
00860   int   bufferPoint;
00861   int   r;
00862 
00863   // if there is any space left in the buffer, fill it up
00864   if ( !stream.eof )
00865   {
00866     count = stream.bufferSize - (stream.threadPosition - stream.streamPosition);
00867     if ( count )
00868     {
00869       bufferPoint = stream.threadPosition % stream.bufferSize;
00870       buffer = stream.bufferSize - bufferPoint;
00871       readCount = buffer < count ? buffer : count;
00872       r = FS_Read ( stream.buffer + bufferPoint, readCount, stream.file );
00873       stream.threadPosition += r;
00874 
00875       if ( r != readCount )
00876         stream.eof = qtrue;
00877     }
00878   }
00879 }
00880 
00881 /*
00882 ===============
00883 Sys_InitStreamThread
00884 
00885 ================
00886 */
00887 void Sys_InitStreamThread( void ) 
00888 {
00889 }
00890 
00891 /*
00892 ===============
00893 Sys_ShutdownStreamThread
00894 
00895 ================
00896 */
00897 void Sys_ShutdownStreamThread( void ) 
00898 {
00899 }
00900 
00901 
00902 /*
00903 ===============
00904 Sys_BeginStreamedFile
00905 
00906 ================
00907 */
00908 void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) 
00909 {
00910   if ( stream.file )
00911   {
00912     Com_Error( ERR_FATAL, "Sys_BeginStreamedFile: unclosed stream");
00913   }
00914 
00915   stream.file = f;
00916   stream.buffer = Z_Malloc( readAhead );
00917   stream.bufferSize = readAhead;
00918   stream.streamPosition = 0;
00919   stream.threadPosition = 0;
00920   stream.eof = qfalse;
00921 }
00922 
00923 /*
00924 ===============
00925 Sys_EndStreamedFile
00926 
00927 ================
00928 */
00929 void Sys_EndStreamedFile( fileHandle_t f ) 
00930 {
00931   if ( f != stream.file )
00932   {
00933     Com_Error( ERR_FATAL, "Sys_EndStreamedFile: wrong file");
00934   }
00935 
00936   stream.file = 0;
00937   Z_Free( stream.buffer );
00938 }
00939 
00940 
00941 /*
00942 ===============
00943 Sys_StreamedRead
00944 
00945 ================
00946 */
00947 int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) 
00948 {
00949   int   available;
00950   int   remaining;
00951   int   sleepCount;
00952   int   copy;
00953   int   bufferCount;
00954   int   bufferPoint;
00955   byte  *dest;
00956 
00957   dest = (byte *)buffer;
00958   remaining = size * count;
00959 
00960   if ( remaining <= 0 )
00961   {
00962     Com_Error( ERR_FATAL, "Streamed read with non-positive size" );
00963   }
00964 
00965   sleepCount = 0;
00966   while ( remaining > 0 )
00967   {
00968     available = stream.threadPosition - stream.streamPosition;
00969     if ( !available )
00970     {
00971       if (stream.eof)
00972         break;
00973       Sys_StreamThread();
00974       continue;
00975     }
00976 
00977     bufferPoint = stream.streamPosition % stream.bufferSize;
00978     bufferCount = stream.bufferSize - bufferPoint;
00979 
00980     copy = available < bufferCount ? available : bufferCount;
00981     if ( copy > remaining )
00982     {
00983       copy = remaining;
00984     }
00985     memcpy( dest, stream.buffer + bufferPoint, copy );
00986     stream.streamPosition += copy;
00987     dest += copy;
00988     remaining -= copy;
00989   }
00990 
00991   return(count * size - remaining) / size;
00992 }
00993 
00994 /*
00995 ===============
00996 Sys_StreamSeek
00997 
00998 ================
00999 */
01000 void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) {
01001   // clear to that point
01002   FS_Seek( f, offset, origin );
01003   stream.streamPosition = 0;
01004   stream.threadPosition = 0;
01005   stream.eof = qfalse;
01006 }
01007 
01008 #endif
01009 
01010 /*
01011 ========================================================================
01012 
01013 EVENT LOOP
01014 
01015 ========================================================================
01016 */
01017 
01018 // bk000306: upped this from 64
01019 #define MAX_QUED_EVENTS     256
01020 #define MASK_QUED_EVENTS    ( MAX_QUED_EVENTS - 1 )
01021 
01022 sysEvent_t  eventQue[MAX_QUED_EVENTS];
01023 // bk000306: initialize
01024 int   eventHead = 0;
01025 int             eventTail = 0;
01026 byte    sys_packetReceived[MAX_MSGLEN];
01027 
01028 /*
01029 ================
01030 Sys_QueEvent
01031 
01032 A time of 0 will get the current time
01033 Ptr should either be null, or point to a block of data that can
01034 be freed by the game later.
01035 ================
01036 */
01037 void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) {
01038   sysEvent_t  *ev;
01039 
01040   ev = &eventQue[ eventHead & MASK_QUED_EVENTS ];
01041 
01042   // bk000305 - was missing
01043   if ( eventHead - eventTail >= MAX_QUED_EVENTS )
01044   {
01045     Com_Printf("Sys_QueEvent: overflow\n");
01046     // we are discarding an event, but don't leak memory
01047     if ( ev->evPtr )
01048     {
01049       Z_Free( ev->evPtr );
01050     }
01051     eventTail++;
01052   }
01053 
01054   eventHead++;
01055 
01056   if ( time == 0 )
01057   {
01058     time = Sys_Milliseconds();
01059   }
01060 
01061   ev->evTime = time;
01062   ev->evType = type;
01063   ev->evValue = value;
01064   ev->evValue2 = value2;
01065   ev->evPtrLength = ptrLength;
01066   ev->evPtr = ptr;
01067 }
01068 
01069 /*
01070 ================
01071 Sys_GetEvent
01072 
01073 ================
01074 */
01075 sysEvent_t Sys_GetEvent( void ) {
01076   sysEvent_t  ev;
01077   char    *s;
01078   msg_t   netmsg;
01079   netadr_t  adr;
01080 
01081   // return if we have data
01082   if ( eventHead > eventTail )
01083   {
01084     eventTail++;
01085     return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
01086   }
01087 
01088   // pump the message loop
01089   // in vga this calls KBD_Update, under X, it calls GetEvent
01090   Sys_SendKeyEvents ();
01091 
01092   // check for console commands
01093   s = Sys_ConsoleInput();
01094   if ( s )
01095   {
01096     char  *b;
01097     int   len;
01098 
01099     len = strlen( s ) + 1;
01100     b = Z_Malloc( len );
01101     strcpy( b, s );
01102     Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b );
01103   }
01104 
01105   // check for other input devices
01106   IN_Frame();
01107 
01108   // check for network packets
01109   MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) );
01110   if ( Sys_GetPacket ( &adr, &netmsg ) )
01111   {
01112     netadr_t    *buf;
01113     int       len;
01114 
01115     // copy out to a seperate buffer for qeueing
01116     len = sizeof( netadr_t ) + netmsg.cursize;
01117     buf = Z_Malloc( len );
01118     *buf = adr;
01119     memcpy( buf+1, netmsg.data, netmsg.cursize );
01120     Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf );
01121   }
01122 
01123   // return if we have data
01124   if ( eventHead > eventTail )
01125   {
01126     eventTail++;
01127     return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ];
01128   }
01129 
01130   // create an empty event to return
01131 
01132   memset( &ev, 0, sizeof( ev ) );
01133   ev.evTime = Sys_Milliseconds();
01134 
01135   return ev;
01136 }
01137 
01138 /*****************************************************************************/
01139 
01140 qboolean Sys_CheckCD( void ) {
01141   return qtrue;
01142 }
01143 
01144 void Sys_AppActivate (void)
01145 {
01146 }
01147 
01148 char *Sys_GetClipboardData(void)
01149 {
01150   return NULL;
01151 }
01152 
01153 void  Sys_Print( const char *msg )
01154 {
01155   if (ttycon_on)
01156   {
01157     tty_Hide();
01158   }
01159   fputs(msg, stderr);
01160   if (ttycon_on)
01161   {
01162     tty_Show();
01163   }
01164 }
01165 
01166 
01167 void    Sys_ConfigureFPU() { // bk001213 - divide by zero
01168 #ifdef __linux__
01169 #ifdef __i386
01170 #ifndef NDEBUG
01171 
01172   // bk0101022 - enable FPE's in debug mode
01173   static int fpu_word = _FPU_DEFAULT & ~(_FPU_MASK_ZM | _FPU_MASK_IM);
01174   int current = 0;
01175   _FPU_GETCW(current);
01176   if ( current!=fpu_word)
01177   {
01178 #if 0
01179     Com_Printf("FPU Control 0x%x (was 0x%x)\n", fpu_word, current );
01180     _FPU_SETCW( fpu_word );
01181     _FPU_GETCW( current );
01182     assert(fpu_word==current);
01183 #endif
01184   }
01185 #else // NDEBUG
01186   static int fpu_word = _FPU_DEFAULT;
01187   _FPU_SETCW( fpu_word );
01188 #endif // NDEBUG
01189 #endif // __i386 
01190 #endif // __linux
01191 }
01192 
01193 void Sys_PrintBinVersion( const char* name ) {
01194   char* date = __DATE__;
01195   char* time = __TIME__;
01196   char* sep = "==============================================================";
01197   fprintf( stdout, "\n\n%s\n", sep );
01198 #ifdef DEDICATED
01199   fprintf( stdout, "Linux Quake3 Dedicated Server [%s %s]\n", date, time );  
01200 #else
01201   fprintf( stdout, "Linux Quake3 Full Executable  [%s %s]\n", date, time );  
01202 #endif
01203   fprintf( stdout, " local install: %s\n", name );
01204   fprintf( stdout, "%s\n\n", sep );
01205 }
01206 
01207 void Sys_ParseArgs( int argc, char* argv[] ) {
01208 
01209   if ( argc==2 )
01210   {
01211     if ( (!strcmp( argv[1], "--version" ))
01212          || ( !strcmp( argv[1], "-v" )) )
01213     {
01214       Sys_PrintBinVersion( argv[0] );
01215       Sys_Exit(0);
01216     }
01217   }
01218 }
01219 
01220 #include "../client/client.h"
01221 extern clientStatic_t cls;
01222 
01223 int main ( int argc, char* argv[] )
01224 {
01225   // int    oldtime, newtime; // bk001204 - unused
01226   int   len, i;
01227   char  *cmdline;
01228   void Sys_SetDefaultCDPath(const char *path);
01229 
01230   // go back to real user for config loads
01231   saved_euid = geteuid();
01232   seteuid(getuid());
01233 
01234   Sys_ParseArgs( argc, argv );  // bk010104 - added this for support
01235 
01236   Sys_SetDefaultCDPath(argv[0]);
01237 
01238   // merge the command line, this is kinda silly
01239   for (len = 1, i = 1; i < argc; i++)
01240     len += strlen(argv[i]) + 1;
01241   cmdline = malloc(len);
01242   *cmdline = 0;
01243   for (i = 1; i < argc; i++)
01244   {
01245     if (i > 1)
01246       strcat(cmdline, " ");
01247     strcat(cmdline, argv[i]);
01248   }
01249 
01250   // bk000306 - clear queues
01251   memset( &eventQue[0], 0, MAX_QUED_EVENTS*sizeof(sysEvent_t) ); 
01252   memset( &sys_packetReceived[0], 0, MAX_MSGLEN*sizeof(byte) );
01253 
01254   Com_Init(cmdline);
01255   NET_Init();
01256 
01257   Sys_ConsoleInputInit();
01258 
01259   fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY);
01260     
01261 #ifdef DEDICATED
01262     // init here for dedicated, as we don't have GLimp_Init
01263     InitSig();
01264 #endif
01265 
01266   while (1)
01267   {
01268 #ifdef __linux__
01269     Sys_ConfigureFPU();
01270 #endif
01271     Com_Frame ();
01272   }
01273 }

Generated on Thu Aug 25 12:38:04 2005 for Quake III Arena by  doxygen 1.3.9.1