]> icculus.org git repositories - divverent/darkplaces.git/blob - common.c
reuse screenspace depth texture unit for orthographic shadowmaps so they can coexist...
[divverent/darkplaces.git] / common.c
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 // common.c -- misc functions used in client and server
21
22 #include "quakedef.h"
23
24 #include <stdlib.h>
25 #include <fcntl.h>
26 #ifndef WIN32
27 #include <unistd.h>
28 #endif
29
30 cvar_t registered = {0, "registered","0", "indicates if this is running registered quake (whether gfx/pop.lmp was found)"};
31 cvar_t cmdline = {0, "cmdline","0", "contains commandline the engine was launched with"};
32
33 char com_token[MAX_INPUTLINE];
34 int com_argc;
35 const char **com_argv;
36
37 gamemode_t gamemode;
38 const char *gamename;
39 const char *gamedirname1;
40 const char *gamedirname2;
41 const char *gamescreenshotname;
42 const char *gameuserdirname;
43 char com_modname[MAX_OSPATH] = "";
44
45
46 /*
47 ============================================================================
48
49                                         BYTE ORDER FUNCTIONS
50
51 ============================================================================
52 */
53
54
55 float BuffBigFloat (const unsigned char *buffer)
56 {
57         union
58         {
59                 float f;
60                 unsigned int i;
61         }
62         u;
63         u.i = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
64         return u.f;
65 }
66
67 int BuffBigLong (const unsigned char *buffer)
68 {
69         return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
70 }
71
72 short BuffBigShort (const unsigned char *buffer)
73 {
74         return (buffer[0] << 8) | buffer[1];
75 }
76
77 float BuffLittleFloat (const unsigned char *buffer)
78 {
79         union
80         {
81                 float f;
82                 unsigned int i;
83         }
84         u;
85         u.i = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
86         return u.f;
87 }
88
89 int BuffLittleLong (const unsigned char *buffer)
90 {
91         return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
92 }
93
94 short BuffLittleShort (const unsigned char *buffer)
95 {
96         return (buffer[1] << 8) | buffer[0];
97 }
98
99 void StoreBigLong (unsigned char *buffer, unsigned int i)
100 {
101         buffer[0] = (i >> 24) & 0xFF;
102         buffer[1] = (i >> 16) & 0xFF;
103         buffer[2] = (i >>  8) & 0xFF;
104         buffer[3] = i         & 0xFF;
105 }
106
107 void StoreBigShort (unsigned char *buffer, unsigned short i)
108 {
109         buffer[0] = (i >>  8) & 0xFF;
110         buffer[1] = i         & 0xFF;
111 }
112
113 void StoreLittleLong (unsigned char *buffer, unsigned int i)
114 {
115         buffer[0] = i         & 0xFF;
116         buffer[1] = (i >>  8) & 0xFF;
117         buffer[2] = (i >> 16) & 0xFF;
118         buffer[3] = (i >> 24) & 0xFF;
119 }
120
121 void StoreLittleShort (unsigned char *buffer, unsigned short i)
122 {
123         buffer[0] = i         & 0xFF;
124         buffer[1] = (i >>  8) & 0xFF;
125 }
126
127 /*
128 ============================================================================
129
130                                         CRC FUNCTIONS
131
132 ============================================================================
133 */
134
135 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
136 // and the initial and final xor values shown below...  in other words, the
137 // CCITT standard CRC used by XMODEM
138
139 #define CRC_INIT_VALUE  0xffff
140 #define CRC_XOR_VALUE   0x0000
141
142 static unsigned short crctable[256] =
143 {
144         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
145         0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
146         0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
147         0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
148         0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
149         0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
150         0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
151         0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
152         0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
153         0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
154         0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
155         0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
156         0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
157         0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
158         0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
159         0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
160         0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
161         0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
162         0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
163         0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
164         0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
165         0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
166         0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
167         0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
168         0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
169         0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
170         0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
171         0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
172         0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
173         0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
174         0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
175         0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
176 };
177
178 unsigned short CRC_Block(const unsigned char *data, size_t size)
179 {
180         unsigned short crc = CRC_INIT_VALUE;
181         while (size--)
182                 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)];
183         return crc ^ CRC_XOR_VALUE;
184 }
185
186 unsigned short CRC_Block_CaseInsensitive(const unsigned char *data, size_t size)
187 {
188         unsigned short crc = CRC_INIT_VALUE;
189         while (size--)
190                 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (tolower(*data++))];
191         return crc ^ CRC_XOR_VALUE;
192 }
193
194 // QuakeWorld
195 static unsigned char chktbl[1024 + 4] =
196 {
197         0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
198         0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
199         0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
200         0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
201         0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
202         0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
203         0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
204         0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
205         0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
206         0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
207         0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
208         0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
209         0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
210         0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
211         0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
212         0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
213         0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
214         0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
215         0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
216         0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
217         0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
218         0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
219         0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
220         0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
221         0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
222         0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
223         0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
224         0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
225         0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
226         0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
227         0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
228         0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
229
230         // map checksum goes here
231         0x00,0x00,0x00,0x00
232 };
233
234 // QuakeWorld
235 unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence)
236 {
237         unsigned char *p;
238         unsigned char chkb[60 + 4];
239
240         p = chktbl + (sequence % (sizeof(chktbl) - 8));
241
242         if (length > 60)
243                 length = 60;
244         memcpy(chkb, base, length);
245
246         chkb[length] = (sequence & 0xff) ^ p[0];
247         chkb[length+1] = p[1];
248         chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
249         chkb[length+3] = p[3];
250
251         return CRC_Block(chkb, length + 4) & 0xff;
252 }
253
254 /*
255 ==============================================================================
256
257                         MESSAGE IO FUNCTIONS
258
259 Handles byte ordering and avoids alignment errors
260 ==============================================================================
261 */
262
263 //
264 // writing functions
265 //
266
267 void MSG_WriteChar (sizebuf_t *sb, int c)
268 {
269         unsigned char    *buf;
270
271         buf = SZ_GetSpace (sb, 1);
272         buf[0] = c;
273 }
274
275 void MSG_WriteByte (sizebuf_t *sb, int c)
276 {
277         unsigned char    *buf;
278
279         buf = SZ_GetSpace (sb, 1);
280         buf[0] = c;
281 }
282
283 void MSG_WriteShort (sizebuf_t *sb, int c)
284 {
285         unsigned char    *buf;
286
287         buf = SZ_GetSpace (sb, 2);
288         buf[0] = c&0xff;
289         buf[1] = c>>8;
290 }
291
292 void MSG_WriteLong (sizebuf_t *sb, int c)
293 {
294         unsigned char    *buf;
295
296         buf = SZ_GetSpace (sb, 4);
297         buf[0] = c&0xff;
298         buf[1] = (c>>8)&0xff;
299         buf[2] = (c>>16)&0xff;
300         buf[3] = c>>24;
301 }
302
303 void MSG_WriteFloat (sizebuf_t *sb, float f)
304 {
305         union
306         {
307                 float   f;
308                 int     l;
309         } dat;
310
311
312         dat.f = f;
313         dat.l = LittleLong (dat.l);
314
315         SZ_Write (sb, (unsigned char *)&dat.l, 4);
316 }
317
318 void MSG_WriteString (sizebuf_t *sb, const char *s)
319 {
320         if (!s || !*s)
321                 MSG_WriteChar (sb, 0);
322         else
323                 SZ_Write (sb, (unsigned char *)s, (int)strlen(s)+1);
324 }
325
326 void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s)
327 {
328         if (s && *s)
329                 SZ_Write (sb, (unsigned char *)s, (int)strlen(s));
330 }
331
332 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
333 {
334         if (f >= 0)
335                 MSG_WriteShort (sb, (int)(f * 8.0 + 0.5));
336         else
337                 MSG_WriteShort (sb, (int)(f * 8.0 - 0.5));
338 }
339
340 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
341 {
342         if (f >= 0)
343                 MSG_WriteShort (sb, (int)(f + 0.5));
344         else
345                 MSG_WriteShort (sb, (int)(f - 0.5));
346 }
347
348 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
349 {
350         MSG_WriteFloat (sb, f);
351 }
352
353 void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol)
354 {
355         if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
356                 MSG_WriteCoord13i (sb, f);
357         else if (protocol == PROTOCOL_DARKPLACES1)
358                 MSG_WriteCoord32f (sb, f);
359         else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
360                 MSG_WriteCoord16i (sb, f);
361         else
362                 MSG_WriteCoord32f (sb, f);
363 }
364
365 void MSG_WriteVector (sizebuf_t *sb, float *v, protocolversion_t protocol)
366 {
367         MSG_WriteCoord (sb, v[0], protocol);
368         MSG_WriteCoord (sb, v[1], protocol);
369         MSG_WriteCoord (sb, v[2], protocol);
370 }
371
372 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
373 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
374 {
375         if (f >= 0)
376                 MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255);
377         else
378                 MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255);
379 }
380
381 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
382 {
383         if (f >= 0)
384                 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535);
385         else
386                 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535);
387 }
388
389 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
390 {
391         MSG_WriteFloat (sb, f);
392 }
393
394 void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
395 {
396         if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD)
397                 MSG_WriteAngle8i (sb, f);
398         else
399                 MSG_WriteAngle16i (sb, f);
400 }
401
402 //
403 // reading functions
404 //
405 int msg_readcount;
406 qboolean msg_badread;
407
408 void MSG_BeginReading (void)
409 {
410         msg_readcount = 0;
411         msg_badread = false;
412 }
413
414 int MSG_ReadLittleShort (void)
415 {
416         if (msg_readcount+2 > net_message.cursize)
417         {
418                 msg_badread = true;
419                 return -1;
420         }
421         msg_readcount += 2;
422         return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
423 }
424
425 int MSG_ReadBigShort (void)
426 {
427         if (msg_readcount+2 > net_message.cursize)
428         {
429                 msg_badread = true;
430                 return -1;
431         }
432         msg_readcount += 2;
433         return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
434 }
435
436 int MSG_ReadLittleLong (void)
437 {
438         if (msg_readcount+4 > net_message.cursize)
439         {
440                 msg_badread = true;
441                 return -1;
442         }
443         msg_readcount += 4;
444         return net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
445 }
446
447 int MSG_ReadBigLong (void)
448 {
449         if (msg_readcount+4 > net_message.cursize)
450         {
451                 msg_badread = true;
452                 return -1;
453         }
454         msg_readcount += 4;
455         return (net_message.data[msg_readcount-4]<<24) + (net_message.data[msg_readcount-3]<<16) + (net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1];
456 }
457
458 float MSG_ReadLittleFloat (void)
459 {
460         union
461         {
462                 float f;
463                 int l;
464         } dat;
465         if (msg_readcount+4 > net_message.cursize)
466         {
467                 msg_badread = true;
468                 return -1;
469         }
470         msg_readcount += 4;
471         dat.l = net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
472         return dat.f;
473 }
474
475 float MSG_ReadBigFloat (void)
476 {
477         union
478         {
479                 float f;
480                 int l;
481         } dat;
482         if (msg_readcount+4 > net_message.cursize)
483         {
484                 msg_badread = true;
485                 return -1;
486         }
487         msg_readcount += 4;
488         dat.l = (net_message.data[msg_readcount-4]<<24) | (net_message.data[msg_readcount-3]<<16) | (net_message.data[msg_readcount-2]<<8) | net_message.data[msg_readcount-1];
489         return dat.f;
490 }
491
492 char *MSG_ReadString (void)
493 {
494         static char string[MAX_INPUTLINE];
495         int l,c;
496         for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadByte()) != -1 && c != 0;l++)
497                 string[l] = c;
498         string[l] = 0;
499         return string;
500 }
501
502 int MSG_ReadBytes (int numbytes, unsigned char *out)
503 {
504         int l, c;
505         for (l = 0;l < numbytes && (c = MSG_ReadByte()) != -1;l++)
506                 out[l] = c;
507         return l;
508 }
509
510 float MSG_ReadCoord13i (void)
511 {
512         return MSG_ReadLittleShort() * (1.0/8.0);
513 }
514
515 float MSG_ReadCoord16i (void)
516 {
517         return (signed short) MSG_ReadLittleShort();
518 }
519
520 float MSG_ReadCoord32f (void)
521 {
522         return MSG_ReadLittleFloat();
523 }
524
525 float MSG_ReadCoord (protocolversion_t protocol)
526 {
527         if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
528                 return MSG_ReadCoord13i();
529         else if (protocol == PROTOCOL_DARKPLACES1)
530                 return MSG_ReadCoord32f();
531         else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
532                 return MSG_ReadCoord16i();
533         else
534                 return MSG_ReadCoord32f();
535 }
536
537 void MSG_ReadVector (float *v, protocolversion_t protocol)
538 {
539         v[0] = MSG_ReadCoord(protocol);
540         v[1] = MSG_ReadCoord(protocol);
541         v[2] = MSG_ReadCoord(protocol);
542 }
543
544 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
545 float MSG_ReadAngle8i (void)
546 {
547         return (signed char) MSG_ReadByte () * (360.0/256.0);
548 }
549
550 float MSG_ReadAngle16i (void)
551 {
552         return (signed short)MSG_ReadShort () * (360.0/65536.0);
553 }
554
555 float MSG_ReadAngle32f (void)
556 {
557         return MSG_ReadFloat ();
558 }
559
560 float MSG_ReadAngle (protocolversion_t protocol)
561 {
562         if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD)
563                 return MSG_ReadAngle8i ();
564         else
565                 return MSG_ReadAngle16i ();
566 }
567
568
569 //===========================================================================
570
571 void SZ_Clear (sizebuf_t *buf)
572 {
573         buf->cursize = 0;
574 }
575
576 unsigned char *SZ_GetSpace (sizebuf_t *buf, int length)
577 {
578         unsigned char *data;
579
580         if (buf->cursize + length > buf->maxsize)
581         {
582                 if (!buf->allowoverflow)
583                         Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
584
585                 if (length > buf->maxsize)
586                         Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
587
588                 buf->overflowed = true;
589                 Con_Print("SZ_GetSpace: overflow\n");
590                 SZ_Clear (buf);
591         }
592
593         data = buf->data + buf->cursize;
594         buf->cursize += length;
595
596         return data;
597 }
598
599 void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length)
600 {
601         memcpy (SZ_GetSpace(buf,length),data,length);
602 }
603
604 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
605 // attention, it has been eradicated from here, its only (former) use in
606 // all of darkplaces.
607
608 static char *hexchar = "0123456789ABCDEF";
609 void Com_HexDumpToConsole(const unsigned char *data, int size)
610 {
611         int i, j, n;
612         char text[1024];
613         char *cur, *flushpointer;
614         const unsigned char *d;
615         cur = text;
616         flushpointer = text + 512;
617         for (i = 0;i < size;)
618         {
619                 n = 16;
620                 if (n > size - i)
621                         n = size - i;
622                 d = data + i;
623                 // print offset
624                 *cur++ = hexchar[(i >> 12) & 15];
625                 *cur++ = hexchar[(i >>  8) & 15];
626                 *cur++ = hexchar[(i >>  4) & 15];
627                 *cur++ = hexchar[(i >>  0) & 15];
628                 *cur++ = ':';
629                 // print hex
630                 for (j = 0;j < 16;j++)
631                 {
632                         if (j < n)
633                         {
634                                 *cur++ = hexchar[(d[j] >> 4) & 15];
635                                 *cur++ = hexchar[(d[j] >> 0) & 15];
636                         }
637                         else
638                         {
639                                 *cur++ = ' ';
640                                 *cur++ = ' ';
641                         }
642                         if ((j & 3) == 3)
643                                 *cur++ = ' ';
644                 }
645                 // print text
646                 for (j = 0;j < 16;j++)
647                 {
648                         if (j < n)
649                         {
650                                 // color change prefix character has to be treated specially
651                                 if (d[j] == STRING_COLOR_TAG)
652                                 {
653                                         *cur++ = STRING_COLOR_TAG;
654                                         *cur++ = STRING_COLOR_TAG;
655                                 }
656                                 else if (d[j] >= (unsigned char) ' ')
657                                         *cur++ = d[j];
658                                 else
659                                         *cur++ = '.';
660                         }
661                         else
662                                 *cur++ = ' ';
663                 }
664                 *cur++ = '\n';
665                 i += n;
666                 if (cur >= flushpointer || i >= size)
667                 {
668                         *cur++ = 0;
669                         Con_Print(text);
670                         cur = text;
671                 }
672         }
673 }
674
675 void SZ_HexDumpToConsole(const sizebuf_t *buf)
676 {
677         Com_HexDumpToConsole(buf->data, buf->cursize);
678 }
679
680
681 //============================================================================
682
683 /*
684 ==============
685 COM_Wordwrap
686
687 Word wraps a string. The wordWidth function is guaranteed to be called exactly
688 once for each word in the string, so it may be stateful, no idea what that
689 would be good for any more. At the beginning of the string, it will be called
690 for the char 0 to initialize a clean state, and then once with the string " "
691 (a space) so the routine knows how long a space is.
692
693 In case no single character fits into the given width, the wordWidth function
694 must return the width of exactly one character.
695
696 Wrapped lines get the isContinuation flag set and are continuationWidth less wide.
697
698 The sum of the return values of the processLine function will be returned.
699 ==============
700 */
701 int COM_Wordwrap(const char *string, size_t length, float continuationWidth, float maxWidth, COM_WordWidthFunc_t wordWidth, void *passthroughCW, COM_LineProcessorFunc processLine, void *passthroughPL)
702 {
703         // Logic is as follows:
704         //
705         // For each word or whitespace:
706         //   Newline found? Output current line, advance to next line. This is not a continuation. Continue.
707         //   Space found? Always add it to the current line, no matter if it fits.
708         //   Word found? Check if current line + current word fits.
709         //     If it fits, append it. Continue.
710         //     If it doesn't fit, output current line, advance to next line. Append the word. This is a continuation. Continue.
711
712         qboolean isContinuation = false;
713         float spaceWidth;
714         const char *startOfLine = string;
715         const char *cursor = string;
716         const char *end = string + length;
717         float spaceUsedInLine = 0;
718         float spaceUsedForWord;
719         int result = 0;
720         size_t wordLen;
721         size_t dummy;
722
723         dummy = 0;
724         wordWidth(passthroughCW, NULL, &dummy, -1);
725         dummy = 1;
726         spaceWidth = wordWidth(passthroughCW, " ", &dummy, -1);
727
728         for(;;)
729         {
730                 char ch = (cursor < end) ? *cursor : 0;
731                 switch(ch)
732                 {
733                         case 0: // end of string
734                                 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
735                                 isContinuation = false;
736                                 goto out;
737                         case '\n': // end of line
738                                 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
739                                 isContinuation = false;
740                                 ++cursor;
741                                 startOfLine = cursor;
742                                 break;
743                         case ' ': // space
744                                 ++cursor;
745                                 spaceUsedInLine += spaceWidth;
746                                 break;
747                         default: // word
748                                 wordLen = 1;
749                                 while(cursor + wordLen < end)
750                                 {
751                                         switch(cursor[wordLen])
752                                         {
753                                                 case 0:
754                                                 case '\n':
755                                                 case ' ':
756                                                         goto out_inner;
757                                                 default:
758                                                         ++wordLen;
759                                                         break;
760                                         }
761                                 }
762                                 out_inner:
763                                 spaceUsedForWord = wordWidth(passthroughCW, cursor, &wordLen, maxWidth - continuationWidth); // this may have reduced wordLen when it won't fit - but this is GOOD. TODO fix words that do fit in a non-continuation line
764                                 if(wordLen < 1) // cannot happen according to current spec of wordWidth
765                                 {
766                                         wordLen = 1;
767                                         spaceUsedForWord = maxWidth + 1; // too high, forces it in a line of itself
768                                 }
769                                 if(spaceUsedInLine + spaceUsedForWord <= maxWidth || cursor == startOfLine)
770                                 {
771                                         // we can simply append it
772                                         cursor += wordLen;
773                                         spaceUsedInLine += spaceUsedForWord;
774                                 }
775                                 else
776                                 {
777                                         // output current line
778                                         result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
779                                         isContinuation = true;
780                                         startOfLine = cursor;
781                                         cursor += wordLen;
782                                         spaceUsedInLine = continuationWidth + spaceUsedForWord;
783                                 }
784                 }
785         }
786         out:
787
788         return result;
789
790 /*
791         qboolean isContinuation = false;
792         float currentWordSpace = 0;
793         const char *currentWord = 0;
794         float minReserve = 0;
795
796         float spaceUsedInLine = 0;
797         const char *currentLine = 0;
798         const char *currentLineEnd = 0;
799         float currentLineFinalWhitespace = 0;
800         const char *p;
801
802         int result = 0;
803         minReserve = charWidth(passthroughCW, 0);
804         minReserve += charWidth(passthroughCW, ' ');
805
806         if(maxWidth < continuationWidth + minReserve)
807                 maxWidth = continuationWidth + minReserve;
808
809         charWidth(passthroughCW, 0);
810
811         for(p = string; p < string + length; ++p)
812         {
813                 char c = *p;
814                 float w = charWidth(passthroughCW, c);
815
816                 if(!currentWord)
817                 {
818                         currentWord = p;
819                         currentWordSpace = 0;
820                 }
821
822                 if(!currentLine)
823                 {
824                         currentLine = p;
825                         spaceUsedInLine = isContinuation ? continuationWidth : 0;
826                         currentLineEnd = 0;
827                 }
828
829                 if(c == ' ')
830                 {
831                         // 1. I can add the word AND a space - then just append it.
832                         if(spaceUsedInLine + currentWordSpace + w <= maxWidth)
833                         {
834                                 currentLineEnd = p; // note: space not included here
835                                 currentLineFinalWhitespace = w;
836                                 spaceUsedInLine += currentWordSpace + w;
837                         }
838                         // 2. I can just add the word - then append it, output current line and go to next one.
839                         else if(spaceUsedInLine + currentWordSpace <= maxWidth)
840                         {
841                                 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
842                                 currentLine = 0;
843                                 isContinuation = true;
844                         }
845                         // 3. Otherwise, output current line and go to next one, where I can add the word.
846                         else if(continuationWidth + currentWordSpace + w <= maxWidth)
847                         {
848                                 if(currentLineEnd)
849                                         result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
850                                 currentLine = currentWord;
851                                 spaceUsedInLine = continuationWidth + currentWordSpace + w;
852                                 currentLineEnd = p;
853                                 currentLineFinalWhitespace = w;
854                                 isContinuation = true;
855                         }
856                         // 4. We can't even do that? Then output both current and next word as new lines.
857                         else
858                         {
859                                 if(currentLineEnd)
860                                 {
861                                         result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
862                                         isContinuation = true;
863                                 }
864                                 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
865                                 currentLine = 0;
866                                 isContinuation = true;
867                         }
868                         currentWord = 0;
869                 }
870                 else if(c == '\n')
871                 {
872                         // 1. I can add the word - then do it.
873                         if(spaceUsedInLine + currentWordSpace <= maxWidth)
874                         {
875                                 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
876                         }
877                         // 2. Otherwise, output current line, next one and make tabula rasa.
878                         else
879                         {
880                                 if(currentLineEnd)
881                                 {
882                                         processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
883                                         isContinuation = true;
884                                 }
885                                 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
886                         }
887                         currentWord = 0;
888                         currentLine = 0;
889                         isContinuation = false;
890                 }
891                 else
892                 {
893                         currentWordSpace += w;
894                         if(
895                                 spaceUsedInLine + currentWordSpace > maxWidth // can't join this line...
896                                 &&
897                                 continuationWidth + currentWordSpace > maxWidth // can't join any other line...
898                         )
899                         {
900                                 // this word cannot join ANY line...
901                                 // so output the current line...
902                                 if(currentLineEnd)
903                                 {
904                                         result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
905                                         isContinuation = true;
906                                 }
907
908                                 // then this word's beginning...
909                                 if(isContinuation)
910                                 {
911                                         // it may not fit, but we know we have to split it into maxWidth - continuationWidth pieces
912                                         float pieceWidth = maxWidth - continuationWidth;
913                                         const char *pos = currentWord;
914                                         currentWordSpace = 0;
915
916                                         // reset the char width function to a state where no kerning occurs (start of word)
917                                         charWidth(passthroughCW, ' ');
918                                         while(pos <= p)
919                                         {
920                                                 float w = charWidth(passthroughCW, *pos);
921                                                 if(currentWordSpace + w > pieceWidth) // this piece won't fit any more
922                                                 {
923                                                         // print everything until it
924                                                         result += processLine(passthroughPL, currentWord, pos - currentWord, currentWordSpace, true);
925                                                         // go to here
926                                                         currentWord = pos;
927                                                         currentWordSpace = 0;
928                                                 }
929                                                 currentWordSpace += w;
930                                                 ++pos;
931                                         }
932                                         // now we have a currentWord that fits... set up its next line
933                                         // currentWordSpace has been set
934                                         // currentWord has been set
935                                         spaceUsedInLine = continuationWidth;
936                                         currentLine = currentWord;
937                                         currentLineEnd = 0;
938                                         isContinuation = true;
939                                 }
940                                 else
941                                 {
942                                         // we have a guarantee that it will fix (see if clause)
943                                         result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace - w, isContinuation);
944
945                                         // and use the rest of this word as new start of a line
946                                         currentWordSpace = w;
947                                         currentWord = p;
948                                         spaceUsedInLine = continuationWidth;
949                                         currentLine = p;
950                                         currentLineEnd = 0;
951                                         isContinuation = true;
952                                 }
953                         }
954                 }
955         }
956
957         if(!currentWord)
958         {
959                 currentWord = p;
960                 currentWordSpace = 0;
961         }
962
963         if(currentLine) // Same procedure as \n
964         {
965                 // Can I append the current word?
966                 if(spaceUsedInLine + currentWordSpace <= maxWidth)
967                         result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
968                 else
969                 {
970                         if(currentLineEnd)
971                         {
972                                 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
973                                 isContinuation = true;
974                         }
975                         result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
976                 }
977         }
978
979         return result;
980 */
981 }
982
983 /*
984 ==============
985 COM_ParseToken_Simple
986
987 Parse a token out of a string
988 ==============
989 */
990 int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash)
991 {
992         int len;
993         int c;
994         const char *data = *datapointer;
995
996         len = 0;
997         com_token[0] = 0;
998
999         if (!data)
1000         {
1001                 *datapointer = NULL;
1002                 return false;
1003         }
1004
1005 // skip whitespace
1006 skipwhite:
1007         // line endings:
1008         // UNIX: \n
1009         // Mac: \r
1010         // Windows: \r\n
1011         for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1012         {
1013                 if (*data == 0)
1014                 {
1015                         // end of file
1016                         *datapointer = NULL;
1017                         return false;
1018                 }
1019         }
1020
1021         // handle Windows line ending
1022         if (data[0] == '\r' && data[1] == '\n')
1023                 data++;
1024
1025         if (data[0] == '/' && data[1] == '/')
1026         {
1027                 // comment
1028                 while (*data && *data != '\n' && *data != '\r')
1029                         data++;
1030                 goto skipwhite;
1031         }
1032         else if (data[0] == '/' && data[1] == '*')
1033         {
1034                 // comment
1035                 data++;
1036                 while (*data && (data[0] != '*' || data[1] != '/'))
1037                         data++;
1038                 if (*data)
1039                         data++;
1040                 if (*data)
1041                         data++;
1042                 goto skipwhite;
1043         }
1044         else if (*data == '\"')
1045         {
1046                 // quoted string
1047                 for (data++;*data && *data != '\"';data++)
1048                 {
1049                         c = *data;
1050                         if (*data == '\\' && parsebackslash)
1051                         {
1052                                 data++;
1053                                 c = *data;
1054                                 if (c == 'n')
1055                                         c = '\n';
1056                                 else if (c == 't')
1057                                         c = '\t';
1058                         }
1059                         if (len < (int)sizeof(com_token) - 1)
1060                                 com_token[len++] = c;
1061                 }
1062                 com_token[len] = 0;
1063                 if (*data == '\"')
1064                         data++;
1065                 *datapointer = data;
1066                 return true;
1067         }
1068         else if (*data == '\r')
1069         {
1070                 // translate Mac line ending to UNIX
1071                 com_token[len++] = '\n';data++;
1072                 com_token[len] = 0;
1073                 *datapointer = data;
1074                 return true;
1075         }
1076         else if (*data == '\n')
1077         {
1078                 // single character
1079                 com_token[len++] = *data++;
1080                 com_token[len] = 0;
1081                 *datapointer = data;
1082                 return true;
1083         }
1084         else
1085         {
1086                 // regular word
1087                 for (;!ISWHITESPACE(*data);data++)
1088                         if (len < (int)sizeof(com_token) - 1)
1089                                 com_token[len++] = *data;
1090                 com_token[len] = 0;
1091                 *datapointer = data;
1092                 return true;
1093         }
1094 }
1095
1096 /*
1097 ==============
1098 COM_ParseToken_QuakeC
1099
1100 Parse a token out of a string
1101 ==============
1102 */
1103 int COM_ParseToken_QuakeC(const char **datapointer, qboolean returnnewline)
1104 {
1105         int len;
1106         int c;
1107         const char *data = *datapointer;
1108
1109         len = 0;
1110         com_token[0] = 0;
1111
1112         if (!data)
1113         {
1114                 *datapointer = NULL;
1115                 return false;
1116         }
1117
1118 // skip whitespace
1119 skipwhite:
1120         // line endings:
1121         // UNIX: \n
1122         // Mac: \r
1123         // Windows: \r\n
1124         for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1125         {
1126                 if (*data == 0)
1127                 {
1128                         // end of file
1129                         *datapointer = NULL;
1130                         return false;
1131                 }
1132         }
1133
1134         // handle Windows line ending
1135         if (data[0] == '\r' && data[1] == '\n')
1136                 data++;
1137
1138         if (data[0] == '/' && data[1] == '/')
1139         {
1140                 // comment
1141                 while (*data && *data != '\n' && *data != '\r')
1142                         data++;
1143                 goto skipwhite;
1144         }
1145         else if (data[0] == '/' && data[1] == '*')
1146         {
1147                 // comment
1148                 data++;
1149                 while (*data && (data[0] != '*' || data[1] != '/'))
1150                         data++;
1151                 if (*data)
1152                         data++;
1153                 if (*data)
1154                         data++;
1155                 goto skipwhite;
1156         }
1157         else if (*data == '\"' || *data == '\'')
1158         {
1159                 // quoted string
1160                 char quote = *data;
1161                 for (data++;*data && *data != quote;data++)
1162                 {
1163                         c = *data;
1164                         if (*data == '\\')
1165                         {
1166                                 data++;
1167                                 c = *data;
1168                                 if (c == 'n')
1169                                         c = '\n';
1170                                 else if (c == 't')
1171                                         c = '\t';
1172                         }
1173                         if (len < (int)sizeof(com_token) - 1)
1174                                 com_token[len++] = c;
1175                 }
1176                 com_token[len] = 0;
1177                 if (*data == quote)
1178                         data++;
1179                 *datapointer = data;
1180                 return true;
1181         }
1182         else if (*data == '\r')
1183         {
1184                 // translate Mac line ending to UNIX
1185                 com_token[len++] = '\n';data++;
1186                 com_token[len] = 0;
1187                 *datapointer = data;
1188                 return true;
1189         }
1190         else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1191         {
1192                 // single character
1193                 com_token[len++] = *data++;
1194                 com_token[len] = 0;
1195                 *datapointer = data;
1196                 return true;
1197         }
1198         else
1199         {
1200                 // regular word
1201                 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1202                         if (len < (int)sizeof(com_token) - 1)
1203                                 com_token[len++] = *data;
1204                 com_token[len] = 0;
1205                 *datapointer = data;
1206                 return true;
1207         }
1208 }
1209
1210 /*
1211 ==============
1212 COM_ParseToken_VM_Tokenize
1213
1214 Parse a token out of a string
1215 ==============
1216 */
1217 int COM_ParseToken_VM_Tokenize(const char **datapointer, qboolean returnnewline)
1218 {
1219         int len;
1220         int c;
1221         const char *data = *datapointer;
1222
1223         len = 0;
1224         com_token[0] = 0;
1225
1226         if (!data)
1227         {
1228                 *datapointer = NULL;
1229                 return false;
1230         }
1231
1232 // skip whitespace
1233 skipwhite:
1234         // line endings:
1235         // UNIX: \n
1236         // Mac: \r
1237         // Windows: \r\n
1238         for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1239         {
1240                 if (*data == 0)
1241                 {
1242                         // end of file
1243                         *datapointer = NULL;
1244                         return false;
1245                 }
1246         }
1247
1248         // handle Windows line ending
1249         if (data[0] == '\r' && data[1] == '\n')
1250                 data++;
1251
1252         if (data[0] == '/' && data[1] == '/')
1253         {
1254                 // comment
1255                 while (*data && *data != '\n' && *data != '\r')
1256                         data++;
1257                 goto skipwhite;
1258         }
1259         else if (data[0] == '/' && data[1] == '*')
1260         {
1261                 // comment
1262                 data++;
1263                 while (*data && (data[0] != '*' || data[1] != '/'))
1264                         data++;
1265                 if (*data)
1266                         data++;
1267                 if (*data)
1268                         data++;
1269                 goto skipwhite;
1270         }
1271         else if (*data == '\"' || *data == '\'')
1272         {
1273                 char quote = *data;
1274                 // quoted string
1275                 for (data++;*data && *data != quote;data++)
1276                 {
1277                         c = *data;
1278                         if (*data == '\\')
1279                         {
1280                                 data++;
1281                                 c = *data;
1282                                 if (c == 'n')
1283                                         c = '\n';
1284                                 else if (c == 't')
1285                                         c = '\t';
1286                         }
1287                         if (len < (int)sizeof(com_token) - 1)
1288                                 com_token[len++] = c;
1289                 }
1290                 com_token[len] = 0;
1291                 if (*data == quote)
1292                         data++;
1293                 *datapointer = data;
1294                 return true;
1295         }
1296         else if (*data == '\r')
1297         {
1298                 // translate Mac line ending to UNIX
1299                 com_token[len++] = '\n';data++;
1300                 com_token[len] = 0;
1301                 *datapointer = data;
1302                 return true;
1303         }
1304         else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1305         {
1306                 // single character
1307                 com_token[len++] = *data++;
1308                 com_token[len] = 0;
1309                 *datapointer = data;
1310                 return true;
1311         }
1312         else
1313         {
1314                 // regular word
1315                 for (;!ISWHITESPACE(*data) && *data != ',' && *data != ';' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1316                         if (len < (int)sizeof(com_token) - 1)
1317                                 com_token[len++] = *data;
1318                 com_token[len] = 0;
1319                 *datapointer = data;
1320                 return true;
1321         }
1322 }
1323
1324 /*
1325 ==============
1326 COM_ParseToken_Console
1327
1328 Parse a token out of a string, behaving like the qwcl console
1329 ==============
1330 */
1331 int COM_ParseToken_Console(const char **datapointer)
1332 {
1333         int len;
1334         const char *data = *datapointer;
1335
1336         len = 0;
1337         com_token[0] = 0;
1338
1339         if (!data)
1340         {
1341                 *datapointer = NULL;
1342                 return false;
1343         }
1344
1345 // skip whitespace
1346 skipwhite:
1347         for (;ISWHITESPACE(*data);data++)
1348         {
1349                 if (*data == 0)
1350                 {
1351                         // end of file
1352                         *datapointer = NULL;
1353                         return false;
1354                 }
1355         }
1356
1357         if (*data == '/' && data[1] == '/')
1358         {
1359                 // comment
1360                 while (*data && *data != '\n' && *data != '\r')
1361                         data++;
1362                 goto skipwhite;
1363         }
1364         else if (*data == '\"')
1365         {
1366                 // quoted string
1367                 for (data++;*data && *data != '\"';data++)
1368                 {
1369                         // allow escaped " and \ case
1370                         if (*data == '\\' && (data[1] == '\"' || data[1] == '\\'))
1371                                 data++;
1372                         if (len < (int)sizeof(com_token) - 1)
1373                                 com_token[len++] = *data;
1374                 }
1375                 com_token[len] = 0;
1376                 if (*data == '\"')
1377                         data++;
1378                 *datapointer = data;
1379         }
1380         else
1381         {
1382                 // regular word
1383                 for (;!ISWHITESPACE(*data);data++)
1384                         if (len < (int)sizeof(com_token) - 1)
1385                                 com_token[len++] = *data;
1386                 com_token[len] = 0;
1387                 *datapointer = data;
1388         }
1389
1390         return true;
1391 }
1392
1393
1394 /*
1395 ================
1396 COM_CheckParm
1397
1398 Returns the position (1 to argc-1) in the program's argument list
1399 where the given parameter apears, or 0 if not present
1400 ================
1401 */
1402 int COM_CheckParm (const char *parm)
1403 {
1404         int i;
1405
1406         for (i=1 ; i<com_argc ; i++)
1407         {
1408                 if (!com_argv[i])
1409                         continue;               // NEXTSTEP sometimes clears appkit vars.
1410                 if (!strcmp (parm,com_argv[i]))
1411                         return i;
1412         }
1413
1414         return 0;
1415 }
1416
1417 //===========================================================================
1418
1419 // Game mods
1420
1421 typedef struct gamemode_info_s
1422 {
1423         const char* prog_name;
1424         const char* cmdline;
1425         const char* gamename;
1426         const char* gamedirname1;
1427         const char* gamedirname2;
1428         const char* gamescreenshotname;
1429         const char* gameuserdirname;
1430 } gamemode_info_t;
1431
1432 static const gamemode_info_t gamemode_info [GAME_COUNT] =
1433 {// prog_name           cmdline                 gamename                                basegame        modgame                 screenshotprefix        userdir
1434
1435 // GAME_NORMAL
1436 // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
1437 { "",                           "-quake",               "DarkPlaces-Quake",             "id1",          NULL,                   "dp",                   "darkplaces" },
1438 // GAME_HIPNOTIC
1439 // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
1440 { "hipnotic",           "-hipnotic",    "Darkplaces-Hipnotic",  "id1",          "hipnotic",             "dp",                   "darkplaces" },
1441 // GAME_ROGUE
1442 // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
1443 { "rogue",                      "-rogue",               "Darkplaces-Rogue",             "id1",          "rogue",                "dp",                   "darkplaces" },
1444 // GAME_NEHAHRA
1445 // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
1446 { "nehahra",            "-nehahra",             "DarkPlaces-Nehahra",   "id1",          "nehahra",              "dp",                   "darkplaces" },
1447 // GAME_NEXUIZ
1448 // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
1449 { "nexuiz",                     "-nexuiz",              "Nexuiz",                               "data",         NULL,                   "nexuiz",               "nexuiz" },
1450 // GAME_TRANSFUSION
1451 // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
1452 { "transfusion",        "-transfusion", "Transfusion",                  "basetf",       NULL,                   "transfusion",  "transfusion" },
1453 // GAME_GOODVSBAD2
1454 // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
1455 { "gvb2",                       "-goodvsbad2",  "GoodVs.Bad2",                  "rts",          NULL,                   "gvb2",                 "gvb2" },
1456 // GAME_TEU
1457 // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
1458 { "teu",                        "-teu",                 "TheEvilUnleashed",             "baseteu",      NULL,                   "teu",                  "teu" },
1459 // GAME_BATTLEMECH
1460 // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
1461 { "battlemech",         "-battlemech",  "Battlemech",                   "base",         NULL,                   "battlemech",   "battlemech" },
1462 // GAME_ZYMOTIC
1463 // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
1464 { "zymotic",            "-zymotic",             "Zymotic",                              "basezym",              NULL,                   "zymotic",              "zymotic" },
1465 // GAME_SETHERAL
1466 // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
1467 { "setheral",           "-setheral",    "Setheral",                             "data",         NULL,                   "setheral",             "setheral" },
1468 // GAME_SOM
1469 // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
1470 { "som",                        "-som",                 "Son of Man",                   "id1",          "sonofman",             "som",                  "darkplaces" },
1471 // GAME_TENEBRAE
1472 // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
1473 { "tenebrae",           "-tenebrae",    "DarkPlaces-Tenebrae",  "id1",          "tenebrae",             "dp",                   "darkplaces" },
1474 // GAME_NEOTERIC
1475 // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
1476 { "neoteric",           "-neoteric",    "Neoteric",                             "id1",          "neobase",              "neo",                  "darkplaces" },
1477 // GAME_OPENQUARTZ
1478 // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
1479 { "openquartz",         "-openquartz",  "OpenQuartz",                   "id1",          NULL,                   "openquartz",   "darkplaces" },
1480 // GAME_PRYDON
1481 // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
1482 { "prydon",                     "-prydon",              "PrydonGate",                   "id1",          "prydon",               "prydon",               "darkplaces" },
1483 // GAME_DELUXEQUAKE
1484 // COMMANDLINEOPTION: Game: -dq runs the game Deluxe Quake
1485 { "dq", "-dq",  "Deluxe Quake",         "basedq",               "extradq",              "basedq",               "dq" },
1486 // GAME_THEHUNTED
1487 // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
1488 { "thehunted",          "-thehunted",   "The Hunted",                   "thdata",       NULL,                   "th",                   "thehunted" },
1489 // GAME_DEFEATINDETAIL2
1490 // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
1491 { "did2",                       "-did2",                "Defeat In Detail 2",   "data",         NULL,                   "did2_",                "did2" },
1492 // GAME_DARSANA
1493 // COMMANDLINEOPTION: Game: -darsana runs the game Darsana
1494 { "darsana",            "-darsana",     "Darsana",                      "ddata",        NULL,                   "darsana",                      "darsana" },
1495 // GAME_CONTAGIONTHEORY
1496 // COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory
1497 { "contagiontheory",            "-contagiontheory",     "Contagion Theory",                     "ctdata",       NULL,                   "ct",                   "contagiontheory" },
1498 // GAME_EDU2P
1499 // COMMANDLINEOPTION: Game: -edu2p runs the game Edu2 prototype
1500 { "edu2p", "-edu2p", "EDU2 Prototype", "id1", "edu2", "edu2_p", "edu2prototype" },
1501 // GAME_BLADEMASTER
1502 // COMMANDLINEOPTION: Game: -blademaster runs the game Prophecy: Return of the BladeMaster
1503 { "blademaster", "-blademaster", "Prophecy: Return of the BladeMaster", "basebm", NULL, "blademaster", "blademaster" },
1504 // GAME_PROPHECY
1505 // COMMANDLINEOPTION: Game: -prophecy runs the game Quake (default)
1506 { "prophecy",                           "-prophecy",            "Prophecy",             "data",         NULL,                   "prophecy",                     "prophecy" },
1507 // GAME_BLOODOMNICIDE
1508 // COMMANDLINEOPTION: Game: -omnicide runs the game Blood Omnicide
1509 { "omnicide", "-omnicide", "Blood Omnicide", "kain", NULL, "omnicide", "omnicide" },
1510 };
1511
1512 void COM_InitGameType (void)
1513 {
1514         char name [MAX_OSPATH];
1515         unsigned int i;
1516
1517         FS_StripExtension (com_argv[0], name, sizeof (name));
1518         COM_ToLowerString (name, name, sizeof (name));
1519
1520         // Check the binary name; default to GAME_NORMAL (0)
1521         gamemode = GAME_NORMAL;
1522         for (i = 1; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
1523                 if (strstr (name, gamemode_info[i].prog_name))
1524                 {
1525                         gamemode = (gamemode_t)i;
1526                         break;
1527                 }
1528
1529         // Look for a command-line option
1530         for (i = 0; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
1531                 if (COM_CheckParm (gamemode_info[i].cmdline))
1532                 {
1533                         gamemode = (gamemode_t)i;
1534                         break;
1535                 }
1536
1537         gamename = gamemode_info[gamemode].gamename;
1538         gamedirname1 = gamemode_info[gamemode].gamedirname1;
1539         gamedirname2 = gamemode_info[gamemode].gamedirname2;
1540         gamescreenshotname = gamemode_info[gamemode].gamescreenshotname;
1541         gameuserdirname = gamemode_info[gamemode].gameuserdirname;
1542 }
1543
1544
1545 /*
1546 ================
1547 COM_Init
1548 ================
1549 */
1550 void COM_Init_Commands (void)
1551 {
1552         int i, j, n;
1553         char com_cmdline[MAX_INPUTLINE];
1554
1555         Cvar_RegisterVariable (&registered);
1556         Cvar_RegisterVariable (&cmdline);
1557
1558         // reconstitute the command line for the cmdline externally visible cvar
1559         n = 0;
1560         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
1561         {
1562                 i = 0;
1563                 if (strstr(com_argv[j], " "))
1564                 {
1565                         // arg contains whitespace, store quotes around it
1566                         com_cmdline[n++] = '\"';
1567                         while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1568                                 com_cmdline[n++] = com_argv[j][i++];
1569                         com_cmdline[n++] = '\"';
1570                 }
1571                 else
1572                 {
1573                         while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1574                                 com_cmdline[n++] = com_argv[j][i++];
1575                 }
1576                 if (n < ((int)sizeof(com_cmdline) - 1))
1577                         com_cmdline[n++] = ' ';
1578                 else
1579                         break;
1580         }
1581         com_cmdline[n] = 0;
1582         Cvar_Set ("cmdline", com_cmdline);
1583 }
1584
1585 /*
1586 ============
1587 va
1588
1589 does a varargs printf into a temp buffer, so I don't need to have
1590 varargs versions of all text functions.
1591 FIXME: make this buffer size safe someday
1592 ============
1593 */
1594 char *va(const char *format, ...)
1595 {
1596         va_list argptr;
1597         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1598         static char string[8][1024], *s;
1599         static int stringindex = 0;
1600
1601         s = string[stringindex];
1602         stringindex = (stringindex + 1) & 7;
1603         va_start (argptr, format);
1604         dpvsnprintf (s, sizeof (string[0]), format,argptr);
1605         va_end (argptr);
1606
1607         return s;
1608 }
1609
1610
1611 //======================================
1612
1613 // snprintf and vsnprintf are NOT portable. Use their DP counterparts instead
1614
1615 #undef snprintf
1616 #undef vsnprintf
1617
1618 #ifdef WIN32
1619 # define snprintf _snprintf
1620 # define vsnprintf _vsnprintf
1621 #endif
1622
1623
1624 int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...)
1625 {
1626         va_list args;
1627         int result;
1628
1629         va_start (args, format);
1630         result = dpvsnprintf (buffer, buffersize, format, args);
1631         va_end (args);
1632
1633         return result;
1634 }
1635
1636
1637 int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args)
1638 {
1639         int result;
1640
1641 #if _MSC_VER >= 1400
1642         result = _vsnprintf_s (buffer, buffersize, _TRUNCATE, format, args);
1643 #else
1644         result = vsnprintf (buffer, buffersize, format, args);
1645 #endif
1646         if (result < 0 || (size_t)result >= buffersize)
1647         {
1648                 buffer[buffersize - 1] = '\0';
1649                 return -1;
1650         }
1651
1652         return result;
1653 }
1654
1655
1656 //======================================
1657
1658 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1659 {
1660         if (size_out == 0)
1661                 return;
1662
1663         while (*in && size_out > 1)
1664         {
1665                 if (*in >= 'A' && *in <= 'Z')
1666                         *out++ = *in++ + 'a' - 'A';
1667                 else
1668                         *out++ = *in++;
1669                 size_out--;
1670         }
1671         *out = '\0';
1672 }
1673
1674 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1675 {
1676         if (size_out == 0)
1677                 return;
1678
1679         while (*in && size_out > 1)
1680         {
1681                 if (*in >= 'a' && *in <= 'z')
1682                         *out++ = *in++ + 'A' - 'a';
1683                 else
1684                         *out++ = *in++;
1685                 size_out--;
1686         }
1687         *out = '\0';
1688 }
1689
1690 int COM_StringBeginsWith(const char *s, const char *match)
1691 {
1692         for (;*s && *match;s++, match++)
1693                 if (*s != *match)
1694                         return false;
1695         return true;
1696 }
1697
1698 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1699 {
1700         int argc, commentprefixlength;
1701         char *tokenbufend;
1702         const char *l;
1703         argc = 0;
1704         tokenbufend = tokenbuf + tokenbufsize;
1705         l = *text;
1706         commentprefixlength = 0;
1707         if (commentprefix)
1708                 commentprefixlength = (int)strlen(commentprefix);
1709         while (*l && *l != '\n' && *l != '\r')
1710         {
1711                 if (!ISWHITESPACE(*l))
1712                 {
1713                         if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1714                         {
1715                                 while (*l && *l != '\n' && *l != '\r')
1716                                         l++;
1717                                 break;
1718                         }
1719                         if (argc >= maxargc)
1720                                 return -1;
1721                         argv[argc++] = tokenbuf;
1722                         if (*l == '"')
1723                         {
1724                                 l++;
1725                                 while (*l && *l != '"')
1726                                 {
1727                                         if (tokenbuf >= tokenbufend)
1728                                                 return -1;
1729                                         *tokenbuf++ = *l++;
1730                                 }
1731                                 if (*l == '"')
1732                                         l++;
1733                         }
1734                         else
1735                         {
1736                                 while (!ISWHITESPACE(*l))
1737                                 {
1738                                         if (tokenbuf >= tokenbufend)
1739                                                 return -1;
1740                                         *tokenbuf++ = *l++;
1741                                 }
1742                         }
1743                         if (tokenbuf >= tokenbufend)
1744                                 return -1;
1745                         *tokenbuf++ = 0;
1746                 }
1747                 else
1748                         l++;
1749         }
1750         // line endings:
1751         // UNIX: \n
1752         // Mac: \r
1753         // Windows: \r\n
1754         if (*l == '\r')
1755                 l++;
1756         if (*l == '\n')
1757                 l++;
1758         *text = l;
1759         return argc;
1760 }
1761
1762 /*
1763 ============
1764 COM_StringLengthNoColors
1765
1766 calculates the visible width of a color coded string.
1767
1768 *valid is filled with TRUE if the string is a valid colored string (that is, if
1769 it does not end with an unfinished color code). If it gets filled with FALSE, a
1770 fix would be adding a STRING_COLOR_TAG at the end of the string.
1771
1772 valid can be set to NULL if the caller doesn't care.
1773
1774 For size_s, specify the maximum number of characters from s to use, or 0 to use
1775 all characters until the zero terminator.
1776 ============
1777 */
1778 size_t
1779 COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid)
1780 {
1781         const char *end = size_s ? (s + size_s) : NULL;
1782         size_t len = 0;
1783         for(;;)
1784         {
1785                 switch((s == end) ? 0 : *s)
1786                 {
1787                         case 0:
1788                                 if(valid)
1789                                         *valid = TRUE;
1790                                 return len;
1791                         case STRING_COLOR_TAG:
1792                                 ++s;
1793                                 switch((s == end) ? 0 : *s)
1794                                 {
1795                                         case STRING_COLOR_RGB_TAG_CHAR:
1796                                                 if (s+1 != end && isxdigit(s[1]) &&
1797                                                         s+2 != end && isxdigit(s[2]) &&
1798                                                         s+3 != end && isxdigit(s[3]) )
1799                                                 {
1800                                                         s+=3;
1801                                                         break;
1802                                                 }
1803                                                 ++len; // STRING_COLOR_TAG
1804                                                 ++len; // STRING_COLOR_RGB_TAG_CHAR
1805                                                 break;
1806                                         case 0: // ends with unfinished color code!
1807                                                 ++len;
1808                                                 if(valid)
1809                                                         *valid = FALSE;
1810                                                 return len;
1811                                         case STRING_COLOR_TAG: // escaped ^
1812                                                 ++len;
1813                                                 break;
1814                                         case '0': case '1': case '2': case '3': case '4':
1815                                         case '5': case '6': case '7': case '8': case '9': // color code
1816                                                 break;
1817                                         default: // not a color code
1818                                                 ++len; // STRING_COLOR_TAG
1819                                                 ++len; // the character
1820                                                 break;
1821                                 }
1822                                 break;
1823                         default:
1824                                 ++len;
1825                                 break;
1826                 }
1827                 ++s;
1828         }
1829         // never get here
1830 }
1831
1832 /*
1833 ============
1834 COM_StringDecolorize
1835
1836 removes color codes from a string.
1837
1838 If escape_carets is true, the resulting string will be safe for printing. If
1839 escape_carets is false, the function will just strip color codes (for logging
1840 for example).
1841
1842 If the output buffer size did not suffice for converting, the function returns
1843 FALSE. Generally, if escape_carets is false, the output buffer needs
1844 strlen(str)+1 bytes, and if escape_carets is true, it can need strlen(str)*1.5+2
1845 bytes. In any case, the function makes sure that the resulting string is
1846 zero terminated.
1847
1848 For size_in, specify the maximum number of characters from in to use, or 0 to use
1849 all characters until the zero terminator.
1850 ============
1851 */
1852 qboolean
1853 COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets)
1854 {
1855 #define APPEND(ch) do { if(--size_out) { *out++ = (ch); } else { *out++ = 0; return FALSE; } } while(0)
1856         const char *end = size_in ? (in + size_in) : NULL;
1857         if(size_out < 1)
1858                 return FALSE;
1859         for(;;)
1860         {
1861                 switch((in == end) ? 0 : *in)
1862                 {
1863                         case 0:
1864                                 *out++ = 0;
1865                                 return TRUE;
1866                         case STRING_COLOR_TAG:
1867                                 ++in;
1868                                 switch((in == end) ? 0 : *in)
1869                                 {
1870                                         case STRING_COLOR_RGB_TAG_CHAR:
1871                                                 if (in+1 != end && isxdigit(in[1]) &&
1872                                                         in+2 != end && isxdigit(in[2]) &&
1873                                                         in+3 != end && isxdigit(in[3]) )
1874                                                 {
1875                                                         in+=3;
1876                                                         break;
1877                                                 }
1878                                                 APPEND(STRING_COLOR_TAG);
1879                                                 if(escape_carets)
1880                                                         APPEND(STRING_COLOR_TAG);
1881                                                 APPEND(STRING_COLOR_RGB_TAG_CHAR);
1882                                                 break;
1883                                         case 0: // ends with unfinished color code!
1884                                                 APPEND(STRING_COLOR_TAG);
1885                                                 // finish the code by appending another caret when escaping
1886                                                 if(escape_carets)
1887                                                         APPEND(STRING_COLOR_TAG);
1888                                                 *out++ = 0;
1889                                                 return TRUE;
1890                                         case STRING_COLOR_TAG: // escaped ^
1891                                                 APPEND(STRING_COLOR_TAG);
1892                                                 // append a ^ twice when escaping
1893                                                 if(escape_carets)
1894                                                         APPEND(STRING_COLOR_TAG);
1895                                                 break;
1896                                         case '0': case '1': case '2': case '3': case '4':
1897                                         case '5': case '6': case '7': case '8': case '9': // color code
1898                                                 break;
1899                                         default: // not a color code
1900                                                 APPEND(STRING_COLOR_TAG);
1901                                                 APPEND(*in);
1902                                                 break;
1903                                 }
1904                                 break;
1905                         default:
1906                                 APPEND(*in);
1907                                 break;
1908                 }
1909                 ++in;
1910         }
1911         // never get here
1912 #undef APPEND
1913 }
1914
1915 // written by Elric, thanks Elric!
1916 char *SearchInfostring(const char *infostring, const char *key)
1917 {
1918         static char value [MAX_INPUTLINE];
1919         char crt_key [MAX_INPUTLINE];
1920         size_t value_ind, key_ind;
1921         char c;
1922
1923         if (*infostring++ != '\\')
1924                 return NULL;
1925
1926         value_ind = 0;
1927         for (;;)
1928         {
1929                 key_ind = 0;
1930
1931                 // Get the key name
1932                 for (;;)
1933                 {
1934                         c = *infostring++;
1935
1936                         if (c == '\0')
1937                                 return NULL;
1938                         if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1939                         {
1940                                 crt_key[key_ind] = '\0';
1941                                 break;
1942                         }
1943
1944                         crt_key[key_ind++] = c;
1945                 }
1946
1947                 // If it's the key we are looking for, save it in "value"
1948                 if (!strcmp(crt_key, key))
1949                 {
1950                         for (;;)
1951                         {
1952                                 c = *infostring++;
1953
1954                                 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1955                                 {
1956                                         value[value_ind] = '\0';
1957                                         return value;
1958                                 }
1959
1960                                 value[value_ind++] = c;
1961                         }
1962                 }
1963
1964                 // Else, skip the value
1965                 for (;;)
1966                 {
1967                         c = *infostring++;
1968
1969                         if (c == '\0')
1970                                 return NULL;
1971                         if (c == '\\')
1972                                 break;
1973                 }
1974         }
1975 }
1976
1977 void InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
1978 {
1979         int pos = 0, j;
1980         size_t keylength;
1981         if (!key)
1982                 key = "";
1983         if (!value)
1984                 value = "";
1985         keylength = strlen(key);
1986         if (valuelength < 1 || !value)
1987         {
1988                 Con_Printf("InfoString_GetValue: no room in value\n");
1989                 return;
1990         }
1991         value[0] = 0;
1992         if (strchr(key, '\\'))
1993         {
1994                 Con_Printf("InfoString_GetValue: key name \"%s\" contains \\ which is not possible in an infostring\n", key);
1995                 return;
1996         }
1997         if (strchr(key, '\"'))
1998         {
1999                 Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key);
2000                 return;
2001         }
2002         if (!key[0])
2003         {
2004                 Con_Printf("InfoString_GetValue: can not look up a key with no name\n");
2005                 return;
2006         }
2007         while (buffer[pos] == '\\')
2008         {
2009                 if (!memcmp(buffer + pos+1, key, keylength))
2010                 {
2011                         for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2012                         pos++;
2013                         for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++)
2014                                 value[j] = buffer[pos+j];
2015                         value[j] = 0;
2016                         return;
2017                 }
2018                 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2019                 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2020         }
2021         // if we reach this point the key was not found
2022 }
2023
2024 void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value)
2025 {
2026         int pos = 0, pos2;
2027         size_t keylength;
2028         if (!key)
2029                 key = "";
2030         if (!value)
2031                 value = "";
2032         keylength = strlen(key);
2033         if (strchr(key, '\\') || strchr(value, '\\'))
2034         {
2035                 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \\ which is not possible to store in an infostring\n", key, value);
2036                 return;
2037         }
2038         if (strchr(key, '\"') || strchr(value, '\"'))
2039         {
2040                 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \" which is not allowed in an infostring\n", key, value);
2041                 return;
2042         }
2043         if (!key[0])
2044         {
2045                 Con_Printf("InfoString_SetValue: can not set a key with no name\n");
2046                 return;
2047         }
2048         while (buffer[pos] == '\\')
2049         {
2050                 if (!memcmp(buffer + pos+1, key, keylength))
2051                         break;
2052                 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2053                 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2054         }
2055         // if we found the key, find the end of it because we will be replacing it
2056         pos2 = pos;
2057         if (buffer[pos] == '\\')
2058         {
2059                 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2060                 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2061         }
2062         if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2))
2063         {
2064                 Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value);
2065                 return;
2066         }
2067         if (value && value[0])
2068         {
2069                 // set the key/value and append the remaining text
2070                 char tempbuffer[4096];
2071                 strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer));
2072                 dpsnprintf(buffer + pos, bufferlength - pos, "\\%s\\%s%s", key, value, tempbuffer);
2073         }
2074         else
2075         {
2076                 // just remove the key from the text
2077                 strlcpy(buffer + pos, buffer + pos2, bufferlength - pos);
2078         }
2079 }
2080
2081 void InfoString_Print(char *buffer)
2082 {
2083         int i;
2084         char key[2048];
2085         char value[2048];
2086         while (*buffer)
2087         {
2088                 if (*buffer != '\\')
2089                 {
2090                         Con_Printf("InfoString_Print: corrupt string\n");
2091                         return;
2092                 }
2093                 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2094                         if (i < (int)sizeof(key)-1)
2095                                 key[i++] = *buffer;
2096                 key[i] = 0;
2097                 if (*buffer != '\\')
2098                 {
2099                         Con_Printf("InfoString_Print: corrupt string\n");
2100                         return;
2101                 }
2102                 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2103                         if (i < (int)sizeof(value)-1)
2104                                 value[i++] = *buffer;
2105                 value[i] = 0;
2106                 // empty value is an error case
2107                 Con_Printf("%20s %s\n", key, value[0] ? value : "NO VALUE");
2108         }
2109 }
2110
2111 //========================================================
2112 // strlcat and strlcpy, from OpenBSD
2113
2114 /*
2115  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
2116  *
2117  * Permission to use, copy, modify, and distribute this software for any
2118  * purpose with or without fee is hereby granted, provided that the above
2119  * copyright notice and this permission notice appear in all copies.
2120  *
2121  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2122  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2123  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2124  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2125  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2126  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2127  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2128  */
2129
2130 /*      $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
2131 /*      $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
2132
2133
2134 #ifndef HAVE_STRLCAT
2135 size_t
2136 strlcat(char *dst, const char *src, size_t siz)
2137 {
2138         register char *d = dst;
2139         register const char *s = src;
2140         register size_t n = siz;
2141         size_t dlen;
2142
2143         /* Find the end of dst and adjust bytes left but don't go past end */
2144         while (n-- != 0 && *d != '\0')
2145                 d++;
2146         dlen = d - dst;
2147         n = siz - dlen;
2148
2149         if (n == 0)
2150                 return(dlen + strlen(s));
2151         while (*s != '\0') {
2152                 if (n != 1) {
2153                         *d++ = *s;
2154                         n--;
2155                 }
2156                 s++;
2157         }
2158         *d = '\0';
2159
2160         return(dlen + (s - src));       /* count does not include NUL */
2161 }
2162 #endif  // #ifndef HAVE_STRLCAT
2163
2164
2165 #ifndef HAVE_STRLCPY
2166 size_t
2167 strlcpy(char *dst, const char *src, size_t siz)
2168 {
2169         register char *d = dst;
2170         register const char *s = src;
2171         register size_t n = siz;
2172
2173         /* Copy as many bytes as will fit */
2174         if (n != 0 && --n != 0) {
2175                 do {
2176                         if ((*d++ = *s++) == 0)
2177                                 break;
2178                 } while (--n != 0);
2179         }
2180
2181         /* Not enough room in dst, add NUL and traverse rest of src */
2182         if (n == 0) {
2183                 if (siz != 0)
2184                         *d = '\0';              /* NUL-terminate dst */
2185                 while (*s++)
2186                         ;
2187         }
2188
2189         return(s - src - 1);    /* count does not include NUL */
2190 }
2191
2192 #endif  // #ifndef HAVE_STRLCPY
2193
2194 void FindFraction(double val, int *num, int *denom, int denomMax)
2195 {
2196         int i;
2197         double bestdiff;
2198         // initialize
2199         bestdiff = fabs(val);
2200         *num = 0;
2201         *denom = 1;
2202
2203         for(i = 1; i <= denomMax; ++i)
2204         {
2205                 int inum = (int) floor(0.5 + val * i);
2206                 double diff = fabs(val - inum / (double)i);
2207                 if(diff < bestdiff)
2208                 {
2209                         bestdiff = diff;
2210                         *num = inum;
2211                         *denom = i;
2212                 }
2213         }
2214 }