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