nuq-svga now links

This commit is contained in:
Bill Currie 2000-08-23 05:53:17 +00:00
parent 9f8660c30e
commit 7b52e8b908
13 changed files with 2519 additions and 2026 deletions

View file

@ -49,6 +49,8 @@ common_ASM= sys_ia32.S worlda.S $(math_ASM)
#endif
common_SOURCES= crc.c cvar.c cmd.c mathlib.c wad.c world.c \
msg.c sizebuf.c qendian.c qargs.c quakefs.c \
va.c quakeio.c link.c com.c \
zone.c $(common_ASM)
#

View file

@ -1,7 +1,7 @@
/*
cmd.c
@description@
script command processing module
Copyright (C) 1996-1997 Id Software, Inc.
@ -27,22 +27,27 @@
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
# include <config.h>
#endif
#include <string.h>
#include <ctype.h>
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <stdlib.h>
#include "cmd.h"
#include "host.h"
#include "client.h"
#include "msg.h"
#include "quakefs.h"
#include "qargs.h"
#include "zone.h"
#include "console.h"
#include "sys.h"
#include "sizebuf.h"
#include "cmd.h"
#include "cvar.h"
#include "sizebuf.h"
#include "console.h"
#include "host.h"
#include "qargs.h"
#include "quakefs.h"
#include "zone.h"
#include "client.h"
void Cmd_ForwardToServer (void);
@ -56,12 +61,10 @@ typedef struct cmdalias_s
} cmdalias_t;
cmdalias_t *cmd_alias;
int trashtest;
int *trashspot;
cmd_source_t cmd_source;
qboolean cmd_wait;
cvar_t *cl_warncmd;
//=============================================================================
/*
@ -87,6 +90,7 @@ void Cmd_Wait_f (void)
*/
sizebuf_t cmd_text;
byte cmd_text_buf[8192];
/*
============
@ -95,10 +99,10 @@ Cbuf_Init
*/
void Cbuf_Init (void)
{
SZ_Alloc (&cmd_text, 8192); // space for commands and script files
cmd_text.data = cmd_text_buf;
cmd_text.maxsize = sizeof(cmd_text_buf);
}
/*
============
Cbuf_AddText
@ -109,7 +113,7 @@ Adds command text at the end of the buffer
void Cbuf_AddText (char *text)
{
int l;
l = strlen (text);
if (cmd_text.cursize + l >= cmd_text.maxsize)
@ -117,7 +121,6 @@ void Cbuf_AddText (char *text)
Con_Printf ("Cbuf_AddText: overflow\n");
return;
}
SZ_Write (&cmd_text, text, strlen (text));
}
@ -131,6 +134,7 @@ Adds a \n to the text
FIXME: actually change the command buffer to do less copying
============
*/
#if 0 // Tonik
void Cbuf_InsertText (char *text)
{
char *temp;
@ -140,72 +144,103 @@ void Cbuf_InsertText (char *text)
templen = cmd_text.cursize;
if (templen)
{
temp = Z_Malloc (templen);
temp = malloc (templen);
memcpy (temp, cmd_text.data, templen);
SZ_Clear (&cmd_text);
}
else
temp = NULL; // shut up compiler
// add the entire text of the file
Cbuf_AddText (text);
SZ_Write (&cmd_text, "\n", 1);
// add the copied off data
if (templen)
{
SZ_Write (&cmd_text, temp, templen);
Z_Free (temp);
free (temp);
}
}
#else
void Cbuf_InsertText (char *text)
{
int textlen;
textlen = strlen(text);
if (cmd_text.cursize + 1 + textlen >= cmd_text.maxsize)
{
Con_Printf ("Cbuf_InsertText: overflow\n");
return;
}
if (!cmd_text.cursize)
{
memcpy (cmd_text.data, text, textlen);
cmd_text.cursize = textlen;
return;
}
// Move up to make room for inserted text
memmove (cmd_text.data + textlen + 1, cmd_text.data, cmd_text.cursize);
cmd_text.cursize += textlen + 1;
// Insert new text
memcpy (cmd_text.data, text, textlen);
cmd_text.data[textlen] = '\n';
}
#endif
static void
extract_line(char *line)
{
int i;
char *text;
int quotes;
// find a \n or ; line break
text = (char *)cmd_text.data;
quotes = 0;
for (i=0 ; i< cmd_text.cursize ; i++) {
if (text[i] == '"')
quotes++;
if ( !(quotes&1) && text[i] == ';')
break; // don't break if inside a quoted string
if (text[i] == '\n' || text[i] == '\r')
break;
}
memcpy (line, text, i);
line[i] = '\0';
// delete the text from the command buffer and move remaining commands down
// this is necessary because commands (exec, alias) can insert data at the
// beginning of the text buffer
if (i == cmd_text.cursize)
cmd_text.cursize = 0;
else {
i++;
cmd_text.cursize -= i;
memcpy (text, text+i, cmd_text.cursize);
}
}
/*
============
Cbuf_Execute
============
Cbuf_Execute
*/
void Cbuf_Execute (void)
void
Cbuf_Execute (void)
{
int i;
char *text;
char line[1024];
int quotes;
while (cmd_text.cursize)
{
// find a \n or ; line break
text = (char *)cmd_text.data;
char line[1024] = {0};
quotes = 0;
for (i=0 ; i< cmd_text.cursize ; i++)
{
if (text[i] == '"')
quotes++;
if ( !(quotes&1) && text[i] == ';')
break; // don't break if inside a quoted string
if (text[i] == '\n')
break;
}
memcpy (line, text, i);
line[i] = 0;
// delete the text from the command buffer and move remaining commands down
// this is necessary because commands (exec, alias) can insert data at the
// beginning of the text buffer
if (i == cmd_text.cursize)
cmd_text.cursize = 0;
else
{
i++;
cmd_text.cursize -= i;
memcpy (text, text+i, cmd_text.cursize);
}
// execute the command line
while (cmd_text.cursize) {
extract_line (line);
// execute the command line
//Con_DPrintf("+%s\n",line),
Cmd_ExecuteString (line, src_command);
if (cmd_wait)
{ // skip out while text still remains in buffer, leaving it
// for next frame
@ -214,6 +249,25 @@ void Cbuf_Execute (void)
}
}
}
/*
Cbuf_Execute
*/
void
Cbuf_Execute_Sets (void)
{
char line[1024] = {0};
while (cmd_text.cursize) {
extract_line (line);
// execute the command line
if (strncmp(line,"set",3)==0
&& isspace((int) line[3]))
//Con_DPrintf("+%s\n",line),
Cmd_ExecuteString (line, src_command);
}
}
/*
==============================================================================
@ -237,66 +291,74 @@ void Cmd_StuffCmds_f (void)
{
int i, j;
int s;
char *text, *build, c;
if (Cmd_Argc () != 1)
{
Con_Printf ("stuffcmds : execute command line parameters\n");
return;
}
char *build, c;
// build the combined string to parse from
s = 0;
for (i=1 ; i<com_argc ; i++)
{
if (!com_argv[i])
continue; // NEXTSTEP nulls out -NXHost
s += strlen (com_argv[i]) + 1;
}
s = strlen (com_cmdline);
if (!s)
return;
text = Z_Malloc (s+1);
text[0] = 0;
for (i=1 ; i<com_argc ; i++)
{
if (!com_argv[i])
continue; // NEXTSTEP nulls out -NXHost
strcat (text,com_argv[i]);
if (i != com_argc-1)
strcat (text, " ");
}
// pull out the commands
build = Z_Malloc (s+1);
build = malloc (s+1);
build[0] = 0;
for (i=0 ; i<s-1 ; i++)
{
if (text[i] == '+')
if (com_cmdline[i] == '+')
{
i++;
for (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)
for (j=i ; ((com_cmdline[j] != '+')
&& (com_cmdline[j] != '-')
&& (com_cmdline[j] != 0)) ; j++)
;
c = text[j];
text[j] = 0;
strcat (build, text+i);
c = com_cmdline[j];
com_cmdline[j] = 0;
strcat (build, com_cmdline+i);
strcat (build, "\n");
text[j] = c;
com_cmdline[j] = c;
i = j-1;
}
}
//Con_Printf("[\n%s]\n",build);
if (build[0])
Cbuf_InsertText (build);
Z_Free (text);
Z_Free (build);
free (build);
}
/*
Cmd_Exec_File
*/
void
Cmd_Exec_File (char *path)
{
char *f;
int mark;
int len;
char base[32];
FILE *file;
if ((file = fopen (path, "r")) != NULL) {
// extract the filename base name for hunk tag
COM_FileBase (path, base);
len = COM_filelength (file);
mark = Hunk_LowMark ();
f = (char *)Hunk_AllocName (len+1, base);
if (f) {
f[len] = 0;
fread (f, 1, len, file);
fclose (file);
Cbuf_InsertText (f);
}
Hunk_FreeToLowMark (mark);
}
}
/*
===============
@ -314,6 +376,7 @@ void Cmd_Exec_f (void)
return;
}
// FIXME: is this safe freeing the hunk here???
mark = Hunk_LowMark ();
f = (char *)COM_LoadHunkFile (Cmd_Argv(1));
if (!f)
@ -321,8 +384,9 @@ void Cmd_Exec_f (void)
Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
return;
}
Con_Printf ("execing %s\n",Cmd_Argv(1));
if (!Cvar_Command () && (cl_warncmd->value || developer->value))
Con_Printf ("execing %s\n",Cmd_Argv(1));
Cbuf_InsertText (f);
Hunk_FreeToLowMark (mark);
}
@ -338,7 +402,7 @@ Just prints the rest of the line to the console
void Cmd_Echo_f (void)
{
int i;
for (i=1 ; i<Cmd_Argc() ; i++)
Con_Printf ("%s ",Cmd_Argv(i));
Con_Printf ("\n");
@ -355,8 +419,8 @@ Creates a new command that executes a command string (possibly ; seperated)
char *CopyString (char *in)
{
char *out;
out = Z_Malloc (strlen(in)+1);
out = malloc (strlen(in)+1);
strcpy (out, in);
return out;
}
@ -388,18 +452,18 @@ void Cmd_Alias_f (void)
{
if (!strcmp(s, a->name))
{
Z_Free (a->value);
free (a->value);
break;
}
}
if (!a)
{
a = Z_Malloc (sizeof(cmdalias_t));
a = calloc (1, sizeof(cmdalias_t));
a->next = cmd_alias;
cmd_alias = a;
}
strcpy (a->name, s);
strcpy (a->name, s);
// copy the rest of the command line
cmd[0] = 0; // start out with a null string
@ -411,10 +475,45 @@ void Cmd_Alias_f (void)
strcat (cmd, " ");
}
strcat (cmd, "\n");
a->value = CopyString (cmd);
}
void Cmd_UnAlias_f (void)
{
cmdalias_t *a, *prev;
char *s;
if (Cmd_Argc() != 2)
{
Con_Printf ("unalias <alias>: erase an existing alias\n");
return;
}
s = Cmd_Argv(1);
if (strlen(s) >= MAX_ALIAS_NAME)
{
Con_Printf ("Alias name is too long\n");
return;
}
prev = cmd_alias;
for (a = cmd_alias ; a ; a = a->next)
{
if (!strcmp(s, a->name))
{
free (a->value);
prev->next = a->next;
if (a == cmd_alias)
cmd_alias = a->next;
free (a);
return;
}
prev = a;
}
Con_Printf ("Unknown alias \"%s\"\n", s);
}
/*
=============================================================================
@ -438,29 +537,10 @@ static char *cmd_argv[MAX_ARGS];
static char *cmd_null_string = "";
static char *cmd_args = NULL;
cmd_source_t cmd_source;
static cmd_function_t *cmd_functions; // possible commands to execute
/*
============
Cmd_Init
============
*/
void Cmd_Init (void)
{
//
// register our commands
//
Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);
Cmd_AddCommand ("exec",Cmd_Exec_f);
Cmd_AddCommand ("echo",Cmd_Echo_f);
Cmd_AddCommand ("alias",Cmd_Alias_f);
Cmd_AddCommand ("cmd", Cmd_ForwardToServer);
Cmd_AddCommand ("wait", Cmd_Wait_f);
}
/*
============
Cmd_Argc
@ -478,18 +558,22 @@ Cmd_Argv
*/
char *Cmd_Argv (int arg)
{
if ( (unsigned)arg >= cmd_argc )
if ( arg >= cmd_argc )
return cmd_null_string;
return cmd_argv[arg];
return cmd_argv[arg];
}
/*
============
Cmd_Args
Returns a single string containing argv(1) to argv(argc()-1)
============
*/
char *Cmd_Args (void)
{
if (!cmd_args)
return "";
return cmd_args;
}
@ -503,23 +587,22 @@ Parses the given string into command line tokens.
*/
void Cmd_TokenizeString (char *text)
{
int i;
// clear the args from the last string
for (i=0 ; i<cmd_argc ; i++)
Z_Free (cmd_argv[i]);
static char argv_buf[1024];
int argv_idx;
argv_idx = 0;
cmd_argc = 0;
cmd_args = NULL;
while (1)
{
// skip whitespace up to a /n
while (*text && *text <= ' ' && *text != '\n')
while (*text && *(unsigned char*)text <= ' ' && *text != '\n')
{
text++;
}
if (*text == '\n')
{ // a newline seperates commands in the buffer
text++;
@ -528,22 +611,29 @@ void Cmd_TokenizeString (char *text)
if (!*text)
return;
if (cmd_argc == 1)
cmd_args = text;
text = COM_Parse (text);
if (!text)
return;
if (cmd_argc < MAX_ARGS)
{
cmd_argv[cmd_argc] = Z_Malloc (strlen(com_token)+1);
if (argv_idx + strlen(com_token) + 1 > 1024)
{
Con_Printf ("Cmd_TokenizeString: overflow\n");
return;
}
cmd_argv[cmd_argc] = argv_buf + argv_idx;
strcpy (cmd_argv[cmd_argc], com_token);
argv_idx += strlen(com_token) + 1;
cmd_argc++;
}
}
}
@ -555,17 +645,17 @@ Cmd_AddCommand
void Cmd_AddCommand (char *cmd_name, xcommand_t function)
{
cmd_function_t *cmd;
if (host_initialized) // because hunk allocation would get stomped
Sys_Error ("Cmd_AddCommand after host_initialized");
// fail if the command is a variable name
if (Cvar_VariableString(cmd_name)[0])
{
Con_Printf ("Cmd_AddCommand: %s already defined as a var\n", cmd_name);
return;
}
// fail if the command already exists
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
{
@ -612,20 +702,112 @@ char *Cmd_CompleteCommand (char *partial)
{
cmd_function_t *cmd;
int len;
cmdalias_t *a;
len = strlen(partial);
if (!len)
return NULL;
// check functions
// check for exact match
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
if (!strncmp (partial,cmd->name, len))
if (!strcasecmp (partial, cmd->name))
return cmd->name;
for (a=cmd_alias ; a ; a=a->next)
if (!strcasecmp (partial, a->name))
return a->name;
// check for partial match
for (cmd=cmd_functions ; cmd ; cmd=cmd->next)
if (!strncasecmp (partial, cmd->name, len))
return cmd->name;
for (a=cmd_alias ; a ; a=a->next)
if (!strncasecmp (partial, a->name, len))
return a->name;
return NULL;
}
/*
============
Cmd_ExpandVariables
Expand $fov-like expressions
FIXME: better handling of buffer overflows?
============
*/
// dest must point to a 1024-byte buffer
void Cmd_ExpandVariables (char *data, char *dest)
{
unsigned int c;
char buf[1024];
int i, len;
cvar_t *var, *bestvar;
int quotes = 0;
len = 0;
// parse a regular word
while ( (c = *data) != 0)
{
if (c == '"')
quotes++;
if (c == '$' && !(quotes&1))
{
data++;
// Copy the text after '$' to a temp buffer
i = 0;
buf[0] = 0;
bestvar = NULL;
while ((c = *data) > 32)
{
if (c == '$')
break;
data++;
buf[i++] = c;
buf[i] = 0;
if ((var = Cvar_FindVar(buf)) != 0)
bestvar = var;
if (i >= sizeof(buf)-1)
break;
}
if (bestvar)
{
// check buffer size
if (len + strlen(bestvar->string) >= 1024-1)
break;
strcpy(&dest[len], bestvar->string);
len += strlen(bestvar->string);
i = strlen(bestvar->name);
while (buf[i])
dest[len++] = buf[i++];
}
else
{
// no matching cvar name was found
dest[len++] = '$';
if (len + strlen(buf) >= 1024-1)
break;
strcpy (&dest[len], buf);
len += strlen(buf);
}
}
else
{
dest[len] = c;
data++;
len++;
if (len >= 1024-1)
break;
}
};
dest[len] = 0;
}
/*
============
Cmd_ExecuteString
@ -634,14 +816,21 @@ A complete command line has been parsed, so try to execute it
FIXME: lookupnoadd the token to speed search?
============
*/
void Cmd_ExecuteString (char *text, cmd_source_t src)
{
void Cmd_ExecuteString (char *text, cmd_source_t src)
{
cmd_function_t *cmd;
cmdalias_t *a;
char buf[1024];
cmd_source = src;
#if 0
Cmd_TokenizeString (text);
#else
Cmd_ExpandVariables (text, buf);
Cmd_TokenizeString (buf);
#endif
// execute the command line
if (!Cmd_Argc())
return; // no tokens
@ -651,11 +840,18 @@ void Cmd_ExecuteString (char *text, cmd_source_t src)
{
if (!strcasecmp (cmd_argv[0],cmd->name))
{
cmd->function ();
if (!cmd->function)
Cmd_ForwardToServer ();
else
cmd->function ();
return;
}
}
// Tonik: check cvars
if (Cvar_Command())
return;
// check alias
for (a=cmd_alias ; a ; a=a->next)
{
@ -666,13 +862,138 @@ void Cmd_ExecuteString (char *text, cmd_source_t src)
}
}
// check cvars
if (!Cvar_Command ())
if (cl_warncmd->value || developer->value)
Con_Printf ("Unknown command \"%s\"\n", Cmd_Argv(0));
}
/*
================
Cmd_CheckParm
Returns the position (1 to argc-1) in the command's argument list
where the given parameter apears, or 0 if not present
================
*/
int Cmd_CheckParm (char *parm)
{
int i;
if (!parm)
Sys_Error ("Cmd_CheckParm: NULL");
for (i = 1; i < Cmd_Argc (); i++)
if (! strcasecmp (parm, Cmd_Argv (i)))
return i;
return 0;
}
void Cmd_CmdList_f (void)
{
cmd_function_t *cmd;
int i;
for (cmd=cmd_functions, i=0 ; cmd ; cmd=cmd->next, i++)
{
Con_Printf("%s\n", cmd->name);
}
Con_Printf ("------------\n%d commands\n", i);
}
char com_token[MAX_COM_TOKEN];
/*
==============
COM_Parse
Parse a token out of a string
==============
*/
char *COM_Parse (char *data)
{
unsigned int c;
int len;
len = 0;
com_token[0] = 0;
if (!data)
return NULL;
// skip whitespace
skipwhite:
while ( (c = *data) <= ' ')
{
if (c == 0)
return NULL; // end of file;
data++;
}
// skip // comments
if (c=='/' && data[1] == '/')
{
while (*data && *data != '\n')
data++;
goto skipwhite;
}
// handle quoted strings specially
if (c == '\"')
{
data++;
while (1)
{
c = *data++;
if (c=='\"' || !c)
{
com_token[len] = 0;
return data;
}
com_token[len] = c;
len++;
}
}
// parse a regular word
do
{
com_token[len] = c;
data++;
len++;
if (len >= MAX_COM_TOKEN-1)
break;
c = *data;
} while (c>32);
com_token[len] = 0;
return data;
}
/*
============
Cmd_Init
============
*/
void Cmd_Init (void)
{
//
// register our commands
//
Cmd_AddCommand ("stuffcmds",Cmd_StuffCmds_f);
Cmd_AddCommand ("exec",Cmd_Exec_f);
Cmd_AddCommand ("echo",Cmd_Echo_f);
Cmd_AddCommand ("alias",Cmd_Alias_f);
Cmd_AddCommand ("cmd", Cmd_ForwardToServer);
Cmd_AddCommand ("wait", Cmd_Wait_f);
}
/*
===================
Cmd_ForwardToServer
@ -687,9 +1008,9 @@ void Cmd_ForwardToServer (void)
Con_Printf ("Can't \"%s\", not connected\n", Cmd_Argv(0));
return;
}
if (cls.demoplayback)
return; // not really connected
return; // not really connected
MSG_WriteByte (&cls.message, clc_stringcmd);
if (strcasecmp(Cmd_Argv(0), "cmd") != 0)
@ -702,27 +1023,3 @@ void Cmd_ForwardToServer (void)
else
SZ_Print (&cls.message, "\n");
}
/*
================
Cmd_CheckParm
Returns the position (1 to argc-1) in the command's argument list
where the given parameter apears, or 0 if not present
================
*/
int Cmd_CheckParm (char *parm)
{
int i;
if (!parm)
Sys_Error ("Cmd_CheckParm: NULL");
for (i = 1; i < Cmd_Argc (); i++)
if (! strcasecmp (parm, Cmd_Argv (i)))
return i;
return 0;
}

110
source/com.c Normal file
View file

@ -0,0 +1,110 @@
/*
com.c
@description@
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "qendian.h"
#include "cvar.h"
#include "quakefs.h"
#include "console.h"
#include "qargs.h"
#include "qdefs.h"
cvar_t *cmdline;
int static_registered = 1;
/*
================
COM_CheckRegistered
Looks for the pop.txt file and verifies it.
Sets the "registered" cvar.
Immediately exits out if an alternate game was attempted to be started without
being registered.
================
*/
void COM_CheckRegistered (void)
{
FILE *h;
unsigned short check[128];
COM_FOpenFile("gfx/pop.lmp", &h);
static_registered = 0;
if (h) {
static_registered = 1;
fread (check, 1, sizeof(check), h);
fclose (h);
}
if (static_registered) {
Cvar_Set (registered, "1");
Con_Printf ("Playing registered version.\n");
}
}
/*
================
COM_Init
================
*/
void COM_Init ()
{
byte swaptest[2] = {1,0};
// set the byte swapping variables in a portable manner
if ( *(short *)swaptest == 1)
{
bigendien = false;
BigShort = ShortSwap;
LittleShort = ShortNoSwap;
BigLong = LongSwap;
LittleLong = LongNoSwap;
BigFloat = FloatSwap;
LittleFloat = FloatNoSwap;
}
else
{
bigendien = true;
BigShort = ShortNoSwap;
LittleShort = ShortSwap;
BigLong = LongNoSwap;
LittleLong = LongSwap;
BigFloat = FloatNoSwap;
LittleFloat = FloatSwap;
}
registered = Cvar_Get("registered", "0", CVAR_NONE, "None");
cmdline = Cvar_Get("cmdline", "0", CVAR_SERVERINFO, "None");
Cmd_AddCommand ("path", COM_Path_f);
COM_InitFilesystem ();
COM_CheckRegistered ();
}

File diff suppressed because it is too large Load diff

View file

@ -61,6 +61,8 @@ Memory is cleared / released when a server or client begins, not when they end.
*/
qboolean msg_suppress_1 = 0;
quakeparms_t host_parms;
qboolean host_initialized; // true if into command execution

60
source/link.c Normal file
View file

@ -0,0 +1,60 @@
/*
link.c
(description)
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "link.h"
// ClearLink is used for new headnodes
void ClearLink (link_t *l)
{
l->prev = l->next = l;
}
void RemoveLink (link_t *l)
{
l->next->prev = l->prev;
l->prev->next = l->next;
}
void InsertLinkBefore (link_t *l, link_t *before)
{
l->next = before;
l->prev = before->prev;
l->prev->next = l;
l->next->prev = l;
}
void InsertLinkAfter (link_t *l, link_t *after)
{
l->next = after->next;
l->prev = after;
l->prev->next = l;
l->next->prev = l;
}

265
source/msg.c Normal file
View file

@ -0,0 +1,265 @@
/*
msg.c
@description@
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "msg.h"
#include "qendian.h"
#include "net.h"
/*
==============================================================================
MESSAGE IO FUNCTIONS
Handles byte ordering and avoids alignment errors
==============================================================================
*/
//
// writing functions
//
void MSG_WriteChar (sizebuf_t *sb, int c)
{
byte *buf;
#ifdef PARANOID
if (c < -128 || c > 127)
Sys_Error ("MSG_WriteChar: range error");
#endif
buf = SZ_GetSpace (sb, 1);
buf[0] = c;
}
void MSG_WriteByte (sizebuf_t *sb, int c)
{
byte *buf;
#ifdef PARANOID
if (c < 0 || c > 255)
Sys_Error ("MSG_WriteByte: range error");
#endif
buf = SZ_GetSpace (sb, 1);
buf[0] = c;
}
void MSG_WriteShort (sizebuf_t *sb, int c)
{
byte *buf;
#ifdef PARANOID
if (c < ((short)0x8000) || c > (short)0x7fff)
Sys_Error ("MSG_WriteShort: range error");
#endif
buf = SZ_GetSpace (sb, 2);
buf[0] = c&0xff;
buf[1] = c>>8;
}
void MSG_WriteLong (sizebuf_t *sb, int c)
{
byte *buf;
buf = SZ_GetSpace (sb, 4);
buf[0] = c&0xff;
buf[1] = (c>>8)&0xff;
buf[2] = (c>>16)&0xff;
buf[3] = c>>24;
}
void MSG_WriteFloat (sizebuf_t *sb, float f)
{
union
{
float f;
int l;
} dat;
dat.f = f;
dat.l = LittleLong (dat.l);
SZ_Write (sb, &dat.l, 4);
}
void MSG_WriteString (sizebuf_t *sb, char *s)
{
if (!s)
SZ_Write (sb, "", 1);
else
SZ_Write (sb, s, strlen(s)+1);
}
void MSG_WriteCoord (sizebuf_t *sb, float f)
{
MSG_WriteShort (sb, (int)(f*8));
}
void MSG_WriteAngle (sizebuf_t *sb, float f)
{
MSG_WriteByte (sb, ((int)f*256/360) & 255);
}
//
// reading functions
//
int msg_readcount;
qboolean msg_badread;
void MSG_BeginReading (void)
{
msg_readcount = 0;
msg_badread = false;
}
// returns -1 and sets msg_badread if no more characters are available
int MSG_ReadChar (void)
{
int c;
if (msg_readcount+1 > net_message.cursize)
{
msg_badread = true;
return -1;
}
c = (signed char)net_message.data[msg_readcount];
msg_readcount++;
return c;
}
int MSG_ReadByte (void)
{
int c;
if (msg_readcount+1 > net_message.cursize)
{
msg_badread = true;
return -1;
}
c = (unsigned char)net_message.data[msg_readcount];
msg_readcount++;
return c;
}
int MSG_ReadShort (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;
}
int MSG_ReadLong (void)
{
int c;
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 c;
}
float MSG_ReadFloat (void)
{
union
{
byte 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];
msg_readcount += 4;
dat.l = LittleLong (dat.l);
return dat.f;
}
char *MSG_ReadString (void)
{
static char string[2048];
int l,c;
l = 0;
do
{
c = MSG_ReadChar ();
if (c == -1 || c == 0)
break;
string[l] = c;
l++;
} while (l < sizeof(string)-1);
string[l] = 0;
return string;
}
float MSG_ReadCoord (void)
{
return MSG_ReadShort() * (1.0/8);
}
float MSG_ReadAngle (void)
{
return MSG_ReadChar() * (360.0/256);
}

155
source/qargs.c Normal file
View file

@ -0,0 +1,155 @@
/*
qargs.c
command line argument processing routines
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 1999,2000 Nelson Rush.
Copyright (C) 1999,2000 contributors of the QuakeForge project
Please see the file "AUTHORS" for a list of contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "string.h"
#include "ctype.h"
#include "stdlib.h"
#include "qtypes.h"
#include "crc.h"
#include "sys.h"
#include "cmd.h"
#include "console.h"
#include "client.h"
#include "assert.h"
#include <string.h>
usercmd_t nullcmd; // guarenteed to be zero
static char **largv;
static char *argvdummy = " ";
static char *safeargvs[] =
{"-stdvid", "-nolan", "-nosound", "-nocdaudio", "-nojoy", "-nomouse", "-dibonly"};
#define NUM_SAFE_ARGVS (sizeof(safeargvs)/sizeof(safeargvs[0]))
int com_argc;
char **com_argv;
char *com_cmdline;
cvar_t *cmdline;
qboolean nouse = false; // 1999-10-29 +USE fix by Maddes
/*
================
COM_CheckParm
Returns the position (1 to argc-1) in the program's argument list
where the given parameter apears, or 0 if not present
================
*/
int COM_CheckParm (char *parm)
{
int i;
for (i=1 ; i<com_argc ; i++)
{
if (!com_argv[i])
continue; // NEXTSTEP sometimes clears appkit vars.
if (!strcmp (parm,com_argv[i]))
return i;
}
return 0;
}
/*
================
COM_InitArgv
================
*/
void COM_InitArgv (int argc, char **argv)
{
qboolean safe;
int i, len;
safe = false;
largv = (char**)calloc (1, (argc + NUM_SAFE_ARGVS + 1) * sizeof (char**));
for (com_argc=0, len=0 ; com_argc < argc ; com_argc++)
{
largv[com_argc] = argv[com_argc];
if ((argv[com_argc]) && !strcmp ("-safe", argv[com_argc]))
safe = true;
if (com_argc)
len += strlen (argv[com_argc]) + 1;
}
com_cmdline = (char*)calloc (1, len+1); // need strlen(com_cmdline)+2
com_cmdline[0] = 0;
if (len) {
for (i=1; i < argc; i++)
{
strncat (com_cmdline, argv[i], len);
assert(len - strlen(com_cmdline) > 0);
strcat (com_cmdline, " ");
}
com_cmdline[len - 1] = '\0';
}
if (safe)
{
// force all the safe-mode switches. Note that we reserved extra space in
// case we need to add these, so we don't need an overflow check
for (i=0 ; i<NUM_SAFE_ARGVS ; i++)
{
largv[com_argc] = safeargvs[i];
com_argc++;
}
}
largv[com_argc] = argvdummy;
com_argv = largv;
// 1999-10-29 +USE fix by Maddes start
if (COM_CheckParm ("-nouse"))
{
nouse = true;
}
// 1999-10-29 +USE fix by Maddes end
}
/*
================
COM_AddParm
Adds the given string at the end of the current argument list
================
*/
void COM_AddParm (char *parm)
{
largv[com_argc++] = parm;
}

105
source/qendian.c Normal file
View file

@ -0,0 +1,105 @@
/*
qendian.c
(description)
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 1999,2000 contributors of the QuakeForge project
Please see the file "AUTHORS" for a list of contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <ctype.h>
#include <qtypes.h>
/*
============================================================================
BYTE ORDER FUNCTIONS
============================================================================
*/
qboolean bigendien;
short (*BigShort) (short l);
short (*LittleShort) (short l);
int (*BigLong) (int l);
int (*LittleLong) (int l);
float (*BigFloat) (float l);
float (*LittleFloat) (float l);
short ShortSwap (short l)
{
byte b1,b2;
b1 = l&255;
b2 = (l>>8)&255;
return (b1<<8) + b2;
}
short ShortNoSwap (short l)
{
return l;
}
int LongSwap (int l)
{
byte b1,b2,b3,b4;
b1 = l&255;
b2 = (l>>8)&255;
b3 = (l>>16)&255;
b4 = (l>>24)&255;
return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4;
}
int LongNoSwap (int l)
{
return l;
}
float FloatSwap (float f)
{
union
{
float f;
byte b[4];
} dat1, dat2;
dat1.f = f;
dat2.b[0] = dat1.b[3];
dat2.b[1] = dat1.b[2];
dat2.b[2] = dat1.b[1];
dat2.b[3] = dat1.b[0];
return dat2.f;
}
float FloatNoSwap (float f)
{
return f;
}

996
source/quakefs.c Normal file
View file

@ -0,0 +1,996 @@
/*
quakefs.c
virtual filesystem functions
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif
#include <fcntl.h>
#include <dirent.h>
#ifdef HAVE_FNMATCH_H
#include <fnmatch.h>
#endif
#ifdef WIN32
#include <io.h>
#endif
#ifdef _MSC_VER
#define _POSIX_
#endif
#include "host.h"
#include "qtypes.h"
#include "quakefs.h"
#include "sys.h"
#include "console.h"
#include "draw.h"
#include "cmd.h"
#include "cvar.h"
#include "qendian.h"
#include "info.h"
#include "server.h"
#include "va.h"
extern qboolean is_server;
qboolean standard_quake = true, rogue, hipnotic;
cvar_t *registered;
/*
All of Quake's data access is through a hierchical file system, but the
contents of the file system can be transparently merged from several
sources.
The "user 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.
*/
/*
=============================================================================
QUAKE FILESYSTEM
=============================================================================
*/
char gamedirfile[MAX_OSPATH];
cvar_t *fs_userpath;
cvar_t *fs_sharepath;
cvar_t *fs_basegame;
int com_filesize;
/*
In-memory pack file structs
*/
typedef struct
{
char name[MAX_QPATH];
int filepos, filelen;
} packfile_t;
typedef struct pack_s
{
char filename[MAX_OSPATH];
FILE *handle;
int numfiles;
packfile_t *files;
} pack_t;
/*
Structs for pack files on disk
*/
typedef struct
{
char name[56];
int filepos, filelen;
} dpackfile_t;
typedef struct
{
char id[4];
int dirofs;
int dirlen;
} dpackheader_t;
#define MAX_FILES_IN_PACK 2048
char com_gamedir[MAX_OSPATH];
typedef struct searchpath_s
{
char filename[MAX_OSPATH];
pack_t *pack; // only one of filename / pack will be used
struct searchpath_s *next;
} searchpath_t;
searchpath_t *com_searchpaths;
searchpath_t *com_base_searchpaths; // without gamedirs
/*
COM_FileBase
*/
void
COM_FileBase (char *in, char *out)
{
char *s, *s2;
s = in + strlen(in) - 1;
while (s != in && *s != '.')
s--;
for (s2 = s ; *s2 && *s2 != '/' ; s2--)
;
if (s-s2 < 2)
strcpy (out,"?model?");
else
{
s--;
strncpy (out,s2+1, s-s2);
out[s-s2] = 0;
}
}
/*
COM_filelength
*/
int
COM_filelength (FILE *f)
{
int pos;
int end;
pos = ftell (f);
fseek (f, 0, SEEK_END);
end = ftell (f);
fseek (f, pos, SEEK_SET);
return end;
}
/*
COM_FileOpenRead
*/
int
COM_FileOpenRead (char *path, FILE **hndl)
{
FILE *f;
f = fopen(path, "rb");
if (!f)
{
*hndl = NULL;
return -1;
}
*hndl = f;
return COM_filelength(f);
}
/*
COM_Path_f
*/
void
COM_Path_f (void)
{
searchpath_t *s;
Con_Printf ("Current search path:\n");
for (s=com_searchpaths ; s ; s=s->next)
{
if (s == com_base_searchpaths)
Con_Printf ("----------\n");
if (s->pack)
Con_Printf ("%s (%i files)\n", s->pack->filename, s->pack->numfiles);
else
Con_Printf ("%s\n", s->filename);
}
}
/*
COM_Maplist_f
List map files in gamepaths.
*/
void
COM_Maplist_f ( void )
{
searchpath_t *search;
DIR *dir_ptr;
struct dirent *dirent;
char buf[MAX_OSPATH];
for (search = com_searchpaths ; search != NULL ; search = search->next) {
if (search->pack) {
int i;
pack_t *pak = search->pack;
Con_Printf ("Looking in %s...\n",search->pack->filename);
for (i=0 ; i<pak->numfiles ; i++) {
char *name=pak->files[i].name;
if (!fnmatch ("maps/*.bsp", name, FNM_PATHNAME)
|| !fnmatch ("maps/*.bsp.gz", name, FNM_PATHNAME))
Con_Printf ("%s\n", name+5);
}
} else {
snprintf (buf, sizeof(buf), "%s/maps", search->filename);
dir_ptr = opendir(buf);
Con_Printf ("Looking in %s...\n",buf);
if (!dir_ptr)
continue;
while ((dirent = readdir (dir_ptr)))
if (!fnmatch ("*.bsp", dirent->d_name, 0)
|| !fnmatch ("*.bsp.gz", dirent->d_name, 0))
Con_Printf ("%s\n", dirent->d_name);
closedir (dir_ptr);
}
}
}
/*
COM_WriteFile
The filename will be prefixed by the current game directory
*/
void
COM_WriteFile ( char *filename, void *data, int len )
{
FILE *f;
char name[MAX_OSPATH];
snprintf(name, sizeof(name), "%s/%s", com_gamedir, filename);
f = fopen (name, "wb");
if (!f) {
Sys_mkdir(com_gamedir);
f = fopen (name, "wb");
if (!f)
Sys_Error ("Error opening %s", filename);
}
Sys_Printf ("COM_WriteFile: %s\n", name);
fwrite (data, 1, len, f);
fclose (f);
}
/*
COM_CreatePath
Only used for CopyFile and download
*/
void
COM_CreatePath ( char *path )
{
char *ofs;
char e_path[PATH_MAX];
Qexpand_squiggle (path, e_path);
path = e_path;
for (ofs = path+1 ; *ofs ; ofs++) {
if (*ofs == '/') { // create the directory
*ofs = 0;
Sys_mkdir (path);
*ofs = '/';
}
}
}
/*
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)
{
FILE *in, *out;
int remaining, count;
char buf[4096];
remaining = COM_FileOpenRead (netpath, &in);
COM_CreatePath (cachepath); // create directories up to the cache file
out = fopen(cachepath, "wb");
if (!out)
Sys_Error ("Error opening %s", cachepath);
while (remaining)
{
if (remaining < sizeof(buf))
count = remaining;
else
count = sizeof(buf);
fread (buf, 1, count, in);
fwrite (buf, 1, count, out);
remaining -= count;
}
fclose (in);
fclose (out);
}
/*
COM_OpenRead
*/
FILE *
COM_OpenRead (const char *path, int offs, int len)
{
int fd=open(path,O_RDONLY);
unsigned char id[2];
unsigned char 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);
}
read(fd,id,2);
if (id[0]==0x1f && id[1]==0x8b) {
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
return fdopen(fd,"rb");
return 0;
}
int file_from_pak; // global indicating file came from pack file ZOID
/*
COM_FOpenFile
Finds the file in the search path.
Sets com_filesize and one of handle or file
*/
int
COM_FOpenFile (char *filename, FILE **gzfile)
{
searchpath_t *search;
char netpath[MAX_OSPATH];
pack_t *pak;
int i;
int findtime;
file_from_pak = 0;
//
// search through the path, one element at a time
//
for (search = com_searchpaths ; 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++) {
char *fn=0;
if (!strcmp (pak->files[i].name, filename))
fn=filename;
if (fn)
{ // found it!
if (developer->value)
Sys_Printf ("PackFile: %s : %s\n",pak->filename, fn);
// open a new file on the pakfile
*gzfile=COM_OpenRead(pak->filename,pak->files[i].filepos,
pak->files[i].filelen);
file_from_pak = 1;
return com_filesize;
}
}
}
else
{
// check a file in the directory tree
snprintf(netpath, sizeof(netpath), "%s/%s",search->filename,
filename);
findtime = Sys_FileTime (netpath);
if (findtime == -1) {
continue;
}
if(developer->value)
Sys_Printf ("FindFile: %s\n",netpath);
*gzfile=COM_OpenRead(netpath,-1,-1);
return com_filesize;
}
}
Sys_Printf ("FindFile: can't find %s\n", filename);
*gzfile = NULL;
com_filesize = -1;
return -1;
}
cache_user_t *loadcache;
byte *loadbuf;
int loadsize;
/*
COM_LoadFile
Filename are relative to the quake directory.
Allways appends a 0 byte to the loaded data.
*/
byte *
COM_LoadFile (char *path, int usehunk)
{
FILE *h;
byte *buf;
char base[32];
int len;
buf = NULL; // quiet compiler warning
// look for it in the filesystem or pack files
len = com_filesize = COM_FOpenFile (path, &h);
if (!h)
return NULL;
// extract the filename base name for hunk tag
COM_FileBase (path, base);
if (usehunk == 1)
buf = Hunk_AllocName (len+1, base);
else if (usehunk == 2)
buf = Hunk_TempAlloc (len+1);
else if (usehunk == 0)
buf = calloc (1, len+1);
else if (usehunk == 3)
buf = Cache_Alloc (loadcache, len+1, base);
else if (usehunk == 4)
{
if (len+1 > loadsize)
buf = Hunk_TempAlloc (len+1);
else
buf = loadbuf;
}
else
Sys_Error ("COM_LoadFile: bad usehunk");
if (!buf)
Sys_Error ("COM_LoadFile: not enough space for %s", path);
((byte *)buf)[len] = 0;
//if (!is_server) {
Draw_BeginDisc();
//}
fread (buf, 1, len, h);
fclose (h);
//if (!is_server) {
Draw_EndDisc();
//}
return buf;
}
byte *
COM_LoadHunkFile (char *path)
{
return COM_LoadFile (path, 1);
}
byte *
COM_LoadTempFile (char *path)
{
return COM_LoadFile (path, 2);
}
void
COM_LoadCacheFile (char *path, struct cache_user_s *cu)
{
loadcache = cu;
COM_LoadFile (path, 3);
}
// uses temp hunk if larger than bufsize
byte *
COM_LoadStackFile (char *path, void *buffer, int bufsize)
{
byte *buf;
loadbuf = (byte *)buffer;
loadsize = bufsize;
buf = COM_LoadFile (path, 4);
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 (char *packfile)
{
dpackheader_t header;
int i;
packfile_t *newfiles;
int numpackfiles;
pack_t *pack;
FILE *packhandle;
dpackfile_t info[MAX_FILES_IN_PACK];
if (COM_FileOpenRead (packfile, &packhandle) == -1)
return NULL;
fread (&header, 1, sizeof(header), packhandle);
if (header.id[0] != 'P' || header.id[1] != 'A'
|| header.id[2] != 'C' || header.id[3] != 'K')
Sys_Error ("%s is not a packfile", packfile);
header.dirofs = LittleLong (header.dirofs);
header.dirlen = LittleLong (header.dirlen);
numpackfiles = header.dirlen / sizeof(dpackfile_t);
if (numpackfiles > MAX_FILES_IN_PACK)
Sys_Error ("%s has %i files", packfile, numpackfiles);
newfiles = calloc (1, numpackfiles * sizeof(packfile_t));
fseek (packhandle, header.dirofs, SEEK_SET);
fread (info, 1, header.dirlen, packhandle);
// parse the directory
for (i=0 ; i<numpackfiles ; i++)
{
strcpy (newfiles[i].name, info[i].name);
newfiles[i].filepos = LittleLong(info[i].filepos);
newfiles[i].filelen = LittleLong(info[i].filelen);
}
pack = calloc (1, sizeof (pack_t));
strcpy (pack->filename, packfile);
pack->handle = packhandle;
pack->numfiles = numpackfiles;
pack->files = newfiles;
Con_Printf ("Added packfile %s (%i files)\n", packfile, numpackfiles);
return pack;
}
#define FBLOCK_SIZE 32
#define FNAME_SIZE MAX_OSPATH
// Note, this is /NOT/ a work-alike strcmp, this groups numbers sanely.
//int qstrcmp(const char *val, const char *ref)
int qstrcmp(char **os1, char **os2)
{
int in1, in2, n1, n2;
char *s1, *s2;
s1 = *os1;
s2 = *os2;
while (1) {
in1 = in2 = n1 = n2 = 0;
if ((in1 = isdigit((int) *s1)))
n1 = strtol(s1, &s1, 10);
if ((in2 = isdigit((int) *s2)))
n2 = strtol(s2, &s2, 10);
if (in1 && in2) {
if (n1 != n2)
return n1-n2;
} else {
if (*s1 != *s2)
return *s1 - *s2;
else if (*s1 == '\0')
return *s1 - *s2;
s1++;
s2++;
}
}
}
void
COM_LoadGameDirectory(char *dir)
{
searchpath_t *search;
pack_t *pak;
DIR *dir_ptr;
struct dirent *dirent;
char **pakfiles = NULL;
int i = 0, bufsize = 0, count = 0;
Con_DPrintf ("COM_LoadGameDirectory (\"%s\")\n", dir);
pakfiles = calloc(1, FBLOCK_SIZE * sizeof(char *));
bufsize += FBLOCK_SIZE;
if (!pakfiles)
goto COM_LoadGameDirectory_free;
for (i = count; i < bufsize; i++) {
pakfiles[i] = NULL;
}
dir_ptr = opendir(dir);
if (!dir_ptr)
return;
while ((dirent = readdir(dir_ptr))) {
if (!fnmatch("*.pak", dirent->d_name, 0)) {
if (count >= bufsize) {
bufsize += FBLOCK_SIZE;
pakfiles = realloc(pakfiles, bufsize * sizeof(char *));
if (!pakfiles)
goto COM_LoadGameDirectory_free;
for (i = count; i < bufsize; i++)
pakfiles[i] = NULL;
}
pakfiles[count] = malloc(FNAME_SIZE);
snprintf(pakfiles[count], FNAME_SIZE - 1, "%s/%s", dir,
dirent->d_name);
pakfiles[count][FNAME_SIZE - 1] = '\0';
count++;
}
}
closedir(dir_ptr);
// XXX WARNING!!! This is /NOT/ subtable for strcmp!!!!!
// This passes 'char **' instead of 'char *' to the cmp function!
qsort(pakfiles, count, sizeof(char *),
(int (*)(const void *, const void *)) qstrcmp);
for (i = 0; i < count; i++) {
pak = COM_LoadPackFile(pakfiles[i]);
if (!pak) {
Sys_Error(va("Bad pakfile %s!!", pakfiles[i]));
} else {
search = calloc (1, sizeof(searchpath_t));
search->pack = pak;
search->next = com_searchpaths;
com_searchpaths = search;
}
}
COM_LoadGameDirectory_free:
for (i = 0; i < count; i++)
free(pakfiles[i]);
free(pakfiles);
}
/*
COM_AddDirectory
Sets com_gamedir, adds the directory to the head of the path,
then loads and adds pak1.pak pak2.pak ...
*/
void
COM_AddDirectory (char *dir)
{
searchpath_t *search;
char *p;
char e_dir[PATH_MAX];
Qexpand_squiggle (dir, e_dir);
dir = e_dir;
if ((p = strrchr(dir, '/')) != NULL) {
strcpy (gamedirfile, ++p);
strcpy (com_gamedir, dir);
} else {
strcpy (gamedirfile, dir);
strcpy (com_gamedir, va("%s/%s", fs_userpath->string, dir));
}
//
// add the directory to the search path
//
search = calloc (1, sizeof(searchpath_t));
strcpy (search->filename, dir);
search->next = com_searchpaths;
com_searchpaths = search;
//
// add any pak files in the format pak0.pak pak1.pak, ...
//
COM_LoadGameDirectory (dir);
}
/*
COM_AddGameDirectory
FIXME: this is a wrapper for COM_AddDirectory (which used to be
this function) to have it load share and base paths. Whenver
someone goes through to clean up the fs code, this function should
merge with COM_AddGameDirectory.
*/
void
COM_AddGameDirectory (char *dir)
{
Con_DPrintf ("COM_AddGameDirectory (\"%s/%s\")\n",
fs_sharepath->string, dir);
if (strcmp (fs_sharepath->string, fs_userpath->string) != 0)
COM_AddDirectory (va("%s/%s", fs_sharepath->string, dir));
COM_AddDirectory (va("%s/%s", fs_userpath->string, dir));
}
/*
COM_Gamedir
Sets the gamedir and path to a different directory.
*/
void
COM_Gamedir (char *dir)
{
searchpath_t *next;
if (strstr(dir, "..") || strstr(dir, "/")
|| strstr(dir, "\\") || strstr(dir, ":") )
{
Con_Printf ("Gamedir should be a single filename, not a path\n");
return;
}
if (strcmp (gamedirfile, dir) == 0)
return; // still the same
strcpy (gamedirfile, dir);
//
// free up any current game dir info
//
while (com_searchpaths != com_base_searchpaths)
{
if (com_searchpaths->pack)
{
fclose (com_searchpaths->pack->handle);
free (com_searchpaths->pack->files);
free (com_searchpaths->pack);
}
next = com_searchpaths->next;
free (com_searchpaths);
com_searchpaths = next;
}
//
// flush all data, so it will be forced to reload
//
Cache_Flush ();
if (strcmp (dir, fs_basegame->string) == 0)
return;
if (strcmp (dir, "qw") == 0
&& strcmp (fs_basegame->string, "id1") == 0)
return;
COM_AddGameDirectory (dir);
}
/*
================
SV_Gamedir_f
Sets the gamedir and path to a different directory.
================
*/
void COM_Gamedir_f (void)
{
char *dir;
if (Cmd_Argc() == 1)
{
Con_Printf ("Current gamedir: %s\n", gamedirfile);
return;
}
if (Cmd_Argc() != 2)
{
Con_Printf ("Usage: gamedir <newdir>\n");
return;
}
dir = Cmd_Argv(1);
if (strstr(dir, "..") || strstr(dir, "/")
|| strstr(dir, "\\") || strstr(dir, ":") )
{
Con_Printf ("Gamedir should be a single filename, not a path\n");
return;
}
COM_Gamedir (dir);
/* XXX not in nuq?
if (is_server) {
Info_SetValueForStarKey (svs.info, "*gamedir", dir,
MAX_SERVERINFO_STRING);
}
*/
}
/*
COM_InitFilesystem
*/
void
COM_InitFilesystem ( void )
{
fs_sharepath = Cvar_Get ("fs_sharepath", FS_SHAREPATH, CVAR_ROM,
"location of shared (read only) game directories");
fs_userpath = Cvar_Get ("fs_userpath", FS_USERPATH, CVAR_ROM,
"location of your game directories");
fs_basegame = Cvar_Get ("fs_basegame", BASEGAME, CVAR_ROM,
"game to use by default");
Cmd_AddCommand ("gamedir", COM_Gamedir_f);
/*
start up with basegame->string by default
*/
COM_CreatePath (va("%s/%s/dummy", fs_userpath->string,
fs_basegame->string));
COM_AddGameDirectory(fs_basegame->string);
// If we're dealing with id1, use qw too
if (stricmp (fs_basegame->string, "id1") == 0)
{
COM_CreatePath (va("%s/qw/dummy", fs_userpath->string));
COM_AddGameDirectory ("qw");
}
// any set gamedirs will be freed up to here
com_base_searchpaths = com_searchpaths;
}
/*
============
COM_SkipPath
============
*/
char *COM_SkipPath (char *pathname)
{
char *last;
last = pathname;
while (*pathname)
{
if (*pathname=='/')
last = pathname+1;
pathname++;
}
return last;
}
/*
============
COM_StripExtension
============
*/
void COM_StripExtension (char *in, char *out)
{
while (*in && *in != '.')
*out++ = *in++;
*out = 0;
}
/*
============
COM_FileExtension
============
*/
char *COM_FileExtension (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_DefaultExtension
==================
*/
void COM_DefaultExtension (char *path, char *extension)
{
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);
}

193
source/quakeio.c Normal file
View file

@ -0,0 +1,193 @@
/*
quakeio.c
(description)
Copyright (C) 1996-1997 Id Software, Inc.
Copyright (C) 1999,2000 contributors of the QuakeForge project
Please see the file "AUTHORS" for a list of contributors
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HAVE_MALLOC_H
# include <malloc.h>
#endif
#include <stdarg.h>
#include <stdlib.h>
#include <quakeio.h>
#include <string.h>
#ifdef WIN32
# include <io.h>
# include <fcntl.h>
#else
# include <pwd.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef _MSC_VER
# define _POSIX_
#endif
#include <limits.h>
void
Qexpand_squiggle(const char *path, char *dest)
{
char *home;
#ifndef _WIN32
struct passwd *pwd_ent;
#endif
if (strncmp (path, "~/",2) != 0) {
strcpy (dest,path);
return;
}
#ifndef _WIN32
if ((pwd_ent = getpwuid (getuid()))) {
home = pwd_ent->pw_dir;
} else
#endif
home = getenv("HOME");
if (home) {
strcpy (dest, home);
strcat (dest, path+1); // skip leading ~
} else
strcpy (dest,path);
}
int
Qrename(const char *old, const char *new)
{
char e_old[PATH_MAX];
char e_new[PATH_MAX];
Qexpand_squiggle (old, e_old);
Qexpand_squiggle (new, e_new);
return rename (e_old, e_new);
}
FILE *
Qopen(const char *path, const char *mode)
{
FILE *file;
char e_path[PATH_MAX];
Qexpand_squiggle (path, e_path);
path = e_path;
file=fopen(path,mode);
return file;
}
FILE *
Qdopen(int fd, const char *mode)
{
FILE *file;
file=fdopen(fd,mode);
#ifdef WIN32
# ifdef __BORLANDC__
setmode(_fileno(file),O_BINARY);
# else
_setmode(_fileno(file),_O_BINARY);
# endif
#endif
return file;
}
void
Qclose(FILE *file)
{
fclose(file);
}
int
Qread(FILE *file, void *buf, int count)
{
return fread(buf, 1, count, file);
}
int
Qwrite(FILE *file, void *buf, int count)
{
return fwrite(buf, 1, count, file);
}
int
Qprintf(FILE *file, const char *fmt, ...)
{
va_list args;
int ret=-1;
va_start(args,fmt);
ret=vfprintf(file, fmt, args);
va_end(args);
return ret;
}
char *
Qgets(FILE *file, char *buf, int count)
{
return fgets(buf, count, file);
}
int
Qgetc(FILE *file)
{
return fgetc(file);
}
int
Qputc(FILE *file, int c)
{
return fputc(c, file);
}
int
Qseek(FILE *file, long offset, int whence)
{
return fseek(file, offset, whence);
}
long
Qtell(FILE *file)
{
return ftell(file);
}
int
Qflush(FILE *file)
{
return fflush(file);
}
int
Qeof(FILE *file)
{
return feof(file);
}

90
source/sizebuf.c Normal file
View file

@ -0,0 +1,90 @@
/*
sizebuf.c
(description)
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "sizebuf.h"
#include "sys.h"
#include "zone.h"
void SZ_Alloc (sizebuf_t *buf, int startsize)
{
if (startsize < 256)
startsize = 256;
buf->data = Hunk_AllocName (startsize, "sizebuf");
buf->maxsize = startsize;
buf->cursize = 0;
}
void SZ_Clear (sizebuf_t *buf)
{
buf->cursize = 0;
buf->overflowed = false;
}
void *SZ_GetSpace (sizebuf_t *buf, int length)
{
void *data;
if (buf->cursize + length > buf->maxsize)
{
if (!buf->allowoverflow)
Sys_Error ("SZ_GetSpace: overflow without allowoverflow set (%d)", buf->maxsize);
if (length > buf->maxsize)
Sys_Error ("SZ_GetSpace: %i is > full buffer size", length);
Sys_Printf ("SZ_GetSpace: overflow\n"); // because Con_Printf may be redirected
SZ_Clear (buf);
buf->overflowed = true;
}
data = buf->data + buf->cursize;
buf->cursize += length;
return data;
}
void SZ_Write (sizebuf_t *buf, void *data, int length)
{
memcpy (SZ_GetSpace(buf,length),data,length);
}
void SZ_Print (sizebuf_t *buf, char *data)
{
int len;
len = strlen(data)+1;
if (!buf->cursize || buf->data[buf->cursize-1])
memcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0
else
memcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0
}

55
source/va.c Normal file
View file

@ -0,0 +1,55 @@
/*
va.c
varargs printf function
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
$Id$
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <stdarg.h>
#include "qtypes.h"
/*
va
does a varargs printf into a temp buffer, so I don't need to have
varargs versions of all text functions.
FIXME: make this buffer size safe someday
*/
char *
va(char *format, ...)
{
va_list argptr;
static char string[1024];
va_start (argptr, format);
vsnprintf (string, sizeof(string), format, argptr);
va_end (argptr);
return string;
}