]> de.git.xonotic.org Git - xonotic/darkplaces.git/blobdiff - common.c
Lots of str[n]cat, str[n]cpy, and [v]sprintf have been replaced by strlcat, strlcpy...
[xonotic/darkplaces.git] / common.c
index 584bd837881759c23879e48d1fbd64129613d3d1..7dab60b7760d462f426d3e542177b99c2c566d13 100644 (file)
--- a/common.c
+++ b/common.c
@@ -21,9 +21,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
 #include <stdlib.h>
 #include <fcntl.h>
-#ifdef WIN32
-#include <io.h>
-#else
+#ifndef WIN32
 #include <unistd.h>
 #endif
 
@@ -32,14 +30,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 cvar_t registered = {0, "registered","0"};
 cvar_t cmdline = {0, "cmdline","0"};
 
-mempool_t *pak_mempool;
-
-qboolean com_modified;   // set true if using non-id files
-
-void COM_InitFilesystem (void);
+extern qboolean fs_modified;   // set true if using non-id files
 
 char com_token[1024];
-char com_basedir[MAX_OSPATH];
 int com_argc;
 const char **com_argv;
 
@@ -52,70 +45,6 @@ char *gamename;
 char *gamedirname;
 char com_modname[MAX_OSPATH];
 
-/*
-
-
-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.
-
-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
-only used during filesystem initialization.
-
-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.
-
-The "cache directory" is only used during development to save network bandwidth, especially over ISDN / T1 lines.  If there is a cache directory
-specified, when a file is found by the normal search path, it will be mirrored
-into the cache directory, then opened there.
-
-
-
-FIXME:
-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.
-
-*/
-
-//============================================================================
-
-
-/*
-============================================================================
-
-                                       LIBRARY REPLACEMENT FUNCTIONS
-
-============================================================================
-*/
-
-int Q_strncasecmp (const char *s1, const char *s2, int n)
-{
-       int             c1, c2;
-
-       while (1)
-       {
-               c1 = *s1++;
-               c2 = *s2++;
-
-               if (!n--)
-                       return 0;               // strings are equal until end point
-
-               if (c1 != c2)
-               {
-                       if (c1 >= 'a' && c1 <= 'z')
-                               c1 -= ('a' - 'A');
-                       if (c2 >= 'a' && c2 <= 'z')
-                               c2 -= ('a' - 'A');
-                       if (c1 != c2)
-                               return -1;              // strings not equal
-               }
-               if (!c1)
-                       return 0;               // strings are equal
-       }
-
-       return -1;
-}
-
-int Q_strcasecmp (const char *s1, const char *s2)
-{
-       return Q_strncasecmp (s1, s2, 99999);
-}
 
 /*
 ============================================================================
@@ -194,6 +123,30 @@ float FloatNoSwap (float f)
 }
 #endif
 
+
+// Extract integers from buffers
+
+unsigned int BuffBigLong (const qbyte *buffer)
+{
+       return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
+}
+
+unsigned short BuffBigShort (const qbyte *buffer)
+{
+       return (buffer[0] << 8) | buffer[1];
+}
+
+unsigned int BuffLittleLong (const qbyte *buffer)
+{
+       return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
+}
+
+unsigned short BuffLittleShort (const qbyte *buffer)
+{
+       return (buffer[1] << 8) | buffer[0];
+}
+
+
 /*
 ==============================================================================
 
@@ -210,7 +163,7 @@ Handles byte ordering and avoids alignment errors
 void MSG_WriteChar (sizebuf_t *sb, int c)
 {
        qbyte    *buf;
-       
+
        buf = SZ_GetSpace (sb, 1);
        buf[0] = c;
 }
@@ -218,7 +171,7 @@ void MSG_WriteChar (sizebuf_t *sb, int c)
 void MSG_WriteByte (sizebuf_t *sb, int c)
 {
        qbyte    *buf;
-       
+
        buf = SZ_GetSpace (sb, 1);
        buf[0] = c;
 }
@@ -266,7 +219,7 @@ void MSG_WriteString (sizebuf_t *sb, const char *s)
                SZ_Write (sb, s, strlen(s)+1);
 }
 
-// used by server (always latest dpprotocol)
+// used by server (always latest PROTOCOL_DARKPLACES)
 void MSG_WriteDPCoord (sizebuf_t *sb, float f)
 {
        if (f >= 0)
@@ -304,61 +257,81 @@ void MSG_BeginReading (void)
        msg_badread = false;
 }
 
-int MSG_ReadShort (void)
+int MSG_ReadLittleShort (void)
 {
-       int c;
-
        if (msg_readcount+2 > net_message.cursize)
        {
                msg_badread = true;
                return -1;
        }
-
-       c = (short)(net_message.data[msg_readcount]
-       + (net_message.data[msg_readcount+1]<<8));
-
        msg_readcount += 2;
-
-       return c;
+       return (short)(net_message.data[msg_readcount-2] | (net_message.data[msg_readcount-1]<<8));
 }
 
-int MSG_ReadLong (void)
+int MSG_ReadBigShort (void)
 {
-       int c;
+       if (msg_readcount+2 > net_message.cursize)
+       {
+               msg_badread = true;
+               return -1;
+       }
+       msg_readcount += 2;
+       return (short)((net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1]);
+}
 
+int MSG_ReadLittleLong (void)
+{
        if (msg_readcount+4 > net_message.cursize)
        {
                msg_badread = true;
                return -1;
        }
-
-       c = net_message.data[msg_readcount]
-       + (net_message.data[msg_readcount+1]<<8)
-       + (net_message.data[msg_readcount+2]<<16)
-       + (net_message.data[msg_readcount+3]<<24);
-
        msg_readcount += 4;
+       return net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
+}
 
-       return c;
+int MSG_ReadBigLong (void)
+{
+       if (msg_readcount+4 > net_message.cursize)
+       {
+               msg_badread = true;
+               return -1;
+       }
+       msg_readcount += 4;
+       return (net_message.data[msg_readcount-4]<<24) + (net_message.data[msg_readcount-3]<<16) + (net_message.data[msg_readcount-2]<<8) + net_message.data[msg_readcount-1];
 }
 
-float MSG_ReadFloat (void)
+float MSG_ReadLittleFloat (void)
 {
        union
        {
-               qbyte b[4];
                float f;
                int l;
        } dat;
-
-       dat.b[0] =      net_message.data[msg_readcount];
-       dat.b[1] =      net_message.data[msg_readcount+1];
-       dat.b[2] =      net_message.data[msg_readcount+2];
-       dat.b[3] =      net_message.data[msg_readcount+3];
+       if (msg_readcount+4 > net_message.cursize)
+       {
+               msg_badread = true;
+               return -1;
+       }
        msg_readcount += 4;
+       dat.l = net_message.data[msg_readcount-4] | (net_message.data[msg_readcount-3]<<8) | (net_message.data[msg_readcount-2]<<16) | (net_message.data[msg_readcount-1]<<24);
+       return dat.f;
+}
 
-       dat.l = LittleLong (dat.l);
-
+float MSG_ReadBigFloat (void)
+{
+       union
+       {
+               float f;
+               int l;
+       } dat;
+       if (msg_readcount+4 > net_message.cursize)
+       {
+               msg_badread = true;
+               return -1;
+       }
+       msg_readcount += 4;
+       dat.l = (net_message.data[msg_readcount-4]<<24) | (net_message.data[msg_readcount-3]<<16) | (net_message.data[msg_readcount-2]<<8) | net_message.data[msg_readcount-1];
        return dat.f;
 }
 
@@ -366,37 +339,35 @@ char *MSG_ReadString (void)
 {
        static char string[2048];
        int l,c;
-
-       l = 0;
-       do
-       {
-               c = MSG_ReadChar ();
-               if (c == -1 || c == 0)
-                       break;
+       for (l = 0;l < (int) sizeof(string) - 1 && (c = MSG_ReadChar()) != -1 && c != 0;l++)
                string[l] = c;
-               l++;
-       } while (l < (int)sizeof(string)-1);
-
        string[l] = 0;
-
        return string;
 }
 
-// used by server (always latest dpprotocol)
+int MSG_ReadBytes (int numbytes, unsigned char *out)
+{
+       int l, c;
+       for (l = 0;l < numbytes && (c = MSG_ReadChar()) != -1;l++)
+               out[l] = c;
+       return l;
+}
+
+// used by server (always latest PROTOCOL_DARKPLACES)
 float MSG_ReadDPCoord (void)
 {
-       return (signed short) MSG_ReadShort();
+       return (signed short) MSG_ReadLittleShort();
 }
 
 // used by client
 float MSG_ReadCoord (void)
 {
-       if (dpprotocol == DPPROTOCOL_VERSION2 || dpprotocol == DPPROTOCOL_VERSION3)
-               return (signed short) MSG_ReadShort();
-       else if (dpprotocol == DPPROTOCOL_VERSION1)
-               return MSG_ReadFloat();
+       if (cl.protocol == PROTOCOL_DARKPLACES2 || cl.protocol == PROTOCOL_DARKPLACES3 || cl.protocol == PROTOCOL_DARKPLACES4)
+               return (signed short) MSG_ReadLittleShort();
+       else if (cl.protocol == PROTOCOL_DARKPLACES1)
+               return MSG_ReadLittleFloat();
        else
-               return MSG_ReadShort() * (1.0f/8.0f);
+               return MSG_ReadLittleShort() * (1.0f/8.0f);
 }
 
 
@@ -467,158 +438,65 @@ void SZ_Print (sizebuf_t *buf, const char *data)
 }
 
 static char *hexchar = "0123456789ABCDEF";
-void SZ_HexDumpToConsole(const sizebuf_t *buf)
+void Com_HexDumpToConsole(const qbyte *data, int size)
 {
-       int i;
+       int i, j, n;
        char text[1024];
        char *cur, *flushpointer;
+       const qbyte *d;
        cur = text;
        flushpointer = text + 512;
-       for (i = 0;i < buf->cursize;i++)
-       {
-               if ((i & 15) == 0)
-               {
-                       *cur++ = hexchar[(i >> 12) & 15];
-                       *cur++ = hexchar[(i >>  8) & 15];
-                       *cur++ = hexchar[(i >>  4) & 15];
-                       *cur++ = hexchar[(i >>  0) & 15];
-                       *cur++ = ':';
-                       *cur++ = ' ';
-               }
-               else if ((i & 15) == 15)
-                       *cur++ = '\n';
-               else
-                       *cur++ = ' ';
-               if (i & 1)
+       for (i = 0;i < size;)
+       {
+               n = 16;
+               if (n > size - i)
+                       n = size - i;
+               d = data + i;
+               *cur++ = hexchar[(i >> 12) & 15];
+               *cur++ = hexchar[(i >>  8) & 15];
+               *cur++ = hexchar[(i >>  4) & 15];
+               *cur++ = hexchar[(i >>  0) & 15];
+               *cur++ = ':';
+               for (j = 0;j < n;j++)
                {
-                       *cur++ = hexchar[(buf->data[i] >> 4) & 15] | 0x80;
-                       *cur++ = hexchar[(buf->data[i] >> 0) & 15] | 0x80;
+                       if (j & 1)
+                       {
+                               *cur++ = hexchar[(d[j] >> 4) & 15] | 0x80;
+                               *cur++ = hexchar[(d[j] >> 0) & 15] | 0x80;
+                       }
+                       else
+                       {
+                               *cur++ = hexchar[(d[j] >> 4) & 15];
+                               *cur++ = hexchar[(d[j] >> 0) & 15];
+                       }
                }
-               else
+               for (;j < 16;j++)
                {
-                       *cur++ = hexchar[(buf->data[i] >> 4) & 15];
-                       *cur++ = hexchar[(buf->data[i] >> 0) & 15];
+                       *cur++ = ' ';
+                       *cur++ = ' ';
                }
-               if (cur >= flushpointer)
+               for (j = 0;j < n;j++)
+                       *cur++ = (d[j] >= ' ' && d[j] <= 0x7E) ? d[j] : '.';
+               for (;j < 16;j++)
+                       *cur++ = ' ';
+               *cur++ = '\n';
+               i += n;
+               if (cur >= flushpointer || i >= size)
                {
                        *cur++ = 0;
                        Con_Printf("%s", text);
                        cur = text;
                }
        }
-       if ((i & 15) != 0)
-               *cur++ = '\n';
-       if (cur > text)
-       {
-               *cur++ = 0;
-               Con_Printf("%s", text);
-       }
 }
 
-
-//============================================================================
-
-
-/*
-============
-COM_StripExtension
-============
-*/
-// LordHavoc: replacement for severely broken COM_StripExtension that was used in original quake.
-void COM_StripExtension (const char *in, char *out)
-{
-       char *last = NULL;
-       while (*in)
-       {
-               if (*in == '.')
-                       last = out;
-               else if (*in == '/' || *in == '\\' || *in == ':')
-                       last = NULL;
-               *out++ = *in++;
-       }
-       if (last)
-               *last = 0;
-       else
-               *out = 0;
-}
-
-/*
-============
-COM_FileExtension
-============
-*/
-char *COM_FileExtension (const char *in)
-{
-       static char exten[8];
-       int i;
-
-       while (*in && *in != '.')
-               in++;
-       if (!*in)
-               return "";
-       in++;
-       for (i=0 ; i<7 && *in ; i++,in++)
-               exten[i] = *in;
-       exten[i] = 0;
-       return exten;
-}
-
-/*
-============
-COM_FileBase
-============
-*/
-void COM_FileBase (const char *in, char *out)
+void SZ_HexDumpToConsole(const sizebuf_t *buf)
 {
-       const char *slash, *dot, *s;
-
-       slash = in;
-       dot = NULL;
-       s = in;
-       while(*s)
-       {
-               if (*s == '/')
-                       slash = s + 1;
-               if (*s == '.')
-                       dot = s;
-               s++;
-       }
-       if (dot == NULL)
-               dot = s;
-       if (dot - slash < 2)
-               strcpy (out,"?model?");
-       else
-       {
-               while (slash < dot)
-                       *out++ = *slash++;
-               *out++ = 0;
-       }
+       Com_HexDumpToConsole(buf->data, buf->cursize);
 }
 
 
