/* | |
Copyright (C) 1996-1997 Id Software, Inc. | |
This program is free software; you can redistribute it and/or | |
modify it under the terms of the GNU General Public License | |
as published by the Free Software Foundation; either version 2 | |
of the License, or (at your option) any later version. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
See the GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program; if not, write to the Free Software | |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
*/ | |
#include <errno.h> | |
#include <unistd.h> | |
#include <signal.h> | |
#include <stdlib.h> | |
#include <limits.h> | |
#include <sys/time.h> | |
#include <sys/types.h> | |
#include <dir.h> | |
#include <unistd.h> | |
#include <fcntl.h> | |
#include <stdarg.h> | |
#include <stdio.h> | |
#include <sys/stat.h> | |
#include <string.h> | |
#include <dpmi.h> | |
#include <sys/nearptr.h> | |
#include <conio.h> | |
#include "quakedef.h" | |
#include "dosisms.h" | |
#define MINIMUM_WIN_MEMORY 0x800000 | |
#define MINIMUM_WIN_MEMORY_LEVELPAK (MINIMUM_WIN_MEMORY + 0x100000) | |
int end_of_memory; | |
qboolean lockmem, lockunlockmem, unlockmem; | |
static int win95; | |
#define STDOUT 1 | |
#define KEYBUF_SIZE 256 | |
static unsigned char keybuf[KEYBUF_SIZE]; | |
static int keybuf_head=0; | |
static int keybuf_tail=0; | |
static quakeparms_t quakeparms; | |
int sys_checksum; | |
static double curtime = 0.0; | |
static double lastcurtime = 0.0; | |
static double oldtime = 0.0; | |
static qboolean isDedicated; | |
static int minmem; | |
float fptest_temp; | |
extern char start_of_memory __asm__("start"); | |
//============================================================================= | |
// this is totally dependent on cwsdpmi putting the stack right after tge | |
// global data | |
// This does evil things in a Win95 DOS box!!! | |
#if 0 | |
extern byte end; | |
#define CHECKBYTE 0xed | |
void Sys_InitStackCheck (void) | |
{ | |
int i; | |
for (i=0 ; i<128*1024 ; i++) | |
(&end)[i] = CHECKBYTE; | |
} | |
void Sys_StackCheck (void) | |
{ | |
int i; | |
for (i=0 ; i<128*1024 ; i++) | |
if ( (&end)[i] != CHECKBYTE ) | |
break; | |
Con_Printf ("%i undisturbed stack bytes\n", i); | |
if (end != CHECKBYTE) | |
Sys_Error ("System stack overflow!"); | |
} | |
#endif | |
//============================================================================= | |
byte scantokey[128] = | |
{ | |
// 0 1 2 3 4 5 6 7 | |
// 8 9 A B C D E F | |
0 , 27, '1', '2', '3', '4', '5', '6', | |
'7', '8', '9', '0', '-', '=', K_BACKSPACE, 9, // 0 | |
'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', | |
'o', 'p', '[', ']', 13 , K_CTRL,'a', 's', // 1 | |
'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', | |
'\'' , '`', K_SHIFT,'\\', 'z', 'x', 'c', 'v', // 2 | |
'b', 'n', 'm', ',', '.', '/', K_SHIFT,'*', | |
K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 | |
K_F6, K_F7, K_F8, K_F9, K_F10,0 , 0 , K_HOME, | |
K_UPARROW,K_PGUP,'-',K_LEFTARROW,'5',K_RIGHTARROW,'+',K_END, //4 | |
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, | |
K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 | |
}; | |
byte shiftscantokey[128] = | |
{ | |
// 0 1 2 3 4 5 6 7 | |
// 8 9 A B C D E F | |
0 , 27, '!', '@', '#', '$', '%', '^', | |
'&', '*', '(', ')', '_', '+', K_BACKSPACE, 9, // 0 | |
'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', | |
'O', 'P', '{', '}', 13 , K_CTRL,'A', 'S', // 1 | |
'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', | |
'"' , '~', K_SHIFT,'|', 'Z', 'X', 'C', 'V', // 2 | |
'B', 'N', 'M', '<', '>', '?', K_SHIFT,'*', | |
K_ALT,' ', 0 , K_F1, K_F2, K_F3, K_F4, K_F5, // 3 | |
K_F6, K_F7, K_F8, K_F9, K_F10,0 , 0 , K_HOME, | |
K_UPARROW,K_PGUP,'_',K_LEFTARROW,'%',K_RIGHTARROW,'+',K_END, //4 | |
K_DOWNARROW,K_PGDN,K_INS,K_DEL,0,0, 0, K_F11, | |
K_F12,0 , 0 , 0 , 0 , 0 , 0 , 0, // 5 | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, // 6 | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, | |
0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 // 7 | |
}; | |
void TrapKey(void) | |
{ | |
// static int ctrl=0; | |
keybuf[keybuf_head] = dos_inportb(0x60); | |
dos_outportb(0x20, 0x20); | |
/* | |
if (scantokey[keybuf[keybuf_head]&0x7f] == K_CTRL) | |
ctrl=keybuf[keybuf_head]&0x80; | |
if (ctrl && scantokey[keybuf[keybuf_head]&0x7f] == 'c') | |
Sys_Error("ctrl-c hit\n"); | |
*/ | |
keybuf_head = (keybuf_head + 1) & (KEYBUF_SIZE-1); | |
} | |
#define SC_UPARROW 0x48 | |
#define SC_DOWNARROW 0x50 | |
#define SC_LEFTARROW 0x4b | |
#define SC_RIGHTARROW 0x4d | |
#define SC_LEFTSHIFT 0x2a | |
#define SC_RIGHTSHIFT 0x36 | |
#define SC_RIGHTARROW 0x4d | |
void MaskExceptions (void); | |
void Sys_InitFloatTime (void); | |
void Sys_PushFPCW_SetHigh (void); | |
void Sys_PopFPCW (void); | |
#define LEAVE_FOR_CACHE (512*1024) //FIXME: tune | |
#define LOCKED_FOR_MALLOC (128*1024) //FIXME: tune | |
void Sys_DetectWin95 (void) | |
{ | |
__dpmi_regs r; | |
r.x.ax = 0x160a; /* Get Windows Version */ | |
__dpmi_int(0x2f, &r); | |
if(r.x.ax || r.h.bh < 4) /* Not windows or earlier than Win95 */ | |
{ | |
win95 = 0; | |
lockmem = true; | |
lockunlockmem = false; | |
unlockmem = true; | |
} | |
else | |
{ | |
win95 = 1; | |
lockunlockmem = COM_CheckParm ("-winlockunlock"); | |
if (lockunlockmem) | |
lockmem = true; | |
else | |
lockmem = COM_CheckParm ("-winlock"); | |
unlockmem = lockmem && !lockunlockmem; | |
} | |
} | |
void *dos_getmaxlockedmem(int *size) | |
{ | |
__dpmi_free_mem_info meminfo; | |
__dpmi_meminfo info; | |
int working_size; | |
void *working_memory; | |
int last_locked; | |
int extra, i, j, allocsize; | |
static char *msg = "Locking data..."; | |
int m, n; | |
byte *x; | |
// first lock all the current executing image so the locked count will | |
// be accurate. It doesn't hurt to lock the memory multiple times | |
last_locked = __djgpp_selector_limit + 1; | |
info.size = last_locked - 4096; | |
info.address = __djgpp_base_address + 4096; | |
if (lockmem) | |
{ | |
if(__dpmi_lock_linear_region(&info)) | |
{ | |
Sys_Error ("Lock of current memory at 0x%lx for %ldKb failed!\n", | |
info.address, info.size/1024); | |
} | |
} | |
__dpmi_get_free_memory_information(&meminfo); | |
if (!win95) /* Not windows or earlier than Win95 */ | |
{ | |
working_size = meminfo.maximum_locked_page_allocation_in_pages * 4096; | |
} | |
else | |
{ | |
working_size = meminfo.largest_available_free_block_in_bytes - | |
LEAVE_FOR_CACHE; | |
} | |
working_size &= ~0xffff; /* Round down to 64K */ | |
working_size += 0x10000; | |
do | |
{ | |
working_size -= 0x10000; /* Decrease 64K and try again */ | |
working_memory = sbrk(working_size); | |
} while (working_memory == (void *)-1); | |
extra = 0xfffc - ((unsigned)sbrk(0) & 0xffff); | |
if (extra > 0) | |
{ | |
sbrk(extra); | |
working_size += extra; | |
} | |
// now grab the memory | |
info.address = last_locked + __djgpp_base_address; | |
if (!win95) | |
{ | |
info.size = __djgpp_selector_limit + 1 - last_locked; | |
while (info.size > 0 && __dpmi_lock_linear_region(&info)) | |
{ | |
info.size -= 0x1000; | |
working_size -= 0x1000; | |
sbrk(-0x1000); | |
} | |
} | |
else | |
{ /* Win95 section */ | |
j = COM_CheckParm("-winmem"); | |
if (standard_quake) | |
minmem = MINIMUM_WIN_MEMORY; | |
else | |
minmem = MINIMUM_WIN_MEMORY_LEVELPAK; | |
if (j) | |
{ | |
allocsize = ((int)(Q_atoi(com_argv[j+1]))) * 0x100000 + | |
LOCKED_FOR_MALLOC; | |
if (allocsize < (minmem + LOCKED_FOR_MALLOC)) | |
allocsize = minmem + LOCKED_FOR_MALLOC; | |
} | |
else | |
{ | |
allocsize = minmem + LOCKED_FOR_MALLOC; | |
} | |
if (!lockmem) | |
{ | |
// we won't lock, just sbrk the memory | |
info.size = allocsize; | |
goto UpdateSbrk; | |
} | |
// lock the memory down | |
write (STDOUT, msg, strlen (msg)); | |
for (j=allocsize ; j>(minmem + LOCKED_FOR_MALLOC) ; | |
j -= 0x100000) | |
{ | |
info.size = j; | |
if (!__dpmi_lock_linear_region(&info)) | |
goto Locked; | |
write (STDOUT, ".", 1); | |
} | |
// finally, try with the absolute minimum amount | |
for (i=0 ; i<10 ; i++) | |
{ | |
info.size = minmem + LOCKED_FOR_MALLOC; | |
if (!__dpmi_lock_linear_region(&info)) | |
goto Locked; | |
} | |
Sys_Error ("Can't lock memory; %d Mb lockable RAM required. " | |
"Try shrinking smartdrv.", info.size / 0x100000); | |
Locked: | |
UpdateSbrk: | |
info.address += info.size; | |
info.address -= __djgpp_base_address + 4; // ending point, malloc align | |
working_size = info.address - (int)working_memory; | |
sbrk(info.address-(int)sbrk(0)); // negative adjustment | |
} | |
if (lockunlockmem) | |
{ | |
__dpmi_unlock_linear_region (&info); | |
printf ("Locked and unlocked %d Mb data\n", working_size / 0x100000); | |
} | |
else if (lockmem) | |
{ | |
printf ("Locked %d Mb data\n", working_size / 0x100000); | |
} | |
else | |
{ | |
printf ("Allocated %d Mb data\n", working_size / 0x100000); | |
} | |
// touch all the memory to make sure it's there. The 16-page skip is to | |
// keep Win 95 from thinking we're trying to page ourselves in (we are | |
// doing that, of course, but there's no reason we shouldn't) | |
x = (byte *)working_memory; | |
for (n=0 ; n<4 ; n++) | |
{ | |
for (m=0 ; m<(working_size - 16 * 0x1000) ; m += 4) | |
{ | |
sys_checksum += *(int *)&x[m]; | |
sys_checksum += *(int *)&x[m + 16 * 0x1000]; | |
} | |
} | |
// give some of what we locked back for malloc before returning. Done | |
// by cheating and passing a negative value to sbrk | |
working_size -= LOCKED_FOR_MALLOC; | |
sbrk( -(LOCKED_FOR_MALLOC)); | |
*size = working_size; | |
return working_memory; | |
} | |
/* | |
============ | |
Sys_FileTime | |
returns -1 if not present | |
============ | |
*/ | |
int Sys_FileTime (char *path) | |
{ | |
struct stat buf; | |
if (stat (path,&buf) == -1) | |
return -1; | |
return buf.st_mtime; | |
} | |
void Sys_mkdir (char *path) | |
{ | |
mkdir (path, 0777); | |
} | |
void Sys_Sleep(void) | |
{ | |
} | |
char *Sys_ConsoleInput(void) | |
{ | |
static char text[256]; | |
static int len = 0; | |
char ch; | |
if (!isDedicated) | |
return NULL; | |
if (! kbhit()) | |
return NULL; | |
ch = getche(); | |
switch (ch) | |
{ | |
case '\r': | |
putch('\n'); | |
if (len) | |
{ | |
text[len] = 0; | |
len = 0; | |
return text; | |
} | |
break; | |
case '\b': | |
putch(' '); | |
if (len) | |
{ | |
len--; | |
putch('\b'); | |
} | |
break; | |
default: | |
text[len] = ch; | |
len = (len + 1) & 0xff; | |
break; | |
} | |
return NULL; | |
} | |
void Sys_Init(void) | |
{ | |
MaskExceptions (); | |
Sys_SetFPCW (); | |
dos_outportb(0x43, 0x34); // set system timer to mode 2 | |
dos_outportb(0x40, 0); // for the Sys_FloatTime() function | |
dos_outportb(0x40, 0); | |
Sys_InitFloatTime (); | |
_go32_interrupt_stack_size = 4 * 1024;; | |
_go32_rmcb_stack_size = 4 * 1024; | |
} | |
void Sys_Shutdown(void) | |
{ | |
if (!isDedicated) | |
dos_restoreintr(9); | |
if (unlockmem) | |
{ | |
dos_unlockmem (&start_of_memory, | |
end_of_memory - (int)&start_of_memory); | |
dos_unlockmem (quakeparms.membase, quakeparms.memsize); | |
} | |
} | |
#define SC_RSHIFT 0x36 | |
#define SC_LSHIFT 0x2a | |
void Sys_SendKeyEvents (void) | |
{ | |
int k, next; | |
int outkey; | |
// get key events | |
while (keybuf_head != keybuf_tail) | |
{ | |
k = keybuf[keybuf_tail++]; | |
keybuf_tail &= (KEYBUF_SIZE-1); | |
if (k==0xe0) | |
continue; // special / pause keys | |
next = keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)]; | |
if (next == 0xe1) | |
continue; // pause key bullshit | |
if (k==0xc5 && next == 0x9d) | |
{ | |
Key_Event (K_PAUSE, true); | |
continue; | |
} | |
// extended keyboard shift key bullshit | |
if ( (k&0x7f)==SC_LSHIFT || (k&0x7f)==SC_RSHIFT ) | |
{ | |
if ( keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)]==0xe0 ) | |
continue; | |
k &= 0x80; | |
k |= SC_RSHIFT; | |
} | |
if (k==0xc5 && keybuf[(keybuf_tail-2)&(KEYBUF_SIZE-1)] == 0x9d) | |
continue; // more pause bullshit | |
outkey = scantokey[k & 0x7f]; | |
if (k & 0x80) | |
Key_Event (outkey, false); | |
else | |
Key_Event (outkey, true); | |
} | |
} | |
// ======================================================================= | |
// General routines | |
// ======================================================================= | |
/* | |
================ | |
Sys_Printf | |
================ | |
*/ | |
void Sys_Printf (char *fmt, ...) | |
{ | |
va_list argptr; | |
char text[1024]; | |
va_start (argptr,fmt); | |
vsprintf (text,fmt,argptr); | |
va_end (argptr); | |
if (cls.state == ca_dedicated) | |
fprintf(stderr, "%s", text); | |
} | |
void Sys_AtExit (void) | |
{ | |
// shutdown only once (so Sys_Error can call this function to shutdown, then | |
// print the error message, then call exit without exit calling this function | |
// again) | |
Sys_Shutdown(); | |
} | |
void Sys_Quit (void) | |
{ | |
byte screen[80*25*2]; | |
byte *d; | |
char ver[6]; | |
int i; | |
// load the sell screen before shuting everything down | |
if (registered.value) | |
d = COM_LoadHunkFile ("end2.bin"); | |
else | |
d = COM_LoadHunkFile ("end1.bin"); | |
if (d) | |
memcpy (screen, d, sizeof(screen)); | |
// write the version number directly to the end screen | |
sprintf (ver, " v%4.2f", VERSION); | |
for (i=0 ; i<6 ; i++) | |
screen[0*80*2 + 72*2 + i*2] = ver[i]; | |
Host_Shutdown(); | |
// do the text mode sell screen | |
if (d) | |
{ | |
memcpy ((void *)real2ptr(0xb8000), screen,80*25*2); | |
// set text pos | |
regs.x.ax = 0x0200; | |
regs.h.bh = 0; | |
regs.h.dl = 0; | |
regs.h.dh = 22; | |
dos_int86 (0x10); | |
} | |
else | |
printf ("couldn't load endscreen.\n"); | |
exit(0); | |
} | |
void Sys_Error (char *error, ...) | |
{ | |
va_list argptr; | |
char string[1024]; | |
va_start (argptr,error); | |
vsprintf (string,error,argptr); | |
va_end (argptr); | |
Host_Shutdown(); | |
fprintf(stderr, "Error: %s\n", string); | |
// Sys_AtExit is called by exit to shutdown the system | |
exit(0); | |
} | |
int Sys_FileOpenRead (char *path, int *handle) | |
{ | |
int h; | |
struct stat fileinfo; | |
h = open (path, O_RDONLY|O_BINARY, 0666); | |
*handle = h; | |
if (h == -1) | |
return -1; | |
if (fstat (h,&fileinfo) == -1) | |
Sys_Error ("Error fstating %s", path); | |
return fileinfo.st_size; | |
} | |
int Sys_FileOpenWrite (char *path) | |
{ | |
int handle; | |
umask (0); | |
handle = open(path,O_RDWR | O_BINARY | O_CREAT | O_TRUNC | |
, 0666); | |
if (handle == -1) | |
Sys_Error ("Error opening %s: %s", path,strerror(errno)); | |
return handle; | |
} | |
void Sys_FileClose (int handle) | |
{ | |
close (handle); | |
} | |
void Sys_FileSeek (int handle, int position) | |
{ | |
lseek (handle, position, SEEK_SET); | |
} | |
int Sys_FileRead (int handle, void *dest, int count) | |
{ | |
return read (handle, dest, count); | |
} | |
int Sys_FileWrite (int handle, void *data, int count) | |
{ | |
return write (handle, data, count); | |
} | |
/* | |
================ | |
Sys_MakeCodeWriteable | |
================ | |
*/ | |
void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length) | |
{ | |
// it's always writeable | |
} | |
/* | |
================ | |
Sys_FloatTime | |
================ | |
*/ | |
double Sys_FloatTime (void) | |
{ | |
int r; | |
unsigned t, tick; | |
double ft, time; | |
static int sametimecount; | |
Sys_PushFPCW_SetHigh (); | |
//{static float t = 0; t=t+0.05; return t;} // DEBUG | |
t = *(unsigned short*)real2ptr(0x46c) * 65536; | |
dos_outportb(0x43, 0); // latch time | |
r = dos_inportb(0x40); | |
r |= dos_inportb(0x40) << 8; | |
r = (r-1) & 0xffff; | |
tick = *(unsigned short*)real2ptr(0x46c) * 65536; | |
if ((tick != t) && (r & 0x8000)) | |
t = tick; | |
ft = (double) (t+(65536-r)) / 1193200.0; | |
time = ft - oldtime; | |
oldtime = ft; | |
if (time < 0) | |
{ | |
if (time > -3000.0) | |
time = 0.0; | |
else | |
time += 3600.0; | |
} | |
curtime += time; | |
if (curtime == lastcurtime) | |
{ | |
sametimecount++; | |
if (sametimecount > 100000) | |
{ | |
curtime += 1.0; | |
sametimecount = 0; | |
} | |
} | |
else | |
{ | |
sametimecount = 0; | |
} | |
lastcurtime = curtime; | |
Sys_PopFPCW (); | |
return curtime; | |
} | |
/* | |
================ | |
Sys_InitFloatTime | |
================ | |
*/ | |
void Sys_InitFloatTime (void) | |
{ | |
int j; | |
Sys_FloatTime (); | |
oldtime = curtime; | |
j = COM_CheckParm("-starttime"); | |
if (j) | |
{ | |
curtime = (double) (Q_atof(com_argv[j+1])); | |
} | |
else | |
{ | |
curtime = 0.0; | |
} | |
lastcurtime = curtime; | |
} | |
/* | |
================ | |
Sys_GetMemory | |
================ | |
*/ | |
void Sys_GetMemory(void) | |
{ | |
int j, tsize; | |
j = COM_CheckParm("-mem"); | |
if (j) | |
{ | |
quakeparms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024); | |
quakeparms.membase = malloc (quakeparms.memsize); | |
} | |
else | |
{ | |
quakeparms.membase = dos_getmaxlockedmem (&quakeparms.memsize); | |
} | |
fprintf(stderr, "malloc'd: %d\n", quakeparms.memsize); | |
if (COM_CheckParm ("-heapsize")) | |
{ | |
tsize = Q_atoi (com_argv[COM_CheckParm("-heapsize") + 1]) * 1024; | |
if (tsize < quakeparms.memsize) | |
quakeparms.memsize = tsize; | |
} | |
} | |
/* | |
================ | |
Sys_PageInProgram | |
walks the text, data, and bss to make sure it's all paged in so that the | |
actual physical memory detected by Sys_GetMemory is correct. | |
================ | |
*/ | |
void Sys_PageInProgram(void) | |
{ | |
int i, j; | |
end_of_memory = (int)sbrk(0); | |
if (lockmem) | |
{ | |
if (dos_lockmem ((void *)&start_of_memory, | |
end_of_memory - (int)&start_of_memory)) | |
Sys_Error ("Couldn't lock text and data"); | |
} | |
if (lockunlockmem) | |
{ | |
dos_unlockmem((void *)&start_of_memory, | |
end_of_memory - (int)&start_of_memory); | |
printf ("Locked and unlocked %d Mb image\n", | |
(end_of_memory - (int)&start_of_memory) / 0x100000); | |
} | |
else if (lockmem) | |
{ | |
printf ("Locked %d Mb image\n", | |
(end_of_memory - (int)&start_of_memory) / 0x100000); | |
} | |
else | |
{ | |
printf ("Loaded %d Mb image\n", | |
(end_of_memory - (int)&start_of_memory) / 0x100000); | |
} | |
// touch the entire image, doing the 16-page skip so Win95 doesn't think we're | |
// trying to page ourselves in | |
for (j=0 ; j<4 ; j++) | |
{ | |
for(i=(int)&start_of_memory ; i<(end_of_memory - 16 * 0x1000) ; i += 4) | |
{ | |
sys_checksum += *(int *)i; | |
sys_checksum += *(int *)(i + 16 * 0x1000); | |
} | |
} | |
} | |
/* | |
================ | |
Sys_NoFPUExceptionHandler | |
================ | |
*/ | |
void Sys_NoFPUExceptionHandler(int whatever) | |
{ | |
printf ("\nError: Quake requires a floating-point processor\n"); | |
exit (0); | |
} | |
/* | |
================ | |
Sys_DefaultExceptionHandler | |
================ | |
*/ | |
void Sys_DefaultExceptionHandler(int whatever) | |
{ | |
} | |
/* | |
================ | |
main | |
================ | |
*/ | |
int main (int c, char **v) | |
{ | |
double time, oldtime, newtime; | |
extern void (*dos_error_func)(char *, ...); | |
static char cwd[1024]; | |
printf ("Quake v%4.2f\n", VERSION); | |
// make sure there's an FPU | |
signal(SIGNOFP, Sys_NoFPUExceptionHandler); | |
signal(SIGABRT, Sys_DefaultExceptionHandler); | |
signal(SIGALRM, Sys_DefaultExceptionHandler); | |
signal(SIGKILL, Sys_DefaultExceptionHandler); | |
signal(SIGQUIT, Sys_DefaultExceptionHandler); | |
signal(SIGINT, Sys_DefaultExceptionHandler); | |
if (fptest_temp >= 0.0) | |
fptest_temp += 0.1; | |
COM_InitArgv (c, v); | |
quakeparms.argc = com_argc; | |
quakeparms.argv = com_argv; | |
dos_error_func = Sys_Error; | |
Sys_DetectWin95 (); | |
Sys_PageInProgram (); | |
Sys_GetMemory (); | |
atexit (Sys_AtExit); // in case we crash | |
getwd (cwd); | |
if (cwd[Q_strlen(cwd)-1] == '/') cwd[Q_strlen(cwd)-1] = 0; | |
quakeparms.basedir = cwd; //"f:/quake"; | |
isDedicated = (COM_CheckParm ("-dedicated") != 0); | |
Sys_Init (); | |
if (!isDedicated) | |
dos_registerintr(9, TrapKey); | |
//Sys_InitStackCheck (); | |
Host_Init(&quakeparms); | |
//Sys_StackCheck (); | |
//Con_Printf ("Top of stack: 0x%x\n", &time); | |
oldtime = Sys_FloatTime (); | |
while (1) | |
{ | |
newtime = Sys_FloatTime (); | |
time = newtime - oldtime; | |
if (cls.state == ca_dedicated && (time<sys_ticrate.value)) | |
continue; | |
Host_Frame (time); | |
//Sys_StackCheck (); | |
oldtime = newtime; | |
} | |
} | |