Subversion Repositories Kolibri OS

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 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 char     *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
27
static char     *argvdummy = " ";
28
 
29
static char     *safeargvs[NUM_SAFE_ARGVS] =
30
	{"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"};
31
 
32
cvar_t  registered = {"registered","0"};
33
cvar_t  cmdline = {"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
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
147
			((int *)dest)[i] = fill;
148
	}
149
	else
150
		for (i=0 ; i
151
			((byte *)dest)[i] = fill;
152
}
153
 
154
void Q_memcpy (void *dest, 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
162
			((int *)dest)[i] = ((int *)src)[i];
163
	}
164
	else
165
		for (i=0 ; i
166
			((byte *)dest)[i] = ((byte *)src)[i];
167
}
168
 
169
int Q_memcmp (void *m1, 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, char *src)
181
{
182
	while (*src)
183
	{
184
		*dest++ = *src++;
185
	}
186
	*dest++ = 0;
187
}
188
 
189
void Q_strncpy (char *dest, 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 (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(char *s, char c)
211
{
212
    int len = Q_strlen(s);
213
    s += len;
214
    while (len--)
215
	if (*--s == c) return s;
216
    return 0;
217
}
218
 
219
void Q_strcat (char *dest, char *src)
220
{
221
	dest += Q_strlen(dest);
222
	Q_strcpy (dest, src);
223
}
224
 
225
int Q_strcmp (char *s1, 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 (char *s1, 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 (char *s1, 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 (char *s1, char *s2)
288
{
289
	return Q_strncasecmp (s1, s2, 99999);
290
}
291
 
292
int Q_atoi (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 (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
#ifdef SDL
435
#include "SDL_byteorder.h"
436
#endif
437
 
438
qboolean        bigendien;
439
 
440
short   (*BigShort) (short l);
441
short   (*LittleShort) (short l);
442
int     (*BigLong) (int l);
443
int     (*LittleLong) (int l);
444
float   (*BigFloat) (float l);
445
float   (*LittleFloat) (float l);
446
 
447
short   ShortSwap (short l)
448
{
449
	byte    b1,b2;
450
 
451
	b1 = l&255;
452
	b2 = (l>>8)&255;
453
 
454
	return (b1<<8) + b2;
455
}
456
 
457
short   ShortNoSwap (short l)
458
{
459
	return l;
460
}
461
 
462
int    LongSwap (int l)
463
{
464
	byte    b1,b2,b3,b4;
465
 
466
	b1 = l&255;
467
	b2 = (l>>8)&255;
468
	b3 = (l>>16)&255;
469
	b4 = (l>>24)&255;
470
 
471
	return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
472
}
473
 
474
int     LongNoSwap (int l)
475
{
476
	return l;
477
}
478
 
479
float FloatSwap (float f)
480
{
481
	union
482
	{
483
		float   f;
484
		byte    b[4];
485
	} dat1, dat2;
486
 
487
 
488
	dat1.f = f;
489
	dat2.b[0] = dat1.b[3];
490
	dat2.b[1] = dat1.b[2];
491
	dat2.b[2] = dat1.b[1];
492
	dat2.b[3] = dat1.b[0];
493
	return dat2.f;
494
}
495
 
496
float FloatNoSwap (float f)
497
{
498
	return f;
499
}
500
 
501
/*
502
==============================================================================
503
 
504
			MESSAGE IO FUNCTIONS
505
 
506
Handles byte ordering and avoids alignment errors
507
==============================================================================
508
*/
509
 
510
//
511
// writing functions
512
//
513
 
514
void MSG_WriteChar (sizebuf_t *sb, int c)
515
{
516
	byte    *buf;
517
 
518
#ifdef PARANOID
519
	if (c < -128 || c > 127)
520
		Sys_Error ("MSG_WriteChar: range error");
521
#endif
522
 
523
	buf = SZ_GetSpace (sb, 1);
524
	buf[0] = c;
525
}
526
 
527
void MSG_WriteByte (sizebuf_t *sb, int c)
528
{
529
	byte    *buf;
530
 
531
#ifdef PARANOID
532
	if (c < 0 || c > 255)
533
		Sys_Error ("MSG_WriteByte: range error");
534
#endif
535
 
536
	buf = SZ_GetSpace (sb, 1);
537
	buf[0] = c;
538
}
539
 
540
void MSG_WriteShort (sizebuf_t *sb, int c)
541
{
542
	byte    *buf;
543
 
544
#ifdef PARANOID
545
	if (c < ((short)0x8000) || c > (short)0x7fff)
546
		Sys_Error ("MSG_WriteShort: range error");
547
#endif
548
 
549
	buf = SZ_GetSpace (sb, 2);
550
	buf[0] = c&0xff;
551
	buf[1] = c>>8;
552
}
553
 
554
void MSG_WriteLong (sizebuf_t *sb, int c)
555
{
556
	byte    *buf;
557
 
558
	buf = SZ_GetSpace (sb, 4);
559
	buf[0] = c&0xff;
560
	buf[1] = (c>>8)&0xff;
561
	buf[2] = (c>>16)&0xff;
562
	buf[3] = c>>24;
563
}
564
 
565
void MSG_WriteFloat (sizebuf_t *sb, float f)
566
{
567
	union
568
	{
569
		float   f;
570
		int     l;
571
	} dat;
572
 
573
 
574
	dat.f = f;
575
	dat.l = LittleLong (dat.l);
576
 
577
	SZ_Write (sb, &dat.l, 4);
578
}
579
 
580
void MSG_WriteString (sizebuf_t *sb, char *s)
581
{
582
	if (!s)
583
		SZ_Write (sb, "", 1);
584
	else
585
		SZ_Write (sb, s, Q_strlen(s)+1);
586
}
587
 
588
void MSG_WriteCoord (sizebuf_t *sb, float f)
589
{
590
	MSG_WriteShort (sb, (int)(f*8));
591
}
592
 
593
void MSG_WriteAngle (sizebuf_t *sb, float f)
594
{
595
	MSG_WriteByte (sb, ((int)f*256/360) & 255);
596
}
597
 
598
//
599
// reading functions
600
//
601
int                     msg_readcount;
602
qboolean        msg_badread;
603
 
604
void MSG_BeginReading (void)
605
{
606
	msg_readcount = 0;
607
	msg_badread = false;
608
}
609
 
610
// returns -1 and sets msg_badread if no more characters are available
611
int MSG_ReadChar (void)
612
{
613
	int     c;
614
 
615
	if (msg_readcount+1 > net_message.cursize)
616
	{
617
		msg_badread = true;
618
		return -1;
619
	}
620
 
621
	c = (signed char)net_message.data[msg_readcount];
622
	msg_readcount++;
623
 
624
	return c;
625
}
626
 
627
int MSG_ReadByte (void)
628
{
629
	int     c;
630
 
631
	if (msg_readcount+1 > net_message.cursize)
632
	{
633
		msg_badread = true;
634
		return -1;
635
	}
636
 
637
	c = (unsigned char)net_message.data[msg_readcount];
638
	msg_readcount++;
639
 
640
	return c;
641
}
642
 
643
int MSG_ReadShort (void)
644
{
645
	int     c;
646
 
647
	if (msg_readcount+2 > net_message.cursize)
648
	{
649
		msg_badread = true;
650
		return -1;
651
	}
652
 
653
	c = (short)(net_message.data[msg_readcount]
654
	+ (net_message.data[msg_readcount+1]<<8));
655
 
656
	msg_readcount += 2;
657
 
658
	return c;
659
}
660
 
661
int MSG_ReadLong (void)
662
{
663
	int     c;
664
 
665
	if (msg_readcount+4 > net_message.cursize)
666
	{
667
		msg_badread = true;
668
		return -1;
669
	}
670
 
671
	c = net_message.data[msg_readcount]
672
	+ (net_message.data[msg_readcount+1]<<8)
673
	+ (net_message.data[msg_readcount+2]<<16)
674
	+ (net_message.data[msg_readcount+3]<<24);
675
 
676
	msg_readcount += 4;
677
 
678
	return c;
679
}
680
 
681
float MSG_ReadFloat (void)
682
{
683
	union
684
	{
685
		byte    b[4];
686
		float   f;
687
		int     l;
688
	} dat;
689
 
690
	dat.b[0] =      net_message.data[msg_readcount];
691
	dat.b[1] =      net_message.data[msg_readcount+1];
692
	dat.b[2] =      net_message.data[msg_readcount+2];
693
	dat.b[3] =      net_message.data[msg_readcount+3];
694
	msg_readcount += 4;
695
 
696
	dat.l = LittleLong (dat.l);
697
 
698
	return dat.f;
699
}
700
 
701
char *MSG_ReadString (void)
702
{
703
	static char     string[2048];
704
	int             l,c;
705
 
706
	l = 0;
707
	do
708
	{
709
		c = MSG_ReadChar ();
710
		if (c == -1 || c == 0)
711
			break;
712
		string[l] = c;
713
		l++;
714
	} while (l < sizeof(string)-1);
715
 
716
	string[l] = 0;
717
 
718
	return string;
719
}
720
 
721
float MSG_ReadCoord (void)
722
{
723
	return MSG_ReadShort() * (1.0/8);
724
}
725
 
726
float MSG_ReadAngle (void)
727
{
728
	return MSG_ReadChar() * (360.0/256);
729
}
730
 
731
 
732
 
733
//===========================================================================
734
 
735
void SZ_Alloc (sizebuf_t *buf, int startsize)
736
{
737
	if (startsize < 256)
738
		startsize = 256;
739
	buf->data = Hunk_AllocName (startsize, "sizebuf");
740
	buf->maxsize = startsize;
741
	buf->cursize = 0;
742
}
743
 
744
 
745
void SZ_Free (sizebuf_t *buf)
746
{
747
//      Z_Free (buf->data);
748
//      buf->data = NULL;
749
//      buf->maxsize = 0;
750
	buf->cursize = 0;
751
}
752
 
753
void SZ_Clear (sizebuf_t *buf)
754
{
755
	buf->cursize = 0;
756
}
757
 
758
void *SZ_GetSpace (sizebuf_t *buf, int length)
759
{
760
	void    *data;
761
 
762
	if (buf->cursize + length > buf->maxsize)
763
	{
764
		if (!buf->allowoverflow)
765
			Sys_Error ("SZ_GetSpace: overflow without allowoverflow set");
766
 
767
		if (length > buf->maxsize)
768
			Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);
769
 
770
		buf->overflowed = true;
771
		Con_Printf ("SZ_GetSpace: overflow");
772
		SZ_Clear (buf);
773
	}
774
 
775
	data = buf->data + buf->cursize;
776
	buf->cursize += length;
777
 
778
	return data;
779
}
780
 
781
void SZ_Write (sizebuf_t *buf, void *data, int length)
782
{
783
	Q_memcpy (SZ_GetSpace(buf,length),data,length);
784
}
785
 
786
void SZ_Print (sizebuf_t *buf, char *data)
787
{
788
	int             len;
789
 
790
	len = Q_strlen(data)+1;
791
 
792
// byte * cast to keep VC++ happy
793
	if (buf->data[buf->cursize-1])
794
		Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
795
	else
796
		Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
797
}
798
 
799
 
800
//============================================================================
801
 
802
 
803
/*
804
============
805
COM_SkipPath
806
============
807
*/
808
char *COM_SkipPath (char *pathname)
809
{
810
	char    *last;
811
 
812
	last = pathname;
813
	while (*pathname)
814
	{
815
		if (*pathname=='/')
816
			last = pathname+1;
817
		pathname++;
818
	}
819
	return last;
820
}
821
 
822
/*
823
============
824
COM_StripExtension
825
============
826
*/
827
void COM_StripExtension (char *in, char *out)
828
{
829
	while (*in && *in != '.')
830
		*out++ = *in++;
831
	*out = 0;
832
}
833
 
834
/*
835
============
836
COM_FileExtension
837
============
838
*/
839
char *COM_FileExtension (char *in)
840
{
841
	static char exten[8];
842
	int             i;
843
 
844
	while (*in && *in != '.')
845
		in++;
846
	if (!*in)
847
		return "";
848
	in++;
849
	for (i=0 ; i<7 && *in ; i++,in++)
850
		exten[i] = *in;
851
	exten[i] = 0;
852
	return exten;
853
}
854
 
855
/*
856
============
857
COM_FileBase
858
============
859
*/
860
void COM_FileBase (char *in, char *out)
861
{
862
	char *s, *s2;
863
 
864
	s = in + strlen(in) - 1;
865
 
866
	while (s != in && *s != '.')
867
		s--;
868
 
869
	for (s2 = s ; *s2 && *s2 != '/' ; s2--)
870
	;
871
 
872
	if (s-s2 < 2)
873
		strcpy (out,"?model?");
874
	else
875
	{
876
		s--;
877
		strncpy (out,s2+1, s-s2);
878
		out[s-s2] = 0;
879
	}
880
}
881
 
882
 
883
/*
884
==================
885
COM_DefaultExtension
886
==================
887
*/
888
void COM_DefaultExtension (char *path, char *extension)
889
{
890
	char    *src;
891
//
892
// if path doesn't have a .EXT, append extension
893
// (extension should include the .)
894
//
895
	src = path + strlen(path) - 1;
896
 
897
	while (*src != '/' && src != path)
898
	{
899
		if (*src == '.')
900
			return;                 // it has an extension
901
		src--;
902
	}
903
 
904
	strcat (path, extension);
905
}
906
 
907
 
908
/*
909
==============
910
COM_Parse
911
 
912
Parse a token out of a string
913
==============
914
*/
915
char *COM_Parse (char *data)
916
{
917
	int             c;
918
	int             len;
919
 
920
	len = 0;
921
	com_token[0] = 0;
922
 
923
	if (!data)
924
		return NULL;
925
 
926
// skip whitespace
927
skipwhite:
928
	while ( (c = *data) <= ' ')
929
	{
930
		if (c == 0)
931
			return NULL;                    // end of file;
932
		data++;
933
	}
934
 
935
// skip // comments
936
	if (c=='/' && data[1] == '/')
937
	{
938
		while (*data && *data != '\n')
939
			data++;
940
		goto skipwhite;
941
	}
942
 
943
 
944
// handle quoted strings specially
945
	if (c == '\"')
946
	{
947
		data++;
948
		while (1)
949
		{
950
			c = *data++;
951
			if (c=='\"' || !c)
952
			{
953
				com_token[len] = 0;
954
				return data;
955
			}
956
			com_token[len] = c;
957
			len++;
958
		}
959
	}
960
 
961
// parse single characters
962
	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
963
	{
964
		com_token[len] = c;
965
		len++;
966
		com_token[len] = 0;
967
		return data+1;
968
	}
969
 
970
// parse a regular word
971
	do
972
	{
973
		com_token[len] = c;
974
		data++;
975
		len++;
976
		c = *data;
977
	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
978
			break;
979
	} while (c>32);
980
 
981
	com_token[len] = 0;
982
	return data;
983
}
984
 
985
 
986
/*
987
================
988
COM_CheckParm
989
 
990
Returns the position (1 to argc-1) in the program's argument list
991
where the given parameter apears, or 0 if not present
992
================
993
*/
994
int COM_CheckParm (char *parm)
995
{
996
	int             i;
997
 
998
	for (i=1 ; i
999
	{
1000
		if (!com_argv[i])
1001
			continue;               // NEXTSTEP sometimes clears appkit vars.
1002
		if (!Q_strcmp (parm,com_argv[i]))
1003
			return i;
1004
	}
1005
 
1006
	return 0;
1007
}
1008
 
1009
/*
1010
================
1011
COM_CheckRegistered
1012
 
1013
Looks for the pop.txt file and verifies it.
1014
Sets the "registered" cvar.
1015
Immediately exits out if an alternate game was attempted to be started without
1016
being registered.
1017
================
1018
*/
1019
void COM_CheckRegistered (void)
1020
{
1021
	int             h;
1022
	unsigned short  check[128];
1023
	int                     i;
1024
 
1025
	COM_OpenFile("gfx/pop.lmp", &h);
1026
	static_registered = 0;
1027
 
1028
	if (h == -1)
1029
	{
1030
#if WINDED
1031
	Sys_Error ("This dedicated server requires a full registered copy of Quake");
1032
#endif
1033
		Con_Printf ("Playing shareware version.\n");
1034
		if (com_modified)
1035
			Sys_Error ("You must have the registered version to use modified games");
1036
		return;
1037
	}
1038
 
1039
	Sys_FileRead (h, check, sizeof(check));
1040
	COM_CloseFile (h);
1041
 
1042
	for (i=0 ; i<128 ; i++)
1043
		if (pop[i] != (unsigned short)BigShort (check[i]))
1044
			Sys_Error ("Corrupted data file.");
1045
 
1046
	Cvar_Set ("cmdline", com_cmdline);
1047
	Cvar_Set ("registered", "1");
1048
	static_registered = 1;
1049
	Con_Printf ("Playing registered version.\n");
1050
}
1051
 
1052
 
1053
void COM_Path_f (void);
1054
 
1055
 
1056
/*
1057
================
1058
COM_InitArgv
1059
================
1060
*/
1061
void COM_InitArgv (int argc, char **argv)
1062
{
1063
	qboolean        safe;
1064
	int             i, j, n;
1065
 
1066
// reconstitute the command line for the cmdline externally visible cvar
1067
	n = 0;
1068
 
1069
	for (j=0 ; (j
1070
	{
1071
		i = 0;
1072
 
1073
		while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i])
1074
		{
1075
			com_cmdline[n++] = argv[j][i++];
1076
		}
1077
 
1078
		if (n < (CMDLINE_LENGTH - 1))
1079
			com_cmdline[n++] = ' ';
1080
		else
1081
			break;
1082
	}
1083
 
1084
	com_cmdline[n] = 0;
1085
 
1086
	safe = false;
1087
 
1088
	for (com_argc=0 ; (com_argc
1089
		 com_argc++)
1090
	{
1091
		largv[com_argc] = argv[com_argc];
1092
		if (!Q_strcmp ("-safe", argv[com_argc]))
1093
			safe = true;
1094
	}
1095
 
1096
	if (safe)
1097
	{
1098
	// force all the safe-mode switches. Note that we reserved extra space in
1099
	// case we need to add these, so we don't need an overflow check
1100
		for (i=0 ; i
1101
		{
1102
			largv[com_argc] = safeargvs[i];
1103
			com_argc++;
1104
		}
1105
	}
1106
 
1107
	largv[com_argc] = argvdummy;
1108
	com_argv = largv;
1109
 
1110
	if (COM_CheckParm ("-rogue"))
1111
	{
1112
		rogue = true;
1113
		standard_quake = false;
1114
	}
1115
 
1116
	if (COM_CheckParm ("-hipnotic"))
1117
	{
1118
		hipnotic = true;
1119
		standard_quake = false;
1120
	}
1121
}
1122
 
1123
 
1124
/*
1125
================
1126
COM_Init
1127
================
1128
*/
1129
void COM_Init (char *basedir)
1130
{
1131
	byte    swaptest[2] = {1,0};
1132
 
1133
// set the byte swapping variables in a portable manner
1134
#ifdef SDL
1135
	// This is necessary because egcs 1.1.1 mis-compiles swaptest with -O2
1136
	if ( SDL_BYTEORDER == SDL_LIL_ENDIAN )
1137
#else
1138
	if ( *(short *)swaptest == 1)
1139
#endif
1140
	{
1141
		bigendien = false;
1142
		BigShort = ShortSwap;
1143
		LittleShort = ShortNoSwap;
1144
		BigLong = LongSwap;
1145
		LittleLong = LongNoSwap;
1146
		BigFloat = FloatSwap;
1147
		LittleFloat = FloatNoSwap;
1148
	}
1149
	else
1150
	{
1151
		bigendien = true;
1152
		BigShort = ShortNoSwap;
1153
		LittleShort = ShortSwap;
1154
		BigLong = LongNoSwap;
1155
		LittleLong = LongSwap;
1156
		BigFloat = FloatNoSwap;
1157
		LittleFloat = FloatSwap;
1158
	}
1159
 
1160
	Cvar_RegisterVariable (®istered);
1161
	Cvar_RegisterVariable (&cmdline);
1162
	Cmd_AddCommand ("path", COM_Path_f);
1163
 
1164
	COM_InitFilesystem ();
1165
	COM_CheckRegistered ();
1166
}
1167
 
1168
 
1169
/*
1170
============
1171
va
1172
 
1173
does a varargs printf into a temp buffer, so I don't need to have
1174
varargs versions of all text functions.
1175
FIXME: make this buffer size safe someday
1176
============
1177
*/
1178
char    *va(char *format, ...)
1179
{
1180
	va_list         argptr;
1181
	static char             string[1024];
1182
 
1183
	va_start (argptr, format);
1184
	vsprintf (string, format,argptr);
1185
	va_end (argptr);
1186
 
1187
	return string;
1188
}
1189
 
1190
 
1191
/// just for debugging
1192
int     memsearch (byte *start, int count, int search)
1193
{
1194
	int             i;
1195
 
1196
	for (i=0 ; i
1197
		if (start[i] == search)
1198
			return i;
1199
	return -1;
1200
}
1201
 
1202
/*
1203
=============================================================================
1204
 
1205
QUAKE FILESYSTEM
1206
 
1207
=============================================================================
1208
*/
1209
 
1210
int     com_filesize;
1211
 
1212
 
1213
//
1214
// in memory
1215
//
1216
 
1217
typedef struct
1218
{
1219
	char    name[MAX_QPATH];
1220
	int             filepos, filelen;
1221
} packfile_t;
1222
 
1223
typedef struct pack_s
1224
{
1225
	char    filename[MAX_OSPATH];
1226
	int             handle;
1227
	int             numfiles;
1228
	packfile_t      *files;
1229
} pack_t;
1230
 
1231
//
1232
// on disk
1233
//
1234
typedef struct
1235
{
1236
	char    name[56];
1237
	int             filepos, filelen;
1238
} dpackfile_t;
1239
 
1240
typedef struct
1241
{
1242
	char    id[4];
1243
	int             dirofs;
1244
	int             dirlen;
1245
} dpackheader_t;
1246
 
1247
#define MAX_FILES_IN_PACK       2048
1248
 
1249
char    com_cachedir[MAX_OSPATH];
1250
char    com_gamedir[MAX_OSPATH];
1251
 
1252
typedef struct searchpath_s
1253
{
1254
	char    filename[MAX_OSPATH];
1255
	pack_t  *pack;          // only one of filename / pack will be used
1256
	struct searchpath_s *next;
1257
} searchpath_t;
1258
 
1259
searchpath_t    *com_searchpaths;
1260
 
1261
/*
1262
============
1263
COM_Path_f
1264
 
1265
============
1266
*/
1267
void COM_Path_f (void)
1268
{
1269
	searchpath_t    *s;
1270
 
1271
	Con_Printf ("Current search path:\n");
1272
	for (s=com_searchpaths ; s ; s=s->next)
1273
	{
1274
		if (s->pack)
1275
		{
1276
			Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
1277
		}
1278
		else
1279
			Con_Printf ("%s\n", s->filename);
1280
	}
1281
}
1282
 
1283
/*
1284
============
1285
COM_WriteFile
1286
 
1287
The filename will be prefixed by the current game directory
1288
============
1289
*/
1290
void COM_WriteFile (char *filename, void *data, int len)
1291
{
1292
	int             handle;
1293
	char    name[MAX_OSPATH];
1294
 
1295
	sprintf (name, "%s/%s", com_gamedir, filename);
1296
 
1297
	handle = Sys_FileOpenWrite (name);
1298
	if (handle == -1)
1299
	{
1300
		Sys_Printf ("COM_WriteFile: failed on %s\n", name);
1301
		return;
1302
	}
1303
 
1304
	Sys_Printf ("COM_WriteFile: %s\n", name);
1305
	Sys_FileWrite (handle, data, len);
1306
	Sys_FileClose (handle);
1307
}
1308
 
1309
 
1310
/*
1311
============
1312
COM_CreatePath
1313
 
1314
Only used for CopyFile
1315
============
1316
*/
1317
void    COM_CreatePath (char *path)
1318
{
1319
	char    *ofs;
1320
 
1321
	for (ofs = path+1 ; *ofs ; ofs++)
1322
	{
1323
		if (*ofs == '/')
1324
		{       // create the directory
1325
			*ofs = 0;
1326
			Sys_mkdir (path);
1327
			*ofs = '/';
1328
		}
1329
	}
1330
}
1331
 
1332
 
1333
/*
1334
===========
1335
COM_CopyFile
1336
 
1337
Copies a file over from the net to the local cache, creating any directories
1338
needed.  This is for the convenience of developers using ISDN from home.
1339
===========
1340
*/
1341
void COM_CopyFile (char *netpath, char *cachepath)
1342
{
1343
	int             in, out;
1344
	int             remaining, count;
1345
	char    buf[4096];
1346
 
1347
	remaining = Sys_FileOpenRead (netpath, &in);
1348
	COM_CreatePath (cachepath);     // create directories up to the cache file
1349
	out = Sys_FileOpenWrite (cachepath);
1350
 
1351
	while (remaining)
1352
	{
1353
		if (remaining < sizeof(buf))
1354
			count = remaining;
1355
		else
1356
			count = sizeof(buf);
1357
		Sys_FileRead (in, buf, count);
1358
		Sys_FileWrite (out, buf, count);
1359
		remaining -= count;
1360
	}
1361
 
1362
	Sys_FileClose (in);
1363
	Sys_FileClose (out);
1364
}
1365
 
1366
/*
1367
===========
1368
COM_FindFile
1369
 
1370
Finds the file in the search path.
1371
Sets com_filesize and one of handle or file
1372
===========
1373
*/
1374
int COM_FindFile (char *filename, int *handle, FILE **file)
1375
{
1376
	searchpath_t    *search;
1377
	char            netpath[MAX_OSPATH];
1378
	char            cachepath[MAX_OSPATH];
1379
	pack_t          *pak;
1380
	int                     i;
1381
	int                     findtime, cachetime;
1382
 
1383
	if (file && handle)
1384
		Sys_Error ("COM_FindFile: both handle and file set");
1385
	if (!file && !handle)
1386
		Sys_Error ("COM_FindFile: neither handle or file set");
1387
 
1388
//
1389
// search through the path, one element at a time
1390
//
1391
	search = com_searchpaths;
1392
	if (proghack)
1393
	{	// gross hack to use quake 1 progs with quake 2 maps
1394
		if (!strcmp(filename, "progs.dat"))
1395
			search = search->next;
1396
	}
1397
 
1398
	for ( ; search ; search = search->next)
1399
	{
1400
	// is the element a pak file?
1401
		if (search->pack)
1402
		{
1403
		// look through all the pak file elements
1404
			pak = search->pack;
1405
			for (i=0 ; inumfiles ; i++)
1406
				if (!strcmp (pak->files[i].name, filename))
1407
				{       // found it!
1408
					Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename);
1409
					if (handle)
1410
					{
1411
						*handle = pak->handle;
1412
						Sys_FileSeek (pak->handle, pak->files[i].filepos);
1413
					}
1414
					else
1415
					{       // open a new file on the pakfile
1416
						*file = fopen (pak->filename, "rb");
1417
						if (*file)
1418
							fseek (*file, pak->files[i].filepos, SEEK_SET);
1419
					}
1420
					com_filesize = pak->files[i].filelen;
1421
					return com_filesize;
1422
				}
1423
		}
1424
		else
1425
		{
1426
	// check a file in the directory tree
1427
			if (!static_registered)
1428
			{       // if not a registered version, don't ever go beyond base
1429
				if ( strchr (filename, '/') || strchr (filename,'\\'))
1430
					continue;
1431
			}
1432
 
1433
			sprintf (netpath, "%s/%s",search->filename, filename);
1434
 
1435
			findtime = Sys_FileTime (netpath);
1436
			if (findtime == -1)
1437
				continue;
1438
 
1439
		// see if the file needs to be updated in the cache
1440
			if (!com_cachedir[0])
1441
				strcpy (cachepath, netpath);
1442
			else
1443
			{
1444
#if defined(_WIN32)
1445
				if ((strlen(netpath) < 2) || (netpath[1] != ':'))
1446
					sprintf (cachepath,"%s%s", com_cachedir, netpath);
1447
				else
1448
					sprintf (cachepath,"%s%s", com_cachedir, netpath+2);
1449
#else
1450
				sprintf (cachepath,"%s/%s", com_cachedir, netpath);
1451
#endif
1452
 
1453
				cachetime = Sys_FileTime (cachepath);
1454
 
1455
				if (cachetime < findtime)
1456
					COM_CopyFile (netpath, cachepath);
1457
				strcpy (netpath, cachepath);
1458
			}
1459
 
1460
			Sys_Printf ("FindFile: %s\n",netpath);
1461
			com_filesize = Sys_FileOpenRead (netpath, &i);
1462
			if (handle)
1463
				*handle = i;
1464
			else
1465
			{
1466
				Sys_FileClose (i);
1467
				*file = fopen (netpath, "rb");
1468
			}
1469
			return com_filesize;
1470
		}
1471
 
1472
	}
1473
 
1474
	Sys_Printf ("FindFile: can't find %s\n", filename);
1475
 
1476
	if (handle)
1477
		*handle = -1;
1478
	else
1479
		*file = NULL;
1480
	com_filesize = -1;
1481
	return -1;
1482
}
1483
 
1484
 
1485
/*
1486
===========
1487
COM_OpenFile
1488
 
1489
filename never has a leading slash, but may contain directory walks
1490
returns a handle and a length
1491
it may actually be inside a pak file
1492
===========
1493
*/
1494
int COM_OpenFile (char *filename, int *handle)
1495
{
1496
	return COM_FindFile (filename, handle, NULL);
1497
}
1498
 
1499
/*
1500
===========
1501
COM_FOpenFile
1502
 
1503
If the requested file is inside a packfile, a new FILE * will be opened
1504
into the file.
1505
===========
1506
*/
1507
int COM_FOpenFile (char *filename, FILE **file)
1508
{
1509
	return COM_FindFile (filename, NULL, file);
1510
}
1511
 
1512
/*
1513
============
1514
COM_CloseFile
1515
 
1516
If it is a pak file handle, don't really close it
1517
============
1518
*/
1519
void COM_CloseFile (int h)
1520
{
1521
	searchpath_t    *s;
1522
 
1523
	for (s = com_searchpaths ; s ; s=s->next)
1524
		if (s->pack && s->pack->handle == h)
1525
			return;
1526
 
1527
	Sys_FileClose (h);
1528
}
1529
 
1530
 
1531
/*
1532
============
1533
COM_LoadFile
1534
 
1535
Filename are reletive to the quake directory.
1536
Allways appends a 0 byte.
1537
============
1538
*/
1539
cache_user_t *loadcache;
1540
byte    *loadbuf;
1541
int             loadsize;
1542
byte *COM_LoadFile (char *path, int usehunk)
1543
{
1544
	int             h;
1545
	byte    *buf;
1546
	char    base[32];
1547
	int             len;
1548
 
1549
	buf = NULL;     // quiet compiler warning
1550
 
1551
// look for it in the filesystem or pack files
1552
	len = COM_OpenFile (path, &h);
1553
	if (h == -1)
1554
		return NULL;
1555
 
1556
// extract the filename base name for hunk tag
1557
	COM_FileBase (path, base);
1558
 
1559
	if (usehunk == 1)
1560
		buf = Hunk_AllocName (len+1, base);
1561
	else if (usehunk == 2)
1562
		buf = Hunk_TempAlloc (len+1);
1563
	else if (usehunk == 0)
1564
		buf = Z_Malloc (len+1);
1565
	else if (usehunk == 3)
1566
		buf = Cache_Alloc (loadcache, len+1, base);
1567
	else if (usehunk == 4)
1568
	{
1569
		if (len+1 > loadsize)
1570
			buf = Hunk_TempAlloc (len+1);
1571
		else
1572
			buf = loadbuf;
1573
	}
1574
	else
1575
		Sys_Error ("COM_LoadFile: bad usehunk");
1576
 
1577
	if (!buf)
1578
		Sys_Error ("COM_LoadFile: not enough space for %s", path);
1579
 
1580
	((byte *)buf)[len] = 0;
1581
 
1582
	Draw_BeginDisc ();
1583
	Sys_FileRead (h, buf, len);
1584
	COM_CloseFile (h);
1585
	Draw_EndDisc ();
1586
 
1587
	return buf;
1588
}
1589
 
1590
byte *COM_LoadHunkFile (char *path)
1591
{
1592
	return COM_LoadFile (path, 1);
1593
}
1594
 
1595
byte *COM_LoadTempFile (char *path)
1596
{
1597
	return COM_LoadFile (path, 2);
1598
}
1599
 
1600
void COM_LoadCacheFile (char *path, struct cache_user_s *cu)
1601
{
1602
	loadcache = cu;
1603
	COM_LoadFile (path, 3);
1604
}
1605
 
1606
// uses temp hunk if larger than bufsize
1607
byte *COM_LoadStackFile (char *path, void *buffer, int bufsize)
1608
{
1609
	byte    *buf;
1610
 
1611
	loadbuf = (byte *)buffer;
1612
	loadsize = bufsize;
1613
	buf = COM_LoadFile (path, 4);
1614
 
1615
	return buf;
1616
}
1617
 
1618
/*
1619
=================
1620
COM_LoadPackFile
1621
 
1622
Takes an explicit (not game tree related) path to a pak file.
1623
 
1624
Loads the header and directory, adding the files at the beginning
1625
of the list so they override previous pack files.
1626
=================
1627
*/
1628
pack_t *COM_LoadPackFile (char *packfile)
1629
{
1630
	dpackheader_t   header;
1631
	int                             i;
1632
	packfile_t              *newfiles;
1633
	int                             numpackfiles;
1634
	pack_t                  *pack;
1635
	int                             packhandle;
1636
	dpackfile_t             info[MAX_FILES_IN_PACK];
1637
	unsigned short          crc;
1638
 
1639
	if (Sys_FileOpenRead (packfile, &packhandle) == -1)
1640
	{
1641
//              Con_Printf ("Couldn't open %s\n", packfile);
1642
		return NULL;
1643
	}
1644
	Sys_FileRead (packhandle, (void *)&header, sizeof(header));
1645
	if (header.id[0] != 'P' || header.id[1] != 'A'
1646
	|| header.id[2] != 'C' || header.id[3] != 'K')
1647
		Sys_Error ("%s is not a packfile", packfile);
1648
	header.dirofs = LittleLong (header.dirofs);
1649
	header.dirlen = LittleLong (header.dirlen);
1650
 
1651
	numpackfiles = header.dirlen / sizeof(dpackfile_t);
1652
 
1653
	if (numpackfiles > MAX_FILES_IN_PACK)
1654
		Sys_Error ("%s has %i files", packfile, numpackfiles);
1655
 
1656
	if (numpackfiles != PAK0_COUNT)
1657
		com_modified = true;    // not the original file
1658
 
1659
	newfiles = Hunk_AllocName (numpackfiles * sizeof(packfile_t), "packfile");
1660
 
1661
	Sys_FileSeek (packhandle, header.dirofs);
1662
	Sys_FileRead (packhandle, (void *)info, header.dirlen);
1663
 
1664
// crc the directory to check for modifications
1665
	CRC_Init (&crc);
1666
	for (i=0 ; i
1667
		CRC_ProcessByte (&crc, ((byte *)info)[i]);
1668
	if (crc != PAK0_CRC)
1669
		com_modified = true;
1670
 
1671
// parse the directory
1672
	for (i=0 ; i
1673
	{
1674
		strcpy (newfiles[i].name, info[i].name);
1675
		newfiles[i].filepos = LittleLong(info[i].filepos);
1676
		newfiles[i].filelen = LittleLong(info[i].filelen);
1677
	}
1678
 
1679
	pack = Hunk_Alloc (sizeof (pack_t));
1680
	strcpy (pack->filename, packfile);
1681
	pack->handle = packhandle;
1682
	pack->numfiles = numpackfiles;
1683
	pack->files = newfiles;
1684
 
1685
	Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
1686
	return pack;
1687
}
1688
 
1689
 
1690
/*
1691
================
1692
COM_AddGameDirectory
1693
 
1694
Sets com_gamedir, adds the directory to the head of the path,
1695
then loads and adds pak1.pak pak2.pak ...
1696
================
1697
*/
1698
void COM_AddGameDirectory (char *dir)
1699
{
1700
	int                             i;
1701
	searchpath_t    *search;
1702
	pack_t                  *pak;
1703
	char                    pakfile[MAX_OSPATH];
1704
 
1705
	strcpy (com_gamedir, dir);
1706
 
1707
//
1708
// add the directory to the search path
1709
//
1710
	search = Hunk_Alloc (sizeof(searchpath_t));
1711
	strcpy (search->filename, dir);
1712
	search->next = com_searchpaths;
1713
	com_searchpaths = search;
1714
 
1715
//
1716
// add any pak files in the format pak0.pak pak1.pak, ...
1717
//
1718
	for (i=0 ; ; i++)
1719
	{
1720
		sprintf (pakfile, "%s/pak%i.pak", dir, i);
1721
		pak = COM_LoadPackFile (pakfile);
1722
		if (!pak)
1723
			break;
1724
		search = Hunk_Alloc (sizeof(searchpath_t));
1725
		search->pack = pak;
1726
		search->next = com_searchpaths;
1727
		com_searchpaths = search;
1728
	}
1729
 
1730
//
1731
// add the contents of the parms.txt file to the end of the command line
1732
//
1733
 
1734
}
1735
 
1736
/*
1737
================
1738
COM_InitFilesystem
1739
================
1740
*/
1741
void COM_InitFilesystem (void)
1742
{
1743
	int             i, j;
1744
	char    basedir[MAX_OSPATH];
1745
	searchpath_t    *search;
1746
 
1747
//
1748
// -basedir 
1749
// Overrides the system supplied base directory (under GAMENAME)
1750
//
1751
	i = COM_CheckParm ("-basedir");
1752
	if (i && i < com_argc-1)
1753
		strcpy (basedir, com_argv[i+1]);
1754
	else
1755
		strcpy (basedir, host_parms.basedir);
1756
 
1757
	j = strlen (basedir);
1758
 
1759
	if (j > 0)
1760
	{
1761
		if ((basedir[j-1] == '\\') || (basedir[j-1] == '/'))
1762
			basedir[j-1] = 0;
1763
	}
1764
 
1765
//
1766
// -cachedir 
1767
// Overrides the system supplied cache directory (NULL or /qcache)
1768
// -cachedir - will disable caching.
1769
//
1770
	i = COM_CheckParm ("-cachedir");
1771
	if (i && i < com_argc-1)
1772
	{
1773
		if (com_argv[i+1][0] == '-')
1774
			com_cachedir[0] = 0;
1775
		else
1776
			strcpy (com_cachedir, com_argv[i+1]);
1777
	}
1778
	else if (host_parms.cachedir)
1779
		strcpy (com_cachedir, host_parms.cachedir);
1780
	else
1781
		com_cachedir[0] = 0;
1782
 
1783
//
1784
// start up with GAMENAME by default (id1)
1785
//
1786
#ifdef _KOLIBRI
1787
	COM_AddGameDirectory (basedir);
1788
#else
1789
	COM_AddGameDirectory (va("%s/"GAMENAME, basedir) );
1790
#endif
1791
 
1792
	if (COM_CheckParm ("-rogue"))
1793
		COM_AddGameDirectory (va("%s/rogue", basedir) );
1794
	if (COM_CheckParm ("-hipnotic"))
1795
		COM_AddGameDirectory (va("%s/hipnotic", basedir) );
1796
 
1797
//
1798
// -game 
1799
// Adds basedir/gamedir as an override game
1800
//
1801
	i = COM_CheckParm ("-game");
1802
	if (i && i < com_argc-1)
1803
	{
1804
		com_modified = true;
1805
		COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1]));
1806
	}
1807
 
1808
//
1809
// -path  [] ...
1810
// Fully specifies the exact serach path, overriding the generated one
1811
//
1812
	i = COM_CheckParm ("-path");
1813
	if (i)
1814
	{
1815
		com_modified = true;
1816
		com_searchpaths = NULL;
1817
		while (++i < com_argc)
1818
		{
1819
			if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
1820
				break;
1821
 
1822
			search = Hunk_Alloc (sizeof(searchpath_t));
1823
			if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
1824
			{
1825
				search->pack = COM_LoadPackFile (com_argv[i]);
1826
				if (!search->pack)
1827
					Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
1828
			}
1829
			else
1830
				strcpy (search->filename, com_argv[i]);
1831
			search->next = com_searchpaths;
1832
			com_searchpaths = search;
1833
		}
1834
	}
1835
 
1836
	if (COM_CheckParm ("-proghack"))
1837
		proghack = true;
1838
}
1839
 
1840