diff --git a/engine/qclib/execloop.h b/engine/qclib/execloop.h index 5006fcc5b..40f22e8a6 100644 --- a/engine/qclib/execloop.h +++ b/engine/qclib/execloop.h @@ -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; diff --git a/engine/qclib/pr_comp.h b/engine/qclib/pr_comp.h index 35ea6e504..35a3bdc7b 100644 --- a/engine/qclib/pr_comp.h +++ b/engine/qclib/pr_comp.h @@ -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. diff --git a/engine/qclib/pr_edict.c b/engine/qclib/pr_edict.c index 048cba145..fc7775d70 100644 --- a/engine/qclib/pr_edict.c +++ b/engine/qclib/pr_edict.c @@ -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 ("\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) diff --git a/engine/qclib/pr_exec.c b/engine/qclib/pr_exec.c index 23c8697ce..aaf1610ef 100644 --- a/engine/qclib/pr_exec.c +++ b/engine/qclib/pr_exec.c @@ -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; diff --git a/engine/qclib/progsint.h b/engine/qclib/progsint.h index d8905276f..4fad8e00c 100644 --- a/engine/qclib/progsint.h +++ b/engine/qclib/progsint.h @@ -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); diff --git a/engine/qclib/progslib.h b/engine/qclib/progslib.h index cb3aa7cac..70996858c 100644 --- a/engine/qclib/progslib.h +++ b/engine/qclib/progslib.h @@ -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) diff --git a/engine/qclib/qcc.h b/engine/qclib/qcc.h index e0c2bb66c..996c80a27 100644 --- a/engine/qclib/qcc.h +++ b/engine/qclib/qcc.h @@ -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. diff --git a/engine/qclib/qcc_pr_comp.c b/engine/qclib/qcc_pr_comp.c index 0533a201a..fd63a76d5 100644 --- a/engine/qclib/qcc_pr_comp.c +++ b/engine/qclib/qcc_pr_comp.c @@ -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; diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index e81aa5cfe..ca64a79f2 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -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) {