]> icculus.org git repositories - divverent/darkplaces.git/blob - common.c
renamed byte to qbyte throughout engine to eliminate a mingw conflict
[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 // used by client
562 void MSG_WriteCoord (sizebuf_t *sb, float f)
563 {
564         if (dpprotocol == DPPROTOCOL_VERSION2)
565         {
566                 if (f >= 0)
567                         MSG_WriteShort (sb, (int)(f + 0.5f));
568                 else
569                         MSG_WriteShort (sb, (int)(f - 0.5f));
570         }
571         else if (dpprotocol == DPPROTOCOL_VERSION1)
572                 MSG_WriteFloat(sb, f);
573         else
574         {
575                 if (f >= 0)
576                         MSG_WriteShort (sb, (int)(f*8.0f + 0.5f));
577                 else
578                         MSG_WriteShort (sb, (int)(f*8.0f - 0.5f));
579         }
580 }
581
582 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
583 {
584         if (f >= 0)
585                 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
586         else
587                 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
588 }
589
590 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
591 void MSG_WriteAngle (sizebuf_t *sb, float f)
592 {
593         if (f >= 0)
594                 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
595         else
596                 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
597 }
598
599 //
600 // reading functions
601 //
602 int                     msg_readcount;
603 qboolean        msg_badread;
604
605 void MSG_BeginReading (void)
606 {
607         msg_readcount = 0;
608         msg_badread = false;
609 }
610
611 /*
612 // returns -1 and sets msg_badread if no more characters are available
613 int MSG_ReadChar (void)
614 {
615         int     c;
616
617         // LordHavoc: minor optimization
618         if (msg_readcount >= net_message.cursize)
619 //      if (msg_readcount+1 > net_message.cursize)
620         {
621                 msg_badread = true;
622                 return -1;
623         }
624
625         c = (signed char)net_message.data[msg_readcount];
626         msg_readcount++;
627
628         return c;
629 }
630
631 int MSG_ReadByte (void)
632 {
633         int     c;
634
635         // LordHavoc: minor optimization
636         if (msg_readcount >= net_message.cursize)
637 //      if (msg_readcount+1 > net_message.cursize)
638         {
639                 msg_badread = true;
640                 return -1;
641         }
642
643         c = (unsigned char)net_message.data[msg_readcount];
644         msg_readcount++;
645
646         return c;
647 }
648 */
649
650 int MSG_ReadShort (void)
651 {
652         int     c;
653
654         if (msg_readcount+2 > net_message.cursize)
655         {
656                 msg_badread = true;
657                 return -1;
658         }
659
660         c = (short)(net_message.data[msg_readcount]
661         + (net_message.data[msg_readcount+1]<<8));
662
663         msg_readcount += 2;
664
665         return c;
666 }
667
668 int MSG_ReadLong (void)
669 {
670         int     c;
671
672         if (msg_readcount+4 > net_message.cursize)
673         {
674                 msg_badread = true;
675                 return -1;
676         }
677
678         c = net_message.data[msg_readcount]
679         + (net_message.data[msg_readcount+1]<<8)
680         + (net_message.data[msg_readcount+2]<<16)
681         + (net_message.data[msg_readcount+3]<<24);
682
683         msg_readcount += 4;
684
685         return c;
686 }
687
688 float MSG_ReadFloat (void)
689 {
690         union
691         {
692                 qbyte    b[4];
693                 float   f;
694                 int     l;
695         } dat;
696
697         dat.b[0] =      net_message.data[msg_readcount];
698         dat.b[1] =      net_message.data[msg_readcount+1];
699         dat.b[2] =      net_message.data[msg_readcount+2];
700         dat.b[3] =      net_message.data[msg_readcount+3];
701         msg_readcount += 4;
702
703         dat.l = LittleLong (dat.l);
704
705         return dat.f;
706 }
707
708 char *MSG_ReadString (void)
709 {
710         static char     string[2048];
711         int             l,c;
712
713         l = 0;
714         do
715         {
716                 c = MSG_ReadChar ();
717                 if (c == -1 || c == 0)
718                         break;
719                 string[l] = c;
720                 l++;
721         } while (l < sizeof(string)-1);
722
723         string[l] = 0;
724
725         return string;
726 }
727
728 // used by server (always latest dpprotocol)
729 float MSG_ReadDPCoord (void)
730 {
731         return (signed short) MSG_ReadShort();
732 }
733
734 // used by client
735 float MSG_ReadCoord (void)
736 {
737         if (dpprotocol == DPPROTOCOL_VERSION2)
738                 return (signed short) MSG_ReadShort();
739         else if (dpprotocol == DPPROTOCOL_VERSION1)
740                 return MSG_ReadFloat();
741         else
742                 return MSG_ReadShort() * (1.0f/8.0f);
743 }
744
745 /*
746 float MSG_ReadCoord (void)
747 {
748         return MSG_ReadShort() * (1.0f/8.0f);
749 }
750
751 float MSG_ReadAngle (void)
752 {
753         return MSG_ReadChar() * (360.0f/256.0f);
754 }
755
756 float MSG_ReadPreciseAngle (void)
757 {
758         return MSG_ReadShort() * (360.0f/65536);
759 }
760 */
761
762
763 //===========================================================================
764
765 void SZ_Alloc (sizebuf_t *buf, int startsize, char *name)
766 {
767         if (startsize < 256)
768                 startsize = 256;
769         buf->mempool = Mem_AllocPool(name);
770         buf->data = Mem_Alloc(buf->mempool, startsize);
771         buf->maxsize = startsize;
772         buf->cursize = 0;
773 }
774
775
776 void SZ_Free (sizebuf_t *buf)
777 {
778         Mem_FreePool(&buf->mempool);
779         buf->data = NULL;
780         buf->maxsize = 0;
781         buf->cursize = 0;
782 }
783
784 void SZ_Clear (sizebuf_t *buf)
785 {
786         buf->cursize = 0;
787 }
788
789 void *SZ_GetSpace (sizebuf_t *buf, int length)
790 {
791         void    *data;
792
793         if (buf->cursize + length > buf->maxsize)
794         {
795                 if (!buf->allowoverflow)
796                         Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
797
798                 if (length > buf->maxsize)
799                         Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
800
801                 buf->overflowed = true;
802                 Con_Printf ("SZ_GetSpace: overflow");
803                 SZ_Clear (buf);
804         }
805
806         data = buf->data + buf->cursize;
807         buf->cursize += length;
808         
809         return data;
810 }
811
812 void SZ_Write (sizebuf_t *buf, void *data, int length)
813 {
814         memcpy (SZ_GetSpace(buf,length),data,length);         
815 }
816
817 void SZ_Print (sizebuf_t *buf, char *data)
818 {
819         int             len;
820         
821         len = strlen(data)+1;
822
823 // byte * cast to keep VC++ happy
824         if (buf->data[buf->cursize-1])
825                 memcpy ((qbyte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
826         else
827                 memcpy ((qbyte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
828 }
829
830
831 //============================================================================
832
833
834 /*
835 ============
836 COM_SkipPath
837 ============
838 */
839 char *COM_SkipPath (char *pathname)
840 {
841         char    *last;
842
843         last = pathname;
844         while (*pathname)
845         {
846                 if (*pathname=='/')
847                         last = pathname+1;
848                 pathname++;
849         }
850         return last;
851 }
852
853 /*
854 ============
855 COM_StripExtension
856 ============
857 */
858 // LordHavoc: replacement for severely broken COM_StripExtension that was used in original quake.
859 void COM_StripExtension (char *in, char *out)
860 {
861         char *last = NULL;
862         while (*in)
863         {
864                 if (*in == '.')
865                         last = in;
866                 if ((*in == '/') || (*in == '\\') || (*in == ':'))
867                         last = NULL;
868                 *out++ = *in++;
869         }
870         if (last)
871                 *last = 0;
872 }
873
874 /*
875 ============
876 COM_FileExtension
877 ============
878 */
879 char *COM_FileExtension (char *in)
880 {
881         static char exten[8];
882         int             i;
883
884         while (*in && *in != '.')
885                 in++;
886         if (!*in)
887                 return "";
888         in++;
889         for (i=0 ; i<7 && *in ; i++,in++)
890                 exten[i] = *in;
891         exten[i] = 0;
892         return exten;
893 }
894
895 /*
896 ============
897 COM_FileBase
898 ============
899 */
900 void COM_FileBase (char *in, char *out)
901 {
902         char *slash, *dot;
903         char *s;
904
905         slash = in;
906         dot = NULL;
907         s = in;
908         while(*s)
909         {
910                 if (*s == '/')
911                         slash = s + 1;
912                 if (*s == '.')
913                         dot = s;
914                 s++;
915         }
916         if (dot == NULL)
917                 dot = s;
918         if (dot - slash < 2)
919                 strcpy (out,"?model?");
920         else
921         {
922                 while (slash < dot)
923                         *out++ = *slash++;
924                 *out++ = 0;
925         }
926 }
927
928
929 /*
930 ==================
931 COM_DefaultExtension
932 ==================
933 */
934 void COM_DefaultExtension (char *path, char *extension)
935 {
936         char    *src;
937 //
938 // if path doesn't have a .EXT, append extension
939 // (extension should include the .)
940 //
941         src = path + strlen(path) - 1;
942
943         while (*src != '/' && src != path)
944         {
945                 if (*src == '.')
946                         return;                 // it has an extension
947                 src--;
948         }
949
950         strcat (path, extension);
951 }
952
953
954 /*
955 ==============
956 COM_Parse
957
958 Parse a token out of a string
959 ==============
960 */
961 char *COM_Parse (char *data)
962 {
963         int             c;
964         int             len;
965         
966         len = 0;
967         com_token[0] = 0;
968         
969         if (!data)
970                 return NULL;
971                 
972 // skip whitespace
973 skipwhite:
974         while ( (c = *data) <= ' ')
975         {
976                 if (c == 0)
977                         return NULL;                    // end of file;
978                 data++;
979         }
980         
981 // skip // comments
982         if (c=='/' && data[1] == '/')
983         {
984                 while (*data && *data != '\n')
985                         data++;
986                 goto skipwhite;
987         }
988         
989
990 // handle quoted strings specially
991         if (c == '\"')
992         {
993                 data++;
994                 while (1)
995                 {
996                         c = *data++;
997                         if (c=='\"' || !c)
998                         {
999                                 com_token[len] = 0;
1000                                 return data;
1001                         }
1002                         com_token[len] = c;
1003                         len++;
1004                 }
1005         }
1006
1007 // parse single characters
1008         if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
1009         {
1010                 com_token[len] = c;
1011                 len++;
1012                 com_token[len] = 0;
1013                 return data+1;
1014         }
1015
1016 // parse a regular word
1017         do
1018         {
1019                 com_token[len] = c;
1020                 data++;
1021                 len++;
1022                 c = *data;
1023         if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
1024                         break;
1025         } while (c>32);
1026         
1027         com_token[len] = 0;
1028         return data;
1029 }
1030
1031
1032 /*
1033 ================
1034 COM_CheckParm
1035
1036 Returns the position (1 to argc-1) in the program's argument list
1037 where the given parameter apears, or 0 if not present
1038 ================
1039 */
1040 int COM_CheckParm (char *parm)
1041 {
1042         int             i;
1043         
1044         for (i=1 ; i<com_argc ; i++)
1045         {
1046                 if (!com_argv[i])
1047                         continue;               // NEXTSTEP sometimes clears appkit vars.
1048                 if (!strcmp (parm,com_argv[i]))
1049                         return i;
1050         }
1051                 
1052         return 0;
1053 }
1054
1055 /*
1056 ================
1057 COM_CheckRegistered
1058
1059 Looks for the pop.txt file and verifies it.
1060 Sets the "registered" cvar.
1061 Immediately exits out if an alternate game was attempted to be started without
1062 being registered.
1063 ================
1064 */
1065 void COM_CheckRegistered (void)
1066 {
1067         Cvar_Set ("cmdline", com_cmdline);
1068
1069 //      static_registered = 0;
1070
1071         if (!Sys_FileTime("gfx/pop.lmp"))
1072         {
1073                 if (com_modified)
1074                         Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
1075                 else
1076                         Con_Printf ("Playing shareware version.\n");
1077 //#if WINDED
1078 //      Sys_Error ("This dedicated server requires a full registered copy of Quake");
1079 //#endif
1080 //              Con_Printf ("Playing shareware version.\n");
1081 //              if (com_modified)
1082 //                      Sys_Error ("You must have the registered version to use modified games");
1083                 return;
1084         }
1085
1086 //      Cvar_Set ("cmdline", com_cmdline);
1087         Cvar_Set ("registered", "1");
1088 //      static_registered = 1;
1089         Con_Printf ("Playing registered version.\n");
1090 }
1091
1092
1093 void COM_Path_f (void);
1094
1095
1096 /*
1097 ================
1098 COM_InitArgv
1099 ================
1100 */
1101 void COM_InitArgv (int argc, char **argv)
1102 {
1103         qboolean        safe;
1104         int             i, j, n;
1105
1106 // reconstitute the command line for the cmdline externally visible cvar
1107         n = 0;
1108
1109         for (j=0 ; (j<MAX_NUM_ARGVS) && (j< argc) ; j++)
1110         {
1111                 i = 0;
1112
1113                 while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i])
1114                 {
1115                         com_cmdline[n++] = argv[j][i++];
1116                 }
1117
1118                 if (n < (CMDLINE_LENGTH - 1))
1119                         com_cmdline[n++] = ' ';
1120                 else
1121                         break;
1122         }
1123
1124         com_cmdline[n] = 0;
1125
1126         safe = false;
1127
1128         for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;
1129                  com_argc++)
1130         {
1131                 largv[com_argc] = argv[com_argc];
1132                 if (!strcmp ("-safe", argv[com_argc]))
1133                         safe = true;
1134         }
1135
1136         if (safe)
1137         {
1138         // force all the safe-mode switches. Note that we reserved extra space in
1139         // case we need to add these, so we don't need an overflow check
1140                 for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
1141                 {
1142                         largv[com_argc] = safeargvs[i];
1143                         com_argc++;
1144                 }
1145         }
1146
1147         largv[com_argc] = argvdummy;
1148         com_argv = largv;
1149
1150 #if ZYMOTIC
1151         gamemode = GAME_ZYMOTIC;
1152 #elif FIENDARENA
1153         gamemode = GAME_FIENDARENA;
1154 #elif NEHAHRA
1155         gamemode = GAME_NEHAHRA;
1156 #else
1157         if (COM_CheckParm ("-zymotic"))
1158                 gamemode = GAME_ZYMOTIC;
1159         else if (COM_CheckParm ("-fiendarena"))
1160                 gamemode = GAME_FIENDARENA;
1161         else if (COM_CheckParm ("-nehahra"))
1162                 gamemode = GAME_NEHAHRA;
1163         else if (COM_CheckParm ("-hipnotic"))
1164                 gamemode = GAME_HIPNOTIC;
1165         else if (COM_CheckParm ("-rogue"))
1166                 gamemode = GAME_ROGUE;
1167 #endif
1168         switch(gamemode)
1169         {
1170         case GAME_NORMAL:
1171                 gamename = "DarkPlaces";
1172                 break;
1173         case GAME_HIPNOTIC:
1174                 gamename = "Darkplaces-Hipnotic";
1175                 break;
1176         case GAME_ROGUE:
1177                 gamename = "Darkplaces-Rogue";
1178                 break;
1179         case GAME_NEHAHRA:
1180                 gamename = "DarkPlaces-Nehahra";
1181                 break;
1182         case GAME_FIENDARENA:
1183                 gamename = "FiendArena";
1184                 break;
1185         case GAME_ZYMOTIC:
1186                 gamename = "Zymotic";
1187                 break;
1188         default:
1189                 Sys_Error("COM_InitArgv: unknown gamemode %i\n", gamemode);
1190                 break;
1191         }
1192 }
1193
1194
1195 extern void Mathlib_Init(void);
1196
1197 /*
1198 ================
1199 COM_Init
1200 ================
1201 */
1202 void COM_Init (void)
1203 {
1204 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
1205         qbyte    swaptest[2] = {1,0};
1206
1207 // set the byte swapping variables in a portable manner
1208         if ( *(short *)swaptest == 1)
1209         {
1210                 BigShort = ShortSwap;
1211                 LittleShort = ShortNoSwap;
1212                 BigLong = LongSwap;
1213                 LittleLong = LongNoSwap;
1214                 BigFloat = FloatSwap;
1215                 LittleFloat = FloatNoSwap;
1216         }
1217         else
1218         {
1219                 BigShort = ShortNoSwap;
1220                 LittleShort = ShortSwap;
1221                 BigLong = LongNoSwap;
1222                 LittleLong = LongSwap;
1223                 BigFloat = FloatNoSwap;
1224                 LittleFloat = FloatSwap;
1225         }
1226 #endif
1227
1228         pak_mempool = Mem_AllocPool("paks");
1229
1230         Cvar_RegisterVariable (&registered);
1231         Cvar_RegisterVariable (&cmdline);
1232         Cmd_AddCommand ("path", COM_Path_f);
1233
1234         Mathlib_Init();
1235
1236         COM_InitFilesystem ();
1237         COM_CheckRegistered ();
1238 }
1239
1240
1241 /*
1242 ============
1243 va
1244
1245 does a varargs printf into a temp buffer, so I don't need to have
1246 varargs versions of all text functions.
1247 FIXME: make this buffer size safe someday
1248 ============
1249 */
1250 char    *va(char *format, ...)
1251 {
1252         va_list argptr;
1253         // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1254         static char string[8][1024], *s;
1255         static int stringindex = 0;
1256
1257         s = string[stringindex];
1258         stringindex = (stringindex + 1) & 7;
1259         va_start (argptr, format);
1260         vsprintf (s, format,argptr);
1261         va_end (argptr);
1262
1263         return s;
1264 }
1265
1266
1267 /// just for debugging
1268 int     memsearch (qbyte *start, int count, int search)
1269 {
1270         int             i;
1271
1272         for (i=0 ; i<count ; i++)
1273                 if (start[i] == search)
1274                         return i;
1275         return -1;
1276 }
1277
1278 /*
1279 =============================================================================
1280
1281 QUAKE FILESYSTEM
1282
1283 =============================================================================
1284 */
1285
1286 int     com_filesize;
1287
1288
1289 //
1290 // in memory
1291 //
1292
1293 typedef struct
1294 {
1295         char name[MAX_QPATH];
1296         int filepos, filelen;
1297 } packfile_t;
1298
1299 typedef struct pack_s
1300 {
1301         char filename[MAX_OSPATH];
1302         int handle;
1303         int numfiles;
1304         packfile_t *files;
1305         mempool_t *mempool;
1306         struct pack_s *next;
1307 } pack_t;
1308
1309 //
1310 // on disk
1311 //
1312 typedef struct
1313 {
1314         char name[56];
1315         int filepos, filelen;
1316 } dpackfile_t;
1317
1318 typedef struct
1319 {
1320         char id[4];
1321         int dirofs;
1322         int dirlen;
1323 } dpackheader_t;
1324
1325 // LordHavoc: was 2048, increased to 65536 and changed info[MAX_PACK_FILES] to a temporary alloc
1326 #define MAX_FILES_IN_PACK       65536
1327
1328 pack_t  *packlist = NULL;
1329
1330 #if CACHEENABLE
1331 char    com_cachedir[MAX_OSPATH];
1332 #endif
1333 char    com_gamedir[MAX_OSPATH];
1334
1335 typedef struct searchpath_s
1336 {
1337         char filename[MAX_OSPATH];
1338         pack_t *pack;          // only one of filename / pack will be used
1339         struct searchpath_s *next;
1340 } searchpath_t;
1341
1342 searchpath_t    *com_searchpaths;
1343
1344 /*
1345 ============
1346 COM_Path_f
1347
1348 ============
1349 */
1350 void COM_Path_f (void)
1351 {
1352         searchpath_t    *s;
1353
1354         Con_Printf ("Current search path:\n");
1355         for (s=com_searchpaths ; s ; s=s->next)
1356         {
1357                 if (s->pack)
1358                 {
1359                         Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
1360                 }
1361                 else
1362                         Con_Printf ("%s\n", s->filename);
1363         }
1364 }
1365
1366 /*
1367 ============
1368 COM_CreatePath
1369
1370 LordHavoc: Previously only used for CopyFile, now also used for COM_WriteFile.
1371 ============
1372 */
1373 void    COM_CreatePath (char *path)
1374 {
1375         char    *ofs, save;
1376
1377         for (ofs = path+1 ; *ofs ; ofs++)
1378         {
1379                 if (*ofs == '/' || *ofs == '\\' || *ofs == ':')
1380                 {       // create the directory
1381                         save = *ofs;
1382                         *ofs = 0;
1383                         Sys_mkdir (path);
1384                         *ofs = save;
1385                 }
1386         }
1387 }
1388
1389
1390 /*
1391 ============
1392 COM_WriteFile
1393
1394 The filename will be prefixed by the current game directory
1395 ============
1396 */
1397 void COM_WriteFile (char *filename, void *data, int len)
1398 {
1399         int             handle;
1400         char    name[MAX_OSPATH];
1401
1402         sprintf (name, "%s/%s", com_gamedir, filename);
1403
1404         // LordHavoc: added this
1405         COM_CreatePath (name); // create directories up to the file
1406
1407         handle = Sys_FileOpenWrite (name);
1408         if (handle == -1)
1409         {
1410                 Sys_Printf ("COM_WriteFile: failed on %s\n", name);
1411                 return;
1412         }
1413
1414         Con_Printf ("COM_WriteFile: %s\n", name);
1415         Sys_FileWrite (handle, data, len);
1416         Sys_FileClose (handle);
1417 }
1418
1419
1420 /*
1421 ===========
1422 COM_CopyFile
1423
1424 Copies a file over from the net to the local cache, creating any directories
1425 needed.  This is for the convenience of developers using ISDN from home.
1426 ===========
1427 */
1428 void COM_CopyFile (char *netpath, char *cachepath)
1429 {
1430         int             in, out;
1431         int             remaining, count;
1432         char    buf[4096];
1433
1434         remaining = Sys_FileOpenRead (netpath, &in);            
1435         COM_CreatePath (cachepath);     // create directories up to the cache file
1436         out = Sys_FileOpenWrite (cachepath);
1437         
1438         while (remaining)
1439         {
1440                 if (remaining < sizeof(buf))
1441                         count = remaining;
1442                 else
1443                         count = sizeof(buf);
1444                 Sys_FileRead (in, buf, count);
1445                 Sys_FileWrite (out, buf, count);
1446                 remaining -= count;
1447         }
1448
1449         Sys_FileClose (in);
1450         Sys_FileClose (out);    
1451 }
1452
1453 /*
1454 ===========
1455 COM_OpenRead
1456 ===========
1457 */
1458 QFile * COM_OpenRead (const char *path, int offs, int len, qboolean zip)
1459 {
1460         int                             fd = open (path, O_RDONLY);
1461         unsigned char   id[2];
1462         unsigned char   len_bytes[4];
1463
1464         if (fd == -1)
1465         {
1466                 Sys_Error ("Couldn't open %s", path);
1467                 return 0;
1468         }
1469         if (offs < 0 || len < 0)
1470         {
1471                 // normal file
1472                 offs = 0;
1473                 len = lseek (fd, 0, SEEK_END);
1474                 lseek (fd, 0, SEEK_SET);
1475         }
1476         lseek (fd, offs, SEEK_SET);
1477         if (zip)
1478         {
1479                 read (fd, id, 2);
1480                 if (id[0] == 0x1f && id[1] == 0x8b)
1481                 {
1482                         lseek (fd, offs + len - 4, SEEK_SET);
1483                         read (fd, len_bytes, 4);
1484                         len = ((len_bytes[3] << 24)
1485                                    | (len_bytes[2] << 16)
1486                                    | (len_bytes[1] << 8)
1487                                    | (len_bytes[0]));
1488                 }
1489         }
1490         lseek (fd, offs, SEEK_SET);
1491         com_filesize = len;
1492
1493 #ifdef WIN32
1494         setmode (fd, O_BINARY);
1495 #endif
1496         if (zip)
1497                 return Qdopen (fd, "rbz");
1498         else
1499                 return Qdopen (fd, "rb");
1500 }
1501
1502 /*
1503 ===========
1504 COM_FindFile
1505
1506 Finds the file in the search path.
1507 Sets com_filesize and one of handle or file
1508 ===========
1509 */
1510 int COM_FindFile (char *filename, QFile **file, qboolean quiet, qboolean zip)
1511 {
1512         searchpath_t    *search;
1513         char                    netpath[MAX_OSPATH];
1514 #if CACHEENABLE
1515         char                    cachepath[MAX_OSPATH];
1516         int                             cachetime;
1517 #endif
1518         pack_t                  *pak;
1519         int                             i;
1520         int                             findtime;
1521         char                    gzfilename[MAX_OSPATH];
1522         int                             filenamelen;
1523
1524         filenamelen = strlen (filename);
1525         sprintf (gzfilename, "%s.gz", filename);
1526
1527         if (!file)
1528                 Sys_Error ("COM_FindFile: file not set");
1529                 
1530 //
1531 // search through the path, one element at a time
1532 //
1533         search = com_searchpaths;
1534 //      if (proghack)
1535 //      {       // gross hack to use quake 1 progs with quake 2 maps
1536 //              if (!strcmp(filename, "progs.dat"))
1537 //                      search = search->next;
1538 //      }
1539
1540         for ( ; search ; search = search->next)
1541         {
1542         // is the element a pak file?
1543                 if (search->pack)
1544                 {
1545                 // look through all the pak file elements
1546                         pak = search->pack;
1547                         for (i=0 ; i<pak->numfiles ; i++)
1548                                 if (!strcmp (pak->files[i].name, filename)
1549                                     || !strcmp (pak->files[i].name, gzfilename))
1550                                 {       // found it!
1551                                         if (!quiet)
1552                                                 Sys_Printf ("PackFile: %s : %s\n",pak->filename, pak->files[i].name);
1553                                         // open a new file on the pakfile
1554                                         *file = COM_OpenRead (pak->filename, pak->files[i].filepos, pak->files[i].filelen, zip);
1555                                         return com_filesize;
1556                                 }
1557                 }
1558                 else
1559                 {               
1560         // check a file in the directory tree
1561 //                      if (!static_registered)
1562 //                      {       // if not a registered version, don't ever go beyond base
1563 //                              if ( strchr (filename, '/') || strchr (filename,'\\'))
1564 //                                      continue;
1565 //                      }
1566                         
1567                         sprintf (netpath, "%s/%s",search->filename, filename);
1568                         
1569                         findtime = Sys_FileTime (netpath);
1570                         if (findtime == -1)
1571                                 continue;
1572                                 
1573 #if CACHEENABLE
1574                         // see if the file needs to be updated in the cache
1575                         if (com_cachedir[0])
1576                         {       
1577 #if defined(_WIN32)
1578                                 if ((strlen(netpath) < 2) || (netpath[1] != ':'))
1579                                         sprintf (cachepath,"%s%s", com_cachedir, netpath);
1580                                 else
1581                                         sprintf (cachepath,"%s%s", com_cachedir, netpath+2);
1582 #else
1583                                 sprintf (cachepath,"%s%s", com_cachedir, netpath);
1584 #endif
1585
1586                                 cachetime = Sys_FileTime (cachepath);
1587                         
1588                                 if (cachetime < findtime)
1589                                         COM_CopyFile (netpath, cachepath);
1590                                 strcpy (netpath, cachepath);
1591                         }       
1592 #endif
1593
1594                         if (!quiet)
1595                                 Sys_Printf ("FindFile: %s\n",netpath);
1596                         *file = COM_OpenRead (netpath, -1, -1, zip);
1597                         return com_filesize;
1598                 }
1599                 
1600         }
1601         
1602         if (!quiet)
1603                 Sys_Printf ("FindFile: can't find %s\n", filename);
1604         
1605         *file = NULL;
1606         com_filesize = -1;
1607         return -1;
1608 }
1609
1610
1611 /*
1612 ===========
1613 COM_FOpenFile
1614
1615 If the requested file is inside a packfile, a new QFile * will be opened
1616 into the file.
1617 ===========
1618 */
1619 int COM_FOpenFile (char *filename, QFile **file, qboolean quiet, qboolean zip)
1620 {
1621         return COM_FindFile (filename, file, quiet, zip);
1622 }
1623
1624
1625 /*
1626 ============
1627 COM_LoadFile
1628
1629 Filename are reletive to the quake directory.
1630 Always appends a 0 byte.
1631 ============
1632 */
1633 qbyte *loadbuf;
1634 int loadsize;
1635 qbyte *COM_LoadFile (char *path, qboolean quiet)
1636 {
1637         QFile *h;
1638         qbyte *buf;
1639         char base[1024];
1640         int len;
1641
1642         buf = NULL;     // quiet compiler warning
1643         loadsize = 0;
1644
1645 // look for it in the filesystem or pack files
1646         len = COM_FOpenFile (path, &h, quiet, true);
1647         if (!h)
1648                 return NULL;
1649
1650         loadsize = len;
1651
1652 // extract the filename base name for hunk tag
1653         COM_FileBase (path, base);
1654
1655         buf = Mem_Alloc(tempmempool, len+1);
1656         if (!buf)
1657                 Sys_Error ("COM_LoadFile: not enough available memory for %s (size %i)", path, len);
1658
1659         ((qbyte *)buf)[len] = 0;
1660
1661         Qread (h, buf, len);
1662         Qclose (h);
1663
1664         return buf;
1665 }
1666
1667 /*
1668 =================
1669 COM_LoadPackFile
1670
1671 Takes an explicit (not game tree related) path to a pak file.
1672
1673 Loads the header and directory, adding the files at the beginning
1674 of the list so they override previous pack files.
1675 =================
1676 */
1677 pack_t *COM_LoadPackFile (char *packfile)
1678 {
1679         dpackheader_t   header;
1680         int                             i;
1681         int                             numpackfiles;
1682         pack_t                  *pack;
1683         int                             packhandle;
1684         // LordHavoc: changed from stack array to temporary alloc, allowing huge pack directories
1685         dpackfile_t             *info;
1686
1687         if (Sys_FileOpenRead (packfile, &packhandle) == -1)
1688         {
1689                 //Con_Printf ("Couldn't open %s\n", packfile);
1690                 return NULL;
1691         }
1692         Sys_FileRead (packhandle, (void *)&header, sizeof(header));
1693         if (memcmp(header.id, "PACK", 4))
1694                 Sys_Error ("%s is not a packfile", packfile);
1695         header.dirofs = LittleLong (header.dirofs);
1696         header.dirlen = LittleLong (header.dirlen);
1697
1698         if (header.dirlen % sizeof(dpackfile_t))
1699                 Sys_Error ("%s has an invalid directory size", packfile);
1700
1701         numpackfiles = header.dirlen / sizeof(dpackfile_t);
1702
1703         if (numpackfiles > MAX_FILES_IN_PACK)
1704                 Sys_Error ("%s has %i files", packfile, numpackfiles);
1705
1706         pack = Mem_Alloc(pak_mempool, sizeof (pack_t));
1707         strcpy (pack->filename, packfile);
1708         pack->handle = packhandle;
1709         pack->numfiles = numpackfiles;
1710         pack->mempool = Mem_AllocPool(packfile);
1711         pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t));
1712         pack->next = packlist;
1713         packlist = pack;
1714
1715         info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles);
1716         Sys_FileSeek (packhandle, header.dirofs);
1717         Sys_FileRead (packhandle, (void *)info, header.dirlen);
1718
1719 // parse the directory
1720         for (i = 0;i < numpackfiles;i++)
1721         {
1722                 strcpy (pack->files[i].name, info[i].name);
1723                 pack->files[i].filepos = LittleLong(info[i].filepos);
1724                 pack->files[i].filelen = LittleLong(info[i].filelen);
1725         }
1726
1727         Mem_Free(info);
1728
1729         Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
1730         return pack;
1731 }
1732
1733
1734 /*
1735 ================
1736 COM_AddGameDirectory
1737
1738 Sets com_gamedir, adds the directory to the head of the path,
1739 then loads and adds pak1.pak pak2.pak ...
1740 ================
1741 */
1742 void COM_AddGameDirectory (char *dir)
1743 {
1744         int                             i;
1745         searchpath_t    *search;
1746         pack_t                  *pak;
1747         char                    pakfile[MAX_OSPATH];
1748
1749         strcpy (com_gamedir, dir);
1750
1751 //
1752 // add the directory to the search path
1753 //
1754         search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
1755         strcpy (search->filename, dir);
1756         search->next = com_searchpaths;
1757         com_searchpaths = search;
1758
1759 //
1760 // add any pak files in the format pak0.pak pak1.pak, ...
1761 //
1762         for (i=0 ; ; i++)
1763         {
1764                 sprintf (pakfile, "%s/pak%i.pak", dir, i);
1765                 pak = COM_LoadPackFile (pakfile);
1766                 if (!pak)
1767                         break;
1768                 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
1769                 search->pack = pak;
1770                 search->next = com_searchpaths;
1771                 com_searchpaths = search;
1772         }
1773
1774 //
1775 // add the contents of the parms.txt file to the end of the command line
1776 //
1777
1778 }
1779
1780 /*
1781 ================
1782 COM_InitFilesystem
1783 ================
1784 */
1785 void COM_InitFilesystem (void)
1786 {
1787         int             i, j;
1788         char    basedir[MAX_OSPATH];
1789         searchpath_t    *search;
1790
1791 //
1792 // -basedir <path>
1793 // Overrides the system supplied base directory (under GAMENAME)
1794 //
1795         i = COM_CheckParm ("-basedir");
1796         if (i && i < com_argc-1)
1797                 strcpy (basedir, com_argv[i+1]);
1798         else
1799                 strcpy (basedir, host_parms.basedir);
1800
1801         j = strlen (basedir);
1802
1803         if (j > 0)
1804         {
1805                 if ((basedir[j-1] == '\\') || (basedir[j-1] == '/'))
1806                         basedir[j-1] = 0;
1807         }
1808
1809 #if CACHEENABLE
1810 //
1811 // -cachedir <path>
1812 // Overrides the system supplied cache directory (NULL or /qcache)
1813 // -cachedir - will disable caching.
1814 //
1815         i = COM_CheckParm ("-cachedir");
1816         if (i && i < com_argc-1)
1817         {
1818                 if (com_argv[i+1][0] == '-')
1819                         com_cachedir[0] = 0;
1820                 else
1821                         strcpy (com_cachedir, com_argv[i+1]);
1822         }
1823         else if (host_parms.cachedir)
1824                 strcpy (com_cachedir, host_parms.cachedir);
1825         else
1826                 com_cachedir[0] = 0;
1827 #endif
1828
1829 // start up with GAMENAME by default (id1)
1830         COM_AddGameDirectory (va("%s/"GAMENAME, basedir) );
1831
1832         switch(gamemode)
1833         {
1834         case GAME_NORMAL:
1835                 break;
1836         case GAME_HIPNOTIC:
1837                 COM_AddGameDirectory (va("%s/hipnotic", basedir) );
1838                 break;
1839         case GAME_ROGUE:
1840                 COM_AddGameDirectory (va("%s/rogue", basedir) );
1841                 break;
1842         case GAME_NEHAHRA:
1843                 COM_AddGameDirectory (va("%s/nehahra", basedir) );
1844                 break;
1845         case GAME_FIENDARENA:
1846                 COM_AddGameDirectory (va("%s/fiendarena", basedir) );
1847                 break;
1848         case GAME_ZYMOTIC:
1849                 COM_AddGameDirectory (va("%s/zymotic", basedir) );
1850                 break;
1851         default:
1852                 Sys_Error("COM_InitFilesystem: unknown gamemode %i\n", gamemode);
1853                 break;
1854         }
1855
1856 //
1857 // -game <gamedir>
1858 // Adds basedir/gamedir as an override game
1859 //
1860         i = COM_CheckParm ("-game");
1861         if (i && i < com_argc-1)
1862         {
1863                 com_modified = true;
1864                 COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1]));
1865         }
1866
1867 //
1868 // -path <dir or packfile> [<dir or packfile>] ...
1869 // Fully specifies the exact search path, overriding the generated one
1870 //
1871         i = COM_CheckParm ("-path");
1872         if (i)
1873         {
1874                 com_modified = true;
1875                 com_searchpaths = NULL;
1876                 while (++i < com_argc)
1877                 {
1878                         if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
1879                                 break;
1880
1881                         search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
1882                         if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
1883                         {
1884                                 search->pack = COM_LoadPackFile (com_argv[i]);
1885                                 if (!search->pack)
1886                                         Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
1887                         }
1888                         else
1889                                 strcpy (search->filename, com_argv[i]);
1890                         search->next = com_searchpaths;
1891                         com_searchpaths = search;
1892                 }
1893         }
1894
1895 //      if (COM_CheckParm ("-proghack"))
1896 //              proghack = true;
1897 }
1898
1899 int COM_FileExists(char *filename)
1900 {
1901         searchpath_t    *search;
1902         char                    netpath[MAX_OSPATH];
1903         pack_t                  *pak;
1904         int                             i;
1905         int                             findtime;
1906
1907         for (search = com_searchpaths;search;search = search->next)
1908         {
1909                 if (search->pack)
1910                 {
1911                         pak = search->pack;
1912                         for (i = 0;i < pak->numfiles;i++)
1913                                 if (!strcmp (pak->files[i].name, filename))
1914                                         return true;
1915                 }
1916                 else
1917                 {
1918                         sprintf (netpath, "%s/%s",search->filename, filename);
1919                         findtime = Sys_FileTime (netpath);
1920                         if (findtime != -1)
1921                                 return true;
1922                 }               
1923         }
1924
1925         return false;
1926 }
1927
1928
1929 //======================================
1930 // LordHavoc: added these because they are useful
1931
1932 void COM_ToLowerString(char *in, char *out)
1933 {
1934         while (*in)
1935         {
1936                 if (*in >= 'A' && *in <= 'Z')
1937                         *out++ = *in++ + 'a' - 'A';
1938                 else
1939                         *out++ = *in++;
1940         }
1941 }
1942
1943 void COM_ToUpperString(char *in, char *out)
1944 {
1945         while (*in)
1946         {
1947                 if (*in >= 'a' && *in <= 'z')
1948                         *out++ = *in++ + 'A' - 'a';
1949                 else
1950                         *out++ = *in++;
1951         }
1952 }