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