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