]> icculus.org git repositories - divverent/darkplaces.git/blob - common.c
implemented PRYDON_CLIENTCURSOR extension (clientside mouse pointer that feeds back...
[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         Log_Init ();
996         COM_CheckRegistered ();
997 }
998
999
1000 /*
1001 ============
1002 va
1003
1004 does a varargs printf into a temp buffer, so I don't need to have
1005 varargs versions of all text functions.
1006 FIXME: make this buffer size safe someday
1007 ============
1008 */
1009 char *va(const char *format, ...)
1010 {
1011         va_list argptr;
1012         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1013         static char string[8][1024], *s;
1014         static int stringindex = 0;
1015
1016         s = string[stringindex];
1017         stringindex = (stringindex + 1) & 7;
1018         va_start (argptr, format);
1019         vsnprintf (s, sizeof (string[0]), format,argptr);
1020         va_end (argptr);
1021
1022         return s;
1023 }
1024
1025
1026 //======================================
1027
1028 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1029 {
1030         if (size_out == 0)
1031                 return;
1032
1033         while (*in && size_out > 1)
1034         {
1035                 if (*in >= 'A' && *in <= 'Z')
1036                         *out++ = *in++ + 'a' - 'A';
1037                 else
1038                         *out++ = *in++;
1039                 size_out--;
1040         }
1041         *out = '\0';
1042 }
1043
1044 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1045 {
1046         if (size_out == 0)
1047                 return;
1048
1049         while (*in && size_out > 1)
1050         {
1051                 if (*in >= 'a' && *in <= 'z')
1052                         *out++ = *in++ + 'A' - 'a';
1053                 else
1054                         *out++ = *in++;
1055                 size_out--;
1056         }
1057         *out = '\0';
1058 }
1059
1060 int COM_StringBeginsWith(const char *s, const char *match)
1061 {
1062         for (;*s && *match;s++, match++)
1063                 if (*s != *match)
1064                         return false;
1065         return true;
1066 }
1067
1068 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1069 {
1070         int argc, commentprefixlength;
1071         char *tokenbufend;
1072         const char *l;
1073         argc = 0;
1074         tokenbufend = tokenbuf + tokenbufsize;
1075         l = *text;
1076         commentprefixlength = 0;
1077         if (commentprefix)
1078                 commentprefixlength = strlen(commentprefix);
1079         while (*l && *l != '\n')
1080         {
1081                 if (*l > ' ')
1082                 {
1083                         if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1084                         {
1085                                 while (*l && *l != '\n')
1086                                         l++;
1087                                 break;
1088                         }
1089                         if (argc >= maxargc)
1090                                 return -1;
1091                         argv[argc++] = tokenbuf;
1092                         if (*l == '"')
1093                         {
1094                                 l++;
1095                                 while (*l && *l != '"')
1096                                 {
1097                                         if (tokenbuf >= tokenbufend)
1098                                                 return -1;
1099                                         *tokenbuf++ = *l++;
1100                                 }
1101                                 if (*l == '"')
1102                                         l++;
1103                         }
1104                         else
1105                         {
1106                                 while (*l > ' ')
1107                                 {
1108                                         if (tokenbuf >= tokenbufend)
1109                                                 return -1;
1110                                         *tokenbuf++ = *l++;
1111                                 }
1112                         }
1113                         if (tokenbuf >= tokenbufend)
1114                                 return -1;
1115                         *tokenbuf++ = 0;
1116                 }
1117                 else
1118                         l++;
1119         }
1120         if (*l == '\n')
1121                 l++;
1122         *text = l;
1123         return argc;
1124 }
1125
1126 // written by Elric, thanks Elric!
1127 char *SearchInfostring(const char *infostring, const char *key)
1128 {
1129         static char value [256];
1130         char crt_key [256];
1131         size_t value_ind, key_ind;
1132         char c;
1133
1134         if (*infostring++ != '\\')
1135                 return NULL;
1136
1137         value_ind = 0;
1138         for (;;)
1139         {
1140                 key_ind = 0;
1141
1142                 // Get the key name
1143                 for (;;)
1144                 {
1145                         c = *infostring++;
1146
1147                         if (c == '\0')
1148                                 return NULL;
1149                         if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1150                         {
1151                                 crt_key[key_ind] = '\0';
1152                                 break;
1153                         }
1154
1155                         crt_key[key_ind++] = c;
1156                 }
1157
1158                 // If it's the key we are looking for, save it in "value"
1159                 if (!strcmp(crt_key, key))
1160                 {
1161                         for (;;)
1162                         {
1163                                 c = *infostring++;
1164
1165                                 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1166                                 {
1167                                         value[value_ind] = '\0';
1168                                         return value;
1169                                 }
1170
1171                                 value[value_ind++] = c;
1172                         }
1173                 }
1174
1175                 // Else, skip the value
1176                 for (;;)
1177                 {
1178                         c = *infostring++;
1179
1180                         if (c == '\0')
1181                                 return NULL;
1182                         if (c == '\\')
1183                                 break;
1184                 }
1185         }
1186 }
1187
1188
1189 //========================================================
1190 // strlcat and strlcpy, from OpenBSD
1191
1192 /*
1193  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1194  *
1195  * Permission to use, copy, modify, and distribute this software for any
1196  * purpose with or without fee is hereby granted, provided that the above
1197  * copyright notice and this permission notice appear in all copies.
1198  *
1199  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1200  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1201  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1202  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1203  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1204  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1205  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1206  */
1207
1208 /*      $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
1209 /*      $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
1210
1211
1212 #ifndef HAVE_STRLCAT
1213 size_t
1214 strlcat(char *dst, const char *src, size_t siz)
1215 {
1216         register char *d = dst;
1217         register const char *s = src;
1218         register size_t n = siz;
1219         size_t dlen;
1220
1221         /* Find the end of dst and adjust bytes left but don't go past end */
1222         while (n-- != 0 && *d != '\0')
1223                 d++;
1224         dlen = d - dst;
1225         n = siz - dlen;
1226
1227         if (n == 0)
1228                 return(dlen + strlen(s));
1229         while (*s != '\0') {
1230                 if (n != 1) {
1231                         *d++ = *s;
1232                         n--;
1233                 }
1234                 s++;
1235         }
1236         *d = '\0';
1237
1238         return(dlen + (s - src));       /* count does not include NUL */
1239 }
1240 #endif  // #ifndef HAVE_STRLCAT
1241
1242
1243 #ifndef HAVE_STRLCPY
1244 size_t
1245 strlcpy(char *dst, const char *src, size_t siz)
1246 {
1247         register char *d = dst;
1248         register const char *s = src;
1249         register size_t n = siz;
1250
1251         /* Copy as many bytes as will fit */
1252         if (n != 0 && --n != 0) {
1253                 do {
1254                         if ((*d++ = *s++) == 0)
1255                                 break;
1256                 } while (--n != 0);
1257         }
1258
1259         /* Not enough room in dst, add NUL and traverse rest of src */
1260         if (n == 0) {
1261                 if (siz != 0)
1262                         *d = '\0';              /* NUL-terminate dst */
1263                 while (*s++)
1264                         ;
1265         }
1266
1267         return(s - src - 1);    /* count does not include NUL */
1268 }
1269
1270 #endif  // #ifndef HAVE_STRLCPY