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