mirror of
https://git.code.sf.net/p/quake/nuq
synced 2024-11-25 05:21:41 +00:00
nuq-svga now links
This commit is contained in:
parent
9f8660c30e
commit
7b52e8b908
13 changed files with 2519 additions and 2026 deletions
|
@ -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)
|
||||
|
||||
#
|
||||
|
|
557
source/cmd.c
557
source/cmd.c
|
@ -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
|
||||
|
@ -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,7 +144,7 @@ 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);
|
||||
}
|
||||
|
@ -149,61 +153,92 @@ void Cbuf_InsertText (char *text)
|
|||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Cbuf_Execute
|
||||
============
|
||||
*/
|
||||
void Cbuf_Execute (void)
|
||||
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;
|
||||
char line[1024];
|
||||
int quotes;
|
||||
|
||||
while (cmd_text.cursize)
|
||||
{
|
||||
// find a \n or ; line break
|
||||
text = (char *)cmd_text.data;
|
||||
|
||||
quotes = 0;
|
||||
for (i=0 ; i< cmd_text.cursize ; i++)
|
||||
{
|
||||
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')
|
||||
if (text[i] == '\n' || text[i] == '\r')
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
memcpy (line, text, i);
|
||||
line[i] = 0;
|
||||
|
||||
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
|
||||
{
|
||||
else {
|
||||
i++;
|
||||
cmd_text.cursize -= i;
|
||||
memcpy (text, text+i, cmd_text.cursize);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Cbuf_Execute
|
||||
|
||||
*/
|
||||
void
|
||||
Cbuf_Execute (void)
|
||||
{
|
||||
char line[1024] = {0};
|
||||
|
||||
while (cmd_text.cursize) {
|
||||
extract_line (line);
|
||||
// execute the command line
|
||||
//Con_DPrintf("+%s\n",line),
|
||||
Cmd_ExecuteString (line, src_command);
|
||||
|
||||
if (cmd_wait)
|
||||
|
@ -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;
|
||||
char *build, c;
|
||||
|
||||
if (Cmd_Argc () != 1)
|
||||
{
|
||||
Con_Printf ("stuffcmds : execute command line parameters\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// 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;
|
||||
c = com_cmdline[j];
|
||||
com_cmdline[j] = 0;
|
||||
|
||||
strcat (build, text+i);
|
||||
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,6 +384,7 @@ void Cmd_Exec_f (void)
|
|||
Con_Printf ("couldn't exec %s\n",Cmd_Argv(1));
|
||||
return;
|
||||
}
|
||||
if (!Cvar_Command () && (cl_warncmd->value || developer->value))
|
||||
Con_Printf ("execing %s\n",Cmd_Argv(1));
|
||||
|
||||
Cbuf_InsertText (f);
|
||||
|
@ -356,7 +420,7 @@ char *CopyString (char *in)
|
|||
{
|
||||
char *out;
|
||||
|
||||
out = Z_Malloc (strlen(in)+1);
|
||||
out = malloc (strlen(in)+1);
|
||||
strcpy (out, in);
|
||||
return out;
|
||||
}
|
||||
|
@ -388,14 +452,14 @@ 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;
|
||||
}
|
||||
|
@ -415,6 +479,41 @@ void Cmd_Alias_f (void)
|
|||
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,7 +558,7 @@ Cmd_Argv
|
|||
*/
|
||||
char *Cmd_Argv (int arg)
|
||||
{
|
||||
if ( (unsigned)arg >= cmd_argc )
|
||||
if ( arg >= cmd_argc )
|
||||
return cmd_null_string;
|
||||
return cmd_argv[arg];
|
||||
}
|
||||
|
@ -486,10 +566,14 @@ char *Cmd_Argv (int 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,11 +587,10 @@ Parses the given string into command line tokens.
|
|||
*/
|
||||
void Cmd_TokenizeString (char *text)
|
||||
{
|
||||
int i;
|
||||
static char argv_buf[1024];
|
||||
int argv_idx;
|
||||
|
||||
// clear the args from the last string
|
||||
for (i=0 ; i<cmd_argc ; i++)
|
||||
Z_Free (cmd_argv[i]);
|
||||
argv_idx = 0;
|
||||
|
||||
cmd_argc = 0;
|
||||
cmd_args = NULL;
|
||||
|
@ -515,7 +598,7 @@ void Cmd_TokenizeString (char *text)
|
|||
while (1)
|
||||
{
|
||||
// skip whitespace up to a /n
|
||||
while (*text && *text <= ' ' && *text != '\n')
|
||||
while (*text && *(unsigned char*)text <= ' ' && *text != '\n')
|
||||
{
|
||||
text++;
|
||||
}
|
||||
|
@ -538,8 +621,15 @@ void Cmd_TokenizeString (char *text)
|
|||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -638,9 +820,16 @@ 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())
|
||||
|
@ -651,11 +840,18 @@ void Cmd_ExecuteString (char *text, cmd_source_t src)
|
|||
{
|
||||
if (!strcasecmp (cmd_argv[0],cmd->name))
|
||||
{
|
||||
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
|
||||
|
@ -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
110
source/com.c
Normal 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 ();
|
||||
}
|
1837
source/common.c
1837
source/common.c
File diff suppressed because it is too large
Load diff
|
@ -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
60
source/link.c
Normal 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
265
source/msg.c
Normal 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
155
source/qargs.c
Normal 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
105
source/qendian.c
Normal 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
996
source/quakefs.c
Normal 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
193
source/quakeio.c
Normal 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
90
source/sizebuf.c
Normal 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
55
source/va.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue