Home | History | Annotate | Download | only in WinQuake
      1 /*
      2 Copyright (C) 1996-1997 Id Software, Inc.
      3 
      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.
      8 
      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.
     12 
     13 See the GNU General Public License for more details.
     14 
     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.
     18 
     19 */
     20 // common.c -- misc functions used in client and server
     21 
     22 #include "quakedef.h"
     23 
     24 #define NUM_SAFE_ARGVS  7
     25 
     26 static const char     *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
     27 static const char     *argvdummy = " ";
     28 
     29 static const char     *safeargvs[NUM_SAFE_ARGVS] =
     30 	{"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"};
     31 
     32 cvar_t	registered = CVAR2("registered","0");
     33 cvar_t  cmdline = CVAR4("cmdline","0", false, true);
     34 
     35 qboolean        com_modified;   // set true if using non-id files
     36 
     37 qboolean		proghack;
     38 
     39 int             static_registered = 1;  // only for startup check, then set
     40 
     41 qboolean		msg_suppress_1 = 0;
     42 
     43 void COM_InitFilesystem (void);
     44 
     45 // if a packfile directory differs from this, it is assumed to be hacked
     46 #define PAK0_COUNT              339
     47 #define PAK0_CRC                32981
     48 
     49 char	com_token[1024];
     50 int		com_argc;
     51 const char	**com_argv;
     52 
     53 #define CMDLINE_LENGTH	256
     54 char	com_cmdline[CMDLINE_LENGTH];
     55 
     56 qboolean		standard_quake = true, rogue, hipnotic;
     57 
     58 // this graphic needs to be in the pak file to use registered features
     59 unsigned short pop[] =
     60 {
     61  0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
     62 ,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000
     63 ,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000
     64 ,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600
     65 ,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563
     66 ,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564
     67 ,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564
     68 ,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563
     69 ,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500
     70 ,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200
     71 ,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000
     72 ,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000
     73 ,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000
     74 ,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000
     75 ,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000
     76 ,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000
     77 };
     78 
     79 /*
     80 
     81 
     82 All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
     83 
     84 The "base directory" is the path to the directory holding the quake.exe and all game directories.  The sys_* files pass this to host_init in quakeparms_t->basedir.  This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory.  The base directory is
     85 only used during filesystem initialization.
     86 
     87 The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to.  This can be overridden with the "-game" command line parameter.  The game directory can never be changed while quake is executing.  This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
     88 
     89 The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines.  If there is a cache directory
     90 specified, when a file is found by the normal search path, it will be mirrored
     91 into the cache directory, then opened there.
     92 
     93 
     94 
     95 FIXME:
     96 The file "parms.txt" will be read out of the game directory and appended to the current command line arguments to allow different games to initialize startup parms differently.  This could be used to add a "-sspeed 22050" for the high quality sound edition.  Because they are added at the end, they will not override an explicit setting on the original command line.
     97 
     98 */
     99 
    100 //============================================================================
    101 
    102 
    103 // ClearLink is used for new headnodes
    104 void ClearLink (link_t *l)
    105 {
    106 	l->prev = l->next = l;
    107 }
    108 
    109 void RemoveLink (link_t *l)
    110 {
    111 	l->next->prev = l->prev;
    112 	l->prev->next = l->next;
    113 }
    114 
    115 void InsertLinkBefore (link_t *l, link_t *before)
    116 {
    117 	l->next = before;
    118 	l->prev = before->prev;
    119 	l->prev->next = l;
    120 	l->next->prev = l;
    121 }
    122 void InsertLinkAfter (link_t *l, link_t *after)
    123 {
    124 	l->next = after->next;
    125 	l->prev = after;
    126 	l->prev->next = l;
    127 	l->next->prev = l;
    128 }
    129 
    130 /*
    131 ============================================================================
    132 
    133 					LIBRARY REPLACEMENT FUNCTIONS
    134 
    135 ============================================================================
    136 */
    137 
    138 void Q_memset (void *dest, int fill, int count)
    139 {
    140 	int             i;
    141 
    142 	if ( (((long)dest | count) & 3) == 0)
    143 	{
    144 		count >>= 2;
    145 		fill = fill | (fill<<8) | (fill<<16) | (fill<<24);
    146 		for (i=0 ; i<count ; i++)
    147 			((int *)dest)[i] = fill;
    148 	}
    149 	else
    150 		for (i=0 ; i<count ; i++)
    151 			((byte *)dest)[i] = fill;
    152 }
    153 
    154 void Q_memcpy (void *dest, const void *src, int count)
    155 {
    156 	int             i;
    157 
    158 	if (( ( (long)dest | (long)src | count) & 3) == 0 )
    159 	{
    160 		count>>=2;
    161 		for (i=0 ; i<count ; i++)
    162 			((int *)dest)[i] = ((int *)src)[i];
    163 	}
    164 	else
    165 		for (i=0 ; i<count ; i++)
    166 			((byte *)dest)[i] = ((byte *)src)[i];
    167 }
    168 
    169 int Q_memcmp (const void *m1, const void *m2, int count)
    170 {
    171 	while(count)
    172 	{
    173 		count--;
    174 		if (((byte *)m1)[count] != ((byte *)m2)[count])
    175 			return -1;
    176 	}
    177 	return 0;
    178 }
    179 
    180 void Q_strcpy (char *dest, const char *src)
    181 {
    182 	while (*src)
    183 	{
    184 		*dest++ = *src++;
    185 	}
    186 	*dest++ = 0;
    187 }
    188 
    189 void Q_strncpy (char *dest, const char *src, int count)
    190 {
    191 	while (*src && count--)
    192 	{
    193 		*dest++ = *src++;
    194 	}
    195 	if (count)
    196 		*dest++ = 0;
    197 }
    198 
    199 int Q_strlen (const char *str)
    200 {
    201 	int             count;
    202 
    203 	count = 0;
    204 	while (str[count])
    205 		count++;
    206 
    207 	return count;
    208 }
    209 
    210 char *Q_strrchr(const char *s, char c)
    211 {
    212     int len = Q_strlen(s);
    213     s += len;
    214     while (len--)
    215 	if (*--s == c) return (char*)  s;
    216     return 0;
    217 }
    218 
    219 void Q_strcat (char *dest, const char *src)
    220 {
    221 	dest += Q_strlen(dest);
    222 	Q_strcpy (dest, src);
    223 }
    224 
    225 int Q_strcmp (const char *s1, const char *s2)
    226 {
    227 	while (1)
    228 	{
    229 		if (*s1 != *s2)
    230 			return -1;              // strings not equal
    231 		if (!*s1)
    232 			return 0;               // strings are equal
    233 		s1++;
    234 		s2++;
    235 	}
    236 
    237 	return -1;
    238 }
    239 
    240 int Q_strncmp (const char *s1, const char *s2, int count)
    241 {
    242 	while (1)
    243 	{
    244 		if (!count--)
    245 			return 0;
    246 		if (*s1 != *s2)
    247 			return -1;              // strings not equal
    248 		if (!*s1)
    249 			return 0;               // strings are equal
    250 		s1++;
    251 		s2++;
    252 	}
    253 
    254 	return -1;
    255 }
    256 
    257 int Q_strncasecmp (const char *s1, const char *s2, int n)
    258 {
    259 	int             c1, c2;
    260 
    261 	while (1)
    262 	{
    263 		c1 = *s1++;
    264 		c2 = *s2++;
    265 
    266 		if (!n--)
    267 			return 0;               // strings are equal until end point
    268 
    269 		if (c1 != c2)
    270 		{
    271 			if (c1 >= 'a' && c1 <= 'z')
    272 				c1 -= ('a' - 'A');
    273 			if (c2 >= 'a' && c2 <= 'z')
    274 				c2 -= ('a' - 'A');
    275 			if (c1 != c2)
    276 				return -1;              // strings not equal
    277 		}
    278 		if (!c1)
    279 			return 0;               // strings are equal
    280 //              s1++;
    281 //              s2++;
    282 	}
    283 
    284 	return -1;
    285 }
    286 
    287 int Q_strcasecmp (const char *s1, const char *s2)
    288 {
    289 	return Q_strncasecmp (s1, s2, 99999);
    290 }
    291 
    292 int Q_atoi (const char *str)
    293 {
    294 	int             val;
    295 	int             sign;
    296 	int             c;
    297 
    298 	if (*str == '-')
    299 	{
    300 		sign = -1;
    301 		str++;
    302 	}
    303 	else
    304 		sign = 1;
    305 
    306 	val = 0;
    307 
    308 //
    309 // check for hex
    310 //
    311 	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
    312 	{
    313 		str += 2;
    314 		while (1)
    315 		{
    316 			c = *str++;
    317 			if (c >= '0' && c <= '9')
    318 				val = (val<<4) + c - '0';
    319 			else if (c >= 'a' && c <= 'f')
    320 				val = (val<<4) + c - 'a' + 10;
    321 			else if (c >= 'A' && c <= 'F')
    322 				val = (val<<4) + c - 'A' + 10;
    323 			else
    324 				return val*sign;
    325 		}
    326 	}
    327 
    328 //
    329 // check for character
    330 //
    331 	if (str[0] == '\'')
    332 	{
    333 		return sign * str[1];
    334 	}
    335 
    336 //
    337 // assume decimal
    338 //
    339 	while (1)
    340 	{
    341 		c = *str++;
    342 		if (c <'0' || c > '9')
    343 			return val*sign;
    344 		val = val*10 + c - '0';
    345 	}
    346 
    347 	return 0;
    348 }
    349 
    350 
    351 float Q_atof (const char *str)
    352 {
    353 	double			val;
    354 	int             sign;
    355 	int             c;
    356 	int             decimal, total;
    357 
    358 	if (*str == '-')
    359 	{
    360 		sign = -1;
    361 		str++;
    362 	}
    363 	else
    364 		sign = 1;
    365 
    366 	val = 0;
    367 
    368 //
    369 // check for hex
    370 //
    371 	if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
    372 	{
    373 		str += 2;
    374 		while (1)
    375 		{
    376 			c = *str++;
    377 			if (c >= '0' && c <= '9')
    378 				val = (val*16) + c - '0';
    379 			else if (c >= 'a' && c <= 'f')
    380 				val = (val*16) + c - 'a' + 10;
    381 			else if (c >= 'A' && c <= 'F')
    382 				val = (val*16) + c - 'A' + 10;
    383 			else
    384 				return val*sign;
    385 		}
    386 	}
    387 
    388 //
    389 // check for character
    390 //
    391 	if (str[0] == '\'')
    392 	{
    393 		return sign * str[1];
    394 	}
    395 
    396 //
    397 // assume decimal
    398 //
    399 	decimal = -1;
    400 	total = 0;
    401 	while (1)
    402 	{
    403 		c = *str++;
    404 		if (c == '.')
    405 		{
    406 			decimal = total;
    407 			continue;
    408 		}
    409 		if (c <'0' || c > '9')
    410 			break;
    411 		val = val*10 + c - '0';
    412 		total++;
    413 	}
    414 
    415 	if (decimal == -1)
    416 		return val*sign;
    417 	while (total > decimal)
    418 	{
    419 		val /= 10;
    420 		total--;
    421 	}
    422 
    423 	return val*sign;
    424 }
    425 
    426 /*
    427 ============================================================================
    428 
    429 					BYTE ORDER FUNCTIONS
    430 
    431 ============================================================================
    432 */
    433 
    434 qboolean        bigendien;
    435 
    436 short   (*BigShort) (short l);
    437 short   (*LittleShort) (short l);
    438 int     (*BigLong) (int l);
    439 int     (*LittleLong) (int l);
    440 float   (*BigFloat) (float l);
    441 float   (*LittleFloat) (float l);
    442 
    443 short   ShortSwap (short l)
    444 {
    445 	byte    b1,b2;
    446 
    447 	b1 = l&255;
    448 	b2 = (l>>8)&255;
    449 
    450 	return (b1<<8) + b2;
    451 }
    452 
    453 short   ShortNoSwap (short l)
    454 {
    455 	return l;
    456 }
    457 
    458 int    LongSwap (int l)
    459 {
    460 	byte    b1,b2,b3,b4;
    461 
    462 	b1 = l&255;
    463 	b2 = (l>>8)&255;
    464 	b3 = (l>>16)&255;
    465 	b4 = (l>>24)&255;
    466 
    467 	return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
    468 }
    469 
    470 int     LongNoSwap (int l)
    471 {
    472 	return l;
    473 }
    474 
    475 float FloatSwap (float f)
    476 {
    477 	union
    478 	{
    479 		float   f;
    480 		byte    b[4];
    481 	} dat1, dat2;
    482 
    483 
    484 	dat1.f = f;
    485 	dat2.b[0] = dat1.b[3];
    486 	dat2.b[1] = dat1.b[2];
    487 	dat2.b[2] = dat1.b[1];
    488 	dat2.b[3] = dat1.b[0];
    489 	return dat2.f;
    490 }
    491 
    492 float FloatNoSwap (float f)
    493 {
    494 	return f;
    495 }
    496 
    497 /*
    498 ==============================================================================
    499 
    500 			MESSAGE IO FUNCTIONS
    501 
    502 Handles byte ordering and avoids alignment errors
    503 ==============================================================================
    504 */
    505 
    506 //
    507 // writing functions
    508 //
    509 
    510 void MSG_WriteChar (sizebuf_t *sb, int c)
    511 {
    512 	byte    *buf;
    513 
    514 #ifdef PARANOID
    515 	if (c < -128 || c > 127)
    516 		Sys_Error ("MSG_WriteChar: range error");
    517 #endif
    518 
    519 	buf = (byte*) SZ_GetSpace (sb, 1);
    520 	buf[0] = c;
    521 }
    522 
    523 void MSG_WriteByte (sizebuf_t *sb, int c)
    524 {
    525 	byte    *buf;
    526 
    527 #ifdef PARANOID
    528 	if (c < 0 || c > 255)
    529 		Sys_Error ("MSG_WriteByte: range error");
    530 #endif
    531 
    532 	buf = (byte*) SZ_GetSpace (sb, 1);
    533 	buf[0] = c;
    534 }
    535 
    536 void MSG_WriteShort (sizebuf_t *sb, int c)
    537 {
    538 	byte    *buf;
    539 
    540 #ifdef PARANOID
    541 	if (c < ((short)0x8000) || c > (short)0x7fff)
    542 		Sys_Error ("MSG_WriteShort: range error");
    543 #endif
    544 
    545 	buf = (byte*) SZ_GetSpace (sb, 2);
    546 	buf[0] = c&0xff;
    547 	buf[1] = c>>8;
    548 }
    549 
    550 void MSG_WriteLong (sizebuf_t *sb, int c)
    551 {
    552 	byte    *buf;
    553 
    554 	buf = (byte*) SZ_GetSpace (sb, 4);
    555 	buf[0] = c&0xff;
    556 	buf[1] = (c>>8)&0xff;
    557 	buf[2] = (c>>16)&0xff;
    558 	buf[3] = c>>24;
    559 }
    560 
    561 void MSG_WriteFloat (sizebuf_t *sb, float f)
    562 {
    563 	union
    564 	{
    565 		float   f;
    566 		int     l;
    567 	} dat;
    568 
    569 
    570 	dat.f = f;
    571 	dat.l = LittleLong (dat.l);
    572 
    573 	SZ_Write (sb, &dat.l, 4);
    574 }
    575 
    576 void MSG_WriteString (sizebuf_t *sb, const char *s)
    577 {
    578 	if (!s)
    579 		SZ_Write (sb, "", 1);
    580 	else
    581 		SZ_Write (sb, s, Q_strlen(s)+1);
    582 }
    583 
    584 void MSG_WriteCoord (sizebuf_t *sb, float f)
    585 {
    586 	MSG_WriteShort (sb, (int)(f*8));
    587 }
    588 
    589 void MSG_WriteAngle (sizebuf_t *sb, float f)
    590 {
    591 	MSG_WriteByte (sb, ((int)f*256/360) & 255);
    592 }
    593 
    594 //
    595 // reading functions
    596 //
    597 int                     msg_readcount;
    598 qboolean        msg_badread;
    599 
    600 void MSG_BeginReading (void)
    601 {
    602 	msg_readcount = 0;
    603 	msg_badread = false;
    604 }
    605 
    606 // returns -1 and sets msg_badread if no more characters are available
    607 int MSG_ReadChar (void)
    608 {
    609 	int     c;
    610 
    611 	if (msg_readcount+1 > net_message.cursize)
    612 	{
    613 		msg_badread = true;
    614 		return -1;
    615 	}
    616 
    617 	c = (signed char)net_message.data[msg_readcount];
    618 	msg_readcount++;
    619 
    620 	return c;
    621 }
    622 
    623 int MSG_ReadByte (void)
    624 {
    625 	int     c;
    626 
    627 	if (msg_readcount+1 > net_message.cursize)
    628 	{
    629 		msg_badread = true;
    630 		return -1;
    631 	}
    632 
    633 	c = (unsigned char)net_message.data[msg_readcount];
    634 	msg_readcount++;
    635 
    636 	return c;
    637 }
    638 
    639 int MSG_ReadShort (void)
    640 {
    641 	int     c;
    642 
    643 	if (msg_readcount+2 > net_message.cursize)
    644 	{
    645 		msg_badread = true;
    646 		return -1;
    647 	}
    648 
    649 	c = (short)(net_message.data[msg_readcount]
    650 	+ (net_message.data[msg_readcount+1]<<8));
    651 
    652 	msg_readcount += 2;
    653 
    654 	return c;
    655 }
    656 
    657 int MSG_ReadLong (void)
    658 {
    659 	int     c;
    660 
    661 	if (msg_readcount+4 > net_message.cursize)
    662 	{
    663 		msg_badread = true;
    664 		return -1;
    665 	}
    666 
    667 	c = net_message.data[msg_readcount]
    668 	+ (net_message.data[msg_readcount+1]<<8)
    669 	+ (net_message.data[msg_readcount+2]<<16)
    670 	+ (net_message.data[msg_readcount+3]<<24);
    671 
    672 	msg_readcount += 4;
    673 
    674 	return c;
    675 }
    676 
    677 float MSG_ReadFloat (void)
    678 {
    679 	union
    680 	{
    681 		byte    b[4];
    682 		float   f;
    683 		int     l;
    684 	} dat;
    685 
    686 	dat.b[0] =      net_message.data[msg_readcount];
    687 	dat.b[1] =      net_message.data[msg_readcount+1];
    688 	dat.b[2] =      net_message.data[msg_readcount+2];
    689 	dat.b[3] =      net_message.data[msg_readcount+3];
    690 	msg_readcount += 4;
    691 
    692 	dat.l = LittleLong (dat.l);
    693 
    694 	return dat.f;
    695 }
    696 
    697 char *MSG_ReadString (void)
    698 {
    699 	static char     string[2048];
    700 	int             l,c;
    701 
    702 	l = 0;
    703 	do
    704 	{
    705 		c = MSG_ReadChar ();
    706 		if (c == -1 || c == 0)
    707 			break;
    708 		string[l] = c;
    709 		l++;
    710 	} while (l < (int) (sizeof(string)-1));
    711 
    712 	string[l] = 0;
    713 
    714 	return string;
    715 }
    716 
    717 float MSG_ReadCoord (void)
    718 {
    719 	return MSG_ReadShort() * (1.0/8);
    720 }
    721 
    722 float MSG_ReadAngle (void)
    723 {
    724 	return MSG_ReadChar() * (360.0/256);
    725 }
    726 
    727 
    728 
    729 //===========================================================================
    730 
    731 void SZ_Alloc (sizebuf_t *buf, int startsize)
    732 {
    733 	if (startsize < 256)
    734 		startsize = 256;
    735 	buf->data = (byte*) Hunk_AllocName (startsize, "sizebuf");
    736 	buf->maxsize = startsize;
    737 	buf->cursize = 0;
    738 }
    739 
    740 
    741 void SZ_Free (sizebuf_t *buf)
    742 {
    743 //      Z_Free (buf->data);
    744 //      buf->data = NULL;
    745 //      buf->maxsize = 0;
    746 	buf->cursize = 0;
    747 }
    748 
    749 void SZ_Clear (sizebuf_t *buf)
    750 {
    751 	buf->cursize = 0;
    752 }
    753 
    754 void *SZ_GetSpace (sizebuf_t *buf, int length)
    755 {
    756 	void    *data;
    757 
    758 	if (buf->cursize + length > buf->maxsize)
    759 	{
    760 		if (!buf->allowoverflow)
    761 			Sys_Error ("SZ_GetSpace: overflow without allowoverflow set");
    762 
    763 		if (length > buf->maxsize)
    764 			Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);
    765 
    766 		buf->overflowed = true;
    767 		Con_Printf ("SZ_GetSpace: overflow");
    768 		SZ_Clear (buf);
    769 	}
    770 
    771 	data = buf->data + buf->cursize;
    772 	buf->cursize += length;
    773 
    774 	return data;
    775 }
    776 
    777 void SZ_Write (sizebuf_t *buf, const void *data, int length)
    778 {
    779 	Q_memcpy (SZ_GetSpace(buf,length),data,length);
    780 }
    781 
    782 void SZ_Print (sizebuf_t *buf, const char *data)
    783 {
    784 	int             len;
    785 
    786 	len = Q_strlen(data)+1;
    787 
    788 // byte * cast to keep VC++ happy
    789 	if (buf->data[buf->cursize-1])
    790 		Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
    791 	else
    792 		Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
    793 }
    794 
    795 
    796 //============================================================================
    797 
    798 
    799 /*
    800 ============
    801 COM_SkipPath
    802 ============
    803 */
    804 const char *COM_SkipPath (const char *pathname)
    805 {
    806 	const char    *last;
    807 
    808 	last = pathname;
    809 	while (*pathname)
    810 	{
    811 		if (*pathname=='/')
    812 			last = pathname+1;
    813 		pathname++;
    814 	}
    815 	return last;
    816 }
    817 
    818 /*
    819 ============
    820 COM_StripExtension
    821 ============
    822 */
    823 void COM_StripExtension (const char *in, char *out)
    824 {
    825 	while (*in && *in != '.')
    826 		*out++ = *in++;
    827 	*out = 0;
    828 }
    829 
    830 /*
    831 ============
    832 COM_FileExtension
    833 ============
    834 */
    835 const char *COM_FileExtension (const char *in)
    836 {
    837 	static char exten[8];
    838 	int             i;
    839 
    840 	while (*in && *in != '.')
    841 		in++;
    842 	if (!*in)
    843 		return "";
    844 	in++;
    845 	for (i=0 ; i<7 && *in ; i++,in++)
    846 		exten[i] = *in;
    847 	exten[i] = 0;
    848 	return exten;
    849 }
    850 
    851 /*
    852 ============
    853 COM_FileBase
    854 ============
    855 */
    856 void COM_FileBase (const char *in, char *out, size_t outSize)
    857 {
    858 	// Get the "base" part of a path, make sure we don't exceed outSize bytes
    859 
    860 	const char* start;
    861 	const char* end;
    862 	size_t len;
    863 
    864 	if(!outSize)
    865 		return;
    866 
    867 	start = strrchr(in, '/');
    868 	if(start)
    869 	{
    870 		start++;
    871 	}
    872 	else
    873 	{
    874 		start = in;
    875 	}
    876 
    877 	// Start now points to the beginning of the filename part of the file.
    878 
    879 	end = strrchr(start, '.');
    880 
    881 	if(!end)
    882 	{
    883 		end = start + strlen(start);
    884 	}
    885 
    886 	// end now points one character beyond the end of the base part of the file.
    887 
    888 	len = end - start;
    889 	if(len > outSize - 1)
    890 		len = outSize - 1;
    891 
    892 	memcpy(out, start, len);
    893 	out[len] = 0;
    894 }
    895 
    896 
    897 /*
    898 ==================
    899 COM_DefaultExtension
    900 ==================
    901 */
    902 void COM_DefaultExtension (char *path, const char *extension)
    903 {
    904 	char    *src;
    905 //
    906 // if path doesn't have a .EXT, append extension
    907 // (extension should include the .)
    908 //
    909 	src = path + strlen(path) - 1;
    910 
    911 	while (*src != '/' && src != path)
    912 	{
    913 		if (*src == '.')
    914 			return;                 // it has an extension
    915 		src--;
    916 	}
    917 
    918 	strcat (path, extension);
    919 }
    920 
    921 
    922 /*
    923 ==============
    924 COM_Parse
    925 
    926 Parse a token out of a string
    927 ==============
    928 */
    929 char *COM_Parse (char *data)
    930 {
    931 	int             c;
    932 	int             len;
    933 
    934 	len = 0;
    935 	com_token[0] = 0;
    936 
    937 	if (!data)
    938 		return NULL;
    939 
    940 // skip whitespace
    941 skipwhite:
    942 	while ( (c = *data) <= ' ')
    943 	{
    944 		if (c == 0)
    945 			return NULL;                    // end of file;
    946 		data++;
    947 	}
    948 
    949 // skip // comments
    950 	if (c=='/' && data[1] == '/')
    951 	{
    952 		while (*data && *data != '\n')
    953 			data++;
    954 		goto skipwhite;
    955 	}
    956 
    957 
    958 // handle quoted strings specially
    959 	if (c == '\"')
    960 	{
    961 		data++;
    962 		while (1)
    963 		{
    964 			c = *data++;
    965 			if (c=='\"' || !c)
    966 			{
    967 				com_token[len] = 0;
    968 				return data;
    969 			}
    970 			com_token[len] = c;
    971 			len++;
    972 		}
    973 	}
    974 
    975 // parse single characters
    976 	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
    977 	{
    978 		com_token[len] = c;
    979 		len++;
    980 		com_token[len] = 0;
    981 		return data+1;
    982 	}
    983 
    984 // parse a regular word
    985 	do
    986 	{
    987 		com_token[len] = c;
    988 		data++;
    989 		len++;
    990 		c = *data;
    991 	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
    992 			break;
    993 	} while (c>32);
    994 
    995 	com_token[len] = 0;
    996 	return data;
    997 }
    998 
    999 
   1000 /*
   1001 ================
   1002 COM_CheckParm
   1003 
   1004 Returns the position (1 to argc-1) in the program's argument list
   1005 where the given parameter apears, or 0 if not present
   1006 ================
   1007 */
   1008 int COM_CheckParm (const char *parm)
   1009 {
   1010 	int             i;
   1011 
   1012 	for (i=1 ; i<com_argc ; i++)
   1013 	{
   1014 		if (!com_argv[i])
   1015 			continue;               // NEXTSTEP sometimes clears appkit vars.
   1016 		if (!Q_strcmp (parm,com_argv[i]))
   1017 			return i;
   1018 	}
   1019 
   1020 	return 0;
   1021 }
   1022 
   1023 /*
   1024 ================
   1025 COM_CheckRegistered
   1026 
   1027 Looks for the pop.txt file and verifies it.
   1028 Sets the "registered" cvar.
   1029 Immediately exits out if an alternate game was attempted to be started without
   1030 being registered.
   1031 ================
   1032 */
   1033 void COM_CheckRegistered (void)
   1034 {
   1035 	int             h;
   1036 	unsigned short  check[128];
   1037 	int                     i;
   1038 
   1039 	COM_OpenFile("gfx/pop.lmp", &h);
   1040 	static_registered = 0;
   1041 
   1042 	if (h == -1)
   1043 	{
   1044 #if WINDED
   1045 	Sys_Error ("This dedicated server requires a full registered copy of Quake");
   1046 #endif
   1047 		Con_Printf ("Playing shareware version.\n");
   1048 		if (com_modified)
   1049 			Sys_Error ("You must have the registered version to use modified games");
   1050 
   1051 #ifdef USE_OPENGLES
   1052 		// For development purposes pretend we're registered. This allows glquake
   1053 		// file caching to work:
   1054 
   1055 		static_registered = 1;
   1056 #endif // USE_OPENGLES
   1057 		return;
   1058 	}
   1059 
   1060 	Sys_FileRead (h, check, sizeof(check));
   1061 	COM_CloseFile (h);
   1062 
   1063 	for (i=0 ; i<128 ; i++)
   1064 		if (pop[i] != (unsigned short)BigShort (check[i]))
   1065 			Sys_Error ("Corrupted data file.");
   1066 
   1067 	Cvar_Set ("cmdline", com_cmdline);
   1068 	Cvar_Set ("registered", "1");
   1069 	static_registered = 1;
   1070 	Con_Printf ("Playing registered version.\n");
   1071 }
   1072 
   1073 
   1074 void COM_Path_f (void);
   1075 
   1076 
   1077 /*
   1078 ================
   1079 COM_InitArgv
   1080 ================
   1081 */
   1082 void COM_InitArgv (int argc, const char **argv)
   1083 {
   1084 	qboolean        safe;
   1085 	int             i, j, n;
   1086 
   1087 // reconstitute the command line for the cmdline externally visible cvar
   1088 	n = 0;
   1089 
   1090 	for (j=0 ; (j<MAX_NUM_ARGVS) && (j< argc) ; j++)
   1091 	{
   1092 		i = 0;
   1093 
   1094 		while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i])
   1095 		{
   1096 			com_cmdline[n++] = argv[j][i++];
   1097 		}
   1098 
   1099 		if (n < (CMDLINE_LENGTH - 1))
   1100 			com_cmdline[n++] = ' ';
   1101 		else
   1102 			break;
   1103 	}
   1104 
   1105 	com_cmdline[n] = 0;
   1106 
   1107 	safe = false;
   1108 
   1109 	for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;
   1110 		 com_argc++)
   1111 	{
   1112 		largv[com_argc] = argv[com_argc];
   1113 		if (!Q_strcmp ("-safe", argv[com_argc]))
   1114 			safe = true;
   1115 	}
   1116 
   1117 	if (safe)
   1118 	{
   1119 	// force all the safe-mode switches. Note that we reserved extra space in
   1120 	// case we need to add these, so we don't need an overflow check
   1121 		for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
   1122 		{
   1123 			largv[com_argc] = safeargvs[i];
   1124 			com_argc++;
   1125 		}
   1126 	}
   1127 
   1128 	largv[com_argc] = argvdummy;
   1129 	com_argv = largv;
   1130 
   1131 	if (COM_CheckParm ("-rogue"))
   1132 	{
   1133 		rogue = true;
   1134 		standard_quake = false;
   1135 	}
   1136 
   1137 	if (COM_CheckParm ("-hipnotic"))
   1138 	{
   1139 		hipnotic = true;
   1140 		standard_quake = false;
   1141 	}
   1142 }
   1143 
   1144 
   1145 /*
   1146 ================
   1147 COM_Init
   1148 ================
   1149 */
   1150 
   1151 typedef union swapTest_ {
   1152     byte b[2];
   1153     short s;
   1154 } swapTest;
   1155 
   1156 void COM_Init (const char *basedir)
   1157 {
   1158 	swapTest swaptest;
   1159 	swaptest.b[0] = 1;
   1160 	swaptest.b[1] = 0;
   1161 
   1162 // set the byte swapping variables in a portable manner
   1163 	if ( swaptest.s == 1)
   1164 	{
   1165 		bigendien = false;
   1166 		BigShort = ShortSwap;
   1167 		LittleShort = ShortNoSwap;
   1168 		BigLong = LongSwap;
   1169 		LittleLong = LongNoSwap;
   1170 		BigFloat = FloatSwap;
   1171 		LittleFloat = FloatNoSwap;
   1172 	}
   1173 	else
   1174 	{
   1175 		bigendien = true;
   1176 		BigShort = ShortNoSwap;
   1177 		LittleShort = ShortSwap;
   1178 		BigLong = LongNoSwap;
   1179 		LittleLong = LongSwap;
   1180 		BigFloat = FloatNoSwap;
   1181 		LittleFloat = FloatSwap;
   1182 	}
   1183 
   1184 	Cvar_RegisterVariable (&registered);
   1185 	Cvar_RegisterVariable (&cmdline);
   1186 	Cmd_AddCommand ("path", COM_Path_f);
   1187 
   1188 	COM_InitFilesystem ();
   1189 	COM_CheckRegistered ();
   1190 }
   1191 
   1192 
   1193 /*
   1194 ============
   1195 va
   1196 
   1197 does a varargs printf into a temp buffer, so I don't need to have
   1198 varargs versions of all text functions.
   1199 FIXME: make this buffer size safe someday
   1200 ============
   1201 */
   1202 char    *va(const char *format, ...)
   1203 {
   1204 	va_list         argptr;
   1205 	static char             string[1024];
   1206 
   1207 	va_start (argptr, format);
   1208 	vsprintf (string, format,argptr);
   1209 	va_end (argptr);
   1210 
   1211 	return string;
   1212 }
   1213 
   1214 
   1215 /// just for debugging
   1216 int     memsearch (const byte *start, int count, int search)
   1217 {
   1218 	int             i;
   1219 
   1220 	for (i=0 ; i<count ; i++)
   1221 		if (start[i] == search)
   1222 			return i;
   1223 	return -1;
   1224 }
   1225 
   1226 /*
   1227 =============================================================================
   1228 
   1229 QUAKE FILESYSTEM
   1230 
   1231 =============================================================================
   1232 */
   1233 
   1234 int     com_filesize;
   1235 
   1236 
   1237 //
   1238 // in memory
   1239 //
   1240 
   1241 typedef struct
   1242 {
   1243 	char    name[MAX_QPATH];
   1244 	int             filepos, filelen;
   1245 } packfile_t;
   1246 
   1247 typedef struct pack_s
   1248 {
   1249 	char    filename[MAX_OSPATH];
   1250 	int             handle;
   1251 	int             numfiles;
   1252 	packfile_t      *files;
   1253 } pack_t;
   1254 
   1255 //
   1256 // on disk
   1257 //
   1258 typedef struct
   1259 {
   1260 	char    name[56];
   1261 	int             filepos, filelen;
   1262 } dpackfile_t;
   1263 
   1264 typedef struct
   1265 {
   1266 	char    id[4];
   1267 	int             dirofs;
   1268 	int             dirlen;
   1269 } dpackheader_t;
   1270 
   1271 #define MAX_FILES_IN_PACK       2048
   1272 
   1273 char    com_cachedir[MAX_OSPATH];
   1274 char    com_gamedir[MAX_OSPATH];
   1275 
   1276 typedef struct searchpath_s
   1277 {
   1278 	char    filename[MAX_OSPATH];
   1279 	pack_t  *pack;          // only one of filename / pack will be used
   1280 	struct searchpath_s *next;
   1281 } searchpath_t;
   1282 
   1283 searchpath_t    *com_searchpaths;
   1284 
   1285 /*
   1286 ============
   1287 COM_Path_f
   1288 
   1289 ============
   1290 */
   1291 void COM_Path_f (void)
   1292 {
   1293 	searchpath_t    *s;
   1294 
   1295 	Con_Printf ("Current search path:\n");
   1296 	for (s=com_searchpaths ; s ; s=s->next)
   1297 	{
   1298 		if (s->pack)
   1299 		{
   1300 			Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
   1301 		}
   1302 		else
   1303 			Con_Printf ("%s\n", s->filename);
   1304 	}
   1305 }
   1306 
   1307 /*
   1308 ============
   1309 COM_WriteFile
   1310 
   1311 The filename will be prefixed by the current game directory
   1312 ============
   1313 */
   1314 void COM_WriteFile (const char *filename, void *data, int len)
   1315 {
   1316 	int             handle;
   1317 	char    name[MAX_OSPATH];
   1318 
   1319 	sprintf (name, "%s/%s", com_gamedir, filename);
   1320 
   1321 	handle = Sys_FileOpenWrite (name);
   1322 	if (handle == -1)
   1323 	{
   1324 		Sys_Printf ("COM_WriteFile: failed on %s\n", name);
   1325 		return;
   1326 	}
   1327 
   1328 	Sys_Printf ("COM_WriteFile: %s\n", name);
   1329 	Sys_FileWrite (handle, data, len);
   1330 	Sys_FileClose (handle);
   1331 }
   1332 
   1333 
   1334 /*
   1335 ============
   1336 COM_CreatePath
   1337 
   1338 Only used for CopyFile
   1339 ============
   1340 */
   1341 void    COM_CreatePath (const char *path)
   1342 {
   1343     char    *ofs;
   1344 
   1345 	for (ofs = (char*) path+1 ; *ofs ; ofs++)
   1346 	{
   1347 		if (*ofs == '/')
   1348 		{       // create the directory
   1349 			*ofs = 0;
   1350 			Sys_mkdir (path);
   1351 			*ofs = '/';
   1352 		}
   1353 	}
   1354 }
   1355 
   1356 
   1357 /*
   1358 ===========
   1359 COM_CopyFile
   1360 
   1361 Copies a file over from the net to the local cache, creating any directories
   1362 needed.  This is for the convenience of developers using ISDN from home.
   1363 ===========
   1364 */
   1365 void COM_CopyFile (const char *netpath, const char *cachepath)
   1366 {
   1367 	int             in, out;
   1368 	int             remaining, count;
   1369 	char    buf[4096];
   1370 
   1371 	remaining = Sys_FileOpenRead (netpath, &in);
   1372 	COM_CreatePath (cachepath);     // create directories up to the cache file
   1373 	out = Sys_FileOpenWrite (cachepath);
   1374 
   1375 	while (remaining)
   1376 	{
   1377 		if (remaining < (int) sizeof(buf))
   1378 			count = remaining;
   1379 		else
   1380 			count = sizeof(buf);
   1381 		Sys_FileRead (in, buf, count);
   1382 		Sys_FileWrite (out, buf, count);
   1383 		remaining -= count;
   1384 	}
   1385 
   1386 	Sys_FileClose (in);
   1387 	Sys_FileClose (out);
   1388 }
   1389 
   1390 /*
   1391 ===========
   1392 COM_FindFile
   1393 
   1394 Finds the file in the search path.
   1395 Sets com_filesize and one of handle or file
   1396 ===========
   1397 */
   1398 int COM_FindFile (const char *filename, int *handle, FILE **file)
   1399 {
   1400 	searchpath_t    *search;
   1401 	char            netpath[MAX_OSPATH];
   1402 	char            cachepath[MAX_OSPATH];
   1403 	pack_t          *pak;
   1404 	int                     i;
   1405 	int                     findtime, cachetime;
   1406 
   1407 	if (file && handle)
   1408 		Sys_Error ("COM_FindFile: both handle and file set");
   1409 	if (!file && !handle)
   1410 		Sys_Error ("COM_FindFile: neither handle or file set");
   1411 
   1412 //
   1413 // search through the path, one element at a time
   1414 //
   1415 	search = com_searchpaths;
   1416 	if (proghack)
   1417 	{	// gross hack to use quake 1 progs with quake 2 maps
   1418 		if (!strcmp(filename, "progs.dat"))
   1419 			search = search->next;
   1420 	}
   1421 
   1422 	for ( ; search ; search = search->next)
   1423 	{
   1424 	// is the element a pak file?
   1425 		if (search->pack)
   1426 		{
   1427 		// look through all the pak file elements
   1428 			pak = search->pack;
   1429 			for (i=0 ; i<pak->numfiles ; i++)
   1430 				if (!strcmp (pak->files[i].name, filename))
   1431 				{       // found it!
   1432 					// Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename);
   1433 					if (handle)
   1434 					{
   1435 						*handle = pak->handle;
   1436 						Sys_FileSeek (pak->handle, pak->files[i].filepos);
   1437 					}
   1438 					else
   1439 					{       // open a new file on the pakfile
   1440 						*file = fopen (pak->filename, "rb");
   1441 						if (*file)
   1442 							fseek (*file, pak->files[i].filepos, SEEK_SET);
   1443 					}
   1444 					com_filesize = pak->files[i].filelen;
   1445 					return com_filesize;
   1446 				}
   1447 		}
   1448 		else
   1449 		{
   1450 	// check a file in the directory tree
   1451 			if (!static_registered)
   1452 			{       // if not a registered version, don't ever go beyond base
   1453 				if ( strchr (filename, '/') || strchr (filename,'\\'))
   1454 					continue;
   1455 			}
   1456 
   1457 			sprintf (netpath, "%s/%s",search->filename, filename);
   1458 
   1459 			findtime = Sys_FileTime (netpath);
   1460 			if (findtime == -1)
   1461 				continue;
   1462 
   1463 		// see if the file needs to be updated in the cache
   1464 			if (!com_cachedir[0])
   1465 				strcpy (cachepath, netpath);
   1466 			else
   1467 			{
   1468 #if defined(_WIN32)
   1469 				if ((strlen(netpath) < 2) || (netpath[1] != ':'))
   1470 					sprintf (cachepath,"%s%s", com_cachedir, netpath);
   1471 				else
   1472 					sprintf (cachepath,"%s%s", com_cachedir, netpath+2);
   1473 #else
   1474 				sprintf (cachepath,"%s%s", com_cachedir, netpath);
   1475 #endif
   1476 
   1477 				cachetime = Sys_FileTime (cachepath);
   1478 
   1479 				if (cachetime < findtime)
   1480 					COM_CopyFile (netpath, cachepath);
   1481 				strcpy (netpath, cachepath);
   1482 			}
   1483 
   1484 			// Sys_Printf ("FindFile: %s\n",netpath);
   1485 			com_filesize = Sys_FileOpenRead (netpath, &i);
   1486 			if (handle)
   1487 				*handle = i;
   1488 			else
   1489 			{
   1490 				Sys_FileClose (i);
   1491 				*file = fopen (netpath, "rb");
   1492 			}
   1493 			return com_filesize;
   1494 		}
   1495 
   1496 	}
   1497 
   1498 	Sys_Printf ("FindFile: can't find %s\n", filename);
   1499 
   1500 	if (handle)
   1501 		*handle = -1;
   1502 	else
   1503 		*file = NULL;
   1504 	com_filesize = -1;
   1505 	return -1;
   1506 }
   1507 
   1508 
   1509 /*
   1510 ===========
   1511 COM_OpenFile
   1512 
   1513 filename never has a leading slash, but may contain directory walks
   1514 returns a handle and a length
   1515 it may actually be inside a pak file
   1516 ===========
   1517 */
   1518 int COM_OpenFile (const char *filename, int *handle)
   1519 {
   1520 	return COM_FindFile (filename, handle, NULL);
   1521 }
   1522 
   1523 /*
   1524 ===========
   1525 COM_FOpenFile
   1526 
   1527 If the requested file is inside a packfile, a new FILE * will be opened
   1528 into the file.
   1529 ===========
   1530 */
   1531 int COM_FOpenFile (const char *filename, FILE **file)
   1532 {
   1533 	return COM_FindFile (filename, NULL, file);
   1534 }
   1535 
   1536 /*
   1537 ============
   1538 COM_CloseFile
   1539 
   1540 If it is a pak file handle, don't really close it
   1541 ============
   1542 */
   1543 void COM_CloseFile (int h)
   1544 {
   1545 	searchpath_t    *s;
   1546 
   1547 	for (s = com_searchpaths ; s ; s=s->next)
   1548 		if (s->pack && s->pack->handle == h)
   1549 			return;
   1550 
   1551 	Sys_FileClose (h);
   1552 }
   1553 
   1554 
   1555 /*
   1556 ============
   1557 COM_LoadFile
   1558 
   1559 Filename are reletive to the quake directory.
   1560 Allways appends a 0 byte.
   1561 ============
   1562 */
   1563 cache_user_t *loadcache;
   1564 byte    *loadbuf;
   1565 int             loadsize;
   1566 byte *COM_LoadFile (const char *path, int usehunk)
   1567 {
   1568 	int             h;
   1569 	byte    *buf;
   1570 	char    base[32];
   1571 	int             len;
   1572 
   1573 	buf = NULL;     // quiet compiler warning
   1574 
   1575 // look for it in the filesystem or pack files
   1576 	len = COM_OpenFile (path, &h);
   1577 	if (h == -1)
   1578 		return NULL;
   1579 
   1580 // extract the filename base name for hunk tag
   1581 	COM_FileBase (path, base, sizeof(base));
   1582 
   1583 	if (usehunk == 1)
   1584 		buf = (byte*) Hunk_AllocName (len+1, base);
   1585 	else if (usehunk == 2)
   1586 		buf = (byte*) Hunk_TempAlloc (len+1);
   1587 	else if (usehunk == 0)
   1588 		buf = (byte*) Z_Malloc (len+1);
   1589 	else if (usehunk == 3)
   1590 		buf = (byte*) Cache_Alloc (loadcache, len+1, base);
   1591 	else if (usehunk == 4)
   1592 	{
   1593 		if (len+1 > loadsize)
   1594 			buf = (byte*) Hunk_TempAlloc (len+1);
   1595 		else
   1596 			buf = loadbuf;
   1597 	}
   1598 	else
   1599 		Sys_Error ("COM_LoadFile: bad usehunk");
   1600 
   1601 	if (!buf)
   1602 		Sys_Error ("COM_LoadFile: not enough space for %s", path);
   1603 
   1604 	((byte *)buf)[len] = 0;
   1605 
   1606 	Draw_BeginDisc ();
   1607 	Sys_FileRead (h, buf, len);
   1608 	COM_CloseFile (h);
   1609 	Draw_EndDisc ();
   1610 
   1611 	return buf;
   1612 }
   1613 
   1614 byte *COM_LoadHunkFile (const char *path)
   1615 {
   1616 	return COM_LoadFile (path, 1);
   1617 }
   1618 
   1619 byte *COM_LoadTempFile (const char *path)
   1620 {
   1621 	return COM_LoadFile (path, 2);
   1622 }
   1623 
   1624 void COM_LoadCacheFile (char *path, struct cache_user_s *cu)
   1625 {
   1626 	loadcache = cu;
   1627 	COM_LoadFile (path, 3);
   1628 }
   1629 
   1630 // uses temp hunk if larger than bufsize
   1631 byte *COM_LoadStackFile (const char *path, void *buffer, int bufsize)
   1632 {
   1633 	byte    *buf;
   1634 
   1635 	loadbuf = (byte *)buffer;
   1636 	loadsize = bufsize;
   1637 	buf = COM_LoadFile (path, 4);
   1638 
   1639 	return buf;
   1640 }
   1641 
   1642 /*
   1643 =================
   1644 COM_LoadPackFile
   1645 
   1646 Takes an explicit (not game tree related) path to a pak file.
   1647 
   1648 Loads the header and directory, adding the files at the beginning
   1649 of the list so they override previous pack files.
   1650 =================
   1651 */
   1652 pack_t *COM_LoadPackFile (const char *packfile)
   1653 {
   1654 	dpackheader_t   header;
   1655 	int                             i;
   1656 	packfile_t              *newfiles;
   1657 	int                             numpackfiles;
   1658 	pack_t                  *pack;
   1659 	int                             packhandle;
   1660 	dpackfile_t             info[MAX_FILES_IN_PACK];
   1661 	unsigned short          crc;
   1662 
   1663 	if (Sys_FileOpenRead (packfile, &packhandle) == -1)
   1664 	{
   1665 //              Con_Printf ("Couldn't open %s\n", packfile);
   1666 		return NULL;
   1667 	}
   1668 	Sys_FileRead (packhandle, (void *)&header, sizeof(header));
   1669 	if (header.id[0] != 'P' || header.id[1] != 'A'
   1670 	|| header.id[2] != 'C' || header.id[3] != 'K')
   1671 		Sys_Error ("%s is not a packfile", packfile);
   1672 	header.dirofs = LittleLong (header.dirofs);
   1673 	header.dirlen = LittleLong (header.dirlen);
   1674 
   1675 	numpackfiles = header.dirlen / sizeof(dpackfile_t);
   1676 
   1677 	if (numpackfiles > MAX_FILES_IN_PACK)
   1678 		Sys_Error ("%s has %i files", packfile, numpackfiles);
   1679 
   1680 	if (numpackfiles != PAK0_COUNT)
   1681 		com_modified = true;    // not the original file
   1682 
   1683 	newfiles = (packfile_t*) Hunk_AllocName (numpackfiles * sizeof(packfile_t), "packfile");
   1684 
   1685 	Sys_FileSeek (packhandle, header.dirofs);
   1686 	Sys_FileRead (packhandle, (void *)info, header.dirlen);
   1687 
   1688 // crc the directory to check for modifications
   1689 	CRC_Init (&crc);
   1690 	for (i=0 ; i<header.dirlen ; i++)
   1691 		CRC_ProcessByte (&crc, ((byte *)info)[i]);
   1692 	if (crc != PAK0_CRC)
   1693 		com_modified = true;
   1694 
   1695 // parse the directory
   1696 	for (i=0 ; i<numpackfiles ; i++)
   1697 	{
   1698 		strcpy (newfiles[i].name, info[i].name);
   1699 		newfiles[i].filepos = LittleLong(info[i].filepos);
   1700 		newfiles[i].filelen = LittleLong(info[i].filelen);
   1701 	}
   1702 
   1703 	pack = (pack_t*) Hunk_Alloc (sizeof (pack_t));
   1704 	strcpy (pack->filename, packfile);
   1705 	pack->handle = packhandle;
   1706 	pack->numfiles = numpackfiles;
   1707 	pack->files = newfiles;
   1708 
   1709 	Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
   1710 	return pack;
   1711 }
   1712 
   1713 
   1714 /*
   1715 ================
   1716 COM_AddGameDirectory
   1717 
   1718 Sets com_gamedir, adds the directory to the head of the path,
   1719 then loads and adds pak1.pak pak2.pak ...
   1720 ================
   1721 */
   1722 void COM_AddGameDirectory (char *dir)
   1723 {
   1724 	int                             i;
   1725 	searchpath_t    *search;
   1726 	pack_t                  *pak;
   1727 	char                    pakfile[MAX_OSPATH];
   1728 
   1729 	strcpy (com_gamedir, dir);
   1730 
   1731 //
   1732 // add the directory to the search path
   1733 //
   1734 	search = (searchpath_t*) Hunk_Alloc (sizeof(searchpath_t));
   1735 	strcpy (search->filename, dir);
   1736 	search->next = com_searchpaths;
   1737 	com_searchpaths = search;
   1738 
   1739 //
   1740 // add any pak files in the format pak0.pak pak1.pak, ...
   1741 //
   1742 	for (i=0 ; ; i++)
   1743 	{
   1744 		sprintf (pakfile, "%s/pak%i.pak", dir, i);
   1745 		pak = COM_LoadPackFile (pakfile);
   1746 		if (!pak)
   1747 			break;
   1748 		search = (searchpath_t*) Hunk_Alloc (sizeof(searchpath_t));
   1749 		search->pack = pak;
   1750 		search->next = com_searchpaths;
   1751 		com_searchpaths = search;
   1752 	}
   1753 
   1754 //
   1755 // add the contents of the parms.txt file to the end of the command line
   1756 //
   1757 
   1758 }
   1759 
   1760 /*
   1761 ================
   1762 COM_InitFilesystem
   1763 ================
   1764 */
   1765 void COM_InitFilesystem (void)
   1766 {
   1767 	int             i, j;
   1768 	char    basedir[MAX_OSPATH];
   1769 	searchpath_t    *search;
   1770 
   1771 //
   1772 // -basedir <path>
   1773 // Overrides the system supplied base directory (under GAMENAME)
   1774 //
   1775 	i = COM_CheckParm ("-basedir");
   1776 	if (i && i < com_argc-1)
   1777 		strcpy (basedir, com_argv[i+1]);
   1778 	else
   1779 		strcpy (basedir, host_parms.basedir);
   1780 
   1781 	j = strlen (basedir);
   1782 
   1783 	if (j > 0)
   1784 	{
   1785 		if ((basedir[j-1] == '\\') || (basedir[j-1] == '/'))
   1786 			basedir[j-1] = 0;
   1787 	}
   1788 
   1789 //
   1790 // -cachedir <path>
   1791 // Overrides the system supplied cache directory (NULL or /qcache)
   1792 // -cachedir - will disable caching.
   1793 //
   1794 	i = COM_CheckParm ("-cachedir");
   1795 	if (i && i < com_argc-1)
   1796 	{
   1797 		if (com_argv[i+1][0] == '-')
   1798 			com_cachedir[0] = 0;
   1799 		else
   1800 			strcpy (com_cachedir, com_argv[i+1]);
   1801 	}
   1802 	else if (host_parms.cachedir)
   1803 		strcpy (com_cachedir, host_parms.cachedir);
   1804 	else
   1805 		com_cachedir[0] = 0;
   1806 
   1807 //
   1808 // start up with GAMENAME by default (id1)
   1809 //
   1810 	COM_AddGameDirectory (va("%s/" GAMENAME, basedir) );
   1811 
   1812 	if (COM_CheckParm ("-rogue"))
   1813 		COM_AddGameDirectory (va("%s/rogue", basedir) );
   1814 	if (COM_CheckParm ("-hipnotic"))
   1815 		COM_AddGameDirectory (va("%s/hipnotic", basedir) );
   1816 
   1817 //
   1818 // -game <gamedir>
   1819 // Adds basedir/gamedir as an override game
   1820 //
   1821 	i = COM_CheckParm ("-game");
   1822 	if (i && i < com_argc-1)
   1823 	{
   1824 		com_modified = true;
   1825 		COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1]));
   1826 	}
   1827 
   1828 //
   1829 // -path <dir or packfile> [<dir or packfile>] ...
   1830 // Fully specifies the exact serach path, overriding the generated one
   1831 //
   1832 	i = COM_CheckParm ("-path");
   1833 	if (i)
   1834 	{
   1835 		com_modified = true;
   1836 		com_searchpaths = NULL;
   1837 		while (++i < com_argc)
   1838 		{
   1839 			if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
   1840 				break;
   1841 
   1842 			search = (searchpath_t*) Hunk_Alloc (sizeof(searchpath_t));
   1843 			if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
   1844 			{
   1845 				search->pack = COM_LoadPackFile (com_argv[i]);
   1846 				if (!search->pack)
   1847 					Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
   1848 			}
   1849 			else
   1850 				strcpy (search->filename, com_argv[i]);
   1851 			search->next = com_searchpaths;
   1852 			com_searchpaths = search;
   1853 		}
   1854 	}
   1855 
   1856 	if (COM_CheckParm ("-proghack"))
   1857 		proghack = true;
   1858 }
   1859 
   1860 
   1861