fix while(1)->while(0) issues.

debug evaluation is more verbose (gives field listings when passed an entity).
added string length checks in various places.
sizeof(array) works again.
tweaked fields to be a little more user friendly, and not complain about classes so much when simply using entities.

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@4460 fc73d0e0-1445-4013-8a0c-d673dee63da5
This commit is contained in:
Spoike 2013-08-21 06:55:54 +00:00
parent 7793b0a73a
commit 803c8c4878
9 changed files with 213 additions and 151 deletions

View File

@ -68,7 +68,7 @@ cont: //last statement may have been a breakpoint
break;
case ev_function:
case ev_string:
printf("Watch point hit in %s, \"%s\" now set to %s.\n", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), prinst.watch_name, PR_ValueString(progfuncs, prinst.watch_type, prinst.watch_ptr));
printf("Watch point hit in %s, \"%s\" now set to %s.\n", PR_StringToNative(&progfuncs->funcs, pr_xfunction->s_name), prinst.watch_name, PR_ValueString(progfuncs, prinst.watch_type, prinst.watch_ptr, false));
break;
}
prinst.watch_old = *prinst.watch_ptr;

View File

@ -107,55 +107,55 @@ enum qcop_e {
//these following ones are Hexen 2 constants.
OP_MULSTORE_F,
OP_MULSTORE_VF,
OP_MULSTOREP_F,
OP_MULSTOREP_VF,
OP_MULSTORE_F, //66 redundant, for h2 compat
OP_MULSTORE_VF, //67 redundant, for h2 compat
OP_MULSTOREP_F, //68
OP_MULSTOREP_VF,//69
OP_DIVSTORE_F, //70
OP_DIVSTOREP_F,
OP_DIVSTORE_F, //70 redundant, for h2 compat
OP_DIVSTOREP_F, //71
OP_ADDSTORE_F,
OP_ADDSTORE_V,
OP_ADDSTOREP_F,
OP_ADDSTOREP_V,
OP_ADDSTORE_F, //72 redundant, for h2 compat
OP_ADDSTORE_V, //73 redundant, for h2 compat
OP_ADDSTOREP_F, //74
OP_ADDSTOREP_V, //75
OP_SUBSTORE_F,
OP_SUBSTORE_V,
OP_SUBSTOREP_F,
OP_SUBSTOREP_V,
OP_SUBSTORE_F, //76 redundant, for h2 compat
OP_SUBSTORE_V, //77 redundant, for h2 compat
OP_SUBSTOREP_F, //78
OP_SUBSTOREP_V, //79
OP_FETCH_GBL_F, //80
OP_FETCH_GBL_V,
OP_FETCH_GBL_S,
OP_FETCH_GBL_E,
OP_FETCH_GBL_FNC,
OP_FETCH_GBL_V, //81
OP_FETCH_GBL_S, //82
OP_FETCH_GBL_E, //83
OP_FETCH_GBL_FNC,//84
OP_CSTATE,
OP_CWSTATE,
OP_CSTATE, //85
OP_CWSTATE, //86
OP_THINKTIME,
OP_THINKTIME, //87
OP_BITSET,
OP_BITSETP,
OP_BITSET, //88 redundant, for h2 compat
OP_BITSETP, //89
OP_BITCLR, //90
OP_BITCLRP,
OP_BITCLRP, //91
OP_RAND0,
OP_RAND1,
OP_RAND2,
OP_RANDV0,
OP_RANDV1,
OP_RANDV2,
OP_RAND0, //92
OP_RAND1, //93
OP_RAND2, //94
OP_RANDV0, //95
OP_RANDV1, //96
OP_RANDV2, //97
OP_SWITCH_F,
OP_SWITCH_V,
OP_SWITCH_F, //98
OP_SWITCH_V, //99
OP_SWITCH_S, //100
OP_SWITCH_E,
OP_SWITCH_FNC,
OP_SWITCH_E, //101
OP_SWITCH_FNC, //102
OP_CASE,
OP_CASERANGE,
OP_CASE, //103
OP_CASERANGE, //104
@ -286,9 +286,9 @@ enum qcop_e {
OP_GSTOREP_I,
OP_GSTOREP_F,
OP_GSTOREP_ENT,
OP_GSTOREP_FLD, // integers //200
OP_GSTOREP_FLD, //200
OP_GSTOREP_S,
OP_GSTOREP_FNC, // pointers
OP_GSTOREP_FNC,
OP_GSTOREP_V,
OP_GADDRESS,
OP_GLOAD_I,
@ -297,9 +297,9 @@ enum qcop_e {
OP_GLOAD_ENT,
OP_GLOAD_S,
OP_GLOAD_FNC, //210
OP_BOUNDCHECK,
//back to ones that we do use.
OP_BOUNDCHECK,
OP_UNUSED, //used to be OP_STOREP_P, which is now emulated with OP_STOREP_I, fteqcc nor fte generated it
OP_PUSH, //push 4octets onto the local-stack (which is ALWAYS poped on function return). Returns a pointer.
OP_POP, //pop those ones that were pushed (don't over do it). Needs assembler.

View File

@ -111,7 +111,7 @@ struct edict_s *PDECL ED_Alloc (pubprogfuncs_t *ppf)
{
int size;
char *buf;
buf = PR_SaveEnts(&progfuncs->funcs, NULL, &size, 0);
buf = PR_SaveEnts(&progfuncs->funcs, NULL, &size, 0, 0);
progfuncs->funcs.parms->WriteFile("edalloc.dump", buf, size);
Sys_Error ("ED_Alloc: no free edicts (max is %i)", maxedicts);
}
@ -465,14 +465,28 @@ dfunction_t *ED_FindFunction (progfuncs_t *progfuncs, char *name, progsnum_t *pr
return NULL;
}
#ifdef _WIN32
static void VARGS QC_snprintfz (char *dest, size_t size, const char *fmt, ...)
{
va_list args;
va_start (args, fmt);
vsnprintf (dest, size-1, fmt, args);
va_end (args);
//make sure its terminated.
dest[size-1] = 0;
}
#else
#define QC_snprintfz snprintf
#endif
/*
============
PR_ValueString
Returns a string describing *data in a human-readable type specific manner
if verbose, contains entity field listing etc too
=============
*/
char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val)
char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val, pbool verbose)
{
static char line[4096];
fdef_t *fielddef;
@ -488,13 +502,13 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val)
switch (type)
{
case ev_struct:
sprintf (line, "struct");
QC_snprintfz (line, sizeof(line), "struct");
break;
case ev_union:
sprintf (line, "union");
QC_snprintfz (line, sizeof(line), "union");
break;
case ev_string:
sprintf (line, "%s", PR_StringToNative(&progfuncs->funcs, val->string));
QC_snprintfz (line, sizeof(line), "%s", PR_StringToNative(&progfuncs->funcs, val->string));
break;
case ev_entity:
fielddef = ED_FindField(progfuncs, "classname");
@ -504,26 +518,34 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val)
string_t *v;
ed = (edictrun_t *)EDICT_NUM(progfuncs, val->edict);
v = (string_t *)((char *)edvars(ed) + fielddef->ofs*4);
sprintf (line, "entity %i(%s)", val->edict, PR_StringToNative(&progfuncs->funcs, *v));
QC_snprintfz (line, sizeof(line), "entity %i(%s)", val->edict, PR_StringToNative(&progfuncs->funcs, *v));
}
else
sprintf (line, "entity %i", val->edict);
QC_snprintfz (line, sizeof(line), "entity %i", val->edict);
if (verbose)
{
struct edict_s *ed = EDICT_NUM(progfuncs, val->edict);
int size = strlen(line);
if (ed)
PR_SaveEnt(&progfuncs->funcs, line, &size, sizeof(line), ed);
}
break;
case ev_function:
if (!val->function)
sprintf (line, "NULL function");
QC_snprintfz (line, sizeof(line), "NULL function");
else
{
if ((val->function & 0xff000000)>>24 >= (unsigned)maxprogs || !pr_progstate[(val->function & 0xff000000)>>24].functions)
sprintf (line, "Bad function %i:%i", (val->function & 0xff000000)>>24, val->function & ~0xff000000);
QC_snprintfz (line, sizeof(line), "Bad function %i:%i", (val->function & 0xff000000)>>24, val->function & ~0xff000000);
else
{
if ((val->function &~0xff000000) >= pr_progs->numfunctions)
sprintf(line, "bad function %i:%i\n", (val->function & 0xff000000)>>24, val->function & ~0xff000000);
QC_snprintfz (line, sizeof(line), "bad function %i:%i\n", (val->function & 0xff000000)>>24, val->function & ~0xff000000);
else
{
f = pr_progstate[(val->function & 0xff000000)>>24].functions + (val->function & ~0xff000000);
sprintf (line, "%i:%s()", (val->function & 0xff000000)>>24, f->s_name+progfuncs->funcs.stringtable);
QC_snprintfz (line, sizeof(line), "%i:%s()", (val->function & 0xff000000)>>24, f->s_name+progfuncs->funcs.stringtable);
}
}
}
@ -531,34 +553,34 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val)
case ev_field:
fielddef = ED_FieldAtOfs (progfuncs, val->_int + progfuncs->funcs.fieldadjust);
if (!fielddef)
sprintf (line, ".??? (%i)", val->_int);
QC_snprintfz (line, sizeof(line), ".??? (%i)", val->_int);
else
sprintf (line, ".%s (%i)", fielddef->name, val->_int);
QC_snprintfz (line, sizeof(line), ".%s (%i)", fielddef->name, val->_int);
break;
case ev_void:
sprintf (line, "void type");
QC_snprintfz (line, sizeof(line), "void type");
break;
case ev_float:
sprintf (line, "%g", val->_float);
QC_snprintfz (line, sizeof(line), "%g", val->_float);
break;
case ev_integer:
sprintf (line, "%i", val->_int);
QC_snprintfz (line, sizeof(line), "%i", val->_int);
break;
case ev_vector:
sprintf (line, "'%g %g %g'", val->_vector[0], val->_vector[1], val->_vector[2]);
QC_snprintfz (line, sizeof(line), "'%g %g %g'", val->_vector[0], val->_vector[1], val->_vector[2]);
break;
case ev_pointer:
sprintf (line, "pointer");
QC_snprintfz (line, sizeof(line), "pointer");
{
// int entnum;
// int valofs;
if (val->_int == 0)
{
sprintf (line, "NULL pointer");
QC_snprintfz (line, sizeof(line), "NULL pointer");
break;
}
//FIXME: :/
sprintf(line, "UNKNOWN");
QC_snprintfz (line, sizeof(line), "UNKNOWN");
// entnum = ((qbyte *)val->edict - (qbyte *)sv_edicts) / pr_edict_size;
// valofs = (int *)val->edict - (int *)edvars(EDICT_NUM(progfuncs, entnum));
// fielddef = ED_FieldAtOfs (progfuncs, valofs );
@ -569,7 +591,7 @@ char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val)
}
break;
default:
sprintf (line, "bad type %i", type);
QC_snprintfz (line, sizeof(line), "bad type %i", type);
break;
}
@ -819,7 +841,7 @@ char *PR_GlobalString (progfuncs_t *progfuncs, int ofs)
sprintf (line,"%i(?""?""?)", ofs);
else
{
s = PR_ValueString (progfuncs, def16->type, val);
s = PR_ValueString (progfuncs, def16->type, val, false);
sprintf (line,"%i(%s)%s", ofs, def16->s_name+progfuncs->funcs.stringtable, s);
}
@ -836,7 +858,7 @@ char *PR_GlobalString (progfuncs_t *progfuncs, int ofs)
sprintf (line,"%i(?""?""?)", ofs);
else
{
s = PR_ValueString (progfuncs, def32->type, val);
s = PR_ValueString (progfuncs, def32->type, val, false);
sprintf (line,"%i(%s)%s", ofs, def32->s_name+progfuncs->funcs.stringtable, s);
}
@ -940,7 +962,7 @@ void PDECL ED_Print (pubprogfuncs_t *ppf, struct edict_s *ed)
while (l++ < 15)
printf (" ");
printf ("%s\n", PR_ValueString(progfuncs, d->type, (eval_t *)v));
printf ("%s\n", PR_ValueString(progfuncs, d->type, (eval_t *)v, false));
}
}
@ -1333,6 +1355,16 @@ cont:
}
#endif
static void PR_Cat(char *out, const char *in, int *len, int max)
{
int newl = strlen(in);
max-=1;
if (*len + newl > max)
newl = max - *len; //truncate
memcpy(out + *len, in, newl+1);
*len += newl;
}
/*
================
ED_LoadFromFile
@ -1349,9 +1381,9 @@ to call ED_CallSpawnFunctions () to let the objects initialize themselves.
================
*/
char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buffer) //switch first.
char *ED_WriteGlobals(progfuncs_t *progfuncs, char *buf, int *bufofs, int bufmax) //switch first.
{
#define AddS(str) strcpy(buffer, str);buffer+=strlen(str);
#define AddS(str) PR_Cat(buf, str, bufofs, bufmax)
int *v;
ddef32_t *def32;
ddef16_t *def16;
@ -1485,13 +1517,14 @@ add32:
Sys_Error("Bad struct type in SaveEnts");
}
return buffer;
return buf;
#undef AddS
}
char *ED_WriteEdict(progfuncs_t *progfuncs, edictrun_t *ed, char *buffer, pbool q1compatible)
char *ED_WriteEdict(progfuncs_t *progfuncs, edictrun_t *ed, char *buf, int *bufofs, int bufmax, pbool q1compatible)
{
#define AddS(str) PR_Cat(buf, str, bufofs, bufmax)
fdef_t *d;
int *v;
unsigned int i;unsigned int j;
char *name;
@ -1531,13 +1564,13 @@ char *ED_WriteEdict(progfuncs_t *progfuncs, edictrun_t *ed, char *buffer, pbool
AddS("\""); AddS(tmp); AddS("\"\n");
}
return buffer;
return buf;
#undef AddS
}
char *SaveCallStack (progfuncs_t *progfuncs, char *s)
char *SaveCallStack (progfuncs_t *progfuncs, char *buf, int *bufofs, int bufmax)
{
#define AddS(str) strcpy(s, str);s+=strlen(str);
#define AddS(str) PR_Cat(buf, str, bufofs, bufmax)
char buffer[8192];
dfunction_t *f;
int i;
@ -1551,7 +1584,7 @@ char *SaveCallStack (progfuncs_t *progfuncs, char *s)
if (pr_depth == 0)
{
AddS ("<NO STACK>\n");
return s;
return buf;
}
globalbase = (int *)pr_globals + pr_xfunction->parm_start + pr_xfunction->locals;
@ -1594,7 +1627,7 @@ char *SaveCallStack (progfuncs_t *progfuncs, char *s)
sprintf(buffer, "\t\t\"%s\" \"entity %i\"\n", local->s_name+progfuncs->funcs.stringtable, ((eval_t*)(globalbase - f->locals+arg))->edict);
}
else
sprintf(buffer, "\t\t\"%s\"\t\"%s\"\n", local->s_name+progfuncs->funcs.stringtable, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase - f->locals+arg)));
sprintf(buffer, "\t\t\"%s\"\t\"%s\"\n", local->s_name+progfuncs->funcs.stringtable, PR_ValueString(progfuncs, local->type, (eval_t*)(globalbase - f->locals+arg), false));
if (local->type == ev_vector)
arg+=2;
@ -1609,27 +1642,28 @@ char *SaveCallStack (progfuncs_t *progfuncs, char *s)
globalbase -= f->locals;
}
}
return s;
return buf;
#undef AddS
}
//there are two ways of saving everything.
//0 is to save just the entities.
//1 is to save the entites, and all the progs info so that all the variables are saved off, and it can be reloaded to exactly how it was (provided no files or data has been changed outside, like the progs.dat for example)
char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *mem, int *len, int alldata)
char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *buf, int *bufofs, int bufmax, int alldata)
{
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
#define AddS(str) strcpy(s, str);s+=strlen(str);
char *s, *os;
#define AddS(str) PR_Cat(buf, str, bufofs, bufmax)
unsigned int a;
char *buffree = NULL;
int oldprogs;
if (mem)
if (!buf)
{
os = s = mem;
if (bufmax <= 0)
bufmax = 5*1024*1024;
buffree = buf = externs->memalloc(bufmax);
}
else
os = s = externs->memalloc(5*1024*1024);
*bufofs = 0;
if (alldata == 2)
{ //special Q1 savegame compatability mode.
@ -1643,7 +1677,7 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *mem, int *len, int alldata)
}
if (!pr_progstate[0].progs || a != maxprogs) //the state of the progs wasn't Q1 compatible.
{
externs->memfree(os);
externs->memfree(buffree);
return NULL;
}
@ -1653,7 +1687,7 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *mem, int *len, int alldata)
oldprogs = pr_typecurrent;
PR_SwitchProgs(progfuncs, 0);
s = ED_WriteGlobals(progfuncs, s);
ED_WriteGlobals(progfuncs, buf, bufofs, bufmax);
PR_SwitchProgs(progfuncs, oldprogs);
@ -1668,13 +1702,12 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *mem, int *len, int alldata)
AddS ("{\n");
if (!ed->isfree)
s = ED_WriteEdict(progfuncs, ed, s, true);
ED_WriteEdict(progfuncs, ed, buf, bufofs, bufmax, true);
AddS ("}\n");
}
*len = s - os;
return os;
return buf;
}
if (alldata)
@ -1707,7 +1740,7 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *mem, int *len, int alldata)
{
//include callstack
AddS("stacktrace {\n");
s = SaveCallStack(progfuncs, s);
SaveCallStack(progfuncs, buf, bufofs, bufmax);
AddS("}\n");
}
@ -1720,7 +1753,7 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *mem, int *len, int alldata)
PR_SwitchProgs(progfuncs, a);
s = ED_WriteGlobals(progfuncs, s);
ED_WriteGlobals(progfuncs, buf, bufofs, bufmax);
AddS ("}\n");
}
@ -1735,13 +1768,12 @@ char *PDECL PR_SaveEnts(pubprogfuncs_t *ppf, char *mem, int *len, int alldata)
AddS (qcva("entity %i{\n", a));
s = ED_WriteEdict(progfuncs, ed, s, false);
ED_WriteEdict(progfuncs, ed, buf, bufofs, bufmax, false);
AddS ("}\n");
}
*len = s - os;
return os;
return buf;
#undef AddS
}
@ -2263,10 +2295,10 @@ int PDECL PR_LoadEnts(pubprogfuncs_t *ppf, char *file, float killonspawnflags)
return max_fields_size;
}
#define AddS(str) strcpy(s, str);s+=strlen(str);
char *PDECL PR_SaveEnt (pubprogfuncs_t *ppf, char *buf, int *size, struct edict_s *ed)
//FIXME: maxsize is ignored.
char *PDECL PR_SaveEnt (pubprogfuncs_t *ppf, char *buf, int *size, int maxsize, struct edict_s *ed)
{
#define AddS(str) PR_Cat(buf, str, size, maxsize)
progfuncs_t *progfuncs = (progfuncs_t*)ppf;
fdef_t *d;
int *v;
@ -2274,8 +2306,6 @@ char *PDECL PR_SaveEnt (pubprogfuncs_t *ppf, char *buf, int *size, struct edict_
char *name;
int type;
char *s = buf;
// if (ed->free)
// continue;
@ -2289,7 +2319,7 @@ char *PDECL PR_SaveEnt (pubprogfuncs_t *ppf, char *buf, int *size, struct edict_
d = &prinst.field[i];
name = d->name;
len = strlen(name); // should we skip vars with no name?
if (len > 2 && name[len-2] == '_')
if (len > 2 && name[len-2] == '_' && (name[len-1] == 'x' || name[len-1] == 'y' || name[len-1] == 'z'))
continue; // skip _x, _y, _z vars
v = (int*)((edictrun_t*)ed)->fields + d->ofs;
@ -2308,8 +2338,6 @@ char *PDECL PR_SaveEnt (pubprogfuncs_t *ppf, char *buf, int *size, struct edict_
AddS ("}\n");
*size = s - buf;
return buf;
}
struct edict_s *PDECL PR_RestoreEnt (pubprogfuncs_t *ppf, char *buf, int *size, struct edict_s *ed)

View File

@ -657,18 +657,20 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, char *key, eval_t **result, etype_
c2 = COM_TrimString(c2);
def = ED_FindLocalOrGlobal(progfuncs, c2, &fval);
if (def)
if (def && def->type == ev_field)
{
fofs = fval->_int + progfuncs->funcs.fieldadjust;
fdef = ED_FieldAtOfs(progfuncs, fofs);
}
else
{
fdef = ED_FindField(progfuncs, c2);
if (c)*c = '.';
if (!fdef)
return false;
fofs = fdef->ofs;
}
if (c)*c = '.';
if (!fdef)
return false;
fofs = fdef->ofs;
type = fdef->type;
ed = PROG_TO_EDICT(progfuncs, val->_int);
if (!ed)
@ -676,7 +678,6 @@ pbool LocateDebugTerm(progfuncs_t *progfuncs, char *key, eval_t **result, etype_
if (fofs < 0 || fofs >= max_fields_size)
return false;
val = (eval_t *) (((char *)ed->fields) + fofs*4);
type = fdef->type;
}
*rettype = type;
*result = val;
@ -886,7 +887,7 @@ char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *ppf, char *key)
}
assignment[-1] = '=';
}
strcpy(buf, PR_ValueString(progfuncs, type, val));
QC_snprintfz(buf, sizeof(buf), "%s", PR_ValueString(progfuncs, type, val, true));
return buf;
}
@ -1192,7 +1193,7 @@ void PR_ExecuteCode (progfuncs_t *progfuncs, int s)
break;
case ev_function:
case ev_string:
printf("Watch point \"%s\" set by engine to %s.\n", prinst.watch_name, PR_ValueString(progfuncs, prinst.watch_type, prinst.watch_ptr));
printf("Watch point \"%s\" set by engine to %s.\n", prinst.watch_name, PR_ValueString(progfuncs, prinst.watch_type, prinst.watch_ptr, false));
break;
}
prinst.watch_old = *prinst.watch_ptr;

