2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // common.c -- misc functions used in client and server
30 cvar_t registered = {0, "registered","0", "indicates if this is running registered quake (whether gfx/qpop.lmp was found)"};
31 cvar_t cmdline = {0, "cmdline","0", "contains commandline the engine was launched with"};
33 extern qboolean fs_modified; // set true if using non-id files
35 char com_token[MAX_INPUTLINE];
37 const char **com_argv;
41 const char *gamedirname1;
42 const char *gamedirname2;
43 const char *gamescreenshotname;
44 const char *gameuserdirname;
45 char com_modname[MAX_OSPATH] = "";
49 ============================================================================
53 ============================================================================
56 short ShortSwap (short l)
68 unsigned char b1,b2,b3,b4;
75 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
78 float FloatSwap (float f)
88 dat2.b[0] = dat1.b[3];
89 dat2.b[1] = dat1.b[2];
90 dat2.b[2] = dat1.b[1];
91 dat2.b[3] = dat1.b[0];
96 // Extract integers from buffers
98 unsigned int BuffBigLong (const unsigned char *buffer)
100 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
103 unsigned short BuffBigShort (const unsigned char *buffer)
105 return (buffer[0] << 8) | buffer[1];
108 unsigned int BuffLittleLong (const unsigned char *buffer)
110 return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
113 unsigned short BuffLittleShort (const unsigned char *buffer)
115 return (buffer[1] << 8) | buffer[0];
120 ============================================================================
124 ============================================================================
127 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
128 // and the initial and final xor values shown below... in other words, the
129 // CCITT standard CRC used by XMODEM
131 #define CRC_INIT_VALUE 0xffff
132 #define CRC_XOR_VALUE 0x0000
134 static unsigned short crctable[256] =
136 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
137 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
138 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
139 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
140 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
141 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
142 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
143 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
144 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
145 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
146 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
147 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
148 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
149 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
150 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
151 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
152 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
153 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
154 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
155 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
156 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
157 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
158 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
159 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
160 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
161 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
162 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
163 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
164 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
165 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
166 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
167 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
170 unsigned short CRC_Block(const unsigned char *data, size_t size)
172 unsigned short crc = CRC_INIT_VALUE;
174 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)];
175 return crc ^ CRC_XOR_VALUE;
179 static unsigned char chktbl[1024 + 4] =
181 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
182 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
183 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
184 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
185 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
186 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
187 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
188 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
189 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
190 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
191 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
192 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
193 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
194 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
195 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
196 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
197 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
198 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
199 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
200 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
201 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
202 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
203 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
204 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
205 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
206 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
207 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
208 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
209 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
210 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
211 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
212 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
214 // map checksum goes here
219 unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence)
222 unsigned char chkb[60 + 4];
224 p = chktbl + (sequence % (sizeof(chktbl) - 8));
228 memcpy(chkb, base, length);
230 chkb[length] = (sequence & 0xff) ^ p[0];
231 chkb[length+1] = p[1];
232 chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
233 chkb[length+3] = p[3];
235 return CRC_Block(chkb, length + 4) & 0xff;
239 ==============================================================================
243 Handles byte ordering and avoids alignment errors
244 ==============================================================================
251 void MSG_WriteChar (sizebuf_t *sb, int c)
255 buf = SZ_GetSpace (sb, 1);
259 void MSG_WriteByte (sizebuf_t *sb, int c)
263 buf = SZ_GetSpace (sb, 1);
267 void MSG_WriteShort (sizebuf_t *sb, int c)
271 buf = SZ_GetSpace (sb, 2);
276 void MSG_WriteLong (sizebuf_t *sb, int c)
280 buf = SZ_GetSpace (sb, 4);
282 buf[1] = (c>>8)&0xff;
283 buf[2] = (c>>16)&0xff;
287 void MSG_WriteFloat (sizebuf_t *sb, float f)
297 dat.l = LittleLong (dat.l);
299 SZ_Write (sb, (unsigned char *)&dat.l, 4);
302 void MSG_WriteString (sizebuf_t *sb, const char *s)
305 MSG_WriteChar (sb, 0);
307 SZ_Write (sb, (unsigned char *)s, (int)strlen(s)+1);
310 void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s)
313 SZ_Write (sb, (unsigned char *)s, (int)strlen(s));
316 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
319 MSG_WriteShort (sb, (int)(f * 8.0 + 0.5));
321 MSG_WriteShort (sb, (int)(f * 8.0 - 0.5));
324 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
327 MSG_WriteShort (sb, (int)(f + 0.5));
329 MSG_WriteShort (sb, (int)(f - 0.5));
332 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
334 MSG_WriteFloat (sb, f);
337 void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol)
339 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_QUAKEWORLD)
340 MSG_WriteCoord13i (sb, f);
341 else if (protocol == PROTOCOL_DARKPLACES1)
342 MSG_WriteCoord32f (sb, f);
343 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
344 MSG_WriteCoord16i (sb, f);
346 MSG_WriteCoord32f (sb, f);
349 void MSG_WriteVector (sizebuf_t *sb, float *v, protocolversion_t protocol)
351 MSG_WriteCoord (sb, v[0], protocol);
352 MSG_WriteCoord (sb, v[1], protocol);
353 MSG_WriteCoord (sb, v[2], protocol);
356 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
357 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
360 MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255);
362 MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255);
365 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
368 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535);
370 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535);
373 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
375 MSG_WriteFloat (sb, f);
378 void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
380 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD)
381 MSG_WriteAngle8i (sb, f);
383 MSG_WriteAngle16i (sb, f);
390 qboolean msg_badread;
392 void MSG_BeginReading (void)
398 int MSG_ReadLittleShort (void)
400 if (msg_readcount+2 > net_message.cursize)
406 return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
409 int MSG_ReadBigShort (void)
411 if (msg_readcount+2 > net_message.cursize)
417 return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
420 int MSG_ReadLittleLong (void)
422 if (msg_readcount+4 > net_message.cursize)
428 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);
431 int MSG_ReadBigLong (void)
433 if (msg_readcount+4 > net_message.cursize)
439 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];
442 float MSG_ReadLittleFloat (void)
449 if (msg_readcount+4 > net_message.cursize)
455 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);
459 float MSG_ReadBigFloat (void)
466 if (msg_readcount+4 > net_message.cursize)
472 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];
476 char *MSG_ReadString (void)
478 static char string[MAX_INPUTLINE];
480 for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadByte()) != -1 && c != 0;l++)
486 int MSG_ReadBytes (int numbytes, unsigned char *out)
489 for (l = 0;l < numbytes && (c = MSG_ReadByte()) != -1;l++)
494 float MSG_ReadCoord13i (void)
496 return MSG_ReadLittleShort() * (1.0/8.0);
499 float MSG_ReadCoord16i (void)
501 return (signed short) MSG_ReadLittleShort();
504 float MSG_ReadCoord32f (void)
506 return MSG_ReadLittleFloat();
509 float MSG_ReadCoord (protocolversion_t protocol)
511 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_QUAKEWORLD)
512 return MSG_ReadCoord13i();
513 else if (protocol == PROTOCOL_DARKPLACES1)
514 return MSG_ReadCoord32f();
515 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
516 return MSG_ReadCoord16i();
518 return MSG_ReadCoord32f();
521 void MSG_ReadVector (float *v, protocolversion_t protocol)
523 v[0] = MSG_ReadCoord(protocol);
524 v[1] = MSG_ReadCoord(protocol);
525 v[2] = MSG_ReadCoord(protocol);
528 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
529 float MSG_ReadAngle8i (void)
531 return (signed char) MSG_ReadByte () * (360.0/256.0);
534 float MSG_ReadAngle16i (void)
536 return (signed short)MSG_ReadShort () * (360.0/65536.0);
539 float MSG_ReadAngle32f (void)
541 return MSG_ReadFloat ();
544 float MSG_ReadAngle (protocolversion_t protocol)
546 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD)
547 return MSG_ReadAngle8i ();
549 return MSG_ReadAngle16i ();
553 //===========================================================================
555 void SZ_Clear (sizebuf_t *buf)
560 unsigned char *SZ_GetSpace (sizebuf_t *buf, int length)
564 if (buf->cursize + length > buf->maxsize)
566 if (!buf->allowoverflow)
567 Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
569 if (length > buf->maxsize)
570 Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
572 buf->overflowed = true;
573 Con_Print("SZ_GetSpace: overflow\n");
577 data = buf->data + buf->cursize;
578 buf->cursize += length;
583 void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length)
585 memcpy (SZ_GetSpace(buf,length),data,length);
588 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
589 // attention, it has been eradicated from here, its only (former) use in
590 // all of darkplaces.
592 static char *hexchar = "0123456789ABCDEF";
593 void Com_HexDumpToConsole(const unsigned char *data, int size)
597 char *cur, *flushpointer;
598 const unsigned char *d;
600 flushpointer = text + 512;
601 for (i = 0;i < size;)
608 *cur++ = hexchar[(i >> 12) & 15];
609 *cur++ = hexchar[(i >> 8) & 15];
610 *cur++ = hexchar[(i >> 4) & 15];
611 *cur++ = hexchar[(i >> 0) & 15];
614 for (j = 0;j < 16;j++)
618 *cur++ = hexchar[(d[j] >> 4) & 15];
619 *cur++ = hexchar[(d[j] >> 0) & 15];
630 for (j = 0;j < 16;j++)
634 // color change prefix character has to be treated specially
635 if (d[j] == STRING_COLOR_TAG)
637 *cur++ = STRING_COLOR_TAG;
638 *cur++ = STRING_COLOR_TAG;
640 else if (d[j] >= ' ')
650 if (cur >= flushpointer || i >= size)
659 void SZ_HexDumpToConsole(const sizebuf_t *buf)
661 Com_HexDumpToConsole(buf->data, buf->cursize);
665 //============================================================================
672 Parse a token out of a string
675 int COM_ParseToken(const char **datapointer, int returnnewline)
678 const char *data = *datapointer;
695 for (;*data <= ' ' && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
705 // handle Windows line ending
706 if (data[0] == '\r' && data[1] == '\n')
709 if (data[0] == '/' && data[1] == '/')
712 while (*data && *data != '\n' && *data != '\r')
716 else if (data[0] == '/' && data[1] == '*')
720 while (*data && (data[0] != '*' || data[1] != '/'))
725 else if (*data == '\"')
728 for (data++;*data != '\"';data++)
730 if (*data == '\\' && data[1] == '"' )
732 if (!*data || len >= (int)sizeof(com_token) - 1)
738 com_token[len++] = *data;
741 *datapointer = data+1;
744 else if (*data == '\'')
747 for (data++;*data != '\'';data++)
749 if (*data == '\\' && data[1] == '\'' )
751 if (!*data || len >= (int)sizeof(com_token) - 1)
757 com_token[len++] = *data;
760 *datapointer = data+1;
763 else if (*data == '\r')
765 // translate Mac line ending to UNIX
766 com_token[len++] = '\n';
771 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
774 com_token[len++] = *data++;
782 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';' && *data != '\'' && *data != '"';data++)
784 if (len >= (int)sizeof(com_token) - 1)
790 com_token[len++] = *data;
800 COM_ParseTokenConsole
802 Parse a token out of a string, behaving like the qwcl console
805 int COM_ParseTokenConsole(const char **datapointer)
808 const char *data = *datapointer;
821 for (;*data <= ' ';data++)
831 if (*data == '/' && data[1] == '/')
834 while (*data && *data != '\n' && *data != '\r')
838 else if (*data == '\"')
841 for (data++;*data != '\"';data++)
843 if (!*data || len >= (int)sizeof(com_token) - 1)
849 com_token[len++] = *data;
852 *datapointer = data+1;
857 for (;*data > ' ';data++)
859 if (len >= (int)sizeof(com_token) - 1)
865 com_token[len++] = *data;
879 Returns the position (1 to argc-1) in the program's argument list
880 where the given parameter apears, or 0 if not present
883 int COM_CheckParm (const char *parm)
887 for (i=1 ; i<com_argc ; i++)
890 continue; // NEXTSTEP sometimes clears appkit vars.
891 if (!strcmp (parm,com_argv[i]))
898 //===========================================================================
902 typedef struct gamemode_info_s
904 const char* prog_name;
906 const char* gamename;
907 const char* gamedirname1;
908 const char* gamedirname2;
909 const char* gamescreenshotname;
910 const char* gameuserdirname;
913 static const gamemode_info_t gamemode_info [] =
914 {// prog_name cmdline gamename gamedirname gamescreenshotname
917 // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
918 { "", "-quake", "DarkPlaces-Quake", "id1", NULL, "dp", "darkplaces" },
920 // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
921 { "hipnotic", "-hipnotic", "Darkplaces-Hipnotic", "id1", "hipnotic", "dp", "darkplaces" },
923 // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
924 { "rogue", "-rogue", "Darkplaces-Rogue", "id1", "rogue", "dp", "darkplaces" },
926 // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
927 { "nehahra", "-nehahra", "DarkPlaces-Nehahra", "id1", "nehahra", "dp", "darkplaces" },
929 // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
930 { "nexuiz", "-nexuiz", "Nexuiz", "data", NULL, "nexuiz", "nexuiz" },
932 // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
933 { "transfusion", "-transfusion", "Transfusion", "basetf", NULL, "transfusion", "transfusion" },
935 // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
936 { "gvb2", "-goodvsbad2", "GoodVs.Bad2", "rts", NULL, "gvb2", "gvb2" },
938 // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
939 { "teu", "-teu", "TheEvilUnleashed", "baseteu", NULL, "teu", "teu" },
941 // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
942 { "battlemech", "-battlemech", "Battlemech", "base", NULL, "battlemech", "battlemech" },
944 // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
945 { "zymotic", "-zymotic", "Zymotic", "basezym", NULL, "zymotic", "zymotic" },
947 // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
948 { "setheral", "-setheral", "Setheral", "data", NULL, "setheral", "setheral" },
950 // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
951 { "som", "-som", "Son of Man", "id1", "sonofman", "som", "darkplaces" },
953 // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
954 { "tenebrae", "-tenebrae", "DarkPlaces-Tenebrae", "id1", "tenebrae", "dp", "darkplaces" },
956 // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
957 { "neoteric", "-neoteric", "Neoteric", "id1", "neobase", "neo", "darkplaces" },
959 // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
960 { "openquartz", "-openquartz", "OpenQuartz", "id1", NULL, "openquartz", "darkplaces" },
962 // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
963 { "prydon", "-prydon", "PrydonGate", "id1", "prydon", "prydon", "darkplaces" },
965 // COMMANDLINEOPTION: Game: -netherworld runs the game Netherworld: Dark Master
966 { "netherworld", "-netherworld", "Netherworld: Dark Master", "id1", "netherworld", "nw", "darkplaces" },
968 // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
969 { "thehunted", "-thehunted", "The Hunted", "thdata", NULL, "th", "thehunted" },
970 // GAME_DEFEATINDETAIL2
971 // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
972 { "did2", "-did2", "Defeat In Detail 2", "data", NULL, "did2_", "did2" },
974 // COMMANDLINEOPTION: Game: -darsana runs the game Darsana
975 { "darsana", "-darsana", "Darsana", "ddata", NULL, "darsana", "darsana" },
976 // GAME_CONTAGIONTHEORY
977 // COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory
978 { "contagiontheory", "-contagiontheory", "Contagion Theory", "ctdata", NULL, "ct", "contagiontheory" },
981 void COM_InitGameType (void)
983 char name [MAX_OSPATH];
986 FS_StripExtension (com_argv[0], name, sizeof (name));
987 COM_ToLowerString (name, name, sizeof (name));
989 // Check the binary name; default to GAME_NORMAL (0)
990 gamemode = GAME_NORMAL;
991 for (i = 1; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
992 if (strstr (name, gamemode_info[i].prog_name))
994 gamemode = (gamemode_t)i;
998 // Look for a command-line option
999 for (i = 0; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
1000 if (COM_CheckParm (gamemode_info[i].cmdline))
1002 gamemode = (gamemode_t)i;
1006 gamename = gamemode_info[gamemode].gamename;
1007 gamedirname1 = gamemode_info[gamemode].gamedirname1;
1008 gamedirname2 = gamemode_info[gamemode].gamedirname2;
1009 gamescreenshotname = gamemode_info[gamemode].gamescreenshotname;
1010 gameuserdirname = gamemode_info[gamemode].gameuserdirname;
1019 void COM_Init_Commands (void)
1022 char com_cmdline[MAX_INPUTLINE];
1024 Cvar_RegisterVariable (®istered);
1025 Cvar_RegisterVariable (&cmdline);
1027 // reconstitute the command line for the cmdline externally visible cvar
1029 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
1032 if (strstr(com_argv[j], " "))
1034 // arg contains whitespace, store quotes around it
1035 com_cmdline[n++] = '\"';
1036 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1037 com_cmdline[n++] = com_argv[j][i++];
1038 com_cmdline[n++] = '\"';
1042 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1043 com_cmdline[n++] = com_argv[j][i++];
1045 if (n < ((int)sizeof(com_cmdline) - 1))
1046 com_cmdline[n++] = ' ';
1051 Cvar_Set ("cmdline", com_cmdline);
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
1063 char *va(const char *format, ...)
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;
1070 s = string[stringindex];
1071 stringindex = (stringindex + 1) & 7;
1072 va_start (argptr, format);
1073 dpvsnprintf (s, sizeof (string[0]), format,argptr);
1080 //======================================
1082 // snprintf and vsnprintf are NOT portable. Use their DP counterparts instead
1088 # define snprintf _snprintf
1089 # define vsnprintf _vsnprintf
1093 int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...)
1098 va_start (args, format);
1099 result = dpvsnprintf (buffer, buffersize, format, args);
1106 int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args)
1110 result = vsnprintf (buffer, buffersize, format, args);
1111 if (result < 0 || (size_t)result >= buffersize)
1113 buffer[buffersize - 1] = '\0';
1121 //======================================
1123 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1128 while (*in && size_out > 1)
1130 if (*in >= 'A' && *in <= 'Z')
1131 *out++ = *in++ + 'a' - 'A';
1139 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1144 while (*in && size_out > 1)
1146 if (*in >= 'a' && *in <= 'z')
1147 *out++ = *in++ + 'A' - 'a';
1155 int COM_StringBeginsWith(const char *s, const char *match)
1157 for (;*s && *match;s++, match++)
1163 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1165 int argc, commentprefixlength;
1169 tokenbufend = tokenbuf + tokenbufsize;
1171 commentprefixlength = 0;
1173 commentprefixlength = (int)strlen(commentprefix);
1174 while (*l && *l != '\n' && *l != '\r')
1178 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1180 while (*l && *l != '\n' && *l != '\r')
1184 if (argc >= maxargc)
1186 argv[argc++] = tokenbuf;
1190 while (*l && *l != '"')
1192 if (tokenbuf >= tokenbufend)
1203 if (tokenbuf >= tokenbufend)
1208 if (tokenbuf >= tokenbufend)
1227 // written by Elric, thanks Elric!
1228 char *SearchInfostring(const char *infostring, const char *key)
1230 static char value [MAX_INPUTLINE];
1231 char crt_key [MAX_INPUTLINE];
1232 size_t value_ind, key_ind;
1235 if (*infostring++ != '\\')
1250 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1252 crt_key[key_ind] = '\0';
1256 crt_key[key_ind++] = c;
1259 // If it's the key we are looking for, save it in "value"
1260 if (!strcmp(crt_key, key))
1266 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1268 value[value_ind] = '\0';
1272 value[value_ind++] = c;
1276 // Else, skip the value
1289 void InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
1297 keylength = strlen(key);
1298 if (valuelength < 1 || !value)
1300 Con_Printf("InfoString_GetValue: no room in value\n");
1304 if (strchr(key, '\\'))
1306 Con_Printf("InfoString_GetValue: key name \"%s\" contains \\ which is not possible in an infostring\n", key);
1309 if (strchr(key, '\"'))
1311 Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key);
1316 Con_Printf("InfoString_GetValue: can not look up a key with no name\n");
1319 while (buffer[pos] == '\\')
1321 if (!memcmp(buffer + pos+1, key, keylength))
1323 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1325 for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++)
1326 value[j] = buffer[pos+j];
1330 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1331 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1333 // if we reach this point the key was not found
1336 void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value)
1344 keylength = strlen(key);
1345 if (strchr(key, '\\') || strchr(value, '\\'))
1347 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \\ which is not possible to store in an infostring\n", key, value);
1350 if (strchr(key, '\"') || strchr(value, '\"'))
1352 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \" which is not allowed in an infostring\n", key, value);
1357 Con_Printf("InfoString_SetValue: can not set a key with no name\n");
1360 while (buffer[pos] == '\\')
1362 if (!memcmp(buffer + pos+1, key, keylength))
1364 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1365 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1367 // if we found the key, find the end of it because we will be replacing it
1369 if (buffer[pos] == '\\')
1371 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
1372 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
1374 if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2))
1376 Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value);
1379 if (value && value[0])
1381 // set the key/value and append the remaining text
1382 char tempbuffer[4096];
1383 strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer));
1384 sprintf(buffer + pos, "\\%s\\%s%s", key, value, tempbuffer);
1388 // just remove the key from the text
1389 strlcpy(buffer + pos, buffer + pos2, bufferlength - pos);
1393 void InfoString_Print(char *buffer)
1400 if (*buffer != '\\')
1402 Con_Printf("InfoString_Print: corrupt string\n");
1405 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
1406 if (i < (int)sizeof(key)-1)
1409 if (*buffer != '\\')
1411 Con_Printf("InfoString_Print: corrupt string\n");
1414 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
1415 if (i < (int)sizeof(value)-1)
1416 value[i++] = *buffer;
1418 // empty value is an error case
1419 Con_Printf("%20s %s\n", key, value[0] ? value : "NO VALUE");
1423 //========================================================
1424 // strlcat and strlcpy, from OpenBSD
1427 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1429 * Permission to use, copy, modify, and distribute this software for any
1430 * purpose with or without fee is hereby granted, provided that the above
1431 * copyright notice and this permission notice appear in all copies.
1433 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1434 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1435 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1436 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1437 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1438 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1439 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1442 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
1443 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
1446 #ifndef HAVE_STRLCAT
1448 strlcat(char *dst, const char *src, size_t siz)
1450 register char *d = dst;
1451 register const char *s = src;
1452 register size_t n = siz;
1455 /* Find the end of dst and adjust bytes left but don't go past end */
1456 while (n-- != 0 && *d != '\0')
1462 return(dlen + strlen(s));
1463 while (*s != '\0') {
1472 return(dlen + (s - src)); /* count does not include NUL */
1474 #endif // #ifndef HAVE_STRLCAT
1477 #ifndef HAVE_STRLCPY
1479 strlcpy(char *dst, const char *src, size_t siz)
1481 register char *d = dst;
1482 register const char *s = src;
1483 register size_t n = siz;
1485 /* Copy as many bytes as will fit */
1486 if (n != 0 && --n != 0) {
1488 if ((*d++ = *s++) == 0)
1493 /* Not enough room in dst, add NUL and traverse rest of src */
1496 *d = '\0'; /* NUL-terminate dst */
1501 return(s - src - 1); /* count does not include NUL */
1504 #endif // #ifndef HAVE_STRLCPY