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