ffc2a08589
Added version+time+date to segfault lots. try to use vbo+vao as needed. added a manifest file in order to disable uac emulation and its virtual store lies. particles now support a sort of namespace. eg: an effect called "cfg.effect" will load up the 'cfg' particle config and use its 'effect' effect (but not replace any explicit effects). You can still create particle effects called 'cfg.effect' with no issue. Added support for fsarchive plugins. Added a sys_register_file_associations command. .bsp not yet handled, but demo playback should work fine. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4324 fc73d0e0-1445-4013-8a0c-d673dee63da5
386 lines
9.1 KiB
C
386 lines
9.1 KiB
C
// log.c: handles console logging functions and cvars
|
|
|
|
#include "quakedef.h"
|
|
|
|
// cvar callbacks
|
|
void Log_Dir_Callback (struct cvar_s *var, char *oldvalue);
|
|
void Log_Name_Callback (struct cvar_s *var, char *oldvalue);
|
|
|
|
// cvars
|
|
#define CONLOGGROUP "Console logging"
|
|
cvar_t log_enable[LOG_TYPES] = { CVARF("log_enable", "0", CVAR_NOTFROMSERVER),
|
|
CVARF("log_enable_players", "0", CVAR_NOTFROMSERVER)};
|
|
cvar_t log_name[LOG_TYPES] = { CVARFC("log_name", "", CVAR_NOTFROMSERVER, Log_Name_Callback),
|
|
CVARFC("log_name_players", "", CVAR_NOTFROMSERVER, Log_Name_Callback)};
|
|
cvar_t log_dir = CVARFC("log_dir", "", CVAR_NOTFROMSERVER, Log_Dir_Callback);
|
|
cvar_t log_readable = CVARF("log_readable", "0", CVAR_NOTFROMSERVER);
|
|
cvar_t log_developer = CVARF("log_developer", "0", CVAR_NOTFROMSERVER);
|
|
cvar_t log_rotate_files = CVARF("log_rotate_files", "0", CVAR_NOTFROMSERVER);
|
|
cvar_t log_rotate_size = CVARF("log_rotate_size", "131072", CVAR_NOTFROMSERVER);
|
|
cvar_t log_dosformat = CVARF("log_dosformat", "0", CVAR_NOTFROMSERVER);
|
|
|
|
// externals
|
|
extern char gamedirfile[];
|
|
|
|
// table of readable characters, same as ezquake
|
|
char readable[256] =
|
|
{
|
|
'.', '_', '_', '_', '_', '.', '_', '_',
|
|
'_', '_', '\n', '_', '\n', '>', '.', '.',
|
|
'[', ']', '0', '1', '2', '3', '4', '5',
|
|
'6', '7', '8', '9', '.', '_', '_', '_',
|
|
' ', '!', '\"', '#', '$', '%', '&', '\'',
|
|
'(', ')', '*', '+', ',', '-', '.', '/',
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', ':', ';', '<', '=', '>', '?',
|
|
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
|
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
|
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
|
'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
|
|
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
|
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
|
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
|
|
'x', 'y', 'z', '{', '|', '}', '~', '_',
|
|
'_', '_', '_', '_', '_', '.', '_', '_',
|
|
'_', '_', '_', '_', '_', '>', '.', '.',
|
|
'[', ']', '0', '1', '2', '3', '4', '5',
|
|
'6', '7', '8', '9', '.', '_', '_', '_',
|
|
' ', '!', '\"', '#', '$', '%', '&', '\'',
|
|
'(', ')', '*', '+', ',', '-', '.', '/',
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', ':', ';', '<', '=', '>', '?',
|
|
'@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
|
|
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
|
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
|
|
'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
|
|
'`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
|
|
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
|
|
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
|
|
'x', 'y', 'z', '{', '|', '}', '~', '_'
|
|
};
|
|
|
|
// Log_Dir_Callback: called when a log_dir is changed
|
|
void Log_Dir_Callback (struct cvar_s *var, char *oldvalue)
|
|
{
|
|
char *t = var->string;
|
|
|
|
// sanity check for directory
|
|
if (strstr(t, "..") || strstr(t, ":") || *t == '/' || *t == '\\')
|
|
{
|
|
Con_Printf(CON_NOTICE "%s forced to default due to invalid characters.\n", var->name);
|
|
// recursion is avoided by assuming the default value is sane
|
|
Cvar_ForceSet(var, var->defaultstr);
|
|
}
|
|
}
|
|
|
|
// Log_Name_Callback: called when a log_name is changed
|
|
void Log_Name_Callback (struct cvar_s *var, char *oldvalue)
|
|
{
|
|
char *t = var->string;
|
|
|
|
// sanity check for directory
|
|
if (strstr(t, "..") || strstr(t, ":") || strstr(t, "/") || strstr(t, "\\"))
|
|
{
|
|
Con_Printf(CON_NOTICE "%s forced to default due to invalid characters.\n", var->name);
|
|
// recursion is avoided by assuming the default value is sane
|
|
Cvar_ForceSet(var, var->defaultstr);
|
|
}
|
|
}
|
|
|
|
// Con_Log: log string to console log
|
|
void Log_String (logtype_t lognum, char *s)
|
|
{
|
|
vfsfile_t *fi;
|
|
char *d; // directory
|
|
char *f; // filename
|
|
char *t;
|
|
char logbuf[1024];
|
|
int i;
|
|
char fname[MAX_QPATH];
|
|
|
|
if (!log_enable[lognum].value)
|
|
return;
|
|
|
|
// get directory/filename
|
|
d = gamedirfile;
|
|
if (log_dir.string[0])
|
|
d = log_dir.string;
|
|
|
|
f = NULL;
|
|
switch(lognum)
|
|
{
|
|
case LOG_CONSOLE:
|
|
f = "qconsole";
|
|
break;
|
|
case LOG_PLAYER:
|
|
f = "players";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if (log_name[lognum].string[0])
|
|
f = log_name[lognum].string;
|
|
|
|
if (!f)
|
|
return;
|
|
|
|
// readable translation and Q3 code removal, use t for final string to write
|
|
t = logbuf;
|
|
// max debuglog buf is 1024
|
|
for (i = 0; i < 1023; i++, s++)
|
|
{
|
|
if (*s == 0)
|
|
break;
|
|
else if (((int)(log_readable.value) & 2) && *s == '^')
|
|
{
|
|
// log_readable 2 removes Q3 codes as well
|
|
char c = s[1];
|
|
|
|
if ((c >= '0' && c <= '9') || c == 'a' || c == 'b' || c == 'h' || c == 's' || c == 'r')
|
|
{
|
|
i--;
|
|
s++;
|
|
}
|
|
else if (c == '&')
|
|
{
|
|
if (isextendedcode(s[2]) && isextendedcode(s[3]))
|
|
{
|
|
i--;
|
|
s += 3;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*t = '^';
|
|
t++;
|
|
}
|
|
}
|
|
else if (log_dosformat.value && *s == '\n')
|
|
{
|
|
// convert \n to \r\n
|
|
*t = '\r';
|
|
t++;
|
|
i++;
|
|
if (i < 1023)
|
|
{
|
|
*t = '\n';
|
|
t++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// use readable table to convert quake chars to reabable text
|
|
if ((int)(log_readable.value) & 1)
|
|
*t = readable[(unsigned char)(*s)]; // translate
|
|
else
|
|
*t = *s; // copy
|
|
t++;
|
|
}
|
|
}
|
|
|
|
*t = 0;
|
|
|
|
Q_snprintfz(fname, sizeof(fname), "%s/%s.log",d,f);
|
|
|
|
// file rotation
|
|
if (log_rotate_size.value >= 4096 && log_rotate_files.value >= 1)
|
|
{
|
|
int x;
|
|
vfsfile_t *fi;
|
|
|
|
// check file size, use x as temp
|
|
if ((fi = FS_OpenVFS(fname, "rb", FS_ROOT)))
|
|
{
|
|
x = VFS_GETLEN(fi);
|
|
VFS_CLOSE(fi);
|
|
x += i; // add string size to file size to never go over
|
|
}
|
|
else
|
|
x = 0;
|
|
|
|
if (x > (int)log_rotate_size.value)
|
|
{
|
|
char newf[MAX_OSPATH];
|
|
char oldf[MAX_OSPATH];
|
|
|
|
i = log_rotate_files.value;
|
|
|
|
// unlink file at the top of the chain
|
|
snprintf(oldf, sizeof(oldf)-1, "%s.%i", f, i);
|
|
FS_Remove(oldf, FS_ROOT);
|
|
|
|
// rename files through chain
|
|
for (x = i-1; x > 0; x--)
|
|
{
|
|
strcpy(newf, oldf);
|
|
snprintf(oldf, sizeof(oldf)-1, "%s.%i", f, x);
|
|
|
|
// check if file exists, otherwise skip
|
|
if ((fi = FS_OpenVFS(oldf, "rb", FS_ROOT)))
|
|
VFS_CLOSE(fi);
|
|
else
|
|
continue; // skip nonexistant files
|
|
|
|
if (!FS_Rename(oldf, newf, FS_ROOT))
|
|
{
|
|
// rename failed, disable log and bug out
|
|
Cvar_ForceSet(&log_enable[lognum], "0");
|
|
Con_Printf("Unable to rotate log files. Logging disabled.\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// TODO: option to compress file somewhere in here?
|
|
// rename our base file, which better exist...
|
|
if (!FS_Rename(f, oldf, FS_ROOT))
|
|
{
|
|
// rename failed, disable log and bug out
|
|
Cvar_ForceSet(&log_enable[lognum], "0");
|
|
Con_Printf("Unable to rename base log file. Logging disabled.\n");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
FS_CreatePath(f, FS_ROOT);
|
|
if ((fi = FS_OpenVFS(f, "ab", FS_ROOT)))
|
|
{
|
|
VFS_WRITE(fi, logbuf, strlen(logbuf));
|
|
VFS_CLOSE(fi);
|
|
}
|
|
else
|
|
{
|
|
// write failed, bug out
|
|
Cvar_ForceSet(&log_enable[lognum], "0");
|
|
Con_Printf("Unable to write to log file. Logging disabled.\n");
|
|
return;
|
|
}
|
|
}
|
|
|
|
void Con_Log (char *s)
|
|
{
|
|
Log_String(LOG_CONSOLE, s);
|
|
}
|
|
|
|
|
|
#ifndef CLIENTONLY
|
|
//still to add stuff at:
|
|
//connects
|
|
//disconnects
|
|
//kicked
|
|
void SV_LogPlayer(client_t *cl, char *msg)
|
|
{
|
|
char line[2048];
|
|
char remote_adr[MAX_ADR_SIZE];
|
|
char realip_adr[MAX_ADR_SIZE];
|
|
|
|
if (cl->protocol == SCP_BAD)
|
|
return; //don't log botclients
|
|
|
|
snprintf(line, sizeof(line),
|
|
"%s\\%s\\%i\\%s\\%s\\%i%s\n",
|
|
msg, cl->name, cl->userid,
|
|
NET_BaseAdrToString(remote_adr, sizeof(remote_adr), &cl->netchan.remote_address), (cl->realip_status > 0 ? NET_BaseAdrToString(realip_adr, sizeof(realip_adr), &cl->realip) : "??"),
|
|
cl->netchan.remote_address.port, cl->userinfo);
|
|
|
|
Log_String(LOG_PLAYER, line);
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
void Log_Logfile_f (void)
|
|
{
|
|
extern char gamedirfile[];
|
|
|
|
if (log_enable[LOG_CONSOLE].value)
|
|
{
|
|
Cvar_SetValue(&log_enable[LOG_CONSOLE], 0);
|
|
Con_Printf("Logging disabled.\n");
|
|
}
|
|
else
|
|
{
|
|
char *d, *f;
|
|
|
|
d = gamedirfile;
|
|
if (log_dir.string[0])
|
|
d = log_dir.string;
|
|
|
|
f = "qconsole";
|
|
if (log_name[LOG_CONSOLE].string[0])
|
|
f = log_name[LOG_CONSOLE].string;
|
|
|
|
Con_Printf("%s", va("Logging to %s/%s.log.\n", d, f));
|
|
Cvar_SetValue(&log_enable[LOG_CONSOLE], 1);
|
|
}
|
|
|
|
}
|
|
/*
|
|
void SV_Fraglogfile_f (void)
|
|
{
|
|
char name[MAX_OSPATH];
|
|
int i;
|
|
|
|
if (sv_fraglogfile)
|
|
{
|
|
Con_TPrintf (STL_FLOGGINGOFF);
|
|
VFS_CLOSE (sv_fraglogfile);
|
|
sv_fraglogfile = NULL;
|
|
return;
|
|
}
|
|
|
|
// find an unused name
|
|
for (i=0 ; i<1000 ; i++)
|
|
{
|
|
sprintf (name, "frag_%i.log", i);
|
|
sv_fraglogfile = FS_OpenVFS(name, "rb", FS_GAME);
|
|
if (!sv_fraglogfile)
|
|
{ // can't read it, so create this one
|
|
sv_fraglogfile = FS_OpenVFS (name, "wb", FS_GAME);
|
|
if (!sv_fraglogfile)
|
|
i=1000; // give error
|
|
break;
|
|
}
|
|
VFS_CLOSE (sv_fraglogfile);
|
|
}
|
|
if (i==1000)
|
|
{
|
|
Con_TPrintf (STL_FLOGGINGFAILED);
|
|
sv_fraglogfile = NULL;
|
|
return;
|
|
}
|
|
|
|
Con_TPrintf (STL_FLOGGINGTO, name);
|
|
}
|
|
*/
|
|
|
|
|
|
void Log_Init(void)
|
|
{
|
|
int i;
|
|
// register cvars
|
|
for (i = 0; i < LOG_TYPES; i++)
|
|
{
|
|
Cvar_Register (&log_enable[i], CONLOGGROUP);
|
|
Cvar_Register (&log_name[i], CONLOGGROUP);
|
|
}
|
|
Cvar_Register (&log_dir, CONLOGGROUP);
|
|
Cvar_Register (&log_readable, CONLOGGROUP);
|
|
Cvar_Register (&log_developer, CONLOGGROUP);
|
|
Cvar_Register (&log_rotate_size, CONLOGGROUP);
|
|
Cvar_Register (&log_rotate_files, CONLOGGROUP);
|
|
Cvar_Register (&log_dosformat, CONLOGGROUP);
|
|
|
|
Cmd_AddCommand("logfile", Log_Logfile_f);
|
|
|
|
// cmd line options, debug options
|
|
#ifdef CRAZYDEBUGGING
|
|
Cvar_ForceSet(&log_enable[LOG_CONSOLE], "1");
|
|
TRACE(("dbg: Con_Init: log_enable forced\n"));
|
|
#endif
|
|
|
|
if (COM_CheckParm("-condebug"))
|
|
Cvar_ForceSet(&log_enable[LOG_CONSOLE], "1");
|
|
}
|