]> git.xonotic.org Git - xonotic/darkplaces.git/blob - common.c
changed executable name detection to ignore path
[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, float *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 int msg_readcount;
408 qboolean msg_badread;
409
410 void MSG_BeginReading (void)
411 {
412         msg_readcount = 0;
413         msg_badread = false;
414 }
415
416 int MSG_ReadLittleShort (void)
417 {
418         if (msg_readcount+2 > net_message.cursize)
419         {
420                 msg_badread = true;
421                 return -1;
422         }
423         msg_readcount += 2;
424         return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
425 }
426
427 int MSG_ReadBigShort (void)
428 {
429         if (msg_readcount+2 > net_message.cursize)
430         {
431                 msg_badread = true;
432                 return -1;
433         }
434         msg_readcount += 2;
435         return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
436 }
437
438 int MSG_ReadLittleLong (void)
439 {
440         if (msg_readcount+4 > net_message.cursize)
441         {
442                 msg_badread = true;
443                 return -1;
444         }
445         msg_readcount += 4;
446         return net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
447 }
448
449 int MSG_ReadBigLong (void)
450 {
451         if (msg_readcount+4 > net_message.cursize)
452         {
453                 msg_badread = true;
454                 return -1;
455         }
456         msg_readcount += 4;
457         return (net_message.data[msg_readcount-4]<<24) + (net_message.data[msg_readcount-3]<<16) + (net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1];
458 }
459
460 float MSG_ReadLittleFloat (void)
461 {
462         union
463         {
464                 float f;
465                 int l;
466         } dat;
467         if (msg_readcount+4 > net_message.cursize)
468         {
469                 msg_badread = true;
470                 return -1;
471         }
472         msg_readcount += 4;
473         dat.l = net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
474         return dat.f;
475 }
476
477 float MSG_ReadBigFloat (void)
478 {
479         union
480         {
481                 float f;
482                 int l;
483         } dat;
484         if (msg_readcount+4 > net_message.cursize)
485         {
486                 msg_badread = true;
487                 return -1;
488         }
489         msg_readcount += 4;
490         dat.l = (net_message.data[msg_readcount-4]<<24) | (net_message.data[msg_readcount-3]<<16) | (net_message.data[msg_readcount-2]<<8) | net_message.data[msg_readcount-1];
491         return dat.f;
492 }
493
494 char *MSG_ReadString (void)
495 {
496         static char string[MAX_INPUTLINE];
497         const int maxstring = sizeof(string);
498         int l = 0,c;
499         // read string into buffer, but only store as many characters as will fit
500         while ((c = MSG_ReadByte()) > 0)
501                 if (l < maxstring - 1)
502                         string[l++] = c;
503         string[l] = 0;
504         return string;
505 }
506
507 int MSG_ReadBytes (int numbytes, unsigned char *out)
508 {
509         int l, c;
510         for (l = 0;l < numbytes && (c = MSG_ReadByte()) != -1;l++)
511                 out[l] = c;
512         return l;
513 }
514
515 float MSG_ReadCoord13i (void)
516 {
517         return MSG_ReadLittleShort() * (1.0/8.0);
518 }
519
520 float MSG_ReadCoord16i (void)
521 {
522         return (signed short) MSG_ReadLittleShort();
523 }
524
525 float MSG_ReadCoord32f (void)
526 {
527         return MSG_ReadLittleFloat();
528 }
529
530 float MSG_ReadCoord (protocolversion_t protocol)
531 {
532         if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
533                 return MSG_ReadCoord13i();
534         else if (protocol == PROTOCOL_DARKPLACES1)
535                 return MSG_ReadCoord32f();
536         else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
537                 return MSG_ReadCoord16i();
538         else
539                 return MSG_ReadCoord32f();
540 }
541
542 void MSG_ReadVector (float *v, protocolversion_t protocol)
543 {
544         v[0] = MSG_ReadCoord(protocol);
545         v[1] = MSG_ReadCoord(protocol);
546         v[2] = MSG_ReadCoord(protocol);
547 }
548
549 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
550 float MSG_ReadAngle8i (void)
551 {
552         return (signed char) MSG_ReadByte () * (360.0/256.0);
553 }
554
555 float MSG_ReadAngle16i (void)
556 {
557         return (signed short)MSG_ReadShort () * (360.0/65536.0);
558 }
559
560 float MSG_ReadAngle32f (void)
561 {
562         return MSG_ReadFloat ();
563 }
564
565 float MSG_ReadAngle (protocolversion_t protocol)
566 {
567         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)
568                 return MSG_ReadAngle8i ();
569         else
570                 return MSG_ReadAngle16i ();
571 }
572
573
574 //===========================================================================
575
576 void SZ_Clear (sizebuf_t *buf)
577 {
578         buf->cursize = 0;
579 }
580
581 unsigned char *SZ_GetSpace (sizebuf_t *buf, int length)
582 {
583         unsigned char *data;
584
585         if (buf->cursize + length > buf->maxsize)
586         {
587                 if (!buf->allowoverflow)
588                         Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
589
590                 if (length > buf->maxsize)
591                         Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
592
593                 buf->overflowed = true;
594                 Con_Print("SZ_GetSpace: overflow\n");
595                 SZ_Clear (buf);
596         }
597
598         data = buf->data + buf->cursize;
599         buf->cursize += length;
600
601         return data;
602 }
603
604 void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length)
605 {
606         memcpy (SZ_GetSpace(buf,length),data,length);
607 }
608
609 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
610 // attention, it has been eradicated from here, its only (former) use in
611 // all of darkplaces.
612
613 static const char *hexchar = "0123456789ABCDEF";
614 void Com_HexDumpToConsole(const unsigned char *data, int size)
615 {
616         int i, j, n;
617         char text[1024];
618         char *cur, *flushpointer;
619         const unsigned char *d;
620         cur = text;
621         flushpointer = text + 512;
622         for (i = 0;i < size;)
623         {
624                 n = 16;
625                 if (n > size - i)
626                         n = size - i;
627                 d = data + i;
628                 // print offset
629                 *cur++ = hexchar[(i >> 12) & 15];
630                 *cur++ = hexchar[(i >>  8) & 15];
631                 *cur++ = hexchar[(i >>  4) & 15];
632                 *cur++ = hexchar[(i >>  0) & 15];
633                 *cur++ = ':';
634                 // print hex
635                 for (j = 0;j < 16;j++)
636                 {
637                         if (j < n)
638                         {
639                                 *cur++ = hexchar[(d[j] >> 4) & 15];
640                                 *cur++ = hexchar[(d[j] >> 0) & 15];
641                         }
642                         else
643                         {
644                                 *cur++ = ' ';
645                                 *cur++ = ' ';
646                         }
647                         if ((j & 3) == 3)
648                                 *cur++ = ' ';
649                 }
650                 // print text
651                 for (j = 0;j < 16;j++)
652                 {
653                         if (j < n)
654                         {
655                                 // color change prefix character has to be treated specially
656                                 if (d[j] == STRING_COLOR_TAG)
657                                 {
658                                         *cur++ = STRING_COLOR_TAG;
659                                         *cur++ = STRING_COLOR_TAG;
660                                 }
661                                 else if (d[j] >= (unsigned char) ' ')
662                                         *cur++ = d[j];
663                                 else
664                                         *cur++ = '.';
665                         }
666                         else
667                                 *cur++ = ' ';
668                 }
669                 *cur++ = '\n';
670                 i += n;
671                 if (cur >= flushpointer || i >= size)
672                 {
673                         *cur++ = 0;
674                         Con_Print(text);
675                         cur = text;
676                 }
677         }
678 }
679
680 void SZ_HexDumpToConsole(const sizebuf_t *buf)
681 {
682         Com_HexDumpToConsole(buf->data, buf->cursize);
683 }
684
685
686 //============================================================================
687
688 /*
689 ==============
690 COM_Wordwrap
691
692 Word wraps a string. The wordWidth function is guaranteed to be called exactly
693 once for each word in the string, so it may be stateful, no idea what that
694 would be good for any more. At the beginning of the string, it will be called
695 for the char 0 to initialize a clean state, and then once with the string " "
696 (a space) so the routine knows how long a space is.
697
698 In case no single character fits into the given width, the wordWidth function
699 must return the width of exactly one character.
700
701 Wrapped lines get the isContinuation flag set and are continuationWidth less wide.
702
703 The sum of the return values of the processLine function will be returned.
704 ==============
705 */
706 int COM_Wordwrap(const char *string, size_t length, float continuationWidth, float maxWidth, COM_WordWidthFunc_t wordWidth, void *passthroughCW, COM_LineProcessorFunc processLine, void *passthroughPL)
707 {
708         // Logic is as follows:
709         //
710         // For each word or whitespace:
711         //   Newline found? Output current line, advance to next line. This is not a continuation. Continue.
712         //   Space found? Always add it to the current line, no matter if it fits.
713         //   Word found? Check if current line + current word fits.
714         //     If it fits, append it. Continue.
715         //     If it doesn't fit, output current line, advance to next line. Append the word. This is a continuation. Continue.
716
717         qboolean isContinuation = false;
718         float spaceWidth;
719         const char *startOfLine = string;
720         const char *cursor = string;
721         const char *end = string + length;
722         float spaceUsedInLine = 0;
723         float spaceUsedForWord;
724         int result = 0;
725         size_t wordLen;
726         size_t dummy;
727
728         dummy = 0;
729         wordWidth(passthroughCW, NULL, &dummy, -1);
730         dummy = 1;
731         spaceWidth = wordWidth(passthroughCW, " ", &dummy, -1);
732
733         for(;;)
734         {
735                 char ch = (cursor < end) ? *cursor : 0;
736                 switch(ch)
737                 {
738                         case 0: // end of string
739                                 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
740                                 isContinuation = false;
741                                 goto out;
742                         case '\n': // end of line
743                                 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
744                                 isContinuation = false;
745                                 ++cursor;
746                                 startOfLine = cursor;
747                                 break;
748                         case ' ': // space
749                                 ++cursor;
750                                 spaceUsedInLine += spaceWidth;
751                                 break;
752                         default: // word
753                                 wordLen = 1;
754                                 while(cursor + wordLen < end)
755                                 {
756                                         switch(cursor[wordLen])
757                                         {
758                                                 case 0:
759                                                 case '\n':
760                                                 case ' ':
761                                                         goto out_inner;
762                                                 default:
763                                                         ++wordLen;
764                                                         break;
765                                         }
766                                 }
767                                 out_inner:
768                                 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
769                                 if(wordLen < 1) // cannot happen according to current spec of wordWidth
770                                 {
771                                         wordLen = 1;
772                                         spaceUsedForWord = maxWidth + 1; // too high, forces it in a line of itself
773                                 }
774                                 if(spaceUsedInLine + spaceUsedForWord <= maxWidth || cursor == startOfLine)
775                                 {
776                                         // we can simply append it
777                                         cursor += wordLen;
778                                         spaceUsedInLine += spaceUsedForWord;
779                                 }
780                                 else
781                                 {
782                                         // output current line
783                                         result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
784                                         isContinuation = true;
785                                         startOfLine = cursor;
786                                         cursor += wordLen;
787                                         spaceUsedInLine = continuationWidth + spaceUsedForWord;
788                                 }
789                 }
790         }
791         out:
792
793         return result;
794
795 /*
796         qboolean isContinuation = false;
797         float currentWordSpace = 0;
798         const char *currentWord = 0;
799         float minReserve = 0;
800
801         float spaceUsedInLine = 0;
802         const char *currentLine = 0;
803         const char *currentLineEnd = 0;
804         float currentLineFinalWhitespace = 0;
805         const char *p;
806
807         int result = 0;
808         minReserve = charWidth(passthroughCW, 0);
809         minReserve += charWidth(passthroughCW, ' ');
810
811         if(maxWidth < continuationWidth + minReserve)
812                 maxWidth = continuationWidth + minReserve;
813
814         charWidth(passthroughCW, 0);
815
816         for(p = string; p < string + length; ++p)
817         {
818                 char c = *p;
819                 float w = charWidth(passthroughCW, c);
820
821                 if(!currentWord)
822                 {
823                         currentWord = p;
824                         currentWordSpace = 0;
825                 }
826
827                 if(!currentLine)
828                 {
829                         currentLine = p;
830                         spaceUsedInLine = isContinuation ? continuationWidth : 0;
831                         currentLineEnd = 0;
832                 }
833
834                 if(c == ' ')
835                 {
836                         // 1. I can add the word AND a space - then just append it.
837                         if(spaceUsedInLine + currentWordSpace + w <= maxWidth)
838                         {
839                                 currentLineEnd = p; // note: space not included here
840                                 currentLineFinalWhitespace = w;
841                                 spaceUsedInLine += currentWordSpace + w;
842                         }
843                         // 2. I can just add the word - then append it, output current line and go to next one.
844                         else if(spaceUsedInLine + currentWordSpace <= maxWidth)
845                         {
846                                 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
847                                 currentLine = 0;
848                                 isContinuation = true;
849                         }
850                         // 3. Otherwise, output current line and go to next one, where I can add the word.
851                         else if(continuationWidth + currentWordSpace + w <= maxWidth)
852                         {
853                                 if(currentLineEnd)
854                                         result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
855                                 currentLine = currentWord;
856                                 spaceUsedInLine = continuationWidth + currentWordSpace + w;
857                                 currentLineEnd = p;
858                                 currentLineFinalWhitespace = w;
859                                 isContinuation = true;
860                         }
861                         // 4. We can't even do that? Then output both current and next word as new lines.
862                         else
863                         {
864                                 if(currentLineEnd)
865                                 {
866                                         result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
867                                         isContinuation = true;
868                                 }
869                                 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
870                                 currentLine = 0;
871                                 isContinuation = true;
872                         }
873                         currentWord = 0;
874                 }
875                 else if(c == '\n')
876                 {
877                         // 1. I can add the word - then do it.
878                         if(spaceUsedInLine + currentWordSpace <= maxWidth)
879                         {
880                                 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
881                         }
882                         // 2. Otherwise, output current line, next one and make tabula rasa.
883                         else
884                         {
885                                 if(currentLineEnd)
886                                 {
887                                         processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
888                                         isContinuation = true;
889                                 }
890                                 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
891                         }
892                         currentWord = 0;
893                         currentLine = 0;
894                         isContinuation = false;
895                 }
896                 else
897                 {
898                         currentWordSpace += w;
899                         if(
900                                 spaceUsedInLine + currentWordSpace > maxWidth // can't join this line...
901                                 &&
902                                 continuationWidth + currentWordSpace > maxWidth // can't join any other line...
903                         )
904                         {
905                                 // this word cannot join ANY line...
906                                 // so output the current line...
907                                 if(currentLineEnd)
908                                 {
909                                         result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
910                                         isContinuation = true;
911                                 }
912
913                                 // then this word's beginning...
914                                 if(isContinuation)
915                                 {
916                                         // it may not fit, but we know we have to split it into maxWidth - continuationWidth pieces
917                                         float pieceWidth = maxWidth - continuationWidth;
918                                         const char *pos = currentWord;
919                                         currentWordSpace = 0;
920
921                                         // reset the char width function to a state where no kerning occurs (start of word)
922                                         charWidth(passthroughCW, ' ');
923                                         while(pos <= p)
924                                         {
925                                                 float w = charWidth(passthroughCW, *pos);
926                                                 if(currentWordSpace + w > pieceWidth) // this piece won't fit any more
927                                                 {
928                                                         // print everything until it
929                                                         result += processLine(passthroughPL, currentWord, pos - currentWord, currentWordSpace, true);
930                                                         // go to here
931                                                         currentWord = pos;
932                                                         currentWordSpace = 0;
933                                                 }
934                                                 currentWordSpace += w;
935                                                 ++pos;
936                                         }
937                                         // now we have a currentWord that fits... set up its next line
938                                         // currentWordSpace has been set
939                                         // currentWord has been set
940                                         spaceUsedInLine = continuationWidth;
941                                         currentLine = currentWord;
942                                         currentLineEnd = 0;
943                                         isContinuation = true;
944                                 }
945                                 else
946                                 {
947                                         // we have a guarantee that it will fix (see if clause)
948                                         result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace - w, isContinuation);
949
950                                         // and use the rest of this word as new start of a line
951                                         currentWordSpace = w;
952                                         currentWord = p;
953                                         spaceUsedInLine = continuationWidth;
954                                         currentLine = p;
955                                         currentLineEnd = 0;
956                                         isContinuation = true;
957                                 }
958                         }
959                 }
960         }
961
962         if(!currentWord)
963         {
964                 currentWord = p;
965                 currentWordSpace = 0;
966         }
967
968         if(currentLine) // Same procedure as \n
969         {
970                 // Can I append the current word?
971                 if(spaceUsedInLine + currentWordSpace <= maxWidth)
972                         result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
973                 else
974                 {
975                         if(currentLineEnd)
976                         {
977                                 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
978                                 isContinuation = true;
979                         }
980                         result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
981                 }
982         }
983
984         return result;
985 */
986 }
987
988 /*
989 ==============
990 COM_ParseToken_Simple
991
992 Parse a token out of a string
993 ==============
994 */
995 int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash)
996 {
997         int len;
998         int c;
999         const char *data = *datapointer;
1000
1001         len = 0;
1002         com_token[0] = 0;
1003
1004         if (!data)
1005         {
1006                 *datapointer = NULL;
1007                 return false;
1008         }
1009
1010 // skip whitespace
1011 skipwhite:
1012         // line endings:
1013         // UNIX: \n
1014         // Mac: \r
1015         // Windows: \r\n
1016         for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1017         {
1018                 if (*data == 0)
1019                 {
1020                         // end of file
1021                         *datapointer = NULL;
1022                         return false;
1023                 }
1024         }
1025
1026         // handle Windows line ending
1027         if (data[0] == '\r' && data[1] == '\n')
1028                 data++;
1029
1030         if (data[0] == '/' && data[1] == '/')
1031         {
1032                 // comment
1033                 while (*data && *data != '\n' && *data != '\r')
1034                         data++;
1035                 goto skipwhite;
1036         }
1037         else if (data[0] == '/' && data[1] == '*')
1038         {
1039                 // comment
1040                 data++;
1041                 while (*data && (data[0] != '*' || data[1] != '/'))
1042                         data++;
1043                 if (*data)
1044                         data++;
1045                 if (*data)
1046                         data++;
1047                 goto skipwhite;
1048         }
1049         else if (*data == '\"')
1050         {
1051                 // quoted string
1052                 for (data++;*data && *data != '\"';data++)
1053                 {
1054                         c = *data;
1055                         if (*data == '\\' && parsebackslash)
1056                         {
1057                                 data++;
1058                                 c = *data;
1059                                 if (c == 'n')
1060                                         c = '\n';
1061                                 else if (c == 't')
1062                                         c = '\t';
1063                         }
1064                         if (len < (int)sizeof(com_token) - 1)
1065                                 com_token[len++] = c;
1066                 }
1067                 com_token[len] = 0;
1068                 if (*data == '\"')
1069                         data++;
1070                 *datapointer = data;
1071                 return true;
1072         }
1073         else if (*data == '\r')
1074         {
1075                 // translate Mac line ending to UNIX
1076                 com_token[len++] = '\n';data++;
1077                 com_token[len] = 0;
1078                 *datapointer = data;
1079                 return true;
1080         }
1081         else if (*data == '\n')
1082         {
1083                 // single character
1084                 com_token[len++] = *data++;
1085                 com_token[len] = 0;
1086                 *datapointer = data;
1087                 return true;
1088         }
1089         else
1090         {
1091                 // regular word
1092                 for (;!ISWHITESPACE(*data);data++)
1093                         if (len < (int)sizeof(com_token) - 1)
1094                                 com_token[len++] = *data;
1095                 com_token[len] = 0;
1096                 *datapointer = data;
1097                 return true;
1098         }
1099 }
1100
1101 /*
1102 ==============
1103 COM_ParseToken_QuakeC
1104
1105 Parse a token out of a string
1106 ==============
1107 */
1108 int COM_ParseToken_QuakeC(const char **datapointer, qboolean returnnewline)
1109 {
1110         int len;
1111         int c;
1112         const char *data = *datapointer;
1113
1114         len = 0;
1115         com_token[0] = 0;
1116
1117         if (!data)
1118         {
1119                 *datapointer = NULL;
1120                 return false;
1121         }
1122
1123 // skip whitespace
1124 skipwhite:
1125         // line endings:
1126         // UNIX: \n
1127         // Mac: \r
1128         // Windows: \r\n
1129         for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1130         {
1131                 if (*data == 0)
1132                 {
1133                         // end of file
1134                         *datapointer = NULL;
1135                         return false;
1136                 }
1137         }
1138
1139         // handle Windows line ending
1140         if (data[0] == '\r' && data[1] == '\n')
1141                 data++;
1142
1143         if (data[0] == '/' && data[1] == '/')
1144         {
1145                 // comment
1146                 while (*data && *data != '\n' && *data != '\r')
1147                         data++;
1148                 goto skipwhite;
1149         }
1150         else if (data[0] == '/' && data[1] == '*')
1151         {
1152                 // comment
1153                 data++;
1154                 while (*data && (data[0] != '*' || data[1] != '/'))
1155                         data++;
1156                 if (*data)
1157                         data++;
1158                 if (*data)
1159                         data++;
1160                 goto skipwhite;
1161         }
1162         else if (*data == '\"' || *data == '\'')
1163         {
1164                 // quoted string
1165                 char quote = *data;
1166                 for (data++;*data && *data != quote;data++)
1167                 {
1168                         c = *data;
1169                         if (*data == '\\')
1170                         {
1171                                 data++;
1172                                 c = *data;
1173                                 if (c == 'n')
1174                                         c = '\n';
1175                                 else if (c == 't')
1176                                         c = '\t';
1177                         }
1178                         if (len < (int)sizeof(com_token) - 1)
1179                                 com_token[len++] = c;
1180                 }
1181                 com_token[len] = 0;
1182                 if (*data == quote)
1183                         data++;
1184                 *datapointer = data;
1185                 return true;
1186         }
1187         else if (*data == '\r')
1188         {
1189                 // translate Mac line ending to UNIX
1190                 com_token[len++] = '\n';data++;
1191                 com_token[len] = 0;
1192                 *datapointer = data;
1193                 return true;
1194         }
1195         else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1196         {
1197                 // single character
1198                 com_token[len++] = *data++;
1199                 com_token[len] = 0;
1200                 *datapointer = data;
1201                 return true;
1202         }
1203         else
1204         {
1205                 // regular word
1206                 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1207                         if (len < (int)sizeof(com_token) - 1)
1208                                 com_token[len++] = *data;
1209                 com_token[len] = 0;
1210                 *datapointer = data;
1211                 return true;
1212         }
1213 }
1214
1215 /*
1216 ==============
1217 COM_ParseToken_VM_Tokenize
1218
1219 Parse a token out of a string
1220 ==============
1221 */
1222 int COM_ParseToken_VM_Tokenize(const char **datapointer, qboolean returnnewline)
1223 {
1224         int len;
1225         int c;
1226         const char *data = *datapointer;
1227
1228         len = 0;
1229         com_token[0] = 0;
1230
1231         if (!data)
1232         {
1233                 *datapointer = NULL;
1234                 return false;
1235         }
1236
1237 // skip whitespace
1238 skipwhite:
1239         // line endings:
1240         // UNIX: \n
1241         // Mac: \r
1242         // Windows: \r\n
1243         for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1244         {
1245                 if (*data == 0)
1246                 {
1247                         // end of file
1248                         *datapointer = NULL;
1249                         return false;
1250                 }
1251         }
1252
1253         // handle Windows line ending
1254         if (data[0] == '\r' && data[1] == '\n')
1255                 data++;
1256
1257         if (data[0] == '/' && data[1] == '/')
1258         {
1259                 // comment
1260                 while (*data && *data != '\n' && *data != '\r')
1261                         data++;
1262                 goto skipwhite;
1263         }
1264         else if (data[0] == '/' && data[1] == '*')
1265         {
1266                 // comment
1267                 data++;
1268                 while (*data && (data[0] != '*' || data[1] != '/'))
1269                         data++;
1270                 if (*data)
1271                         data++;
1272                 if (*data)
1273                         data++;
1274                 goto skipwhite;
1275         }
1276         else if (*data == '\"' || *data == '\'')
1277         {
1278                 char quote = *data;
1279                 // quoted string
1280                 for (data++;*data && *data != quote;data++)
1281                 {
1282                         c = *data;
1283                         if (*data == '\\')
1284                         {
1285                                 data++;
1286                                 c = *data;
1287                                 if (c == 'n')
1288                                         c = '\n';
1289                                 else if (c == 't')
1290                                         c = '\t';
1291                         }
1292                         if (len < (int)sizeof(com_token) - 1)
1293                                 com_token[len++] = c;
1294                 }
1295                 com_token[len] = 0;
1296                 if (*data == quote)
1297                         data++;
1298                 *datapointer = data;
1299                 return true;
1300         }
1301         else if (*data == '\r')
1302         {
1303                 // translate Mac line ending to UNIX
1304                 com_token[len++] = '\n';data++;
1305                 com_token[len] = 0;
1306                 *datapointer = data;
1307                 return true;
1308         }
1309         else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1310         {
1311                 // single character
1312                 com_token[len++] = *data++;
1313                 com_token[len] = 0;
1314                 *datapointer = data;
1315                 return true;
1316         }
1317         else
1318         {
1319                 // regular word
1320                 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1321                         if (len < (int)sizeof(com_token) - 1)
1322                                 com_token[len++] = *data;
1323                 com_token[len] = 0;
1324                 *datapointer = data;
1325                 return true;
1326         }
1327 }
1328
1329 /*
1330 ==============
1331 COM_ParseToken_Console
1332
1333 Parse a token out of a string, behaving like the qwcl console
1334 ==============
1335 */
1336 int COM_ParseToken_Console(const char **datapointer)
1337 {
1338         int len;
1339         const char *data = *datapointer;
1340
1341         len = 0;
1342         com_token[0] = 0;
1343
1344         if (!data)
1345         {
1346                 *datapointer = NULL;
1347                 return false;
1348         }
1349
1350 // skip whitespace
1351 skipwhite:
1352         for (;ISWHITESPACE(*data);data++)
1353         {
1354                 if (*data == 0)
1355                 {
1356                         // end of file
1357                         *datapointer = NULL;
1358                         return false;
1359                 }
1360         }
1361
1362         if (*data == '/' && data[1] == '/')
1363         {
1364                 // comment
1365                 while (*data && *data != '\n' && *data != '\r')
1366                         data++;
1367                 goto skipwhite;
1368         }
1369         else if (*data == '\"')
1370         {
1371                 // quoted string
1372                 for (data++;*data && *data != '\"';data++)
1373                 {
1374                         // allow escaped " and \ case
1375                         if (*data == '\\' && (data[1] == '\"' || data[1] == '\\'))
1376                                 data++;
1377                         if (len < (int)sizeof(com_token) - 1)
1378                                 com_token[len++] = *data;
1379                 }
1380                 com_token[len] = 0;
1381                 if (*data == '\"')
1382                         data++;
1383                 *datapointer = data;
1384         }
1385         else
1386         {
1387                 // regular word
1388                 for (;!ISWHITESPACE(*data);data++)
1389                         if (len < (int)sizeof(com_token) - 1)
1390                                 com_token[len++] = *data;
1391                 com_token[len] = 0;
1392                 *datapointer = data;
1393         }
1394
1395         return true;
1396 }
1397
1398
1399 /*
1400 ================
1401 COM_CheckParm
1402
1403 Returns the position (1 to argc-1) in the program's argument list
1404 where the given parameter apears, or 0 if not present
1405 ================
1406 */
1407 int COM_CheckParm (const char *parm)
1408 {
1409         int i;
1410
1411         for (i=1 ; i<com_argc ; i++)
1412         {
1413                 if (!com_argv[i])
1414                         continue;               // NEXTSTEP sometimes clears appkit vars.
1415                 if (!strcmp (parm,com_argv[i]))
1416                         return i;
1417         }
1418
1419         return 0;
1420 }
1421
1422 //===========================================================================
1423
1424 // Game mods
1425
1426 gamemode_t com_startupgamemode;
1427 gamemode_t com_startupgamegroup;
1428
1429 typedef struct gamemode_info_s
1430 {
1431         gamemode_t mode; // this gamemode
1432         gamemode_t group; // different games with same group can switch automatically when gamedirs change
1433         const char* prog_name; // not null
1434         const char* cmdline; // not null
1435         const char* gamename; // not null
1436         const char* gamedirname1; // not null
1437         const char* gamedirname2; // null
1438         const char* gamescreenshotname; // not nul
1439         const char* gameuserdirname; // not null
1440 } gamemode_info_t;
1441
1442 static const gamemode_info_t gamemode_info [GAME_COUNT] =
1443 {// game                                basegame                                prog_name                       cmdline                         gamename                                basegame        modgame                 screenshot              userdir                            // commandline option
1444 { GAME_NORMAL,                  GAME_NORMAL,                    "",                                     "-quake",                       "DarkPlaces-Quake",             "id1",          NULL,                   "dp",                   "darkplaces"            }, // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
1445 { GAME_HIPNOTIC,                GAME_NORMAL,                    "hipnotic",                     "-hipnotic",            "Darkplaces-Hipnotic",  "id1",          "hipnotic",             "dp",                   "darkplaces"            }, // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
1446 { GAME_ROGUE,                   GAME_NORMAL,                    "rogue",                        "-rogue",                       "Darkplaces-Rogue",             "id1",          "rogue",                "dp",                   "darkplaces"            }, // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
1447 { GAME_NEHAHRA,                 GAME_NORMAL,                    "nehahra",                      "-nehahra",                     "DarkPlaces-Nehahra",   "id1",          "nehahra",              "dp",                   "darkplaces"            }, // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
1448 { GAME_NEXUIZ,                  GAME_NEXUIZ,                    "nexuiz",                       "-nexuiz",                      "Nexuiz",                               "data",         NULL,                   "nexuiz",               "nexuiz"                        }, // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
1449 { GAME_XONOTIC,                 GAME_XONOTIC,                   "xonotic",                      "-xonotic",                     "Xonotic",                              "data",         NULL,                   "xonotic",              "xonotic"                       }, // COMMANDLINEOPTION: Game: -xonotic runs the multiplayer game Xonotic
1450 { GAME_TRANSFUSION,             GAME_TRANSFUSION,               "transfusion",          "-transfusion",         "Transfusion",                  "basetf",       NULL,                   "transfusion",  "transfusion"           }, // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
1451 { 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
1452 { 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)
1453 { GAME_BATTLEMECH,              GAME_BATTLEMECH,                "battlemech",           "-battlemech",          "Battlemech",                   "base",         NULL,                   "battlemech",   "battlemech"            }, // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
1454 { GAME_ZYMOTIC,                 GAME_ZYMOTIC,                   "zymotic",                      "-zymotic",                     "Zymotic",                              "basezym",      NULL,                   "zymotic",              "zymotic"                       }, // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
1455 { GAME_SETHERAL,                GAME_SETHERAL,                  "setheral",                     "-setheral",            "Setheral",                             "data",         NULL,                   "setheral",             "setheral"                      }, // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
1456 { GAME_SOM,                             GAME_NORMAL,                    "sonofman",                     "-som",                         "Son of Man",                   "id1",          "sonofman",             "som",                  "darkplaces"            }, // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
1457 { 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)
1458 { GAME_NEOTERIC,                GAME_NORMAL,                    "neoteric",                     "-neoteric",            "Neoteric",                             "id1",          "neobase",              "neo",                  "darkplaces"            }, // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
1459 { 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
1460 { GAME_PRYDON,                  GAME_NORMAL,                    "prydon",                       "-prydon",                      "PrydonGate",                   "id1",          "prydon",               "prydon",               "darkplaces"            }, // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
1461 { GAME_DELUXEQUAKE,             GAME_DELUXEQUAKE,               "dq",                           "-dq",                          "Deluxe Quake",                 "basedq",       "extradq",              "basedq",               "dq"                            }, // COMMANDLINEOPTION: Game: -dq runs the game Deluxe Quake
1462 { GAME_THEHUNTED,               GAME_THEHUNTED,                 "thehunted",            "-thehunted",           "The Hunted",                   "thdata",       NULL,                   "th",                   "thehunted"                     }, // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
1463 { GAME_DEFEATINDETAIL2, GAME_DEFEATINDETAIL2,   "did2",                         "-did2",                        "Defeat In Detail 2",   "data",         NULL,                   "did2_",                "did2"                          }, // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
1464 { GAME_DARSANA,                 GAME_DARSANA,                   "darsana",                      "-darsana",                     "Darsana",                              "ddata",        NULL,                   "darsana",              "darsana"                       }, // COMMANDLINEOPTION: Game: -darsana runs the game Darsana
1465 { GAME_CONTAGIONTHEORY, GAME_CONTAGIONTHEORY,   "contagiontheory",      "-contagiontheory",     "Contagion Theory",             "ctdata",       NULL,                   "ct",                   "contagiontheory"       }, // COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory
1466 { GAME_EDU2P,                   GAME_EDU2P,                             "edu2p",                        "-edu2p",                       "EDU2 Prototype",               "id1",          "edu2",                 "edu2_p",               "edu2prototype"         }, // COMMANDLINEOPTION: Game: -edu2p runs the game Edu2 prototype
1467 { GAME_PROPHECY,                GAME_PROPHECY,                  "prophecy",                     "-prophecy",            "Prophecy",                             "data",         NULL,                   "prophecy",             "prophecy"                      }, // COMMANDLINEOPTION: Game: -prophecy runs the game Prophecy
1468 { GAME_BLOODOMNICIDE,   GAME_BLOODOMNICIDE,             "omnicide",                     "-omnicide",            "Blood Omnicide",               "kain",         NULL,                   "omnicide",             "omnicide"                      }, // COMMANDLINEOPTION: Game: -omnicide runs the game Blood Omnicide
1469 { GAME_STEELSTORM,              GAME_STEELSTORM,                "steelstorm",           "-steelstorm",          "Steel-Storm",                  "gamedata",     NULL,                   "ss",                   "steelstorm"            }, // COMMANDLINEOPTION: Game: -steelstorm runs the game Steel Storm
1470 { GAME_STRAPBOMB,               GAME_STRAPBOMB,                 "strapbomb",            "-strapbomb",           "Strap-on-bomb Car",    "id1",          NULL,                   "strap",                "strapbomb"                     }, // COMMANDLINEOPTION: Game: -strapbomb runs the game Strap-on-bomb Car
1471 { GAME_MOONHELM,                GAME_MOONHELM,                  "moonhelm",                     "-moonhelm",            "MoonHelm",                             "data",         NULL,                   "mh",                   "moonhelm"                      }, // COMMANDLINEOPTION: Game: -moonhelm runs the game MoonHelm
1472 };
1473
1474 static void COM_SetGameType(int index);
1475 void COM_InitGameType (void)
1476 {
1477         char name [MAX_OSPATH];
1478         int i;
1479         int index = 0;
1480
1481         // check executable filename for keywords, but do it SMARTLY - only check the last path element
1482         FS_StripExtension(FS_FileWithoutPath(com_argv[0]), name, sizeof (name));
1483         COM_ToLowerString(name, name, sizeof (name));
1484         for (i = 1;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1485                 if (gamemode_info[i].prog_name && gamemode_info[i].prog_name[0] && strstr (name, gamemode_info[i].prog_name))
1486                 {
1487                         index = i;
1488                         break;
1489                 }
1490
1491         // check commandline options for keywords
1492         for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1493                 if (COM_CheckParm (gamemode_info[i].cmdline))
1494                 {
1495                         index = i;
1496                         break;
1497                 }
1498
1499         com_startupgamemode = gamemode_info[index].mode;
1500         com_startupgamegroup = gamemode_info[index].group;
1501         COM_SetGameType(index);
1502 }
1503
1504 void COM_ChangeGameTypeForGameDirs(void)
1505 {
1506         int i;
1507         int index = -1;
1508         // this will not not change the gamegroup
1509         // first check if a base game (single gamedir) matches
1510         for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1511         {
1512                 if (gamemode_info[i].group == com_startupgamegroup && !(gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]))
1513                 {
1514                         index = i;
1515                         break;
1516                 }
1517         }
1518         // now that we have a base game, see if there is a matching derivative game (two gamedirs)
1519         if (fs_numgamedirs)
1520         {
1521                 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1522                 {
1523                         if (gamemode_info[i].group == com_startupgamegroup && (gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]) && !strcasecmp(fs_gamedirs[0], gamemode_info[i].gamedirname2))
1524                         {
1525                                 index = i;
1526                                 break;
1527                         }
1528                 }
1529         }
1530         // we now have a good guess at which game this is meant to be...
1531         if (index >= 0 && gamemode != gamemode_info[index].mode)
1532                 COM_SetGameType(index);
1533 }
1534
1535 static void COM_SetGameType(int index)
1536 {
1537         int i, t;
1538         if (index < 0 || index >= (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0])))
1539                 index = 0;
1540         gamemode = gamemode_info[index].mode;
1541         gamename = gamemode_info[index].gamename;
1542         gamedirname1 = gamemode_info[index].gamedirname1;
1543         gamedirname2 = gamemode_info[index].gamedirname2;
1544         gamescreenshotname = gamemode_info[index].gamescreenshotname;
1545         gameuserdirname = gamemode_info[index].gameuserdirname;
1546
1547         if (gamemode == com_startupgamemode)
1548         {
1549                 if((t = COM_CheckParm("-customgamename")) && t + 1 < com_argc)
1550                         gamename = com_argv[t+1];
1551                 if((t = COM_CheckParm("-customgamedirname1")) && t + 1 < com_argc)
1552                         gamedirname1 = com_argv[t+1];
1553                 if((t = COM_CheckParm("-customgamedirname2")) && t + 1 < com_argc)
1554                         gamedirname2 = *com_argv[t+1] ? com_argv[t+1] : NULL;
1555                 if((t = COM_CheckParm("-customgamescreenshotname")) && t + 1 < com_argc)
1556                         gamescreenshotname = com_argv[t+1];
1557                 if((t = COM_CheckParm("-customgameuserdirname")) && t + 1 < com_argc)
1558                         gameuserdirname = com_argv[t+1];
1559         }
1560
1561         if (gamedirname2 && gamedirname2[0])
1562                 Con_Printf("Game is %s using base gamedirs %s %s", gamename, gamedirname1, gamedirname2);
1563         else
1564                 Con_Printf("Game is %s using base gamedir %s", gamename, gamedirname1);
1565         for (i = 0;i < fs_numgamedirs;i++)
1566         {
1567                 if (i == 0)
1568                         Con_Printf(", with mod gamedirs");
1569                 Con_Printf(" %s", fs_gamedirs[i]);
1570         }
1571         Con_Printf("\n");
1572 }
1573
1574
1575 /*
1576 ================
1577 COM_Init
1578 ================
1579 */
1580 void COM_Init_Commands (void)
1581 {
1582         int i, j, n;
1583         char com_cmdline[MAX_INPUTLINE];
1584
1585         Cvar_RegisterVariable (&registered);
1586         Cvar_RegisterVariable (&cmdline);
1587
1588         // reconstitute the command line for the cmdline externally visible cvar
1589         n = 0;
1590         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
1591         {
1592                 i = 0;
1593                 if (strstr(com_argv[j], " "))
1594                 {
1595                         // arg contains whitespace, store quotes around it
1596                         com_cmdline[n++] = '\"';
1597                         while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1598                                 com_cmdline[n++] = com_argv[j][i++];
1599                         com_cmdline[n++] = '\"';
1600                 }
1601                 else
1602                 {
1603                         while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1604                                 com_cmdline[n++] = com_argv[j][i++];
1605                 }
1606                 if (n < ((int)sizeof(com_cmdline) - 1))
1607                         com_cmdline[n++] = ' ';
1608                 else
1609                         break;
1610         }
1611         com_cmdline[n] = 0;
1612         Cvar_Set ("cmdline", com_cmdline);
1613 }
1614
1615 /*
1616 ============
1617 va
1618
1619 does a varargs printf into a temp buffer, so I don't need to have
1620 varargs versions of all text functions.
1621 FIXME: make this buffer size safe someday
1622 ============
1623 */
1624 char *va(const char *format, ...)
1625 {
1626         va_list argptr;
1627         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1628         static char string[8][1024], *s;
1629         static int stringindex = 0;
1630
1631         s = string[stringindex];
1632         stringindex = (stringindex + 1) & 7;
1633         va_start (argptr, format);
1634         dpvsnprintf (s, sizeof (string[0]), format,argptr);
1635         va_end (argptr);
1636
1637         return s;
1638 }
1639
1640
1641 //======================================
1642
1643 // snprintf and vsnprintf are NOT portable. Use their DP counterparts instead
1644
1645 #undef snprintf
1646 #undef vsnprintf
1647
1648 #ifdef WIN32
1649 # define snprintf _snprintf
1650 # define vsnprintf _vsnprintf
1651 #endif
1652
1653
1654 int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...)
1655 {
1656         va_list args;
1657         int result;
1658
1659         va_start (args, format);
1660         result = dpvsnprintf (buffer, buffersize, format, args);
1661         va_end (args);
1662
1663         return result;
1664 }
1665
1666
1667 int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args)
1668 {
1669         int result;
1670
1671 #if _MSC_VER >= 1400
1672         result = _vsnprintf_s (buffer, buffersize, _TRUNCATE, format, args);
1673 #else
1674         result = vsnprintf (buffer, buffersize, format, args);
1675 #endif
1676         if (result < 0 || (size_t)result >= buffersize)
1677         {
1678                 buffer[buffersize - 1] = '\0';
1679                 return -1;
1680         }
1681
1682         return result;
1683 }
1684
1685
1686 //======================================
1687
1688 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1689 {
1690         if (size_out == 0)
1691                 return;
1692
1693         if(utf8_enable.integer)
1694         {
1695                 *out = 0;
1696                 while(*in && size_out > 1)
1697                 {
1698                         int n;
1699                         Uchar ch = u8_getchar_utf8_enabled(in, &in);
1700                         ch = u8_tolower(ch);
1701                         n = u8_fromchar(ch, out, size_out);
1702                         if(n <= 0)
1703                                 break;
1704                         out += n;
1705                         size_out -= n;
1706                 }
1707                 return;
1708         }
1709
1710         while (*in && size_out > 1)
1711         {
1712                 if (*in >= 'A' && *in <= 'Z')
1713                         *out++ = *in++ + 'a' - 'A';
1714                 else
1715                         *out++ = *in++;
1716                 size_out--;
1717         }
1718         *out = '\0';
1719 }
1720
1721 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1722 {
1723         if (size_out == 0)
1724                 return;
1725
1726         if(utf8_enable.integer)
1727         {
1728                 *out = 0;
1729                 while(*in && size_out > 1)
1730                 {
1731                         int n;
1732                         Uchar ch = u8_getchar_utf8_enabled(in, &in);
1733                         ch = u8_toupper(ch);
1734                         n = u8_fromchar(ch, out, size_out);
1735                         if(n <= 0)
1736                                 break;
1737                         out += n;
1738                         size_out -= n;
1739                 }
1740                 return;
1741         }
1742
1743         while (*in && size_out > 1)
1744         {
1745                 if (*in >= 'a' && *in <= 'z')
1746                         *out++ = *in++ + 'A' - 'a';
1747                 else
1748                         *out++ = *in++;
1749                 size_out--;
1750         }
1751         *out = '\0';
1752 }
1753
1754 int COM_StringBeginsWith(const char *s, const char *match)
1755 {
1756         for (;*s && *match;s++, match++)
1757                 if (*s != *match)
1758                         return false;
1759         return true;
1760 }
1761
1762 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1763 {
1764         int argc, commentprefixlength;
1765         char *tokenbufend;
1766         const char *l;
1767         argc = 0;
1768         tokenbufend = tokenbuf + tokenbufsize;
1769         l = *text;
1770         commentprefixlength = 0;
1771         if (commentprefix)
1772                 commentprefixlength = (int)strlen(commentprefix);
1773         while (*l && *l != '\n' && *l != '\r')
1774         {
1775                 if (!ISWHITESPACE(*l))
1776                 {
1777                         if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1778                         {
1779                                 while (*l && *l != '\n' && *l != '\r')
1780                                         l++;
1781                                 break;
1782                         }
1783                         if (argc >= maxargc)
1784                                 return -1;
1785                         argv[argc++] = tokenbuf;
1786                         if (*l == '"')
1787                         {
1788                                 l++;
1789                                 while (*l && *l != '"')
1790                                 {
1791                                         if (tokenbuf >= tokenbufend)
1792                                                 return -1;
1793                                         *tokenbuf++ = *l++;
1794                                 }
1795                                 if (*l == '"')
1796                                         l++;
1797                         }
1798                         else
1799                         {
1800                                 while (!ISWHITESPACE(*l))
1801                                 {
1802                                         if (tokenbuf >= tokenbufend)
1803                                                 return -1;
1804                                         *tokenbuf++ = *l++;
1805                                 }
1806                         }
1807                         if (tokenbuf >= tokenbufend)
1808                                 return -1;
1809                         *tokenbuf++ = 0;
1810                 }
1811                 else
1812                         l++;
1813         }
1814         // line endings:
1815         // UNIX: \n
1816         // Mac: \r
1817         // Windows: \r\n
1818         if (*l == '\r')
1819                 l++;
1820         if (*l == '\n')
1821                 l++;
1822         *text = l;
1823         return argc;
1824 }
1825
1826 /*
1827 ============
1828 COM_StringLengthNoColors
1829
1830 calculates the visible width of a color coded string.
1831
1832 *valid is filled with TRUE if the string is a valid colored string (that is, if
1833 it does not end with an unfinished color code). If it gets filled with FALSE, a
1834 fix would be adding a STRING_COLOR_TAG at the end of the string.
1835
1836 valid can be set to NULL if the caller doesn't care.
1837
1838 For size_s, specify the maximum number of characters from s to use, or 0 to use
1839 all characters until the zero terminator.
1840 ============
1841 */
1842 size_t
1843 COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid)
1844 {
1845         const char *end = size_s ? (s + size_s) : NULL;
1846         size_t len = 0;
1847         for(;;)
1848         {
1849                 switch((s == end) ? 0 : *s)
1850                 {
1851                         case 0:
1852                                 if(valid)
1853                                         *valid = TRUE;
1854                                 return len;
1855                         case STRING_COLOR_TAG:
1856                                 ++s;
1857                                 switch((s == end) ? 0 : *s)
1858                                 {
1859                                         case STRING_COLOR_RGB_TAG_CHAR:
1860                                                 if (s+1 != end && isxdigit(s[1]) &&
1861                                                         s+2 != end && isxdigit(s[2]) &&
1862                                                         s+3 != end && isxdigit(s[3]) )
1863                                                 {
1864                                                         s+=3;
1865                                                         break;
1866                                                 }
1867                                                 ++len; // STRING_COLOR_TAG
1868                                                 ++len; // STRING_COLOR_RGB_TAG_CHAR
1869                                                 break;
1870                                         case 0: // ends with unfinished color code!
1871                                                 ++len;
1872                                                 if(valid)
1873                                                         *valid = FALSE;
1874                                                 return len;
1875                                         case STRING_COLOR_TAG: // escaped ^
1876                                                 ++len;
1877                                                 break;
1878                                         case '0': case '1': case '2': case '3': case '4':
1879                                         case '5': case '6': case '7': case '8': case '9': // color code
1880                                                 break;
1881                                         default: // not a color code
1882                                                 ++len; // STRING_COLOR_TAG
1883                                                 ++len; // the character
1884                                                 break;
1885                                 }
1886                                 break;
1887                         default:
1888                                 ++len;
1889                                 break;
1890                 }
1891                 ++s;
1892         }
1893         // never get here
1894 }
1895
1896 /*
1897 ============
1898 COM_StringDecolorize
1899
1900 removes color codes from a string.
1901
1902 If escape_carets is true, the resulting string will be safe for printing. If
1903 escape_carets is false, the function will just strip color codes (for logging
1904 for example).
1905
1906 If the output buffer size did not suffice for converting, the function returns
1907 FALSE. Generally, if escape_carets is false, the output buffer needs
1908 strlen(str)+1 bytes, and if escape_carets is true, it can need strlen(str)*1.5+2
1909 bytes. In any case, the function makes sure that the resulting string is
1910 zero terminated.
1911
1912 For size_in, specify the maximum number of characters from in to use, or 0 to use
1913 all characters until the zero terminator.
1914 ============
1915 */
1916 qboolean
1917 COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets)
1918 {
1919 #define APPEND(ch) do { if(--size_out) { *out++ = (ch); } else { *out++ = 0; return FALSE; } } while(0)
1920         const char *end = size_in ? (in + size_in) : NULL;
1921         if(size_out < 1)
1922                 return FALSE;
1923         for(;;)
1924         {
1925                 switch((in == end) ? 0 : *in)
1926                 {
1927                         case 0:
1928                                 *out++ = 0;
1929                                 return TRUE;
1930                         case STRING_COLOR_TAG:
1931                                 ++in;
1932                                 switch((in == end) ? 0 : *in)
1933                                 {
1934                                         case STRING_COLOR_RGB_TAG_CHAR:
1935                                                 if (in+1 != end && isxdigit(in[1]) &&
1936                                                         in+2 != end && isxdigit(in[2]) &&
1937                                                         in+3 != end && isxdigit(in[3]) )
1938                                                 {
1939                                                         in+=3;
1940                                                         break;
1941                                                 }
1942                                                 APPEND(STRING_COLOR_TAG);
1943                                                 if(escape_carets)
1944                                                         APPEND(STRING_COLOR_TAG);
1945                                                 APPEND(STRING_COLOR_RGB_TAG_CHAR);
1946                                                 break;
1947                                         case 0: // ends with unfinished color code!
1948                                                 APPEND(STRING_COLOR_TAG);
1949                                                 // finish the code by appending another caret when escaping
1950                                                 if(escape_carets)
1951                                                         APPEND(STRING_COLOR_TAG);
1952                                                 *out++ = 0;
1953                                                 return TRUE;
1954                                         case STRING_COLOR_TAG: // escaped ^
1955                                                 APPEND(STRING_COLOR_TAG);
1956                                                 // append a ^ twice when escaping
1957                                                 if(escape_carets)
1958                                                         APPEND(STRING_COLOR_TAG);
1959                                                 break;
1960                                         case '0': case '1': case '2': case '3': case '4':
1961                                         case '5': case '6': case '7': case '8': case '9': // color code
1962                                                 break;
1963                                         default: // not a color code
1964                                                 APPEND(STRING_COLOR_TAG);
1965                                                 APPEND(*in);
1966                                                 break;
1967                                 }
1968                                 break;
1969                         default:
1970                                 APPEND(*in);
1971                                 break;
1972                 }
1973                 ++in;
1974         }
1975         // never get here
1976 #undef APPEND
1977 }
1978
1979 // written by Elric, thanks Elric!
1980 char *SearchInfostring(const char *infostring, const char *key)
1981 {
1982         static char value [MAX_INPUTLINE];
1983         char crt_key [MAX_INPUTLINE];
1984         size_t value_ind, key_ind;
1985         char c;
1986
1987         if (*infostring++ != '\\')
1988                 return NULL;
1989
1990         value_ind = 0;
1991         for (;;)
1992         {
1993                 key_ind = 0;
1994
1995                 // Get the key name
1996                 for (;;)
1997                 {
1998                         c = *infostring++;
1999
2000                         if (c == '\0')
2001                                 return NULL;
2002                         if (c == '\\' || key_ind == sizeof (crt_key) - 1)
2003                         {
2004                                 crt_key[key_ind] = '\0';
2005                                 break;
2006                         }
2007
2008                         crt_key[key_ind++] = c;
2009                 }
2010
2011                 // If it's the key we are looking for, save it in "value"
2012                 if (!strcmp(crt_key, key))
2013                 {
2014                         for (;;)
2015                         {
2016                                 c = *infostring++;
2017
2018                                 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
2019                                 {
2020                                         value[value_ind] = '\0';
2021                                         return value;
2022                                 }
2023
2024                                 value[value_ind++] = c;
2025                         }
2026                 }
2027
2028                 // Else, skip the value
2029                 for (;;)
2030                 {
2031                         c = *infostring++;
2032
2033                         if (c == '\0')
2034                                 return NULL;
2035                         if (c == '\\')
2036                                 break;
2037                 }
2038         }
2039 }
2040
2041 void InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
2042 {
2043         int pos = 0, j;
2044         size_t keylength;
2045         if (!key)
2046                 key = "";
2047         keylength = strlen(key);
2048         if (valuelength < 1 || !value)
2049         {
2050                 Con_Printf("InfoString_GetValue: no room in value\n");
2051                 return;
2052         }
2053         value[0] = 0;
2054         if (strchr(key, '\\'))
2055         {
2056                 Con_Printf("InfoString_GetValue: key name \"%s\" contains \\ which is not possible in an infostring\n", key);
2057                 return;
2058         }
2059         if (strchr(key, '\"'))
2060         {
2061                 Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key);
2062                 return;
2063         }
2064         if (!key[0])
2065         {
2066                 Con_Printf("InfoString_GetValue: can not look up a key with no name\n");
2067                 return;
2068         }
2069         while (buffer[pos] == '\\')
2070         {
2071                 if (!memcmp(buffer + pos+1, key, keylength))
2072                 {
2073                         for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2074                         pos++;
2075                         for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++)
2076                                 value[j] = buffer[pos+j];
2077                         value[j] = 0;
2078                         return;
2079                 }
2080                 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2081                 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2082         }
2083         // if we reach this point the key was not found
2084 }
2085
2086 void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value)
2087 {
2088         int pos = 0, pos2;
2089         size_t keylength;
2090         if (!key)
2091                 key = "";
2092         if (!value)
2093                 value = "";
2094         keylength = strlen(key);
2095         if (strchr(key, '\\') || strchr(value, '\\'))
2096         {
2097                 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \\ which is not possible to store in an infostring\n", key, value);
2098                 return;
2099         }
2100         if (strchr(key, '\"') || strchr(value, '\"'))
2101         {
2102                 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \" which is not allowed in an infostring\n", key, value);
2103                 return;
2104         }
2105         if (!key[0])
2106         {
2107                 Con_Printf("InfoString_SetValue: can not set a key with no name\n");
2108                 return;
2109         }
2110         while (buffer[pos] == '\\')
2111         {
2112                 if (!memcmp(buffer + pos+1, key, keylength))
2113                         break;
2114                 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2115                 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2116         }
2117         // if we found the key, find the end of it because we will be replacing it
2118         pos2 = pos;
2119         if (buffer[pos] == '\\')
2120         {
2121                 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2122                 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2123         }
2124         if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2))
2125         {
2126                 Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value);
2127                 return;
2128         }
2129         if (value && value[0])
2130         {
2131                 // set the key/value and append the remaining text
2132                 char tempbuffer[4096];
2133                 strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer));
2134                 dpsnprintf(buffer + pos, bufferlength - pos, "\\%s\\%s%s", key, value, tempbuffer);
2135         }
2136         else
2137         {
2138                 // just remove the key from the text
2139                 strlcpy(buffer + pos, buffer + pos2, bufferlength - pos);
2140         }
2141 }
2142
2143 void InfoString_Print(char *buffer)
2144 {
2145         int i;
2146         char key[2048];
2147         char value[2048];
2148         while (*buffer)
2149         {
2150                 if (*buffer != '\\')
2151                 {
2152                         Con_Printf("InfoString_Print: corrupt string\n");
2153                         return;
2154                 }
2155                 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2156                         if (i < (int)sizeof(key)-1)
2157                                 key[i++] = *buffer;
2158                 key[i] = 0;
2159                 if (*buffer != '\\')
2160                 {
2161                         Con_Printf("InfoString_Print: corrupt string\n");
2162                         return;
2163                 }
2164                 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2165                         if (i < (int)sizeof(value)-1)
2166                                 value[i++] = *buffer;
2167                 value[i] = 0;
2168                 // empty value is an error case
2169                 Con_Printf("%20s %s\n", key, value[0] ? value : "NO VALUE");
2170         }
2171 }
2172
2173 //========================================================
2174 // strlcat and strlcpy, from OpenBSD
2175
2176 /*
2177  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
2178  *
2179  * Permission to use, copy, modify, and distribute this software for any
2180  * purpose with or without fee is hereby granted, provided that the above
2181  * copyright notice and this permission notice appear in all copies.
2182  *
2183  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2184  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2185  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2186  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2187  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2188  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2189  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2190  */
2191
2192 /*      $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
2193 /*      $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
2194
2195
2196 #ifndef HAVE_STRLCAT
2197 size_t
2198 strlcat(char *dst, const char *src, size_t siz)
2199 {
2200         register char *d = dst;
2201         register const char *s = src;
2202         register size_t n = siz;
2203         size_t dlen;
2204
2205         /* Find the end of dst and adjust bytes left but don't go past end */
2206         while (n-- != 0 && *d != '\0')
2207                 d++;
2208         dlen = d - dst;
2209         n = siz - dlen;
2210
2211         if (n == 0)
2212                 return(dlen + strlen(s));
2213         while (*s != '\0') {
2214                 if (n != 1) {
2215                         *d++ = *s;
2216                         n--;
2217                 }
2218                 s++;
2219         }
2220         *d = '\0';
2221
2222         return(dlen + (s - src));       /* count does not include NUL */
2223 }
2224 #endif  // #ifndef HAVE_STRLCAT
2225
2226
2227 #ifndef HAVE_STRLCPY
2228 size_t
2229 strlcpy(char *dst, const char *src, size_t siz)
2230 {
2231         register char *d = dst;
2232         register const char *s = src;
2233         register size_t n = siz;
2234
2235         /* Copy as many bytes as will fit */
2236         if (n != 0 && --n != 0) {
2237                 do {
2238                         if ((*d++ = *s++) == 0)
2239                                 break;
2240                 } while (--n != 0);
2241         }
2242
2243         /* Not enough room in dst, add NUL and traverse rest of src */
2244         if (n == 0) {
2245                 if (siz != 0)
2246                         *d = '\0';              /* NUL-terminate dst */
2247                 while (*s++)
2248                         ;
2249         }
2250
2251         return(s - src - 1);    /* count does not include NUL */
2252 }
2253
2254 #endif  // #ifndef HAVE_STRLCPY
2255
2256 void FindFraction(double val, int *num, int *denom, int denomMax)
2257 {
2258         int i;
2259         double bestdiff;
2260         // initialize
2261         bestdiff = fabs(val);
2262         *num = 0;
2263         *denom = 1;
2264
2265         for(i = 1; i <= denomMax; ++i)
2266         {
2267                 int inum = (int) floor(0.5 + val * i);
2268                 double diff = fabs(val - inum / (double)i);
2269                 if(diff < bestdiff)
2270                 {
2271                         bestdiff = diff;
2272                         *num = inum;
2273                         *denom = i;
2274                 }
2275         }
2276 }
2277
2278 // decodes an XPM from C syntax
2279 char **XPM_DecodeString(const char *in)
2280 {
2281         static char *tokens[257];
2282         static char lines[257][512];
2283         size_t line = 0;
2284
2285         // skip until "{" token
2286         while(COM_ParseToken_QuakeC(&in, false) && strcmp(com_token, "{"));
2287
2288         // now, read in succession: string, comma-or-}
2289         while(COM_ParseToken_QuakeC(&in, false))
2290         {
2291                 tokens[line] = lines[line];
2292                 strlcpy(lines[line++], com_token, sizeof(lines[0]));
2293                 if(!COM_ParseToken_QuakeC(&in, false))
2294                         return NULL;
2295                 if(!strcmp(com_token, "}"))
2296                         break;
2297                 if(strcmp(com_token, ","))
2298                         return NULL;
2299                 if(line >= sizeof(tokens) / sizeof(tokens[0]))
2300                         return NULL;
2301         }
2302
2303         return tokens;
2304 }
2305
2306 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2307 static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes)
2308 {
2309         unsigned char i0 = (bytes > 0) ? in[0] : 0;
2310         unsigned char i1 = (bytes > 1) ? in[1] : 0;
2311         unsigned char i2 = (bytes > 2) ? in[2] : 0;
2312         unsigned char o0 = base64[i0 >> 2];
2313         unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077];
2314         unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077];
2315         unsigned char o3 = base64[i2 & 077];
2316         out[0] = (bytes > 0) ? o0 : '?';
2317         out[1] = (bytes > 0) ? o1 : '?';
2318         out[2] = (bytes > 1) ? o2 : '=';
2319         out[3] = (bytes > 2) ? o3 : '=';
2320 }
2321
2322 size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen)
2323 {
2324         size_t blocks, i;
2325         // expand the out-buffer
2326         blocks = (buflen + 2) / 3;
2327         if(blocks*4 > outbuflen)
2328                 return 0;
2329         for(i = blocks; i > 0; )
2330         {
2331                 --i;
2332                 base64_3to4(buf + 3*i, buf + 4*i, buflen - 3*i);
2333         }
2334         return blocks * 4;
2335 }