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++)
503 int MSG_ReadBytes (int numbytes, unsigned char *out)
506 for (l = 0;l < numbytes && (c = MSG_ReadByte()) != -1;l++)
511 float MSG_ReadCoord13i (void)
513 return MSG_ReadLittleShort() * (1.0/8.0);
516 float MSG_ReadCoord16i (void)
518 return (signed short) MSG_ReadLittleShort();
521 float MSG_ReadCoord32f (void)
523 return MSG_ReadLittleFloat();
526 float MSG_ReadCoord (protocolversion_t protocol)
528 if (protocol == PROTOCOL_QUAKE || protocol == PROTOCOL_QUAKEDP || protocol == PROTOCOL_NEHAHRAMOVIE || protocol == PROTOCOL_NEHAHRABJP || protocol == PROTOCOL_NEHAHRABJP2 || protocol == PROTOCOL_NEHAHRABJP3 || protocol == PROTOCOL_QUAKEWORLD)
529 return MSG_ReadCoord13i();
530 else if (protocol == PROTOCOL_DARKPLACES1)
531 return MSG_ReadCoord32f();
532 else if (protocol == PROTOCOL_DARKPLACES2 || protocol == PROTOCOL_DARKPLACES3 || protocol == PROTOCOL_DARKPLACES4)
533 return MSG_ReadCoord16i();
535 return MSG_ReadCoord32f();
538 void MSG_ReadVector (float *v, protocolversion_t protocol)
540 v[0] = MSG_ReadCoord(protocol);
541 v[1] = MSG_ReadCoord(protocol);
542 v[2] = MSG_ReadCoord(protocol);
545 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
546 float MSG_ReadAngle8i (void)
548 return (signed char) MSG_ReadByte () * (360.0/256.0);
551 float MSG_ReadAngle16i (void)
553 return (signed short)MSG_ReadShort () * (360.0/65536.0);
556 float MSG_ReadAngle32f (void)
558 return MSG_ReadFloat ();
561 float MSG_ReadAngle (protocolversion_t protocol)
563 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)
564 return MSG_ReadAngle8i ();
566 return MSG_ReadAngle16i ();
570 //===========================================================================
572 void SZ_Clear (sizebuf_t *buf)
577 unsigned char *SZ_GetSpace (sizebuf_t *buf, int length)
581 if (buf->cursize + length > buf->maxsize)
583 if (!buf->allowoverflow)
584 Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
586 if (length > buf->maxsize)
587 Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
589 buf->overflowed = true;
590 Con_Print("SZ_GetSpace: overflow\n");
594 data = buf->data + buf->cursize;
595 buf->cursize += length;
600 void SZ_Write (sizebuf_t *buf, const unsigned char *data, int length)
602 memcpy (SZ_GetSpace(buf,length),data,length);
605 // LordHavoc: thanks to Fuh for bringing the pure evil of SZ_Print to my
606 // attention, it has been eradicated from here, its only (former) use in
607 // all of darkplaces.
609 static const char *hexchar = "0123456789ABCDEF";
610 void Com_HexDumpToConsole(const unsigned char *data, int size)
614 char *cur, *flushpointer;
615 const unsigned char *d;
617 flushpointer = text + 512;
618 for (i = 0;i < size;)
625 *cur++ = hexchar[(i >> 12) & 15];
626 *cur++ = hexchar[(i >> 8) & 15];
627 *cur++ = hexchar[(i >> 4) & 15];
628 *cur++ = hexchar[(i >> 0) & 15];
631 for (j = 0;j < 16;j++)
635 *cur++ = hexchar[(d[j] >> 4) & 15];
636 *cur++ = hexchar[(d[j] >> 0) & 15];
647 for (j = 0;j < 16;j++)
651 // color change prefix character has to be treated specially
652 if (d[j] == STRING_COLOR_TAG)
654 *cur++ = STRING_COLOR_TAG;
655 *cur++ = STRING_COLOR_TAG;
657 else if (d[j] >= (unsigned char) ' ')
667 if (cur >= flushpointer || i >= size)
676 void SZ_HexDumpToConsole(const sizebuf_t *buf)
678 Com_HexDumpToConsole(buf->data, buf->cursize);
682 //============================================================================
688 Word wraps a string. The wordWidth function is guaranteed to be called exactly
689 once for each word in the string, so it may be stateful, no idea what that
690 would be good for any more. At the beginning of the string, it will be called
691 for the char 0 to initialize a clean state, and then once with the string " "
692 (a space) so the routine knows how long a space is.
694 In case no single character fits into the given width, the wordWidth function
695 must return the width of exactly one character.
697 Wrapped lines get the isContinuation flag set and are continuationWidth less wide.
699 The sum of the return values of the processLine function will be returned.
702 int COM_Wordwrap(const char *string, size_t length, float continuationWidth, float maxWidth, COM_WordWidthFunc_t wordWidth, void *passthroughCW, COM_LineProcessorFunc processLine, void *passthroughPL)
704 // Logic is as follows:
706 // For each word or whitespace:
707 // Newline found? Output current line, advance to next line. This is not a continuation. Continue.
708 // Space found? Always add it to the current line, no matter if it fits.
709 // Word found? Check if current line + current word fits.
710 // If it fits, append it. Continue.
711 // If it doesn't fit, output current line, advance to next line. Append the word. This is a continuation. Continue.
713 qboolean isContinuation = false;
715 const char *startOfLine = string;
716 const char *cursor = string;
717 const char *end = string + length;
718 float spaceUsedInLine = 0;
719 float spaceUsedForWord;
725 wordWidth(passthroughCW, NULL, &dummy, -1);
727 spaceWidth = wordWidth(passthroughCW, " ", &dummy, -1);
731 char ch = (cursor < end) ? *cursor : 0;
734 case 0: // end of string
735 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
736 isContinuation = false;
738 case '\n': // end of line
739 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
740 isContinuation = false;
742 startOfLine = cursor;
746 spaceUsedInLine += spaceWidth;
750 while(cursor + wordLen < end)
752 switch(cursor[wordLen])
764 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
765 if(wordLen < 1) // cannot happen according to current spec of wordWidth
768 spaceUsedForWord = maxWidth + 1; // too high, forces it in a line of itself
770 if(spaceUsedInLine + spaceUsedForWord <= maxWidth || cursor == startOfLine)
772 // we can simply append it
774 spaceUsedInLine += spaceUsedForWord;
778 // output current line
779 result += processLine(passthroughPL, startOfLine, cursor - startOfLine, spaceUsedInLine, isContinuation);
780 isContinuation = true;
781 startOfLine = cursor;
783 spaceUsedInLine = continuationWidth + spaceUsedForWord;
792 qboolean isContinuation = false;
793 float currentWordSpace = 0;
794 const char *currentWord = 0;
795 float minReserve = 0;
797 float spaceUsedInLine = 0;
798 const char *currentLine = 0;
799 const char *currentLineEnd = 0;
800 float currentLineFinalWhitespace = 0;
804 minReserve = charWidth(passthroughCW, 0);
805 minReserve += charWidth(passthroughCW, ' ');
807 if(maxWidth < continuationWidth + minReserve)
808 maxWidth = continuationWidth + minReserve;
810 charWidth(passthroughCW, 0);
812 for(p = string; p < string + length; ++p)
815 float w = charWidth(passthroughCW, c);
820 currentWordSpace = 0;
826 spaceUsedInLine = isContinuation ? continuationWidth : 0;
832 // 1. I can add the word AND a space - then just append it.
833 if(spaceUsedInLine + currentWordSpace + w <= maxWidth)
835 currentLineEnd = p; // note: space not included here
836 currentLineFinalWhitespace = w;
837 spaceUsedInLine += currentWordSpace + w;
839 // 2. I can just add the word - then append it, output current line and go to next one.
840 else if(spaceUsedInLine + currentWordSpace <= maxWidth)
842 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
844 isContinuation = true;
846 // 3. Otherwise, output current line and go to next one, where I can add the word.
847 else if(continuationWidth + currentWordSpace + w <= maxWidth)
850 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
851 currentLine = currentWord;
852 spaceUsedInLine = continuationWidth + currentWordSpace + w;
854 currentLineFinalWhitespace = w;
855 isContinuation = true;
857 // 4. We can't even do that? Then output both current and next word as new lines.
862 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
863 isContinuation = true;
865 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
867 isContinuation = true;
873 // 1. I can add the word - then do it.
874 if(spaceUsedInLine + currentWordSpace <= maxWidth)
876 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
878 // 2. Otherwise, output current line, next one and make tabula rasa.
883 processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
884 isContinuation = true;
886 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
890 isContinuation = false;
894 currentWordSpace += w;
896 spaceUsedInLine + currentWordSpace > maxWidth // can't join this line...
898 continuationWidth + currentWordSpace > maxWidth // can't join any other line...
901 // this word cannot join ANY line...
902 // so output the current line...
905 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
906 isContinuation = true;
909 // then this word's beginning...
912 // it may not fit, but we know we have to split it into maxWidth - continuationWidth pieces
913 float pieceWidth = maxWidth - continuationWidth;
914 const char *pos = currentWord;
915 currentWordSpace = 0;
917 // reset the char width function to a state where no kerning occurs (start of word)
918 charWidth(passthroughCW, ' ');
921 float w = charWidth(passthroughCW, *pos);
922 if(currentWordSpace + w > pieceWidth) // this piece won't fit any more
924 // print everything until it
925 result += processLine(passthroughPL, currentWord, pos - currentWord, currentWordSpace, true);
928 currentWordSpace = 0;
930 currentWordSpace += w;
933 // now we have a currentWord that fits... set up its next line
934 // currentWordSpace has been set
935 // currentWord has been set
936 spaceUsedInLine = continuationWidth;
937 currentLine = currentWord;
939 isContinuation = true;
943 // we have a guarantee that it will fix (see if clause)
944 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace - w, isContinuation);
946 // and use the rest of this word as new start of a line
947 currentWordSpace = w;
949 spaceUsedInLine = continuationWidth;
952 isContinuation = true;
961 currentWordSpace = 0;
964 if(currentLine) // Same procedure as \n
966 // Can I append the current word?
967 if(spaceUsedInLine + currentWordSpace <= maxWidth)
968 result += processLine(passthroughPL, currentLine, p - currentLine, spaceUsedInLine + currentWordSpace, isContinuation);
973 result += processLine(passthroughPL, currentLine, currentLineEnd - currentLine, spaceUsedInLine - currentLineFinalWhitespace, isContinuation);
974 isContinuation = true;
976 result += processLine(passthroughPL, currentWord, p - currentWord, currentWordSpace, isContinuation);
986 COM_ParseToken_Simple
988 Parse a token out of a string
991 int COM_ParseToken_Simple(const char **datapointer, qboolean returnnewline, qboolean parsebackslash)
995 const char *data = *datapointer;
1002 *datapointer = NULL;
1012 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1017 *datapointer = NULL;
1022 // handle Windows line ending
1023 if (data[0] == '\r' && data[1] == '\n')
1026 if (data[0] == '/' && data[1] == '/')
1029 while (*data && *data != '\n' && *data != '\r')
1033 else if (data[0] == '/' && data[1] == '*')
1037 while (*data && (data[0] != '*' || data[1] != '/'))
1045 else if (*data == '\"')
1048 for (data++;*data && *data != '\"';data++)
1051 if (*data == '\\' && parsebackslash)
1060 if (len < (int)sizeof(com_token) - 1)
1061 com_token[len++] = c;
1066 *datapointer = data;
1069 else if (*data == '\r')
1071 // translate Mac line ending to UNIX
1072 com_token[len++] = '\n';data++;
1074 *datapointer = data;
1077 else if (*data == '\n')
1080 com_token[len++] = *data++;
1082 *datapointer = data;
1088 for (;!ISWHITESPACE(*data);data++)
1089 if (len < (int)sizeof(com_token) - 1)
1090 com_token[len++] = *data;
1092 *datapointer = data;
1099 COM_ParseToken_QuakeC
1101 Parse a token out of a string
1104 int COM_ParseToken_QuakeC(const char **datapointer, qboolean returnnewline)
1108 const char *data = *datapointer;
1115 *datapointer = NULL;
1125 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1130 *datapointer = NULL;
1135 // handle Windows line ending
1136 if (data[0] == '\r' && data[1] == '\n')
1139 if (data[0] == '/' && data[1] == '/')
1142 while (*data && *data != '\n' && *data != '\r')
1146 else if (data[0] == '/' && data[1] == '*')
1150 while (*data && (data[0] != '*' || data[1] != '/'))
1158 else if (*data == '\"' || *data == '\'')
1162 for (data++;*data && *data != quote;data++)
1174 if (len < (int)sizeof(com_token) - 1)
1175 com_token[len++] = c;
1180 *datapointer = data;
1183 else if (*data == '\r')
1185 // translate Mac line ending to UNIX
1186 com_token[len++] = '\n';data++;
1188 *datapointer = data;
1191 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1194 com_token[len++] = *data++;
1196 *datapointer = data;
1202 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1203 if (len < (int)sizeof(com_token) - 1)
1204 com_token[len++] = *data;
1206 *datapointer = data;
1213 COM_ParseToken_VM_Tokenize
1215 Parse a token out of a string
1218 int COM_ParseToken_VM_Tokenize(const char **datapointer, qboolean returnnewline)
1222 const char *data = *datapointer;
1229 *datapointer = NULL;
1239 for (;ISWHITESPACE(*data) && ((*data != '\n' && *data != '\r') || !returnnewline);data++)
1244 *datapointer = NULL;
1249 // handle Windows line ending
1250 if (data[0] == '\r' && data[1] == '\n')
1253 if (data[0] == '/' && data[1] == '/')
1256 while (*data && *data != '\n' && *data != '\r')
1260 else if (data[0] == '/' && data[1] == '*')
1264 while (*data && (data[0] != '*' || data[1] != '/'))
1272 else if (*data == '\"' || *data == '\'')
1276 for (data++;*data && *data != quote;data++)
1288 if (len < (int)sizeof(com_token) - 1)
1289 com_token[len++] = c;
1294 *datapointer = data;
1297 else if (*data == '\r')
1299 // translate Mac line ending to UNIX
1300 com_token[len++] = '\n';data++;
1302 *datapointer = data;
1305 else if (*data == '\n' || *data == '{' || *data == '}' || *data == ')' || *data == '(' || *data == ']' || *data == '[' || *data == ':' || *data == ',' || *data == ';')
1308 com_token[len++] = *data++;
1310 *datapointer = data;
1316 for (;!ISWHITESPACE(*data) && *data != '{' && *data != '}' && *data != ')' && *data != '(' && *data != ']' && *data != '[' && *data != ':' && *data != ',' && *data != ';';data++)
1317 if (len < (int)sizeof(com_token) - 1)
1318 com_token[len++] = *data;
1320 *datapointer = data;
1327 COM_ParseToken_Console
1329 Parse a token out of a string, behaving like the qwcl console
1332 int COM_ParseToken_Console(const char **datapointer)
1335 const char *data = *datapointer;
1342 *datapointer = NULL;
1348 for (;ISWHITESPACE(*data);data++)
1353 *datapointer = NULL;
1358 if (*data == '/' && data[1] == '/')
1361 while (*data && *data != '\n' && *data != '\r')
1365 else if (*data == '\"')
1368 for (data++;*data && *data != '\"';data++)
1370 // allow escaped " and \ case
1371 if (*data == '\\' && (data[1] == '\"' || data[1] == '\\'))
1373 if (len < (int)sizeof(com_token) - 1)
1374 com_token[len++] = *data;
1379 *datapointer = data;
1384 for (;!ISWHITESPACE(*data);data++)
1385 if (len < (int)sizeof(com_token) - 1)
1386 com_token[len++] = *data;
1388 *datapointer = data;
1399 Returns the position (1 to argc-1) in the program's argument list
1400 where the given parameter apears, or 0 if not present
1403 int COM_CheckParm (const char *parm)
1407 for (i=1 ; i<com_argc ; i++)
1410 continue; // NEXTSTEP sometimes clears appkit vars.
1411 if (!strcmp (parm,com_argv[i]))
1418 //===========================================================================
1422 typedef struct gamemode_info_s
1424 const char* prog_name; // not null
1425 const char* cmdline; // not null
1426 const char* gamename; // not null
1427 const char* gamedirname1; // not null
1428 const char* gamedirname2; // null
1429 const char* gamescreenshotname; // not nul
1430 const char* gameuserdirname; // not null
1433 static const gamemode_info_t gamemode_info [GAME_COUNT] =
1434 {// prog_name cmdline gamename basegame modgame screenshotprefix userdir
1437 // COMMANDLINEOPTION: Game: -quake runs the game Quake (default)
1438 { "", "-quake", "DarkPlaces-Quake", "id1", NULL, "dp", "darkplaces" },
1440 // COMMANDLINEOPTION: Game: -hipnotic runs Quake mission pack 1: The Scourge of Armagon
1441 { "hipnotic", "-hipnotic", "Darkplaces-Hipnotic", "id1", "hipnotic", "dp", "darkplaces" },
1443 // COMMANDLINEOPTION: Game: -rogue runs Quake mission pack 2: The Dissolution of Eternity
1444 { "rogue", "-rogue", "Darkplaces-Rogue", "id1", "rogue", "dp", "darkplaces" },
1446 // COMMANDLINEOPTION: Game: -nehahra runs The Seal of Nehahra movie and game
1447 { "nehahra", "-nehahra", "DarkPlaces-Nehahra", "id1", "nehahra", "dp", "darkplaces" },
1449 // COMMANDLINEOPTION: Game: -nexuiz runs the multiplayer game Nexuiz
1450 { "nexuiz", "-nexuiz", "Nexuiz", "data", NULL, "nexuiz", "nexuiz" },
1452 // COMMANDLINEOPTION: Game: -xonotic runs the multiplayer game Xonotic
1453 { "xonotic", "-xonotic", "Xonotic", "data", NULL, "xonotic", "xonotic" },
1455 // COMMANDLINEOPTION: Game: -transfusion runs Transfusion (the recreation of Blood in Quake)
1456 { "transfusion", "-transfusion", "Transfusion", "basetf", NULL, "transfusion", "transfusion" },
1458 // COMMANDLINEOPTION: Game: -goodvsbad2 runs the psychadelic RTS FPS game Good Vs Bad 2
1459 { "gvb2", "-goodvsbad2", "GoodVs.Bad2", "rts", NULL, "gvb2", "gvb2" },
1461 // COMMANDLINEOPTION: Game: -teu runs The Evil Unleashed (this option is obsolete as they are not using darkplaces)
1462 { "teu", "-teu", "TheEvilUnleashed", "baseteu", NULL, "teu", "teu" },
1464 // COMMANDLINEOPTION: Game: -battlemech runs the multiplayer topdown deathmatch game BattleMech
1465 { "battlemech", "-battlemech", "Battlemech", "base", NULL, "battlemech", "battlemech" },
1467 // COMMANDLINEOPTION: Game: -zymotic runs the singleplayer game Zymotic
1468 { "zymotic", "-zymotic", "Zymotic", "basezym", NULL, "zymotic", "zymotic" },
1470 // COMMANDLINEOPTION: Game: -setheral runs the multiplayer game Setheral
1471 { "setheral", "-setheral", "Setheral", "data", NULL, "setheral", "setheral" },
1473 // COMMANDLINEOPTION: Game: -som runs the multiplayer game Son Of Man
1474 { "som", "-som", "Son of Man", "id1", "sonofman", "som", "darkplaces" },
1476 // COMMANDLINEOPTION: Game: -tenebrae runs the graphics test mod known as Tenebrae (some features not implemented)
1477 { "tenebrae", "-tenebrae", "DarkPlaces-Tenebrae", "id1", "tenebrae", "dp", "darkplaces" },
1479 // COMMANDLINEOPTION: Game: -neoteric runs the game Neoteric
1480 { "neoteric", "-neoteric", "Neoteric", "id1", "neobase", "neo", "darkplaces" },
1482 // COMMANDLINEOPTION: Game: -openquartz runs the game OpenQuartz, a standalone GPL replacement of the quake content
1483 { "openquartz", "-openquartz", "OpenQuartz", "id1", NULL, "openquartz", "darkplaces" },
1485 // COMMANDLINEOPTION: Game: -prydon runs the topdown point and click action-RPG Prydon Gate
1486 { "prydon", "-prydon", "PrydonGate", "id1", "prydon", "prydon", "darkplaces" },
1488 // COMMANDLINEOPTION: Game: -dq runs the game Deluxe Quake
1489 { "dq", "-dq", "Deluxe Quake", "basedq", "extradq", "basedq", "dq" },
1491 // COMMANDLINEOPTION: Game: -thehunted runs the game The Hunted
1492 { "thehunted", "-thehunted", "The Hunted", "thdata", NULL, "th", "thehunted" },
1493 // GAME_DEFEATINDETAIL2
1494 // COMMANDLINEOPTION: Game: -did2 runs the game Defeat In Detail 2
1495 { "did2", "-did2", "Defeat In Detail 2", "data", NULL, "did2_", "did2" },
1497 // COMMANDLINEOPTION: Game: -darsana runs the game Darsana
1498 { "darsana", "-darsana", "Darsana", "ddata", NULL, "darsana", "darsana" },
1499 // GAME_CONTAGIONTHEORY
1500 // COMMANDLINEOPTION: Game: -contagiontheory runs the game Contagion Theory
1501 { "contagiontheory", "-contagiontheory", "Contagion Theory", "ctdata", NULL, "ct", "contagiontheory" },
1503 // COMMANDLINEOPTION: Game: -edu2p runs the game Edu2 prototype
1504 { "edu2p", "-edu2p", "EDU2 Prototype", "id1", "edu2", "edu2_p", "edu2prototype" },
1506 // COMMANDLINEOPTION: Game: -prophecy runs the game Prophecy
1507 { "prophecy", "-prophecy", "Prophecy", "data", NULL, "prophecy", "prophecy" },
1508 // GAME_BLOODOMNICIDE
1509 // COMMANDLINEOPTION: Game: -omnicide runs the game Blood Omnicide
1510 { "omnicide", "-omnicide", "Blood Omnicide", "kain", NULL, "omnicide", "omnicide" },
1512 // COMMANDLINEOPTION: Game: -steelstorm runs the game Steel Storm
1513 { "steelstorm", "-steelstorm", "Steel-Storm", "gamedata", NULL, "ss", "steelstorm" },
1515 // COMMANDLINEOPTION: Game: -strapbomb runs the game Strap-on-bomb Car
1516 { "strapbomb", "-strapbomb", "Strap-on-bomb Car", "id1", NULL, "strap", "strapbomb" },
1519 void COM_InitGameType (void)
1521 char name [MAX_OSPATH];
1525 FS_StripExtension (com_argv[0], name, sizeof (name));
1526 COM_ToLowerString (name, name, sizeof (name));
1528 // Check the binary name; default to GAME_NORMAL (0)
1529 gamemode = GAME_NORMAL;
1530 for (i = 1; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
1531 if (strstr (name, gamemode_info[i].prog_name))
1533 gamemode = (gamemode_t)i;
1537 // Look for a command-line option
1538 for (i = 0; i < sizeof (gamemode_info) / sizeof (gamemode_info[0]); i++)
1539 if (COM_CheckParm (gamemode_info[i].cmdline))
1541 gamemode = (gamemode_t)i;
1545 gamename = gamemode_info[gamemode].gamename;
1546 gamedirname1 = gamemode_info[gamemode].gamedirname1;
1547 gamedirname2 = gamemode_info[gamemode].gamedirname2;
1548 gamescreenshotname = gamemode_info[gamemode].gamescreenshotname;
1549 gameuserdirname = gamemode_info[gamemode].gameuserdirname;
1551 if((t = COM_CheckParm("-customgamename")) && t + 1 < com_argc)
1552 gamename = com_argv[t+1];
1553 if((t = COM_CheckParm("-customgamedirname1")) && t + 1 < com_argc)
1554 gamedirname1 = com_argv[t+1];
1555 if((t = COM_CheckParm("-customgamedirname2")) && t + 1 < com_argc)
1556 gamedirname2 = *com_argv[t+1] ? com_argv[t+1] : NULL;
1557 if((t = COM_CheckParm("-customgamescreenshotname")) && t + 1 < com_argc)
1558 gamescreenshotname = com_argv[t+1];
1559 if((t = COM_CheckParm("-customgameuserdirname")) && t + 1 < com_argc)
1560 gameuserdirname = com_argv[t+1];
1569 void COM_Init_Commands (void)
1572 char com_cmdline[MAX_INPUTLINE];
1574 Cvar_RegisterVariable (®istered);
1575 Cvar_RegisterVariable (&cmdline);
1577 // reconstitute the command line for the cmdline externally visible cvar
1579 for (j = 0;(j < MAX_NUM_ARGVS) && (j < com_argc);j++)
1582 if (strstr(com_argv[j], " "))
1584 // arg contains whitespace, store quotes around it
1585 com_cmdline[n++] = '\"';
1586 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1587 com_cmdline[n++] = com_argv[j][i++];
1588 com_cmdline[n++] = '\"';
1592 while ((n < ((int)sizeof(com_cmdline) - 1)) && com_argv[j][i])
1593 com_cmdline[n++] = com_argv[j][i++];
1595 if (n < ((int)sizeof(com_cmdline) - 1))
1596 com_cmdline[n++] = ' ';
1601 Cvar_Set ("cmdline", com_cmdline);
1608 does a varargs printf into a temp buffer, so I don't need to have
1609 varargs versions of all text functions.
1610 FIXME: make this buffer size safe someday
1613 char *va(const char *format, ...)
1616 // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1617 static char string[8][1024], *s;
1618 static int stringindex = 0;
1620 s = string[stringindex];
1621 stringindex = (stringindex + 1) & 7;
1622 va_start (argptr, format);
1623 dpvsnprintf (s, sizeof (string[0]), format,argptr);
1630 //======================================
1632 // snprintf and vsnprintf are NOT portable. Use their DP counterparts instead
1638 # define snprintf _snprintf
1639 # define vsnprintf _vsnprintf
1643 int dpsnprintf (char *buffer, size_t buffersize, const char *format, ...)
1648 va_start (args, format);
1649 result = dpvsnprintf (buffer, buffersize, format, args);
1656 int dpvsnprintf (char *buffer, size_t buffersize, const char *format, va_list args)
1660 #if _MSC_VER >= 1400
1661 result = _vsnprintf_s (buffer, buffersize, _TRUNCATE, format, args);
1663 result = vsnprintf (buffer, buffersize, format, args);
1665 if (result < 0 || (size_t)result >= buffersize)
1667 buffer[buffersize - 1] = '\0';
1675 //======================================
1677 void COM_ToLowerString (const char *in, char *out, size_t size_out)
1682 while (*in && size_out > 1)
1684 if (*in >= 'A' && *in <= 'Z')
1685 *out++ = *in++ + 'a' - 'A';
1693 void COM_ToUpperString (const char *in, char *out, size_t size_out)
1698 while (*in && size_out > 1)
1700 if (*in >= 'a' && *in <= 'z')
1701 *out++ = *in++ + 'A' - 'a';
1709 int COM_StringBeginsWith(const char *s, const char *match)
1711 for (;*s && *match;s++, match++)
1717 int COM_ReadAndTokenizeLine(const char **text, char **argv, int maxargc, char *tokenbuf, int tokenbufsize, const char *commentprefix)
1719 int argc, commentprefixlength;
1723 tokenbufend = tokenbuf + tokenbufsize;
1725 commentprefixlength = 0;
1727 commentprefixlength = (int)strlen(commentprefix);
1728 while (*l && *l != '\n' && *l != '\r')
1730 if (!ISWHITESPACE(*l))
1732 if (commentprefixlength && !strncmp(l, commentprefix, commentprefixlength))
1734 while (*l && *l != '\n' && *l != '\r')
1738 if (argc >= maxargc)
1740 argv[argc++] = tokenbuf;
1744 while (*l && *l != '"')
1746 if (tokenbuf >= tokenbufend)
1755 while (!ISWHITESPACE(*l))
1757 if (tokenbuf >= tokenbufend)
1762 if (tokenbuf >= tokenbufend)
1783 COM_StringLengthNoColors
1785 calculates the visible width of a color coded string.
1787 *valid is filled with TRUE if the string is a valid colored string (that is, if
1788 it does not end with an unfinished color code). If it gets filled with FALSE, a
1789 fix would be adding a STRING_COLOR_TAG at the end of the string.
1791 valid can be set to NULL if the caller doesn't care.
1793 For size_s, specify the maximum number of characters from s to use, or 0 to use
1794 all characters until the zero terminator.
1798 COM_StringLengthNoColors(const char *s, size_t size_s, qboolean *valid)
1800 const char *end = size_s ? (s + size_s) : NULL;
1804 switch((s == end) ? 0 : *s)
1810 case STRING_COLOR_TAG:
1812 switch((s == end) ? 0 : *s)
1814 case STRING_COLOR_RGB_TAG_CHAR:
1815 if (s+1 != end && isxdigit(s[1]) &&
1816 s+2 != end && isxdigit(s[2]) &&
1817 s+3 != end && isxdigit(s[3]) )
1822 ++len; // STRING_COLOR_TAG
1823 ++len; // STRING_COLOR_RGB_TAG_CHAR
1825 case 0: // ends with unfinished color code!
1830 case STRING_COLOR_TAG: // escaped ^
1833 case '0': case '1': case '2': case '3': case '4':
1834 case '5': case '6': case '7': case '8': case '9': // color code
1836 default: // not a color code
1837 ++len; // STRING_COLOR_TAG
1838 ++len; // the character
1853 COM_StringDecolorize
1855 removes color codes from a string.
1857 If escape_carets is true, the resulting string will be safe for printing. If
1858 escape_carets is false, the function will just strip color codes (for logging
1861 If the output buffer size did not suffice for converting, the function returns
1862 FALSE. Generally, if escape_carets is false, the output buffer needs
1863 strlen(str)+1 bytes, and if escape_carets is true, it can need strlen(str)*1.5+2
1864 bytes. In any case, the function makes sure that the resulting string is
1867 For size_in, specify the maximum number of characters from in to use, or 0 to use
1868 all characters until the zero terminator.
1872 COM_StringDecolorize(const char *in, size_t size_in, char *out, size_t size_out, qboolean escape_carets)
1874 #define APPEND(ch) do { if(--size_out) { *out++ = (ch); } else { *out++ = 0; return FALSE; } } while(0)
1875 const char *end = size_in ? (in + size_in) : NULL;
1880 switch((in == end) ? 0 : *in)
1885 case STRING_COLOR_TAG:
1887 switch((in == end) ? 0 : *in)
1889 case STRING_COLOR_RGB_TAG_CHAR:
1890 if (in+1 != end && isxdigit(in[1]) &&
1891 in+2 != end && isxdigit(in[2]) &&
1892 in+3 != end && isxdigit(in[3]) )
1897 APPEND(STRING_COLOR_TAG);
1899 APPEND(STRING_COLOR_TAG);
1900 APPEND(STRING_COLOR_RGB_TAG_CHAR);
1902 case 0: // ends with unfinished color code!
1903 APPEND(STRING_COLOR_TAG);
1904 // finish the code by appending another caret when escaping
1906 APPEND(STRING_COLOR_TAG);
1909 case STRING_COLOR_TAG: // escaped ^
1910 APPEND(STRING_COLOR_TAG);
1911 // append a ^ twice when escaping
1913 APPEND(STRING_COLOR_TAG);
1915 case '0': case '1': case '2': case '3': case '4':
1916 case '5': case '6': case '7': case '8': case '9': // color code
1918 default: // not a color code
1919 APPEND(STRING_COLOR_TAG);
1934 // written by Elric, thanks Elric!
1935 char *SearchInfostring(const char *infostring, const char *key)
1937 static char value [MAX_INPUTLINE];
1938 char crt_key [MAX_INPUTLINE];
1939 size_t value_ind, key_ind;
1942 if (*infostring++ != '\\')
1957 if (c == '\\' || key_ind == sizeof (crt_key) - 1)
1959 crt_key[key_ind] = '\0';
1963 crt_key[key_ind++] = c;
1966 // If it's the key we are looking for, save it in "value"
1967 if (!strcmp(crt_key, key))
1973 if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
1975 value[value_ind] = '\0';
1979 value[value_ind++] = c;
1983 // Else, skip the value
1996 void InfoString_GetValue(const char *buffer, const char *key, char *value, size_t valuelength)
2002 keylength = strlen(key);
2003 if (valuelength < 1 || !value)
2005 Con_Printf("InfoString_GetValue: no room in value\n");
2009 if (strchr(key, '\\'))
2011 Con_Printf("InfoString_GetValue: key name \"%s\" contains \\ which is not possible in an infostring\n", key);
2014 if (strchr(key, '\"'))
2016 Con_Printf("InfoString_SetValue: key name \"%s\" contains \" which is not allowed in an infostring\n", key);
2021 Con_Printf("InfoString_GetValue: can not look up a key with no name\n");
2024 while (buffer[pos] == '\\')
2026 if (!memcmp(buffer + pos+1, key, keylength))
2028 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2030 for (j = 0;buffer[pos+j] && buffer[pos+j] != '\\' && j < (int)valuelength - 1;j++)
2031 value[j] = buffer[pos+j];
2035 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2036 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2038 // if we reach this point the key was not found
2041 void InfoString_SetValue(char *buffer, size_t bufferlength, const char *key, const char *value)
2049 keylength = strlen(key);
2050 if (strchr(key, '\\') || strchr(value, '\\'))
2052 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \\ which is not possible to store in an infostring\n", key, value);
2055 if (strchr(key, '\"') || strchr(value, '\"'))
2057 Con_Printf("InfoString_SetValue: \"%s\" \"%s\" contains \" which is not allowed in an infostring\n", key, value);
2062 Con_Printf("InfoString_SetValue: can not set a key with no name\n");
2065 while (buffer[pos] == '\\')
2067 if (!memcmp(buffer + pos+1, key, keylength))
2069 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2070 for (pos++;buffer[pos] && buffer[pos] != '\\';pos++);
2072 // if we found the key, find the end of it because we will be replacing it
2074 if (buffer[pos] == '\\')
2076 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2077 for (pos2++;buffer[pos2] && buffer[pos2] != '\\';pos2++);
2079 if (bufferlength <= pos + 1 + strlen(key) + 1 + strlen(value) + strlen(buffer + pos2))
2081 Con_Printf("InfoString_SetValue: no room for \"%s\" \"%s\" in infostring\n", key, value);
2084 if (value && value[0])
2086 // set the key/value and append the remaining text
2087 char tempbuffer[4096];
2088 strlcpy(tempbuffer, buffer + pos2, sizeof(tempbuffer));
2089 dpsnprintf(buffer + pos, bufferlength - pos, "\\%s\\%s%s", key, value, tempbuffer);
2093 // just remove the key from the text
2094 strlcpy(buffer + pos, buffer + pos2, bufferlength - pos);
2098 void InfoString_Print(char *buffer)
2105 if (*buffer != '\\')
2107 Con_Printf("InfoString_Print: corrupt string\n");
2110 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2111 if (i < (int)sizeof(key)-1)
2114 if (*buffer != '\\')
2116 Con_Printf("InfoString_Print: corrupt string\n");
2119 for (buffer++, i = 0;*buffer && *buffer != '\\';buffer++)
2120 if (i < (int)sizeof(value)-1)
2121 value[i++] = *buffer;
2123 // empty value is an error case
2124 Con_Printf("%20s %s\n", key, value[0] ? value : "NO VALUE");
2128 //========================================================
2129 // strlcat and strlcpy, from OpenBSD
2132 * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
2134 * Permission to use, copy, modify, and distribute this software for any
2135 * purpose with or without fee is hereby granted, provided that the above
2136 * copyright notice and this permission notice appear in all copies.
2138 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
2139 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
2140 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
2141 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2142 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
2143 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
2144 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
2147 /* $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $ */
2148 /* $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $ */
2151 #ifndef HAVE_STRLCAT
2153 strlcat(char *dst, const char *src, size_t siz)
2155 register char *d = dst;
2156 register const char *s = src;
2157 register size_t n = siz;
2160 /* Find the end of dst and adjust bytes left but don't go past end */
2161 while (n-- != 0 && *d != '\0')
2167 return(dlen + strlen(s));
2168 while (*s != '\0') {
2177 return(dlen + (s - src)); /* count does not include NUL */
2179 #endif // #ifndef HAVE_STRLCAT
2182 #ifndef HAVE_STRLCPY
2184 strlcpy(char *dst, const char *src, size_t siz)
2186 register char *d = dst;
2187 register const char *s = src;
2188 register size_t n = siz;
2190 /* Copy as many bytes as will fit */
2191 if (n != 0 && --n != 0) {
2193 if ((*d++ = *s++) == 0)
2198 /* Not enough room in dst, add NUL and traverse rest of src */
2201 *d = '\0'; /* NUL-terminate dst */
2206 return(s - src - 1); /* count does not include NUL */
2209 #endif // #ifndef HAVE_STRLCPY
2211 void FindFraction(double val, int *num, int *denom, int denomMax)
2216 bestdiff = fabs(val);
2220 for(i = 1; i <= denomMax; ++i)
2222 int inum = (int) floor(0.5 + val * i);
2223 double diff = fabs(val - inum / (double)i);
2233 // decodes an XPM from C syntax
2234 char **XPM_DecodeString(const char *in)
2236 static char *tokens[257];
2237 static char lines[257][512];
2240 // skip until "{" token
2241 while(COM_ParseToken_QuakeC(&in, false) && strcmp(com_token, "{"));
2243 // now, read in succession: string, comma-or-}
2244 while(COM_ParseToken_QuakeC(&in, false))
2246 tokens[line] = lines[line];
2247 strlcpy(lines[line++], com_token, sizeof(lines[0]));
2248 if(!COM_ParseToken_QuakeC(&in, false))
2250 if(!strcmp(com_token, "}"))
2252 if(strcmp(com_token, ","))
2254 if(line >= sizeof(tokens) / sizeof(tokens[0]))