View File

@ -269,9 +269,9 @@ int PDECL Comp_Continue(pubprogfuncs_t *progfuncs);
pbool PDECL PR_SetWatchPoint(pubprogfuncs_t *progfuncs, char *key);
char *PDECL PR_EvaluateDebugString(pubprogfuncs_t *progfuncs, char *key);
char *PDECL PR_SaveEnts(pubprogfuncs_t *progfuncs, char *mem, int *size, int mode);
char *PDECL PR_SaveEnts(pubprogfuncs_t *progfuncs, char *mem, int *size, int maxsize, int mode);
int PDECL PR_LoadEnts(pubprogfuncs_t *progfuncs, char *file, float killonspawnflags);
char *PDECL PR_SaveEnt (pubprogfuncs_t *progfuncs, char *buf, int *size, struct edict_s *ed);
char *PDECL PR_SaveEnt (pubprogfuncs_t *progfuncs, char *buf, int *size, int maxsize, struct edict_s *ed);
struct edict_s *PDECL PR_RestoreEnt (pubprogfuncs_t *progfuncs, char *buf, int *size, struct edict_s *ed);
void PDECL PR_StackTrace (pubprogfuncs_t *progfuncs);
@ -472,7 +472,7 @@ dfunction_t *ED_FindFunction (progfuncs_t *progfuncs, char *name, progsnum_t *pn
func_t PDECL PR_FindFunc(pubprogfuncs_t *progfncs, char *funcname, progsnum_t pnum);
void PDECL PR_Configure (pubprogfuncs_t *progfncs, size_t addressable_size, int max_progs);
int PDECL PR_InitEnts(pubprogfuncs_t *progfncs, int maxents);
char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val);
char *PR_ValueString (progfuncs_t *progfuncs, etype_t type, eval_t *val, pbool verbose);
void PDECL QC_ClearEdict (pubprogfuncs_t *progfuncs, struct edict_s *ed);
void PRAddressableFlush(progfuncs_t *progfuncs, size_t totalammount);
void QC_FlushProgsOffsets(progfuncs_t *progfuncs);

