|
|
1.1 root 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 <ctype.h>
23:
24: #ifdef SERVERONLY
25: #include "qwsvdef.h"
26: #else
27: #include "quakedef.h"
28: #endif
29:
30: #define MAX_NUM_ARGVS 50
31: #define NUM_SAFE_ARGVS 6
32:
33: usercmd_t nullcmd; // guarenteed to be zero
34:
35: static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
36: static char *argvdummy = " ";
37:
38: static char *safeargvs[NUM_SAFE_ARGVS] =
39: {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse"};
40:
41: cvar_t registered = {"registered","0"};
42:
43: qboolean com_modified; // set true if using non-id files
44:
45: int static_registered = 1; // only for startup check, then set
46:
47: qboolean msg_suppress_1 = 0;
48:
49: void COM_InitFilesystem (void);
50: void COM_Path_f (void);
51:
52:
53: // if a packfile directory differs from this, it is assumed to be hacked
54: #define PAK0_COUNT 339
55: #define PAK0_CRC 52883
56:
57: qboolean standard_quake = true, rogue, hipnotic;
58:
59: char gamedirfile[MAX_OSPATH];
60:
61: // this graphic needs to be in the pak file to use registered features
62: unsigned short pop[] =
63: {
64: 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000
65: ,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000
66: ,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000
67: ,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600
68: ,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563
69: ,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564
70: ,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564
71: ,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563
72: ,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500
73: ,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200
74: ,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000
75: ,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000
76: ,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000
77: ,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000
78: ,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000
79: ,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000
80: };
81:
82: /*
83:
84:
85: 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.
86:
87: 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
88: only used during filesystem initialization.
89:
90: 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.
91:
92: The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines. If there is a cache directory
93: specified, when a file is found by the normal search path, it will be mirrored
94: into the cache directory, then opened there.
95:
96: */
97:
98: //============================================================================
99:
100:
101: // ClearLink is used for new headnodes
102: void ClearLink (link_t *l)
103: {
104: l->prev = l->next = l;
105: }
106:
107: void RemoveLink (link_t *l)
108: {
109: l->next->prev = l->prev;
110: l->prev->next = l->next;
111: }
112:
113: void InsertLinkBefore (link_t *l, link_t *before)
114: {
115: l->next = before;
116: l->prev = before->prev;
117: l->prev->next = l;
118: l->next->prev = l;
119: }
120: void InsertLinkAfter (link_t *l, link_t *after)
121: {
122: l->next = after->next;
123: l->prev = after;
124: l->prev->next = l;
125: l->next->prev = l;
126: }
127:
128: /*
129: ============================================================================
130:
131: LIBRARY REPLACEMENT FUNCTIONS
132:
133: ============================================================================
134: */
135:
136: #if 0
137: void Q_memset (void *dest, int fill, int count)
138: {
139: int i;
140:
141: if ( (((long)dest | count) & 3) == 0)
142: {
143: count >>= 2;
144: fill = fill | (fill<<8) | (fill<<16) | (fill<<24);
145: for (i=0 ; i<count ; i++)
146: ((int *)dest)[i] = fill;
147: }
148: else
149: for (i=0 ; i<count ; i++)
150: ((byte *)dest)[i] = fill;
151: }
152:
153: void Q_memcpy (void *dest, void *src, int count)
154: {
155: int i;
156:
157: if (( ( (long)dest | (long)src | count) & 3) == 0 )
158: {
159: count>>=2;
160: for (i=0 ; i<count ; i++)
161: ((int *)dest)[i] = ((int *)src)[i];
162: }
163: else
164: for (i=0 ; i<count ; i++)
165: ((byte *)dest)[i] = ((byte *)src)[i];
166: }
167:
168: int Q_memcmp (void *m1, void *m2, int count)
169: {
170: while(count)
171: {
172: count--;
173: if (((byte *)m1)[count] != ((byte *)m2)[count])
174: return -1;
175: }
176: return 0;
177: }
178:
179: void Q_strcpy (char *dest, char *src)
180: {
181: while (*src)
182: {
183: *dest++ = *src++;
184: }
185: *dest++ = 0;
186: }
187:
188: void Q_strncpy (char *dest, char *src, int count)
189: {
190: while (*src && count--)
191: {
192: *dest++ = *src++;
193: }
194: if (count)
195: *dest++ = 0;
196: }
197:
198: int Q_strlen (char *str)
199: {
200: int count;
201:
202: count = 0;
203: while (str[count])
204: count++;
205:
206: return count;
207: }
208:
209: char *Q_strrchr(char *s, char c)
210: {
211: int len = Q_strlen(s);
212: s += len;
213: while (len--)
214: if (*--s == c) return s;
215: return 0;
216: }
217:
218: void Q_strcat (char *dest, char *src)
219: {
220: dest += Q_strlen(dest);
221: Q_strcpy (dest, src);
222: }
223:
224: int Q_strcmp (char *s1, char *s2)
225: {
226: while (1)
227: {
228: if (*s1 != *s2)
229: return -1; // strings not equal
230: if (!*s1)
231: return 0; // strings are equal
232: s1++;
233: s2++;
234: }
235:
236: return -1;
237: }
238:
239: int Q_strncmp (char *s1, char *s2, int count)
240: {
241: while (1)
242: {
243: if (!count--)
244: return 0;
245: if (*s1 != *s2)
246: return -1; // strings not equal
247: if (!*s1)
248: return 0; // strings are equal
249: s1++;
250: s2++;
251: }
252:
253: return -1;
254: }
255:
256: int Q_strncasecmp (char *s1, char *s2, int n)
257: {
258: int c1, c2;
259:
260: while (1)
261: {
262: c1 = *s1++;
263: c2 = *s2++;
264:
265: if (!n--)
266: return 0; // strings are equal until end point
267:
268: if (c1 != c2)
269: {
270: if (c1 >= 'a' && c1 <= 'z')
271: c1 -= ('a' - 'A');
272: if (c2 >= 'a' && c2 <= 'z')
273: c2 -= ('a' - 'A');
274: if (c1 != c2)
275: return -1; // strings not equal
276: }
277: if (!c1)
278: return 0; // strings are equal
279: // s1++;
280: // s2++;
281: }
282:
283: return -1;
284: }
285:
286: int Q_strcasecmp (char *s1, char *s2)
287: {
288: return Q_strncasecmp (s1, s2, 99999);
289: }
290:
291: #endif
292:
293: int Q_atoi (char *str)
294: {
295: int val;
296: int sign;
297: int c;
298:
299: if (*str == '-')
300: {
301: sign = -1;
302: str++;
303: }
304: else
305: sign = 1;
306:
307: val = 0;
308:
309: //
310: // check for hex
311: //
312: if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
313: {
314: str += 2;
315: while (1)
316: {
317: c = *str++;
318: if (c >= '0' && c <= '9')
319: val = (val<<4) + c - '0';
320: else if (c >= 'a' && c <= 'f')
321: val = (val<<4) + c - 'a' + 10;
322: else if (c >= 'A' && c <= 'F')
323: val = (val<<4) + c - 'A' + 10;
324: else
325: return val*sign;
326: }
327: }
328:
329: //
330: // check for character
331: //
332: if (str[0] == '\'')
333: {
334: return sign * str[1];
335: }
336:
337: //
338: // assume decimal
339: //
340: while (1)
341: {
342: c = *str++;
343: if (c <'0' || c > '9')
344: return val*sign;
345: val = val*10 + c - '0';
346: }
347:
348: return 0;
349: }
350:
351:
352: float Q_atof (char *str)
353: {
354: double val;
355: int sign;
356: int c;
357: int decimal, total;
358:
359: if (*str == '-')
360: {
361: sign = -1;
362: str++;
363: }
364: else
365: sign = 1;
366:
367: val = 0;
368:
369: //
370: // check for hex
371: //
372: if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
373: {
374: str += 2;
375: while (1)
376: {
377: c = *str++;
378: if (c >= '0' && c <= '9')
379: val = (val*16) + c - '0';
380: else if (c >= 'a' && c <= 'f')
381: val = (val*16) + c - 'a' + 10;
382: else if (c >= 'A' && c <= 'F')
383: val = (val*16) + c - 'A' + 10;
384: else
385: return val*sign;
386: }
387: }
388:
389: //
390: // check for character
391: //
392: if (str[0] == '\'')
393: {
394: return sign * str[1];
395: }
396:
397: //
398: // assume decimal
399: //
400: decimal = -1;
401: total = 0;
402: while (1)
403: {
404: c = *str++;
405: if (c == '.')
406: {
407: decimal = total;
408: continue;
409: }
410: if (c <'0' || c > '9')
411: break;
412: val = val*10 + c - '0';
413: total++;
414: }
415:
416: if (decimal == -1)
417: return val*sign;
418: while (total > decimal)
419: {
420: val /= 10;
421: total--;
422: }
423:
424: return val*sign;
425: }
426:
427: /*
428: ============================================================================
429:
430: BYTE ORDER FUNCTIONS
431:
432: ============================================================================
433: */
434:
435: qboolean bigendien;
436:
437: short (*BigShort) (short l);
438: short (*LittleShort) (short l);
439: int (*BigLong) (int l);
440: int (*LittleLong) (int l);
441: float (*BigFloat) (float l);
442: float (*LittleFloat) (float l);
443:
444: short ShortSwap (short l)
445: {
446: byte b1,b2;
447:
448: b1 = l&255;
449: b2 = (l>>8)&255;
450:
451: return (b1<<8) + b2;
452: }
453:
454: short ShortNoSwap (short l)
455: {
456: return l;
457: }
458:
459: int LongSwap (int l)
460: {
461: byte b1,b2,b3,b4;
462:
463: b1 = l&255;
464: b2 = (l>>8)&255;
465: b3 = (l>>16)&255;
466: b4 = (l>>24)&255;
467:
468: return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
469: }
470:
471: int LongNoSwap (int l)
472: {
473: return l;
474: }
475:
476: float FloatSwap (float f)
477: {
478: union
479: {
480: float f;
481: byte b[4];
482: } dat1, dat2;
483:
484:
485: dat1.f = f;
486: dat2.b[0] = dat1.b[3];
487: dat2.b[1] = dat1.b[2];
488: dat2.b[2] = dat1.b[1];
489: dat2.b[3] = dat1.b[0];
490: return dat2.f;
491: }
492:
493: float FloatNoSwap (float f)
494: {
495: return f;
496: }
497:
498: /*
499: ==============================================================================
500:
501: MESSAGE IO FUNCTIONS
502:
503: Handles byte ordering and avoids alignment errors
504: ==============================================================================
505: */
506:
507: //
508: // writing functions
509: //
510:
511: void MSG_WriteChar (sizebuf_t *sb, int c)
512: {
513: byte *buf;
514:
515: #ifdef PARANOID
516: if (c < -128 || c > 127)
517: Sys_Error ("MSG_WriteChar: range error");
518: #endif
519:
520: buf = SZ_GetSpace (sb, 1);
521: buf[0] = c;
522: }
523:
524: void MSG_WriteByte (sizebuf_t *sb, int c)
525: {
526: byte *buf;
527:
528: #ifdef PARANOID
529: if (c < 0 || c > 255)
530: Sys_Error ("MSG_WriteByte: range error");
531: #endif
532:
533: buf = SZ_GetSpace (sb, 1);
534: buf[0] = c;
535: }
536:
537: void MSG_WriteShort (sizebuf_t *sb, int c)
538: {
539: byte *buf;
540:
541: #ifdef PARANOID
542: if (c < ((short)0x8000) || c > (short)0x7fff)
543: Sys_Error ("MSG_WriteShort: range error");
544: #endif
545:
546: buf = SZ_GetSpace (sb, 2);
547: buf[0] = c&0xff;
548: buf[1] = c>>8;
549: }
550:
551: void MSG_WriteLong (sizebuf_t *sb, int c)
552: {
553: byte *buf;
554:
555: buf = SZ_GetSpace (sb, 4);
556: buf[0] = c&0xff;
557: buf[1] = (c>>8)&0xff;
558: buf[2] = (c>>16)&0xff;
559: buf[3] = c>>24;
560: }
561:
562: void MSG_WriteFloat (sizebuf_t *sb, float f)
563: {
564: union
565: {
566: float f;
567: int l;
568: } dat;
569:
570:
571: dat.f = f;
572: dat.l = LittleLong (dat.l);
573:
574: SZ_Write (sb, &dat.l, 4);
575: }
576:
577: void MSG_WriteString (sizebuf_t *sb, char *s)
578: {
579: if (!s)
580: SZ_Write (sb, "", 1);
581: else
582: SZ_Write (sb, s, Q_strlen(s)+1);
583: }
584:
585: void MSG_WriteCoord (sizebuf_t *sb, float f)
586: {
587: MSG_WriteShort (sb, (int)(f*8));
588: }
589:
590: void MSG_WriteAngle (sizebuf_t *sb, float f)
591: {
592: MSG_WriteByte (sb, (int)(f*256/360) & 255);
593: }
594:
595: void MSG_WriteAngle16 (sizebuf_t *sb, float f)
596: {
597: MSG_WriteShort (sb, (int)(f*65536/360) & 65535);
598: }
599:
600: void MSG_WriteDeltaUsercmd (sizebuf_t *buf, usercmd_t *from, usercmd_t *cmd)
601: {
602: int bits;
603:
604: //
605: // send the movement message
606: //
607: bits = 0;
608: if (cmd->angles[0] != from->angles[0])
609: bits |= CM_ANGLE1;
610: if (cmd->angles[1] != from->angles[1])
611: bits |= CM_ANGLE2;
612: if (cmd->angles[2] != from->angles[2])
613: bits |= CM_ANGLE3;
614: if (cmd->forwardmove != from->forwardmove)
615: bits |= CM_FORWARD;
616: if (cmd->sidemove != from->sidemove)
617: bits |= CM_SIDE;
618: if (cmd->upmove != from->upmove)
619: bits |= CM_UP;
620: if (cmd->buttons != from->buttons)
621: bits |= CM_BUTTONS;
622: if (cmd->impulse != from->impulse)
623: bits |= CM_IMPULSE;
624:
625: MSG_WriteByte (buf, bits);
626:
627: if (bits & CM_ANGLE1)
628: MSG_WriteAngle16 (buf, cmd->angles[0]);
629: if (bits & CM_ANGLE2)
630: MSG_WriteAngle16 (buf, cmd->angles[1]);
631: if (bits & CM_ANGLE3)
632: MSG_WriteAngle16 (buf, cmd->angles[2]);
633:
634: if (bits & CM_FORWARD)
635: MSG_WriteShort (buf, cmd->forwardmove);
636: if (bits & CM_SIDE)
637: MSG_WriteShort (buf, cmd->sidemove);
638: if (bits & CM_UP)
639: MSG_WriteShort (buf, cmd->upmove);
640:
641: if (bits & CM_BUTTONS)
642: MSG_WriteByte (buf, cmd->buttons);
643: if (bits & CM_IMPULSE)
644: MSG_WriteByte (buf, cmd->impulse);
645: MSG_WriteByte (buf, cmd->msec);
646: }
647:
648:
649: //
650: // reading functions
651: //
652: int msg_readcount;
653: qboolean msg_badread;
654:
655: void MSG_BeginReading (void)
656: {
657: msg_readcount = 0;
658: msg_badread = false;
659: }
660:
661: int MSG_GetReadCount(void)
662: {
663: return msg_readcount;
664: }
665:
666: // returns -1 and sets msg_badread if no more characters are available
667: int MSG_ReadChar (void)
668: {
669: int c;
670:
671: if (msg_readcount+1 > net_message.cursize)
672: {
673: msg_badread = true;
674: return -1;
675: }
676:
677: c = (signed char)net_message.data[msg_readcount];
678: msg_readcount++;
679:
680: return c;
681: }
682:
683: int MSG_ReadByte (void)
684: {
685: int c;
686:
687: if (msg_readcount+1 > net_message.cursize)
688: {
689: msg_badread = true;
690: return -1;
691: }
692:
693: c = (unsigned char)net_message.data[msg_readcount];
694: msg_readcount++;
695:
696: return c;
697: }
698:
699: int MSG_ReadShort (void)
700: {
701: int c;
702:
703: if (msg_readcount+2 > net_message.cursize)
704: {
705: msg_badread = true;
706: return -1;
707: }
708:
709: c = (short)(net_message.data[msg_readcount]
710: + (net_message.data[msg_readcount+1]<<8));
711:
712: msg_readcount += 2;
713:
714: return c;
715: }
716:
717: int MSG_ReadLong (void)
718: {
719: int c;
720:
721: if (msg_readcount+4 > net_message.cursize)
722: {
723: msg_badread = true;
724: return -1;
725: }
726:
727: c = net_message.data[msg_readcount]
728: + (net_message.data[msg_readcount+1]<<8)
729: + (net_message.data[msg_readcount+2]<<16)
730: + (net_message.data[msg_readcount+3]<<24);
731:
732: msg_readcount += 4;
733:
734: return c;
735: }
736:
737: float MSG_ReadFloat (void)
738: {
739: union
740: {
741: byte b[4];
742: float f;
743: int l;
744: } dat;
745:
746: dat.b[0] = net_message.data[msg_readcount];
747: dat.b[1] = net_message.data[msg_readcount+1];
748: dat.b[2] = net_message.data[msg_readcount+2];
749: dat.b[3] = net_message.data[msg_readcount+3];
750: msg_readcount += 4;
751:
752: dat.l = LittleLong (dat.l);
753:
754: return dat.f;
755: }
756:
757: char *MSG_ReadString (void)
758: {
759: static char string[2048];
760: int l,c;
761:
762: l = 0;
763: do
764: {
765: c = MSG_ReadChar ();
766: if (c == -1 || c == 0)
767: break;
768: string[l] = c;
769: l++;
770: } while (l < sizeof(string)-1);
771:
772: string[l] = 0;
773:
774: return string;
775: }
776:
777: char *MSG_ReadStringLine (void)
778: {
779: static char string[2048];
780: int l,c;
781:
782: l = 0;
783: do
784: {
785: c = MSG_ReadChar ();
786: if (c == -1 || c == 0 || c == '\n')
787: break;
788: string[l] = c;
789: l++;
790: } while (l < sizeof(string)-1);
791:
792: string[l] = 0;
793:
794: return string;
795: }
796:
797: float MSG_ReadCoord (void)
798: {
799: return MSG_ReadShort() * (1.0/8);
800: }
801:
802: float MSG_ReadAngle (void)
803: {
804: return MSG_ReadChar() * (360.0/256);
805: }
806:
807: float MSG_ReadAngle16 (void)
808: {
809: return MSG_ReadShort() * (360.0/65536);
810: }
811:
812: void MSG_ReadDeltaUsercmd (usercmd_t *from, usercmd_t *move)
813: {
814: int bits;
815:
816: memcpy (move, from, sizeof(*move));
817:
818: bits = MSG_ReadByte ();
819:
820: // read current angles
821: if (bits & CM_ANGLE1)
822: move->angles[0] = MSG_ReadAngle16 ();
823: if (bits & CM_ANGLE2)
824: move->angles[1] = MSG_ReadAngle16 ();
825: if (bits & CM_ANGLE3)
826: move->angles[2] = MSG_ReadAngle16 ();
827:
828: // read movement
829: if (bits & CM_FORWARD)
830: move->forwardmove = MSG_ReadShort ();
831: if (bits & CM_SIDE)
832: move->sidemove = MSG_ReadShort ();
833: if (bits & CM_UP)
834: move->upmove = MSG_ReadShort ();
835:
836: // read buttons
837: if (bits & CM_BUTTONS)
838: move->buttons = MSG_ReadByte ();
839:
840: if (bits & CM_IMPULSE)
841: move->impulse = MSG_ReadByte ();
842:
843: // read time to run command
844: move->msec = MSG_ReadByte ();
845: }
846:
847:
848: //===========================================================================
849:
850: void SZ_Clear (sizebuf_t *buf)
851: {
852: buf->cursize = 0;
853: buf->overflowed = false;
854: }
855:
856: void *SZ_GetSpace (sizebuf_t *buf, int length)
857: {
858: void *data;
859:
860: if (buf->cursize + length > buf->maxsize)
861: {
862: if (!buf->allowoverflow)
863: Sys_Error ("SZ_GetSpace: overflow without allowoverflow set (%d)", buf->maxsize);
864:
865: if (length > buf->maxsize)
866: Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);
867:
868: Sys_Printf ("SZ_GetSpace: overflow\n"); // because Con_Printf may be redirected
869: SZ_Clear (buf);
870: buf->overflowed = true;
871: }
872:
873: data = buf->data + buf->cursize;
874: buf->cursize += length;
875:
876: return data;
877: }
878:
879: void SZ_Write (sizebuf_t *buf, void *data, int length)
880: {
881: Q_memcpy (SZ_GetSpace(buf,length),data,length);
882: }
883:
884: void SZ_Print (sizebuf_t *buf, char *data)
885: {
886: int len;
887:
888: len = Q_strlen(data)+1;
889:
890: if (!buf->cursize || buf->data[buf->cursize-1])
891: Q_memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
892: else
893: Q_memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
894: }
895:
896:
897: //============================================================================
898:
899:
900: /*
901: ============
902: COM_SkipPath
903: ============
904: */
905: char *COM_SkipPath (char *pathname)
906: {
907: char *last;
908:
909: last = pathname;
910: while (*pathname)
911: {
912: if (*pathname=='/')
913: last = pathname+1;
914: pathname++;
915: }
916: return last;
917: }
918:
919: /*
920: ============
921: COM_StripExtension
922: ============
923: */
924: void COM_StripExtension (char *in, char *out)
925: {
926: while (*in && *in != '.')
927: *out++ = *in++;
928: *out = 0;
929: }
930:
931: /*
932: ============
933: COM_FileExtension
934: ============
935: */
936: char *COM_FileExtension (char *in)
937: {
938: static char exten[8];
939: int i;
940:
941: while (*in && *in != '.')
942: in++;
943: if (!*in)
944: return "";
945: in++;
946: for (i=0 ; i<7 && *in ; i++,in++)
947: exten[i] = *in;
948: exten[i] = 0;
949: return exten;
950: }
951:
952: /*
953: ============
954: COM_FileBase
955: ============
956: */
957: void COM_FileBase (char *in, char *out)
958: {
959: char *s, *s2;
960:
961: s = in + strlen(in) - 1;
962:
963: while (s != in && *s != '.')
964: s--;
965:
966: for (s2 = s ; *s2 && *s2 != '/' ; s2--)
967: ;
968:
969: if (s-s2 < 2)
970: strcpy (out,"?model?");
971: else
972: {
973: s--;
974: strncpy (out,s2+1, s-s2);
975: out[s-s2] = 0;
976: }
977: }
978:
979:
980: /*
981: ==================
982: COM_DefaultExtension
983: ==================
984: */
985: void COM_DefaultExtension (char *path, char *extension)
986: {
987: char *src;
988: //
989: // if path doesn't have a .EXT, append extension
990: // (extension should include the .)
991: //
992: src = path + strlen(path) - 1;
993:
994: while (*src != '/' && src != path)
995: {
996: if (*src == '.')
997: return; // it has an extension
998: src--;
999: }
1000:
1001: strcat (path, extension);
1002: }
1003:
1004: //============================================================================
1005:
1006: char com_token[1024];
1007: int com_argc;
1008: char **com_argv;
1009:
1010:
1011: /*
1012: ==============
1013: COM_Parse
1014:
1015: Parse a token out of a string
1016: ==============
1017: */
1018: char *COM_Parse (char *data)
1019: {
1020: int c;
1021: int len;
1022:
1023: len = 0;
1024: com_token[0] = 0;
1025:
1026: if (!data)
1027: return NULL;
1028:
1029: // skip whitespace
1030: skipwhite:
1031: while ( (c = *data) <= ' ')
1032: {
1033: if (c == 0)
1034: return NULL; // end of file;
1035: data++;
1036: }
1037:
1038: // skip // comments
1039: if (c=='/' && data[1] == '/')
1040: {
1041: while (*data && *data != '\n')
1042: data++;
1043: goto skipwhite;
1044: }
1045:
1046:
1047: // handle quoted strings specially
1048: if (c == '\"')
1049: {
1050: data++;
1051: while (1)
1052: {
1053: c = *data++;
1054: if (c=='\"' || !c)
1055: {
1056: com_token[len] = 0;
1057: return data;
1058: }
1059: com_token[len] = c;
1060: len++;
1061: }
1062: }
1063:
1064: // parse a regular word
1065: do
1066: {
1067: com_token[len] = c;
1068: data++;
1069: len++;
1070: c = *data;
1071: } while (c>32);
1072:
1073: com_token[len] = 0;
1074: return data;
1075: }
1076:
1077:
1078: /*
1079: ================
1080: COM_CheckParm
1081:
1082: Returns the position (1 to argc-1) in the program's argument list
1083: where the given parameter apears, or 0 if not present
1084: ================
1085: */
1086: int COM_CheckParm (char *parm)
1087: {
1088: int i;
1089:
1090: for (i=1 ; i<com_argc ; i++)
1091: {
1092: if (!com_argv[i])
1093: continue; // NEXTSTEP sometimes clears appkit vars.
1094: if (!Q_strcmp (parm,com_argv[i]))
1095: return i;
1096: }
1097:
1098: return 0;
1099: }
1100:
1101: /*
1102: ================
1103: COM_CheckRegistered
1104:
1105: Looks for the pop.txt file and verifies it.
1106: Sets the "registered" cvar.
1107: Immediately exits out if an alternate game was attempted to be started without
1108: being registered.
1109: ================
1110: */
1111: void COM_CheckRegistered (void)
1112: {
1113: FILE *h;
1114: unsigned short check[128];
1115: int i;
1116:
1117: COM_FOpenFile("gfx/pop.lmp", &h);
1118: static_registered = 0;
1119:
1120: if (!h)
1121: {
1122: Con_Printf ("Playing shareware version.\n");
1123: #ifndef SERVERONLY
1124: // FIXME DEBUG -- only temporary
1125: if (com_modified)
1126: Sys_Error ("You must have the registered version to play QuakeWorld");
1127: #endif
1128: return;
1129: }
1130:
1131: fread (check, 1, sizeof(check), h);
1132: fclose (h);
1133:
1134: for (i=0 ; i<128 ; i++)
1135: if (pop[i] != (unsigned short)BigShort (check[i]))
1136: Sys_Error ("Corrupted data file.");
1137:
1138: Cvar_Set ("registered", "1");
1139: static_registered = 1;
1140: Con_Printf ("Playing registered version.\n");
1141: }
1142:
1143:
1144:
1145: /*
1146: ================
1147: COM_InitArgv
1148: ================
1149: */
1150: void COM_InitArgv (int argc, char **argv)
1151: {
1152: qboolean safe;
1153: int i;
1154:
1155: safe = false;
1156:
1157: for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;
1158: com_argc++)
1159: {
1160: largv[com_argc] = argv[com_argc];
1161: if (!Q_strcmp ("-safe", argv[com_argc]))
1162: safe = true;
1163: }
1164:
1165: if (safe)
1166: {
1167: // force all the safe-mode switches. Note that we reserved extra space in
1168: // case we need to add these, so we don't need an overflow check
1169: for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
1170: {
1171: largv[com_argc] = safeargvs[i];
1172: com_argc++;
1173: }
1174: }
1175:
1176: largv[com_argc] = argvdummy;
1177: com_argv = largv;
1178: }
1179:
1180: /*
1181: ================
1182: COM_AddParm
1183:
1184: Adds the given string at the end of the current argument list
1185: ================
1186: */
1187: void COM_AddParm (char *parm)
1188: {
1189: largv[com_argc++] = parm;
1190: }
1191:
1192:
1193: /*
1194: ================
1195: COM_Init
1196: ================
1197: */
1198: void COM_Init (void)
1199: {
1200: byte swaptest[2] = {1,0};
1201:
1202: // set the byte swapping variables in a portable manner
1203: if ( *(short *)swaptest == 1)
1204: {
1205: bigendien = false;
1206: BigShort = ShortSwap;
1207: LittleShort = ShortNoSwap;
1208: BigLong = LongSwap;
1209: LittleLong = LongNoSwap;
1210: BigFloat = FloatSwap;
1211: LittleFloat = FloatNoSwap;
1212: }
1213: else
1214: {
1215: bigendien = true;
1216: BigShort = ShortNoSwap;
1217: LittleShort = ShortSwap;
1218: BigLong = LongNoSwap;
1219: LittleLong = LongSwap;
1220: BigFloat = FloatNoSwap;
1221: LittleFloat = FloatSwap;
1222: }
1223:
1224: Cvar_RegisterVariable (®istered);
1225: Cmd_AddCommand ("path", COM_Path_f);
1226:
1227: COM_InitFilesystem ();
1228: COM_CheckRegistered ();
1229: }
1230:
1231:
1232: /*
1233: ============
1234: va
1235:
1236: does a varargs printf into a temp buffer, so I don't need to have
1237: varargs versions of all text functions.
1238: FIXME: make this buffer size safe someday
1239: ============
1240: */
1241: char *va(char *format, ...)
1242: {
1243: va_list argptr;
1244: static char string[1024];
1245:
1246: va_start (argptr, format);
1247: vsprintf (string, format,argptr);
1248: va_end (argptr);
1249:
1250: return string;
1251: }
1252:
1253:
1254: /// just for debugging
1255: int memsearch (byte *start, int count, int search)
1256: {
1257: int i;
1258:
1259: for (i=0 ; i<count ; i++)
1260: if (start[i] == search)
1261: return i;
1262: return -1;
1263: }
1264:
1265: /*
1266: =============================================================================
1267:
1268: QUAKE FILESYSTEM
1269:
1270: =============================================================================
1271: */
1272:
1273: int com_filesize;
1274:
1275:
1276: //
1277: // in memory
1278: //
1279:
1280: typedef struct
1281: {
1282: char name[MAX_QPATH];
1283: int filepos, filelen;
1284: } packfile_t;
1285:
1286: typedef struct pack_s
1287: {
1288: char filename[MAX_OSPATH];
1289: FILE *handle;
1290: int numfiles;
1291: packfile_t *files;
1292: } pack_t;
1293:
1294: //
1295: // on disk
1296: //
1297: typedef struct
1298: {
1299: char name[56];
1300: int filepos, filelen;
1301: } dpackfile_t;
1302:
1303: typedef struct
1304: {
1305: char id[4];
1306: int dirofs;
1307: int dirlen;
1308: } dpackheader_t;
1309:
1310: #define MAX_FILES_IN_PACK 2048
1311:
1312: char com_gamedir[MAX_OSPATH];
1313: char com_basedir[MAX_OSPATH];
1314:
1315: typedef struct searchpath_s
1316: {
1317: char filename[MAX_OSPATH];
1318: pack_t *pack; // only one of filename / pack will be used
1319: struct searchpath_s *next;
1320: } searchpath_t;
1321:
1322: searchpath_t *com_searchpaths;
1323: searchpath_t *com_base_searchpaths; // without gamedirs
1324:
1325: /*
1326: ================
1327: COM_filelength
1328: ================
1329: */
1330: int COM_filelength (FILE *f)
1331: {
1332: int pos;
1333: int end;
1334:
1335: pos = ftell (f);
1336: fseek (f, 0, SEEK_END);
1337: end = ftell (f);
1338: fseek (f, pos, SEEK_SET);
1339:
1340: return end;
1341: }
1342:
1343: int COM_FileOpenRead (char *path, FILE **hndl)
1344: {
1345: FILE *f;
1346:
1347: f = fopen(path, "rb");
1348: if (!f)
1349: {
1350: *hndl = NULL;
1351: return -1;
1352: }
1353: *hndl = f;
1354:
1355: return COM_filelength(f);
1356: }
1357:
1358: /*
1359: ============
1360: COM_Path_f
1361:
1362: ============
1363: */
1364: void COM_Path_f (void)
1365: {
1366: searchpath_t *s;
1367:
1368: Con_Printf ("Current search path:\n");
1369: for (s=com_searchpaths ; s ; s=s->next)
1370: {
1371: if (s == com_base_searchpaths)
1372: Con_Printf ("----------\n");
1373: if (s->pack)
1374: Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
1375: else
1376: Con_Printf ("%s\n", s->filename);
1377: }
1378: }
1379:
1380: /*
1381: ============
1382: COM_WriteFile
1383:
1384: The filename will be prefixed by the current game directory
1385: ============
1386: */
1387: void COM_WriteFile (char *filename, void *data, int len)
1388: {
1389: FILE *f;
1390: char name[MAX_OSPATH];
1391:
1392: sprintf (name, "%s/%s", com_gamedir, filename);
1393:
1394: f = fopen (name, "wb");
1395: if (!f) {
1396: Sys_mkdir(com_gamedir);
1397: f = fopen (name, "wb");
1398: if (!f)
1399: Sys_Error ("Error opening %s", filename);
1400: }
1401:
1402: Sys_Printf ("COM_WriteFile: %s\n", name);
1403: fwrite (data, 1, len, f);
1404: fclose (f);
1405: }
1406:
1407:
1408: /*
1409: ============
1410: COM_CreatePath
1411:
1412: Only used for CopyFile and download
1413: ============
1414: */
1415: void COM_CreatePath (char *path)
1416: {
1417: char *ofs;
1418:
1419: for (ofs = path+1 ; *ofs ; ofs++)
1420: {
1421: if (*ofs == '/')
1422: { // create the directory
1423: *ofs = 0;
1424: Sys_mkdir (path);
1425: *ofs = '/';
1426: }
1427: }
1428: }
1429:
1430:
1431: /*
1432: ===========
1433: COM_CopyFile
1434:
1435: Copies a file over from the net to the local cache, creating any directories
1436: needed. This is for the convenience of developers using ISDN from home.
1437: ===========
1438: */
1439: void COM_CopyFile (char *netpath, char *cachepath)
1440: {
1441: FILE *in, *out;
1442: int remaining, count;
1443: char buf[4096];
1444:
1445: remaining = COM_FileOpenRead (netpath, &in);
1446: COM_CreatePath (cachepath); // create directories up to the cache file
1447: out = fopen(cachepath, "wb");
1448: if (!out)
1449: Sys_Error ("Error opening %s", cachepath);
1450:
1451: while (remaining)
1452: {
1453: if (remaining < sizeof(buf))
1454: count = remaining;
1455: else
1456: count = sizeof(buf);
1457: fread (buf, 1, count, in);
1458: fwrite (buf, 1, count, out);
1459: remaining -= count;
1460: }
1461:
1462: fclose (in);
1463: fclose (out);
1464: }
1465:
1466: /*
1467: ===========
1468: COM_FindFile
1469:
1470: Finds the file in the search path.
1471: Sets com_filesize and one of handle or file
1472: ===========
1473: */
1474: int file_from_pak; // global indicating file came from pack file ZOID
1475:
1476: int COM_FOpenFile (char *filename, FILE **file)
1477: {
1478: searchpath_t *search;
1479: char netpath[MAX_OSPATH];
1480: pack_t *pak;
1481: int i;
1482: int findtime;
1483:
1484: file_from_pak = 0;
1485:
1486: //
1487: // search through the path, one element at a time
1488: //
1489: for (search = com_searchpaths ; search ; search = search->next)
1490: {
1491: // is the element a pak file?
1492: if (search->pack)
1493: {
1494: // look through all the pak file elements
1495: pak = search->pack;
1496: for (i=0 ; i<pak->numfiles ; i++)
1497: if (!strcmp (pak->files[i].name, filename))
1498: { // found it!
1499: Sys_Printf ("PackFile: %s : %s\n",pak->filename, filename);
1500: // open a new file on the pakfile
1501: *file = fopen (pak->filename, "rb");
1502: if (!*file)
1503: Sys_Error ("Couldn't reopen %s", pak->filename);
1504: fseek (*file, pak->files[i].filepos, SEEK_SET);
1505: com_filesize = pak->files[i].filelen;
1506: file_from_pak = 1;
1507: return com_filesize;
1508: }
1509: }
1510: else
1511: {
1512: // check a file in the directory tree
1513: if (!static_registered)
1514: { // if not a registered version, don't ever go beyond base
1515: if ( strchr (filename, '/') || strchr (filename,'\\'))
1516: continue;
1517: }
1518:
1519: sprintf (netpath, "%s/%s",search->filename, filename);
1520:
1521: findtime = Sys_FileTime (netpath);
1522: if (findtime == -1)
1523: continue;
1524:
1525: Sys_Printf ("FindFile: %s\n",netpath);
1526:
1527: *file = fopen (netpath, "rb");
1528: return COM_filelength (*file);
1529: }
1530:
1531: }
1532:
1533: Sys_Printf ("FindFile: can't find %s\n", filename);
1534:
1535: *file = NULL;
1536: com_filesize = -1;
1537: return -1;
1538: }
1539:
1540: /*
1541: ============
1542: COM_LoadFile
1543:
1544: Filename are reletive to the quake directory.
1545: Allways appends a 0 byte to the loaded data.
1546: ============
1547: */
1548: cache_user_t *loadcache;
1549: byte *loadbuf;
1550: int loadsize;
1551: byte *COM_LoadFile (char *path, int usehunk)
1552: {
1553: FILE *h;
1554: byte *buf;
1555: char base[32];
1556: int len;
1557:
1558: buf = NULL; // quiet compiler warning
1559:
1560: // look for it in the filesystem or pack files
1561: len = com_filesize = COM_FOpenFile (path, &h);
1562: if (!h)
1563: return NULL;
1564:
1565: // extract the filename base name for hunk tag
1566: COM_FileBase (path, base);
1567:
1568: if (usehunk == 1)
1569: buf = Hunk_AllocName (len+1, base);
1570: else if (usehunk == 2)
1571: buf = Hunk_TempAlloc (len+1);
1572: else if (usehunk == 0)
1573: buf = Z_Malloc (len+1);
1574: else if (usehunk == 3)
1575: buf = Cache_Alloc (loadcache, len+1, base);
1576: else if (usehunk == 4)
1577: {
1578: if (len+1 > loadsize)
1579: buf = Hunk_TempAlloc (len+1);
1580: else
1581: buf = loadbuf;
1582: }
1583: else
1584: Sys_Error ("COM_LoadFile: bad usehunk");
1585:
1586: if (!buf)
1587: Sys_Error ("COM_LoadFile: not enough space for %s", path);
1588:
1589: ((byte *)buf)[len] = 0;
1590: #ifndef SERVERONLY
1591: Draw_BeginDisc ();
1592: #endif
1593: fread (buf, 1, len, h);
1594: fclose (h);
1595: #ifndef SERVERONLY
1596: Draw_EndDisc ();
1597: #endif
1598:
1599: return buf;
1600: }
1601:
1602: byte *COM_LoadHunkFile (char *path)
1603: {
1604: return COM_LoadFile (path, 1);
1605: }
1606:
1607: byte *COM_LoadTempFile (char *path)
1608: {
1609: return COM_LoadFile (path, 2);
1610: }
1611:
1612: void COM_LoadCacheFile (char *path, struct cache_user_s *cu)
1613: {
1614: loadcache = cu;
1615: COM_LoadFile (path, 3);
1616: }
1617:
1618: // uses temp hunk if larger than bufsize
1619: byte *COM_LoadStackFile (char *path, void *buffer, int bufsize)
1620: {
1621: byte *buf;
1622:
1623: loadbuf = (byte *)buffer;
1624: loadsize = bufsize;
1625: buf = COM_LoadFile (path, 4);
1626:
1627: return buf;
1628: }
1629:
1630: /*
1631: =================
1632: COM_LoadPackFile
1633:
1634: Takes an explicit (not game tree related) path to a pak file.
1635:
1636: Loads the header and directory, adding the files at the beginning
1637: of the list so they override previous pack files.
1638: =================
1639: */
1640: pack_t *COM_LoadPackFile (char *packfile)
1641: {
1642: dpackheader_t header;
1643: int i;
1644: packfile_t *newfiles;
1645: int numpackfiles;
1646: pack_t *pack;
1647: FILE *packhandle;
1648: dpackfile_t info[MAX_FILES_IN_PACK];
1649: unsigned short crc;
1650:
1651: if (COM_FileOpenRead (packfile, &packhandle) == -1)
1652: return NULL;
1653:
1654: fread (&header, 1, sizeof(header), packhandle);
1655: if (header.id[0] != 'P' || header.id[1] != 'A'
1656: || header.id[2] != 'C' || header.id[3] != 'K')
1657: Sys_Error ("%s is not a packfile", packfile);
1658: header.dirofs = LittleLong (header.dirofs);
1659: header.dirlen = LittleLong (header.dirlen);
1660:
1661: numpackfiles = header.dirlen / sizeof(dpackfile_t);
1662:
1663: if (numpackfiles > MAX_FILES_IN_PACK)
1664: Sys_Error ("%s has %i files", packfile, numpackfiles);
1665:
1666: if (numpackfiles != PAK0_COUNT)
1667: com_modified = true; // not the original file
1668:
1669: newfiles = Z_Malloc (numpackfiles * sizeof(packfile_t));
1670:
1671: fseek (packhandle, header.dirofs, SEEK_SET);
1672: fread (&info, 1, header.dirlen, packhandle);
1673:
1674: // crc the directory to check for modifications
1675: crc = CRC_Block((byte *)info, header.dirlen);
1676:
1677: // CRC_Init (&crc);
1678: // for (i=0 ; i<header.dirlen ; i++)
1679: // CRC_ProcessByte (&crc, ((byte *)info)[i]);
1680: if (crc != PAK0_CRC)
1681: com_modified = true;
1682:
1683: // parse the directory
1684: for (i=0 ; i<numpackfiles ; i++)
1685: {
1686: strcpy (newfiles[i].name, info[i].name);
1687: newfiles[i].filepos = LittleLong(info[i].filepos);
1688: newfiles[i].filelen = LittleLong(info[i].filelen);
1689: }
1690:
1691: pack = Z_Malloc (sizeof (pack_t));
1692: strcpy (pack->filename, packfile);
1693: pack->handle = packhandle;
1694: pack->numfiles = numpackfiles;
1695: pack->files = newfiles;
1696:
1697: Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
1698: return pack;
1699: }
1700:
1701:
1702: /*
1703: ================
1704: COM_AddGameDirectory
1705:
1706: Sets com_gamedir, adds the directory to the head of the path,
1707: then loads and adds pak1.pak pak2.pak ...
1708: ================
1709: */
1710: void COM_AddGameDirectory (char *dir)
1711: {
1712: int i;
1713: searchpath_t *search;
1714: pack_t *pak;
1715: char pakfile[MAX_OSPATH];
1716: char *p;
1717:
1718: if ((p = strrchr(dir, '/')) != NULL)
1719: strcpy(gamedirfile, ++p);
1720: else
1721: strcpy(gamedirfile, p);
1722: strcpy (com_gamedir, dir);
1723:
1724: //
1725: // add the directory to the search path
1726: //
1727: search = Hunk_Alloc (sizeof(searchpath_t));
1728: strcpy (search->filename, dir);
1729: search->next = com_searchpaths;
1730: com_searchpaths = search;
1731:
1732: //
1733: // add any pak files in the format pak0.pak pak1.pak, ...
1734: //
1735: for (i=0 ; ; i++)
1736: {
1737: sprintf (pakfile, "%s/pak%i.pak", dir, i);
1738: pak = COM_LoadPackFile (pakfile);
1739: if (!pak)
1740: break;
1741: search = Hunk_Alloc (sizeof(searchpath_t));
1742: search->pack = pak;
1743: search->next = com_searchpaths;
1744: com_searchpaths = search;
1745: }
1746:
1747: }
1748:
1749: /*
1750: ================
1751: COM_Gamedir
1752:
1753: Sets the gamedir and path to a different directory.
1754: ================
1755: */
1756: void COM_Gamedir (char *dir)
1757: {
1758: searchpath_t *search, *next;
1759: int i;
1760: pack_t *pak;
1761: char pakfile[MAX_OSPATH];
1762:
1763: if (strstr(dir, "..") || strstr(dir, "/")
1764: || strstr(dir, "\\") || strstr(dir, ":") )
1765: {
1766: Con_Printf ("Gamedir should be a single filename, not a path\n");
1767: return;
1768: }
1769:
1770: if (!strcmp(gamedirfile, dir))
1771: return; // still the same
1772: strcpy (gamedirfile, dir);
1773:
1774: //
1775: // free up any current game dir info
1776: //
1777: while (com_searchpaths != com_base_searchpaths)
1778: {
1779: if (com_searchpaths->pack)
1780: {
1781: fclose (com_searchpaths->pack->handle);
1782: Z_Free (com_searchpaths->pack->files);
1783: Z_Free (com_searchpaths->pack);
1784: }
1785: next = com_searchpaths->next;
1786: Z_Free (com_searchpaths);
1787: com_searchpaths = next;
1788: }
1789:
1790: //
1791: // flush all data, so it will be forced to reload
1792: //
1793: Cache_Flush ();
1794:
1795: if (!strcmp(dir,"id1") || !strcmp(dir, "qw"))
1796: return;
1797:
1798: sprintf (com_gamedir, "%s/%s", com_basedir, dir);
1799:
1800: //
1801: // add the directory to the search path
1802: //
1803: search = Z_Malloc (sizeof(searchpath_t));
1804: strcpy (search->filename, com_gamedir);
1805: search->next = com_searchpaths;
1806: com_searchpaths = search;
1807:
1808: //
1809: // add any pak files in the format pak0.pak pak1.pak, ...
1810: //
1811: for (i=0 ; ; i++)
1812: {
1813: sprintf (pakfile, "%s/pak%i.pak", com_gamedir, i);
1814: pak = COM_LoadPackFile (pakfile);
1815: if (!pak)
1816: break;
1817: search = Z_Malloc (sizeof(searchpath_t));
1818: search->pack = pak;
1819: search->next = com_searchpaths;
1820: com_searchpaths = search;
1821: }
1822: }
1823:
1824: /*
1825: ================
1826: COM_InitFilesystem
1827: ================
1828: */
1829: void COM_InitFilesystem (void)
1830: {
1831: int i;
1832:
1833: //
1834: // -basedir <path>
1835: // Overrides the system supplied base directory (under id1)
1836: //
1837: i = COM_CheckParm ("-basedir");
1838: if (i && i < com_argc-1)
1839: strcpy (com_basedir, com_argv[i+1]);
1840: else
1841: strcpy (com_basedir, host_parms.basedir);
1842:
1843: //
1844: // start up with id1 by default
1845: //
1846: COM_AddGameDirectory (va("%s/id1", com_basedir) );
1847: COM_AddGameDirectory (va("%s/qw", com_basedir) );
1848:
1849: // any set gamedirs will be freed up to here
1850: com_base_searchpaths = com_searchpaths;
1851: }
1852:
1853:
1854:
1855: /*
1856: =====================================================================
1857:
1858: INFO STRINGS
1859:
1860: =====================================================================
1861: */
1862:
1863: /*
1864: ===============
1865: Info_ValueForKey
1866:
1867: Searches the string for the given
1868: key and returns the associated value, or an empty string.
1869: ===============
1870: */
1871: char *Info_ValueForKey (char *s, char *key)
1872: {
1873: char pkey[512];
1874: static char value[4][512]; // use two buffers so compares
1875: // work without stomping on each other
1876: static int valueindex;
1877: char *o;
1878:
1879: valueindex = (valueindex + 1) % 4;
1880: if (*s == '\\')
1881: s++;
1882: while (1)
1883: {
1884: o = pkey;
1885: while (*s != '\\')
1886: {
1887: if (!*s)
1888: return "";
1889: *o++ = *s++;
1890: }
1891: *o = 0;
1892: s++;
1893:
1894: o = value[valueindex];
1895:
1896: while (*s != '\\' && *s)
1897: {
1898: if (!*s)
1899: return "";
1900: *o++ = *s++;
1901: }
1902: *o = 0;
1903:
1904: if (!strcmp (key, pkey) )
1905: return value[valueindex];
1906:
1907: if (!*s)
1908: return "";
1909: s++;
1910: }
1911: }
1912:
1913: void Info_RemoveKey (char *s, char *key)
1914: {
1915: char *start;
1916: char pkey[512];
1917: char value[512];
1918: char *o;
1919:
1920: if (strstr (key, "\\"))
1921: {
1922: Con_Printf ("Can't use a key with a \\\n");
1923: return;
1924: }
1925:
1926: while (1)
1927: {
1928: start = s;
1929: if (*s == '\\')
1930: s++;
1931: o = pkey;
1932: while (*s != '\\')
1933: {
1934: if (!*s)
1935: return;
1936: *o++ = *s++;
1937: }
1938: *o = 0;
1939: s++;
1940:
1941: o = value;
1942: while (*s != '\\' && *s)
1943: {
1944: if (!*s)
1945: return;
1946: *o++ = *s++;
1947: }
1948: *o = 0;
1949:
1950: if (!strcmp (key, pkey) )
1951: {
1952: strcpy (start, s); // remove this part
1953: return;
1954: }
1955:
1956: if (!*s)
1957: return;
1958: }
1959:
1960: }
1961:
1962: void Info_RemovePrefixedKeys (char *start, char prefix)
1963: {
1964: char *s;
1965: char pkey[512];
1966: char value[512];
1967: char *o;
1968:
1969: s = start;
1970:
1971: while (1)
1972: {
1973: if (*s == '\\')
1974: s++;
1975: o = pkey;
1976: while (*s != '\\')
1977: {
1978: if (!*s)
1979: return;
1980: *o++ = *s++;
1981: }
1982: *o = 0;
1983: s++;
1984:
1985: o = value;
1986: while (*s != '\\' && *s)
1987: {
1988: if (!*s)
1989: return;
1990: *o++ = *s++;
1991: }
1992: *o = 0;
1993:
1994: if (pkey[0] == prefix)
1995: {
1996: Info_RemoveKey (start, pkey);
1997: s = start;
1998: }
1999:
2000: if (!*s)
2001: return;
2002: }
2003:
2004: }
2005:
2006:
2007: void Info_SetValueForStarKey (char *s, char *key, char *value, int maxsize)
2008: {
2009: char new[1024], *v;
2010: int c;
2011: #ifdef SERVERONLY
2012: extern cvar_t sv_highchars;
2013: #endif
2014:
2015: if (strstr (key, "\\") || strstr (value, "\\") )
2016: {
2017: Con_Printf ("Can't use keys or values with a \\\n");
2018: return;
2019: }
2020:
2021: if (strstr (key, "\"") || strstr (value, "\"") )
2022: {
2023: Con_Printf ("Can't use keys or values with a \"\n");
2024: return;
2025: }
2026:
2027: if (strlen(key) > 63 || strlen(value) > 63)
2028: {
2029: Con_Printf ("Keys and values must be < 64 characters.\n");
2030: return;
2031: }
2032:
2033: // this next line is kinda trippy
2034: if (*(v = Info_ValueForKey(s, key))) {
2035: // key exists, make sure we have enough room for new value, if we don't,
2036: // don't change it!
2037: if (strlen(value) - strlen(v) + strlen(s) > maxsize) {
2038: Con_Printf ("Info string length exceeded\n");
2039: return;
2040: }
2041: }
2042: Info_RemoveKey (s, key);
2043: if (!value || !strlen(value))
2044: return;
2045:
2046: sprintf (new, "\\%s\\%s", key, value);
2047:
2048: if ((int)(strlen(new) + strlen(s)) > maxsize)
2049: {
2050: Con_Printf ("Info string length exceeded\n");
2051: return;
2052: }
2053:
2054: // only copy ascii values
2055: s += strlen(s);
2056: v = new;
2057: while (*v)
2058: {
2059: c = (unsigned char)*v++;
2060: #ifndef SERVERONLY
2061: // client only allows highbits on name
2062: if (stricmp(key, "name") != 0) {
2063: c &= 127;
2064: if (c < 32 || c > 127)
2065: continue;
2066: // auto lowercase team
2067: if (stricmp(key, "team") == 0)
2068: c = tolower(c);
2069: }
2070: #else
2071: if (!sv_highchars.value) {
2072: c &= 127;
2073: if (c < 32 || c > 127)
2074: continue;
2075: }
2076: #endif
2077: // c &= 127; // strip high bits
2078: if (c > 13) // && c < 127)
2079: *s++ = c;
2080: }
2081: *s = 0;
2082: }
2083:
2084: void Info_SetValueForKey (char *s, char *key, char *value, int maxsize)
2085: {
2086: if (key[0] == '*')
2087: {
2088: Con_Printf ("Can't set * keys\n");
2089: return;
2090: }
2091:
2092: Info_SetValueForStarKey (s, key, value, maxsize);
2093: }
2094:
2095: void Info_Print (char *s)
2096: {
2097: char key[512];
2098: char value[512];
2099: char *o;
2100: int l;
2101:
2102: if (*s == '\\')
2103: s++;
2104: while (*s)
2105: {
2106: o = key;
2107: while (*s && *s != '\\')
2108: *o++ = *s++;
2109:
2110: l = o - key;
2111: if (l < 20)
2112: {
2113: memset (o, ' ', 20-l);
2114: key[20] = 0;
2115: }
2116: else
2117: *o = 0;
2118: Con_Printf ("%s", key);
2119:
2120: if (!*s)
2121: {
2122: Con_Printf ("MISSING VALUE\n");
2123: return;
2124: }
2125:
2126: o = value;
2127: s++;
2128: while (*s && *s != '\\')
2129: *o++ = *s++;
2130: *o = 0;
2131:
2132: if (*s)
2133: s++;
2134: Con_Printf ("%s\n", value);
2135: }
2136: }
2137:
2138: static byte chktbl[1024 + 4] = {
2139: 0x78,0xd2,0x94,0xe3,0x41,0xec,0xd6,0xd5,0xcb,0xfc,0xdb,0x8a,0x4b,0xcc,0x85,0x01,
2140: 0x23,0xd2,0xe5,0xf2,0x29,0xa7,0x45,0x94,0x4a,0x62,0xe3,0xa5,0x6f,0x3f,0xe1,0x7a,
2141: 0x64,0xed,0x5c,0x99,0x29,0x87,0xa8,0x78,0x59,0x0d,0xaa,0x0f,0x25,0x0a,0x5c,0x58,
2142: 0xfb,0x00,0xa7,0xa8,0x8a,0x1d,0x86,0x80,0xc5,0x1f,0xd2,0x28,0x69,0x71,0x58,0xc3,
2143: 0x51,0x90,0xe1,0xf8,0x6a,0xf3,0x8f,0xb0,0x68,0xdf,0x95,0x40,0x5c,0xe4,0x24,0x6b,
2144: 0x29,0x19,0x71,0x3f,0x42,0x63,0x6c,0x48,0xe7,0xad,0xa8,0x4b,0x91,0x8f,0x42,0x36,
2145: 0x34,0xe7,0x32,0x55,0x59,0x2d,0x36,0x38,0x38,0x59,0x9b,0x08,0x16,0x4d,0x8d,0xf8,
2146: 0x0a,0xa4,0x52,0x01,0xbb,0x52,0xa9,0xfd,0x40,0x18,0x97,0x37,0xff,0xc9,0x82,0x27,
2147: 0xb2,0x64,0x60,0xce,0x00,0xd9,0x04,0xf0,0x9e,0x99,0xbd,0xce,0x8f,0x90,0x4a,0xdd,
2148: 0xe1,0xec,0x19,0x14,0xb1,0xfb,0xca,0x1e,0x98,0x0f,0xd4,0xcb,0x80,0xd6,0x05,0x63,
2149: 0xfd,0xa0,0x74,0xa6,0x86,0xf6,0x19,0x98,0x76,0x27,0x68,0xf7,0xe9,0x09,0x9a,0xf2,
2150: 0x2e,0x42,0xe1,0xbe,0x64,0x48,0x2a,0x74,0x30,0xbb,0x07,0xcc,0x1f,0xd4,0x91,0x9d,
2151: 0xac,0x55,0x53,0x25,0xb9,0x64,0xf7,0x58,0x4c,0x34,0x16,0xbc,0xf6,0x12,0x2b,0x65,
2152: 0x68,0x25,0x2e,0x29,0x1f,0xbb,0xb9,0xee,0x6d,0x0c,0x8e,0xbb,0xd2,0x5f,0x1d,0x8f,
2153: 0xc1,0x39,0xf9,0x8d,0xc0,0x39,0x75,0xcf,0x25,0x17,0xbe,0x96,0xaf,0x98,0x9f,0x5f,
2154: 0x65,0x15,0xc4,0x62,0xf8,0x55,0xfc,0xab,0x54,0xcf,0xdc,0x14,0x06,0xc8,0xfc,0x42,
2155: 0xd3,0xf0,0xad,0x10,0x08,0xcd,0xd4,0x11,0xbb,0xca,0x67,0xc6,0x48,0x5f,0x9d,0x59,
2156: 0xe3,0xe8,0x53,0x67,0x27,0x2d,0x34,0x9e,0x9e,0x24,0x29,0xdb,0x69,0x99,0x86,0xf9,
2157: 0x20,0xb5,0xbb,0x5b,0xb0,0xf9,0xc3,0x67,0xad,0x1c,0x9c,0xf7,0xcc,0xef,0xce,0x69,
2158: 0xe0,0x26,0x8f,0x79,0xbd,0xca,0x10,0x17,0xda,0xa9,0x88,0x57,0x9b,0x15,0x24,0xba,
2159: 0x84,0xd0,0xeb,0x4d,0x14,0xf5,0xfc,0xe6,0x51,0x6c,0x6f,0x64,0x6b,0x73,0xec,0x85,
2160: 0xf1,0x6f,0xe1,0x67,0x25,0x10,0x77,0x32,0x9e,0x85,0x6e,0x69,0xb1,0x83,0x00,0xe4,
2161: 0x13,0xa4,0x45,0x34,0x3b,0x40,0xff,0x41,0x82,0x89,0x79,0x57,0xfd,0xd2,0x8e,0xe8,
2162: 0xfc,0x1d,0x19,0x21,0x12,0x00,0xd7,0x66,0xe5,0xc7,0x10,0x1d,0xcb,0x75,0xe8,0xfa,
2163: 0xb6,0xee,0x7b,0x2f,0x1a,0x25,0x24,0xb9,0x9f,0x1d,0x78,0xfb,0x84,0xd0,0x17,0x05,
2164: 0x71,0xb3,0xc8,0x18,0xff,0x62,0xee,0xed,0x53,0xab,0x78,0xd3,0x65,0x2d,0xbb,0xc7,
2165: 0xc1,0xe7,0x70,0xa2,0x43,0x2c,0x7c,0xc7,0x16,0x04,0xd2,0x45,0xd5,0x6b,0x6c,0x7a,
2166: 0x5e,0xa1,0x50,0x2e,0x31,0x5b,0xcc,0xe8,0x65,0x8b,0x16,0x85,0xbf,0x82,0x83,0xfb,
2167: 0xde,0x9f,0x36,0x48,0x32,0x79,0xd6,0x9b,0xfb,0x52,0x45,0xbf,0x43,0xf7,0x0b,0x0b,
2168: 0x19,0x19,0x31,0xc3,0x85,0xec,0x1d,0x8c,0x20,0xf0,0x3a,0xfa,0x80,0x4d,0x2c,0x7d,
2169: 0xac,0x60,0x09,0xc0,0x40,0xee,0xb9,0xeb,0x13,0x5b,0xe8,0x2b,0xb1,0x20,0xf0,0xce,
2170: 0x4c,0xbd,0xc6,0x04,0x86,0x70,0xc6,0x33,0xc3,0x15,0x0f,0x65,0x19,0xfd,0xc2,0xd3,
2171:
2172: // map checksum goes here
2173: 0x00,0x00,0x00,0x00
2174: };
2175:
2176: static byte chkbuf[16 + 60 + 4];
2177:
2178: static unsigned last_mapchecksum = 0;
2179:
2180: #if 0
2181: /*
2182: ====================
2183: COM_BlockSequenceCheckByte
2184:
2185: For proxy protecting
2186: ====================
2187: */
2188: byte COM_BlockSequenceCheckByte (byte *base, int length, int sequence, unsigned mapchecksum)
2189: {
2190: int checksum;
2191: byte *p;
2192:
2193: if (last_mapchecksum != mapchecksum) {
2194: last_mapchecksum = mapchecksum;
2195: chktbl[1024] = (mapchecksum & 0xff000000) >> 24;
2196: chktbl[1025] = (mapchecksum & 0x00ff0000) >> 16;
2197: chktbl[1026] = (mapchecksum & 0x0000ff00) >> 8;
2198: chktbl[1027] = (mapchecksum & 0x000000ff);
2199:
2200: Com_BlockFullChecksum (chktbl, sizeof(chktbl), chkbuf);
2201: }
2202:
2203: p = chktbl + (sequence % (sizeof(chktbl) - 8));
2204:
2205: if (length > 60)
2206: length = 60;
2207: memcpy (chkbuf + 16, base, length);
2208:
2209: length += 16;
2210:
2211: chkbuf[length] = (sequence & 0xff) ^ p[0];
2212: chkbuf[length+1] = p[1];
2213: chkbuf[length+2] = ((sequence>>8) & 0xff) ^ p[2];
2214: chkbuf[length+3] = p[3];
2215:
2216: length += 4;
2217:
2218: checksum = LittleLong(Com_BlockChecksum (chkbuf, length));
2219:
2220: checksum &= 0xff;
2221:
2222: return checksum;
2223: }
2224: #endif
2225:
2226: /*
2227: ====================
2228: COM_BlockSequenceCRCByte
2229:
2230: For proxy protecting
2231: ====================
2232: */
2233: byte COM_BlockSequenceCRCByte (byte *base, int length, int sequence)
2234: {
2235: unsigned short crc;
2236: byte *p;
2237: byte chkb[60 + 4];
2238:
2239: p = chktbl + (sequence % (sizeof(chktbl) - 8));
2240:
2241: if (length > 60)
2242: length = 60;
2243: memcpy (chkb, base, length);
2244:
2245: chkb[length] = (sequence & 0xff) ^ p[0];
2246: chkb[length+1] = p[1];
2247: chkb[length+2] = ((sequence>>8) & 0xff) ^ p[2];
2248: chkb[length+3] = p[3];
2249:
2250: length += 4;
2251:
2252: crc = CRC_Block(chkb, length);
2253:
2254: crc &= 0xff;
2255:
2256: return crc;
2257: }
2258:
2259: // char *date = "Oct 24 1996";
2260: static char *date = __DATE__ ;
2261: static char *mon[12] =
2262: { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
2263: static char mond[12] =
2264: { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2265:
2266: // returns days since Oct 24 1996
2267: int build_number( void )
2268: {
2269: int m = 0;
2270: int d = 0;
2271: int y = 0;
2272: static int b = 0;
2273:
2274: if (b != 0)
2275: return b;
2276:
2277: for (m = 0; m < 11; m++)
2278: {
2279: if (Q_strncasecmp( &date[0], mon[m], 3 ) == 0)
2280: break;
2281: d += mond[m];
2282: }
2283:
2284: d += atoi( &date[4] ) - 1;
2285:
2286: y = atoi( &date[7] ) - 1900;
2287:
2288: b = d + (int)((y - 1) * 365.25);
2289:
2290: if (((y % 4) == 0) && m > 1)
2291: {
2292: b += 1;
2293: }
2294:
2295: b -= 35778; // Dec 16 1998
2296:
2297: return b;
2298: }
2299:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.