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 (®istered);
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