"DP_QC_GETTAGINFO "
"DP_QC_MINMAXBOUND "
"DP_QC_MULTIPLETEMPSTRINGS "
+"DP_QC_UNLIMITEDTEMPSTRINGS "
"DP_QC_RANDOMVEC "
"DP_QC_SINCOSSQRTPOW "
//"DP_QC_STRINGBUFFERS " //[515]: not needed ?
// #19 void(string s) precache_sound
void VM_CL_precache_sound (void)
{
- const char *n;
VM_SAFEPARMCOUNT(1, VM_CL_precache_sound);
- n = PRVM_G_STRING(OFS_PARM0);
- S_PrecacheSound(n, true, false);
+ S_PrecacheSound(PRVM_G_STRING(OFS_PARM0), true, false);
}
// #20 void(string s) precache_model
void VM_CL_getstats (void)
{
int i;
- char *t;
+ char t[17];
VM_SAFEPARMCOUNT(1, VM_CL_getstats);
i = (int)PRVM_G_FLOAT(OFS_PARM0);
if(i < 0 || i > MAX_CL_STATS-4)
{
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
VM_Warning("VM_CL_getstats: index>MAX_CL_STATS-4 or index<0\n");
return;
}
- t = VM_GetTempString();
- strlcpy(t, (char*)&cl.stats[i], 16);
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(t);
+ strlcpy(t, (char*)&cl.stats[i], sizeof(t));
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
}
//#333 void(entity e, float mdlindex) setmodelindex (EXT_CSQC)
VM_SAFEPARMCOUNT(1, VM_CL_modelnameforindex);
- PRVM_G_INT(OFS_RETURN) = 0;
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
model = CSQC_GetModelByIndex((int)PRVM_G_FLOAT(OFS_PARM0));
PRVM_G_INT(OFS_RETURN) = model ? PRVM_SetEngineString(model->name) : 0;
}
//#335 float(string effectname) particleeffectnum (EXT_CSQC)
void VM_CL_particleeffectnum (void)
{
- const char *n;
int i;
VM_SAFEPARMCOUNT(1, VM_CL_particleeffectnum);
- n = PRVM_G_STRING(OFS_PARM0);
- i = CL_ParticleEffectIndexForName(n);
+ i = CL_ParticleEffectIndexForName(PRVM_G_STRING(OFS_PARM0));
if (i == 0)
i = -1;
PRVM_G_FLOAT(OFS_RETURN) = i;
//#342 string(float keynum) getkeybind (EXT_CSQC)
void VM_CL_getkeybind (void)
{
- int i;
-
VM_SAFEPARMCOUNT(1, VM_CL_getkeybind);
- i = (int)PRVM_G_FLOAT(OFS_PARM0);
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(Key_GetBind(i));
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_GetBind((int)PRVM_G_FLOAT(OFS_PARM0)));
}
//#343 void(float usecursor) setcursormode (EXT_CSQC)
int i;
char t[128];
const char *c;
- char *temp;
VM_SAFEPARMCOUNT(2, VM_CL_getplayerkey);
else
if(!strcasecmp(c, "frags"))
sprintf(t, "%i", cl.scores[i].frags);
-// else
-// if(!strcasecmp(c, "ping"))
-// sprintf(t, "%i", cl.scores[i].ping);
-// else
-// if(!strcasecmp(c, "entertime"))
-// sprintf(t, "%f", cl.scores[i].entertime);
+ else
+ if(!strcasecmp(c, "ping"))
+ sprintf(t, "%i", cl.scores[i].qw_ping);
+ else
+ if(!strcasecmp(c, "entertime"))
+ sprintf(t, "%f", cl.scores[i].qw_entertime);
else
if(!strcasecmp(c, "colors"))
sprintf(t, "%i", cl.scores[i].colors);
sprintf(t, "%i", i+1);
if(!t[0])
return;
- temp = VM_GetTempString();
- strlcpy(temp, t, VM_STRINGTEMP_LENGTH);
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(temp);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
}
//#349 float() isdemo (EXT_CSQC)
//#366 string() readstring (EXT_CSQC)
void VM_CL_ReadString (void)
{
- char *t, *s;
- t = VM_GetTempString();
- s = MSG_ReadString();
- PRVM_G_INT(OFS_RETURN) = 0;
- if(s)
- {
- strlcpy(t, s, VM_STRINGTEMP_LENGTH);
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(t);
- }
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(MSG_ReadString());
}
//#367 float() readfloat (EXT_CSQC)
{
model_t *model;
msurface_t *surface;
- PRVM_G_INT(OFS_RETURN) = 0;
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
if (!(model = CSQC_GetModelFromEntity(PRVM_G_EDICT(OFS_PARM0))) || !(surface = cl_getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
return;
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
}
// #438 float(entity e, vector p) getsurfacenearpoint
void VM_uncolorstring (void) //#170
{
const char *in;
- char *out;
+ char out[VM_STRINGTEMP_LENGTH];
int k = 0, i = 0;
VM_SAFEPARMCOUNT(1, VM_uncolorstring);
in = PRVM_G_STRING(OFS_PARM0);
- if(!in)
- PRVM_ERROR ("VM_uncolorstring: %s: NULL\n", PRVM_NAME);
VM_CheckEmptyString (in);
- out = VM_GetTempString();
while (in[k])
{
++k;
++i;
}
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(out);
}
void VM_CL_selecttraceline (void)
{
const char *s;
s = PRVM_G_STRING(OFS_PARM0);
- if(!s)
- return;
if((unsigned)PRVM_G_FLOAT(OFS_PARM1) > strlen(s))
return;
PRVM_G_FLOAT(OFS_RETURN) = (unsigned char)s[(int)PRVM_G_FLOAT(OFS_PARM1)];
//#223 string(float c, ...) chr2str (FTE_STRINGS)
void VM_chr2str (void)
{
- char *t;
+ char t[128];
int i;
- t = VM_GetTempString();
- for(i=0;i<prog->argc;i++)
+ for(i = 0;i < prog->argc && i < (int)sizeof(t) - 1;i++)
t[i] = (unsigned char)PRVM_G_FLOAT(OFS_PARM0+i*3);
t[i] = 0;
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(t);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(t);
}
//#228 float(string s1, string s2, float len) strncmp (FTE_STRINGS)
return true;
}
+extern sizebuf_t vm_tempstringsbuf;
qboolean CL_VM_ConsoleCommand (const char *cmd)
{
+ int restorevm_tempstringsbuf_cursize;
qboolean r;
if(!csqc_loaded)
return false;
CSQC_BEGIN
*prog->time = cl.time;
- PRVM_G_INT(OFS_PARM0) = PRVM_SetEngineString(cmd);
+ restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
+ PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(cmd);
PRVM_ExecuteProgram (prog->globals.client->CSQC_ConsoleCommand, CL_F_CONSOLECOMMAND);
+ vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
r = CSQC_RETURNVAL;
CSQC_END
return r;
void CL_VM_Parse_StuffCmd (const char *msg)
{
+ int restorevm_tempstringsbuf_cursize;
if(msg[0] == 'c')
if(msg[1] == 's')
if(msg[2] == 'q')
}
CSQC_BEGIN
*prog->time = cl.time;
- PRVM_G_INT(OFS_PARM0) = PRVM_SetEngineString(msg);
+ restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
+ PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
PRVM_ExecuteProgram ((func_t)(CSQC_Parse_StuffCmd - prog->functions), CL_F_PARSE_STUFFCMD);
+ vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
CSQC_END
}
static void CL_VM_Parse_Print (const char *msg)
{
+ int restorevm_tempstringsbuf_cursize;
CSQC_BEGIN
*prog->time = cl.time;
- PRVM_G_INT(OFS_PARM0) = PRVM_SetEngineString(msg);
+ restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
+ PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
PRVM_ExecuteProgram ((func_t)(CSQC_Parse_Print - prog->functions), CL_F_PARSE_PRINT);
+ vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
CSQC_END
}
void CL_VM_Parse_CenterPrint (const char *msg)
{
+ int restorevm_tempstringsbuf_cursize;
if(!csqc_loaded || !CSQC_Parse_CenterPrint)
{
SCR_CenterPrint((char*)msg);
}
CSQC_BEGIN
*prog->time = cl.time;
- PRVM_G_INT(OFS_PARM0) = PRVM_SetEngineString(msg);
+ restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
+ PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(msg);
PRVM_ExecuteProgram ((func_t)(CSQC_Parse_CenterPrint - prog->functions), CL_F_PARSE_CENTERPRINT);
+ vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
CSQC_END
}
"DP_CINEMATIC_DPV "
"DP_MENU_EXTRESPONSEPACKET "
"DP_QC_ASINACOSATANATAN2TAN "
-"DP_QC_STRINGCOLORFUNCTIONS";
+"DP_QC_STRINGCOLORFUNCTIONS "
+"DP_QC_UNLIMITEDTEMPSTRINGS";
/*
=========
s = PRVM_G_STRING(OFS_PARM0 + (prog->argc - 1));
- if(!s)
- PRVM_ERROR("VM_M_callfunction: null string !");
-
VM_CheckEmptyString(s);
func = PRVM_ED_FindFunction(s);
s = PRVM_G_STRING(OFS_PARM0);
- if(!s)
- PRVM_ERROR("VM_M_isfunction: null string !");
-
VM_CheckEmptyString(s);
func = PRVM_ED_FindFunction(s);
void VM_M_findkeysforcommand(void)
{
const char *cmd;
- char *ret;
+ char ret[VM_STRINGTEMP_LENGTH];
int keys[NUMKEYS];
int i;
VM_CheckEmptyString(cmd);
- (ret = VM_GetTempString())[0] = 0;
-
M_FindKeysForCommand(cmd, keys);
+ ret[0] = 0;
for(i = 0; i < NUMKEYS; i++)
- strlcat(ret, va(" \'%i\'", keys[i]), VM_STRINGTEMP_LENGTH);
+ strlcat(ret, va(" \'%i\'", keys[i]), sizeof(ret));
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(ret);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(ret);
}
/*
VM_SAFEPARMCOUNT( 4, VM_M_setserverlistmaskstring );
str = PRVM_G_STRING( OFS_PARM2 );
- if( !str )
- PRVM_ERROR( "VM_M_setserverlistmaskstring: null string passed!" );
masknr = (int)PRVM_G_FLOAT( OFS_PARM0 );
if( masknr >= 0 && masknr <= SERVERLIST_ANDMASKCOUNT )
VM_SAFEPARMCOUNT(2, VM_M_getserverliststring);
- PRVM_G_INT(OFS_RETURN) = 0;
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
hostnr = (int)PRVM_G_FLOAT(OFS_PARM1);
VM_SAFEPARMCOUNT(2, VM_M_getserverliststring);
- PRVM_G_INT(OFS_RETURN) = 0;
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
hostnr = (int)PRVM_G_FLOAT(OFS_PARM1);
VM_SAFEPARMCOUNT(0,VM_argv);
if (net_extresponse_count <= 0)
- {
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(NULL);
- }
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
else
{
int first;
const char *PRVM_GetString(int num);
int PR_SetQCString(const char *s);
int PRVM_SetEngineString(const char *s);
+int PRVM_SetTempString(const char *s);
char *PR_AllocString(int bufferlength);
void PR_FreeString(char *s);
const char *PRVM_GetString(int num);
int PRVM_SetEngineString(const char *s);
+int PRVM_SetTempString(const char *s);
int PRVM_AllocString(size_t bufferlength, char **pointer);
void PRVM_FreeString(int num);
//============================================================================
// Common
-// temp string handling
-// LordHavoc: added this to semi-fix the problem of using many ftos calls in a print
-static char vm_string_temp[VM_STRINGTEMP_BUFFERS][VM_STRINGTEMP_LENGTH];
-static int vm_string_tempindex = 0;
-
-// TODO: (move vm_files and vm_fssearchlist to prvm_prog_t struct)
+// TODO DONE: move vm_files and vm_fssearchlist to prvm_prog_t struct
// TODO: move vm_files and vm_fssearchlist back [9/13/2006 Black]
-char *VM_GetTempString(void)
-{
- char *s;
- s = vm_string_temp[vm_string_tempindex];
- vm_string_tempindex = (vm_string_tempindex + 1) % VM_STRINGTEMP_BUFFERS;
- return s;
-}
+// TODO: (move vm_files and vm_fssearchlist to prvm_prog_t struct again) [2007-01-23 LordHavoc]
+// TODO: will this war ever end? [2007-01-23 LordHavoc]
void VM_CheckEmptyString (const char *s)
{
*/
void VM_cvar_string(void)
{
- char *out;
const char *name;
- const char *cvar_string;
VM_SAFEPARMCOUNT(1,VM_cvar_string);
name = PRVM_G_STRING(OFS_PARM0);
- if(!name)
- PRVM_ERROR("VM_cvar_string: %s: null string", PRVM_NAME);
-
VM_CheckEmptyString(name);
- out = VM_GetTempString();
-
- cvar_string = Cvar_VariableString(name);
-
- strlcpy(out, cvar_string, VM_STRINGTEMP_LENGTH);
-
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(out);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Cvar_VariableString(name));
}
*/
void VM_cvar_defstring (void)
{
- char *out;
const char *name;
- const char *cvar_string;
VM_SAFEPARMCOUNT(1,VM_cvar_string);
name = PRVM_G_STRING(OFS_PARM0);
- if(!name)
- PRVM_ERROR("VM_cvar_defstring: %s: null string", PRVM_NAME);
-
VM_CheckEmptyString(name);
- out = VM_GetTempString();
-
- cvar_string = Cvar_VariableDefString(name);
-
- strlcpy(out, cvar_string, VM_STRINGTEMP_LENGTH);
-
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(out);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Cvar_VariableDefString(name));
}
/*
=================
void VM_ftos (void)
{
float v;
- char *s;
+ char s[128];
VM_SAFEPARMCOUNT(1, VM_ftos);
v = PRVM_G_FLOAT(OFS_PARM0);
- s = VM_GetTempString();
if ((float)((int)v) == v)
sprintf(s, "%i", (int)v);
else
sprintf(s, "%f", v);
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(s);
}
/*
void VM_vtos (void)
{
- char *s;
+ char s[512];
VM_SAFEPARMCOUNT(1,VM_vtos);
- s = VM_GetTempString();
sprintf (s, "'%5.1f %5.1f %5.1f'", PRVM_G_VECTOR(OFS_PARM0)[0], PRVM_G_VECTOR(OFS_PARM0)[1], PRVM_G_VECTOR(OFS_PARM0)[2]);
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(s);
}
/*
void VM_etos (void)
{
- char *s;
+ char s[128];
VM_SAFEPARMCOUNT(1, VM_etos);
- s = VM_GetTempString();
sprintf (s, "entity %i", PRVM_G_EDICTNUM(OFS_PARM0));
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(s);
}
/*
// LordHavoc: apparently BloodMage does a find(world, weaponmodel, "") and
// expects it to find all the monsters, so we must be careful to support
// searching for ""
- if (!s)
- s = "";
for (e++ ; e < prog->num_edicts ; e++)
{
// LordHavoc: apparently BloodMage does a find(world, weaponmodel, "") and
// expects it to find all the monsters, so we must be careful to support
// searching for ""
- if (!s)
- s = "";
ent = PRVM_NEXT_EDICT(prog->edicts);
for (i = 1;i < prog->num_edicts;i++, ent = PRVM_NEXT_EDICT(ent))
*/
void VM_changelevel (void)
{
- const char *s;
-
VM_SAFEPARMCOUNT(1, VM_changelevel);
if(!sv.active)
return;
svs.changelevel_issued = true;
- s = PRVM_G_STRING(OFS_PARM0);
- Cbuf_AddText (va("changelevel %s\n",s));
+ Cbuf_AddText (va("changelevel %s\n",PRVM_G_STRING(OFS_PARM0)));
}
/*
void VM_fgets(void)
{
int c, end;
- static char string[VM_STRINGTEMP_LENGTH];
+ char string[VM_STRINGTEMP_LENGTH];
int filenum;
VM_SAFEPARMCOUNT(1,VM_fgets);
if (developer.integer >= 100)
Con_Printf("fgets: %s: %s\n", PRVM_NAME, string);
if (c >= 0 || end)
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(string);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
else
- PRVM_G_INT(OFS_RETURN) = 0;
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
}
/*
//float(string s) strlen = #114; // returns how many characters are in a string
void VM_strlen(void)
{
- const char *s;
-
VM_SAFEPARMCOUNT(1,VM_strlen);
- s = PRVM_G_STRING(OFS_PARM0);
- if (s)
- PRVM_G_FLOAT(OFS_RETURN) = strlen(s);
- else
- PRVM_G_FLOAT(OFS_RETURN) = 0;
+ PRVM_G_FLOAT(OFS_RETURN) = strlen(PRVM_G_STRING(OFS_PARM0));
}
// DRESK - Decolorized String
// string (string s) strdecolorize = #472; // returns the passed in string with color codes stripped
void VM_strdecolorize(void)
{
- char *szNewString;
+ char szNewString[VM_STRINGTEMP_LENGTH];
const char *szString;
size_t nCnt;
int nPos;
// Prepare Strings
VM_SAFEPARMCOUNT(1,VM_strdecolorize);
szString = PRVM_G_STRING(OFS_PARM0);
- szNewString = VM_GetTempString();
while(!bFinished)
{ // Traverse through String
nPos = nPos + 1;
}
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(szNewString);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(szNewString);
}
// DRESK - String Length (not counting color codes)
VM_SAFEPARMCOUNT(1,VM_strlennocol);
szString = PRVM_G_STRING(OFS_PARM0);
- if(szString)
- { // Valid String
- while(!bFinished)
- { // Count Characters
- // SV_BroadcastPrintf("Position '%d'; Character '%c'; Length '%d'\n", nPos, szString[nPos], nCnt);
-
- if( szString[nPos] == '\n' || szString[nPos] == '\r' || szString[nPos] <= 0)
- { // String End Found
- // SV_BroadcastPrintf("Found End of String at '%d'\n", nPos);
- bFinished = 1;
+
+ while(!bFinished)
+ { // Count Characters
+ // SV_BroadcastPrintf("Position '%d'; Character '%c'; Length '%d'\n", nPos, szString[nPos], nCnt);
+
+ if( szString[nPos] == '\n' || szString[nPos] == '\r' || szString[nPos] <= 0)
+ { // String End Found
+ // SV_BroadcastPrintf("Found End of String at '%d'\n", nPos);
+ bFinished = 1;
+ }
+ else
+ if( szString[nPos] == STRING_COLOR_TAG)
+ { // Color Code Located
+ if( szString[nPos + 1] == STRING_COLOR_TAG)
+ { // Increment Length; Skip Color Code
+ nCnt = nCnt + 1;
+ nPos = nPos + 1;
}
else
- if( szString[nPos] == STRING_COLOR_TAG)
- { // Color Code Located
- if( szString[nPos + 1] == STRING_COLOR_TAG)
- { // Increment Length; Skip Color Code
- nCnt = nCnt + 1;
- nPos = nPos + 1;
- }
- else
- if( szString[nPos + 1] >= '0' && szString[nPos + 1] <= '9' )
- { // Color Code Found; Increment Position
- // SV_BroadcastPrintf("Found Color Codes at '%d'\n", nPos);
- nPos = nPos + 1;
- }
- else
- { // Unknown Color Code; Increment Length!
- nPos = nPos + 1;
- nCnt = nCnt + 1;
- }
+ if( szString[nPos + 1] >= '0' && szString[nPos + 1] <= '9' )
+ { // Color Code Found; Increment Position
+ // SV_BroadcastPrintf("Found Color Codes at '%d'\n", nPos);
+ nPos = nPos + 1;
}
else
- // Increment String Length
+ { // Unknown Color Code; Increment Length!
+ nPos = nPos + 1;
nCnt = nCnt + 1;
-
- // Increment Position
- nPos = nPos + 1;
+ }
}
- PRVM_G_FLOAT(OFS_RETURN) = nCnt;
+ else
+ // Increment String Length
+ nCnt = nCnt + 1;
+
+ // Increment Position
+ nPos = nPos + 1;
}
- else
- PRVM_G_FLOAT(OFS_RETURN) = 0;
+ PRVM_G_FLOAT(OFS_RETURN) = nCnt;
}
/*
// and returns as a tempstring
void VM_strcat(void)
{
- char *s;
+ char s[VM_STRINGTEMP_LENGTH];
if(prog->argc < 1)
PRVM_ERROR("VM_strcat wrong parameter count (min. 1 expected ) !");
- s = VM_GetTempString();
- VM_VarString(0, s, VM_STRINGTEMP_LENGTH);
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(s);
+ VM_VarString(0, s, sizeof(s));
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(s);
}
/*
{
int i, start, length;
const char *s;
- char *string;
+ char string[VM_STRINGTEMP_LENGTH];
VM_SAFEPARMCOUNT(3,VM_substring);
- string = VM_GetTempString();
s = PRVM_G_STRING(OFS_PARM0);
start = (int)PRVM_G_FLOAT(OFS_PARM1);
length = (int)PRVM_G_FLOAT(OFS_PARM2);
- if (!s)
- s = "";
for (i = 0;i < start && *s;i++, s++);
- for (i = 0;i < VM_STRINGTEMP_LENGTH - 1 && *s && i < length;i++, s++)
+ for (i = 0;i < (int)sizeof(string) - 1 && *s && i < length;i++, s++)
string[i] = *s;
string[i] = 0;
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(string);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(string);
}
/*
//this function originally written by KrimZon, made shorter by LordHavoc
//20040203: rewritten by LordHavoc (no longer uses allocations)
int num_tokens = 0;
-char *tokens[256], tokenbuf[MAX_INPUTLINE];
+int tokens[256];
void VM_tokenize (void)
{
- size_t pos;
const char *p;
+#if 0
+ size_t pos = 0;
+ char tokenbuf[MAX_INPUTLINE];
+ size_t tokenlen;
+#endif
VM_SAFEPARMCOUNT(1,VM_tokenize);
p = PRVM_G_STRING(OFS_PARM0);
num_tokens = 0;
- pos = 0;
while(COM_ParseToken(&p, false))
{
- size_t tokenlen;
if (num_tokens >= (int)(sizeof(tokens)/sizeof(tokens[0])))
break;
+#if 0
tokenlen = strlen(com_token) + 1;
if (pos + tokenlen > sizeof(tokenbuf))
break;
- tokens[num_tokens++] = tokenbuf + pos;
+ tokens[num_tokens++] = PRVM_SetEngineString(tokenbuf + pos);
memcpy(tokenbuf + pos, com_token, tokenlen);
pos += tokenlen;
+#else
+ tokens[num_tokens++] = PRVM_SetTempString(com_token);
+#endif
}
PRVM_G_FLOAT(OFS_RETURN) = num_tokens;
token_num = (int)PRVM_G_FLOAT(OFS_PARM0);
if (token_num >= 0 && token_num < num_tokens)
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tokens[token_num]);
+ PRVM_G_INT(OFS_RETURN) = tokens[token_num];
else
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(NULL);
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
}
/*
VM_SAFEPARMCOUNT(1,VM_loadfromfile);
filename = PRVM_G_STRING(OFS_PARM0);
- // .. is parent directory on many platforms
- // / is parent directory on Amiga
- // : is root of drive on Amiga (also used as a directory separator on Mac, but / works there too, so that's a bad idea)
- // \ is a windows-ism (so it's naughty to use it, / works on all platforms)
- if ((filename[0] == '.' && filename[1] == '.') || filename[0] == '/' || strrchr(filename, ':') || strrchr(filename, '\\'))
+ if (FS_CheckNastyPath(filename, false))
{
PRVM_G_FLOAT(OFS_RETURN) = -4;
VM_Warning("VM_loadfromfile: %s dangerous or non-portable filename \"%s\" not allowed. (contains : or \\ or begins with .. or /)\n", PRVM_NAME, filename);
void VM_search_getfilename(void)
{
int handle, filenum;
- char *tmp;
VM_SAFEPARMCOUNT(2, VM_search_getfilename);
handle = (int)PRVM_G_FLOAT(OFS_PARM0);
return;
}
- tmp = VM_GetTempString();
- strlcpy(tmp, prog->opensearches[handle]->filenames[filenum], VM_STRINGTEMP_LENGTH);
-
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(prog->opensearches[handle]->filenames[filenum]);
}
/*
*/
void VM_chr(void)
{
- char *tmp;
+ char tmp[2];
VM_SAFEPARMCOUNT(1, VM_chr);
- tmp = VM_GetTempString();
tmp[0] = (unsigned char) PRVM_G_FLOAT(OFS_PARM0);
tmp[1] = 0;
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(tmp);
}
//=============================================================================
s = PRVM_G_STRING(OFS_PARM0);
PRVM_G_INT(OFS_RETURN) = PRVM_G_INT(OFS_PARM0);
-
- if(!s)
- PRVM_ERROR ("VM_precache_pic: %s: NULL", PRVM_NAME);
-
VM_CheckEmptyString (s);
// AK Draw_CachePic is supposed to always return a valid pointer
if( Draw_CachePic(s, false)->tex == r_texture_notexture )
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(NULL);
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
}
/*
VM_SAFEPARMCOUNT(1,VM_freepic);
s = PRVM_G_STRING(OFS_PARM0);
-
- if(!s)
- PRVM_ERROR ("VM_freepic: NULL");
-
VM_CheckEmptyString (s);
Draw_FreePic(s);
VM_SAFEPARMCOUNT(6,VM_drawstring);
string = PRVM_G_STRING(OFS_PARM1);
- if(!string)
- {
- PRVM_G_FLOAT(OFS_RETURN) = -1;
- VM_Warning("VM_drawstring: %s passed null string !\n",PRVM_NAME);
- return;
- }
-
- //VM_CheckEmptyString(string); Why should it be checked - perhaps the menu wants to support the precolored letters, too?
-
pos = PRVM_G_VECTOR(OFS_PARM0);
scale = PRVM_G_VECTOR(OFS_PARM2);
rgb = PRVM_G_VECTOR(OFS_PARM3);
VM_SAFEPARMCOUNT(6,VM_drawpic);
picname = PRVM_G_STRING(OFS_PARM1);
-
- if(!picname)
- {
- PRVM_G_FLOAT(OFS_RETURN) = -1;
- VM_Warning("VM_drawpic: %s passed null picture name !\n", PRVM_NAME);
- return;
- }
-
VM_CheckEmptyString (picname);
// is pic cached ? no function yet for that
VM_SAFEPARMCOUNT(1,VM_getimagesize);
p = PRVM_G_STRING(OFS_PARM0);
-
- if(!p)
- PRVM_ERROR("VM_getimagepos: %s passed null picture name !", PRVM_NAME);
-
VM_CheckEmptyString (p);
pic = Draw_CachePic (p, false);
*/
void VM_keynumtostring (void)
{
- int keynum;
- char *tmp;
VM_SAFEPARMCOUNT(1, VM_keynumtostring);
- keynum = (int)PRVM_G_FLOAT(OFS_PARM0);
-
- tmp = VM_GetTempString();
-
- strlcpy(tmp, Key_KeynumToString(keynum), VM_STRINGTEMP_LENGTH);
-
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(tmp);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(Key_KeynumToString((int)PRVM_G_FLOAT(OFS_PARM0)));
}
/*
*/
void VM_stringtokeynum (void)
{
- const char *str;
VM_SAFEPARMCOUNT( 1, VM_keynumtostring );
- str = PRVM_G_STRING( OFS_PARM0 );
-
- PRVM_G_INT(OFS_RETURN) = Key_StringToKeynum( str );
+ PRVM_G_INT(OFS_RETURN) = Key_StringToKeynum(PRVM_G_STRING(OFS_PARM0));
}
// CL_Video interface functions
*/
void VM_altstr_prepare( void )
{
- char *outstr, *out;
+ char *out;
const char *instr, *in;
int size;
+ char outstr[VM_STRINGTEMP_LENGTH];
VM_SAFEPARMCOUNT( 1, VM_altstr_prepare );
instr = PRVM_G_STRING( OFS_PARM0 );
- //VM_CheckEmptyString( instr );
- outstr = VM_GetTempString();
- for( out = outstr, in = instr, size = VM_STRINGTEMP_LENGTH - 1 ; size && *in ; size--, in++, out++ )
+ for( out = outstr, in = instr, size = sizeof(outstr) - 1 ; size && *in ; size--, in++, out++ )
if( *in == '\'' ) {
*out++ = '\\';
*out = '\'';
*out = *in;
*out = 0;
- PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr );
+ PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr );
}
/*
void VM_altstr_get( void )
{
const char *altstr, *pos;
- char *outstr, *out;
+ char *out;
int count, size;
+ char outstr[VM_STRINGTEMP_LENGTH];
VM_SAFEPARMCOUNT( 2, VM_altstr_get );
altstr = PRVM_G_STRING( OFS_PARM0 );
- //VM_CheckEmptyString( altstr );
count = (int)PRVM_G_FLOAT( OFS_PARM1 );
count = count * 2 + 1;
count--;
if( !*pos ) {
- PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( NULL );
+ PRVM_G_INT( OFS_RETURN ) = 0;
return;
}
- outstr = VM_GetTempString();
- for( out = outstr, size = VM_STRINGTEMP_LENGTH - 1 ; size && *pos ; size--, pos++, out++ )
+ for( out = outstr, size = sizeof(outstr) - 1 ; size && *pos ; size--, pos++, out++ )
if( *pos == '\\' ) {
if( !*++pos )
break;
*out = *pos;
*out = 0;
- PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr );
+ PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr );
}
/*
int num;
const char *altstr, *str;
const char *in;
- char *outstr, *out;
+ char *out;
+ char outstr[VM_STRINGTEMP_LENGTH];
VM_SAFEPARMCOUNT( 3, VM_altstr_set );
altstr = PRVM_G_STRING( OFS_PARM0 );
- //VM_CheckEmptyString( altstr );
num = (int)PRVM_G_FLOAT( OFS_PARM1 );
str = PRVM_G_STRING( OFS_PARM2 );
- //VM_CheckEmptyString( str );
- outstr = out = VM_GetTempString();
+ out = outstr;
for( num = num * 2 + 1, in = altstr; *in && num; *out++ = *in++ )
if( *in == '\\' ) {
if( !*++in ) {
num--;
}
- if( !in ) {
- PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( altstr );
- return;
- }
// copy set in
for( ; *str; *out++ = *str++ );
// now jump over the old content
if( *in == '\'' || (*in == '\\' && !*++in) )
break;
- if( !in ) {
- PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( NULL );
- return;
- }
-
- strlcpy(out, in, VM_STRINGTEMP_LENGTH);
- PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr );
+ strlcpy(out, in, outstr + sizeof(outstr) - out);
+ PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr );
}
/*
const char *set;
const char *instr;
const char *in;
- char *outstr;
char *out;
+ char outstr[VM_STRINGTEMP_LENGTH];
in = instr = PRVM_G_STRING( OFS_PARM0 );
num = (int)PRVM_G_FLOAT( OFS_PARM1 );
set = setstr = PRVM_G_STRING( OFS_PARM2 );
- out = outstr = VM_GetTempString();
+ out = outstr;
for( num = num * 2 + 2 ; *in && num > 0 ; *out++ = *in++ )
if( *in == '\\' ) {
if( !*++in ) {
for( ; *set ; *out++ = *set++ );
*out++ = '\'';
- strlcpy(out, in, VM_STRINGTEMP_LENGTH);
- PRVM_G_INT( OFS_RETURN ) = PRVM_SetEngineString( outstr );
+ strlcpy(out, in, outstr + sizeof(outstr) - out);
+ PRVM_G_INT( OFS_RETURN ) = PRVM_SetTempString( outstr );
}
void VM_buf_implode (void)
{
qcstrbuffer_t *b;
- char *k;
+ char k[VM_STRINGTEMP_LENGTH];
const char *sep;
int i;
size_t l;
VM_SAFEPARMCOUNT(2, VM_buf_implode);
b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0));
- PRVM_G_INT(OFS_RETURN) = 0;
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
if(!b)
{
VM_Warning("VM_buf_implode: invalid buffer %i used in %s\n", (int)PRVM_G_FLOAT(OFS_PARM0), PRVM_NAME);
if(!b->num_strings)
return;
sep = PRVM_G_STRING(OFS_PARM1);
- k = VM_GetTempString();
k[0] = 0;
for(l=i=0;i<b->num_strings;i++)
if(b->strings[i])
{
- l += strlen(b->strings[i]);
- if(l>=4095)
+ l += (i > 0 ? strlen(sep) : 0) + strlen(b->strings[i]);
+ if (l >= sizeof(k) - 1)
break;
- strlcat(k, b->strings[i], VM_STRINGTEMP_LENGTH);
- if(sep && (i != b->num_strings-1))
- {
- l += strlen(sep);
- if(l>=4095)
- break;
- strlcat(k, sep, VM_STRINGTEMP_LENGTH);
- }
+ strlcat(k, sep, sizeof(k));
+ strlcat(k, b->strings[i], sizeof(k));
}
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(k);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(k);
}
/*
========================
VM_bufstr_get
-get a string from buffer, returns direct pointer, dont str_unzone it!
+get a string from buffer, returns tempstring, dont str_unzone it!
string bufstr_get(float bufhandle, float string_index) = #465;
========================
*/
int strindex;
VM_SAFEPARMCOUNT(2, VM_bufstr_get);
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
b = BUFSTR_BUFFER((int)PRVM_G_FLOAT(OFS_PARM0));
if(!b)
{
VM_Warning("VM_bufstr_get: invalid string index %i used in %s\n", strindex, PRVM_NAME);
return;
}
- PRVM_G_INT(OFS_RETURN) = 0;
if(b->num_strings <= strindex)
return;
if(b->strings[strindex])
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(b->strings[strindex]);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(b->strings[strindex]);
}
/*
return;
}
news = PRVM_G_STRING(OFS_PARM2);
- if(!news)
- {
- VM_Warning("VM_bufstr_set: null string used in %s\n", PRVM_NAME);
- return;
- }
if(b->strings[strindex])
Z_Free(b->strings[strindex]);
alloclen = strlen(news) + 1;
return;
}
string = PRVM_G_STRING(OFS_PARM1);
- if(!string)
- {
- VM_Warning("VM_bufstr_add: null string used in %s\n", PRVM_NAME);
- return;
- }
-
order = (int)PRVM_G_FLOAT(OFS_PARM2);
if(order)
strindex = b->num_strings;
// builtins and other general functions
-char *VM_GetTempString(void);
void VM_CheckEmptyString (const char *s);
void VM_VarString(int first, char *out, int outlength);
cvar_t prvm_traceqc = {0, "prvm_traceqc", "0", "prints every QuakeC statement as it is executed (only for really thorough debugging!)"};
// LordHavoc: counts usage of each QuakeC statement
cvar_t prvm_statementprofiling = {0, "prvm_statementprofiling", "0", "counts how many times each QuakeC statement has been executed, these counts are displayed in prvm_printfunction output (if enabled)"};
+cvar_t prvm_tempstringmemory = {0, "prvm_tempstringmemory", "8388608", "amount of temporary string memory allowed in a single QuakeC invocation (QuakeC function call made by the engine)"};
//============================================================================
// mempool handling
Cvar_RegisterVariable (&prvm_boundscheck);
Cvar_RegisterVariable (&prvm_traceqc);
Cvar_RegisterVariable (&prvm_statementprofiling);
+ Cvar_RegisterVariable (&prvm_tempstringmemory);
//VM_Cmd_Init();
}
*/
+sizebuf_t vm_tempstringsbuf;
+
const char *PRVM_GetString(int num)
{
- if (num >= 0 && num < prog->stringssize)
- return prog->strings + num;
- else if (num < 0 && num >= -prog->numknownstrings)
+ if (num >= 0)
{
- num = -1 - num;
- if (!prog->knownstrings[num])
- PRVM_ERROR("PRVM_GetString: attempt to get string that is already freed");
- return prog->knownstrings[num];
+ if (num < prog->stringssize)
+ return prog->strings + num;
+ else
+#if 1
+ if (num <= prog->stringssize + vm_tempstringsbuf.maxsize)
+ {
+ num -= prog->stringssize;
+ if (num < vm_tempstringsbuf.cursize)
+ return (char *)vm_tempstringsbuf.data + num;
+ else
+ {
+ VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
+ return "";
+ }
+ }
+ else
+#endif
+ {
+ VM_Warning("PRVM_GetString: Invalid constant-string offset (%i >= %i prog->stringssize)", num, prog->stringssize);
+ return "";
+ }
}
else
{
- PRVM_ERROR("PRVM_GetString: invalid string offset %i", num);
- return "";
+ num = -1 - num;
+#if 0
+ if (num >= (1<<30))
+ {
+ // special range reserved for tempstrings
+ num -= (1<<30);
+ if (num < vm_tempstringsbuf.cursize)
+ return (char *)vm_tempstringsbuf.data + num;
+ else
+ {
+ VM_Warning("PRVM_GetString: Invalid temp-string offset (%i >= %i vm_tempstringsbuf.cursize)", num, vm_tempstringsbuf.cursize);
+ return "";
+ }
+ }
+ else
+#endif
+ if (num < prog->numknownstrings)
+ {
+ if (!prog->knownstrings[num])
+ VM_Warning("PRVM_GetString: Invalid zone-string offset (%i has been freed)", num);
+ return prog->knownstrings[num];
+ }
+ else
+ {
+ VM_Warning("PRVM_GetString: Invalid zone-string offset (%i >= %i)", num, prog->numknownstrings);
+ return "";
+ }
}
}
return 0;
if (s >= prog->strings && s <= prog->strings + prog->stringssize)
PRVM_ERROR("PRVM_SetEngineString: s in prog->strings area");
+ // if it's in the tempstrings area, use a reserved range
+ // (otherwise we'd get millions of useless string offsets cluttering the database)
+ if (s >= (char *)vm_tempstringsbuf.data && s < (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.maxsize)
+#if 1
+ return prog->stringssize + (s - (char *)vm_tempstringsbuf.data);
+#else
+ return -1 - ((1<<30) + (s - (char *)vm_tempstringsbuf.data));
+#endif
+ // see if it's a known string address
for (i = 0;i < prog->numknownstrings;i++)
if (prog->knownstrings[i] == s)
return -1 - i;
return -1 - i;
}
+// temp string handling
+
+// all tempstrings go into this buffer consecutively, and it is reset
+// whenever PRVM_ExecuteProgram returns to the engine
+// (technically each PRVM_ExecuteProgram call saves the cursize value and
+// restores it on return, so multiple recursive calls can share the same
+// buffer)
+// the buffer size is controlled by the prvm_tempstringmemory cvar, causing it
+// to be reallocated between invocations if the cvar has changed
+
+int PRVM_SetTempString(const char *s)
+{
+ int size;
+ char *t;
+ if (!s)
+ return 0;
+ size = (int)strlen(s) + 1;
+ if (vm_tempstringsbuf.cursize + size >= vm_tempstringsbuf.maxsize)
+ PRVM_ERROR("PRVM_SetTempString: tempstrings buffer full! (increase prvm_tempstringmemory cvar or reduce use of tempstrings in quakec code)\n");
+ t = (char *)vm_tempstringsbuf.data + vm_tempstringsbuf.cursize;
+ memcpy(t, s, size);
+ vm_tempstringsbuf.cursize += size;
+ return PRVM_SetEngineString(t);
+}
+
int PRVM_AllocString(size_t bufferlength, char **pointer)
{
int i;
PRVM_StackTrace ();
}
-void PRVM_Crash()
+extern sizebuf_t vm_tempstringsbuf;
+void PRVM_Crash(void)
{
if (prog == NULL)
return;
prog->depth = 0;
prog->localstack_used = 0;
+ // delete all tempstrings (FIXME: is this safe in VM->engine->VM recursion?)
+ vm_tempstringsbuf.cursize = 0;
+
// reset the prog pointer
prog = NULL;
}
extern cvar_t prvm_boundscheck;
extern cvar_t prvm_traceqc;
extern cvar_t prvm_statementprofiling;
+extern cvar_t prvm_tempstringmemory;
extern int PRVM_ED_FindFieldOffset (const char *field);
extern ddef_t* PRVM_ED_FindGlobal(const char *name);
+extern sizebuf_t vm_tempstringsbuf;
void PRVM_ExecuteProgram (func_t fnum, const char *errormessage)
{
dstatement_t *st, *startst;
prvm_edict_t *ed;
prvm_eval_t *ptr;
int jumpcount, cachedpr_trace, exitdepth;
+ int restorevm_tempstringsbuf_cursize;
if (!fnum || fnum >= (unsigned int)prog->progs->numfunctions)
{
f = &prog->functions[fnum];
+ // after executing this function, delete all tempstrings it created
+ restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
+ // if there is no stack, this is a good time to reallocate the
+ // vm_tempstringsbuf if the cvar has changed
+ if (restorevm_tempstringsbuf_cursize == 0)
+ {
+ int maxsize = bound(4096, prvm_tempstringmemory.integer, 1<<30);
+ if (vm_tempstringsbuf.maxsize != maxsize || !vm_tempstringsbuf.data)
+ {
+ if (vm_tempstringsbuf.data)
+ Mem_Free(vm_tempstringsbuf.data);
+ vm_tempstringsbuf.maxsize = maxsize;
+ vm_tempstringsbuf.data = Mem_Alloc(sv_mempool, vm_tempstringsbuf.maxsize);
+ }
+ }
+
prog->trace = prvm_traceqc.integer;
// we know we're done when pr_depth drops to this
}
}
}
+
+cleanup:
+ if (developer.integer >= 200 && vm_tempstringsbuf.cursize > restorevm_tempstringsbuf_cursize)
+ Con_Printf("PRVM_ExecuteProgram: %s used %i bytes of tempstrings\n", PRVM_GetString(prog->functions[fnum].s_name), vm_tempstringsbuf.cursize - restorevm_tempstringsbuf_cursize);
+ // delete tempstrings created by this function
+ vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
}
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int);
- return;
+ goto cleanup;
}
#endif
ptr = (prvm_eval_t *)((unsigned char *)prog->edictsfields + OPB->_int);
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR("%s attempted to write to an out of bounds edict (%i)", PRVM_NAME, OPB->_int);
- return;
+ goto cleanup;
}
#endif
ptr = (prvm_eval_t *)((unsigned char *)prog->edictsfields + OPB->_int);
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR("%s attempted to address an invalid field (%i) in an edict", PRVM_NAME, OPB->_int);
- return;
+ goto cleanup;
}
#endif
if (OPA->edict == 0 && !prog->allowworldwrites)
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR("forbidden assignment to null/world entity in %s", PRVM_NAME);
- return;
+ goto cleanup;
}
ed = PRVM_PROG_TO_EDICT(OPA->edict);
OPC->_int = (unsigned char *)((int *)ed->fields.vp + OPB->_int) - (unsigned char *)prog->edictsfields;
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
- return;
+ goto cleanup;
}
#endif
ed = PRVM_PROG_TO_EDICT(OPA->edict);
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR("%s attempted to read an invalid field in an edict (%i)", PRVM_NAME, OPB->_int);
- return;
+ goto cleanup;
}
#endif
ed = PRVM_PROG_TO_EDICT(OPA->edict);
st = prog->statements + PRVM_LeaveFunction();
startst = st;
if (prog->depth <= exitdepth)
- return; // all done
+ goto cleanup; // all done
if (prog->trace != cachedpr_trace)
goto chooseexecprogram;
break;
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR ("%s Progs attempted to write to an out of bounds edict", PRVM_NAME);
- return;
+ goto cleanup;
}
#endif
ptr = (prvm_eval_t *)((unsigned char *)prog->edictsfields + OPB->_int);
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR ("%s Progs attempted to read an out of bounds edict number", PRVM_NAME);
- return;
+ goto cleanup;
}
if (OPB->_int < 0 || OPB->_int >= progs->entityfields)
{
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR ("%s Progs attempted to read an invalid field in an edict", PRVM_NAME);
- return;
+ goto cleanup;
}
#endif
ed = PRVM_PROG_TO_EDICT(OPA->edict);
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR ("%s Progs attempted to write to an invalid indexed global", PRVM_NAME);
- return;
+ goto cleanup;
}
#endif
pr_globals[OPB->_int] = OPA->_float;
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR ("%s Progs attempted to write to an invalid indexed global", PRVM_NAME);
- return;
+ goto cleanup;
}
#endif
pr_globals[OPB->_int ] = OPA->vector[0];
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR ("%s Progs attempted to address an out of bounds global", PRVM_NAME);
- return;
+ goto cleanup;
}
#endif
OPC->_float = pr_globals[i];
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR ("%s Progs attempted to read an invalid indexed global", PRVM_NAME);
- return;
+ goto cleanup;
}
#endif
OPC->_float = pr_globals[OPA->_int];
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR ("%s Progs attempted to read an invalid indexed global", PRVM_NAME);
- return;
+ goto cleanup;
}
#endif
OPC->vector[0] = pr_globals[OPA->_int ];
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR ("%s Progs boundcheck failed at line number %d, value is < 0 or >= %d", PRVM_NAME, st->b, st->c);
- return;
+ goto cleanup;
}
break;
prog->xfunction->profile += (st - startst);
prog->xstatement = st - prog->statements;
PRVM_ERROR ("Bad opcode %i in %s", st->op, PRVM_NAME);
+ goto cleanup;
}
}
// sv_phys.c
#include "quakedef.h"
-// used only for VM_GetTempString
-#include "prvm_cmds.h"
/*
if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename)))
{
if (trace->hittexture)
- {
- char *s = VM_GetTempString();
- strlcpy(s, trace->hittexture->name, VM_STRINGTEMP_LENGTH);
- val->string = PRVM_SetEngineString(s);
- }
+ val->string = PRVM_SetTempString(trace->hittexture->name);
else
val->string = 0;
}
===================
*/
extern void SV_SendServerinfo(client_t *client);
+extern sizebuf_t vm_tempstringsbuf;
void SV_ReadClientMessage(void)
{
int cmd, num, start;
Cmd_ExecuteString (s, src_client);
else if (SV_ParseClientCommandQC)
{
- PRVM_G_INT(OFS_PARM0) = PRVM_SetEngineString(s);
+ int restorevm_tempstringsbuf_cursize;
+ restorevm_tempstringsbuf_cursize = vm_tempstringsbuf.cursize;
+ PRVM_G_INT(OFS_PARM0) = PRVM_SetTempString(s);
prog->globals.server->self = PRVM_EDICT_TO_PROG(host_client->edict);
PRVM_ExecuteProgram ((func_t)(SV_ParseClientCommandQC - prog->functions), "QC function SV_ParseClientCommand is missing");
+ vm_tempstringsbuf.cursize = restorevm_tempstringsbuf_cursize;
}
else
Cmd_ExecuteString (s, src_client);
"DP_QC_SINCOSSQRTPOW "
"DP_QC_STRINGBUFFERS "
"DP_QC_STRINGCOLORFUNCTIONS "
+"DP_QC_UNLIMITEDTEMPSTRINGS "
"DP_QC_TRACEBOX "
"DP_QC_TRACETOSS "
"DP_QC_TRACE_MOVETYPE_HITMODEL "
if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename)))
{
if (trace.hittexture)
- {
- char *s = VM_GetTempString();
- strlcpy(s, trace.hittexture->name, VM_STRINGTEMP_LENGTH);
- val->string = PRVM_SetEngineString(s);
- }
+ val->string = PRVM_SetTempString(trace.hittexture->name);
else
val->string = 0;
}
if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename)))
{
if (trace.hittexture)
- {
- char *s = VM_GetTempString();
- strlcpy(s, trace.hittexture->name, VM_STRINGTEMP_LENGTH);
- val->string = PRVM_SetEngineString(s);
- }
+ val->string = PRVM_SetTempString(trace.hittexture->name);
else
val->string = 0;
}
if ((val = PRVM_GETGLOBALFIELDVALUE(gval_trace_dphittexturename)))
{
if (trace.hittexture)
- {
- char *s = VM_GetTempString();
- strlcpy(s, trace.hittexture->name, VM_STRINGTEMP_LENGTH);
- val->string = PRVM_SetEngineString(s);
- }
+ val->string = PRVM_SetTempString(trace.hittexture->name);
else
val->string = 0;
}
int i;
const char *s;
s = PRVM_G_STRING(OFS_PARM1);
- if (!s || !s[0])
+ if (!s[0])
{
VM_Warning("effect: no model specified\n");
return;
{
model_t *model;
msurface_t *surface;
- PRVM_G_INT(OFS_RETURN) = 0;
+ PRVM_G_INT(OFS_RETURN) = OFS_NULL;
if (!(model = getmodel(PRVM_G_EDICT(OFS_PARM0))) || !(surface = getsurface(model, (int)PRVM_G_FLOAT(OFS_PARM1))))
return;
- PRVM_G_INT(OFS_RETURN) = PRVM_SetEngineString(surface->texture->name);
+ PRVM_G_INT(OFS_RETURN) = PRVM_SetTempString(surface->texture->name);
}
//PF_getsurfacenearpoint, // #438 float(entity e, vector p) getsurfacenearpoint = #438;
void PF_getsurfacenearpoint(void)
0 bug darkplaces readme: it would be a very good idea to add documentation of sv_gameplayfix_* cvars in the readme as a means to run broken mods (xaGe)
0 bug darkplaces renderer: GL13 path has broken handling of unlit surfaces in Nexuiz toxic.bsp - the small red light surfaces are black in GL13 path (m0rfar)
0 bug darkplaces renderer: monsters teleporting in really slow down rendering, perhaps the teleport light is casting huge shadows? new information suggests it is the particles. (romi, lcatlnx)
-0 bug darkplaces renderer: there's some sort of bug with GL_CullFace, it is sometimes rendering the map using GL_CullFace(GL_NONE) depending on viewpoint
0 bug darkplaces server: SV_PushMove is ignoring model type in its angles_x handling, where as the renderer checks only model type to determine angles_x handling (Urre)
0 bug darkplaces server: SV_PushMove's call to SV_ClipMoveToEntity should do a trace, not just a point test, to support hollow pusher models (Urre)
0 bug darkplaces wgl client: during video mode setup, sometimes another application's window becomes permanently top most, not darkplaces' fullscreen window, why? (tZork)
0 change darkplaces client: particles shouldn't be using contents checks to decide whether to die, they should use movement traces
0 change darkplaces client: restrict wateralpha and such cvars according to what is permitted in qw serverinfo?
0 change darkplaces client: turn off coronas on dlights (Jago)
-0 change darkplaces extensions: edit FRIK_FILE documentation to mention that fgets uses its own separate buffer, so only one fgets can be done at a time without uzing strzone, but that darkplaces uses standard tempstrings for fgets (it doesn't - change it!) and mention DP_QC_MULTIPLETEMPSTRINGS (FrikaC)
-0 change darkplaces extensions: edit FRIK_FILE documentation to mention that strcat uses its own separate buffer, and that a = strcat(a, b);a = strcat(a, c); works correctly despite this, also mention that in DP strcat uses standard tempstrings, and mention DP_QC_MULTIPLETEMPSTRINGS (FrikaC)
+0 change darkplaces extensions: edit FRIK_FILE documentation to mention that fgets uses its own separate buffer, so only one fgets can be done at a time without uzing strzone, but that this is not true with DP_QC_UNLIMITEDTEMPSTRINGS (FrikaC)
+0 change darkplaces extensions: edit FRIK_FILE documentation to mention that strcat uses its own separate buffer, and that a = strcat(a, b);a = strcat(a, c); works correctly despite this, but that strcat is far more flexible with DP_QC_UNLIMITEDTEMPSTRINGS (FrikaC)
0 change darkplaces general: make r_speeds 2 show timings for other subsystems such as client, sound, server, network (Carni)
0 change darkplaces loader: load *lava and *teleport and *rift textures as a black diffuse texture with all the color put into a glow layer, and remove the MATERIALFLAG_FULLBRIGHT accordingly, this way replacement textures can make it not glow (Kedhrin)
0 change darkplaces memory: optimize model loaders to use less individual allocations, especially the q1bsp loader, it is responsible for a lot of very small (1-8 byte) allocations in the memlist all report
0 change hmap2: qbsp should do tjunc fixing on leaky maps
0 change revelation: change the wabbit kill message to " was hunting wabbit but shot " " instead"
0 change zmodel: include the example script in the build zips, not just in the files directory
-0 cleanup darkplaces cleanup: remove cgame* files and any references
-0 cleanup darkplaces cleanup: remove ui.* files and any references
0 cleanup darkplaces renderer: split GLSL program compilation code into shaderobject and programobject functions to reduce code
0 feature darkplaces client: add .loc file support and say macros
0 feature darkplaces client: add .mvd demo support
0 feature darkplaces dpv playback: when video ends, execute a console command, perhaps "endvideo", this could be an alias set by a mod before it began playing the video (SavageX, motorsep)
0 feature darkplaces editlights: add r_editlights_edit commands for turn/turnx/turny/turnz to allow angle adjustments using binds (Kedhrin)
0 feature darkplaces editlights: split rtlight drawshadows option into drawworldshadows and drawentityshadows options, this allows combinations like no world shadows (for speed) but still having entity shadows (Mitchell, romi, Kedhrin)
+0 feature darkplaces extensions: document DP_QC_UNLIMITEDTEMPSTRINGS extension explaining the new tempstring system and the prvm_tempstringmemory cvar, add a note to DP_QC_MULTIPLETEMPSTRINGS that it is superceded by DP_QC_UNLIMITEDTEMPSTRINGS when present
0 feature darkplaces filesystem: gamedir command to switch between mods, should be able to take multiple parameters to load multiple mods ontop of eachother like the -game commandline option can (FrikaC)
0 feature darkplaces loader: add hud_clearprecache and hud_precachepic commands to preload pics by name, these get reloaded by r_restart as well, mods can put a lot of these commands in their default.cfg to precache needed hud art (Tomaz)
0 feature darkplaces loader: load .vis files produced by hmap2
5 feature darkplaces client: add a "edictedit" command to open up a dialog to edit an edict (allow multiple dialogs to be open at once)
5 feature darkplaces client: add qc debugger, which would have its own very simple fullscreen console, this would be called directly from the qc interpreter, not from client (painQuin)
5 feature darkplaces console: r_textutf8 cvar (to parse UTF-8 codes), should affect all text rendering, using multiple conchar images for different groups of 256 characters (VorteX)
-5 feature darkplaces renderer: add ALIASSKIN_NOCULLFACE and ALIASSKIN_SORTTRIANGLES flags, and figure out how to activate them somehow (FrikaC)
5 feature darkplaces renderer: add dpshader support
5 feature darkplaces renderer: add some kind of sun flare support, possibly stored in a dpshader (CheapAlert)
5 feature darkplaces renderer: do a minimap that works by simply using nearclip to sheer off anything above the eye, and draws anything below normally, or via a cvar as height coloring (Supajoe)
+5 feature darkplaces renderer: implement transparent triangle sorting within each entity (FrikaC)
5 feature darkplaces renderer: lightshader files (probably loaded by the cubemap field already present in rtlights handling), these would indicate what attenuation textures to use for the light, what cubemap filter, which corona texture and size and so on, and all textures can be animated (romi, Urre)
5 feature darkplaces server: split server into a separate thread when running listen mode so that a host running too slow won't spoil the game (Toddd)
5 feature dpzoo.map: make some things that make the player bigger/smaller to demonstrate scaling and better viewheight handling and brush collisions (depends on brush collisions)
d bug darkplaces renderer: reverse corona traceline direction so that a player in solid can see coronas (Urre)
d bug darkplaces renderer: shadow volumes from q3bsp brush models are broken, maybe inverted or something (Vermeulen)
d bug darkplaces renderer: text coloring is only affecting the first line of messagemode text (LordHavoc)
+d bug darkplaces renderer: there's some sort of bug with GL_CullFace, it is sometimes rendering the map using GL_CullFace(GL_NONE) depending on viewpoint
d bug darkplaces renderer: transparent entities are not being lit by rtlights, where as transparent water belonging to an opaque entity (world) is being lit by rtlights (SavageX)
d bug darkplaces renderer: transparent surfaces are not being lit by rtlights (Vermeulen)
d bug darkplaces renderer: vertex normals seem to be generated backwards
d change dpmodel: include the example script in the build zips, not just in the files directory
d change dpmodel: keep all bones instead of removing unused ones (Ghostface)
d change hmap2: increase MAXTOKEN from 1024 to 16384 (FrikaC)
+d cleanup darkplaces cleanup: remove cgame* files and any references
+d cleanup darkplaces cleanup: remove ui.* files and any references
d cleanup darkplaces console: look at Black's recent console args changes and clean it up as he requested, particularly removing a commented block (Black)
d cleanup darkplaces csqc: cl.csqcentities/cl.num_csqcentities/cl.max_csqcentities are probably entirely unnecessary
d cleanup darkplaces general: get rid of fs_filesize, use parameters/local variables instead (Randy)