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