View File

@ -97,10 +97,10 @@ struct pubprogfuncs_s
char *(PDECL *filefromnewprogs) (pubprogfuncs_t *prinst, char *prname, char *fname, int *size, char *buffer); //reveals encoded/added files from a progs on the disk somewhere
void (PDECL *ED_Print) (pubprogfuncs_t *prinst, struct edict_s *ed);
char *(PDECL *save_ents) (pubprogfuncs_t *prinst, char *buf, int *size, int mode); //dump the entire progs info into one big self allocated string
char *(PDECL *save_ents) (pubprogfuncs_t *prinst, char *buf, int *size, int maxsize, int mode); //dump the entire progs info into one big self allocated string
int (PDECL *load_ents) (pubprogfuncs_t *prinst, char *s, float killonspawnflags); //restore the entire progs state (or just add some more ents) (returns edicts ize)
char *(PDECL *saveent) (pubprogfuncs_t *prinst, char *buf, int *size, struct edict_s *ed); //will save just one entities vars
char *(PDECL *saveent) (pubprogfuncs_t *prinst, char *buf, int *size, int maxsize, struct edict_s *ed); //will save just one entities vars
struct edict_s *(PDECL *restoreent) (pubprogfuncs_t *prinst, char *buf, int *size, struct edict_s *ed); //will restore the entity that had it's values saved (can use NULL for ed)
union eval_s *(PDECL *FindGlobal) (pubprogfuncs_t *prinst, char *name, progsnum_t num, etype_t *type); //find a pointer to the globals value
@ -251,7 +251,7 @@ typedef union eval_s
#define ED_Clear(pf, ed) (*pf->EntClear) (pf, ed)
#define PR_LoadEnts(pf, s, kf) (*pf->load_ents) (pf, s, kf)
#define PR_SaveEnts(pf, buf, size, mode) (*pf->save_ents) (pf, buf, size, mode)
#define PR_SaveEnts(pf, buf, size, maxsize, mode) (*pf->save_ents) (pf, buf, size, maxsize, mode)
#define EDICT_NUM(pf, num) (*pf->EDICT_NUM) (pf, num)
#define NUM_FOR_EDICT(pf, e) (*pf->NUM_FOR_EDICT) (pf, e)