-/*
-==================
-COM_DefaultExtension
-==================
-*/
-void COM_DefaultExtension (char *path, const char *extension)
-{
-       const char *src;
-//
-// if path doesn't have a .EXT, append extension
-// (extension should include the .)
-//
-       src = path + strlen(path) - 1;
-
-       while (*src != '/' && src != path)
-       {
-               if (*src == '.')
-                       return;                 // it has an extension
-               src--;
-       }
-
-       strcat (path, extension);
-}
+//============================================================================
 
 
 /*
@@ -628,7 +506,7 @@ COM_ParseToken
 Parse a token out of a string
 ==============
 */
-int COM_ParseToken (const char **datapointer)
+int COM_ParseToken(const char **datapointer, int returnnewline)
 {
        int c;
        int len;
@@ -645,7 +523,7 @@ int COM_ParseToken (const char **datapointer)
 
 // skip whitespace
 skipwhite:
-       while ((c = *data) <= ' ')
+       while ((c = *data) <= ' ' && (c != '\n' || !returnnewline))
        {
                if (c == 0)
                {
@@ -656,15 +534,25 @@ skipwhite:
                data++;
        }
 
-// skip // comments
-       if (c=='/' && data[1] == '/')
+       // check if it's a comment
+       if (c == '/')
        {
-               while (*data && *data != '\n')
-                       data++;
-               goto skipwhite;
+               // skip // comments
+               if (data[1] == '/')
+               {
+                       while (*data && *data != '\n')
+                               data++;
+                       goto skipwhite;
+               }
+               // skip /* comments
+               if (data[1] == '*')
+               {
+                       while (*data && *data != '*' && data[1] != '/')
+                               data++;
+                       goto skipwhite;
+               }
        }
 
-
 // handle quoted strings specially
        if (c == '\"')
        {
@@ -672,7 +560,7 @@ skipwhite:
                while (1)
                {
                        c = *data++;
-                       if (c=='\"' || !c)
+                       if (c == '\"' || !c)
                        {
                                com_token[len] = 0;
                                *datapointer = data;
@@ -684,7 +572,7 @@ skipwhite:
        }
 
 // parse single characters
-       if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
+       if (c == '{' || c == '}' || c == ')' || c == '(' || c == ']' || c == '[' || c == '\'' || c == ':' || c == ',' || c == ';' || c == '\n')
        {
                com_token[len] = c;
                len++;
@@ -700,7 +588,7 @@ skipwhite:
                data++;
                len++;
                c = *data;
-               if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
+               if (c == '{' || c == '}' || c == ')' || c == '(' || c == ']' || c == '[' || c == '\'' || c == ':' || c == ',' || c == ';')
                        break;
        } while (c>32);
 
@@ -747,9 +635,9 @@ void COM_CheckRegistered (void)
 {
        Cvar_Set ("cmdline", com_cmdline);
 
-       if (!Sys_FileTime("gfx/pop.lmp"))
+       if (!FS_FileExists("gfx/pop.lmp"))
        {
-               if (com_modified)
+               if (fs_modified)
                        Con_Printf ("Playing shareware version, with modification.\nwarning: most mods require full quake data.\n");
                else
                        Con_Printf ("Playing shareware version.\n");
@@ -761,9 +649,6 @@ void COM_CheckRegistered (void)
 }
 
 
-void COM_Path_f (void);
-
-
 /*
 ================
 COM_InitArgv
@@ -790,22 +675,34 @@ void COM_InitArgv (void)
 void COM_InitGameType (void)
 {
        char name[MAX_OSPATH];
-       COM_StripExtension(com_argv[0], name);
+       FS_StripExtension(com_argv[0], name);
        COM_ToLowerString(name, name);
 
        if (strstr(name, "transfusion"))
                gamemode = GAME_TRANSFUSION;
+       else if (strstr(name, "nexuiz"))
+               gamemode = GAME_NEXUIZ;
        else if (strstr(name, "nehahra"))
                gamemode = GAME_NEHAHRA;
        else if (strstr(name, "hipnotic"))
                gamemode = GAME_HIPNOTIC;
        else if (strstr(name, "rogue"))
                gamemode = GAME_ROGUE;
+       else if (strstr(name, "gvb2"))
+               gamemode = GAME_GOODVSBAD2;
+       else if (strstr(name, "teu"))
+               gamemode = GAME_TEU;
+       else if (strstr(name, "battlemech"))
+               gamemode = GAME_BATTLEMECH;
+       else if (strstr(name, "zymotic"))
+               gamemode = GAME_ZYMOTIC;
        else
                gamemode = GAME_NORMAL;
 
        if (COM_CheckParm ("-transfusion"))
                gamemode = GAME_TRANSFUSION;
+       else if (COM_CheckParm ("-nexuiz"))
+               gamemode = GAME_NEXUIZ;
        else if (COM_CheckParm ("-nehahra"))
                gamemode = GAME_NEHAHRA;
        else if (COM_CheckParm ("-hipnotic"))
@@ -814,6 +711,14 @@ void COM_InitGameType (void)
                gamemode = GAME_ROGUE;
        else if (COM_CheckParm ("-quake"))
                gamemode = GAME_NORMAL;
+       else if (COM_CheckParm ("-goodvsbad2"))
+               gamemode = GAME_GOODVSBAD2;
+       else if (COM_CheckParm ("-teu"))
+               gamemode = GAME_TEU;
+       else if (COM_CheckParm ("-battlemech"))
+               gamemode = GAME_BATTLEMECH;
+       else if (COM_CheckParm ("-zymotic"))
+               gamemode = GAME_ZYMOTIC;
 
        switch(gamemode)
        {
@@ -833,10 +738,30 @@ void COM_InitGameType (void)
                gamename = "DarkPlaces-Nehahra";
                gamedirname = "nehahra";
                break;
+       case GAME_NEXUIZ:
+               gamename = "Nexuiz";
+               gamedirname = "data";
+               break;
        case GAME_TRANSFUSION:
                gamename = "Transfusion";
                gamedirname = "transfusion";
                break;
+       case GAME_GOODVSBAD2:
+               gamename = "GoodVs.Bad2";
+               gamedirname = "rts";
+               break;
+       case GAME_TEU:
+               gamename = "TheEvilUnleashed";
+               gamedirname = "baseteu";
+               break;
+       case GAME_BATTLEMECH:
+               gamename = "Battlemech";
+               gamedirname = "base";
+               break;
+       case GAME_ZYMOTIC:
+               gamename = "Zymotic";
+               gamedirname = "data";
+               break;
        default:
                Sys_Error("COM_InitGameType: unknown gamemode %i\n", gamemode);
                break;
@@ -845,6 +770,7 @@ void COM_InitGameType (void)
 
 
 extern void Mathlib_Init(void);
+extern void FS_Init (void);
 
 /*
 ================
@@ -877,15 +803,13 @@ void COM_Init (void)
        }
 #endif
 
-       pak_mempool = Mem_AllocPool("paks");
-
        Cvar_RegisterVariable (&registered);
        Cvar_RegisterVariable (&cmdline);
-       Cmd_AddCommand ("path", COM_Path_f);
 
        Mathlib_Init();
 
-       COM_InitFilesystem ();
+       FS_Init ();
+       Con_InitLogging();
        COM_CheckRegistered ();
 
        COM_InitGameType();
@@ -911,625 +835,187 @@ char *va(const char *format, ...)
        s = string[stringindex];
        stringindex = (stringindex + 1) & 7;
        va_start (argptr, format);
-       vsprintf (s, format,argptr);
+       vsnprintf (s, sizeof (string[0]), format,argptr);
        va_end (argptr);
 
        return s;
 }
 
 
-/*
-=============================================================================
-
-QUAKE FILESYSTEM
-
-=============================================================================
-*/
-
-int com_filesize;
-
-
-//
-// in memory
-//
-
-typedef struct
-{
-       char name[MAX_QPATH];
-       int filepos, filelen;
-} packfile_t;
-
-typedef struct pack_s
-{
-       char filename[MAX_OSPATH];
-       int handle;
-       int numfiles;
-       packfile_t *files;
-       mempool_t *mempool;
-       struct pack_s *next;
-} pack_t;
-
-//
-// on disk
-//
-typedef struct
-{
-       char name[56];
-       int filepos, filelen;
-} dpackfile_t;
-
-typedef struct
-{
-       char id[4];
-       int dirofs;
-       int dirlen;
-} dpackheader_t;
-
-// LordHavoc: was 2048, increased to 65536 and changed info[MAX_PACK_FILES] to a temporary alloc
-#define MAX_FILES_IN_PACK       65536
-
-pack_t *packlist = NULL;
-
-#if CACHEENABLE
-char com_cachedir[MAX_OSPATH];
-#endif
-char com_gamedir[MAX_OSPATH];
-
-typedef struct searchpath_s
-{
-       // only one of filename / pack will be used
-       char filename[MAX_OSPATH];
-       pack_t *pack;
-       struct searchpath_s *next;
-} searchpath_t;
-
-searchpath_t *com_searchpaths;
-
-/*
-============
-COM_Path_f
+//======================================
+// LordHavoc: added these because they are useful
 
-============
-*/
-void COM_Path_f (void)
+void COM_ToLowerString(const char *in, char *out)
 {
-       searchpath_t *s;
-
-       Con_Printf ("Current search path:\n");
-       for (s=com_searchpaths ; s ; s=s->next)
+       while (*in)
        {
-               if (s->pack)
-               {
-                       Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
-               }
+               if (*in >= 'A' && *in <= 'Z')
+                       *out++ = *in++ + 'a' - 'A';
                else
-                       Con_Printf ("%s\n", s->filename);
+                       *out++ = *in++;
        }
 }
 
-/*
-============
-COM_CreatePath
-
-LordHavoc: Previously only used for CopyFile, now also used for COM_WriteFile.
-============
-*/
-void    COM_CreatePath (char *path)
+void COM_ToUpperString(const char *in, char *out)
 {
-       char *ofs, save;
-
-       for (ofs = path+1 ; *ofs ; ofs++)
+       while (*in)
        {
-               if (*ofs == '/' || *ofs == '\\')
-               {
-                       // create the directory
-                       save = *ofs;
-                       *ofs = 0;
-                       Sys_mkdir (path);
-                       *ofs = save;
-               }
+               if (*in >= 'a' && *in <= 'z')
+                       *out++ = *in++ + 'A' - 'a';
+               else
+                       *out++ = *in++;
        }
 }
 
-
-/*
-============
-COM_WriteFile
-
-The filename will be prefixed by the current game directory
-============
-*/
-qboolean COM_WriteFile (const char *filename, void *data, int len)
+int COM_StringBeginsWith(const char *s, const char *match)
 {
-       int handle;
-       char name[MAX_OSPATH];
-
-       sprintf (name, "%s/%s", com_gamedir, filename);
-
-       // LordHavoc: added this
-       // create directories up to the file
-       COM_CreatePath (name);
-
-       handle = Sys_FileOpenWrite (name);
-       if (handle == -1)
-       {
-               Con_Printf ("COM_WriteFile: failed on %s\n", name);
-               return false;
-       }
-
-       Con_DPrintf ("COM_WriteFile: %s\n", name);
-       Sys_FileWrite (handle, data, len);
-       Sys_FileClose (handle);
+       for (;*s && *match;s++, match++)
+               if (*s != *match)
+                       return false;
        return true;
 }
 
-
-/*
-===========
-COM_CopyFile
-
-Copies a file over from the net to the local cache, creating any directories
-needed.  This is for the convenience of developers using ISDN from home.
-===========
-*/
-void COM_CopyFile (char *netpath, char *cachepath)
+// written by Elric, thanks Elric!
+char *SearchInfostring(const char *infostring, const char *key)
 {
-       int in, out, remaining, count;
-       char buf[4096];
+       static char value [256];
+       char crt_key [256];
+       size_t value_ind, key_ind;
+       char c;
 
-       remaining = Sys_FileOpenRead (netpath, &in);
-       COM_CreatePath (cachepath);     // create directories up to the cache file
-       out = Sys_FileOpenWrite (cachepath);
+       if (*infostring++ != '\\')
+               return NULL;
 
-       while (remaining)
+       value_ind = 0;
+       for (;;)
        {
-               if (remaining < (int)sizeof(buf))
-                       count = remaining;
-               else
-                       count = sizeof(buf);
-               Sys_FileRead (in, buf, count);
-               Sys_FileWrite (out, buf, count);
-               remaining -= count;
-       }
-
-       Sys_FileClose (in);
-       Sys_FileClose (out);
-}
+               key_ind = 0;
 
-/*
-===========
-COM_OpenRead
-===========
-*/
-QFile * COM_OpenRead (const char *path, int offs, int len, qboolean zip)
-{
-       int fd = open (path, O_RDONLY);
-       unsigned char id[2], len_bytes[4];
-
-       if (fd == -1)
-       {
-               Sys_Error ("Couldn't open %s", path);
-               return 0;
-       }
-       if (offs < 0 || len < 0)
-       {
-               // normal file
-               offs = 0;
-               len = lseek (fd, 0, SEEK_END);
-               lseek (fd, 0, SEEK_SET);
-       }
-       lseek (fd, offs, SEEK_SET);
-       if (zip)
-       {
-               read (fd, id, 2);
-               if (id[0] == 0x1f && id[1] == 0x8b)
+               // Get the key name
+               for (;;)
                {
-                       lseek (fd, offs + len - 4, SEEK_SET);
-                       read (fd, len_bytes, 4);
-                       len = ((len_bytes[3] << 24)
-                                  | (len_bytes[2] << 16)
-                                  | (len_bytes[1] << 8)
-                                  | (len_bytes[0]));
-               }
-       }
-       lseek (fd, offs, SEEK_SET);
-       com_filesize = len;
-
-#ifdef WIN32
-       setmode (fd, O_BINARY);
-#endif
-       if (zip)
-               return Qdopen (fd, "rbz");
-       else
-               return Qdopen (fd, "rb");
-}
-
-/*
-===========
-COM_FindFile
+                       c = *infostring++;
 
-Finds the file in the search path.
-Sets com_filesize and one of handle or file
-===========
-*/
-int COM_FindFile (const char *filename, QFile **file, qboolean quiet, qboolean zip)
-{
-       searchpath_t *search;
-       char netpath[MAX_OSPATH];
-#if CACHEENABLE
-       char cachepath[MAX_OSPATH];
-       int cachetime;
-#endif
-       pack_t *pak;
-       int i, findtime, filenamelen;
-       char gzfilename[MAX_OSPATH];
-
-       filenamelen = strlen (filename);
-       sprintf (gzfilename, "%s.gz", filename);
-
-       if (!file)
-               Sys_Error ("COM_FindFile: file not set");
-
-//
-// search through the path, one element at a time
-//
-       search = com_searchpaths;
+                       if (c == '\0')
+                               return NULL;
+                       if (c == '\\' || key_ind == sizeof (crt_key) - 1)
+                       {
+                               crt_key[key_ind] = '\0';
+                               break;
+                       }
 
-       for ( ; search ; search = search->next)
-       {
-       // is the element a pak file?
-               if (search->pack)
-               {
-               // look through all the pak file elements
-                       pak = search->pack;
-                       for (i=0 ; i<pak->numfiles ; i++)
-                               if (!strcmp (pak->files[i].name, filename)
-                                   || !strcmp (pak->files[i].name, gzfilename))
-                               {       // found it!
-                                       if (!quiet)
-                                               Sys_Printf ("PackFile: %s : %s\n",pak->filename, pak->files[i].name);
-                                       // open a new file on the pakfile
-                                       *file = COM_OpenRead (pak->filename, pak->files[i].filepos, pak->files[i].filelen, zip);
-                                       return com_filesize;
-                               }
+                       crt_key[key_ind++] = c;
                }
-               else
-               {
-                       sprintf (netpath, "%s/%s",search->filename, filename);
 
-                       findtime = Sys_FileTime (netpath);
-                       if (findtime == -1)
-                               continue;
-
-#if CACHEENABLE
-                       // see if the file needs to be updated in the cache
-                       if (com_cachedir[0])
+               // If it's the key we are looking for, save it in "value"
+               if (!strcmp(crt_key, key))
+               {
+                       for (;;)
                        {
-#if defined(_WIN32)
-                               if ((strlen(netpath) < 2) || (netpath[1] != ':'))
-                                       sprintf (cachepath,"%s%s", com_cachedir, netpath);
-                               else
-                                       sprintf (cachepath,"%s%s", com_cachedir, netpath+2);
-#else
-                               sprintf (cachepath,"%s%s", com_cachedir, netpath);
-#endif
+                               c = *infostring++;
 
-                               cachetime = Sys_FileTime (cachepath);
+                               if (c == '\0' || c == '\\' || value_ind == sizeof (value) - 1)
+                               {
+                                       value[value_ind] = '\0';
+                                       return value;
+                               }
 
-                               if (cachetime < findtime)
-                                       COM_CopyFile (netpath, cachepath);
-                               strcpy (netpath, cachepath);
+                               value[value_ind++] = c;
                        }
-#endif
-                       if (!quiet)
-                               Sys_Printf ("FindFile: %s\n",netpath);
-                       *file = COM_OpenRead (netpath, -1, -1, zip);
-                       return com_filesize;
                }
-       }
-
-       if (!quiet)
-               Sys_Printf ("FindFile: can't find %s\n", filename);
-
-       *file = NULL;
-       com_filesize = -1;
-       return -1;
-}
-
-
-/*
-===========
-COM_FOpenFile
-
-If the requested file is inside a packfile, a new QFile * will be opened
-into the file.
-===========
-*/
-int COM_FOpenFile (const char *filename, QFile **file, qboolean quiet, qboolean zip)
-{
-       return COM_FindFile (filename, file, quiet, zip);
-}
-
-
-/*
-============
-COM_LoadFile
-
-Filename are reletive to the quake directory.
-Always appends a 0 byte.
-============
-*/
-qbyte *loadbuf;
-int loadsize;
-qbyte *COM_LoadFile (const char *path, qboolean quiet)
-{
-       QFile *h;
-       qbyte *buf;
-       char base[1024];
-       int len;
 
-       buf = NULL;     // quiet compiler warning
-       loadsize = 0;
-
-// look for it in the filesystem or pack files
-       len = COM_FOpenFile (path, &h, quiet, true);
-       if (!h)
-               return NULL;
-
-       loadsize = len;
-
-// extract the filename base name for hunk tag
-       COM_FileBase (path, base);
-
-       buf = Mem_Alloc(tempmempool, len+1);
-       if (!buf)
-               Sys_Error ("COM_LoadFile: not enough available memory for %s (size %i)", path, len);
-
-       ((qbyte *)buf)[len] = 0;
-
-       Qread (h, buf, len);
-       Qclose (h);
-
-       return buf;
-}
-
-/*
-=================
-COM_LoadPackFile
-
-Takes an explicit (not game tree related) path to a pak file.
-
-Loads the header and directory, adding the files at the beginning
-of the list so they override previous pack files.
-=================
-*/
-pack_t *COM_LoadPackFile (const char *packfile)
-{
-       dpackheader_t header;
-       int i, numpackfiles, packhandle;
-       pack_t *pack;
-       // LordHavoc: changed from stack array to temporary alloc, allowing huge pack directories
-       dpackfile_t *info;
-
-       if (Sys_FileOpenRead (packfile, &packhandle) == -1)
-               return NULL;
-
-       Sys_FileRead (packhandle, (void *)&header, sizeof(header));
-       if (memcmp(header.id, "PACK", 4))
-               Sys_Error ("%s is not a packfile", packfile);
-       header.dirofs = LittleLong (header.dirofs);
-       header.dirlen = LittleLong (header.dirlen);
-
-       if (header.dirlen % sizeof(dpackfile_t))
-               Sys_Error ("%s has an invalid directory size", packfile);
-
-       numpackfiles = header.dirlen / sizeof(dpackfile_t);
-
-       if (numpackfiles > MAX_FILES_IN_PACK)
-               Sys_Error ("%s has %i files", packfile, numpackfiles);
-
-       pack = Mem_Alloc(pak_mempool, sizeof (pack_t));
-       strcpy (pack->filename, packfile);
-       pack->handle = packhandle;
-       pack->numfiles = numpackfiles;
-       pack->mempool = Mem_AllocPool(packfile);
-       pack->files = Mem_Alloc(pack->mempool, numpackfiles * sizeof(packfile_t));
-       pack->next = packlist;
-       packlist = pack;
-
-       info = Mem_Alloc(tempmempool, sizeof(*info) * numpackfiles);
-       Sys_FileSeek (packhandle, header.dirofs);
-       Sys_FileRead (packhandle, (void *)info, header.dirlen);
-
-// parse the directory
-       for (i = 0;i < numpackfiles;i++)
-       {
-               strcpy (pack->files[i].name, info[i].name);
-               pack->files[i].filepos = LittleLong(info[i].filepos);
-               pack->files[i].filelen = LittleLong(info[i].filelen);
-       }
-
-       Mem_Free(info);
-
-       Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
-       return pack;
-}
-
-
-/*
-================
-COM_AddGameDirectory
-
-Sets com_gamedir, adds the directory to the head of the path,
-then loads and adds pak1.pak pak2.pak ...
-================
-*/
-void COM_AddGameDirectory (char *dir)
-{
-       stringlist_t *list, *current;
-       searchpath_t *search;
-       pack_t *pak;
-       char pakfile[MAX_OSPATH];
-
-       strcpy (com_gamedir, dir);
-
-//
-// add the directory to the search path
-//
-       search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
-       strcpy (search->filename, dir);
-       search->next = com_searchpaths;
-       com_searchpaths = search;
-
-       // add any paks in the directory
-       list = listdirectory(dir);
-       for (current = list;current;current = current->next)
-       {
-               if (matchpattern(current->text, "*.pak", true))
+               // Else, skip the value
+               for (;;)
                {
-                       sprintf (pakfile, "%s/%s", dir, current->text);
-                       pak = COM_LoadPackFile (pakfile);
-                       if (pak)
-                       {
-                               search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
-                               search->pack = pak;
-                               search->next = com_searchpaths;
-                               com_searchpaths = search;
-                       }
-                       else
-                               Con_Printf("unable to load pak \"%s\"\n", pakfile);
-               }
-       }
-       freedirectory(list);
-}
-
-/*
-================
-COM_InitFilesystem
-================
-*/
-void COM_InitFilesystem (void)
-{
-       int i;
-       searchpath_t *search;
+                       c = *infostring++;
 
-       strcpy(com_basedir, ".");
-
-       // -basedir <path>
-       // Overrides the system supplied base directory (under GAMENAME)
-       i = COM_CheckParm ("-basedir");
-       if (i && i < com_argc-1)
-               strcpy (com_basedir, com_argv[i+1]);
-
-       i = strlen (com_basedir);
-       if (i > 0 && (com_basedir[i-1] == '\\' || com_basedir[i-1] == '/'))
-               com_basedir[i-1] = 0;
-
-// start up with GAMENAME by default (id1)
-       strcpy(com_modname, GAMENAME);
-       COM_AddGameDirectory (va("%s/"GAMENAME, com_basedir));
-       if (gamedirname[0])
-       {
-               com_modified = true;
-               strcpy(com_modname, gamedirname);
-               COM_AddGameDirectory (va("%s/%s", com_basedir, gamedirname));
-       }
-
-       // -game <gamedir>
-       // Adds basedir/gamedir as an override game
-       i = COM_CheckParm ("-game");
-       if (i && i < com_argc-1)
-       {
-               com_modified = true;
-               strcpy(com_modname, com_argv[i+1]);
-               COM_AddGameDirectory (va("%s/%s", com_basedir, com_argv[i+1]));
-       }
-
-       // -path <dir or packfile> [<dir or packfile>] ...
-       // Fully specifies the exact search path, overriding the generated one
-       i = COM_CheckParm ("-path");
-       if (i)
-       {
-               com_modified = true;
-               com_searchpaths = NULL;
-               while (++i < com_argc)
-               {
-                       if (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')
+                       if (c == '\0')
+                               return NULL;
+                       if (c == '\\')
                                break;
-
-                       search = Mem_Alloc(pak_mempool, sizeof(searchpath_t));
-                       if ( !strcmp(COM_FileExtension(com_argv[i]), "pak") )
-                       {
-                               search->pack = COM_LoadPackFile (com_argv[i]);
-                               if (!search->pack)
-                                       Sys_Error ("Couldn't load packfile: %s", com_argv[i]);
-                       }
-                       else
-                               strcpy (search->filename, com_argv[i]);
-                       search->next = com_searchpaths;
-                       com_searchpaths = search;
                }
        }
 }
 
-int COM_FileExists(const char *filename)
-{
-       searchpath_t *search;
-       char netpath[MAX_OSPATH];
-       pack_t *pak;
-       int i, findtime;
 
-       for (search = com_searchpaths;search;search = search->next)
-       {
-               if (search->pack)
-               {
-                       pak = search->pack;
-                       for (i = 0;i < pak->numfiles;i++)
-                               if (!strcmp (pak->files[i].name, filename))
-                                       return true;
-               }
-               else
-               {
-                       sprintf (netpath, "%s/%s",search->filename, filename);
-                       findtime = Sys_FileTime (netpath);
-                       if (findtime != -1)
-                               return true;
+//========================================================
+// strlcat and strlcpy, from OpenBSD
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*     $OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $    */
+/*     $OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $     */
+
+
+// Most (all?) BSDs already have them
+#if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__)
+
+size_t
+strlcat(char *dst, const char *src, size_t siz)
+{
+       register char *d = dst;
+       register const char *s = src;
+       register size_t n = siz;
+       size_t dlen;
+
+       /* Find the end of dst and adjust bytes left but don't go past end */
+       while (n-- != 0 && *d != '\0')
+               d++;
+       dlen = d - dst;
+       n = siz - dlen;
+
+       if (n == 0)
+               return(dlen + strlen(s));
+       while (*s != '\0') {
+               if (n != 1) {
+                       *d++ = *s;
+                       n--;
                }
+               s++;
        }
+       *d = '\0';
 
-       return false;
+       return(dlen + (s - src));       /* count does not include NUL */
 }
 
-
-//======================================
-// LordHavoc: added these because they are useful
-
-void COM_ToLowerString(const char *in, char *out)
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
 {
-       while (*in)
-       {
-               if (*in >= 'A' && *in <= 'Z')
-                       *out++ = *in++ + 'a' - 'A';
-               else
-                       *out++ = *in++;
+       register char *d = dst;
+       register const char *s = src;
+       register size_t n = siz;
+
+       /* Copy as many bytes as will fit */
+       if (n != 0 && --n != 0) {
+               do {
+                       if ((*d++ = *s++) == 0)
+                               break;
+               } while (--n != 0);
        }
-}
 
-void COM_ToUpperString(const char *in, char *out)
-{
-       while (*in)
-       {
-               if (*in >= 'a' && *in <= 'z')
-                       *out++ = *in++ + 'A' - 'a';
-               else
-                       *out++ = *in++;
+       /* Not enough room in dst, add NUL and traverse rest of src */
+       if (n == 0) {
+               if (siz != 0)
+                       *d = '\0';              /* NUL-terminate dst */
+               while (*s++)
+                       ;
        }
-}
 
-int COM_StringBeginsWith(const char *s, const char *match)
-{
-       for (;*s && *match;s++, match++)
-               if (*s != *match)
-                       return false;
-       return true;
+       return(s - src - 1);    /* count does not include NUL */
 }
+
+#endif  // #if !defined(__OpenBSD__) && !defined(__NetBSD__) && !defined(__FreeBSD__)