• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
ClearLink(link_t * l)104 void ClearLink (link_t *l)
105 {
106 	l->prev = l->next = l;
107 }
108 
RemoveLink(link_t * l)109 void RemoveLink (link_t *l)
110 {
111 	l->next->prev = l->prev;
112 	l->prev->next = l->next;
113 }
114 
InsertLinkBefore(link_t * l,link_t * before)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 }
InsertLinkAfter(link_t * l,link_t * after)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 
Q_memset(void * dest,int fill,int count)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 
Q_memcpy(void * dest,const void * src,int count)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 
Q_memcmp(const void * m1,const void * m2,int count)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 
Q_strcpy(char * dest,const char * src)180 void Q_strcpy (char *dest, const char *src)
181 {
182 	while (*src)
183 	{
184 		*dest++ = *src++;
185 	}
186 	*dest++ = 0;
187 }
188 
Q_strncpy(char * dest,const char * src,int count)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 
Q_strlen(const char * str)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 
Q_strrchr(const char * s,char c)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 
Q_strcat(char * dest,const char * src)219 void Q_strcat (char *dest, const char *src)
220 {
221 	dest += Q_strlen(dest);
222 	Q_strcpy (dest, src);
223 }
224 
Q_strcmp(const char * s1,const char * s2)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 
Q_strncmp(const char * s1,const char * s2,int count)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 
Q_strncasecmp(const char * s1,const char * s2,int n)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 
Q_strcasecmp(const char * s1,const char * s2)287 int Q_strcasecmp (const char *s1, const char *s2)
288 {
289 	return Q_strncasecmp (s1, s2, 99999);
290 }
291 
Q_atoi(const char * str)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 
Q_atof(const char * str)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 
ShortSwap(short l)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 
ShortNoSwap(short l)453 short   ShortNoSwap (short l)
454 {
455 	return l;
456 }
457 
LongSwap(int l)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 
LongNoSwap(int l)470 int     LongNoSwap (int l)
471 {
472 	return l;
473 }
474 
FloatSwap(float f)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 
FloatNoSwap(float f)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 
MSG_WriteChar(sizebuf_t * sb,int c)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 
MSG_WriteByte(sizebuf_t * sb,int c)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 
MSG_WriteShort(sizebuf_t * sb,int c)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 
MSG_WriteLong(sizebuf_t * sb,int c)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 
MSG_WriteFloat(sizebuf_t * sb,float f)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 
MSG_WriteString(sizebuf_t * sb,const char * s)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 
MSG_WriteCoord(sizebuf_t * sb,float f)584 void MSG_WriteCoord (sizebuf_t *sb, float f)
585 {
586 	MSG_WriteShort (sb, (int)(f*8));
587 }
588 
MSG_WriteAngle(sizebuf_t * sb,float f)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 
MSG_BeginReading(void)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
MSG_ReadChar(void)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 
MSG_ReadByte(void)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 
MSG_ReadShort(void)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 
MSG_ReadLong(void)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 
MSG_ReadFloat(void)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 
MSG_ReadString(void)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 
MSG_ReadCoord(void)717 float MSG_ReadCoord (void)
718 {
719 	return MSG_ReadShort() * (1.0/8);
720 }
721 
MSG_ReadAngle(void)722 float MSG_ReadAngle (void)
723 {
724 	return MSG_ReadChar() * (360.0/256);
725 }
726 
727 
728 
729 //===========================================================================
730 
SZ_Alloc(sizebuf_t * buf,int startsize)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 
SZ_Free(sizebuf_t * buf)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 
SZ_Clear(sizebuf_t * buf)749 void SZ_Clear (sizebuf_t *buf)
750 {
751 	buf->cursize = 0;
752 }
753 
SZ_GetSpace(sizebuf_t * buf,int length)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 
SZ_Write(sizebuf_t * buf,const void * data,int length)777 void SZ_Write (sizebuf_t *buf, const void *data, int length)
778 {
779 	Q_memcpy (SZ_GetSpace(buf,length),data,length);
780 }
781 
SZ_Print(sizebuf_t * buf,const char * data)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 */
COM_SkipPath(const char * pathname)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 */
COM_StripExtension(const char * in,char * out)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 */
COM_FileExtension(const char * in)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 */
COM_FileBase(const char * in,char * out,size_t outSize)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 */
COM_DefaultExtension(char * path,const char * extension)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 */
COM_Parse(char * data)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 */
COM_CheckParm(const char * parm)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 */
COM_CheckRegistered(void)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 */
COM_InitArgv(int argc,const char ** argv)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 
COM_Init(const char * basedir)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 */
va(const char * format,...)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
memsearch(const byte * start,int count,int search)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 */
COM_Path_f(void)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 */
COM_WriteFile(const char * filename,void * data,int len)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 */
COM_CreatePath(const char * path)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 */
COM_CopyFile(const char * netpath,const char * cachepath)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 */
COM_FindFile(const char * filename,int * handle,FILE ** file)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 */
COM_OpenFile(const char * filename,int * handle)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 */
COM_FOpenFile(const char * filename,FILE ** file)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 */
COM_CloseFile(int h)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;
COM_LoadFile(const char * path,int usehunk)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 
COM_LoadHunkFile(const char * path)1614 byte *COM_LoadHunkFile (const char *path)
1615 {
1616 	return COM_LoadFile (path, 1);
1617 }
1618 
COM_LoadTempFile(const char * path)1619 byte *COM_LoadTempFile (const char *path)
1620 {
1621 	return COM_LoadFile (path, 2);
1622 }
1623 
COM_LoadCacheFile(char * path,struct cache_user_s * cu)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
COM_LoadStackFile(const char * path,void * buffer,int 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 */
COM_LoadPackFile(const char * packfile)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 */
COM_AddGameDirectory(char * dir)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 */
COM_InitFilesystem(void)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