View File

@ -649,6 +649,7 @@ enum {
WARN_MISSINGOPTIONAL,
WARN_SYSTEMCRC,
WARN_CONDITIONALTYPEMISMATCH,
WARN_MISSINGMEMBERQUALIFIER,//virtual/static/nonvirtual qualifier is missing
WARN_SELFNOTTHIS, //warned for because 'self' does not have the right type. we convert such references to 'this' instead, which is more usable.
WARN_EVILPREPROCESSOR, //exploited by nexuiz, and generally unsafe.
WARN_UNARYNOTSCOPE, //!foo & bar the ! applies to the result of &. This is unlike C.

View File

@ -140,8 +140,8 @@ QCC_type_t *QCC_PR_FindType (QCC_type_t *type);
QCC_type_t *QCC_PR_PointerType (QCC_type_t *pointsto);
QCC_type_t *QCC_PR_FieldType (QCC_type_t *pointsto);
QCC_def_t *QCC_PR_Term (int exprflags);
QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, pbool expandmemberfields);
QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign);
QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, pbool expandmemberfields, pbool makearraypointers);
QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign, pbool makestructpointers);
QCC_def_t *QCC_PR_GenerateFunctionCall (QCC_def_t *newself, QCC_def_t *func, QCC_def_t *arglist[], QCC_type_t *argtypelist[], int argcount);
void QCC_Marshal_Locals(int firststatement, int laststatement);
@ -3344,7 +3344,7 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *newself, QCC_def_t *func) //warn
{
int sz;
int oldstcount = numstatements;
e = QCC_PR_Expression (TOP_PRIORITY, EXPR_DISALLOW_COMMA);
e = QCC_PR_ParseValue(pr_classtype, false, true, false);
//the term should not have side effects, or generate any actual statements.
numstatements = oldstcount;
QCC_PR_Expect(")");
@ -3770,7 +3770,7 @@ QCC_def_t *QCC_PR_ParseFunctionCall (QCC_def_t *newself, QCC_def_t *func) //warn
while(QCC_PR_CheckToken(","))
{
QCC_def_t *f, *p, *v;
f = QCC_PR_ParseValue(rettype, false, false);
f = QCC_PR_ParseValue(rettype, false, false, true);
if (f->type->type != ev_field)
QCC_PR_ParseError(0, "Named field is not a field.");
if (QCC_PR_CheckToken("=")) //allow : or = as a separator, but throw a warning for =
@ -4591,7 +4591,7 @@ static QCC_def_t *QCC_PR_ExpandField(QCC_def_t *ent, QCC_def_t *field)
QCC_PR_SimpleStatement(OP_LOAD_FNC, nthis->ofs, field->ofs, func->ofs, false);
qcc_usefulstatement=true;
r = QCC_PR_ParseFunctionCall(nthis, func);
r = QCC_PR_ParseArrayPointer(r, true);
r = QCC_PR_ParseArrayPointer(r, true, true);
}
else
{
@ -4630,11 +4630,16 @@ static QCC_def_t *QCC_PR_ParseField(QCC_def_t *d)
QCC_PR_Expect(")");
}
else
field = QCC_PR_ParseValue(d->type, false, false);
field = QCC_PR_ParseValue(d->type, false, false, true);
if (field->type->type == ev_field || field->type->type == ev_variant)
d = QCC_PR_ExpandField(d, field);
else
QCC_PR_ParseError(ERR_INTERNAL, "Bad field type of class %s", d->type->name);
{
if (d->type->parentclass)
QCC_PR_ParseError(ERR_INTERNAL, "%s is not a field of class %s", field->name, d->type->name);
else
QCC_PR_ParseError(ERR_INTERNAL, "%s is not a field", field->name);
}
d = QCC_PR_ParseField(d);
}
@ -4649,7 +4654,7 @@ within types which are a contiguous block, expanding to an array index.
Also calls QCC_PR_ParseField, which does fields too.
*/
QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign)
QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign, pbool makearraypointers)
{
QCC_type_t *t;
QCC_def_t *idx;
@ -5068,11 +5073,11 @@ QCC_def_t *QCC_PR_ParseArrayPointer (QCC_def_t *d, pbool allowarrayassign)
}
/*parse recursively*/
d = QCC_PR_ParseArrayPointer(d, allowarrayassign);
d = QCC_PR_ParseArrayPointer(d, allowarrayassign, makearraypointers);
}
//float b[64]; return b; should return a pointer, and NOT the value b[0].
if (arraysize)
if (arraysize && makearraypointers)
d = QCC_PR_GenerateAddressOf(statatementstart, d);
d = QCC_PR_ParseField(d);
@ -5086,7 +5091,7 @@ PR_ParseValue
Returns the global ofs for the current token
============
*/
QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, pbool expandmemberfields)
QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, pbool expandmemberfields, pbool makearraypointers)
{
QCC_def_t *d, *od;
QCC_type_t *t;
@ -5316,7 +5321,7 @@ QCC_def_t *QCC_PR_ParseValue (QCC_type_t *assumeclass, pbool allowarrayassign, p
QCC_PR_ParseWarning (WARN_SELFNOTTHIS, "'self' used inside OO function, use 'this'.", pr_scope->name);
}
d = QCC_PR_ParseArrayPointer(d, allowarrayassign);
d = QCC_PR_ParseArrayPointer(d, allowarrayassign, makearraypointers);
if (pr_classtype && expandmemberfields && d->type->type == ev_field)
{
@ -5602,12 +5607,12 @@ QCC_def_t *QCC_PR_Term (int exprflags)
QCC_PR_Expect (")");
conditional = oldcond;
QCC_PR_ParseArrayPointer(e, true);
QCC_PR_ParseArrayPointer(e, true, true);
}
return e;
}
}
return QCC_PR_ParseValue (pr_classtype, !(exprflags&EXPR_DISALLOW_ARRAYASSIGN), true);
return QCC_PR_ParseValue (pr_classtype, !(exprflags&EXPR_DISALLOW_ARRAYASSIGN), true, true);
}
@ -5679,7 +5684,7 @@ QCC_def_t *QCC_PR_Expression (int priority, int exprflags)
{
qcc_usefulstatement=true;
e = QCC_PR_ParseFunctionCall (NULL, e);
e = QCC_PR_ParseArrayPointer(e, true);
e = QCC_PR_ParseArrayPointer(e, true, true);
}
if (QCC_PR_CheckToken ("?"))
{
@ -6365,7 +6370,7 @@ void QCC_PR_ParseStatement (void)
if (((e->constant && !e->temp) || !STRCMP(e->name, "IMMEDIATE")) && opt_compound_jumps)
{
optres_compound_jumps++;
if (!G_INT(e->ofs) == wasuntil)
if (!G_INT(e->ofs) != wasuntil)
{
QCC_PR_ParseWarning(0, "while(0)?");
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_GOTO], 0, 0, &patch1));
@ -6379,7 +6384,7 @@ void QCC_PR_ParseStatement (void)
{
if (e->constant && !e->temp)
{
if (!G_FLOAT(e->ofs) == wasuntil)
if (!G_FLOAT(e->ofs) != wasuntil)
QCC_FreeTemp(QCC_PR_Statement (&pr_opcodes[OP_GOTO], 0, 0, &patch1));
else
patch1 = NULL;
@ -7323,7 +7328,7 @@ void QCC_PR_ParseAsm(void)
{
patch1 = &statements[numstatements];
a = QCC_PR_ParseValue(pr_classtype, false, false);
a = QCC_PR_ParseValue(pr_classtype, false, false, true);
QCC_PR_Statement3(&pr_opcodes[op], a, NULL, NULL, true);
if (pr_token_type == tt_name)
@ -7342,8 +7347,8 @@ void QCC_PR_ParseAsm(void)
{
patch1 = &statements[numstatements];
a = QCC_PR_ParseValue(pr_classtype, false, false);
b = QCC_PR_ParseValue(pr_classtype, false, false);
a = QCC_PR_ParseValue(pr_classtype, false, false, true);
b = QCC_PR_ParseValue(pr_classtype, false, false, true);
QCC_PR_Statement3(&pr_opcodes[op], a, b, NULL, true);
if (pr_token_type == tt_name)
@ -7362,15 +7367,15 @@ void QCC_PR_ParseAsm(void)
else
{
if (pr_opcodes[op].type_a != &type_void)
a = QCC_PR_ParseValue(pr_classtype, false, false);
a = QCC_PR_ParseValue(pr_classtype, false, false, true);
else
a=NULL;
if (pr_opcodes[op].type_b != &type_void)
b = QCC_PR_ParseValue(pr_classtype, false, false);
b = QCC_PR_ParseValue(pr_classtype, false, false, true);
else
b=NULL;
if (pr_opcodes[op].associative==ASSOC_LEFT && pr_opcodes[op].type_c != &type_void)
c = QCC_PR_ParseValue(pr_classtype, false, false);
c = QCC_PR_ParseValue(pr_classtype, false, false, true);
else
c=NULL;

View File

@ -3963,11 +3963,20 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
while (!QCC_PR_CheckToken("}"))
{
pbool havebody = false;
pbool isstatic = false, isvirt = false;
if (QCC_PR_CheckKeyword(1, "static"))
isstatic = true;
if (QCC_PR_CheckKeyword(1, "virtual"))
isvirt = true;
pbool isvirt = false;
pbool isnonvirt = false;
pbool isstatic = false;
while(1)
{
if (QCC_PR_CheckKeyword(1, "nonvirtual"))
isnonvirt = true;
else if (QCC_PR_CheckKeyword(1, "static"))
isstatic = true;
else if (QCC_PR_CheckKeyword(1, "virtual"))
isvirt = true;
else
break;
}
newparm = QCC_PR_ParseType(false, false);
if (!newparm)
@ -3976,9 +3985,7 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
if (newparm->type == ev_struct || newparm->type == ev_union) //we wouldn't be able to handle it.
QCC_PR_ParseError(ERR_INTERNAL, "Struct or union in class %s", classname);
parmname = qccHunkAlloc(strlen(pr_token)+1);
strcpy(parmname, pr_token);
QCC_PR_Lex();
parmname = QCC_PR_ParseName();
if (QCC_PR_CheckToken("["))
{
arraysize = QCC_PR_IntConstExpr();
@ -3987,9 +3994,30 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
else
arraysize = 0;
if (isvirt && newparm->type != ev_function)
if (newparm->type == ev_function)
{
QCC_Error(ERR_INTERNAL, "virtual keyword on member that is not a function");
if (isstatic)
QCC_PR_ParseError(ERR_INTERNAL, "%s::%s static functions are not supported at this time.", classname, parmname);
if (!strcmp(classname, parmname))
{
if (isstatic)
QCC_PR_ParseError(ERR_INTERNAL, "Constructor %s::%s may not be static.", classname, pr_token);
if (!isvirt)
isnonvirt = true;//silently promote constructors to nonvirt
}
else if (!isvirt && !isnonvirt && !isstatic)
{
QCC_PR_ParseWarning(WARN_MISSINGMEMBERQUALIFIER, "%s::%s was not qualified. Assuming non-virtual.", classname, parmname);
isnonvirt = true;
}
if (isvirt+isnonvirt+isstatic != 1)
QCC_PR_ParseError(ERR_INTERNAL, "Multiple conflicting qualifiers on %s::%s.", classname, pr_token);
}
else
{
if (isvirt|isnonvirt)
QCC_Error(ERR_INTERNAL, "virtual keyword on member that is not a function");
}
if (newparm->type == ev_function)
@ -4078,12 +4106,11 @@ QCC_type_t *QCC_PR_ParseType (int newtype, pbool silentfail)
}
}
if (!isvirt && !isstatic)
if (!isvirt)
{
QCC_def_t *fdef;
QCC_type_t *pc;
unsigned int i;
isstatic = true; //assume static if its initialised inside the function.
for (pc = newt->parentclass; pc; pc = pc->parentclass)
{