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
31 cvar_t registered = {0, "registered","0", "indicates if this is running registered quake (whether gfx/pop.lmp was found)"};
32 cvar_t cmdline = {0, "cmdline","0", "contains commandline the engine was launched with"};
34 char com_token[MAX_INPUTLINE];
36 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 ============================================================================
57 float BuffBigFloat (const unsigned char *buffer)
65 u.i = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
69 int BuffBigLong (const unsigned char *buffer)
71 return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
74 short BuffBigShort (const unsigned char *buffer)
76 return (buffer[0] << 8) | buffer[1];
79 float BuffLittleFloat (const unsigned char *buffer)
87 u.i = (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
91 int BuffLittleLong (const unsigned char *buffer)
93 return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
96 short BuffLittleShort (const unsigned char *buffer)
98 return (buffer[1] << 8) | buffer[0];
101 void StoreBigLong (unsigned char *buffer, unsigned int i)
103 buffer[0] = (i >> 24) & 0xFF;
104 buffer[1] = (i >> 16) & 0xFF;
105 buffer[2] = (i >> 8) & 0xFF;
106 buffer[3] = i & 0xFF;
109 void StoreBigShort (unsigned char *buffer, unsigned short i)
111 buffer[0] = (i >> 8) & 0xFF;
112 buffer[1] = i & 0xFF;
115 void StoreLittleLong (unsigned char *buffer, unsigned int i)
117 buffer[0] = i & 0xFF;
118 buffer[1] = (i >> 8) & 0xFF;
119 buffer[2] = (i >> 16) & 0xFF;
120 buffer[3] = (i >> 24) & 0xFF;
123 void StoreLittleShort (unsigned char *buffer, unsigned short i)
125 buffer[0] = i & 0xFF;
126 buffer[1] = (i >> 8) & 0xFF;
130 ============================================================================
134 ============================================================================
137 // this is a 16 bit, non-reflected CRC using the polynomial 0x1021
138 // and the initial and final xor values shown below... in other words, the
139 // CCITT standard CRC used by XMODEM
141 #define CRC_INIT_VALUE 0xffff
142 #define CRC_XOR_VALUE 0x0000
144 static unsigned short crctable[256] =
146 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
147 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
148 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
149 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
150 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
151 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
152 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
153 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
154 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
155 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
156 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
157 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
158 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
159 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
160 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
161 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
162 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
163 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
164 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
165 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
166 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
167 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
168 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
169 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
170 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
171 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
172 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
173 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
174 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
175 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
176 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
177 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
180 unsigned short CRC_Block(const unsigned char *data, size_t size)
182 unsigned short crc = CRC_INIT_VALUE;
184 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)];
185 return crc ^ CRC_XOR_VALUE;
188 unsigned short CRC_Block_CaseInsensitive(const unsigned char *data, size_t size)
190 unsigned short crc = CRC_INIT_VALUE;
192 crc = (crc << 8) ^ crctable[(crc >> 8) ^ (tolower(*data++))];
193 return crc ^ CRC_XOR_VALUE;
197 static unsigned char chktbl[1024 + 4] =
199 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
200 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
201 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
202 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
203 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
204 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
205 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
206 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
207 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
208 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
209 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
210 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
211 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
212 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
213 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
214 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
215 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
216 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
217 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
218 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
219 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
220 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
221 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
222 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
223 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
224 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
225 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
226 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
227 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
228 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
229 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
230 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
232 // map checksum goes here
237 unsigned char COM_BlockSequenceCRCByteQW(unsigned char *base, int length, int sequence)
240 unsigned char chkb[60 + 4];
242 p = chktbl + (sequence % (sizeof(chktbl) - 8));
246 memcpy(chkb, base, length);
248 chkb[length] = (sequence & 0xff) ^ p[0];
249 chkb[length+1] = p[1];
250 chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
251 chkb[length+3] = p[3];
253 return CRC_Block(chkb, length + 4) & 0xff;
257 ==============================================================================
261 Handles byte ordering and avoids alignment errors
262 ==============================================================================
269 void MSG_WriteChar (sizebuf_t *sb, int c)
273 buf = SZ_GetSpace (sb, 1);
277 void MSG_WriteByte (sizebuf_t *sb, int c)
281 buf = SZ_GetSpace (sb, 1);
285 void MSG_WriteShort (sizebuf_t *sb, int c)
289 buf = SZ_GetSpace (sb, 2);
294 void MSG_WriteLong (sizebuf_t *sb, int c)
298 buf = SZ_GetSpace (sb, 4);
300 buf[1] = (c>>8)&0xff;
301 buf[2] = (c>>16)&0xff;
305 void MSG_WriteFloat (sizebuf_t *sb, float f)
315 dat.l = LittleLong (dat.l);
317 SZ_Write (sb, (unsigned char *)&dat.l, 4);
320 void MSG_WriteString (sizebuf_t *sb, const char *s)
323 MSG_WriteChar (sb, 0);
325 SZ_Write (sb, (unsigned char *)s, (int)strlen(s)+1);
328 void MSG_WriteUnterminatedString (sizebuf_t *sb, const char *s)
331 SZ_Write (sb, (unsigned char *)s, (int)strlen(s));
334 void MSG_WriteCoord13i (sizebuf_t *sb, float f)
337 MSG_WriteShort (sb, (int)(f * 8.0 + 0.5));
339 MSG_WriteShort (sb, (int)(f * 8.0 - 0.5));
342 void MSG_WriteCoord16i (sizebuf_t *sb, float f)
345 MSG_WriteShort (sb, (int)(f + 0.5));
347 MSG_WriteShort (sb, (int)(f - 0.5));
350 void MSG_WriteCoord32f (sizebuf_t *sb, float f)
352 MSG_WriteFloat (sb, f);
355 void MSG_WriteCoord (sizebuf_t *sb, float f, protocolversion_t protocol)
357 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
358 MSG_WriteCoord13i (sb, f);
359 else if (protocol == PROTOCOL_DARKPLACES1)
360 MSG_WriteCoord32f (sb, f);
361 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
362 MSG_WriteCoord16i (sb, f);
364 MSG_WriteCoord32f (sb, f);
367 void MSG_WriteVector (sizebuf_t *sb, float *v, protocolversion_t protocol)
369 MSG_WriteCoord (sb, v[0], protocol);
370 MSG_WriteCoord (sb, v[1], protocol);
371 MSG_WriteCoord (sb, v[2], protocol);
374 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
375 void MSG_WriteAngle8i (sizebuf_t *sb, float f)
378 MSG_WriteByte (sb, (int)(f*(256.0/360.0) + 0.5) & 255);
380 MSG_WriteByte (sb, (int)(f*(256.0/360.0) - 0.5) & 255);
383 void MSG_WriteAngle16i (sizebuf_t *sb, float f)
386 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) + 0.5) & 65535);
388 MSG_WriteShort (sb, (int)(f*(65536.0/360.0) - 0.5) & 65535);
391 void MSG_WriteAngle32f (sizebuf_t *sb, float f)
393 MSG_WriteFloat (sb, f);
396 void MSG_WriteAngle (sizebuf_t *sb, float f, protocolversion_t protocol)
398 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)
399 MSG_WriteAngle8i (sb, f);
401 MSG_WriteAngle16i (sb, f);
408 void MSG_BeginReading(sizebuf_t *sb)
414 int MSG_ReadLittleShort(sizebuf_t *sb)
416 if (sb->readcount+2 > sb->cursize)
422 return (short)(sb->data[sb->readcount-2] | (sb->data[sb->readcount-1]<<8));
425 int MSG_ReadBigShort (sizebuf_t *sb)
427 if (sb->readcount+2 > sb->cursize)
433 return (short)((sb->data[sb->readcount-2]<<8) + sb->data[sb->readcount-1]);
436 int MSG_ReadLittleLong (sizebuf_t *sb)
438 if (sb->readcount+4 > sb->cursize)
444 return sb->data[sb->readcount-4] | (sb->data[sb->readcount-3]<<8) | (sb->data[sb->readcount-2]<<16) | (sb->data[sb->readcount-1]<<24);
447 int MSG_ReadBigLong (sizebuf_t *sb)
449 if (sb->readcount+4 > sb->cursize)
455 return (sb->data[sb->readcount-4]<<24) + (sb->data[sb->readcount-3]<<16) + (sb->data[sb->readcount-2]<<8) + sb->data[sb->readcount-1];
458 float MSG_ReadLittleFloat (sizebuf_t *sb)
465 if (sb->readcount+4 > sb->cursize)
471 dat.l = sb->data[sb->readcount-4] | (sb->data[sb->readcount-3]<<8) | (sb->data[sb->readcount-2]<<16) | (sb->data[sb->readcount-1]<<24);
475 float MSG_ReadBigFloat (sizebuf_t *sb)
482 if (sb->readcount+4 > sb->cursize)
488 dat.l = (sb->data[sb->readcount-4]<<24) | (sb->data[sb->readcount-3]<<16) | (sb->data[sb->readcount-2]<<8) | sb->data[sb->readcount-1];
492 char *MSG_ReadString (sizebuf_t *sb, char *string, size_t maxstring)
496 // read string into sbfer, but only store as many characters as will fit
497 while ((c = MSG_ReadByte(sb)) > 0)
498 if (l < maxstring - 1)
504 int MSG_ReadBytes (sizebuf_t *sb, int numbytes, unsigned char *out)
507 for (l = 0;l < numbytes && (c = MSG_ReadByte(sb)) != -1;l++)
512 float MSG_ReadCoord13i (sizebuf_t *sb)
514 return MSG_ReadLittleShort(sb) * (1.0/8.0);
517 float MSG_ReadCoord16i (sizebuf_t *sb)
519 return (signed short) MSG_ReadLittleShort(sb);
522 float MSG_ReadCoord32f (sizebuf_t *sb)
524 return MSG_ReadLittleFloat(sb);
527 float MSG_ReadCoord (sizebuf_t *sb, protocolversion_t protocol)
529 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
530 return MSG_ReadCoord13i(sb);
531 else if (protocol == PROTOCOL_DARKPLACES1)
532 return MSG_ReadCoord32f(sb);
533 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
534 return MSG_ReadCoord16i(sb);
536 return MSG_ReadCoord32f(sb);
539 void MSG_ReadVector (sizebuf_t *sb, float *v, protocolversion_t protocol)
541 v[0] = MSG_ReadCoord(sb, protocol);
542 v[1] = MSG_ReadCoord(sb, protocol);
543 v[2] = MSG_ReadCoord(sb, protocol);
546 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
547 float MSG_ReadAngle8i (sizebuf_t *sb)
549 return (signed char) MSG_ReadByte (sb) * (360.0/256.0);
552 float MSG_ReadAngle16i (sizebuf_t *sb)
554 return (signed short)MSG_ReadShort (sb) * (360.0/65536.0);
557 float MSG_ReadAngle32f (sizebuf_t *sb)
559 return MSG_ReadFloat (sb);
562 float MSG_ReadAngle (sizebuf_t *sb, protocolversion_t protocol)
564 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)
565 return MSG_ReadAngle8i (sb);
567 return MSG_ReadAngle16i (sb);
571 //===========================================================================
573 void SZ_Clear (sizebuf_t *buf)
578 unsigned char *SZ_GetSpace (sizebuf_t *buf, int length)
582 if (buf->cursize + length > buf->maxsize)
584 if (!buf->allowoverflow)
585 Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
587 if (length > buf->maxsize)
588 Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
590 buf->overflowed = true;
591 Con_Print("SZ_GetSpace: overflow\n");
595 data = buf->data + buf->cursize;
596 buf->cursize += length;
601 void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length)
603 memcpy (SZ_GetSpace(buf,length),data,length);
606 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
607 // attention, it has been eradicated from here, its only (former) use in
608 // all of darkplaces.
610 static const char *hexchar = "0123456789ABCDEF";
611 void Com_HexDumpToConsole(const unsigned char *data, int size)
615 char *cur, *flushpointer;
616 const unsigned char *d;
618 flushpointer = text + 512;
619 for (i = 0;i < size;)
626 *cur++ = hexchar[(i >> 12) & 15];
627 *cur++ = hexchar[(i >> 8) & 15];
628 *cur++ = hexchar[(i >> 4) & 15];
629 *cur++ = hexchar[(i >> 0) & 15];
632 for (j = 0;j < 16;j++)
636 *cur++ = hexchar[(d[j] >> 4) & 15];
637 *cur++ = hexchar[(d[j] >> 0) & 15];
648 for (j = 0;j < 16;j++)
652 // color change prefix character has to be treated specially
653 if (d[j] == STRING_COLOR_TAG)
655 *cur++ = STRING_COLOR_TAG;
656 *cur++ = STRING_COLOR_TAG;
658 else if (d[j] >= (unsigned char) ' ')
668 if (cur >= flushpointer || i >= size)
677 void SZ_HexDumpToConsole(const sizebuf_t *buf)
679 Com_HexDumpToConsole(buf->data, buf->cursize);
683 //============================================================================
689 Word wraps a string. The wordWidth function is guaranteed to be called exactly
690 once for each word in the string, so it may be stateful, no idea what that
691 would be good for any more. At the beginning of the string, it will be called
692 for the char 0 to initialize a clean state, and then once with the string " "
693 (a space) so the routine knows how long a space is.
695 In case no single character fits into the given width, the wordWidth function
696 must return the width of exactly one character.
698 Wrapped lines get the isContinuation flag set and are continuationWidth less wide.
700 The sum of the return values of the processLine function will be returned.
703 int COM_Wordwrap(const char *string, size_t length, float continuationWidth, float maxWidth, COM_WordWidthFunc_t wordWidth, void *passthroughCW, COM_LineProcessorFunc processLine, void *passthroughPL)
705 // Logic is as follows:
707 // For each word or whitespace:
708 // Newline found? Output current line, advance to next line. This is not a continuation. Continue.
709 // Space found? Always add it to the current line, no matter if it fits.
710 // Word found? Check if current line + current word fits.
711 // If it fits, append it. Continue.
712 // If it doesn't fit, output current line, advance to next line. Append the word. This is a continuation. Continue.
714 qboolean isContinuation = false;
716 const char *startOfLine = string;
717 const char *cursor = string;
718 const char *end = string + length;
719 float spaceUsedInLine = 0;
720 float spaceUsedForWord;
726 wordWidth(passthroughCW, NULL, &dummy, -1);
728 spaceWidth = wordWidth(passthroughCW, " ", &dummy, -1);
732 char ch = (cursor < end) ? *cursor : 0;
735 case 0: // end of string
736 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
737 isContinuation = false;
739 case '\n': // end of line
740 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
741 isContinuation = false;
743 startOfLine = cursor;
747 spaceUsedInLine += spaceWidth;
751 while(cursor + wordLen < end)
753 switch(cursor[wordLen])
765 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
766 if(wordLen < 1) // cannot happen according to current spec of wordWidth
769 spaceUsedForWord = maxWidth + 1; // too high, forces it in a line of itself
771 if(spaceUsedInLine + spaceUsedForWord <= maxWidth || cursor == startOfLine)
773 // we can simply append it
775 spaceUsedInLine += spaceUsedForWord;
779 // output current line
780 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
781 isContinuation = true;
782 startOfLine = cursor;
784 spaceUsedInLine = continuationWidth + spaceUsedForWord;
793 qboolean isContinuation = false;
794 float currentWordSpace = 0;
795 const char *currentWord = 0;
796 float minReserve = 0;
798 float spaceUsedInLine = 0;
799 const char *currentLine = 0;
800 const char *currentLineEnd = 0;
801 float currentLineFinalWhitespace = 0;
805 minReserve = charWidth(passthroughCW, 0);
806 minReserve += charWidth(passthroughCW, ' ');
808 if(maxWidth < continuationWidth + minReserve)
809 maxWidth = continuationWidth + minReserve;
811 charWidth(passthroughCW, 0);
813 for(p = string; p < string + length; ++p)
816 float w = charWidth(passthroughCW, c);
821 currentWordSpace = 0;
827 spaceUsedInLine = isContinuation ? continuationWidth : 0;
833 // 1. I can add the word AND a space - then just append it.
834 if(spaceUsedInLine + currentWordSpace + w <= maxWidth)
836 currentLineEnd = p; // note: space not included here
837 currentLineFinalWhitespace = w;
838 spaceUsedInLine += currentWordSpace + w;
840 // 2. I can just add the word - then append it, output current line and go to next one.
841 else if(spaceUsedInLine + currentWordSpace <= maxWidth)
843 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
845 isContinuation = true;
847 // 3. Otherwise, output current line and go to next one, where I can add the word.
848 else if(continuationWidth + currentWordSpace + w <= maxWidth)
851 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
852 currentLine = currentWord;
853 spaceUsedInLine = continuationWidth + currentWordSpace + w;
855 currentLineFinalWhitespace = w;
856 isContinuation = true;
858 // 4. We can't even do that? Then output both current and next word as new lines.
863 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
864 isContinuation = true;
866 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
868 isContinuation = true;
874 // 1. I can add the word - then do it.
875 if(spaceUsedInLine + currentWordSpace <= maxWidth)
877 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
879 // 2. Otherwise, output current line, next one and make tabula rasa.
884 processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
885 isContinuation = true;
887 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
891 isContinuation = false;
895 currentWordSpace += w;
897 spaceUsedInLine + currentWordSpace > maxWidth // can't join this line...
899 continuationWidth + currentWordSpace > maxWidth // can't join any other line...
902 // this word cannot join ANY line...
903 // so output the current line...
906 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
907 isContinuation = true;
910 // then this word's beginning...
913 // it may not fit, but we know we have to split it into maxWidth - continuationWidth pieces
914 float pieceWidth = maxWidth - continuationWidth;
915 const char *pos = currentWord;
916 currentWordSpace = 0;
918 // reset the char width function to a state where no kerning occurs (start of word)
919 charWidth(passthroughCW, ' ');
922 float w = charWidth(passthroughCW, *pos);
923 if(currentWordSpace + w > pieceWidth) // this piece won't fit any more
925 // print everything until it
926 result += processLine(passthroughPL, currentWord, pos - currentWord, currentWordSpace, true);
929 currentWordSpace = 0;
931 currentWordSpace += w;
934 // now we have a currentWord that fits... set up its next line
935 // currentWordSpace has been set
936 // currentWord has been set
937 spaceUsedInLine = continuationWidth;
938 currentLine = currentWord;
940 isContinuation = true;
944 // we have a guarantee that it will fix (see if clause)
945 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace - w, isContinuation);
947 // and use the rest of this word as new start of a line
948 currentWordSpace = w;
950 spaceUsedInLine = continuationWidth;
953 isContinuation = true;
962 currentWordSpace = 0;
965 if(currentLine) // Same procedure as \n
967 // Can I append the current word?
968 if(spaceUsedInLine + currentWordSpace <= maxWidth)
969 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
974 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
975 isContinuation = true;
977 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
987 COM_ParseToken_Simple
989 Parse a token out of a string
992 int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash, qboolean parsecomments)
996 const char *data = *datapointer;
1003 *datapointer = NULL;
1013 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1018 *datapointer = NULL;
1023 // handle Windows line ending
1024 if (data[0] == '\r' && data[1] == '\n')
1027 if (parsecomments && data[0] == '/' && data[1] == '/')
1030 while (*data && *data != '\n' && *data != '\r')
1034 else if (parsecomments && data[0] == '/' && data[1] == '*')
1038 while (*data && (data[0] != '*' || data[1] != '/'))
1046 else if (*data == '\"')
1049 for (data++;*data && *data != '\"';data++)
1052 if (*data == '\\' && parsebackslash)
1061 if (len < (int)sizeof(com_token) - 1)
1062 com_token[len++] = c;
1067 *datapointer = data;
1070 else if (*data == '\r')
1072 // translate Mac line ending to UNIX
1073 com_token[len++] = '\n';data++;
1075 *datapointer = data;
1078 else if (*data == '\n')
1081 com_token[len++] = *data++;
1083 *datapointer = data;
1089 for (;!ISWHITESPACE(*data);data++)
1090 if (len < (int)sizeof(com_token) - 1)
1091 com_token[len++] = *data;
1093 *datapointer = data;
1100 COM_ParseToken_QuakeC
1102 Parse a token out of a string
1105 int COM_ParseToken_QuakeC(const char **datapointer, qboolean returnnewline)
1109 const char *data = *datapointer;
1116 *datapointer = NULL;
1126 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1131 *datapointer = NULL;
1136 // handle Windows line ending
1137 if (data[0] == '\r' && data[1] == '\n')
1140 if (data[0] == '/' && data[1] == '/')
1143 while (*data && *data != '\n' && *data != '\r')
1147 else if (data[0] == '/' && data[1] == '*')
1151 while (*data && (data[0] != '*' || data[1] != '/'))
1159 else if (*data == '\"' || *data == '\'')
1163 for (data++;*data && *data != quote;data++)
1175 if (len < (int)sizeof(com_token) - 1)
1176 com_token[len++] = c;
1181 *datapointer = data;
1184 else if (*data == '\r')
1186 // translate Mac line ending to UNIX
1187 com_token[len++] = '\n';data++;
1189 *datapointer = data;
1192 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1195 com_token[len++] = *data++;
1197 *datapointer = data;
1203 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1204 if (len < (int)sizeof(com_token) - 1)
1205 com_token[len++] = *data;
1207 *datapointer = data;
1214 COM_ParseToken_VM_Tokenize
1216 Parse a token out of a string
1219 int COM_ParseToken_VM_Tokenize(const char **datapointer, qboolean returnnewline)
1223 const char *data = *datapointer;
1230 *datapointer = NULL;
1240 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1245 *datapointer = NULL;
1250 // handle Windows line ending
1251 if (data[0] == '\r' && data[1] == '\n')
1254 if (data[0] == '/' && data[1] == '/')
1257 while (*data && *data != '\n' && *data != '\r')
1261 else if (data[0] == '/' && data[1] == '*')
1265 while (*data && (data[0] != '*' || data[1] != '/'))
1273 else if (*data == '\"' || *data == '\'')
1277 for (data++;*data && *data != quote;data++)
1289 if (len < (int)sizeof(com_token) - 1)
1290 com_token[len++] = c;
1295 *datapointer = data;
1298 else if (*data == '\r')
1300 // translate Mac line ending to UNIX
1301 com_token[len++] = '\n';data++;
1303 *datapointer = data;
1306 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1309 com_token[len++] = *data++;
1311 *datapointer = data;
1317 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1318 if (len < (int)sizeof(com_token) - 1)
1319 com_token[len++] = *data;
1321 *datapointer = data;
1328 COM_ParseToken_Console
1330 Parse a token out of a string, behaving like the qwcl console
1333 int COM_ParseToken_Console(const char **datapointer)
1336 const char *data = *datapointer;
1343 *datapointer = NULL;
1349 for (;ISWHITESPACE(*data);data++)
1354 *datapointer = NULL;
1359 if (*data == '/' && data[1] == '/')
1362 while (*data && *data != '\n' && *data != '\r')
1366 else if (*data == '\"')
1369 for (data++;*data && *data != '\"';data++)
1371 // allow escaped " and \ case
1372 if (*data == '\\' && (data[1] == '\"' || data[1] == '\\'))
1374 if (len < (int)sizeof(com_token) - 1)
1375 com_token[len++] = *data;
1380 *datapointer = data;
1385 for (;!ISWHITESPACE(*data);data++)
1386 if (len < (int)sizeof(com_token) - 1)
1387 com_token[len++] = *data;
1389 *datapointer = data;
1400 Returns the position (1 to argc-1) in the program's argument list
1401 where the given parameter apears, or 0 if not present
1404 int COM_CheckParm (const char *parm)
1408 for (i=1 ; i<com_argc ; i++)
1411 continue; // NEXTSTEP sometimes clears appkit vars.
1412 if (!strcmp (parm,com_argv[i]))
1419 //===========================================================================
1423 gamemode_t com_startupgamemode;
1424 gamemode_t com_startupgamegroup;
1426 typedef struct gamemode_info_s
1428 gamemode_t mode; // this gamemode
1429 gamemode_t group; // different games with same group can switch automatically when gamedirs change
1430 const char* prog_name; // not null
1431 const char* cmdline; // not null
1432 const char* gamename; // not null
1433 const char* gamedirname1; // not null
1434 const char* gamedirname2; // null
1435 const char* gamescreenshotname; // not nul
1436 const char* gameuserdirname; // not null
1439 static const gamemode_info_t gamemode_info [GAME_COUNT] =
1440 {// game basegame prog_name cmdline gamename basegame modgame screenshot userdir // commandline option
1441 { GAME_NORMAL, GAME_NORMAL, "", "-quake", "DarkPlaces-Quake", "id1", NULL, "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
1442 { GAME_HIPNOTIC, GAME_NORMAL, "hipnotic", "-hipnotic", "Darkplaces-Hipnotic", "id1", "hipnotic", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
1443 { GAME_ROGUE, GAME_NORMAL, "rogue", "-rogue", "Darkplaces-Rogue", "id1", "rogue", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
1444 { GAME_NEHAHRA, GAME_NORMAL, "nehahra", "-nehahra", "DarkPlaces-Nehahra", "id1", "nehahra", "dp", "darkplaces" }, // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
1445 { GAME_NEXUIZ, GAME_NEXUIZ, "nexuiz", "-nexuiz", "Nexuiz", "data", NULL, "nexuiz", "nexuiz" }, // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
1446 { GAME_XONOTIC, GAME_XONOTIC, "xonotic", "-xonotic", "Xonotic", "data", NULL, "xonotic", "xonotic" }, // COMMANDLINEOPTION: Game: -xonotic runs the multiplayer game Xonotic
1447 { GAME_TRANSFUSION, GAME_TRANSFUSION, "transfusion", "-transfusion", "Transfusion", "basetf", NULL, "transfusion", "transfusion" }, // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
1448 { 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
1449 { 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)
1450 { GAME_BATTLEMECH, GAME_BATTLEMECH, "battlemech", "-battlemech", "Battlemech", "base", NULL, "battlemech", "battlemech" }, // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
1451 { GAME_ZYMOTIC, GAME_ZYMOTIC, "zymotic", "-zymotic", "Zymotic", "basezym", NULL, "zymotic", "zymotic" }, // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
1452 { GAME_SETHERAL, GAME_SETHERAL, "setheral", "-setheral", "Setheral", "data", NULL, "setheral", "setheral" }, // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
1453 { GAME_SOM, GAME_NORMAL, "sonofman", "-som", "Son of Man", "id1", "sonofman", "som", "darkplaces" }, // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
1454 { 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)
1455 { GAME_NEOTERIC, GAME_NORMAL, "neoteric", "-neoteric", "Neoteric", "id1", "neobase", "neo", "darkplaces" }, // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
1456 { 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
1457 { GAME_PRYDON, GAME_NORMAL, "prydon", "-prydon", "PrydonGate", "id1", "prydon", "prydon", "darkplaces" }, // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
1458 { GAME_DELUXEQUAKE, GAME_DELUXEQUAKE, "dq", "-dq", "Deluxe Quake", "basedq", "extradq", "basedq", "dq" }, // COMMANDLINEOPTION: Game: -dq runs the game Deluxe Quake
1459 { GAME_THEHUNTED, GAME_THEHUNTED, "thehunted", "-thehunted", "The Hunted", "thdata", NULL, "th", "thehunted" }, // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
1460 { GAME_DEFEATINDETAIL2, GAME_DEFEATINDETAIL2, "did2", "-did2", "Defeat In Detail 2", "data", NULL, "did2_", "did2" }, // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
1461 { GAME_DARSANA, GAME_DARSANA, "darsana", "-darsana", "Darsana", "ddata", NULL, "darsana", "darsana" }, // COMMANDLINEOPTION: Game: -darsana runs the game Darsana
1462 { GAME_CONTAGIONTHEORY, GAME_CONTAGIONTHEORY, "contagiontheory", "-contagiontheory", "Contagion Theory", "ctdata", NULL, "ct", "contagiontheory" }, // COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory
1463 { GAME_EDU2P, GAME_EDU2P, "edu2p", "-edu2p", "EDU2 Prototype", "id1", "edu2", "edu2_p", "edu2prototype" }, // COMMANDLINEOPTION: Game: -edu2p runs the game Edu2 prototype
1464 { GAME_PROPHECY, GAME_PROPHECY, "prophecy", "-prophecy", "Prophecy", "gamedata", NULL, "phcy", "prophecy" }, // COMMANDLINEOPTION: Game: -prophecy runs the game Prophecy
1465 { GAME_BLOODOMNICIDE, GAME_BLOODOMNICIDE, "omnicide", "-omnicide", "Blood Omnicide", "kain", NULL, "omnicide", "omnicide" }, // COMMANDLINEOPTION: Game: -omnicide runs the game Blood Omnicide
1466 { GAME_STEELSTORM, GAME_STEELSTORM, "steelstorm", "-steelstorm", "Steel-Storm", "gamedata", NULL, "ss", "steelstorm" }, // COMMANDLINEOPTION: Game: -steelstorm runs the game Steel Storm
1467 { GAME_STEELSTORM2, GAME_STEELSTORM2, "steelstorm2", "-steelstorm2", "Steel Storm 2", "gamedata", NULL, "ss2", "steelstorm2" }, // COMMANDLINEOPTION: Game: -steelstorm2 runs the game Steel Storm 2
1468 { GAME_TOMESOFMEPHISTOPHELES, GAME_TOMESOFMEPHISTOPHELES, "tomesofmephistopheles", "-tomesofmephistopheles", "Tomes of Mephistopheles", "gamedata", NULL, "tom", "tomesofmephistopheles" }, // 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 // check executable filename for keywords, but do it SMARTLY - only check the last path element
1481 FS_StripExtension(FS_FileWithoutPath(com_argv[0]), name, sizeof (name));
1482 COM_ToLowerString(name, name, sizeof (name));
1483 for (i = 1;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1484 if (gamemode_info[i].prog_name && gamemode_info[i].prog_name[0] && strstr (name, gamemode_info[i].prog_name))
1487 // check commandline options for keywords
1488 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1489 if (COM_CheckParm (gamemode_info[i].cmdline))
1492 com_startupgamemode = gamemode_info[index].mode;
1493 com_startupgamegroup = gamemode_info[index].group;
1494 COM_SetGameType(index);
1497 void COM_ChangeGameTypeForGameDirs(void)
1501 // this will not not change the gamegroup
1502 // first check if a base game (single gamedir) matches
1503 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1505 if (gamemode_info[i].group == com_startupgamegroup && !(gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]))
1511 // now that we have a base game, see if there is a matching derivative game (two gamedirs)
1514 for (i = 0;i < (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0]));i++)
1516 if (gamemode_info[i].group == com_startupgamegroup && (gamemode_info[i].gamedirname2 && gamemode_info[i].gamedirname2[0]) && !strcasecmp(fs_gamedirs[0], gamemode_info[i].gamedirname2))
1523 // we now have a good guess at which game this is meant to be...
1524 if (index >= 0 && gamemode != gamemode_info[index].mode)
1525 COM_SetGameType(index);
1528 static void COM_SetGameType(int index)
1531 if (index < 0 || index >= (int)(sizeof (gamemode_info) / sizeof (gamemode_info[0])))
1533 gamemode = gamemode_info[index].mode;
1534 gamename = gamemode_info[index].gamename;
1535 gamedirname1 = gamemode_info[index].gamedirname1;
1536 gamedirname2 = gamemode_info[index].gamedirname2;
1537 gamescreenshotname = gamemode_info[index].gamescreenshotname;
1538 gameuserdirname = gamemode_info[index].gameuserdirname;
1540 if (gamemode == com_startupgamemode)
1542 if((t = COM_CheckParm("-customgamename")) && t + 1 < com_argc)
1543 gamename = com_argv[t+1];
1544 if((t = COM_CheckParm("-customgamedirname1")) && t + 1 < com_argc)
1545 gamedirname1 = com_argv[t+1];
1546 if((t = COM_CheckParm("-customgamedirname2")) && t + 1 < com_argc)
1547 gamedirname2 = *com_argv[t+1] ? com_argv[t+1] : NULL;
1548 if((t = COM_CheckParm("-customgamescreenshotname")) && t + 1 < com_argc)
1549 gamescreenshotname = com_argv[t+1];
1550 if((t = COM_CheckParm("-customgameuserdirname")) && t + 1 < com_argc)
1551 gameuserdirname = com_argv[t+1];
1554 if (gamedirname2 && gamedirname2[0])
1555 Con_Printf("Game is %s using base gamedirs %s %s", gamename, gamedirname1, gamedirname2);
1557 Con_Printf("Game is %s using base gamedir %s", gamename, gamedirname1);
1558 for (i = 0;i < fs_numgamedirs;i++)
1561 Con_Printf(", with mod gamedirs");
1562 Con_Printf(" %s", fs_gamedirs[i]);
1573 void COM_Init_Commands (void)
1576 char com_cmdline[MAX_INPUTLINE];
1578 Cvar_RegisterVariable (®istered);
1579 Cvar_RegisterVariable (&cmdline);
1581 // reconstitute the command line for the cmdline externally visible cvar
1583 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
1586 if (strstr(com_argv[j], " "))
1588 // arg contains whitespace, store quotes around it
1589 com_cmdline[n++] = '\"';
1590 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1591 com_cmdline[n++] = com_argv[j][i++];
1592 com_cmdline[n++] = '\"';
1596 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1597 com_cmdline[n++] = com_argv[j][i++];
1599 if (n < ((int)sizeof(com_cmdline) - 1))
1600 com_cmdline[n++] = ' ';
1605 Cvar_Set ("cmdline", com_cmdline);
1612 varargs print into provided buffer, returns buffer (so that it can be called in-line, unlike dpsnprintf)
1615 char *va(char *buf, size_t buflen, const char *format, ...)
1619 va_start (argptr, format);
1620 dpvsnprintf (buf, buflen, format,argptr);
1627 //======================================
1629 // snprintf and vsnprintf are NOT portable. Use their DP counterparts instead
1635 # define snprintf _snprintf
1636 # define vsnprintf _vsnprintf
1640 int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...)
1645 va_start (args, format);
1646 result = dpvsnprintf (buffer, buffersize, format, args);
1653 int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args)
1657 #if _MSC_VER >= 1400
1658 result = _vsnprintf_s (buffer, buffersize, _TRUNCATE, format, args);
1660 result = vsnprintf (buffer, buffersize, format, args);
1662 if (result < 0 || (size_t)result >= buffersize)
1664 buffer[buffersize - 1] = '\0';
1672 //======================================
1674 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1679 if(utf8_enable.integer)
1682 while(*in && size_out > 1)
1685 Uchar ch = u8_getchar_utf8_enabled(in, &in);
1686 ch = u8_tolower(ch);
1687 n = u8_fromchar(ch, out, size_out);
1696 while (*in && size_out > 1)
1698 if (*in >= 'A' && *in <= 'Z')
1699 *out++ = *in++ + 'a' - 'A';
1707 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1712 if(utf8_enable.integer)
1715 while(*in && size_out > 1)
1718 Uchar ch = u8_getchar_utf8_enabled(in, &in);
1719 ch = u8_toupper(ch);
1720 n = u8_fromchar(ch, out, size_out);
1729 while (*in && size_out > 1)
1731 if (*in >= 'a' && *in <= 'z')
1732 *out++ = *in++ + 'A' - 'a';
1740 int COM_StringBeginsWith(const char *s, const char *match)
1742 for (;*s && *match;s++, match++)
1748 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1750 int argc, commentprefixlength;
1754 tokenbufend = tokenbuf + tokenbufsize;
1756 commentprefixlength = 0;
1758 commentprefixlength = (int)strlen(commentprefix);
1759 while (*l && *l != '\n' && *l != '\r')
1761 if (!ISWHITESPACE(*l))
1763 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1765 while (*l && *l != '\n' && *l != '\r')
1769 if (argc >= maxargc)
1771 argv[argc++] = tokenbuf;
1775 while (*l && *l != '"')
1777 if (tokenbuf >= tokenbufend)
1786 while (!ISWHITESPACE(*l))
1788 if (tokenbuf >= tokenbufend)
1793 if (tokenbuf >= tokenbufend)
1814 COM_StringLengthNoColors
1816 calculates the visible width of a color coded string.
1818 *valid is filled with TRUE if the string is a valid colored string (that is, if
1819 it does not end with an unfinished color code). If it gets filled with FALSE, a
1820 fix would be adding a STRING_COLOR_TAG at the end of the string.
1822 valid can be set to NULL if the caller doesn't care.
1824 For size_s, specify the maximum number of characters from s to use, or 0 to use
1825 all characters until the zero terminator.
1829 COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid)
1831 const char *end = size_s ? (s + size_s) : NULL;
1835 switch((s == end) ? 0 : *s)
1841 case STRING_COLOR_TAG:
1843 switch((s == end) ? 0 : *s)
1845 case STRING_COLOR_RGB_TAG_CHAR:
1846 if (s+1 != end && isxdigit(s[1]) &&
1847 s+2 != end && isxdigit(s[2]) &&
1848 s+3 != end && isxdigit(s[3]) )
1853 ++len; // STRING_COLOR_TAG
1854 ++len; // STRING_COLOR_RGB_TAG_CHAR
1856 case 0: // ends with unfinished color code!
1861 case STRING_COLOR_TAG: // escaped ^
1864 case '0': case '1': case '2': case '3': case '4':
1865 case '5': case '6': case '7': case '8': case '9': // color code
1867 default: // not a color code
1868 ++len; // STRING_COLOR_TAG
1869 ++len; // the character
1884 COM_StringDecolorize
1886 removes color codes from a string.
1888 If escape_carets is true, the resulting string will be safe for printing. If
1889 escape_carets is false, the function will just strip color codes (for logging
1892 If the output buffer size did not suffice for converting, the function returns
1893 FALSE. Generally, if escape_carets is false, the output buffer needs
1894 strlen(str)+1 bytes, and if escape_carets is true, it can need strlen(str)*1.5+2
1895 bytes. In any case, the function makes sure that the resulting string is
1898 For size_in, specify the maximum number of characters from in to use, or 0 to use
1899 all characters until the zero terminator.
1903 COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets)
1905 #define APPEND(ch) do { if(--size_out) { *out++ = (ch); } else { *out++ = 0; return FALSE; } } while(0)
1906 const char *end = size_in ? (in + size_in) : NULL;
1911 switch((in == end) ? 0 : *in)
1916 case STRING_COLOR_TAG:
1918 switch((in == end) ? 0 : *in)
1920 case STRING_COLOR_RGB_TAG_CHAR:
1921 if (in+1 != end && isxdigit(in[1]) &&
1922 in+2 != end && isxdigit(in[2]) &&
1923 in+3 != end && isxdigit(in[3]) )
1928 APPEND(STRING_COLOR_TAG);
1930 APPEND(STRING_COLOR_TAG);
1931 APPEND(STRING_COLOR_RGB_TAG_CHAR);
1933 case 0: // ends with unfinished color code!
1934 APPEND(STRING_COLOR_TAG);
1935 // finish the code by appending another caret when escaping
1937 APPEND(STRING_COLOR_TAG);
1940 case STRING_COLOR_TAG: // escaped ^
1941 APPEND(STRING_COLOR_TAG);
1942 // append a ^ twice when escaping
1944 APPEND(STRING_COLOR_TAG);
1946 case '0': case '1': case '2': case '3': case '4':
1947 case '5': case '6': case '7': case '8': case '9': // color code
1949 default: // not a color code
1950 APPEND(STRING_COLOR_TAG);
1965 char *InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
1971 keylength = strlen(key);
1972 if (valuelength < 1 || !value)
1974 Con_Printf("InfoString_GetValue: no room in value\n");
1978 if (strchr(key, '\\'))
1980 Con_Printf("InfoString_GetValue: key name \"%s\" contains \\ which is not possible in an infostring\n", key);
1983 if (strchr(key, '\"'))
1985 Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key);
1990 Con_Printf("InfoString_GetValue: can not look up a key with no name\n");
1993 while (buffer[pos] == '\\')
1995 if (!memcmp(buffer + pos+1, key, keylength))
1997 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
1999 for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++)
2000 value[j] = buffer[pos+j];
2004 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2005 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2007 // if we reach this point the key was not found
2011 void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value)
2019 keylength = strlen(key);
2020 if (strchr(key, '\\') || strchr(value, '\\'))
2022 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \\ which is not possible to store in an infostring\n", key, value);
2025 if (strchr(key, '\"') || strchr(value, '\"'))
2027 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \" which is not allowed in an infostring\n", key, value);
2032 Con_Printf("InfoString_SetValue: can not set 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++);
2040 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2042 // if we found the key, find the end of it because we will be replacing it
2044 if (buffer[pos] == '\\')
2046 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2047 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2049 if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2))
2051 Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value);
2054 if (value && value[0])
2056 // set the key/value and append the remaining text
2057 char tempbuffer[MAX_INPUTLINE];
2058 strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer));
2059 dpsnprintf(buffer + pos, bufferlength - pos, "\\%s\\%s%s", key, value, tempbuffer);
2063 // just remove the key from the text
2064 strlcpy(buffer + pos, buffer + pos2, bufferlength - pos);
2068 void InfoString_Print(char *buffer)
2071 char key[MAX_INPUTLINE];
2072 char value[MAX_INPUTLINE];
2075 if (*buffer != '\\')
2077 Con_Printf("InfoString_Print: corrupt string\n");
2080 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2081 if (i < (int)sizeof(key)-1)
2084 if (*buffer != '\\')
2086 Con_Printf("InfoString_Print: corrupt string\n");
2089 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2090 if (i < (int)sizeof(value)-1)
2091 value[i++] = *buffer;
2093 // empty value is an error case
2094 Con_Printf("%20s %s\n", key, value[0] ? value : "NO VALUE");
2098 //========================================================
2099 // strlcat and strlcpy, from OpenBSD
2102 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
2104 * Permission to use, copy, modify, and distribute this software for any
2105 * purpose with or without fee is hereby granted, provided that the above
2106 * copyright notice and this permission notice appear in all copies.
2108 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2109 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2110 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2111 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2112 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2113 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2114 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2117 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
2118 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
2121 #ifndef HAVE_STRLCAT
2123 strlcat(char *dst, const char *src, size_t siz)
2125 register char *d = dst;
2126 register const char *s = src;
2127 register size_t n = siz;
2130 /* Find the end of dst and adjust bytes left but don't go past end */
2131 while (n-- != 0 && *d != '\0')
2137 return(dlen + strlen(s));
2138 while (*s != '\0') {
2147 return(dlen + (s - src)); /* count does not include NUL */
2149 #endif // #ifndef HAVE_STRLCAT
2152 #ifndef HAVE_STRLCPY
2154 strlcpy(char *dst, const char *src, size_t siz)
2156 register char *d = dst;
2157 register const char *s = src;
2158 register size_t n = siz;
2160 /* Copy as many bytes as will fit */
2161 if (n != 0 && --n != 0) {
2163 if ((*d++ = *s++) == 0)
2168 /* Not enough room in dst, add NUL and traverse rest of src */
2171 *d = '\0'; /* NUL-terminate dst */
2176 return(s - src - 1); /* count does not include NUL */
2179 #endif // #ifndef HAVE_STRLCPY
2181 void FindFraction(double val, int *num, int *denom, int denomMax)
2186 bestdiff = fabs(val);
2190 for(i = 1; i <= denomMax; ++i)
2192 int inum = (int) floor(0.5 + val * i);
2193 double diff = fabs(val - inum / (double)i);
2203 // decodes an XPM from C syntax
2204 char **XPM_DecodeString(const char *in)
2206 static char *tokens[257];
2207 static char lines[257][512];
2210 // skip until "{" token
2211 while(COM_ParseToken_QuakeC(&in, false) && strcmp(com_token, "{"));
2213 // now, read in succession: string, comma-or-}
2214 while(COM_ParseToken_QuakeC(&in, false))
2216 tokens[line] = lines[line];
2217 strlcpy(lines[line++], com_token, sizeof(lines[0]));
2218 if(!COM_ParseToken_QuakeC(&in, false))
2220 if(!strcmp(com_token, "}"))
2222 if(strcmp(com_token, ","))
2224 if(line >= sizeof(tokens) / sizeof(tokens[0]))
2231 static const char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
2232 static void base64_3to4(const unsigned char *in, unsigned char *out, int bytes)
2234 unsigned char i0 = (bytes > 0) ? in[0] : 0;
2235 unsigned char i1 = (bytes > 1) ? in[1] : 0;
2236 unsigned char i2 = (bytes > 2) ? in[2] : 0;
2237 unsigned char o0 = base64[i0 >> 2];
2238 unsigned char o1 = base64[((i0 << 4) | (i1 >> 4)) & 077];
2239 unsigned char o2 = base64[((i1 << 2) | (i2 >> 6)) & 077];
2240 unsigned char o3 = base64[i2 & 077];
2241 out[0] = (bytes > 0) ? o0 : '?';
2242 out[1] = (bytes > 0) ? o1 : '?';
2243 out[2] = (bytes > 1) ? o2 : '=';
2244 out[3] = (bytes > 2) ? o3 : '=';
2247 size_t base64_encode(unsigned char *buf, size_t buflen, size_t outbuflen)
2250 // expand the out-buffer
2251 blocks = (buflen + 2) / 3;
2252 if(blocks*4 > outbuflen)
2254 for(i = blocks; i > 0; )
2257 base64_3to4(buf + 3*i, buf + 4*i, buflen - 3*i);