diff --git a/include/QF/progs.h b/include/QF/progs.h index 1aef70a18..2202d8845 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -64,6 +64,8 @@ void PR_Init (void); void PR_Init_Cvars (void); void PR_PrintStatement (progs_t *pr, dstatement_t *s); +void PR_PushFrame (progs_t *pr); +void PR_PopFrame (progs_t *pr); void PR_EnterFunction (progs_t *pr, dfunction_t *f); void PR_ExecuteProgram (progs_t *pr, func_t fnum); void PR_LoadProgsFile (progs_t *pr, QFile *file, int size, int edicts, @@ -286,13 +288,15 @@ void PR_Cmds_Init (progs_t *pr); //============================================================================ -#define MAX_STACK_DEPTH 32 -#define LOCALSTACK_SIZE 2048 +#define MAX_STACK_DEPTH 64 +#define LOCALSTACK_SIZE 4096 + +typedef struct strref_s strref_t; typedef struct { int s; dfunction_t *f; - struct strref_s *tstr; + strref_t *tstr; } prstack_t; struct progs_s { @@ -312,15 +316,13 @@ struct progs_s { int max_load_funcs; pr_load_func_t **load_funcs; - // garbage collected strings struct dstring_mem_s *ds_mem; - struct strref_s *static_strings; - struct strref_s **dynamic_strings; - struct strref_s *free_string_refs; + strref_t *static_strings; + strref_t **dynamic_strings; unsigned dyn_str_size; struct hashtab_s *strref_hash; int num_strings; - struct strref_s *pr_xtstr; + strref_t *pr_xtstr; dfunction_t *pr_functions; char *pr_strings; diff --git a/libs/console/menu.c b/libs/console/menu.c index 1cdc32691..d453d1a0b 100644 --- a/libs/console/menu.c +++ b/libs/console/menu.c @@ -586,14 +586,13 @@ Menu_KeyEvent (knum_t key, short unicode, qboolean down) return; } else if (menu->items && menu->items[menu->cur_item]->func && menu->items[menu->cur_item]->allkeys) { + PR_PushFrame (&menu_pr_state); item = menu->items[menu->cur_item]; - if (item->text) - P_INT (&menu_pr_state, 0) = - PR_SetString (&menu_pr_state, item->text); - else - P_INT (&menu_pr_state, 0) = 0; + P_STRING (&menu_pr_state, 0) = PR_SetTempString (&menu_pr_state, + item->text); P_INT (&menu_pr_state, 1) = key; PR_ExecuteProgram (&menu_pr_state, item->func); + PR_PopFrame (&menu_pr_state); if (R_INT (&menu_pr_state)) return; } @@ -615,13 +614,12 @@ Menu_KeyEvent (knum_t key, short unicode, qboolean down) { item = menu->items[menu->cur_item]; if (item->func) { - if (item->text) - P_INT (&menu_pr_state, 0) = - PR_SetString (&menu_pr_state, item->text); - else - P_INT (&menu_pr_state, 0) = 0; + PR_PushFrame (&menu_pr_state); + P_STRING (&menu_pr_state, 0) = + PR_SetTempString (&menu_pr_state, item->text); P_INT (&menu_pr_state, 1) = key; PR_ExecuteProgram (&menu_pr_state, item->func); + PR_PopFrame (&menu_pr_state); } else { menu = item; if (menu->enter_hook) { diff --git a/libs/gamecode/builtins/bi_gib.c b/libs/gamecode/builtins/bi_gib.c index 16791602b..657c8c066 100644 --- a/libs/gamecode/builtins/bi_gib.c +++ b/libs/gamecode/builtins/bi_gib.c @@ -85,14 +85,16 @@ bi_gib_builtin_f (void) if (!builtin) Sys_Error ("bi_gib_builtin_f: unexpected call %s", GIB_Argv (0)); + PR_PushFrame (builtin->pr); pr_list = PR_Zone_Malloc (builtin->pr, GIB_Argc() * sizeof (pr_type_t)); for (i = 0; i < GIB_Argc(); i++) - pr_list[i].integer_var = PR_SetString (builtin->pr, GIB_Argv(i)); + pr_list[i].integer_var = PR_SetTempString (builtin->pr, GIB_Argv(i)); P_INT (builtin->pr, 0) = GIB_Argc(); P_INT (builtin->pr, 1) = POINTER_TO_PROG (builtin->pr, pr_list); PR_ExecuteProgram (builtin->pr, builtin->func); + PR_PopFrame (builtin->pr); PR_Zone_Free (builtin->pr, pr_list); } diff --git a/libs/gamecode/engine/pr_debug.c b/libs/gamecode/engine/pr_debug.c index d9e710809..2853d72b7 100644 --- a/libs/gamecode/engine/pr_debug.c +++ b/libs/gamecode/engine/pr_debug.c @@ -535,51 +535,57 @@ PR_PrintStatement (progs_t * pr, dstatement_t *s) Sys_Printf ("%s\n", line->str); } +static void +dump_frame (progs_t *pr, prstack_t *frame) +{ + dfunction_t *f = frame->f; + + if (!f) { + Sys_Printf ("\n"); + return; + } + if (pr_debug->int_val && pr->debug) { + pr_lineno_t *lineno = PR_Find_Lineno (pr, frame->s); + pr_auxfunction_t *func = PR_Get_Lineno_Func (pr, lineno); + unsigned int line = PR_Get_Lineno_Line (pr, lineno); + int addr = PR_Get_Lineno_Addr (pr, lineno); + + line += func->source_line; + if (addr == frame->s) { + Sys_Printf ("%12s:%d : %s: %x\n", + PR_GetString (pr, f->s_file), + line, + PR_GetString (pr, f->s_name), + frame->s); + } else { + Sys_Printf ("%12s:%d+%d : %s: %x\n", + PR_GetString (pr, f->s_file), + line, frame->s - addr, + PR_GetString (pr, f->s_name), + frame->s); + } + } else { + Sys_Printf ("%12s : %s: %x\n", PR_GetString (pr, f->s_file), + PR_GetString (pr, f->s_name), frame->s); + } +} + void -PR_StackTrace (progs_t * pr) +PR_StackTrace (progs_t *pr) { int i; - dfunction_t *f; + prstack_t top; if (pr->pr_depth == 0) { Sys_Printf ("\n"); return; } - pr->pr_stack[pr->pr_depth].s = pr->pr_xstatement; - pr->pr_stack[pr->pr_depth].f = pr->pr_xfunction; - for (i = pr->pr_depth; i >= 0; i--) { - f = pr->pr_stack[i].f; - - if (!f) { - Sys_Printf ("\n"); - } else { - if (pr_debug->int_val && pr->debug) { - pr_lineno_t *lineno = PR_Find_Lineno (pr, pr->pr_stack[i].s); - pr_auxfunction_t *func = PR_Get_Lineno_Func (pr, lineno); - unsigned int line = PR_Get_Lineno_Line (pr, lineno); - int addr = PR_Get_Lineno_Addr (pr, lineno); - - line += func->source_line; - if (addr == pr->pr_stack[i].s) { - Sys_Printf ("%12s:%d : %s: %x\n", - PR_GetString (pr, f->s_file), - line, - PR_GetString (pr, f->s_name), - pr->pr_stack[i].s); - } else { - Sys_Printf ("%12s:%d+%d : %s: %x\n", - PR_GetString (pr, f->s_file), - line, pr->pr_stack[i].s - addr, - PR_GetString (pr, f->s_name), - pr->pr_stack[i].s); - } - } else { - Sys_Printf ("%12s : %s: %x\n", PR_GetString (pr, f->s_file), - PR_GetString (pr, f->s_name), pr->pr_stack[i].s); - } - } - } + top.s = pr->pr_xstatement; + top.f = pr->pr_xfunction; + dump_frame (pr, &top); + for (i = pr->pr_depth - 1; i >= 0; i--) + dump_frame (pr, pr->pr_stack + i); } void diff --git a/libs/gamecode/engine/pr_exec.c b/libs/gamecode/engine/pr_exec.c index a00cf9bde..1007c4882 100644 --- a/libs/gamecode/engine/pr_exec.c +++ b/libs/gamecode/engine/pr_exec.c @@ -75,23 +75,59 @@ PR_RunError (progs_t * pr, const char *error, ...) PR_Error (pr, "Program error: %s", string->str); } +inline void +PR_PushFrame (progs_t *pr) +{ + prstack_t *frame; + + if (pr->pr_depth == MAX_STACK_DEPTH) + PR_RunError (pr, "stack overflow"); + + frame = pr->pr_stack + pr->pr_depth++; + + frame->s = pr->pr_xstatement; + frame->f = pr->pr_xfunction; + frame->tstr = pr->pr_xtstr; + + pr->pr_xtstr = 0; + pr->pr_xfunction = 0; +} + +inline void +PR_PopFrame (progs_t *pr) +{ + prstack_t *frame; + + if (pr->pr_depth <= 0) + PR_Error (pr, "prog stack underflow"); + + if (pr->pr_xtstr) + PR_FreeTempStrings (pr); + + // up stack + frame = pr->pr_stack + --pr->pr_depth; + + pr->pr_xfunction = frame->f; + pr->pr_xstatement = frame->s; + pr->pr_xtstr = frame->tstr; +} + /* PR_EnterFunction Returns the new program statement counter */ void -PR_EnterFunction (progs_t * pr, dfunction_t *f) +PR_EnterFunction (progs_t *pr, dfunction_t *f) { int i, j, c, o; int k; + PR_PushFrame (pr); + //Sys_Printf("%s:\n", PR_GetString(pr,f->s_name)); - pr->pr_stack[pr->pr_depth].s = pr->pr_xstatement; - pr->pr_stack[pr->pr_depth].f = pr->pr_xfunction; - pr->pr_depth++; - if (pr->pr_depth >= MAX_STACK_DEPTH - 1) - PR_RunError (pr, "stack overflow"); + pr->pr_xfunction = f; + pr->pr_xstatement = f->first_statement - 1; // offset the st++ // save off any locals that the new function steps on c = f->locals; @@ -134,39 +170,24 @@ PR_EnterFunction (progs_t * pr, dfunction_t *f) (MAX_PARMS - i) * pr->pr_param_size * sizeof (pr_type_t)); } } - - pr->pr_xfunction = f; - pr->pr_xstatement = f->first_statement - 1; // offset the st++ - pr->pr_xtstr = 0; - return; } static void -PR_LeaveFunction (progs_t * pr) +PR_LeaveFunction (progs_t *pr) { int c; + dfunction_t *f = pr->pr_xfunction; - if (pr->pr_depth <= 0) - PR_Error (pr, "prog stack underflow"); + PR_PopFrame (pr); // restore locals from the stack - c = pr->pr_xfunction->locals; + c = f->locals; pr->localstack_used -= c; if (pr->localstack_used < 0) PR_RunError (pr, "PR_LeaveFunction: locals stack underflow"); - memcpy (&pr->pr_globals[pr->pr_xfunction->parm_start], - &pr->localstack[pr->localstack_used], - sizeof (pr_type_t) * c); - - if (pr->pr_xtstr) - PR_FreeTempStrings (pr); - - // up stack - pr->pr_depth--; - pr->pr_xfunction = pr->pr_stack[pr->pr_depth].f; - pr->pr_xstatement = pr->pr_stack[pr->pr_depth].s; - pr->pr_xtstr = pr->pr_stack[pr->pr_depth].tstr; + memcpy (&pr->pr_globals[f->parm_start], + &pr->localstack[pr->localstack_used], sizeof (pr_type_t) * c); } #define OPA (*op_a) diff --git a/libs/gamecode/engine/pr_obj.c b/libs/gamecode/engine/pr_obj.c index dc2ce48a7..0a8e4b2d8 100644 --- a/libs/gamecode/engine/pr_obj.c +++ b/libs/gamecode/engine/pr_obj.c @@ -403,7 +403,7 @@ pr_obj_msg_sendv (progs_t *pr) PR_GetString (pr, op->sel_id)); if (args.count > 6) args.count = 6; - memcpy (P_GPOINTER (pr, 2), G_GPOINTER (pr, args.list), + memcpy (pr->pr_params[2], G_GPOINTER (pr, args.list), args.count * 4 * pr->pr_param_size); call_function (pr, method->method_imp); } diff --git a/libs/gamecode/engine/pr_strings.c b/libs/gamecode/engine/pr_strings.c index 8767a0141..00d0d7304 100644 --- a/libs/gamecode/engine/pr_strings.c +++ b/libs/gamecode/engine/pr_strings.c @@ -46,12 +46,37 @@ static __attribute__ ((unused)) const char rcsid[] = #include "QF/hash.h" #include "QF/progs.h" -typedef struct strref_s { - struct strref_s *next; +struct strref_s { + strref_t *next; char *string; dstring_t *dstring; int count; -} strref_t; +}; + +// format adjustments +#define FMT_ALTFORM (1<<0) +#define FMT_LJUSTIFY (1<<1) +#define FMT_ZEROPAD (1<<2) +#define FMT_ADDSIGN (1<<3) +#define FMT_ADDBLANK (1<<4) +#define FMT_HEX (1<<5) + +typedef struct fmt_item_s { + byte type; + unsigned flags; + int minFieldWidth; + int precision; + union { + const char *string_var; + int integer_var; + unsigned uinteger_var; + float float_var; + } data; + struct fmt_item_s *next; +} fmt_item_t; + +static strref_t *free_string_refs; +static fmt_item_t *free_fmt_items; static void * pr_strings_alloc (void *_pr, size_t size) @@ -78,7 +103,7 @@ static strref_t * new_string_ref (progs_t *pr) { strref_t *sr; - if (!pr->free_string_refs) { + if (!free_string_refs) { int i, size; pr->dyn_str_size++; @@ -86,15 +111,15 @@ new_string_ref (progs_t *pr) pr->dynamic_strings = realloc (pr->dynamic_strings, size); if (!pr->dynamic_strings) PR_Error (pr, "out of memory"); - if (!(pr->free_string_refs = calloc (1024, sizeof (strref_t)))) + if (!(free_string_refs = calloc (1024, sizeof (strref_t)))) PR_Error (pr, "out of memory"); - pr->dynamic_strings[pr->dyn_str_size - 1] = pr->free_string_refs; - for (i = 0, sr = pr->free_string_refs; i < 1023; i++, sr++) + pr->dynamic_strings[pr->dyn_str_size - 1] = free_string_refs; + for (i = 0, sr = free_string_refs; i < 1023; i++, sr++) sr->next = sr + 1; sr->next = 0; } - sr = pr->free_string_refs; - pr->free_string_refs = sr->next; + sr = free_string_refs; + free_string_refs = sr->next; sr->next = 0; return sr; } @@ -104,8 +129,8 @@ free_string_ref (progs_t *pr, strref_t *sr) { sr->string = 0; sr->dstring = 0; - sr->next = pr->free_string_refs; - pr->free_string_refs = sr; + sr->next = free_string_refs; + free_string_refs = sr; } static int @@ -173,7 +198,7 @@ PR_LoadStrings (progs_t *pr) pr->strref_hash = Hash_NewTable (1021, strref_get_key, strref_free, pr); pr->dynamic_strings = 0; - pr->free_string_refs = 0; + free_string_refs = 0; pr->dyn_str_size = 0; } @@ -282,6 +307,9 @@ PR_SetTempString (progs_t *pr, const char *s) { strref_t *sr; + if (!s) + return PR_SetString (pr, ""); + sr = new_string_ref (pr); sr->string = pr_strdup(pr, s); sr->count = 0; @@ -346,28 +374,6 @@ PR_FreeTempStrings (progs_t *pr) pr->pr_xtstr = 0; } -// format adjustments -#define FMT_ALTFORM (1<<0) -#define FMT_LJUSTIFY (1<<1) -#define FMT_ZEROPAD (1<<2) -#define FMT_ADDSIGN (1<<3) -#define FMT_ADDBLANK (1<<4) -#define FMT_HEX (1<<5) - -typedef struct fmt_item_s { - byte type; - unsigned flags; - int minFieldWidth; - int precision; - union { - const char *string_var; - int integer_var; - unsigned uinteger_var; - float float_var; - } data; - struct fmt_item_s *next; -} fmt_item_t; - #define PRINT(t) \ switch ((doWidth << 1) | doPrecision) { \ case 3: \ @@ -446,8 +452,6 @@ I_DoPrint (dstring_t *result, fmt_item_t *formatting) dstring_delete (tmp); } -static fmt_item_t *free_fmt_items; - static fmt_item_t * new_fmt_item (void) { @@ -492,7 +496,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, *fi = new_fmt_item (); c = l = format; - while (*c) { // count "%"s, checking our input along the way + while (*c) { if (*c++ == '%') { if (c != l + 1) { // have some unformatted text to print @@ -676,7 +680,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, fi = &(*fi)->next; } - if (0 && fmt_count != count) { + if (fmt_count != count) { printf ("%d %d", fmt_count, count); if (fmt_count > count) msg = "Not enough arguments for format string."; diff --git a/qw/source/sv_ccmds.c b/qw/source/sv_ccmds.c index 9e3f34b50..2d04fb69f 100644 --- a/qw/source/sv_ccmds.c +++ b/qw/source/sv_ccmds.c @@ -859,10 +859,12 @@ SV_SetLocalinfo (const char *key, const char *value) if (sv_funcs.LocalinfoChanged) { *sv_globals.time = sv.time; *sv_globals.self = 0; - P_STRING (&sv_pr_state, 0) = PR_SetString (&sv_pr_state, key); - P_STRING (&sv_pr_state, 1) = PR_SetString (&sv_pr_state, oldvalue); - P_STRING (&sv_pr_state, 2) = PR_SetString (&sv_pr_state, value); + PR_PushFrame (&sv_pr_state); + P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key); + P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, oldvalue); + P_STRING (&sv_pr_state, 2) = PR_SetTempString (&sv_pr_state, value); PR_ExecuteProgram (&sv_pr_state, sv_funcs.LocalinfoChanged); + PR_PopFrame (&sv_pr_state); } if (oldvalue) diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index 673e5e7d0..5a512a415 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -810,12 +810,14 @@ SV_Say (qboolean team) } if (sv_funcs.ChatMessage) { - P_STRING (&sv_pr_state, 0) = PR_SetString (&sv_pr_state, p); + PR_PushFrame (&sv_pr_state); + P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, p); G_FLOAT (&sv_pr_state, 1) = (float) team; *sv_globals.time = sv.time; *sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player); PR_ExecuteProgram (&sv_pr_state, sv_funcs.ChatMessage); + PR_PopFrame (&sv_pr_state); if (R_FLOAT (&sv_pr_state)) return; } @@ -1121,12 +1123,14 @@ SV_SetUserinfo (client_t *client, const char *key, const char *value) key, oldvalue, value); if (sv_funcs.UserInfoChanged) { + PR_PushFrame (&sv_pr_state); *sv_globals.time = sv.time; *sv_globals.self = EDICT_TO_PROG (&sv_pr_state, client->edict); - P_STRING (&sv_pr_state, 0) = PR_SetString (&sv_pr_state, key); - P_STRING (&sv_pr_state, 1) = PR_SetString (&sv_pr_state, oldvalue); - P_STRING (&sv_pr_state, 2) = PR_SetString (&sv_pr_state, value); + P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key); + P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, oldvalue); + P_STRING (&sv_pr_state, 2) = PR_SetTempString (&sv_pr_state, value); PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoChanged); + PR_PopFrame (&sv_pr_state); } if (oldvalue) @@ -1169,10 +1173,12 @@ SV_SetInfo_f (void *unused) value = Cmd_Argv (2); if (sv_funcs.UserInfoCallback) { + PR_PushFrame (&sv_pr_state); *sv_globals.self = EDICT_TO_PROG (&sv_pr_state, sv_player); - P_STRING (&sv_pr_state, 0) = PR_SetString (&sv_pr_state, key); - P_STRING (&sv_pr_state, 1) = PR_SetString (&sv_pr_state, value); + P_STRING (&sv_pr_state, 0) = PR_SetTempString (&sv_pr_state, key); + P_STRING (&sv_pr_state, 1) = PR_SetTempString (&sv_pr_state, value); PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoCallback); + PR_PopFrame (&sv_pr_state); return; } diff --git a/tools/qwaq/main.c b/tools/qwaq/main.c index d18523e8a..e86f13155 100644 --- a/tools/qwaq/main.c +++ b/tools/qwaq/main.c @@ -161,17 +161,19 @@ main (int argc, char **argv) if (!load_progs (name)) Sys_Error ("couldn't load %s", "qwaq.dat"); + PR_PushFrame (&pr); if (argc > 2) pr_argc = argc - 1; pr_argv = PR_Zone_Malloc (&pr, (pr_argc + 1) * 4); - pr_argv[0] = PR_SetString (&pr, name); + pr_argv[0] = PR_SetTempString (&pr, name); for (i = 1; i < pr_argc; i++) - pr_argv[i] = PR_SetString (&pr, argv[1 + i]); + pr_argv[i] = PR_SetTempString (&pr, argv[1 + i]); pr_argv[i] = 0; main_func = PR_GetFunctionIndex (&pr, "main"); - P_INT (&pr, 0) = pr_argc; - P_INT (&pr, 1) = POINTER_TO_PROG (&pr, pr_argv); + P_POINTER (&pr, 0) = pr_argc; + P_POINTER (&pr, 1) = POINTER_TO_PROG (&pr, pr_argv); PR_ExecuteProgram (&pr, main_func); + PR_PopFrame (&pr); return R_INT (&pr); }