]> icculus.org git repositories - divverent/darkplaces.git/blob - common.c
now aborts video capture if it falls behind by more than a second (as the sound is...
[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)
277                 MSG_WriteCoord13i (sb, f);
278         else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5)
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)
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 == 250)
449                 return MSG_ReadCoord13i();
450         else if (protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES5)
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)
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 || len >= (int)sizeof(com_token) - 1)
673                         {
674                                 com_token[0] = 0;
675                                 *datapointer = NULL;
676                                 return false;
677                         }
678                         com_token[len++] = *data;
679                 }
680                 com_token[len] = 0;
681                 *datapointer = data+1;
682                 return true;
683         }
684         else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
685         {
686                 // single character
687                 com_token[len++] = *data++;
688                 com_token[len] = 0;
689                 *datapointer = data;
690                 return true;
691         }
692         else
693         {
694                 // regular word
695                 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';';data++)
696                 {
697                         if (len >= (int)sizeof(com_token) - 1)
698                         {
699                                 com_token[0] = 0;
700                                 *datapointer = NULL;
701                                 return false;
702                         }
703                         com_token[len++] = *data;
704                 }
705                 com_token[len] = 0;
706                 *datapointer = data;
707                 return true;
708         }
709 }
710
711 /*
712 ==============
713 COM_ParseTokenConsole
714
715 Parse a token out of a string, behaving like the qwcl console
716 ==============
717 */
718 int COM_ParseTokenConsole(const char **datapointer)
719 {
720         int len;
721         const char *data = *datapointer;
722
723         len = 0;
724         com_token[0] = 0;
725
726         if (!data)
727         {
728                 *datapointer = NULL;
729                 return false;
730         }
731
732 // skip whitespace
733 skipwhite:
734         for (;*data <= ' ';data++)
735         {
736                 if (*data == 0)
737                 {
738                         // end of file
739                         *datapointer = NULL;
740                         return false;
741                 }
742         }
743
744         if (*data == '/' && data[1] == '/')
745         {
746                 // comment
747                 while (*data && *data != '\n')
748                         data++;
749                 goto skipwhite;
750         }
751         else if (*data == '\"')
752         {
753                 // quoted string
754                 for (data++;*data != '\"';data++)
755                 {
756                         if (!*data || len >= (int)sizeof(com_token) - 1)
757                         {
758                                 com_token[0] = 0;
759                                 *datapointer = NULL;
760                                 return false;
761                         }
762                         com_token[len++] = *data;
763                 }
764                 com_token[len] = 0;
765                 *datapointer = data+1;
766                 return true;
767         }
768         else
769         {
770                 // regular word
771                 for (;*data > ' ';data++)
772                 {
773                         if (len >= (int)sizeof(com_token) - 1)
774                         {
775                                 com_token[0] = 0;
776                                 *datapointer = NULL;
777                                 return false;
778                         }
779                         com_token[len++] = *data;
780                 }
781                 com_token[len] = 0;
782                 *datapointer = data;
783                 return true;
784         }
785 }
786
787
788 /*
789 ================
790 COM_CheckParm
791
792 Returns the position (1 to argc-1) in the program's argument list
793 where the given parameter apears, or 0 if not present
794 ================
795 */
796 int COM_CheckParm (const char *parm)
797 {
798         int i;
799
800         for (i=1 ; i<com_argc ; i++)
801         {
802                 if (!com_argv[i])
803                         continue;               // NEXTSTEP sometimes clears appkit vars.
804                 if (!strcmp (parm,com_argv[i]))
805                         return i;
806         }
807
808         return 0;
809 }
810
811 /*
812 ================
813 COM_CheckRegistered
814
815 Looks for the pop.txt file and verifies it.
816 Sets the "registered" cvar.
817 Immediately exits out if an alternate game was attempted to be started without
818 being registered.
819 ================
820 */
821 void COM_CheckRegistered (void)
822 {
823         Cvar_Set ("cmdline", com_cmdline);
824
825         if (!FS_FileExists("gfx/pop.lmp"))
826         {
827                 if (fs_modified)
828                         Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
829                 else
830                         Con_Print("Playing shareware version.\n");
831                 return;
832         }
833
834         Cvar_Set ("registered", "1");
835         Con_Print("Playing registered version.\n");
836 }
837
838
839 /*
840 ================
841 COM_InitArgv
842 ================
843 */
844 void COM_InitArgv (void)
845 {
846         int i, j, n;
847         // reconstitute the command line for the cmdline externally visible cvar
848         n = 0;
849         for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
850         {
851                 i = 0;
852                 if (strstr(com_argv[j], " "))
853                 {
854                         // arg contains whitespace, store quotes around it
855                         com_cmdline[n++] = '\"';
856                         while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
857                                 com_cmdline[n++] = com_argv[j][i++];
858                         com_cmdline[n++] = '\"';
859                 }
860                 else
861                 {
862                         while ((n < (CMDLINE_LENGTH - 1)) && com_argv[j][i])
863                                 com_cmdline[n++] = com_argv[j][i++];
864                 }
865                 if (n < (CMDLINE_LENGTH - 1))
866                         com_cmdline[n++] = ' ';
867                 else
868                         break;
869         }
870         com_cmdline[n] = 0;
871 }
872
873
874 //===========================================================================
875
876 // Game mods
877
878 typedef struct
879 {
880         const char* prog_name;
881         const char* cmdline;
882         const char* gamename;
883         const char* gamedirname;
884         const char* gamescreenshotname;
885 } gamemode_info_t;
886
887 static const gamemode_info_t gamemode_info [] =
888 {// prog_name           cmdline                 gamename                                gamedirname     gamescreenshotname
889
890 // GAME_NORMAL
891 // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
892 { "",                           "-quake",               "DarkPlaces-Quake",             "",                     "dp" },
893 // GAME_HIPNOTIC
894 // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
895 { "hipnotic",           "-hipnotic",    "Darkplaces-Hipnotic",  "hipnotic",     "dp" },
896 // GAME_ROGUE
897 // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
898 { "rogue",                      "-rogue",               "Darkplaces-Rogue",             "rogue",        "dp" },
899 // GAME_NEHAHRA
900 // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
901 { "nehahra",            "-nehahra",             "DarkPlaces-Nehahra",   "nehahra",      "dp" },
902 // GAME_NEXUIZ
903 // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
904 { "nexuiz",                     "-nexuiz",              "Nexuiz",                               "data",         "nexuiz" },
905 // GAME_TRANSFUSION
906 // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
907 { "transfusion",        "-transfusion", "Transfusion",                  "basetf",       "transfusion" },
908 // GAME_GOODVSBAD2
909 // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
910 { "gvb2",                       "-goodvsbad2",  "GoodVs.Bad2",                  "rts",          "gvb2" },
911 // GAME_TEU
912 // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
913 { "teu",                        "-teu",                 "TheEvilUnleashed",             "baseteu",      "teu" },
914 // GAME_BATTLEMECH
915 // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech 
916 { "battlemech",         "-battlemech",  "Battlemech",                   "base",         "battlemech" },
917 // GAME_ZYMOTIC
918 // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
919 { "zymotic",            "-zymotic",             "Zymotic",                              "data",         "zymotic" },
920 // GAME_FNIGGIUM
921 // COMMANDLINEOPTION: Game: -fniggium runs the post apocalyptic melee RPG Fniggium 
922 { "fniggium",           "-fniggium",    "Fniggium",                             "data",         "fniggium" },
923 // GAME_SETHERAL
924 // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral 
925 { "setheral",           "-setheral",    "Setheral",                             "data",         "setheral" },
926 // GAME_SOM
927 // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man 
928 { "som",                        "-som",                 "Son of Man",                   "sonofman",     "som" },
929 // GAME_TENEBRAE
930 // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
931 { "tenebrae",           "-tenebrae",    "DarkPlaces-Tenebrae",  "tenebrae",     "dp" },
932 // GAME_NEOTERIC
933 // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
934 { "neoteric",           "-neoteric",    "Neoteric",                             "neobase",      "neo" },
935 // GAME_OPENQUARTZ
936 // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
937 { "openquartz",         "-openquartz",  "OpenQuartz",                   "id1",          "openquartz"},
938 // GAME_PRYDON
939 // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
940 { "prydon",                     "-prydon",              "PrydonGate",                   "prydon",       "prydon"},
941 // GAME_NETHERWORLD
942 // COMMANDLINEOPTION: Game: -netherworld runs the game Netherworld: Dark Masters
943 { "netherworld",        "-netherworld", "Dark Masters",                 "netherworld",  "nw"},
944 };
945
946 void COM_InitGameType (void)
947 {
948         char name [MAX_OSPATH];
949         unsigned int i;
950
951         FS_StripExtension (com_argv[0], name, sizeof (name));
952         COM_ToLowerString (name, name, sizeof (name));
953
954         // Check the binary name; default to GAME_NORMAL (0)
955         gamemode = GAME_NORMAL;
956         for (i = 1; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
957                 if (strstr (name, gamemode_info[i].prog_name))
958                 {
959                         gamemode = i;
960                         break;
961                 }
962
963         // Look for a command-line option
964         for (i = 0; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
965                 if (COM_CheckParm (gamemode_info[i].cmdline))
966                 {
967                         gamemode = i;
968                         break;
969                 }
970
971         gamename = gamemode_info[gamemode].gamename;
972         gamedirname = gamemode_info[gamemode].gamedirname;
973         gamescreenshotname = gamemode_info[gamemode].gamescreenshotname;
974 }
975
976
977 extern void Mathlib_Init(void);
978 extern void FS_Init (void);
979
980 /*
981 ================
982 COM_Init
983 ================
984 */
985 void COM_Init (void)
986 {
987         Cvar_RegisterVariable (&registered);
988         Cvar_RegisterVariable (&cmdline);
989
990         Mathlib_Init();
991
992         FS_Init ();
993         Log_Init ();
994         COM_CheckRegistered ();
995 }
996
997
998 /*
999 ============
1000 va
1001
1002 does a varargs printf into a temp buffer, so I don't need to have
1003 varargs versions of all text functions.
1004 FIXME: make this buffer size safe someday
1005 ============
1006 */
1007 char *va(const char *format, ...)
1008 {
1009         va_list argptr;
1010         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1011         static char string[8][1024], *s;
1012         static int stringindex = 0;
1013
1014         s = string[stringindex];
1015         stringindex = (stringindex + 1) & 7;
1016         va_start (argptr, format);
1017         vsnprintf (s, sizeof (string[0]), format,argptr);
1018         va_end (argptr);
1019
1020         return s;
1021 }
1022
1023
1024 //======================================
1025
1026 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1027 {
1028         if (size_out == 0)
1029                 return;
1030
1031         while (*in && size_out > 1)
1032         {
1033                 if (*in >= 'A' && *in <= 'Z')
1034                         *out++ = *in++ + 'a' - 'A';
1035                 else
1036                         *out++ = *in++;
1037                 size_out--;
1038         }
1039         *out = '\0';
1040 }
1041
1042 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1043 {
1044         if (size_out == 0)
1045                 return;
1046
1047         while (*in && size_out > 1)
1048         {
1049                 if (*in >= 'a' && *in <= 'z')
1050                         *out++ = *in++ + 'A' - 'a';
1051                 else
1052                         *out++ = *in++;
1053                 size_out--;
1054         }
1055         *out = '\0';
1056 }
1057
1058 int COM_StringBeginsWith(const char *s, const char *match)
1059 {
1060         for (;*s && *match;s++, match++)
1061                 if (*s != *match)
1062                         return false;
1063         return true;
1064 }
1065
1066 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1067 {
1068         int argc, commentprefixlength;
1069         char *tokenbufend;
1070         const char *l;
1071         argc = 0;
1072         tokenbufend = tokenbuf + tokenbufsize;
1073         l = *text;
1074         commentprefixlength = 0;
1075         if (commentprefix)
1076                 commentprefixlength = strlen(commentprefix);
1077         while (*l && *l != '\n')
1078         {
1079                 if (*l > ' ')
1080                 {
1081                         if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1082                         {
1083                                 while (*l && *l != '\n')
1084                                         l++;
1085                                 break;
1086                         }
1087                         if (argc >= maxargc)
1088                                 return -1;
1089                         argv[argc++] = tokenbuf;
1090                         if (*l == '"')
1091                         {
1092                                 l++;
1093                                 while (*l && *l != '"')
1094                                 {
1095                                         if (tokenbuf >= tokenbufend)
1096                                                 return -1;
1097                                         *tokenbuf++ = *l++;
1098                                 }
1099                                 if (*l == '"')
1100                                         l++;
1101                         }
1102                         else
1103                         {
1104                                 while (*l > ' ')
1105                                 {
1106                                         if (tokenbuf >= tokenbufend)
1107                                                 return -1;
1108                                         *tokenbuf++ = *l++;
1109                                 }
1110                         }
1111                         if (tokenbuf >= tokenbufend)
1112                                 return -1;
1113                         *tokenbuf++ = 0;
1114                 }
1115                 else
1116                         l++;
1117         }
1118         if (*l == '\n')
1119                 l++;
1120         *text = l;
1121         return argc;
1122 }
1123
1124 // written by Elric, thanks Elric!
1125 char *SearchInfostring(const char *infostring, const char *key)
1126 {
1127         static char value [256];
1128         char crt_key [256];
1129         size_t value_ind, key_ind;
1130         char c;
1131
1132         if (*infostring++ != '\\')
1133                 return NULL;
1134
1135         value_ind = 0;
1136         for (;;)
1137         {
1138                 key_ind = 0;
1139
1140                 // Get the key name
1141                 for (;;)
1142                 {
1143                         c = *infostring++;
1144
1145                         if (c == '\0')
1146                                 return NULL;
1147                         if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1148                         {
1149                                 crt_key[key_ind] = '\0';
1150                                 break;
1151                         }
1152
1153                         crt_key[key_ind++] = c;
1154                 }
1155
1156                 // If it's the key we are looking for, save it in "value"
1157                 if (!strcmp(crt_key, key))
1158                 {
1159                         for (;;)
1160                         {
1161                                 c = *infostring++;
1162
1163                                 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1164                                 {
1165                                         value[value_ind] = '\0';
1166                                         return value;
1167                                 }
1168
1169                                 value[value_ind++] = c;
1170                         }
1171                 }
1172
1173                 // Else, skip the value
1174                 for (;;)
1175                 {
1176                         c = *infostring++;
1177
1178                         if (c == '\0')
1179                                 return NULL;
1180                         if (c == '\\')
1181                                 break;
1182                 }
1183         }
1184 }
1185
1186
1187 //========================================================
1188 // strlcat and strlcpy, from OpenBSD
1189
1190 /*
1191  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1192  *
1193  * Permission to use, copy, modify, and distribute this software for any
1194  * purpose with or without fee is hereby granted, provided that the above
1195  * copyright notice and this permission notice appear in all copies.
1196  *
1197  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1198  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1199  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1200  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1201  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1202  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1203  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1204  */
1205
1206 /*      $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
1207 /*      $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
1208
1209
1210 #ifndef HAVE_STRLCAT
1211 size_t
1212 strlcat(char *dst, const char *src, size_t siz)
1213 {
1214         register char *d = dst;
1215         register const char *s = src;
1216         register size_t n = siz;
1217         size_t dlen;
1218
1219         /* Find the end of dst and adjust bytes left but don't go past end */
1220         while (n-- != 0 && *d != '\0')
1221                 d++;
1222         dlen = d - dst;
1223         n = siz - dlen;
1224
1225         if (n == 0)
1226                 return(dlen + strlen(s));
1227         while (*s != '\0') {
1228                 if (n != 1) {
1229                         *d++ = *s;
1230                         n--;
1231                 }
1232                 s++;
1233         }
1234         *d = '\0';
1235
1236         return(dlen + (s - src));       /* count does not include NUL */
1237 }
1238 #endif  // #ifndef HAVE_STRLCAT
1239
1240
1241 #ifndef HAVE_STRLCPY
1242 size_t
1243 strlcpy(char *dst, const char *src, size_t siz)
1244 {
1245         register char *d = dst;
1246         register const char *s = src;
1247         register size_t n = siz;
1248
1249         /* Copy as many bytes as will fit */
1250         if (n != 0 && --n != 0) {
1251                 do {
1252                         if ((*d++ = *s++) == 0)
1253                                 break;
1254                 } while (--n != 0);
1255         }
1256
1257         /* Not enough room in dst, add NUL and traverse rest of src */
1258         if (n == 0) {
1259                 if (siz != 0)
1260                         *d = '\0';              /* NUL-terminate dst */
1261                 while (*s++)
1262                         ;
1263         }
1264
1265         return(s - src - 1);    /* count does not include NUL */
1266 }
1267
1268 #endif  // #ifndef HAVE_STRLCPY