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;
39 char com_cmdline[MAX_INPUTLINE];
43 const char *gamedirname1;
44 const char *gamedirname2;
45 const char *gamescreenshotname;
46 const char *gameuserdirname;
47 char com_modname[MAX_OSPATH] = "";
51 ============================================================================
55 ============================================================================
58 short ShortSwap (short l)
70 unsigned char b1,b2,b3,b4;
77 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
80 float FloatSwap (float 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];
98 // Extract integers from buffers
100 unsigned int BuffBigLong (const unsigned char *buffer)
102 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
105 unsigned short BuffBigShort (const unsigned char *buffer)
107 return (buffer[0] << 8) | buffer[1];
110 unsigned int BuffLittleLong (const unsigned char *buffer)
112 return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
115 unsigned short BuffLittleShort (const unsigned char *buffer)
117 return (buffer[1] << 8) | buffer[0];
122 ============================================================================
126 ============================================================================
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
133 #define CRC_INIT_VALUE 0xffff
134 #define CRC_XOR_VALUE 0x0000
136 static unsigned short crctable[256] =
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
172 unsigned short CRC_Block(const unsigned char *data, size_t size)
174 unsigned short crc = CRC_INIT_VALUE;
176 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)];
177 return crc ^ CRC_XOR_VALUE;
181 static unsigned char chktbl[1024 + 4] =
183 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
184 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
185 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
186 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
187 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
188 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
189 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
190 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
191 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
192 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
193 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
194 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
195 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
196 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
197 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
198 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
199 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
200 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
201 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
202 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
203 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
204 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
205 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
206 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
207 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
208 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
209 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
210 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
211 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
212 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
213 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
214 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
216 // map checksum goes here
221 unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence)
224 unsigned char chkb[60 + 4];
226 p = chktbl + (sequence % (sizeof(chktbl) - 8));
230 memcpy(chkb, base, length);
232 chkb[length] = (sequence & 0xff) ^ p[0];
233 chkb[length+1] = p[1];
234 chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
235 chkb[length+3] = p[3];
237 return CRC_Block(chkb, length + 4) & 0xff;
241 ==============================================================================
245 Handles byte ordering and avoids alignment errors
246 ==============================================================================
253 void MSG_WriteChar (sizebuf_t *sb, int c)
257 buf = SZ_GetSpace (sb, 1);
261 void MSG_WriteByte (sizebuf_t *sb, int c)
265 buf = SZ_GetSpace (sb, 1);
269 void MSG_WriteShort (sizebuf_t *sb, int c)
273 buf = SZ_GetSpace (sb, 2);
278 void MSG_WriteLong (sizebuf_t *sb, int c)
282 buf = SZ_GetSpace (sb, 4);
284 buf[1] = (c>>8)&0xff;
285 buf[2] = (c>>16)&0xff;
289 void MSG_WriteFloat (sizebuf_t *sb, float f)
299 dat.l = LittleLong (dat.l);
301 SZ_Write (sb, (unsigned char *)&dat.l, 4);
304 void MSG_WriteString (sizebuf_t *sb, const char *s)
307 MSG_WriteChar (sb, 0);
309 SZ_Write (sb, (unsigned char *)s, (int)strlen(s)+1);
312 void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s)
315 SZ_Write (sb, (unsigned char *)s, (int)strlen(s));
318 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
321 MSG_WriteShort (sb, (int)(f * 8.0 + 0.5));
323 MSG_WriteShort (sb, (int)(f * 8.0 - 0.5));
326 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
329 MSG_WriteShort (sb, (int)(f + 0.5));
331 MSG_WriteShort (sb, (int)(f - 0.5));
334 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
336 MSG_WriteFloat (sb, f);
339 void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol)
341 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_QUAKEWORLD)
342 MSG_WriteCoord13i (sb, f);
343 else if (protocol == PROTOCOL_DARKPLACES1)
344 MSG_WriteCoord32f (sb, f);
345 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
346 MSG_WriteCoord16i (sb, f);
348 MSG_WriteCoord32f (sb, f);
351 void MSG_WriteVector (sizebuf_t *sb, float *v, protocolversion_t protocol)
353 MSG_WriteCoord (sb, v[0], protocol);
354 MSG_WriteCoord (sb, v[1], protocol);
355 MSG_WriteCoord (sb, v[2], protocol);
358 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
359 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
362 MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255);
364 MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255);
367 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
370 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535);
372 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535);
375 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
377 MSG_WriteFloat (sb, f);
380 void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
382 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)
383 MSG_WriteAngle8i (sb, f);
385 MSG_WriteAngle16i (sb, f);
392 qboolean msg_badread;
394 void MSG_BeginReading (void)
400 int MSG_ReadLittleShort (void)
402 if (msg_readcount+2 > net_message.cursize)
408 return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
411 int MSG_ReadBigShort (void)
413 if (msg_readcount+2 > net_message.cursize)
419 return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
422 int MSG_ReadLittleLong (void)
424 if (msg_readcount+4 > net_message.cursize)
430 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);
433 int MSG_ReadBigLong (void)
435 if (msg_readcount+4 > net_message.cursize)
441 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];
444 float MSG_ReadLittleFloat (void)
451 if (msg_readcount+4 > net_message.cursize)
457 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);
461 float MSG_ReadBigFloat (void)
468 if (msg_readcount+4 > net_message.cursize)
474 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];
478 char *MSG_ReadString (void)
480 static char string[MAX_INPUTLINE];
482 for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadByte()) != -1 && c != 0;l++)
488 int MSG_ReadBytes (int numbytes, unsigned char *out)
491 for (l = 0;l < numbytes && (c = MSG_ReadByte()) != -1;l++)
496 float MSG_ReadCoord13i (void)
498 return MSG_ReadLittleShort() * (1.0/8.0);
501 float MSG_ReadCoord16i (void)
503 return (signed short) MSG_ReadLittleShort();
506 float MSG_ReadCoord32f (void)
508 return MSG_ReadLittleFloat();
511 float MSG_ReadCoord (protocolversion_t protocol)
513 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_QUAKEWORLD)
514 return MSG_ReadCoord13i();
515 else if (protocol == PROTOCOL_DARKPLACES1)
516 return MSG_ReadCoord32f();
517 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
518 return MSG_ReadCoord16i();
520 return MSG_ReadCoord32f();
523 void MSG_ReadVector (float *v, protocolversion_t protocol)
525 v[0] = MSG_ReadCoord(protocol);
526 v[1] = MSG_ReadCoord(protocol);
527 v[2] = MSG_ReadCoord(protocol);
530 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
531 float MSG_ReadAngle8i (void)
533 return (signed char) MSG_ReadByte () * (360.0/256.0);
536 float MSG_ReadAngle16i (void)
538 return (signed short)MSG_ReadShort () * (360.0/65536.0);
541 float MSG_ReadAngle32f (void)
543 return MSG_ReadFloat ();
546 float MSG_ReadAngle (protocolversion_t protocol)
548 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)
549 return MSG_ReadAngle8i ();
551 return MSG_ReadAngle16i ();
555 //===========================================================================
557 void SZ_Clear (sizebuf_t *buf)
562 unsigned char *SZ_GetSpace (sizebuf_t *buf, int length)
566 if (buf->cursize + length > buf->maxsize)
568 if (!buf->allowoverflow)
569 Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
571 if (length > buf->maxsize)
572 Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
574 buf->overflowed = true;
575 Con_Print("SZ_GetSpace: overflow\n");
579 data = buf->data + buf->cursize;
580 buf->cursize += length;
585 void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length)
587 memcpy (SZ_GetSpace(buf,length),data,length);
590 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
591 // attention, it has been eradicated from here, its only (former) use in
592 // all of darkplaces.
594 static char *hexchar = "0123456789ABCDEF";
595 void Com_HexDumpToConsole(const unsigned char *data, int size)
599 char *cur, *flushpointer;
600 const unsigned char *d;
602 flushpointer = text + 512;
603 for (i = 0;i < size;)
610 *cur++ = hexchar[(i >> 12) & 15];
611 *cur++ = hexchar[(i >> 8) & 15];
612 *cur++ = hexchar[(i >> 4) & 15];
613 *cur++ = hexchar[(i >> 0) & 15];
616 for (j = 0;j < 16;j++)
620 *cur++ = hexchar[(d[j] >> 4) & 15];
621 *cur++ = hexchar[(d[j] >> 0) & 15];
632 for (j = 0;j < 16;j++)
636 // color change prefix character has to be treated specially
637 if (d[j] == STRING_COLOR_TAG)
639 *cur++ = STRING_COLOR_TAG;
640 *cur++ = STRING_COLOR_TAG;
642 else if (d[j] >= ' ')
652 if (cur >= flushpointer || i >= size)
661 void SZ_HexDumpToConsole(const sizebuf_t *buf)
663 Com_HexDumpToConsole(buf->data, buf->cursize);
667 //============================================================================
674 Parse a token out of a string
677 int COM_ParseToken(const char **datapointer, int returnnewline)
680 const char *data = *datapointer;
697 for (;*data <= ' ' && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
707 // handle Windows line ending
708 if (data[0] == '\r' && data[1] == '\n')
711 if (data[0] == '/' && data[1] == '/')
714 while (*data && *data != '\n' && *data != '\r')
718 else if (data[0] == '/' && data[1] == '*')
722 while (*data && (data[0] != '*' || data[1] != '/'))
727 else if (*data == '\"')
730 for (data++;*data != '\"';data++)
732 if (*data == '\\' && data[1] == '"' )
734 if (!*data || len >= (int)sizeof(com_token) - 1)
740 com_token[len++] = *data;
743 *datapointer = data+1;
746 else if (*data == '\'')
749 for (data++;*data != '\'';data++)
751 if (*data == '\\' && data[1] == '\'' )
753 if (!*data || len >= (int)sizeof(com_token) - 1)
759 com_token[len++] = *data;
762 *datapointer = data+1;
765 else if (*data == '\r')
767 // translate Mac line ending to UNIX
768 com_token[len++] = '\n';
773 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == '\'' || *data == ':' || *data == ',' || *data == ';')
776 com_token[len++] = *data++;
784 for (;*data > ' ' && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != '\'' && *data != ':' && *data != ',' && *data != ';' && *data != '\'' && *data != '"';data++)
786 if (len >= (int)sizeof(com_token) - 1)
792 com_token[len++] = *data;
802 COM_ParseTokenConsole
804 Parse a token out of a string, behaving like the qwcl console
807 int COM_ParseTokenConsole(const char **datapointer)
810 const char *data = *datapointer;
823 for (;*data <= ' ';data++)
833 if (*data == '/' && data[1] == '/')
836 while (*data && *data != '\n' && *data != '\r')
840 else if (*data == '\"')
843 for (data++;*data != '\"';data++)
845 if (!*data || len >= (int)sizeof(com_token) - 1)
851 com_token[len++] = *data;
854 *datapointer = data+1;
859 for (;*data > ' ';data++)
861 if (len >= (int)sizeof(com_token) - 1)
867 com_token[len++] = *data;
881 Returns the position (1 to argc-1) in the program's argument list
882 where the given parameter apears, or 0 if not present
885 int COM_CheckParm (const char *parm)
889 for (i=1 ; i<com_argc ; i++)
892 continue; // NEXTSTEP sometimes clears appkit vars.
893 if (!strcmp (parm,com_argv[i]))
904 Looks for the pop.txt file and verifies it.
905 Sets the "registered" cvar.
906 Immediately exits out if an alternate game was attempted to be started without
910 void COM_CheckRegistered (void)
912 Cvar_Set ("cmdline", com_cmdline);
914 if (gamemode == GAME_NORMAL && !FS_FileExists("gfx/pop.lmp"))
917 Con_Print("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
919 Con_Print("Playing shareware version.\n");
923 Cvar_Set ("registered", "1");
924 Con_Print("Playing registered version.\n");
933 void COM_InitArgv (void)
936 // reconstitute the command line for the cmdline externally visible cvar
938 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
941 if (strstr(com_argv[j], " "))
943 // arg contains whitespace, store quotes around it
944 com_cmdline[n++] = '\"';
945 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
946 com_cmdline[n++] = com_argv[j][i++];
947 com_cmdline[n++] = '\"';
951 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
952 com_cmdline[n++] = com_argv[j][i++];
954 if (n < ((int)sizeof(com_cmdline) - 1))
955 com_cmdline[n++] = ' ';
963 //===========================================================================
967 typedef struct gamemode_info_s
969 const char* prog_name;
971 const char* gamename;
972 const char* gamedirname1;
973 const char* gamedirname2;
974 const char* gamescreenshotname;
975 const char* gameuserdirname;
978 static const gamemode_info_t gamemode_info [] =
979 {// prog_name cmdline gamename gamedirname gamescreenshotname
982 // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
983 { "", "-quake", "DarkPlaces-Quake", "id1", NULL, "dp", "darkplaces" },
985 // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
986 { "hipnotic", "-hipnotic", "Darkplaces-Hipnotic", "id1", "hipnotic", "dp", "darkplaces" },
988 // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
989 { "rogue", "-rogue", "Darkplaces-Rogue", "id1", "rogue", "dp", "darkplaces" },
991 // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
992 { "nehahra", "-nehahra", "DarkPlaces-Nehahra", "id1", "nehahra", "dp", "darkplaces" },
994 // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
995 { "nexuiz", "-nexuiz", "Nexuiz", "data", NULL, "nexuiz", "nexuiz" },
997 // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
998 { "transfusion", "-transfusion", "Transfusion", "basetf", NULL, "transfusion", "transfusion" },
1000 // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
1001 { "gvb2", "-goodvsbad2", "GoodVs.Bad2", "rts", NULL, "gvb2", "gvb2" },
1003 // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
1004 { "teu", "-teu", "TheEvilUnleashed", "baseteu", NULL, "teu", "teu" },
1006 // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
1007 { "battlemech", "-battlemech", "Battlemech", "base", NULL, "battlemech", "battlemech" },
1009 // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
1010 { "zymotic", "-zymotic", "Zymotic", "basezym", NULL, "zymotic", "zymotic" },
1012 // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
1013 { "setheral", "-setheral", "Setheral", "data", NULL, "setheral", "setheral" },
1015 // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
1016 { "som", "-som", "Son of Man", "id1", "sonofman", "som", "darkplaces" },
1018 // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
1019 { "tenebrae", "-tenebrae", "DarkPlaces-Tenebrae", "id1", "tenebrae", "dp", "darkplaces" },
1021 // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
1022 { "neoteric", "-neoteric", "Neoteric", "id1", "neobase", "neo", "darkplaces" },
1024 // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
1025 { "openquartz", "-openquartz", "OpenQuartz", "id1", NULL, "openquartz", "darkplaces" },
1027 // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
1028 { "prydon", "-prydon", "PrydonGate", "id1", "prydon", "prydon", "darkplaces" },
1030 // COMMANDLINEOPTION: Game: -netherworld runs the game Netherworld: Dark Master
1031 { "netherworld", "-netherworld", "Netherworld: Dark Master", "id1", "netherworld", "nw", "darkplaces" },
1033 // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
1034 { "thehunted", "-thehunted", "The Hunted", "thdata", NULL, "th", "thehunted" },
1035 // GAME_DEFEATINDETAIL2
1036 // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
1037 { "did2", "-did2", "Defeat In Detail 2", "data", NULL, "did2_", "did2" },
1040 void COM_InitGameType (void)
1042 char name [MAX_OSPATH];
1045 FS_StripExtension (com_argv[0], name, sizeof (name));
1046 COM_ToLowerString (name, name, sizeof (name));
1048 // Check the binary name; default to GAME_NORMAL (0)
1049 gamemode = GAME_NORMAL;
1050 for (i = 1; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
1051 if (strstr (name, gamemode_info[i].prog_name))
1053 gamemode = (gamemode_t)i;
1057 // Look for a command-line option
1058 for (i = 0; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
1059 if (COM_CheckParm (gamemode_info[i].cmdline))
1061 gamemode = (gamemode_t)i;
1065 gamename = gamemode_info[gamemode].gamename;
1066 gamedirname1 = gamemode_info[gamemode].gamedirname1;
1067 gamedirname2 = gamemode_info[gamemode].gamedirname2;
1068 gamescreenshotname = gamemode_info[gamemode].gamescreenshotname;
1069 gameuserdirname = gamemode_info[gamemode].gameuserdirname;
1078 void COM_Init_Commands (void)
1080 Cvar_RegisterVariable (®istered);
1081 Cvar_RegisterVariable (&cmdline);
1088 does a varargs printf into a temp buffer, so I don't need to have
1089 varargs versions of all text functions.
1090 FIXME: make this buffer size safe someday
1093 char *va(const char *format, ...)
1096 // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1097 static char string[8][1024], *s;
1098 static int stringindex = 0;
1100 s = string[stringindex];
1101 stringindex = (stringindex + 1) & 7;
1102 va_start (argptr, format);
1103 dpvsnprintf (s, sizeof (string[0]), format,argptr);
1110 //======================================
1112 // snprintf and vsnprintf are NOT portable. Use their DP counterparts instead
1118 # define snprintf _snprintf
1119 # define vsnprintf _vsnprintf
1123 int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...)
1128 va_start (args, format);
1129 result = dpvsnprintf (buffer, buffersize, format, args);
1136 int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args)
1140 result = vsnprintf (buffer, buffersize, format, args);
1141 if (result < 0 || (size_t)result >= buffersize)
1143 buffer[buffersize - 1] = '\0';
1151 //======================================
1153 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1158 while (*in && size_out > 1)
1160 if (*in >= 'A' && *in <= 'Z')
1161 *out++ = *in++ + 'a' - 'A';
1169 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1174 while (*in && size_out > 1)
1176 if (*in >= 'a' && *in <= 'z')
1177 *out++ = *in++ + 'A' - 'a';
1185 int COM_StringBeginsWith(const char *s, const char *match)
1187 for (;*s && *match;s++, match++)
1193 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1195 int argc, commentprefixlength;
1199 tokenbufend = tokenbuf + tokenbufsize;
1201 commentprefixlength = 0;
1203 commentprefixlength = (int)strlen(commentprefix);
1204 while (*l && *l != '\n' && *l != '\r')
1208 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1210 while (*l && *l != '\n' && *l != '\r')
1214 if (argc >= maxargc)
1216 argv[argc++] = tokenbuf;
1220 while (*l && *l != '"')
1222 if (tokenbuf >= tokenbufend)
1233 if (tokenbuf >= tokenbufend)
1238 if (tokenbuf >= tokenbufend)
1257 // written by Elric, thanks Elric!
1258 char *SearchInfostring(const char *infostring, const char *key)
1260 static char value [MAX_INPUTLINE];
1261 char crt_key [MAX_INPUTLINE];
1262 size_t value_ind, key_ind;
1265 if (*infostring++ != '\\')
1280 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1282 crt_key[key_ind] = '\0';
1286 crt_key[key_ind++] = c;
1289 // If it's the key we are looking for, save it in "value"
1290 if (!strcmp(crt_key, key))
1296 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1298 value[value_ind] = '\0';
1302 value[value_ind++] = c;
1306 // Else, skip the value
1319 void InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
1327 keylength = strlen(key);
1328 if (valuelength < 1 || !value)
1330 Con_Printf("InfoString_GetValue: no room in value\n");
1334 if (strchr(key, '\\'))
1336 Con_Printf("InfoString_GetValue: key name \"%s\" contains \\ which is not possible in an infostring\n", key);
1339 if (strchr(key, '\"'))
1341 Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key);
1346 Con_Printf("InfoString_GetValue: can not look up a key with no name\n");
1349 while (buffer[pos] == '\\')
1351 if (!memcmp(buffer + pos+1, key, keylength))
1353 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1355 for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++)
1356 value[j] = buffer[pos+j];
1360 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1361 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1363 // if we reach this point the key was not found
1366 void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value)
1374 keylength = strlen(key);
1375 if (strchr(key, '\\') || strchr(value, '\\'))
1377 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \\ which is not possible to store in an infostring\n", key, value);
1380 if (strchr(key, '\"') || strchr(value, '\"'))
1382 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \" which is not allowed in an infostring\n", key, value);
1387 Con_Printf("InfoString_SetValue: can not set a key with no name\n");
1390 while (buffer[pos] == '\\')
1392 if (!memcmp(buffer + pos+1, key, keylength))
1394 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1395 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1397 // if we found the key, find the end of it because we will be replacing it
1399 if (buffer[pos] == '\\')
1401 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
1402 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
1404 if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2))
1406 Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value);
1409 if (value && value[0])
1411 // set the key/value and append the remaining text
1412 char tempbuffer[4096];
1413 strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer));
1414 sprintf(buffer + pos, "\\%s\\%s%s", key, value, tempbuffer);
1418 // just remove the key from the text
1419 strcpy(buffer + pos, buffer + pos2);
1423 void InfoString_Print(char *buffer)
1430 if (*buffer != '\\')
1432 Con_Printf("InfoString_Print: corrupt string\n");
1435 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
1436 if (i < (int)sizeof(key)-1)
1439 if (*buffer != '\\')
1441 Con_Printf("InfoString_Print: corrupt string\n");
1444 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
1445 if (i < (int)sizeof(value)-1)
1446 value[i++] = *buffer;
1448 // empty value is an error case
1449 Con_Printf("%20s %s\n", key, value[0] ? value : "NO VALUE");
1453 //========================================================
1454 // strlcat and strlcpy, from OpenBSD
1457 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
1459 * Permission to use, copy, modify, and distribute this software for any
1460 * purpose with or without fee is hereby granted, provided that the above
1461 * copyright notice and this permission notice appear in all copies.
1463 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1464 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1465 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1466 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1467 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1468 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1469 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1472 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
1473 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
1476 #ifndef HAVE_STRLCAT
1478 strlcat(char *dst, const char *src, size_t siz)
1480 register char *d = dst;
1481 register const char *s = src;
1482 register size_t n = siz;
1485 /* Find the end of dst and adjust bytes left but don't go past end */
1486 while (n-- != 0 && *d != '\0')
1492 return(dlen + strlen(s));
1493 while (*s != '\0') {
1502 return(dlen + (s - src)); /* count does not include NUL */
1504 #endif // #ifndef HAVE_STRLCAT
1507 #ifndef HAVE_STRLCPY
1509 strlcpy(char *dst, const char *src, size_t siz)
1511 register char *d = dst;
1512 register const char *s = src;
1513 register size_t n = siz;
1515 /* Copy as many bytes as will fit */
1516 if (n != 0 && --n != 0) {
1518 if ((*d++ = *s++) == 0)
1523 /* Not enough room in dst, add NUL and traverse rest of src */
1526 *d = '\0'; /* NUL-terminate dst */
1531 return(s - src - 1); /* count does not include NUL */
1534 #endif // #ifndef HAVE_STRLCPY