2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // common.c -- misc functions used in client and server
32 #define NUM_SAFE_ARGVS 7
34 static char *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];
35 static char *argvdummy = " ";
37 static char *safeargvs[NUM_SAFE_ARGVS] =
38 {"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-window"};
40 cvar_t registered = {0, "registered","0"};
41 cvar_t cmdline = {0, "cmdline","0"};
43 mempool_t *pak_mempool;
45 qboolean com_modified; // set true if using non-id files
49 //int static_registered = 1; // only for startup check, then set
51 qboolean msg_suppress_1 = 0;
53 void COM_InitFilesystem (void);
59 // LordHavoc: made commandline 1024 characters instead of 256
60 #define CMDLINE_LENGTH 1024
61 char com_cmdline[CMDLINE_LENGTH];
69 All of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.
71 The "base directory" is the path to the directory holding the quake.exe and all game directories. The sys_* files pass this to host_init in quakeparms_t->basedir. This can be overridden with the "-basedir" command line parm to allow code debugging in a different directory. The base directory is
72 only used during filesystem initialization.
74 The "game directory" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to. This can be overridden with the "-game" command line parameter. The game directory can never be changed while quake is executing. This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.
76 The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines. If there is a cache directory
77 specified, when a file is found by the normal search path, it will be mirrored
78 into the cache directory, then opened there.
83 The file "parms.txt" will be read out of the game directory and appended to the current command line arguments to allow different games to initialize startup parms differently. This could be used to add a "-sspeed 22050" for the high quality sound edition. Because they are added at the end, they will not override an explicit setting on the original command line.
87 //============================================================================
91 ============================================================================
93 LIBRARY REPLACEMENT FUNCTIONS
95 ============================================================================
99 void Q_memset (void *dest, int fill, int count)
103 if ( (((long)dest | count) & 3) == 0)
106 fill = fill | (fill<<8) | (fill<<16) | (fill<<24);
107 for (i=0 ; i<count ; i++)
108 ((int *)dest)[i] = fill;
111 for (i=0 ; i<count ; i++)
112 ((qbyte *)dest)[i] = fill;
115 void Q_memcpy (void *dest, void *src, int count)
119 if (( ( (long)dest | (long)src | count) & 3) == 0 )
122 for (i=0 ; i<count ; i++)
123 ((int *)dest)[i] = ((int *)src)[i];
126 for (i=0 ; i<count ; i++)
127 ((qbyte *)dest)[i] = ((qbyte *)src)[i];
130 int Q_memcmp (void *m1, void *m2, int count)
135 if (((qbyte *)m1)[count] != ((qbyte *)m2)[count])
141 void Q_strcpy (char *dest, char *src)
150 void Q_strncpy (char *dest, char *src, int count)
152 while (*src && count--)
160 int Q_strlen (char *str)
171 char *Q_strrchr(char *s, char c)
173 int len = Q_strlen(s);
176 if (*--s == c) return s;
180 void Q_strcat (char *dest, char *src)
182 dest += Q_strlen(dest);
183 Q_strcpy (dest, src);
186 int Q_strcmp (char *s1, char *s2)
191 return -1; // strings not equal
193 return 0; // strings are equal
201 int Q_strncmp (char *s1, char *s2, int count)
208 return -1; // strings not equal
210 return 0; // strings are equal
218 int Q_strncasecmp (char *s1, char *s2, int n)
228 return 0; // strings are equal until end point
232 if (c1 >= 'a' && c1 <= 'z')
234 if (c2 >= 'a' && c2 <= 'z')
237 return -1; // strings not equal
240 return 0; // strings are equal
248 int Q_strcasecmp (char *s1, char *s2)
250 return Q_strncasecmp (s1, s2, 99999);
253 int Q_atoi (char *str)
272 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
278 if (c >= '0' && c <= '9')
279 val = (val<<4) + c - '0';
280 else if (c >= 'a' && c <= 'f')
281 val = (val<<4) + c - 'a' + 10;
282 else if (c >= 'A' && c <= 'F')
283 val = (val<<4) + c - 'A' + 10;
290 // check for character
294 return sign * str[1];
303 if (c <'0' || c > '9')
305 val = val*10 + c - '0';
312 float Q_atof (char *str)
332 if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X') )
338 if (c >= '0' && c <= '9')
339 val = (val*16) + c - '0';
340 else if (c >= 'a' && c <= 'f')
341 val = (val*16) + c - 'a' + 10;
342 else if (c >= 'A' && c <= 'F')
343 val = (val*16) + c - 'A' + 10;
350 // check for character
354 return sign * str[1];
370 if (c <'0' || c > '9')
372 val = val*10 + c - '0';
378 while (total > decimal)
389 ============================================================================
393 ============================================================================
396 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
397 short (*BigShort) (short l);
398 short (*LittleShort) (short l);
399 int (*BigLong) (int l);
400 int (*LittleLong) (int l);
401 float (*BigFloat) (float l);
402 float (*LittleFloat) (float l);
405 short ShortSwap (short l)
415 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
416 short ShortNoSwap (short l)
431 return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
434 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
435 int LongNoSwap (int l)
441 float FloatSwap (float f)
451 dat2.b[0] = dat1.b[3];
452 dat2.b[1] = dat1.b[2];
453 dat2.b[2] = dat1.b[1];
454 dat2.b[3] = dat1.b[0];
458 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
459 float FloatNoSwap (float f)
466 ==============================================================================
470 Handles byte ordering and avoids alignment errors
471 ==============================================================================
478 void MSG_WriteChar (sizebuf_t *sb, int c)
483 // if (c < -128 || c > 127)
484 // Sys_Error ("MSG_WriteChar: range error");
487 buf = SZ_GetSpace (sb, 1);
491 void MSG_WriteByte (sizebuf_t *sb, int c)
496 // if (c < 0 || c > 255)
497 // Sys_Error ("MSG_WriteByte: range error");
500 buf = SZ_GetSpace (sb, 1);
504 void MSG_WriteShort (sizebuf_t *sb, int c)
509 // if (c < ((short)0x8000) || c > (short)0x7fff)
510 // Sys_Error ("MSG_WriteShort: range error");
513 buf = SZ_GetSpace (sb, 2);
518 void MSG_WriteLong (sizebuf_t *sb, int c)
522 buf = SZ_GetSpace (sb, 4);
524 buf[1] = (c>>8)&0xff;
525 buf[2] = (c>>16)&0xff;
529 void MSG_WriteFloat (sizebuf_t *sb, float f)
539 dat.l = LittleLong (dat.l);
541 SZ_Write (sb, &dat.l, 4);
544 void MSG_WriteString (sizebuf_t *sb, char *s)
547 SZ_Write (sb, "", 1);
549 SZ_Write (sb, s, strlen(s)+1);
552 // used by server (always latest dpprotocol)
553 void MSG_WriteDPCoord (sizebuf_t *sb, float f)
556 MSG_WriteShort (sb, (int)(f + 0.5f));
558 MSG_WriteShort (sb, (int)(f - 0.5f));
561 void MSG_WritePreciseAngle (sizebuf_t *sb, float f)
564 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) + 0.5f) & 65535);
566 MSG_WriteShort (sb, (int)(f*(65536.0f/360.0f) - 0.5f) & 65535);
569 // LordHavoc: round to nearest value, rather than rounding toward zero, fixes crosshair problem
570 void MSG_WriteAngle (sizebuf_t *sb, float f)
573 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) + 0.5f) & 255);
575 MSG_WriteByte (sb, (int)(f*(256.0f/360.0f) - 0.5f) & 255);
582 qboolean msg_badread;
584 void MSG_BeginReading (void)
591 // returns -1 and sets msg_badread if no more characters are available
592 int MSG_ReadChar (void)
596 // LordHavoc: minor optimization
597 if (msg_readcount >= net_message.cursize)
598 // if (msg_readcount+1 > net_message.cursize)
604 c = (signed char)net_message.data[msg_readcount];
610 int MSG_ReadByte (void)
614 // LordHavoc: minor optimization
615 if (msg_readcount >= net_message.cursize)
616 // if (msg_readcount+1 > net_message.cursize)
622 c = (unsigned char)net_message.data[msg_readcount];
629 int MSG_ReadShort (void)
633 if (msg_readcount+2 > net_message.cursize)
639 c = (short)(net_message.data[msg_readcount]
640 + (net_message.data[msg_readcount+1]<<8));
647 int MSG_ReadLong (void)
651 if (msg_readcount+4 > net_message.cursize)
657 c = net_message.data[msg_readcount]
658 + (net_message.data[msg_readcount+1]<<8)
659 + (net_message.data[msg_readcount+2]<<16)
660 + (net_message.data[msg_readcount+3]<<24);
667 float MSG_ReadFloat (void)
676 dat.b[0] = net_message.data[msg_readcount];
677 dat.b[1] = net_message.data[msg_readcount+1];
678 dat.b[2] = net_message.data[msg_readcount+2];
679 dat.b[3] = net_message.data[msg_readcount+3];
682 dat.l = LittleLong (dat.l);
687 char *MSG_ReadString (void)
689 static char string[2048];
696 if (c == -1 || c == 0)
700 } while (l < sizeof(string)-1);
707 // used by server (always latest dpprotocol)
708 float MSG_ReadDPCoord (void)
710 return (signed short) MSG_ReadShort();
714 float MSG_ReadCoord (void)
716 if (dpprotocol == DPPROTOCOL_VERSION2 || dpprotocol == DPPROTOCOL_VERSION3)
717 return (signed short) MSG_ReadShort();
718 else if (dpprotocol == DPPROTOCOL_VERSION1)
719 return MSG_ReadFloat();
721 return MSG_ReadShort() * (1.0f/8.0f);
725 float MSG_ReadCoord (void)
727 return MSG_ReadShort() * (1.0f/8.0f);
730 float MSG_ReadAngle (void)
732 return MSG_ReadChar() * (360.0f/256.0f);
735 float MSG_ReadPreciseAngle (void)
737 return MSG_ReadShort() * (360.0f/65536);
742 //===========================================================================
744 void SZ_Alloc (sizebuf_t *buf, int startsize, char *name)
748 buf->mempool = Mem_AllocPool(name);
749 buf->data = Mem_Alloc(buf->mempool, startsize);
750 buf->maxsize = startsize;
755 void SZ_Free (sizebuf_t *buf)
757 Mem_FreePool(&buf->mempool);
763 void SZ_Clear (sizebuf_t *buf)
768 void *SZ_GetSpace (sizebuf_t *buf, int length)
772 if (buf->cursize + length > buf->maxsize)
774 if (!buf->allowoverflow)
775 Host_Error ("SZ_GetSpace: overflow without allowoverflow set");
777 if (length > buf->maxsize)
778 Host_Error ("SZ_GetSpace: %i is > full buffer size", length);
780 buf->overflowed = true;
781 Con_Printf ("SZ_GetSpace: overflow");
785 data = buf->data + buf->cursize;
786 buf->cursize += length;
791 void SZ_Write (sizebuf_t *buf, void *data, int length)
793 memcpy (SZ_GetSpace(buf,length),data,length);
796 void SZ_Print (sizebuf_t *buf, char *data)
800 len = strlen(data)+1;
802 // byte * cast to keep VC++ happy
803 if (buf->data[buf->cursize-1])
804 memcpy ((qbyte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
806 memcpy ((qbyte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
810 //============================================================================
818 char *COM_SkipPath (char *pathname)
837 // LordHavoc: replacement for severely broken COM_StripExtension that was used in original quake.
838 void COM_StripExtension (char *in, char *out)
845 else if (*in == '/' || *in == '\\' || *in == ':')
858 char *COM_FileExtension (char *in)
860 static char exten[8];
863 while (*in && *in != '.')
868 for (i=0 ; i<7 && *in ; i++,in++)
879 void COM_FileBase (char *in, char *out)
898 strcpy (out,"?model?");
913 void COM_DefaultExtension (char *path, char *extension)
917 // if path doesn't have a .EXT, append extension
918 // (extension should include the .)
920 src = path + strlen(path) - 1;
922 while (*src != '/' && src != path)
925 return; // it has an extension
929 strcat (path, extension);
937 Parse a token out of a string
940 char *COM_Parse (char *data)
953 while ( (c = *data) <= ' ')
956 return NULL; // end of file;
961 if (c=='/' && data[1] == '/')
963 while (*data && *data != '\n')
969 // handle quoted strings specially
986 // parse single characters
987 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
995 // parse a regular word
1002 if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
1015 Returns the position (1 to argc-1) in the program's argument list
1016 where the given parameter apears, or 0 if not present
1019 int COM_CheckParm (char *parm)
1023 for (i=1 ; i<com_argc ; i++)
1026 continue; // NEXTSTEP sometimes clears appkit vars.
1027 if (!strcmp (parm,com_argv[i]))
1038 Looks for the pop.txt file and verifies it.
1039 Sets the "registered" cvar.
1040 Immediately exits out if an alternate game was attempted to be started without
1044 void COM_CheckRegistered (void)
1046 Cvar_Set ("cmdline", com_cmdline);
1048 // static_registered = 0;
1050 if (!Sys_FileTime("gfx/pop.lmp"))
1053 Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
1055 Con_Printf ("Playing shareware version.\n");
1057 // Sys_Error ("This dedicated server requires a full registered copy of Quake");
1059 // Con_Printf ("Playing shareware version.\n");
1060 // if (com_modified)
1061 // Sys_Error ("You must have the registered version to use modified games");
1065 // Cvar_Set ("cmdline", com_cmdline);
1066 Cvar_Set ("registered", "1");
1067 // static_registered = 1;
1068 Con_Printf ("Playing registered version.\n");
1072 void COM_Path_f (void);
1080 void COM_InitArgv (int argc, char **argv)
1085 // reconstitute the command line for the cmdline externally visible cvar
1088 for (j=0 ; (j<MAX_NUM_ARGVS) && (j< argc) ; j++)
1092 while ((n < (CMDLINE_LENGTH - 1)) && argv[j][i])
1094 com_cmdline[n++] = argv[j][i++];
1097 if (n < (CMDLINE_LENGTH - 1))
1098 com_cmdline[n++] = ' ';
1107 for (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;
1110 largv[com_argc] = argv[com_argc];
1111 if (!strcmp ("-safe", argv[com_argc]))
1117 // force all the safe-mode switches. Note that we reserved extra space in
1118 // case we need to add these, so we don't need an overflow check
1119 for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
1121 largv[com_argc] = safeargvs[i];
1126 largv[com_argc] = argvdummy;
1130 gamemode = GAME_ZYMOTIC;
1132 gamemode = GAME_FIENDARENA;
1134 gamemode = GAME_NEHAHRA;
1136 if (COM_CheckParm ("-zymotic"))
1137 gamemode = GAME_ZYMOTIC;
1138 else if (COM_CheckParm ("-fiendarena"))
1139 gamemode = GAME_FIENDARENA;
1140 else if (COM_CheckParm ("-nehahra"))
1141 gamemode = GAME_NEHAHRA;
1142 else if (COM_CheckParm ("-hipnotic"))
1143 gamemode = GAME_HIPNOTIC;
1144 else if (COM_CheckParm ("-rogue"))
1145 gamemode = GAME_ROGUE;
1150 gamename = "DarkPlaces";
1153 gamename = "Darkplaces-Hipnotic";
1156 gamename = "Darkplaces-Rogue";
1159 gamename = "DarkPlaces-Nehahra";
1161 case GAME_FIENDARENA:
1162 gamename = "FiendArena";
1165 gamename = "Zymotic";
1168 Sys_Error("COM_InitArgv: unknown gamemode %i\n", gamemode);
1174 extern void Mathlib_Init(void);
1181 void COM_Init (void)
1183 #if !defined(ENDIAN_LITTLE) && !defined(ENDIAN_BIG)
1184 qbyte swaptest[2] = {1,0};
1186 // set the byte swapping variables in a portable manner
1187 if ( *(short *)swaptest == 1)
1189 BigShort = ShortSwap;
1190 LittleShort = ShortNoSwap;
1192 LittleLong = LongNoSwap;
1193 BigFloat = FloatSwap;
1194 LittleFloat = FloatNoSwap;
1198 BigShort = ShortNoSwap;
1199 LittleShort = ShortSwap;
1200 BigLong = LongNoSwap;
1201 LittleLong = LongSwap;
1202 BigFloat = FloatNoSwap;
1203 LittleFloat = FloatSwap;
1207 pak_mempool = Mem_AllocPool("paks");
1209 Cvar_RegisterVariable (®istered);
1210 Cvar_RegisterVariable (&cmdline);
1211 Cmd_AddCommand ("path", COM_Path_f);
1215 COM_InitFilesystem ();
1216 COM_CheckRegistered ();
1224 does a varargs printf into a temp buffer, so I don't need to have
1225 varargs versions of all text functions.
1226 FIXME: make this buffer size safe someday
1229 char *va(char *format, ...)
1232 // LordHavoc: now cycles through 8 buffers to avoid problems in most cases
1233 static char string[8][1024], *s;
1234 static int stringindex = 0;
1236 s = string[stringindex];
1237 stringindex = (stringindex + 1) & 7;
1238 va_start (argptr, format);
1239 vsprintf (s, format,argptr);
1246 /// just for debugging
1247 int memsearch (qbyte *start, int count, int search)
1251 for (i=0 ; i<count ; i++)
1252 if (start[i] == search)
1258 =============================================================================
1262 =============================================================================
1274 char name[MAX_QPATH];
1275 int filepos, filelen;
1278 typedef struct pack_s
1280 char filename[MAX_OSPATH];
1285 struct pack_s *next;
1294 int filepos, filelen;
1304 // LordHavoc: was 2048, increased to 65536 and changed info[MAX_PACK_FILES] to a temporary alloc
1305 #define MAX_FILES_IN_PACK 65536
1307 pack_t *packlist = NULL;
1310 char com_cachedir[MAX_OSPATH];
1312 char com_gamedir[MAX_OSPATH];
1314 typedef struct searchpath_s
1316 char filename[MAX_OSPATH];
1317 pack_t *pack; // only one of filename / pack will be used
1318 struct searchpath_s *next;
1321 searchpath_t *com_searchpaths;
1329 void COM_Path_f (void)
1333 Con_Printf ("Current search path:\n");
1334 for (s=com_searchpaths ; s ; s=s->next)
1338 Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
1341 Con_Printf ("%s\n", s->filename);
1349 LordHavoc: Previously only used for CopyFile, now also used for COM_WriteFile.
1352 void COM_CreatePath (char *path)
1356 for (ofs = path+1 ; *ofs ; ofs++)
1358 if (*ofs == '/' || *ofs == '\\')
1360 // create the directory
1374 The filename will be prefixed by the current game directory
1377 void COM_WriteFile (char *filename, void *data, int len)
1380 char name[MAX_OSPATH];
1382 sprintf (name, "%s/%s", com_gamedir, filename);
1384 // LordHavoc: added this
1385 COM_CreatePath (name); // create directories up to the file
1387 handle = Sys_FileOpenWrite (name);
1390 Sys_Printf ("COM_WriteFile: failed on %s\n", name);
1394 Con_Printf ("COM_WriteFile: %s\n", name);
1395 Sys_FileWrite (handle, data, len);
1396 Sys_FileClose (handle);
1404 Copies a file over from the net to the local cache, creating any directories
1405 needed. This is for the convenience of developers using ISDN from home.
1408 void COM_CopyFile (char *netpath, char *cachepath)
1411 int remaining, count;
1414 remaining = Sys_FileOpenRead (netpath, &in);
1415 COM_CreatePath (cachepath); // create directories up to the cache file
1416 out = Sys_FileOpenWrite (cachepath);
1420 if (remaining < sizeof(buf))
1423 count = sizeof(buf);
1424 Sys_FileRead (in, buf, count);
1425 Sys_FileWrite (out, buf, count);
1430 Sys_FileClose (out);
1438 QFile * COM_OpenRead (const char *path, int offs, int len, qboolean zip)
1440 int fd = open (path, O_RDONLY);
1441 unsigned char id[2];
1442 unsigned char len_bytes[4];
1446 Sys_Error ("Couldn't open %s", path);
1449 if (offs < 0 || len < 0)
1453 len = lseek (fd, 0, SEEK_END);
1454 lseek (fd, 0, SEEK_SET);
1456 lseek (fd, offs, SEEK_SET);
1460 if (id[0] == 0x1f && id[1] == 0x8b)
1462 lseek (fd, offs + len - 4, SEEK_SET);
1463 read (fd, len_bytes, 4);
1464 len = ((len_bytes[3] << 24)
1465 | (len_bytes[2] << 16)
1466 | (len_bytes[1] << 8)
1470 lseek (fd, offs, SEEK_SET);
1474 setmode (fd, O_BINARY);
1477 return Qdopen (fd, "rbz");
1479 return Qdopen (fd, "rb");
1486 Finds the file in the search path.
1487 Sets com_filesize and one of handle or file
1490 int COM_FindFile (char *filename, QFile **file, qboolean quiet, qboolean zip)
1492 searchpath_t *search;
1493 char netpath[MAX_OSPATH];
1495 char cachepath[MAX_OSPATH];
1501 char gzfilename[MAX_OSPATH];
1504 filenamelen = strlen (filename);
1505 sprintf (gzfilename, "%s.gz", filename);
1508 Sys_Error ("COM_FindFile: file not set");
1511 // search through the path, one element at a time
1513 search = com_searchpaths;
1515 // { // gross hack to use quake 1 progs with quake 2 maps
1516 // if (!strcmp(filename, "progs.dat"))
1517 // search = search->next;
1520 for ( ; search ; search = search->next)
1522 // is the element a pak file?
1525 // look through all the pak file elements
1527 for (i=0 ; i<pak->numfiles ; i++)
1528 if (!strcmp (pak->files[i].name, filename)
1529 || !strcmp (pak->files[i].name, gzfilename))
1532 Sys_Printf ("PackFile: %s : %s\n",pak->filename, pak->files[i].name);
1533 // open a new file on the pakfile
1534 *file = COM_OpenRead (pak->filename, pak->files[i].filepos, pak->files[i].filelen, zip);
1535 return com_filesize;
1540 // check a file in the directory tree
1541 // if (!static_registered)
1542 // { // if not a registered version, don't ever go beyond base
1543 // if ( strchr (filename, '/') || strchr (filename,'\\'))
1547 sprintf (netpath, "%s/%s",search->filename, filename);
1549 findtime = Sys_FileTime (netpath);
1554 // see if the file needs to be updated in the cache
1555 if (com_cachedir[0])
1558 if ((strlen(netpath) < 2) || (netpath[1] != ':'))
1559 sprintf (cachepath,"%s%s", com_cachedir, netpath);
1561 sprintf (cachepath,"%s%s", com_cachedir, netpath+2);
1563 sprintf (cachepath,"%s%s", com_cachedir, netpath);
1566 cachetime = Sys_FileTime (cachepath);
1568 if (cachetime < findtime)
1569 COM_CopyFile (netpath, cachepath);
1570 strcpy (netpath, cachepath);
1575 Sys_Printf ("FindFile: %s\n",netpath);
1576 *file = COM_OpenRead (netpath, -1, -1, zip);
1577 return com_filesize;
1583 Sys_Printf ("FindFile: can't find %s\n", filename);
1595 If the requested file is inside a packfile, a new QFile * will be opened
1599 int COM_FOpenFile (char *filename, QFile **file, qboolean quiet, qboolean zip)
1601 return COM_FindFile (filename, file, quiet, zip);
1609 Filename are reletive to the quake directory.
1610 Always appends a 0 byte.
1615 qbyte *COM_LoadFile (char *path, qboolean quiet)
1622 buf = NULL; // quiet compiler warning
1625 // look for it in the filesystem or pack files
1626 len = COM_FOpenFile (path, &h, quiet, true);
1632 // extract the filename base name for hunk tag
1633 COM_FileBase (path, base);
1635 buf = Mem_Alloc(tempmempool, len+1);
1637 Sys_Error ("COM_LoadFile: not enough available memory for %s (size %i)", path, len);
1639 ((qbyte *)buf)[len] = 0;
1641 Qread (h, buf, len);
1651 Takes an explicit (not game tree related) path to a pak file.
1653 Loads the header and directory, adding the files at the beginning
1654 of the list so they override previous pack files.
1657 pack_t *COM_LoadPackFile (char *packfile)
1659 dpackheader_t header;
1664 // LordHavoc: changed from stack array to temporary alloc, allowing huge pack directories
1667 if (Sys_FileOpenRead (packfile, &packhandle) == -1)
1669 //Con_Printf ("Couldn't open %s\n", packfile);
1672 Sys_FileRead (packhandle, (void *)&header, sizeof(header));
1673 if (memcmp(header.id, "PACK", 4))
1674 Sys_Error ("%s is not a packfile", packfile);
1675 header.dirofs = LittleLong (header.dirofs);
1676 header.dirlen = LittleLong (header.dirlen);
1678 if (header.dirlen % sizeof(dpackfile_t))
1679 Sys_Error ("%s has an invalid directory size", packfile);
1681 numpackfiles = header.dirlen / sizeof(dpackfile_t);
1683 if (numpackfiles > MAX_FILES_IN_PACK)
1684 Sys_Error ("%s has %i files", packfile, numpackfiles);
1686 pack = Mem_Alloc(pak_mempool, sizeof (pack_t));
1687 strcpy (pack->filename, packfile);
1688 pack->handle = packhandle;
1689 pack->numfiles = numpackfiles;
1690 pack->mempool = Mem_AllocPool(packfile);
1691 pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t));
1692 pack->next = packlist;
1695 info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles);
1696 Sys_FileSeek (packhandle, header.dirofs);
1697 Sys_FileRead (packhandle, (void *)info, header.dirlen);
1699 // parse the directory
1700 for (i = 0;i < numpackfiles;i++)
1702 strcpy (pack->files[i].name, info[i].name);
1703 pack->files[i].filepos = LittleLong(info[i].filepos);
1704 pack->files[i].filelen = LittleLong(info[i].filelen);
1709 Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
1716 COM_AddGameDirectory
1718 Sets com_gamedir, adds the directory to the head of the path,
1719 then loads and adds pak1.pak pak2.pak ...
1722 void COM_AddGameDirectory (char *dir)
1725 searchpath_t *search;
1727 char pakfile[MAX_OSPATH];
1729 strcpy (com_gamedir, dir);
1732 // add the directory to the search path
1734 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
1735 strcpy (search->filename, dir);
1736 search->next = com_searchpaths;
1737 com_searchpaths = search;
1740 // add any pak files in the format pak0.pak pak1.pak, ...
1744 sprintf (pakfile, "%s/pak%i.pak", dir, i);
1745 pak = COM_LoadPackFile (pakfile);
1748 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
1750 search->next = com_searchpaths;
1751 com_searchpaths = search;
1755 // add the contents of the parms.txt file to the end of the command line
1765 void COM_InitFilesystem (void)
1768 char basedir[MAX_OSPATH];
1769 searchpath_t *search;
1773 // Overrides the system supplied base directory (under GAMENAME)
1775 i = COM_CheckParm ("-basedir");
1776 if (i && i < com_argc-1)
1777 strcpy (basedir, com_argv[i+1]);
1779 strcpy (basedir, host_parms.basedir);
1781 j = strlen (basedir);
1785 if ((basedir[j-1] == '\\') || (basedir[j-1] == '/'))
1792 // Overrides the system supplied cache directory (NULL or /qcache)
1793 // -cachedir - will disable caching.
1795 i = COM_CheckParm ("-cachedir");
1796 if (i && i < com_argc-1)
1798 if (com_argv[i+1][0] == '-')
1799 com_cachedir[0] = 0;
1801 strcpy (com_cachedir, com_argv[i+1]);
1803 else if (host_parms.cachedir)
1804 strcpy (com_cachedir, host_parms.cachedir);
1806 com_cachedir[0] = 0;
1809 // start up with GAMENAME by default (id1)
1810 COM_AddGameDirectory (va("%s/"GAMENAME, basedir) );
1817 COM_AddGameDirectory (va("%s/hipnotic", basedir) );
1820 COM_AddGameDirectory (va("%s/rogue", basedir) );
1823 COM_AddGameDirectory (va("%s/nehahra", basedir) );
1825 case GAME_FIENDARENA:
1826 COM_AddGameDirectory (va("%s/fiendarena", basedir) );
1829 COM_AddGameDirectory (va("%s/zymotic", basedir) );
1832 Sys_Error("COM_InitFilesystem: unknown gamemode %i\n", gamemode);
1838 // Adds basedir/gamedir as an override game
1840 i = COM_CheckParm ("-game");
1841 if (i && i < com_argc-1)
1843 com_modified = true;
1844 COM_AddGameDirectory (va("%s/%s", basedir, com_argv[i+1]));
1848 // -path <dir or packfile> [<dir or packfile>] ...
1849 // Fully specifies the exact search path, overriding the generated one
1851 i = COM_CheckParm ("-path");
1854 com_modified = true;
1855 com_searchpaths = NULL;
1856 while (++i < com_argc)
1858 if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
1861 search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
1862 if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
1864 search->pack = COM_LoadPackFile (com_argv[i]);
1866 Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
1869 strcpy (search->filename, com_argv[i]);
1870 search->next = com_searchpaths;
1871 com_searchpaths = search;
1875 // if (COM_CheckParm ("-proghack"))
1879 int COM_FileExists(char *filename)
1881 searchpath_t *search;
1882 char netpath[MAX_OSPATH];
1887 for (search = com_searchpaths;search;search = search->next)
1892 for (i = 0;i < pak->numfiles;i++)
1893 if (!strcmp (pak->files[i].name, filename))
1898 sprintf (netpath, "%s/%s",search->filename, filename);
1899 findtime = Sys_FileTime (netpath);
1909 //======================================
1910 // LordHavoc: added these because they are useful
1912 void COM_ToLowerString(char *in, char *out)
1916 if (*in >= 'A' && *in <= 'Z')
1917 *out++ = *in++ + 'a' - 'A';
1923 void COM_ToUpperString(char *in, char *out)
1927 if (*in >= 'a' && *in <= 'z')
1928 *out++ = *in++ + 'A' - 'a';