unix_main.c (28793B)
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 Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 #include <unistd.h> 23 #include <signal.h> 24 #include <stdlib.h> 25 #include <limits.h> 26 #include <sys/time.h> 27 #include <sys/types.h> 28 #include <unistd.h> 29 #include <fcntl.h> 30 #include <stdarg.h> 31 #include <stdio.h> 32 #include <sys/ipc.h> 33 #include <sys/shm.h> 34 #include <sys/stat.h> 35 #include <string.h> 36 #include <ctype.h> 37 #include <sys/wait.h> 38 #include <sys/mman.h> 39 #include <errno.h> 40 #ifdef __linux__ // rb010123 41 #include <mntent.h> 42 #endif 43 #include <dlfcn.h> 44 45 #ifdef __linux__ 46 #include <fpu_control.h> // bk001213 - force dumps on divide by zero 47 #endif 48 49 // FIXME TTimo should we gard this? most *nix system should comply? 50 #include <termios.h> 51 52 #include "../game/q_shared.h" 53 #include "../qcommon/qcommon.h" 54 #include "../renderer/tr_public.h" 55 56 #include "linux_local.h" // bk001204 57 58 // Structure containing functions exported from refresh DLL 59 refexport_t re; 60 61 unsigned sys_frame_time; 62 63 uid_t saved_euid; 64 qboolean stdin_active = qtrue; 65 66 // ============================================================= 67 // tty console variables 68 // ============================================================= 69 70 // enable/disabled tty input mode 71 // NOTE TTimo this is used during startup, cannot be changed during run 72 static cvar_t *ttycon = NULL; 73 // general flag to tell about tty console mode 74 static qboolean ttycon_on = qfalse; 75 // when printing general stuff to stdout stderr (Sys_Printf) 76 // we need to disable the tty console stuff 77 // this increments so we can recursively disable 78 static int ttycon_hide = 0; 79 // some key codes that the terminal may be using 80 // TTimo NOTE: I'm not sure how relevant this is 81 static int tty_erase; 82 static int tty_eof; 83 84 static struct termios tty_tc; 85 86 static field_t tty_con; 87 88 // history 89 // NOTE TTimo this is a bit duplicate of the graphical console history 90 // but it's safer and faster to write our own here 91 #define TTY_HISTORY 32 92 static field_t ttyEditLines[TTY_HISTORY]; 93 static int hist_current = -1, hist_count = 0; 94 95 // ======================================================================= 96 // General routines 97 // ======================================================================= 98 99 // bk001207 100 #define MEM_THRESHOLD 96*1024*1024 101 102 /* 103 ================== 104 Sys_LowPhysicalMemory() 105 ================== 106 */ 107 qboolean Sys_LowPhysicalMemory() { 108 //MEMORYSTATUS stat; 109 //GlobalMemoryStatus (&stat); 110 //return (stat.dwTotalPhys <= MEM_THRESHOLD) ? qtrue : qfalse; 111 return qfalse; // bk001207 - FIXME 112 } 113 114 /* 115 ================== 116 Sys_FunctionCmp 117 ================== 118 */ 119 int Sys_FunctionCmp(void *f1, void *f2) { 120 return qtrue; 121 } 122 123 /* 124 ================== 125 Sys_FunctionCheckSum 126 ================== 127 */ 128 int Sys_FunctionCheckSum(void *f1) { 129 return 0; 130 } 131 132 /* 133 ================== 134 Sys_MonkeyShouldBeSpanked 135 ================== 136 */ 137 int Sys_MonkeyShouldBeSpanked( void ) { 138 return 0; 139 } 140 141 void Sys_BeginProfiling( void ) { 142 } 143 144 /* 145 ================= 146 Sys_In_Restart_f 147 148 Restart the input subsystem 149 ================= 150 */ 151 void Sys_In_Restart_f( void ) 152 { 153 IN_Shutdown(); 154 IN_Init(); 155 } 156 157 // ============================================================= 158 // tty console routines 159 // NOTE: if the user is editing a line when something gets printed to the early console then it won't look good 160 // so we provide tty_Clear and tty_Show to be called before and after a stdout or stderr output 161 // ============================================================= 162 163 // flush stdin, I suspect some terminals are sending a LOT of shit 164 // FIXME TTimo relevant? 165 void tty_FlushIn() 166 { 167 char key; 168 while (read(0, &key, 1)!=-1); 169 } 170 171 // do a backspace 172 // TTimo NOTE: it seems on some terminals just sending '\b' is not enough 173 // so for now, in any case we send "\b \b" .. yeah well .. 174 // (there may be a way to find out if '\b' alone would work though) 175 void tty_Back() 176 { 177 char key; 178 key = '\b'; 179 write(1, &key, 1); 180 key = ' '; 181 write(1, &key, 1); 182 key = '\b'; 183 write(1, &key, 1); 184 } 185 186 // clear the display of the line currently edited 187 // bring cursor back to beginning of line 188 void tty_Hide() 189 { 190 int i; 191 assert(ttycon_on); 192 if (ttycon_hide) 193 { 194 ttycon_hide++; 195 return; 196 } 197 if (tty_con.cursor>0) 198 { 199 for (i=0; i<tty_con.cursor; i++) 200 { 201 tty_Back(); 202 } 203 } 204 ttycon_hide++; 205 } 206 207 // show the current line 208 // FIXME TTimo need to position the cursor if needed?? 209 void tty_Show() 210 { 211 int i; 212 assert(ttycon_on); 213 assert(ttycon_hide>0); 214 ttycon_hide--; 215 if (ttycon_hide == 0) 216 { 217 if (tty_con.cursor) 218 { 219 for (i=0; i<tty_con.cursor; i++) 220 { 221 write(1, tty_con.buffer+i, 1); 222 } 223 } 224 } 225 } 226 227 // never exit without calling this, or your terminal will be left in a pretty bad state 228 void Sys_ConsoleInputShutdown() 229 { 230 if (ttycon_on) 231 { 232 Com_Printf("Shutdown tty console\n"); 233 tcsetattr (0, TCSADRAIN, &tty_tc); 234 } 235 } 236 237 void Hist_Add(field_t *field) 238 { 239 int i; 240 assert(hist_count <= TTY_HISTORY); 241 assert(hist_count >= 0); 242 assert(hist_current >= -1); 243 assert(hist_current <= hist_count); 244 // make some room 245 for (i=TTY_HISTORY-1; i>0; i--) 246 { 247 ttyEditLines[i] = ttyEditLines[i-1]; 248 } 249 ttyEditLines[0] = *field; 250 if (hist_count<TTY_HISTORY) 251 { 252 hist_count++; 253 } 254 hist_current = -1; // re-init 255 } 256 257 field_t *Hist_Prev() 258 { 259 int hist_prev; 260 assert(hist_count <= TTY_HISTORY); 261 assert(hist_count >= 0); 262 assert(hist_current >= -1); 263 assert(hist_current <= hist_count); 264 hist_prev = hist_current + 1; 265 if (hist_prev >= hist_count) 266 { 267 return NULL; 268 } 269 hist_current++; 270 return &(ttyEditLines[hist_current]); 271 } 272 273 field_t *Hist_Next() 274 { 275 assert(hist_count <= TTY_HISTORY); 276 assert(hist_count >= 0); 277 assert(hist_current >= -1); 278 assert(hist_current <= hist_count); 279 if (hist_current >= 0) 280 { 281 hist_current--; 282 } 283 if (hist_current == -1) 284 { 285 return NULL; 286 } 287 return &(ttyEditLines[hist_current]); 288 } 289 290 // ============================================================= 291 // general sys routines 292 // ============================================================= 293 294 #if 0 295 // NOTE TTimo this is not used .. looks interesting though? protection against buffer overflow kind of stuff? 296 void Sys_Printf (char *fmt, ...) 297 { 298 va_list argptr; 299 char text[1024]; 300 unsigned char *p; 301 302 va_start (argptr,fmt); 303 vsprintf (text,fmt,argptr); 304 va_end (argptr); 305 306 if (strlen(text) > sizeof(text)) 307 Sys_Error("memory overwrite in Sys_Printf"); 308 309 for (p = (unsigned char *)text; *p; p++) 310 { 311 *p &= 0x7f; 312 if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9) 313 printf("[%02x]", *p); 314 else 315 putc(*p, stdout); 316 } 317 } 318 #endif 319 320 // single exit point (regular exit or in case of signal fault) 321 void Sys_Exit( int ex ) { 322 Sys_ConsoleInputShutdown(); 323 324 #ifdef NDEBUG // regular behavior 325 326 // We can't do this 327 // as long as GL DLL's keep installing with atexit... 328 //exit(ex); 329 _exit(ex); 330 #else 331 332 // Give me a backtrace on error exits. 333 assert( ex == 0 ); 334 exit(ex); 335 #endif 336 } 337 338 339 void Sys_Quit (void) { 340 CL_Shutdown (); 341 fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); 342 Sys_Exit(0); 343 } 344 345 void Sys_Init(void) 346 { 347 Cmd_AddCommand ("in_restart", Sys_In_Restart_f); 348 349 #if defined __linux__ 350 #if defined __i386__ 351 Cvar_Set( "arch", "linux i386" ); 352 #elif defined __alpha__ 353 Cvar_Set( "arch", "linux alpha" ); 354 #elif defined __sparc__ 355 Cvar_Set( "arch", "linux sparc" ); 356 #elif defined __FreeBSD__ 357 358 #if defined __i386__ // FreeBSD 359 Cvar_Set( "arch", "freebsd i386" ); 360 #elif defined __alpha__ 361 Cvar_Set( "arch", "freebsd alpha" ); 362 #else 363 Cvar_Set( "arch", "freebsd unknown" ); 364 #endif // FreeBSD 365 366 #else 367 Cvar_Set( "arch", "linux unknown" ); 368 #endif 369 #elif defined __sun__ 370 #if defined __i386__ 371 Cvar_Set( "arch", "solaris x86" ); 372 #elif defined __sparc__ 373 Cvar_Set( "arch", "solaris sparc" ); 374 #else 375 Cvar_Set( "arch", "solaris unknown" ); 376 #endif 377 #elif defined __sgi__ 378 #if defined __mips__ 379 Cvar_Set( "arch", "sgi mips" ); 380 #else 381 Cvar_Set( "arch", "sgi unknown" ); 382 #endif 383 #else 384 Cvar_Set( "arch", "unknown" ); 385 #endif 386 387 Cvar_Set( "username", Sys_GetCurrentUser() ); 388 389 IN_Init(); 390 391 } 392 393 void Sys_Error( const char *error, ...) 394 { 395 va_list argptr; 396 char string[1024]; 397 398 // change stdin to non blocking 399 // NOTE TTimo not sure how well that goes with tty console mode 400 fcntl (0, F_SETFL, fcntl (0, F_GETFL, 0) & ~FNDELAY); 401 402 // don't bother do a show on this one heh 403 if (ttycon_on) 404 { 405 tty_Hide(); 406 } 407 408 CL_Shutdown (); 409 410 va_start (argptr,error); 411 vsprintf (string,error,argptr); 412 va_end (argptr); 413 fprintf(stderr, "Sys_Error: %s\n", string); 414 415 Sys_Exit( 1 ); // bk010104 - use single exit point. 416 } 417 418 void Sys_Warn (char *warning, ...) 419 { 420 va_list argptr; 421 char string[1024]; 422 423 va_start (argptr,warning); 424 vsprintf (string,warning,argptr); 425 va_end (argptr); 426 427 if (ttycon_on) 428 { 429 tty_Hide(); 430 } 431 432 fprintf(stderr, "Warning: %s", string); 433 434 if (ttycon_on) 435 { 436 tty_Show(); 437 } 438 } 439 440 /* 441 ============ 442 Sys_FileTime 443 444 returns -1 if not present 445 ============ 446 */ 447 int Sys_FileTime (char *path) 448 { 449 struct stat buf; 450 451 if (stat (path,&buf) == -1) 452 return -1; 453 454 return buf.st_mtime; 455 } 456 457 void floating_point_exception_handler(int whatever) 458 { 459 signal(SIGFPE, floating_point_exception_handler); 460 } 461 462 // initialize the console input (tty mode if wanted and possible) 463 void Sys_ConsoleInputInit() 464 { 465 struct termios tc; 466 467 // TTimo 468 // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=390 469 // ttycon 0 or 1, if the process is backgrounded (running non interactively) 470 // then SIGTTIN or SIGTOU is emitted, if not catched, turns into a SIGSTP 471 signal(SIGTTIN, SIG_IGN); 472 signal(SIGTTOU, SIG_IGN); 473 474 // FIXME TTimo initialize this in Sys_Init or something? 475 ttycon = Cvar_Get("ttycon", "1", 0); 476 if (ttycon && ttycon->value) 477 { 478 if (isatty(STDIN_FILENO)!=1) 479 { 480 Com_Printf("stdin is not a tty, tty console mode failed\n"); 481 Cvar_Set("ttycon", "0"); 482 ttycon_on = qfalse; 483 return; 484 } 485 Com_Printf("Started tty console (use +set ttycon 0 to disable)\n"); 486 Field_Clear(&tty_con); 487 tcgetattr (0, &tty_tc); 488 tty_erase = tty_tc.c_cc[VERASE]; 489 tty_eof = tty_tc.c_cc[VEOF]; 490 tc = tty_tc; 491 /* 492 ECHO: don't echo input characters 493 ICANON: enable canonical mode. This enables the special 494 characters EOF, EOL, EOL2, ERASE, KILL, REPRINT, 495 STATUS, and WERASE, and buffers by lines. 496 ISIG: when any of the characters INTR, QUIT, SUSP, or 497 DSUSP are received, generate the corresponding sig 498 nal 499 */ 500 tc.c_lflag &= ~(ECHO | ICANON); 501 /* 502 ISTRIP strip off bit 8 503 INPCK enable input parity checking 504 */ 505 tc.c_iflag &= ~(ISTRIP | INPCK); 506 tc.c_cc[VMIN] = 1; 507 tc.c_cc[VTIME] = 0; 508 tcsetattr (0, TCSADRAIN, &tc); 509 ttycon_on = qtrue; 510 } else 511 ttycon_on = qfalse; 512 } 513 514 char *Sys_ConsoleInput(void) 515 { 516 // we use this when sending back commands 517 static char text[256]; 518 int i; 519 int avail; 520 char key; 521 field_t *history; 522 523 if (ttycon && ttycon->value) 524 { 525 avail = read(0, &key, 1); 526 if (avail != -1) 527 { 528 // we have something 529 // backspace? 530 // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere 531 if ((key == tty_erase) || (key == 127) || (key == 8)) 532 { 533 if (tty_con.cursor > 0) 534 { 535 tty_con.cursor--; 536 tty_con.buffer[tty_con.cursor] = '\0'; 537 tty_Back(); 538 } 539 return NULL; 540 } 541 // check if this is a control char 542 if ((key) && (key) < ' ') 543 { 544 if (key == '\n') 545 { 546 // push it in history 547 Hist_Add(&tty_con); 548 strcpy(text, tty_con.buffer); 549 Field_Clear(&tty_con); 550 key = '\n'; 551 write(1, &key, 1); 552 return text; 553 } 554 if (key == '\t') 555 { 556 tty_Hide(); 557 Field_CompleteCommand( &tty_con ); 558 // Field_CompleteCommand does weird things to the string, do a cleanup 559 // it adds a '\' at the beginning of the string 560 // cursor doesn't reflect actual length of the string that's sent back 561 tty_con.cursor = strlen(tty_con.buffer); 562 if (tty_con.cursor>0) 563 { 564 if (tty_con.buffer[0] == '\\') 565 { 566 for (i=0; i<=tty_con.cursor; i++) 567 { 568 tty_con.buffer[i] = tty_con.buffer[i+1]; 569 } 570 tty_con.cursor--; 571 } 572 } 573 tty_Show(); 574 return NULL; 575 } 576 avail = read(0, &key, 1); 577 if (avail != -1) 578 { 579 // VT 100 keys 580 if (key == '[' || key == 'O') 581 { 582 avail = read(0, &key, 1); 583 if (avail != -1) 584 { 585 switch (key) 586 { 587 case 'A': 588 history = Hist_Prev(); 589 if (history) 590 { 591 tty_Hide(); 592 tty_con = *history; 593 tty_Show(); 594 } 595 tty_FlushIn(); 596 return NULL; 597 break; 598 case 'B': 599 history = Hist_Next(); 600 tty_Hide(); 601 if (history) 602 { 603 tty_con = *history; 604 } else 605 { 606 Field_Clear(&tty_con); 607 } 608 tty_Show(); 609 tty_FlushIn(); 610 return NULL; 611 break; 612 case 'C': 613 return NULL; 614 case 'D': 615 return NULL; 616 } 617 } 618 } 619 } 620 Com_DPrintf("droping ISCTL sequence: %d, tty_erase: %d\n", key, tty_erase); 621 tty_FlushIn(); 622 return NULL; 623 } 624 // push regular character 625 tty_con.buffer[tty_con.cursor] = key; 626 tty_con.cursor++; 627 // print the current line (this is differential) 628 write(1, &key, 1); 629 } 630 return NULL; 631 } else 632 { 633 int len; 634 fd_set fdset; 635 struct timeval timeout; 636 637 if (!com_dedicated || !com_dedicated->value) 638 return NULL; 639 640 if (!stdin_active) 641 return NULL; 642 643 FD_ZERO(&fdset); 644 FD_SET(0, &fdset); // stdin 645 timeout.tv_sec = 0; 646 timeout.tv_usec = 0; 647 if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset)) 648 { 649 return NULL; 650 } 651 652 len = read (0, text, sizeof(text)); 653 if (len == 0) 654 { // eof! 655 stdin_active = qfalse; 656 return NULL; 657 } 658 659 if (len < 1) 660 return NULL; 661 text[len-1] = 0; // rip off the /n and terminate 662 663 return text; 664 } 665 } 666 667 /*****************************************************************************/ 668 669 /* 670 ================= 671 Sys_UnloadDll 672 673 ================= 674 */ 675 void Sys_UnloadDll( void *dllHandle ) { 676 // bk001206 - verbose error reporting 677 const char* err; // rb010123 - now const 678 if ( !dllHandle ) 679 { 680 Com_Printf("Sys_UnloadDll(NULL)\n"); 681 return; 682 } 683 dlclose( dllHandle ); 684 err = dlerror(); 685 if ( err != NULL ) 686 Com_Printf ( "Sys_UnloadGame failed on dlclose: \"%s\"!\n", err ); 687 } 688 689 690 /* 691 ================= 692 Sys_LoadDll 693 694 Used to load a development dll instead of a virtual machine 695 TTimo: 696 changed the load procedure to match VFS logic, and allow developer use 697 #1 look down current path 698 #2 look in fs_homepath 699 #3 look in fs_basepath 700 ================= 701 */ 702 extern char *FS_BuildOSPath( const char *base, const char *game, const char *qpath ); 703 704 void *Sys_LoadDll( const char *name, char *fqpath , 705 int (**entryPoint)(int, ...), 706 int (*systemcalls)(int, ...) ) 707 { 708 void *libHandle; 709 void (*dllEntry)( int (*syscallptr)(int, ...) ); 710 char curpath[MAX_OSPATH]; 711 char fname[MAX_OSPATH]; 712 char *basepath; 713 char *homepath; 714 char *pwdpath; 715 char *gamedir; 716 char *fn; 717 const char* err = NULL; 718 719 *fqpath = 0; 720 721 // bk001206 - let's have some paranoia 722 assert( name ); 723 724 getcwd(curpath, sizeof(curpath)); 725 #if defined __i386__ 726 snprintf (fname, sizeof(fname), "%si386.so", name); 727 #elif defined __powerpc__ //rcg010207 - PPC support. 728 snprintf (fname, sizeof(fname), "%sppc.so", name); 729 #elif defined __axp__ 730 snprintf (fname, sizeof(fname), "%saxp.so", name); 731 #elif defined __mips__ 732 snprintf (fname, sizeof(fname), "%smips.so", name); 733 #else 734 #error Unknown arch 735 #endif 736 737 // bk001129 - was RTLD_LAZY 738 #define Q_RTLD RTLD_NOW 739 740 pwdpath = Sys_Cwd(); 741 basepath = Cvar_VariableString( "fs_basepath" ); 742 homepath = Cvar_VariableString( "fs_homepath" ); 743 gamedir = Cvar_VariableString( "fs_game" ); 744 745 // pwdpath 746 fn = FS_BuildOSPath( pwdpath, gamedir, fname ); 747 Com_Printf( "Sys_LoadDll(%s)... \n", fn ); 748 libHandle = dlopen( fn, Q_RTLD ); 749 750 if ( !libHandle ) 751 { 752 Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", fn, dlerror() ); 753 // fs_homepath 754 fn = FS_BuildOSPath( homepath, gamedir, fname ); 755 Com_Printf( "Sys_LoadDll(%s)... \n", fn ); 756 libHandle = dlopen( fn, Q_RTLD ); 757 758 if ( !libHandle ) 759 { 760 Com_Printf( "Sys_LoadDll(%s) failed:\n\"%s\"\n", fn, dlerror() ); 761 // fs_basepath 762 fn = FS_BuildOSPath( basepath, gamedir, fname ); 763 Com_Printf( "Sys_LoadDll(%s)... \n", fn ); 764 libHandle = dlopen( fn, Q_RTLD ); 765 766 if ( !libHandle ) 767 { 768 #ifndef NDEBUG // bk001206 - in debug abort on failure 769 Com_Error ( ERR_FATAL, "Sys_LoadDll(%s) failed dlopen() completely!\n", name ); 770 #else 771 Com_Printf ( "Sys_LoadDll(%s) failed dlopen() completely!\n", name ); 772 #endif 773 return NULL; 774 } else 775 Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn ); 776 } else 777 Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn ); 778 } else 779 Com_Printf ( "Sys_LoadDll(%s): succeeded ...\n", fn ); 780 781 dllEntry = dlsym( libHandle, "dllEntry" ); 782 *entryPoint = dlsym( libHandle, "vmMain" ); 783 if ( !*entryPoint || !dllEntry ) 784 { 785 err = dlerror(); 786 #ifndef NDEBUG // bk001206 - in debug abort on failure 787 Com_Error ( ERR_FATAL, "Sys_LoadDll(%s) failed dlsym(vmMain):\n\"%s\" !\n", name, err ); 788 #else 789 Com_Printf ( "Sys_LoadDll(%s) failed dlsym(vmMain):\n\"%s\" !\n", name, err ); 790 #endif 791 dlclose( libHandle ); 792 err = dlerror(); 793 if ( err != NULL ) 794 Com_Printf ( "Sys_LoadDll(%s) failed dlcose:\n\"%s\"\n", name, err ); 795 return NULL; 796 } 797 Com_Printf ( "Sys_LoadDll(%s) found **vmMain** at %p \n", name, *entryPoint ); // bk001212 798 dllEntry( systemcalls ); 799 Com_Printf ( "Sys_LoadDll(%s) succeeded!\n", name ); 800 if ( libHandle ) Q_strncpyz ( fqpath , fn , MAX_QPATH ) ; // added 7/20/02 by T.Ray 801 return libHandle; 802 } 803 804 /* 805 ======================================================================== 806 807 BACKGROUND FILE STREAMING 808 809 ======================================================================== 810 */ 811 812 #if 1 813 814 void Sys_InitStreamThread( void ) { 815 } 816 817 void Sys_ShutdownStreamThread( void ) { 818 } 819 820 void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) { 821 } 822 823 void Sys_EndStreamedFile( fileHandle_t f ) { 824 } 825 826 int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) { 827 return FS_Read( buffer, size * count, f ); 828 } 829 830 void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) { 831 FS_Seek( f, offset, origin ); 832 } 833 834 #else 835 836 typedef struct 837 { 838 fileHandle_t file; 839 byte *buffer; 840 qboolean eof; 841 int bufferSize; 842 int streamPosition; // next byte to be returned by Sys_StreamRead 843 int threadPosition; // next byte to be read from file 844 } streamState_t; 845 846 streamState_t stream; 847 848 /* 849 =============== 850 Sys_StreamThread 851 852 A thread will be sitting in this loop forever 853 ================ 854 */ 855 void Sys_StreamThread( void ) 856 { 857 int buffer; 858 int count; 859 int readCount; 860 int bufferPoint; 861 int r; 862 863 // if there is any space left in the buffer, fill it up 864 if ( !stream.eof ) 865 { 866 count = stream.bufferSize - (stream.threadPosition - stream.streamPosition); 867 if ( count ) 868 { 869 bufferPoint = stream.threadPosition % stream.bufferSize; 870 buffer = stream.bufferSize - bufferPoint; 871 readCount = buffer < count ? buffer : count; 872 r = FS_Read ( stream.buffer + bufferPoint, readCount, stream.file ); 873 stream.threadPosition += r; 874 875 if ( r != readCount ) 876 stream.eof = qtrue; 877 } 878 } 879 } 880 881 /* 882 =============== 883 Sys_InitStreamThread 884 885 ================ 886 */ 887 void Sys_InitStreamThread( void ) 888 { 889 } 890 891 /* 892 =============== 893 Sys_ShutdownStreamThread 894 895 ================ 896 */ 897 void Sys_ShutdownStreamThread( void ) 898 { 899 } 900 901 902 /* 903 =============== 904 Sys_BeginStreamedFile 905 906 ================ 907 */ 908 void Sys_BeginStreamedFile( fileHandle_t f, int readAhead ) 909 { 910 if ( stream.file ) 911 { 912 Com_Error( ERR_FATAL, "Sys_BeginStreamedFile: unclosed stream"); 913 } 914 915 stream.file = f; 916 stream.buffer = Z_Malloc( readAhead ); 917 stream.bufferSize = readAhead; 918 stream.streamPosition = 0; 919 stream.threadPosition = 0; 920 stream.eof = qfalse; 921 } 922 923 /* 924 =============== 925 Sys_EndStreamedFile 926 927 ================ 928 */ 929 void Sys_EndStreamedFile( fileHandle_t f ) 930 { 931 if ( f != stream.file ) 932 { 933 Com_Error( ERR_FATAL, "Sys_EndStreamedFile: wrong file"); 934 } 935 936 stream.file = 0; 937 Z_Free( stream.buffer ); 938 } 939 940 941 /* 942 =============== 943 Sys_StreamedRead 944 945 ================ 946 */ 947 int Sys_StreamedRead( void *buffer, int size, int count, fileHandle_t f ) 948 { 949 int available; 950 int remaining; 951 int sleepCount; 952 int copy; 953 int bufferCount; 954 int bufferPoint; 955 byte *dest; 956 957 dest = (byte *)buffer; 958 remaining = size * count; 959 960 if ( remaining <= 0 ) 961 { 962 Com_Error( ERR_FATAL, "Streamed read with non-positive size" ); 963 } 964 965 sleepCount = 0; 966 while ( remaining > 0 ) 967 { 968 available = stream.threadPosition - stream.streamPosition; 969 if ( !available ) 970 { 971 if (stream.eof) 972 break; 973 Sys_StreamThread(); 974 continue; 975 } 976 977 bufferPoint = stream.streamPosition % stream.bufferSize; 978 bufferCount = stream.bufferSize - bufferPoint; 979 980 copy = available < bufferCount ? available : bufferCount; 981 if ( copy > remaining ) 982 { 983 copy = remaining; 984 } 985 memcpy( dest, stream.buffer + bufferPoint, copy ); 986 stream.streamPosition += copy; 987 dest += copy; 988 remaining -= copy; 989 } 990 991 return(count * size - remaining) / size; 992 } 993 994 /* 995 =============== 996 Sys_StreamSeek 997 998 ================ 999 */ 1000 void Sys_StreamSeek( fileHandle_t f, int offset, int origin ) { 1001 // clear to that point 1002 FS_Seek( f, offset, origin ); 1003 stream.streamPosition = 0; 1004 stream.threadPosition = 0; 1005 stream.eof = qfalse; 1006 } 1007 1008 #endif 1009 1010 /* 1011 ======================================================================== 1012 1013 EVENT LOOP 1014 1015 ======================================================================== 1016 */ 1017 1018 // bk000306: upped this from 64 1019 #define MAX_QUED_EVENTS 256 1020 #define MASK_QUED_EVENTS ( MAX_QUED_EVENTS - 1 ) 1021 1022 sysEvent_t eventQue[MAX_QUED_EVENTS]; 1023 // bk000306: initialize 1024 int eventHead = 0; 1025 int eventTail = 0; 1026 byte sys_packetReceived[MAX_MSGLEN]; 1027 1028 /* 1029 ================ 1030 Sys_QueEvent 1031 1032 A time of 0 will get the current time 1033 Ptr should either be null, or point to a block of data that can 1034 be freed by the game later. 1035 ================ 1036 */ 1037 void Sys_QueEvent( int time, sysEventType_t type, int value, int value2, int ptrLength, void *ptr ) { 1038 sysEvent_t *ev; 1039 1040 ev = &eventQue[ eventHead & MASK_QUED_EVENTS ]; 1041 1042 // bk000305 - was missing 1043 if ( eventHead - eventTail >= MAX_QUED_EVENTS ) 1044 { 1045 Com_Printf("Sys_QueEvent: overflow\n"); 1046 // we are discarding an event, but don't leak memory 1047 if ( ev->evPtr ) 1048 { 1049 Z_Free( ev->evPtr ); 1050 } 1051 eventTail++; 1052 } 1053 1054 eventHead++; 1055 1056 if ( time == 0 ) 1057 { 1058 time = Sys_Milliseconds(); 1059 } 1060 1061 ev->evTime = time; 1062 ev->evType = type; 1063 ev->evValue = value; 1064 ev->evValue2 = value2; 1065 ev->evPtrLength = ptrLength; 1066 ev->evPtr = ptr; 1067 } 1068 1069 /* 1070 ================ 1071 Sys_GetEvent 1072 1073 ================ 1074 */ 1075 sysEvent_t Sys_GetEvent( void ) { 1076 sysEvent_t ev; 1077 char *s; 1078 msg_t netmsg; 1079 netadr_t adr; 1080 1081 // return if we have data 1082 if ( eventHead > eventTail ) 1083 { 1084 eventTail++; 1085 return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ]; 1086 } 1087 1088 // pump the message loop 1089 // in vga this calls KBD_Update, under X, it calls GetEvent 1090 Sys_SendKeyEvents (); 1091 1092 // check for console commands 1093 s = Sys_ConsoleInput(); 1094 if ( s ) 1095 { 1096 char *b; 1097 int len; 1098 1099 len = strlen( s ) + 1; 1100 b = Z_Malloc( len ); 1101 strcpy( b, s ); 1102 Sys_QueEvent( 0, SE_CONSOLE, 0, 0, len, b ); 1103 } 1104 1105 // check for other input devices 1106 IN_Frame(); 1107 1108 // check for network packets 1109 MSG_Init( &netmsg, sys_packetReceived, sizeof( sys_packetReceived ) ); 1110 if ( Sys_GetPacket ( &adr, &netmsg ) ) 1111 { 1112 netadr_t *buf; 1113 int len; 1114 1115 // copy out to a seperate buffer for qeueing 1116 len = sizeof( netadr_t ) + netmsg.cursize; 1117 buf = Z_Malloc( len ); 1118 *buf = adr; 1119 memcpy( buf+1, netmsg.data, netmsg.cursize ); 1120 Sys_QueEvent( 0, SE_PACKET, 0, 0, len, buf ); 1121 } 1122 1123 // return if we have data 1124 if ( eventHead > eventTail ) 1125 { 1126 eventTail++; 1127 return eventQue[ ( eventTail - 1 ) & MASK_QUED_EVENTS ]; 1128 } 1129 1130 // create an empty event to return 1131 1132 memset( &ev, 0, sizeof( ev ) ); 1133 ev.evTime = Sys_Milliseconds(); 1134 1135 return ev; 1136 } 1137 1138 /*****************************************************************************/ 1139 1140 qboolean Sys_CheckCD( void ) { 1141 return qtrue; 1142 } 1143 1144 void Sys_AppActivate (void) 1145 { 1146 } 1147 1148 char *Sys_GetClipboardData(void) 1149 { 1150 return NULL; 1151 } 1152 1153 void Sys_Print( const char *msg ) 1154 { 1155 if (ttycon_on) 1156 { 1157 tty_Hide(); 1158 } 1159 fputs(msg, stderr); 1160 if (ttycon_on) 1161 { 1162 tty_Show(); 1163 } 1164 } 1165 1166 1167 void Sys_ConfigureFPU() { // bk001213 - divide by zero 1168 #ifdef __linux__ 1169 #ifdef __i386 1170 #ifndef NDEBUG 1171 1172 // bk0101022 - enable FPE's in debug mode 1173 static int fpu_word = _FPU_DEFAULT & ~(_FPU_MASK_ZM | _FPU_MASK_IM); 1174 int current = 0; 1175 _FPU_GETCW(current); 1176 if ( current!=fpu_word) 1177 { 1178 #if 0 1179 Com_Printf("FPU Control 0x%x (was 0x%x)\n", fpu_word, current ); 1180 _FPU_SETCW( fpu_word ); 1181 _FPU_GETCW( current ); 1182 assert(fpu_word==current); 1183 #endif 1184 } 1185 #else // NDEBUG 1186 static int fpu_word = _FPU_DEFAULT; 1187 _FPU_SETCW( fpu_word ); 1188 #endif // NDEBUG 1189 #endif // __i386 1190 #endif // __linux 1191 } 1192 1193 void Sys_PrintBinVersion( const char* name ) { 1194 char* date = __DATE__; 1195 char* time = __TIME__; 1196 char* sep = "=============================================================="; 1197 fprintf( stdout, "\n\n%s\n", sep ); 1198 #ifdef DEDICATED 1199 fprintf( stdout, "Linux Quake3 Dedicated Server [%s %s]\n", date, time ); 1200 #else 1201 fprintf( stdout, "Linux Quake3 Full Executable [%s %s]\n", date, time ); 1202 #endif 1203 fprintf( stdout, " local install: %s\n", name ); 1204 fprintf( stdout, "%s\n\n", sep ); 1205 } 1206 1207 void Sys_ParseArgs( int argc, char* argv[] ) { 1208 1209 if ( argc==2 ) 1210 { 1211 if ( (!strcmp( argv[1], "--version" )) 1212 || ( !strcmp( argv[1], "-v" )) ) 1213 { 1214 Sys_PrintBinVersion( argv[0] ); 1215 Sys_Exit(0); 1216 } 1217 } 1218 } 1219 1220 #include "../client/client.h" 1221 extern clientStatic_t cls; 1222 1223 int main ( int argc, char* argv[] ) 1224 { 1225 // int oldtime, newtime; // bk001204 - unused 1226 int len, i; 1227 char *cmdline; 1228 void Sys_SetDefaultCDPath(const char *path); 1229 1230 // go back to real user for config loads 1231 saved_euid = geteuid(); 1232 seteuid(getuid()); 1233 1234 Sys_ParseArgs( argc, argv ); // bk010104 - added this for support 1235 1236 Sys_SetDefaultCDPath(argv[0]); 1237 1238 // merge the command line, this is kinda silly 1239 for (len = 1, i = 1; i < argc; i++) 1240 len += strlen(argv[i]) + 1; 1241 cmdline = malloc(len); 1242 *cmdline = 0; 1243 for (i = 1; i < argc; i++) 1244 { 1245 if (i > 1) 1246 strcat(cmdline, " "); 1247 strcat(cmdline, argv[i]); 1248 } 1249 1250 // bk000306 - clear queues 1251 memset( &eventQue[0], 0, MAX_QUED_EVENTS*sizeof(sysEvent_t) ); 1252 memset( &sys_packetReceived[0], 0, MAX_MSGLEN*sizeof(byte) ); 1253 1254 Com_Init(cmdline); 1255 NET_Init(); 1256 1257 Sys_ConsoleInputInit(); 1258 1259 fcntl(0, F_SETFL, fcntl (0, F_GETFL, 0) | FNDELAY); 1260 1261 #ifdef DEDICATED 1262 // init here for dedicated, as we don't have GLimp_Init 1263 InitSig(); 1264 #endif 1265 1266 while (1) 1267 { 1268 #ifdef __linux__ 1269 Sys_ConfigureFPU(); 1270 #endif 1271 Com_Frame (); 1272 } 1273 }