1/* 2Copyright (C) 1996-1997 Id Software, Inc. 3 4This program is free software; you can redistribute it and/or 5modify it under the terms of the GNU General Public License 6as published by the Free Software Foundation; either version 2 7of the License, or (at your option) any later version. 8 9This program is distributed in the hope that it will be useful, 10but WITHOUT ANY WARRANTY; without even the implied warranty of 11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13See the GNU General Public License for more details. 14 15You should have received a copy of the GNU General Public License 16along with this program; if not, write to the Free Software 17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18 19*/ 20#include <errno.h> 21#include <unistd.h> 22#include <signal.h> 23#include <stdlib.h> 24#include <limits.h> 25#include <sys/time.h> 26#include <sys/types.h> 27#include <dir.h> 28#include <unistd.h> 29#include <fcntl.h> 30#include <stdarg.h> 31#include <stdio.h> 32#include <sys/stat.h> 33#include <string.h> 34#include <dpmi.h> 35#include <sys/nearptr.h> 36#include <conio.h> 37 38#include "quakedef.h" 39#include "dosisms.h" 40 41#define MINIMUM_WIN_MEMORY 0x800000 42#define MINIMUM_WIN_MEMORY_LEVELPAK (MINIMUM_WIN_MEMORY + 0x100000) 43 44int end_of_memory; 45qboolean lockmem, lockunlockmem, unlockmem; 46static int win95; 47 48#define STDOUT 1 49 50#define KEYBUF_SIZE 256 51static unsigned char keybuf[KEYBUF_SIZE]; 52static int keybuf_head=0; 53static int keybuf_tail=0; 54 55static quakeparms_t quakeparms; 56int sys_checksum; 57static double curtime = 0.0; 58static double lastcurtime = 0.0; 59static double oldtime = 0.0; 60 61static qboolean isDedicated; 62 63static int minmem; 64 65float fptest_temp; 66 67extern char start_of_memory __asm__("start"); 68 69//============================================================================= 70 71// this is totally dependent on cwsdpmi putting the stack right after tge 72// global data 73 74// This does evil things in a Win95 DOS box!!! 75#if 0 76extern byte end; 77#define CHECKBYTE 0xed 78void Sys_InitStackCheck (void) 79{ 80 int i; 81 82 for (i=0 ; i<128*1024 ; i++) 83 (&end)[i] = CHECKBYTE; 84} 85 86void Sys_StackCheck (void) 87{ 88 int i; 89 90 for (i=0 ; i<128*1024 ; i++) 91 if ( (&end)[i] != CHECKBYTE ) 92 break; 93 94 Con_Printf ("%i undisturbed stack bytes\n", i); 95 if (end != CHECKBYTE) 96 Sys_Error ("System stack overflow!"); 97} 98#endif 99 100//============================================================================= 101 102byte scantokey[128] = 103 { 104// 0 1 2 3 4 5 6 7 105// 8 9 A B C D E F 106 0 , 27, '1', '2', '3', '4', '5', '6', 107 '7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 108 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 109 'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1 110 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', 111 '\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2 112 'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*', 113 K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 114 K_F6, K_F7, K_F8, K_F9, K_F10,0 , 0 , K_HOME, 115 K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4 116 K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, 117 K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 118 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 119 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 120 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 121 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 122 }; 123 124byte shiftscantokey[128] = 125 { 126// 0 1 2 3 4 5 6 7 127// 8 9 A B C D E F 128 0 , 27, '!', '@', '#', '$', '%', '^', 129 '&', '*', '(', ')', '_', '+', K_BACKSPACE, 9, // 0 130 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 131 'O', 'P', '{', '}', 13 , K_CTRL,'A', 'S', // 1 132 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', 133 '"' , '~', K_SHIFT,'|', 'Z', 'X', 'C', 'V', // 2 134 'B', 'N', 'M', '<', '>', '?', K_SHIFT,'*', 135 K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 136 K_F6, K_F7, K_F8, K_F9, K_F10,0 , 0 , K_HOME, 137 K_UPARROW,K_PGUP,'_',K_LEFTARROW,'%',K_RIGHTARROW,'+',K_END, //4 138 K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, 139 K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 140 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 141 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 142 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 143 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 144 }; 145 146void TrapKey(void) 147{ 148// static int ctrl=0; 149 keybuf[keybuf_head] = dos_inportb(0x60); 150 dos_outportb(0x20, 0x20); 151 /* 152 if (scantokey[keybuf[keybuf_head]&0x7f] == K_CTRL) 153 ctrl=keybuf[keybuf_head]&0x80; 154 if (ctrl && scantokey[keybuf[keybuf_head]&0x7f] == 'c') 155 Sys_Error("ctrl-c hit\n"); 156 */ 157 keybuf_head = (keybuf_head + 1) & (KEYBUF_SIZE-1); 158} 159 160#define SC_UPARROW 0x48 161#define SC_DOWNARROW 0x50 162#define SC_LEFTARROW 0x4b 163#define SC_RIGHTARROW 0x4d 164#define SC_LEFTSHIFT 0x2a 165#define SC_RIGHTSHIFT 0x36 166#define SC_RIGHTARROW 0x4d 167 168void MaskExceptions (void); 169void Sys_InitFloatTime (void); 170void Sys_PushFPCW_SetHigh (void); 171void Sys_PopFPCW (void); 172 173#define LEAVE_FOR_CACHE (512*1024) //FIXME: tune 174#define LOCKED_FOR_MALLOC (128*1024) //FIXME: tune 175 176 177void Sys_DetectWin95 (void) 178{ 179 __dpmi_regs r; 180 181 r.x.ax = 0x160a; /* Get Windows Version */ 182 __dpmi_int(0x2f, &r); 183 184 if(r.x.ax || r.h.bh < 4) /* Not windows or earlier than Win95 */ 185 { 186 win95 = 0; 187 lockmem = true; 188 lockunlockmem = false; 189 unlockmem = true; 190 } 191 else 192 { 193 win95 = 1; 194 lockunlockmem = COM_CheckParm ("-winlockunlock"); 195 196 if (lockunlockmem) 197 lockmem = true; 198 else 199 lockmem = COM_CheckParm ("-winlock"); 200 201 unlockmem = lockmem && !lockunlockmem; 202 } 203} 204 205 206void *dos_getmaxlockedmem(int *size) 207{ 208 __dpmi_free_mem_info meminfo; 209 __dpmi_meminfo info; 210 int working_size; 211 void *working_memory; 212 int last_locked; 213 int extra, i, j, allocsize; 214 static char *msg = "Locking data..."; 215 int m, n; 216 byte *x; 217 218// first lock all the current executing image so the locked count will 219// be accurate. It doesn't hurt to lock the memory multiple times 220 last_locked = __djgpp_selector_limit + 1; 221 info.size = last_locked - 4096; 222 info.address = __djgpp_base_address + 4096; 223 224 if (lockmem) 225 { 226 if(__dpmi_lock_linear_region(&info)) 227 { 228 Sys_Error ("Lock of current memory at 0x%lx for %ldKb failed!\n", 229 info.address, info.size/1024); 230 } 231 } 232 233 __dpmi_get_free_memory_information(&meminfo); 234 235 if (!win95) /* Not windows or earlier than Win95 */ 236 { 237 working_size = meminfo.maximum_locked_page_allocation_in_pages * 4096; 238 } 239 else 240 { 241 working_size = meminfo.largest_available_free_block_in_bytes - 242 LEAVE_FOR_CACHE; 243 } 244 245 working_size &= ~0xffff; /* Round down to 64K */ 246 working_size += 0x10000; 247 248 do 249 { 250 working_size -= 0x10000; /* Decrease 64K and try again */ 251 working_memory = sbrk(working_size); 252 } while (working_memory == (void *)-1); 253 254 extra = 0xfffc - ((unsigned)sbrk(0) & 0xffff); 255 256 if (extra > 0) 257 { 258 sbrk(extra); 259 working_size += extra; 260 } 261 262// now grab the memory 263 info.address = last_locked + __djgpp_base_address; 264 265 if (!win95) 266 { 267 info.size = __djgpp_selector_limit + 1 - last_locked; 268 269 while (info.size > 0 && __dpmi_lock_linear_region(&info)) 270 { 271 info.size -= 0x1000; 272 working_size -= 0x1000; 273 sbrk(-0x1000); 274 } 275 } 276 else 277 { /* Win95 section */ 278 j = COM_CheckParm("-winmem"); 279 280 if (standard_quake) 281 minmem = MINIMUM_WIN_MEMORY; 282 else 283 minmem = MINIMUM_WIN_MEMORY_LEVELPAK; 284 285 if (j) 286 { 287 allocsize = ((int)(Q_atoi(com_argv[j+1]))) * 0x100000 + 288 LOCKED_FOR_MALLOC; 289 290 if (allocsize < (minmem + LOCKED_FOR_MALLOC)) 291 allocsize = minmem + LOCKED_FOR_MALLOC; 292 } 293 else 294 { 295 allocsize = minmem + LOCKED_FOR_MALLOC; 296 } 297 298 if (!lockmem) 299 { 300 // we won't lock, just sbrk the memory 301 info.size = allocsize; 302 goto UpdateSbrk; 303 } 304 305 // lock the memory down 306 write (STDOUT, msg, strlen (msg)); 307 308 for (j=allocsize ; j>(minmem + LOCKED_FOR_MALLOC) ; 309 j -= 0x100000) 310 { 311 info.size = j; 312 313 if (!__dpmi_lock_linear_region(&info)) 314 goto Locked; 315 316 write (STDOUT, ".", 1); 317 } 318 319 // finally, try with the absolute minimum amount 320 for (i=0 ; i<10 ; i++) 321 { 322 info.size = minmem + LOCKED_FOR_MALLOC; 323 324 if (!__dpmi_lock_linear_region(&info)) 325 goto Locked; 326 } 327 328 Sys_Error ("Can't lock memory; %d Mb lockable RAM required. " 329 "Try shrinking smartdrv.", info.size / 0x100000); 330 331Locked: 332 333UpdateSbrk: 334 335 info.address += info.size; 336 info.address -= __djgpp_base_address + 4; // ending point, malloc align 337 working_size = info.address - (int)working_memory; 338 sbrk(info.address-(int)sbrk(0)); // negative adjustment 339 } 340 341 342 if (lockunlockmem) 343 { 344 __dpmi_unlock_linear_region (&info); 345 printf ("Locked and unlocked %d Mb data\n", working_size / 0x100000); 346 } 347 else if (lockmem) 348 { 349 printf ("Locked %d Mb data\n", working_size / 0x100000); 350 } 351 else 352 { 353 printf ("Allocated %d Mb data\n", working_size / 0x100000); 354 } 355 356// touch all the memory to make sure it's there. The 16-page skip is to 357// keep Win 95 from thinking we're trying to page ourselves in (we are 358// doing that, of course, but there's no reason we shouldn't) 359 x = (byte *)working_memory; 360 361 for (n=0 ; n<4 ; n++) 362 { 363 for (m=0 ; m<(working_size - 16 * 0x1000) ; m += 4) 364 { 365 sys_checksum += *(int *)&x[m]; 366 sys_checksum += *(int *)&x[m + 16 * 0x1000]; 367 } 368 } 369 370// give some of what we locked back for malloc before returning. Done 371// by cheating and passing a negative value to sbrk 372 working_size -= LOCKED_FOR_MALLOC; 373 sbrk( -(LOCKED_FOR_MALLOC)); 374 *size = working_size; 375 return working_memory; 376} 377 378 379/* 380============ 381Sys_FileTime 382 383returns -1 if not present 384============ 385*/ 386int Sys_FileTime (char *path) 387{ 388 struct stat buf; 389 390 if (stat (path,&buf) == -1) 391 return -1; 392 393 return buf.st_mtime; 394} 395 396void Sys_mkdir (char *path) 397{ 398 mkdir (path, 0777); 399} 400 401 402void Sys_Sleep(void) 403{ 404} 405 406 407char *Sys_ConsoleInput(void) 408{ 409 static char text[256]; 410 static int len = 0; 411 char ch; 412 413 if (!isDedicated) 414 return NULL; 415 416 if (! kbhit()) 417 return NULL; 418 419 ch = getche(); 420 421 switch (ch) 422 { 423 case '\r': 424 putch('\n'); 425 if (len) 426 { 427 text[len] = 0; 428 len = 0; 429 return text; 430 } 431 break; 432 433 case '\b': 434 putch(' '); 435 if (len) 436 { 437 len--; 438 putch('\b'); 439 } 440 break; 441 442 default: 443 text[len] = ch; 444 len = (len + 1) & 0xff; 445 break; 446 } 447 448 return NULL; 449} 450 451void Sys_Init(void) 452{ 453 454 MaskExceptions (); 455 456 Sys_SetFPCW (); 457 458 dos_outportb(0x43, 0x34); // set system timer to mode 2 459 dos_outportb(0x40, 0); // for the Sys_FloatTime() function 460 dos_outportb(0x40, 0); 461 462 Sys_InitFloatTime (); 463 464 _go32_interrupt_stack_size = 4 * 1024;; 465 _go32_rmcb_stack_size = 4 * 1024; 466} 467 468void Sys_Shutdown(void) 469{ 470 if (!isDedicated) 471 dos_restoreintr(9); 472 473 if (unlockmem) 474 { 475 dos_unlockmem (&start_of_memory, 476 end_of_memory - (int)&start_of_memory); 477 dos_unlockmem (quakeparms.membase, quakeparms.memsize); 478 } 479} 480 481 482#define SC_RSHIFT 0x36 483#define SC_LSHIFT 0x2a 484void Sys_SendKeyEvents (void) 485{ 486 int k, next; 487 int outkey; 488 489// get key events 490 491 while (keybuf_head != keybuf_tail) 492 { 493 494 k = keybuf[keybuf_tail++]; 495 keybuf_tail &= (KEYBUF_SIZE-1); 496 497 if (k==0xe0) 498 continue; // special / pause keys 499 next = keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)]; 500 if (next == 0xe1) 501 continue; // pause key bullshit 502 if (k==0xc5 && next == 0x9d) 503 { 504 Key_Event (K_PAUSE, true); 505 continue; 506 } 507 508 // extended keyboard shift key bullshit 509 if ( (k&0x7f)==SC_LSHIFT || (k&0x7f)==SC_RSHIFT ) 510 { 511 if ( keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)]==0xe0 ) 512 continue; 513 k &= 0x80; 514 k |= SC_RSHIFT; 515 } 516 517 if (k==0xc5 && keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)] == 0x9d) 518 continue; // more pause bullshit 519 520 outkey = scantokey[k & 0x7f]; 521 522 if (k & 0x80) 523 Key_Event (outkey, false); 524 else 525 Key_Event (outkey, true); 526 527 } 528 529} 530 531 532// ======================================================================= 533// General routines 534// ======================================================================= 535 536/* 537================ 538Sys_Printf 539================ 540*/ 541 542void Sys_Printf (char *fmt, ...) 543{ 544 va_list argptr; 545 char text[1024]; 546 547 va_start (argptr,fmt); 548 vsprintf (text,fmt,argptr); 549 va_end (argptr); 550 551 if (cls.state == ca_dedicated) 552 fprintf(stderr, "%s", text); 553} 554 555void Sys_AtExit (void) 556{ 557 558// shutdown only once (so Sys_Error can call this function to shutdown, then 559// print the error message, then call exit without exit calling this function 560// again) 561 Sys_Shutdown(); 562} 563 564 565void Sys_Quit (void) 566{ 567 byte screen[80*25*2]; 568 byte *d; 569 char ver[6]; 570 int i; 571 572 573// load the sell screen before shuting everything down 574 if (registered.value) 575 d = COM_LoadHunkFile ("end2.bin"); 576 else 577 d = COM_LoadHunkFile ("end1.bin"); 578 if (d) 579 memcpy (screen, d, sizeof(screen)); 580 581// write the version number directly to the end screen 582 sprintf (ver, " v%4.2f", VERSION); 583 for (i=0 ; i<6 ; i++) 584 screen[0*80*2 + 72*2 + i*2] = ver[i]; 585 586 Host_Shutdown(); 587 588// do the text mode sell screen 589 if (d) 590 { 591 memcpy ((void *)real2ptr(0xb8000), screen,80*25*2); 592 593 // set text pos 594 regs.x.ax = 0x0200; 595 regs.h.bh = 0; 596 regs.h.dl = 0; 597 regs.h.dh = 22; 598 dos_int86 (0x10); 599 } 600 else 601 printf ("couldn't load endscreen.\n"); 602 603 exit(0); 604} 605 606void Sys_Error (char *error, ...) 607{ 608 va_list argptr; 609 char string[1024]; 610 611 va_start (argptr,error); 612 vsprintf (string,error,argptr); 613 va_end (argptr); 614 615 Host_Shutdown(); 616 fprintf(stderr, "Error: %s\n", string); 617// Sys_AtExit is called by exit to shutdown the system 618 exit(0); 619} 620 621 622int Sys_FileOpenRead (char *path, int *handle) 623{ 624 int h; 625 struct stat fileinfo; 626 627 h = open (path, O_RDONLY|O_BINARY, 0666); 628 *handle = h; 629 if (h == -1) 630 return -1; 631 632 if (fstat (h,&fileinfo) == -1) 633 Sys_Error ("Error fstating %s", path); 634 635 return fileinfo.st_size; 636} 637 638int Sys_FileOpenWrite (char *path) 639{ 640 int handle; 641 642 umask (0); 643 644 handle = open(path,O_RDWR | O_BINARY | O_CREAT | O_TRUNC 645 , 0666); 646 647 if (handle == -1) 648 Sys_Error ("Error opening %s: %s", path,strerror(errno)); 649 650 return handle; 651} 652 653void Sys_FileClose (int handle) 654{ 655 close (handle); 656} 657 658void Sys_FileSeek (int handle, int position) 659{ 660 lseek (handle, position, SEEK_SET); 661} 662 663int Sys_FileRead (int handle, void *dest, int count) 664{ 665 return read (handle, dest, count); 666} 667 668int Sys_FileWrite (int handle, void *data, int count) 669{ 670 return write (handle, data, count); 671} 672 673/* 674================ 675Sys_MakeCodeWriteable 676================ 677*/ 678void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) 679{ 680 // it's always writeable 681} 682 683 684/* 685================ 686Sys_FloatTime 687================ 688*/ 689double Sys_FloatTime (void) 690{ 691 int r; 692 unsigned t, tick; 693 double ft, time; 694 static int sametimecount; 695 696 Sys_PushFPCW_SetHigh (); 697 698//{static float t = 0; t=t+0.05; return t;} // DEBUG 699 700 t = *(unsigned short*)real2ptr(0x46c) * 65536; 701 702 dos_outportb(0x43, 0); // latch time 703 r = dos_inportb(0x40); 704 r |= dos_inportb(0x40) << 8; 705 r = (r-1) & 0xffff; 706 707 tick = *(unsigned short*)real2ptr(0x46c) * 65536; 708 if ((tick != t) && (r & 0x8000)) 709 t = tick; 710 711 ft = (double) (t+(65536-r)) / 1193200.0; 712 time = ft - oldtime; 713 oldtime = ft; 714 715 if (time < 0) 716 { 717 if (time > -3000.0) 718 time = 0.0; 719 else 720 time += 3600.0; 721 } 722 723 curtime += time; 724 725 if (curtime == lastcurtime) 726 { 727 sametimecount++; 728 729 if (sametimecount > 100000) 730 { 731 curtime += 1.0; 732 sametimecount = 0; 733 } 734 } 735 else 736 { 737 sametimecount = 0; 738 } 739 740 lastcurtime = curtime; 741 742 Sys_PopFPCW (); 743 744 return curtime; 745} 746 747 748/* 749================ 750Sys_InitFloatTime 751================ 752*/ 753void Sys_InitFloatTime (void) 754{ 755 int j; 756 757 Sys_FloatTime (); 758 759 oldtime = curtime; 760 761 j = COM_CheckParm("-starttime"); 762 763 if (j) 764 { 765 curtime = (double) (Q_atof(com_argv[j+1])); 766 } 767 else 768 { 769 curtime = 0.0; 770 } 771 lastcurtime = curtime; 772} 773 774 775/* 776================ 777Sys_GetMemory 778================ 779*/ 780void Sys_GetMemory(void) 781{ 782 int j, tsize; 783 784 j = COM_CheckParm("-mem"); 785 if (j) 786 { 787 quakeparms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024); 788 quakeparms.membase = malloc (quakeparms.memsize); 789 } 790 else 791 { 792 quakeparms.membase = dos_getmaxlockedmem (&quakeparms.memsize); 793 } 794 795 fprintf(stderr, "malloc'd: %d\n", quakeparms.memsize); 796 797 if (COM_CheckParm ("-heapsize")) 798 { 799 tsize = Q_atoi (com_argv[COM_CheckParm("-heapsize") + 1]) * 1024; 800 801 if (tsize < quakeparms.memsize) 802 quakeparms.memsize = tsize; 803 } 804} 805 806 807/* 808================ 809Sys_PageInProgram 810 811walks the text, data, and bss to make sure it's all paged in so that the 812actual physical memory detected by Sys_GetMemory is correct. 813================ 814*/ 815void Sys_PageInProgram(void) 816{ 817 int i, j; 818 819 end_of_memory = (int)sbrk(0); 820 821 if (lockmem) 822 { 823 if (dos_lockmem ((void *)&start_of_memory, 824 end_of_memory - (int)&start_of_memory)) 825 Sys_Error ("Couldn't lock text and data"); 826 } 827 828 if (lockunlockmem) 829 { 830 dos_unlockmem((void *)&start_of_memory, 831 end_of_memory - (int)&start_of_memory); 832 printf ("Locked and unlocked %d Mb image\n", 833 (end_of_memory - (int)&start_of_memory) / 0x100000); 834 } 835 else if (lockmem) 836 { 837 printf ("Locked %d Mb image\n", 838 (end_of_memory - (int)&start_of_memory) / 0x100000); 839 } 840 else 841 { 842 printf ("Loaded %d Mb image\n", 843 (end_of_memory - (int)&start_of_memory) / 0x100000); 844 } 845 846// touch the entire image, doing the 16-page skip so Win95 doesn't think we're 847// trying to page ourselves in 848 for (j=0 ; j<4 ; j++) 849 { 850 for(i=(int)&start_of_memory ; i<(end_of_memory - 16 * 0x1000) ; i += 4) 851 { 852 sys_checksum += *(int *)i; 853 sys_checksum += *(int *)(i + 16 * 0x1000); 854 } 855 } 856} 857 858 859/* 860================ 861Sys_NoFPUExceptionHandler 862================ 863*/ 864void Sys_NoFPUExceptionHandler(int whatever) 865{ 866 printf ("\nError: Quake requires a floating-point processor\n"); 867 exit (0); 868} 869 870 871/* 872================ 873Sys_DefaultExceptionHandler 874================ 875*/ 876void Sys_DefaultExceptionHandler(int whatever) 877{ 878} 879 880 881/* 882================ 883main 884================ 885*/ 886int main (int c, char **v) 887{ 888 double time, oldtime, newtime; 889 extern void (*dos_error_func)(char *, ...); 890 static char cwd[1024]; 891 892 printf ("Quake v%4.2f\n", VERSION); 893 894// make sure there's an FPU 895 signal(SIGNOFP, Sys_NoFPUExceptionHandler); 896 signal(SIGABRT, Sys_DefaultExceptionHandler); 897 signal(SIGALRM, Sys_DefaultExceptionHandler); 898 signal(SIGKILL, Sys_DefaultExceptionHandler); 899 signal(SIGQUIT, Sys_DefaultExceptionHandler); 900 signal(SIGINT, Sys_DefaultExceptionHandler); 901 902 if (fptest_temp >= 0.0) 903 fptest_temp += 0.1; 904 905 COM_InitArgv (c, v); 906 907 quakeparms.argc = com_argc; 908 quakeparms.argv = com_argv; 909 910 dos_error_func = Sys_Error; 911 912 Sys_DetectWin95 (); 913 Sys_PageInProgram (); 914 Sys_GetMemory (); 915 916 atexit (Sys_AtExit); // in case we crash 917 918 getwd (cwd); 919 if (cwd[Q_strlen(cwd)-1] == '/') cwd[Q_strlen(cwd)-1] = 0; 920 quakeparms.basedir = cwd; //"f:/quake"; 921 922 isDedicated = (COM_CheckParm ("-dedicated") != 0); 923 924 Sys_Init (); 925 926 if (!isDedicated) 927 dos_registerintr(9, TrapKey); 928 929//Sys_InitStackCheck (); 930 931 Host_Init(&quakeparms); 932 933//Sys_StackCheck (); 934 935//Con_Printf ("Top of stack: 0x%x\n", &time); 936 oldtime = Sys_FloatTime (); 937 while (1) 938 { 939 newtime = Sys_FloatTime (); 940 time = newtime - oldtime; 941 942 if (cls.state == ca_dedicated && (time<sys_ticrate.value)) 943 continue; 944 945 Host_Frame (time); 946 947//Sys_StackCheck (); 948 949 oldtime = newtime; 950 } 951} 952 953 954