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/pop.lmp was found)"};
31 cvar_t cmdline = {0, "cmdline","0", "contains commandline the engine was launched with"};
33 char com_token[MAX_INPUTLINE];
35 const char **com_argv;
40 const char *gamedirname1;
41 const char *gamedirname2;
42 const char *gamescreenshotname;
43 const char *gameuserdirname;
44 char com_modname[MAX_OSPATH] = "";
48 ============================================================================
52 ============================================================================
56 float BuffBigFloat (const unsigned char *buffer)
64 u.i = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
68 int BuffBigLong (const unsigned char *buffer)
70 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
73 short BuffBigShort (const unsigned char *buffer)
75 return (buffer[0] << 8) | buffer[1];
78 float BuffLittleFloat (const unsigned char *buffer)
86 u.i = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
90 int BuffLittleLong (const unsigned char *buffer)
92 return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
95 short BuffLittleShort (const unsigned char *buffer)
97 return (buffer[1] << 8) | buffer[0];
100 void StoreBigLong (unsigned char *buffer, unsigned int i)
102 buffer[0] = (i >> 24) & 0xFF;
103 buffer[1] = (i >> 16) & 0xFF;
104 buffer[2] = (i >> 8) & 0xFF;
105 buffer[3] = i & 0xFF;
108 void StoreBigShort (unsigned char *buffer, unsigned short i)
110 buffer[0] = (i >> 8) & 0xFF;
111 buffer[1] = i & 0xFF;
114 void StoreLittleLong (unsigned char *buffer, unsigned int i)
116 buffer[0] = i & 0xFF;
117 buffer[1] = (i >> 8) & 0xFF;
118 buffer[2] = (i >> 16) & 0xFF;
119 buffer[3] = (i >> 24) & 0xFF;
122 void StoreLittleShort (unsigned char *buffer, unsigned short i)
124 buffer[0] = i & 0xFF;
125 buffer[1] = (i >> 8) & 0xFF;
129 ============================================================================
133 ============================================================================
136 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
137 // and the initial and final xor values shown below... in other words, the
138 // CCITT standard CRC used by XMODEM
140 #define CRC_INIT_VALUE 0xffff
141 #define CRC_XOR_VALUE 0x0000
143 static unsigned short crctable[256] =
145 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
146 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
147 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
148 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
149 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
150 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
151 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
152 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
153 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
154 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
155 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
156 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
157 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
158 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
159 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
160 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
161 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
162 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
163 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
164 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
165 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
166 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
167 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
168 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
169 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
170 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
171 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
172 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
173 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
174 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
175 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
176 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
179 unsigned short CRC_Block(const unsigned char *data, size_t size)
181 unsigned short crc = CRC_INIT_VALUE;
183 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)];
184 return crc ^ CRC_XOR_VALUE;
187 unsigned short CRC_Block_CaseInsensitive(const unsigned char *data, size_t size)
189 unsigned short crc = CRC_INIT_VALUE;
191 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (tolower(*data++))];
192 return crc ^ CRC_XOR_VALUE;
196 static unsigned char chktbl[1024 + 4] =
198 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
199 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
200 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
201 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
202 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
203 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
204 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
205 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
206 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
207 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
208 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
209 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
210 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
211 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
212 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
213 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
214 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
215 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
216 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
217 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
218 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
219 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
220 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
221 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
222 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
223 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
224 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
225 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
226 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
227 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
228 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
229 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
231 // map checksum goes here
236 unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence)
239 unsigned char chkb[60 + 4];
241 p = chktbl + (sequence % (sizeof(chktbl) - 8));
245 memcpy(chkb, base, length);
247 chkb[length] = (sequence & 0xff) ^ p[0];
248 chkb[length+1] = p[1];
249 chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
250 chkb[length+3] = p[3];
252 return CRC_Block(chkb, length + 4) & 0xff;
256 ==============================================================================
260 Handles byte ordering and avoids alignment errors
261 ==============================================================================
268 void MSG_WriteChar (sizebuf_t *sb, int c)
272 buf = SZ_GetSpace (sb, 1);
276 void MSG_WriteByte (sizebuf_t *sb, int c)
280 buf = SZ_GetSpace (sb, 1);
284 void MSG_WriteShort (sizebuf_t *sb, int c)
288 buf = SZ_GetSpace (sb, 2);
293 void MSG_WriteLong (sizebuf_t *sb, int c)
297 buf = SZ_GetSpace (sb, 4);
299 buf[1] = (c>>8)&0xff;
300 buf[2] = (c>>16)&0xff;
304 void MSG_WriteFloat (sizebuf_t *sb, float f)
314 dat.l = LittleLong (dat.l);
316 SZ_Write (sb, (unsigned char *)&dat.l, 4);
319 void MSG_WriteString (sizebuf_t *sb, const char *s)
322 MSG_WriteChar (sb, 0);
324 SZ_Write (sb, (unsigned char *)s, (int)strlen(s)+1);
327 void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s)
330 SZ_Write (sb, (unsigned char *)s, (int)strlen(s));
333 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
336 MSG_WriteShort (sb, (int)(f * 8.0 + 0.5));
338 MSG_WriteShort (sb, (int)(f * 8.0 - 0.5));
341 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
344 MSG_WriteShort (sb, (int)(f + 0.5));
346 MSG_WriteShort (sb, (int)(f - 0.5));
349 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
351 MSG_WriteFloat (sb, f);
354 void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol)
356 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
357 MSG_WriteCoord13i (sb, f);
358 else if (protocol == PROTOCOL_DARKPLACES1)
359 MSG_WriteCoord32f (sb, f);
360 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
361 MSG_WriteCoord16i (sb, f);
363 MSG_WriteCoord32f (sb, f);
366 void MSG_WriteVector (sizebuf_t *sb, float *v, protocolversion_t protocol)
368 MSG_WriteCoord (sb, v[0], protocol);
369 MSG_WriteCoord (sb, v[1], protocol);
370 MSG_WriteCoord (sb, v[2], protocol);
373 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
374 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
377 MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255);
379 MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255);
382 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
385 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535);
387 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535);
390 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
392 MSG_WriteFloat (sb, f);
395 void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
397 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD)
398 MSG_WriteAngle8i (sb, f);
400 MSG_WriteAngle16i (sb, f);
407 qboolean msg_badread;
409 void MSG_BeginReading (void)
415 int MSG_ReadLittleShort (void)
417 if (msg_readcount+2 > net_message.cursize)
423 return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
426 int MSG_ReadBigShort (void)
428 if (msg_readcount+2 > net_message.cursize)
434 return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
437 int MSG_ReadLittleLong (void)
439 if (msg_readcount+4 > net_message.cursize)
445 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);
448 int MSG_ReadBigLong (void)
450 if (msg_readcount+4 > net_message.cursize)
456 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];
459 float MSG_ReadLittleFloat (void)
466 if (msg_readcount+4 > net_message.cursize)
472 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);
476 float MSG_ReadBigFloat (void)
483 if (msg_readcount+4 > net_message.cursize)
489 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];
493 char *MSG_ReadString (void)
495 static char string[MAX_INPUTLINE];
497 for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadByte()) != -1 && c != 0;l++)
499 // read the rest of the string anyway
500 while(c != -1 && c != 0)
506 int MSG_ReadBytes (int numbytes, unsigned char *out)
509 for (l = 0;l < numbytes && (c = MSG_ReadByte()) != -1;l++)
514 float MSG_ReadCoord13i (void)
516 return MSG_ReadLittleShort() * (1.0/8.0);
519 float MSG_ReadCoord16i (void)
521 return (signed short) MSG_ReadLittleShort();
524 float MSG_ReadCoord32f (void)
526 return MSG_ReadLittleFloat();
529 float MSG_ReadCoord (protocolversion_t protocol)
531 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
532 return MSG_ReadCoord13i();
533 else if (protocol == PROTOCOL_DARKPLACES1)
534 return MSG_ReadCoord32f();
535 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
536 return MSG_ReadCoord16i();
538 return MSG_ReadCoord32f();
541 void MSG_ReadVector (float *v, protocolversion_t protocol)
543 v[0] = MSG_ReadCoord(protocol);
544 v[1] = MSG_ReadCoord(protocol);
545 v[2] = MSG_ReadCoord(protocol);
548 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
549 float MSG_ReadAngle8i (void)
551 return (signed char) MSG_ReadByte () * (360.0/256.0);
554 float MSG_ReadAngle16i (void)
556 return (signed short)MSG_ReadShort () * (360.0/65536.0);
559 float MSG_ReadAngle32f (void)
561 return MSG_ReadFloat ();
564 float MSG_ReadAngle (protocolversion_t protocol)
566 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_DARKPLACES1 || protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4 || protocol == PROTOCOL_QUAKEWORLD)
567 return MSG_ReadAngle8i ();
569 return MSG_ReadAngle16i ();
573 //===========================================================================
575 void SZ_Clear (sizebuf_t *buf)
580 unsigned char *SZ_GetSpace (sizebuf_t *buf, int length)
584 if (buf->cursize + length > buf->maxsize)
586 if (!buf->allowoverflow)
587 Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
589 if (length > buf->maxsize)
590 Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
592 buf->overflowed = true;
593 Con_Print("SZ_GetSpace: overflow\n");
597 data = buf->data + buf->cursize;
598 buf->cursize += length;
603 void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length)
605 memcpy (SZ_GetSpace(buf,length),data,length);
608 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
609 // attention, it has been eradicated from here, its only (former) use in
610 // all of darkplaces.
612 static const char *hexchar = "0123456789ABCDEF";
613 void Com_HexDumpToConsole(const unsigned char *data, int size)
617 char *cur, *flushpointer;
618 const unsigned char *d;
620 flushpointer = text + 512;
621 for (i = 0;i < size;)
628 *cur++ = hexchar[(i >> 12) & 15];
629 *cur++ = hexchar[(i >> 8) & 15];
630 *cur++ = hexchar[(i >> 4) & 15];
631 *cur++ = hexchar[(i >> 0) & 15];
634 for (j = 0;j < 16;j++)
638 *cur++ = hexchar[(d[j] >> 4) & 15];
639 *cur++ = hexchar[(d[j] >> 0) & 15];
650 for (j = 0;j < 16;j++)
654 // color change prefix character has to be treated specially
655 if (d[j] == STRING_COLOR_TAG)
657 *cur++ = STRING_COLOR_TAG;
658 *cur++ = STRING_COLOR_TAG;
660 else if (d[j] >= (unsigned char) ' ')
670 if (cur >= flushpointer || i >= size)
679 void SZ_HexDumpToConsole(const sizebuf_t *buf)
681 Com_HexDumpToConsole(buf->data, buf->cursize);
685 //============================================================================
691 Word wraps a string. The wordWidth function is guaranteed to be called exactly
692 once for each word in the string, so it may be stateful, no idea what that
693 would be good for any more. At the beginning of the string, it will be called
694 for the char 0 to initialize a clean state, and then once with the string " "
695 (a space) so the routine knows how long a space is.
697 In case no single character fits into the given width, the wordWidth function
698 must return the width of exactly one character.
700 Wrapped lines get the isContinuation flag set and are continuationWidth less wide.
702 The sum of the return values of the processLine function will be returned.
705 int COM_Wordwrap(const char *string, size_t length, float continuationWidth, float maxWidth, COM_WordWidthFunc_t wordWidth, void *passthroughCW, COM_LineProcessorFunc processLine, void *passthroughPL)
707 // Logic is as follows:
709 // For each word or whitespace:
710 // Newline found? Output current line, advance to next line. This is not a continuation. Continue.
711 // Space found? Always add it to the current line, no matter if it fits.
712 // Word found? Check if current line + current word fits.
713 // If it fits, append it. Continue.
714 // If it doesn't fit, output current line, advance to next line. Append the word. This is a continuation. Continue.
716 qboolean isContinuation = false;
718 const char *startOfLine = string;
719 const char *cursor = string;
720 const char *end = string + length;
721 float spaceUsedInLine = 0;
722 float spaceUsedForWord;
728 wordWidth(passthroughCW, NULL, &dummy, -1);
730 spaceWidth = wordWidth(passthroughCW, " ", &dummy, -1);
734 char ch = (cursor < end) ? *cursor : 0;
737 case 0: // end of string
738 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
739 isContinuation = false;
741 case '\n': // end of line
742 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
743 isContinuation = false;
745 startOfLine = cursor;
749 spaceUsedInLine += spaceWidth;
753 while(cursor + wordLen < end)
755 switch(cursor[wordLen])
767 spaceUsedForWord = wordWidth(passthroughCW, cursor, &wordLen, maxWidth - continuationWidth); // this may have reduced wordLen when it won't fit - but this is GOOD. TODO fix words that do fit in a non-continuation line
768 if(wordLen < 1) // cannot happen according to current spec of wordWidth
771 spaceUsedForWord = maxWidth + 1; // too high, forces it in a line of itself
773 if(spaceUsedInLine + spaceUsedForWord <= maxWidth || cursor == startOfLine)
775 // we can simply append it
777 spaceUsedInLine += spaceUsedForWord;
781 // output current line
782 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
783 isContinuation = true;
784 startOfLine = cursor;
786 spaceUsedInLine = continuationWidth + spaceUsedForWord;
795 qboolean isContinuation = false;
796 float currentWordSpace = 0;
797 const char *currentWord = 0;
798 float minReserve = 0;
800 float spaceUsedInLine = 0;
801 const char *currentLine = 0;
802 const char *currentLineEnd = 0;
803 float currentLineFinalWhitespace = 0;
807 minReserve = charWidth(passthroughCW, 0);
808 minReserve += charWidth(passthroughCW, ' ');
810 if(maxWidth < continuationWidth + minReserve)
811 maxWidth = continuationWidth + minReserve;
813 charWidth(passthroughCW, 0);
815 for(p = string; p < string + length; ++p)
818 float w = charWidth(passthroughCW, c);
823 currentWordSpace = 0;
829 spaceUsedInLine = isContinuation ? continuationWidth : 0;
835 // 1. I can add the word AND a space - then just append it.
836 if(spaceUsedInLine + currentWordSpace + w <= maxWidth)
838 currentLineEnd = p; // note: space not included here
839 currentLineFinalWhitespace = w;
840 spaceUsedInLine += currentWordSpace + w;
842 // 2. I can just add the word - then append it, output current line and go to next one.
843 else if(spaceUsedInLine + currentWordSpace <= maxWidth)
845 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
847 isContinuation = true;
849 // 3. Otherwise, output current line and go to next one, where I can add the word.
850 else if(continuationWidth + currentWordSpace + w <= maxWidth)
853 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
854 currentLine = currentWord;
855 spaceUsedInLine = continuationWidth + currentWordSpace + w;
857 currentLineFinalWhitespace = w;
858 isContinuation = true;
860 // 4. We can't even do that? Then output both current and next word as new lines.
865 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
866 isContinuation = true;
868 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
870 isContinuation = true;
876 // 1. I can add the word - then do it.
877 if(spaceUsedInLine + currentWordSpace <= maxWidth)
879 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
881 // 2. Otherwise, output current line, next one and make tabula rasa.
886 processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
887 isContinuation = true;
889 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
893 isContinuation = false;
897 currentWordSpace += w;
899 spaceUsedInLine + currentWordSpace > maxWidth // can't join this line...
901 continuationWidth + currentWordSpace > maxWidth // can't join any other line...
904 // this word cannot join ANY line...
905 // so output the current line...
908 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
909 isContinuation = true;
912 // then this word's beginning...
915 // it may not fit, but we know we have to split it into maxWidth - continuationWidth pieces
916 float pieceWidth = maxWidth - continuationWidth;
917 const char *pos = currentWord;
918 currentWordSpace = 0;
920 // reset the char width function to a state where no kerning occurs (start of word)
921 charWidth(passthroughCW, ' ');
924 float w = charWidth(passthroughCW, *pos);
925 if(currentWordSpace + w > pieceWidth) // this piece won't fit any more
927 // print everything until it
928 result += processLine(passthroughPL, currentWord, pos - currentWord, currentWordSpace, true);
931 currentWordSpace = 0;
933 currentWordSpace += w;
936 // now we have a currentWord that fits... set up its next line
937 // currentWordSpace has been set
938 // currentWord has been set
939 spaceUsedInLine = continuationWidth;
940 currentLine = currentWord;
942 isContinuation = true;
946 // we have a guarantee that it will fix (see if clause)
947 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace - w, isContinuation);
949 // and use the rest of this word as new start of a line
950 currentWordSpace = w;
952 spaceUsedInLine = continuationWidth;
955 isContinuation = true;
964 currentWordSpace = 0;
967 if(currentLine) // Same procedure as \n
969 // Can I append the current word?
970 if(spaceUsedInLine + currentWordSpace <= maxWidth)
971 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
976 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
977 isContinuation = true;
979 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
989 COM_ParseToken_Simple
991 Parse a token out of a string
994 int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash)
998 const char *data = *datapointer;
1005 *datapointer = NULL;
1015 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1020 *datapointer = NULL;
1025 // handle Windows line ending
1026 if (data[0] == '\r' && data[1] == '\n')
1029 if (data[0] == '/' && data[1] == '/')
1032 while (*data && *data != '\n' && *data != '\r')
1036 else if (data[0] == '/' && data[1] == '*')
1040 while (*data && (data[0] != '*' || data[1] != '/'))
1048 else if (*data == '\"')
1051 for (data++;*data && *data != '\"';data++)
1054 if (*data == '\\' && parsebackslash)
1063 if (len < (int)sizeof(com_token) - 1)
1064 com_token[len++] = c;
1069 *datapointer = data;
1072 else if (*data == '\r')
1074 // translate Mac line ending to UNIX
1075 com_token[len++] = '\n';data++;
1077 *datapointer = data;
1080 else if (*data == '\n')
1083 com_token[len++] = *data++;
1085 *datapointer = data;
1091 for (;!ISWHITESPACE(*data);data++)
1092 if (len < (int)sizeof(com_token) - 1)
1093 com_token[len++] = *data;
1095 *datapointer = data;
1102 COM_ParseToken_QuakeC
1104 Parse a token out of a string
1107 int COM_ParseToken_QuakeC(const char **datapointer, qboolean returnnewline)
1111 const char *data = *datapointer;
1118 *datapointer = NULL;
1128 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1133 *datapointer = NULL;
1138 // handle Windows line ending
1139 if (data[0] == '\r' && data[1] == '\n')
1142 if (data[0] == '/' && data[1] == '/')
1145 while (*data && *data != '\n' && *data != '\r')
1149 else if (data[0] == '/' && data[1] == '*')
1153 while (*data && (data[0] != '*' || data[1] != '/'))
1161 else if (*data == '\"' || *data == '\'')
1165 for (data++;*data && *data != quote;data++)
1177 if (len < (int)sizeof(com_token) - 1)
1178 com_token[len++] = c;
1183 *datapointer = data;
1186 else if (*data == '\r')
1188 // translate Mac line ending to UNIX
1189 com_token[len++] = '\n';data++;
1191 *datapointer = data;
1194 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1197 com_token[len++] = *data++;
1199 *datapointer = data;
1205 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1206 if (len < (int)sizeof(com_token) - 1)
1207 com_token[len++] = *data;
1209 *datapointer = data;
1216 COM_ParseToken_VM_Tokenize
1218 Parse a token out of a string
1221 int COM_ParseToken_VM_Tokenize(const char **datapointer, qboolean returnnewline)
1225 const char *data = *datapointer;
1232 *datapointer = NULL;
1242 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1247 *datapointer = NULL;
1252 // handle Windows line ending
1253 if (data[0] == '\r' && data[1] == '\n')
1256 if (data[0] == '/' && data[1] == '/')
1259 while (*data && *data != '\n' && *data != '\r')
1263 else if (data[0] == '/' && data[1] == '*')
1267 while (*data && (data[0] != '*' || data[1] != '/'))
1275 else if (*data == '\"' || *data == '\'')
1279 for (data++;*data && *data != quote;data++)
1291 if (len < (int)sizeof(com_token) - 1)
1292 com_token[len++] = c;
1297 *datapointer = data;
1300 else if (*data == '\r')
1302 // translate Mac line ending to UNIX
1303 com_token[len++] = '\n';data++;
1305 *datapointer = data;
1308 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1311 com_token[len++] = *data++;
1313 *datapointer = data;
1319 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1320 if (len < (int)sizeof(com_token) - 1)
1321 com_token[len++] = *data;
1323 *datapointer = data;
1330 COM_ParseToken_Console
1332 Parse a token out of a string, behaving like the qwcl console
1335 int COM_ParseToken_Console(const char **datapointer)
1338 const char *data = *datapointer;
1345 *datapointer = NULL;
1351 for (;ISWHITESPACE(*data);data++)
1356 *datapointer = NULL;
1361 if (*data == '/' && data[1] == '/')
1364 while (*data && *data != '\n' && *data != '\r')
1368 else if (*data == '\"')
1371 for (data++;*data && *data != '\"';data++)
1373 // allow escaped " and \ case
1374 if (*data == '\\' && (data[1] == '\"' || data[1] == '\\'))
1376 if (len < (int)sizeof(com_token) - 1)
1377 com_token[len++] = *data;
1382 *datapointer = data;
1387 for (;!ISWHITESPACE(*data);data++)
1388 if (len < (int)sizeof(com_token) - 1)
1389 com_token[len++] = *data;
1391 *datapointer = data;
1402 Returns the position (1 to argc-1) in the program's argument list
1403 where the given parameter apears, or 0 if not present
1406 int COM_CheckParm (const char *parm)
1410 for (i=1 ; i<com_argc ; i++)
1413 continue; // NEXTSTEP sometimes clears appkit vars.
1414 if (!strcmp (parm,com_argv[i]))
1421 //===========================================================================
1425 gamemode_t com_startupgamemode;
1426 gamemode_t com_startupgamegroup;
1428 typedef struct gamemode_info_s
1430 gamemode_t mode; // this gamemode
1431 gamemode_t group; // different games with same group can switch automatically when gamedirs change
1432 const char* prog_name; // not null
1433 const char* cmdline; // not null
1434 const char* gamename; // not null
1435 const char* gamedirname1; // not null
1436 const char* gamedirname2; // null
1437 const char* gamescreenshotname; // not nul
1438 const char* gameuserdirname; // not null
1441 static const gamemode_info_t gamemode_info [GAME_COUNT] =
1442 {// game basegame prog_name cmdline gamename basegame modgame screenshot userdir // commandline option
1443 { GAME_NORMAL, GAME_NORMAL, "", "-quake", "DarkPlaces-Quake", "id1", NULL, "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
1444 { GAME_HIPNOTIC, GAME_NORMAL, "hipnotic", "-hipnotic", "Darkplaces-Hipnotic", "id1", "hipnotic", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
1445 { GAME_ROGUE, GAME_NORMAL, "rogue", "-rogue", "Darkplaces-Rogue", "id1", "rogue", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
1446 { GAME_NEHAHRA, GAME_NORMAL, "nehahra", "-nehahra", "DarkPlaces-Nehahra", "id1", "nehahra", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
1447 { GAME_NEXUIZ, GAME_NEXUIZ, "nexuiz", "-nexuiz", "Nexuiz", "data", NULL, "nexuiz", "nexuiz" }, // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
1448 { GAME_XONOTIC, GAME_XONOTIC, "xonotic", "-xonotic", "Xonotic", "data", NULL, "xonotic", "xonotic" }, // COMMANDLINEOPTION: Game: -xonotic runs the multiplayer game Xonotic
1449 { GAME_TRANSFUSION, GAME_TRANSFUSION, "transfusion", "-transfusion", "Transfusion", "basetf", NULL, "transfusion", "transfusion" }, // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
1450 { GAME_GOODVSBAD2, GAME_GOODVSBAD2, "gvb2", "-goodvsbad2", "GoodVs.Bad2", "rts", NULL, "gvb2", "gvb2" }, // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
1451 { GAME_TEU, GAME_TEU, "teu", "-teu", "TheEvilUnleashed", "baseteu", NULL, "teu", "teu" }, // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
1452 { GAME_BATTLEMECH, GAME_BATTLEMECH, "battlemech", "-battlemech", "Battlemech", "base", NULL, "battlemech", "battlemech" }, // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
1453 { GAME_ZYMOTIC, GAME_ZYMOTIC, "zymotic", "-zymotic", "Zymotic", "basezym", NULL, "zymotic", "zymotic" }, // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
1454 { GAME_SETHERAL, GAME_SETHERAL, "setheral", "-setheral", "Setheral", "data", NULL, "setheral", "setheral" }, // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
1455 { GAME_SOM, GAME_NORMAL, "som", "-som", "Son of Man", "id1", "sonofman", "som", "darkplaces" }, // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
1456 { GAME_TENEBRAE, GAME_NORMAL, "tenebrae", "-tenebrae", "DarkPlaces-Tenebrae", "id1", "tenebrae", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
1457 { GAME_NEOTERIC, GAME_NORMAL, "neoteric", "-neoteric", "Neoteric", "id1", "neobase", "neo", "darkplaces" }, // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
1458 { GAME_OPENQUARTZ, GAME_NORMAL, "openquartz", "-openquartz", "OpenQuartz", "id1", NULL, "openquartz", "darkplaces" }, // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
1459 { GAME_PRYDON, GAME_NORMAL, "prydon", "-prydon", "PrydonGate", "id1", "prydon", "prydon", "darkplaces" }, // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
1460 { GAME_DELUXEQUAKE, GAME_DELUXEQUAKE, "dq", "-dq", "Deluxe Quake", "basedq", "extradq", "basedq", "dq" }, // COMMANDLINEOPTION: Game: -dq runs the game Deluxe Quake
1461 { GAME_THEHUNTED, GAME_THEHUNTED, "thehunted", "-thehunted", "The Hunted", "thdata", NULL, "th", "thehunted" }, // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
1462 { GAME_DEFEATINDETAIL2, GAME_DEFEATINDETAIL2, "did2", "-did2", "Defeat In Detail 2", "data", NULL, "did2_", "did2" }, // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
1463 { GAME_DARSANA, GAME_DARSANA, "darsana", "-darsana", "Darsana", "ddata", NULL, "darsana", "darsana" }, // COMMANDLINEOPTION: Game: -darsana runs the game Darsana
1464 { GAME_CONTAGIONTHEORY, GAME_CONTAGIONTHEORY, "contagiontheory", "-contagiontheory", "Contagion Theory", "ctdata", NULL, "ct", "contagiontheory" }, // COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory
1465 { GAME_EDU2P, GAME_EDU2P, "edu2p", "-edu2p", "EDU2 Prototype", "id1", "edu2", "edu2_p", "edu2prototype" }, // COMMANDLINEOPTION: Game: -edu2p runs the game Edu2 prototype
1466 { GAME_PROPHECY, GAME_PROPHECY, "prophecy", "-prophecy", "Prophecy", "data", NULL, "prophecy", "prophecy" }, // COMMANDLINEOPTION: Game: -prophecy runs the game Prophecy
1467 { GAME_BLOODOMNICIDE, GAME_BLOODOMNICIDE, "omnicide", "-omnicide", "Blood Omnicide", "kain", NULL, "omnicide", "omnicide" }, // COMMANDLINEOPTION: Game: -omnicide runs the game Blood Omnicide
1468 { GAME_STEELSTORM, GAME_STEELSTORM, "steelstorm", "-steelstorm", "Steel-Storm", "gamedata", NULL, "ss", "steelstorm" }, // COMMANDLINEOPTION: Game: -steelstorm runs the game Steel Storm
1469 { GAME_STRAPBOMB, GAME_STRAPBOMB, "strapbomb", "-strapbomb", "Strap-on-bomb Car", "id1", NULL, "strap", "strapbomb" }, // COMMANDLINEOPTION: Game: -strapbomb runs the game Strap-on-bomb Car
1470 { GAME_MOONHELM, GAME_MOONHELM, "moonhelm", "-moonhelm", "MoonHelm", "data", NULL, "mh", "moonhelm" }, // COMMANDLINEOPTION: Game: -moonhelm runs the game MoonHelm
1473 static void COM_SetGameType(int index);
1474 void COM_InitGameType (void)
1476 char name [MAX_OSPATH];
1480 FS_StripExtension (com_argv[0], name, sizeof (name));
1481 COM_ToLowerString (name, name, sizeof (name));
1483 // check executable filename for keywords
1484 for (i = 1;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1485 if (gamemode_info[i].prog_name && gamemode_info[i].prog_name[0] && strstr (name, gamemode_info[i].prog_name))
1491 // check commandline options for keywords
1492 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1493 if (COM_CheckParm (gamemode_info[i].cmdline))
1499 com_startupgamemode = gamemode_info[index].mode;
1500 com_startupgamegroup = gamemode_info[index].group;
1501 COM_SetGameType(index);
1504 void COM_ChangeGameTypeForGameDirs(void)
1508 // this will not not change the gamegroup
1509 // first check if a base game (single gamedir) matches
1510 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1512 if (gamemode_info[i].group == com_startupgamegroup && !(gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]))
1518 // now that we have a base game, see if there is a matching derivative game (two gamedirs)
1521 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1523 if (gamemode_info[i].group == com_startupgamegroup && (gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]) && !strcasecmp(fs_gamedirs[0], gamemode_info[i].gamedirname2))
1530 // we now have a good guess at which game this is meant to be...
1531 if (index >= 0 && gamemode != gamemode_info[index].mode)
1532 COM_SetGameType(index);
1535 static void COM_SetGameType(int index)
1538 if (index < 0 || index >= (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0])))
1540 gamemode = gamemode_info[index].mode;
1541 gamename = gamemode_info[index].gamename;
1542 gamedirname1 = gamemode_info[index].gamedirname1;
1543 gamedirname2 = gamemode_info[index].gamedirname2;
1544 gamescreenshotname = gamemode_info[index].gamescreenshotname;
1545 gameuserdirname = gamemode_info[index].gameuserdirname;
1547 if (gamemode == com_startupgamemode)
1549 if((t = COM_CheckParm("-customgamename")) && t + 1 < com_argc)
1550 gamename = com_argv[t+1];
1551 if((t = COM_CheckParm("-customgamedirname1")) && t + 1 < com_argc)
1552 gamedirname1 = com_argv[t+1];
1553 if((t = COM_CheckParm("-customgamedirname2")) && t + 1 < com_argc)
1554 gamedirname2 = *com_argv[t+1] ? com_argv[t+1] : NULL;
1555 if((t = COM_CheckParm("-customgamescreenshotname")) && t + 1 < com_argc)
1556 gamescreenshotname = com_argv[t+1];
1557 if((t = COM_CheckParm("-customgameuserdirname")) && t + 1 < com_argc)
1558 gameuserdirname = com_argv[t+1];
1561 if (gamedirname2 && gamedirname2[0])
1562 Con_Printf("Game is %s using base gamedirs %s %s", gamename, gamedirname1, gamedirname2);
1564 Con_Printf("Game is %s using base gamedir %s", gamename, gamedirname1);
1565 for (i = 0;i < fs_numgamedirs;i++)
1568 Con_Printf(", with mod gamedirs");
1569 Con_Printf(" %s", fs_gamedirs[i]);
1580 void COM_Init_Commands (void)
1583 char com_cmdline[MAX_INPUTLINE];
1585 Cvar_RegisterVariable (®istered);
1586 Cvar_RegisterVariable (&cmdline);
1588 // reconstitute the command line for the cmdline externally visible cvar
1590 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
1593 if (strstr(com_argv[j], " "))
1595 // arg contains whitespace, store quotes around it
1596 com_cmdline[n++] = '\"';
1597 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1598 com_cmdline[n++] = com_argv[j][i++];
1599 com_cmdline[n++] = '\"';
1603 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1604 com_cmdline[n++] = com_argv[j][i++];
1606 if (n < ((int)sizeof(com_cmdline) - 1))
1607 com_cmdline[n++] = ' ';
1612 Cvar_Set ("cmdline", com_cmdline);
1619 does a varargs printf into a temp buffer, so I don't need to have
1620 varargs versions of all text functions.
1621 FIXME: make this buffer size safe someday
1624 char *va(const char *format, ...)
1627 // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1628 static char string[8][1024], *s;
1629 static int stringindex = 0;
1631 s = string[stringindex];
1632 stringindex = (stringindex + 1) & 7;
1633 va_start (argptr, format);
1634 dpvsnprintf (s, sizeof (string[0]), format,argptr);
1641 //======================================
1643 // snprintf and vsnprintf are NOT portable. Use their DP counterparts instead
1649 # define snprintf _snprintf
1650 # define vsnprintf _vsnprintf
1654 int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...)
1659 va_start (args, format);
1660 result = dpvsnprintf (buffer, buffersize, format, args);
1667 int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args)
1671 #if _MSC_VER >= 1400
1672 result = _vsnprintf_s (buffer, buffersize, _TRUNCATE, format, args);
1674 result = vsnprintf (buffer, buffersize, format, args);
1676 if (result < 0 || (size_t)result >= buffersize)
1678 buffer[buffersize - 1] = '\0';
1686 //======================================
1688 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1693 while (*in && size_out > 1)
1695 if (*in >= 'A' && *in <= 'Z')
1696 *out++ = *in++ + 'a' - 'A';
1704 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1709 while (*in && size_out > 1)
1711 if (*in >= 'a' && *in <= 'z')
1712 *out++ = *in++ + 'A' - 'a';
1720 int COM_StringBeginsWith(const char *s, const char *match)
1722 for (;*s && *match;s++, match++)
1728 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1730 int argc, commentprefixlength;
1734 tokenbufend = tokenbuf + tokenbufsize;
1736 commentprefixlength = 0;
1738 commentprefixlength = (int)strlen(commentprefix);
1739 while (*l && *l != '\n' && *l != '\r')
1741 if (!ISWHITESPACE(*l))
1743 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1745 while (*l && *l != '\n' && *l != '\r')
1749 if (argc >= maxargc)
1751 argv[argc++] = tokenbuf;
1755 while (*l && *l != '"')
1757 if (tokenbuf >= tokenbufend)
1766 while (!ISWHITESPACE(*l))
1768 if (tokenbuf >= tokenbufend)
1773 if (tokenbuf >= tokenbufend)
1794 COM_StringLengthNoColors
1796 calculates the visible width of a color coded string.
1798 *valid is filled with TRUE if the string is a valid colored string (that is, if
1799 it does not end with an unfinished color code). If it gets filled with FALSE, a
1800 fix would be adding a STRING_COLOR_TAG at the end of the string.
1802 valid can be set to NULL if the caller doesn't care.
1804 For size_s, specify the maximum number of characters from s to use, or 0 to use
1805 all characters until the zero terminator.
1809 COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid)
1811 const char *end = size_s ? (s + size_s) : NULL;
1815 switch((s == end) ? 0 : *s)
1821 case STRING_COLOR_TAG:
1823 switch((s == end) ? 0 : *s)
1825 case STRING_COLOR_RGB_TAG_CHAR:
1826 if (s+1 != end && isxdigit(s[1]) &&
1827 s+2 != end && isxdigit(s[2]) &&
1828 s+3 != end && isxdigit(s[3]) )
1833 ++len; // STRING_COLOR_TAG
1834 ++len; // STRING_COLOR_RGB_TAG_CHAR
1836 case 0: // ends with unfinished color code!
1841 case STRING_COLOR_TAG: // escaped ^
1844 case '0': case '1': case '2': case '3': case '4':
1845 case '5': case '6': case '7': case '8': case '9': // color code
1847 default: // not a color code
1848 ++len; // STRING_COLOR_TAG
1849 ++len; // the character
1864 COM_StringDecolorize
1866 removes color codes from a string.
1868 If escape_carets is true, the resulting string will be safe for printing. If
1869 escape_carets is false, the function will just strip color codes (for logging
1872 If the output buffer size did not suffice for converting, the function returns
1873 FALSE. Generally, if escape_carets is false, the output buffer needs
1874 strlen(str)+1 bytes, and if escape_carets is true, it can need strlen(str)*1.5+2
1875 bytes. In any case, the function makes sure that the resulting string is
1878 For size_in, specify the maximum number of characters from in to use, or 0 to use
1879 all characters until the zero terminator.
1883 COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets)
1885 #define APPEND(ch) do { if(--size_out) { *out++ = (ch); } else { *out++ = 0; return FALSE; } } while(0)
1886 const char *end = size_in ? (in + size_in) : NULL;
1891 switch((in == end) ? 0 : *in)
1896 case STRING_COLOR_TAG:
1898 switch((in == end) ? 0 : *in)
1900 case STRING_COLOR_RGB_TAG_CHAR:
1901 if (in+1 != end && isxdigit(in[1]) &&
1902 in+2 != end && isxdigit(in[2]) &&
1903 in+3 != end && isxdigit(in[3]) )
1908 APPEND(STRING_COLOR_TAG);
1910 APPEND(STRING_COLOR_TAG);
1911 APPEND(STRING_COLOR_RGB_TAG_CHAR);
1913 case 0: // ends with unfinished color code!
1914 APPEND(STRING_COLOR_TAG);
1915 // finish the code by appending another caret when escaping
1917 APPEND(STRING_COLOR_TAG);
1920 case STRING_COLOR_TAG: // escaped ^
1921 APPEND(STRING_COLOR_TAG);
1922 // append a ^ twice when escaping
1924 APPEND(STRING_COLOR_TAG);
1926 case '0': case '1': case '2': case '3': case '4':
1927 case '5': case '6': case '7': case '8': case '9': // color code
1929 default: // not a color code
1930 APPEND(STRING_COLOR_TAG);
1945 // written by Elric, thanks Elric!
1946 char *SearchInfostring(const char *infostring, const char *key)
1948 static char value [MAX_INPUTLINE];
1949 char crt_key [MAX_INPUTLINE];
1950 size_t value_ind, key_ind;
1953 if (*infostring++ != '\\')
1968 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1970 crt_key[key_ind] = '\0';
1974 crt_key[key_ind++] = c;
1977 // If it's the key we are looking for, save it in "value"
1978 if (!strcmp(crt_key, key))
1984 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1986 value[value_ind] = '\0';
1990 value[value_ind++] = c;
1994 // Else, skip the value
2007 void InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
2013 keylength = strlen(key);
2014 if (valuelength < 1 || !value)
2016 Con_Printf("InfoString_GetValue: no room in value\n");
2020 if (strchr(key, '\\'))
2022 Con_Printf("InfoString_GetValue: key name \"%s\" contains \\ which is not possible in an infostring\n", key);
2025 if (strchr(key, '\"'))
2027 Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key);
2032 Con_Printf("InfoString_GetValue: can not look up a key with no name\n");
2035 while (buffer[pos] == '\\')
2037 if (!memcmp(buffer + pos+1, key, keylength))
2039 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2041 for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++)
2042 value[j] = buffer[pos+j];
2046 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2047 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2049 // if we reach this point the key was not found
2052 void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value)
2060 keylength = strlen(key);
2061 if (strchr(key, '\\') || strchr(value, '\\'))
2063 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \\ which is not possible to store in an infostring\n", key, value);
2066 if (strchr(key, '\"') || strchr(value, '\"'))
2068 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \" which is not allowed in an infostring\n", key, value);
2073 Con_Printf("InfoString_SetValue: can not set a key with no name\n");
2076 while (buffer[pos] == '\\')
2078 if (!memcmp(buffer + pos+1, key, keylength))
2080 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2081 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2083 // if we found the key, find the end of it because we will be replacing it
2085 if (buffer[pos] == '\\')
2087 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2088 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2090 if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2))
2092 Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value);
2095 if (value && value[0])
2097 // set the key/value and append the remaining text
2098 char tempbuffer[4096];
2099 strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer));
2100 dpsnprintf(buffer + pos, bufferlength - pos, "\\%s\\%s%s", key, value, tempbuffer);
2104 // just remove the key from the text
2105 strlcpy(buffer + pos, buffer + pos2, bufferlength - pos);
2109 void InfoString_Print(char *buffer)
2116 if (*buffer != '\\')
2118 Con_Printf("InfoString_Print: corrupt string\n");
2121 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2122 if (i < (int)sizeof(key)-1)
2125 if (*buffer != '\\')
2127 Con_Printf("InfoString_Print: corrupt string\n");
2130 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2131 if (i < (int)sizeof(value)-1)
2132 value[i++] = *buffer;
2134 // empty value is an error case
2135 Con_Printf("%20s %s\n", key, value[0] ? value : "NO VALUE");
2139 //========================================================
2140 // strlcat and strlcpy, from OpenBSD
2143 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
2145 * Permission to use, copy, modify, and distribute this software for any
2146 * purpose with or without fee is hereby granted, provided that the above
2147 * copyright notice and this permission notice appear in all copies.
2149 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2150 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2151 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2152 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2153 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2154 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2155 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2158 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
2159 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
2162 #ifndef HAVE_STRLCAT
2164 strlcat(char *dst, const char *src, size_t siz)
2166 register char *d = dst;
2167 register const char *s = src;
2168 register size_t n = siz;
2171 /* Find the end of dst and adjust bytes left but don't go past end */
2172 while (n-- != 0 && *d != '\0')
2178 return(dlen + strlen(s));
2179 while (*s != '\0') {
2188 return(dlen + (s - src)); /* count does not include NUL */
2190 #endif // #ifndef HAVE_STRLCAT
2193 #ifndef HAVE_STRLCPY
2195 strlcpy(char *dst, const char *src, size_t siz)
2197 register char *d = dst;
2198 register const char *s = src;
2199 register size_t n = siz;
2201 /* Copy as many bytes as will fit */
2202 if (n != 0 && --n != 0) {
2204 if ((*d++ = *s++) == 0)
2209 /* Not enough room in dst, add NUL and traverse rest of src */
2212 *d = '\0'; /* NUL-terminate dst */
2217 return(s - src - 1); /* count does not include NUL */
2220 #endif // #ifndef HAVE_STRLCPY
2222 void FindFraction(double val, int *num, int *denom, int denomMax)
2227 bestdiff = fabs(val);
2231 for(i = 1; i <= denomMax; ++i)
2233 int inum = (int) floor(0.5 + val * i);
2234 double diff = fabs(val - inum / (double)i);
2244 // decodes an XPM from C syntax
2245 char **XPM_DecodeString(const char *in)
2247 static char *tokens[257];
2248 static char lines[257][512];
2251 // skip until "{" token
2252 while(COM_ParseToken_QuakeC(&in, false) && strcmp(com_token, "{"));
2254 // now, read in succession: string, comma-or-}
2255 while(COM_ParseToken_QuakeC(&in, false))
2257 tokens[line] = lines[line];
2258 strlcpy(lines[line++], com_token, sizeof(lines[0]));
2259 if(!COM_ParseToken_QuakeC(&in, false))
2261 if(!strcmp(com_token, "}"))
2263 if(strcmp(com_token, ","))
2265 if(line >= sizeof(tokens) / sizeof(tokens[0]))
2272 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2273 static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes)
2275 unsigned char i0 = (bytes > 0) ? in[0] : 0;
2276 unsigned char i1 = (bytes > 1) ? in[1] : 0;
2277 unsigned char i2 = (bytes > 2) ? in[2] : 0;
2278 unsigned char o0 = base64[i0 >> 2];
2279 unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077];
2280 unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077];
2281 unsigned char o3 = base64[i2 & 077];
2282 out[0] = (bytes > 0) ? o0 : '?';
2283 out[1] = (bytes > 0) ? o1 : '?';
2284 out[2] = (bytes > 1) ? o2 : '=';
2285 out[3] = (bytes > 2) ? o3 : '=';
2288 size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen)
2291 // expand the out-buffer
2292 blocks = (buflen + 2) / 3;
2293 if(blocks*4 > outbuflen)
2295 for(i = blocks; i > 0; )
2298 base64_3to4(buf + 3*i, buf + 4*i, buflen - 3*i);