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