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 <sys/types.h> 21#include "qwsvdef.h" 22 23#ifdef NeXT 24#include <libc.h> 25#endif 26 27#if defined(__linux__) || defined(sun) 28#include <sys/stat.h> 29#include <unistd.h> 30#include <sys/time.h> 31#include <errno.h> 32#else 33#include <sys/dir.h> 34#endif 35 36cvar_t sys_nostdout = {"sys_nostdout","0"}; 37cvar_t sys_extrasleep = {"sys_extrasleep","0"}; 38 39qboolean stdin_ready; 40 41/* 42=============================================================================== 43 44 REQUIRED SYS FUNCTIONS 45 46=============================================================================== 47*/ 48 49/* 50============ 51Sys_FileTime 52 53returns -1 if not present 54============ 55*/ 56int Sys_FileTime (char *path) 57{ 58 struct stat buf; 59 60 if (stat (path,&buf) == -1) 61 return -1; 62 63 return buf.st_mtime; 64} 65 66 67/* 68============ 69Sys_mkdir 70 71============ 72*/ 73void Sys_mkdir (char *path) 74{ 75 if (mkdir (path, 0777) != -1) 76 return; 77 if (errno != EEXIST) 78 Sys_Error ("mkdir %s: %s",path, strerror(errno)); 79} 80 81 82/* 83================ 84Sys_DoubleTime 85================ 86*/ 87double Sys_DoubleTime (void) 88{ 89 struct timeval tp; 90 struct timezone tzp; 91 static int secbase; 92 93 gettimeofday(&tp, &tzp); 94 95 if (!secbase) 96 { 97 secbase = tp.tv_sec; 98 return tp.tv_usec/1000000.0; 99 } 100 101 return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; 102} 103 104/* 105================ 106Sys_Error 107================ 108*/ 109void Sys_Error (char *error, ...) 110{ 111 va_list argptr; 112 char string[1024]; 113 114 va_start (argptr,error); 115 vsprintf (string,error,argptr); 116 va_end (argptr); 117 printf ("Fatal error: %s\n",string); 118 119 exit (1); 120} 121 122/* 123================ 124Sys_Printf 125================ 126*/ 127void Sys_Printf (char *fmt, ...) 128{ 129 va_list argptr; 130 static char text[2048]; 131 unsigned char *p; 132 133 va_start (argptr,fmt); 134 vsprintf (text,fmt,argptr); 135 va_end (argptr); 136 137 if (strlen(text) > sizeof(text)) 138 Sys_Error("memory overwrite in Sys_Printf"); 139 140 if (sys_nostdout.value) 141 return; 142 143 for (p = (unsigned char *)text; *p; p++) { 144 *p &= 0x7f; 145 if ((*p > 128 || *p < 32) && *p != 10 && *p != 13 && *p != 9) 146 printf("[%02x]", *p); 147 else 148 putc(*p, stdout); 149 } 150 fflush(stdout); 151} 152 153 154/* 155================ 156Sys_Quit 157================ 158*/ 159void Sys_Quit (void) 160{ 161 exit (0); // appkit isn't running 162} 163 164static int do_stdin = 1; 165 166/* 167================ 168Sys_ConsoleInput 169 170Checks for a complete line of text typed in at the console, then forwards 171it to the host command processor 172================ 173*/ 174char *Sys_ConsoleInput (void) 175{ 176 static char text[256]; 177 int len; 178 179 if (!stdin_ready || !do_stdin) 180 return NULL; // the select didn't say it was ready 181 stdin_ready = false; 182 183 len = read (0, text, sizeof(text)); 184 if (len == 0) { 185 // end of file 186 do_stdin = 0; 187 return NULL; 188 } 189 if (len < 1) 190 return NULL; 191 text[len-1] = 0; // rip off the /n and terminate 192 193 return text; 194} 195 196/* 197============= 198Sys_Init 199 200Quake calls this so the system can register variables before host_hunklevel 201is marked 202============= 203*/ 204void Sys_Init (void) 205{ 206 Cvar_RegisterVariable (&sys_nostdout); 207 Cvar_RegisterVariable (&sys_extrasleep); 208} 209 210/* 211============= 212main 213============= 214*/ 215void main(int argc, char *argv[]) 216{ 217 double time, oldtime, newtime; 218 quakeparms_t parms; 219 fd_set fdset; 220 extern int net_socket; 221 struct timeval timeout; 222 int j; 223 224 memset (&parms, 0, sizeof(parms)); 225 226 COM_InitArgv (argc, argv); 227 parms.argc = com_argc; 228 parms.argv = com_argv; 229 230 parms.memsize = 16*1024*1024; 231 232 j = COM_CheckParm("-mem"); 233 if (j) 234 parms.memsize = (int) (Q_atof(com_argv[j+1]) * 1024 * 1024); 235 if ((parms.membase = malloc (parms.memsize)) == NULL) 236 Sys_Error("Can't allocate %ld\n", parms.memsize); 237 238 parms.basedir = "."; 239 240/* 241 if (Sys_FileTime ("id1/pak0.pak") != -1) 242 else 243 parms.basedir = "/raid/quake/v2"; 244*/ 245 246 SV_Init (&parms); 247 248// run one frame immediately for first heartbeat 249 SV_Frame (0.1); 250 251// 252// main loop 253// 254 oldtime = Sys_DoubleTime () - 0.1; 255 while (1) 256 { 257 // select on the net socket and stdin 258 // the only reason we have a timeout at all is so that if the last 259 // connected client times out, the message would not otherwise 260 // be printed until the next event. 261 FD_ZERO(&fdset); 262 if (do_stdin) 263 FD_SET(0, &fdset); 264 FD_SET(net_socket, &fdset); 265 timeout.tv_sec = 1; 266 timeout.tv_usec = 0; 267 if (select (net_socket+1, &fdset, NULL, NULL, &timeout) == -1) 268 continue; 269 stdin_ready = FD_ISSET(0, &fdset); 270 271 // find time passed since last cycle 272 newtime = Sys_DoubleTime (); 273 time = newtime - oldtime; 274 oldtime = newtime; 275 276 SV_Frame (time); 277 278 // extrasleep is just a way to generate a fucked up connection on purpose 279 if (sys_extrasleep.value) 280 usleep (sys_extrasleep.value); 281 } 282} 283 284