- Removed Con_SafePrint and Con_SafePrintf since they now does the same things as...
[divverent/darkplaces.git] / common.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // common.c -- misc functions used in client and server
21
22 #include <stdlib.h>
23 #include <fcntl.h>
24 #ifndef WIN32
25 #include <unistd.h>
26 #endif
27
28 #include "quakedef.h"
29
30 cvar_t registered = {0, "registered","0"};
31 cvar_t cmdline = {0, "cmdline","0"};
32
33 extern qboolean fs_modified;   // set true if using non-id files
34
35 char com_token[1024];
36 int com_argc;
37 const char **com_argv;
38
39 // LordHavoc: made commandline 1024 characters instead of 256
40 #define CMDLINE_LENGTH  1024
41 char com_cmdline[CMDLINE_LENGTH];
42
43 int gamemode;
44 const char *gamename;
45 const char *gamedirname;
46 const char *gamescreenshotname;
47 char com_modname[MAX_OSPATH] = "";
48
49
50 /*
51 ============================================================================
52
53                                         BYTE ORDER FUNCTIONS
54
55 ============================================================================
56 */
57
58 short   ShortSwap (short l)
59 {
60         qbyte    b1,b2;
61
62         b1 = l&255;
63         b2 = (l>>8)&255;
64
65         return (b1<<8) + b2;
66 }
67
68 int    LongSwap (int l)
69 {
70         qbyte    b1,b2,b3,b4;
71
72         b1 = l&255;
73         b2 = (l>>8)&255;
74         b3 = (l>>16)&255;
75         b4 = (l>>24)&255;
76
77         return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
78 }
79
80 float FloatSwap (float f)
81 {
82         union
83         {
84                 float   f;
85                 qbyte    b[4];
86         } dat1, dat2;
87
88
89         dat1.f = f;
90         dat2.b[0] = dat1.b[3];
91         dat2.b[1] = dat1.b[2];
92         dat2.b[2] = dat1.b[1];
93         dat2.b[3] = dat1.b[0];
94         return dat2.f;
95 }
96
97
98 // Extract integers from buffers
99
100 unsigned int BuffBigLong (const qbyte *buffer)
101 {
102         return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
103 }
104
105 unsigned short BuffBigShort (const qbyte *buffer)
106 {
107         return (buffer[0] << 8) | buffer[1];
108 }
109
110 unsigned int BuffLittleLong (const qbyte *buffer)
111 {
112         return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
113 }
114
115 unsigned short BuffLittleShort (const qbyte *buffer)
116 {
117         return (buffer[1] << 8) | buffer[0];
118 }
119
120
121 /*
122 ============================================================================
123
124                                         CRC FUNCTIONS
125
126 ============================================================================
127 */
128
129 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
130 // and the initial and final xor values shown below...  in other words, the
131 // CCITT standard CRC used by XMODEM
132
133 #define CRC_INIT_VALUE  0xffff
134 #define CRC_XOR_VALUE   0x0000
135
136 static unsigned short crctable[256] =
137 {
138         0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
139         0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
140         0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
141         0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
142         0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
143         0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
144         0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
145         0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
146         0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
147         0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
148         0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
149         0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
150         0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
151         0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
152         0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
153         0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
154         0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
155         0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
156         0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
157         0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
158         0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
159         0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
160         0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
161         0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
162         0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
163         0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
164         0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
165         0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
166         0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
167         0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
168         0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
169         0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
170 };
171
172 unsigned short CRC_Block(qbyte *data, int size)
173 {
174         unsigned short crc = CRC_INIT_VALUE;
175         while (size--)
176                 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)];
177         return crc ^ CRC_XOR_VALUE;
178 }
179
180
181 /*
182 ==============================================================================
183
184                         MESSAGE IO FUNCTIONS
185
186 Handles byte ordering and avoids alignment errors
187 ==============================================================================
188 */
189
190 //
191 // writing functions
192 //
193
194 void MSG_WriteChar (sizebuf_t *sb, int c)
195 {
196         qbyte    *buf;
197
198         buf = SZ_GetSpace (sb, 1);
199         buf[0] = c;
200 }
201
202 void MSG_WriteByte (sizebuf_t *sb, int c)
203 {
204         qbyte    *buf;
205
206         buf = SZ_GetSpace (sb, 1);
207         buf[0] = c;
208 }
209
210 void MSG_WriteShort (sizebuf_t *sb, int c)
211 {
212         qbyte    *buf;
213
214         buf = SZ_GetSpace (sb, 2);
215         buf[0] = c&0xff;
216         buf[1] = c>>8;
217 }
218
219 void MSG_WriteLong (sizebuf_t *sb, int c)
220 {
221         qbyte    *buf;
222
223         buf = SZ_GetSpace (sb, 4);
224         buf[0] = c&0xff;
225         buf[1] = (c>>8)&0xff;
226         buf[2] = (c>>16)&0xff;
227         buf[3] = c>>24;
228 }
229
230 void MSG_WriteFloat (sizebuf_t *sb, float f)
231 {
232         union
233         {
234                 float   f;
235                 int     l;
236         } dat;
237
238
239         dat.f = f;
240         dat.l = LittleLong (dat.l);
241
242         SZ_Write (sb, &dat.l, 4);
243 }
244
245 void MSG_WriteString (sizebuf_t *sb, const char *s)
246 {
247         if (!s)
248                 SZ_Write (sb, "", 1);
249         else
250                 SZ_Write (sb, s, strlen(s)+1);
251 }
252
253 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
254 {
255         if (f >= 0)
256                 MSG_WriteShort (sb, (int)(f * 8.0 + 0.5));
257         else
258                 MSG_WriteShort (sb, (int)(f * 8.0 - 0.5));
259 }
260
261 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
262 {
263         if (f >= 0)
264                 MSG_WriteShort (sb, (int)(f + 0.5));
265         else
266                 MSG_WriteShort (sb, (int)(f - 0.5));
267 }
268
269 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
270 {
271         MSG_WriteFloat (sb, f);
272 }
273
274 void MSG_WriteCoord (sizebuf_t *sb, float f, int protocol)
275 {
276         if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_NEHAHRAMOVIE)
277                 MSG_WriteCoord13i (sb, f);
278         else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6)
279                 MSG_WriteCoord32f (sb, f);
280         else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
281                 MSG_WriteCoord16i (sb, f);
282         else
283                 Host_Error("MSG_WriteCoord: unknown protocol\n");
284 }
285
286 void MSG_WriteVector (sizebuf_t *sb, float *v, int protocol)
287 {
288         MSG_WriteCoord (sb, v[0], protocol);
289         MSG_WriteCoord (sb, v[1], protocol);
290         MSG_WriteCoord (sb, v[2], protocol);
291 }
292
293 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
294 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
295 {
296         if (f >= 0)
297                 MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255);
298         else
299                 MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255);
300 }
301
302 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
303 {
304         if (f >= 0)
305                 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535);
306         else
307                 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535);
308 }
309
310 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
311 {
312         MSG_WriteFloat (sb, f);
313 }
314
315 void MSG_WriteAngle (sizebuf_t *sb, float f, int protocol)
316 {
317         if (protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6)
318                 MSG_WriteAngle16i (sb, f);
319         else
320                 MSG_WriteAngle8i (sb, f);
321 }
322
323 //
324 // reading functions
325 //
326 int msg_readcount;
327 qboolean msg_badread;
328
329 void MSG_BeginReading (void)
330 {
331         msg_readcount = 0;
332         msg_badread = false;
333 }
334
335 int MSG_ReadLittleShort (void)
336 {
337         if (msg_readcount+2 > net_message.cursize)
338         {
339                 msg_badread = true;
340                 return -1;
341         }
342         msg_readcount += 2;
343         return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
344 }
345
346 int MSG_ReadBigShort (void)
347 {
348         if (msg_readcount+2 > net_message.cursize)
349         {
350                 msg_badread = true;
351                 return -1;
352         }
353         msg_readcount += 2;
354         return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
355 }
356
357 int MSG_ReadLittleLong (void)
358 {
359         if (msg_readcount+4 > net_message.cursize)
360         {
361                 msg_badread = true;
362                 return -1;
363         }
364         msg_readcount += 4;
365         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);
366 }
367
368 int MSG_ReadBigLong (void)
369 {
370         if (msg_readcount+4 > net_message.cursize)
371         {
372                 msg_badread = true;
373                 return -1;
374         }
375         msg_readcount += 4;
376         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];
377 }
378
379 float MSG_ReadLittleFloat (void)
380 {
381         union
382         {
383                 float f;
384                 int l;
385         } dat;
386         if (msg_readcount+4 > net_message.cursize)
387         {
388                 msg_badread = true;
389                 return -1;
390         }
391         msg_readcount += 4;
392         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);
393         return dat.f;
394 }
395
396 float MSG_ReadBigFloat (void)
397 {
398         union
399         {
400                 float f;
401                 int l;
402         } dat;
403         if (msg_readcount+4 > net_message.cursize)
404         {
405                 msg_badread = true;
406                 return -1;
407         }
408         msg_readcount += 4;
409         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];
410         return dat.f;
411 }
412
413 char *MSG_ReadString (void)
414 {
415         static char string[2048];
416         int l,c;
417         for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadChar()) != -1 && c != 0;l++)
418                 string[l] = c;
419         string[l] = 0;
420         return string;
421 }
422
423 int MSG_ReadBytes (int numbytes, unsigned char *out)
424 {
425         int l, c;
426         for (l = 0;l < numbytes && (c = MSG_ReadChar()) != -1;l++)
427                 out[l] = c;
428         return l;
429 }
430
431 float MSG_ReadCoord13i (void)
432 {
433         return MSG_ReadLittleShort() * (1.0/8.0);
434 }
435
436 float MSG_ReadCoord16i (void)
437 {
438         return (signed short) MSG_ReadLittleShort();
439 }
440
441 float MSG_ReadCoord32f (void)
442 {
443         return MSG_ReadLittleFloat();
444 }
445
446 float MSG_ReadCoord (int protocol)
447 {
448         if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_NEHAHRAMOVIE)
449                 return MSG_ReadCoord13i();
450         else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6)
451                 return MSG_ReadCoord32f();
452         else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
453                 return MSG_ReadCoord16i();
454         Host_Error("MSG_ReadCoord: unknown protocol\n");
455         return 0;
456 }
457
458 void MSG_ReadVector (float *v, int protocol)
459 {
460         v[0] = MSG_ReadCoord(protocol);
461         v[1] = MSG_ReadCoord(protocol);
462         v[2] = MSG_ReadCoord(protocol);
463 }
464
465 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
466 float MSG_ReadAngle8i (void)
467 {
468         return (signed char) MSG_ReadByte () * (360.0/256.0);
469 }
470
471 float MSG_ReadAngle16i (void)
472 {
473         return (signed short)MSG_ReadShort () * (360.0/65536.0);
474 }
475
476 float MSG_ReadAngle32f (void)
477 {
478         return MSG_ReadFloat ();
479 }
480
481 float MSG_ReadAngle (int protocol)
482 {
483         if (protocol == PROTOCOL_DARKPLACES5 || protocol == PROTOCOL_DARKPLACES6)
484                 return MSG_ReadAngle16i ();
485         else
486                 return MSG_ReadAngle8i ();
487 }
488
489
490 //===========================================================================
491
492 void SZ_Alloc (sizebuf_t *buf, int startsize, const char *name)
493 {
494         if (startsize < 256)
495                 startsize = 256;
496         buf->mempool = Mem_AllocPool(name, 0, NULL);
497         buf->data = Mem_Alloc(buf->mempool, startsize);
498         buf->maxsize = startsize;
499         buf->cursize = 0;
500 }
501
502
503 void SZ_Free (sizebuf_t *buf)
504 {
505         Mem_FreePool(&buf->mempool);
506         buf->data = NULL;
507         buf->maxsize = 0;
508         buf->cursize = 0;
509 }
510
511 void SZ_Clear (sizebuf_t *buf)
512 {
513         buf->cursize = 0;
514 }
515
516 void *SZ_GetSpace (sizebuf_t *buf, int length)
517 {
518         void *data;
519
520         if (buf->cursize + length > buf->maxsize)
521         {
522                 if (!buf->allowoverflow)
523                         Host_Error ("SZ_GetSpace: overflow without allowoverflow set\n");
524
525                 if (length > buf->maxsize)
526                         Host_Error ("SZ_GetSpace: %i is > full buffer size\n", length);
527
528                 buf->overflowed = true;
529                 Con_Print("SZ_GetSpace: overflow\n");
530                 SZ_Clear (buf);
531         }
532
533         data = buf->data + buf->cursize;
534         buf->cursize += length;
535
536         return data;
537 }
538
539 void SZ_Write (sizebuf_t *buf, const void *data, int length)
540 {
541         memcpy (SZ_GetSpace(buf,length),data,length);
542 }
543
544 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
545 // attention, it has been eradicated from here, its only (former) use in
546 // all of darkplaces.
547
548 static char *hexchar = "0123456789ABCDEF";
549 void Com_HexDumpToConsole(const qbyte *data, int size)
550 {
551         int i, j, n;
552         char text[1024];
553         char *cur, *flushpointer;
554         const qbyte *d;
555         cur = text;
556         flushpointer = text + 512;
557         for (i = 0;i < size;)
558         {
559                 n = 16;
560                 if (n > size - i)
561                         n = size - i;
562                 d = data + i;
563                 // print offset
564                 *cur++ = hexchar[(i >> 12) & 15];
565                 *cur++ = hexchar[(i >>  8) & 15];
566                 *cur++ = hexchar[(i >>  4) & 15];
567                 *cur++ = hexchar[(i >>  0) & 15];
568                 *cur++ = ':';
569                 // print hex
570                 for (j = 0;j < 16;j++)
571                 {
572                         if (j < n)
573                         {
574                                 *cur++ = hexchar[(d[j] >> 4) & 15];
575                                 *cur++ = hexchar[(d[j] >> 0) & 15];
576                         }
577                         else
578                         {
579                                 *cur++ = ' ';
580                                 *cur++ = ' ';
581                         }
582                         if ((j & 3) == 3)
583                                 *cur++ = ' ';
584                 }
585                 // print text
586                 for (j = 0;j < 16;j++)
587                 {
588                         if (j < n)
589                         {
590                                 if (d[j] >= ' ' && d[j] <= 127)
591                                         *cur++ = d[j];
592                                 else
593                                         *cur++ = '.';
594                         }
595                         else
596                                 *cur++ = ' ';
597                 }
598                 *cur++ = '\n';
599                 i += n;
600                 if (cur >= flushpointer || i >= size)
601                 {
602                         *cur++ = 0;
603                         Con_Print(text);
604                         cur = text;
605                 }
606         }
607 }
608
609 void SZ_HexDumpToConsole(const sizebuf_t *buf)
610 {
611         Com_HexDumpToConsole(buf->data, buf->cursize);
612 }
613
614
615 //============================================================================
616
617
618 /*
619 ==============
620 COM_ParseToken
621
622 Parse a token out of a string
623 ==============
624 */
625 int COM_ParseToken(const char **datapointer, int returnnewline)
626 {
627         int len;
628         const char *data = *datapointer;
629
630         len = 0;
631         com_token[0] = 0;
632
633         if (!data)
634         {
635                 *datapointer = NULL;
636                 return false;
637         }
638
639 // skip whitespace
640 skipwhite:
641         for (;*data <= ' ' && (*data != '\n' || !returnnewline);data++)
642         {
643                 if (*data == 0)
644                 {
645                         // end of file
646                         *datapointer = NULL;
647                         return false;
648                 }
649         }
650
651         if (data[0] == '/' && data[1] == '/')
652         {
653                 // comment
654                 while (*data && *data != '\n')
655                         data++;
656                 goto skipwhite;
657         }
658         else if (data[0] == '/' && data[1] == '*')
659         {
660                 // comment
661                 data++;
662                 while (*data && (data[0] != '*' || data[1] != '/'))
663                         data++;
664                 data += 2;
665                 goto skipwhite;
666         }
667         else if (*data == '\"')
668         {
669                 // quoted string
670                 for (data++;*data != '\"';data++)
671                 {
672                         if (*data == '\\' && data[1] == '"' )
673                                 data++;
674                         if (!*data || len >= (int)sizeof(com_token) - 1)
675                         {
676                                 com_token[0] = 0;
677                                 *datapointer = NULL;
678                                 return false;
679                         }
680                         com_token[len++] = *data;
681                 }
682                 com_token[len] = 0;
683                 *datapointer = data+1;
684                 return true;
685         }
686         else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
687         {
688                 // single character
689                 com_token[len++] = *data++;
690                 com_token[len] = 0;
691                 *datapointer = data;
692                 return true;
693         }
694         else
695         {
696                 // regular word
697                 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';';data++)
698                 {
699                         if (len >= (int)sizeof(com_token) - 1)
700                         {
701                                 com_token[0] = 0;
702                                 *datapointer = NULL;
703                                 return false;
704                         }
705                         com_token[len++] = *data;
706                 }
707                 com_token[len] = 0;
708                 *datapointer = data;
709                 return true;
710         }
711 }
712
713 /*
714 ==============
715 COM_ParseTokenConsole
716
717 Parse a token out of a string, behaving like the qwcl console
718 ==============
719 */
720 int COM_ParseTokenConsole(const char **datapointer)
721 {
722         int len;
723         const char *data = *datapointer;
724
725         len = 0;
726         com_token[0] = 0;
727
728         if (!data)
729         {
730                 *datapointer = NULL;
731                 return false;
732         }
733
734 // skip whitespace
735 skipwhite:
736         for (;*data <= ' ';data++)
737         {
738                 if (*data == 0)
739                 {
740                         // end of file
741                         *datapointer = NULL;
742                         return false;
743                 }
744         }
745
746         if (*data == '/' && data[1] == '/')
747         {
748                 // comment
749                 while (*data && *data != '\n')
750                         data++;
751                 goto skipwhite;
752         }
753         else if (*data == '\"')
754         {
755                 // quoted string
756                 for (data++;*data != '\"';data++)
757                 {
758                         if (!*data || len >= (int)sizeof(com_token) - 1)
759                         {
760                                 com_token[0] = 0;
761                                 *datapointer = NULL;
762                                 return false;
763                         }
764                         com_token[len++] = *data;
765                 }
766                 com_token[len] = 0;
767                 *datapointer = data+1;
768                 return true;
769         }
770         else
771         {
772                 // regular word
773                 for (;*data > ' ';data++)
774                 {
775                         if (len >= (int)sizeof(com_token) - 1)
776                         {
777                                 com_token[0] = 0;
778                                 *datapointer = NULL;
779                                 return false;
780                         }
781                         com_token[len++] = *data;
782                 }
783                 com_token[len] = 0;
784                 *datapointer = data;
785                 return true;
786         }
787 }
788
789
790 /*
791 ================
792 COM_CheckParm
793
794 Returns the position (1 to argc-1) in the program's argument list
795 where the given parameter apears, or 0 if not present
796 ================
797 */
798 int COM_CheckParm (const char *parm)
799 {
800         int i;
801
802         for (i=1 ; i<com_argc ; i++)
803         {
804                 if (!com_argv[i])
805                         continue;               // NEXTSTEP sometimes clears appkit vars.
806                 if (!strcmp (parm,com_argv[i]))
807                         return i;
808         }
809
810         return 0;
811 }
812
813 /*
814 ================
815 COM_CheckRegistered
816
817 Looks for the pop.txt file and verifies it.
818 Sets the "registered" cvar.
819 Immediately exits out if an alternate game was attempted to be started without
820 being registered.
821 ================
822 */
823 void COM_CheckRegistered (void)
824 {
825         Cvar_Set ("cmdline", com_cmdline);
826
827         if (!FS_FileExists("gfx/pop.lmp"))
828         {
829                 if (fs_modified)
830                         Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
831                 else
832                         Con_Print("Playing shareware version.\n");
833                 return;
834         }
835
836         Cvar_Set ("registered", "1");
837         Con_Print("Playing registered version.\n");
838 }
839
840
841 /*
842 ================
843 COM_InitArgv
844 ================
845 */
846 void COM_InitArgv (void)
847 {
848         int i, j, n;
849         // reconstitute the command line for the cmdline externally visible cvar
850         n = 0;
851         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
852         {
853                 i = 0;
854                 if (strstr(com_argv[j], " "))
855                 {
856                         // arg contains whitespace, store quotes around it
857                         com_cmdline[n++] = '\"';
858                         while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
859                                 com_cmdline[n++] = com_argv[j][i++];
860                         com_cmdline[n++] = '\"';
861                 }
862                 else
863                 {
864                         while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
865                                 com_cmdline[n++] = com_argv[j][i++];
866                 }
867                 if (n < (CMDLINE_LENGTH - 1))
868                         com_cmdline[n++] = ' ';
869                 else
870                         break;
871         }
872         com_cmdline[n] = 0;
873 }
874
875
876 //===========================================================================
877
878 // Game mods
879
880 typedef struct
881 {
882         const char* prog_name;
883         const char* cmdline;
884         const char* gamename;
885         const char* gamedirname;
886         const char* gamescreenshotname;
887 } gamemode_info_t;
888
889 static const gamemode_info_t gamemode_info [] =
890 {// prog_name           cmdline                 gamename                                gamedirname     gamescreenshotname
891
892 // GAME_NORMAL
893 // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
894 { "",                           "-quake",               "DarkPlaces-Quake",             "",                     "dp" },
895 // GAME_HIPNOTIC
896 // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
897 { "hipnotic",           "-hipnotic",    "Darkplaces-Hipnotic",  "hipnotic",     "dp" },
898 // GAME_ROGUE
899 // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
900 { "rogue",                      "-rogue",               "Darkplaces-Rogue",             "rogue",        "dp" },
901 // GAME_NEHAHRA
902 // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
903 { "nehahra",            "-nehahra",             "DarkPlaces-Nehahra",   "nehahra",      "dp" },
904 // GAME_NEXUIZ
905 // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
906 { "nexuiz",                     "-nexuiz",              "Nexuiz",                               "data",         "nexuiz" },
907 // GAME_TRANSFUSION
908 // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
909 { "transfusion",        "-transfusion", "Transfusion",                  "basetf",       "transfusion" },
910 // GAME_GOODVSBAD2
911 // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
912 { "gvb2",                       "-goodvsbad2",  "GoodVs.Bad2",                  "rts",          "gvb2" },
913 // GAME_TEU
914 // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
915 { "teu",                        "-teu",                 "TheEvilUnleashed",             "baseteu",      "teu" },
916 // GAME_BATTLEMECH
917 // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech 
918 { "battlemech",         "-battlemech",  "Battlemech",                   "base",         "battlemech" },
919 // GAME_ZYMOTIC
920 // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
921 { "zymotic",            "-zymotic",             "Zymotic",                              "data",         "zymotic" },
922 // GAME_FNIGGIUM
923 // COMMANDLINEOPTION: Game: -fniggium runs the post apocalyptic melee RPG Fniggium 
924 { "fniggium",           "-fniggium",    "Fniggium",                             "data",         "fniggium" },
925 // GAME_SETHERAL
926 // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral 
927 { "setheral",           "-setheral",    "Setheral",                             "data",         "setheral" },
928 // GAME_SOM
929 // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man 
930 { "som",                        "-som",                 "Son of Man",                   "sonofman",     "som" },
931 // GAME_TENEBRAE
932 // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
933 { "tenebrae",           "-tenebrae",    "DarkPlaces-Tenebrae",  "tenebrae",     "dp" },
934 // GAME_NEOTERIC
935 // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
936 { "neoteric",           "-neoteric",    "Neoteric",                             "neobase",      "neo" },
937 // GAME_OPENQUARTZ
938 // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
939 { "openquartz",         "-openquartz",  "OpenQuartz",                   "id1",          "openquartz"},
940 // GAME_PRYDON
941 // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
942 { "prydon",                     "-prydon",              "PrydonGate",                   "prydon",       "prydon"},
943 // GAME_NETHERWORLD
944 // COMMANDLINEOPTION: Game: -netherworld runs the game Netherworld: Dark Masters
945 { "netherworld",        "-netherworld", "Dark Masters",                 "netherworld",  "nw"},
946 };
947
948 void COM_InitGameType (void)
949 {
950         char name [MAX_OSPATH];
951         unsigned int i;
952
953         FS_StripExtension (com_argv[0], name, sizeof (name));
954         COM_ToLowerString (name, name, sizeof (name));
955
956         // Check the binary name; default to GAME_NORMAL (0)
957         gamemode = GAME_NORMAL;
958         for (i = 1; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
959                 if (strstr (name, gamemode_info[i].prog_name))
960                 {
961                         gamemode = i;
962                         break;
963                 }
964
965         // Look for a command-line option
966         for (i = 0; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
967                 if (COM_CheckParm (gamemode_info[i].cmdline))
968                 {
969                         gamemode = i;
970                         break;
971                 }
972
973         gamename = gamemode_info[gamemode].gamename;
974         gamedirname = gamemode_info[gamemode].gamedirname;
975         gamescreenshotname = gamemode_info[gamemode].gamescreenshotname;
976 }
977
978
979 extern void Mathlib_Init(void);
980 extern void FS_Init (void);
981
982 /*
983 ================
984 COM_Init
985 ================
986 */
987 void COM_Init (void)
988 {
989         Cvar_RegisterVariable (&registered);
990         Cvar_RegisterVariable (&cmdline);
991
992         Mathlib_Init();
993
994         FS_Init ();
995         COM_CheckRegistered ();
996 }
997
998
999 /*
1000 ============
1001 va
1002
1003 does a varargs printf into a temp buffer, so I don't need to have
1004 varargs versions of all text functions.
1005 FIXME: make this buffer size safe someday
1006 ============
1007 */
1008 char *va(const char *format, ...)
1009 {
1010         va_list argptr;
1011         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1012         static char string[8][1024], *s;
1013         static int stringindex = 0;
1014
1015         s = string[stringindex];
1016         stringindex = (stringindex + 1) & 7;
1017         va_start (argptr, format);
1018         vsnprintf (s, sizeof (string[0]), format,argptr);
1019         va_end (argptr);
1020
1021         return s;
1022 }
1023
1024
1025 //======================================
1026
1027 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1028 {
1029         if (size_out == 0)
1030                 return;
1031
1032         while (*in && size_out > 1)
1033         {
1034                 if (*in >= 'A' && *in <= 'Z')
1035                         *out++ = *in++ + 'a' - 'A';
1036                 else
1037                         *out++ = *in++;
1038                 size_out--;
1039         }
1040         *out = '\0';
1041 }
1042
1043 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1044 {
1045         if (size_out == 0)
1046                 return;
1047
1048         while (*in && size_out > 1)
1049         {
1050                 if (*in >= 'a' && *in <= 'z')
1051                         *out++ = *in++ + 'A' - 'a';
1052                 else
1053                         *out++ = *in++;
1054                 size_out--;
1055         }
1056         *out = '\0';
1057 }
1058
1059 int COM_StringBeginsWith(const char *s, const char *match)
1060 {
1061         for (;*s && *match;s++, match++)
1062                 if (*s != *match)
1063                         return false;
1064         return true;
1065 }
1066
1067 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1068 {
1069         int argc, commentprefixlength;
1070         char *tokenbufend;
1071         const char *l;
1072         argc = 0;
1073         tokenbufend = tokenbuf + tokenbufsize;
1074         l = *text;
1075         commentprefixlength = 0;
1076         if (commentprefix)
1077                 commentprefixlength = strlen(commentprefix);
1078         while (*l && *l != '\n')
1079         {
1080                 if (*l > ' ')
1081                 {
1082                         if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1083                         {
1084                                 while (*l && *l != '\n')
1085                                         l++;
1086                                 break;
1087                         }
1088                         if (argc >= maxargc)
1089                                 return -1;
1090                         argv[argc++] = tokenbuf;
1091                         if (*l == '"')
1092                         {
1093                                 l++;
1094                                 while (*l && *l != '"')
1095                                 {
1096                                         if (tokenbuf >= tokenbufend)
1097                                                 return -1;
1098                                         *tokenbuf++ = *l++;
1099                                 }
1100                                 if (*l == '"')
1101                                         l++;
1102                         }
1103                         else
1104                         {
1105                                 while (*l > ' ')
1106                                 {
1107                                         if (tokenbuf >= tokenbufend)
1108                                                 return -1;
1109                                         *tokenbuf++ = *l++;
1110                                 }
1111                         }
1112                         if (tokenbuf >= tokenbufend)
1113                                 return -1;
1114                         *tokenbuf++ = 0;
1115                 }
1116                 else
1117                         l++;
1118         }
1119         if (*l == '\n')
1120                 l++;
1121         *text = l;
1122         return argc;
1123 }
1124
1125 // written by Elric, thanks Elric!
1126 char *SearchInfostring(const char *infostring, const char *key)
1127 {
1128         static char value [256];
1129         char crt_key [256];
1130         size_t value_ind, key_ind;
1131         char c;
1132
1133         if (*infostring++ != '\\')
1134                 return NULL;
1135
1136         value_ind = 0;
1137         for (;;)
1138         {
1139                 key_ind = 0;
1140
1141                 // Get the key name
1142                 for (;;)
1143                 {
1144                         c = *infostring++;
1145
1146                         if (c == '\0')
1147                                 return NULL;
1148                         if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1149                         {
1150                                 crt_key[key_ind] = '\0';
1151                                 break;
1152                         }
1153
1154                         crt_key[key_ind++] = c;
1155                 }
1156
1157                 // If it's the key we are looking for, save it in "value"
1158                 if (!strcmp(crt_key, key))
1159                 {
1160                         for (;;)
1161                         {
1162                                 c = *infostring++;
1163
1164                                 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1165                                 {
1166                                         value[value_ind] = '\0';
1167                                         return value;
1168                                 }
1169
1170                                 value[value_ind++] = c;
1171                         }
1172                 }
1173
1174                 // Else, skip the value
1175                 for (;;)
1176                 {
1177                         c = *infostring++;
1178
1179                         if (c == '\0')
1180                                 return NULL;
1181                         if (c == '\\')
1182                                 break;
1183                 }
1184         }
1185 }
1186
1187
1188 //========================================================
1189 // strlcat and strlcpy, from OpenBSD
1190
1191 /*
1192  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1193  *
1194  * Permission to use, copy, modify, and distribute this software for any
1195  * purpose with or without fee is hereby granted, provided that the above
1196  * copyright notice and this permission notice appear in all copies.
1197  *
1198  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1199  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1200  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1201  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1202  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1203  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1204  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1205  */
1206
1207 /*      $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
1208 /*      $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
1209
1210
1211 #ifndef HAVE_STRLCAT
1212 size_t
1213 strlcat(char *dst, const char *src, size_t siz)
1214 {
1215         register char *d = dst;
1216         register const char *s = src;
1217         register size_t n = siz;
1218         size_t dlen;
1219
1220         /* Find the end of dst and adjust bytes left but don't go past end */
1221         while (n-- != 0 && *d != '\0')
1222                 d++;
1223         dlen = d - dst;
1224         n = siz - dlen;
1225
1226         if (n == 0)
1227                 return(dlen + strlen(s));
1228         while (*s != '\0') {
1229                 if (n != 1) {
1230                         *d++ = *s;
1231                         n--;
1232                 }
1233                 s++;
1234         }
1235         *d = '\0';
1236
1237         return(dlen + (s - src));       /* count does not include NUL */
1238 }
1239 #endif  // #ifndef HAVE_STRLCAT
1240
1241
1242 #ifndef HAVE_STRLCPY
1243 size_t
1244 strlcpy(char *dst, const char *src, size_t siz)
1245 {
1246         register char *d = dst;
1247         register const char *s = src;
1248         register size_t n = siz;
1249
1250         /* Copy as many bytes as will fit */
1251         if (n != 0 && --n != 0) {
1252                 do {
1253                         if ((*d++ = *s++) == 0)
1254                                 break;
1255                 } while (--n != 0);
1256         }
1257
1258         /* Not enough room in dst, add NUL and traverse rest of src */
1259         if (n == 0) {
1260                 if (siz != 0)
1261                         *d = '\0';              /* NUL-terminate dst */
1262                 while (*s++)
1263                         ;
1264         }
1265
1266         return(s - src - 1);    /* count does not include NUL */
1267 }
1268
1269 #endif  // #ifndef HAVE_STRLCPY