From ee228504aa96c18a1f677607ace95afbec427ca4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 01:28:09 +0900 Subject: [PATCH 001/444] Fix self-referenced enum declarations eg: typedef enum foo { bar = 1, baz = bar, } foo; --- tools/qfcc/source/qc-parse.y | 2 ++ tools/qfcc/source/struct.c | 1 + 2 files changed, 3 insertions(+) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index c34efd0a0..a2bbf1c03 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -553,6 +553,7 @@ optional_enum_list enum_list : '{' enum_init enumerator_list optional_comma '}' { + current_symtab = current_symtab->parent; $$ = finish_enum ($3); } ; @@ -562,6 +563,7 @@ enum_init { $$ = find_enum ($-1); start_enum ($$); + current_symtab = $$->type->t.symtab; } ; diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 358b337f0..800a1aa66 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -201,6 +201,7 @@ add_enum (symbol_t *enm, symbol_t *name, expr_t *val) if (enum_tab->symbols) value = ((symbol_t *)(enum_tab->symtail))->s.value->v.integer_val + 1; if (val) { + convert_name (val); if (!is_constant (val)) error (val, "non-constant initializer"); else if (!is_integer_val (val)) From c61d0b6ff00800d6e8a9beaf924730cef885a081 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 01:51:24 +0900 Subject: [PATCH 002/444] Allow unlimited parameters in function declarations However, definitions are still limited to 8 parameters. This allows processing of C headers for type information. --- tools/qfcc/include/function.h | 1 - tools/qfcc/include/type.h | 2 +- tools/qfcc/source/class.c | 9 ++++++--- tools/qfcc/source/cpp.c | 3 --- tools/qfcc/source/function.c | 36 ++++++++++++++++++++--------------- 5 files changed, 28 insertions(+), 23 deletions(-) diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index 88ea05dc8..209f40026 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -141,7 +141,6 @@ function_t *build_code_function (struct symbol_s *fsym, struct expr_s *statements); function_t *build_builtin_function (struct symbol_s *sym, struct expr_s *bi_val, int far); -void build_function (function_t *f); void finish_function (function_t *f); void emit_function (function_t *f, struct expr_s *e); int function_parms (function_t *f, byte *parm_size); diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 6944db353..fcb4a808a 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -38,7 +38,7 @@ typedef struct ty_func_s { struct type_s *type; int num_params; - struct type_s *param_types[MAX_PARMS]; + struct type_s **param_types; } ty_func_t; typedef struct ty_fldptr_s { diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index e0d601aa9..b249069c2 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -70,12 +70,14 @@ static hashtab_t *protocol_hash; // these will be built up further type_t type_obj_selector = { ev_invalid, 0, 0, ty_struct}; type_t type_SEL = { ev_pointer, "SEL", 1, ty_none, {{&type_obj_selector}}}; +type_t *IMP_params[] = {&type_id, &type_SEL}; type_t type_IMP = { ev_func, "IMP", 1, ty_none, - {{&type_id, -3, {&type_id, &type_SEL}}}}; + {{&type_id, -3, IMP_params}}}; type_t type_obj_super = { ev_invalid, 0, 0 }; type_t type_SuperPtr = { ev_pointer, 0, 1, ty_none, {{&type_obj_super}}}; +type_t *supermsg_params[] = {&type_SuperPtr, &type_SEL}; type_t type_supermsg = { ev_func, ".supermsg", 1, ty_none, - {{&type_id, -3, {&type_SuperPtr, &type_SEL}}}}; + {{&type_id, -3, supermsg_params}}}; type_t type_obj_method = { ev_invalid, 0, 0, ty_struct }; type_t type_obj_method_description = { ev_invalid, 0, 0, ty_struct }; type_t type_obj_category = { ev_invalid, 0, 0, ty_struct}; @@ -83,8 +85,9 @@ type_t type_obj_ivar = { ev_invalid, 0, 0, ty_struct}; type_t type_obj_module = { ev_invalid, 0, 0, ty_struct}; type_t type_moduleptr = { ev_pointer, 0, 1, ty_none, {{&type_obj_module}}}; +type_t *obj_exec_class_params[] = { &type_moduleptr }; type_t type_obj_exec_class = { ev_func, 0, 1, ty_none, - {{&type_void, 1, { &type_moduleptr }}}}; + {{&type_void, 1, obj_exec_class_params}}}; type_t type_obj_object = {ev_invalid, 0, 0, ty_struct}; type_t type_id = { ev_pointer, "id", 1, ty_none, {{&type_obj_object}}}; diff --git a/tools/qfcc/source/cpp.c b/tools/qfcc/source/cpp.c index 9bea8741d..7e8affb49 100644 --- a/tools/qfcc/source/cpp.c +++ b/tools/qfcc/source/cpp.c @@ -141,9 +141,6 @@ build_cpp_args (const char *in_name, const char *out_name) } } *arg = 0; - //for (arg = cpp_argv; *arg; arg++) - // printf ("%s ", *arg); - //puts (""); } //============================================================================ diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index b150e4baf..884dce1da 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -155,6 +155,7 @@ parse_params (type_t *type, param_t *parms) { param_t *p; type_t *new; + int count; new = new_type (); new->type = ev_func; @@ -163,10 +164,12 @@ parse_params (type_t *type, param_t *parms) new->t.func.num_params = 0; for (p = parms; p; p = p->next) { - if (new->t.func.num_params > MAX_PARMS) { - error (0, "too many params"); - return type; + if (p->type) { + count++; } + } + new->t.func.param_types = malloc (count * sizeof (type_t)); + for (p = parms; p; p = p->next) { if (!p->selector && !p->type && !p->name) { if (p->next) internal_error (0, 0); @@ -581,12 +584,25 @@ begin_function (symbol_t *sym, const char *nicename, symtab_t *parent, return sym->s.func; } +static void +build_function (symbol_t *fsym) +{ + if (fsym->type->t.func.num_params > MAX_PARMS) { + error (0, "too many params"); + } + // FIXME +// f->def->constant = 1; +// f->def->nosave = 1; +// f->def->initialized = 1; +// G_FUNCTION (f->def->ofs) = f->function_num; +} + function_t * build_code_function (symbol_t *fsym, expr_t *state_expr, expr_t *statements) { if (fsym->sy_type != sy_func) // probably in error recovery return 0; - build_function (fsym->s.func); + build_function (fsym); if (state_expr) { state_expr->next = statements; statements = state_expr; @@ -629,7 +645,7 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val, int far) bi = expr_float (bi_val); sym->s.func->builtin = bi; reloc_def_func (sym->s.func, sym->s.func->def); - build_function (sym->s.func); + build_function (sym); finish_function (sym->s.func); // for debug info @@ -638,16 +654,6 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val, int far) return sym->s.func; } -void -build_function (function_t *f) -{ - // FIXME -// f->def->constant = 1; -// f->def->nosave = 1; -// f->def->initialized = 1; -// G_FUNCTION (f->def->ofs) = f->function_num; -} - void finish_function (function_t *f) { From 2d52da9c0d9ec87c5fa3931b65445596478febe7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 02:30:50 +0900 Subject: [PATCH 003/444] Fix segfault in unlimited params --- tools/qfcc/source/function.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 884dce1da..4d3a617e9 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -330,8 +330,9 @@ find_function (expr_t *fexpr, expr_t *params) return e; type.t.func.num_params++; } - if (type.t.func.num_params > MAX_PARMS) - return fexpr; + i = type.t.func.num_params * sizeof (type_t); + type.t.func.param_types = alloca(i); + memset (type.t.func.param_types, 0, i); for (i = 0, e = params; e; i++, e = e->next) { type.t.func.param_types[type.t.func.num_params - 1 - i] = get_type (e); if (e->type == ex_error) From bd6dcafdc89c1a3c1ab7a41931838b784d17f913 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 02:31:16 +0900 Subject: [PATCH 004/444] Replace system defines/includes with qfcc's Right now, it probably works only with modern gcc. --- config.d/qfcc.m4 | 2 +- tools/qfcc/configure.in | 2 +- tools/qfcc/include/cpp.h | 2 ++ tools/qfcc/source/cpp.c | 46 +++++++++++++++++++++++++++++++++---- tools/qfcc/source/options.c | 5 +++- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/config.d/qfcc.m4 b/config.d/qfcc.m4 index 3e1d87ae7..380e6a31c 100644 --- a/config.d/qfcc.m4 +++ b/config.d/qfcc.m4 @@ -9,7 +9,7 @@ AC_ARG_WITH(cpp, if test "x$cpp_name" != xauto; then CPP_NAME="$cpp_name" else - CPP_NAME="cpp %d -o %o %i" + CPP_NAME="cpp %u %d %s -o %o %i" case "$host_os" in *freebsd*) CPP_NAME="cpp %d %i %o" diff --git a/tools/qfcc/configure.in b/tools/qfcc/configure.in index 21934d623..3c6383d5a 100644 --- a/tools/qfcc/configure.in +++ b/tools/qfcc/configure.in @@ -30,7 +30,7 @@ AC_ARG_WITH(cpp, if test "x$cpp_name" != xauto; then CPP_NAME="$cpp_name" else - CPP_NAME="cpp %d -o %o %i" + CPP_NAME="cpp %u %d %s -o %o %i" case "$target_os" in *bsd*) touch conftest.c diff --git a/tools/qfcc/include/cpp.h b/tools/qfcc/include/cpp.h index 6b599b439..81274c353 100644 --- a/tools/qfcc/include/cpp.h +++ b/tools/qfcc/include/cpp.h @@ -34,6 +34,8 @@ struct dstring_s; void parse_cpp_name (void); +void add_cpp_sysinc (const char *arg); +void add_cpp_undef (const char *arg); void add_cpp_def (const char *arg); void intermediate_file (struct dstring_s *ifile, const char *filename, const char *ext, int local); diff --git a/tools/qfcc/source/cpp.c b/tools/qfcc/source/cpp.c index 7e8affb49..71b42c6d1 100644 --- a/tools/qfcc/source/cpp.c +++ b/tools/qfcc/source/cpp.c @@ -67,11 +67,25 @@ cpp_arg_t *cpp_arg_list; cpp_arg_t **cpp_arg_tail = &cpp_arg_list; cpp_arg_t *cpp_def_list; cpp_arg_t **cpp_def_tail = &cpp_def_list; +cpp_arg_t *cpp_undef_list; +cpp_arg_t **cpp_undef_tail = &cpp_undef_list; +cpp_arg_t *cpp_sysinc_list; +cpp_arg_t **cpp_sysinc_tail = &cpp_sysinc_list; const char **cpp_argv; const char *cpp_name = CPP_NAME; static int cpp_argc = 0; dstring_t *tempname; +static const char ** +append_cpp_args (const char **arg, cpp_arg_t *arg_list) +{ + cpp_arg_t *cpp_arg; + + for (cpp_arg = arg_list; cpp_arg; cpp_arg = cpp_arg->next) + *arg++ = cpp_arg->arg; + return arg; +} + static void add_cpp_arg (const char *arg) { @@ -83,6 +97,28 @@ add_cpp_arg (const char *arg) cpp_argc++; } +void +add_cpp_sysinc (const char *arg) +{ + cpp_arg_t *cpp_arg = malloc (sizeof (cpp_arg_t)); + cpp_arg->next = 0; + cpp_arg->arg = arg; + *cpp_sysinc_tail = cpp_arg; + cpp_sysinc_tail = &(*cpp_sysinc_tail)->next; + cpp_argc++; +} + +void +add_cpp_undef (const char *arg) +{ + cpp_arg_t *cpp_arg = malloc (sizeof (cpp_arg_t)); + cpp_arg->next = 0; + cpp_arg->arg = arg; + *cpp_undef_tail = cpp_arg; + cpp_undef_tail = &(*cpp_undef_tail)->next; + cpp_argc++; +} + void add_cpp_def (const char *arg) { @@ -117,7 +153,6 @@ static void build_cpp_args (const char *in_name, const char *out_name) { cpp_arg_t *cpp_arg; - cpp_arg_t *cpp_def; const char **arg; if (cpp_argv) @@ -126,9 +161,12 @@ build_cpp_args (const char *in_name, const char *out_name) for (arg = cpp_argv, cpp_arg = cpp_arg_list; cpp_arg; cpp_arg = cpp_arg->next) { - if (!strcmp (cpp_arg->arg, "%d")) { - for (cpp_def = cpp_def_list; cpp_def; cpp_def = cpp_def->next) - *arg++ = cpp_def->arg; + if (!strcmp (cpp_arg->arg, "%u")) { + arg = append_cpp_args (arg, cpp_undef_list); + } else if (!strcmp (cpp_arg->arg, "%s")) { + arg = append_cpp_args (arg, cpp_sysinc_list); + } else if (!strcmp (cpp_arg->arg, "%d")) { + arg = append_cpp_args (arg, cpp_def_list); } else if (!strcmp (cpp_arg->arg, "%i")) { *arg++ = in_name; } else if (!strcmp (cpp_arg->arg, "%o")) { diff --git a/tools/qfcc/source/options.c b/tools/qfcc/source/options.c index cfd1e27bf..c3f283e89 100644 --- a/tools/qfcc/source/options.c +++ b/tools/qfcc/source/options.c @@ -299,6 +299,8 @@ DecodeArgs (int argc, char **argv) int c; int saw_E = 0, saw_MD = 0; + add_cpp_undef ("-undef"); + add_cpp_undef ("-nostdinc"); add_cpp_def ("-D__QFCC__=1"); add_cpp_def ("-D__QUAKEC__=1"); @@ -720,7 +722,8 @@ DecodeArgs (int argc, char **argv) // add the default paths if (!options.no_default_paths) { - add_cpp_def (nva ("-I%s", QFCC_INCLUDE_PATH)); + add_cpp_sysinc ("-isystem"); + add_cpp_sysinc (QFCC_INCLUDE_PATH); linker_add_path (QFCC_LIB_PATH); } From a65d6bce09d08fdc1d33f56eb21033dc321684d5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 02:43:27 +0900 Subject: [PATCH 005/444] Fix a warning that got through I forgot to compile test in optimized... --- tools/qfcc/source/function.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 4d3a617e9..538bb8f65 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -155,7 +155,7 @@ parse_params (type_t *type, param_t *parms) { param_t *p; type_t *new; - int count; + int count = 0; new = new_type (); new->type = ev_func; @@ -168,7 +168,9 @@ parse_params (type_t *type, param_t *parms) count++; } } - new->t.func.param_types = malloc (count * sizeof (type_t)); + if (count) { + new->t.func.param_types = malloc (count * sizeof (type_t)); + } for (p = parms; p; p = p->next) { if (!p->selector && !p->type && !p->name) { if (p->next) From 4c40928112099d7c736a6b5819d0dc84411fde11 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 02:53:38 +0900 Subject: [PATCH 006/444] Remove what appears to be a redundant check It was long wrong anyway as it checked past the end of the function's parameters, which caused a segfault when calling varargs functions with no formal parameters. --- tools/qfcc/source/expr.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 7d7e55a21..03e3ddc6a 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1892,11 +1892,6 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) if (type_size (t) > type_size (&type_param)) err = error (e, "formal parameter %d is too large to be passed by" " value", i + 1); - if (ftype->t.func.param_types[i] == &type_float - && is_integer_val (e)) { - convert_int (e); - t = &type_float; - } if (i < parm_count) { if (e->type == ex_nil) convert_nil (e, t = ftype->t.func.param_types[i]); @@ -1934,7 +1929,8 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) for (e = params, i = 0; e; e = e->next, i++) { if (has_function_call (e)) { *a = new_temp_def_expr (arg_types[i]); - arg_exprs[arg_expr_count][0] = cast_expr (arg_types[i], convert_vector (e)); + arg_exprs[arg_expr_count][0] = cast_expr (arg_types[i], + convert_vector (e)); arg_exprs[arg_expr_count][1] = *a; arg_expr_count++; } else { From 67e183c8b65cad0745c063f5e830a9a45552ea1b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 10:46:16 +0900 Subject: [PATCH 007/444] Put the guts of qwaq's reflection code into ruamoko --- ruamoko/include/Makefile.am | 2 +- ruamoko/include/types.h | 84 +++++++++++++++++++++++++++++++++++++ ruamoko/lib/Makefile.am | 2 +- ruamoko/lib/types.r | 28 +++++++++++++ tools/qwaq/types.r | 2 + 5 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 ruamoko/include/types.h create mode 100644 ruamoko/lib/types.r diff --git a/ruamoko/include/Makefile.am b/ruamoko/include/Makefile.am index d978b3a70..b11080d13 100644 --- a/ruamoko/include/Makefile.am +++ b/ruamoko/include/Makefile.am @@ -3,7 +3,7 @@ pkgincludedir= $(datarootdir)/qfcc/include nobase_pkginclude_HEADERS= \ crudefile.h debug.h entities.h infokey.h math.h message.h nq_message.h \ physics.h msgbuf.h qfile.h qfs.h qw_message.h qw_physics.h qw_sys.h \ - server.h sound.h script.h string.h sv_sound.h system.h \ + server.h sound.h script.h string.h sv_sound.h system.h types.h \ \ draw.h key.h \ \ diff --git a/ruamoko/include/types.h b/ruamoko/include/types.h new file mode 100644 index 000000000..8ff66e10c --- /dev/null +++ b/ruamoko/include/types.h @@ -0,0 +1,84 @@ +#ifndef __types_h +#define __types_h + +typedef enum { + ev_void, + ev_string, + ev_float, + ev_vector, + ev_entity, + ev_field, + ev_func, + ev_pointer, // end of v6 types + ev_quat, + ev_integer, + ev_uinteger, + ev_short, // value is embedded in the opcode + ev_double, + + ev_invalid, // invalid type. used for instruction checking + ev_type_count // not a type, gives number of types +} etype_t; + +typedef enum { + ty_none, ///< func/field/pointer or not used + ty_struct, + ty_union, + ty_enum, + ty_array, + ty_class, +} ty_meta_e; + +typedef struct qfot_fldptr_s { + etype_t type; + struct qfot_type_s *aux_type; +} qfot_fldptr_t; + +typedef struct qfot_func_s { + etype_t type; + struct qfot_type_s *return_type; + int num_params; + struct qfot_type_s *param_types[1]; +} qfot_func_t; + +typedef struct qfot_var_s { + struct qfot_type_s *type; + string name; + int offset; // value for enum, 0 for union +} qfot_var_t; + +typedef struct qfot_struct_s { + string tag; + int num_fields; + qfot_var_t fields[1]; +} qfot_struct_t; + +typedef struct qfot_array_s { + struct qfot_type_s *type; + int base; + int size; +} qfot_array_t; + +typedef struct qfot_type_s { + ty_meta_e meta; + int size; + string encoding; + union { + etype_t type; + qfot_fldptr_t fldptr; + qfot_func_t func; + qfot_struct_t strct; + qfot_array_t array; + string class; + } t; +} qfot_type_t; + +typedef struct qfot_type_encodings_s { + qfot_type_t *types; + int size; +} qfot_type_encodings_t; + +@extern string ty_meta_name[6]; +@extern string pr_type_name[ev_type_count]; + +#endif diff --git a/ruamoko/lib/Makefile.am b/ruamoko/lib/Makefile.am index 53a20875b..e4b475d64 100644 --- a/ruamoko/lib/Makefile.am +++ b/ruamoko/lib/Makefile.am @@ -27,7 +27,7 @@ SUFFIXES= .o .r .qc libr_a_SOURCES=\ cbuf.r cmd.r cvar.r file.r hash.r msgbuf.r plist.r qfile.r qfs.r script.r \ - sound.r string.r math.r \ + sound.r string.r math.r types.r \ Object.r Protocol.r \ AutoreleasePool.r Array.r Array+Private.r Entity.r PropertyList.r Set.r libr_a_AR=$(PAK) -cf diff --git a/ruamoko/lib/types.r b/ruamoko/lib/types.r new file mode 100644 index 000000000..66140b83f --- /dev/null +++ b/ruamoko/lib/types.r @@ -0,0 +1,28 @@ +#include +#include + +string ty_meta_name[6] = { + "basic", + "struct", + "union", + "enum", + "array", + "class", +}; + +string pr_type_name[ev_type_count] = { + "void", + "string", + "float", + "vector", + "entity", + "field", + "function", + "pointer", + "quaternion", + "integer", + "uinteger", + "short", + "double" + "invalid", +}; diff --git a/tools/qwaq/types.r b/tools/qwaq/types.r index 82665e20a..324185b93 100644 --- a/tools/qwaq/types.r +++ b/tools/qwaq/types.r @@ -12,6 +12,7 @@ typedef enum { ev_integer, ev_uinteger, ev_short, // value is embedded in the opcode + ev_double, ev_invalid, // invalid type. used for instruction checking ev_type_count // not a type, gives number of types @@ -107,6 +108,7 @@ string pr_type_name[ev_type_count] = { "integer", "uinteger", "short", + "double" "invalid", }; From 7a315b4a893393709e0cba381f889ccafaaee798 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 10:50:15 +0900 Subject: [PATCH 008/444] Fix storage class for for-loop declarations Getting "i redeclared" when i was declared in a for loop in two different functions was a tad unexpected. --- tools/qfcc/source/qc-parse.y | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index a2bbf1c03..a71563abb 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -153,7 +153,7 @@ int yylex (void); %token PROTECTED PROTOCOL PUBLIC SELECTOR REFERENCE SELF THIS %type optional_specifiers specifiers local_specifiers -%type storage_class save_storage +%type storage_class save_storage set_spec_storage %type type_specifier type_specifier_or_storage_class %type type @@ -349,6 +349,14 @@ save_storage } ; +set_spec_storage + : /* emtpy */ + { + $$ = $0; + $$.storage = current_storage; + } + ; + function_body : optional_state_expr { @@ -1229,7 +1237,7 @@ switch_block opt_init : cexpr - | type init_var_decl_list { $$ = $2; } + | type set_spec_storage init_var_decl_list { $$ = $3; } | /* empty */ { $$ = 0; From a6f3e1753a1376a4ffead4b943d39fe6a8b229e0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 12:58:55 +0900 Subject: [PATCH 009/444] Fix ruamoko's hashtab_t typedef Being typedefed directly to a pointer is a holdover from when pointer declarations were really awkward. --- ruamoko/include/hash.h | 32 ++++++++++++++++---------------- ruamoko/lib/hash.r | 30 +++++++++++++++--------------- ruamoko/scheme/Machine.h | 2 +- ruamoko/scheme/Symbol.r | 2 +- 4 files changed, 33 insertions(+), 33 deletions(-) diff --git a/ruamoko/include/hash.h b/ruamoko/include/hash.h index 8c07169aa..2d0aa80fc 100644 --- a/ruamoko/include/hash.h +++ b/ruamoko/include/hash.h @@ -1,24 +1,24 @@ #ifndef __ruamoko_hash_h #define __ruamoko_hash_h -typedef struct _hashtab_t *hashtab_t; +typedef struct _hashtab_t hashtab_t; -@extern hashtab_t Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud); -@extern void Hash_SetHashCompare (hashtab_t tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)); -@extern void Hash_DelTable (hashtab_t tab); -@extern void Hash_FlushTable (hashtab_t tab); -@extern int Hash_Add (hashtab_t tab, void *ele); -@extern int Hash_AddElement (hashtab_t tab, void *ele); -@extern void *Hash_Find (hashtab_t tab, string key); -@extern void *Hash_FindElement (hashtab_t tab, void *ele); -@extern void **Hash_FindList (hashtab_t tab, string key); -@extern void **Hash_FindElementList (hashtab_t tab, void *ele); -@extern void *Hash_Del (hashtab_t tab, string key); -@extern void *Hash_DelElement (hashtab_t tab, void *ele); -@extern void Hash_Free (hashtab_t tab, void *ele); +@extern hashtab_t *Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud); +@extern void Hash_SetHashCompare (hashtab_t *tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)); +@extern void Hash_DelTable (hashtab_t *tab); +@extern void Hash_FlushTable (hashtab_t *tab); +@extern int Hash_Add (hashtab_t *tab, void *ele); +@extern int Hash_AddElement (hashtab_t *tab, void *ele); +@extern void *Hash_Find (hashtab_t *tab, string key); +@extern void *Hash_FindElement (hashtab_t *tab, void *ele); +@extern void **Hash_FindList (hashtab_t *tab, string key); +@extern void **Hash_FindElementList (hashtab_t *tab, void *ele); +@extern void *Hash_Del (hashtab_t *tab, string key); +@extern void *Hash_DelElement (hashtab_t *tab, void *ele); +@extern void Hash_Free (hashtab_t *tab, void *ele); @extern int Hash_String (string str); @extern int Hash_Buffer (void *buf, int len); -@extern void **Hash_GetList (hashtab_t tab); -@extern void Hash_Stats (hashtab_t tab); +@extern void **Hash_GetList (hashtab_t *tab); +@extern void Hash_Stats (hashtab_t *tab); #endif // __ruamoko_hash_h diff --git a/ruamoko/lib/hash.r b/ruamoko/lib/hash.r index 24844bfc2..a70d59b10 100644 --- a/ruamoko/lib/hash.r +++ b/ruamoko/lib/hash.r @@ -1,19 +1,19 @@ #include "hash.h" -hashtab_t Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud) = #0; -void Hash_SetHashCompare (hashtab_t tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)) = #0; -void Hash_DelTable (hashtab_t tab) = #0; -void Hash_FlushTable (hashtab_t tab) = #0; -int Hash_Add (hashtab_t tab, void *ele) = #0; -int Hash_AddElement (hashtab_t tab, void *ele) = #0; -void *Hash_Find (hashtab_t tab, string key) = #0; -void *Hash_FindElement (hashtab_t tab, void *ele) = #0; -void **Hash_FindList (hashtab_t tab, string key) = #0; -void **Hash_FindElementList (hashtab_t tab, void *ele) = #0; -void *Hash_Del (hashtab_t tab, string key) = #0; -void *Hash_DelElement (hashtab_t tab, void *ele) = #0; -void Hash_Free (hashtab_t tab, void *ele) = #0; +hashtab_t *Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud) = #0; +void Hash_SetHashCompare (hashtab_t *tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)) = #0; +void Hash_DelTable (hashtab_t *tab) = #0; +void Hash_FlushTable (hashtab_t *tab) = #0; +int Hash_Add (hashtab_t *tab, void *ele) = #0; +int Hash_AddElement (hashtab_t *tab, void *ele) = #0; +void *Hash_Find (hashtab_t *tab, string key) = #0; +void *Hash_FindElement (hashtab_t *tab, void *ele) = #0; +void **Hash_FindList (hashtab_t *tab, string key) = #0; +void **Hash_FindElementList (hashtab_t *tab, void *ele) = #0; +void *Hash_Del (hashtab_t *tab, string key) = #0; +void *Hash_DelElement (hashtab_t *tab, void *ele) = #0; +void Hash_Free (hashtab_t *tab, void *ele) = #0; int Hash_String (string str) = #0; int Hash_Buffer (void *buf, int len) = #0; -void **Hash_GetList (hashtab_t tab) = #0; -void Hash_Stats (hashtab_t tab) = #0; +void **Hash_GetList (hashtab_t *tab) = #0; +void Hash_Stats (hashtab_t *tab) = #0; diff --git a/ruamoko/scheme/Machine.h b/ruamoko/scheme/Machine.h index 7c99a2433..a7da59f61 100644 --- a/ruamoko/scheme/Machine.h +++ b/ruamoko/scheme/Machine.h @@ -11,7 +11,7 @@ { state_t state; SchemeObject *value; - hashtab_t globals; + hashtab_t *globals; SchemeObject *all_globals; } - (void) loadCode: (CompiledCode *) code; diff --git a/ruamoko/scheme/Symbol.r b/ruamoko/scheme/Symbol.r index 0704b3a50..b83f3dbd6 100644 --- a/ruamoko/scheme/Symbol.r +++ b/ruamoko/scheme/Symbol.r @@ -16,7 +16,7 @@ void SymbolFree (void *ele, void *data) [s release]; } -hashtab_t symbols; +hashtab_t *symbols; Symbol *lparen; Symbol *rparen; Symbol *quote; From b00c866c4e32d109de7c2dc683eff4f3c4e0378f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 13:00:36 +0900 Subject: [PATCH 010/444] Allow casting between string and pointer types --- tools/qfcc/include/type.h | 1 + tools/qfcc/source/expr.c | 5 +++++ tools/qfcc/source/type.c | 8 ++++++++ 3 files changed, 14 insertions(+) diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index fcb4a808a..33d283462 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -166,6 +166,7 @@ int is_field (const type_t *type) __attribute__((pure)); int is_struct (const type_t *type) __attribute__((pure)); int is_array (const type_t *type) __attribute__((pure)); int is_func (const type_t *type) __attribute__((pure)); +int is_string (const type_t *type) __attribute__((pure)); int type_compatible (const type_t *dst, const type_t *src) __attribute__((pure)); int type_assignable (const type_t *dst, const type_t *src); int type_size (const type_t *type) __attribute__((pure)); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 03e3ddc6a..691a03162 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2595,6 +2595,11 @@ cast_expr (type_t *type, expr_t *e) if ((type == type_default && is_enum (e_type)) || (is_enum (type) && e_type == type_default)) return e; + if ((is_pointer (type) && is_string (e_type)) + || (is_string (type) && is_pointer (e_type))) { + c = new_alias_expr (type, e); + return c; + } if (!(type->type == ev_pointer && (e_type->type == ev_pointer || is_integral (e_type) || is_array (e_type))) diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 289b76563..c0d5b58e3 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -785,6 +785,14 @@ is_func (const type_t *type) return 0; } +int +is_string (const type_t *type) +{ + if (type->type == ev_string) + return 1; + return 0; +} + int type_compatible (const type_t *dst, const type_t *src) { From 2db5d04e3f5cfdd76e2cf3ab0214f3cae7e52caf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 14:40:01 +0900 Subject: [PATCH 011/444] Reduce the ephemeral nature of str_mid When the substring is the tail of the supplied string, return a "pointer" to within the supplied string rather than a new "return" string. This means that tail-end substrings of string constants are themselves constants. --- libs/ruamoko/rua_string.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/ruamoko/rua_string.c b/libs/ruamoko/rua_string.c index 7f233e362..fcd78c1cc 100644 --- a/libs/ruamoko/rua_string.c +++ b/libs/ruamoko/rua_string.c @@ -112,6 +112,10 @@ bi_str_mid (progs_t *pr) end = size; if (pos < 0 || pos >= size || end <= pos) return; + if (end == size) { + R_STRING (pr) = str + pos - pr->pr_strings; + return; + } temp = alloca (end - pos + 1); strncpy (temp, str + pos, end - pos); temp[end - pos] = 0; From adb7f5d601b793a077b033cef3d4b4340f6d06de Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 16:21:55 +0900 Subject: [PATCH 012/444] Quieten the test script build rules --- tools/qfcc/test/Makefile.am | 78 ++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index d9d66090a..fd2603f61 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -104,7 +104,7 @@ address_cast_obj=$(address_cast_dat_SOURCES:.r=.qfo) address-cast.dat$(EXEEXT): $(address_cast_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(address_cast_obj) address-cast.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/address-cast.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/address-cast.Qo @@ -113,7 +113,7 @@ alignment_obj=$(alignment_dat_SOURCES:.r=.qfo) alignment.dat$(EXEEXT): $(alignment_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(alignment_obj) alignment.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/alignment.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/alignment.Qo @@ -122,7 +122,7 @@ chewed_alias_obj=$(chewed_alias_dat_SOURCES:.r=.qfo) chewed-alias.dat$(EXEEXT): $(chewed_alias_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(chewed_alias_obj) chewed-alias.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/chewed-alias.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/chewed-alias.Qo @@ -131,7 +131,7 @@ chewed_return_obj=$(chewed_return_dat_SOURCES:.r=.qfo) chewed-return.dat$(EXEEXT): $(chewed_return_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(chewed_return_obj) chewed-return.run: Makefile build-run - TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ + @TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ include ./$(DEPDIR)/chewed-return.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/chewed-return.Qo @@ -140,7 +140,7 @@ comma_expr_obj=$(comma_expr_dat_SOURCES:.r=.qfo) comma-expr.dat$(EXEEXT): $(comma_expr_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(comma_expr_obj) comma-expr.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/comma-expr.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/comma-expr.Qo @@ -149,7 +149,7 @@ deadbool_obj=$(deadbool_dat_SOURCES:.r=.qfo) deadbool.dat$(EXEEXT): $(deadbool_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(deadbool_obj) deadbool.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/deadbool.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/deadbool.Qo @@ -158,46 +158,46 @@ double_obj=$(double_dat_SOURCES:.r=.qfo) double.dat$(EXEEXT): $(double_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(double_obj) double.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/double.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/double.Qo double-demote-int.run$(EXEEXT): double-demote-int.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-float.run$(EXEEXT): double-demote-float.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-int-ainit.run$(EXEEXT): double-demote-int-ainit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-float-ainit.run$(EXEEXT): double-demote-float-ainit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-int-ginit.run$(EXEEXT): double-demote-int-ginit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-float-ginit.run$(EXEEXT): double-demote-float-ginit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-int-linit.run$(EXEEXT): double-demote-int-linit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-demote-float-linit.run$(EXEEXT): double-demote-float-linit.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-int-compare.run$(EXEEXT): double-int-compare.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< double-float-compare.run$(EXEEXT): double-float-compare.r Makefile build-compile-fail-run - $(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< + @$(srcdir)/build-compile-fail-run $@ $(QFCC) $(QCFLAGS) $< enum_dat_SOURCES=enum.r enum_obj=$(enum_dat_SOURCES:.r=.qfo) enum.dat$(EXEEXT): $(enum_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(enum_obj) enum.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/enum.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/enum.Qo @@ -206,7 +206,7 @@ fordecl_obj=$(fordecl_dat_SOURCES:.r=.qfo) fordecl.dat$(EXEEXT): $(fordecl_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(fordecl_obj) fordecl.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/fordecl.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/fordecl.Qo @@ -215,7 +215,7 @@ func_expr_obj=$(func_expr_dat_SOURCES:.r=.qfo) func-expr.dat$(EXEEXT): $(func_expr_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(func_expr_obj) func-expr.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/func-expr.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/func-expr.Qo @@ -224,7 +224,7 @@ func_static_obj=$(func_static_dat_SOURCES:.r=.qfo) func-static.dat$(EXEEXT): $(func_static_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(func_static_obj) func-static.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/func-static.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/func-static.Qo @@ -233,7 +233,7 @@ infloop_obj=$(infloop_dat_SOURCES:.r=.qfo) infloop.dat$(EXEEXT): $(infloop_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(infloop_obj) infloop.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/infloop.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/infloop.Qo @@ -242,7 +242,7 @@ ivar_struct_return_obj=$(ivar_struct_return_dat_SOURCES:.r=.qfo) ivar-struct-return.dat$(EXEEXT): $(ivar_struct_return_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(ivar_struct_return_obj) ivar-struct-return.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/ivar-struct-return.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/ivar-struct-return.Qo @@ -251,7 +251,7 @@ modulo_obj=$(modulo_dat_SOURCES:.r=.qfo) modulo.dat$(EXEEXT): $(modulo_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(modulo_obj) modulo.run: Makefile build-run - TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ + @TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ include ./$(DEPDIR)/modulo.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/modulo.Qo @@ -260,7 +260,7 @@ paramret_obj=$(paramret_dat_SOURCES:.r=.qfo) paramret.dat$(EXEEXT): $(paramret_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(paramret_obj) paramret.run: Makefile build-run - TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ + @TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ include ./$(DEPDIR)/paramret.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/paramret.Qo @@ -269,7 +269,7 @@ quaternion_obj=$(quaternion_dat_SOURCES:.r=.qfo) quaternion.dat$(EXEEXT): $(quaternion_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(quaternion_obj) quaternion.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/quaternion.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/quaternion.Qo @@ -278,7 +278,7 @@ return_ivar_obj=$(return_ivar_dat_SOURCES:.r=.qfo) return-ivar.dat$(EXEEXT): $(return_ivar_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(return_ivar_obj) return-ivar.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/return-ivar.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/return-ivar.Qo @@ -287,7 +287,7 @@ sendv_obj=$(sendv_dat_SOURCES:.r=.qfo) sendv.dat$(EXEEXT): $(sendv_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(sendv_obj) sendv.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/sendv.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/sendv.Qo @@ -296,7 +296,7 @@ state_obj=$(state_dat_SOURCES:.r=.qfo) state.dat$(EXEEXT): $(state_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(state_obj) state.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/state.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/state.Qo @@ -305,7 +305,7 @@ structarray_obj=$(structarray_dat_SOURCES:.r=.qfo) structarray.dat$(EXEEXT): $(structarray_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(structarray_obj) structarray.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/structarray.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/structarray.Qo @@ -314,7 +314,7 @@ structlive_obj=$(structlive_dat_SOURCES:.r=.qfo) structlive.dat$(EXEEXT): $(structlive_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(structlive_obj) structlive.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/structlive.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/structlive.Qo @@ -323,7 +323,7 @@ structptr_obj=$(structptr_dat_SOURCES:.r=.qfo) structptr.dat$(EXEEXT): $(structptr_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(structptr_obj) structptr.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/structptr.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/structptr.Qo @@ -332,7 +332,7 @@ structstruct_obj=$(structstruct_dat_SOURCES:.r=.qfo) structstruct.dat$(EXEEXT): $(structstruct_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(structstruct_obj) structstruct.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/structstruct.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/structstruct.Qo @@ -341,7 +341,7 @@ swap_obj=$(swap_dat_SOURCES:.r=.qfo) swap.dat$(EXEEXT): $(swap_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(swap_obj) swap.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/swap.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/swap.Qo @@ -350,7 +350,7 @@ triangle_obj=$(triangle_dat_SOURCES:.r=.qfo) triangle.dat$(EXEEXT): $(triangle_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(triangle_obj) triangle.run: Makefile build-run - $(srcdir)/build-run $@ 100000 100000 1.00005 50002.4961 + @$(srcdir)/build-run $@ 100000 100000 1.00005 50002.4961 include ./$(DEPDIR)/triangle.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/triangle.Qo @@ -359,7 +359,7 @@ vecexpr_obj=$(vecexpr_dat_SOURCES:.r=.qfo) vecexpr.dat$(EXEEXT): $(vecexpr_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(vecexpr_obj) vecexpr.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/vecexpr.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/vecexpr.Qo @@ -368,7 +368,7 @@ vecinit_obj=$(vecinit_dat_SOURCES:.r=.qfo) vecinit.dat$(EXEEXT): $(vecinit_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(vecinit_obj) vecinit.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/vecinit.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/vecinit.Qo @@ -377,7 +377,7 @@ voidfor_obj=$(voidfor_dat_SOURCES:.r=.qfo) voidfor.dat$(EXEEXT): $(voidfor_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(voidfor_obj) voidfor.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/voidfor.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/voidfor.Qo @@ -386,7 +386,7 @@ while_obj=$(while_dat_SOURCES:.r=.qfo) while.dat$(EXEEXT): $(while_obj) $(QFCC_DEP) $(QFCC) $(QCFLAGS) -o $@ $(while_obj) while.run: Makefile build-run - $(srcdir)/build-run $@ + @$(srcdir)/build-run $@ include ./$(DEPDIR)/while.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/while.Qo From 2f18364364ee1340b8108ddee315c288ccde2978 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 17:05:25 +0900 Subject: [PATCH 013/444] Start work on encoding typedef chains --- include/QF/pr_type.h | 7 ++++ ruamoko/include/types.h | 8 +++++ tools/qfcc/include/type.h | 6 ++++ tools/qfcc/source/dump_globals.c | 4 +++ tools/qfcc/source/obj_file.c | 6 ++++ tools/qfcc/source/type.c | 15 ++++++++ tools/qfcc/test/Makefile.am | 14 ++++++-- tools/qfcc/test/typedef.r | 62 ++++++++++++++++++++++++++++++++ 8 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 tools/qfcc/test/typedef.r diff --git a/include/QF/pr_type.h b/include/QF/pr_type.h index 0c8b37664..0e33b0fd6 100644 --- a/include/QF/pr_type.h +++ b/include/QF/pr_type.h @@ -40,6 +40,12 @@ #include "QF/pr_comp.h" +typedef struct qfot_alias_s { + pr_int_t type; ///< type at end of alias chain + pointer_t aux_type; ///< referenced type + string_t name; ///< alias name +} qfot_alias_t; + typedef struct qfot_fldptr_s { pr_int_t type; ///< ev_field or ev_pointer pointer_t aux_type; ///< referenced type @@ -94,6 +100,7 @@ typedef struct qfot_type_s { qfot_struct_t strct; ///< ty_struct/ty_union/ty_enum qfot_array_t array; ///< ty_array pointer_t class; ///< ty_class + qfot_alias_t alias; ///< ty_alias } t; } qfot_type_t; diff --git a/ruamoko/include/types.h b/ruamoko/include/types.h index 8ff66e10c..deb480ebf 100644 --- a/ruamoko/include/types.h +++ b/ruamoko/include/types.h @@ -27,8 +27,15 @@ typedef enum { ty_enum, ty_array, ty_class, + ty_alias, } ty_meta_e; +typedef struct qfot_alias_s { + etype_t type; + struct qfot_type_s *aux_type; + string name; +} qfot_alias_t; + typedef struct qfot_fldptr_s { etype_t type; struct qfot_type_s *aux_type; @@ -70,6 +77,7 @@ typedef struct qfot_type_s { qfot_struct_t strct; qfot_array_t array; string class; + qfot_alias_t alias; } t; } qfot_type_t; diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 33d283462..45aecd293 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -51,6 +51,10 @@ typedef struct ty_array_s { int size; } ty_array_t; +typedef struct ty_alias_s { + struct type_s *type; +} ty_alias_t; + typedef enum { ty_none, ///< func/field/pointer or not used ty_struct, @@ -58,6 +62,7 @@ typedef enum { ty_enum, ty_array, ty_class, + ty_alias, } ty_meta_e; typedef struct type_s { @@ -72,6 +77,7 @@ typedef struct type_s { ty_array_t array; struct symtab_s *symtab; struct class_s *class; + ty_alias_t alias; } t; struct type_s *next; int freeable; diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 9e0b5bd5f..d77f5af32 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -493,6 +493,10 @@ dump_qfo_types (qfo_t *qfo, int base_address) printf (" %-5x %d %d\n", type->t.array.type, type->t.array.base, type->t.array.size); break; + case ty_alias: + printf (" %s %-5x\n", QFO_GETSTR (qfo, type->t.alias.name), + type->t.alias.type); + break; case ty_class: printf (" %-5x\n", type->t.class); break; diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 44148eec8..e49d64c46 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -648,8 +648,10 @@ get_def_type (qfo_t *qfo, pointer_t type) type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { case ty_none: + case ty_alias: // field, pointer and function types store their basic type in // the same location. + // alias types store the basic type at the end of the alias chain return type_def->t.type; case ty_struct: case ty_union: @@ -674,9 +676,11 @@ get_type_size (qfo_t *qfo, pointer_t type) return 1; type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { + case ty_alias: case ty_none: // field, pointer and function types store their basic type in // the same location. + // alias types store the basic type at the end of the alias chain return pr_type_size[type_def->t.type]; case ty_struct: for (i = size = 0; i < type_def->t.strct.num_fields; i++) @@ -723,8 +727,10 @@ get_type_alignment_log (qfo_t *qfo, pointer_t type) type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { case ty_none: + case ty_alias: // field, pointer and function types store their basic type in // the same location. + // alias types store the basic type at the end of the alias chain return qfo_log2 (ev_types[type_def->t.type]->alignment); case ty_struct: case ty_union: diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index c0d5b58e3..5ffd2b7be 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -292,6 +292,8 @@ types_same (type_t *a, type_t *b) if (a->t.class != b->t.class) return 0; return compare_protocols (a->protos, b->protos); + case ty_alias: + return !strcmp (a->name, b->name); } internal_error (0, "we be broke"); } @@ -341,6 +343,9 @@ find_type (type_t *type) break; case ty_class: break; + case ty_alias: + type->t.alias.type = find_type (type->t.alias.type); + break; } } @@ -512,6 +517,11 @@ print_type_str (dstring_t *str, const type_t *type) dasprintf (str, "[%d]", type->t.array.size); } break; + case ty_alias: + dasprintf (str, "({%s=", type->name); + print_type_str (str, type->t.alias.type); + dstring_appendstr (str, "})"); + break; case ty_none: break; } @@ -671,6 +681,9 @@ encode_type (dstring_t *encoding, const type_t *type) encode_type (encoding, type->t.array.type); dasprintf (encoding, "]"); break; + case ty_alias: + encode_type (encoding, type->t.alias.type); + break; case ty_none: dasprintf (encoding, "?"); break; @@ -892,6 +905,8 @@ type_size (const type_t *type) } case ty_array: return type->t.array.size * type_size (type->t.array.type); + case ty_alias: + return type_size (type->t.alias.type); case ty_none: return 0; } diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index fd2603f61..e715b38ed 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -9,8 +9,8 @@ AM_CPPFLAGS= -I$(top_srcdir)/include $(QFCC_INCS) QFCC_DEP=$(builddir)/../source/qfcc$(EXEEXT) QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g --no-default-paths -Werror -QCPPFLAGS= +QCFLAGS=-qq -O -g -Werror +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) SUFFIXES=.qfo .r @@ -54,6 +54,7 @@ test_progs_dat=\ structstruct.dat \ swap.dat \ triangle.dat \ + typedef.dat \ vecexpr.dat \ vecinit.dat \ voidfor.dat \ @@ -354,6 +355,15 @@ triangle.run: Makefile build-run include ./$(DEPDIR)/triangle.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/triangle.Qo +typedef_dat_SOURCES=typedef.r +typedef_obj=$(typedef_dat_SOURCES:.r=.qfo) +typedef.dat$(EXEEXT): $(typedef_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(typedef_obj) +typedef.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/typedef.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/typedef.Qo + vecexpr_dat_SOURCES=vecexpr.r vecexpr_obj=$(vecexpr_dat_SOURCES:.r=.qfo) vecexpr.dat$(EXEEXT): $(vecexpr_obj) $(QFCC_DEP) diff --git a/tools/qfcc/test/typedef.r b/tools/qfcc/test/typedef.r new file mode 100644 index 000000000..48ea84478 --- /dev/null +++ b/tools/qfcc/test/typedef.r @@ -0,0 +1,62 @@ +#include + +// can't link against libr.a (may not be built) +void *PR_FindGlobal (string name) = #0; +void printf (string fmt, ...) = #0; + +qfot_type_encodings_t *encodings; + +typedef int *foo; +typedef int *bar; + +foo baz; +bar snafu; + +qfot_type_t * +next_type (qfot_type_t *type) +{ + int size = type.size; + if (!size) + size = 4; + return (qfot_type_t *) ((int *) type + size); +} + +int +main (void) +{ + int found_foo = 0; + int found_bar = 0; + qfot_type_t *type; + qfot_type_t *alias; + + baz = snafu; // must be able to assign without warnings (won't compile) + + encodings = PR_FindGlobal (".type_encodings"); + + for (type = encodings.types; + ((int *)type - (int *) encodings.types) < encodings.size; + type = next_type (type)) { + if (type.meta == ty_alias && type.t.alias.type == ev_integer) { + alias = type.t.alias.aux_type; + if (type.t.alias.name == "foo") { + if (alias.meta == ty_none && alias.t.type == ev_integer) { + found_foo = 1; + } else { + printf ("foo type not aliased to int\n"); + } + } + if (type.t.alias.name == "bar") { + if (alias.meta == ty_none && alias.t.type == ev_integer) { + found_bar = 1; + } else { + printf ("bar type not aliased to int\n"); + } + } + } + } + if (!(found_bar && found_foo)) { + printf ("missing typedef: foo: %d bar:%d\n", found_foo, found_bar); + return 1; + } + return 0; +} From a5aba6c8ac80dc680ba9f0e324cee01d397b0fc9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 18:11:43 +0900 Subject: [PATCH 014/444] Implement type aliasing The separate types are in the file, but there are multiple issues --- tools/qfcc/include/type.h | 6 ++++-- tools/qfcc/source/dump_globals.c | 1 + tools/qfcc/source/obj_type.c | 19 ++++++++++++++++++- tools/qfcc/source/qc-parse.y | 1 + tools/qfcc/source/type.c | 19 +++++++++++++++++++ 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 45aecd293..1efbfc21a 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -138,8 +138,9 @@ void chain_type (type_t *type); /** Append a type to the end of a type chain. - The type chain must be made up of only field, pointer, function and array - types, as other types do not have auxiliary type fields. + The type chain must be made up of only field, pointer, function, array + and alias (typedef) types, as other types do not have auxiliary type + fields. \param type The type chain to which the type will be appended. \param new The type to be appended. May be any type. @@ -153,6 +154,7 @@ type_t *field_type (type_t *aux); type_t *pointer_type (type_t *aux); type_t *array_type (type_t *aux, int size); type_t *based_array_type (type_t *aux, int base, int top); +type_t *alias_type (type_t *aux, const char *name); void print_type_str (struct dstring_s *str, const type_t *type); void print_type (const type_t *type); const char *encode_params (const type_t *type); diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index d77f5af32..7f4adbbc9 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -423,6 +423,7 @@ static const char *ty_meta_names[] = { "ty_enum", "ty_array", "ty_class", + "ty_alias", }; #define NUM_META ((int)(sizeof (ty_meta_names) / sizeof (ty_meta_names[0]))) diff --git a/tools/qfcc/source/obj_type.c b/tools/qfcc/source/obj_type.c index 55da5c137..e67f7a0b5 100644 --- a/tools/qfcc/source/obj_type.c +++ b/tools/qfcc/source/obj_type.c @@ -253,6 +253,22 @@ qfo_encode_class (type_t *type) return def; } +static def_t * +qfo_encode_alias (type_t *type) +{ + qfot_type_t *enc; + def_t *def; + def_t *alias_type_def; + + alias_type_def = qfo_encode_type (type->t.alias.type); + + def = qfo_new_encoding (type, sizeof (enc->t.alias)); + enc = D_POINTER (qfot_type_t, def); + ENC_DEF (enc->t.alias.type, alias_type_def); + ENC_STR (enc->t.alias.name, type->name); + return def; +} + def_t * qfo_encode_type (type_t *type) { @@ -265,6 +281,7 @@ qfo_encode_type (type_t *type) qfo_encode_struct, // ty_enum qfo_encode_array, // ty_array qfo_encode_class, // ty_class + qfo_encode_alias, // ty_alias }; if (type->type_def && type->type_def->external) { @@ -274,7 +291,7 @@ qfo_encode_type (type_t *type) } if (type->type_def) return type->type_def; - if (type->meta > ty_class) + if (type->meta > sizeof (funcs) / (sizeof (funcs[0]))) internal_error (0, "bad type meta type"); if (!type->encoding) type->encoding = type_get_encoding (type); diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index a71563abb..4773eb303 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -406,6 +406,7 @@ external_decl $1->type = find_type (append_type ($1->type, spec.type)); if (spec.is_typedef) { $1->sy_type = sy_type; + $1->type = alias_type ($1->type, $1->name); symtab_addsymbol (current_symtab, $1); } else { initialize_def ($1, 0, current_symtab->space, spec.storage); diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 5ffd2b7be..964d2d367 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -445,6 +445,25 @@ based_array_type (type_t *aux, int base, int top) return new; } +type_t * +alias_type (type_t *aux, const char *name) +{ + type_t _new; + type_t *new = &_new; + + if (!aux || !name) { + internal_error (0, "alias to null type or with no name"); + } + memset (&_new, 0, sizeof (_new)); + new->name = save_string (name); + new->meta = ty_alias; + new->type = aux->type; + new->alignment = aux->alignment; + new->t.alias.type = aux; + new = find_type (new); + return new; +} + void print_type_str (dstring_t *str, const type_t *type) { From d50a27a045a9fb7cbe6a15cd3557b88e5d75a4ba Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 18:28:11 +0900 Subject: [PATCH 015/444] Race down the alias chain before checking types This takes care of some of the type aliasing issues. --- tools/qfcc/include/type.h | 1 + tools/qfcc/source/type.c | 337 ++++++++++++++++++++------------------ 2 files changed, 182 insertions(+), 156 deletions(-) diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 1efbfc21a..098df5e00 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -160,6 +160,7 @@ void print_type (const type_t *type); const char *encode_params (const type_t *type); void encode_type (struct dstring_s *encoding, const type_t *type); const char *type_get_encoding (const type_t *type); +const type_t *unalias_type (const type_t *type) __attribute__((pure)); int is_void (const type_t *type) __attribute__((pure)); int is_enum (const type_t *type) __attribute__((pure)); int is_integral (const type_t *type) __attribute__((pure)); diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 964d2d367..2aff5c5d1 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -471,84 +471,95 @@ print_type_str (dstring_t *str, const type_t *type) dasprintf (str, " (null)"); return; } - switch (type->type) { - case ev_field: - dasprintf (str, ".("); - print_type_str (str, type->t.fldptr.type); - dasprintf (str, ")"); - break; - case ev_func: - print_type_str (str, type->t.func.type); - if (type->t.func.num_params == -1) { - dasprintf (str, "(...)"); + switch (type->meta) { + case ty_class: + dasprintf (str, " %s", type->t.class->name); + if (type->protos) + print_protocollist (str, type->protos); + return; + case ty_enum: + dasprintf (str, " enum %s", type->name); + return; + case ty_struct: + dasprintf (str, " struct %s", type->name); + return; + case ty_union: + dasprintf (str, " union %s", type->name); + return; + case ty_array: + print_type_str (str, type->t.array.type); + if (type->t.array.base) { + dasprintf (str, "[%d..%d]", type->t.array.base, + type->t.array.base + type->t.array.size - 1); } else { - int c, i; - dasprintf (str, "("); - if ((c = type->t.func.num_params) < 0) - c = ~c; // num_params is one's compliment - for (i = 0; i < c; i++) { - if (i) - dasprintf (str, ", "); - print_type_str (str, type->t.func.param_types[i]); - } - if (type->t.func.num_params < 0) - dasprintf (str, ", ..."); - dasprintf (str, ")"); + dasprintf (str, "[%d]", type->t.array.size); } - break; - case ev_pointer: - if (obj_is_id (type)) { - dasprintf (str, "id"); - if (type->t.fldptr.type->protos) - print_protocollist (str, type->t.fldptr.type->protos); - break; - } - if (type == &type_SEL) { - dasprintf (str, "SEL"); - break; - } - dasprintf (str, "(*"); - print_type_str (str, type->t.fldptr.type); - dasprintf (str, ")"); - break; - case ev_invalid: - switch (type->meta) { - case ty_class: - dasprintf (str, " %s", type->t.class->name); - if (type->protos) - print_protocollist (str, type->protos); - break; - case ty_enum: - dasprintf (str, " enum %s", type->name); - break; - case ty_struct: - dasprintf (str, " struct %s", type->name); - break; - case ty_union: - dasprintf (str, " union %s", type->name); - break; - case ty_array: - print_type_str (str, type->t.array.type); - if (type->t.array.base) { - dasprintf (str, "[%d..%d]", type->t.array.base, - type->t.array.base + type->t.array.size - 1); + return; + case ty_alias: + dasprintf (str, "({%s=", type->name); + print_type_str (str, type->t.alias.type); + dstring_appendstr (str, "})"); + return; + case ty_none: + switch (type->type) { + case ev_field: + dasprintf (str, ".("); + print_type_str (str, type->t.fldptr.type); + dasprintf (str, ")"); + return; + case ev_func: + print_type_str (str, type->t.func.type); + if (type->t.func.num_params == -1) { + dasprintf (str, "(...)"); } else { - dasprintf (str, "[%d]", type->t.array.size); + int c, i; + dasprintf (str, "("); + if ((c = type->t.func.num_params) < 0) + c = ~c; // num_params is one's compliment + for (i = 0; i < c; i++) { + if (i) + dasprintf (str, ", "); + print_type_str (str, type->t.func.param_types[i]); + } + if (type->t.func.num_params < 0) + dasprintf (str, ", ..."); + dasprintf (str, ")"); } - break; - case ty_alias: - dasprintf (str, "({%s=", type->name); - print_type_str (str, type->t.alias.type); - dstring_appendstr (str, "})"); - break; - case ty_none: + return; + case ev_pointer: + if (obj_is_id (type)) { + dasprintf (str, "id"); + if (type->t.fldptr.type->protos) + print_protocollist (str, type->t.fldptr.type->protos); + return; + } + if (type == &type_SEL) { + dasprintf (str, "SEL"); + return; + } + dasprintf (str, "(*"); + print_type_str (str, type->t.fldptr.type); + dasprintf (str, ")"); + return; + case ev_void: + case ev_string: + case ev_float: + case ev_vector: + case ev_entity: + case ev_quat: + case ev_integer: + case ev_uinteger: + case ev_short: + case ev_double: + dasprintf (str, " %s", pr_type_name[type->type]); + return; + case ev_invalid: + case ev_type_count: break; } break; - default: - dasprintf (str, " %s", pr_type_name[type->type]); - break; } + internal_error (0, "bad type meta:type %d:%d", type->meta, type->type); } void @@ -622,96 +633,103 @@ encode_type (dstring_t *encoding, const type_t *type) { if (!type) return; - switch (type->type) { - case ev_void: - dasprintf (encoding, "v"); - break; - case ev_string: - dasprintf (encoding, "*"); - break; - case ev_double: - dasprintf (encoding, "d"); - break; - case ev_float: - dasprintf (encoding, "f"); - break; - case ev_vector: - dasprintf (encoding, "V"); - break; - case ev_entity: - dasprintf (encoding, "E"); - break; - case ev_field: - dasprintf (encoding, "F"); - encode_type (encoding, type->t.fldptr.type); - break; - case ev_func: - dasprintf (encoding, "("); - encode_type (encoding, type->t.func.type); - dasprintf (encoding, "%s)", encode_params (type)); - break; - case ev_pointer: - if (type == &type_id) { - dasprintf (encoding, "@"); + switch (type->meta) { + case ty_class: + encode_class (encoding, type); + return; + case ty_enum: + encode_enum (encoding, type); + return; + case ty_struct: + case ty_union: + encode_struct (encoding, type); + return; + case ty_array: + dasprintf (encoding, "["); + dasprintf (encoding, "%d", type->t.array.size); + if (type->t.array.base) + dasprintf (encoding, ":%d", type->t.array.base); + dasprintf (encoding, "="); + encode_type (encoding, type->t.array.type); + dasprintf (encoding, "]"); + return; + case ty_alias: + encode_type (encoding, type->t.alias.type); + return; + case ty_none: + switch (type->type) { + case ev_void: + dasprintf (encoding, "v"); + return; + case ev_string: + dasprintf (encoding, "*"); + return; + case ev_double: + dasprintf (encoding, "d"); + return; + case ev_float: + dasprintf (encoding, "f"); + return; + case ev_vector: + dasprintf (encoding, "V"); + return; + case ev_entity: + dasprintf (encoding, "E"); + return; + case ev_field: + dasprintf (encoding, "F"); + encode_type (encoding, type->t.fldptr.type); + return; + case ev_func: + dasprintf (encoding, "("); + encode_type (encoding, type->t.func.type); + dasprintf (encoding, "%s)", encode_params (type)); + return; + case ev_pointer: + if (type == &type_id) { + dasprintf (encoding, "@"); + return; + } + if (type == &type_SEL) { + dasprintf (encoding, ":"); + return; + } + if (type == &type_Class) { + dasprintf (encoding, "#"); + return; + } + type = type->t.fldptr.type; + dasprintf (encoding, "^"); + encode_type (encoding, type); + return; + case ev_quat: + dasprintf (encoding, "Q"); + return; + case ev_integer: + dasprintf (encoding, "i"); + return; + case ev_uinteger: + dasprintf (encoding, "I"); + return; + case ev_short: + dasprintf (encoding, "s"); + return; + case ev_invalid: + case ev_type_count: break; } - if (type == &type_SEL) { - dasprintf (encoding, ":"); - break; - } - if (type == &type_Class) { - dasprintf (encoding, "#"); - break; - } - type = type->t.fldptr.type; - dasprintf (encoding, "^"); - encode_type (encoding, type); - break; - case ev_quat: - dasprintf (encoding, "Q"); - break; - case ev_integer: - dasprintf (encoding, "i"); - break; - case ev_uinteger: - dasprintf (encoding, "I"); - break; - case ev_short: - dasprintf (encoding, "s"); - break; - case ev_invalid: - switch (type->meta) { - case ty_class: - encode_class (encoding, type); - break; - case ty_enum: - encode_enum (encoding, type); - break; - case ty_struct: - case ty_union: - encode_struct (encoding, type); - break; - case ty_array: - dasprintf (encoding, "["); - dasprintf (encoding, "%d", type->t.array.size); - if (type->t.array.base) - dasprintf (encoding, ":%d", type->t.array.base); - dasprintf (encoding, "="); - encode_type (encoding, type->t.array.type); - dasprintf (encoding, "]"); - break; - case ty_alias: - encode_type (encoding, type->t.alias.type); - break; - case ty_none: - dasprintf (encoding, "?"); - break; - } - break; - case ev_type_count: - dasprintf (encoding, "?"); break; } + internal_error (0, "bad type meta:type %d:%d", type->meta, type->type); +} + +const type_t * +unalias_type (const type_t *type) +{ + while (type->meta == ty_alias) { + type = type->t.alias.type; + } + return type; } int @@ -723,6 +741,7 @@ is_void (const type_t *type) int is_enum (const type_t *type) { + type = unalias_type (type); if (type->type == ev_invalid && type->meta == ty_enum) return 1; return 0; @@ -779,6 +798,7 @@ is_math (const type_t *type) int is_struct (const type_t *type) { + type = unalias_type (type); if (type->type == ev_invalid && (type->meta == ty_struct || type->meta == ty_union)) return 1; @@ -804,6 +824,7 @@ is_field (const type_t *type) int is_array (const type_t *type) { + type = unalias_type (type); if (type->type == ev_invalid && type->meta == ty_array) return 1; return 0; @@ -828,6 +849,8 @@ is_string (const type_t *type) int type_compatible (const type_t *dst, const type_t *src) { + dst = unalias_type (dst); + src = unalias_type (src); // same type if (dst == src) { return 1; @@ -847,6 +870,8 @@ type_compatible (const type_t *dst, const type_t *src) int type_assignable (const type_t *dst, const type_t *src) { + dst = unalias_type (dst); + src = unalias_type (src); int ret; // same type From 9610788deac044bae7d8dd68762ae390a368c7e7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 19:16:07 +0900 Subject: [PATCH 016/444] Fix some more type aliasing issues Getting there... (I knew this would be a big job) --- tools/qfcc/source/expr.c | 8 ++++---- tools/qfcc/source/qc-parse.y | 2 ++ tools/qfcc/source/type.c | 7 +++++-- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 691a03162..da96bd5fc 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1138,9 +1138,9 @@ append_expr (expr_t *block, expr_t *e) } static symbol_t * -get_struct_field (type_t *t1, expr_t *e1, expr_t *e2) +get_struct_field (const type_t *t1, expr_t *e1, expr_t *e2) { - symtab_t *strct = t1->t.symtab; + symtab_t *strct = unalias_type (t1)->t.symtab; symbol_t *sym = e2->e.symbol;//FIXME need to check symbol_t *field; @@ -1159,12 +1159,12 @@ get_struct_field (type_t *t1, expr_t *e1, expr_t *e2) expr_t * field_expr (expr_t *e1, expr_t *e2) { - type_t *t1, *t2; + const type_t *t1, *t2; expr_t *e; if (e1->type == ex_error) return e1; - t1 = get_type (e1); + t1 = unalias_type (get_type (e1)); if (t1->type == ev_entity) { symbol_t *field = 0; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 4773eb303..e64bb748e 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -422,6 +422,7 @@ external_decl if (spec.is_typedef) { error (0, "typedef %s is initialized", $1->name); $1->sy_type = sy_type; + $1->type = alias_type ($1->type, $1->name); symtab_addsymbol (current_symtab, $1); } else { initialize_def ($1, $2, current_symtab->space, spec.storage); @@ -435,6 +436,7 @@ external_decl $1->type = find_type (append_type ($1->type, spec.type)); if (spec.is_typedef) { $1->sy_type = sy_type; + $1->type = alias_type ($1->type, $1->name); symtab_addsymbol (current_symtab, $1); } else { $1 = function_symbol ($1, spec.is_overload, 1); diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 2aff5c5d1..2c3064405 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -897,8 +897,11 @@ type_assignable (const type_t *dst, const type_t *src) if (ret >= 0) return ret; - dst = dst->t.fldptr.type; - src = src->t.fldptr.type; + dst = unalias_type (dst->t.fldptr.type); + src = unalias_type (src->t.fldptr.type); + if (dst == src) { + return 1; + } if (is_void (dst)) return 1; if (is_void (src)) From 6bcc2c49ab829fc370c7f783e79cedd72fdb7a20 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 20:52:27 +0900 Subject: [PATCH 017/444] Use helper functions for type checks They hide the evil details of aliased types. More to come :/ --- tools/qfcc/source/def.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 6e545ba40..7bef8790b 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -307,10 +307,9 @@ init_elements (struct def_s *def, expr_t *eles) elements[i].offset = base_offset + i * type_size (array_type); } num_elements = i; - } else if (is_struct (def->type) - || def->type == &type_vector - || def->type == &type_quaternion) { - symtab_t *symtab = def->type->t.symtab; + } else if (is_struct (def->type) || is_vector (def->type) + || is_quaternion (def->type)) { + symtab_t *symtab = unalias_type (def->type)->t.symtab; symbol_t *field; for (i = 0, field = symtab->symbols; field; field = field->next) { From 6bc803c72d31d37319c9be3adaae7ec4f8f7e662 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 20:53:50 +0900 Subject: [PATCH 018/444] Use correct encoding for alias types I got confused which field was which. --- tools/qfcc/source/dump_globals.c | 4 ++-- tools/qfcc/source/obj_type.c | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 7f4adbbc9..7d7d29f9e 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -495,8 +495,8 @@ dump_qfo_types (qfo_t *qfo, int base_address) type->t.array.base, type->t.array.size); break; case ty_alias: - printf (" %s %-5x\n", QFO_GETSTR (qfo, type->t.alias.name), - type->t.alias.type); + printf (" %s %d %-5x\n", QFO_GETSTR (qfo, type->t.alias.name), + type->t.alias.type, type->t.alias.aux_type); break; case ty_class: printf (" %-5x\n", type->t.class); diff --git a/tools/qfcc/source/obj_type.c b/tools/qfcc/source/obj_type.c index e67f7a0b5..ff2409986 100644 --- a/tools/qfcc/source/obj_type.c +++ b/tools/qfcc/source/obj_type.c @@ -264,7 +264,8 @@ qfo_encode_alias (type_t *type) def = qfo_new_encoding (type, sizeof (enc->t.alias)); enc = D_POINTER (qfot_type_t, def); - ENC_DEF (enc->t.alias.type, alias_type_def); + enc->t.alias.type = type->type; + ENC_DEF (enc->t.alias.aux_type, alias_type_def); ENC_STR (enc->t.alias.name, type->name); return def; } From 6a70d2e362077a73ec6fad1ac250c39a8ce60c41 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 20:56:01 +0900 Subject: [PATCH 019/444] Give alias types a unique encoding The encoding is used as the def name and it needs to be different than the alias target or the linker throws it away as an external def. --- tools/qfcc/source/type.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 2c3064405..4453e6284 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -654,7 +654,9 @@ encode_type (dstring_t *encoding, const type_t *type) dasprintf (encoding, "]"); return; case ty_alias: + dasprintf (encoding, "{%s>", type->name); encode_type (encoding, type->t.alias.type); + dasprintf (encoding, "}"); return; case ty_none: switch (type->type) { From a0914e1ec86612c8d0d493c406c3349342ef75a9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 20:58:02 +0900 Subject: [PATCH 020/444] Fix the typedef test case to actually work --- tools/qfcc/test/typedef.r | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tools/qfcc/test/typedef.r b/tools/qfcc/test/typedef.r index 48ea84478..ff5015c9e 100644 --- a/tools/qfcc/test/typedef.r +++ b/tools/qfcc/test/typedef.r @@ -21,36 +21,36 @@ next_type (qfot_type_t *type) return (qfot_type_t *) ((int *) type + size); } +int +check_alias (qfot_type_t *alias) +{ + if (alias.meta != ty_none && alias.t.type != ev_pointer) { + printf ("%s is not a *int alias\n", alias.t.alias.name); + return 0; + } + return 1; +} + int main (void) { + baz = snafu; + int found_foo = 0; int found_bar = 0; qfot_type_t *type; - qfot_type_t *alias; - - baz = snafu; // must be able to assign without warnings (won't compile) encodings = PR_FindGlobal (".type_encodings"); for (type = encodings.types; ((int *)type - (int *) encodings.types) < encodings.size; type = next_type (type)) { - if (type.meta == ty_alias && type.t.alias.type == ev_integer) { - alias = type.t.alias.aux_type; + if (type.meta == ty_alias) { if (type.t.alias.name == "foo") { - if (alias.meta == ty_none && alias.t.type == ev_integer) { - found_foo = 1; - } else { - printf ("foo type not aliased to int\n"); - } + found_foo = check_alias (type.t.alias.aux_type); } if (type.t.alias.name == "bar") { - if (alias.meta == ty_none && alias.t.type == ev_integer) { - found_bar = 1; - } else { - printf ("bar type not aliased to int\n"); - } + found_bar = check_alias (type.t.alias.aux_type); } } } From a6003ed08a8e82a5c4d4766c668f0132d099a4b3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 21:04:45 +0900 Subject: [PATCH 021/444] Walk qfo alias chain for type size and alignment While the basic type is stored in the alias type record, it's no good for size or alignment as it will give incorrect results for complex types. --- tools/qfcc/source/obj_file.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index e49d64c46..803f9995c 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -677,10 +677,10 @@ get_type_size (qfo_t *qfo, pointer_t type) type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { case ty_alias: + return get_type_size (qfo, type_def->t.alias.aux_type); case ty_none: // field, pointer and function types store their basic type in // the same location. - // alias types store the basic type at the end of the alias chain return pr_type_size[type_def->t.type]; case ty_struct: for (i = size = 0; i < type_def->t.strct.num_fields; i++) @@ -726,11 +726,11 @@ get_type_alignment_log (qfo_t *qfo, pointer_t type) return 0; type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { - case ty_none: case ty_alias: + return get_type_alignment_log (qfo, type_def->t.alias.aux_type); + case ty_none: // field, pointer and function types store their basic type in // the same location. - // alias types store the basic type at the end of the alias chain return qfo_log2 (ev_types[type_def->t.type]->alignment); case ty_struct: case ty_union: From fd2b7ee6f9caedc870ef0ea2a1d2d18540a317d6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 21:13:36 +0900 Subject: [PATCH 022/444] Use more type checking helper functions --- tools/qfcc/include/type.h | 3 +++ tools/qfcc/source/expr.c | 6 +++--- tools/qfcc/source/type.c | 32 ++++++++++++++++++++++++++++++-- 3 files changed, 36 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 098df5e00..17f21665d 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -163,6 +163,9 @@ const char *type_get_encoding (const type_t *type); const type_t *unalias_type (const type_t *type) __attribute__((pure)); int is_void (const type_t *type) __attribute__((pure)); int is_enum (const type_t *type) __attribute__((pure)); +int is_integer (const type_t *type) __attribute__((pure)); +int is_uinteger (const type_t *type) __attribute__((pure)); +int is_short (const type_t *type) __attribute__((pure)); int is_integral (const type_t *type) __attribute__((pure)); int is_double (const type_t *type) __attribute__((pure)); int is_float (const type_t *type) __attribute__((pure)); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index da96bd5fc..44032eb5d 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1459,15 +1459,15 @@ convert_from_bool (expr_t *e, type_t *type) expr_t *one; expr_t *cond; - if (type == &type_float) { + if (is_float (type)) { one = new_float_expr (1); zero = new_float_expr (0); - } else if (type == &type_integer) { + } else if (is_integer (type)) { one = new_integer_expr (1); zero = new_integer_expr (0); } else if (is_enum (type) && enum_as_bool (type, &zero, &one)) { // don't need to do anything - } else if (type == &type_uinteger) { + } else if (is_uinteger (type)) { one = new_uinteger_expr (1); zero = new_uinteger_expr (0); } else { diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 4453e6284..0622d392e 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -750,11 +750,39 @@ is_enum (const type_t *type) } int -is_integral (const type_t *type) +is_integer (const type_t *type) { etype_t t = type->type; - if (t == ev_integer || t == ev_uinteger || t == ev_short) + if (t == ev_integer) + return 1; + return is_enum (type); +} + +int +is_uinteger (const type_t *type) +{ + etype_t t = type->type; + + if (t == ev_uinteger) + return 1; + return is_enum (type); +} + +int +is_short (const type_t *type) +{ + etype_t t = type->type; + + if (t == ev_short) + return 1; + return is_enum (type); +} + +int +is_integral (const type_t *type) +{ + if (is_integer (type) || is_uinteger (type) || is_short (type)) return 1; return is_enum (type); } From 1b43046c8a1e06d96ff78641b12ed386450070dd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 19 Feb 2020 21:28:32 +0900 Subject: [PATCH 023/444] Handle aliased types when building function calls --- tools/qfcc/include/expr.h | 2 +- tools/qfcc/source/expr.c | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 90e4f6313..36d785be0 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -623,7 +623,7 @@ expr_t *binary_expr (int op, expr_t *e1, expr_t *e2); expr_t *field_expr (expr_t *e1, expr_t *e2); expr_t *asx_expr (int op, expr_t *e1, expr_t *e2); expr_t *unary_expr (int op, expr_t *e); -expr_t *build_function_call (expr_t *fexpr, struct type_s *ftype, +expr_t *build_function_call (expr_t *fexpr, const struct type_s *ftype, expr_t *params); expr_t *function_expr (expr_t *e1, expr_t *e2); struct function_s; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 44032eb5d..efddb5427 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1843,7 +1843,7 @@ bitnot_expr: } expr_t * -build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) +build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) { expr_t *e; int arg_count = 0, parm_count = 0; @@ -1855,6 +1855,8 @@ build_function_call (expr_t *fexpr, type_t *ftype, expr_t *params) expr_t *call; expr_t *err = 0; + ftype = unalias_type (ftype); + for (e = params; e; e = e->next) { if (e->type == ex_error) return e; From caf78b5422ac3883a13dd80b6997aed9ee2a2a6e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 21 Feb 2020 17:47:16 +0900 Subject: [PATCH 024/444] Rename ty_none to ty_basic This far better reflects the actual meaning. It is very likely that ty_none is a holdover from long before there was full type encoding and it meant that the union in qfcc's type_t had no data. This is still true for basic types, but only if not a function, field or pointer type. If the type was function, field or pointer, it was not true, so it was misnamed pretty much from the start. --- include/QF/pr_type.h | 6 +++--- ruamoko/include/types.h | 2 +- tools/qfcc/include/type.h | 3 ++- tools/qfcc/source/class.c | 17 +++++++++-------- tools/qfcc/source/dump_globals.c | 4 ++-- tools/qfcc/source/linker.c | 2 +- tools/qfcc/source/obj_file.c | 8 ++++---- tools/qfcc/source/type.c | 24 +++++++++++++----------- 8 files changed, 35 insertions(+), 31 deletions(-) diff --git a/include/QF/pr_type.h b/include/QF/pr_type.h index 0e33b0fd6..80f90b309 100644 --- a/include/QF/pr_type.h +++ b/include/QF/pr_type.h @@ -94,9 +94,9 @@ typedef struct qfot_type_s { pr_int_t size; ///< total word size of this encoding string_t encoding; ///< Objective-QC encoding union { - pr_int_t type; ///< basic type: etype_t - qfot_fldptr_t fldptr; ///< ty_none, ev_pointer/ev_field - qfot_func_t func; ///< ty_none, ev_func + pr_int_t type; ///< ty_basic: etype_t + qfot_fldptr_t fldptr; ///< ty_basic, ev_pointer/ev_field + qfot_func_t func; ///< ty_basic, ev_func qfot_struct_t strct; ///< ty_struct/ty_union/ty_enum qfot_array_t array; ///< ty_array pointer_t class; ///< ty_class diff --git a/ruamoko/include/types.h b/ruamoko/include/types.h index deb480ebf..b435a6bab 100644 --- a/ruamoko/include/types.h +++ b/ruamoko/include/types.h @@ -21,7 +21,7 @@ typedef enum { } etype_t; typedef enum { - ty_none, ///< func/field/pointer or not used + ty_basic, ///< VM type (float, int, pointer, field, etc) ty_struct, ty_union, ty_enum, diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 17f21665d..34afd4449 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -56,7 +56,7 @@ typedef struct ty_alias_s { } ty_alias_t; typedef enum { - ty_none, ///< func/field/pointer or not used + ty_basic, ///< VM type (float, int, pointer, field, etc) ty_struct, ty_union, ty_enum, @@ -72,6 +72,7 @@ typedef struct type_s { /// function/pointer/array/struct types are more complex ty_meta_e meta; union { + // no data for ty_basic when not a func, field or pointer ty_func_t func; ty_fldptr_t fldptr; ty_array_t array; diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index b249069c2..caa1967cd 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -69,30 +69,31 @@ static hashtab_t *protocol_hash; // these will be built up further type_t type_obj_selector = { ev_invalid, 0, 0, ty_struct}; -type_t type_SEL = { ev_pointer, "SEL", 1, ty_none, {{&type_obj_selector}}}; +type_t type_SEL = { ev_pointer, "SEL", 1, ty_basic, + {{&type_obj_selector}}}; type_t *IMP_params[] = {&type_id, &type_SEL}; -type_t type_IMP = { ev_func, "IMP", 1, ty_none, +type_t type_IMP = { ev_func, "IMP", 1, ty_basic, {{&type_id, -3, IMP_params}}}; type_t type_obj_super = { ev_invalid, 0, 0 }; -type_t type_SuperPtr = { ev_pointer, 0, 1, ty_none, {{&type_obj_super}}}; +type_t type_SuperPtr = { ev_pointer, 0, 1, ty_basic, {{&type_obj_super}}}; type_t *supermsg_params[] = {&type_SuperPtr, &type_SEL}; -type_t type_supermsg = { ev_func, ".supermsg", 1, ty_none, +type_t type_supermsg = { ev_func, ".supermsg", 1, ty_basic, {{&type_id, -3, supermsg_params}}}; type_t type_obj_method = { ev_invalid, 0, 0, ty_struct }; type_t type_obj_method_description = { ev_invalid, 0, 0, ty_struct }; type_t type_obj_category = { ev_invalid, 0, 0, ty_struct}; type_t type_obj_ivar = { ev_invalid, 0, 0, ty_struct}; type_t type_obj_module = { ev_invalid, 0, 0, ty_struct}; -type_t type_moduleptr = { ev_pointer, 0, 1, ty_none, +type_t type_moduleptr = { ev_pointer, 0, 1, ty_basic, {{&type_obj_module}}}; type_t *obj_exec_class_params[] = { &type_moduleptr }; -type_t type_obj_exec_class = { ev_func, 0, 1, ty_none, +type_t type_obj_exec_class = { ev_func, 0, 1, ty_basic, {{&type_void, 1, obj_exec_class_params}}}; type_t type_obj_object = {ev_invalid, 0, 0, ty_struct}; -type_t type_id = { ev_pointer, "id", 1, ty_none, {{&type_obj_object}}}; +type_t type_id = { ev_pointer, "id", 1, ty_basic, {{&type_obj_object}}}; type_t type_obj_class = { ev_invalid, 0, 0, ty_struct}; -type_t type_Class = { ev_pointer, 0, 1, ty_none, {{&type_obj_class}}}; +type_t type_Class = { ev_pointer, 0, 1, ty_basic, {{&type_obj_class}}}; type_t type_obj_protocol = { ev_invalid, 0, 0, ty_struct}; int obj_initialized = 0; diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 7d7d29f9e..89dbb50fa 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -417,7 +417,7 @@ qfo_functions (qfo_t *qfo) } static const char *ty_meta_names[] = { - "ty_none", + "ty_basic", "ty_struct", "ty_union", "ty_enum", @@ -461,7 +461,7 @@ dump_qfo_types (qfo_t *qfo, int base_address) break; } switch ((ty_meta_e) type->meta) { - case ty_none: + case ty_basic: printf (" %-10s", (type->t.type < 0 || type->t.type >= ev_type_count) ? "invalid type" diff --git a/tools/qfcc/source/linker.c b/tools/qfcc/source/linker.c index 3f07ba7b0..3ce5ca3fd 100644 --- a/tools/qfcc/source/linker.c +++ b/tools/qfcc/source/linker.c @@ -1164,7 +1164,7 @@ check_defs (void) defref_t *_d = Hash_Find (defined_data_defs, "self"); if (_d) { qfo_def_t *d = REF (_d); - if (QFO_TYPEMETA (work, d->type) == ty_none + if (QFO_TYPEMETA (work, d->type) == ty_basic && QFO_TYPETYPE (work, d->type) == ev_entity) def_warning (d, "@self and self used together"); } diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 803f9995c..d4db18377 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -647,7 +647,7 @@ get_def_type (qfo_t *qfo, pointer_t type) return ev_void; type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { - case ty_none: + case ty_basic: case ty_alias: // field, pointer and function types store their basic type in // the same location. @@ -678,7 +678,7 @@ get_type_size (qfo_t *qfo, pointer_t type) switch ((ty_meta_e)type_def->meta) { case ty_alias: return get_type_size (qfo, type_def->t.alias.aux_type); - case ty_none: + case ty_basic: // field, pointer and function types store their basic type in // the same location. return pr_type_size[type_def->t.type]; @@ -728,7 +728,7 @@ get_type_alignment_log (qfo_t *qfo, pointer_t type) switch ((ty_meta_e)type_def->meta) { case ty_alias: return get_type_alignment_log (qfo, type_def->t.alias.aux_type); - case ty_none: + case ty_basic: // field, pointer and function types store their basic type in // the same location. return qfo_log2 (ev_types[type_def->t.type]->alignment); @@ -773,7 +773,7 @@ function_params (qfo_t *qfo, qfo_func_t *func, dfunction_t *df) if (func->type >= qfo->spaces[qfo_type_space].data_size) return; type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, func->type); - if (type->meta != ty_none && type->t.type != ev_func) + if (type->meta != ty_basic && type->t.type != ev_func) return; df->numparms = num_params = type->t.func.num_params; if (num_params < 0) diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 0622d392e..e33f0ec34 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -67,11 +67,13 @@ type_t type_string = { ev_string, "string", 1 }; type_t type_float = { ev_float, "float", 1 }; type_t type_vector = { ev_vector, "vector", 1 }; type_t type_entity = { ev_entity, "entity", 1 }; -type_t type_field = {ev_field, "field", 1, ty_none, {{&type_void}} }; +type_t type_field = {ev_field, "field", 1, ty_basic, {{&type_void}} }; // type_function is a void() function used for state defs -type_t type_function = { ev_func, "function", 1, ty_none, {{&type_void}} }; -type_t type_pointer = { ev_pointer, "pointer", 1, ty_none, {{&type_void}} }; +type_t type_function = { ev_func, "function", 1, ty_basic, + {{&type_void}} }; +type_t type_pointer = { ev_pointer, "pointer", 1, ty_basic, + {{&type_void}} }; type_t type_quaternion = { ev_quat, "quaternion", 1 }; type_t type_integer = { ev_integer, "int", 1 }; type_t type_uinteger = { ev_uinteger, "uint", 1 }; @@ -88,7 +90,7 @@ type_t type_zero = { ev_invalid, 0, 0, ty_struct }; type_t type_type_encodings = { ev_invalid, "@type_encodings", 0, ty_struct }; -type_t type_floatfield = { ev_field, ".float", 1, ty_none, +type_t type_floatfield = { ev_field, ".float", 1, ty_basic, {{&type_float}} }; type_t *ev_types[ev_type_count] = { @@ -252,7 +254,7 @@ types_same (type_t *a, type_t *b) if (a->type != b->type || a->meta != b->meta) return 0; switch (a->meta) { - case ty_none: + case ty_basic: switch (a->type) { case ev_field: case ev_pointer: @@ -315,7 +317,7 @@ find_type (type_t *type) if (type->freeable) { switch (type->meta) { - case ty_none: + case ty_basic: switch (type->type) { case ev_field: case ev_pointer: @@ -500,7 +502,7 @@ print_type_str (dstring_t *str, const type_t *type) print_type_str (str, type->t.alias.type); dstring_appendstr (str, "})"); return; - case ty_none: + case ty_basic: switch (type->type) { case ev_field: dasprintf (str, ".("); @@ -658,7 +660,7 @@ encode_type (dstring_t *encoding, const type_t *type) encode_type (encoding, type->t.alias.type); dasprintf (encoding, "}"); return; - case ty_none: + case ty_basic: switch (type->type) { case ev_void: dasprintf (encoding, "v"); @@ -984,7 +986,7 @@ type_size (const type_t *type) return type->t.array.size * type_size (type->t.array.type); case ty_alias: return type_size (type->t.alias.type); - case ty_none: + case ty_basic: return 0; } break; @@ -1060,7 +1062,7 @@ init_types (void) make_structure ("@param", 'u', param_struct, &type_param); make_structure ("@vector", 's', vector_struct, &type_vector); type_vector.type = ev_vector; - type_vector.meta = ty_none; + type_vector.meta = ty_basic; make_structure ("@type_encodings", 's', type_encoding_struct, &type_type_encodings); @@ -1070,7 +1072,7 @@ init_types (void) make_structure ("@quaternion", 's', quaternion_struct, &type_quaternion); type_quaternion.type = ev_quat; - type_quaternion.meta = ty_none; + type_quaternion.meta = ty_basic; { symbol_t *sym; sym = new_symbol_type ("x", &type_float); From 8b225dbfc10962c113e2cb32cc1594c3e7bcd301 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 21 Feb 2020 17:53:27 +0900 Subject: [PATCH 025/444] Ensure .ctor functions do not reset tracing --- tools/qfcc/test/test-harness.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qfcc/test/test-harness.c b/tools/qfcc/test/test-harness.c index a8f829cd9..ed8a5c929 100644 --- a/tools/qfcc/test/test-harness.c +++ b/tools/qfcc/test/test-harness.c @@ -149,6 +149,7 @@ init_qf (void) pr.allocate_progs_mem = allocate_progs_mem; pr.free_progs_mem = free_progs_mem; pr.no_exec_limit = 0; // absolutely want a limit! + pr.pr_trace_depth = -1; pr.pr_trace = options.trace; PR_Init_Cvars (); From 3c9e2a6451f331be6c9fc3f01f846475e1c7a8fd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 21 Feb 2020 17:54:42 +0900 Subject: [PATCH 026/444] Rename the sys documentation group --- include/QF/sys.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/sys.h b/include/QF/sys.h index 85785ed6e..10ef6999f 100644 --- a/include/QF/sys.h +++ b/include/QF/sys.h @@ -28,7 +28,7 @@ #ifndef __sys_h #define __sys_h -/** \defgroup sys Portability +/** \defgroup sys System Portability \ingroup utils Non-portable functions */ From fe796eee68906a8f31f0f743708af226a486e84f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 21 Feb 2020 17:58:19 +0900 Subject: [PATCH 027/444] Move the meta type enum ino pr_type.h --- include/QF/pr_type.h | 10 ++++++++++ tools/qfcc/include/type.h | 12 +----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/QF/pr_type.h b/include/QF/pr_type.h index 80f90b309..b2ea05060 100644 --- a/include/QF/pr_type.h +++ b/include/QF/pr_type.h @@ -40,6 +40,16 @@ #include "QF/pr_comp.h" +typedef enum { + ty_basic, ///< VM type (float, int, pointer, field, etc) + ty_struct, + ty_union, + ty_enum, + ty_array, + ty_class, + ty_alias, +} ty_meta_e; + typedef struct qfot_alias_s { pr_int_t type; ///< type at end of alias chain pointer_t aux_type; ///< referenced type diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 34afd4449..784ed6f9a 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -31,7 +31,7 @@ #ifndef __type_h #define __type_h -#include "QF/pr_comp.h" +#include "QF/pr_type.h" #include "def.h" @@ -55,16 +55,6 @@ typedef struct ty_alias_s { struct type_s *type; } ty_alias_t; -typedef enum { - ty_basic, ///< VM type (float, int, pointer, field, etc) - ty_struct, - ty_union, - ty_enum, - ty_array, - ty_class, - ty_alias, -} ty_meta_e; - typedef struct type_s { etype_t type; ///< ev_invalid means structure/array etc const char *name; From 7e76a96f7d0c963ca98899e6196c98b87f8d6a71 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 21 Feb 2020 21:13:18 +0900 Subject: [PATCH 028/444] Fix a missed ty_none --- tools/qfcc/test/typedef.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/test/typedef.r b/tools/qfcc/test/typedef.r index ff5015c9e..bb5d52e4a 100644 --- a/tools/qfcc/test/typedef.r +++ b/tools/qfcc/test/typedef.r @@ -24,7 +24,7 @@ next_type (qfot_type_t *type) int check_alias (qfot_type_t *alias) { - if (alias.meta != ty_none && alias.t.type != ev_pointer) { + if (alias.meta != ty_basic && alias.t.type != ev_pointer) { printf ("%s is not a *int alias\n", alias.t.alias.name); return 0; } From c296514b950ad2956e2da00d85dadf27406ee40a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 21 Feb 2020 21:17:28 +0900 Subject: [PATCH 029/444] Make pr.load_file 'return' the file size --- include/QF/progs.h | 2 +- libs/console/menu.c | 6 ++++-- libs/gamecode/pr_debug.c | 7 +++++-- libs/gamecode/pr_load.c | 6 ++++-- tools/qfcc/source/qfprogs.c | 3 ++- tools/qfcc/test/test-harness.c | 3 ++- tools/qwaq/main.c | 3 ++- tools/qwaq/qwaq.c | 3 ++- 8 files changed, 22 insertions(+), 11 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index e7953883e..87fd87c89 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1550,7 +1550,7 @@ struct progs_s { int no_exec_limit; void (*file_error) (progs_t *pr, const char *path); - void *(*load_file) (progs_t *pr, const char *path); + void *(*load_file) (progs_t *pr, const char *path, off_t *size); void *(*allocate_progs_mem) (progs_t *pr, int size); void (*free_progs_mem) (progs_t *pr, void *mem); diff --git a/libs/console/menu.c b/libs/console/menu.c index e65fff1cb..043532023 100644 --- a/libs/console/menu.c +++ b/libs/console/menu.c @@ -510,9 +510,11 @@ menu_free_progs_mem (progs_t *pr, void *mem) } static void * -menu_load_file (progs_t *pr, const char *path) +menu_load_file (progs_t *pr, const char *path, off_t *size) { - return QFS_LoadFile (QFS_FOpenFile (path), 0); + void *data = QFS_LoadFile (QFS_FOpenFile (path), 0); + *size = qfs_filesize; + return data; } static builtin_t builtins[] = { diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 174987135..7f86c2c8f 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -65,6 +65,7 @@ typedef struct { typedef struct { char *name; char *text; + off_t size; line_t *lines; pr_uint_t num_lines; progs_t *pr; @@ -227,7 +228,8 @@ PR_Load_Source_File (progs_t *pr, const char *fname) return 0; for (dir = source_paths; *dir && !f->text; dir++) { f->text = pr->load_file (pr, va ("%s%s%s", *dir, **dir ? "/" : "", - fname)); + fname), + &f->size); } if (!f->text) { pr->file_error (pr, fname); @@ -273,6 +275,7 @@ PR_LoadDebug (progs_t *pr) { char *sym_path; const char *path_end, *sym_file; + off_t debug_size; pr_uint_t i; ddef_t *def; pr_type_t *str = 0; @@ -303,7 +306,7 @@ PR_LoadDebug (progs_t *pr) sym_path = malloc (strlen (sym_file) + (path_end - pr->progs_name) + 1); strncpy (sym_path, pr->progs_name, path_end - pr->progs_name); strcpy (sym_path + (path_end - pr->progs_name), sym_file); - pr->debug = pr->load_file (pr, sym_path); + pr->debug = pr->load_file (pr, sym_path, &debug_size); if (!pr->debug) { Sys_Printf ("can't load %s for debug info\n", sym_path); free (sym_path); diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index 8bc554296..cadfebca3 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -81,9 +81,11 @@ file_error (progs_t *pr, const char *path) } static void * -load_file (progs_t *pr, const char *path) +load_file (progs_t *pr, const char *path, off_t *size) { - return QFS_LoadHunkFile (QFS_FOpenFile (path)); + void *data = QFS_LoadHunkFile (QFS_FOpenFile (path)); + *size = qfs_filesize; + return data; } static void * diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index 10ddf8abd..be14d144f 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -176,7 +176,7 @@ file_error (progs_t *pr, const char *name) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -191,6 +191,7 @@ load_file (progs_t *pr, const char *name) sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } diff --git a/tools/qfcc/test/test-harness.c b/tools/qfcc/test/test-harness.c index ed8a5c929..78c657d05 100644 --- a/tools/qfcc/test/test-harness.c +++ b/tools/qfcc/test/test-harness.c @@ -96,7 +96,7 @@ open_file (const char *path, int *len) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -112,6 +112,7 @@ load_file (progs_t *pr, const char *name) sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } diff --git a/tools/qwaq/main.c b/tools/qwaq/main.c index 15270d5e4..035e4f73b 100644 --- a/tools/qwaq/main.c +++ b/tools/qwaq/main.c @@ -65,7 +65,7 @@ open_file (const char *path, int *len) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -81,6 +81,7 @@ load_file (progs_t *pr, const char *name) sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } diff --git a/tools/qwaq/qwaq.c b/tools/qwaq/qwaq.c index 40576e868..24a14d217 100644 --- a/tools/qwaq/qwaq.c +++ b/tools/qwaq/qwaq.c @@ -71,7 +71,7 @@ open_file (const char *path, int *len) } static void * -load_file (progs_t *pr, const char *name) +load_file (progs_t *pr, const char *name, off_t *_size) { QFile *file; int size; @@ -87,6 +87,7 @@ load_file (progs_t *pr, const char *name) sym = malloc (size + 1); sym[size] = 0; Qread (file, sym, size); + *_size = size; return sym; } From e7b4eedc07526d925f3538e00ed905dbddd2fb54 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 22 Feb 2020 14:04:10 +0900 Subject: [PATCH 030/444] Fix segfault in dereferencing undefined field containers --- tools/qfcc/source/expr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index efddb5427..ab9672813 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1162,9 +1162,10 @@ field_expr (expr_t *e1, expr_t *e2) const type_t *t1, *t2; expr_t *e; + t1 = get_type (e1); if (e1->type == ex_error) return e1; - t1 = unalias_type (get_type (e1)); + t1 = unalias_type (t1); if (t1->type == ev_entity) { symbol_t *field = 0; From 4df926e531fe203e293e9e7c3d0ec326bc05fe61 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 22 Feb 2020 14:11:15 +0900 Subject: [PATCH 031/444] Write extended ddef information to progs far data I was originally going to put it in the debug syms file, but I realized that the data persistence code would need access to both def type and certainly correct def offsets for defs in far data. --- include/QF/pr_comp.h | 10 +++++++++ tools/qfcc/include/type.h | 3 +++ tools/qfcc/source/obj_file.c | 43 +++++++++++++++++++++++++++++++----- tools/qfcc/source/qfcc.c | 1 + tools/qfcc/source/type.c | 18 +++++++++++++++ tools/qwaq/main.qc | 1 + tools/qwaq/types.r | 27 ++++++++++++++++++++++ 7 files changed, 98 insertions(+), 5 deletions(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 185a802ad..6b39ff1bc 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -423,6 +423,16 @@ typedef struct ddef_s { pr_int_t s_name; } ddef_t; +typedef struct xdef_s { + pointer_t type; ///< pointer to type definition + pointer_t ofs; ///< 32-bit version of ddef_t.ofs +} xdef_t; + +typedef struct pr_xdefs_s { + pointer_t xdefs; + pr_int_t num_xdefs; +} pr_xdefs_t; + typedef struct dparmsize_s { uint8_t size:5; uint8_t alignment:3; diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 784ed6f9a..c8913933e 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -116,6 +116,9 @@ extern type_t type_va_list; extern type_t type_param; extern type_t type_zero; extern type_t type_type_encodings; +extern type_t type_xdef; +extern type_t type_xdef_pointer; +extern type_t type_xdefs; extern struct symtab_s *vector_struct; extern struct symtab_s *quaternion_struct; diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index d4db18377..79c4effeb 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -879,12 +879,16 @@ qfo_to_progs (qfo_t *qfo, int *size) pr_type_t *locals; pr_type_t *far_data; pr_type_t *type_data; + pr_type_t *xdef_data; dprograms_t *progs; qfo_def_t *types_def = 0; + qfo_def_t *xdefs_def = 0; unsigned i, j; unsigned near_data_size = 0; unsigned locals_size = 0; int locals_start; + int type_encodings_start; + int xdefs_start; unsigned big_locals = 0; int big_func = 0; @@ -893,7 +897,9 @@ qfo_to_progs (qfo_t *qfo, int *size) progs->version = options.code.progsversion; progs->numstatements = qfo->spaces[qfo_code_space].data_size; progs->numglobaldefs = qfo->spaces[qfo_near_data_space].num_defs; - //FIXME ddef offsets are 16 bits + //ddef offsets are 16 bits so the ddef ofs will likely be invalid + //thus it will be forced invalid and the true offset written to the + //symbols file if it is created (fa progs->numglobaldefs += qfo->spaces[qfo_far_data_space].num_defs; progs->numfielddefs = qfo->spaces[qfo_entity_space].num_defs; progs->numfunctions = qfo->num_funcs + 1; @@ -915,7 +921,11 @@ qfo_to_progs (qfo_t *qfo, int *size) near_data_size = progs->numglobals; progs->numglobals = RUP (progs->numglobals, 16 / sizeof (pr_type_t)); progs->numglobals += qfo->spaces[qfo_far_data_space].data_size; + type_encodings_start = progs->numglobals; progs->numglobals += qfo->spaces[qfo_type_space].data_size; + progs->numglobals = RUP (progs->numglobals, type_xdef.alignment); + xdefs_start = progs->numglobals; + progs->numglobals += progs->numglobaldefs * type_size (&type_xdef); progs->entityfields = qfo->spaces[qfo_entity_space].data_size; *size += progs->numstatements * sizeof (dstatement_t); *size += progs->numglobaldefs * sizeof (ddef_t); @@ -954,7 +964,8 @@ qfo_to_progs (qfo_t *qfo, int *size) globals = (pr_type_t*) data; locals = globals + locals_start; far_data = globals + near_data_size; - type_data = far_data + qfo->spaces[qfo_far_data_space].data_size; + type_data = globals + type_encodings_start; + xdef_data = globals + xdefs_start; memcpy (strings, qfo->spaces[qfo_strings_space].d.strings, qfo->spaces[qfo_strings_space].data_size * sizeof (char)); @@ -987,14 +998,18 @@ qfo_to_progs (qfo_t *qfo, int *size) qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i; if (!strcmp (QFO_GETSTR (qfo, def->name), ".type_encodings")) types_def = def; + if (!strcmp (QFO_GETSTR (qfo, def->name), ".xdefs")) + xdefs_def = def; convert_def (qfo, def, globaldefs++); } - //FIXME ddef offsets are 16 bits for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++) { qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + i; def->offset += far_data - globals; - convert_def (qfo, def, globaldefs++); + convert_def (qfo, def, globaldefs); + // the correct offset will be written to the far data space + globaldefs->ofs = -1; + globaldefs++; } for (i = 0; i < qfo->spaces[qfo_type_space].num_defs; i++) { @@ -1025,9 +1040,27 @@ qfo_to_progs (qfo_t *qfo, int *size) if (types_def) { qfot_type_encodings_t *encodings; encodings = (qfot_type_encodings_t *) &globals[types_def->offset]; - encodings->types = type_data - globals; + encodings->types = type_encodings_start; encodings->size = qfo->spaces[qfo_type_space].data_size; } + if (xdefs_def) { + int xdef_data_size = type_size (&type_xdef); + pr_xdefs_t *xdefs = (pr_xdefs_t *) &globals[xdefs_def->offset]; + xdefs->xdefs = xdefs_start; + xdefs->num_xdefs = progs->numglobaldefs; + for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++) { + qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i; + xdef_data[0].pointer_var = def->type + type_encodings_start; + xdef_data[1].pointer_var = def->offset; + xdef_data += xdef_data_size; + } + for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++) { + qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + i; + xdef_data[0].pointer_var = def->type + type_encodings_start; + xdef_data[1].pointer_var = def->offset; + xdef_data += xdef_data_size; + } + } // undo the relocation of the offsets of local defs so the local defs have // the correct offset in the debug info diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 780db073a..9e292d136 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -423,6 +423,7 @@ finish_link (void) ¶m_size); linker_add_def (".param_alignment", &type_integer, flags, ¶m_alignment); + linker_add_def (".xdefs", &type_xdefs, flags, 0); } if (options.code.debug) { diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index e33f0ec34..04c8d7442 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -89,6 +89,9 @@ type_t type_param = { ev_invalid, 0, 0, ty_struct }; type_t type_zero = { ev_invalid, 0, 0, ty_struct }; type_t type_type_encodings = { ev_invalid, "@type_encodings", 0, ty_struct }; +type_t type_xdef = { ev_invalid, "@xdef", 0, ty_struct }; +type_t type_xdef_pointer = { ev_pointer, 0, 1, ty_basic, {{&type_xdef}} }; +type_t type_xdefs = { ev_invalid, "@xdefs", 0, ty_struct }; type_t type_floatfield = { ev_field, ".float", 1, ty_basic, {{&type_float}} }; @@ -1045,6 +1048,16 @@ init_types (void) {"size", &type_integer}, {0, 0} }; + static struct_def_t xdef_struct[] = { + {"types", &type_pointer}, + {"offset", &type_pointer}, + {0, 0} + }; + static struct_def_t xdefs_struct[] = { + {"xdefs", &type_xdef_pointer}, + {"num_xdefs", &type_pointer}, + {0, 0} + }; type_nil = &type_quaternion; type_default = &type_integer; @@ -1066,6 +1079,8 @@ init_types (void) make_structure ("@type_encodings", 's', type_encoding_struct, &type_type_encodings); + make_structure ("@xdef", 's', xdef_struct, &type_xdef); + make_structure ("@xdefs", 's', xdefs_struct, &type_xdefs); if (options.traditional) return; @@ -1120,6 +1135,9 @@ chain_initial_types (void) chain_type (&type_param); chain_type (&type_zero); chain_type (&type_type_encodings); + chain_type (&type_xdef); + chain_type (&type_xdef_pointer); + chain_type (&type_xdefs); va_list_struct[1].type = pointer_type (&type_param); make_structure ("@va_list", 's', va_list_struct, &type_va_list); diff --git a/tools/qwaq/main.qc b/tools/qwaq/main.qc index 1014c1f4d..25cfaabdb 100644 --- a/tools/qwaq/main.qc +++ b/tools/qwaq/main.qc @@ -109,5 +109,6 @@ int main (int argc, string *argv) test_script (); test_plist (); test_types (); + test_xdefs (); return 0; }; diff --git a/tools/qwaq/types.r b/tools/qwaq/types.r index 324185b93..5cf874c61 100644 --- a/tools/qwaq/types.r +++ b/tools/qwaq/types.r @@ -77,6 +77,16 @@ typedef struct qfot_type_encodings_s { int size; } qfot_type_encodings_t; +typedef struct xdef_s { + qfot_type_t *type; + void *offset; +} xdef_t; + +typedef struct pr_xdefs_s { + xdef_t *xdefs; + int num_xdefs; +} pr_xdefs_t; + qfot_type_t * next_type (qfot_type_t *type) { @@ -174,3 +184,20 @@ test_types (void) } } } + +void +test_xdefs (void) +{ + pr_xdefs_t *xdefs; + int i; + + xdefs = PR_FindGlobal (".xdefs"); + if (!xdefs) { + printf ("Can't find xdefs\n"); + return; + } + printf ("%p %i\n", xdefs.xdefs, xdefs.num_xdefs); + for (i = 0; i < xdefs.num_xdefs; i++) { + printf ("%p %p\n", xdefs.xdefs[i].type, xdefs.xdefs[i].offset); + } +} From 81083698a8958137ba91d28fdaf21416eb4a93a8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 22 Feb 2020 22:33:44 +0900 Subject: [PATCH 032/444] Move to using an in-memory form of ddef_t This allows the VM to work with extended ddefs transparently. It seems to have uncovered a typedef alias relocation bug, though. --- include/QF/pr_comp.h | 13 ++++++-- include/QF/pr_debug.h | 2 +- include/QF/progs.h | 22 +++++++------ libs/console/menu.c | 2 +- libs/gamecode/pr_debug.c | 56 ++++++++++++++++---------------- libs/gamecode/pr_edict.c | 6 ++-- libs/gamecode/pr_load.c | 56 ++++++++++++++++++++++++++------ libs/gamecode/pr_opcode.c | 2 +- libs/gamecode/pr_parse.c | 22 ++++++------- libs/gamecode/pr_resolve.c | 20 ++++++------ libs/ruamoko/pr_cmds.c | 4 +-- libs/ruamoko/rua_obj.c | 4 +-- nq/source/sv_progs.c | 4 +-- qw/source/sv_pr_qwe.c | 2 +- qw/source/sv_progs.c | 4 +-- tools/qfcc/source/dump_globals.c | 24 +++++++------- tools/qfcc/source/dump_modules.c | 6 ++-- tools/qfcc/source/obj_file.c | 48 +++++++++++++++------------ tools/qfcc/source/qfprogs.c | 41 +++++++++++++++++++++-- 19 files changed, 213 insertions(+), 125 deletions(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 6b39ff1bc..d1865d1cc 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -420,7 +420,7 @@ typedef struct ddef_s { pr_ushort_t type; // if DEF_SAVEGLOBGAL bit is set // the variable needs to be saved in savegames pr_ushort_t ofs; - pr_int_t s_name; + string_t s_name; } ddef_t; typedef struct xdef_s { @@ -433,6 +433,13 @@ typedef struct pr_xdefs_s { pr_int_t num_xdefs; } pr_xdefs_t; +typedef struct pr_def_s { + pr_uint_t type; + pointer_t ofs; + string_t name; + pointer_t type_encoding; +} pr_def_t; + typedef struct dparmsize_s { uint8_t size:5; uint8_t alignment:3; @@ -445,11 +452,11 @@ typedef struct dparmsize_s { typedef struct dfunction_s { pr_int_t first_statement; // negative numbers are builtins pr_int_t parm_start; - pr_int_t locals; // total ints of parms + locals + pr_uint_t locals; // total ints of parms + locals pr_int_t profile; // runtime - pr_int_t s_name; + string_t s_name; pr_int_t s_file; // source file defined in pr_int_t numparms; diff --git a/include/QF/pr_debug.h b/include/QF/pr_debug.h index 65b953381..d80b9f417 100644 --- a/include/QF/pr_debug.h +++ b/include/QF/pr_debug.h @@ -51,7 +51,7 @@ typedef struct pr_lineno_s { pr_uint_t line; } pr_lineno_t; -#define PROG_DEBUG_VERSION 0x00001002 // MMmmmRRR 0.001.002 (hex) +#define PROG_DEBUG_VERSION 0x00001003 // MMmmmRRR 0.001.002 (hex) typedef struct pr_debug_header_s { pr_int_t version; diff --git a/include/QF/progs.h b/include/QF/progs.h index 87fd87c89..e93bea597 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -236,7 +236,7 @@ void ED_PrintNum (progs_t *pr, pr_int_t ent); // pr_parse.c struct script_s; struct plitem_s; -qboolean ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, +qboolean ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s); struct plitem_s *ED_EntityDict (progs_t *pr, edict_t *ed); struct plitem_s *ED_GlobalsDict (progs_t *pr); @@ -269,11 +269,11 @@ void ED_EntityParseFunction (progs_t *pr); */ ///@{ -ddef_t *PR_FieldAtOfs (progs_t *pr, pr_int_t ofs) __attribute__((pure)); -ddef_t *PR_GlobalAtOfs (progs_t *pr, pr_int_t ofs) __attribute__((pure)); +pr_def_t *PR_FieldAtOfs (progs_t *pr, pointer_t ofs) __attribute__((pure)); +pr_def_t *PR_GlobalAtOfs (progs_t *pr, pointer_t ofs) __attribute__((pure)); -ddef_t *PR_FindField (progs_t *pr, const char *name); -ddef_t *PR_FindGlobal (progs_t *pr, const char *name); +pr_def_t *PR_FindField (progs_t *pr, const char *name); +pr_def_t *PR_FindGlobal (progs_t *pr, const char *name); dfunction_t *PR_FindFunction (progs_t *pr, const char *name); int PR_ResolveGlobals (progs_t *pr); @@ -1499,8 +1499,8 @@ pr_uint_t PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno) __attribute__((p pr_lineno_t *PR_Find_Lineno (progs_t *pr, pr_uint_t addr) __attribute__((pure)); const char *PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); const char *PR_Get_Source_Line (progs_t *pr, pr_uint_t addr); -ddef_t *PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) __attribute__((pure)); -ddef_t *PR_Get_Local_Def (progs_t *pr, pr_int_t offs) __attribute__((pure)); +pr_def_t *PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) __attribute__((pure)); +pr_def_t *PR_Get_Local_Def (progs_t *pr, pointer_t offs) __attribute__((pure)); void PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents); void PR_DumpState (progs_t *pr); void PR_StackTrace (progs_t *pr); @@ -1616,8 +1616,10 @@ struct progs_s { bfunction_t *function_table; char *pr_strings; int pr_stringsize; - ddef_t *pr_globaldefs; - ddef_t *pr_fielddefs; + ddef_t *pr_globalddefs; + ddef_t *pr_fieldddefs; + pr_def_t *pr_globaldefs; + pr_def_t *pr_fielddefs; dstatement_t *pr_statements; pr_type_t *pr_globals; unsigned globals_size; @@ -1708,7 +1710,7 @@ struct progs_s { struct pr_auxfunction_s *auxfunctions; struct pr_auxfunction_s **auxfunction_map; struct pr_lineno_s *linenos; - ddef_t *local_defs; + pr_def_t *local_defs; pr_type_t *watch; int wp_conditional; pr_type_t wp_val; diff --git a/libs/console/menu.c b/libs/console/menu.c index 043532023..8320bc405 100644 --- a/libs/console/menu.c +++ b/libs/console/menu.c @@ -117,7 +117,7 @@ static int menu_resolve_globals (progs_t *pr) { const char *sym; - ddef_t *def; + pr_def_t *def; dfunction_t *f; size_t i; diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 7f86c2c8f..0c388eaff 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -126,17 +126,17 @@ pr_debug_expression_error (script_t *script, const char *msg) Sys_Printf ("%s\n", msg); } -static ddef_t +static pr_def_t parse_expression (progs_t *pr, const char *expr, int conditional) { script_t *es; char *e; pr_type_t *expr_ptr; - ddef_t d; + pr_def_t d; d.ofs = 0; d.type = ev_invalid; - d.s_name = 0; + d.name = 0; es = Script_New (); es->error = pr_debug_expression_error; Script_Start (es, "", expr); @@ -145,7 +145,7 @@ parse_expression (progs_t *pr, const char *expr, int conditional) if (Script_GetToken (es, 1)) { if (strequal (es->token->str, "[")) { edict_t *ent; - ddef_t *field; + pr_def_t *field; if (!Script_GetToken (es, 1)) goto error; @@ -169,7 +169,7 @@ parse_expression (progs_t *pr, const char *expr, int conditional) d.type = ev_void; d.ofs = PR_SetPointer (pr, expr_ptr); } else { - ddef_t *global = PR_FindGlobal (pr, es->token->str); + pr_def_t *global = PR_FindGlobal (pr, es->token->str); if (!global) goto error; d = *global; @@ -277,7 +277,7 @@ PR_LoadDebug (progs_t *pr) const char *path_end, *sym_file; off_t debug_size; pr_uint_t i; - ddef_t *def; + pr_def_t *def; pr_type_t *str = 0; if (pr->debug) @@ -348,7 +348,7 @@ PR_LoadDebug (progs_t *pr) pr->auxfunctions = (pr_auxfunction_t*)((char*)pr->debug + pr->debug->auxfunctions); pr->linenos = (pr_lineno_t*)((char*)pr->debug + pr->debug->linenos); - pr->local_defs = (ddef_t*)((char*)pr->debug + pr->debug->locals); + pr->local_defs = (pr_def_t*)((char*)pr->debug + pr->debug->locals); i = pr->progs->numfunctions * sizeof (pr_auxfunction_t *); pr->auxfunction_map = pr->allocate_progs_mem (pr, i); @@ -377,7 +377,7 @@ PR_LoadDebug (progs_t *pr) for (i = 0; i < pr->debug->num_locals; i++) { pr->local_defs[i].type = LittleShort (pr->local_defs[i].type); pr->local_defs[i].ofs = LittleShort (pr->local_defs[i].ofs); - pr->local_defs[i].s_name = LittleLong (pr->local_defs[i].s_name); + pr->local_defs[i].name = LittleLong (pr->local_defs[i].name); } return 1; } @@ -474,12 +474,12 @@ PR_Get_Source_Line (progs_t *pr, pr_uint_t addr) file->lines[line - 1].text); } -ddef_t * +pr_def_t * PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) { pr_uint_t i; pr_auxfunction_t *aux_func; - ddef_t *ddef = 0; + pr_def_t *ddef = 0; int num_params; int param_offs = 0; @@ -522,7 +522,7 @@ static etype_t get_etype (progs_t *pr, int typeptr) { //FIXME cache .type_encodings def - ddef_t *te_def = PR_FindGlobal (pr, ".type_encodings"); + pr_def_t *te_def = PR_FindGlobal (pr, ".type_encodings"); qfot_type_encodings_t *encodings; qfot_type_t *type; @@ -538,8 +538,8 @@ get_etype (progs_t *pr, int typeptr) return ev_void; } -ddef_t * -PR_Get_Local_Def (progs_t *pr, pr_int_t offs) +pr_def_t * +PR_Get_Local_Def (progs_t *pr, pointer_t offs) { pr_uint_t i; dfunction_t *func; @@ -554,7 +554,7 @@ PR_Get_Local_Def (progs_t *pr, pr_int_t offs) if (!aux_func) return 0; offs -= func->parm_start; - if (offs < 0 || offs >= func->locals) + if (offs >= func->locals) return 0; for (i = 0; i < aux_func->num_locals; i++) if (pr->local_defs[aux_func->local_defs + i].ofs == offs) @@ -594,7 +594,7 @@ static const char * value_string (progs_t *pr, etype_t type, pr_type_t *val) { static dstring_t *line; - ddef_t *def; + pr_def_t *def; pr_int_t ofs; edict_t *edict; dfunction_t *f; @@ -655,7 +655,7 @@ value_string (progs_t *pr, etype_t type, pr_type_t *val) case ev_field: def = PR_FieldAtOfs (pr, val->integer_var); if (def) - dsprintf (line, ".%s", PR_GetString (pr, def->s_name)); + dsprintf (line, ".%s", PR_GetString (pr, def->name)); else dsprintf (line, ".<$%04x>", val->integer_var); break; @@ -679,8 +679,8 @@ value_string (progs_t *pr, etype_t type, pr_type_t *val) def = PR_Get_Local_Def (pr, ofs); if (!def) def = PR_GlobalAtOfs (pr, ofs); - if (def && def->s_name) - dsprintf (line, "&%s", PR_GetString (pr, def->s_name)); + if (def && def->name) + dsprintf (line, "&%s", PR_GetString (pr, def->name)); else dsprintf (line, "[$%x]", ofs); break; @@ -711,17 +711,17 @@ value_string (progs_t *pr, etype_t type, pr_type_t *val) return line->str; } -static ddef_t * +static pr_def_t * def_string (progs_t *pr, pr_int_t ofs, dstring_t *dstr) { - ddef_t *def = 0; + pr_def_t *def = 0; const char *name; if (pr_debug->int_val && pr->debug) def = PR_Get_Local_Def (pr, ofs); if (!def) def = PR_GlobalAtOfs (pr, ofs); - if (!def || !*(name = PR_GetString (pr, def->s_name))) + if (!def || !*(name = PR_GetString (pr, def->name))) dsprintf (dstr, "[$%x]", ofs); else dsprintf (dstr, "%s", name); @@ -732,7 +732,7 @@ static const char * global_string (progs_t *pr, pointer_t ofs, etype_t type, int contents) { static dstring_t *line = NULL; - ddef_t *def = NULL; + pr_def_t *def = NULL; const char *s; if (!line) @@ -771,7 +771,7 @@ global_string (progs_t *pr, pointer_t ofs, etype_t type, int contents) VISIBLE void PR_Debug_Watch (progs_t *pr, const char *expr) { - ddef_t watch; + pr_def_t watch; if (!expr) { Sys_Printf ("watch \n"); if (pr->watch) { @@ -802,7 +802,7 @@ PR_Debug_Watch (progs_t *pr, const char *expr) VISIBLE void PR_Debug_Print (progs_t *pr, const char *expr) { - ddef_t print; + pr_def_t print; if (!expr) { Sys_Printf ("print \n"); @@ -825,7 +825,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) opcode_t *op; static dstring_t *line; dfunction_t *call_func = 0; - ddef_t *parm_def = 0; + pr_def_t *parm_def = 0; pr_auxfunction_t *aux_func = 0; if (!line) @@ -1075,7 +1075,7 @@ ED_Print (progs_t *pr, edict_t *ed) int type, l; pr_uint_t i; const char *name; - ddef_t *d; + pr_def_t *d; pr_type_t *v; if (ed->free) { @@ -1086,9 +1086,9 @@ ED_Print (progs_t *pr, edict_t *ed) Sys_Printf ("\nEDICT %d:\n", NUM_FOR_BAD_EDICT (pr, ed)); for (i = 0; i < pr->progs->numfielddefs; i++) { d = &pr->pr_fielddefs[i]; - if (!d->s_name) // null field def (probably 1st) + if (!d->name) // null field def (probably 1st) continue; - name = PR_GetString (pr, d->s_name); + name = PR_GetString (pr, d->name); if (name[strlen (name) - 2] == '_' && strchr ("xyz", name[strlen (name) -1])) continue; // skip _x, _y, _z vars diff --git a/libs/gamecode/pr_edict.c b/libs/gamecode/pr_edict.c index 2241e3e9f..76eb07e9b 100644 --- a/libs/gamecode/pr_edict.c +++ b/libs/gamecode/pr_edict.c @@ -158,7 +158,7 @@ ED_PrintEdicts (progs_t *pr, const char *fieldval) { pr_int_t i; int count; - ddef_t *def; + pr_def_t *def; def = PR_FindField(pr, "classname"); @@ -188,8 +188,8 @@ ED_Count (progs_t *pr) { pr_int_t i; int active, models, solid, step, zombie; - ddef_t *solid_def; - ddef_t *model_def; + pr_def_t *solid_def; + pr_def_t *model_def; edict_t *ent; solid_def = PR_FindField (pr, "solid"); diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index cadfebca3..eec948d45 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -70,8 +70,8 @@ static const char * var_get_key (const void *d, void *_pr) { progs_t *pr = (progs_t*)_pr; - ddef_t *def = (ddef_t*)d; - return PR_GetString (pr, def->s_name); + pr_def_t *def = (pr_def_t*)d; + return PR_GetString (pr, def->name); } static void @@ -119,6 +119,8 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) dprograms_t progs; byte *base; byte *heap; + pr_def_t *xdefs_def = 0; + if (!pr->file_error) pr->file_error = file_error; @@ -220,8 +222,8 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) (dfunction_t *) (base + pr->progs->ofs_functions); pr->pr_strings = (char *) base + pr->progs->ofs_strings; pr->pr_stringsize = (char *) heap + pr->zone_size - (char *) base; - pr->pr_globaldefs = (ddef_t *) (base + pr->progs->ofs_globaldefs); - pr->pr_fielddefs = (ddef_t *) (base + pr->progs->ofs_fielddefs); + pr->pr_globalddefs = (ddef_t *) (base + pr->progs->ofs_globaldefs); + pr->pr_fieldddefs = (ddef_t *) (base + pr->progs->ofs_fielddefs); pr->pr_statements = (dstatement_t *) (base + pr->progs->ofs_statements); pr->pr_globals = (pr_type_t *) (base + pr->progs->ofs_globals); @@ -272,24 +274,58 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) Hash_Add (pr->function_hash, &pr->pr_functions[i]); } + if (pr->pr_globaldefs) { + free (pr->pr_globaldefs); + } + pr->pr_globaldefs = calloc (pr->progs->numglobaldefs, sizeof (pr_def_t)); + for (i = 0; i < pr->progs->numglobaldefs; i++) { - pr->pr_globaldefs[i].type = LittleShort (pr->pr_globaldefs[i].type); - pr->pr_globaldefs[i].ofs = LittleShort (pr->pr_globaldefs[i].ofs); - pr->pr_globaldefs[i].s_name = LittleLong (pr->pr_globaldefs[i].s_name); + pr->pr_globalddefs[i].type = LittleShort (pr->pr_globalddefs[i].type); + pr->pr_globalddefs[i].ofs = LittleShort (pr->pr_globalddefs[i].ofs); + pr->pr_globalddefs[i].s_name = LittleLong (pr->pr_globalddefs[i].s_name); + + pr->pr_globaldefs[i].type = pr->pr_globalddefs[i].type; + pr->pr_globaldefs[i].ofs = pr->pr_globalddefs[i].ofs; + pr->pr_globaldefs[i].name = pr->pr_globalddefs[i].s_name; Hash_Add (pr->global_hash, &pr->pr_globaldefs[i]); } + if (pr->pr_fielddefs) { + free (pr->pr_fielddefs); + } + pr->pr_fielddefs = calloc (pr->progs->numfielddefs, sizeof (pr_def_t)); for (i = 0; i < pr->progs->numfielddefs; i++) { - pr->pr_fielddefs[i].type = LittleShort (pr->pr_fielddefs[i].type); + pr->pr_fieldddefs[i].type = LittleShort (pr->pr_fieldddefs[i].type); if (pr->pr_fielddefs[i].type & DEF_SAVEGLOBAL) PR_Error (pr, "PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); - pr->pr_fielddefs[i].ofs = LittleShort (pr->pr_fielddefs[i].ofs); - pr->pr_fielddefs[i].s_name = LittleLong (pr->pr_fielddefs[i].s_name); + pr->pr_fieldddefs[i].ofs = LittleShort (pr->pr_fieldddefs[i].ofs); + pr->pr_fieldddefs[i].s_name = LittleLong (pr->pr_fieldddefs[i].s_name); + + pr->pr_fielddefs[i].type = pr->pr_fieldddefs[i].type; + pr->pr_fielddefs[i].ofs = pr->pr_fieldddefs[i].ofs; + pr->pr_fielddefs[i].name = pr->pr_fieldddefs[i].s_name; Hash_Add (pr->field_hash, &pr->pr_fielddefs[i]); } for (i = 0; i < pr->progs->numglobals; i++) ((int *) pr->pr_globals)[i] = LittleLong (((int *) pr->pr_globals)[i]); + + xdefs_def = PR_FindGlobal (pr, ".xdefs"); + if (xdefs_def) { + pr_xdefs_t *xdefs = &G_STRUCT (pr, pr_xdefs_t, xdefs_def->ofs); + xdef_t *xdef = &G_STRUCT (pr, xdef_t, xdefs->xdefs); + pr_def_t *def; + for (def = pr->pr_globaldefs, i = 0; i < pr->progs->numglobaldefs; + i++, xdef++, def++) { + def->ofs = xdef->ofs; + def->type_encoding = xdef->type; + } + for (def = pr->pr_fielddefs, i = 0; i < pr->progs->numfielddefs; + i++, xdef++, def++) { + def->ofs = xdef->ofs; + def->type_encoding = xdef->type; + } + } } VISIBLE void diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index 15185b37d..0ad3fab4b 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -1535,7 +1535,7 @@ check_global (progs_t *pr, dstatement_t *st, opcode_t *op, etype_t type, unsigned short operand, int check_denorm) { const char *msg; - ddef_t *def; + pr_def_t *def; switch (type) { case ev_short: diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index a8259ee78..69219651f 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -71,7 +71,7 @@ static const char * PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) { static dstring_t *line = 0; - ddef_t *def; + pr_def_t *def; dfunction_t *f; if (!line) @@ -93,7 +93,7 @@ PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) break; case ev_field: def = PR_FieldAtOfs (pr, val->integer_var); - dsprintf (line, "%s", PR_GetString (pr, def->s_name)); + dsprintf (line, "%s", PR_GetString (pr, def->name)); break; case ev_void: dstring_copystr (line, "void"); @@ -131,9 +131,9 @@ ED_EntityDict (progs_t *pr, edict_t *ed) if (!ed->free) { for (i = 0; i < pr->progs->numfielddefs; i++) { - ddef_t *d = &pr->pr_fielddefs[i]; + pr_def_t *d = &pr->pr_fielddefs[i]; - name = PR_GetString (pr, d->s_name); + name = PR_GetString (pr, d->name); if (!name[0]) continue; // skip unnamed fields if (name[strlen (name) - 2] == '_') @@ -169,7 +169,7 @@ ED_GlobalsDict (progs_t *pr) pr_uint_t i; const char *name; const char *value; - ddef_t *def; + pr_def_t *def; int type; for (i = 0; i < pr->progs->numglobaldefs; i++) { @@ -182,7 +182,7 @@ ED_GlobalsDict (progs_t *pr) if (type != ev_string && type != ev_float && type != ev_entity) continue; - name = PR_GetString (pr, def->s_name); + name = PR_GetString (pr, def->name); value = PR_UglyValueString (pr, type, &pr->pr_globals[def->ofs]); PL_D_AddObject (globals, name, PL_NewString (value)); } @@ -222,11 +222,11 @@ ED_NewString (progs_t *pr, const char *string) returns false if error */ VISIBLE qboolean -ED_ParseEpair (progs_t *pr, pr_type_t *base, ddef_t *key, const char *s) +ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s) { int i; char *string; - ddef_t *def; + pr_def_t *def; char *v, *w; pr_type_t *d; dfunction_t *func; @@ -357,8 +357,8 @@ ED_ConvertToPlist (script_t *script, int nohack) VISIBLE void ED_InitGlobals (progs_t *pr, plitem_t *globals) { - ddef_t vector_def; - ddef_t *global; + pr_def_t vector_def; + pr_def_t *global; plitem_t *keys; int count; const char *global_name; @@ -405,7 +405,7 @@ ED_InitGlobals (progs_t *pr, plitem_t *globals) VISIBLE void ED_InitEntity (progs_t *pr, plitem_t *entity, edict_t *ent) { - ddef_t *field; + pr_def_t *field; plitem_t *keys; const char *field_name; const char *value; diff --git a/libs/gamecode/pr_resolve.c b/libs/gamecode/pr_resolve.c index 3238e774e..07ef44d60 100644 --- a/libs/gamecode/pr_resolve.c +++ b/libs/gamecode/pr_resolve.c @@ -52,10 +52,10 @@ #include "compat.h" -ddef_t * -PR_GlobalAtOfs (progs_t * pr, pr_int_t ofs) +pr_def_t * +PR_GlobalAtOfs (progs_t * pr, pointer_t ofs) { - ddef_t *def; + pr_def_t *def; pr_uint_t i; for (i = 0; i < pr->progs->numglobaldefs; i++) { @@ -66,10 +66,10 @@ PR_GlobalAtOfs (progs_t * pr, pr_int_t ofs) return NULL; } -VISIBLE ddef_t * -PR_FieldAtOfs (progs_t * pr, pr_int_t ofs) +VISIBLE pr_def_t * +PR_FieldAtOfs (progs_t * pr, pointer_t ofs) { - ddef_t *def; + pr_def_t *def; pr_uint_t i; for (i = 0; i < pr->progs->numfielddefs; i++) { @@ -80,13 +80,13 @@ PR_FieldAtOfs (progs_t * pr, pr_int_t ofs) return NULL; } -VISIBLE ddef_t * +VISIBLE pr_def_t * PR_FindField (progs_t * pr, const char *name) { return Hash_Find (pr->field_hash, name); } -VISIBLE ddef_t * +VISIBLE pr_def_t * PR_FindGlobal (progs_t * pr, const char *name) { return Hash_Find (pr->global_hash, name); @@ -108,7 +108,7 @@ VISIBLE int PR_ResolveGlobals (progs_t *pr) { const char *sym; - ddef_t *def; + pr_def_t *def; int i; if (pr->progs->version == PROG_ID_VERSION) { @@ -180,7 +180,7 @@ int PR_AccessField (progs_t *pr, const char *name, etype_t type, const char *file, int line) { - ddef_t *def = PR_FindField (pr, name); + pr_def_t *def = PR_FindField (pr, name); if (!def) PR_Error (pr, "undefined field %s accessed at %s:%d", name, file, line); diff --git a/libs/ruamoko/pr_cmds.c b/libs/ruamoko/pr_cmds.c index 8352228d4..8c6aa3d58 100644 --- a/libs/ruamoko/pr_cmds.c +++ b/libs/ruamoko/pr_cmds.c @@ -255,7 +255,7 @@ PF_Find (progs_t *pr) int i; // ev_vector int e, f; etype_t type; - ddef_t *field_def; + pr_def_t *field_def; edict_t *ed; e = P_EDICTNUM (pr, 0); @@ -596,7 +596,7 @@ static void PF_PR_SetField (progs_t *pr) { edict_t *ent = P_EDICT (pr, 0); - ddef_t *field = PR_FindField (pr, P_GSTRING (pr, 1)); + pr_def_t *field = PR_FindField (pr, P_GSTRING (pr, 1)); const char *value = P_GSTRING (pr, 2); R_INT (pr) = 0; diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index ed3a1d78b..efb193bc8 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1550,7 +1550,7 @@ static void rua_PR_FindGlobal (progs_t *pr) { const char *name = P_GSTRING (pr, 0); - ddef_t *def; + pr_def_t *def; R_POINTER (pr) = 0; def = PR_FindGlobal (pr, name); @@ -1654,7 +1654,7 @@ rua_init_finish (progs_t *pr) static int rua_init_runtime (progs_t *pr) { - ddef_t *def; + pr_def_t *def; unsigned i; if (!pr->selector_hash) diff --git a/nq/source/sv_progs.c b/nq/source/sv_progs.c index 7e98550d4..60ee75368 100644 --- a/nq/source/sv_progs.c +++ b/nq/source/sv_progs.c @@ -379,7 +379,7 @@ set_address (sv_def_t *def, void *address) static int resolve_globals (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { @@ -425,7 +425,7 @@ resolve_functions (progs_t *pr, sv_def_t *def, int mode) static int resolve_fields (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { diff --git a/qw/source/sv_pr_qwe.c b/qw/source/sv_pr_qwe.c index 0c844abd8..7c8a46d84 100644 --- a/qw/source/sv_pr_qwe.c +++ b/qw/source/sv_pr_qwe.c @@ -551,7 +551,7 @@ static int qwe_load_finish (progs_t *pr) { edict_t *ent; - ddef_t *targetname; + pr_def_t *targetname; targetname = PR_FindField (pr, "targetname"); ent = EDICT_NUM (pr, 0); diff --git a/qw/source/sv_progs.c b/qw/source/sv_progs.c index e4856f69b..f5abeed3f 100644 --- a/qw/source/sv_progs.c +++ b/qw/source/sv_progs.c @@ -389,7 +389,7 @@ set_address (sv_def_t *def, void *address) static int resolve_globals (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { @@ -435,7 +435,7 @@ resolve_functions (progs_t *pr, sv_def_t *def, int mode) static int resolve_fields (progs_t *pr, sv_def_t *def, int mode) { - ddef_t *ddef; + pr_def_t *ddef; int ret = 1; if (mode == 2) { diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 89dbb50fa..79024313b 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -52,14 +52,14 @@ static int cmp (const void *_a, const void *_b) { - const ddef_t *a = (const ddef_t *)_a; - const ddef_t *b = (const ddef_t *)_b; + const pr_def_t *a = (const pr_def_t *)_a; + const pr_def_t *b = (const pr_def_t *)_b; return a->ofs - b->ofs; } static void -dump_def (progs_t *pr, ddef_t *def, int indent) +dump_def (progs_t *pr, pr_def_t *def, int indent) { const char *name; const char *type; @@ -69,10 +69,10 @@ dump_def (progs_t *pr, ddef_t *def, int indent) const char *str; int saveglobal; - if (!def->type && !def->ofs && !def->s_name) + if (!def->type && !def->ofs && !def->name) return; - name = PR_GetString (pr, def->s_name); + name = PR_GetString (pr, def->name); type = pr_type_name[def->type & ~DEF_SAVEGLOBAL]; saveglobal = (def->type & DEF_SAVEGLOBAL) != 0; offset = def->ofs; @@ -148,15 +148,15 @@ dump_def (progs_t *pr, ddef_t *def, int indent) break; } } - printf ("%*s %x %d %s %s%s\n", indent * 12, "", - offset, saveglobal, name, type, comment); + printf ("%*s %x %d %s %s:%x %s\n", indent * 12, "", + offset, saveglobal, name, type, def->type_encoding, comment); } void dump_globals (progs_t *pr) { unsigned int i; - ddef_t *global_defs = pr->pr_globaldefs; + pr_def_t *global_defs = pr->pr_globaldefs; if (sorted) { global_defs = malloc (pr->progs->numglobaldefs * sizeof (ddef_t)); @@ -165,7 +165,7 @@ dump_globals (progs_t *pr) qsort (global_defs, pr->progs->numglobaldefs, sizeof (ddef_t), cmp); } for (i = 0; i < pr->progs->numglobaldefs; i++) { - ddef_t *def = &global_defs[i]; + pr_def_t *def = &global_defs[i]; dump_def (pr, def, 0); } } @@ -180,9 +180,9 @@ dump_fields (progs_t *pr) const char *comment; for (i = 0; i < pr->progs->numfielddefs; i++) { - ddef_t *def = &pr->pr_fielddefs[i]; + pr_def_t *def = &pr->pr_fielddefs[i]; - name = PR_GetString (pr, def->s_name); + name = PR_GetString (pr, def->name); type = pr_type_name[def->type & ~DEF_SAVEGLOBAL]; offset = def->ofs; @@ -516,7 +516,7 @@ dump_types (progs_t *pr) { qfo_mspace_t spaces[qfo_num_spaces]; qfo_t qfo; - ddef_t *encodings_def; + pr_def_t *encodings_def; qfot_type_encodings_t *encodings; encodings_def = PR_FindGlobal (pr, ".type_encodings"); diff --git a/tools/qfcc/source/dump_modules.c b/tools/qfcc/source/dump_modules.c index d55195aaa..6bb559003 100644 --- a/tools/qfcc/source/dump_modules.c +++ b/tools/qfcc/source/dump_modules.c @@ -205,11 +205,11 @@ dump_modules (progs_t *pr) unsigned int i; for (i = 0; i < pr->progs->numglobaldefs; i++) { - ddef_t *def = &pr->pr_globaldefs[i]; + pr_def_t *def = &pr->pr_globaldefs[i]; const char *name = ""; - if (PR_StringValid (pr, def->s_name)) - name = PR_GetString (pr, def->s_name); + if (PR_StringValid (pr, def->name)) + name = PR_GetString (pr, def->name); if (strcmp (name, "_OBJ_MODULE") == 0) { printf ("module @ %x\n", def->ofs); dump_module (pr, &G_STRUCT (pr, pr_module_t, def->ofs)); diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 79c4effeb..f79bed688 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -926,6 +926,7 @@ qfo_to_progs (qfo_t *qfo, int *size) progs->numglobals = RUP (progs->numglobals, type_xdef.alignment); xdefs_start = progs->numglobals; progs->numglobals += progs->numglobaldefs * type_size (&type_xdef); + progs->numglobals += progs->numfielddefs * type_size (&type_xdef); progs->entityfields = qfo->spaces[qfo_entity_space].data_size; *size += progs->numstatements * sizeof (dstatement_t); *size += progs->numglobaldefs * sizeof (ddef_t); @@ -1012,10 +1013,6 @@ qfo_to_progs (qfo_t *qfo, int *size) globaldefs++; } - for (i = 0; i < qfo->spaces[qfo_type_space].num_defs; i++) { - qfo->spaces[qfo_type_space].defs[i].offset += type_data - globals; - } - for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++) { convert_def (qfo, qfo->spaces[qfo_entity_space].defs + i, fielddefs + i); @@ -1044,21 +1041,27 @@ qfo_to_progs (qfo_t *qfo, int *size) encodings->size = qfo->spaces[qfo_type_space].data_size; } if (xdefs_def) { - int xdef_data_size = type_size (&type_xdef); - pr_xdefs_t *xdefs = (pr_xdefs_t *) &globals[xdefs_def->offset]; + pr_xdefs_t *xdefs = (pr_xdefs_t *) &globals[xdefs_def->offset]; + xdef_t *xdef = (xdef_t *) xdef_data; xdefs->xdefs = xdefs_start; - xdefs->num_xdefs = progs->numglobaldefs; - for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++) { + xdefs->num_xdefs = progs->numglobaldefs + progs->numfielddefs; + for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; + i++, xdef++) { qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i; - xdef_data[0].pointer_var = def->type + type_encodings_start; - xdef_data[1].pointer_var = def->offset; - xdef_data += xdef_data_size; + xdef->type = def->type + type_encodings_start; + xdef->ofs = def->offset; } - for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++) { + for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; + i++, xdef++) { qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + i; - xdef_data[0].pointer_var = def->type + type_encodings_start; - xdef_data[1].pointer_var = def->offset; - xdef_data += xdef_data_size; + xdef->type = def->type + type_encodings_start; + xdef->ofs = def->offset; + } + for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; + i++, xdef++) { + qfo_def_t *def = qfo->spaces[qfo_entity_space].defs + i; + xdef->type = def->type + type_encodings_start; + xdef->ofs = def->offset; } } @@ -1108,7 +1111,7 @@ qfo_to_sym (qfo_t *qfo, int *size) pr_auxfunction_t *auxfuncs; pr_auxfunction_t *aux; pr_lineno_t *linenos; - ddef_t *locals, *ld; + pr_def_t *locals, *ld; *size = sizeof (pr_debug_header_t); sym = calloc (1, *size); @@ -1129,12 +1132,12 @@ qfo_to_sym (qfo_t *qfo, int *size) *size += sym->num_auxfunctions * sizeof (pr_auxfunction_t); *size += sym->num_linenos * sizeof (pr_lineno_t); - *size += sym->num_locals * sizeof (ddef_t); + *size += sym->num_locals * sizeof (pr_def_t); sym = realloc (sym, *size); auxfuncs = (pr_auxfunction_t *)(sym + 1); linenos = (pr_lineno_t *)(auxfuncs + sym->num_auxfunctions); - locals = (ddef_t *)(linenos + sym->num_linenos); + locals = (pr_def_t *)(linenos + sym->num_linenos); sym->auxfunctions = (char *) auxfuncs - (char *) sym; sym->linenos = (char *) linenos - (char *) sym; @@ -1162,8 +1165,13 @@ qfo_to_sym (qfo_t *qfo, int *size) qfo->lines[func->line_info].fa.func = aux - auxfuncs; if (num_locals) { aux->local_defs = ld - locals; - for (j = 0; j < num_locals; j++) - convert_def (qfo, def++, ld++); + for (j = 0; j < num_locals; j++, def++, ld++) { + ld->type = get_def_type (qfo, def->type); + ld->type = def->type; + ld->ofs = def->offset; + ld->name = def->name; + ld->type_encoding = def->type; + } } aux->num_locals = num_locals; //FIXME check type diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index be14d144f..e113912fb 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -256,6 +256,9 @@ convert_qfo (void) { int size; int i; + xdef_t *xdef = 0; + pr_xdefs_t *xdefs = 0; + ddef_t *xdefs_def = 0; pr.progs = qfo_to_progs (qfo, &size); @@ -264,20 +267,52 @@ convert_qfo (void) pr.pr_strings = P (char, ofs_strings); pr.pr_stringsize = pr.progs->numstrings; pr.pr_functions = P (dfunction_t, ofs_functions); - pr.pr_globaldefs = P (ddef_t, ofs_globaldefs); - pr.pr_fielddefs = P (ddef_t, ofs_fielddefs); + pr.pr_globalddefs = P (ddef_t, ofs_globaldefs); + pr.pr_fieldddefs = P (ddef_t, ofs_fielddefs); pr.pr_globals = P (pr_type_t, ofs_globals); pr.globals_size = pr.progs->numglobals; pr.pr_edict_size = max (1, pr.progs->entityfields) * 4; pr.pr_edictareasize = 1 * pr.pr_edict_size; #undef P + pr.pr_globaldefs = malloc ((pr.progs->numglobaldefs + + pr.progs->numfielddefs) + * sizeof (pr_def_t)); + // can't use PR_FindGlobal yet as pr_globaldefs is still uninitialized + for (i = 0; i < (int) pr.progs->numglobaldefs; i++) { + ddef_t *ddef = pr.pr_globalddefs + i; + if (!strcmp (PR_GetString (&pr, ddef->s_name), ".xdefs")) { + xdefs_def = ddef; + break; + } + } + if (xdefs_def) { + xdefs = &G_STRUCT (&pr, pr_xdefs_t, xdefs_def->ofs); + xdef = &G_STRUCT (&pr, xdef_t, xdefs->xdefs); + } + for (i = 0; i < (int) pr.progs->numglobaldefs; i++, xdef++) { + ddef_t *ddef = pr.pr_globalddefs + i; + pr_def_t *def = pr.pr_globaldefs + i; + def->type = ddef->type; + def->ofs = xdefs ? xdef->ofs : ddef->ofs; + def->name = ddef->s_name; + def->type_encoding = xdefs ? xdef->type : 0; + } + for (i = 0; i < (int) pr.progs->numfielddefs; i++, xdef++) { + ddef_t *ddef = pr.pr_fieldddefs + i; + pr_def_t *def = pr.pr_fielddefs + i; + def->type = ddef->type; + def->ofs = xdefs ? xdef->ofs : ddef->ofs; + def->name = ddef->s_name; + def->type_encoding = xdefs ? xdef->type : 0; + } + if (verbosity) { pr.debug = qfo_to_sym (qfo, &size); #define P(t,o) ((t *)((char *)pr.debug + pr.debug->o)) pr.auxfunctions = P (pr_auxfunction_t, auxfunctions); pr.linenos = P (pr_lineno_t, linenos); - pr.local_defs = P (ddef_t, locals); + pr.local_defs = P (pr_def_t, locals); #undef P pr.local_defs = calloc (qfo->num_defs, sizeof (ddef_t)); From 806af854475f491c6facb6afb68b15e2ea9672e6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 22 Feb 2020 22:44:08 +0900 Subject: [PATCH 033/444] Remove reference to ddef_t from progs.h This cleans up some horrible names and redundant fields that were a result of the transition to pr_def_t --- include/QF/progs.h | 2 -- libs/gamecode/pr_load.c | 35 ++++++++++++++++++----------------- tools/qfcc/source/qfprogs.c | 13 ++++++++----- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index e93bea597..a413b2f25 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1616,8 +1616,6 @@ struct progs_s { bfunction_t *function_table; char *pr_strings; int pr_stringsize; - ddef_t *pr_globalddefs; - ddef_t *pr_fieldddefs; pr_def_t *pr_globaldefs; pr_def_t *pr_fielddefs; dstatement_t *pr_statements; diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index eec948d45..99136ed4f 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -120,7 +120,8 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) byte *base; byte *heap; pr_def_t *xdefs_def = 0; - + ddef_t *global_ddefs; + ddef_t *field_ddefs; if (!pr->file_error) pr->file_error = file_error; @@ -222,8 +223,8 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) (dfunction_t *) (base + pr->progs->ofs_functions); pr->pr_strings = (char *) base + pr->progs->ofs_strings; pr->pr_stringsize = (char *) heap + pr->zone_size - (char *) base; - pr->pr_globalddefs = (ddef_t *) (base + pr->progs->ofs_globaldefs); - pr->pr_fieldddefs = (ddef_t *) (base + pr->progs->ofs_fielddefs); + global_ddefs = (ddef_t *) (base + pr->progs->ofs_globaldefs); + field_ddefs = (ddef_t *) (base + pr->progs->ofs_fielddefs); pr->pr_statements = (dstatement_t *) (base + pr->progs->ofs_statements); pr->pr_globals = (pr_type_t *) (base + pr->progs->ofs_globals); @@ -280,13 +281,13 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) pr->pr_globaldefs = calloc (pr->progs->numglobaldefs, sizeof (pr_def_t)); for (i = 0; i < pr->progs->numglobaldefs; i++) { - pr->pr_globalddefs[i].type = LittleShort (pr->pr_globalddefs[i].type); - pr->pr_globalddefs[i].ofs = LittleShort (pr->pr_globalddefs[i].ofs); - pr->pr_globalddefs[i].s_name = LittleLong (pr->pr_globalddefs[i].s_name); + global_ddefs[i].type = LittleShort (global_ddefs[i].type); + global_ddefs[i].ofs = LittleShort (global_ddefs[i].ofs); + global_ddefs[i].s_name = LittleLong (global_ddefs[i].s_name); - pr->pr_globaldefs[i].type = pr->pr_globalddefs[i].type; - pr->pr_globaldefs[i].ofs = pr->pr_globalddefs[i].ofs; - pr->pr_globaldefs[i].name = pr->pr_globalddefs[i].s_name; + pr->pr_globaldefs[i].type = global_ddefs[i].type; + pr->pr_globaldefs[i].ofs = global_ddefs[i].ofs; + pr->pr_globaldefs[i].name = global_ddefs[i].s_name; Hash_Add (pr->global_hash, &pr->pr_globaldefs[i]); } @@ -295,15 +296,15 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) } pr->pr_fielddefs = calloc (pr->progs->numfielddefs, sizeof (pr_def_t)); for (i = 0; i < pr->progs->numfielddefs; i++) { - pr->pr_fieldddefs[i].type = LittleShort (pr->pr_fieldddefs[i].type); - if (pr->pr_fielddefs[i].type & DEF_SAVEGLOBAL) - PR_Error (pr, "PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL"); - pr->pr_fieldddefs[i].ofs = LittleShort (pr->pr_fieldddefs[i].ofs); - pr->pr_fieldddefs[i].s_name = LittleLong (pr->pr_fieldddefs[i].s_name); + field_ddefs[i].type = LittleShort (field_ddefs[i].type); + if (field_ddefs[i].type & DEF_SAVEGLOBAL) + PR_Error (pr, "PR_LoadProgs: DEF_SAVEGLOBAL on field def %zd", i); + field_ddefs[i].ofs = LittleShort (field_ddefs[i].ofs); + field_ddefs[i].s_name = LittleLong (field_ddefs[i].s_name); - pr->pr_fielddefs[i].type = pr->pr_fieldddefs[i].type; - pr->pr_fielddefs[i].ofs = pr->pr_fieldddefs[i].ofs; - pr->pr_fielddefs[i].name = pr->pr_fieldddefs[i].s_name; + pr->pr_fielddefs[i].type = field_ddefs[i].type; + pr->pr_fielddefs[i].ofs = field_ddefs[i].ofs; + pr->pr_fielddefs[i].name = field_ddefs[i].s_name; Hash_Add (pr->field_hash, &pr->pr_fielddefs[i]); } diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index e113912fb..28d9141c5 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -259,6 +259,8 @@ convert_qfo (void) xdef_t *xdef = 0; pr_xdefs_t *xdefs = 0; ddef_t *xdefs_def = 0; + ddef_t *global_ddefs; + ddef_t *field_ddefs; pr.progs = qfo_to_progs (qfo, &size); @@ -267,8 +269,8 @@ convert_qfo (void) pr.pr_strings = P (char, ofs_strings); pr.pr_stringsize = pr.progs->numstrings; pr.pr_functions = P (dfunction_t, ofs_functions); - pr.pr_globalddefs = P (ddef_t, ofs_globaldefs); - pr.pr_fieldddefs = P (ddef_t, ofs_fielddefs); + global_ddefs = P (ddef_t, ofs_globaldefs); + field_ddefs = P (ddef_t, ofs_fielddefs); pr.pr_globals = P (pr_type_t, ofs_globals); pr.globals_size = pr.progs->numglobals; pr.pr_edict_size = max (1, pr.progs->entityfields) * 4; @@ -278,9 +280,10 @@ convert_qfo (void) pr.pr_globaldefs = malloc ((pr.progs->numglobaldefs + pr.progs->numfielddefs) * sizeof (pr_def_t)); + pr.pr_fielddefs = pr.pr_globaldefs + pr.progs->numglobaldefs; // can't use PR_FindGlobal yet as pr_globaldefs is still uninitialized for (i = 0; i < (int) pr.progs->numglobaldefs; i++) { - ddef_t *ddef = pr.pr_globalddefs + i; + ddef_t *ddef = global_ddefs + i; if (!strcmp (PR_GetString (&pr, ddef->s_name), ".xdefs")) { xdefs_def = ddef; break; @@ -291,7 +294,7 @@ convert_qfo (void) xdef = &G_STRUCT (&pr, xdef_t, xdefs->xdefs); } for (i = 0; i < (int) pr.progs->numglobaldefs; i++, xdef++) { - ddef_t *ddef = pr.pr_globalddefs + i; + ddef_t *ddef = global_ddefs + i; pr_def_t *def = pr.pr_globaldefs + i; def->type = ddef->type; def->ofs = xdefs ? xdef->ofs : ddef->ofs; @@ -299,7 +302,7 @@ convert_qfo (void) def->type_encoding = xdefs ? xdef->type : 0; } for (i = 0; i < (int) pr.progs->numfielddefs; i++, xdef++) { - ddef_t *ddef = pr.pr_fieldddefs + i; + ddef_t *ddef = field_ddefs + i; pr_def_t *def = pr.pr_fielddefs + i; def->type = ddef->type; def->ofs = xdefs ? xdef->ofs : ddef->ofs; From 3aabfa71d986e75d7489dd58f3cefa3ce5a8b608 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 22 Feb 2020 23:33:56 +0900 Subject: [PATCH 034/444] Find lost type encoding relocations I have no idea why I thought it was a good idea to delete those lines. Yay for regression tests, though. --- tools/qfcc/source/obj_file.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index f79bed688..8d7250abc 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -1013,6 +1013,10 @@ qfo_to_progs (qfo_t *qfo, int *size) globaldefs++; } + for (i = 0; i < qfo->spaces[qfo_type_space].num_defs; i++) { + qfo->spaces[qfo_type_space].defs[i].offset += type_encodings_start; + } + for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++) { convert_def (qfo, qfo->spaces[qfo_entity_space].defs + i, fielddefs + i); From 52d54f98bfecd16674ec71bae798ad36bc3150db Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 22 Feb 2020 23:41:09 +0900 Subject: [PATCH 035/444] Fix some issues in the typedef test It wasn't being strict enough in the test (but was good enough to catch the relocation error, at least) and was printing the alias name incorrectly. --- tools/qfcc/test/typedef.r | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/test/typedef.r b/tools/qfcc/test/typedef.r index bb5d52e4a..e6e80a92b 100644 --- a/tools/qfcc/test/typedef.r +++ b/tools/qfcc/test/typedef.r @@ -22,10 +22,12 @@ next_type (qfot_type_t *type) } int -check_alias (qfot_type_t *alias) +check_alias (string name, qfot_type_t *alias) { - if (alias.meta != ty_basic && alias.t.type != ev_pointer) { - printf ("%s is not a *int alias\n", alias.t.alias.name); + if (alias.meta != ty_basic || alias.t.type != ev_pointer + || alias.t.fldptr.aux_type.meta != ty_basic + || alias.t.fldptr.aux_type.t.type != ev_integer) { + printf ("%s is not a *int alias\n", name); return 0; } return 1; @@ -47,10 +49,12 @@ main (void) type = next_type (type)) { if (type.meta == ty_alias) { if (type.t.alias.name == "foo") { - found_foo = check_alias (type.t.alias.aux_type); + found_foo = check_alias (type.t.alias.name, + type.t.alias.aux_type); } if (type.t.alias.name == "bar") { - found_bar = check_alias (type.t.alias.aux_type); + found_bar = check_alias (type.t.alias.name, + type.t.alias.aux_type); } } } From f8b1a3a89fdb40cdf4463c467388dd2ddd365071 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 11:41:19 +0900 Subject: [PATCH 036/444] Return the previous sys print callbacks This allows for temporary overrides. --- include/QF/sys.h | 4 ++-- libs/util/sys.c | 8 ++++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/include/QF/sys.h b/include/QF/sys.h index 10ef6999f..76b6ad844 100644 --- a/include/QF/sys.h +++ b/include/QF/sys.h @@ -65,8 +65,8 @@ int Sys_mkdir (const char *path); typedef void (*sys_printf_t) (const char *fmt, va_list args) __attribute__((format(printf, 1, 0))); typedef void (*sys_error_t) (void *data); -void Sys_SetStdPrintf (sys_printf_t func); -void Sys_SetErrPrintf (sys_printf_t func); +sys_printf_t Sys_SetStdPrintf (sys_printf_t func); +sys_printf_t Sys_SetErrPrintf (sys_printf_t func); void Sys_PushErrorHandler (sys_error_t func, void *data); void Sys_PopErrorHandler (void); diff --git a/libs/util/sys.c b/libs/util/sys.c index b2e28f71d..62ddfa35b 100644 --- a/libs/util/sys.c +++ b/libs/util/sys.c @@ -240,16 +240,20 @@ Sys_FileExists (const char *path) for want of a better name, but it sets the function pointer for the actual implementation of Sys_Printf. */ -VISIBLE void +VISIBLE sys_printf_t Sys_SetStdPrintf (sys_printf_t func) { + sys_printf_t prev = sys_std_printf_function; sys_std_printf_function = func; + return prev; } -VISIBLE void +VISIBLE sys_printf_t Sys_SetErrPrintf (sys_printf_t func) { + sys_printf_t prev = sys_err_printf_function; sys_err_printf_function = func; + return prev; } void From 6c6433dea5bb6643747960f77d430afaf6c11ff9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 11:52:35 +0900 Subject: [PATCH 037/444] Fetch the def name only once when scanning Not that speed is critical at this point, but it feels better. --- tools/qfcc/source/obj_file.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 8d7250abc..15fc0fdf0 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -997,9 +997,10 @@ qfo_to_progs (qfo_t *qfo, int *size) for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++) { qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i; - if (!strcmp (QFO_GETSTR (qfo, def->name), ".type_encodings")) + const char *defname = QFO_GETSTR (qfo, def->name); + if (!strcmp (defname, ".type_encodings")) types_def = def; - if (!strcmp (QFO_GETSTR (qfo, def->name), ".xdefs")) + if (!strcmp (defname, ".xdefs")) xdefs_def = def; convert_def (qfo, def, globaldefs++); } From 155a633ebe0455b334e8d5605055fe4a5653e638 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 11:53:57 +0900 Subject: [PATCH 038/444] Include extended defs data in the size report --- tools/qfcc/source/obj_file.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 15fc0fdf0..735a68ab0 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -891,6 +891,8 @@ qfo_to_progs (qfo_t *qfo, int *size) int xdefs_start; unsigned big_locals = 0; int big_func = 0; + pr_xdefs_t *xdefs; + xdef_t *xdef; *size = RUP (sizeof (dprograms_t), 16); progs = calloc (1, *size); @@ -1046,8 +1048,8 @@ qfo_to_progs (qfo_t *qfo, int *size) encodings->size = qfo->spaces[qfo_type_space].data_size; } if (xdefs_def) { - pr_xdefs_t *xdefs = (pr_xdefs_t *) &globals[xdefs_def->offset]; - xdef_t *xdef = (xdef_t *) xdef_data; + xdefs = (pr_xdefs_t *) &globals[xdefs_def->offset]; + xdef = (xdef_t *) xdef_data; xdefs->xdefs = xdefs_start; xdefs->num_xdefs = progs->numglobaldefs + progs->numfielddefs; for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; @@ -1091,7 +1093,7 @@ qfo_to_progs (qfo_t *qfo, int *size) printf ("%6i statements\n", progs->numstatements); printf ("%6i functions\n", progs->numfunctions); printf ("%6i global defs\n", progs->numglobaldefs); - printf ("%6i fielddefs\n", progs->numfielddefs); + printf ("%6i field defs\n", progs->numfielddefs); printf ("%6i globals\n", progs->numglobals); printf (" %6i near globals\n", near_data_size); printf (" %6i locals size%s\n", locals_size, big_function); @@ -1099,6 +1101,10 @@ qfo_to_progs (qfo_t *qfo, int *size) qfo->spaces[qfo_far_data_space].data_size); printf (" %6i type globals\n", qfo->spaces[qfo_type_space].data_size); + if (xdefs) { + printf (" %6i extended defs\n", + xdefs->num_xdefs * type_size (&type_xdef)); + } printf ("%6i entity fields\n", progs->entityfields); } From 81293d98dd2d236d647c1b6e2e72a33ba63b2bc7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 14:39:02 +0900 Subject: [PATCH 039/444] Fix qfo line info dumping The addition of xdef data has made qfo_to_progs unusable in qfprogs, resulting in various invalid memory accesses. It always was an ugly hack anyway, so this is the first step to proper qfo support in qfprogs. --- tools/qfcc/include/qfprogs.h | 1 + tools/qfcc/source/dump_lines.c | 164 ++++++++++++++++++++++++++------- tools/qfcc/source/qfprogs.c | 94 +------------------ 3 files changed, 139 insertions(+), 120 deletions(-) diff --git a/tools/qfcc/include/qfprogs.h b/tools/qfcc/include/qfprogs.h index 09fade09d..bb64b3fb6 100644 --- a/tools/qfcc/include/qfprogs.h +++ b/tools/qfcc/include/qfprogs.h @@ -56,6 +56,7 @@ void dump_strings (struct progs_s *pr); void qfo_globals (struct qfo_s *qfo); void qfo_functions (struct qfo_s *qfo); +void qfo_lines (struct qfo_s *qfo); void qfo_relocs (struct qfo_s *qfo); void qfo_types (struct qfo_s *qfo); diff --git a/tools/qfcc/source/dump_lines.c b/tools/qfcc/source/dump_lines.c index 847bdb5c2..ae504c03d 100644 --- a/tools/qfcc/source/dump_lines.c +++ b/tools/qfcc/source/dump_lines.c @@ -41,49 +41,151 @@ #include #include "QF/progs.h" +#include "QF/pr_type.h" +#include "obj_file.h" #include "qfprogs.h" -void -dump_lines (progs_t *pr) +typedef struct { + const char *source_name; + const char *source_file; + pr_uint_t source_line; + pr_int_t first_statement; + pointer_t return_type; + pr_uint_t local_defs; + pr_uint_t num_locals; + pr_uint_t line_info; + pr_uint_t function; +} func_data_t; + +typedef func_data_t *(*get_func_data_t)(unsigned func, void *data); + +static func_data_t * +progs_get_func_data (unsigned func_index, void *data) { - unsigned int i, line, addr; - pr_lineno_t *lineno; - pr_auxfunction_t *aux_func = 0; - dfunction_t *func = 0; + static func_data_t func_data; + progs_t *pr = (progs_t *) data; + pr_auxfunction_t *aux_func; + dfunction_t *func; - if (!pr->debug) - return; - for (i = 0; i < pr->debug->num_linenos; i++) { - lineno = &pr->linenos[i]; + memset (&func_data, 0, sizeof (func_data)); + if (func_index < pr->debug->num_auxfunctions) { + aux_func = pr->auxfunctions + func_index; + func_data.source_line = aux_func->source_line; + func_data.return_type = aux_func->return_type; + func_data.num_locals = aux_func->num_locals; + func_data.local_defs = aux_func->local_defs; + func_data.line_info = aux_func->line_info; + func_data.function = aux_func->function; + if (aux_func->function < (unsigned int) pr->progs->numfunctions) { + func = pr->pr_functions + aux_func->function; + func_data.source_file = pr->pr_strings + func->s_file; + func_data.source_name = pr->pr_strings + func->s_name; + func_data.first_statement = func->first_statement; + } + return &func_data; + } + return 0; +} +static void +dump_line_set (pr_lineno_t *lineno, unsigned count, + get_func_data_t get_func_data, void *data) +{ + unsigned int line, addr; + func_data_t *func_data = 0; + + for (; count-- > 0; lineno++) { if (!lineno->line) { - aux_func = 0; - func = 0; - if (lineno->fa.func < pr->debug->num_auxfunctions) - aux_func = pr->auxfunctions + lineno->fa.func; - if (aux_func - && aux_func->function < (unsigned int) pr->progs->numfunctions) - func = pr->pr_functions + aux_func->function; + func_data = get_func_data(lineno->fa.func, data); } printf ("%5u %5u", lineno->fa.addr, lineno->line); line = addr = -1; - if (aux_func) - line = aux_func->source_line + lineno->line; - if (func) - addr = lineno->line ? lineno->fa.addr - : (unsigned int) func->first_statement; - if (aux_func && func) - printf (" %05x %s:%u %s+%u %d", addr, pr->pr_strings + func->s_file, - line, pr->pr_strings + func->s_name, - addr - func->first_statement, aux_func->return_type); - else if (aux_func) - printf ("%u %u %u %u %u %d", aux_func->function, line, - aux_func->line_info, aux_func->local_defs, - aux_func->num_locals, aux_func->return_type); - else if (lineno->line) + if (func_data) { + line = func_data->source_line + lineno->line; + if (func_data->source_name) { + addr = lineno->line ? (pr_int_t) lineno->fa.addr + : func_data->first_statement; + printf (" %05x %s:%u %s+%u %d", addr, func_data->source_file, + line, func_data->source_name, + addr - func_data->first_statement, + func_data->return_type); + } else { + printf ("%u %u %u %u %u %d", func_data->function, line, + func_data->line_info, func_data->local_defs, + func_data->num_locals, func_data->return_type); + } + } else if (lineno->line) { printf ("%5x", lineno->fa.addr); + } printf ("\n"); } } + +void +dump_lines (progs_t *pr) +{ + if (!pr->debug) + return; + dump_line_set (pr->linenos, pr->debug->num_linenos, + progs_get_func_data, pr); +} + +static func_data_t * +qfo_get_func_data (unsigned func_index, void *data) +{ + return (func_data_t *) data; +} + +static void +qfo_set_func_data (qfo_t *qfo, qfo_func_t *func, func_data_t *func_data) +{ + qfot_type_t *type; + + func_data->source_line = func->line; + //FIXME check type + type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, func->type); + func_data->return_type = type->t.func.return_type; + func_data->num_locals = -1; + if (func->locals_space < qfo->num_spaces) { + func_data->num_locals = qfo->spaces[func->locals_space].num_defs; + } + func_data->local_defs = func->locals_space; + func_data->line_info = func->line_info; + func_data->function = func - qfo->funcs; + func_data->source_file = QFO_GETSTR (qfo, func->file); + func_data->source_name = QFO_GETSTR (qfo, func->name); + func_data->first_statement = func->code; +} + +void +qfo_lines (qfo_t *qfo) +{ + static func_data_t func_data; + pr_lineno_t *start_lineno = 0; + pr_lineno_t *lineno; + qfo_func_t *func = 0; + + for (func = qfo->funcs; func - qfo->funcs < qfo->num_funcs; func++) { + if (!func->line_info) { + // builtin + continue; + } + if (func->line_info >= qfo->num_lines) { + printf ("%s: bad line info: %u >= %u\n", + QFO_GETSTR (qfo, func->name), + func->line_info, qfo->num_lines); + continue; + } + qfo_set_func_data(qfo, func, &func_data); + start_lineno = qfo->lines + func->line_info; + for (lineno = start_lineno + 1; + lineno - qfo->lines < qfo->num_lines && lineno->line; + lineno++) + { + } + dump_line_set (start_lineno, lineno-start_lineno, + qfo_get_func_data, &func_data); + } +} diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index 28d9141c5..692a4f5ed 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -128,7 +128,6 @@ static edict_t *edicts; static int num_edicts; static int reserved_edicts = 1; static progs_t pr; -static int need_progs; static qfo_t *qfo; static const char *source_path = ""; @@ -234,7 +233,7 @@ init_qf (void) { Sys_Init (); - Cvar_Get ("pr_debug", va ("%d", verbosity), 0, 0, ""); + Cvar_Get ("pr_debug", va ("%d", 1+verbosity), 0, 0, ""); Cvar_Get ("pr_source_path", source_path, 0, 0, ""); PR_Init_Cvars (); PR_Init (); @@ -251,87 +250,6 @@ init_qf (void) Hash_SetHashCompare (func_tab, func_hash, func_compare); } -static void -convert_qfo (void) -{ - int size; - int i; - xdef_t *xdef = 0; - pr_xdefs_t *xdefs = 0; - ddef_t *xdefs_def = 0; - ddef_t *global_ddefs; - ddef_t *field_ddefs; - - pr.progs = qfo_to_progs (qfo, &size); - -#define P(t,o) ((t *)((char *)pr.progs + pr.progs->o)) - pr.pr_statements = P (dstatement_t, ofs_statements); - pr.pr_strings = P (char, ofs_strings); - pr.pr_stringsize = pr.progs->numstrings; - pr.pr_functions = P (dfunction_t, ofs_functions); - global_ddefs = P (ddef_t, ofs_globaldefs); - field_ddefs = P (ddef_t, ofs_fielddefs); - pr.pr_globals = P (pr_type_t, ofs_globals); - pr.globals_size = pr.progs->numglobals; - pr.pr_edict_size = max (1, pr.progs->entityfields) * 4; - pr.pr_edictareasize = 1 * pr.pr_edict_size; -#undef P - - pr.pr_globaldefs = malloc ((pr.progs->numglobaldefs - + pr.progs->numfielddefs) - * sizeof (pr_def_t)); - pr.pr_fielddefs = pr.pr_globaldefs + pr.progs->numglobaldefs; - // can't use PR_FindGlobal yet as pr_globaldefs is still uninitialized - for (i = 0; i < (int) pr.progs->numglobaldefs; i++) { - ddef_t *ddef = global_ddefs + i; - if (!strcmp (PR_GetString (&pr, ddef->s_name), ".xdefs")) { - xdefs_def = ddef; - break; - } - } - if (xdefs_def) { - xdefs = &G_STRUCT (&pr, pr_xdefs_t, xdefs_def->ofs); - xdef = &G_STRUCT (&pr, xdef_t, xdefs->xdefs); - } - for (i = 0; i < (int) pr.progs->numglobaldefs; i++, xdef++) { - ddef_t *ddef = global_ddefs + i; - pr_def_t *def = pr.pr_globaldefs + i; - def->type = ddef->type; - def->ofs = xdefs ? xdef->ofs : ddef->ofs; - def->name = ddef->s_name; - def->type_encoding = xdefs ? xdef->type : 0; - } - for (i = 0; i < (int) pr.progs->numfielddefs; i++, xdef++) { - ddef_t *ddef = field_ddefs + i; - pr_def_t *def = pr.pr_fielddefs + i; - def->type = ddef->type; - def->ofs = xdefs ? xdef->ofs : ddef->ofs; - def->name = ddef->s_name; - def->type_encoding = xdefs ? xdef->type : 0; - } - - if (verbosity) { - pr.debug = qfo_to_sym (qfo, &size); -#define P(t,o) ((t *)((char *)pr.debug + pr.debug->o)) - pr.auxfunctions = P (pr_auxfunction_t, auxfunctions); - pr.linenos = P (pr_lineno_t, linenos); - pr.local_defs = P (pr_def_t, locals); -#undef P - - pr.local_defs = calloc (qfo->num_defs, sizeof (ddef_t)); - - pr.auxfunction_map = calloc (pr.progs->numfunctions, - sizeof (pr_auxfunction_t *)); - for (i = 0; (int) i < pr.progs->numfunctions; i++) //FIXME (cast) - pr.auxfunction_map[i] = 0; - - for (i = 0; i < (int) pr.debug->num_auxfunctions; i++) { - pr_auxfunction_t *aux = pr.auxfunctions + i; - pr.auxfunction_map[aux->function] = aux; - } - } -} - static int load_progs (const char *name) { @@ -349,6 +267,7 @@ load_progs (const char *name) Qread (file, buff, 4); buff[4] = 0; Qseek (file, 0, SEEK_SET); + qfo = 0; if (!strcmp (buff, QFO)) { qfo = qfo_read (file); Qclose (file); @@ -356,9 +275,7 @@ load_progs (const char *name) if (!qfo) return 0; - if (!need_progs) - return 1; - convert_qfo (); + return 1; } else { pr.progs_name = name; pr.max_edicts = 1; @@ -392,7 +309,7 @@ operation_t operations[] = { {dump_strings, 0}, // strings {dump_fields, 0}, // fields {dump_functions, qfo_functions}, // functions - {dump_lines, 0}, // lines + {dump_lines, qfo_lines}, // lines {dump_modules, 0}, // modules {0, qfo_relocs}, // relocs {dump_types, qfo_types}, // types @@ -451,12 +368,11 @@ main (int argc, char **argv) } init_qf (); while (optind < argc) { - need_progs = !func->qfo; if (!load_progs (argv[optind++])) return 1; if (qfo && func->qfo) func->qfo (qfo); - else if (func->progs) + else if (!qfo && func->progs) func->progs (&pr); else fprintf (stderr, "can't process %s\n", argv[optind - 1]); From b0157e509559a8a403dcd882f0d27fd43bc94baa Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 14:56:50 +0900 Subject: [PATCH 040/444] Fix qfo field dumping --- tools/qfcc/include/qfprogs.h | 1 + tools/qfcc/source/dump_globals.c | 35 ++++++++++++++++++++++++++++++++ tools/qfcc/source/qfprogs.c | 2 +- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/include/qfprogs.h b/tools/qfcc/include/qfprogs.h index bb64b3fb6..22a4574c4 100644 --- a/tools/qfcc/include/qfprogs.h +++ b/tools/qfcc/include/qfprogs.h @@ -55,6 +55,7 @@ struct dfunction_s *func_find (int st_num); void dump_strings (struct progs_s *pr); void qfo_globals (struct qfo_s *qfo); +void qfo_fields (struct qfo_s *qfo); void qfo_functions (struct qfo_s *qfo); void qfo_lines (struct qfo_s *qfo); void qfo_relocs (struct qfo_s *qfo); diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 79024313b..ea94f5d9d 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -192,6 +192,41 @@ dump_fields (progs_t *pr) } } +void +qfo_fields (qfo_t *qfo) +{ + unsigned int i; + const char *name; + const char *typestr; + qfot_type_t *type; + int offset; + const char *comment; + qfo_mspace_t *space = &qfo->spaces[qfo_entity_space]; + + if (qfo_entity_space >= qfo->num_spaces) { + printf ("no entity space\n"); + return; + } + if (!space->num_defs) { + printf ("no fields\n"); + return; + } + + for (i = 0; i < space->num_defs; i++) { + qfo_def_t *def = space->defs + i; + + name = QFO_GETSTR (qfo, def->name); + //FIXME check type + type = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, def->type); + typestr = QFO_GETSTR (qfo, type->encoding); + offset = def->offset; + + comment = ""; + + printf ("%d %s %s%s\n", offset, name, typestr, comment); + } +} + void dump_functions (progs_t *pr) { diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index 692a4f5ed..1ff2e6a85 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -307,7 +307,7 @@ operation_t operations[] = { {disassemble_progs, 0}, // disassemble {dump_globals, qfo_globals}, // globals {dump_strings, 0}, // strings - {dump_fields, 0}, // fields + {dump_fields, qfo_fields}, // fields {dump_functions, qfo_functions}, // functions {dump_lines, qfo_lines}, // lines {dump_modules, 0}, // modules From 6009d1d02384fede00a5c53b1b4e18cf1461a9a5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 15:08:31 +0900 Subject: [PATCH 041/444] Fix qfo strings dumping --- tools/qfcc/include/qfprogs.h | 1 + tools/qfcc/source/dump_strings.c | 42 ++++++++++++++++++++++++-------- tools/qfcc/source/qfprogs.c | 2 +- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/tools/qfcc/include/qfprogs.h b/tools/qfcc/include/qfprogs.h index 22a4574c4..731a61194 100644 --- a/tools/qfcc/include/qfprogs.h +++ b/tools/qfcc/include/qfprogs.h @@ -59,6 +59,7 @@ void qfo_fields (struct qfo_s *qfo); void qfo_functions (struct qfo_s *qfo); void qfo_lines (struct qfo_s *qfo); void qfo_relocs (struct qfo_s *qfo); +void qfo_strings (struct qfo_s *qfo); void qfo_types (struct qfo_s *qfo); #endif//__qfprogs_h diff --git a/tools/qfcc/source/dump_strings.c b/tools/qfcc/source/dump_strings.c index 91d6ca2ba..fc0c0cb7d 100644 --- a/tools/qfcc/source/dump_strings.c +++ b/tools/qfcc/source/dump_strings.c @@ -36,21 +36,22 @@ #include "QF/progs.h" #include "QF/sys.h" +#include "obj_file.h" #include "qfprogs.h" -void -dump_strings (progs_t *pr) +static void +dump_string_block (const char *strblock, unsigned size) { - int i = 0; - char *s = pr->pr_strings; + const char *s = strblock; printf ("%d ", 0); - while (i++ < pr->progs->numstrings) { - switch (*s) { + while (s - strblock < size) { + char c = *s++; + switch (c) { case 0: fputs ("\n", stdout); - if (i < pr->progs->numstrings) - printf ("%d ", i); + if (s - strblock < size) + printf ("%ld ", s - strblock); break; case 9: fputs ("\\t", stdout); @@ -62,9 +63,30 @@ dump_strings (progs_t *pr) fputs ("\\r", stdout); break; default: - fputc (sys_char_map[(unsigned char)*s], stdout); + fputc (sys_char_map[(unsigned char)c], stdout); break; } - s++; } } + +void +dump_strings (progs_t *pr) +{ + dump_string_block (pr->pr_strings, pr->progs->numstrings); +} + +void +qfo_strings (qfo_t *qfo) +{ + qfo_mspace_t *space = &qfo->spaces[qfo_strings_space]; + + if (qfo_strings_space >= qfo->num_spaces) { + printf ("no strings space\n"); + return; + } + if (!space->data_size) { + printf ("no strings\n"); + return; + } + dump_string_block (space->d.strings, space->data_size); +} diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index 1ff2e6a85..42c91b9ed 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -306,7 +306,7 @@ typedef struct { operation_t operations[] = { {disassemble_progs, 0}, // disassemble {dump_globals, qfo_globals}, // globals - {dump_strings, 0}, // strings + {dump_strings, qfo_strings}, // strings {dump_fields, qfo_fields}, // fields {dump_functions, qfo_functions}, // functions {dump_lines, qfo_lines}, // lines From 4b7ecdf74a2ce15316879bcdb0c4d0e646d61100 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 15:56:36 +0900 Subject: [PATCH 042/444] Make PR_Init take an instance to initialize This allows internal sub-systems to do per-instance initializations without other engine systems having to know about them. --- include/QF/pr_comp.h | 2 +- include/QF/progs.h | 8 ++++++-- libs/console/menu.c | 2 ++ libs/gamecode/pr_debug.c | 2 +- libs/gamecode/pr_load.c | 7 ++++--- libs/gamecode/pr_opcode.c | 4 ++++ libs/ruamoko/rua_init.c | 1 - nq/source/host.c | 5 ----- nq/source/sv_progs.c | 5 +++++ qw/source/cl_main.c | 4 +--- qw/source/sv_main.c | 3 --- qw/source/sv_progs.c | 6 ++++++ tools/qfcc/source/qfprogs.c | 3 ++- tools/qfcc/test/test-harness.c | 2 +- tools/qwaq/main.c | 2 +- tools/qwaq/qwaq.c | 2 +- 16 files changed, 35 insertions(+), 23 deletions(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index d1865d1cc..9df0416d3 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -409,7 +409,7 @@ typedef struct opcode_s { extern opcode_t pr_opcodes[]; opcode_t *PR_Opcode (pr_short_t opcode); -void PR_Opcode_Init (void); +void PR_Opcode_Init (void); // idempotent typedef struct dstatement_s { pr_opcode_e op:16; diff --git a/include/QF/progs.h b/include/QF/progs.h index a413b2f25..a07f70534 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -53,8 +53,12 @@ typedef struct edict_s edict_t; ///@{ /** Initialize the progs engine. + + The first call will initialize subsystems common to all progs instances. + + \param pr The progs engine instance to initialize. */ -void PR_Init (void); +void PR_Init (progs_t *pr); /** Initialize the Cvars for the progs engine. Call before calling PR_Init(). */ @@ -1488,7 +1492,7 @@ void *PR_Zone_Realloc (progs_t *pr, void *ptr, pr_int_t size); /// \addtogroup debug ///@{ -void PR_Debug_Init (void); +void PR_Debug_Init (progs_t *pr); void PR_Debug_Init_Cvars (void); int PR_LoadDebug (progs_t *pr); void PR_Debug_Watch (progs_t *pr, const char *expr); diff --git a/libs/console/menu.c b/libs/console/menu.c index 8320bc405..3ebf1d60a 100644 --- a/libs/console/menu.c +++ b/libs/console/menu.c @@ -583,6 +583,8 @@ Menu_Init (void) menu_pr_state.max_edicts = 0; menu_pr_state.zone_size = 1024 * 1024; + PR_Init (&menu_pr_state); + menu_hash = Hash_NewTable (61, menu_get_key, menu_free, 0); PR_RegisterBuiltins (&menu_pr_state, builtins); diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 0c388eaff..8f05793b9 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -200,7 +200,7 @@ error: } void -PR_Debug_Init (void) +PR_Debug_Init (progs_t *pr) { file_hash = Hash_NewTable (1024, file_get_key, file_free, 0); } diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index 99136ed4f..a7dced537 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -466,10 +466,11 @@ PR_Init_Cvars (void) } VISIBLE void -PR_Init (void) +PR_Init (progs_t *pr) { - PR_Opcode_Init (); - PR_Debug_Init (); + PR_Opcode_Init (); // idempotent + PR_Resources_Init (pr); + PR_Debug_Init (pr); } VISIBLE void diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index 0ad3fab4b..26ce130cb 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -1493,6 +1493,10 @@ PR_Opcode_Init (void) { opcode_t *op; + if (opcode_table) { + // already initialized + return; + } opcode_table = Hash_NewTable (1021, 0, 0, 0); Hash_SetHashCompare (opcode_table, opcode_get_hash, opcode_compare); diff --git a/libs/ruamoko/rua_init.c b/libs/ruamoko/rua_init.c index ab973b569..bbfc67525 100644 --- a/libs/ruamoko/rua_init.c +++ b/libs/ruamoko/rua_init.c @@ -56,7 +56,6 @@ RUA_Init (progs_t *pr, int secure) { size_t i; - PR_Resources_Init (pr); for (i = 0; i < sizeof (init_funcs) / sizeof (init_funcs[0]); i++) init_funcs[i] (pr, secure); } diff --git a/nq/source/host.c b/nq/source/host.c index f6b59cf8b..67b55507b 100644 --- a/nq/source/host.c +++ b/nq/source/host.c @@ -896,14 +896,9 @@ Host_Init (void) Game_Init (); - PR_Init_Cvars (); - SV_Progs_Init_Cvars (); - if (!isDedicated) CL_InitCvars (); - PR_Init (); - if (isDedicated) { PI_RegisterPlugins (server_plugin_list); Con_Init ("server"); diff --git a/nq/source/sv_progs.c b/nq/source/sv_progs.c index 60ee75368..8626ade59 100644 --- a/nq/source/sv_progs.c +++ b/nq/source/sv_progs.c @@ -521,6 +521,8 @@ SV_LoadProgs (void) void SV_Progs_Init (void) { + SV_Progs_Init_Cvars (); + pr_gametype = "netquake"; sv_pr_state.edicts = &sv.edicts; sv_pr_state.num_edicts = &sv.num_edicts; @@ -531,6 +533,8 @@ SV_Progs_Init (void) sv_pr_state.bi_map = bi_map; sv_pr_state.resolve = resolve; + PR_Init (&sv_pr_state); + SV_PR_Cmds_Init (); Cmd_AddCommand ("edict", ED_PrintEdict_f, "Report information on a given " @@ -548,6 +552,7 @@ SV_Progs_Init (void) void SV_Progs_Init_Cvars (void) { + PR_Init_Cvars (); sv_progs = Cvar_Get ("sv_progs", "", CVAR_NONE, NULL, "Override the default game progs."); sv_progs_zone = Cvar_Get ("sv_progs_zone", "256", CVAR_NONE, NULL, diff --git a/qw/source/cl_main.c b/qw/source/cl_main.c index 09fb1aec2..aa223736f 100644 --- a/qw/source/cl_main.c +++ b/qw/source/cl_main.c @@ -1804,12 +1804,10 @@ Host_Init (void) Netchan_Init_Cvars (); - PR_Init_Cvars (); + PR_Init_Cvars (); // FIXME location CL_Init_Cvars (); - PR_Init (); - CL_Chat_Init (); CL_Cmd_Init (); diff --git a/qw/source/sv_main.c b/qw/source/sv_main.c index c69e23594..d764c012f 100644 --- a/qw/source/sv_main.c +++ b/qw/source/sv_main.c @@ -2523,8 +2523,6 @@ SV_Init (void) Mod_Init_Cvars (); Netchan_Init_Cvars (); Pmove_Init_Cvars (); - SV_Progs_Init_Cvars (); - PR_Init_Cvars (); // and now reprocess the cmdline's sets for overrides Cmd_StuffCmds (sv_cbuf); @@ -2534,7 +2532,6 @@ SV_Init (void) Game_Init (); - PR_Init (); SV_Progs_Init (); Mod_Init (); diff --git a/qw/source/sv_progs.c b/qw/source/sv_progs.c index f5abeed3f..2c4ff5c3f 100644 --- a/qw/source/sv_progs.c +++ b/qw/source/sv_progs.c @@ -544,6 +544,8 @@ SV_LoadProgs (void) void SV_Progs_Init (void) { + SV_Progs_Init_Cvars (); + pr_gametype = "quakeworld"; sv_pr_state.edicts = &sv.edicts; sv_pr_state.num_edicts = &sv.num_edicts; @@ -556,6 +558,8 @@ SV_Progs_Init (void) sv_pr_state.bi_map = bi_map; sv_pr_state.resolve = resolve; + PR_Init (&sv_pr_state); + SV_PR_Cmds_Init (); SV_PR_QWE_Init (&sv_pr_state); SV_PR_CPQW_Init (&sv_pr_state); @@ -575,6 +579,8 @@ SV_Progs_Init (void) void SV_Progs_Init_Cvars (void) { + PR_Init_Cvars (); + r_skyname = Cvar_Get ("r_skyname", "", CVAR_NONE, NULL, "Default name of skybox if none given by map"); sv_progs = Cvar_Get ("sv_progs", "", CVAR_NONE, NULL, diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index 42c91b9ed..64dab879a 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -236,7 +236,6 @@ init_qf (void) Cvar_Get ("pr_debug", va ("%d", 1+verbosity), 0, 0, ""); Cvar_Get ("pr_source_path", source_path, 0, 0, ""); PR_Init_Cvars (); - PR_Init (); pr.edicts = &edicts; pr.num_edicts = &num_edicts; @@ -246,6 +245,8 @@ init_qf (void) pr.allocate_progs_mem = allocate_progs_mem; pr.free_progs_mem = free_progs_mem; + PR_Init (&pr); + func_tab = Hash_NewTable (1021, 0, 0, 0); Hash_SetHashCompare (func_tab, func_hash, func_compare); } diff --git a/tools/qfcc/test/test-harness.c b/tools/qfcc/test/test-harness.c index 78c657d05..cabef6ab7 100644 --- a/tools/qfcc/test/test-harness.c +++ b/tools/qfcc/test/test-harness.c @@ -154,7 +154,7 @@ init_qf (void) pr.pr_trace = options.trace; PR_Init_Cvars (); - PR_Init (); + PR_Init (&pr); RUA_Init (&pr, 0); PR_Cmds_Init(&pr); BI_Init (&pr); diff --git a/tools/qwaq/main.c b/tools/qwaq/main.c index 035e4f73b..1ab7c027e 100644 --- a/tools/qwaq/main.c +++ b/tools/qwaq/main.c @@ -117,7 +117,7 @@ init_qf (void) pr.no_exec_limit = 1; PR_Init_Cvars (); - PR_Init (); + PR_Init (&pr); RUA_Init (&pr, 0); PR_Cmds_Init(&pr); BI_Init (&pr); diff --git a/tools/qwaq/qwaq.c b/tools/qwaq/qwaq.c index 24a14d217..b446a02dd 100644 --- a/tools/qwaq/qwaq.c +++ b/tools/qwaq/qwaq.c @@ -128,7 +128,7 @@ init_qf (void) pr.no_exec_limit = 1; PR_Init_Cvars (); - PR_Init (); + PR_Init (&pr); RUA_Init (&pr, 0); PR_Cmds_Init (&pr); BI_Init (&pr); From b173c35eb455676a59826b700511c90352479e2e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 18:56:30 +0900 Subject: [PATCH 043/444] Rework progs debug to use the type encodings It's only a start: the output is, if anything, slightly worse than before, but it does have the basics going. --- include/QF/progs.h | 43 +++ libs/gamecode/pr_debug.c | 664 ++++++++++++++++++++++++++++----------- 2 files changed, 519 insertions(+), 188 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index a07f70534..78b3036c7 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1492,6 +1492,49 @@ void *PR_Zone_Realloc (progs_t *pr, void *ptr, pr_int_t size); /// \addtogroup debug ///@{ +struct qfot_type_s; + +/** Callback for viewing progs data + + \param type C pointer to the type definition by which to view the + data. + \param value C pointer to the data to be viewed. + \param data User data. +*/ +typedef void (*type_view_func) (struct qfot_type_s *type, pr_type_t *value, + void *data); + +/** Set of callbacks for viewing progs data + + Each possible type has its own callback. Basic types (those for which the + VM has specific instructions) all have separate callbacks, one for each + type, but the callbacks for compound types are expected to some + interpretation on their own, such as displaying a simple identifier or + the entire contents of the data. +*/ +typedef struct type_view_s { + type_view_func void_view; + type_view_func string_view; + type_view_func float_view; + type_view_func vector_view; + type_view_func entity_view; + type_view_func field_view; + type_view_func func_view; + type_view_func pointer_view; + type_view_func quat_view; + type_view_func integer_view; + type_view_func uinteger_view; + type_view_func short_view; + type_view_func double_view; + + type_view_func struct_view; + type_view_func union_view; + type_view_func enum_view; + type_view_func array_view; + type_view_func class_view; + type_view_func alias_view; +} type_view_t; + void PR_Debug_Init (progs_t *pr); void PR_Debug_Init_Cvars (void); int PR_LoadDebug (progs_t *pr); diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 8f05793b9..2a41ec61c 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -71,12 +71,81 @@ typedef struct { progs_t *pr; } file_t; +typedef struct { + dstring_t *string; +} pr_debug_resources_t; + +typedef struct { + progs_t *pr; + dstring_t *dstr; +} pr_debug_data_t; + cvar_t *pr_debug; cvar_t *pr_source_path; static hashtab_t *file_hash; static char *source_path_string; static char **source_paths; +static void pr_debug_void_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_string_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_float_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_vector_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_entity_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_field_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_func_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_pointer_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_quat_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_integer_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_uinteger_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_short_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_double_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_struct_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_union_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_enum_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_array_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_class_view (qfot_type_t *type, pr_type_t *value, + void *_data); +static void pr_debug_alias_view (qfot_type_t *type, pr_type_t *value, + void *_data); + +static type_view_t raw_type_view = { + pr_debug_void_view, + pr_debug_string_view, + pr_debug_float_view, + pr_debug_vector_view, + pr_debug_entity_view, + pr_debug_field_view, + pr_debug_func_view, + pr_debug_pointer_view, + pr_debug_quat_view, + pr_debug_integer_view, + pr_debug_uinteger_view, + pr_debug_short_view, + pr_debug_double_view, + pr_debug_struct_view, + pr_debug_union_view, + pr_debug_enum_view, + pr_debug_array_view, + pr_debug_class_view, + pr_debug_alias_view, +}; static const char * file_get_key (const void *_f, void *unused) @@ -199,10 +268,28 @@ error: return d; } +static void +pr_debug_clear (progs_t *pr, void *data) +{ + __auto_type res = (pr_debug_resources_t *) data; + + if (res->string) { + dstring_clearstr (res->string); + } else { + res->string = dstring_newstr (); + } +} + void PR_Debug_Init (progs_t *pr) { - file_hash = Hash_NewTable (1024, file_get_key, file_free, 0); + pr_debug_resources_t *res = calloc (1, sizeof (*res)); + res->string = 0; + + PR_Resources_Register (pr, "PR_Debug", res, pr_debug_clear); + if (!file_hash) { + file_hash = Hash_NewTable (1024, file_get_key, file_free, 0); + } } void @@ -591,181 +678,386 @@ PR_DumpState (progs_t *pr) #define ISDENORM(x) ((x) && !((x) & 0x7f800000)) static const char * -value_string (progs_t *pr, etype_t type, pr_type_t *val) +value_string (pr_debug_data_t *data, qfot_type_t *type, pr_type_t *value) { - static dstring_t *line; - pr_def_t *def; - pr_int_t ofs; - edict_t *edict; - dfunction_t *f; - const char *str; - - if (!line) - line = dstring_new (); - - type &= ~DEF_SAVEGLOBAL; - - switch (type) { - case ev_string: - if (!PR_StringValid (pr, val->string_var)) - return "*** invalid ***"; - str = PR_GetString (pr, val->string_var); - dstring_copystr (line, "\""); - while (*str) { - const char *s; - - for (s = str; *s && !strchr ("\"\n\t", *s); s++) - ; - if (s != str) - dstring_appendsubstr (line, str, s - str); - if (*s) { - switch (*s) { - case '\"': - dstring_appendstr (line, "\\\""); - break; - case '\n': - dstring_appendstr (line, "\\n"); - break; - case '\t': - dstring_appendstr (line, "\\t"); - break; - default: - dasprintf (line, "\\x%02x", *s & 0xff); - } - s++; - } - str = s; - } - dstring_appendstr (line, "\""); - break; - case ev_entity: - edict = PROG_TO_EDICT (pr, val->entity_var); - dsprintf (line, "entity %d", NUM_FOR_BAD_EDICT (pr, edict)); - break; - case ev_func: - if (val->func_var < 0 || val->func_var >= pr->progs->numfunctions) - dsprintf (line, "INVALID:%d", val->func_var); - else if (!val->func_var) - return "NULL"; - else { - f = pr->pr_functions + val->func_var; - dsprintf (line, "%s()", PR_GetString (pr, f->s_name)); + switch (type->meta) { + case ty_basic: + switch (type->t.type) { + case ev_void: + raw_type_view.void_view (type, value, data); + break; + case ev_string: + raw_type_view.string_view (type, value, data); + break; + case ev_float: + raw_type_view.float_view (type, value, data); + break; + case ev_vector: + raw_type_view.vector_view (type, value, data); + break; + case ev_entity: + raw_type_view.entity_view (type, value, data); + break; + case ev_field: + raw_type_view.field_view (type, value, data); + break; + case ev_func: + raw_type_view.func_view (type, value, data); + break; + case ev_pointer: + raw_type_view.pointer_view (type, value, data); + break; + case ev_quat: + raw_type_view.quat_view (type, value, data); + break; + case ev_integer: + raw_type_view.integer_view (type, value, data); + break; + case ev_uinteger: + raw_type_view.uinteger_view (type, value, data); + break; + case ev_short: + raw_type_view.short_view (type, value, data); + break; + case ev_double: + raw_type_view.double_view (type, value, data); + break; + case ev_invalid: + case ev_type_count: + dstring_appendstr (data->dstr, ""); } break; - case ev_field: - def = PR_FieldAtOfs (pr, val->integer_var); - if (def) - dsprintf (line, ".%s", PR_GetString (pr, def->name)); - else - dsprintf (line, ".<$%04x>", val->integer_var); + case ty_struct: + raw_type_view.struct_view (type, value, data); break; - case ev_void: - return "void"; - case ev_float: - if (ISDENORM (val->integer_var) && val->uinteger_var != 0x80000000) - dsprintf (line, "<%08x>", val->integer_var); - else - dsprintf (line, "%g", val->float_var); + case ty_union: + raw_type_view.union_view (type, value, data); break; - case ev_vector: - dsprintf (line, "'%g %g %g'", - val->vector_var[0], val->vector_var[1], - val->vector_var[2]); + case ty_enum: + raw_type_view.enum_view (type, value, data); break; - case ev_pointer: - def = 0; - ofs = val->integer_var; - if (pr_debug->int_val && pr->debug) - def = PR_Get_Local_Def (pr, ofs); - if (!def) - def = PR_GlobalAtOfs (pr, ofs); - if (def && def->name) - dsprintf (line, "&%s", PR_GetString (pr, def->name)); - else - dsprintf (line, "[$%x]", ofs); + case ty_array: + raw_type_view.array_view (type, value, data); break; - case ev_quat: - dsprintf (line, "'%g %g %g %g'", - val->vector_var[0], val->vector_var[1], - val->vector_var[2], val->vector_var[3]); + case ty_class: + raw_type_view.class_view (type, value, data); break; - case ev_integer: - dsprintf (line, "%d", val->integer_var); - break; - case ev_uinteger: - dsprintf (line, "$%08x", val->uinteger_var); - break; - case ev_double: - dsprintf (line, "%g", *(double *)val); - break; - case ev_short: - case ev_invalid: - case ev_type_count: - //dsprintf (line, "bad type %i", type); - dsprintf (line, "<%x %x %x %x>", - val[0].integer_var, val[1].integer_var, - val[2].integer_var, val[3].integer_var); + case ty_alias: + raw_type_view.alias_view (type, value, data); break; } - - return line->str; + return data->dstr->str; } static pr_def_t * -def_string (progs_t *pr, pr_int_t ofs, dstring_t *dstr) +pr_debug_find_def (progs_t *pr, pr_int_t ofs) { pr_def_t *def = 0; - const char *name; if (pr_debug->int_val && pr->debug) def = PR_Get_Local_Def (pr, ofs); if (!def) def = PR_GlobalAtOfs (pr, ofs); - if (!def || !*(name = PR_GetString (pr, def->name))) - dsprintf (dstr, "[$%x]", ofs); - else - dsprintf (dstr, "%s", name); return def; } static const char * -global_string (progs_t *pr, pointer_t ofs, etype_t type, int contents) +global_string (pr_debug_data_t *data, pointer_t ofs, etype_t etype, + int contents) { - static dstring_t *line = NULL; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; pr_def_t *def = NULL; - const char *s; + qfot_type_t dummy_type = { }; + qfot_type_t *type; + const char *name = 0; - if (!line) - line = dstring_newstr(); + dstring_clearstr (dstr); - if (type == ev_short) { - dsprintf (line, "%04x", (short) ofs); - return line->str; + if (etype == ev_short) { + dsprintf (dstr, "%04x", (short) ofs); + return dstr->str; } - def = def_string (pr, ofs, line); + if (ofs > pr->globals_size) { + dsprintf (dstr, "%08x out of bounds", ofs); + return dstr->str; + } - if (contents && (def || type != ev_void)) { - const char *oi = ""; - if (def) { - if (type == ev_void) - type = def->type; - if (type != (etype_t) (def->type & ~DEF_SAVEGLOBAL)) - oi = "?"; - } - - if (ofs > pr->globals_size) - s = "Out of bounds"; - else - s = value_string (pr, type, &pr->pr_globals[ofs]); - - if (strequal(line->str, "IMMEDIATE") || strequal(line->str, ".imm")) { - dsprintf (line, "%s", s); + def = pr_debug_find_def (pr, ofs); + if (!def || !PR_StringValid (pr, def->name) + || !*(name = PR_GetString (pr, def->name))) { + dsprintf (dstr, "[$%x]", ofs); + } + if (name) { + if (strequal (name, "IMMEDIATE") || strequal (name, ".imm")) { + contents = 1; } else { - dasprintf (line, "%s(%s)", oi, s); + dsprintf (dstr, "%s", name); } } - return line->str; + if (contents) { + if (name) { + dstring_appendstr (dstr, "("); + } + if (def) { + if (!def->type_encoding) { + dummy_type.t.type = def->type; + type = &dummy_type; + } else { + type = &G_STRUCT (pr, qfot_type_t, def->type_encoding); + } + } else { + dummy_type.t.type = etype; + type = &dummy_type; + } + value_string (data, type, pr->pr_globals + ofs); + if (name) { + dstring_appendstr (dstr, ")"); + } + } + return dstr->str; +} + +static void +pr_debug_void_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dasprintf (data->dstr, ""); +} + +static void +pr_debug_string_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + string_t string = value->string_var; + if (PR_StringValid (data->pr, string)) { + const char *str = PR_GetString (data->pr, string); + + dstring_appendstr (dstr, "\""); + while (*str) { + const char *s; + + for (s = str; *s && !strchr ("\"\n\t", *s); s++) { + } + if (s != str) { + dstring_appendsubstr (dstr, str, s - str); + } + if (*s) { + switch (*s) { + case '\"': + dstring_appendstr (dstr, "\\\""); + break; + case '\n': + dstring_appendstr (dstr, "\\n"); + break; + case '\t': + dstring_appendstr (dstr, "\\t"); + break; + default: + dasprintf (dstr, "\\x%02x", *s & 0xff); + } + s++; + } + str = s; + } + dstring_appendstr (dstr, "\""); + } else { + dstring_appendstr (dstr, "*** invalid string offset ***"); + } +} + +static void +pr_debug_float_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + if (data->pr->progs->version == PROG_ID_VERSION + && ISDENORM (value->integer_var) + && value->uinteger_var != 0x80000000) { + dasprintf (dstr, "<%08x>", value->integer_var); + } else { + dasprintf (dstr, "%g", value->float_var); + } +} + +static void +pr_debug_vector_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "'%g %g %g'", + value->vector_var[0], value->vector_var[1], + value->vector_var[2]); +} + +static void +pr_debug_entity_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + edict_t *edict = PROG_TO_EDICT (pr, value->entity_var); + + dasprintf (dstr, "entity %d", NUM_FOR_BAD_EDICT (pr, edict)); +} + +static void +pr_debug_field_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + pr_def_t *def = PR_FieldAtOfs (pr, value->integer_var); + + if (def) { + dasprintf (dstr, ".%s", PR_GetString (pr, def->name)); + } else { + dasprintf (dstr, ".<$%04x>", value->integer_var); + } +} + +static void +pr_debug_func_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + + if (value->func_var < 0 || value->func_var >= pr->progs->numfunctions) { + dasprintf (dstr, "INVALID:%d", value->func_var); + } else if (!value->func_var) { + dstring_appendstr (dstr, "NULL"); + } else { + dfunction_t *f = pr->pr_functions + value->func_var; + dasprintf (dstr, "%s()", PR_GetString (pr, f->s_name)); + } +} + +static void +pr_debug_pointer_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; + dstring_t *dstr = data->dstr; + pointer_t ofs = value->integer_var; + pr_def_t *def; + + if (pr_debug->int_val && pr->debug) { + def = PR_Get_Local_Def (pr, ofs); + } + if (!def) { + def = PR_GlobalAtOfs (pr, ofs); + } + if (def && def->name) { + dasprintf (dstr, "&%s", PR_GetString (pr, def->name)); + } else { + dasprintf (dstr, "[$%x]", ofs); + } +} + +static void +pr_debug_quat_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "'%g %g %g %g'", + value->vector_var[0], value->vector_var[1], + value->vector_var[2], value->vector_var[3]); +} + +static void +pr_debug_integer_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "%d", value->integer_var); +} + +static void +pr_debug_uinteger_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "$%08x", value->uinteger_var); +} + +static void +pr_debug_short_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "%d", (short)value->integer_var); +} + +static void +pr_debug_double_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dasprintf (dstr, "%g", *(double *)value); +} + +static void +pr_debug_struct_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); +} + +static void +pr_debug_union_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); +} + +static void +pr_debug_enum_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); +} + +static void +pr_debug_array_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); +} + +static void +pr_debug_class_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); +} + +static void +pr_debug_alias_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + __auto_type data = (pr_debug_data_t *) _data; + dstring_t *dstr = data->dstr; + + dstring_appendstr (dstr, ""); } VISIBLE void @@ -780,8 +1072,7 @@ PR_Debug_Watch (progs_t *pr, const char *expr) if (pr->wp_conditional) Sys_Printf (" if new val == %d\n", pr->wp_val.integer_var); - } else { - Sys_Printf (" none active\n"); + } else { Sys_Printf (" none active\n"); } return; } @@ -803,6 +1094,8 @@ VISIBLE void PR_Debug_Print (progs_t *pr, const char *expr) { pr_def_t print; + dstring_t *dstr = dstring_newstr(); + pr_debug_data_t data = {pr, dstr}; if (!expr) { Sys_Printf ("print \n"); @@ -811,9 +1104,10 @@ PR_Debug_Print (progs_t *pr, const char *expr) print = parse_expression (pr, expr, 0); if (print.type != ev_invalid) { - const char *s = global_string (pr, print.ofs, print.type, 1); + const char *s = global_string (&data, print.ofs, print.type, 1); Sys_Printf ("[%d] = %s\n", print.ofs, s); } + dstring_delete (dstr); } VISIBLE void @@ -824,15 +1118,21 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) const char *fmt; opcode_t *op; static dstring_t *line; + static dstring_t *dstr; dfunction_t *call_func = 0; pr_def_t *parm_def = 0; pr_auxfunction_t *aux_func = 0; + pr_debug_data_t data; - if (!line) + if (!line) { line = dstring_new (); - + dstr = dstring_new (); + } dstring_clearstr (line); + data.pr = pr; + data.dstr = dstr; + if (pr_debug->int_val > 1) dump_code = 1; @@ -915,10 +1215,12 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) aux_func = get_aux_function (pr); if (aux_func) optype = get_etype (pr, aux_func->return_type); - str = global_string (pr, opval, optype, contents & 1); + str = global_string (&data, opval, optype, + contents & 1); break; case 'F': - str = global_string (pr, opval, optype, contents & 1); + str = global_string (&data, opval, optype, + contents & 1); if (G_FUNCTION (pr, opval) >= 0 && G_FUNCTION (pr, opval) < pr->progs->numfunctions) @@ -929,16 +1231,19 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) optype = ev_void; if (parm_def) optype = parm_def->type; - str = global_string (pr, opval, optype, contents & 1); + str = global_string (&data, opval, optype, + contents & 1); break; case 'V': - str = global_string (pr, opval, ev_void, contents & 1); + str = global_string (&data, opval, ev_void, + contents & 1); break; case 'G': - str = global_string (pr, opval, optype, contents & 1); + str = global_string (&data, opval, optype, + contents & 1); break; case 'g': - str = global_string (pr, opval, optype, 0); + str = global_string (&data, opval, optype, 0); break; case 's': str = va ("%d", (short) opval); @@ -961,7 +1266,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) str = "bad entity.field"; break; } - str = global_string (pr, opval, optype, + str = global_string (&data, opval, optype, contents & 1); str = va ("$%x $%x %s", s->a, s->b, str); } @@ -1072,11 +1377,15 @@ PR_Profile (progs_t * pr) VISIBLE void ED_Print (progs_t *pr, edict_t *ed) { - int type, l; + int l; pr_uint_t i; const char *name; pr_def_t *d; pr_type_t *v; + qfot_type_t dummy_type = { }; + qfot_type_t *type; + dstring_t *dstr = dstring_newstr(); + pr_debug_data_t data = {pr, dstr}; if (ed->free) { Sys_Printf ("FREE\n"); @@ -1088,6 +1397,12 @@ ED_Print (progs_t *pr, edict_t *ed) d = &pr->pr_fielddefs[i]; if (!d->name) // null field def (probably 1st) continue; + if (!d->type_encoding) { + dummy_type.t.type = d->type; + type = &dummy_type; + } else { + type = &G_STRUCT (pr, qfot_type_t, d->type_encoding); + } name = PR_GetString (pr, d->name); if (name[strlen (name) - 2] == '_' && strchr ("xyz", name[strlen (name) -1])) @@ -1095,41 +1410,14 @@ ED_Print (progs_t *pr, edict_t *ed) v = ed->v + d->ofs; - // if the value is still all 0, skip the field - type = d->type & ~DEF_SAVEGLOBAL; - - switch (type) { - case ev_entity: - case ev_integer: - case ev_uinteger: - case ev_pointer: - case ev_func: - case ev_field: - if (!v->integer_var) - continue; - break; - case ev_string: - if (PR_StringValid (pr, v->string_var)) - if (!PR_GetString (pr, v->string_var)[0]) - continue; - break; - case ev_float: - if (!v->float_var) - continue; - break; - case ev_vector: - if (!v[0].float_var && !v[1].float_var && !v[2].float_var) - continue; - break; - case ev_void: - break; - default: - PR_Error (pr, "ED_Print: Unhandled type %d", type); - } - l = 15 - strlen (name); if (l < 1) l = 1; - Sys_Printf ("%s%*s%s\n", name, l, "", value_string (pr, d->type, v)); + + dstring_clearstr (dstr); + value_string (&data, type, v); + Sys_Printf ("%s%*s%s\n", name, l, "", dstr->str); } + + dstring_delete (dstr); } From d0dc0e15fbb19b90e7bdfe4b873d589e2b1476bc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 19:02:16 +0900 Subject: [PATCH 044/444] Handle alias types in debug prints --- libs/gamecode/pr_debug.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 2a41ec61c..06ed76a5b 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -1055,9 +1055,10 @@ static void pr_debug_alias_view (qfot_type_t *type, pr_type_t *value, void *_data) { __auto_type data = (pr_debug_data_t *) _data; - dstring_t *dstr = data->dstr; + progs_t *pr = data->pr; - dstring_appendstr (dstr, ""); + type = &G_STRUCT (pr, qfot_type_t, type->t.alias.aux_type); + value_string (data, type, value); } VISIBLE void From c3c55f0bccc0dff92fc1815598ae0a92c1d7a9da Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 19:05:43 +0900 Subject: [PATCH 045/444] Fix some source formatting --- libs/util/sys.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libs/util/sys.c b/libs/util/sys.c index 62ddfa35b..811cac886 100644 --- a/libs/util/sys.c +++ b/libs/util/sys.c @@ -126,18 +126,18 @@ qboolean stdin_ready; /* The translation table between the graphical font and plain ASCII --KB */ VISIBLE const char sys_char_map[256] = { - '\0', '#', '#', '#', '#', '.', '#', '#', - '#', 9, 10, '#', ' ', 13, '.', '.', + 0, '#', '#', '#', '#', '.', '#', '#', + '#', 9, 10, '#', ' ', 13, '.', '.', '[', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '<', '=', '>', - ' ', '!', '"', '#', '$', '%', '&', '\'', + ' ', '!', '"', '#', '$', '%', '&','\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + 'X', 'Y', 'Z', '[','\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', @@ -147,14 +147,14 @@ VISIBLE const char sys_char_map[256] = { '#', '#', ' ', '#', ' ', '>', '.', '.', '[', ']', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.', '<', '=', '>', - ' ', '!', '"', '#', '$', '%', '&', '\'', + ' ', '!', '"', '#', '$', '%', '&','\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', + 'X', 'Y', 'Z', '[','\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', From c9fca9c98a00e9002f9a9308f2a299e645a19e44 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 20:48:12 +0900 Subject: [PATCH 046/444] Fix another inside-out type utility function --- tools/qfcc/source/type.c | 67 ++++++++++++++-------------------------- 1 file changed, 24 insertions(+), 43 deletions(-) diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 04c8d7442..a22ca4f0a 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -947,52 +947,33 @@ type_assignable (const type_t *dst, const type_t *src) int type_size (const type_t *type) { - switch (type->type) { - case ev_void: - case ev_string: - case ev_float: - case ev_vector: - case ev_entity: - case ev_field: - case ev_func: - case ev_pointer: - case ev_quat: - case ev_integer: - case ev_uinteger: - case ev_short: - case ev_double: - case ev_type_count: + switch (type->meta) { + case ty_basic: return pr_type_size[type->type]; - case ev_invalid: - switch (type->meta) { - case ty_enum: - if (!type->t.symtab) - return 0; - return type_size (&type_integer); - case ty_struct: - case ty_union: - if (!type->t.symtab) - return 0; - return type->t.symtab->size; - case ty_class: - { - class_t *class = type->t.class; - int size; - if (!class->ivars) - return 0; - size = class->ivars->size; - if (class->super_class) - size += type_size (class->super_class->type); - return size; - } - case ty_array: - return type->t.array.size * type_size (type->t.array.type); - case ty_alias: - return type_size (type->t.alias.type); - case ty_basic: + case ty_struct: + case ty_union: + if (!type->t.symtab) + return 0; + return type->t.symtab->size; + case ty_enum: + if (!type->t.symtab) + return 0; + return type_size (&type_integer); + case ty_array: + return type->t.array.size * type_size (type->t.array.type); + case ty_class: + { + class_t *class = type->t.class; + int size; + if (!class->ivars) return 0; + size = class->ivars->size; + if (class->super_class) + size += type_size (class->super_class->type); + return size; } - break; + case ty_alias: + return type_size (type->t.alias.type); } return 0; } From 2a392080693e8bfca2fac8a5feb60eba637deb67 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 20:48:43 +0900 Subject: [PATCH 047/444] Set void alignment to 1 qcc allowed void variables. --- tools/qfcc/source/type.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index a22ca4f0a..a583a943c 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -62,7 +62,7 @@ // simple types. function types are dynamically allocated type_t type_invalid = { ev_invalid, "invalid" }; -type_t type_void = { ev_void, "void" }; +type_t type_void = { ev_void, "void", 1 }; type_t type_string = { ev_string, "string", 1 }; type_t type_float = { ev_float, "float", 1 }; type_t type_vector = { ev_vector, "vector", 1 }; From ea3af84baaab88050f740796445daa4d5bab3f79 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 20:49:56 +0900 Subject: [PATCH 048/444] Fix ICE when const-folding doubles I really need to rework that system. --- tools/qfcc/include/expr.h | 1 + tools/qfcc/source/constfold.c | 6 +++++- tools/qfcc/source/expr.c | 8 ++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 36d785be0..bfeb1b83f 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -612,6 +612,7 @@ void dump_dot_expr (void *e, const char *filename); void convert_int (expr_t *e); void convert_short (expr_t *e); void convert_short_int (expr_t *e); +void convert_double (expr_t *e); void convert_nil (expr_t *e, struct type_s *t); expr_t *test_expr (expr_t *e); diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index 3cba7f467..df8ea6ae0 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -148,8 +148,12 @@ convert_to_float (expr_t *e) case ev_short: convert_short (e); return e; + case ev_double: + convert_double (e); + return e; default: - internal_error (e, 0); + internal_error (e, "bad conversion to float: %d", + e->e.value->lltype); } break; case ex_symbol: diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index ab9672813..e8505fac2 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1546,6 +1546,14 @@ convert_short_int (expr_t *e) e->e.value = new_integer_val (integer_val); } +void +convert_double (expr_t *e) +{ + float float_val = expr_double (e); + e->type = ex_value; + e->e.value = new_float_val (float_val); +} + void convert_nil (expr_t *e, type_t *t) { From 7efefceee2956cf2c725c2136d7b53f25f342ffd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 22:21:25 +0900 Subject: [PATCH 049/444] Fix a comment --- include/QF/pr_comp.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 9df0416d3..40ac1aa00 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -417,7 +417,7 @@ typedef struct dstatement_s { } GCC_STRUCT dstatement_t; typedef struct ddef_s { - pr_ushort_t type; // if DEF_SAVEGLOBGAL bit is set + pr_ushort_t type; // if DEF_SAVEGLOBAL bit is set // the variable needs to be saved in savegames pr_ushort_t ofs; string_t s_name; From 23573953a76626af7e6dba4e2a1b936b8bcbc4c1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 22:25:08 +0900 Subject: [PATCH 050/444] Change pr_type_size to pr_ushort_t --- include/QF/pr_comp.h | 2 +- libs/gamecode/pr_opcode.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 40ac1aa00..0430d35fe 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -50,7 +50,7 @@ typedef enum { ev_type_count // not a type, gives number of types } etype_t; -extern int pr_type_size[ev_type_count]; +extern pr_ushort_t pr_type_size[ev_type_count]; extern const char *pr_type_name[ev_type_count]; #define OFS_NULL 0 diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index 26ce130cb..3d2bc0c4d 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -48,7 +48,7 @@ hashtab_t *opcode_table; -VISIBLE int pr_type_size[ev_type_count] = { +VISIBLE pr_ushort_t pr_type_size[ev_type_count] = { 1, // ev_void 1, // ev_string 1, // ev_float From e6f243323e9fbbe8442d6dfd47b2d935fb380875 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 22:26:09 +0900 Subject: [PATCH 051/444] Fix type of class in qfo type encodings --- include/QF/pr_type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/QF/pr_type.h b/include/QF/pr_type.h index b2ea05060..39215840f 100644 --- a/include/QF/pr_type.h +++ b/include/QF/pr_type.h @@ -109,7 +109,7 @@ typedef struct qfot_type_s { qfot_func_t func; ///< ty_basic, ev_func qfot_struct_t strct; ///< ty_struct/ty_union/ty_enum qfot_array_t array; ///< ty_array - pointer_t class; ///< ty_class + string_t class; ///< ty_class qfot_alias_t alias; ///< ty_alias } t; } qfot_type_t; From 14cde99d6ebe83912191827556b0c228c1826542 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 22:27:07 +0900 Subject: [PATCH 052/444] White space of the worst sort. --- tools/qfcc/include/expr.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index bfeb1b83f..e8fdccb0c 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -191,12 +191,12 @@ typedef struct ex_value_s { typedef struct expr_s { struct expr_s *next; ///< the next expression in a block expression - expr_type type; ///< the type of the result of this expression - int line; ///< source line that generated this expression - string_t file; ///< source file that generated this expression + expr_type type; ///< the type of the result of this expression + int line; ///< source line that generated this expression + string_t file; ///< source file that generated this expression int printid; ///< avoid duplicate output when printing - unsigned paren:1; ///< the expression is enclosed in () - unsigned rvalue:1; ///< the expression is on the right side of = + unsigned paren:1; ///< the expression is enclosed in () + unsigned rvalue:1; ///< the expression is on the right side of = union { ex_label_t label; ///< label expression ex_labelref_t labelref; ///< label reference expression (&) From e23aa40994aff978d0f78e96e7e919ab40748365 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 22:28:54 +0900 Subject: [PATCH 053/444] Implicitly cast unadorned floating point constants Floating point constants without f or d adornments will automatically cast, without warnings, to the type appropriate to the rest of the expression. --- tools/qfcc/include/expr.h | 1 + tools/qfcc/source/def.c | 3 ++- tools/qfcc/source/expr_assign.c | 8 +++++--- tools/qfcc/source/expr_binary.c | 9 +++++++++ tools/qfcc/source/qc-lex.l | 1 + 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index e8fdccb0c..0a030e75a 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -197,6 +197,7 @@ typedef struct expr_s { int printid; ///< avoid duplicate output when printing unsigned paren:1; ///< the expression is enclosed in () unsigned rvalue:1; ///< the expression is on the right side of = + unsigned implicit:1; ///< don't warn for implicit casts union { ex_label_t label; ///< label expression ex_labelref_t labelref; ///< label reference expression (&) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 7bef8790b..ce59166a5 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -609,7 +609,8 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, reloc_def_field (init->e.value->v.pointer.def, sym->s.def); } else { ex_value_t *v = init->e.value; - if (is_double (init_type) + if (!init->implicit + && is_double (init_type) && (is_integral (sym->type) || is_float (sym->type))) { warning (init, "assigning double to %s in initializer " "(use a cast)", sym->type->name); diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 600c6140a..046f1c07b 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -151,9 +151,11 @@ check_types_compatible (expr_t *dst, expr_t *src) if (type_assignable (dst_type, src_type)) { if (is_scalar (dst_type) && is_scalar (src_type)) { - if (is_double (src_type)) { - warning (dst, "assignment of double to %s (use a cast)\n", - dst_type->name); + if (!src->implicit) { + if (is_double (src_type)) { + warning (dst, "assignment of double to %s (use a cast)\n", + dst_type->name); + } } // the types are different but cast-compatible expr_t *new = cast_expr (dst_type, src); diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 2e31116f3..ed8dcc85d 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -954,6 +954,15 @@ binary_expr (int op, expr_t *e1, expr_t *e2) et1 = low_level_type (t1); et2 = low_level_type (t2); + if (is_constant (e1) && is_double (t1) && e1->implicit && is_float (t2)) { + t1 = &type_float; + convert_double (e1); + } + if (is_constant (e2) && is_double (t2) && e2->implicit && is_float (t1)) { + t2 = &type_float; + convert_double (e2); + } + if (et1 >= ev_type_count || !binary_expr_types[et1]) return invalid_binary_expr(op, e1, e2); if (et2 >= ev_type_count || !binary_expr_types[et1][et2]) diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 58b661220..353191593 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -143,6 +143,7 @@ STRING \"(\\.|[^"\\])*\" if (options.traditional < 1) { double d = strtod (yytext, 0); qc_yylval.expr = new_double_expr (d); + qc_yylval.expr->implicit = 1; } else { float f = strtof (yytext, 0); qc_yylval.expr = new_float_expr (f); From 607fd2e30ef6e2281c83ec638934c9a56de923af Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 22:51:00 +0900 Subject: [PATCH 054/444] Allow constant initialized globals in advanced code Use -C const-initializers to enable (or no-const-initializers to disable in traditional/extended code). --- tools/qfcc/doc/man/qfcc.1 | 23 ++++++++++++++++------- tools/qfcc/include/options.h | 1 + tools/qfcc/source/def.c | 2 +- tools/qfcc/source/expr.c | 13 +++++++++++++ tools/qfcc/source/options.c | 8 +++++++- 5 files changed, 38 insertions(+), 9 deletions(-) diff --git a/tools/qfcc/doc/man/qfcc.1 b/tools/qfcc/doc/man/qfcc.1 index a5e2794e0..b4fbd2685 100644 --- a/tools/qfcc/doc/man/qfcc.1 +++ b/tools/qfcc/doc/man/qfcc.1 @@ -85,7 +85,8 @@ No compilation or linking is done. .TP .B \-\-extended -Allow extended keywords in traditional mode. +Allow extended keywords in traditional mode. Otherwise, it has \fIall\fP +the implications of \fB\-\-traditional\fP. .TP .B \-F, \-\-files @@ -198,9 +199,9 @@ Look for \*[progs.src] in \fBDIR\fP instead of the current directory. .TP .B \-\-traditional Use traditional QuakeC syntax, semantics and \*(lqbugs\*(rq. -Also implies the \fBv6only\fP, \fBno-short-circuit\fP and -\fBno-local-merging\fP code generation options (see -\fBCODE GENERATION OPTIONS\fP). +Also implies the \fBv6only\fP, \fBno-short-circuit\fP, +\fBconst-initializers\fP and \fBno-local-merging\fP code generation options +(see \fBCODE GENERATION OPTIONS\fP). This is the default when using \fBprogs.src\fP mode. .TP @@ -236,15 +237,23 @@ command line. Unsupported options are ignored. The following options are supported by \*[qfcc]'s \fB\-\-code\fP argument: +.TP +.B const-initializers +Treat initialized globals as constants. +This option is implied by \fB\-\-traditional\fP and \fB\-\-extended\fP, and is +turned off by \fB\-\-advanced\fP. + .TP .B cow Allow assignment to initialized globals. -In Quake-C and Ruamoko, a global that has been initialized to a value is not -a variable, but a named constant. +When initialized globals are treated as constants (traditional Quake-C, or +when const-initializers is activated), a global that has been initialized to a +value is not a variable, but a named constant. However, \fBqcc\fP never really enforced this. The \fBcow\fP option allows \*[qfcc] to gracefully cope with QuakeC source that assigns values to initialized globals in this manner. -(also known as \*(lqcopy on write\*(rq\(emnever mind the bovine connotations) +(also known as \*(lqcopy on write\*(rq\(emlo and behold the bovine +connotations) .TP .B cpp diff --git a/tools/qfcc/include/options.h b/tools/qfcc/include/options.h index cfcd350de..01345cff4 100644 --- a/tools/qfcc/include/options.h +++ b/tools/qfcc/include/options.h @@ -45,6 +45,7 @@ typedef struct { unsigned progsversion; // Progs version to generate code for qboolean vector_components; // add *_[xyz] symbols for vectors qboolean ifstring; // expand if (str) to if (str != "") + qboolean const_initializers; // initialied globals are constant } code_options_t; typedef struct { diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index ce59166a5..38d95ca23 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -626,7 +626,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, } } sym->s.def->initialized = 1; - if (options.traditional) { + if (options.code.const_initializers) { sym->s.def->constant = 1; sym->s.def->nosave = 1; } diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index e8505fac2..5e370c4b0 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2626,6 +2626,19 @@ cast_expr (type_t *type, expr_t *e) ex_value_t *val = 0; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const) { val = e->e.symbol->s.value; + } else if (e->type == ex_symbol + && e->e.symbol->sy_type == sy_var) { + // initialized global def treated as a constant + // from the tests above, the def is known to be constant + // and of one of the three storable scalar types + def_t *def = e->e.symbol->s.def; + if (is_float (def->type)) { + val = new_float_val (D_FLOAT (def)); + } else if (is_double (def->type)) { + val = new_double_val (D_DOUBLE (def)); + } else if (is_integral (def->type)) { + val = new_integer_val (D_INT (def)); + } } else if (e->type == ex_value) { val = e->e.value; } else if (e->type == ex_nil) { diff --git a/tools/qfcc/source/options.c b/tools/qfcc/source/options.c index c3f283e89..f9807de7b 100644 --- a/tools/qfcc/source/options.c +++ b/tools/qfcc/source/options.c @@ -194,12 +194,13 @@ code_usage (void) printf ("%s - QuakeForge Code Compiler\n", this_program); printf ("Code generation options\n"); printf ( +" [no-]const-initializers Treat initialized globals as constants.\n" " [no-]cow Allow assignment to initialized globals.\n" " [no-]cpp Preprocess all input files with cpp.\n" " [no-]crc Write progdefs.h crc to progs.dat.\n" " [no-]debug Generate debug information.\n" " [no-]fast-float Use float values directly in \"if\" statements.\n" -" help Display his text.\n" +" help Display this text.\n" " [no-]local-merging Merge the local variable blocks into one.\n" " [no-]optimize Perform various optimizations on the code.\n" " [no-]short-circuit Generate short circuit code for logical\n" @@ -392,16 +393,19 @@ DecodeArgs (int argc, char **argv) options.traditional = 1; options.advanced = false; options.code.progsversion = PROG_ID_VERSION; + options.code.const_initializers = true; break; case OPT_TRADITIONAL: options.traditional = 2; options.advanced = false; options.code.progsversion = PROG_ID_VERSION; + options.code.const_initializers = true; break; case OPT_ADVANCED: options.traditional = 0; options.advanced = true; options.code.progsversion = PROG_VERSION; + options.code.const_initializers = false; break; case OPT_BLOCK_DOT: if (optarg) { @@ -506,6 +510,8 @@ DecodeArgs (int argc, char **argv) options.code.progsversion = PROG_ID_VERSION; else options.code.progsversion = PROG_VERSION; + } else if (!(strcasecmp (temp, "const-initializers"))) { + options.code.const_initializers = flag; } temp = strtok (NULL, ","); } From 526c27cf03973ef60a3e5af706334b33ddd6be07 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 23:10:10 +0900 Subject: [PATCH 055/444] Handle implicit casts for double/float comparisons --- tools/qfcc/source/expr_binary.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index ed8dcc85d..aad78dea5 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -762,8 +762,13 @@ double_compare (int op, expr_t *e1, expr_t *e2) type_t *t2 = get_type (e2); expr_t *e; - if ((is_double (t1) && is_float (t2)) - || (is_float (t1) && is_double (t2))) { + if (is_constant (e1) && e1->implicit && is_double (t1) && is_float (t2)) { + t1 = &type_float; + convert_double (e1); + } + if (is_float (t1) && is_constant (e2) && e2->implicit && is_double (t2)) { + t2 = &type_float; + convert_double (e2); } if (is_double (t1)) { if (is_float (t2)) { @@ -772,7 +777,7 @@ double_compare (int op, expr_t *e1, expr_t *e2) warning (e2, "comparison between double and integer"); } e2 = cast_expr (&type_double, e2); - } else { + } else if (is_double (t2)) { if (is_float (t1)) { warning (e1, "comparison between float and double"); } else if (!is_constant (e1)) { From 05f6ddbb13f424fd8e54e6d835d3c7736945d859 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 23:10:56 +0900 Subject: [PATCH 056/444] Print promoted warnings as errors This makes it much easier to see why a compilation failed when only warnings are visible. --- tools/qfcc/source/diagnostic.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/diagnostic.c b/tools/qfcc/source/diagnostic.c index d38c1eecb..5ba576212 100644 --- a/tools/qfcc/source/diagnostic.c +++ b/tools/qfcc/source/diagnostic.c @@ -99,16 +99,21 @@ static __attribute__((format(printf, 4, 0))) void __warning (expr_t *e, const char *file, int line, const char *fmt, va_list args) { + static int promoted = 0; dstring_t *message = dstring_new (); report_function (e); if (options.warnings.promote) { - options.warnings.promote = 0; // want to do this only once - fprintf (stderr, "%s: warnings treated as errors\n", "qfcc"); + if (!promoted) { + promoted = 1; // want to do this only once + fprintf (stderr, "%s: warnings treated as errors\n", "qfcc"); + } pr.error_count++; + format_message (message, "error", e, fmt, args); + } else { + format_message (message, "warning", e, fmt, args); } - format_message (message, "warning", e, fmt, args); if (options.verbosity > 1) { dasprintf (message, " (%s:%d)", file, line); } From 5374798ef90147afa4abc12e43dcc1bf8d826664 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 23:18:31 +0900 Subject: [PATCH 057/444] Fix order of operations for implicit casts --- tools/qfcc/source/expr_binary.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index aad78dea5..a251860bf 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -956,9 +956,6 @@ binary_expr (int op, expr_t *e1, expr_t *e2) } } - et1 = low_level_type (t1); - et2 = low_level_type (t2); - if (is_constant (e1) && is_double (t1) && e1->implicit && is_float (t2)) { t1 = &type_float; convert_double (e1); @@ -968,6 +965,9 @@ binary_expr (int op, expr_t *e1, expr_t *e2) convert_double (e2); } + et1 = low_level_type (t1); + et2 = low_level_type (t2); + if (et1 >= ev_type_count || !binary_expr_types[et1]) return invalid_binary_expr(op, e1, e2); if (et2 >= ev_type_count || !binary_expr_types[et1][et2]) From dda045bf96fc82596a2942227bbb98b7eb77a805 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 23:29:58 +0900 Subject: [PATCH 058/444] Do lazy computation of def sizes from type encodings The size is calculated when needed and cached. --- include/QF/pr_comp.h | 3 +- libs/gamecode/pr_debug.c | 69 +++++++++++++++++++++++++++++++++++---- libs/gamecode/pr_load.c | 2 ++ libs/gamecode/pr_opcode.c | 1 + 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 0430d35fe..451d3a9ab 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -434,7 +434,8 @@ typedef struct pr_xdefs_s { } pr_xdefs_t; typedef struct pr_def_s { - pr_uint_t type; + pr_ushort_t type; + pr_ushort_t size; ///< may not be correct pointer_t ofs; string_t name; pointer_t type_encoding; diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 06ed76a5b..9b0deece5 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -195,6 +195,57 @@ pr_debug_expression_error (script_t *script, const char *msg) Sys_Printf ("%s\n", msg); } +#define RUP(x,a) (((x) + ((a) - 1)) & ~((a) - 1)) +static pr_short_t +pr_debug_type_size (progs_t *pr, qfot_type_t *type) +{ + pr_short_t size; + qfot_type_t *aux_type; + switch (type->meta) { + case ty_basic: + return pr_type_size[type->t.type]; + case ty_struct: + case ty_union: + size = 0; + for (pr_int_t i = 0; i < type->t.strct.num_fields; i++) { + qfot_var_t *field = &type->t.strct.fields[i]; + aux_type = &G_STRUCT (pr, qfot_type_t, field->type); + size = max (size, + field->offset + pr_debug_type_size (pr, aux_type)); + } + return size; + case ty_enum: + return pr_type_size[ev_integer]; + case ty_array: + aux_type = &G_STRUCT (pr, qfot_type_t, type->t.array.type); + size = pr_debug_type_size (pr, aux_type); + return type->t.array.size * size; + case ty_class: + return 1; //FIXME or should it return sizeof class struct? + case ty_alias: + aux_type = &G_STRUCT (pr, qfot_type_t, type->t.alias.aux_type); + return pr_debug_type_size (pr, aux_type); + } + return 0; +} + +static qfot_type_t * +get_def_type (progs_t *pr, pr_def_t *def, qfot_type_t *type) +{ + if (!def->type_encoding) { + // no type encoding, so use basic type data to fill in and return + // the dummy encoding + memset (type, 0, sizeof (*type)); + type->t.type = def->type; + } else { + type = &G_STRUCT (pr, qfot_type_t, def->type_encoding); + if (!def->size) { + def->size = pr_debug_type_size (pr, type); + } + } + return type; +} + static pr_def_t parse_expression (progs_t *pr, const char *expr, int conditional) { @@ -1379,7 +1430,7 @@ VISIBLE void ED_Print (progs_t *pr, edict_t *ed) { int l; - pr_uint_t i; + pr_uint_t i, j; const char *name; pr_def_t *d; pr_type_t *v; @@ -1398,17 +1449,21 @@ ED_Print (progs_t *pr, edict_t *ed) d = &pr->pr_fielddefs[i]; if (!d->name) // null field def (probably 1st) continue; - if (!d->type_encoding) { - dummy_type.t.type = d->type; - type = &dummy_type; - } else { - type = &G_STRUCT (pr, qfot_type_t, d->type_encoding); - } + type = get_def_type (pr, d, &dummy_type); name = PR_GetString (pr, d->name); if (name[strlen (name) - 2] == '_' && strchr ("xyz", name[strlen (name) -1])) continue; // skip _x, _y, _z vars + for (j = 0; j < d->size; j++) { + if (E_INT (ed, d->ofs + j)) { + break; + } + } + if (j == d->size) { + continue; + } + v = ed->v + d->ofs; l = 15 - strlen (name); diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index a7dced537..994e9b581 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -281,11 +281,13 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) pr->pr_globaldefs = calloc (pr->progs->numglobaldefs, sizeof (pr_def_t)); for (i = 0; i < pr->progs->numglobaldefs; i++) { + pr_ushort_t safe_type = global_ddefs[i].type & ~DEF_SAVEGLOBAL; global_ddefs[i].type = LittleShort (global_ddefs[i].type); global_ddefs[i].ofs = LittleShort (global_ddefs[i].ofs); global_ddefs[i].s_name = LittleLong (global_ddefs[i].s_name); pr->pr_globaldefs[i].type = global_ddefs[i].type; + pr->pr_globaldefs[i].size = pr_type_size[safe_type]; pr->pr_globaldefs[i].ofs = global_ddefs[i].ofs; pr->pr_globaldefs[i].name = global_ddefs[i].s_name; Hash_Add (pr->global_hash, &pr->pr_globaldefs[i]); diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index 3d2bc0c4d..ab266c84c 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -62,6 +62,7 @@ VISIBLE pr_ushort_t pr_type_size[ev_type_count] = { 1, // ev_uinteger 0, // ev_short value in opcode 2, // ev_double + 0, // ev_invalid not a valid/simple type }; VISIBLE const char *pr_type_name[ev_type_count] = { From f387b9aa47dc411be0238f6aec95d6bb0ad64a4a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 23:41:12 +0900 Subject: [PATCH 059/444] Propagate implicit for negating double constants --- tools/qfcc/source/expr.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 5e370c4b0..16db0b57d 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1634,6 +1634,7 @@ unary_expr (int op, expr_t *e) vec3_t v; quat_t q; const char *s; + expr_t *new; convert_name (e); if (e->type == ex_error) @@ -1651,7 +1652,9 @@ unary_expr (int op, expr_t *e) case ev_pointer: internal_error (e, "type check failed!"); case ev_double: - return new_double_expr (-expr_double (e)); + new = new_double_expr (-expr_double (e)); + new->implicit = e->implicit; + return new; case ev_float: return new_float_expr (-expr_float (e)); case ev_vector: From 27ae5ccfcecaff4d4ead562248bfe28b0c05ac4c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 23 Feb 2020 23:46:47 +0900 Subject: [PATCH 060/444] Fix ICE after incomplete type error Attempting to define a variable with an incomplete type is an error, and results in a default size 1 of allocated, but I forgot to set default alignment when implementing alignment. --- tools/qfcc/source/def.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 38d95ca23..ed5e69964 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -153,6 +153,7 @@ new_def (const char *name, type_t *type, defspace_t *space, if (!size) { error (0, "%s has incomplete type", name); size = 1; + alignment = 1; } if (alignment < 1) { print_type (type); From 11365024d2648972dd1b76252f6b1fd6e23c2752 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 00:07:48 +0900 Subject: [PATCH 061/444] Fix writing of frames files when not requested I forgot to check for the option for separate compilation. --- tools/qfcc/source/qfcc.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 9e292d136..8a363a9cd 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -391,7 +391,9 @@ compile_to_obj (const char *file, const char *obj, lang_t lang) exit (1); } } - write_frame_macros (va ("%s.frame", file_basename (file))); + if (options.frames_files) { + write_frame_macros (va ("%s.frame", file_basename (file))); + } if (!err) { qfo_t *qfo; @@ -750,8 +752,10 @@ progs_src_compile (void) } else { if (compile_file (qc_filename->str)) return 1; - write_frame_macros (va ("%s.frame", - file_basename (qc_filename->str))); + if (options.frames_files) { + write_frame_macros (va ("%s.frame", + file_basename (qc_filename->str))); + } } if (!Script_TokenAvailable (script, 0)) break; From 0bf7ec07b719bcbfb0402a292202ead3d677501b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 00:22:13 +0900 Subject: [PATCH 062/444] Make debug output verbosity 2 and internal diagnostic sources level 1. --- tools/qfcc/source/diagnostic.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/source/diagnostic.c b/tools/qfcc/source/diagnostic.c index 5ba576212..84892687f 100644 --- a/tools/qfcc/source/diagnostic.c +++ b/tools/qfcc/source/diagnostic.c @@ -114,7 +114,7 @@ __warning (expr_t *e, const char *file, int line, format_message (message, "warning", e, fmt, args); } - if (options.verbosity > 1) { + if (options.verbosity) { dasprintf (message, " (%s:%d)", file, line); } if (warning_hook) { @@ -130,7 +130,7 @@ _debug (expr_t *e, const char *file, int line, const char *fmt, ...) { va_list args; - if (options.verbosity < 1) + if (options.verbosity < 2) return; report_function (e); @@ -208,7 +208,7 @@ _notice (expr_t *e, const char *file, int line, const char *fmt, ...) report_function (e); format_message (message, "notice", e, fmt, args); - if (options.verbosity > 1) { + if (options.verbosity) { dasprintf (message, " (%s:%d)", file, line); } if (notice_hook) { @@ -257,7 +257,7 @@ _error (expr_t *e, const char *file, int line, const char *fmt, ...) dstring_t *message = dstring_new (); format_message (message, "error", e, fmt, args); - if (options.verbosity > 1) { + if (options.verbosity) { dasprintf (message, " (%s:%d)", file, line); } if (error_hook) { From d6752c254c649cb30157c810ae2f553f7b04816a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 01:20:24 +0900 Subject: [PATCH 063/444] Move short-circuit boolean code to its own file --- tools/qfcc/source/Makefile.am | 3 +- tools/qfcc/source/expr.c | 229 ------------------------- tools/qfcc/source/expr_binary.c | 3 +- tools/qfcc/source/expr_bool.c | 295 ++++++++++++++++++++++++++++++++ 4 files changed, 299 insertions(+), 231 deletions(-) create mode 100644 tools/qfcc/source/expr_bool.c diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am index 7feed1dca..d9ceb5ba2 100644 --- a/tools/qfcc/source/Makefile.am +++ b/tools/qfcc/source/Makefile.am @@ -41,7 +41,8 @@ bin_SCRIPTS= qfpreqcc common_src=\ class.c codespace.c constfold.c cpp.c dags.c debug.c def.c defspace.c \ diagnostic.c dot.c dot_dag.c dot_expr.c dot_flow.c dot_sblock.c emit.c \ - expr.c expr_assign.c expr_binary.c flow.c function.c grab.c idstuff.c \ + expr.c expr_assign.c expr_binary.c expr_bool.c flow.c function.c grab.c \ + idstuff.c \ linker.c method.c \ obj_file.c \ obj_type.c opcodes.c options.c pragma.c qfcc.c reloc.c shared.c \ diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 16db0b57d..41c3ca7a2 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1262,197 +1262,6 @@ field_expr (expr_t *e1, expr_t *e2) return type_mismatch (e1, e2, '.'); } -expr_t * -test_expr (expr_t *e) -{ - static float zero[4] = {0, 0, 0, 0}; - expr_t *new = 0; - type_t *type; - - if (e->type == ex_error) - return e; - - type = get_type (e); - if (e->type == ex_error) - return e; - switch (type->type) { - case ev_type_count: - internal_error (e, 0); - case ev_void: - if (options.traditional) { - if (options.warnings.traditional) - warning (e, "void has no value"); - return e; - } - return error (e, "void has no value"); - case ev_string: - if (!options.code.ifstring) - return new_alias_expr (type_default, e); - new = new_string_expr (0); - break; - case ev_uinteger: - case ev_integer: - case ev_short: - if (type_default != &type_integer) - return new_alias_expr (type_default, e); - return e; - case ev_float: - if (options.code.fast_float - || options.code.progsversion == PROG_ID_VERSION) { - if (type_default != &type_float) - return new_alias_expr (type_default, e); - return e; - } - new = new_float_expr (0); - break; - case ev_double: - new = new_double_expr (0); - break; - case ev_vector: - new = new_vector_expr (zero); - break; - case ev_entity: - return new_alias_expr (type_default, e); - case ev_field: - return new_alias_expr (type_default, e); - case ev_func: - return new_alias_expr (type_default, e); - case ev_pointer: - return new_alias_expr (type_default, e); - case ev_quat: - new = new_quaternion_expr (zero); - break; - case ev_invalid: - if (is_enum (type)) { - new = new_nil_expr (); - break; - } - return test_error (e, get_type (e)); - } - new->line = e->line; - new->file = e->file; - new = binary_expr (NE, e, new); - new->line = e->line; - new->file = e->file; - return new; -} - -void -backpatch (ex_list_t *list, expr_t *label) -{ - int i; - expr_t *e; - - if (!list) - return; - if (!label || label->type != ex_label) - internal_error (label, "not a label"); - - for (i = 0; i < list->size; i++) { - e = list->e[i]; - if (e->type == ex_uexpr && e->e.expr.op == 'g') - e->e.expr.e1 = label; - else if (e->type == ex_expr && (e->e.expr.op == 'i' - || e->e.expr.op == 'n')) - e->e.expr.e2 = label; - else { - internal_error (e, 0); - } - label->e.label.used++; - } -} - -static ex_list_t * -merge (ex_list_t *l1, ex_list_t *l2) -{ - ex_list_t *m; - - if (!l1 && !l2) - internal_error (0, 0); - if (!l2) - return l1; - if (!l1) - return l2; - m = malloc ((size_t)&((ex_list_t *)0)->e[l1->size + l2->size]); - m->size = l1->size + l2->size; - memcpy (m->e, l1->e, l1->size * sizeof (expr_t *)); - memcpy (m->e + l1->size, l2->e, l2->size * sizeof (expr_t *)); - return m; -} - -static ex_list_t * -make_list (expr_t *e) -{ - ex_list_t *m; - - m = malloc ((size_t)&((ex_list_t *) 0)->e[1]); - m->size = 1; - m->e[0] = e; - return m; -} - -expr_t * -convert_bool (expr_t *e, int block) -{ - expr_t *b; - - if (e->type == ex_expr && (e->e.expr.op == '=' || e->e.expr.op == PAS)) { - expr_t *src; - if (!e->paren && options.warnings.precedence) - warning (e, "suggest parentheses around assignment " - "used as truth value"); - src = e->e.expr.e2; - if (src->type == ex_block) { - src = new_temp_def_expr (get_type (src)); - e = new_binary_expr (e->e.expr.op, e->e.expr.e1, - assign_expr (src, e->e.expr.e2)); - } - b = convert_bool (src, 1); - if (b->type == ex_error) - return b; - // insert the assignment into the bool's block - e->next = b->e.bool.e->e.block.head; - b->e.bool.e->e.block.head = e; - if (b->e.bool.e->e.block.tail == &b->e.bool.e->e.block.head) { - // shouldn't happen, but just in case - b->e.bool.e->e.block.tail = &e->next; - } - return b; - } - - if (e->type == ex_uexpr && e->e.expr.op == '!' - && get_type (e->e.expr.e1) != &type_string) { - e = convert_bool (e->e.expr.e1, 0); - if (e->type == ex_error) - return e; - e = unary_expr ('!', e); - } - if (e->type != ex_bool) { - e = test_expr (e); - if (e->type == ex_error) - return e; - if (is_integer_val (e)) { - b = goto_expr (0); - if (expr_integer (e)) - e = new_bool_expr (make_list (b), 0, b); - else - e = new_bool_expr (0, make_list (b), b); - } else { - b = new_block_expr (); - append_expr (b, branch_expr ('i', e, 0)); - append_expr (b, goto_expr (0)); - e = new_bool_expr (make_list (b->e.block.head), - make_list (b->e.block.head->next), b); - } - } - if (block && e->e.bool.e->type != ex_block) { - expr_t *block = new_block_expr (); - append_expr (block, e->e.bool.e); - e->e.bool.e = block; - } - return e; -} - expr_t * convert_from_bool (expr_t *e, type_t *type) { @@ -1484,44 +1293,6 @@ convert_from_bool (expr_t *e, type_t *type) return e; } -expr_t * -bool_expr (int op, expr_t *label, expr_t *e1, expr_t *e2) -{ - expr_t *block; - - if (!options.code.short_circuit) - return binary_expr (op, e1, e2); - - e1 = convert_bool (e1, 0); - if (e1->type == ex_error) - return e1; - - e2 = convert_bool (e2, 0); - if (e2->type == ex_error) - return e2; - - block = new_block_expr (); - append_expr (block, e1); - append_expr (block, label); - append_expr (block, e2); - - switch (op) { - case OR: - backpatch (e1->e.bool.false_list, label); - return new_bool_expr (merge (e1->e.bool.true_list, - e2->e.bool.true_list), - e2->e.bool.false_list, block); - break; - case AND: - backpatch (e1->e.bool.true_list, label); - return new_bool_expr (e2->e.bool.true_list, - merge (e1->e.bool.false_list, - e2->e.bool.false_list), block); - break; - } - internal_error (e1, 0); -} - void convert_int (expr_t *e) { diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index a251860bf..ee1fb162c 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -992,8 +992,9 @@ binary_expr (int op, expr_t *e1, expr_t *e2) e = new_binary_expr (op, e1, e2); e->e.expr.type = expr_type->type; if (is_compare (op) || is_logic (op)) { - if (options.code.progsversion == PROG_ID_VERSION) + if (options.code.progsversion == PROG_ID_VERSION) { e->e.expr.type = &type_float; + } } return fold_constants (e); } diff --git a/tools/qfcc/source/expr_bool.c b/tools/qfcc/source/expr_bool.c new file mode 100644 index 000000000..6eda9aa8d --- /dev/null +++ b/tools/qfcc/source/expr_bool.c @@ -0,0 +1,295 @@ +/* + expr_bool.c + + short-circuit boolean expressions + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + Date: 2001/06/15 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "qfcc.h" +#include "class.h" +#include "def.h" +#include "defspace.h" +#include "diagnostic.h" +#include "emit.h" +#include "expr.h" +#include "function.h" +#include "idstuff.h" +#include "method.h" +#include "options.h" +#include "reloc.h" +#include "shared.h" +#include "strpool.h" +#include "struct.h" +#include "symtab.h" +#include "type.h" +#include "value.h" +#include "qc-parse.h" + +expr_t * +test_expr (expr_t *e) +{ + static float zero[4] = {0, 0, 0, 0}; + expr_t *new = 0; + type_t *type; + + if (e->type == ex_error) + return e; + + type = get_type (e); + if (e->type == ex_error) + return e; + switch (type->type) { + case ev_type_count: + internal_error (e, 0); + case ev_void: + if (options.traditional) { + if (options.warnings.traditional) + warning (e, "void has no value"); + return e; + } + return error (e, "void has no value"); + case ev_string: + if (!options.code.ifstring) + return new_alias_expr (type_default, e); + new = new_string_expr (0); + break; + case ev_uinteger: + case ev_integer: + case ev_short: + if (type_default != &type_integer) + return new_alias_expr (type_default, e); + return e; + case ev_float: + if (options.code.fast_float + || options.code.progsversion == PROG_ID_VERSION) { + if (type_default != &type_float) + return new_alias_expr (type_default, e); + return e; + } + new = new_float_expr (0); + break; + case ev_double: + new = new_double_expr (0); + break; + case ev_vector: + new = new_vector_expr (zero); + break; + case ev_entity: + return new_alias_expr (type_default, e); + case ev_field: + return new_alias_expr (type_default, e); + case ev_func: + return new_alias_expr (type_default, e); + case ev_pointer: + return new_alias_expr (type_default, e); + case ev_quat: + new = new_quaternion_expr (zero); + break; + case ev_invalid: + if (is_enum (type)) { + new = new_nil_expr (); + break; + } + return test_error (e, get_type (e)); + } + new->line = e->line; + new->file = e->file; + new = binary_expr (NE, e, new); + new->line = e->line; + new->file = e->file; + return new; +} + +void +backpatch (ex_list_t *list, expr_t *label) +{ + int i; + expr_t *e; + + if (!list) + return; + if (!label || label->type != ex_label) + internal_error (label, "not a label"); + + for (i = 0; i < list->size; i++) { + e = list->e[i]; + if (e->type == ex_uexpr && e->e.expr.op == 'g') + e->e.expr.e1 = label; + else if (e->type == ex_expr && (e->e.expr.op == 'i' + || e->e.expr.op == 'n')) + e->e.expr.e2 = label; + else { + internal_error (e, 0); + } + label->e.label.used++; + } +} + +static ex_list_t * +merge (ex_list_t *l1, ex_list_t *l2) +{ + ex_list_t *m; + + if (!l1 && !l2) + internal_error (0, 0); + if (!l2) + return l1; + if (!l1) + return l2; + m = malloc ((size_t)&((ex_list_t *)0)->e[l1->size + l2->size]); + m->size = l1->size + l2->size; + memcpy (m->e, l1->e, l1->size * sizeof (expr_t *)); + memcpy (m->e + l1->size, l2->e, l2->size * sizeof (expr_t *)); + return m; +} + +static ex_list_t * +make_list (expr_t *e) +{ + ex_list_t *m; + + m = malloc ((size_t)&((ex_list_t *) 0)->e[1]); + m->size = 1; + m->e[0] = e; + return m; +} + +expr_t * +bool_expr (int op, expr_t *label, expr_t *e1, expr_t *e2) +{ + expr_t *block; + + if (!options.code.short_circuit) + return binary_expr (op, e1, e2); + + e1 = convert_bool (e1, 0); + if (e1->type == ex_error) + return e1; + + e2 = convert_bool (e2, 0); + if (e2->type == ex_error) + return e2; + + block = new_block_expr (); + append_expr (block, e1); + append_expr (block, label); + append_expr (block, e2); + + switch (op) { + case OR: + backpatch (e1->e.bool.false_list, label); + return new_bool_expr (merge (e1->e.bool.true_list, + e2->e.bool.true_list), + e2->e.bool.false_list, block); + break; + case AND: + backpatch (e1->e.bool.true_list, label); + return new_bool_expr (e2->e.bool.true_list, + merge (e1->e.bool.false_list, + e2->e.bool.false_list), block); + break; + } + internal_error (e1, 0); +} + +expr_t * +convert_bool (expr_t *e, int block) +{ + expr_t *b; + + if (e->type == ex_expr && (e->e.expr.op == '=' || e->e.expr.op == PAS)) { + expr_t *src; + if (!e->paren && options.warnings.precedence) + warning (e, "suggest parentheses around assignment " + "used as truth value"); + src = e->e.expr.e2; + if (src->type == ex_block) { + src = new_temp_def_expr (get_type (src)); + e = new_binary_expr (e->e.expr.op, e->e.expr.e1, + assign_expr (src, e->e.expr.e2)); + } + b = convert_bool (src, 1); + if (b->type == ex_error) + return b; + // insert the assignment into the bool's block + e->next = b->e.bool.e->e.block.head; + b->e.bool.e->e.block.head = e; + if (b->e.bool.e->e.block.tail == &b->e.bool.e->e.block.head) { + // shouldn't happen, but just in case + b->e.bool.e->e.block.tail = &e->next; + } + return b; + } + + if (e->type == ex_uexpr && e->e.expr.op == '!' + && get_type (e->e.expr.e1) != &type_string) { + e = convert_bool (e->e.expr.e1, 0); + if (e->type == ex_error) + return e; + e = unary_expr ('!', e); + } + if (e->type != ex_bool) { + e = test_expr (e); + if (e->type == ex_error) + return e; + if (is_integer_val (e)) { + b = goto_expr (0); + if (expr_integer (e)) + e = new_bool_expr (make_list (b), 0, b); + else + e = new_bool_expr (0, make_list (b), b); + } else { + b = new_block_expr (); + append_expr (b, branch_expr ('i', e, 0)); + append_expr (b, goto_expr (0)); + e = new_bool_expr (make_list (b->e.block.head), + make_list (b->e.block.head->next), b); + } + } + if (block && e->e.bool.e->type != ex_block) { + expr_t *block = new_block_expr (); + append_expr (block, e->e.bool.e); + e->e.bool.e = block; + } + return e; +} From 55e53211e2711e155b1ace1a6d19e363d2a6647c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 02:11:31 +0900 Subject: [PATCH 064/444] Generate default type expressions for folded booleans --- tools/qfcc/source/constfold.c | 102 +++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 46 deletions(-) diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index df8ea6ae0..e7c037deb 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -69,6 +69,16 @@ valid_op (int op, int *valid_ops) return *valid_ops == op; } +static expr_t * +cmp_result_expr (int result) +{ + if (is_float (type_default)) { + return new_float_expr (result); + } else { + return new_integer_expr(result); + } +} + static expr_t * do_op_string (int op, expr_t *e, expr_t *e1, expr_t *e2) { @@ -108,22 +118,22 @@ do_op_string (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_string_expr (save_string (temp_str->str)); break; case LT: - e = new_integer_expr (strcmp (s1, s2) < 0); + e = cmp_result_expr (strcmp (s1, s2) < 0); break; case GT: - e = new_integer_expr (strcmp (s1, s2) > 0); + e = cmp_result_expr (strcmp (s1, s2) > 0); break; case LE: - e = new_integer_expr (strcmp (s1, s2) <= 0); + e = cmp_result_expr (strcmp (s1, s2) <= 0); break; case GE: - e = new_integer_expr (strcmp (s1, s2) >= 0); + e = cmp_result_expr (strcmp (s1, s2) >= 0); break; case EQ: - e = new_integer_expr (strcmp (s1, s2) == 0); + e = cmp_result_expr (strcmp (s1, s2) == 0); break; case NE: - e = new_integer_expr (strcmp (s1, s2)); + e = cmp_result_expr (strcmp (s1, s2)); break; default: internal_error (e1, 0); @@ -300,28 +310,28 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_float_expr ((int)f1 >> (int)f2); break; case AND: - e = new_integer_expr (f1 && f2); + e = cmp_result_expr (f1 && f2); break; case OR: - e = new_integer_expr (f1 || f2); + e = cmp_result_expr (f1 || f2); break; case LT: - e = new_integer_expr (f1 < f2); + e = cmp_result_expr (f1 < f2); break; case GT: - e = new_integer_expr (f1 > f2); + e = cmp_result_expr (f1 > f2); break; case LE: - e = new_integer_expr (f1 <= f2); + e = cmp_result_expr (f1 <= f2); break; case GE: - e = new_integer_expr (f1 >= f2); + e = cmp_result_expr (f1 >= f2); break; case EQ: - e = new_integer_expr (f1 == f2); + e = cmp_result_expr (f1 == f2); break; case NE: - e = new_integer_expr (f1 != f2); + e = cmp_result_expr (f1 != f2); break; default: internal_error (e1, 0); @@ -411,22 +421,22 @@ do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_double_expr ((int)d1 % (int)d2); break; case LT: - e = new_integer_expr (d1 < d2); + e = cmp_result_expr (d1 < d2); break; case GT: - e = new_integer_expr (d1 > d2); + e = cmp_result_expr (d1 > d2); break; case LE: - e = new_integer_expr (d1 <= d2); + e = cmp_result_expr (d1 <= d2); break; case GE: - e = new_integer_expr (d1 >= d2); + e = cmp_result_expr (d1 >= d2); break; case EQ: - e = new_integer_expr (d1 == d2); + e = cmp_result_expr (d1 == d2); break; case NE: - e = new_integer_expr (d1 != d2); + e = cmp_result_expr (d1 != d2); break; default: internal_error (e1, 0); @@ -539,10 +549,10 @@ do_op_vector (int op, expr_t *e, expr_t *e1, expr_t *e2) } break; case EQ: - e = new_integer_expr (VectorCompare (v1, v2)); + e = cmp_result_expr (VectorCompare (v1, v2)); break; case NE: - e = new_integer_expr (!VectorCompare (v1, v2)); + e = cmp_result_expr (!VectorCompare (v1, v2)); break; default: internal_error (e1, 0); @@ -776,10 +786,10 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_quaternion_expr (q); break; case EQ: - e = new_integer_expr (QuatCompare (q1, q2)); + e = cmp_result_expr (QuatCompare (q1, q2)); break; case NE: - e = new_integer_expr (!QuatCompare (q1, q2)); + e = cmp_result_expr (!QuatCompare (q1, q2)); break; default: internal_error (e1, 0); @@ -877,28 +887,28 @@ do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_integer_expr (i1 >> i2); break; case AND: - e = new_integer_expr (i1 && i2); + e = cmp_result_expr (i1 && i2); break; case OR: - e = new_integer_expr (i1 || i2); + e = cmp_result_expr (i1 || i2); break; case LT: - e = new_integer_expr (i1 < i2); + e = cmp_result_expr (i1 < i2); break; case GT: - e = new_integer_expr (i1 > i2); + e = cmp_result_expr (i1 > i2); break; case LE: - e = new_integer_expr (i1 <= i2); + e = cmp_result_expr (i1 <= i2); break; case GE: - e = new_integer_expr (i1 >= i2); + e = cmp_result_expr (i1 >= i2); break; case EQ: - e = new_integer_expr (i1 == i2); + e = cmp_result_expr (i1 == i2); break; case NE: - e = new_integer_expr (i1 != i2); + e = cmp_result_expr (i1 != i2); break; default: internal_error (e1, 0); @@ -981,22 +991,22 @@ do_op_short (int op, expr_t *e, expr_t *e1, expr_t *e2) e = new_short_expr (i1 || i2); break; case LT: - e = new_integer_expr (i1 < i2); + e = cmp_result_expr (i1 < i2); break; case GT: - e = new_integer_expr (i1 > i2); + e = cmp_result_expr (i1 > i2); break; case LE: - e = new_integer_expr (i1 <= i2); + e = cmp_result_expr (i1 <= i2); break; case GE: - e = new_integer_expr (i1 >= i2); + e = cmp_result_expr (i1 >= i2); break; case EQ: - e = new_integer_expr (i1 == i2); + e = cmp_result_expr (i1 == i2); break; case NE: - e = new_integer_expr (i1 != i2); + e = cmp_result_expr (i1 != i2); break; default: internal_error (e1, 0); @@ -1375,7 +1385,7 @@ uop_string (int op, expr_t *e, expr_t *e1) return e; s = expr_string (e1); - return new_integer_expr (!s || !s[0]); + return cmp_result_expr (!s || !s[0]); } static expr_t * @@ -1399,7 +1409,7 @@ uop_float (int op, expr_t *e, expr_t *e1) return new_float_expr (-expr_float (e1)); case '!': print_type (get_type (e)); - return new_integer_expr (!expr_float (e1)); + return cmp_result_expr (!expr_float (e1)); case '~': return new_float_expr (~(int) expr_float (e1)); case 'C': @@ -1430,7 +1440,7 @@ uop_vector (int op, expr_t *e, expr_t *e1) VectorNegate (expr_vector (e), v); return new_vector_expr (v); case '!': - return new_integer_expr (!VectorIsZero (expr_vector (e1))); + return cmp_result_expr (!VectorIsZero (expr_vector (e1))); } internal_error (e, "vector unary op blew up"); } @@ -1524,7 +1534,7 @@ uop_quaternion (int op, expr_t *e, expr_t *e1) QuatNegate (expr_vector (e), q); return new_quaternion_expr (q); case '!': - return new_integer_expr (!QuatIsZero (expr_quaternion (e1))); + return cmp_result_expr (!QuatIsZero (expr_quaternion (e1))); case '~': QuatConj (expr_vector (e), q); return new_quaternion_expr (q); @@ -1550,7 +1560,7 @@ uop_integer (int op, expr_t *e, expr_t *e1) case '-': return new_integer_expr (-expr_integer (e1)); case '!': - return new_integer_expr (!expr_integer (e1)); + return cmp_result_expr (!expr_integer (e1)); case '~': return new_integer_expr (~expr_integer (e1)); case 'C': @@ -1575,7 +1585,7 @@ uop_uinteger (int op, expr_t *e, expr_t *e1) case '-': return new_uinteger_expr (-expr_uinteger (e1)); case '!': - return new_integer_expr (!expr_uinteger (e1)); + return cmp_result_expr (!expr_uinteger (e1)); case '~': return new_uinteger_expr (~expr_uinteger (e1)); } @@ -1598,7 +1608,7 @@ uop_short (int op, expr_t *e, expr_t *e1) case '-': return new_short_expr (-expr_short (e1)); case '!': - return new_integer_expr (!expr_short (e1)); + return cmp_result_expr (!expr_short (e1)); case '~': return new_short_expr (~expr_short (e1)); } @@ -1626,7 +1636,7 @@ uop_double (int op, expr_t *e, expr_t *e1) return new_double_expr (-expr_double (e1)); case '!': print_type (get_type (e)); - return new_integer_expr (!expr_double (e1)); + return cmp_result_expr (!expr_double (e1)); case 'C': if (type == &type_integer) { return new_integer_expr (expr_double (e1)); From 9c26d12f95bae7c4223dc601ed49f577ec267ae4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 02:13:23 +0900 Subject: [PATCH 065/444] Cast rather than alias for testing constants Fixes ICE in do { ... } while (1); --- tools/qfcc/source/expr_bool.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/expr_bool.c b/tools/qfcc/source/expr_bool.c index 6eda9aa8d..c460144b5 100644 --- a/tools/qfcc/source/expr_bool.c +++ b/tools/qfcc/source/expr_bool.c @@ -96,14 +96,22 @@ test_expr (expr_t *e) case ev_uinteger: case ev_integer: case ev_short: - if (type_default != &type_integer) + if (type_default != &type_integer) { + if (is_constant (e)) { + return cast_expr (type_default, e); + } return new_alias_expr (type_default, e); + } return e; case ev_float: if (options.code.fast_float || options.code.progsversion == PROG_ID_VERSION) { - if (type_default != &type_float) + if (type_default != &type_float) { + if (is_constant (e)) { + return cast_expr (type_default, e); + } return new_alias_expr (type_default, e); + } return e; } new = new_float_expr (0); From ac32bbca40d0dbb1f79d78e202f5a496c0005005 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 02:14:44 +0900 Subject: [PATCH 066/444] Improve code for short-circuited float logic --- tools/qfcc/source/expr_bool.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/expr_bool.c b/tools/qfcc/source/expr_bool.c index c460144b5..7f7fdbfee 100644 --- a/tools/qfcc/source/expr_bool.c +++ b/tools/qfcc/source/expr_bool.c @@ -280,9 +280,16 @@ convert_bool (expr_t *e, int block) e = test_expr (e); if (e->type == ex_error) return e; - if (is_integer_val (e)) { + if (is_constant (e)) { + int val; + b = goto_expr (0); - if (expr_integer (e)) + if (is_integer_val (e)) { + val = expr_integer (e); + } else { + val = expr_float (e) != 0; + } + if (val) e = new_bool_expr (make_list (b), 0, b); else e = new_bool_expr (0, make_list (b), b); From 2adcad7c84e23522a94cf6f683b294b4cb5ab80a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 02:25:28 +0900 Subject: [PATCH 067/444] Allow non-short-circuited logic to work --- tools/qfcc/source/expr_binary.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index ee1fb162c..228112311 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -72,6 +72,8 @@ static expr_type_t float_float[] = { {MOD, &type_float}, {SHL, &type_float}, {SHR, &type_float}, + {AND, &type_integer}, + {OR, &type_integer}, {EQ, &type_integer}, {NE, &type_integer}, {LE, &type_integer}, @@ -274,6 +276,8 @@ static expr_type_t integer_integer[] = { {MOD, &type_integer}, {SHL, &type_integer}, {SHR, &type_integer}, + {AND, &type_integer}, + {OR, &type_integer}, {EQ, &type_integer}, {NE, &type_integer}, {LE, &type_integer}, From c43b9681ebc62155b316f56e1d300ccec44a05e9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 08:43:32 +0900 Subject: [PATCH 068/444] Keep structure members aligned --- tools/qfcc/source/struct.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 800a1aa66..5fe569d31 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -124,6 +124,7 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) if (s->sy_type != sy_var) continue; if (su == 's') { + symtab->size = RUP (symtab->size, s->type->alignment); s->s.offset = symtab->size; symtab->size += type_size (s->type); } else { From 7406e0308e85179f0104a785ea233abc989b8314 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 11:28:43 +0900 Subject: [PATCH 069/444] Fix some warnings picked up in an optimized build --- include/QF/progs.h | 6 +++--- libs/console/buffer.c | 2 +- libs/gamecode/pr_debug.c | 8 ++++---- tools/qfcc/source/obj_file.c | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 78b3036c7..d007ac81f 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1787,7 +1787,7 @@ struct progs_s { \return C pointer represented by the parameter. 0 offset -> NULL */ static inline pr_type_t * -PR_GetPointer (progs_t *pr, pointer_t o) +PR_GetPointer (const progs_t *pr, pointer_t o) { return o ? pr->pr_globals + o : 0; } @@ -1798,9 +1798,9 @@ PR_GetPointer (progs_t *pr, pointer_t o) \return Progs offset/pointer represented by \c p. NULL -> 0 offset */ static inline pointer_t -PR_SetPointer (progs_t *pr, void *p) +PR_SetPointer (const progs_t *pr, const void *p) { - return p ? (pr_type_t *) p - pr->pr_globals : 0; + return p ? (const pr_type_t *) p - pr->pr_globals : 0; } ///@} diff --git a/libs/console/buffer.c b/libs/console/buffer.c index d494c0655..2aa477abc 100644 --- a/libs/console/buffer.c +++ b/libs/console/buffer.c @@ -92,7 +92,7 @@ Con_BufferAddText (con_buffer_t *buf, const char *text) } while (len--) { byte c = *pos++ = *text++; - if ((size_t) (pos - buf->buffer) >= buf->buffer_size) + if (pos >= buf->buffer + buf->buffer_size) pos = buf->buffer; cur_line->len++; if (pos == tail_line->text) { diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 9b0deece5..d895f631a 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -196,8 +196,8 @@ pr_debug_expression_error (script_t *script, const char *msg) } #define RUP(x,a) (((x) + ((a) - 1)) & ~((a) - 1)) -static pr_short_t -pr_debug_type_size (progs_t *pr, qfot_type_t *type) +static pr_short_t __attribute__((pure)) +pr_debug_type_size (const progs_t *pr, const qfot_type_t *type) { pr_short_t size; qfot_type_t *aux_type; @@ -208,7 +208,7 @@ pr_debug_type_size (progs_t *pr, qfot_type_t *type) case ty_union: size = 0; for (pr_int_t i = 0; i < type->t.strct.num_fields; i++) { - qfot_var_t *field = &type->t.strct.fields[i]; + const qfot_var_t *field = &type->t.strct.fields[i]; aux_type = &G_STRUCT (pr, qfot_type_t, field->type); size = max (size, field->offset + pr_debug_type_size (pr, aux_type)); @@ -995,7 +995,7 @@ pr_debug_pointer_view (qfot_type_t *type, pr_type_t *value, void *_data) progs_t *pr = data->pr; dstring_t *dstr = data->dstr; pointer_t ofs = value->integer_var; - pr_def_t *def; + pr_def_t *def = 0; if (pr_debug->int_val && pr->debug) { def = PR_Get_Local_Def (pr, ofs); diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 735a68ab0..855e48b61 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -891,7 +891,7 @@ qfo_to_progs (qfo_t *qfo, int *size) int xdefs_start; unsigned big_locals = 0; int big_func = 0; - pr_xdefs_t *xdefs; + pr_xdefs_t *xdefs = 0; xdef_t *xdef; *size = RUP (sizeof (dprograms_t), 16); From a30433fa9ebfa47ced0ac883e33f8d0c333c3272 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 12:21:20 +0900 Subject: [PATCH 070/444] Make header protection consistent And delete a couple of useless files. --- include/QF/Makefile.am | 4 ++-- include/QF/bspfile.h | 6 ++--- include/QF/cdaudio.h | 6 ++--- include/QF/checksum.h | 6 ++--- include/QF/console.h | 6 ++--- include/QF/crc.h | 6 ++--- include/QF/cvar.h | 6 ++--- include/QF/draw.h | 6 ++--- include/QF/dstring.h | 6 ++--- include/QF/gib.h | 6 ++--- include/QF/hash.h | 6 ++--- include/QF/hl.h | 40 -------------------------------- include/QF/image.h | 2 +- include/QF/info.h | 6 ++--- include/QF/input.h | 6 ++--- include/QF/iqm.h | 6 ++--- include/QF/joystick.h | 6 ++--- include/QF/keys.h | 6 ++--- include/QF/link.h | 6 ++--- include/QF/llist.h | 6 ++--- include/QF/locs.h | 6 ++--- include/QF/mathlib.h | 6 ++--- include/QF/mdfour.h | 6 ++--- include/QF/model.h | 6 ++--- include/QF/modelgen.h | 6 ++--- include/QF/msg.h | 6 ++--- include/QF/object.h | 6 ++--- include/QF/pak.h | 6 ++--- include/QF/pcx.h | 6 ++--- include/QF/plugin.h | 6 ++--- include/QF/pr_comp.h | 6 ++--- include/QF/pr_debug.h | 6 ++--- include/QF/pr_obj.h | 6 ++--- include/QF/pr_type.h | 6 ++--- include/QF/qargs.h | 6 ++--- include/QF/qdefs.h | 6 ++--- include/QF/qendian.h | 6 ++--- include/QF/qfplist.h | 6 ++--- include/QF/qtypes.h | 6 ++--- include/QF/quakefs.h | 6 ++--- include/QF/quakeio.h | 6 ++--- include/QF/render.h | 6 ++--- include/QF/screen.h | 6 ++--- include/QF/sizebuf.h | 6 ++--- include/QF/skin.h | 6 ++--- include/QF/sound.h | 6 ++--- include/QF/spritegn.h | 6 ++--- include/QF/sys.h | 6 ++--- include/QF/teamplay.h | 6 ++--- include/QF/tga.h | 6 ++--- include/QF/uint32.h | 52 ------------------------------------------ include/QF/va.h | 6 ++--- include/QF/ver_check.h | 6 ++--- include/QF/vid.h | 6 ++--- include/QF/view.h | 6 ++--- include/QF/wad.h | 6 ++--- include/QF/zone.h | 6 ++--- 57 files changed, 162 insertions(+), 254 deletions(-) delete mode 100644 include/QF/hl.h delete mode 100644 include/QF/uint32.h diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am index 8bf956359..3041d64d6 100644 --- a/include/QF/Makefile.am +++ b/include/QF/Makefile.am @@ -2,14 +2,14 @@ AUTOMAKE_OPTIONS = foreign pkgincludedir = $(includedir)/QF nobase_pkginclude_HEADERS = \ alloc.h bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \ - console.h crc.h csqc.h cvar.h dstring.h draw.h gib.h hash.h hl.h \ + console.h crc.h csqc.h cvar.h dstring.h draw.h gib.h hash.h \ idparse.h image.h in_event.h info.h input.h iqm.h joystick.h keys.h \ link.h llist.h locs.h mathlib.h mdfour.h mersenne.h model.h modelgen.h \ msg.h object.h pak.h pakfile.h pcx.h png.h plugin.h pr_comp.h pr_debug.h \ pr_obj.h pr_type.h progs.h qargs.h qdefs.h qendian.h qfplist.h qtypes.h \ quakefs.h \ quakeio.h render.h riff.h ruamoko.h screen.h script.h segtext.h set.h \ - sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h tga.h uint32.h va.h \ + sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h tga.h va.h \ ver_check.h vid.h vrect.h view.h wad.h wadfile.h winding.h zone.h \ \ GL/ati.h GL/defines.h GL/extensions.h GL/funcs.h GL/qf_draw.h \ diff --git a/include/QF/bspfile.h b/include/QF/bspfile.h index b7683849f..0d32c09e8 100644 --- a/include/QF/bspfile.h +++ b/include/QF/bspfile.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __bspfile_h_ -#define __bspfile_h_ +#ifndef __QF_bspfile_h +#define __QF_bspfile_h #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -310,4 +310,4 @@ void BSP_AddVisibility (bsp_t *bsp, const byte *visdata, size_t visdatasize); void BSP_AddEntities (bsp_t *bsp, const char *entdata, size_t entdatasize); void BSP_AddTextures (bsp_t *bsp, const byte *texdata, size_t texdatasize); -#endif//__bspfile_h_ +#endif//__QF_bspfile_h diff --git a/include/QF/cdaudio.h b/include/QF/cdaudio.h index e7596ad78..abc07b2e7 100644 --- a/include/QF/cdaudio.h +++ b/include/QF/cdaudio.h @@ -25,8 +25,8 @@ */ -#ifndef _CDAUDIO_H -#define _CDAUDIO_H +#ifndef __QF_cdaudio_h +#define __QF_cdaudio_h #include "QF/qtypes.h" @@ -38,4 +38,4 @@ void CDAudio_Resume(void); void CDAudio_Shutdown(void); void CDAudio_Update(void); -#endif // _CDAUDIO_H +#endif//__QF_cdaudio_h diff --git a/include/QF/checksum.h b/include/QF/checksum.h index ed6f035b1..12fcaf477 100644 --- a/include/QF/checksum.h +++ b/include/QF/checksum.h @@ -25,8 +25,8 @@ */ -#ifndef __checksum_h -#define __checksum_h +#ifndef __QF_checksum_h +#define __QF_checksum_h /** \addtogroup crc */ @@ -40,4 +40,4 @@ byte COM_BlockSequenceCRCByte (const byte *base, int length, int sequence); ///@} -#endif // __checksum_h +#endif//__QF_checksum_h diff --git a/include/QF/console.h b/include/QF/console.h index 4f3bcb3c8..da88f8744 100644 --- a/include/QF/console.h +++ b/include/QF/console.h @@ -25,8 +25,8 @@ */ -#ifndef __console_h -#define __console_h +#ifndef __QF_console_h +#define __QF_console_h #include @@ -151,4 +151,4 @@ void Menu_Leave_f (void); void Menu_Prev_f (void); void Menu_Next_f (void); -#endif // __console_h +#endif//__QF_console_h diff --git a/include/QF/crc.h b/include/QF/crc.h index cc635e7b9..ad26bacb8 100644 --- a/include/QF/crc.h +++ b/include/QF/crc.h @@ -25,8 +25,8 @@ */ -#ifndef __crc_h -#define __crc_h +#ifndef __QF_crc_h +#define __QF_crc_h /** \defgroup crc Checksum generation. \ingroup utils @@ -43,4 +43,4 @@ unsigned short CRC_Block (const byte *start, int count) __attribute__((pure)); ///@} -#endif // __crc_h +#endif//__QF_crc_h diff --git a/include/QF/cvar.h b/include/QF/cvar.h index 3d81a3b1c..946a20f13 100644 --- a/include/QF/cvar.h +++ b/include/QF/cvar.h @@ -25,8 +25,8 @@ */ -#ifndef __cvar_h -#define __cvar_h +#ifndef __QF_cvar_h +#define __QF_cvar_h /** \defgroup cvar Configuration variables \ingroup utils @@ -140,4 +140,4 @@ extern cvar_t *cvar_vars; ///@} -#endif // __cvar_h +#endif//__QF_cvar_h diff --git a/include/QF/draw.h b/include/QF/draw.h index 529f3e892..8f6b78889 100644 --- a/include/QF/draw.h +++ b/include/QF/draw.h @@ -25,8 +25,8 @@ */ -#ifndef _DRAW_H -#define _DRAW_H +#ifndef __QF_draw_h +#define __QF_draw_h /** \defgroup video Video Sub-sytem */ @@ -234,4 +234,4 @@ void Draw_Picf (float x, float y, qpic_t *pic); void Draw_SubPic(int x, int y, qpic_t *pic, int srcx, int srcy, int width, int height); ///@} -#endif // _DRAW_H +#endif//__QF_draw_h diff --git a/include/QF/dstring.h b/include/QF/dstring.h index 638d9e340..bb5ea9117 100644 --- a/include/QF/dstring.h +++ b/include/QF/dstring.h @@ -25,8 +25,8 @@ */ -#ifndef __dstring_h -#define __dstring_h +#ifndef __QF_dstring_h +#define __QF_dstring_h /** \defgroup dstring Dynamic Strings \ingroup utils @@ -177,4 +177,4 @@ int dasprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(prin ///@} -#endif // __dstring_h +#endif//__QF_dstring_h diff --git a/include/QF/gib.h b/include/QF/gib.h index 34c187ac7..09bcf01ad 100644 --- a/include/QF/gib.h +++ b/include/QF/gib.h @@ -28,8 +28,8 @@ */ -#ifndef __gib_h -#define __gib_h +#ifndef __QF_gib_h +#define __QF_gib_h // Dependencies @@ -216,4 +216,4 @@ unsigned long int GIB_Handle_New (gib_object_t *data); void GIB_Handle_Free (unsigned long int num); gib_object_t *GIB_Handle_Get (unsigned long int num) __attribute__((pure)); -#endif +#endif//__QF_gib_h diff --git a/include/QF/hash.h b/include/QF/hash.h index ae040cfa9..7a31a06db 100644 --- a/include/QF/hash.h +++ b/include/QF/hash.h @@ -25,8 +25,8 @@ */ -#ifndef __hash_h -#define __hash_h +#ifndef __QF_hash_h +#define __QF_hash_h #include #include @@ -211,4 +211,4 @@ void Hash_Stats (hashtab_t *tab); ///@} -#endif // __hash_h +#endif//__QF_hash_h diff --git a/include/QF/hl.h b/include/QF/hl.h deleted file mode 100644 index 286768cc0..000000000 --- a/include/QF/hl.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - hl_bsp.h - - Half Life file definitions - - Copyright (C) 1996-1997 Id Software, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ - - -#ifndef _HL_BSP_H -#define _HL_BSP_H - -#include "QF/qtypes.h" - -extern void CL_ParseEntityLump(const char *entdata); -extern void HL_Mod_LoadLighting (lump_t *l); -extern void HL_Mod_LoadTextures (lump_t *l); -extern byte *W_GetTexture(const char *name, int matchwidth, int matchheight); -extern void W_LoadTextureWadFile (const char *filename, int complain); - -#endif // _HL_BSP_H diff --git a/include/QF/image.h b/include/QF/image.h index 33c69c120..106379bb7 100644 --- a/include/QF/image.h +++ b/include/QF/image.h @@ -49,4 +49,4 @@ typedef struct tex_s { tex_t *LoadImage (const char *imageFile); -#endif //__QF_image_h +#endif//__QF_image_h diff --git a/include/QF/info.h b/include/QF/info.h index 4e34f6fa2..7bf16b0ab 100644 --- a/include/QF/info.h +++ b/include/QF/info.h @@ -25,8 +25,8 @@ */ -#ifndef _INFO_H -#define _INFO_H +#ifndef __QF_info_h +#define __QF_info_h /** \defgroup info Info Keys \ingroup utils @@ -65,4 +65,4 @@ void Info_AddKeys (info_t *info, info_t *keys); ///@} -#endif // _INFO_H +#endif//__QF_info_h diff --git a/include/QF/input.h b/include/QF/input.h index 8f0438071..5835ee17b 100644 --- a/include/QF/input.h +++ b/include/QF/input.h @@ -25,8 +25,8 @@ */ -#ifndef __QF_input_h_ -#define __QF_input_h_ +#ifndef __QF_input_h +#define __QF_input_h #include "QF/keys.h" @@ -75,4 +75,4 @@ void IN_LL_Grab_Input (int grab); extern kbutton_t in_strafe, in_klook, in_speed, in_mlook; -#endif // __QF_input_h_ +#endif//__QF_input_h diff --git a/include/QF/iqm.h b/include/QF/iqm.h index fb6517c76..adc5a3313 100644 --- a/include/QF/iqm.h +++ b/include/QF/iqm.h @@ -1,5 +1,5 @@ -#ifndef __QF_iqm_h__ -#define __QF_iqm_h__ +#ifndef __QF_iqm_h +#define __QF_iqm_h #include "QF/qtypes.h" @@ -149,4 +149,4 @@ typedef struct { void *extra_data; } iqm_t; -#endif//__QF_iqm_h__ +#endif//__QF_iqm_h diff --git a/include/QF/joystick.h b/include/QF/joystick.h index 1eeba5d49..4b8163f7e 100644 --- a/include/QF/joystick.h +++ b/include/QF/joystick.h @@ -25,8 +25,8 @@ */ -#ifndef __QF_joystick_h_ -#define __QF_joystick_h_ +#ifndef __QF_joystick_h +#define __QF_joystick_h #include #include "QF/quakeio.h" @@ -154,4 +154,4 @@ int JOY_GetAxis_i (int dest, const char *c); void Joy_WriteBindings (QFile *f); -#endif // __QF_joystick_h_ +#endif//__QF_joystick_h diff --git a/include/QF/keys.h b/include/QF/keys.h index 66ef8d99e..7c9c959fd 100644 --- a/include/QF/keys.h +++ b/include/QF/keys.h @@ -26,8 +26,8 @@ */ -#ifndef _KEYS_H -#define _KEYS_H +#ifndef __QF_keys_h +#define __QF_keys_h #ifndef __QFCC__ # include "QF/qtypes.h" @@ -661,4 +661,4 @@ void Key_Progs_Init (struct progs_s *pr); ///@} -#endif // _KEYS_H +#endif//__QF_keys_h diff --git a/include/QF/link.h b/include/QF/link.h index de29bb454..5b6fdcf8c 100644 --- a/include/QF/link.h +++ b/include/QF/link.h @@ -25,8 +25,8 @@ */ -#ifndef _LINK_H -#define _LINK_H +#ifndef __QF_link_h +#define __QF_link_h // (type *)STRUCT_FROM_LINK(link_t *link, type, member) // ent = STRUCT_FROM_LINK(link,entity_t,order) @@ -43,4 +43,4 @@ void RemoveLink (link_t *l); void InsertLinkBefore (link_t *l, link_t *before); void InsertLinkAfter (link_t *l, link_t *after); -#endif // _LINK_H +#endif//__QF_link_h diff --git a/include/QF/llist.h b/include/QF/llist.h index b9a3a0140..e555c6bd6 100644 --- a/include/QF/llist.h +++ b/include/QF/llist.h @@ -25,8 +25,8 @@ */ -#ifndef _LLIST_H -#define _LLIST_H +#ifndef __QF_llist_h +#define __QF_llist_h #include "QF/qtypes.h" @@ -112,4 +112,4 @@ void *llist_createarray (llist_t *list, size_t esize); //@} -#endif +#endif//__QF_llist_h diff --git a/include/QF/locs.h b/include/QF/locs.h index 425e8980d..4f7dc9b5c 100644 --- a/include/QF/locs.h +++ b/include/QF/locs.h @@ -25,8 +25,8 @@ */ -#ifndef __locs_h -#define __locs_h +#ifndef __QF_locs_h +#define __QF_locs_h #include "QF/qtypes.h" @@ -47,4 +47,4 @@ void locs_reset (void); void locs_save (const char *filename, qboolean gz); void map_to_loc (const char *mapname, char *filename); -#endif // __locs_h +#endif//__QF_locs_h diff --git a/include/QF/mathlib.h b/include/QF/mathlib.h index 5c9b854fe..851b841eb 100644 --- a/include/QF/mathlib.h +++ b/include/QF/mathlib.h @@ -25,8 +25,8 @@ */ -#ifndef __mathlib_h -#define __mathlib_h +#ifndef __QF_mathlib_h +#define __QF_mathlib_h /** \defgroup mathlib Vector and matrix functions \ingroup utils @@ -220,4 +220,4 @@ void BarycentricCoords (const vec_t **points, int num_points, const vec3_t p, ///@} -#endif // __mathlib_h +#endif//__QF_mathlib_h diff --git a/include/QF/mdfour.h b/include/QF/mdfour.h index 19360e838..bff20aefb 100644 --- a/include/QF/mdfour.h +++ b/include/QF/mdfour.h @@ -26,8 +26,8 @@ */ -#ifndef __mdfour_h -#define __mdfour_h +#ifndef __QF_mdfour_h +#define __QF_mdfour_h /** \addtogroup crc */ @@ -49,4 +49,4 @@ void mdfour(unsigned char *out, const unsigned char *in, int n); ///@} -#endif // __mdfour_h +#endif//__QF_mdfour_h diff --git a/include/QF/model.h b/include/QF/model.h index 6b3fbc3b5..d4b243241 100644 --- a/include/QF/model.h +++ b/include/QF/model.h @@ -25,8 +25,8 @@ */ -#ifndef _MODEL_H -#define _MODEL_H +#ifndef __QF_model_h +#define __QF_model_h #include "QF/qtypes.h" #include "QF/bspfile.h" @@ -468,4 +468,4 @@ extern byte *mod_base; extern byte mod_novis[MAX_MAP_LEAFS / 8]; extern int mod_lightmap_bytes; -#endif // _MODEL_H +#endif//__QF_model_h diff --git a/include/QF/modelgen.h b/include/QF/modelgen.h index 447a8c864..66cdd1308 100644 --- a/include/QF/modelgen.h +++ b/include/QF/modelgen.h @@ -31,8 +31,8 @@ // * pass data from one to the other via model files. * // ********************************************************* -#ifndef _MODELGEN_H -#define _MODELGEN_H +#ifndef __QF_modelgen_h +#define __QF_modelgen_h #include "QF/mathlib.h" @@ -142,4 +142,4 @@ typedef struct { // little-endian "IDP2" #define IDHEADER_MD2 (('2'<<24)+('P'<<16)+('D'<<8)+'I') -#endif // _MODELGEN_H +#endif//__QF_modelgen_h diff --git a/include/QF/msg.h b/include/QF/msg.h index 6a92e2d54..4f696f896 100644 --- a/include/QF/msg.h +++ b/include/QF/msg.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef _MSG_H -#define _MSG_H +#ifndef __QF_msg_h +#define __QF_msg_h /** \defgroup msg Message reading and writing \ingroup utils @@ -251,4 +251,4 @@ int MSG_ReadUTF8 (qmsg_t *msg); ///@} -#endif +#endif//__QF_msg_h diff --git a/include/QF/object.h b/include/QF/object.h index 39f06210b..f5c4f97f8 100644 --- a/include/QF/object.h +++ b/include/QF/object.h @@ -32,8 +32,8 @@ */ -#ifndef __object_h -#define __object_h +#ifndef __QF_object_h +#define __QF_object_h #include "QF/qtypes.h" @@ -115,4 +115,4 @@ void Object_Garbage_Collect (void); #include "QF/classes/String.h" -#endif +#endif//__QF_object_h diff --git a/include/QF/pak.h b/include/QF/pak.h index ea86ffd14..e331fca6e 100644 --- a/include/QF/pak.h +++ b/include/QF/pak.h @@ -28,8 +28,8 @@ */ -#ifndef __qf_pak_h -#define __qf_pak_h +#ifndef __QF_pak_h +#define __QF_pak_h /** \addtogroup pak */ @@ -53,4 +53,4 @@ typedef struct { ///@} -#endif//__qf_pak_h +#endif//__QF_pak_h diff --git a/include/QF/pcx.h b/include/QF/pcx.h index 6bfeb03e5..8536b9f69 100644 --- a/include/QF/pcx.h +++ b/include/QF/pcx.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __pcx_h -#define __pcx_h +#ifndef __QF_pcx_h +#define __QF_pcx_h #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -77,4 +77,4 @@ pcx_t *EncodePCX (byte *data, int width, int height, int rowbytes, */ struct tex_s *LoadPCX (QFile *f, qboolean convert, byte *pal); -#endif // __pcx_h +#endif//__QF_pcx_h diff --git a/include/QF/plugin.h b/include/QF/plugin.h index 0a06f73f2..f1ff974a3 100644 --- a/include/QF/plugin.h +++ b/include/QF/plugin.h @@ -25,8 +25,8 @@ */ -#ifndef __QF_plugin_h_ -#define __QF_plugin_h_ +#ifndef __QF_plugin_h +#define __QF_plugin_h /** \defgroup plugin Plugins \ingroup utils @@ -113,4 +113,4 @@ void PI_Shutdown (void); ///@} -#endif // __QF_plugin_h_ +#endif//__QF_plugin_h diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 451d3a9ab..8c03a7981 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -18,8 +18,8 @@ */ // this file is shared by QuakeForge and qfcc -#ifndef __pr_comp_h -#define __pr_comp_h +#ifndef __QF_pr_comp_h +#define __QF_pr_comp_h #include "QF/qtypes.h" @@ -513,4 +513,4 @@ typedef struct dprograms_s { pr_uint_t entityfields; } dprograms_t; -#endif // __pr_comp_h +#endif//__QF_pr_comp_h diff --git a/include/QF/pr_debug.h b/include/QF/pr_debug.h index d80b9f417..be5e1471d 100644 --- a/include/QF/pr_debug.h +++ b/include/QF/pr_debug.h @@ -28,8 +28,8 @@ */ -#ifndef __pr_debug_h -#define __pr_debug_h +#ifndef __QF_pr_debug_h +#define __QF_pr_debug_h #include "QF/pr_comp.h" @@ -65,4 +65,4 @@ typedef struct pr_debug_header_s { pr_uint_t num_locals; } pr_debug_header_t; -#endif//__pr_debug_h +#endif//__QF_pr_debug_h diff --git a/include/QF/pr_obj.h b/include/QF/pr_obj.h index 5e4f8463c..fa3bbca84 100644 --- a/include/QF/pr_obj.h +++ b/include/QF/pr_obj.h @@ -28,8 +28,8 @@ */ -#ifndef __pr_obj_h -#define __pr_obj_h +#ifndef __QF_pr_obj_h +#define __QF_pr_obj_h #include "QF/pr_comp.h" @@ -185,4 +185,4 @@ typedef struct pr_super_s { pointer_t class; } pr_super_t; -#endif//__pr_obj_h +#endif//__QF_pr_obj_h diff --git a/include/QF/pr_type.h b/include/QF/pr_type.h index 39215840f..179a4e407 100644 --- a/include/QF/pr_type.h +++ b/include/QF/pr_type.h @@ -28,8 +28,8 @@ */ -#ifndef __pr_type_h -#define __pr_type_h +#ifndef __QF_pr_type_h +#define __QF_pr_type_h /** \defgroup qfcc_qfo_type Object file type encoding \ingroup progs @@ -121,4 +121,4 @@ typedef struct qfot_type_encodings_s { ///@} -#endif//__pr_type_h +#endif//__QF_pr_type_h diff --git a/include/QF/qargs.h b/include/QF/qargs.h index 50dfbd35a..bf49495a4 100644 --- a/include/QF/qargs.h +++ b/include/QF/qargs.h @@ -27,8 +27,8 @@ */ -#ifndef __qargs_h -#define __qargs_h +#ifndef __QF_qargs_h +#define __QF_qargs_h /** \addtogroup misc */ @@ -52,4 +52,4 @@ void COM_ParseConfig (void); ///@} -#endif // __qargs_h +#endif//__QF_qargs_h diff --git a/include/QF/qdefs.h b/include/QF/qdefs.h index 1d00abee0..a0dbbfe5c 100644 --- a/include/QF/qdefs.h +++ b/include/QF/qdefs.h @@ -27,8 +27,8 @@ */ -#ifndef __qdefs_h -#define __qdefs_h +#ifndef __QF_qdefs_h +#define __QF_qdefs_h #define MAX_QPATH 64 #define MAX_CL_STATS 32 @@ -40,4 +40,4 @@ #define clc_stringcmd 4 -#endif // __qdefs_h +#endif//__QF_qdefs_h diff --git a/include/QF/qendian.h b/include/QF/qendian.h index a42bd749f..7c418be53 100644 --- a/include/QF/qendian.h +++ b/include/QF/qendian.h @@ -27,8 +27,8 @@ */ -#ifndef __qendian_h -#define __qendian_h +#ifndef __QF_qendian_h +#define __QF_qendian_h /** \defgroup qendian Endian handling functions \ingroup utils @@ -120,4 +120,4 @@ unsigned int ReadLong (struct QFile_s *file); ///@} -#endif // __qendian_h +#endif//__QF_qendian_h diff --git a/include/QF/qfplist.h b/include/QF/qfplist.h index e0c2557ca..7a12b7c4c 100644 --- a/include/QF/qfplist.h +++ b/include/QF/qfplist.h @@ -25,8 +25,8 @@ */ -#ifndef __QF_qfplist_h_ -#define __QF_qfplist_h_ +#ifndef __QF_qfplist_h +#define __QF_qfplist_h /** \defgroup qfplist Property lists \ingroup utils @@ -228,4 +228,4 @@ void PL_Free (plitem_t *item); ///@} -#endif // __QF_qfplist_h_ +#endif//__QF_qfplist_h diff --git a/include/QF/qtypes.h b/include/QF/qtypes.h index e328ff2fc..ea3a4df6c 100644 --- a/include/QF/qtypes.h +++ b/include/QF/qtypes.h @@ -27,8 +27,8 @@ */ -#ifndef __qtypes_h -#define __qtypes_h +#ifndef __QF_qtypes_h +#define __QF_qtypes_h #include #include @@ -115,4 +115,4 @@ typedef struct sphere_s { vec_t radius; } sphere_t; -#endif // __qtypes_h +#endif//__QF_qtypes_h diff --git a/include/QF/quakefs.h b/include/QF/quakefs.h index 364718db0..761997eea 100644 --- a/include/QF/quakefs.h +++ b/include/QF/quakefs.h @@ -27,8 +27,8 @@ */ -#ifndef __quakefs_h -#define __quakefs_h +#ifndef __QF_quakefs_h +#define __QF_quakefs_h /** \defgroup quakefs Quake Filesystem \ingroup utils @@ -420,4 +420,4 @@ void QFS_FilelistFree (filelist_t *list); ///@} -#endif // __quakefs_h +#endif//__QF_quakefs_h diff --git a/include/QF/quakeio.h b/include/QF/quakeio.h index 08b14af69..1fd7205a0 100644 --- a/include/QF/quakeio.h +++ b/include/QF/quakeio.h @@ -26,8 +26,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __quakeio_h -#define __quakeio_h +#ifndef __QF_quakeio_h +#define __QF_quakeio_h #include @@ -62,4 +62,4 @@ const char *Qgetline(QFile *file); ///@} -#endif /*__quakeio_h*/ +#endif//__QF_quakeio_h diff --git a/include/QF/render.h b/include/QF/render.h index cc08c3800..86892e4ec 100644 --- a/include/QF/render.h +++ b/include/QF/render.h @@ -25,8 +25,8 @@ */ -#ifndef __render_h -#define __render_h +#ifndef __QF_render_h +#define __QF_render_h #include "QF/mathlib.h" #include "QF/model.h" @@ -177,4 +177,4 @@ void R_LoadModule (void (*load_gl)(void), struct progs_s; void R_Progs_Init (struct progs_s *pr); -#endif // __render_h +#endif//__QF_render_h diff --git a/include/QF/screen.h b/include/QF/screen.h index 9586e20a1..8dda2deb4 100644 --- a/include/QF/screen.h +++ b/include/QF/screen.h @@ -26,8 +26,8 @@ */ // screen.h -#ifndef __screen_h -#define __screen_h +#ifndef __QF_screen_h +#define __QF_screen_h #include "QF/qtypes.h" @@ -67,4 +67,4 @@ extern struct qpic_s *scr_turtle; extern struct cvar_s *hud_fps, *hud_time; -#endif // __screen_h +#endif//__QF_screen_h diff --git a/include/QF/sizebuf.h b/include/QF/sizebuf.h index 7f6fc4ac3..08436b1b8 100644 --- a/include/QF/sizebuf.h +++ b/include/QF/sizebuf.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __sizebuf_h -#define __sizebuf_h +#ifndef __QF_sizebuf_h +#define __QF_sizebuf_h /** \defgroup sizebuf Fixed Size Buffers \ingroup utils @@ -53,4 +53,4 @@ void SZ_Print (sizebuf_t *buf, const char *data); // strcats onto the sizebuf ///@} -#endif // __sizebuf_h +#endif//__QF_sizebuf_h diff --git a/include/QF/skin.h b/include/QF/skin.h index b9c8a3dcb..7f520e1d6 100644 --- a/include/QF/skin.h +++ b/include/QF/skin.h @@ -25,8 +25,8 @@ */ -#ifndef _SKIN_H -#define _SKIN_H +#ifndef __QF_skin_h +#define __QF_skin_h #include "QF/qtypes.h" #include "QF/vid.h" @@ -57,4 +57,4 @@ typedef struct skin_s { int auxtex; } skin_t; -#endif +#endif//__QF_skin_h diff --git a/include/QF/sound.h b/include/QF/sound.h index 3382d4b91..9fba9b158 100644 --- a/include/QF/sound.h +++ b/include/QF/sound.h @@ -26,8 +26,8 @@ */ // sound.h -- client sound i/o functions -#ifndef _SOUND_H -#define _SOUND_H +#ifndef __QF_sound_h +#define __QF_sound_h /** \defgroup sound QuakeForge sound engine */ @@ -195,4 +195,4 @@ void S_Progs_Init (struct progs_s *pr); ///@} -#endif // _SOUND_H +#endif//__QF_sound_h diff --git a/include/QF/spritegn.h b/include/QF/spritegn.h index 4505ad59f..de490f28d 100644 --- a/include/QF/spritegn.h +++ b/include/QF/spritegn.h @@ -45,8 +45,8 @@ // //------------------------------------------------------- -#ifndef _SPRITEGN_H -#define _SPRITEGN_H +#ifndef __QF_sprintgn_h +#define __QF_sprintgn_h #define SPR_VERSION 1 #define SP2_VERSION 2 @@ -102,4 +102,4 @@ typedef struct { // little-endian "IDS2" #define IDHEADER_SP2 (('2'<<24)+('S'<<16)+('D'<<8)+'I') -#endif // _SPRITEGN_H +#endif//__QF_sprintgn_h diff --git a/include/QF/sys.h b/include/QF/sys.h index 76b6ad844..06e2590fa 100644 --- a/include/QF/sys.h +++ b/include/QF/sys.h @@ -25,8 +25,8 @@ */ -#ifndef __sys_h -#define __sys_h +#ifndef __QF_sys_h +#define __QF_sys_h /** \defgroup sys System Portability \ingroup utils @@ -159,4 +159,4 @@ char *Sys_ExpandSquiggle (const char *path); ///@} -#endif // __sys_h +#endif//__QF_sys_h diff --git a/include/QF/teamplay.h b/include/QF/teamplay.h index bf4ae9445..91b2a6f65 100644 --- a/include/QF/teamplay.h +++ b/include/QF/teamplay.h @@ -25,8 +25,8 @@ */ -#ifndef __teamplay_h -#define __teamplay_h +#ifndef __QF_teamplay_h +#define __QF_teamplay_h extern struct cvar_s *cl_parsesay; extern struct cvar_s *cl_nofake; @@ -47,4 +47,4 @@ const char *Team_ParseSay (struct dstring_s *buf, const char *); void Locs_Init (void); void Team_ParseChat (const char *string); void Team_ResetTimers (void); -#endif // __teamplay_h +#endif//__QF_teamplay_h diff --git a/include/QF/tga.h b/include/QF/tga.h index 1d0bc8c25..365f5d366 100644 --- a/include/QF/tga.h +++ b/include/QF/tga.h @@ -25,8 +25,8 @@ */ -#ifndef __tga_h -#define __tga_h +#ifndef __QF_tga_h +#define __QF_tga_h #include "QF/qtypes.h" #include "QF/quakeio.h" @@ -70,4 +70,4 @@ typedef struct _TargaHeader { struct tex_s *LoadTGA (QFile *fin); void WriteTGAfile (const char *tganame, byte *data, int width, int height); -#endif // __tga_h +#endif//__QF_tga_h diff --git a/include/QF/uint32.h b/include/QF/uint32.h deleted file mode 100644 index 513117d01..000000000 --- a/include/QF/uint32.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - uint32.h - - Definitions for portable (?) unsigned int - - Copyright (C) 2000 Jeff Teunissen - - Author: Jeff Teunissen - Date: 01 Jan 2000 - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ - -#ifndef __uint32_h -#define __uint32_h - -#ifndef int32 -# if (SIZEOF_INT == 4) -# define int32 int -# elif (SIZEOF_LONG == 4) -# define int32 long -# elif (SIZEOF_SHORT == 4) -# define int32 short -# else -/* I hope this works */ -# define int32 int -# define LARGE_INT32 -# endif -#endif - -#ifndef uint32 -# define uint32 unsigned int32 -#endif - -#endif // __uint32_h diff --git a/include/QF/va.h b/include/QF/va.h index 40c794712..1bf0eadaf 100644 --- a/include/QF/va.h +++ b/include/QF/va.h @@ -26,8 +26,8 @@ */ -#ifndef __va_h -#define __va_h +#ifndef __QF_va_h +#define __QF_va_h /** \addtogroup misc Formatted printing. @@ -41,4 +41,4 @@ char *nva(const char *format, ...) __attribute__((format(printf,1,2))); ///@} -#endif // __va_h +#endif//__QF_va_h diff --git a/include/QF/ver_check.h b/include/QF/ver_check.h index 8ac943796..eaa4d9391 100644 --- a/include/QF/ver_check.h +++ b/include/QF/ver_check.h @@ -25,8 +25,8 @@ */ -#ifndef __ver_check_h_ -#define __ver_check_h_ +#ifndef __QF_ver_check_h +#define __QF_ver_check_h /** \defgroup utils Utils */ @@ -47,4 +47,4 @@ int ver_compare (const char *, const char *); ///@} -#endif // __ver_check_h_ +#endif//__QF_ver_check_h diff --git a/include/QF/vid.h b/include/QF/vid.h index 70298fa8b..312da65dd 100644 --- a/include/QF/vid.h +++ b/include/QF/vid.h @@ -25,8 +25,8 @@ */ -#ifndef __vid_h_ -#define __vid_h_ +#ifndef __QF_vid_h +#define __QF_vid_h #include "QF/qtypes.h" #include "QF/vrect.h" @@ -89,4 +89,4 @@ void VID_Init (byte *palette, byte *colormap); void VID_Shutdown (void); void VID_SetCaption (const char *text); -#endif // __vid_h_ +#endif//__QF_vid_h diff --git a/include/QF/view.h b/include/QF/view.h index 570935ae8..5a6ae339f 100644 --- a/include/QF/view.h +++ b/include/QF/view.h @@ -28,8 +28,8 @@ */ -#ifndef __qf_view_h -#define __qf_view_h +#ifndef __QF_view_h +#define __QF_view_h /** \defgroup console_view Console View Objects \ingroup console @@ -217,4 +217,4 @@ void view_move (view_t *view, int xp, int yp); ///@} -#endif//__qf_view_h +#endif//__QF_view_h diff --git a/include/QF/wad.h b/include/QF/wad.h index 82e836dc9..2e6bb9c67 100644 --- a/include/QF/wad.h +++ b/include/QF/wad.h @@ -26,8 +26,8 @@ */ // wad.h -#ifndef _WAD_H -#define _WAD_H +#ifndef __QF_wad_h +#define __QF_wad_h /** \addtogroup wad Wad Files @@ -48,4 +48,4 @@ void SwapPic (qpic_t *pic); ///@} -#endif // _WAD_H +#endif//__QF_wad_h diff --git a/include/QF/zone.h b/include/QF/zone.h index 1f968737f..10063b2cc 100644 --- a/include/QF/zone.h +++ b/include/QF/zone.h @@ -24,8 +24,8 @@ Boston, MA 02111-1307, USA */ -#ifndef __zone_h -#define __zone_h +#ifndef __QF_zone_h +#define __QF_zone_h /** \defgroup zone Memory Management \ingroup utils @@ -142,4 +142,4 @@ int Cache_ReadLock (cache_user_t *c) __attribute__((pure)); ///@} -#endif // __zone_h +#endif//__QF_zone_h From f7493fe8fb65a8a356c157185c647f131cf48730 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 17:30:33 +0900 Subject: [PATCH 071/444] Add a buffer-gap text buffer This should be good for text editing and working with text files in general. --- include/QF/txtbuffer.h | 98 +++++++++++++ libs/util/Makefile.am | 3 +- libs/util/test/Makefile.am | 6 +- libs/util/test/test-txtbuffer.c | 240 ++++++++++++++++++++++++++++++++ libs/util/txtbuffer.c | 172 +++++++++++++++++++++++ 5 files changed, 517 insertions(+), 2 deletions(-) create mode 100644 include/QF/txtbuffer.h create mode 100644 libs/util/test/test-txtbuffer.c create mode 100644 libs/util/txtbuffer.c diff --git a/include/QF/txtbuffer.h b/include/QF/txtbuffer.h new file mode 100644 index 000000000..e73c7257a --- /dev/null +++ b/include/QF/txtbuffer.h @@ -0,0 +1,98 @@ +/* + txtbuffer.h + + Text buffer for edit or scrollback + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_txtbuffer_h +#define __QF_txtbuffer_h + +#include +#include + +/** \defgroup txtbuffer Text buffers + \ingroup utils +*/ +///@{ + +/// must be a power of 2 +#define TXTBUFFER_GROW 0x4000 + +/** Text buffer implementing efficient editing. +*/ +typedef struct txtbuffer_s { + struct txtbuffer_s *next; + char *text; + size_t textSize; ///< amount of text in the buffer + size_t bufferSize; ///< current capacity of the buffer + size_t gapOffset; ///< beginning of the gap + size_t gapSize; ///< size of gap. gapSize + textSize == bufferSize +} txtbuffer_t; + +/** Create a new, empty buffer. +*/ +txtbuffer_t *TextBuffer_Create (void); + +/** Destroy a buffer, freeing all resources connected to it. + \param buffer The buffer to destroy. +*/ +void TextBuffer_Destroy (txtbuffer_t *buffer); + +/** Insert a block of text at the specified offset. + + Text after the offset is moved to be after the inserted block of text. + The buffer is resized as necessary. + nul characters are not significant in that they do not mark the end of + the text to be inserted. + + \param buffer The buffer to be updated + \param offset The offset in the buffer at which to insert the text block + \param text The text block to be inserted. May contain nul ('\0') + characters. + \param text_len The number of characters to insert. + \return 1 for success, 0 for failure (offset not valid or out + of memory) +*/ +int TextBuffer_InsertAt (txtbuffer_t *buffer, size_t offset, + const char *text, size_t text_len); + +/** Delete a block of text from the buffer. + + The buffer is not resized. Rather, its capacity before resizing is require + is increased. + + \param buffer The buffer to be updated + \param offset The offset of the beginning of the text block to be deleted + \param len The amount of characters to be deleted. Values larger than + the amount of text in the buffer beyond the beginning of + block are truncated to the amount of remaining text. Thus + using excessivly large values sets the offset to be the + end of the buffer. + \return 1 for success, 0 for failure (offset not valid) +*/ +int TextBuffer_DeleteAt (txtbuffer_t *buffer, size_t offset, size_t len); + +///@} + +#endif//__QF_txtbuffer_h diff --git a/libs/util/Makefile.am b/libs/util/Makefile.am index 0c6421450..c35e4e305 100644 --- a/libs/util/Makefile.am +++ b/libs/util/Makefile.am @@ -53,7 +53,8 @@ libQFutil_la_SOURCES= \ fendian.c hash.c idparse.c info.c link.c llist.c \ mathlib.c mdfour.c mersenne.c msg.c pakfile.c plugin.c qargs.c qendian.c \ qfplist.c quakefs.c quakeio.c riff.c script.c segtext.c set.c sizebuf.c \ - string.c sys.c va.c ver_check.c vrect.c wad.c wadfile.c zone.c \ + string.c sys.c txtbuffer.c va.c ver_check.c vrect.c wad.c wadfile.c \ + zone.c \ $(dirent) $(fnmatch) $(getopt) EXTRA_DIST= $(fnmatch_src) $(getopt_src) diff --git a/libs/util/test/Makefile.am b/libs/util/test/Makefile.am index a7bdb5d4e..283ac561e 100644 --- a/libs/util/test/Makefile.am +++ b/libs/util/test/Makefile.am @@ -4,7 +4,7 @@ AM_CPPFLAGS= -I$(top_srcdir)/include check_PROGRAMS= \ test-bary test-cs test-dq test-half test-mat3 test-mat4 test-plist \ - test-qfs test-quat test-seb test-seg test-set test-vrect + test-qfs test-quat test-seb test-seg test-set test-txtbuffer test-vrect test_bary_SOURCES=test-bary.c test_bary_LDADD=$(top_builddir)/libs/util/libQFutil.la @@ -54,6 +54,10 @@ test_set_SOURCES=test-set.c test_set_LDADD=$(top_builddir)/libs/util/libQFutil.la test_set_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la +test_txtbuffer_SOURCES=test-txtbuffer.c +test_txtbuffer_LDADD=$(top_builddir)/libs/util/libQFutil.la +test_txtbuffer_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la + test_vrect_SOURCES=test-vrect.c test_vrect_LDADD=$(top_builddir)/libs/util/libQFutil.la test_vrect_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la diff --git a/libs/util/test/test-txtbuffer.c b/libs/util/test/test-txtbuffer.c new file mode 100644 index 000000000..44ccebdc9 --- /dev/null +++ b/libs/util/test/test-txtbuffer.c @@ -0,0 +1,240 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include + +#include "QF/txtbuffer.h" + +static size_t +check_text_ptr (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->text != 0; +} + +static size_t +get_textSize (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->textSize; +} + +static size_t +get_bufferSize (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->bufferSize; +} + +static size_t +get_gapOffset (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->gapOffset; +} + +static size_t +get_gapSize (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + return buffer->gapSize; +} + +static size_t +insert_text (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + if (TextBuffer_InsertAt (buffer, offset, txt, length)) { + memset (buffer->text + buffer->gapOffset, 0xff, buffer->gapSize); + return 1; + } + return 0; +} + +static size_t +delete_text (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + if (TextBuffer_DeleteAt (buffer, offset, length)) { + memset (buffer->text + buffer->gapOffset, 0xff, buffer->gapSize); + return 1; + } + return 0; +} + +static size_t +destroy_buffer (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + TextBuffer_Destroy (buffer); + return 0; +} + +typedef size_t (*test_func) (txtbuffer_t *buffer, size_t offset, + const char *text, size_t length); + +static const char test_text[] = { + "Guarding the entrance to the Grendal\n" + "Gorge is the Shadow Gate, a small keep\n" + "and monastary which was once the home\n" + "of the Shadow cult.\n\n" + "For years the Shadow Gate existed in\n" + "obscurity but after the cult discovered\n" + "the \3023\354\341\343\353\240\307\341\364\345 in the caves below\n" + "the empire took notice.\n" + "A batallion of Imperial Knights were\n" + "sent to the gate to destroy the cult\n" + "and claim the artifact for the King.", +}; +static const char empty[TXTBUFFER_GROW] = { }; + +static size_t +compare_text (txtbuffer_t *buffer, size_t offset, const char *txt, + size_t length) +{ + //printf("%zd %ld %zd\n", offset, txt - test_text, length); + size_t res = memcmp (buffer->text + offset, txt, length) == 0; + if (!res) { + for (size_t i = 0; i < length; i++) { + //printf ("%02x %02x\n", txt[i] & 0xff, buffer->text[offset + i] & 0xff); + } + } + return res; +} + +#define txtsize (sizeof (test_text) - 1) +#define txtsize0 txtsize +#define bufsize0 (TXTBUFFER_GROW) +#define gapoffs0 txtsize0 +#define gapsize0 (bufsize0 - txtsize0) +#define subtxtlen 200 +#define suboffs 200 +#define txtsize1 (txtsize0 + subtxtlen) +#define bufsize1 (TXTBUFFER_GROW) +#define gapoffs1 (suboffs + subtxtlen) +#define gapsize1 (bufsize1 - txtsize1) +#define deltxtlen 350 +#define deloffs 150 +#define txtsize2 (txtsize + subtxtlen - deltxtlen) +#define bufsize2 (TXTBUFFER_GROW) +#define gapoffs2 (deloffs) +#define gapsize2 (bufsize2 - txtsize2) +#define deltxtrem (txtsize2 - gapoffs2) +#define emptyoffs 370 +#define txtsize3 (txtsize + sizeof (empty)) +#define bufsize3 (2 * TXTBUFFER_GROW) +#define gapoffs3 (emptyoffs + sizeof (empty)) +#define gapsize3 (bufsize3 - txtsize3) +#define txtsize4 (txtsize + 2 * sizeof (empty)) +#define bufsize4 (3 * TXTBUFFER_GROW) +#define gapoffs4 (emptyoffs + sizeof (empty)) +#define gapsize4 (bufsize4 - txtsize4) + +struct { + test_func test; + size_t offset_param; + const char *text_param; + size_t length_param; + int test_expect; +} tests[] = { + { check_text_ptr, 0, 0, 0, 0 }, + { get_textSize, 0, 0, 0, 0 }, + { get_bufferSize, 0, 0, 0, 0 }, + { get_gapOffset, 0, 0, 0, 0 }, + { get_gapSize, 0, 0, 0, 0 }, + { insert_text, 0, test_text, txtsize, 1 }, + { get_textSize, 0, 0, 0, txtsize0 }, + { get_bufferSize, 0, 0, 0, bufsize0 }, + { get_gapOffset, 0, 0, 0, gapoffs0 }, + { get_gapSize, 0, 0, 0, gapsize0 }, + { compare_text, 0, test_text, txtsize, 1 }, + { insert_text, suboffs, test_text, subtxtlen, 1 }, + { get_textSize, 0, 0, 0, txtsize1 }, + { get_bufferSize, 0, 0, 0, bufsize1 }, + { get_gapOffset, 0, 0, 0, gapoffs1 }, + { get_gapSize, 0, 0, 0, gapsize1 }, + { compare_text, 0, test_text, txtsize, 0 }, + { compare_text, 0, test_text, suboffs, 1 }, + { compare_text, suboffs, test_text, subtxtlen, 1 }, + { compare_text, gapoffs1 + gapsize1, test_text + subtxtlen, txtsize - subtxtlen, 1 }, + { delete_text, deloffs, 0, deltxtlen, 1 }, + { get_textSize, 0, 0, 0, txtsize2 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, gapoffs2 }, + { get_gapSize, 0, 0, 0, gapsize2 }, + { compare_text, 0, test_text, suboffs, 0 }, + { compare_text, suboffs, test_text, subtxtlen, 0 }, + { compare_text, gapoffs1 + gapsize1, test_text + subtxtlen, txtsize - subtxtlen, 0 }, + { compare_text, 0, test_text, deloffs, 1 }, + { compare_text, gapoffs2 + gapsize2, test_text + txtsize - deltxtrem, deltxtrem, 1 }, + { compare_text, gapoffs2 + gapsize2 - 1, test_text + txtsize - deltxtrem - 1, 1, 0 }, + { delete_text, 0, 0, -1, 1 }, + { check_text_ptr, 0, 0, 0, 1 }, + { get_textSize, 0, 0, 0, 0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, 0 }, + { get_gapSize, 0, 0, 0, bufsize2 }, + { insert_text, 1, test_text, txtsize, 0 }, + { get_textSize, 0, 0, 0, 0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, 0 }, + { get_gapSize, 0, 0, 0, bufsize2 }, + { insert_text, 0, test_text, txtsize, 1 }, + { insert_text, 300, 0, 0, 1 }, + { get_textSize, 0, 0, 0, txtsize0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, 300 }, + { get_gapSize, 0, 0, 0, gapsize0 }, + { compare_text, 0, test_text, 300, 1 }, + { compare_text, 300, test_text + 300, 1, 0 }, + { compare_text, 300 + gapsize0, test_text + 300, txtsize - 300, 1 }, + { compare_text, 300 + gapsize0 - 1, test_text + 300 - 1, 1, 0 }, + { insert_text, 350, 0, 0, 1 }, + { compare_text, (emptyoffs - 20) + gapsize0, test_text + (emptyoffs - 20), txtsize - (emptyoffs - 20), 1 }, + { get_textSize, 0, 0, 0, txtsize0 }, + { get_bufferSize, 0, 0, 0, bufsize2 }, + { get_gapOffset, 0, 0, 0, (emptyoffs - 20) }, + { get_gapSize, 0, 0, 0, gapsize0 }, + { insert_text, emptyoffs, empty, sizeof (empty), 1 }, + { get_textSize, 0, 0, 0, txtsize3 }, + { get_bufferSize, 0, 0, 0, bufsize3 }, + { get_gapOffset, 0, 0, 0, gapoffs3 }, + { get_gapSize, 0, 0, 0, gapsize3 }, + { insert_text, emptyoffs, empty, sizeof (empty), 1 }, + { get_textSize, 0, 0, 0, txtsize4 }, + { get_bufferSize, 0, 0, 0, bufsize4 }, + { get_gapOffset, 0, 0, 0, gapoffs4 }, + { get_gapSize, 0, 0, 0, gapsize4 }, + { destroy_buffer, 0, 0, 0, 0 }, +}; +#define num_tests (sizeof (tests) / sizeof (tests[0])) +int test_start_line = __LINE__ - num_tests - 2; + +int +main (int argc, const char **argv) +{ + size_t i; + int res = 0; + + txtbuffer_t *buffer = TextBuffer_Create (); + + for (i = 0; i < num_tests; i++) { + if (tests[i].test) { + int test_res; + test_res = tests[i].test (buffer, + tests[i].offset_param, + tests[i].text_param, + tests[i].length_param); + if (test_res != tests[i].test_expect) { + res |= 1; + printf ("test %d (line %d) failed\n", (int) i, + (int) i + test_start_line); + printf ("expect: %d\n", tests[i].test_expect); + printf ("got : %d\n", test_res); + continue; + } + } + } + return res; +} diff --git a/libs/util/txtbuffer.c b/libs/util/txtbuffer.c new file mode 100644 index 000000000..03ad06500 --- /dev/null +++ b/libs/util/txtbuffer.c @@ -0,0 +1,172 @@ +/* + txtbuffer.c + + Text buffer + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif + +#include "QF/alloc.h" +#include "QF/qtypes.h" +#include "QF/sys.h" +#include "QF/txtbuffer.h" + +#include "compat.h" + +static txtbuffer_t *txtbuffers_freelist; + +static char * +txtbuffer_open_gap (txtbuffer_t *buffer, size_t offset, size_t length) +{ + size_t len; + char *dst; + char *src; + + if (offset == buffer->gapOffset && length <= buffer->gapSize) { + return buffer->text + buffer->gapOffset; + } + if (length <= buffer->gapSize) { + // no resize needed + if (offset < buffer->gapOffset) { + len = buffer->gapOffset - offset; + dst = buffer->text + buffer->gapOffset + buffer->gapSize - len; + src = buffer->text + offset; + } else { + len = offset - buffer->gapOffset; + dst = buffer->text + buffer->gapOffset; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + } + memmove (dst, src, len); + } else { + // need to resize the buffer + // grow the buffer by the difference in lengths rounded up to the + // next multiple of TXTBUFFER_GROW + size_t new_size = buffer->bufferSize + length - buffer->gapSize; + new_size = (new_size + TXTBUFFER_GROW - 1) & ~(TXTBUFFER_GROW - 1); + char *new_text = realloc (buffer->text, new_size); + + if (!new_text) { + return 0; + } + buffer->text = new_text; + + if (offset < buffer->gapOffset) { + // move the old post-gap to the end of the new buffer + len = buffer->bufferSize - (buffer->gapOffset + buffer->gapSize); + dst = buffer->text + new_size - len; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + // move the remaining chunk to after the end of the new gap or + // just before the location of the previous move + len = buffer->gapOffset - offset; + dst -= len; + src = buffer->text + offset; + memmove (dst, src, len); + } else if (offset > buffer->gapOffset) { + // move the old post-offset to the end of the new buffer + len = buffer->bufferSize - (offset + buffer->gapSize); + dst = buffer->text + new_size - len; + src = buffer->text + offset + buffer->gapSize; + memmove (dst, src, len); + // move the old post-gap to offset block to before the new gap + len = offset - buffer->gapOffset; + dst = buffer->text + buffer->gapOffset; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + } else { + // the gap only grew, did not move + len = buffer->bufferSize - (offset + buffer->gapSize); + dst = buffer->text + new_size - len; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + } + buffer->gapSize += new_size - buffer->bufferSize; + buffer->bufferSize = new_size; + } + buffer->gapOffset = offset; + return buffer->text + buffer->gapOffset; +} + +VISIBLE txtbuffer_t * +TextBuffer_Create (void) +{ + txtbuffer_t *buffer; + ALLOC (16, txtbuffer_t, txtbuffers, buffer); + return buffer; +} + +VISIBLE void +TextBuffer_Destroy (txtbuffer_t *buffer) +{ + if (buffer->text) { + free (buffer->text); + } + FREE (txtbuffers, buffer); +} + +VISIBLE int +TextBuffer_InsertAt (txtbuffer_t *buffer, size_t offset, + const char *text, size_t text_len) +{ + char *dst; + + if (offset > buffer->textSize) { + return 0; + } + dst = txtbuffer_open_gap (buffer, offset, text_len); + if (!dst) { + return 0; + } + memcpy (dst, text, text_len); + buffer->textSize += text_len; + buffer->gapOffset += text_len; + buffer->gapSize -= text_len; + return 1; +} + +VISIBLE int +TextBuffer_DeleteAt (txtbuffer_t *buffer, size_t offset, size_t len) +{ + if (offset > buffer->textSize) { + return 0; + } + // only moves, does not resize, the gap if necessary + txtbuffer_open_gap (buffer, offset, buffer->gapSize); + // clamp len to the amount of text beyond offset + if (len > buffer->textSize - offset) { + len = buffer->textSize - offset; + } + // delete the text + buffer->gapSize += len; + buffer->textSize -= len; + return 1; +} From 3720956d8884d0aee329f79ab66237fcbed4192e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 24 Feb 2020 18:52:46 +0900 Subject: [PATCH 072/444] Speed up two of the three deletion cases The initial code was pretty much a port of the code in the editor I wrote 25 years ago. Either I didn't think of the optimization back then, or I tried to implement it, failed, and figured it wasn't worth it (despite using it on a 386dx33). However, I noticed it now and it was easy enough to get working, and it's always good to not do something that's not needed. --- libs/util/txtbuffer.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/libs/util/txtbuffer.c b/libs/util/txtbuffer.c index 03ad06500..59ee0da16 100644 --- a/libs/util/txtbuffer.c +++ b/libs/util/txtbuffer.c @@ -116,6 +116,32 @@ txtbuffer_open_gap (txtbuffer_t *buffer, size_t offset, size_t length) return buffer->text + buffer->gapOffset; } +static char * +txtbuffer_delete_text (txtbuffer_t *buffer, size_t offset, size_t length) +{ + size_t len; + char *dst; + char *src; + + if (offset > buffer->gapOffset) { + len = offset - buffer->gapOffset; + dst = buffer->text + buffer->gapOffset; + src = buffer->text + buffer->gapOffset + buffer->gapSize; + memmove (dst, src, len); + } else if (offset + length < buffer->gapOffset) { + len = buffer->gapOffset - (offset + length); + dst = buffer->text + buffer->gapSize + (offset + length); + src = buffer->text + (offset + length); + memmove (dst, src, len); + } + // don't need to do any copying when offset <= gapOffset && + // offset + length >= offset + buffer->gapOffset = offset; + buffer->gapSize += length; + buffer->textSize -= length; + return buffer->text + buffer->gapOffset; +} + VISIBLE txtbuffer_t * TextBuffer_Create (void) { @@ -159,14 +185,10 @@ TextBuffer_DeleteAt (txtbuffer_t *buffer, size_t offset, size_t len) if (offset > buffer->textSize) { return 0; } - // only moves, does not resize, the gap if necessary - txtbuffer_open_gap (buffer, offset, buffer->gapSize); // clamp len to the amount of text beyond offset if (len > buffer->textSize - offset) { len = buffer->textSize - offset; } - // delete the text - buffer->gapSize += len; - buffer->textSize -= len; + txtbuffer_delete_text (buffer, offset, len); return 1; } From c51c9edd9d1cdf2b374727be0d0b3a06926c50d5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 00:11:01 +0900 Subject: [PATCH 073/444] Fix incorrect encoding of local defs --- tools/qfcc/source/obj_file.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 855e48b61..d1c5296c4 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -1178,7 +1178,6 @@ qfo_to_sym (qfo_t *qfo, int *size) aux->local_defs = ld - locals; for (j = 0; j < num_locals; j++, def++, ld++) { ld->type = get_def_type (qfo, def->type); - ld->type = def->type; ld->ofs = def->offset; ld->name = def->name; ld->type_encoding = def->type; From 1cfac0f11a785ff1d1556b2110845f161301a042 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 00:12:02 +0900 Subject: [PATCH 074/444] Resolve local def type encodings They need to be resolved at load-time. --- tools/qfcc/source/dump_globals.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index ea94f5d9d..ea52bd8f6 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -234,6 +234,13 @@ dump_functions (progs_t *pr) const char *name; int start, count; const char *comment; + pr_def_t *encodings_def; + pointer_t type_encodings = 0; + + encodings_def = PR_FindGlobal (pr, ".type_encodings"); + if (encodings_def) { + type_encodings = encodings_def->ofs; + } for (i = 0; i < pr->progs->numfunctions; i++) { dfunction_t *func = &pr->pr_functions[i]; @@ -256,7 +263,7 @@ dump_functions (progs_t *pr) func->parm_size[j].size); printf (") %d @ %x", func->locals, func->parm_start); puts (""); - if (pr->debug) { + if (pr->debug && type_encodings) { pr_auxfunction_t *aux = pr->auxfunction_map[i]; if (!aux) continue; @@ -265,8 +272,11 @@ dump_functions (progs_t *pr) aux->line_info, aux->local_defs, aux->num_locals, aux->return_type); - for (j = 0; j < (int)aux->num_locals; j++) + for (j = 0; j < (int)aux->num_locals; j++) { + pr->local_defs[+ aux->local_defs + j].type_encoding + += type_encodings; dump_def (pr, pr->local_defs + aux->local_defs + j, 1); + } } } } From 256dee98a17d9264dceec38c730d41ad53474c64 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 00:21:56 +0900 Subject: [PATCH 075/444] Make progs string resources management private Strangely enough, using the progs resources system. This is a step towards having progs that can be reset properly, or even dynamically created VMs. --- include/QF/progs.h | 25 +--- libs/gamecode/pr_load.c | 3 +- libs/gamecode/pr_strings.c | 231 +++++++++++++++++++++--------------- tools/qfcc/source/qfprogs.c | 1 - 4 files changed, 141 insertions(+), 119 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index d007ac81f..25f81f2b5 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1146,12 +1146,12 @@ int PR_RelocateBuiltins (progs_t *pr); */ ///@{ -/** Initialize the string tables using the strings supplied by the progs. - Called automatically during progs load. - \param pr pointer to ::progs_t VM struct - \return true for success, false for failure +/** Initialize the string management subsystem. + + \param pr The VM of which the string management subsystem will be + initialized; */ -int PR_LoadStrings (progs_t *pr); +void PR_Strings_Init (progs_t *pr); /** Check the validity of a string index. \param pr pointer to ::progs_t VM struct @@ -1230,11 +1230,6 @@ string_t PR_NewMutableString (progs_t *pr); */ string_t PR_SetDynamicString (progs_t *pr, const char *s); -/** Clear all of the return string slots. Called at progs load. - \param pr pointer to ::progs_t VM struct -*/ -void PR_ClearReturnStrings (progs_t *pr); - /** Destroy a mutable, dynamic or temporary string. \param pr pointer to ::progs_t VM struct \param str string index of the string to be destroyed @@ -1644,15 +1639,7 @@ struct progs_s { /// \name string management ///@{ - struct dstring_mem_s *ds_mem; - strref_t *free_string_refs; - strref_t *static_strings; - strref_t **string_map; - strref_t *return_strings[PR_RS_SLOTS]; - int rs_slot; - unsigned dyn_str_size; - struct hashtab_s *strref_hash; - int num_strings; + struct prstr_resources_s *pr_string_resources; strref_t *pr_xtstr; int float_promoted; ///< for PR_Sprintf ///@} diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index 994e9b581..a156e99c8 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -133,7 +133,6 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) pr->free_progs_mem = free_progs_mem; PR_Resources_Clear (pr); - PR_ClearReturnStrings (pr); if (pr->progs) pr->free_progs_mem (pr, pr->progs); pr->progs = 0; @@ -374,7 +373,6 @@ pr_run_ctors (progs_t *pr) } static int (*load_funcs_1[])(progs_t *) = { - PR_LoadStrings, PR_RelocateBuiltins, PR_LoadDebug, 0, @@ -472,6 +470,7 @@ PR_Init (progs_t *pr) { PR_Opcode_Init (); // idempotent PR_Resources_Init (pr); + PR_Strings_Init (pr); PR_Debug_Init (pr); } diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index 85602e3d2..a8c8c4fee 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -44,6 +44,19 @@ #include "QF/progs.h" #include "QF/va.h" +typedef struct prstr_resources_s { + progs_t *pr; + dstring_mem_t ds_mem; + strref_t *free_string_refs; + strref_t *static_strings; + strref_t **string_map; + strref_t *return_strings[PR_RS_SLOTS]; + int rs_slot; + unsigned dyn_str_size; + struct hashtab_s *strref_hash; + int num_strings; +} prstr_resources_t; + typedef enum { str_free, str_static, @@ -111,51 +124,51 @@ pr_strings_realloc (void *_pr, void *ptr, size_t size) } static strref_t * -new_string_ref (progs_t *pr) +new_string_ref (prstr_resources_t *res) { strref_t *sr; - if (!pr->free_string_refs) { + if (!res->free_string_refs) { int i; size_t size; - pr->dyn_str_size++; - size = pr->dyn_str_size * sizeof (strref_t *); - pr->string_map = realloc (pr->string_map, size); - if (!pr->string_map) - PR_Error (pr, "out of memory"); - if (!(pr->free_string_refs = calloc (1024, sizeof (strref_t)))) - PR_Error (pr, "out of memory"); - pr->string_map[pr->dyn_str_size - 1] = pr->free_string_refs; - for (i = 0, sr = pr->free_string_refs; i < 1023; i++, sr++) + res->dyn_str_size++; + size = res->dyn_str_size * sizeof (strref_t *); + res->string_map = realloc (res->string_map, size); + if (!res->string_map) + PR_Error (res->pr, "out of memory"); + if (!(res->free_string_refs = calloc (1024, sizeof (strref_t)))) + PR_Error (res->pr, "out of memory"); + res->string_map[res->dyn_str_size - 1] = res->free_string_refs; + for (i = 0, sr = res->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 = res->free_string_refs; + res->free_string_refs = sr->next; sr->next = 0; return sr; } static void -free_string_ref (progs_t *pr, strref_t *sr) +free_string_ref (prstr_resources_t *res, strref_t *sr) { sr->type = str_free; if (sr->prev) *sr->prev = sr->next; - sr->next = pr->free_string_refs; - pr->free_string_refs = sr; + sr->next = res->free_string_refs; + res->free_string_refs = sr; } static __attribute__((pure)) string_t -string_index (progs_t *pr, strref_t *sr) +string_index (prstr_resources_t *res, strref_t *sr) { - long o = (long) (sr - pr->static_strings); + long o = (long) (sr - res->static_strings); unsigned i; - if (o >= 0 && o < pr->num_strings) - return sr->s.string - pr->pr_strings; - for (i = 0; i < pr->dyn_str_size; i++) { - int d = sr - pr->string_map[i]; + if (o >= 0 && o < res->num_strings) + return sr->s.string - res->pr->pr_strings; + for (i = 0; i < res->dyn_str_size; i++) { + int d = sr - res->string_map[i]; if (d >= 0 && d < 1024) return ~(i * 1024 + d); } @@ -172,24 +185,44 @@ strref_get_key (const void *_sr, void *notused) } static void -strref_free (void *_sr, void *_pr) +strref_free (void *_sr, void *_res) { - progs_t *pr = (progs_t*)_pr; - strref_t *sr = (strref_t*)_sr; + __auto_type res = (prstr_resources_t *) _res; + __auto_type sr = (strref_t *) _sr; // Since this is called only by Hash_FlushTable, the memory pointed // to by sr->string or sr->dstring has already been lost in the progs // load/reload and thus there's no need to free it. // free the string and ref only if it's not a static string - if (sr < pr->static_strings || sr >= pr->static_strings + pr->num_strings) { - free_string_ref (pr, sr); + if (sr < res->static_strings + || sr >= res->static_strings + res->num_strings) { + free_string_ref (res, sr); } } -VISIBLE int +static void +pr_strings_clear (progs_t *pr, void *data) +{ + __auto_type res = (prstr_resources_t *) data; + int i; + + for (i = 0; i < PR_RS_SLOTS; i++) { + if (res->return_strings[i]) + free_string_ref (res, res->return_strings[i]); + res->return_strings[i] = 0; + } + res->rs_slot = 0; + + pr->pr_string_resources = res; + pr->pr_xtstr = 0; +} + +static int PR_LoadStrings (progs_t *pr) { + prstr_resources_t *res = PR_Resources_Find (pr, "Strings"); + char *end = pr->pr_strings + pr->progs->numstrings; char *str = pr->pr_strings; int count = 0; @@ -199,43 +232,41 @@ PR_LoadStrings (progs_t *pr) str += strlen (str) + 1; } - if (!pr->ds_mem) { - pr->ds_mem = malloc (sizeof (dstring_mem_t)); - pr->ds_mem->alloc = pr_strings_alloc; - pr->ds_mem->free = pr_strings_free; - pr->ds_mem->realloc = pr_strings_realloc; - pr->ds_mem->data = pr; - } - if (pr->strref_hash) { - Hash_FlushTable (pr->strref_hash); + res->ds_mem.alloc = pr_strings_alloc; + res->ds_mem.free = pr_strings_free; + res->ds_mem.realloc = pr_strings_realloc; + res->ds_mem.data = pr; + + if (res->strref_hash) { + Hash_FlushTable (res->strref_hash); } else { - pr->strref_hash = Hash_NewTable (1021, strref_get_key, strref_free, - pr); - pr->string_map = 0; - pr->free_string_refs = 0; - pr->dyn_str_size = 0; + res->strref_hash = Hash_NewTable (1021, strref_get_key, strref_free, + res); + res->string_map = 0; + res->free_string_refs = 0; + res->dyn_str_size = 0; } - if (pr->static_strings) - free (pr->static_strings); - pr->static_strings = malloc (count * sizeof (strref_t)); + if (res->static_strings) + free (res->static_strings); + res->static_strings = malloc (count * sizeof (strref_t)); count = 0; str = pr->pr_strings; while (str < end) { - if (!Hash_Find (pr->strref_hash, str)) { - pr->static_strings[count].type = str_static; - pr->static_strings[count].s.string = str; - Hash_Add (pr->strref_hash, &pr->static_strings[count]); + if (!Hash_Find (res->strref_hash, str)) { + res->static_strings[count].type = str_static; + res->static_strings[count].s.string = str; + Hash_Add (res->strref_hash, &res->static_strings[count]); count++; } str += strlen (str) + 1; } - pr->num_strings = count; + res->num_strings = count; return 1; } static inline strref_t * -get_strref (progs_t *pr, string_t num) +get_strref (prstr_resources_t *res, string_t num) { if (num < 0) { strref_t *ref; @@ -243,9 +274,9 @@ get_strref (progs_t *pr, string_t num) num = ~num % 1024; - if (row >= pr->dyn_str_size) + if (row >= res->dyn_str_size) return 0; - ref = &pr->string_map[row][num]; + ref = &res->string_map[row][num]; if (ref->type == str_free) return 0; return ref; @@ -257,7 +288,7 @@ static inline __attribute__((pure)) const char * get_string (progs_t *pr, string_t num) { if (num < 0) { - strref_t *ref = get_strref (pr, num); + strref_t *ref = get_strref (pr->pr_string_resources, num); if (!ref) return 0; switch (ref->type) { @@ -299,7 +330,7 @@ PR_GetString (progs_t *pr, string_t num) VISIBLE dstring_t * PR_GetMutableString (progs_t *pr, string_t num) { - strref_t *ref = get_strref (pr, num); + strref_t *ref = get_strref (pr->pr_string_resources, num); if (ref) { if (ref->type == str_mutable) return ref->s.dstring; @@ -331,70 +362,60 @@ pr_strdup (progs_t *pr, const char *s) VISIBLE string_t PR_SetString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) s = ""; - sr = Hash_Find (pr->strref_hash, s); + sr = Hash_Find (res->strref_hash, s); if (__builtin_expect (!sr, 1)) { - sr = new_string_ref (pr); + sr = new_string_ref (res); sr->type = str_static; sr->s.string = pr_strdup(pr, s); - Hash_Add (pr->strref_hash, sr); - } - return string_index (pr, sr); -} - -void -PR_ClearReturnStrings (progs_t *pr) -{ - int i; - - for (i = 0; i < PR_RS_SLOTS; i++) { - if (pr->return_strings[i]) - free_string_ref (pr, pr->return_strings[i]); - pr->return_strings[i] = 0; + Hash_Add (res->strref_hash, sr); } + return string_index (res, sr); } VISIBLE string_t PR_SetReturnString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) s = ""; - if ((sr = Hash_Find (pr->strref_hash, s))) { - return string_index (pr, sr); + if ((sr = Hash_Find (res->strref_hash, s))) { + return string_index (res, sr); } - if ((sr = pr->return_strings[pr->rs_slot])) { + if ((sr = res->return_strings[res->rs_slot])) { if (sr->type != str_return) PR_Error (pr, "internal string error"); pr_strfree (pr, sr->s.string); } else { - sr = new_string_ref (pr); + sr = new_string_ref (res); } sr->type = str_return; sr->s.string = pr_strdup(pr, s); - pr->return_strings[pr->rs_slot++] = sr; - pr->rs_slot %= PR_RS_SLOTS; - return string_index (pr, sr); + res->return_strings[res->rs_slot++] = sr; + res->rs_slot %= PR_RS_SLOTS; + return string_index (res, sr); } static inline string_t -pr_settempstring (progs_t *pr, char *s) +pr_settempstring (progs_t *pr, prstr_resources_t *res, char *s) { strref_t *sr; - sr = new_string_ref (pr); + sr = new_string_ref (res); sr->type = str_temp; sr->s.string = s; sr->next = pr->pr_xtstr; pr->pr_xtstr = sr; - return string_index (pr, sr); + return string_index (res, sr); } VISIBLE string_t @@ -410,46 +431,49 @@ PR_CatStrings (progs_t *pr, const char *a, const char *b) strcpy (c, a); strcpy (c + lena, b); - return pr_settempstring (pr, c); + return pr_settempstring (pr, pr->pr_string_resources, c); } VISIBLE string_t PR_SetTempString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) return PR_SetString (pr, ""); - if ((sr = Hash_Find (pr->strref_hash, s))) { - return string_index (pr, sr); + if ((sr = Hash_Find (res->strref_hash, s))) { + return string_index (res, sr); } - return pr_settempstring (pr, pr_strdup (pr, s)); + return pr_settempstring (pr, res, pr_strdup (pr, s)); } VISIBLE string_t PR_SetDynamicString (progs_t *pr, const char *s) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr; if (!s) return PR_SetString (pr, ""); - if ((sr = Hash_Find (pr->strref_hash, s))) { - return string_index (pr, sr); + if ((sr = Hash_Find (res->strref_hash, s))) { + return string_index (res, sr); } - sr = new_string_ref (pr); + sr = new_string_ref (res); sr->type = str_dynamic; sr->s.string = pr_strdup (pr, s); - return string_index (pr, sr); + return string_index (res, sr); } void PR_MakeTempString (progs_t *pr, string_t str) { - strref_t *sr = get_strref (pr, str); + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr = get_strref (res, str); if (!sr) PR_RunError (pr, "invalid string %d", str); @@ -470,16 +494,18 @@ PR_MakeTempString (progs_t *pr, string_t str) VISIBLE string_t PR_NewMutableString (progs_t *pr) { - strref_t *sr = new_string_ref (pr); + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr = new_string_ref (res); sr->type = str_mutable; - sr->s.dstring = _dstring_newstr (pr->ds_mem); - return string_index (pr, sr); + sr->s.dstring = _dstring_newstr (&res->ds_mem); + return string_index (res, sr); } VISIBLE void PR_FreeString (progs_t *pr, string_t str) { - strref_t *sr = get_strref (pr, str); + prstr_resources_t *res = pr->pr_string_resources; + strref_t *sr = get_strref (res, str); if (sr) { switch (sr->type) { @@ -496,7 +522,7 @@ PR_FreeString (progs_t *pr, string_t str) default: PR_Error (pr, "internal string error"); } - free_string_ref (pr, sr); + free_string_ref (res, sr); return; } if (!get_string (pr, str)) @@ -506,20 +532,21 @@ PR_FreeString (progs_t *pr, string_t str) void PR_FreeTempStrings (progs_t *pr) { + prstr_resources_t *res = pr->pr_string_resources; strref_t *sr, *t; for (sr = pr->pr_xtstr; sr; sr = t) { t = sr->next; if (sr->type != str_temp) PR_Error (pr, "internal string error"); - if (R_STRING (pr) < 0 && string_index (pr, sr) == R_STRING (pr) + if (R_STRING (pr) < 0 && string_index (res, sr) == R_STRING (pr) && pr->pr_depth) { prstack_t *frame = pr->pr_stack + pr->pr_depth - 1; sr->next = frame->tstr; frame->tstr = sr; } else { pr_strfree (pr, sr->s.string); - free_string_ref (pr, sr); + free_string_ref (res, sr); } } pr->pr_xtstr = 0; @@ -881,3 +908,13 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, error: PR_RunError (pr, "%s: %s", name, msg); } + +void +PR_Strings_Init (progs_t *pr) +{ + prstr_resources_t *res = calloc (1, sizeof (*res)); + res->pr = pr; + + PR_Resources_Register (pr, "Strings", res, pr_strings_clear); + PR_AddLoadFunc (pr, PR_LoadStrings); +} diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index 64dab879a..37acd11fc 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -287,7 +287,6 @@ load_progs (const char *name) if (!pr.progs) return 0; - PR_LoadStrings (&pr); PR_ResolveGlobals (&pr); PR_LoadDebug (&pr); } From 99c818adccd15a5e823c41ac38427196ff60c71d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 00:25:24 +0900 Subject: [PATCH 076/444] Ensure progs zone is always set on load --- libs/gamecode/pr_load.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index a156e99c8..1178fe039 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -212,6 +212,7 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) *pr->edicts = (edict_t *)((byte *) pr->progs + pr->progs_size); } + pr->zone = 0; if (pr->zone_size) { //FIXME zone_size needs to be at least as big as memzone_t, but //memzone_t is opaque so its size is unknown From 9bb68f2d8c047a410651d97cf814bb0c9952a82c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 14:30:26 +0900 Subject: [PATCH 077/444] Allow nested use of PR_SaveParams() PR_SaveParams() is required for implementing the +initialize diversion used by Objective-QuakeC because builtins do not have local def spaces (of course, a normal stack calling convention would help). However, it is entirely possible for a call to +initialize to trigger another call to +initialize, thus the need for stacking parameter stashes. As a bonus, this implementation cleans up some fields in progs_t. --- include/QF/progs.h | 59 +++++++++++++++++++++++++++++++++----- libs/gamecode/pr_exec.c | 31 +++++++++++--------- libs/gamecode/pr_resolve.c | 4 --- libs/ruamoko/rua_obj.c | 4 +-- 4 files changed, 71 insertions(+), 27 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 25f81f2b5..1162625ac 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -91,15 +91,63 @@ void PR_RunError (progs_t *pr, const char *error, ...) __attribute__((format(pri (pr)->pr_params[1] = (pr)->pr_real_params[1]; \ } while (0) -/** Save the current parameters. - \param pr pointer to ::progs_t VM struct +/** \name Detouring Function Calls + + These functions allow a builtin function that uses PR_CallFunction() to + safely insert a call to another VM function. The +initialize diversion + required by Objective-QuakeC uses this. + + PR_PushFrame (pr); + __auto_type params = PR_SaveParams (pr); + ... set up parameters to detour_function + PR_ExecuteProgram (pr, detour_function) + PR_RestoreParams (pr, params); + PR_PopFrame (pr); + */ -void PR_SaveParams (progs_t *pr); +///@{ +typedef struct pr_stashed_params_s { + pr_type_t *param_ptrs[2]; + int argc; + pr_type_t params[1]; +} pr_stashed_params_t; + +/** Save the current parameters to the provided stash. + + \warning The memory for the parameter stash is allocated using + alloca(). + + \param pr pointer to ::progs_t VM struct + \return Pointer to a newly allocated and initialized parameter + stash that has the current parameters saved to it. + \hideinitializer +*/ +#define PR_SaveParams(pr) \ + _PR_SaveParams((pr), \ + alloca (field_offset (pr_stashed_params_t, \ + params[(pr)->pr_argc \ + * (pr)->pr_param_size]))) + +/** [INTERNAL] Save the current parameters to the provided stash. + + \warning Requires \a params to be correctly allocated. Use + PR_SaveParams instead as it will create a suitable stash for + saving the parameters. + + \param pr pointer to ::progs_t VM struct + \param params location to save the parameters, must be of adequade size + to hold \a pr_argc * \a pr_param_size words in \a params + \return \a params Allows the likes of: + __auto_type params = PR_SaveParams (pr); +*/ +pr_stashed_params_t *_PR_SaveParams (progs_t *pr, pr_stashed_params_t *params); /** Restore the parameters saved by PR_SaveParams(). \param pr pointer to ::progs_t VM struct + \param params pointer to stash created by PR_SaveParams() */ -void PR_RestoreParams (progs_t *pr); +void PR_RestoreParams (progs_t *pr, pr_stashed_params_t *params); +///@} /** Push an execution frame onto the VM stack. Saves current execution state. \param pr pointer to ::progs_t VM struct @@ -1662,9 +1710,6 @@ struct progs_s { pr_type_t *pr_return; pr_type_t *pr_params[MAX_PARMS]; pr_type_t *pr_real_params[MAX_PARMS]; - pr_type_t *pr_param_ptrs[2]; - pr_type_t *pr_saved_params; - int pr_saved_argc; int pr_param_size; ///< covers both params and return int pr_param_alignment; ///< covers both params and return ///@} diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index f7becdfa5..e7e9d28eb 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -72,37 +72,40 @@ PR_RunError (progs_t * pr, const char *error, ...) PR_Error (pr, "Program error: %s", string->str); } -VISIBLE void -PR_SaveParams (progs_t *pr) +VISIBLE pr_stashed_params_t * +_PR_SaveParams (progs_t *pr, pr_stashed_params_t *params) { int i; int size = pr->pr_param_size * sizeof (pr_type_t); - pr->pr_param_ptrs[0] = pr->pr_params[0]; - pr->pr_param_ptrs[1] = pr->pr_params[1]; + params->param_ptrs[0] = pr->pr_params[0]; + params->param_ptrs[1] = pr->pr_params[1]; pr->pr_params[0] = pr->pr_real_params[0]; pr->pr_params[1] = pr->pr_real_params[1]; for (i = 0; i < pr->pr_argc; i++) { - memcpy (pr->pr_saved_params + i * pr->pr_param_size, + memcpy (params->params + i * pr->pr_param_size, pr->pr_real_params[i], size); - if (i < 2) - memcpy (pr->pr_real_params[i], pr->pr_param_ptrs[0], size); + if (i < 2) { //XXX FIXME what the what?!? + memcpy (pr->pr_real_params[i], params->param_ptrs[0], size); + } } - pr->pr_saved_argc = pr->pr_argc; + params->argc = pr->pr_argc; + return params; } VISIBLE void -PR_RestoreParams (progs_t *pr) +PR_RestoreParams (progs_t *pr, pr_stashed_params_t *params) { int i; int size = pr->pr_param_size * sizeof (pr_type_t); - pr->pr_params[0] = pr->pr_param_ptrs[0]; - pr->pr_params[1] = pr->pr_param_ptrs[1]; - pr->pr_argc = pr->pr_saved_argc; - for (i = 0; i < pr->pr_argc; i++) + pr->pr_params[0] = params->param_ptrs[0]; + pr->pr_params[1] = params->param_ptrs[1]; + pr->pr_argc = params->argc; + for (i = 0; i < pr->pr_argc; i++) { memcpy (pr->pr_real_params[i], - pr->pr_saved_params + i * pr->pr_param_size, size); + params->params + i * pr->pr_param_size, size); + } } VISIBLE inline void diff --git a/libs/gamecode/pr_resolve.c b/libs/gamecode/pr_resolve.c index 07ef44d60..0f7acaa8f 100644 --- a/libs/gamecode/pr_resolve.c +++ b/libs/gamecode/pr_resolve.c @@ -139,10 +139,6 @@ PR_ResolveGlobals (progs_t *pr) goto error; pr->pr_param_alignment = G_INT (pr, def->ofs); } - if (pr->pr_saved_params) - free (pr->pr_saved_params); - pr->pr_saved_params = calloc (pr->pr_param_size * MAX_PARMS, - sizeof (pr_type_t)); memcpy (pr->pr_real_params, pr->pr_params, sizeof (pr->pr_params)); if (!pr->globals.time) { if ((def = PR_FindGlobal (pr, "time"))) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index efb193bc8..f44da87a9 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -728,12 +728,12 @@ obj_send_initialize (progs_t *pr, pr_class_t *class) sel = &G_STRUCT (pr, pr_sel_t, method->method_name); if (sel->sel_id == selector->sel_id) { PR_PushFrame (pr); - PR_SaveParams (pr); + __auto_type params = PR_SaveParams (pr); // param 0 is known to be the class pointer P_POINTER (pr, 1) = method->method_name; // pr->pr_argc is known to be 2 PR_ExecuteProgram (pr, method->method_imp); - PR_RestoreParams (pr); + PR_RestoreParams (pr, params); PR_PopFrame (pr); return; } From 6e56c9a4aa0eac6194be3c327a96c48e999072f4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 14:40:03 +0900 Subject: [PATCH 078/444] Ensure edict_parse is reset on progs load A server switching from a game that sets edict_parse to one that does not could go badly when it comes time to loading a level. --- libs/gamecode/pr_load.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index 1178fe039..2b6e9d9ff 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -188,6 +188,7 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) pr->pr_edict_size = align_size (pr->pr_edict_size); pr->pr_edictareasize = pr->max_edicts * pr->pr_edict_size; + pr->edict_parse = 0; mem_size = pr->progs_size + pr->zone_size + pr->pr_edictareasize + pr->stack_size; From 6a4ef598ab3212975099d27ba38416f0714d2e28 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 14:57:36 +0900 Subject: [PATCH 079/444] Allow progs num_edicts and reserved_edicts to be null Really, while there are edict related instructions, edict support should probably not be in the VM itself. --- include/QF/progs.h | 1 + libs/gamecode/pr_edict.c | 32 +++++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 1162625ac..f5767f47c 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1715,6 +1715,7 @@ struct progs_s { ///@} /// \name edicts + /// \todo FIXME should this be outside the VM? ///@{ edict_t **edicts; int max_edicts; ///< set by user diff --git a/libs/gamecode/pr_edict.c b/libs/gamecode/pr_edict.c index 76eb07e9b..29559f8f1 100644 --- a/libs/gamecode/pr_edict.c +++ b/libs/gamecode/pr_edict.c @@ -63,7 +63,7 @@ ED_ClearEdict (progs_t *pr, edict_t *e, int val) { pr_uint_t i; - if (NUM_FOR_EDICT (pr, e) < *pr->reserved_edicts) + if (pr->reserved_edicts && NUM_FOR_EDICT (pr, e) < *pr->reserved_edicts) Sys_Printf ("clearing reserved edict %d\n", NUM_FOR_EDICT (pr, e)); for (i=0; i < pr->progs->entityfields; i++) e->v[i].integer_var = val; @@ -86,6 +86,9 @@ ED_Alloc (progs_t *pr) edict_t *e; int start = pr->reserved_edicts ? *pr->reserved_edicts : 0; + if (!pr->num_edicts) { + PR_RunError (pr, "Edicts not supported in this VM\n"); + } for (i = start + 1; i < *pr->num_edicts; i++) { e = EDICT_NUM (pr, i); // the first couple seconds of server time can involve a lot of @@ -145,6 +148,10 @@ ED_Free (progs_t *pr, edict_t *ed) VISIBLE void ED_PrintNum (progs_t *pr, pr_int_t ent) { + if (!pr->num_edicts) { + Sys_Printf ("Edicts not supported in this VM\n"); + return; + } ED_Print (pr, EDICT_NUM (pr, ent)); } @@ -162,9 +169,13 @@ ED_PrintEdicts (progs_t *pr, const char *fieldval) def = PR_FindField(pr, "classname"); + if (!pr->num_edicts) { + Sys_Printf ("Edicts not supported in this VM\n"); + return; + } if (fieldval && fieldval[0] && def) { count = 0; - for (i = 0; i < *(pr)->num_edicts; i++) + for (i = 0; i < *pr->num_edicts; i++) if (strequal(fieldval, E_GSTRING (pr, EDICT_NUM(pr, i), def->ofs))) { ED_PrintNum (pr, i); @@ -172,9 +183,9 @@ ED_PrintEdicts (progs_t *pr, const char *fieldval) } Sys_Printf ("%i entities\n", count); } else { - for (i = 0; i < *(pr)->num_edicts; i++) + for (i = 0; i < *pr->num_edicts; i++) ED_PrintNum (pr, i); - Sys_Printf ("%i entities\n", *(pr)->num_edicts); + Sys_Printf ("%i entities\n", *pr->num_edicts); } } @@ -192,10 +203,14 @@ ED_Count (progs_t *pr) pr_def_t *model_def; edict_t *ent; + if (!pr->num_edicts) { + Sys_Printf ("Edicts not supported in this VM\n"); + return; + } solid_def = PR_FindField (pr, "solid"); model_def = PR_FindField (pr, "model"); active = models = solid = step = zombie = 0; - for (i = 0; i < *(pr)->num_edicts; i++) { + for (i = 0; i < *pr->num_edicts; i++) { ent = EDICT_NUM (pr, i); if (ent->free) { if (pr->globals.time && *pr->globals.time - ent->freetime <= 0.5) @@ -209,7 +224,7 @@ ED_Count (progs_t *pr) models++; } - Sys_Printf ("num_edicts:%3i\n", *(pr)->num_edicts); + Sys_Printf ("num_edicts:%3i\n", *pr->num_edicts); Sys_Printf ("active :%3i\n", active); Sys_Printf ("view :%3i\n", models); Sys_Printf ("touch :%3i\n", solid); @@ -234,7 +249,7 @@ ED_NumForEdict (progs_t *pr, edict_t *e) b = NUM_FOR_BAD_EDICT (pr, e); - if (b && (b < 0 || b >= *(pr)->num_edicts)) + if (b && (b < 0 || b >= *pr->num_edicts)) PR_RunError (pr, "NUM_FOR_EDICT: bad pointer %d %p %p", b, e, *(pr)->edicts); @@ -244,6 +259,9 @@ ED_NumForEdict (progs_t *pr, edict_t *e) qboolean PR_EdictValid (progs_t *pr, pr_int_t e) { + if (!pr->num_edicts) { + return false; + } if (e < 0 || e >= pr->pr_edictareasize) return false; if (e % pr->pr_edict_size) From 61d7f4f9c4145168871ad64f30e879a0860979cc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 15:18:15 +0900 Subject: [PATCH 080/444] Dump locals stack when dumping main stack Any shutdown functions in progs will need locals too. --- libs/gamecode/pr_exec.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index e7e9d28eb..345792f4d 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -68,6 +68,7 @@ PR_RunError (progs_t * pr, const char *error, ...) // dump the stack so PR_Error can shutdown functions pr->pr_depth = 0; + pr->localstack_used = 0; PR_Error (pr, "Program error: %s", string->str); } From e3953be8f8d7911052ecc08d6f2baa2d00a4e9e9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 15:19:21 +0900 Subject: [PATCH 081/444] Ensure execution state is initialized on progs load --- libs/gamecode/pr_load.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index 2b6e9d9ff..efa347f4b 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -330,6 +330,12 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) def->type_encoding = xdef->type; } } + pr->pr_trace = 0; + pr->pr_trace_depth = 0; + pr->pr_xfunction = 0; + pr->pr_xstatement = 0; + pr->pr_depth = 0; + pr->localstack_used = 0; } VISIBLE void From a55b9544ac6c876683de267d17ed7af8e9357453 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 17:28:32 +0900 Subject: [PATCH 082/444] Improve handling of pr_argc It is now set to 0 when progs are loaded and every time PR_ExecuteProgram() returns. This takes care of the default case, but when setting parameters, pr_argc needs to be set correctly in case a vararg function is called. --- doc/progs/vm-exec.c | 1 + include/QF/progs.h | 2 +- libs/console/bi_inputline.c | 2 ++ libs/console/menu.c | 5 +++++ libs/gamecode/pr_exec.c | 1 + libs/gamecode/pr_load.c | 1 + libs/gamecode/pr_parse.c | 1 + libs/gib/bi_gib.c | 1 + libs/ruamoko/rua_hash.c | 4 ++++ qw/source/sv_ccmds.c | 1 + qw/source/sv_pr_cpqw.c | 1 + qw/source/sv_pr_qwe.c | 1 + qw/source/sv_user.c | 2 ++ tools/qfcc/test/test-harness.c | 1 + tools/qwaq/main.c | 1 + tools/qwaq/qwaq.c | 1 + 16 files changed, 25 insertions(+), 1 deletion(-) diff --git a/doc/progs/vm-exec.c b/doc/progs/vm-exec.c index 0234c2158..1f9ae4b8e 100644 --- a/doc/progs/vm-exec.c +++ b/doc/progs/vm-exec.c @@ -23,6 +23,7 @@ call_progs_main (progs_t *pr, int argc, const char **argv) PR_RESET_PARAMS (pr); P_INT (pr, 0) = argc; P_POINTER (pr, 1) = PR_SetPointer (pr, pr_argv); + pr->pr_argc = 2; PR_ExecuteProgram (pr, progs_main); PR_PopFrame (pr); PR_Zone_Free (pr, pr_argv); diff --git a/include/QF/progs.h b/include/QF/progs.h index f5767f47c..00f948d52 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1732,7 +1732,7 @@ struct progs_s { /// \name execution state ///@{ - int pr_argc; + int pr_argc; //FIXME need a good way to ensure it is correct qboolean pr_trace; int pr_trace_depth; diff --git a/libs/console/bi_inputline.c b/libs/console/bi_inputline.c index e4a936d6f..f48a4551e 100644 --- a/libs/console/bi_inputline.c +++ b/libs/console/bi_inputline.c @@ -130,9 +130,11 @@ bi_inputline_enter (inputline_t *il) P_POINTER (pr, 0) = data->data[0]; P_POINTER (pr, 1) = data->data[1]; P_STRING (pr, 2) = PR_SetTempString (pr, line); + pr->pr_argc = 3; } else { P_STRING (pr, 0) = PR_SetTempString (pr, line); P_POINTER (pr, 1) = data->data[0]; + pr->pr_argc = 2; } PR_ExecuteProgram (pr, data->enter); PR_PopFrame (pr); diff --git a/libs/console/menu.c b/libs/console/menu.c index 3ebf1d60a..ec9fc3355 100644 --- a/libs/console/menu.c +++ b/libs/console/menu.c @@ -439,6 +439,7 @@ bi_Menu_Enter (progs_t *pr) P_STRING (&menu_pr_state, 0) = PR_SetTempString (&menu_pr_state, item->text); P_INT (&menu_pr_state, 1) = 0; + pr->pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, item->func); PR_PopFrame (&menu_pr_state); run_menu_post (); @@ -672,6 +673,7 @@ Menu_Draw (view_t *view) PR_RESET_PARAMS (&menu_pr_state); P_INT (&menu_pr_state, 0) = x; P_INT (&menu_pr_state, 1) = y; + menu_pr_state.pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, menu->draw); ret = R_INT (&menu_pr_state); run_menu_post (); @@ -706,6 +708,7 @@ Menu_Draw (view_t *view) PR_RESET_PARAMS (&menu_pr_state); P_INT (&menu_pr_state, 0) = x + item->x; P_INT (&menu_pr_state, 1) = y + item->y; + menu_pr_state.pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, menu->cursor); run_menu_post (); } else { @@ -738,6 +741,7 @@ Menu_KeyEvent (knum_t key, short unicode, qboolean down) P_INT (&menu_pr_state, 0) = key; P_INT (&menu_pr_state, 1) = unicode; P_INT (&menu_pr_state, 2) = down; + menu_pr_state.pr_argc = 3; PR_ExecuteProgram (&menu_pr_state, menu->keyevent); ret = R_INT (&menu_pr_state); run_menu_post (); @@ -752,6 +756,7 @@ Menu_KeyEvent (knum_t key, short unicode, qboolean down) P_STRING (&menu_pr_state, 0) = PR_SetTempString (&menu_pr_state, item->text); P_INT (&menu_pr_state, 1) = key; + menu_pr_state.pr_argc = 2; PR_ExecuteProgram (&menu_pr_state, item->func); PR_PopFrame (&menu_pr_state); ret = R_INT (&menu_pr_state); diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 345792f4d..024594d81 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -1640,6 +1640,7 @@ op_call: watch->integer_var); } exit_program: + pr->pr_argc = 0; Sys_PopErrorHandler (); Sys_PopSignalHook (); } diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index efa347f4b..b7790711f 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -336,6 +336,7 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) pr->pr_xstatement = 0; pr->pr_depth = 0; pr->localstack_used = 0; + pr->pr_argc = 0; } VISIBLE void diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index 69219651f..f17b69bf1 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -524,6 +524,7 @@ ED_LoadFromFile (progs_t *pr, const char *data) PR_PushFrame (pr); PR_RESET_PARAMS (pr); P_INT (pr, 0) = PR_SetTempString (pr, data); + pr->pr_argc = 1; PR_ExecuteProgram (pr, pr->edict_parse); PR_PopFrame (pr); return; diff --git a/libs/gib/bi_gib.c b/libs/gib/bi_gib.c index b1482c030..3c462712c 100644 --- a/libs/gib/bi_gib.c +++ b/libs/gib/bi_gib.c @@ -91,6 +91,7 @@ bi_gib_builtin_f (void) PR_RESET_PARAMS (builtin->pr); P_INT (builtin->pr, 0) = GIB_Argc(); P_INT (builtin->pr, 1) = PR_SetPointer (builtin->pr, pr_list); + builtin->pr->pr_argc = 2; PR_ExecuteProgram (builtin->pr, builtin->func); PR_PopFrame (builtin->pr); PR_Zone_Free (builtin->pr, pr_list); diff --git a/libs/ruamoko/rua_hash.c b/libs/ruamoko/rua_hash.c index cc6d2b8c6..fedb8c288 100644 --- a/libs/ruamoko/rua_hash.c +++ b/libs/ruamoko/rua_hash.c @@ -98,6 +98,7 @@ bi_get_key (const void *key, void *_ht) PR_RESET_PARAMS (ht->pr); P_INT (ht->pr, 0) = (intptr_t) (key); P_INT (ht->pr, 1) = ht->ud; + ht->pr->pr_argc = 2; PR_ExecuteProgram (ht->pr, ht->gk); return PR_GetString (ht->pr, R_STRING (ht->pr)); } @@ -109,6 +110,7 @@ bi_get_hash (const void *key, void *_ht) PR_RESET_PARAMS (ht->pr); P_INT (ht->pr, 0) = (intptr_t) (key); P_INT (ht->pr, 1) = ht->ud; + ht->pr->pr_argc = 2; PR_ExecuteProgram (ht->pr, ht->gh); return R_INT (ht->pr); } @@ -121,6 +123,7 @@ bi_compare (const void *key1, const void *key2, void *_ht) P_INT (ht->pr, 0) = (intptr_t) (key1); P_INT (ht->pr, 1) = (intptr_t) (key2); P_INT (ht->pr, 2) = ht->ud; + ht->pr->pr_argc = 3; PR_ExecuteProgram (ht->pr, ht->cmp); return R_INT (ht->pr); } @@ -132,6 +135,7 @@ bi_free (void *key, void *_ht) PR_RESET_PARAMS (ht->pr); P_INT (ht->pr, 0) = (intptr_t) (key); P_INT (ht->pr, 1) = ht->ud; + ht->pr->pr_argc = 2; PR_ExecuteProgram (ht->pr, ht->f); } diff --git a/qw/source/sv_ccmds.c b/qw/source/sv_ccmds.c index aa359c576..318a2edaf 100644 --- a/qw/source/sv_ccmds.c +++ b/qw/source/sv_ccmds.c @@ -950,6 +950,7 @@ SV_SetLocalinfo (const char *key, const char *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); + sv_pr_state.pr_argc = 3; PR_ExecuteProgram (&sv_pr_state, sv_funcs.LocalinfoChanged); PR_PopFrame (&sv_pr_state); } diff --git a/qw/source/sv_pr_cpqw.c b/qw/source/sv_pr_cpqw.c index 594f66219..e67b951b6 100644 --- a/qw/source/sv_pr_cpqw.c +++ b/qw/source/sv_pr_cpqw.c @@ -822,6 +822,7 @@ cpqw_user_cmd (void) P_STRING (pr, i) = PR_SetTempString (pr, Cmd_Argv (i - 1)); for (; i < 7; i++) P_STRING (pr, i) = 0; + pr->pr_argc = 7; PR_ExecuteProgram (pr, cpqw_funcs.ClientCommand); PR_PopFrame (pr); return (int) R_FLOAT (pr); diff --git a/qw/source/sv_pr_qwe.c b/qw/source/sv_pr_qwe.c index 7c8a46d84..9a84892cf 100644 --- a/qw/source/sv_pr_qwe.c +++ b/qw/source/sv_pr_qwe.c @@ -353,6 +353,7 @@ PF_calltimeofday (progs_t *pr) P_FLOAT (pr, 5) = (float) date.year; P_STRING (pr, 6) = PR_SetReturnString (pr, date.str); + pr->pr_argc = 7; PR_ExecuteProgram (pr, (func_t) (f - sv_pr_state.pr_functions)); PR_PopFrame (&sv_pr_state); } diff --git a/qw/source/sv_user.c b/qw/source/sv_user.c index 5398eff6c..a6b56c219 100644 --- a/qw/source/sv_user.c +++ b/qw/source/sv_user.c @@ -1211,6 +1211,7 @@ SV_SetUserinfo (client_t *client, const char *key, const char *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); + sv_pr_state.pr_argc = 3; PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoChanged); PR_PopFrame (&sv_pr_state); send_changes = !R_FLOAT (&sv_pr_state); @@ -1261,6 +1262,7 @@ SV_SetInfo_f (void *unused) PR_RESET_PARAMS (&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, value); + sv_pr_state.pr_argc = 2; PR_ExecuteProgram (&sv_pr_state, sv_funcs.UserInfoCallback); PR_PopFrame (&sv_pr_state); if (R_FLOAT (&sv_pr_state)) diff --git a/tools/qfcc/test/test-harness.c b/tools/qfcc/test/test-harness.c index cabef6ab7..1c6610723 100644 --- a/tools/qfcc/test/test-harness.c +++ b/tools/qfcc/test/test-harness.c @@ -266,6 +266,7 @@ main (int argc, char **argv) PR_RESET_PARAMS (&pr); P_INT (&pr, 0) = pr_argc; P_POINTER (&pr, 1) = PR_SetPointer (&pr, pr_argv); + pr.pr_argc = 2; PR_ExecuteProgram (&pr, main_func); PR_PopFrame (&pr); if (options.flote) diff --git a/tools/qwaq/main.c b/tools/qwaq/main.c index 1ab7c027e..7f51ea6df 100644 --- a/tools/qwaq/main.c +++ b/tools/qwaq/main.c @@ -177,6 +177,7 @@ main (int argc, char **argv) PR_RESET_PARAMS (&pr); P_INT (&pr, 0) = pr_argc; P_POINTER (&pr, 1) = PR_SetPointer (&pr, pr_argv); + pr.pr_argc = 2; PR_ExecuteProgram (&pr, main_func); PR_PopFrame (&pr); return R_INT (&pr); diff --git a/tools/qwaq/qwaq.c b/tools/qwaq/qwaq.c index b446a02dd..05d515f4e 100644 --- a/tools/qwaq/qwaq.c +++ b/tools/qwaq/qwaq.c @@ -189,6 +189,7 @@ main (int argc, const char **argv) PR_RESET_PARAMS (&pr); P_INT (&pr, 0) = pr_argc; P_POINTER (&pr, 1) = PR_SetPointer (&pr, pr_argv); + pr.pr_argc = 2; PR_ExecuteProgram (&pr, main_func); PR_PopFrame (&pr); return R_INT (&pr); From 6739f5df4dbd3ebf72b0718a74b1cb43f1e968fe Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 17:39:34 +0900 Subject: [PATCH 083/444] Fix an out-by-one error Noticed while sorting out pr_argc --- qw/source/sv_pr_cpqw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qw/source/sv_pr_cpqw.c b/qw/source/sv_pr_cpqw.c index e67b951b6..4263cc097 100644 --- a/qw/source/sv_pr_cpqw.c +++ b/qw/source/sv_pr_cpqw.c @@ -818,11 +818,11 @@ cpqw_user_cmd (void) PR_PushFrame (pr); P_FLOAT (pr, 0) = argc; - for (i = 1; i < argc; i++) + for (i = 1; i < argc + 1; i++) P_STRING (pr, i) = PR_SetTempString (pr, Cmd_Argv (i - 1)); - for (; i < 7; i++) + for (; i < 8; i++) P_STRING (pr, i) = 0; - pr->pr_argc = 7; + pr->pr_argc = 8; PR_ExecuteProgram (pr, cpqw_funcs.ClientCommand); PR_PopFrame (pr); return (int) R_FLOAT (pr); From ca6fe0730bc151653043669f86f0f3f5b9c53dd9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 19:02:24 +0900 Subject: [PATCH 084/444] Fix qfcc test harness tracing Just a consequence of progs execution state being initialized properly. --- tools/qfcc/test/test-harness.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/test/test-harness.c b/tools/qfcc/test/test-harness.c index 1c6610723..69e660941 100644 --- a/tools/qfcc/test/test-harness.c +++ b/tools/qfcc/test/test-harness.c @@ -150,8 +150,6 @@ init_qf (void) pr.allocate_progs_mem = allocate_progs_mem; pr.free_progs_mem = free_progs_mem; pr.no_exec_limit = 0; // absolutely want a limit! - pr.pr_trace_depth = -1; - pr.pr_trace = options.trace; PR_Init_Cvars (); PR_Init (&pr); @@ -178,6 +176,8 @@ load_progs (const char *name) Qclose (file); if (!PR_RunLoadFuncs (&pr)) PR_Error (&pr, "unable to load %s", pr.progs_name); + pr.pr_trace_depth = -1; + pr.pr_trace = options.trace; return 1; } From 89e83d7d73548375af6a9750152c93bf3726e979 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 20:07:29 +0900 Subject: [PATCH 085/444] Move the debug info out of progs_t The debug subsystem now uses the resources system to ensure it cleans up, and its data is now semi-private. Unfortunately, PR_LoadDebug had to remain public for qfprogs because using PR_RunLoadFuncs would cause builtin resolution to complain. --- include/QF/progs.h | 14 +- libs/gamecode/pr_debug.c | 291 ++++++++++++++++++++----------- libs/gamecode/pr_load.c | 1 - tools/qfcc/source/dump_globals.c | 16 +- tools/qfcc/source/dump_lines.c | 11 +- 5 files changed, 211 insertions(+), 122 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 00f948d52..ebfa0a3fd 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1583,6 +1583,11 @@ void PR_Debug_Init_Cvars (void); int PR_LoadDebug (progs_t *pr); void PR_Debug_Watch (progs_t *pr, const char *expr); void PR_Debug_Print (progs_t *pr, const char *expr); +pr_auxfunction_t *PR_Debug_AuxFunction (progs_t *pr, pr_uint_t func) __attribute__((pure)); +pr_auxfunction_t *PR_Debug_MappedAuxFunction (progs_t *pr, pr_uint_t func) __attribute__((pure)); +pr_def_t *PR_Debug_LocalDefs (progs_t *pr, pr_auxfunction_t *aux_function) __attribute__((pure)); +pr_lineno_t *PR_Debug_Linenos (progs_t *pr, pr_auxfunction_t *aux_function, + pr_uint_t *num_linenos); pr_auxfunction_t *PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); pr_uint_t PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); pr_uint_t PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); @@ -1781,14 +1786,9 @@ struct progs_s { struct obj_list_s *class_tree_list; ///@} - /// \name debug info + /// \name debugging ///@{ - const char *debugfile; - struct pr_debug_header_s *debug; - struct pr_auxfunction_s *auxfunctions; - struct pr_auxfunction_s **auxfunction_map; - struct pr_lineno_s *linenos; - pr_def_t *local_defs; + struct prdeb_resources_s *pr_debug_resources; pr_type_t *watch; int wp_conditional; pr_type_t wp_val; diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index d895f631a..898e7255a 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -71,9 +71,16 @@ typedef struct { progs_t *pr; } file_t; -typedef struct { +typedef struct prdeb_resources_s { + progs_t *pr; dstring_t *string; -} pr_debug_resources_t; + const char *debugfile; + struct pr_debug_header_s *debug; + struct pr_auxfunction_s *auxfunctions; + struct pr_auxfunction_s **auxfunction_map; + struct pr_lineno_s *linenos; + pr_def_t *local_defs; +} prdeb_resources_t; typedef struct { progs_t *pr; @@ -322,35 +329,28 @@ error: static void pr_debug_clear (progs_t *pr, void *data) { - __auto_type res = (pr_debug_resources_t *) data; + __auto_type res = (prdeb_resources_t *) data; if (res->string) { dstring_clearstr (res->string); } else { res->string = dstring_newstr (); } -} -void -PR_Debug_Init (progs_t *pr) -{ - pr_debug_resources_t *res = calloc (1, sizeof (*res)); - res->string = 0; + if (res->debug) + pr->free_progs_mem (pr, res->debug); + res->debug = 0; + res->auxfunctions = 0; + if (res->auxfunction_map) + pr->free_progs_mem (pr, res->auxfunction_map); + res->auxfunction_map = 0; + res->linenos = 0; + res->local_defs = 0; - PR_Resources_Register (pr, "PR_Debug", res, pr_debug_clear); - if (!file_hash) { - file_hash = Hash_NewTable (1024, file_get_key, file_free, 0); - } -} - -void -PR_Debug_Init_Cvars (void) -{ - pr_debug = Cvar_Get ("pr_debug", "0", CVAR_NONE, NULL, - "enable progs debugging"); - pr_source_path = Cvar_Get ("pr_source_path", ".", CVAR_NONE, source_path_f, - "where to look (within gamedir) for source " - "files"); + pr->pr_debug_resources = res; + pr->watch = 0; + pr->wp_conditional = 0; + pr->wp_val.integer_var = 0; } static file_t * @@ -411,6 +411,7 @@ PR_Load_Source_File (progs_t *pr, const char *fname) VISIBLE int PR_LoadDebug (progs_t *pr) { + prdeb_resources_t *res = PR_Resources_Find (pr, "PR_Debug"); char *sym_path; const char *path_end, *sym_file; off_t debug_size; @@ -418,16 +419,6 @@ PR_LoadDebug (progs_t *pr) pr_def_t *def; pr_type_t *str = 0; - if (pr->debug) - pr->free_progs_mem (pr, pr->debug); - pr->debug = 0; - pr->auxfunctions = 0; - if (pr->auxfunction_map) - pr->free_progs_mem (pr, pr->auxfunction_map); - pr->auxfunction_map = 0; - pr->linenos = 0; - pr->local_defs = 0; - if (!pr_debug->int_val) return 1; @@ -438,107 +429,169 @@ PR_LoadDebug (progs_t *pr) Hash_FlushTable (file_hash); if (!str) return 1; - pr->debugfile = PR_GetString (pr, str->string_var); - sym_file = QFS_SkipPath (pr->debugfile); + res->debugfile = PR_GetString (pr, str->string_var); + sym_file = QFS_SkipPath (res->debugfile); path_end = QFS_SkipPath (pr->progs_name); sym_path = malloc (strlen (sym_file) + (path_end - pr->progs_name) + 1); strncpy (sym_path, pr->progs_name, path_end - pr->progs_name); strcpy (sym_path + (path_end - pr->progs_name), sym_file); - pr->debug = pr->load_file (pr, sym_path, &debug_size); - if (!pr->debug) { + res->debug = pr->load_file (pr, sym_path, &debug_size); + if (!res->debug) { Sys_Printf ("can't load %s for debug info\n", sym_path); free (sym_path); return 1; } - pr->debug->version = LittleLong (pr->debug->version); - if (pr->debug->version != PROG_DEBUG_VERSION) { + res->debug->version = LittleLong (res->debug->version); + if (res->debug->version != PROG_DEBUG_VERSION) { Sys_Printf ("ignoring %s with unsupported version %x.%03x.%03x\n", sym_path, - (pr->debug->version >> 24) & 0xff, - (pr->debug->version >> 12) & 0xfff, - pr->debug->version & 0xfff); - pr->debug = 0; + (res->debug->version >> 24) & 0xff, + (res->debug->version >> 12) & 0xfff, + res->debug->version & 0xfff); + res->debug = 0; free (sym_path); return 1; } - pr->debug->crc = LittleShort (pr->debug->crc); - if (pr->debug->crc != pr->crc) { + res->debug->crc = LittleShort (res->debug->crc); + if (res->debug->crc != pr->crc) { Sys_Printf ("ignoring %s that doesn't match %s. (CRCs: " "sym:%d dat:%d)\n", sym_path, pr->progs_name, - pr->debug->crc, + res->debug->crc, pr->crc); - pr->debug = 0; + res->debug = 0; free (sym_path); return 1; } free (sym_path); - pr->debug->you_tell_me_and_we_will_both_know = LittleShort - (pr->debug->you_tell_me_and_we_will_both_know); - pr->debug->auxfunctions = LittleLong (pr->debug->auxfunctions); - pr->debug->num_auxfunctions = LittleLong (pr->debug->num_auxfunctions); - pr->debug->linenos = LittleLong (pr->debug->linenos); - pr->debug->num_linenos = LittleLong (pr->debug->num_linenos); - pr->debug->locals = LittleLong (pr->debug->locals); - pr->debug->num_locals = LittleLong (pr->debug->num_locals); + res->debug->you_tell_me_and_we_will_both_know = LittleShort + (res->debug->you_tell_me_and_we_will_both_know); + res->debug->auxfunctions = LittleLong (res->debug->auxfunctions); + res->debug->num_auxfunctions = LittleLong (res->debug->num_auxfunctions); + res->debug->linenos = LittleLong (res->debug->linenos); + res->debug->num_linenos = LittleLong (res->debug->num_linenos); + res->debug->locals = LittleLong (res->debug->locals); + res->debug->num_locals = LittleLong (res->debug->num_locals); - pr->auxfunctions = (pr_auxfunction_t*)((char*)pr->debug + - pr->debug->auxfunctions); - pr->linenos = (pr_lineno_t*)((char*)pr->debug + pr->debug->linenos); - pr->local_defs = (pr_def_t*)((char*)pr->debug + pr->debug->locals); + res->auxfunctions = (pr_auxfunction_t*)((char*)res->debug + + res->debug->auxfunctions); + res->linenos = (pr_lineno_t*)((char*)res->debug + res->debug->linenos); + res->local_defs = (pr_def_t*)((char*)res->debug + res->debug->locals); i = pr->progs->numfunctions * sizeof (pr_auxfunction_t *); - pr->auxfunction_map = pr->allocate_progs_mem (pr, i); + res->auxfunction_map = pr->allocate_progs_mem (pr, i); for (i = 0; (int) i < pr->progs->numfunctions; i++) //FIXME (cast) - pr->auxfunction_map[i] = 0; + res->auxfunction_map[i] = 0; - for (i = 0; i < pr->debug->num_auxfunctions; i++) { - pr->auxfunctions[i].function = LittleLong - (pr->auxfunctions[i].function); - pr->auxfunctions[i].source_line = LittleLong - (pr->auxfunctions[i].source_line); - pr->auxfunctions[i].line_info = LittleLong - (pr->auxfunctions[i].line_info); - pr->auxfunctions[i].local_defs = LittleLong - (pr->auxfunctions[i].local_defs); - pr->auxfunctions[i].num_locals = LittleLong - (pr->auxfunctions[i].num_locals); + for (i = 0; i < res->debug->num_auxfunctions; i++) { + res->auxfunctions[i].function = LittleLong + (res->auxfunctions[i].function); + res->auxfunctions[i].source_line = LittleLong + (res->auxfunctions[i].source_line); + res->auxfunctions[i].line_info = LittleLong + (res->auxfunctions[i].line_info); + res->auxfunctions[i].local_defs = LittleLong + (res->auxfunctions[i].local_defs); + res->auxfunctions[i].num_locals = LittleLong + (res->auxfunctions[i].num_locals); - pr->auxfunction_map[pr->auxfunctions[i].function] = - &pr->auxfunctions[i]; + res->auxfunction_map[res->auxfunctions[i].function] = + &res->auxfunctions[i]; } - for (i = 0; i < pr->debug->num_linenos; i++) { - pr->linenos[i].fa.func = LittleLong (pr->linenos[i].fa.func); - pr->linenos[i].line = LittleLong (pr->linenos[i].line); + for (i = 0; i < res->debug->num_linenos; i++) { + res->linenos[i].fa.func = LittleLong (res->linenos[i].fa.func); + res->linenos[i].line = LittleLong (res->linenos[i].line); } - for (i = 0; i < pr->debug->num_locals; i++) { - pr->local_defs[i].type = LittleShort (pr->local_defs[i].type); - pr->local_defs[i].ofs = LittleShort (pr->local_defs[i].ofs); - pr->local_defs[i].name = LittleLong (pr->local_defs[i].name); + for (i = 0; i < res->debug->num_locals; i++) { + res->local_defs[i].type = LittleShort (res->local_defs[i].type); + res->local_defs[i].ofs = LittleShort (res->local_defs[i].ofs); + res->local_defs[i].name = LittleLong (res->local_defs[i].name); } return 1; } +VISIBLE pr_auxfunction_t * +PR_Debug_AuxFunction (progs_t *pr, pr_uint_t func) +{ + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug || func >= res->debug->num_auxfunctions) { + return 0; + } + return &res->auxfunctions[func]; +} + +VISIBLE pr_auxfunction_t * +PR_Debug_MappedAuxFunction (progs_t *pr, pr_uint_t func) +{ + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug || (int)func >= pr->progs->numfunctions) {//FIXME (cast) + return 0; + } + return res->auxfunction_map[func]; +} + +VISIBLE pr_def_t * +PR_Debug_LocalDefs (progs_t *pr, pr_auxfunction_t *aux_function) +{ + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug || !aux_function) { + return 0; + } + if (aux_function->local_defs > res->debug->num_locals) { + return 0; + } + return res->local_defs + aux_function->local_defs; +} + +VISIBLE pr_lineno_t * +PR_Debug_Linenos (progs_t *pr, pr_auxfunction_t *aux_function, + pr_uint_t *num_linenos) +{ + pr_uint_t i, count; + prdeb_resources_t *res = pr->pr_debug_resources; + if (!res->debug) { + return 0; + } + if (!aux_function) { + *num_linenos = res->debug->num_linenos; + return res->linenos; + } + if (aux_function->line_info > res->debug->num_linenos) { + return 0; + } + //FIXME put lineno count in sym file + for (count = 1, i = aux_function->line_info + 1; + i < res->debug->num_linenos; i++, count++) { + if (!res->linenos[i].line) { + break; + } + } + *num_linenos = count; + return res->linenos + aux_function->line_info; +} + pr_auxfunction_t * PR_Get_Lineno_Func (progs_t *pr, pr_lineno_t *lineno) { - while (lineno > pr->linenos && lineno->line) + prdeb_resources_t *res = pr->pr_debug_resources; + while (lineno > res->linenos && lineno->line) lineno--; if (lineno->line) return 0; - return &pr->auxfunctions[lineno->fa.func]; + return &res->auxfunctions[lineno->fa.func]; } pr_uint_t PR_Get_Lineno_Addr (progs_t *pr, pr_lineno_t *lineno) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_auxfunction_t *f; if (lineno->line) return lineno->fa.addr; - if (lineno->fa.func < pr->debug->num_auxfunctions) { - f = &pr->auxfunctions[lineno->fa.func]; + if (lineno->fa.func < res->debug->num_auxfunctions) { + f = &res->auxfunctions[lineno->fa.func]; return pr->pr_functions[f->function].first_statement; } // take a wild guess that only the line number is bogus and return @@ -557,16 +610,17 @@ PR_Get_Lineno_Line (progs_t *pr, pr_lineno_t *lineno) pr_lineno_t * PR_Find_Lineno (progs_t *pr, pr_uint_t addr) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_uint_t i; pr_lineno_t *lineno = 0; - if (!pr->debug) + if (!res->debug) return 0; - if (!pr->debug->num_linenos) + if (!res->debug->num_linenos) return 0; - for (i = pr->debug->num_linenos; i > 0; i--) { - if (PR_Get_Lineno_Addr (pr, &pr->linenos[i - 1]) <= addr) { - lineno = &pr->linenos[i - 1]; + for (i = res->debug->num_linenos; i > 0; i--) { + if (PR_Get_Lineno_Addr (pr, &res->linenos[i - 1]) <= addr) { + lineno = &res->linenos[i - 1]; break; } } @@ -615,13 +669,14 @@ PR_Get_Source_Line (progs_t *pr, pr_uint_t addr) pr_def_t * PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_uint_t i; pr_auxfunction_t *aux_func; pr_def_t *ddef = 0; int num_params; int param_offs = 0; - if (!pr->debug) + if (!res->debug) return 0; if (!func) return 0; @@ -634,12 +689,12 @@ PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) if (parm >= (unsigned) num_params) return 0; - aux_func = pr->auxfunction_map[func - pr->pr_functions]; + aux_func = res->auxfunction_map[func - pr->pr_functions]; if (!aux_func) return 0; for (i = 0; i < aux_func->num_locals; i++) { - ddef = &pr->local_defs[aux_func->local_defs + param_offs + i]; + ddef = &res->local_defs[aux_func->local_defs + param_offs + i]; if (!parm--) break; } @@ -649,11 +704,12 @@ PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) static pr_auxfunction_t * get_aux_function (progs_t *pr) { + prdeb_resources_t *res = pr->pr_debug_resources; dfunction_t *func; - if (!pr->pr_xfunction || !pr->auxfunction_map) + if (!pr->pr_xfunction || !res->auxfunction_map) return 0; func = pr->pr_xfunction->descriptor; - return pr->auxfunction_map[func - pr->pr_functions]; + return res->auxfunction_map[func - pr->pr_functions]; } static etype_t @@ -679,6 +735,7 @@ get_etype (progs_t *pr, int typeptr) pr_def_t * PR_Get_Local_Def (progs_t *pr, pointer_t offs) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_uint_t i; dfunction_t *func; pr_auxfunction_t *aux_func; @@ -688,23 +745,24 @@ PR_Get_Local_Def (progs_t *pr, pointer_t offs) func = pr->pr_xfunction->descriptor; if (!func) return 0; - aux_func = pr->auxfunction_map[func - pr->pr_functions]; + aux_func = res->auxfunction_map[func - pr->pr_functions]; if (!aux_func) return 0; offs -= func->parm_start; if (offs >= func->locals) return 0; for (i = 0; i < aux_func->num_locals; i++) - if (pr->local_defs[aux_func->local_defs + i].ofs == offs) - return &pr->local_defs[aux_func->local_defs + i]; + if (res->local_defs[aux_func->local_defs + i].ofs == offs) + return &res->local_defs[aux_func->local_defs + i]; return 0; } VISIBLE void PR_DumpState (progs_t *pr) { + prdeb_resources_t *res = pr->pr_debug_resources; if (pr->pr_xfunction) { - if (pr_debug->int_val && pr->debug) { + if (pr_debug->int_val && res->debug) { pr_lineno_t *lineno; pr_auxfunction_t *func = 0; dfunction_t *descriptor = pr->pr_xfunction->descriptor; @@ -803,9 +861,10 @@ value_string (pr_debug_data_t *data, qfot_type_t *type, pr_type_t *value) static pr_def_t * pr_debug_find_def (progs_t *pr, pr_int_t ofs) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_def_t *def = 0; - if (pr_debug->int_val && pr->debug) + if (pr_debug->int_val && res->debug) def = PR_Get_Local_Def (pr, ofs); if (!def) def = PR_GlobalAtOfs (pr, ofs); @@ -993,11 +1052,12 @@ pr_debug_pointer_view (qfot_type_t *type, pr_type_t *value, void *_data) { __auto_type data = (pr_debug_data_t *) _data; progs_t *pr = data->pr; + prdeb_resources_t *res = pr->pr_debug_resources; //FIXME dstring_t *dstr = data->dstr; pointer_t ofs = value->integer_var; pr_def_t *def = 0; - if (pr_debug->int_val && pr->debug) { + if (pr_debug->int_val && res->debug) { def = PR_Get_Local_Def (pr, ofs); } if (!def) { @@ -1165,6 +1225,7 @@ PR_Debug_Print (progs_t *pr, const char *expr) VISIBLE void PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) { + prdeb_resources_t *res = pr->pr_debug_resources; int addr = s - pr->pr_statements; int dump_code = contents & 2; const char *fmt; @@ -1188,7 +1249,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) if (pr_debug->int_val > 1) dump_code = 1; - if (pr_debug->int_val && pr->debug) { + if (pr_debug->int_val && res->debug) { const char *source_line = PR_Get_Source_Line (pr, addr); if (source_line) { @@ -1344,13 +1405,14 @@ do_print: static void dump_frame (progs_t *pr, prstack_t *frame) { + prdeb_resources_t *res = pr->pr_debug_resources; dfunction_t *f = frame->f ? frame->f->descriptor : 0; if (!f) { Sys_Printf ("\n"); return; } - if (pr_debug->int_val && pr->debug) { + if (pr_debug->int_val && res->debug) { pr_lineno_t *lineno = PR_Find_Lineno (pr, frame->s); pr_auxfunction_t *func = PR_Get_Lineno_Func (pr, lineno); pr_uint_t line = PR_Get_Lineno_Line (pr, lineno); @@ -1477,3 +1539,26 @@ ED_Print (progs_t *pr, edict_t *ed) dstring_delete (dstr); } + +void +PR_Debug_Init (progs_t *pr) +{ + prdeb_resources_t *res = calloc (1, sizeof (*res)); + res->pr = pr; + + PR_Resources_Register (pr, "PR_Debug", res, pr_debug_clear); + if (!file_hash) { + file_hash = Hash_NewTable (1024, file_get_key, file_free, 0); + } + PR_AddLoadFunc (pr, PR_LoadDebug); +} + +void +PR_Debug_Init_Cvars (void) +{ + pr_debug = Cvar_Get ("pr_debug", "0", CVAR_NONE, NULL, + "enable progs debugging"); + pr_source_path = Cvar_Get ("pr_source_path", ".", CVAR_NONE, source_path_f, + "where to look (within gamedir) for source " + "files"); +} diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index b7790711f..51723cd64 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -383,7 +383,6 @@ pr_run_ctors (progs_t *pr) static int (*load_funcs_1[])(progs_t *) = { PR_RelocateBuiltins, - PR_LoadDebug, 0, }; diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index ea52bd8f6..0dba5c6dc 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -263,19 +263,23 @@ dump_functions (progs_t *pr) func->parm_size[j].size); printf (") %d @ %x", func->locals, func->parm_start); puts (""); - if (pr->debug && type_encodings) { - pr_auxfunction_t *aux = pr->auxfunction_map[i]; - if (!aux) + if (type_encodings) { + pr_auxfunction_t *aux = PR_Debug_MappedAuxFunction (pr, i); + if (!aux) { continue; + } printf (" %d %s:%d %d %d %d %x\n", aux->function, PR_GetString (pr, func->s_file), aux->source_line, aux->line_info, aux->local_defs, aux->num_locals, aux->return_type); + pr_def_t *local_defs = PR_Debug_LocalDefs (pr, aux); + if (!local_defs) { + continue; + } for (j = 0; j < (int)aux->num_locals; j++) { - pr->local_defs[+ aux->local_defs + j].type_encoding - += type_encodings; - dump_def (pr, pr->local_defs + aux->local_defs + j, 1); + local_defs[j].type_encoding += type_encodings;//FIXME do in debug + dump_def (pr, local_defs + j, 1); } } } diff --git a/tools/qfcc/source/dump_lines.c b/tools/qfcc/source/dump_lines.c index ae504c03d..966203a72 100644 --- a/tools/qfcc/source/dump_lines.c +++ b/tools/qfcc/source/dump_lines.c @@ -69,8 +69,8 @@ progs_get_func_data (unsigned func_index, void *data) dfunction_t *func; memset (&func_data, 0, sizeof (func_data)); - if (func_index < pr->debug->num_auxfunctions) { - aux_func = pr->auxfunctions + func_index; + aux_func = PR_Debug_AuxFunction (pr, func_index); + if (aux_func) { func_data.source_line = aux_func->source_line; func_data.return_type = aux_func->return_type; func_data.num_locals = aux_func->num_locals; @@ -126,10 +126,11 @@ dump_line_set (pr_lineno_t *lineno, unsigned count, void dump_lines (progs_t *pr) { - if (!pr->debug) + pr_lineno_t *linenos; + pr_uint_t num_linenos; + if (!(linenos = PR_Debug_Linenos (pr, 0, &num_linenos))) return; - dump_line_set (pr->linenos, pr->debug->num_linenos, - progs_get_func_data, pr); + dump_line_set (linenos, num_linenos, progs_get_func_data, pr); } static func_data_t * From 4bc36836a10e699cb2fbfd7a34e99e7189b8653e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 20:16:37 +0900 Subject: [PATCH 086/444] Correct the type of an aux function's return type It was made to be the address of the type encoding long ago. --- include/QF/pr_debug.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/QF/pr_debug.h b/include/QF/pr_debug.h index be5e1471d..be398f056 100644 --- a/include/QF/pr_debug.h +++ b/include/QF/pr_debug.h @@ -39,8 +39,7 @@ typedef struct pr_auxfunction_s { pr_uint_t line_info; // index to first lineno entry pr_uint_t local_defs; // index to the first local def pr_uint_t num_locals; // number of local defs - pr_short_t return_type; // return type of this function - pr_short_t reserved; + pr_uint_t return_type; // return type of this function } pr_auxfunction_t; typedef struct pr_lineno_s { From 282132958f2dbea62e651a643aff3a82fb3f8084 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 20:45:36 +0900 Subject: [PATCH 087/444] Relocate local def type encodings in debug load For technical reasons (programmer laziness), qfcc does not fix up local def type encodings when writing the debug symbols file (type encoding location not readily accessible). --- libs/gamecode/pr_debug.c | 29 +++++++++++++++++++---------- tools/qfcc/source/dump_globals.c | 1 - 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 898e7255a..e9bc860a9 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -80,6 +80,7 @@ typedef struct prdeb_resources_s { struct pr_auxfunction_s **auxfunction_map; struct pr_lineno_s *linenos; pr_def_t *local_defs; + pr_def_t *type_encodings_def; } prdeb_resources_t; typedef struct { @@ -418,6 +419,7 @@ PR_LoadDebug (progs_t *pr) pr_uint_t i; pr_def_t *def; pr_type_t *str = 0; + pointer_t type_encodings = 0; if (!pr_debug->int_val) return 1; @@ -503,10 +505,22 @@ PR_LoadDebug (progs_t *pr) res->linenos[i].fa.func = LittleLong (res->linenos[i].fa.func); res->linenos[i].line = LittleLong (res->linenos[i].line); } + res->type_encodings_def = PR_FindGlobal (pr, ".type_encodings"); + if (res->type_encodings_def) { + __auto_type encodings = &G_STRUCT (pr, qfot_type_encodings_t, + res->type_encodings_def->ofs); + type_encodings = encodings->types; + } for (i = 0; i < res->debug->num_locals; i++) { res->local_defs[i].type = LittleShort (res->local_defs[i].type); - res->local_defs[i].ofs = LittleShort (res->local_defs[i].ofs); + res->local_defs[i].size = LittleShort (res->local_defs[i].size); + res->local_defs[i].ofs = LittleLong (res->local_defs[i].ofs); res->local_defs[i].name = LittleLong (res->local_defs[i].name); + res->local_defs[i].type_encoding + = LittleLong (res->local_defs[i].type_encoding); + if (type_encodings) { + res->local_defs[i].type_encoding += type_encodings; + } } return 1; } @@ -715,18 +729,13 @@ get_aux_function (progs_t *pr) static etype_t get_etype (progs_t *pr, int typeptr) { - //FIXME cache .type_encodings def - pr_def_t *te_def = PR_FindGlobal (pr, ".type_encodings"); - qfot_type_encodings_t *encodings; qfot_type_t *type; - if (!te_def) { - // can't decode the type, so make no assumptions about it - return typeptr; + if (!typeptr) { + return ev_void; } - encodings = &G_STRUCT (pr, qfot_type_encodings_t, te_def->ofs); - type = &G_STRUCT (pr, qfot_type_t, encodings->types + typeptr); - if (type->meta == 0) { + type = &G_STRUCT (pr, qfot_type_t, typeptr); + if (type->meta == ty_basic) { return type->t.type; } return ev_void; diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 0dba5c6dc..65271b289 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -278,7 +278,6 @@ dump_functions (progs_t *pr) continue; } for (j = 0; j < (int)aux->num_locals; j++) { - local_defs[j].type_encoding += type_encodings;//FIXME do in debug dump_def (pr, local_defs + j, 1); } } From 66dd3ef0704bf15f8465277cd560c5db961608ef Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 21:23:13 +0900 Subject: [PATCH 088/444] Make a bunch of count things positive-only This fixes a pile of FIXMEs, because some things should never be negative. --- include/QF/pr_comp.h | 8 ++++---- libs/gamecode/pr_builtins.c | 3 ++- libs/gamecode/pr_debug.c | 17 +++++++++-------- libs/gamecode/pr_load.c | 2 +- tools/qfcc/source/dump_globals.c | 15 ++++++++++----- tools/qfcc/source/qfprogs.c | 3 ++- 6 files changed, 28 insertions(+), 20 deletions(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 8c03a7981..60022098f 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -27,7 +27,7 @@ typedef int16_t pr_short_t; typedef uint16_t pr_ushort_t; typedef int32_t pr_int_t; typedef uint32_t pr_uint_t; -typedef pr_int_t func_t; +typedef pr_uint_t func_t; typedef pr_int_t string_t; typedef pr_uint_t pointer_t; @@ -455,7 +455,7 @@ typedef struct dfunction_s { pr_int_t parm_start; pr_uint_t locals; // total ints of parms + locals - pr_int_t profile; // runtime + pr_uint_t profile; // runtime string_t s_name; pr_int_t s_file; // source file defined in @@ -502,10 +502,10 @@ typedef struct dprograms_s { pr_uint_t numfielddefs; pr_uint_t ofs_functions; - pr_int_t numfunctions; // function 0 is an empty + pr_uint_t numfunctions; // function 0 is an empty pr_uint_t ofs_strings; - pr_int_t numstrings; // first string is a null string + pr_uint_t numstrings; // first string is a null string pr_uint_t ofs_globals; pr_uint_t numglobals; diff --git a/libs/gamecode/pr_builtins.c b/libs/gamecode/pr_builtins.c index a3ab8c9d9..12c2e6050 100644 --- a/libs/gamecode/pr_builtins.c +++ b/libs/gamecode/pr_builtins.c @@ -158,7 +158,8 @@ bi_no_function (progs_t *pr) VISIBLE int PR_RelocateBuiltins (progs_t *pr) { - pr_int_t i, ind; + pr_uint_t i; + pr_int_t ind; int bad = 0; dfunction_t *desc; bfunction_t *func; diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index e9bc860a9..9fd61b020 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -483,7 +483,7 @@ PR_LoadDebug (progs_t *pr) i = pr->progs->numfunctions * sizeof (pr_auxfunction_t *); res->auxfunction_map = pr->allocate_progs_mem (pr, i); - for (i = 0; (int) i < pr->progs->numfunctions; i++) //FIXME (cast) + for (i = 0; i < pr->progs->numfunctions; i++) res->auxfunction_map[i] = 0; for (i = 0; i < res->debug->num_auxfunctions; i++) { @@ -539,7 +539,7 @@ VISIBLE pr_auxfunction_t * PR_Debug_MappedAuxFunction (progs_t *pr, pr_uint_t func) { prdeb_resources_t *res = pr->pr_debug_resources; - if (!res->debug || (int)func >= pr->progs->numfunctions) {//FIXME (cast) + if (!res->debug || func >= pr->progs->numfunctions) { return 0; } return res->auxfunction_map[func]; @@ -1046,7 +1046,7 @@ pr_debug_func_view (qfot_type_t *type, pr_type_t *value, void *_data) progs_t *pr = data->pr; dstring_t *dstr = data->dstr; - if (value->func_var < 0 || value->func_var >= pr->progs->numfunctions) { + if (value->func_var >= pr->progs->numfunctions) { dasprintf (dstr, "INVALID:%d", value->func_var); } else if (!value->func_var) { dstring_appendstr (dstr, "NULL"); @@ -1300,6 +1300,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) unsigned parm_ind = 0; pr_int_t opval; etype_t optype = ev_void; + func_t func; if (mode == 'P') { opchar = fmt[3]; @@ -1343,10 +1344,10 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) case 'F': str = global_string (&data, opval, optype, contents & 1); - if (G_FUNCTION (pr, opval) >= 0 - && G_FUNCTION (pr, opval) - < pr->progs->numfunctions) - call_func = pr->pr_functions + G_FUNCTION (pr, opval); + func = G_FUNCTION (pr, opval); + if (func < pr->progs->numfunctions) { + call_func = pr->pr_functions + func; + } break; case 'P': parm_def = PR_Get_Param_Def (pr, call_func, parm_ind); @@ -1468,7 +1469,7 @@ PR_StackTrace (progs_t *pr) VISIBLE void PR_Profile (progs_t * pr) { - pr_int_t max, num, i; + pr_uint_t max, num, i; dfunction_t *best, *f; num = 0; diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index 51723cd64..c8157efa8 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -370,7 +370,7 @@ PR_AddLoadFinishFunc (progs_t *pr, int (*func)(progs_t *)) static int pr_run_ctors (progs_t *pr) { - pr_int_t fnum; + pr_uint_t fnum; dfunction_t *func; for (fnum = 0; fnum < pr->progs->numfunctions; fnum++) { diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 65271b289..9343a0ac7 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -86,7 +86,12 @@ dump_def (progs_t *pr, pr_def_t *def, int indent) break; case ev_string: string = G_INT (pr, offset); - if (string < 0 || string >= pr->progs->numstrings) { + // at runtime, strings can be negative (thus string_t is + // signed), but negative strings means they have been + // dynamically allocated, thus a negative string index should + // never appear in compiled code + if (string < 0 + || (pr_uint_t) string >= pr->progs->numstrings) { str = "invalid string offset"; comment = va (" %d %s", string, str); } else { @@ -115,7 +120,7 @@ dump_def (progs_t *pr, pr_def_t *def, int indent) { func_t func = G_FUNCTION (pr, offset); int start; - if (func >= 0 && func < pr->progs->numfunctions) { + if (func < pr->progs->numfunctions) { start = pr->pr_functions[func].first_statement; if (start > 0) comment = va (" %d @ %x", func, start); @@ -230,9 +235,9 @@ qfo_fields (qfo_t *qfo) void dump_functions (progs_t *pr) { - int i, j; + pr_uint_t i, j, count; const char *name; - int start, count; + int start; const char *comment; pr_def_t *encodings_def; pointer_t type_encodings = 0; @@ -277,7 +282,7 @@ dump_functions (progs_t *pr) if (!local_defs) { continue; } - for (j = 0; j < (int)aux->num_locals; j++) { + for (j = 0; j < aux->num_locals; j++) { dump_def (pr, local_defs + j, 1); } } diff --git a/tools/qfcc/source/qfprogs.c b/tools/qfcc/source/qfprogs.c index 37acd11fc..02f05bce9 100644 --- a/tools/qfcc/source/qfprogs.c +++ b/tools/qfcc/source/qfprogs.c @@ -255,7 +255,8 @@ static int load_progs (const char *name) { QFile *file; - int i, size; + int size; + pr_uint_t i; char buff[5]; Hash_FlushTable (func_tab); From 3577d27a45815a53c9f5b0dc0b5db2bdcb45efd1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 25 Feb 2020 23:14:18 +0900 Subject: [PATCH 089/444] Move the ObjQC data into a resource block This makes it nice and private (though with the cached pointer, ObjQC is still a first-class component). --- include/QF/progs.h | 15 +- libs/ruamoko/rua_obj.c | 488 ++++++++++++++++++++++++----------------- 2 files changed, 288 insertions(+), 215 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index ebfa0a3fd..369360449 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1636,8 +1636,6 @@ typedef struct { strref_t *tstr; ///< Linked list of temporary strings. } prstack_t; -struct obj_list_s; - struct progs_s { int (*parse_field) (progs_t *pr, const char *key, const char *value); @@ -1772,18 +1770,7 @@ struct progs_s { /// \name obj info ///@{ - unsigned selector_index; - unsigned selector_index_max; - struct obj_list_s **selector_sels; - string_t *selector_names; - struct hashtab_s *selector_hash; - struct hashtab_s *classes; - struct hashtab_s *load_methods; - struct obj_list_s *unresolved_classes; - struct obj_list_s *unclaimed_categories; - struct obj_list_s *unclaimed_proto_list; - struct obj_list_s *module_list; - struct obj_list_s *class_tree_list; + struct probj_resources_s *pr_objective_resources; ///@} /// \name debugging diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index f44da87a9..93fe8a68b 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -61,6 +61,22 @@ typedef struct obj_list_s { void *data; } obj_list; +typedef struct probj_resources_s { + progs_t *pr; + unsigned selector_index; + unsigned selector_index_max; + obj_list **selector_sels; + string_t *selector_names; + hashtab_t *selector_hash; + hashtab_t *classes; + hashtab_t *load_methods; + obj_list *unresolved_classes; + obj_list *unclaimed_categories; + obj_list *unclaimed_proto_list; + obj_list *module_list; + obj_list *class_tree_list; +} probj_t; + static obj_list *obj_list_free_list; static obj_list * @@ -144,7 +160,7 @@ class_tree_new (void) } static int -class_is_subclass_of_class (progs_t *pr, pr_class_t *class, +class_is_subclass_of_class (probj_t *probj, pr_class_t *class, pr_class_t *superclass) { while (class) { @@ -152,20 +168,22 @@ class_is_subclass_of_class (progs_t *pr, pr_class_t *class, return 1; if (!class->super_class) break; - class = Hash_Find (pr->classes, PR_GetString (pr, class->super_class)); + class = Hash_Find (probj->classes, + PR_GetString (probj->pr, class->super_class)); } return 0; } static class_tree * -create_tree_of_subclasses_inherited_from (progs_t *pr, pr_class_t *bottom, +create_tree_of_subclasses_inherited_from (probj_t *probj, pr_class_t *bottom, pr_class_t *upper) { + progs_t *pr = probj->pr; const char *super_class = PR_GetString (pr, bottom->super_class); pr_class_t *superclass; class_tree *tree, *prev; - superclass = bottom->super_class ? Hash_Find (pr->classes, super_class) + superclass = bottom->super_class ? Hash_Find (probj->classes, super_class) : 0; tree = prev = class_tree_new (); prev->class = bottom; @@ -174,7 +192,7 @@ create_tree_of_subclasses_inherited_from (progs_t *pr, pr_class_t *bottom, tree->class = superclass; tree->subclasses = list_cons (prev, tree->subclasses); super_class = PR_GetString (pr, superclass->super_class); - superclass = (superclass->super_class ? Hash_Find (pr->classes, + superclass = (superclass->super_class ? Hash_Find (probj->classes, super_class) : 0); prev = tree; @@ -183,16 +201,17 @@ create_tree_of_subclasses_inherited_from (progs_t *pr, pr_class_t *bottom, } static class_tree * -_obj_tree_insert_class (progs_t *pr, class_tree *tree, pr_class_t *class) +_obj_tree_insert_class (probj_t *probj, class_tree *tree, pr_class_t *class) { + progs_t *pr = probj->pr; obj_list *subclasses; class_tree *new_tree; if (!tree) - return create_tree_of_subclasses_inherited_from (pr, class, 0); + return create_tree_of_subclasses_inherited_from (probj, class, 0); if (class == tree->class) return tree; - if ((class->super_class ? Hash_Find (pr->classes, + if ((class->super_class ? Hash_Find (probj->classes, PR_GetString (pr, class->super_class)) : 0) == tree->class) { @@ -209,32 +228,32 @@ _obj_tree_insert_class (progs_t *pr, class_tree *tree, pr_class_t *class) tree->subclasses = list_cons (node, tree->subclasses); return tree; } - if (!class_is_subclass_of_class (pr, class, tree->class)) + if (!class_is_subclass_of_class (probj, class, tree->class)) return 0; for (subclasses = tree->subclasses; subclasses; subclasses = subclasses->next) { pr_class_t *aclass = ((class_tree *)subclasses->data)->class; - if (class_is_subclass_of_class (pr, class, aclass)) { - subclasses->data = _obj_tree_insert_class (pr, subclasses->data, + if (class_is_subclass_of_class (probj, class, aclass)) { + subclasses->data = _obj_tree_insert_class (probj, subclasses->data, class); return tree; } } - new_tree = create_tree_of_subclasses_inherited_from (pr, class, + new_tree = create_tree_of_subclasses_inherited_from (probj, class, tree->class); tree->subclasses = list_cons (new_tree, tree->subclasses); return tree; } static void -obj_tree_insert_class (progs_t *pr, pr_class_t *class) +obj_tree_insert_class (probj_t *probj, pr_class_t *class) { obj_list *list_node; class_tree *tree; - list_node = pr->class_tree_list; + list_node = probj->class_tree_list; while (list_node) { - tree = _obj_tree_insert_class (pr, list_node->data, class); + tree = _obj_tree_insert_class (probj, list_node->data, class); if (tree) { list_node->data = tree; break; @@ -243,73 +262,75 @@ obj_tree_insert_class (progs_t *pr, pr_class_t *class) } } if (!list_node) { - tree = _obj_tree_insert_class (pr, 0, class); - pr->class_tree_list = list_cons (tree, pr->class_tree_list); + tree = _obj_tree_insert_class (probj, 0, class); + probj->class_tree_list = list_cons (tree, probj->class_tree_list); } } static void -obj_create_classes_tree (progs_t *pr, pr_module_t *module) +obj_create_classes_tree (probj_t *probj, pr_module_t *module) { + progs_t *pr = probj->pr; pr_symtab_t *symtab = &G_STRUCT (pr, pr_symtab_t, module->symtab); int i; for (i = 0; i < symtab->cls_def_cnt; i++) { pr_class_t *class = &G_STRUCT (pr, pr_class_t, symtab->defs[i]); - obj_tree_insert_class (pr, class); + obj_tree_insert_class (probj, class); } } static void -obj_destroy_class_tree_node (progs_t *pr, class_tree *tree, int level) +obj_destroy_class_tree_node (probj_t *probj, class_tree *tree, int level) { tree->subclasses = (obj_list *) class_tree_free_list; class_tree_free_list = tree; } static void -obj_preorder_traverse (progs_t *pr, class_tree *tree, int level, - void (*func) (progs_t *, class_tree *, int)) +obj_preorder_traverse (probj_t *probj, class_tree *tree, int level, + void (*func) (probj_t *, class_tree *, int)) { obj_list *node; - func (pr, tree, level); + func (probj, tree, level); for (node = tree->subclasses; node; node = node->next) - obj_preorder_traverse (pr, node->data, level + 1, func); + obj_preorder_traverse (probj, node->data, level + 1, func); } static void -obj_postorder_traverse (progs_t *pr, class_tree *tree, int level, - void (*func) (progs_t *, class_tree *, int)) +obj_postorder_traverse (probj_t *probj, class_tree *tree, int level, + void (*func) (probj_t *, class_tree *, int)) { obj_list *node; for (node = tree->subclasses; node; node = node->next) - obj_postorder_traverse (pr, node->data, level + 1, func); - func (pr, tree, level); + obj_postorder_traverse (probj, node->data, level + 1, func); + func (probj, tree, level); } static const char * -selector_get_key (const void *s, void *_pr) +selector_get_key (const void *s, void *_probj) { - progs_t *pr = (progs_t *) _pr; - return PR_GetString (pr, pr->selector_names[(intptr_t) s]); + __auto_type probj = (probj_t *) _probj; + return PR_GetString (probj->pr, probj->selector_names[(intptr_t) s]); } static const char * -class_get_key (const void *c, void *pr) +class_get_key (const void *c, void *_probj) { - return PR_GetString ((progs_t *)pr, ((pr_class_t *)c)->name); + __auto_type probj = (probj_t *) _probj; + return PR_GetString (probj->pr, ((pr_class_t *)c)->name); } static uintptr_t -load_methods_get_hash (const void *m, void *pr) +load_methods_get_hash (const void *m, void *_probj) { return (uintptr_t) m; } static int -load_methods_compare (const void *m1, const void *m2, void *pr) +load_methods_compare (const void *m1, const void *m2, void *_probj) { return m1 == m2; } @@ -323,8 +344,9 @@ sel_eq (pr_sel_t *s1, pr_sel_t *s2) } static int -object_is_instance (progs_t *pr, pr_id_t *object) +object_is_instance (probj_t *probj, pr_id_t *object) { + progs_t *pr = probj->pr; pr_class_t *class; if (object) { @@ -335,8 +357,9 @@ object_is_instance (progs_t *pr, pr_id_t *object) } static string_t -object_get_class_name (progs_t *pr, pr_id_t *object) +object_get_class_name (probj_t *probj, pr_id_t *object) { + progs_t *pr = probj->pr; pr_class_t *class; if (object) { @@ -356,8 +379,9 @@ object_get_class_name (progs_t *pr, pr_id_t *object) //==================================================================== static void -finish_class (progs_t *pr, pr_class_t *class, pointer_t object_ptr) +finish_class (probj_t *probj, pr_class_t *class, pointer_t object_ptr) { + progs_t *pr = probj->pr; pr_class_t *meta = &G_STRUCT (pr, pr_class_t, class->class_pointer); pr_class_t *val; @@ -365,7 +389,7 @@ finish_class (progs_t *pr, pr_class_t *class, pointer_t object_ptr) if (class->super_class) { const char *super_class = PR_GetString (pr, class->super_class); const char *class_name = PR_GetString (pr, class->name); - val = Hash_Find (pr->classes, super_class); + val = Hash_Find (probj->classes, super_class); if (!val) PR_Error (pr, "broken class %s: super class %s not found", class_name, super_class); @@ -384,39 +408,40 @@ finish_class (progs_t *pr, pr_class_t *class, pointer_t object_ptr) //==================================================================== static int -add_sel_name (progs_t *pr, const char *name) +add_sel_name (probj_t *probj, const char *name) { - int ind = ++pr->selector_index; + int ind = ++probj->selector_index; int size, i; - if (pr->selector_index >= pr->selector_index_max) { - size = pr->selector_index_max + 128; - pr->selector_sels = realloc (pr->selector_sels, - size * sizeof (obj_list *)); - pr->selector_names = realloc (pr->selector_names, - size * sizeof (string_t)); - for (i = pr->selector_index_max; i < size; i++) { - pr->selector_sels[i] = 0; - pr->selector_names[i] = 0; + if (probj->selector_index >= probj->selector_index_max) { + size = probj->selector_index_max + 128; + probj->selector_sels = realloc (probj->selector_sels, + size * sizeof (obj_list *)); + probj->selector_names = realloc (probj->selector_names, + size * sizeof (string_t)); + for (i = probj->selector_index_max; i < size; i++) { + probj->selector_sels[i] = 0; + probj->selector_names[i] = 0; } - pr->selector_index_max = size; + probj->selector_index_max = size; } - pr->selector_names[ind] = PR_SetString (pr, name); + probj->selector_names[ind] = PR_SetString (probj->pr, name); return ind; } static pr_sel_t * -sel_register_typed_name (progs_t *pr, const char *name, const char *types, +sel_register_typed_name (probj_t *probj, const char *name, const char *types, pr_sel_t *sel) { + progs_t *pr = probj->pr; intptr_t index; int is_new = 0; obj_list *l; Sys_MaskPrintf (SYS_RUA_OBJ, " Registering SEL %s %s\n", name, types); - index = (intptr_t) Hash_Find (pr->selector_hash, name); + index = (intptr_t) Hash_Find (probj->selector_hash, name); if (index) { - for (l = pr->selector_sels[index]; l; l = l->next) { + for (l = probj->selector_sels[index]; l; l = l->next) { pr_sel_t *s = l->data; if (!types || !s->sel_types) { if (!s->sel_types && !types) { @@ -435,7 +460,7 @@ sel_register_typed_name (progs_t *pr, const char *name, const char *types, } } } else { - index = add_sel_name (pr, name); + index = add_sel_name (probj, name); is_new = 1; } if (!sel) @@ -446,11 +471,11 @@ sel_register_typed_name (progs_t *pr, const char *name, const char *types, l = obj_list_new (); l->data = sel; - l->next = pr->selector_sels[index]; - pr->selector_sels[index] = l; + l->next = probj->selector_sels[index]; + probj->selector_sels[index] = l; if (is_new) - Hash_Add (pr->selector_hash, (void *) index); + Hash_Add (probj->selector_hash, (void *) index); done: Sys_MaskPrintf (SYS_RUA_OBJ, " %d @ %x\n", sel->sel_id, PR_SetPointer (pr, sel)); @@ -458,40 +483,43 @@ done: } static pr_sel_t * -sel_register_name (progs_t *pr, const char *name) +sel_register_name (probj_t *probj, const char *name) { - return sel_register_typed_name (pr, name, "", 0); + return sel_register_typed_name (probj, name, "", 0); } static void -register_selectors_from_list (progs_t *pr, pr_method_list_t *method_list) +register_selectors_from_list (probj_t *probj, pr_method_list_t *method_list) { + progs_t *pr = probj->pr; int i; for (i = 0; i < method_list->method_count; i++) { pr_method_t *method = &method_list->method_list[i]; const char *name = PR_GetString (pr, method->method_name); const char *types = PR_GetString (pr, method->method_types); - pr_sel_t *sel = sel_register_typed_name (pr, name, types, 0); + pr_sel_t *sel = sel_register_typed_name (probj, name, types, 0); method->method_name = PR_SetPointer (pr, sel); } } static void -obj_register_selectors_from_class (progs_t *pr, pr_class_t *class) +obj_register_selectors_from_class (probj_t *probj, pr_class_t *class) { + progs_t *pr = probj->pr; pr_method_list_t *method_list = &G_STRUCT (pr, pr_method_list_t, class->methods); while (method_list) { - register_selectors_from_list (pr, method_list); + register_selectors_from_list (probj, method_list); method_list = &G_STRUCT (pr, pr_method_list_t, method_list->method_next); } } static void -obj_init_protocols (progs_t *pr, pr_protocol_list_t *protos) +obj_init_protocols (probj_t *probj, pr_protocol_list_t *protos) { + progs_t *pr = probj->pr; pr_class_t *proto_class; pr_protocol_t *proto; int i; @@ -499,9 +527,9 @@ obj_init_protocols (progs_t *pr, pr_protocol_list_t *protos) if (!protos) return; - if (!(proto_class = Hash_Find (pr->classes, "Protocol"))) { - pr->unclaimed_proto_list = list_cons (protos, - pr->unclaimed_proto_list); + if (!(proto_class = Hash_Find (probj->classes, "Protocol"))) { + probj->unclaimed_proto_list = list_cons (protos, + probj->unclaimed_proto_list); return; } @@ -509,8 +537,8 @@ obj_init_protocols (progs_t *pr, pr_protocol_list_t *protos) proto = &G_STRUCT (pr, pr_protocol_t, protos->list[i]); if (!proto->class_pointer) { proto->class_pointer = PR_SetPointer (pr, proto_class); - obj_init_protocols (pr, &G_STRUCT (pr, pr_protocol_list_t, - proto->protocol_list)); + obj_init_protocols (probj, &G_STRUCT (pr, pr_protocol_list_t, + proto->protocol_list)); } else { if (proto->class_pointer != PR_SetPointer (pr, proto_class)) PR_RunError (pr, "protocol broken"); @@ -519,8 +547,10 @@ obj_init_protocols (progs_t *pr, pr_protocol_list_t *protos) } static void -class_add_method_list (progs_t *pr, pr_class_t *class, pr_method_list_t *list) +class_add_method_list (probj_t *probj, pr_class_t *class, + pr_method_list_t *list) { + progs_t *pr = probj->pr; int i; for (i = 0; i < list->method_count; i++) { @@ -528,7 +558,7 @@ class_add_method_list (progs_t *pr, pr_class_t *class, pr_method_list_t *list) if (method->method_name) { const char *name = PR_GetString (pr, method->method_name); const char *types = PR_GetString (pr, method->method_types); - pr_sel_t *sel = sel_register_typed_name (pr, name, types, 0); + pr_sel_t *sel = sel_register_typed_name (probj, name, types, 0); method->method_name = PR_SetPointer (pr, sel); } } @@ -538,7 +568,7 @@ class_add_method_list (progs_t *pr, pr_class_t *class, pr_method_list_t *list) } static void -obj_class_add_protocols (progs_t *pr, pr_class_t *class, +obj_class_add_protocols (probj_t *probj, pr_class_t *class, pr_protocol_list_t *protos) { if (!protos) @@ -549,50 +579,54 @@ obj_class_add_protocols (progs_t *pr, pr_class_t *class, } static void -finish_category (progs_t *pr, pr_category_t *category, pr_class_t *class) +finish_category (probj_t *probj, pr_category_t *category, pr_class_t *class) { + progs_t *pr = probj->pr; pr_method_list_t *method_list; pr_protocol_list_t *protocol_list; if (category->instance_methods) { method_list = &G_STRUCT (pr, pr_method_list_t, category->instance_methods); - class_add_method_list (pr, class, method_list); + class_add_method_list (probj, class, method_list); } if (category->class_methods) { pr_class_t *meta = &G_STRUCT (pr, pr_class_t, class->class_pointer); method_list = &G_STRUCT (pr, pr_method_list_t, category->class_methods); - class_add_method_list (pr, meta, method_list); + class_add_method_list (probj, meta, method_list); } if (category->protocols) { protocol_list = &G_STRUCT (pr, pr_protocol_list_t, category->protocols); - obj_init_protocols (pr, protocol_list); - obj_class_add_protocols (pr, class, protocol_list); + obj_init_protocols (probj, protocol_list); + obj_class_add_protocols (probj, class, protocol_list); } } static void -obj_send_message_in_list (progs_t *pr, pr_method_list_t *method_list, +obj_send_message_in_list (probj_t *probj, pr_method_list_t *method_list, pr_class_t *class, pr_sel_t *op) { + progs_t *pr = probj->pr; int i; if (!method_list) return; - obj_send_message_in_list (pr, &G_STRUCT (pr, pr_method_list_t, - method_list->method_next), + obj_send_message_in_list (probj, &G_STRUCT (pr, pr_method_list_t, + method_list->method_next), class, op); for (i = 0; i < method_list->method_count; i++) { pr_method_t *mth = &method_list->method_list[i]; if (mth->method_name && sel_eq (&G_STRUCT (pr, pr_sel_t, mth->method_name), op) - && !Hash_FindElement (pr->load_methods, (void *) (intptr_t) mth->method_imp)) { - Hash_AddElement (pr->load_methods, (void *) (intptr_t) mth->method_imp); - + && !Hash_FindElement (probj->load_methods, + (void *) (intptr_t) mth->method_imp)) { + Hash_AddElement (probj->load_methods, + (void *) (intptr_t) mth->method_imp); + //FIXME need to wrap in save/restore params? PR_ExecuteProgram (pr, mth->method_imp); break; } @@ -600,58 +634,62 @@ obj_send_message_in_list (progs_t *pr, pr_method_list_t *method_list, } static void -send_load (progs_t *pr, class_tree *tree, int level) +send_load (probj_t *probj, class_tree *tree, int level) { - pr_sel_t *load_sel = sel_register_name (pr, "load"); + progs_t *pr = probj->pr; + pr_sel_t *load_sel = sel_register_name (probj, "load"); pr_class_t *class = tree->class; pr_class_t *meta = &G_STRUCT (pr, pr_class_t, class->class_pointer); pr_method_list_t *method_list = &G_STRUCT (pr, pr_method_list_t, meta->methods); - obj_send_message_in_list (pr, method_list, class, load_sel); + obj_send_message_in_list (probj, method_list, class, load_sel); } static void -obj_send_load (progs_t *pr) +obj_send_load (probj_t *probj) { + progs_t *pr = probj->pr; obj_list *m; - if (pr->unresolved_classes) { - pr_class_t *class = pr->unresolved_classes->data; + if (probj->unresolved_classes) { + pr_class_t *class = probj->unresolved_classes->data; const char *super_class = PR_GetString (pr, class->super_class); - while (Hash_Find (pr->classes, super_class)) { - list_remove (&pr->unresolved_classes); - if (pr->unresolved_classes) { - class = pr->unresolved_classes->data; + while (Hash_Find (probj->classes, super_class)) { + list_remove (&probj->unresolved_classes); + if (probj->unresolved_classes) { + class = probj->unresolved_classes->data; super_class = PR_GetString (pr, class->super_class); } else { break; } } - if (pr->unresolved_classes) + if (probj->unresolved_classes) return; } //XXX constant string stuff here (see init.c in libobjc source) - for (m = pr->module_list; m; m = m->next) - obj_create_classes_tree (pr, m->data); - while (pr->class_tree_list) { - obj_preorder_traverse (pr, pr->class_tree_list->data, 0, send_load); - obj_postorder_traverse (pr, pr->class_tree_list->data, 0, + for (m = probj->module_list; m; m = m->next) + obj_create_classes_tree (probj, m->data); + while (probj->class_tree_list) { + obj_preorder_traverse (probj, probj->class_tree_list->data, 0, + send_load); + obj_postorder_traverse (probj, probj->class_tree_list->data, 0, obj_destroy_class_tree_node); - list_remove (&pr->class_tree_list); + list_remove (&probj->class_tree_list); } //XXX callback - //for (m = pr->module_list; m; m = m->next) - // obj_create_classes_tree (pr, m->data); - obj_list_free (pr->module_list); - pr->module_list = 0; + //for (m = probj->module_list; m; m = m->next) + // obj_create_classes_tree (probj, m->data); + obj_list_free (probj->module_list); + probj->module_list = 0; } static pr_method_t * -obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) +obj_find_message (probj_t *probj, pr_class_t *class, pr_sel_t *selector) { + progs_t *pr = probj->pr; pr_class_t *c = class; pr_method_list_t *method_list; pr_method_t *method; @@ -661,7 +699,7 @@ obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) string_t *names; if (dev & SYS_RUA_MSG) { - names = pr->selector_names; + names = probj->selector_names; Sys_Printf ("Searching for %s\n", PR_GetString (pr, names[selector->sel_id])); } @@ -680,13 +718,13 @@ obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) i < method_list->method_count; i++, method++) { sel = &G_STRUCT (pr, pr_sel_t, method->method_name); if (developer->int_val & SYS_RUA_MSG) { - names = pr->selector_names; + names = probj->selector_names; Sys_Printf (" %s\n", PR_GetString (pr, names[sel->sel_id])); } if (sel->sel_id == selector->sel_id) { if (dev & SYS_RUA_MSG) { - names = pr->selector_names; + names = probj->selector_names; Sys_Printf ("found %s: %x\n", PR_GetString (pr, names[selector->sel_id]), method->method_imp); @@ -703,13 +741,14 @@ obj_find_message (progs_t *pr, pr_class_t *class, pr_sel_t *selector) } static void -obj_send_initialize (progs_t *pr, pr_class_t *class) +obj_send_initialize (probj_t *probj, pr_class_t *class) { + progs_t *pr = probj->pr; pr_method_list_t *method_list; pr_method_t *method; pr_sel_t *sel; pr_class_t *class_pointer; - pr_sel_t *selector = sel_register_name (pr, "initialize"); + pr_sel_t *selector = sel_register_name (probj, "initialize"); int i; if (PR_CLS_ISINITIALIZED (class)) @@ -718,8 +757,8 @@ obj_send_initialize (progs_t *pr, pr_class_t *class) PR_CLS_SETINITIALIZED (class); PR_CLS_SETINITIALIZED (class_pointer); if (class->super_class) - obj_send_initialize (pr, &G_STRUCT (pr, pr_class_t, - class->super_class)); + obj_send_initialize (probj, &G_STRUCT (pr, pr_class_t, + class->super_class)); method_list = &G_STRUCT (pr, pr_method_list_t, class_pointer->methods); while (method_list) { @@ -744,47 +783,50 @@ obj_send_initialize (progs_t *pr, pr_class_t *class) } static func_t -get_imp (progs_t *pr, pr_class_t *class, pr_sel_t *sel) +get_imp (probj_t *probj, pr_class_t *class, pr_sel_t *sel) { - pr_method_t *method = obj_find_message (pr, class, sel); + pr_method_t *method = obj_find_message (probj, class, sel); return method ? method->method_imp : 0; } static func_t -obj_msg_lookup (progs_t *pr, pr_id_t *receiver, pr_sel_t *op) +obj_msg_lookup (probj_t *probj, pr_id_t *receiver, pr_sel_t *op) { + progs_t *pr = probj->pr; pr_class_t *class; if (!receiver) return 0; class = &G_STRUCT (pr, pr_class_t, receiver->class_pointer); if (PR_CLS_ISCLASS (class)) { if (!PR_CLS_ISINITIALIZED (class)) - obj_send_initialize (pr, class); + obj_send_initialize (probj, class); } else if (PR_CLS_ISMETA (class) && PR_CLS_ISCLASS ((pr_class_t *) receiver)) { if (!PR_CLS_ISINITIALIZED ((pr_class_t *) receiver)) - obj_send_initialize (pr, (pr_class_t *) receiver); + obj_send_initialize (probj, (pr_class_t *) receiver); } - return get_imp (pr, class, op); + return get_imp (probj, class, op); } static func_t -obj_msg_lookup_super (progs_t *pr, pr_super_t *super, pr_sel_t *op) +obj_msg_lookup_super (probj_t *probj, pr_super_t *super, pr_sel_t *op) { + progs_t *pr = probj->pr; pr_class_t *class; if (!super->self) return 0; class = &G_STRUCT (pr, pr_class_t, super->class); - return get_imp (pr, class, op); + return get_imp (probj, class, op); } static void -obj_verror (progs_t *pr, pr_id_t *object, int code, const char *fmt, int count, +obj_verror (probj_t *probj, pr_id_t *object, int code, const char *fmt, int count, pr_type_t **args) { + progs_t *pr = probj->pr; dstring_t *dstr = dstring_newstr (); PR_Sprintf (pr, dstr, "obj_verror", fmt, count, args); @@ -792,8 +834,9 @@ obj_verror (progs_t *pr, pr_id_t *object, int code, const char *fmt, int count, } static void -dump_ivars (progs_t *pr, pointer_t _ivars) +dump_ivars (probj_t *probj, pointer_t _ivars) { + progs_t *pr = probj->pr; pr_ivar_list_t *ivars; int i; @@ -811,6 +854,7 @@ dump_ivars (progs_t *pr, pointer_t _ivars) static void rua___obj_exec_class (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_module_t *module = &P_STRUCT (pr, pr_module_t, 0); pr_symtab_t *symtab; pr_sel_t *sel; @@ -833,14 +877,14 @@ rua___obj_exec_class (progs_t *pr) symtab->cat_def_cnt, symtab->cat_def_cnt == 1 ? "y" : "ies"); - pr->module_list = list_cons (module, pr->module_list); + probj->module_list = list_cons (module, probj->module_list); sel = &G_STRUCT (pr, pr_sel_t, symtab->refs); for (i = 0; i < symtab->sel_ref_cnt; i++) { const char *name, *types; name = PR_GetString (pr, sel->sel_id); types = PR_GetString (pr, sel->sel_types); - sel_register_typed_name (pr, name, types, sel); + sel_register_typed_name (probj, name, types, sel); sel++; } @@ -860,7 +904,7 @@ rua___obj_exec_class (progs_t *pr) class->instance_size, class->ivars); if (developer->int_val & SYS_RUA_OBJ) - dump_ivars (pr, class->ivars); + dump_ivars (probj, class->ivars); Sys_MaskPrintf (SYS_RUA_OBJ, " instance methods: %x\n", class->methods); Sys_MaskPrintf (SYS_RUA_OBJ, " protocols: %x\n", class->protocols); @@ -870,30 +914,31 @@ rua___obj_exec_class (progs_t *pr) meta->instance_size, meta->ivars); if (developer->int_val & SYS_RUA_OBJ) - dump_ivars (pr, meta->ivars); + dump_ivars (probj, meta->ivars); class->subclass_list = 0; - Hash_Add (pr->classes, class); + Hash_Add (probj->classes, class); - obj_register_selectors_from_class (pr, class); - obj_register_selectors_from_class (pr, meta); + obj_register_selectors_from_class (probj, class); + obj_register_selectors_from_class (probj, meta); if (class->protocols) { pr_protocol_list_t *protocol_list; protocol_list = &G_STRUCT (pr, pr_protocol_list_t, class->protocols); - obj_init_protocols (pr, protocol_list); + obj_init_protocols (probj, protocol_list); } - if (class->super_class && !Hash_Find (pr->classes, super_class)) - pr->unresolved_classes = list_cons (class, pr->unresolved_classes); + if (class->super_class && !Hash_Find (probj->classes, super_class)) + probj->unresolved_classes = list_cons (class, + probj->unresolved_classes); } for (i = 0; i < symtab->cat_def_cnt; i++, ptr++) { pr_category_t *category = &G_STRUCT (pr, pr_category_t, *ptr); const char *class_name = PR_GetString (pr, category->class_name); - pr_class_t *class = Hash_Find (pr->classes, class_name); + pr_class_t *class = Hash_Find (probj->classes, class_name); Sys_MaskPrintf (SYS_RUA_OBJ, "Category %s (%s) @ %x\n", PR_GetString (pr, category->class_name), @@ -906,36 +951,37 @@ rua___obj_exec_class (progs_t *pr) category->protocols); if (class) { - finish_category (pr, category, class); + finish_category (probj, category, class); } else { - pr->unclaimed_categories = list_cons (category, - pr->unclaimed_categories); + probj->unclaimed_categories + = list_cons (category, probj->unclaimed_categories); } } - for (cell = &pr->unclaimed_categories; *cell; ) { + for (cell = &probj->unclaimed_categories; *cell; ) { pr_category_t *category = (*cell)->data; const char *class_name = PR_GetString (pr, category->class_name); - pr_class_t *class = Hash_Find (pr->classes, class_name); + pr_class_t *class = Hash_Find (probj->classes, class_name); if (class) { list_remove (cell); - finish_category (pr, category, class); + finish_category (probj, category, class); } else { cell = &(*cell)->next; } } - if (pr->unclaimed_proto_list && Hash_Find (pr->classes, "Protocol")) { - for (cell = &pr->unclaimed_proto_list; *cell; ) { - obj_init_protocols (pr, (*cell)->data); + if (probj->unclaimed_proto_list + && Hash_Find (probj->classes, "Protocol")) { + for (cell = &probj->unclaimed_proto_list; *cell; ) { + obj_init_protocols (probj, (*cell)->data); list_remove (cell); } } Sys_MaskPrintf (SYS_RUA_OBJ, "Finished initializing %s module\n", PR_GetString (pr, module->name)); - obj_send_load (pr); + obj_send_load (probj); Sys_MaskPrintf (SYS_RUA_OBJ, "Leaving %s module init\n", PR_GetString (pr, module->name)); } @@ -943,18 +989,20 @@ rua___obj_exec_class (progs_t *pr) static void rua_obj_error (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); int code = P_INT (pr, 1); const char *fmt = P_GSTRING (pr, 2); int count = pr->pr_argc - 3; pr_type_t **args = &pr->pr_params[3]; - obj_verror (pr, object, code, fmt, count, args); + obj_verror (probj, object, code, fmt, count, args); } static void rua_obj_verror (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); int code = P_INT (pr, 1); const char *fmt = P_GSTRING (pr, 2); @@ -965,12 +1013,13 @@ rua_obj_verror (progs_t *pr) for (i = 0; i < val->count; i++) args[i] = params + i * pr->pr_param_size; - obj_verror (pr, object, code, fmt, val->count, args); + obj_verror (probj, object, code, fmt, val->count, args); } static void rua_obj_set_error_handler (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //func_t func = P_INT (pr, 0); //arglist //XXX @@ -980,38 +1029,41 @@ rua_obj_set_error_handler (progs_t *pr) static void rua_obj_msg_lookup (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *receiver = &P_STRUCT (pr, pr_id_t, 0); pr_sel_t *op = &P_STRUCT (pr, pr_sel_t, 1); - R_INT (pr) = obj_msg_lookup (pr, receiver, op); + R_INT (pr) = obj_msg_lookup (probj, receiver, op); } static void rua_obj_msg_lookup_super (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_super_t *super = &P_STRUCT (pr, pr_super_t, 0); pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); - R_INT (pr) = obj_msg_lookup_super (pr, super, _cmd); + R_INT (pr) = obj_msg_lookup_super (probj, super, _cmd); } static void rua_obj_msg_sendv (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *receiver = &P_STRUCT (pr, pr_id_t, 0); pr_sel_t *op = &P_STRUCT (pr, pr_sel_t, 1); pr_va_list_t *args = (pr_va_list_t *) &P_POINTER (pr, 2); pr_type_t *params = G_GPOINTER (pr, args->list); int count = args->count; - func_t imp = obj_msg_lookup (pr, receiver, op); + func_t imp = obj_msg_lookup (probj, receiver, op); count = bound (0, count, 6); if (count && pr_boundscheck->int_val) PR_BoundsCheckSize (pr, args->list, count * pr->pr_param_size); if (!imp) PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, receiver)), - PR_GetString (pr, pr->selector_names[op->sel_id])); + PR_GetString (pr, object_get_class_name (probj, receiver)), + PR_GetString (pr, probj->selector_names[op->sel_id])); if (count) memcpy (pr->pr_params[2], params, count * 4 * pr->pr_param_size); PR_CallFunction (pr, imp); @@ -1096,6 +1148,7 @@ rua_obj_free (progs_t *pr) static void rua_obj_get_uninstalled_dtable (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //XXX PR_RunError (pr, "%s, not implemented", __FUNCTION__); } @@ -1103,6 +1156,7 @@ rua_obj_get_uninstalled_dtable (progs_t *pr) static void rua_obj_msgSend (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *self = &P_STRUCT (pr, pr_id_t, 0); pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); func_t imp; @@ -1113,11 +1167,11 @@ rua_obj_msgSend (progs_t *pr) } if (!_cmd) PR_RunError (pr, "null selector"); - imp = obj_msg_lookup (pr, self, _cmd); + imp = obj_msg_lookup (probj, self, _cmd); if (!imp) PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, self)), - PR_GetString (pr, pr->selector_names[_cmd->sel_id])); + PR_GetString (pr, object_get_class_name (probj, self)), + PR_GetString (pr, probj->selector_names[_cmd->sel_id])); PR_CallFunction (pr, imp); } @@ -1125,16 +1179,17 @@ rua_obj_msgSend (progs_t *pr) static void rua_obj_msgSend_super (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_super_t *super = &P_STRUCT (pr, pr_super_t, 0); pr_sel_t *_cmd = &P_STRUCT (pr, pr_sel_t, 1); func_t imp; - imp = obj_msg_lookup_super (pr, super, _cmd); + imp = obj_msg_lookup_super (probj, super, _cmd); if (!imp) { pr_id_t *self = &G_STRUCT (pr, pr_id_t, super->self); PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, self)), - PR_GetString (pr, pr->selector_names[_cmd->sel_id])); + PR_GetString (pr, object_get_class_name (probj, self)), + PR_GetString (pr, probj->selector_names[_cmd->sel_id])); } pr->pr_params[0] = pr->pr_real_params[0]; P_POINTER (pr, 0) = super->self; @@ -1144,10 +1199,11 @@ rua_obj_msgSend_super (progs_t *pr) static void rua_obj_get_class (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); pr_class_t *class; - class = Hash_Find (pr->classes, name); + class = Hash_Find (probj->classes, name); if (!class) PR_RunError (pr, "could not find class %s", name); RETURN_POINTER (pr, class); @@ -1156,16 +1212,18 @@ rua_obj_get_class (progs_t *pr) static void rua_obj_lookup_class (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); pr_class_t *class; - class = Hash_Find (pr->classes, name); + class = Hash_Find (probj->classes, name); RETURN_POINTER (pr, class); } static void rua_obj_next_class (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //XXX PR_RunError (pr, "%s, not implemented", __FUNCTION__); } @@ -1175,10 +1233,11 @@ rua_obj_next_class (progs_t *pr) static void rua_sel_get_name (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 0); - if (sel->sel_id > 0 && sel->sel_id <= pr->selector_index) - R_STRING (pr) = pr->selector_names[sel->sel_id]; + if (sel->sel_id > 0 && sel->sel_id <= probj->selector_index) + R_STRING (pr) = probj->selector_names[sel->sel_id]; else R_STRING (pr) = 0; } @@ -1194,25 +1253,28 @@ rua_sel_get_type (progs_t *pr) static void rua_sel_get_uid (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); - RETURN_POINTER (pr, sel_register_typed_name (pr, name, "", 0)); + RETURN_POINTER (pr, sel_register_typed_name (probj, name, "", 0)); } static void rua_sel_register_name (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; const char *name = P_GSTRING (pr, 0); - RETURN_POINTER (pr, sel_register_typed_name (pr, name, "", 0)); + RETURN_POINTER (pr, sel_register_typed_name (probj, name, "", 0)); } static void rua_sel_is_mapped (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; // FIXME might correspond to a string pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 0); - R_INT (pr) = sel->sel_id > 0 && sel->sel_id <= pr->selector_index; + R_INT (pr) = sel->sel_id > 0 && sel->sel_id <= probj->selector_index; } //==================================================================== @@ -1220,20 +1282,22 @@ rua_sel_is_mapped (progs_t *pr) static void rua_class_get_class_method (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); pr_sel_t *aSel = &P_STRUCT (pr, pr_sel_t, 1); pr_method_t *method; class = &G_STRUCT (pr, pr_class_t, class->class_pointer); - method = obj_find_message (pr, class, aSel); + method = obj_find_message (probj, class, aSel); RETURN_POINTER (pr, method); } static void rua_class_get_instance_method (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); pr_sel_t *aSel = &P_STRUCT (pr, pr_sel_t, 1); - pr_method_t *method = obj_find_message (pr, class, aSel); + pr_method_t *method = obj_find_message (probj, class, aSel); RETURN_POINTER (pr, method); } @@ -1363,6 +1427,7 @@ rua_class_get_gc_object_type (progs_t *pr) static void rua_class_ivar_set_gcinvisible (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //pr_class_t *impostor = &P_STRUCT (pr, pr_class_t, 0); //const char *ivarname = P_GSTRING (pr, 1); //int gcInvisible = P_INT (pr, 2); @@ -1383,10 +1448,11 @@ rua_method_get_imp (progs_t *pr) static void rua_get_imp (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 1); - R_INT (pr) = get_imp (pr, class, sel); + R_INT (pr) = get_imp (probj, class, sel); } //==================================================================== @@ -1476,9 +1542,10 @@ rua_object_get_meta_class (progs_t *pr) static void rua_object_get_class_name (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); - R_STRING (pr) = object_get_class_name (pr, object); + R_STRING (pr) = object_get_class_name (probj, object); } static void @@ -1496,9 +1563,10 @@ rua_object_is_class (progs_t *pr) static void rua_object_is_instance (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); - R_INT (pr) = object_is_instance (pr, object); + R_INT (pr) = object_is_instance (probj, object); } static void @@ -1524,6 +1592,7 @@ rua__i_Object__hash (progs_t *pr) static void rua__i_Object_error_error_ (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *self = &P_STRUCT (pr, pr_id_t, 0); const char *fmt = P_GSTRING (pr, 2); dstring_t *dstr = dstring_new (); @@ -1531,14 +1600,15 @@ rua__i_Object_error_error_ (progs_t *pr) pr_type_t **args = &pr->pr_params[3]; dsprintf (dstr, "error: %s (%s)\n%s", - PR_GetString (pr, object_get_class_name (pr, self)), - object_is_instance (pr, self) ? "instance" : "class", fmt); - obj_verror (pr, self, 0, dstr->str, count, args); + PR_GetString (pr, object_get_class_name (probj, self)), + object_is_instance (probj, self) ? "instance" : "class", fmt); + obj_verror (probj, self, 0, dstr->str, count, args); } static void rua__c_Object__conformsToProtocol_ (progs_t *pr) { + //probj_t *probj = pr->pr_objective_resources; //pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); //pr_protocol_t *proto = &P_STRUCT (pr, pr_protocol_t, 2); //... @@ -1631,20 +1701,21 @@ static builtin_t obj_methods [] = { static int rua_init_finish (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_class_t **class_list, **class; - class_list = (pr_class_t **) Hash_GetList (pr->classes); + class_list = (pr_class_t **) Hash_GetList (probj->classes); if (*class_list) { pr_class_t *object_class; pointer_t object_ptr; - object_class = Hash_Find (pr->classes, "Object"); + object_class = Hash_Find (probj->classes, "Object"); if (object_class && !object_class->super_class) object_ptr = (pr_type_t *)object_class - pr->pr_globals; else PR_Error (pr, "root class Object not found"); for (class = class_list; *class; class++) - finish_class (pr, *class, object_ptr); + finish_class (probj, *class, object_ptr); } free (class_list); @@ -1652,40 +1723,42 @@ rua_init_finish (progs_t *pr) } static int -rua_init_runtime (progs_t *pr) +rua_obj_init_runtime (progs_t *pr) { + probj_t *probj = pr->pr_objective_resources; pr_def_t *def; unsigned i; - if (!pr->selector_hash) - pr->selector_hash = Hash_NewTable (1021, selector_get_key, 0, pr); + if (!probj->selector_hash) + probj->selector_hash = Hash_NewTable (1021, selector_get_key, 0, + probj); else - Hash_FlushTable (pr->selector_hash); - pr->selector_index = 0; - for (i = 0; i < pr->selector_index_max; i++) { - obj_list_free (pr->selector_sels[i]); - pr->selector_sels[i] = 0; - pr->selector_names[i] = 0; + Hash_FlushTable (probj->selector_hash); + probj->selector_index = 0; + for (i = 0; i < probj->selector_index_max; i++) { + obj_list_free (probj->selector_sels[i]); + probj->selector_sels[i] = 0; + probj->selector_names[i] = 0; } - if (!pr->classes) - pr->classes = Hash_NewTable (1021, class_get_key, 0, pr); + if (!probj->classes) + probj->classes = Hash_NewTable (1021, class_get_key, 0, probj); else - Hash_FlushTable (pr->classes); + Hash_FlushTable (probj->classes); - if (!pr->load_methods) { - pr->load_methods = Hash_NewTable (1021, 0, 0, pr); - Hash_SetHashCompare (pr->load_methods, load_methods_get_hash, + if (!probj->load_methods) { + probj->load_methods = Hash_NewTable (1021, 0, 0, probj); + Hash_SetHashCompare (probj->load_methods, load_methods_get_hash, load_methods_compare); } else { - Hash_FlushTable (pr->load_methods); + Hash_FlushTable (probj->load_methods); } - pr->unresolved_classes = 0; - pr->unclaimed_categories = 0; - pr->unclaimed_proto_list = 0; - pr->module_list = 0; - pr->class_tree_list = 0; + probj->unresolved_classes = 0; + probj->unclaimed_categories = 0; + probj->unclaimed_proto_list = 0; + probj->module_list = 0; + probj->class_tree_list = 0; if ((def = PR_FindField (pr, ".this"))) pr->fields.this = def->ofs; @@ -1694,17 +1767,30 @@ rua_init_runtime (progs_t *pr) return 1; } +static void +rua_obj_cleanup (progs_t *pr, void *data) +{ + __auto_type probj = (probj_t *) data; + pr->pr_objective_resources = probj; +} + void RUA_Obj_Init (progs_t *pr, int secure) { + probj_t *probj = calloc (1, sizeof (*probj)); + probj->pr = pr; + + PR_Resources_Register (pr, "RUA_ObjectiveQuakeC", probj, rua_obj_cleanup); + PR_RegisterBuiltins (pr, obj_methods); - PR_AddLoadFunc (pr, rua_init_runtime); + PR_AddLoadFunc (pr, rua_obj_init_runtime); } func_t RUA_Obj_msg_lookup (progs_t *pr, pointer_t _self, pointer_t __cmd) { + probj_t *probj = pr->pr_objective_resources; pr_id_t *self = &G_STRUCT (pr, pr_id_t, _self); pr_sel_t *_cmd = &G_STRUCT (pr, pr_sel_t, __cmd); func_t imp; @@ -1713,11 +1799,11 @@ RUA_Obj_msg_lookup (progs_t *pr, pointer_t _self, pointer_t __cmd) return 0; if (!_cmd) PR_RunError (pr, "null selector"); - imp = obj_msg_lookup (pr, self, _cmd); + imp = obj_msg_lookup (probj, self, _cmd); if (!imp) PR_RunError (pr, "%s does not respond to %s", - PR_GetString (pr, object_get_class_name (pr, self)), - PR_GetString (pr, pr->selector_names[_cmd->sel_id])); + PR_GetString (pr, object_get_class_name (probj, self)), + PR_GetString (pr, probj->selector_names[_cmd->sel_id])); return imp; } From f185e07ad2ed23e64ae80655e3044c9536670d2a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 01:01:47 +0900 Subject: [PATCH 090/444] Fix some missing dependencies Generally not a problem with libtool and its automatic dependencies, but best to be explicit. --- config.d/build_control.m4 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index abc60cd75..13004a6c8 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -372,6 +372,7 @@ QF_DEPS(QFCC, QF_DEPS(QFCC_TEST, [], [$(top_builddir)/libs/ruamoko/libQFruamoko.la + $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la], [$(WIN32_LIBS)], ) @@ -406,6 +407,7 @@ QF_DEPS(QFVIS, QF_DEPS(QWAQ, [], [$(top_builddir)/libs/ruamoko/libQFruamoko.la + $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la], [$(WIN32_LIBS)], ) @@ -413,6 +415,7 @@ QF_DEPS(CARNE, [], [$(top_builddir)/libs/gib/libQFgib.la $(top_builddir)/libs/ruamoko/libQFruamoko.la + $(top_builddir)/libs/gamecode/libQFgamecode.la $(top_builddir)/libs/util/libQFutil.la], [$(WIN32_LIBS)], ) From 35c9d6ee38ae3aa00097627c5ef86be520935962 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 01:20:28 +0900 Subject: [PATCH 091/444] Make pr_obcode.c mostly thread safe Its public data is all read-only, and once set up, its private data is too (just don't call init in multiple threads). --- include/QF/pr_comp.h | 6 +++--- libs/gamecode/pr_opcode.c | 12 ++++++------ tools/qfcc/source/opcodes.c | 3 ++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 60022098f..03f5b3a46 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -50,8 +50,8 @@ typedef enum { ev_type_count // not a type, gives number of types } etype_t; -extern pr_ushort_t pr_type_size[ev_type_count]; -extern const char *pr_type_name[ev_type_count]; +extern const pr_ushort_t pr_type_size[ev_type_count]; +extern const char * const pr_type_name[ev_type_count]; #define OFS_NULL 0 #define OFS_RETURN 1 @@ -407,7 +407,7 @@ typedef struct opcode_s { const char *fmt; } opcode_t; -extern opcode_t pr_opcodes[]; +extern const opcode_t pr_opcodes[]; opcode_t *PR_Opcode (pr_short_t opcode); void PR_Opcode_Init (void); // idempotent diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index ab266c84c..853176925 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -46,9 +46,9 @@ #include "compat.h" -hashtab_t *opcode_table; +static hashtab_t *opcode_table; -VISIBLE pr_ushort_t pr_type_size[ev_type_count] = { +VISIBLE const pr_ushort_t pr_type_size[ev_type_count] = { 1, // ev_void 1, // ev_string 1, // ev_float @@ -65,7 +65,7 @@ VISIBLE pr_ushort_t pr_type_size[ev_type_count] = { 0, // ev_invalid not a valid/simple type }; -VISIBLE const char *pr_type_name[ev_type_count] = { +VISIBLE const char * const pr_type_name[ev_type_count] = { "void", "string", "float", @@ -98,7 +98,7 @@ VISIBLE const char *pr_type_name[ev_type_count] = { // c operand c // x place holder for P (padding) // 0-7 parameter index (for P) -VISIBLE opcode_t pr_opcodes[] = { +VISIBLE const opcode_t pr_opcodes[] = { {"", "done", OP_DONE, false, // OP_DONE is actually the same as ev_entity, ev_field, ev_void, // OP_RETURN, the types are bogus PROG_ID_VERSION, @@ -1492,7 +1492,7 @@ PR_Opcode (pr_short_t opcode) VISIBLE void PR_Opcode_Init (void) { - opcode_t *op; + const opcode_t *op; if (opcode_table) { // already initialized @@ -1502,7 +1502,7 @@ PR_Opcode_Init (void) Hash_SetHashCompare (opcode_table, opcode_get_hash, opcode_compare); for (op = pr_opcodes; op->name; op++) { - Hash_AddElement (opcode_table, op); + Hash_AddElement (opcode_table, (void *) op); } } diff --git a/tools/qfcc/source/opcodes.c b/tools/qfcc/source/opcodes.c index bf8b5b189..bbf10250a 100644 --- a/tools/qfcc/source/opcodes.c +++ b/tools/qfcc/source/opcodes.c @@ -131,7 +131,8 @@ opcode_free (void *_op, void *unused) void opcode_init (void) { - opcode_t *op, *mop; + const opcode_t *op; + opcode_t *mop; if (opcode_type_table) { Hash_FlushTable (opcode_void_table); From 4c1b6ce76ce62c287f3dde86b721c8e23ad2f587 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 01:55:56 +0900 Subject: [PATCH 092/444] Make pr_parse thread safe Or at least, conversion to property list is thread safe. --- libs/gamecode/pr_parse.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index f17b69bf1..c63bb71b5 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -68,15 +68,11 @@ Easier to parse than PR_ValueString */ static const char * -PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) +PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val, dstring_t *line) { - static dstring_t *line = 0; pr_def_t *def; dfunction_t *f; - if (!line) - line = dstring_new (); - type &= ~DEF_SAVEGLOBAL; switch (type) { @@ -121,6 +117,7 @@ PR_UglyValueString (progs_t *pr, etype_t type, pr_type_t *val) VISIBLE plitem_t * ED_EntityDict (progs_t *pr, edict_t *ed) { + dstring_t *dstr = dstring_newstr (); plitem_t *entity = PL_NewDictionary (); pr_uint_t i; int j; @@ -149,10 +146,11 @@ ED_EntityDict (progs_t *pr, edict_t *ed) if (j == pr_type_size[type]) continue; - value = PR_UglyValueString (pr, type, v); + value = PR_UglyValueString (pr, type, v, dstr); PL_D_AddObject (entity, name, PL_NewString (value)); } } + dstring_delete (dstr); return entity; } @@ -165,6 +163,7 @@ ED_EntityDict (progs_t *pr, edict_t *ed) VISIBLE plitem_t * ED_GlobalsDict (progs_t *pr) { + dstring_t *dstr = dstring_newstr (); plitem_t *globals = PL_NewDictionary (); pr_uint_t i; const char *name; @@ -183,9 +182,10 @@ ED_GlobalsDict (progs_t *pr) continue; name = PR_GetString (pr, def->name); - value = PR_UglyValueString (pr, type, &pr->pr_globals[def->ofs]); + value = PR_UglyValueString (pr, type, &pr->pr_globals[def->ofs], dstr); PL_D_AddObject (globals, name, PL_NewString (value)); } + dstring_delete (dstr); return globals; } From 42713cad8b13b589c4b218b3d0ccbd06ae139777 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 09:39:03 +0900 Subject: [PATCH 093/444] Make script much friendlier to use It now simply sets an error message pointer and returns false if there's an error. --- include/QF/script.h | 6 ++++-- libs/gamecode/pr_debug.c | 10 +++------ libs/ruamoko/rua_script.c | 13 ++--------- libs/util/script.c | 45 +++++++++++++++++---------------------- 4 files changed, 28 insertions(+), 46 deletions(-) diff --git a/include/QF/script.h b/include/QF/script.h index 357e5100b..34e6f269a 100644 --- a/include/QF/script.h +++ b/include/QF/script.h @@ -41,8 +41,9 @@ typedef struct script_s { /// line number of the file being processed. used only for error reporting /// but updated internally. int line; - /// if set, will be called instead of the internal error handler - void (*error)(struct script_s *script, const char *msg); + /// contains last error message or null if no error + /// if set, no tokens will be parsed. + const char *error; /// if set, multi line quoted tokens will be treated as errors int no_quote_lines; /// if set, characters in this string will always be lexed as single @@ -65,6 +66,7 @@ void Script_Delete (script_t *script); /** Prepare a script_t object for parsing. The caller is responsible for freeing the memory associated with file and data when parsing is complete. + Resets \a script->error \param script The script_t object being parsed \param file Name of the file being parsed. used only for error reporting \param data The script to be parsed diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 9fd61b020..f7f3f3b7c 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -197,12 +197,6 @@ source_path_f (cvar_t *var) source_paths[i] = 0; } -static void -pr_debug_expression_error (script_t *script, const char *msg) -{ - Sys_Printf ("%s\n", msg); -} - #define RUP(x,a) (((x) + ((a) - 1)) & ~((a) - 1)) static pr_short_t __attribute__((pure)) pr_debug_type_size (const progs_t *pr, const qfot_type_t *type) @@ -266,7 +260,6 @@ parse_expression (progs_t *pr, const char *expr, int conditional) d.type = ev_invalid; d.name = 0; es = Script_New (); - es->error = pr_debug_expression_error; Script_Start (es, "", expr); expr_ptr = 0; es->single = "{}()':[]."; @@ -323,6 +316,9 @@ parse_expression (progs_t *pr, const char *expr, int conditional) Sys_Printf ("ignoring tail\n"); } error: + if (es->error) { + Sys_Printf (es->error); + } Script_Delete (es); return d; } diff --git a/libs/ruamoko/rua_script.c b/libs/ruamoko/rua_script.c index c6fae5750..ff5b2ab0a 100644 --- a/libs/ruamoko/rua_script.c +++ b/libs/ruamoko/rua_script.c @@ -48,7 +48,6 @@ typedef struct { script_t script; string_t dstr; progs_t *pr; - string_t err_msg; } rua_script_t; typedef struct { @@ -92,13 +91,6 @@ bi_script_clear (progs_t *pr, void *data) script_reset (res); } -static void -bi_script_error (script_t *_script, const char *msg) -{ - rua_script_t *script = (rua_script_t *)_script; - script->err_msg = PR_SetString (script->pr, msg); -} - static void bi_Script_New (progs_t *pr) { @@ -110,7 +102,6 @@ bi_Script_New (progs_t *pr) script->dstr = PR_NewMutableString (pr); script->script.token = PR_GetMutableString (pr, script->dstr); - script->script.error = bi_script_error; script->pr = pr; R_INT (pr) = script_index (res, script); } @@ -180,8 +171,8 @@ bi_Script_Error (progs_t *pr) if (!script) PR_RunError (pr, "invalid script handle"); - R_STRING (pr) = script->err_msg; - script->err_msg = 0; + R_STRING (pr) = PR_SetString (pr, script->script.error); + script->script.error = 0; } static void diff --git a/libs/util/script.c b/libs/util/script.c index eeb1df977..fa8b51ae0 100644 --- a/libs/util/script.c +++ b/libs/util/script.c @@ -34,19 +34,6 @@ #include "QF/dstring.h" #include "QF/script.h" -static void __attribute__ ((format (printf, 2, 3), noreturn)) -script_error (script_t *script, const char *fmt, ...) -{ - va_list args; - - va_start (args, fmt); - fprintf (stderr, "%s:%d: ", script->file, script->line); - vfprintf (stderr, fmt, args); - fprintf (stderr, "\n"); - va_end (args); - exit (1); -} - VISIBLE script_t * Script_New (void) { @@ -69,11 +56,16 @@ Script_Start (script_t *script, const char *file, const char *data) script->file = file; script->p = data; script->unget = false; + script->error = 0; } VISIBLE qboolean Script_TokenAvailable (script_t *script, qboolean crossline) { + if (script->error) { + return false; + } + if (script->unget) return true; skipspace: @@ -111,6 +103,10 @@ Script_GetToken (script_t *script, qboolean crossline) { const char *token_p; + if (script->error) { + return false; + } + if (script->unget) { // is a token allready waiting? script->unget = false; return true; @@ -118,10 +114,7 @@ Script_GetToken (script_t *script, qboolean crossline) if (!Script_TokenAvailable (script, crossline)) { if (!crossline) { - if (script->error) - script->error (script, "line is incomplete"); - else - script_error (script, "line is incomplete"); + script->error = "line is incomplete"; } return false; } @@ -134,18 +127,13 @@ Script_GetToken (script_t *script, qboolean crossline) while (*script->p != '"') { if (!*script->p) { script->line = start_line; - if (script->error) - script->error (script, "EOF inside quoted token"); - else - script_error (script, "EOF inside quoted token"); + script->error = "EOF inside quoted token"; return false; } if (*script->p == '\n') { if (script->no_quote_lines) { - if (script->error) - script->error (script, "EOL inside quoted token"); - else - script_error (script, "EOL inside quoted token"); + script->error = "EOL inside quoted token"; + return false; } script->line++; } @@ -175,11 +163,16 @@ Script_GetToken (script_t *script, qboolean crossline) VISIBLE void Script_UngetToken (script_t *script) { - script->unget = true; + if (!script->error) { + script->unget = true; + } } VISIBLE const char * Script_Token (script_t *script) { + if (script->error) { + return 0; + } return script->token->str; } From d60291a73e16308125df3ede2dc3428283bd7cca Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 09:46:59 +0900 Subject: [PATCH 094/444] Clean up a lot of va usage va is not thread-safe (it's not save even without threads), and I want to be able to run progs in threads. --- libs/gamecode/pr_edict.c | 12 ------------ libs/gamecode/pr_load.c | 5 ----- libs/gamecode/pr_parse.c | 19 +++++++------------ libs/gamecode/pr_resolve.c | 16 +++++----------- libs/ruamoko/rua_qfile.c | 4 +--- 5 files changed, 13 insertions(+), 43 deletions(-) diff --git a/libs/gamecode/pr_edict.c b/libs/gamecode/pr_edict.c index 29559f8f1..e3bfc778b 100644 --- a/libs/gamecode/pr_edict.c +++ b/libs/gamecode/pr_edict.c @@ -34,22 +34,10 @@ #ifdef HAVE_STRINGS_H # include #endif -#include -#include -#include "QF/cbuf.h" -#include "QF/crc.h" #include "QF/cvar.h" -#include "QF/dstring.h" -#include "QF/hash.h" -#include "QF/idparse.h" #include "QF/progs.h" -#include "QF/qdefs.h" -#include "QF/qendian.h" -#include "QF/quakefs.h" #include "QF/sys.h" -#include "QF/zone.h" -#include "QF/va.h" #include "compat.h" diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index c8157efa8..df72cbbc9 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -34,22 +34,17 @@ #ifdef HAVE_STRINGS_H # include #endif -#include -#include -#include "QF/cmd.h" #include "QF/crc.h" #include "QF/cvar.h" #include "QF/dstring.h" #include "QF/hash.h" #include "QF/mathlib.h" #include "QF/progs.h" -#include "QF/qdefs.h" #include "QF/qendian.h" #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/zone.h" -#include "QF/va.h" #include "compat.h" diff --git a/libs/gamecode/pr_parse.c b/libs/gamecode/pr_parse.c index c63bb71b5..2652694e8 100644 --- a/libs/gamecode/pr_parse.c +++ b/libs/gamecode/pr_parse.c @@ -43,21 +43,12 @@ #include #endif -#include "QF/cbuf.h" -#include "QF/crc.h" -#include "QF/cvar.h" #include "QF/dstring.h" -#include "QF/hash.h" #include "QF/mathlib.h" #include "QF/progs.h" -#include "QF/qdefs.h" #include "QF/qfplist.h" -#include "QF/qendian.h" -#include "QF/quakefs.h" #include "QF/script.h" #include "QF/sys.h" -#include "QF/zone.h" -#include "QF/va.h" #include "compat.h" @@ -301,6 +292,7 @@ ED_ParseEpair (progs_t *pr, pr_type_t *base, pr_def_t *key, const char *s) VISIBLE plitem_t * ED_ConvertToPlist (script_t *script, int nohack) { + dstring_t *dstr = dstring_newstr (); plitem_t *plist = PL_NewArray (); plitem_t *ent; plitem_t *key; @@ -341,15 +333,18 @@ ED_ConvertToPlist (script_t *script, int nohack) token = script->token->str; if (strequal (token, "}")) Sys_Error ("ED_ConvertToPlist: closing brace without data"); - if (anglehack) - value = PL_NewString (va ("0 %s 0", token)); - else + if (anglehack) { + dsprintf (dstr, "0 %s 0", token); + value = PL_NewString (dstr->str); + } else { value = PL_NewString (token); + } PL_D_AddObject (ent, PL_String (key), value); PL_Free (key); } PL_A_AddObject (plist, ent); } + dstring_delete (dstr); return plist; } diff --git a/libs/gamecode/pr_resolve.c b/libs/gamecode/pr_resolve.c index 0f7acaa8f..5297f101a 100644 --- a/libs/gamecode/pr_resolve.c +++ b/libs/gamecode/pr_resolve.c @@ -34,23 +34,14 @@ #ifdef HAVE_STRINGS_H # include #endif -#include -#include -#include "QF/cmd.h" -#include "QF/crc.h" -#include "QF/cvar.h" #include "QF/hash.h" #include "QF/progs.h" -#include "QF/qdefs.h" -#include "QF/qendian.h" -#include "QF/quakefs.h" #include "QF/sys.h" -#include "QF/zone.h" -#include "QF/va.h" #include "compat.h" +static const char param_str[] = ".param_0"; pr_def_t * PR_GlobalAtOfs (progs_t * pr, pointer_t ofs) @@ -124,11 +115,14 @@ PR_ResolveGlobals (progs_t *pr) pr->pr_param_size = OFS_PARM1 - OFS_PARM0; pr->pr_param_alignment = 0; // log2 } else { + char *param_n = alloca (sizeof (param_str)); + strcpy (param_n, param_str); if (!(def = PR_FindGlobal (pr, sym = ".return"))) goto error; pr->pr_return = &pr->pr_globals[def->ofs]; for (i = 0; i < MAX_PARMS; i++) { - if (!(def = PR_FindGlobal (pr, sym = va(".param_%d", i)))) + param_n[sizeof (param_str) - 2] = i + '0'; + if (!(def = PR_FindGlobal (pr, sym = param_n))) goto error; pr->pr_params[i] = &pr->pr_globals[def->ofs]; } diff --git a/libs/ruamoko/rua_qfile.c b/libs/ruamoko/rua_qfile.c index 057ff0ef6..d96c433a2 100644 --- a/libs/ruamoko/rua_qfile.c +++ b/libs/ruamoko/rua_qfile.c @@ -38,9 +38,7 @@ #include "QF/dstring.h" #include "QF/progs.h" -#include "QF/quakefs.h" -#include "QF/va.h" -#include "QF/zone.h" +#include "QF/quakeio.h" #include "rua_internal.h" From aa02069dd1c2fd2d4b85e3ee06738cefcc4999e1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 13:40:26 +0900 Subject: [PATCH 095/444] Add a breakpoint flag to opcodes The progs execution code will call a breakpoint handler just before executing an instruction with the flag set. This means there's no need for the breakpoint handler to mess with execution state or even the instruction in order to continue past the breakpoint. The flag being set in a progs file is invalid. --- include/QF/pr_comp.h | 1 + include/QF/progs.h | 1 + libs/gamecode/pr_exec.c | 11 ++++++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 03f5b3a46..6458d3913 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -396,6 +396,7 @@ typedef enum { OP_MOD_F, OP_MOD_D, } pr_opcode_e; +#define OP_BREAK 0x8000 typedef struct opcode_s { const char *name; diff --git a/include/QF/progs.h b/include/QF/progs.h index 369360449..5abd0d1c6 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1776,6 +1776,7 @@ struct progs_s { /// \name debugging ///@{ struct prdeb_resources_s *pr_debug_resources; + void (*breakpoint_handler) (progs_t *pr); pr_type_t *watch; int wp_conditional; pr_type_t wp_val; diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 024594d81..b933572e4 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -440,7 +440,16 @@ PR_ExecuteProgram (progs_t *pr, func_t fnum) if (pr->pr_trace) PR_PrintStatement (pr, st, 1); - switch (st->op) { + if (st->op & OP_BREAK) { + if (pr->breakpoint_handler) { + pr->breakpoint_handler (pr); + } else { + PR_RunError (pr, "breakpoint hit"); + } + } + + pr_opcode_e op = st->op & ~OP_BREAK; + switch (op) { case OP_ADD_D: OPC_double_var = OPA_double_var + OPB_double_var; break; From 225a375ab96225a4ebc2bf855132241028f616f4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 13:43:03 +0900 Subject: [PATCH 096/444] Extend the lifetime of return-strings This is done by putting the most recently used return-string at the end of the queue for recycling. --- libs/gamecode/pr_strings.c | 82 +++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 18 deletions(-) diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index a8c8c4fee..cb74797a5 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -44,14 +44,20 @@ #include "QF/progs.h" #include "QF/va.h" +typedef struct strref_slot_s { + struct strref_slot_s *next; + struct strref_slot_s **prev; + strref_t *strref; +} strref_slot_t; + typedef struct prstr_resources_s { progs_t *pr; dstring_mem_t ds_mem; strref_t *free_string_refs; strref_t *static_strings; strref_t **string_map; - strref_t *return_strings[PR_RS_SLOTS]; - int rs_slot; + strref_slot_t return_strings[PR_RS_SLOTS]; + strref_slot_t *rs_slot; unsigned dyn_str_size; struct hashtab_s *strref_hash; int num_strings; @@ -68,7 +74,7 @@ typedef enum { struct strref_s { strref_t *next; - strref_t **prev; + strref_slot_t *rs_slot; str_e type; union { char *string; @@ -146,6 +152,7 @@ new_string_ref (prstr_resources_t *res) sr = res->free_string_refs; res->free_string_refs = sr->next; sr->next = 0; + sr->rs_slot = 0; return sr; } @@ -153,8 +160,6 @@ static void free_string_ref (prstr_resources_t *res, strref_t *sr) { sr->type = str_free; - if (sr->prev) - *sr->prev = sr->next; sr->next = res->free_string_refs; res->free_string_refs = sr; } @@ -208,11 +213,18 @@ pr_strings_clear (progs_t *pr, void *data) int i; for (i = 0; i < PR_RS_SLOTS; i++) { - if (res->return_strings[i]) - free_string_ref (res, res->return_strings[i]); - res->return_strings[i] = 0; + if (res->return_strings[i].strref) + free_string_ref (res, res->return_strings[i].strref); + res->return_strings[i].strref = 0; + } + if (!res->rs_slot) { + strref_slot_t * const rs = res->return_strings; + for (i = 0; i < PR_RS_SLOTS; i++) { + rs[i].next = &rs[(i + 1) % PR_RS_SLOTS]; + rs[i].prev = &rs[(i - 1 + PR_RS_SLOTS) % PR_RS_SLOTS].next; + } + res->rs_slot = rs; } - res->rs_slot = 0; pr->pr_string_resources = res; pr->pr_xtstr = 0; @@ -265,6 +277,28 @@ PR_LoadStrings (progs_t *pr) return 1; } +static void +requeue_strref (prstr_resources_t *res, strref_t *sr) +{ + strref_slot_t *rs_slot = sr->rs_slot; + if (rs_slot->next != res->rs_slot) { + // this is the oldest slot, so advance res->rs_slot to the + // next oldest slot so this slot does not get reused just yet + if (res->rs_slot == rs_slot) { + res->rs_slot = rs_slot->next; + } + // unlink this slot from the chain + rs_slot->next->prev = rs_slot->prev; + *rs_slot->prev = rs_slot->next; + // link this slot just before the oldest slot: all the slots + // form a doubly linked circular list + rs_slot->prev = res->rs_slot->prev; + rs_slot->next = res->rs_slot; + *res->rs_slot->prev = rs_slot; + res->rs_slot->prev = &rs_slot->next; + } +} + static inline strref_t * get_strref (prstr_resources_t *res, string_t num) { @@ -287,15 +321,17 @@ get_strref (prstr_resources_t *res, string_t num) static inline __attribute__((pure)) const char * get_string (progs_t *pr, string_t num) { + __auto_type res = pr->pr_string_resources; if (num < 0) { - strref_t *ref = get_strref (pr->pr_string_resources, num); + strref_t *ref = get_strref (res, num); if (!ref) return 0; switch (ref->type) { + case str_return: + requeue_strref (res, ref); case str_static: case str_temp: case str_dynamic: - case str_return: return ref->s.string; case str_mutable: return ref->s.dstring->str; @@ -313,7 +349,7 @@ get_string (progs_t *pr, string_t num) VISIBLE qboolean PR_StringValid (progs_t *pr, string_t num) { - return get_string (pr, num) != 0; + return get_strref (pr->pr_string_resources, num) != 0; } VISIBLE const char * @@ -387,21 +423,32 @@ PR_SetReturnString (progs_t *pr, const char *s) if (!s) s = ""; if ((sr = Hash_Find (res->strref_hash, s))) { + if (sr->type == str_return && sr->rs_slot) { + requeue_strref (res, sr); + } else if ((sr->type == str_return && !sr->rs_slot) + || (sr->type != str_return && sr->rs_slot)) { + PR_Error (pr, "internal string error"); + } return string_index (res, sr); } - if ((sr = res->return_strings[res->rs_slot])) { - if (sr->type != str_return) + // grab the string ref from the oldest slot, or make a new one if the + // slot is empty + if ((sr = res->rs_slot->strref)) { + if (sr->type != str_return || sr->rs_slot != res->rs_slot) { PR_Error (pr, "internal string error"); + } pr_strfree (pr, sr->s.string); } else { sr = new_string_ref (res); } sr->type = str_return; + sr->rs_slot = res->rs_slot; sr->s.string = pr_strdup(pr, s); - res->return_strings[res->rs_slot++] = sr; - res->rs_slot %= PR_RS_SLOTS; + // the oldest slot just became the newest, so advance to the next oldest + res->rs_slot = res->rs_slot->next; + return string_index (res, sr); } @@ -525,8 +572,7 @@ PR_FreeString (progs_t *pr, string_t str) free_string_ref (res, sr); return; } - if (!get_string (pr, str)) - PR_RunError (pr, "attempt to free invalid string %d", str); + PR_RunError (pr, "attempt to free invalid string %d", str); } void From 383a7fe5e1ab15edf388657f618e4dee4cb14c06 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 13:45:14 +0900 Subject: [PATCH 097/444] Remove File_Open Other than its blocking of access to certain files, it really wasn't that useful compared to the functions in qfs, and pointless with access to qfs anyway. --- include/rua_internal.h | 2 - libs/ruamoko/Makefile.am | 2 +- libs/ruamoko/rua_file.c | 184 ---------------------------------- libs/ruamoko/rua_init.c | 1 - libs/ruamoko/rua_qfs.c | 7 ++ ruamoko/cl_menu/client_menu.r | 14 +-- ruamoko/include/Makefile.am | 2 +- ruamoko/include/file.h | 8 -- ruamoko/include/qfs.h | 1 + ruamoko/lib/Makefile.am | 2 +- ruamoko/lib/file.r | 3 - ruamoko/lib/qfs.r | 1 + 12 files changed, 19 insertions(+), 208 deletions(-) delete mode 100644 libs/ruamoko/rua_file.c delete mode 100644 ruamoko/include/file.h delete mode 100644 ruamoko/lib/file.r diff --git a/include/rua_internal.h b/include/rua_internal.h index 0b6b34801..158d6e477 100644 --- a/include/rua_internal.h +++ b/include/rua_internal.h @@ -39,8 +39,6 @@ void RUA_Cmd_Init (struct progs_s *pr, int secure); void RUA_Cvar_Init (struct progs_s *pr, int secure); -void RUA_File_Init (struct progs_s *pr, int secure); - void RUA_Hash_Init (struct progs_s *pr, int secure); void RUA_Math_Init (struct progs_s *pr, int secure); diff --git a/libs/ruamoko/Makefile.am b/libs/ruamoko/Makefile.am index 64c65e972..15d4c4360 100644 --- a/libs/ruamoko/Makefile.am +++ b/libs/ruamoko/Makefile.am @@ -16,6 +16,6 @@ libQFruamoko_la_LIBADD= $(rua_libs) libQFruamoko_la_DEPENDENCIES= $(rua_libs) libQFruamoko_la_SOURCES= \ pr_cmds.c \ - rua_cbuf.c rua_cmd.c rua_cvar.c rua_file.c rua_hash.c rua_init.c \ + rua_cbuf.c rua_cmd.c rua_cvar.c rua_hash.c rua_init.c \ rua_math.c rua_msgbuf.c rua_obj.c rua_plist.c rua_qfile.c rua_qfs.c \ rua_script.c rua_set.c rua_string.c diff --git a/libs/ruamoko/rua_file.c b/libs/ruamoko/rua_file.c deleted file mode 100644 index 61def0a3f..000000000 --- a/libs/ruamoko/rua_file.c +++ /dev/null @@ -1,184 +0,0 @@ -/* - bi_file.c - - CSQC file builtins - - Copyright (C) 1996-1997 Id Software, Inc. - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License - as published by the Free Software Foundation; either version 2 - of the License, or (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - - See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to: - - Free Software Foundation, Inc. - 59 Temple Place - Suite 330 - Boston, MA 02111-1307, USA - -*/ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include -#ifdef HAVE_STRING_H -# include -#endif -#ifdef HAVE_STRINGS_H -# include -#endif - -#ifdef HAVE_FNMATCH_H -# define model_t sunmodel_t -# include -# undef model_t -#else -# ifdef _WIN32 -# include "fnmatch.h" -# endif -#endif - -#ifndef HAVE_FNMATCH_PROTO -int fnmatch (const char *__pattern, const char *__string, int __flags); -#endif - -#include "QF/cvar.h" -#include "QF/progs.h" -#include "QF/quakefs.h" -#include "QF/va.h" -#include "QF/zone.h" - -#include "rua_internal.h" - -static const char *file_ban_list[] = { - "default.cfg{,.gz}", - "demo1.dem{,.gz}", - "demo2.dem{,.gz}", - "demo3.dem{,.gz}", - "end1.bin{,.gz}", - "end2.bin{,.gz}", - "gfx.wad{,.gz}", - "progs.dat{,.gz}", - "quake.rc{,.gz}", - 0, -}; - -static const char *dir_ban_list[] = { - "gfx", - "maps", - "progs", - "skins", - "sound", - 0, -}; - -static int -file_readable (char *path) -{ - char t; - char *p = strchr (path, '/'); - const char **match; - - if (p) { - t = *p; - *p = 0; - for (match = dir_ban_list; *match; match++) { - if (fnmatch (*match, path, FNM_PATHNAME) == 0) { - *p = t; - return 0; - } - } - } else { - for (match = file_ban_list; *match; match++) { - if (fnmatch (*match, path, FNM_PATHNAME) == 0) { - return 0; - } - } - } - return 1; -} - -static int -file_writeable (char *path) -{ - return file_readable (path); -} - -static void -bi_File_Open (progs_t *pr) -{ - QFile *file; - const char *pth = P_GSTRING (pr, 0); - const char *mode = P_GSTRING (pr, 1); - char *path; - char *p; - int do_write = 0; - int do_read = 0; - - p = strchr (mode, 'r'); - if (p) { - do_read |= 1; - if (p[1] == '+') - do_write |= 1; - } - - p = strchr (mode, 'w'); - if (p) { - do_write |= 1; - if (p[1] == '+') - do_read |= 1; - } - - p = strchr (mode, 'a'); - if (p) { - do_write |= 1; - if (p[1] == '+') - do_read |= 1; - } - - path = QFS_CompressPath (pth); - //printf ("'%s' '%s'\n", P_GSTRING (pr, 0), path); - if (!path[0]) - goto error; - if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || path [2] == 0)) - goto error; - if (path[strlen (path) - 1] =='/') - goto error; - if (!do_read && !do_write) - goto error; - if (do_read && !file_readable (path)) - goto error; - if (do_write && !file_writeable (path)) - goto error; - - file = QFS_Open (va ("%s/%s", qfs_gamedir->dir.def, path), mode); - if (!file) - goto error; - free (path); - if ((R_INT (pr) = QFile_AllocHandle (pr, file))) - return; - Qclose (file); - return; -error: - free (path); - R_INT (pr) = 0; -} - -static builtin_t builtins[] = { - {"File_Open", bi_File_Open, -1}, - {0} -}; - -void -RUA_File_Init (progs_t *pr, int secure) -{ - PR_RegisterBuiltins (pr, builtins); -} diff --git a/libs/ruamoko/rua_init.c b/libs/ruamoko/rua_init.c index bbfc67525..7741405a5 100644 --- a/libs/ruamoko/rua_init.c +++ b/libs/ruamoko/rua_init.c @@ -39,7 +39,6 @@ static void (*init_funcs[])(progs_t *, int) = { RUA_Cbuf_Init, RUA_Cmd_Init, RUA_Cvar_Init, - RUA_File_Init, RUA_Hash_Init, RUA_Math_Init, RUA_MsgBuf_Init, diff --git a/libs/ruamoko/rua_qfs.c b/libs/ruamoko/rua_qfs.c index 35d69d0c8..87b2c5add 100644 --- a/libs/ruamoko/rua_qfs.c +++ b/libs/ruamoko/rua_qfs.c @@ -181,6 +181,12 @@ bi_QFS_FilelistFree (progs_t *pr) PR_Zone_Free (pr, list); } +static void +bi_QFS_GetDirectory (progs_t *pr) +{ + RETURN_STRING (pr, qfs_gamedir->dir.def); +} + static builtin_t builtins[] = { {"QFS_Open", bi_QFS_Open, -1}, {"QFS_WOpen", bi_QFS_WOpen, -1}, @@ -190,6 +196,7 @@ static builtin_t builtins[] = { {"QFS_WriteFile", bi_QFS_WriteFile, -1}, {"QFS_Filelist", bi_QFS_Filelist, -1}, {"QFS_FilelistFree", bi_QFS_FilelistFree, -1}, + {"QFS_GetDirectory", bi_QFS_GetDirectory, -1}, {0} }; diff --git a/ruamoko/cl_menu/client_menu.r b/ruamoko/cl_menu/client_menu.r index 769ad9cae..840eac1c8 100644 --- a/ruamoko/cl_menu/client_menu.r +++ b/ruamoko/cl_menu/client_menu.r @@ -1,6 +1,5 @@ #include "AutoreleasePool.h" #include "menu.h" -#include "file.h" #include "cmd.h" #include "gib.h" #include "draw.h" @@ -10,6 +9,7 @@ #include "options.h" #include "servlist.h" #include "system.h" +#include "qfs.h" #include "debug.h" #include "HUD.h" #include "client_menu.h" @@ -137,17 +137,17 @@ void (int quick) scan_saves = local QFile f; local string line; local int max = MAX_SAVEGAMES; - if (quick) + string basename = "s"; + if (quick) { max = MAX_QUICK; + basename = "quick"; + } + string gamedir = QFS_GetDirectory(); for (i = 0; i < max; i++) { if (!filenames[i]) filenames[i] = str_new (); loadable[i] = 0; - if (quick) { - f = File_Open (sprintf ("quick%i.sav", i + 1), "rz"); - } else { - f = File_Open (sprintf ("s%i.sav", i), "rz"); - } + f = QFS_OpenFile (sprintf ("%s/%s%i.sav", gamedir, basename, i)); if (!f) { str_copy (filenames[i], "--- UNUSED SLOT ---"); continue; diff --git a/ruamoko/include/Makefile.am b/ruamoko/include/Makefile.am index b11080d13..17167cbec 100644 --- a/ruamoko/include/Makefile.am +++ b/ruamoko/include/Makefile.am @@ -7,7 +7,7 @@ nobase_pkginclude_HEADERS= \ \ draw.h key.h \ \ - cbuf.h cmd.h cvar.h file.h gib.h hash.h plist.h runtime.h \ + cbuf.h cmd.h cvar.h gib.h hash.h plist.h runtime.h \ Object.h Protocol.h \ AutoreleasePool.h Array.h Entity.h PropertyList.h Set.h \ \ diff --git a/ruamoko/include/file.h b/ruamoko/include/file.h deleted file mode 100644 index f1c3a580b..000000000 --- a/ruamoko/include/file.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __ruamoko_file_h -#define __ruamoko_file_h - -#include "qfile.h" - -@extern QFile File_Open (string path, string mode); - -#endif//__ruamoko_file_h diff --git a/ruamoko/include/qfs.h b/ruamoko/include/qfs.h index 484a020c0..4a31154f9 100644 --- a/ruamoko/include/qfs.h +++ b/ruamoko/include/qfs.h @@ -17,5 +17,6 @@ typedef struct _qfslist_t *QFSlist; @extern int QFS_WriteFile (string filename, void *buf, int count); @extern QFSlist QFS_Filelist (string path, string ext, int strip); @extern void QFS_FilelistFree (QFSlist list); +@extern string QFS_GetDirectory (void); #endif//__ruamoko_qfs_h diff --git a/ruamoko/lib/Makefile.am b/ruamoko/lib/Makefile.am index e4b475d64..ee2c80ff7 100644 --- a/ruamoko/lib/Makefile.am +++ b/ruamoko/lib/Makefile.am @@ -26,7 +26,7 @@ SUFFIXES= .o .r .qc $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $< libr_a_SOURCES=\ - cbuf.r cmd.r cvar.r file.r hash.r msgbuf.r plist.r qfile.r qfs.r script.r \ + cbuf.r cmd.r cvar.r hash.r msgbuf.r plist.r qfile.r qfs.r script.r \ sound.r string.r math.r types.r \ Object.r Protocol.r \ AutoreleasePool.r Array.r Array+Private.r Entity.r PropertyList.r Set.r diff --git a/ruamoko/lib/file.r b/ruamoko/lib/file.r deleted file mode 100644 index 02494d317..000000000 --- a/ruamoko/lib/file.r +++ /dev/null @@ -1,3 +0,0 @@ -#include "file.h" - -QFile (string path, string mode) File_Open = #0; diff --git a/ruamoko/lib/qfs.r b/ruamoko/lib/qfs.r index e1d374fc4..b0632d030 100644 --- a/ruamoko/lib/qfs.r +++ b/ruamoko/lib/qfs.r @@ -8,3 +8,4 @@ QFile QFS_OpenFile (string filename) = #0; int QFS_WriteFile (string filename, void *buf, int count) = #0; QFSlist QFS_Filelist (string path, string ext, int strip) = #0; void QFS_FilelistFree (QFSlist list) = #0; +string QFS_GetDirectory (void) = #0; From 5d302ff6f419041fd7feb2eb7eff2f8f2d86d518 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 17:13:13 +0900 Subject: [PATCH 098/444] Fix incorrect usage of signed verbosity --- tools/qfcc/source/diagnostic.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/diagnostic.c b/tools/qfcc/source/diagnostic.c index 84892687f..ab830280a 100644 --- a/tools/qfcc/source/diagnostic.c +++ b/tools/qfcc/source/diagnostic.c @@ -114,7 +114,7 @@ __warning (expr_t *e, const char *file, int line, format_message (message, "warning", e, fmt, args); } - if (options.verbosity) { + if (options.verbosity > 0) { dasprintf (message, " (%s:%d)", file, line); } if (warning_hook) { @@ -208,7 +208,7 @@ _notice (expr_t *e, const char *file, int line, const char *fmt, ...) report_function (e); format_message (message, "notice", e, fmt, args); - if (options.verbosity) { + if (options.verbosity > 0) { dasprintf (message, " (%s:%d)", file, line); } if (notice_hook) { @@ -257,7 +257,7 @@ _error (expr_t *e, const char *file, int line, const char *fmt, ...) dstring_t *message = dstring_new (); format_message (message, "error", e, fmt, args); - if (options.verbosity) { + if (options.verbosity > 0) { dasprintf (message, " (%s:%d)", file, line); } if (error_hook) { From 5c36c60005e55f64af1e26e8590ae863d7dbb40a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 17:41:45 +0900 Subject: [PATCH 099/444] Use type check helpers some more --- tools/qfcc/source/expr.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 41c3ca7a2..666a3f3fd 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -291,7 +291,7 @@ cast_error (expr_t *e, type_t *t1, type_t *t2) print_type_str (s1, t1); print_type_str (s2, t2); - e = error (e, "can not cast from %s to %s", s1->str, s2->str); + e = error (e, "cannot cast from %s to %s", s1->str, s2->str); dstring_delete (s1); dstring_delete (s2); return e; @@ -2385,11 +2385,11 @@ cast_expr (type_t *type, expr_t *e) c = new_alias_expr (type, e); return c; } - if (!(type->type == ev_pointer - && (e_type->type == ev_pointer || is_integral (e_type) + if (!(is_pointer (type) + && (is_pointer (e_type) || is_integral (e_type) || is_array (e_type))) - && !(is_integral (type) && e_type->type == ev_pointer) - && !(type->type == ev_func && e_type->type == ev_func) + && !(is_integral (type) && is_pointer (e_type)) + && !(is_func (type) && is_func (e_type)) && !(is_scalar (type) && is_scalar (e_type))) { return cast_error (e, e_type, type); } From 9528c1176e28791d9fac24f725dae069c1387f86 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 17:45:08 +0900 Subject: [PATCH 100/444] Rename cast_expr's type vars for better clarity --- tools/qfcc/source/expr.c | 54 ++++++++++++++++++++-------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 666a3f3fd..9ad394a07 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2362,41 +2362,41 @@ think_expr (symbol_t *think_sym) } expr_t * -cast_expr (type_t *type, expr_t *e) +cast_expr (type_t *dstType, expr_t *e) { expr_t *c; - type_t *e_type; + type_t *srcType; convert_name (e); if (e->type == ex_error) return e; - e_type = get_type (e); + srcType = get_type (e); - if (type == e_type) + if (dstType == srcType) return e; - if ((type == type_default && is_enum (e_type)) - || (is_enum (type) && e_type == type_default)) + if ((dstType == type_default && is_enum (srcType)) + || (is_enum (dstType) && srcType == type_default)) return e; - if ((is_pointer (type) && is_string (e_type)) - || (is_string (type) && is_pointer (e_type))) { - c = new_alias_expr (type, e); + if ((is_pointer (dstType) && is_string (srcType)) + || (is_string (dstType) && is_pointer (srcType))) { + c = new_alias_expr (dstType, e); return c; } - if (!(is_pointer (type) - && (is_pointer (e_type) || is_integral (e_type) - || is_array (e_type))) - && !(is_integral (type) && is_pointer (e_type)) - && !(is_func (type) && is_func (e_type)) - && !(is_scalar (type) && is_scalar (e_type))) { - return cast_error (e, e_type, type); + if (!(is_pointer (dstType) + && (is_pointer (srcType) || is_integral (srcType) + || is_array (srcType))) + && !(is_integral (dstType) && is_pointer (srcType)) + && !(is_func (dstType) && is_func (srcType)) + && !(is_scalar (dstType) && is_scalar (srcType))) { + return cast_error (e, srcType, dstType); } - if (is_array (e_type)) { - return address_expr (e, 0, type->t.fldptr.type); + if (is_array (srcType)) { + return address_expr (e, 0, dstType->t.fldptr.type); } - if (is_constant (e) && is_scalar (type) && is_scalar (e_type)) { + if (is_constant (e) && is_scalar (dstType) && is_scalar (srcType)) { ex_value_t *val = 0; if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const) { val = e->e.symbol->s.value; @@ -2416,24 +2416,24 @@ cast_expr (type_t *type, expr_t *e) } else if (e->type == ex_value) { val = e->e.value; } else if (e->type == ex_nil) { - convert_nil (e, type); + convert_nil (e, dstType); return e; } if (!val) internal_error (e, "unexpected constant expression type"); - e->e.value = convert_value (val, type); + e->e.value = convert_value (val, dstType); e->type = ex_value; c = e; - } else if (is_integral (type) && is_integral (e_type)) { - c = new_alias_expr (type, e); - } else if (is_scalar (type) && is_scalar (e_type)) { + } else if (is_integral (dstType) && is_integral (srcType)) { + c = new_alias_expr (dstType, e); + } else if (is_scalar (dstType) && is_scalar (srcType)) { c = new_unary_expr ('C', e); - c->e.expr.type = type; + c->e.expr.type = dstType; } else if (e->type == ex_uexpr && e->e.expr.op == '.') { - e->e.expr.type = type; + e->e.expr.type = dstType; c = e; } else { - c = new_alias_expr (type, e); + c = new_alias_expr (dstType, e); } return c; } From 69b5029de5a4f28b88b84d0b8dc07549c7eb3ceb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 17:46:53 +0900 Subject: [PATCH 101/444] Throw away function parameter type alias info typedef is meant to create a simple renaming of a potentially complex type, not create a new type. Keeping the parameter type alias info makes the types effectively different when it comes to overloaded function resolution, which is quite contrary to the goal. Does expose some breakage elsewhere, though. --- tools/qfcc/TODO | 1 + tools/qfcc/source/function.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/TODO b/tools/qfcc/TODO index 5bce50696..8180ed95d 100644 --- a/tools/qfcc/TODO +++ b/tools/qfcc/TODO @@ -18,5 +18,6 @@ o isset() intrinsic for more consistent string handling. o arrays in entities o optional arguments for functions (alternative to overloading) vector(vector fwd, optional vector up) vectoangles = #51; +o rewrite type system to be const-correct (hard!) ? try to reduce memory consumption ?? embedded nul characters in strings (why?) diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 538bb8f65..eb376e0ea 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -177,7 +177,10 @@ parse_params (type_t *type, param_t *parms) internal_error (0, 0); new->t.func.num_params = -(new->t.func.num_params + 1); } else if (p->type) { - new->t.func.param_types[new->t.func.num_params] = p->type; + // FIXME this cast should not be necessary, but making the + // type system const-correct would probably take a rewrite + type_t *t = (type_t *) unalias_type (p->type); + new->t.func.param_types[new->t.func.num_params] = t; new->t.func.num_params++; } } From 4cec3bbff6aa749490ae8a947b6f65c288d9278d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 17:49:09 +0900 Subject: [PATCH 102/444] Unalias types when checking cast-compatibility This fixes the problem with passing typedefs to function parameters. --- tools/qfcc/source/expr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 9ad394a07..c23460b06 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2374,7 +2374,7 @@ cast_expr (type_t *dstType, expr_t *e) srcType = get_type (e); - if (dstType == srcType) + if (unalias_type (dstType) == unalias_type (srcType)) return e; if ((dstType == type_default && is_enum (srcType)) From 6fccfdf1b9888fbb76075fdb06e50e2da6ff08b1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 18:03:00 +0900 Subject: [PATCH 103/444] Fix a thinko in the save game menu I thought I had to prepend the gamedir when using QFS_FOpenFile (or QFS_OpenFile in rua). Nope, it's gamedir based --- ruamoko/cl_menu/client_menu.r | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ruamoko/cl_menu/client_menu.r b/ruamoko/cl_menu/client_menu.r index 840eac1c8..67f9e80f1 100644 --- a/ruamoko/cl_menu/client_menu.r +++ b/ruamoko/cl_menu/client_menu.r @@ -142,12 +142,13 @@ void (int quick) scan_saves = max = MAX_QUICK; basename = "quick"; } - string gamedir = QFS_GetDirectory(); for (i = 0; i < max; i++) { if (!filenames[i]) filenames[i] = str_new (); loadable[i] = 0; - f = QFS_OpenFile (sprintf ("%s/%s%i.sav", gamedir, basename, i)); + string path = sprintf ("%s%i.sav", basename, i); + dprint(path + "\n"); + f = QFS_OpenFile (path); if (!f) { str_copy (filenames[i], "--- UNUSED SLOT ---"); continue; From 0f4d89a832ce285352ac9478ef0e6021a0de4a67 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 18:19:21 +0900 Subject: [PATCH 104/444] Move free_fmt_items into strings resources This will make it per-thread. --- libs/gamecode/pr_strings.c | 128 ++++++++++++++++++------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index cb74797a5..6d39b8481 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -44,44 +44,6 @@ #include "QF/progs.h" #include "QF/va.h" -typedef struct strref_slot_s { - struct strref_slot_s *next; - struct strref_slot_s **prev; - strref_t *strref; -} strref_slot_t; - -typedef struct prstr_resources_s { - progs_t *pr; - dstring_mem_t ds_mem; - strref_t *free_string_refs; - strref_t *static_strings; - strref_t **string_map; - strref_slot_t return_strings[PR_RS_SLOTS]; - strref_slot_t *rs_slot; - unsigned dyn_str_size; - struct hashtab_s *strref_hash; - int num_strings; -} prstr_resources_t; - -typedef enum { - str_free, - str_static, - str_dynamic, - str_mutable, - str_temp, - str_return, -} str_e; - -struct strref_s { - strref_t *next; - strref_slot_t *rs_slot; - str_e type; - union { - char *string; - dstring_t *dstring; - } s; -}; - // format adjustments #define FMT_ALTFORM (1<<0) #define FMT_LJUSTIFY (1<<1) @@ -106,7 +68,44 @@ typedef struct fmt_item_s { struct fmt_item_s *next; } fmt_item_t; -static fmt_item_t *free_fmt_items; +typedef struct strref_slot_s { + struct strref_slot_s *next; + struct strref_slot_s **prev; + strref_t *strref; +} strref_slot_t; + +typedef struct prstr_resources_s { + progs_t *pr; + dstring_mem_t ds_mem; + strref_t *free_string_refs; + strref_t *static_strings; + strref_t **string_map; + strref_slot_t return_strings[PR_RS_SLOTS]; + strref_slot_t *rs_slot; + unsigned dyn_str_size; + struct hashtab_s *strref_hash; + int num_strings; + fmt_item_t *free_fmt_items; +} prstr_resources_t; + +typedef enum { + str_free, + str_static, + str_dynamic, + str_mutable, + str_temp, + str_return, +} str_e; + +struct strref_s { + strref_t *next; + strref_slot_t *rs_slot; + str_e type; + union { + char *string; + dstring_t *dstring; + } s; +}; static void * pr_strings_alloc (void *_pr, size_t size) @@ -694,30 +693,30 @@ I_DoPrint (dstring_t *result, fmt_item_t *formatting) } static fmt_item_t * -new_fmt_item (void) +new_fmt_item (prstr_resources_t *res) { int i; fmt_item_t *fi; - if (!free_fmt_items) { - free_fmt_items = malloc (16 * sizeof (fmt_item_t)); + if (!res->free_fmt_items) { + res->free_fmt_items = malloc (16 * sizeof (fmt_item_t)); for (i = 0; i < 15; i++) - free_fmt_items[i].next = free_fmt_items + i + 1; - free_fmt_items[i].next = 0; + res->free_fmt_items[i].next = res->free_fmt_items + i + 1; + res->free_fmt_items[i].next = 0; } - fi = free_fmt_items; - free_fmt_items = fi->next; + fi = res->free_fmt_items; + res->free_fmt_items = fi->next; memset (fi, 0, sizeof (*fi)); fi->precision = -1; return fi; } static void -free_fmt_item (fmt_item_t *fi) +free_fmt_item (prstr_resources_t *res, fmt_item_t *fi) { - fi->next = free_fmt_items; - free_fmt_items = fi; + fi->next = res->free_fmt_items; + res->free_fmt_items = fi; } #undef P_var @@ -728,6 +727,7 @@ VISIBLE void PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, const char *format, int count, pr_type_t **args) { + prstr_resources_t *res = pr->pr_string_resources; const char *c, *l; const char *msg = ""; fmt_item_t *fmt_items = 0; @@ -737,7 +737,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, if (!name) name = "PR_Sprintf"; - *fi = new_fmt_item (); + *fi = new_fmt_item (res); c = l = format; while (*c) { if (*c++ == '%') { @@ -747,14 +747,14 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->type = 's'; (*fi)->data.string_var = l; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; } if (*c == '%') { (*fi)->type = 's'; (*fi)->data.string_var = "%"; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; } else { do { @@ -802,7 +802,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, case '@': // object fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'e': @@ -812,7 +812,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, P_EDICTNUM (pr, fmt_count); fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'i': @@ -823,7 +823,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.integer_var = P_INT (pr, fmt_count); fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'f': @@ -842,7 +842,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, } fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'p': @@ -852,7 +852,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.uinteger_var = P_UINT (pr, fmt_count); fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 's': @@ -861,7 +861,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.string_var = P_GSTRING (pr, fmt_count); fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'v': @@ -888,7 +888,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->type = 's'; (*fi)->data.string_var = " "; } - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; (*fi)->flags = flags; @@ -898,7 +898,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.float_var = P_VECTOR (pr, fmt_count)[i]; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; } } @@ -907,7 +907,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.string_var = "'"; fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; case 'x': @@ -916,7 +916,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->data.uinteger_var = P_UINT (pr, fmt_count); fmt_count++; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); fi = &(*fi)->next; break; } @@ -932,7 +932,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, (*fi)->type = 's'; (*fi)->data.string_var = l; - (*fi)->next = new_fmt_item (); + (*fi)->next = new_fmt_item (res); } if (fmt_count != count) { @@ -947,7 +947,7 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, I_DoPrint (result, fmt_items); while (fmt_items) { fmt_item_t *t = fmt_items->next; - free_fmt_item (fmt_items); + free_fmt_item (res, fmt_items); fmt_items = t; } return; From 36bc139b274bf2279463404249fdc5159d8f45b6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 18:35:19 +0900 Subject: [PATCH 105/444] Avoid use of va in PR_Sprintf With this, progs strings are thread safe so long as only one thread tries to use the VM. --- libs/gamecode/pr_strings.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index 6d39b8481..4e2acca11 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -86,6 +86,7 @@ typedef struct prstr_resources_s { struct hashtab_s *strref_hash; int num_strings; fmt_item_t *free_fmt_items; + dstring_t *print_str; } prstr_resources_t; typedef enum { @@ -623,10 +624,9 @@ PR_FreeTempStrings (progs_t *pr) list item. */ static void -I_DoPrint (dstring_t *result, fmt_item_t *formatting) +I_DoPrint (dstring_t *tmp, dstring_t *result, fmt_item_t *formatting) { fmt_item_t *current = formatting; - dstring_t *tmp = dstring_new (); while (current) { qboolean doPrecision, doWidth; @@ -689,7 +689,6 @@ I_DoPrint (dstring_t *result, fmt_item_t *formatting) } current = current->next; } - dstring_delete (tmp); } static fmt_item_t * @@ -940,11 +939,13 @@ PR_Sprintf (progs_t *pr, dstring_t *result, const char *name, msg = "Not enough arguments for format string."; else msg = "Too many arguments for format string."; - msg = va ("%s: %d %d", msg, fmt_count, count); + dsprintf (res->print_str, "%s: %d %d", msg, fmt_count, count); + msg = res->print_str->str; goto error; } - I_DoPrint (result, fmt_items); + dstring_clear (res->print_str); + I_DoPrint (res->print_str, result, fmt_items); while (fmt_items) { fmt_item_t *t = fmt_items->next; free_fmt_item (res, fmt_items); @@ -960,6 +961,7 @@ PR_Strings_Init (progs_t *pr) { prstr_resources_t *res = calloc (1, sizeof (*res)); res->pr = pr; + res->print_str = dstring_new (); PR_Resources_Register (pr, "Strings", res, pr_strings_clear); PR_AddLoadFunc (pr, PR_LoadStrings); From ddd007e2d56bcff50f6aafe16a5186b389bd70c1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 19:00:19 +0900 Subject: [PATCH 106/444] [dstring] Return the string instead of printed size Other than consistency with printf(), I'm not sure why we went with the printed size as the return value; returning the resultant strings makes much more sense as dsprintf() (etc) can then be used as a safe va() --- include/QF/dstring.h | 8 ++++---- libs/util/dstring.c | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/include/QF/dstring.h b/include/QF/dstring.h index bb5ea9117..937e9be54 100644 --- a/include/QF/dstring.h +++ b/include/QF/dstring.h @@ -164,15 +164,15 @@ void dstring_clearstr (dstring_t *dstr); /** Formatted printing to dstrings. Existing data is replaced by the formatted string. */ -int dvsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); -int dsprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); +char *dvsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); +char *dsprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); ///@} ///@{ /** Formatted printing to dstrings. Formatted string is appened to the dstring. Embedded nulls in the dstring are ignored. */ -int davsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); -int dasprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); +char *davsprintf (dstring_t *dstr, const char *fmt, va_list args) __attribute__((format(printf,2,0))); +char *dasprintf (dstring_t *dstr, const char *fmt, ...) __attribute__((format(printf,2,3))); ///@} ///@} diff --git a/libs/util/dstring.c b/libs/util/dstring.c index 18d83f44a..fb495403c 100644 --- a/libs/util/dstring.c +++ b/libs/util/dstring.c @@ -299,7 +299,7 @@ dstring_clearstr (dstring_t *dstr) dstr->str[0] = 0; } -static __attribute__((format(printf, 3, 0))) int +static __attribute__((format(printf, 3, 0))) char * _dvsprintf (dstring_t *dstr, int offs, const char *fmt, va_list args) { int size; @@ -325,20 +325,20 @@ _dvsprintf (dstring_t *dstr, int offs, const char *fmt, va_list args) } dstr->size = size + offs + 1; dstr->str[dstr->size - 1] = 0; - return size; + return dstr->str; } -VISIBLE int +VISIBLE char * dvsprintf (dstring_t *dstr, const char *fmt, va_list args) { return _dvsprintf (dstr, 0, fmt, args); } -VISIBLE int +VISIBLE char * dsprintf (dstring_t *dstr, const char *fmt, ...) { va_list args; - int ret; + char *ret; va_start (args, fmt); ret = _dvsprintf (dstr, 0, fmt, args); @@ -347,7 +347,7 @@ dsprintf (dstring_t *dstr, const char *fmt, ...) return ret; } -VISIBLE int +VISIBLE char * davsprintf (dstring_t *dstr, const char *fmt, va_list args) { int offs = 0; @@ -357,11 +357,11 @@ davsprintf (dstring_t *dstr, const char *fmt, va_list args) return _dvsprintf (dstr, offs, fmt, args); } -VISIBLE int +VISIBLE char * dasprintf (dstring_t *dstr, const char *fmt, ...) { va_list args; - int ret; + char *ret; int offs = 0; if (dstr->size) From 62b541793dddb7a4564d1c2eab1dadaf8c4ee19a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 19:30:10 +0900 Subject: [PATCH 107/444] [gamecode] Remove all use of va With this, the VA is very close to being safe to use in a threaded environment (so long as each VM is used by only one thread). Just the debug file hash and source paths to sort out. --- libs/gamecode/pr_builtins.c | 1 - libs/gamecode/pr_debug.c | 83 ++++++++++++++++++------------------- libs/gamecode/pr_strings.c | 1 - 3 files changed, 41 insertions(+), 44 deletions(-) diff --git a/libs/gamecode/pr_builtins.c b/libs/gamecode/pr_builtins.c index 12c2e6050..7e4bb4431 100644 --- a/libs/gamecode/pr_builtins.c +++ b/libs/gamecode/pr_builtins.c @@ -47,7 +47,6 @@ #include "QF/quakefs.h" #include "QF/sys.h" #include "QF/zone.h" -#include "QF/va.h" #include "compat.h" diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index f7f3f3b7c..3ae9a972e 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -52,7 +52,6 @@ #include "QF/quakefs.h" #include "QF/script.h" #include "QF/sys.h" -#include "QF/va.h" #include "QF/zone.h" #include "compat.h" @@ -74,6 +73,9 @@ typedef struct { typedef struct prdeb_resources_s { progs_t *pr; dstring_t *string; + dstring_t *dva; + dstring_t *line; + dstring_t *dstr; const char *debugfile; struct pr_debug_header_s *debug; struct pr_auxfunction_s *auxfunctions; @@ -328,11 +330,10 @@ pr_debug_clear (progs_t *pr, void *data) { __auto_type res = (prdeb_resources_t *) data; - if (res->string) { - dstring_clearstr (res->string); - } else { - res->string = dstring_newstr (); - } + dstring_clearstr (res->string); + dstring_clearstr (res->dva); + dstring_clearstr (res->line); + dstring_clearstr (res->dstr); if (res->debug) pr->free_progs_mem (pr, res->debug); @@ -353,6 +354,7 @@ pr_debug_clear (progs_t *pr, void *data) static file_t * PR_Load_Source_File (progs_t *pr, const char *fname) { + prdeb_resources_t *res = pr->pr_debug_resources; char *l, *p, **dir; file_t *f = Hash_Find (file_hash, fname); @@ -362,8 +364,8 @@ PR_Load_Source_File (progs_t *pr, const char *fname) if (!f) return 0; for (dir = source_paths; *dir && !f->text; dir++) { - f->text = pr->load_file (pr, va ("%s%s%s", *dir, **dir ? "/" : "", - fname), + f->text = pr->load_file (pr, dsprintf (res->dva, "%s%s%s", *dir, + **dir ? "/" : "", fname), &f->size); } if (!f->text) { @@ -651,6 +653,7 @@ PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) const char * PR_Get_Source_Line (progs_t *pr, pr_uint_t addr) { + prdeb_resources_t *res = pr->pr_debug_resources; const char *fname; pr_uint_t line; file_t *file; @@ -670,10 +673,11 @@ PR_Get_Source_Line (progs_t *pr, pr_uint_t addr) file = PR_Load_Source_File (pr, fname); if (!file || !file->lines || !line || line > file->num_lines) - return va ("%s:%u", fname, line); + return dsprintf (res->dva, "%s:%u", fname, line); - return va ("%s:%u:%.*s", fname, line, (int)file->lines[line - 1].len, - file->lines[line - 1].text); + return dsprintf (res->dva, "%s:%u:%.*s", fname, line, + (int)file->lines[line - 1].len, + file->lines[line - 1].text); } pr_def_t * @@ -1210,9 +1214,9 @@ PR_Debug_Watch (progs_t *pr, const char *expr) VISIBLE void PR_Debug_Print (progs_t *pr, const char *expr) { + prdeb_resources_t *res = pr->pr_debug_resources; pr_def_t print; - dstring_t *dstr = dstring_newstr(); - pr_debug_data_t data = {pr, dstr}; + pr_debug_data_t data = {pr, res->dstr}; if (!expr) { Sys_Printf ("print \n"); @@ -1224,7 +1228,6 @@ PR_Debug_Print (progs_t *pr, const char *expr) const char *s = global_string (&data, print.ofs, print.type, 1); Sys_Printf ("[%d] = %s\n", print.ofs, s); } - dstring_delete (dstr); } VISIBLE void @@ -1235,21 +1238,13 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) int dump_code = contents & 2; const char *fmt; opcode_t *op; - static dstring_t *line; - static dstring_t *dstr; dfunction_t *call_func = 0; pr_def_t *parm_def = 0; pr_auxfunction_t *aux_func = 0; pr_debug_data_t data; - if (!line) { - line = dstring_new (); - dstr = dstring_new (); - } - dstring_clearstr (line); - data.pr = pr; - data.dstr = dstr; + data.dstr = res->dstr; if (pr_debug->int_val > 1) dump_code = 1; @@ -1258,7 +1253,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) const char *source_line = PR_Get_Source_Line (pr, addr); if (source_line) { - dasprintf (line, "%s%s", source_line, dump_code ? "\n" : ""); + dasprintf (res->line, "%s%s", source_line, dump_code ? "\n" : ""); if (!dump_code) goto do_print; } @@ -1268,27 +1263,27 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) op = PR_Opcode (s->op); if (!op) { - Sys_Printf ("%sUnknown instruction %d\n", line->str, s->op); + Sys_Printf ("%sUnknown instruction %d\n", res->line->str, s->op); return; } if (!(fmt = op->fmt)) fmt = "%Ga, %Gb, %gc"; - dasprintf (line, "%04x ", addr); + dasprintf (res->line, "%04x ", addr); if (pr_debug->int_val > 2) - dasprintf (line, "%02x %04x(%8s) %04x(%8s) %04x(%8s)\t", + dasprintf (res->line, "%02x %04x(%8s) %04x(%8s) %04x(%8s)\t", s->op, s->a, pr_type_name[op->type_a], s->b, pr_type_name[op->type_b], s->c, pr_type_name[op->type_c]); - dasprintf (line, "%s ", op->opname); + dasprintf (res->line, "%s ", op->opname); while (*fmt) { if (*fmt == '%') { if (fmt[1] == '%') { - dstring_appendsubstr (line, fmt + 1, 1); + dstring_appendsubstr (res->line, fmt + 1, 1); fmt += 2; } else { const char *str; @@ -1365,10 +1360,11 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) str = global_string (&data, opval, optype, 0); break; case 's': - str = va ("%d", (short) opval); + str = dsprintf (res->dva, "%d", (short) opval); break; case 'O': - str = va ("%04x", addr + (short) opval); + str = dsprintf (res->dva, "%04x", + addr + (short) opval); break; case 'E': { @@ -1387,25 +1383,26 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) } str = global_string (&data, opval, optype, contents & 1); - str = va ("$%x $%x %s", s->a, s->b, str); + str = dsprintf (res->dva, "$%x $%x %s", + s->a, s->b, str); } break; default: goto err; } - dstring_appendstr (line, str); + dstring_appendstr (res->line, str); fmt += 3; continue; err: - dstring_appendstr (line, fmt); + dstring_appendstr (res->line, fmt); break; } } else { - dstring_appendsubstr (line, fmt++, 1); + dstring_appendsubstr (res->line, fmt++, 1); } } do_print: - Sys_Printf ("%s\n", line->str); + Sys_Printf ("%s\n", res->line->str); } static void @@ -1497,6 +1494,7 @@ PR_Profile (progs_t * pr) VISIBLE void ED_Print (progs_t *pr, edict_t *ed) { + prdeb_resources_t *res = pr->pr_debug_resources; int l; pr_uint_t i, j; const char *name; @@ -1504,8 +1502,7 @@ ED_Print (progs_t *pr, edict_t *ed) pr_type_t *v; qfot_type_t dummy_type = { }; qfot_type_t *type; - dstring_t *dstr = dstring_newstr(); - pr_debug_data_t data = {pr, dstr}; + pr_debug_data_t data = {pr, res->dstr}; if (ed->free) { Sys_Printf ("FREE\n"); @@ -1538,12 +1535,10 @@ ED_Print (progs_t *pr, edict_t *ed) if (l < 1) l = 1; - dstring_clearstr (dstr); + dstring_clearstr (res->dstr); value_string (&data, type, v); - Sys_Printf ("%s%*s%s\n", name, l, "", dstr->str); + Sys_Printf ("%s%*s%s\n", name, l, "", res->dstr->str); } - - dstring_delete (dstr); } void @@ -1551,6 +1546,10 @@ PR_Debug_Init (progs_t *pr) { prdeb_resources_t *res = calloc (1, sizeof (*res)); res->pr = pr; + res->string = dstring_newstr (); + res->dva = dstring_newstr (); + res->line = dstring_newstr (); + res->dstr = dstring_newstr (); PR_Resources_Register (pr, "PR_Debug", res, pr_debug_clear); if (!file_hash) { diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index 4e2acca11..ff5e1ffab 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -42,7 +42,6 @@ #include "QF/dstring.h" #include "QF/hash.h" #include "QF/progs.h" -#include "QF/va.h" // format adjustments #define FMT_ALTFORM (1<<0) From 126f8502bd1f1af53455ed7ed73d2e127c3a35b5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 26 Feb 2020 22:10:59 +0900 Subject: [PATCH 108/444] Start working on a qwaq console tool The intention is it will hopefully become a debugger. It will certainly help with development of the progs engine. --- config.d/build_control.m4 | 5 +- config.d/curses.m4 | 27 ++++- tools/qwaq/Makefile.am | 23 +++-- tools/qwaq/defs.qc | 22 ----- tools/qwaq/main.c | 39 ++++---- tools/qwaq/main.qc | 114 --------------------- tools/qwaq/qwaq-curses.c | 54 ++++++++++ tools/qwaq/test.r | 42 -------- tools/qwaq/types.r | 203 -------------------------------------- 9 files changed, 119 insertions(+), 410 deletions(-) delete mode 100644 tools/qwaq/defs.qc delete mode 100644 tools/qwaq/main.qc create mode 100644 tools/qwaq/qwaq-curses.c delete mode 100644 tools/qwaq/test.r delete mode 100644 tools/qwaq/types.r diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index 13004a6c8..a53bf74a4 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -227,7 +227,10 @@ if test "x$ENABLE_tools_qfvis" = xyes; then QF_NEED(libs,[util]) fi if test "x$ENABLE_tools_qwaq" = xyes; then - QF_NEED(tools,[qwaq]) + if test "x$HAVE_PANEL" = xyes -a "x$HAVE_PTHREAD" = xyes; then + QWAQ_TARGETS="$QWAQ_TARGETS qwaq-curses\$(EXEEXT)" + fi + QF_NEED(tools,[qfcc qwaq]) QF_NEED(libs,[ruamoko gamecode util]) fi if test "x$ENABLE_tools_wad" = xyes; then diff --git a/config.d/curses.m4 b/config.d/curses.m4 index 80a2b0415..073e98217 100644 --- a/config.d/curses.m4 +++ b/config.d/curses.m4 @@ -2,7 +2,7 @@ AC_ARG_ENABLE(curses, [ --disable-curses disable curses support] ) if test "x$enable_curses" != "xno"; then - AC_CHECK_HEADERS(curses.h) + AC_CHECK_HEADER(curses.h) AC_CHECK_LIB(ncurses, initscr, CURSES_LIBS=-lncurses, AC_CHECK_LIB(pdcurses, initscr, @@ -13,7 +13,32 @@ if test "x$enable_curses" != "xno"; then ) ) ) + if test "x$CURSES_LIBS" != "x"; then + AC_DEFINE(HAVE_CURSES, 1, [Define if you have the ncurses library]) + HAVE_CURSES=yes + else + HAVE_CURSES=no + fi else + HAVE_CURSES=no CURSES_LIBS= fi AC_SUBST(CURSES_LIBS) + +if test "x$HAVE_CURSES" == "xyes"; then + AC_CHECK_HEADER(panel.h, + [AC_CHECK_LIB(panel, new_panel, + [AC_DEFINE(HAVE_PANEL, 1, + [Define if you have the ncurses panel library]) + PANEL_LIBS=-lpanel + HAVE_PANEL=yes], + [HAVE_PANEL=no], + $CURSES_LIBS + )], + HAVE_PANEL=no, + [] + ) +else + PANEL_LIBS= +fi +AC_SUBST(PANEL_LIBS) diff --git a/tools/qwaq/Makefile.am b/tools/qwaq/Makefile.am index dd34fd9c5..104a7743d 100644 --- a/tools/qwaq/Makefile.am +++ b/tools/qwaq/Makefile.am @@ -2,21 +2,24 @@ QWAQ_LIBS=@QWAQ_LIBS@ QWAQ_DEPS=@QWAQ_DEPS@ QWAQ_INCS=@QWAQ_INCS@ -AM_CPPFLAGS= -I$(top_srcdir)/include $(QWAQ_INCS) +AM_CPPFLAGS= -I$(top_srcdir)/include $(QWAQ_INCS) $(PTHREAD_CFLAGS) QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QFCC=$(top_builddir)/tools/qfcc/source/qfcc QCFLAGS=-qq -O -g -Werror --advanced --no-default-paths -noinst_PROGRAMS=qwaq @QWAQ_TARGETS@ -noinst_DATA=qwaq.dat +noinst_PROGRAMS=@QWAQ_TARGETS@ +noinst_DATA= #qwaq.dat qwaq_dat_src= \ - defs.qc main.qc test.r types.r + $e -qwaq_SOURCES= main.c builtins.c -qwaq_LDADD= $(QWAQ_LIBS) -qwaq_DEPENDENCIES= $(QWAQ_DEPS) +qwaq_curses_libs= +qwaq_curses_SOURCES=main.c qwaq-curses.c +qwaq_curses_LDADD= $(qwaq_curses_libs) $(QWAQ_LIBS) \ + $(PANEL_LIBS) $(CURSES_LIBS) $(PTHREAD_LDFLAGS) $(DL_LIBS) +qwaq_curses_LDFLAGS= +qwaq_curses_DEPENDENCIES= $(qwaq_curses_libs) $(QWAQ_DEPS) cl_plugin_libs= \ @client_static_plugin_libs@ @@ -42,9 +45,9 @@ qwaq_x11_LDADD= $(qwaq_x11_libs) $(QWAQ_LIBS) \ qwaq_x11_LDFLAGS= qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS) -qwaq.dat: progs.src $(qwaq_dat_src) $(QFCC_DEP) $(top_srcdir)/ruamoko/lib/Object.r - $(QFCC) $(QCFLAGS) -I$(top_srcdir)/ruamoko/include +#qwaq.dat: $(qwaq_dat_src) $(QFCC_DEP) $(top_srcdir)/ruamoko/lib/Object.r +# $(QFCC) $(QCFLAGS) -I$(top_srcdir)/ruamoko/include -EXTRA_PROGRAMS=qwaq-x11 +EXTRA_PROGRAMS=qwaq-curses qwaq-x11 EXTRA_DIST=$(qwaq_dat_src) qwaq.h CLEANFILES= *.dat *.sym diff --git a/tools/qwaq/defs.qc b/tools/qwaq/defs.qc deleted file mode 100644 index e872fb799..000000000 --- a/tools/qwaq/defs.qc +++ /dev/null @@ -1,22 +0,0 @@ -void (string str) print = #0; -int () errno = #0; -string (int err) strerror = #0; -int (...) open = #0; // string path, float flags[, float mode] -int (int handle) close = #0; -string read (int handle, int count, int *result) = #0; -int (int handle, string buffer, int count) write = #0; -int (int handle, int pos, int whence) seek = #0; - -//void() traceon = #0; // turns statment trace on -//void() traceoff = #0; - -void (...) printf = #0; - - -float time; -entity self; - -.float nextthink; -.void() think; -.float frame; -.vector origin; diff --git a/tools/qwaq/main.c b/tools/qwaq/main.c index 7f51ea6df..357579290 100644 --- a/tools/qwaq/main.c +++ b/tools/qwaq/main.c @@ -33,24 +33,27 @@ #include -#include -#include -#include -#include +#include "QF/cbuf.h" +#include "QF/cmd.h" +#include "QF/cvar.h" +#include "QF/gib.h" +#include "QF/idparse.h" +#include "QF/progs.h" +#include "QF/qargs.h" +#include "QF/quakefs.h" #include "QF/ruamoko.h" -#include +#include "QF/sys.h" #include "QF/va.h" -#include +#include "QF/zone.h" #include "qwaq.h" #define MAX_EDICTS 1024 -static edict_t *edicts; -static int num_edicts; -static int reserved_edicts; static progs_t pr; +cbuf_t *qwaq_cbuf; + static QFile * open_file (const char *path, int *len) { @@ -100,17 +103,18 @@ free_progs_mem (progs_t *pr, void *mem) static void init_qf (void) { - Sys_Init (); - //Cvar_Get ("developer", "128", 0, 0, 0); + qwaq_cbuf = Cbuf_New (&id_interp); - Memory_Init (malloc (1024 * 1024), 1024 * 1024); + Sys_Init (); + COM_ParseConfig (); + + //Cvar_Set (developer, "1"); + + Memory_Init (malloc (8 * 1024 * 1024), 8 * 1024 * 1024); Cvar_Get ("pr_debug", "2", 0, 0, 0); Cvar_Get ("pr_boundscheck", "0", 0, 0, 0); - pr.edicts = &edicts; - pr.num_edicts = &num_edicts; - pr.reserved_edicts = &reserved_edicts; pr.load_file = load_file; pr.allocate_progs_mem = allocate_progs_mem; pr.free_progs_mem = free_progs_mem; @@ -119,7 +123,7 @@ init_qf (void) PR_Init_Cvars (); PR_Init (&pr); RUA_Init (&pr, 0); - PR_Cmds_Init(&pr); + PR_Cmds_Init (&pr); BI_Init (&pr); } @@ -144,7 +148,7 @@ load_progs (const char *name) } int -main (int argc, char **argv) +main (int argc, const char **argv) { dfunction_t *dfunc; func_t main_func = 0; @@ -152,6 +156,7 @@ main (int argc, char **argv) string_t *pr_argv; int pr_argc = 1, i; + COM_InitArgv (argc, argv); init_qf (); if (argc > 1) diff --git a/tools/qwaq/main.qc b/tools/qwaq/main.qc deleted file mode 100644 index 25cfaabdb..000000000 --- a/tools/qwaq/main.qc +++ /dev/null @@ -1,114 +0,0 @@ -string read_file (string filename) -{ - local QFile file; - local string data = nil, d; - file = Qopen (filename, "rtz"); - if (!file) { - printf ("Can't open %s for reading." - " Probably a bad hardcoded filename:)\n", filename); - return nil; - } - while ((d = Qgetline (file))) - data = data + d; - //FIXME can't read to a string, can't convert a pointer to a string ... - //Qread (file, data, 1023); - Qclose (file); - d = str_new (); - str_copy (d, data); - return d; -} - -void test_plist (void) -{ - local string data, l; - local plitem_t pl, item, i; - - data = read_file ("/home/bill/.quakeforge/gamedir.conf"); - pl = PL_GetPropertyList ("{" + data + "}"); - l = PL_WritePropertyList (pl); - printf ("%s", data); - printf ("%s", l); - i = PL_ObjectForKey (pl, "QF"); - item = PL_RemoveObjectForKey (pl, "QF"); - l = PL_WritePropertyList (item); - printf ("%s", l); - PL_Free (item); - //Because i and item both point to the same plitem, and item has been, - //freed, freeing i will generate an error - //l = PL_WritePropertyList (i); - PL_Free (pl); - str_free (data); -} - -void test_script (void) -{ - local script_t script; - local string token; - local string data; - - data = read_file ("progs.src"); - script = Script_New (); - token = Script_Start (script, "progs.src", data); - while (Script_GetToken (script, 1)) { - printf ("%s\n", token); - } - Script_Delete (script); - str_free (data); -} - -void () test_str = -{ - local string a,b,c,d; - a = "testing "; - b = "temp "; - c = "strings "; - d = "\n"; - print (a + b + c + d); - printf ("%i \"%.5s\" %3.4f %v\n", 14, "hi there", 3.1415926, '4 1 3'); -}; -void (...) dprint = #0; -int main (int argc, string *argv) -{ - local int i; - local SEL sel; - dprint ("foo", "bar\n"); - for (i = 0; i < argc; i++) { - print (argv[i]); - print ("\n"); - } - local id foo = [[Foo alloc] init]; - [foo run]; - sel = sel_get_uid ("run"); - if (sel) { - print ("found selector for `run'\n"); - if ([foo respondsToSelector:sel]) - print ("foo responds to `run'\n"); - else - print ("foo does not repond to `run'\n"); - } else - print ("did not find selector for `run'\n"); - sel = sel_get_uid ("alloc"); - if (sel) { - print ("found selector for `alloc'\n"); - if ([Object instancesRespondToSelector:sel]) - print ("Object instances respond to `alloc'\n"); - else - print ("Object instances do not repond to `alloc'\n"); - } else - print ("did not find selector for `alloc'\n"); - sel = sel_get_uid ("run:with:me:"); - if (sel) { - print ("found selector for `run:with:me:'\n"); - if ([Object instancesRespondToSelector:sel]) - print ("Object instances respond to `run:with:me:'\n"); - else - print ("Object instances do not repond to `run:with:me:'\n"); - } else - print ("did not find selector for `run:with:me:'\n"); - test_str (); - test_script (); - test_plist (); - test_types (); - test_xdefs (); - return 0; -}; diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c new file mode 100644 index 000000000..71439d0a9 --- /dev/null +++ b/tools/qwaq/qwaq-curses.c @@ -0,0 +1,54 @@ +/* + #FILENAME# + + #DESCRIPTION# + + Copyright (C) 2001 #AUTHOR# + + Author: #AUTHOR# + Date: #DATE# + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "QF/progs.h" +#include "QF/sys.h" + +#include "qwaq.h" + +static builtin_t builtins[] = { + {0} +}; + +static void +bi_shutdown (void) +{ +} + +void +BI_Init (progs_t *pr) +{ + PR_RegisterBuiltins (pr, builtins); + + Sys_RegisterShutdown (bi_shutdown); +} diff --git a/tools/qwaq/test.r b/tools/qwaq/test.r deleted file mode 100644 index 6e0afd6f2..000000000 --- a/tools/qwaq/test.r +++ /dev/null @@ -1,42 +0,0 @@ -@interface Foo : Object -{ - int x; -} --run; -@end - - -@implementation Foo - -+load -{ - print ("+load\n"); - return self; -} - -+alloc -{ - print ("+alloc\n"); - return class_create_instance (self); -} - --init -{ - print ("-init\n"); - return [super init]; -} - -+ (void) initialize -{ - print ("+initialize\n"); -} - --run -{ - print ("Hello world\n"); - printf ("%i %p [%s %s]\n", self, &self.x, [self description], - __PRETTY_FUNCTION__); - return self; -} - -@end diff --git a/tools/qwaq/types.r b/tools/qwaq/types.r deleted file mode 100644 index 5cf874c61..000000000 --- a/tools/qwaq/types.r +++ /dev/null @@ -1,203 +0,0 @@ -#include "runtime.h" //FIXME for PR_FindGlobal -typedef enum { - ev_void, - ev_string, - ev_float, - ev_vector, - ev_entity, - ev_field, - ev_func, - ev_pointer, // end of v6 types - ev_quat, - ev_integer, - ev_uinteger, - ev_short, // value is embedded in the opcode - ev_double, - - ev_invalid, // invalid type. used for instruction checking - ev_type_count // not a type, gives number of types -} etype_t; - -typedef enum { - ty_none, ///< func/field/pointer or not used - ty_struct, - ty_union, - ty_enum, - ty_array, - ty_class, -} ty_meta_e; - - -typedef struct qfot_fldptr_s { - etype_t type; - struct qfot_type_s *aux_type; -} qfot_fldptr_t; - -typedef struct qfot_func_s { - etype_t type; - struct qfot_type_s *return_type; - int num_params; - struct qfot_type_s *param_types[1]; -} qfot_func_t; - -typedef struct qfot_var_s { - struct qfot_type_s *type; - string name; - int offset; // value for enum, 0 for union -} qfot_var_t; - -typedef struct qfot_struct_s { - string tag; - int num_fields; - qfot_var_t fields[1]; -} qfot_struct_t; - -typedef struct qfot_array_s { - struct qfot_type_s *type; - int base; - int size; -} qfot_array_t; - -typedef struct qfot_type_s { - ty_meta_e meta; - int size; - string encoding; - union { - etype_t type; - qfot_fldptr_t fldptr; - qfot_func_t func; - qfot_struct_t strct; - qfot_array_t array; - string class; - } t; -} qfot_type_t; - -typedef struct qfot_type_encodings_s { - qfot_type_t *types; - int size; -} qfot_type_encodings_t; - -typedef struct xdef_s { - qfot_type_t *type; - void *offset; -} xdef_t; - -typedef struct pr_xdefs_s { - xdef_t *xdefs; - int num_xdefs; -} pr_xdefs_t; - -qfot_type_t * -next_type (qfot_type_t *type) -{ - int size = type.size; - if (!size) - size = 4; - return (qfot_type_t *) ((int *) type + size); -} - -string ty_meta_name[6] = { - "basic", - "struct", - "union", - "enum", - "array", - "class", -}; - -string pr_type_name[ev_type_count] = { - "void", - "string", - "float", - "vector", - "entity", - "field", - "function", - "pointer", - "quaternion", - "integer", - "uinteger", - "short", - "double" - "invalid", -}; - -void -test_types (void) -{ - qfot_type_encodings_t *encodings; - qfot_type_t *type; - int i; - - encodings = PR_FindGlobal (".type_encodings"); - if (!encodings) { - printf ("Can't find encodings\n"); - return; - } - for (type = encodings.types; - ((int *)type - (int *) encodings.types) < encodings.size; - type = next_type (type)) { - printf ("%p %-6s %-20s", type, ty_meta_name[type.meta], - type.encoding); - if (!type.size) { - printf ("\n"); - continue; - } - switch (type.meta) { - case ty_none: - printf (" %-10s", pr_type_name[type.t.type]); - if (type.t.type == ev_func) { - int count = type.t.func.num_params; - printf ("%p %d", type.t.func.return_type, count); - if (count < 0) - count = ~count; - for (i = 0; i < count; i++) - printf (" %p", type.t.func.param_types[i]); - } else if (type.t.type == ev_pointer) { - printf (" *%p", type.t.fldptr.aux_type); - } else if (type.t.type == ev_field) { - printf (" .%p", type.t.fldptr.aux_type); - } else { - printf (" %p", type.t.fldptr.aux_type); - } - printf ("\n"); - break; - case ty_struct: - case ty_union: - case ty_enum: - printf (" %s\n", type.t.strct.tag); - for (i = 0; i < type.t.strct.num_fields; i++) { - printf (" %p %4x %s\n", - type.t.strct.fields[i].type, - type.t.strct.fields[i].offset, - type.t.strct.fields[i].name); - } - break; - case ty_array: - printf (" %p %d %d\n", type.t.array.type, - type.t.array.base, type.t.array.size); - break; - case ty_class: - printf (" %s %p\n", type.t.class, - obj_lookup_class (type.t.class)); - break; - } - } -} - -void -test_xdefs (void) -{ - pr_xdefs_t *xdefs; - int i; - - xdefs = PR_FindGlobal (".xdefs"); - if (!xdefs) { - printf ("Can't find xdefs\n"); - return; - } - printf ("%p %i\n", xdefs.xdefs, xdefs.num_xdefs); - for (i = 0; i < xdefs.num_xdefs; i++) { - printf ("%p %p\n", xdefs.xdefs[i].type, xdefs.xdefs[i].offset); - } -} From edde4bad15c9f4910d4e2a333fed0a6d23b9a30b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 01:18:38 +0900 Subject: [PATCH 109/444] Create a basic hello world And it has begun. It has some problems, but worse, it seems I broke qfprogs and maybe pr_debug.c. --- tools/qwaq/Makefile.am | 33 +++++++-- tools/qwaq/main.c | 6 +- tools/qwaq/qwaq-app.r | 23 ++++++ tools/qwaq/qwaq-curses.c | 153 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 204 insertions(+), 11 deletions(-) create mode 100644 tools/qwaq/qwaq-app.r diff --git a/tools/qwaq/Makefile.am b/tools/qwaq/Makefile.am index 104a7743d..b6e9b8345 100644 --- a/tools/qwaq/Makefile.am +++ b/tools/qwaq/Makefile.am @@ -1,15 +1,25 @@ +AUTOMAKE_OPTIONS= foreign + QWAQ_LIBS=@QWAQ_LIBS@ QWAQ_DEPS=@QWAQ_DEPS@ QWAQ_INCS=@QWAQ_INCS@ AM_CPPFLAGS= -I$(top_srcdir)/include $(QWAQ_INCS) $(PTHREAD_CFLAGS) +noinst_PROGRAMS=@QWAQ_TARGETS@ qwaq-app.dat$(EXEEXT) + QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QFCC=$(top_builddir)/tools/qfcc/source/qfcc -QCFLAGS=-qq -O -g -Werror --advanced --no-default-paths -noinst_PROGRAMS=@QWAQ_TARGETS@ -noinst_DATA= #qwaq.dat +QCFLAGS=-qq -O -g -Werror +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) + +SUFFIXES=.o .r +.r.o: + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo qwaq_dat_src= \ $e @@ -45,8 +55,21 @@ qwaq_x11_LDADD= $(qwaq_x11_libs) $(QWAQ_LIBS) \ qwaq_x11_LDFLAGS= qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS) -#qwaq.dat: $(qwaq_dat_src) $(QFCC_DEP) $(top_srcdir)/ruamoko/lib/Object.r -# $(QFCC) $(QCFLAGS) -I$(top_srcdir)/ruamoko/include +r_depfiles_remade= + +qwaq_app_dat_SOURCES=qwaq-app.r +qwaq_app_obj=$(qwaq_app_dat_SOURCES:.r=.o) +qwaq_app_dep=$(addprefix ./$(DEPDIR)/,$(qwaq_app_obj:.o=.Qo)) +qwaq-app.dat$(EXEEXT): $(qwaq_app_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(qwaq_app_obj) +include $(qwaq_app_dep) # am--include-marker +r_depfiles_remade += $(qwaq_app_dep) + +$(r_depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) EXTRA_PROGRAMS=qwaq-curses qwaq-x11 EXTRA_DIST=$(qwaq_dat_src) qwaq.h diff --git a/tools/qwaq/main.c b/tools/qwaq/main.c index 357579290..3f88a428a 100644 --- a/tools/qwaq/main.c +++ b/tools/qwaq/main.c @@ -152,7 +152,7 @@ main (int argc, const char **argv) { dfunction_t *dfunc; func_t main_func = 0; - const char *name = "qwaq.dat"; + const char *name = "qwaq-app.dat"; string_t *pr_argv; int pr_argc = 1, i; @@ -162,8 +162,9 @@ main (int argc, const char **argv) if (argc > 1) name = argv[1]; - if (!load_progs (name)) + if (!load_progs (name)) { Sys_Error ("couldn't load %s", name); + } PR_PushFrame (&pr); if (argc > 2) @@ -185,5 +186,6 @@ main (int argc, const char **argv) pr.pr_argc = 2; PR_ExecuteProgram (&pr, main_func); PR_PopFrame (&pr); + Sys_Shutdown (); return R_INT (&pr); } diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r new file mode 100644 index 000000000..6473ef6a8 --- /dev/null +++ b/tools/qwaq/qwaq-app.r @@ -0,0 +1,23 @@ +typedef struct window_s *window_t; + +void initialize (void) = #0; +window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; +void destroy_window (window_t win) = #0; +void wprintf (window_t win, string fmt, ...) = #0; +int wgetch (window_t win) = #0; + +int main (int argc, string *argv) +{ + int ch; + + initialize (); + window_t win = create_window (20, 5, 50, 10); + wprintf (win, "Hi there!\n"); + do { + ch = wgetch (win); + if (ch) { + wprintf (win, "%d\n", ch); + } + } while (ch != 27); + return 0; +} diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index 71439d0a9..a3f055ae8 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -31,24 +31,169 @@ # include "config.h" #endif +#include +#include +#include + +#include "QF/dstring.h" #include "QF/progs.h" #include "QF/sys.h" #include "qwaq.h" -static builtin_t builtins[] = { - {0} -}; +#define always_inline inline __attribute__((__always_inline__)) +typedef struct window_s { + WINDOW *win; +} window_t; + +typedef struct qwaq_resources_s { + progs_t *pr; + int initialized; + dstring_t *print_buffer; + PR_RESMAP (window_t) window_map; +} qwaq_resources_t; + +static window_t * +window_new (qwaq_resources_t *res) +{ + PR_RESNEW (window_t, res->window_map); +} + +static void +window_free (qwaq_resources_t *res, window_t *win) +{ + PR_RESFREE (window_t, res->window_map, win); +} + +static void +window_reset (qwaq_resources_t *res) +{ + PR_RESRESET (window_t, res->window_map); +} + +static inline window_t * +window_get (qwaq_resources_t *res, unsigned index) +{ + PR_RESGET(res->window_map, index); +} + +static inline int +window_index (qwaq_resources_t *res, window_t *win) +{ + PR_RESINDEX (res->window_map, win); +} + +static always_inline window_t * +get_window (qwaq_resources_t *res, const char *name, int handle) +{ + window_t *window = window_get (res, handle); + + if (!window || !window->win) { + PR_RunError (res->pr, "invalid window passed to %s", name + 3); + } + return window; +} + +static int need_endwin; static void bi_shutdown (void) { + if (need_endwin) { + endwin (); + } } +static void +bi_initialize (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + initscr (); + need_endwin = 1; + res->initialized = 1; + raw (); + keypad (stdscr, TRUE); + noecho (); + nonl (); +} + +static void +bi_create_window (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int xpos = P_INT (pr, 0); + int ypos = P_INT (pr, 1); + int xlen = P_INT (pr, 2); + int ylen = P_INT (pr, 3); + window_t *window = window_new (res); + window->win = newwin (ylen, xlen, ypos, xpos); + keypad (window->win, TRUE); + R_INT (pr) = window_index (res, window); +} + +static void +bi_destroy_window (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); + delwin (window->win); + window->win = 0; + window_free (res, window); +} + +static void +bi_wprintf (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); + const char *fmt = P_GSTRING (pr, 1); + int count = pr->pr_argc - 2; + pr_type_t **args = pr->pr_params + 2; + + PR_Sprintf (pr, res->print_buffer, "bi_wprintf", fmt, count, args); + waddstr (window->win, res->print_buffer->str); + wrefresh (window->win); +} + +static void +bi_wgetch (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); + + R_INT (pr) = wgetch (window->win); +} + +static void +bi_qwaq_clear (progs_t *pr, void *data) +{ + __auto_type res = (qwaq_resources_t *) data; + + if (res->initialized) { + endwin (); + } + need_endwin = 0; + window_reset (res); +} + +static builtin_t builtins[] = { + {"initialize", bi_initialize, -1}, + {"create_window", bi_create_window, -1}, + {"destroy_window", bi_destroy_window, -1}, + {"wprintf", bi_wprintf, -1}, + {"wgetch", bi_wgetch, -1}, + {0} +}; + void BI_Init (progs_t *pr) { - PR_RegisterBuiltins (pr, builtins); + qwaq_resources_t *res = calloc (sizeof (*res), 1); + res->pr = pr; + res->print_buffer = dstring_newstr (); + PR_Resources_Register (pr, "qwaq", res, bi_qwaq_clear); + PR_RegisterBuiltins (pr, builtins); Sys_RegisterShutdown (bi_shutdown); } From c9186c82961af767afc83a90d6e223c5cba2951c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 01:25:41 +0900 Subject: [PATCH 110/444] Clear the statement line buffer The problem with moving to a cached buffer is it needs to be cleared. Fixes the weird output of qfprogs and tracing (not missing local defs, though). --- libs/gamecode/pr_debug.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 3ae9a972e..e7bf90a92 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -1243,6 +1243,8 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) pr_auxfunction_t *aux_func = 0; pr_debug_data_t data; + dstring_clearstr (res->line); + data.pr = pr; data.dstr = res->dstr; From 789f263855b5b94d27295b7552fcbaf580b6a99d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 02:07:53 +0900 Subject: [PATCH 111/444] Use get_strref() correctly I had forgotten that it works only for dynamic strings. --- libs/gamecode/pr_strings.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index ff5e1ffab..4d393776e 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -348,6 +348,9 @@ get_string (progs_t *pr, string_t num) VISIBLE qboolean PR_StringValid (progs_t *pr, string_t num) { + if (num >= 0) { + return num < pr->pr_stringsize; + } return get_strref (pr->pr_string_resources, num) != 0; } From e8c357393f369c853e7fac3932fd825254b57c5d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 02:11:54 +0900 Subject: [PATCH 112/444] [qwaq] Clear qwaq's print buffer Didn't realized PR_Sprintf appended. Or, more likely, I had forgotten because I imagine Deek and I discussed it at the time. --- tools/qwaq/qwaq-curses.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index a3f055ae8..3932298d8 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -151,6 +151,7 @@ bi_wprintf (progs_t *pr) int count = pr->pr_argc - 2; pr_type_t **args = pr->pr_params + 2; + dstring_clearstr (res->print_buffer); PR_Sprintf (pr, res->print_buffer, "bi_wprintf", fmt, count, args); waddstr (window->win, res->print_buffer->str); wrefresh (window->win); From dbbb8a1396de8e948ee30bb2d54fadd1890381b2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 17:43:39 +0900 Subject: [PATCH 113/444] [qfcc] Fix syntax error for id as a field name event.e.mouse.id produced a syntax error, which is contrary to Objective-C. --- tools/qfcc/source/qc-parse.y | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index e64bb748e..8c417a8f5 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -184,7 +184,7 @@ int yylex (void); %type optional_state_expr texpr vector_expr %type statement statements compound_statement %type else label break_label continue_label -%type unary_expr cast_expr opt_arg_list arg_list +%type unary_expr ident_expr cast_expr opt_arg_list arg_list %type init_var_decl_list init_var_decl %type switch_block %type identifier @@ -1288,6 +1288,7 @@ unary_expr | '(' expr ')' { $$ = $2; $$->paren = 1; } | unary_expr '(' opt_arg_list ')' { $$ = function_expr ($1, $3); } | unary_expr '[' expr ']' { $$ = array_expr ($1, $3); } + | unary_expr '.' ident_expr { $$ = field_expr ($1, $3); } | unary_expr '.' unary_expr { $$ = field_expr ($1, $3); } | INCOP unary_expr { $$ = incop_expr ($1, $2, 0); } | unary_expr INCOP { $$ = incop_expr ($2, $1, 1); } @@ -1306,6 +1307,12 @@ unary_expr | obj_expr { $$ = $1; } ; +ident_expr + : OBJECT { $$ = new_symbol_expr ($1); } + | CLASS_NAME { $$ = new_symbol_expr ($1); } + | TYPE_NAME { $$ = new_symbol_expr ($1); } + ; + vector_expr : '[' expr ',' arg_list ']' { From 7c9072aebf84e6eaea4c78978ee6f1210340b004 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 17:50:11 +0900 Subject: [PATCH 114/444] [qfcc] Create struct fields for "type typename" Such declarations were being lost, thus in the following, the id field never got added: typedef struct qwaq_mevent_s { int id; int x, y, z; int buttons; } qwaq_mevent_t; --- tools/qfcc/include/type.h | 1 + tools/qfcc/source/qc-parse.y | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index c8913933e..46d524574 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -81,6 +81,7 @@ typedef struct type_s { typedef struct { type_t *type; struct param_s *params; + struct symbol_s *sym; ///< for dealing with "int id" etc storage_class_t storage; unsigned multi_type:1; unsigned multi_store:1; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 8c417a8f5..dd33aa07c 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -484,6 +484,15 @@ specifiers type : type_specifier | type type_specifier + { + // deal with eg "int id" + $1.sym = $2.sym; + + if (!$1.sym) { + error (0, "two or more data types in declaration specifiers"); + } + $$ = $1; + } ; type_specifier_or_storage_class @@ -501,6 +510,7 @@ type_specifier | TYPE_NAME { $$ = make_spec ($1->type, 0, 0, 0); + $$.sym = $1; } | OBJECT protocolrefs { @@ -512,6 +522,7 @@ type_specifier } else { $$ = make_spec (&type_id, 0, 0, 0); } + $$.sym = $1; } | CLASS_NAME protocolrefs { @@ -523,6 +534,7 @@ type_specifier } else { $$ = make_spec ($1->type, 0, 0, 0); } + $$.sym = $1; } // NOTE: fields don't parse the way they should. This is not a problem // for basic types, but functions need special treatment @@ -656,6 +668,22 @@ struct_def_list struct_def : type struct_decl_list | type + { + if ($1.sym) { + // a type name (id, typedef, etc) was used as a field name. + // this is allowed in C + print_type ($1.type); + printf ("%s\n", $1.sym->name); + $1.sym = new_symbol ($1.sym->name); + $1.sym->type = $1.type; + $1.sym->sy_type = sy_var; + symtab_addsymbol (current_symtab, $1.sym); + } else { + // bare type + warning (0, "declaration does not declare anything"); + } + $$ = $1; + } ; struct_decl_list From b4aebc120ee5f1355de9545b155fc43fedbea426 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 20:30:07 +0900 Subject: [PATCH 115/444] [qfcc] Treat { } as nil for initializing compound types --- tools/qfcc/include/expr.h | 2 +- tools/qfcc/source/def.c | 67 ++++++++++++++++++++++++++++--- tools/qfcc/source/expr.c | 3 +- tools/qfcc/source/qc-parse.y | 7 ++++ tools/qfcc/test/Makefile.am | 10 +++++ tools/qfcc/test/struct-nil-init.r | 12 ++++++ 6 files changed, 93 insertions(+), 8 deletions(-) create mode 100644 tools/qfcc/test/struct-nil-init.r diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 0a030e75a..ac2646dfe 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -614,7 +614,7 @@ void convert_int (expr_t *e); void convert_short (expr_t *e); void convert_short_int (expr_t *e); void convert_double (expr_t *e); -void convert_nil (expr_t *e, struct type_s *t); +expr_t *convert_nil (expr_t *e, struct type_s *t); expr_t *test_expr (expr_t *e); void backpatch (ex_list_t *list, expr_t *label); diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index ed5e69964..049740563 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -287,6 +287,21 @@ def_to_ddef (def_t *def, ddef_t *ddef, int aux) ddef->s_name = ReuseString (def->name); } +static int +zero_memory (expr_t *local_expr, def_t *def, type_t *zero_type, + int init_size, int init_offset) +{ + int zero_size = type_size (zero_type); + expr_t *zero = convert_nil (new_nil_expr (), zero_type); + expr_t *dst; + + for (; init_offset < init_size + 1 - zero_size; init_offset += zero_size) { + dst = new_pointer_expr (init_offset, zero_type, def); + append_expr (local_expr, assign_expr (unary_expr ('.', dst), zero)); + } + return init_offset; +} + static void init_elements (struct def_s *def, expr_t *eles) { @@ -298,6 +313,39 @@ init_elements (struct def_s *def, expr_t *eles) base_offset = def->offset; if (def->local && local_expr) base_offset = 0; + if (eles->type == ex_nil) { + if (def->local && local_expr) { + // memset to 0 + int init_size = type_size (def->type); + int init_offset = 0; + + if (options.code.progsversion != PROG_ID_VERSION) { + init_offset = zero_memory (local_expr, def, &type_zero, + init_size, init_offset); + } + // probably won't happen any time soon, but who knows... + if (options.code.progsversion != PROG_ID_VERSION + && init_size - init_offset >= type_size (&type_quaternion)) { + init_offset = zero_memory (local_expr, def, &type_quaternion, + init_size, init_offset); + } + if (init_size - init_offset >= type_size (&type_vector)) { + init_offset = zero_memory (local_expr, def, &type_vector, + init_size, init_offset); + } + if (options.code.progsversion != PROG_ID_VERSION + && init_size - init_offset >= type_size (&type_double)) { + init_offset = zero_memory (local_expr, def, &type_double, + init_size, init_offset); + } + if (init_size - init_offset >= type_size (type_default)) { + zero_memory (local_expr, def, type_default, + init_size, init_offset); + } + } + // it's a global, so already initialized to 0 + return; + } if (is_array (def->type)) { type_t *array_type = def->type->t.array.type; int array_size = def->type->t.array.size; @@ -334,8 +382,11 @@ init_elements (struct def_s *def, expr_t *eles) } for (count = 0, e = eles->e.block.head; e; count++, e = e->next) { convert_name (e); - if (e->type == ex_nil && count < num_elements) + if (e->type == ex_nil && count < num_elements + && !(is_array (elements[count].type) + || is_struct (elements[count].type))) { convert_nil (e, elements[count].type); + } if (e->type == ex_error) { free (elements); return; @@ -349,7 +400,8 @@ init_elements (struct def_s *def, expr_t *eles) for (i = 0, e = eles->e.block.head; i < count; i++, e = e->next) { g = D_POINTER (pr_type_t, &elements[i]); c = constant_expr (e); - if (c->type == ex_block) { + // nil will not survive as nil to this point if array or struct + if (c->type == ex_block || c->type == ex_nil) { if (!is_array (elements[i].type) && !is_struct (elements[i].type)) { error (e, "type mismatch in initializer"); @@ -567,15 +619,18 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, convert_name (init); if (init->type == ex_error) return; - if (init->type == ex_nil) - convert_nil (init, sym->type); if ((is_array (sym->type) || is_struct (sym->type) || sym->type == &type_vector || sym->type == &type_quaternion) - && init->type == ex_block && !init->e.block.result) { + && ((init->type == ex_block && !init->e.block.result) + || init->type == ex_nil)) { init_elements (sym->s.def, init); sym->s.def->initialized = 1; } else { - type_t *init_type = get_type (init); + type_t *init_type; + if (init->type == ex_nil) { + convert_nil (init, sym->type); + } + init_type = get_type (init); if (!type_assignable (sym->type, init_type)) { error (init, "type mismatch in initializer"); return; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index c23460b06..7d5baddb9 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1325,11 +1325,12 @@ convert_double (expr_t *e) e->e.value = new_float_val (float_val); } -void +expr_t * convert_nil (expr_t *e, type_t *t) { e->type = ex_value; e->e.value = new_nil_val (t); + return e; } int diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index dd33aa07c..07c12692e 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1065,6 +1065,13 @@ opt_initializer var_initializer : '=' expr { $$ = $2; } | '=' '{' element_list optional_comma '}' { $$ = $3; } + | '=' '{' '}' + { + if (is_scalar ($-1.type)) { + error (0, "empty scalar initializer"); + } + $$ = new_nil_expr (); + } ; optional_state_expr diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index e715b38ed..c53dd7cbf 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -48,6 +48,7 @@ test_progs_dat=\ return-ivar.dat \ sendv.dat \ state.dat \ + struct-nil-init.dat \ structarray.dat \ structlive.dat \ structptr.dat \ @@ -301,6 +302,15 @@ state.run: Makefile build-run include ./$(DEPDIR)/state.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/state.Qo +struct_nil_init_dat_SOURCES=struct-nil-init.r +struct_nil_init_obj=$(struct_nil_init_dat_SOURCES:.r=.qfo) +struct-nil-init.dat$(EXEEXT): $(struct_nil_init_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(struct_nil_init_obj) +struct-nil-init.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/struct-nil-init.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/struct-nil-init.Qo + structarray_dat_SOURCES=structarray.r structarray_obj=$(structarray_dat_SOURCES:.r=.qfo) structarray.dat$(EXEEXT): $(structarray_obj) $(QFCC_DEP) diff --git a/tools/qfcc/test/struct-nil-init.r b/tools/qfcc/test/struct-nil-init.r new file mode 100644 index 000000000..065a43b34 --- /dev/null +++ b/tools/qfcc/test/struct-nil-init.r @@ -0,0 +1,12 @@ +#pragma bug die + +struct foo { + quaternion x; + double y; +}; + +int main() +{ + struct foo bar = { }; + return bar.y; // to survive and prevail +} From 08bf8a04e4f53750b8dfb221c8c578b8ae98611a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 21:01:09 +0900 Subject: [PATCH 116/444] [qwaq] Implement an event queue It seems to have an issue with a bogus clearing of the screen, but the basics seem to be working. --- tools/qwaq/event.h | 25 ++++++++++++ tools/qwaq/qwaq-app.r | 25 ++++++++++-- tools/qwaq/qwaq-curses.c | 82 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 tools/qwaq/event.h diff --git a/tools/qwaq/event.h b/tools/qwaq/event.h new file mode 100644 index 000000000..a3591fdca --- /dev/null +++ b/tools/qwaq/event.h @@ -0,0 +1,25 @@ +#ifndef __qwaq_event_h +#define __qwaq_event_h + +typedef enum { + qe_idle, + qe_key, + qe_mouse, +} qwaq_etype; + +// right now, this is just a copy of ncurses MEVENT, but all int +typedef struct qwaq_mevent_s { + int id; // XXX does it matter? + int x, y, z; // z? what? + int buttons; +} qwaq_mevent_t; + +typedef struct qwaq_event_s { + qwaq_etype event_type; + union { + int key; + qwaq_mevent_t mouse; + } e; +} qwaq_event_t; + +#endif//__qwaq_event_h diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index 6473ef6a8..05f07bd68 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -1,3 +1,5 @@ +#include "event.h" + typedef struct window_s *window_t; void initialize (void) = #0; @@ -6,17 +8,32 @@ void destroy_window (window_t win) = #0; void wprintf (window_t win, string fmt, ...) = #0; int wgetch (window_t win) = #0; +void process_input (void) = #0; +int get_event (qwaq_event_t *event) = #0; + int main (int argc, string *argv) { - int ch; + int ch = 0; + qwaq_event_t event = { }; initialize (); window_t win = create_window (20, 5, 50, 10); wprintf (win, "Hi there!\n"); do { - ch = wgetch (win); - if (ch) { - wprintf (win, "%d\n", ch); + process_input (); + + if (get_event (&event)) { + if (event.event_type == qe_key) { + ch = event.e.key; + wprintf (win, "key: %d\n", ch); + } else if (event.event_type == qe_mouse) { + wprintf (win, "mouse: %d %d %d %d %d\n", + event.e.mouse.id, + event.e.mouse.x, + event.e.mouse.y, + event.e.mouse.z, + event.e.mouse.buttons); + } } } while (ch != 27); return 0; diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index 3932298d8..a281c3327 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -40,8 +40,11 @@ #include "QF/sys.h" #include "qwaq.h" +#include "event.h" #define always_inline inline __attribute__((__always_inline__)) +#define QUEUE_SIZE 16 // must be power of 2 greater than 1 +#define QUEUE_MASK (QUEUE_SIZE - 1) typedef struct window_s { WINDOW *win; @@ -52,6 +55,9 @@ typedef struct qwaq_resources_s { int initialized; dstring_t *print_buffer; PR_RESMAP (window_t) window_map; + qwaq_event_t event_queue[QUEUE_SIZE]; + unsigned queue_head; + unsigned queue_tail; } qwaq_resources_t; static window_t * @@ -116,6 +122,8 @@ bi_initialize (progs_t *pr) keypad (stdscr, TRUE); noecho (); nonl (); + nodelay (stdscr, TRUE); + mousemask(ALL_MOUSE_EVENTS, NULL); } static void @@ -166,6 +174,78 @@ bi_wgetch (progs_t *pr) R_INT (pr) = wgetch (window->win); } +static void +add_event (qwaq_resources_t *res, qwaq_event_t *event) +{ + if (((res->queue_head - res->queue_tail) & QUEUE_MASK) != QUEUE_MASK) { + res->event_queue[res->queue_head] = *event; + res->queue_head = (res->queue_head + 1) & QUEUE_MASK; + } +} + +static int +get_event (qwaq_resources_t *res, qwaq_event_t *event) +{ + if (res->queue_head != res->queue_tail) { + if (event) { + *event = res->event_queue[res->queue_tail]; + res->queue_tail = (res->queue_tail + 1) & QUEUE_MASK; + } + return 1; + } + return 0; +} + +static void +mouse_event (qwaq_resources_t *res, MEVENT *mevent) +{ + qwaq_event_t event = {}; + event.event_type = qe_mouse; + event.e.mouse.id = mevent->id; + event.e.mouse.x = mevent->x; + event.e.mouse.y = mevent->y; + event.e.mouse.z = mevent->z; + event.e.mouse.buttons = mevent->bstate; + add_event (res, &event); +} + +static void +key_event (qwaq_resources_t *res, int key) +{ + qwaq_event_t event = {}; + event.event_type = qe_key; + event.e.key = key; + add_event (res, &event); +} + +static void +bi_process_input (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + if (Sys_CheckInput (1, -1)) { + int ch; + while ((ch = getch ()) != ERR && ch) { + fflush (stderr); + if (ch == KEY_MOUSE) { + MEVENT mevent; + getmouse (&mevent); + mouse_event (res, &mevent); + } else { + key_event (res, ch); + } + } + } +} + +static void +bi_get_event (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + qwaq_event_t *event = &G_STRUCT (pr, qwaq_event_t, P_INT (pr, 0)); + + R_INT (pr) = get_event (res, event); +} + static void bi_qwaq_clear (progs_t *pr, void *data) { @@ -184,6 +264,8 @@ static builtin_t builtins[] = { {"destroy_window", bi_destroy_window, -1}, {"wprintf", bi_wprintf, -1}, {"wgetch", bi_wgetch, -1}, + {"process_input", bi_process_input, -1}, + {"get_event", bi_get_event, -1}, {0} }; From a3ed5926b955fa016180c039241c230a62f303b5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 21:08:12 +0900 Subject: [PATCH 117/444] [qwaq] Remove unnecessary fields from mouse events id and z seem to always be 0. Ironically, it turns out that the work needed for "int id" and "large" struct nil init wasn't strictly necessary to get to this point, but without having done that work, I wouldn't know :) --- tools/qwaq/event.h | 3 +-- tools/qwaq/qwaq-app.r | 4 +--- tools/qwaq/qwaq-curses.c | 2 -- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/tools/qwaq/event.h b/tools/qwaq/event.h index a3591fdca..933c61569 100644 --- a/tools/qwaq/event.h +++ b/tools/qwaq/event.h @@ -9,8 +9,7 @@ typedef enum { // right now, this is just a copy of ncurses MEVENT, but all int typedef struct qwaq_mevent_s { - int id; // XXX does it matter? - int x, y, z; // z? what? + int x, y; int buttons; } qwaq_mevent_t; diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index 05f07bd68..1bc2dcbe9 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -27,11 +27,9 @@ int main (int argc, string *argv) ch = event.e.key; wprintf (win, "key: %d\n", ch); } else if (event.event_type == qe_mouse) { - wprintf (win, "mouse: %d %d %d %d %d\n", - event.e.mouse.id, + wprintf (win, "mouse: %d %d %d\n", event.e.mouse.x, event.e.mouse.y, - event.e.mouse.z, event.e.mouse.buttons); } } diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index a281c3327..ccc4b73b1 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -201,10 +201,8 @@ mouse_event (qwaq_resources_t *res, MEVENT *mevent) { qwaq_event_t event = {}; event.event_type = qe_mouse; - event.e.mouse.id = mevent->id; event.e.mouse.x = mevent->x; event.e.mouse.y = mevent->y; - event.e.mouse.z = mevent->z; event.e.mouse.buttons = mevent->bstate; add_event (res, &event); } From dd25bf5dfec0949c34f9e4eabf6275ec963dbebd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 21:22:10 +0900 Subject: [PATCH 118/444] [qwaq] Read mouse movements Many thanks to https://gist.github.com/sylt/93d3f7b77e7f3a881603 for the necessary escape sequence to get xterm reporting mouse movement events. --- tools/qwaq/qwaq-app.r | 13 +++++++------ tools/qwaq/qwaq-curses.c | 23 ++++++++++++++++++++++- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index 1bc2dcbe9..3cb5f85a4 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -6,6 +6,7 @@ void initialize (void) = #0; window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; void destroy_window (window_t win) = #0; void wprintf (window_t win, string fmt, ...) = #0; +void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; int wgetch (window_t win) = #0; void process_input (void) = #0; @@ -25,14 +26,14 @@ int main (int argc, string *argv) if (get_event (&event)) { if (event.event_type == qe_key) { ch = event.e.key; - wprintf (win, "key: %d\n", ch); + mvwprintf (win, 1, 1, "key: %d\n", ch); } else if (event.event_type == qe_mouse) { - wprintf (win, "mouse: %d %d %d\n", - event.e.mouse.x, - event.e.mouse.y, - event.e.mouse.buttons); + mvwprintf (win, 1, 2, "mouse: %d %d %d\n", + event.e.mouse.x, + event.e.mouse.y, + event.e.mouse.buttons); } } - } while (ch != 27); + } while (ch != 'q' && ch != 'Q'); return 0; } diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index ccc4b73b1..eb3724020 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "QF/dstring.h" #include "QF/progs.h" @@ -45,6 +46,7 @@ #define always_inline inline __attribute__((__always_inline__)) #define QUEUE_SIZE 16 // must be power of 2 greater than 1 #define QUEUE_MASK (QUEUE_SIZE - 1) +#define MOUSE_MOVES "\033[?1003h" // Make the terminal report mouse movements typedef struct window_s { WINDOW *win; @@ -123,7 +125,8 @@ bi_initialize (progs_t *pr) noecho (); nonl (); nodelay (stdscr, TRUE); - mousemask(ALL_MOUSE_EVENTS, NULL); + mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); + write(1, MOUSE_MOVES, sizeof (MOUSE_MOVES) - 1); } static void @@ -165,6 +168,23 @@ bi_wprintf (progs_t *pr) wrefresh (window->win); } +static void +bi_mvwprintf (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + const char *fmt = P_GSTRING (pr, 3); + int count = pr->pr_argc - 4; + pr_type_t **args = pr->pr_params + 4; + + dstring_clearstr (res->print_buffer); + PR_Sprintf (pr, res->print_buffer, "bi_wprintf", fmt, count, args); + mvwaddstr (window->win, y, x, res->print_buffer->str); + wrefresh (window->win); +} + static void bi_wgetch (progs_t *pr) { @@ -261,6 +281,7 @@ static builtin_t builtins[] = { {"create_window", bi_create_window, -1}, {"destroy_window", bi_destroy_window, -1}, {"wprintf", bi_wprintf, -1}, + {"mvwprintf", bi_mvwprintf, -1}, {"wgetch", bi_wgetch, -1}, {"process_input", bi_process_input, -1}, {"get_event", bi_get_event, -1}, From 6a58dcdddd1a8efbfab49b15864585d0f2f20e19 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 27 Feb 2020 21:38:55 +0900 Subject: [PATCH 119/444] [qwaq] Fix lost output Turns out all I needed was a refresh() after initialization. --- tools/qwaq/qwaq-curses.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index eb3724020..210124e35 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -127,6 +127,7 @@ bi_initialize (progs_t *pr) nodelay (stdscr, TRUE); mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); write(1, MOUSE_MOVES, sizeof (MOUSE_MOVES) - 1); + refresh(); } static void From 644ef93dde821e9fe16b07be1a982b0b2850a21c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 28 Feb 2020 22:27:29 +0900 Subject: [PATCH 120/444] [qwaq] Create some ring-buffer macros I expect I will need several messaging buffers, and ring buffers tend to be quite robust. Replacing the event buffer code with the macros made testing easy. --- tools/qwaq/qwaq-app.r | 2 +- tools/qwaq/qwaq-curses.c | 71 ++++++++++++++++++++++++++++++++++------ 2 files changed, 62 insertions(+), 11 deletions(-) diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index 3cb5f85a4..9aa3301f2 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -28,7 +28,7 @@ int main (int argc, string *argv) ch = event.e.key; mvwprintf (win, 1, 1, "key: %d\n", ch); } else if (event.event_type == qe_mouse) { - mvwprintf (win, 1, 2, "mouse: %d %d %d\n", + mvwprintf (win, 1, 2, "mouse: %2d %2d %08x\n", event.e.mouse.x, event.e.mouse.y, event.e.mouse.buttons); diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index 210124e35..1a5d08840 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -48,6 +48,61 @@ #define QUEUE_MASK (QUEUE_SIZE - 1) #define MOUSE_MOVES "\033[?1003h" // Make the terminal report mouse movements +#define RING_BUFFER(type, size) \ + struct { \ + type buffer[size]; \ + unsigned head; \ + unsigned tail; \ + } + +#define RB_buffer_size(ring_buffer) \ + ({ __auto_type rb = (ring_buffer); \ + sizeof (rb->buffer) / sizeof (rb->buffer[0]); \ + }) + +#define RB_SPACE_AVAILABLE(ring_buffer) \ + ({ __auto_type rb = &(ring_buffer); \ + (rb->tail + RB_buffer_size(rb) - rb->head - 1) % RB_buffer_size(rb);\ + }) + +#define RB_DATA_AVAILABLE(ring_buffer) \ + ({ __auto_type rb = &(ring_buffer); \ + (rb->head + RB_buffer_size (rb) - rb->tail) % RB_buffer_size (rb); \ + }) + +#define RB_WRITE_DATA(ring_buffer, data, count) \ + ({ __auto_type rb = &(ring_buffer); \ + typeof (&rb->buffer[0]) d = (data); \ + unsigned c = (count); \ + unsigned h = rb->head; \ + rb->head = (h + c) % RB_buffer_size (rb); \ + if (c > RB_buffer_size (rb) - h) { \ + memcpy (rb->buffer + h, d, \ + (RB_buffer_size (rb) - h) * sizeof (rb->buffer[0])); \ + c -= RB_buffer_size (rb) - h; \ + d += RB_buffer_size (rb) - h; \ + h = 0; \ + } \ + memcpy (rb->buffer + h, d, c * sizeof (rb->buffer[0])); \ + }) + +#define RB_READ_DATA(ring_buffer, data, count) \ + ({ __auto_type rb = &(ring_buffer); \ + typeof (&rb->buffer[0]) d = (data); \ + unsigned c = (count); \ + unsigned oc = c; \ + unsigned t = rb->tail; \ + if (c > RB_buffer_size (rb) - t) { \ + memcpy (d, rb->buffer + t, \ + (RB_buffer_size (rb) - t) * sizeof (rb->buffer[0])); \ + c -= RB_buffer_size (rb) - t; \ + d += RB_buffer_size (rb) - t; \ + t = 0; \ + } \ + memcpy (d, rb->buffer + t, c * sizeof (rb->buffer[0])); \ + rb->tail = (t + oc) % RB_buffer_size (rb); \ + }) + typedef struct window_s { WINDOW *win; } window_t; @@ -57,9 +112,7 @@ typedef struct qwaq_resources_s { int initialized; dstring_t *print_buffer; PR_RESMAP (window_t) window_map; - qwaq_event_t event_queue[QUEUE_SIZE]; - unsigned queue_head; - unsigned queue_tail; + RING_BUFFER (qwaq_event_t, QUEUE_SIZE) event_queue; } qwaq_resources_t; static window_t * @@ -92,7 +145,7 @@ window_index (qwaq_resources_t *res, window_t *win) PR_RESINDEX (res->window_map, win); } -static always_inline window_t * +static always_inline window_t * __attribute__((pure)) get_window (qwaq_resources_t *res, const char *name, int handle) { window_t *window = window_get (res, handle); @@ -198,19 +251,17 @@ bi_wgetch (progs_t *pr) static void add_event (qwaq_resources_t *res, qwaq_event_t *event) { - if (((res->queue_head - res->queue_tail) & QUEUE_MASK) != QUEUE_MASK) { - res->event_queue[res->queue_head] = *event; - res->queue_head = (res->queue_head + 1) & QUEUE_MASK; + if (RB_SPACE_AVAILABLE (res->event_queue) >= 1) { + RB_WRITE_DATA (res->event_queue, event, 1); } } static int get_event (qwaq_resources_t *res, qwaq_event_t *event) { - if (res->queue_head != res->queue_tail) { + if (RB_DATA_AVAILABLE (res->event_queue) >= 1) { if (event) { - *event = res->event_queue[res->queue_tail]; - res->queue_tail = (res->queue_tail + 1) & QUEUE_MASK; + RB_READ_DATA (res->event_queue, event, 1); } return 1; } From bd98d1d9fb45208bec172390b9428f8b83fe1ec3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 01:45:33 +0900 Subject: [PATCH 121/444] [qwaq] Prepare for threading So far, no threading has been set up, and only window creation and printing have been updated, but the basics of the design seem to be sound. The builtin functions now no longer call ncurses directly: the build commands and write them to a command buffer. Commands that have return values (eg, window creation) write their results to a results buffer that the originating builtin function reads. Builtin functions that expect a result "poll" the results buffer for the correct result (marked by the same command). In a single UI-thread environment, the results should always be in the same order as the commands, and in a multi-UI-thread environment, things should (fingers crossed) sort themselves out as ONE of the threads will be the originator of the next available result. Strings in commands (eg, for printing) are handled by acquiring a string id (index into an array of dstring_t) and including the string id in the written command. The string id is released upon completion of the command. Builtin functions write commands, acquire string ids, and read results. The command processor reads commands, releases string ids, and writes results. Since commands, string ids, and results are all in ring buffers, and assuming there is only one thread running the builtin functions and only one thread processing commands (there can be only one because ncurses is not thread-safe), then there should never be any contention on the buffers. Of course, if there are multiple threads running the builtin functions, then locking will be required on the builtin function side. --- tools/qwaq/qwaq-app.r | 7 +- tools/qwaq/qwaq-curses.c | 357 ++++++++++++++++++++++++++++++--------- 2 files changed, 280 insertions(+), 84 deletions(-) diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index 9aa3301f2..a0b2a2c63 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -5,11 +5,8 @@ typedef struct window_s *window_t; void initialize (void) = #0; window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; void destroy_window (window_t win) = #0; -void wprintf (window_t win, string fmt, ...) = #0; void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; -int wgetch (window_t win) = #0; -void process_input (void) = #0; int get_event (qwaq_event_t *event) = #0; int main (int argc, string *argv) @@ -19,10 +16,8 @@ int main (int argc, string *argv) initialize (); window_t win = create_window (20, 5, 50, 10); - wprintf (win, "Hi there!\n"); + mvwprintf (win, 0, 0, "Hi there!\n"); do { - process_input (); - if (get_event (&event)) { if (event.event_type == qe_key) { ch = event.e.key; diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index 1a5d08840..bb5c3a958 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -32,6 +32,7 @@ #endif #include +#include #include #include #include @@ -44,9 +45,19 @@ #include "event.h" #define always_inline inline __attribute__((__always_inline__)) -#define QUEUE_SIZE 16 // must be power of 2 greater than 1 -#define QUEUE_MASK (QUEUE_SIZE - 1) +#define QUEUE_SIZE 16 #define MOUSE_MOVES "\033[?1003h" // Make the terminal report mouse movements +#define STRING_ID_QUEUE_SIZE 8 // must be > 1 +#define COMMAND_QUEUE_SIZE 128 +#define CMD_SIZE(x) sizeof(x)/sizeof(x[0]) + +typedef enum qwaq_commands_e { + qwaq_cmd_create_window, + qwaq_cmd_destroy_window, + qwaq_cmd_create_panel, + qwaq_cmd_destroy_panel, + qwaq_cmd_mvwprint, +} qwaq_commands; #define RING_BUFFER(type, size) \ struct { \ @@ -103,16 +114,36 @@ rb->tail = (t + oc) % RB_buffer_size (rb); \ }) +#define RB_DROP_DATA(ring_buffer, count) \ + ({ __auto_type rb = &(ring_buffer); \ + unsigned c = (count); \ + unsigned t = rb->tail; \ + rb->tail = (t + c) % RB_buffer_size (rb); \ + }) + +#define RB_PEEK_DATA(ring_buffer, ahead) \ + ({ __auto_type rb = &(ring_buffer); \ + rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)]; \ + }) + typedef struct window_s { WINDOW *win; } window_t; +typedef struct panel_s { + PANEL *panel; +} panel_t; + typedef struct qwaq_resources_s { progs_t *pr; int initialized; - dstring_t *print_buffer; PR_RESMAP (window_t) window_map; + PR_RESMAP (panel_t) panel_map; RING_BUFFER (qwaq_event_t, QUEUE_SIZE) event_queue; + RING_BUFFER (int, COMMAND_QUEUE_SIZE) command_queue; + RING_BUFFER (int, COMMAND_QUEUE_SIZE) results; + RING_BUFFER (int, STRING_ID_QUEUE_SIZE) string_ids; + dstring_t strings[STRING_ID_QUEUE_SIZE - 1]; } qwaq_resources_t; static window_t * @@ -156,96 +187,127 @@ get_window (qwaq_resources_t *res, const char *name, int handle) return window; } -static int need_endwin; -static void -bi_shutdown (void) +static panel_t * +panel_new (qwaq_resources_t *res) { - if (need_endwin) { - endwin (); + PR_RESNEW (panel_t, res->panel_map); +} + +static void +panel_free (qwaq_resources_t *res, panel_t *win) +{ + PR_RESFREE (panel_t, res->panel_map, win); +} + +static void +panel_reset (qwaq_resources_t *res) +{ + PR_RESRESET (panel_t, res->panel_map); +} + +static inline panel_t * +panel_get (qwaq_resources_t *res, unsigned index) +{ + PR_RESGET(res->panel_map, index); +} + +static inline int +panel_index (qwaq_resources_t *res, panel_t *win) +{ + PR_RESINDEX (res->panel_map, win); +} + +static always_inline panel_t * __attribute__((pure)) +get_panel (qwaq_resources_t *res, const char *name, int handle) +{ + panel_t *panel = panel_get (res, handle); + + if (!panel || !panel->panel) { + PR_RunError (res->pr, "invalid panel passed to %s", name + 3); + } + return panel; +} + +static int +acquire_string (qwaq_resources_t *res) +{ + int string_id = -1; + + // XXX add locking and loop for available + if (RB_DATA_AVAILABLE (res->string_ids)) { + RB_READ_DATA (res->string_ids, &string_id, 1); + } + // XXX unlock and end of loop + return string_id; +} + +static void +release_string (qwaq_resources_t *res, int string_id) +{ + // locking shouldn't be necessary as there should be only one writer + // but if it becomes such that there is more than one writer, locks as per + // acquire + if (RB_SPACE_AVAILABLE (res->string_ids)) { + RB_WRITE_DATA (res->string_ids, &string_id, 1); } } static void -bi_initialize (progs_t *pr) +create_window (qwaq_resources_t *res) { - qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int xpos = RB_PEEK_DATA (res->command_queue, 2); + int ypos = RB_PEEK_DATA (res->command_queue, 3); + int xlen = RB_PEEK_DATA (res->command_queue, 4); + int ylen = RB_PEEK_DATA (res->command_queue, 5); - initscr (); - need_endwin = 1; - res->initialized = 1; - raw (); - keypad (stdscr, TRUE); - noecho (); - nonl (); - nodelay (stdscr, TRUE); - mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); - write(1, MOUSE_MOVES, sizeof (MOUSE_MOVES) - 1); - refresh(); -} - -static void -bi_create_window (progs_t *pr) -{ - qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int xpos = P_INT (pr, 0); - int ypos = P_INT (pr, 1); - int xlen = P_INT (pr, 2); - int ylen = P_INT (pr, 3); window_t *window = window_new (res); window->win = newwin (ylen, xlen, ypos, xpos); keypad (window->win, TRUE); - R_INT (pr) = window_index (res, window); + + int window_id = window_index (res, window); + + int cmd_result[] = { qwaq_cmd_create_window, window_id }; + + // loop + if (RB_SPACE_AVAILABLE (res->results) >= CMD_SIZE (cmd_result)) { + RB_WRITE_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); + } } static void -bi_destroy_window (progs_t *pr) +move_print (qwaq_resources_t *res) { - qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); - delwin (window->win); - window->win = 0; - window_free (res, window); -} + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int x = RB_PEEK_DATA (res->command_queue, 3); + int y = RB_PEEK_DATA (res->command_queue, 4); + int string_id = RB_PEEK_DATA (res->command_queue, 5); -static void -bi_wprintf (progs_t *pr) -{ - qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); - const char *fmt = P_GSTRING (pr, 1); - int count = pr->pr_argc - 2; - pr_type_t **args = pr->pr_params + 2; - - dstring_clearstr (res->print_buffer); - PR_Sprintf (pr, res->print_buffer, "bi_wprintf", fmt, count, args); - waddstr (window->win, res->print_buffer->str); + window_t *window = get_window (res, __FUNCTION__, window_id); + mvwaddstr (window->win, y, x, res->strings[string_id].str); + release_string (res, string_id); wrefresh (window->win); } static void -bi_mvwprintf (progs_t *pr) +process_commands (qwaq_resources_t *res) { - qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); - int x = P_INT (pr, 1); - int y = P_INT (pr, 2); - const char *fmt = P_GSTRING (pr, 3); - int count = pr->pr_argc - 4; - pr_type_t **args = pr->pr_params + 4; - - dstring_clearstr (res->print_buffer); - PR_Sprintf (pr, res->print_buffer, "bi_wprintf", fmt, count, args); - mvwaddstr (window->win, y, x, res->print_buffer->str); - wrefresh (window->win); -} - -static void -bi_wgetch (progs_t *pr) -{ - qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); - - R_INT (pr) = wgetch (window->win); + while (RB_DATA_AVAILABLE (res->command_queue) > 2) { + switch ((qwaq_commands) RB_PEEK_DATA (res->command_queue, 0)) { + case qwaq_cmd_create_window: + create_window (res); + break; + case qwaq_cmd_destroy_window: + break; + case qwaq_cmd_create_panel: + break; + case qwaq_cmd_destroy_panel: + break; + case qwaq_cmd_mvwprint: + move_print (res); + break; + } + RB_DROP_DATA (res->command_queue, RB_PEEK_DATA (res->command_queue, 1)); + } } static void @@ -289,9 +351,8 @@ key_event (qwaq_resources_t *res, int key) } static void -bi_process_input (progs_t *pr) +process_input (qwaq_resources_t *res) { - qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); if (Sys_CheckInput (1, -1)) { int ch; while ((ch = getch ()) != ERR && ch) { @@ -307,15 +368,143 @@ bi_process_input (progs_t *pr) } } +static int need_endwin; +static void +bi_shutdown (void) +{ + if (need_endwin) { + endwin (); + } +} + +static void +bi_create_window (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int xpos = P_INT (pr, 0); + int ypos = P_INT (pr, 1); + int xlen = P_INT (pr, 2); + int ylen = P_INT (pr, 3); + int command[] = { + qwaq_cmd_create_window, 0, + xpos, ypos, xlen, ylen, + }; + + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + // XXX should just wait on the mutex + process_commands (res); + process_input (res); + // locking and loop until id is correct + if (RB_DATA_AVAILABLE (res->results) + && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_create_window) { + int cmd_result[2]; // should results have a size? + RB_READ_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); + R_INT (pr) = cmd_result[1]; + } +} + +static void +bi_destroy_window (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); + delwin (window->win); + window->win = 0; + window_free (res, window); +} + +static void +bi_create_panel (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); + + panel_t *panel = panel_new (res); + panel->panel = new_panel (window->win); + R_INT (pr) = panel_index (res, panel); +} + +static void +bi_destroy_panel (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + panel_t *panel = get_panel (res, __FUNCTION__, P_INT (pr, 0)); + del_panel (panel->panel); + panel->panel = 0; + panel_free (res, panel); +} + +static void +bi_mvwprintf (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + const char *fmt = P_GSTRING (pr, 3); + int count = pr->pr_argc - 4; + pr_type_t **args = pr->pr_params + 4; + + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_mvwprint, 0, + window_id, x, y, string_id + }; + + if (get_window (res, __FUNCTION__, window_id)) { + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "mvwprintf", fmt, count, args); + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + } +} + +static void +bi_wgetch (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); + + R_INT (pr) = wgetch (window->win); +} + static void bi_get_event (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); qwaq_event_t *event = &G_STRUCT (pr, qwaq_event_t, P_INT (pr, 0)); + process_commands (res); + process_input (res); R_INT (pr) = get_event (res, event); } +static void +bi_initialize (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + initscr (); + need_endwin = 1; + res->initialized = 1; + raw (); + keypad (stdscr, TRUE); + noecho (); + nonl (); + nodelay (stdscr, TRUE); + mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); + write(1, MOUSE_MOVES, sizeof (MOUSE_MOVES) - 1); + refresh(); +} + static void bi_qwaq_clear (progs_t *pr, void *data) { @@ -326,28 +515,40 @@ bi_qwaq_clear (progs_t *pr, void *data) } need_endwin = 0; window_reset (res); + panel_reset (res); } static builtin_t builtins[] = { {"initialize", bi_initialize, -1}, {"create_window", bi_create_window, -1}, {"destroy_window", bi_destroy_window, -1}, - {"wprintf", bi_wprintf, -1}, + {"create_panel", bi_create_panel, -1}, + {"destroy_panel", bi_destroy_panel, -1}, {"mvwprintf", bi_mvwprintf, -1}, {"wgetch", bi_wgetch, -1}, - {"process_input", bi_process_input, -1}, {"get_event", bi_get_event, -1}, {0} }; +static __attribute__((format(printf, 1, 0))) void +qwaq_print (const char *fmt, va_list args) +{ + vfprintf (stderr, fmt, args); + fflush (stderr); +} + void BI_Init (progs_t *pr) { qwaq_resources_t *res = calloc (sizeof (*res), 1); res->pr = pr; - res->print_buffer = dstring_newstr (); + for (int i = 0; i < STRING_ID_QUEUE_SIZE - 1; i++) { + RB_WRITE_DATA (res->string_ids, &i, 1); + res->strings[i].mem = &dstring_default_mem; + } PR_Resources_Register (pr, "qwaq", res, bi_qwaq_clear); PR_RegisterBuiltins (pr, builtins); Sys_RegisterShutdown (bi_shutdown); + Sys_SetStdPrintf (qwaq_print); } From 513c808875ccaae0e9cbede9f8ba8d1b0ac97413 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 02:07:47 +0900 Subject: [PATCH 122/444] [qwaq] Make some bad ascii art --- tools/qwaq/qwaq-app.r | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index a0b2a2c63..bf3bfb85e 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -16,7 +16,9 @@ int main (int argc, string *argv) initialize (); window_t win = create_window (20, 5, 50, 10); - mvwprintf (win, 0, 0, "Hi there!\n"); + mvwprintf (win, 0, 0, "Hi there! (q to quit)\n"); + mvwprintf (win, 1, 1, "(?)Oo.\n"); + mvwprintf (win, 1, 2, " \\_O>\n"); do { if (get_event (&event)) { if (event.event_type == qe_key) { From 0119660b01c5a8bba42915c9239bebef5df93fd4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 11:44:43 +0900 Subject: [PATCH 123/444] [qwaq] Convert remaining functions to command queue Now that the initial prototype seems to be working well, it's time to implement more commands. I might have to do some wrappers for actual command writing (and result reading) as it looks like there will be a lot of nearly identical code. --- tools/qwaq/qwaq-app.r | 2 + tools/qwaq/qwaq-curses.c | 101 ++++++++++++++++++++++++++++++--------- 2 files changed, 80 insertions(+), 23 deletions(-) diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index bf3bfb85e..3e51b7e98 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -32,5 +32,7 @@ int main (int argc, string *argv) } } } while (ch != 'q' && ch != 'Q'); + destroy_window (win); + get_event (&event); return 0; } diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index bb5c3a958..e218e969a 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -265,7 +265,6 @@ create_window (qwaq_resources_t *res) keypad (window->win, TRUE); int window_id = window_index (res, window); - int cmd_result[] = { qwaq_cmd_create_window, window_id }; // loop @@ -274,6 +273,44 @@ create_window (qwaq_resources_t *res) } } +static void +destroy_window (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + delwin (window->win); + window_free (res, window); +} + +static void +create_panel (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + panel_t *panel = panel_new (res); + panel->panel = new_panel (window->win); + + int panel_id = panel_index (res, panel); + int cmd_result[] = { qwaq_cmd_create_panel, panel_id }; + + // loop + if (RB_SPACE_AVAILABLE (res->results) >= CMD_SIZE (cmd_result)) { + RB_WRITE_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); + } +} + +static void +destroy_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + del_panel (panel->panel); + panel_free (res, panel); +} + static void move_print (qwaq_resources_t *res) { @@ -297,10 +334,13 @@ process_commands (qwaq_resources_t *res) create_window (res); break; case qwaq_cmd_destroy_window: + destroy_window (res); break; case qwaq_cmd_create_panel: + create_panel (res); break; case qwaq_cmd_destroy_panel: + destroy_panel (res); break; case qwaq_cmd_mvwprint: move_print (res); @@ -411,31 +451,56 @@ static void bi_destroy_window (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); - delwin (window->win); - window->win = 0; - window_free (res, window); + int window_id = P_INT (pr, 0); + int command[] = { qwaq_cmd_destroy_window, 0, window_id, }; + + if (get_window (res, __FUNCTION__, window_id)) { + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + } } static void bi_create_panel (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); + int window_id = P_INT (pr, 0); + int command[] = { qwaq_cmd_create_panel, 0, window_id, }; - panel_t *panel = panel_new (res); - panel->panel = new_panel (window->win); - R_INT (pr) = panel_index (res, panel); + if (get_window (res, __FUNCTION__, window_id)) { + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + + // locking and loop until id is correct + if (RB_DATA_AVAILABLE (res->results) + && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_create_panel) { + int cmd_result[2]; // should results have a size? + RB_READ_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); + R_INT (pr) = cmd_result[1]; + } + } } static void bi_destroy_panel (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - panel_t *panel = get_panel (res, __FUNCTION__, P_INT (pr, 0)); - del_panel (panel->panel); - panel->panel = 0; - panel_free (res, panel); + int panel_id = P_INT (pr, 0); + int command[] = { qwaq_cmd_destroy_panel, 0, panel_id, }; + + if (get_panel (res, __FUNCTION__, panel_id)) { + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + } } static void @@ -467,15 +532,6 @@ bi_mvwprintf (progs_t *pr) } } -static void -bi_wgetch (progs_t *pr) -{ - qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - window_t *window = get_window (res, __FUNCTION__, P_INT (pr, 0)); - - R_INT (pr) = wgetch (window->win); -} - static void bi_get_event (progs_t *pr) { @@ -525,7 +581,6 @@ static builtin_t builtins[] = { {"create_panel", bi_create_panel, -1}, {"destroy_panel", bi_destroy_panel, -1}, {"mvwprintf", bi_mvwprintf, -1}, - {"wgetch", bi_wgetch, -1}, {"get_event", bi_get_event, -1}, {0} }; From ea69921e6a268a35b37e7f094a2bd0416ca1cc97 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 12:33:45 +0900 Subject: [PATCH 124/444] [qwaq] Validate window before acquiring string If the window is invalid and recovery is done, string ids will leak if acquired before validation. Afterwards, make the rest of the builtin wrappers consistent: extract parameters, validate, [acquire resources], generate command. --- tools/qwaq/qwaq-curses.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index e218e969a..8460a36b4 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -452,9 +452,10 @@ bi_destroy_window (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); int window_id = P_INT (pr, 0); - int command[] = { qwaq_cmd_destroy_window, 0, window_id, }; if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_destroy_window, 0, window_id, }; + command[1] = CMD_SIZE(command); if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { @@ -468,9 +469,10 @@ bi_create_panel (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); int window_id = P_INT (pr, 0); - int command[] = { qwaq_cmd_create_panel, 0, window_id, }; if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_create_panel, 0, window_id, }; + command[1] = CMD_SIZE(command); if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { @@ -514,14 +516,14 @@ bi_mvwprintf (progs_t *pr) int count = pr->pr_argc - 4; pr_type_t **args = pr->pr_params + 4; - int string_id = acquire_string (res); - dstring_t *print_buffer = res->strings + string_id; - int command[] = { - qwaq_cmd_mvwprint, 0, - window_id, x, y, string_id - }; - if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_mvwprint, 0, + window_id, x, y, string_id + }; + command[1] = CMD_SIZE(command); dstring_clearstr (print_buffer); From 17005637cadbd74d6d3d08720c9daeb3b23adfe6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 12:46:25 +0900 Subject: [PATCH 125/444] [qwaq] Rename the internal function names Now they reflect the curses functions they wrap. The externally visible builtin names are not changed because the parameters are in x, y order rather than curses' y, x order. --- tools/qwaq/qwaq-curses.c | 76 ++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 38 deletions(-) diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index 8460a36b4..fafbe8c80 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -52,11 +52,11 @@ #define CMD_SIZE(x) sizeof(x)/sizeof(x[0]) typedef enum qwaq_commands_e { - qwaq_cmd_create_window, - qwaq_cmd_destroy_window, - qwaq_cmd_create_panel, - qwaq_cmd_destroy_panel, - qwaq_cmd_mvwprint, + qwaq_cmd_newwin, + qwaq_cmd_delwin, + qwaq_cmd_new_panel, + qwaq_cmd_del_panel, + qwaq_cmd_mvwaddstr, } qwaq_commands; #define RING_BUFFER(type, size) \ @@ -253,7 +253,7 @@ release_string (qwaq_resources_t *res, int string_id) } static void -create_window (qwaq_resources_t *res) +cmd_newwin (qwaq_resources_t *res) { int xpos = RB_PEEK_DATA (res->command_queue, 2); int ypos = RB_PEEK_DATA (res->command_queue, 3); @@ -265,7 +265,7 @@ create_window (qwaq_resources_t *res) keypad (window->win, TRUE); int window_id = window_index (res, window); - int cmd_result[] = { qwaq_cmd_create_window, window_id }; + int cmd_result[] = { qwaq_cmd_newwin, window_id }; // loop if (RB_SPACE_AVAILABLE (res->results) >= CMD_SIZE (cmd_result)) { @@ -274,7 +274,7 @@ create_window (qwaq_resources_t *res) } static void -destroy_window (qwaq_resources_t *res) +cmd_delwin (qwaq_resources_t *res) { int window_id = RB_PEEK_DATA (res->command_queue, 2); @@ -284,7 +284,7 @@ destroy_window (qwaq_resources_t *res) } static void -create_panel (qwaq_resources_t *res) +cmd_new_panel (qwaq_resources_t *res) { int window_id = RB_PEEK_DATA (res->command_queue, 2); @@ -293,7 +293,7 @@ create_panel (qwaq_resources_t *res) panel->panel = new_panel (window->win); int panel_id = panel_index (res, panel); - int cmd_result[] = { qwaq_cmd_create_panel, panel_id }; + int cmd_result[] = { qwaq_cmd_new_panel, panel_id }; // loop if (RB_SPACE_AVAILABLE (res->results) >= CMD_SIZE (cmd_result)) { @@ -302,7 +302,7 @@ create_panel (qwaq_resources_t *res) } static void -destroy_panel (qwaq_resources_t *res) +cmd_del_panel (qwaq_resources_t *res) { int panel_id = RB_PEEK_DATA (res->command_queue, 2); @@ -312,7 +312,7 @@ destroy_panel (qwaq_resources_t *res) } static void -move_print (qwaq_resources_t *res) +cmd_mvwaddstr (qwaq_resources_t *res) { int window_id = RB_PEEK_DATA (res->command_queue, 2); int x = RB_PEEK_DATA (res->command_queue, 3); @@ -330,20 +330,20 @@ process_commands (qwaq_resources_t *res) { while (RB_DATA_AVAILABLE (res->command_queue) > 2) { switch ((qwaq_commands) RB_PEEK_DATA (res->command_queue, 0)) { - case qwaq_cmd_create_window: - create_window (res); + case qwaq_cmd_newwin: + cmd_newwin (res); break; - case qwaq_cmd_destroy_window: - destroy_window (res); + case qwaq_cmd_delwin: + cmd_delwin (res); break; - case qwaq_cmd_create_panel: - create_panel (res); + case qwaq_cmd_new_panel: + cmd_new_panel (res); break; - case qwaq_cmd_destroy_panel: - destroy_panel (res); + case qwaq_cmd_del_panel: + cmd_del_panel (res); break; - case qwaq_cmd_mvwprint: - move_print (res); + case qwaq_cmd_mvwaddstr: + cmd_mvwaddstr (res); break; } RB_DROP_DATA (res->command_queue, RB_PEEK_DATA (res->command_queue, 1)); @@ -418,7 +418,7 @@ bi_shutdown (void) } static void -bi_create_window (progs_t *pr) +bi_newwin (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); int xpos = P_INT (pr, 0); @@ -426,7 +426,7 @@ bi_create_window (progs_t *pr) int xlen = P_INT (pr, 2); int ylen = P_INT (pr, 3); int command[] = { - qwaq_cmd_create_window, 0, + qwaq_cmd_newwin, 0, xpos, ypos, xlen, ylen, }; @@ -440,7 +440,7 @@ bi_create_window (progs_t *pr) process_input (res); // locking and loop until id is correct if (RB_DATA_AVAILABLE (res->results) - && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_create_window) { + && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_newwin) { int cmd_result[2]; // should results have a size? RB_READ_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); R_INT (pr) = cmd_result[1]; @@ -448,13 +448,13 @@ bi_create_window (progs_t *pr) } static void -bi_destroy_window (progs_t *pr) +bi_delwin (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); int window_id = P_INT (pr, 0); if (get_window (res, __FUNCTION__, window_id)) { - int command[] = { qwaq_cmd_destroy_window, 0, window_id, }; + int command[] = { qwaq_cmd_delwin, 0, window_id, }; command[1] = CMD_SIZE(command); @@ -465,13 +465,13 @@ bi_destroy_window (progs_t *pr) } static void -bi_create_panel (progs_t *pr) +bi_new_panel (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); int window_id = P_INT (pr, 0); if (get_window (res, __FUNCTION__, window_id)) { - int command[] = { qwaq_cmd_create_panel, 0, window_id, }; + int command[] = { qwaq_cmd_new_panel, 0, window_id, }; command[1] = CMD_SIZE(command); @@ -481,7 +481,7 @@ bi_create_panel (progs_t *pr) // locking and loop until id is correct if (RB_DATA_AVAILABLE (res->results) - && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_create_panel) { + && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_new_panel) { int cmd_result[2]; // should results have a size? RB_READ_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); R_INT (pr) = cmd_result[1]; @@ -490,11 +490,11 @@ bi_create_panel (progs_t *pr) } static void -bi_destroy_panel (progs_t *pr) +bi_del_panel (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); int panel_id = P_INT (pr, 0); - int command[] = { qwaq_cmd_destroy_panel, 0, panel_id, }; + int command[] = { qwaq_cmd_del_panel, 0, panel_id, }; if (get_panel (res, __FUNCTION__, panel_id)) { command[1] = CMD_SIZE(command); @@ -520,14 +520,14 @@ bi_mvwprintf (progs_t *pr) int string_id = acquire_string (res); dstring_t *print_buffer = res->strings + string_id; int command[] = { - qwaq_cmd_mvwprint, 0, + qwaq_cmd_mvwaddstr, 0, window_id, x, y, string_id }; command[1] = CMD_SIZE(command); dstring_clearstr (print_buffer); - PR_Sprintf (pr, print_buffer, "mvwprintf", fmt, count, args); + PR_Sprintf (pr, print_buffer, "mvwaddstr", fmt, count, args); if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); } @@ -578,10 +578,10 @@ bi_qwaq_clear (progs_t *pr, void *data) static builtin_t builtins[] = { {"initialize", bi_initialize, -1}, - {"create_window", bi_create_window, -1}, - {"destroy_window", bi_destroy_window, -1}, - {"create_panel", bi_create_panel, -1}, - {"destroy_panel", bi_destroy_panel, -1}, + {"create_window", bi_newwin, -1}, + {"destroy_window", bi_delwin, -1}, + {"create_panel", bi_new_panel, -1}, + {"destroy_panel", bi_del_panel, -1}, {"mvwprintf", bi_mvwprintf, -1}, {"get_event", bi_get_event, -1}, {0} From 5e4677f8d54471d2949e84d089aafcb8275dff5b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 13:06:58 +0900 Subject: [PATCH 126/444] [qwaq] Implement the immediately useful panel functions --- tools/qwaq/qwaq-curses.c | 129 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 127 insertions(+), 2 deletions(-) diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index fafbe8c80..eaab87c82 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -56,6 +56,11 @@ typedef enum qwaq_commands_e { qwaq_cmd_delwin, qwaq_cmd_new_panel, qwaq_cmd_del_panel, + qwaq_cmd_hide_panel, + qwaq_cmd_show_panel, + qwaq_cmd_top_panel, + qwaq_cmd_bottom_panel, + qwaq_cmd_move_panel, qwaq_cmd_mvwaddstr, } qwaq_commands; @@ -311,6 +316,58 @@ cmd_del_panel (qwaq_resources_t *res) panel_free (res, panel); } +static void +cmd_hide_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + hide_panel (panel->panel); + panel_free (res, panel); +} + +static void +cmd_show_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + show_panel (panel->panel); + panel_free (res, panel); +} + +static void +cmd_top_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + top_panel (panel->panel); + panel_free (res, panel); +} + +static void +cmd_bottom_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + bottom_panel (panel->panel); + panel_free (res, panel); +} + +static void +cmd_move_panel (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + int x = RB_PEEK_DATA (res->command_queue, 3); + int y = RB_PEEK_DATA (res->command_queue, 4); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + move_panel (panel->panel, y, x); + panel_free (res, panel); +} + static void cmd_mvwaddstr (qwaq_resources_t *res) { @@ -342,6 +399,21 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_del_panel: cmd_del_panel (res); break; + case qwaq_cmd_hide_panel: + cmd_hide_panel (res); + break; + case qwaq_cmd_show_panel: + cmd_show_panel (res); + break; + case qwaq_cmd_top_panel: + cmd_top_panel (res); + break; + case qwaq_cmd_bottom_panel: + cmd_bottom_panel (res); + break; + case qwaq_cmd_move_panel: + cmd_move_panel (res); + break; case qwaq_cmd_mvwaddstr: cmd_mvwaddstr (res); break; @@ -490,13 +562,61 @@ bi_new_panel (progs_t *pr) } static void -bi_del_panel (progs_t *pr) +panel_command (progs_t *pr, qwaq_commands cmd) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); int panel_id = P_INT (pr, 0); - int command[] = { qwaq_cmd_del_panel, 0, panel_id, }; if (get_panel (res, __FUNCTION__, panel_id)) { + int command[] = { cmd, 0, panel_id, }; + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + } +} + +static void +bi_del_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_del_panel); +} + +static void +bi_hide_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_hide_panel); +} + +static void +bi_show_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_show_panel); +} + +static void +bi_top_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_top_panel); +} + +static void +bi_bottom_panel (progs_t *pr) +{ + panel_command (pr, qwaq_cmd_bottom_panel); +} + +static void +bi_move_panel (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int panel_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + + if (get_panel (res, __FUNCTION__, panel_id)) { + int command[] = { qwaq_cmd_move_panel, 0, panel_id, x, y, }; command[1] = CMD_SIZE(command); if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { @@ -582,6 +702,11 @@ static builtin_t builtins[] = { {"destroy_window", bi_delwin, -1}, {"create_panel", bi_new_panel, -1}, {"destroy_panel", bi_del_panel, -1}, + {"hide_panel", bi_hide_panel, -1}, + {"show_panel", bi_show_panel, -1}, + {"top_panel", bi_top_panel, -1}, + {"bottom_panel", bi_bottom_panel, -1}, + {"move_panel", bi_move_panel, -1}, {"mvwprintf", bi_mvwprintf, -1}, {"get_event", bi_get_event, -1}, {0} From f5f50ae23133f2924113be937d28ea56f6293b1a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 14:38:54 +0900 Subject: [PATCH 127/444] [qwaq] Make stdscr available to progs --- tools/qwaq/qwaq-app.r | 2 ++ tools/qwaq/qwaq-curses.c | 7 +++++++ 2 files changed, 9 insertions(+) diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index 3e51b7e98..9e8706b89 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -2,6 +2,8 @@ typedef struct window_s *window_t; +window_t stdscr = (window_t) 1; + void initialize (void) = #0; window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; void destroy_window (window_t win) = #0; diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index eaab87c82..00caef9f5 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -142,6 +142,7 @@ typedef struct panel_s { typedef struct qwaq_resources_s { progs_t *pr; int initialized; + window_t stdscr; PR_RESMAP (window_t) window_map; PR_RESMAP (panel_t) panel_map; RING_BUFFER (qwaq_event_t, QUEUE_SIZE) event_queue; @@ -184,6 +185,10 @@ window_index (qwaq_resources_t *res, window_t *win) static always_inline window_t * __attribute__((pure)) get_window (qwaq_resources_t *res, const char *name, int handle) { + if (handle == 1) { + return &res->stdscr; + } + window_t *window = window_get (res, handle); if (!window || !window->win) { @@ -681,6 +686,8 @@ bi_initialize (progs_t *pr) mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); write(1, MOUSE_MOVES, sizeof (MOUSE_MOVES) - 1); refresh(); + + res->stdscr.win = stdscr; } static void From ec4e9b326d1d1cc988fca1ca786073b6b04bbfbf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 14:43:08 +0900 Subject: [PATCH 128/444] [qwaq] Don't call wrefresh in cmd_mvwaddstr There is now an implementation for wrefresh. --- tools/qwaq/qwaq-app.r | 13 ++++++++----- tools/qwaq/qwaq-curses.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index 9e8706b89..ccf7485bb 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -8,6 +8,7 @@ void initialize (void) = #0; window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; void destroy_window (window_t win) = #0; void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; +void wrefresh (window_t win) = #0; int get_event (qwaq_event_t *event) = #0; @@ -18,20 +19,22 @@ int main (int argc, string *argv) initialize (); window_t win = create_window (20, 5, 50, 10); - mvwprintf (win, 0, 0, "Hi there! (q to quit)\n"); - mvwprintf (win, 1, 1, "(?)Oo.\n"); - mvwprintf (win, 1, 2, " \\_O>\n"); + mvwprintf (win, 0, 0, "Hi there! (q to quit)"); + mvwprintf (win, 1, 1, "(?)Oo."); + mvwprintf (win, 1, 2, " \\_O>"); + wrefresh (win); do { if (get_event (&event)) { if (event.event_type == qe_key) { ch = event.e.key; - mvwprintf (win, 1, 1, "key: %d\n", ch); + mvwprintf (win, 1, 1, "key: %d", ch); } else if (event.event_type == qe_mouse) { - mvwprintf (win, 1, 2, "mouse: %2d %2d %08x\n", + mvwprintf (win, 1, 2, "mouse: %2d %2d %08x", event.e.mouse.x, event.e.mouse.y, event.e.mouse.buttons); } + wrefresh (win); } } while (ch != 'q' && ch != 'Q'); destroy_window (win); diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index 00caef9f5..0f80dfc62 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -62,6 +62,7 @@ typedef enum qwaq_commands_e { qwaq_cmd_bottom_panel, qwaq_cmd_move_panel, qwaq_cmd_mvwaddstr, + qwaq_cmd_wrefresh, } qwaq_commands; #define RING_BUFFER(type, size) \ @@ -384,6 +385,14 @@ cmd_mvwaddstr (qwaq_resources_t *res) window_t *window = get_window (res, __FUNCTION__, window_id); mvwaddstr (window->win, y, x, res->strings[string_id].str); release_string (res, string_id); +} + +static void +cmd_wrefresh (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); wrefresh (window->win); } @@ -422,6 +431,9 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_mvwaddstr: cmd_mvwaddstr (res); break; + case qwaq_cmd_wrefresh: + cmd_wrefresh (res); + break; } RB_DROP_DATA (res->command_queue, RB_PEEK_DATA (res->command_queue, 1)); } @@ -659,6 +671,22 @@ bi_mvwprintf (progs_t *pr) } } +static void +bi_wrefresh (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_wrefresh, 0, window_id, }; + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + } +} + static void bi_get_event (progs_t *pr) { @@ -715,6 +743,7 @@ static builtin_t builtins[] = { {"bottom_panel", bi_bottom_panel, -1}, {"move_panel", bi_move_panel, -1}, {"mvwprintf", bi_mvwprintf, -1}, + {"wrefresh", bi_wrefresh, -1}, {"get_event", bi_get_event, -1}, {0} }; From ae532870c42d057bd431db8580440badfe5a3fa3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 14:48:18 +0900 Subject: [PATCH 129/444] [qwaq] Implement basic color support --- tools/qwaq/color.h | 21 +++++++++++ tools/qwaq/qwaq-app.r | 10 +++++ tools/qwaq/qwaq-curses.c | 79 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 tools/qwaq/color.h diff --git a/tools/qwaq/color.h b/tools/qwaq/color.h new file mode 100644 index 000000000..95067b5de --- /dev/null +++ b/tools/qwaq/color.h @@ -0,0 +1,21 @@ +#ifndef __qwaq_color_h +#define __qwaq_color_h + +#ifndef COLOR_PAIR +// double protection in case this header is included in a C file + +#define COLOR_PAIR(cp) ((cp) << 8) + +// taken from ncurses.h +#define COLOR_BLACK 0 +#define COLOR_RED 1 +#define COLOR_GREEN 2 +#define COLOR_YELLOW 3 +#define COLOR_BLUE 4 +#define COLOR_MAGENTA 5 +#define COLOR_CYAN 6 +#define COLOR_WHITE 7 + +#endif + +#endif//__qwaq_color_h diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index ccf7485bb..3e39f14a0 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -1,3 +1,4 @@ +#include "color.h" #include "event.h" typedef struct window_s *window_t; @@ -11,6 +12,10 @@ void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; void wrefresh (window_t win) = #0; int get_event (qwaq_event_t *event) = #0; +int max_colors (void) = #0; +int max_color_pairs (void) = #0; +int init_pair (int pair, int f, int b) = #0; +void wbkgd (window_t win, int ch) = #0; int main (int argc, string *argv) { @@ -18,10 +23,15 @@ int main (int argc, string *argv) qwaq_event_t event = { }; initialize (); + init_pair (1, COLOR_WHITE, COLOR_BLUE); + wbkgd (stdscr, COLOR_PAIR(1)); + wrefresh (stdscr); window_t win = create_window (20, 5, 50, 10); + wbkgd (win, COLOR_PAIR(0)); mvwprintf (win, 0, 0, "Hi there! (q to quit)"); mvwprintf (win, 1, 1, "(?)Oo."); mvwprintf (win, 1, 2, " \\_O>"); + mvwprintf (win, 1, 3, " %d %d", max_colors (), max_color_pairs ()); wrefresh (win); do { if (get_event (&event)) { diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index 0f80dfc62..a5db37e02 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -63,6 +63,8 @@ typedef enum qwaq_commands_e { qwaq_cmd_move_panel, qwaq_cmd_mvwaddstr, qwaq_cmd_wrefresh, + qwaq_cmd_init_pair, + qwaq_cmd_wbkgd, } qwaq_commands; #define RING_BUFFER(type, size) \ @@ -396,6 +398,26 @@ cmd_wrefresh (qwaq_resources_t *res) wrefresh (window->win); } +static void +cmd_init_pair (qwaq_resources_t *res) +{ + int pair = RB_PEEK_DATA (res->command_queue, 2); + int f = RB_PEEK_DATA (res->command_queue, 3); + int b = RB_PEEK_DATA (res->command_queue, 4); + + init_pair (pair, f, b); +} + +static void +cmd_wbkgd (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int ch = RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + wbkgd (window->win, ch); +} + static void process_commands (qwaq_resources_t *res) { @@ -434,6 +456,12 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_wrefresh: cmd_wrefresh (res); break; + case qwaq_cmd_init_pair: + cmd_init_pair (res); + break; + case qwaq_cmd_wbkgd: + cmd_wbkgd (res); + break; } RB_DROP_DATA (res->command_queue, RB_PEEK_DATA (res->command_queue, 1)); } @@ -698,6 +726,52 @@ bi_get_event (progs_t *pr) R_INT (pr) = get_event (res, event); } +static void +bi_max_colors (progs_t *pr) +{ + R_INT (pr) = COLORS; +} + +static void +bi_max_color_pairs (progs_t *pr) +{ + R_INT (pr) = COLOR_PAIRS; +} + +static void +bi_init_pair (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int pair = P_INT (pr, 0); + int f = P_INT (pr, 1); + int b = P_INT (pr, 2); + + int command[] = { qwaq_cmd_init_pair, 0, pair, f, b, }; + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } +} + +static void +bi_wbkgd (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + int ch = P_INT (pr, 1); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_wbkgd, 0, window_id, ch, }; + + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + } +} + static void bi_initialize (progs_t *pr) { @@ -706,6 +780,7 @@ bi_initialize (progs_t *pr) initscr (); need_endwin = 1; res->initialized = 1; + start_color (); raw (); keypad (stdscr, TRUE); noecho (); @@ -745,6 +820,10 @@ static builtin_t builtins[] = { {"mvwprintf", bi_mvwprintf, -1}, {"wrefresh", bi_wrefresh, -1}, {"get_event", bi_get_event, -1}, + {"max_colors", bi_max_colors, -1}, + {"max_color_pairs", bi_max_color_pairs, -1}, + {"init_pair", bi_init_pair, -1}, + {"wbkgd", bi_wbkgd, -1}, {0} }; From 75f4cebf0eda783cb9bb54a4770a3369b3a7fa93 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 16:11:07 +0900 Subject: [PATCH 130/444] Clean up after removal of uint32.h I guess I forgot to check for its usage in header files, and the fact that it didn't get cleaned out from being installed hid the error. --- include/QF/mdfour.h | 8 ++++---- libs/util/mdfour.c | 19 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/include/QF/mdfour.h b/include/QF/mdfour.h index bff20aefb..ec8648cd2 100644 --- a/include/QF/mdfour.h +++ b/include/QF/mdfour.h @@ -29,17 +29,17 @@ #ifndef __QF_mdfour_h #define __QF_mdfour_h +#include "QF/qtypes.h" + /** \addtogroup crc */ ///@{ -#include "QF/uint32.h" - #define MDFOUR_DIGEST_BYTES 16 struct mdfour { - uint32 A, B, C, D; - uint32 totalN; + uint32_t A, B, C, D; + uint32_t totalN; }; void mdfour_begin(struct mdfour *md); // old: MD4Init diff --git a/libs/util/mdfour.c b/libs/util/mdfour.c index 99f57bef2..61bc46e9a 100644 --- a/libs/util/mdfour.c +++ b/libs/util/mdfour.c @@ -37,7 +37,6 @@ #endif #include "QF/mdfour.h" -#include "QF/uint32.h" /* NOTE: This code makes no attempt to be fast! It assumes that a int is at least 32 bits long @@ -62,12 +61,12 @@ static struct mdfour *m; /* this applies md4 to 64 byte chunks */ static void -mdfour64 (uint32 * M) +mdfour64 (uint32_t * M) { int j; - uint32 AA, BB, CC, DD; - uint32 X[16]; - uint32 A, B, C, D; + uint32_t AA, BB, CC, DD; + uint32_t X[16]; + uint32_t A, B, C, D; for (j = 0; j < 16; j++) X[j] = M[j]; @@ -154,7 +153,7 @@ mdfour64 (uint32 * M) } static void -copy64 (uint32 * M, const unsigned char *in) +copy64 (uint32_t * M, const unsigned char *in) { int i; @@ -164,7 +163,7 @@ copy64 (uint32 * M, const unsigned char *in) } static void -copy4 (unsigned char *out, uint32 x) +copy4 (unsigned char *out, uint32_t x) { out[0] = x & 0xFF; out[1] = (x >> 8) & 0xFF; @@ -186,8 +185,8 @@ static void mdfour_tail (const unsigned char *in, int n) { unsigned char buf[128]; - uint32 M[16]; - uint32 b; + uint32_t M[16]; + uint32_t b; m->totalN += n; @@ -214,7 +213,7 @@ mdfour_tail (const unsigned char *in, int n) VISIBLE void mdfour_update (struct mdfour *md, const unsigned char *in, int n) { - uint32 M[16]; + uint32_t M[16]; if (n == 0) mdfour_tail (in, n); From 8b6d05a4dd2cbc95508b2fc604a353c9fd8b774c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 16:36:23 +0900 Subject: [PATCH 131/444] [qwaq] Ensure mouse motion reporting gets turned off It seems that xterm automatically disables it when ncurses shuts down and mate-terminal does not, or maybe a different version of something. Still, good to clean up properly. --- tools/qwaq/qwaq-curses.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index a5db37e02..73fe6b39b 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -46,7 +46,8 @@ #define always_inline inline __attribute__((__always_inline__)) #define QUEUE_SIZE 16 -#define MOUSE_MOVES "\033[?1003h" // Make the terminal report mouse movements +#define MOUSE_MOVES_ON "\033[?1003h"// Make the terminal report mouse movements +#define MOUSE_MOVES_OFF "\033[?1003l"// Make the terminal report mouse movements #define STRING_ID_QUEUE_SIZE 8 // must be > 1 #define COMMAND_QUEUE_SIZE 128 #define CMD_SIZE(x) sizeof(x)/sizeof(x[0]) @@ -530,6 +531,7 @@ static void bi_shutdown (void) { if (need_endwin) { + write(1, MOUSE_MOVES_OFF, sizeof (MOUSE_MOVES_OFF) - 1); endwin (); } } @@ -787,7 +789,7 @@ bi_initialize (progs_t *pr) nonl (); nodelay (stdscr, TRUE); mousemask(ALL_MOUSE_EVENTS | REPORT_MOUSE_POSITION, NULL); - write(1, MOUSE_MOVES, sizeof (MOUSE_MOVES) - 1); + write(1, MOUSE_MOVES_ON, sizeof (MOUSE_MOVES_ON) - 1); refresh(); res->stdscr.win = stdscr; @@ -799,6 +801,7 @@ bi_qwaq_clear (progs_t *pr, void *data) __auto_type res = (qwaq_resources_t *) data; if (res->initialized) { + write(1, MOUSE_MOVES_OFF, sizeof (MOUSE_MOVES_OFF) - 1); endwin (); } need_endwin = 0; From e93ca9d828c55846f42c0bea00d227d8a9983233 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 20:13:25 +0900 Subject: [PATCH 132/444] [qfcc] Fix infinite loop in linker --- tools/qfcc/source/linker.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/source/linker.c b/tools/qfcc/source/linker.c index 3ce5ca3fd..5a9d367ce 100644 --- a/tools/qfcc/source/linker.c +++ b/tools/qfcc/source/linker.c @@ -1122,12 +1122,11 @@ undefined_def (qfo_def_t *def) if (func->code < 0) { continue; } - if ((pr_uint_t) func->code > reloc->offset) { - continue; - } - if (!best || reloc->offset - func->code < best_dist) { - best = func; - best_dist = reloc->offset - func->code; + if ((pr_uint_t) func->code <= reloc->offset) { + if (!best || reloc->offset - func->code < best_dist) { + best = func; + best_dist = reloc->offset - func->code; + } } func++; } From 271d836cd2ba2157b6ab51be740fef1fd7b60d62 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 29 Feb 2020 21:09:24 +0900 Subject: [PATCH 133/444] [qfcc] Catch static class instances in structs --- tools/qfcc/source/struct.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 5fe569d31..989b298ef 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -47,6 +47,7 @@ #include #include +#include "class.h" #include "def.h" #include "defspace.h" #include "diagnostic.h" @@ -123,6 +124,10 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) for (s = symtab->symbols; s; s = s->next) { if (s->sy_type != sy_var) continue; + if (obj_is_class (s->type)) { + error (0, "statically allocated instance of class %s", + s->type->t.class->name); + } if (su == 's') { symtab->size = RUP (symtab->size, s->type->alignment); s->s.offset = symtab->size; From c079eb851b4165c80aad33f88475f2f8465ec8f0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 00:40:55 +0900 Subject: [PATCH 134/444] [qwaq] Start work on the actual app It doesn't look good, but it does have panel based windows working, and using objects. Won't build reliably right now due to qwaq being in tools and thus building before ruamoko, but I'll fix that next. --- tools/qwaq/Makefile.am | 4 +- tools/qwaq/event.h | 15 ++- tools/qwaq/qwaq-app.h | 18 ++++ tools/qwaq/qwaq-app.r | 142 ++++++++++++++++++++-------- tools/qwaq/qwaq-curses.c | 198 +++++++++++++++++++++++++++++++++++++++ tools/qwaq/qwaq-curses.h | 37 ++++++++ tools/qwaq/qwaq-view.h | 44 +++++++++ tools/qwaq/qwaq-view.r | 105 +++++++++++++++++++++ tools/qwaq/qwaq-window.h | 11 +++ tools/qwaq/qwaq-window.r | 8 ++ 10 files changed, 540 insertions(+), 42 deletions(-) create mode 100644 tools/qwaq/qwaq-app.h create mode 100644 tools/qwaq/qwaq-curses.h create mode 100644 tools/qwaq/qwaq-view.h create mode 100644 tools/qwaq/qwaq-view.r create mode 100644 tools/qwaq/qwaq-window.h create mode 100644 tools/qwaq/qwaq-window.r diff --git a/tools/qwaq/Makefile.am b/tools/qwaq/Makefile.am index b6e9b8345..f38fc77e5 100644 --- a/tools/qwaq/Makefile.am +++ b/tools/qwaq/Makefile.am @@ -57,11 +57,11 @@ qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS) r_depfiles_remade= -qwaq_app_dat_SOURCES=qwaq-app.r +qwaq_app_dat_SOURCES=qwaq-app.r qwaq-view.r qwaq-window.r qwaq_app_obj=$(qwaq_app_dat_SOURCES:.r=.o) qwaq_app_dep=$(addprefix ./$(DEPDIR)/,$(qwaq_app_obj:.o=.Qo)) qwaq-app.dat$(EXEEXT): $(qwaq_app_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(qwaq_app_obj) + $(QFCC) $(QCFLAGS) -o $@ $(qwaq_app_obj) -lr include $(qwaq_app_dep) # am--include-marker r_depfiles_remade += $(qwaq_app_dep) diff --git a/tools/qwaq/event.h b/tools/qwaq/event.h index 933c61569..006d37c42 100644 --- a/tools/qwaq/event.h +++ b/tools/qwaq/event.h @@ -2,22 +2,33 @@ #define __qwaq_event_h typedef enum { - qe_idle, + qe_none, qe_key, qe_mouse, + qe_command, // application level command } qwaq_etype; -// right now, this is just a copy of ncurses MEVENT, but all int +typedef enum { + qc_valid, + qc_exit, + qc_error, +} qwaq_command; + typedef struct qwaq_mevent_s { int x, y; int buttons; } qwaq_mevent_t; +typedef struct qwaq_message_s { + qwaq_command command; +} qwaq_message_t; + typedef struct qwaq_event_s { qwaq_etype event_type; union { int key; qwaq_mevent_t mouse; + qwaq_message_t message; } e; } qwaq_event_t; diff --git a/tools/qwaq/qwaq-app.h b/tools/qwaq/qwaq-app.h new file mode 100644 index 000000000..c02beac67 --- /dev/null +++ b/tools/qwaq/qwaq-app.h @@ -0,0 +1,18 @@ +#ifndef __qwaq_app_h +#define __qwaq_app_h + +#include "qwaq-view.h" + +#include "event.h" + +@interface QwaqApplication: Object +{ + qwaq_event_t event; + qwaq_command endState; + View *view; +} +-run; +-handleEvent: (qwaq_event_t *) event; +@end + +#endif//__qwaq_app_h diff --git a/tools/qwaq/qwaq-app.r b/tools/qwaq/qwaq-app.r index 3e39f14a0..80ed06c41 100644 --- a/tools/qwaq/qwaq-app.r +++ b/tools/qwaq/qwaq-app.r @@ -1,7 +1,97 @@ -#include "color.h" -#include "event.h" +#include -typedef struct window_s *window_t; +#include "color.h" +#include "qwaq-app.h" +#include "qwaq-curses.h" +#include "qwaq-window.h" + +static AutoreleasePool *autorelease_pool; +static void +arp_start (void) +{ + autorelease_pool = [[AutoreleasePool alloc] init]; +} + +static void +arp_end (void) +{ + [autorelease_pool release]; + autorelease_pool = nil; +} + +@implementation QwaqApplication ++app +{ + return [[[self alloc] init] autorelease]; +} + +-init +{ + if (!(self = [super init])) { + return nil; + } + initialize (); + init_pair (1, COLOR_WHITE, COLOR_BLUE); + init_pair (2, COLOR_WHITE, COLOR_BLACK); + view = [[View viewFromWindow:stdscr] retain]; + [view setBackground: COLOR_PAIR (1)]; + Rect r = view.rect; + wprintf (view.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); + r.xpos = r.xlen / 4; + r.ypos = r.ylen / 4; + r.xlen /= 2; + r.ylen /= 2; + wprintf (view.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); + wrefresh(view.window); + Window *w; + [view addView: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; + wprintf (w.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); + return self; +} + +-run +{ + do { + arp_start (); + + update_panels (); + doupdate (); + get_event (&event); + if (event.event_type != qe_none) { + [self handleEvent: &event]; + } + + arp_end (); + } while (!endState); + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + [view handleEvent: event]; + if (event.event_type == qe_key && event.e.key == '\x18') { + event.event_type = qe_command; + event.e.message.command = qc_exit; + } + if (event.event_type == qe_command + && (event.e.message.command == qc_exit + || event.e.message.command == qc_error)) { + endState = event.e.message.command; + } + return self; +} +@end + +int main (int argc, string *argv) +{ + id app = [[QwaqApplication app] retain]; + + [app run]; + [app release]; + qwaq_event_t event; + get_event (&event); // XXX need a "wait for queue idle" + return 0; +} window_t stdscr = (window_t) 1; @@ -9,45 +99,21 @@ void initialize (void) = #0; window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; void destroy_window (window_t win) = #0; void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; +void wprintf (window_t win, string fmt, ...) = #0; void wrefresh (window_t win) = #0; - int get_event (qwaq_event_t *event) = #0; int max_colors (void) = #0; int max_color_pairs (void) = #0; int init_pair (int pair, int f, int b) = #0; void wbkgd (window_t win, int ch) = #0; -int main (int argc, string *argv) -{ - int ch = 0; - qwaq_event_t event = { }; - - initialize (); - init_pair (1, COLOR_WHITE, COLOR_BLUE); - wbkgd (stdscr, COLOR_PAIR(1)); - wrefresh (stdscr); - window_t win = create_window (20, 5, 50, 10); - wbkgd (win, COLOR_PAIR(0)); - mvwprintf (win, 0, 0, "Hi there! (q to quit)"); - mvwprintf (win, 1, 1, "(?)Oo."); - mvwprintf (win, 1, 2, " \\_O>"); - mvwprintf (win, 1, 3, " %d %d", max_colors (), max_color_pairs ()); - wrefresh (win); - do { - if (get_event (&event)) { - if (event.event_type == qe_key) { - ch = event.e.key; - mvwprintf (win, 1, 1, "key: %d", ch); - } else if (event.event_type == qe_mouse) { - mvwprintf (win, 1, 2, "mouse: %2d %2d %08x", - event.e.mouse.x, - event.e.mouse.y, - event.e.mouse.buttons); - } - wrefresh (win); - } - } while (ch != 'q' && ch != 'Q'); - destroy_window (win); - get_event (&event); - return 0; -} +panel_t create_panel (window_t window) = #0; +void destroy_panel (panel_t panel) = #0; +void hide_panel (panel_t panel) = #0; +void show_panel (panel_t panel) = #0; +void top_panel (panel_t panel) = #0; +void bottom_panel (panel_t panel) = #0; +void move_panel (panel_t panel, int x, int y) = #0; +window_t panel_window (panel_t panel) = #0; +void update_panels (void) = #0; +void doupdate (void) = #0; diff --git a/tools/qwaq/qwaq-curses.c b/tools/qwaq/qwaq-curses.c index 73fe6b39b..1c081e1eb 100644 --- a/tools/qwaq/qwaq-curses.c +++ b/tools/qwaq/qwaq-curses.c @@ -55,6 +55,7 @@ typedef enum qwaq_commands_e { qwaq_cmd_newwin, qwaq_cmd_delwin, + qwaq_cmd_getwrect, qwaq_cmd_new_panel, qwaq_cmd_del_panel, qwaq_cmd_hide_panel, @@ -62,7 +63,11 @@ typedef enum qwaq_commands_e { qwaq_cmd_top_panel, qwaq_cmd_bottom_panel, qwaq_cmd_move_panel, + qwaq_cmd_panel_window, + qwaq_cmd_update_panels, + qwaq_cmd_doupdate, qwaq_cmd_mvwaddstr, + qwaq_cmd_waddstr, qwaq_cmd_wrefresh, qwaq_cmd_init_pair, qwaq_cmd_wbkgd, @@ -141,6 +146,7 @@ typedef struct window_s { typedef struct panel_s { PANEL *panel; + int window_id; } panel_t; typedef struct qwaq_resources_s { @@ -297,6 +303,28 @@ cmd_delwin (qwaq_resources_t *res) window_free (res, window); } +static void +cmd_getwrect (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int xpos, ypos; + int xlen, ylen; + + window_t *window = get_window (res, __FUNCTION__, window_id); + getparyx (window->win, ypos, xpos); + if (xpos == -1 && ypos ==-1) { + getbegyx (window->win, ypos, xpos); + } + getmaxyx (window->win, ylen, xlen); + + int cmd_result[] = { qwaq_cmd_getwrect, xpos, ypos, xlen, ylen }; + + // loop + if (RB_SPACE_AVAILABLE (res->results) >= CMD_SIZE (cmd_result)) { + RB_WRITE_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); + } +} + static void cmd_new_panel (qwaq_resources_t *res) { @@ -305,6 +333,7 @@ cmd_new_panel (qwaq_resources_t *res) window_t *window = get_window (res, __FUNCTION__, window_id); panel_t *panel = panel_new (res); panel->panel = new_panel (window->win); + panel->window_id = window_id; int panel_id = panel_index (res, panel); int cmd_result[] = { qwaq_cmd_new_panel, panel_id }; @@ -377,6 +406,34 @@ cmd_move_panel (qwaq_resources_t *res) panel_free (res, panel); } +static void +cmd_panel_window (qwaq_resources_t *res) +{ + int panel_id = RB_PEEK_DATA (res->command_queue, 2); + + panel_t *panel = get_panel (res, __FUNCTION__, panel_id); + + int window_id = panel->window_id; + int cmd_result[] = { qwaq_cmd_panel_window, window_id, }; + + // loop + if (RB_SPACE_AVAILABLE (res->results) >= CMD_SIZE (cmd_result)) { + RB_WRITE_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); + } +} + +static void +cmd_update_panels (qwaq_resources_t *res) +{ + update_panels (); +} + +static void +cmd_doupdate (qwaq_resources_t *res) +{ + doupdate (); +} + static void cmd_mvwaddstr (qwaq_resources_t *res) { @@ -390,6 +447,17 @@ cmd_mvwaddstr (qwaq_resources_t *res) release_string (res, string_id); } +static void +cmd_waddstr (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int string_id = RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + waddstr (window->win, res->strings[string_id].str); + release_string (res, string_id); +} + static void cmd_wrefresh (qwaq_resources_t *res) { @@ -430,6 +498,9 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_delwin: cmd_delwin (res); break; + case qwaq_cmd_getwrect: + cmd_getwrect (res); + break; case qwaq_cmd_new_panel: cmd_new_panel (res); break; @@ -451,9 +522,21 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_move_panel: cmd_move_panel (res); break; + case qwaq_cmd_panel_window: + cmd_panel_window (res); + break; + case qwaq_cmd_update_panels: + cmd_update_panels (res); + break; + case qwaq_cmd_doupdate: + cmd_doupdate (res); + break; case qwaq_cmd_mvwaddstr: cmd_mvwaddstr (res); break; + case qwaq_cmd_waddstr: + cmd_waddstr (res); + break; case qwaq_cmd_wrefresh: cmd_wrefresh (res); break; @@ -583,6 +666,37 @@ bi_delwin (progs_t *pr) } } +static void +bi_getwrect (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_getwrect, 0, window_id, }; + + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + // XXX should just wait on the mutex + process_commands (res); + process_input (res); + // locking and loop until id is correct + if (RB_DATA_AVAILABLE (res->results) + && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_getwrect) { + int cmd_result[5]; + RB_READ_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); + // return xpos, ypos, xlen, ylen + (&R_INT (pr))[0] = cmd_result[1]; + (&R_INT (pr))[1] = cmd_result[2]; + (&R_INT (pr))[2] = cmd_result[3]; + (&R_INT (pr))[3] = cmd_result[4]; + } + } +} + static void bi_new_panel (progs_t *pr) { @@ -672,6 +786,58 @@ bi_move_panel (progs_t *pr) } } +static void +bi_panel_window (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int panel_id = P_INT (pr, 0); + + if (get_panel (res, __FUNCTION__, panel_id)) { + int command[] = { qwaq_cmd_panel_window, 0, panel_id, }; + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + // XXX should just wait on the mutex + process_commands (res); + process_input (res); + // locking and loop until id is correct + if (RB_DATA_AVAILABLE (res->results) + && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_panel_window) { + int cmd_result[2]; + RB_READ_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); + (&R_INT (pr))[0] = cmd_result[0]; + } + } +} + +static void +bi_update_panels (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_update_panels, 0, }; + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } +} + +static void +bi_doupdate (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + int command[] = { qwaq_cmd_doupdate, 0, }; + command[1] = CMD_SIZE(command); + + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } +} + static void bi_mvwprintf (progs_t *pr) { @@ -701,6 +867,33 @@ bi_mvwprintf (progs_t *pr) } } +static void +bi_wprintf (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + const char *fmt = P_GSTRING (pr, 1); + int count = pr->pr_argc - 2; + pr_type_t **args = pr->pr_params + 2; + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_waddstr, 0, + window_id, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "waddstr", fmt, count, args); + if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { + RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); + } + } +} + static void bi_wrefresh (progs_t *pr) { @@ -813,6 +1006,7 @@ static builtin_t builtins[] = { {"initialize", bi_initialize, -1}, {"create_window", bi_newwin, -1}, {"destroy_window", bi_delwin, -1}, + {"getwrect", bi_getwrect, -1}, {"create_panel", bi_new_panel, -1}, {"destroy_panel", bi_del_panel, -1}, {"hide_panel", bi_hide_panel, -1}, @@ -820,7 +1014,11 @@ static builtin_t builtins[] = { {"top_panel", bi_top_panel, -1}, {"bottom_panel", bi_bottom_panel, -1}, {"move_panel", bi_move_panel, -1}, + {"panel_window", bi_panel_window, -1}, + {"update_panels", bi_update_panels, -1}, + {"doupdate", bi_doupdate, -1}, {"mvwprintf", bi_mvwprintf, -1}, + {"wprintf", bi_wprintf, -1}, {"wrefresh", bi_wrefresh, -1}, {"get_event", bi_get_event, -1}, {"max_colors", bi_max_colors, -1}, diff --git a/tools/qwaq/qwaq-curses.h b/tools/qwaq/qwaq-curses.h new file mode 100644 index 000000000..751c521a7 --- /dev/null +++ b/tools/qwaq/qwaq-curses.h @@ -0,0 +1,37 @@ +#ifndef __qwaq_curses_h +#define __qwaq_curses_h + +#include "event.h" + +#ifdef __QFCC__ +typedef struct window_s *window_t; +typedef struct panel_s *panel_t; + +@extern window_t stdscr; + +@extern void initialize (void); +@extern window_t create_window (int xpos, int ypos, int xlen, int ylen); +@extern void destroy_window (window_t win); +@extern void mvwprintf (window_t win, int x, int y, string fmt, ...); +@extern void wprintf (window_t win, string fmt, ...); +@extern void wrefresh (window_t win); + +@extern panel_t create_panel (window_t window); +@extern void destroy_panel (panel_t panel); +@extern void hide_panel (panel_t panel); +@extern void show_panel (panel_t panel); +@extern void top_panel (panel_t panel); +@extern void bottom_panel (panel_t panel); +@extern void move_panel (panel_t panel, int x, int y); +@extern window_t panel_window (panel_t panel); +@extern void update_panels (void); +@extern void doupdate (void); + +@extern int get_event (qwaq_event_t *event); +@extern int max_colors (void); +@extern int max_color_pairs (void); +@extern int init_pair (int pair, int f, int b); +@extern void wbkgd (window_t win, int ch); +#endif + +#endif//__qwaq_curses_h diff --git a/tools/qwaq/qwaq-view.h b/tools/qwaq/qwaq-view.h new file mode 100644 index 000000000..63a9b4db5 --- /dev/null +++ b/tools/qwaq/qwaq-view.h @@ -0,0 +1,44 @@ +#ifndef __qwaq_view_h +#define __qwaq_view_h + +#include +#include + +#include "event.h" +#include "qwaq-curses.h" + +typedef struct { + int xpos; + int ypos; + int xlen; + int ylen; +} Rect; + +typedef struct { + int x; + int y; +} Point; + +@extern Rect makeRect (int xpos, int ypos, int xlen, int ylen); +//XXX will not work if point or rect point to a local variabl +@extern int rectContainsPoint (Rect *rect, Point *point); +@extern Rect getwrect (window_t window); + +@interface View: Object +{ + Rect rect; + Rect absRect; + Array *views; + Point point; // can't be local :( + View *focusedView; + window_t window; + panel_t panel; +} ++viewFromWindow: (window_t) window; +-initWithRect: (Rect) rect; +-handleEvent: (qwaq_event_t *) event; +-addView: (View *) view; +-setBackground: (int) ch; +@end + +#endif//__qwaq_view_h diff --git a/tools/qwaq/qwaq-view.r b/tools/qwaq/qwaq-view.r new file mode 100644 index 000000000..3673b8fee --- /dev/null +++ b/tools/qwaq/qwaq-view.r @@ -0,0 +1,105 @@ +#include "qwaq-curses.h" +#include "qwaq-view.h" + +Rect +makeRect (int xpos, int ypos, int xlen, int ylen) +{ + Rect rect = {xpos, ypos, xlen, ylen}; + return rect; +} + +int +rectContainsPoint (Rect *rect, Point *point) +{ + return ((point.x >= rect.xpos && point.x < rect.xpos + rect.xlen) + && (point.y >= rect.ypos && point.y < rect.ypos + rect.ylen)); +} + +@implementation View + ++viewFromWindow: (window_t) window +{ + return [[[self alloc] initFromWindow: window] autorelease]; +} + +-initWithRect: (Rect) rect +{ + if (!(self = [super init])) { + return nil; + } + self.rect = rect; + self.absRect = rect; + self.window = create_window (rect.xpos, rect.ypos, rect.xlen, rect.ylen); + self.panel = create_panel (self.window); + return self; +} + +-initFromWindow: (window_t) window +{ + if (!(self = [super init])) { + return nil; + } + rect = getwrect (window); + self.window = window; + self.panel = nil; + return self; +} + +-initWithPanel: (panel_t) panel +{ + if (!(self = [super init])) { + return nil; + } + self.panel = panel; + self.window = panel_window (panel); + rect = getwrect (window); + return self; +} + +-addView: (View *) view +{ + [views addObject: view]; + return self; +} + +-setBackground: (int) ch +{ + wbkgd (window, ch); + if (!panel) { + wrefresh (window); + } + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + switch (event.event_type) { + case qe_mouse: + point.x = event.e.mouse.x; + point.y = event.e.mouse.y; + for (int i = [views count]; i--> 0; ) { + View *v = [views objectAtIndex: i]; + if (rectContainsPoint (&v.absRect, &point)) { + [v handleEvent: event]; + break; + } + } + break; + case qe_key: + case qe_command: + if (focusedView) { + [focusedView handleEvent: event]; + for (int i = [views count]; + event.event_type != qe_none && i--> 0; ) { + View *v = [views objectAtIndex: i]; + [v handleEvent: event]; + } + } + break; + } + return self; +} + +@end + +Rect getwrect (window_t window) = #0; diff --git a/tools/qwaq/qwaq-window.h b/tools/qwaq/qwaq-window.h new file mode 100644 index 000000000..13730ccca --- /dev/null +++ b/tools/qwaq/qwaq-window.h @@ -0,0 +1,11 @@ +#ifndef __qwaq_window_h +#define __qwaq_window_h + +#include "qwaq-view.h" + +@interface Window: View +{ +} +@end + +#endif//__qwaq_window_h diff --git a/tools/qwaq/qwaq-window.r b/tools/qwaq/qwaq-window.r new file mode 100644 index 000000000..48722cdc2 --- /dev/null +++ b/tools/qwaq/qwaq-window.r @@ -0,0 +1,8 @@ +#include "qwaq-window.h" + +@implementation Window ++windowWithRect: (Rect) rect +{ + return [[[self alloc] initWithRect: rect] autorelease]; +} +@end From df2ed4b0863725c48d4c2c07532b0cfa943f7a42 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 00:55:15 +0900 Subject: [PATCH 135/444] [qwaq] Move from tools to ruamoko This fixes the dependency issues between qwaq and ruamoko. qwaq is actually older than ruamoko. That little language feature test has come a long way. However, I'm considering moving to non-recursive make, but... --- config.d/ac_config_files.m4 | 3 +-- config.d/build_control.m4 | 9 ++++++--- ruamoko/Makefile.am | 3 ++- {tools => ruamoko}/qwaq/.gdbinit | 0 {tools => ruamoko}/qwaq/Makefile.am | 0 {tools => ruamoko}/qwaq/builtins.c | 0 {tools => ruamoko}/qwaq/color.h | 0 {tools => ruamoko}/qwaq/event.h | 0 {tools => ruamoko}/qwaq/main.c | 0 {tools => ruamoko}/qwaq/progs.src.in | 0 {tools => ruamoko}/qwaq/qwaq-app.h | 0 {tools => ruamoko}/qwaq/qwaq-app.r | 0 {tools => ruamoko}/qwaq/qwaq-bi.c | 0 {tools => ruamoko}/qwaq/qwaq-curses.c | 0 {tools => ruamoko}/qwaq/qwaq-curses.h | 0 {tools => ruamoko}/qwaq/qwaq-view.h | 0 {tools => ruamoko}/qwaq/qwaq-view.r | 0 {tools => ruamoko}/qwaq/qwaq-window.h | 0 {tools => ruamoko}/qwaq/qwaq-window.r | 0 {tools => ruamoko}/qwaq/qwaq.c | 0 {tools => ruamoko}/qwaq/qwaq.h | 0 tools/Makefile.am | 2 +- 22 files changed, 10 insertions(+), 7 deletions(-) rename {tools => ruamoko}/qwaq/.gdbinit (100%) rename {tools => ruamoko}/qwaq/Makefile.am (100%) rename {tools => ruamoko}/qwaq/builtins.c (100%) rename {tools => ruamoko}/qwaq/color.h (100%) rename {tools => ruamoko}/qwaq/event.h (100%) rename {tools => ruamoko}/qwaq/main.c (100%) rename {tools => ruamoko}/qwaq/progs.src.in (100%) rename {tools => ruamoko}/qwaq/qwaq-app.h (100%) rename {tools => ruamoko}/qwaq/qwaq-app.r (100%) rename {tools => ruamoko}/qwaq/qwaq-bi.c (100%) rename {tools => ruamoko}/qwaq/qwaq-curses.c (100%) rename {tools => ruamoko}/qwaq/qwaq-curses.h (100%) rename {tools => ruamoko}/qwaq/qwaq-view.h (100%) rename {tools => ruamoko}/qwaq/qwaq-view.r (100%) rename {tools => ruamoko}/qwaq/qwaq-window.h (100%) rename {tools => ruamoko}/qwaq/qwaq-window.r (100%) rename {tools => ruamoko}/qwaq/qwaq.c (100%) rename {tools => ruamoko}/qwaq/qwaq.h (100%) diff --git a/config.d/ac_config_files.m4 b/config.d/ac_config_files.m4 index 587a515d9..6f49d4bb5 100644 --- a/config.d/ac_config_files.m4 +++ b/config.d/ac_config_files.m4 @@ -74,8 +74,6 @@ tools/qfvis/Makefile tools/qfvis/include/Makefile tools/qfvis/source/Makefile - tools/qwaq/Makefile - tools/qwaq/progs.src tools/wad/Makefile tools/wav/Makefile @@ -87,6 +85,7 @@ ruamoko/gui/Makefile ruamoko/cl_menu/Makefile ruamoko/scheme/Makefile + ruamoko/qwaq/Makefile pkg-config/Makefile pkg-config/qfcc.pc diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index a53bf74a4..98517088e 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -230,7 +230,8 @@ if test "x$ENABLE_tools_qwaq" = xyes; then if test "x$HAVE_PANEL" = xyes -a "x$HAVE_PTHREAD" = xyes; then QWAQ_TARGETS="$QWAQ_TARGETS qwaq-curses\$(EXEEXT)" fi - QF_NEED(tools,[qfcc qwaq]) + QF_NEED(tools,[qfcc]) + QF_NEED(ruamoko,[qwaq]) QF_NEED(libs,[ruamoko gamecode util]) fi if test "x$ENABLE_tools_wad" = xyes; then @@ -244,11 +245,13 @@ fi QF_NEED(top, [libs hw nq qtv qw]) -QF_PROCESS_NEED_DIRS(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis qwaq wad wav]) -QF_PROCESS_NEED_FUNC(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis qwaq wad wav], QF_NEED(top,tools)) +QF_PROCESS_NEED_DIRS(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis wad wav]) +QF_PROCESS_NEED_FUNC(tools,[bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis wad wav], QF_NEED(top,tools)) QF_PROCESS_NEED_DIRS(libs,[util gamecode ruamoko gib audio image models video console net qw client]) +QF_PROCESS_NEED_DIRS(ruamoko,[qwaq]) + if test "$ENABLE_tools_qfcc" = "yes" -a "$ENABLE_tools_pak" = "yes"; then QF_NEED(top, [ruamoko]) fi diff --git a/ruamoko/Makefile.am b/ruamoko/Makefile.am index 779fc1439..b899690f8 100644 --- a/ruamoko/Makefile.am +++ b/ruamoko/Makefile.am @@ -1,4 +1,5 @@ -SUBDIRS= include lib game gui cl_menu scheme +SUBDIRS= include lib game gui cl_menu scheme @ruamoko_dirs@ +DIST_SUBDIRS=qwaq doc: Doxyfile doxygen diff --git a/tools/qwaq/.gdbinit b/ruamoko/qwaq/.gdbinit similarity index 100% rename from tools/qwaq/.gdbinit rename to ruamoko/qwaq/.gdbinit diff --git a/tools/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am similarity index 100% rename from tools/qwaq/Makefile.am rename to ruamoko/qwaq/Makefile.am diff --git a/tools/qwaq/builtins.c b/ruamoko/qwaq/builtins.c similarity index 100% rename from tools/qwaq/builtins.c rename to ruamoko/qwaq/builtins.c diff --git a/tools/qwaq/color.h b/ruamoko/qwaq/color.h similarity index 100% rename from tools/qwaq/color.h rename to ruamoko/qwaq/color.h diff --git a/tools/qwaq/event.h b/ruamoko/qwaq/event.h similarity index 100% rename from tools/qwaq/event.h rename to ruamoko/qwaq/event.h diff --git a/tools/qwaq/main.c b/ruamoko/qwaq/main.c similarity index 100% rename from tools/qwaq/main.c rename to ruamoko/qwaq/main.c diff --git a/tools/qwaq/progs.src.in b/ruamoko/qwaq/progs.src.in similarity index 100% rename from tools/qwaq/progs.src.in rename to ruamoko/qwaq/progs.src.in diff --git a/tools/qwaq/qwaq-app.h b/ruamoko/qwaq/qwaq-app.h similarity index 100% rename from tools/qwaq/qwaq-app.h rename to ruamoko/qwaq/qwaq-app.h diff --git a/tools/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r similarity index 100% rename from tools/qwaq/qwaq-app.r rename to ruamoko/qwaq/qwaq-app.r diff --git a/tools/qwaq/qwaq-bi.c b/ruamoko/qwaq/qwaq-bi.c similarity index 100% rename from tools/qwaq/qwaq-bi.c rename to ruamoko/qwaq/qwaq-bi.c diff --git a/tools/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c similarity index 100% rename from tools/qwaq/qwaq-curses.c rename to ruamoko/qwaq/qwaq-curses.c diff --git a/tools/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h similarity index 100% rename from tools/qwaq/qwaq-curses.h rename to ruamoko/qwaq/qwaq-curses.h diff --git a/tools/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h similarity index 100% rename from tools/qwaq/qwaq-view.h rename to ruamoko/qwaq/qwaq-view.h diff --git a/tools/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r similarity index 100% rename from tools/qwaq/qwaq-view.r rename to ruamoko/qwaq/qwaq-view.r diff --git a/tools/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h similarity index 100% rename from tools/qwaq/qwaq-window.h rename to ruamoko/qwaq/qwaq-window.h diff --git a/tools/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r similarity index 100% rename from tools/qwaq/qwaq-window.r rename to ruamoko/qwaq/qwaq-window.r diff --git a/tools/qwaq/qwaq.c b/ruamoko/qwaq/qwaq.c similarity index 100% rename from tools/qwaq/qwaq.c rename to ruamoko/qwaq/qwaq.c diff --git a/tools/qwaq/qwaq.h b/ruamoko/qwaq/qwaq.h similarity index 100% rename from tools/qwaq/qwaq.h rename to ruamoko/qwaq/qwaq.h diff --git a/tools/Makefile.am b/tools/Makefile.am index 008638b4a..768efdccb 100644 --- a/tools/Makefile.am +++ b/tools/Makefile.am @@ -1,5 +1,5 @@ SUBDIRS=@tools_dirs@ -DIST_SUBDIRS=bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis qwaq wad wav +DIST_SUBDIRS=bsp2img carne pak qfbsp qfcc qflight qflmp qfmodelgen qfspritegen qfvis wad wav EXTRA_DIST= \ io_mesh_qfmdl/export_mdl.py io_mesh_qfmdl/import_mdl.py \ io_mesh_qfmdl/__init__.py io_mesh_qfmdl/mdl.py io_mesh_qfmdl/qfplist.py \ From 1033716b2b7c893a2d0098c299c313d80bdd89c9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 13:53:18 +0900 Subject: [PATCH 136/444] [qfcc] Fix some curly space --- tools/qfcc/source/class.c | 3 ++- tools/qfcc/source/method.c | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index caa1967cd..841fa53a0 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -925,7 +925,7 @@ class_find_method (class_type_t *class_type, method_t *method) start_methods = methods; start_class = class; while (class) { - for (m = methods->head; m; m = m->next) + for (m = methods->head; m; m = m->next) { if (method_compare (method, m)) { if (m->type != method->type) error (0, "method type mismatch"); @@ -937,6 +937,7 @@ class_find_method (class_type_t *class_type, method_t *method) method_set_param_names (m, method); return m; } + } if (class->methods == methods) class = class->super_class; else diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 883133b64..726acfd76 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -474,7 +474,7 @@ emit_methods (methodlist_t *methods, const char *name, int instance) if (!methods) return 0; - for (count = 0, m = methods->head; m; m = m->next) + for (count = 0, m = methods->head; m; m = m->next) { if (!m->instance == !instance) { if (!m->def && options.warnings.unimplemented) { warning (0, "Method `%c%s' not implemented", @@ -483,6 +483,7 @@ emit_methods (methodlist_t *methods, const char *name, int instance) if (m->def) count++; } + } if (!count) return 0; methods->count = count; From caa297b756d5ced81908d66b7b23eb600e61c6c6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 16:13:18 +0900 Subject: [PATCH 137/444] [qfcc] Remove type alias encoding It proved to be too fragile in its current implementation. It broke pointers to incomplete structs and switch enum checking, and getting it to work for other things was overly invasive. I still want the encoding, but need to come up with something more robust.a --- include/QF/pr_type.h | 7 ---- tools/qfcc/include/type.h | 12 ++----- tools/qfcc/source/def.c | 2 +- tools/qfcc/source/dump_globals.c | 4 --- tools/qfcc/source/expr.c | 6 ++-- tools/qfcc/source/function.c | 5 +-- tools/qfcc/source/obj_file.c | 6 ---- tools/qfcc/source/obj_type.c | 18 ---------- tools/qfcc/source/qc-parse.y | 3 -- tools/qfcc/source/type.c | 56 ++------------------------------ tools/qfcc/test/Makefile.am | 1 - 11 files changed, 8 insertions(+), 112 deletions(-) diff --git a/include/QF/pr_type.h b/include/QF/pr_type.h index 179a4e407..c7fbc4b9c 100644 --- a/include/QF/pr_type.h +++ b/include/QF/pr_type.h @@ -47,14 +47,8 @@ typedef enum { ty_enum, ty_array, ty_class, - ty_alias, } ty_meta_e; -typedef struct qfot_alias_s { - pr_int_t type; ///< type at end of alias chain - pointer_t aux_type; ///< referenced type - string_t name; ///< alias name -} qfot_alias_t; typedef struct qfot_fldptr_s { pr_int_t type; ///< ev_field or ev_pointer @@ -110,7 +104,6 @@ typedef struct qfot_type_s { qfot_struct_t strct; ///< ty_struct/ty_union/ty_enum qfot_array_t array; ///< ty_array string_t class; ///< ty_class - qfot_alias_t alias; ///< ty_alias } t; } qfot_type_t; diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 46d524574..21f4feb2c 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -51,10 +51,6 @@ typedef struct ty_array_s { int size; } ty_array_t; -typedef struct ty_alias_s { - struct type_s *type; -} ty_alias_t; - typedef struct type_s { etype_t type; ///< ev_invalid means structure/array etc const char *name; @@ -68,7 +64,6 @@ typedef struct type_s { ty_array_t array; struct symtab_s *symtab; struct class_s *class; - ty_alias_t alias; } t; struct type_s *next; int freeable; @@ -133,9 +128,8 @@ void chain_type (type_t *type); /** Append a type to the end of a type chain. - The type chain must be made up of only field, pointer, function, array - and alias (typedef) types, as other types do not have auxiliary type - fields. + The type chain must be made up of only field, pointer, function, and + array types, as other types do not have auxiliary type fields. \param type The type chain to which the type will be appended. \param new The type to be appended. May be any type. @@ -149,13 +143,11 @@ type_t *field_type (type_t *aux); type_t *pointer_type (type_t *aux); type_t *array_type (type_t *aux, int size); type_t *based_array_type (type_t *aux, int base, int top); -type_t *alias_type (type_t *aux, const char *name); void print_type_str (struct dstring_s *str, const type_t *type); void print_type (const type_t *type); const char *encode_params (const type_t *type); void encode_type (struct dstring_s *encoding, const type_t *type); const char *type_get_encoding (const type_t *type); -const type_t *unalias_type (const type_t *type) __attribute__((pure)); int is_void (const type_t *type) __attribute__((pure)); int is_enum (const type_t *type) __attribute__((pure)); int is_integer (const type_t *type) __attribute__((pure)); diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 049740563..82e88c5ae 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -358,7 +358,7 @@ init_elements (struct def_s *def, expr_t *eles) num_elements = i; } else if (is_struct (def->type) || is_vector (def->type) || is_quaternion (def->type)) { - symtab_t *symtab = unalias_type (def->type)->t.symtab; + symtab_t *symtab = def->type->t.symtab; symbol_t *field; for (i = 0, field = symtab->symbols; field; field = field->next) { diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 9343a0ac7..657f016e8 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -547,10 +547,6 @@ dump_qfo_types (qfo_t *qfo, int base_address) printf (" %-5x %d %d\n", type->t.array.type, type->t.array.base, type->t.array.size); break; - case ty_alias: - printf (" %s %d %-5x\n", QFO_GETSTR (qfo, type->t.alias.name), - type->t.alias.type, type->t.alias.aux_type); - break; case ty_class: printf (" %-5x\n", type->t.class); break; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 7d5baddb9..ad91a8d81 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1140,7 +1140,7 @@ append_expr (expr_t *block, expr_t *e) static symbol_t * get_struct_field (const type_t *t1, expr_t *e1, expr_t *e2) { - symtab_t *strct = unalias_type (t1)->t.symtab; + symtab_t *strct = t1->t.symtab; symbol_t *sym = e2->e.symbol;//FIXME need to check symbol_t *field; @@ -1165,7 +1165,6 @@ field_expr (expr_t *e1, expr_t *e2) t1 = get_type (e1); if (e1->type == ex_error) return e1; - t1 = unalias_type (t1); if (t1->type == ev_entity) { symbol_t *field = 0; @@ -1639,7 +1638,6 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) expr_t *call; expr_t *err = 0; - ftype = unalias_type (ftype); for (e = params; e; e = e->next) { if (e->type == ex_error) @@ -2375,7 +2373,7 @@ cast_expr (type_t *dstType, expr_t *e) srcType = get_type (e); - if (unalias_type (dstType) == unalias_type (srcType)) + if (dstType == srcType) return e; if ((dstType == type_default && is_enum (srcType)) diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index eb376e0ea..538bb8f65 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -177,10 +177,7 @@ parse_params (type_t *type, param_t *parms) internal_error (0, 0); new->t.func.num_params = -(new->t.func.num_params + 1); } else if (p->type) { - // FIXME this cast should not be necessary, but making the - // type system const-correct would probably take a rewrite - type_t *t = (type_t *) unalias_type (p->type); - new->t.func.param_types[new->t.func.num_params] = t; + new->t.func.param_types[new->t.func.num_params] = p->type; new->t.func.num_params++; } } diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index d1c5296c4..6ceb1a74e 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -648,10 +648,8 @@ get_def_type (qfo_t *qfo, pointer_t type) type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { case ty_basic: - case ty_alias: // field, pointer and function types store their basic type in // the same location. - // alias types store the basic type at the end of the alias chain return type_def->t.type; case ty_struct: case ty_union: @@ -676,8 +674,6 @@ get_type_size (qfo_t *qfo, pointer_t type) return 1; type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { - case ty_alias: - return get_type_size (qfo, type_def->t.alias.aux_type); case ty_basic: // field, pointer and function types store their basic type in // the same location. @@ -726,8 +722,6 @@ get_type_alignment_log (qfo_t *qfo, pointer_t type) return 0; type_def = QFO_POINTER (qfo, qfo_type_space, qfot_type_t, type); switch ((ty_meta_e)type_def->meta) { - case ty_alias: - return get_type_alignment_log (qfo, type_def->t.alias.aux_type); case ty_basic: // field, pointer and function types store their basic type in // the same location. diff --git a/tools/qfcc/source/obj_type.c b/tools/qfcc/source/obj_type.c index ff2409986..c21e7e576 100644 --- a/tools/qfcc/source/obj_type.c +++ b/tools/qfcc/source/obj_type.c @@ -253,23 +253,6 @@ qfo_encode_class (type_t *type) return def; } -static def_t * -qfo_encode_alias (type_t *type) -{ - qfot_type_t *enc; - def_t *def; - def_t *alias_type_def; - - alias_type_def = qfo_encode_type (type->t.alias.type); - - def = qfo_new_encoding (type, sizeof (enc->t.alias)); - enc = D_POINTER (qfot_type_t, def); - enc->t.alias.type = type->type; - ENC_DEF (enc->t.alias.aux_type, alias_type_def); - ENC_STR (enc->t.alias.name, type->name); - return def; -} - def_t * qfo_encode_type (type_t *type) { @@ -282,7 +265,6 @@ qfo_encode_type (type_t *type) qfo_encode_struct, // ty_enum qfo_encode_array, // ty_array qfo_encode_class, // ty_class - qfo_encode_alias, // ty_alias }; if (type->type_def && type->type_def->external) { diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 07c12692e..1bcd240c1 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -406,7 +406,6 @@ external_decl $1->type = find_type (append_type ($1->type, spec.type)); if (spec.is_typedef) { $1->sy_type = sy_type; - $1->type = alias_type ($1->type, $1->name); symtab_addsymbol (current_symtab, $1); } else { initialize_def ($1, 0, current_symtab->space, spec.storage); @@ -422,7 +421,6 @@ external_decl if (spec.is_typedef) { error (0, "typedef %s is initialized", $1->name); $1->sy_type = sy_type; - $1->type = alias_type ($1->type, $1->name); symtab_addsymbol (current_symtab, $1); } else { initialize_def ($1, $2, current_symtab->space, spec.storage); @@ -436,7 +434,6 @@ external_decl $1->type = find_type (append_type ($1->type, spec.type)); if (spec.is_typedef) { $1->sy_type = sy_type; - $1->type = alias_type ($1->type, $1->name); symtab_addsymbol (current_symtab, $1); } else { $1 = function_symbol ($1, spec.is_overload, 1); diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index a583a943c..4fd77a9fd 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -297,8 +297,6 @@ types_same (type_t *a, type_t *b) if (a->t.class != b->t.class) return 0; return compare_protocols (a->protos, b->protos); - case ty_alias: - return !strcmp (a->name, b->name); } internal_error (0, "we be broke"); } @@ -348,9 +346,6 @@ find_type (type_t *type) break; case ty_class: break; - case ty_alias: - type->t.alias.type = find_type (type->t.alias.type); - break; } } @@ -450,25 +445,6 @@ based_array_type (type_t *aux, int base, int top) return new; } -type_t * -alias_type (type_t *aux, const char *name) -{ - type_t _new; - type_t *new = &_new; - - if (!aux || !name) { - internal_error (0, "alias to null type or with no name"); - } - memset (&_new, 0, sizeof (_new)); - new->name = save_string (name); - new->meta = ty_alias; - new->type = aux->type; - new->alignment = aux->alignment; - new->t.alias.type = aux; - new = find_type (new); - return new; -} - void print_type_str (dstring_t *str, const type_t *type) { @@ -500,11 +476,6 @@ print_type_str (dstring_t *str, const type_t *type) dasprintf (str, "[%d]", type->t.array.size); } return; - case ty_alias: - dasprintf (str, "({%s=", type->name); - print_type_str (str, type->t.alias.type); - dstring_appendstr (str, "})"); - return; case ty_basic: switch (type->type) { case ev_field: @@ -658,11 +629,6 @@ encode_type (dstring_t *encoding, const type_t *type) encode_type (encoding, type->t.array.type); dasprintf (encoding, "]"); return; - case ty_alias: - dasprintf (encoding, "{%s>", type->name); - encode_type (encoding, type->t.alias.type); - dasprintf (encoding, "}"); - return; case ty_basic: switch (type->type) { case ev_void: @@ -730,15 +696,6 @@ encode_type (dstring_t *encoding, const type_t *type) internal_error (0, "bad type meta:type %d:%d", type->meta, type->type); } -const type_t * -unalias_type (const type_t *type) -{ - while (type->meta == ty_alias) { - type = type->t.alias.type; - } - return type; -} - int is_void (const type_t *type) { @@ -748,7 +705,6 @@ is_void (const type_t *type) int is_enum (const type_t *type) { - type = unalias_type (type); if (type->type == ev_invalid && type->meta == ty_enum) return 1; return 0; @@ -833,7 +789,6 @@ is_math (const type_t *type) int is_struct (const type_t *type) { - type = unalias_type (type); if (type->type == ev_invalid && (type->meta == ty_struct || type->meta == ty_union)) return 1; @@ -859,7 +814,6 @@ is_field (const type_t *type) int is_array (const type_t *type) { - type = unalias_type (type); if (type->type == ev_invalid && type->meta == ty_array) return 1; return 0; @@ -884,8 +838,6 @@ is_string (const type_t *type) int type_compatible (const type_t *dst, const type_t *src) { - dst = unalias_type (dst); - src = unalias_type (src); // same type if (dst == src) { return 1; @@ -905,8 +857,6 @@ type_compatible (const type_t *dst, const type_t *src) int type_assignable (const type_t *dst, const type_t *src) { - dst = unalias_type (dst); - src = unalias_type (src); int ret; // same type @@ -932,8 +882,8 @@ type_assignable (const type_t *dst, const type_t *src) if (ret >= 0) return ret; - dst = unalias_type (dst->t.fldptr.type); - src = unalias_type (src->t.fldptr.type); + dst = dst->t.fldptr.type; + src = src->t.fldptr.type; if (dst == src) { return 1; } @@ -972,8 +922,6 @@ type_size (const type_t *type) size += type_size (class->super_class->type); return size; } - case ty_alias: - return type_size (type->t.alias.type); } return 0; } diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index c53dd7cbf..937686a6e 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -55,7 +55,6 @@ test_progs_dat=\ structstruct.dat \ swap.dat \ triangle.dat \ - typedef.dat \ vecexpr.dat \ vecinit.dat \ voidfor.dat \ From 4d076da4b6b2b78f7f1b0315331eae0f3a2f7cc8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 16:15:33 +0900 Subject: [PATCH 138/444] [qwaq] Fix warning hidden by type alias bug --- ruamoko/qwaq/qwaq-view.r | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 3673b8fee..e71006846 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -96,6 +96,8 @@ rectContainsPoint (Rect *rect, Point *point) } } break; + case qe_none: + break; } return self; } From 4e4b553cc3c2fbc958007758f0c585052e445029 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 16:20:23 +0900 Subject: [PATCH 139/444] [gamecode] Take care of missed type alias stuff --- include/QF/progs.h | 1 - libs/gamecode/pr_debug.c | 19 ------------------- 2 files changed, 20 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 5abd0d1c6..18ea33b04 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1575,7 +1575,6 @@ typedef struct type_view_s { type_view_func enum_view; type_view_func array_view; type_view_func class_view; - type_view_func alias_view; } type_view_t; void PR_Debug_Init (progs_t *pr); diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index e7bf90a92..28bb97e54 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -132,8 +132,6 @@ static void pr_debug_array_view (qfot_type_t *type, pr_type_t *value, void *_data); static void pr_debug_class_view (qfot_type_t *type, pr_type_t *value, void *_data); -static void pr_debug_alias_view (qfot_type_t *type, pr_type_t *value, - void *_data); static type_view_t raw_type_view = { pr_debug_void_view, @@ -154,7 +152,6 @@ static type_view_t raw_type_view = { pr_debug_enum_view, pr_debug_array_view, pr_debug_class_view, - pr_debug_alias_view, }; static const char * @@ -226,9 +223,6 @@ pr_debug_type_size (const progs_t *pr, const qfot_type_t *type) return type->t.array.size * size; case ty_class: return 1; //FIXME or should it return sizeof class struct? - case ty_alias: - aux_type = &G_STRUCT (pr, qfot_type_t, type->t.alias.aux_type); - return pr_debug_type_size (pr, aux_type); } return 0; } @@ -860,9 +854,6 @@ value_string (pr_debug_data_t *data, qfot_type_t *type, pr_type_t *value) case ty_class: raw_type_view.class_view (type, value, data); break; - case ty_alias: - raw_type_view.alias_view (type, value, data); - break; } return data->dstr->str; } @@ -1171,16 +1162,6 @@ pr_debug_class_view (qfot_type_t *type, pr_type_t *value, void *_data) dstring_appendstr (dstr, ""); } -static void -pr_debug_alias_view (qfot_type_t *type, pr_type_t *value, void *_data) -{ - __auto_type data = (pr_debug_data_t *) _data; - progs_t *pr = data->pr; - - type = &G_STRUCT (pr, qfot_type_t, type->t.alias.aux_type); - value_string (data, type, value); -} - VISIBLE void PR_Debug_Watch (progs_t *pr, const char *expr) { From 277c64a4607b2f5b32b01497f4b2b19a9754e231 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 17:28:33 +0900 Subject: [PATCH 140/444] [qfcc] Correct a typo --- tools/qfcc/source/idstuff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/idstuff.c b/tools/qfcc/source/idstuff.c index 629862003..2f195b7e2 100644 --- a/tools/qfcc/source/idstuff.c +++ b/tools/qfcc/source/idstuff.c @@ -295,7 +295,7 @@ WriteProgdefs (dprograms_t *progs, const char *filename) crc = CRC_Block ((byte *) dstr->str, dstr->size - 1); dasprintf (dstr, "#define PROGHEADER_CRC %u\n", crc); - dstring_insertstr (dstr, 0, "/* Actually, generated by qfcc, be one must " + dstring_insertstr (dstr, 0, "/* Actually, generated by qfcc, but one must " "maintain formalities */"); if (filename) { From b5443216097966c06e39fb5319a4ac5bc6cc7415 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 17:43:28 +0900 Subject: [PATCH 141/444] [qfcc] Catch deferences to incomplete types Reporting an error is so much more helpful than segmentation fault. --- tools/qfcc/source/class.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 841fa53a0..682bf59f5 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -889,6 +889,10 @@ class_find_ivar (class_t *class, int vis, const char *name) { symbol_t *ivar; + if (!class->ivars) { + error (0, "accessing incomplete type %s", class->name); + return 0; + } ivar = symtab_lookup (class->ivars, name); if (ivar) { if (ivar->visibility > (vis_t) vis) From 80d9401eeeb58a620b4ce8344ab2ad24b9803cdb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 17:44:13 +0900 Subject: [PATCH 142/444] [qfcc] Report errors for objects in function decls The number of time's I've forgotten the * in a declaration in objective code (probably thanks to C#'s lack of them). --- tools/qfcc/source/function.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 538bb8f65..3b844b5a3 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -46,6 +46,7 @@ #include "qfcc.h" +#include "class.h" #include "codespace.h" #include "debug.h" #include "def.h" @@ -157,6 +158,11 @@ parse_params (type_t *type, param_t *parms) type_t *new; int count = 0; + if (type && obj_is_class (type)) { + error (0, "cannot return an object (forgot *?)"); + type = &type_id; + } + new = new_type (); new->type = ev_func; new->alignment = 1; @@ -177,6 +183,10 @@ parse_params (type_t *type, param_t *parms) internal_error (0, 0); new->t.func.num_params = -(new->t.func.num_params + 1); } else if (p->type) { + if (obj_is_class (p->type)) { + error (0, "cannot use an object as a parameter (forgot *?)"); + p->type = &type_id; + } new->t.func.param_types[new->t.func.num_params] = p->type; new->t.func.num_params++; } From 92cb3a5285fb75538255c18e2e2dc692e4ecf74b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 18:25:02 +0900 Subject: [PATCH 143/444] [qwaq] Flatten the hierarchy and do some cleanup --- ruamoko/qwaq/Makefile.am | 2 +- ruamoko/qwaq/qwaq-app.h | 6 ++-- ruamoko/qwaq/qwaq-app.r | 18 +++++----- ruamoko/qwaq/qwaq-rect.h | 21 +++++++++++ ruamoko/qwaq/qwaq-screen.h | 22 ++++++++++++ ruamoko/qwaq/qwaq-screen.r | 32 +++++++++++++++++ ruamoko/qwaq/qwaq-view.h | 30 ++-------------- ruamoko/qwaq/qwaq-view.r | 71 +------------------------------------- ruamoko/qwaq/qwaq-window.h | 18 ++++++++-- ruamoko/qwaq/qwaq-window.r | 63 +++++++++++++++++++++++++++++++++ 10 files changed, 172 insertions(+), 111 deletions(-) create mode 100644 ruamoko/qwaq/qwaq-rect.h create mode 100644 ruamoko/qwaq/qwaq-screen.h create mode 100644 ruamoko/qwaq/qwaq-screen.r diff --git a/ruamoko/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am index f38fc77e5..38584d949 100644 --- a/ruamoko/qwaq/Makefile.am +++ b/ruamoko/qwaq/Makefile.am @@ -57,7 +57,7 @@ qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS) r_depfiles_remade= -qwaq_app_dat_SOURCES=qwaq-app.r qwaq-view.r qwaq-window.r +qwaq_app_dat_SOURCES=qwaq-app.r qwaq-screen.r qwaq-window.r qwaq-view.r qwaq_app_obj=$(qwaq_app_dat_SOURCES:.r=.o) qwaq_app_dep=$(addprefix ./$(DEPDIR)/,$(qwaq_app_obj:.o=.Qo)) qwaq-app.dat$(EXEEXT): $(qwaq_app_obj) $(QFCC_DEP) diff --git a/ruamoko/qwaq/qwaq-app.h b/ruamoko/qwaq/qwaq-app.h index c02beac67..b603fb4b1 100644 --- a/ruamoko/qwaq/qwaq-app.h +++ b/ruamoko/qwaq/qwaq-app.h @@ -1,15 +1,15 @@ #ifndef __qwaq_app_h #define __qwaq_app_h -#include "qwaq-view.h" - #include "event.h" +@class Screen; + @interface QwaqApplication: Object { qwaq_event_t event; qwaq_command endState; - View *view; + Screen *screen; } -run; -handleEvent: (qwaq_event_t *) event; diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 80ed06c41..d9051f4d9 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -4,6 +4,8 @@ #include "qwaq-app.h" #include "qwaq-curses.h" #include "qwaq-window.h" +#include "qwaq-screen.h" +#include "qwaq-view.h" static AutoreleasePool *autorelease_pool; static void @@ -33,18 +35,18 @@ arp_end (void) initialize (); init_pair (1, COLOR_WHITE, COLOR_BLUE); init_pair (2, COLOR_WHITE, COLOR_BLACK); - view = [[View viewFromWindow:stdscr] retain]; - [view setBackground: COLOR_PAIR (1)]; - Rect r = view.rect; - wprintf (view.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); + screen = [[Screen screen] retain]; + [screen setBackground: COLOR_PAIR (1)]; + Rect r = screen.rect; + wprintf (screen.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); r.xpos = r.xlen / 4; r.ypos = r.ylen / 4; r.xlen /= 2; r.ylen /= 2; - wprintf (view.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); - wrefresh(view.window); + wprintf (screen.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); + wrefresh(screen.window); Window *w; - [view addView: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; + [screen add: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; wprintf (w.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); return self; } @@ -68,7 +70,7 @@ arp_end (void) -handleEvent: (qwaq_event_t *) event { - [view handleEvent: event]; + [screen handleEvent: event]; if (event.event_type == qe_key && event.e.key == '\x18') { event.event_type = qe_command; event.e.message.command = qc_exit; diff --git a/ruamoko/qwaq/qwaq-rect.h b/ruamoko/qwaq/qwaq-rect.h new file mode 100644 index 000000000..0c26b5817 --- /dev/null +++ b/ruamoko/qwaq/qwaq-rect.h @@ -0,0 +1,21 @@ +#ifndef __qwaq_rect_h +#define __qwaq_rect_h + +typedef struct { + int xpos; + int ypos; + int xlen; + int ylen; +} Rect; + +typedef struct { + int x; + int y; +} Point; + +@extern Rect makeRect (int xpos, int ypos, int xlen, int ylen); +//XXX will not work if point or rect point to a local variabl +@extern int rectContainsPoint (Rect *rect, Point *point); +@extern Rect getwrect (struct window_s *window); + +#endif//__qwaq_rect_h diff --git a/ruamoko/qwaq/qwaq-screen.h b/ruamoko/qwaq/qwaq-screen.h new file mode 100644 index 000000000..365c54506 --- /dev/null +++ b/ruamoko/qwaq/qwaq-screen.h @@ -0,0 +1,22 @@ +#ifndef __qwaq_screen_h +#define __qwaq_screen_h + +#include + +#include "qwaq-rect.h" +@class View; +@class Array; + +@interface Screen: Object +{ + Rect rect; + Array *views; + View *focusedView; + struct window_s *window; +} ++(Screen *) screen; +-add: obj; +-setBackground: (int) ch; +@end + +#endif//__qwaq_screen_h diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r new file mode 100644 index 000000000..cd4e25365 --- /dev/null +++ b/ruamoko/qwaq/qwaq-screen.r @@ -0,0 +1,32 @@ +#include "qwaq-curses.h" +#include "qwaq-screen.h" + +@implementation Screen ++(Screen *) screen +{ + return [[[self alloc] init] autorelease]; +} + +-init +{ + if (!(self = [super init])) { + return nil; + } + window = stdscr; + rect = getwrect (window); + return self; +} + +-add: obj +{ + return self; +} + +-setBackground: (int) ch +{ + wbkgd (window, ch); + wrefresh (window); + return self; +} + +@end diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index 63a9b4db5..811998ed0 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -4,41 +4,17 @@ #include #include -#include "event.h" -#include "qwaq-curses.h" - -typedef struct { - int xpos; - int ypos; - int xlen; - int ylen; -} Rect; - -typedef struct { - int x; - int y; -} Point; - -@extern Rect makeRect (int xpos, int ypos, int xlen, int ylen); -//XXX will not work if point or rect point to a local variabl -@extern int rectContainsPoint (Rect *rect, Point *point); -@extern Rect getwrect (window_t window); +#include "qwaq-rect.h" @interface View: Object { Rect rect; Rect absRect; - Array *views; Point point; // can't be local :( - View *focusedView; - window_t window; - panel_t panel; + struct window_s *window; } -+viewFromWindow: (window_t) window; -initWithRect: (Rect) rect; --handleEvent: (qwaq_event_t *) event; --addView: (View *) view; --setBackground: (int) ch; +-handleEvent: (struct qwaq_event_s *) event; @end #endif//__qwaq_view_h diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index e71006846..c03d880f4 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -17,11 +17,6 @@ rectContainsPoint (Rect *rect, Point *point) @implementation View -+viewFromWindow: (window_t) window -{ - return [[[self alloc] initFromWindow: window] autorelease]; -} - -initWithRect: (Rect) rect { if (!(self = [super init])) { @@ -29,76 +24,12 @@ rectContainsPoint (Rect *rect, Point *point) } self.rect = rect; self.absRect = rect; - self.window = create_window (rect.xpos, rect.ypos, rect.xlen, rect.ylen); - self.panel = create_panel (self.window); - return self; -} - --initFromWindow: (window_t) window -{ - if (!(self = [super init])) { - return nil; - } - rect = getwrect (window); - self.window = window; - self.panel = nil; - return self; -} - --initWithPanel: (panel_t) panel -{ - if (!(self = [super init])) { - return nil; - } - self.panel = panel; - self.window = panel_window (panel); - rect = getwrect (window); - return self; -} - --addView: (View *) view -{ - [views addObject: view]; - return self; -} - --setBackground: (int) ch -{ - wbkgd (window, ch); - if (!panel) { - wrefresh (window); - } + self.window = nil; return self; } -handleEvent: (qwaq_event_t *) event { - switch (event.event_type) { - case qe_mouse: - point.x = event.e.mouse.x; - point.y = event.e.mouse.y; - for (int i = [views count]; i--> 0; ) { - View *v = [views objectAtIndex: i]; - if (rectContainsPoint (&v.absRect, &point)) { - [v handleEvent: event]; - break; - } - } - break; - case qe_key: - case qe_command: - if (focusedView) { - [focusedView handleEvent: event]; - for (int i = [views count]; - event.event_type != qe_none && i--> 0; ) { - View *v = [views objectAtIndex: i]; - [v handleEvent: event]; - } - } - break; - case qe_none: - break; - } return self; } diff --git a/ruamoko/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h index 13730ccca..5d777c828 100644 --- a/ruamoko/qwaq/qwaq-window.h +++ b/ruamoko/qwaq/qwaq-window.h @@ -1,11 +1,25 @@ #ifndef __qwaq_window_h #define __qwaq_window_h -#include "qwaq-view.h" +#include "Object.h" -@interface Window: View +@class View; +@class Array; + +#include "qwaq-rect.h" + +@interface Window: Object { + Rect rect; + Point point; // FIXME can't be local :( + Array *views; + View *focusedView; + struct window_s *window; + struct panel_s *panel; } ++windowWithRect: (Rect) rect; +-addView: (View *) view; +-setBackground: (int) ch; @end #endif//__qwaq_window_h diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 48722cdc2..70fe2c476 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -1,8 +1,71 @@ +#include + +#include "event.h" +#include "qwaq-curses.h" #include "qwaq-window.h" +#include "qwaq-view.h" @implementation Window + +windowWithRect: (Rect) rect { return [[[self alloc] initWithRect: rect] autorelease]; } + +-initWithRect: (Rect) rect +{ + if (!(self = [super init])) { + return nil; + } + self.rect = rect; + window = create_window (rect.xpos, rect.ypos, rect.xlen, rect.ylen); + panel = create_panel (window); + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + switch (event.event_type) { + case qe_mouse: + point.x = event.e.mouse.x; + point.y = event.e.mouse.y; + for (int i = [views count]; i--> 0; ) { + View *v = [views objectAtIndex: i]; + if (rectContainsPoint (&v.absRect, &point)) { + [v handleEvent: event]; + break; + } + } + break; + case qe_key: + case qe_command: + if (focusedView) { + [focusedView handleEvent: event]; + for (int i = [views count]; + event.event_type != qe_none && i--> 0; ) { + View *v = [views objectAtIndex: i]; + [v handleEvent: event]; + } + } + break; + case qe_none: + break; + } + return self; +} + +-addView: (View *) view +{ + [views addObject: view]; + view.absRect.xpos = view.rect.xpos + rect.xpos; + view.absRect.ypos = view.rect.ypos + rect.ypos; + view.window = window; + return self; +} + +-setBackground: (int) ch +{ + wbkgd (window, ch); + return self; +} @end From 254bf29bd4f299d6afe5138e803de768b2a47413 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 1 Mar 2020 19:37:40 +0900 Subject: [PATCH 144/444] [qfcc] Handle protocol forward declarations --- tools/qfcc/source/class.c | 8 +++++-- tools/qfcc/source/qc-parse.y | 41 +++++++++++++++++++++++++++--------- 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 682bf59f5..07068ecb9 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -515,7 +515,11 @@ class_add_protocols (class_t *class, protocollist_t *protocols) for (i = 0; i < protocols->count; i++) { p = protocols->list[i]; - copy_methods (methods, p->methods); + if (p->methods) { + copy_methods (methods, p->methods); + } else { + warning (0, "definition of protocol `%s' not found", p->name); + } if (p->protocols) class_add_protocols (class, p->protocols); } @@ -1356,7 +1360,7 @@ get_protocol (const char *name, int create) p = calloc (sizeof (protocol_t), 1); p->name = name; - p->methods = new_methodlist (); + p->methods = 0; p->class_type.type = ct_protocol; p->class_type.c.protocol = p; if (name) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 1bcd240c1..a7b353082 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -192,7 +192,7 @@ int yylex (void); %type overloaded_identifier %type identifier_list -%type selector reserved_word +%type protocol_name_list selector reserved_word %type optional_param_list unaryselector keyworddecl %type keywordselector %type methodproto methoddecl @@ -1443,6 +1443,7 @@ identifier obj_def : classdef { } | classdecl + | protocoldecl | protocoldef | { if (!current_class) PARSE_ERROR; } methoddef | END @@ -1570,17 +1571,18 @@ category_reference } ; - protocol_name : identifier { $$ = get_protocol ($1->name, 0); - if ($$) { - error (0, "redefinition of %s", $1->name); + if ($$ && $$->methods) { + error (0, "redefinition of protocol %s", $1->name); $$ = get_protocol (0, 1); - } else { + } + if (!$$) { $$ = get_protocol ($1->name, 1); } + $$->methods = new_methodlist (); current_class = &$$->class_type; } ; @@ -1673,18 +1675,33 @@ classdef | REFERENCE category_reference ';' { } ; +protocoldecl + : protocol + protocol_name_list ';' + { + while ($2) { + get_protocol ($2->name, 1); + $2 = $2->next; + } + } + ; + protocoldef - : PROTOCOL { $$ = current_class; } + : protocol protocol_name - protocolrefs { protocol_add_protocols ($3, $4); $$ = 0; } - methodprotolist { protocol_add_methods ($3, $6); } + protocolrefs { protocol_add_protocols ($2, $3); $$ = 0; } + methodprotolist { protocol_add_methods ($2, $5); } END { - current_class = $2; - (void) ($5); + current_class = $1; + (void) ($4); } ; +protocol + : PROTOCOL { $$ = current_class; } + ; + protocolrefs : /* emtpy */ { $$ = 0; } | LT { $$ = new_protocol_list (); } @@ -1870,6 +1887,10 @@ keywordselector | keywordselector keyworddecl { $2->next = $1; $$ = $2; } ; +protocol_name_list + : identifier + | protocol_name_list ',' identifier { $3->next = $1; $$ = $3; } + selector : NAME { $$ = $1; } | CLASS_NAME { $$ = $1; } From 544d7de1ec5e2b1c2b229a43a0feff34dd9d198a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 10:42:26 +0900 Subject: [PATCH 145/444] [qfcc] Implement @protocol(foo) Unlike gcc, qfcc requires foo to be defined, not just declared (I suspect this is a bug in gcc, or even the ObjC spec), because allowing forward declarations causes an empty (no methods) protocol to be emitted, and then when the protocol is actually defined, one with methods, resulting in two different versions of the same protocol, which comments in the gnu objc runtime specifically state is a problem but is not checked because it "never happens in practice" (found while investigating gcc's behavior with @protocol and just what some of the comments about static instance lists meant). --- tools/qfcc/include/class.h | 1 + tools/qfcc/source/class.c | 6 ++++-- tools/qfcc/source/expr.c | 11 +++++++++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index 323912591..a4f65538b 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -74,6 +74,7 @@ typedef struct protocol_s { const char *name; struct methodlist_s *methods; struct protocollist_s *protocols; + struct def_s *def; class_type_t class_type; } protocol_t; diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 07068ecb9..64ebf692f 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -1387,8 +1387,10 @@ protocol_add_protocols (protocol_t *protocol, protocollist_t *protocols) def_t * protocol_def (protocol_t *protocol) { - return make_symbol (protocol->name, &type_obj_protocol, - pr.far_data, sc_static)->s.def; + if (!protocol->def) { + protocol->def = emit_protocol (protocol); + } + return protocol->def; } protocollist_t * diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index ad91a8d81..967484f95 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2470,9 +2470,16 @@ selector_expr (keywordarg_t *selector) } expr_t * -protocol_expr (const char *protocol) +protocol_expr (const char *protocol_name) { - return error (0, "not implemented"); + protocol_t *protocol = get_protocol (protocol_name, 0); + + if (!protocol) { + return error (0, "cannot find protocol declaration for `%s'", + protocol_name); + } + class_t *proto_class = get_class (new_symbol ("Protocol"), 1); + return new_pointer_expr (0, proto_class->type, protocol_def (protocol)); } expr_t * From b6b7f9675f77fcab401be1f32d2fc1c35109f26d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 10:48:51 +0900 Subject: [PATCH 146/444] [qfcc] Emit static instance lists For now, only protocols are in the list (gcc adds only static string objects and qfcc doesn't do those yet, so not so far behind). qfprogs dumps them. --- tools/qfcc/include/class.h | 5 + tools/qfcc/source/class.c | 164 +++++++++++++++++++++++++++++-- tools/qfcc/source/dump_modules.c | 54 +++++++++- tools/qfcc/source/dump_strings.c | 4 +- 4 files changed, 216 insertions(+), 11 deletions(-) diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index a4f65538b..726a272be 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -83,6 +83,11 @@ typedef struct protocollist_s { protocol_t **list; } protocollist_t; +typedef struct static_instance_s { + const char *class; + struct def_s *instance; +} static_instance_t; + extern struct type_s type_id; extern struct type_s type_obj_object; extern struct type_s type_obj_class; diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 64ebf692f..0b981d065 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -66,6 +66,8 @@ static hashtab_t *class_hash; static hashtab_t *category_hash; static hashtab_t *protocol_hash; +static hashtab_t *static_instances; +static hashtab_t *static_instance_classes; // these will be built up further type_t type_obj_selector = { ev_invalid, 0, 0, ty_struct}; @@ -178,6 +180,141 @@ static struct_def_t object_struct[] = { {0, 0} }; +static const char * +static_instance_get_key (const void *instance, void *unused) +{ + return ((static_instance_t *) instance)->class; +} + +static void +add_static_instance (const char *class, def_t *instance_def) +{ + static_instance_t *instance = malloc (sizeof (*instance)); + + if (!static_instances) { + static_instances = Hash_NewTable (1021, static_instance_get_key, 0, 0); + static_instance_classes = Hash_NewTable (1021, static_instance_get_key, + 0, 0); + } + + instance->class = save_string (class); + instance->instance = instance_def; + Hash_Add (static_instances, instance); + + // uniqued set of class names for all static instances + if (!Hash_Find (static_instance_classes, class)) { + Hash_Add (static_instance_classes, instance); + } +} +typedef struct { + const char *class_name; + int num_instances; + static_instance_t **instances; +} obj_static_instances_data_t; + +static void +emit_instance_classname (def_t *def, void *data, int index) +{ + obj_static_instances_data_t *da = (obj_static_instances_data_t *)data; + + if (def->type != &type_string) + internal_error (0, "%s: expected string def", __FUNCTION__); + EMIT_STRING (def->space, D_STRING (def), da->class_name); +} + +static void +emit_instance_defs (def_t *def, void *data, int index) +{ + obj_static_instances_data_t *da = (obj_static_instances_data_t *)data; + + if (!is_array (def->type) || def->type->t.array.type->type != ev_pointer) + internal_error (0, "%s: expected array of pointers def", __FUNCTION__); + if (index < 0 || index >= da->num_instances + 1) + internal_error (0, "%s: out of bounds index: %d %d", + __FUNCTION__, index, da->num_instances + 1); + D_INT (def) = 0; + if (index < da->num_instances) { + EMIT_DEF (def->space, D_INT (def), da->instances[index]->instance); + } +} + +static def_t * +emit_static_instances (const char *classname) +{ + static struct_def_t instances_struct[] = { + {"class_name", &type_string, emit_instance_classname}, + {"instances", 0, emit_instance_defs}, + {0, 0} + }; + obj_static_instances_data_t data = {}; + def_t *instances_def; + + data.class_name = classname; + data.instances = (static_instance_t **) Hash_FindList (static_instances, + classname); + for (static_instance_t **inst = data.instances; *inst; inst++) { + data.num_instances++; + } + instances_struct[1].type = array_type (&type_pointer, + data.num_instances + 1); + instances_def = emit_structure (va ("_OBJ_STATIC_INSTANCES_%s", classname), + 's', instances_struct, 0, &data, + sc_static); + free (data.instances); + return instances_def; +} + +static def_t * +emit_static_instances_list (void) +{ + static_instance_t **classes; + int num_classes = 0; + def_t **instance_lists; + type_t *instance_lists_type; + symbol_t *instance_lists_sym; + def_t *instance_lists_def; + pointer_t *list; + defspace_t *space; + + if (!static_instance_classes || !static_instances) { + return 0; + } + + classes = (static_instance_t **) Hash_GetList (static_instance_classes); + for (static_instance_t **c = classes; *c; c++) { + num_classes++; + } + if (!num_classes) { + free (classes); + return 0; + } + instance_lists = alloca (num_classes * sizeof (*instance_lists)); + for (int i = 0; i < num_classes; i++) { + instance_lists[i] = emit_static_instances (classes[i]->class); + } + free (classes); + + // +1 for terminating null + instance_lists_type = array_type (&type_pointer, num_classes + 1); + instance_lists_sym = make_symbol ("_OBJ_STATIC_INSTANCES", + instance_lists_type, + pr.far_data, sc_static); + if (!instance_lists_sym->table) { + symtab_addsymbol (pr.symtab, instance_lists_sym); + } + instance_lists_def = instance_lists_sym->s.def; + instance_lists_def->initialized = instance_lists_def->constant = 1; + instance_lists_def->nosave = 1; + + list = D_POINTER (pointer_t, instance_lists_def); + space = instance_lists_def->space; + for (int i = 0; i < num_classes; i++, list++) { + EMIT_DEF (space, *list, instance_lists[i]); + } + *list = 0; + return instance_lists_def; +} + int obj_is_id (const type_t *type) { @@ -1185,6 +1322,7 @@ typedef struct { int cls_def_cnt; category_t **categories; int cat_def_cnt; + def_t *instances_list; } obj_symtab_data_t; static void @@ -1238,10 +1376,10 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!is_array (def->type) || def->type->t.array.type->type != ev_pointer) internal_error (0, "%s: expected array of pointers def", __FUNCTION__); - if (index < 0 || index >= da->cls_def_cnt + da->cat_def_cnt) + if (index < 0 || index >= da->cls_def_cnt + da->cat_def_cnt + 1) internal_error (0, "%s: out of bounds index: %d %d", __FUNCTION__, index, - da->cls_def_cnt + da->cat_def_cnt); + da->cls_def_cnt + da->cat_def_cnt + 1); if (index < da->cls_def_cnt) { class_t **cl; @@ -1250,7 +1388,7 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!index--) break; EMIT_DEF (def->space, D_INT (def), (*cl)->def); - } else { + } else if (index < da->cls_def_cnt + da->cat_def_cnt) { category_t **ca; index -= da->cls_def_cnt; for (ca = da->categories; *ca; ca++) @@ -1258,6 +1396,11 @@ emit_symtab_defs (def_t *def, void *data, int index) if (!index--) break; EMIT_DEF (def->space, D_INT (def), (*ca)->def); + } else { + D_INT (def) = 0; + if (da->instances_list) { + EMIT_DEF (def->space, D_INT (def), da->instances_list); + } } } @@ -1273,7 +1416,7 @@ class_finish_module (void) {0, 0} }; - obj_symtab_data_t data = {0, 0, 0, 0, 0}; + obj_symtab_data_t data = {}; class_t **cl; category_t **ca; @@ -1299,10 +1442,14 @@ class_finish_module (void) if ((*ca)->def && !(*ca)->def->external) data.cat_def_cnt++; } - if (!data.refs && !data.cls_def_cnt && !data.cat_def_cnt) + data.instances_list = emit_static_instances_list (); + if (!data.refs && !data.cls_def_cnt && !data.cat_def_cnt + && !data.instances_list) return; symtab_struct[4].type = array_type (&type_pointer, - data.cls_def_cnt + data.cat_def_cnt); + data.cls_def_cnt + + data.cat_def_cnt + + 1); symtab_def = emit_structure ("_OBJ_SYMTAB", 's', symtab_struct, 0, &data, sc_static); free (data.classes); @@ -1389,6 +1536,7 @@ protocol_def (protocol_t *protocol) { if (!protocol->def) { protocol->def = emit_protocol (protocol); + add_static_instance ("Protocol", protocol->def); } return protocol->def; } @@ -1548,6 +1696,10 @@ clear_classes (void) Hash_FlushTable (protocol_hash); if (category_hash) Hash_FlushTable (category_hash); + if (static_instances) + Hash_FlushTable (static_instances); + if (static_instance_classes) + Hash_FlushTable (static_instance_classes); obj_initialized = 0; } diff --git a/tools/qfcc/source/dump_modules.c b/tools/qfcc/source/dump_modules.c index 6bb559003..68cee44eb 100644 --- a/tools/qfcc/source/dump_modules.c +++ b/tools/qfcc/source/dump_modules.c @@ -89,22 +89,41 @@ dump_selector (progs_t *pr, pr_sel_t *sel) printf (" %s\n", sel_types); } +static void +dump_method_description_list (progs_t *pr, char c, + pr_method_description_list_t *list) +{ + if (list) { + for (int i = 0; i < list->count; i++) { + printf ("%*s%s\n", 20, "", PR_GetString (pr, list->list[i].name)); + printf ("%*s%s\n", 20, "", PR_GetString (pr, list->list[i].types)); + } + } +} + static void dump_protocol (progs_t *pr, pr_protocol_t *proto) { const char *protocol_name = ""; - printf (" %d ", proto->class_pointer); + printf (" %x %x ", + (pointer_t) ((pr_int_t *) proto - (pr_int_t *) pr->pr_globals), + proto->class_pointer); if (PR_StringValid (pr, proto->protocol_name)) protocol_name = PR_GetString (pr, proto->protocol_name); printf ("<%s>\n", protocol_name); + dump_method_description_list (pr, '-', + &G_STRUCT (pr, pr_method_description_list_t, + proto->instance_methods)); + dump_method_description_list (pr, '-', + &G_STRUCT (pr, pr_method_description_list_t, + proto->class_methods)); } static void dump_protocol_list (progs_t *pr, pr_protocol_list_t *list) { int i; - printf (" %d\n", list->next); - printf (" %d\n", list->count); + printf (" %x %d\n", list->next, list->count); for (i = 0; i < list->count; i++) { if (list->list[i] <= 0 || list->list[i] >= pr->globals_size) { printf ("invalid pointer\n"); @@ -171,6 +190,32 @@ dump_category (progs_t *pr, pr_category_t *category) category->protocols)); } +static void +dump_static_instance_lists (progs_t *pr, pointer_t instance_lists) +{ + pointer_t *ptr = &G_STRUCT (pr, pointer_t, instance_lists); + + printf (" static instance lists @ %x\n", instance_lists); + while (*ptr) { + __auto_type list = &G_STRUCT (pr, pr_static_instances_t, *ptr); + const char *class_name = "*** INVALID ***"; + + if (PR_StringValid (pr, list->class_name)) { + class_name = PR_GetString (pr, list->class_name); + } + printf (" %x %s\n", *ptr, class_name); + for (int i = 0; list->instances[i]; i++) { + if (!strcmp (class_name, "Protocol")) { + dump_protocol (pr, &G_STRUCT (pr, pr_protocol_t, + list->instances[i])); + } else { + printf (" %x\n", list->instances[i]); + } + } + ptr++; + } +} + static void dump_module (progs_t *pr, pr_module_t *module) { @@ -197,6 +242,9 @@ dump_module (progs_t *pr, pr_module_t *module) dump_class (pr, &G_STRUCT (pr, pr_class_t, *ptr++)); for (i = 0; i < symtab->cat_def_cnt; i++) dump_category (pr, &G_STRUCT (pr, pr_category_t, *ptr++)); + if (*ptr) { + dump_static_instance_lists (pr, *ptr); + } } void diff --git a/tools/qfcc/source/dump_strings.c b/tools/qfcc/source/dump_strings.c index fc0c0cb7d..77f3c0ae4 100644 --- a/tools/qfcc/source/dump_strings.c +++ b/tools/qfcc/source/dump_strings.c @@ -44,14 +44,14 @@ dump_string_block (const char *strblock, unsigned size) { const char *s = strblock; - printf ("%d ", 0); + printf ("%x ", 0); while (s - strblock < size) { char c = *s++; switch (c) { case 0: fputs ("\n", stdout); if (s - strblock < size) - printf ("%ld ", s - strblock); + printf ("%lx ", s - strblock); break; case 9: fputs ("\\t", stdout); From 8021613b79daa56e908c34ff3d44da2e55f390c5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 10:52:09 +0900 Subject: [PATCH 147/444] [qfcc] Fix missing protocol method lists The problem was an erroneous assumption that the methods had to be defined. Any class implementing a protocol must implement (and thus define) the methods, but a protocol declaration cannot: it merely declares the methods, and it's entirely possible for a module to see only the protocol definition and not any classes implementing the protocol. --- tools/qfcc/source/method.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 726acfd76..2ae50f39d 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -511,9 +511,11 @@ emit_method_list_item (def_t *def, void *data, int index) method_t *m; pr_method_description_t *desc; - if (def->type != &type_obj_method_description) - internal_error (0, "%s: expected method_description def", + if (!is_array (def->type) + || def->type->t.array.type != &type_obj_method_description) { + internal_error (0, "%s: expected array of method_description def", __FUNCTION__); + } if (index < 0 || index >= methods->count) internal_error (0, "%s: out of bounds index: %d %d", __FUNCTION__, index, methods->count); @@ -521,7 +523,7 @@ emit_method_list_item (def_t *def, void *data, int index) desc = D_POINTER (pr_method_description_t, def); for (m = methods->head; m; m = m->next) { - if (!m->instance != !methods->instance || !m->def) + if (!m->instance != !methods->instance) continue; if (!index--) break; @@ -547,7 +549,7 @@ emit_method_descriptions (methodlist_t *methods, const char *name, return 0; for (count = 0, m = methods->head; m; m = m->next) - if (!m->instance == !instance && m->def) + if (!m->instance == !instance) count++; if (!count) return 0; From 9ccff74fcf5dac1abdcffa6c8b9bfbc7cd7094df Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 10:55:46 +0900 Subject: [PATCH 148/444] [qfcc] Emit only one instance per protocol per module This is actually a double issue: when a class implementing a protocol used the protocol in @protocol(), not only would the protocol get emitted as part of the class data specifying that the class conforms to the protocol, a second instance would be emitted again when @protocol() was used. On top of that, only the instance referenced by @protocol() would be initialized. Now, both class emission and @protocol() get their protocol def from the same place and thus only one, properly initialized, protocol instance is emitted. --- tools/qfcc/source/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 0b981d065..381b37e1e 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -1667,7 +1667,7 @@ emit_protocol_list_item (def_t *def, void *data, int index) internal_error (0, "%s: out of bounds index: %d %d", __FUNCTION__, index, protocols->count); } - EMIT_DEF (def->space, D_INT(def), emit_protocol (protocol)); + EMIT_DEF (def->space, D_INT(def), protocol_def (protocol)); } def_t * From bc4bea79cb9af733a908915a77c428095099ed3a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 13:00:33 +0900 Subject: [PATCH 149/444] [ruamoko] Remove a stale FIXME This was fixed when pr_def_t was introduced. I missed the comment at the time. --- libs/ruamoko/rua_obj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 93fe8a68b..2d30874dd 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1625,7 +1625,7 @@ rua_PR_FindGlobal (progs_t *pr) R_POINTER (pr) = 0; def = PR_FindGlobal (pr, name); if (def) - R_POINTER (pr) = def->ofs; //FIXME def's can't access > 32k + R_POINTER (pr) = def->ofs; } //==================================================================== From 78f552aa87570ba7e9d8742198d2efc71bb50fe6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 13:02:29 +0900 Subject: [PATCH 150/444] [ruamoko] Initialize static instances This is one step closer to implementing conformsToProtocol. However, protocols are not yet initialized correctly: they are not registered, nor are their selectors. While the static initializer list pointer was not written previously, the module struct always came immediately after the symbols struct, and the module version has so far always been 0. Thus, the list pointer is correctly 0 for older progs and there's no need for a version bump. --- libs/ruamoko/rua_obj.c | 90 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 80 insertions(+), 10 deletions(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 2d30874dd..3aa345bfa 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -72,6 +72,7 @@ typedef struct probj_resources_s { hashtab_t *load_methods; obj_list *unresolved_classes; obj_list *unclaimed_categories; + obj_list *uninitialized_statics; obj_list *unclaimed_proto_list; obj_list *module_list; obj_list *class_tree_list; @@ -516,6 +517,24 @@ obj_register_selectors_from_class (probj_t *probj, pr_class_t *class) } } +static void obj_init_protocols (probj_t *probj, pr_protocol_list_t *protos); + +static void +obj_init_protocol (probj_t *probj, pr_class_t *proto_class, + pr_protocol_t *proto) +{ + progs_t *pr = probj->pr; + + if (!proto->class_pointer) { + proto->class_pointer = PR_SetPointer (pr, proto_class); + obj_init_protocols (probj, &G_STRUCT (pr, pr_protocol_list_t, + proto->protocol_list)); + } else { + if (proto->class_pointer != PR_SetPointer (pr, proto_class)) + PR_RunError (pr, "protocol broken"); + } +} + static void obj_init_protocols (probj_t *probj, pr_protocol_list_t *protos) { @@ -535,14 +554,7 @@ obj_init_protocols (probj_t *probj, pr_protocol_list_t *protos) for (i = 0; i < protos->count; i++) { proto = &G_STRUCT (pr, pr_protocol_t, protos->list[i]); - if (!proto->class_pointer) { - proto->class_pointer = PR_SetPointer (pr, proto_class); - obj_init_protocols (probj, &G_STRUCT (pr, pr_protocol_list_t, - proto->protocol_list)); - } else { - if (proto->class_pointer != PR_SetPointer (pr, proto_class)) - PR_RunError (pr, "protocol broken"); - } + obj_init_protocol (probj, proto_class, proto); } } @@ -851,6 +863,51 @@ dump_ivars (probj_t *probj, pointer_t _ivars) } } +static void +obj_init_statics (probj_t *probj) +{ + progs_t *pr = probj->pr; + obj_list **cell = &probj->uninitialized_statics; + pointer_t *ptr; + pointer_t *inst; + + Sys_MaskPrintf (SYS_RUA_OBJ, "Initializing statics\n"); + while (*cell) { + int initialized = 1; + + for (ptr = (*cell)->data; *ptr; ptr++) { + __auto_type statics = &G_STRUCT (pr, pr_static_instances_t, *ptr); + const char *class_name = PR_GetString (pr, statics->class_name); + pr_class_t *class = Hash_Find (probj->classes, class_name); + + Sys_MaskPrintf (SYS_RUA_OBJ, " %s %p\n", class_name, class); + if (!class) { + initialized = 0; + continue; + } + + if (strcmp (class_name, "Protocol") == 0) { + // protocols are special + for (inst = statics->instances; *inst; inst++) { + obj_init_protocol (probj, class, + &G_STRUCT (pr, pr_protocol_t, *inst)); + } + } else { + for (inst = statics->instances; *inst; inst++) { + pr_id_t *id = &G_STRUCT (pr, pr_id_t, *inst); + id->class_pointer = PR_SetPointer (pr, class); + } + } + } + + if (initialized) { + list_remove (cell); + } else { + cell = &(*cell)->next; + } + } +} + static void rua___obj_exec_class (progs_t *pr) { @@ -869,13 +926,16 @@ rua___obj_exec_class (progs_t *pr) return; Sys_MaskPrintf (SYS_RUA_OBJ, "Initializing %s module\n" "symtab @ %x : %d selector%s @ %x, " - "%d class%s and %d categor%s\n", + "%d class%s and %d categor%s\n" + "static instance lists: %s\n", PR_GetString (pr, module->name), module->symtab, symtab->sel_ref_cnt, symtab->sel_ref_cnt == 1 ? "" : "s", symtab->refs, symtab->cls_def_cnt, symtab->cls_def_cnt == 1 ? "" : "es", symtab->cat_def_cnt, - symtab->cat_def_cnt == 1 ? "y" : "ies"); + symtab->cat_def_cnt == 1 ? "y" : "ies", + symtab->defs[symtab->cls_def_cnt + + symtab->cat_def_cnt] ? "yes" : "no"); probj->module_list = list_cons (module, probj->module_list); @@ -958,6 +1018,16 @@ rua___obj_exec_class (progs_t *pr) } } + if (*ptr) { + Sys_MaskPrintf (SYS_RUA_OBJ, "Static instances lists: %x\n", *ptr); + probj->uninitialized_statics + = list_cons (&G_STRUCT (pr, pointer_t, *ptr), + probj->uninitialized_statics); + } + if (probj->uninitialized_statics) { + obj_init_statics (probj); + } + for (cell = &probj->unclaimed_categories; *cell; ) { pr_category_t *category = (*cell)->data; const char *class_name = PR_GetString (pr, category->class_name); From 0db617719e39faa16381d2c5cfa95d3d6850375c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 13:31:26 +0900 Subject: [PATCH 151/444] [qfcc] Improve error messages for bad qc builtins While global quakec functions could not be initialized to another function, the error messages were rather obscure. --- tools/qfcc/source/qc-parse.y | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index a7b353082..8d939185b 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1014,11 +1014,20 @@ non_code_func } | '=' expr { - symbol_t *sym = $0; - specifier_t spec = $-1; - initialize_def (sym, $2, current_symtab->space, spec.storage); - if (sym->s.def) - sym->s.def->nosave |= spec.nosave; + if (local_expr) { + symbol_t *sym = $0; + specifier_t spec = $-1; + initialize_def (sym, $2, current_symtab->space, spec.storage); + if (sym->s.def) + sym->s.def->nosave |= spec.nosave; + } else { + if (is_integer_val ($2) || is_float_val ($2)) { + error (0, "invalid function initializer." + " did you forget #?"); + } else { + error (0, "cannot create global function variables"); + } + } } | /* emtpy */ { From 5893bd750135a95222ae34f004da7c9bc27af31b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 13:32:58 +0900 Subject: [PATCH 152/444] [qfcc] Catch erroneous negative builtin numbers Setting a builtin number negative makes it a non-builtin function, but possibly in the middle of another function. Not good. --- tools/qfcc/source/function.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 3b844b5a3..e2b87d04a 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -656,6 +656,10 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val, int far) bi = expr_integer (bi_val); else bi = expr_float (bi_val); + if (bi < 0) { + error (bi_val, "builtin functions must be positive or 0"); + return 0; + } sym->s.func->builtin = bi; reloc_def_func (sym->s.func, sym->s.func->def); build_function (sym); From a906efac47d804798870a1d1eb839c7db6433483 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 15:20:34 +0900 Subject: [PATCH 153/444] [ruamoko] Register protocols and their selectors --- libs/ruamoko/rua_obj.c | 47 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 3aa345bfa..028850561 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -69,6 +69,7 @@ typedef struct probj_resources_s { string_t *selector_names; hashtab_t *selector_hash; hashtab_t *classes; + hashtab_t *protocols; hashtab_t *load_methods; obj_list *unresolved_classes; obj_list *unclaimed_categories; @@ -324,6 +325,13 @@ class_get_key (const void *c, void *_probj) return PR_GetString (probj->pr, ((pr_class_t *)c)->name); } +static const char * +protocol_get_key (const void *p, void *_probj) +{ + __auto_type probj = (probj_t *) _probj; + return PR_GetString (probj->pr, ((pr_protocol_t *)p)->protocol_name); +} + static uintptr_t load_methods_get_hash (const void *m, void *_probj) { @@ -490,7 +498,27 @@ sel_register_name (probj_t *probj, const char *name) } static void -register_selectors_from_list (probj_t *probj, pr_method_list_t *method_list) +obj_register_selectors_from_description_list (probj_t *probj, + pr_method_description_list_t *method_list) +{ + progs_t *pr = probj->pr; + int i; + + if (!method_list) { + return; + } + for (i = 0; i < method_list->count; i++) { + pr_method_description_t *method = &method_list->list[i]; + const char *name = PR_GetString (pr, method->name); + const char *types = PR_GetString (pr, method->types); + pr_sel_t *sel = sel_register_typed_name (probj, name, types, 0); + method->name = PR_SetPointer (pr, sel); + } +} + +static void +obj_register_selectors_from_list (probj_t *probj, + pr_method_list_t *method_list) { progs_t *pr = probj->pr; int i; @@ -511,7 +539,7 @@ obj_register_selectors_from_class (probj_t *probj, pr_class_t *class) pr_method_list_t *method_list = &G_STRUCT (pr, pr_method_list_t, class->methods); while (method_list) { - register_selectors_from_list (probj, method_list); + obj_register_selectors_from_list (probj, method_list); method_list = &G_STRUCT (pr, pr_method_list_t, method_list->method_next); } @@ -526,7 +554,17 @@ obj_init_protocol (probj_t *probj, pr_class_t *proto_class, progs_t *pr = probj->pr; if (!proto->class_pointer) { + const char *protocol_name = PR_GetString (pr, proto->protocol_name); proto->class_pointer = PR_SetPointer (pr, proto_class); + obj_register_selectors_from_description_list (probj, + &G_STRUCT (pr, pr_method_description_list_t, + proto->instance_methods)); + obj_register_selectors_from_description_list (probj, + &G_STRUCT (pr, pr_method_description_list_t, + proto->class_methods)); + if (!Hash_Find (probj->protocols, protocol_name)) { + Hash_Add (probj->protocols, proto); + } obj_init_protocols (probj, &G_STRUCT (pr, pr_protocol_list_t, proto->protocol_list)); } else { @@ -1816,6 +1854,11 @@ rua_obj_init_runtime (progs_t *pr) else Hash_FlushTable (probj->classes); + if (!probj->protocols) + probj->protocols = Hash_NewTable (1021, protocol_get_key, 0, probj); + else + Hash_FlushTable (probj->protocols); + if (!probj->load_methods) { probj->load_methods = Hash_NewTable (1021, 0, 0, probj); Hash_SetHashCompare (probj->load_methods, load_methods_get_hash, From 0e40366c7fe3a34f8f20ce52c051254721c8cc6b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 15:21:10 +0900 Subject: [PATCH 154/444] [ruamoko] Implement class conformsToProtocol Seems to work nicely, too :) --- libs/ruamoko/rua_obj.c | 85 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 6 deletions(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 028850561..e088ff140 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1713,15 +1713,88 @@ rua__i_Object_error_error_ (progs_t *pr) obj_verror (probj, self, 0, dstr->str, count, args); } +static int +obj_protocol_conformsToProtocol (probj_t *probj, pr_protocol_t *proto, + pr_protocol_t *protocol) +{ + progs_t *pr = probj->pr; + + pr_protocol_list_t *proto_list; + + if (!proto || !protocol) { + return 0; + } + if (proto == protocol) { + return 1; + } + if (proto->protocol_name == protocol->protocol_name + || strcmp (PR_GetString (pr, proto->protocol_name), + PR_GetString (pr, protocol->protocol_name)) == 0) { + return 1; + } + proto_list = &G_STRUCT (pr, pr_protocol_list_t, proto->protocol_list); + while (proto_list) { + Sys_MaskPrintf (SYS_RUA_OBJ, "%x %x %d\n", + PR_SetPointer (pr, proto_list), proto_list->next, + proto_list->count); + for (int i = 0; i < proto_list->count; i++) { + proto = &G_STRUCT (pr, pr_protocol_t, proto_list->list[i]); + if (proto == protocol + || obj_protocol_conformsToProtocol (probj, proto, protocol)) { + return 1; + } + } + + proto_list = &G_STRUCT (pr, pr_protocol_list_t, proto_list->next); + } + return 0; +} + static void rua__c_Object__conformsToProtocol_ (progs_t *pr) { - //probj_t *probj = pr->pr_objective_resources; - //pr_id_t *object = &P_STRUCT (pr, pr_id_t, 0); - //pr_protocol_t *proto = &P_STRUCT (pr, pr_protocol_t, 2); - //... - //XXX - PR_RunError (pr, "%s, not implemented", __FUNCTION__); + probj_t *probj = pr->pr_objective_resources; + // class points to _OBJ_CLASS_foo, and class->class_pointer points to + // _OBJ_METACLASS_foo + pr_class_t *class = &P_STRUCT (pr, pr_class_t, 0); + // protocol->class_pointer must point to _OBJ_CLASS_Protocol (ie, if + // protocol is not actually a protocol, then the class cannot conform + // to it) + pr_protocol_t *protocol = &P_STRUCT (pr, pr_protocol_t, 2); + pr_protocol_list_t *proto_list; + + if (!class || !protocol) { + goto not_conforms; + } + if (protocol->class_pointer != PR_SetPointer (pr, + Hash_Find (probj->classes, + "Protocol"))) { + goto not_conforms; + } + proto_list = &G_STRUCT (pr, pr_protocol_list_t, class->protocols); + while (proto_list) { + Sys_MaskPrintf (SYS_RUA_OBJ, "%x %x %d\n", + PR_SetPointer (pr, proto_list), proto_list->next, + proto_list->count); + for (int i = 0; i < proto_list->count; i++) { + __auto_type proto = &G_STRUCT (pr, pr_protocol_t, + proto_list->list[i]); + if (proto == protocol + || obj_protocol_conformsToProtocol (probj, proto, protocol)) { + goto conforms; + } + } + + proto_list = &G_STRUCT (pr, pr_protocol_list_t, proto_list->next); + } +not_conforms: + Sys_MaskPrintf (SYS_RUA_OBJ, "does not conform\n"); + R_INT (pr) = 0; + return; +conforms: + Sys_MaskPrintf (SYS_RUA_OBJ, "conforms\n"); + R_INT (pr) = 1; + return; } static void From d88a091fc658500d16fd88219e2102067ac376f1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 15:22:54 +0900 Subject: [PATCH 155/444] [qwaq] Use protocols to distinguish object abilities Well, that took a fair bit more than it should have to get working: had to implement the protocol support in qfcc and engine-side ruamoko. --- ruamoko/qwaq/event.h | 12 ++++++++++++ ruamoko/qwaq/main.c | 3 +++ ruamoko/qwaq/qwaq-draw.h | 8 ++++++++ ruamoko/qwaq/qwaq-screen.h | 4 +++- ruamoko/qwaq/qwaq-screen.r | 16 ++++++++++++++++ ruamoko/qwaq/qwaq-view.h | 4 ++-- ruamoko/qwaq/qwaq-view.r | 2 +- ruamoko/qwaq/qwaq-window.h | 3 ++- ruamoko/qwaq/qwaq-window.r | 15 +++++++++++++++ 9 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 ruamoko/qwaq/qwaq-draw.h diff --git a/ruamoko/qwaq/event.h b/ruamoko/qwaq/event.h index 006d37c42..f494234a9 100644 --- a/ruamoko/qwaq/event.h +++ b/ruamoko/qwaq/event.h @@ -32,4 +32,16 @@ typedef struct qwaq_event_s { } e; } qwaq_event_t; +#ifdef __QFCC__ // don't want C gcc to see this :) +@protocol HandleEvent +-handleEvent: (struct qwaq_event_s *) event; +@end + +@protocol TakeFocus +-takeFocus; +-loseFocus; +@end + +#endif + #endif//__qwaq_event_h diff --git a/ruamoko/qwaq/main.c b/ruamoko/qwaq/main.c index 3f88a428a..191714c74 100644 --- a/ruamoko/qwaq/main.c +++ b/ruamoko/qwaq/main.c @@ -166,6 +166,9 @@ main (int argc, const char **argv) Sys_Error ("couldn't load %s", name); } + //pr.pr_trace = 1; + //pr.pr_trace_depth = -1; + PR_PushFrame (&pr); if (argc > 2) pr_argc = argc - 1; diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h new file mode 100644 index 000000000..4abac3e55 --- /dev/null +++ b/ruamoko/qwaq/qwaq-draw.h @@ -0,0 +1,8 @@ +#ifndef __qwaq_draw_h +#define __qwaq_draw_h + +@protocol Draw +-draw; +@end + +#endif diff --git a/ruamoko/qwaq/qwaq-screen.h b/ruamoko/qwaq/qwaq-screen.h index 365c54506..cbd0a6721 100644 --- a/ruamoko/qwaq/qwaq-screen.h +++ b/ruamoko/qwaq/qwaq-screen.h @@ -3,14 +3,16 @@ #include +#include "qwaq-draw.h" #include "qwaq-rect.h" @class View; @class Array; -@interface Screen: Object +@interface Screen: Object { Rect rect; Array *views; + Array *event_handlers; View *focusedView; struct window_s *window; } diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index cd4e25365..e44c25481 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -19,6 +19,12 @@ -add: obj { + if ([obj conformsToProtocol: @protocol (Draw)]) { + [views addObject: obj]; + } + if ([obj conformsToProtocol: @protocol (HandleEvent)]) { + [event_handlers addObject: obj]; + } return self; } @@ -29,4 +35,14 @@ return self; } +-handleEvent: (qwaq_event_t *) event +{ + return self; +} + +-draw +{ + return self; +} + @end diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index 811998ed0..e532f9f0b 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -4,9 +4,10 @@ #include #include +#include "qwaq-draw.h" #include "qwaq-rect.h" -@interface View: Object +@interface View: Object { Rect rect; Rect absRect; @@ -14,7 +15,6 @@ struct window_s *window; } -initWithRect: (Rect) rect; --handleEvent: (struct qwaq_event_s *) event; @end #endif//__qwaq_view_h diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index c03d880f4..8cf37c53d 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -28,7 +28,7 @@ rectContainsPoint (Rect *rect, Point *point) return self; } --handleEvent: (qwaq_event_t *) event +-draw { return self; } diff --git a/ruamoko/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h index 5d777c828..66c6d440e 100644 --- a/ruamoko/qwaq/qwaq-window.h +++ b/ruamoko/qwaq/qwaq-window.h @@ -6,9 +6,10 @@ @class View; @class Array; +#include "qwaq-draw.h" #include "qwaq-rect.h" -@interface Window: Object +@interface Window: Object { Rect rect; Point point; // FIXME can't be local :( diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 70fe2c476..307f09dce 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -68,4 +68,19 @@ wbkgd (window, ch); return self; } + +-takeFocus +{ + return self; +} + +-loseFocus +{ + return self; +} + +-draw +{ + return self; +} @end From fa66e9fc2f61c9b43670a822c2f051aee1f0fb7f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 18:15:31 +0900 Subject: [PATCH 156/444] [qwaq] Move queue handling into separate functions This makes it so I need to edit only one place when I get threads working. Also, it fixes some bugs (eg, panel creation wasn't implemented correctly). --- ruamoko/qwaq/qwaq-curses.c | 196 +++++++++++++++---------------------- 1 file changed, 79 insertions(+), 117 deletions(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 1c081e1eb..474203e47 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -97,7 +97,7 @@ typedef enum qwaq_commands_e { #define RB_WRITE_DATA(ring_buffer, data, count) \ ({ __auto_type rb = &(ring_buffer); \ - typeof (&rb->buffer[0]) d = (data); \ + const typeof (rb->buffer[0]) *d = (data); \ unsigned c = (count); \ unsigned h = rb->head; \ rb->head = (h + c) % RB_buffer_size (rb); \ @@ -272,6 +272,45 @@ release_string (qwaq_resources_t *res, int string_id) } } +static void +qwaq_submit_command (qwaq_resources_t *res, const int *cmd) +{ + unsigned len = cmd[1]; + + if (RB_SPACE_AVAILABLE (res->command_queue) >= len) { + RB_WRITE_DATA (res->command_queue, cmd, len); + } else { + PR_RunError (res->pr, "command buffer full"); + } +} + +static void +qwaq_submit_result (qwaq_resources_t *res, const int *result, unsigned len) +{ + // loop + if (RB_SPACE_AVAILABLE (res->results) >= len) { + RB_WRITE_DATA (res->results, result, len); + } else { + PR_RunError (res->pr, "result buffer full"); + } +} + +//XXX goes away with threads +static void process_commands (qwaq_resources_t *); +static void process_input (qwaq_resources_t *); +static void +qwaq_wait_result (qwaq_resources_t *res, int *result, int cmd, unsigned len) +{ + // XXX should just wait on the mutex + process_commands (res); + process_input (res); + // locking and loop until id is correct + if (RB_DATA_AVAILABLE (res->results) >= len + && RB_PEEK_DATA (res->results, 0) == cmd) { + RB_READ_DATA (res->results, result, len); + } +} + static void cmd_newwin (qwaq_resources_t *res) { @@ -286,11 +325,7 @@ cmd_newwin (qwaq_resources_t *res) int window_id = window_index (res, window); int cmd_result[] = { qwaq_cmd_newwin, window_id }; - - // loop - if (RB_SPACE_AVAILABLE (res->results) >= CMD_SIZE (cmd_result)) { - RB_WRITE_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); - } + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); } static void @@ -318,11 +353,7 @@ cmd_getwrect (qwaq_resources_t *res) getmaxyx (window->win, ylen, xlen); int cmd_result[] = { qwaq_cmd_getwrect, xpos, ypos, xlen, ylen }; - - // loop - if (RB_SPACE_AVAILABLE (res->results) >= CMD_SIZE (cmd_result)) { - RB_WRITE_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); - } + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); } static void @@ -337,11 +368,7 @@ cmd_new_panel (qwaq_resources_t *res) int panel_id = panel_index (res, panel); int cmd_result[] = { qwaq_cmd_new_panel, panel_id }; - - // loop - if (RB_SPACE_AVAILABLE (res->results) >= CMD_SIZE (cmd_result)) { - RB_WRITE_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); - } + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); } static void @@ -415,11 +442,7 @@ cmd_panel_window (qwaq_resources_t *res) int window_id = panel->window_id; int cmd_result[] = { qwaq_cmd_panel_window, window_id, }; - - // loop - if (RB_SPACE_AVAILABLE (res->results) >= CMD_SIZE (cmd_result)) { - RB_WRITE_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); - } + qwaq_submit_result (res, cmd_result, CMD_SIZE (cmd_result)); } static void @@ -631,22 +654,12 @@ bi_newwin (progs_t *pr) qwaq_cmd_newwin, 0, xpos, ypos, xlen, ylen, }; - command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } - // XXX should just wait on the mutex - process_commands (res); - process_input (res); - // locking and loop until id is correct - if (RB_DATA_AVAILABLE (res->results) - && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_newwin) { - int cmd_result[2]; // should results have a size? - RB_READ_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); - R_INT (pr) = cmd_result[1]; - } + int cmd_result[2]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_newwin, CMD_SIZE (cmd_result)); + R_INT (pr) = cmd_result[1]; } static void @@ -657,12 +670,8 @@ bi_delwin (progs_t *pr) if (get_window (res, __FUNCTION__, window_id)) { int command[] = { qwaq_cmd_delwin, 0, window_id, }; - command[1] = CMD_SIZE(command); - - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } + qwaq_submit_command (res, command); } } @@ -674,26 +683,17 @@ bi_getwrect (progs_t *pr) if (get_window (res, __FUNCTION__, window_id)) { int command[] = { qwaq_cmd_getwrect, 0, window_id, }; - command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } - // XXX should just wait on the mutex - process_commands (res); - process_input (res); - // locking and loop until id is correct - if (RB_DATA_AVAILABLE (res->results) - && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_getwrect) { - int cmd_result[5]; - RB_READ_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); - // return xpos, ypos, xlen, ylen - (&R_INT (pr))[0] = cmd_result[1]; - (&R_INT (pr))[1] = cmd_result[2]; - (&R_INT (pr))[2] = cmd_result[3]; - (&R_INT (pr))[3] = cmd_result[4]; - } + int cmd_result[5]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_getwrect, + CMD_SIZE (cmd_result)); + // return xpos, ypos, xlen, ylen + (&R_INT (pr))[0] = cmd_result[1]; + (&R_INT (pr))[1] = cmd_result[2]; + (&R_INT (pr))[2] = cmd_result[3]; + (&R_INT (pr))[3] = cmd_result[4]; } } @@ -705,20 +705,13 @@ bi_new_panel (progs_t *pr) if (get_window (res, __FUNCTION__, window_id)) { int command[] = { qwaq_cmd_new_panel, 0, window_id, }; - command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } - - // locking and loop until id is correct - if (RB_DATA_AVAILABLE (res->results) - && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_new_panel) { - int cmd_result[2]; // should results have a size? - RB_READ_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); - R_INT (pr) = cmd_result[1]; - } + int cmd_result[2]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_new_panel, + CMD_SIZE (cmd_result)); + R_INT (pr) = cmd_result[1]; } } @@ -731,10 +724,7 @@ panel_command (progs_t *pr, qwaq_commands cmd) if (get_panel (res, __FUNCTION__, panel_id)) { int command[] = { cmd, 0, panel_id, }; command[1] = CMD_SIZE(command); - - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } + qwaq_submit_command (res, command); } } @@ -779,10 +769,7 @@ bi_move_panel (progs_t *pr) if (get_panel (res, __FUNCTION__, panel_id)) { int command[] = { qwaq_cmd_move_panel, 0, panel_id, x, y, }; command[1] = CMD_SIZE(command); - - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } + qwaq_submit_command (res, command); } } @@ -795,20 +782,12 @@ bi_panel_window (progs_t *pr) if (get_panel (res, __FUNCTION__, panel_id)) { int command[] = { qwaq_cmd_panel_window, 0, panel_id, }; command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } - // XXX should just wait on the mutex - process_commands (res); - process_input (res); - // locking and loop until id is correct - if (RB_DATA_AVAILABLE (res->results) - && RB_PEEK_DATA (res->results, 0) == qwaq_cmd_panel_window) { - int cmd_result[2]; - RB_READ_DATA (res->results, cmd_result, CMD_SIZE (cmd_result)); - (&R_INT (pr))[0] = cmd_result[0]; - } + int cmd_result[2]; + qwaq_wait_result (res, cmd_result, qwaq_cmd_panel_window, + CMD_SIZE (cmd_result)); + (&R_INT (pr))[0] = cmd_result[1]; } } @@ -819,10 +798,7 @@ bi_update_panels (progs_t *pr) int command[] = { qwaq_cmd_update_panels, 0, }; command[1] = CMD_SIZE(command); - - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } + qwaq_submit_command (res, command); } static void @@ -832,10 +808,7 @@ bi_doupdate (progs_t *pr) int command[] = { qwaq_cmd_doupdate, 0, }; command[1] = CMD_SIZE(command); - - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } + qwaq_submit_command (res, command); } static void @@ -861,9 +834,8 @@ bi_mvwprintf (progs_t *pr) dstring_clearstr (print_buffer); PR_Sprintf (pr, print_buffer, "mvwaddstr", fmt, count, args); - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } + + qwaq_submit_command (res, command); } } @@ -888,9 +860,8 @@ bi_wprintf (progs_t *pr) dstring_clearstr (print_buffer); PR_Sprintf (pr, print_buffer, "waddstr", fmt, count, args); - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } + + qwaq_submit_command (res, command); } } @@ -903,10 +874,7 @@ bi_wrefresh (progs_t *pr) if (get_window (res, __FUNCTION__, window_id)) { int command[] = { qwaq_cmd_wrefresh, 0, window_id, }; command[1] = CMD_SIZE(command); - - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } + qwaq_submit_command (res, command); } } @@ -943,10 +911,7 @@ bi_init_pair (progs_t *pr) int command[] = { qwaq_cmd_init_pair, 0, pair, f, b, }; command[1] = CMD_SIZE(command); - - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } + qwaq_submit_command (res, command); } static void @@ -958,12 +923,9 @@ bi_wbkgd (progs_t *pr) if (get_window (res, __FUNCTION__, window_id)) { int command[] = { qwaq_cmd_wbkgd, 0, window_id, ch, }; - command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); - if (RB_SPACE_AVAILABLE (res->command_queue) >= CMD_SIZE(command)) { - RB_WRITE_DATA (res->command_queue, command, CMD_SIZE(command)); - } } } From a0c4d566683c3e9663d94519fac00dfe52af99d6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 18:19:41 +0900 Subject: [PATCH 157/444] [qwaq] Continue processing on void commands If the last command in the buffer had no parameters, its length would be only 2 and thus processing would stop before reading the command from the buffer. --- ruamoko/qwaq/qwaq-curses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 474203e47..2b53efb06 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -513,7 +513,7 @@ cmd_wbkgd (qwaq_resources_t *res) static void process_commands (qwaq_resources_t *res) { - while (RB_DATA_AVAILABLE (res->command_queue) > 2) { + while (RB_DATA_AVAILABLE (res->command_queue) >= 2) { switch ((qwaq_commands) RB_PEEK_DATA (res->command_queue, 0)) { case qwaq_cmd_newwin: cmd_newwin (res); From b9ab30ff59d49cf5044332b7c1a53017471b6bac Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 18:24:45 +0900 Subject: [PATCH 158/444] [qwaq] Add mvwaddch and ACS support --- ruamoko/qwaq/qwaq-app.r | 2 ++ ruamoko/qwaq/qwaq-curses.c | 50 +++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-curses.h | 64 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index d9051f4d9..28bf31126 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -103,11 +103,13 @@ void destroy_window (window_t win) = #0; void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; void wprintf (window_t win, string fmt, ...) = #0; void wrefresh (window_t win) = #0; +void mvwaddch (window_t win, int x, int y, int ch) = #0; int get_event (qwaq_event_t *event) = #0; int max_colors (void) = #0; int max_color_pairs (void) = #0; int init_pair (int pair, int f, int b) = #0; void wbkgd (window_t win, int ch) = #0; +int acs_char (int acs) = #0; panel_t create_panel (window_t window) = #0; void destroy_panel (panel_t panel) = #0; diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 2b53efb06..e8c6548eb 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -68,6 +68,7 @@ typedef enum qwaq_commands_e { qwaq_cmd_doupdate, qwaq_cmd_mvwaddstr, qwaq_cmd_waddstr, + qwaq_cmd_mvwaddch, qwaq_cmd_wrefresh, qwaq_cmd_init_pair, qwaq_cmd_wbkgd, @@ -481,6 +482,18 @@ cmd_waddstr (qwaq_resources_t *res) release_string (res, string_id); } +static void +cmd_mvwaddch (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int x = RB_PEEK_DATA (res->command_queue, 3); + int y = RB_PEEK_DATA (res->command_queue, 4); + int ch = RB_PEEK_DATA (res->command_queue, 5); + + window_t *window = get_window (res, __FUNCTION__, window_id); + mvwaddch (window->win, y, x, ch); +} + static void cmd_wrefresh (qwaq_resources_t *res) { @@ -560,6 +573,9 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_waddstr: cmd_waddstr (res); break; + case qwaq_cmd_mvwaddch: + cmd_mvwaddch (res); + break; case qwaq_cmd_wrefresh: cmd_wrefresh (res); break; @@ -865,6 +881,25 @@ bi_wprintf (progs_t *pr) } } +static void +bi_mvwaddch (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + int ch = P_INT (pr, 3); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { + qwaq_cmd_mvwaddch, 0, + window_id, x, y, ch + }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} + static void bi_wrefresh (progs_t *pr) { @@ -925,7 +960,20 @@ bi_wbkgd (progs_t *pr) int command[] = { qwaq_cmd_wbkgd, 0, window_id, ch, }; command[1] = CMD_SIZE(command); qwaq_submit_command (res, command); + } +} +static const char qwaq_acs_char_map[] = "lmkjtuvwqxnos`afg~,+.-hi0pryz{|}"; +static void +bi_acs_char (progs_t *pr) +{ + unsigned acs = P_INT (pr, 0); + if (acs < 256) { + R_INT (pr) = NCURSES_ACS(acs); + } else if (acs - 256 < sizeof (qwaq_acs_char_map)) { + R_INT (pr) = NCURSES_ACS(qwaq_acs_char_map[acs - 256]); + } else { + R_INT (pr) = 0; } } @@ -981,12 +1029,14 @@ static builtin_t builtins[] = { {"doupdate", bi_doupdate, -1}, {"mvwprintf", bi_mvwprintf, -1}, {"wprintf", bi_wprintf, -1}, + {"mvwaddch", bi_mvwaddch, -1}, {"wrefresh", bi_wrefresh, -1}, {"get_event", bi_get_event, -1}, {"max_colors", bi_max_colors, -1}, {"max_color_pairs", bi_max_color_pairs, -1}, {"init_pair", bi_init_pair, -1}, {"wbkgd", bi_wbkgd, -1}, + {"acs_char", bi_acs_char, -1}, {0} }; diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index 751c521a7..bf5d24191 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -4,6 +4,67 @@ #include "event.h" #ifdef __QFCC__ +// names, order and comments lifted from ncurses.h +typedef enum { +/* VT100 symbols begin here */ + ACS_ULCORNER = 256, /* upper left corner */ + ACS_LLCORNER, /* lower left corner */ + ACS_URCORNER, /* upper right corner */ + ACS_LRCORNER, /* lower right corner */ + ACS_LTEE, /* tee pointing right */ + ACS_RTEE, /* tee pointing left */ + ACS_BTEE, /* tee pointing up */ + ACS_TTEE, /* tee pointing down */ + ACS_HLINE, /* horizontal line */ + ACS_VLINE, /* vertical line */ + ACS_PLUS, /* large plus or crossover */ + ACS_S1, /* scan line 1 */ + ACS_S9, /* scan line 9 */ + ACS_DIAMOND, /* diamond */ + ACS_CKBOARD, /* checker board (stipple) */ + ACS_DEGREE, /* degree symbol */ + ACS_PLMINUS, /* plus/minus */ + ACS_BULLET, /* bullet */ +/* Teletype 5410v1 symbols begin here */ + ACS_LARROW, /* arrow pointing left */ + ACS_RARROW, /* arrow pointing right */ + ACS_DARROW, /* arrow pointing down */ + ACS_UARROW, /* arrow pointing up */ + ACS_BOARD, /* board of squares */ + ACS_LANTERN, /* lantern symbol */ + ACS_BLOCK, /* solid square block */ +/* + * These aren't documented, but a lot of System Vs have them anyway + * (you can spot pprryyzz{{||}} in a lot of AT&T terminfo strings). + * The ACS_names may not match AT&T's, our source didn't know them. + */ + ACS_S3, /* scan line 3 */ + ACS_S7, /* scan line 7 */ + ACS_LEQUAL, /* less/equal */ + ACS_GEQUAL, /* greater/equal */ + ACS_PI, /* Pi */ + ACS_NEQUAL, /* not equal */ + ACS_STERLING, /* UK pound sign */ + +/* + * Line drawing ACS names are of the form ACS_trbl, where t is the top, r + * is the right, b is the bottom, and l is the left. t, r, b, and l might + * be B (blank), S (single), D (double), or T (thick). The subset defined + * here only uses B and S. + */ + ACS_BSSB = ACS_ULCORNER, + ACS_SSBB = ACS_LLCORNER, + ACS_BBSS = ACS_URCORNER, + ACS_SBBS = ACS_LRCORNER, + ACS_SBSS = ACS_RTEE, + ACS_SSSB = ACS_LTEE, + ACS_SSBS = ACS_BTEE, + ACS_BSSS = ACS_TTEE, + ACS_BSBS = ACS_HLINE, + ACS_SBSB = ACS_VLINE, + ACS_SSSS = ACS_PLUS, +} qwaq_acs_chars; + typedef struct window_s *window_t; typedef struct panel_s *panel_t; @@ -15,6 +76,7 @@ typedef struct panel_s *panel_t; @extern void mvwprintf (window_t win, int x, int y, string fmt, ...); @extern void wprintf (window_t win, string fmt, ...); @extern void wrefresh (window_t win); +@extern void mvwaddch (window_t win, int x, int y, int ch); @extern panel_t create_panel (window_t window); @extern void destroy_panel (panel_t panel); @@ -32,6 +94,8 @@ typedef struct panel_s *panel_t; @extern int max_color_pairs (void); @extern int init_pair (int pair, int f, int b); @extern void wbkgd (window_t win, int ch); + +@extern int acs_char (int acs); #endif #endif//__qwaq_curses_h From 6f1386fa0dbd77f7030ff21a31e01a06b80fea60 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 18:29:31 +0900 Subject: [PATCH 159/444] [qwaq] Test out acs chars and the classes Crashes due to flooding the command buffer, but otherwise works (with larger buffer). --- ruamoko/qwaq/qwaq-app.r | 7 ++++--- ruamoko/qwaq/qwaq-screen.r | 5 +++++ ruamoko/qwaq/qwaq-window.r | 16 ++++++++++++++++ 3 files changed, 25 insertions(+), 3 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 28bf31126..619001b79 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -44,20 +44,21 @@ arp_end (void) r.xlen /= 2; r.ylen /= 2; wprintf (screen.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); + wprintf (screen.window, "%d\n", acs_char(ACS_HLINE)); + mvwaddch(screen.window, 4, 4, acs_char(ACS_HLINE)); wrefresh(screen.window); Window *w; [screen add: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; - wprintf (w.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); + //wprintf (w.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); return self; } -run { + [screen draw]; do { arp_start (); - update_panels (); - doupdate (); get_event (&event); if (event.event_type != qe_none) { [self handleEvent: &event]; diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index e44c25481..be7400468 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -12,6 +12,8 @@ if (!(self = [super init])) { return nil; } + views = [[Array array] retain]; + event_handlers = [[Array array] retain]; window = stdscr; rect = getwrect (window); return self; @@ -42,6 +44,9 @@ -draw { + [views makeObjectsPerformSelector: @selector (draw)]; + update_panels (); + doupdate (); return self; } diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 307f09dce..bf94b177d 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -81,6 +81,22 @@ -draw { + int x = 0, y = 0; + for (int i = ACS_ULCORNER; i <= ACS_STERLING; i++) { + int ch = acs_char (i); + if (ch) { + mvwaddch (window, x, y, ch); + } else { + mvwaddch (window, x, y, '.'); + } + if (++x >= rect.xlen) { + x = 0; + if (++y >= rect.ylen) { + break; + } + } + } + wrefresh(window); return self; } @end From 33a07c0f6b3cecae9eb4b72bbb5387ec916ec8ec Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 18:30:58 +0900 Subject: [PATCH 160/444] [qwaq] Make command buffer larger for now A small one should be fine once threading is working. --- ruamoko/qwaq/qwaq-curses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index e8c6548eb..f33e01a5a 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -49,7 +49,7 @@ #define MOUSE_MOVES_ON "\033[?1003h"// Make the terminal report mouse movements #define MOUSE_MOVES_OFF "\033[?1003l"// Make the terminal report mouse movements #define STRING_ID_QUEUE_SIZE 8 // must be > 1 -#define COMMAND_QUEUE_SIZE 128 +#define COMMAND_QUEUE_SIZE 1280 #define CMD_SIZE(x) sizeof(x)/sizeof(x[0]) typedef enum qwaq_commands_e { From d91289ea1b37856c8d7b60d3114581f44ca06713 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 18:43:27 +0900 Subject: [PATCH 161/444] [qwaq] Remove unnecessary wrefresh calls --- ruamoko/qwaq/qwaq-app.r | 1 - ruamoko/qwaq/qwaq-screen.r | 1 - ruamoko/qwaq/qwaq-window.r | 1 - 3 files changed, 3 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 619001b79..e100ae69e 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -46,7 +46,6 @@ arp_end (void) wprintf (screen.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); wprintf (screen.window, "%d\n", acs_char(ACS_HLINE)); mvwaddch(screen.window, 4, 4, acs_char(ACS_HLINE)); - wrefresh(screen.window); Window *w; [screen add: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; //wprintf (w.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index be7400468..770104c64 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -33,7 +33,6 @@ -setBackground: (int) ch { wbkgd (window, ch); - wrefresh (window); return self; } diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index bf94b177d..493a6ccff 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -96,7 +96,6 @@ } } } - wrefresh(window); return self; } @end From e33d83fc9eeeb97707b5eb9fe908afbea69f32fc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 20:16:29 +0900 Subject: [PATCH 162/444] [qfcc] Accept "struct foo; struct foo { ... };" That is, do not treat structure definition after declaration to be a redefinition. --- tools/qfcc/source/qc-parse.y | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 8d939185b..5658382c5 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -610,9 +610,18 @@ struct_specifier if (!sym->table) { symtab_addsymbol (current_symtab, sym); } else { - error (0, "%s %s redefined", $1 == 's' ? "struct" : "union", - $2->name); - $1 = 0; + if (!sym->type) { + internal_error (0, "broken structure symbol?"); + } + if (sym->type->meta == ty_enum + || (sym->type->meta == ty_struct && sym->type->t.symtab)) { + error (0, "%s %s redefined", + $1 == 's' ? "struct" : "union", $2->name); + $1 = 0; + } else if (sym->type->meta != ty_struct) { + internal_error (0, "%s is not a struct or union", + $2->name); + } } current_symtab = new_symtab (current_symtab, stab_local); } From f6d650d47351ba71d4df9049436c9e8a506578b7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 21:15:21 +0900 Subject: [PATCH 163/444] [qfcc] Merge duplicate methods in interfaces Duplicate methods in an interface (especially across protocols and between protocols and the interface) are both harmless and even to be expected. They certainly should not cause the compiler to demand duplicate method implementations :) --- tools/qfcc/source/class.c | 9 +++------ tools/qfcc/source/method.c | 6 ++++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 381b37e1e..e4861b8d2 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -631,8 +631,7 @@ class_add_methods (class_t *class, methodlist_t *methods) if (!methods) return; - *class->methods->tail = methods->head; - class->methods->tail = methods->tail; + copy_methods (class->methods, methods); free (methods); methods_set_self_type (class, class->methods); @@ -1260,8 +1259,7 @@ category_add_methods (category_t *category, methodlist_t *methods) { if (!methods) return; - *category->methods->tail = methods->head; - category->methods->tail = methods->tail; + copy_methods (category->methods, methods); free (methods); methods_set_self_type (category->class, category->methods); @@ -1520,8 +1518,7 @@ protocol_add_methods (protocol_t *protocol, methodlist_t *methods) { if (!methods) return; - *protocol->methods->tail = methods->head; - protocol->methods->tail = methods->tail; + copy_methods (protocol->methods, methods); free (methods); } diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 2ae50f39d..4bc819621 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -147,6 +147,12 @@ add_method (methodlist_t *methodlist, method_t *method) if (method->next) internal_error (0, "add_method: method loop detected"); + for (method_t *m = methodlist->head; m; m = m->next) { + if (method_compare (m, method)) { + debug (0, "dropping duplicate method: %s", method->name); + return; + } + } *methodlist->tail = method; methodlist->tail = &method->next; } From 8a4de6fea6159779cce78b51cb18b6d7e31accb4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 22:38:12 +0900 Subject: [PATCH 164/444] [qfcc] Fix segmentation fault for parameter errors --- tools/qfcc/source/expr.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 967484f95..ea9d64881 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1670,6 +1670,10 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) for (i = arg_count - 1, e = params; i >= 0; i--, e = e->next) { type_t *t = get_type (e); + if (!t) { + return e; + } + if (!type_size (t)) err = error (e, "type of formal parameter %d is incomplete", i + 1); From f025bd96d46ba4416bb9df669473106c39888004 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 2 Mar 2020 23:38:04 +0900 Subject: [PATCH 165/444] [qfcc] Copy self param when copying methods Copying methods is done when adding protocols to classes (the current use for adding regular methods is an incorrect solution to a different problem). However, when a method is added to a class, the type of its self parameter is set to be a pointer to the class. Thus, not only does the method need to be copied, the self parameter does too, otherwise the self parameter of methods added via protocols will have their type set to be a pointer to the last class seen adding the protocol. That is, if, while compiling the implementation for class A, but the interface for class B is comes after the interface for class A, and both A and B add protocol P, then all methods in protocol P will have self pointing to B rather than A. @protocol P -method; @end @interface A

@end @interface B

@end @implementation A -method {} // self is B, not A! @end --- tools/qfcc/source/method.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 4bc819621..e296adf3b 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -208,11 +208,21 @@ new_methodlist (void) void copy_methods (methodlist_t *dst, methodlist_t *src) { - method_t *s, *d; + method_t *s, *d; + param_t *self; for (s = src->head; s; s = s->next) { d = malloc (sizeof (method_t)); *d = *s; + // The above is only a shallow copy and thus even though the methods + // are not shared between the source and destination lists, the + // parameters are. Thus, duplicate the self (first) parameter so + // changing its type to match the class into which it is inserted does + // not affect the source list. The rest of the parameters do not need + // to be copied as they will not be altered. + self = malloc (sizeof (param_t)); + *self = *d->params; + d->params = self; d->next = 0; add_method (dst, d); } From 679744fc7d671ad1ec90d08e090229bb5145d298 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 00:11:07 +0900 Subject: [PATCH 166/444] [libr] Fix incorrect bounds check on array insert --- ruamoko/lib/Array.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruamoko/lib/Array.r b/ruamoko/lib/Array.r index 4673c31d8..bbf5ce883 100644 --- a/ruamoko/lib/Array.r +++ b/ruamoko/lib/Array.r @@ -261,7 +261,7 @@ { local unsigned i; - if (index >= count) // FIXME: need exceptions + if (index > count) // FIXME: need exceptions [self error: "-insertObject:atIndex: index out of range"]; if (count == capacity) { // at capacity, expand From ed04e6fc23b20fdd7e4dc85c7020f82533e3610d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 00:11:54 +0900 Subject: [PATCH 167/444] [qfcc] Merge method lists instead of copying This is for adding methods to classes and protocols via their interface, not for adding methods by adding protocols (they still get copied). Slightly more memory efficient. --- tools/qfcc/include/method.h | 2 ++ tools/qfcc/source/class.c | 9 +++------ tools/qfcc/source/method.c | 40 ++++++++++++++++++++++++++++++++++++- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/tools/qfcc/include/method.h b/tools/qfcc/include/method.h index ef51e1579..6b02bbe00 100644 --- a/tools/qfcc/include/method.h +++ b/tools/qfcc/include/method.h @@ -80,6 +80,8 @@ struct symbol_s *method_symbol (struct class_type_s *class_type, void method_set_param_names (method_t *dst, method_t *src); methodlist_t *new_methodlist (void); +//NOTE frees the source list and any methods not copied +void merge_method_lists (methodlist_t *dst, methodlist_t *src); void copy_methods (methodlist_t *dst, methodlist_t *src); int method_compare (method_t *m1, method_t *m2); diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index e4861b8d2..4b331d237 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -631,8 +631,7 @@ class_add_methods (class_t *class, methodlist_t *methods) if (!methods) return; - copy_methods (class->methods, methods); - free (methods); + merge_method_lists (class->methods, methods); methods_set_self_type (class, class->methods); } @@ -1259,8 +1258,7 @@ category_add_methods (category_t *category, methodlist_t *methods) { if (!methods) return; - copy_methods (category->methods, methods); - free (methods); + merge_method_lists (category->methods, methods); methods_set_self_type (category->class, category->methods); } @@ -1518,8 +1516,7 @@ protocol_add_methods (protocol_t *protocol, methodlist_t *methods) { if (!methods) return; - copy_methods (protocol->methods, methods); - free (methods); + merge_method_lists (protocol->methods, methods); } void diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index e296adf3b..d1f8dd5cd 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -205,6 +205,38 @@ new_methodlist (void) return l; } +static int +method_in_list (methodlist_t *method_list, method_t *method) +{ + method_t *m; + + for (m = method_list->head; m; m = m->next) { + if (method_compare (m, method)) { + return 1; + } + } + return 0; +} + +void +merge_method_lists (methodlist_t *dst, methodlist_t *src) +{ + while (src->head) { + method_t *s = src->head; + src->head = s->next; + s->next = 0; + if (method_in_list (dst, s)) { + debug (0, "dropping duplicate method: %s", s->name); + free (s); + } else { + // add_method does the duplicate check + *dst->tail = s; + dst->tail = &s->next; + } + } + free (src); +} + void copy_methods (methodlist_t *dst, methodlist_t *src) { @@ -212,6 +244,10 @@ copy_methods (methodlist_t *dst, methodlist_t *src) param_t *self; for (s = src->head; s; s = s->next) { + if (method_in_list (dst, s)) { + debug (0, "skipping duplicate method: %s", s->name); + continue; + } d = malloc (sizeof (method_t)); *d = *s; // The above is only a shallow copy and thus even though the methods @@ -224,7 +260,9 @@ copy_methods (methodlist_t *dst, methodlist_t *src) *self = *d->params; d->params = self; d->next = 0; - add_method (dst, d); + // add_method does the duplicate check + *dst->tail = d; + dst->tail = &d->next; } } From 50d39d64cbd77071d34a4fd2db33b1f1909ce8be Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 09:30:20 +0900 Subject: [PATCH 168/444] [qwaq] Link against build ruamoko libs, not installed --- ruamoko/qwaq/Makefile.am | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ruamoko/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am index 38584d949..f32d9d536 100644 --- a/ruamoko/qwaq/Makefile.am +++ b/ruamoko/qwaq/Makefile.am @@ -13,7 +13,9 @@ QFCC=$(top_builddir)/tools/qfcc/source/qfcc QCFLAGS=-qq -O -g -Werror QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) SUFFIXES=.o .r .r.o: @@ -61,7 +63,7 @@ qwaq_app_dat_SOURCES=qwaq-app.r qwaq-screen.r qwaq-window.r qwaq-view.r qwaq_app_obj=$(qwaq_app_dat_SOURCES:.r=.o) qwaq_app_dep=$(addprefix ./$(DEPDIR)/,$(qwaq_app_obj:.o=.Qo)) qwaq-app.dat$(EXEEXT): $(qwaq_app_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(qwaq_app_obj) -lr + $(QLINK) -o $@ $(qwaq_app_obj) -lr include $(qwaq_app_dep) # am--include-marker r_depfiles_remade += $(qwaq_app_dep) From 16223098e52a7e981277581bd0df43202f9cb643 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 10:42:05 +0900 Subject: [PATCH 169/444] [qfcc] Fix ivar visibility It was broken by the big rewrite and I forgot to fix it. --- tools/qfcc/source/expr.c | 3 ++- tools/qfcc/source/qc-parse.y | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index ea9d64881..dafb49c96 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1202,8 +1202,9 @@ field_expr (expr_t *e1, expr_t *e2) class_t *class = t1->t.fldptr.type->t.class; symbol_t *sym = e2->e.symbol;//FIXME need to check symbol_t *ivar; + int protected = class_access (current_class, class); - ivar = class_find_ivar (class, vis_protected, sym->name); + ivar = class_find_ivar (class, protected, sym->name); if (!ivar) return new_error_expr (); e2->type = ex_value; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 5658382c5..7ae13bd6e 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -706,6 +706,7 @@ struct_decl $1->type = append_type ($1->type, $0.type); $1->type = find_type ($1->type); $1->sy_type = sy_var; + $1->visibility = current_visibility; symtab_addsymbol (current_symtab, $1); } | var_decl @@ -715,6 +716,7 @@ struct_decl $1->type = append_type ($1->type, $0.type); $1->type = find_type ($1->type); $1->sy_type = sy_var; + $1->visibility = current_visibility; symtab_addsymbol (current_symtab, $1); } | var_decl ':' expr %prec COMMA {} @@ -1762,6 +1764,7 @@ ivar_decl_list tab = $$->parent; // preserve the ivars inheritance chain build_struct ('s', 0, $$, 0); $$->parent = tab; + current_visibility = vis_public; } ; From c2138183dd159a2d2ee13288b5f319b7ee582ebf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 10:43:29 +0900 Subject: [PATCH 170/444] [libr] Initialize SetIterator the right way I'd written Set.[rh] after the big rewrite so never noticed the access error. --- ruamoko/lib/Set.r | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/ruamoko/lib/Set.r b/ruamoko/lib/Set.r index 10cf6397d..06ef95193 100644 --- a/ruamoko/lib/Set.r +++ b/ruamoko/lib/Set.r @@ -27,6 +27,15 @@ string set_as_string (set_t *set) = #0; @implementation SetIterator: Object +- initWithIterator: (set_iter_t *) iter +{ + if (!(self = [super init])) { + return nil; + } + self.iter = iter; + return self; +} + - (SetIterator *) next { if ((iter = set_next (iter))) @@ -84,8 +93,7 @@ string set_as_string (set_t *set) = #0; if (!iter) return nil; - iterator = [[SetIterator alloc] init]; - iterator.iter = iter; + iterator = [[SetIterator alloc] initWithIterator: iter]; return iterator; } From bb25057feb7a51a3420da14e14ca09da0825fc47 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 10:46:28 +0900 Subject: [PATCH 171/444] [qwaq] Quickly Workaround Access Qualifications :) --- ruamoko/qwaq/qwaq-screen.h | 1 + ruamoko/qwaq/qwaq-view.h | 1 + ruamoko/qwaq/qwaq-window.h | 1 + 3 files changed, 3 insertions(+) diff --git a/ruamoko/qwaq/qwaq-screen.h b/ruamoko/qwaq/qwaq-screen.h index cbd0a6721..5ded2ecaf 100644 --- a/ruamoko/qwaq/qwaq-screen.h +++ b/ruamoko/qwaq/qwaq-screen.h @@ -10,6 +10,7 @@ @interface Screen: Object { + @public Rect rect; Array *views; Array *event_handlers; diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index e532f9f0b..817ec0ab7 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -9,6 +9,7 @@ @interface View: Object { + @public Rect rect; Rect absRect; Point point; // can't be local :( diff --git a/ruamoko/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h index 66c6d440e..ae45d7e72 100644 --- a/ruamoko/qwaq/qwaq-window.h +++ b/ruamoko/qwaq/qwaq-window.h @@ -11,6 +11,7 @@ @interface Window: Object { + @public Rect rect; Point point; // FIXME can't be local :( Array *views; From c7cde5f409626609665cbb847df3e0c18c896412 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 10:59:01 +0900 Subject: [PATCH 172/444] [qfcc] Pass gcc's purity test *sigh* --- tools/qfcc/source/method.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index d1f8dd5cd..c5bd8b334 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -205,7 +205,7 @@ new_methodlist (void) return l; } -static int +static int __attribute__((pure)) method_in_list (methodlist_t *method_list, method_t *method) { method_t *m; From b8984e5f660b426a5c3a994c1eb565926e801e65 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 13:39:24 +0900 Subject: [PATCH 173/444] [qfcc] Fix another infinite loop in the linker I think this should be it for infinite loops caused by undefined symbols. I don't know why I didn't remove this continue when I removed the other. --- tools/qfcc/source/linker.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/source/linker.c b/tools/qfcc/source/linker.c index 5a9d367ce..de107d1b4 100644 --- a/tools/qfcc/source/linker.c +++ b/tools/qfcc/source/linker.c @@ -1119,10 +1119,8 @@ undefined_def (qfo_def_t *def) pr_lineno_t *line; while (func - work->funcs < work->num_funcs) { - if (func->code < 0) { - continue; - } - if ((pr_uint_t) func->code <= reloc->offset) { + if (func->code >= 0 + && (pr_uint_t) func->code <= reloc->offset) { if (!best || reloc->offset - func->code < best_dist) { best = func; best_dist = reloc->offset - func->code; From cdc1f0c5e7429845243311fd563de7eb961cd773 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 15:24:41 +0900 Subject: [PATCH 174/444] [libr] Treat ruamoko headers as system headers Now that qfcc actually supports them properly. --- ruamoko/gui/Group.r | 6 +++--- ruamoko/gui/InputLine.r | 6 +++--- ruamoko/gui/Makefile.am | 5 ++++- ruamoko/gui/Pic.r | 6 +++--- ruamoko/gui/Point.r | 2 +- ruamoko/gui/Rect.r | 8 ++++---- ruamoko/gui/Size.r | 2 +- ruamoko/gui/Slider.r | 6 +++--- ruamoko/gui/Text.r | 6 +++--- ruamoko/gui/View.r | 8 ++++---- ruamoko/include/Array.h | 4 ++-- ruamoko/include/AutoreleasePool.h | 2 +- ruamoko/include/Entity.h | 2 +- ruamoko/include/Object.h | 2 +- ruamoko/include/PropertyList.h | 4 ++-- ruamoko/include/Protocol.h | 2 +- ruamoko/include/draw.h | 2 +- ruamoko/include/gui/Group.h | 2 +- ruamoko/include/gui/InputLine.h | 2 +- ruamoko/include/gui/Pic.h | 2 +- ruamoko/include/gui/Rect.h | 4 ++-- ruamoko/include/gui/Slider.h | 2 +- ruamoko/include/gui/Text.h | 2 +- ruamoko/include/gui/View.h | 4 ++-- ruamoko/include/key.h | 2 +- ruamoko/include/msgbuf.h | 2 +- ruamoko/include/plist.h | 2 +- ruamoko/include/qfs.h | 2 +- ruamoko/include/qw_message.h | 2 +- ruamoko/lib/Array.r | 6 +++--- ruamoko/lib/AutoreleasePool.r | 5 ++--- ruamoko/lib/Entity.r | 12 ++++++------ ruamoko/lib/Makefile.am | 5 ++++- ruamoko/lib/Object.r | 4 ++-- ruamoko/lib/PropertyList.r | 2 +- ruamoko/lib/Protocol.r | 2 +- ruamoko/lib/Set.r | 2 +- ruamoko/lib/cbuf.r | 2 +- ruamoko/lib/cmd.r | 2 +- ruamoko/lib/crudefile.r | 2 +- ruamoko/lib/cvar.r | 2 +- ruamoko/lib/debug.r | 2 +- ruamoko/lib/draw.r | 2 +- ruamoko/lib/entities.r | 2 +- ruamoko/lib/gib.r | 2 +- ruamoko/lib/hash.r | 2 +- ruamoko/lib/infokey.r | 2 +- ruamoko/lib/key.r | 2 +- ruamoko/lib/math.r | 2 +- ruamoko/lib/message.r | 2 +- ruamoko/lib/msgbuf.r | 2 +- ruamoko/lib/nq_message.r | 2 +- ruamoko/lib/physics.r | 2 +- ruamoko/lib/plist.r | 2 +- ruamoko/lib/qfile.r | 2 +- ruamoko/lib/qfs.r | 2 +- ruamoko/lib/qw_message.r | 2 +- ruamoko/lib/qw_physics.r | 2 +- ruamoko/lib/qw_sys.r | 2 +- ruamoko/lib/script.r | 2 +- ruamoko/lib/server.r | 2 +- ruamoko/lib/sound.r | 2 +- ruamoko/lib/string.r | 2 +- ruamoko/lib/sv_sound.r | 2 +- ruamoko/lib/system.r | 2 +- 65 files changed, 100 insertions(+), 95 deletions(-) diff --git a/ruamoko/gui/Group.r b/ruamoko/gui/Group.r index 4bcccadf1..56b7303c7 100644 --- a/ruamoko/gui/Group.r +++ b/ruamoko/gui/Group.r @@ -1,6 +1,6 @@ -#include "gui/Group.h" -#include "gui/Point.h" -#include "Array.h" +#include +#include +#include @implementation Group diff --git a/ruamoko/gui/InputLine.r b/ruamoko/gui/InputLine.r index 781e56b78..e4fb8df8a 100644 --- a/ruamoko/gui/InputLine.r +++ b/ruamoko/gui/InputLine.r @@ -1,6 +1,6 @@ -#include "draw.h" -#include "gui/InputLine.h" -#include "gui/Rect.h" +#include +#include +#include inputline_t InputLine_Create (int lines, int size, int prompt) = #0; void InputLine_SetPos (inputline_t il, int x, int y) = #0; diff --git a/ruamoko/gui/Makefile.am b/ruamoko/gui/Makefile.am index e4866e856..91ac97245 100644 --- a/ruamoko/gui/Makefile.am +++ b/ruamoko/gui/Makefile.am @@ -4,7 +4,10 @@ pkglibdir=$(datarootdir)/qfcc/lib QFCC=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths -QCPPFLAGS=$(AM_CPPFLAGS) +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) RANLIB=touch diff --git a/ruamoko/gui/Pic.r b/ruamoko/gui/Pic.r index 89cf93950..748393cc5 100644 --- a/ruamoko/gui/Pic.r +++ b/ruamoko/gui/Pic.r @@ -1,6 +1,6 @@ -#include "draw.h" -#include "string.h" -#include "gui/Pic.h" +#include +#include +#include @implementation Pic -(id)init diff --git a/ruamoko/gui/Point.r b/ruamoko/gui/Point.r index c25c72000..91163087b 100644 --- a/ruamoko/gui/Point.r +++ b/ruamoko/gui/Point.r @@ -1,4 +1,4 @@ -#include "gui/Point.h" +#include Point makePoint (int x, int y) { diff --git a/ruamoko/gui/Rect.r b/ruamoko/gui/Rect.r index be1c69384..a7280cea3 100644 --- a/ruamoko/gui/Rect.r +++ b/ruamoko/gui/Rect.r @@ -1,7 +1,7 @@ -#include "Object.h" -#include "gui/Point.h" -#include "gui/Size.h" -#include "gui/Rect.h" +#include +#include +#include +#include Rect makeRect (int x, int y, int w, int h) { diff --git a/ruamoko/gui/Size.r b/ruamoko/gui/Size.r index d4565a33f..da1bf04a9 100644 --- a/ruamoko/gui/Size.r +++ b/ruamoko/gui/Size.r @@ -1,4 +1,4 @@ -#include "gui/Size.h" +#include Size makeSize (int width, int height) { diff --git a/ruamoko/gui/Slider.r b/ruamoko/gui/Slider.r index d43cdcf21..275a64de4 100644 --- a/ruamoko/gui/Slider.r +++ b/ruamoko/gui/Slider.r @@ -1,7 +1,7 @@ -#include "draw.h" +#include -#include "gui/Slider.h" -#include "gui/Rect.h" +#include +#include @implementation Slider diff --git a/ruamoko/gui/Text.r b/ruamoko/gui/Text.r index 731f661ce..6011273d8 100644 --- a/ruamoko/gui/Text.r +++ b/ruamoko/gui/Text.r @@ -1,6 +1,6 @@ -#include "gui/Text.h" -#include "string.h" -#include "draw.h" +#include +#include +#include @implementation Text - (id) init diff --git a/ruamoko/gui/View.r b/ruamoko/gui/View.r index 2accc4fe7..a83ebeb33 100644 --- a/ruamoko/gui/View.r +++ b/ruamoko/gui/View.r @@ -1,7 +1,7 @@ -#include "gui/Size.h" -#include "gui/Point.h" -#include "gui/Rect.h" -#include "gui/View.h" +#include +#include +#include +#include @implementation View diff --git a/ruamoko/include/Array.h b/ruamoko/include/Array.h index 8a9f91f36..113e466a9 100644 --- a/ruamoko/include/Array.h +++ b/ruamoko/include/Array.h @@ -1,8 +1,8 @@ #ifndef __ruamoko_Array_h #define __ruamoko_Array_h -#include "Object.h" -#include "runtime.h" +#include +#include /** The Array class is a general ordered collection class. diff --git a/ruamoko/include/AutoreleasePool.h b/ruamoko/include/AutoreleasePool.h index a02600c9e..c8202e0f0 100644 --- a/ruamoko/include/AutoreleasePool.h +++ b/ruamoko/include/AutoreleasePool.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_AutoreleasePool_h #define __ruamoko_AutoreleasePool_h -#include "Object.h" +#include @class Array; diff --git a/ruamoko/include/Entity.h b/ruamoko/include/Entity.h index 85f304efb..8ff0f568c 100644 --- a/ruamoko/include/Entity.h +++ b/ruamoko/include/Entity.h @@ -30,7 +30,7 @@ #ifndef __ruamoko_Entity_h #define __ruamoko_Entity_h -#include "Object.h" +#include @interface Entity: Object { diff --git a/ruamoko/include/Object.h b/ruamoko/include/Object.h index 23623ef06..475e0bec9 100644 --- a/ruamoko/include/Object.h +++ b/ruamoko/include/Object.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_Object_h #define __ruamoko_Object_h -#include "runtime.h" +#include @class Protocol; diff --git a/ruamoko/include/PropertyList.h b/ruamoko/include/PropertyList.h index 0f255cdfe..3deb99a2b 100644 --- a/ruamoko/include/PropertyList.h +++ b/ruamoko/include/PropertyList.h @@ -1,8 +1,8 @@ #ifndef __ruamoko_PropertyList_h #define __ruamoko_PropertyList_h -#include "plist.h" -#include "Object.h" +#include +#include @interface PLItem: Object { diff --git a/ruamoko/include/Protocol.h b/ruamoko/include/Protocol.h index 2894ee4fa..3d377ab75 100644 --- a/ruamoko/include/Protocol.h +++ b/ruamoko/include/Protocol.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_Protocol_h #define __ruamoko_Protocol_h -#include "Object.h" +#include struct obj_method_description { string name; diff --git a/ruamoko/include/draw.h b/ruamoko/include/draw.h index df4a1470f..ae868ff36 100644 --- a/ruamoko/include/draw.h +++ b/ruamoko/include/draw.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_draw_h #define __ruamoko_draw_h -#include "Object.h" +#include struct _qpic_t { int width; diff --git a/ruamoko/include/gui/Group.h b/ruamoko/include/gui/Group.h index f20cca09c..ccd4baa65 100644 --- a/ruamoko/include/gui/Group.h +++ b/ruamoko/include/gui/Group.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_gui_Group_h #define __ruamoko_gui_Group_h -#include "View.h" +#include /** \addtogroup gui */ ///@{ diff --git a/ruamoko/include/gui/InputLine.h b/ruamoko/include/gui/InputLine.h index 363cc0b8c..c0b14cfb4 100644 --- a/ruamoko/include/gui/InputLine.h +++ b/ruamoko/include/gui/InputLine.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_gui_InputLine_h #define __ruamoko_gui_InputLine_h -#include "View.h" +#include /** \defgroup inputline Low level intputline interface. \ingroup gui diff --git a/ruamoko/include/gui/Pic.h b/ruamoko/include/gui/Pic.h index 9ed9e3380..9bfe29fbc 100644 --- a/ruamoko/include/gui/Pic.h +++ b/ruamoko/include/gui/Pic.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_gui_Pic_h #define __ruamoko_gui_Pic_h -#include "gui/View.h" +#include /** \addtogroup gui */ ///@{ diff --git a/ruamoko/include/gui/Rect.h b/ruamoko/include/gui/Rect.h index 005ce4a70..d1432f460 100644 --- a/ruamoko/include/gui/Rect.h +++ b/ruamoko/include/gui/Rect.h @@ -1,8 +1,8 @@ #ifndef __ruamoko_gui_Rect_h #define __ruamoko_gui_Rect_h -#include "gui/Point.h" -#include "gui/Size.h" +#include +#include /** \addtogroup gui */ ///@{ diff --git a/ruamoko/include/gui/Slider.h b/ruamoko/include/gui/Slider.h index 66710d28e..99840af7e 100644 --- a/ruamoko/include/gui/Slider.h +++ b/ruamoko/include/gui/Slider.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_gui_Slider_h #define __ruamoko_gui_Slider_h -#include "View.h" +#include /** \addtogroup gui */ ///@{ diff --git a/ruamoko/include/gui/Text.h b/ruamoko/include/gui/Text.h index d5654d555..ef389bf9c 100644 --- a/ruamoko/include/gui/Text.h +++ b/ruamoko/include/gui/Text.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_gui_Text_h #define __ruamoko_gui_Text_h -#include "View.h" +#include /** \addtogroup gui */ ///@{ diff --git a/ruamoko/include/gui/View.h b/ruamoko/include/gui/View.h index c2a99e036..3cb51ee67 100644 --- a/ruamoko/include/gui/View.h +++ b/ruamoko/include/gui/View.h @@ -1,8 +1,8 @@ #ifndef __ruamoko_gui_View_h #define __ruamoko_gui_View_h -#include "Object.h" -#include "gui/Rect.h" +#include +#include /** \defgroup gui GUI goo for gooey chewing */ diff --git a/ruamoko/include/key.h b/ruamoko/include/key.h index bc7d04801..f3355b3d2 100644 --- a/ruamoko/include/key.h +++ b/ruamoko/include/key.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_key_h #define __ruamoko_key_h -#include "QF/keys.h" +#include @extern int Key_keydown (int keynum); @extern string Key_SetBinding (string imt, int keynum, string binding); diff --git a/ruamoko/include/msgbuf.h b/ruamoko/include/msgbuf.h index d26ba4de9..172d7338a 100644 --- a/ruamoko/include/msgbuf.h +++ b/ruamoko/include/msgbuf.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_msgbuf_h #define __ruamoko_msgbuf_h -#include "qfile.h" +#include struct msgbuf_s; typedef struct msgbuf_s msgbuf_t; diff --git a/ruamoko/include/plist.h b/ruamoko/include/plist.h index 949419ea9..4544e00ff 100644 --- a/ruamoko/include/plist.h +++ b/ruamoko/include/plist.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_plist_h #define __ruamoko_plist_h -#include "qfile.h" +#include typedef struct plitem_s *plitem_t; typedef enum {QFDictionary, QFArray, QFBinary, QFString} pltype_t; // possible types diff --git a/ruamoko/include/qfs.h b/ruamoko/include/qfs.h index 4a31154f9..379e29ad2 100644 --- a/ruamoko/include/qfs.h +++ b/ruamoko/include/qfs.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_qfs_h #define __ruamoko_qfs_h -#include "qfile.h" +#include struct _qfslist_t { int count; diff --git a/ruamoko/include/qw_message.h b/ruamoko/include/qw_message.h index 5bd7efb0d..60c8587d1 100644 --- a/ruamoko/include/qw_message.h +++ b/ruamoko/include/qw_message.h @@ -1,7 +1,7 @@ #ifndef __ruamoko_qw_message_h #define __ruamoko_qw_message_h -#include "message.h" +#include @extern void multicast (vector where, float set); diff --git a/ruamoko/lib/Array.r b/ruamoko/lib/Array.r index bbf5ce883..842076f72 100644 --- a/ruamoko/lib/Array.r +++ b/ruamoko/lib/Array.r @@ -1,7 +1,7 @@ -#include "math.h" +#include -#include "Array.h" -#include "runtime.h" +#include +#include #define STANDARD_CAPACITY 16 #define ARRAY_MAX_GRANULARITY 100 diff --git a/ruamoko/lib/AutoreleasePool.r b/ruamoko/lib/AutoreleasePool.r index 6d8077cfc..b4aadd36f 100644 --- a/ruamoko/lib/AutoreleasePool.r +++ b/ruamoko/lib/AutoreleasePool.r @@ -1,7 +1,6 @@ -#include "AutoreleasePool.h" -#include "Array+Private.h" +#include -#include "Array.h" +#include #include "Array+Private.h" @static Array *poolStack; diff --git a/ruamoko/lib/Entity.r b/ruamoko/lib/Entity.r index 5cc1f4f11..474bc3db1 100644 --- a/ruamoko/lib/Entity.r +++ b/ruamoko/lib/Entity.r @@ -1,10 +1,10 @@ -#include "Entity.h" +#include -#include "debug.h" -#include "entities.h" -#include "plist.h" -#include "script.h" -#include "string.h" +#include +#include +#include +#include +#include typedef void () void_function; diff --git a/ruamoko/lib/Makefile.am b/ruamoko/lib/Makefile.am index ee2c80ff7..525c20d6c 100644 --- a/ruamoko/lib/Makefile.am +++ b/ruamoko/lib/Makefile.am @@ -4,7 +4,10 @@ pkglibdir=$(datarootdir)/qfcc/lib QFCC=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QCFLAGS=-qq -O -g -Wall -Wno-integer-divide -Werror --no-default-paths -QCPPFLAGS=$(AM_CPPFLAGS) +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) RANLIB=touch diff --git a/ruamoko/lib/Object.r b/ruamoko/lib/Object.r index a6b0e9d85..dba6b5071 100644 --- a/ruamoko/lib/Object.r +++ b/ruamoko/lib/Object.r @@ -1,5 +1,5 @@ -#include "Object.h" -#include "AutoreleasePool.h" +#include +#include void *PR_FindGlobal (string name) = #0; //FIXME where? diff --git a/ruamoko/lib/PropertyList.r b/ruamoko/lib/PropertyList.r index 0bcfa9850..b65edc85d 100644 --- a/ruamoko/lib/PropertyList.r +++ b/ruamoko/lib/PropertyList.r @@ -1,4 +1,4 @@ -#include "PropertyList.h" +#include @implementation PLItem diff --git a/ruamoko/lib/Protocol.r b/ruamoko/lib/Protocol.r index 715ca30a7..8893d13bb 100644 --- a/ruamoko/lib/Protocol.r +++ b/ruamoko/lib/Protocol.r @@ -1,4 +1,4 @@ -#include "Protocol.h" +#include struct obj_protocol_list { struct obj_protocol_list *next; diff --git a/ruamoko/lib/Set.r b/ruamoko/lib/Set.r index 06ef95193..9e215ec51 100644 --- a/ruamoko/lib/Set.r +++ b/ruamoko/lib/Set.r @@ -1,4 +1,4 @@ -#include "Set.h" +#include void set_del_iter (set_iter_t *set_iter) = #0; set_t *set_new (void) = #0; diff --git a/ruamoko/lib/cbuf.r b/ruamoko/lib/cbuf.r index 496585fd5..f22498f3c 100644 --- a/ruamoko/lib/cbuf.r +++ b/ruamoko/lib/cbuf.r @@ -1,4 +1,4 @@ -#include "cbuf.h" +#include void (string text) Cbuf_AddText = #0; void (string text) Cbuf_InsertText = #0; diff --git a/ruamoko/lib/cmd.r b/ruamoko/lib/cmd.r index 2ecb6d100..ba86632f8 100644 --- a/ruamoko/lib/cmd.r +++ b/ruamoko/lib/cmd.r @@ -1,4 +1,4 @@ -#include "cmd.h" +#include void (string name, void () func) Cmd_AddCommand = #0; int () Cmd_Argc = #0; diff --git a/ruamoko/lib/crudefile.r b/ruamoko/lib/crudefile.r index c8d4b9e27..2987af452 100644 --- a/ruamoko/lib/crudefile.r +++ b/ruamoko/lib/crudefile.r @@ -1,4 +1,4 @@ -#include "crudefile.h" +#include float (string path, string mode) cfopen = #0x000f0000 + 103; void (float desc) cfclose = #0x000f0000 + 104; diff --git a/ruamoko/lib/cvar.r b/ruamoko/lib/cvar.r index 168c38e18..be12b212e 100644 --- a/ruamoko/lib/cvar.r +++ b/ruamoko/lib/cvar.r @@ -1,4 +1,4 @@ -#include "cvar.h" +#include float (string s) cvar = #45; void (string var, string val) cvar_set = #72; diff --git a/ruamoko/lib/debug.r b/ruamoko/lib/debug.r index 844c88eff..7cf9c8895 100644 --- a/ruamoko/lib/debug.r +++ b/ruamoko/lib/debug.r @@ -1,4 +1,4 @@ -#include "debug.h" +#include void abort (void) = #6; void coredump (void) = #28; diff --git a/ruamoko/lib/draw.r b/ruamoko/lib/draw.r index 741857bf5..5aef3ab75 100644 --- a/ruamoko/lib/draw.r +++ b/ruamoko/lib/draw.r @@ -1,4 +1,4 @@ -#include "draw.h" +#include void Draw_FreePic (qpic_t pic) = #0; qpic_t Draw_MakePic (int width, int heiight, string data) = #0; diff --git a/ruamoko/lib/entities.r b/ruamoko/lib/entities.r index f55bd91a7..f49cc9a53 100644 --- a/ruamoko/lib/entities.r +++ b/ruamoko/lib/entities.r @@ -1,4 +1,4 @@ -#include "entities.h" +#include void setmodel (entity e, string m) = #3; void setorigin (entity e, vector o) = #2; diff --git a/ruamoko/lib/gib.r b/ruamoko/lib/gib.r index c3fead7b1..26baacd2f 100644 --- a/ruamoko/lib/gib.r +++ b/ruamoko/lib/gib.r @@ -1,4 +1,4 @@ -#include "gib.h" +#include void GIB_Builtin_Add (string name, void func (int argc, string *argv)) = #0; int (string value) GIB_Return = #0; diff --git a/ruamoko/lib/hash.r b/ruamoko/lib/hash.r index a70d59b10..120d140f9 100644 --- a/ruamoko/lib/hash.r +++ b/ruamoko/lib/hash.r @@ -1,4 +1,4 @@ -#include "hash.h" +#include hashtab_t *Hash_NewTable (int size, string gk (void *ele, void *data), void f (void *ele, void *data), void *ud) = #0; void Hash_SetHashCompare (hashtab_t *tab, unsigned gh (void *ele, void *data), int cmp (void *ele1, void *ele2, void *data)) = #0; diff --git a/ruamoko/lib/infokey.r b/ruamoko/lib/infokey.r index d0049a4fd..a2913df18 100644 --- a/ruamoko/lib/infokey.r +++ b/ruamoko/lib/infokey.r @@ -1,4 +1,4 @@ -#include "infokey.h" +#include string (entity e, string key) infokey = #80; void (entity ent, string key, string value) setinfokey = #0x000f0000 + 102; diff --git a/ruamoko/lib/key.r b/ruamoko/lib/key.r index 19662f138..4b8c1a09a 100644 --- a/ruamoko/lib/key.r +++ b/ruamoko/lib/key.r @@ -1,4 +1,4 @@ -#include "key.h" +#include int Key_keydown (int keynum) = #0; string (string imt, int keynum, string binding) Key_SetBinding = #0; diff --git a/ruamoko/lib/math.r b/ruamoko/lib/math.r index 80db2b710..47624527a 100644 --- a/ruamoko/lib/math.r +++ b/ruamoko/lib/math.r @@ -1,4 +1,4 @@ -#include "math.h" +#include vector v_forward, v_up, v_right; diff --git a/ruamoko/lib/message.r b/ruamoko/lib/message.r index 3136cd678..4ddb31571 100644 --- a/ruamoko/lib/message.r +++ b/ruamoko/lib/message.r @@ -1,4 +1,4 @@ -#include "message.h" +#include void (...) bprint = #23; void (entity client, string s) sprint = #24; diff --git a/ruamoko/lib/msgbuf.r b/ruamoko/lib/msgbuf.r index c1352a43e..1bd4e09b1 100644 --- a/ruamoko/lib/msgbuf.r +++ b/ruamoko/lib/msgbuf.r @@ -1,4 +1,4 @@ -#include "msgbuf.h" +#include msgbuf_t *MsgBuf_New (int size) = #0; void MsgBuf_Delete (msgbuf_t *msgbuf) = #0; diff --git a/ruamoko/lib/nq_message.r b/ruamoko/lib/nq_message.r index 14c06827a..223d1c604 100644 --- a/ruamoko/lib/nq_message.r +++ b/ruamoko/lib/nq_message.r @@ -1,3 +1,3 @@ -#include "nq_message.h" +#include void (vector o, vector d, float color, float count) particle = #48; diff --git a/ruamoko/lib/physics.r b/ruamoko/lib/physics.r index ca19e052f..b42585d00 100644 --- a/ruamoko/lib/physics.r +++ b/ruamoko/lib/physics.r @@ -1,4 +1,4 @@ -#include "physics.h" +#include float trace_allsolid; float trace_startsolid; diff --git a/ruamoko/lib/plist.r b/ruamoko/lib/plist.r index 4b01c653b..40ab2e1fc 100644 --- a/ruamoko/lib/plist.r +++ b/ruamoko/lib/plist.r @@ -1,4 +1,4 @@ -#include "plist.h" +#include plitem_t PL_GetFromFile (QFile file) = #0; plitem_t PL_GetPropertyList (string str) = #0; diff --git a/ruamoko/lib/qfile.r b/ruamoko/lib/qfile.r index 072d72a1c..487beb5c5 100644 --- a/ruamoko/lib/qfile.r +++ b/ruamoko/lib/qfile.r @@ -1,4 +1,4 @@ -#include "qfile.h" +#include int Qrename (string old, string new) = #0; int Qremove (string path) = #0; diff --git a/ruamoko/lib/qfs.r b/ruamoko/lib/qfs.r index b0632d030..d467b09ce 100644 --- a/ruamoko/lib/qfs.r +++ b/ruamoko/lib/qfs.r @@ -1,4 +1,4 @@ -#include "qfs.h" +#include QFile QFS_Open (string path, string mode) = #0; QFile QFS_WOpen (string path, int zip) = #0; diff --git a/ruamoko/lib/qw_message.r b/ruamoko/lib/qw_message.r index fcc714c37..218db52cd 100644 --- a/ruamoko/lib/qw_message.r +++ b/ruamoko/lib/qw_message.r @@ -1,3 +1,3 @@ -#include "qw_message.h" +#include void (vector where, float set) multicast = #82; diff --git a/ruamoko/lib/qw_physics.r b/ruamoko/lib/qw_physics.r index 431e97e63..0ff633569 100644 --- a/ruamoko/lib/qw_physics.r +++ b/ruamoko/lib/qw_physics.r @@ -1,4 +1,4 @@ -#include "qw_physics.h" +#include entity (entity ent) testentitypos = #0x000f0000 + 92; void (vector start, vector mins, vector maxs, vector end, float type, entity passent) checkmove = #0x000f0000 + 98; diff --git a/ruamoko/lib/qw_sys.r b/ruamoko/lib/qw_sys.r index 8d8643576..529f42947 100644 --- a/ruamoko/lib/qw_sys.r +++ b/ruamoko/lib/qw_sys.r @@ -1,3 +1,3 @@ -#include "qw_sys.h" +#include void (entity killer, entity killee) logfrag = #79; diff --git a/ruamoko/lib/script.r b/ruamoko/lib/script.r index 74c120075..e72c4b72a 100644 --- a/ruamoko/lib/script.r +++ b/ruamoko/lib/script.r @@ -1,4 +1,4 @@ -#include "script.h" +#include script_t Script_New (void) = #0; void Script_Delete (script_t script) = #0; diff --git a/ruamoko/lib/server.r b/ruamoko/lib/server.r index 42bd99eb5..b65c3ac7d 100644 --- a/ruamoko/lib/server.r +++ b/ruamoko/lib/server.r @@ -1,4 +1,4 @@ -#include "server.h" +#include void (string s) precache_sound = #19; void (string s) precache_model = #20; diff --git a/ruamoko/lib/sound.r b/ruamoko/lib/sound.r index 863800c81..000ef7047 100644 --- a/ruamoko/lib/sound.r +++ b/ruamoko/lib/sound.r @@ -1,3 +1,3 @@ -#include "sound.h" +#include void (string sound) S_LocalSound = #0; diff --git a/ruamoko/lib/string.r b/ruamoko/lib/string.r index f7eda6b48..36247bf91 100644 --- a/ruamoko/lib/string.r +++ b/ruamoko/lib/string.r @@ -1,4 +1,4 @@ -#include "string.h" +#include string (float f) ftos = #26; string (vector v) vtos = #27; diff --git a/ruamoko/lib/sv_sound.r b/ruamoko/lib/sv_sound.r index 7880c6b1b..cd4b4f43e 100644 --- a/ruamoko/lib/sv_sound.r +++ b/ruamoko/lib/sv_sound.r @@ -1,4 +1,4 @@ -#include "sound.h" +#include void (entity e, float chan, string samp, float vol, float atten) sound = #8; void (vector pos, string samp, float vol, float atten) ambientsound = #74; diff --git a/ruamoko/lib/system.r b/ruamoko/lib/system.r index 1a387f890..753a41d99 100644 --- a/ruamoko/lib/system.r +++ b/ruamoko/lib/system.r @@ -1,4 +1,4 @@ -#include "system.h" +#include float time; From 6def1fc01c8ac8adafc01c049062a3179b13b698 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 15:26:33 +0900 Subject: [PATCH 175/444] [qfcc] Fix a bootstrap warning --- tools/qfcc/test/Makefile.am | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index 937686a6e..129240670 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -364,14 +364,14 @@ triangle.run: Makefile build-run include ./$(DEPDIR)/triangle.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/triangle.Qo -typedef_dat_SOURCES=typedef.r -typedef_obj=$(typedef_dat_SOURCES:.r=.qfo) -typedef.dat$(EXEEXT): $(typedef_obj) $(QFCC_DEP) - $(QFCC) $(QCFLAGS) -o $@ $(typedef_obj) -typedef.run: Makefile build-run - @$(srcdir)/build-run $@ -include ./$(DEPDIR)/typedef.Qo # am--include-marker -r_depfiles_remade += ./$(DEPDIR)/typedef.Qo +#typedef_dat_SOURCES=typedef.r +#typedef_obj=$(typedef_dat_SOURCES:.r=.qfo) +#typedef.dat$(EXEEXT): $(typedef_obj) $(QFCC_DEP) +# $(QFCC) $(QCFLAGS) -o $@ $(typedef_obj) +#typedef.run: Makefile build-run +# @$(srcdir)/build-run $@ +#include ./$(DEPDIR)/typedef.Qo # am--include-marker +#r_depfiles_remade += ./$(DEPDIR)/typedef.Qo vecexpr_dat_SOURCES=vecexpr.r vecexpr_obj=$(vecexpr_dat_SOURCES:.r=.qfo) From 051a572bcc28ef59e847960638c55613e48c6529 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 17:24:53 +0900 Subject: [PATCH 176/444] [build] Dependency checking for all ruamoko code Including dependency on qfcc itself. Getting automake to chooch the way I want it to chooch can be a pain in the... see AvE --- ruamoko/cl_menu/Makefile.am | 67 ++++++++++++++++-------- ruamoko/game/Makefile.am | 62 +++++++++++++++------- ruamoko/gui/Makefile.am | 36 +++++++++---- ruamoko/lib/Makefile.am | 98 ++++++++++++++++++++++++---------- ruamoko/scheme/Makefile.am | 101 +++++++++++++++++++++--------------- 5 files changed, 244 insertions(+), 120 deletions(-) diff --git a/ruamoko/cl_menu/Makefile.am b/ruamoko/cl_menu/Makefile.am index 55c21a857..ceaef7fe5 100644 --- a/ruamoko/cl_menu/Makefile.am +++ b/ruamoko/cl_menu/Makefile.am @@ -1,43 +1,66 @@ ## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -pkgdatadir=@sharepath@/QF +AUTOMAKE_OPTIONS= foreign no-exeext QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g -Wall -Werror -Wno-integer-divide --no-default-paths -QCPPFLAGS=-I. -I$(srcdir) -I$(top_builddir)/ruamoko/include -I$(top_srcdir)/ruamoko/include -I$(top_builddir)/include -I$(top_srcdir)/include -GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi + GZ=@progs_gz@ +menu_libexec=menu.dat +menu_data=menu.plist menu.sym + +pkglibexecdir=@sharepath@/QF +pkgdatadir=@sharepath@/QF + +pkgdata_DATA= $(menu_data) +pkglibexec_PROGRAMS= $(menu_libexec) +EXTRA_PROGRAMS= $(menu_libexec) + +QCFLAGS=-qq -O -g -Wall -Werror -Wno-integer-divide +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +MKDIR_P = @MKDIR_P@ +am__mv = mv -f + +GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi # BSD make can't handle $(shell foo) directives, and GNU make can't handle |= # so we have to bite the bullet and pass this to the shell every time. STRIP=`echo -n $(srcdir)/ | sed -e 's/[^/]//g' | wc -c` -menu_data=menu.dat$(GZ) menu.sym$(GZ) menu.plist - -data=$(menu_data) - -pkgdata_DATA= $(data) -EXTRA_DATA= $(menu_data) +SUFFIXES=.o .r +.r.o: + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -p $(STRIP) -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo menu_src= \ client_menu.r controls_o.r options.r options_util.r servlist.r \ - Frame.r menu.r HUD.r plistmenu.r ../lib/debug.r \ + Frame.r HUD.r menu.r plistmenu.r \ \ CrosshairCvar.r CrosshairView.r CvarColor.r CvarColorView.r \ CvarObject.r CvarRange.r CvarRangeView.r CvarString.r CvarStringView.r \ CvarToggle.r CvarToggleView.r \ MenuGroup.r MouseToggle.r ProxyView.r RunToggle.r SubMenu.r -SUFFIXES=.qfo .r -.r.qfo: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< -menu_obj=$(menu_src:.r=.qfo) +r_depfiles_remade= -menu.dat$(GZ): $(menu_obj) $(QFCC_DEP) ../lib/libcsqc.a ../lib/libr.a ../gui/libgui.a - $(QFCC) $(QCFLAGS) -p $(STRIP) -o menu.dat $(menu_obj) ../gui/libgui.a ../lib/libcsqc.a ../lib/libr.a - $(GZIP) -menu.sym$(GZ): menu.dat$(GZ) +menu_dat_SOURCES=$(menu_src) +menu_obj=$(menu_src:.r=.o) +menu_dep=$(addprefix ./$(DEPDIR)/,$(menu_obj:.o=.Qo)) +menu.dat: $(menu_obj) $(QFCC_DEP) ../lib/libcsqc.a ../lib/libr.a ../gui/libgui.a + $(QLINK) -p $(STRIP) -o menu.dat $(menu_obj) ../gui/libgui.a ../lib/libcsqc.a ../lib/libr.a +include $(menu_dep) # am--include-marker +r_depfiles_remade += $(menu_dep) + +menu.sym: menu.dat + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) EXTRA_DIST= $(menu_src) \ CrosshairCvar.h CrosshairView.h CvarColor.h CvarColorView.h CvarObject.h \ @@ -46,4 +69,4 @@ EXTRA_DIST= $(menu_src) \ MenuGroup.h MouseToggle.h ProxyView.h RunToggle.h SubMenu.h client_menu.h \ controls_o.h menu.h options.h options_util.h plistmenu.h servlist.h \ menu.plist -CLEANFILES= *.dat *.sym *.gz *.qfo +CLEANFILES= *.dat *.sym *.gz *.qfo *.o diff --git a/ruamoko/game/Makefile.am b/ruamoko/game/Makefile.am index e1ff2fbf2..95093647f 100644 --- a/ruamoko/game/Makefile.am +++ b/ruamoko/game/Makefile.am @@ -1,35 +1,57 @@ ## Process this file with automake to produce Makefile.in -AUTOMAKE_OPTIONS= foreign - -#FIXME should qf data be installed somewhere other than id1 that gets -#searched after everything else? -pkgdatadir=@sharepath@/id1 +AUTOMAKE_OPTIONS= foreign no-exeext QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths -QCPPFLAGS=-I. -I$(srcdir) -I$(top_builddir)/ruamoko/include -I$(top_srcdir)/ruamoko/include -GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi + GZ=@progs_gz@ +game_libexec=game.dat + +pkglibexecdir=@sharepath@/QF + +# this will eventually go into pkglibexecdir, but for now... +noinst_PROGRAMS= $(game_libexec) +EXTRA_PROGRAMS= $(game_libexec) + +QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +MKDIR_P = @MKDIR_P@ +am__mv = mv -f + +GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi # BSD make can't handle $(shell foo) directives, and GNU make can't handle |= # so we have to bite the bullet and pass this to the shell every time. STRIP=`echo -n $(srcdir)/ | sed -e 's/[^/]//g' | wc -c` -data=game.dat$(GZ) - -noinst_DATA= $(data) -EXTRA_DATA= game.dat +SUFFIXES=.o .r +.r.o: + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -p $(STRIP) -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo game_src= Axe.r GameEntity.r World.r tempent.r -SUFFIXES=.qfo .r -.r.qfo: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< +r_depfiles_remade= -game_obj=$(game_src:.r=.qfo) -game.dat$(GZ): $(game_obj) ../lib/libr.a ../lib/libqw.a - $(QFCC) $(QCFLAGS) -p $(STRIP) -o game.dat $(game_obj) ../lib/libr.a ../lib/libqw.a ../lib/libr.a - $(GZIP) +game_dat_SOURCES=$(game_src) +game_obj=$(game_src:.r=.o) +game_dep=$(addprefix ./$(DEPDIR)/,$(game_obj:.o=.Qo)) +game.dat: $(game_obj) $(QFCC_DEP) ../lib/libr.a ../lib/libqw.a + $(QLINK) -p $(STRIP) -o game.dat $(game_obj) ../lib/libr.a ../lib/libqw.a ../lib/libr.a +include $(game_dep) # am--include-marker +r_depfiles_remade += $(game_dep) + +game.sym: game.dat + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) EXTRA_DIST= $(game_src) Axe.h GameEntity.h tempent.h Weapon.h World.h -CLEANFILES= *.dat *.sym *.gz *.qfo +CLEANFILES= *.dat *.sym *.gz *.o *.qfo diff --git a/ruamoko/gui/Makefile.am b/ruamoko/gui/Makefile.am index 91ac97245..35d2624df 100644 --- a/ruamoko/gui/Makefile.am +++ b/ruamoko/gui/Makefile.am @@ -1,30 +1,48 @@ AUTOMAKE_OPTIONS= foreign +QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) +QFCC=$(QFCC_DEP) + +gui_libs=libgui.a +libs=$(gui_libs) + pkglibdir=$(datarootdir)/qfcc/lib +pkglib_LIBRARIES= $(libs) +EXTRA_LIBRARIES= $(gui_libs) + QFCC=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +MKDIR_P = @MKDIR_P@ +am__mv = mv -f + PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) RANLIB=touch -AM_CPPFLAGS= -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include - -gui_libs=libgui.a -libs=$(gui_libs) - -pkglib_LIBRARIES= $(libs) -EXTRA_LIBRARIES= $(gui_libs) - -SUFFIXES= .qfo .r .qc +SUFFIXES= .o .r .r.o: $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $< +r_depfiles_remade= + libgui_a_SOURCES= \ Group.r InputLine.r Pic.r Point.r Rect.r Size.r Slider.r Text.r View.r +libgui_a_obj=$(libgui_a_SOURCES:.r=.o) +libgui_a_dep=$(addprefix ./$(DEPDIR)/,$(libgui_a_obj:.o=.Qo)) libgui_a_AR= $(PAK) -cf +include $(libgui_a_dep) # am--include-marker +r_depfiles_remade += $(libgui_a_dep) + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) + CLEANFILES= *.qfo *.o diff --git a/ruamoko/lib/Makefile.am b/ruamoko/lib/Makefile.am index 525c20d6c..8a66a3839 100644 --- a/ruamoko/lib/Makefile.am +++ b/ruamoko/lib/Makefile.am @@ -1,53 +1,95 @@ AUTOMAKE_OPTIONS= foreign -pkglibdir=$(datarootdir)/qfcc/lib - -QFCC=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) -QCFLAGS=-qq -O -g -Wall -Wno-integer-divide -Werror --no-default-paths -QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include -QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib -QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) -QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) -PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) -RANLIB=touch - -AM_CPPFLAGS= -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include - -noinst_HEADERS= \ - Array+Private.h +QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) +QFCC=$(QFCC_DEP) ruamoko_libs=libr.a libqw.a libnq.a libcsqc.a libs=$(ruamoko_libs) +pkglibdir=$(datarootdir)/qfcc/lib + pkglib_LIBRARIES= $(libs) EXTRA_LIBRARIES= $(ruamoko_libs) -SUFFIXES= .o .r .qc +noinst_HEADERS= \ + Array+Private.h + +QCFLAGS=-qq -O -g -Wall -Wno-integer-divide -Werror +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +MKDIR_P = @MKDIR_P@ +am__mv = mv -f + +PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) +RANLIB=touch + +SUFFIXES= .o .r .r.o: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $< -.qc.o: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -c -o $@ $< + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -p $(STRIP) -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo + +r_depfiles_remade= libr_a_SOURCES=\ cbuf.r cmd.r cvar.r hash.r msgbuf.r plist.r qfile.r qfs.r script.r \ sound.r string.r math.r types.r \ Object.r Protocol.r \ AutoreleasePool.r Array.r Array+Private.r Entity.r PropertyList.r Set.r +libr_a_obj=$(libr_a_SOURCES:.r=.o) +libr_a_dep=$(addprefix ./$(DEPDIR)/,$(libr_a_obj:.o=.Qo)) libr_a_AR=$(PAK) -cf +include $(libr_a_dep) # am--include-marker +r_depfiles_remade += $(libr_a_dep) -libqw_a_SOURCES=\ - crudefile.r debug.r entities.r infokey.r math.r message.r \ - physics.r qw_message.r qw_physics.r qw_sys.r \ - server.r sv_sound.r system.r +common_src=debug.r system.r +server_src= \ + crudefile.r entities.r infokey.r message.r \ + physics.r server.r sv_sound.r +libqw_a_src= \ + qw_message.r qw_physics.r qw_sys.r +libnq_a_src= \ + nq_message.r +libcsqc_a_src= draw.r gib.r key.r + +common_obj=$(common_src:.r=.o) +common_dep=$(addprefix ./$(DEPDIR)/,$(common_obj:.o=.Qo)) +include $(common_dep) # am--include-marker +r_depfiles_remade += $(common_dep) + +server_obj=$(server_src:.r=.o) +server_dep=$(addprefix ./$(DEPDIR)/,$(server_obj:.o=.Qo)) +include $(server_dep) # am--include-marker +r_depfiles_remade += $(server_dep) + +libqw_a_SOURCES=$(libqw_a_src) $(common_src) $(server_src) math.r +libqw_a_obj=$(libqw_a_src:.r=.o) +libqw_a_dep=$(addprefix ./$(DEPDIR)/,$(libqw_a_obj:.o=.Qo)) libqw_a_AR=$(PAK) -cf +include $(libqw_a_dep) # am--include-marker +r_depfiles_remade += $(libqw_a_dep) -libnq_a_SOURCES=\ - crudefile.r debug.r entities.r infokey.r math.r message.r \ - nq_message.r physics.r server.r sv_sound.r system.r +libnq_a_SOURCES=$(libnq_a_src) $(common_src) $(server_src) math.r +libnq_a_obj=$(libnq_a_src:.r=.o) +libnq_a_dep=$(addprefix ./$(DEPDIR)/,$(libnq_a_obj:.o=.Qo)) libnq_a_AR=$(PAK) -cf +include $(libnq_a_dep) # am--include-marker +r_depfiles_remade += $(libnq_a_dep) -libcsqc_a_SOURCES= \ - debug.r draw.r gib.r key.r system.r +libcsqc_a_SOURCES=$(libcsqc_a_src) $(common_src) +libcsqc_a_obj=$(libcsqc_a_src:.r=.o) +libcsqc_a_dep=$(addprefix ./$(DEPDIR)/,$(libcsqc_a_obj:.o=.Qo)) libcsqc_a_AR= $(PAK) -cf +include $(libcsqc_a_dep) # am--include-marker +r_depfiles_remade += $(libcsqc_a_dep) + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) CLEANFILES= *.qfo *.o diff --git a/ruamoko/scheme/Makefile.am b/ruamoko/scheme/Makefile.am index 75f784ef5..f62c36191 100644 --- a/ruamoko/scheme/Makefile.am +++ b/ruamoko/scheme/Makefile.am @@ -1,30 +1,75 @@ -AUTOMAKE_OPTIONS= foreign - -pkglibdir=$(datarootdir)/qfcc/lib +AUTOMAKE_OPTIONS= foreign no-exeext QFCC_DEP=$(top_builddir)/tools/qfcc/source/qfcc$(EXEEXT) QFCC=$(QFCC_DEP) -QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide --no-default-paths -QCPPFLAGS=$(AM_CPPFLAGS) + +GZ=@progs_gz@ +scheme_libs=libscheme.a +scheme_libexec=main.dat + +pkglibdir=$(datarootdir)/qfcc/lib +#FIXME where to put pkglibexec? +#pkglibexecdir=$(datarootdir)/qfcc/bin + +pkglib_LIBRARIES= $(scheme_libs) +EXTRA_LIBRARIES= $(scheme_libs) + +noinst_PROGRAMS= $(scheme_libexec) +EXTRA_PROGRAMS = $(scheme_libexec) + +QCFLAGS=-qq -O -g -Werror -Wall -Wno-integer-divide +QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include +QCLINKFLAGS=--no-default-paths -L$(top_builddir)/ruamoko/lib +QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) +QLINK=$(QFCC) $(QCFLAGS) $(QCLINKFLAGS) + +MKDIR_P = @MKDIR_P@ +am__mv = mv -f + PAK=$(top_builddir)/tools/pak/pak$(EXEEXT) GZIP=if echo $@ | grep -q .gz; then gzip -f `basename $@ .gz`; if test -f `basename $@ .dat.gz`.sym; then gzip -f `basename $@ .dat.gz`.sym; fi; fi -GZ=@progs_gz@ # BSD make can't handle $(shell foo) directives, and GNU make can't handle |= # so we have to bite the bullet and pass this to the shell every time. STRIP=`echo -n $(srcdir)/ | sed -e 's/[^/]//g' | wc -c` - RANLIB=touch -AM_CPPFLAGS= -I$(top_srcdir)/ruamoko/include -I$(top_srcdir)/include +SUFFIXES=.o .r +.r.o: + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -p $(STRIP) -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo -scheme_libs=libscheme.a -libs=$(scheme_libs) -data=$(scheme_data) +r_depfiles_remade= -pkglib_LIBRARIES= $(libs) -EXTRA_LIBRARIES= $(scheme_libs) -#pkgdata_DATA= $(data) -EXTRA_DATA = $(scheme_data) +libscheme_a_SOURCES=\ + SchemeObject.r Cons.r Number.r SchemeString.r Symbol.r Lexer.r Parser.r \ + Nil.r Procedure.r Primitive.r Lambda.r Scope.r Instruction.r builtins.r \ + Frame.r CompiledCode.r Compiler.r Continuation.r Machine.r Void.r \ + Error.r Boolean.r BaseContinuation.r +libscheme_a_obj=$(libscheme_a_SOURCES:.r=.o) +libscheme_a_dep=$(addprefix ./$(DEPDIR)/,$(libscheme_a_obj:.o=.Qo)) +libscheme_a_AR=$(PAK) -cf +include $(libscheme_a_dep) # am--include-marker +r_depfiles_remade += $(libscheme_a_dep) + +scheme_src=\ + main.r defs.r + +main_dat_SOURCES=$(scheme_src) +main_obj=$(scheme_src:.r=.o) +main_dep=$(addprefix ./$(DEPDIR)/,$(main_obj:.o=.Qo)) +main.dat: $(main_obj) $(QFCC_DEP) libscheme.a ../lib/libcsqc.a ../lib/libr.a + $(QLINK) -p $(STRIP) -o main.dat $(main_obj) libscheme.a ../lib/libcsqc.a ../lib/libr.a +include $(main_dep) # am--include-marker +r_depfiles_remade += $(main_dep) + +main.sym: main.dat + +$(r_depfiles_remade): + $(MKDIR_P) $(@D) + echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) EXTRA_DIST = \ BaseContinuation.h Boolean.h CompiledCode.h Compiler.h Cons.h \ @@ -34,30 +79,4 @@ EXTRA_DIST = \ debug.h defs.h state.h \ \ main.r defs.r - -SUFFIXES=.qc .qfo .r -.r.qfo: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< -.r.o: - $(QFCC) $(QCFLAGS) $(QCPPFLAGS) -p $(STRIP) -c -o $@ $< - -libscheme_a_SOURCES=\ - SchemeObject.r Cons.r Number.r SchemeString.r Symbol.r Lexer.r Parser.r \ - Nil.r Procedure.r Primitive.r Lambda.r Scope.r Instruction.r builtins.r \ - Frame.r CompiledCode.r Compiler.r Continuation.r Machine.r Void.r \ - Error.r Boolean.r BaseContinuation.r -libscheme_a_AR=$(PAK) -cf - -scheme_data=\ - main.dat$(GZ) - -scheme_src=\ - main.r defs.r - -scheme_obj=$(scheme_src:.qc=.o) - -main.dat$(GZ): $(scheme_obj) $(QFCC_DEP) ../lib/libcsqc.a ../lib/libr.a libscheme.a - $(QFCC) $(QCFLAGS) -p $(STRIP) -o main.dat $(scheme_obj) libscheme.a ../lib/libcsqc.a ../lib/libr.a - $(GZIP) - CLEANFILES= *.dat *.sym *.gz *.qfo *.o From b186332da0ca011a1e7c296cb5482890b122cfd9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 17:32:48 +0900 Subject: [PATCH 177/444] [qfcc] Make initialization of external vars an error --- tools/qfcc/source/def.c | 4 ++-- tools/qfcc/source/qc-parse.y | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 82e88c5ae..c0332be60 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -575,7 +575,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, internal_error (0, "half defined var"); if (storage == sc_extern) { if (init) - warning (0, "initializing external variable"); + error (0, "initializing external variable"); return; } if (init && check->s.def->initialized) { @@ -611,7 +611,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, init_field_def (sym->s.def, init, storage); if (storage == sc_extern) { if (init) - warning (0, "initializing external variable"); + error (0, "initializing external variable"); return; } if (!init) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 7ae13bd6e..3fac0f926 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1021,6 +1021,9 @@ overloaded_identifier non_code_func : '=' '#' expr { + if ($-1.storage == sc_extern) { + error (0, "initializing external variable"); + } build_builtin_function ($0, $3, 0); } | '=' expr From 7976eec2ce6b2e099ad7e020459298c566ba5170 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 17:35:14 +0900 Subject: [PATCH 178/444] [scheme] Clean up a pile of rotten bits --- ruamoko/scheme/SchemeObject.h | 1 + ruamoko/scheme/defs.h | 22 +++++++++++----------- ruamoko/scheme/defs.r | 2 +- ruamoko/scheme/main.r | 35 +++++++++++++++++++---------------- 4 files changed, 32 insertions(+), 28 deletions(-) diff --git a/ruamoko/scheme/SchemeObject.h b/ruamoko/scheme/SchemeObject.h index 262c700f4..e831b50bd 100644 --- a/ruamoko/scheme/SchemeObject.h +++ b/ruamoko/scheme/SchemeObject.h @@ -14,6 +14,7 @@ int line; string source; } ++ (void) finishCollecting; + (void) collectCheckPoint; - (void) mark; - (void) markReachable; diff --git a/ruamoko/scheme/defs.h b/ruamoko/scheme/defs.h index a1d691684..7f1e4289c 100644 --- a/ruamoko/scheme/defs.h +++ b/ruamoko/scheme/defs.h @@ -1,13 +1,13 @@ -@extern void (string str) print = #0; -@extern int () errno = #0; -@extern string (int err) strerror = #0; -@extern int (...) open = #0; // string path, float flags[, float mode] -@extern int (int handle) close = #0; -@extern string read (int handle, int count, int *result) = #0; -@extern int (int handle, string buffer, int count) write = #0; -@extern int (int handle, int pos, int whence) seek = #0; +@extern void (string str) print; +@extern int () errno; +@extern string (int err) strerror; +@extern int (...) open; // string path, float flags[, float mode] +@extern int (int handle) close; +@extern string read (int handle, int count, int *result); +@extern int (int handle, string buffer, int count) write; +@extern int (int handle, int pos, int whence) seek; -@extern void() traceon = #0; // turns statment trace on -@extern void() traceoff = #0; +@extern void() traceon; // turns statment trace on +@extern void() traceoff; -@extern void (...) printf = #0; +@extern void (...) printf; diff --git a/ruamoko/scheme/defs.r b/ruamoko/scheme/defs.r index 943ef9173..1c638232d 100644 --- a/ruamoko/scheme/defs.r +++ b/ruamoko/scheme/defs.r @@ -3,7 +3,7 @@ int () errno = #0; string (int err) strerror = #0; int (...) open = #0; // string path, float flags[, float mode] int (int handle) close = #0; -string (int handle, int count, int []result) read = #0; +string read (int handle, int count, int *result) = #0; int (int handle, string buffer, int count) write = #0; int (int handle, int pos, int whence) seek = #0; diff --git a/ruamoko/scheme/main.r b/ruamoko/scheme/main.r index fb1fa3e33..be7d8bca6 100644 --- a/ruamoko/scheme/main.r +++ b/ruamoko/scheme/main.r @@ -22,23 +22,23 @@ string readfile (string filename) str_copy(res, acc); return res; } - -int main (int argc, string []argv) +int main (int argc, string *argv) { - local Parser parser; - local CompiledCode code; - local Compiler comp; - local Machine vm; - local Lambda lm; - local SchemeObject stuff, res; + local Parser *parser; + local CompiledCode *code; + local Compiler *comp; + local Machine *vm; + local Lambda *lm; + local SchemeObject *stuff, *res; + local Error *err; if (argc < 1) { return -1; } //traceon(); - + parser = [Parser newFromSource: readfile(argv[1]) file: argv[1]]; vm = [Machine new]; [vm makeRootCell]; @@ -46,26 +46,29 @@ int main (int argc, string []argv) builtin_addtomachine (vm); while ((stuff = [parser read])) { if ([stuff isError]) { - printf(">> %s: %i\n", [stuff source], [stuff line]); - printf(">> Error (%s): %s\n", [stuff type], [stuff message]); + err = (Error *) stuff; + printf(">> %s: %i\n", [err source], [err line]); + printf(">> Error (%s): %s\n", [err type], [err message]); return -1; } comp = [Compiler newWithLambda: cons ([Symbol forString: "lambda"], cons ([Nil nil], cons(stuff, [Nil nil]))) scope: nil]; - code = (CompiledCode) [comp compile]; + code = (CompiledCode *) [comp compile]; if ([code isError]) { - printf(">> %s: %i\n", [code source], [code line]); - printf(">> Error (%s): %s\n", [code type], [code message]); + err = (Error *) code; + printf(">> %s: %i\n", [err source], [err line]); + printf(">> Error (%s): %s\n", [err type], [err message]); return -1; } lm = [Lambda newWithCode: code environment: nil]; [lm invokeOnMachine: vm]; res = [vm run]; if ([res isError]) { - printf(">> %s: %i\n", [res source], [res line]); - printf(">> Error (%s): %s\n", [res type], [res message]); + err = (Error *) res; + printf(">> %s: %i\n", [err source], [err line]); + printf(">> Error (%s): %s\n", [err type], [err message]); return -1; } [vm reset]; From c58cf2c2d059a585c5e941418d2ea66b6f404986 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 21:30:47 +0900 Subject: [PATCH 179/444] [qwaq] Fail at object oriented design 101 This is horrible, doesn't work, isn't really the direction I want to go (that became apparent while implementing Screen's handleEvent) and crashes anyway (Array and not-id...) *sigh* Still, this does have some good stuff in it, and it pushed qfcc along some more. --- ruamoko/qwaq/event.h | 6 +++- ruamoko/qwaq/qwaq-app.r | 12 +++++--- ruamoko/qwaq/qwaq-curses.c | 61 ++++++++++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-curses.h | 2 ++ ruamoko/qwaq/qwaq-draw.h | 2 ++ ruamoko/qwaq/qwaq-rect.h | 2 +- ruamoko/qwaq/qwaq-screen.h | 5 ++- ruamoko/qwaq/qwaq-screen.r | 63 +++++++++++++++++++++++++++++++++++++- ruamoko/qwaq/qwaq-view.h | 1 + ruamoko/qwaq/qwaq-view.r | 11 +++++++ ruamoko/qwaq/qwaq-window.h | 4 +-- ruamoko/qwaq/qwaq-window.r | 22 +++++++++++++ 12 files changed, 180 insertions(+), 11 deletions(-) diff --git a/ruamoko/qwaq/event.h b/ruamoko/qwaq/event.h index f494234a9..9eca5158e 100644 --- a/ruamoko/qwaq/event.h +++ b/ruamoko/qwaq/event.h @@ -37,11 +37,15 @@ typedef struct qwaq_event_s { -handleEvent: (struct qwaq_event_s *) event; @end -@protocol TakeFocus +@protocol HandleFocusedEvent -takeFocus; -loseFocus; @end +@protocol HandleMouseEvent +-(struct Rect_s *)getRect; +@end + #endif #endif//__qwaq_event_h diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index e100ae69e..ed6339faf 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -37,15 +37,15 @@ arp_end (void) init_pair (2, COLOR_WHITE, COLOR_BLACK); screen = [[Screen screen] retain]; [screen setBackground: COLOR_PAIR (1)]; - Rect r = screen.rect; - wprintf (screen.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); + Rect r = *[screen getRect]; + [screen printf:"%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen]; r.xpos = r.xlen / 4; r.ypos = r.ylen / 4; r.xlen /= 2; r.ylen /= 2; - wprintf (screen.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); - wprintf (screen.window, "%d\n", acs_char(ACS_HLINE)); - mvwaddch(screen.window, 4, 4, acs_char(ACS_HLINE)); + [screen printf:"%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen]; + [screen printf:"%d\n", acs_char(ACS_HLINE)]; + [screen addch: acs_char(ACS_HLINE) atX:4 Y:4]; Window *w; [screen add: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; //wprintf (w.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); @@ -102,6 +102,7 @@ window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; void destroy_window (window_t win) = #0; void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; void wprintf (window_t win, string fmt, ...) = #0; +void wvprintf (window_t win, string fmt, @va_list args) = #0; void wrefresh (window_t win) = #0; void mvwaddch (window_t win, int x, int y, int ch) = #0; int get_event (qwaq_event_t *event) = #0; @@ -109,6 +110,7 @@ int max_colors (void) = #0; int max_color_pairs (void) = #0; int init_pair (int pair, int f, int b) = #0; void wbkgd (window_t win, int ch) = #0; +void scrollok (window_t win, int flag) = #0; int acs_char (int acs) = #0; panel_t create_panel (window_t window) = #0; diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index f33e01a5a..c03a38542 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -72,6 +72,7 @@ typedef enum qwaq_commands_e { qwaq_cmd_wrefresh, qwaq_cmd_init_pair, qwaq_cmd_wbkgd, + qwaq_cmd_scrollok, } qwaq_commands; #define RING_BUFFER(type, size) \ @@ -523,6 +524,16 @@ cmd_wbkgd (qwaq_resources_t *res) wbkgd (window->win, ch); } +static void +cmd_scrollok (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int flag = RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + scrollok (window->win, flag); +} + static void process_commands (qwaq_resources_t *res) { @@ -585,6 +596,9 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_wbkgd: cmd_wbkgd (res); break; + case qwaq_cmd_scrollok: + cmd_scrollok (res); + break; } RB_DROP_DATA (res->command_queue, RB_PEEK_DATA (res->command_queue, 1)); } @@ -881,6 +895,37 @@ bi_wprintf (progs_t *pr) } } +static void +bi_wvprintf (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + const char *fmt = P_GSTRING (pr, 1); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 2); + pr_type_t *list_start = PR_GetPointer (pr, args->list); + pr_type_t **list = alloca (args->count); + + for (int i = 0; i < args->count; i++) { + list[i] = list_start + i * pr->pr_param_size; + } + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_waddstr, 0, + window_id, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "waddstr", fmt, args->count, list); + + qwaq_submit_command (res, command); + } +} + static void bi_mvwaddch (progs_t *pr) { @@ -963,6 +1008,20 @@ bi_wbkgd (progs_t *pr) } } +static void +bi_scrollok (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + int flag = P_INT (pr, 1); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_scrollok, 0, window_id, flag, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} + static const char qwaq_acs_char_map[] = "lmkjtuvwqxnos`afg~,+.-hi0pryz{|}"; static void bi_acs_char (progs_t *pr) @@ -1029,6 +1088,7 @@ static builtin_t builtins[] = { {"doupdate", bi_doupdate, -1}, {"mvwprintf", bi_mvwprintf, -1}, {"wprintf", bi_wprintf, -1}, + {"wvprintf", bi_wvprintf, -1}, {"mvwaddch", bi_mvwaddch, -1}, {"wrefresh", bi_wrefresh, -1}, {"get_event", bi_get_event, -1}, @@ -1036,6 +1096,7 @@ static builtin_t builtins[] = { {"max_color_pairs", bi_max_color_pairs, -1}, {"init_pair", bi_init_pair, -1}, {"wbkgd", bi_wbkgd, -1}, + {"scrollok", bi_scrollok, -1}, {"acs_char", bi_acs_char, -1}, {0} }; diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index bf5d24191..e9574e764 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -75,6 +75,7 @@ typedef struct panel_s *panel_t; @extern void destroy_window (window_t win); @extern void mvwprintf (window_t win, int x, int y, string fmt, ...); @extern void wprintf (window_t win, string fmt, ...); +@extern void wvprintf (window_t win, string fmt, @va_list args); @extern void wrefresh (window_t win); @extern void mvwaddch (window_t win, int x, int y, int ch); @@ -94,6 +95,7 @@ typedef struct panel_s *panel_t; @extern int max_color_pairs (void); @extern int init_pair (int pair, int f, int b); @extern void wbkgd (window_t win, int ch); +@extern void scrollok (window_t win, int flag); @extern int acs_char (int acs); #endif diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h index 4abac3e55..7b614a29e 100644 --- a/ruamoko/qwaq/qwaq-draw.h +++ b/ruamoko/qwaq/qwaq-draw.h @@ -3,6 +3,8 @@ @protocol Draw -draw; +-redraw; +-setParent: parent; @end #endif diff --git a/ruamoko/qwaq/qwaq-rect.h b/ruamoko/qwaq/qwaq-rect.h index 0c26b5817..c679352fc 100644 --- a/ruamoko/qwaq/qwaq-rect.h +++ b/ruamoko/qwaq/qwaq-rect.h @@ -1,7 +1,7 @@ #ifndef __qwaq_rect_h #define __qwaq_rect_h -typedef struct { +typedef struct Rect_s { int xpos; int ypos; int xlen; diff --git a/ruamoko/qwaq/qwaq-screen.h b/ruamoko/qwaq/qwaq-screen.h index 5ded2ecaf..8c83abb6e 100644 --- a/ruamoko/qwaq/qwaq-screen.h +++ b/ruamoko/qwaq/qwaq-screen.h @@ -10,16 +10,19 @@ @interface Screen: Object { - @public Rect rect; Array *views; Array *event_handlers; + Array *focused_handlers; + Array *mouse_handlers; + Array *mouse_handler_rects; View *focusedView; struct window_s *window; } +(Screen *) screen; -add: obj; -setBackground: (int) ch; +-printf: (string) fmt, ...; @end #endif//__qwaq_screen_h diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index 770104c64..0c8573a83 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -1,3 +1,4 @@ +#include #include "qwaq-curses.h" #include "qwaq-screen.h" @@ -14,7 +15,11 @@ } views = [[Array array] retain]; event_handlers = [[Array array] retain]; + focused_handlers = [[Array array] retain]; + mouse_handlers = [[Array array] retain]; + mouse_handler_rects = [[Array array] retain]; window = stdscr; + scrollok (window, 1); rect = getwrect (window); return self; } @@ -22,10 +27,22 @@ -add: obj { if ([obj conformsToProtocol: @protocol (Draw)]) { + // "top" objects are drawn last [views addObject: obj]; + [obj setParent: self]; + } + if ([obj conformsToProtocol: @protocol (HandleFocusedEvent)]) { + // want "top" objects to respond first + [focused_handlers insertObject: obj atIndex: 0]; + } + if ([obj conformsToProtocol: @protocol (HandleMouseEvent)]) { + // "top" objects respond first, but the array is searched in reverse + [mouse_handlers addObject: obj]; + [mouse_handler_rects addObject: (id) [obj getRect]]; } if ([obj conformsToProtocol: @protocol (HandleEvent)]) { - [event_handlers addObject: obj]; + // want "top" objects to respond first + [event_handlers insertObject: obj atIndex: 0]; } return self; } @@ -38,6 +55,25 @@ -handleEvent: (qwaq_event_t *) event { + switch (event.event_type) { + case qe_none: + break; + case qe_key: + case qe_command: + [focused_handlers + makeObjectsPerformSelector: @selector(handleEvent:) + withObject: (id) event]; + break; + case qe_mouse: + Point p = { event.e.mouse.x, event.e.mouse.y }; + for (int i = [mouse_handler_rects count]; i-->0; ) { + //if (rectContainsPoint((Rect*)mouse_handler_rects._objs[i], &p)) { + // [mouse_handlers._objs[i] handleEvent: event]; + // break; + //} + } + break; + } return self; } @@ -49,4 +85,29 @@ return self; } +-redraw +{ + [self error:"hmm"]; + update_panels (); + doupdate (); + return self; +} + +-printf: (string) fmt, ... +{ + wvprintf (window, fmt, @args); + return self; +} + +-addch: (int) ch atX: (int) x Y: (int) y +{ + mvwaddch(window, x, y, ch); + return self; +} + +-setParent: parent +{ + return self; +} + @end diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index 817ec0ab7..e7c0db85e 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -13,6 +13,7 @@ Rect rect; Rect absRect; Point point; // can't be local :( + id parent; struct window_s *window; } -initWithRect: (Rect) rect; diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 8cf37c53d..bc218630f 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -33,6 +33,17 @@ rectContainsPoint (Rect *rect, Point *point) return self; } +-setParent: parent +{ + self.parent = parent; + return self; +} + +-redraw +{ + return [parent redraw]; +} + @end Rect getwrect (window_t window) = #0; diff --git a/ruamoko/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h index ae45d7e72..19921301a 100644 --- a/ruamoko/qwaq/qwaq-window.h +++ b/ruamoko/qwaq/qwaq-window.h @@ -9,10 +9,10 @@ #include "qwaq-draw.h" #include "qwaq-rect.h" -@interface Window: Object +@interface Window: Object { - @public Rect rect; + id parent; Point point; // FIXME can't be local :( Array *views; View *focusedView; diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 493a6ccff..7e201aa9a 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -17,6 +17,7 @@ if (!(self = [super init])) { return nil; } + views = [[Array array] retain]; self.rect = rect; window = create_window (rect.xpos, rect.ypos, rect.xlen, rect.ylen); panel = create_panel (window); @@ -27,6 +28,9 @@ { switch (event.event_type) { case qe_mouse: + mvwprintf(window, 0, 3, "%2d %2d %08x", + event.e.mouse.x, event.e.mouse.y, event.e.mouse.buttons); + [self redraw]; point.x = event.e.mouse.x; point.y = event.e.mouse.y; for (int i = [views count]; i--> 0; ) { @@ -60,6 +64,7 @@ view.absRect.xpos = view.rect.xpos + rect.xpos; view.absRect.ypos = view.rect.ypos + rect.ypos; view.window = window; + [view setParent: self]; return self; } @@ -96,6 +101,23 @@ } } } + [views makeObjectsPerformSelector: @selector (draw)]; return self; } + +-(Rect *) getRect +{ + return ▭ +} + +-setParent: parent +{ + self.parent = parent; + return self; +} + +-redraw +{ + return [parent redraw]; +} @end From de01cff70ed2e1b1490b5c79cab11f064b0e9810 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 3 Mar 2020 22:22:53 +0900 Subject: [PATCH 180/444] [build] Install QF/keys.h into qfcc's include directory As well as $prefix/include, of course. This fixes the problem with external ruamoko builds failing due to keys.h and qfcc's "lockdown" on system headers. --- config.d/build_control.m4 | 8 ++++++++ include/QF/Makefile.am | 11 ++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/config.d/build_control.m4 b/config.d/build_control.m4 index 98517088e..88b58e610 100644 --- a/config.d/build_control.m4 +++ b/config.d/build_control.m4 @@ -254,7 +254,15 @@ QF_PROCESS_NEED_DIRS(ruamoko,[qwaq]) if test "$ENABLE_tools_qfcc" = "yes" -a "$ENABLE_tools_pak" = "yes"; then QF_NEED(top, [ruamoko]) + qfcc_include_qf="\$(qfcc_include_qf)" fi +QF_SUBST(qfcc_include_qf) + +if test x"${top_need_libs}" = xyes; then + include_qf="\$(include_qf)" +fi +QF_SUBST(include_qf) + progs_gz= if test "$HAVE_ZLIB" = "yes"; then progs_gz=".gz" diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am index 3041d64d6..724d192df 100644 --- a/include/QF/Makefile.am +++ b/include/QF/Makefile.am @@ -1,6 +1,9 @@ AUTOMAKE_OPTIONS = foreign pkgincludedir = $(includedir)/QF -nobase_pkginclude_HEADERS = \ +#for header files that qfcc (ruamoko) will use +pkgdatadir = $(datarootdir)/qfcc/include/QF + +include_qf= \ alloc.h bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \ console.h crc.h csqc.h cvar.h dstring.h draw.h gib.h hash.h \ idparse.h image.h in_event.h info.h input.h iqm.h joystick.h keys.h \ @@ -26,3 +29,9 @@ nobase_pkginclude_HEADERS = \ \ plugin/cd.h plugin/console.h plugin/general.h plugin/input.h \ plugin/snd_output.h plugin/snd_render.h plugin/vid_render.h + +qfcc_include_qf=keys.h +nobase_pkginclude_HEADERS = @include_qf@ +pkgdata_DATA=@qfcc_include_qf@ + +EXTRA_HEADERS = $(include_qf) $(qfcc_include_qf) From 57b2751732a06cf4bcc0a7ae855b17a5de9b0f46 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 00:37:10 +0900 Subject: [PATCH 181/444] [qfcc] Add failing vector element address test It's an evil thing to do, but it should at least work. --- tools/qfcc/test/Makefile.am | 10 ++++++++++ tools/qfcc/test/vecaddr.r | 16 ++++++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 tools/qfcc/test/vecaddr.r diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index 129240670..fc6f7692b 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -55,6 +55,7 @@ test_progs_dat=\ structstruct.dat \ swap.dat \ triangle.dat \ + vecaddr.dat \ vecexpr.dat \ vecinit.dat \ voidfor.dat \ @@ -373,6 +374,15 @@ r_depfiles_remade += ./$(DEPDIR)/triangle.Qo #include ./$(DEPDIR)/typedef.Qo # am--include-marker #r_depfiles_remade += ./$(DEPDIR)/typedef.Qo +vecaddr_dat_SOURCES=vecaddr.r +vecaddr_obj=$(vecaddr_dat_SOURCES:.r=.qfo) +vecaddr.dat$(EXEEXT): $(vecaddr_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(vecaddr_obj) +vecaddr.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/vecaddr.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/vecaddr.Qo + vecexpr_dat_SOURCES=vecexpr.r vecexpr_obj=$(vecexpr_dat_SOURCES:.r=.qfo) vecexpr.dat$(EXEEXT): $(vecexpr_obj) $(QFCC_DEP) diff --git a/tools/qfcc/test/vecaddr.r b/tools/qfcc/test/vecaddr.r new file mode 100644 index 000000000..323d9205c --- /dev/null +++ b/tools/qfcc/test/vecaddr.r @@ -0,0 +1,16 @@ +void printf (string fmt, ...) = #0; + +float foo (vector v, float z) +{ + return v * *(vector*)(&v.y); +} + +int +main (int argc, string *argv) +{ + vector v = [1, 2, 3]; + vector w = [2, 3, 4]; + float f; + printf ("%v %g %g %g\n", v, v*v, v*w, f=foo (v, 4)); + return f != v*w; +} From 4fa203852acfd9aea655c798500b1a4ba70cba37 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 00:55:31 +0900 Subject: [PATCH 182/444] [qfcc] Use offset alias offset when creating alias of offset alias Yes, that's correct. It happens when casting the address of a structure field (for the test case this fixes, vector field). --- tools/qfcc/source/expr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index dafb49c96..00d2b60ee 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2065,6 +2065,8 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) t = e1->e.expr.type; if (e2) { e2 = binary_expr ('+', e1->e.expr.e2, e2); + } else { + e2 = e1->e.expr.e2; } return address_expr (e1->e.expr.e1, e2, t); } From e298904dc03920d0e6754cf7dc8ab496caa6673d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 16:31:28 +0900 Subject: [PATCH 183/444] [qfcc] Implement anonymous structs and unions For struct/union scope --- tools/qfcc/include/symtab.h | 1 + tools/qfcc/source/qc-parse.y | 39 ++++++++++++++++++++++-- tools/qfcc/source/struct.c | 23 +++++++++++++++ tools/qfcc/source/symtab.c | 2 +- tools/qfcc/test/Makefile.am | 10 +++++++ tools/qfcc/test/anonstruct.r | 57 ++++++++++++++++++++++++++++++++++++ 6 files changed, 128 insertions(+), 4 deletions(-) create mode 100644 tools/qfcc/test/anonstruct.r diff --git a/tools/qfcc/include/symtab.h b/tools/qfcc/include/symtab.h index c0c064f3e..53b42f150 100644 --- a/tools/qfcc/include/symtab.h +++ b/tools/qfcc/include/symtab.h @@ -45,6 +45,7 @@ typedef enum vis_e { vis_public, vis_protected, vis_private, + vis_anonymous, } vis_t; typedef enum { diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 3fac0f926..17316e79f 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -42,6 +42,7 @@ #include #include +#include #include "class.h" #include "debug.h" @@ -264,6 +265,26 @@ default_type (specifier_t spec, symbol_t *sym) return spec; } +static int +is_anonymous_struct (specifier_t spec) +{ + if (spec.sym) { + return 0; + } + if (!is_struct (spec.type)) { + return 0; + } + if (spec.type->t.symtab->parent) { + return 0; + } + // struct and union type names always begin with "tag ". Untagged s/u + // are "tag ..". + if (spec.type->name[4] != '.') { + return 0; + } + return 1; +} + %} %expect 0 @@ -675,15 +696,27 @@ struct_def : type struct_decl_list | type { - if ($1.sym) { + if ($1.sym && $1.sym->type != $1.type) { // a type name (id, typedef, etc) was used as a field name. // this is allowed in C - print_type ($1.type); - printf ("%s\n", $1.sym->name); $1.sym = new_symbol ($1.sym->name); $1.sym->type = $1.type; $1.sym->sy_type = sy_var; symtab_addsymbol (current_symtab, $1.sym); + if (!$1.sym->table) { + error (0, "duplicate field `%s'", $1.sym->name); + } + } else if (is_anonymous_struct ($1)) { + // anonymous struct/union + // type->name always begins with "tag " + $1.sym = new_symbol (va (".anonymous.%s", $1.type->name + 4)); + $1.sym->type = $1.type; + $1.sym->sy_type = sy_var; + $1.sym->visibility = vis_anonymous; + symtab_addsymbol (current_symtab, $1.sym); + if (!$1.sym->table) { + error (0, "duplicate field `%s'", $1.sym->name); + } } else { // bare type warning (0, "declaration does not declare anything"); diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 989b298ef..7af7f26b2 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -114,6 +114,7 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) symbol_t *sym = find_struct (su, tag, type); symbol_t *s; int alignment = 1; + symbol_t *as; symtab->parent = 0; // disconnect struct's symtab from parent scope @@ -140,6 +141,28 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) if (s->type->alignment > alignment) { alignment = s->type->alignment; } + if (s->visibility == vis_anonymous) { + symtab_t *anonymous; + symbol_t *t = s->next; + int offset = s->s.offset; + + if (!is_struct (s->type)) { + internal_error (0, "non-struct/union anonymous field"); + } + anonymous = s->type->t.symtab; + for (as = anonymous->symbols; as; as = as->next) { + if (Hash_Find (symtab->tab, as->name)) { + error (0, "ambiguous field `%s' in anonymous %s", + as->name, su == 's' ? "struct" : "union"); + } else { + s->next = copy_symbol (as); + s = s->next; + s->s.offset += offset; + Hash_Add (symtab->tab, s); + } + } + s->next = t; + } } if (!type) sym->type = find_type (sym->type); // checks the tag, not the symtab diff --git a/tools/qfcc/source/symtab.c b/tools/qfcc/source/symtab.c index f26a690e7..377671e8a 100644 --- a/tools/qfcc/source/symtab.c +++ b/tools/qfcc/source/symtab.c @@ -152,7 +152,7 @@ symtab_removesymbol (symtab_t *symtab, symbol_t *symbol) for (s = &symtab->symbols; *s && *s != symbol; s = & (*s)->next) ; if (!*s) - internal_error (0, "symtab_removesymbol"); + internal_error (0, "attempt to remove symbol not in symtab"); *s = (*s)->next; if (symtab->symtail == &symbol->next) symtab->symtail = s; diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index fc6f7692b..2e1001c11 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -31,6 +31,7 @@ fail_bins= test_progs_dat=\ address-cast.dat \ alignment.dat \ + anonstruct.dat \ chewed-alias.dat \ chewed-return.dat \ comma-expr.dat \ @@ -119,6 +120,15 @@ alignment.run: Makefile build-run include ./$(DEPDIR)/alignment.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/alignment.Qo +anonstruct_dat_SOURCES=anonstruct.r +anonstruct_obj=$(anonstruct_dat_SOURCES:.r=.qfo) +anonstruct.dat$(EXEEXT): $(anonstruct_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(anonstruct_obj) +anonstruct.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/anonstruct.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/anonstruct.Qo + chewed_alias_dat_SOURCES=chewed-alias.r chewed_alias_obj=$(chewed_alias_dat_SOURCES:.r=.qfo) chewed-alias.dat$(EXEEXT): $(chewed_alias_obj) $(QFCC_DEP) diff --git a/tools/qfcc/test/anonstruct.r b/tools/qfcc/test/anonstruct.r new file mode 100644 index 000000000..a426d8f61 --- /dev/null +++ b/tools/qfcc/test/anonstruct.r @@ -0,0 +1,57 @@ +void printf (string fmt, ...) = #0; + +typedef struct xyzzy_s { + int magic; +} xyzzy_t; + +typedef struct anon_s { + int foo; + int id; + struct { + int bar; + int baz; + }; + union { + int snafu; + float fizzle; + }; +} anon_t; + +union { + int xsnafu; + float xfizzle; +}; + +int foo (float f) +{ + anon_t anon; + anon.fizzle = f; + return anon.snafu; +} + +int main() +{ + anon_t anon; + int ret = 0; + if (&anon.snafu != &anon.fizzle) { + printf ("anon union broken: %p %p\n", + &anon.snafu, &anon.fizzle); + ret |= 1; + } + if (&anon.snafu - &anon.baz != 1) { + printf ("snafu and baz not adjacant: snafu:%p baz:%p\n", + &anon.snafu, &anon.baz); + ret |= 1; + } + if (&anon.baz - &anon.bar != 1) { + printf ("baz and bar not adjacant: baz:%p bar:%p\n", + &anon.baz, &anon.bar); + ret |= 1; + } + if (&anon.bar - &anon.id != 1) { + printf ("bar not after id: bar:%p id:%p\n", + &anon.bar, &anon.id); + ret |= 1; + } + return ret; +} From 597890dda154e8817bffa96bde0104dcbe7a6130 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 16:32:04 +0900 Subject: [PATCH 184/444] [qfcc] Catch duplicate field definitions --- tools/qfcc/source/qc-parse.y | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 17316e79f..f0a2f5055 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -741,6 +741,9 @@ struct_decl $1->sy_type = sy_var; $1->visibility = current_visibility; symtab_addsymbol (current_symtab, $1); + if (!$1->table) { + error (0, "duplicate field `%s'", $1->name); + } } | var_decl { @@ -751,6 +754,9 @@ struct_decl $1->sy_type = sy_var; $1->visibility = current_visibility; symtab_addsymbol (current_symtab, $1); + if (!$1->table) { + error (0, "duplicate field `%s'", $1->name); + } } | var_decl ':' expr %prec COMMA {} | ':' expr %prec COMMA {} From 4c82114547a0f39f20da22f5cade1299855bc758 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 17:40:49 +0900 Subject: [PATCH 185/444] [qfcc] Catch several useless specifier expressions --- tools/qfcc/source/qc-parse.y | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index f0a2f5055..cf9c2fb9f 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -285,6 +285,13 @@ is_anonymous_struct (specifier_t spec) return 1; } +static int +is_null_spec (specifier_t spec) +{ + static specifier_t null_spec; + return memcmp (&spec, &null_spec, sizeof (spec)) == 0; +} + %} %expect 0 @@ -333,7 +340,25 @@ external_def_list external_def : optional_specifiers external_decl_list ';' { } - | optional_specifiers ';' { } + | optional_specifiers ';' + { + if (!is_null_spec ($1)) { + if (!$1.type && !$1.sym) { + warning (0, "useless specifiers"); + } else if ($1.type && !$1.sym) { + if (is_anonymous_struct ($1)){ + warning (0, "unnamed struct/union that defines " + "no instances"); + } else { + warning (0, "useless type name in empty declaration"); + } + } else if (!$1.type && $1.sym) { + bug (0, "wha? %p %p", $1.type, $1.sym); + } else { + bug (0, "wha? %p %p", $1.type, $1.sym); + } + } + } | optional_specifiers qc_func_params { type_t **type; From 7a2335e9f43e739baf801c5d7aca753d35b67e15 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 18:07:10 +0900 Subject: [PATCH 186/444] [qfcc] Catch useless specifiers in function scope --- tools/qfcc/source/qc-parse.y | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index cf9c2fb9f..25581f8ec 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1232,6 +1232,26 @@ local_def local_expr = 0; (void) ($2); } + | specifiers ';' + { + if (!is_null_spec ($1)) { + if (!$1.type && !$1.sym) { + warning (0, "useless specifiers"); + } else if ($1.type && !$1.sym) { + if (is_anonymous_struct ($1)){ + warning (0, "unnamed struct/union that defines " + "no instances"); + } else { + warning (0, "useless type name in empty declaration"); + } + } else if (!$1.type && $1.sym) { + bug (0, "wha? %p %p", $1.type, $1.sym); + } else { + bug (0, "wha? %p %p", $1.type, $1.sym); + } + } + $$ = 0; + } ; statement From f532780dbee88efe42331ed21575089cdc1f1650 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 18:38:04 +0900 Subject: [PATCH 187/444] [qfcc] Treat opaque structs as not anonymous I don't know why the segfault happened where it did, but forward-declared structs certainly can't be used as anonymous structs. --- tools/qfcc/source/qc-parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 25581f8ec..24138407d 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -274,7 +274,7 @@ is_anonymous_struct (specifier_t spec) if (!is_struct (spec.type)) { return 0; } - if (spec.type->t.symtab->parent) { + if (!spec.type->t.symtab || spec.type->t.symtab->parent) { return 0; } // struct and union type names always begin with "tag ". Untagged s/u From 269a8a558ad51da626a9169e11d20721f6d73783 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 18:39:41 +0900 Subject: [PATCH 188/444] [qfcc] Allow bare enum and named struct declarations Got a little overzealous there --- tools/qfcc/source/qc-parse.y | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 24138407d..46cf09e7e 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -349,7 +349,7 @@ external_def if (is_anonymous_struct ($1)){ warning (0, "unnamed struct/union that defines " "no instances"); - } else { + } else if (!is_enum ($1.type) && !is_struct ($1.type)) { warning (0, "useless type name in empty declaration"); } } else if (!$1.type && $1.sym) { @@ -1241,7 +1241,7 @@ local_def if (is_anonymous_struct ($1)){ warning (0, "unnamed struct/union that defines " "no instances"); - } else { + } else if (!is_enum ($1.type) && !is_struct ($1.type)) { warning (0, "useless type name in empty declaration"); } } else if (!$1.type && $1.sym) { From d57e05258c6ae3cb80e2c41a0ba000b5f35df06c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 19:10:09 +0900 Subject: [PATCH 189/444] [qwaq] Remove now unnecessary union field name \o/ --- ruamoko/qwaq/event.h | 2 +- ruamoko/qwaq/qwaq-app.r | 10 +++++----- ruamoko/qwaq/qwaq-curses.c | 8 ++++---- ruamoko/qwaq/qwaq-screen.r | 2 +- ruamoko/qwaq/qwaq-window.r | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/ruamoko/qwaq/event.h b/ruamoko/qwaq/event.h index 9eca5158e..28ddccf59 100644 --- a/ruamoko/qwaq/event.h +++ b/ruamoko/qwaq/event.h @@ -29,7 +29,7 @@ typedef struct qwaq_event_s { int key; qwaq_mevent_t mouse; qwaq_message_t message; - } e; + }; } qwaq_event_t; #ifdef __QFCC__ // don't want C gcc to see this :) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index ed6339faf..12280d2b3 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -71,14 +71,14 @@ arp_end (void) -handleEvent: (qwaq_event_t *) event { [screen handleEvent: event]; - if (event.event_type == qe_key && event.e.key == '\x18') { + if (event.event_type == qe_key && event.key == '\x18') { event.event_type = qe_command; - event.e.message.command = qc_exit; + event.message.command = qc_exit; } if (event.event_type == qe_command - && (event.e.message.command == qc_exit - || event.e.message.command == qc_error)) { - endState = event.e.message.command; + && (event.message.command == qc_exit + || event.message.command == qc_error)) { + endState = event.message.command; } return self; } diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index c03a38542..3d8098ea7 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -629,9 +629,9 @@ mouse_event (qwaq_resources_t *res, MEVENT *mevent) { qwaq_event_t event = {}; event.event_type = qe_mouse; - event.e.mouse.x = mevent->x; - event.e.mouse.y = mevent->y; - event.e.mouse.buttons = mevent->bstate; + event.mouse.x = mevent->x; + event.mouse.y = mevent->y; + event.mouse.buttons = mevent->bstate; add_event (res, &event); } @@ -640,7 +640,7 @@ key_event (qwaq_resources_t *res, int key) { qwaq_event_t event = {}; event.event_type = qe_key; - event.e.key = key; + event.key = key; add_event (res, &event); } diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index 0c8573a83..4e68cae30 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -65,7 +65,7 @@ withObject: (id) event]; break; case qe_mouse: - Point p = { event.e.mouse.x, event.e.mouse.y }; + Point p = { event.mouse.x, event.mouse.y }; for (int i = [mouse_handler_rects count]; i-->0; ) { //if (rectContainsPoint((Rect*)mouse_handler_rects._objs[i], &p)) { // [mouse_handlers._objs[i] handleEvent: event]; diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 7e201aa9a..af53a6546 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -29,10 +29,10 @@ switch (event.event_type) { case qe_mouse: mvwprintf(window, 0, 3, "%2d %2d %08x", - event.e.mouse.x, event.e.mouse.y, event.e.mouse.buttons); + event.mouse.x, event.mouse.y, event.mouse.buttons); [self redraw]; - point.x = event.e.mouse.x; - point.y = event.e.mouse.y; + point.x = event.mouse.x; + point.y = event.mouse.y; for (int i = [views count]; i--> 0; ) { View *v = [views objectAtIndex: i]; if (rectContainsPoint (&v.absRect, &point)) { From c214797e973ae8124af900f8b9f8f0cd9ece9912 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 21:09:36 +0900 Subject: [PATCH 190/444] [gamecode] Fix some curly space and add some comments. took a bit to figure out what i was doing --- libs/gamecode/pr_debug.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 28bb97e54..6a4703724 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -178,21 +178,30 @@ source_path_f (cvar_t *var) int i; char *s; - if (source_path_string) + if (source_path_string) { free (source_path_string); + } source_path_string = strdup (var->string); - if (source_paths) + if (source_paths) { free (source_paths); - for (i = 2, s = source_path_string; *s; s++) - if (*s == ';') + } + // i starts at 2 because an empty path is equivalent to "." and the + // list is null terminated + for (i = 2, s = source_path_string; *s; s++) { + if (*s == ';') { i++; + } + } source_paths = malloc (i * sizeof (char *)); source_paths[0] = source_path_string; - for (i = 1, s = source_path_string; *s; s++) + // i starts at one because the first path is in 0 and any additional + // paths come after, then the null terminator + for (i = 1, s = source_path_string; *s; s++) { if (*s == ';') { *s++ = 0; source_paths[i++] = s; } + } source_paths[i] = 0; } From 68fc11857ad8ef4c58f5169b209ff6872b0e625c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 21:10:23 +0900 Subject: [PATCH 191/444] [gamecode] Fix a string splitting error --- libs/gamecode/pr_debug.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 6a4703724..c102b46f8 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -198,8 +198,8 @@ source_path_f (cvar_t *var) // paths come after, then the null terminator for (i = 1, s = source_path_string; *s; s++) { if (*s == ';') { - *s++ = 0; - source_paths[i++] = s; + *s = 0; + source_paths[i++] = s + 1; } } source_paths[i] = 0; From 815ae02121e71ad77f51949394fd177b0d2b62d4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 21:17:17 +0900 Subject: [PATCH 192/444] [qwaq] Allocate enough bytes for the args list d'oh --- ruamoko/qwaq/qwaq-curses.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 3d8098ea7..1a75fa4dc 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -903,7 +903,7 @@ bi_wvprintf (progs_t *pr) const char *fmt = P_GSTRING (pr, 1); __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 2); pr_type_t *list_start = PR_GetPointer (pr, args->list); - pr_type_t **list = alloca (args->count); + pr_type_t **list = alloca (args->count * sizeof (*list)); for (int i = 0; i < args->count; i++) { list[i] = list_start + i * pr->pr_param_size; From f3236410d0460f28df9ed8fcda369e6bfe52b997 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 4 Mar 2020 22:09:40 +0900 Subject: [PATCH 193/444] [qwaq] Make the event system more informative Doesn't have timestamps at this stage, but otherwise it reflects the event system I had in my old text UI which was heavily based on TurboVision. TV is pretty good (after looking at things a bit closer I found it wasn't as deep as I thought), and better yet, Borland released it to the public domain 23 years ago! (wish I'd known that). Anyway, this commit gets something happening on the screen, even though the current hierarchy is still a mess. --- ruamoko/qwaq/event.h | 33 ++++++++++++++--- ruamoko/qwaq/qwaq-app.r | 15 +++++--- ruamoko/qwaq/qwaq-curses.c | 76 ++++++++++++++++++++++++++++++++++++-- ruamoko/qwaq/qwaq-screen.h | 2 +- ruamoko/qwaq/qwaq-screen.r | 34 +++++++++++------ ruamoko/qwaq/qwaq-window.r | 4 +- 6 files changed, 135 insertions(+), 29 deletions(-) diff --git a/ruamoko/qwaq/event.h b/ruamoko/qwaq/event.h index 28ddccf59..445240e54 100644 --- a/ruamoko/qwaq/event.h +++ b/ruamoko/qwaq/event.h @@ -2,11 +2,31 @@ #define __qwaq_event_h typedef enum { - qe_none, - qe_key, - qe_mouse, - qe_command, // application level command -} qwaq_etype; + qe_mousedown = 0x0001, + qe_mouseup = 0x0002, + qe_mouseclick= 0x0004, + qe_mousemove = 0x0008, + qe_mouseauto = 0x0010, +} qwaq_mouse_event; + +typedef enum { + qe_keydown = 0x0020, +} qwaq_key_event; + +typedef enum { + qe_command = 0x0200, // application level command + qe_broadcast = 0x0400, +} qwaq_message_event; + +typedef enum { + qe_none = 0x0000, + qe_mouse = 0x001f, + qe_key = 0x0020, + qe_system = 0x01c0, + qe_message = 0xfe00, + + qe_focused = qe_key | qe_command, +} qwaq_event_mask; typedef enum { qc_valid, @@ -17,6 +37,7 @@ typedef enum { typedef struct qwaq_mevent_s { int x, y; int buttons; + int click; } qwaq_mevent_t; typedef struct qwaq_message_s { @@ -24,7 +45,7 @@ typedef struct qwaq_message_s { } qwaq_message_t; typedef struct qwaq_event_s { - qwaq_etype event_type; + int what; union { int key; qwaq_mevent_t mouse; diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 12280d2b3..3bf67706a 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -1,3 +1,4 @@ +int fence; #include #include "color.h" @@ -47,8 +48,9 @@ arp_end (void) [screen printf:"%d\n", acs_char(ACS_HLINE)]; [screen addch: acs_char(ACS_HLINE) atX:4 Y:4]; Window *w; - [screen add: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; + //[screen add: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; //wprintf (w.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); + [screen redraw]; return self; } @@ -59,7 +61,7 @@ arp_end (void) arp_start (); get_event (&event); - if (event.event_type != qe_none) { + if (event.what != qe_none) { [self handleEvent: &event]; } @@ -71,11 +73,11 @@ arp_end (void) -handleEvent: (qwaq_event_t *) event { [screen handleEvent: event]; - if (event.event_type == qe_key && event.key == '\x18') { - event.event_type = qe_command; + if (event.what == qe_key && event.key == '\x18') { + event.what = qe_command; event.message.command = qc_exit; } - if (event.event_type == qe_command + if (event.what == qe_command && (event.message.command == qc_exit || event.message.command == qc_error)) { endState = event.message.command; @@ -86,6 +88,9 @@ arp_end (void) int main (int argc, string *argv) { + fence = 0; + //while (!fence) {} + id app = [[QwaqApplication app] retain]; [app run]; diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 1a75fa4dc..e51c47259 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -142,6 +142,11 @@ typedef enum qwaq_commands_e { rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)]; \ }) +#define RB_POKE_DATA(ring_buffer, ahead, data) \ + ({ __auto_type rb = &(ring_buffer); \ + rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)] = (data); \ + }) + typedef struct window_s { WINDOW *win; } window_t; @@ -607,6 +612,16 @@ process_commands (qwaq_resources_t *res) static void add_event (qwaq_resources_t *res, qwaq_event_t *event) { + // lock + // { + // merge motion events + unsigned last = RB_DATA_AVAILABLE (res->event_queue); + if (event->what == qe_mousemove && last > 1 + && RB_PEEK_DATA(res->event_queue, last - 1).what == qe_mousemove) { + RB_POKE_DATA(res->event_queue, last - 1, *event); + return; // unlock + } + // } if (RB_SPACE_AVAILABLE (res->event_queue) >= 1) { RB_WRITE_DATA (res->event_queue, event, 1); } @@ -624,14 +639,69 @@ get_event (qwaq_resources_t *res, qwaq_event_t *event) return 0; } +#define M_MOVE REPORT_MOUSE_POSITION +#define M_PRESS ( BUTTON1_PRESSED \ + | BUTTON2_PRESSED \ + | BUTTON3_PRESSED \ + | BUTTON4_PRESSED \ + | BUTTON5_PRESSED) +#define M_RELEASE ( BUTTON1_RELEASED \ + | BUTTON2_RELEASED \ + | BUTTON3_RELEASED \ + | BUTTON4_RELEASED \ + | BUTTON5_RELEASED) +#define M_CLICK ( BUTTON1_CLICKED \ + | BUTTON2_CLICKED \ + | BUTTON3_CLICKED \ + | BUTTON4_CLICKED \ + | BUTTON5_CLICKED) +#define M_DCLICK ( BUTTON1_DOUBLE_CLICKED \ + | BUTTON2_DOUBLE_CLICKED \ + | BUTTON3_DOUBLE_CLICKED \ + | BUTTON4_DOUBLE_CLICKED \ + | BUTTON5_DOUBLE_CLICKED) +#define M_TCLICK ( BUTTON1_TRIPLE_CLICKED \ + | BUTTON2_TRIPLE_CLICKED \ + | BUTTON3_TRIPLE_CLICKED \ + | BUTTON4_TRIPLE_CLICKED \ + | BUTTON5_TRIPLE_CLICKED) + static void -mouse_event (qwaq_resources_t *res, MEVENT *mevent) +mouse_event (qwaq_resources_t *res, const MEVENT *mevent) { + int mask = mevent->bstate; qwaq_event_t event = {}; - event.event_type = qe_mouse; + event.mouse.x = mevent->x; event.mouse.y = mevent->y; event.mouse.buttons = mevent->bstate; + if (mask & M_MOVE) { + event.what = qe_mousemove; + mask &= ~M_MOVE; + } + if (mask & M_PRESS) { + event.what = qe_mousedown; + mask &= ~M_PRESS; + } + if (mask & M_RELEASE) { + event.what = qe_mouseup; + mask &= ~M_RELEASE; + } + if (mask & M_CLICK) { + event.what = qe_mouseclick; + mask &= ~M_CLICK; + event.mouse.click = 1; + } + if (mask & M_DCLICK) { + event.what = qe_mouseclick; + mask &= ~M_DCLICK; + event.mouse.click = 2; + } + if (mask & M_TCLICK) { + event.what = qe_mouseclick; + mask &= ~M_TCLICK; + event.mouse.click = 3; + } add_event (res, &event); } @@ -639,7 +709,7 @@ static void key_event (qwaq_resources_t *res, int key) { qwaq_event_t event = {}; - event.event_type = qe_key; + event.what = qe_keydown; event.key = key; add_event (res, &event); } diff --git a/ruamoko/qwaq/qwaq-screen.h b/ruamoko/qwaq/qwaq-screen.h index 8c83abb6e..1294b2e28 100644 --- a/ruamoko/qwaq/qwaq-screen.h +++ b/ruamoko/qwaq/qwaq-screen.h @@ -8,7 +8,7 @@ @class View; @class Array; -@interface Screen: Object +@interface Screen: Object { Rect rect; Array *views; diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index 4e68cae30..401e0e41e 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -55,23 +55,28 @@ -handleEvent: (qwaq_event_t *) event { - switch (event.event_type) { + if (event.what & qe_mouse) { + [self printf:"%04x %2d %2d %d %08x\r", event.what, event.mouse.x, event.mouse.y, event.mouse.click, event.mouse.buttons]; + [self redraw]; + Point p = { event.mouse.x, event.mouse.y }; + for (int i = [mouse_handler_rects count]; i-->0; ) { + //if (rectContainsPoint((Rect*)mouse_handler_rects._objs[i], &p)) { + // [mouse_handlers._objs[i] handleEvent: event]; + // break; + //} + } + } else if (event.what & qe_focused) { + [focused_handlers + makeObjectsPerformSelector: @selector(handleEvent:) + withObject: (id) event]; + } + switch (event.what) { case qe_none: break; case qe_key: case qe_command: - [focused_handlers - makeObjectsPerformSelector: @selector(handleEvent:) - withObject: (id) event]; break; case qe_mouse: - Point p = { event.mouse.x, event.mouse.y }; - for (int i = [mouse_handler_rects count]; i-->0; ) { - //if (rectContainsPoint((Rect*)mouse_handler_rects._objs[i], &p)) { - // [mouse_handlers._objs[i] handleEvent: event]; - // break; - //} - } break; } return self; @@ -87,8 +92,8 @@ -redraw { - [self error:"hmm"]; update_panels (); + wrefresh(window); doupdate (); return self; } @@ -105,6 +110,11 @@ return self; } +- (Rect *) getRect +{ + return ▭ +} + -setParent: parent { return self; diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index af53a6546..d99b21b3c 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -26,7 +26,7 @@ -handleEvent: (qwaq_event_t *) event { - switch (event.event_type) { + switch (event.what) { case qe_mouse: mvwprintf(window, 0, 3, "%2d %2d %08x", event.mouse.x, event.mouse.y, event.mouse.buttons); @@ -46,7 +46,7 @@ if (focusedView) { [focusedView handleEvent: event]; for (int i = [views count]; - event.event_type != qe_none && i--> 0; ) { + event.what != qe_none && i--> 0; ) { View *v = [views objectAtIndex: i]; [v handleEvent: event]; } From 0bb4279a9f14aef844d810aa8c9e6351da1823b3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 01:45:38 +0900 Subject: [PATCH 194/444] [qfcc] Handle bitwise not of enums It looks like I need to handle other unary expressions too, but another time. --- tools/qfcc/source/expr.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 00d2b60ee..ecdc3606c 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1407,6 +1407,7 @@ unary_expr (int op, expr_t *e) quat_t q; const char *s; expr_t *new; + type_t *t; convert_name (e); if (e->type == ex_error) @@ -1568,6 +1569,11 @@ unary_expr (int op, expr_t *e) case ev_short: return new_short_expr (~expr_short (e)); case ev_invalid: + t = get_type (e); + if (t->meta == ty_enum) { + return new_integer_expr (~expr_integer (e)); + } + break; case ev_type_count: case ev_void: break; From 896c14f33a1afe2297ab056546e5679bd8d6020a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 01:46:56 +0900 Subject: [PATCH 195/444] [qfcc] Support anonymous structs in ivars Missed this earlier. --- tools/qfcc/source/qc-parse.y | 18 ++++++++++++++++++ tools/qfcc/source/symtab.c | 3 ++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 46cf09e7e..a6c5d99e4 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1873,6 +1873,24 @@ ivar_decls ivar_decl : type ivars + | type + { + if (is_anonymous_struct ($1)) { + // anonymous struct/union + // type->name always begins with "tag " + $1.sym = new_symbol (va (".anonymous.%s", $1.type->name + 4)); + $1.sym->type = $1.type; + $1.sym->sy_type = sy_var; + $1.sym->visibility = vis_anonymous; + symtab_addsymbol (current_symtab, $1.sym); + if (!$1.sym->table) { + error (0, "duplicate field `%s'", $1.sym->name); + } + } else { + // bare type + warning (0, "declaration does not declare anything"); + } + } ; ivars diff --git a/tools/qfcc/source/symtab.c b/tools/qfcc/source/symtab.c index 377671e8a..f94e8d71a 100644 --- a/tools/qfcc/source/symtab.c +++ b/tools/qfcc/source/symtab.c @@ -182,7 +182,8 @@ symtab_flat_copy (symtab_t *symtab, symtab_t *parent) newtab = new_symtab (parent, stab_local); do { for (symbol = symtab->symbols; symbol; symbol = symbol->next) { - if (Hash_Find (newtab->tab, symbol->name)) + if (symbol->visibility == vis_anonymous + || Hash_Find (newtab->tab, symbol->name)) continue; newsym = copy_symbol (symbol); symtab_addsymbol (newtab, newsym); From efcbbbb6417a8e9f45d032f3c961098e751be325 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 08:50:29 +0900 Subject: [PATCH 196/444] [qfcc] Catch use of missing superclass interfaces --- tools/qfcc/source/qc-parse.y | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index a6c5d99e4..3966b9cf9 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1630,6 +1630,10 @@ class_with_super new_class_with_super : new_class_name ':' class_name { + if (!$3->ivars) { + error (0, "cannot find interface declaration for `%s', " + "superclass of `%s'", $3->name, $1->name); + } $1->super_class = $3; $$ = $1; } From 78b71c28fe738028d4a130e5b403de078559e5ec Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 11:03:23 +0900 Subject: [PATCH 197/444] [qfcc] Make reloc functions const-correct --- tools/qfcc/include/reloc.h | 19 ++++++++++--------- tools/qfcc/source/reloc.c | 14 +++++++------- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/tools/qfcc/include/reloc.h b/tools/qfcc/include/reloc.h index 2272dab5d..dc6e802c8 100644 --- a/tools/qfcc/include/reloc.h +++ b/tools/qfcc/include/reloc.h @@ -68,7 +68,7 @@ typedef enum { */ typedef struct reloc_s { struct reloc_s *next; ///< next reloc in reloc chain - struct ex_label_s *label; ///< instruction label for *_op relocs + const struct ex_label_s *label; ///< instruction label for *_op relocs struct defspace_s *space; ///< the space containing the location in ///< need of adjustment for def_* relocations ///< (op_* relocations always use the code @@ -78,7 +78,7 @@ typedef struct reloc_s { reloc_type type; ///< type type of relocation to perform int line; ///< current source line when creating reloc string_t file; ///< current source file when creating reloc - void *return_address; ///< for debugging + const void *return_address; ///< for debugging } reloc_t; struct statement_s; @@ -147,7 +147,7 @@ void reloc_op_def_ofs (struct def_s *def, int offset, int field); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_def (struct def_s *def, struct def_s *location); +void reloc_def_def (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing a def. @@ -162,7 +162,7 @@ void reloc_def_def (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_def_ofs (struct def_s *def, struct def_s *location); +void reloc_def_def_ofs (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing a function. @@ -177,7 +177,7 @@ void reloc_def_def_ofs (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_func (struct function_s *func, struct def_s *location); +void reloc_def_func (struct function_s *func, const struct def_s *location); /** Create a relocation record for a data location referencing a string. @@ -191,7 +191,7 @@ void reloc_def_func (struct function_s *func, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_string (struct def_s *location); +void reloc_def_string (const struct def_s *location); /** Create a relocation record for a data location referencing a field. @@ -206,7 +206,7 @@ void reloc_def_string (struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_field (struct def_s *def, struct def_s *location); +void reloc_def_field (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing a field. @@ -221,7 +221,7 @@ void reloc_def_field (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_field_ofs (struct def_s *def, struct def_s *location); +void reloc_def_field_ofs (struct def_s *def, const struct def_s *location); /** Create a relocation record for a data location referencing an instruction. @@ -237,7 +237,8 @@ void reloc_def_field_ofs (struct def_s *def, struct def_s *location); adjusted. As the def's space and offset will be copied into the relocation record, a dummy def may be used. */ -void reloc_def_op (struct ex_label_s *label, struct def_s *location); +void reloc_def_op (const struct ex_label_s *label, + const struct def_s *location); void reloc_attach_relocs (reloc_t *relocs, reloc_t **location); diff --git a/tools/qfcc/source/reloc.c b/tools/qfcc/source/reloc.c index 29f1663d8..7c4ed3ce3 100644 --- a/tools/qfcc/source/reloc.c +++ b/tools/qfcc/source/reloc.c @@ -210,7 +210,7 @@ reloc_op_def_ofs (def_t *def, int offset, int field) } void -reloc_def_def (def_t *def, def_t *location) +reloc_def_def (def_t *def, const def_t *location) { reloc_t *ref; @@ -221,7 +221,7 @@ reloc_def_def (def_t *def, def_t *location) } void -reloc_def_def_ofs (def_t *def, def_t *location) +reloc_def_def_ofs (def_t *def, const def_t *location) { reloc_t *ref; @@ -232,7 +232,7 @@ reloc_def_def_ofs (def_t *def, def_t *location) } void -reloc_def_func (function_t *func, def_t *location) +reloc_def_func (function_t *func, const def_t *location) { reloc_t *ref; @@ -243,7 +243,7 @@ reloc_def_func (function_t *func, def_t *location) } void -reloc_def_string (def_t *location) +reloc_def_string (const def_t *location) { reloc_t *ref; @@ -254,7 +254,7 @@ reloc_def_string (def_t *location) } void -reloc_def_field (def_t *def, def_t *location) +reloc_def_field (def_t *def, const def_t *location) { reloc_t *ref; @@ -265,7 +265,7 @@ reloc_def_field (def_t *def, def_t *location) } void -reloc_def_field_ofs (def_t *def, def_t *location) +reloc_def_field_ofs (def_t *def, const def_t *location) { reloc_t *ref; @@ -276,7 +276,7 @@ reloc_def_field_ofs (def_t *def, def_t *location) } void -reloc_def_op (ex_label_t *label, def_t *location) +reloc_def_op (const ex_label_t *label, const def_t *location) { reloc_t *ref; From 1b2a806f2829b1b756d577e4c8e6981c7daa04f5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 11:04:22 +0900 Subject: [PATCH 198/444] [qfcc] Fix test that failed due to improved warnings --- tools/qfcc/test/anonstruct.r | 5 ----- 1 file changed, 5 deletions(-) diff --git a/tools/qfcc/test/anonstruct.r b/tools/qfcc/test/anonstruct.r index a426d8f61..684ae8c2b 100644 --- a/tools/qfcc/test/anonstruct.r +++ b/tools/qfcc/test/anonstruct.r @@ -17,11 +17,6 @@ typedef struct anon_s { }; } anon_t; -union { - int xsnafu; - float xfizzle; -}; - int foo (float f) { anon_t anon; From 9ccfe8aefc2de99f2411ae080656887e113ffda7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 11:05:13 +0900 Subject: [PATCH 199/444] [qfcc] Rewrite init_elements The end goal was to fix erroneous non-constant initializer errors for the following (ie, nested initializer blocks): typedef struct { int x; int y; } Point; typedef struct { int width; int height; } Extent; typedef struct Rect_s { Point offset; Extent extent; } Rect; Rect makeRect (int xpos, int ypos, int xlen, int ylen) { Rect rect = {{xpos, ypos}, {xlen, ylen}}; return rect; } However, it turned out that nested initializer blocks for local variables did not work at all in that the relocations were lost because fake defs were being created for the generated instructions. Thus, instead of creating fake defs, simply record the offset relative to the base def, the type, and the basic type initializer expression, then generate instructions that all refer to the correct def but with a relative offset. Other than using the new element system, static initializers are largely unaffected. --- tools/qfcc/source/def.c | 285 +++++++++++++++++++++++----------------- 1 file changed, 167 insertions(+), 118 deletions(-) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index c0332be60..93152b6db 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -62,7 +62,37 @@ #include "type.h" #include "value.h" +typedef struct element_s { + struct element_s *next; + int offset; + type_t *type; + expr_t *expr; +} element_t; + +typedef struct element_chain_s { + element_t *head; + element_t **tail; +} element_chain_t; + static def_t *defs_freelist; +static element_t *elements_freelist; + +static element_t * +new_element (void) +{ + element_t *element; + ALLOC (256, element_t, elements, element); + return element; +} + +static element_t * +append_element (element_chain_t *element_chain, element_t *element) +{ + element->next = 0; + *element_chain->tail = element; + element_chain->tail = &element->next; + return element; +} static void set_storage_bits (def_t *def, storage_class_t storage) @@ -303,141 +333,158 @@ zero_memory (expr_t *local_expr, def_t *def, type_t *zero_type, } static void -init_elements (struct def_s *def, expr_t *eles) +init_elements_nil (def_t *def) { - expr_t *e, *c; - int count, i, num_elements, base_offset; - pr_type_t *g; - def_t *elements; + if (def->local && local_expr) { + // memset to 0 + int init_size = type_size (def->type); + int init_offset = 0; - base_offset = def->offset; - if (def->local && local_expr) - base_offset = 0; - if (eles->type == ex_nil) { - if (def->local && local_expr) { - // memset to 0 - int init_size = type_size (def->type); - int init_offset = 0; - - if (options.code.progsversion != PROG_ID_VERSION) { - init_offset = zero_memory (local_expr, def, &type_zero, - init_size, init_offset); - } - // probably won't happen any time soon, but who knows... - if (options.code.progsversion != PROG_ID_VERSION - && init_size - init_offset >= type_size (&type_quaternion)) { - init_offset = zero_memory (local_expr, def, &type_quaternion, - init_size, init_offset); - } - if (init_size - init_offset >= type_size (&type_vector)) { - init_offset = zero_memory (local_expr, def, &type_vector, - init_size, init_offset); - } - if (options.code.progsversion != PROG_ID_VERSION - && init_size - init_offset >= type_size (&type_double)) { - init_offset = zero_memory (local_expr, def, &type_double, - init_size, init_offset); - } - if (init_size - init_offset >= type_size (type_default)) { - zero_memory (local_expr, def, type_default, - init_size, init_offset); - } + if (options.code.progsversion != PROG_ID_VERSION) { + init_offset = zero_memory (local_expr, def, &type_zero, + init_size, init_offset); + } + // probably won't happen any time soon, but who knows... + if (options.code.progsversion != PROG_ID_VERSION + && init_size - init_offset >= type_size (&type_quaternion)) { + init_offset = zero_memory (local_expr, def, &type_quaternion, + init_size, init_offset); + } + if (init_size - init_offset >= type_size (&type_vector)) { + init_offset = zero_memory (local_expr, def, &type_vector, + init_size, init_offset); + } + if (options.code.progsversion != PROG_ID_VERSION + && init_size - init_offset >= type_size (&type_double)) { + init_offset = zero_memory (local_expr, def, &type_double, + init_size, init_offset); + } + if (init_size - init_offset >= type_size (type_default)) { + zero_memory (local_expr, def, type_default, + init_size, init_offset); } - // it's a global, so already initialized to 0 - return; } - if (is_array (def->type)) { - type_t *array_type = def->type->t.array.type; - int array_size = def->type->t.array.size; - elements = calloc (array_size, sizeof (def_t)); + // it's a global, so already initialized to 0 +} + +static void +build_element_chain (element_chain_t *element_chain, type_t *type, + expr_t *eles, int base_offset) +{ + expr_t *e = eles->e.block.head; + + if (is_array (type)) { + type_t *array_type = type->t.array.type; + int array_size = type->t.array.size; + int i; + for (i = 0; i < array_size; i++) { - elements[i].type = array_type; - elements[i].space = def->space; - elements[i].offset = base_offset + i * type_size (array_type); + int offset = base_offset + i * type_size (array_type); + if (e && e->type == ex_block) { + build_element_chain (element_chain, array_type, e, offset); + } else { + element_t *element = new_element (); + element->type = array_type; + element->offset = offset; + element->expr = e; // null will be treated as nil + append_element (element_chain, element); + } + if (e) { + e = e->next; + } } - num_elements = i; - } else if (is_struct (def->type) || is_vector (def->type) - || is_quaternion (def->type)) { - symtab_t *symtab = def->type->t.symtab; + } else if (is_struct (type) || is_vector (type) || is_quaternion (type)) { + symtab_t *symtab = type->t.symtab; symbol_t *field; - for (i = 0, field = symtab->symbols; field; field = field->next) { - if (field->sy_type != sy_var) + for (field = symtab->symbols; field; field = field->next) { + int offset = base_offset + field->s.offset; + if (field->sy_type != sy_var + || field->visibility == vis_anonymous) { continue; - i++; + } + if (e && e->type == ex_block) { + build_element_chain (element_chain, field->type, e, offset); + } else { + element_t *element = new_element (); + element->type = field->type; + element->offset = offset; + element->expr = e; // null will be treated as nil + append_element (element_chain, element); + } + if (e) { + e = e->next; + } } - elements = calloc (i, sizeof (def_t)); - for (i = 0, field = symtab->symbols; field; field = field->next) { - if (field->sy_type != sy_var) - continue; - elements[i].type = field->type; - elements[i].space = def->space; - elements[i].offset = base_offset + field->s.offset; - i++; - } - num_elements = i; } else { error (eles, "invalid initializer"); + } + if (e && e->next && options.warnings.initializer) { + warning (eles, "excessive elements in initializer"); + } +} + +static void +init_elements (struct def_s *def, expr_t *eles) +{ + expr_t *c; + pr_type_t *g; + element_chain_t element_chain; + element_t *element; + + if (eles->type == ex_nil) { + init_elements_nil (def); return; } - for (count = 0, e = eles->e.block.head; e; count++, e = e->next) { - convert_name (e); - if (e->type == ex_nil && count < num_elements - && !(is_array (elements[count].type) - || is_struct (elements[count].type))) { - convert_nil (e, elements[count].type); - } - if (e->type == ex_error) { - free (elements); - return; - } - } - if (count > num_elements) { - if (options.warnings.initializer) - warning (eles, "excessive elements in initializer"); - count = num_elements; - } - for (i = 0, e = eles->e.block.head; i < count; i++, e = e->next) { - g = D_POINTER (pr_type_t, &elements[i]); - c = constant_expr (e); - // nil will not survive as nil to this point if array or struct - if (c->type == ex_block || c->type == ex_nil) { - if (!is_array (elements[i].type) - && !is_struct (elements[i].type)) { - error (e, "type mismatch in initializer"); - continue; - } - init_elements (&elements[i], c); - continue; - } else if (c->type == ex_labelref) { - def_t loc; - loc.space = elements[i].space; - loc.offset = elements[i].offset; - reloc_def_op (c->e.labelref.label, &loc); - continue; - } else if (c->type == ex_value) { - if (c->e.value->lltype == ev_integer - && elements[i].type->type == ev_float) - convert_int (c); - if (get_type (c) != elements[i].type) { - error (e, "type mismatch in initializer"); - continue; - } - } else { - if (!def->local || !local_expr) { - error (e, "non-constant initializer"); - continue; - } - } - if (def->local && local_expr) { - int offset = elements[i].offset; - type_t *type = elements[i].type; + + element_chain.head = 0; + element_chain.tail = &element_chain.head; + build_element_chain (&element_chain, def->type, eles, 0); + + if (def->local && local_expr) { + for (element = element_chain.head; element; element = element->next) { + int offset = element->offset; + type_t *type = element->type; expr_t *ptr = new_pointer_expr (offset, type, def); + if (element->expr) { + c = constant_expr (element->expr); + } else { + c = convert_nil (new_nil_expr (), type); + } append_expr (local_expr, assign_expr (unary_expr ('.', ptr), c)); - } else { - if (c->type != ex_value) + } + } else { + def_t dummy = *def; + for (element = element_chain.head; element; element = element->next) { + if (element->expr) { + c = constant_expr (element->expr); + } else { + c = convert_nil (new_nil_expr (), element->type); + } + dummy.offset = def->offset + element->offset; + g = D_POINTER (pr_type_t, &dummy); + if (c->type == ex_labelref) { + reloc_def_op (c->e.labelref.label, &dummy); + continue; + } else if (c->type == ex_value) { + if (c->e.value->lltype == ev_integer + && is_float (element->type)) { + convert_int (c); + } + if (get_type (c) != element->type) { + error (c, "type mismatch in initializer"); + continue; + } + } else { + if (!def->local || !local_expr) { + error (c, "non-constant initializer"); + continue; + } + } + if (c->type != ex_value) { internal_error (c, "bogus expression type in init_elements()"); + } if (c->e.value->lltype == ev_string) { EMIT_STRING (def->space, g->string_var, c->e.value->v.string_val); @@ -446,7 +493,9 @@ init_elements (struct def_s *def, expr_t *eles) } } } - free (elements); + + *element_chain.tail = elements_freelist; + elements_freelist = element_chain.head; } static void From 1459361cbdd1ca55729a0d156f10911c365172d5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 11:48:15 +0900 Subject: [PATCH 200/444] [qfcc] Set builtin function def flags This fixes the missing redefinition error when a builtin is defined twice (and thus corrupting the function chain). --- tools/qfcc/source/function.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index e2b87d04a..ff54b2ce5 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -650,6 +650,9 @@ build_builtin_function (symbol_t *sym, expr_t *bi_val, int far) if (sym->s.func->def->external) return 0; + sym->s.func->def->initialized = 1; + sym->s.func->def->constant = 1; + sym->s.func->def->nosave = 1; add_function (sym->s.func); if (is_integer_val (bi_val)) From 65a5e4f2a49428629e86135f95b6bd1de15c275d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 12:52:37 +0900 Subject: [PATCH 201/444] [qfcc] Allow inherited methods to satisfy protocols I suspect that the current state of things will produce problems later on, but this works for now. --- tools/qfcc/include/method.h | 9 ++++++- tools/qfcc/source/class.c | 18 +++++++++++-- tools/qfcc/source/method.c | 50 +++++++++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/include/method.h b/tools/qfcc/include/method.h index 6b02bbe00..c64f04ade 100644 --- a/tools/qfcc/include/method.h +++ b/tools/qfcc/include/method.h @@ -58,6 +58,10 @@ typedef struct methodlist_s { int instance; ///< used only for emitting } methodlist_t; +typedef struct methodset_s { + struct hashtab_s *tab; +} methodset_t; + typedef struct keywordarg_s { // the first two fields match the first two fields of param_t in // functionl.h @@ -80,9 +84,12 @@ struct symbol_s *method_symbol (struct class_type_s *class_type, void method_set_param_names (method_t *dst, method_t *src); methodlist_t *new_methodlist (void); +methodset_t *new_methodset (void); +void methodset_add_methods (methodset_t *methodset, methodlist_t *methods); +int methodset_contains_method (methodset_t *methodset, method_t *method); //NOTE frees the source list and any methods not copied void merge_method_lists (methodlist_t *dst, methodlist_t *src); -void copy_methods (methodlist_t *dst, methodlist_t *src); +void copy_methods (methodlist_t *dst, methodlist_t *src, methodset_t *except); int method_compare (method_t *m1, method_t *m2); keywordarg_t *new_keywordarg (const char *selector, struct expr_s *expr); diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 4b331d237..5a9c5c6e0 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -642,16 +642,23 @@ class_add_protocols (class_t *class, protocollist_t *protocols) int i; protocol_t *p; methodlist_t *methods; + methodset_t *except; + class_t *super; if (!protocols) return; methods = class->methods; + except = new_methodset (); + for (super = class->super_class; super; super = super->super_class) { + methodset_add_methods (except, super->methods); + } + for (i = 0; i < protocols->count; i++) { p = protocols->list[i]; if (p->methods) { - copy_methods (methods, p->methods); + copy_methods (methods, p->methods, except); } else { warning (0, "definition of protocol `%s' not found", p->name); } @@ -1269,15 +1276,22 @@ category_add_protocols (category_t *category, protocollist_t *protocols) int i; protocol_t *p; methodlist_t *methods; + methodset_t *except; + class_t *class; if (!protocols) return; methods = category->methods; + except = new_methodset (); + for (class = category->class; class; class = class->super_class) { + methodset_add_methods (except, class->methods); + } + for (i = 0; i < protocols->count; i++) { p = protocols->list[i]; - copy_methods (methods, p->methods); + copy_methods (methods, p->methods, except); if (p->protocols) category_add_protocols (category, p->protocols); } diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index c5bd8b334..e68ad857f 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -205,6 +205,52 @@ new_methodlist (void) return l; } +static uintptr_t +methodset_get_hash (const void *_method, void *unused) +{ + method_t *method = (method_t *) _method; + uintptr_t hash; + + hash = Hash_String (method->name); + return hash ^ (method->instance << 3); +} + +static int +methodset_compare (const void *_m1, const void *_m2, void *unused) +{ + method_t *m1 = (method_t *) _m1; + method_t *m2 = (method_t *) _m2; + int cmp; + + cmp = strcmp (m1->name, m2->name) == 0; + return cmp && m1->instance == m2->instance; +} + +methodset_t * +new_methodset (void) +{ + methodset_t *s = malloc (sizeof (*s)); + s->tab = Hash_NewTable (31, 0, 0, 0); + Hash_SetHashCompare (s->tab, methodset_get_hash, methodset_compare); + return s; +} + +void +methodset_add_methods (methodset_t *methodset, methodlist_t *methods) +{ + method_t *m; + + for (m = methods->head; m; m = m->next) { + Hash_AddElement (methodset->tab, m); + } +} + +int +methodset_contains_method (methodset_t *methodset, method_t *method) +{ + return Hash_FindElement (methodset->tab, method) != 0; +} + static int __attribute__((pure)) method_in_list (methodlist_t *method_list, method_t *method) { @@ -238,13 +284,13 @@ merge_method_lists (methodlist_t *dst, methodlist_t *src) } void -copy_methods (methodlist_t *dst, methodlist_t *src) +copy_methods (methodlist_t *dst, methodlist_t *src, methodset_t *except) { method_t *s, *d; param_t *self; for (s = src->head; s; s = s->next) { - if (method_in_list (dst, s)) { + if (methodset_contains_method (except, s) || method_in_list (dst, s)) { debug (0, "skipping duplicate method: %s", s->name); continue; } From ccaa4ad3d21334d3c59047055f31c53e8d876b49 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 14:14:20 +0900 Subject: [PATCH 202/444] [qfcc] Catch assignment of void* to class pointers id and other class pointers imply that the object can receive messages, but void * has no such implication, so treat it as a mismatch. --- tools/qfcc/source/class.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 5a9c5c6e0..60cfe27ca 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -445,8 +445,14 @@ obj_types_assignable (const type_t *dst, const type_t *src) int i; //puts ("%$$\"$#%"); - if (!obj_is_classptr (dst) || !obj_is_classptr (src)) + if (!obj_is_classptr (src)) { + // if dst is a class pointer, then the types are not compatible, + // otherwise unknown + return obj_is_classptr (dst) - 1; + } + if (!obj_is_classptr (dst)) { return -1; + } dst_is_proto = obj_is_id (dst) && (dst_protos = obj_get_protos (dst)); src_is_proto = obj_is_id (src) && (src_protos = obj_get_protos (src)); From 669c8f43d8817605acd25e14a1219121d2b9586a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 14:48:49 +0900 Subject: [PATCH 203/444] whitespace --- tools/qfcc/source/expr.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index ecdc3606c..c384bcfe5 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1645,7 +1645,6 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) expr_t *call; expr_t *err = 0; - for (e = params; e; e = e->next) { if (e->type == ex_error) return e; From 59db90d17760536976443e8170d46e290b8dcafd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 14:48:53 +0900 Subject: [PATCH 204/444] [qfcc] Fix method not found warnings It turns out they should not be optional, but do need to be smarter about when and which. So another two FIXMEs gone :) --- tools/qfcc/source/class.c | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 60cfe27ca..574a484b9 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -1136,19 +1136,15 @@ class_message_response (class_t *class, int class_msg, expr_t *sel) } c = c->super_class; } - //FIXME right option? - if (options.warnings.interface_check) - warning (sel, "%s may not respond to %c%s", class->name, - class_msg ? '+' : '-', selector->name); + warning (sel, "%s may not respond to %c%s", class->name, + class_msg ? '+' : '-', selector->name); } m = find_method (selector->name); - if (m) - return m; - //FIXME right option? - if (options.warnings.interface_check) + if (!m && (!class || class->type == &type_obj_object)) { warning (sel, "could not find method for %c%s", class_msg ? '+' : '-', selector->name); - return 0; + } + return m; } static uintptr_t From 2ddfe2ef0721f17b31cc7c9560ea002db2646e67 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 15:00:42 +0900 Subject: [PATCH 205/444] [libr] Accept void * for performSelector:withObject: It's up to the receiver what the object should be. --- ruamoko/include/Array.h | 2 +- ruamoko/include/Object.h | 6 +++--- ruamoko/lib/Array.r | 4 ++-- ruamoko/lib/Object.r | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/ruamoko/include/Array.h b/ruamoko/include/Array.h index 113e466a9..060f50956 100644 --- a/ruamoko/include/Array.h +++ b/ruamoko/include/Array.h @@ -271,7 +271,7 @@ Iteratively sends #performSelector:withObject: to each contained object. */ - (void) makeObjectsPerformSelector: (SEL)selector - withObject: (id)arg; + withObject: (void *)arg; //\} @end diff --git a/ruamoko/include/Object.h b/ruamoko/include/Object.h index 475e0bec9..eb10e55ef 100644 --- a/ruamoko/include/Object.h +++ b/ruamoko/include/Object.h @@ -20,10 +20,10 @@ - (id) performSelector: (SEL)aSelector; - (id) performSelector: (SEL)aSelector - withObject: (id)anObject; + withObject: (void *)anObject; - (id) performSelector: (SEL)aSelector - withObject: (id)anObject - withObject: (id)anotherObject; + withObject: (void *)anObject + withObject: (void *)anotherObject; - (BOOL) respondsToSelector: (SEL)aSelector; - (BOOL) conformsToProtocol: (Protocol *)aProtocol; diff --git a/ruamoko/lib/Array.r b/ruamoko/lib/Array.r index 842076f72..2946141cc 100644 --- a/ruamoko/lib/Array.r +++ b/ruamoko/lib/Array.r @@ -162,7 +162,7 @@ - (id) objectAtIndex: (unsigned)index { if (index >= count) // FIXME: need exceptions - [self error: "-replaceObjectAtIndex:withObject: index out of range"]; + [self error: "-objectAtIndex:withObject: index out of range"]; return _objs[index]; } @@ -401,7 +401,7 @@ } - (void) makeObjectsPerformSelector: (SEL)selector - withObject: (id)anObject + withObject: (void *)anObject { local int i; diff --git a/ruamoko/lib/Object.r b/ruamoko/lib/Object.r index dba6b5071..d85a78064 100644 --- a/ruamoko/lib/Object.r +++ b/ruamoko/lib/Object.r @@ -247,7 +247,7 @@ BOOL (id object) object_is_meta_class = #0; return msg (self, aSelector); } -- (id) performSelector: (SEL)aSelector withObject: (id)anObject +- (id) performSelector: (SEL)aSelector withObject: (void *)anObject { local IMP msg = nil; // FIXME teach qfcc about noreturn @@ -260,8 +260,8 @@ BOOL (id object) object_is_meta_class = #0; } - (id) performSelector: (SEL)aSelector - withObject: (id)anObject - withObject: (id)anotherObject + withObject: (void *)anObject + withObject: (void *)anotherObject { local IMP msg; From a4582e526d6e7cb2cf414240d24e6891d32f59ca Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 15:02:40 +0900 Subject: [PATCH 206/444] [cl_menu,scheme] Clean up after tightened pointer checks --- ruamoko/cl_menu/options.r | 12 ++++++------ ruamoko/cl_menu/plistmenu.r | 2 +- ruamoko/scheme/Symbol.r | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ruamoko/cl_menu/options.r b/ruamoko/cl_menu/options.r index e0529c23e..a228b1062 100644 --- a/ruamoko/cl_menu/options.r +++ b/ruamoko/cl_menu/options.r @@ -130,7 +130,7 @@ MENU_video_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"video_options"]); - video_options = ret.pointer_val; + video_options = (Group *) ret.pointer_val; } Menu_End (); @@ -177,7 +177,7 @@ MENU_audio_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"audio_options"]); - audio_options = ret.pointer_val; + audio_options = (Group *) ret.pointer_val; } Menu_End (); @@ -224,7 +224,7 @@ MENU_control_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"control_options"]); - control_options = ret.pointer_val; + control_options = (Group *) ret.pointer_val; } MENU_control_binding (); //FIXME how to hook in the bindings menu? @@ -275,7 +275,7 @@ MENU_feature_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"feature_options"]); - feature_options = ret.pointer_val; + feature_options = (Group *) ret.pointer_val; } Menu_End (); @@ -361,7 +361,7 @@ MENU_player_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"player_options"]); - player_options = ret.pointer_val; + player_options = (Group *) ret.pointer_val; } Menu_End (); @@ -426,7 +426,7 @@ MENU_network_options (PLItem *plist) if (plist) { ret = object_from_plist ([(PLDictionary*) plist getObjectForKey:"network_options"]); - network_options = ret.pointer_val; + network_options = (Group *) ret.pointer_val; } Menu_End (); diff --git a/ruamoko/cl_menu/plistmenu.r b/ruamoko/cl_menu/plistmenu.r index d5e722377..bdece6082 100644 --- a/ruamoko/cl_menu/plistmenu.r +++ b/ruamoko/cl_menu/plistmenu.r @@ -103,7 +103,7 @@ array_from_plist (PLArray *plarray) count = [plarray count]; for (i = 0; i < count; i++) { ret = object_from_plist ([plarray getObjectAtIndex:i]); - [array addObject: ret.pointer_val]; + [array addObject: (id) ret.pointer_val]; } ret.pointer_val = array; return ret; diff --git a/ruamoko/scheme/Symbol.r b/ruamoko/scheme/Symbol.r index b83f3dbd6..2adfc6a25 100644 --- a/ruamoko/scheme/Symbol.r +++ b/ruamoko/scheme/Symbol.r @@ -45,7 +45,7 @@ Symbol *symbol (string str) { local Symbol *res; - if ((res = Hash_Find (symbols, s))) { + if ((res = (Symbol *) Hash_Find (symbols, s))) { return res; } else { res = (Symbol*) [self newFromString: s]; From 1bf56b28ac8dd2e885c86085eb8fe5a9da0e5640 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 15:39:34 +0900 Subject: [PATCH 207/444] [qfcc] Warn when messaging a forward-declared class But only once. --- tools/qfcc/include/class.h | 1 + tools/qfcc/source/class.c | 10 +++++++++- tools/qfcc/source/qc-parse.y | 5 ++++- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index 726a272be..7f7f0920d 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -48,6 +48,7 @@ typedef struct class_type_s { typedef struct class_s { int defined; + int interface_declared; const char *name; struct class_s *super_class; struct category_s *categories; diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 574a484b9..8e2d458e1 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -1042,7 +1042,10 @@ class_find_ivar (class_t *class, int vis, const char *name) symbol_t *ivar; if (!class->ivars) { - error (0, "accessing incomplete type %s", class->name); + if (!class->interface_declared) { + class->interface_declared = 1; + error (0, "accessing incomplete type %s", class->name); + } return 0; } ivar = symtab_lookup (class->ivars, name); @@ -1119,6 +1122,11 @@ class_message_response (class_t *class, int class_msg, expr_t *sel) if (!selector) return 0; if (class && class->type != &type_obj_object) { + if (!class->interface_declared) { + class->interface_declared = 1; + warning (0, "cannot find interface declaration for `%s'", + class->name); + } while (c) { for (cat = c->categories; cat; cat = cat->next) { for (m = cat->methods->head; m; m = m->next) { diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 3966b9cf9..a99f8c6b5 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1612,6 +1612,7 @@ new_class_name $1 = check_redefined ($1); $$ = get_class ($1, 1); } + $$->interface_declared = 1; current_class = &$$->class_type; if (!$1->table) symtab_addsymbol (current_symtab, $1); @@ -1630,10 +1631,12 @@ class_with_super new_class_with_super : new_class_name ':' class_name { - if (!$3->ivars) { + if (!$3->interface_declared) { + $3->interface_declared = 1; error (0, "cannot find interface declaration for `%s', " "superclass of `%s'", $3->name, $1->name); } + $1->interface_declared = 1; $1->super_class = $3; $$ = $1; } From c377b324a10a5bbbbfa4ed469ea0b518e43cf0ad Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 15:44:53 +0900 Subject: [PATCH 208/444] [qwaq] Add Group and clean up lots of mess Things are finally doing something again, and getting closer to having a moveable window. --- ruamoko/qwaq/Makefile.am | 6 +-- ruamoko/qwaq/event.h | 1 + ruamoko/qwaq/qwaq-app.r | 18 +++++---- ruamoko/qwaq/qwaq-curses.c | 50 +++++++++++++++++++++++++ ruamoko/qwaq/qwaq-curses.h | 2 + ruamoko/qwaq/qwaq-draw.h | 3 +- ruamoko/qwaq/qwaq-group.h | 17 +++++++++ ruamoko/qwaq/qwaq-group.r | 60 ++++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-rect.h | 17 +++++---- ruamoko/qwaq/qwaq-screen.h | 18 ++------- ruamoko/qwaq/qwaq-screen.r | 51 +------------------------ ruamoko/qwaq/qwaq-view.h | 48 ++++++++++++++++++++++-- ruamoko/qwaq/qwaq-view.r | 76 ++++++++++++++++++++++++++++++++++---- ruamoko/qwaq/qwaq-window.h | 7 ++-- ruamoko/qwaq/qwaq-window.r | 30 +++++---------- 15 files changed, 287 insertions(+), 117 deletions(-) create mode 100644 ruamoko/qwaq/qwaq-group.h create mode 100644 ruamoko/qwaq/qwaq-group.r diff --git a/ruamoko/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am index f32d9d536..ab08a5579 100644 --- a/ruamoko/qwaq/Makefile.am +++ b/ruamoko/qwaq/Makefile.am @@ -23,8 +23,8 @@ SUFFIXES=.o .r sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo -qwaq_dat_src= \ - $e +qwaq_app_dat_src= \ + qwaq-app.r qwaq-group.r qwaq-screen.r qwaq-window.r qwaq-view.r qwaq_curses_libs= qwaq_curses_SOURCES=main.c qwaq-curses.c @@ -59,7 +59,7 @@ qwaq_x11_DEPENDENCIES= $(qwaq_x11_libs) $(QWAQ_DEPS) r_depfiles_remade= -qwaq_app_dat_SOURCES=qwaq-app.r qwaq-screen.r qwaq-window.r qwaq-view.r +qwaq_app_dat_SOURCES=$(qwaq_app_dat_src) qwaq_app_obj=$(qwaq_app_dat_SOURCES:.r=.o) qwaq_app_dep=$(addprefix ./$(DEPDIR)/,$(qwaq_app_obj:.o=.Qo)) qwaq-app.dat$(EXEEXT): $(qwaq_app_obj) $(QFCC_DEP) diff --git a/ruamoko/qwaq/event.h b/ruamoko/qwaq/event.h index 445240e54..03f479fdc 100644 --- a/ruamoko/qwaq/event.h +++ b/ruamoko/qwaq/event.h @@ -26,6 +26,7 @@ typedef enum { qe_message = 0xfe00, qe_focused = qe_key | qe_command, + qe_positional = qe_mouse, } qwaq_event_mask; typedef enum { diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 3bf67706a..aba39ac96 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -39,17 +39,19 @@ arp_end (void) screen = [[Screen screen] retain]; [screen setBackground: COLOR_PAIR (1)]; Rect r = *[screen getRect]; - [screen printf:"%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen]; - r.xpos = r.xlen / 4; - r.ypos = r.ylen / 4; - r.xlen /= 2; - r.ylen /= 2; - [screen printf:"%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen]; + [screen printf:"%d %d %d %d\n", + r.offset.x, r.offset.y, r.extent.width, r.extent.height]; + r.offset.x = r.extent.width / 4; + r.offset.y = r.extent.height / 4; + r.extent.width /= 2; + r.extent.height /= 2; + [screen printf:"%d %d %d %d\n", + r.offset.x, r.offset.y, r.extent.width, r.extent.height]; [screen printf:"%d\n", acs_char(ACS_HLINE)]; [screen addch: acs_char(ACS_HLINE) atX:4 Y:4]; Window *w; //[screen add: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; - //wprintf (w.window, "%d %d %d %d\n", r.xpos, r.ypos, r.xlen, r.ylen); + //wprintf (w.window, "%d %d %d %d\n", r.offset.x, r.offset.y, r.extent.width, r.ylen); [screen redraw]; return self; } @@ -128,3 +130,5 @@ void move_panel (panel_t panel, int x, int y) = #0; window_t panel_window (panel_t panel) = #0; void update_panels (void) = #0; void doupdate (void) = #0; +int curs_set (int visibility) = #0; +int move (int x, int y) = #0; diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index e51c47259..9213e4bdd 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -73,6 +73,8 @@ typedef enum qwaq_commands_e { qwaq_cmd_init_pair, qwaq_cmd_wbkgd, qwaq_cmd_scrollok, + qwaq_cmd_move, + qwaq_cmd_curs_set, } qwaq_commands; #define RING_BUFFER(type, size) \ @@ -539,6 +541,23 @@ cmd_scrollok (qwaq_resources_t *res) scrollok (window->win, flag); } +static void +cmd_move (qwaq_resources_t *res) +{ + int x = RB_PEEK_DATA (res->command_queue, 2); + int y = RB_PEEK_DATA (res->command_queue, 3); + + move (y, x); +} + +static void +cmd_curs_set (qwaq_resources_t *res) +{ + int visibility = RB_PEEK_DATA (res->command_queue, 2); + + curs_set (visibility); +} + static void process_commands (qwaq_resources_t *res) { @@ -604,6 +623,12 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_scrollok: cmd_scrollok (res); break; + case qwaq_cmd_move: + cmd_move (res); + break; + case qwaq_cmd_curs_set: + cmd_curs_set (res); + break; } RB_DROP_DATA (res->command_queue, RB_PEEK_DATA (res->command_queue, 1)); } @@ -1106,6 +1131,29 @@ bi_acs_char (progs_t *pr) } } +static void +bi_move (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int x = P_INT (pr, 0); + int y = P_INT (pr, 1); + + int command[] = { qwaq_cmd_move, 0, x, y, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} + +static void +bi_curs_set (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int visibility = P_INT (pr, 0); + + int command[] = { qwaq_cmd_curs_set, 0, visibility, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); +} + static void bi_initialize (progs_t *pr) { @@ -1168,6 +1216,8 @@ static builtin_t builtins[] = { {"wbkgd", bi_wbkgd, -1}, {"scrollok", bi_scrollok, -1}, {"acs_char", bi_acs_char, -1}, + {"move", bi_move, -1}, + {"curs_set", bi_curs_set, -1}, {0} }; diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index e9574e764..a17640bd5 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -98,6 +98,8 @@ typedef struct panel_s *panel_t; @extern void scrollok (window_t win, int flag); @extern int acs_char (int acs); +@extern int curs_set (int visibility); +@extern int move (int x, int y); #endif #endif//__qwaq_curses_h diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h index 7b614a29e..983dd8074 100644 --- a/ruamoko/qwaq/qwaq-draw.h +++ b/ruamoko/qwaq/qwaq-draw.h @@ -4,7 +4,8 @@ @protocol Draw -draw; -redraw; --setParent: parent; +-setOwner: owner; +-(struct window_s*) getWindow; @end #endif diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h new file mode 100644 index 000000000..a018102d6 --- /dev/null +++ b/ruamoko/qwaq/qwaq-group.h @@ -0,0 +1,17 @@ +#ifndef __qwaq_group_h +#define __qwaq_group_h + +#include "qwaq-view.h" + +@class Array; + +@interface Group : View +{ + Array *views; + int focused; +} +-insert: (View *) view; +-remove: (View *) view; +@end + +#endif//__qwaq_group_h diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r new file mode 100644 index 000000000..a4fc171d0 --- /dev/null +++ b/ruamoko/qwaq/qwaq-group.r @@ -0,0 +1,60 @@ +#include +#include "event.h" +#include "qwaq-group.h" + +@implementation Group +-init +{ + if (!(self = [super init])) { + return nil; + } + views = [[Array array] retain]; + return self; +} + +-(void)dealloc +{ + [views release]; +} + +-insert: (View *) view +{ + [views insertObject: view atIndex: 0]; + return self; +} + +-remove: (View *) view +{ + int index = [views indexOfObject: view]; + if (index != NotFound) { + if (focused == index) { + focused = -1; + } else if (focused > index) { + focused--; + } + [views removeObjectAtIndex: index]; + } + return self; +} + +-draw +{ + [views makeObjectsPerformSelector: @selector(draw)]; + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + [super handleEvent: event]; + if (event.what & qe_focused) { + if (focused >= 0) { + [[views objectAtIndex:focused] handleEvent: event]; + } + } else if (event.what & qe_positional) { + } else { + // broadcast + [views makeObjectsPerformSelector: @selector(draw) withObject: event]; + } + return self; +} +@end diff --git a/ruamoko/qwaq/qwaq-rect.h b/ruamoko/qwaq/qwaq-rect.h index c679352fc..8976d25db 100644 --- a/ruamoko/qwaq/qwaq-rect.h +++ b/ruamoko/qwaq/qwaq-rect.h @@ -1,18 +1,21 @@ #ifndef __qwaq_rect_h #define __qwaq_rect_h -typedef struct Rect_s { - int xpos; - int ypos; - int xlen; - int ylen; -} Rect; - typedef struct { int x; int y; } Point; +typedef struct { + int width; + int height; +} Extent; + +typedef struct Rect_s { + Point offset; + Extent extent; +} Rect; + @extern Rect makeRect (int xpos, int ypos, int xlen, int ylen); //XXX will not work if point or rect point to a local variabl @extern int rectContainsPoint (Rect *rect, Point *point); diff --git a/ruamoko/qwaq/qwaq-screen.h b/ruamoko/qwaq/qwaq-screen.h index 1294b2e28..e92daa2a4 100644 --- a/ruamoko/qwaq/qwaq-screen.h +++ b/ruamoko/qwaq/qwaq-screen.h @@ -1,28 +1,18 @@ #ifndef __qwaq_screen_h #define __qwaq_screen_h -#include - #include "qwaq-draw.h" #include "qwaq-rect.h" -@class View; -@class Array; +#include "qwaq-view.h" -@interface Screen: Object +@interface Screen: View { - Rect rect; - Array *views; - Array *event_handlers; - Array *focused_handlers; - Array *mouse_handlers; - Array *mouse_handler_rects; - View *focusedView; - struct window_s *window; } +(Screen *) screen; --add: obj; +-handleEvent: (qwaq_event_t *) event; -setBackground: (int) ch; -printf: (string) fmt, ...; +-addch: (int) ch atX: (int) x Y: (int) y; @end #endif//__qwaq_screen_h diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index 401e0e41e..45ae3228b 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -13,40 +13,12 @@ if (!(self = [super init])) { return nil; } - views = [[Array array] retain]; - event_handlers = [[Array array] retain]; - focused_handlers = [[Array array] retain]; - mouse_handlers = [[Array array] retain]; - mouse_handler_rects = [[Array array] retain]; window = stdscr; scrollok (window, 1); rect = getwrect (window); return self; } --add: obj -{ - if ([obj conformsToProtocol: @protocol (Draw)]) { - // "top" objects are drawn last - [views addObject: obj]; - [obj setParent: self]; - } - if ([obj conformsToProtocol: @protocol (HandleFocusedEvent)]) { - // want "top" objects to respond first - [focused_handlers insertObject: obj atIndex: 0]; - } - if ([obj conformsToProtocol: @protocol (HandleMouseEvent)]) { - // "top" objects respond first, but the array is searched in reverse - [mouse_handlers addObject: obj]; - [mouse_handler_rects addObject: (id) [obj getRect]]; - } - if ([obj conformsToProtocol: @protocol (HandleEvent)]) { - // want "top" objects to respond first - [event_handlers insertObject: obj atIndex: 0]; - } - return self; -} - -setBackground: (int) ch { wbkgd (window, ch); @@ -58,33 +30,12 @@ if (event.what & qe_mouse) { [self printf:"%04x %2d %2d %d %08x\r", event.what, event.mouse.x, event.mouse.y, event.mouse.click, event.mouse.buttons]; [self redraw]; - Point p = { event.mouse.x, event.mouse.y }; - for (int i = [mouse_handler_rects count]; i-->0; ) { - //if (rectContainsPoint((Rect*)mouse_handler_rects._objs[i], &p)) { - // [mouse_handlers._objs[i] handleEvent: event]; - // break; - //} - } - } else if (event.what & qe_focused) { - [focused_handlers - makeObjectsPerformSelector: @selector(handleEvent:) - withObject: (id) event]; - } - switch (event.what) { - case qe_none: - break; - case qe_key: - case qe_command: - break; - case qe_mouse: - break; } return self; } -draw { - [views makeObjectsPerformSelector: @selector (draw)]; update_panels (); doupdate (); return self; @@ -115,7 +66,7 @@ return ▭ } --setParent: parent +-setOwner: owner { return self; } diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index e7c0db85e..bd38962e6 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -7,16 +7,56 @@ #include "qwaq-draw.h" #include "qwaq-rect.h" -@interface View: Object +@class Group; + +enum { + ofCanFocus =0x0001, + ofFirstClick =0x0002, + ofDontDraw =0x0004, + ofPreProcess =0x0008, + ofPostProcess =0x0010, + ofMakeFirst =0x0020, + ofTileable =0x0040, + ofCentered =0x0080, + + ofCallHasObject =0x8000, +}; + +enum { + sfDrawn =0x0001, + sfDisabled =0x0002, + sfInFocus =0x0004, + sfModal =0x0008, + sfLocked =0x0010, +}; + +@interface View: Object { - @public - Rect rect; + union { + Rect rect; + struct { + int xpos; + int ypos; + int xlen; + int ylen; + }; + }; Rect absRect; Point point; // can't be local :( - id parent; + Group *owner; struct window_s *window; + int state; + int options; + int cursorState; + Point cursor; } -initWithRect: (Rect) rect; +- (void) dealloc; +-(struct window_s *) getWindow; +-setOwner: (Group *) owner; +-(struct Rect_s *)getRect; +-draw; +-redraw; @end #endif//__qwaq_view_h diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index bc218630f..969f1dfe2 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -1,18 +1,21 @@ #include "qwaq-curses.h" #include "qwaq-view.h" +#include "qwaq-group.h" Rect makeRect (int xpos, int ypos, int xlen, int ylen) { - Rect rect = {xpos, ypos, xlen, ylen}; + Rect rect = {{xpos, ypos}, {xlen, ylen}}; return rect; } int rectContainsPoint (Rect *rect, Point *point) { - return ((point.x >= rect.xpos && point.x < rect.xpos + rect.xlen) - && (point.y >= rect.ypos && point.y < rect.ypos + rect.ylen)); + return ((point.x >= rect.offset.x + && point.x < rect.offset.x + rect.extent.width) + && (point.y >= rect.offset.y + && point.y < rect.offset.y + rect.extent.height)); } @implementation View @@ -24,24 +27,83 @@ rectContainsPoint (Rect *rect, Point *point) } self.rect = rect; self.absRect = rect; - self.window = nil; return self; } +- (void) dealloc +{ + if (owner) { + [owner remove:self]; + } + [super dealloc]; +} + +static void +updateScreenCursor (View *view) +{ + while ((view.state & sfInFocus) && view.owner) { + View *owner = (View *) view.owner; + if (view.cursor.x >= 0 && view.cursor.x < view.xlen + && view.cursor.y >= 0 && view.cursor.y < view.ylen) { + owner.cursor.x = view.cursor.x + view.xpos; + owner.cursor.y = view.cursor.y + view.ypos; + owner.cursorState = view.cursorState; + } else { + owner.cursorState = 0; + } + view = owner; + } + if (view.state & sfInFocus) { + if (view.cursor.x >= 0 && view.cursor.x < view.xlen + && view.cursor.y >= 0 && view.cursor.y < view.ylen) { + curs_set (view.cursorState); + move(view.cursor.x, view.cursor.y); + } else { + curs_set (0); + } + } +} + -draw { + state |= sfDrawn; + updateScreenCursor (self); return self; } --setParent: parent +-hide { - self.parent = parent; + if (state & sfDrawn) { + state &= ~sfDrawn; + updateScreenCursor (self); + } return self; } -redraw { - return [parent redraw]; + if ((state & sfDrawn) && !(options & ofDontDraw)) { + [self draw]; + [owner redraw]; + } + return self; +} + +-setOwner: (Group *) owner +{ + self.owner = owner; + window = [owner getWindow]; + return self; +} + +-(window_t) getWindow +{ + return window; +} + +- (Rect *) getRect +{ + return ▭ } @end diff --git a/ruamoko/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h index 19921301a..8073c3312 100644 --- a/ruamoko/qwaq/qwaq-window.h +++ b/ruamoko/qwaq/qwaq-window.h @@ -3,16 +3,15 @@ #include "Object.h" -@class View; @class Array; #include "qwaq-draw.h" #include "qwaq-rect.h" +#include "qwaq-view.h" +#include "qwaq-group.h" -@interface Window: Object +@interface Window: Group { - Rect rect; - id parent; Point point; // FIXME can't be local :( Array *views; View *focusedView; diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index d99b21b3c..237c9dcb9 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -19,14 +19,14 @@ } views = [[Array array] retain]; self.rect = rect; - window = create_window (rect.xpos, rect.ypos, rect.xlen, rect.ylen); + window = create_window (xpos, ypos, xlen, ylen); panel = create_panel (window); return self; } -handleEvent: (qwaq_event_t *) event { - switch (event.what) { +/* switch (event.what) { case qe_mouse: mvwprintf(window, 0, 3, "%2d %2d %08x", event.mouse.x, event.mouse.y, event.mouse.buttons); @@ -54,17 +54,17 @@ break; case qe_none: break; - } + }*/ return self; } -addView: (View *) view { - [views addObject: view]; +/* [views addObject: view]; view.absRect.xpos = view.rect.xpos + rect.xpos; view.absRect.ypos = view.rect.ypos + rect.ypos; view.window = window; - [view setParent: self]; + [view setOwner: self];*/ return self; } @@ -74,16 +74,6 @@ return self; } --takeFocus -{ - return self; -} - --loseFocus -{ - return self; -} - -draw { int x = 0, y = 0; @@ -94,9 +84,9 @@ } else { mvwaddch (window, x, y, '.'); } - if (++x >= rect.xlen) { + if (++x >= xlen) { x = 0; - if (++y >= rect.ylen) { + if (++y >= ylen) { break; } } @@ -110,14 +100,14 @@ return ▭ } --setParent: parent +-setOwner: owner { - self.parent = parent; + self.owner = owner; return self; } -redraw { - return [parent redraw]; + return [owner redraw]; } @end From 5200c3f51860906aa1866e3b895a9a9c85f3d517 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 18:26:11 +0900 Subject: [PATCH 209/444] [qfcc] Update chewed-alias test for new warnings --- tools/qfcc/test/chewed-alias.r | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/test/chewed-alias.r b/tools/qfcc/test/chewed-alias.r index 7f151bce5..08c060534 100644 --- a/tools/qfcc/test/chewed-alias.r +++ b/tools/qfcc/test/chewed-alias.r @@ -1,4 +1,9 @@ -@class Array,Object; +@interface Array +-count; +-lastObject; +@end +@interface Object +@end @static entity waypoint_thinker; @static Array *waypoint_queue; void foo (void) @@ -18,4 +23,6 @@ void __obj_exec_class (struct obj_module *msg) = #0; @implementation Object @end @implementation Array +-count { return self; } +-lastObject { return nil; } @end From 66b8ab689014435db7951c2944eb28b0b4f088ac Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 18:45:47 +0900 Subject: [PATCH 210/444] [qfcc] Rework method ivar access While expression symbols worked for what they are, they weren't so good for ivar access because every ivar of a class (and its super classes) would be accessed at method scope creation, generating spurious access errors if any were private. That is, when the access checks worked at all. --- tools/qfcc/include/symtab.h | 8 ++++++++ tools/qfcc/source/class.c | 24 +++++++++++++++++++----- tools/qfcc/source/expr.c | 4 ++++ tools/qfcc/source/expr_assign.c | 2 ++ tools/qfcc/source/struct.c | 4 ++++ tools/qfcc/source/symtab.c | 2 ++ 6 files changed, 39 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/include/symtab.h b/tools/qfcc/include/symtab.h index 53b42f150..7a6904f1a 100644 --- a/tools/qfcc/include/symtab.h +++ b/tools/qfcc/include/symtab.h @@ -56,8 +56,14 @@ typedef enum { sy_expr, ///< symbol refers to an expression sy_func, ///< symbol refers to a function sy_class, ///< symbol refers to a class + sy_convert, ///< symbol refers to a conversion function } sy_type_e; +typedef struct symconv_s { + struct expr_s *(*conv) (struct symbol_s *symbol, void *data); + void *data; +} symconv_t; + typedef struct symbol_s { struct symbol_s *next; ///< chain of symbols in symbol table struct symtab_s *table; ///< symbol table that owns this symbol @@ -72,6 +78,7 @@ typedef struct symbol_s { struct ex_value_s *value; ///< sy_const struct expr_s *expr; ///< sy_expr struct function_s *func; ///< sy_func + symconv_t convert; ///< sy_convert } s; } symbol_t; @@ -92,6 +99,7 @@ typedef struct symtab_s { symbol_t *symbols; ///< chain of symbols in this table symbol_t **symtail; ///< keep chain in declaration order struct defspace_s *space; ///< storage for vars in scope symtabs + struct class_s *class; ///< owning class if ivar scope } symtab_t; const char *symtype_str (sy_type_e type) __attribute__((const)); diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 8e2d458e1..50ab5dcd7 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -1050,8 +1050,11 @@ class_find_ivar (class_t *class, int vis, const char *name) } ivar = symtab_lookup (class->ivars, name); if (ivar) { - if (ivar->visibility > (vis_t) vis) + if (ivar->visibility > (vis_t) vis + || (ivar->table->class != class + && ivar->visibility > vis_protected)) { goto access_error; + } return ivar; } error (0, "%s.%s does not exist", class->name, name); @@ -1180,6 +1183,7 @@ class_new_ivars (class_t *class) if (class->super_class) super_ivars = class->super_class->ivars; ivars = new_symtab (super_ivars, stab_local); + ivars->class = class; return ivars; } @@ -1756,6 +1760,15 @@ class_ivar_scope (class_type_t *class_type, symtab_t *parent) return symtab_flat_copy (class->ivars, parent); } +static expr_t * +class_dereference_ivar (symbol_t *sym, void *_self) +{ + expr_t *self = (expr_t *) _self; + + return field_expr (copy_expr (self), + new_symbol_expr (new_symbol (sym->name))); +} + void class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, symtab_t *param_scope) @@ -1769,8 +1782,9 @@ class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, if (!ivar_scope) return; self = symtab_lookup (param_scope, "self"); - if (!self) + if (!self) { internal_error (0, "I've lost my self!"); + } self_expr = new_symbol_expr (self); if (self->type != class_ptr) { debug (0, "class method scope"); @@ -1780,9 +1794,9 @@ class_finish_ivar_scope (class_type_t *class_type, symtab_t *ivar_scope, for (sym = ivar_scope->symbols; sym; sym = sym->next) { if (sym->sy_type != sy_var) continue; - sym->sy_type = sy_expr; - sym->s.expr = field_expr (copy_expr (self_expr), - new_symbol_expr (new_symbol (sym->name))); + sym->sy_type = sy_convert; + sym->s.convert.conv = class_dereference_ivar; + sym->s.convert.data = self_expr; } } diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index c384bcfe5..c82585674 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -109,6 +109,10 @@ convert_name (expr_t *e) //FIXME need a def return; } + if (sym->sy_type == sy_convert) { + new = sym->s.convert.conv (sym, sym->s.convert.data); + goto convert; + } if (sym->sy_type == sy_expr) { new = copy_expr (sym->s.expr); goto convert; diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 046f1c07b..f0d7daf4b 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -101,6 +101,8 @@ check_valid_lvalue (expr_t *expr) break; case sy_class: break; + case sy_convert: + break; } break; case ex_temp: diff --git a/tools/qfcc/source/struct.c b/tools/qfcc/source/struct.c index 7af7f26b2..85c8a85ba 100644 --- a/tools/qfcc/source/struct.c +++ b/tools/qfcc/source/struct.c @@ -151,6 +151,9 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) } anonymous = s->type->t.symtab; for (as = anonymous->symbols; as; as = as->next) { + if (as->visibility == vis_anonymous || as->sy_type!= sy_var) { + continue; + } if (Hash_Find (symtab->tab, as->name)) { error (0, "ambiguous field `%s' in anonymous %s", as->name, su == 's' ? "struct" : "union"); @@ -158,6 +161,7 @@ build_struct (int su, symbol_t *tag, symtab_t *symtab, type_t *type) s->next = copy_symbol (as); s = s->next; s->s.offset += offset; + s->table = symtab; Hash_Add (symtab->tab, s); } } diff --git a/tools/qfcc/source/symtab.c b/tools/qfcc/source/symtab.c index f94e8d71a..353e29142 100644 --- a/tools/qfcc/source/symtab.c +++ b/tools/qfcc/source/symtab.c @@ -59,6 +59,7 @@ static const char *sy_type_names[] = { "sy_expr", "sy_func", "sy_class", + "sy_convert", }; const char * @@ -165,6 +166,7 @@ symbol_t * copy_symbol (symbol_t *symbol) { symbol_t *sym = new_symbol (symbol->name); + sym->visibility = symbol->visibility; sym->type = symbol->type; sym->params = copy_params (symbol->params); sym->sy_type = symbol->sy_type; From 94e35b5f576267d21dcad1bcb36bcc71bd0bca99 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 5 Mar 2020 21:10:15 +0900 Subject: [PATCH 211/444] [qfcc] Clean up error messages around superclass --- tools/qfcc/source/qc-parse.y | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index a99f8c6b5..3732e47b7 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1589,9 +1589,13 @@ classdecl class_name : identifier %prec CLASS_NOT_CATEGORY { - $1 = check_undefined ($1); - if (!$1->type || !obj_is_class ($1->type)) { - error (0, "`%s' is not a class %p", $1->name, $1->type); + if (!$1->type) { + $$ = get_class ($1, 1); + if (!$1->table) { + symtab_addsymbol (current_symtab, $1); + } + } else if (!obj_is_class ($1->type)) { + error (0, "`%s' is not a class", $1->name); $$ = get_class (0, 1); } else { $$ = $1->type->t.class; From 3b959c3ed0d8dc29b49bbd67da53ad5ac3b22399 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 00:23:44 +0900 Subject: [PATCH 212/444] [gamecode] Add a macros for arbitrary param/return types Of course, the type has to be small enough to fit or bad things may happen, but it beats having to type the crazy casting every time. --- include/QF/progs.h | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 18ea33b04..ea17f533e 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -562,6 +562,20 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define P_var(p,n,t) ((p)->pr_params[n]->t##_var) +/** Access a parameter as an arbitray type. + + \par QC type: + \c struct etc small enough to fit in a single parameter + \param p pointer to ::progs_t VM struct + \param t C type of the structure + \param n parameter number (0-7) + \return structure lvalue. use & to make a pointer of the + appropriate type. + + \hideinitializer +*/ +#define P_PACKED(p,t,n) (*(t *) (p)->pr_params[n]) + /** Access a float parameter. Can be assigned to. \par QC type: @@ -584,7 +598,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define P_DOUBLE(p,n) (*(double *) ((p)->pr_params[n])) +#define P_DOUBLE(p,n) P_PACKED(p, double, n) /** Access an integer parameter. Can be assigned to. @@ -670,7 +684,6 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define P_POINTER(p,n) P_var (p, n, pointer) - /** Access an entity parameter. \par QC type: @@ -767,6 +780,19 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ */ #define R_var(p,t) ((p)->pr_return->t##_var) +/** Access the VM function return value parameter as an arbitray type. + + \par QC type: + \c struct etc small enough to fit in the return slot + \param p pointer to ::progs_t VM struct + \param t C type of the structure + \return structure lvalue. use & to make a pointer of the + appropriate type. + + \hideinitializer +*/ +#define R_PACKED(p,t) (*(t *) (p)->pr_return) + /** Access the VM function return value as a \c float \par QC type: @@ -787,7 +813,7 @@ void PR_Undefined (progs_t *pr, const char *type, const char *name) __attribute_ \hideinitializer */ -#define R_DOUBLE(p) (*(double *) ((p)->pr_return)) +#define R_DOUBLE(p) R_PACKED (p, double) /** Access the VM function return value as a \c ::pr_int_t (AKA int32_t) From 971caf553dcd5c5aed2258ef8da6aa5ea1ec7efe Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 00:30:11 +0900 Subject: [PATCH 213/444] [qwaq] Add debug output to the command queue Be sure to redirect stderr or the screen will get messed up --- ruamoko/qwaq/qwaq-curses.c | 32 +++++++++++++++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 9213e4bdd..bab6a9283 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -77,6 +77,29 @@ typedef enum qwaq_commands_e { qwaq_cmd_curs_set, } qwaq_commands; +const char *qwaq_command_names[]= { + "newwin", + "delwin", + "getwrect", + "new_panel", + "del_panel", + "hide_panel", + "show_panel", + "top_panel", + "bottom_panel", + "move_panel", + "panel_window", + "update_panels", + "doupdate", + "mvwaddstr", + "waddstr", + "mvwaddch", + "wrefresh", + "init_pair", + "wbkgd", + "scrollok", + "move", + "curs_set", #define RING_BUFFER(type, size) \ struct { \ type buffer[size]; \ @@ -562,7 +585,14 @@ static void process_commands (qwaq_resources_t *res) { while (RB_DATA_AVAILABLE (res->command_queue) >= 2) { - switch ((qwaq_commands) RB_PEEK_DATA (res->command_queue, 0)) { + qwaq_commands cmd = RB_PEEK_DATA (res->command_queue, 0); + int len = RB_PEEK_DATA (res->command_queue, 1); + Sys_Printf ("%s[%d]", qwaq_command_names[cmd], len); + for (int i = 2; i < len; i++) { + Sys_Printf (" %d", RB_PEEK_DATA (res->command_queue, i)); + } + Sys_Printf ("\n"); + switch (cmd) { case qwaq_cmd_newwin: cmd_newwin (res); break; From f18e3c3ad72679893fa2586d75637385edd69a67 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 00:31:29 +0900 Subject: [PATCH 214/444] [qwaq] Add wborder command --- ruamoko/qwaq/qwaq-app.r | 1 + ruamoko/qwaq/qwaq-curses.c | 43 ++++++++++++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-curses.h | 17 +++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index aba39ac96..054b4e3c8 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -132,3 +132,4 @@ void update_panels (void) = #0; void doupdate (void) = #0; int curs_set (int visibility) = #0; int move (int x, int y) = #0; +void wborder (window_t window, box_sides_t sides, box_corners_t corners) = #0; diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index bab6a9283..73c500368 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -43,6 +43,7 @@ #include "qwaq.h" #include "event.h" +#include "qwaq-curses.h" #define always_inline inline __attribute__((__always_inline__)) #define QUEUE_SIZE 16 @@ -75,6 +76,7 @@ typedef enum qwaq_commands_e { qwaq_cmd_scrollok, qwaq_cmd_move, qwaq_cmd_curs_set, + qwaq_cmd_wborder, } qwaq_commands; const char *qwaq_command_names[]= { @@ -100,6 +102,9 @@ const char *qwaq_command_names[]= { "scrollok", "move", "curs_set", + "wborder", +}; + #define RING_BUFFER(type, size) \ struct { \ type buffer[size]; \ @@ -581,6 +586,23 @@ cmd_curs_set (qwaq_resources_t *res) curs_set (visibility); } +static void +cmd_wborder (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int ls = RB_PEEK_DATA (res->command_queue, 3); + int rs = RB_PEEK_DATA (res->command_queue, 4); + int ts = RB_PEEK_DATA (res->command_queue, 5); + int bs = RB_PEEK_DATA (res->command_queue, 6); + int tl = RB_PEEK_DATA (res->command_queue, 7); + int tr = RB_PEEK_DATA (res->command_queue, 8); + int bl = RB_PEEK_DATA (res->command_queue, 9); + int br = RB_PEEK_DATA (res->command_queue, 10); + + window_t *window = get_window (res, __FUNCTION__, window_id); + wborder (window->win, ls, rs, ts, bs, tl, tr, bl, br); +} + static void process_commands (qwaq_resources_t *res) { @@ -659,6 +681,9 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_curs_set: cmd_curs_set (res); break; + case qwaq_cmd_wborder: + cmd_wborder (res); + break; } RB_DROP_DATA (res->command_queue, RB_PEEK_DATA (res->command_queue, 1)); } @@ -1184,6 +1209,23 @@ bi_curs_set (progs_t *pr) qwaq_submit_command (res, command); } +static void +bi_wborder (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + int window_id = P_INT (pr, 0); + __auto_type sides = P_PACKED (pr, box_sides_t, 1); + __auto_type corns = P_PACKED (pr, box_corners_t, 2); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_wborder, 0, window_id, + sides.ls, sides.rs, sides.ts, sides.bs, + corns.tl, corns.tr, corns.bl, corns.br, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} + static void bi_initialize (progs_t *pr) { @@ -1248,6 +1290,7 @@ static builtin_t builtins[] = { {"acs_char", bi_acs_char, -1}, {"move", bi_move, -1}, {"curs_set", bi_curs_set, -1}, + {"wborder", bi_wborder, -1}, {0} }; diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index a17640bd5..62bdef880 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -3,6 +3,20 @@ #include "event.h" +typedef struct box_sides_s { + int ls; + int rs; + int ts; + int bs; +} box_sides_t; + +typedef struct box_corners_s { + int tl; + int tr; + int bl; + int br; +} box_corners_t; + #ifdef __QFCC__ // names, order and comments lifted from ncurses.h typedef enum { @@ -100,6 +114,9 @@ typedef struct panel_s *panel_t; @extern int acs_char (int acs); @extern int curs_set (int visibility); @extern int move (int x, int y); + +@extern void wborder (window_t window, + box_sides_t sides, box_corners_t corners); #endif #endif//__qwaq_curses_h From ad4cde15b53e9e3e4e9ca380f200c76b9da41b24 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 00:32:09 +0900 Subject: [PATCH 215/444] [qwaq] Get Window working It even draws a border around itself. --- ruamoko/qwaq/qwaq-app.h | 3 ++- ruamoko/qwaq/qwaq-app.r | 14 +++++--------- ruamoko/qwaq/qwaq-group.r | 9 +++++++++ ruamoko/qwaq/qwaq-screen.r | 11 +++-------- ruamoko/qwaq/qwaq-view.r | 5 +++++ ruamoko/qwaq/qwaq-window.h | 4 ---- ruamoko/qwaq/qwaq-window.r | 28 ++++++++++++++++++++++------ 7 files changed, 46 insertions(+), 28 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.h b/ruamoko/qwaq/qwaq-app.h index b603fb4b1..d8b899624 100644 --- a/ruamoko/qwaq/qwaq-app.h +++ b/ruamoko/qwaq/qwaq-app.h @@ -2,10 +2,11 @@ #define __qwaq_app_h #include "event.h" +#include "qwaq-group.h" @class Screen; -@interface QwaqApplication: Object +@interface QwaqApplication: Group { qwaq_event_t event; qwaq_command endState; diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 054b4e3c8..dfd82e096 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -33,32 +33,28 @@ arp_end (void) if (!(self = [super init])) { return nil; } + initialize (); init_pair (1, COLOR_WHITE, COLOR_BLUE); init_pair (2, COLOR_WHITE, COLOR_BLACK); + screen = [[Screen screen] retain]; + [self insert:screen]; [screen setBackground: COLOR_PAIR (1)]; Rect r = *[screen getRect]; - [screen printf:"%d %d %d %d\n", - r.offset.x, r.offset.y, r.extent.width, r.extent.height]; r.offset.x = r.extent.width / 4; r.offset.y = r.extent.height / 4; r.extent.width /= 2; r.extent.height /= 2; - [screen printf:"%d %d %d %d\n", - r.offset.x, r.offset.y, r.extent.width, r.extent.height]; - [screen printf:"%d\n", acs_char(ACS_HLINE)]; - [screen addch: acs_char(ACS_HLINE) atX:4 Y:4]; Window *w; - //[screen add: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; + [self insert: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; //wprintf (w.window, "%d %d %d %d\n", r.offset.x, r.offset.y, r.extent.width, r.ylen); - [screen redraw]; return self; } -run { - [screen draw]; + [self draw]; do { arp_start (); diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index a4fc171d0..1b1bd5c61 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -12,6 +12,15 @@ return self; } +-initWithRect: (Rect) rect +{ + if (!(self = [super initWithRect: rect])) { + return nil; + } + views = [[Array array] retain]; + return self; +} + -(void)dealloc { [views release]; diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index 45ae3228b..e39406448 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -10,12 +10,11 @@ -init { - if (!(self = [super init])) { + if (!(self = [super initWithRect:getwrect (stdscr)])) { return nil; } window = stdscr; scrollok (window, 1); - rect = getwrect (window); return self; } @@ -28,7 +27,7 @@ -handleEvent: (qwaq_event_t *) event { if (event.what & qe_mouse) { - [self printf:"%04x %2d %2d %d %08x\r", event.what, event.mouse.x, event.mouse.y, event.mouse.click, event.mouse.buttons]; + [self printf:"%04x %2d %2d %d %08x \r", event.what, event.mouse.x, event.mouse.y, event.mouse.click, event.mouse.buttons]; [self redraw]; } return self; @@ -61,13 +60,9 @@ return self; } -- (Rect *) getRect -{ - return ▭ -} - -setOwner: owner { + self.owner = owner; return self; } diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 969f1dfe2..3fb5b4e77 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -20,6 +20,11 @@ rectContainsPoint (Rect *rect, Point *point) @implementation View +-init +{ + return [super init]; +} + -initWithRect: (Rect) rect { if (!(self = [super init])) { diff --git a/ruamoko/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h index 8073c3312..c59a72f28 100644 --- a/ruamoko/qwaq/qwaq-window.h +++ b/ruamoko/qwaq/qwaq-window.h @@ -13,13 +13,9 @@ @interface Window: Group { Point point; // FIXME can't be local :( - Array *views; - View *focusedView; - struct window_s *window; struct panel_s *panel; } +windowWithRect: (Rect) rect; --addView: (View *) view; -setBackground: (int) ch; @end diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 237c9dcb9..45e8c4a77 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -17,7 +17,6 @@ if (!(self = [super init])) { return nil; } - views = [[Array array] retain]; self.rect = rect; window = create_window (xpos, ypos, xlen, ylen); panel = create_panel (window); @@ -76,22 +75,39 @@ -draw { - int x = 0, y = 0; - for (int i = ACS_ULCORNER; i <= ACS_STERLING; i++) { + static box_sides_t box_sides = { + ACS_VLINE, ACS_VLINE, + ACS_HLINE, ACS_HLINE, + }; + static box_corners_t box_corners = { + ACS_ULCORNER, ACS_URCORNER, + ACS_LLCORNER, ACS_LRCORNER, + }; + if (box_sides.ls == ACS_VLINE) { + int *foo = &box_sides.ls; + for (int i = 0; i < 8; i++) { + foo[i] = acs_char (foo[i]); + } + } + [super draw]; + int x = 1, y = 1; + wborder (window, box_sides, box_corners); + //for (int i = ACS_ULCORNER; i <= ACS_STERLING; i++) { + for (int i = 32; i <= 127; i++) { int ch = acs_char (i); if (ch) { mvwaddch (window, x, y, ch); } else { mvwaddch (window, x, y, '.'); } - if (++x >= xlen) { - x = 0; + if (++x > 32) { + x = 1; if (++y >= ylen) { break; } } } - [views makeObjectsPerformSelector: @selector (draw)]; + wrefresh (window); return self; } From 6bf2fd546d945e5171d92d1176286915e77ccebe Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 11:27:31 +0900 Subject: [PATCH 216/444] [qwaq] Extend Array makeObjectsPerform methods Added conditional message sending and reversed traversal of the array. --- ruamoko/qwaq/qwaq-group.h | 24 ++++++++++++++- ruamoko/qwaq/qwaq-group.r | 63 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h index a018102d6..a1b58fbae 100644 --- a/ruamoko/qwaq/qwaq-group.h +++ b/ruamoko/qwaq/qwaq-group.h @@ -1,9 +1,31 @@ #ifndef __qwaq_group_h #define __qwaq_group_h +#include #include "qwaq-view.h" -@class Array; +typedef BOOL condition_func (id object, void *data); +typedef BOOL condition_func2 (id object, void *anObject, void *data); + +@interface Array (Group) +- (void) makeObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data; +- (void) makeObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data; +- (void) makeReversedObjectsPerformSelector: (SEL)selector; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data; +@end @interface Group : View { diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index 1b1bd5c61..3d03c3402 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -2,6 +2,69 @@ #include "event.h" #include "qwaq-group.h" +@implementation Array (Group) +- (void) makeObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data +{ + for (int i = 0; i < [self count]; i++) { + if (condition (_objs[i], data)) { + [_objs[i] performSelector: selector]; + } + } +} + +- (void) makeObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data +{ + for (int i = 0; i < [self count]; i++) { + if (condition (_objs[i], anObject, data)) { + [_objs[i] performSelector: selector withObject: anObject]; + } + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector +{ + for (int i = [self count]; i-->0; ) { + [_objs[i] performSelector: selector]; + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject +{ + for (int i = [self count]; i-->0; ) { + [_objs[i] performSelector: selector withObject: anObject]; + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data +{ + for (int i = [self count]; i-->0; ) { + if (condition (_objs[i], data)) { + [_objs[i] performSelector: selector]; + } + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data +{ + for (int i = [self count]; i-->0; ) { + if (condition (_objs[i], anObject, data)) { + [_objs[i] performSelector: selector withObject: anObject]; + } + } +} +@end + @implementation Group -init { From 40ae7a7f1902dceb4aae554ec852571fc2393cd4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 11:53:40 +0900 Subject: [PATCH 217/444] [qwaq] Implement ofDontDraw The conditional selector performance seems to work nicely, but I've found a mistake with View.window (partly, realizing why my old lib (and probably TV in the first place) had separate textContext and buffers between views and groups). --- ruamoko/qwaq/qwaq-group.h | 1 + ruamoko/qwaq/qwaq-group.r | 20 ++++++++++++++++++-- ruamoko/qwaq/qwaq-screen.r | 18 ++++++------------ ruamoko/qwaq/qwaq-view.h | 3 +-- ruamoko/qwaq/qwaq-view.r | 6 ------ 5 files changed, 26 insertions(+), 22 deletions(-) diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h index a1b58fbae..a5cf5635e 100644 --- a/ruamoko/qwaq/qwaq-group.h +++ b/ruamoko/qwaq/qwaq-group.h @@ -31,6 +31,7 @@ typedef BOOL condition_func2 (id object, void *anObject, void *data); { Array *views; int focused; + struct window_s *window; } -insert: (View *) view; -remove: (View *) view; diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index 3d03c3402..c25c6b9ee 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -91,7 +91,7 @@ -insert: (View *) view { - [views insertObject: view atIndex: 0]; + [views addObject: view]; return self; } @@ -109,9 +109,25 @@ return self; } +static BOOL +not_dont_draw (id aView, void *aGroup) +{ + View *view = aView; + Group *group = (Group *) aGroup; + if (!(view.options & ofDontDraw)) { + if (!view.textContext) { + view.textContext = group.window; + } + return YES; + } + return NO; +} + -draw { - [views makeObjectsPerformSelector: @selector(draw)]; + [views makeObjectsPerformSelector: @selector(draw) + if: not_dont_draw + with: self]; return self; } diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index e39406448..7b7a9c9cd 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -13,14 +13,14 @@ if (!(self = [super initWithRect:getwrect (stdscr)])) { return nil; } - window = stdscr; - scrollok (window, 1); + textContext = stdscr; + scrollok (textContext, 1); return self; } -setBackground: (int) ch { - wbkgd (window, ch); + wbkgd (textContext, ch); return self; } @@ -43,26 +43,20 @@ -redraw { update_panels (); - wrefresh(window); + wrefresh(textContext); doupdate (); return self; } -printf: (string) fmt, ... { - wvprintf (window, fmt, @args); + wvprintf (textContext, fmt, @args); return self; } -addch: (int) ch atX: (int) x Y: (int) y { - mvwaddch(window, x, y, ch); - return self; -} - --setOwner: owner -{ - self.owner = owner; + mvwaddch(textContext, x, y, ch); return self; } diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index bd38962e6..a168268af 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -44,7 +44,7 @@ enum { Rect absRect; Point point; // can't be local :( Group *owner; - struct window_s *window; + struct window_s *textContext; //FIXME separate class int state; int options; int cursorState; @@ -52,7 +52,6 @@ enum { } -initWithRect: (Rect) rect; - (void) dealloc; --(struct window_s *) getWindow; -setOwner: (Group *) owner; -(struct Rect_s *)getRect; -draw; diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 3fb5b4e77..6b6f3e80d 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -97,15 +97,9 @@ updateScreenCursor (View *view) -setOwner: (Group *) owner { self.owner = owner; - window = [owner getWindow]; return self; } --(window_t) getWindow -{ - return window; -} - - (Rect *) getRect { return ▭ From ba9c43d2d3b323204415cc85234a390d2a6d1852 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 13:54:46 +0900 Subject: [PATCH 218/444] [qwaq] Create a TextContext class It is essentially just a wrapper around the window versions of ncurses functions. --- ruamoko/qwaq/Makefile.am | 7 +- ruamoko/qwaq/qwaq-app.r | 32 --- ruamoko/qwaq/qwaq-curses.c | 376 ++++++++++++++++++++++++++++---- ruamoko/qwaq/qwaq-curses.h | 2 + ruamoko/qwaq/qwaq-rect.h | 2 + ruamoko/qwaq/qwaq-textcontext.h | 46 ++++ ruamoko/qwaq/qwaq-textcontext.r | 92 ++++++++ 7 files changed, 481 insertions(+), 76 deletions(-) create mode 100644 ruamoko/qwaq/qwaq-textcontext.h create mode 100644 ruamoko/qwaq/qwaq-textcontext.r diff --git a/ruamoko/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am index ab08a5579..cf71f7590 100644 --- a/ruamoko/qwaq/Makefile.am +++ b/ruamoko/qwaq/Makefile.am @@ -24,7 +24,12 @@ SUFFIXES=.o .r $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo qwaq_app_dat_src= \ - qwaq-app.r qwaq-group.r qwaq-screen.r qwaq-window.r qwaq-view.r + qwaq-app.r \ + qwaq-group.r \ + qwaq-screen.r \ + qwaq-textcontext.r \ + qwaq-view.r \ + qwaq-window.r qwaq_curses_libs= qwaq_curses_SOURCES=main.c qwaq-curses.c diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index dfd82e096..9d046a89f 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -97,35 +97,3 @@ int main (int argc, string *argv) get_event (&event); // XXX need a "wait for queue idle" return 0; } - -window_t stdscr = (window_t) 1; - -void initialize (void) = #0; -window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; -void destroy_window (window_t win) = #0; -void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; -void wprintf (window_t win, string fmt, ...) = #0; -void wvprintf (window_t win, string fmt, @va_list args) = #0; -void wrefresh (window_t win) = #0; -void mvwaddch (window_t win, int x, int y, int ch) = #0; -int get_event (qwaq_event_t *event) = #0; -int max_colors (void) = #0; -int max_color_pairs (void) = #0; -int init_pair (int pair, int f, int b) = #0; -void wbkgd (window_t win, int ch) = #0; -void scrollok (window_t win, int flag) = #0; -int acs_char (int acs) = #0; - -panel_t create_panel (window_t window) = #0; -void destroy_panel (panel_t panel) = #0; -void hide_panel (panel_t panel) = #0; -void show_panel (panel_t panel) = #0; -void top_panel (panel_t panel) = #0; -void bottom_panel (panel_t panel) = #0; -void move_panel (panel_t panel, int x, int y) = #0; -window_t panel_window (panel_t panel) = #0; -void update_panels (void) = #0; -void doupdate (void) = #0; -int curs_set (int visibility) = #0; -int move (int x, int y) = #0; -void wborder (window_t window, box_sides_t sides, box_corners_t corners) = #0; diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 73c500368..f625f80ec 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -44,6 +44,8 @@ #include "qwaq.h" #include "event.h" #include "qwaq-curses.h" +#include "qwaq-rect.h" +#include "qwaq-textcontext.h" #define always_inline inline __attribute__((__always_inline__)) #define QUEUE_SIZE 16 @@ -856,10 +858,9 @@ bi_delwin (progs_t *pr) } static void -bi_getwrect (progs_t *pr) +qwaq_getwrect (progs_t *pr, int window_id) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int window_id = P_INT (pr, 0); if (get_window (res, __FUNCTION__, window_id)) { int command[] = { qwaq_cmd_getwrect, 0, window_id, }; @@ -876,6 +877,11 @@ bi_getwrect (progs_t *pr) (&R_INT (pr))[3] = cmd_result[4]; } } +static void +bi_getwrect (progs_t *pr) +{ + qwaq_getwrect (pr, P_INT (pr, 0)); +} static void bi_new_panel (progs_t *pr) @@ -992,15 +998,10 @@ bi_doupdate (progs_t *pr) } static void -bi_mvwprintf (progs_t *pr) +qwaq_mvwprintf (progs_t *pr, int window_id, int x, int y, const char *fmt, + int count, pr_type_t **args) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int window_id = P_INT (pr, 0); - int x = P_INT (pr, 1); - int y = P_INT (pr, 2); - const char *fmt = P_GSTRING (pr, 3); - int count = pr->pr_argc - 4; - pr_type_t **args = pr->pr_params + 4; if (get_window (res, __FUNCTION__, window_id)) { int string_id = acquire_string (res); @@ -1018,15 +1019,24 @@ bi_mvwprintf (progs_t *pr) qwaq_submit_command (res, command); } } +static void +bi_mvwprintf (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + const char *fmt = P_GSTRING (pr, 3); + int count = pr->pr_argc - 4; + pr_type_t **args = pr->pr_params + 4; + + qwaq_mvwprintf (pr, window_id, x, y, fmt, count, args); +} static void -bi_wprintf (progs_t *pr) +qwaq_wprintf (progs_t *pr, int window_id, const char *fmt, + int count, pr_type_t **args) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int window_id = P_INT (pr, 0); - const char *fmt = P_GSTRING (pr, 1); - int count = pr->pr_argc - 2; - pr_type_t **args = pr->pr_params + 2; if (get_window (res, __FUNCTION__, window_id)) { int string_id = acquire_string (res); @@ -1044,14 +1054,21 @@ bi_wprintf (progs_t *pr) qwaq_submit_command (res, command); } } - static void -bi_wvprintf (progs_t *pr) +bi_wprintf (progs_t *pr) { - qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); int window_id = P_INT (pr, 0); const char *fmt = P_GSTRING (pr, 1); - __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 2); + int count = pr->pr_argc - 2; + pr_type_t **args = pr->pr_params + 2; + + qwaq_wprintf (pr, window_id, fmt, count, args); +} + +static void +qwaq_wvprintf (progs_t *pr, int window_id, const char *fmt, pr_va_list_t *args) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); pr_type_t *list_start = PR_GetPointer (pr, args->list); pr_type_t **list = alloca (args->count * sizeof (*list)); @@ -1075,15 +1092,60 @@ bi_wvprintf (progs_t *pr) qwaq_submit_command (res, command); } } +static void +bi_wvprintf (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + const char *fmt = P_GSTRING (pr, 1); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 2); + + qwaq_wvprintf (pr, window_id, fmt, args); +} static void -bi_mvwaddch (progs_t *pr) +qwaq_mvwvprintf (progs_t *pr, int window_id, int x, int y, + const char *fmt, pr_va_list_t *args) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + pr_type_t *list_start = PR_GetPointer (pr, args->list); + pr_type_t **list = alloca (args->count * sizeof (*list)); + + for (int i = 0; i < args->count; i++) { + list[i] = list_start + i * pr->pr_param_size; + } + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_mvwaddstr, 0, + window_id, x, y, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_clearstr (print_buffer); + PR_Sprintf (pr, print_buffer, "waddstr", fmt, args->count, list); + + qwaq_submit_command (res, command); + } +} +static void +bi_mvwvprintf (progs_t *pr) +{ int window_id = P_INT (pr, 0); int x = P_INT (pr, 1); int y = P_INT (pr, 2); - int ch = P_INT (pr, 3); + const char *fmt = P_GSTRING (pr, 2); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 3); + + qwaq_mvwvprintf (pr, x, y, window_id, fmt, args); +} + +static void +qwaq_mvwaddch (progs_t *pr, int window_id, int x, int y, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); if (get_window (res, __FUNCTION__, window_id)) { int command[] = { @@ -1094,12 +1156,21 @@ bi_mvwaddch (progs_t *pr) qwaq_submit_command (res, command); } } +static void +bi_mvwaddch (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + int ch = P_INT (pr, 3); + + qwaq_mvwaddch (pr, window_id, x, y, ch); +} static void -bi_wrefresh (progs_t *pr) +qwaq_wrefresh (progs_t *pr, int window_id) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int window_id = P_INT (pr, 0); if (get_window (res, __FUNCTION__, window_id)) { int command[] = { qwaq_cmd_wrefresh, 0, window_id, }; @@ -1107,6 +1178,13 @@ bi_wrefresh (progs_t *pr) qwaq_submit_command (res, command); } } +static void +bi_wrefresh (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + + qwaq_wrefresh (pr, window_id); +} static void bi_get_event (progs_t *pr) @@ -1132,24 +1210,28 @@ bi_max_color_pairs (progs_t *pr) } static void -bi_init_pair (progs_t *pr) +qwaq_init_pair (progs_t *pr, int pair, int f, int b) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int pair = P_INT (pr, 0); - int f = P_INT (pr, 1); - int b = P_INT (pr, 2); int command[] = { qwaq_cmd_init_pair, 0, pair, f, b, }; command[1] = CMD_SIZE(command); qwaq_submit_command (res, command); } +static void +bi_init_pair (progs_t *pr) +{ + int pair = P_INT (pr, 0); + int f = P_INT (pr, 1); + int b = P_INT (pr, 2); + + qwaq_init_pair (pr, pair, f, b); +} static void -bi_wbkgd (progs_t *pr) +qwaq_wbkgd (progs_t *pr, int window_id, int ch) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int window_id = P_INT (pr, 0); - int ch = P_INT (pr, 1); if (get_window (res, __FUNCTION__, window_id)) { int command[] = { qwaq_cmd_wbkgd, 0, window_id, ch, }; @@ -1157,13 +1239,19 @@ bi_wbkgd (progs_t *pr) qwaq_submit_command (res, command); } } +static void +bi_wbkgd (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int ch = P_INT (pr, 1); + + qwaq_wbkgd (pr, window_id, ch); +} static void -bi_scrollok (progs_t *pr) +qwaq_scrollok (progs_t *pr, int window_id, int flag) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int window_id = P_INT (pr, 0); - int flag = P_INT (pr, 1); if (get_window (res, __FUNCTION__, window_id)) { int command[] = { qwaq_cmd_scrollok, 0, window_id, flag, }; @@ -1171,12 +1259,19 @@ bi_scrollok (progs_t *pr) qwaq_submit_command (res, command); } } +static void +bi_scrollok (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int flag = P_INT (pr, 1); + + qwaq_scrollok (pr, window_id, flag); +} static const char qwaq_acs_char_map[] = "lmkjtuvwqxnos`afg~,+.-hi0pryz{|}"; static void -bi_acs_char (progs_t *pr) +qwaq_acs_char (progs_t *pr, unsigned acs) { - unsigned acs = P_INT (pr, 0); if (acs < 256) { R_INT (pr) = NCURSES_ACS(acs); } else if (acs - 256 < sizeof (qwaq_acs_char_map)) { @@ -1185,37 +1280,54 @@ bi_acs_char (progs_t *pr) R_INT (pr) = 0; } } +static void +bi_acs_char (progs_t *pr) +{ + int acs = P_INT (pr, 0); + + qwaq_acs_char (pr, acs); +} static void -bi_move (progs_t *pr) +qwaq_move (progs_t *pr, int x, int y) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int x = P_INT (pr, 0); - int y = P_INT (pr, 1); int command[] = { qwaq_cmd_move, 0, x, y, }; command[1] = CMD_SIZE(command); qwaq_submit_command (res, command); } +static void +bi_move (progs_t *pr) +{ + int x = P_INT (pr, 0); + int y = P_INT (pr, 1); + + qwaq_move (pr, x, y); +} static void -bi_curs_set (progs_t *pr) +qwaq_curs_set (progs_t *pr, int visibility) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int visibility = P_INT (pr, 0); int command[] = { qwaq_cmd_curs_set, 0, visibility, }; command[1] = CMD_SIZE(command); qwaq_submit_command (res, command); } +static void +bi_curs_set (progs_t *pr) +{ + int visibility = P_INT (pr, 0); + + qwaq_curs_set (pr, visibility); +} static void -bi_wborder (progs_t *pr) +qwaq_wborder (progs_t *pr, int window_id, + box_sides_t sides, box_corners_t corns) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); - int window_id = P_INT (pr, 0); - __auto_type sides = P_PACKED (pr, box_sides_t, 1); - __auto_type corns = P_PACKED (pr, box_corners_t, 2); if (get_window (res, __FUNCTION__, window_id)) { int command[] = { qwaq_cmd_wborder, 0, window_id, @@ -1225,6 +1337,15 @@ bi_wborder (progs_t *pr) qwaq_submit_command (res, command); } } +static void +bi_wborder (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + __auto_type sides = P_PACKED (pr, box_sides_t, 1); + __auto_type corns = P_PACKED (pr, box_corners_t, 2); + + qwaq_wborder (pr, window_id, sides, corns); +} static void bi_initialize (progs_t *pr) @@ -1247,6 +1368,155 @@ bi_initialize (progs_t *pr) res->stdscr.win = stdscr; } +static void +bi_c_TextContext__is_initialized (progs_t *pr) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + R_INT (pr) = res->initialized; +} + +static void +bi_c_TextContext__max_colors (progs_t *pr) +{ + bi_max_colors (pr); +} + +static void +bi_c_TextContext__max_color_pairs (progs_t *pr) +{ + bi_max_color_pairs (pr); +} + +static void +bi_c_TextContext__init_pair_ (progs_t *pr) +{ + int pair = P_INT (pr, 2); + int f = P_INT (pr, 3); + int b = P_INT (pr, 4); + + qwaq_init_pair (pr, pair, f, b); +} + +static void +bi_c_TextContext__acs_char_ (progs_t *pr) +{ + int acs = P_INT (pr, 2); + + qwaq_acs_char (pr, acs); +} + +static void +bi_c_TextContext__move_ (progs_t *pr) +{ + Point *pos = &P_PACKED (pr, Point, 2); + + qwaq_move (pr, pos->x, pos->y); +} + +static void +bi_c_TextContext__curs_set_ (progs_t *pr) +{ + int visibility = P_INT (pr, 2); + + qwaq_curs_set (pr, visibility); +} + +static void +bi_c_TextContext__doupdate (progs_t *pr) +{ + bi_doupdate (pr); +} + +static void +bi_i_TextContext__mvprintf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + const char *fmt = P_GSTRING (pr, 3); + int count = pr->pr_argc - 4; + pr_type_t **args = pr->pr_params + 4; + + qwaq_mvwprintf (pr, window_id, pos->x, pos->y, fmt, count, args); +} + +static void +bi_i_TextContext__printf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + const char *fmt = P_GSTRING (pr, 2); + int count = pr->pr_argc - 3; + pr_type_t **args = pr->pr_params + 3; + + qwaq_wprintf (pr, window_id, fmt, count, args); +} + +static void +bi_i_TextContext__vprintf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + const char *fmt = P_GSTRING (pr, 2); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 3); + + qwaq_wvprintf (pr, window_id, fmt, args); +} + +static void +bi_i_TextContext__mvvprintf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + const char *fmt = P_GSTRING (pr, 3); + __auto_type args = (pr_va_list_t *) &P_POINTER (pr, 4); + + qwaq_mvwvprintf (pr, pos->x, pos->y, window_id, fmt, args); +} + +static void +bi_i_TextContext__refresh (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + + qwaq_wrefresh (pr, window_id); +} + +static void +bi_i_TextContext__mvaddch_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + int ch = P_INT (pr, 3); + + qwaq_mvwaddch (pr, window_id, pos->x, pos->y, ch); +} + +static void +bi_i_TextContext__bkgd_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int ch = P_INT (pr, 2); + + qwaq_wbkgd (pr, window_id, ch); +} + +static void +bi_i_TextContext__scrollok_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int flag = P_INT (pr, 2); + + qwaq_scrollok (pr, window_id, flag); +} + +static void +bi_i_TextContext__border_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + __auto_type sides = P_PACKED (pr, box_sides_t, 2); + __auto_type corns = P_PACKED (pr, box_corners_t, 3); + + qwaq_wborder (pr, window_id, sides, corns); +} + static void bi_qwaq_clear (progs_t *pr, void *data) { @@ -1279,6 +1549,7 @@ static builtin_t builtins[] = { {"mvwprintf", bi_mvwprintf, -1}, {"wprintf", bi_wprintf, -1}, {"wvprintf", bi_wvprintf, -1}, + {"mvwvprintf", bi_mvwvprintf, -1}, {"mvwaddch", bi_mvwaddch, -1}, {"wrefresh", bi_wrefresh, -1}, {"get_event", bi_get_event, -1}, @@ -1291,6 +1562,25 @@ static builtin_t builtins[] = { {"move", bi_move, -1}, {"curs_set", bi_curs_set, -1}, {"wborder", bi_wborder, -1}, + + {"_c_TextContext__is_initialized", bi_c_TextContext__is_initialized, -1}, + {"_c_TextContext__max_colors", bi_c_TextContext__max_colors, -1}, + {"_c_TextContext__max_color_pairs", bi_c_TextContext__max_color_pairs, -1}, + {"_c_TextContext__init_pair_", bi_c_TextContext__init_pair_, -1}, + {"_c_TextContext__acs_char_", bi_c_TextContext__acs_char_, -1}, + {"_c_TextContext__move_", bi_c_TextContext__move_, -1}, + {"_c_TextContext__curs_set_", bi_c_TextContext__curs_set_, -1}, + {"_c_TextContext__doupdate", bi_c_TextContext__doupdate, -1}, + {"_i_TextContext__mvprintf_", bi_i_TextContext__mvprintf_, -1}, + {"_i_TextContext__printf_", bi_i_TextContext__printf_, -1}, + {"_i_TextContext__vprintf_", bi_i_TextContext__vprintf_, -1}, + {"_i_TextContext__mvvprintf_", bi_i_TextContext__mvvprintf_, -1}, + {"_i_TextContext__refresh", bi_i_TextContext__refresh, -1}, + {"_i_TextContext__mvaddch_", bi_i_TextContext__mvaddch_, -1}, + {"_i_TextContext__bkgd_", bi_i_TextContext__bkgd_, -1}, + {"_i_TextContext__scrollok_", bi_i_TextContext__scrollok_, -1}, + {"_i_TextContext__border_", bi_i_TextContext__border_, -1}, + {0} }; diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index 62bdef880..aa9d2456d 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -90,6 +90,8 @@ typedef struct panel_s *panel_t; @extern void mvwprintf (window_t win, int x, int y, string fmt, ...); @extern void wprintf (window_t win, string fmt, ...); @extern void wvprintf (window_t win, string fmt, @va_list args); +@extern void mvwvprintf (window_t win, int x, int y, + string fmt, @va_list args); @extern void wrefresh (window_t win); @extern void mvwaddch (window_t win, int x, int y, int ch); diff --git a/ruamoko/qwaq/qwaq-rect.h b/ruamoko/qwaq/qwaq-rect.h index 8976d25db..92c241f40 100644 --- a/ruamoko/qwaq/qwaq-rect.h +++ b/ruamoko/qwaq/qwaq-rect.h @@ -16,9 +16,11 @@ typedef struct Rect_s { Extent extent; } Rect; +#ifdef __QFCC__ @extern Rect makeRect (int xpos, int ypos, int xlen, int ylen); //XXX will not work if point or rect point to a local variabl @extern int rectContainsPoint (Rect *rect, Point *point); @extern Rect getwrect (struct window_s *window); +#endif #endif//__qwaq_rect_h diff --git a/ruamoko/qwaq/qwaq-textcontext.h b/ruamoko/qwaq/qwaq-textcontext.h new file mode 100644 index 000000000..8cd20d74f --- /dev/null +++ b/ruamoko/qwaq/qwaq-textcontext.h @@ -0,0 +1,46 @@ +#ifndef __qwaq_textcontect_h +#define __qwaq_textcontect_h + +#ifdef __QFCC__ +#include +#include "qwaq-curses.h" +#include "qwaq-rect.h" + +@interface TextContext : Object +{ + window_t window; +} ++ (int) max_colors; ++ (int) max_color_pairs; ++ (void) init_pair: (int) pair, int fg, int bg; ++ (int) acs_char: (int) acs; ++ (void) move: (Point) pos; ++ (void) curs_set: (int) visibility; ++ (void) doupdate; + +-init; +-initWithRect: (Rect) rect; +-initWithWindow: (window_t) window; +- (void) mvprintf: (Point) pos, string fmt, ...; +- (void) printf: (string) fmt, ...; +- (void) vprintf: (string) mft, @va_list args; +- (void) mvvprintf: (Point) pos, string mft, @va_list args; +- (void) refresh; +- (void) mvaddch: (Point) pos, int ch; +- (void) bkgd: (int) ch; +- (void) scrollok: (int) flag; +- (void) border: (box_sides_t) sides, box_corners_t corners; +@end + +#else + +#include "QF/pr_obj.h" + +typedef struct qwaq_textcontext_s { + pr_id_t isa; + pointer_t window; +} qwaq_textcontext_t; + +#endif + +#endif//__qwaq_textcontect_h diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r new file mode 100644 index 000000000..43c8f9320 --- /dev/null +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -0,0 +1,92 @@ +#include "qwaq-textcontext.h" + +@implementation TextContext ++ (int) is_initialized = #0; ++ (void) initialize +{ + if (![self is_initialized]) { + initialize (); + } +} + ++ (int) max_colors = #0; ++ (int) max_color_pairs = #0; ++ (void) init_pair: (int) pair, int fg, int bg = #0; ++ (int) acs_char: (int) acs = #0; ++ (void) move: (Point) pos = #0; ++ (void) curs_set: (int) visibility = #0; ++ (void) doupdate = #0; + +- init +{ + if (!(self = [super init])) { + return nil; + } + window = stdscr; + return self; +} + +- initWithRect: (Rect) rect +{ + if (!(self = [super init])) { + return nil; + } + window = create_window (rect.offset.x, rect.offset.y, + rect.extent.width, rect.extent.height); + return self; +} + +- initWithWindow: (window_t) window +{ + if (!(self = [super init])) { + return nil; + } + self.window = window; + return self; +} + +- (void) mvprintf: (Point) pos, string fmt, ... = #0; +- (void) printf: (string) fmt, ... = #0; +- (void) vprintf: (string) mft, @va_list args = #0; +- (void) mvvprintf: (Point) pos, string mft, @va_list args = #0; +- (void) refresh = #0; +- (void) mvaddch: (Point) pos, int ch = #0; +- (void) bkgd: (int) ch = #0; +- (void) scrollok: (int) flag = #0; +- (void) border: (box_sides_t) sides, box_corners_t corners = #0; + +@end + +window_t stdscr = (window_t) 1; + +void initialize (void) = #0; +window_t create_window (int xpos, int ypos, int xlen, int ylen) = #0; +void destroy_window (window_t win) = #0; +void mvwprintf (window_t win, int x, int y, string fmt, ...) = #0; +void wprintf (window_t win, string fmt, ...) = #0; +void wvprintf (window_t win, string fmt, @va_list args) = #0; +void mvwvprintf (window_t win, int x, int y, string fmt, @va_list args) = #0; +void wrefresh (window_t win) = #0; +void mvwaddch (window_t win, int x, int y, int ch) = #0; +int get_event (qwaq_event_t *event) = #0; +int max_colors (void) = #0; +int max_color_pairs (void) = #0; +int init_pair (int pair, int f, int b) = #0; +void wbkgd (window_t win, int ch) = #0; +void scrollok (window_t win, int flag) = #0; +int acs_char (int acs) = #0; + +panel_t create_panel (window_t window) = #0; +void destroy_panel (panel_t panel) = #0; +void hide_panel (panel_t panel) = #0; +void show_panel (panel_t panel) = #0; +void top_panel (panel_t panel) = #0; +void bottom_panel (panel_t panel) = #0; +void move_panel (panel_t panel, int x, int y) = #0; +window_t panel_window (panel_t panel) = #0; +void update_panels (void) = #0; + +void doupdate (void) = #0; +int curs_set (int visibility) = #0; +int move (int x, int y) = #0; +void wborder (window_t window, box_sides_t sides, box_corners_t corners) = #0; From a2cebe3cac830343202cb6246f0fd80788a05929 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 17:36:23 +0900 Subject: [PATCH 219/444] [qfcc] Add failing test for method parameters --- tools/qfcc/test/Makefile.am | 10 ++++++++++ tools/qfcc/test/methodparams.r | 17 +++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 tools/qfcc/test/methodparams.r diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index 2e1001c11..7ea8e5c21 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -43,6 +43,7 @@ test_progs_dat=\ func-static.dat \ infloop.dat \ ivar-struct-return.dat \ + methodparams.dat \ modulo.dat \ paramret.dat \ quaternion.dat \ @@ -258,6 +259,15 @@ ivar-struct-return.run: Makefile build-run include ./$(DEPDIR)/ivar-struct-return.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/ivar-struct-return.Qo +methodparams_dat_SOURCES=methodparams.r +methodparams_obj=$(methodparams_dat_SOURCES:.r=.qfo) +methodparams.dat$(EXEEXT): $(methodparams_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(methodparams_obj) +methodparams.run: Makefile build-run + @TEST_HARNESS_OPTS=--float $(srcdir)/build-run $@ +include ./$(DEPDIR)/methodparams.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/methodparams.Qo + modulo_dat_SOURCES=modulo.r modulo_obj=$(modulo_dat_SOURCES:.r=.qfo) modulo.dat$(EXEEXT): $(modulo_obj) $(QFCC_DEP) diff --git a/tools/qfcc/test/methodparams.r b/tools/qfcc/test/methodparams.r new file mode 100644 index 000000000..b91322358 --- /dev/null +++ b/tools/qfcc/test/methodparams.r @@ -0,0 +1,17 @@ +typedef struct { int x, y; } Point; +@interface TextContext +- (void) mvvprintf: (Point) pos, string mft, @va_list args; +@end +@interface View +{ + TextContext *textContext; +} +- (void) mvprintf: (Point) pos, string mft, ...; +@end + +@implementation View +- (void) mvprintf: (Point) pos, string fmt, ... +{ + [textContext mvvprintf: pos, fmt, @args]; +} +@end From 9b269c2f8ecda23231d33be6bbda7abe3a71d758 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 17:14:14 +0900 Subject: [PATCH 220/444] [qfcc] Fix mangled method parameters Method parameters (ie, extra parameters without selector names) were getting reversed during function type construction. --- tools/qfcc/include/function.h | 2 +- tools/qfcc/source/function.c | 16 +++++++++++++++- tools/qfcc/source/method.c | 6 +++--- tools/qfcc/source/qc-parse.y | 3 +-- tools/qfcc/test/methodparams.r | 12 ++++++++++++ 5 files changed, 32 insertions(+), 7 deletions(-) diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index 209f40026..39cde918c 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -119,8 +119,8 @@ param_t *new_param (const char *selector, struct type_s *type, const char *name); param_t *param_append_identifiers (param_t *params, struct symbol_s *idents, struct type_s *type); -param_t *_reverse_params (param_t *params, param_t *next); param_t *reverse_params (param_t *params); +param_t *append_params (param_t *params, param_t *more_params); param_t *copy_params (param_t *params); struct type_s *parse_params (struct type_s *type, param_t *params); param_t *check_params (param_t *params); diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index ff54b2ce5..7f53cd11d 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -120,7 +120,7 @@ param_append_identifiers (param_t *params, symbol_t *idents, type_t *type) return params; } -param_t * +static param_t * _reverse_params (param_t *params, param_t *next) { param_t *p = params; @@ -138,6 +138,20 @@ reverse_params (param_t *params) return _reverse_params (params, 0); } +param_t * +append_params (param_t *params, param_t *more_params) +{ + if (params) { + param_t *p; + for (p = params; p->next; ) { + p = p->next; + } + p->next = more_params; + return params; + } + return more_params; +} + param_t * copy_params (param_t *params) { diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index e68ad857f..676726a5c 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -89,8 +89,8 @@ new_method (type_t *ret_type, param_t *selector, param_t *opt_params) dstring_t *name = dstring_newstr (); dstring_t *types = dstring_newstr (); - opt_params = reverse_params (opt_params); - selector = _reverse_params (selector, opt_params); + selector = reverse_params (selector); + selector = append_params (selector, opt_params); cmd->next = selector; self->next = cmd; @@ -109,7 +109,7 @@ new_method (type_t *ret_type, param_t *selector, param_t *opt_params) free (name); free (types); - //print_type (meth->type); puts (""); + //print_type (meth->type); meth->def = 0; if (!known_methods) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 3732e47b7..93f4aeea9 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -2010,8 +2010,7 @@ optional_param_list | ',' param_list { $$ = $2; } | ',' param_list ',' ELLIPSIS { - $$ = new_param (0, 0, 0); - $$->next = $2; + $$ = param_append_identifiers ($2, 0, 0); } ; diff --git a/tools/qfcc/test/methodparams.r b/tools/qfcc/test/methodparams.r index b91322358..b29e6954b 100644 --- a/tools/qfcc/test/methodparams.r +++ b/tools/qfcc/test/methodparams.r @@ -15,3 +15,15 @@ typedef struct { int x, y; } Point; [textContext mvvprintf: pos, fmt, @args]; } @end +id obj_msgSend (id receiver, SEL op, ...) = #0; +void __obj_exec_class (struct obj_module *msg) = #0; +@interface Object +@end +@implementation Object +@end + +int +main (void) +{ + return 0; // to survive and prevail :) +} From bea64838cc3aac2519ce91ba8e317e57a6bfbd05 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 17:25:19 +0900 Subject: [PATCH 221/444] [qwaq] Use new TextContext Not quite right yet, but it worked first try (once I got another compiler bug sorted). --- ruamoko/qwaq/qwaq-group.h | 2 +- ruamoko/qwaq/qwaq-group.r | 2 +- ruamoko/qwaq/qwaq-screen.h | 2 -- ruamoko/qwaq/qwaq-screen.r | 26 ++++++--------------- ruamoko/qwaq/qwaq-textcontext.h | 8 +++++-- ruamoko/qwaq/qwaq-textcontext.r | 14 +++++++++++ ruamoko/qwaq/qwaq-view.h | 11 ++++++++- ruamoko/qwaq/qwaq-view.r | 41 +++++++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-window.r | 22 +++++++++--------- 9 files changed, 91 insertions(+), 37 deletions(-) diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h index a5cf5635e..b599a0c36 100644 --- a/ruamoko/qwaq/qwaq-group.h +++ b/ruamoko/qwaq/qwaq-group.h @@ -31,7 +31,7 @@ typedef BOOL condition_func2 (id object, void *anObject, void *data); { Array *views; int focused; - struct window_s *window; + TextContext *buffer; } -insert: (View *) view; -remove: (View *) view; diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index c25c6b9ee..6b8296182 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -116,7 +116,7 @@ not_dont_draw (id aView, void *aGroup) Group *group = (Group *) aGroup; if (!(view.options & ofDontDraw)) { if (!view.textContext) { - view.textContext = group.window; + view.textContext = group.buffer; } return YES; } diff --git a/ruamoko/qwaq/qwaq-screen.h b/ruamoko/qwaq/qwaq-screen.h index e92daa2a4..c51910d0e 100644 --- a/ruamoko/qwaq/qwaq-screen.h +++ b/ruamoko/qwaq/qwaq-screen.h @@ -11,8 +11,6 @@ +(Screen *) screen; -handleEvent: (qwaq_event_t *) event; -setBackground: (int) ch; --printf: (string) fmt, ...; --addch: (int) ch atX: (int) x Y: (int) y; @end #endif//__qwaq_screen_h diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index 7b7a9c9cd..e34ddb7c9 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -13,14 +13,8 @@ if (!(self = [super initWithRect:getwrect (stdscr)])) { return nil; } - textContext = stdscr; - scrollok (textContext, 1); - return self; -} - --setBackground: (int) ch -{ - wbkgd (textContext, ch); + textContext = [TextContext screen]; + [textContext scrollok: 1]; return self; } @@ -36,27 +30,21 @@ -draw { update_panels (); - doupdate (); + [TextContext doupdate]; return self; } -redraw { update_panels (); - wrefresh(textContext); - doupdate (); + [textContext refresh]; + [TextContext doupdate]; return self; } --printf: (string) fmt, ... +-setBackground: (int) ch { - wvprintf (textContext, fmt, @args); - return self; -} - --addch: (int) ch atX: (int) x Y: (int) y -{ - mvwaddch(textContext, x, y, ch); + [textContext bkgd:ch]; return self; } diff --git a/ruamoko/qwaq/qwaq-textcontext.h b/ruamoko/qwaq/qwaq-textcontext.h index 8cd20d74f..952814f08 100644 --- a/ruamoko/qwaq/qwaq-textcontext.h +++ b/ruamoko/qwaq/qwaq-textcontext.h @@ -17,16 +17,20 @@ + (void) move: (Point) pos; + (void) curs_set: (int) visibility; + (void) doupdate; ++ (TextContext *) screen; -init; -initWithRect: (Rect) rect; -initWithWindow: (window_t) window; -- (void) mvprintf: (Point) pos, string fmt, ...; + +-(window_t) window; + - (void) printf: (string) fmt, ...; - (void) vprintf: (string) mft, @va_list args; +- (void) mvprintf: (Point) pos, string fmt, ...; - (void) mvvprintf: (Point) pos, string mft, @va_list args; -- (void) refresh; - (void) mvaddch: (Point) pos, int ch; +- (void) refresh; - (void) bkgd: (int) ch; - (void) scrollok: (int) flag; - (void) border: (box_sides_t) sides, box_corners_t corners; diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index 43c8f9320..f38947773 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -17,6 +17,15 @@ + (void) curs_set: (int) visibility = #0; + (void) doupdate = #0; +static TextContext *screen; ++ (TextContext *) screen +{ + if (!screen) { + screen = [[TextContext alloc] init]; + } + return screen; +} + - init { if (!(self = [super init])) { @@ -45,6 +54,11 @@ return self; } +-(window_t) window +{ + return window; +} + - (void) mvprintf: (Point) pos, string fmt, ... = #0; - (void) printf: (string) fmt, ... = #0; - (void) vprintf: (string) mft, @va_list args = #0; diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index a168268af..0f8727128 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -6,6 +6,7 @@ #include "qwaq-draw.h" #include "qwaq-rect.h" +#include "qwaq-textcontext.h" @class Group; @@ -44,7 +45,7 @@ enum { Rect absRect; Point point; // can't be local :( Group *owner; - struct window_s *textContext; //FIXME separate class + TextContext *textContext; int state; int options; int cursorState; @@ -56,6 +57,14 @@ enum { -(struct Rect_s *)getRect; -draw; -redraw; + +- (void) refresh; +- (void) printf: (string) fmt, ...; +- (void) vprintf: (string) fmt, @va_list args; +//- (void) addch: (int) ch; +- (void) mvprintf: (Point) pos, string fmt, ...; +- (void) mvvprintf: (Point) pos, string fmt, @va_list args; +- (void) mvaddch: (Point) pos, int ch; @end #endif//__qwaq_view_h diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 6b6f3e80d..f5297c1e7 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -105,6 +105,47 @@ updateScreenCursor (View *view) return ▭ } +- (void) printf: (string) fmt, ... +{ + [textContext vprintf: fmt, @args]; +} + +- (void) vprintf: (string) fmt, @va_list args +{ + [textContext vprintf: fmt, args]; +} + +- (void) refresh +{ + [textContext refresh]; +} +/* +- (void) addch: (int) ch +{ + [textContext addch:ch]; +}*/ + +- (void) mvprintf: (Point) pos, string fmt, ... +{ + pos.x += xpos; + pos.y += ypos; + [textContext mvvprintf: pos, fmt, @args]; +} + +- (void) mvvprintf: (Point) pos, string fmt, @va_list args +{ + pos.x += xpos; + pos.y += ypos; + [textContext mvvprintf: pos, fmt, args]; +} + +- (void) mvaddch: (Point) pos, int ch +{ + pos.x += xpos; + pos.y += ypos; + [textContext mvaddch: pos, ch]; +} + @end Rect getwrect (window_t window) = #0; diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 45e8c4a77..3cee19d48 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -18,8 +18,8 @@ return nil; } self.rect = rect; - window = create_window (xpos, ypos, xlen, ylen); - panel = create_panel (window); + buffer = [[TextContext alloc] initWithRect: rect]; + panel = create_panel ([buffer window]); return self; } @@ -69,7 +69,7 @@ -setBackground: (int) ch { - wbkgd (window, ch); + [buffer bkgd: ch]; return self; } @@ -90,24 +90,24 @@ } } [super draw]; - int x = 1, y = 1; - wborder (window, box_sides, box_corners); + [buffer border: box_sides, box_corners]; + Point pos = { 1, 1 }; //for (int i = ACS_ULCORNER; i <= ACS_STERLING; i++) { for (int i = 32; i <= 127; i++) { int ch = acs_char (i); if (ch) { - mvwaddch (window, x, y, ch); + [buffer mvaddch: pos, ch]; } else { - mvwaddch (window, x, y, '.'); + [buffer mvaddch: pos, '.']; } - if (++x > 32) { - x = 1; - if (++y >= ylen) { + if (++pos.x > 32) { + pos.x = 1; + if (++pos.y >= ylen) { break; } } } - wrefresh (window); + [buffer refresh]; return self; } From d0a249590cfc29c07fc28918e753f2135de54616 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 17:45:58 +0900 Subject: [PATCH 222/444] [qwaq] Use self where possible for drawing in Window --- ruamoko/qwaq/qwaq-window.r | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 3cee19d48..53bf92d66 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -19,6 +19,7 @@ } self.rect = rect; buffer = [[TextContext alloc] initWithRect: rect]; + textContext = buffer; panel = create_panel ([buffer window]); return self; } @@ -96,9 +97,9 @@ for (int i = 32; i <= 127; i++) { int ch = acs_char (i); if (ch) { - [buffer mvaddch: pos, ch]; + [self mvaddch: pos, ch]; } else { - [buffer mvaddch: pos, '.']; + [self mvaddch: pos, '.']; } if (++pos.x > 32) { pos.x = 1; @@ -107,7 +108,7 @@ } } } - [buffer refresh]; + [self refresh]; return self; } From 9a96a9b2c990bd8b88dec2bd411473b69cb8df54 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 17:46:36 +0900 Subject: [PATCH 223/444] [qwaq] Use own version of positional drawing in Window Double offsetting the prints doesn't quite look right ;) --- ruamoko/qwaq/qwaq-window.r | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 53bf92d66..23d919648 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -127,4 +127,19 @@ { return [owner redraw]; } + +- (void) mvprintf: (Point) pos, string fmt, ... +{ + [textContext mvvprintf: pos, fmt, @args]; +} + +- (void) mvvprintf: (Point) pos, string fmt, @va_list args +{ + [textContext mvvprintf: pos, fmt, args]; +} + +- (void) mvaddch: (Point) pos, int ch +{ + [textContext mvaddch: pos, ch]; +} @end From b8b74fc07467d6c1f5a60e0fc73695dd15c3d52c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 17:57:33 +0900 Subject: [PATCH 224/444] [qwaq] Implement missing addch I either forgot about it, or just didn't need it at the time, but I'm sure it will be useful later when more stuff is implemented. --- ruamoko/qwaq/qwaq-curses.c | 48 ++++++++++++++++++++++++++++++++- ruamoko/qwaq/qwaq-curses.h | 1 + ruamoko/qwaq/qwaq-textcontext.h | 1 + ruamoko/qwaq/qwaq-textcontext.r | 2 ++ ruamoko/qwaq/qwaq-view.h | 2 +- ruamoko/qwaq/qwaq-view.r | 4 +-- 6 files changed, 54 insertions(+), 4 deletions(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index f625f80ec..8b218dfad 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -72,6 +72,7 @@ typedef enum qwaq_commands_e { qwaq_cmd_mvwaddstr, qwaq_cmd_waddstr, qwaq_cmd_mvwaddch, + qwaq_cmd_waddch, qwaq_cmd_wrefresh, qwaq_cmd_init_pair, qwaq_cmd_wbkgd, @@ -532,6 +533,16 @@ cmd_mvwaddch (qwaq_resources_t *res) mvwaddch (window->win, y, x, ch); } +static void +cmd_waddch (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int ch = RB_PEEK_DATA (res->command_queue, 3); + + window_t *window = get_window (res, __FUNCTION__, window_id); + waddch (window->win, ch); +} + static void cmd_wrefresh (qwaq_resources_t *res) { @@ -665,6 +676,9 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_mvwaddch: cmd_mvwaddch (res); break; + case qwaq_cmd_waddch: + cmd_waddch (res); + break; case qwaq_cmd_wrefresh: cmd_wrefresh (res); break; @@ -1102,6 +1116,27 @@ bi_wvprintf (progs_t *pr) qwaq_wvprintf (pr, window_id, fmt, args); } +static void +qwaq_waddch (progs_t *pr, int window_id, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_waddch, 0, window_id, ch }; + + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_waddch (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int ch = P_INT (pr, 0); + + qwaq_waddch (pr, window_id, ch); +} + static void qwaq_mvwvprintf (progs_t *pr, int window_id, int x, int y, const char *fmt, pr_va_list_t *args) @@ -1451,7 +1486,7 @@ bi_i_TextContext__printf_ (progs_t *pr) } static void -bi_i_TextContext__vprintf_ (progs_t *pr) +bi_i_TextContext__addch_ (progs_t *pr) { int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; const char *fmt = P_GSTRING (pr, 2); @@ -1460,6 +1495,15 @@ bi_i_TextContext__vprintf_ (progs_t *pr) qwaq_wvprintf (pr, window_id, fmt, args); } +static void +bi_i_TextContext__vprintf_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int ch = P_INT (pr, 1); + + qwaq_waddch (pr, window_id, ch); +} + static void bi_i_TextContext__mvvprintf_ (progs_t *pr) { @@ -1551,6 +1595,7 @@ static builtin_t builtins[] = { {"wvprintf", bi_wvprintf, -1}, {"mvwvprintf", bi_mvwvprintf, -1}, {"mvwaddch", bi_mvwaddch, -1}, + {"waddch", bi_waddch, -1}, {"wrefresh", bi_wrefresh, -1}, {"get_event", bi_get_event, -1}, {"max_colors", bi_max_colors, -1}, @@ -1574,6 +1619,7 @@ static builtin_t builtins[] = { {"_i_TextContext__mvprintf_", bi_i_TextContext__mvprintf_, -1}, {"_i_TextContext__printf_", bi_i_TextContext__printf_, -1}, {"_i_TextContext__vprintf_", bi_i_TextContext__vprintf_, -1}, + {"_i_TextContext__addch_", bi_i_TextContext__addch_, -1}, {"_i_TextContext__mvvprintf_", bi_i_TextContext__mvvprintf_, -1}, {"_i_TextContext__refresh", bi_i_TextContext__refresh, -1}, {"_i_TextContext__mvaddch_", bi_i_TextContext__mvaddch_, -1}, diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index aa9d2456d..16cd4fe4e 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -94,6 +94,7 @@ typedef struct panel_s *panel_t; string fmt, @va_list args); @extern void wrefresh (window_t win); @extern void mvwaddch (window_t win, int x, int y, int ch); +@extern void waddch (window_t win, int ch); @extern panel_t create_panel (window_t window); @extern void destroy_panel (panel_t panel); diff --git a/ruamoko/qwaq/qwaq-textcontext.h b/ruamoko/qwaq/qwaq-textcontext.h index 952814f08..4a47b16ca 100644 --- a/ruamoko/qwaq/qwaq-textcontext.h +++ b/ruamoko/qwaq/qwaq-textcontext.h @@ -27,6 +27,7 @@ - (void) printf: (string) fmt, ...; - (void) vprintf: (string) mft, @va_list args; +- (void) addch: (int) ch; - (void) mvprintf: (Point) pos, string fmt, ...; - (void) mvvprintf: (Point) pos, string mft, @va_list args; - (void) mvaddch: (Point) pos, int ch; diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index f38947773..59b54fb6a 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -62,6 +62,7 @@ static TextContext *screen; - (void) mvprintf: (Point) pos, string fmt, ... = #0; - (void) printf: (string) fmt, ... = #0; - (void) vprintf: (string) mft, @va_list args = #0; +- (void) addch: (int) ch = #0; - (void) mvvprintf: (Point) pos, string mft, @va_list args = #0; - (void) refresh = #0; - (void) mvaddch: (Point) pos, int ch = #0; @@ -82,6 +83,7 @@ void wvprintf (window_t win, string fmt, @va_list args) = #0; void mvwvprintf (window_t win, int x, int y, string fmt, @va_list args) = #0; void wrefresh (window_t win) = #0; void mvwaddch (window_t win, int x, int y, int ch) = #0; +void waddch (window_t win, int ch) = #0; int get_event (qwaq_event_t *event) = #0; int max_colors (void) = #0; int max_color_pairs (void) = #0; diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index 0f8727128..10e0c93ae 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -61,7 +61,7 @@ enum { - (void) refresh; - (void) printf: (string) fmt, ...; - (void) vprintf: (string) fmt, @va_list args; -//- (void) addch: (int) ch; +- (void) addch: (int) ch; - (void) mvprintf: (Point) pos, string fmt, ...; - (void) mvvprintf: (Point) pos, string fmt, @va_list args; - (void) mvaddch: (Point) pos, int ch; diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index f5297c1e7..541012a47 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -119,11 +119,11 @@ updateScreenCursor (View *view) { [textContext refresh]; } -/* + - (void) addch: (int) ch { [textContext addch:ch]; -}*/ +} - (void) mvprintf: (Point) pos, string fmt, ... { From 1250fe7446c5f2a676285ccf18f9b53844143083 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 18:29:16 +0900 Subject: [PATCH 225/444] [qwaq] Use a log file instead of stderr Now I don't have to worry about remembering to redirect the output, but debugging is still easy. --- ruamoko/qwaq/qwaq-curses.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 8b218dfad..15746b5e6 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -1630,11 +1630,13 @@ static builtin_t builtins[] = { {0} }; +static FILE *logfile; + static __attribute__((format(printf, 1, 0))) void qwaq_print (const char *fmt, va_list args) { - vfprintf (stderr, fmt, args); - fflush (stderr); + vfprintf (logfile, fmt, args); + fflush (logfile); } void @@ -1650,5 +1652,6 @@ BI_Init (progs_t *pr) PR_Resources_Register (pr, "qwaq", res, bi_qwaq_clear); PR_RegisterBuiltins (pr, builtins); Sys_RegisterShutdown (bi_shutdown); + logfile = fopen ("qwaq-curses.log", "wt"); Sys_SetStdPrintf (qwaq_print); } From 07e6baf32f66fa372a90b88321f1b6386c1d38c1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 20:32:37 +0900 Subject: [PATCH 226/444] [qfcc] Support { } as nil in nested initializers Did top-level earlier, but forgot to add support for deeper nestings. --- tools/qfcc/source/def.c | 5 ++++- tools/qfcc/source/qc-parse.y | 21 +++++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 93152b6db..cf36912bf 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -450,7 +450,10 @@ init_elements (struct def_s *def, expr_t *eles) if (element->expr) { c = constant_expr (element->expr); } else { - c = convert_nil (new_nil_expr (), type); + c = new_nil_expr (); + } + if (c->type == ex_nil) { + c = convert_nil (c, type); } append_expr (local_expr, assign_expr (unary_expr ('.', ptr), c)); } diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 93f4aeea9..ba266c512 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1148,7 +1148,8 @@ opt_initializer var_initializer : '=' expr { $$ = $2; } - | '=' '{' element_list optional_comma '}' { $$ = $3; } + | '=' '{' { $$ = $-1; } + element_list optional_comma '}' { $$ = $4; } | '=' '{' '}' { if (is_scalar ($-1.type)) { @@ -1169,14 +1170,26 @@ element_list $$ = new_block_expr (); append_expr ($$, $1); } - | element_list ',' element + | element_list ',' {$$ = $0; } element { - append_expr ($$, $3); + append_expr ($$, $4); } ; element - : '{' element_list optional_comma '}' { $$ = $2; } + : '{' { $$ = $0; } + element_list optional_comma '}' { $$ = $3; } + | '{' '}' + { + // FIXME doesn't check the right type (does prove the inherited + // attributes have been passed down correctly though). The problem + // is that the type of the sub elements needs to be extracted if + // possible + if (is_scalar ($0.type)) { + error (0, "empty scalar initializer"); + } + $$ = new_nil_expr (); + } | expr { $$ = $1; } ; From 9dbc81432a8212ca19b5106bd23c6657e7743e77 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 20:33:47 +0900 Subject: [PATCH 227/444] [qfcc] Use full type for differentiating values This fixes the problem of using nil for two different compound types within the one expression. The problem is all compound types have the same low-level type (ev_invalid) and this caused the two different nils to have the same type when taken back up to expression level. --- tools/qfcc/source/value.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index fc2024a57..97198268c 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -80,7 +80,7 @@ static uintptr_t value_get_hash (const void *_val, void *unused) { const ex_value_t *val = (const ex_value_t *) _val; - return Hash_Buffer (&val->v, sizeof (val->v)) + val->lltype; + return Hash_Buffer (&val->v, sizeof (val->v)) ^ (uintptr_t) val->type; } static int @@ -88,7 +88,7 @@ value_compare (const void *_val1, const void *_val2, void *unused) { const ex_value_t *val1 = (const ex_value_t *) _val1; const ex_value_t *val2 = (const ex_value_t *) _val2; - if (val1->lltype != val2->lltype) + if (val1->type != val2->type) return 0; return memcmp (&val1->v, &val2->v, sizeof (val1->v)) == 0; } From de06efa6047a682e10ee9c45ef868b7b3f1e7715 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 20:38:40 +0900 Subject: [PATCH 228/444] [qfcc] Fix handling of nil for static initializers nil is most definitely constant. --- tools/qfcc/source/def.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index cf36912bf..3f2f1c838 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -463,7 +463,10 @@ init_elements (struct def_s *def, expr_t *eles) if (element->expr) { c = constant_expr (element->expr); } else { - c = convert_nil (new_nil_expr (), element->type); + c = new_nil_expr (); + } + if (c->type == ex_nil) { + c = convert_nil (c, element->type); } dummy.offset = def->offset + element->offset; g = D_POINTER (pr_type_t, &dummy); From f0ecf7b30a776d6ec6f50c3e168a304d776d4ace Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 20:43:38 +0900 Subject: [PATCH 229/444] [qwaq] Clean out log file with make clean --- ruamoko/qwaq/Makefile.am | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruamoko/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am index cf71f7590..bf8c2c9b8 100644 --- a/ruamoko/qwaq/Makefile.am +++ b/ruamoko/qwaq/Makefile.am @@ -80,4 +80,4 @@ am--depfiles: $(am__depfiles_remade) $(r_depfiles_remade) EXTRA_PROGRAMS=qwaq-curses qwaq-x11 EXTRA_DIST=$(qwaq_dat_src) qwaq.h -CLEANFILES= *.dat *.sym +CLEANFILES= *.dat *.sym qwaq-curses.log From f7757cf894a357681d008c5ee6af650f6df99356 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 21:05:53 +0900 Subject: [PATCH 230/444] [qfcc] Add filename to dot output It makes things so much easier when viewing the graphs --- tools/qfcc/source/dot_dag.c | 1 + tools/qfcc/source/dot_expr.c | 1 + tools/qfcc/source/dot_flow.c | 1 + tools/qfcc/source/dot_sblock.c | 1 + 4 files changed, 4 insertions(+) diff --git a/tools/qfcc/source/dot_dag.c b/tools/qfcc/source/dot_dag.c index bf0e26c63..e954f75d3 100644 --- a/tools/qfcc/source/dot_dag.c +++ b/tools/qfcc/source/dot_dag.c @@ -176,6 +176,7 @@ dot_dump_dag (void *_dag, const char *filename) dstring_t *dstr = dstring_newstr(); dasprintf (dstr, "digraph dag_%p {\n", dag); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot;\n"); dasprintf (dstr, " clusterrank=local;\n"); dasprintf (dstr, " rankdir=TB;\n"); diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index 081dbecec..f8601c6ff 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -551,6 +551,7 @@ dump_dot_expr (void *_e, const char *filename) expr_t *e = (expr_t *) _e; dasprintf (dstr, "digraph expr_%p {\n", e); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot; rankdir=TB; compound=true;\n"); _print_expr (dstr, e, 0, ++id, 0); dasprintf (dstr, "}\n"); diff --git a/tools/qfcc/source/dot_flow.c b/tools/qfcc/source/dot_flow.c index d702f7b9e..68f043d98 100644 --- a/tools/qfcc/source/dot_flow.c +++ b/tools/qfcc/source/dot_flow.c @@ -332,6 +332,7 @@ print_flowgraph (flow_dot_t *method, flowgraph_t *graph, const char *filename) dstring_t *dstr = dstring_newstr(); dasprintf (dstr, "digraph flowgraph_%s_%p {\n", method->type, graph); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot;\n"); dasprintf (dstr, " clusterrank=local;\n"); dasprintf (dstr, " rankdir=TB;\n"); diff --git a/tools/qfcc/source/dot_sblock.c b/tools/qfcc/source/dot_sblock.c index 72b245efe..26e32681e 100644 --- a/tools/qfcc/source/dot_sblock.c +++ b/tools/qfcc/source/dot_sblock.c @@ -128,6 +128,7 @@ print_sblock (sblock_t *sblock, const char *filename) dstring_t *dstr = dstring_newstr(); dasprintf (dstr, "digraph sblock_%p {\n", sblock); + dasprintf (dstr, " graph [label=\"%s\"];\n", quote_string (filename)); dasprintf (dstr, " layout=dot; rankdir=TB;\n"); for (i = 0; sblock; sblock = sblock->next, i++) flow_sblock (dstr, sblock, i); From faa6eabfbe0fdf51fd983740f77e65aaae2702b7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 6 Mar 2020 22:28:04 +0900 Subject: [PATCH 231/444] [qfcc] Add a failing test for struct init to param This actually took a bit to reproduce. --- tools/qfcc/test/Makefile.am | 10 ++++++++++ tools/qfcc/test/struct-init-param.r | 30 +++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 tools/qfcc/test/struct-init-param.r diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index 7ea8e5c21..99c24142c 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -50,6 +50,7 @@ test_progs_dat=\ return-ivar.dat \ sendv.dat \ state.dat \ + struct-init-param.dat \ struct-nil-init.dat \ structarray.dat \ structlive.dat \ @@ -322,6 +323,15 @@ state.run: Makefile build-run include ./$(DEPDIR)/state.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/state.Qo +struct_init_param_dat_SOURCES=struct-init-param.r +struct_init_param_obj=$(struct_init_param_dat_SOURCES:.r=.qfo) +struct-init-param.dat$(EXEEXT): $(struct_init_param_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(struct_init_param_obj) +struct-init-param.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/struct-init-param.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/struct-init-param.Qo + struct_nil_init_dat_SOURCES=struct-nil-init.r struct_nil_init_obj=$(struct_nil_init_dat_SOURCES:.r=.qfo) struct-nil-init.dat$(EXEEXT): $(struct_nil_init_obj) $(QFCC_DEP) diff --git a/tools/qfcc/test/struct-init-param.r b/tools/qfcc/test/struct-init-param.r new file mode 100644 index 000000000..8b166099e --- /dev/null +++ b/tools/qfcc/test/struct-init-param.r @@ -0,0 +1,30 @@ +typedef struct { + int x; + int y; +} Point; + +typedef struct { + int width; + int height; +} Extent; + +typedef struct Rect_s { + Point offset; + Extent extent; +} Rect; + +void *foo (void *obj, void *cmd, void *o, Point pos, Rect r) +{ + return obj; +} + +void *bar (Rect *obj, void *cmd, void *o, Point pos) +{ + Rect rect = { {}, obj.extent }; + return foo (obj, cmd, o, pos, rect); +} + +int main (void) +{ + return 1;// don't want this to pass until I've checked the generated code +} From 48514ba2f3dd432371ed3325a46108ecd4f9bb19 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 7 Mar 2020 01:30:36 +0900 Subject: [PATCH 232/444] [qfcc] Create alias def for defs accessed via pointer This the fixes the incorrect flow analysis caused by the def being seen to have the wrong size (structure field of structure def seen through a constant pointer). Fixes the ICE, but the pointer constant is broken somewhere in dags, presumably. --- tools/qfcc/source/flow.c | 4 +++- tools/qfcc/source/statements.c | 8 +++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 995aa5b7d..aa05733e8 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -859,8 +859,10 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, && s->opc->o.value->lltype == ev_pointer && s->opc->o.value->v.pointer.def) { operand_t *op; + def_t *alias; ex_pointer_t *ptr = &s->opc->o.value->v.pointer; - op = def_operand (ptr->def, ptr->type); + alias = alias_def (ptr->def, ptr->type, ptr->val); + op = def_operand (alias, ptr->type); flow_add_op_var (def, op); if (operands) operands[0] = op; diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 239c11f49..e29cedaa4 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -103,7 +103,13 @@ operand_string (operand_t *op) op->o.value->v.quaternion_val[2], op->o.value->v.quaternion_val[3]); case ev_pointer: - return va ("ptr %d", op->o.value->v.pointer.val); + if (op->o.value->v.pointer.def) { + return va ("ptr %s+%d", + op->o.value->v.pointer.def->name, + op->o.value->v.pointer.val); + } else { + return va ("ptr %d", op->o.value->v.pointer.val); + } case ev_field: return va ("field %d", op->o.value->v.pointer.val); case ev_entity: From 6ada20f685fcf4d46dfd2e376d5dd91aa7ead93e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 7 Mar 2020 02:06:33 +0900 Subject: [PATCH 233/444] [qfcc] Show offset for op_x_def_ofs relocs --- tools/qfcc/source/dump_globals.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 657f016e8..157635f63 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -337,6 +337,8 @@ qfo_relocs (qfo_t *qfo) qfo_reloc_t *reloc; qfo_def_t *def; qfo_func_t *func; + int opind; + dstatement_t *statement; unsigned i; for (i = 0; i < qfo->num_relocs; i++) { @@ -399,10 +401,13 @@ qfo_relocs (qfo_t *qfo) case rel_op_b_def_ofs: case rel_op_c_def_ofs: def = qfo->defs + reloc->target; - printf (" op.%c@%x def#%d %s", - reloc->type - rel_op_a_def_ofs + 'a', + opind = reloc->type - rel_op_a_def_ofs; + statement = QFO_STATEMENT (qfo, reloc->offset); + printf (" op.%c@%x def#%d %s+%d", + opind + 'a', reloc->offset, reloc->target, - QFO_GETSTR (qfo, def->name)); + QFO_GETSTR (qfo, def->name), + ((pr_ushort_t *)statement)[opind + 1]); break; case rel_def_def_ofs: def = qfo->defs + reloc->target; From 777ce56cf3090f7b32edec1dbdcbe3e47e8cf4ba Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 7 Mar 2020 17:48:19 +0900 Subject: [PATCH 234/444] [doc] Enable MathJax Nice. Very nice. --- doc/quakeforge.dox.conf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/quakeforge.dox.conf.in b/doc/quakeforge.dox.conf.in index 3781f222a..a235a895d 100644 --- a/doc/quakeforge.dox.conf.in +++ b/doc/quakeforge.dox.conf.in @@ -1566,7 +1566,7 @@ FORMULA_TRANSPARENT = YES # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -USE_MATHJAX = NO +USE_MATHJAX = YES # When MathJax is enabled you can set the default output format to be used for # the MathJax output. See the MathJax site (see: From e524db1fc116778859c4bb8cfa00e9b03956d523 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 03:11:46 +0900 Subject: [PATCH 235/444] [qfcc] Set op type when aliasing a value This fixes the ICE when attempting to compile address-cast without optimization (just realized why, too: the assignment was optimized out of existence). --- tools/qfcc/source/statements.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index e29cedaa4..2f2d0a07d 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -890,6 +890,7 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op) type = e->e.expr.type; sblock = statement_subexpr (sblock, e->e.expr.e1, &aop); if (type_compatible (aop->type, type)) { + //FIXME type_compatible??? shouldn't that be type_size ==? if (offset) { internal_error (e, "offset alias of same size type"); } @@ -924,6 +925,7 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op) *op = def_operand (alias_def (def, type, offset), 0); } else if (aop->op_type == op_value) { *op = value_operand (aop->o.value); + (*op)->type = type; } else { internal_error (e, "invalid alias target: %s: %s", optype_str (aop->op_type), operand_string (aop)); From 2b15e61b28f5c56429115e570788e8b7b8c3ef9f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 03:33:01 +0900 Subject: [PATCH 236/444] [qfcc] Remove obsolete structure fields init_vars hasn't been used for a long time. --- tools/qfcc/include/flow.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tools/qfcc/include/flow.h b/tools/qfcc/include/flow.h index b4cc48cf5..515c207d1 100644 --- a/tools/qfcc/include/flow.h +++ b/tools/qfcc/include/flow.h @@ -84,12 +84,6 @@ typedef struct flownode_s { struct set_s *in; struct set_s *out; } live_vars; - struct { - struct set_s *use; - struct set_s *def; - struct set_s *in; - struct set_s *out; - } init_vars; struct sblock_s *sblock; ///< original statement block struct dag_s *dag; ///< dag for this node } flownode_t; From f56de00c2103692fbdcb480415eec4b02181b934 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 03:38:45 +0900 Subject: [PATCH 237/444] [qfcc] Rename a field depth_first is much clearer than dfo. I had to check what dfo meant too many times in one night. --- tools/qfcc/include/flow.h | 2 +- tools/qfcc/source/flow.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/qfcc/include/flow.h b/tools/qfcc/include/flow.h index 515c207d1..f57fd3c37 100644 --- a/tools/qfcc/include/flow.h +++ b/tools/qfcc/include/flow.h @@ -96,7 +96,7 @@ typedef struct flowgraph_s { flowedge_t *edges; ///< array of all edges in the graph int num_edges; struct set_s *dfst; ///< edges in the depth-first search tree - int *dfo; ///< depth-first order of nodes + int *depth_first; ///< depth-first order of nodes flowloop_t *loops; ///< linked list of natural loops } flowgraph_t; diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index aa05733e8..3f1f37151 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -148,8 +148,8 @@ delete_graph (flowgraph_t *graph) free (graph->edges); if (graph->dfst) set_delete (graph->dfst); - if (graph->dfo) - free (graph->dfo); + if (graph->depth_first) + free (graph->depth_first); FREE (graphs, graph); } @@ -541,7 +541,7 @@ flow_reaching_defs (flowgraph_t *graph) changed = 0; // flow down the graph for (i = 0; i < graph->num_nodes; i++) { - node = graph->nodes[graph->dfo[i]]; + node = graph->nodes[graph->depth_first[i]]; in = node->reaching_defs.in; out = node->reaching_defs.out; gen = node->reaching_defs.gen; @@ -626,7 +626,7 @@ flow_live_vars (flowgraph_t *graph) // flow UP the graph because live variable analysis uses information // from a node's successors rather than its predecessors. for (j = graph->num_nodes - 1; j >= 0; j--) { - node = graph->nodes[graph->dfo[j]]; + node = graph->nodes[graph->depth_first[j]]; set_empty (tmp); for (succ = set_first (node->successors); succ; succ = set_next (succ)) @@ -718,7 +718,7 @@ flow_uninitialized (flowgraph_t *graph) defs = set_new (); for (i = 0; i < graph->num_nodes; i++) { - node = graph->nodes[graph->dfo[i]]; + node = graph->nodes[graph->depth_first[i]]; set_empty (defs); // collect definitions of all variables "used" in this node. use from // the live vars analysis is perfect for the job @@ -1177,7 +1177,7 @@ df_search (flowgraph_t *graph, set_t *visited, int *i, int n) } } node->dfn = --*i; - graph->dfo[node->dfn] = n; + graph->depth_first[node->dfn] = n; } static void @@ -1190,11 +1190,11 @@ flow_build_dfst (flowgraph_t *graph) set_add (visited, graph->num_nodes); set_add (visited, graph->num_nodes + 1); - if (graph->dfo) - free (graph->dfo); + if (graph->depth_first) + free (graph->depth_first); if (graph->dfst) set_delete (graph->dfst); - graph->dfo = calloc (graph->num_nodes, sizeof (int)); + graph->depth_first = calloc (graph->num_nodes, sizeof (int)); graph->dfst = set_new (); i = graph->num_nodes; df_search (graph, visited, &i, 0); From d44d956038698da9e02562e1452a430052199b00 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 03:39:24 +0900 Subject: [PATCH 238/444] [qfcc] Remove a long dead function --- tools/qfcc/source/flow.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 3f1f37151..f7e144663 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -210,18 +210,6 @@ flowvar_is_local (flowvar_t *var) { return !(flowvar_is_global (var) || flowvar_is_param (var)); } -#if 0 -static int -flowvar_is_initialized (flowvar_t *var) -{ - def_t *def; - - if (var->op->op_type != op_def) - return 0; - def = var->op->o.def; - return def->initialized; -} -#endif flowvar_t * flow_get_var (operand_t *op) { From 7338689146f5e588460fa90196b0520b9d91699f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 03:42:18 +0900 Subject: [PATCH 239/444] [qfcc] Treat offset real tempops as an error tempops always have an offset field, but only those that are aliases should ever have a non-zero offset. --- tools/qfcc/source/flow.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index f7e144663..526aadbcd 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -271,6 +271,9 @@ get_temp_address (function_t *func, operand_t *op) top->o.tempop.flowaddr = func->tmpaddr; func->tmpaddr += top->size; } + if (top->o.tempop.offset) { + internal_error (0, "real tempop with a non-zero offset"); + } op->o.tempop.flowaddr = top->o.tempop.flowaddr + op->o.tempop.offset; return op->o.tempop.flowaddr; } From 809c103fd1f6b856b8a788adacdddbbedf10c677 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 03:46:52 +0900 Subject: [PATCH 240/444] [qfcc] Shuffle some code around to be clearer Doing the same thing at the end of two branches of an if/else seems off. And doing an associative(?) set operation every time through a loop is wasteful. --- tools/qfcc/source/flow.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 526aadbcd..d5288616a 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -458,12 +458,11 @@ flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) if (op->op_type == op_temp) { tempop_visit_all (&op->o.tempop, 1, flow_tempop_kill_aliases_visit, tmp); - set_difference (tmp, uninit); } else if (op->op_type == op_def) { def_visit_all (op->o.def, 1, flow_def_kill_aliases_visit, tmp); - // don't allow aliases to kill definitions in the entry dummy block - set_difference (tmp, uninit); } + // don't allow aliases to kill definitions in the entry dummy block + set_difference (tmp, uninit); // merge the alias kills with the current def's kills set_union (kill, tmp); } @@ -492,8 +491,8 @@ flow_reaching_defs (flowgraph_t *graph) for (i = 0; i < graph->func->num_vars; i++) { var = graph->func->vars[i]; set_union (uninit, var->define);// do not want alias handling here - set_difference (uninit, kill); // remove any gens from the function } + set_difference (uninit, kill); // remove any gens from the function graph->nodes[graph->num_nodes]->reaching_defs.out = uninit; graph->nodes[graph->num_nodes]->reaching_defs.in = set_new (); graph->nodes[graph->num_nodes]->reaching_defs.gen = set_new (); From e4c87091a36c7a891f861fb4a5e4bb10c86fc798 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 03:53:53 +0900 Subject: [PATCH 241/444] [qfcc] Lots of flow analysis docs And some function shuffling for grouping. I'm not satisfied with the docs, but they're a lot more helpful than they were. --- tools/qfcc/source/flow.c | 343 ++++++++++++++++++++++++++++++++------- 1 file changed, 283 insertions(+), 60 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index d5288616a..0a29ff16d 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -57,11 +57,11 @@ #include "symtab.h" #include "type.h" -static flowvar_t *vars_freelist; -static flowloop_t *loops_freelist; -static flownode_t *nodes_freelist; -static flowgraph_t *graphs_freelist; +/// \addtogroup qfcc_flow +///@{ +/** Static operand definitions for the ever present return and parameter slots. + */ static struct { const char *name; operand_t op; @@ -78,6 +78,17 @@ static struct { }; static const int num_flow_params = sizeof(flow_params)/sizeof(flow_params[0]); +/** \name Flow analysis memory management */ +///@{ +static flowvar_t *vars_freelist; ///< flowvar pool +static flowloop_t *loops_freelist; ///< flow loop pool +static flownode_t *nodes_freelist; ///< flow node pool +static flowgraph_t *graphs_freelist; ///< flow graph pool + +/** Allocate a new flow var. + * + * The var's use and define sets are initialized to empty. + */ static flowvar_t * new_flowvar (void) { @@ -88,6 +99,10 @@ new_flowvar (void) return var; } +/** Allocate a new flow loop. + * + * The loop's nodes set is initialized to the empty set. + */ static flowloop_t * new_loop (void) { @@ -97,6 +112,8 @@ new_loop (void) return loop; } +/** Free a flow loop and its nodes set. + */ static void delete_loop (flowloop_t *loop) { @@ -104,6 +121,10 @@ delete_loop (flowloop_t *loop) FREE (loops, loop); } +/** Allocate a new flow node. + * + * The node is completely empty. + */ static flownode_t * new_node (void) { @@ -112,6 +133,10 @@ new_node (void) return node; } +/** Free a flow node and its resources. + * + * \bug not global_vars or the vars and defs sets? + */ static void delete_node (flownode_t *node) { @@ -126,6 +151,10 @@ delete_node (flownode_t *node) FREE (nodes, node); } +/** Allocate a new flow graph. + * + * The graph is completely empty. + */ static flowgraph_t * new_graph (void) { @@ -134,6 +163,10 @@ new_graph (void) return graph; } +/** Return a flow graph and its resources to the pools. + * + * \bug except loops? + */ static void __attribute__((unused)) delete_graph (flowgraph_t *graph) { @@ -152,7 +185,77 @@ delete_graph (flowgraph_t *graph) free (graph->depth_first); FREE (graphs, graph); } +///@} +/** \name Flowvar classification */ +///@{ +/** Check if the flowvar refers to a global variable. + * + * For the flowvar to refer to a global variable, the flowvar's operand + * must be a def operand (but the def itself may be an alias of the real def) + * and the rel def must not have its def_t::local flag set. This means that + * function-scope static variables are not considered local (ie, only + * non-static function-scope variables and function parameters are considered + * local (temp vars are local too, but are not represented by \a op_def)). + */ +static int +flowvar_is_global (flowvar_t *var) +{ + def_t *def; + + if (var->op->op_type != op_def) + return 0; + def = var->op->o.def; + if (def->alias) + def = def->alias; + if (def->local) + return 0; + return 1; +} + +/** Check if the flowvar refers to a function parameter. + * + * For the flowvar to refer to a function parameter, the flowvar's operand + * must be a def operand (but the def itself may be an alias of the real def) + * and the rel def must have both its def_t::local and def_t::param flags set. + * + * Temp vars are are not represented by op_def, so no mistake can be made. + */ +static int +flowvar_is_param (flowvar_t *var) +{ + def_t *def; + + if (var->op->op_type != op_def) + return 0; + def = var->op->o.def; + if (def->alias) + def = def->alias; + if (!def->local) + return 0; + if (!def->param) + return 0; + return 1; +} + +/** Check if the flowvar refers to a function parameter. + * + * As this is simply "neither global nor pamam", all other flowvars are + * considered local, in particular actual non-staic function scope variables + * and temp vars. + */ +static int +flowvar_is_local (flowvar_t *var) +{ + return !(flowvar_is_global (var) || flowvar_is_param (var)); +} +///@} + +/** Extract the def from a def or temp flowvar. + * + * It is an error for the operand referenced by the flowvar to be anything + * other than a real def or temp. + */ static __attribute__((pure)) def_t * flowvar_get_def (flowvar_t *var) { @@ -173,43 +276,13 @@ flowvar_get_def (flowvar_t *var) return 0; } -static int -flowvar_is_global (flowvar_t *var) -{ - def_t *def; - - if (var->op->op_type != op_def) - return 0; - def = var->op->o.def; - if (def->alias) - def = def->alias; - if (def->local) - return 0; - return 1; -} - -static int -flowvar_is_param (flowvar_t *var) -{ - def_t *def; - - if (var->op->op_type != op_def) - return 0; - def = var->op->o.def; - if (def->alias) - def = def->alias; - if (!def->local) - return 0; - if (!def->param) - return 0; - return 1; -} - -static int -flowvar_is_local (flowvar_t *var) -{ - return !(flowvar_is_global (var) || flowvar_is_param (var)); -} +/** Get a def or temp var operand's flowvar. + * + * Other operand types never have a flowvar. + * + * If the operand does not yet have a flowvar, one is created and assigned + * to the operand. + */ flowvar_t * flow_get_var (operand_t *op) { @@ -229,6 +302,12 @@ flow_get_var (operand_t *op) return 0; } +/** Indicate whether the operand should be counted. + * + * If the operand is a def or temp var operand, and it has not already been + * counted, then it is counted, otherwise it is not. + * \return 1 if the operand should be counted, 0 if not + */ static int count_operand (operand_t *op) { @@ -240,14 +319,15 @@ count_operand (operand_t *op) return 0; var = flow_get_var (op); - // flowvars are initialized with number == 0, and any global flowvar - // used by a function will always have a number >= 0 after flow analysis, - // and local flowvars will always be 0 before flow analysis, so use -1 - // to indicate the variable has been counted. - // - // Also, since this is the beginning of flow analysis for this function, - // ensure the define/use sets for global vars are empty. However, as - // checking if a var is global is too much trouble, just clear them all. + /** Flowvars are initialized with number == 0, and any global flowvar + * used by a function will always have a number >= 0 after flow analysis, + * and local flowvars will always be 0 before flow analysis, so use -1 + * to indicate the variable has been counted. + * + * Also, since this is the beginning of flow analysis for this function, + * ensure the define/use sets for global vars are empty. However, since + * checking if a var is global is too much trouble, just clear them all. + */ if (var && var->number != -1) { set_empty (var->use); set_empty (var->define); @@ -257,6 +337,22 @@ count_operand (operand_t *op) return 0; } +/** Allocate flow analysis pseudo address space to a temporary variable. + * + * If the operand already has an address allocated (flowvar_t::flowaddr is + * not 0), then the already allocated address is returned. + * + * If the operand refers to an alias, the alias chain is followed to the + * actual temp var operand and the real temp var is allocated space if it + * has not allready been alloced. + * + * The operand is given the address of the real temp var operand plus whatever + * offset the operand has. + * + * Real temp var operands must have a zero offset. + * + * The operand address is set in \a op and returned. + */ static int get_temp_address (function_t *func, operand_t *op) { @@ -278,6 +374,8 @@ get_temp_address (function_t *func, operand_t *op) return op->o.tempop.flowaddr; } +/** Add an operand's flowvar to the function's list of variables. + */ static void add_operand (function_t *func, operand_t *op) { @@ -289,8 +387,15 @@ add_operand (function_t *func, operand_t *op) return; var = flow_get_var (op); - // If the flowvar number is still -1, then the flowvar has not yet been - // added to the list of variables referenced by the function. + /** If the flowvar number is still -1, then the flowvar has not yet been + * added to the list of variables referenced by the function. + * + * The flowvar's flowvar_t::number is set to its index in the function's + * list of flowvars. + * + * Also, temp and local flowvars are assigned addresses from the flow + * analysys pseudo address space so partial accesses can be analyzed. + */ if (var && var->number == -1) { var->number = func->num_vars++; var->op = op; @@ -303,6 +408,8 @@ add_operand (function_t *func, operand_t *op) } } +/** Create symbols and defs for params/return if not already available. + */ static symbol_t * param_symbol (const char *name) { @@ -313,6 +420,15 @@ param_symbol (const char *name) return sym; } +/** Build an array of all the statements in a function. + + The array exists so statements can be referenced by number and thus used + in sets. + + The statement references in the array (function_t::statements) are in the + same order as they are within the statement blocks (function_t::sblock) + and with the blocks in the same order as the linked list of blocks. +*/ static void flow_build_statements (function_t *func) { @@ -335,6 +451,48 @@ flow_build_statements (function_t *func) } } +/** Build an array of all the variables used by a function + * + * The array exists so variables can be referenced by number and thus used + * in sets. However, because larger variables may be aliased by smaller types, + * their representation is more complicated. + * + * # Local variable representation + * Defined local vars add their address in local space to the number of + * statements in the function. Thus their flow analysis address in in the + * range: + * + * ([num_statements ... num_statements+localsize]) + * + * with a set element in flowvar_t::define for each word used by the var. + * That is, single word types (int, float, pointer, etc) have one element, + * doubles have two adjacant elements, and vectors and quaternions have + * three and four elements respectively (also adjacant). Structural types + * (struct, union, array) have as many adjacant elements as their size + * dictates. + * + * Temporary vars are pseudo allocated and their addresses are added as + * for normal local vars. + * + * Note, however, that flowvar_t::define also includes real function + * statements that assign to the variable. + * + * # Pseudo Address Space + * Temporary variables are _effectively_ local variables and thus will + * be treated as such by the analizer in that their addresses and sizes + * will be used to determine which and how many set elements to use. + * + * However, at this stage, temporary variables do not have any address + * space assigned to them because their lifetimes are generally limited + * to a few statements and the memory used for the temp vars may be + * recycled. Thus, give temp vars a pseudo address space just past the + * address space used for source-defined local variables. As each temp + * var is added to the analyzer, get_temp_address() assigns the temp var + * an address using function_t::tmpaddr as a starting point. + * + * add_operand() takes care of setting flowvar_t::flowaddr for both locals + * and temps. + */ static void flow_build_vars (function_t *func) { @@ -371,6 +529,7 @@ flow_build_vars (function_t *func) // set up pseudo address space for temp vars so accessing tmp vars // though aliases analyses correctly func->tmpaddr = func->num_statements + func->symtab->space->size; + func->num_vars = 0; // incremented by add_operand // first, add .return and .param_[0-7] as they are always needed for (i = 0; i < num_flow_params; i++) @@ -399,15 +558,8 @@ flow_build_vars (function_t *func) if (flowvar_is_global (func->vars[i])) set_add (func->global_vars, i); } - // create dummy defs for local vars - // defined local vars add their address in local space to the number of - // statements in the function: - // ([num_statements ... num_statements+localsize]) - // with a set element for each def used in the local space - // - // temporary vars are pseudo allocated and their addresses are added as for - // locals - // add_operand takes care of setting flowaddr for both locals and temps + // Put the local varibals in their place (set var->defined to the addresses + // spanned by the var) for (i = 0; i < func->num_vars; i++) { int j; @@ -424,6 +576,8 @@ flow_build_vars (function_t *func) set_delete (stdef); } +/** Add the tempop's spanned addresses to the kill set + */ static int flow_tempop_kill_aliases_visit (tempop_t *tempop, void *_kill) { @@ -435,6 +589,8 @@ flow_tempop_kill_aliases_visit (tempop_t *tempop, void *_kill) return 0; } +/** Add the def's spanned addresses to the kill set + */ static int flow_def_kill_aliases_visit (def_t *def, void *_kill) { @@ -446,6 +602,13 @@ flow_def_kill_aliases_visit (def_t *def, void *_kill) return 0; } +/** Add the flowvar's spanned addresses to the kill set + * + * If the flowvar refers to an alias, then the real def/tempop and any + * overlapping aliases are aslo killed. + * + * However, other aliases cannot kill anything in the uninitialized set. + */ static void flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) { @@ -455,6 +618,7 @@ flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) set_union (kill, var->define); op = var->op; tmp = set_new (); + // collect the kill sets from any aliases if (op->op_type == op_temp) { tempop_visit_all (&op->o.tempop, 1, flow_tempop_kill_aliases_visit, tmp); @@ -467,6 +631,8 @@ flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) set_union (kill, tmp); } +/** Compute reaching defs + */ static void flow_reaching_defs (flowgraph_t *graph) { @@ -484,15 +650,37 @@ flow_reaching_defs (flowgraph_t *graph) flowvar_t *var; // First, create out for the entry dummy node using fake statement numbers. + //\f[ \bigcup\limits_{i=1}^{\infty} F_{i} \f] + //\f[ \bigcap\limits_{i=1}^{\infty} F_{i} \f] + + /** The dummy entry node reaching defs \a out set is initialized to: + * \f[ out_{reaching}=[\bigcup\limits_{v \in \{locals\}} define_{v}] + * \setminus \{statements\} \f] + * where {\a locals} is the set of local def and tempop flowvars (does + * not include parameters), \a define is the set of addresses spanned + * by the flowvar (see flow_build_vars()) (XXX along with statement + * gens), and {\a statements} is the set of all statements in the + * function (ensures the \a out set does not include any initializers in + * the code nodes). + * + * All other entry node sets are initialized to empty. + */ + // kill represents the set of all statements in the function kill = set_new (); for (i = 0; i < graph->func->num_statements; i++) set_add (kill, i); + // uninit uninit = set_new (); for (i = 0; i < graph->func->num_vars; i++) { var = graph->func->vars[i]; set_union (uninit, var->define);// do not want alias handling here } + /** Any possible gens from the function code are removed from the + * \a uninit set (which becomes the \a out set of the entry node's + * reaching defs) in order to prevent them leaking into the real nodes. + */ set_difference (uninit, kill); // remove any gens from the function + // initialize the reaching defs sets in the entry node graph->nodes[graph->num_nodes]->reaching_defs.out = uninit; graph->nodes[graph->num_nodes]->reaching_defs.in = set_new (); graph->nodes[graph->num_nodes]->reaching_defs.gen = set_new (); @@ -555,6 +743,8 @@ flow_reaching_defs (flowgraph_t *graph) set_delete (stkill); } +/** Update the node's \a use set from the statement's \a use set + */ static void live_set_use (set_t *stuse, set_t *use, set_t *def) { @@ -563,6 +753,8 @@ live_set_use (set_t *stuse, set_t *use, set_t *def) set_union (use, stuse); } +/** Update the node's \a def set from the statement's \a def set + */ static void live_set_def (set_t *stdef, set_t *use, set_t *def) { @@ -1240,6 +1432,35 @@ flow_make_node (sblock_t *sblock, int id, function_t *func) return node; } +/** Build the flow graph for the function. + * + * In addition to the nodes create by the statement blocks, there are two + * dummy blocks: + * + * \dot + * digraph flow_build_graph { + * layout = dot; rankdir = TB; compound =true; nodesp = 1.0; + * dummy_entry [shape=box,label="entry"]; + * sblock0 [label="code"]; sblock1 [label="code"]; + * sblock2 [label="code"]; sblock3 [label="code"]; + * dummy_exit [shape=box,label="exit"]; + * dummy_entry -> sblock0; sblock0 -> sblock1; + * sblock1 -> sblock2; sblock2 -> sblock1; + * sblock2 -> dummy_exit; sblock1 -> sblock3; + * sblock3 -> dummy_exit; + * } + * \enddot + * + * The entry block is used for detecting use of uninitialized local variables + * and the exit block is used for ensuring global variables are treated as + * live at function exit. + * + * The exit block, which also is empty of statements, has its live vars + * \a use set initilized to the set of global defs, which are simply numbered + * by their index in the functions list of flowvars. All other exit node sets + * are initialized to empty. + * \f[ use_{live}=globals \f] + */ static flowgraph_t * flow_build_graph (function_t *func) { @@ -1303,3 +1524,5 @@ flow_data_flow (function_t *func) flow_cleanup_dags (graph); func->sblock = flow_generate (graph); } + +///@} From c2ed6d41bd368f0ef6ee3a4d6a42c401a61200a0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 03:55:08 +0900 Subject: [PATCH 242/444] [qfcc] Finish struct-init-param test When the bug is fixed, it will pass now (does without optimization). --- tools/qfcc/test/struct-init-param.r | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/test/struct-init-param.r b/tools/qfcc/test/struct-init-param.r index 8b166099e..1b3bc9e7a 100644 --- a/tools/qfcc/test/struct-init-param.r +++ b/tools/qfcc/test/struct-init-param.r @@ -1,3 +1,4 @@ +void printf (string fmt, ...) = #0; typedef struct { int x; int y; @@ -13,18 +14,31 @@ typedef struct Rect_s { Extent extent; } Rect; -void *foo (void *obj, void *cmd, void *o, Point pos, Rect r) -{ - return obj; -} +void *foo (Rect *obj, void *cmd, Rect *o, Point pos, Rect r); -void *bar (Rect *obj, void *cmd, void *o, Point pos) +void *bar (Rect *obj, void *cmd, Rect *o, Point pos) { Rect rect = { {}, obj.extent }; return foo (obj, cmd, o, pos, rect); } +void *foo (Rect *obj, void *cmd, Rect *o, Point pos, Rect r) +{ + *o = r; + return obj; +} + +Rect obj = { { 1, 2}, { 3, 4} }; +Rect o = { { 5, 6}, {7, 8} }; + int main (void) { - return 1;// don't want this to pass until I've checked the generated code + int ret = 1; + bar(&obj, nil, &o, obj.offset); + printf ("%d %d %d %d\n", o.offset.x, o.offset.y, + o.extent.width, o.extent.height); + if (o.offset.x == 0 && o.offset.y == 0 + && o.extent.width == 3 && o.extent.height == 4) + ret = 0; + return ret; } From b2faca16a7393d728ee0d2543ce84a249b381c2d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 12:08:56 +0900 Subject: [PATCH 243/444] [qfcc] Rename the kill alias functions Having "visit" in the name felt redundant in the end. --- tools/qfcc/source/flow.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 0a29ff16d..897e853e4 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -579,7 +579,7 @@ flow_build_vars (function_t *func) /** Add the tempop's spanned addresses to the kill set */ static int -flow_tempop_kill_aliases_visit (tempop_t *tempop, void *_kill) +flow_tempop_kill_aliases (tempop_t *tempop, void *_kill) { set_t *kill = (set_t *) _kill; flowvar_t *var; @@ -592,7 +592,7 @@ flow_tempop_kill_aliases_visit (tempop_t *tempop, void *_kill) /** Add the def's spanned addresses to the kill set */ static int -flow_def_kill_aliases_visit (def_t *def, void *_kill) +flow_def_kill_aliases (def_t *def, void *_kill) { set_t *kill = (set_t *) _kill; flowvar_t *var; @@ -620,10 +620,9 @@ flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) tmp = set_new (); // collect the kill sets from any aliases if (op->op_type == op_temp) { - tempop_visit_all (&op->o.tempop, 1, flow_tempop_kill_aliases_visit, - tmp); + tempop_visit_all (&op->o.tempop, 1, flow_tempop_kill_aliases, tmp); } else if (op->op_type == op_def) { - def_visit_all (op->o.def, 1, flow_def_kill_aliases_visit, tmp); + def_visit_all (op->o.def, 1, flow_def_kill_aliases, tmp); } // don't allow aliases to kill definitions in the entry dummy block set_difference (tmp, uninit); From a2f203c840ea551ca3ed3c41d217a96df7278990 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 12:10:12 +0900 Subject: [PATCH 244/444] [qfcc] Correct a comment There's a world of difference between "any" and "only". --- tools/qfcc/include/def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/include/def.h b/tools/qfcc/include/def.h index df0104178..d06b5961a 100644 --- a/tools/qfcc/include/def.h +++ b/tools/qfcc/include/def.h @@ -293,7 +293,7 @@ int def_size (def_t *def) __attribute__((pure)); function will return. \param def The def representing the alias cluster to visit. - \param overlap If non-zero, then only defs that overlap \a def will + \param overlap If non-zero, then any defs that overlap \a def will be visited. If 2, then the given def must fully overlap the visited def. \param visit The function to call when visiting a def. The first From 8696e76a25c6bcfbff1f5e263d6d847e98a3382a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 12:11:53 +0900 Subject: [PATCH 245/444] [qfcc] Handle aliases when setting use and def As expected, this does not fix the mangled pointer problem in struct-init-param.r, but it does improve the ud-chains. There's still a problem with .return, but it's handling in flow_analyze_statement is a bit "special" :P. --- tools/qfcc/source/flow.c | 80 ++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 897e853e4..5ff1c9662 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -541,7 +541,12 @@ flow_build_vars (function_t *func) flow_analyze_statement (s, 0, 0, 0, operands); for (j = 0; j < 4; j++) add_operand (func, operands[j]); - + } + // and set the use/def sets for the vars (has to be a separate pass + // because the allias handling reqruires the flow address to be valid + // (ie, not -1) + for (i = 0; i < func->num_statements; i++) { + s = func->statements[i]; flow_analyze_statement (s, stuse, stdef, 0, 0); for (var_i = set_first (stdef); var_i; var_i = set_next (var_i)) { var = func->vars[var_i->element]; @@ -977,16 +982,45 @@ flow_generate (flowgraph_t *graph) return code; } +static int +flow_tempop_add_aliases (tempop_t *tempop, void *_set) +{ + set_t *set = (set_t *) _set; + flowvar_t *var; + var = tempop->flowvar; + if (var) + set_add (set, var->number); + return 0; +} + +static int +flow_def_add_aliases (def_t *def, void *_set) +{ + set_t *set = (set_t *) _set; + flowvar_t *var; + var = def->flowvar; + if (var) + set_add (set, var->number); + return 0; +} + static void -flow_add_op_var (set_t *set, operand_t *op) +flow_add_op_var (set_t *set, operand_t *op, int is_use) { flowvar_t *var; + int ol = is_use ? 2 : 1; if (!set) return; if (!(var = flow_get_var (op))) return; set_add (set, var->number); + + if (op->op_type == op_temp) { + tempop_visit_all (&op->o.tempop, ol, flow_tempop_add_aliases, set); + } else { + def_visit_all (op->o.def, ol, flow_def_add_aliases, set); + } } void @@ -1010,10 +1044,10 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, case st_none: internal_error (s->expr, "not a statement"); case st_expr: - flow_add_op_var (def, s->opc); - flow_add_op_var (use, s->opa); + flow_add_op_var (def, s->opc, 0); + flow_add_op_var (use, s->opa, 1); if (s->opb) - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opb, 1); if (operands) { operands[0] = s->opc; operands[1] = s->opa; @@ -1021,8 +1055,8 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, } break; case st_assign: - flow_add_op_var (def, s->opb); - flow_add_op_var (use, s->opa); + flow_add_op_var (def, s->opb, 0); + flow_add_op_var (use, s->opa, 1); if (operands) { operands[0] = s->opb; operands[1] = s->opa; @@ -1030,12 +1064,12 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, break; case st_ptrassign: case st_move: - flow_add_op_var (use, s->opa); - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opa, 1); + flow_add_op_var (use, s->opb, 1); if (!strcmp (s->opcode, "")) { - flow_add_op_var (def, s->opc); + flow_add_op_var (def, s->opc, 0); } else if (!strcmp (s->opcode, "")) { - flow_add_op_var (use, s->opc); + flow_add_op_var (use, s->opc, 0); if (s->opc->op_type == op_value && s->opc->o.value->lltype == ev_pointer && s->opc->o.value->v.pointer.def) { @@ -1044,7 +1078,7 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, ex_pointer_t *ptr = &s->opc->o.value->v.pointer; alias = alias_def (ptr->def, ptr->type, ptr->val); op = def_operand (alias, ptr->type); - flow_add_op_var (def, op); + flow_add_op_var (def, op, 0); if (operands) operands[0] = op; else @@ -1055,7 +1089,7 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, } } else { if (s->opc) - flow_add_op_var (use, s->opc); + flow_add_op_var (use, s->opc, 1); } if (kill) { set_everything (kill); @@ -1070,10 +1104,10 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, } break; case st_state: - flow_add_op_var (use, s->opa); - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opa, 1); + flow_add_op_var (use, s->opb, 1); if (s->opc) - flow_add_op_var (use, s->opc); + flow_add_op_var (use, s->opc, 1); //FIXME entity members if (operands) { operands[1] = s->opa; @@ -1084,7 +1118,7 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, case st_func: if (strcmp (s->opcode, "") == 0 || strcmp (s->opcode, "") == 0) { - flow_add_op_var (use, s->opa); + flow_add_op_var (use, s->opa, 1); } else if (strcmp (s->opcode, "") == 0) { if (use) set_add (use, 0); //FIXME assumes .return location @@ -1092,14 +1126,14 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, if (strncmp (s->opcode, "opcode[5] - '0'; - flow_add_op_var (use, s->opa); + flow_add_op_var (use, s->opa, 1); } else if (strncmp (s->opcode, "opcode[6] - '0'; - flow_add_op_var (use, s->opa); - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opa, 1); + flow_add_op_var (use, s->opb, 1); if (s->opc) - flow_add_op_var (use, s->opc); + flow_add_op_var (use, s->opc, 1); } if (calln >= 0) { if (use) { @@ -1117,9 +1151,9 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, break; case st_flow: if (strcmp (s->opcode, "") != 0) { - flow_add_op_var (use, s->opa); + flow_add_op_var (use, s->opa, 1); if (strcmp (s->opcode, "") == 0) - flow_add_op_var (use, s->opb); + flow_add_op_var (use, s->opb, 1); } if (operands) { operands[1] = s->opa; From b81d58c795fcc95176b9a9f65a00fdf8ed0e7ee8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 14:58:57 +0900 Subject: [PATCH 246/444] Revert "[qfcc] Correct a comment" This reverts commit a2f203c840ea551ca3ed3c41d217a96df7278990. There is indeed a world of difference between "any" and "only", and it helps if I read the rest of the docs AND the code :P. --- tools/qfcc/include/def.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/include/def.h b/tools/qfcc/include/def.h index d06b5961a..df0104178 100644 --- a/tools/qfcc/include/def.h +++ b/tools/qfcc/include/def.h @@ -293,7 +293,7 @@ int def_size (def_t *def) __attribute__((pure)); function will return. \param def The def representing the alias cluster to visit. - \param overlap If non-zero, then any defs that overlap \a def will + \param overlap If non-zero, then only defs that overlap \a def will be visited. If 2, then the given def must fully overlap the visited def. \param visit The function to call when visiting a def. The first From d9d321f65b1281e302afab531d15e9c68cf4304a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 15:40:07 +0900 Subject: [PATCH 247/444] [qfcc] Check for previous errors in vector exprs Fixes a segfault when one of the expressions used to construct the vector was the result of an error. --- tools/qfcc/source/expr.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index c82585674..7b9721be4 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -659,15 +659,23 @@ new_vector_list (expr_t *e) case 3: // quaternion or vector. all expressions must be compatible with // a float (ie, a scalar) - for (t = e; t; t = t->next) - if (!is_scalar (get_type (t))) + for (t = e; t; t = t->next) { + if (t->type == ex_error) { + return t; + } + if (!is_scalar (get_type (t))) { return error (t, "invalid type for vector element"); + } + } vec = new_expr (); vec->type = ex_vector; vec->e.vector.type = type; vec->e.vector.list = e; break; case 2: + if (e->type == ex_error || e->next->type == ex_error) { + return e; + } if (is_scalar (get_type (e)) && is_scalar (get_type (e->next))) { // scalar, scalar // expand [x, y] to [x, y, 0] From 695b3ba0d043633db22410dddeaf3a2bcc9d50c7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 16:50:39 +0900 Subject: [PATCH 248/444] [qfcc] Rearrange vecexpr.r for easier debugging Putting the most likely function to have problems at the top reduces break-point shenanigans. --- tools/qfcc/test/vecexpr.r | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/test/vecexpr.r b/tools/qfcc/test/vecexpr.r index 8667b0c93..0365ed589 100644 --- a/tools/qfcc/test/vecexpr.r +++ b/tools/qfcc/test/vecexpr.r @@ -1,4 +1,14 @@ #include "test-harness.h" + +vector t1(); +vector t2(float x); + +vector +t3(float x) +{ + return [x, t2(9).z, x] * 2; +} + vector t1() { @@ -11,12 +21,6 @@ t2(float x) return [x, x, x]; } -vector -t3(float x) -{ - return [x, t2(9).z, x] * 2; -} - int main () { From 035da472ecd39b19e1745e068ddab8bfef2abc08 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 16:51:01 +0900 Subject: [PATCH 249/444] [qfcc] Offset alias tempop offsets Alias tempop offsets are relative to the real tempop. This fixes alias tempops never overlapping the real tempop. --- tools/qfcc/source/statements.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 2f2d0a07d..61ab35c5e 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -362,6 +362,12 @@ tempop_overlap (tempop_t *t1, tempop_t *t2) int size1 = type_size (t1->type); int size2 = type_size (t2->type); + if (t1->alias) { + offs1 += t1->alias->o.tempop.offset; + } + if (t2->alias) { + offs2 += t2->alias->o.tempop.offset; + } if (offs1 <= offs2 && offs1 + size1 >= offs2 + size2) return 2; // t1 fully overlaps t2 if (offs1 < offs2 + size2 && offs2 < offs1 + size1) From 3d9410c66dcca13a23b6cc5500aa2690a8090ce4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 16:53:28 +0900 Subject: [PATCH 250/444] [qfcc] Force overlap to 0 for non-alias def/temops Make the code behave as intended: visiting all aliases when starting with the real def/tempop regardless of the overlap setting. --- tools/qfcc/source/def.c | 2 ++ tools/qfcc/source/statements.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 3f2f1c838..865ef4066 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -807,6 +807,8 @@ def_visit_all (def_t *def, int overlap, def = def->alias; if ((ret = visit (def, data))) return ret; + } else { + overlap = 0; } for (def = def->alias_defs; def; def = def->next) { if (def == start_def) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 61ab35c5e..0ba4d1e21 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -393,6 +393,8 @@ tempop_visit_all (tempop_t *tempop, int overlap, tempop = &top->o.tempop; if ((ret = visit (tempop, data))) return ret; + } else { + overlap = 0; } for (top = tempop->alias_ops; top; top = top->next) { if (top->op_type != op_temp) { From 5020966be32693032ab7a864bc2f020b306975e4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 16:57:12 +0900 Subject: [PATCH 251/444] [qfcc] Fix ud-chain alias handling That was a fair bit trickier than I thought, but now .return and .paramN are handled correctly, too, especially taking call instructions into account (they can "kill" all 9 defs). --- tools/qfcc/source/flow.c | 55 +++++++++++++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 5ff1c9662..4ee42e214 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -99,6 +99,16 @@ new_flowvar (void) return var; } +/** Delete a flow var + */ +static void +delete_flowvar (flowvar_t *var) +{ + set_delete (var->use); + set_delete (var->define); + FREE (vars, var); +} + /** Allocate a new flow loop. * * The loop's nodes set is initialized to the empty set. @@ -507,7 +517,16 @@ flow_build_vars (function_t *func) // first, count .return and .param_[0-7] as they are always needed for (i = 0; i < num_flow_params; i++) { - flow_params[i].op.o.def = param_symbol (flow_params[i].name)->s.def; + def_t *def = param_symbol (flow_params[i].name)->s.def; + def_t *a; + for (a = def->alias_defs; a; a = a->next) { + if (a->flowvar) { + delete_flowvar (a->flowvar); + a->flowvar = 0; + } + //free_def (def->alias_defs); + } + flow_params[i].op.o.def = def; num_vars += count_operand (&flow_params[i].op); } // then run through the statements in the function looking for accessed @@ -630,7 +649,9 @@ flow_kill_aliases (set_t *kill, flowvar_t *var, const set_t *uninit) def_visit_all (op->o.def, 1, flow_def_kill_aliases, tmp); } // don't allow aliases to kill definitions in the entry dummy block - set_difference (tmp, uninit); + if (uninit) { + set_difference (tmp, uninit); + } // merge the alias kills with the current def's kills set_union (kill, tmp); } @@ -1008,7 +1029,7 @@ static void flow_add_op_var (set_t *set, operand_t *op, int is_use) { flowvar_t *var; - int ol = is_use ? 2 : 1; + int ol = is_use ? 1 : 2; if (!set) return; @@ -1016,6 +1037,10 @@ flow_add_op_var (set_t *set, operand_t *op, int is_use) return; set_add (set, var->number); + // FIXME XXX I think the curent implementation will have problems + // for the def set when assinging to an alias as right now the real + // var is being treated as assigned as well. Want to handle partial + // defs properly, but I am as yet uncertain of how. if (op->op_type == op_temp) { tempop_visit_all (&op->o.tempop, ol, flow_tempop_add_aliases, set); } else { @@ -1120,8 +1145,9 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, || strcmp (s->opcode, "") == 0) { flow_add_op_var (use, s->opa, 1); } else if (strcmp (s->opcode, "") == 0) { - if (use) - set_add (use, 0); //FIXME assumes .return location + if (use) { + flow_add_op_var (use, &flow_params[0].op, 1); + } } if (strncmp (s->opcode, "= 0) { if (use) { - for (i = start; i < calln; i++) - set_add (use, i + 1);//FIXME assumes .param_N locations + for (i = start; i < calln; i++) { + flow_add_op_var (use, &flow_params[i + 1].op, 1); + } + } + if (def) { + for (i = 0; i < num_flow_params; i++) { + flow_add_op_var (def, &flow_params[i].op, 0); + } + } + if (kill) { + for (i = 0; i < num_flow_params; i++) { + flow_kill_aliases (kill, + flow_get_var (&flow_params[i].op), + 0); + } } - if (kill) - set_add (kill, 0); //FIXME assumes .return location } if (operands) { operands[1] = s->opa; From bcf75b541a68f2546707cf22e9d2c6f926801f26 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 17:40:38 +0900 Subject: [PATCH 252/444] [qfcc] Build movep dest pointer correctly This fixes the mangled pointer in struct-init-param.r. --- tools/qfcc/source/dags.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index 8de4d0e54..86acc210a 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -867,6 +867,8 @@ generate_moveps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) statement_t *st; operand_t *dst = 0; type_t *type; + int offset = 0; + def_t *dstDef; operands[0] = make_operand (dag, block, dagnode, 0); operands[1] = make_operand (dag, block, dagnode, 1); @@ -875,7 +877,12 @@ generate_moveps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) var = dag->labels[var_iter->element]; dst = var->op; type = dst->o.def->type; - operands[2] = value_operand (new_pointer_val (0, type, dst->o.def)); + dstDef = dst->o.def; + if (dstDef->alias) { + offset = dstDef->offset; + dstDef = dstDef->alias; + } + operands[2] = value_operand (new_pointer_val (offset, type, dstDef)); st = build_statement ("", operands, var->expr); sblock_add_statement (block, st); } From 89ec86f77fc4e7d0fd34862915550a48ed527f58 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 19:13:57 +0900 Subject: [PATCH 253/444] [qfcc] Add option to promote of float through ... The server code is not yet ready for doubles, especially in its varargs builtins: they expect only floats. When float promotion is enabled (default for advanced code, disabled for traditional or v6only), "@float_promoted@" is written to the prog's strings. --- tools/qfcc/doc/man/qfcc.1 | 6 ++++++ tools/qfcc/source/expr.c | 17 ++++++++++++++--- tools/qfcc/source/options.c | 7 +++++++ tools/qfcc/source/qfcc.c | 3 +++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/doc/man/qfcc.1 b/tools/qfcc/doc/man/qfcc.1 index b4fbd2685..3162f813d 100644 --- a/tools/qfcc/doc/man/qfcc.1 +++ b/tools/qfcc/doc/man/qfcc.1 @@ -295,6 +295,12 @@ This can be a problem because instructions can access addresses up to 32767 in older servers or 65535 in most modern servers. Defaults to off for traditional mode, and on for advanced mode. +.TP +.B promote\-float +Promote float when passed to a function that takes a variable number of +arguements. Defaults to enabled for advanced code, is forced off for +traditional or v6only code (mostly because such code does not have doubles). + .TP .B short\-circuit Generate short circuit code for logical operators (\fB&&\fP and \fB||\fP). diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 7b9721be4..c1c78ff86 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1718,9 +1718,20 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) if (is_integer_val (e) && options.code.progsversion == PROG_ID_VERSION) convert_int (e); - if (is_float (get_type (e)) - && options.code.progsversion != PROG_ID_VERSION) { - t = &type_double; + if (options.code.promote_float) { + if (is_float (get_type (e))) { + t = &type_double; + } + } else { + if (is_double (get_type (e))) { + if (!e->implicit) { + warning (e, "passing double into ... function"); + } + if (is_constant (e)) { + // don't auto-demote non-constant doubles + t = &type_float; + } + } } if (is_integer_val (e) && options.warnings.vararg_integer) warning (e, "passing integer constant into ... function"); diff --git a/tools/qfcc/source/options.c b/tools/qfcc/source/options.c index f9807de7b..6f972fd82 100644 --- a/tools/qfcc/source/options.c +++ b/tools/qfcc/source/options.c @@ -203,6 +203,7 @@ code_usage (void) " help Display this text.\n" " [no-]local-merging Merge the local variable blocks into one.\n" " [no-]optimize Perform various optimizations on the code.\n" +" [no-]promote-float Promote float when passed through ...\n" " [no-]short-circuit Generate short circuit code for logical\n" " operators.\n" " [no-]single-cpp Convert progs.src to cpp input file.\n" @@ -310,6 +311,7 @@ DecodeArgs (int argc, char **argv) options.code.vector_components = -1; options.code.crc = -1; options.code.fast_float = true; + options.code.promote_float = true; options.warnings.uninited_variable = true; options.warnings.unused = true; options.warnings.executable = true; @@ -489,6 +491,8 @@ DecodeArgs (int argc, char **argv) options.code.debug = flag; } else if (!(strcasecmp (temp, "fast-float"))) { options.code.fast_float = flag; + } else if (!(strcasecmp (temp, "promote-float"))) { + options.code.promote_float = flag; } else if (!strcasecmp (temp, "help")) { code_usage (); } else if (!(strcasecmp (temp, "local-merging"))) { @@ -716,8 +720,11 @@ DecodeArgs (int argc, char **argv) options.code.local_merging = true; if (options.code.vector_components == (qboolean) -1) options.code.vector_components = false; + } else { + options.code.promote_float = 0; } if (options.code.progsversion == PROG_ID_VERSION) { + options.code.promote_float = 0; add_cpp_def ("-D__VERSION6__=1"); if (options.code.crc == (qboolean) -1) options.code.crc = true; diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 8a363a9cd..6a7e1a039 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -148,6 +148,9 @@ InitData (void) pr.code = codespace_new (); memset (codespace_newstatement (pr.code), 0, sizeof (dstatement_t)); pr.strings = strpool_new (); + if (options.code.promote_float) { + ReuseString ("@float_promoted@"); + } pr.num_functions = 1; pr.num_linenos = 0; From c726d77e7dfe116cb07ed17c01ae06d2310faf50 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 19:17:24 +0900 Subject: [PATCH 254/444] [gamecode] Respect the @float_promoted@ magic string Rather than relying on progs code version, use the string to determine whether PR_Sprintf should behave as if floats have been promoted through ... I imagine I'll get to the rest of the server code at some stage. With these two changes, nq-x11 works again (teleporters were the symptom). --- libs/gamecode/pr_load.c | 2 -- libs/gamecode/pr_strings.c | 7 +++++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/libs/gamecode/pr_load.c b/libs/gamecode/pr_load.c index df72cbbc9..d385dff12 100644 --- a/libs/gamecode/pr_load.c +++ b/libs/gamecode/pr_load.c @@ -202,8 +202,6 @@ PR_LoadProgsFile (progs_t *pr, QFile *file, int size) base -= sizeof (progs); // offsets are from file start heap = ((byte *) pr->progs + pr->progs_size + pr->pr_edictareasize); - pr->float_promoted = progs.version == PROG_VERSION; - if (pr->edicts) { *pr->edicts = (edict_t *)((byte *) pr->progs + pr->progs_size); } diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index 4d393776e..e280b4743 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -238,8 +238,15 @@ PR_LoadStrings (progs_t *pr) char *str = pr->pr_strings; int count = 0; + pr->float_promoted = 0; + while (str < end) { count++; + if (*str == '@' && pr->progs->version == PROG_VERSION) { + if (!strcmp (str, "@float_promoted@")) { + pr->float_promoted = 1; + } + } str += strlen (str) + 1; } From a013714bd01f0cb20c9a646947f9392940a7e385 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 20:11:21 +0900 Subject: [PATCH 255/444] [qfcc] Add missing header file changes Oops --- tools/qfcc/include/options.h | 1 + tools/qfcc/include/value.h | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/qfcc/include/options.h b/tools/qfcc/include/options.h index 01345cff4..a43c908b6 100644 --- a/tools/qfcc/include/options.h +++ b/tools/qfcc/include/options.h @@ -46,6 +46,7 @@ typedef struct { qboolean vector_components; // add *_[xyz] symbols for vectors qboolean ifstring; // expand if (str) to if (str != "") qboolean const_initializers; // initialied globals are constant + qboolean promote_float; // promote float through ... } code_options_t; typedef struct { diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index aaac286b7..b4f22ee60 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -36,6 +36,7 @@ */ ///@{ +struct def_s; struct ex_value_s; struct type_s; From 5f299cbac79bf567a6bec3d30ab85dbb575ab462 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 21:29:31 +0900 Subject: [PATCH 256/444] [gamecode] Ensure static string refs are initialized That was a fun one to track down :P --- libs/gamecode/pr_strings.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index e280b4743..6270a8d12 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -267,7 +267,7 @@ PR_LoadStrings (progs_t *pr) if (res->static_strings) free (res->static_strings); - res->static_strings = malloc (count * sizeof (strref_t)); + res->static_strings = calloc (count, sizeof (strref_t)); count = 0; str = pr->pr_strings; while (str < end) { @@ -344,7 +344,7 @@ get_string (progs_t *pr, string_t num) case str_free: break; } - PR_Error (pr, "internal string error"); + PR_Error (pr, "internal string error: %d", __LINE__); } else { if (num >= pr->pr_stringsize) return 0; @@ -436,7 +436,8 @@ PR_SetReturnString (progs_t *pr, const char *s) requeue_strref (res, sr); } else if ((sr->type == str_return && !sr->rs_slot) || (sr->type != str_return && sr->rs_slot)) { - PR_Error (pr, "internal string error"); + PR_Error (pr, "internal string error: %d %d %p", __LINE__, + sr->type, sr->rs_slot); } return string_index (res, sr); } @@ -445,7 +446,7 @@ PR_SetReturnString (progs_t *pr, const char *s) // slot is empty if ((sr = res->rs_slot->strref)) { if (sr->type != str_return || sr->rs_slot != res->rs_slot) { - PR_Error (pr, "internal string error"); + PR_Error (pr, "internal string error: %d", __LINE__); } pr_strfree (pr, sr->s.string); } else { @@ -576,7 +577,7 @@ PR_FreeString (progs_t *pr, string_t str) break; case str_return: default: - PR_Error (pr, "internal string error"); + PR_Error (pr, "internal string error: %d", __LINE__); } free_string_ref (res, sr); return; @@ -593,7 +594,7 @@ PR_FreeTempStrings (progs_t *pr) for (sr = pr->pr_xtstr; sr; sr = t) { t = sr->next; if (sr->type != str_temp) - PR_Error (pr, "internal string error"); + PR_Error (pr, "internal string error: %d", __LINE__); if (R_STRING (pr) < 0 && string_index (res, sr) == R_STRING (pr) && pr->pr_depth) { prstack_t *frame = pr->pr_stack + pr->pr_depth - 1; From 67ec9bfb4796062800e863580295a16974553db5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 21:30:08 +0900 Subject: [PATCH 257/444] [vid] Initialize x event before sending Quietens valgrind nicely (though it gave a weird source of the memory). --- libs/video/targets/in_x11.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/video/targets/in_x11.c b/libs/video/targets/in_x11.c index dc689a7d5..8ef111ec2 100644 --- a/libs/video/targets/in_x11.c +++ b/libs/video/targets/in_x11.c @@ -672,7 +672,7 @@ event_focusin (XEvent *event) static void center_pointer (void) { - XEvent event; + XEvent event = {}; event.type = MotionNotify; event.xmotion.display = x_disp; From bb0e65e9d4c2fd469bdeebfe1f2ccb4f3c728461 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 21:45:51 +0900 Subject: [PATCH 258/444] [cl_menu] Silence some debug output --- ruamoko/cl_menu/client_menu.r | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ruamoko/cl_menu/client_menu.r b/ruamoko/cl_menu/client_menu.r index 67f9e80f1..dc4cd487e 100644 --- a/ruamoko/cl_menu/client_menu.r +++ b/ruamoko/cl_menu/client_menu.r @@ -147,7 +147,7 @@ void (int quick) scan_saves = filenames[i] = str_new (); loadable[i] = 0; string path = sprintf ("%s%i.sav", basename, i); - dprint(path + "\n"); + //dprint(path + "\n"); f = QFS_OpenFile (path); if (!f) { str_copy (filenames[i], "--- UNUSED SLOT ---"); From 89cf9f95232ccaa87c7977665daf970c443f1c45 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 22:19:37 +0900 Subject: [PATCH 259/444] [qwaq] Use Sys_Printf for load error messages It gets them into the log file. --- ruamoko/qwaq/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ruamoko/qwaq/main.c b/ruamoko/qwaq/main.c index 191714c74..ae82758ad 100644 --- a/ruamoko/qwaq/main.c +++ b/ruamoko/qwaq/main.c @@ -32,6 +32,8 @@ #endif #include +#include +#include #include "QF/cbuf.h" #include "QF/cmd.h" @@ -60,7 +62,7 @@ open_file (const char *path, int *len) QFile *file = Qopen (path, "rbz"); if (!file) { - perror (path); + Sys_Printf ("%s\n", sys_errlist[errno]); return 0; } *len = Qfilesize (file); From 8fc007648c1afd7a42c79fb4b13ff94d03b06b6f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 22:20:46 +0900 Subject: [PATCH 260/444] [qwaq] Add missed command enum string --- ruamoko/qwaq/qwaq-curses.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 15746b5e6..8d252a0b2 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -99,6 +99,7 @@ const char *qwaq_command_names[]= { "mvwaddstr", "waddstr", "mvwaddch", + "waddch", "wrefresh", "init_pair", "wbkgd", From 0780cca4963b2114a8c0666f255f6284df1aee5b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 8 Mar 2020 22:21:15 +0900 Subject: [PATCH 261/444] [qwaq] Fixed swapped method implementations That was fun --- ruamoko/qwaq/qwaq-curses.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 8d252a0b2..1981a434c 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -1487,7 +1487,7 @@ bi_i_TextContext__printf_ (progs_t *pr) } static void -bi_i_TextContext__addch_ (progs_t *pr) +bi_i_TextContext__vprintf_ (progs_t *pr) { int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; const char *fmt = P_GSTRING (pr, 2); @@ -1497,7 +1497,7 @@ bi_i_TextContext__addch_ (progs_t *pr) } static void -bi_i_TextContext__vprintf_ (progs_t *pr) +bi_i_TextContext__addch_ (progs_t *pr) { int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; int ch = P_INT (pr, 1); From 98756df9f75ffaf11a7dc3bffc108cb85289b3bf Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 9 Mar 2020 18:03:25 +0900 Subject: [PATCH 262/444] [gamecode] Set final resource map free list pointer The sub-tables were being properly linked together, but the very final table was not properly terminated. --- include/QF/progs.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/QF/progs.h b/include/QF/progs.h index ea17f533e..1ef71aeb2 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1491,6 +1491,8 @@ void *PR_Resources_Find (progs_t *pr, const char *name); Any memory allocated to the resource must be freed before freeing the resource. + A reset resource map is guaranteed to allocate elements sequentially. + \param type The type of the resource. Must match the \c type parameter used for PR_RESMAP. \param map The resource map. @@ -1505,6 +1507,8 @@ void *PR_Resources_Find (progs_t *pr, const char *name); *(type **) &map._free[j] = &map._free[j + 1]; \ if (i < map._size - 1) \ *(type **) &map._free[j] = &map._map[i + 1][0]; \ + else \ + *(type **) &map._free[j] = 0; \ } \ map._free = map._map[0]; From 1ccdd7678055d0dee27819c95de08e58f4d2836c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 9 Mar 2020 18:09:03 +0900 Subject: [PATCH 263/444] [ruamoko] Clean up runtime init and cleanup Move the semi-permanent resource initialisation into the module init and the cleanup of those resources into cleanup. Makes actual runtime init much easier to read. --- libs/ruamoko/rua_obj.c | 72 ++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index e088ff140..a8c2f9e7b 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1908,43 +1908,6 @@ rua_obj_init_runtime (progs_t *pr) { probj_t *probj = pr->pr_objective_resources; pr_def_t *def; - unsigned i; - - if (!probj->selector_hash) - probj->selector_hash = Hash_NewTable (1021, selector_get_key, 0, - probj); - else - Hash_FlushTable (probj->selector_hash); - probj->selector_index = 0; - for (i = 0; i < probj->selector_index_max; i++) { - obj_list_free (probj->selector_sels[i]); - probj->selector_sels[i] = 0; - probj->selector_names[i] = 0; - } - - if (!probj->classes) - probj->classes = Hash_NewTable (1021, class_get_key, 0, probj); - else - Hash_FlushTable (probj->classes); - - if (!probj->protocols) - probj->protocols = Hash_NewTable (1021, protocol_get_key, 0, probj); - else - Hash_FlushTable (probj->protocols); - - if (!probj->load_methods) { - probj->load_methods = Hash_NewTable (1021, 0, 0, probj); - Hash_SetHashCompare (probj->load_methods, load_methods_get_hash, - load_methods_compare); - } else { - Hash_FlushTable (probj->load_methods); - } - - probj->unresolved_classes = 0; - probj->unclaimed_categories = 0; - probj->unclaimed_proto_list = 0; - probj->module_list = 0; - probj->class_tree_list = 0; if ((def = PR_FindField (pr, ".this"))) pr->fields.this = def->ofs; @@ -1956,15 +1919,50 @@ rua_obj_init_runtime (progs_t *pr) static void rua_obj_cleanup (progs_t *pr, void *data) { + unsigned i; + __auto_type probj = (probj_t *) data; pr->pr_objective_resources = probj; + + Hash_FlushTable (probj->selector_hash); + probj->selector_index = 0; + for (i = 0; i < probj->selector_index_max; i++) { + obj_list_free (probj->selector_sels[i]); + probj->selector_sels[i] = 0; + probj->selector_names[i] = 0; + } + + for (i = 0; i < probj->dtables._size; i++) { + dtable_t *dtable = dtable_get (probj, i); + if (!dtable->imp) { + break; + } + free (dtable->imp); + } + dtable_reset (probj); + + Hash_FlushTable (probj->classes); + Hash_FlushTable (probj->protocols); + Hash_FlushTable (probj->load_methods); + probj->unresolved_classes = 0; + probj->unclaimed_categories = 0; + probj->unclaimed_proto_list = 0; + probj->module_list = 0; + probj->class_tree_list = 0; } void RUA_Obj_Init (progs_t *pr, int secure) { probj_t *probj = calloc (1, sizeof (*probj)); + probj->pr = pr; + probj->selector_hash = Hash_NewTable (1021, selector_get_key, 0, probj); + probj->classes = Hash_NewTable (1021, class_get_key, 0, probj); + probj->protocols = Hash_NewTable (1021, protocol_get_key, 0, probj); + probj->load_methods = Hash_NewTable (1021, 0, 0, probj); + Hash_SetHashCompare (probj->load_methods, load_methods_get_hash, + load_methods_compare); PR_Resources_Register (pr, "RUA_ObjectiveQuakeC", probj, rua_obj_cleanup); From e2f4c189f998621c396eb2e9d5cd56f43d05c9ae Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 9 Mar 2020 18:11:36 +0900 Subject: [PATCH 264/444] [ruamoko] Install and use dispatch tables This should speed up ruamoko code somewhat as hash table lookups have been replaced with direct array indexing. As a bonus, support for message forwarding has been added (though not tested). --- include/QF/pr_obj.h | 2 +- libs/ruamoko/rua_obj.c | 125 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 124 insertions(+), 3 deletions(-) diff --git a/include/QF/pr_obj.h b/include/QF/pr_obj.h index fa3bbca84..52f05aa16 100644 --- a/include/QF/pr_obj.h +++ b/include/QF/pr_obj.h @@ -94,7 +94,7 @@ typedef struct pr_class_s { pr_int_t instance_size; pointer_t ivars; // pr_ivar_list_t pointer_t methods; // pr_method_list_t - pointer_t dtable; + pointer_t dtable; // resource index pointer_t subclass_list; // pr_class_t pointer_t sibling_class; // pr_class_t pointer_t protocols; // pr_protocol_list_t diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index a8c2f9e7b..50ba97de1 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -56,17 +56,26 @@ #include "compat.h" #include "rua_internal.h" +#define always_inline inline __attribute__((__always_inline__)) + typedef struct obj_list_s { struct obj_list_s *next; void *data; } obj_list; +typedef struct dtable_s { + size_t size; + func_t *imp; +} dtable_t; + typedef struct probj_resources_s { progs_t *pr; unsigned selector_index; unsigned selector_index_max; obj_list **selector_sels; string_t *selector_names; + PR_RESMAP (dtable_t) dtables; + func_t obj_forward; hashtab_t *selector_hash; hashtab_t *classes; hashtab_t *protocols; @@ -79,6 +88,41 @@ typedef struct probj_resources_s { obj_list *class_tree_list; } probj_t; +static dtable_t * +dtable_new (probj_t *probj) +{ + PR_RESNEW (dtable_t, probj->dtables); +} + +static void +dtable_reset (probj_t *probj) +{ + PR_RESRESET (dtable_t, probj->dtables); +} + +static inline dtable_t * +dtable_get (probj_t *probj, int index) +{ + PR_RESGET (probj->dtables, index); +} + +static inline int +dtable_index (probj_t *probj, dtable_t *dtable) +{ + PR_RESINDEX (probj->dtables, dtable); +} + +static always_inline dtable_t * __attribute__((pure)) +get_dtable (probj_t *probj, const char *name, int index) +{ + dtable_t *dtable = dtable_get (probj, index); + + if (!dtable) { + PR_RunError (probj->pr, "invalid dtable index in %s", name); + } + return dtable; +} + static obj_list *obj_list_free_list; static obj_list * @@ -832,12 +876,83 @@ obj_send_initialize (probj_t *probj, pr_class_t *class) } } +static void +obj_install_methods_in_dtable (probj_t *probj, pr_class_t *class, + pr_method_list_t *method_list) +{ + progs_t *pr = probj->pr; + dtable_t *dtable; + + if (!method_list) { + return; + } + if (method_list->method_next) { + obj_install_methods_in_dtable (probj, class, + &G_STRUCT (pr, pr_method_list_t, + method_list->method_next)); + } + + dtable = get_dtable (probj, __FUNCTION__, class->dtable); + for (int i = 0; i < method_list->method_count; i++) { + pr_method_t *method = &method_list->method_list[i]; + pr_sel_t *sel = &G_STRUCT (pr, pr_sel_t, method->method_name); + if (sel->sel_id < dtable->size) { + dtable->imp[sel->sel_id] = method->method_imp; + } + } +} + +static void +obj_install_dispatch_table_for_class (probj_t *probj, pr_class_t *class) +{ + progs_t *pr = probj->pr; + pr_class_t *super = &G_STRUCT (pr, pr_class_t, class->super_class); + dtable_t *dtable; + + Sys_MaskPrintf (SYS_RUA_OBJ, " install dispatch for class %s %x %d\n", + PR_GetString (pr, class->name), + class->methods, + PR_CLS_ISMETA(class)); + + if (super && !super->dtable) { + obj_install_dispatch_table_for_class (probj, super); + } + + dtable = dtable_new (probj); + class->dtable = dtable_index (probj, dtable); + dtable->size = probj->selector_index + 1; + dtable->imp = calloc (dtable->size, sizeof (func_t)); + if (super) { + dtable_t *super_dtable = get_dtable (probj, __FUNCTION__, + super->dtable); + memcpy (dtable->imp, super_dtable->imp, + super_dtable->size * sizeof (*dtable->imp)); + } + obj_install_methods_in_dtable (probj, class, + &G_STRUCT (pr, pr_method_list_t, + class->methods)); +} + static func_t get_imp (probj_t *probj, pr_class_t *class, pr_sel_t *sel) { - pr_method_t *method = obj_find_message (probj, class, sel); + func_t imp = 0; - return method ? method->method_imp : 0; + if (class->dtable) { + dtable_t *dtable = get_dtable (probj, __FUNCTION__, class->dtable); + if (sel->sel_id < dtable->size) { + imp = dtable->imp[sel->sel_id]; + } + } + if (!imp) { + if (!class->dtable) { + obj_install_dispatch_table_for_class (probj, class); + imp = get_imp (probj, class, sel); + } else { + imp = probj->obj_forward; + } + } + return imp; } static func_t @@ -1908,10 +2023,16 @@ rua_obj_init_runtime (progs_t *pr) { probj_t *probj = pr->pr_objective_resources; pr_def_t *def; + dfunction_t *obj_forward; if ((def = PR_FindField (pr, ".this"))) pr->fields.this = def->ofs; + probj->obj_forward = 0; + if ((obj_forward = PR_FindFunction (pr, "__obj_forward"))) { + probj->obj_forward = (intptr_t) (obj_forward - pr->pr_functions); + } + PR_AddLoadFinishFunc (pr, rua_init_finish); return 1; } From a4875951498b4c1be74363299290b9f591948087 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 9 Mar 2020 19:09:08 +0900 Subject: [PATCH 265/444] [ruamoko,libr] Begin implementation of __obj_forward libr supplies an __obj_forward definition that links to a builtin, but as it is the only def in its object file, it is readily replaceable by an alternative Ruamoko implementation. The builtin version currently simply errors out (rather facetiously), but only as a stub to allow progs to load. --- libs/ruamoko/rua_obj.c | 12 ++++++++++++ ruamoko/include/runtime.h | 1 + ruamoko/lib/Makefile.am | 1 + ruamoko/lib/Object.r | 5 +++++ ruamoko/lib/obj_forward.r | 3 +++ 5 files changed, 22 insertions(+) create mode 100644 ruamoko/lib/obj_forward.r diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 50ba97de1..f5e48ef39 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1209,6 +1209,17 @@ rua___obj_exec_class (progs_t *pr) PR_GetString (pr, module->name)); } +static void +rua___obj_forward (progs_t *pr) +{ + probj_t *probj = pr->pr_objective_resources; + pr_id_t *receiver = &P_STRUCT (pr, pr_id_t, 0); + pr_sel_t *op = &P_STRUCT (pr, pr_sel_t, 1); + PR_RunError (pr, "seriously, dude, %s does not respond to %s", + PR_GetString (pr, object_get_class_name (probj, receiver)), + PR_GetString (pr, probj->selector_names[op->sel_id])); +} + static void rua_obj_error (progs_t *pr) { @@ -1928,6 +1939,7 @@ rua_PR_FindGlobal (progs_t *pr) static builtin_t obj_methods [] = { {"__obj_exec_class", rua___obj_exec_class, -1}, + {"__obj_forward", rua___obj_forward, -1}, {"obj_error", rua_obj_error, -1}, {"obj_verror", rua_obj_verror, -1}, diff --git a/ruamoko/include/runtime.h b/ruamoko/include/runtime.h index bbcd793ed..357416e26 100644 --- a/ruamoko/include/runtime.h +++ b/ruamoko/include/runtime.h @@ -38,6 +38,7 @@ typedef enum { YES ///< a true value } BOOL; +@extern void __obj_forward(id, SEL, ...); @extern void obj_error (id object, int code, string fmt, ...); @extern void obj_verror (id object, int code, string fmt, @va_list args); //obj_error_handler obj_set_error_handler (objc_error_handler func); diff --git a/ruamoko/lib/Makefile.am b/ruamoko/lib/Makefile.am index 8a66a3839..da1157a82 100644 --- a/ruamoko/lib/Makefile.am +++ b/ruamoko/lib/Makefile.am @@ -37,6 +37,7 @@ r_depfiles_remade= libr_a_SOURCES=\ cbuf.r cmd.r cvar.r hash.r msgbuf.r plist.r qfile.r qfs.r script.r \ sound.r string.r math.r types.r \ + obj_forward.r \ Object.r Protocol.r \ AutoreleasePool.r Array.r Array+Private.r Entity.r PropertyList.r Set.r libr_a_obj=$(libr_a_SOURCES:.r=.o) diff --git a/ruamoko/lib/Object.r b/ruamoko/lib/Object.r index d85a78064..07de4b7eb 100644 --- a/ruamoko/lib/Object.r +++ b/ruamoko/lib/Object.r @@ -1,6 +1,11 @@ #include #include +static void link__obj_forward (void) +{ + __obj_forward (nil, nil); +} + void *PR_FindGlobal (string name) = #0; //FIXME where? void __obj_exec_class (struct obj_module *msg) = #0; diff --git a/ruamoko/lib/obj_forward.r b/ruamoko/lib/obj_forward.r new file mode 100644 index 000000000..60ad819b5 --- /dev/null +++ b/ruamoko/lib/obj_forward.r @@ -0,0 +1,3 @@ +// __obj_foward is the only thing in this file so it can be readily replaced +// at link time +void __obj_forward(id object, SEL sel, ...) = #0; From e3fe93c586bbad8908ce79cfde915f78ae6b2807 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 9 Mar 2020 20:41:17 +0900 Subject: [PATCH 266/444] [gamecode] Implement most of message forwarding All that's left is the parameter setup of forward::. --- libs/ruamoko/rua_obj.c | 85 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 79 insertions(+), 6 deletions(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index f5e48ef39..4dca5d218 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -76,6 +76,8 @@ typedef struct probj_resources_s { string_t *selector_names; PR_RESMAP (dtable_t) dtables; func_t obj_forward; + pr_sel_t *forward_selector; + dstring_t *msg; hashtab_t *selector_hash; hashtab_t *classes; hashtab_t *protocols; @@ -491,7 +493,6 @@ sel_register_typed_name (probj_t *probj, const char *name, const char *types, int is_new = 0; obj_list *l; - Sys_MaskPrintf (SYS_RUA_OBJ, " Registering SEL %s %s\n", name, types); index = (intptr_t) Hash_Find (probj->selector_hash, name); if (index) { for (l = probj->selector_sels[index]; l; l = l->next) { @@ -513,6 +514,8 @@ sel_register_typed_name (probj_t *probj, const char *name, const char *types, } } } else { + Sys_MaskPrintf (SYS_RUA_OBJ, " Registering SEL %s %s\n", + name, types); index = add_sel_name (probj, name); is_new = 1; } @@ -933,6 +936,15 @@ obj_install_dispatch_table_for_class (probj_t *probj, pr_class_t *class) class->methods)); } +static inline dtable_t * +obj_check_dtable_installed (probj_t *probj, pr_class_t *class) +{ + if (!class->dtable) { + obj_install_dispatch_table_for_class (probj, class); + } + return get_dtable (probj, __FUNCTION__, class->dtable); +} + static func_t get_imp (probj_t *probj, pr_class_t *class, pr_sel_t *sel) { @@ -955,6 +967,23 @@ get_imp (probj_t *probj, pr_class_t *class, pr_sel_t *sel) return imp; } +static int +obj_reponds_to (probj_t *probj, pr_id_t *obj, pr_sel_t *sel) +{ + progs_t *pr = probj->pr; + pr_class_t *class; + dtable_t *dtable; + func_t imp = 0; + + class = &G_STRUCT (pr, pr_class_t, obj->class_pointer); + dtable = obj_check_dtable_installed (probj, class); + + if (sel->sel_id < dtable->size) { + imp = dtable->imp[sel->sel_id]; + } + return imp != 0; +} + static func_t obj_msg_lookup (probj_t *probj, pr_id_t *receiver, pr_sel_t *op) { @@ -1213,11 +1242,54 @@ static void rua___obj_forward (progs_t *pr) { probj_t *probj = pr->pr_objective_resources; - pr_id_t *receiver = &P_STRUCT (pr, pr_id_t, 0); - pr_sel_t *op = &P_STRUCT (pr, pr_sel_t, 1); - PR_RunError (pr, "seriously, dude, %s does not respond to %s", - PR_GetString (pr, object_get_class_name (probj, receiver)), - PR_GetString (pr, probj->selector_names[op->sel_id])); + pr_id_t *obj = &P_STRUCT (pr, pr_id_t, 0); + pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 1); + pr_sel_t *fwd_sel = probj->forward_selector; + pr_sel_t *err_sel; + pr_class_t *class =&G_STRUCT (pr, pr_class_t, obj->class_pointer); + func_t imp; + + if (!fwd_sel) { + //FIXME sel_register_typed_name is really not the way to go about + //looking for a selector by name + fwd_sel = sel_register_typed_name (probj, "forward::", "", 0); + probj->forward_selector = fwd_sel; + } + if (obj_reponds_to (probj, obj, fwd_sel)) { + imp = get_imp (probj, class, fwd_sel); + PR_CallFunction (pr, imp); + return; + } + //FIXME ditto + err_sel = sel_register_typed_name (probj, "doesNotRecognize:", "", 0); + if (obj_reponds_to (probj, obj, err_sel)) { + imp = get_imp (probj, class, err_sel); + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = PR_SetPointer (pr, obj); + P_POINTER (pr, 1) = PR_SetPointer (pr, err_sel); + P_POINTER (pr, 2) = PR_SetPointer (pr, sel); + PR_CallFunction (pr, imp); + return; + } + + dsprintf (probj->msg, "(%s) %s does not recognize %s", + PR_CLS_ISMETA (class) ? "class" : "instance", + PR_GetString (pr, class->name), + PR_GetString (pr, probj->selector_names[sel->sel_id])); + + //FIXME ditto + err_sel = sel_register_typed_name (probj, "error:", "", 0); + if (obj_reponds_to (probj, obj, err_sel)) { + imp = get_imp (probj, class, err_sel); + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = PR_SetPointer (pr, obj); + P_POINTER (pr, 1) = PR_SetPointer (pr, err_sel); + P_POINTER (pr, 2) = PR_SetTempString (pr, probj->msg->str); + PR_CallFunction (pr, imp); + return; + } + + PR_RunError (pr, "%s", probj->msg->str); } static void @@ -2094,6 +2166,7 @@ RUA_Obj_Init (progs_t *pr, int secure) probj->classes = Hash_NewTable (1021, class_get_key, 0, probj); probj->protocols = Hash_NewTable (1021, protocol_get_key, 0, probj); probj->load_methods = Hash_NewTable (1021, 0, 0, probj); + probj->msg = dstring_newstr(); Hash_SetHashCompare (probj->load_methods, load_methods_get_hash, load_methods_compare); From 7d43bd5c663e80234a04d5d0da94c10c89d1506d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 9 Mar 2020 22:16:19 +0900 Subject: [PATCH 267/444] [gamecode] Add function PR_AllocTempBlock() PR_AllocTempBlock() works the same way as PR_SetTempString(), except that it takes a size parameter and always allocates (never tries to merge). This is, in a way, abusing the string system, but I needed a way to allocate a block of progs memory that would be automatically freed when the current frame ended. The biggest abuse is the need to cast away the const of PR_GetString()'s return value. --- include/QF/progs.h | 12 ++++++++++++ libs/gamecode/pr_strings.c | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 1ef71aeb2..28a2890d2 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1274,6 +1274,18 @@ string_t PR_SetReturnString(progs_t *pr, const char *s); */ string_t PR_SetTempString(progs_t *pr, const char *s); +/** Make a temporary memory block that will be freed when the current progs + stack frame is exited. The contents may be anything and a new block is + returned every time, and the block is in VM addressible space. To access + the contents of the block (for reading, writing, etc), use PR_GetString() + and cast the pointer as necessary. + + \param pr pointer to ::progs_t VM struct + \param size size of block in bytes + \return string index of the block +*/ +string_t PR_AllocTempBlock (progs_t *pr, size_t size); + /** Make a temporary progs string that is the concatenation of two C strings. \param pr pointer to ::progs_t VM struct \param a C string diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index 6270a8d12..d9eee8fa2 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -384,10 +384,16 @@ PR_GetMutableString (progs_t *pr, string_t num) PR_RunError (pr, "Invalid string offset: %d", num); } +static inline void * +pr_strmalloc (progs_t *pr, size_t size) +{ + return PR_Zone_Malloc (pr, size); +} + static inline char * pr_stralloc (progs_t *pr, size_t len) { - return PR_Zone_Malloc (pr, len + 1); + return pr_strmalloc (pr, len + 1); } static inline void @@ -507,6 +513,13 @@ PR_SetTempString (progs_t *pr, const char *s) return pr_settempstring (pr, res, pr_strdup (pr, s)); } +VISIBLE string_t +PR_AllocTempBlock (progs_t *pr, size_t size) +{ + prstr_resources_t *res = pr->pr_string_resources; + return pr_settempstring (pr, res, pr_strmalloc (pr, size)); +} + VISIBLE string_t PR_SetDynamicString (progs_t *pr, const char *s) { From fa0a74efdfc8d2cf6ee222ed91e6dd6cf8637402 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 9 Mar 2020 22:20:11 +0900 Subject: [PATCH 268/444] [ruamoko] Finish implementation of __obj_forward With this, object's implementing forward:: seem to accept the message well, including receiving all the original args (not quite sure how to deal with them in ruamoko code just yet, though). --- libs/ruamoko/rua_obj.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 4dca5d218..fb54585c1 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1257,6 +1257,25 @@ rua___obj_forward (progs_t *pr) } if (obj_reponds_to (probj, obj, fwd_sel)) { imp = get_imp (probj, class, fwd_sel); + // forward:(SEL) sel :(@va_list) args + // args is full param list + //FIXME oh for a stack + size_t size = pr->pr_argc * sizeof (pr_type_t); + string_t args_block = PR_AllocTempBlock (pr, size); + + int argc = pr->pr_argc; + __auto_type argv = (pr_type_t *) PR_GetString (pr, args_block); + // can't memcpy all params because 0 and 1 could be anywhere + memcpy (argv + 0, &P_INT (pr, 0), 4 * sizeof (pr_type_t)); + memcpy (argv + 4, &P_INT (pr, 1), 4 * sizeof (pr_type_t)); + memcpy (argv + 8, &P_INT (pr, 2), (argc - 2) * sizeof (pr_type_t)); + + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = PR_SetPointer (pr, obj); + P_POINTER (pr, 1) = PR_SetPointer (pr, fwd_sel); + P_POINTER (pr, 2) = PR_SetPointer (pr, sel); + P_PACKED (pr, pr_va_list_t, 3).count = argc; + P_PACKED (pr, pr_va_list_t, 3).list = PR_SetPointer (pr, argv); PR_CallFunction (pr, imp); return; } From 9b0368039eef0cccebd8c8c302af2cd3c15d64fb Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 9 Mar 2020 22:54:22 +0900 Subject: [PATCH 269/444] [ruamoko] Include param size in size of args block I forget it every time. It really doesn't help that params are 4 words and words are 4 bytes, so seeing a size of 12 for 3 parameters *looks* right. --- libs/ruamoko/rua_obj.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index fb54585c1..a88edacc0 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1260,7 +1260,7 @@ rua___obj_forward (progs_t *pr) // forward:(SEL) sel :(@va_list) args // args is full param list //FIXME oh for a stack - size_t size = pr->pr_argc * sizeof (pr_type_t); + size_t size = pr->pr_argc * pr->pr_param_size * sizeof(pr_type_t); string_t args_block = PR_AllocTempBlock (pr, size); int argc = pr->pr_argc; From f290b115a5724535e8d2de303cde55662a14e553 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 9 Mar 2020 23:36:09 +0900 Subject: [PATCH 270/444] [gamecode] Add function PR_PushTempString This "pushes" a temp string onto the callee's stack frame after removing it from the caller's stack frame. This is so builtins can pass auto-freed memory to called progs code. No checking is done, but mayhem is likely to ensue if a string is pushed that was allocated in an earlier frame. --- include/QF/progs.h | 12 ++++++++++++ libs/gamecode/pr_exec.c | 12 +++++++++++- libs/gamecode/pr_strings.c | 21 +++++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 28a2890d2..2659ce303 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1286,6 +1286,17 @@ string_t PR_SetTempString(progs_t *pr, const char *s); */ string_t PR_AllocTempBlock (progs_t *pr, size_t size); +/** Push a temporary string to the callee stack frame + + This is for when the temp string needs to be freed when the called function + returns rather than the calling function. It is an error to push a non-temp + string. + + \param pr pointer to ::progs_t VM struct + \param num string index of the temp string +*/ +void PR_PushTempString (progs_t *pr, string_t num); + /** Make a temporary progs string that is the concatenation of two C strings. \param pr pointer to ::progs_t VM struct \param a C string @@ -1733,6 +1744,7 @@ struct progs_s { ///@{ struct prstr_resources_s *pr_string_resources; strref_t *pr_xtstr; + strref_t *pr_pushtstr; int float_promoted; ///< for PR_Sprintf ///@} diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index b933572e4..7f097dcf7 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -123,7 +123,8 @@ PR_PushFrame (progs_t *pr) frame->f = pr->pr_xfunction; frame->tstr = pr->pr_xtstr; - pr->pr_xtstr = 0; + pr->pr_xtstr = pr->pr_pushtstr; + pr->pr_pushtstr = 0; pr->pr_xfunction = 0; } @@ -137,6 +138,15 @@ PR_PopFrame (progs_t *pr) if (pr->pr_xtstr) PR_FreeTempStrings (pr); + // normally, this won't happen, but if a builtin pushed a temp string + // when calling a function and the callee was another builtin that + // did not call a progs function, then the push strings will still be + // valid because PR_EnterFunction was never called + if (pr->pr_pushtstr) { + pr->pr_xtstr = pr->pr_pushtstr; + pr->pr_pushtstr = 0; + PR_FreeTempStrings (pr); + } // up stack frame = pr->pr_stack + --pr->pr_depth; diff --git a/libs/gamecode/pr_strings.c b/libs/gamecode/pr_strings.c index d9eee8fa2..00bb16e4f 100644 --- a/libs/gamecode/pr_strings.c +++ b/libs/gamecode/pr_strings.c @@ -520,6 +520,27 @@ PR_AllocTempBlock (progs_t *pr, size_t size) return pr_settempstring (pr, res, pr_strmalloc (pr, size)); } +VISIBLE void +PR_PushTempString (progs_t *pr, string_t num) +{ + prstr_resources_t *res = pr->pr_string_resources; + strref_t *ref = get_strref (res, num); + strref_t **temp_ref; + + if (!ref || ref->type != str_temp) { + PR_Error (pr, "attempt to push a non-temp string"); + } + for (temp_ref = &pr->pr_xtstr; *temp_ref; temp_ref = &(*temp_ref)->next) { + if (*temp_ref == ref) { + *temp_ref = ref->next; + ref->next = pr->pr_pushtstr; + pr->pr_pushtstr = ref; + return; + } + } + PR_Error (pr, "attempt to push stale temp string"); +} + VISIBLE string_t PR_SetDynamicString (progs_t *pr, const char *s) { From af37b660e8c3be492984ee213423f449eb5798c6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 9 Mar 2020 23:38:27 +0900 Subject: [PATCH 271/444] [ruamoko] Push the forwarded args block This causes the block to be freed when the forward: handler returns (assuming it's not yet another builtin). This is necessary so calling a lot of forwarded messages in a loop doesn't leak memory (though it will get freed eventually). --- libs/ruamoko/rua_obj.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index a88edacc0..35557b5ff 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1276,6 +1276,7 @@ rua___obj_forward (progs_t *pr) P_POINTER (pr, 2) = PR_SetPointer (pr, sel); P_PACKED (pr, pr_va_list_t, 3).count = argc; P_PACKED (pr, pr_va_list_t, 3).list = PR_SetPointer (pr, argv); + PR_PushTempString (pr, args_block); PR_CallFunction (pr, imp); return; } From 2a152e63563aaf1f016466c967819f13bc4d0ac0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 00:07:01 +0900 Subject: [PATCH 272/444] [ruamoko] Add builtin __obj_responds_to Fast dtable-based messages response test. However, it does not handle forwarding. --- libs/ruamoko/rua_obj.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index 35557b5ff..c249e2b6a 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1312,6 +1312,16 @@ rua___obj_forward (progs_t *pr) PR_RunError (pr, "%s", probj->msg->str); } +static void +rua___obj_responds_to (progs_t *pr) +{ + probj_t *probj = pr->pr_objective_resources; + pr_id_t *obj = &P_STRUCT (pr, pr_id_t, 0); + pr_sel_t *sel = &P_STRUCT (pr, pr_sel_t, 1); + + R_INT (pr) = obj_reponds_to (probj, obj, sel); +} + static void rua_obj_error (progs_t *pr) { @@ -2032,6 +2042,7 @@ rua_PR_FindGlobal (progs_t *pr) static builtin_t obj_methods [] = { {"__obj_exec_class", rua___obj_exec_class, -1}, {"__obj_forward", rua___obj_forward, -1}, + {"__obj_responds_to", rua___obj_responds_to, -1}, {"obj_error", rua_obj_error, -1}, {"obj_verror", rua_obj_verror, -1}, From 4978713dee093902bdf5753daa3f2ca06cb13602 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 00:09:46 +0900 Subject: [PATCH 273/444] [libr] Add __obj_responds_to proto and definition --- ruamoko/include/runtime.h | 3 ++- ruamoko/lib/Object.r | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ruamoko/include/runtime.h b/ruamoko/include/runtime.h index 357416e26..80e0aff7e 100644 --- a/ruamoko/include/runtime.h +++ b/ruamoko/include/runtime.h @@ -38,7 +38,8 @@ typedef enum { YES ///< a true value } BOOL; -@extern void __obj_forward(id, SEL, ...); +@extern void __obj_forward(id obj, SEL sel, ...); +@extern BOOL __obj_responds_to(id obj, SEL sel); @extern void obj_error (id object, int code, string fmt, ...); @extern void obj_verror (id object, int code, string fmt, @va_list args); //obj_error_handler obj_set_error_handler (objc_error_handler func); diff --git a/ruamoko/lib/Object.r b/ruamoko/lib/Object.r index 07de4b7eb..21e53326f 100644 --- a/ruamoko/lib/Object.r +++ b/ruamoko/lib/Object.r @@ -9,6 +9,7 @@ static void link__obj_forward (void) void *PR_FindGlobal (string name) = #0; //FIXME where? void __obj_exec_class (struct obj_module *msg) = #0; +BOOL __obj_responds_to(id obj, SEL sel) = #0; void (id object, int code, string fmt, ...) obj_error = #0; void (id object, int code, string fmt, @va_list args) obj_verror = #0; //obj_error_handler (objc_error_handler func) obj_set_error_handler = #0; From e9eab683666b9829e9f6dd8c3bb7d1d7efab6589 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 02:39:18 +0900 Subject: [PATCH 274/444] [qwaq] Begin work on local drawing buffers --- ruamoko/qwaq/Makefile.am | 2 + ruamoko/qwaq/qwaq-draw.h | 25 +++++++++--- ruamoko/qwaq/qwaq-draw.r | 86 ++++++++++++++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-rect.h | 1 + ruamoko/qwaq/qwaq-rect.r | 39 ++++++++++++++++++ ruamoko/qwaq/qwaq-view.r | 16 -------- 6 files changed, 148 insertions(+), 21 deletions(-) create mode 100644 ruamoko/qwaq/qwaq-draw.r create mode 100644 ruamoko/qwaq/qwaq-rect.r diff --git a/ruamoko/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am index bf8c2c9b8..dc5fa56b9 100644 --- a/ruamoko/qwaq/Makefile.am +++ b/ruamoko/qwaq/Makefile.am @@ -25,7 +25,9 @@ SUFFIXES=.o .r qwaq_app_dat_src= \ qwaq-app.r \ + qwaq-draw.r \ qwaq-group.r \ + qwaq-rect.r \ qwaq-screen.r \ qwaq-textcontext.r \ qwaq-view.r \ diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h index 983dd8074..50475fa3d 100644 --- a/ruamoko/qwaq/qwaq-draw.h +++ b/ruamoko/qwaq/qwaq-draw.h @@ -1,11 +1,26 @@ #ifndef __qwaq_draw_h #define __qwaq_draw_h -@protocol Draw --draw; --redraw; --setOwner: owner; --(struct window_s*) getWindow; +#include + +#include "qwaq-rect.h" + +@interface DrawBuffer : Object +{ + int *buffer; + Extent size; + Point cursor; +} ++ (DrawBuffer *) buffer: (Extent) size; +- initWithSize: (Extent) size; +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; + +- (void) printf: (string) fmt, ...; +- (void) vprintf: (string) fmt, @va_list args; +- (void) addch: (int) ch; +- (void) mvprintf: (Point) pos, string fmt, ...; +- (void) mvvprintf: (Point) pos, string fmt, @va_list args; +- (void) mvaddch: (Point) pos, int ch; @end #endif diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r new file mode 100644 index 000000000..8ee7ad029 --- /dev/null +++ b/ruamoko/qwaq/qwaq-draw.r @@ -0,0 +1,86 @@ +#include "qwaq-curses.h" +#include "qwaq-draw.h" + +@implementation DrawBuffer + ++ (DrawBuffer *) buffer: (Extent) size +{ + return [[self alloc] initWithSize: size]; +} + +- initWithSize: (Extent) size +{ + if (!(self = [super init])) { + return nil; + } + buffer = obj_malloc (size.width * size.height); + self.size = size; + return self; +} + +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect +{ + Extent srcSize = srcBuffer.size; + Rect r = { {}, srcBuffer.size }; + Rect t = { pos, rect.extent }; + + t = clipRect (r, t); + if (t.extent.width < 0 || t.extent.height < 0) { + return self; + } + + rect.offset.x += t.offset.x - pos.x; + rect.offset.y += t.offset.y - pos.y; + rect.extent = t.extent; + pos = t.offset; + + r.offset = nil; + r.extent = size; + + rect = clipRect (r, rect); + if (rect.extent.width < 0 || rect.extent.height < 0) { + return self; + } + + int *dst = buffer + pos.y * size.width + pos.x; + int *src = srcBuffer.buffer + + rect.offset.y * srcSize.width + rect.offset.x; + for (int y = 0; y < rect.extent.height; y++) { + int *d = dst; + int *s = src; + dst += size.width; + src += srcSize.width; + for (int x = 0; x < rect.extent.width; x++) { + // FIXME 1) need memcpy/memmove + // 2) the generated code could be better + *d++ = *s++; + } + } + return self; +} + +- (void) printf: (string) fmt, ... +{ +} + +- (void) vprintf: (string) fmt, @va_list args +{ +} + +- (void) addch: (int) ch +{ +} + +- (void) mvprintf: (Point) pos, string fmt, ... +{ +} + +- (void) mvvprintf: (Point) pos, string fmt, @va_list args +{ +} + +- (void) mvaddch: (Point) pos, int ch +{ +} + +@end diff --git a/ruamoko/qwaq/qwaq-rect.h b/ruamoko/qwaq/qwaq-rect.h index 92c241f40..9d4fc51e4 100644 --- a/ruamoko/qwaq/qwaq-rect.h +++ b/ruamoko/qwaq/qwaq-rect.h @@ -21,6 +21,7 @@ typedef struct Rect_s { //XXX will not work if point or rect point to a local variabl @extern int rectContainsPoint (Rect *rect, Point *point); @extern Rect getwrect (struct window_s *window); +@extern Rect clipRect (Rect clipRect, Rect rect); #endif #endif//__qwaq_rect_h diff --git a/ruamoko/qwaq/qwaq-rect.r b/ruamoko/qwaq/qwaq-rect.r new file mode 100644 index 000000000..6ee5c7df5 --- /dev/null +++ b/ruamoko/qwaq/qwaq-rect.r @@ -0,0 +1,39 @@ +#include "qwaq-rect.h" + +Rect +clipRect (Rect clipRect, Rect rect) +{ + if (rect.offset.x < clipRect.offset.x) { + int dist = clipRect.offset.x - rect.offset.x; + rect.offset.x += dist; + rect.extent.width -= dist; + } + if (rect.offset.y < clipRect.offset.y) { + int dist = clipRect.offset.y - rect.offset.y; + rect.offset.y += dist; + rect.extent.height -= dist; + } + if (rect.offset.x + rect.extent.width > clipRect.extent.width) { + rect.extent.width = clipRect.extent.width - rect.offset.x; + } + if (rect.offset.y + rect.extent.height > clipRect.extent.height) { + rect.extent.height = clipRect.extent.height - rect.offset.y; + } + return rect; +} + +Rect +makeRect (int xpos, int ypos, int xlen, int ylen) +{ + Rect rect = {{xpos, ypos}, {xlen, ylen}}; + return rect; +} + +int +rectContainsPoint (Rect *rect, Point *point) +{ + return ((point.x >= rect.offset.x + && point.x < rect.offset.x + rect.extent.width) + && (point.y >= rect.offset.y + && point.y < rect.offset.y + rect.extent.height)); +} diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 541012a47..fc0ccf90f 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -2,22 +2,6 @@ #include "qwaq-view.h" #include "qwaq-group.h" -Rect -makeRect (int xpos, int ypos, int xlen, int ylen) -{ - Rect rect = {{xpos, ypos}, {xlen, ylen}}; - return rect; -} - -int -rectContainsPoint (Rect *rect, Point *point) -{ - return ((point.x >= rect.offset.x - && point.x < rect.offset.x + rect.extent.width) - && (point.y >= rect.offset.y - && point.y < rect.offset.y + rect.extent.height)); -} - @implementation View -init From 4b7d5447bbe5f8b6b0c760660fcd2ae183544c40 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 02:56:37 +0900 Subject: [PATCH 275/444] [ruamoko] Correct obj_msg_sendv for __obj_forward Until I implemented forwarding, I didn't know how obj_msg_sendv was meant to be used, so no surprise I got the implementation wrong. --- libs/ruamoko/rua_obj.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index c249e2b6a..f02bedcc3 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1386,22 +1386,41 @@ static void rua_obj_msg_sendv (progs_t *pr) { probj_t *probj = pr->pr_objective_resources; + pointer_t obj = P_POINTER (pr, 0); pr_id_t *receiver = &P_STRUCT (pr, pr_id_t, 0); + pointer_t sel = P_POINTER (pr, 1); pr_sel_t *op = &P_STRUCT (pr, pr_sel_t, 1); - pr_va_list_t *args = (pr_va_list_t *) &P_POINTER (pr, 2); - pr_type_t *params = G_GPOINTER (pr, args->list); - int count = args->count; func_t imp = obj_msg_lookup (probj, receiver, op); - count = bound (0, count, 6); - if (count && pr_boundscheck->int_val) + __auto_type args = &P_PACKED (pr, pr_va_list_t, 2); + int count = args->count; + pr_type_t *params = G_GPOINTER (pr, args->list); + + if (count < 2 || count > MAX_PARMS) { + PR_RunError (pr, "bad args count in obj_msg_sendv: %d", count); + } + if (pr_boundscheck->int_val) { PR_BoundsCheckSize (pr, args->list, count * pr->pr_param_size); - if (!imp) + } + + if (!imp) { PR_RunError (pr, "%s does not respond to %s", PR_GetString (pr, object_get_class_name (probj, receiver)), PR_GetString (pr, probj->selector_names[op->sel_id])); - if (count) - memcpy (pr->pr_params[2], params, count * 4 * pr->pr_param_size); + } + + pr->pr_argc = count; + // skip over the first two parameters because receiver and op will + // replace them + count -= 2; + params += 2 * pr->pr_param_size; + PR_RESET_PARAMS (pr); + P_POINTER (pr, 0) = obj; + P_POINTER (pr, 1) = sel; + if (count) { + memcpy (&P_INT (pr, 2), params, + count * sizeof (pr_type_t) * pr->pr_param_size); + } PR_CallFunction (pr, imp); } From f9d798c31439a6528df041944dd1a2496fccb676 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 02:58:30 +0900 Subject: [PATCH 276/444] [qwaq] Use forwarding for some text methods refresh won't be in the drawing buffer protocol, and the move commands need to be offset by the view's position in its window, but it works as intended. --- ruamoko/qwaq/qwaq-view.h | 10 +++++++--- ruamoko/qwaq/qwaq-view.r | 20 ++++++++------------ 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index 10e0c93ae..086b9d12d 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -59,12 +59,16 @@ enum { -redraw; - (void) refresh; -- (void) printf: (string) fmt, ...; -- (void) vprintf: (string) fmt, @va_list args; -- (void) addch: (int) ch; - (void) mvprintf: (Point) pos, string fmt, ...; - (void) mvvprintf: (Point) pos, string fmt, @va_list args; - (void) mvaddch: (Point) pos, int ch; @end +//These are forwarded (FIXME make a protocol) +@interface View (TextContext) +- (void) printf: (string) fmt, ...; +- (void) vprintf: (string) fmt, @va_list args; +- (void) addch: (int) ch; +@end + #endif//__qwaq_view_h diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index fc0ccf90f..98cdf4429 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -89,14 +89,15 @@ updateScreenCursor (View *view) return ▭ } -- (void) printf: (string) fmt, ... +- (void) forward: (SEL) sel : (@va_list) args { - [textContext vprintf: fmt, @args]; -} - -- (void) vprintf: (string) fmt, @va_list args -{ - [textContext vprintf: fmt, args]; + if (!textContext) { + return; + } + if (!__obj_responds_to (textContext, sel)) { + [self error: "no implementation for %s", sel_get_name (sel)]; + } + obj_msg_sendv (textContext, sel, args); } - (void) refresh @@ -104,11 +105,6 @@ updateScreenCursor (View *view) [textContext refresh]; } -- (void) addch: (int) ch -{ - [textContext addch:ch]; -} - - (void) mvprintf: (Point) pos, string fmt, ... { pos.x += xpos; From 21b64421c3aaf2339c000b5e5fc805181f554fd1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 03:09:21 +0900 Subject: [PATCH 277/444] [ruamoko] Copy ALL the params to the args block *sigh* --- libs/ruamoko/rua_obj.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index f02bedcc3..c30683d0e 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1260,7 +1260,8 @@ rua___obj_forward (progs_t *pr) // forward:(SEL) sel :(@va_list) args // args is full param list //FIXME oh for a stack - size_t size = pr->pr_argc * pr->pr_param_size * sizeof(pr_type_t); + size_t parm_size = pr->pr_param_size * sizeof(pr_type_t); + size_t size = pr->pr_argc * parm_size; string_t args_block = PR_AllocTempBlock (pr, size); int argc = pr->pr_argc; @@ -1268,7 +1269,7 @@ rua___obj_forward (progs_t *pr) // can't memcpy all params because 0 and 1 could be anywhere memcpy (argv + 0, &P_INT (pr, 0), 4 * sizeof (pr_type_t)); memcpy (argv + 4, &P_INT (pr, 1), 4 * sizeof (pr_type_t)); - memcpy (argv + 8, &P_INT (pr, 2), (argc - 2) * sizeof (pr_type_t)); + memcpy (argv + 8, &P_INT (pr, 2), (argc - 2) * parm_size); PR_RESET_PARAMS (pr); P_POINTER (pr, 0) = PR_SetPointer (pr, obj); From fb92ee12d67b8a82f69515b1da23d0156216e211 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 03:10:55 +0900 Subject: [PATCH 278/444] [qwaq] Set event type to none when no events Fixes the endless looping on the last event. --- ruamoko/qwaq/qwaq-curses.c | 1 + 1 file changed, 1 insertion(+) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 1981a434c..de5ed8ef0 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -733,6 +733,7 @@ get_event (qwaq_resources_t *res, qwaq_event_t *event) } return 1; } + event->what = qe_none; return 0; } From 6c56e93fc8f2edfc4796ee8f35aa3cca368b6f64 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 03:24:31 +0900 Subject: [PATCH 279/444] [gamecode] Be more careful with temp strings If a temp string is found in the return slot, PR_FreeTempStrings won't delete the string. However, PR_PopFrame was blindly stomping on the possibly surviving temp string with the push strings, which would cause a leak. --- libs/gamecode/pr_exec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 7f097dcf7..47b39bc58 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -142,7 +142,9 @@ PR_PopFrame (progs_t *pr) // when calling a function and the callee was another builtin that // did not call a progs function, then the push strings will still be // valid because PR_EnterFunction was never called - if (pr->pr_pushtstr) { + // however, not if a temp string survived: better to hold on to the push + // strings a little longer than lose one erroneously + if (!pr->pr_xtstr && pr->pr_pushtstr) { pr->pr_xtstr = pr->pr_pushtstr; pr->pr_pushtstr = 0; PR_FreeTempStrings (pr); From b517b95e45201b9bdec5428b1a636ff9e1123a77 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 14:29:43 +0900 Subject: [PATCH 280/444] [libr] Add -performv:: --- ruamoko/include/Object.h | 4 ++++ ruamoko/lib/Object.r | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/ruamoko/include/Object.h b/ruamoko/include/Object.h index eb10e55ef..981977651 100644 --- a/ruamoko/include/Object.h +++ b/ruamoko/include/Object.h @@ -24,6 +24,10 @@ - (id) performSelector: (SEL)aSelector withObject: (void *)anObject withObject: (void *)anotherObject; +// void return does not touch the actual return value (effectively retval) +// so if the target returns a value, and the forwarding method simply returns +// (and is void), the vallue will get out to the caller +- (void) performv: (SEL) sel : (@va_list) args; - (BOOL) respondsToSelector: (SEL)aSelector; - (BOOL) conformsToProtocol: (Protocol *)aProtocol; diff --git a/ruamoko/lib/Object.r b/ruamoko/lib/Object.r index 21e53326f..6c7e0e6f4 100644 --- a/ruamoko/lib/Object.r +++ b/ruamoko/lib/Object.r @@ -280,6 +280,11 @@ BOOL (id object) object_is_meta_class = #0; return msg (self, aSelector, anObject, anotherObject); } +- (void) performv: (SEL) sel : (@va_list) args +{ + obj_msg_sendv (self, sel, args); +} + - (void) doesNotRecognizeSelector: (SEL)aSelector { [self error: "%s does not recognize %s", From 1b1249bdb0887c44a46b189153816eeed49806a4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 18:16:07 +0900 Subject: [PATCH 281/444] [ruamoko] Add vsprintf builtin --- libs/ruamoko/pr_cmds.c | 20 ++++++++++++++++++++ ruamoko/include/string.h | 1 + ruamoko/lib/string.r | 1 + 3 files changed, 22 insertions(+) diff --git a/libs/ruamoko/pr_cmds.c b/libs/ruamoko/pr_cmds.c index 8c6aa3d58..9a531fb14 100644 --- a/libs/ruamoko/pr_cmds.c +++ b/libs/ruamoko/pr_cmds.c @@ -583,6 +583,25 @@ PF_sprintf (progs_t *pr) dstring_delete (dstr); } +static void +PF_vsprintf (progs_t *pr) +{ + const char *fmt = P_GSTRING (pr, 0); + __auto_type args = &P_PACKED (pr, pr_va_list_t, 1); + pr_type_t *list_start = PR_GetPointer (pr, args->list); + pr_type_t **list = alloca (args->count * sizeof (*list)); + dstring_t *dstr; + + for (int i = 0; i < args->count; i++) { + list[i] = list_start + i * pr->pr_param_size; + } + + dstr = dstring_newstr (); + PR_Sprintf (pr, dstr, "PF_vsprintf", fmt, args->count, list); + RETURN_STRING (pr, dstr->str); + dstring_delete (dstr); +} + /* string () gametype */ @@ -643,6 +662,7 @@ static builtin_t builtins[] = { {"strlen", PF_strlen, QF 100}, {"charcount", PF_charcount, QF 101}, {"sprintf", PF_sprintf, QF 109}, + {"vsprintf", PF_vsprintf, -1}, {"ftoi", PF_ftoi, QF 110}, {"itof", PF_itof, QF 111}, {"itos", PF_itos, QF 112}, diff --git a/ruamoko/include/string.h b/ruamoko/include/string.h index c4136e2fc..d41e94ef8 100644 --- a/ruamoko/include/string.h +++ b/ruamoko/include/string.h @@ -7,6 +7,7 @@ @extern float strlen (string s); @extern float charcount (string goal, string s); @extern string sprintf (string fmt, ...); +@extern string vsprintf (string fmt, @va_list args); @extern string itos (int i); @extern int stoi (string s); @extern vector stov (string s); diff --git a/ruamoko/lib/string.r b/ruamoko/lib/string.r index 36247bf91..c6c239fa6 100644 --- a/ruamoko/lib/string.r +++ b/ruamoko/lib/string.r @@ -6,6 +6,7 @@ float (string s) stof = #81; float (string s) strlen = #0x000f0000 + 100; float (string goal, string s) charcount = #0x000f0000 + 101; string (string fmt, ...) sprintf = #0x000f0000 + 109; +string vsprintf (string fmt, @va_list args) = #0; string (int i) itos = #0x000f0000 + 112; int (string s) stoi = #0x000f0000 + 113; vector (string s) stov = #0x000f0000 + 114; From 694ad2e840c07c01ca7806adeaa4b39bc88ed4be Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 18:16:55 +0900 Subject: [PATCH 282/444] [ruamoko] Add str_char builtin This returns the character (as an int) at the index. Equivalent to string[index], but qc code doesn't have char-level access and not having it means that strings can internally change to wchar without too much fuss (maybe). --- libs/ruamoko/rua_string.c | 13 +++++++++++++ ruamoko/include/string.h | 1 + ruamoko/lib/string.r | 1 + 3 files changed, 15 insertions(+) diff --git a/libs/ruamoko/rua_string.c b/libs/ruamoko/rua_string.c index fcd78c1cc..c96f44e57 100644 --- a/libs/ruamoko/rua_string.c +++ b/libs/ruamoko/rua_string.c @@ -134,6 +134,18 @@ bi_str_str (progs_t *pr) R_STRING (pr) = res - pr->pr_strings; } +static void +bi_str_char (progs_t *pr) +{ + const char *str = P_GSTRING (pr, 0); + int ind = P_INT (pr, 1); + + if (ind < 0) { + PR_RunError (pr, "negative index to str_char"); + } + R_INT (pr) = str[ind]; +} + static builtin_t builtins[] = { {"str_new", bi_str_new, -1}, {"str_free", bi_str_free, -1}, @@ -143,6 +155,7 @@ static builtin_t builtins[] = { {"str_mid|*i", bi_str_mid, -1}, {"str_mid|*ii", bi_str_mid, -1}, {"str_str", bi_str_str, -1}, + {"str_char", bi_str_char, -1}, {0} }; diff --git a/ruamoko/include/string.h b/ruamoko/include/string.h index d41e94ef8..3951c94c5 100644 --- a/ruamoko/include/string.h +++ b/ruamoko/include/string.h @@ -20,5 +20,6 @@ @extern @overload string str_mid (string str, int start); @extern @overload string str_mid (string str, int start, int len); @extern string str_str (string haystack, string needle); +@extern int str_char (string str, int ind); #endif//__ruamoko_string_h diff --git a/ruamoko/lib/string.r b/ruamoko/lib/string.r index c6c239fa6..58f64911a 100644 --- a/ruamoko/lib/string.r +++ b/ruamoko/lib/string.r @@ -19,3 +19,4 @@ string (string str) str_clear = #0; string (string str, int start) str_mid = #0; string (string str, int start, int len) str_mid = #0; string (string haystack, string needle) str_str = #0; +int str_char (string str, int ind) = #0; From f91fb4f840d352b46f7cae83a4ce4126391bb65c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 18:21:06 +0900 Subject: [PATCH 283/444] [qwaq] Add an mvwblit_line builtin I had to do my own thing with curses as the function I had planned to use turned out to be quite different from what I wanted (misread the man page). --- ruamoko/qwaq/qwaq-curses.c | 54 +++++++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-curses.h | 1 + ruamoko/qwaq/qwaq-textcontext.r | 1 + 3 files changed, 56 insertions(+) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index de5ed8ef0..8ba194619 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -80,6 +80,7 @@ typedef enum qwaq_commands_e { qwaq_cmd_move, qwaq_cmd_curs_set, qwaq_cmd_wborder, + qwaq_cmd_mvwblit_line, } qwaq_commands; const char *qwaq_command_names[]= { @@ -107,6 +108,7 @@ const char *qwaq_command_names[]= { "move", "curs_set", "wborder", + "mvwblit_line", }; #define RING_BUFFER(type, size) \ @@ -617,6 +619,22 @@ cmd_wborder (qwaq_resources_t *res) wborder (window->win, ls, rs, ts, bs, tl, tr, bl, br); } +static void +cmd_mvwblit_line (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + int x = RB_PEEK_DATA (res->command_queue, 3); + int y = RB_PEEK_DATA (res->command_queue, 4); + int chs_id = RB_PEEK_DATA (res->command_queue, 5); + int len = RB_PEEK_DATA (res->command_queue, 6); + int *chs = (int *) res->strings[chs_id].str; + + window_t *window = get_window (res, __FUNCTION__, window_id); + for (int i = 0; i < len; i++) { + mvwaddch (window->win, y, x, chs[i]); + } +} + static void process_commands (qwaq_resources_t *res) { @@ -701,6 +719,9 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_wborder: cmd_wborder (res); break; + case qwaq_cmd_mvwblit_line: + cmd_mvwblit_line (res); + break; } RB_DROP_DATA (res->command_queue, RB_PEEK_DATA (res->command_queue, 1)); } @@ -1384,6 +1405,38 @@ bi_wborder (progs_t *pr) qwaq_wborder (pr, window_id, sides, corns); } +static void +qwaq__mvwblit_line (progs_t *pr, int window_id, int x, int y, + int *chs, int len) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int chs_id = acquire_string (res); + dstring_t *chs_buf = res->strings + chs_id; + int command[] = { qwaq_cmd_mvwblit_line, 0, window_id, + x, y, chs_id, len,}; + + command[1] = CMD_SIZE(command); + + chs_buf->size = len * sizeof (int); + dstring_adjust (chs_buf); + memcpy (chs_buf->str, chs, len * sizeof (int)); + + qwaq_submit_command (res, command); + } +} +static void +bi_mvwblit_line (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + int *chs = (int *) P_GPOINTER (pr, 3); + int len = P_INT (pr, 4); + qwaq__mvwblit_line (pr, window_id, x, y, chs, len); +} + static void bi_initialize (progs_t *pr) { @@ -1609,6 +1662,7 @@ static builtin_t builtins[] = { {"move", bi_move, -1}, {"curs_set", bi_curs_set, -1}, {"wborder", bi_wborder, -1}, + {"mvwblit_line", bi_mvwblit_line, -1}, {"_c_TextContext__is_initialized", bi_c_TextContext__is_initialized, -1}, {"_c_TextContext__max_colors", bi_c_TextContext__max_colors, -1}, diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index 16cd4fe4e..b592ac84b 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -120,6 +120,7 @@ typedef struct panel_s *panel_t; @extern void wborder (window_t window, box_sides_t sides, box_corners_t corners); +@extern void mvwblit_line (window_t window, int x, int y, int *wch, int len); #endif #endif//__qwaq_curses_h diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index 59b54fb6a..1797bde48 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -106,3 +106,4 @@ void doupdate (void) = #0; int curs_set (int visibility) = #0; int move (int x, int y) = #0; void wborder (window_t window, box_sides_t sides, box_corners_t corners) = #0; +void mvwblit_line (window_t window, int x, int y, int *wch, int len) = #0; From b3850bbc6986729d12bec63a54b9933979719937 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 19:23:51 +0900 Subject: [PATCH 284/444] [qwaq] Implement blitting from draw buffer to text Sending the data out to curses. --- ruamoko/qwaq/qwaq-draw.h | 4 ++++ ruamoko/qwaq/qwaq-draw.r | 10 ++++++++++ ruamoko/qwaq/qwaq-textcontext.h | 17 +++++++++++++++++ ruamoko/qwaq/qwaq-textcontext.r | 34 +++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+) diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h index 50475fa3d..931ea6d12 100644 --- a/ruamoko/qwaq/qwaq-draw.h +++ b/ruamoko/qwaq/qwaq-draw.h @@ -13,6 +13,10 @@ } + (DrawBuffer *) buffer: (Extent) size; - initWithSize: (Extent) size; + +- (Extent) size; +- (int *) buffer; + - blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; - (void) printf: (string) fmt, ...; diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r index 8ee7ad029..333d737e4 100644 --- a/ruamoko/qwaq/qwaq-draw.r +++ b/ruamoko/qwaq/qwaq-draw.r @@ -18,6 +18,16 @@ return self; } +- (Extent) size +{ + return size; +} + +- (int *) buffer +{ + return buffer; +} + - blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect { Extent srcSize = srcBuffer.size; diff --git a/ruamoko/qwaq/qwaq-textcontext.h b/ruamoko/qwaq/qwaq-textcontext.h index 4a47b16ca..765f90572 100644 --- a/ruamoko/qwaq/qwaq-textcontext.h +++ b/ruamoko/qwaq/qwaq-textcontext.h @@ -6,9 +6,24 @@ #include "qwaq-curses.h" #include "qwaq-rect.h" +@class DrawBuffer; + @interface TextContext : Object { window_t window; + union { + Rect rect; + struct { + Point offset; + Extent size; + }; + struct { + int xpos; + int ypos; + int xlen; + int ylen; + }; + }; } + (int) max_colors; + (int) max_color_pairs; @@ -25,6 +40,8 @@ -(window_t) window; +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; + - (void) printf: (string) fmt, ...; - (void) vprintf: (string) mft, @va_list args; - (void) addch: (int) ch; diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index 1797bde48..726872ccf 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -1,3 +1,4 @@ +#include "qwaq-draw.h" #include "qwaq-textcontext.h" @implementation TextContext @@ -59,6 +60,39 @@ static TextContext *screen; return window; } +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect +{ + Extent srcSize = [srcBuffer size]; + Rect r = { {}, srcSize }; + Rect t = { pos, rect.extent }; + + t = clipRect (r, t); + if (t.extent.width < 0 || t.extent.height < 0) { + return self; + } + + rect.offset.x += t.offset.x - pos.x; + rect.offset.y += t.offset.y - pos.y; + rect.extent = t.extent; + pos = t.offset; + + r.offset = nil; + r.extent = size; + + rect = clipRect (r, rect); + if (rect.extent.width < 0 || rect.extent.height < 0) { + return self; + } + + int *src = [srcBuffer buffer] + + rect.offset.y * srcSize.width + rect.offset.x; + for (int y = 0; y < rect.extent.height; y++) { + mvwblit_line (window, pos.x, y + pos.y, src, rect.extent.width); + src += srcSize.width; + } + return self; +} + - (void) mvprintf: (Point) pos, string fmt, ... = #0; - (void) printf: (string) fmt, ... = #0; - (void) vprintf: (string) mft, @va_list args = #0; From ce67d9b202d878001ba614a3f5849fa844c110fe Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 10 Mar 2020 19:27:26 +0900 Subject: [PATCH 285/444] [qwaq] Flesh out DrawBuffer's methods --- ruamoko/qwaq/qwaq-draw.h | 2 ++ ruamoko/qwaq/qwaq-draw.r | 70 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h index 931ea6d12..a0ef18dc1 100644 --- a/ruamoko/qwaq/qwaq-draw.h +++ b/ruamoko/qwaq/qwaq-draw.h @@ -22,9 +22,11 @@ - (void) printf: (string) fmt, ...; - (void) vprintf: (string) fmt, @va_list args; - (void) addch: (int) ch; +- (void) addstr: (string) str; - (void) mvprintf: (Point) pos, string fmt, ...; - (void) mvvprintf: (Point) pos, string fmt, @va_list args; - (void) mvaddch: (Point) pos, int ch; +- (void) mvaddstr: (Point) pos, string str; @end #endif diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r index 333d737e4..66e266a50 100644 --- a/ruamoko/qwaq/qwaq-draw.r +++ b/ruamoko/qwaq/qwaq-draw.r @@ -1,3 +1,5 @@ +#include + #include "qwaq-curses.h" #include "qwaq-draw.h" @@ -71,26 +73,94 @@ - (void) printf: (string) fmt, ... { + string str = vsprintf (fmt, @args); + [self addstr: str]; } - (void) vprintf: (string) fmt, @va_list args { + string str = vsprintf (fmt, args); + [self addstr: str]; } - (void) addch: (int) ch { + if (cursor.x < 0) { + cursor.x = 0; + } + if (cursor.y < 0) { + cursor.y = 0; + } + if (cursor.x >= size.width && cursor.y < size.height) { + cursor.x = 0; + cursor.y++; + } + if (cursor.y >= size.height) { + return; + } + if (ch == '\n') { + cursor.x = 0; + cursor.y++; + } else if (ch == '\r') { + cursor.x = 0; + } else { + buffer[cursor.y * size.width + cursor.x++] = ch; + } +} + +- (void) addstr: (string) str +{ + int ind = 0; + int ch; + + if (cursor.y >= size.height) { + return; + } + while (cursor.x < size.width && (ch = str_char (str, ind++))) { + [self addch: ch]; + } } - (void) mvprintf: (Point) pos, string fmt, ... { + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + string str = vsprintf (fmt, @args); + [self addstr: str]; } - (void) mvvprintf: (Point) pos, string fmt, @va_list args { + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + string str = vsprintf (fmt, args); + [self addstr: str]; } - (void) mvaddch: (Point) pos, int ch { + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + [self addch: ch]; +} + +- (void) mvaddstr: (Point) pos, string str +{ + if (pos.x < 0 || pos.x >= size.width + || pos.y < 0 || pos.y >= size.height) { + return; + } + cursor = pos; + [self addstr: str]; } @end From 9acfdea8b50f3e7cf1e4732177e76b93411fc1a5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 01:52:45 +0900 Subject: [PATCH 286/444] [qfcc] Improve line number binding for function calls Multi-line calls (especially messages) got rather confusing to read as the lines jumped back and forth. Now the binding is better but the dags code is reordering the parameters sometimes. --- tools/qfcc/include/expr.h | 8 ++++++++ tools/qfcc/source/expr.c | 33 ++++++++++++++++++++++++--------- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index ac2646dfe..f0f118e8d 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -264,6 +264,14 @@ expr_t *new_expr (void); */ expr_t *copy_expr (expr_t *e); +/** Copy source expression's file and line to the destination expression + + \param dst The expression to receive the file and line + \param src The expression from which the file and line will be taken + \return \a dst +*/ +expr_t *expr_file_line (expr_t *dst, const expr_t *src); + /** Create a new label name. The label name is guaranteed to to the compilation. It is made up of the diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index c1c78ff86..67206c663 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -432,6 +432,14 @@ copy_expr (expr_t *e) internal_error (e, "invalid expression"); } +expr_t * +expr_file_line (expr_t *dst, const expr_t *src) +{ + dst->file = src->file; + dst->line = src->line; + return dst; +} + const char * new_label_name (void) { @@ -1654,6 +1662,7 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) type_t *arg_types[MAX_PARMS]; expr_t *arg_exprs[MAX_PARMS][2]; int arg_expr_count = 0; + expr_t *assign; expr_t *call; expr_t *err = 0; @@ -1741,29 +1750,33 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) if (err) return err; - call = new_block_expr (); + call = expr_file_line (new_block_expr (), fexpr); call->e.block.is_call = 1; for (e = params, i = 0; e; e = e->next, i++) { if (has_function_call (e)) { - *a = new_temp_def_expr (arg_types[i]); - arg_exprs[arg_expr_count][0] = cast_expr (arg_types[i], - convert_vector (e)); + expr_t *cast = cast_expr (arg_types[i], convert_vector (e)); + expr_t *tmp = new_temp_def_expr (arg_types[i]); + *a = expr_file_line (tmp, e); + arg_exprs[arg_expr_count][0] = expr_file_line (cast, e); arg_exprs[arg_expr_count][1] = *a; arg_expr_count++; } else { - *a = cast_expr (arg_types[i], convert_vector (e)); + *a = expr_file_line (cast_expr (arg_types[i], convert_vector (e)), + e); } a = &(*a)->next; } for (i = 0; i < arg_expr_count - 1; i++) { - append_expr (call, assign_expr (arg_exprs[i][1], arg_exprs[i][0])); + assign = assign_expr (arg_exprs[i][1], arg_exprs[i][0]); + append_expr (call, expr_file_line (assign, arg_exprs[i][0])); } if (arg_expr_count) { e = assign_expr (arg_exprs[arg_expr_count - 1][1], arg_exprs[arg_expr_count - 1][0]); + e = expr_file_line (e, arg_exprs[arg_expr_count - 1][0]); append_expr (call, e); } - e = new_binary_expr ('c', fexpr, args); + e = expr_file_line (new_binary_expr ('c', fexpr, args), fexpr); e->e.expr.type = ftype->t.func.type; append_expr (call, e); if (ftype->t.func.type != &type_void) { @@ -2637,14 +2650,16 @@ message_expr (expr_t *receiver, keywordarg_t *message) for (m = message; m; m = m->next) { *a = m->expr; - while ((*a)) + while ((*a)) { + expr_file_line (selector, *a); a = &(*a)->next; + } } *a = selector; a = &(*a)->next; *a = receiver; - send_msg = send_message (super); + send_msg = expr_file_line (send_message (super), receiver); if (method) { expr_t *err; if ((err = method_check_params (method, args))) From 5535a6a5093fdb6fd1b4f944e7946552fb8f5fc2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 10:49:49 +0900 Subject: [PATCH 287/444] [qfcc] Fix missing words in a comment --- tools/qfcc/include/expr.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index f0f118e8d..99fa466b9 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -274,9 +274,9 @@ expr_t *expr_file_line (expr_t *dst, const expr_t *src); /** Create a new label name. - The label name is guaranteed to to the compilation. It is made up of the - name of the current function plus an incrementing number. The number is - not reset between functions. + The label name is guaranteed to be unique to the compilation. It is made + up of the name of the current function plus an incrementing number. The + number is not reset between functions. \return The string representing the label name. */ From 826f066e009fbc52763d336807e92f05c7e9303e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 10:50:15 +0900 Subject: [PATCH 288/444] [qfcc] Be more consistent with string saving Not that it really makes any difference for labels since they're guaranteed unique, but it does remove the question of "why nva instead of save_string?". Looking at history, save_string came after I changed it from strdup (va()) to nva(), and then either didn't think to look for nva or thought it wasn't worth changing. --- tools/qfcc/source/expr.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 67206c663..416442419 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -446,10 +446,9 @@ new_label_name (void) static int label = 0; int lnum = ++label; const char *fname = current_func->sym->name; - char *lname; + const char *lname; - lname = nva ("$%s_%d", fname, lnum); - SYS_CHECKMEM (lname); + lname = save_string (va ("$%s_%d", fname, lnum)); return lname; } From 3061f7e30ec02b17f503f4969d78827171b11631 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 11:04:49 +0900 Subject: [PATCH 289/444] [qfcc] Update sendv test for corrected implementation --- tools/qfcc/test/sendv.r | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/test/sendv.r b/tools/qfcc/test/sendv.r index 979a72c43..aa2cb6665 100644 --- a/tools/qfcc/test/sendv.r +++ b/tools/qfcc/test/sendv.r @@ -8,12 +8,13 @@ int obj_increment_retaincount (id object) = #0; void send (id obj, string cmd, string str) { - @static @param params[1]; - @va_list va_list = {1, params}; - SEL sel; + @static @param params[3]; + @va_list va_list = {3, params}; + SEL sel = sel_get_uid (cmd); - params[0].string_val = str; - sel = sel_get_uid (cmd); + params[0].pointer_val = obj; + params[1].pointer_val = sel; + params[2].string_val = str; obj_msg_sendv (obj, sel, va_list); } From d5560434c022a8aa064c4bbeec6f49e3248bc378 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 11:06:09 +0900 Subject: [PATCH 290/444] [qfcc] Rename label to bool_label for clarity And also so I can use `label' for source labels. --- tools/qfcc/source/qc-parse.y | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index ba266c512..9752a4c48 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -184,7 +184,7 @@ int yylex (void); %type opt_init opt_expr cexpr expr element_list element %type optional_state_expr texpr vector_expr %type statement statements compound_statement -%type else label break_label continue_label +%type else bool_label break_label continue_label %type unary_expr ident_expr cast_expr opt_arg_list arg_list %type init_var_decl_list init_var_decl %type switch_block @@ -1358,7 +1358,7 @@ else } ; -label +bool_label : /* empty */ { $$ = new_label_expr (); @@ -1489,8 +1489,8 @@ expr | expr '=' expr { $$ = assign_expr ($1, $3); } | expr ASX expr { $$ = asx_expr ($2, $1, $3); } | expr '?' expr ':' expr { $$ = conditional_expr ($1, $3, $5); } - | expr AND label expr { $$ = bool_expr (AND, $3, $1, $4); } - | expr OR label expr { $$ = bool_expr (OR, $3, $1, $4); } + | expr AND bool_label expr { $$ = bool_expr (AND, $3, $1, $4); } + | expr OR bool_label expr { $$ = bool_expr (OR, $3, $1, $4); } | expr EQ expr { $$ = binary_expr (EQ, $1, $3); } | expr NE expr { $$ = binary_expr (NE, $1, $3); } | expr LE expr { $$ = binary_expr (LE, $1, $3); } From 1cd5ea57324e7f4e2640070393a86c2b7c22f275 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 11:31:54 +0900 Subject: [PATCH 291/444] [qfcc] Add support for named labels in statements Yeah, I've finally decided to implement goto. Limited to function scope of course. --- tools/qfcc/include/expr.h | 13 +++++++++++++ tools/qfcc/include/function.h | 1 + tools/qfcc/source/expr.c | 21 +++++++++++++++++++++ tools/qfcc/source/function.c | 1 + tools/qfcc/source/qc-parse.y | 10 +++++++++- 5 files changed, 45 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 99fa466b9..6556a8d06 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -290,6 +290,19 @@ const char *new_label_name (void); */ expr_t *new_label_expr (void); +/** Create a named label expression node. + + The label name is set using new_label_name(), but the symbol is used to add + the label to the function's label scope symbol table. If the label already + exists in the function's label scope, then the existing label is returned, + allowing for forward label declarations. + + \param label The name symbol to use for adding the label to the function + label scope. + \return The new label expression (::ex_label_t) node. +*/ +expr_t *named_label_expr (struct symbol_s *label); + /** Create a new label reference expression node. Used for taking the address of a label (eg. jump tables). diff --git a/tools/qfcc/include/function.h b/tools/qfcc/include/function.h index 39cde918c..951b40597 100644 --- a/tools/qfcc/include/function.h +++ b/tools/qfcc/include/function.h @@ -79,6 +79,7 @@ typedef struct function_s { scope symbol table's defspace. */ struct symtab_s *symtab; + struct symtab_s *label_scope; struct reloc_s *refs; ///< relocation targets for this function struct expr_s *var_init; const char *name; ///< nice name for __PRETTY_FUNCTION__ diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 416442419..d080d2332 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -495,6 +495,27 @@ new_label_expr (void) return l; } +expr_t * +named_label_expr (symbol_t *label) +{ + symbol_t *sym; + + if (!current_func) { + // XXX this might be only an error + internal_error (0, "label defined outside of function scope"); + } + + sym = symtab_lookup (current_func->label_scope, label->name); + + if (sym) { + return sym->s.expr; + } + label->sy_type = sy_expr; + label->s.expr = new_label_expr (); + symtab_addsymbol (current_func->label_scope, label); + return label->s.expr; +} + expr_t * new_label_ref (ex_label_t *label) { diff --git a/tools/qfcc/source/function.c b/tools/qfcc/source/function.c index 7f53cd11d..c9e5474a5 100644 --- a/tools/qfcc/source/function.c +++ b/tools/qfcc/source/function.c @@ -493,6 +493,7 @@ build_scope (symbol_t *fsym, symtab_t *parent) symtab = new_symtab (parent, stab_local); fsym->s.func->symtab = symtab; + fsym->s.func->label_scope = new_symtab (0, stab_local); symtab->space = defspace_new (ds_virtual); current_symtab = symtab; diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 9752a4c48..3e5079313 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -188,7 +188,7 @@ int yylex (void); %type unary_expr ident_expr cast_expr opt_arg_list arg_list %type init_var_decl_list init_var_decl %type switch_block -%type identifier +%type identifier label %type overloaded_identifier @@ -1292,6 +1292,10 @@ statement else error (0, "continue outside of loop"); } + | label + { + $$ = named_label_expr ($1); + } | CASE expr ':' { $$ = case_label_expr (switch_block, $2); @@ -1358,6 +1362,10 @@ else } ; +label + : NAME ':' + ; + bool_label : /* empty */ { From 4a8854d9ed63006155076646397222ebec99daa0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 12:51:34 +0900 Subject: [PATCH 292/444] [qfcc] Add expression tracking to operands Not much uses it yet, but it will make for better diagnostics. --- tools/qfcc/include/statements.h | 13 +++--- tools/qfcc/source/dags.c | 8 ++-- tools/qfcc/source/flow.c | 2 +- tools/qfcc/source/statements.c | 75 +++++++++++++++++---------------- 4 files changed, 52 insertions(+), 46 deletions(-) diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index ce230d9ec..d1ccff441 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -57,6 +57,7 @@ typedef struct operand_s { op_type_e op_type; struct type_s *type; ///< possibly override def's type int size; ///< for structures + struct expr_s *expr; ///< expression generating this operand union { struct def_s *def; struct ex_value_s *value; @@ -115,14 +116,16 @@ struct dstring_s; const char *optype_str (op_type_e type) __attribute__((const)); -operand_t *def_operand (struct def_s *def, struct type_s *type); -operand_t *return_operand (struct type_s *type); -operand_t *value_operand (struct ex_value_s *value); +operand_t *def_operand (struct def_s *def, struct type_s *type, + struct expr_s *expr); +operand_t *return_operand (struct type_s *type, struct expr_s *expr); +operand_t *value_operand (struct ex_value_s *value, struct expr_s *expr); int tempop_overlap (tempop_t *t1, tempop_t *t2) __attribute__((pure)); -operand_t *temp_operand (struct type_s *type); +operand_t *temp_operand (struct type_s *type, struct expr_s *expr); int tempop_visit_all (tempop_t *tempop, int overlap, int (*visit) (tempop_t *, void *), void *data); -operand_t *alias_operand (struct type_s *type, operand_t *op); +operand_t *alias_operand (struct type_s *type, operand_t *op, + struct expr_s *expr); void free_operand (operand_t *op); sblock_t *new_sblock (void); diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index 86acc210a..a97b3e68c 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -821,7 +821,7 @@ static operand_t * fix_op_type (operand_t *op, type_t *type) { if (op && op->op_type != op_label && op->type != type) - op = alias_operand (type, op); + op = alias_operand (type, op, op->expr); return op; } @@ -882,7 +882,8 @@ generate_moveps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) offset = dstDef->offset; dstDef = dstDef->alias; } - operands[2] = value_operand (new_pointer_val (offset, type, dstDef)); + operands[2] = value_operand (new_pointer_val (offset, type, dstDef), + operands[1]->expr); st = build_statement ("", operands, var->expr); sblock_add_statement (block, st); } @@ -937,7 +938,8 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode) operands[1] = make_operand (dag, block, dagnode, 1); type = get_type (dagnode->label->expr); if (!(var_iter = set_first (dagnode->identifiers))) { - operands[2] = temp_operand (get_type (dagnode->label->expr)); + operands[2] = temp_operand (get_type (dagnode->label->expr), + dagnode->label->expr); } else { daglabel_t *var = dag->labels[var_iter->element]; diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 4ee42e214..ff0d1de96 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -1102,7 +1102,7 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, def_t *alias; ex_pointer_t *ptr = &s->opc->o.value->v.pointer; alias = alias_def (ptr->def, ptr->type, ptr->val); - op = def_operand (alias, ptr->type); + op = def_operand (alias, ptr->type, s->opc->expr); flow_add_op_var (def, op, 0); if (operands) operands[0] = op; diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 0ba4d1e21..e156efd1a 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -273,11 +273,12 @@ new_statement (st_type_t type, const char *opcode, expr_t *expr) } static operand_t * -new_operand (op_type_e op) +new_operand (op_type_e op, expr_t *expr) { operand_t *operand; ALLOC (256, operand_t, operands, operand); operand->op_type = op; + operand->expr = expr; return operand; } @@ -311,13 +312,13 @@ free_sblock (sblock_t *sblock) } operand_t * -def_operand (def_t *def, type_t *type) +def_operand (def_t *def, type_t *type, expr_t *expr) { operand_t *op; if (!type) type = def->type; - op = new_operand (op_def); + op = new_operand (op_def, expr); op->type = type; op->size = type_size (type); op->o.def = def; @@ -325,28 +326,28 @@ def_operand (def_t *def, type_t *type) } operand_t * -return_operand (type_t *type) +return_operand (type_t *type, expr_t *expr) { symbol_t *return_symbol; return_symbol = make_symbol (".return", &type_param, pr.symtab->space, sc_extern); - return def_operand (return_symbol->s.def, type); + return def_operand (return_symbol->s.def, type, expr); } operand_t * -value_operand (ex_value_t *value) +value_operand (ex_value_t *value, expr_t *expr) { operand_t *op; - op = new_operand (op_value); + op = new_operand (op_value, expr); op->type = value->type; op->o.value = value; return op; } operand_t * -temp_operand (type_t *type) +temp_operand (type_t *type, expr_t *expr) { - operand_t *op = new_operand (op_temp); + operand_t *op = new_operand (op_temp, expr); op->o.tempop.type = type; op->type = type; @@ -412,7 +413,7 @@ tempop_visit_all (tempop_t *tempop, int overlap, } operand_t * -alias_operand (type_t *type, operand_t *op) +alias_operand (type_t *type, operand_t *op, expr_t *expr) { operand_t *aop; @@ -420,7 +421,7 @@ alias_operand (type_t *type, operand_t *op) internal_error (0, "\naliasing operand with type of different size" " (%d, %d)", type_size (type), type_size (op->type)); } - aop = new_operand (op_alias); + aop = new_operand (op_alias, expr); aop->o.alias = op; aop->type = type; aop->size = type_size (type); @@ -428,10 +429,10 @@ alias_operand (type_t *type, operand_t *op) } static operand_t * -short_operand (short short_val) +short_operand (short short_val, expr_t *expr) { ex_value_t *val = new_short_val (short_val); - return value_operand (val); + return value_operand (val, expr); } static const char * @@ -593,7 +594,7 @@ statement_branch (sblock_t *sblock, expr_t *e) if (e->type == ex_uexpr && e->e.expr.op == 'g') { s = new_statement (st_flow, "", e); - s->opa = new_operand (op_label); + s->opa = new_operand (op_label, e); s->opa->o.label = &e->e.expr.e1->e.label; } else { if (e->e.expr.op == 'g') { @@ -604,7 +605,7 @@ statement_branch (sblock_t *sblock, expr_t *e) opcode = convert_op (e->e.expr.op); s = new_statement (st_flow, opcode, e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); - s->opb = new_operand (op_label); + s->opb = new_operand (op_label, e); s->opb->o.label = &e->e.expr.e2->e.label; } } @@ -783,7 +784,7 @@ expr_address (sblock_t *sblock, expr_t *e, operand_t **op) statement_t *s; s = new_statement (st_expr, "&", e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); - s->opc = temp_operand (e->e.expr.type); + s->opc = temp_operand (e->e.expr.type, e); sblock_add_statement (sblock, s); *(op) = s->opc; return sblock; @@ -795,7 +796,7 @@ lea_statement (operand_t *pointer, operand_t *offset, expr_t *e) statement_t *s = new_statement (st_expr, "&", e); s->opa = pointer; s->opb = offset; - s->opc = temp_operand (&type_pointer); + s->opc = temp_operand (&type_pointer, e); return s; } @@ -804,7 +805,7 @@ address_statement (operand_t *value, expr_t *e) { statement_t *s = new_statement (st_expr, "&", e); s->opa = value; - s->opc = temp_operand (&type_pointer); + s->opc = temp_operand (&type_pointer, e); return s; } @@ -819,7 +820,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) && e->e.expr.e1->type == ex_symbol) { if (e->e.expr.e1->e.symbol->sy_type != sy_var) internal_error (e, "address of non-var"); - *op = def_operand (e->e.expr.e1->e.symbol->s.def, type); + *op = def_operand (e->e.expr.e1->e.symbol->s.def, type, e); } else if (e->type == ex_expr && e->e.expr.op == '&') { statement_t *s; operand_t *ptr = 0; @@ -827,7 +828,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) sblock = statement_subexpr (sblock, e->e.expr.e1, &ptr); sblock = statement_subexpr (sblock, e->e.expr.e2, &offs); if (!*op) - *op = temp_operand (type); + *op = temp_operand (type, e); if (low_level_type (type) == ev_void) { operand_t *src_addr; operand_t *dst_addr; @@ -843,7 +844,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) s = new_statement (st_move, "", deref); s->opa = src_addr; - s->opb = short_operand (type_size (type)); + s->opb = short_operand (type_size (type), e); s->opc = dst_addr; sblock_add_statement (sblock, s); } else { @@ -856,17 +857,17 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) } else if (e->type == ex_value && e->e.value->lltype == ev_pointer) { ex_pointer_t *ptr = &e->e.value->v.pointer; *op = def_operand (alias_def (ptr->def, ptr->type, ptr->val), - ptr->type); + ptr->type, e); } else { statement_t *s; operand_t *ptr = 0; sblock = statement_subexpr (sblock, e, &ptr); if (!*op) - *op = temp_operand (type); + *op = temp_operand (type, e); s = new_statement (st_expr, ".", deref); s->opa = ptr; - s->opb = short_operand (0); + s->opb = short_operand (0, e); s->opc = *op; sblock_add_statement (sblock, s); } @@ -919,7 +920,7 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op) } } if (!top) { - top = temp_operand (type); + top = temp_operand (type, e); top->o.tempop.alias = aop; top->o.tempop.offset = offset; top->next = aop->o.tempop.alias_ops; @@ -930,9 +931,9 @@ expr_alias (sblock_t *sblock, expr_t *e, operand_t **op) def = aop->o.def; while (def->alias) def = def->alias; - *op = def_operand (alias_def (def, type, offset), 0); + *op = def_operand (alias_def (def, type, offset), 0, e); } else if (aop->op_type == op_value) { - *op = value_operand (aop->o.value); + *op = value_operand (aop->o.value, e); (*op)->type = type; } else { internal_error (e, "invalid alias target: %s: %s", @@ -970,7 +971,7 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); sblock = statement_subexpr (sblock, e->e.expr.e2, &s->opb); if (!*op) - *op = temp_operand (e->e.expr.type); + *op = temp_operand (e->e.expr.type, e); s->opc = *op; sblock_add_statement (sblock, s); break; @@ -989,7 +990,7 @@ expr_cast (sblock_t *sblock, expr_t *e, operand_t **op) if (is_scalar (src_type) && is_scalar (type)) { operand_t *src = 0; sblock = statement_subexpr (sblock, e->e.expr.e1, &src); - *op = temp_operand (e->e.expr.type); + *op = temp_operand (e->e.expr.type, e); s = new_statement (st_expr, "", e); s->opa = src; s->opc = *op; @@ -1046,7 +1047,7 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op) s = new_statement (st_expr, opcode, e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); if (!*op) - *op = temp_operand (e->e.expr.type); + *op = temp_operand (e->e.expr.type, e); s->opc = *op; sblock_add_statement (sblock, s); } @@ -1059,11 +1060,11 @@ expr_symbol (sblock_t *sblock, expr_t *e, operand_t **op) symbol_t *sym = e->e.symbol; if (sym->sy_type == sy_var) { - *op = def_operand (sym->s.def, sym->type); + *op = def_operand (sym->s.def, sym->type, e); } else if (sym->sy_type == sy_const) { - *op = value_operand (sym->s.value); + *op = value_operand (sym->s.value, e); } else if (sym->sy_type == sy_func) { - *op = def_operand (sym->s.func->def, 0); + *op = def_operand (sym->s.func->def, 0, e); } else { internal_error (e, "unexpected symbol type: %s for %s", symtype_str (sym->sy_type), sym->name); @@ -1075,7 +1076,7 @@ static sblock_t * expr_temp (sblock_t *sblock, expr_t *e, operand_t **op) { if (!e->e.temp.op) - e->e.temp.op = temp_operand (e->e.temp.type); + e->e.temp.op = temp_operand (e->e.temp.type, e); *op = e->e.temp.op; return sblock; } @@ -1151,7 +1152,7 @@ expr_vector_e (sblock_t *sblock, expr_t *e, operand_t **op) static sblock_t * expr_value (sblock_t *sblock, expr_t *e, operand_t **op) { - *op = value_operand (e->e.value); + *op = value_operand (e->e.value, e); return sblock; } @@ -1414,7 +1415,7 @@ statement_uexpr (sblock_t *sblock, expr_t *e) } s = new_statement (st_func, opcode, e); if (e->e.expr.e1) { - s->opa = return_operand (get_type (e->e.expr.e1)); + s->opa = return_operand (get_type (e->e.expr.e1), e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); } sblock_add_statement (sblock, s); @@ -1718,7 +1719,7 @@ check_final_block (sblock_t *sblock) s = new_statement (st_func, "", 0); if (options.traditional || options.code.progsversion == PROG_ID_VERSION) { s->opcode = save_string (""); - s->opa = return_operand (&type_void); + s->opa = return_operand (&type_void, 0); } sblock_add_statement (sblock, s); } From 813319efc241d94154df1032067c90828fa27f73 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 12:53:40 +0900 Subject: [PATCH 293/444] [qfcc] Implement goto It's just too useful when used correctly. --- tools/qfcc/source/qc-lex.l | 1 + tools/qfcc/source/qc-parse.y | 9 +++++++-- tools/qfcc/source/statements.c | 16 +++++++++++----- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tools/qfcc/source/qc-lex.l b/tools/qfcc/source/qc-lex.l index 353191593..9d5c5a1b9 100644 --- a/tools/qfcc/source/qc-lex.l +++ b/tools/qfcc/source/qc-lex.l @@ -353,6 +353,7 @@ static keyword_t obj_keywords[] = { // make the language features available to traditional code. static keyword_t at_keywords[] = { {"for", FOR }, + {"goto", GOTO }, {"break", BREAK }, {"continue", CONTINUE}, {"switch", SWITCH }, diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 3e5079313..27423d4ef 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -145,8 +145,8 @@ int yylex (void); %token VALUE STRING %token LOCAL RETURN WHILE DO IF ELSE FOR BREAK CONTINUE ELLIPSIS -%token NIL IFBE IFB IFAE IFA SWITCH CASE DEFAULT ENUM TYPEDEF -%token ARGS EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT +%token NIL IFBE IFB IFAE IFA GOTO SWITCH CASE DEFAULT ENUM +%token ARGS TYPEDEF EXTERN STATIC SYSTEM NOSAVE OVERLOAD NOT %token STRUCT %token TYPE %token OBJECT TYPE_NAME @@ -1310,6 +1310,11 @@ statement switch_block = $5; break_label = $2; } + | GOTO NAME + { + expr_t *label = named_label_expr ($2); + $$ = goto_expr (label); + } | IF not '(' texpr ')' statement %prec IFX { $$ = build_if_statement ($2, $4, $6, 0, 0); diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index e156efd1a..42a5494e8 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1551,7 +1551,7 @@ remove_label_from_dest (ex_label_t *label) sblock_t *sblock; ex_label_t **l; - if (!label) + if (!label || !label->dest) return; debug (0, "dropping deceased label %s", label->name); @@ -1588,14 +1588,20 @@ thread_jumps (sblock_t *blocks) if (!sblock->statements) continue; s = (statement_t *) sblock->tail; - if (statement_is_goto (s)) + if (statement_is_goto (s)) { label = &s->opa->o.label; - else if (statement_is_cond (s)) + if (!(*label)->dest && s->opa->expr) { + error (s->opa->expr, "undefined label `%s'", (*label)->name); + s->opa->expr = 0; + } + } else if (statement_is_cond (s)) { label = &s->opb->o.label; - else + } else { continue; + } for (l = *label; - l->dest->statements && statement_is_goto (l->dest->statements); + l->dest && l->dest->statements + && statement_is_goto (l->dest->statements); l = l->dest->statements->opa->o.label) { } if (l != *label) { From 393e540ffa3af2613668b0de13af2375ae5fcc1e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 13:31:12 +0900 Subject: [PATCH 294/444] [qfcc] Print the source name of an undefined label Undefined labels generated by the compiler indicate severe trouble. --- tools/qfcc/include/expr.h | 1 + tools/qfcc/source/expr.c | 6 +++++- tools/qfcc/source/statements.c | 7 ++++--- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 6556a8d06..fa88dc80d 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -75,6 +75,7 @@ typedef struct ex_label_s { struct reloc_s *refs; ///< relocations associated with this label struct sblock_s *dest; ///< the location of this label if known const char *name; ///< the name of this label + struct symbol_s *symbol; ///< symbol used to define this label (maybe 0) int used; ///< label is used as a target struct daglabel_s *daglabel; } ex_label_t; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index d080d2332..e9967dbc7 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -499,6 +499,7 @@ expr_t * named_label_expr (symbol_t *label) { symbol_t *sym; + expr_t *l; if (!current_func) { // XXX this might be only an error @@ -510,8 +511,11 @@ named_label_expr (symbol_t *label) if (sym) { return sym->s.expr; } + l = new_label_expr (); + l->e.label.name = save_string (va ("%s_%s", l->e.label.name, label->name)); + l->e.label.symbol = label; label->sy_type = sy_expr; - label->s.expr = new_label_expr (); + label->s.expr = l; symtab_addsymbol (current_func->label_scope, label); return label->s.expr; } diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 42a5494e8..f82fa552e 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1590,9 +1590,10 @@ thread_jumps (sblock_t *blocks) s = (statement_t *) sblock->tail; if (statement_is_goto (s)) { label = &s->opa->o.label; - if (!(*label)->dest && s->opa->expr) { - error (s->opa->expr, "undefined label `%s'", (*label)->name); - s->opa->expr = 0; + if (!(*label)->dest && (*label)->symbol) { + error (s->opa->expr, "undefined label `%s'", + (*label)->symbol->name); + (*label)->symbol = 0; } } else if (statement_is_cond (s)) { label = &s->opb->o.label; From f10f9e157df69587deabcf0e09f550bdd76c31a7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 13:33:06 +0900 Subject: [PATCH 295/444] [qfcc] Warn about unused labels --- tools/qfcc/source/statements.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index f82fa552e..517fcc7b3 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1344,7 +1344,11 @@ statement_label (sblock_t *sblock, expr_t *e) e->e.label.next = sblock->labels; sblock->labels = &e->e.label; } else { - debug (e, "dropping unused label %s", e->e.label.name); + if (e->e.label.symbol) { + warning (e, "unused label %s", e->e.label.symbol->name); + } else { + debug (e, "dropping unused label %s", e->e.label.name); + } } return sblock; } From d1e83b9d4887eba79236b5531dc8e0a42063d702 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 15:46:57 +0900 Subject: [PATCH 296/444] [qfcc] Create a compound initializer expression type This fixes the problem of using the return value of a function as an element in a compound initializer. The cause of the problem is that compound initializers were represented by block expressions, but function calls are contained within block expressions, so def initialization saw the block expression and thought it was a nested compound initializer. Technically, it was a bug in the nested element parsing code in that it wasn't checking the result value of the block expression, but using a whole new expression type makes things much cleaner and the work done paves the way for labeled initializers and compound assignments. --- tools/qfcc/include/expr.h | 17 ++++++++++ tools/qfcc/source/def.c | 36 +++++++++++---------- tools/qfcc/source/expr.c | 57 +++++++++++++++++++++++++++++++-- tools/qfcc/source/expr_assign.c | 1 + tools/qfcc/source/qc-parse.y | 42 +++++++++++------------- 5 files changed, 109 insertions(+), 44 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index fa88dc80d..230ecd241 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -55,6 +55,7 @@ typedef enum { ex_nil, ///< umm, nil, null. nuff said (0 of any type) ex_value, ///< constant value (::ex_value_t) + ex_compound, ///< compound initializer } expr_type; /** Binary and unary expressions. @@ -84,6 +85,17 @@ typedef struct { ex_label_t *label; } ex_labelref_t; +typedef struct ex_initele_s { + struct ex_initele_s *next; ///< next in chain + struct symbol_s *symbol; ///< for labeled initializers + struct expr_s *expr; ///< initializer expression +} ex_initele_t; + +typedef struct ex_cmpinit_s { + ex_initele_t *head; + ex_initele_t **tail; +} ex_cmpinit_t; + typedef struct { struct expr_s *head; ///< the first expression in the block struct expr_s **tail; ///< last expression in the block, for appending @@ -210,6 +222,7 @@ typedef struct expr_s { ex_temp_t temp; ///< temporary variable expression ex_vector_t vector; ///< vector expression list ex_value_t *value; ///< constant value + ex_cmpinit_t compound; ///< compound initializer } e; } expr_t; @@ -348,6 +361,10 @@ expr_t *new_block_expr (void); */ expr_t *build_block_expr (expr_t *expr_list); +ex_initele_t *new_initele (expr_t *expr, struct symbol_s *symbol); +expr_t *new_compound_init (void); +expr_t *append_element (expr_t *compound, ex_initele_t *element); + /** Create a new binary expression node node. If either \a e1 or \a e2 are error expressions, then that expression will diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 865ef4066..d600fb0ae 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -86,7 +86,7 @@ new_element (void) } static element_t * -append_element (element_chain_t *element_chain, element_t *element) +append_init_element (element_chain_t *element_chain, element_t *element) { element->next = 0; *element_chain->tail = element; @@ -371,7 +371,7 @@ static void build_element_chain (element_chain_t *element_chain, type_t *type, expr_t *eles, int base_offset) { - expr_t *e = eles->e.block.head; + ex_initele_t *ele = eles->e.compound.head; if (is_array (type)) { type_t *array_type = type->t.array.type; @@ -380,17 +380,18 @@ build_element_chain (element_chain_t *element_chain, type_t *type, for (i = 0; i < array_size; i++) { int offset = base_offset + i * type_size (array_type); - if (e && e->type == ex_block) { - build_element_chain (element_chain, array_type, e, offset); + if (ele->expr && ele->expr->type == ex_compound) { + build_element_chain (element_chain, array_type, + ele->expr, offset); } else { element_t *element = new_element (); element->type = array_type; element->offset = offset; - element->expr = e; // null will be treated as nil - append_element (element_chain, element); + element->expr = ele->expr; // null will be treated as nil + append_init_element (element_chain, element); } - if (e) { - e = e->next; + if (ele) { + ele = ele->next; } } } else if (is_struct (type) || is_vector (type) || is_quaternion (type)) { @@ -403,23 +404,24 @@ build_element_chain (element_chain_t *element_chain, type_t *type, || field->visibility == vis_anonymous) { continue; } - if (e && e->type == ex_block) { - build_element_chain (element_chain, field->type, e, offset); + if (ele->expr && ele->expr->type == ex_compound) { + build_element_chain (element_chain, field->type, + ele->expr, offset); } else { element_t *element = new_element (); element->type = field->type; element->offset = offset; - element->expr = e; // null will be treated as nil - append_element (element_chain, element); + element->expr = ele->expr; // null will be treated as nil + append_init_element (element_chain, element); } - if (e) { - e = e->next; + if (ele) { + ele = ele->next; } } } else { error (eles, "invalid initializer"); } - if (e && e->next && options.warnings.initializer) { + if (ele && ele->next && options.warnings.initializer) { warning (eles, "excessive elements in initializer"); } } @@ -652,7 +654,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, } if (!sym->s.def) { if (is_array (sym->type) && !type_size (sym->type) - && init->type == ex_block && !init->e.block.result) { + && init->type == ex_compound) { sym->type = array_type (sym->type->t.array.type, num_elements (init)); } @@ -676,7 +678,7 @@ initialize_def (symbol_t *sym, expr_t *init, defspace_t *space, return; if ((is_array (sym->type) || is_struct (sym->type) || sym->type == &type_vector || sym->type == &type_quaternion) - && ((init->type == ex_block && !init->e.block.result) + && ((init->type == ex_compound) || init->type == ex_nil)) { init_elements (sym->s.def, init); sym->s.def->initialized = 1; diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index e9967dbc7..b4173f45d 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -217,6 +217,7 @@ get_type (expr_t *e) return &type_void; case ex_label: case ex_error: + case ex_compound: return 0; // something went very wrong case ex_bool: if (options.code.progsversion == PROG_ID_VERSION) @@ -420,14 +421,21 @@ copy_expr (expr_t *e) n = new_expr (); n->e.vector.type = e->e.vector.type; n->e.vector.list = copy_expr (e->e.vector.list); - n = n->e.vector.list; t = e->e.vector.list; + e = n->e.vector.list; while (t->next) { - n->next = copy_expr (t->next); - n = n->next; + e->next = copy_expr (t->next); + e = e->next; t = t->next; } return n; + case ex_compound: + n = new_expr (); + *n = *e; + for (ex_initele_t *i = e->e.compound.head; i; i = i->next) { + append_element (n, new_initele (i->expr, i->symbol)); + } + return n; } internal_error (e, "invalid expression"); } @@ -543,6 +551,46 @@ new_block_expr (void) return b; } +ex_initele_t * +new_initele (expr_t *expr, symbol_t *symbol) +{ + ex_initele_t *i = calloc (1, sizeof (*i)); + i->expr = expr; + i->symbol = symbol; + return i; +} + +expr_t * +new_compound_init (void) +{ + expr_t *c = new_expr (); + c->type = ex_compound; + c->e.compound.head = 0; + c->e.compound.tail = &c->e.compound.head; + return c; +} + +expr_t * +append_element (expr_t *compound, ex_initele_t *element) +{ + if (compound->type != ex_compound) { + internal_error (compound, "not a compound expression"); + } + + if (!element || (element->expr && element->expr->type == ex_error)) { + return compound; + } + + if (element->next) { + internal_error (compound, "append_element: element loop detected"); + } + + *compound->e.compound.tail = element; + compound->e.compound.tail = &element->next; + + return compound; +} + expr_t * new_binary_expr (int op, expr_t *e1, expr_t *e2) { @@ -1499,6 +1547,7 @@ unary_expr (int op, expr_t *e) case ex_label: case ex_labelref: case ex_state: + case ex_compound: internal_error (e, 0); case ex_uexpr: if (e->e.expr.op == '-') @@ -1565,6 +1614,7 @@ unary_expr (int op, expr_t *e) case ex_label: case ex_labelref: case ex_state: + case ex_compound: internal_error (e, 0); case ex_bool: return new_bool_expr (e->e.bool.false_list, @@ -1630,6 +1680,7 @@ unary_expr (int op, expr_t *e) case ex_label: case ex_labelref: case ex_state: + case ex_compound: internal_error (e, 0); case ex_uexpr: if (e->e.expr.op == '~') diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index f0d7daf4b..466ffcf95 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -123,6 +123,7 @@ check_valid_lvalue (expr_t *expr) return check_valid_lvalue (expr->e.expr.e1); } break; + case ex_compound: case ex_state: case ex_bool: case ex_label: diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 27423d4ef..83ac9ca8a 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -98,6 +98,7 @@ int yylex (void); void *pointer; // for ensuring pointer values are null struct type_s *type; struct expr_s *expr; + struct ex_initele_s *element; struct function_s *function; struct switch_block_s *switch_block; struct param_s *param; @@ -181,7 +182,9 @@ int yylex (void); %type methoddef %type opt_initializer var_initializer local_def -%type opt_init opt_expr cexpr expr element_list element +%type opt_init opt_expr cexpr expr +%type compound_init element_list +%type element %type optional_state_expr texpr vector_expr %type statement statements compound_statement %type else bool_label break_label continue_label @@ -1148,17 +1151,20 @@ opt_initializer var_initializer : '=' expr { $$ = $2; } - | '=' '{' { $$ = $-1; } - element_list optional_comma '}' { $$ = $4; } - | '=' '{' '}' + | '=' compound_init { - if (is_scalar ($-1.type)) { + if (!$2 && is_scalar ($-1.type)) { error (0, "empty scalar initializer"); } - $$ = new_nil_expr (); + $$ = $2 ? $2 : new_nil_expr (); } ; +compound_init + : '{' element_list optional_comma '}' { $$ = $2; } + | '{' '}' { $$ = 0; } + ; + optional_state_expr : /* emtpy */ { $$ = 0; } | vector_expr { $$ = build_state_expr ($1); } @@ -1167,30 +1173,18 @@ optional_state_expr element_list : element { - $$ = new_block_expr (); - append_expr ($$, $1); + $$ = new_compound_init (); + append_element ($$, $1); } - | element_list ',' {$$ = $0; } element + | element_list ',' element { - append_expr ($$, $4); + append_element ($$, $3); } ; element - : '{' { $$ = $0; } - element_list optional_comma '}' { $$ = $3; } - | '{' '}' - { - // FIXME doesn't check the right type (does prove the inherited - // attributes have been passed down correctly though). The problem - // is that the type of the sub elements needs to be extracted if - // possible - if (is_scalar ($0.type)) { - error (0, "empty scalar initializer"); - } - $$ = new_nil_expr (); - } - | expr { $$ = $1; } + : compound_init { $$ = new_initele ($1, 0); } + | expr { $$ = new_initele ($1, 0); } ; optional_comma From afd31ed29243e5840f5889c6c746e1cf37a1b153 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 16:07:58 +0900 Subject: [PATCH 297/444] [qfcc] Rename cexpr to comma_expr It took me too long to figure out what cexpr was for. --- tools/qfcc/source/qc-parse.y | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 83ac9ca8a..5b3216d10 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -182,7 +182,7 @@ int yylex (void); %type methoddef %type opt_initializer var_initializer local_def -%type opt_init opt_expr cexpr expr +%type opt_init opt_expr comma_expr expr %type compound_init element_list %type element %type optional_state_expr texpr vector_expr @@ -1342,7 +1342,7 @@ statement break_label = $2; continue_label = $3; } - | cexpr ';' + | comma_expr ';' { $$ = $1; } @@ -1398,7 +1398,7 @@ switch_block ; opt_init - : cexpr + : comma_expr | type set_spec_storage init_var_decl_list { $$ = $3; } | /* empty */ { @@ -1431,7 +1431,7 @@ init_var_decl ; opt_expr - : cexpr + : comma_expr | /* empty */ { $$ = 0; @@ -1521,7 +1521,7 @@ texpr : expr { $$ = convert_bool ($1, 1); } ; -cexpr +comma_expr : arg_list { if ($1->next) { From 023a920a511cb3e488608773d36b1a18b9172893 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 19:38:50 +0900 Subject: [PATCH 298/444] [gamecode] Replace lost parameter auto-reset rcallN messes with the progs parameter pointers and not resetting them can cause incorrect data to be copied into the called function. --- libs/gamecode/pr_exec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 47b39bc58..d673b7d1c 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -199,6 +199,7 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f) if (pr->pr_params[i] != pr->pr_real_params[i]) { copy_param (pr->pr_real_params[i], pr->pr_params[i], f->parm_size[i].size); + pr->pr_params[i] = pr->pr_real_params[i]; } } } else if (f->numparms < 0) { @@ -210,6 +211,7 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f) if (pr->pr_params[i] != pr->pr_real_params[i]) { copy_param (pr->pr_real_params[i], pr->pr_params[i], f->parm_size[i].size); + pr->pr_params[i] = pr->pr_real_params[i]; } } dparmsize_t parmsize = { pr->pr_param_size, pr->pr_param_alignment }; @@ -221,6 +223,7 @@ PR_EnterFunction (progs_t *pr, bfunction_t *f) if (pr->pr_params[i] != pr->pr_real_params[i]) { copy_param (pr->pr_real_params[i], pr->pr_params[i], parmsize.size); + pr->pr_params[i] = pr->pr_real_params[i]; } } } From b6439e8dc1f2db26078a9b38c4760ac427ef5f44 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 19:42:38 +0900 Subject: [PATCH 299/444] [qfcc] Support compound init in assignment and params foo({...}) and bar = {...} --- tools/qfcc/include/expr.h | 30 ++-- tools/qfcc/source/Makefile.am | 3 +- tools/qfcc/source/def.c | 109 +-------------- tools/qfcc/source/expr.c | 63 +++------ tools/qfcc/source/expr_assign.c | 8 +- tools/qfcc/source/expr_compound.c | 209 ++++++++++++++++++++++++++++ tools/qfcc/source/qc-parse.y | 32 +++-- tools/qfcc/test/Makefile.am | 10 ++ tools/qfcc/test/compound.r | 72 ++++++++++ tools/qfcc/test/struct-init-param.r | 19 ++- 10 files changed, 381 insertions(+), 174 deletions(-) create mode 100644 tools/qfcc/source/expr_compound.c create mode 100644 tools/qfcc/test/compound.r diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 230ecd241..008313a5a 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -85,16 +85,18 @@ typedef struct { ex_label_t *label; } ex_labelref_t; -typedef struct ex_initele_s { - struct ex_initele_s *next; ///< next in chain - struct symbol_s *symbol; ///< for labeled initializers +typedef struct element_s { + struct element_s *next; ///< next in chain + int offset; + struct type_s *type; struct expr_s *expr; ///< initializer expression -} ex_initele_t; + struct symbol_s *symbol; ///< for labeled initializers +} element_t; -typedef struct ex_cmpinit_s { - ex_initele_t *head; - ex_initele_t **tail; -} ex_cmpinit_t; +typedef struct element_chain_s { + element_t *head; + element_t **tail; +} element_chain_t; typedef struct { struct expr_s *head; ///< the first expression in the block @@ -222,7 +224,7 @@ typedef struct expr_s { ex_temp_t temp; ///< temporary variable expression ex_vector_t vector; ///< vector expression list ex_value_t *value; ///< constant value - ex_cmpinit_t compound; ///< compound initializer + element_chain_t compound; ///< compound initializer } e; } expr_t; @@ -361,9 +363,15 @@ expr_t *new_block_expr (void); */ expr_t *build_block_expr (expr_t *expr_list); -ex_initele_t *new_initele (expr_t *expr, struct symbol_s *symbol); +element_t *new_element (expr_t *expr, struct symbol_s *symbol); expr_t *new_compound_init (void); -expr_t *append_element (expr_t *compound, ex_initele_t *element); +expr_t *append_element (expr_t *compound, element_t *element); +expr_t *initialized_temp_expr (struct type_s *type, expr_t *compound); +void assign_elements (expr_t *local_expr, expr_t *ptr, + element_chain_t *element_chain); +void build_element_chain (element_chain_t *element_chain, struct type_s *type, + expr_t *eles, int base_offset); +void free_element_chain (element_chain_t *element_chain); /** Create a new binary expression node node. diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am index d9ceb5ba2..cfd31afbc 100644 --- a/tools/qfcc/source/Makefile.am +++ b/tools/qfcc/source/Makefile.am @@ -41,7 +41,8 @@ bin_SCRIPTS= qfpreqcc common_src=\ class.c codespace.c constfold.c cpp.c dags.c debug.c def.c defspace.c \ diagnostic.c dot.c dot_dag.c dot_expr.c dot_flow.c dot_sblock.c emit.c \ - expr.c expr_assign.c expr_binary.c expr_bool.c flow.c function.c grab.c \ + expr.c expr_assign.c expr_binary.c expr_bool.c expr_compound.c \ + flow.c function.c grab.c \ idstuff.c \ linker.c method.c \ obj_file.c \ diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index d600fb0ae..f690f2c3b 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -62,37 +62,7 @@ #include "type.h" #include "value.h" -typedef struct element_s { - struct element_s *next; - int offset; - type_t *type; - expr_t *expr; -} element_t; - -typedef struct element_chain_s { - element_t *head; - element_t **tail; -} element_chain_t; - static def_t *defs_freelist; -static element_t *elements_freelist; - -static element_t * -new_element (void) -{ - element_t *element; - ALLOC (256, element_t, elements, element); - return element; -} - -static element_t * -append_init_element (element_chain_t *element_chain, element_t *element) -{ - element->next = 0; - *element_chain->tail = element; - element_chain->tail = &element->next; - return element; -} static void set_storage_bits (def_t *def, storage_class_t storage) @@ -367,65 +337,6 @@ init_elements_nil (def_t *def) // it's a global, so already initialized to 0 } -static void -build_element_chain (element_chain_t *element_chain, type_t *type, - expr_t *eles, int base_offset) -{ - ex_initele_t *ele = eles->e.compound.head; - - if (is_array (type)) { - type_t *array_type = type->t.array.type; - int array_size = type->t.array.size; - int i; - - for (i = 0; i < array_size; i++) { - int offset = base_offset + i * type_size (array_type); - if (ele->expr && ele->expr->type == ex_compound) { - build_element_chain (element_chain, array_type, - ele->expr, offset); - } else { - element_t *element = new_element (); - element->type = array_type; - element->offset = offset; - element->expr = ele->expr; // null will be treated as nil - append_init_element (element_chain, element); - } - if (ele) { - ele = ele->next; - } - } - } else if (is_struct (type) || is_vector (type) || is_quaternion (type)) { - symtab_t *symtab = type->t.symtab; - symbol_t *field; - - for (field = symtab->symbols; field; field = field->next) { - int offset = base_offset + field->s.offset; - if (field->sy_type != sy_var - || field->visibility == vis_anonymous) { - continue; - } - if (ele->expr && ele->expr->type == ex_compound) { - build_element_chain (element_chain, field->type, - ele->expr, offset); - } else { - element_t *element = new_element (); - element->type = field->type; - element->offset = offset; - element->expr = ele->expr; // null will be treated as nil - append_init_element (element_chain, element); - } - if (ele) { - ele = ele->next; - } - } - } else { - error (eles, "invalid initializer"); - } - if (ele && ele->next && options.warnings.initializer) { - warning (eles, "excessive elements in initializer"); - } -} - static void init_elements (struct def_s *def, expr_t *eles) { @@ -444,21 +355,8 @@ init_elements (struct def_s *def, expr_t *eles) build_element_chain (&element_chain, def->type, eles, 0); if (def->local && local_expr) { - for (element = element_chain.head; element; element = element->next) { - int offset = element->offset; - type_t *type = element->type; - expr_t *ptr = new_pointer_expr (offset, type, def); - - if (element->expr) { - c = constant_expr (element->expr); - } else { - c = new_nil_expr (); - } - if (c->type == ex_nil) { - c = convert_nil (c, type); - } - append_expr (local_expr, assign_expr (unary_expr ('.', ptr), c)); - } + expr_t *ptr = new_pointer_expr (0, def->type, def); + assign_elements (local_expr, pointer_expr (ptr), &element_chain); } else { def_t dummy = *def; for (element = element_chain.head; element; element = element->next) { @@ -502,8 +400,7 @@ init_elements (struct def_s *def, expr_t *eles) } } - *element_chain.tail = elements_freelist; - elements_freelist = element_chain.head; + free_element_chain (&element_chain); } static void diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index b4173f45d..4b0317d53 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -432,8 +432,8 @@ copy_expr (expr_t *e) case ex_compound: n = new_expr (); *n = *e; - for (ex_initele_t *i = e->e.compound.head; i; i = i->next) { - append_element (n, new_initele (i->expr, i->symbol)); + for (element_t *i = e->e.compound.head; i; i = i->next) { + append_element (n, new_element (i->expr, i->symbol)); } return n; } @@ -551,46 +551,6 @@ new_block_expr (void) return b; } -ex_initele_t * -new_initele (expr_t *expr, symbol_t *symbol) -{ - ex_initele_t *i = calloc (1, sizeof (*i)); - i->expr = expr; - i->symbol = symbol; - return i; -} - -expr_t * -new_compound_init (void) -{ - expr_t *c = new_expr (); - c->type = ex_compound; - c->e.compound.head = 0; - c->e.compound.tail = &c->e.compound.head; - return c; -} - -expr_t * -append_element (expr_t *compound, ex_initele_t *element) -{ - if (compound->type != ex_compound) { - internal_error (compound, "not a compound expression"); - } - - if (!element || (element->expr && element->expr->type == ex_error)) { - return compound; - } - - if (element->next) { - internal_error (compound, "append_element: element loop detected"); - } - - *compound->e.compound.tail = element; - compound->e.compound.tail = &element->next; - - return compound; -} - expr_t * new_binary_expr (int op, expr_t *e1, expr_t *e2) { @@ -1731,6 +1691,7 @@ expr_t * build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) { expr_t *e; + expr_t *p; int arg_count = 0, parm_count = 0; int i; expr_t *args = 0, **a = &args; @@ -1770,8 +1731,18 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) parm_count = ftype->t.func.num_params; } for (i = arg_count - 1, e = params; i >= 0; i--, e = e->next) { - type_t *t = get_type (e); + type_t *t; + if (e->type == ex_compound) { + if (i < parm_count) { + t = ftype->t.func.param_types[i]; + } else { + return error (e, "cannot pass compound initializer " + "through ..."); + } + } else { + t = get_type (e); + } if (!t) { return e; } @@ -1827,7 +1798,11 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) call = expr_file_line (new_block_expr (), fexpr); call->e.block.is_call = 1; - for (e = params, i = 0; e; e = e->next, i++) { + for (p = params, i = 0; p; p = p->next, i++) { + expr_t *e = p; + if (e->type == ex_compound) { + e = expr_file_line (initialized_temp_expr (arg_types[i], e), e); + } if (has_function_call (e)) { expr_t *cast = cast_expr (arg_types[i], convert_vector (e)); expr_t *tmp = new_temp_def_expr (arg_types[i]); diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 466ffcf95..edad8eff7 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -313,10 +313,16 @@ assign_expr (expr_t *dst, expr_t *src) } dst_type = get_type (dst); - src_type = get_type (src); if (!dst_type) { internal_error (dst, "dst_type broke in assign_expr"); } + if (src->type == ex_compound) { + src = initialized_temp_expr (dst_type, src); + if (src->type == ex_error) { + return src; + } + } + src_type = get_type (src); if (!src_type) { internal_error (src, "src_type broke in assign_expr"); } diff --git a/tools/qfcc/source/expr_compound.c b/tools/qfcc/source/expr_compound.c new file mode 100644 index 000000000..5ead7de7a --- /dev/null +++ b/tools/qfcc/source/expr_compound.c @@ -0,0 +1,209 @@ +/* + expr_compound.c + + compound intializer expression construction and manipulations + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/03/11 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "diagnostic.h" +#include "expr.h" +#include "options.h" +#include "symtab.h" +#include "type.h" + +static element_t *elements_freelist; + +element_t * +new_element (expr_t *expr, symbol_t *symbol) +{ + element_t *element; + ALLOC (256, element_t, elements, element); + element->expr = expr; + element->symbol = symbol; + return element; +} + +static element_t * +append_init_element (element_chain_t *element_chain, element_t *element) +{ + element->next = 0; + *element_chain->tail = element; + element_chain->tail = &element->next; + return element; +} + +expr_t * +new_compound_init (void) +{ + expr_t *c = new_expr (); + c->type = ex_compound; + c->e.compound.head = 0; + c->e.compound.tail = &c->e.compound.head; + return c; +} + +void +build_element_chain (element_chain_t *element_chain, type_t *type, + expr_t *eles, int base_offset) +{ + element_t *ele = eles->e.compound.head; + + if (is_array (type)) { + type_t *array_type = type->t.array.type; + int array_size = type->t.array.size; + int i; + + for (i = 0; i < array_size; i++) { + int offset = base_offset + i * type_size (array_type); + if (ele && ele->expr && ele->expr->type == ex_compound) { + build_element_chain (element_chain, array_type, + ele->expr, offset); + } else { + element_t *element = new_element (0, 0); + element->type = array_type; + element->offset = offset; + element->expr = ele ? ele->expr : 0; // null -> nil + append_init_element (element_chain, element); + } + if (ele) { + ele = ele->next; + } + } + } else if (is_struct (type) || is_vector (type) || is_quaternion (type)) { + symtab_t *symtab = type->t.symtab; + symbol_t *field; + + for (field = symtab->symbols; field; field = field->next) { + int offset = base_offset + field->s.offset; + if (field->sy_type != sy_var + || field->visibility == vis_anonymous) { + continue; + } + if (ele && ele->expr && ele->expr->type == ex_compound) { + build_element_chain (element_chain, field->type, + ele->expr, offset); + } else { + element_t *element = new_element (0, 0); + element->type = field->type; + element->offset = offset; + element->expr = ele ? ele->expr : 0; // null -> nil + append_init_element (element_chain, element); + } + if (ele) { + ele = ele->next; + } + } + } else { + error (eles, "invalid initializer"); + } + if (ele && ele->next && options.warnings.initializer) { + warning (eles, "excessive elements in initializer"); + } +} + +void free_element_chain (element_chain_t *element_chain) +{ + *element_chain->tail = elements_freelist; + elements_freelist = element_chain->head; + element_chain->head = 0; + element_chain->tail = &element_chain->head; +} + +expr_t * +append_element (expr_t *compound, element_t *element) +{ + if (compound->type != ex_compound) { + internal_error (compound, "not a compound expression"); + } + + if (!element || (element->expr && element->expr->type == ex_error)) { + return compound; + } + + if (element->next) { + internal_error (compound, "append_element: element loop detected"); + } + append_init_element (&compound->e.compound, element); + return compound; +} + +void +assign_elements (expr_t *local_expr, expr_t *init, + element_chain_t *element_chain) +{ + element_t *element; + + for (element = element_chain->head; element; element = element->next) { + int offset = element->offset; + type_t *type = element->type; + expr_t *alias = new_offset_alias_expr (type, init, offset); + + expr_t *c; + + if (element->expr) { + c = constant_expr (element->expr); + } else { + c = new_nil_expr (); + } + if (c->type == ex_nil) { + c = convert_nil (c, type); + } + append_expr (local_expr, assign_expr (alias, c)); + } +} + +expr_t * +initialized_temp_expr (type_t *type, expr_t *compound) +{ + element_chain_t element_chain; + expr_t *temp = new_temp_def_expr (type); + expr_t *block = new_block_expr (); + + element_chain.head = 0; + element_chain.tail = &element_chain.head; + build_element_chain (&element_chain, type, compound, 0); + assign_elements (block, temp, &element_chain); + block->e.block.result = temp; + free_element_chain (&element_chain); + return block; +} diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 5b3216d10..a4ce4c433 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -98,7 +98,7 @@ int yylex (void); void *pointer; // for ensuring pointer values are null struct type_s *type; struct expr_s *expr; - struct ex_initele_s *element; + struct element_s *element; struct function_s *function; struct switch_block_s *switch_block; struct param_s *param; @@ -188,7 +188,8 @@ int yylex (void); %type optional_state_expr texpr vector_expr %type statement statements compound_statement %type else bool_label break_label continue_label -%type unary_expr ident_expr cast_expr opt_arg_list arg_list +%type unary_expr ident_expr cast_expr expr_list +%type opt_arg_list arg_list arg_expr %type init_var_decl_list init_var_decl %type switch_block %type identifier label @@ -1183,8 +1184,8 @@ element_list ; element - : compound_init { $$ = new_initele ($1, 0); } - | expr { $$ = new_initele ($1, 0); } + : compound_init { $$ = new_element ($1, 0); } + | expr { $$ = new_element ($1, 0); } ; optional_comma @@ -1473,7 +1474,7 @@ ident_expr ; vector_expr - : '[' expr ',' arg_list ']' + : '[' expr ',' expr_list ']' { expr_t *t = $4; while (t->next) @@ -1494,6 +1495,7 @@ cast_expr expr : cast_expr | expr '=' expr { $$ = assign_expr ($1, $3); } + | expr '=' compound_init { $$ = assign_expr ($1, $3); } | expr ASX expr { $$ = asx_expr ($2, $1, $3); } | expr '?' expr ':' expr { $$ = conditional_expr ($1, $3, $5); } | expr AND bool_label expr { $$ = bool_expr (AND, $3, $1, $4); } @@ -1522,7 +1524,7 @@ texpr ; comma_expr - : arg_list + : expr_list { if ($1->next) { expr_t *res = $1; @@ -1533,20 +1535,34 @@ comma_expr } ; +expr_list + : expr + | expr_list ',' expr + { + $3->next = $1; + $$ = $3; + } + ; + opt_arg_list : /* emtpy */ { $$ = 0; } | arg_list { $$ = $1; } ; arg_list - : expr - | arg_list ',' expr + : arg_expr + | arg_list ',' arg_expr { $3->next = $1; $$ = $3; } ; +arg_expr + : expr + | compound_init + ; + const : VALUE | NIL { $$ = new_nil_expr (); } diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index 99c24142c..f4d31a2c9 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -35,6 +35,7 @@ test_progs_dat=\ chewed-alias.dat \ chewed-return.dat \ comma-expr.dat \ + compound.dat \ deadbool.dat \ double.dat \ enum.dat \ @@ -158,6 +159,15 @@ comma-expr.run: Makefile build-run include ./$(DEPDIR)/comma-expr.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/comma-expr.Qo +compound_dat_SOURCES=compound.r +compound_obj=$(compound_dat_SOURCES:.r=.qfo) +compound.dat$(EXEEXT): $(compound_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(compound_obj) +compound.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/compound.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/compound.Qo + deadbool_dat_SOURCES=deadbool.r deadbool_obj=$(deadbool_dat_SOURCES:.r=.qfo) deadbool.dat$(EXEEXT): $(deadbool_obj) $(QFCC_DEP) diff --git a/tools/qfcc/test/compound.r b/tools/qfcc/test/compound.r new file mode 100644 index 000000000..19a72d3fe --- /dev/null +++ b/tools/qfcc/test/compound.r @@ -0,0 +1,72 @@ +#include "test-harness.h" + +typedef struct Point { + int x; + int y; +} Point; + +typedef struct Size { + int width; + int height; +} Size; + +typedef struct Rect { + Point origin; + Size size; +} Rect; + +int test_simple_param (Point p, int x, int y) +{ + int ret = !(p.x == x && p.y == y); + if (ret) { + printf ("simple param: {%d, %d} != {%d, %d}\n", p.x, p.y, x, y); + } + return ret; +} + +int test_nested_param (Rect r, int x, int y, int w, int h) +{ + int ret = !(r.origin.x == x && r.origin.y == y + && r.size.width == w && r.size.height == h); + if (ret) { + printf ("nested param: {{%d, %d}, {%d, %d}} != ", + r.origin.x, r.origin.y, r.size.width, r.size.height); + printf ("{{%d, %d}, {%d, %d}}\n", x, y, w, h); + } + return ret; +} + +int test_simple_assign (int x, int y) +{ + Point p; + p = { x, y }; + int ret = !(p.x == x && p.y == y); + if (ret) { + printf ("simple assign: {%d, %d} != {%d, %d}\n", p.x, p.y, x, y); + } + return ret; +} + +int test_nested_assign (int x, int y, int w, int h) +{ + Rect r; + r = {{x, y}, {w, h}}; + int ret = !(r.origin.x == x && r.origin.y == y + && r.size.width == w && r.size.height == h); + if (ret) { + printf ("nested assign: {{%d, %d}, {%d, %d}} != ", + r.origin.x, r.origin.y, r.size.width, r.size.height); + printf ("{{%d, %d}, {%d, %d}}\n", x, y, w, h); + } + return ret; +} + +int main (void) +{ + int ret = 0; + ret |= test_simple_param ({1, 2}, 1, 2); + ret |= test_nested_param ({{1, 2}, {3, 4}}, 1, 2, 3, 4); + ret |= test_simple_assign (1, 2); + ret |= test_nested_assign (1, 2, 3, 4); + return ret; +} diff --git a/tools/qfcc/test/struct-init-param.r b/tools/qfcc/test/struct-init-param.r index 1b3bc9e7a..f043cfde3 100644 --- a/tools/qfcc/test/struct-init-param.r +++ b/tools/qfcc/test/struct-init-param.r @@ -16,6 +16,12 @@ typedef struct Rect_s { void *foo (Rect *obj, void *cmd, Rect *o, Point pos, Rect r); +void *baz (Rect *obj, void *cmd, Rect *o, Point pos) +{ + Rect rect = { {1, 2}, {3, 4} }; + return foo (obj, cmd, o, pos, rect); +} + void *bar (Rect *obj, void *cmd, Rect *o, Point pos) { Rect rect = { {}, obj.extent }; @@ -33,12 +39,19 @@ Rect o = { { 5, 6}, {7, 8} }; int main (void) { - int ret = 1; + int ret = 0; bar(&obj, nil, &o, obj.offset); printf ("%d %d %d %d\n", o.offset.x, o.offset.y, o.extent.width, o.extent.height); - if (o.offset.x == 0 && o.offset.y == 0 + if not (o.offset.x == 0 && o.offset.y == 0 && o.extent.width == 3 && o.extent.height == 4) - ret = 0; + ret |= 1; + + baz(&obj, nil, &o, obj.offset); + printf ("%d %d %d %d\n", o.offset.x, o.offset.y, + o.extent.width, o.extent.height); + if not (o.offset.x == 1 && o.offset.y == 2 + && o.extent.width == 3 && o.extent.height == 4) + ret |= 1; return ret; } From 48a256efaa62034196258c7254a8ffd115e97f15 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 20:45:25 +0900 Subject: [PATCH 300/444] [qfcc] Fix segfault when assigning {} I had intended to check, but forgot. --- tools/qfcc/source/expr_assign.c | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index edad8eff7..a6b3f81f0 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -293,29 +293,33 @@ assign_expr (expr_t *dst, expr_t *src) type_t *dst_type, *src_type; convert_name (dst); - convert_name (src); - if (dst->type == ex_error) { return dst; } - if (src->type == ex_error) { - return src; - } - - if (options.traditional - && (expr = check_assign_logic_precedence (dst, src))) { - return expr; - } - - if ((expr = check_valid_lvalue (dst))) { return expr; } - dst_type = get_type (dst); if (!dst_type) { internal_error (dst, "dst_type broke in assign_expr"); } + + if (src) { + convert_name (src); + if (src->type == ex_error) { + return src; + } + + if (options.traditional + && (expr = check_assign_logic_precedence (dst, src))) { + return expr; + } + } else { + if (is_scalar (dst_type)) { + return error (dst, "empty scalar initializer"); + } + src = new_nil_expr (); + } if (src->type == ex_compound) { src = initialized_temp_expr (dst_type, src); if (src->type == ex_error) { From d418be31e6d1362cdbaa4b980207817172f0fcf2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 20:55:21 +0900 Subject: [PATCH 301/444] [qfcc] Tweak ivar test to check old bug It turns out that assigning nil to an ivar struct does not work (should, of course). --- tools/qfcc/test/ivar-struct-return.r | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qfcc/test/ivar-struct-return.r b/tools/qfcc/test/ivar-struct-return.r index 5e212a5ba..a3883b81c 100644 --- a/tools/qfcc/test/ivar-struct-return.r +++ b/tools/qfcc/test/ivar-struct-return.r @@ -17,6 +17,7 @@ typedef struct Point Point; @implementation Object -(Point) origin { + origin = nil; return origin; } @end From 6ca85d770d471a9212cff42b8981d3222328c052 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 22:48:55 +0900 Subject: [PATCH 302/444] [gamecode] Add memset instructions --- include/QF/pr_comp.h | 3 +++ libs/gamecode/pr_exec.c | 23 ++++++++++++++++++++++- libs/gamecode/pr_opcode.c | 10 ++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 6458d3913..80b9e963d 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -395,6 +395,9 @@ typedef enum { OP_MOD_I, OP_MOD_F, OP_MOD_D, + + OP_MEMSET, + OP_MEMSETI, } pr_opcode_e; #define OP_BREAK 0x8000 diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index d673b7d1c..718e2b09a 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -404,6 +404,14 @@ check_stack_pointer (progs_t *pr, pointer_t stack, int size) } } +static inline void +pr_memset (pr_type_t *dst, int val, int count) +{ + while (count-- > 0) { + (*dst++).integer_var = val; + } +} + /* PR_ExecuteProgram @@ -1608,7 +1616,20 @@ op_call: pr->pr_globals + OPA.integer_var, st->b * 4); break; - + case OP_MEMSET: + if (pr_boundscheck->int_val) { + PR_BoundsCheckSize (pr, OPC.pointer_var, OPB.uinteger_var); + } + pr_memset (pr->pr_globals + OPC.pointer_var, OPA.integer_var, + OPB.integer_var); + break; + case OP_MEMSETI: + if (pr_boundscheck->int_val) { + PR_BoundsCheckSize (pr, OPC.pointer_var, st->b); + } + pr_memset (pr->pr_globals + OPC.pointer_var, OPA.integer_var, + st->b); + break; case OP_GE_D: OPC.float_var = OPA_double_var >= OPB_double_var; break; diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index 853176925..dc3a59fb9 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -1183,6 +1183,16 @@ VISIBLE const opcode_t pr_opcodes[] = { PROG_VERSION, "%Ga, %Gb, %Gc", }, + {"", "memset", OP_MEMSET, true, + ev_integer, ev_integer, ev_pointer, + PROG_VERSION, + "%Ga, %Gb, %Gc", + }, + {"", "memseti", OP_MEMSETI, true, + ev_integer, ev_short, ev_pointer, + PROG_VERSION, + "%Ga, %Gb, %Gc", + }, {"", "push.s", OP_PUSH_S, false, ev_string, ev_invalid, ev_invalid, From be5f11f33a34d9db9663d35da65c31a7badb00de Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 22:57:20 +0900 Subject: [PATCH 303/444] [qfcc] Support the new memset instructions --- tools/qfcc/include/expr.h | 11 +++++++++++ tools/qfcc/source/expr.c | 32 ++++++++++++++++++++++++++++++++ tools/qfcc/source/expr_assign.c | 1 + tools/qfcc/source/statements.c | 30 +++++++++++++++++++++++++++++- 4 files changed, 73 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 008313a5a..322298da4 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -56,6 +56,7 @@ typedef enum { ex_nil, ///< umm, nil, null. nuff said (0 of any type) ex_value, ///< constant value (::ex_value_t) ex_compound, ///< compound initializer + ex_memset, ///< memset needs three params... } expr_type; /** Binary and unary expressions. @@ -142,6 +143,12 @@ typedef struct { struct expr_s *e; } ex_bool_t; +typedef struct ex_memset_s { + struct expr_s *dst; + struct expr_s *val; + struct expr_s *count; +} ex_memset_t; + /** State expression used for think function state-machines. State expressions are of the form [framenum, nextthink] @@ -225,6 +232,7 @@ typedef struct expr_s { ex_vector_t vector; ///< vector expression list ex_value_t *value; ///< constant value element_chain_t compound; ///< compound initializer + ex_memset_t memset; ///< memset expr params } e; } expr_t; @@ -640,6 +648,9 @@ expr_t *new_param_expr (struct type_s *type, int num); expr_t *new_move_expr (expr_t *e1, expr_t *e2, struct type_s *type, int indirect); +expr_t *new_memset_expr (expr_t *dst, expr_t *val, expr_t *count); + + /** Convert a name to an expression of the appropriate type. Converts the expression in-place. If the exprssion is not a name diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 4b0317d53..47f398f46 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -214,6 +214,7 @@ get_type (expr_t *e) convert_name (e); switch (e->type) { case ex_labelref: + case ex_memset: return &type_void; case ex_label: case ex_error: @@ -436,6 +437,13 @@ copy_expr (expr_t *e) append_element (n, new_element (i->expr, i->symbol)); } return n; + case ex_memset: + n = new_expr (); + *n = *e; + n->e.memset.dst = copy_expr (e->e.memset.dst); + n->e.memset.val = copy_expr (e->e.memset.val); + n->e.memset.count = copy_expr (e->e.memset.count); + return n; } internal_error (e, "invalid expression"); } @@ -1171,6 +1179,27 @@ new_move_expr (expr_t *e1, expr_t *e2, type_t *type, int indirect) return e; } +expr_t * +new_memset_expr (expr_t *dst, expr_t *val, expr_t *count) +{ + expr_t *e; + if (!is_pointer (get_type (dst))) { + return error (dst, "incorrect destination type for memset"); + } + if (!is_scalar (get_type (val))) { + return error (val, "memset value must be a scalar"); + } + if (!is_integral (get_type (count))) { + return error (val, "memset count must be integral"); + } + e = new_expr (); + e->type = ex_memset; + e->e.memset.dst = dst; + e->e.memset.val = val; + e->e.memset.count = count; + return e; +} + expr_t * append_expr (expr_t *block, expr_t *e) { @@ -1508,6 +1537,7 @@ unary_expr (int op, expr_t *e) case ex_labelref: case ex_state: case ex_compound: + case ex_memset: internal_error (e, 0); case ex_uexpr: if (e->e.expr.op == '-') @@ -1575,6 +1605,7 @@ unary_expr (int op, expr_t *e) case ex_labelref: case ex_state: case ex_compound: + case ex_memset: internal_error (e, 0); case ex_bool: return new_bool_expr (e->e.bool.false_list, @@ -1641,6 +1672,7 @@ unary_expr (int op, expr_t *e) case ex_labelref: case ex_state: case ex_compound: + case ex_memset: internal_error (e, 0); case ex_uexpr: if (e->e.expr.op == '~') diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index a6b3f81f0..0ada7160b 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -123,6 +123,7 @@ check_valid_lvalue (expr_t *expr) return check_valid_lvalue (expr->e.expr.e1); } break; + case ex_memset: case ex_compound: case ex_state: case ex_bool: diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 517fcc7b3..1bb2bc2ba 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1438,6 +1438,32 @@ statement_uexpr (sblock_t *sblock, expr_t *e) return sblock; } +static sblock_t * +statement_memset (sblock_t *sblock, expr_t *e) +{ + expr_t *dst = e->e.memset.dst; + expr_t *val = e->e.memset.val; + expr_t *count = e->e.memset.count; + const char *opcode = ""; + statement_t *s; + + if (is_constant (count)) { + if (is_integer (get_type (count)) + && (unsigned) expr_integer (count) < 0x10000) { + count = new_short_expr (expr_integer (count)); + } + if (is_uinteger (get_type (count)) && expr_integer (count) < 0x10000) { + count = new_short_expr (expr_uinteger (count)); + } + } + s = new_statement (st_move, opcode, e); + sblock = statement_subexpr (sblock, dst, &s->opc); + sblock = statement_subexpr (sblock, count, &s->opb); + sblock = statement_subexpr (sblock, val, &s->opa); + sblock_add_statement (sblock, s); + return sblock; +} + static sblock_t * statement_nonexec (sblock_t *sblock, expr_t *e) { @@ -1463,10 +1489,12 @@ statement_slist (sblock_t *sblock, expr_t *e) statement_nonexec, // ex_vector statement_nonexec, // ex_nil statement_nonexec, // ex_value + 0, // ex_compound + statement_memset, }; for (/**/; e; e = e->next) { - if (e->type > ex_value) + if (e->type > ex_memset) internal_error (e, "bad expression type"); sblock = sfuncs[e->type] (sblock, e); } From 5d349efe782f777181818e81de8f65f413f8c356 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 22:57:48 +0900 Subject: [PATCH 304/444] [qfcc] Delay conversion of nil in assignments It's not possible to take the address of constants (at this stage) and trying to use a move instruction with .zero as source would result in the VM complaining about null pointer access when bounds checking is on. Thus, don't convert a nil source expression until it is known to be safe, and use memset when it is not. --- tools/qfcc/include/expr.h | 1 + tools/qfcc/source/expr.c | 6 ++++++ tools/qfcc/source/expr_assign.c | 37 +++++++++++++++++++++++---------- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 322298da4..9879ee810 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -595,6 +595,7 @@ int is_logic (int op) __attribute__((const)); int has_function_call (expr_t *e) __attribute__((pure)); +int is_nil (expr_t *e) __attribute__((pure)); int is_string_val (expr_t *e) __attribute__((pure)); int is_float_val (expr_t *e) __attribute__((pure)); int is_vector_val (expr_t *e) __attribute__((pure)); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 47f398f46..2d419c20f 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -882,6 +882,12 @@ constant_expr (expr_t *e) return new; } +int +is_nil (expr_t *e) +{ + return e->type == ex_nil; +} + int is_string_val (expr_t *e) { diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 0ada7160b..07a838b13 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -345,21 +345,22 @@ assign_expr (expr_t *dst, expr_t *src) } src_type = get_type (src); } - if (!is_void (dst_type) && src->type == ex_nil) { + if (!is_struct (dst_type) && is_nil (src)) { // nil is a type-agnostic 0 // FIXME: assignment to compound types? error or memset? src_type = dst_type; convert_nil (src, src_type); } - if ((expr = check_types_compatible (dst, src))) { - // expr might be a valid expression, but if so, check_types_compatible - // will take care of everything - return expr; - } - - if ((expr = assign_vector_expr (dst, src))) { - return expr; + if (!is_nil (src)) { + if ((expr = check_types_compatible (dst, src))) { + // expr might be a valid expression, but if so, + // check_types_compatible will take care of everything + return expr; + } + if ((expr = assign_vector_expr (dst, src))) { + return expr; + } } if (is_indirect (dst) && is_indirect (src)) { @@ -381,8 +382,18 @@ assign_expr (expr_t *dst, expr_t *src) debug (dst, "here"); if (is_struct (dst_type)) { dst = address_expr (dst, 0, 0); - src = address_expr (src, 0, 0); - return new_move_expr (dst, src, dst_type, 1); + if (is_nil (src)) { + int size = type_size (dst_type); + return new_memset_expr (dst, new_integer_expr (0), + new_integer_expr (size)); + } else { + src = address_expr (src, 0, 0); + return new_move_expr (dst, src, dst_type, 1); + } + } + if (is_nil (src)) { + src_type = dst_type; + convert_nil (src, src_type); } if (dst->type == ex_expr) { if (get_type (dst->e.expr.e1) == &type_entity) { @@ -420,6 +431,10 @@ assign_expr (expr_t *dst, expr_t *src) } } + if (is_nil (src)) { + src_type = dst_type; + convert_nil (src, src_type); + } if (is_struct (dst_type)) { return new_move_expr (dst, src, dst_type, 0); } From e4caf50ee1aeb2a54fdaacf57cbdf6dc5e1db889 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 11 Mar 2020 23:52:12 +0900 Subject: [PATCH 305/444] [qfcc] Update switch tables for compound initializers Forgot to do a full test build (Machine.r found it) --- tools/qfcc/source/def.c | 2 ++ tools/qfcc/source/statements.c | 6 +++--- tools/qfcc/source/switch.c | 6 ++++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index f690f2c3b..d642261ef 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -371,6 +371,8 @@ init_elements (struct def_s *def, expr_t *eles) dummy.offset = def->offset + element->offset; g = D_POINTER (pr_type_t, &dummy); if (c->type == ex_labelref) { + // reloc_def_* use only the def's offset and space, so dummy + // is ok reloc_def_op (c->e.labelref.label, &dummy); continue; } else if (c->type == ex_value) { diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 1bb2bc2ba..0b27803a1 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -536,7 +536,7 @@ statement_get_targetlist (statement_t *s) sblock_t **target_list; int count = 0, i; def_t *table = 0; - expr_t *e; + element_t *e; if (statement_is_cond (s)) { count = 1; @@ -555,9 +555,9 @@ statement_get_targetlist (statement_t *s) } else if (statement_is_jumpb (s)) { if (table->alias) internal_error (0, "aliased jump table"); - e = table->initializer->e.block.head; //FIXME check!!! + e = table->initializer->e.compound.head; //FIXME check!!! for (i = 0; i < count; e = e->next, i++) - target_list[i] = e->e.labelref.label->dest; + target_list[i] = e->expr->e.labelref.label->dest; } return target_list; } diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index 7e76ef6f4..967a7b73f 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -337,11 +337,13 @@ build_switch (expr_t *sw, case_node_t *tree, int op, expr_t *sw_val, const char *table_name = new_label_name (); int i; expr_t *range = binary_expr ('-', tree->high, tree->low); + expr_t *label; - table_init = new_block_expr (); + table_init = new_compound_init (); for (i = 0; i <= high - low; i++) { tree->labels[i]->e.label.used++; - append_expr (table_init, address_expr (tree->labels[i], 0, 0)); + label = address_expr (tree->labels[i], 0, 0); + append_element (table_init, new_element (label, 0)); } table_sym = new_symbol_type (table_name, array_type (&type_integer, From 0d4c7ba10fa8d7df5349e881128bfb78d47835d4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 12 Mar 2020 00:52:42 +0900 Subject: [PATCH 306/444] [cl_menu] Update plist usage of obj_msg_sendv Wonder if there's anywhere else... --- ruamoko/cl_menu/plistmenu.r | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ruamoko/cl_menu/plistmenu.r b/ruamoko/cl_menu/plistmenu.r index bdece6082..00d2a61e0 100644 --- a/ruamoko/cl_menu/plistmenu.r +++ b/ruamoko/cl_menu/plistmenu.r @@ -58,6 +58,7 @@ class_from_plist (PLDictionary *pldict) return ret; } obj = [class alloc]; + params[0].pointer_val = obj; messages = (PLArray*) [pldict getObjectForKey:"Messages"]; message_count = [messages count]; @@ -65,9 +66,10 @@ class_from_plist (PLDictionary *pldict) msg = (PLArray*) [messages getObjectAtIndex:i]; selname = [(PLString*) [msg getObjectAtIndex:0] string]; sel = sel_get_uid (selname); - va_list.count = [msg count] - 1; - for (j = 0; j < va_list.count; j++) { - paramstr = [(PLString*) [msg getObjectAtIndex:j + 1] string]; + params[1].pointer_val = sel; + va_list.count = [msg count] + 1; + for (j = 2; j < va_list.count; j++) { + paramstr = [(PLString*) [msg getObjectAtIndex:j - 1] string]; switch (str_mid (paramstr, 0, 1)) { case "\"": va_list.list[j].string_val = str_mid (paramstr, 1, -1); From 21a8559674ac3cb72b9a8a0c13dd3cadb254701e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 12 Mar 2020 19:30:54 +0900 Subject: [PATCH 307/444] [qfcc] Improve handling of nil assignments Especially when they result in using memset. --- tools/qfcc/include/expr.h | 3 ++- tools/qfcc/source/expr.c | 11 +++++------ tools/qfcc/source/expr_assign.c | 15 +++++++++------ 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 9879ee810..a8a1a98f2 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -147,6 +147,7 @@ typedef struct ex_memset_s { struct expr_s *dst; struct expr_s *val; struct expr_s *count; + struct type_s *type; } ex_memset_t; /** State expression used for think function state-machines. @@ -649,7 +650,7 @@ expr_t *new_param_expr (struct type_s *type, int num); expr_t *new_move_expr (expr_t *e1, expr_t *e2, struct type_s *type, int indirect); -expr_t *new_memset_expr (expr_t *dst, expr_t *val, expr_t *count); +expr_t *new_memset_expr (expr_t *dst, expr_t *val, struct type_s *type); /** Convert a name to an expression of the appropriate type. diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 2d419c20f..922d47921 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -214,8 +214,9 @@ get_type (expr_t *e) convert_name (e); switch (e->type) { case ex_labelref: - case ex_memset: return &type_void; + case ex_memset: + return e->e.memset.type; case ex_label: case ex_error: case ex_compound: @@ -1186,7 +1187,7 @@ new_move_expr (expr_t *e1, expr_t *e2, type_t *type, int indirect) } expr_t * -new_memset_expr (expr_t *dst, expr_t *val, expr_t *count) +new_memset_expr (expr_t *dst, expr_t *val, type_t *type) { expr_t *e; if (!is_pointer (get_type (dst))) { @@ -1195,14 +1196,12 @@ new_memset_expr (expr_t *dst, expr_t *val, expr_t *count) if (!is_scalar (get_type (val))) { return error (val, "memset value must be a scalar"); } - if (!is_integral (get_type (count))) { - return error (val, "memset count must be integral"); - } e = new_expr (); e->type = ex_memset; e->e.memset.dst = dst; e->e.memset.val = val; - e->e.memset.count = count; + e->e.memset.count = new_integer_expr (type_size (type)); + e->e.memset.type = type; return e; } diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 07a838b13..f0dca6474 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -286,6 +286,12 @@ is_indirect (expr_t *e) return is_const_ptr (e->e.expr.e1); } +static __attribute__((pure)) int +is_memset (expr_t *e) +{ + return e->type == ex_memset; +} + expr_t * assign_expr (expr_t *dst, expr_t *src) { @@ -305,7 +311,7 @@ assign_expr (expr_t *dst, expr_t *src) internal_error (dst, "dst_type broke in assign_expr"); } - if (src) { + if (src && !is_memset (src)) { convert_name (src); if (src->type == ex_error) { return src; @@ -316,7 +322,7 @@ assign_expr (expr_t *dst, expr_t *src) return expr; } } else { - if (is_scalar (dst_type)) { + if (!is_memset (src) && is_scalar (dst_type)) { return error (dst, "empty scalar initializer"); } src = new_nil_expr (); @@ -347,7 +353,6 @@ assign_expr (expr_t *dst, expr_t *src) } if (!is_struct (dst_type) && is_nil (src)) { // nil is a type-agnostic 0 - // FIXME: assignment to compound types? error or memset? src_type = dst_type; convert_nil (src, src_type); } @@ -383,9 +388,7 @@ assign_expr (expr_t *dst, expr_t *src) if (is_struct (dst_type)) { dst = address_expr (dst, 0, 0); if (is_nil (src)) { - int size = type_size (dst_type); - return new_memset_expr (dst, new_integer_expr (0), - new_integer_expr (size)); + return new_memset_expr (dst, new_integer_expr (0), dst_type); } else { src = address_expr (src, 0, 0); return new_move_expr (dst, src, dst_type, 1); From 08b7064a3f647aa98d8a6bdd351b1be8be790327 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 12 Mar 2020 19:32:09 +0900 Subject: [PATCH 308/444] [ruamoko] Set pr_argc before calling error methods Builtins calling ruamoko code need to be careful of the arg count in case the ruamoko function uses varargs. --- libs/ruamoko/rua_obj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/ruamoko/rua_obj.c b/libs/ruamoko/rua_obj.c index c30683d0e..854341b56 100644 --- a/libs/ruamoko/rua_obj.c +++ b/libs/ruamoko/rua_obj.c @@ -1289,6 +1289,7 @@ rua___obj_forward (progs_t *pr) P_POINTER (pr, 0) = PR_SetPointer (pr, obj); P_POINTER (pr, 1) = PR_SetPointer (pr, err_sel); P_POINTER (pr, 2) = PR_SetPointer (pr, sel); + pr->pr_argc = 3; PR_CallFunction (pr, imp); return; } @@ -1306,6 +1307,7 @@ rua___obj_forward (progs_t *pr) P_POINTER (pr, 0) = PR_SetPointer (pr, obj); P_POINTER (pr, 1) = PR_SetPointer (pr, err_sel); P_POINTER (pr, 2) = PR_SetTempString (pr, probj->msg->str); + pr->pr_argc = 3; PR_CallFunction (pr, imp); return; } From bbfd498b74f1325530caa9228ca3f357884e18ab Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 12 Mar 2020 19:34:18 +0900 Subject: [PATCH 309/444] [qfcc] Handle compound and memset dot nodes compound is currently not very informative, but it's better than "bad expression type" --- tools/qfcc/source/dot_expr.c | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index f8601c6ff..6b1cb2428 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -506,6 +506,29 @@ print_value (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) e->line); } +static void +print_compound (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + dasprintf (dstr, "%*se_%p [label=\"compound init\"];\n", indent, "", e); +} + +static void +print_memset (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + expr_t *dst = e->e.memset.dst; + expr_t *val = e->e.memset.val; + expr_t *count = e->e.memset.count; + _print_expr (dstr, dst, level, id, next); + _print_expr (dstr, val, level, id, next); + _print_expr (dstr, count, level, id, next); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, dst); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, val); + dasprintf (dstr, "%*se_%p -> \"e_%p\";\n", indent, "", e, count); + dasprintf (dstr, "%*se_%p [label=\"memset\"];\n", indent, "", e); +} + static void _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { @@ -523,6 +546,8 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) print_vector, print_nil, print_value, + print_compound, + print_memset, }; int indent = level * 2 + 2; @@ -534,7 +559,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) return; e->printid = id; - if ((int) e->type < 0 || e->type > ex_value) { + if ((int) e->type < 0 || e->type > ex_memset) { dasprintf (dstr, "%*se_%p [label=\"(bad expr type)\\n%d\"];\n", indent, "", e, e->line); return; From c7435830031df704cf3a9ca91e15b654e6727e9d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 12 Mar 2020 19:35:32 +0900 Subject: [PATCH 310/444] [qfcc] Fix a comment --- tools/qfcc/source/class.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 50ab5dcd7..647a64716 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -722,7 +722,7 @@ emit_ivar_list_item (def_t *def, void *data, int index) defspace_t *space; #if 0 - //FIXME the type is dynamic, so need a way to pass it before it cn be + //FIXME the type is dynamic, so need a way to pass it before it can be //checked if (def->type != &XXX) internal_error (0, "%s: expected XXX def", From 65b48c734c2efc1194e2cdec4469fd7d35043cf8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 12 Mar 2020 19:36:15 +0900 Subject: [PATCH 311/444] [qfcc} Mark some more functions as pure I guess gcc doesn't consider recursive functions as pure, but marking get_type as pure had a slight ripple effect. --- tools/qfcc/include/expr.h | 4 ++-- tools/qfcc/source/switch.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index a8a1a98f2..d6b71d2b1 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -263,7 +263,7 @@ extern expr_t *local_expr; \return Pointer to the type description, or null if the expression type (expr_t::type) is inappropriate. */ -struct type_s *get_type (expr_t *e); +struct type_s *get_type (expr_t *e) __attribute__((pure)); /** Get the basic type code of the expression result. @@ -271,7 +271,7 @@ struct type_s *get_type (expr_t *e); \return Pointer to the type description, or ev_type_count if get_type() returns null. */ -etype_t extract_type (expr_t *e); +etype_t extract_type (expr_t *e) __attribute__((pure)); /** Create a new expression node. diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index 967a7b73f..6c00279a0 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -85,7 +85,7 @@ get_hash (const void *_cl, void *unused) return Hash_Buffer (&val->v, sizeof (val->v)) + val->lltype; } -static int +static int __attribute__((pure)) compare (const void *_cla, const void *_clb, void *unused) { case_label_t *cla = (case_label_t *) _cla; From 4c2a6c9eb218ee219531d776e4da0e8f3807340f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 12 Mar 2020 19:37:55 +0900 Subject: [PATCH 312/444] [qfcc] Allow implicit demotion in initializer elements Notably, implicit double constants (no adorning d) being used to initialize float struct members. --- tools/qfcc/source/def.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index d642261ef..751bac7f5 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -380,6 +380,10 @@ init_elements (struct def_s *def, expr_t *eles) && is_float (element->type)) { convert_int (c); } + if (is_double (get_type (c)) && is_float (element->type) + && c->implicit) { + convert_double (c); + } if (get_type (c) != element->type) { error (c, "type mismatch in initializer"); continue; From f45484236181ad4c6a2a46f017852793c6c2d2c1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 12 Mar 2020 19:47:09 +0900 Subject: [PATCH 313/444] [qfcc] Add breaking assignment chain test This bug drove me nuts for several hours until I figured out what was going on. The assignment sub-tree is being generated, then lost. It works for simple assignments because a = b = c -> (= a (= b c)), but for complex assignments (those that require move or memset), a = b = c -> (b = c) (a = c) but nothing points to (b = c). The cause is using binary expressions to store assignments. --- tools/qfcc/test/Makefile.am | 10 ++++ tools/qfcc/test/assignchain.r | 89 +++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 tools/qfcc/test/assignchain.r diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index f4d31a2c9..ceb32813f 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -31,6 +31,7 @@ fail_bins= test_progs_dat=\ address-cast.dat \ alignment.dat \ + assignchain.dat \ anonstruct.dat \ chewed-alias.dat \ chewed-return.dat \ @@ -132,6 +133,15 @@ anonstruct.run: Makefile build-run include ./$(DEPDIR)/anonstruct.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/anonstruct.Qo +assignchain_dat_SOURCES=assignchain.r +assignchain_obj=$(assignchain_dat_SOURCES:.r=.qfo) +assignchain.dat$(EXEEXT): $(assignchain_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(assignchain_obj) +assignchain.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/assignchain.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/assignchain.Qo + chewed_alias_dat_SOURCES=chewed-alias.r chewed_alias_obj=$(chewed_alias_dat_SOURCES:.r=.qfo) chewed-alias.dat$(EXEEXT): $(chewed_alias_obj) $(QFCC_DEP) diff --git a/tools/qfcc/test/assignchain.r b/tools/qfcc/test/assignchain.r new file mode 100644 index 000000000..1e9b8eb8d --- /dev/null +++ b/tools/qfcc/test/assignchain.r @@ -0,0 +1,89 @@ +#include "test-harness.h" + +typedef struct foo { + int x; + float y; +} foo; + +int x, y; +int z = 42; +foo bar, baz; +foo foo_init = { 5, 6.25 }; + +int test_simple_global (void) +{ + int ret = 0; + x = y = z; + if (x != z || y != z) { + printf ("test_simple_global: x=%d y=%d z=%d\n", x, y, z); + ret |= 1; + } + return ret; +} + +int test_struct_global (void) +{ + int ret = 0; + bar = baz = foo_init; + if (bar.x != foo_init.x || bar.y != foo_init.y) { + printf ("test_struct: bar={%d %g} foo_init={%d %g}\n", + bar.x, bar.y, foo_init.x, foo_init.y); + ret |= 1; + } + if (baz.x != foo_init.x || baz.y != foo_init.y) { + printf ("test_struct: baz={%d %g} foo_init={%d %g}\n", + baz.x, baz.y, foo_init.x, foo_init.y); + ret |= 1; + } + bar = baz = nil; + if (bar.x || baz.x || bar.y || baz.y) { + printf ("test_struct: bar={%d %g} baz={%d %g}\n", + bar.x, bar.y, baz.x, baz.y); + ret |= 1; + } + return ret; +} + +int test_simple_pointer (int *x, int *y) +{ + int ret = 0; + *x = *y = z; + if (*x != z || *y != z) { + printf ("test_simple_global: *x=%d *y=%d z=%d\n", *x, *y, z); + ret |= 1; + } + return ret; +} + +int test_struct_pointer (foo *bar, foo *baz) +{ + int ret = 0; + *bar = *baz = foo_init; + if (bar.x != foo_init.x || bar.y != foo_init.y) { + printf ("test_struct: bar={%d %g} foo_init={%d %g}\n", + bar.x, bar.y, foo_init.x, foo_init.y); + ret |= 1; + } + if (baz.x != foo_init.x || baz.y != foo_init.y) { + printf ("test_struct: baz={%d %g} foo_init={%d %g}\n", + baz.x, baz.y, foo_init.x, foo_init.y); + ret |= 1; + } + *bar = *baz = nil; + if (bar.x || baz.x || bar.y || baz.y) { + printf ("test_struct: bar={%d %g} baz={%d %g}\n", + bar.x, bar.y, baz.x, baz.y); + ret |= 1; + } + return ret; +} + +int main () +{ + int ret = 0; + ret |= test_simple_global (); + ret |= test_struct_global (); + ret |= test_simple_pointer (&x, &y); + ret |= test_struct_pointer (&bar, &baz); + return ret; +} From 9c5fac2226e1ec22da8a7665451c5ce15e5c75d5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 12 Mar 2020 19:53:15 +0900 Subject: [PATCH 314/444] [qfcc] Catch another assignment chain failure --- tools/qfcc/test/assignchain.r | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/qfcc/test/assignchain.r b/tools/qfcc/test/assignchain.r index 1e9b8eb8d..454279f45 100644 --- a/tools/qfcc/test/assignchain.r +++ b/tools/qfcc/test/assignchain.r @@ -69,6 +69,8 @@ int test_struct_pointer (foo *bar, foo *baz) baz.x, baz.y, foo_init.x, foo_init.y); ret |= 1; } + *bar = foo_init; + *baz = foo_init; *bar = *baz = nil; if (bar.x || baz.x || bar.y || baz.y) { printf ("test_struct: bar={%d %g} baz={%d %g}\n", From 9c06b227199db67c73e7f08573fc3f56878d8bdd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 01:59:35 +0900 Subject: [PATCH 315/444] [qfcc] Fix segfault when assigning {} --- tools/qfcc/source/expr_assign.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index f0dca6474..aa759b88d 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -322,7 +322,7 @@ assign_expr (expr_t *dst, expr_t *src) return expr; } } else { - if (!is_memset (src) && is_scalar (dst_type)) { + if (!src && is_scalar (dst_type)) { return error (dst, "empty scalar initializer"); } src = new_nil_expr (); From 7f9a415cbcb84d56bb2950f4f21aec0692a2e22f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 02:09:55 +0900 Subject: [PATCH 316/444] [qwaq] Get DrawBuffer and TextContext working Especially blitting whole regions. Partial regions not tested yet. --- ruamoko/qwaq/qwaq-curses.c | 18 ++++++++++++++---- ruamoko/qwaq/qwaq-draw.r | 2 +- ruamoko/qwaq/qwaq-rect.h | 2 ++ ruamoko/qwaq/qwaq-rect.r | 12 ++++++++++++ ruamoko/qwaq/qwaq-textcontext.r | 27 ++++++++++++++++++++++++++- ruamoko/qwaq/qwaq-window.h | 1 + ruamoko/qwaq/qwaq-window.r | 5 +++++ 7 files changed, 61 insertions(+), 6 deletions(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 8ba194619..3c1714e35 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -291,12 +291,18 @@ get_panel (qwaq_resources_t *res, const char *name, int handle) return panel; } +//XXX goes away with threads +static void process_commands (qwaq_resources_t *); +static void process_input (qwaq_resources_t *); static int acquire_string (qwaq_resources_t *res) { int string_id = -1; // XXX add locking and loop for available + if (!RB_DATA_AVAILABLE (res->string_ids)) { + process_commands(res); + } if (RB_DATA_AVAILABLE (res->string_ids)) { RB_READ_DATA (res->string_ids, &string_id, 1); } @@ -338,9 +344,6 @@ qwaq_submit_result (qwaq_resources_t *res, const int *result, unsigned len) } } -//XXX goes away with threads -static void process_commands (qwaq_resources_t *); -static void process_input (qwaq_resources_t *); static void qwaq_wait_result (qwaq_resources_t *res, int *result, int cmd, unsigned len) { @@ -628,11 +631,18 @@ cmd_mvwblit_line (qwaq_resources_t *res) int chs_id = RB_PEEK_DATA (res->command_queue, 5); int len = RB_PEEK_DATA (res->command_queue, 6); int *chs = (int *) res->strings[chs_id].str; + int save_x; + int save_y; window_t *window = get_window (res, __FUNCTION__, window_id); + getyx (window->win, save_y, save_x); for (int i = 0; i < len; i++) { - mvwaddch (window->win, y, x, chs[i]); + Sys_Printf(" %d", chs[i]); + mvwaddch (window->win, y, x + i, chs[i]); } + Sys_Printf("\n"); + wmove (window->win, save_y, save_x); + release_string (res, chs_id); } static void diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r index 66e266a50..d1cdc950d 100644 --- a/ruamoko/qwaq/qwaq-draw.r +++ b/ruamoko/qwaq/qwaq-draw.r @@ -33,7 +33,7 @@ - blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect { Extent srcSize = srcBuffer.size; - Rect r = { {}, srcBuffer.size }; + Rect r = { {}, size }; Rect t = { pos, rect.extent }; t = clipRect (r, t); diff --git a/ruamoko/qwaq/qwaq-rect.h b/ruamoko/qwaq/qwaq-rect.h index 9d4fc51e4..d1ba8719b 100644 --- a/ruamoko/qwaq/qwaq-rect.h +++ b/ruamoko/qwaq/qwaq-rect.h @@ -18,6 +18,8 @@ typedef struct Rect_s { #ifdef __QFCC__ @extern Rect makeRect (int xpos, int ypos, int xlen, int ylen); +@extern Point makePoint (int x, int y); +@extern Extent makeExtent (int width, int height); //XXX will not work if point or rect point to a local variabl @extern int rectContainsPoint (Rect *rect, Point *point); @extern Rect getwrect (struct window_s *window); diff --git a/ruamoko/qwaq/qwaq-rect.r b/ruamoko/qwaq/qwaq-rect.r index 6ee5c7df5..8813c84ee 100644 --- a/ruamoko/qwaq/qwaq-rect.r +++ b/ruamoko/qwaq/qwaq-rect.r @@ -29,6 +29,18 @@ makeRect (int xpos, int ypos, int xlen, int ylen) return rect; } +Point makePoint (int x, int y) +{ + Point p = {x, y}; + return p; +} + +Extent makeExtent (int width, int height) +{ + Extent e = {width, height}; + return e; +} + int rectContainsPoint (Rect *rect, Point *point) { diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index 726872ccf..9a63e0681 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -43,6 +43,8 @@ static TextContext *screen; } window = create_window (rect.offset.x, rect.offset.y, rect.extent.width, rect.extent.height); + offset = {}; + size = rect.extent; return self; } @@ -60,13 +62,30 @@ static TextContext *screen; return window; } +-(Extent) size +{ + return size; +} + - blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect { Extent srcSize = [srcBuffer size]; - Rect r = { {}, srcSize }; + Rect r = { {}, size }; Rect t = { pos, rect.extent }; + wprintf (stdscr, "src: %p\n", srcBuffer); + wprintf (stdscr, "srcSize: %d %d\n", srcSize.width, srcSize.height); + wprintf (stdscr, "pos: %d %d\n", pos.x, pos.x); + wprintf (stdscr, "rect: %d %d %d %d\n", + rect.offset.x, rect.offset.y, + rect.extent.width, rect.extent.height); + wprintf (stdscr, "r: %d %d %d %d\n", + r.offset.x, r.offset.y, r.extent.width, r.extent.height); + wprintf (stdscr, "t: %d %d %d %d\n", + t.offset.x, t.offset.y, t.extent.width, t.extent.height); t = clipRect (r, t); + wprintf (stdscr, "t: %d %d %d %d\n", + t.offset.x, t.offset.y, t.extent.width, t.extent.height); if (t.extent.width < 0 || t.extent.height < 0) { return self; } @@ -80,6 +99,12 @@ static TextContext *screen; r.extent = size; rect = clipRect (r, rect); + wprintf (stdscr, "pos: %d %d\n", pos.x, pos.x); + wprintf (stdscr, "rect: %d %d %d %d\n", + rect.offset.x, rect.offset.y, + rect.extent.width, rect.extent.height); + wprintf (stdscr, "r: %d %d %d %d\n", + r.offset.x, r.offset.y, r.extent.width, r.extent.height); if (rect.extent.width < 0 || rect.extent.height < 0) { return self; } diff --git a/ruamoko/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h index c59a72f28..2e925c035 100644 --- a/ruamoko/qwaq/qwaq-window.h +++ b/ruamoko/qwaq/qwaq-window.h @@ -14,6 +14,7 @@ { Point point; // FIXME can't be local :( struct panel_s *panel; + DrawBuffer *buf; } +windowWithRect: (Rect) rect; -setBackground: (int) ch; diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 23d919648..5a0f328ff 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -21,6 +21,10 @@ buffer = [[TextContext alloc] initWithRect: rect]; textContext = buffer; panel = create_panel ([buffer window]); + buf = [DrawBuffer buffer: makeExtent (3, 3)]; + [buf mvaddstr: makePoint (0, 0), "XOX"]; + [buf mvaddstr: makePoint (0, 1), "OXO"]; + [buf mvaddstr: makePoint (0, 2), "XOX"]; return self; } @@ -108,6 +112,7 @@ } } } + [textContext blitFromBuffer: buf to: makePoint (6, 3) from: [buf rect]]; [self refresh]; return self; } From 3defe50be627b95a2c2740e65a4fe863c81c9307 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 02:37:25 +0900 Subject: [PATCH 317/444] [qwaq] Add printf builtin to ease debugging --- ruamoko/qwaq/qwaq-curses.c | 16 ++++++++++++++++ ruamoko/qwaq/qwaq-curses.h | 2 ++ ruamoko/qwaq/qwaq-textcontext.r | 2 ++ 3 files changed, 20 insertions(+) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 3c1714e35..f7ef86f54 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -1468,6 +1468,20 @@ bi_initialize (progs_t *pr) res->stdscr.win = stdscr; } +static void +bi_printf (progs_t *pr) +{ + const char *fmt = P_GSTRING (pr, 0); + int count = pr->pr_argc - 1; + pr_type_t **args = pr->pr_params + 1; + dstring_t *dstr = dstring_new (); + + PR_Sprintf (pr, dstr, "bi_printf", fmt, count, args); + if (dstr->str) + Sys_Printf (dstr->str, stdout); + dstring_delete (dstr); +} + static void bi_c_TextContext__is_initialized (progs_t *pr) { @@ -1674,6 +1688,8 @@ static builtin_t builtins[] = { {"wborder", bi_wborder, -1}, {"mvwblit_line", bi_mvwblit_line, -1}, + {"printf", bi_printf, -1}, + {"_c_TextContext__is_initialized", bi_c_TextContext__is_initialized, -1}, {"_c_TextContext__max_colors", bi_c_TextContext__max_colors, -1}, {"_c_TextContext__max_color_pairs", bi_c_TextContext__max_color_pairs, -1}, diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index b592ac84b..5e59c9f08 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -121,6 +121,8 @@ typedef struct panel_s *panel_t; @extern void wborder (window_t window, box_sides_t sides, box_corners_t corners); @extern void mvwblit_line (window_t window, int x, int y, int *wch, int len); + +@extern void printf(string fmt, ...); #endif #endif//__qwaq_curses_h diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index 9a63e0681..934fd597a 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -166,3 +166,5 @@ int curs_set (int visibility) = #0; int move (int x, int y) = #0; void wborder (window_t window, box_sides_t sides, box_corners_t corners) = #0; void mvwblit_line (window_t window, int x, int y, int *wch, int len) = #0; + +void printf(string fmt, ...) = #0; From d0f21ec2b40ce1cbfc8c4267fcd177323ac820ba Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 02:43:01 +0900 Subject: [PATCH 318/444] [qwaq] Add -refresh to TextContext This does the right thing in the presence of panels and dealing with stdscr. --- ruamoko/qwaq/qwaq-app.r | 7 +++++++ ruamoko/qwaq/qwaq-curses.c | 28 +++++++++++++++++++++++++--- ruamoko/qwaq/qwaq-screen.r | 2 -- ruamoko/qwaq/qwaq-textcontext.h | 1 + ruamoko/qwaq/qwaq-textcontext.r | 1 + 5 files changed, 34 insertions(+), 5 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 9d046a89f..fffe51c7b 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -68,6 +68,13 @@ arp_end (void) return self; } +-draw +{ + [super draw]; + [TextContext refresh]; + return self; +} + -handleEvent: (qwaq_event_t *) event { [screen handleEvent: event]; diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index f7ef86f54..eb9ee8024 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -1025,7 +1025,7 @@ bi_panel_window (progs_t *pr) } static void -bi_update_panels (progs_t *pr) +qwaq_update_panels (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); @@ -1033,9 +1033,14 @@ bi_update_panels (progs_t *pr) command[1] = CMD_SIZE(command); qwaq_submit_command (res, command); } +static void +bi_update_panels (progs_t *pr) +{ + qwaq_update_panels (pr); +} static void -bi_doupdate (progs_t *pr) +qwaq_doupdate (progs_t *pr) { qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); @@ -1043,6 +1048,11 @@ bi_doupdate (progs_t *pr) command[1] = CMD_SIZE(command); qwaq_submit_command (res, command); } +static void +bi_doupdate (progs_t *pr) +{ + qwaq_doupdate (pr); +} static void qwaq_mvwprintf (progs_t *pr, int window_id, int x, int y, const char *fmt, @@ -1594,12 +1604,23 @@ bi_i_TextContext__mvvprintf_ (progs_t *pr) qwaq_mvwvprintf (pr, pos->x, pos->y, window_id, fmt, args); } +static void +bi_c_TextContext__refresh (progs_t *pr) +{ + qwaq_update_panels (pr); + qwaq_doupdate (pr); +} + static void bi_i_TextContext__refresh (progs_t *pr) { int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; - qwaq_wrefresh (pr, window_id); + //qwaq_wrefresh (pr, window_id); + qwaq_update_panels (pr); + if (window_id == 1) { + qwaq_doupdate (pr); + } } static void @@ -1703,6 +1724,7 @@ static builtin_t builtins[] = { {"_i_TextContext__vprintf_", bi_i_TextContext__vprintf_, -1}, {"_i_TextContext__addch_", bi_i_TextContext__addch_, -1}, {"_i_TextContext__mvvprintf_", bi_i_TextContext__mvvprintf_, -1}, + {"_c_TextContext__refresh", bi_c_TextContext__refresh, -1}, {"_i_TextContext__refresh", bi_i_TextContext__refresh, -1}, {"_i_TextContext__mvaddch_", bi_i_TextContext__mvaddch_, -1}, {"_i_TextContext__bkgd_", bi_i_TextContext__bkgd_, -1}, diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index e34ddb7c9..5b2db43ce 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -36,9 +36,7 @@ -redraw { - update_panels (); [textContext refresh]; - [TextContext doupdate]; return self; } diff --git a/ruamoko/qwaq/qwaq-textcontext.h b/ruamoko/qwaq/qwaq-textcontext.h index 765f90572..c260b6f44 100644 --- a/ruamoko/qwaq/qwaq-textcontext.h +++ b/ruamoko/qwaq/qwaq-textcontext.h @@ -49,6 +49,7 @@ - (void) mvvprintf: (Point) pos, string mft, @va_list args; - (void) mvaddch: (Point) pos, int ch; - (void) refresh; ++ (void) refresh; - (void) bkgd: (int) ch; - (void) scrollok: (int) flag; - (void) border: (box_sides_t) sides, box_corners_t corners; diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index 934fd597a..8a4660dfa 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -124,6 +124,7 @@ static TextContext *screen; - (void) addch: (int) ch = #0; - (void) mvvprintf: (Point) pos, string mft, @va_list args = #0; - (void) refresh = #0; ++ (void) refresh = #0; - (void) mvaddch: (Point) pos, int ch = #0; - (void) bkgd: (int) ch = #0; - (void) scrollok: (int) flag = #0; From 1d3c8d8a6c906f86341b704c13a12cb33f4613e2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 02:46:25 +0900 Subject: [PATCH 319/444] [qwaq] Sort out mess around placement of getwrect --- ruamoko/qwaq/qwaq-curses.h | 4 ++++ ruamoko/qwaq/qwaq-rect.h | 1 - ruamoko/qwaq/qwaq-textcontext.r | 1 + ruamoko/qwaq/qwaq-view.r | 3 +-- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index 5e59c9f08..70af63f7c 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -18,6 +18,8 @@ typedef struct box_corners_s { } box_corners_t; #ifdef __QFCC__ +#include "qwaq-rect.h" + // names, order and comments lifted from ncurses.h typedef enum { /* VT100 symbols begin here */ @@ -122,6 +124,8 @@ typedef struct panel_s *panel_t; box_sides_t sides, box_corners_t corners); @extern void mvwblit_line (window_t window, int x, int y, int *wch, int len); +@extern Rect getwrect (struct window_s *window); + @extern void printf(string fmt, ...); #endif diff --git a/ruamoko/qwaq/qwaq-rect.h b/ruamoko/qwaq/qwaq-rect.h index d1ba8719b..7cd72e886 100644 --- a/ruamoko/qwaq/qwaq-rect.h +++ b/ruamoko/qwaq/qwaq-rect.h @@ -22,7 +22,6 @@ typedef struct Rect_s { @extern Extent makeExtent (int width, int height); //XXX will not work if point or rect point to a local variabl @extern int rectContainsPoint (Rect *rect, Point *point); -@extern Rect getwrect (struct window_s *window); @extern Rect clipRect (Rect clipRect, Rect rect); #endif diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index 8a4660dfa..848f3dfd5 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -167,5 +167,6 @@ int curs_set (int visibility) = #0; int move (int x, int y) = #0; void wborder (window_t window, box_sides_t sides, box_corners_t corners) = #0; void mvwblit_line (window_t window, int x, int y, int *wch, int len) = #0; +Rect getwrect (window_t window) = #0; void printf(string fmt, ...) = #0; diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 98cdf4429..19df51b9c 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -126,6 +126,5 @@ updateScreenCursor (View *view) [textContext mvaddch: pos, ch]; } -@end -Rect getwrect (window_t window) = #0; +@end From 45acbddb792490d25281f2504b955e4ef56a8d1e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 02:52:23 +0900 Subject: [PATCH 320/444] [qwaq] Make DrawBuffer and TextContext sizes available --- ruamoko/qwaq/qwaq-draw.h | 1 + ruamoko/qwaq/qwaq-draw.r | 5 +++++ ruamoko/qwaq/qwaq-textcontext.h | 3 ++- ruamoko/qwaq/qwaq-textcontext.r | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h index a0ef18dc1..5f7c7bc18 100644 --- a/ruamoko/qwaq/qwaq-draw.h +++ b/ruamoko/qwaq/qwaq-draw.h @@ -16,6 +16,7 @@ - (Extent) size; - (int *) buffer; +- (Rect) rect; - blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r index d1cdc950d..1311deb3c 100644 --- a/ruamoko/qwaq/qwaq-draw.r +++ b/ruamoko/qwaq/qwaq-draw.r @@ -29,6 +29,11 @@ { return buffer; } +- (Rect) rect +{ + Rect rect = { nil, size }; + return rect; +} - blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect { diff --git a/ruamoko/qwaq/qwaq-textcontext.h b/ruamoko/qwaq/qwaq-textcontext.h index c260b6f44..1fbcb4fbd 100644 --- a/ruamoko/qwaq/qwaq-textcontext.h +++ b/ruamoko/qwaq/qwaq-textcontext.h @@ -38,7 +38,8 @@ -initWithRect: (Rect) rect; -initWithWindow: (window_t) window; --(window_t) window; +- (window_t) window; +- (Extent) size; - blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index 848f3dfd5..dd94e34c1 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -33,6 +33,7 @@ static TextContext *screen; return nil; } window = stdscr; + rect = getwrect (window); return self; } From 047131a737992936c8f92e577b5c827ba4c7ee68 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 09:46:36 +0900 Subject: [PATCH 321/444] [qfcc] Check for compound init in message args I had forgotten message sending did its own type checking and thus needed to be updated for compound initializers in message parameters. --- tools/qfcc/source/method.c | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 676726a5c..5b818afad 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -706,20 +706,27 @@ method_check_params (method_t *method, expr_t *args) arg_list[i--] = a; for (i = 2; i < count; i++) { expr_t *e = arg_list[i]; - type_t *t = get_type (e); + type_t *arg_type = mtype->t.func.param_types[i]; + type_t *t; - if (!t) + if (e->type == ex_compound) { + e = expr_file_line (initialized_temp_expr (arg_type, e), e); + } + t = get_type (e); + if (!t) { return e; + } if (i < param_count) { - if (e->type != ex_nil) - if (!type_assignable (mtype->t.func.param_types[i], t)) { - err = param_mismatch (e, i - 1, method->name, - mtype->t.func.param_types[i], t); + if (e->type != ex_nil) { + if (!type_assignable (arg_type, t)) { + err = param_mismatch (e, i - 1, method->name, arg_type, t); } + } } else { - if (is_integer_val (e) && options.warnings.vararg_integer) + if (is_integer_val (e) && options.warnings.vararg_integer) { warning (e, "passing integer consant into ... function"); + } } } free (arg_list); From 8d10b0f4aab448cba66ef135218bdb9d46d3f721 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 09:58:52 +0900 Subject: [PATCH 322/444] [qfcc] Support compound initializers for return --- tools/qfcc/source/expr.c | 27 +++++++++++++++++---------- tools/qfcc/source/qc-parse.y | 6 ++---- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 922d47921..44d62a803 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1930,9 +1930,10 @@ expr_t * return_expr (function_t *f, expr_t *e) { type_t *t; + type_t *ret_type = f->sym->type->t.func.type; if (!e) { - if (f->sym->type->t.func.type != &type_void) { + if (ret_type != &type_void) { if (options.traditional) { if (options.warnings.traditional) warning (e, @@ -1950,25 +1951,31 @@ return_expr (function_t *f, expr_t *e) } } + if (e->type == ex_compound) { + e = expr_file_line (initialized_temp_expr (ret_type, e), e); + } + t = get_type (e); - if (e->type == ex_error) + if (e->type == ex_error) { return e; - if (f->sym->type->t.func.type == &type_void) { + } + if (ret_type == &type_void) { if (!options.traditional) return error (e, "returning a value for a void function"); if (options.warnings.traditional) warning (e, "returning a value for a void function"); } - if (e->type == ex_bool) - e = convert_from_bool (e, f->sym->type->t.func.type); - if (f->sym->type->t.func.type == &type_float && is_integer_val (e)) { + if (e->type == ex_bool) { + e = convert_from_bool (e, ret_type); + } + if (ret_type == &type_float && is_integer_val (e)) { convert_int (e); t = &type_float; } if (t == &type_void) { if (e->type == ex_nil) { - t = f->sym->type->t.func.type; + t = ret_type; convert_nil (e, t); if (e->type == ex_nil) return error (e, "invalid return type for NIL"); @@ -1980,7 +1987,7 @@ return_expr (function_t *f, expr_t *e) //FIXME does anything need to be done here? } } - if (!type_assignable (f->sym->type->t.func.type, t)) { + if (!type_assignable (ret_type, t)) { if (!options.traditional) return error (e, "type mismatch for return value of %s", f->sym->name); @@ -1988,8 +1995,8 @@ return_expr (function_t *f, expr_t *e) warning (e, "type mismatch for return value of %s", f->sym->name); } else { - if (f->sym->type->t.func.type != t) { - e = cast_expr (f->sym->type->t.func.type, e); + if (ret_type != t) { + e = cast_expr (ret_type, e); t = f->sym->type->t.func.type; } } diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index a4ce4c433..9fe7fbbd2 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -1267,10 +1267,8 @@ statement | error ';' { $$ = 0; yyerrok; } | compound_statement { $$ = $1; } | local_def { $$ = $1; } - | RETURN opt_expr ';' - { - $$ = return_expr (current_func, $2); - } + | RETURN opt_expr ';' { $$ = return_expr (current_func, $2); } + | RETURN compound_init ';' { $$ = return_expr (current_func, $2); } | BREAK ';' { $$ = 0; From 6001abbfdb03ce166b414e4b790844bbf5124bea Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 10:00:05 +0900 Subject: [PATCH 323/444] [qwaq] Use the now working compound init more --- ruamoko/qwaq/qwaq-rect.r | 6 ++---- ruamoko/qwaq/qwaq-window.r | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/ruamoko/qwaq/qwaq-rect.r b/ruamoko/qwaq/qwaq-rect.r index 8813c84ee..e0e3e5ee6 100644 --- a/ruamoko/qwaq/qwaq-rect.r +++ b/ruamoko/qwaq/qwaq-rect.r @@ -31,14 +31,12 @@ makeRect (int xpos, int ypos, int xlen, int ylen) Point makePoint (int x, int y) { - Point p = {x, y}; - return p; + return {x, y}; } Extent makeExtent (int width, int height) { - Extent e = {width, height}; - return e; + return {width, height}; } int diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 5a0f328ff..a4a69ee83 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -21,10 +21,10 @@ buffer = [[TextContext alloc] initWithRect: rect]; textContext = buffer; panel = create_panel ([buffer window]); - buf = [DrawBuffer buffer: makeExtent (3, 3)]; - [buf mvaddstr: makePoint (0, 0), "XOX"]; - [buf mvaddstr: makePoint (0, 1), "OXO"]; - [buf mvaddstr: makePoint (0, 2), "XOX"]; + buf = [DrawBuffer buffer: {3, 3}]; + [buf mvaddstr: {0, 0}, "XOX"]; + [buf mvaddstr: {0, 1}, "OXO"]; + [buf mvaddstr: {0, 2}, "XOX"]; return self; } From 6dfe37635d9a48ded032fb2a8692a975b30c999b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 14:56:56 +0900 Subject: [PATCH 324/444] [gamecode] Dump union contents The output is messy, but better than --- libs/gamecode/pr_debug.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index c102b46f8..89e5f6ba9 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -1139,8 +1139,22 @@ static void pr_debug_union_view (qfot_type_t *type, pr_type_t *value, void *_data) { __auto_type data = (pr_debug_data_t *) _data; + progs_t *pr = data->pr; dstring_t *dstr = data->dstr; + qfot_struct_t *strct = &type->t.strct; + dstring_appendstr (dstr, "{"); + for (int i = 0; i < strct->num_fields; i++) { + qfot_var_t *field = strct->fields + i; + qfot_type_t *val_type = &G_STRUCT (pr, qfot_type_t, field->type); + pr_type_t *val = value + field->offset; + dasprintf (dstr, "%s=", PR_GetString (pr, field->name)); + value_string (data, val_type, val); + if (i < strct->num_fields) { + dstring_appendstr (dstr, ", "); + } + } + dstring_appendstr (dstr, "}"); dstring_appendstr (dstr, ""); } From 087cee06be61498eee7b6b5aae4fa40005eae239 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 14:57:33 +0900 Subject: [PATCH 325/444] [gamecode] Use full precision for floating point values --- libs/gamecode/pr_debug.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 89e5f6ba9..0b76cb997 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -998,7 +998,7 @@ pr_debug_float_view (qfot_type_t *type, pr_type_t *value, void *_data) && value->uinteger_var != 0x80000000) { dasprintf (dstr, "<%08x>", value->integer_var); } else { - dasprintf (dstr, "%g", value->float_var); + dasprintf (dstr, "%.9g", value->float_var); } } @@ -1008,7 +1008,7 @@ pr_debug_vector_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "'%g %g %g'", + dasprintf (dstr, "'%.9g %.9g %.9g'", value->vector_var[0], value->vector_var[1], value->vector_var[2]); } @@ -1085,7 +1085,7 @@ pr_debug_quat_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "'%g %g %g %g'", + dasprintf (dstr, "'%.9g %.9g %.9g %.9g'", value->vector_var[0], value->vector_var[1], value->vector_var[2], value->vector_var[3]); } @@ -1123,7 +1123,7 @@ pr_debug_double_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "%g", *(double *)value); + dasprintf (dstr, "%.17g", *(double *)value); } static void From a0d85e33c21e2578f9e484eba969fa9419b81925 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 17:50:57 +0900 Subject: [PATCH 326/444] [gamecode] Rework implementation of memset* The memset instructions now match the move* instructions other than the first operand (always int). Probably breaks much, but fixed in next few commits. --- include/QF/pr_comp.h | 3 ++- libs/gamecode/pr_exec.c | 9 ++++++--- libs/gamecode/pr_opcode.c | 16 ++++++++++++---- 3 files changed, 20 insertions(+), 8 deletions(-) diff --git a/include/QF/pr_comp.h b/include/QF/pr_comp.h index 80b9e963d..3c6ccc8fe 100644 --- a/include/QF/pr_comp.h +++ b/include/QF/pr_comp.h @@ -396,8 +396,9 @@ typedef enum { OP_MOD_F, OP_MOD_D, - OP_MEMSET, OP_MEMSETI, + OP_MEMSETP, + OP_MEMSETPI, } pr_opcode_e; #define OP_BREAK 0x8000 diff --git a/libs/gamecode/pr_exec.c b/libs/gamecode/pr_exec.c index 718e2b09a..a73e5a474 100644 --- a/libs/gamecode/pr_exec.c +++ b/libs/gamecode/pr_exec.c @@ -1616,14 +1616,17 @@ op_call: pr->pr_globals + OPA.integer_var, st->b * 4); break; - case OP_MEMSET: + case OP_MEMSETI: + pr_memset (&OPC, OPA.integer_var, st->b); + break; + case OP_MEMSETP: if (pr_boundscheck->int_val) { - PR_BoundsCheckSize (pr, OPC.pointer_var, OPB.uinteger_var); + PR_BoundsCheckSize (pr, OPC.pointer_var, OPB.integer_var); } pr_memset (pr->pr_globals + OPC.pointer_var, OPA.integer_var, OPB.integer_var); break; - case OP_MEMSETI: + case OP_MEMSETPI: if (pr_boundscheck->int_val) { PR_BoundsCheckSize (pr, OPC.pointer_var, st->b); } diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index dc3a59fb9..3d3e8fe17 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -1181,17 +1181,22 @@ VISIBLE const opcode_t pr_opcodes[] = { {"", "movepi", OP_MOVEPI, true, ev_pointer, ev_short, ev_pointer, PROG_VERSION, - "%Ga, %Gb, %Gc", + "%Ga, %sb, %Gc", }, - {"", "memset", OP_MEMSET, true, + {"", "memseti", OP_MEMSETI, true, + ev_integer, ev_short, ev_void, + PROG_VERSION, + "%Ga, %sb, %gc", + }, + {"", "memsetp", OP_MEMSETP, true, ev_integer, ev_integer, ev_pointer, PROG_VERSION, "%Ga, %Gb, %Gc", }, - {"", "memseti", OP_MEMSETI, true, + {"", "memsetpi", OP_MEMSETPI, true, ev_integer, ev_short, ev_pointer, PROG_VERSION, - "%Ga, %Gb, %Gc", + "%Ga, %sb, %Gc", }, {"", "push.s", OP_PUSH_S, false, @@ -1710,6 +1715,9 @@ PR_Check_Opcodes (progs_t *pr) check_global_size (pr, st, op, st->b, st->a); check_global_size (pr, st, op, st->b, st->c); break; + case OP_MEMSETI: + check_global_size (pr, st, op, st->b, st->c); + break; case OP_PUSHB_F: case OP_PUSHB_S: case OP_PUSHB_ENT: From 2c9c15f4c85470ee37e1b684125325946b1c9844 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 17:54:05 +0900 Subject: [PATCH 327/444] [qfcc] Add a type check helper for structural types ie, struct/union/array. I finally though up a decent name (didn't want to use record as that's a pascal type). --- tools/qfcc/include/type.h | 1 + tools/qfcc/source/type.c | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 21f4feb2c..791ea0fc9 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -164,6 +164,7 @@ int is_pointer (const type_t *type) __attribute__((pure)); int is_field (const type_t *type) __attribute__((pure)); int is_struct (const type_t *type) __attribute__((pure)); int is_array (const type_t *type) __attribute__((pure)); +int is_structural (const type_t *type) __attribute__((pure)); int is_func (const type_t *type) __attribute__((pure)); int is_string (const type_t *type) __attribute__((pure)); int type_compatible (const type_t *dst, const type_t *src) __attribute__((pure)); diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 4fd77a9fd..1c21e1d62 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -827,6 +827,12 @@ is_func (const type_t *type) return 0; } +int +is_structural (const type_t *type) +{ + return is_struct (type) || is_array (type); +} + int is_string (const type_t *type) { From 19002116c2fc566d11ef1c7a689f6ceb4ad467cd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 17:56:07 +0900 Subject: [PATCH 328/444] [qfcc] Fix missing expression types from dot_expr --- tools/qfcc/source/dot_expr.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index 6b1cb2428..c81d982cc 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -67,6 +67,8 @@ const char *expr_names[] = "vector", "nil", "value", + "compound", + "memset", }; const char * From c04f1c01560dcb0922b69449a7806edd926aa040 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 17:57:58 +0900 Subject: [PATCH 329/444] [qfcc] Really delay the conversion of nil Now convert_nil only assigns the nil expression a type, and nil makes its way down to the statement emission code (where it belongs, really). Breaks even more things :) --- tools/qfcc/include/expr.h | 1 + tools/qfcc/source/def.c | 9 +++++---- tools/qfcc/source/expr.c | 9 +++++---- tools/qfcc/source/statements.c | 27 +++++++++++++++++++++++---- 4 files changed, 34 insertions(+), 12 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index d6b71d2b1..65c8ad290 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -234,6 +234,7 @@ typedef struct expr_s { ex_value_t *value; ///< constant value element_chain_t compound; ///< compound initializer ex_memset_t memset; ///< memset expr params + struct type_s *nil; ///< type for nil if known } e; } expr_t; diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 751bac7f5..689b21dac 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -360,10 +360,11 @@ init_elements (struct def_s *def, expr_t *eles) } else { def_t dummy = *def; for (element = element_chain.head; element; element = element->next) { - if (element->expr) { - c = constant_expr (element->expr); - } else { - c = new_nil_expr (); + if (!element->expr + || ((c = constant_expr (element->expr))->type == ex_nil)) { + // nil is type agnostic 0 and defspaces are initialized to + // 0 on creation + continue; } if (c->type == ex_nil) { c = convert_nil (c, element->type); diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 44d62a803..c4408f6e2 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -226,6 +226,10 @@ get_type (expr_t *e) return &type_float; return &type_integer; case ex_nil: + if (e->e.nil) { + return e->e.nil; + } + // fall through case ex_state: return &type_void; case ex_block: @@ -1414,8 +1418,7 @@ convert_double (expr_t *e) expr_t * convert_nil (expr_t *e, type_t *t) { - e->type = ex_value; - e->e.value = new_nil_val (t); + e->e.nil = t; return e; } @@ -1977,8 +1980,6 @@ return_expr (function_t *f, expr_t *e) if (e->type == ex_nil) { t = ret_type; convert_nil (e, t); - if (e->type == ex_nil) - return error (e, "invalid return type for NIL"); } else { if (!options.traditional) return error (e, "void value not ignored as it ought to be"); diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 0b27803a1..e38248bed 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1149,6 +1149,23 @@ expr_vector_e (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } +static sblock_t * +expr_nil (sblock_t *sblock, expr_t *e, operand_t **op) +{ + type_t *nil = e->e.nil; + expr_t *ptr; + if (!is_struct (nil) && !is_array (nil)) { + *op = value_operand (new_nil_val (nil), e); + return sblock; + } + ptr = address_expr (new_temp_def_expr (nil), 0, 0); + expr_file_line (ptr, e); + sblock = statement_subexpr (sblock, ptr, op); + e = expr_file_line (new_memset_expr (ptr, new_integer_expr (0), nil), e); + sblock = statement_slist (sblock, e); + return sblock; +} + static sblock_t * expr_value (sblock_t *sblock, expr_t *e, operand_t **op) { @@ -1171,18 +1188,20 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op) expr_symbol, expr_temp, expr_vector_e, // ex_vector - 0, // ex_nil + expr_nil, expr_value, + 0, // ex_compound + 0, // ex_memset }; if (!e) { *op = 0; return sblock; } - if (e->type > ex_value) - internal_error (e, "bad expression type"); + if (e->type > ex_memset) + internal_error (e, "bad sub-expression type"); if (!sfuncs[e->type]) - internal_error (e, "unexpected expression type: %s", + internal_error (e, "unexpected sub-expression type: %s", expr_names[e->type]); sblock = sfuncs[e->type] (sblock, e, op); From 3d88c3845fe0baede222e5aa2a8a336b30232f24 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 18:20:38 +0900 Subject: [PATCH 330/444] [qfcc] Move struct copy/set into statement emission Doing it in the expression trees was a big mistake for a several reasons. For one, expression trees are meant to be target-agnostic, so they're the wrong place for selecting instruction types. Also, the move and memset expressions broke "a = b = c;" type expression chains. This fixes most things (including the assignchain test) with -Werror turned off (some issues in flow analysis uncovered by the nil migration: memset target not extracted). --- tools/qfcc/source/expr_assign.c | 106 ++------------------------------ tools/qfcc/source/statements.c | 106 ++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 102 deletions(-) diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index aa759b88d..465746983 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -263,29 +263,6 @@ assign_vector_expr (expr_t *dst, expr_t *src) return 0; } -static __attribute__((pure)) int -is_const_ptr (expr_t *e) -{ - if ((e->type != ex_value || e->e.value->lltype != ev_pointer) - || !(POINTER_VAL (e->e.value->v.pointer) >= 0 - && POINTER_VAL (e->e.value->v.pointer) < 65536)) { - return 1; - } - return 0; -} - -static __attribute__((pure)) int -is_indirect (expr_t *e) -{ - if (e->type == ex_block && e->e.block.result) - return is_indirect (e->e.block.result); - if (e->type == ex_expr && e->e.expr.op == '.') - return 1; - if (!(e->type == ex_uexpr && e->e.expr.op == '.')) - return 0; - return is_const_ptr (e->e.expr.e1); -} - static __attribute__((pure)) int is_memset (expr_t *e) { @@ -345,17 +322,14 @@ assign_expr (expr_t *dst, expr_t *src) src_type = get_type (src); } if (src->type == ex_bool) { + // boolean expressions are chains of tests, so extract the result + // of the tests src = convert_from_bool (src, dst_type); if (src->type == ex_error) { return src; } src_type = get_type (src); } - if (!is_struct (dst_type) && is_nil (src)) { - // nil is a type-agnostic 0 - src_type = dst_type; - convert_nil (src, src_type); - } if (!is_nil (src)) { if ((expr = check_types_compatible (dst, src))) { @@ -366,80 +340,8 @@ assign_expr (expr_t *dst, expr_t *src) if ((expr = assign_vector_expr (dst, src))) { return expr; } - } - - if (is_indirect (dst) && is_indirect (src)) { - debug (dst, "here"); - if (is_struct (src_type)) { - dst = address_expr (dst, 0, 0); - src = address_expr (src, 0, 0); - expr = new_move_expr (dst, src, src_type, 1); - } else { - expr_t *temp = new_temp_def_expr (dst_type); - - expr = new_block_expr (); - append_expr (expr, assign_expr (temp, src)); - append_expr (expr, assign_expr (dst, temp)); - expr->e.block.result = temp; - } - return expr; - } else if (is_indirect (dst)) { - debug (dst, "here"); - if (is_struct (dst_type)) { - dst = address_expr (dst, 0, 0); - if (is_nil (src)) { - return new_memset_expr (dst, new_integer_expr (0), dst_type); - } else { - src = address_expr (src, 0, 0); - return new_move_expr (dst, src, dst_type, 1); - } - } - if (is_nil (src)) { - src_type = dst_type; - convert_nil (src, src_type); - } - if (dst->type == ex_expr) { - if (get_type (dst->e.expr.e1) == &type_entity) { - dst_type = dst->e.expr.type; - dst->e.expr.type = pointer_type (dst_type); - dst->e.expr.op = '&'; - } - op = PAS; - } else { - if (is_const_ptr (dst->e.expr.e1)) { - dst = dst->e.expr.e1; - op = PAS; - } - } - } else if (is_indirect (src)) { - debug (dst, "here"); - if (is_struct (dst_type)) { - dst = address_expr (dst, 0, 0); - src = address_expr (src, 0, 0); - src->rvalue = 1; - return new_move_expr (dst, src, src_type, 1); - } - if (src->type == ex_uexpr) { - expr = src->e.expr.e1; - if (is_const_ptr (expr)) { - if (expr->type == ex_expr && expr->e.expr.op == '&' - && expr->e.expr.type->type == ev_pointer - && !is_constant (expr)) { - src = expr; - src->e.expr.op = '.'; - src->e.expr.type = src_type; - src->rvalue = 1; - } - } - } - } - - if (is_nil (src)) { - src_type = dst_type; - convert_nil (src, src_type); - } - if (is_struct (dst_type)) { - return new_move_expr (dst, src, dst_type, 0); + } else { + convert_nil (src, dst_type); } expr = new_binary_expr (op, dst, src); diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index e38248bed..4a3aff674 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -42,6 +42,7 @@ #include "qfalloca.h" #include "QF/alloc.h" +#include "QF/mathlib.h" #include "QF/va.h" #include "dags.h" @@ -615,18 +616,123 @@ statement_branch (sblock_t *sblock, expr_t *e) return sblock->next; } +static __attribute__((pure)) int +is_const_ptr (expr_t *e) +{ + if ((e->type != ex_value || e->e.value->lltype != ev_pointer) + || !(POINTER_VAL (e->e.value->v.pointer) >= 0 + && POINTER_VAL (e->e.value->v.pointer) < 65536)) { + return 1; + } + return 0; +} + +static __attribute__((pure)) int +is_indirect (expr_t *e) +{ + if (e->type == ex_block && e->e.block.result) + return is_indirect (e->e.block.result); + if (e->type == ex_expr && e->e.expr.op == '.') + return 1; + if (!(e->type == ex_uexpr && e->e.expr.op == '.')) + return 0; + return is_const_ptr (e->e.expr.e1); +} + +static sblock_t * +expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op) +{ + statement_t *s; + expr_t *dst_expr = e->e.expr.e1; + expr_t *src_expr = e->e.expr.e2; + type_t *dst_type = get_type (dst_expr); + type_t *src_type = get_type (src_expr); + unsigned count; + expr_t *count_expr; + operand_t *dst = 0; + operand_t *src = 0; + operand_t *size = 0; + static const char *opcode_sets[][2] = { + {"", ""}, + {"", ""}, + }; + const unsigned max_count = 1 << 16; + const char **opcode_set = opcode_sets[0]; + const char *opcode; + int need_ptr = 0; + operand_t *dummy; + + if (src_expr->type == ex_expr + && (src_expr->e.expr.op == '=' || src_expr->e.expr.op == PAS)) { + sblock = statement_subexpr (sblock, src_expr, &dummy); + } + // follow the assignment chain to find the actual source expression + // (can't take the address of an assignment) + while (src_expr->type == ex_expr + && (src_expr->e.expr.op == '=' || src_expr->e.expr.op == PAS)) { + src_expr = src_expr->e.expr.e2; + } + if (src_expr->type == ex_nil) { + // switch to memset because nil is type agnostic 0 + src_expr = new_integer_expr (0); + opcode_set = opcode_sets[1]; + if (is_indirect (dst_expr)) { + need_ptr = 1; + dst_expr = address_expr (dst_expr, 0, 0); + } + } else { + if (is_indirect (dst_expr) || is_indirect (src_expr)) { + need_ptr = 1; + dst_expr = address_expr (dst_expr, 0, 0); + src_expr = address_expr (src_expr, 0, 0); + } + } + + if (type_size (dst_type) != type_size (src_type)) { + bug (e, "dst and src sizes differ in expr_assign_copy: %d %d", + type_size (dst_type), type_size (src_type)); + } + count = min (type_size (dst_type), type_size (src_type)); + if (count < (1 << 16)) { + count_expr = expr_file_line (new_short_expr (count), e); + } else { + count_expr = expr_file_line (new_integer_expr (count), e); + } + + if (count < max_count && !need_ptr) { + opcode = opcode_set[0]; + } else { + opcode = opcode_set[1]; + } + + s = new_statement (st_move, opcode, e); + sblock = statement_subexpr (sblock, dst_expr, &dst); + sblock = statement_subexpr (sblock, src_expr, &src); + sblock = statement_subexpr (sblock, count_expr, &size); + s->opa = src; + s->opb = size; + s->opc = dst; + sblock_add_statement (sblock, s); + return sblock; +} + static sblock_t * expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) { statement_t *s; expr_t *src_expr = e->e.expr.e2; expr_t *dst_expr = e->e.expr.e1; + type_t *dst_type = get_type (dst_expr); operand_t *src = 0; operand_t *dst = 0; operand_t *ofs = 0; const char *opcode = convert_op (e->e.expr.op); st_type_t type; + if (is_structural (dst_type)) { + return expr_assign_copy (sblock, e, op); + } + if (e->e.expr.op == '=') { sblock = statement_subexpr (sblock, dst_expr, &dst); src = dst; From e22579d70e134aa04038cdedd8fe24176cc063a3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 18:28:54 +0900 Subject: [PATCH 331/444] [qfcc] Analyze memset target pointer This fixes the false uninitialized warnings cause by nil migration. --- tools/qfcc/source/flow.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index ff0d1de96..a1043df52 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -1091,9 +1091,11 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, case st_move: flow_add_op_var (use, s->opa, 1); flow_add_op_var (use, s->opb, 1); - if (!strcmp (s->opcode, "")) { + if (!strcmp (s->opcode, "") + || !strcmp (s->opcode, "")) { flow_add_op_var (def, s->opc, 0); - } else if (!strcmp (s->opcode, "")) { + } else if (!strcmp (s->opcode, "") + || !strcmp (s->opcode, "")) { flow_add_op_var (use, s->opc, 0); if (s->opc->op_type == op_value && s->opc->o.value->lltype == ev_pointer From f738639d68883698a23ae72770478d990e8489e9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 19:58:07 +0900 Subject: [PATCH 332/444] Revert "[qfcc} Mark some more functions as pure" This reverts commit 65b48c734c2efc1194e2cdec4469fd7d35043cf8. I forgot that get_type calls convert_name, which most definitely is not pure. Fixes the segfault in scheme. --- tools/qfcc/include/expr.h | 4 ++-- tools/qfcc/source/switch.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 65c8ad290..b25481a8f 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -264,7 +264,7 @@ extern expr_t *local_expr; \return Pointer to the type description, or null if the expression type (expr_t::type) is inappropriate. */ -struct type_s *get_type (expr_t *e) __attribute__((pure)); +struct type_s *get_type (expr_t *e); /** Get the basic type code of the expression result. @@ -272,7 +272,7 @@ struct type_s *get_type (expr_t *e) __attribute__((pure)); \return Pointer to the type description, or ev_type_count if get_type() returns null. */ -etype_t extract_type (expr_t *e) __attribute__((pure)); +etype_t extract_type (expr_t *e); /** Create a new expression node. diff --git a/tools/qfcc/source/switch.c b/tools/qfcc/source/switch.c index 6c00279a0..967a7b73f 100644 --- a/tools/qfcc/source/switch.c +++ b/tools/qfcc/source/switch.c @@ -85,7 +85,7 @@ get_hash (const void *_cl, void *unused) return Hash_Buffer (&val->v, sizeof (val->v)) + val->lltype; } -static int __attribute__((pure)) +static int compare (const void *_cla, const void *_clb, void *unused) { case_label_t *cla = (case_label_t *) _cla; From a069fad41ea87366243f19c45cf3f7b761b3dfa2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 20:16:06 +0900 Subject: [PATCH 333/444] [gamecode] Print only entity address when no edicts If the edicts pointer is null, it's not possible to convert the entity address to an index. --- libs/gamecode/pr_debug.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 0b76cb997..9464c326c 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -1019,9 +1019,13 @@ pr_debug_entity_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; progs_t *pr = data->pr; dstring_t *dstr = data->dstr; - edict_t *edict = PROG_TO_EDICT (pr, value->entity_var); - dasprintf (dstr, "entity %d", NUM_FOR_BAD_EDICT (pr, edict)); + if (pr->edicts) { + edict_t *edict = PROG_TO_EDICT (pr, value->entity_var); + dasprintf (dstr, "entity %d", NUM_FOR_BAD_EDICT (pr, edict)); + } else { + dasprintf (dstr, "entity [%x]",value->entity_var); + } } static void From de89f2f31fde7ee2066fcd46632057534b4088e7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 20:47:57 +0900 Subject: [PATCH 334/444] [qfcc] Fix a test that wasn't failing when it should --- tools/qfcc/test/assignchain.r | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qfcc/test/assignchain.r b/tools/qfcc/test/assignchain.r index 454279f45..4d6fd2e4b 100644 --- a/tools/qfcc/test/assignchain.r +++ b/tools/qfcc/test/assignchain.r @@ -85,6 +85,7 @@ int main () int ret = 0; ret |= test_simple_global (); ret |= test_struct_global (); + x = 0; y = 0; ret |= test_simple_pointer (&x, &y); ret |= test_struct_pointer (&bar, &baz); return ret; From d150210888f90c0a0ae290181b3d2a2b406c1c4c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 20:56:10 +0900 Subject: [PATCH 335/444] [qfcc] Nuke PAS from orbit And there was much rejoicing. I hated having to create that opcode. --- tools/qfcc/source/constfold.c | 21 ++++----------------- tools/qfcc/source/dot_expr.c | 1 - tools/qfcc/source/expr_bool.c | 2 +- tools/qfcc/source/qc-parse.y | 2 +- tools/qfcc/source/statements.c | 25 ++----------------------- 5 files changed, 8 insertions(+), 43 deletions(-) diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index e7c037deb..f46d1a452 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -226,7 +226,7 @@ do_op_float (int op, expr_t *e, expr_t *e1, expr_t *e2) if (!valid_op (op, valid)) return error (e1, "invalid operator for float"); - if (op == '=' || op == PAS) { + if (op == '=') { if ((type = get_type (e1)) != &type_float) { //FIXME optimize casting a constant e->e.expr.e2 = e2 = cf_cast_expr (type, e2); @@ -355,7 +355,7 @@ do_op_double (int op, expr_t *e, expr_t *e1, expr_t *e2) if (!valid_op (op, valid)) return error (e1, "invalid operator for double"); - if (op == '=' || op == PAS) { + if (op == '=') { if ((type = get_type (e1)) != &type_double) { //FIXME optimize casting a constant e->e.expr.e2 = e2 = cf_cast_expr (type, e2); @@ -616,7 +616,7 @@ static expr_t * do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2) { type_t *type; - static int valid[] = {'=', PAS, '-', '&', 'M', '.', EQ, NE, 0}; + static int valid[] = {'=', '-', '&', 'M', '.', EQ, NE, 0}; if (is_integral (type = get_type (e2)) && (op == '-' || op == '+')) { // pointer arithmetic @@ -640,26 +640,13 @@ do_op_pointer (int op, expr_t *e, expr_t *e1, expr_t *e2) e = binary_expr ('/', e, new_integer_expr (type_size (type))); return e; } - if (op == PAS && (type = get_type (e1)->t.fldptr.type) != get_type (e2)) { - // make sure auto-convertions happen - expr_t *tmp = new_temp_def_expr (type); - expr_t *ass = new_binary_expr ('=', tmp, e2); - - tmp->file = e1->file; - ass->line = e2->line; - ass->file = e2->file; - ass = fold_constants (ass); - if (e->e.expr.e2 == tmp) - internal_error (e2, 0); - e->e.expr.e2 = ass->e.expr.e2; - } if (op == EQ || op == NE) { if (options.code.progsversion > PROG_ID_VERSION) e->e.expr.type = &type_integer; else e->e.expr.type = &type_float; } - if (op != PAS && op != '.' && op != '&' && op != 'M' + if (op != '.' && op != '&' && op != 'M' && extract_type (e1) != extract_type (e2)) return type_mismatch (e1, e2, op); if ((op == '.' || op == '&') && get_type (e2) == &type_uinteger) diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index c81d982cc..76bd21089 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -75,7 +75,6 @@ const char * get_op_string (int op) { switch (op) { - case PAS: return ".="; case OR: return "||"; case AND: return "&&"; case EQ: return "=="; diff --git a/tools/qfcc/source/expr_bool.c b/tools/qfcc/source/expr_bool.c index 7f7fdbfee..74f8d24de 100644 --- a/tools/qfcc/source/expr_bool.c +++ b/tools/qfcc/source/expr_bool.c @@ -245,7 +245,7 @@ convert_bool (expr_t *e, int block) { expr_t *b; - if (e->type == ex_expr && (e->e.expr.op == '=' || e->e.expr.op == PAS)) { + if (e->type == ex_expr && e->e.expr.op == '=') { expr_t *src; if (!e->paren && options.warnings.precedence) warning (e, "suggest parentheses around assignment " diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 9fe7fbbd2..6ca42392c 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -124,7 +124,7 @@ int yylex (void); %nonassoc STORAGEX %left COMMA -%right '=' ASX PAS /* pointer assign */ +%right '=' ASX %right '?' ':' %left OR %left AND diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 4a3aff674..1ac0311a5 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -440,7 +440,6 @@ static const char * convert_op (int op) { switch (op) { - case PAS: return ".="; case OR: return "||"; case AND: return "&&"; case EQ: return "=="; @@ -662,14 +661,12 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op) int need_ptr = 0; operand_t *dummy; - if (src_expr->type == ex_expr - && (src_expr->e.expr.op == '=' || src_expr->e.expr.op == PAS)) { + if (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { sblock = statement_subexpr (sblock, src_expr, &dummy); } // follow the assignment chain to find the actual source expression // (can't take the address of an assignment) - while (src_expr->type == ex_expr - && (src_expr->e.expr.op == '=' || src_expr->e.expr.op == PAS)) { + while (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { src_expr = src_expr->e.expr.e2; } if (src_expr->type == ex_nil) { @@ -743,22 +740,6 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) if (src == dst) return sblock; type = st_assign; - } else { - //FIXME this sucks. find a better way to handle both pointer - //dereferences and pointer assignements - sblock = statement_subexpr (sblock, src_expr, &src); - if (dst_expr->type == ex_expr - && extract_type (dst_expr->e.expr.e1) == ev_pointer - && !is_constant (dst_expr->e.expr.e1)) { - sblock = statement_subexpr (sblock, dst_expr->e.expr.e1, &dst); - sblock = statement_subexpr (sblock, dst_expr->e.expr.e2, &ofs); - } else { - sblock = statement_subexpr (sblock, dst_expr, &dst); - ofs = 0; - } - if (op) - *op = src; - type = st_ptrassign; } s = new_statement (type, opcode, e); s->opa = src; @@ -1059,7 +1040,6 @@ expr_expr (sblock_t *sblock, expr_t *e, operand_t **op) sblock = expr_call (sblock, e, op); break; case '=': - case PAS: sblock = expr_assign (sblock, e, op); break; case 'm': @@ -1506,7 +1486,6 @@ statement_expr (sblock_t *sblock, expr_t *e) sblock = statement_branch (sblock, e); break; case '=': - case PAS: sblock = expr_assign (sblock, e, 0); break; case 'm': From 57134e01cdad37fc4ea34765a1092e41f60cc9ad Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 13 Mar 2020 22:14:30 +0900 Subject: [PATCH 336/444] [qfcc] Handle l-value pointer dereferences again While I still hate ".=", at least it's more hidden, and the new implementation is a fair bit cleaner (hah, goto a label in an if (0) {} block). Most importantly, the expression tree code knows nothing about it. Now just to figure out what broke func-epxr. A bit of whack-a-mole, but yay for automated tests. --- tools/qfcc/source/statements.c | 75 ++++++++++++++++++++++++++-------- 1 file changed, 58 insertions(+), 17 deletions(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 1ac0311a5..37a94b81c 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -659,11 +659,11 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op) const char **opcode_set = opcode_sets[0]; const char *opcode; int need_ptr = 0; - operand_t *dummy; + //operand_t *dummy; - if (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { - sblock = statement_subexpr (sblock, src_expr, &dummy); - } + //if (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { + // sblock = statement_subexpr (sblock, src_expr, &dummy); + //} // follow the assignment chain to find the actual source expression // (can't take the address of an assignment) while (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { @@ -726,21 +726,62 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) const char *opcode = convert_op (e->e.expr.op); st_type_t type; - if (is_structural (dst_type)) { - return expr_assign_copy (sblock, e, op); - } - - if (e->e.expr.op == '=') { - sblock = statement_subexpr (sblock, dst_expr, &dst); - src = dst; + if (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { sblock = statement_subexpr (sblock, src_expr, &src); - ofs = 0; - if (op) - *op = dst; - if (src == dst) - return sblock; - type = st_assign; + if (is_structural (dst_type)) { + return expr_assign_copy (sblock, e, op); + } + if (is_indirect (dst_expr)) { + goto dereference_dst; + } else { + sblock = statement_subexpr (sblock, dst_expr, &dst); + } + } else { + if (is_structural (dst_type)) { + return expr_assign_copy (sblock, e, op); + } + + if (is_indirect (dst_expr)) { + // If both dst_expr and src_expr are indirect, then a staging temp + // is needed, but emitting src_expr first generates that temp + // because src is null. If src_expr is not indirect and is a simple + // variable reference, then just the ref will be generated and thus + // will be assigned to the dereferenced destination. If src_expr + // is not simple, then a temp will be generated, so all good. + sblock = statement_subexpr (sblock, src_expr, &src); + goto dereference_dst; + } else { + // dst_expr is direct and known to be an l-value, so emitting + // its expression will simply generate a reference to that l-value + // which will be used as the default location to store src_expr's + // result + sblock = statement_subexpr (sblock, dst_expr, &dst); + src = dst; + sblock = statement_subexpr (sblock, src_expr, &src); + } } + if (0) { +dereference_dst: + // dst_expr is a dereferenced pointer, so need to un-dereference it + // to get the pointer and switch to storep instructions. + dst_expr = address_expr (dst_expr, 0, 0); + opcode = ".="; // FIXME find a nicer representation (lose strings?) + if (dst_expr->type == ex_expr && !is_const_ptr (dst_expr->e.expr.e1)) { + sblock = statement_subexpr (sblock, dst_expr->e.expr.e1, &dst); + sblock = statement_subexpr (sblock, dst_expr->e.expr.e2, &ofs); + } else { + sblock = statement_subexpr (sblock, dst_expr, &dst); + ofs = 0; + } + } + if (op) { + *op = src; + } + if (src == dst) { + return sblock; + } + type = st_assign; + s = new_statement (type, opcode, e); s->opa = src; s->opb = dst; From b1459ac816cbbd99ecee1ee7a85290cd080b9202 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 01:24:13 +0900 Subject: [PATCH 337/444] [qfcc] Move return save temp into call block This fixes func-expr after the assignment rewrite. Now all tests pass when not optimizing (something not quite right in assignchain when optimizing). --- tools/qfcc/source/expr.c | 3 +++ tools/qfcc/source/expr_binary.c | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index c4408f6e2..85c07511b 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1843,6 +1843,9 @@ build_function_call (expr_t *fexpr, const type_t *ftype, expr_t *params) if (e->type == ex_compound) { e = expr_file_line (initialized_temp_expr (arg_types[i], e), e); } + // FIXME this is target-specific info and should not be in the + // expression tree + // That, or always use a temp, since it should get optimized out if (has_function_call (e)) { expr_t *cast = cast_expr (arg_types[i], convert_vector (e)); expr_t *tmp = new_temp_def_expr (arg_types[i]); diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index 228112311..c2d446334 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -924,10 +924,14 @@ binary_expr (int op, expr_t *e1, expr_t *e2) convert_name (e1); e1 = convert_vector (e1); + // FIXME this is target-specific info and should not be in the + // expression tree if (e1->type == ex_block && e1->e.block.is_call && has_function_call (e2) && e1->e.block.result) { - e = new_temp_def_expr (get_type (e1->e.block.result)); - e1 = assign_expr (e, e1); + expr_t *tmp = new_temp_def_expr (get_type (e1->e.block.result)); + e = assign_expr (tmp, e1->e.block.result); + append_expr (e1, e); + e1->e.block.result = tmp; } if (e1->type == ex_error) return e1; From a98f0e04eba6541b20f4f10383fdf2cf20e71a5c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 01:28:00 +0900 Subject: [PATCH 338/444] [qfcc] Correct some misinformative prints --- tools/qfcc/test/assignchain.r | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/test/assignchain.r b/tools/qfcc/test/assignchain.r index 4d6fd2e4b..7f08c0494 100644 --- a/tools/qfcc/test/assignchain.r +++ b/tools/qfcc/test/assignchain.r @@ -26,18 +26,18 @@ int test_struct_global (void) int ret = 0; bar = baz = foo_init; if (bar.x != foo_init.x || bar.y != foo_init.y) { - printf ("test_struct: bar={%d %g} foo_init={%d %g}\n", + printf ("test_struct_global: bar={%d %g} foo_init={%d %g}\n", bar.x, bar.y, foo_init.x, foo_init.y); ret |= 1; } if (baz.x != foo_init.x || baz.y != foo_init.y) { - printf ("test_struct: baz={%d %g} foo_init={%d %g}\n", + printf ("test_struct_global: baz={%d %g} foo_init={%d %g}\n", baz.x, baz.y, foo_init.x, foo_init.y); ret |= 1; } bar = baz = nil; if (bar.x || baz.x || bar.y || baz.y) { - printf ("test_struct: bar={%d %g} baz={%d %g}\n", + printf ("test_struct_global: bar={%d %g} baz={%d %g}\n", bar.x, bar.y, baz.x, baz.y); ret |= 1; } @@ -49,7 +49,7 @@ int test_simple_pointer (int *x, int *y) int ret = 0; *x = *y = z; if (*x != z || *y != z) { - printf ("test_simple_global: *x=%d *y=%d z=%d\n", *x, *y, z); + printf ("test_simple_pointer: *x=%d *y=%d z=%d\n", *x, *y, z); ret |= 1; } return ret; @@ -60,12 +60,12 @@ int test_struct_pointer (foo *bar, foo *baz) int ret = 0; *bar = *baz = foo_init; if (bar.x != foo_init.x || bar.y != foo_init.y) { - printf ("test_struct: bar={%d %g} foo_init={%d %g}\n", + printf ("test_struct_pointer: bar={%d %g} foo_init={%d %g}\n", bar.x, bar.y, foo_init.x, foo_init.y); ret |= 1; } if (baz.x != foo_init.x || baz.y != foo_init.y) { - printf ("test_struct: baz={%d %g} foo_init={%d %g}\n", + printf ("test_struct_pointer: baz={%d %g} foo_init={%d %g}\n", baz.x, baz.y, foo_init.x, foo_init.y); ret |= 1; } From d30c895c134024562b9ff615b44e9ec4e09ed32a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 11:36:42 +0900 Subject: [PATCH 339/444] [qfcc] Use correct assignment statement type Just another minor detail lost in the assignment rewrite. With this, all tests pass when optimizing. --- tools/qfcc/source/statements.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 37a94b81c..e58294b00 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -760,6 +760,8 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) sblock = statement_subexpr (sblock, src_expr, &src); } } + type = st_assign; + if (0) { dereference_dst: // dst_expr is a dereferenced pointer, so need to un-dereference it @@ -773,6 +775,7 @@ dereference_dst: sblock = statement_subexpr (sblock, dst_expr, &dst); ofs = 0; } + type = st_ptrassign; } if (op) { *op = src; @@ -780,7 +783,6 @@ dereference_dst: if (src == dst) { return sblock; } - type = st_assign; s = new_statement (type, opcode, e); s->opa = src; From 7cc51c9ca35f08b311d71c9dae1a7b3f28ebe71e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 12:27:23 +0900 Subject: [PATCH 340/444] [qfcc] Save block expression creator's address I've already found the bug that necessitated it (and the creator was innocent), but it will help later. --- tools/qfcc/include/expr.h | 1 + tools/qfcc/source/expr.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index b25481a8f..0efc998ba 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -104,6 +104,7 @@ typedef struct { struct expr_s **tail; ///< last expression in the block, for appending struct expr_s *result; ///< the result of this block if non-void int is_call; ///< this block exprssion forms a function call + void *return_addr;///< who allocated this } ex_block_t; typedef struct { diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 85c07511b..734886f9a 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -561,6 +561,7 @@ new_block_expr (void) b->type = ex_block; b->e.block.head = 0; b->e.block.tail = &b->e.block.head; + b->e.block.return_addr = __builtin_return_address (0); return b; } From 277ff719f5929e2494360376fa5656ffe054bb95 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 12:30:18 +0900 Subject: [PATCH 341/444] Revert "Do not lose the block expression when taking its address." This reverts commit b49d90e769e6f936795379ed643aa91f55561610. I suspect this was a workaround for the mess in assignment chains. However, it caused compile errors with the new implementation, and is just bogus anyway. --- tools/qfcc/source/expr.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 734886f9a..70e4b2076 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2229,8 +2229,7 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) case ex_block: if (!e1->e.block.result) return error (e1, "invalid type for unary &"); - e1->e.block.result = address_expr (e1->e.block.result, e2, t); - return e1; + return address_expr (e1->e.block.result, e2, t); case ex_label: return new_label_ref (&e1->e.label); case ex_temp: From 6608c8a1f66c4f007bfd48e14b8c058252665177 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 13:14:25 +0900 Subject: [PATCH 342/444] Revert "Support taking the address of block expressions that have a result." This reverts commit c78d15b331f830118a27726b522765d985f94624. While a block expression's result may be an l-value, block expressions are not (and their results may not be), thus taking the address of one is not really correct. It seems the only place that tries to do so is the assignment code when dealing with structures. --- tools/qfcc/source/expr.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 70e4b2076..72624364c 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2226,10 +2226,6 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) return address_expr (e1->e.expr.e1, e2, t); } return error (e1, "invalid type for unary &"); - case ex_block: - if (!e1->e.block.result) - return error (e1, "invalid type for unary &"); - return address_expr (e1->e.block.result, e2, t); case ex_label: return new_label_ref (&e1->e.label); case ex_temp: From 51a30de9c560caf89403af1514cc2dcdecd1fe89 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 16:51:54 +0900 Subject: [PATCH 343/444] [qfcc] Print accurate linenos for more ICEs --- tools/qfcc/source/dags.c | 9 +++++---- tools/qfcc/source/flow.c | 6 +++--- tools/qfcc/source/statements.c | 13 +++++++------ 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index a97b3e68c..ce4bd98cf 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -80,7 +80,7 @@ flush_daglabels (void) else if (op->op_type == op_label) op->o.label->daglabel = 0; else - internal_error (0, "unexpected operand type"); + internal_error (op->expr, "unexpected operand type"); } daglabel_chain = daglabel_chain->daglabel_chain; } @@ -186,7 +186,7 @@ operand_label (dag_t *dag, operand_t *op) label->op = op; op->o.label->daglabel = label; } else { - internal_error (0, "unexpected operand type: %d", op->op_type); + internal_error (op->expr, "unexpected operand type: %d", op->op_type); } return label; } @@ -498,7 +498,7 @@ dag_kill_aliases (daglabel_t *l) def_visit_all (op->o.def, 1, dag_def_kill_aliases_visit, l); } } else { - internal_error (0, "rvalue assignment?"); + internal_error (op->expr, "rvalue assignment?"); } } @@ -555,7 +555,8 @@ dagnode_attach_label (dagnode_t *n, daglabel_t *l) internal_error (0, "attempt to attach operator label to dagnode " "identifiers"); if (!op_is_identifier (l->op)) - internal_error (0, "attempt to attach non-identifer label to dagnode " + internal_error (l->op->expr, + "attempt to attach non-identifer label to dagnode " "identifiers"); if (l->dagnode) { // if the node is a leaf, then kill its value so no attempt is made diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index a1043df52..d3fa1d38f 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -280,9 +280,9 @@ flowvar_get_def (flowvar_t *var) case op_temp: return op->o.tempop.def; case op_alias: - internal_error (0, "unexpected alias operand"); + internal_error (op->expr, "unexpected alias operand"); } - internal_error (0, "oops, blue pill"); + internal_error (op->expr, "oops, blue pill"); return 0; } @@ -378,7 +378,7 @@ get_temp_address (function_t *func, operand_t *op) func->tmpaddr += top->size; } if (top->o.tempop.offset) { - internal_error (0, "real tempop with a non-zero offset"); + internal_error (top->expr, "real tempop with a non-zero offset"); } op->o.tempop.flowaddr = top->o.tempop.flowaddr + op->o.tempop.offset; return op->o.tempop.flowaddr; diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index e58294b00..d633d6434 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -207,7 +207,7 @@ print_operand (operand_t *op) case ev_void: case ev_invalid: case ev_type_count: - internal_error (0, "weird value type"); + internal_error (op->expr, "weird value type"); } break; case op_label: @@ -390,7 +390,7 @@ tempop_visit_all (tempop_t *tempop, int overlap, if (tempop->alias) { top = tempop->alias; if (top->op_type != op_temp) { - internal_error (0, "temp alias of non-temp operand"); + internal_error (top->expr, "temp alias of non-temp operand"); } tempop = &top->o.tempop; if ((ret = visit (tempop, data))) @@ -400,7 +400,7 @@ tempop_visit_all (tempop_t *tempop, int overlap, } for (top = tempop->alias_ops; top; top = top->next) { if (top->op_type != op_temp) { - internal_error (0, "temp alias of non-temp operand"); + internal_error (top->expr, "temp alias of non-temp operand"); } tempop = &top->o.tempop; if (tempop == start_tempop) @@ -419,8 +419,9 @@ alias_operand (type_t *type, operand_t *op, expr_t *expr) operand_t *aop; if (type_size (type) != type_size (op->type)) { - internal_error (0, "\naliasing operand with type of different size" - " (%d, %d)", type_size (type), type_size (op->type)); + internal_error (op->expr, + "aliasing operand with type of different size: %d, %d", + type_size (type), type_size (op->type)); } aop = new_operand (op_alias, expr); aop->o.alias = op; @@ -554,7 +555,7 @@ statement_get_targetlist (statement_t *s) target_list[0] = statement_get_target (s); } else if (statement_is_jumpb (s)) { if (table->alias) - internal_error (0, "aliased jump table"); + internal_error (s->opa->expr, "aliased jump table"); e = table->initializer->e.compound.head; //FIXME check!!! for (i = 0; i < count; e = e->next, i++) target_list[i] = e->expr->e.labelref.label->dest; From 7d5644e0553df6e453a28a1462cdcc10337dc711 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 17:44:08 +0900 Subject: [PATCH 344/444] [qfcc] Save operand creator return address --- tools/qfcc/include/statements.h | 2 ++ tools/qfcc/source/statements.c | 30 +++++++++++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index d1ccff441..dcb882d2b 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -58,6 +58,7 @@ typedef struct operand_s { struct type_s *type; ///< possibly override def's type int size; ///< for structures struct expr_s *expr; ///< expression generating this operand + void *return_addr; ///< who created this operand union { struct def_s *def; struct ex_value_s *value; @@ -126,6 +127,7 @@ int tempop_visit_all (tempop_t *tempop, int overlap, int (*visit) (tempop_t *, void *), void *data); operand_t *alias_operand (struct type_s *type, operand_t *op, struct expr_s *expr); +operand_t *label_operand (struct expr_s *label); void free_operand (operand_t *op); sblock_t *new_sblock (void); diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index d633d6434..3b8c5b013 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -274,12 +274,13 @@ new_statement (st_type_t type, const char *opcode, expr_t *expr) } static operand_t * -new_operand (op_type_e op, expr_t *expr) +new_operand (op_type_e op, expr_t *expr, void *return_addr) { operand_t *operand; ALLOC (256, operand_t, operands, operand); operand->op_type = op; operand->expr = expr; + operand->return_addr = return_addr; return operand; } @@ -319,7 +320,7 @@ def_operand (def_t *def, type_t *type, expr_t *expr) if (!type) type = def->type; - op = new_operand (op_def, expr); + op = new_operand (op_def, expr, __builtin_return_address (0)); op->type = type; op->size = type_size (type); op->o.def = def; @@ -339,7 +340,7 @@ operand_t * value_operand (ex_value_t *value, expr_t *expr) { operand_t *op; - op = new_operand (op_value, expr); + op = new_operand (op_value, expr, __builtin_return_address (0)); op->type = value->type; op->o.value = value; return op; @@ -348,7 +349,7 @@ value_operand (ex_value_t *value, expr_t *expr) operand_t * temp_operand (type_t *type, expr_t *expr) { - operand_t *op = new_operand (op_temp, expr); + operand_t *op = new_operand (op_temp, expr, __builtin_return_address (0)); op->o.tempop.type = type; op->type = type; @@ -423,13 +424,26 @@ alias_operand (type_t *type, operand_t *op, expr_t *expr) "aliasing operand with type of different size: %d, %d", type_size (type), type_size (op->type)); } - aop = new_operand (op_alias, expr); + aop = new_operand (op_alias, expr, __builtin_return_address (0)); aop->o.alias = op; aop->type = type; aop->size = type_size (type); return aop; } +operand_t * +label_operand (expr_t *label) +{ + operand_t *lop; + + if (label->type != ex_label) { + internal_error (label, "not a label expression"); + } + lop = new_operand (op_label, label, __builtin_return_address (0)); + lop->o.label = &label->e.label; + return lop; +} + static operand_t * short_operand (short short_val, expr_t *expr) { @@ -595,8 +609,7 @@ statement_branch (sblock_t *sblock, expr_t *e) if (e->type == ex_uexpr && e->e.expr.op == 'g') { s = new_statement (st_flow, "", e); - s->opa = new_operand (op_label, e); - s->opa->o.label = &e->e.expr.e1->e.label; + s->opa = label_operand (e->e.expr.e1); } else { if (e->e.expr.op == 'g') { s = new_statement (st_flow, "", e); @@ -606,8 +619,7 @@ statement_branch (sblock_t *sblock, expr_t *e) opcode = convert_op (e->e.expr.op); s = new_statement (st_flow, opcode, e); sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); - s->opb = new_operand (op_label, e); - s->opb->o.label = &e->e.expr.e2->e.label; + s->opb = label_operand (e->e.expr.e2); } } From eca976e5ae79cdb1928f9f9cba64e0464abd4f36 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 17:45:54 +0900 Subject: [PATCH 345/444] [qfcc] Expose l-value checking Needed for assignment chains. --- tools/qfcc/include/expr.h | 1 + tools/qfcc/source/expr_assign.c | 33 +++++++++++++++++++++------------ 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 0efc998ba..39e405622 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -710,6 +710,7 @@ expr_t *build_for_statement (expr_t *init, expr_t *test, expr_t *next, expr_t *break_label, expr_t *continue_label); expr_t *build_state_expr (expr_t *e); expr_t *think_expr (struct symbol_s *think_sym); +int is_lvalue (const expr_t *expr) __attribute__((pure)); expr_t *assign_expr (expr_t *dst, expr_t *src); expr_t *cast_expr (struct type_s *t, expr_t *e); diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 465746983..88d45ad7b 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -81,8 +81,8 @@ check_assign_logic_precedence (expr_t *dst, expr_t *src) return 0; } -static expr_t * -check_valid_lvalue (expr_t *expr) +int +is_lvalue (const expr_t *expr) { switch (expr->type) { case ex_symbol: @@ -90,7 +90,7 @@ check_valid_lvalue (expr_t *expr) case sy_name: break; case sy_var: - return 0; + return 1; case sy_const: break; case sy_type: @@ -106,21 +106,21 @@ check_valid_lvalue (expr_t *expr) } break; case ex_temp: - return 0; + return 1; case ex_expr: if (expr->e.expr.op == '.') { - return 0; + return 1; } if (expr->e.expr.op == 'A') { - return check_valid_lvalue (expr->e.expr.e1); + return is_lvalue (expr->e.expr.e1); } break; case ex_uexpr: if (expr->e.expr.op == '.') { - return 0; + return 1; } if (expr->e.expr.op == 'A') { - return check_valid_lvalue (expr->e.expr.e1); + return is_lvalue (expr->e.expr.e1); } break; case ex_memset: @@ -136,11 +136,20 @@ check_valid_lvalue (expr_t *expr) case ex_error: break; } - if (options.traditional) { - warning (expr, "invalid lvalue in assignment"); - return 0; + return 0; +} + +static expr_t * +check_valid_lvalue (expr_t *expr) +{ + if (!is_lvalue (expr)) { + if (options.traditional) { + warning (expr, "invalid lvalue in assignment"); + return 0; + } + return error (expr, "invalid lvalue in assignment"); } - return error (expr, "invalid lvalue in assignment"); + return 0; } static expr_t * From 97e0c235295dc6f932edc170a7d0ae6c7cc1b44a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 17:47:23 +0900 Subject: [PATCH 346/444] [qfcc] Create a nil operand This is for struct assignments so they can pass the source operand back up the assignment chain. --- tools/qfcc/include/statements.h | 4 +++- tools/qfcc/source/emit.c | 2 ++ tools/qfcc/source/flow.c | 2 ++ tools/qfcc/source/statements.c | 18 ++++++++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index dcb882d2b..7a0b241ed 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -38,6 +38,7 @@ typedef enum { op_label, op_temp, op_alias, + op_nil, } op_type_e; typedef struct { @@ -55,7 +56,7 @@ typedef struct { typedef struct operand_s { struct operand_s *next; op_type_e op_type; - struct type_s *type; ///< possibly override def's type + struct type_s *type; ///< possibly override def's/nil's type int size; ///< for structures struct expr_s *expr; ///< expression generating this operand void *return_addr; ///< who created this operand @@ -117,6 +118,7 @@ struct dstring_s; const char *optype_str (op_type_e type) __attribute__((const)); +operand_t *nil_operand (struct type_s *type, struct expr_s *expr); operand_t *def_operand (struct def_s *def, struct type_s *type, struct expr_s *expr); operand_t *return_operand (struct type_s *type, struct expr_s *expr); diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 253502206..0073f3967 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -106,6 +106,8 @@ get_operand_def (expr_t *expr, operand_t *op) return op->o.tempop.def; case op_alias: return get_operand_def (expr, op->o.alias); + case op_nil: + internal_error (expr, "unexpected nil operand"); } return 0; } diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index d3fa1d38f..d3e82b7ce 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -281,6 +281,8 @@ flowvar_get_def (flowvar_t *var) return op->o.tempop.def; case op_alias: internal_error (op->expr, "unexpected alias operand"); + case op_nil: + internal_error (op->expr, "unexpected nil operand"); } internal_error (op->expr, "oops, blue pill"); return 0; diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 3b8c5b013..c64640c2f 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -65,6 +65,8 @@ static const char *op_type_names[] = { "op_value", "op_label", "op_temp", + "op_alias", + "op_nil", }; const char * @@ -150,6 +152,8 @@ operand_string (operand_t *op) strcpy (buf, alias); return va ("alias(%s,%s)", pr_type_name[op->type->type], buf); } + case op_nil: + return va ("nil"); } return ("??"); } @@ -222,6 +226,10 @@ print_operand (operand_t *op) printf ("alias(%s,", pr_type_name[op->type->type]); print_operand (op->o.alias); printf (")"); + break; + case op_nil: + printf ("nil"); + break; } } @@ -313,6 +321,16 @@ free_sblock (sblock_t *sblock) FREE (sblocks, sblock); } +operand_t * +nil_operand (type_t *type, expr_t *expr) +{ + operand_t *op; + op = new_operand (op_nil, expr, __builtin_return_address (0)); + op->type = type; + op->size = type_size (type); + return op; +} + operand_t * def_operand (def_t *def, type_t *type, expr_t *expr) { From 025dd634936853a3d6fd673f85a53ea36a52bf70 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 17:48:53 +0900 Subject: [PATCH 347/444] [qfcc] Bubble right-hand assignee back up chain This fixes assignchain when not optimizing. There are problems in dags, though, with address expressions. --- tools/qfcc/source/statements.c | 114 ++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 38 deletions(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index c64640c2f..63ec29f15 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -646,6 +646,46 @@ statement_branch (sblock_t *sblock, expr_t *e) return sblock->next; } +static sblock_t * +expr_address (sblock_t *sblock, expr_t *e, operand_t **op) +{ + statement_t *s; + s = new_statement (st_expr, "&", e); + sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); + s->opc = temp_operand (e->e.expr.type, e); + sblock_add_statement (sblock, s); + *(op) = s->opc; + return sblock; +} + +static sblock_t * +operand_address (sblock_t *sblock, operand_t *reference, operand_t **op, + expr_t *e) +{ + statement_t *s; + + switch (reference->op_type) { + case op_def: + case op_temp: + case op_alias: + s = new_statement (st_expr, "&", e); + s->opa = reference; + s->opc = temp_operand (pointer_type (reference->type), e); + sblock_add_statement (sblock, s); + if (op) { + *(op) = s->opc; + } + return sblock; + case op_value: + case op_label: + case op_nil: + break; + } + internal_error ((*op)->expr, + "invalid operand type for operand address: %s", + op_type_names[reference->op_type]); +} + static __attribute__((pure)) int is_const_ptr (expr_t *e) { @@ -660,8 +700,6 @@ is_const_ptr (expr_t *e) static __attribute__((pure)) int is_indirect (expr_t *e) { - if (e->type == ex_block && e->e.block.result) - return is_indirect (e->e.block.result); if (e->type == ex_expr && e->e.expr.op == '.') return 1; if (!(e->type == ex_uexpr && e->e.expr.op == '.')) @@ -670,7 +708,7 @@ is_indirect (expr_t *e) } static sblock_t * -expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op) +expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op, operand_t *src) { statement_t *s; expr_t *dst_expr = e->e.expr.e1; @@ -680,7 +718,6 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op) unsigned count; expr_t *count_expr; operand_t *dst = 0; - operand_t *src = 0; operand_t *size = 0; static const char *opcode_sets[][2] = { {"", ""}, @@ -692,29 +729,44 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op) int need_ptr = 0; //operand_t *dummy; - //if (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { - // sblock = statement_subexpr (sblock, src_expr, &dummy); - //} - // follow the assignment chain to find the actual source expression - // (can't take the address of an assignment) - while (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { - src_expr = src_expr->e.expr.e2; - } - if (src_expr->type == ex_nil) { - // switch to memset because nil is type agnostic 0 + if ((src && src->op_type == op_nil) || src_expr->type == ex_nil) { + // switch to memset because nil is type agnostic 0 and structures + // can be any size src_expr = new_integer_expr (0); + sblock = statement_subexpr (sblock, src_expr, &src); opcode_set = opcode_sets[1]; + if (op) { + *op = nil_operand (dst_type, src_expr); + } if (is_indirect (dst_expr)) { - need_ptr = 1; - dst_expr = address_expr (dst_expr, 0, 0); + goto dereference_dst; } } else { + if (!src) { + // This is the very right-hand node of a non-nil assignment chain + // (there may be more chains somwhere within src_expr, but they + // are not part of this chain as they are separated by another + // expression). + sblock = statement_subexpr (sblock, src_expr, &src); + } + // send the source operand back up through the assignment chain + // before modifying src if its address is needed + if (op) { + *op = src; + } if (is_indirect (dst_expr) || is_indirect (src_expr)) { - need_ptr = 1; - dst_expr = address_expr (dst_expr, 0, 0); - src_expr = address_expr (src_expr, 0, 0); + sblock = operand_address (sblock, src, &src, src_expr); + goto dereference_dst; } } + if (0) { +dereference_dst: + // dst_expr is a dereferenced pointer, so need to un-dereference it + // to get the pointer and switch to storep instructions. + dst_expr = expr_file_line (address_expr (dst_expr, 0, 0), e); + need_ptr = 1; + } + sblock = statement_subexpr (sblock, dst_expr, &dst); if (type_size (dst_type) != type_size (src_type)) { bug (e, "dst and src sizes differ in expr_assign_copy: %d %d", @@ -726,6 +778,7 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op) } else { count_expr = expr_file_line (new_integer_expr (count), e); } + sblock = statement_subexpr (sblock, count_expr, &size); if (count < max_count && !need_ptr) { opcode = opcode_set[0]; @@ -734,9 +787,6 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op) } s = new_statement (st_move, opcode, e); - sblock = statement_subexpr (sblock, dst_expr, &dst); - sblock = statement_subexpr (sblock, src_expr, &src); - sblock = statement_subexpr (sblock, count_expr, &size); s->opa = src; s->opb = size; s->opc = dst; @@ -760,7 +810,7 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) if (src_expr->type == ex_expr && src_expr->e.expr.op == '=') { sblock = statement_subexpr (sblock, src_expr, &src); if (is_structural (dst_type)) { - return expr_assign_copy (sblock, e, op); + return expr_assign_copy (sblock, e, op, src); } if (is_indirect (dst_expr)) { goto dereference_dst; @@ -769,7 +819,7 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) } } else { if (is_structural (dst_type)) { - return expr_assign_copy (sblock, e, op); + return expr_assign_copy (sblock, e, op, src); } if (is_indirect (dst_expr)) { @@ -797,7 +847,7 @@ expr_assign (sblock_t *sblock, expr_t *e, operand_t **op) dereference_dst: // dst_expr is a dereferenced pointer, so need to un-dereference it // to get the pointer and switch to storep instructions. - dst_expr = address_expr (dst_expr, 0, 0); + dst_expr = expr_file_line (address_expr (dst_expr, 0, 0), e); opcode = ".="; // FIXME find a nicer representation (lose strings?) if (dst_expr->type == ex_expr && !is_const_ptr (dst_expr->e.expr.e1)) { sblock = statement_subexpr (sblock, dst_expr->e.expr.e1, &dst); @@ -939,18 +989,6 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) return sblock->next; } -static sblock_t * -expr_address (sblock_t *sblock, expr_t *e, operand_t **op) -{ - statement_t *s; - s = new_statement (st_expr, "&", e); - sblock = statement_subexpr (sblock, e->e.expr.e1, &s->opa); - s->opc = temp_operand (e->e.expr.type, e); - sblock_add_statement (sblock, s); - *(op) = s->opc; - return sblock; -} - static statement_t * lea_statement (operand_t *pointer, operand_t *offset, expr_t *e) { @@ -1318,7 +1356,7 @@ expr_nil (sblock_t *sblock, expr_t *e, operand_t **op) *op = value_operand (new_nil_val (nil), e); return sblock; } - ptr = address_expr (new_temp_def_expr (nil), 0, 0); + ptr = expr_file_line (address_expr (new_temp_def_expr (nil), 0, 0), e); expr_file_line (ptr, e); sblock = statement_subexpr (sblock, ptr, op); e = expr_file_line (new_memset_expr (ptr, new_integer_expr (0), nil), e); From 72f4b8ccb5402de8e3d5d821882b0be2aa6c55e1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 19:26:47 +0900 Subject: [PATCH 348/444] [qfcc] Give address operands a good expression That is, those created by operand_address. The dag code needs the expression that is attached to the statement to have the correct expression type in order to do the right thing with the operands and aliasing, especially when generating temps. This fixes assignchain when optimizing (all tests pass again). --- tools/qfcc/include/expr.h | 2 +- tools/qfcc/source/statements.c | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 39e405622..170fc7a50 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -401,7 +401,7 @@ expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2); /** Create a new unary expression node node. If \a e1 is an error expression, then it will be returned instead of a - new binary expression. + new unary expression. \param op The op-code of the unary expression. \param e1 The "right" side of the expression. diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 63ec29f15..0b2337b0b 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -663,14 +663,22 @@ operand_address (sblock_t *sblock, operand_t *reference, operand_t **op, expr_t *e) { statement_t *s; + type_t *type; switch (reference->op_type) { case op_def: case op_temp: case op_alias: + // build an address expression so dags can extract the correct + // type. address_expr cannot be used because reference might not + // be something it likes + e = expr_file_line (new_unary_expr ('&', e), e); + type = pointer_type (reference->type); + e->e.expr.type = type; + s = new_statement (st_expr, "&", e); s->opa = reference; - s->opc = temp_operand (pointer_type (reference->type), e); + s->opc = temp_operand (type, e); sblock_add_statement (sblock, s); if (op) { *(op) = s->opc; From 877ad35a82f0eaf50988527eac7c351d140234b9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 19:45:07 +0900 Subject: [PATCH 349/444] [qwaq] Rework the hierarchy again It doesn't work right now because View unconditionally sends refresh to its textContext, but textContext can be a draw buffer which does not respond to refresh. Still, these changes (notably the assignment chain in qwaq-group.r really pushed qfcc). --- ruamoko/qwaq/qwaq-app.h | 11 +++++++---- ruamoko/qwaq/qwaq-app.r | 15 ++++++++------- ruamoko/qwaq/qwaq-group.h | 3 ++- ruamoko/qwaq/qwaq-group.r | 17 +++++++++-------- ruamoko/qwaq/qwaq-screen.h | 1 - ruamoko/qwaq/qwaq-screen.r | 12 +++--------- ruamoko/qwaq/qwaq-view.h | 1 + ruamoko/qwaq/qwaq-view.r | 4 ++++ 8 files changed, 34 insertions(+), 30 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.h b/ruamoko/qwaq/qwaq-app.h index d8b899624..7062ad096 100644 --- a/ruamoko/qwaq/qwaq-app.h +++ b/ruamoko/qwaq/qwaq-app.h @@ -1,18 +1,21 @@ #ifndef __qwaq_app_h #define __qwaq_app_h +#include + #include "event.h" -#include "qwaq-group.h" -@class Screen; +@class Group; -@interface QwaqApplication: Group +@interface QwaqApplication: Object { qwaq_event_t event; qwaq_command endState; - Screen *screen; + + Group *objects; } -run; +-draw; -handleEvent: (qwaq_event_t *) event; @end diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index fffe51c7b..5b5889768 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -38,16 +38,17 @@ arp_end (void) init_pair (1, COLOR_WHITE, COLOR_BLUE); init_pair (2, COLOR_WHITE, COLOR_BLACK); - screen = [[Screen screen] retain]; - [self insert:screen]; - [screen setBackground: COLOR_PAIR (1)]; - Rect r = *[screen getRect]; + TextContext *screen = [TextContext screen]; + objects = [[Group alloc] initWithContext: screen]; + + [screen bkgd: COLOR_PAIR (1)]; + Rect r = { nil, [screen size] }; r.offset.x = r.extent.width / 4; r.offset.y = r.extent.height / 4; r.extent.width /= 2; r.extent.height /= 2; Window *w; - [self insert: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; + [objects insert: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; //wprintf (w.window, "%d %d %d %d\n", r.offset.x, r.offset.y, r.extent.width, r.ylen); return self; } @@ -70,14 +71,14 @@ arp_end (void) -draw { - [super draw]; + [objects draw]; [TextContext refresh]; return self; } -handleEvent: (qwaq_event_t *) event { - [screen handleEvent: event]; + [objects handleEvent: event]; if (event.what == qe_key && event.key == '\x18') { event.what = qe_command; event.message.command = qc_exit; diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h index b599a0c36..be251b243 100644 --- a/ruamoko/qwaq/qwaq-group.h +++ b/ruamoko/qwaq/qwaq-group.h @@ -31,8 +31,9 @@ typedef BOOL condition_func2 (id object, void *anObject, void *data); { Array *views; int focused; - TextContext *buffer; + id buffer; //FIXME id or sim } +-initWithContext: (id) context; //FIXME id or sim -insert: (View *) view; -remove: (View *) view; @end diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index 6b8296182..57a5eb8a6 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -66,11 +66,16 @@ @end @implementation Group --init + +-initWithContext: (id) context { if (!(self = [super init])) { return nil; } + textContext = context; + absRect = rect = { nil, [textContext size] }; + printf ("\n\nsize:%d %d\n\n", rect.extent.width, rect.extent.height); + buffer = [DrawBuffer buffer: rect.extent]; views = [[Array array] retain]; return self; } @@ -92,6 +97,7 @@ -insert: (View *) view { [views addObject: view]; + view.textContext = buffer; return self; } @@ -114,13 +120,8 @@ not_dont_draw (id aView, void *aGroup) { View *view = aView; Group *group = (Group *) aGroup; - if (!(view.options & ofDontDraw)) { - if (!view.textContext) { - view.textContext = group.buffer; - } - return YES; - } - return NO; + + return !(view.options & ofDontDraw); } -draw diff --git a/ruamoko/qwaq/qwaq-screen.h b/ruamoko/qwaq/qwaq-screen.h index c51910d0e..9ec2ba8f3 100644 --- a/ruamoko/qwaq/qwaq-screen.h +++ b/ruamoko/qwaq/qwaq-screen.h @@ -10,7 +10,6 @@ } +(Screen *) screen; -handleEvent: (qwaq_event_t *) event; --setBackground: (int) ch; @end #endif//__qwaq_screen_h diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index 5b2db43ce..16d3f1be6 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -29,20 +29,14 @@ -draw { - update_panels (); - [TextContext doupdate]; return self; } -redraw { - [textContext refresh]; - return self; -} - --setBackground: (int) ch -{ - [textContext bkgd:ch]; + //update_panels (); + [TextContext refresh]; + //[TextContext doupdate]; return self; } diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index 086b9d12d..e6b5bd47e 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -57,6 +57,7 @@ enum { -(struct Rect_s *)getRect; -draw; -redraw; +-handleEvent: (qwaq_event_t *) event; - (void) refresh; - (void) mvprintf: (Point) pos, string fmt, ...; diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 19df51b9c..b005dd4de 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -126,5 +126,9 @@ updateScreenCursor (View *view) [textContext mvaddch: pos, ch]; } +-handleEvent: (qwaq_event_t *) event +{ + return self; +} @end From fea6381574f888cd625823a523c14070fe99bd49 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 20:44:43 +0900 Subject: [PATCH 350/444] [gamecode] Rework debug type handling a little Type encodings are used whenever they are available. For now, if they are not, then everything is treated as void (which prints , not very useful). Most return statements and references to .return are now very readable (excluding structs), and only params going through "..." are a messy union. --- include/QF/pr_type.h | 2 +- libs/gamecode/pr_debug.c | 93 ++++++++++++++++++++++++++-------------- 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/include/QF/pr_type.h b/include/QF/pr_type.h index c7fbc4b9c..c9e45185c 100644 --- a/include/QF/pr_type.h +++ b/include/QF/pr_type.h @@ -109,7 +109,7 @@ typedef struct qfot_type_s { typedef struct qfot_type_encodings_s { pointer_t types; - pr_int_t size; + pr_uint_t size; } qfot_type_encodings_t; ///@} diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 9464c326c..979400244 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -83,6 +83,8 @@ typedef struct prdeb_resources_s { struct pr_lineno_s *linenos; pr_def_t *local_defs; pr_def_t *type_encodings_def; + qfot_type_t void_type; + qfot_type_t *type_encodings[ev_type_count]; } prdeb_resources_t; typedef struct { @@ -352,6 +354,10 @@ pr_debug_clear (progs_t *pr, void *data) pr->watch = 0; pr->wp_conditional = 0; pr->wp_val.integer_var = 0; + + for (int i = 0; i < ev_type_count; i++ ) { + res->type_encodings[i] = &res->void_type; + } } static file_t * @@ -420,7 +426,10 @@ PR_LoadDebug (progs_t *pr) pr_uint_t i; pr_def_t *def; pr_type_t *str = 0; + qfot_type_encodings_t *encodings = 0; pointer_t type_encodings = 0; + pointer_t type_ptr; + qfot_type_t *type; if (!pr_debug->int_val) return 1; @@ -508,8 +517,8 @@ PR_LoadDebug (progs_t *pr) } res->type_encodings_def = PR_FindGlobal (pr, ".type_encodings"); if (res->type_encodings_def) { - __auto_type encodings = &G_STRUCT (pr, qfot_type_encodings_t, - res->type_encodings_def->ofs); + encodings = &G_STRUCT (pr, qfot_type_encodings_t, + res->type_encodings_def->ofs); type_encodings = encodings->types; } for (i = 0; i < res->debug->num_locals; i++) { @@ -523,6 +532,16 @@ PR_LoadDebug (progs_t *pr) res->local_defs[i].type_encoding += type_encodings; } } + if (encodings) { + for (type_ptr = 4; type_ptr < encodings->size; + type_ptr += type->size) { + type = &G_STRUCT (pr, qfot_type_t, type_encodings + type_ptr); + if (type->meta == ty_basic + && type->t.type >= 0 && type->t.type < ev_type_count) { + res->type_encodings[type->t.type] = type; + } + } + } return 1; } @@ -729,19 +748,15 @@ get_aux_function (progs_t *pr) return res->auxfunction_map[func - pr->pr_functions]; } -static etype_t -get_etype (progs_t *pr, int typeptr) +static qfot_type_t * +get_type (prdeb_resources_t *res, int typeptr) { - qfot_type_t *type; + progs_t *pr = res->pr; if (!typeptr) { - return ev_void; + return &res->void_type; } - type = &G_STRUCT (pr, qfot_type_t, typeptr); - if (type->meta == ty_basic) { - return type->t.type; - } - return ev_void; + return &G_STRUCT (pr, qfot_type_t, typeptr); } pr_def_t * @@ -881,19 +896,19 @@ pr_debug_find_def (progs_t *pr, pr_int_t ofs) } static const char * -global_string (pr_debug_data_t *data, pointer_t ofs, etype_t etype, +global_string (pr_debug_data_t *data, pointer_t ofs, qfot_type_t *type, int contents) { progs_t *pr = data->pr; + prdeb_resources_t *res = pr->pr_debug_resources; dstring_t *dstr = data->dstr; pr_def_t *def = NULL; qfot_type_t dummy_type = { }; - qfot_type_t *type; const char *name = 0; dstring_clearstr (dstr); - if (etype == ev_short) { + if (type && type->meta == ty_basic && type->t.type == ev_short) { dsprintf (dstr, "%04x", (short) ofs); return dstr->str; } @@ -919,16 +934,17 @@ global_string (pr_debug_data_t *data, pointer_t ofs, etype_t etype, if (name) { dstring_appendstr (dstr, "("); } - if (def) { - if (!def->type_encoding) { - dummy_type.t.type = def->type; - type = &dummy_type; + if (!type) { + if (def) { + if (!def->type_encoding) { + dummy_type.t.type = def->type; + type = &dummy_type; + } else { + type = &G_STRUCT (pr, qfot_type_t, def->type_encoding); + } } else { - type = &G_STRUCT (pr, qfot_type_t, def->type_encoding); + type = &res->void_type; } - } else { - dummy_type.t.type = etype; - type = &dummy_type; } value_string (data, type, pr->pr_globals + ofs); if (name) { @@ -1118,7 +1134,7 @@ pr_debug_short_view (qfot_type_t *type, pr_type_t *value, void *_data) __auto_type data = (pr_debug_data_t *) _data; dstring_t *dstr = data->dstr; - dasprintf (dstr, "%d", (short)value->integer_var); + dasprintf (dstr, "%04x", (short)value->integer_var); } static void @@ -1232,8 +1248,9 @@ PR_Debug_Print (progs_t *pr, const char *expr) } print = parse_expression (pr, expr, 0); - if (print.type != ev_invalid) { - const char *s = global_string (&data, print.ofs, print.type, 1); + if (print.type_encoding) { + qfot_type_t *type = get_type (res, print.type_encoding); + const char *s = global_string (&data, print.ofs, type, 1); Sys_Printf ("[%d] = %s\n", print.ofs, s); } } @@ -1300,7 +1317,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) char mode = fmt[1], opchar = fmt[2]; unsigned parm_ind = 0; pr_int_t opval; - etype_t optype = ev_void; + qfot_type_t *optype = ev_void; func_t func; if (mode == 'P') { @@ -1314,15 +1331,15 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) switch (opchar) { case 'a': opval = s->a; - optype = op->type_a; + optype = res->type_encodings[op->type_a]; break; case 'b': opval = s->b; - optype = op->type_b; + optype = res->type_encodings[op->type_b]; break; case 'c': opval = s->c; - optype = op->type_c; + optype = res->type_encodings[op->type_c]; break; case 'x': if (mode == 'P') { @@ -1337,8 +1354,9 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) case 'R': optype = ev_void; aux_func = get_aux_function (pr); - if (aux_func) - optype = get_etype (pr, aux_func->return_type); + if (aux_func) { + optype = get_type (res, aux_func->return_type); + } str = global_string (&data, opval, optype, contents & 1); break; @@ -1353,8 +1371,9 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) case 'P': parm_def = PR_Get_Param_Def (pr, call_func, parm_ind); optype = ev_void; - if (parm_def) - optype = parm_def->type; + if (parm_def) { + optype = get_type (res, parm_def->type_encoding); + } str = global_string (&data, opval, optype, contents & 1); break; @@ -1561,6 +1580,14 @@ PR_Debug_Init (progs_t *pr) res->line = dstring_newstr (); res->dstr = dstring_newstr (); + res->void_type.meta = ty_basic; + res->void_type.size = 4; + res->void_type.encoding = 0; + res->void_type.t.type = ev_void; + for (int i = 0; i < ev_type_count; i++ ) { + res->type_encodings[i] = &res->void_type; + } + PR_Resources_Register (pr, "PR_Debug", res, pr_debug_clear); if (!file_hash) { file_hash = Hash_NewTable (1024, file_get_key, file_free, 0); From 9492f08536908e3ed01486d2dafe8e3312da9ddc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 21:03:01 +0900 Subject: [PATCH 351/444] [gamecode] Print structs as well as unions Much better :) --- libs/gamecode/pr_debug.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 979400244..c59a3968a 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -1147,16 +1147,8 @@ pr_debug_double_view (qfot_type_t *type, pr_type_t *value, void *_data) } static void -pr_debug_struct_view (qfot_type_t *type, pr_type_t *value, void *_data) -{ - __auto_type data = (pr_debug_data_t *) _data; - dstring_t *dstr = data->dstr; - - dstring_appendstr (dstr, ""); -} - -static void -pr_debug_union_view (qfot_type_t *type, pr_type_t *value, void *_data) +pr_dump_struct (qfot_type_t *type, pr_type_t *value, void *_data, + const char *struct_type) { __auto_type data = (pr_debug_data_t *) _data; progs_t *pr = data->pr; @@ -1170,12 +1162,23 @@ pr_debug_union_view (qfot_type_t *type, pr_type_t *value, void *_data) pr_type_t *val = value + field->offset; dasprintf (dstr, "%s=", PR_GetString (pr, field->name)); value_string (data, val_type, val); - if (i < strct->num_fields) { + if (i < strct->num_fields - 1) { dstring_appendstr (dstr, ", "); } } dstring_appendstr (dstr, "}"); - dstring_appendstr (dstr, ""); + //dasprintf (dstr, "<%s>", struct_type); +} +static void +pr_debug_struct_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + pr_dump_struct (type, value, _data, "struct"); +} + +static void +pr_debug_union_view (qfot_type_t *type, pr_type_t *value, void *_data) +{ + pr_dump_struct (type, value, _data, "union"); } static void From 327d6929928741711673ecda854232825e24cbe7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 22:04:33 +0900 Subject: [PATCH 352/444] [qfcc] Correct order of @zero fields This is part of what messed up float_val in the encoding for @params. The other part is something in the linker type encoding merge code: it may be too aggressive. It's also what messed up the size of @params. --- tools/qfcc/source/type.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index 1c21e1d62..cdf7ca6df 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -937,7 +937,6 @@ init_types (void) { static struct_def_t zero_struct[] = { {"string_val", &type_string}, - {"double_val", &type_double}, {"float_val", &type_float}, {"entity_val", &type_entity}, {"field_val", &type_field}, @@ -949,6 +948,7 @@ init_types (void) {"integer_val", &type_integer}, {"uinteger_val", &type_uinteger}, {"quaternion_val", &type_quaternion}, + {"double_val", &type_double}, {0, 0} }; static struct_def_t param_struct[] = { From 20fd5eb80c6d580e2533f1ca9e95e18ab676dd0a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 22:07:36 +0900 Subject: [PATCH 353/444] [qfcc] Show def size when dumping defs --- tools/qfcc/source/dump_globals.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/dump_globals.c b/tools/qfcc/source/dump_globals.c index 157635f63..9b5900454 100644 --- a/tools/qfcc/source/dump_globals.c +++ b/tools/qfcc/source/dump_globals.c @@ -153,8 +153,9 @@ dump_def (progs_t *pr, pr_def_t *def, int indent) break; } } - printf ("%*s %x %d %s %s:%x %s\n", indent * 12, "", - offset, saveglobal, name, type, def->type_encoding, comment); + printf ("%*s %x:%d %d %s %s:%x %s\n", indent * 12, "", + offset, def->size, saveglobal, name, type, def->type_encoding, + comment); } void From 067bc264fafc175c314fb53d5d3d81cfa661a394 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 22:08:27 +0900 Subject: [PATCH 354/444] [qfcc] Set local def size in debug sym file It was getting random garbage. Not good for debuggers. --- tools/qfcc/source/obj_file.c | 1 + tools/qfcc/source/qfcc.c | 8 +++++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 6ceb1a74e..1a63eeea8 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -1172,6 +1172,7 @@ qfo_to_sym (qfo_t *qfo, int *size) aux->local_defs = ld - locals; for (j = 0; j < num_locals; j++, def++, ld++) { ld->type = get_def_type (qfo, def->type); + ld->size = get_type_size (qfo, def->type); ld->ofs = def->offset; ld->name = def->name; ld->type_encoding = def->type; diff --git a/tools/qfcc/source/qfcc.c b/tools/qfcc/source/qfcc.c index 6a7e1a039..7d0f8c800 100644 --- a/tools/qfcc/source/qfcc.c +++ b/tools/qfcc/source/qfcc.c @@ -448,7 +448,12 @@ finish_link (void) } else { int size; dprograms_t *progs; + pr_debug_header_t *sym = 0; + int sym_size = 0; + if (options.code.debug) { + sym = qfo_to_sym (qfo, &sym_size); + } progs = qfo_to_progs (qfo, &size); //finish_compilation (); @@ -462,9 +467,6 @@ finish_link (void) WriteProgs (progs, size); if (options.code.debug) { - pr_debug_header_t *sym; - int sym_size = 0; - sym = qfo_to_sym (qfo, &sym_size); sym->crc = CRC_Block ((byte *) progs, size); WriteSym (sym, sym_size); } From 2f9f6d3aa9a8f2c671559fb5f9d108b348aafc54 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sat, 14 Mar 2020 23:38:22 +0900 Subject: [PATCH 355/444] [gamecode] Relocate aux function return types They are written with offsets relative to the type encodings base. --- libs/gamecode/pr_debug.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index c59a3968a..31589e1e1 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -496,6 +496,12 @@ PR_LoadDebug (progs_t *pr) for (i = 0; i < pr->progs->numfunctions; i++) res->auxfunction_map[i] = 0; + res->type_encodings_def = PR_FindGlobal (pr, ".type_encodings"); + if (res->type_encodings_def) { + encodings = &G_STRUCT (pr, qfot_type_encodings_t, + res->type_encodings_def->ofs); + type_encodings = encodings->types; + } for (i = 0; i < res->debug->num_auxfunctions; i++) { res->auxfunctions[i].function = LittleLong (res->auxfunctions[i].function); @@ -508,6 +514,9 @@ PR_LoadDebug (progs_t *pr) res->auxfunctions[i].num_locals = LittleLong (res->auxfunctions[i].num_locals); + if (type_encodings) { + res->auxfunctions[i].return_type += type_encodings; + } res->auxfunction_map[res->auxfunctions[i].function] = &res->auxfunctions[i]; } @@ -515,12 +524,6 @@ PR_LoadDebug (progs_t *pr) res->linenos[i].fa.func = LittleLong (res->linenos[i].fa.func); res->linenos[i].line = LittleLong (res->linenos[i].line); } - res->type_encodings_def = PR_FindGlobal (pr, ".type_encodings"); - if (res->type_encodings_def) { - encodings = &G_STRUCT (pr, qfot_type_encodings_t, - res->type_encodings_def->ofs); - type_encodings = encodings->types; - } for (i = 0; i < res->debug->num_locals; i++) { res->local_defs[i].type = LittleShort (res->local_defs[i].type); res->local_defs[i].size = LittleShort (res->local_defs[i].size); @@ -1320,7 +1323,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) char mode = fmt[1], opchar = fmt[2]; unsigned parm_ind = 0; pr_int_t opval; - qfot_type_t *optype = ev_void; + qfot_type_t *optype = &res->void_type; func_t func; if (mode == 'P') { @@ -1355,7 +1358,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) } switch (mode) { case 'R': - optype = ev_void; + optype = &res->void_type; aux_func = get_aux_function (pr); if (aux_func) { optype = get_type (res, aux_func->return_type); @@ -1373,7 +1376,7 @@ PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents) break; case 'P': parm_def = PR_Get_Param_Def (pr, call_func, parm_ind); - optype = ev_void; + optype = &res->void_type; if (parm_def) { optype = get_type (res, parm_def->type_encoding); } From 9a08a51ebdcc61e12377b40593364f653606920b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 15 Mar 2020 01:32:38 +0900 Subject: [PATCH 356/444] [qfcc] Ensure progs defs are sorted by address --- tools/qfcc/source/obj_file.c | 50 +++++++++++++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/source/obj_file.c b/tools/qfcc/source/obj_file.c index 1a63eeea8..45d01be47 100644 --- a/tools/qfcc/source/obj_file.c +++ b/tools/qfcc/source/obj_file.c @@ -31,6 +31,8 @@ # include "config.h" #endif +#define _GNU_SOURCE // for qsort_r + #ifdef HAVE_STRING_H # include #endif @@ -860,6 +862,17 @@ align_globals_size (unsigned size) return RUP (size, 16 / sizeof (pr_type_t)); } +static int +qfo_def_compare (const void *i1, const void *i2, void *d) +{ + __auto_type defs = (const qfo_def_t *) d; + unsigned ind1 = *(unsigned *) i1; + unsigned ind2 = *(unsigned *) i2; + const qfo_def_t *def1 = defs + ind1; + const qfo_def_t *def2 = defs + ind2; + return def1->offset - def2->offset; +} + dprograms_t * qfo_to_progs (qfo_t *qfo, int *size) { @@ -887,6 +900,9 @@ qfo_to_progs (qfo_t *qfo, int *size) int big_func = 0; pr_xdefs_t *xdefs = 0; xdef_t *xdef; + unsigned *def_indices; + unsigned *far_def_indices; + unsigned *field_def_indices; *size = RUP (sizeof (dprograms_t), 16); progs = calloc (1, *size); @@ -895,7 +911,7 @@ qfo_to_progs (qfo_t *qfo, int *size) progs->numglobaldefs = qfo->spaces[qfo_near_data_space].num_defs; //ddef offsets are 16 bits so the ddef ofs will likely be invalid //thus it will be forced invalid and the true offset written to the - //symbols file if it is created (fa + //.xdefs array in the progs file progs->numglobaldefs += qfo->spaces[qfo_far_data_space].num_defs; progs->numfielddefs = qfo->spaces[qfo_entity_space].num_defs; progs->numfunctions = qfo->num_funcs + 1; @@ -936,6 +952,29 @@ qfo_to_progs (qfo_t *qfo, int *size) memset (progs + 1, 0, *size - sizeof (dprograms_t)); data += RUP (sizeof (dprograms_t), 16); + def_indices = alloca ((progs->numglobaldefs + progs->numfielddefs) + * sizeof (*def_indices)); + far_def_indices = def_indices + qfo->spaces[qfo_near_data_space].num_defs; + field_def_indices = def_indices + progs->numglobaldefs; + for (unsigned i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++) { + def_indices[i] = i; + } + for (unsigned i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++) { + far_def_indices[i] = i; + } + for (unsigned i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++) { + field_def_indices[i] = i; + } + qsort_r (def_indices, qfo->spaces[qfo_near_data_space].num_defs, + sizeof (unsigned), qfo_def_compare, + qfo->spaces[qfo_near_data_space].defs); + qsort_r (far_def_indices, qfo->spaces[qfo_far_data_space].num_defs, + sizeof (unsigned), qfo_def_compare, + qfo->spaces[qfo_far_data_space].defs); + qsort_r (field_def_indices, qfo->spaces[qfo_entity_space].num_defs, + sizeof (unsigned), qfo_def_compare, + qfo->spaces[qfo_entity_space].defs); + progs->ofs_strings = data - (byte *) progs; strings = (char *) data; data += RUP (progs->numstrings * sizeof (char), 16); @@ -992,7 +1031,8 @@ qfo_to_progs (qfo_t *qfo, int *size) } for (i = 0; i < qfo->spaces[qfo_near_data_space].num_defs; i++) { - qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + i; + unsigned ind = def_indices[i]; + qfo_def_t *def = qfo->spaces[qfo_near_data_space].defs + ind; const char *defname = QFO_GETSTR (qfo, def->name); if (!strcmp (defname, ".type_encodings")) types_def = def; @@ -1002,7 +1042,8 @@ qfo_to_progs (qfo_t *qfo, int *size) } for (i = 0; i < qfo->spaces[qfo_far_data_space].num_defs; i++) { - qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + i; + unsigned ind = far_def_indices[i]; + qfo_def_t *def = qfo->spaces[qfo_far_data_space].defs + ind; def->offset += far_data - globals; convert_def (qfo, def, globaldefs); // the correct offset will be written to the far data space @@ -1015,7 +1056,8 @@ qfo_to_progs (qfo_t *qfo, int *size) } for (i = 0; i < qfo->spaces[qfo_entity_space].num_defs; i++) { - convert_def (qfo, qfo->spaces[qfo_entity_space].defs + i, + unsigned ind = field_def_indices[i]; + convert_def (qfo, qfo->spaces[qfo_entity_space].defs + ind, fielddefs + i); } From 968de155a1c08fc2dd4e3f3e6836c42e26e33c20 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 15 Mar 2020 01:33:25 +0900 Subject: [PATCH 357/444] [qfcc] Make some counts unsigned How do you have -1 def? --- tools/qfcc/include/obj_file.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/qfcc/include/obj_file.h b/tools/qfcc/include/obj_file.h index ae1986245..62d7b80f0 100644 --- a/tools/qfcc/include/obj_file.h +++ b/tools/qfcc/include/obj_file.h @@ -60,13 +60,13 @@ */ typedef struct qfo_header_s { int8_t qfo[4]; ///< identifier string (includes nul) (#QFO) - pr_int_t version; ///< QFO format version (#QFO_VERSION) - pr_int_t num_spaces; - pr_int_t num_relocs; ///< number of relocation records - pr_int_t num_defs; ///< number of def records - pr_int_t num_funcs; ///< number of function records - pr_int_t num_lines; ///< number of line records - pr_int_t num_loose_relocs; ///< number of loose relocation records + pr_uint_t version; ///< QFO format version (#QFO_VERSION) + pr_uint_t num_spaces; + pr_uint_t num_relocs; ///< number of relocation records + pr_uint_t num_defs; ///< number of def records + pr_uint_t num_funcs; ///< number of function records + pr_uint_t num_lines; ///< number of line records + pr_uint_t num_loose_relocs; ///< number of loose relocation records ///< (included in num_relocs) } qfo_header_t; From 3d62a7f25377c3b31efedc3a3211146d1d156a5e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 15 Mar 2020 02:48:13 +0900 Subject: [PATCH 358/444] [gamecode] Use fuzzy bsearch to find defs by address The idea is to find th def that contains the address. Had to write my own bsearch (well... lifted from wikipedia) because libc's is exact. The defs are assumed to be sorted (which qfcc now ensures when it writes progs and sym files). --- include/QF/progs.h | 2 ++ libs/gamecode/pr_resolve.c | 42 ++++++++++++++++++++++---------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 2659ce303..7dc7e4af2 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -321,6 +321,8 @@ void ED_EntityParseFunction (progs_t *pr); */ ///@{ +pr_def_t *PR_SearchDefs (pr_def_t *defs, unsigned num_defs, pointer_t offset) + __attribute__((pure)); pr_def_t *PR_FieldAtOfs (progs_t *pr, pointer_t ofs) __attribute__((pure)); pr_def_t *PR_GlobalAtOfs (progs_t *pr, pointer_t ofs) __attribute__((pure)); diff --git a/libs/gamecode/pr_resolve.c b/libs/gamecode/pr_resolve.c index 5297f101a..03e6949a2 100644 --- a/libs/gamecode/pr_resolve.c +++ b/libs/gamecode/pr_resolve.c @@ -43,32 +43,38 @@ static const char param_str[] = ".param_0"; +pr_def_t * +PR_SearchDefs (pr_def_t *defs, unsigned num_defs, pointer_t offset) +{ + // fuzzy bsearh + unsigned left = 0; + unsigned right = num_defs - 1; + unsigned mid; + + while (left != right) { + mid = (left + right + 1) / 2; + if (defs[mid].ofs > offset) { + right = mid - 1; + } else { + left = mid; + } + } + if (defs[left].ofs <= offset) { + return defs + left; + } + return 0; +} + pr_def_t * PR_GlobalAtOfs (progs_t * pr, pointer_t ofs) { - pr_def_t *def; - pr_uint_t i; - - for (i = 0; i < pr->progs->numglobaldefs; i++) { - def = &pr->pr_globaldefs[i]; - if (def->ofs == ofs) - return def; - } - return NULL; + return PR_SearchDefs (pr->pr_globaldefs, pr->progs->numglobaldefs, ofs); } VISIBLE pr_def_t * PR_FieldAtOfs (progs_t * pr, pointer_t ofs) { - pr_def_t *def; - pr_uint_t i; - - for (i = 0; i < pr->progs->numfielddefs; i++) { - def = &pr->pr_fielddefs[i]; - if (def->ofs == ofs) - return def; - } - return NULL; + return PR_SearchDefs (pr->pr_fielddefs, pr->progs->numfielddefs, ofs); } VISIBLE pr_def_t * From 99f89840f9290aeb465a4b2985ced2ce9f15add0 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 15 Mar 2020 02:51:29 +0900 Subject: [PATCH 359/444] [gamecode] Show containing def and relative offset No more guessing when accessing structure field members. Next is ivars, I guess. --- include/QF/progs.h | 2 +- libs/gamecode/pr_debug.c | 70 ++++++++++++++++++++++++---------------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/include/QF/progs.h b/include/QF/progs.h index 7dc7e4af2..c615e6d14 100644 --- a/include/QF/progs.h +++ b/include/QF/progs.h @@ -1649,7 +1649,7 @@ pr_lineno_t *PR_Find_Lineno (progs_t *pr, pr_uint_t addr) __attribute__((pure)); const char *PR_Get_Source_File (progs_t *pr, pr_lineno_t *lineno) __attribute__((pure)); const char *PR_Get_Source_Line (progs_t *pr, pr_uint_t addr); pr_def_t *PR_Get_Param_Def (progs_t *pr, dfunction_t *func, unsigned parm) __attribute__((pure)); -pr_def_t *PR_Get_Local_Def (progs_t *pr, pointer_t offs) __attribute__((pure)); +pr_def_t *PR_Get_Local_Def (progs_t *pr, pointer_t *offs) __attribute__((pure)); void PR_PrintStatement (progs_t *pr, dstatement_t *s, int contents); void PR_DumpState (progs_t *pr); void PR_StackTrace (progs_t *pr); diff --git a/libs/gamecode/pr_debug.c b/libs/gamecode/pr_debug.c index 31589e1e1..d2ed5e7f1 100644 --- a/libs/gamecode/pr_debug.c +++ b/libs/gamecode/pr_debug.c @@ -763,12 +763,13 @@ get_type (prdeb_resources_t *res, int typeptr) } pr_def_t * -PR_Get_Local_Def (progs_t *pr, pointer_t offs) +PR_Get_Local_Def (progs_t *pr, pointer_t *offset) { prdeb_resources_t *res = pr->pr_debug_resources; - pr_uint_t i; dfunction_t *func; pr_auxfunction_t *aux_func; + pointer_t offs = *offset; + pr_def_t *def; if (!pr->pr_xfunction) return 0; @@ -781,10 +782,11 @@ PR_Get_Local_Def (progs_t *pr, pointer_t offs) offs -= func->parm_start; if (offs >= func->locals) return 0; - for (i = 0; i < aux_func->num_locals; i++) - if (res->local_defs[aux_func->local_defs + i].ofs == offs) - return &res->local_defs[aux_func->local_defs + i]; - return 0; + if ((def = PR_SearchDefs (res->local_defs + aux_func->local_defs, + aux_func->num_locals, offs))) { + *offset = offs - def->ofs; + } + return def; } VISIBLE void @@ -886,20 +888,28 @@ value_string (pr_debug_data_t *data, qfot_type_t *type, pr_type_t *value) } static pr_def_t * -pr_debug_find_def (progs_t *pr, pr_int_t ofs) +pr_debug_find_def (progs_t *pr, pointer_t *ofs) { prdeb_resources_t *res = pr->pr_debug_resources; pr_def_t *def = 0; - if (pr_debug->int_val && res->debug) + if (*ofs >= pr->progs->numglobals) { + return 0; + } + if (pr_debug->int_val && res->debug) { def = PR_Get_Local_Def (pr, ofs); - if (!def) - def = PR_GlobalAtOfs (pr, ofs); + } + if (!def) { + def = PR_GlobalAtOfs (pr, *ofs); + if (def) { + *ofs -= def->ofs; + } + } return def; } static const char * -global_string (pr_debug_data_t *data, pointer_t ofs, qfot_type_t *type, +global_string (pr_debug_data_t *data, pointer_t offset, qfot_type_t *type, int contents) { progs_t *pr = data->pr; @@ -908,29 +918,34 @@ global_string (pr_debug_data_t *data, pointer_t ofs, qfot_type_t *type, pr_def_t *def = NULL; qfot_type_t dummy_type = { }; const char *name = 0; + pointer_t offs = offset; dstring_clearstr (dstr); if (type && type->meta == ty_basic && type->t.type == ev_short) { - dsprintf (dstr, "%04x", (short) ofs); + dsprintf (dstr, "%04x", (short) offset); return dstr->str; } - if (ofs > pr->globals_size) { - dsprintf (dstr, "%08x out of bounds", ofs); + if (offset > pr->globals_size) { + dsprintf (dstr, "%08x out of bounds", offset); return dstr->str; } - def = pr_debug_find_def (pr, ofs); + def = pr_debug_find_def (pr, &offs); if (!def || !PR_StringValid (pr, def->name) || !*(name = PR_GetString (pr, def->name))) { - dsprintf (dstr, "[$%x]", ofs); + dsprintf (dstr, "[$%x]", offset); } if (name) { if (strequal (name, "IMMEDIATE") || strequal (name, ".imm")) { contents = 1; } else { - dsprintf (dstr, "%s", name); + if (offs) { + dsprintf (dstr, "{%s + %u}", name, offs); + } else { + dsprintf (dstr, "%s", name); + } } } if (contents) { @@ -949,7 +964,7 @@ global_string (pr_debug_data_t *data, pointer_t ofs, qfot_type_t *type, type = &res->void_type; } } - value_string (data, type, pr->pr_globals + ofs); + value_string (data, type, pr->pr_globals + offset); if (name) { dstring_appendstr (dstr, ")"); } @@ -1084,21 +1099,20 @@ pr_debug_pointer_view (qfot_type_t *type, pr_type_t *value, void *_data) { __auto_type data = (pr_debug_data_t *) _data; progs_t *pr = data->pr; - prdeb_resources_t *res = pr->pr_debug_resources; //FIXME dstring_t *dstr = data->dstr; - pointer_t ofs = value->integer_var; + pointer_t offset = value->integer_var; + pointer_t offs = offset; pr_def_t *def = 0; - if (pr_debug->int_val && res->debug) { - def = PR_Get_Local_Def (pr, ofs); - } - if (!def) { - def = PR_GlobalAtOfs (pr, ofs); - } + def = pr_debug_find_def (pr, &offs); if (def && def->name) { - dasprintf (dstr, "&%s", PR_GetString (pr, def->name)); + if (offs) { + dasprintf (dstr, "&%s + %u", PR_GetString (pr, def->name), offs); + } else { + dasprintf (dstr, "&%s", PR_GetString (pr, def->name)); + } } else { - dasprintf (dstr, "[$%x]", ofs); + dasprintf (dstr, "[$%x]", offset); } } From e3a1413ad3b1a30eb4ee9d8be23044548fd31116 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 15 Mar 2020 10:06:37 +0900 Subject: [PATCH 360/444] [gamecode] Tweak output for lea --- libs/gamecode/pr_opcode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/gamecode/pr_opcode.c b/libs/gamecode/pr_opcode.c index 3d3e8fe17..30ad8b06e 100644 --- a/libs/gamecode/pr_opcode.c +++ b/libs/gamecode/pr_opcode.c @@ -544,12 +544,12 @@ VISIBLE const opcode_t pr_opcodes[] = { {"&", "lea", OP_LEA, false, ev_pointer, ev_integer, ev_pointer, PROG_VERSION, - "%Ga, %Gb, %gc", + "(%Ga + %Gb), %gc", }, {"&", "leai", OP_LEAI, false, ev_pointer, ev_short, ev_pointer, PROG_VERSION, - "%Ga, %sb, %gc", + "(%Ga + %sb), %gc", }, {"", "conv.if", OP_CONV_IF, false, From e1140d476aa3f9c14cfa13ee1cc8e918fdc3fd24 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 15 Mar 2020 16:19:45 +0900 Subject: [PATCH 361/444] [qfcc] Handle syntax errors in method protos --- tools/qfcc/source/qc-parse.y | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 6ca42392c..7f257505b 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -2020,6 +2020,10 @@ methodproto $2->instance = 0; $$ = $2; } + | '-' error ';' + { $$ = new_method (&type_id, new_param ("", 0, 0), 0); } + | '+' error ';' + { $$ = new_method (&type_id, new_param ("", 0, 0), 0); } | '-' methoddecl ';' { $2->instance = 1; From fb33a7f2a7df64dec778ba55eaedb987f894712b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 15 Mar 2020 20:27:43 +0900 Subject: [PATCH 362/444] [qfcc] Remove "impossible" code It is not possible to adorn Class with protocols, so no need to check for them when checking if a type is a class. --- tools/qfcc/include/class.h | 2 +- tools/qfcc/source/class.c | 9 --------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index 7f7f0920d..a468e19b5 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -116,7 +116,7 @@ struct symbol_s; int obj_is_id (const struct type_s *type) __attribute__((pure)); int obj_is_class (const struct type_s *type) __attribute__((pure)); -int obj_is_Class (const struct type_s *type) __attribute__((pure)); +int obj_is_Class (const struct type_s *type) __attribute__((const)); int obj_is_classptr (const struct type_s *type) __attribute__((pure)); int obj_types_assignable (const struct type_s *dst, const struct type_s *src); diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index 647a64716..d1322c174 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -345,15 +345,6 @@ obj_is_Class (const type_t *type) { if (type == &type_Class) return 1; - // type may be a qualified Class, in which case it will be a pointer to - // a qualified obj_class struct - if (type->type != ev_pointer) - return 0; - if (!is_struct (type->t.fldptr.type)) - return 0; - // if the the symtabs match, then type is Class in disguise - if (type->t.fldptr.type->t.symtab == type_obj_class.t.symtab) - return 1; return 0; } From ea042cf87aba79500da216a23df2f33fb146b035 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 15 Mar 2020 20:50:04 +0900 Subject: [PATCH 363/444] [qfcc] Split out the obj-qc specific expr code --- tools/qfcc/source/Makefile.am | 2 +- tools/qfcc/source/expr.c | 200 ------------------------- tools/qfcc/source/expr_obj.c | 266 ++++++++++++++++++++++++++++++++++ 3 files changed, 267 insertions(+), 201 deletions(-) create mode 100644 tools/qfcc/source/expr_obj.c diff --git a/tools/qfcc/source/Makefile.am b/tools/qfcc/source/Makefile.am index cfd31afbc..bbaf06ee6 100644 --- a/tools/qfcc/source/Makefile.am +++ b/tools/qfcc/source/Makefile.am @@ -41,7 +41,7 @@ bin_SCRIPTS= qfpreqcc common_src=\ class.c codespace.c constfold.c cpp.c dags.c debug.c def.c defspace.c \ diagnostic.c dot.c dot_dag.c dot_expr.c dot_flow.c dot_sblock.c emit.c \ - expr.c expr_assign.c expr_binary.c expr_bool.c expr_compound.c \ + expr.c expr_assign.c expr_binary.c expr_bool.c expr_compound.c expr_obj.c \ flow.c function.c grab.c \ idstuff.c \ linker.c method.c \ diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 72624364c..8a702714d 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1099,28 +1099,6 @@ expr_short (expr_t *e) internal_error (e, "not a short constant"); } -expr_t * -new_self_expr (void) -{ - symbol_t *sym; - - sym = make_symbol (".self", &type_entity, pr.near_data, sc_extern); - if (!sym->table) - symtab_addsymbol (pr.symtab, sym); - return new_symbol_expr (sym); -} - -expr_t * -new_this_expr (void) -{ - symbol_t *sym; - - sym = make_symbol (".this", field_type (&type_id), pr.near_data, sc_extern); - if (!sym->table) - symtab_addsymbol (pr.symtab, sym); - return new_symbol_expr (sym); -} - expr_t * new_alias_expr (type_t *type, expr_t *expr) { @@ -2579,51 +2557,6 @@ cast_expr (type_t *dstType, expr_t *e) return c; } -expr_t * -selector_expr (keywordarg_t *selector) -{ - dstring_t *sel_id = dstring_newstr (); - expr_t *sel; - symbol_t *sel_sym; - symbol_t *sel_table; - int index; - - selector = copy_keywordargs (selector); - selector = (keywordarg_t *) reverse_params ((param_t *) selector); - selector_name (sel_id, selector); - index = selector_index (sel_id->str); - index *= type_size (type_SEL.t.fldptr.type); - sel_sym = make_symbol ("_OBJ_SELECTOR_TABLE_PTR", &type_SEL, - pr.near_data, sc_static); - if (!sel_sym->table) { - symtab_addsymbol (pr.symtab, sel_sym); - sel_table = make_symbol ("_OBJ_SELECTOR_TABLE", - array_type (type_SEL.t.fldptr.type, 0), - pr.far_data, sc_extern); - if (!sel_table->table) - symtab_addsymbol (pr.symtab, sel_table); - reloc_def_def (sel_table->s.def, sel_sym->s.def); - } - sel = new_symbol_expr (sel_sym); - dstring_delete (sel_id); - sel = new_binary_expr ('&', sel, new_short_expr (index)); - sel->e.expr.type = &type_SEL; - return sel; -} - -expr_t * -protocol_expr (const char *protocol_name) -{ - protocol_t *protocol = get_protocol (protocol_name, 0); - - if (!protocol) { - return error (0, "cannot find protocol declaration for `%s'", - protocol_name); - } - class_t *proto_class = get_class (new_symbol ("Protocol"), 1); - return new_pointer_expr (0, proto_class->type, protocol_def (protocol)); -} - expr_t * encode_expr (type_t *type) { @@ -2636,139 +2569,6 @@ encode_expr (type_t *type) return e; } -expr_t * -super_expr (class_type_t *class_type) -{ - symbol_t *sym; - expr_t *super; - expr_t *e; - expr_t *super_block; - class_t *class; - - if (!class_type) - return error (0, "`super' used outside of class implementation"); - - class = extract_class (class_type); - - if (!class->super_class) - return error (0, "%s has no super class", class->name); - - sym = symtab_lookup (current_symtab, ".super"); - if (!sym || sym->table != current_symtab) { - sym = new_symbol_type (".super", &type_obj_super); - initialize_def (sym, 0, current_symtab->space, sc_local); - } - super = new_symbol_expr (sym); - - super_block = new_block_expr (); - - e = assign_expr (field_expr (super, new_name_expr ("self")), - new_name_expr ("self")); - append_expr (super_block, e); - - e = new_symbol_expr (class_pointer_symbol (class)); - e = assign_expr (field_expr (super, new_name_expr ("class")), - field_expr (e, new_name_expr ("super_class"))); - append_expr (super_block, e); - - e = address_expr (super, 0, 0); - super_block->e.block.result = e; - return super_block; -} - -expr_t * -message_expr (expr_t *receiver, keywordarg_t *message) -{ - expr_t *args = 0, **a = &args; - expr_t *selector = selector_expr (message); - expr_t *call; - keywordarg_t *m; - int self = 0, super = 0, class_msg = 0; - type_t *rec_type; - type_t *return_type; - type_t *method_type = &type_IMP; - class_t *class = 0; - method_t *method; - expr_t *send_msg; - - if (receiver->type == ex_symbol - && strcmp (receiver->e.symbol->name, "super") == 0) { - super = 1; - - receiver = super_expr (current_class); - - if (receiver->type == ex_error) - return receiver; - receiver = cast_expr (&type_id, receiver); //FIXME better way? - class = extract_class (current_class); - } else { - if (receiver->type == ex_symbol) { - if (strcmp (receiver->e.symbol->name, "self") == 0) - self = 1; - if (receiver->e.symbol->sy_type == sy_class) { - class = receiver->e.symbol->type->t.class; - class_msg = 1; - receiver = new_symbol_expr (class_pointer_symbol (class)); - } - } else if (receiver->type == ex_nil) { - convert_nil (receiver, &type_id); - } - rec_type = get_type (receiver); - - if (receiver->type == ex_error) - return receiver; - - if (rec_type == &type_id || rec_type == &type_Class) { - } else { - if (rec_type->type == ev_pointer) - rec_type = rec_type->t.fldptr.type; - if (!obj_is_class (rec_type)) - return error (receiver, "not a class/object"); - - if (self) { - if (!class) - class = extract_class (current_class); - if (rec_type == &type_obj_class) - class_msg = 1; - } else { - if (!class) - class = rec_type->t.class; - } - } - } - - return_type = &type_id; - method = class_message_response (class, class_msg, selector); - if (method) - return_type = method->type->t.func.type; - - for (m = message; m; m = m->next) { - *a = m->expr; - while ((*a)) { - expr_file_line (selector, *a); - a = &(*a)->next; - } - } - *a = selector; - a = &(*a)->next; - *a = receiver; - - send_msg = expr_file_line (send_message (super), receiver); - if (method) { - expr_t *err; - if ((err = method_check_params (method, args))) - return err; - method_type = method->type; - } - call = build_function_call (send_msg, method_type, args); - - if (call->type == ex_error) - return receiver; - - call->e.block.result = new_ret_expr (return_type); - return call; -} - expr_t * sizeof_expr (expr_t *expr, struct type_s *type) { diff --git a/tools/qfcc/source/expr_obj.c b/tools/qfcc/source/expr_obj.c new file mode 100644 index 000000000..fe04e2c98 --- /dev/null +++ b/tools/qfcc/source/expr_obj.c @@ -0,0 +1,266 @@ +/* + expr_obj.c + + Objective-QuakeC expression construction and manipulations + + Copyright (C) 2001 Bill Currie + + Author: Bill Currie + Date: 2001/06/15 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#include + +#include "QF/alloc.h" +#include "QF/dstring.h" +#include "QF/mathlib.h" +#include "QF/sys.h" +#include "QF/va.h" + +#include "qfcc.h" +#include "class.h" +#include "def.h" +#include "defspace.h" +#include "diagnostic.h" +#include "emit.h" +#include "expr.h" +#include "function.h" +#include "idstuff.h" +#include "method.h" +#include "options.h" +#include "reloc.h" +#include "shared.h" +#include "strpool.h" +#include "struct.h" +#include "symtab.h" +#include "type.h" +#include "value.h" +#include "qc-parse.h" + +expr_t * +new_self_expr (void) +{ + symbol_t *sym; + + sym = make_symbol (".self", &type_entity, pr.near_data, sc_extern); + if (!sym->table) + symtab_addsymbol (pr.symtab, sym); + return new_symbol_expr (sym); +} + +expr_t * +new_this_expr (void) +{ + symbol_t *sym; + + sym = make_symbol (".this", field_type (&type_id), pr.near_data, sc_extern); + if (!sym->table) + symtab_addsymbol (pr.symtab, sym); + return new_symbol_expr (sym); +} + +expr_t * +selector_expr (keywordarg_t *selector) +{ + dstring_t *sel_id = dstring_newstr (); + expr_t *sel; + symbol_t *sel_sym; + symbol_t *sel_table; + int index; + + selector = copy_keywordargs (selector); + selector = (keywordarg_t *) reverse_params ((param_t *) selector); + selector_name (sel_id, selector); + index = selector_index (sel_id->str); + index *= type_size (type_SEL.t.fldptr.type); + sel_sym = make_symbol ("_OBJ_SELECTOR_TABLE_PTR", &type_SEL, + pr.near_data, sc_static); + if (!sel_sym->table) { + symtab_addsymbol (pr.symtab, sel_sym); + sel_table = make_symbol ("_OBJ_SELECTOR_TABLE", + array_type (type_SEL.t.fldptr.type, 0), + pr.far_data, sc_extern); + if (!sel_table->table) + symtab_addsymbol (pr.symtab, sel_table); + reloc_def_def (sel_table->s.def, sel_sym->s.def); + } + sel = new_symbol_expr (sel_sym); + dstring_delete (sel_id); + sel = new_binary_expr ('&', sel, new_short_expr (index)); + sel->e.expr.type = &type_SEL; + return sel; +} + +expr_t * +protocol_expr (const char *protocol_name) +{ + protocol_t *protocol = get_protocol (protocol_name, 0); + + if (!protocol) { + return error (0, "cannot find protocol declaration for `%s'", + protocol_name); + } + class_t *proto_class = get_class (new_symbol ("Protocol"), 1); + return new_pointer_expr (0, proto_class->type, protocol_def (protocol)); +} + +expr_t * +super_expr (class_type_t *class_type) +{ + symbol_t *sym; + expr_t *super; + expr_t *e; + expr_t *super_block; + class_t *class; + + if (!class_type) + return error (0, "`super' used outside of class implementation"); + + class = extract_class (class_type); + + if (!class->super_class) + return error (0, "%s has no super class", class->name); + + sym = symtab_lookup (current_symtab, ".super"); + if (!sym || sym->table != current_symtab) { + sym = new_symbol_type (".super", &type_obj_super); + initialize_def (sym, 0, current_symtab->space, sc_local); + } + super = new_symbol_expr (sym); + + super_block = new_block_expr (); + + e = assign_expr (field_expr (super, new_name_expr ("self")), + new_name_expr ("self")); + append_expr (super_block, e); + + e = new_symbol_expr (class_pointer_symbol (class)); + e = assign_expr (field_expr (super, new_name_expr ("class")), + field_expr (e, new_name_expr ("super_class"))); + append_expr (super_block, e); + + e = address_expr (super, 0, 0); + super_block->e.block.result = e; + return super_block; +} + +expr_t * +message_expr (expr_t *receiver, keywordarg_t *message) +{ + expr_t *args = 0, **a = &args; + expr_t *selector = selector_expr (message); + expr_t *call; + keywordarg_t *m; + int self = 0, super = 0, class_msg = 0; + type_t *rec_type; + type_t *return_type; + type_t *method_type = &type_IMP; + class_t *class = 0; + method_t *method; + expr_t *send_msg; + + if (receiver->type == ex_symbol + && strcmp (receiver->e.symbol->name, "super") == 0) { + super = 1; + + receiver = super_expr (current_class); + + if (receiver->type == ex_error) + return receiver; + receiver = cast_expr (&type_id, receiver); //FIXME better way? + class = extract_class (current_class); + } else { + if (receiver->type == ex_symbol) { + if (strcmp (receiver->e.symbol->name, "self") == 0) + self = 1; + if (receiver->e.symbol->sy_type == sy_class) { + class = receiver->e.symbol->type->t.class; + class_msg = 1; + receiver = new_symbol_expr (class_pointer_symbol (class)); + } + } else if (receiver->type == ex_nil) { + convert_nil (receiver, &type_id); + } + rec_type = get_type (receiver); + + if (receiver->type == ex_error) + return receiver; + + if (rec_type == &type_id || rec_type == &type_Class) { + } else { + if (rec_type->type == ev_pointer) + rec_type = rec_type->t.fldptr.type; + if (!obj_is_class (rec_type)) + return error (receiver, "not a class/object"); + + if (self) { + if (!class) + class = extract_class (current_class); + if (rec_type == &type_obj_class) + class_msg = 1; + } else { + if (!class) + class = rec_type->t.class; + } + } + } + + return_type = &type_id; + method = class_message_response (class, class_msg, selector); + if (method) + return_type = method->type->t.func.type; + + for (m = message; m; m = m->next) { + *a = m->expr; + while ((*a)) { + expr_file_line (selector, *a); + a = &(*a)->next; + } + } + *a = selector; + a = &(*a)->next; + *a = receiver; + + send_msg = expr_file_line (send_message (super), receiver); + if (method) { + expr_t *err; + if ((err = method_check_params (method, args))) + return err; + method_type = method->type; + } + call = build_function_call (send_msg, method_type, args); + + if (call->type == ex_error) + return receiver; + + call->e.block.result = new_ret_expr (return_type); + return call; +} From 0fe3fda44dd76e9648a3b1ec11b51296d38fc916 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Sun, 15 Mar 2020 23:30:57 +0900 Subject: [PATCH 364/444] [qfcc] Fix protocol adorned id as message receiver This took a bit as type_id has no class data, only protocols attached to the type_obj_object instance, and then protocol lists can get deep. --- tools/qfcc/include/class.h | 8 ++- tools/qfcc/include/method.h | 3 + tools/qfcc/source/class.c | 107 ++++++++++++++++++++++++++++------- tools/qfcc/source/expr_obj.c | 73 +++++++++--------------- tools/qfcc/source/method.c | 14 +++++ 5 files changed, 138 insertions(+), 67 deletions(-) diff --git a/tools/qfcc/include/class.h b/tools/qfcc/include/class.h index a468e19b5..68cefcd12 100644 --- a/tools/qfcc/include/class.h +++ b/tools/qfcc/include/class.h @@ -113,6 +113,7 @@ struct dstring_s; struct expr_s; struct method_s; struct symbol_s; +struct selector_s; int obj_is_id (const struct type_s *type) __attribute__((pure)); int obj_is_class (const struct type_s *type) __attribute__((pure)); @@ -141,7 +142,7 @@ void class_finish_ivar_scope (class_type_t *class_type, struct symtab_s *param_scope); struct method_s *class_find_method (class_type_t *class_type, struct method_s *method); -struct method_s *class_message_response (class_t *class, int class_msg, +struct method_s *class_message_response (struct type_s *clstype, int class_msg, struct expr_s *sel); struct symbol_s *class_pointer_symbol (class_t *class_type); category_t *get_category (struct symbol_s *class_name, @@ -161,6 +162,11 @@ struct def_s *protocol_def (protocol_t *protocol); protocollist_t *new_protocol_list (void); protocollist_t *add_protocol (protocollist_t *protocollist, const char *name); int procollist_find_protocol (protocollist_t *protocollist, protocol_t *proto) __attribute__((pure)); +struct method_s *protocollist_find_method (protocollist_t *protocollist, + struct selector_s *selector, + int nstance) + __attribute__((pure)); + int compare_protocols (protocollist_t *protos1, protocollist_t *protos2) __attribute__((pure)); void print_protocollist (struct dstring_s *dstr, protocollist_t *protocollist); struct def_s *emit_protocol (protocol_t *protocol); diff --git a/tools/qfcc/include/method.h b/tools/qfcc/include/method.h index c64f04ade..598e151ee 100644 --- a/tools/qfcc/include/method.h +++ b/tools/qfcc/include/method.h @@ -98,6 +98,9 @@ keywordarg_t *copy_keywordargs (const keywordarg_t *kwargs); struct expr_s *send_message (int super); method_t *find_method (const char *sel_name); +method_t *methodlist_find_method (methodlist_t *methodlist, + selector_t *selector, int instance) + __attribute__((pure)); void selector_name (struct dstring_s *sel_id, keywordarg_t *selector); void method_types (struct dstring_s *sel_types, method_t *method); diff --git a/tools/qfcc/source/class.c b/tools/qfcc/source/class.c index d1322c174..6f4473e1d 100644 --- a/tools/qfcc/source/class.c +++ b/tools/qfcc/source/class.c @@ -1104,42 +1104,79 @@ class_find_method (class_type_t *class_type, method_t *method) return method; } +static method_t * +cls_find_method (methodlist_t *methodlist, selector_t *selector, + int class_msg, int is_root) +{ + method_t *m = 0; + m = methodlist_find_method (methodlist, selector, !class_msg); + if (!m && is_root && class_msg + && (m = methodlist_find_method (methodlist, selector, 1))) { + return m; + } + return m; +} + method_t * -class_message_response (class_t *class, int class_msg, expr_t *sel) +class_message_response (type_t *clstype, int class_msg, expr_t *sel) { selector_t *selector; method_t *m; - class_t *c = class; + class_t *c; + class_t *class = 0; category_t *cat; + dstring_t *dstr; selector = get_selector (sel); if (!selector) return 0; - if (class && class->type != &type_obj_object) { - if (!class->interface_declared) { - class->interface_declared = 1; - warning (0, "cannot find interface declaration for `%s'", - class->name); + + if (!obj_is_classptr (clstype) && !obj_is_class (clstype)) { + error (0, "neither class nor object"); + return 0; + } + if (obj_is_id (clstype)) { + protocollist_t *protos = clstype->t.fldptr.type->protos; + if (protos) { + if ((m = protocollist_find_method (protos, selector, !class_msg))) { + return m; + } + dstr = dstring_new (); + print_protocollist (dstr, protos); + warning (sel, "id%s may not respond to %c%s", dstr->str, + class_msg ? '+' : '-', selector->name); + dstring_delete (dstr); } - while (c) { - for (cat = c->categories; cat; cat = cat->next) { - for (m = cat->methods->head; m; m = m->next) { - if (((!c->super_class && class_msg) - || class_msg != m->instance) - && strcmp (selector->name, m->name) == 0) + } else { + if (obj_is_class (clstype)) { + class = clstype->t.class; + } else if (obj_is_class (clstype->t.fldptr.type)) { + class = clstype->t.fldptr.type->t.class; + } + if (class && class->type != &type_obj_object) { + if (!class->interface_declared) { + class->interface_declared = 1; + warning (0, "cannot find interface declaration for `%s'", + class->name); + } + c = class; + while (c) { + for (cat = c->categories; cat; cat = cat->next) { + if ((m = cls_find_method (cat->methods, selector, + class_msg, + !c->super_class))) { return m; + } } - } - for (m = c->methods->head; m; m = m->next) { - if (((!c->super_class && class_msg) - || class_msg != m->instance) - && strcmp (selector->name, m->name) == 0) + if ((m = cls_find_method (c->methods, selector, class_msg, + !c->super_class))) { return m; + } + c = c->super_class; } - c = c->super_class; + warning (sel, "%s may not respond to %c%s", class->name, + class_msg ? '+' : '-', selector->name); } - warning (sel, "%s may not respond to %c%s", class->name, - class_msg ? '+' : '-', selector->name); } m = find_method (selector->name); if (!m && (!class || class->type == &type_obj_object)) { @@ -1592,6 +1629,34 @@ procollist_find_protocol (protocollist_t *protocollist, protocol_t *proto) return 0; } +static method_t * +protocol_find_method (protocol_t *protocol, selector_t *selector, int instance) +{ + method_t *m = 0; + if (protocol->methods) { + m = methodlist_find_method (protocol->methods, selector, instance); + } + if (!m && protocol->protocols) { + return protocollist_find_method (protocol->protocols, selector, + instance); + } + return m; +} + +method_t * +protocollist_find_method (protocollist_t *protocollist, selector_t *selector, + int instance) +{ + method_t *m; + for (int i = 0; i < protocollist->count; i++) { + if ((m = protocol_find_method (protocollist->list[i], selector, + instance))) { + return m; + } + } + return 0; +} + int compare_protocols (protocollist_t *protos1, protocollist_t *protos2) { diff --git a/tools/qfcc/source/expr_obj.c b/tools/qfcc/source/expr_obj.c index fe04e2c98..6858adb54 100644 --- a/tools/qfcc/source/expr_obj.c +++ b/tools/qfcc/source/expr_obj.c @@ -179,62 +179,45 @@ message_expr (expr_t *receiver, keywordarg_t *message) expr_t *selector = selector_expr (message); expr_t *call; keywordarg_t *m; - int self = 0, super = 0, class_msg = 0; - type_t *rec_type; + int super = 0, class_msg = 0; + type_t *rec_type = 0; type_t *return_type; type_t *method_type = &type_IMP; - class_t *class = 0; method_t *method; expr_t *send_msg; - if (receiver->type == ex_symbol - && strcmp (receiver->e.symbol->name, "super") == 0) { - super = 1; + if (receiver->type == ex_nil) { + rec_type = &type_id; + convert_nil (receiver, rec_type); + } else if (receiver->type == ex_symbol) { + if (strcmp (receiver->e.symbol->name, "self") == 0) { + rec_type = get_type (receiver); + } else if (strcmp (receiver->e.symbol->name, "super") == 0) { + super = 1; - receiver = super_expr (current_class); + receiver = super_expr (current_class); - if (receiver->type == ex_error) - return receiver; - receiver = cast_expr (&type_id, receiver); //FIXME better way? - class = extract_class (current_class); - } else { - if (receiver->type == ex_symbol) { - if (strcmp (receiver->e.symbol->name, "self") == 0) - self = 1; - if (receiver->e.symbol->sy_type == sy_class) { - class = receiver->e.symbol->type->t.class; - class_msg = 1; - receiver = new_symbol_expr (class_pointer_symbol (class)); - } - } else if (receiver->type == ex_nil) { - convert_nil (receiver, &type_id); - } - rec_type = get_type (receiver); - - if (receiver->type == ex_error) - return receiver; - - if (rec_type == &type_id || rec_type == &type_Class) { - } else { - if (rec_type->type == ev_pointer) - rec_type = rec_type->t.fldptr.type; - if (!obj_is_class (rec_type)) - return error (receiver, "not a class/object"); - - if (self) { - if (!class) - class = extract_class (current_class); - if (rec_type == &type_obj_class) - class_msg = 1; - } else { - if (!class) - class = rec_type->t.class; - } + if (receiver->type == ex_error) + return receiver; + receiver = cast_expr (&type_id, receiver); //FIXME better way? + rec_type = extract_class (current_class)->type; + } else if (receiver->e.symbol->sy_type == sy_class) { + class_t *class; + rec_type = receiver->e.symbol->type; + class = rec_type->t.class; + class_msg = 1; + receiver = new_symbol_expr (class_pointer_symbol (class)); } } + if (!rec_type) { + rec_type = get_type (receiver); + } + + if (receiver->type == ex_error) + return receiver; return_type = &type_id; - method = class_message_response (class, class_msg, selector); + method = class_message_response (rec_type, class_msg, selector); if (method) return_type = method->type->t.func.type; diff --git a/tools/qfcc/source/method.c b/tools/qfcc/source/method.c index 5b818afad..e8e342c7a 100644 --- a/tools/qfcc/source/method.c +++ b/tools/qfcc/source/method.c @@ -375,6 +375,20 @@ find_method (const char *sel_name) return Hash_Find (known_methods, sel_name); } +method_t * +methodlist_find_method (methodlist_t *methodlist, selector_t *selector, + int instance) +{ + method_t *m; + + for (m = methodlist->head; m; m = m->next) { + if (m->instance == instance && strcmp (selector->name, m->name) == 0) { + return m; + } + } + return 0; +} + void selector_name (dstring_t *sel_id, keywordarg_t *selector) { From 2f07d9a310f5f51bdceaa6e1ad725423e035fe6e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 09:24:34 +0900 Subject: [PATCH 365/444] [qfcc] Improve accuracy of some more diagnostics --- tools/qfcc/source/dags.c | 3 ++- tools/qfcc/source/flow.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index ce4bd98cf..ffaee9be9 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -423,7 +423,8 @@ dagnode_set_edges (dag_t *dag, dagnode_t *n) param_node = def_visit_all (param_def, 0, dag_find_node, &daglabel); if (!param_node) { - bug (0, ".param_%d not set for %s", i, n->label->opcode); + bug (n->label->expr, ".param_%d not set for %s", i, + n->label->opcode); continue; } daglabel->live = 1; diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index d3e82b7ce..d0b59ef12 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -1255,7 +1255,7 @@ flow_find_successors (flowgraph_t *graph) if (sb->next) { set_add (node->successors, sb->next->flownode->id); } else { - bug (0, "code drops off the end of the function"); + bug (st->expr, "code drops off the end of the function"); // this shouldn't happen // however, make the exit dummy block the node's successor set_add (node->successors, graph->num_nodes + 1); From a0c28a5ac580909f90a9cecea4fd5c85dc0a6c73 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 12:15:55 +0900 Subject: [PATCH 366/444] [qfcc] Support pointers to temp operands This is necessary for correctly taking the address of operands. --- tools/qfcc/include/expr.h | 1 + tools/qfcc/include/statements.h | 2 +- tools/qfcc/include/value.h | 4 ++- tools/qfcc/source/dags.c | 2 +- tools/qfcc/source/emit.c | 44 ++++++++++++++++++----------- tools/qfcc/source/expr.c | 6 ++-- tools/qfcc/source/value.c | 4 ++- tools/qfcc/test/struct-init-param.r | 22 ++++++++------- tools/qfcc/test/test-harness.c | 1 + 9 files changed, 53 insertions(+), 33 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 170fc7a50..836ec864d 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -126,6 +126,7 @@ typedef struct ex_pointer_s { int val; struct type_s *type; struct def_s *def; + struct tempop_s *tempop; } ex_pointer_t; typedef struct ex_func_s { diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index 7a0b241ed..26904db3d 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -41,7 +41,7 @@ typedef enum { op_nil, } op_type_e; -typedef struct { +typedef struct tempop_s { struct def_s *def; int offset; struct type_s *type; diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index b4f22ee60..f2dc7195f 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -38,6 +38,7 @@ struct def_s; struct ex_value_s; +struct tempop_s; struct type_s; struct ex_value_s *new_string_val (const char *string_val); @@ -49,7 +50,8 @@ struct ex_value_s *new_field_val (int field_val, struct type_s *type, struct def_s *def); struct ex_value_s *new_func_val (int func_val, struct type_s *type); struct ex_value_s *new_pointer_val (int val, struct type_s *type, - struct def_s *def); + struct def_s *def, + struct tempop_s *tempop); struct ex_value_s *new_quaternion_val (const float *quaternion_val); struct ex_value_s *new_integer_val (int integer_val); struct ex_value_s *new_uinteger_val (int uinteger_val); diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index ffaee9be9..6745a7a94 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -884,7 +884,7 @@ generate_moveps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) offset = dstDef->offset; dstDef = dstDef->alias; } - operands[2] = value_operand (new_pointer_val (offset, type, dstDef), + operands[2] = value_operand (new_pointer_val (offset, type, dstDef, 0), operands[1]->expr); st = build_statement ("", operands, var->expr); sblock_add_statement (block, st); diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index 0073f3967..f859e4b9f 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -60,16 +60,40 @@ static def_t zero_def; +static def_t *get_operand_def (expr_t *expr, operand_t *op); + static def_t * -get_value_def (ex_value_t *value, type_t *type) +get_tempop_def (expr_t *expr, tempop_t *tempop, type_t *type) +{ + if (tempop->def) { + return tempop->def; + } + if (tempop->alias) { + def_t *tdef = get_operand_def (expr, tempop->alias); + int offset = tempop->offset; + tempop->def = alias_def (tdef, type, offset); + } + if (!tempop->def) { + tempop->def = temp_def (type); + } + return tempop->def; +} + +static def_t * +get_value_def (expr_t *expr, ex_value_t *value, type_t *type) { def_t *def; - if (type == &type_short) { + if (is_short (type)) { def = new_def (0, &type_short, 0, sc_extern); def->offset = value->v.short_val; return def; } + if (is_pointer (type) && value->v.pointer.tempop + && !value->v.pointer.def) { + value->v.pointer.def = get_tempop_def (expr, value->v.pointer.tempop, + type->t.fldptr.type); + } def = emit_value (value, 0); if (type != def->type) return alias_def (def, type, 0); @@ -85,25 +109,13 @@ get_operand_def (expr_t *expr, operand_t *op) case op_def: return op->o.def; case op_value: - return get_value_def (op->o.value, op->type); + return get_value_def (expr, op->o.value, op->type); case op_label: op->type = &type_short; zero_def.type = &type_short; return &zero_def; //FIXME case op_temp: - if (op->o.tempop.def) { - return op->o.tempop.def; - } - if (op->o.tempop.alias) { - def_t *tdef = get_operand_def (expr, op->o.tempop.alias); - int offset = op->o.tempop.offset; - type_t *type = op->type; - op->o.tempop.def = alias_def (tdef, type, offset); - } - if (!op->o.tempop.def) { - op->o.tempop.def = temp_def (op->type); - } - return op->o.tempop.def; + return get_tempop_def (expr, &op->o.tempop, op->type); case op_alias: return get_operand_def (expr, op->o.alias); case op_nil: diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 8a702714d..2cd64dc13 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -800,7 +800,7 @@ new_pointer_expr (int val, type_t *type, def_t *def) { expr_t *e = new_expr (); e->type = ex_value; - e->e.value = new_pointer_val (val, type, def); + e->e.value = new_pointer_val (val, type, def, 0); return e; } @@ -2152,7 +2152,7 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) if (is_array (type)) { e = e1; e->type = ex_value; - e->e.value = new_pointer_val (0, t, def); + e->e.value = new_pointer_val (0, t, def, 0); } else { e = new_pointer_expr (0, t, def); e->line = e1->line; @@ -2218,7 +2218,7 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) return e2; if (e->type == ex_value && e->e.value->lltype == ev_pointer && is_short_val (e2)) { - e->e.value = new_pointer_val (e->e.value->v.pointer.val + expr_short (e2), t, e->e.value->v.pointer.def); + e->e.value = new_pointer_val (e->e.value->v.pointer.val + expr_short (e2), t, e->e.value->v.pointer.def, 0); } else { if (!is_short_val (e2) || expr_short (e2)) { if (e->type == ex_expr && e->e.expr.op == '&') { diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index 97198268c..424dadce5 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -197,7 +197,8 @@ new_func_val (int func_val, type_t *type) } ex_value_t * -new_pointer_val (int pointer_val, type_t *type, def_t *def) +new_pointer_val (int pointer_val, type_t *type, def_t *def, + struct tempop_s *tempop) { ex_value_t val; if (!type) { @@ -208,6 +209,7 @@ new_pointer_val (int pointer_val, type_t *type, def_t *def) val.v.pointer.val = pointer_val; val.v.pointer.type = type; val.v.pointer.def = def; + val.v.pointer.tempop = tempop; return find_value (&val); } diff --git a/tools/qfcc/test/struct-init-param.r b/tools/qfcc/test/struct-init-param.r index f043cfde3..c3dd5927b 100644 --- a/tools/qfcc/test/struct-init-param.r +++ b/tools/qfcc/test/struct-init-param.r @@ -40,18 +40,20 @@ Rect o = { { 5, 6}, {7, 8} }; int main (void) { int ret = 0; + int ok; + bar(&obj, nil, &o, obj.offset); - printf ("%d %d %d %d\n", o.offset.x, o.offset.y, - o.extent.width, o.extent.height); - if not (o.offset.x == 0 && o.offset.y == 0 - && o.extent.width == 3 && o.extent.height == 4) - ret |= 1; + ok = (o.offset.x == 0 && o.offset.y == 0 + && o.extent.width == 3 && o.extent.height == 4); + ret |= !ok; + printf ("%d %d %d %d %d\n", o.offset.x, o.offset.y, + o.extent.width, o.extent.height, ok); baz(&obj, nil, &o, obj.offset); - printf ("%d %d %d %d\n", o.offset.x, o.offset.y, - o.extent.width, o.extent.height); - if not (o.offset.x == 1 && o.offset.y == 2 - && o.extent.width == 3 && o.extent.height == 4) - ret |= 1; + ok = (o.offset.x == 1 && o.offset.y == 2 + && o.extent.width == 3 && o.extent.height == 4); + ret |= !ok; + printf ("%d %d %d %d %d\n", o.offset.x, o.offset.y, + o.extent.width, o.extent.height, ok); return ret; } diff --git a/tools/qfcc/test/test-harness.c b/tools/qfcc/test/test-harness.c index 69e660941..934c02cb0 100644 --- a/tools/qfcc/test/test-harness.c +++ b/tools/qfcc/test/test-harness.c @@ -138,6 +138,7 @@ init_qf (void) cvar_t *debug = Cvar_Get ("pr_debug", "2", 0, 0, 0); Cvar_Get ("pr_boundscheck", "2", 0, 0, 0); + Cvar_Get ("pr_deadbeef_locals", "1", 0, 0, 0); if (options.trace > 1) { Cvar_SetValue (debug, 4); From b58deb56804f9091f07ec0c2b939169772ec40ca Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 12:21:38 +0900 Subject: [PATCH 367/444] [qfcc] Rewrite operand_address to be much simpler It now creates a pointer value and returns that rather than generating an address statement. --- tools/qfcc/source/statements.c | 49 ++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 0b2337b0b..a68304838 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -658,39 +658,42 @@ expr_address (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } -static sblock_t * -operand_address (sblock_t *sblock, operand_t *reference, operand_t **op, - expr_t *e) +static operand_t * +operand_address (operand_t *reference, expr_t *e) { - statement_t *s; + def_t *def; type_t *type; + int offset = 0; + type = reference->type; switch (reference->op_type) { case op_def: - case op_temp: - case op_alias: - // build an address expression so dags can extract the correct - // type. address_expr cannot be used because reference might not - // be something it likes - e = expr_file_line (new_unary_expr ('&', e), e); - type = pointer_type (reference->type); - e->e.expr.type = type; - - s = new_statement (st_expr, "&", e); - s->opa = reference; - s->opc = temp_operand (type, e); - sblock_add_statement (sblock, s); - if (op) { - *(op) = s->opc; + // assumes aliasing is only one level deep which should be the + // case + def = reference->o.def; + if (def->alias) { + offset = def->offset; + def = def->alias; } - return sblock; + return value_operand (new_pointer_val (offset, type, def, 0), e); + case op_temp: + // assumes aliasing is only one level deep which should be the + // case + if (reference->o.tempop.alias) { + offset = reference->o.tempop.offset; + reference = reference->o.tempop.alias; + } + return value_operand (new_pointer_val (offset, type, 0, + &reference->o.tempop), e); + case op_alias: + //op_alias comes only from alias_operand and that is called + // by dags, so not expected case op_value: case op_label: case op_nil: break; } - internal_error ((*op)->expr, - "invalid operand type for operand address: %s", + internal_error (e, "invalid operand type for operand address: %s", op_type_names[reference->op_type]); } @@ -763,7 +766,7 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op, operand_t *src) *op = src; } if (is_indirect (dst_expr) || is_indirect (src_expr)) { - sblock = operand_address (sblock, src, &src, src_expr); + src = operand_address (src, src_expr); goto dereference_dst; } } From c8e45c6cfce6ad6c2b8f9f19aef677cca45913c2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 12:25:28 +0900 Subject: [PATCH 368/444] [qfcc] Use operand_address in expr_deref This fixes the technically correct but horrible mess of temps and addressing when dealing with ivars, and the resulting uninitialized temps due to the non-constant pointers (do need statement level constant folding, though). --- tools/qfcc/source/statements.c | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index a68304838..9c926978d 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -966,7 +966,6 @@ expr_call (sblock_t *sblock, expr_t *call, operand_t **op) continue; } if (is_struct (get_type (param))) { - //FIXME this should be done in the expression tree expr_t *mov = assign_expr (param, a); mov->line = a->line; mov->file = a->file; @@ -1010,15 +1009,6 @@ lea_statement (operand_t *pointer, operand_t *offset, expr_t *e) return s; } -static statement_t * -address_statement (operand_t *value, expr_t *e) -{ - statement_t *s = new_statement (st_expr, "&", e); - s->opa = value; - s->opc = temp_operand (&type_pointer, e); - return s; -} - static sblock_t * expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) { @@ -1047,13 +1037,11 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) src_addr = s->opc; sblock_add_statement (sblock, s); - //FIXME an address immediate would be nice. - s = address_statement (*op, e); - dst_addr = s->opc; - sblock_add_statement (sblock, s); + dst_addr = operand_address (*op, e); s = new_statement (st_move, "", deref); s->opa = src_addr; + //FIXME large types s->opb = short_operand (type_size (type), e); s->opc = dst_addr; sblock_add_statement (sblock, s); From b544a052bf25d891c28521c0a3d3fa0cec3f130a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 13:46:46 +0900 Subject: [PATCH 369/444] [gamecode] Bail if PR_SearchDefs is given 0 defs Fixes the hang when searching for a field in progs that don't have any. --- libs/gamecode/pr_resolve.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/gamecode/pr_resolve.c b/libs/gamecode/pr_resolve.c index 03e6949a2..6270653d2 100644 --- a/libs/gamecode/pr_resolve.c +++ b/libs/gamecode/pr_resolve.c @@ -51,6 +51,9 @@ PR_SearchDefs (pr_def_t *defs, unsigned num_defs, pointer_t offset) unsigned right = num_defs - 1; unsigned mid; + if (!num_defs) { + return 0; + } while (left != right) { mid = (left + right + 1) / 2; if (defs[mid].ofs > offset) { From db06300dddaf4fc50be73312cc5d6fe0613f95e7 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 20:20:07 +0900 Subject: [PATCH 370/444] [qfcc] Make print_operand usable from gdb It not emitting a \n made life difficult, especially whenever gdb decided to make access to printf or puts awkward. --- tools/qfcc/source/statements.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 9c926978d..54f183096 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -158,8 +158,8 @@ operand_string (operand_t *op) return ("??"); } -void -print_operand (operand_t *op) +static void +_print_operand (operand_t *op) { switch (op->op_type) { case op_def: @@ -224,7 +224,7 @@ print_operand (operand_t *op) break; case op_alias: printf ("alias(%s,", pr_type_name[op->type->type]); - print_operand (op->o.alias); + _print_operand (op->o.alias); printf (")"); break; case op_nil: @@ -233,18 +233,25 @@ print_operand (operand_t *op) } } +void +print_operand (operand_t *op) +{ + _print_operand (op); + puts (""); +} + void print_statement (statement_t *s) { printf ("(%s, ", s->opcode); if (s->opa) - print_operand (s->opa); + _print_operand (s->opa); printf (", "); if (s->opb) - print_operand (s->opb); + _print_operand (s->opb); printf (", "); if (s->opc) - print_operand (s->opc); + _print_operand (s->opc); printf (")\n"); } From 69924fe717c9ffc0ce06a54a4521f4a76f009f96 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 20:21:07 +0900 Subject: [PATCH 371/444] [qfcc] Return correct value for is_const_ptr It really helps if the logic is not inverted. --- tools/qfcc/source/statements.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 54f183096..f1a4b42e0 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -710,9 +710,9 @@ is_const_ptr (expr_t *e) if ((e->type != ex_value || e->e.value->lltype != ev_pointer) || !(POINTER_VAL (e->e.value->v.pointer) >= 0 && POINTER_VAL (e->e.value->v.pointer) < 65536)) { - return 1; + return 0; } - return 0; + return 1; } static __attribute__((pure)) int From 1d10136f2e09d4209fa62348b1556051b0a57bb4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 20:24:22 +0900 Subject: [PATCH 372/444] [qfcc] Treat all dereferences and indirect Why I had a const pointer test on there is beyond me. --- tools/qfcc/source/statements.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index f1a4b42e0..013fbd42b 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -722,7 +722,7 @@ is_indirect (expr_t *e) return 1; if (!(e->type == ex_uexpr && e->e.expr.op == '.')) return 0; - return is_const_ptr (e->e.expr.e1); + return 1; } static sblock_t * From ede7dd6d7e3b9dec51fe8755ad65dad069d6dc45 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 20:31:21 +0900 Subject: [PATCH 373/444] [qfcc] Catch attempts to emit a bad operand type --- tools/qfcc/source/emit.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index f859e4b9f..d9b4167f6 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -121,6 +121,7 @@ get_operand_def (expr_t *expr, operand_t *op) case op_nil: internal_error (expr, "unexpected nil operand"); } + internal_error (expr, "unexpected operand"); return 0; } From 5c0c056e2caaf34d9fe57b1f181549bc3ed89e21 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 21:07:31 +0900 Subject: [PATCH 374/444] [qfcc] Add is_entity type test helper --- tools/qfcc/include/type.h | 1 + tools/qfcc/source/type.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/tools/qfcc/include/type.h b/tools/qfcc/include/type.h index 791ea0fc9..ba3b82f1e 100644 --- a/tools/qfcc/include/type.h +++ b/tools/qfcc/include/type.h @@ -162,6 +162,7 @@ int is_quaternion (const type_t *type) __attribute__((pure)); int is_math (const type_t *type) __attribute__((pure)); int is_pointer (const type_t *type) __attribute__((pure)); int is_field (const type_t *type) __attribute__((pure)); +int is_entity (const type_t *type) __attribute__((pure)); int is_struct (const type_t *type) __attribute__((pure)); int is_array (const type_t *type) __attribute__((pure)); int is_structural (const type_t *type) __attribute__((pure)); diff --git a/tools/qfcc/source/type.c b/tools/qfcc/source/type.c index cdf7ca6df..4404f2ed0 100644 --- a/tools/qfcc/source/type.c +++ b/tools/qfcc/source/type.c @@ -811,6 +811,14 @@ is_field (const type_t *type) return 0; } +int +is_entity (const type_t *type) +{ + if (type->type == ev_entity) + return 1; + return 0; +} + int is_array (const type_t *type) { From f9face0cefc0c1cb9613e1de7ef0f4d7c5465c3d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 16 Mar 2020 23:26:39 +0900 Subject: [PATCH 375/444] [qfcc] Make is_indirect easier to read --- tools/qfcc/source/statements.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 013fbd42b..20e145b0c 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -718,11 +718,11 @@ is_const_ptr (expr_t *e) static __attribute__((pure)) int is_indirect (expr_t *e) { - if (e->type == ex_expr && e->e.expr.op == '.') + if ((e->type == ex_expr || e->type == ex_uexpr) + && e->e.expr.op == '.') { return 1; - if (!(e->type == ex_uexpr && e->e.expr.op == '.')) - return 0; - return 1; + } + return 0; } static sblock_t * From 8e6baf1bde4aa76919b8dffac0d9d49498bbf989 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 01:39:35 +0900 Subject: [PATCH 376/444] [qfcc] Fix assigning to entity fields At least for basic types. Compound types need testing. --- tools/qfcc/source/statements.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 20e145b0c..1733700fd 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -883,6 +883,15 @@ dereference_dst: return sblock; } + if (is_entity (dst->type) && ofs && is_field (ofs->type)) { + s = new_statement (st_expr, "&", dst_expr); + s->opa = dst; + s->opb = ofs; + s->opc = temp_operand (&type_pointer, dst_expr); + sblock_add_statement (sblock, s); + dst = s->opc; + ofs = 0; + } s = new_statement (type, opcode, e); s->opa = src; s->opb = dst; From fd06cd2b006ad6445ce6f320d4e0034a87f96897 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 01:40:35 +0900 Subject: [PATCH 377/444] [qfcc] Analyze assignment through const pointers This fixes a false-positive uninitialized warning. --- tools/qfcc/source/flow.c | 56 ++++++++++++++++++++++++++-------------- 1 file changed, 36 insertions(+), 20 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index d0b59ef12..ba8868f43 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -1040,7 +1040,7 @@ flow_add_op_var (set_t *set, operand_t *op, int is_use) set_add (set, var->number); // FIXME XXX I think the curent implementation will have problems - // for the def set when assinging to an alias as right now the real + // for the def set when assigning to an alias as right now the real // var is being treated as assigned as well. Want to handle partial // defs properly, but I am as yet uncertain of how. if (op->op_type == op_temp) { @@ -1050,6 +1050,28 @@ flow_add_op_var (set_t *set, operand_t *op, int is_use) } } +static int +flow_analyize_pointer_operand (operand_t *ptrop, set_t *def, + operand_t *operands[4]) +{ + if (ptrop->op_type == op_value + && ptrop->o.value->lltype == ev_pointer + && ptrop->o.value->v.pointer.def) { + operand_t *op; + def_t *alias; + ex_pointer_t *ptr = &ptrop->o.value->v.pointer; + alias = alias_def (ptr->def, ptr->type, ptr->val); + op = def_operand (alias, ptr->type, ptrop->expr); + flow_add_op_var (def, op, 0); + if (operands) + operands[0] = op; + else + free_operand (op); + return 1; + } + return 0; +} + void flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, operand_t *operands[4]) @@ -1099,37 +1121,31 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, } else if (!strcmp (s->opcode, "") || !strcmp (s->opcode, "")) { flow_add_op_var (use, s->opc, 0); - if (s->opc->op_type == op_value - && s->opc->o.value->lltype == ev_pointer - && s->opc->o.value->v.pointer.def) { - operand_t *op; - def_t *alias; - ex_pointer_t *ptr = &s->opc->o.value->v.pointer; - alias = alias_def (ptr->def, ptr->type, ptr->val); - op = def_operand (alias, ptr->type, s->opc->expr); - flow_add_op_var (def, op, 0); - if (operands) - operands[0] = op; - else - free_operand (op); - } else { - if (operands) + if (!flow_analyize_pointer_operand (s->opc, def, operands)) { + if (operands) { operands[3] = s->opc; + } } + } else if (!strcmp (s->opcode, ".=")) { + flow_add_op_var (use, s->opc, 1); + flow_analyize_pointer_operand (s->opb, def, operands); } else { - if (s->opc) - flow_add_op_var (use, s->opc, 1); + internal_error (s->expr, "unexpected opcode '%s' for %d", + s->opcode, s->type); } if (kill) { set_everything (kill); } if (operands) { - if (!strcmp (s->opcode, "")) + if (!strcmp (s->opcode, "") + || !strcmp (s->opcode, "")) { operands[0] = s->opc; + } operands[1] = s->opa; operands[2] = s->opb; - if (strncmp (s->opcode, "opcode, "opc; + } } break; case st_state: From 888192a9eaf8772841c3ffc2bef2e40336b49445 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 01:42:46 +0900 Subject: [PATCH 378/444] [qfcc] Resurrect ex_def expression type It turns out to be useful still as using symbol expressions isn't always appropriate and the workarounds were getting nasty. --- tools/qfcc/include/expr.h | 8 ++++++++ tools/qfcc/source/dot_expr.c | 11 +++++++++++ tools/qfcc/source/expr.c | 21 +++++++++++++++++++++ tools/qfcc/source/expr_assign.c | 2 ++ tools/qfcc/source/statements.c | 9 +++++++++ 5 files changed, 51 insertions(+) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index 836ec864d..dc3a84f63 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -49,6 +49,7 @@ typedef enum { ex_block, ///< statement block expression (::ex_block_t) ex_expr, ///< binary expression (::ex_expr_t) ex_uexpr, ///< unary expression (::ex_expr_t) + ex_def, ///< non-temporary variable (::def_t) ex_symbol, ///< non-temporary variable (::symbol_t) ex_temp, ///< temporary variable (::ex_temp_t) ex_vector, ///< "vector" expression (::ex_vector_t) @@ -230,6 +231,7 @@ typedef struct expr_s { ex_bool_t bool; ///< boolean logic expression ex_block_t block; ///< statement block expression ex_expr_t expr; ///< binary or unary expression + struct def_s *def; ///< def reference expression struct symbol_s *symbol; ///< symbol reference expression ex_temp_t temp; ///< temporary variable expression ex_vector_t vector; ///< vector expression list @@ -411,6 +413,12 @@ expr_t *new_binary_expr (int op, expr_t *e1, expr_t *e2); */ expr_t *new_unary_expr (int op, expr_t *e1); +/** Create a new def reference (non-temporary variable) expression node. + + \return The new def reference expression node (::def_t). +*/ +expr_t *new_def_expr (struct def_s *def); + /** Create a new symbol reference (non-temporary variable) expression node. \return The new symbol reference expression node (::symbol_t). diff --git a/tools/qfcc/source/dot_expr.c b/tools/qfcc/source/dot_expr.c index 76bd21089..27d535845 100644 --- a/tools/qfcc/source/dot_expr.c +++ b/tools/qfcc/source/dot_expr.c @@ -62,6 +62,7 @@ const char *expr_names[] = "block", "expr", "uexpr", + "def", "symbol", "temp", "vector", @@ -354,6 +355,15 @@ print_uexpr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) dstring_delete (typestr); } +static void +print_def (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) +{ + int indent = level * 2 + 2; + + dasprintf (dstr, "%*se_%p [label=\"d %s\\n%d\"];\n", indent, "", e, + e->e.def->name, e->line); +} + static void print_symbol (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) { @@ -542,6 +552,7 @@ _print_expr (dstring_t *dstr, expr_t *e, int level, int id, expr_t *next) print_block, print_subexpr, print_uexpr, + print_def, print_symbol, print_temp, print_vector, diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 2cd64dc13..8eeea76c1 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -239,6 +239,8 @@ get_type (expr_t *e) case ex_expr: case ex_uexpr: return e->e.expr.type; + case ex_def: + return e->e.def->type; case ex_symbol: return e->e.symbol->type; case ex_temp: @@ -342,6 +344,7 @@ copy_expr (expr_t *e) return 0; switch (e->type) { case ex_error: + case ex_def: case ex_symbol: case ex_nil: case ex_value: @@ -610,6 +613,15 @@ new_unary_expr (int op, expr_t *e1) return e; } +expr_t * +new_def_expr (def_t *def) +{ + expr_t *e = new_expr (); + e->type = ex_def; + e->e.def = def; + return e; +} + expr_t * new_symbol_expr (symbol_t *symbol) { @@ -1542,6 +1554,13 @@ unary_expr (int op, expr_t *e) n->e.expr.type = e->e.expr.type; return n; } + case ex_def: + { + expr_t *n = new_unary_expr (op, e); + + n->e.expr.type = e->e.def->type; + return n; + } case ex_symbol: { expr_t *n = new_unary_expr (op, e); @@ -1602,6 +1621,7 @@ unary_expr (int op, expr_t *e) return error (e, "invalid type for unary !"); case ex_uexpr: case ex_expr: + case ex_def: case ex_symbol: case ex_temp: case ex_vector: @@ -1671,6 +1691,7 @@ unary_expr (int op, expr_t *e) goto bitnot_expr; case ex_expr: case ex_bool: + case ex_def: case ex_symbol: case ex_temp: case ex_vector: diff --git a/tools/qfcc/source/expr_assign.c b/tools/qfcc/source/expr_assign.c index 88d45ad7b..7d1f1aab9 100644 --- a/tools/qfcc/source/expr_assign.c +++ b/tools/qfcc/source/expr_assign.c @@ -85,6 +85,8 @@ int is_lvalue (const expr_t *expr) { switch (expr->type) { + case ex_def: + return !expr->e.def->constant; case ex_symbol: switch (expr->e.symbol->sy_type) { case sy_name: diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 1733700fd..a950842e5 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -1267,6 +1267,13 @@ expr_uexpr (sblock_t *sblock, expr_t *e, operand_t **op) return sblock; } +static sblock_t * +expr_def (sblock_t *sblock, expr_t *e, operand_t **op) +{ + *op = def_operand (e->e.def, e->e.def->type, e); + return sblock; +} + static sblock_t * expr_symbol (sblock_t *sblock, expr_t *e, operand_t **op) { @@ -1398,6 +1405,7 @@ statement_subexpr (sblock_t *sblock, expr_t *e, operand_t **op) expr_block, // ex_block expr_expr, expr_uexpr, + expr_def, expr_symbol, expr_temp, expr_vector_e, // ex_vector @@ -1715,6 +1723,7 @@ statement_slist (sblock_t *sblock, expr_t *e) statement_block, statement_expr, statement_uexpr, + statement_nonexec, // ex_def statement_nonexec, // ex_symbol statement_nonexec, // ex_temp statement_nonexec, // ex_vector From e4a403bbb38154b6fa1a28f8e17354fe7587a233 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 10:55:27 +0900 Subject: [PATCH 379/444] [qfcc] Improve integral value extraction readability --- tools/qfcc/source/expr.c | 53 ++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 8eeea76c1..509f5fcfb 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1039,13 +1039,16 @@ expr_quaternion (expr_t *e) int is_integer_val (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 1; - if (e->type == ex_value && e->e.value->lltype == ev_integer) + } + if (e->type == ex_value && e->e.value->lltype == ev_integer) { return 1; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && (e->e.symbol->type->type == ev_integer - || is_enum (e->e.symbol->type))) + && is_integral (e->e.symbol->type)) { + return 1; + } return 1; return 0; } @@ -1053,61 +1056,75 @@ is_integer_val (expr_t *e) int expr_integer (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 0; - if (e->type == ex_value && e->e.value->lltype == ev_integer) + } + if (e->type == ex_value && e->e.value->lltype == ev_integer) { return e->e.value->v.integer_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const && (e->e.symbol->type->type == ev_integer - || is_enum (e->e.symbol->type))) + || is_enum (e->e.symbol->type))) { return e->e.symbol->s.value->v.integer_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var && e->e.symbol->s.def->constant - && is_integral (e->e.symbol->s.def->type)) + && is_integral (e->e.symbol->s.def->type)) { return D_INT (e->e.symbol->s.def); + } internal_error (e, "not an integer constant"); } unsigned expr_uinteger (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 0; - if (e->type == ex_value && e->e.value->lltype == ev_uinteger) + } + if (e->type == ex_value && e->e.value->lltype == ev_uinteger) { return e->e.value->v.uinteger_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && e->e.symbol->type->type == ev_uinteger) + && e->e.symbol->type->type == ev_uinteger) { return e->e.symbol->s.value->v.uinteger_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_var && e->e.symbol->s.def->constant - && is_integral (e->e.symbol->s.def->type)) + && is_integral (e->e.symbol->s.def->type)) { return D_INT (e->e.symbol->s.def); + } internal_error (e, "not an unsigned constant"); } int is_short_val (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 1; - if (e->type == ex_value && e->e.value->lltype == ev_short) + } + if (e->type == ex_value && e->e.value->lltype == ev_short) { return 1; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && e->e.symbol->type->type == ev_short) + && e->e.symbol->type->type == ev_short) { return 1; + } return 0; } short expr_short (expr_t *e) { - if (e->type == ex_nil) + if (e->type == ex_nil) { return 0; - if (e->type == ex_value && e->e.value->lltype == ev_short) + } + if (e->type == ex_value && e->e.value->lltype == ev_short) { return e->e.value->v.short_val; + } if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const - && e->e.symbol->type->type == ev_short) + && e->e.symbol->type->type == ev_short) { return e->e.symbol->s.value->v.short_val; + } internal_error (e, "not a short constant"); } From 80967e1471cd5448ea0aa296c5e0e433332f45a9 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 10:56:45 +0900 Subject: [PATCH 380/444] [qfcc] Support def exprs in integral value extractors --- tools/qfcc/source/expr.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 509f5fcfb..638af8e12 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1049,7 +1049,10 @@ is_integer_val (expr_t *e) && is_integral (e->e.symbol->type)) { return 1; } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { return 1; + } return 0; } @@ -1072,6 +1075,10 @@ expr_integer (expr_t *e) && is_integral (e->e.symbol->s.def->type)) { return D_INT (e->e.symbol->s.def); } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return D_INT (e->e.def); + } internal_error (e, "not an integer constant"); } @@ -1093,6 +1100,10 @@ expr_uinteger (expr_t *e) && is_integral (e->e.symbol->s.def->type)) { return D_INT (e->e.symbol->s.def); } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return D_INT (e->e.def); + } internal_error (e, "not an unsigned constant"); } From c3f04384d565653f05f65fe6fd72815a71df7a7e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 11:07:50 +0900 Subject: [PATCH 381/444] [qfcc] Make a general integral value extractor All too often I just want the value. --- tools/qfcc/include/expr.h | 4 +++ tools/qfcc/source/expr.c | 54 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index dc3a84f63..a181f7205 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -567,6 +567,8 @@ unsigned expr_uinteger (expr_t *e) __attribute__((pure)); expr_t *new_short_expr (short short_val); short expr_short (expr_t *e) __attribute__((pure)); +int expr_integral (expr_t *e) __attribute__((pure)); + /** Check of the expression refers to a constant value. \param e The expression to check. @@ -613,7 +615,9 @@ int is_float_val (expr_t *e) __attribute__((pure)); int is_vector_val (expr_t *e) __attribute__((pure)); int is_quaternion_val (expr_t *e) __attribute__((pure)); int is_integer_val (expr_t *e) __attribute__((pure)); +int is_uinteger_val (expr_t *e) __attribute__((pure)); int is_short_val (expr_t *e) __attribute__((pure)); +int is_integral_val (expr_t *e) __attribute__((pure)); /** Create a reference to the global .self entity variable. diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 638af8e12..c8c9207fc 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1082,6 +1082,26 @@ expr_integer (expr_t *e) internal_error (e, "not an integer constant"); } +int +is_uinteger_val (expr_t *e) +{ + if (e->type == ex_nil) { + return 1; + } + if (e->type == ex_value && e->e.value->lltype == ev_uinteger) { + return 1; + } + if (e->type == ex_symbol && e->e.symbol->sy_type == sy_const + && is_integral (e->e.symbol->type)) { + return 1; + } + if (e->type == ex_def && e->e.def->constant + && is_integral (e->e.def->type)) { + return 1; + } + return 0; +} + unsigned expr_uinteger (expr_t *e) { @@ -1139,6 +1159,40 @@ expr_short (expr_t *e) internal_error (e, "not a short constant"); } +int +is_integral_val (expr_t *e) +{ + if (is_constant (e)) { + if (is_integer_val (e)) { + return 1; + } + if (is_uinteger_val (e)) { + return 1; + } + if (is_short_val (e)) { + return 1; + } + } + return 0; +} + +int +expr_integral (expr_t *e) +{ + if (is_constant (e)) { + if (is_integer_val (e)) { + return expr_integer (e); + } + if (is_uinteger_val (e)) { + return expr_uinteger (e); + } + if (is_short_val (e)) { + return expr_short (e); + } + } + internal_error (e, "not an integral constant"); +} + expr_t * new_alias_expr (type_t *type, expr_t *expr) { From 9cb3ee01d601b92a1813e6e93ed7aaf4952088a6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 11:19:12 +0900 Subject: [PATCH 382/444] [qfcc] Add pointer value check Extraction is a little more complicated, though, so undecided on that. --- tools/qfcc/include/expr.h | 1 + tools/qfcc/source/expr.c | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index a181f7205..b2e01a491 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -618,6 +618,7 @@ int is_integer_val (expr_t *e) __attribute__((pure)); int is_uinteger_val (expr_t *e) __attribute__((pure)); int is_short_val (expr_t *e) __attribute__((pure)); int is_integral_val (expr_t *e) __attribute__((pure)); +int is_pointer_val (expr_t *e) __attribute__((pure)); /** Create a reference to the global .self entity variable. diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index c8c9207fc..29e249d70 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -1193,6 +1193,15 @@ expr_integral (expr_t *e) internal_error (e, "not an integral constant"); } +int +is_pointer_val (expr_t *e) +{ + if (e->type == ex_value && e->e.value->lltype == ev_pointer) { + return 1; + } + return 0; +} + expr_t * new_alias_expr (type_t *type, expr_t *expr) { From 0d751dcdc5e78ec95229d0638e859f301d11b781 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 12:12:06 +0900 Subject: [PATCH 383/444] [qfcc] Improve robustness of do_op_integer --- tools/qfcc/source/constfold.c | 86 +++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index f46d1a452..e1b380a5d 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -789,7 +789,8 @@ do_op_quaternion (int op, expr_t *e, expr_t *e1, expr_t *e2) static expr_t * do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) { - int i1, i2; + int isval1 = 0, isval2 = 0; + int val1, val2; static int valid[] = { '=', '+', '-', '*', '/', '&', '|', '^', '%', SHL, SHR, AND, OR, LT, GT, LE, GE, EQ, NE, 0 @@ -798,11 +799,23 @@ do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) if (!valid_op (op, valid)) return error (e1, "invalid operator for integer"); - if (is_short_val (e1)) - convert_short_int (e1); + if (is_short_val (e1)) { + isval1 = 1; + val1 = expr_short (e1); + } + if (is_integer_val (e1)) { + isval1 = 1; + val1 = expr_integer (e1); + } - if (is_short_val (e2)) - convert_short_int (e2); + if (is_short_val (e2)) { + isval2 = 1; + val2 = expr_short (e2); + } + if (is_integer_val (e2)) { + isval2 = 1; + val2 = expr_integer (e2); + } if (is_compare (op) || is_logic (op)) { if (options.code.progsversion > PROG_ID_VERSION) @@ -813,89 +826,86 @@ do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) e->e.expr.type = &type_integer; } - if (op == '*' && is_constant (e1) && expr_integer (e1) == 1) + if (op == '*' && isval1 && val1 == 1) return e2; - if (op == '*' && is_constant (e2) && expr_integer (e2) == 1) + if (op == '*' && isval2 && val2 == 1) return e1; - if (op == '*' && is_constant (e1) && expr_integer (e1) == 0) + if (op == '*' && isval1 && val1 == 0) return e1; - if (op == '*' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '*' && isval2 && val2 == 0) return e2; - if (op == '/' && is_constant (e2) && expr_integer (e2) == 1) + if (op == '/' && isval2 && val2 == 1) return e1; - if (op == '/' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '/' && isval2 && val2 == 0) return error (e, "division by zero"); - if (op == '/' && is_constant (e1) && expr_integer (e1) == 0) + if (op == '/' && isval1 && val1 == 0) return e1; - if (op == '+' && is_constant (e1) && expr_integer (e1) == 0) + if (op == '+' && isval1 && val1 == 0) return e2; - if (op == '+' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '+' && isval2 && val2 == 0) return e1; - if (op == '-' && is_constant (e2) && expr_integer (e2) == 0) + if (op == '-' && isval2 && val2 == 0) return e1; - if (op == '=' || !is_constant (e1) || !is_constant (e2)) + if (op == '=' || !isval1 || !isval2) return e; - i1 = expr_integer (e1); - i2 = expr_integer (e2); - switch (op) { case '+': - e = new_integer_expr (i1 + i2); + e = new_integer_expr (val1 + val2); break; case '-': - e = new_integer_expr (i1 - i2); + e = new_integer_expr (val1 - val2); break; case '*': - e = new_integer_expr (i1 * i2); + e = new_integer_expr (val1 * val2); break; case '/': if (options.warnings.integer_divide) - warning (e2, "%d / %d == %d", i1, i2, i1 / i2); - e = new_integer_expr (i1 / i2); + warning (e2, "%d / %d == %d", val1, val2, val1 / val2); + e = new_integer_expr (val1 / val2); break; case '&': - e = new_integer_expr (i1 & i2); + e = new_integer_expr (val1 & val2); break; case '|': - e = new_integer_expr (i1 | i2); + e = new_integer_expr (val1 | val2); break; case '^': - e = new_integer_expr (i1 ^ i2); + e = new_integer_expr (val1 ^ val2); break; case '%': - e = new_integer_expr (i1 % i2); + e = new_integer_expr (val1 % val2); break; case SHL: - e = new_integer_expr (i1 << i2); + e = new_integer_expr (val1 << val2); break; case SHR: - e = new_integer_expr (i1 >> i2); + e = new_integer_expr (val1 >> val2); break; case AND: - e = cmp_result_expr (i1 && i2); + e = cmp_result_expr (val1 && val2); break; case OR: - e = cmp_result_expr (i1 || i2); + e = cmp_result_expr (val1 || val2); break; case LT: - e = cmp_result_expr (i1 < i2); + e = cmp_result_expr (val1 < val2); break; case GT: - e = cmp_result_expr (i1 > i2); + e = cmp_result_expr (val1 > val2); break; case LE: - e = cmp_result_expr (i1 <= i2); + e = cmp_result_expr (val1 <= val2); break; case GE: - e = cmp_result_expr (i1 >= i2); + e = cmp_result_expr (val1 >= val2); break; case EQ: - e = cmp_result_expr (i1 == i2); + e = cmp_result_expr (val1 == val2); break; case NE: - e = cmp_result_expr (i1 != i2); + e = cmp_result_expr (val1 != val2); break; default: internal_error (e1, 0); From 0d784d9ef4157c2b383246feae25efdc597b3f1b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 12:13:09 +0900 Subject: [PATCH 384/444] [qfcc] Rework address expr calculation This removes a bogus lea from the instruction stream (and there can be many such). --- tools/qfcc/source/def.c | 9 +++++---- tools/qfcc/source/expr.c | 24 +++++++++++++++++++++--- 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/tools/qfcc/source/def.c b/tools/qfcc/source/def.c index 689b21dac..2fbf0bf08 100644 --- a/tools/qfcc/source/def.c +++ b/tools/qfcc/source/def.c @@ -296,8 +296,9 @@ zero_memory (expr_t *local_expr, def_t *def, type_t *zero_type, expr_t *dst; for (; init_offset < init_size + 1 - zero_size; init_offset += zero_size) { - dst = new_pointer_expr (init_offset, zero_type, def); - append_expr (local_expr, assign_expr (unary_expr ('.', dst), zero)); + dst = new_def_expr (def); + dst = new_offset_alias_expr (zero_type, dst, init_offset); + append_expr (local_expr, assign_expr (dst, zero)); } return init_offset; } @@ -355,8 +356,8 @@ init_elements (struct def_s *def, expr_t *eles) build_element_chain (&element_chain, def->type, eles, 0); if (def->local && local_expr) { - expr_t *ptr = new_pointer_expr (0, def->type, def); - assign_elements (local_expr, pointer_expr (ptr), &element_chain); + expr_t *dst = new_def_expr (def); + assign_elements (local_expr, dst, &element_chain); } else { def_t dummy = *def; for (element = element_chain.head; element; element = element->next) { diff --git a/tools/qfcc/source/expr.c b/tools/qfcc/source/expr.c index 29e249d70..ac128e378 100644 --- a/tools/qfcc/source/expr.c +++ b/tools/qfcc/source/expr.c @@ -2256,6 +2256,22 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) t = get_type (e1); switch (e1->type) { + case ex_def: + { + def_t *def = e1->e.def; + type_t *type = def->type; + + if (is_array (type)) { + e = e1; + e->type = ex_value; + e->e.value = new_pointer_val (0, t, def, 0); + } else { + e = new_pointer_expr (0, t, def); + e->line = e1->line; + e->file = e1->file; + } + } + break; case ex_symbol: if (e1->e.symbol->sy_type == sy_var) { def_t *def = e1->e.symbol->s.def; @@ -2328,9 +2344,11 @@ address_expr (expr_t *e1, expr_t *e2, type_t *t) if (e2) { if (e2->type == ex_error) return e2; - if (e->type == ex_value && e->e.value->lltype == ev_pointer - && is_short_val (e2)) { - e->e.value = new_pointer_val (e->e.value->v.pointer.val + expr_short (e2), t, e->e.value->v.pointer.def, 0); + if (is_pointer_val (e) && is_integral_val (e2)) { + int base = e->e.value->v.pointer.val; + int offset = expr_integral (e2); + def_t *def = e->e.value->v.pointer.def; + e->e.value = new_pointer_val (base + offset, t, def, 0); } else { if (!is_short_val (e2) || expr_short (e2)) { if (e->type == ex_expr && e->e.expr.op == '&') { From c5400c458175eec7c0f253a3defed1d66fecbcf3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 12:16:24 +0900 Subject: [PATCH 385/444] [qfcc] Make anonstruct test robust against pointer math I noticed that pointer math is currently incorrect in qfcc, but it would be nice for fixing it to not break anonstruct since it is testing something else. --- tools/qfcc/test/anonstruct.r | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tools/qfcc/test/anonstruct.r b/tools/qfcc/test/anonstruct.r index 684ae8c2b..3c025bb38 100644 --- a/tools/qfcc/test/anonstruct.r +++ b/tools/qfcc/test/anonstruct.r @@ -28,22 +28,22 @@ int main() { anon_t anon; int ret = 0; - if (&anon.snafu != &anon.fizzle) { + if ((int)&anon.snafu != (int)&anon.fizzle) { printf ("anon union broken: %p %p\n", &anon.snafu, &anon.fizzle); ret |= 1; } - if (&anon.snafu - &anon.baz != 1) { + if ((int)&anon.snafu - (int)&anon.baz != 1) { printf ("snafu and baz not adjacant: snafu:%p baz:%p\n", &anon.snafu, &anon.baz); ret |= 1; } - if (&anon.baz - &anon.bar != 1) { + if ((int)&anon.baz - (int)&anon.bar != 1) { printf ("baz and bar not adjacant: baz:%p bar:%p\n", &anon.baz, &anon.bar); ret |= 1; } - if (&anon.bar - &anon.id != 1) { + if ((int)&anon.bar - (int)&anon.id != 1) { printf ("bar not after id: bar:%p id:%p\n", &anon.bar, &anon.id); ret |= 1; From 441e7b99bcb8cd42b8cc2c73ec1bab457bdf1c84 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 12:45:55 +0900 Subject: [PATCH 386/444] [qfcc] Correctly implement pointer arithmetic --- tools/qfcc/source/expr_binary.c | 74 +++++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/tools/qfcc/source/expr_binary.c b/tools/qfcc/source/expr_binary.c index c2d446334..b7b526853 100644 --- a/tools/qfcc/source/expr_binary.c +++ b/tools/qfcc/source/expr_binary.c @@ -46,6 +46,7 @@ typedef struct { } expr_type_t; static expr_t *pointer_arithmetic (int op, expr_t *e1, expr_t *e2); +static expr_t *pointer_compare (int op, expr_t *e1, expr_t *e2); static expr_t *inverse_multiply (int op, expr_t *e1, expr_t *e2); static expr_t *double_compare (int op, expr_t *e1, expr_t *e2); @@ -176,13 +177,13 @@ static expr_type_t func_func[] = { }; static expr_type_t pointer_pointer[] = { - {'-', &type_integer, &type_integer, &type_integer}, - {EQ, &type_integer}, - {NE, &type_integer}, - {LE, &type_integer}, - {GE, &type_integer}, - {LT, &type_integer}, - {GT, &type_integer}, + {'-', 0, 0, 0, pointer_arithmetic}, + {EQ, 0, 0, 0, pointer_compare}, + {NE, 0, 0, 0, pointer_compare}, + {LE, 0, 0, 0, pointer_compare}, + {GE, 0, 0, 0, pointer_compare}, + {LT, 0, 0, 0, pointer_compare}, + {GT, 0, 0, 0, pointer_compare}, {0, 0} }; @@ -255,7 +256,7 @@ static expr_type_t integer_vector[] = { }; static expr_type_t integer_pointer[] = { - {'+', &type_pointer, 0, &type_integer}, + {'+', 0, 0, 0, pointer_arithmetic}, {0, 0} }; @@ -735,21 +736,58 @@ static expr_t * pointer_arithmetic (int op, expr_t *e1, expr_t *e2) { expr_t *e; - type_t *ptype = get_type (e1); + type_t *t1 = get_type (e1); + type_t *t2 = get_type (e2); + expr_t *ptr; + expr_t *offset; + expr_t *psize; + type_t *ptype; - if (!is_pointer (ptype)) { - ptype = get_type (e2); - } - if (!is_pointer (ptype)) { + if (!is_pointer (t1) && !is_pointer (t2)) { internal_error (e1, "pointer arithmetic on non-pointers"); } - - e1 = cast_expr (&type_integer, e1); - e2 = cast_expr (&type_integer, e2); - e = binary_expr (op, e1, e2); + if (is_pointer (t1) && is_pointer (t2)) { + if (op != '-') { + return error (e2, "invalid pointer operation"); + } + if (t1 != t2) { + return error (e2, "cannot use %c on pointers of different types", + op); + } + e1 = cast_expr (&type_integer, e1); + e2 = cast_expr (&type_integer, e2); + psize = new_integer_expr (type_size (t1->t.fldptr.type)); + return binary_expr ('/', binary_expr ('-', e1, e2), psize); + } else if (is_pointer (t1)) { + offset = cast_expr (&type_integer, e2); + ptr = cast_expr (&type_integer, e1); + ptype = t1; + } else if (is_pointer (t2)) { + offset = cast_expr (&type_integer, e1); + ptr = cast_expr (&type_integer, e2); + ptype = t2; + } + psize = new_integer_expr (type_size (ptype->t.fldptr.type)); + e = binary_expr (op, ptr, binary_expr ('*', offset, psize)); return cast_expr (ptype, e); } +static expr_t * +pointer_compare (int op, expr_t *e1, expr_t *e2) +{ + type_t *t1 = get_type (e1); + type_t *t2 = get_type (e2); + expr_t *e; + + if (!type_assignable (t1, t2)) { + return error (e2, "cannot use %s on pointers of different types", + get_op_string (op)); + } + e = new_binary_expr (op, e1, e2); + e->e.expr.type = &type_integer; + return e; +} + static expr_t * inverse_multiply (int op, expr_t *e1, expr_t *e2) { @@ -790,7 +828,7 @@ double_compare (int op, expr_t *e1, expr_t *e2) e1 = cast_expr (&type_double, e1); } e = new_binary_expr (op, e1, e2); - e->e.expr.type = &type_double; + e->e.expr.type = &type_integer; return e; } From 28a8c1fda7523d2f5ac947127e8532844afb9558 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 14:05:31 +0900 Subject: [PATCH 387/444] [qwaq] Implement more curses wrappers --- ruamoko/qwaq/qwaq-curses.c | 83 ++++++++++++++++++++++++++++++++- ruamoko/qwaq/qwaq-curses.h | 2 + ruamoko/qwaq/qwaq-textcontext.r | 11 ++++- 3 files changed, 93 insertions(+), 3 deletions(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index eb9ee8024..3da81cfe3 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -1054,6 +1054,64 @@ bi_doupdate (progs_t *pr) qwaq_doupdate (pr); } +static void +qwaq_waddstr (progs_t *pr, int window_id, const char *str) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_waddstr, 0, + window_id, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_copystr (print_buffer, str); + qwaq_submit_command (res, command); + } +} +static void +bi_waddstr (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + const char *str = P_GSTRING (pr, 1); + + qwaq_waddstr (pr, window_id, str); +} + +static void +qwaq_mvwaddstr (progs_t *pr, int window_id, int x, int y, const char *str) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int string_id = acquire_string (res); + dstring_t *print_buffer = res->strings + string_id; + int command[] = { + qwaq_cmd_mvwaddstr, 0, + window_id, x, y, string_id + }; + + command[1] = CMD_SIZE(command); + + dstring_copystr (print_buffer, str); + qwaq_submit_command (res, command); + } +} +static void +bi_mvwaddstr (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int x = P_INT (pr, 1); + int y = P_INT (pr, 2); + const char *str = P_GSTRING (pr, 3); + + qwaq_mvwaddstr (pr, window_id, x, y, str); +} + static void qwaq_mvwprintf (progs_t *pr, int window_id, int x, int y, const char *fmt, int count, pr_type_t **args) @@ -1588,11 +1646,20 @@ static void bi_i_TextContext__addch_ (progs_t *pr) { int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; - int ch = P_INT (pr, 1); + int ch = P_INT (pr, 2); qwaq_waddch (pr, window_id, ch); } +static void +bi_i_TextContext__addstr_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + const char *str = P_GSTRING (pr, 2); + + qwaq_waddstr (pr, window_id, str); +} + static void bi_i_TextContext__mvvprintf_ (progs_t *pr) { @@ -1633,6 +1700,16 @@ bi_i_TextContext__mvaddch_ (progs_t *pr) qwaq_mvwaddch (pr, window_id, pos->x, pos->y, ch); } +static void +bi_i_TextContext__mvaddstr_ (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + Point *pos = &P_PACKED (pr, Point, 2); + const char *str = P_GSTRING (pr, 3); + + qwaq_mvwaddstr (pr, window_id, pos->x, pos->y, str); +} + static void bi_i_TextContext__bkgd_ (progs_t *pr) { @@ -1696,6 +1773,8 @@ static builtin_t builtins[] = { {"mvwvprintf", bi_mvwvprintf, -1}, {"mvwaddch", bi_mvwaddch, -1}, {"waddch", bi_waddch, -1}, + {"mvwaddstr", bi_mvwaddstr, -1}, + {"waddstr", bi_waddstr, -1}, {"wrefresh", bi_wrefresh, -1}, {"get_event", bi_get_event, -1}, {"max_colors", bi_max_colors, -1}, @@ -1723,10 +1802,12 @@ static builtin_t builtins[] = { {"_i_TextContext__printf_", bi_i_TextContext__printf_, -1}, {"_i_TextContext__vprintf_", bi_i_TextContext__vprintf_, -1}, {"_i_TextContext__addch_", bi_i_TextContext__addch_, -1}, + {"_i_TextContext__addstr_", bi_i_TextContext__addstr_, -1}, {"_i_TextContext__mvvprintf_", bi_i_TextContext__mvvprintf_, -1}, {"_c_TextContext__refresh", bi_c_TextContext__refresh, -1}, {"_i_TextContext__refresh", bi_i_TextContext__refresh, -1}, {"_i_TextContext__mvaddch_", bi_i_TextContext__mvaddch_, -1}, + {"_i_TextContext__mvaddstr_", bi_i_TextContext__mvaddstr_, -1}, {"_i_TextContext__bkgd_", bi_i_TextContext__bkgd_, -1}, {"_i_TextContext__scrollok_", bi_i_TextContext__scrollok_, -1}, {"_i_TextContext__border_", bi_i_TextContext__border_, -1}, diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index 70af63f7c..fc5c5c4cc 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -97,6 +97,8 @@ typedef struct panel_s *panel_t; @extern void wrefresh (window_t win); @extern void mvwaddch (window_t win, int x, int y, int ch); @extern void waddch (window_t win, int ch); +@extern void mvwaddstr (window_t win, int x, int y, string str); +@extern void waddstr (window_t win, string str); @extern panel_t create_panel (window_t window); @extern void destroy_panel (panel_t panel); diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index dd94e34c1..d7ec2a4c4 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -119,14 +119,19 @@ static TextContext *screen; return self; } -- (void) mvprintf: (Point) pos, string fmt, ... = #0; - (void) printf: (string) fmt, ... = #0; - (void) vprintf: (string) mft, @va_list args = #0; - (void) addch: (int) ch = #0; +- (void) addstr: (string) str = #0; + +- (void) mvprintf: (Point) pos, string fmt, ... = #0; - (void) mvvprintf: (Point) pos, string mft, @va_list args = #0; +- (void) mvaddch: (Point) pos, int ch = #0; +- (void) mvaddstr: (Point) pos, string str = #0; + - (void) refresh = #0; + (void) refresh = #0; -- (void) mvaddch: (Point) pos, int ch = #0; + - (void) bkgd: (int) ch = #0; - (void) scrollok: (int) flag = #0; - (void) border: (box_sides_t) sides, box_corners_t corners = #0; @@ -145,6 +150,8 @@ void mvwvprintf (window_t win, int x, int y, string fmt, @va_list args) = #0; void wrefresh (window_t win) = #0; void mvwaddch (window_t win, int x, int y, int ch) = #0; void waddch (window_t win, int ch) = #0; +void mvwaddstr (window_t win, int x, int y, string str) = #0; +void waddstr (window_t win, string str) = #0; int get_event (qwaq_event_t *event) = #0; int max_colors (void) = #0; int max_color_pairs (void) = #0; From d02a01c28207b5a8c45bcd83c3c5d7e5e6360733 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 14:46:20 +0900 Subject: [PATCH 388/444] [qfcc] Make tempop pointer strings more informative Now that the address of a tempop can be taken, their op strings need to be visible. --- tools/qfcc/source/statements.c | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index a950842e5..554473ea8 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -77,6 +77,21 @@ optype_str (op_type_e type) return op_type_names[type]; } +static const char * +tempop_string (tempop_t *tempop) +{ + if (tempop->alias) { + return va ("", + pr_type_name[tempop->type->type], + tempop, tempop->users, + &tempop->alias->o.tempop, + tempop->offset, + tempop->alias->o.tempop.users); + } + return va ("", pr_type_name[tempop->type->type], + &tempop, tempop->users); +} + const char * operand_string (operand_t *op) { @@ -110,6 +125,10 @@ operand_string (operand_t *op) return va ("ptr %s+%d", op->o.value->v.pointer.def->name, op->o.value->v.pointer.val); + } else if(op->o.value->v.pointer.tempop) { + tempop_t *tempop = op->o.value->v.pointer.tempop; + return va ("ptr %s+%d", tempop_string (tempop), + op->o.value->v.pointer.val); } else { return va ("ptr %d", op->o.value->v.pointer.val); } @@ -136,15 +155,7 @@ operand_string (operand_t *op) case op_label: return op->o.label->name; case op_temp: - if (op->o.tempop.alias) - return va ("", - pr_type_name[op->type->type], - op, op->o.tempop.users, - op->o.tempop.alias, - op->o.tempop.offset, - op->o.tempop.alias->o.tempop.users); - return va ("", pr_type_name[op->o.tempop.type->type], - op, op->o.tempop.users); + return tempop_string (&op->o.tempop); case op_alias: { const char *alias = operand_string (op->o.alias); From c5cbe83f71a8f3cc149a2f4318caa6dceb3c2aa6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 14:47:34 +0900 Subject: [PATCH 389/444] [qfcc] Initialize statement numbers to -1 This is to indicate the statement has not yet been flow analyzed. --- tools/qfcc/source/statements.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 554473ea8..6058c62a8 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -296,6 +296,7 @@ new_statement (st_type_t type, const char *opcode, expr_t *expr) statement->type = type; statement->opcode = save_string (opcode); statement->expr = expr; + statement->number = -1; // indicates flow analysis not done yet return statement; } From 0cbe438ac199abae3a890c72fa25c4e24fbbfd66 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 15:04:07 +0900 Subject: [PATCH 390/444] [util] Make va slight robust against chained use va now cycles through a set of four dstrings rather than using just the one. This allows for some simple chaining of va usage. --- libs/util/va.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/libs/util/va.c b/libs/util/va.c index aa99f7955..dd24c05d1 100644 --- a/libs/util/va.c +++ b/libs/util/va.c @@ -51,16 +51,23 @@ VISIBLE char * va (const char *fmt, ...) { va_list args; - static dstring_t *string; + static dstring_t *string[4]; +#define NUM_STRINGS (sizeof (string) / sizeof (string[0])) + static int str_index; + dstring_t *dstr; - if (!string) - string = dstring_new (); + if (!string[0]) { + for (size_t i = 0; i < NUM_STRINGS; i++) { + string[i] = dstring_new (); + } + } + dstr = string[str_index++ % NUM_STRINGS]; va_start (args, fmt); - dvsprintf (string, fmt, args); + dvsprintf (dstr, fmt, args); va_end (args); - return string->str; + return dstr->str; } VISIBLE char * From 0de011d0bf9055d3c2333fbca81ce2f10d53b3c3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 15:23:24 +0900 Subject: [PATCH 391/444] [qfcc] Add some disabled additional statement info It's a bit cluttered for normal debugging, but I haven't decided how to make it optional just yet. --- tools/qfcc/source/dot_sblock.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tools/qfcc/source/dot_sblock.c b/tools/qfcc/source/dot_sblock.c index 26e32681e..fc892a1c7 100644 --- a/tools/qfcc/source/dot_sblock.c +++ b/tools/qfcc/source/dot_sblock.c @@ -41,6 +41,7 @@ #include #include +#include #include #include "dags.h" @@ -62,6 +63,30 @@ flow_statement (dstring_t *dstr, statement_t *s) dasprintf (dstr, "%s", html_string(operand_string (s->opa))); dasprintf (dstr, "%s", html_string(operand_string (s->opb))); dasprintf (dstr, "%s", html_string(operand_string (s->opc))); +#if 0 + if (s->number >= 0) { + set_t *use = set_new (); + set_t *def = set_new (); + set_t *kill = set_new (); + set_t *ops = set_new (); + operand_t *operands[4]; + + flow_analyze_statement (s, use, def, kill, operands); + for (int i = 0; i < 4; i++) { + if (operands[i]) { + set_add (ops, i); + } + } + dasprintf (dstr, "%s", html_string(set_as_string (use))); + dasprintf (dstr, "%s", html_string(set_as_string (def))); + dasprintf (dstr, "%s", html_string(set_as_string (kill))); + dasprintf (dstr, "%s", html_string(set_as_string (ops))); + + set_delete (use); + set_delete (def); + set_delete (kill); + } +#endif dasprintf (dstr, "\n"); } From 6ec92fb83bf55f2a46ed07d04e239ffe5794efff Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 15:28:15 +0900 Subject: [PATCH 392/444] [qfcc] Point pointer tempop to the operand It turns out I need the operand itself, not just the tempop. --- tools/qfcc/include/expr.h | 2 +- tools/qfcc/include/value.h | 2 +- tools/qfcc/source/emit.c | 5 +++-- tools/qfcc/source/statements.c | 15 ++++++++------- tools/qfcc/source/value.c | 2 +- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/tools/qfcc/include/expr.h b/tools/qfcc/include/expr.h index b2e01a491..be1640ffc 100644 --- a/tools/qfcc/include/expr.h +++ b/tools/qfcc/include/expr.h @@ -127,7 +127,7 @@ typedef struct ex_pointer_s { int val; struct type_s *type; struct def_s *def; - struct tempop_s *tempop; + struct operand_s *tempop; } ex_pointer_t; typedef struct ex_func_s { diff --git a/tools/qfcc/include/value.h b/tools/qfcc/include/value.h index f2dc7195f..a2f13dd67 100644 --- a/tools/qfcc/include/value.h +++ b/tools/qfcc/include/value.h @@ -51,7 +51,7 @@ struct ex_value_s *new_field_val (int field_val, struct type_s *type, struct ex_value_s *new_func_val (int func_val, struct type_s *type); struct ex_value_s *new_pointer_val (int val, struct type_s *type, struct def_s *def, - struct tempop_s *tempop); + struct operand_s *tempop); struct ex_value_s *new_quaternion_val (const float *quaternion_val); struct ex_value_s *new_integer_val (int integer_val); struct ex_value_s *new_uinteger_val (int uinteger_val); diff --git a/tools/qfcc/source/emit.c b/tools/qfcc/source/emit.c index d9b4167f6..e7a4b2465 100644 --- a/tools/qfcc/source/emit.c +++ b/tools/qfcc/source/emit.c @@ -63,8 +63,9 @@ static def_t zero_def; static def_t *get_operand_def (expr_t *expr, operand_t *op); static def_t * -get_tempop_def (expr_t *expr, tempop_t *tempop, type_t *type) +get_tempop_def (expr_t *expr, operand_t *tmpop, type_t *type) { + tempop_t *tempop = &tmpop->o.tempop; if (tempop->def) { return tempop->def; } @@ -115,7 +116,7 @@ get_operand_def (expr_t *expr, operand_t *op) zero_def.type = &type_short; return &zero_def; //FIXME case op_temp: - return get_tempop_def (expr, &op->o.tempop, op->type); + return get_tempop_def (expr, op, op->type); case op_alias: return get_operand_def (expr, op->o.alias); case op_nil: diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 6058c62a8..ac5d6d6f0 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -78,18 +78,19 @@ optype_str (op_type_e type) } static const char * -tempop_string (tempop_t *tempop) +tempop_string (operand_t *tmpop) { + tempop_t *tempop = &tmpop->o.tempop; if (tempop->alias) { return va ("", pr_type_name[tempop->type->type], - tempop, tempop->users, - &tempop->alias->o.tempop, + tmpop, tempop->users, + tempop->alias, tempop->offset, tempop->alias->o.tempop.users); } return va ("", pr_type_name[tempop->type->type], - &tempop, tempop->users); + tmpop, tempop->users); } const char * @@ -126,7 +127,7 @@ operand_string (operand_t *op) op->o.value->v.pointer.def->name, op->o.value->v.pointer.val); } else if(op->o.value->v.pointer.tempop) { - tempop_t *tempop = op->o.value->v.pointer.tempop; + operand_t *tempop = op->o.value->v.pointer.tempop; return va ("ptr %s+%d", tempop_string (tempop), op->o.value->v.pointer.val); } else { @@ -155,7 +156,7 @@ operand_string (operand_t *op) case op_label: return op->o.label->name; case op_temp: - return tempop_string (&op->o.tempop); + return tempop_string (op); case op_alias: { const char *alias = operand_string (op->o.alias); @@ -703,7 +704,7 @@ operand_address (operand_t *reference, expr_t *e) reference = reference->o.tempop.alias; } return value_operand (new_pointer_val (offset, type, 0, - &reference->o.tempop), e); + reference), e); case op_alias: //op_alias comes only from alias_operand and that is called // by dags, so not expected diff --git a/tools/qfcc/source/value.c b/tools/qfcc/source/value.c index 424dadce5..2ee44db06 100644 --- a/tools/qfcc/source/value.c +++ b/tools/qfcc/source/value.c @@ -198,7 +198,7 @@ new_func_val (int func_val, type_t *type) ex_value_t * new_pointer_val (int pointer_val, type_t *type, def_t *def, - struct tempop_s *tempop) + struct operand_s *tempop) { ex_value_t val; if (!type) { From fa2cbc72d84be5b63812c1a2d8a066466381c471 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 15:48:06 +0900 Subject: [PATCH 393/444] [qfcc] Analyze tempop pointers in move/memset statements --- tools/qfcc/source/flow.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index ba8868f43..febd101b6 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -1054,20 +1054,28 @@ static int flow_analyize_pointer_operand (operand_t *ptrop, set_t *def, operand_t *operands[4]) { - if (ptrop->op_type == op_value - && ptrop->o.value->lltype == ev_pointer - && ptrop->o.value->v.pointer.def) { - operand_t *op; - def_t *alias; + if (ptrop->op_type == op_value && ptrop->o.value->lltype == ev_pointer) { ex_pointer_t *ptr = &ptrop->o.value->v.pointer; - alias = alias_def (ptr->def, ptr->type, ptr->val); - op = def_operand (alias, ptr->type, ptrop->expr); - flow_add_op_var (def, op, 0); - if (operands) - operands[0] = op; - else - free_operand (op); - return 1; + operand_t *op = 0; + if (ptrop->o.value->v.pointer.def) { + def_t *alias; + alias = alias_def (ptr->def, ptr->type, ptr->val); + op = def_operand (alias, ptr->type, ptrop->expr); + } + if (ptrop->o.value->v.pointer.tempop) { + op = ptrop->o.value->v.pointer.tempop; + } + if (op) { + flow_add_op_var (def, op, 0); + if (operands) { + operands[0] = op; + } else { + if (op->op_type != op_temp) { + free_operand (op); + } + } + return 1; + } } return 0; } From dec2e6249ef147a802987d622dfe80c614eeb44d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 16:32:26 +0900 Subject: [PATCH 394/444] [qfcc] Increase flow operand count to 5 MOVEP instructions have up to 5 operands: 2 pointers, the count, and 0-2 referenced variables (when known). --- tools/qfcc/include/flow.h | 3 ++- tools/qfcc/source/dags.c | 14 +++++++++----- tools/qfcc/source/dot_sblock.c | 4 ++-- tools/qfcc/source/flow.c | 8 ++++---- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/tools/qfcc/include/flow.h b/tools/qfcc/include/flow.h index f57fd3c37..f68c5d5cf 100644 --- a/tools/qfcc/include/flow.h +++ b/tools/qfcc/include/flow.h @@ -102,9 +102,10 @@ typedef struct flowgraph_s { flowvar_t *flow_get_var (struct operand_s *op); +#define FLOW_OPERANDS 5 void flow_analyze_statement (struct statement_s *s, struct set_s *use, struct set_s *def, struct set_s *kill, - struct operand_s *operands[4]); + struct operand_s *operands[FLOW_OPERANDS]); void flow_data_flow (struct function_s *func); diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index 6745a7a94..f1e1edde7 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -700,6 +700,8 @@ dag_create (flownode_t *flownode) dagnode_t **nodes; daglabel_t **labels; int num_statements = 0; + int num_nodes; + int num_lables; set_t *live_vars = set_new (); flush_daglabels (); @@ -713,14 +715,16 @@ dag_create (flownode_t *flownode) dag = new_dag (); dag->flownode = flownode; - // at most 4 per statement - dag->nodes = alloca (num_statements * 4 * sizeof (dagnode_t)); - // at most 4 per statement, + return + params - dag->labels = alloca (num_statements * (4 + 1 + 8) * sizeof (daglabel_t)); + // at most FLOW_OPERANDS per statement + num_nodes = num_statements * FLOW_OPERANDS; + dag->nodes = alloca (num_nodes * sizeof (dagnode_t)); + // at most FLOW_OPERANDS per statement, + return + params + num_lables = num_statements * (FLOW_OPERANDS + 1 + 8); + dag->labels = alloca (num_lables * sizeof (daglabel_t)); dag->roots = set_new (); for (s = block->statements; s; s = s->next) { - operand_t *operands[4]; + operand_t *operands[FLOW_OPERANDS]; dagnode_t *n = 0, *children[3] = {0, 0, 0}; daglabel_t *op, *lx; int i; diff --git a/tools/qfcc/source/dot_sblock.c b/tools/qfcc/source/dot_sblock.c index fc892a1c7..b0e975ef7 100644 --- a/tools/qfcc/source/dot_sblock.c +++ b/tools/qfcc/source/dot_sblock.c @@ -69,10 +69,10 @@ flow_statement (dstring_t *dstr, statement_t *s) set_t *def = set_new (); set_t *kill = set_new (); set_t *ops = set_new (); - operand_t *operands[4]; + operand_t *operands[FLOW_OPERANDS]; flow_analyze_statement (s, use, def, kill, operands); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < FLOW_OPERANDS; i++) { if (operands[i]) { set_add (ops, i); } diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index febd101b6..0ccf0d32a 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -509,7 +509,7 @@ static void flow_build_vars (function_t *func) { statement_t *s; - operand_t *operands[4]; + operand_t *operands[FLOW_OPERANDS]; int num_vars = 0; int i, j; set_t *stuse; @@ -1052,7 +1052,7 @@ flow_add_op_var (set_t *set, operand_t *op, int is_use) static int flow_analyize_pointer_operand (operand_t *ptrop, set_t *def, - operand_t *operands[4]) + operand_t *operands[FLOW_OPERANDS]) { if (ptrop->op_type == op_value && ptrop->o.value->lltype == ev_pointer) { ex_pointer_t *ptr = &ptrop->o.value->v.pointer; @@ -1082,7 +1082,7 @@ flow_analyize_pointer_operand (operand_t *ptrop, set_t *def, void flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, - operand_t *operands[4]) + operand_t *operands[FLOW_OPERANDS]) { int i, start, calln = -1; @@ -1093,7 +1093,7 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, if (kill) set_empty (kill); if (operands) { - for (i = 0; i < 4; i++) + for (i = 0; i < FLOW_OPERANDS; i++) operands[i] = 0; } From 3c2f6c8447325ae64fbbc74f93d470296b0ff6b2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 21:28:10 +0900 Subject: [PATCH 395/444] [qfcc] Simplify flow_analyize_pointer_operand and its usage. The parts of flow_analyze_statement that use it know where the returned operand needs to go. Unfortunately, this breaks dags pretty hard, but that's because dags needs to learn about the fancy assignment-type statements. --- tools/qfcc/source/flow.c | 49 +++++++++++++++++----------------------- 1 file changed, 21 insertions(+), 28 deletions(-) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index 0ccf0d32a..adf417989 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -1050,13 +1050,13 @@ flow_add_op_var (set_t *set, operand_t *op, int is_use) } } -static int -flow_analyize_pointer_operand (operand_t *ptrop, set_t *def, - operand_t *operands[FLOW_OPERANDS]) +static operand_t * +flow_analyze_pointer_operand (operand_t *ptrop, set_t *def) { + operand_t *op = 0; + if (ptrop->op_type == op_value && ptrop->o.value->lltype == ev_pointer) { ex_pointer_t *ptr = &ptrop->o.value->v.pointer; - operand_t *op = 0; if (ptrop->o.value->v.pointer.def) { def_t *alias; alias = alias_def (ptr->def, ptr->type, ptr->val); @@ -1067,17 +1067,9 @@ flow_analyize_pointer_operand (operand_t *ptrop, set_t *def, } if (op) { flow_add_op_var (def, op, 0); - if (operands) { - operands[0] = op; - } else { - if (op->op_type != op_temp) { - free_operand (op); - } - } - return 1; } } - return 0; + return op; } void @@ -1085,6 +1077,9 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, operand_t *operands[FLOW_OPERANDS]) { int i, start, calln = -1; + operand_t *res_op = 0; + operand_t *aux_op1 = 0; + operand_t *aux_op2 = 0; if (use) set_empty (use); @@ -1126,17 +1121,19 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, if (!strcmp (s->opcode, "") || !strcmp (s->opcode, "")) { flow_add_op_var (def, s->opc, 0); - } else if (!strcmp (s->opcode, "") - || !strcmp (s->opcode, "")) { + res_op = s->opc; + } else if (!strcmp (s->opcode, "")) { flow_add_op_var (use, s->opc, 0); - if (!flow_analyize_pointer_operand (s->opc, def, operands)) { - if (operands) { - operands[3] = s->opc; - } - } + aux_op2 = flow_analyze_pointer_operand (s->opa, use); + res_op = flow_analyze_pointer_operand (s->opc, def); + aux_op1 = s->opc; + } else if (!strcmp (s->opcode, "")) { + flow_add_op_var (use, s->opc, 0); + res_op = flow_analyze_pointer_operand (s->opc, def); + aux_op1 = s->opc; } else if (!strcmp (s->opcode, ".=")) { flow_add_op_var (use, s->opc, 1); - flow_analyize_pointer_operand (s->opb, def, operands); + res_op = flow_analyze_pointer_operand (s->opb, def); } else { internal_error (s->expr, "unexpected opcode '%s' for %d", s->opcode, s->type); @@ -1145,15 +1142,11 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, set_everything (kill); } if (operands) { - if (!strcmp (s->opcode, "") - || !strcmp (s->opcode, "")) { - operands[0] = s->opc; - } + operands[0] = res_op; operands[1] = s->opa; operands[2] = s->opb; - if (strncmp (s->opcode, "opc; - } + operands[3] = aux_op1; + operands[4] = aux_op2; } break; case st_state: From 16bda667857203a43d26d14d7dfd19eb4ede964f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 21:39:49 +0900 Subject: [PATCH 396/444] [qfcc] Add more statement types for move/memset They ease the statement checks between assign/move/memset and the pointer versions (don't need all those strcmps) --- tools/qfcc/include/statements.h | 13 ++++++++----- tools/qfcc/source/dags.c | 26 ++++++++++++++++++++++---- tools/qfcc/source/flow.c | 3 +++ tools/qfcc/source/statements.c | 11 +++++++---- 4 files changed, 40 insertions(+), 13 deletions(-) diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index 26904db3d..8ee8a16f4 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -73,17 +73,20 @@ typedef struct operand_s { Statement types are broken down into expressions (binary and unary, includes address and pointer dereferencing (read)), assignment, pointer - assignment (write to dereference pointer), move (special case of pointer - assignment), state, function related (call, rcall, return and done), and - flow control (conditional branches, goto, jump (single pointer and jump - table)). + assignment (write to dereference pointer), move (special case of + assignment), pointer move (special case of pointer assignment), state, + function related (call, rcall, return and done), and flow control + (conditional branches, goto, jump (single pointer and jump table)). */ typedef enum { st_none, ///< not a (valid) statement. Used in dags. st_expr, ///< c = a op b; or c = op a; st_assign, ///< b = a st_ptrassign, ///< *b = a; or *(b + c) = a; - st_move, ///< memcpy (c, a, b); + st_move, ///< memcpy (c, a, b); c and a are direct def references + st_ptrmove, ///< memcpy (c, a, b); c and a are pointers + st_memset, ///< memset (c, a, b); c is direct def reference + st_ptrmemset, ///< memset (c, a, b); c is pointer st_state, ///< state (a, b); or state (a, b, c) st_func, ///< call, rcall or return/done st_flow, ///< if/ifa/ifae/ifb/ifbe/ifnot or goto or jump/jumpb diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index f1e1edde7..e594ca2ae 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -49,8 +49,10 @@ #include "dags.h" #include "diagnostic.h" +#include "dot.h" #include "flow.h" #include "function.h" +#include "options.h" #include "qfcc.h" #include "statements.h" #include "strpool.h" @@ -133,6 +135,11 @@ daglabel_string (daglabel_t *label) // operand_string might use quote_string, which returns a pointer to // a static variable. dstring_copystr (str, operand_string (label->op)); +#if 0 + if (label->op->type) { + dstring_appendstr (str, label->op->type->encoding); + } +#endif return quote_string (str->str); } @@ -730,10 +737,13 @@ dag_create (flownode_t *flownode) int i; dag_make_children (dag, s, operands, children); - if (s->type == st_flow || s->type == st_func) - for (i = 0; i < 3; i++) - if (children[i]) + if (s->type == st_flow || s->type == st_func) { + for (i = 0; i < 3; i++) { + if (children[i]) { dag_make_var_live (live_vars, operands[i + 1]); + } + } + } op = opcode_label (dag, s->opcode, s->expr); n = children[0]; if (s->type != st_assign @@ -759,7 +769,12 @@ dag_create (flownode_t *flownode) labels = malloc (dag->num_labels * sizeof (daglabel_t *)); memcpy (labels, dag->labels, dag->num_labels * sizeof (daglabel_t *)); dag->labels = labels; - +#if 0 + if (options.block_dot.dags) { + flownode->dag = dag; + dump_dot ("raw-dags", flownode->graph, dump_dot_flow_dags); + } +#endif dag_remove_dead_vars (dag, live_vars); dag_sort_nodes (dag); set_delete (live_vars); @@ -972,6 +987,9 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode) dst = operands[0]; break; case st_move: + case st_ptrmove: + case st_memset: + case st_ptrmemset: if (!strcmp (dagnode->label->opcode, "")) { dst = generate_moves (dag, block, dagnode); break; diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index adf417989..ac554d0a2 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -1116,6 +1116,9 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, break; case st_ptrassign: case st_move: + case st_ptrmove: + case st_memset: + case st_ptrmemset: flow_add_op_var (use, s->opa, 1); flow_add_op_var (use, s->opb, 1); if (!strcmp (s->opcode, "") diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index ac5d6d6f0..78173ac0b 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -758,7 +758,7 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op, operand_t *src) const char **opcode_set = opcode_sets[0]; const char *opcode; int need_ptr = 0; - //operand_t *dummy; + st_type_t type = st_move; if ((src && src->op_type == op_nil) || src_expr->type == ex_nil) { // switch to memset because nil is type agnostic 0 and structures @@ -769,6 +769,7 @@ expr_assign_copy (sblock_t *sblock, expr_t *e, operand_t **op, operand_t *src) if (op) { *op = nil_operand (dst_type, src_expr); } + type = st_memset; if (is_indirect (dst_expr)) { goto dereference_dst; } @@ -815,9 +816,10 @@ dereference_dst: opcode = opcode_set[0]; } else { opcode = opcode_set[1]; + type++; // from st_move/st_memset to st_ptrmove/st_ptrmemset } - s = new_statement (st_move, opcode, e); + s = new_statement (type, opcode, e); s->opa = src; s->opb = size; s->opc = dst; @@ -932,7 +934,8 @@ expr_move (sblock_t *sblock, expr_t *e, operand_t **op) dst = *op; sblock = statement_subexpr (sblock, src_expr, &src); sblock = statement_subexpr (sblock, size_expr, &size); - s = new_statement (st_move, convert_op (e->e.expr.op), e); + s = new_statement (e->e.expr.op == 'm' ? st_move : st_ptrmove, + convert_op (e->e.expr.op), e); s->opa = src; s->opb = size; s->opc = dst; @@ -1068,7 +1071,7 @@ expr_deref (sblock_t *sblock, expr_t *deref, operand_t **op) dst_addr = operand_address (*op, e); - s = new_statement (st_move, "", deref); + s = new_statement (st_ptrmove, "", deref); s->opa = src_addr; //FIXME large types s->opb = short_operand (type_size (type), e); From 77806f4b1b5929be4aceeb1d138c3a15b6940685 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 22:35:36 +0900 Subject: [PATCH 397/444] [qfcc] Get dag code generation mostly working There's an ICE in return-ivar, but assignchain passes let alone builds. --- tools/qfcc/source/dags.c | 120 ++++++++++++++++++++++++++++++--------- 1 file changed, 93 insertions(+), 27 deletions(-) diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index e594ca2ae..718a6319b 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -746,13 +746,14 @@ dag_create (flownode_t *flownode) } op = opcode_label (dag, s->opcode, s->expr); n = children[0]; - if (s->type != st_assign - && !(n = dagnode_search (dag, op, children))) { - n = new_node (dag); - n->type = s->type; - n->label = op; - dagnode_add_children (dag, n, operands, children); - dagnode_set_edges (dag, n); + if (s->type != st_assign) { + if (!(n = dagnode_search (dag, op, children))) { + n = new_node (dag); + n->type = s->type; + n->label = op; + dagnode_add_children (dag, n, operands, children); + dagnode_set_edges (dag, n); + } } lx = operand_label (dag, operands[0]); if (lx && lx->dagnode != n) { @@ -893,24 +894,91 @@ generate_moveps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) operands[0] = make_operand (dag, block, dagnode, 0); operands[1] = make_operand (dag, block, dagnode, 1); + if (dagnode->children[2]) { + operands[2] = make_operand (dag, block, dagnode, 2); + st = build_statement ("", operands, dagnode->label->expr); + sblock_add_statement (block, st); + } else { + for (var_iter = set_first (dagnode->identifiers); var_iter; + var_iter = set_next (var_iter)) { + var = dag->labels[var_iter->element]; + dst = var->op; + type = dst->o.def->type; + dstDef = dst->o.def; + if (dstDef->alias) { + offset = dstDef->offset; + dstDef = dstDef->alias; + } + operands[2] = value_operand (new_pointer_val (offset, type, dstDef, 0), + operands[1]->expr); + st = build_statement ("", operands, var->expr); + sblock_add_statement (block, st); + } + } + return dst; +} + +static operand_t * +generate_memsets (dag_t *dag, sblock_t *block, dagnode_t *dagnode) +{ + set_iter_t *var_iter; + daglabel_t *var; + operand_t *operands[3] = {0, 0, 0}; + statement_t *st; + operand_t *dst; + + operands[0] = make_operand (dag, block, dagnode, 0); + operands[1] = make_operand (dag, block, dagnode, 1); + dst = operands[0]; for (var_iter = set_first (dagnode->identifiers); var_iter; var_iter = set_next (var_iter)) { var = dag->labels[var_iter->element]; - dst = var->op; - type = dst->o.def->type; - dstDef = dst->o.def; - if (dstDef->alias) { - offset = dstDef->offset; - dstDef = dstDef->alias; - } - operands[2] = value_operand (new_pointer_val (offset, type, dstDef, 0), - operands[1]->expr); - st = build_statement ("", operands, var->expr); + operands[2] = var->op; + dst = operands[2]; + st = build_statement ("", operands, var->expr); sblock_add_statement (block, st); } return dst; } +static operand_t * +generate_memsetps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) +{ + set_iter_t *var_iter; + daglabel_t *var; + operand_t *operands[3] = {0, 0, 0}; + statement_t *st; + operand_t *dst = 0; + type_t *type; + int offset = 0; + def_t *dstDef; + + operands[0] = make_operand (dag, block, dagnode, 0); + operands[1] = make_operand (dag, block, dagnode, 1); + if (dagnode->children[2]) { + operands[2] = make_operand (dag, block, dagnode, 2); + st = build_statement ("", operands, dagnode->label->expr); + sblock_add_statement (block, st); + } else { + for (var_iter = set_first (dagnode->identifiers); var_iter; + var_iter = set_next (var_iter)) { + var = dag->labels[var_iter->element]; + dst = var->op; + type = dst->o.def->type; + dstDef = dst->o.def; + if (dstDef->alias) { + offset = dstDef->offset; + dstDef = dstDef->alias; + } + operands[2] = value_operand (new_pointer_val (offset, type, dstDef, 0), + operands[1]->expr); + st = build_statement ("", operands, var->expr); + sblock_add_statement (block, st); + } + } + return dst; +} + static operand_t * generate_assignments (dag_t *dag, sblock_t *block, operand_t *src, set_iter_t *var_iter, type_t *type) @@ -987,19 +1055,17 @@ dag_gencode (dag_t *dag, sblock_t *block, dagnode_t *dagnode) dst = operands[0]; break; case st_move: + dst = generate_moves (dag, block, dagnode); + break; case st_ptrmove: + dst = generate_moveps (dag, block, dagnode); + break; case st_memset: + dst = generate_memsets (dag, block, dagnode); + break; case st_ptrmemset: - if (!strcmp (dagnode->label->opcode, "")) { - dst = generate_moves (dag, block, dagnode); - break; - } - if (!strcmp (dagnode->label->opcode, "") - && !dagnode->children[2]) { - dst = generate_moveps (dag, block, dagnode); - break; - } - //fall through + dst = generate_memsetps (dag, block, dagnode); + break; case st_state: case st_func: for (i = 0; i < 3; i++) From 34c9ec51bb2cd67866882d0208dc166a59ce1d1a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 22:46:23 +0900 Subject: [PATCH 398/444] [qfcc] Make opcode and statement type names available --- tools/qfcc/include/statements.h | 3 +++ tools/qfcc/source/statements.c | 16 +++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/tools/qfcc/include/statements.h b/tools/qfcc/include/statements.h index 8ee8a16f4..829723729 100644 --- a/tools/qfcc/include/statements.h +++ b/tools/qfcc/include/statements.h @@ -119,6 +119,9 @@ struct expr_s; struct type_s; struct dstring_s; +extern const char *op_type_names[]; +extern const char *st_type_names[]; + const char *optype_str (op_type_e type) __attribute__((const)); operand_t *nil_operand (struct type_s *type, struct expr_s *expr); diff --git a/tools/qfcc/source/statements.c b/tools/qfcc/source/statements.c index 78173ac0b..ba7af0765 100644 --- a/tools/qfcc/source/statements.c +++ b/tools/qfcc/source/statements.c @@ -60,7 +60,7 @@ #include "value.h" #include "qc-parse.h" -static const char *op_type_names[] = { +const char *op_type_names[] = { "op_def", "op_value", "op_label", @@ -69,6 +69,20 @@ static const char *op_type_names[] = { "op_nil", }; +const char *st_type_names[] = { + "st_none", + "st_expr", + "st_assign", + "st_ptrassign", + "st_move", + "st_ptrmove", + "st_memset", + "st_ptrmemset", + "st_state", + "st_func", + "st_flow", +}; + const char * optype_str (op_type_e type) { From 578bf9a16f893619b78acc98d888eb07b4aaf11f Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 22:54:27 +0900 Subject: [PATCH 399/444] [qfcc] Set dag node value for movep This fixes compilation of all tests. However, structptr still fails. --- tools/qfcc/source/dags.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index 718a6319b..6b3e3ff44 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -898,6 +898,11 @@ generate_moveps (dag_t *dag, sblock_t *block, dagnode_t *dagnode) operands[2] = make_operand (dag, block, dagnode, 2); st = build_statement ("", operands, dagnode->label->expr); sblock_add_statement (block, st); + if ((var_iter = set_first (dagnode->identifiers))) { + var = dag->labels[var_iter->element]; + dst = var->op; + set_del_iter (var_iter); + } } else { for (var_iter = set_first (dagnode->identifiers); var_iter; var_iter = set_next (var_iter)) { From 22cd39c853d9c85dae8f976dba82868480758679 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 23:05:57 +0900 Subject: [PATCH 400/444] [qfcc] Mark ptr assignment offset as an operand This fixes structptr. All current tests pass. --- tools/qfcc/source/flow.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qfcc/source/flow.c b/tools/qfcc/source/flow.c index ac554d0a2..438ece827 100644 --- a/tools/qfcc/source/flow.c +++ b/tools/qfcc/source/flow.c @@ -1137,6 +1137,7 @@ flow_analyze_statement (statement_t *s, set_t *use, set_t *def, set_t *kill, } else if (!strcmp (s->opcode, ".=")) { flow_add_op_var (use, s->opc, 1); res_op = flow_analyze_pointer_operand (s->opb, def); + aux_op1 = s->opc; } else { internal_error (s->expr, "unexpected opcode '%s' for %d", s->opcode, s->type); From 43ea34535e9959e997d6efaaddc790b13f2d5dce Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Tue, 17 Mar 2020 23:34:37 +0900 Subject: [PATCH 401/444] [qfcc] Make ivar-struct-return fail It turns out that assignments to struct fields are not counted as live when the whole struct is later used via a pointer move. --- tools/qfcc/test/ivar-struct-return.r | 11 ++++++----- tools/qfcc/test/test-harness.h | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/tools/qfcc/test/ivar-struct-return.r b/tools/qfcc/test/ivar-struct-return.r index a3883b81c..8351293c8 100644 --- a/tools/qfcc/test/ivar-struct-return.r +++ b/tools/qfcc/test/ivar-struct-return.r @@ -1,4 +1,5 @@ #pragma bug die +#include "test-harness.h" struct Point { int x; @@ -11,18 +12,18 @@ typedef struct Point Point; int foo; Point origin; } --(Point) origin; ++(Point) origin; @end @implementation Object --(Point) origin ++(Point) origin { - origin = nil; + origin = {1, 2}; return origin; } @end -void __obj_exec_class (struct obj_module *msg) = #0; int main() { - return 0; // to survive and prevail + Point p = [Object origin]; + return !(p.x == 1 && p.y == 2); } diff --git a/tools/qfcc/test/test-harness.h b/tools/qfcc/test/test-harness.h index f350c7ec7..63f368416 100644 --- a/tools/qfcc/test/test-harness.h +++ b/tools/qfcc/test/test-harness.h @@ -5,3 +5,5 @@ string strerror (int err) = #0; void exit (int code) = #0; entity spawn (void) = #0; void remove (entity e) = #0; +id obj_msgSend (id receiver, SEL op, ...) = #0; +void __obj_exec_class (struct obj_module *msg) = #0; From 0293d335d01b5367c80ac87435137a28287208dc Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 18 Mar 2020 00:02:36 +0900 Subject: [PATCH 402/444] [qfcc] Mark known source def live for movep This fixes ivar-struct-return (and qwaq). --- tools/qfcc/source/dags.c | 5 +++++ tools/qfcc/source/dot_sblock.c | 3 +-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/qfcc/source/dags.c b/tools/qfcc/source/dags.c index 6b3e3ff44..8b352e1c1 100644 --- a/tools/qfcc/source/dags.c +++ b/tools/qfcc/source/dags.c @@ -744,6 +744,11 @@ dag_create (flownode_t *flownode) } } } + if (operands[4]) { + // a movep instruction knew what it was reading, so mark that + // as live + dag_make_var_live (live_vars, operands[4]); + } op = opcode_label (dag, s->opcode, s->expr); n = children[0]; if (s->type != st_assign) { diff --git a/tools/qfcc/source/dot_sblock.c b/tools/qfcc/source/dot_sblock.c index b0e975ef7..8e003aa6b 100644 --- a/tools/qfcc/source/dot_sblock.c +++ b/tools/qfcc/source/dot_sblock.c @@ -102,11 +102,10 @@ dot_sblock (dstring_t *dstr, sblock_t *sblock, int blockno) dasprintf (dstr, " \n"); dasprintf (dstr, " %p(%d)\n", sblock, blockno); - dasprintf (dstr, " \n"); + dasprintf (dstr, " \n"); for (l = sblock->labels; l; l = l->next) dasprintf (dstr, " %s(%d)\n", l->name, l->used); dasprintf (dstr, " \n"); - dasprintf (dstr, " \n"); dasprintf (dstr, " \n"); for (s = sblock->statements; s; s = s->next) flow_statement (dstr, s); From e5bc6dd8b688eeecc9748b0370697db76eb194d2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 18 Mar 2020 01:12:23 +0900 Subject: [PATCH 403/444] [qwaq] Split Array(Group) into its own file --- ruamoko/qwaq/Makefile.am | 1 + ruamoko/qwaq/qwaq-garray.r | 66 ++++++++++++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-group.r | 63 ------------------------------------ 3 files changed, 67 insertions(+), 63 deletions(-) create mode 100644 ruamoko/qwaq/qwaq-garray.r diff --git a/ruamoko/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am index dc5fa56b9..76b4af136 100644 --- a/ruamoko/qwaq/Makefile.am +++ b/ruamoko/qwaq/Makefile.am @@ -26,6 +26,7 @@ SUFFIXES=.o .r qwaq_app_dat_src= \ qwaq-app.r \ qwaq-draw.r \ + qwaq-garray.r \ qwaq-group.r \ qwaq-rect.r \ qwaq-screen.r \ diff --git a/ruamoko/qwaq/qwaq-garray.r b/ruamoko/qwaq/qwaq-garray.r new file mode 100644 index 000000000..1b7fc46d3 --- /dev/null +++ b/ruamoko/qwaq/qwaq-garray.r @@ -0,0 +1,66 @@ +#include +#include "event.h" +#include "qwaq-group.h" + +@implementation Array (Group) +- (void) makeObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data +{ + for (int i = 0; i < [self count]; i++) { + if (condition (_objs[i], data)) { + [_objs[i] performSelector: selector]; + } + } +} + +- (void) makeObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data +{ + for (int i = 0; i < [self count]; i++) { + if (condition (_objs[i], anObject, data)) { + [_objs[i] performSelector: selector withObject: anObject]; + } + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector +{ + for (int i = [self count]; i-->0; ) { + [_objs[i] performSelector: selector]; + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject +{ + for (int i = [self count]; i-->0; ) { + [_objs[i] performSelector: selector withObject: anObject]; + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data +{ + for (int i = [self count]; i-->0; ) { + if (condition (_objs[i], data)) { + [_objs[i] performSelector: selector]; + } + } +} + +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data +{ + for (int i = [self count]; i-->0; ) { + if (condition (_objs[i], anObject, data)) { + [_objs[i] performSelector: selector withObject: anObject]; + } + } +} +@end diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index 57a5eb8a6..205f07dda 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -2,69 +2,6 @@ #include "event.h" #include "qwaq-group.h" -@implementation Array (Group) -- (void) makeObjectsPerformSelector: (SEL)selector - if: (condition_func)condition - with: (void *)data -{ - for (int i = 0; i < [self count]; i++) { - if (condition (_objs[i], data)) { - [_objs[i] performSelector: selector]; - } - } -} - -- (void) makeObjectsPerformSelector: (SEL)selector - withObject: (void *)anObject - if: (condition_func2)condition - with: (void *)data -{ - for (int i = 0; i < [self count]; i++) { - if (condition (_objs[i], anObject, data)) { - [_objs[i] performSelector: selector withObject: anObject]; - } - } -} - -- (void) makeReversedObjectsPerformSelector: (SEL)selector -{ - for (int i = [self count]; i-->0; ) { - [_objs[i] performSelector: selector]; - } -} - -- (void) makeReversedObjectsPerformSelector: (SEL)selector - withObject: (void *)anObject -{ - for (int i = [self count]; i-->0; ) { - [_objs[i] performSelector: selector withObject: anObject]; - } -} - -- (void) makeReversedObjectsPerformSelector: (SEL)selector - if: (condition_func)condition - with: (void *)data -{ - for (int i = [self count]; i-->0; ) { - if (condition (_objs[i], data)) { - [_objs[i] performSelector: selector]; - } - } -} - -- (void) makeReversedObjectsPerformSelector: (SEL)selector - withObject: (void *)anObject - if: (condition_func2)condition - with: (void *)data -{ - for (int i = [self count]; i-->0; ) { - if (condition (_objs[i], anObject, data)) { - [_objs[i] performSelector: selector withObject: anObject]; - } - } -} -@end - @implementation Group -initWithContext: (id) context From affadc3d252c8a74eefad6892527405b082ccbe6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 18 Mar 2020 01:39:12 +0900 Subject: [PATCH 404/444] [qwaq] Create protocols for DrawBuffer and TextContext Plenty of flaws at the moment (casts to id :/), but the basic idea seems to be ok. --- ruamoko/qwaq/qwaq-app.r | 4 +--- ruamoko/qwaq/qwaq-draw.h | 27 +++++++++++++++++---------- ruamoko/qwaq/qwaq-draw.r | 3 +++ ruamoko/qwaq/qwaq-group.h | 4 ++-- ruamoko/qwaq/qwaq-group.r | 3 +-- ruamoko/qwaq/qwaq-screen.r | 2 +- ruamoko/qwaq/qwaq-textcontext.h | 9 ++------- ruamoko/qwaq/qwaq-view.h | 8 ++------ ruamoko/qwaq/qwaq-view.r | 4 +++- ruamoko/qwaq/qwaq-window.r | 8 ++++---- 10 files changed, 36 insertions(+), 36 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 5b5889768..d8809f307 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -47,9 +47,7 @@ arp_end (void) r.offset.y = r.extent.height / 4; r.extent.width /= 2; r.extent.height /= 2; - Window *w; - [objects insert: w=[[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; - //wprintf (w.window, "%d %d %d %d\n", r.offset.x, r.offset.y, r.extent.width, r.ylen); + [objects insert: [[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; return self; } diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h index 5f7c7bc18..1592559d0 100644 --- a/ruamoko/qwaq/qwaq-draw.h +++ b/ruamoko/qwaq/qwaq-draw.h @@ -5,20 +5,17 @@ #include "qwaq-rect.h" -@interface DrawBuffer : Object -{ - int *buffer; - Extent size; - Point cursor; -} -+ (DrawBuffer *) buffer: (Extent) size; -- initWithSize: (Extent) size; +@class DrawBuffer; +@protocol DrawBuffer +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; +- (Rect) rect; - (Extent) size; - (int *) buffer; -- (Rect) rect; +@end -- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; +@protocol TextContext +- (Extent) size; - (void) printf: (string) fmt, ...; - (void) vprintf: (string) fmt, @va_list args; @@ -30,4 +27,14 @@ - (void) mvaddstr: (Point) pos, string str; @end +@interface DrawBuffer : Object +{ + int *buffer; + Extent size; + Point cursor; +} ++ (DrawBuffer *) buffer: (Extent) size; +- initWithSize: (Extent) size; +@end + #endif diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r index 1311deb3c..600537215 100644 --- a/ruamoko/qwaq/qwaq-draw.r +++ b/ruamoko/qwaq/qwaq-draw.r @@ -41,6 +41,9 @@ Rect r = { {}, size }; Rect t = { pos, rect.extent }; + wprintf (stdscr, "src: %p\n", srcBuffer); + wprintf (stdscr, "srcSize: %d %d\n", srcSize.width, srcSize.height); + t = clipRect (r, t); if (t.extent.width < 0 || t.extent.height < 0) { return self; diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h index be251b243..c534979ab 100644 --- a/ruamoko/qwaq/qwaq-group.h +++ b/ruamoko/qwaq/qwaq-group.h @@ -31,9 +31,9 @@ typedef BOOL condition_func2 (id object, void *anObject, void *data); { Array *views; int focused; - id buffer; //FIXME id or sim + id buffer; } --initWithContext: (id) context; //FIXME id or sim +-initWithContext: (id) context; -insert: (View *) view; -remove: (View *) view; @end diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index 205f07dda..770834c71 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -4,14 +4,13 @@ @implementation Group --initWithContext: (id) context +-initWithContext: (id) context { if (!(self = [super init])) { return nil; } textContext = context; absRect = rect = { nil, [textContext size] }; - printf ("\n\nsize:%d %d\n\n", rect.extent.width, rect.extent.height); buffer = [DrawBuffer buffer: rect.extent]; views = [[Array array] retain]; return self; diff --git a/ruamoko/qwaq/qwaq-screen.r b/ruamoko/qwaq/qwaq-screen.r index 16d3f1be6..b6149db25 100644 --- a/ruamoko/qwaq/qwaq-screen.r +++ b/ruamoko/qwaq/qwaq-screen.r @@ -14,7 +14,7 @@ return nil; } textContext = [TextContext screen]; - [textContext scrollok: 1]; + [(id)textContext scrollok: 1]; return self; } diff --git a/ruamoko/qwaq/qwaq-textcontext.h b/ruamoko/qwaq/qwaq-textcontext.h index 1fbcb4fbd..ce0f5ef2c 100644 --- a/ruamoko/qwaq/qwaq-textcontext.h +++ b/ruamoko/qwaq/qwaq-textcontext.h @@ -4,11 +4,12 @@ #ifdef __QFCC__ #include #include "qwaq-curses.h" +#include "qwaq-draw.h" #include "qwaq-rect.h" @class DrawBuffer; -@interface TextContext : Object +@interface TextContext : Object { window_t window; union { @@ -43,12 +44,6 @@ - blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; -- (void) printf: (string) fmt, ...; -- (void) vprintf: (string) mft, @va_list args; -- (void) addch: (int) ch; -- (void) mvprintf: (Point) pos, string fmt, ...; -- (void) mvvprintf: (Point) pos, string mft, @va_list args; -- (void) mvaddch: (Point) pos, int ch; - (void) refresh; + (void) refresh; - (void) bkgd: (int) ch; diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index e6b5bd47e..54e52f03a 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -45,7 +45,7 @@ enum { Rect absRect; Point point; // can't be local :( Group *owner; - TextContext *textContext; + id textContext; int state; int options; int cursorState; @@ -65,11 +65,7 @@ enum { - (void) mvaddch: (Point) pos, int ch; @end -//These are forwarded (FIXME make a protocol) -@interface View (TextContext) -- (void) printf: (string) fmt, ...; -- (void) vprintf: (string) fmt, @va_list args; -- (void) addch: (int) ch; +@interface View (TextContext) @end #endif//__qwaq_view_h diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index b005dd4de..659e9ffbe 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -102,7 +102,9 @@ updateScreenCursor (View *view) - (void) refresh { - [textContext refresh]; + if (__obj_responds_to (textContext, @selector(refresh))) { + [(id)textContext refresh]; + } } - (void) mvprintf: (Point) pos, string fmt, ... diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index a4a69ee83..af0f576cb 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -20,7 +20,7 @@ self.rect = rect; buffer = [[TextContext alloc] initWithRect: rect]; textContext = buffer; - panel = create_panel ([buffer window]); + panel = create_panel ([(id)buffer window]); buf = [DrawBuffer buffer: {3, 3}]; [buf mvaddstr: {0, 0}, "XOX"]; [buf mvaddstr: {0, 1}, "OXO"]; @@ -74,7 +74,7 @@ -setBackground: (int) ch { - [buffer bkgd: ch]; + [(id)buffer bkgd: ch]; return self; } @@ -95,7 +95,7 @@ } } [super draw]; - [buffer border: box_sides, box_corners]; + [(id)buffer border: box_sides, box_corners]; Point pos = { 1, 1 }; //for (int i = ACS_ULCORNER; i <= ACS_STERLING; i++) { for (int i = 32; i <= 127; i++) { @@ -112,7 +112,7 @@ } } } - [textContext blitFromBuffer: buf to: makePoint (6, 3) from: [buf rect]]; + [(id)textContext blitFromBuffer: buf to: makePoint (6, 3) from: [buf rect]]; [self refresh]; return self; } From f6f6b2cba38147ca4b5dc4ef1023473148b234bd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 18 Mar 2020 01:40:58 +0900 Subject: [PATCH 405/444] [qwaq] Doc the issue number for blit slug --- ruamoko/qwaq/qwaq-draw.r | 1 + 1 file changed, 1 insertion(+) diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r index 600537215..fd0d368aa 100644 --- a/ruamoko/qwaq/qwaq-draw.r +++ b/ruamoko/qwaq/qwaq-draw.r @@ -73,6 +73,7 @@ for (int x = 0; x < rect.extent.width; x++) { // FIXME 1) need memcpy/memmove // 2) the generated code could be better + // github issue #3 *d++ = *s++; } } From 4c6e1b7fc4a9f15d1c180e31d4884e1b54491d2e Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Wed, 18 Mar 2020 01:51:52 +0900 Subject: [PATCH 406/444] [qfcc] Fix some uninitialized variable warnings I really wish gcc would catch more issues when not optimizing. --- tools/qfcc/source/constfold.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/constfold.c b/tools/qfcc/source/constfold.c index e1b380a5d..f367987a3 100644 --- a/tools/qfcc/source/constfold.c +++ b/tools/qfcc/source/constfold.c @@ -790,7 +790,7 @@ static expr_t * do_op_integer (int op, expr_t *e, expr_t *e1, expr_t *e2) { int isval1 = 0, isval2 = 0; - int val1, val2; + int val1 = 0, val2 = 0; static int valid[] = { '=', '+', '-', '*', '/', '&', '|', '^', '%', SHL, SHR, AND, OR, LT, GT, LE, GE, EQ, NE, 0 From 7447854d7c70aa01c72779ac0831d52d0cbf36c5 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 11:01:26 +0900 Subject: [PATCH 407/444] [qfcc] Recover from syntax errors in abstract_decl --- tools/qfcc/source/qc-parse.y | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/qfcc/source/qc-parse.y b/tools/qfcc/source/qc-parse.y index 7f257505b..4e49397bc 100644 --- a/tools/qfcc/source/qc-parse.y +++ b/tools/qfcc/source/qc-parse.y @@ -914,6 +914,7 @@ abstract_decl $1.type = type_default; $$->type = find_type (append_type ($$->type, $1.type)); } + | error { $$ = new_symbol (""); } ; qc_param_decl From b16093a5336ba79dd93efdae1a458525e73662d4 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 11:04:02 +0900 Subject: [PATCH 408/444] [qwaq] Split out Array(Group) interface --- ruamoko/qwaq/qwaq-garray.h | 29 +++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-garray.r | 2 +- ruamoko/qwaq/qwaq-group.h | 24 ------------------------ ruamoko/qwaq/qwaq-group.r | 1 + 4 files changed, 31 insertions(+), 25 deletions(-) create mode 100644 ruamoko/qwaq/qwaq-garray.h diff --git a/ruamoko/qwaq/qwaq-garray.h b/ruamoko/qwaq/qwaq-garray.h new file mode 100644 index 000000000..1a2e53576 --- /dev/null +++ b/ruamoko/qwaq/qwaq-garray.h @@ -0,0 +1,29 @@ +#ifndef __qwaq_garray_h +#define __qwaq_garray_h + +#include + +typedef BOOL condition_func (id object, void *data); +typedef BOOL condition_func2 (id object, void *anObject, void *data); + +@interface Array (Group) +- (void) makeObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data; +- (void) makeObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data; +- (void) makeReversedObjectsPerformSelector: (SEL)selector; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + if: (condition_func)condition + with: (void *)data; +- (void) makeReversedObjectsPerformSelector: (SEL)selector + withObject: (void *)anObject + if: (condition_func2)condition + with: (void *)data; +@end + +#endif//__qwaq_garray_h diff --git a/ruamoko/qwaq/qwaq-garray.r b/ruamoko/qwaq/qwaq-garray.r index 1b7fc46d3..b3298ffa4 100644 --- a/ruamoko/qwaq/qwaq-garray.r +++ b/ruamoko/qwaq/qwaq-garray.r @@ -1,6 +1,6 @@ #include #include "event.h" -#include "qwaq-group.h" +#include "qwaq-garray.h" @implementation Array (Group) - (void) makeObjectsPerformSelector: (SEL)selector diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h index c534979ab..483a07c05 100644 --- a/ruamoko/qwaq/qwaq-group.h +++ b/ruamoko/qwaq/qwaq-group.h @@ -1,32 +1,8 @@ #ifndef __qwaq_group_h #define __qwaq_group_h -#include #include "qwaq-view.h" -typedef BOOL condition_func (id object, void *data); -typedef BOOL condition_func2 (id object, void *anObject, void *data); - -@interface Array (Group) -- (void) makeObjectsPerformSelector: (SEL)selector - if: (condition_func)condition - with: (void *)data; -- (void) makeObjectsPerformSelector: (SEL)selector - withObject: (void *)anObject - if: (condition_func2)condition - with: (void *)data; -- (void) makeReversedObjectsPerformSelector: (SEL)selector; -- (void) makeReversedObjectsPerformSelector: (SEL)selector - withObject: (void *)anObject; -- (void) makeReversedObjectsPerformSelector: (SEL)selector - if: (condition_func)condition - with: (void *)data; -- (void) makeReversedObjectsPerformSelector: (SEL)selector - withObject: (void *)anObject - if: (condition_func2)condition - with: (void *)data; -@end - @interface Group : View { Array *views; diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index 770834c71..e9982fd1c 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -1,5 +1,6 @@ #include #include "event.h" +#include "qwaq-garray.h" #include "qwaq-group.h" @implementation Group From 2f3ca9d9e477ed96103a36cbb0d8edf6416dc90c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 11:32:44 +0900 Subject: [PATCH 409/444] [qwaq] Clean up the hierarchy I think I've finally figured out what I want the core hierarchy to be. Right now, it's just the two classes: View and Window (derived from View). Window has a Group, and Group is just a collection of Views that it manages. QwaqApplication is just an object but like a Window, it has a Group of views. View Window has a Group Group contains Views QwaqApplication has a group More work needs to be done on drawing and event handling, but things are working again. --- ruamoko/qwaq/qwaq-app.r | 1 + ruamoko/qwaq/qwaq-group.h | 14 +++++++++++--- ruamoko/qwaq/qwaq-group.r | 25 ++++++++++--------------- ruamoko/qwaq/qwaq-view.h | 9 ++++++++- ruamoko/qwaq/qwaq-view.r | 13 ++++++++++++- ruamoko/qwaq/qwaq-window.h | 8 ++++---- ruamoko/qwaq/qwaq-window.r | 16 +++++++++++----- 7 files changed, 57 insertions(+), 29 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index d8809f307..798c83308 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -4,6 +4,7 @@ int fence; #include "color.h" #include "qwaq-app.h" #include "qwaq-curses.h" +#include "qwaq-group.h" #include "qwaq-window.h" #include "qwaq-screen.h" #include "qwaq-view.h" diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h index 483a07c05..956e43d1a 100644 --- a/ruamoko/qwaq/qwaq-group.h +++ b/ruamoko/qwaq/qwaq-group.h @@ -1,17 +1,25 @@ #ifndef __qwaq_group_h #define __qwaq_group_h -#include "qwaq-view.h" +#include -@interface Group : View +#include "event.h" +#include "qwaq-draw.h" + +@class View; + +@interface Group : Object { Array *views; int focused; - id buffer; + id context; } -initWithContext: (id) context; -insert: (View *) view; -remove: (View *) view; +-draw; +-redraw; +-handleEvent: (qwaq_event_t *) event; @end #endif//__qwaq_group_h diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index e9982fd1c..0480fbf05 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -1,7 +1,9 @@ #include #include "event.h" +#include "qwaq-draw.h" #include "qwaq-garray.h" #include "qwaq-group.h" +#include "qwaq-view.h" @implementation Group @@ -10,18 +12,7 @@ if (!(self = [super init])) { return nil; } - textContext = context; - absRect = rect = { nil, [textContext size] }; - buffer = [DrawBuffer buffer: rect.extent]; - views = [[Array array] retain]; - return self; -} - --initWithRect: (Rect) rect -{ - if (!(self = [super initWithRect: rect])) { - return nil; - } + self.context = context; views = [[Array array] retain]; return self; } @@ -34,7 +25,7 @@ -insert: (View *) view { [views addObject: view]; - view.textContext = buffer; + [view setContext: context]; return self; } @@ -58,7 +49,7 @@ not_dont_draw (id aView, void *aGroup) View *view = aView; Group *group = (Group *) aGroup; - return !(view.options & ofDontDraw); + return !([view options] & ofDontDraw); } -draw @@ -69,9 +60,13 @@ not_dont_draw (id aView, void *aGroup) return self; } +-redraw +{ + return self; +} + -handleEvent: (qwaq_event_t *) event { - [super handleEvent: event]; if (event.what & qe_focused) { if (focused >= 0) { [[views objectAtIndex:focused] handleEvent: event]; diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index 54e52f03a..ef6d79568 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -53,12 +53,19 @@ enum { } -initWithRect: (Rect) rect; - (void) dealloc; + -setOwner: (Group *) owner; --(struct Rect_s *)getRect; + +-(struct Rect_s *)rect; + +-(int) options; + +-setContext: (id) context; -draw; -redraw; -handleEvent: (qwaq_event_t *) event; + - (void) refresh; - (void) mvprintf: (Point) pos, string fmt, ...; - (void) mvvprintf: (Point) pos, string fmt, @va_list args; diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 659e9ffbe..5217504fd 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -27,6 +27,17 @@ [super dealloc]; } +- setContext: (id) context +{ + textContext = context; + return self; +} + +- (int) options +{ + return options; +} + static void updateScreenCursor (View *view) { @@ -84,7 +95,7 @@ updateScreenCursor (View *view) return self; } -- (Rect *) getRect +- (Rect *) rect { return ▭ } diff --git a/ruamoko/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h index 2e925c035..18c4f9fc6 100644 --- a/ruamoko/qwaq/qwaq-window.h +++ b/ruamoko/qwaq/qwaq-window.h @@ -3,17 +3,17 @@ #include "Object.h" -@class Array; +@class Group; #include "qwaq-draw.h" #include "qwaq-rect.h" #include "qwaq-view.h" -#include "qwaq-group.h" -@interface Window: Group +@interface Window: View { - Point point; // FIXME can't be local :( struct panel_s *panel; + Group *objects; + Point point; // FIXME can't be local :( DrawBuffer *buf; } +windowWithRect: (Rect) rect; diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index af0f576cb..0f3c81037 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -2,6 +2,7 @@ #include "event.h" #include "qwaq-curses.h" +#include "qwaq-group.h" #include "qwaq-window.h" #include "qwaq-view.h" @@ -18,9 +19,9 @@ return nil; } self.rect = rect; - buffer = [[TextContext alloc] initWithRect: rect]; - textContext = buffer; - panel = create_panel ([(id)buffer window]); + textContext = [[TextContext alloc] initWithRect: rect]; + panel = create_panel ([(id)textContext window]); + buf = [DrawBuffer buffer: {3, 3}]; [buf mvaddstr: {0, 0}, "XOX"]; [buf mvaddstr: {0, 1}, "OXO"]; @@ -28,6 +29,11 @@ return self; } +-setContext: (id) context +{ + return self; +} + -handleEvent: (qwaq_event_t *) event { /* switch (event.what) { @@ -74,7 +80,7 @@ -setBackground: (int) ch { - [(id)buffer bkgd: ch]; + [(id)textContext bkgd: ch]; return self; } @@ -95,7 +101,7 @@ } } [super draw]; - [(id)buffer border: box_sides, box_corners]; + [(id)textContext border: box_sides, box_corners]; Point pos = { 1, 1 }; //for (int i = ACS_ULCORNER; i <= ACS_STERLING; i++) { for (int i = 32; i <= 127; i++) { From 01835cbd94349f6b729e11929fc380d1b1a9ed89 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 13:48:48 +0900 Subject: [PATCH 410/444] [qwaq] Add blitFromBuffer to TextContext protocol --- ruamoko/qwaq/qwaq-draw.h | 1 + ruamoko/qwaq/qwaq-window.r | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h index 1592559d0..efda03b41 100644 --- a/ruamoko/qwaq/qwaq-draw.h +++ b/ruamoko/qwaq/qwaq-draw.h @@ -15,6 +15,7 @@ @end @protocol TextContext +- blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; - (Extent) size; - (void) printf: (string) fmt, ...; diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 0f3c81037..d2b52e985 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -118,7 +118,7 @@ } } } - [(id)textContext blitFromBuffer: buf to: makePoint (6, 3) from: [buf rect]]; + [textContext blitFromBuffer: buf to: makePoint (6, 3) from: [buf rect]]; [self refresh]; return self; } From 8c3cf83f02b57c09040b4600b58822648c102405 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 13:49:27 +0900 Subject: [PATCH 411/444] [qwaq] Add Listener and ListenerGroup delegates Simple single parameter (caller) direct messages. --- ruamoko/qwaq/Makefile.am | 1 + ruamoko/qwaq/qwaq-listener.h | 29 ++++++++++++++++ ruamoko/qwaq/qwaq-listener.r | 66 ++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 ruamoko/qwaq/qwaq-listener.h create mode 100644 ruamoko/qwaq/qwaq-listener.r diff --git a/ruamoko/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am index 76b4af136..f0dbe4167 100644 --- a/ruamoko/qwaq/Makefile.am +++ b/ruamoko/qwaq/Makefile.am @@ -28,6 +28,7 @@ qwaq_app_dat_src= \ qwaq-draw.r \ qwaq-garray.r \ qwaq-group.r \ + qwaq-listener.r \ qwaq-rect.r \ qwaq-screen.r \ qwaq-textcontext.r \ diff --git a/ruamoko/qwaq/qwaq-listener.h b/ruamoko/qwaq/qwaq-listener.h new file mode 100644 index 000000000..bb02d71f1 --- /dev/null +++ b/ruamoko/qwaq/qwaq-listener.h @@ -0,0 +1,29 @@ +#ifndef __qwaq_listener_h +#define __qwaq_listener_h + +#include + +@class Array; + +@interface Listener : Object +{ + id responder; + SEL message; + IMP imp; +} +-initWithResponder: (id) responder message: (SEL) message; +-(void) respond: (id) caller; +-(BOOL) matchResponder: (id) responder message: (SEL) message; +@end + +@interface ListenerGroup : Object +{ + Array *listeners; +} +-init; +-addListener: (id) responder message: (SEL) message; +-removeListener: (id) responder message: (SEL) message; +-(void) respond: (id) caller; +@end + +#endif//__qwaq_listener_h diff --git a/ruamoko/qwaq/qwaq-listener.r b/ruamoko/qwaq/qwaq-listener.r new file mode 100644 index 000000000..5184668fd --- /dev/null +++ b/ruamoko/qwaq/qwaq-listener.r @@ -0,0 +1,66 @@ +#include + +#include "qwaq-listener.h" + +@class Array; + +@implementation Listener +-initWithResponder: (id) responder message: (SEL) message +{ + if (!(self = [super init])) { + return nil; + } + self.responder = responder; + self.message = message; + imp = [responder instanceMethodForSelector: message]; + return self; +} + +-(void)respond: (id) caller +{ + imp (responder, message, caller); +} + +-(BOOL) matchResponder: (id) responder message: (SEL) message +{ + return self.responder == responder && self.message == message; +} +@end + +@implementation ListenerGroup : Object +-init +{ + if (!(self = [super init])) { + return nil; + } + listeners = [[Array alloc] retain]; + return self; +} + +-addListener: (id) responder message: (SEL) message +{ + Listener *listener = [[Listener alloc] initWithResponder: responder + message: message]; + if (listener) { + [listeners addObject: listener]; + } + return self; +} + +-removeListener: (id) responder message: (SEL) message +{ + for (int i = [listeners count]; i-- > 0; ) { + Listener *l = [listeners objectAtIndex: i]; + if ([l matchResponder: responder message: message]) { + [listeners removeObjectAtIndex: i]; + } + } + return self; +} + +-(void)respond: (id) caller +{ + [listeners makeObjectsPerformSelector: @selector (respond:) + withObject: caller]; +} +@end From 03f87d6f27cc4eed12c380b5397f3ec270ba2f20 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 13:50:35 +0900 Subject: [PATCH 412/444] [qwaq] Add pos Point alias --- ruamoko/qwaq/qwaq-view.h | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index ef6d79568..920fa793e 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -36,10 +36,14 @@ enum { union { Rect rect; struct { - int xpos; - int ypos; - int xlen; - int ylen; + int xpos; + int ypos; + int xlen; + int ylen; + }; + struct { + Point pos; + Extent size; }; }; Rect absRect; From 6a18b1dd559c4324b16bae6815cf9cd9aa05506b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 13:51:14 +0900 Subject: [PATCH 413/444] [qwaq] Add function to merge extents It's pretty much the union of two rectangles with the same origin. --- ruamoko/qwaq/qwaq-rect.h | 1 + ruamoko/qwaq/qwaq-rect.r | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/ruamoko/qwaq/qwaq-rect.h b/ruamoko/qwaq/qwaq-rect.h index 7cd72e886..3278afd14 100644 --- a/ruamoko/qwaq/qwaq-rect.h +++ b/ruamoko/qwaq/qwaq-rect.h @@ -20,6 +20,7 @@ typedef struct Rect_s { @extern Rect makeRect (int xpos, int ypos, int xlen, int ylen); @extern Point makePoint (int x, int y); @extern Extent makeExtent (int width, int height); +@extern Extent mergeExtents (Extent a, Extent b); //XXX will not work if point or rect point to a local variabl @extern int rectContainsPoint (Rect *rect, Point *point); @extern Rect clipRect (Rect clipRect, Rect rect); diff --git a/ruamoko/qwaq/qwaq-rect.r b/ruamoko/qwaq/qwaq-rect.r index e0e3e5ee6..64048ca0b 100644 --- a/ruamoko/qwaq/qwaq-rect.r +++ b/ruamoko/qwaq/qwaq-rect.r @@ -39,6 +39,12 @@ Extent makeExtent (int width, int height) return {width, height}; } +Extent mergeExtents (Extent a, Extent b) +{ + return { a.width < b.width ? b.width : a.width, + a.height < b.height ? b.height : a.height }; +} + int rectContainsPoint (Rect *rect, Point *point) { From bd3884f6fabf940affef7c289d251ff36c35b128 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 13:52:14 +0900 Subject: [PATCH 414/444] [qwaq] Add a button class It may or may not work just yet, but I think it's the right direction. --- ruamoko/qwaq/Makefile.am | 1 + ruamoko/qwaq/qwaq-button.h | 28 ++++++++++++ ruamoko/qwaq/qwaq-button.r | 91 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 ruamoko/qwaq/qwaq-button.h create mode 100644 ruamoko/qwaq/qwaq-button.r diff --git a/ruamoko/qwaq/Makefile.am b/ruamoko/qwaq/Makefile.am index f0dbe4167..683a0923c 100644 --- a/ruamoko/qwaq/Makefile.am +++ b/ruamoko/qwaq/Makefile.am @@ -25,6 +25,7 @@ SUFFIXES=.o .r qwaq_app_dat_src= \ qwaq-app.r \ + qwaq-button.r \ qwaq-draw.r \ qwaq-garray.r \ qwaq-group.r \ diff --git a/ruamoko/qwaq/qwaq-button.h b/ruamoko/qwaq/qwaq-button.h new file mode 100644 index 000000000..2c19236d3 --- /dev/null +++ b/ruamoko/qwaq/qwaq-button.h @@ -0,0 +1,28 @@ +#ifndef __qwaq_button_h +#define __qwaq_button_h + +#include "qwaq-draw.h" +#include "qwaq-view.h" + +@class ListenerGroup; + +@interface Button : View +{ + DrawBuffer *icon[2]; + int pressed; + ListenerGroup *onPress; + ListenerGroup *onRelease; + ListenerGroup *onClick; + ListenerGroup *onDrag; + ListenerGroup *onAuto; +} +-initWithPos: (Point) pos releasedIcon: (DrawBuffer *) released + pressedIcon: (DrawBuffer *) pressed; +-(ListenerGroup *) onPress; +-(ListenerGroup *) onRelease; +-(ListenerGroup *) onClick; +-(ListenerGroup *) onDrag; +-(ListenerGroup *) onAuto; +@end + +#endif//__qwaq_button_h diff --git a/ruamoko/qwaq/qwaq-button.r b/ruamoko/qwaq/qwaq-button.r new file mode 100644 index 000000000..d79092b0c --- /dev/null +++ b/ruamoko/qwaq/qwaq-button.r @@ -0,0 +1,91 @@ +#include "qwaq-button.h" +#include "qwaq-listener.h" + +@implementation Button +-initWithPos: (Point) pos releasedIcon: (DrawBuffer *) released + pressedIcon: (DrawBuffer *) pressed +{ + Extent size = mergeExtents ([released size], [pressed size]); + + if (!(self = [super initWithRect: {pos, size}])) { + return nil; + } + icon[0] = released; + icon[1] = pressed; + onPress = [[ListenerGroup alloc] init]; + onRelease = [[ListenerGroup alloc] init]; + onClick = [[ListenerGroup alloc] init]; + onDrag = [[ListenerGroup alloc] init]; + onAuto = [[ListenerGroup alloc] init]; + return self; +} + +-draw +{ + [textContext blitFromBuffer: icon[pressed] + to: pos + from: [icon[pressed] rect]]; + return self; +} + +-handleEvent: (qwaq_event_t *) event +{ + ListenerGroup *action = nil; + + if (event.what & qe_mouse) { + switch ((qwaq_mouse_event) (event.what & qe_mouse)) { + case qe_mousedown: + pressed = 1; + [self redraw]; + action = onPress; + break; + case qe_mouseup: + pressed = 0; + [self redraw]; + action = onRelease; + break; + case qe_mouseclick: + action = onClick; + break; + case qe_mousemove: + if (pressed) { + action = onDrag; + } + break; + case qe_mouseauto: + action = onAuto; + break; + } + if (action) { + [action respond: self]; + } + } + return self; +} + +-(ListenerGroup *) onPress +{ + return onPress; +} + +-(ListenerGroup *) onRelease +{ + return onRelease; +} + +-(ListenerGroup *) onClick +{ + return onClick; +} + +-(ListenerGroup *) onDrag +{ + return onDrag; +} + +-(ListenerGroup *) onAuto +{ + return onAuto; +} + +@end From db39f7ed3e87851b6e7fec7a5f7042a894122056 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 13:57:10 +0900 Subject: [PATCH 415/444] [qwaq] Add hover listener to button Forgot about this (very useful for tooltips etc). --- ruamoko/qwaq/qwaq-button.h | 2 ++ ruamoko/qwaq/qwaq-button.r | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/ruamoko/qwaq/qwaq-button.h b/ruamoko/qwaq/qwaq-button.h index 2c19236d3..470a2ae08 100644 --- a/ruamoko/qwaq/qwaq-button.h +++ b/ruamoko/qwaq/qwaq-button.h @@ -15,6 +15,7 @@ ListenerGroup *onClick; ListenerGroup *onDrag; ListenerGroup *onAuto; + ListenerGroup *onHover; } -initWithPos: (Point) pos releasedIcon: (DrawBuffer *) released pressedIcon: (DrawBuffer *) pressed; @@ -23,6 +24,7 @@ -(ListenerGroup *) onClick; -(ListenerGroup *) onDrag; -(ListenerGroup *) onAuto; +-(ListenerGroup *) onHover; @end #endif//__qwaq_button_h diff --git a/ruamoko/qwaq/qwaq-button.r b/ruamoko/qwaq/qwaq-button.r index d79092b0c..093865576 100644 --- a/ruamoko/qwaq/qwaq-button.r +++ b/ruamoko/qwaq/qwaq-button.r @@ -17,6 +17,7 @@ onClick = [[ListenerGroup alloc] init]; onDrag = [[ListenerGroup alloc] init]; onAuto = [[ListenerGroup alloc] init]; + onHover = [[ListenerGroup alloc] init]; return self; } @@ -88,4 +89,8 @@ return onAuto; } +-(ListenerGroup *) onHover +{ + return onHover; +} @end From 3e9977c272debe36c27eeb9c8785a9123e9745fd Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 15:53:20 +0900 Subject: [PATCH 416/444] [qwaq] Give up on pass-by-reference for now It's too much hassle to ensure the passed variable isn't a local. It's just not worth the grief right now. --- ruamoko/qwaq/qwaq-rect.h | 3 +-- ruamoko/qwaq/qwaq-rect.r | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ruamoko/qwaq/qwaq-rect.h b/ruamoko/qwaq/qwaq-rect.h index 3278afd14..2ab79788e 100644 --- a/ruamoko/qwaq/qwaq-rect.h +++ b/ruamoko/qwaq/qwaq-rect.h @@ -21,8 +21,7 @@ typedef struct Rect_s { @extern Point makePoint (int x, int y); @extern Extent makeExtent (int width, int height); @extern Extent mergeExtents (Extent a, Extent b); -//XXX will not work if point or rect point to a local variabl -@extern int rectContainsPoint (Rect *rect, Point *point); +@extern int rectContainsPoint (Rect rect, Point point); @extern Rect clipRect (Rect clipRect, Rect rect); #endif diff --git a/ruamoko/qwaq/qwaq-rect.r b/ruamoko/qwaq/qwaq-rect.r index 64048ca0b..c2677decc 100644 --- a/ruamoko/qwaq/qwaq-rect.r +++ b/ruamoko/qwaq/qwaq-rect.r @@ -46,7 +46,7 @@ Extent mergeExtents (Extent a, Extent b) } int -rectContainsPoint (Rect *rect, Point *point) +rectContainsPoint (Rect rect, Point point) { return ((point.x >= rect.offset.x && point.x < rect.offset.x + rect.extent.width) From 23e6b498454d27f53b2dc173e58a890e2f1294a3 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 15:55:57 +0900 Subject: [PATCH 417/444] [qwaq] Implement mouse enter/leave events --- ruamoko/qwaq/qwaq-group.h | 2 ++ ruamoko/qwaq/qwaq-group.r | 30 ++++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-view.h | 7 ++++++- ruamoko/qwaq/qwaq-view.r | 18 ++++++++++++++++-- 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h index 956e43d1a..c1edd01b3 100644 --- a/ruamoko/qwaq/qwaq-group.h +++ b/ruamoko/qwaq/qwaq-group.h @@ -11,6 +11,8 @@ @interface Group : Object { Array *views; + View *mouse_grabbed; + View *mouse_within; int focused; id context; } diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index 0480fbf05..75c5c2a90 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -65,6 +65,18 @@ not_dont_draw (id aView, void *aGroup) return self; } +static View * +find_mouse_view(Group *group, Point pos) +{ + for (int i = [group.views count]; i--; ) { + View *v = [group.views objectAtIndex: i]; + if ([v containsPoint: pos]) { + return v; + } + } + return nil; +} + -handleEvent: (qwaq_event_t *) event { if (event.what & qe_focused) { @@ -72,6 +84,24 @@ not_dont_draw (id aView, void *aGroup) [[views objectAtIndex:focused] handleEvent: event]; } } else if (event.what & qe_positional) { + Point pos = {event.mouse.x, event.mouse.y}; + if (mouse_grabbed) { + [mouse_grabbed handleEvent: event]; + } else { + if (mouse_within && ![mouse_within containsPoint: pos]) { + [mouse_within onMouseLeave: pos]; + mouse_within = nil; + } + if (!mouse_within) { + mouse_within = find_mouse_view (self, pos); + if (mouse_within) { + [mouse_within onMouseEnter: pos]; + } + } + if (mouse_within) { + [mouse_within handleEvent: event]; + } + } } else { // broadcast [views makeObjectsPerformSelector: @selector(draw) withObject: event]; diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index 920fa793e..a7314f7e0 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -60,7 +60,9 @@ enum { -setOwner: (Group *) owner; --(struct Rect_s *)rect; +-(Rect)rect; + +-(int) containsPoint: (Point) point; -(int) options; @@ -69,6 +71,9 @@ enum { -redraw; -handleEvent: (qwaq_event_t *) event; +- (void) onMouseEnter: (Point) pos; +- (void) onMouseLeave: (Point) pos; + - (void) refresh; - (void) mvprintf: (Point) pos, string fmt, ...; diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 5217504fd..b46004755 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -95,9 +95,14 @@ updateScreenCursor (View *view) return self; } -- (Rect *) rect +- (Rect) rect { - return ▭ + return rect; +} + +-(int) containsPoint: (Point) point +{ + return rectContainsPoint (rect, point); } - (void) forward: (SEL) sel : (@va_list) args @@ -144,4 +149,13 @@ updateScreenCursor (View *view) return self; } +- (void) onMouseEnter: (Point) pos +{ +} + +- (void) onMouseLeave: (Point) pos +{ +} + + @end From 19161ea80a60c4b568c738f228b14180a747adb2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 16:27:30 +0900 Subject: [PATCH 418/444] [qwaq] Clean things up in prep for button testing --- ruamoko/qwaq/qwaq-app.r | 2 +- ruamoko/qwaq/qwaq-group.h | 5 ++- ruamoko/qwaq/qwaq-group.r | 17 +++++++++- ruamoko/qwaq/qwaq-view.h | 2 ++ ruamoko/qwaq/qwaq-view.r | 10 ++++++ ruamoko/qwaq/qwaq-window.r | 68 +++----------------------------------- 6 files changed, 38 insertions(+), 66 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 798c83308..e040fe84c 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -40,7 +40,7 @@ arp_end (void) init_pair (2, COLOR_WHITE, COLOR_BLACK); TextContext *screen = [TextContext screen]; - objects = [[Group alloc] initWithContext: screen]; + objects = [[Group alloc] initWithContext: screen owner: nil]; [screen bkgd: COLOR_PAIR (1)]; Rect r = { nil, [screen size] }; diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h index c1edd01b3..f9e4bc858 100644 --- a/ruamoko/qwaq/qwaq-group.h +++ b/ruamoko/qwaq/qwaq-group.h @@ -10,18 +10,21 @@ @interface Group : Object { + View *owner; Array *views; View *mouse_grabbed; View *mouse_within; int focused; id context; } --initWithContext: (id) context; +-initWithContext: (id) context owner: (View *) owner; -insert: (View *) view; -remove: (View *) view; -draw; -redraw; -handleEvent: (qwaq_event_t *) event; +-(void) grabMouse; +-(void) releaseMouse; @end #endif//__qwaq_group_h diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index 75c5c2a90..284a8a6a3 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -7,12 +7,14 @@ @implementation Group --initWithContext: (id) context +-initWithContext: (id) context owner: (View *) owner { if (!(self = [super init])) { return nil; } + self.owner = owner; self.context = context; + focused = -1; views = [[Array array] retain]; return self; } @@ -108,4 +110,17 @@ find_mouse_view(Group *group, Point pos) } return self; } + +-(void) grabMouse +{ + mouse_grabbed = mouse_within; + [owner grabMouse]; +} + +-(void) releaseMouse +{ + mouse_grabbed = mouse_within; + [owner grabMouse]; +} + @end diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index a7314f7e0..e56a38ffa 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -63,6 +63,8 @@ enum { -(Rect)rect; -(int) containsPoint: (Point) point; +-(void) grabMouse; +-(void) releaseMouse; -(int) options; diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index b46004755..6302e7db1 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -105,6 +105,16 @@ updateScreenCursor (View *view) return rectContainsPoint (rect, point); } +-(void) grabMouse +{ + [owner grabMouse]; +} + +-(void) releaseMouse +{ + [owner releaseMouse]; +} + - (void) forward: (SEL) sel : (@va_list) args { if (!textContext) { diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index d2b52e985..d0ee95fa2 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -22,6 +22,8 @@ textContext = [[TextContext alloc] initWithRect: rect]; panel = create_panel ([(id)textContext window]); + objects = [[Group alloc] initWithContext: textContext owner: self]; + buf = [DrawBuffer buffer: {3, 3}]; [buf mvaddstr: {0, 0}, "XOX"]; [buf mvaddstr: {0, 1}, "OXO"]; @@ -36,45 +38,13 @@ -handleEvent: (qwaq_event_t *) event { -/* switch (event.what) { - case qe_mouse: - mvwprintf(window, 0, 3, "%2d %2d %08x", - event.mouse.x, event.mouse.y, event.mouse.buttons); - [self redraw]; - point.x = event.mouse.x; - point.y = event.mouse.y; - for (int i = [views count]; i--> 0; ) { - View *v = [views objectAtIndex: i]; - if (rectContainsPoint (&v.absRect, &point)) { - [v handleEvent: event]; - break; - } - } - break; - case qe_key: - case qe_command: - if (focusedView) { - [focusedView handleEvent: event]; - for (int i = [views count]; - event.what != qe_none && i--> 0; ) { - View *v = [views objectAtIndex: i]; - [v handleEvent: event]; - } - } - break; - case qe_none: - break; - }*/ + [objects handleEvent: event]; return self; } -addView: (View *) view { -/* [views addObject: view]; - view.absRect.xpos = view.rect.xpos + rect.xpos; - view.absRect.ypos = view.rect.ypos + rect.ypos; - view.window = window; - [view setOwner: self];*/ + [objects insert: view]; return self; } @@ -102,35 +72,7 @@ } [super draw]; [(id)textContext border: box_sides, box_corners]; - Point pos = { 1, 1 }; - //for (int i = ACS_ULCORNER; i <= ACS_STERLING; i++) { - for (int i = 32; i <= 127; i++) { - int ch = acs_char (i); - if (ch) { - [self mvaddch: pos, ch]; - } else { - [self mvaddch: pos, '.']; - } - if (++pos.x > 32) { - pos.x = 1; - if (++pos.y >= ylen) { - break; - } - } - } - [textContext blitFromBuffer: buf to: makePoint (6, 3) from: [buf rect]]; - [self refresh]; - return self; -} - --(Rect *) getRect -{ - return ▭ -} - --setOwner: owner -{ - self.owner = owner; + [objects draw]; return self; } From 1306d9fcdd1a0094feb48e2a5205ef36c799971d Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 17:33:47 +0900 Subject: [PATCH 419/444] [qwaq] Fix some issues in Listener* --- ruamoko/qwaq/qwaq-listener.r | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruamoko/qwaq/qwaq-listener.r b/ruamoko/qwaq/qwaq-listener.r index 5184668fd..14a0816aa 100644 --- a/ruamoko/qwaq/qwaq-listener.r +++ b/ruamoko/qwaq/qwaq-listener.r @@ -12,7 +12,7 @@ } self.responder = responder; self.message = message; - imp = [responder instanceMethodForSelector: message]; + imp = [responder methodForSelector: message]; return self; } @@ -33,7 +33,7 @@ if (!(self = [super init])) { return nil; } - listeners = [[Array alloc] retain]; + listeners = [[Array array] retain]; return self; } From ec2409cebad037f02b28a02430d4db7d7b5c61d8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 17:34:29 +0900 Subject: [PATCH 420/444] [qwaq] Mention that Window knows addView --- ruamoko/qwaq/qwaq-window.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ruamoko/qwaq/qwaq-window.h b/ruamoko/qwaq/qwaq-window.h index 18c4f9fc6..215fcc2db 100644 --- a/ruamoko/qwaq/qwaq-window.h +++ b/ruamoko/qwaq/qwaq-window.h @@ -18,6 +18,7 @@ } +windowWithRect: (Rect) rect; -setBackground: (int) ch; +-addView: (View *) view; @end #endif//__qwaq_window_h From 490f1ad4b8e69230d74a26edf06b067f1e549938 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 18:36:15 +0900 Subject: [PATCH 421/444] [qwaq] Add wrappers for werase --- ruamoko/qwaq/qwaq-curses.c | 45 +++++++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-curses.h | 1 + ruamoko/qwaq/qwaq-textcontext.r | 2 ++ 3 files changed, 48 insertions(+) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index 3da81cfe3..cfad0c6ff 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -76,6 +76,7 @@ typedef enum qwaq_commands_e { qwaq_cmd_wrefresh, qwaq_cmd_init_pair, qwaq_cmd_wbkgd, + qwaq_cmd_werase, qwaq_cmd_scrollok, qwaq_cmd_move, qwaq_cmd_curs_set, @@ -104,6 +105,7 @@ const char *qwaq_command_names[]= { "wrefresh", "init_pair", "wbkgd", + "werase", "scrollok", "move", "curs_set", @@ -578,6 +580,15 @@ cmd_wbkgd (qwaq_resources_t *res) wbkgd (window->win, ch); } +static void +cmd_werase (qwaq_resources_t *res) +{ + int window_id = RB_PEEK_DATA (res->command_queue, 2); + + window_t *window = get_window (res, __FUNCTION__, window_id); + werase (window->win); +} + static void cmd_scrollok (qwaq_resources_t *res) { @@ -717,6 +728,9 @@ process_commands (qwaq_resources_t *res) case qwaq_cmd_wbkgd: cmd_wbkgd (res); break; + case qwaq_cmd_werase: + cmd_werase (res); + break; case qwaq_cmd_scrollok: cmd_scrollok (res); break; @@ -1384,6 +1398,26 @@ bi_wbkgd (progs_t *pr) qwaq_wbkgd (pr, window_id, ch); } +static void +qwaq_werase (progs_t *pr, int window_id, int ch) +{ + qwaq_resources_t *res = PR_Resources_Find (pr, "qwaq"); + + if (get_window (res, __FUNCTION__, window_id)) { + int command[] = { qwaq_cmd_werase, 0, window_id, }; + command[1] = CMD_SIZE(command); + qwaq_submit_command (res, command); + } +} +static void +bi_werase (progs_t *pr) +{ + int window_id = P_INT (pr, 0); + int ch = P_INT (pr, 1); + + qwaq_werase (pr, window_id, ch); +} + static void qwaq_scrollok (progs_t *pr, int window_id, int flag) { @@ -1719,6 +1753,15 @@ bi_i_TextContext__bkgd_ (progs_t *pr) qwaq_wbkgd (pr, window_id, ch); } +static void +bi_i_TextContext__clear (progs_t *pr) +{ + int window_id = P_STRUCT (pr, qwaq_textcontext_t, 0).window; + int ch = P_INT (pr, 2); + + qwaq_werase (pr, window_id, ch); +} + static void bi_i_TextContext__scrollok_ (progs_t *pr) { @@ -1781,6 +1824,7 @@ static builtin_t builtins[] = { {"max_color_pairs", bi_max_color_pairs, -1}, {"init_pair", bi_init_pair, -1}, {"wbkgd", bi_wbkgd, -1}, + {"werase", bi_werase, -1}, {"scrollok", bi_scrollok, -1}, {"acs_char", bi_acs_char, -1}, {"move", bi_move, -1}, @@ -1809,6 +1853,7 @@ static builtin_t builtins[] = { {"_i_TextContext__mvaddch_", bi_i_TextContext__mvaddch_, -1}, {"_i_TextContext__mvaddstr_", bi_i_TextContext__mvaddstr_, -1}, {"_i_TextContext__bkgd_", bi_i_TextContext__bkgd_, -1}, + {"_i_TextContext__clear", bi_i_TextContext__clear, -1}, {"_i_TextContext__scrollok_", bi_i_TextContext__scrollok_, -1}, {"_i_TextContext__border_", bi_i_TextContext__border_, -1}, diff --git a/ruamoko/qwaq/qwaq-curses.h b/ruamoko/qwaq/qwaq-curses.h index fc5c5c4cc..6d0c43df2 100644 --- a/ruamoko/qwaq/qwaq-curses.h +++ b/ruamoko/qwaq/qwaq-curses.h @@ -116,6 +116,7 @@ typedef struct panel_s *panel_t; @extern int max_color_pairs (void); @extern int init_pair (int pair, int f, int b); @extern void wbkgd (window_t win, int ch); +@extern void werase (window_t win); @extern void scrollok (window_t win, int flag); @extern int acs_char (int acs); diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index d7ec2a4c4..85507dfce 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -133,6 +133,7 @@ static TextContext *screen; + (void) refresh = #0; - (void) bkgd: (int) ch = #0; +- (void) clear = #0; - (void) scrollok: (int) flag = #0; - (void) border: (box_sides_t) sides, box_corners_t corners = #0; @@ -157,6 +158,7 @@ int max_colors (void) = #0; int max_color_pairs (void) = #0; int init_pair (int pair, int f, int b) = #0; void wbkgd (window_t win, int ch) = #0; +void werase (window_t win) = #0; void scrollok (window_t win, int flag) = #0; int acs_char (int acs) = #0; From e49ba896aad3e117263d900ffaa1a4982a56034b Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 18:37:25 +0900 Subject: [PATCH 422/444] [qwaq] Support background and clearing in DrawBuffer --- ruamoko/qwaq/qwaq-draw.h | 3 +++ ruamoko/qwaq/qwaq-draw.r | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/ruamoko/qwaq/qwaq-draw.h b/ruamoko/qwaq/qwaq-draw.h index efda03b41..65599347f 100644 --- a/ruamoko/qwaq/qwaq-draw.h +++ b/ruamoko/qwaq/qwaq-draw.h @@ -18,6 +18,8 @@ - blitFromBuffer: (DrawBuffer *) srcBuffer to: (Point) pos from: (Rect) rect; - (Extent) size; +- (void) bkgd: (int) ch; +- (void) clear; - (void) printf: (string) fmt, ...; - (void) vprintf: (string) fmt, @va_list args; - (void) addch: (int) ch; @@ -33,6 +35,7 @@ int *buffer; Extent size; Point cursor; + int background; } + (DrawBuffer *) buffer: (Extent) size; - initWithSize: (Extent) size; diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r index fd0d368aa..947d349f7 100644 --- a/ruamoko/qwaq/qwaq-draw.r +++ b/ruamoko/qwaq/qwaq-draw.r @@ -80,6 +80,26 @@ return self; } +- (void) bkgd: (int) ch +{ + if ((ch & 0xff) < 32) { + ch = (ch & ~0xff) | 32; + } + background = ch; +} + +- (void) clear +{ + int ch = background; + int *dst = buffer; + int *end = buffer + size.width * size.height; + + while (dst < end) { + *dst++ = ch; + } + cursor = {0, 0}; +} + - (void) printf: (string) fmt, ... { string str = vsprintf (fmt, @args); @@ -113,6 +133,12 @@ } else if (ch == '\r') { cursor.x = 0; } else { + if ((ch & 0xff) < 32) { + ch = (ch & ~0xff) | 32; + } + if (!(ch & ~0xff)) { + ch |= background & ~0xff; + } buffer[cursor.y * size.width + cursor.x++] = ch; } } From 8bd702ab1a5dc0097b43dc12fbf3faadcfb1e82a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 18:38:24 +0900 Subject: [PATCH 423/444] [qwaq] Fetch View origin and size separately --- ruamoko/qwaq/qwaq-view.h | 2 ++ ruamoko/qwaq/qwaq-view.r | 11 +++++++++++ 2 files changed, 13 insertions(+) diff --git a/ruamoko/qwaq/qwaq-view.h b/ruamoko/qwaq/qwaq-view.h index e56a38ffa..2bb646653 100644 --- a/ruamoko/qwaq/qwaq-view.h +++ b/ruamoko/qwaq/qwaq-view.h @@ -61,6 +61,8 @@ enum { -setOwner: (Group *) owner; -(Rect)rect; +-(Point)origin; +-(Extent)size; -(int) containsPoint: (Point) point; -(void) grabMouse; diff --git a/ruamoko/qwaq/qwaq-view.r b/ruamoko/qwaq/qwaq-view.r index 6302e7db1..936a83352 100644 --- a/ruamoko/qwaq/qwaq-view.r +++ b/ruamoko/qwaq/qwaq-view.r @@ -100,6 +100,17 @@ updateScreenCursor (View *view) return rect; } +-(Point)origin +{ + return pos; +} + +-(Extent)size +{ + return size; +} + + -(int) containsPoint: (Point) point { return rectContainsPoint (rect, point); From 28a9e041e64678777c2c6a0ab4bf3fbd3cf5bb34 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 18:39:11 +0900 Subject: [PATCH 424/444] [qwaq] Implement Group redraw --- ruamoko/qwaq/qwaq-group.r | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index 284a8a6a3..a358a4f59 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -64,6 +64,14 @@ not_dont_draw (id aView, void *aGroup) -redraw { + if (owner) { + [owner redraw]; + } else { + [self draw]; + if (__obj_responds_to (context, @selector(refresh))) { + [(id)context refresh]; + } + } return self; } From cce6837fe8119a0832c1721e0357d63c23143e66 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 18:40:21 +0900 Subject: [PATCH 425/444] [qwaq] Offset event mouse coordinates Each level of the object hierarchy has its own offset relative to the level above, but mouse coordinates are absolute. --- ruamoko/qwaq/qwaq-button.r | 1 + ruamoko/qwaq/qwaq-group.r | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/ruamoko/qwaq/qwaq-button.r b/ruamoko/qwaq/qwaq-button.r index 093865576..cece78609 100644 --- a/ruamoko/qwaq/qwaq-button.r +++ b/ruamoko/qwaq/qwaq-button.r @@ -23,6 +23,7 @@ -draw { + [super draw]; [textContext blitFromBuffer: icon[pressed] to: pos from: [icon[pressed] rect]]; diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index a358a4f59..48eca7bd6 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -94,6 +94,12 @@ find_mouse_view(Group *group, Point pos) [[views objectAtIndex:focused] handleEvent: event]; } } else if (event.what & qe_positional) { + Point origin = {}; + if (owner) { + origin = [owner origin]; + } + event.mouse.x -= origin.x; + event.mouse.y -= origin.y; Point pos = {event.mouse.x, event.mouse.y}; if (mouse_grabbed) { [mouse_grabbed handleEvent: event]; @@ -112,6 +118,8 @@ find_mouse_view(Group *group, Point pos) [mouse_within handleEvent: event]; } } + event.mouse.x += origin.x; + event.mouse.y += origin.y; } else { // broadcast [views makeObjectsPerformSelector: @selector(draw) withObject: event]; From 2c20a031e41592bd2d6833eb46c9a2d900e6d729 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 18:41:53 +0900 Subject: [PATCH 426/444] [qwaq] Do up a little button test "scene" Hmm... "scene"... too much Unity? --- ruamoko/qwaq/qwaq-app.h | 4 +++ ruamoko/qwaq/qwaq-app.r | 57 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.h b/ruamoko/qwaq/qwaq-app.h index 7062ad096..db341c7a3 100644 --- a/ruamoko/qwaq/qwaq-app.h +++ b/ruamoko/qwaq/qwaq-app.h @@ -6,6 +6,7 @@ #include "event.h" @class Group; +@class TextContext; @interface QwaqApplication: Object { @@ -13,6 +14,9 @@ qwaq_command endState; Group *objects; + + TextContext *screen; + int autocount; } -run; -draw; diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index e040fe84c..9df5bf3e1 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -3,8 +3,10 @@ int fence; #include "color.h" #include "qwaq-app.h" +#include "qwaq-button.h" #include "qwaq-curses.h" #include "qwaq-group.h" +#include "qwaq-listener.h" #include "qwaq-window.h" #include "qwaq-screen.h" #include "qwaq-view.h" @@ -38,8 +40,10 @@ arp_end (void) initialize (); init_pair (1, COLOR_WHITE, COLOR_BLUE); init_pair (2, COLOR_WHITE, COLOR_BLACK); + init_pair (3, COLOR_WHITE, COLOR_GREEN); + init_pair (4, COLOR_YELLOW, COLOR_RED); - TextContext *screen = [TextContext screen]; + screen = [TextContext screen]; objects = [[Group alloc] initWithContext: screen owner: nil]; [screen bkgd: COLOR_PAIR (1)]; @@ -48,10 +52,59 @@ arp_end (void) r.offset.y = r.extent.height / 4; r.extent.width /= 2; r.extent.height /= 2; - [objects insert: [[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; + Window *w; + [objects insert: w = [[Window windowWithRect: r] setBackground: COLOR_PAIR (2)]]; + DrawBuffer *released = [DrawBuffer buffer: {12, 1}]; + DrawBuffer *pressed = [DrawBuffer buffer: {12, 1}]; + Button *b = [[Button alloc] initWithPos: {3, 4} releasedIcon: released + pressedIcon: pressed]; + [w addView: b]; + [released bkgd: COLOR_PAIR(3)]; + [released clear]; + [released mvaddstr: {2, 0}, "press me"]; + [pressed bkgd: COLOR_PAIR(4)]; + [pressed clear]; + [pressed mvaddstr: {1, 0}, "release me"]; + [[b onPress] addListener: self message: @selector (buttonPressed:)]; + [[b onRelease] addListener: self message: @selector (buttonReleased:)]; + [[b onClick] addListener: self message: @selector (buttonClick:)]; + [[b onDrag] addListener: self message: @selector (buttonDrag:)]; + [[b onAuto] addListener: self message: @selector (buttonAuto:)]; return self; } +-(void) buttonPressed: (id) sender +{ + [screen mvaddstr: {2, 0}, " pressed"]; + [screen refresh]; +} + +-(void) buttonReleased: (id) sender +{ + [screen mvaddstr: {2, 0}, "released"]; + [screen refresh]; +} + +-(void) buttonClick: (id) sender +{ + [screen mvaddstr: {2, 0}, "clicked "]; + [screen refresh]; +} + +-(void) buttonDrag: (id) sender +{ + [screen mvaddstr: {2, 0}, "dragged "]; + Rect rect = [sender rect]; + [screen mvprintf: {15, 0}, "%d %d", rect.offset.x, rect.offset.y]; + [screen refresh]; +} + +-(void) buttonAuto: (id) sender +{ + [screen mvprintf: {2, 1}, "%d", autocount++]; + [screen refresh]; +} + -run { [self draw]; From 95d20d67c77897d30cb79d9791c1f6f9fec986ea Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 19:00:03 +0900 Subject: [PATCH 427/444] [qwaq] Implement mouse grabbing Button will need it for dragging. --- ruamoko/qwaq/qwaq-app.r | 2 +- ruamoko/qwaq/qwaq-button.r | 6 ++++-- ruamoko/qwaq/qwaq-group.r | 5 +++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 9df5bf3e1..7d5ed4ba2 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -40,7 +40,7 @@ arp_end (void) initialize (); init_pair (1, COLOR_WHITE, COLOR_BLUE); init_pair (2, COLOR_WHITE, COLOR_BLACK); - init_pair (3, COLOR_WHITE, COLOR_GREEN); + init_pair (3, COLOR_BLACK, COLOR_GREEN); init_pair (4, COLOR_YELLOW, COLOR_RED); screen = [TextContext screen]; diff --git a/ruamoko/qwaq/qwaq-button.r b/ruamoko/qwaq/qwaq-button.r index cece78609..6287de9ce 100644 --- a/ruamoko/qwaq/qwaq-button.r +++ b/ruamoko/qwaq/qwaq-button.r @@ -38,13 +38,15 @@ switch ((qwaq_mouse_event) (event.what & qe_mouse)) { case qe_mousedown: pressed = 1; - [self redraw]; action = onPress; + [self grabMouse]; + [self redraw]; break; case qe_mouseup: pressed = 0; - [self redraw]; action = onRelease; + [self releaseMouse]; + [self redraw]; break; case qe_mouseclick: action = onClick; diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index 48eca7bd6..c8af9bf8a 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -27,6 +27,7 @@ -insert: (View *) view { [views addObject: view]; + [view setOwner: self]; [view setContext: context]; return self; } @@ -135,8 +136,8 @@ find_mouse_view(Group *group, Point pos) -(void) releaseMouse { - mouse_grabbed = mouse_within; - [owner grabMouse]; + mouse_grabbed = nil; + [owner releaseMouse]; } @end From e8d947ed8a7314e58d48d8f5a0fb118b73b6c008 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 19:25:57 +0900 Subject: [PATCH 428/444] [qwaq] Get click and drag reporting working --- ruamoko/qwaq/qwaq-app.r | 12 ++++++------ ruamoko/qwaq/qwaq-button.h | 6 ++++++ ruamoko/qwaq/qwaq-button.r | 21 +++++++++++++++++++++ 3 files changed, 33 insertions(+), 6 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 7d5ed4ba2..2aaf62880 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -75,33 +75,33 @@ arp_end (void) -(void) buttonPressed: (id) sender { - [screen mvaddstr: {2, 0}, " pressed"]; + [screen mvaddstr: {2, 0}, " pressed "]; [screen refresh]; } -(void) buttonReleased: (id) sender { - [screen mvaddstr: {2, 0}, "released"]; + [screen mvaddstr: {2, 0}, "released "]; [screen refresh]; } -(void) buttonClick: (id) sender { - [screen mvaddstr: {2, 0}, "clicked "]; + [screen mvprintf: {2, 1}, "clicked %d", [sender click]]; [screen refresh]; } -(void) buttonDrag: (id) sender { [screen mvaddstr: {2, 0}, "dragged "]; - Rect rect = [sender rect]; - [screen mvprintf: {15, 0}, "%d %d", rect.offset.x, rect.offset.y]; + Point delta = [sender delta]; + [screen mvprintf: {15, 0}, "%3d %3d", delta.x, delta.y]; [screen refresh]; } -(void) buttonAuto: (id) sender { - [screen mvprintf: {2, 1}, "%d", autocount++]; + [screen mvprintf: {2, 2}, "%d", autocount++]; [screen refresh]; } diff --git a/ruamoko/qwaq/qwaq-button.h b/ruamoko/qwaq/qwaq-button.h index 470a2ae08..bab624e35 100644 --- a/ruamoko/qwaq/qwaq-button.h +++ b/ruamoko/qwaq/qwaq-button.h @@ -10,6 +10,9 @@ { DrawBuffer *icon[2]; int pressed; + int click; + Point dragBase; + Point dragPos; ListenerGroup *onPress; ListenerGroup *onRelease; ListenerGroup *onClick; @@ -25,6 +28,9 @@ -(ListenerGroup *) onDrag; -(ListenerGroup *) onAuto; -(ListenerGroup *) onHover; + +- (int) click; +- (Point) delta; @end #endif//__qwaq_button_h diff --git a/ruamoko/qwaq/qwaq-button.r b/ruamoko/qwaq/qwaq-button.r index 6287de9ce..fe7aa5f2f 100644 --- a/ruamoko/qwaq/qwaq-button.r +++ b/ruamoko/qwaq/qwaq-button.r @@ -38,25 +38,35 @@ switch ((qwaq_mouse_event) (event.what & qe_mouse)) { case qe_mousedown: pressed = 1; + click = 0; + dragBase = {event.mouse.x, event.mouse.y}; action = onPress; [self grabMouse]; [self redraw]; break; case qe_mouseup: pressed = 0; + click = 0; action = onRelease; [self releaseMouse]; + if ([self containsPoint: {event.mouse.x, event.mouse.y}]) { + [onClick respond: self]; + } [self redraw]; break; case qe_mouseclick: action = onClick; + click = event.mouse.click; break; case qe_mousemove: + click = 0; if (pressed) { + dragPos = {event.mouse.x, event.mouse.y}; action = onDrag; } break; case qe_mouseauto: + click = 0; action = onAuto; break; } @@ -96,4 +106,15 @@ { return onHover; } + +- (int) click +{ + return click; +} + +- (Point) delta +{ + return {dragPos.x - dragBase.x, dragPos.y - dragBase.y}; +} + @end From 14fbdc7df91c090fa87b78cc30319effb90fb21a Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 19:35:19 +0900 Subject: [PATCH 429/444] [qwaq] Clean up debug in TextContext --- ruamoko/qwaq/qwaq-textcontext.r | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/ruamoko/qwaq/qwaq-textcontext.r b/ruamoko/qwaq/qwaq-textcontext.r index 85507dfce..d2fd9144b 100644 --- a/ruamoko/qwaq/qwaq-textcontext.r +++ b/ruamoko/qwaq/qwaq-textcontext.r @@ -74,19 +74,7 @@ static TextContext *screen; Rect r = { {}, size }; Rect t = { pos, rect.extent }; - wprintf (stdscr, "src: %p\n", srcBuffer); - wprintf (stdscr, "srcSize: %d %d\n", srcSize.width, srcSize.height); - wprintf (stdscr, "pos: %d %d\n", pos.x, pos.x); - wprintf (stdscr, "rect: %d %d %d %d\n", - rect.offset.x, rect.offset.y, - rect.extent.width, rect.extent.height); - wprintf (stdscr, "r: %d %d %d %d\n", - r.offset.x, r.offset.y, r.extent.width, r.extent.height); - wprintf (stdscr, "t: %d %d %d %d\n", - t.offset.x, t.offset.y, t.extent.width, t.extent.height); t = clipRect (r, t); - wprintf (stdscr, "t: %d %d %d %d\n", - t.offset.x, t.offset.y, t.extent.width, t.extent.height); if (t.extent.width < 0 || t.extent.height < 0) { return self; } @@ -100,12 +88,6 @@ static TextContext *screen; r.extent = size; rect = clipRect (r, rect); - wprintf (stdscr, "pos: %d %d\n", pos.x, pos.x); - wprintf (stdscr, "rect: %d %d %d %d\n", - rect.offset.x, rect.offset.y, - rect.extent.width, rect.extent.height); - wprintf (stdscr, "r: %d %d %d %d\n", - r.offset.x, r.offset.y, r.extent.width, r.extent.height); if (rect.extent.width < 0 || rect.extent.height < 0) { return self; } From f027a42e72679d561a237cac5cd4ed8120186981 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 19:53:32 +0900 Subject: [PATCH 430/444] [qwaq] Treat 0 as transparent character --- ruamoko/qwaq/qwaq-curses.c | 4 +++- ruamoko/qwaq/qwaq-draw.r | 5 +---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index cfad0c6ff..c3dcf1b4c 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -649,7 +649,9 @@ cmd_mvwblit_line (qwaq_resources_t *res) getyx (window->win, save_y, save_x); for (int i = 0; i < len; i++) { Sys_Printf(" %d", chs[i]); - mvwaddch (window->win, y, x + i, chs[i]); + if (chs[i] & 0xff) { + mvwaddch (window->win, y, x + i, chs[i]); + } } Sys_Printf("\n"); wmove (window->win, save_y, save_x); diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r index 947d349f7..31975ef19 100644 --- a/ruamoko/qwaq/qwaq-draw.r +++ b/ruamoko/qwaq/qwaq-draw.r @@ -82,9 +82,6 @@ - (void) bkgd: (int) ch { - if ((ch & 0xff) < 32) { - ch = (ch & ~0xff) | 32; - } background = ch; } @@ -132,7 +129,7 @@ cursor.y++; } else if (ch == '\r') { cursor.x = 0; - } else { + } else if (ch & 0xff) { if ((ch & 0xff) < 32) { ch = (ch & ~0xff) | 32; } From fe4f8315120db57323b53c5642a8335785778554 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 20:31:01 +0900 Subject: [PATCH 431/444] [qwaq] Remove a pile of stray panel_free calls C&P programming FTW :P --- ruamoko/qwaq/qwaq-curses.c | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index c3dcf1b4c..afb2ca246 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -436,7 +436,6 @@ cmd_hide_panel (qwaq_resources_t *res) panel_t *panel = get_panel (res, __FUNCTION__, panel_id); hide_panel (panel->panel); - panel_free (res, panel); } static void @@ -446,7 +445,6 @@ cmd_show_panel (qwaq_resources_t *res) panel_t *panel = get_panel (res, __FUNCTION__, panel_id); show_panel (panel->panel); - panel_free (res, panel); } static void @@ -456,7 +454,6 @@ cmd_top_panel (qwaq_resources_t *res) panel_t *panel = get_panel (res, __FUNCTION__, panel_id); top_panel (panel->panel); - panel_free (res, panel); } static void @@ -466,7 +463,6 @@ cmd_bottom_panel (qwaq_resources_t *res) panel_t *panel = get_panel (res, __FUNCTION__, panel_id); bottom_panel (panel->panel); - panel_free (res, panel); } static void @@ -478,7 +474,6 @@ cmd_move_panel (qwaq_resources_t *res) panel_t *panel = get_panel (res, __FUNCTION__, panel_id); move_panel (panel->panel, y, x); - panel_free (res, panel); } static void @@ -648,12 +643,10 @@ cmd_mvwblit_line (qwaq_resources_t *res) window_t *window = get_window (res, __FUNCTION__, window_id); getyx (window->win, save_y, save_x); for (int i = 0; i < len; i++) { - Sys_Printf(" %d", chs[i]); if (chs[i] & 0xff) { mvwaddch (window->win, y, x + i, chs[i]); } } - Sys_Printf("\n"); wmove (window->win, save_y, save_x); release_string (res, chs_id); } @@ -663,12 +656,12 @@ process_commands (qwaq_resources_t *res) { while (RB_DATA_AVAILABLE (res->command_queue) >= 2) { qwaq_commands cmd = RB_PEEK_DATA (res->command_queue, 0); - int len = RB_PEEK_DATA (res->command_queue, 1); - Sys_Printf ("%s[%d]", qwaq_command_names[cmd], len); - for (int i = 2; i < len; i++) { - Sys_Printf (" %d", RB_PEEK_DATA (res->command_queue, i)); - } - Sys_Printf ("\n"); + //int len = RB_PEEK_DATA (res->command_queue, 1); + //Sys_Printf ("%s[%d]", qwaq_command_names[cmd], len); + //for (int i = 2; i < len; i++) { + // Sys_Printf (" %d", RB_PEEK_DATA (res->command_queue, i)); + //} + //Sys_Printf ("\n"); switch (cmd) { case qwaq_cmd_newwin: cmd_newwin (res); From 3a28d84c3fc992647d5478c6ebc1bcedf9eca845 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 20:31:59 +0900 Subject: [PATCH 432/444] [qwaq] Implement window dragging Other than the stray panel_free, that was surprisingly easy. However, do need to check that the window can be moved otherwise window pos and panel pos will get out of sync. --- ruamoko/qwaq/qwaq-window.r | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index d0ee95fa2..35a0af8b4 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -1,8 +1,11 @@ #include +#include #include "event.h" +#include "qwaq-button.h" #include "qwaq-curses.h" #include "qwaq-group.h" +#include "qwaq-listener.h" #include "qwaq-window.h" #include "qwaq-view.h" @@ -24,6 +27,15 @@ objects = [[Group alloc] initWithContext: textContext owner: self]; + string titlestr = "drag me"; + DrawBuffer *title = [DrawBuffer buffer: {xlen, 1}]; + [title mvaddstr: {(xlen - strlen(titlestr)) / 2, 0}, titlestr]; + + Button *b = [[Button alloc] initWithPos: {0, 0} releasedIcon: title + pressedIcon: title]; + [[b onDrag] addListener: self message: @selector(dragWindow:)]; + [self addView: b]; + buf = [DrawBuffer buffer: {3, 3}]; [buf mvaddstr: {0, 0}, "XOX"]; [buf mvaddstr: {0, 1}, "OXO"]; @@ -31,6 +43,15 @@ return self; } +- (void) dragWindow: (Button *) sender +{ + Point delta = [sender delta]; + xpos += delta.x; + ypos += delta.y; + move_panel (panel, xpos, ypos); + [owner redraw]; +} + -setContext: (id) context { return self; From f329ca83b67ec73ad54dc0c8e02d642eb24d1d35 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 20:39:23 +0900 Subject: [PATCH 433/444] [qwaq] Ensure background color clearing works Even with 0 for the character, colors should get into the buffer. --- ruamoko/qwaq/qwaq-draw.r | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ruamoko/qwaq/qwaq-draw.r b/ruamoko/qwaq/qwaq-draw.r index 31975ef19..757f00e90 100644 --- a/ruamoko/qwaq/qwaq-draw.r +++ b/ruamoko/qwaq/qwaq-draw.r @@ -91,6 +91,9 @@ int *dst = buffer; int *end = buffer + size.width * size.height; + if (ch && !(ch & 0xff)) { + ch |= ' '; + } while (dst < end) { *dst++ = ch; } @@ -129,10 +132,7 @@ cursor.y++; } else if (ch == '\r') { cursor.x = 0; - } else if (ch & 0xff) { - if ((ch & 0xff) < 32) { - ch = (ch & ~0xff) | 32; - } + } else { if (!(ch & ~0xff)) { ch |= background & ~0xff; } From ac23156ecd9cf1d6d3309752033240b1be0278e6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 21:28:55 +0900 Subject: [PATCH 434/444] [qwaq] Clamp window motion to owner's bounds --- ruamoko/qwaq/qwaq-group.h | 3 +++ ruamoko/qwaq/qwaq-group.r | 24 ++++++++++++++++++++++++ ruamoko/qwaq/qwaq-window.r | 20 +++++++++++++++++--- 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/ruamoko/qwaq/qwaq-group.h b/ruamoko/qwaq/qwaq-group.h index f9e4bc858..eaa7606eb 100644 --- a/ruamoko/qwaq/qwaq-group.h +++ b/ruamoko/qwaq/qwaq-group.h @@ -20,6 +20,9 @@ -initWithContext: (id) context owner: (View *) owner; -insert: (View *) view; -remove: (View *) view; +-(Rect) rect; +-(Point) origin; +-(Extent) size; -draw; -redraw; -handleEvent: (qwaq_event_t *) event; diff --git a/ruamoko/qwaq/qwaq-group.r b/ruamoko/qwaq/qwaq-group.r index c8af9bf8a..2df05bcba 100644 --- a/ruamoko/qwaq/qwaq-group.r +++ b/ruamoko/qwaq/qwaq-group.r @@ -46,6 +46,30 @@ return self; } +-(Rect) rect +{ + if (owner) { + return [owner rect]; + } + return {[self origin], [self size]}; +} + +-(Point) origin +{ + if (owner) { + return [owner origin]; + } + return {0, 0}; +} + +-(Extent) size +{ + if (owner) { + return [owner size]; + } + return [context size]; +} + static BOOL not_dont_draw (id aView, void *aGroup) { diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 35a0af8b4..2235a82c9 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -46,9 +46,23 @@ - (void) dragWindow: (Button *) sender { Point delta = [sender delta]; - xpos += delta.x; - ypos += delta.y; - move_panel (panel, xpos, ypos); + Point p = {xpos + delta.x, ypos + delta.y}; + Extent bounds = [owner size]; + if (p.x < 0) { + p.x = 0; + } + if (p.x + xlen > bounds.width) { + p.x = bounds.width - xlen; + } + if (p.y < 0) { + p.y = 0; + } + if (p.y + ylen > bounds.height) { + p.y = bounds.height - ylen; + } + xpos = p.x; + ypos = p.y; + move_panel (panel, p.x, p.y); [owner redraw]; } From 65538104bf1f5eec12279ba8026cd9dea805ac91 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 23:18:01 +0900 Subject: [PATCH 435/444] [qwaq] Tweak listener message names I didn't like the message:message bit --- ruamoko/qwaq/qwaq-app.r | 10 +++++----- ruamoko/qwaq/qwaq-listener.h | 8 ++++---- ruamoko/qwaq/qwaq-listener.r | 12 ++++++------ ruamoko/qwaq/qwaq-window.r | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ruamoko/qwaq/qwaq-app.r b/ruamoko/qwaq/qwaq-app.r index 2aaf62880..beeb02788 100644 --- a/ruamoko/qwaq/qwaq-app.r +++ b/ruamoko/qwaq/qwaq-app.r @@ -65,11 +65,11 @@ arp_end (void) [pressed bkgd: COLOR_PAIR(4)]; [pressed clear]; [pressed mvaddstr: {1, 0}, "release me"]; - [[b onPress] addListener: self message: @selector (buttonPressed:)]; - [[b onRelease] addListener: self message: @selector (buttonReleased:)]; - [[b onClick] addListener: self message: @selector (buttonClick:)]; - [[b onDrag] addListener: self message: @selector (buttonDrag:)]; - [[b onAuto] addListener: self message: @selector (buttonAuto:)]; + [[b onPress] addListener: self : @selector (buttonPressed:)]; + [[b onRelease] addListener: self : @selector (buttonReleased:)]; + [[b onClick] addListener: self : @selector (buttonClick:)]; + [[b onDrag] addListener: self : @selector (buttonDrag:)]; + [[b onAuto] addListener: self : @selector (buttonAuto:)]; return self; } diff --git a/ruamoko/qwaq/qwaq-listener.h b/ruamoko/qwaq/qwaq-listener.h index bb02d71f1..2f7ec02b3 100644 --- a/ruamoko/qwaq/qwaq-listener.h +++ b/ruamoko/qwaq/qwaq-listener.h @@ -11,9 +11,9 @@ SEL message; IMP imp; } --initWithResponder: (id) responder message: (SEL) message; +-initWithResponder: (id) responder :(SEL)message; -(void) respond: (id) caller; --(BOOL) matchResponder: (id) responder message: (SEL) message; +-(BOOL) matchResponder: (id) responder :(SEL)message; @end @interface ListenerGroup : Object @@ -21,8 +21,8 @@ Array *listeners; } -init; --addListener: (id) responder message: (SEL) message; --removeListener: (id) responder message: (SEL) message; +-addListener: (id) responder :(SEL)message; +-removeListener: (id) responder :(SEL)message; -(void) respond: (id) caller; @end diff --git a/ruamoko/qwaq/qwaq-listener.r b/ruamoko/qwaq/qwaq-listener.r index 14a0816aa..26e6f28c5 100644 --- a/ruamoko/qwaq/qwaq-listener.r +++ b/ruamoko/qwaq/qwaq-listener.r @@ -5,7 +5,7 @@ @class Array; @implementation Listener --initWithResponder: (id) responder message: (SEL) message +-initWithResponder: (id) responder :(SEL)message { if (!(self = [super init])) { return nil; @@ -21,7 +21,7 @@ imp (responder, message, caller); } --(BOOL) matchResponder: (id) responder message: (SEL) message +-(BOOL) matchResponder: (id) responder :(SEL)message { return self.responder == responder && self.message == message; } @@ -37,21 +37,21 @@ return self; } --addListener: (id) responder message: (SEL) message +-addListener: (id) responder :(SEL)message { Listener *listener = [[Listener alloc] initWithResponder: responder - message: message]; + : message]; if (listener) { [listeners addObject: listener]; } return self; } --removeListener: (id) responder message: (SEL) message +-removeListener: (id) responder :(SEL)message { for (int i = [listeners count]; i-- > 0; ) { Listener *l = [listeners objectAtIndex: i]; - if ([l matchResponder: responder message: message]) { + if ([l matchResponder: responder : message]) { [listeners removeObjectAtIndex: i]; } } diff --git a/ruamoko/qwaq/qwaq-window.r b/ruamoko/qwaq/qwaq-window.r index 2235a82c9..1c772867f 100644 --- a/ruamoko/qwaq/qwaq-window.r +++ b/ruamoko/qwaq/qwaq-window.r @@ -33,7 +33,7 @@ Button *b = [[Button alloc] initWithPos: {0, 0} releasedIcon: title pressedIcon: title]; - [[b onDrag] addListener: self message: @selector(dragWindow:)]; + [[b onDrag] addListener: self : @selector(dragWindow:)]; [self addView: b]; buf = [DrawBuffer buffer: {3, 3}]; From ec12941fcbbf72fe12c2990d4ebb40f7a77d50d1 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Thu, 19 Mar 2020 23:53:54 +0900 Subject: [PATCH 436/444] Move the ring buffer macros to their own header They seem to have proven themselves to be robust. --- include/QF/Makefile.am | 3 +- include/QF/ringbuffer.h | 103 +++++++++++++++++++++++++++++++++++++ ruamoko/qwaq/qwaq-curses.c | 73 +------------------------- 3 files changed, 106 insertions(+), 73 deletions(-) create mode 100644 include/QF/ringbuffer.h diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am index 724d192df..c0fda5cd1 100644 --- a/include/QF/Makefile.am +++ b/include/QF/Makefile.am @@ -11,7 +11,8 @@ include_qf= \ msg.h object.h pak.h pakfile.h pcx.h png.h plugin.h pr_comp.h pr_debug.h \ pr_obj.h pr_type.h progs.h qargs.h qdefs.h qendian.h qfplist.h qtypes.h \ quakefs.h \ - quakeio.h render.h riff.h ruamoko.h screen.h script.h segtext.h set.h \ + quakeio.h render.h riff.h ringbuffer.h ruamoko.h \ + screen.h script.h segtext.h set.h \ sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h tga.h va.h \ ver_check.h vid.h vrect.h view.h wad.h wadfile.h winding.h zone.h \ \ diff --git a/include/QF/ringbuffer.h b/include/QF/ringbuffer.h new file mode 100644 index 000000000..cc289640e --- /dev/null +++ b/include/QF/ringbuffer.h @@ -0,0 +1,103 @@ +/* + ringbuffer.h + + ring buffer + + Copyright (C) 2020 Bill Currie + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __QF_ringbuffer_h +#define __QF_ringbuffer_h + +#define RING_BUFFER(type, size) \ + struct { \ + type buffer[size]; \ + unsigned head; \ + unsigned tail; \ + } + +#define RB_buffer_size(ring_buffer) \ + ({ __auto_type rb = (ring_buffer); \ + sizeof (rb->buffer) / sizeof (rb->buffer[0]); \ + }) + +#define RB_SPACE_AVAILABLE(ring_buffer) \ + ({ __auto_type rb = &(ring_buffer); \ + (rb->tail + RB_buffer_size(rb) - rb->head - 1) % RB_buffer_size(rb);\ + }) + +#define RB_DATA_AVAILABLE(ring_buffer) \ + ({ __auto_type rb = &(ring_buffer); \ + (rb->head + RB_buffer_size (rb) - rb->tail) % RB_buffer_size (rb); \ + }) + +#define RB_WRITE_DATA(ring_buffer, data, count) \ + ({ __auto_type rb = &(ring_buffer); \ + const typeof (rb->buffer[0]) *d = (data); \ + unsigned c = (count); \ + unsigned h = rb->head; \ + rb->head = (h + c) % RB_buffer_size (rb); \ + if (c > RB_buffer_size (rb) - h) { \ + memcpy (rb->buffer + h, d, \ + (RB_buffer_size (rb) - h) * sizeof (rb->buffer[0])); \ + c -= RB_buffer_size (rb) - h; \ + d += RB_buffer_size (rb) - h; \ + h = 0; \ + } \ + memcpy (rb->buffer + h, d, c * sizeof (rb->buffer[0])); \ + }) + +#define RB_READ_DATA(ring_buffer, data, count) \ + ({ __auto_type rb = &(ring_buffer); \ + typeof (&rb->buffer[0]) d = (data); \ + unsigned c = (count); \ + unsigned oc = c; \ + unsigned t = rb->tail; \ + if (c > RB_buffer_size (rb) - t) { \ + memcpy (d, rb->buffer + t, \ + (RB_buffer_size (rb) - t) * sizeof (rb->buffer[0])); \ + c -= RB_buffer_size (rb) - t; \ + d += RB_buffer_size (rb) - t; \ + t = 0; \ + } \ + memcpy (d, rb->buffer + t, c * sizeof (rb->buffer[0])); \ + rb->tail = (t + oc) % RB_buffer_size (rb); \ + }) + +#define RB_DROP_DATA(ring_buffer, count) \ + ({ __auto_type rb = &(ring_buffer); \ + unsigned c = (count); \ + unsigned t = rb->tail; \ + rb->tail = (t + c) % RB_buffer_size (rb); \ + }) + +#define RB_PEEK_DATA(ring_buffer, ahead) \ + ({ __auto_type rb = &(ring_buffer); \ + rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)]; \ + }) + +#define RB_POKE_DATA(ring_buffer, ahead, data) \ + ({ __auto_type rb = &(ring_buffer); \ + rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)] = (data); \ + }) + +#endif//__QF_ringbuffer_h diff --git a/ruamoko/qwaq/qwaq-curses.c b/ruamoko/qwaq/qwaq-curses.c index afb2ca246..3837d2f8c 100644 --- a/ruamoko/qwaq/qwaq-curses.c +++ b/ruamoko/qwaq/qwaq-curses.c @@ -39,6 +39,7 @@ #include "QF/dstring.h" #include "QF/progs.h" +#include "QF/ringbuffer.h" #include "QF/sys.h" #include "qwaq.h" @@ -113,78 +114,6 @@ const char *qwaq_command_names[]= { "mvwblit_line", }; -#define RING_BUFFER(type, size) \ - struct { \ - type buffer[size]; \ - unsigned head; \ - unsigned tail; \ - } - -#define RB_buffer_size(ring_buffer) \ - ({ __auto_type rb = (ring_buffer); \ - sizeof (rb->buffer) / sizeof (rb->buffer[0]); \ - }) - -#define RB_SPACE_AVAILABLE(ring_buffer) \ - ({ __auto_type rb = &(ring_buffer); \ - (rb->tail + RB_buffer_size(rb) - rb->head - 1) % RB_buffer_size(rb);\ - }) - -#define RB_DATA_AVAILABLE(ring_buffer) \ - ({ __auto_type rb = &(ring_buffer); \ - (rb->head + RB_buffer_size (rb) - rb->tail) % RB_buffer_size (rb); \ - }) - -#define RB_WRITE_DATA(ring_buffer, data, count) \ - ({ __auto_type rb = &(ring_buffer); \ - const typeof (rb->buffer[0]) *d = (data); \ - unsigned c = (count); \ - unsigned h = rb->head; \ - rb->head = (h + c) % RB_buffer_size (rb); \ - if (c > RB_buffer_size (rb) - h) { \ - memcpy (rb->buffer + h, d, \ - (RB_buffer_size (rb) - h) * sizeof (rb->buffer[0])); \ - c -= RB_buffer_size (rb) - h; \ - d += RB_buffer_size (rb) - h; \ - h = 0; \ - } \ - memcpy (rb->buffer + h, d, c * sizeof (rb->buffer[0])); \ - }) - -#define RB_READ_DATA(ring_buffer, data, count) \ - ({ __auto_type rb = &(ring_buffer); \ - typeof (&rb->buffer[0]) d = (data); \ - unsigned c = (count); \ - unsigned oc = c; \ - unsigned t = rb->tail; \ - if (c > RB_buffer_size (rb) - t) { \ - memcpy (d, rb->buffer + t, \ - (RB_buffer_size (rb) - t) * sizeof (rb->buffer[0])); \ - c -= RB_buffer_size (rb) - t; \ - d += RB_buffer_size (rb) - t; \ - t = 0; \ - } \ - memcpy (d, rb->buffer + t, c * sizeof (rb->buffer[0])); \ - rb->tail = (t + oc) % RB_buffer_size (rb); \ - }) - -#define RB_DROP_DATA(ring_buffer, count) \ - ({ __auto_type rb = &(ring_buffer); \ - unsigned c = (count); \ - unsigned t = rb->tail; \ - rb->tail = (t + c) % RB_buffer_size (rb); \ - }) - -#define RB_PEEK_DATA(ring_buffer, ahead) \ - ({ __auto_type rb = &(ring_buffer); \ - rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)]; \ - }) - -#define RB_POKE_DATA(ring_buffer, ahead, data) \ - ({ __auto_type rb = &(ring_buffer); \ - rb->buffer[(rb->tail + ahead) % RB_buffer_size (rb)] = (data); \ - }) - typedef struct window_s { WINDOW *win; } window_t; From f64038b8725b3838faf5701ddfa926ab3d8abc11 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 20 Mar 2020 11:46:16 +0900 Subject: [PATCH 437/444] [qfcc] Add gcd.pas to the tests --- tools/qfcc/test/Makefile.am | 16 +++++++++++++++- tools/qfcc/test/{old => }/gcd.pas | 0 2 files changed, 15 insertions(+), 1 deletion(-) rename tools/qfcc/test/{old => }/gcd.pas (100%) diff --git a/tools/qfcc/test/Makefile.am b/tools/qfcc/test/Makefile.am index ceb32813f..f6f0c6043 100644 --- a/tools/qfcc/test/Makefile.am +++ b/tools/qfcc/test/Makefile.am @@ -13,11 +13,15 @@ QCFLAGS=-qq -O -g -Werror QCPPFLAGS=--no-default-paths -I$(top_srcdir)/ruamoko/include QCOMPILE=$(QFCC) $(QCFLAGS) $(QCPPFLAGS) -SUFFIXES=.qfo .r +SUFFIXES=.qfo .r .pas .r.qfo: $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -c -o $@ $< sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo +.pas.qfo: + $(QCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tqo -c -o $@ $< + sed -i -e '1s@:@: $(QFCC_DEP)@' $(DEPDIR)/$*.Tqo + $(am__mv) $(DEPDIR)/$*.Tqo $(DEPDIR)/$*.Qo QFCC_TEST_LIBS=@QFCC_TEST_LIBS@ QFCC_TEST_DEPS=@QFCC_TEST_DEPS@ @@ -43,6 +47,7 @@ test_progs_dat=\ fordecl.dat \ func-expr.dat \ func-static.dat \ + gcd.dat \ infloop.dat \ ivar-struct-return.dat \ methodparams.dat \ @@ -262,6 +267,15 @@ func-static.run: Makefile build-run include ./$(DEPDIR)/func-static.Qo # am--include-marker r_depfiles_remade += ./$(DEPDIR)/func-static.Qo +gcd_dat_SOURCES=gcd.pas +gcd_obj=$(gcd_dat_SOURCES:.pas=.qfo) +gcd.dat$(EXEEXT): $(gcd_obj) $(QFCC_DEP) + $(QFCC) $(QCFLAGS) -o $@ $(gcd_obj) +gcd.run: Makefile build-run + @$(srcdir)/build-run $@ +include ./$(DEPDIR)/gcd.Qo # am--include-marker +r_depfiles_remade += ./$(DEPDIR)/gcd.Qo + infloop_dat_SOURCES=infloop.r infloop_obj=$(infloop_dat_SOURCES:.r=.qfo) infloop.dat$(EXEEXT): $(infloop_obj) $(QFCC_DEP) diff --git a/tools/qfcc/test/old/gcd.pas b/tools/qfcc/test/gcd.pas similarity index 100% rename from tools/qfcc/test/old/gcd.pas rename to tools/qfcc/test/gcd.pas From ed03eeb8d2fed9a08cfee67807de71510f7ef6b8 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 20 Mar 2020 11:47:01 +0900 Subject: [PATCH 438/444] [qfcc] Resync qc and qp common symbols Forgot I needed to remove PAS from pascal as well. --- tools/qfcc/source/qp-parse.y | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/qfcc/source/qp-parse.y b/tools/qfcc/source/qp-parse.y index 922068b02..08759a544 100644 --- a/tools/qfcc/source/qp-parse.y +++ b/tools/qfcc/source/qp-parse.y @@ -105,7 +105,7 @@ int yylex (void); %nonassoc STORAGEX %left COMMA -%right '=' ASX PAS /* pointer assign */ +%right '=' ASX %right '?' ':' %left OR %left AND From 298fcbbf708883c2fdff49fb33b059b61436dc6c Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 20 Mar 2020 11:48:01 +0900 Subject: [PATCH 439/444] [qfcc] Add ExitCode support to quake-pascal gcd now passes :) --- tools/qfcc/source/qp-parse.y | 43 ++++++++++++++++++++++++++++-------- tools/qfcc/test/gcd.pas | 6 +++-- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/tools/qfcc/source/qp-parse.y b/tools/qfcc/source/qp-parse.y index 08759a544..730eab57a 100644 --- a/tools/qfcc/source/qp-parse.y +++ b/tools/qfcc/source/qp-parse.y @@ -139,6 +139,29 @@ int yylex (void); %type sign %{ + +static void +build_dotmain (symbol_t *program) +{ + symbol_t *dotmain = new_symbol (".main"); + expr_t *code; + expr_t *exitcode; + + dotmain->params = 0; + dotmain->type = parse_params (&type_integer, 0); + dotmain->type = find_type (dotmain->type); + dotmain = function_symbol (dotmain, 0, 1); + + exitcode = new_symbol_expr (symtab_lookup (current_symtab, "ExitCode")); + + current_func = begin_function (dotmain, 0, current_symtab, 0); + current_symtab = current_func->symtab; + code = new_block_expr (); + append_expr (code, function_expr (new_symbol_expr (program), 0)); + append_expr (code, return_expr (current_func, exitcode)); + build_code_function (dotmain, 0, code); +} + %} %% @@ -159,15 +182,7 @@ program build_code_function ($1, 0, $4); current_symtab = st; - $4 = function_expr (new_symbol_expr ($1), 0); - $1 = new_symbol (".main"); - $1->params = 0; - $1->type = parse_params (&type_void, 0); - $1->type = find_type ($1->type); - $1 = function_symbol ($1, 0, 1); - current_func = begin_function ($1, 0, current_symtab, 0); - current_symtab = current_func->symtab; - build_code_function ($1, 0, $4); + build_dotmain ($1); current_symtab = st; } ; @@ -178,6 +193,15 @@ program_head { $$ = $3; + // FIXME need units and standard units + { + symbol_t *sym = new_symbol ("ExitCode"); + sym->type = &type_integer; + initialize_def (sym, 0, current_symtab->space, sc_global); + if (sym->s.def) { + sym->s.def->nosave = 1; + } + } $$->type = parse_params (&type_void, 0); $$->type = find_type ($$->type); $$ = function_symbol ($$, 0, 1); @@ -375,6 +399,7 @@ statement else : ELSE { + // this is only to get the the file and line number info $$ = new_nil_expr (); } ; diff --git a/tools/qfcc/test/gcd.pas b/tools/qfcc/test/gcd.pas index 04e193b26..3879a3d3d 100644 --- a/tools/qfcc/test/gcd.pas +++ b/tools/qfcc/test/gcd.pas @@ -1,5 +1,5 @@ program example (input, output); -var x, y: integer; +var x, y, g: integer; procedure printf (format:string; ...) := #0; function gcd (a, b: integer): integer; var c: quaternion; @@ -11,5 +11,7 @@ end; begin x := 130; y := 120; - printf ("%d\n", gcd (x, y)) + g := gcd (x, y); + printf ("%d\n", g); + ExitCode := g <> 10; end. From 966bd267c58839839394613cecc0a5b0a1208862 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 16:17:21 +0900 Subject: [PATCH 440/444] Add a set of macros for dynamic arrays Includes docs and test cases. --- include/QF/darray.h | 301 +++++++++++++++++++++++++++++++++++ libs/util/test/Makefile.am | 9 +- libs/util/test/test-darray.c | 213 +++++++++++++++++++++++++ 3 files changed, 521 insertions(+), 2 deletions(-) create mode 100644 include/QF/darray.h create mode 100644 libs/util/test/test-darray.c diff --git a/include/QF/darray.h b/include/QF/darray.h new file mode 100644 index 000000000..88792715f --- /dev/null +++ b/include/QF/darray.h @@ -0,0 +1,301 @@ +/* + darray.h + + Dynamic arrays + + Copyright (C) 2020 Bill Currie + + Author: Bill Currie + Date: 2020/02/17 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + See the GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + +*/ + +#ifndef __pr_type_h +#define __pr_type_h + +/** \defgroup darray Dynamic Arrays + \ingroup utils + + Dynamic array container object +*/ +///@{ + +/** The structure defs for a dynamic array with elements of the given type. + + This is just the defs of a struct delcaration: it is useless on its own. + The intended usage is something like: + + typedef struct dynamic_array_s DARRAY_TYPE(int) dynamic_array_t; + + This allows full flexibility in just how the actual type is used. + + The \a size field is the number of elements currently in the array, and + the \a maxSize field is the number of elements the array can hold without + being resized. + + The \a grow field specifies the number of elements by which \a maxSize is + to grow when the array needs to be resized. Setting this to 0 prevents + resizing and any attempt to do so is a fatal error. + + \param ele_type The type to use for the element array, which is accessed + by the \a a field. + \hideinitializer +*/ +#define DARRAY_TYPE(ele_type) \ + { \ + size_t size; \ + size_t maxSize; \ + size_t grow; \ + ele_type *a; \ + } + +/** Clear the array. + + If the array can grow, its backing will be freed and maxSize and a reset, + otherwise maxSize and a are left untouched. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \hideinitializer +*/ +#define DARRAY_CLEAR(array) \ + do { \ + __auto_type ar = (array); \ + free (ar->a); \ + ar->size = 0; \ + if (ar->grow) { \ + ar->maxSize = 0; \ + ar->a = 0; \ + } \ + } while (0) + +/** Set the size of the array. + + If the new size is greater than maxSize, and the array can grow (grow is + non-zero), then maxSize will be increased to the smallest multiple of grow + greater than or equal to size (ie, maxSize >= size, maxSize % grow == 0). + + Attempting to increase maxSize on an array that cannot grow is an error: + it is assumed that the array struct does not own the backing memory. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param newSize The new size of the array: newly opened slots are + uninitialized, but old slots retain their values. + \hideinitializer +*/ +#define DARRAY_RESIZE(array, newSize) \ + do { \ + __auto_type ar = (array); \ + size_t ns = (newSize); \ + if (__builtin_expect (ns > ar->maxSize, 0)) { \ + if (__builtin_expect (!ar->grow, 0)) { \ + Sys_Error ("Attempt to grow fixed-size darray: %s:%d", \ + __FILE__, __LINE__); \ + } \ + ar->maxSize = ar->grow * ((ns + ar->grow - 1) / ar->grow); \ + ar->a = realloc (ar->a, ar->maxSize * sizeof (*ar->a)); \ + if (__builtin_expect (!ar->a, 0)) { \ + Sys_Error ("failed to realloc darray: %s:%d", \ + __FILE__, __LINE__); \ + } \ + } \ + ar->size = ns; \ + } while (0) + +/** Append a value to the end of the array. + + The array is grown by one and the value written to the newly opened slot. + + If the new array size is greater than maxSize and the array can be grown, + the array backing will be resized to the next multiple of grow. + + Attempting to grow an array that cannot grow is an error: it is assumed + that the array struct does not own the backing memory. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param value The value to be appended to the array. Must be of a type + compatible with that used for creating the array struct. + \return The appended value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_APPEND(array, value) \ + ({ \ + __auto_type ar = (array); \ + __auto_type ob = (value); \ + size_t sz = ar->size; \ + DARRAY_RESIZE (ar, ar->size + 1); \ + ar->a[sz] = ob; \ + }) + +/** Open a hole in the array for bulk copying of data. + + The array is grown by the requested size, opening a hole at the specified + index. Values beyond the index are copied to just after the newly opened + hole. + + If the new array size is greater than maxSize and the array can be grown, + the array backing will be resized to the next multiple of grow. + + Attempting to grow an array that cannot grow is an error: it is assumed + that the array struct does not own the backing memory. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param index The index at which the hole will begin. + \param space The sized of the hole to be opened, in array elements. + \return The *address* of the newly opened hole: can be passed to + memcpy and friends. + + memcpy (DARRAY_OPEN_AT(array, index, size), data, + size * sizeof (*data)); + \hideinitializer +*/ +#define DARRAY_OPEN_AT(array, index, space) \ + ({ \ + __auto_type ar = (array); \ + size_t po = (index); \ + size_t sp = (space); \ + if (__builtin_expect (po > ar->size, 0)) { \ + Sys_Error ("Attempt to insert elements outside darray: " \ + "%s:%d", __FILE__, __LINE__); \ + } \ + DARRAY_RESIZE (ar, ar->size + sp); \ + memmove (&ar->a[po + sp], &ar->a[po], \ + (ar->size - po) * sizeof (*ar->a)); \ + &ar->a[po]; \ + }) + +/** Insert a value into the array at the specified index. + + The array is grown by one at the specified index and the value written + to the newly opened slot. Values beyond the index are copied to just + after the newly opened slot. + + If the new array size is greater than maxSize and the array can be grown, + the array backing will be resized to the next multiple of grow. + + Attempting to grow an array that cannot grow is an error: it is assumed + that the array struct does not own the backing memory. + + Attempting to insert a value beyond one past the end of the array is an + error (inserting at index = size is valid). + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param value The value to be inserted into the array. Must be of a type + compatible with that used for creating the array struct. + \param index The index at which the value will be inserted + \return The inserted value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_INSERT_AT(array, value, index) \ + ({ \ + __auto_type ar = (array); \ + __auto_type ob = (value); \ + *DARRAY_OPEN_AT (ar, index, 1) = ob; \ + }) + +/** Close a segment of an array. + + The values beyond the segment are copied to the beginning of the segment + and the array size reduced by the size of the segment. All but the first + one of the values previously in the segment are lost and gone forever. + + Attempting to close a segment that extends outside the array is an error. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param index The index of the beginning of the segment. + \param count The number of values in the segment. + \return The single value at the beginning of the segment: can be + assigned to another compatible value. + \hideinitializer +*/ +#define DARRAY_CLOSE_AT(array, index, count) \ + ({ \ + __auto_type ar = (array); \ + size_t po = (index); \ + size_t co = (count); \ + if (__builtin_expect (po + co > ar->size \ + || po >= ar->size, 0)) { \ + Sys_Error ("Attempt to remove elements outside darray: " \ + "%s:%d", __FILE__, __LINE__); \ + } \ + __auto_type ob = ar->a[po]; \ + memmove (&ar->a[po], &ar->a[po + co], \ + (ar->size - po - co) * sizeof (ob)); \ + ar->size -= co; \ + ob; \ + }) + +/** Remove a value from an array at the specified index. + + The values beyond the index are moved down to fill the hole left by the + single value and the array size reduced by one. + + Attempting to remove a value from beyond the array is an error. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param index The index of the value to be removed. + \return The removed value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_REMOVE_AT(array, index) \ + ({ \ + __auto_type ar = (array); \ + DARRAY_CLOSE_AT (ar, index, 1); \ + }) + +/** Remove (pop) a value from the end of an array. + + The size of the array size reduced by one. + + Attempting to remove a value from an empty array is an error. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \return The removed value: can be assigned to another compatible + value. + \hideinitializer +*/ +#define DARRAY_REMOVE(array) \ + ({ \ + __auto_type ar = (array); \ + DARRAY_CLOSE_AT (ar, ar->size - 1, 1); \ + }) + +///@} + +#endif//__pr_type_h diff --git a/libs/util/test/Makefile.am b/libs/util/test/Makefile.am index 283ac561e..74d9a2f4e 100644 --- a/libs/util/test/Makefile.am +++ b/libs/util/test/Makefile.am @@ -3,8 +3,9 @@ AUTOMAKE_OPTIONS= foreign AM_CPPFLAGS= -I$(top_srcdir)/include check_PROGRAMS= \ - test-bary test-cs test-dq test-half test-mat3 test-mat4 test-plist \ - test-qfs test-quat test-seb test-seg test-set test-txtbuffer test-vrect + test-bary test-cs test-darray test-dq test-half test-mat3 test-mat4 \ + test-plist test-qfs test-quat test-seb test-seg test-set test-txtbuffer \ + test-vrect test_bary_SOURCES=test-bary.c test_bary_LDADD=$(top_builddir)/libs/util/libQFutil.la @@ -14,6 +15,10 @@ test_cs_SOURCES=test-cs.c test_cs_LDADD=$(top_builddir)/libs/util/libQFutil.la test_cs_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la +test_darray_SOURCES=test-darray.c +test_darray_LDADD=$(top_builddir)/libs/util/libQFutil.la +test_darray_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la + test_dq_SOURCES=test-dq.c test_dq_LDADD=$(top_builddir)/libs/util/libQFutil.la test_dq_DEPENDENCIES=$(top_builddir)/libs/util/libQFutil.la diff --git a/libs/util/test/test-darray.c b/libs/util/test/test-darray.c new file mode 100644 index 000000000..59dbad0ab --- /dev/null +++ b/libs/util/test/test-darray.c @@ -0,0 +1,213 @@ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#define remove remove_renamed +#include +#include +#include + +#include "QF/darray.h" +#include "QF/sys.h" +#undef remove + +typedef int (*test_func) (int a, int b); +typedef struct intarray_s DARRAY_TYPE(int) intarray_t; + +intarray_t intarray = {0, 0, 16, 0}; + +static int +append (int val, int b) +{ + return DARRAY_APPEND (&intarray, val); +} + +static int +check_size (int a, int b) +{ + return intarray.size; +} + +static int +check_maxSize (int a, int b) +{ + return intarray.maxSize; +} + +static int +check_grow (int a, int b) +{ + return intarray.grow; +} + +static int +check_maxSizeGrowth (int a, int b) +{ + return intarray.maxSize % intarray.grow; +} + +static int +check_array (int a, int b) +{ + return !!intarray.a; +} + +static int +check_value (int index, int b) +{ + if ((size_t) index >= intarray.size) { + Sys_Error ("indexing beyond array"); + } + return intarray.a[index]; +} + +static int +insert_at (int val, int pos) +{ + return DARRAY_INSERT_AT (&intarray, val, pos); +} + +static int +open_at (int pos, int size) +{ + return DARRAY_OPEN_AT (&intarray, pos, size) - intarray.a; +} + +static const char text[] = "Aloy is an awesome huntress."; +static int +open_at2 (int pos, int size) +{ + memcpy(DARRAY_OPEN_AT (&intarray, pos, size), text, size * sizeof (int)); + return strcmp((char*) (intarray.a + pos), text); +} + +static int +remove_at (int pos, int b) +{ + return DARRAY_REMOVE_AT (&intarray, pos); +} + +static int +remove (int pos, int b) +{ + return DARRAY_REMOVE (&intarray); +} + +static int +close_at (int pos, int size) +{ + return DARRAY_CLOSE_AT (&intarray, pos, size); +} + +static int +clear (int a, int b) +{ + DARRAY_CLEAR (&intarray); + return 0; +} + +static int +resize (int size, int b) +{ + DARRAY_RESIZE (&intarray, size); + return 0; +} + +struct { + test_func test; + int param1, param2; + int test_expect; +} tests[] = { + {check_size, 0, 0, 0}, // confirm array empty but can grow + {check_maxSize, 0, 0, 0}, + {check_grow, 0, 0, 16}, + {check_array, 0, 0, 0}, + {append, 5, 0, 5}, // test first append to emtpty array + {check_size, 0, 0, 1}, + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 16}, + {check_array, 0, 0, 1}, + {check_value, 0, 0, 5}, + {append, 42, 0, 42}, // test a second append + {check_size, 0, 0, 2}, + {check_maxSize, 0, 0, 16}, + {check_value, 0, 0, 5}, + {check_value, 1, 0, 42}, + {insert_at, 69, 1, 69}, // test insertions + {insert_at, 96, 0, 96}, + {check_size, 0, 0, 4}, + {check_maxSize, 0, 0, 16}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 5}, + {check_value, 2, 0, 69}, + {check_value, 3, 0, 42}, + {open_at, 2, 14, 2}, // test opening a large hole + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 18}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 5}, + {check_value, 16, 0, 69}, + {check_value, 17, 0, 42}, + {close_at, 1, 15, 5}, // test block removal + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 3}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 69}, + {check_value, 2, 0, 42}, + {remove, 0, 0, 42}, // test "pop" + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 2}, + {check_value, 0, 0, 96}, + {check_value, 1, 0, 69}, + {remove_at, 0, 0, 96}, // test remove at + {check_maxSize, 0, 0, 32}, + {check_size, 0, 0, 1}, + {check_value, 0, 0, 69}, + {insert_at, 71, 1, 71}, // test insertion at end + {resize, 48, 0, 0}, // test resize bigger + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 48}, + {check_size, 0, 0, 48}, + {check_value, 0, 0, 69}, + {check_value, 1, 0, 71}, + {resize, 24, 0, 0}, // test resize smaller + {check_maxSizeGrowth, 0, 0, 0}, + {check_maxSize, 0, 0, 48}, + {check_size, 0, 0, 24}, + {check_value, 0, 0, 69}, + {check_value, 1, 0, 71}, + {open_at2, 1, (sizeof (text) + sizeof (int) - 1) / sizeof (int), 0}, + {check_value, 0, 0, 69}, + {check_value, 1, 0, 0x796f6c41}, + {check_value, 9, 0, 71}, + {clear, 0, 0, 0}, // test clearing + {check_size, 0, 0, 0}, + {check_maxSize, 0, 0, 0}, + {check_array, 0, 0, 0}, +}; +#define num_tests (sizeof (tests) / sizeof (tests[0])) +int test_start_line = __LINE__ - num_tests - 2; + +int +main (int argc, const char **argv) +{ + int res = 0; + + size_t i; + + for (i = 0; i < num_tests; i++) { + if (tests[i].test) { + int test_res; + test_res = tests[i].test (tests[i].param1, tests[i].param2); + if (test_res != tests[i].test_expect) { + res |= 1; + printf ("test %d (line %d) failed\n", (int) i, + (int) i + test_start_line); + printf ("expect: %d\n", tests[i].test_expect); + printf ("got : %d\n", test_res); + continue; + } + } + } + return res; +} From 0764df127643b32d97a6d73f63039a40bb40ba10 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 16:40:12 +0900 Subject: [PATCH 441/444] Fix incorrect include protection --- include/QF/Makefile.am | 2 +- include/QF/darray.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am index c0fda5cd1..bb6b0d2da 100644 --- a/include/QF/Makefile.am +++ b/include/QF/Makefile.am @@ -5,7 +5,7 @@ pkgdatadir = $(datarootdir)/qfcc/include/QF include_qf= \ alloc.h bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \ - console.h crc.h csqc.h cvar.h dstring.h draw.h gib.h hash.h \ + console.h crc.h csqc.h cvar.h darray.h dstring.h draw.h gib.h hash.h \ idparse.h image.h in_event.h info.h input.h iqm.h joystick.h keys.h \ link.h llist.h locs.h mathlib.h mdfour.h mersenne.h model.h modelgen.h \ msg.h object.h pak.h pakfile.h pcx.h png.h plugin.h pr_comp.h pr_debug.h \ diff --git a/include/QF/darray.h b/include/QF/darray.h index 88792715f..0287f958f 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -28,8 +28,8 @@ */ -#ifndef __pr_type_h -#define __pr_type_h +#ifndef __darray_h +#define __darray_h /** \defgroup darray Dynamic Arrays \ingroup utils @@ -298,4 +298,4 @@ ///@} -#endif//__pr_type_h +#endif//__darray_h From 2966b035bf0cf78544b8a7c2e73e42b3d7c76af6 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Mon, 17 Feb 2020 20:27:43 +0900 Subject: [PATCH 442/444] Add a fixed-array allocator Turned out to be very convenient. --- include/QF/darray.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/include/QF/darray.h b/include/QF/darray.h index 0287f958f..7a4484575 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -67,6 +67,27 @@ ele_type *a; \ } +/** Allocate a fixed-size array using the given allocator + + The allocated array is initilized to be ungrowable, and with both size + and maxSize set to the given size. + + \param array_type Expression acceptable by typeof for determining the + type of the array. + \param array_size The size of the array. + \param alloc Allocator compatible with malloc (eg, alloca). +*/ +#define DARRAY_ALLOCFIXED(array_type, array_size, alloc) \ + ({ \ + __auto_type s = (array_size); \ + typeof (array_type) *ar = alloc (sizeof(*ar) \ + + s * sizeof (*ar->a)); \ + ar->size = ar->maxSize = s; \ + ar->grow = 0; \ + ar->a = (typeof (ar->a)) (ar + 1); \ + ar; \ + }) + /** Clear the array. If the array can grow, its backing will be freed and maxSize and a reset, From 38fc7459e40b865b34350f7225aa45ee49618730 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 20 Mar 2020 12:52:56 +0900 Subject: [PATCH 443/444] Add DARRAY_INIT from the vulkan branch Couldn't cherry-pick this one as it was a bigger commit. --- include/QF/darray.h | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/include/QF/darray.h b/include/QF/darray.h index 7a4484575..9f8c9630b 100644 --- a/include/QF/darray.h +++ b/include/QF/darray.h @@ -88,6 +88,25 @@ ar; \ }) +/** Initialized the array. + + The array will be initialized to be empty but with grow set to the + specifed value. + + \param array *Address* of the array to be modified (ie, pointer to the + array struct instance, not the instance itself: use & for + static instances of the array struct). + \param growSize Number of elements by which the array is to grow when + required. + \hideinitializer +*/ +#define DARRAY_INIT(array, growSize) \ + do { \ + __auto_type ar = (array); \ + ar->size = ar->maxSize = 0; \ + ar->grow = (growSize); \ + } while (0) + /** Clear the array. If the array can grow, its backing will be freed and maxSize and a reset, From d2f03e8a640d96f3e8dc6de1b0173b969ae887b2 Mon Sep 17 00:00:00 2001 From: Bill Currie Date: Fri, 20 Mar 2020 12:55:23 +0900 Subject: [PATCH 444/444] [util] Fix darray test for gcc purity --- libs/util/test/test-darray.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/util/test/test-darray.c b/libs/util/test/test-darray.c index 59dbad0ab..59d3a2ddc 100644 --- a/libs/util/test/test-darray.c +++ b/libs/util/test/test-darray.c @@ -51,7 +51,7 @@ check_array (int a, int b) return !!intarray.a; } -static int +static int __attribute__((pure)) check_value (int index, int b) { if ((size_t) index >= intarray.size) {