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