home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 113 / EnigmaAmiga113CD.iso / software / sviluppo / quake_src / sys_dos.c < prev    next >
C/C++ Source or Header  |  2000-06-17  |  21KB  |  954 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, 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.  
  44. int     end_of_memory;
  45. qboolean  lockmem, lockunlockmem, unlockmem;
  46. static int  win95;
  47.  
  48. #define STDOUT  1
  49.  
  50. #define KEYBUF_SIZE 256
  51. static unsigned char  keybuf[KEYBUF_SIZE];
  52. static int        keybuf_head=0;
  53. static int        keybuf_tail=0;
  54.  
  55. static quakeparms_t quakeparms;
  56. int         sys_checksum;
  57. static double   curtime = 0.0;
  58. static double   lastcurtime = 0.0;
  59. static double   oldtime = 0.0;
  60.  
  61. static qboolean   isDedicated;
  62.  
  63. static int      minmem;
  64.  
  65. float       fptest_temp;
  66.  
  67. extern 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
  76. extern byte end;
  77. #define CHECKBYTE 0xed
  78. void Sys_InitStackCheck (void)
  79. {
  80.   int   i;
  81.   
  82.   for (i=0 ; i<128*1024 ; i++)
  83.     (&end)[i] = CHECKBYTE;
  84. }
  85.  
  86. void 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.  
  102. byte        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.  
  124. byte        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.  
  146. void 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.  
  168. void MaskExceptions (void);
  169. void Sys_InitFloatTime (void);
  170. void Sys_PushFPCW_SetHigh (void);
  171. void Sys_PopFPCW (void);
  172.  
  173. #define LEAVE_FOR_CACHE (512*1024)    //FIXME: tune
  174. #define LOCKED_FOR_MALLOC (128*1024)  //FIXME: tune
  175.  
  176.  
  177. void 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.  
  206. void *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.  
  331. Locked:
  332.  
  333. UpdateSbrk:
  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. ============
  381. Sys_FileTime
  382.  
  383. returns -1 if not present
  384. ============
  385. */
  386. int 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.  
  396. void Sys_mkdir (char *path)
  397. {
  398.   mkdir (path, 0777);
  399. }
  400.  
  401.  
  402. void Sys_Sleep(void)
  403. {
  404. }
  405.  
  406.  
  407. char *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.  
  451. void 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.  
  468. void 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 
  484. void 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. ================
  538. Sys_Printf
  539. ================
  540. */
  541.  
  542. void 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.  
  555. void 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.  
  565. void 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.  
  606. void Sys_Error (char *error, ...)
  607.     va_list     argptr;
  608.     char        string[1024];
  609.     
  610.     va_start (argptr,error);
  611.     vsprintf (string,error,argptr);
  612.     va_end (argptr);
  613.  
  614.   Host_Shutdown();
  615.   fprintf(stderr, "Error: %s\n", string);
  616. // Sys_AtExit is called by exit to shutdown the system
  617.   exit(0);
  618.  
  619.  
  620. int Sys_FileOpenRead (char *path, int *handle)
  621. {
  622.   int h;
  623.   struct stat fileinfo;
  624.     
  625.   h = open (path, O_RDONLY|O_BINARY, 0666);
  626.   *handle = h;
  627.   if (h == -1)
  628.     return -1;
  629.   
  630.   if (fstat (h,&fileinfo) == -1)
  631.     Sys_Error ("Error fstating %s", path);
  632.  
  633.   return fileinfo.st_size;
  634. }
  635.  
  636. int Sys_FileOpenWrite (char *path)
  637. {
  638.   int     handle;
  639.  
  640.   umask (0);
  641.   
  642.   handle = open(path,O_RDWR | O_BINARY | O_CREAT | O_TRUNC
  643.   , 0666);
  644.  
  645.   if (handle == -1)
  646.     Sys_Error ("Error opening %s: %s", path,strerror(errno));
  647.  
  648.   return handle;
  649. }
  650.  
  651. void Sys_FileClose (int handle)
  652. {
  653.   close (handle);
  654. }
  655.  
  656. void Sys_FileSeek (int handle, int position)
  657. {
  658.   lseek (handle, position, SEEK_SET);
  659. }
  660.  
  661. int Sys_FileRead (int handle, void *dest, int count)
  662. {
  663.    return read (handle, dest, count);
  664. }
  665.  
  666. int Sys_FileWrite (int handle, void *data, int count)
  667. {
  668.   return write (handle, data, count);
  669. }
  670.  
  671. /*
  672. ================
  673. Sys_MakeCodeWriteable
  674. ================
  675. */
  676. void Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length)
  677. {
  678.   // it's always writeable
  679. }
  680.  
  681.  
  682. /*
  683. ================
  684. Sys_FloatTime
  685. ================
  686. */
  687. double Sys_FloatTime (void)
  688. {
  689.     int       r;
  690.     unsigned    t, tick;
  691.   double      ft, time;
  692.   static int    sametimecount;
  693.  
  694.   Sys_PushFPCW_SetHigh ();
  695.  
  696. //{static float t = 0; t=t+0.05; return t;} // DEBUG
  697.  
  698.     t = *(unsigned short*)real2ptr(0x46c) * 65536;
  699.  
  700.     dos_outportb(0x43, 0); // latch time
  701.     r = dos_inportb(0x40);
  702.     r |= dos_inportb(0x40) << 8;
  703.     r = (r-1) & 0xffff;
  704.  
  705.     tick = *(unsigned short*)real2ptr(0x46c) * 65536;
  706.     if ((tick != t) && (r & 0x8000))
  707.     t = tick;
  708.  
  709.   ft = (double) (t+(65536-r)) / 1193200.0;
  710.   time = ft - oldtime;
  711.   oldtime = ft;
  712.  
  713.   if (time < 0)
  714.   {
  715.     if (time > -3000.0)
  716.       time = 0.0;
  717.     else
  718.       time += 3600.0;
  719.   }
  720.  
  721.   curtime += time;
  722.  
  723.   if (curtime == lastcurtime)
  724.   {
  725.     sametimecount++;
  726.  
  727.     if (sametimecount > 100000)
  728.     {
  729.       curtime += 1.0;
  730.       sametimecount = 0;
  731.     }
  732.   }
  733.   else
  734.   {
  735.     sametimecount = 0;
  736.   }
  737.  
  738.   lastcurtime = curtime;
  739.  
  740.   Sys_PopFPCW ();
  741.  
  742.     return curtime;
  743. }
  744.  
  745.  
  746. /*
  747. ================
  748. Sys_InitFloatTime
  749. ================
  750. */
  751. void Sys_InitFloatTime (void)
  752. {
  753.   int   j;
  754.  
  755.   Sys_FloatTime ();
  756.  
  757.   oldtime = curtime;
  758.  
  759.   j = COM_CheckParm("-starttime");
  760.  
  761.   if (j)
  762.   {
  763.     curtime = (double) (Q_atof(com_argv[j+1]));
  764.   }
  765.   else
  766.   {
  767.     curtime = 0.0;
  768.   }
  769.   lastcurtime = curtime;
  770. }
  771.  
  772.  
  773. /*
  774. ================
  775. Sys_GetMemory
  776. ================
  777. */
  778. void Sys_GetMemory(void)
  779. {
  780.   int   j, tsize;
  781.  
  782.   j = COM_CheckParm("-mem");
  783.   if (j)
  784.   {
  785.     quakeparms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024);
  786.     quakeparms.membase = malloc (quakeparms.memsize);
  787.   }
  788.   else
  789.   {
  790.     quakeparms.membase = dos_getmaxlockedmem (&quakeparms.memsize);
  791.   }
  792.  
  793.   fprintf(stderr, "malloc'd: %d\n", quakeparms.memsize);
  794.  
  795.   if (COM_CheckParm ("-heapsize"))
  796.   {
  797.     tsize = Q_atoi (com_argv[COM_CheckParm("-heapsize") + 1]) * 1024;
  798.  
  799.     if (tsize < quakeparms.memsize)
  800.       quakeparms.memsize = tsize;
  801.   }
  802. }
  803.  
  804.  
  805. /*
  806. ================
  807. Sys_PageInProgram
  808.  
  809. walks the text, data, and bss to make sure it's all paged in so that the
  810. actual physical memory detected by Sys_GetMemory is correct.
  811. ================
  812. */
  813. void Sys_PageInProgram(void)
  814. {
  815.   int   i, j;
  816.  
  817.   end_of_memory = (int)sbrk(0);
  818.  
  819.   if (lockmem)
  820.   {
  821.     if (dos_lockmem ((void *)&start_of_memory,
  822.              end_of_memory - (int)&start_of_memory))
  823.       Sys_Error ("Couldn't lock text and data");
  824.   }
  825.  
  826.   if (lockunlockmem)
  827.   {
  828.     dos_unlockmem((void *)&start_of_memory,
  829.              end_of_memory - (int)&start_of_memory);
  830.     printf ("Locked and unlocked %d Mb image\n",
  831.         (end_of_memory - (int)&start_of_memory) / 0x100000);
  832.   }
  833.   else if (lockmem)
  834.   {
  835.     printf ("Locked %d Mb image\n",
  836.         (end_of_memory - (int)&start_of_memory) / 0x100000);
  837.   }
  838.   else
  839.   {
  840.     printf ("Loaded %d Mb image\n",
  841.         (end_of_memory - (int)&start_of_memory) / 0x100000);
  842.   }
  843.  
  844. // touch the entire image, doing the 16-page skip so Win95 doesn't think we're
  845. // trying to page ourselves in
  846.   for (j=0 ; j<4 ; j++)
  847.   {
  848.     for(i=(int)&start_of_memory ; i<(end_of_memory - 16 * 0x1000) ; i += 4)
  849.     {
  850.       sys_checksum += *(int *)i;
  851.       sys_checksum += *(int *)(i + 16 * 0x1000);
  852.     }
  853.   }
  854. }
  855.  
  856.  
  857. /*
  858. ================
  859. Sys_NoFPUExceptionHandler
  860. ================
  861. */
  862. void Sys_NoFPUExceptionHandler(int whatever)
  863. {
  864.   printf ("\nError: Quake requires a floating-point processor\n");
  865.   exit (0);
  866. }
  867.  
  868.  
  869. /*
  870. ================
  871. Sys_DefaultExceptionHandler
  872. ================
  873. */
  874. void Sys_DefaultExceptionHandler(int whatever)
  875. {
  876. }
  877.  
  878.  
  879. /*
  880. ================
  881. main
  882. ================
  883. */
  884. int main (int c, char **v)
  885. {
  886.   double      time, oldtime, newtime;
  887.   extern void (*dos_error_func)(char *, ...);
  888.   static  char  cwd[1024];
  889.  
  890.   printf ("Quake v%4.2f\n", VERSION);
  891.   
  892. // make sure there's an FPU
  893.   signal(SIGNOFP, Sys_NoFPUExceptionHandler);
  894.   signal(SIGABRT, Sys_DefaultExceptionHandler);
  895.   signal(SIGALRM, Sys_DefaultExceptionHandler);
  896.   signal(SIGKILL, Sys_DefaultExceptionHandler);
  897.   signal(SIGQUIT, Sys_DefaultExceptionHandler);
  898.   signal(SIGINT, Sys_DefaultExceptionHandler);
  899.  
  900.   if (fptest_temp >= 0.0)
  901.     fptest_temp += 0.1;
  902.  
  903.   COM_InitArgv (c, v);
  904.  
  905.   quakeparms.argc = com_argc;
  906.   quakeparms.argv = com_argv;
  907.  
  908.   dos_error_func = Sys_Error;
  909.  
  910.   Sys_DetectWin95 ();
  911.   Sys_PageInProgram ();
  912.   Sys_GetMemory ();
  913.  
  914.   atexit (Sys_AtExit);  // in case we crash
  915.  
  916.   getwd (cwd);
  917.   if (cwd[Q_strlen(cwd)-1] == '/') cwd[Q_strlen(cwd)-1] = 0;
  918.   quakeparms.basedir = cwd; //"f:/quake";
  919.  
  920.   isDedicated = (COM_CheckParm ("-dedicated") != 0);
  921.  
  922.   Sys_Init ();
  923.  
  924.   if (!isDedicated)
  925.     dos_registerintr(9, TrapKey);
  926.  
  927. //Sys_InitStackCheck ();
  928.   
  929.   Host_Init(&quakeparms);
  930.  
  931. //Sys_StackCheck ();
  932.  
  933. //Con_Printf ("Top of stack: 0x%x\n", &time);
  934.   oldtime = Sys_FloatTime ();
  935.   while (1)
  936.   {
  937.     newtime = Sys_FloatTime ();
  938.     time = newtime - oldtime;
  939.  
  940.     if (cls.state == ca_dedicated && (time<sys_ticrate.value))
  941.       continue;
  942.  
  943.     Host_Frame (time);
  944.  
  945. //Sys_StackCheck ();
  946.  
  947.     oldtime = newtime;
  948.   }
  949. }
  950.  
  951.  
  952.